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