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 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 *> 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 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 *> 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