[clang] [llvm] [libc] [clang-tools-extra] [libcxx] [lldb] [flang] [RISCV] Support constraint "s" (PR #80201)

Fangrui Song via cfe-commits cfe-commits at lists.llvm.org
Thu Feb 1 09:33:49 PST 2024


https://github.com/MaskRay updated https://github.com/llvm/llvm-project/pull/80201

>From 7e9a74f18904f689d76bb2ea06ddf5f30d651b5e Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Wed, 31 Jan 2024 13:39:13 -0800
Subject: [PATCH] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20initia?=
 =?UTF-8?q?l=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Created using spr 1.3.4
---
 clang/lib/Basic/Targets/RISCV.cpp             |  3 +-
 clang/test/CodeGen/RISCV/riscv-inline-asm.c   | 16 +++-
 clang/test/Sema/inline-asm-validate-riscv.c   |  8 ++
 llvm/docs/LangRef.rst                         |  3 +-
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp   |  9 +--
 .../CodeGen/RISCV/inline-asm-S-constraint.ll  | 54 -------------
 .../RISCV/inline-asm-s-constraint-error.ll    | 14 ++++
 .../CodeGen/RISCV/inline-asm-s-constraint.ll  | 76 +++++++++++++++++++
 8 files changed, 116 insertions(+), 67 deletions(-)
 delete mode 100644 llvm/test/CodeGen/RISCV/inline-asm-S-constraint.ll
 create mode 100644 llvm/test/CodeGen/RISCV/inline-asm-s-constraint-error.ll
 create mode 100644 llvm/test/CodeGen/RISCV/inline-asm-s-constraint.ll

diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp
index c71b2e9eeb6c1..837a6e799e3a9 100644
--- a/clang/lib/Basic/Targets/RISCV.cpp
+++ b/clang/lib/Basic/Targets/RISCV.cpp
@@ -96,7 +96,8 @@ bool RISCVTargetInfo::validateAsmConstraint(
     // An address that is held in a general-purpose register.
     Info.setAllowsMemory();
     return true;
-  case 'S': // A symbolic address
+  case 's':
+  case 'S': // A symbol or label reference with a constant offset
     Info.setAllowsRegister();
     return true;
   case 'v':
diff --git a/clang/test/CodeGen/RISCV/riscv-inline-asm.c b/clang/test/CodeGen/RISCV/riscv-inline-asm.c
index 48de5ba3a27e3..3565705dea713 100644
--- a/clang/test/CodeGen/RISCV/riscv-inline-asm.c
+++ b/clang/test/CodeGen/RISCV/riscv-inline-asm.c
@@ -45,8 +45,16 @@ void test_A(int *p) {
   asm volatile("" :: "A"(*p));
 }
 
-void test_S(void) {
-// CHECK-LABEL: define{{.*}} void @test_S()
-// CHECK: call void asm sideeffect "", "S"(ptr nonnull @f)
-  asm volatile("" :: "S"(&f));
+extern int var, arr[2][2];
+struct Pair { int a, b; } pair;
+
+// CHECK-LABEL: test_s(
+// CHECK:         call void asm sideeffect "// $0 $1 $2", "s,s,s"(ptr nonnull @var, ptr nonnull getelementptr inbounds ([2 x [2 x i32]], ptr @arr, {{.*}}), ptr nonnull @test_s)
+// CHECK:         call void asm sideeffect "// $0", "s"(ptr nonnull getelementptr inbounds (%struct.Pair, ptr @pair, {{.*}}))
+// CHECK:         call void asm sideeffect "// $0 $1 $2", "S,S,S"(ptr nonnull @var, ptr nonnull getelementptr inbounds ([2 x [2 x i32]], ptr @arr, {{.*}}), ptr nonnull @test_s)
+void test_s(void) {
+  asm("// %0 %1 %2" :: "s"(&var), "s"(&arr[1][1]), "s"(test_s));
+  asm("// %0" :: "s"(&pair.b));
+
+  asm("// %0 %1 %2" :: "S"(&var), "S"(&arr[1][1]), "S"(test_s));
 }
diff --git a/clang/test/Sema/inline-asm-validate-riscv.c b/clang/test/Sema/inline-asm-validate-riscv.c
index 43a5378bc3f25..806ef60dacbec 100644
--- a/clang/test/Sema/inline-asm-validate-riscv.c
+++ b/clang/test/Sema/inline-asm-validate-riscv.c
@@ -22,6 +22,14 @@ void K(int k) {
   asm volatile ("" :: "K"(AboveMax)); // expected-error{{value '32' out of range for constraint 'K'}}
 }
 
+void test_s(int i) {
+  asm("" :: "s"(test_s(0))); // expected-error{{invalid type 'void' in asm input for constraint 's'}}
+  /// Codegen error
+  asm("" :: "s"(i));
+
+  asm("" :: "S"(test_s(0))); // expected-error{{invalid type 'void' in asm input for constraint 'S'}}
+}
+
 void test_clobber_conflict(void) {
   register long x10 asm("x10");
   asm volatile("" :: "r"(x10) : "x10"); // expected-error {{conflicts with asm clobber list}}
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 7a7ddc59ba985..3648ea2611dd4 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -5075,7 +5075,7 @@ Some constraint codes are typically supported by all targets:
 - ``i``: An integer constant (of target-specific width). Allows either a simple
   immediate, or a relocatable value.
 - ``n``: An integer constant -- *not* including relocatable values.
-- ``s``: An integer constant, but allowing *only* relocatable values.
+- ``s``: A symbol or label reference with a constant offset.
 - ``X``: Allows an operand of any kind, no constraint whatsoever. Typically
   useful to pass a label for an asm branch or call.
 
@@ -5283,6 +5283,7 @@ RISC-V:
 - ``f``: A 32- or 64-bit floating-point register (requires F or D extension).
 - ``r``: A 32- or 64-bit general-purpose register (depending on the platform
   ``XLEN``).
+- ``S``: Alias for ``s``.
 - ``vr``: A vector register. (requires V extension).
 - ``vm``: A vector register for masking operand. (requires V extension).
 
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index b8994e7b7bdb2..fcddf7234e5fa 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -19195,6 +19195,7 @@ RISCVTargetLowering::getConstraintType(StringRef Constraint) const {
       return C_Immediate;
     case 'A':
       return C_Memory;
+    case 's':
     case 'S': // A symbolic address
       return C_Other;
     }
@@ -19456,13 +19457,7 @@ void RISCVTargetLowering::LowerAsmOperandForConstraint(
       }
       return;
     case 'S':
-      if (const auto *GA = dyn_cast<GlobalAddressSDNode>(Op)) {
-        Ops.push_back(DAG.getTargetGlobalAddress(GA->getGlobal(), SDLoc(Op),
-                                                 GA->getValueType(0)));
-      } else if (const auto *BA = dyn_cast<BlockAddressSDNode>(Op)) {
-        Ops.push_back(DAG.getTargetBlockAddress(BA->getBlockAddress(),
-                                                BA->getValueType(0)));
-      }
+      TargetLowering::LowerAsmOperandForConstraint(Op, "s", Ops, DAG);
       return;
     default:
       break;
diff --git a/llvm/test/CodeGen/RISCV/inline-asm-S-constraint.ll b/llvm/test/CodeGen/RISCV/inline-asm-S-constraint.ll
deleted file mode 100644
index 11add36da27b6..0000000000000
--- a/llvm/test/CodeGen/RISCV/inline-asm-S-constraint.ll
+++ /dev/null
@@ -1,54 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc -mtriple=riscv32 < %s | FileCheck %s --check-prefix=RV32
-; RUN: llc -mtriple=riscv64 < %s | FileCheck %s --check-prefix=RV64
-
- at var = external dso_local global i32, align 4
-
-define dso_local ptr @constraint_S() {
-; RV32-LABEL: constraint_S:
-; RV32:       # %bb.0:
-; RV32-NEXT:    #APP
-; RV32-NEXT:    lui a0, %hi(var)
-; RV32-NEXT:    addi a0, a0, %lo(var)
-; RV32-NEXT:    #NO_APP
-; RV32-NEXT:    ret
-;
-; RV64-LABEL: constraint_S:
-; RV64:       # %bb.0:
-; RV64-NEXT:    #APP
-; RV64-NEXT:    lui a0, %hi(var)
-; RV64-NEXT:    addi a0, a0, %lo(var)
-; RV64-NEXT:    #NO_APP
-; RV64-NEXT:    ret
-  %ret = tail call ptr asm "lui $0, %hi($1)\0Aaddi $0, $0, %lo($1)", "=r,S"(ptr nonnull @var)
-  ret ptr %ret
-}
-
-; Function Attrs: nofree nosync nounwind readnone
-define dso_local ptr @constraint_S_label() {
-; RV32-LABEL: constraint_S_label:
-; RV32:       # %bb.0: # %entry
-; RV32-NEXT:  .Ltmp0: # Block address taken
-; RV32-NEXT:  # %bb.1: # %L1
-; RV32-NEXT:    #APP
-; RV32-NEXT:    lui a0, %hi(.Ltmp0)
-; RV32-NEXT:    addi a0, a0, %lo(.Ltmp0)
-; RV32-NEXT:    #NO_APP
-; RV32-NEXT:    ret
-;
-; RV64-LABEL: constraint_S_label:
-; RV64:       # %bb.0: # %entry
-; RV64-NEXT:  .Ltmp0: # Block address taken
-; RV64-NEXT:  # %bb.1: # %L1
-; RV64-NEXT:    #APP
-; RV64-NEXT:    lui a0, %hi(.Ltmp0)
-; RV64-NEXT:    addi a0, a0, %lo(.Ltmp0)
-; RV64-NEXT:    #NO_APP
-; RV64-NEXT:    ret
-entry:
-  br label %L1
-
-L1:
-  %ret = tail call ptr asm "lui $0, %hi($1)\0Aaddi $0, $0, %lo($1)", "=r,S"(ptr blockaddress(@constraint_S_label, %L1))
-  ret ptr %ret
-}
diff --git a/llvm/test/CodeGen/RISCV/inline-asm-s-constraint-error.ll b/llvm/test/CodeGen/RISCV/inline-asm-s-constraint-error.ll
new file mode 100644
index 0000000000000..f836dd6366229
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/inline-asm-s-constraint-error.ll
@@ -0,0 +1,14 @@
+; RUN: not llc -mtriple=riscv64 < %s 2>&1 | FileCheck %s
+
+ at a = external global [4 x i32], align 16
+
+; CHECK-COUNT-2: error: invalid operand for inline asm constraint 's'
+; CHECK-NOT:     error:
+define void @test(i64 %i) {
+entry:
+  %x = alloca i32, align 4
+  %ai = getelementptr inbounds [4 x i32], ptr @a, i64 0, i64 %i
+  call void asm sideeffect "", "s,~{dirflag},~{fpsr},~{flags}"(ptr %x)
+  call void asm sideeffect "", "s,~{dirflag},~{fpsr},~{flags}"(ptr %ai)
+  ret void
+}
diff --git a/llvm/test/CodeGen/RISCV/inline-asm-s-constraint.ll b/llvm/test/CodeGen/RISCV/inline-asm-s-constraint.ll
new file mode 100644
index 0000000000000..4a6c47f88014c
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/inline-asm-s-constraint.ll
@@ -0,0 +1,76 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -relocation-model=static < %s | FileCheck %s --check-prefix=RV32
+; RUN: llc -mtriple=riscv64 -relocation-model=pic < %s | FileCheck %s --check-prefix=RV64
+
+ at var = external dso_local global i32, align 4
+ at a = external global [2 x [2 x i32]], align 4
+
+define dso_local void @test() {
+; CHECK-LABEL: test:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    # var a+12 test
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    ret{{[l|q]}}
+; RV32-LABEL: test:
+; RV32:       # %bb.0: # %entry
+; RV32-NEXT:    #APP
+; RV32-NEXT:    # var a+12 test
+; RV32-NEXT:    #NO_APP
+; RV32-NEXT:    #APP
+; RV32-NEXT:    # var a+12 test
+; RV32-NEXT:    #NO_APP
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test:
+; RV64:       # %bb.0: # %entry
+; RV64-NEXT:    #APP
+; RV64-NEXT:    # var a+12 .Ltest$local
+; RV64-NEXT:    #NO_APP
+; RV64-NEXT:    #APP
+; RV64-NEXT:    # var a+12 .Ltest$local
+; RV64-NEXT:    #NO_APP
+; RV64-NEXT:    ret
+entry:
+  call void asm sideeffect "// $0 $1 $2", "s,s,s,~{dirflag},~{fpsr},~{flags}"(ptr @var, ptr getelementptr inbounds ([2 x [2 x i32]], ptr @a, i64 0, i64 1, i64 1), ptr @test)
+
+  ;; Implement "S" as an alias for "s".
+  call void asm sideeffect "// $0 $1 $2", "S,S,S,~{dirflag},~{fpsr},~{flags}"(ptr @var, ptr getelementptr inbounds ([2 x [2 x i32]], ptr @a, i64 0, i64 1, i64 1), ptr @test)
+  ret void
+}
+
+; Function Attrs: nofree nosync nounwind readnone
+define dso_local ptr @test_label() {
+; RV32-LABEL: test_label:
+; RV32:       # %bb.0: # %entry
+; RV32-NEXT:  .Ltmp0: # Block address taken
+; RV32-NEXT:  # %bb.1: # %L1
+; RV32-NEXT:    #APP
+; RV32-NEXT:    # .Ltmp0
+; RV32-NEXT:    #NO_APP
+; RV32-NEXT:    #APP
+; RV32-NEXT:    lui a0, %hi(.Ltmp0)
+; RV32-NEXT:    addi a0, a0, %lo(.Ltmp0)
+; RV32-NEXT:    #NO_APP
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_label:
+; RV64:       # %bb.0: # %entry
+; RV64-NEXT:  .Ltmp0: # Block address taken
+; RV64-NEXT:  # %bb.1: # %L1
+; RV64-NEXT:    #APP
+; RV64-NEXT:    # .Ltmp0
+; RV64-NEXT:    #NO_APP
+; RV64-NEXT:    #APP
+; RV64-NEXT:    lui a0, %hi(.Ltmp0)
+; RV64-NEXT:    addi a0, a0, %lo(.Ltmp0)
+; RV64-NEXT:    #NO_APP
+; RV64-NEXT:    ret
+entry:
+  br label %L1
+
+L1:
+  call void asm sideeffect "// $0", "s,~{dirflag},~{fpsr},~{flags}"(ptr blockaddress(@test_label, %L1))
+  %ret = tail call ptr asm "lui $0, %hi($1)\0Aaddi $0, $0, %lo($1)", "=r,S"(ptr blockaddress(@test_label, %L1))
+  ret ptr %ret
+}



More information about the cfe-commits mailing list