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