diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp --- a/clang/lib/Basic/Targets/RISCV.cpp +++ b/clang/lib/Basic/Targets/RISCV.cpp @@ -87,6 +87,9 @@ // An address that is held in a general-purpose register. Info.setAllowsMemory(); return true; + case 'S': // A symbolic address + Info.setAllowsRegister(); + return true; case 'v': // A vector register. if (Name[1] == 'r' || Name[1] == 'm') { diff --git a/clang/test/CodeGen/RISCV/riscv-inline-asm.c b/clang/test/CodeGen/RISCV/riscv-inline-asm.c --- a/clang/test/CodeGen/RISCV/riscv-inline-asm.c +++ b/clang/test/CodeGen/RISCV/riscv-inline-asm.c @@ -44,3 +44,9 @@ // CHECK: call void asm sideeffect "", "*A"(i32* %p) asm volatile("" :: "A"(*p)); } + +void test_S() { +// CHECK-LABEL: define{{.*}} void @test_S() +// CHECK: call void asm sideeffect "", "S"(float* nonnull @f) + asm volatile("" :: "S"(&f)); +} diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -8240,6 +8240,8 @@ return C_Immediate; case 'A': return C_Memory; + case 'S': // A symbolic address + return C_Other; } } return TargetLowering::getConstraintType(Constraint); @@ -8469,6 +8471,16 @@ DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getXLenVT())); } return; + case 'S': + if (const GlobalAddressSDNode *GA = dyn_cast(Op)) { + Ops.push_back(DAG.getTargetGlobalAddress(GA->getGlobal(), SDLoc(Op), + GA->getValueType(0))); + } else if (const BlockAddressSDNode *BA = + dyn_cast(Op)) { + Ops.push_back(DAG.getTargetBlockAddress(BA->getBlockAddress(), + BA->getValueType(0))); + } + 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 new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/inline-asm-S-constraint.ll @@ -0,0 +1,54 @@ +; 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 + +@var = external dso_local global i32, align 4 + +define dso_local i8* @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 i8* asm "lui $0, %hi($1)\0Aaddi $0, $0, %lo($1)", "=r,S"(i32* nonnull @var) + ret i8* %ret +} + +; Function Attrs: nofree nosync nounwind readnone +define dso_local i8* @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 i8* asm "lui $0, %hi($1)\0Aaddi $0, $0, %lo($1)", "=r,S"(i8* blockaddress(@constraint_S_label, %L1)) + ret i8* %ret +}