Skip to content

Commit

Permalink
Allow DataLayout to specify addrspace for allocas.
Browse files Browse the repository at this point in the history
LLVM makes several assumptions about address space 0. However,
alloca is presently constrained to always return this address space.
There's no real way to avoid using alloca, so without this
there is no way to opt out of these assumptions.

The problematic assumptions include:
- That the pointer size used for the stack is the same size as
  the code size pointer, which is also the maximum sized pointer.

- That 0 is an invalid, non-dereferencable pointer value.

These are problems for AMDGPU because alloca is used to
implement the private address space, which uses a 32-bit
index as the pointer value. Other pointers are 64-bit
and behave more like LLVM's notion of generic address
space. By changing the address space used for allocas,
we can change our generic pointer type to be LLVM's generic
pointer type which does have similar properties.

llvm-svn: 299888
  • Loading branch information
arsenm committed Apr 10, 2017
1 parent d78bd57 commit 3c1fc76
Show file tree
Hide file tree
Showing 34 changed files with 382 additions and 72 deletions.
7 changes: 5 additions & 2 deletions llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1812,6 +1812,9 @@ as follows:
must be a multiple of 8-bits. If omitted, the natural stack
alignment defaults to "unspecified", which does not prevent any
alignment promotions.
``A<address space>``
Specifies the address space of objects created by '``alloca``'.
Defaults to the default address space of 0.
``p[n]:<size>:<abi>:<pref>``
This specifies the *size* of a pointer and its ``<abi>`` and
``<pref>``\erred alignments for address space ``n``. All sizes are in
Expand Down Expand Up @@ -7192,15 +7195,15 @@ Syntax:

::

<result> = alloca [inalloca] <type> [, <ty> <NumElements>] [, align <alignment>] ; yields type*:result
<result> = alloca [inalloca] <type> [, <ty> <NumElements>] [, align <alignment>] [, addrspace(<num>)] ; yields type addrspace(num)*:result

Overview:
"""""""""

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
default address space (address space zero).
address space for allocas indicated in the datalayout.

Arguments:
""""""""""
Expand Down
3 changes: 3 additions & 0 deletions llvm/include/llvm/IR/DataLayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ class DataLayout {
/// Defaults to false.
bool BigEndian;

unsigned AllocaAddrSpace;
unsigned StackNaturalAlign;

enum ManglingModeT {
Expand Down Expand Up @@ -186,6 +187,7 @@ class DataLayout {
clear();
StringRepresentation = DL.StringRepresentation;
BigEndian = DL.isBigEndian();
AllocaAddrSpace = DL.AllocaAddrSpace;
StackNaturalAlign = DL.StackNaturalAlign;
ManglingMode = DL.ManglingMode;
LegalIntWidths = DL.LegalIntWidths;
Expand Down Expand Up @@ -241,6 +243,7 @@ class DataLayout {
}

unsigned getStackAlignment() const { return StackNaturalAlign; }
unsigned getAllocaAddrSpace() const { return AllocaAddrSpace; }

bool hasMicrosoftFastStdCallMangling() const {
return ManglingMode == MM_WinCOFFX86;
Expand Down
9 changes: 8 additions & 1 deletion llvm/include/llvm/IR/IRBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Operator.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
Expand Down Expand Up @@ -1089,9 +1090,15 @@ class IRBuilder : public IRBuilderBase, public Inserter {
// Instruction creation methods: Memory Instructions
//===--------------------------------------------------------------------===//

AllocaInst *CreateAlloca(Type *Ty, unsigned AddrSpace,
Value *ArraySize = nullptr, const Twine &Name = "") {
return Insert(new AllocaInst(Ty, AddrSpace, ArraySize), Name);
}

AllocaInst *CreateAlloca(Type *Ty, Value *ArraySize = nullptr,
const Twine &Name = "") {
return Insert(new AllocaInst(Ty, ArraySize), Name);
const DataLayout &DL = BB->getParent()->getParent()->getDataLayout();
return Insert(new AllocaInst(Ty, DL.getAllocaAddrSpace(), ArraySize), Name);
}
// \brief Provided to resolve 'CreateLoad(Ptr, "...")' correctly, instead of
// converting the string to 'bool' for the isVolatile parameter.
Expand Down
15 changes: 9 additions & 6 deletions llvm/include/llvm/IR/Instructions.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,18 +67,21 @@ class AllocaInst : public UnaryInstruction {
AllocaInst *cloneImpl() const;

public:
explicit AllocaInst(Type *Ty, Value *ArraySize = nullptr,
explicit AllocaInst(Type *Ty, unsigned AddrSpace,
Value *ArraySize = nullptr,
const Twine &Name = "",
Instruction *InsertBefore = nullptr);
AllocaInst(Type *Ty, Value *ArraySize,
AllocaInst(Type *Ty, unsigned AddrSpace, Value *ArraySize,
const Twine &Name, BasicBlock *InsertAtEnd);

AllocaInst(Type *Ty, const Twine &Name, Instruction *InsertBefore = nullptr);
AllocaInst(Type *Ty, const Twine &Name, BasicBlock *InsertAtEnd);
AllocaInst(Type *Ty, unsigned AddrSpace,
const Twine &Name, Instruction *InsertBefore = nullptr);
AllocaInst(Type *Ty, unsigned AddrSpace,
const Twine &Name, BasicBlock *InsertAtEnd);

AllocaInst(Type *Ty, Value *ArraySize, unsigned Align,
AllocaInst(Type *Ty, unsigned AddrSpace, Value *ArraySize, unsigned Align,
const Twine &Name = "", Instruction *InsertBefore = nullptr);
AllocaInst(Type *Ty, Value *ArraySize, unsigned Align,
AllocaInst(Type *Ty, unsigned AddrSpace, Value *ArraySize, unsigned Align,
const Twine &Name, BasicBlock *InsertAtEnd);

// Out of line virtual method, so the vtable, etc. has a home.
Expand Down
53 changes: 49 additions & 4 deletions llvm/lib/AsmParser/LLParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1852,6 +1852,34 @@ bool LLParser::ParseOptionalCommaAlign(unsigned &Alignment,
return false;
}

/// ParseOptionalCommaAddrSpace
/// ::=
/// ::= ',' addrspace(1)
///
/// This returns with AteExtraComma set to true if it ate an excess comma at the
/// end.
bool LLParser::ParseOptionalCommaAddrSpace(unsigned &AddrSpace,
LocTy &Loc,
bool &AteExtraComma) {
AteExtraComma = false;
while (EatIfPresent(lltok::comma)) {
// Metadata at the end is an early exit.
if (Lex.getKind() == lltok::MetadataVar) {
AteExtraComma = true;
return false;
}

Loc = Lex.getLoc();
if (Lex.getKind() != lltok::kw_addrspace)
return Error(Lex.getLoc(), "expected metadata or 'addrspace'");

if (ParseOptionalAddrSpace(AddrSpace))
return true;
}

return false;
}

bool LLParser::parseAllocSizeArguments(unsigned &BaseSizeArg,
Optional<unsigned> &HowManyArg) {
Lex.Lex();
Expand Down Expand Up @@ -6033,8 +6061,9 @@ bool LLParser::ParseCall(Instruction *&Inst, PerFunctionState &PFS,
/// (',' 'align' i32)?
int LLParser::ParseAlloc(Instruction *&Inst, PerFunctionState &PFS) {
Value *Size = nullptr;
LocTy SizeLoc, TyLoc;
LocTy SizeLoc, TyLoc, ASLoc;
unsigned Alignment = 0;
unsigned AddrSpace = 0;
Type *Ty = nullptr;

bool IsInAlloca = EatIfPresent(lltok::kw_inalloca);
Expand All @@ -6048,20 +6077,36 @@ int LLParser::ParseAlloc(Instruction *&Inst, PerFunctionState &PFS) {
bool AteExtraComma = false;
if (EatIfPresent(lltok::comma)) {
if (Lex.getKind() == lltok::kw_align) {
if (ParseOptionalAlignment(Alignment)) return true;
if (ParseOptionalAlignment(Alignment))
return true;
if (ParseOptionalCommaAddrSpace(AddrSpace, ASLoc, AteExtraComma))
return true;
} else if (Lex.getKind() == lltok::kw_addrspace) {
ASLoc = Lex.getLoc();
if (ParseOptionalAddrSpace(AddrSpace))
return true;
} else if (Lex.getKind() == lltok::MetadataVar) {
AteExtraComma = true;
} else {
if (ParseTypeAndValue(Size, SizeLoc, PFS) ||
ParseOptionalCommaAlign(Alignment, AteExtraComma))
ParseOptionalCommaAlign(Alignment, AteExtraComma) ||
(!AteExtraComma &&
ParseOptionalCommaAddrSpace(AddrSpace, ASLoc, AteExtraComma)))
return true;
}
}

if (Size && !Size->getType()->isIntegerTy())
return Error(SizeLoc, "element count must have integer type");

AllocaInst *AI = new AllocaInst(Ty, Size, Alignment);
const DataLayout &DL = M->getDataLayout();
unsigned AS = DL.getAllocaAddrSpace();
if (AS != AddrSpace) {
// TODO: In the future it should be possible to specify addrspace per-alloca.
return Error(ASLoc, "address space must match datalayout");
}

AllocaInst *AI = new AllocaInst(Ty, AS, Size, Alignment);
AI->setUsedWithInAlloca(IsInAlloca);
AI->setSwiftError(IsSwiftError);
Inst = AI;
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/AsmParser/LLParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,8 @@ namespace llvm {
bool ParseOrdering(AtomicOrdering &Ordering);
bool ParseOptionalStackAlignment(unsigned &Alignment);
bool ParseOptionalCommaAlign(unsigned &Alignment, bool &AteExtraComma);
bool ParseOptionalCommaAddrSpace(unsigned &AddrSpace, LocTy &Loc,
bool &AteExtraComma);
bool ParseOptionalCommaInAlloca(bool &IsInAlloca);
bool parseAllocSizeArguments(unsigned &ElemSizeArg,
Optional<unsigned> &HowManyArg);
Expand Down
7 changes: 6 additions & 1 deletion llvm/lib/Bitcode/Reader/BitcodeReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4006,7 +4006,12 @@ Error BitcodeReader::parseFunctionBody(Function *F) {
}
if (!Ty || !Size)
return error("Invalid record");
AllocaInst *AI = new AllocaInst(Ty, Size, Align);

// FIXME: Make this an optional field.
const DataLayout &DL = TheModule->getDataLayout();
unsigned AS = DL.getAllocaAddrSpace();

AllocaInst *AI = new AllocaInst(Ty, AS, Size, Align);
AI->setUsedWithInAlloca(InAlloca);
AI->setSwiftError(SwiftError);
I = AI;
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/CodeGen/SjLjEHPrepare.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,8 @@ Value *SjLjEHPrepare::setupFunctionContext(Function &F,
// because the value needs to be added to the global context list.
auto &DL = F.getParent()->getDataLayout();
unsigned Align = DL.getPrefTypeAlignment(FunctionContextTy);
FuncCtx = new AllocaInst(FunctionContextTy, nullptr, Align, "fn_context",
&EntryBB->front());
FuncCtx = new AllocaInst(FunctionContextTy, DL.getAllocaAddrSpace(),
nullptr, Align, "fn_context", &EntryBB->front());

// Fill in the function context structure.
for (LandingPadInst *LPI : LPads) {
Expand Down
6 changes: 4 additions & 2 deletions llvm/lib/CodeGen/WinEHPrepare.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ class WinEHPrepare : public FunctionPass {
// All fields are reset by runOnFunction.
EHPersonality Personality = EHPersonality::Unknown;

const DataLayout *DL = nullptr;
DenseMap<BasicBlock *, ColorVector> BlockColors;
MapVector<BasicBlock *, std::vector<BasicBlock *>> FuncletBlocks;
};
Expand All @@ -111,6 +112,7 @@ bool WinEHPrepare::runOnFunction(Function &Fn) {
if (!isFuncletEHPersonality(Personality))
return false;

DL = &Fn.getParent()->getDataLayout();
return prepareExplicitEH(Fn);
}

Expand Down Expand Up @@ -1070,7 +1072,7 @@ AllocaInst *WinEHPrepare::insertPHILoads(PHINode *PN, Function &F) {
if (!isa<TerminatorInst>(EHPad)) {
// If the EHPad isn't a terminator, then we can insert a load in this block
// that will dominate all uses.
SpillSlot = new AllocaInst(PN->getType(), nullptr,
SpillSlot = new AllocaInst(PN->getType(), DL->getAllocaAddrSpace(), nullptr,
Twine(PN->getName(), ".wineh.spillslot"),
&F.getEntryBlock().front());
Value *V = new LoadInst(SpillSlot, Twine(PN->getName(), ".wineh.reload"),
Expand Down Expand Up @@ -1157,7 +1159,7 @@ void WinEHPrepare::replaceUseWithLoad(Value *V, Use &U, AllocaInst *&SpillSlot,
Function &F) {
// Lazilly create the spill slot.
if (!SpillSlot)
SpillSlot = new AllocaInst(V->getType(), nullptr,
SpillSlot = new AllocaInst(V->getType(), DL->getAllocaAddrSpace(), nullptr,
Twine(V->getName(), ".wineh.spillslot"),
&F.getEntryBlock().front());

Expand Down
6 changes: 6 additions & 0 deletions llvm/lib/IR/AsmWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3117,6 +3117,12 @@ void AssemblyWriter::printInstruction(const Instruction &I) {
if (AI->getAlignment()) {
Out << ", align " << AI->getAlignment();
}

unsigned AddrSpace = AI->getType()->getAddressSpace();
if (AddrSpace != 0) {
Out << ", addrspace(" << AddrSpace << ')';
}

} else if (isa<CastInst>(I)) {
if (Operand) {
Out << ' ';
Expand Down
8 changes: 8 additions & 0 deletions llvm/lib/IR/DataLayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ void DataLayout::reset(StringRef Desc) {

LayoutMap = nullptr;
BigEndian = false;
AllocaAddrSpace = 0;
StackNaturalAlign = 0;
ManglingMode = MM_None;
NonIntegralAddressSpaces.clear();
Expand Down Expand Up @@ -352,6 +353,12 @@ void DataLayout::parseSpecifier(StringRef Desc) {
StackNaturalAlign = inBytes(getInt(Tok));
break;
}
case 'A': { // Default stack/alloca address space.
AllocaAddrSpace = getInt(Tok);
if (!isUInt<24>(AllocaAddrSpace))
report_fatal_error("Invalid address space, must be a 24bit integer");
break;
}
case 'm':
if (!Tok.empty())
report_fatal_error("Unexpected trailing characters after mangling specifier in datalayout string");
Expand Down Expand Up @@ -394,6 +401,7 @@ void DataLayout::init(const Module *M) { *this = M->getDataLayout(); }

bool DataLayout::operator==(const DataLayout &Other) const {
bool Ret = BigEndian == Other.BigEndian &&
AllocaAddrSpace == Other.AllocaAddrSpace &&
StackNaturalAlign == Other.StackNaturalAlign &&
ManglingMode == Other.ManglingMode &&
LegalIntWidths == Other.LegalIntWidths &&
Expand Down
41 changes: 23 additions & 18 deletions llvm/lib/IR/Instructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1199,34 +1199,38 @@ static Value *getAISize(LLVMContext &Context, Value *Amt) {
return Amt;
}

AllocaInst::AllocaInst(Type *Ty, const Twine &Name, Instruction *InsertBefore)
: AllocaInst(Ty, /*ArraySize=*/nullptr, Name, InsertBefore) {}

AllocaInst::AllocaInst(Type *Ty, const Twine &Name, BasicBlock *InsertAtEnd)
: AllocaInst(Ty, /*ArraySize=*/nullptr, Name, InsertAtEnd) {}

AllocaInst::AllocaInst(Type *Ty, Value *ArraySize, const Twine &Name,
AllocaInst::AllocaInst(Type *Ty, unsigned AddrSpace, const Twine &Name,
Instruction *InsertBefore)
: AllocaInst(Ty, ArraySize, /*Align=*/0, Name, InsertBefore) {}
: AllocaInst(Ty, AddrSpace, /*ArraySize=*/nullptr, Name, InsertBefore) {}

AllocaInst::AllocaInst(Type *Ty, Value *ArraySize, const Twine &Name,
AllocaInst::AllocaInst(Type *Ty, unsigned AddrSpace, const Twine &Name,
BasicBlock *InsertAtEnd)
: AllocaInst(Ty, ArraySize, /*Align=*/0, Name, InsertAtEnd) {}
: AllocaInst(Ty, AddrSpace, /*ArraySize=*/nullptr, Name, InsertAtEnd) {}

AllocaInst::AllocaInst(Type *Ty, Value *ArraySize, unsigned Align,
AllocaInst::AllocaInst(Type *Ty, unsigned AddrSpace, Value *ArraySize,
const Twine &Name, Instruction *InsertBefore)
: UnaryInstruction(PointerType::getUnqual(Ty), Alloca,
getAISize(Ty->getContext(), ArraySize), InsertBefore),
AllocatedType(Ty) {
: AllocaInst(Ty, AddrSpace, ArraySize, /*Align=*/0, Name, InsertBefore) {}

AllocaInst::AllocaInst(Type *Ty, unsigned AddrSpace, Value *ArraySize,
const Twine &Name, BasicBlock *InsertAtEnd)
: AllocaInst(Ty, AddrSpace, ArraySize, /*Align=*/0, Name, InsertAtEnd) {}

AllocaInst::AllocaInst(Type *Ty, unsigned AddrSpace, Value *ArraySize,
unsigned Align, const Twine &Name,
Instruction *InsertBefore)
: UnaryInstruction(PointerType::get(Ty, AddrSpace), Alloca,
getAISize(Ty->getContext(), ArraySize), InsertBefore),
AllocatedType(Ty) {
setAlignment(Align);
assert(!Ty->isVoidTy() && "Cannot allocate void!");
setName(Name);
}

AllocaInst::AllocaInst(Type *Ty, Value *ArraySize, unsigned Align,
const Twine &Name, BasicBlock *InsertAtEnd)
: UnaryInstruction(PointerType::getUnqual(Ty), Alloca,
getAISize(Ty->getContext(), ArraySize), InsertAtEnd),
AllocaInst::AllocaInst(Type *Ty, unsigned AddrSpace, Value *ArraySize,
unsigned Align, const Twine &Name,
BasicBlock *InsertAtEnd)
: UnaryInstruction(PointerType::get(Ty, AddrSpace), Alloca,
getAISize(Ty->getContext(), ArraySize), InsertAtEnd),
AllocatedType(Ty) {
setAlignment(Align);
assert(!Ty->isVoidTy() && "Cannot allocate void!");
Expand Down Expand Up @@ -3828,6 +3832,7 @@ InsertValueInst *InsertValueInst::cloneImpl() const {

AllocaInst *AllocaInst::cloneImpl() const {
AllocaInst *Result = new AllocaInst(getAllocatedType(),
getType()->getAddressSpace(),
(Value *)getOperand(0), getAlignment());
Result->setUsedWithInAlloca(isUsedWithInAlloca());
Result->setSwiftError(isSwiftError());
Expand Down
5 changes: 3 additions & 2 deletions llvm/lib/IR/Verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3181,8 +3181,9 @@ void Verifier::verifySwiftErrorValue(const Value *SwiftErrorVal) {
void Verifier::visitAllocaInst(AllocaInst &AI) {
SmallPtrSet<Type*, 4> Visited;
PointerType *PTy = AI.getType();
Assert(PTy->getAddressSpace() == 0,
"Allocation instruction pointer not in the generic address space!",
// TODO: Relax this restriction?
Assert(PTy->getAddressSpace() == DL.getAllocaAddrSpace(),
"Allocation instruction pointer not in the stack address space!",
&AI);
Assert(AI.getAllocatedType()->isSized(&Visited),
"Cannot allocate unsized type", &AI);
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/Target/NVPTX/NVPTXLowerArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,8 @@ void NVPTXLowerArgs::handleByValParam(Argument *Arg) {
assert(PType && "Expecting pointer type in handleByValParam");

Type *StructType = PType->getElementType();
AllocaInst *AllocA = new AllocaInst(StructType, Arg->getName(), FirstInst);
unsigned AS = Func->getParent()->getDataLayout().getAllocaAddrSpace();
AllocaInst *AllocA = new AllocaInst(StructType, AS, Arg->getName(), FirstInst);
// Set the alignment to alignment of the byval parameter. This is because,
// later load/stores assume that alignment, and we are going to replace
// the use of the byval parameter with this alloca instruction.
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/Transforms/Coroutines/CoroElide.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@ void Lowerer::elideHeapAllocations(Function *F, Type *FrameTy, AAResults &AA) {
// is spilled into the coroutine frame and recreate the alignment information
// here. Possibly we will need to do a mini SROA here and break the coroutine
// frame into individual AllocaInst recreating the original alignment.
auto *Frame = new AllocaInst(FrameTy, "", InsertPt);
const DataLayout &DL = F->getParent()->getDataLayout();
auto *Frame = new AllocaInst(FrameTy, DL.getAllocaAddrSpace(), "", InsertPt);
auto *FrameVoidPtr =
new BitCastInst(Frame, Type::getInt8PtrTy(C), "vFrame", InsertPt);

Expand Down
Loading

0 comments on commit 3c1fc76

Please sign in to comment.