Skip to content

Commit 8a7843c

Browse files
authored
[RISCV] Add 16 bit GPR sub-register for Zhinx. (#107446)
This patches adds a 16 bit register class for use with Zhinx instructions. This makes them more similar to Zfh instructions and allows us to only spill 16 bits. I've added CodeGenOnly instructions for load/store using GPRF16 as that gave better results than insert_subreg/extract_subreg. I'm using FSGNJ for GPRF16 copy with Zhinx as that gave better results. Zhinxmin will use ADDI+subreg operations. Function arguments use this new GPRF16 register class for f16 arguments with Zhinxmin. Eliminating the need to use RISCVISD::FMV* nodes. I plan to extend this idea to Zfinx next.
1 parent af3837c commit 8a7843c

23 files changed

+964
-282
lines changed

llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,13 @@ struct RISCVOperand final : public MCParsedAsmOperand {
480480
RISCVMCRegisterClasses[RISCV::GPRRegClassID].contains(Reg.RegNum);
481481
}
482482

483+
bool isGPRF16() const {
484+
return Kind == KindTy::Register &&
485+
RISCVMCRegisterClasses[RISCV::GPRF16RegClassID].contains(Reg.RegNum);
486+
}
487+
483488
bool isGPRAsFPR() const { return isGPR() && Reg.IsGPRAsFPR; }
489+
bool isGPRAsFPR16() const { return isGPRF16() && Reg.IsGPRAsFPR; }
484490
bool isGPRPairAsFPR() const { return isGPRPair() && Reg.IsGPRAsFPR; }
485491

486492
bool isGPRPair() const {
@@ -1342,6 +1348,10 @@ unsigned RISCVAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
13421348
Op.Reg.RegNum = convertFPR64ToFPR16(Reg);
13431349
return Match_Success;
13441350
}
1351+
if (Kind == MCK_GPRAsFPR16 && Op.isGPRAsFPR()) {
1352+
Op.Reg.RegNum = Reg - RISCV::X0 + RISCV::X0_H;
1353+
return Match_Success;
1354+
}
13451355

13461356
// There are some GPRF64AsFPR instructions that have no RV32 equivalent. We
13471357
// reject them at parsing thinking we should match as GPRPairAsFPR for RV32.

llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,19 @@ static DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, uint32_t RegNo,
8181
return MCDisassembler::Success;
8282
}
8383

84+
static DecodeStatus DecodeGPRF16RegisterClass(MCInst &Inst, uint32_t RegNo,
85+
uint64_t Address,
86+
const MCDisassembler *Decoder) {
87+
bool IsRVE = Decoder->getSubtargetInfo().hasFeature(RISCV::FeatureStdExtE);
88+
89+
if (RegNo >= 32 || (IsRVE && RegNo >= 16))
90+
return MCDisassembler::Fail;
91+
92+
MCRegister Reg = RISCV::X0_H + RegNo;
93+
Inst.addOperand(MCOperand::createReg(Reg));
94+
return MCDisassembler::Success;
95+
}
96+
8497
static DecodeStatus DecodeGPRX1X5RegisterClass(MCInst &Inst, uint32_t RegNo,
8598
uint64_t Address,
8699
const MCDisassembler *Decoder) {

llvm/lib/Target/RISCV/RISCVCallingConv.cpp

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,23 @@ ArrayRef<MCPhysReg> RISCV::getArgGPRs(const RISCVABI::ABI ABI) {
139139
return ArrayRef(ArgIGPRs);
140140
}
141141

142+
static ArrayRef<MCPhysReg> getArgGPR16s(const RISCVABI::ABI ABI) {
143+
// The GPRs used for passing arguments in the ILP32* and LP64* ABIs, except
144+
// the ILP32E ABI.
145+
static const MCPhysReg ArgIGPRs[] = {RISCV::X10_H, RISCV::X11_H, RISCV::X12_H,
146+
RISCV::X13_H, RISCV::X14_H, RISCV::X15_H,
147+
RISCV::X16_H, RISCV::X17_H};
148+
// The GPRs used for passing arguments in the ILP32E/LP64E ABI.
149+
static const MCPhysReg ArgEGPRs[] = {RISCV::X10_H, RISCV::X11_H,
150+
RISCV::X12_H, RISCV::X13_H,
151+
RISCV::X14_H, RISCV::X15_H};
152+
153+
if (ABI == RISCVABI::ABI_ILP32E || ABI == RISCVABI::ABI_LP64E)
154+
return ArrayRef(ArgEGPRs);
155+
156+
return ArrayRef(ArgIGPRs);
157+
}
158+
142159
static ArrayRef<MCPhysReg> getFastCCArgGPRs(const RISCVABI::ABI ABI) {
143160
// The GPRs used for passing arguments in the FastCC, X5 and X6 might be used
144161
// for save-restore libcall, so we don't use them.
@@ -157,6 +174,26 @@ static ArrayRef<MCPhysReg> getFastCCArgGPRs(const RISCVABI::ABI ABI) {
157174
return ArrayRef(FastCCIGPRs);
158175
}
159176

177+
static ArrayRef<MCPhysReg> getFastCCArgGPRF16s(const RISCVABI::ABI ABI) {
178+
// The GPRs used for passing arguments in the FastCC, X5 and X6 might be used
179+
// for save-restore libcall, so we don't use them.
180+
// Don't use X7 for fastcc, since Zicfilp uses X7 as the label register.
181+
static const MCPhysReg FastCCIGPRs[] = {
182+
RISCV::X10_H, RISCV::X11_H, RISCV::X12_H, RISCV::X13_H,
183+
RISCV::X14_H, RISCV::X15_H, RISCV::X16_H, RISCV::X17_H,
184+
RISCV::X28_H, RISCV::X29_H, RISCV::X30_H, RISCV::X31_H};
185+
186+
// The GPRs used for passing arguments in the FastCC when using ILP32E/LP64E.
187+
static const MCPhysReg FastCCEGPRs[] = {RISCV::X10_H, RISCV::X11_H,
188+
RISCV::X12_H, RISCV::X13_H,
189+
RISCV::X14_H, RISCV::X15_H};
190+
191+
if (ABI == RISCVABI::ABI_ILP32E || ABI == RISCVABI::ABI_LP64E)
192+
return ArrayRef(FastCCEGPRs);
193+
194+
return ArrayRef(FastCCIGPRs);
195+
}
196+
160197
// Pass a 2*XLEN argument that has been split into two XLEN values through
161198
// registers or the stack as necessary.
162199
static bool CC_RISCVAssign2XLen(unsigned XLen, CCState &State, CCValAssign VA1,
@@ -320,6 +357,13 @@ bool llvm::CC_RISCV(unsigned ValNo, MVT ValVT, MVT LocVT,
320357
}
321358
}
322359

360+
if ((ValVT == MVT::f16 && Subtarget.hasStdExtZhinxmin())) {
361+
if (MCRegister Reg = State.AllocateReg(getArgGPR16s(ABI))) {
362+
State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
363+
return false;
364+
}
365+
}
366+
323367
ArrayRef<MCPhysReg> ArgGPRs = RISCV::getArgGPRs(ABI);
324368

325369
// Zfinx/Zdinx use GPR without a bitcast when possible.
@@ -564,9 +608,16 @@ bool llvm::CC_RISCV_FastCC(unsigned ValNo, MVT ValVT, MVT LocVT,
564608

565609
MVT XLenVT = Subtarget.getXLenVT();
566610

611+
// Check if there is an available GPRF16 before hitting the stack.
612+
if ((LocVT == MVT::f16 && Subtarget.hasStdExtZhinxmin())) {
613+
if (MCRegister Reg = State.AllocateReg(getFastCCArgGPRF16s(ABI))) {
614+
State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
615+
return false;
616+
}
617+
}
618+
567619
// Check if there is an available GPR before hitting the stack.
568-
if ((LocVT == MVT::f16 && Subtarget.hasStdExtZhinxmin()) ||
569-
(LocVT == MVT::f32 && Subtarget.hasStdExtZfinx()) ||
620+
if ((LocVT == MVT::f32 && Subtarget.hasStdExtZfinx()) ||
570621
(LocVT == MVT::f64 && Subtarget.is64Bit() &&
571622
Subtarget.hasStdExtZdinx())) {
572623
if (MCRegister Reg = State.AllocateReg(getFastCCArgGPRs(ABI))) {

llvm/lib/Target/RISCV/RISCVDeadRegisterDefinitions.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,19 @@ bool RISCVDeadRegisterDefinitions::runOnMachineFunction(MachineFunction &MF) {
9393
continue;
9494
LLVM_DEBUG(dbgs() << " Dead def operand #" << I << " in:\n ";
9595
MI.print(dbgs()));
96+
Register X0Reg;
9697
const TargetRegisterClass *RC = TII->getRegClass(Desc, I, TRI, MF);
97-
if (!(RC && RC->contains(RISCV::X0))) {
98+
if (RC && RC->contains(RISCV::X0)) {
99+
X0Reg = RISCV::X0;
100+
} else if (RC && RC->contains(RISCV::X0_H)) {
101+
X0Reg = RISCV::X0_H;
102+
} else {
98103
LLVM_DEBUG(dbgs() << " Ignoring, register is not a GPR.\n");
99104
continue;
100105
}
101106
assert(LIS.hasInterval(Reg));
102107
LIS.removeInterval(Reg);
103-
MO.setReg(RISCV::X0);
108+
MO.setReg(X0Reg);
104109
LLVM_DEBUG(dbgs() << " Replacing with zero register. New:\n ";
105110
MI.print(dbgs()));
106111
++NumDeadDefsReplaced;

llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ class RISCVExpandPseudo : public MachineFunctionPass {
4848
MachineBasicBlock::iterator &NextMBBI);
4949
bool expandVMSET_VMCLR(MachineBasicBlock &MBB,
5050
MachineBasicBlock::iterator MBBI, unsigned Opcode);
51+
bool expandMV_FPR16INX(MachineBasicBlock &MBB,
52+
MachineBasicBlock::iterator MBBI);
5153
bool expandRV32ZdinxStore(MachineBasicBlock &MBB,
5254
MachineBasicBlock::iterator MBBI);
5355
bool expandRV32ZdinxLoad(MachineBasicBlock &MBB,
@@ -104,6 +106,8 @@ bool RISCVExpandPseudo::expandMI(MachineBasicBlock &MBB,
104106
// expanded instructions for each pseudo is correct in the Size field of the
105107
// tablegen definition for the pseudo.
106108
switch (MBBI->getOpcode()) {
109+
case RISCV::PseudoMV_FPR16INX:
110+
return expandMV_FPR16INX(MBB, MBBI);
107111
case RISCV::PseudoRV32ZdinxSD:
108112
return expandRV32ZdinxStore(MBB, MBBI);
109113
case RISCV::PseudoRV32ZdinxLD:
@@ -266,6 +270,23 @@ bool RISCVExpandPseudo::expandVMSET_VMCLR(MachineBasicBlock &MBB,
266270
return true;
267271
}
268272

273+
bool RISCVExpandPseudo::expandMV_FPR16INX(MachineBasicBlock &MBB,
274+
MachineBasicBlock::iterator MBBI) {
275+
DebugLoc DL = MBBI->getDebugLoc();
276+
const TargetRegisterInfo *TRI = STI->getRegisterInfo();
277+
Register DstReg = TRI->getMatchingSuperReg(
278+
MBBI->getOperand(0).getReg(), RISCV::sub_16, &RISCV::GPRRegClass);
279+
Register SrcReg = TRI->getMatchingSuperReg(
280+
MBBI->getOperand(1).getReg(), RISCV::sub_16, &RISCV::GPRRegClass);
281+
282+
BuildMI(MBB, MBBI, DL, TII->get(RISCV::ADDI), DstReg)
283+
.addReg(SrcReg, getKillRegState(MBBI->getOperand(1).isKill()))
284+
.addImm(0);
285+
286+
MBBI->eraseFromParent(); // The pseudo instruction is gone now.
287+
return true;
288+
}
289+
269290
// This function expands the PseudoRV32ZdinxSD for storing a double-precision
270291
// floating-point value into memory by generating an equivalent instruction
271292
// sequence for RV32.

llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -928,7 +928,10 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
928928
}
929929

930930
SDNode *Res;
931-
if (Opc == RISCV::FCVT_D_W_IN32X || Opc == RISCV::FCVT_D_W)
931+
if (VT.SimpleTy == MVT::f16 && Opc == RISCV::COPY) {
932+
Res =
933+
CurDAG->getTargetExtractSubreg(RISCV::sub_16, DL, VT, Imm).getNode();
934+
} else if (Opc == RISCV::FCVT_D_W_IN32X || Opc == RISCV::FCVT_D_W)
932935
Res = CurDAG->getMachineNode(
933936
Opc, DL, VT, Imm,
934937
CurDAG->getTargetConstant(RISCVFPRndMode::RNE, DL, XLenVT));

llvm/lib/Target/RISCV/RISCVInstrInfo.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ Register RISCVInstrInfo::isLoadFromStackSlot(const MachineInstr &MI,
104104
MemBytes = 1;
105105
break;
106106
case RISCV::LH:
107+
case RISCV::LH_INX:
107108
case RISCV::LHU:
108109
case RISCV::FLH:
109110
MemBytes = 2;
@@ -144,6 +145,7 @@ Register RISCVInstrInfo::isStoreToStackSlot(const MachineInstr &MI,
144145
MemBytes = 1;
145146
break;
146147
case RISCV::SH:
148+
case RISCV::SH_INX:
147149
case RISCV::FSH:
148150
MemBytes = 2;
149151
break;
@@ -462,6 +464,13 @@ void RISCVInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
462464
return;
463465
}
464466

467+
if (RISCV::GPRF16RegClass.contains(DstReg, SrcReg)) {
468+
BuildMI(MBB, MBBI, DL, get(RISCV::PseudoMV_FPR16INX), DstReg)
469+
.addReg(SrcReg,
470+
getKillRegState(KillSrc) | getRenamableRegState(RenamableSrc));
471+
return;
472+
}
473+
465474
if (RISCV::GPRPairRegClass.contains(DstReg, SrcReg)) {
466475
// Emit an ADDI for both parts of GPRPair.
467476
BuildMI(MBB, MBBI, DL, get(RISCV::ADDI),
@@ -583,6 +592,9 @@ void RISCVInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
583592
Opcode = TRI->getRegSizeInBits(RISCV::GPRRegClass) == 32 ?
584593
RISCV::SW : RISCV::SD;
585594
IsScalableVector = false;
595+
} else if (RISCV::GPRF16RegClass.hasSubClassEq(RC)) {
596+
Opcode = RISCV::SH_INX;
597+
IsScalableVector = false;
586598
} else if (RISCV::GPRPairRegClass.hasSubClassEq(RC)) {
587599
Opcode = RISCV::PseudoRV32ZdinxSD;
588600
IsScalableVector = false;
@@ -666,6 +678,9 @@ void RISCVInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
666678
Opcode = TRI->getRegSizeInBits(RISCV::GPRRegClass) == 32 ?
667679
RISCV::LW : RISCV::LD;
668680
IsScalableVector = false;
681+
} else if (RISCV::GPRF16RegClass.hasSubClassEq(RC)) {
682+
Opcode = RISCV::LH_INX;
683+
IsScalableVector = false;
669684
} else if (RISCV::GPRPairRegClass.hasSubClassEq(RC)) {
670685
Opcode = RISCV::PseudoRV32ZdinxLD;
671686
IsScalableVector = false;
@@ -1538,6 +1553,9 @@ unsigned RISCVInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
15381553
}
15391554

15401555
switch (Opcode) {
1556+
case RISCV::PseudoMV_FPR16INX:
1557+
// MV is always compressible to either c.mv or c.li rd, 0.
1558+
return STI.hasStdExtCOrZca() ? 2 : 4;
15411559
case TargetOpcode::STACKMAP:
15421560
// The upper bound for a stackmap intrinsic is the full length of its shadow
15431561
return StackMapOpers(&MI).getNumPatchBytes();
@@ -2593,6 +2611,7 @@ bool RISCVInstrInfo::canFoldIntoAddrMode(const MachineInstr &MemI, Register Reg,
25932611
case RISCV::LB:
25942612
case RISCV::LBU:
25952613
case RISCV::LH:
2614+
case RISCV::LH_INX:
25962615
case RISCV::LHU:
25972616
case RISCV::LW:
25982617
case RISCV::LWU:
@@ -2602,6 +2621,7 @@ bool RISCVInstrInfo::canFoldIntoAddrMode(const MachineInstr &MemI, Register Reg,
26022621
case RISCV::FLD:
26032622
case RISCV::SB:
26042623
case RISCV::SH:
2624+
case RISCV::SH_INX:
26052625
case RISCV::SW:
26062626
case RISCV::SD:
26072627
case RISCV::FSH:
@@ -2665,9 +2685,11 @@ bool RISCVInstrInfo::getMemOperandsWithOffsetWidth(
26652685
case RISCV::LBU:
26662686
case RISCV::SB:
26672687
case RISCV::LH:
2688+
case RISCV::LH_INX:
26682689
case RISCV::LHU:
26692690
case RISCV::FLH:
26702691
case RISCV::SH:
2692+
case RISCV::SH_INX:
26712693
case RISCV::FSH:
26722694
case RISCV::LW:
26732695
case RISCV::LWU:

llvm/lib/Target/RISCV/RISCVInstrInfo.td

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -520,8 +520,8 @@ class BranchCC_rri<bits<3> funct3, string opcodestr>
520520
}
521521

522522
let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in {
523-
class Load_ri<bits<3> funct3, string opcodestr>
524-
: RVInstI<funct3, OPC_LOAD, (outs GPR:$rd), (ins GPRMem:$rs1, simm12:$imm12),
523+
class Load_ri<bits<3> funct3, string opcodestr, DAGOperand rty = GPR>
524+
: RVInstI<funct3, OPC_LOAD, (outs rty:$rd), (ins GPRMem:$rs1, simm12:$imm12),
525525
opcodestr, "$rd, ${imm12}(${rs1})">;
526526

527527
class HLoad_r<bits<7> funct7, bits<5> funct5, string opcodestr>
@@ -535,9 +535,9 @@ class HLoad_r<bits<7> funct7, bits<5> funct5, string opcodestr>
535535
// reflecting the order these fields are specified in the instruction
536536
// encoding.
537537
let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in {
538-
class Store_rri<bits<3> funct3, string opcodestr>
538+
class Store_rri<bits<3> funct3, string opcodestr, DAGOperand rty = GPR>
539539
: RVInstS<funct3, OPC_STORE, (outs),
540-
(ins GPR:$rs2, GPRMem:$rs1, simm12:$imm12),
540+
(ins rty:$rs2, GPRMem:$rs1, simm12:$imm12),
541541
opcodestr, "$rs2, ${imm12}(${rs1})">;
542542

543543
class HStore_rr<bits<7> funct7, string opcodestr>
@@ -549,8 +549,8 @@ class HStore_rr<bits<7> funct7, string opcodestr>
549549
}
550550

551551
let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
552-
class ALU_ri<bits<3> funct3, string opcodestr>
553-
: RVInstI<funct3, OPC_OP_IMM, (outs GPR:$rd), (ins GPR:$rs1, simm12:$imm12),
552+
class ALU_ri<bits<3> funct3, string opcodestr, DAGOperand rty = GPR>
553+
: RVInstI<funct3, OPC_OP_IMM, (outs rty:$rd), (ins rty:$rs1, simm12:$imm12),
554554
opcodestr, "$rd, $rs1, $imm12">,
555555
Sched<[WriteIALU, ReadIALU]>;
556556

llvm/lib/Target/RISCV/RISCVInstrInfoZc.td

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,9 @@ class CLoadB_ri<bits<6> funct6, string OpcodeStr>
112112
}
113113

114114
let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in
115-
class CLoadH_ri<bits<6> funct6, bit funct1, string OpcodeStr>
116-
: RVInst16CLH<funct6, funct1, 0b00, (outs GPRC:$rd),
115+
class CLoadH_ri<bits<6> funct6, bit funct1, string OpcodeStr,
116+
DAGOperand rty = GPRC>
117+
: RVInst16CLH<funct6, funct1, 0b00, (outs rty:$rd),
117118
(ins GPRCMem:$rs1, uimm2_lsb0:$imm),
118119
OpcodeStr, "$rd, ${imm}(${rs1})"> {
119120
bits<2> imm;
@@ -132,9 +133,10 @@ class CStoreB_rri<bits<6> funct6, string OpcodeStr>
132133
}
133134

134135
let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in
135-
class CStoreH_rri<bits<6> funct6, bit funct1, string OpcodeStr>
136+
class CStoreH_rri<bits<6> funct6, bit funct1, string OpcodeStr,
137+
DAGOperand rty = GPRC>
136138
: RVInst16CSH<funct6, funct1, 0b00, (outs),
137-
(ins GPRC:$rs2, GPRCMem:$rs1, uimm2_lsb0:$imm),
139+
(ins rty:$rs2, GPRCMem:$rs1, uimm2_lsb0:$imm),
138140
OpcodeStr, "$rs2, ${imm}(${rs1})"> {
139141
bits<2> imm;
140142

@@ -202,7 +204,15 @@ def C_SB : CStoreB_rri<0b100010, "c.sb">,
202204
Sched<[WriteSTB, ReadStoreData, ReadMemBase]>;
203205
def C_SH : CStoreH_rri<0b100011, 0b0, "c.sh">,
204206
Sched<[WriteSTH, ReadStoreData, ReadMemBase]>;
207+
208+
// Compressed versions of Zhinx load/store.
209+
let isCodeGenOnly = 1 in {
210+
def C_LH_INX : CLoadH_ri<0b100001, 0b1, "c.lh", GPRF16C>,
211+
Sched<[WriteLDH, ReadMemBase]>;
212+
def C_SH_INX : CStoreH_rri<0b100011, 0b0, "c.sh", GPRF16C>,
213+
Sched<[WriteSTH, ReadStoreData, ReadMemBase]>;
205214
}
215+
} // Predicates = [HasStdExtZcb]
206216

207217
// Zcmp
208218
let DecoderNamespace = "RVZcmp", Predicates = [HasStdExtZcmp],
@@ -318,6 +328,13 @@ def : CompressPat<(SB GPRC:$rs2, GPRCMem:$rs1, uimm2:$imm),
318328
(C_SB GPRC:$rs2, GPRCMem:$rs1, uimm2:$imm)>;
319329
def : CompressPat<(SH GPRC:$rs2, GPRCMem:$rs1, uimm2_lsb0:$imm),
320330
(C_SH GPRC:$rs2, GPRCMem:$rs1, uimm2_lsb0:$imm)>;
331+
332+
let isCompressOnly = true in {
333+
def : CompressPat<(LH_INX GPRF16C:$rd, GPRCMem:$rs1, uimm2_lsb0:$imm),
334+
(C_LH_INX GPRF16C:$rd, GPRCMem:$rs1, uimm2_lsb0:$imm)>;
335+
def : CompressPat<(SH_INX GPRF16C:$rs2, GPRCMem:$rs1, uimm2_lsb0:$imm),
336+
(C_SH_INX GPRF16C:$rs2, GPRCMem:$rs1, uimm2_lsb0:$imm)>;
337+
}
321338
}// Predicates = [HasStdExtZcb]
322339

323340

0 commit comments

Comments
 (0)