forked from OSchip/llvm-project
[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
This commit is contained in:
parent
5ea07f7c07
commit
9e6b2e1605
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue