diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -2459,9 +2459,11 @@ 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. +``A::...`` + Specifies the valid address spaces in which ``alloca`` can create + objects. The address space immediately following the ``A`` is + the default alloca address space. If omitted, the default is that + ``alloca`` should return pointers in address space 0. ``p[n]::::`` This specifies the *size* of a pointer and its ```` and ````\erred alignments for address space ``n``. The fourth parameter @@ -9551,8 +9553,7 @@ The '``alloca``' instruction allocates memory on the stack frame of the currently executing function, to be automatically released when this -function returns to its caller. The object is always allocated in the -address space for allocas indicated in the datalayout. +function returns to its caller. Arguments: """""""""" @@ -9583,6 +9584,12 @@ pointer may not be unique. The order in which memory is allocated (ie., which way the stack grows) is not specified. +If not explicitly specified, the result is allocated in the default +alloca address space for the target. Note that the set of valid address +spaces for alloca is specified in the target's datalayout; see +:ref:`datalayout string` for more on alloca address +spaces. + If the returned pointer is used by :ref:`llvm.lifetime.start `, the returned object is initially dead. See :ref:`llvm.lifetime.start ` and 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 @@ -121,7 +121,7 @@ /// Defaults to false. bool BigEndian; - unsigned AllocaAddrSpace; + SmallVector AllocaAddrSpaces; MaybeAlign StackNaturalAlign; unsigned ProgramAddrSpace; unsigned DefaultGlobalsAddrSpace; @@ -211,7 +211,7 @@ clear(); StringRepresentation = DL.StringRepresentation; BigEndian = DL.isBigEndian(); - AllocaAddrSpace = DL.AllocaAddrSpace; + AllocaAddrSpaces = DL.AllocaAddrSpaces; StackNaturalAlign = DL.StackNaturalAlign; FunctionPtrAlign = DL.FunctionPtrAlign; TheFunctionPtrAlignType = DL.TheFunctionPtrAlignType; @@ -276,7 +276,17 @@ return *StackNaturalAlign; } - unsigned getAllocaAddrSpace() const { return AllocaAddrSpace; } + /// Return the address spaces in which we can alloca. + ArrayRef getAllocaAddrSpaces() const { return AllocaAddrSpaces; } + + /// Return true if we can alloca in the given address space. + bool isAllocaAddrSpace(unsigned AddrSpace) const { + ArrayRef AllocaSpaces = getAllocaAddrSpaces(); + return is_contained(AllocaSpaces, AddrSpace); + } + + // Return the default alloca address space. + unsigned getAllocaAddrSpace() const { return getAllocaAddrSpaces().front(); } /// Returns the alignment of function pointers, which may or may not be /// related to the alignment of functions. 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 @@ -180,7 +180,7 @@ LayoutMap = nullptr; BigEndian = false; - AllocaAddrSpace = 0; + AllocaAddrSpaces.clear(); StackNaturalAlign.reset(); ProgramAddrSpace = 0; DefaultGlobalsAddrSpace = 0; @@ -476,9 +476,20 @@ return Err; break; } - case 'A': { // Default stack/alloca address space. - if (Error Err = getAddrSpace(Tok, AllocaAddrSpace)) - return Err; + case 'A': { // Alloca address spaces. The first one is the default. + while (true) { + unsigned AddrSpace; + if (Error Err = getAddrSpace(Tok, AddrSpace)) + return Err; + if (isAllocaAddrSpace(AddrSpace)) + return reportError( + "Duplicate alloca address space in datalayout string"); + AllocaAddrSpaces.push_back(AddrSpace); + if (Rest.empty()) + break; + if (Error Err = split(Rest, ':', Split)) + return Err; + } break; } case 'G': { // Default address space for global variables. @@ -523,6 +534,10 @@ } } + // If no alloca address spaces specified, default to address space 0. + if (AllocaAddrSpaces.empty()) + AllocaAddrSpaces.push_back(0); + return Error::success(); } @@ -534,7 +549,7 @@ bool DataLayout::operator==(const DataLayout &Other) const { bool Ret = BigEndian == Other.BigEndian && - AllocaAddrSpace == Other.AllocaAddrSpace && + getAllocaAddrSpaces() == Other.getAllocaAddrSpaces() && StackNaturalAlign == Other.StackNaturalAlign && ProgramAddrSpace == Other.ProgramAddrSpace && DefaultGlobalsAddrSpace == Other.DefaultGlobalsAddrSpace && 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 @@ -3802,10 +3802,8 @@ void Verifier::visitAllocaInst(AllocaInst &AI) { SmallPtrSet Visited; PointerType *PTy = AI.getType(); - // TODO: Relax this restriction? - Assert(PTy->getAddressSpace() == DL.getAllocaAddrSpace(), - "Allocation instruction pointer not in the stack address space!", - &AI); + Assert(DL.isAllocaAddrSpace(PTy->getAddressSpace()), + "Allocation instruction pointer not in a stack address space!", &AI); Assert(AI.getAllocatedType()->isSized(&Visited), "Cannot allocate unsized type", &AI); Assert(AI.getArraySize()->getType()->isIntegerTy(), diff --git a/llvm/test/Assembler/datalayout-alloca-addrspace-mismatch-0.ll b/llvm/test/Assembler/datalayout-alloca-addrspace-mismatch-0.ll --- a/llvm/test/Assembler/datalayout-alloca-addrspace-mismatch-0.ll +++ b/llvm/test/Assembler/datalayout-alloca-addrspace-mismatch-0.ll @@ -2,7 +2,7 @@ target datalayout = "A1" -; CHECK: Allocation instruction pointer not in the stack address space! +; CHECK: Allocation instruction pointer not in a stack address space! ; CHECK-NEXT: %alloca_scalar_no_align = alloca i32, align 4, addrspace(2) define void @use_alloca() { diff --git a/llvm/test/Assembler/datalayout-alloca-addrspace-mismatch-1.ll b/llvm/test/Assembler/datalayout-alloca-addrspace-mismatch-1.ll --- a/llvm/test/Assembler/datalayout-alloca-addrspace-mismatch-1.ll +++ b/llvm/test/Assembler/datalayout-alloca-addrspace-mismatch-1.ll @@ -2,7 +2,7 @@ target datalayout = "A1" -; CHECK: Allocation instruction pointer not in the stack address space! +; CHECK: Allocation instruction pointer not in a stack address space! ; CHECK-NEXT: %alloca_scalar_no_align = alloca i32, align 4, addrspace(2) define void @use_alloca() { diff --git a/llvm/test/Assembler/datalayout-alloca-addrspace-mismatch-2.ll b/llvm/test/Assembler/datalayout-alloca-addrspace-mismatch-2.ll --- a/llvm/test/Assembler/datalayout-alloca-addrspace-mismatch-2.ll +++ b/llvm/test/Assembler/datalayout-alloca-addrspace-mismatch-2.ll @@ -2,7 +2,7 @@ target datalayout = "A1" -; CHECK: Allocation instruction pointer not in the stack address space! +; CHECK: Allocation instruction pointer not in a stack address space! ; CHECK-NEXT: %alloca_scalar_no_align = alloca i32, align 4, addrspace(2), !foo !0 define void @use_alloca() { diff --git a/llvm/test/Assembler/drop-debug-info-nonzero-alloca.ll b/llvm/test/Assembler/drop-debug-info-nonzero-alloca.ll --- a/llvm/test/Assembler/drop-debug-info-nonzero-alloca.ll +++ b/llvm/test/Assembler/drop-debug-info-nonzero-alloca.ll @@ -12,7 +12,7 @@ metadata i8* undef, metadata !DILocalVariable(scope: !1), metadata !DIExpression()) -; ALL-NOT: Allocation instruction pointer not in the stack address space! +; ALL-NOT: Allocation instruction pointer not in a stack address space! ; AS: llvm.dbg.value intrinsic requires a !dbg attachment ; AS: warning: ignoring invalid debug info in ret void diff --git a/llvm/test/CodeGen/AMDGPU/invalid-alloca.ll b/llvm/test/CodeGen/AMDGPU/invalid-alloca.ll --- a/llvm/test/CodeGen/AMDGPU/invalid-alloca.ll +++ b/llvm/test/CodeGen/AMDGPU/invalid-alloca.ll @@ -5,7 +5,7 @@ ; RUN: llvm-as < %s | not opt -data-layout=A5 2>&1 | FileCheck -check-prefixes=MISMATCH %s ; AS: assembly parsed, but does not verify as correct! -; COMMON: Allocation instruction pointer not in the stack address space! +; COMMON: Allocation instruction pointer not in a stack address space! ; COMMON: %tmp = alloca i32 ; MISMATCH: Explicit load/store type does not match pointee type of pointer operand ; LLC: error: {{.*}}input module cannot be verified diff --git a/llvm/test/Verifier/alloca-alternate-addrspace-invalid-0.ll b/llvm/test/Verifier/alloca-alternate-addrspace-invalid-0.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Verifier/alloca-alternate-addrspace-invalid-0.ll @@ -0,0 +1,9 @@ +; RUN: not llvm-as %s 2>&1 | FileCheck %s + +target datalayout = "A1" + +define void @use_alloca() { +; CHECK: Allocation instruction pointer not in a stack address space! + %alloca_scalar_no_align = alloca i32, addrspace(2) + ret void +} diff --git a/llvm/test/Verifier/alloca-alternate-addrspace-invalid-1.ll b/llvm/test/Verifier/alloca-alternate-addrspace-invalid-1.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Verifier/alloca-alternate-addrspace-invalid-1.ll @@ -0,0 +1,9 @@ +; RUN: not llvm-as %s 2>&1 | FileCheck %s + +target datalayout = "A1:3" + +define void @use_alloca() { +; CHECK: Allocation instruction pointer not in a stack address space! + %alloca_scalar_no_align = alloca i32, addrspace(2) + ret void +} diff --git a/llvm/test/Verifier/alloca-alternate-addrspace-invalid-2.ll b/llvm/test/Verifier/alloca-alternate-addrspace-invalid-2.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Verifier/alloca-alternate-addrspace-invalid-2.ll @@ -0,0 +1,9 @@ +; RUN: not llvm-as < %s 2>&1 | FileCheck %s + +target datalayout = "" + +define void @use_alloca() { +; CHECK: Allocation instruction pointer not in a stack address space! + %alloca_scalar_no_align = alloca i32, addrspace(2) + ret void +} diff --git a/llvm/test/Verifier/alloca-alternate-addrspace-valid.ll b/llvm/test/Verifier/alloca-alternate-addrspace-valid.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Verifier/alloca-alternate-addrspace-valid.ll @@ -0,0 +1,22 @@ +; RUN: llvm-as %s -o /dev/null + +; Should assemble without error. + +target datalayout = "A1:2:3" + +define void @use_alloca0() { + %alloca_scalar_no_align = alloca i32, addrspace(2) + ret void +} + +define void @use_alloca1() { + %alloca_scalar_no_align = alloca i32, align 4, addrspace(2) + ret void +} + +define void @use_alloca2() { + %alloca_scalar_no_align = alloca i32, align 4, addrspace(2), !foo !0 + ret void +} + +!0 = !{}