[RISCV] Support 'f' Inline Assembly Constraint
authorSam Elliott <selliott@lowrisc.org>
Wed, 31 Jul 2019 09:45:55 +0000 (09:45 +0000)
committerSam Elliott <selliott@lowrisc.org>
Wed, 31 Jul 2019 09:45:55 +0000 (09:45 +0000)
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
clang/test/CodeGen/riscv-inline-asm.c
llvm/lib/Target/RISCV/RISCVISelLowering.cpp
llvm/lib/Target/RISCV/RISCVISelLowering.h
llvm/test/CodeGen/RISCV/inline-asm-d-constraint-f.ll [new file with mode: 0644]
llvm/test/CodeGen/RISCV/inline-asm-f-constraint-f.ll [new file with mode: 0644]
llvm/test/CodeGen/RISCV/inline-asm-invalid.ll

index 788ae69..a634ba6 100644 (file)
@@ -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;
   }
 }
 
index 2d23b7e..f795273 100644 (file)
@@ -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));
+}
index 78bc93d..62c6ba8 100644 (file)
@@ -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<unsigned, const TargetRegisterClass *>
 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;
     }
index 17db03b..f28c475 100644 (file)
@@ -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<unsigned, const TargetRegisterClass *>
   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 (file)
index 0000000..251c063
--- /dev/null
@@ -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 (file)
index 0000000..e342789
--- /dev/null
@@ -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
+}
index ee9c043..06b0f2c 100644 (file)
@@ -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
+}