diff options
author | Nicolai Haehnle <nhaehnle@gmail.com> | 2019-06-25 11:51:35 +0000 |
---|---|---|
committer | Nicolai Haehnle <nhaehnle@gmail.com> | 2019-06-25 11:51:35 +0000 |
commit | 08e8cb576021ce493329bbc9fa29e31cb77bfbda (patch) | |
tree | 19bd8451cd9f1eda8a23f5c81c46ce52b5beb8f3 /llvm/lib/Target/AMDGPU | |
parent | b23c942ce4380295a0755237b3de468abd2b7337 (diff) | |
download | bcm5719-llvm-08e8cb576021ce493329bbc9fa29e31cb77bfbda.tar.gz bcm5719-llvm-08e8cb576021ce493329bbc9fa29e31cb77bfbda.zip |
AMDGPU/MC: Add .amdgpu_lds directive
Summary:
The directive defines a symbol as an group/local memory (LDS) symbol.
LDS symbols behave similar to common symbols for the purposes of ELF,
using the processor-specific SHN_AMDGPU_LDS as section index.
It is the linker and/or runtime loader's job to "instantiate" LDS symbols
and resolve relocations that reference them.
It is not possible to initialize LDS memory (not even zero-initialize
as for .bss).
We want to be able to link together objects -- starting with relocatable
objects, but possible expanding to shared objects in the future -- that
access LDS memory in a flexible way.
LDS memory is in an address space that is entirely separate from the
address space that contains the program image (code and normal data),
so having program segments for it doesn't really make sense.
Furthermore, we want to be able to compile multiple kernels in a
compilation unit which have disjoint use of LDS memory. In that case,
we may want to place LDS symbols differently for different kernels
to save memory (LDS memory is very limited and physically private to
each kernel invocation), so we can't simply place LDS symbols in a
.lds section.
Hence this solution where LDS symbols always stay undefined.
Change-Id: I08cbc37a7c0c32f53f7b6123aa0afc91dbc1748f
Reviewers: arsenm, rampitec, t-tye, b-sumner, jsjodin
Subscribers: kzhuravl, jvesely, wdng, yaxunl, dstuttard, tpr, rupprecht, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D61493
llvm-svn: 364296
Diffstat (limited to 'llvm/lib/Target/AMDGPU')
3 files changed, 92 insertions, 0 deletions
diff --git a/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp b/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp index 02a15692e51..27093076a22 100644 --- a/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp +++ b/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp @@ -915,6 +915,7 @@ private: bool ParseDirectiveHSAMetadata(); bool ParseDirectivePALMetadataBegin(); bool ParseDirectivePALMetadata(); + bool ParseDirectiveAMDGPULDS(); /// Common code to parse out a block of text (typically YAML) between start and /// end directives. @@ -3918,6 +3919,60 @@ bool AMDGPUAsmParser::ParseDirectivePALMetadata() { return false; } +/// ParseDirectiveAMDGPULDS +/// ::= .amdgpu_lds identifier ',' size_expression [',' align_expression] +bool AMDGPUAsmParser::ParseDirectiveAMDGPULDS() { + if (getParser().checkForValidSection()) + return true; + + StringRef Name; + SMLoc NameLoc = getLexer().getLoc(); + if (getParser().parseIdentifier(Name)) + return TokError("expected identifier in directive"); + + MCSymbol *Symbol = getContext().getOrCreateSymbol(Name); + if (parseToken(AsmToken::Comma, "expected ','")) + return true; + + unsigned LocalMemorySize = AMDGPU::IsaInfo::getLocalMemorySize(&getSTI()); + + int64_t Size; + SMLoc SizeLoc = getLexer().getLoc(); + if (getParser().parseAbsoluteExpression(Size)) + return true; + if (Size < 0) + return Error(SizeLoc, "size must be non-negative"); + if (Size > LocalMemorySize) + return Error(SizeLoc, "size is too large"); + + int64_t Align = 4; + if (getLexer().is(AsmToken::Comma)) { + Lex(); + SMLoc AlignLoc = getLexer().getLoc(); + if (getParser().parseAbsoluteExpression(Align)) + return true; + if (Align < 0 || !isPowerOf2_64(Align)) + return Error(AlignLoc, "alignment must be a power of two"); + + // Alignment larger than the size of LDS is possible in theory, as long + // as the linker manages to place to symbol at address 0, but we do want + // to make sure the alignment fits nicely into a 32-bit integer. + if (Align >= 1u << 31) + return Error(AlignLoc, "alignment is too large"); + } + + if (parseToken(AsmToken::EndOfStatement, + "unexpected token in '.amdgpu_lds' directive")) + return true; + + Symbol->redefineIfPossible(); + if (!Symbol->isUndefined()) + return Error(NameLoc, "invalid symbol redefinition"); + + getTargetStreamer().emitAMDGPULDS(Symbol, Size, Align); + return false; +} + bool AMDGPUAsmParser::ParseDirective(AsmToken DirectiveID) { StringRef IDVal = DirectiveID.getString(); @@ -3951,6 +4006,9 @@ bool AMDGPUAsmParser::ParseDirective(AsmToken DirectiveID) { return ParseDirectiveHSAMetadata(); } + if (IDVal == ".amdgpu_lds") + return ParseDirectiveAMDGPULDS(); + if (IDVal == PALMD::AssemblerDirectiveBegin) return ParseDirectivePALMetadataBegin(); diff --git a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.cpp b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.cpp index b675004b59f..39996cd28ae 100644 --- a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.cpp +++ b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.cpp @@ -206,6 +206,12 @@ void AMDGPUTargetAsmStreamer::EmitAMDGPUSymbolType(StringRef SymbolName, } } +void AMDGPUTargetAsmStreamer::emitAMDGPULDS(MCSymbol *Symbol, unsigned Size, + unsigned Align) { + OS << "\t.amdgpu_lds " << Symbol->getName() << ", " << Size << ", " << Align + << '\n'; +} + bool AMDGPUTargetAsmStreamer::EmitISAVersion(StringRef IsaVersionString) { OS << "\t.amd_amdgpu_isa \"" << IsaVersionString << "\"\n"; return true; @@ -497,6 +503,27 @@ void AMDGPUTargetELFStreamer::EmitAMDGPUSymbolType(StringRef SymbolName, Symbol->setType(Type); } +void AMDGPUTargetELFStreamer::emitAMDGPULDS(MCSymbol *Symbol, unsigned Size, + unsigned Align) { + assert(isPowerOf2_32(Align)); + + MCSymbolELF *SymbolELF = cast<MCSymbolELF>(Symbol); + SymbolELF->setType(ELF::STT_OBJECT); + + if (!SymbolELF->isBindingSet()) { + SymbolELF->setBinding(ELF::STB_GLOBAL); + SymbolELF->setExternal(true); + } + + if (SymbolELF->declareCommon(Size, Align, true)) { + report_fatal_error("Symbol: " + Symbol->getName() + + " redeclared as different type"); + } + + SymbolELF->setIndex(ELF::SHN_AMDGPU_LDS); + SymbolELF->setSize(MCConstantExpr::create(Size, getContext())); +} + bool AMDGPUTargetELFStreamer::EmitISAVersion(StringRef IsaVersionString) { // Create two labels to mark the beginning and end of the desc field // and a MCExpr to calculate the size of the desc field. diff --git a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.h b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.h index 9c52199bf6d..683b3e363b9 100644 --- a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.h +++ b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.h @@ -53,6 +53,9 @@ public: virtual void EmitAMDGPUSymbolType(StringRef SymbolName, unsigned Type) = 0; + virtual void emitAMDGPULDS(MCSymbol *Symbol, unsigned Size, + unsigned Align) = 0; + /// \returns True on success, false on failure. virtual bool EmitISAVersion(StringRef IsaVersionString) = 0; @@ -107,6 +110,8 @@ public: void EmitAMDGPUSymbolType(StringRef SymbolName, unsigned Type) override; + void emitAMDGPULDS(MCSymbol *Sym, unsigned Size, unsigned Align) override; + /// \returns True on success, false on failure. bool EmitISAVersion(StringRef IsaVersionString) override; @@ -152,6 +157,8 @@ public: void EmitAMDGPUSymbolType(StringRef SymbolName, unsigned Type) override; + void emitAMDGPULDS(MCSymbol *Sym, unsigned Size, unsigned Align) override; + /// \returns True on success, false on failure. bool EmitISAVersion(StringRef IsaVersionString) override; |