Index: llvm/trunk/docs/LangRef.rst =================================================================== --- llvm/trunk/docs/LangRef.rst +++ llvm/trunk/docs/LangRef.rst @@ -719,7 +719,7 @@ :ref:`parameter attribute ` for the return type, a function name, a (possibly empty) argument list (each with optional :ref:`parameter attributes `), optional :ref:`function attributes `, -an optional section, an optional alignment, +an optional address space, an optional section, an optional alignment, an optional :ref:`comdat `, an optional :ref:`garbage collector name `, an optional :ref:`prefix `, an optional :ref:`prologue `, @@ -731,8 +731,8 @@ optional :ref:`linkage type `, an optional :ref:`visibility style `, an optional :ref:`DLL storage class `, an optional :ref:`calling convention `, an optional ``unnamed_addr`` -or ``local_unnamed_addr`` attribute, a return type, an optional :ref:`parameter -attribute ` for the return type, a function name, a possibly +or ``local_unnamed_addr`` attribute, an optional address space, a return type, +an optional :ref:`parameter attribute ` for the return type, a function name, a possibly empty list of arguments, an optional alignment, an optional :ref:`garbage collector name `, an optional :ref:`prefix `, and an optional :ref:`prologue `. @@ -769,13 +769,16 @@ If the ``local_unnamed_addr`` attribute is given, the address is known to not be significant within the module. +If an explicit address space is not given, it will default to the program +address space from the :ref:`datalayout string`. + Syntax:: define [linkage] [PreemptionSpecifier] [visibility] [DLLStorageClass] [cconv] [ret attrs] @ ([argument list]) - [(unnamed_addr|local_unnamed_addr)] [fn Attrs] [section "name"] - [comdat [($name)]] [align N] [gc] [prefix Constant] + [(unnamed_addr|local_unnamed_addr)] [AddrSpace] [fn Attrs] + [section "name"] [comdat [($name)]] [align N] [gc] [prefix Constant] [prologue Constant] [personality Constant] (!name !N)* { ... } The argument list is a comma separated sequence of arguments where each @@ -6452,7 +6455,7 @@ :: - = invoke [cconv] [ret attrs] | () [fn attrs] + = invoke [cconv] [ret attrs] [addrspace()] [| () [fn attrs] [operand bundles] to label unwind label Overview: @@ -6488,6 +6491,9 @@ #. The optional :ref:`Parameter Attributes ` list for return values. Only '``zeroext``', '``signext``', and '``inreg``' attributes are valid here. +#. The optional addrspace attribute can be used to indicate the adress space + of the called function. If it is not specified, the program address space + from the :ref:`datalayout string` will be used. #. '``ty``': the type of the call instruction itself which is also the type of the return value. Functions that return no value are marked ``void``. @@ -9503,8 +9509,8 @@ :: - = [tail | musttail | notail ] call [fast-math flags] [cconv] [ret attrs] | () [fn attrs] - [ operand bundles ] + = [tail | musttail | notail ] call [fast-math flags] [cconv] [ret attrs] [addrspace()] + [| () [fn attrs] [ operand bundles ] Overview: """"""""" @@ -9575,6 +9581,9 @@ #. The optional :ref:`Parameter Attributes ` list for return values. Only '``zeroext``', '``signext``', and '``inreg``' attributes are valid here. +#. The optional addrspace attribute can be used to indicate the adress space + of the called function. If it is not specified, the program address space + from the :ref:`datalayout string` will be used. #. '``ty``': the type of the call instruction itself which is also the type of the return value. Functions that return no value are marked ``void``. Index: llvm/trunk/include/llvm/IR/Function.h =================================================================== --- llvm/trunk/include/llvm/IR/Function.h +++ llvm/trunk/include/llvm/IR/Function.h @@ -120,7 +120,7 @@ /// function is automatically inserted into the end of the function list for /// the module. /// - Function(FunctionType *Ty, LinkageTypes Linkage, + Function(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N = "", Module *M = nullptr); public: @@ -134,10 +134,24 @@ const Function &getFunction() const { return *this; } static Function *Create(FunctionType *Ty, LinkageTypes Linkage, + unsigned AddrSpace, const Twine &N = "", + Module *M = nullptr) { + return new Function(Ty, Linkage, AddrSpace, N, M); + } + + // TODO: remove this once all users have been updated to pass an AddrSpace + static Function *Create(FunctionType *Ty, LinkageTypes Linkage, const Twine &N = "", Module *M = nullptr) { - return new Function(Ty, Linkage, N, M); + return new Function(Ty, Linkage, static_cast(-1), N, M); } + /// Creates a new function and attaches it to a module. + /// + /// Places the function in the program address space as specified + /// by the module's data layout. + static Function *Create(FunctionType *Ty, LinkageTypes Linkage, + const Twine &N, Module &M); + // Provide fast operand accessors. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); Index: llvm/trunk/include/llvm/IR/GlobalValue.h =================================================================== --- llvm/trunk/include/llvm/IR/GlobalValue.h +++ llvm/trunk/include/llvm/IR/GlobalValue.h @@ -189,6 +189,7 @@ GlobalValue(const GlobalValue &) = delete; unsigned getAlignment() const; + unsigned getAddressSpace() const; enum class UnnamedAddr { None, Index: llvm/trunk/lib/AsmParser/LLParser.h =================================================================== --- llvm/trunk/lib/AsmParser/LLParser.h +++ llvm/trunk/lib/AsmParser/LLParser.h @@ -202,8 +202,9 @@ /// GetGlobalVal - Get a value with the specified name or ID, creating a /// forward reference record if needed. This can return null if the value /// exists but does not have the right type. - GlobalValue *GetGlobalVal(const std::string &Name, Type *Ty, LocTy Loc); - GlobalValue *GetGlobalVal(unsigned ID, Type *Ty, LocTy Loc); + GlobalValue *GetGlobalVal(const std::string &N, Type *Ty, LocTy Loc, + bool IsCall); + GlobalValue *GetGlobalVal(unsigned ID, Type *Ty, LocTy Loc, bool IsCall); /// Get a Comdat with the specified name, creating a forward reference /// record if needed. @@ -267,7 +268,11 @@ bool ParseTLSModel(GlobalVariable::ThreadLocalMode &TLM); bool ParseOptionalThreadLocal(GlobalVariable::ThreadLocalMode &TLM); bool ParseOptionalUnnamedAddr(GlobalVariable::UnnamedAddr &UnnamedAddr); - bool ParseOptionalAddrSpace(unsigned &AddrSpace); + bool ParseOptionalAddrSpace(unsigned &AddrSpace, unsigned DefaultAS = 0); + bool ParseOptionalProgramAddrSpace(unsigned &AddrSpace) { + return ParseOptionalAddrSpace( + AddrSpace, M->getDataLayout().getProgramAddressSpace()); + }; bool ParseOptionalParamAttrs(AttrBuilder &B); bool ParseOptionalReturnAttrs(AttrBuilder &B); bool ParseOptionalLinkage(unsigned &Res, bool &HasLinkage, @@ -448,6 +453,9 @@ bool ConvertValIDToValue(Type *Ty, ValID &ID, Value *&V, PerFunctionState *PFS, bool IsCall); + Value *checkValidVariableType(LocTy Loc, const Twine &Name, Type *Ty, + Value *Val, bool IsCall); + bool parseConstantValue(Type *Ty, Constant *&C); bool ParseValue(Type *Ty, Value *&V, PerFunctionState *PFS); bool ParseValue(Type *Ty, Value *&V, PerFunctionState &PFS) { Index: llvm/trunk/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/trunk/lib/AsmParser/LLParser.cpp +++ llvm/trunk/lib/AsmParser/LLParser.cpp @@ -1317,7 +1317,8 @@ static inline GlobalValue *createGlobalFwdRef(Module *M, PointerType *PTy, const std::string &Name) { if (auto *FT = dyn_cast(PTy->getElementType())) - return Function::Create(FT, GlobalValue::ExternalWeakLinkage, Name, M); + return Function::Create(FT, GlobalValue::ExternalWeakLinkage, + PTy->getAddressSpace(), Name, M); else return new GlobalVariable(*M, PTy->getElementType(), false, GlobalValue::ExternalWeakLinkage, nullptr, Name, @@ -1325,11 +1326,33 @@ PTy->getAddressSpace()); } +Value *LLParser::checkValidVariableType(LocTy Loc, const Twine &Name, Type *Ty, + Value *Val, bool IsCall) { + if (Val->getType() == Ty) + return Val; + // For calls we also accept variables in the program address space. + Type *SuggestedTy = Ty; + if (IsCall && isa(Ty)) { + Type *TyInProgAS = cast(Ty)->getElementType()->getPointerTo( + M->getDataLayout().getProgramAddressSpace()); + SuggestedTy = TyInProgAS; + if (Val->getType() == TyInProgAS) + return Val; + } + if (Ty->isLabelTy()) + Error(Loc, "'" + Name + "' is not a basic block"); + else + Error(Loc, "'" + Name + "' defined with type '" + + getTypeString(Val->getType()) + "' but expected '" + + getTypeString(SuggestedTy) + "'"); + return nullptr; +} + /// GetGlobalVal - Get a value with the specified name or ID, creating a /// forward reference record if needed. This can return null if the value /// exists but does not have the right type. GlobalValue *LLParser::GetGlobalVal(const std::string &Name, Type *Ty, - LocTy Loc) { + LocTy Loc, bool IsCall) { PointerType *PTy = dyn_cast(Ty); if (!PTy) { Error(Loc, "global variable reference must have pointer type"); @@ -1349,12 +1372,9 @@ } // If we have the value in the symbol table or fwd-ref table, return it. - if (Val) { - if (Val->getType() == Ty) return Val; - Error(Loc, "'@" + Name + "' defined with type '" + - getTypeString(Val->getType()) + "'"); - return nullptr; - } + if (Val) + return cast_or_null( + checkValidVariableType(Loc, "@" + Name, Ty, Val, IsCall)); // Otherwise, create a new forward reference for this value and remember it. GlobalValue *FwdVal = createGlobalFwdRef(M, PTy, Name); @@ -1362,7 +1382,8 @@ return FwdVal; } -GlobalValue *LLParser::GetGlobalVal(unsigned ID, Type *Ty, LocTy Loc) { +GlobalValue *LLParser::GetGlobalVal(unsigned ID, Type *Ty, LocTy Loc, + bool IsCall) { PointerType *PTy = dyn_cast(Ty); if (!PTy) { Error(Loc, "global variable reference must have pointer type"); @@ -1380,12 +1401,9 @@ } // If we have the value in the symbol table or fwd-ref table, return it. - if (Val) { - if (Val->getType() == Ty) return Val; - Error(Loc, "'@" + Twine(ID) + "' defined with type '" + - getTypeString(Val->getType()) + "'"); - return nullptr; - } + if (Val) + return cast_or_null( + checkValidVariableType(Loc, "@" + Twine(ID), Ty, Val, IsCall)); // Otherwise, create a new forward reference for this value and remember it. GlobalValue *FwdVal = createGlobalFwdRef(M, PTy, ""); @@ -1500,8 +1518,8 @@ /// ParseOptionalAddrSpace /// := /*empty*/ /// := 'addrspace' '(' uint32 ')' -bool LLParser::ParseOptionalAddrSpace(unsigned &AddrSpace) { - AddrSpace = 0; +bool LLParser::ParseOptionalAddrSpace(unsigned &AddrSpace, unsigned DefaultAS) { + AddrSpace = DefaultAS; if (!EatIfPresent(lltok::kw_addrspace)) return false; return ParseToken(lltok::lparen, "expected '(' in address space") || @@ -2741,19 +2759,6 @@ return false; } -static bool isValidVariableType(Module *M, Type *Ty, Value *Val, bool IsCall) { - if (Val->getType() == Ty) - return true; - // For calls we also accept variables in the program address space - if (IsCall && isa(Ty)) { - Type *TyInProgAS = cast(Ty)->getElementType()->getPointerTo( - M->getDataLayout().getProgramAddressSpace()); - if (Val->getType() == TyInProgAS) - return true; - } - return false; -} - /// GetVal - Get a value with the specified name or ID, creating a /// forward reference record if needed. This can return null if the value /// exists but does not have the right type. @@ -2771,16 +2776,8 @@ } // If we have the value in the symbol table or fwd-ref table, return it. - if (Val) { - if (isValidVariableType(P.M, Ty, Val, IsCall)) - return Val; - if (Ty->isLabelTy()) - P.Error(Loc, "'%" + Name + "' is not a basic block"); - else - P.Error(Loc, "'%" + Name + "' defined with type '" + - getTypeString(Val->getType()) + "'"); - return nullptr; - } + if (Val) + return P.checkValidVariableType(Loc, "%" + Name, Ty, Val, IsCall); // Don't make placeholders with invalid type. if (!Ty->isFirstClassType()) { @@ -2814,16 +2811,8 @@ } // If we have the value in the symbol table or fwd-ref table, return it. - if (Val) { - if (isValidVariableType(P.M, Ty, Val, IsCall)) - return Val; - if (Ty->isLabelTy()) - P.Error(Loc, "'%" + Twine(ID) + "' is not a basic block"); - else - P.Error(Loc, "'%" + Twine(ID) + "' defined with type '" + - getTypeString(Val->getType()) + "'"); - return nullptr; - } + if (Val) + return P.checkValidVariableType(Loc, "%" + Twine(ID), Ty, Val, IsCall); if (!Ty->isFirstClassType()) { P.Error(Loc, "invalid use of a non-first-class type"); @@ -4940,10 +4929,10 @@ return false; } case ValID::t_GlobalName: - V = GetGlobalVal(ID.StrVal, Ty, ID.Loc); + V = GetGlobalVal(ID.StrVal, Ty, ID.Loc, IsCall); return V == nullptr; case ValID::t_GlobalID: - V = GetGlobalVal(ID.UIntVal, Ty, ID.Loc); + V = GetGlobalVal(ID.UIntVal, Ty, ID.Loc, IsCall); return V == nullptr; case ValID::t_APSInt: if (!Ty->isIntegerTy()) @@ -5086,8 +5075,8 @@ /// FunctionHeader /// ::= OptionalLinkage OptionalPreemptionSpecifier OptionalVisibility /// OptionalCallingConv OptRetAttrs OptUnnamedAddr Type GlobalName -/// '(' ArgList ')' OptFuncAttrs OptSection OptionalAlign OptGC -/// OptionalPrefix OptionalPrologue OptPersonalityFn +/// '(' ArgList ')' OptAddrSpace OptFuncAttrs OptSection OptionalAlign +/// OptGC OptionalPrefix OptionalPrologue OptPersonalityFn bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) { // Parse the linkage. LocTy LinkageLoc = Lex.getLoc(); @@ -5165,6 +5154,7 @@ unsigned Alignment; std::string GC; GlobalValue::UnnamedAddr UnnamedAddr = GlobalValue::UnnamedAddr::None; + unsigned AddrSpace = 0; Constant *Prefix = nullptr; Constant *Prologue = nullptr; Constant *PersonalityFn = nullptr; @@ -5172,6 +5162,7 @@ if (ParseArgumentList(ArgList, isVarArg) || ParseOptionalUnnamedAddr(UnnamedAddr) || + ParseOptionalProgramAddrSpace(AddrSpace) || ParseFnAttributeValuePairs(FuncAttrs, FwdRefAttrGrps, false, BuiltinLoc) || (EatIfPresent(lltok::kw_section) && @@ -5216,7 +5207,7 @@ FunctionType *FT = FunctionType::get(RetType, ParamTypeList, isVarArg); - PointerType *PFT = PointerType::getUnqual(FT); + PointerType *PFT = PointerType::get(FT, AddrSpace); Fn = nullptr; if (!FunctionName.empty()) { @@ -5230,8 +5221,9 @@ "function as global value!"); if (Fn->getType() != PFT) return Error(FRVI->second.second, "invalid forward reference to " - "function '" + FunctionName + "' with wrong type!"); - + "function '" + FunctionName + "' with wrong type: " + "expected '" + getTypeString(PFT) + "' but was '" + + getTypeString(Fn->getType()) + "'"); ForwardRefVals.erase(FRVI); } else if ((Fn = M->getFunction(FunctionName))) { // Reject redefinitions. @@ -5249,16 +5241,21 @@ Fn = cast(I->second.first); if (Fn->getType() != PFT) return Error(NameLoc, "type of definition and forward reference of '@" + - Twine(NumberedVals.size()) + "' disagree"); + Twine(NumberedVals.size()) + "' disagree: " + "expected '" + getTypeString(PFT) + "' but was '" + + getTypeString(Fn->getType()) + "'"); ForwardRefValIDs.erase(I); } } if (!Fn) - Fn = Function::Create(FT, GlobalValue::ExternalLinkage, FunctionName, M); + Fn = Function::Create(FT, GlobalValue::ExternalLinkage, AddrSpace, + FunctionName, M); else // Move the forward-reference to the correct spot in the module. M->getFunctionList().splice(M->end(), M->getFunctionList(), Fn); + assert(Fn->getAddressSpace() == AddrSpace && "Created function in wrong AS"); + if (FunctionName.empty()) NumberedVals.push_back(Fn); @@ -5777,6 +5774,7 @@ std::vector FwdRefAttrGrps; LocTy NoBuiltinLoc; unsigned CC; + unsigned InvokeAddrSpace; Type *RetType = nullptr; LocTy RetTypeLoc; ValID CalleeID; @@ -5785,6 +5783,7 @@ BasicBlock *NormalBB, *UnwindBB; if (ParseOptionalCallingConv(CC) || ParseOptionalReturnAttrs(RetAttrs) || + ParseOptionalProgramAddrSpace(InvokeAddrSpace) || ParseType(RetType, RetTypeLoc, true /*void allowed*/) || ParseValID(CalleeID) || ParseParameterList(ArgList, PFS) || ParseFnAttributeValuePairs(FnAttrs, FwdRefAttrGrps, false, @@ -5816,8 +5815,8 @@ // Look up the callee. Value *Callee; - if (ConvertValIDToValue(PointerType::getUnqual(Ty), CalleeID, Callee, &PFS, - /*IsCall=*/true)) + if (ConvertValIDToValue(PointerType::get(Ty, InvokeAddrSpace), CalleeID, + Callee, &PFS, /*IsCall=*/true)) return true; // Set up the Attribute for the function. @@ -6360,6 +6359,7 @@ AttrBuilder RetAttrs, FnAttrs; std::vector FwdRefAttrGrps; LocTy BuiltinLoc; + unsigned CallAddrSpace; unsigned CC; Type *RetType = nullptr; LocTy RetTypeLoc; @@ -6376,6 +6376,7 @@ FastMathFlags FMF = EatFastMathFlagsIfPresent(); if (ParseOptionalCallingConv(CC) || ParseOptionalReturnAttrs(RetAttrs) || + ParseOptionalProgramAddrSpace(CallAddrSpace) || ParseType(RetType, RetTypeLoc, true /*void allowed*/) || ParseValID(CalleeID) || ParseParameterList(ArgList, PFS, TCK == CallInst::TCK_MustTail, @@ -6408,8 +6409,8 @@ // Look up the callee. Value *Callee; - if (ConvertValIDToValue(PointerType::getUnqual(Ty), CalleeID, Callee, &PFS, - /*IsCall=*/true)) + if (ConvertValIDToValue(PointerType::get(Ty, CallAddrSpace), CalleeID, Callee, + &PFS, /*IsCall=*/true)) return true; // Set up the Attribute for the function. Index: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp +++ llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp @@ -2938,7 +2938,7 @@ Error BitcodeReader::parseFunctionRecord(ArrayRef Record) { // v1: [type, callingconv, isproto, linkage, paramattr, alignment, section, // visibility, gc, unnamed_addr, prologuedata, dllstorageclass, comdat, - // prefixdata, personalityfn, preemption specifier] (name in VST) + // prefixdata, personalityfn, preemption specifier, addrspace] (name in VST) // v2: [strtab_offset, strtab_size, v1] StringRef Name; std::tie(Name, Record) = readNameFromStrtab(Record); @@ -2957,8 +2957,12 @@ if (CC & ~CallingConv::MaxID) return error("Invalid calling convention ID"); - Function *Func = - Function::Create(FTy, GlobalValue::ExternalLinkage, Name, TheModule); + unsigned AddrSpace = TheModule->getDataLayout().getProgramAddressSpace(); + if (Record.size() > 16) + AddrSpace = Record[16]; + + Function *Func = Function::Create(FTy, GlobalValue::ExternalLinkage, + AddrSpace, Name, TheModule); Func->setCallingConv(CC); bool isProto = Record[2]; Index: llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1264,7 +1264,7 @@ // FUNCTION: [strtab offset, strtab size, type, callingconv, isproto, // linkage, paramattrs, alignment, section, visibility, gc, // unnamed_addr, prologuedata, dllstorageclass, comdat, - // prefixdata, personalityfn, DSO_Local] + // prefixdata, personalityfn, DSO_Local, addrspace] Vals.push_back(addToStrtab(F.getName())); Vals.push_back(F.getName().size()); Vals.push_back(VE.getTypeID(F.getFunctionType())); @@ -1287,6 +1287,8 @@ F.hasPersonalityFn() ? (VE.getValueID(F.getPersonalityFn()) + 1) : 0); Vals.push_back(F.isDSOLocal()); + Vals.push_back(F.getAddressSpace()); + unsigned AbbrevToUse = 0; Stream.EmitRecord(bitc::MODULE_CODE_FUNCTION, Vals, AbbrevToUse); Vals.clear(); Index: llvm/trunk/lib/IR/AsmWriter.cpp =================================================================== --- llvm/trunk/lib/IR/AsmWriter.cpp +++ llvm/trunk/lib/IR/AsmWriter.cpp @@ -3350,6 +3350,13 @@ StringRef UA = getUnnamedAddrEncoding(F->getUnnamedAddr()); if (!UA.empty()) Out << ' ' << UA; + // We print the function address space if it is non-zero or if we are writing + // a module with a non-zero program address space or if there is no valid + // Module* so that the file can be parsed without the datalayout string. + const Module *Mod = F->getParent(); + if (F->getAddressSpace() != 0 || !Mod || + Mod->getDataLayout().getProgramAddressSpace() != 0) + Out << " addrspace(" << F->getAddressSpace() << ")"; if (Attrs.hasAttributes(AttributeList::FunctionIndex)) Out << " #" << Machine.getAttributeGroupSlot(Attrs.getFnAttributes()); if (F->hasSection()) { @@ -3487,6 +3494,23 @@ AnnotationWriter->printInfoComment(V, Out); } +static void maybePrintCallAddrSpace(const Value *Operand, const Instruction *I, + raw_ostream &Out) { + // We print the address space of the call if it is non-zero. + unsigned CallAddrSpace = Operand->getType()->getPointerAddressSpace(); + bool PrintAddrSpace = CallAddrSpace != 0; + if (!PrintAddrSpace) { + const Module *Mod = getModuleFromVal(I); + // We also print it if it is zero but not equal to the program address space + // or if we can't find a valid Module* to make it possible to parse + // the resulting file even without a datalayout string. + if (!Mod || Mod->getDataLayout().getProgramAddressSpace() != 0) + PrintAddrSpace = true; + } + if (PrintAddrSpace) + Out << " addrspace(" << CallAddrSpace << ")"; +} + // This member is called for each Instruction in a function.. void AssemblyWriter::printInstruction(const Instruction &I) { if (AnnotationWriter) AnnotationWriter->emitInstructionAnnot(&I, Out); @@ -3684,6 +3708,9 @@ if (PAL.hasAttributes(AttributeList::ReturnIndex)) Out << ' ' << PAL.getAsString(AttributeList::ReturnIndex); + // Only print addrspace(N) if necessary: + maybePrintCallAddrSpace(Operand, &I, Out); + // If possible, print out the short form of the call instruction. We can // only do this if the first argument is a pointer to a nonvararg function, // and if the return type is not a pointer to a function. @@ -3726,6 +3753,9 @@ if (PAL.hasAttributes(AttributeList::ReturnIndex)) Out << ' ' << PAL.getAsString(AttributeList::ReturnIndex); + // Only print addrspace(N) if necessary: + maybePrintCallAddrSpace(Operand, &I, Out); + // If possible, print out the short form of the invoke instruction. We can // only do this if the first argument is a pointer to a nonvararg function, // and if the return type is not a pointer to a function. Index: llvm/trunk/lib/IR/AutoUpgrade.cpp =================================================================== --- llvm/trunk/lib/IR/AutoUpgrade.cpp +++ llvm/trunk/lib/IR/AutoUpgrade.cpp @@ -464,7 +464,7 @@ // the end of the name. Change name from llvm.arm.neon.vclz.* to // llvm.ctlz.* FunctionType* fType = FunctionType::get(F->getReturnType(), args, false); - NewFn = Function::Create(fType, F->getLinkage(), + NewFn = Function::Create(fType, F->getLinkage(), F->getAddressSpace(), "llvm.ctlz." + Name.substr(14), F->getParent()); return true; } @@ -480,7 +480,7 @@ // Can't use Intrinsic::getDeclaration here as the return types might // then only be structurally equal. FunctionType* fType = FunctionType::get(F->getReturnType(), Tys, false); - NewFn = Function::Create(fType, F->getLinkage(), + NewFn = Function::Create(fType, F->getLinkage(), F->getAddressSpace(), "llvm." + Name + ".p0i8", F->getParent()); return true; } Index: llvm/trunk/lib/IR/Function.cpp =================================================================== --- llvm/trunk/lib/IR/Function.cpp +++ llvm/trunk/lib/IR/Function.cpp @@ -203,6 +203,11 @@ return NumInstrs; } +Function *Function::Create(FunctionType *Ty, LinkageTypes Linkage, + const Twine &N, Module &M) { + return Create(Ty, Linkage, M.getDataLayout().getProgramAddressSpace(), N, &M); +} + void Function::removeFromParent() { getParent()->getFunctionList().remove(getIterator()); } @@ -215,10 +220,19 @@ // Function Implementation //===----------------------------------------------------------------------===// -Function::Function(FunctionType *Ty, LinkageTypes Linkage, const Twine &name, - Module *ParentModule) +static unsigned computeAddrSpace(unsigned AddrSpace, Module *M) { + // If AS == -1 and we are passed a valid module pointer we place the function + // in the program address space. Otherwise we default to AS0. + if (AddrSpace == static_cast(-1)) + return M ? M->getDataLayout().getProgramAddressSpace() : 0; + return AddrSpace; +} + +Function::Function(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, + const Twine &name, Module *ParentModule) : GlobalObject(Ty, Value::FunctionVal, - OperandTraits::op_begin(this), 0, Linkage, name), + OperandTraits::op_begin(this), 0, Linkage, name, + computeAddrSpace(AddrSpace, ParentModule)), NumArgs(Ty->getNumParams()) { assert(FunctionType::isValidReturnType(getReturnType()) && "invalid return type"); Index: llvm/trunk/lib/IR/Globals.cpp =================================================================== --- llvm/trunk/lib/IR/Globals.cpp +++ llvm/trunk/lib/IR/Globals.cpp @@ -108,6 +108,11 @@ return cast(this)->getAlignment(); } +unsigned GlobalValue::getAddressSpace() const { + PointerType *PtrTy = getType(); + return PtrTy->getAddressSpace(); +} + void GlobalObject::setAlignment(unsigned Align) { assert((Align & (Align-1)) == 0 && "Alignment is not a power of 2!"); assert(Align <= MaximumAlignment && Index: llvm/trunk/lib/IR/Module.cpp =================================================================== --- llvm/trunk/lib/IR/Module.cpp +++ llvm/trunk/lib/IR/Module.cpp @@ -145,7 +145,8 @@ GlobalValue *F = getNamedValue(Name); if (!F) { // Nope, add it - Function *New = Function::Create(Ty, GlobalVariable::ExternalLinkage, Name); + Function *New = Function::Create(Ty, GlobalVariable::ExternalLinkage, + DL.getProgramAddressSpace(), Name); if (!New->isIntrinsic()) // Intrinsics get attrs set on construction New->setAttributes(AttributeList); FunctionList.push_back(New); @@ -154,8 +155,9 @@ // If the function exists but has the wrong type, return a bitcast to the // right type. - if (F->getType() != PointerType::getUnqual(Ty)) - return ConstantExpr::getBitCast(F, PointerType::getUnqual(Ty)); + auto *PTy = PointerType::get(Ty, F->getAddressSpace()); + if (F->getType() != PTy) + return ConstantExpr::getBitCast(F, PTy); // Otherwise, we just found the existing function or a prototype. return F; Index: llvm/trunk/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp =================================================================== --- llvm/trunk/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp +++ llvm/trunk/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp @@ -645,8 +645,8 @@ GlobalValue::LinkageTypes NewFLink, FunctionType *NewFT) { FunctionType *FT = F->getFunctionType(); - Function *NewF = Function::Create(NewFT, NewFLink, NewFName, - F->getParent()); + Function *NewF = Function::Create(NewFT, NewFLink, F->getAddressSpace(), + NewFName, F->getParent()); NewF->copyAttributesFrom(F); NewF->removeAttributes( AttributeList::ReturnIndex, @@ -819,7 +819,8 @@ // easily identify cases of mismatching ABIs. if (getInstrumentedABI() == IA_Args && !IsZeroArgsVoidRet) { FunctionType *NewFT = getArgsFunctionType(FT); - Function *NewF = Function::Create(NewFT, F.getLinkage(), "", &M); + Function *NewF = Function::Create(NewFT, F.getLinkage(), + F.getAddressSpace(), "", &M); NewF->copyAttributesFrom(&F); NewF->removeAttributes( AttributeList::ReturnIndex, Index: llvm/trunk/lib/Transforms/Utils/CloneFunction.cpp =================================================================== --- llvm/trunk/lib/Transforms/Utils/CloneFunction.cpp +++ llvm/trunk/lib/Transforms/Utils/CloneFunction.cpp @@ -235,8 +235,8 @@ ArgTypes, F->getFunctionType()->isVarArg()); // Create the new function... - Function *NewF = - Function::Create(FTy, F->getLinkage(), F->getName(), F->getParent()); + Function *NewF = Function::Create(FTy, F->getLinkage(), F->getAddressSpace(), + F->getName(), F->getParent()); // Loop over the arguments, copying the names of the mapped arguments over... Function::arg_iterator DestI = NewF->arg_begin(); Index: llvm/trunk/lib/Transforms/Utils/CloneModule.cpp =================================================================== --- llvm/trunk/lib/Transforms/Utils/CloneModule.cpp +++ llvm/trunk/lib/Transforms/Utils/CloneModule.cpp @@ -74,8 +74,9 @@ // Loop over the functions in the module, making external functions as before for (const Function &I : M) { - Function *NF = Function::Create(cast(I.getValueType()), - I.getLinkage(), I.getName(), New.get()); + Function *NF = + Function::Create(cast(I.getValueType()), I.getLinkage(), + I.getAddressSpace(), I.getName(), New.get()); NF->copyAttributesFrom(&I); VMap[&I] = NF; } @@ -91,8 +92,8 @@ GlobalValue *GV; if (I->getValueType()->isFunctionTy()) GV = Function::Create(cast(I->getValueType()), - GlobalValue::ExternalLinkage, I->getName(), - New.get()); + GlobalValue::ExternalLinkage, + I->getAddressSpace(), I->getName(), New.get()); else GV = new GlobalVariable( *New, I->getValueType(), false, GlobalValue::ExternalLinkage, Index: llvm/trunk/lib/Transforms/Utils/CodeExtractor.cpp =================================================================== --- llvm/trunk/lib/Transforms/Utils/CodeExtractor.cpp +++ llvm/trunk/lib/Transforms/Utils/CodeExtractor.cpp @@ -670,10 +670,9 @@ AllowVarArgs && oldFunction->isVarArg()); // Create the new function - Function *newFunction = Function::Create(funcType, - GlobalValue::InternalLinkage, - oldFunction->getName() + "_" + - header->getName(), M); + Function *newFunction = Function::Create( + funcType, GlobalValue::InternalLinkage, oldFunction->getAddressSpace(), + oldFunction->getName() + "_" + header->getName(), M); // If the old function is no-throw, so is the new one. if (oldFunction->doesNotThrow()) newFunction->setDoesNotThrow(); Index: llvm/trunk/test/Assembler/call-nonzero-program-addrspace-2.ll =================================================================== --- llvm/trunk/test/Assembler/call-nonzero-program-addrspace-2.ll +++ llvm/trunk/test/Assembler/call-nonzero-program-addrspace-2.ll @@ -1,11 +1,22 @@ -; RUN: llvm-as %s -data-layout=P200 -o /dev/null ; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s +; RUN: llvm-as %s -data-layout=P42 -o - | llvm-dis - -o - | FileCheck %s -check-prefix PROGAS42 ; Check that numbered variables in a nonzero program address space 200 can be used in a call instruction -define i8 @test_unnamed(i8(i32)*, i8(i32) addrspace(200)*) { - %first = call i8 %0(i32 0) ; this is fine - %second = call i8 %1(i32 0) ; this is also fine if it's the program AS - ; CHECK: call-nonzero-program-addrspace-2.ll:[[@LINE-1]]:21: error: '%1' defined with type 'i8 (i32) addrspace(200)*' +define i8 @test_unnamed(i8(i32)*, i8(i32) addrspace(42)*) { + ; Calls with explicit address spaces are fine: + call addrspace(0) i8 %0(i32 0) + call addrspace(42) i8 %1(i32 0) + ; this call is fine if the program address space is 42 + call i8 %1(i32 0) + ; CHECK: call-nonzero-program-addrspace-2.ll:[[@LINE-1]]:11: error: '%1' defined with type 'i8 (i32) addrspace(42)*' but expected 'i8 (i32)*' ret i8 0 } + +; PROGAS42: target datalayout = "P42" +; PROGAS42: define i8 @test_unnamed(i8 (i32)*, i8 (i32) addrspace(42)*) addrspace(42) { +; PROGAS42-NEXT: %3 = call addrspace(0) i8 %0(i32 0) +; PROGAS42-NEXT: %4 = call addrspace(42) i8 %1(i32 0) +; PROGAS42-NEXT: %5 = call addrspace(42) i8 %1(i32 0) +; PROGAS42-NEXT: ret i8 0 +; PROGAS42-NEXT: } Index: llvm/trunk/test/Assembler/call-nonzero-program-addrspace.ll =================================================================== --- llvm/trunk/test/Assembler/call-nonzero-program-addrspace.ll +++ llvm/trunk/test/Assembler/call-nonzero-program-addrspace.ll @@ -1,13 +1,23 @@ -; RUN: llvm-as %s -data-layout=P200 -o /dev/null ; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s +; RUN: llvm-as %s -data-layout=P42 -o - | llvm-dis - -o - | FileCheck %s -check-prefix PROGAS42 -; Check that variables in a nonzero program address space 200 can be used in a call instruction +; Check that variables in a nonzero program address space 42 can be used in a call instruction -define i8 @test(i8(i32)* %fnptr0, i8(i32) addrspace(200)* %fnptr200) { - %first = call i8 %fnptr0(i32 0) ; this is fine - %second = call i8 %fnptr200(i32 0) ; this is also fine if it's the program AS - ; CHECK: call-nonzero-program-addrspace.ll:[[@LINE-1]]:21: error: '%fnptr200' defined with type 'i8 (i32) addrspace(200)*' +define i8 @test(i8(i32)* %fnptr0, i8(i32) addrspace(42)* %fnptr42) { + %explicit_as_0 = call addrspace(0) i8 %fnptr0(i32 0) + %explicit_as_42 = call addrspace(42) i8 %fnptr42(i32 0) + ; Calling %fnptr42 without an explicit addrspace() in the call instruction is only okay if the program AS is 42 + %call_no_as = call i8 %fnptr42(i32 0) + ; CHECK: call-nonzero-program-addrspace.ll:[[@LINE-1]]:25: error: '%fnptr42' defined with type 'i8 (i32) addrspace(42)*' but expected 'i8 (i32)*' ret i8 0 } -declare i32 @__gxx_personality_v0(...) +; PROGAS42: target datalayout = "P42" +; PROGAS42: define i8 @test(i8 (i32)* %fnptr0, i8 (i32) addrspace(42)* %fnptr42) addrspace(42) { +; Print addrspace(0) since the program address space is non-zero: +; PROGAS42-NEXT: %explicit_as_0 = call addrspace(0) i8 %fnptr0(i32 0) +; Also print addrspace(42) since we always print non-zero addrspace: +; PROGAS42-NEXT: %explicit_as_42 = call addrspace(42) i8 %fnptr42(i32 0) +; PROGAS42-NEXT: %call_no_as = call addrspace(42) i8 %fnptr42(i32 0) +; PROGAS42-NEXT: ret i8 0 +; PROGAS42-NEXT: } Index: llvm/trunk/test/Assembler/invoke-nonzero-program-addrspace.ll =================================================================== --- llvm/trunk/test/Assembler/invoke-nonzero-program-addrspace.ll +++ llvm/trunk/test/Assembler/invoke-nonzero-program-addrspace.ll @@ -1,12 +1,15 @@ -; RUN: llvm-as %s -data-layout=P200 -o /dev/null ; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s +; RUN: llvm-as %s -data-layout=P200 -o - | llvm-dis - -o - | FileCheck %s -check-prefix PROGAS200 + ; Check that variables in a nonzero program address space 200 can be used in a invoke instruction -define i8 @test_invoke(i8(i32)* %fnptr0, i8(i32) addrspace(200)* %fnptr200) personality i32 (...)* @__gxx_personality_v0 { - %first = invoke i8 %fnptr0(i32 0) to label %ok unwind label %lpad ; this is fine - %second = invoke i8 %fnptr200(i32 0) to label %ok unwind label %lpad ; this is also fine if it's the program AS - ; CHECK: invoke-nonzero-program-addrspace.ll:[[@LINE-1]]:23: error: '%fnptr200' defined with type 'i8 (i32) addrspace(200)*' +define i8 @test_invoke(i8(i32)* %fnptr0, i8(i32) addrspace(200)* %fnptr200) personality i32 (...) addrspace(200)* @__gxx_personality_v0 { + %explicit_as_0 = invoke addrspace(0) i8 %fnptr0(i32 0) to label %ok unwind label %lpad + %explicit_as_42 = invoke addrspace(200) i8 %fnptr200(i32 0) to label %ok unwind label %lpad + ; The following is only okay if the program address space is 200: + %no_as = invoke i8 %fnptr200(i32 0) to label %ok unwind label %lpad + ; CHECK: invoke-nonzero-program-addrspace.ll:[[@LINE-1]]:22: error: '%fnptr200' defined with type 'i8 (i32) addrspace(200)*' but expected 'i8 (i32)*' ok: ret i8 0 lpad: @@ -16,3 +19,12 @@ } declare i32 @__gxx_personality_v0(...) + + +; PROGAS200: target datalayout = "P200" +; PROGAS200: define i8 @test_invoke(i8 (i32)* %fnptr0, i8 (i32) addrspace(200)* %fnptr200) addrspace(200) personality i32 (...) addrspace(200)* @__gxx_personality_v0 { +; PROGAS200: %explicit_as_0 = invoke addrspace(0) i8 %fnptr0(i32 0) +; PROGAS200: %explicit_as_42 = invoke addrspace(200) i8 %fnptr200(i32 0) +; PROGAS200: %no_as = invoke addrspace(200) i8 %fnptr200(i32 0) +; PROGAS200: ret i8 0 +; PROGAS200: } Index: llvm/trunk/test/Bitcode/function-address-space-fwd-decl.ll =================================================================== --- llvm/trunk/test/Bitcode/function-address-space-fwd-decl.ll +++ llvm/trunk/test/Bitcode/function-address-space-fwd-decl.ll @@ -0,0 +1,39 @@ +; Verify that forward declarations from call instructions work even with non-zero AS +; RUN: llvm-as %s -o - | llvm-dis - | FileCheck %s + +define void @call_named() { +entry: + %0 = tail call addrspace(40) i32 @named(i16* null) + ; CHECK: %0 = tail call addrspace(40) i32 @named(i16* null) + ret void +} + +define void @call_numbered() { +entry: + %0 = tail call addrspace(40) i32 @0(i16* null) + ; CHECK: %0 = tail call addrspace(40) i32 @0(i16* null) + ret void +} + + +define i32 @invoked() personality i8* null { +entry: + %0 = invoke addrspace(40) i32 @foo() to label %l1 unwind label %lpad + ; CHECK: invoke addrspace(40) i32 @foo() +l1: + br label %return +lpad: + %1 = landingpad { i8*, i32 } + catch i8* null + catch i8* null + ret i32 0 +return: + ret i32 0 +} + +declare i32 @foo() addrspace(40) +; CHECK: declare i32 @foo() addrspace(40) +declare i32 @named(i16* nocapture) addrspace(40) +; CHECK: declare i32 @named(i16* nocapture) addrspace(40) +declare i32 @0(i16*) addrspace(40) +; CHECK: declare i32 @0(i16*) addrspace(40) Index: llvm/trunk/test/Bitcode/function-default-address-spaces.ll =================================================================== --- llvm/trunk/test/Bitcode/function-default-address-spaces.ll +++ llvm/trunk/test/Bitcode/function-default-address-spaces.ll @@ -0,0 +1,35 @@ +; RUN: llvm-as %s -o - | llvm-dis - | FileCheck %s -check-prefixes CHECK,PROG-AS0 +; RUN: llvm-as -data-layout "P200" %s -o - | llvm-dis | FileCheck %s -check-prefixes CHECK,PROG-AS200 +; RUN: not llvm-as -data-layout "P123456789" %s -o /dev/null 2>&1 | FileCheck %s -check-prefix BAD-DATALAYOUT +; BAD-DATALAYOUT: LLVM ERROR: Invalid address space, must be a 24-bit integer + +; PROG-AS0-NOT: target datalayout +; PROG-AS200: target datalayout = "P200" + +; Check that a function declaration without an address space (i.e. AS0) does not +; have the addrspace() attribute printed if it is address space zero and it is +; equal to the program address space. + +; PROG-AS0: define void @no_as() { +; PROG-AS200: define void @no_as() addrspace(200) { +define void @no_as() { + ret void +} + +; A function with an explicit addrspace should only have the addrspace printed +; if it is non-zero or if the module has a nonzero datalayout +; PROG-AS0: define void @explit_as0() { +; PROG-AS200: define void @explit_as0() addrspace(0) { +define void @explit_as0() addrspace(0) { + ret void +} + +; CHECK: define void @explit_as200() addrspace(200) { +define void @explit_as200() addrspace(200) { + ret void +} + +; CHECK: define void @explicit_as3() addrspace(3) { +define void @explicit_as3() addrspace(3) { + ret void +} Index: llvm/trunk/test/Bitcode/function-nonzero-address-spaces-types.ll =================================================================== --- llvm/trunk/test/Bitcode/function-nonzero-address-spaces-types.ll +++ llvm/trunk/test/Bitcode/function-nonzero-address-spaces-types.ll @@ -0,0 +1,23 @@ +; Verify that we accept calls to variables in the program AS: +; RUN: llvm-as -data-layout "P40" %s -o - | llvm-dis - | FileCheck %s +; CHECK: target datalayout = "P40" + +; We should get a sensible error for a non-program address call: +; RUN: not llvm-as -data-layout "P39" %s -o /dev/null 2>&1 | FileCheck %s -check-prefix ERR-AS39 +; ERR-AS39: error: '%0' defined with type 'i16 (i16) addrspace(40)*' but expected 'i16 (i16) addrspace(39)*' + +; And also if we don't set a custom program address space: +; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s -check-prefix ERR-AS0 +; ERR-AS0: error: '%0' defined with type 'i16 (i16) addrspace(40)*' but expected 'i16 (i16)*' + +%fun1 = type i16 (i16) +%funptr1 = type %fun1 addrspace(40)* + +@fun_ptr = global %funptr1 @fun + +define i16 @fun(i16 %arg) addrspace(40) { +entry: + %0 = load %funptr1, %funptr1* @fun_ptr + %result = call i16 %0(i16 %arg) + ret i16 %result +} Index: llvm/trunk/test/Bitcode/function-nonzero-address-spaces.ll =================================================================== --- llvm/trunk/test/Bitcode/function-nonzero-address-spaces.ll +++ llvm/trunk/test/Bitcode/function-nonzero-address-spaces.ll @@ -0,0 +1,29 @@ +; Verify that we accept calls to variables in the program AS: +; RUN: llvm-as -data-layout "P40" %s -o - | llvm-dis - | FileCheck %s +; CHECK: target datalayout = "P40" + +; We should get a sensible error for a non-program address call: +; RUN: not llvm-as -data-layout "P39" %s -o /dev/null 2>&1 | FileCheck %s -check-prefix ERR-AS39 +; ERR-AS39: error: '%fnptr' defined with type 'void (i16) addrspace(40)*' but expected 'void (i16) addrspace(39)*' + +; And also if we don't set a custom program address space: +; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s -check-prefix ERR-AS0 +; ERR-AS0: error: '%fnptr' defined with type 'void (i16) addrspace(40)*' but expected 'void (i16)*' + +define void @f_named(i16 %n, void (i16) addrspace(40)* %f) addrspace(40) { +entry: + %f.addr = alloca void (i16) addrspace(40)*, align 1 + store void (i16) addrspace(40)* %f, void (i16) addrspace(40)** %f.addr + %fnptr = load void (i16) addrspace(40)*, void (i16) addrspace(40)** %f.addr + call void %fnptr(i16 8) + ret void +} + +define void @f_numbered(i16 %n, void (i16) addrspace(40)* %f) addrspace(40){ +entry: + %f.addr = alloca void (i16) addrspace(40)*, align 1 + store void (i16) addrspace(40)* %f, void (i16) addrspace(40)** %f.addr + %0 = load void (i16) addrspace(40)*, void (i16) addrspace(40)** %f.addr + call void %0(i16 8) + ret void +}