diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp --- a/clang/lib/CodeGen/CGException.cpp +++ b/clang/lib/CodeGen/CGException.cpp @@ -247,9 +247,9 @@ static llvm::Constant *getOpaquePersonalityFn(CodeGenModule &CGM, const EHPersonality &Personality) { llvm::FunctionCallee Fn = getPersonalityFn(CGM, Personality); - llvm::PointerType* Int8PtrTy = llvm::PointerType::get( + llvm::PointerType *Int8PtrTy = llvm::PointerType::get( llvm::Type::getInt8Ty(CGM.getLLVMContext()), - CGM.getDataLayout().getProgramAddressSpace()); + CGM.getDataLayout().getDefaultProgramAddressSpace()); return llvm::ConstantExpr::getBitCast(cast(Fn.getCallee()), Int8PtrTy); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1296,8 +1296,8 @@ // Ctor function type is void()*. llvm::FunctionType* CtorFTy = llvm::FunctionType::get(VoidTy, false); - llvm::Type *CtorPFTy = llvm::PointerType::get(CtorFTy, - TheModule.getDataLayout().getProgramAddressSpace()); + llvm::Type *CtorPFTy = llvm::PointerType::get( + CtorFTy, TheModule.getDataLayout().getDefaultProgramAddressSpace()); // Get the type of a ctor entry, { i32, void ()*, i8* }. llvm::StructType *CtorStructTy = llvm::StructType::get( diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/lib/CodeGen/CodeGenTypes.cpp @@ -629,7 +629,7 @@ PointeeType = llvm::Type::getInt8Ty(getLLVMContext()); unsigned AS = PointeeType->isFunctionTy() - ? getDataLayout().getProgramAddressSpace() + ? getDataLayout().getDefaultProgramAddressSpace() : Context.getTargetAddressSpace(ETy); ResultType = llvm::PointerType::get(PointeeType, AS); diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -2380,7 +2380,7 @@ alignment defaults to "unspecified", which does not prevent any alignment promotions. ``P
`` - Specifies the address space that corresponds to program memory. + Specifies an address space that corresponds to program memory. Harvard architectures can use this to specify what space LLVM should place things such as functions into. If omitted, the program memory space defaults to the default address space of 0, diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h --- a/llvm/include/llvm/CodeGen/TargetLowering.h +++ b/llvm/include/llvm/CodeGen/TargetLowering.h @@ -359,7 +359,7 @@ /// Return the type for code pointers, which is determined by the program /// address space specified through the data layout. MVT getProgramPointerTy(const DataLayout &DL) const { - return getPointerTy(DL, DL.getProgramAddressSpace()); + return getPointerTy(DL, DL.getDefaultProgramAddressSpace()); } /// Return the type for operands of fence. diff --git a/llvm/include/llvm/IR/DataLayout.h b/llvm/include/llvm/IR/DataLayout.h --- a/llvm/include/llvm/IR/DataLayout.h +++ b/llvm/include/llvm/IR/DataLayout.h @@ -122,7 +122,11 @@ unsigned AllocaAddrSpace; MaybeAlign StackNaturalAlign; - unsigned ProgramAddrSpace; + /// Vector of address spaces that can contain code + /// Always non-empty, contains the default address space by default. + /// Harvard architectures can specify a different address space. + /// WebAssembly might specify more than one address space. + SmallVector ProgramAddrSpaces; MaybeAlign FunctionPtrAlign; FunctionPtrAlignType TheFunctionPtrAlignType; @@ -218,7 +222,7 @@ StackNaturalAlign = DL.StackNaturalAlign; FunctionPtrAlign = DL.FunctionPtrAlign; TheFunctionPtrAlignType = DL.TheFunctionPtrAlignType; - ProgramAddrSpace = DL.ProgramAddrSpace; + ProgramAddrSpaces = DL.ProgramAddrSpaces; ManglingMode = DL.ManglingMode; LegalIntWidths = DL.LegalIntWidths; Alignments = DL.Alignments; @@ -294,7 +298,33 @@ return TheFunctionPtrAlignType; } - unsigned getProgramAddressSpace() const { return ProgramAddrSpace; } + ArrayRef getProgramAddressSpaces() const { + assert(!ProgramAddrSpaces.empty()); + return ProgramAddrSpaces; + } + + unsigned getDefaultProgramAddressSpace() const { + assert(!ProgramAddrSpaces.empty()); + return ProgramAddrSpaces[0]; + } + + bool isProgramAddressSpace(unsigned AddrSpace) const { + ArrayRef ProgramAddressSpaces = getProgramAddressSpaces(); + return find(ProgramAddressSpaces, AddrSpace) != ProgramAddressSpaces.end(); + } + + bool isPointerTypeInProgramAddressSpace(PointerType *PT) const { + return isProgramAddressSpace(PT->getAddressSpace()); + } + + bool isPointerTypeInProgramAddressSpace(Type *Ty) const { + auto *PTy = dyn_cast(Ty); + return PTy && isPointerTypeInProgramAddressSpace(PTy); + } + + bool hasNonZeroProgramAddressSpace() const { + return ProgramAddrSpaces.size() > 1 || ProgramAddrSpaces[0] != 0; + } bool hasMicrosoftFastStdCallMangling() const { return ManglingMode == MM_WinCOFFX86; diff --git a/llvm/include/llvm/Target/TargetMachine.h b/llvm/include/llvm/Target/TargetMachine.h --- a/llvm/include/llvm/Target/TargetMachine.h +++ b/llvm/include/llvm/Target/TargetMachine.h @@ -175,7 +175,7 @@ } unsigned getProgramPointerSize() const { - return DL.getPointerSize(DL.getProgramAddressSpace()); + return DL.getPointerSize(DL.getDefaultProgramAddressSpace()); } unsigned getAllocaPointerSize() const { 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 @@ -256,7 +256,7 @@ bool parseOptionalAddrSpace(unsigned &AddrSpace, unsigned DefaultAS = 0); bool parseOptionalProgramAddrSpace(unsigned &AddrSpace) { return parseOptionalAddrSpace( - AddrSpace, M->getDataLayout().getProgramAddressSpace()); + AddrSpace, M->getDataLayout().getDefaultProgramAddressSpace()); }; bool parseOptionalParamAttrs(AttrBuilder &B); bool parseOptionalReturnAttrs(AttrBuilder &B); 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 @@ -1466,21 +1466,28 @@ 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; + // Call through a function pointer + // The type can live in any of the program address spaces + + // We check if the address space of the pointer type of Val is one + // of the defined program address spaces and if with that AS, Ty matches + // Val's type. + if (M->getDataLayout().isPointerTypeInProgramAddressSpace(Val->getType())) { + Type *TyInProgAS = cast(Ty)->getElementType()->getPointerTo( + cast(Val->getType())->getAddressSpace()); + + 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) + "'"); + getTypeString(Ty) + "'"); return nullptr; } 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 @@ -3276,7 +3276,8 @@ if (CC & ~CallingConv::MaxID) return error("Invalid calling convention ID"); - unsigned AddrSpace = TheModule->getDataLayout().getProgramAddressSpace(); + unsigned AddrSpace = + TheModule->getDataLayout().getDefaultProgramAddressSpace(); if (Record.size() > 16) AddrSpace = Record[16]; 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 @@ -3718,7 +3718,7 @@ // 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) + Mod->getDataLayout().hasNonZeroProgramAddressSpace()) Out << " addrspace(" << F->getAddressSpace() << ")"; if (Attrs.hasAttributes(AttributeList::FunctionIndex)) Out << " #" << Machine.getAttributeGroupSlot(Attrs.getFnAttributes()); @@ -3877,7 +3877,7 @@ // 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) + if (!Mod || Mod->getDataLayout().hasNonZeroProgramAddressSpace()) PrintAddrSpace = true; } if (PrintAddrSpace) diff --git a/llvm/lib/IR/DataLayout.cpp b/llvm/lib/IR/DataLayout.cpp --- a/llvm/lib/IR/DataLayout.cpp +++ b/llvm/lib/IR/DataLayout.cpp @@ -181,7 +181,7 @@ BigEndian = false; AllocaAddrSpace = 0; StackNaturalAlign.reset(); - ProgramAddrSpace = 0; + ProgramAddrSpaces.clear(); FunctionPtrAlign.reset(); TheFunctionPtrAlignType = FunctionPtrAlignType::Independent; ManglingMode = MM_None; @@ -470,8 +470,20 @@ break; } case 'P': { // Function address space. - if (Error Err = getAddrSpace(Tok, ProgramAddrSpace)) + unsigned pa; + if (Error Err = getAddrSpace(Tok, pa)) return Err; + + // Only add if not already defined + bool found = false; + for (size_t i = 0; i < ProgramAddrSpaces.size(); i++) { + if (ProgramAddrSpaces[i] == pa) { + found = true; + break; + } + } + if (!found) + ProgramAddrSpaces.push_back(pa); break; } case 'A': { // Default stack/alloca address space. @@ -516,6 +528,10 @@ } } + // If Program address spaces is empty, add the default address space (0) + if (ProgramAddrSpaces.empty()) + ProgramAddrSpaces.push_back(0); + return Error::success(); } @@ -529,7 +545,7 @@ bool Ret = BigEndian == Other.BigEndian && AllocaAddrSpace == Other.AllocaAddrSpace && StackNaturalAlign == Other.StackNaturalAlign && - ProgramAddrSpace == Other.ProgramAddrSpace && + ProgramAddrSpaces == Other.ProgramAddrSpaces && FunctionPtrAlign == Other.FunctionPtrAlign && TheFunctionPtrAlignType == Other.TheFunctionPtrAlignType && ManglingMode == Other.ManglingMode && diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp --- a/llvm/lib/IR/Function.cpp +++ b/llvm/lib/IR/Function.cpp @@ -306,7 +306,8 @@ Function *Function::Create(FunctionType *Ty, LinkageTypes Linkage, const Twine &N, Module &M) { - return Create(Ty, Linkage, M.getDataLayout().getProgramAddressSpace(), N, &M); + return Create(Ty, Linkage, M.getDataLayout().getDefaultProgramAddressSpace(), + N, &M); } void Function::removeFromParent() { @@ -325,7 +326,7 @@ // 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 M ? M->getDataLayout().getDefaultProgramAddressSpace() : 0; return AddrSpace; } 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 @@ -147,7 +147,7 @@ if (!F) { // Nope, add it Function *New = Function::Create(Ty, GlobalVariable::ExternalLinkage, - DL.getProgramAddressSpace(), Name); + DL.getDefaultProgramAddressSpace(), Name); if (!New->isIntrinsic()) // Intrinsics get attrs set on construction New->setAttributes(AttributeList); FunctionList.push_back(New); diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -650,8 +650,8 @@ if (ArrayType *ATy = dyn_cast(GV.getValueType())) { StructType *STy = dyn_cast(ATy->getElementType()); PointerType *FuncPtrTy = - FunctionType::get(Type::getVoidTy(Context), false)-> - getPointerTo(DL.getProgramAddressSpace()); + FunctionType::get(Type::getVoidTy(Context), false) + ->getPointerTo(DL.getDefaultProgramAddressSpace()); Assert(STy && (STy->getNumElements() == 2 || STy->getNumElements() == 3) && STy->getTypeAtIndex(0u)->isIntegerTy(32) && diff --git a/llvm/lib/Transforms/IPO/LowerTypeTests.cpp b/llvm/lib/Transforms/IPO/LowerTypeTests.cpp --- a/llvm/lib/Transforms/IPO/LowerTypeTests.cpp +++ b/llvm/lib/Transforms/IPO/LowerTypeTests.cpp @@ -1276,12 +1276,12 @@ void LowerTypeTestsModule::moveInitializerToModuleConstructor( GlobalVariable *GV) { if (WeakInitializerFn == nullptr) { - WeakInitializerFn = Function::Create( - FunctionType::get(Type::getVoidTy(M.getContext()), - /* IsVarArg */ false), - GlobalValue::InternalLinkage, - M.getDataLayout().getProgramAddressSpace(), - "__cfi_global_var_init", &M); + WeakInitializerFn = + Function::Create(FunctionType::get(Type::getVoidTy(M.getContext()), + /* IsVarArg */ false), + GlobalValue::InternalLinkage, + M.getDataLayout().getDefaultProgramAddressSpace(), + "__cfi_global_var_init", &M); BasicBlock *BB = BasicBlock::Create(M.getContext(), "entry", WeakInitializerFn); ReturnInst::Create(M.getContext(), BB); @@ -1517,12 +1517,11 @@ for (unsigned I = 0; I != Functions.size(); ++I) GlobalLayout[Functions[I]] = I * EntrySize; - Function *JumpTableFn = - Function::Create(FunctionType::get(Type::getVoidTy(M.getContext()), - /* IsVarArg */ false), - GlobalValue::PrivateLinkage, - M.getDataLayout().getProgramAddressSpace(), - ".cfi.jumptable", &M); + Function *JumpTableFn = Function::Create( + FunctionType::get(Type::getVoidTy(M.getContext()), + /* IsVarArg */ false), + GlobalValue::PrivateLinkage, + M.getDataLayout().getDefaultProgramAddressSpace(), ".cfi.jumptable", &M); ArrayType *JumpTableType = ArrayType::get(getJumpTableEntryType(), Functions.size()); auto JumpTable = @@ -1962,7 +1961,8 @@ F = Function::Create( FunctionType::get(Type::getVoidTy(M.getContext()), false), GlobalVariable::ExternalLinkage, - M.getDataLayout().getProgramAddressSpace(), FunctionName, &M); + M.getDataLayout().getDefaultProgramAddressSpace(), FunctionName, + &M); // If the function is available_externally, remove its definition so // that it is handled the same way as a declaration. Later we will try diff --git a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp --- a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp +++ b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp @@ -1220,12 +1220,12 @@ Function *JT; if (isa(Slot.TypeID)) { JT = Function::Create(FT, Function::ExternalLinkage, - M.getDataLayout().getProgramAddressSpace(), + M.getDataLayout().getDefaultProgramAddressSpace(), getGlobalName(Slot, {}, "branch_funnel"), &M); JT->setVisibility(GlobalValue::HiddenVisibility); } else { JT = Function::Create(FT, Function::InternalLinkage, - M.getDataLayout().getProgramAddressSpace(), + M.getDataLayout().getDefaultProgramAddressSpace(), "branch_funnel", &M); } JT->addAttribute(1, Attribute::Nest); diff --git a/llvm/test/Assembler/function-address_spaces.ll b/llvm/test/Assembler/function-address_spaces.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Assembler/function-address_spaces.ll @@ -0,0 +1,30 @@ +; RUN: llvm-as < %s | llvm-dis | FileCheck %s + +; specifying explicitly P:0 (although it's the default) +; P:1 specifies an extra address space for code where funcrefs live +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1-P0-P1" + +; square and double_square are in addrspace(0) +define i32 @square(i32 %0) { +; CHECK: define i32 @square(i32 %0) addrspace(0) { + %2 = mul nsw i32 %0, %0 + ret i32 %2 +} + +define i32 @double_square(i32 %0) { +; CHECK: define i32 @double_square(i32 %0) addrspace(0) { + %2 = shl i32 %0, 1 + %3 = mul i32 %2, %0 + ret i32 %3 +} + +; funcref is a pointer to a function in addrspace(1) +; called in call_funcref +%func = type void () +%funcref = type %func addrspace(1)* + +define void @call_funcref(%funcref %ref) { +; CHECK: define void @call_funcref(void () addrspace(1)* %ref) addrspace(0) { + call void %ref() + ret void +}