Skip to content

Commit d4de4c3

Browse files
authored
[AArch64] Support optional constant offset for constraint "S" (#80255)
Modify the initial implementation (https://reviews.llvm.org/D46745) to support a constant offset so that the following code will compile: ``` int a[2][2]; void foo() { asm("// %0" :: "S"(&a[1][1])); } ``` We use the generic code path for "s". In GCC's aarch64 port, "S" is supported for PIC while "s" isn't, making "s" less useful. We implement "S" but not "s". Similar to #80201 for RISC-V.
1 parent 9cc2122 commit d4de4c3

File tree

4 files changed

+26
-16
lines changed

4 files changed

+26
-16
lines changed

clang/test/Sema/inline-asm-validate-aarch64.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,24 @@
1+
// RUN: %clang_cc1 -triple aarch64 -fsyntax-only -verify -DVERIFY %s
12
// RUN: %clang_cc1 -triple arm64-apple-darwin -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
23

34
typedef unsigned char uint8_t;
45

6+
#ifdef VERIFY
7+
void test_s(int i) {
8+
asm("" :: "s"(i)); // expected-error{{invalid input constraint 's' in asm}}
9+
10+
/// Codegen error
11+
asm("" :: "S"(i));
12+
asm("" :: "S"(test_s(i))); // expected-error{{invalid type 'void' in asm input for constraint 'S'}}
13+
}
14+
#else
515
uint8_t constraint_r(uint8_t *addr) {
616
uint8_t byte;
717

818
__asm__ volatile("ldrb %0, [%1]" : "=r" (byte) : "r" (addr) : "memory");
919
// CHECK: warning: value size does not match register size specified by the constraint and modifier
1020
// CHECK: note: use constraint modifier "w"
11-
// CHECK: fix-it:{{.*}}:{8:26-8:28}:"%w0"
21+
// CHECK: fix-it:{{.*}}:{[[#@LINE-3]]:26-[[#@LINE-3]]:28}:"%w0"
1222

1323
return byte;
1424
}
@@ -19,7 +29,7 @@ uint8_t constraint_r_symbolic(uint8_t *addr) {
1929
__asm__ volatile("ldrb %[s0], [%[s1]]" : [s0] "=r" (byte) : [s1] "r" (addr) : "memory");
2030
// CHECK: warning: value size does not match register size specified by the constraint and modifier
2131
// CHECK: note: use constraint modifier "w"
22-
// CHECK: fix-it:{{.*}}:{19:26-19:31}:"%w[s0]"
32+
// CHECK: fix-it:{{.*}}:{[[#@LINE-3]]:26-[[#@LINE-3]]:31}:"%w[s0]"
2333

2434
return byte;
2535
}
@@ -40,15 +50,16 @@ uint8_t constraint_r_symbolic_macro(uint8_t *addr) {
4050
// CHECK: warning: value size does not match register size specified by the constraint and modifier
4151
// CHECK: asm ("%w0 %w1 %2" : "+r" (one) : "r" (wide_two));
4252
// CHECK: note: use constraint modifier "w"
43-
// CHECK: fix-it:{{.*}}:{47:17-47:19}:"%w2"
4453

4554
void read_write_modifier0(int one, int two) {
4655
long wide_two = two;
4756
asm ("%w0 %w1 %2" : "+r" (one) : "r" (wide_two));
57+
// CHECK: fix-it:{{.*}}:{[[#@LINE-1]]:17-[[#@LINE-1]]:19}:"%w2"
4858
}
4959

5060
// CHECK-NOT: warning:
5161
void read_write_modifier1(int one, int two) {
5262
long wide_two = two;
5363
asm ("%w0 %1" : "+r" (one), "+r" (wide_two));
5464
}
65+
#endif

llvm/docs/LangRef.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5107,6 +5107,8 @@ AArch64:
51075107
offsets). (However, LLVM currently does this for the ``m`` constraint as
51085108
well.)
51095109
- ``r``: A 32 or 64-bit integer register (W* or X*).
5110+
- ``S``: A symbol or label reference with a constant offset. The generic ``s``
5111+
is not supported.
51105112
- ``Uci``: Like r, but restricted to registers 8 to 11 inclusive.
51115113
- ``Ucj``: Like r, but restricted to registers 12 to 15 inclusive.
51125114
- ``w``: A 32, 64, or 128-bit floating-point, SIMD or SVE vector register.

llvm/lib/Target/AArch64/AArch64ISelLowering.cpp

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10618,7 +10618,7 @@ AArch64TargetLowering::getConstraintType(StringRef Constraint) const {
1061810618
case 'Z':
1061910619
return C_Immediate;
1062010620
case 'z':
10621-
case 'S': // A symbolic address
10621+
case 'S': // A symbol or label reference with a constant offset
1062210622
return C_Other;
1062310623
}
1062410624
} else if (parsePredicateConstraint(Constraint))
@@ -10809,19 +10809,12 @@ void AArch64TargetLowering::LowerAsmOperandForConstraint(
1080910809
Result = DAG.getRegister(AArch64::WZR, MVT::i32);
1081010810
break;
1081110811
}
10812-
case 'S': {
10813-
// An absolute symbolic address or label reference.
10814-
if (const GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Op)) {
10815-
Result = DAG.getTargetGlobalAddress(GA->getGlobal(), SDLoc(Op),
10816-
GA->getValueType(0));
10817-
} else if (const BlockAddressSDNode *BA =
10818-
dyn_cast<BlockAddressSDNode>(Op)) {
10819-
Result =
10820-
DAG.getTargetBlockAddress(BA->getBlockAddress(), BA->getValueType(0));
10821-
} else
10822-
return;
10812+
case 'S':
10813+
// Use the generic code path for "s". In GCC's aarch64 port, "S" is
10814+
// supported for PIC while "s" isn't, making "s" less useful. We implement
10815+
// "S" but not "s".
10816+
TargetLowering::LowerAsmOperandForConstraint(Op, "s", Ops, DAG);
1082310817
break;
10824-
}
1082510818

1082610819
case 'I':
1082710820
case 'J':

llvm/test/CodeGen/AArch64/inlineasm-S-constraint.ll

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
;RUN: llc -mtriple=aarch64-none-linux-gnu -mattr=+neon < %s | FileCheck %s
22
@var = global i32 0
3+
@a = external global [2 x [2 x i32]], align 4
4+
35
define void @test_inline_constraint_S() {
46
; CHECK-LABEL: test_inline_constraint_S:
57
call void asm sideeffect "adrp x0, $0", "S"(ptr @var)
68
call void asm sideeffect "add x0, x0, :lo12:$0", "S"(ptr @var)
9+
call void asm sideeffect "// $0", "S"(ptr getelementptr inbounds ([2 x [2 x i32]], ptr @a, i64 0, i64 1, i64 1))
710
; CHECK: adrp x0, var
811
; CHECK: add x0, x0, :lo12:var
12+
; CHECK: // a+12
913
ret void
1014
}
1115
define i32 @test_inline_constraint_S_label(i1 %in) {

0 commit comments

Comments
 (0)