Skip to content

Commit

Permalink
[LLParser] Support symbolic address space numbers
Browse files Browse the repository at this point in the history
This allows the LLParser to also accept "A", "G", and "P" in `addrspace`
usages. "A" will be replaced by the alloca address space defined in the
globals, "G" by the default globals address space and "P" by the program
address space. This makes it easier to write tests that use different
address space and only only vary the RUN: lines. Currently, the only
alternative is to pre-process the sources with a tool such as `sed`

Importantly, these new string values are only accepted in .ll files and
not stored in the bitcode format, so it does not round-trip via llvm-as
and llvm-dis (see newly added test).

Reviewed By: nikic

Differential Revision: https://reviews.llvm.org/D138789
  • Loading branch information
arichardson committed Dec 8, 2022
1 parent 5131f44 commit f850035
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 1 deletion.
5 changes: 5 additions & 0 deletions llvm/docs/LangRef.rst
Expand Up @@ -3590,6 +3590,11 @@ commonly used to reference objects in memory.
Pointer types may have an optional address space attribute defining
the numbered address space where the pointed-to object resides. For
example, ``ptr addrspace(5)`` is a pointer to address space 5.
In addition to integer constants, ``addrspace`` can also reference one of the
address spaces defined in the :ref:`datalayout string<langref_datalayout>`.
``addrspace("A")`` will use the alloca address space, ``addrspace("G")``
the default globals address space and ``addrspace("P")`` the program address
space.

The default address space is number zero.

Expand Down
23 changes: 22 additions & 1 deletion llvm/lib/AsmParser/LLParser.cpp
Expand Up @@ -1787,8 +1787,29 @@ bool LLParser::parseOptionalAddrSpace(unsigned &AddrSpace, unsigned DefaultAS) {
AddrSpace = DefaultAS;
if (!EatIfPresent(lltok::kw_addrspace))
return false;

auto ParseAddrspaceValue = [&](unsigned &AddrSpace) -> bool {
if (Lex.getKind() == lltok::StringConstant) {
auto AddrSpaceStr = Lex.getStrVal();
if (AddrSpaceStr == "A") {
AddrSpace = M->getDataLayout().getAllocaAddrSpace();
} else if (AddrSpaceStr == "G") {
AddrSpace = M->getDataLayout().getDefaultGlobalsAddressSpace();
} else if (AddrSpaceStr == "P") {
AddrSpace = M->getDataLayout().getProgramAddressSpace();
} else {
return tokError("invalid symbolic addrspace '" + AddrSpaceStr + "'");
}
Lex.Lex();
return false;
} else if (Lex.getKind() != lltok::APSInt) {
return tokError("expected integer or string constant");
}
return parseUInt32(AddrSpace);
};

return parseToken(lltok::lparen, "expected '(' in address space") ||
parseUInt32(AddrSpace) ||
ParseAddrspaceValue(AddrSpace) ||
parseToken(lltok::rparen, "expected ')' in address space");
}

Expand Down
73 changes: 73 additions & 0 deletions llvm/test/Assembler/symbolic-addrspace.ll
@@ -0,0 +1,73 @@
;; Check that we can parse symbolic addres space constants "A", "G", "P".
;; NB: These do not round-trip via llvm-as, they are purely for initial parsing
;; and will be converted to a numerical constant that does not depend on the
;; datalayout by the .ll parser.
; RUN: split-file %s %t --leading-lines
; RUN: llvm-as < %t/valid.ll | llvm-dis | FileCheck %s
; RUN: llvm-as < %t/alloca-in-other-as.ll | llvm-dis | FileCheck %s --check-prefix ALLOCA-IN-GLOBALS
; RUN: not llvm-as < %t/bad-not-string.ll 2>&1 | FileCheck %s --check-prefix=ERR-NOT-STR
; RUN: not llvm-as < %t/bad-unknown-char.ll 2>&1 | FileCheck %s --check-prefix=ERR-BAD-CHAR
; RUN: not llvm-as < %t/bad-multiple-valid-chars.ll 2>&1 | FileCheck %s --check-prefix=ERR-MULTIPLE-CHARS
; RUN: not llvm-as < %t/bad-using-at-symbol.ll 2>&1 | FileCheck %s --check-prefix=ERR-AT-SYMBOL
; RUN: not llvm-as < %t/bad-number-in-quotes.ll 2>&1 | FileCheck %s --check-prefix=ERR-NUMBER-IN-QUOTES

;--- valid.ll
target datalayout = "A1-G2-P3"
; CHECK: target datalayout = "A1-G2-P3"

; CHECK: @str = private addrspace(2) constant [4 x i8] c"str\00"
@str = private addrspace("G") constant [4 x i8] c"str\00"

define void @foo() {
; CHECK: %alloca = alloca i32, align 4, addrspace(1)
%alloca = alloca i32, addrspace("A")
ret void
}

; CHECK: define void @bar() addrspace(3) {
define void @bar() addrspace("P") {
; CHECK: call addrspace(3) void @foo()
call addrspace("P") void @foo()
ret void
}

;--- alloca-in-other-as.ll
target datalayout = "A1-G2-P3"
; ALLOCA-IN-GLOBALS: target datalayout = "A1-G2-P3"

define void @foo() {
; ALLOCA-IN-GLOBALS: %alloca = alloca i32, align 4, addrspace(2){{$}}
; ALLOCA-IN-GLOBALS: %alloca2 = alloca i32, align 4, addrspace(1){{$}}
; ALLOCA-IN-GLOBALS: %alloca3 = alloca i32, align 4{{$}}
; ALLOCA-IN-GLOBALS: %alloca4 = alloca i32, align 4, addrspace(3){{$}}
%alloca = alloca i32, addrspace("G")
%alloca2 = alloca i32, addrspace("A")
%alloca3 = alloca i32
%alloca4 = alloca i32, addrspace("P")
ret void
}

;--- bad-not-string.ll
target datalayout = "G2"
@str = private addrspace(D) constant [4 x i8] c"str\00"
; ERR-NOT-STR: [[#@LINE-1]]:26: error: expected integer or string constant

;--- bad-unknown-char.ll
target datalayout = "G2"
@str = private addrspace("D") constant [4 x i8] c"str\00"
; ERR-BAD-CHAR: [[#@LINE-1]]:26: error: invalid symbolic addrspace 'D'

;--- bad-multiple-valid-chars.ll
target datalayout = "A1-G2"
@str = private addrspace("AG") constant [4 x i8] c"str\00"
; ERR-MULTIPLE-CHARS: [[#@LINE-1]]:26: error: invalid symbolic addrspace 'AG'

;--- bad-using-at-symbol.ll
target datalayout = "A1-G2"
@str = private addrspace(@A) constant [4 x i8] c"str\00"
; ERR-AT-SYMBOL: [[#@LINE-1]]:26: error: expected integer or string constant

;--- bad-number-in-quotes.ll
target datalayout = "A1-G2"
@str = private addrspace("10") constant [4 x i8] c"str\00"
; ERR-NUMBER-IN-QUOTES: [[#@LINE-1]]:26: error: invalid symbolic addrspace '10'

0 comments on commit f850035

Please sign in to comment.