-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[RISCV] Add 32 bit GPR sub-register for Zfinx. #108336
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-backend-risc-v Author: Craig Topper (topperc) ChangesThis patches adds a 32 bit register class for use with Zfinx instructions. I've added CodeGenOnly instructions for load/store using GPRF32 as that Function arguments use this new GPRF32 register class for f32 arguments This is similar to #107446 which adds a 16 bit register class. Patch is 160.87 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/108336.diff 37 Files Affected:
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index 6eb2058107610e..0f1cc84be14558 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -480,7 +480,19 @@ struct RISCVOperand final : public MCParsedAsmOperand {
RISCVMCRegisterClasses[RISCV::GPRRegClassID].contains(Reg.RegNum);
}
+ bool isGPRF16() const {
+ return Kind == KindTy::Register &&
+ RISCVMCRegisterClasses[RISCV::GPRF16RegClassID].contains(Reg.RegNum);
+ }
+
+ bool isGPRF32() const {
+ return Kind == KindTy::Register &&
+ RISCVMCRegisterClasses[RISCV::GPRF32RegClassID].contains(Reg.RegNum);
+ }
+
bool isGPRAsFPR() const { return isGPR() && Reg.IsGPRAsFPR; }
+ bool isGPRAsFPR16() const { return isGPRF16() && Reg.IsGPRAsFPR; }
+ bool isGPRAsFPR32() const { return isGPRF32() && Reg.IsGPRAsFPR; }
bool isGPRPairAsFPR() const { return isGPRPair() && Reg.IsGPRAsFPR; }
bool isGPRPair() const {
@@ -1342,6 +1354,14 @@ unsigned RISCVAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
Op.Reg.RegNum = convertFPR64ToFPR16(Reg);
return Match_Success;
}
+ if (Kind == MCK_GPRAsFPR16 && Op.isGPRAsFPR()) {
+ Op.Reg.RegNum = Reg - RISCV::X0 + RISCV::X0_H;
+ return Match_Success;
+ }
+ if (Kind == MCK_GPRAsFPR32 && Op.isGPRAsFPR()) {
+ Op.Reg.RegNum = Reg - RISCV::X0 + RISCV::X0_W;
+ return Match_Success;
+ }
// There are some GPRF64AsFPR instructions that have no RV32 equivalent. We
// reject them at parsing thinking we should match as GPRPairAsFPR for RV32.
diff --git a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
index b869458a256147..7c8206cb44dec2 100644
--- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
+++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
@@ -81,6 +81,32 @@ static DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, uint32_t RegNo,
return MCDisassembler::Success;
}
+static DecodeStatus DecodeGPRF16RegisterClass(MCInst &Inst, uint32_t RegNo,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ bool IsRVE = Decoder->getSubtargetInfo().hasFeature(RISCV::FeatureStdExtE);
+
+ if (RegNo >= 32 || (IsRVE && RegNo >= 16))
+ return MCDisassembler::Fail;
+
+ MCRegister Reg = RISCV::X0_H + RegNo;
+ Inst.addOperand(MCOperand::createReg(Reg));
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus DecodeGPRF32RegisterClass(MCInst &Inst, uint32_t RegNo,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ bool IsRVE = Decoder->getSubtargetInfo().hasFeature(RISCV::FeatureStdExtE);
+
+ if (RegNo >= 32 || (IsRVE && RegNo >= 16))
+ return MCDisassembler::Fail;
+
+ MCRegister Reg = RISCV::X0_W + RegNo;
+ Inst.addOperand(MCOperand::createReg(Reg));
+ return MCDisassembler::Success;
+}
+
static DecodeStatus DecodeGPRX1X5RegisterClass(MCInst &Inst, uint32_t RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
diff --git a/llvm/lib/Target/RISCV/RISCVCallingConv.cpp b/llvm/lib/Target/RISCV/RISCVCallingConv.cpp
index deba85946be53a..03a0edbd008cae 100644
--- a/llvm/lib/Target/RISCV/RISCVCallingConv.cpp
+++ b/llvm/lib/Target/RISCV/RISCVCallingConv.cpp
@@ -139,6 +139,40 @@ ArrayRef<MCPhysReg> RISCV::getArgGPRs(const RISCVABI::ABI ABI) {
return ArrayRef(ArgIGPRs);
}
+static ArrayRef<MCPhysReg> getArgGPR16s(const RISCVABI::ABI ABI) {
+ // The GPRs used for passing arguments in the ILP32* and LP64* ABIs, except
+ // the ILP32E ABI.
+ static const MCPhysReg ArgIGPRs[] = {RISCV::X10_H, RISCV::X11_H, RISCV::X12_H,
+ RISCV::X13_H, RISCV::X14_H, RISCV::X15_H,
+ RISCV::X16_H, RISCV::X17_H};
+ // The GPRs used for passing arguments in the ILP32E/ILP64E ABI.
+ static const MCPhysReg ArgEGPRs[] = {RISCV::X10_H, RISCV::X11_H,
+ RISCV::X12_H, RISCV::X13_H,
+ RISCV::X14_H, RISCV::X15_H};
+
+ if (ABI == RISCVABI::ABI_ILP32E || ABI == RISCVABI::ABI_LP64E)
+ return ArrayRef(ArgEGPRs);
+
+ return ArrayRef(ArgIGPRs);
+}
+
+static ArrayRef<MCPhysReg> getArgGPR32s(const RISCVABI::ABI ABI) {
+ // The GPRs used for passing arguments in the ILP32* and LP64* ABIs, except
+ // the ILP32E ABI.
+ static const MCPhysReg ArgIGPRs[] = {RISCV::X10_W, RISCV::X11_W, RISCV::X12_W,
+ RISCV::X13_W, RISCV::X14_W, RISCV::X15_W,
+ RISCV::X16_W, RISCV::X17_W};
+ // The GPRs used for passing arguments in the ILP32E/ILP64E ABI.
+ static const MCPhysReg ArgEGPRs[] = {RISCV::X10_W, RISCV::X11_W,
+ RISCV::X12_W, RISCV::X13_W,
+ RISCV::X14_W, RISCV::X15_W};
+
+ if (ABI == RISCVABI::ABI_ILP32E || ABI == RISCVABI::ABI_LP64E)
+ return ArrayRef(ArgEGPRs);
+
+ return ArrayRef(ArgIGPRs);
+}
+
static ArrayRef<MCPhysReg> getFastCCArgGPRs(const RISCVABI::ABI ABI) {
// The GPRs used for passing arguments in the FastCC, X5 and X6 might be used
// for save-restore libcall, so we don't use them.
@@ -157,6 +191,46 @@ static ArrayRef<MCPhysReg> getFastCCArgGPRs(const RISCVABI::ABI ABI) {
return ArrayRef(FastCCIGPRs);
}
+static ArrayRef<MCPhysReg> getFastCCArgGPRF16s(const RISCVABI::ABI ABI) {
+ // The GPRs used for passing arguments in the FastCC, X5 and X6 might be used
+ // for save-restore libcall, so we don't use them.
+ // Don't use X7 for fastcc, since Zicfilp uses X7 as the label register.
+ static const MCPhysReg FastCCIGPRs[] = {
+ RISCV::X10_H, RISCV::X11_H, RISCV::X12_H, RISCV::X13_H,
+ RISCV::X14_H, RISCV::X15_H, RISCV::X16_H, RISCV::X17_H,
+ RISCV::X28_H, RISCV::X29_H, RISCV::X30_H, RISCV::X31_H};
+
+ // The GPRs used for passing arguments in the FastCC when using ILP32E/ILP64E.
+ static const MCPhysReg FastCCEGPRs[] = {RISCV::X10_H, RISCV::X11_H,
+ RISCV::X12_H, RISCV::X13_H,
+ RISCV::X14_H, RISCV::X15_H};
+
+ if (ABI == RISCVABI::ABI_ILP32E || ABI == RISCVABI::ABI_LP64E)
+ return ArrayRef(FastCCEGPRs);
+
+ return ArrayRef(FastCCIGPRs);
+}
+
+static ArrayRef<MCPhysReg> getFastCCArgGPRF32s(const RISCVABI::ABI ABI) {
+ // The GPRs used for passing arguments in the FastCC, X5 and X6 might be used
+ // for save-restore libcall, so we don't use them.
+ // Don't use X7 for fastcc, since Zicfilp uses X7 as the label register.
+ static const MCPhysReg FastCCIGPRs[] = {
+ RISCV::X10_W, RISCV::X11_W, RISCV::X12_W, RISCV::X13_W,
+ RISCV::X14_W, RISCV::X15_W, RISCV::X16_W, RISCV::X17_W,
+ RISCV::X28_W, RISCV::X29_W, RISCV::X30_W, RISCV::X31_W};
+
+ // The GPRs used for passing arguments in the FastCC when using ILP32E/ILP64E.
+ static const MCPhysReg FastCCEGPRs[] = {RISCV::X10_W, RISCV::X11_W,
+ RISCV::X12_W, RISCV::X13_W,
+ RISCV::X14_W, RISCV::X15_W};
+
+ if (ABI == RISCVABI::ABI_ILP32E || ABI == RISCVABI::ABI_LP64E)
+ return ArrayRef(FastCCEGPRs);
+
+ return ArrayRef(FastCCIGPRs);
+}
+
// Pass a 2*XLEN argument that has been split into two XLEN values through
// registers or the stack as necessary.
static bool CC_RISCVAssign2XLen(unsigned XLen, CCState &State, CCValAssign VA1,
@@ -320,11 +394,24 @@ bool llvm::CC_RISCV(unsigned ValNo, MVT ValVT, MVT LocVT,
}
}
+ if ((ValVT == MVT::f16 && Subtarget.hasStdExtZhinxmin())) {
+ if (MCRegister Reg = State.AllocateReg(getArgGPR16s(ABI))) {
+ State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
+ return false;
+ }
+ }
+
+ if ((ValVT == MVT::f32 && Subtarget.hasStdExtZfinx())) {
+ if (MCRegister Reg = State.AllocateReg(getArgGPR32s(ABI))) {
+ State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
+ return false;
+ }
+ }
+
ArrayRef<MCPhysReg> ArgGPRs = RISCV::getArgGPRs(ABI);
- // Zfinx/Zdinx use GPR without a bitcast when possible.
- if ((LocVT == MVT::f32 && XLen == 32 && Subtarget.hasStdExtZfinx()) ||
- (LocVT == MVT::f64 && XLen == 64 && Subtarget.hasStdExtZdinx())) {
+ // Zdinx use GPR without a bitcast when possible.
+ if (LocVT == MVT::f64 && XLen == 64 && Subtarget.hasStdExtZdinx()) {
if (MCRegister Reg = State.AllocateReg(ArgGPRs)) {
State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
return false;
@@ -565,11 +652,24 @@ bool llvm::CC_RISCV_FastCC(unsigned ValNo, MVT ValVT, MVT LocVT,
}
}
+ // Check if there is an available GPRF16 before hitting the stack.
+ if (LocVT == MVT::f16 && Subtarget.hasStdExtZhinxmin()) {
+ if (MCRegister Reg = State.AllocateReg(getFastCCArgGPRF16s(ABI))) {
+ State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
+ return false;
+ }
+ }
+
+ // Check if there is an available GPRF32 before hitting the stack.
+ if (LocVT == MVT::f32 && Subtarget.hasStdExtZfinx()) {
+ if (MCRegister Reg = State.AllocateReg(getFastCCArgGPRF32s(ABI))) {
+ State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
+ return false;
+ }
+ }
+
// Check if there is an available GPR before hitting the stack.
- if ((LocVT == MVT::f16 && Subtarget.hasStdExtZhinxmin()) ||
- (LocVT == MVT::f32 && Subtarget.hasStdExtZfinx()) ||
- (LocVT == MVT::f64 && Subtarget.is64Bit() &&
- Subtarget.hasStdExtZdinx())) {
+ if (LocVT == MVT::f64 && Subtarget.is64Bit() && Subtarget.hasStdExtZdinx()) {
if (MCRegister Reg = State.AllocateReg(getFastCCArgGPRs(ABI))) {
if (LocVT.getSizeInBits() != Subtarget.getXLen()) {
LocVT = Subtarget.getXLenVT();
@@ -688,6 +788,17 @@ bool llvm::CC_RISCV_GHC(unsigned ValNo, MVT ValVT, MVT LocVT,
}
}
+ if (LocVT == MVT::f32 && Subtarget.hasStdExtZfinx()) {
+ static const MCPhysReg GPR32List[] = {
+ RISCV::X9_W, RISCV::X18_W, RISCV::X19_W, RISCV::X20_W,
+ RISCV::X21_W, RISCV::X22_W, RISCV::X23_W, RISCV::X24_W,
+ RISCV::X25_W, RISCV::X26_W, RISCV::X27_W};
+ if (MCRegister Reg = State.AllocateReg(GPR32List)) {
+ State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
+ return false;
+ }
+ }
+
if ((LocVT == MVT::f32 && Subtarget.hasStdExtZfinx()) ||
(LocVT == MVT::f64 && Subtarget.hasStdExtZdinx() &&
Subtarget.is64Bit())) {
diff --git a/llvm/lib/Target/RISCV/RISCVDeadRegisterDefinitions.cpp b/llvm/lib/Target/RISCV/RISCVDeadRegisterDefinitions.cpp
index cce0ffe16e5fe3..d913c0b201a20c 100644
--- a/llvm/lib/Target/RISCV/RISCVDeadRegisterDefinitions.cpp
+++ b/llvm/lib/Target/RISCV/RISCVDeadRegisterDefinitions.cpp
@@ -93,14 +93,21 @@ bool RISCVDeadRegisterDefinitions::runOnMachineFunction(MachineFunction &MF) {
continue;
LLVM_DEBUG(dbgs() << " Dead def operand #" << I << " in:\n ";
MI.print(dbgs()));
+ Register X0Reg;
const TargetRegisterClass *RC = TII->getRegClass(Desc, I, TRI, MF);
- if (!(RC && RC->contains(RISCV::X0))) {
+ if (RC && RC->contains(RISCV::X0)) {
+ X0Reg = RISCV::X0;
+ } else if (RC && RC->contains(RISCV::X0_W)) {
+ X0Reg = RISCV::X0_W;
+ } else if (RC && RC->contains(RISCV::X0_H)) {
+ X0Reg = RISCV::X0_H;
+ } else {
LLVM_DEBUG(dbgs() << " Ignoring, register is not a GPR.\n");
continue;
}
assert(LIS.hasInterval(Reg));
LIS.removeInterval(Reg);
- MO.setReg(RISCV::X0);
+ MO.setReg(X0Reg);
LLVM_DEBUG(dbgs() << " Replacing with zero register. New:\n ";
MI.print(dbgs()));
++NumDeadDefsReplaced;
diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index ff4c0e9bbd50e7..91e1c02d4d2a52 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -959,7 +959,13 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
}
SDNode *Res;
- if (Opc == RISCV::FCVT_D_W_IN32X || Opc == RISCV::FCVT_D_W)
+ if (VT.SimpleTy == MVT::f16 && Opc == RISCV::COPY) {
+ Res =
+ CurDAG->getTargetExtractSubreg(RISCV::sub_16, DL, VT, Imm).getNode();
+ } else if (VT.SimpleTy == MVT::f32 && Opc == RISCV::COPY) {
+ Res =
+ CurDAG->getTargetExtractSubreg(RISCV::sub_32, DL, VT, Imm).getNode();
+ } else if (Opc == RISCV::FCVT_D_W_IN32X || Opc == RISCV::FCVT_D_W)
Res = CurDAG->getMachineNode(
Opc, DL, VT, Imm,
CurDAG->getTargetConstant(RISCVFPRndMode::RNE, DL, XLenVT));
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
index 325a50c9f48a1c..2a7809021b4358 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
@@ -458,6 +458,31 @@ void RISCVInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
return;
}
+ if (RISCV::GPRF16RegClass.contains(DstReg, SrcReg)) {
+ if (STI.hasStdExtZhinx()) {
+ BuildMI(MBB, MBBI, DL, get(RISCV::FSGNJ_H_INX), DstReg)
+ .addReg(SrcReg, getKillRegState(KillSrc))
+ .addReg(SrcReg, getKillRegState(KillSrc));
+ return;
+ }
+ DstReg =
+ TRI->getMatchingSuperReg(DstReg, RISCV::sub_16, &RISCV::GPRRegClass);
+ SrcReg =
+ TRI->getMatchingSuperReg(SrcReg, RISCV::sub_16, &RISCV::GPRRegClass);
+ BuildMI(MBB, MBBI, DL, get(RISCV::ADDI), DstReg)
+ .addReg(SrcReg, getKillRegState(KillSrc))
+ .addImm(0);
+ return;
+ }
+
+ if (RISCV::GPRF32RegClass.contains(DstReg, SrcReg)) {
+ assert(STI.hasStdExtZfinx());
+ BuildMI(MBB, MBBI, DL, get(RISCV::FSGNJ_S_INX), DstReg)
+ .addReg(SrcReg, getKillRegState(KillSrc))
+ .addReg(SrcReg, getKillRegState(KillSrc));
+ return;
+ }
+
if (RISCV::GPRPairRegClass.contains(DstReg, SrcReg)) {
// Emit an ADDI for both parts of GPRPair.
BuildMI(MBB, MBBI, DL, get(RISCV::ADDI),
@@ -579,6 +604,12 @@ void RISCVInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
Opcode = TRI->getRegSizeInBits(RISCV::GPRRegClass) == 32 ?
RISCV::SW : RISCV::SD;
IsScalableVector = false;
+ } else if (RISCV::GPRF16RegClass.hasSubClassEq(RC)) {
+ Opcode = RISCV::SH_INX;
+ IsScalableVector = false;
+ } else if (RISCV::GPRF32RegClass.hasSubClassEq(RC)) {
+ Opcode = RISCV::SW_INX;
+ IsScalableVector = false;
} else if (RISCV::GPRPairRegClass.hasSubClassEq(RC)) {
Opcode = RISCV::PseudoRV32ZdinxSD;
IsScalableVector = false;
@@ -662,6 +693,12 @@ void RISCVInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
Opcode = TRI->getRegSizeInBits(RISCV::GPRRegClass) == 32 ?
RISCV::LW : RISCV::LD;
IsScalableVector = false;
+ } else if (RISCV::GPRF16RegClass.hasSubClassEq(RC)) {
+ Opcode = RISCV::LH_INX;
+ IsScalableVector = false;
+ } else if (RISCV::GPRF32RegClass.hasSubClassEq(RC)) {
+ Opcode = RISCV::LW_INX;
+ IsScalableVector = false;
} else if (RISCV::GPRPairRegClass.hasSubClassEq(RC)) {
Opcode = RISCV::PseudoRV32ZdinxLD;
IsScalableVector = false;
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index 6d0952a42eda9f..deb7c8b8435b8b 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -514,8 +514,8 @@ class BranchCC_rri<bits<3> funct3, string opcodestr>
}
let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in {
-class Load_ri<bits<3> funct3, string opcodestr>
- : RVInstI<funct3, OPC_LOAD, (outs GPR:$rd), (ins GPRMem:$rs1, simm12:$imm12),
+class Load_ri<bits<3> funct3, string opcodestr, DAGOperand rty = GPR>
+ : RVInstI<funct3, OPC_LOAD, (outs rty:$rd), (ins GPRMem:$rs1, simm12:$imm12),
opcodestr, "$rd, ${imm12}(${rs1})">;
class HLoad_r<bits<7> funct7, bits<5> funct5, string opcodestr>
@@ -529,9 +529,9 @@ class HLoad_r<bits<7> funct7, bits<5> funct5, string opcodestr>
// reflecting the order these fields are specified in the instruction
// encoding.
let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in {
-class Store_rri<bits<3> funct3, string opcodestr>
+class Store_rri<bits<3> funct3, string opcodestr, DAGOperand rty = GPR>
: RVInstS<funct3, OPC_STORE, (outs),
- (ins GPR:$rs2, GPRMem:$rs1, simm12:$imm12),
+ (ins rty:$rs2, GPRMem:$rs1, simm12:$imm12),
opcodestr, "$rs2, ${imm12}(${rs1})">;
class HStore_rr<bits<7> funct7, string opcodestr>
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoF.td b/llvm/lib/Target/RISCV/RISCVInstrInfoF.td
index 1442bc1cbc4feb..fcc69e8e9c9f57 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoF.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoF.td
@@ -83,15 +83,14 @@ def any_fma_nsz : PatFrag<(ops node:$rs1, node:$rs2, node:$rs3),
// Zfinx
-def GPRAsFPR : AsmOperandClass {
- let Name = "GPRAsFPR";
+def GPRAsFPR32 : AsmOperandClass {
+ let Name = "GPRAsFPR32";
let ParserMethod = "parseGPRAsFPR";
let RenderMethod = "addRegOperands";
}
def FPR32INX : RegisterOperand<GPRF32> {
- let ParserMatchClass = GPRAsFPR;
- let DecoderMethod = "DecodeGPRRegisterClass";
+ let ParserMatchClass = GPRAsFPR32;
}
// Describes a combination of predicates from F/D/Zfh/Zfhmin or
@@ -306,6 +305,12 @@ def FLW : FPLoad_r<0b010, "flw", FPR32, WriteFLD32>;
def FSW : FPStore_r<0b010, "fsw", FPR32, WriteFST32>;
} // Predicates = [HasStdExtF]
+let Predicates = [HasStdExtZfinx], isCodeGenOnly = 1 in {
+def LW_INX : Load_ri<0b010, "lw", GPRF32>, Sched<[WriteLDW, ReadMemBase]>;
+def SW_INX : Store_rri<0b010, "sw", GPRF32>,
+ Sched<[WriteSTW, ReadStoreData, ReadMemBase]>;
+}
+
foreach Ext = FExts in {
let SchedRW = [WriteFMA32, ReadFMA32, ReadFMA32, ReadFMA32Addend] in {
defm FMADD_S : FPFMA_rrr_frm_m<OPC_MADD, 0b00, "fmadd.s", Ext>;
@@ -682,12 +687,10 @@ defm Select_FPR32INX : SelectCC_GPR_rrirr<FPR32INX, f32>;
def PseudoFROUND_S_INX : PseudoFROUND<FPR32INX, f32>;
/// Loads
-def : Pat<(f32 (load (AddrRegImm (XLenVT GPR:$rs1), simm12:$imm12))),
- (COPY_TO_REGCLASS (LW GPR:$rs1, simm12:$imm12), GPRF32)>;
+def : LdPat<load, LW_INX, f32>;
/// Stores
-def : Pat<(store (f32 FPR32INX:$rs2), (AddrRegImm (XLenVT GPR:$rs1), simm12:$imm12)),
- (SW (COPY_TO_REGCLASS FPR32INX:$rs2, GPR), GPR:$rs1, simm12:$imm12)>;
+def : StPat<store, SW_INX, GPRF32, f32>;
} // Predicates = [HasStdExtZfinx]
let Predicates = [HasStdExtF] in {
@@ -698,8 +701,8 @@ def : Pat<(i32 (bitconvert FPR32:$rs1)), (FMV_X_W FPR32:$rs1)>;
let Predicates = [HasStdExtZfinx] in {
// Moves (no conversion)
-def : Pat<(f32 (bitconvert (i32 GPR:$rs1))), (COPY_TO_REGCLASS GPR:$rs1, GPRF32)>;
-def : Pat<(i32 (bitconvert FPR32INX:$rs1)), (COPY_TO_REGCLASS FPR32INX:$rs1, GPR)>;
+def : Pat<(f32 (bitconvert (i32 GPR:$rs1))), (EXTRACT_SUBREG GPR:$rs1, sub_32)>;
+def : Pat<(i32 (bitconvert FPR32INX:$rs1)), (INSERT_SUBREG (XLenVT (IMPLICIT_DEF)), FPR32INX:$rs1, sub_32)>;
} // Predicates = [HasStdExtZfinx]
let Predicates = [HasStdExtF] in {
@@ -778,8 +781,8 @@ def : Pat<(any_uint_to_fp (i64 GPR:$rs1)), (FCVT_S_LU $rs1, FRM_DYN)>;
let Predicates = [HasStdExtZfinx, IsRV64] in {
// Moves (no conversion)
-def : Pat<(riscv_fmv_w_x_rv64 GPR:$src), (COPY_TO_REGCLASS GPR:$src, GPRF32)>;
-def : Pat<(riscv_fmv_x_anyextw_rv64 GPRF32:$src), (COPY_TO_REGCLASS GPRF32:$src, GPR)>;
+def : Pat<(riscv_fmv_w_x_rv64 GPR:$src), (EXTRACT_SUBREG GPR:$src, sub_32)>;
+def : Pat<(riscv_fmv_x_anyextw_rv64 GPRF32:$src), (INSERT_SUBREG (XLenVT (IMPLICIT_DEF)), FPR32INX:$src, sub_32)>;
// Use target specific isd nodes to help us remember the result is sign
// extended. Matching sext_inreg+fptoui/fptosi may cause the conversion to be
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td
index 792cb7fa6dbc2f..0ba0035c7d48fe 100644
--- a/llvm/lib/Tar...
[truncated]
|
417a49d
to
06ed804
Compare
This patches adds a 32 bit register class for use with Zfinx instructions. This makes them more similar to F instructions and allows us to only spill 32 bits. I've added CodeGenOnly instructions for load/store using GPRF32 as that gave better results than insert_subreg/extract_subreg. I'm using FSGNJ for GPRF32 copy with Zfinx as that gave better results from MachineCopyPropagation. Function arguments use this new GPRF32 register class for f32 arguments with Zfinx. Eliminating the need to use RISCVISD::FMV* nodes. This is similar to llvm#107446 which adds a 16 bit register class.
06ed804
to
ec90ba0
Compare
Co-authored-by: Yingwei Zheng <[email protected]>
Co-authored-by: Yingwei Zheng <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Please wait for additional approval from other reviewers :)
Co-authored-by: Yingwei Zheng <[email protected]>
Co-authored-by: Yingwei Zheng <[email protected]>
✅ With the latest revision this PR passed the C/C++ code formatter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
static const MCPhysReg ArgIGPRs[] = {RISCV::X10_W, RISCV::X11_W, RISCV::X12_W, | ||
RISCV::X13_W, RISCV::X14_W, RISCV::X15_W, | ||
RISCV::X16_W, RISCV::X17_W}; | ||
// The GPRs used for passing arguments in the ILP32E/ILP64E ABI. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ILP64E => LP64E
if ((LocVT == MVT::f32 && Subtarget.hasStdExtZfinx()) || | ||
(LocVT == MVT::f64 && Subtarget.hasStdExtZdinx() && | ||
Subtarget.is64Bit())) { | ||
if (LocVT == MVT::f32 && Subtarget.hasStdExtZfinx()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really an issue for this review directly, but I wonder if we should be more aggressive about erroring out of the GHC calling convention for more obscure targets that are unlikely to ever need it. Is the ghc cc realistically ever going to be needed on a zfinx/zdinx system?
Change looks fine though.
This patches adds a 32 bit register class for use with Zfinx instructions. This makes them more similar to F instructions and allows us to only spill 32 bits. I've added CodeGenOnly instructions for load/store using GPRF32 as that gave better results than insert_subreg/extract_subreg. Function arguments use this new GPRF32 register class for f32 arguments with Zfinx. Eliminating the need to use RISCVISD::FMV* nodes. This is similar to llvm#107446 which adds a 16 bit register class.
This patches adds a 32 bit register class for use with Zfinx instructions.
This makes them more similar to F instructions and allows us to
only spill 32 bits.
I've added CodeGenOnly instructions for load/store using GPRF32 as that
gave better results than insert_subreg/extract_subreg. I'm using FSGNJ for
GPRF32 copy with Zfinx as that gave better results from MachineCopyPropagation.
Function arguments use this new GPRF32 register class for f32 arguments
with Zfinx. Eliminating the need to use RISCVISD::FMV* nodes.
This is similar to #107446 which adds a 16 bit register class.