Skip to content

Commit 28a5cad

Browse files
committed
[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
1 parent f63feaf commit 28a5cad

File tree

3 files changed

+110
-0
lines changed

3 files changed

+110
-0
lines changed

llvm/lib/Target/RISCV/RISCVISelLowering.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2151,6 +2151,44 @@ RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
21512151
return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
21522152
}
21532153

2154+
void RISCVTargetLowering::LowerAsmOperandForConstraint(
2155+
SDValue Op, std::string &Constraint, std::vector<SDValue> &Ops,
2156+
SelectionDAG &DAG) const {
2157+
// Currently only support length 1 constraints.
2158+
if (Constraint.length() == 1) {
2159+
switch (Constraint[0]) {
2160+
case 'I':
2161+
// Validate & create a 12-bit signed immediate operand.
2162+
if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
2163+
uint64_t CVal = C->getSExtValue();
2164+
if (isInt<12>(CVal))
2165+
Ops.push_back(
2166+
DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getXLenVT()));
2167+
}
2168+
return;
2169+
case 'J':
2170+
// Validate & create an integer zero operand.
2171+
if (auto *C = dyn_cast<ConstantSDNode>(Op))
2172+
if (C->getZExtValue() == 0)
2173+
Ops.push_back(
2174+
DAG.getTargetConstant(0, SDLoc(Op), Subtarget.getXLenVT()));
2175+
return;
2176+
case 'K':
2177+
// Validate & create a 5-bit unsigned immediate operand.
2178+
if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
2179+
uint64_t CVal = C->getZExtValue();
2180+
if (isUInt<5>(CVal))
2181+
Ops.push_back(
2182+
DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getXLenVT()));
2183+
}
2184+
return;
2185+
default:
2186+
break;
2187+
}
2188+
}
2189+
TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG);
2190+
}
2191+
21542192
Instruction *RISCVTargetLowering::emitLeadingFence(IRBuilder<> &Builder,
21552193
Instruction *Inst,
21562194
AtomicOrdering Ord) const {

llvm/lib/Target/RISCV/RISCVISelLowering.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@ class RISCVTargetLowering : public TargetLowering {
9393
getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
9494
StringRef Constraint, MVT VT) const override;
9595

96+
void LowerAsmOperandForConstraint(SDValue Op, std::string &Constraint,
97+
std::vector<SDValue> &Ops,
98+
SelectionDAG &DAG) const override;
99+
96100
MachineBasicBlock *
97101
EmitInstrWithCustomInserter(MachineInstr &MI,
98102
MachineBasicBlock *BB) const override;

llvm/test/CodeGen/RISCV/inline-asm.ll

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,72 @@ define i32 @constraint_m2(i32* %a) nounwind {
8282
ret i32 %1
8383
}
8484

85+
define void @constraint_I() {
86+
; RV32I-LABEL: constraint_I:
87+
; RV32I: # %bb.0:
88+
; RV32I-NEXT: #APP
89+
; RV32I-NEXT: addi a0, a0, 2047
90+
; RV32I-NEXT: #NO_APP
91+
; RV32I-NEXT: #APP
92+
; RV32I-NEXT: addi a0, a0, -2048
93+
; RV32I-NEXT: #NO_APP
94+
; RV32I-NEXT: ret
95+
;
96+
; RV64I-LABEL: constraint_I:
97+
; RV64I: # %bb.0:
98+
; RV64I-NEXT: #APP
99+
; RV64I-NEXT: addi a0, a0, 2047
100+
; RV64I-NEXT: #NO_APP
101+
; RV64I-NEXT: #APP
102+
; RV64I-NEXT: addi a0, a0, -2048
103+
; RV64I-NEXT: #NO_APP
104+
; RV64I-NEXT: ret
105+
tail call void asm sideeffect "addi a0, a0, $0", "I"(i32 2047)
106+
tail call void asm sideeffect "addi a0, a0, $0", "I"(i32 -2048)
107+
ret void
108+
}
109+
110+
define void @constraint_J() {
111+
; RV32I-LABEL: constraint_J:
112+
; RV32I: # %bb.0:
113+
; RV32I-NEXT: #APP
114+
; RV32I-NEXT: addi a0, a0, 0
115+
; RV32I-NEXT: #NO_APP
116+
; RV32I-NEXT: ret
117+
;
118+
; RV64I-LABEL: constraint_J:
119+
; RV64I: # %bb.0:
120+
; RV64I-NEXT: #APP
121+
; RV64I-NEXT: addi a0, a0, 0
122+
; RV64I-NEXT: #NO_APP
123+
; RV64I-NEXT: ret
124+
tail call void asm sideeffect "addi a0, a0, $0", "J"(i32 0)
125+
ret void
126+
}
127+
128+
define void @constraint_K() {
129+
; RV32I-LABEL: constraint_K:
130+
; RV32I: # %bb.0:
131+
; RV32I-NEXT: #APP
132+
; RV32I-NEXT: csrwi mstatus, 31
133+
; RV32I-NEXT: #NO_APP
134+
; RV32I-NEXT: #APP
135+
; RV32I-NEXT: csrwi mstatus, 0
136+
; RV32I-NEXT: #NO_APP
137+
; RV32I-NEXT: ret
138+
;
139+
; RV64I-LABEL: constraint_K:
140+
; RV64I: # %bb.0:
141+
; RV64I-NEXT: #APP
142+
; RV64I-NEXT: csrwi mstatus, 31
143+
; RV64I-NEXT: #NO_APP
144+
; RV64I-NEXT: #APP
145+
; RV64I-NEXT: csrwi mstatus, 0
146+
; RV64I-NEXT: #NO_APP
147+
; RV64I-NEXT: ret
148+
tail call void asm sideeffect "csrwi mstatus, $0", "K"(i32 31)
149+
tail call void asm sideeffect "csrwi mstatus, $0", "K"(i32 0)
150+
ret void
151+
}
152+
85153
; TODO: expend tests for more complex constraints, out of range immediates etc

0 commit comments

Comments
 (0)