xref: /freebsd-src/contrib/llvm-project/llvm/lib/Frontend/Offloading/Utility.cpp (revision cb14a3fe5122c879eae1fb480ed7ce82a699ddb6)
1 //===- Utility.cpp ------ Collection of geneirc 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 
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 void offloading::emitOffloadingEntry(Module &M, Constant *Addr, StringRef Name,
32                                      uint64_t Size, int32_t Flags, int32_t Data,
33                                      StringRef SectionName) {
34   llvm::Triple Triple(M.getTargetTriple());
35 
36   Type *Int8PtrTy = PointerType::getUnqual(M.getContext());
37   Type *Int32Ty = Type::getInt32Ty(M.getContext());
38   Type *SizeTy = M.getDataLayout().getIntPtrType(M.getContext());
39 
40   Constant *AddrName = ConstantDataArray::getString(M.getContext(), Name);
41 
42   // Create the constant string used to look up the symbol in the device.
43   auto *Str = new GlobalVariable(M, AddrName->getType(), /*isConstant=*/true,
44                                  GlobalValue::InternalLinkage, AddrName,
45                                  ".omp_offloading.entry_name");
46   Str->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
47 
48   // Construct the offloading entry.
49   Constant *EntryData[] = {
50       ConstantExpr::getPointerBitCastOrAddrSpaceCast(Addr, Int8PtrTy),
51       ConstantExpr::getPointerBitCastOrAddrSpaceCast(Str, Int8PtrTy),
52       ConstantInt::get(SizeTy, Size),
53       ConstantInt::get(Int32Ty, Flags),
54       ConstantInt::get(Int32Ty, Data),
55   };
56   Constant *EntryInitializer = ConstantStruct::get(getEntryTy(M), EntryData);
57 
58   auto *Entry = new GlobalVariable(
59       M, getEntryTy(M),
60       /*isConstant=*/true, GlobalValue::WeakAnyLinkage, EntryInitializer,
61       ".omp_offloading.entry." + Name, nullptr, GlobalValue::NotThreadLocal,
62       M.getDataLayout().getDefaultGlobalsAddressSpace());
63 
64   // The entry has to be created in the section the linker expects it to be.
65   if (Triple.isOSBinFormatCOFF())
66     Entry->setSection((SectionName + "$OE").str());
67   else
68     Entry->setSection(SectionName);
69   Entry->setAlignment(Align(1));
70 }
71 
72 std::pair<GlobalVariable *, GlobalVariable *>
73 offloading::getOffloadEntryArray(Module &M, StringRef SectionName) {
74   llvm::Triple Triple(M.getTargetTriple());
75 
76   auto *ZeroInitilaizer =
77       ConstantAggregateZero::get(ArrayType::get(getEntryTy(M), 0u));
78   auto *EntryInit = Triple.isOSBinFormatCOFF() ? ZeroInitilaizer : nullptr;
79   auto *EntryType = ArrayType::get(getEntryTy(M), 0);
80 
81   auto *EntriesB = new GlobalVariable(M, EntryType, /*isConstant=*/true,
82                                       GlobalValue::ExternalLinkage, EntryInit,
83                                       "__start_" + SectionName);
84   EntriesB->setVisibility(GlobalValue::HiddenVisibility);
85   auto *EntriesE = new GlobalVariable(M, EntryType, /*isConstant=*/true,
86                                       GlobalValue::ExternalLinkage, EntryInit,
87                                       "__stop_" + SectionName);
88   EntriesE->setVisibility(GlobalValue::HiddenVisibility);
89 
90   if (Triple.isOSBinFormatELF()) {
91     // We assume that external begin/end symbols that we have created above will
92     // be defined by the linker. This is done whenever a section name with a
93     // valid C-identifier is present. We define a dummy variable here to force
94     // the linker to always provide these symbols.
95     auto *DummyEntry = new GlobalVariable(
96         M, ZeroInitilaizer->getType(), true, GlobalVariable::ExternalLinkage,
97         ZeroInitilaizer, "__dummy." + SectionName);
98     DummyEntry->setSection(SectionName);
99     DummyEntry->setVisibility(GlobalValue::HiddenVisibility);
100   } else {
101     // The COFF linker will merge sections containing a '$' together into a
102     // single section. The order of entries in this section will be sorted
103     // alphabetically by the characters following the '$' in the name. Set the
104     // sections here to ensure that the beginning and end symbols are sorted.
105     EntriesB->setSection((SectionName + "$OA").str());
106     EntriesE->setSection((SectionName + "$OZ").str());
107   }
108 
109   return std::make_pair(EntriesB, EntriesE);
110 }
111