17a6dacacSDimitry Andric //===- Utility.cpp ------ Collection of generic offloading utilities ------===// 25f757f3fSDimitry Andric // 35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65f757f3fSDimitry Andric // 75f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 85f757f3fSDimitry Andric 95f757f3fSDimitry Andric #include "llvm/Frontend/Offloading/Utility.h" 105f757f3fSDimitry Andric #include "llvm/IR/Constants.h" 115f757f3fSDimitry Andric #include "llvm/IR/GlobalValue.h" 125f757f3fSDimitry Andric #include "llvm/IR/GlobalVariable.h" 135f757f3fSDimitry Andric #include "llvm/IR/Value.h" 14*0fca6ea1SDimitry Andric #include "llvm/Transforms/Utils/ModuleUtils.h" 155f757f3fSDimitry Andric 165f757f3fSDimitry Andric using namespace llvm; 175f757f3fSDimitry Andric using namespace llvm::offloading; 185f757f3fSDimitry Andric 195f757f3fSDimitry Andric StructType *offloading::getEntryTy(Module &M) { 205f757f3fSDimitry Andric LLVMContext &C = M.getContext(); 215f757f3fSDimitry Andric StructType *EntryTy = 225f757f3fSDimitry Andric StructType::getTypeByName(C, "struct.__tgt_offload_entry"); 235f757f3fSDimitry Andric if (!EntryTy) 245f757f3fSDimitry Andric EntryTy = StructType::create( 255f757f3fSDimitry Andric "struct.__tgt_offload_entry", PointerType::getUnqual(C), 265f757f3fSDimitry Andric PointerType::getUnqual(C), M.getDataLayout().getIntPtrType(C), 275f757f3fSDimitry Andric Type::getInt32Ty(C), Type::getInt32Ty(C)); 285f757f3fSDimitry Andric return EntryTy; 295f757f3fSDimitry Andric } 305f757f3fSDimitry Andric 315f757f3fSDimitry Andric // TODO: Rework this interface to be more generic. 327a6dacacSDimitry Andric std::pair<Constant *, GlobalVariable *> 337a6dacacSDimitry Andric offloading::getOffloadingEntryInitializer(Module &M, Constant *Addr, 347a6dacacSDimitry Andric StringRef Name, uint64_t Size, 357a6dacacSDimitry Andric int32_t Flags, int32_t Data) { 36*0fca6ea1SDimitry Andric llvm::Triple Triple(M.getTargetTriple()); 375f757f3fSDimitry Andric Type *Int8PtrTy = PointerType::getUnqual(M.getContext()); 385f757f3fSDimitry Andric Type *Int32Ty = Type::getInt32Ty(M.getContext()); 395f757f3fSDimitry Andric Type *SizeTy = M.getDataLayout().getIntPtrType(M.getContext()); 405f757f3fSDimitry Andric 415f757f3fSDimitry Andric Constant *AddrName = ConstantDataArray::getString(M.getContext(), Name); 425f757f3fSDimitry Andric 43*0fca6ea1SDimitry Andric StringRef Prefix = 44*0fca6ea1SDimitry Andric Triple.isNVPTX() ? "$offloading$entry_name" : ".offloading.entry_name"; 45*0fca6ea1SDimitry Andric 465f757f3fSDimitry Andric // Create the constant string used to look up the symbol in the device. 47*0fca6ea1SDimitry Andric auto *Str = 48*0fca6ea1SDimitry Andric new GlobalVariable(M, AddrName->getType(), /*isConstant=*/true, 49*0fca6ea1SDimitry Andric GlobalValue::InternalLinkage, AddrName, Prefix); 505f757f3fSDimitry Andric Str->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); 515f757f3fSDimitry Andric 525f757f3fSDimitry Andric // Construct the offloading entry. 535f757f3fSDimitry Andric Constant *EntryData[] = { 545f757f3fSDimitry Andric ConstantExpr::getPointerBitCastOrAddrSpaceCast(Addr, Int8PtrTy), 555f757f3fSDimitry Andric ConstantExpr::getPointerBitCastOrAddrSpaceCast(Str, Int8PtrTy), 565f757f3fSDimitry Andric ConstantInt::get(SizeTy, Size), 575f757f3fSDimitry Andric ConstantInt::get(Int32Ty, Flags), 585f757f3fSDimitry Andric ConstantInt::get(Int32Ty, Data), 595f757f3fSDimitry Andric }; 605f757f3fSDimitry Andric Constant *EntryInitializer = ConstantStruct::get(getEntryTy(M), EntryData); 617a6dacacSDimitry Andric return {EntryInitializer, Str}; 627a6dacacSDimitry Andric } 637a6dacacSDimitry Andric 647a6dacacSDimitry Andric void offloading::emitOffloadingEntry(Module &M, Constant *Addr, StringRef Name, 657a6dacacSDimitry Andric uint64_t Size, int32_t Flags, int32_t Data, 667a6dacacSDimitry Andric StringRef SectionName) { 677a6dacacSDimitry Andric llvm::Triple Triple(M.getTargetTriple()); 687a6dacacSDimitry Andric 697a6dacacSDimitry Andric auto [EntryInitializer, NameGV] = 707a6dacacSDimitry Andric getOffloadingEntryInitializer(M, Addr, Name, Size, Flags, Data); 715f757f3fSDimitry Andric 72*0fca6ea1SDimitry Andric StringRef Prefix = 73*0fca6ea1SDimitry Andric Triple.isNVPTX() ? "$offloading$entry$" : ".offloading.entry."; 745f757f3fSDimitry Andric auto *Entry = new GlobalVariable( 755f757f3fSDimitry Andric M, getEntryTy(M), 765f757f3fSDimitry Andric /*isConstant=*/true, GlobalValue::WeakAnyLinkage, EntryInitializer, 77*0fca6ea1SDimitry Andric Prefix + Name, nullptr, GlobalValue::NotThreadLocal, 785f757f3fSDimitry Andric M.getDataLayout().getDefaultGlobalsAddressSpace()); 795f757f3fSDimitry Andric 805f757f3fSDimitry Andric // The entry has to be created in the section the linker expects it to be. 815f757f3fSDimitry Andric if (Triple.isOSBinFormatCOFF()) 825f757f3fSDimitry Andric Entry->setSection((SectionName + "$OE").str()); 835f757f3fSDimitry Andric else 845f757f3fSDimitry Andric Entry->setSection(SectionName); 855f757f3fSDimitry Andric Entry->setAlignment(Align(1)); 865f757f3fSDimitry Andric } 875f757f3fSDimitry Andric 885f757f3fSDimitry Andric std::pair<GlobalVariable *, GlobalVariable *> 895f757f3fSDimitry Andric offloading::getOffloadEntryArray(Module &M, StringRef SectionName) { 905f757f3fSDimitry Andric llvm::Triple Triple(M.getTargetTriple()); 915f757f3fSDimitry Andric 925f757f3fSDimitry Andric auto *ZeroInitilaizer = 935f757f3fSDimitry Andric ConstantAggregateZero::get(ArrayType::get(getEntryTy(M), 0u)); 945f757f3fSDimitry Andric auto *EntryInit = Triple.isOSBinFormatCOFF() ? ZeroInitilaizer : nullptr; 955f757f3fSDimitry Andric auto *EntryType = ArrayType::get(getEntryTy(M), 0); 96*0fca6ea1SDimitry Andric auto Linkage = Triple.isOSBinFormatCOFF() ? GlobalValue::WeakODRLinkage 97*0fca6ea1SDimitry Andric : GlobalValue::ExternalLinkage; 985f757f3fSDimitry Andric 99*0fca6ea1SDimitry Andric auto *EntriesB = 100*0fca6ea1SDimitry Andric new GlobalVariable(M, EntryType, /*isConstant=*/true, Linkage, EntryInit, 1015f757f3fSDimitry Andric "__start_" + SectionName); 1025f757f3fSDimitry Andric EntriesB->setVisibility(GlobalValue::HiddenVisibility); 103*0fca6ea1SDimitry Andric auto *EntriesE = 104*0fca6ea1SDimitry Andric new GlobalVariable(M, EntryType, /*isConstant=*/true, Linkage, EntryInit, 1055f757f3fSDimitry Andric "__stop_" + SectionName); 1065f757f3fSDimitry Andric EntriesE->setVisibility(GlobalValue::HiddenVisibility); 1075f757f3fSDimitry Andric 1085f757f3fSDimitry Andric if (Triple.isOSBinFormatELF()) { 1095f757f3fSDimitry Andric // We assume that external begin/end symbols that we have created above will 1105f757f3fSDimitry Andric // be defined by the linker. This is done whenever a section name with a 1115f757f3fSDimitry Andric // valid C-identifier is present. We define a dummy variable here to force 1125f757f3fSDimitry Andric // the linker to always provide these symbols. 1135f757f3fSDimitry Andric auto *DummyEntry = new GlobalVariable( 114*0fca6ea1SDimitry Andric M, ZeroInitilaizer->getType(), true, GlobalVariable::InternalLinkage, 1155f757f3fSDimitry Andric ZeroInitilaizer, "__dummy." + SectionName); 1165f757f3fSDimitry Andric DummyEntry->setSection(SectionName); 117*0fca6ea1SDimitry Andric appendToCompilerUsed(M, DummyEntry); 1185f757f3fSDimitry Andric } else { 1195f757f3fSDimitry Andric // The COFF linker will merge sections containing a '$' together into a 1205f757f3fSDimitry Andric // single section. The order of entries in this section will be sorted 1215f757f3fSDimitry Andric // alphabetically by the characters following the '$' in the name. Set the 1225f757f3fSDimitry Andric // sections here to ensure that the beginning and end symbols are sorted. 1235f757f3fSDimitry Andric EntriesB->setSection((SectionName + "$OA").str()); 1245f757f3fSDimitry Andric EntriesE->setSection((SectionName + "$OZ").str()); 1255f757f3fSDimitry Andric } 1265f757f3fSDimitry Andric 1275f757f3fSDimitry Andric return std::make_pair(EntriesB, EntriesE); 1285f757f3fSDimitry Andric } 129