diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -2370,6 +2370,14 @@ program memory space defaults to the default address space of 0, which corresponds to a Von Neumann architecture that has code and data in the same space. +``G
`` + Specifies the address space to be used by default when creating global + variables. If omitted, the globals address space defaults to the default + address space 0. + Note: variable declarations without an address space are always created in + address space 0, this property only affects the default value to be used + when creating globals without additional contextual information (e.g. in + LLVM passes). ``A
`` Specifies the address space of objects created by '``alloca``'. Defaults to the default address space of 0. 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 @@ -123,6 +123,7 @@ unsigned AllocaAddrSpace; MaybeAlign StackNaturalAlign; unsigned ProgramAddrSpace; + unsigned DefaultGlobalsAddrSpace; MaybeAlign FunctionPtrAlign; FunctionPtrAlignType TheFunctionPtrAlignType; @@ -219,6 +220,7 @@ FunctionPtrAlign = DL.FunctionPtrAlign; TheFunctionPtrAlignType = DL.TheFunctionPtrAlignType; ProgramAddrSpace = DL.ProgramAddrSpace; + DefaultGlobalsAddrSpace = DL.DefaultGlobalsAddrSpace; ManglingMode = DL.ManglingMode; LegalIntWidths = DL.LegalIntWidths; Alignments = DL.Alignments; @@ -295,6 +297,9 @@ } unsigned getProgramAddressSpace() const { return ProgramAddrSpace; } + unsigned getDefaultGlobalsAddressSpace() const { + return DefaultGlobalsAddrSpace; + } bool hasMicrosoftFastStdCallMangling() const { return ManglingMode == MM_WinCOFFX86; diff --git a/llvm/include/llvm/IR/GlobalVariable.h b/llvm/include/llvm/IR/GlobalVariable.h --- a/llvm/include/llvm/IR/GlobalVariable.h +++ b/llvm/include/llvm/IR/GlobalVariable.h @@ -56,10 +56,11 @@ bool isExternallyInitialized = false); /// GlobalVariable ctor - This creates a global and inserts it before the /// specified other global. - GlobalVariable(Module &M, Type *Ty, bool isConstant, - LinkageTypes Linkage, Constant *Initializer, - const Twine &Name = "", GlobalVariable *InsertBefore = nullptr, - ThreadLocalMode = NotThreadLocal, unsigned AddressSpace = 0, + GlobalVariable(Module &M, Type *Ty, bool isConstant, LinkageTypes Linkage, + Constant *Initializer, const Twine &Name = "", + GlobalVariable *InsertBefore = nullptr, + ThreadLocalMode = NotThreadLocal, + Optional AddressSpace = None, bool isExternallyInitialized = false); GlobalVariable(const GlobalVariable &) = delete; GlobalVariable &operator=(const GlobalVariable &) = delete; 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 @@ -182,6 +182,7 @@ AllocaAddrSpace = 0; StackNaturalAlign.reset(); ProgramAddrSpace = 0; + DefaultGlobalsAddrSpace = 0; FunctionPtrAlign.reset(); TheFunctionPtrAlignType = FunctionPtrAlignType::Independent; ManglingMode = MM_None; @@ -479,6 +480,11 @@ return Err; break; } + case 'G': { // Default address space for global variables. + if (Error Err = getAddrSpace(Tok, DefaultGlobalsAddrSpace)) + return Err; + break; + } case 'm': if (!Tok.empty()) return reportError("Unexpected trailing characters after mangling " @@ -530,6 +536,7 @@ AllocaAddrSpace == Other.AllocaAddrSpace && StackNaturalAlign == Other.StackNaturalAlign && ProgramAddrSpace == Other.ProgramAddrSpace && + DefaultGlobalsAddrSpace == Other.DefaultGlobalsAddrSpace && FunctionPtrAlign == Other.FunctionPtrAlign && TheFunctionPtrAlignType == Other.TheFunctionPtrAlignType && ManglingMode == Other.ManglingMode && diff --git a/llvm/lib/IR/Globals.cpp b/llvm/lib/IR/Globals.cpp --- a/llvm/lib/IR/Globals.cpp +++ b/llvm/lib/IR/Globals.cpp @@ -352,11 +352,15 @@ GlobalVariable::GlobalVariable(Module &M, Type *Ty, bool constant, LinkageTypes Link, Constant *InitVal, const Twine &Name, GlobalVariable *Before, - ThreadLocalMode TLMode, unsigned AddressSpace, + ThreadLocalMode TLMode, + Optional AddressSpace, bool isExternallyInitialized) : GlobalObject(Ty, Value::GlobalVariableVal, OperandTraits::op_begin(this), - InitVal != nullptr, Link, Name, AddressSpace), + InitVal != nullptr, Link, Name, + AddressSpace + ? *AddressSpace + : M.getDataLayout().getDefaultGlobalsAddressSpace()), isConstantGlobal(constant), isExternallyInitializedConstant(isExternallyInitialized) { assert(!Ty->isFunctionTy() && PointerType::isValidElementType(Ty) && diff --git a/llvm/test/Assembler/invalid-datalayout-globals-addrspace.ll b/llvm/test/Assembler/invalid-datalayout-globals-addrspace.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Assembler/invalid-datalayout-globals-addrspace.ll @@ -0,0 +1,4 @@ +; RUN: not --crash llvm-as < %s 2>&1 | FileCheck %s + +; CHECK: Invalid address space, must be a 24-bit integer +target datalayout = "G16777216" diff --git a/llvm/unittests/IR/DataLayoutTest.cpp b/llvm/unittests/IR/DataLayoutTest.cpp --- a/llvm/unittests/IR/DataLayoutTest.cpp +++ b/llvm/unittests/IR/DataLayoutTest.cpp @@ -7,7 +7,9 @@ //===----------------------------------------------------------------------===// #include "llvm/IR/DataLayout.h" +#include "llvm/IR/GlobalVariable.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" #include "llvm/IR/Type.h" #include "gtest/gtest.h" @@ -56,4 +58,35 @@ DL.getValueOrABITypeAlignment(MaybeAlign(), FourByteAlignType)); } -} // anonymous namespace +TEST(DataLayoutTest, GlobalsAddressSpace) { + // When not explicitly defined the globals address space should be zero: + EXPECT_EQ(DataLayout("").getDefaultGlobalsAddressSpace(), 0u); + EXPECT_EQ(DataLayout("P1-A2").getDefaultGlobalsAddressSpace(), 0u); + EXPECT_EQ(DataLayout("G2").getDefaultGlobalsAddressSpace(), 2u); + // Check that creating a GlobalVariable without an explicit address space + // in a module with a default globals address space respects that default: + LLVMContext Context; + std::unique_ptr M(new Module("MyModule", Context)); + // Default is globals in address space zero: + auto *Int32 = Type::getInt32Ty(Context); + auto *DefaultGlobal1 = new GlobalVariable( + *M, Int32, false, GlobalValue::ExternalLinkage, nullptr); + EXPECT_EQ(DefaultGlobal1->getAddressSpace(), 0u); + auto *ExplicitGlobal1 = new GlobalVariable( + *M, Int32, false, GlobalValue::ExternalLinkage, nullptr, "", nullptr, + GlobalValue::NotThreadLocal, 123); + EXPECT_EQ(ExplicitGlobal1->getAddressSpace(), 123u); + + // When using a datalayout with the global address space set to 200, global + // variables should default to 200 + M->setDataLayout("G200"); + auto *DefaultGlobal2 = new GlobalVariable( + *M, Int32, false, GlobalValue::ExternalLinkage, nullptr); + EXPECT_EQ(DefaultGlobal2->getAddressSpace(), 200u); + auto *ExplicitGlobal2 = new GlobalVariable( + *M, Int32, false, GlobalValue::ExternalLinkage, nullptr, "", nullptr, + GlobalValue::NotThreadLocal, 123); + EXPECT_EQ(ExplicitGlobal2->getAddressSpace(), 123u); +} + +} // anonymous namespace