1 //===- Utility.cpp ------ Collection of generic offloading utilities ------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/Frontend/Offloading/Utility.h"
10 #include "llvm/IR/Constants.h"
11 #include "llvm/IR/GlobalValue.h"
12 #include "llvm/IR/GlobalVariable.h"
13 #include "llvm/IR/Value.h"
14
15 using namespace llvm;
16 using namespace llvm::offloading;
17
getEntryTy(Module & M)18 StructType *offloading::getEntryTy(Module &M) {
19 LLVMContext &C = M.getContext();
20 StructType *EntryTy =
21 StructType::getTypeByName(C, "struct.__tgt_offload_entry");
22 if (!EntryTy)
23 EntryTy = StructType::create(
24 "struct.__tgt_offload_entry", PointerType::getUnqual(C),
25 PointerType::getUnqual(C), M.getDataLayout().getIntPtrType(C),
26 Type::getInt32Ty(C), Type::getInt32Ty(C));
27 return EntryTy;
28 }
29
30 // TODO: Rework this interface to be more generic.
31 std::pair<Constant *, GlobalVariable *>
getOffloadingEntryInitializer(Module & M,Constant * Addr,StringRef Name,uint64_t Size,int32_t Flags,int32_t Data)32 offloading::getOffloadingEntryInitializer(Module &M, Constant *Addr,
33 StringRef Name, uint64_t Size,
34 int32_t Flags, int32_t Data) {
35 Type *Int8PtrTy = PointerType::getUnqual(M.getContext());
36 Type *Int32Ty = Type::getInt32Ty(M.getContext());
37 Type *SizeTy = M.getDataLayout().getIntPtrType(M.getContext());
38
39 Constant *AddrName = ConstantDataArray::getString(M.getContext(), Name);
40
41 // Create the constant string used to look up the symbol in the device.
42 auto *Str = new GlobalVariable(M, AddrName->getType(), /*isConstant=*/true,
43 GlobalValue::InternalLinkage, AddrName,
44 ".omp_offloading.entry_name");
45 Str->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
46
47 // Construct the offloading entry.
48 Constant *EntryData[] = {
49 ConstantExpr::getPointerBitCastOrAddrSpaceCast(Addr, Int8PtrTy),
50 ConstantExpr::getPointerBitCastOrAddrSpaceCast(Str, Int8PtrTy),
51 ConstantInt::get(SizeTy, Size),
52 ConstantInt::get(Int32Ty, Flags),
53 ConstantInt::get(Int32Ty, Data),
54 };
55 Constant *EntryInitializer = ConstantStruct::get(getEntryTy(M), EntryData);
56 return {EntryInitializer, Str};
57 }
58
emitOffloadingEntry(Module & M,Constant * Addr,StringRef Name,uint64_t Size,int32_t Flags,int32_t Data,StringRef SectionName)59 void offloading::emitOffloadingEntry(Module &M, Constant *Addr, StringRef Name,
60 uint64_t Size, int32_t Flags, int32_t Data,
61 StringRef SectionName) {
62 llvm::Triple Triple(M.getTargetTriple());
63
64 auto [EntryInitializer, NameGV] =
65 getOffloadingEntryInitializer(M, Addr, Name, Size, Flags, Data);
66
67 auto *Entry = new GlobalVariable(
68 M, getEntryTy(M),
69 /*isConstant=*/true, GlobalValue::WeakAnyLinkage, EntryInitializer,
70 ".omp_offloading.entry." + Name, nullptr, GlobalValue::NotThreadLocal,
71 M.getDataLayout().getDefaultGlobalsAddressSpace());
72
73 // The entry has to be created in the section the linker expects it to be.
74 if (Triple.isOSBinFormatCOFF())
75 Entry->setSection((SectionName + "$OE").str());
76 else
77 Entry->setSection(SectionName);
78 Entry->setAlignment(Align(1));
79 }
80
81 std::pair<GlobalVariable *, GlobalVariable *>
getOffloadEntryArray(Module & M,StringRef SectionName)82 offloading::getOffloadEntryArray(Module &M, StringRef SectionName) {
83 llvm::Triple Triple(M.getTargetTriple());
84
85 auto *ZeroInitilaizer =
86 ConstantAggregateZero::get(ArrayType::get(getEntryTy(M), 0u));
87 auto *EntryInit = Triple.isOSBinFormatCOFF() ? ZeroInitilaizer : nullptr;
88 auto *EntryType = ArrayType::get(getEntryTy(M), 0);
89
90 auto *EntriesB = new GlobalVariable(M, EntryType, /*isConstant=*/true,
91 GlobalValue::ExternalLinkage, EntryInit,
92 "__start_" + SectionName);
93 EntriesB->setVisibility(GlobalValue::HiddenVisibility);
94 auto *EntriesE = new GlobalVariable(M, EntryType, /*isConstant=*/true,
95 GlobalValue::ExternalLinkage, EntryInit,
96 "__stop_" + SectionName);
97 EntriesE->setVisibility(GlobalValue::HiddenVisibility);
98
99 if (Triple.isOSBinFormatELF()) {
100 // We assume that external begin/end symbols that we have created above will
101 // be defined by the linker. This is done whenever a section name with a
102 // valid C-identifier is present. We define a dummy variable here to force
103 // the linker to always provide these symbols.
104 auto *DummyEntry = new GlobalVariable(
105 M, ZeroInitilaizer->getType(), true, GlobalVariable::ExternalLinkage,
106 ZeroInitilaizer, "__dummy." + SectionName);
107 DummyEntry->setSection(SectionName);
108 DummyEntry->setVisibility(GlobalValue::HiddenVisibility);
109 } else {
110 // The COFF linker will merge sections containing a '$' together into a
111 // single section. The order of entries in this section will be sorted
112 // alphabetically by the characters following the '$' in the name. Set the
113 // sections here to ensure that the beginning and end symbols are sorted.
114 EntriesB->setSection((SectionName + "$OA").str());
115 EntriesE->setSection((SectionName + "$OZ").str());
116 }
117
118 return std::make_pair(EntriesB, EntriesE);
119 }
120