Skip to content

Commit 0ab6a63

Browse files
authored
[LLVM][IR] Add support for address space names in DataLayout (llvm#170559)
Add support for specifying the names of address spaces when specifying pointer properties for an address space. Update LLVM's AsmPrinter and LLParser to print and read these symbolic address space name.
1 parent 05ef57f commit 0ab6a63

File tree

7 files changed

+265
-57
lines changed

7 files changed

+265
-57
lines changed

llvm/docs/LangRef.rst

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3334,7 +3334,7 @@ as follows:
33343334
``A<address space>``
33353335
Specifies the address space of objects created by '``alloca``'.
33363336
Defaults to the default address space of 0.
3337-
``p[<flags>][<as>]:<size>:<abi>[:<pref>[:<idx>]]``
3337+
``p[<flags>][<as>][(<name>)]:<size>:<abi>[:<pref>[:<idx>]]``
33383338
This specifies the properties of a pointer in address space ``as``.
33393339
The ``<size>`` parameter specifies the size of the bitwise representation.
33403340
For :ref:`non-integral pointers <nointptrtype>` the representation size may
@@ -3353,7 +3353,11 @@ as follows:
33533353
The optional ``<flags>`` are used to specify properties of pointers in this
33543354
address space: the character ``u`` marks pointers as having an unstable
33553355
representation, and ``e`` marks pointers having external state. See
3356-
:ref:`Non-Integral Pointer Types <nointptrtype>`.
3356+
:ref:`Non-Integral Pointer Types <nointptrtype>`. The ``<name>`` is an
3357+
optional name of that address space, surrounded by ``(`` and ``)``. If the
3358+
name is specified, it must be unique to that address space and cannot be
3359+
``A``, ``G``, or ``P`` which are pre-defined names used to denote alloca,
3360+
global, and program address space respectively.
33573361

33583362
``i<size>:<abi>[:<pref>]``
33593363
This specifies the alignment for an integer type of a given bit

llvm/include/llvm/IR/DataLayout.h

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
#include "llvm/ADT/APInt.h"
2323
#include "llvm/ADT/ArrayRef.h"
24+
#include "llvm/ADT/DenseSet.h"
2425
#include "llvm/ADT/STLExtras.h"
2526
#include "llvm/ADT/SmallVector.h"
2627
#include "llvm/ADT/StringRef.h"
@@ -92,6 +93,9 @@ class DataLayout {
9293
/// of this would be CHERI capabilities where the validity bit is stored
9394
/// separately from the pointer address+bounds information.
9495
bool HasExternalState;
96+
// Symbolic name of the address space.
97+
std::string AddrSpaceName;
98+
9599
LLVM_ABI bool operator==(const PointerSpec &Other) const;
96100
};
97101

@@ -158,7 +162,8 @@ class DataLayout {
158162
/// Sets or updates the specification for pointer in the given address space.
159163
void setPointerSpec(uint32_t AddrSpace, uint32_t BitWidth, Align ABIAlign,
160164
Align PrefAlign, uint32_t IndexBitWidth,
161-
bool HasUnstableRepr, bool HasExternalState);
165+
bool HasUnstableRepr, bool HasExternalState,
166+
StringRef AddrSpaceName);
162167

163168
/// Internal helper to get alignment for integer of given bitwidth.
164169
LLVM_ABI Align getIntegerAlignment(uint32_t BitWidth, bool abi_or_pref) const;
@@ -173,11 +178,13 @@ class DataLayout {
173178
Error parseAggregateSpec(StringRef Spec);
174179

175180
/// Attempts to parse pointer specification ('p').
176-
Error parsePointerSpec(StringRef Spec);
181+
Error parsePointerSpec(StringRef Spec,
182+
SmallDenseSet<StringRef, 8> &AddrSpaceNames);
177183

178184
/// Attempts to parse a single specification.
179185
Error parseSpecification(StringRef Spec,
180-
SmallVectorImpl<unsigned> &NonIntegralAddressSpaces);
186+
SmallVectorImpl<unsigned> &NonIntegralAddressSpaces,
187+
SmallDenseSet<StringRef, 8> &AddrSpaceNames);
181188

182189
/// Attempts to parse a data layout string.
183190
Error parseLayoutString(StringRef LayoutString);
@@ -324,9 +331,13 @@ class DataLayout {
324331
return false;
325332
}
326333

327-
/// Layout pointer alignment
334+
/// Layout pointer alignment.
328335
LLVM_ABI Align getPointerABIAlignment(unsigned AS) const;
329336

337+
LLVM_ABI StringRef getAddressSpaceName(unsigned AS) const;
338+
339+
LLVM_ABI std::optional<unsigned> getNamedAddressSpace(StringRef Name) const;
340+
330341
/// Return target's alignment for stack-based pointers
331342
/// FIXME: The defaults need to be removed once all of
332343
/// the backends/clients are updated.

llvm/lib/AsmParser/LLParser.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1958,13 +1958,16 @@ bool LLParser::parseOptionalAddrSpace(unsigned &AddrSpace, unsigned DefaultAS) {
19581958

19591959
auto ParseAddrspaceValue = [&](unsigned &AddrSpace) -> bool {
19601960
if (Lex.getKind() == lltok::StringConstant) {
1961-
auto AddrSpaceStr = Lex.getStrVal();
1961+
const std::string &AddrSpaceStr = Lex.getStrVal();
19621962
if (AddrSpaceStr == "A") {
19631963
AddrSpace = M->getDataLayout().getAllocaAddrSpace();
19641964
} else if (AddrSpaceStr == "G") {
19651965
AddrSpace = M->getDataLayout().getDefaultGlobalsAddressSpace();
19661966
} else if (AddrSpaceStr == "P") {
19671967
AddrSpace = M->getDataLayout().getProgramAddressSpace();
1968+
} else if (std::optional<unsigned> AS =
1969+
M->getDataLayout().getNamedAddressSpace(AddrSpaceStr)) {
1970+
AddrSpace = *AS;
19681971
} else {
19691972
return tokError("invalid symbolic addrspace '" + AddrSpaceStr + "'");
19701973
}

llvm/lib/IR/AsmWriter.cpp

Lines changed: 47 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ static cl::opt<bool> PreserveAssemblyUseListOrder(
107107
"preserve-ll-uselistorder", cl::Hidden, cl::init(false),
108108
cl::desc("Preserve use-list order when writing LLVM assembly."));
109109

110+
static cl::opt<bool> PrintAddrspaceName("print-addrspace-name", cl::Hidden,
111+
cl::init(false),
112+
cl::desc("Print address space names"));
113+
110114
// Make virtual table appear in this compilation unit.
111115
AssemblyAnnotationWriter::~AssemblyAnnotationWriter() = default;
112116

@@ -543,7 +547,8 @@ namespace {
543547

544548
class TypePrinting {
545549
public:
546-
TypePrinting(const Module *M = nullptr) : DeferredM(M) {}
550+
TypePrinting(const Module *M = nullptr)
551+
: M(M), TypesIncorporated(M == nullptr) {}
547552

548553
TypePrinting(const TypePrinting &) = delete;
549554
TypePrinting &operator=(const TypePrinting &) = delete;
@@ -563,8 +568,9 @@ class TypePrinting {
563568
private:
564569
void incorporateTypes();
565570

566-
/// A module to process lazily when needed. Set to nullptr as soon as used.
567-
const Module *DeferredM;
571+
/// A module to process lazily.
572+
const Module *M;
573+
bool TypesIncorporated;
568574

569575
TypeFinder NamedTypes;
570576

@@ -605,11 +611,11 @@ bool TypePrinting::empty() {
605611
}
606612

607613
void TypePrinting::incorporateTypes() {
608-
if (!DeferredM)
614+
if (TypesIncorporated)
609615
return;
610616

611-
NamedTypes.run(*DeferredM, false);
612-
DeferredM = nullptr;
617+
NamedTypes.run(*M, false);
618+
TypesIncorporated = true;
613619

614620
// The list of struct types we got back includes all the struct types, split
615621
// the unnamed ones out to a numbering and remove the anonymous structs.
@@ -630,6 +636,21 @@ void TypePrinting::incorporateTypes() {
630636
NamedTypes.erase(NextToUse, NamedTypes.end());
631637
}
632638

639+
static void printAddressSpace(const Module *M, unsigned AS, raw_ostream &OS,
640+
StringRef Prefix = " ", StringRef Suffix = "",
641+
bool ForcePrint = false) {
642+
if (AS == 0 && !ForcePrint)
643+
return;
644+
OS << Prefix << "addrspace(";
645+
StringRef ASName =
646+
PrintAddrspaceName && M ? M->getDataLayout().getAddressSpaceName(AS) : "";
647+
if (!ASName.empty())
648+
OS << "\"" << ASName << "\"";
649+
else
650+
OS << AS;
651+
OS << ")" << Suffix;
652+
}
653+
633654
/// Write the specified type to the specified raw_ostream, making use of type
634655
/// names or up references to shorten the type name where possible.
635656
void TypePrinting::print(Type *Ty, raw_ostream &OS) {
@@ -686,8 +707,7 @@ void TypePrinting::print(Type *Ty, raw_ostream &OS) {
686707
case Type::PointerTyID: {
687708
PointerType *PTy = cast<PointerType>(Ty);
688709
OS << "ptr";
689-
if (unsigned AddressSpace = PTy->getAddressSpace())
690-
OS << " addrspace(" << AddressSpace << ')';
710+
printAddressSpace(M, PTy->getAddressSpace(), OS);
691711
return;
692712
}
693713
case Type::ArrayTyID: {
@@ -3896,10 +3916,10 @@ void AssemblyWriter::printGlobal(const GlobalVariable *GV) {
38963916
printThreadLocalModel(GV->getThreadLocalMode(), Out);
38973917
StringRef UA = getUnnamedAddrEncoding(GV->getUnnamedAddr());
38983918
if (!UA.empty())
3899-
Out << UA << ' ';
3919+
Out << UA << ' ';
39003920

3901-
if (unsigned AddressSpace = GV->getType()->getAddressSpace())
3902-
Out << "addrspace(" << AddressSpace << ") ";
3921+
printAddressSpace(GV->getParent(), GV->getType()->getAddressSpace(), Out,
3922+
/*Prefix=*/"", /*Suffix=*/" ");
39033923
if (GV->isExternallyInitialized()) Out << "externally_initialized ";
39043924
Out << (GV->isConstant() ? "constant " : "global ");
39053925
TypePrinter.print(GV->getValueType(), Out);
@@ -4174,9 +4194,10 @@ void AssemblyWriter::printFunction(const Function *F) {
41744194
// a module with a non-zero program address space or if there is no valid
41754195
// Module* so that the file can be parsed without the datalayout string.
41764196
const Module *Mod = F->getParent();
4177-
if (F->getAddressSpace() != 0 || !Mod ||
4178-
Mod->getDataLayout().getProgramAddressSpace() != 0)
4179-
Out << " addrspace(" << F->getAddressSpace() << ")";
4197+
bool ForcePrintAddressSpace =
4198+
!Mod || Mod->getDataLayout().getProgramAddressSpace() != 0;
4199+
printAddressSpace(Mod, F->getAddressSpace(), Out, /*Prefix=*/" ",
4200+
/*Suffix=*/"", ForcePrintAddressSpace);
41804201
if (Attrs.hasFnAttrs())
41814202
Out << " #" << Machine.getAttributeGroupSlot(Attrs.getFnAttrs());
41824203
if (F->hasSection()) {
@@ -4352,23 +4373,21 @@ void AssemblyWriter::printInfoComment(const Value &V, bool isMaterializable) {
43524373

43534374
static void maybePrintCallAddrSpace(const Value *Operand, const Instruction *I,
43544375
raw_ostream &Out) {
4355-
// We print the address space of the call if it is non-zero.
43564376
if (Operand == nullptr) {
43574377
Out << " <cannot get addrspace!>";
43584378
return;
43594379
}
4380+
4381+
// We print the address space of the call if it is non-zero.
4382+
// We also print it if it is zero but not equal to the program address space
4383+
// or if we can't find a valid Module* to make it possible to parse
4384+
// the resulting file even without a datalayout string.
43604385
unsigned CallAddrSpace = Operand->getType()->getPointerAddressSpace();
4361-
bool PrintAddrSpace = CallAddrSpace != 0;
4362-
if (!PrintAddrSpace) {
4363-
const Module *Mod = getModuleFromVal(I);
4364-
// We also print it if it is zero but not equal to the program address space
4365-
// or if we can't find a valid Module* to make it possible to parse
4366-
// the resulting file even without a datalayout string.
4367-
if (!Mod || Mod->getDataLayout().getProgramAddressSpace() != 0)
4368-
PrintAddrSpace = true;
4369-
}
4370-
if (PrintAddrSpace)
4371-
Out << " addrspace(" << CallAddrSpace << ")";
4386+
const Module *Mod = getModuleFromVal(I);
4387+
bool ForcePrintAddrSpace =
4388+
!Mod || Mod->getDataLayout().getProgramAddressSpace() != 0;
4389+
printAddressSpace(Mod, CallAddrSpace, Out, /*Prefix=*/" ", /*Suffix=*/"",
4390+
ForcePrintAddrSpace);
43724391
}
43734392

43744393
// This member is called for each Instruction in a function..
@@ -4735,9 +4754,8 @@ void AssemblyWriter::printInstruction(const Instruction &I) {
47354754
Out << ", align " << A->value();
47364755
}
47374756

4738-
unsigned AddrSpace = AI->getAddressSpace();
4739-
if (AddrSpace != 0)
4740-
Out << ", addrspace(" << AddrSpace << ')';
4757+
printAddressSpace(AI->getModule(), AI->getAddressSpace(), Out,
4758+
/*Prefix=*/", ");
47414759
} else if (isa<CastInst>(I)) {
47424760
if (Operand) {
47434761
Out << ' ';

0 commit comments

Comments
 (0)