[RISCV] Lower inline asm constraints I, J & K for RISC-V

This validates and lowers arguments to inline asm nodes which have the
constraints I, J & K, with the following semantics (equivalent to GCC):

I: Any 12-bit signed immediate.
J: Immediate integer zero only.
K: Any 5-bit unsigned immediate.

Differential Revision: https://reviews.llvm.org/D54093

llvm-svn: 363054
This commit is contained in:
Lewis Revill 2019-06-11 12:42:13 +00:00
parent f63feaf3c2
commit 28a5cadb3a
3 changed files with 110 additions and 0 deletions

View File

@ -2151,6 +2151,44 @@ RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
}
void RISCVTargetLowering::LowerAsmOperandForConstraint(
SDValue Op, std::string &Constraint, std::vector<SDValue> &Ops,
SelectionDAG &DAG) const {
// Currently only support length 1 constraints.
if (Constraint.length() == 1) {
switch (Constraint[0]) {
case 'I':
// Validate & create a 12-bit signed immediate operand.
if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
uint64_t CVal = C->getSExtValue();
if (isInt<12>(CVal))
Ops.push_back(
DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getXLenVT()));
}
return;
case 'J':
// Validate & create an integer zero operand.
if (auto *C = dyn_cast<ConstantSDNode>(Op))
if (C->getZExtValue() == 0)
Ops.push_back(
DAG.getTargetConstant(0, SDLoc(Op), Subtarget.getXLenVT()));
return;
case 'K':
// Validate & create a 5-bit unsigned immediate operand.
if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
uint64_t CVal = C->getZExtValue();
if (isUInt<5>(CVal))
Ops.push_back(
DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getXLenVT()));
}
return;
default:
break;
}
}
TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG);
}
Instruction *RISCVTargetLowering::emitLeadingFence(IRBuilder<> &Builder,
Instruction *Inst,
AtomicOrdering Ord) const {

View File

@ -93,6 +93,10 @@ public:
getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
StringRef Constraint, MVT VT) const override;
void LowerAsmOperandForConstraint(SDValue Op, std::string &Constraint,
std::vector<SDValue> &Ops,
SelectionDAG &DAG) const override;
MachineBasicBlock *
EmitInstrWithCustomInserter(MachineInstr &MI,
MachineBasicBlock *BB) const override;

View File

@ -82,4 +82,72 @@ define i32 @constraint_m2(i32* %a) nounwind {
ret i32 %1
}
define void @constraint_I() {
; RV32I-LABEL: constraint_I:
; RV32I: # %bb.0:
; RV32I-NEXT: #APP
; RV32I-NEXT: addi a0, a0, 2047
; RV32I-NEXT: #NO_APP
; RV32I-NEXT: #APP
; RV32I-NEXT: addi a0, a0, -2048
; RV32I-NEXT: #NO_APP
; RV32I-NEXT: ret
;
; RV64I-LABEL: constraint_I:
; RV64I: # %bb.0:
; RV64I-NEXT: #APP
; RV64I-NEXT: addi a0, a0, 2047
; RV64I-NEXT: #NO_APP
; RV64I-NEXT: #APP
; RV64I-NEXT: addi a0, a0, -2048
; RV64I-NEXT: #NO_APP
; RV64I-NEXT: ret
tail call void asm sideeffect "addi a0, a0, $0", "I"(i32 2047)
tail call void asm sideeffect "addi a0, a0, $0", "I"(i32 -2048)
ret void
}
define void @constraint_J() {
; RV32I-LABEL: constraint_J:
; RV32I: # %bb.0:
; RV32I-NEXT: #APP
; RV32I-NEXT: addi a0, a0, 0
; RV32I-NEXT: #NO_APP
; RV32I-NEXT: ret
;
; RV64I-LABEL: constraint_J:
; RV64I: # %bb.0:
; RV64I-NEXT: #APP
; RV64I-NEXT: addi a0, a0, 0
; RV64I-NEXT: #NO_APP
; RV64I-NEXT: ret
tail call void asm sideeffect "addi a0, a0, $0", "J"(i32 0)
ret void
}
define void @constraint_K() {
; RV32I-LABEL: constraint_K:
; RV32I: # %bb.0:
; RV32I-NEXT: #APP
; RV32I-NEXT: csrwi mstatus, 31
; RV32I-NEXT: #NO_APP
; RV32I-NEXT: #APP
; RV32I-NEXT: csrwi mstatus, 0
; RV32I-NEXT: #NO_APP
; RV32I-NEXT: ret
;
; RV64I-LABEL: constraint_K:
; RV64I: # %bb.0:
; RV64I-NEXT: #APP
; RV64I-NEXT: csrwi mstatus, 31
; RV64I-NEXT: #NO_APP
; RV64I-NEXT: #APP
; RV64I-NEXT: csrwi mstatus, 0
; RV64I-NEXT: #NO_APP
; RV64I-NEXT: ret
tail call void asm sideeffect "csrwi mstatus, $0", "K"(i32 31)
tail call void asm sideeffect "csrwi mstatus, $0", "K"(i32 0)
ret void
}
; TODO: expend tests for more complex constraints, out of range immediates etc