diff --git a/clang/lib/Basic/Targets/LoongArch.cpp b/clang/lib/Basic/Targets/LoongArch.cpp index ca742797d7a3b..f4bcb54bd470d 100644 --- a/clang/lib/Basic/Targets/LoongArch.cpp +++ b/clang/lib/Basic/Targets/LoongArch.cpp @@ -139,6 +139,11 @@ bool LoongArchTargetInfo::validateAsmConstraint( // A signed 16-bit constant. Info.setRequiresImmediate(-32768, 32767); return true; + case 'q': + // A general-purpose register except for $r0 and $r1 (for the csrxchg + // instruction) + Info.setAllowsRegister(); + return true; case 'I': // A signed 12-bit constant (for arithmetic instructions). Info.setRequiresImmediate(-2048, 2047); diff --git a/clang/test/CodeGen/LoongArch/inline-asm-constraints.c b/clang/test/CodeGen/LoongArch/inline-asm-constraints.c index b19494284bd99..ded21206d63bf 100644 --- a/clang/test/CodeGen/LoongArch/inline-asm-constraints.c +++ b/clang/test/CodeGen/LoongArch/inline-asm-constraints.c @@ -35,6 +35,12 @@ void test_m(int *p) { asm volatile("" :: "m"(*(p+4))); } +void test_q(void) { +// CHECK-LABEL: define{{.*}} void @test_q() +// CHECK: call void asm sideeffect "", "q"(i32 0) + asm volatile ("" :: "q"(0)); +} + void test_I(void) { // CHECK-LABEL: define{{.*}} void @test_I() // CHECK: call void asm sideeffect "", "I"(i32 2047) diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp index 9774683e16291..50ec0b2e3ca78 100644 --- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp @@ -7276,6 +7276,8 @@ LoongArchTargetLowering::getConstraintType(StringRef Constraint) const { // 'm': A memory operand whose address is formed by a base register and // offset that is suitable for use in instructions with the same // addressing mode as st.w and ld.w. + // 'q': A general-purpose register except for $r0 and $r1 (for the csrxchg + // instruction) // 'I': A signed 12-bit constant (for arithmetic instructions). // 'J': Integer zero. // 'K': An unsigned 12-bit constant (for logic instructions). @@ -7289,6 +7291,7 @@ LoongArchTargetLowering::getConstraintType(StringRef Constraint) const { default: break; case 'f': + case 'q': return C_RegisterClass; case 'l': case 'I': @@ -7328,6 +7331,8 @@ LoongArchTargetLowering::getRegForInlineAsmConstraint( if (VT.isVector()) break; return std::make_pair(0U, &LoongArch::GPRRegClass); + case 'q': + return std::make_pair(0U, &LoongArch::GPRNoR0R1RegClass); case 'f': if (Subtarget.hasBasicF() && VT == MVT::f32) return std::make_pair(0U, &LoongArch::FPR32RegClass); diff --git a/llvm/test/CodeGen/LoongArch/inline-asm-constraint-q.ll b/llvm/test/CodeGen/LoongArch/inline-asm-constraint-q.ll new file mode 100644 index 0000000000000..e16bd1d8aacf3 --- /dev/null +++ b/llvm/test/CodeGen/LoongArch/inline-asm-constraint-q.ll @@ -0,0 +1,21 @@ +; RUN: llc --mtriple=loongarch32 --mattr=+f --verify-machineinstrs < %s | FileCheck %s +; RUN: llc --mtriple=loongarch64 --mattr=+f --verify-machineinstrs < %s | FileCheck %s + +;; Check that the "q" operand is not R0. +define i32 @constraint_q_not_r0() { +; CHECK-NOT: csrxchg ${{[a-z]*}}, $r0, 0 +; CHECK-NOT: csrxchg ${{[a-z]*}}, $zero, 0 +entry: + %2 = tail call i32 asm "csrxchg $0, $1, 0", "=r,q,0"(i32 0, i32 0) + ret i32 %2 +} + +;; Check that the "q" operand is not R1. +define i32 @constraint_q_not_r1(i32 %0) { +; CHECK-NOT: csrxchg ${{[a-z]*}}, $r1, 0 +; CHECK-NOT: csrxchg ${{[a-z]*}}, $ra, 0 +entry: + %2 = tail call i32 asm "", "={$r1},{$r1}"(i32 0) + %3 = tail call i32 asm "csrxchg $0, $1, 0", "=r,q,0"(i32 %2, i32 %0) + ret i32 %3 +}