From 9e6b2e1605825f852d59034e053a22b712f8fcb9 Mon Sep 17 00:00:00 2001 From: Sam Elliott Date: Wed, 31 Jul 2019 09:45:55 +0000 Subject: [PATCH] [RISCV] Support 'f' Inline Assembly Constraint Summary: This adds the 'f' inline assembly constraint, as supported by GCC. An 'f'-constrained operand is passed in a floating point register. Exactly which kind of floating-point register (32-bit or 64-bit) is decided based on the operand type and the available standard extensions (-f and -d, respectively). This patch adds support in both the clang frontend, and LLVM itself. Reviewers: asb, lewis-revill Reviewed By: asb Subscribers: hiraditya, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, kito-cheng, shiva0217, jrtc27, MaskRay, zzheng, edward-jones, rogfer01, MartinMosbeck, brucehoult, the_o, rkruppe, PkmX, jocewei, psnobl, benna, Jim, s.egerton, cfe-commits, llvm-commits Tags: #clang, #llvm Differential Revision: https://reviews.llvm.org/D65500 llvm-svn: 367403 --- clang/lib/Basic/Targets/RISCV.cpp | 4 +++ clang/test/CodeGen/riscv-inline-asm.c | 12 +++++++ llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 21 ++++++++++++ llvm/lib/Target/RISCV/RISCVISelLowering.h | 1 + .../CodeGen/RISCV/inline-asm-d-constraint-f.ll | 40 ++++++++++++++++++++++ .../CodeGen/RISCV/inline-asm-f-constraint-f.ll | 34 ++++++++++++++++++ llvm/test/CodeGen/RISCV/inline-asm-invalid.ll | 8 +++++ 7 files changed, 120 insertions(+) create mode 100644 llvm/test/CodeGen/RISCV/inline-asm-d-constraint-f.ll create mode 100644 llvm/test/CodeGen/RISCV/inline-asm-f-constraint-f.ll diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp index 788ae69..a634ba6 100644 --- a/clang/lib/Basic/Targets/RISCV.cpp +++ b/clang/lib/Basic/Targets/RISCV.cpp @@ -71,6 +71,10 @@ bool RISCVTargetInfo::validateAsmConstraint( // A 5-bit unsigned immediate for CSR access instructions. Info.setRequiresImmediate(0, 31); return true; + case 'f': + // A floating-point register. + Info.setAllowsRegister(); + return true; } } diff --git a/clang/test/CodeGen/riscv-inline-asm.c b/clang/test/CodeGen/riscv-inline-asm.c index 2d23b7e..f795273 100644 --- a/clang/test/CodeGen/riscv-inline-asm.c +++ b/clang/test/CodeGen/riscv-inline-asm.c @@ -26,3 +26,15 @@ void test_K() { // CHECK: call void asm sideeffect "", "K"(i32 0) asm volatile ("" :: "K"(0)); } + +float f; +double d; +void test_f() { +// CHECK-LABEL: define void @test_f() +// CHECK: [[FLT_ARG:%[a-zA-Z_0-9]+]] = load float, float* @f +// CHECK: call void asm sideeffect "", "f"(float [[FLT_ARG]]) + asm volatile ("" :: "f"(f)); +// CHECK: [[FLT_ARG:%[a-zA-Z_0-9]+]] = load double, double* @d +// CHECK: call void asm sideeffect "", "f"(double [[FLT_ARG]]) + asm volatile ("" :: "f"(d)); +} diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index 78bc93d..62c6ba8 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -2397,6 +2397,21 @@ const char *RISCVTargetLowering::getTargetNodeName(unsigned Opcode) const { return nullptr; } +/// getConstraintType - Given a constraint letter, return the type of +/// constraint it is for this target. +RISCVTargetLowering::ConstraintType +RISCVTargetLowering::getConstraintType(StringRef Constraint) const { + if (Constraint.size() == 1) { + switch (Constraint[0]) { + default: + break; + case 'f': + return C_RegisterClass; + } + } + return TargetLowering::getConstraintType(Constraint); +} + std::pair RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, StringRef Constraint, @@ -2407,6 +2422,12 @@ RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, switch (Constraint[0]) { case 'r': return std::make_pair(0U, &RISCV::GPRRegClass); + case 'f': + if (Subtarget.hasStdExtF() && VT == MVT::f32) + return std::make_pair(0U, &RISCV::FPR32RegClass); + if (Subtarget.hasStdExtD() && VT == MVT::f64) + return std::make_pair(0U, &RISCV::FPR64RegClass); + break; default: break; } diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h index 17db03b..f28c475 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.h +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h @@ -92,6 +92,7 @@ public: // This method returns the name of a target specific DAG node. const char *getTargetNodeName(unsigned Opcode) const override; + ConstraintType getConstraintType(StringRef Constraint) const override; std::pair getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const override; diff --git a/llvm/test/CodeGen/RISCV/inline-asm-d-constraint-f.ll b/llvm/test/CodeGen/RISCV/inline-asm-d-constraint-f.ll new file mode 100644 index 0000000..251c063 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/inline-asm-d-constraint-f.ll @@ -0,0 +1,40 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV32F %s +; RUN: llc -mtriple=riscv64 -mattr=+d -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV64F %s + +@gd = external global double + +define double @constraint_f_double(double %a) nounwind { +; RV32F-LABEL: constraint_f_double: +; RV32F: # %bb.0: +; RV32F-NEXT: addi sp, sp, -16 +; RV32F-NEXT: sw a0, 8(sp) +; RV32F-NEXT: sw a1, 12(sp) +; RV32F-NEXT: fld ft0, 8(sp) +; RV32F-NEXT: lui a0, %hi(gd) +; RV32F-NEXT: fld ft1, %lo(gd)(a0) +; RV32F-NEXT: #APP +; RV32F-NEXT: fadd.d ft0, ft0, ft1 +; RV32F-NEXT: #NO_APP +; RV32F-NEXT: fsd ft0, 8(sp) +; RV32F-NEXT: lw a0, 8(sp) +; RV32F-NEXT: lw a1, 12(sp) +; RV32F-NEXT: addi sp, sp, 16 +; RV32F-NEXT: ret +; +; RV64F-LABEL: constraint_f_double: +; RV64F: # %bb.0: +; RV64F-NEXT: fmv.d.x ft0, a0 +; RV64F-NEXT: lui a0, %hi(gd) +; RV64F-NEXT: fld ft1, %lo(gd)(a0) +; RV64F-NEXT: #APP +; RV64F-NEXT: fadd.d ft0, ft0, ft1 +; RV64F-NEXT: #NO_APP +; RV64F-NEXT: fmv.x.d a0, ft0 +; RV64F-NEXT: ret + %1 = load double, double* @gd + %2 = tail call double asm "fadd.d $0, $1, $2", "=f,f,f"(double %a, double %1) + ret double %2 +} diff --git a/llvm/test/CodeGen/RISCV/inline-asm-f-constraint-f.ll b/llvm/test/CodeGen/RISCV/inline-asm-f-constraint-f.ll new file mode 100644 index 0000000..e342789 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/inline-asm-f-constraint-f.ll @@ -0,0 +1,34 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -mattr=+f -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV32F %s +; RUN: llc -mtriple=riscv64 -mattr=+f -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV64F %s + +@gf = external global float + +define float @constraint_f_float(float %a) nounwind { +; RV32F-LABEL: constraint_f_float: +; RV32F: # %bb.0: +; RV32F-NEXT: fmv.w.x ft0, a0 +; RV32F-NEXT: lui a0, %hi(gf) +; RV32F-NEXT: flw ft1, %lo(gf)(a0) +; RV32F-NEXT: #APP +; RV32F-NEXT: fadd.s ft0, ft0, ft1 +; RV32F-NEXT: #NO_APP +; RV32F-NEXT: fmv.x.w a0, ft0 +; RV32F-NEXT: ret +; +; RV64F-LABEL: constraint_f_float: +; RV64F: # %bb.0: +; RV64F-NEXT: fmv.w.x ft0, a0 +; RV64F-NEXT: lui a0, %hi(gf) +; RV64F-NEXT: flw ft1, %lo(gf)(a0) +; RV64F-NEXT: #APP +; RV64F-NEXT: fadd.s ft0, ft0, ft1 +; RV64F-NEXT: #NO_APP +; RV64F-NEXT: fmv.x.w a0, ft0 +; RV64F-NEXT: ret + %1 = load float, float* @gf + %2 = tail call float asm "fadd.s $0, $1, $2", "=f,f,f"(float %a, float %1) + ret float %2 +} diff --git a/llvm/test/CodeGen/RISCV/inline-asm-invalid.ll b/llvm/test/CodeGen/RISCV/inline-asm-invalid.ll index ee9c043..06b0f2c 100644 --- a/llvm/test/CodeGen/RISCV/inline-asm-invalid.ll +++ b/llvm/test/CodeGen/RISCV/inline-asm-invalid.ll @@ -22,3 +22,11 @@ define void @constraint_K() { tail call void asm sideeffect "csrwi mstatus, $0", "K"(i32 -1) ret void } + +define void @constraint_f() nounwind { +; CHECK: error: couldn't allocate input reg for constraint 'f' + tail call void asm "fadd.s fa0, fa0, $0", "f"(float 0.0) +; CHECK: error: couldn't allocate input reg for constraint 'f' + tail call void asm "fadd.d fa0, fa0, $0", "f"(double 0.0) + ret void +} -- 2.7.4