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