diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -117,6 +117,8 @@ // IFUNC: [ifunc value type, addrspace, resolver val#, linkage, visibility] MODULE_CODE_IFUNC = 18, + + MODULE_CODE_DEVICE_TRIPLE = 19, // TRIPLE: [no, strchr x N] }; /// PARAMATTR blocks have code for defining a parameter attribute set. diff --git a/llvm/include/llvm/IR/GlobalValue.h b/llvm/include/llvm/IR/GlobalValue.h --- a/llvm/include/llvm/IR/GlobalValue.h +++ b/llvm/include/llvm/IR/GlobalValue.h @@ -80,14 +80,14 @@ UnnamedAddrVal(unsigned(UnnamedAddr::None)), DllStorageClass(DefaultStorageClass), ThreadLocal(NotThreadLocal), HasLLVMReservedName(false), IsDSOLocal(false), HasPartition(false), - IntID((Intrinsic::ID)0U), Parent(nullptr) { + DeviceNo(0), IntID((Intrinsic::ID)0U), Parent(nullptr) { setLinkage(Linkage); setName(Name); } Type *ValueType; - static const unsigned GlobalValueSubClassDataBits = 16; + static const unsigned GlobalValueSubClassDataBits = 11; // All bitfields use unsigned as the underlying type so that MSVC will pack // them. @@ -112,9 +112,14 @@ /// https://lld.llvm.org/Partitions.html). unsigned HasPartition : 1; + /// The device # this global is associated with, 0 for host/default device, + /// 1-31 for other devices. A device is in this context a reference to a + /// different target (triple). + unsigned DeviceNo : 5; + private: // Give subclasses access to what otherwise would be wasted padding. - // (16 + 4 + 2 + 2 + 2 + 3 + 1 + 1 + 1) == 32. + // (11 + 4 + 2 + 2 + 2 + 3 + 1 + 1 + 1 + 5) == 32. unsigned SubClassData : GlobalValueSubClassDataBits; friend class Constant; @@ -226,6 +231,16 @@ static_cast(this)->getComdat()); } + /// Return the device number this global is associated with, 0 for + /// host/default device. + unsigned char getDeviceNo() const { return DeviceNo; } + + /// Set the device number this global is associated with. + void setDeviceNo(unsigned DeviceNo) { + assert(DeviceNo < 32 && "device numbers have to be between 0 and 31"); + this->DeviceNo = DeviceNo; + } + VisibilityTypes getVisibility() const { return VisibilityTypes(Visibility); } bool hasDefaultVisibility() const { return Visibility == DefaultVisibility; } bool hasHiddenVisibility() const { return Visibility == HiddenVisibility; } diff --git a/llvm/include/llvm/IR/Module.h b/llvm/include/llvm/IR/Module.h --- a/llvm/include/llvm/IR/Module.h +++ b/llvm/include/llvm/IR/Module.h @@ -183,7 +183,8 @@ IFuncListType IFuncList; ///< The IFuncs in the module NamedMDListType NamedMDList; ///< The named metadata in the module std::string GlobalScopeAsm; ///< Inline Asm at global scope. - std::unique_ptr ValSymTab; ///< Symbol table for values + SmallVector, 2> + ValSymTab; ///< Symbol table(s) for values ComdatSymTabType ComdatSymTab; ///< Symbol table for COMDATs std::unique_ptr OwnedMemoryBuffer; ///< Memory buffer directly owned by this @@ -193,7 +194,8 @@ std::string ModuleID; ///< Human readable identifier for the module std::string SourceFileName; ///< Original source file name for module, ///< recorded in bitcode. - std::string TargetTriple; ///< Platform target triple Module compiled on + SmallVector + TargetTriples; ///< Platform target triple Module compiled on ///< Format: (arch)(sub)-(vendor)-(sys0-(abi) NamedMDSymTabType NamedMDSymTab; ///< NamedMDNode names. DataLayout DL; ///< DataLayout associated with the module @@ -244,9 +246,14 @@ /// Get the data layout for the module's target platform. const DataLayout &getDataLayout() const; - /// Get the target triple which is a string describing the target host. + /// Get the target triple which is a string describing the target device with + /// number \p DeviceNo. If more than a single device is present in the module the + /// device number is required, otherwise it can be ommited. + /// /// @returns a string containing the target triple. - const std::string &getTargetTriple() const { return TargetTriple; } + const std::string &getTargetTriple(int DeviceNo = 0) const { + return TargetTriples[DeviceNo]; + } /// Get the global data context. /// @returns LLVMContext - a container for LLVM's global information @@ -289,7 +296,10 @@ void setDataLayout(const DataLayout &Other); /// Set the target triple. - void setTargetTriple(StringRef T) { TargetTriple = std::string(T); } + void setTargetTriple(StringRef T, int DeviceNo = 0); + + /// TODO + size_t getNumTargetTriples() const { return TargetTriples.size(); } /// Set the module-scope inline assembly blocks. /// A trailing newline is added if the input doesn't have one. @@ -314,7 +324,7 @@ /// Return the global value in the module with the specified name, of /// arbitrary type. This method returns null if a global with the specified /// name is not found. - GlobalValue *getNamedValue(StringRef Name) const; + GlobalValue *getNamedValue(StringRef Name, unsigned DeviceNo = 0) const; /// Return a unique non-zero ID for the specified metadata kind. This ID is /// uniqued across modules in the current LLVMContext. @@ -396,27 +406,27 @@ /// does not exist, return null. If AllowInternal is set to true, this /// function will return types that have InternalLinkage. By default, these /// types are not returned. - GlobalVariable *getGlobalVariable(StringRef Name) const { - return getGlobalVariable(Name, false); + GlobalVariable *getGlobalVariable(StringRef Name, unsigned DeviceNo = 0) const { + return getGlobalVariable(Name, false, DeviceNo); } - GlobalVariable *getGlobalVariable(StringRef Name, bool AllowInternal) const; + GlobalVariable *getGlobalVariable(StringRef Name, bool AllowInternal, unsigned DeviceNo = 0) const; GlobalVariable *getGlobalVariable(StringRef Name, - bool AllowInternal = false) { + bool AllowInternal = false, unsigned DeviceNo = 0) { return static_cast(this)->getGlobalVariable(Name, - AllowInternal); + AllowInternal, DeviceNo); } /// Return the global variable in the module with the specified name, of /// arbitrary type. This method returns null if a global with the specified /// name is not found. - const GlobalVariable *getNamedGlobal(StringRef Name) const { - return getGlobalVariable(Name, true); + const GlobalVariable *getNamedGlobal(StringRef Name, unsigned DeviceNo = 0) const { + return getGlobalVariable(Name, true, DeviceNo); } - GlobalVariable *getNamedGlobal(StringRef Name) { + GlobalVariable *getNamedGlobal(StringRef Name, unsigned DeviceNo = 0) { return const_cast( - static_cast(this)->getNamedGlobal(Name)); + static_cast(this)->getNamedGlobal(Name, DeviceNo)); } /// Look up the specified global in the module symbol table. @@ -576,9 +586,9 @@ } /// Get the symbol table of global variable and function identifiers - const ValueSymbolTable &getValueSymbolTable() const { return *ValSymTab; } + const ValueSymbolTable &getValueSymbolTable(unsigned DeviceNo = 0) const { return *(ValSymTab[DeviceNo]); } /// Get the Module's symbol table of global variable and function identifiers. - ValueSymbolTable &getValueSymbolTable() { return *ValSymTab; } + ValueSymbolTable &getValueSymbolTable(unsigned DeviceNo = 0) { return *(ValSymTab[DeviceNo]); } /// Get the Module's symbol table for COMDATs (constant). const ComdatSymTabType &getComdatSymbolTable() const { return ComdatSymTab; } diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -539,6 +539,7 @@ KEYWORD(musttail); KEYWORD(notail); KEYWORD(target); + KEYWORD(device); KEYWORD(triple); KEYWORD(source_filename); KEYWORD(unwind); diff --git a/llvm/lib/AsmParser/LLParser.h b/llvm/lib/AsmParser/LLParser.h --- a/llvm/lib/AsmParser/LLParser.h +++ b/llvm/lib/AsmParser/LLParser.h @@ -265,6 +265,7 @@ }; bool ParseOptionalParamAttrs(AttrBuilder &B); bool ParseOptionalReturnAttrs(AttrBuilder &B); + bool ParseOptionalDevice(unsigned &DeviceNo); bool ParseOptionalLinkage(unsigned &Res, bool &HasLinkage, unsigned &Visibility, unsigned &DLLStorageClass, bool &DSOLocal); @@ -302,6 +303,7 @@ bool ValidateEndOfIndex(); bool ParseTargetDefinitions(); bool ParseTargetDefinition(); + bool ParseDeviceDefinition(); bool ParseModuleAsm(); bool ParseSourceFileName(); bool ParseDepLibs(); // FIXME: Remove in 4.0. @@ -313,13 +315,13 @@ bool ParseGlobalType(bool &IsConstant); bool ParseUnnamedGlobal(); bool ParseNamedGlobal(); - bool ParseGlobal(const std::string &Name, LocTy NameLoc, unsigned Linkage, - bool HasLinkage, unsigned Visibility, + bool ParseGlobal(const std::string &Name, LocTy NameLoc, unsigned DeviceNo, + unsigned Linkage, bool HasLinkage, unsigned Visibility, unsigned DLLStorageClass, bool DSOLocal, GlobalVariable::ThreadLocalMode TLM, GlobalVariable::UnnamedAddr UnnamedAddr); bool parseIndirectSymbol(const std::string &Name, LocTy NameLoc, - unsigned L, unsigned Visibility, + unsigned DeviceNo, unsigned L, unsigned Visibility, unsigned DLLStorageClass, bool DSOLocal, GlobalVariable::ThreadLocalMode TLM, GlobalVariable::UnnamedAddr UnnamedAddr); diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -308,6 +308,10 @@ if (ParseTargetDefinition()) return true; break; + case lltok::kw_device: + if (ParseDeviceDefinition()) + return true; + break; case lltok::kw_source_filename: if (ParseSourceFileName()) return true; @@ -407,6 +411,26 @@ } } +/// toplevelentity +/// ::= ['device' uint32] 'triple' '=' STRINGCONSTANT +bool LLParser::ParseDeviceDefinition() { + assert(Lex.getKind() == lltok::kw_device); + unsigned DeviceNo = 0; + if (ParseOptionalDevice(DeviceNo)) + return true; + std::string Str; + switch (Lex.getKind()) { + default: return TokError("unknown target property"); + case lltok::kw_triple: + Lex.Lex(); + if (ParseToken(lltok::equal, "expected '=' after target triple") || + ParseStringConstant(Str)) + return true; + M->setTargetTriple(Str, DeviceNo); + return false; + } +} + /// toplevelentity /// ::= 'source_filename' '=' STRINGCONSTANT bool LLParser::ParseSourceFileName() { @@ -561,9 +585,9 @@ /// OptionalLinkage OptionalPreemptionSpecifier OptionalVisibility /// OptionalDLLStorageClass /// ... -> global variable -/// GlobalID '=' OptionalVisibility (ALIAS | IFUNC) ... -/// GlobalID '=' OptionalLinkage OptionalPreemptionSpecifier OptionalVisibility -/// OptionalDLLStorageClass +/// GlobalID '=' OptionalDevice OptionalVisibility (ALIAS | IFUNC) ... +/// GlobalID '=' OptionalDevice OptionalLinkage OptionalPreemptionSpecifier +/// OptionalVisibility OptionalDLLStorageClass /// ... -> global variable bool LLParser::ParseUnnamedGlobal() { unsigned VarID = NumberedVals.size(); @@ -581,27 +605,29 @@ return true; } + unsigned DeviceNo; bool HasLinkage; unsigned Linkage, Visibility, DLLStorageClass; bool DSOLocal; GlobalVariable::ThreadLocalMode TLM; GlobalVariable::UnnamedAddr UnnamedAddr; - if (ParseOptionalLinkage(Linkage, HasLinkage, Visibility, DLLStorageClass, + if (ParseOptionalDevice(DeviceNo) || + ParseOptionalLinkage(Linkage, HasLinkage, Visibility, DLLStorageClass, DSOLocal) || ParseOptionalThreadLocal(TLM) || ParseOptionalUnnamedAddr(UnnamedAddr)) return true; if (Lex.getKind() != lltok::kw_alias && Lex.getKind() != lltok::kw_ifunc) - return ParseGlobal(Name, NameLoc, Linkage, HasLinkage, Visibility, + return ParseGlobal(Name, NameLoc, DeviceNo, Linkage, HasLinkage, Visibility, DLLStorageClass, DSOLocal, TLM, UnnamedAddr); - return parseIndirectSymbol(Name, NameLoc, Linkage, Visibility, + return parseIndirectSymbol(Name, NameLoc, DeviceNo, Linkage, Visibility, DLLStorageClass, DSOLocal, TLM, UnnamedAddr); } /// ParseNamedGlobal: -/// GlobalVar '=' OptionalVisibility (ALIAS | IFUNC) ... -/// GlobalVar '=' OptionalLinkage OptionalPreemptionSpecifier +/// GlobalVar '=' OptionalDevice OptionalVisibility (ALIAS | IFUNC) ... +/// GlobalVar '=' OptionalDevice OptionalLinkage OptionalPreemptionSpecifier /// OptionalVisibility OptionalDLLStorageClass /// ... -> global variable bool LLParser::ParseNamedGlobal() { @@ -610,22 +636,24 @@ std::string Name = Lex.getStrVal(); Lex.Lex(); + unsigned DeviceNo; bool HasLinkage; unsigned Linkage, Visibility, DLLStorageClass; bool DSOLocal; GlobalVariable::ThreadLocalMode TLM; GlobalVariable::UnnamedAddr UnnamedAddr; if (ParseToken(lltok::equal, "expected '=' in global variable") || + ParseOptionalDevice(DeviceNo) || ParseOptionalLinkage(Linkage, HasLinkage, Visibility, DLLStorageClass, DSOLocal) || ParseOptionalThreadLocal(TLM) || ParseOptionalUnnamedAddr(UnnamedAddr)) return true; if (Lex.getKind() != lltok::kw_alias && Lex.getKind() != lltok::kw_ifunc) - return ParseGlobal(Name, NameLoc, Linkage, HasLinkage, Visibility, + return ParseGlobal(Name, NameLoc, DeviceNo, Linkage, HasLinkage, Visibility, DLLStorageClass, DSOLocal, TLM, UnnamedAddr); - return parseIndirectSymbol(Name, NameLoc, Linkage, Visibility, + return parseIndirectSymbol(Name, NameLoc, DeviceNo, Linkage, Visibility, DLLStorageClass, DSOLocal, TLM, UnnamedAddr); } @@ -901,7 +929,8 @@ /// Everything through OptionalUnnamedAddr has already been parsed. /// bool LLParser::parseIndirectSymbol(const std::string &Name, LocTy NameLoc, - unsigned L, unsigned Visibility, + unsigned DeviceNo, unsigned L, + unsigned Visibility, unsigned DLLStorageClass, bool DSOLocal, GlobalVariable::ThreadLocalMode TLM, GlobalVariable::UnnamedAddr UnnamedAddr) { @@ -991,6 +1020,7 @@ GA.reset(GlobalIFunc::create(Ty, AddrSpace, (GlobalValue::LinkageTypes)Linkage, Name, Aliasee, /*Parent*/ nullptr)); + GA->setDeviceNo(DeviceNo); GA->setThreadLocalMode(TLM); GA->setVisibility((GlobalValue::VisibilityTypes)Visibility); GA->setDLLStorageClass((GlobalValue::DLLStorageClassTypes)DLLStorageClass); @@ -1055,7 +1085,7 @@ /// already. /// bool LLParser::ParseGlobal(const std::string &Name, LocTy NameLoc, - unsigned Linkage, bool HasLinkage, + unsigned DeviceNo, unsigned Linkage, bool HasLinkage, unsigned Visibility, unsigned DLLStorageClass, bool DSOLocal, GlobalVariable::ThreadLocalMode TLM, GlobalVariable::UnnamedAddr UnnamedAddr) { @@ -1130,6 +1160,7 @@ if (Init) GV->setInitializer(Init); GV->setConstant(IsConstant); + GV->setDeviceNo(DeviceNo); GV->setLinkage((GlobalValue::LinkageTypes)Linkage); maybeSetDSOLocal(DSOLocal, *GV); GV->setVisibility((GlobalValue::VisibilityTypes)Visibility); @@ -1898,6 +1929,21 @@ } } +/// ParseOptionalDevice +/// ::= /*empty*/ +/// ::= 'device uint32 ' +bool LLParser::ParseOptionalDevice(unsigned &DeviceNo) { + DeviceNo = 0; + if (!EatIfPresent(lltok::kw_device)) + return false; + const auto &DeviceNoLoc = Lex.getLoc(); + if (ParseUInt32(DeviceNo)) + return true; + if (DeviceNo == 0 || DeviceNo > 31) + return Error(DeviceNoLoc, "device numbers have to be between 1 and 31"); + return false; +} + /// ParseOptionalLinkage /// ::= /*empty*/ /// ::= 'private' @@ -5452,13 +5498,14 @@ } /// FunctionHeader -/// ::= OptionalLinkage OptionalPreemptionSpecifier OptionalVisibility -/// OptionalCallingConv OptRetAttrs OptUnnamedAddr Type GlobalName -/// '(' ArgList ')' OptAddrSpace OptFuncAttrs OptSection OptionalAlign -/// OptGC OptionalPrefix OptionalPrologue OptPersonalityFn +/// ::= OptionalDevice OptionalLinkage OptionalPreemptionSpecifier +/// OptionalVisibility OptionalCallingConv OptRetAttrs OptUnnamedAddr Type +/// GlobalName '(' ArgList ')' OptAddrSpace OptFuncAttrs OptSection +/// OptionalAlign OptGC OptionalPrefix OptionalPrologue OptPersonalityFn bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) { // Parse the linkage. LocTy LinkageLoc = Lex.getLoc(); + unsigned DeviceNo; unsigned Linkage; unsigned Visibility; unsigned DLLStorageClass; @@ -5468,7 +5515,8 @@ bool HasLinkage; Type *RetType = nullptr; LocTy RetTypeLoc = Lex.getLoc(); - if (ParseOptionalLinkage(Linkage, HasLinkage, Visibility, DLLStorageClass, + if (ParseOptionalDevice(DeviceNo) || + ParseOptionalLinkage(Linkage, HasLinkage, Visibility, DLLStorageClass, DSOLocal) || ParseOptionalCallingConv(CC) || ParseOptionalReturnAttrs(RetAttrs) || ParseType(RetType, RetTypeLoc, true /*void allowed*/)) @@ -5641,6 +5689,7 @@ if (FunctionName.empty()) NumberedVals.push_back(Fn); + Fn->setDeviceNo(DeviceNo); Fn->setLinkage((GlobalValue::LinkageTypes)Linkage); maybeSetDSOLocal(DSOLocal, *Fn); Fn->setVisibility((GlobalValue::VisibilityTypes)Visibility); diff --git a/llvm/lib/AsmParser/LLToken.h b/llvm/lib/AsmParser/LLToken.h --- a/llvm/lib/AsmParser/LLToken.h +++ b/llvm/lib/AsmParser/LLToken.h @@ -85,6 +85,7 @@ kw_notail, kw_target, kw_triple, + kw_device, kw_source_filename, kw_unwind, kw_deplibs, // FIXME: Remove in 4.0 diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -3139,7 +3139,7 @@ // v1: [pointer type, isconst, initid, linkage, alignment, section, // visibility, threadlocal, unnamed_addr, externally_initialized, // dllstorageclass, comdat, attributes, preemption specifier, - // partition strtab offset, partition strtab size] (name in VST) + // partition strtab offset, partition strtab size, device #] (name in VST) // v2: [strtab_offset, strtab_size, v1] StringRef Name; std::tie(Name, Record) = readNameFromStrtab(Record); @@ -3238,13 +3238,20 @@ if (Record.size() > 15) NewGV->setPartition(StringRef(Strtab.data() + Record[14], Record[15])); + if (Record.size() > 16) { + if (Record[16] <= 0 || Record[16] > 31) + return error("Invalid ID"); + NewGV->setDeviceNo(Record[16]); + } + return Error::success(); } Error BitcodeReader::parseFunctionRecord(ArrayRef Record) { // v1: [type, callingconv, isproto, linkage, paramattr, alignment, section, // visibility, gc, unnamed_addr, prologuedata, dllstorageclass, comdat, - // prefixdata, personalityfn, preemption specifier, addrspace] (name in VST) + // prefixdata, personalityfn, preemption specifier, addrspace, + // device #] (name in VST) // v2: [strtab_offset, strtab_size, v1] StringRef Name; std::tie(Name, Record) = readNameFromStrtab(Record); @@ -3364,6 +3371,13 @@ FunctionsWithBodies.push_back(Func); DeferredFunctionInfo[Func] = 0; } + + if (Record.size() > 19) { + if (Record[19] <= 0 || Record[19] > 31) + return error("Invalid ID"); + Func->setDeviceNo(Record[19]); + } + return Error::success(); } @@ -3372,10 +3386,10 @@ // v1 ALIAS_OLD: [alias type, aliasee val#, linkage] (name in VST) // v1 ALIAS: [alias type, addrspace, aliasee val#, linkage, visibility, // dllstorageclass, threadlocal, unnamed_addr, - // preemption specifier] (name in VST) + // preemption specifier, device #] (name in VST) // v1 IFUNC: [alias type, addrspace, aliasee val#, linkage, // visibility, dllstorageclass, threadlocal, unnamed_addr, - // preemption specifier] (name in VST) + // preemption specifier, device #] (name in VST) // v2: [strtab_offset, strtab_size, v1] StringRef Name; std::tie(Name, Record) = readNameFromStrtab(Record); @@ -3442,6 +3456,12 @@ OpNum += 2; } + if (Record.size() > OpNum) { + if (Record[OpNum] <= 0 || Record[OpNum] > 31) + return error("Invalid ID"); + NewGA->setDeviceNo(Record[OpNum]); + } + FullTy = PointerType::get(FullTy, AddrSpace); assert(NewGA->getType() == flattenPointerTypes(FullTy) && "Incorrect fully structured type provided for GlobalIndirectSymbol"); @@ -3653,6 +3673,18 @@ TheModule->setTargetTriple(S); break; } + case bitc::MODULE_CODE_DEVICE_TRIPLE: { // DEVICE TRIPLE: [no, strchr x N] + if (Record.size() < 1) + return error("Invalid record"); + uint64_t DeviceNo = Record.back(); + if (DeviceNo == 0) + return error("device numbers shall be positive"); + std::string S; + if (convertToString(ArrayRef(&Record[0], Record.size() - 1), 0, S)) + return error("Invalid record"); + TheModule->setTargetTriple(S, DeviceNo); + break; + } case bitc::MODULE_CODE_DATALAYOUT: { // DATALAYOUT: [strchr x N] if (ResolvedDataLayout) return error("datalayout too late in module"); diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -595,6 +595,24 @@ Stream.EmitRecord(Code, Vals, AbbrevToUse); } +static void writeNumberedStringRecord(BitstreamWriter &Stream, unsigned Code, + StringRef Str, unsigned No, + unsigned AbbrevToUse) { + SmallVector Vals; + + // Code: [No, strchar x N] + for (unsigned i = 0, e = Str.size(); i != e; ++i) { + if (AbbrevToUse && !BitCodeAbbrevOp::isChar6(Str[i])) + AbbrevToUse = 0; + Vals.push_back(Str[i]); + } + + Vals.push_back(No); + + // Emit the finished record. + Stream.EmitRecord(Code, Vals, AbbrevToUse); +} + static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) { switch (Kind) { case Attribute::Alignment: @@ -1170,6 +1188,10 @@ if (!M.getTargetTriple().empty()) writeStringRecord(Stream, bitc::MODULE_CODE_TRIPLE, M.getTargetTriple(), 0 /*TODO*/); + for (unsigned u = 1, e = M.getNumTargetTriples(); u < e; u++) + if (!M.getTargetTriple(u).empty()) + writeNumberedStringRecord(Stream, bitc::MODULE_CODE_DEVICE_TRIPLE, + M.getTargetTriple(u), u, 0 /*TODO*/); const std::string &DL = M.getDataLayoutStr(); if (!DL.empty()) writeStringRecord(Stream, bitc::MODULE_CODE_DATALAYOUT, DL, 0 /*TODO*/); @@ -1300,7 +1322,8 @@ GV.hasComdat() || GV.hasAttributes() || GV.isDSOLocal() || - GV.hasPartition()) { + GV.hasPartition() || + GV.getDeviceNo()) { Vals.push_back(getEncodedVisibility(GV)); Vals.push_back(getEncodedThreadLocalMode(GV)); Vals.push_back(getEncodedUnnamedAddr(GV)); @@ -1314,6 +1337,7 @@ Vals.push_back(GV.isDSOLocal()); Vals.push_back(addToStrtab(GV.getPartition())); Vals.push_back(GV.getPartition().size()); + Vals.push_back(GV.getDeviceNo()); } else { AbbrevToUse = SimpleGVarAbbrev; } @@ -1354,6 +1378,7 @@ Vals.push_back(F.getAddressSpace()); Vals.push_back(addToStrtab(F.getPartition())); Vals.push_back(F.getPartition().size()); + Vals.push_back(F.getDeviceNo()); unsigned AbbrevToUse = 0; Stream.EmitRecord(bitc::MODULE_CODE_FUNCTION, Vals, AbbrevToUse); @@ -1378,6 +1403,7 @@ Vals.push_back(A.isDSOLocal()); Vals.push_back(addToStrtab(A.getPartition())); Vals.push_back(A.getPartition().size()); + Vals.push_back(A.getDeviceNo()); unsigned AbbrevToUse = 0; Stream.EmitRecord(bitc::MODULE_CODE_ALIAS, Vals, AbbrevToUse); @@ -1398,6 +1424,7 @@ Vals.push_back(I.isDSOLocal()); Vals.push_back(addToStrtab(I.getPartition())); Vals.push_back(I.getPartition().size()); + Vals.push_back(I.getDeviceNo()); Stream.EmitRecord(bitc::MODULE_CODE_IFUNC, Vals); Vals.clear(); } diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -2684,6 +2684,10 @@ Out << "target datalayout = \"" << DL << "\"\n"; if (!M->getTargetTriple().empty()) Out << "target triple = \"" << M->getTargetTriple() << "\"\n"; + for (unsigned u = 1, e = M->getNumTargetTriples(); u < e; u++) + if (!M->getTargetTriple(u).empty()) + Out << "device " << u << " triple = \"" << M->getTargetTriple(u) + << "\"\n"; if (!M->getModuleInlineAsm().empty()) { Out << '\n'; @@ -3402,6 +3406,9 @@ WriteAsOperandInternal(Out, GV, &TypePrinter, &Machine, GV->getParent()); Out << " = "; + if (unsigned DeviceNo = GV->getDeviceNo()) + Out << "device " << DeviceNo << " "; + if (!GV->hasInitializer() && GV->hasExternalLinkage()) Out << "external "; @@ -3458,6 +3465,9 @@ WriteAsOperandInternal(Out, GIS, &TypePrinter, &Machine, GIS->getParent()); Out << " = "; + if (unsigned DeviceNo = GIS->getDeviceNo()) + Out << "device " << DeviceNo << " "; + Out << getLinkageNameWithSpace(GIS->getLinkage()); PrintDSOLocation(*GIS, Out); PrintVisibility(GIS->getVisibility(), Out); @@ -3564,6 +3574,9 @@ } else Out << "define "; + if (unsigned DeviceNo = F->getDeviceNo()) + Out << "device " << DeviceNo << " "; + Out << getLinkageNameWithSpace(F->getLinkage()); PrintDSOLocation(*F, Out); PrintVisibility(F->getVisibility(), Out); diff --git a/llvm/lib/IR/Module.cpp b/llvm/lib/IR/Module.cpp --- a/llvm/lib/IR/Module.cpp +++ b/llvm/lib/IR/Module.cpp @@ -72,9 +72,10 @@ // Module::Module(StringRef MID, LLVMContext &C) - : Context(C), ValSymTab(std::make_unique()), + : Context(C), Materializer(), ModuleID(std::string(MID)), SourceFileName(std::string(MID)), DL("") { + ValSymTab.push_back(std::make_unique()); Context.addModule(this); } @@ -87,6 +88,13 @@ IFuncList.clear(); } +void Module::setTargetTriple(StringRef T, int DeviceNo) { + ValSymTab.resize(std::max(ValSymTab.size(), size_t(DeviceNo + 1))); + ValSymTab[DeviceNo] = std::make_unique(); + TargetTriples.resize(std::max(TargetTriples.size(), size_t(DeviceNo + 1))); + TargetTriples[DeviceNo] = std::string(T); +} + std::unique_ptr Module::createRNG(const StringRef Name) const { SmallString<32> Salt(Name); @@ -110,8 +118,8 @@ /// getNamedValue - Return the first global value in the module with /// the specified name, of arbitrary type. This method returns null /// if a global with the specified name is not found. -GlobalValue *Module::getNamedValue(StringRef Name) const { - return cast_or_null(getValueSymbolTable().lookup(Name)); +GlobalValue *Module::getNamedValue(StringRef Name, unsigned DeviceNo) const { + return cast_or_null(getValueSymbolTable(DeviceNo).lookup(Name)); } /// getMDKindID - Return a unique non-zero ID for the specified metadata kind. @@ -186,10 +194,10 @@ /// If AllowLocal is set to true, this function will return types that /// have an local. By default, these types are not returned. /// -GlobalVariable *Module::getGlobalVariable(StringRef Name, - bool AllowLocal) const { +GlobalVariable *Module::getGlobalVariable(StringRef Name, bool AllowLocal, + unsigned DeviceNo) const { if (GlobalVariable *Result = - dyn_cast_or_null(getNamedValue(Name))) + dyn_cast_or_null(getNamedValue(Name, DeviceNo))) if (AllowLocal || !Result->hasLocalLinkage()) return Result; return nullptr; diff --git a/llvm/test/Bitcode/compatibility.ll b/llvm/test/Bitcode/compatibility.ll --- a/llvm/test/Bitcode/compatibility.ll +++ b/llvm/test/Bitcode/compatibility.ll @@ -14,6 +14,13 @@ target triple = "x86_64-apple-macosx10.10.0" ; CHECK: target triple = "x86_64-apple-macosx10.10.0" +device 1 triple = "mips-unknown-linux-gnu" +; CHECK: device 1 triple = "mips-unknown-linux-gnu" +device 2 triple = "mips-unknown-linux-gnu" +; CHECK: device 2 triple = "mips-unknown-linux-gnu" +device 31 triple = "nvptx64-unknown-cuda" +; CHECK: device 31 triple = "nvptx64-unknown-cuda" + ;; Module-level assembly module asm "beep boop" ; CHECK: module asm "beep boop" @@ -79,7 +86,7 @@ @constant.vector.f64 = constant <3 x double> ;; Global Variables -; Format: [@ =] [Linkage] [Visibility] [DLLStorageClass] +; Format: [@ =] [Device] [Linkage] [Visibility] [DLLStorageClass] ; [ThreadLocal] [(unnamed_addr|local_unnamed_addr)] [AddrSpace] [ExternallyInitialized] ; [] ; [, section "name"] [, comdat [($name)]] [, align ] @@ -90,6 +97,34 @@ @g2 = constant i32 0 ; CHECK: @g2 = constant i32 0 +; Global Variables -- Device +@g1_d31 = device 31 global i32 0 +; CHECK: @g1_d31 = device 31 global i32 0 +@g2_d1 = device 1 constant i32 0 +; CHECK: @g2_d1 = device 1 constant i32 0 +@g.private_d2 = device 2 private global i32 0 +; CHECK: @g.private_d2 = device 2 private global i32 0 +@g.internal_d31 = device 31 internal global i32 0 +; CHECK: @g.internal_d31 = device 31 internal global i32 0 +@g.available_externally_d1 = device 1 available_externally global i32 0 +; CHECK: @g.available_externally_d1 = device 1 available_externally global i32 0 +@g.linkonce_d2 = device 2 linkonce global i32 0 +; CHECK: @g.linkonce_d2 = device 2 linkonce global i32 0 +@g.weak_d31 = device 31 weak global i32 0 +; CHECK: @g.weak_d31 = device 31 weak global i32 0 +@g.common_d1 = device 1 common global i32 0 +; CHECK: @g.common_d1 = device 1 common global i32 0 +@g.appending_d2 = device 2 appending global [4 x i8] c"test" +; CHECK: @g.appending_d2 = device 2 appending global [4 x i8] c"test" +@g.extern_weak_d31 = device 31 extern_weak global i32 +; CHECK: @g.extern_weak_d31 = device 31 extern_weak global i32 +@g.linkonce_odr_d1 = device 1 linkonce_odr global i32 0 +; CHECK: @g.linkonce_odr_d1 = device 1 linkonce_odr global i32 0 +@g.weak_odr_d2 = device 2 weak_odr global i32 0 +; CHECK: @g.weak_odr_d2 = device 2 weak_odr global i32 0 +@g.external_d31 = device 31 external global i32 +; CHECK: @g.external_d31 = device 31 external global i32 + ; Global Variables -- Linkage @g.private = private global i32 0 ; CHECK: @g.private = private global i32 0 @@ -204,9 +239,25 @@ ; CHECK: @llvm.global_dtors = appending global [1 x %pri.func.data] [%pri.func.data { i32 0, void ()* @g.f1, i8* @g.used3 }], section "llvm.metadata" ;; Aliases -; Format: @ = [Linkage] [Visibility] [DLLStorageClass] [ThreadLocal] +; Format: @ = [Device] [Linkage] [Visibility] [DLLStorageClass] [ThreadLocal] ; [unnamed_addr] alias @ +; Aliases -- Device +@a.private1 = device 1 private alias i32, i32* @g.private +; CHECK: @a.private = device 1 private alias i32, i32* @g.private +@a.internal_d2 = device 2 internal alias i32, i32* @g.internal +; CHECK: @a.internal_d2 = device 2 internal alias i32, i32* @g.internal +@a.linkonce_d31 = device 31 linkonce alias i32, i32* @g.linkonce +; CHECK: @a.linkonce_d31 = device 31 linkonce alias i32, i32* @g.linkonce +@a.weak_d1 = device 1 weak alias i32, i32* @g.weak +; CHECK: @a.weak_d1 = device 1 weak alias i32, i32* @g.weak +@a.linkonce_odr_d2 = device 2 linkonce_odr alias i32, i32* @g.linkonce_odr +; CHECK: @a.linkonce_odr_d2 = device 2 linkonce_odr alias i32, i32* @g.linkonce_odr +@a.weak_odr_d31 = device 31 weak_odr alias i32, i32* @g.weak_odr +; CHECK: @a.weak_odr_d31 = device 31 weak_odr alias i32, i32* @g.weak_odr +@a.external_d1 = device 1 external alias i32, i32* @g1 +; CHECK: @a.external_d1 = device 1 alias i32, i32* @g1 + ; Aliases -- Linkage @a.private = private alias i32, i32* @g.private ; CHECK: @a.private = private alias i32, i32* @g.private @@ -260,9 +311,17 @@ @alias.partition = alias i32, i32* @g.partition, partition "part" ;; IFunc -; Format @ = [Linkage] [Visibility] ifunc , +; Format @ = [Device] [Linkage] [Visibility] ifunc , ; * @ +; IFunc -- Device +@ifunc.external_d1 = device 1 external ifunc void (), i8* ()* @ifunc_resolver +; CHECK: @ifunc.external_d1 = device 1 ifunc void (), i8* ()* @ifunc_resolver +@ifunc.private_d2 = device 2 private ifunc void (), i8* ()* @ifunc_resolver +; CHECK: @ifunc.private_d2 = device 2 private ifunc void (), i8* ()* @ifunc_resolver +@ifunc.internal_d31 = device 31 internal ifunc void (), i8* ()* @ifunc_resolver +; CHECK: @ifunc.internal_d31 = device 31 internal ifunc void (), i8* ()* @ifunc_resolver + ; IFunc -- Linkage @ifunc.external = external ifunc void (), i8* ()* @ifunc_resolver ; CHECK: @ifunc.external = ifunc void (), i8* ()* @ifunc_resolver @@ -289,7 +348,7 @@ } ;; Functions -; Format: define [linkage] [visibility] [DLLStorageClass] +; Format: define [device] [linkage] [visibility] [DLLStorageClass] ; [cconv] [ret attrs] ; @ ([argument list]) ; [(unnamed_addr|local_unnamed_addr)] [fn Attrs] [section "name"] [comdat [($name)]] @@ -306,6 +365,56 @@ ret void } +; Functions -- Device +declare device 1 void @f1_d1 () +; CHECK: declare device 1 void @f1_d1() + +define device 2 void @f2_d2 () { +; CHECK: define device 2 void @f2_d2() +entry: + ret void +} + +define device 31 private void @f.private_d31() { +; CHECK: define device 31 private void @f.private_d31() +entry: + ret void +} +define device 1 internal void @f.internal_d1() { +; CHECK: define device 1 internal void @f.internal_d1() +entry: + ret void +} +define device 2 available_externally void @f.available_externally_d2() { +; CHECK: define device 2 available_externally void @f.available_externally_d2() +entry: + ret void +} +define device 31 linkonce void @f.linkonce_d31() { +; CHECK: define device 31 linkonce void @f.linkonce_d31() +entry: + ret void +} +define device 1 weak void @f.weak_d1() { +; CHECK: define device 1 weak void @f.weak_d1() +entry: + ret void +} +define device 2 linkonce_odr void @f.linkonce_odr_d2() { +; CHECK: define device 2 linkonce_odr void @f.linkonce_odr_d2() +entry: + ret void +} +define device 31 weak_odr void @f.weak_odr_d31() { +; CHECK: define device 31 weak_odr void @f.weak_odr_d31() +entry: + ret void +} +declare device 1 external void @f.external_d1() +; CHECK: declare device 1 void @f.external_d1() +declare device 2 extern_weak void @f.extern_weak_d2() +; CHECK: declare device 2 extern_weak void @f.extern_weak_d2() + ; Functions -- linkage define private void @f.private() { ; CHECK: define private void @f.private()