-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[RISCV][GISel] Use CCValAssign::getCustomReg for converting f16/f32<->GPR. #105700
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
…>GPR. This gives us much better control of the generated code for GISel. I've added G_ versions of our SelectionDAG ISD nodes to make it better match what SelectionDAG generates. This prevents generating copies between register classes of different sizes. SelectionDAG now checks needsCustom() instead of detecting the special cases in the Bitcast handler. Unfortunately, IRTranslator for bitcast still generates copies between register classes of different sizes. Because of this we can't handle i16<->f16 bitcasts without crashing. Not sure if I should teach RISCVInstrInfo::copyPhysReg to allow copies between FPR16 and GPR or if I should convert the copies to instructions in GISel.
@llvm/pr-subscribers-backend-risc-v @llvm/pr-subscribers-llvm-globalisel Author: Craig Topper (topperc) ChangesThis gives us much better control of the generated code for GISel. I've added G_ versions of our SelectionDAG ISD nodes to make it better match what SelectionDAG generates. This prevents generating copies between register classes of different sizes. SelectionDAG now checks needsCustom() instead of detecting the special cases in the Bitcast handler. Unfortunately, IRTranslator for bitcast still generates copies between register classes of different sizes. Because of this we can't handle i16<->f16 bitcasts without crashing. Not sure if I should teach RISCVInstrInfo::copyPhysReg to allow copies between FPR16 and GPR or if I should convert the copies to instructions in GISel. Patch is 24.87 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/105700.diff 6 Files Affected:
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVCallLowering.cpp b/llvm/lib/Target/RISCV/GISel/RISCVCallLowering.cpp
index b274a8fc45c5ce..84e6659f3fc994 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVCallLowering.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVCallLowering.cpp
@@ -103,15 +103,6 @@ struct RISCVOutgoingValueHandler : public CallLowering::OutgoingValueHandler {
void assignValueToReg(Register ValVReg, Register PhysReg,
const CCValAssign &VA) override {
- // If we're passing a smaller fp value into a larger integer register,
- // anyextend before copying.
- if ((VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32) ||
- ((VA.getLocVT() == MVT::i32 || VA.getLocVT() == MVT::i64) &&
- VA.getValVT() == MVT::f16)) {
- LLT DstTy = LLT::scalar(VA.getLocVT().getSizeInBits());
- ValVReg = MIRBuilder.buildAnyExt(DstTy, ValVReg).getReg(0);
- }
-
Register ExtReg = extendRegister(ValVReg, VA);
MIRBuilder.buildCopy(PhysReg, ExtReg);
MIB.addUse(PhysReg, RegState::Implicit);
@@ -120,16 +111,40 @@ struct RISCVOutgoingValueHandler : public CallLowering::OutgoingValueHandler {
unsigned assignCustomValue(CallLowering::ArgInfo &Arg,
ArrayRef<CCValAssign> VAs,
std::function<void()> *Thunk) override {
+ const CCValAssign &VA = VAs[0];
+ if ((VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32) ||
+ (VA.getLocVT().isInteger() && VA.getValVT() == MVT::f16)) {
+ Register PhysReg = VA.getLocReg();
+
+ LLT LocTy(VA.getLocVT());
+ unsigned Opc = VA.getValVT() == MVT::f32 ? RISCV::G_FMV_X_ANYEXTW_RV64
+ : RISCV::G_FMV_X_ANYEXTH;
+
+ auto assignFunc = [=]() {
+ auto Fmv = MIRBuilder.buildInstr(Opc, {LocTy}, {Arg.Regs[0]});
+ Register NewReg = Fmv.getReg(0);
+ MIRBuilder.buildCopy(PhysReg, NewReg);
+ MIB.addUse(PhysReg, RegState::Implicit);
+ };
+
+ if (Thunk) {
+ *Thunk = assignFunc;
+ return 1;
+ }
+
+ assignFunc();
+ return 1;
+ }
+
assert(VAs.size() >= 2 && "Expected at least 2 VAs.");
- const CCValAssign &VALo = VAs[0];
const CCValAssign &VAHi = VAs[1];
assert(VAHi.needsCustom() && "Value doesn't need custom handling");
- assert(VALo.getValNo() == VAHi.getValNo() &&
+ assert(VA.getValNo() == VAHi.getValNo() &&
"Values belong to different arguments");
- assert(VALo.getLocVT() == MVT::i32 && VAHi.getLocVT() == MVT::i32 &&
- VALo.getValVT() == MVT::f64 && VAHi.getValVT() == MVT::f64 &&
+ assert(VA.getLocVT() == MVT::i32 && VAHi.getLocVT() == MVT::i32 &&
+ VA.getValVT() == MVT::f64 && VAHi.getValVT() == MVT::f64 &&
"unexpected custom value");
Register NewRegs[] = {MRI.createGenericVirtualRegister(LLT::scalar(32)),
@@ -148,7 +163,7 @@ struct RISCVOutgoingValueHandler : public CallLowering::OutgoingValueHandler {
}
auto assignFunc = [=]() {
- assignValueToReg(NewRegs[0], VALo.getLocReg(), VALo);
+ assignValueToReg(NewRegs[0], VA.getLocReg(), VA);
if (VAHi.isRegLoc())
assignValueToReg(NewRegs[1], VAHi.getLocReg(), VAHi);
};
@@ -246,16 +261,31 @@ struct RISCVIncomingValueHandler : public CallLowering::IncomingValueHandler {
unsigned assignCustomValue(CallLowering::ArgInfo &Arg,
ArrayRef<CCValAssign> VAs,
std::function<void()> *Thunk) override {
+ const CCValAssign &VA = VAs[0];
+ if ((VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32) ||
+ (VA.getLocVT().isInteger() && VA.getValVT() == MVT::f16)) {
+ Register PhysReg = VA.getLocReg();
+
+ markPhysRegUsed(PhysReg);
+
+ LLT LocTy(VA.getLocVT());
+ auto Copy = MIRBuilder.buildCopy(LocTy, PhysReg);
+
+ unsigned Opc =
+ VA.getValVT() == MVT::f32 ? RISCV::G_FMV_W_X_RV64 : RISCV::G_FMV_H_X;
+ MIRBuilder.buildInstr(Opc, {Arg.Regs[0]}, {Copy.getReg(0)});
+ return 1;
+ }
+
assert(VAs.size() >= 2 && "Expected at least 2 VAs.");
- const CCValAssign &VALo = VAs[0];
const CCValAssign &VAHi = VAs[1];
assert(VAHi.needsCustom() && "Value doesn't need custom handling");
- assert(VALo.getValNo() == VAHi.getValNo() &&
+ assert(VA.getValNo() == VAHi.getValNo() &&
"Values belong to different arguments");
- assert(VALo.getLocVT() == MVT::i32 && VAHi.getLocVT() == MVT::i32 &&
- VALo.getValVT() == MVT::f64 && VAHi.getValVT() == MVT::f64 &&
+ assert(VA.getLocVT() == MVT::i32 && VAHi.getLocVT() == MVT::i32 &&
+ VA.getValVT() == MVT::f64 && VAHi.getValVT() == MVT::f64 &&
"unexpected custom value");
Register NewRegs[] = {MRI.createGenericVirtualRegister(LLT::scalar(32)),
@@ -272,7 +302,7 @@ struct RISCVIncomingValueHandler : public CallLowering::IncomingValueHandler {
const_cast<CCValAssign &>(VAHi));
}
- assignValueToReg(NewRegs[0], VALo.getLocReg(), VALo);
+ assignValueToReg(NewRegs[0], VA.getLocReg(), VA);
if (VAHi.isRegLoc())
assignValueToReg(NewRegs[1], VAHi.getLocReg(), VAHi);
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
index 5369be24f0e7cb..7c6b7f69b0ec5b 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
@@ -434,6 +434,8 @@ RISCVRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
}
case TargetOpcode::G_FPTOSI:
case TargetOpcode::G_FPTOUI:
+ case RISCV::G_FMV_X_ANYEXTW_RV64:
+ case RISCV::G_FMV_X_ANYEXTH:
case RISCV::G_FCLASS: {
LLT Ty = MRI.getType(MI.getOperand(1).getReg());
OpdsMapping[0] = GPRValueMapping;
@@ -441,7 +443,9 @@ RISCVRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
break;
}
case TargetOpcode::G_SITOFP:
- case TargetOpcode::G_UITOFP: {
+ case TargetOpcode::G_UITOFP:
+ case RISCV::G_FMV_W_X_RV64:
+ case RISCV::G_FMV_H_X: {
LLT Ty = MRI.getType(MI.getOperand(0).getReg());
OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());
OpdsMapping[1] = GPRValueMapping;
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 670dee2edb1dfb..6120336ea50675 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -18672,6 +18672,19 @@ bool RISCV::CC_RISCV(const DataLayout &DL, RISCVABI::ABI ABI, unsigned ValNo,
// similar local variables rather than directly checking against the target
// ABI.
+ ArrayRef<MCPhysReg> ArgGPRs = RISCV::getArgGPRs(ABI);
+
+ if (UseGPRForF16_F32 && (ValVT == MVT::f16 || ValVT == MVT::bf16 ||
+ (ValVT == MVT::f32 && XLen == 64))) {
+ Register Reg = State.AllocateReg(ArgGPRs);
+ if (Reg) {
+ LocVT = XLenVT;
+ State.addLoc(
+ CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
+ return false;
+ }
+ }
+
if (UseGPRForF16_F32 &&
(ValVT == MVT::f16 || ValVT == MVT::bf16 || ValVT == MVT::f32)) {
LocVT = XLenVT;
@@ -18681,8 +18694,6 @@ bool RISCV::CC_RISCV(const DataLayout &DL, RISCVABI::ABI ABI, unsigned ValNo,
LocInfo = CCValAssign::BCvt;
}
- ArrayRef<MCPhysReg> ArgGPRs = RISCV::getArgGPRs(ABI);
-
// If this is a variadic argument, the RISC-V calling convention requires
// that it is assigned an 'even' or 'aligned' register if it has 8-byte
// alignment (RV32) or 16-byte alignment (RV64). An aligned register should
@@ -18938,6 +18949,17 @@ void RISCVTargetLowering::analyzeOutputArgs(
static SDValue convertLocVTToValVT(SelectionDAG &DAG, SDValue Val,
const CCValAssign &VA, const SDLoc &DL,
const RISCVSubtarget &Subtarget) {
+ if (VA.needsCustom()) {
+ if (VA.getLocVT().isInteger() &&
+ (VA.getValVT() == MVT::f16 || VA.getValVT() == MVT::bf16))
+ Val = DAG.getNode(RISCVISD::FMV_H_X, DL, VA.getValVT(), Val);
+ else if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
+ Val = DAG.getNode(RISCVISD::FMV_W_X_RV64, DL, MVT::f32, Val);
+ else
+ llvm_unreachable("Unexpected Custom handling.");
+ return Val;
+ }
+
switch (VA.getLocInfo()) {
default:
llvm_unreachable("Unexpected CCValAssign::LocInfo");
@@ -18946,14 +18968,7 @@ static SDValue convertLocVTToValVT(SelectionDAG &DAG, SDValue Val,
Val = convertFromScalableVector(VA.getValVT(), Val, DAG, Subtarget);
break;
case CCValAssign::BCvt:
- if (VA.getLocVT().isInteger() &&
- (VA.getValVT() == MVT::f16 || VA.getValVT() == MVT::bf16)) {
- Val = DAG.getNode(RISCVISD::FMV_H_X, DL, VA.getValVT(), Val);
- } else if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32) {
- Val = DAG.getNode(RISCVISD::FMV_W_X_RV64, DL, MVT::f32, Val);
- } else {
- Val = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Val);
- }
+ Val = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Val);
break;
}
return Val;
@@ -18999,6 +19014,17 @@ static SDValue convertValVTToLocVT(SelectionDAG &DAG, SDValue Val,
const RISCVSubtarget &Subtarget) {
EVT LocVT = VA.getLocVT();
+ if (VA.needsCustom()) {
+ if (LocVT.isInteger() &&
+ (VA.getValVT() == MVT::f16 || VA.getValVT() == MVT::bf16))
+ Val = DAG.getNode(RISCVISD::FMV_X_ANYEXTH, DL, LocVT, Val);
+ else if (LocVT == MVT::i64 && VA.getValVT() == MVT::f32)
+ Val = DAG.getNode(RISCVISD::FMV_X_ANYEXTW_RV64, DL, MVT::i64, Val);
+ else
+ llvm_unreachable("Unexpected Custom handling.");
+ return Val;
+ }
+
switch (VA.getLocInfo()) {
default:
llvm_unreachable("Unexpected CCValAssign::LocInfo");
@@ -19007,14 +19033,7 @@ static SDValue convertValVTToLocVT(SelectionDAG &DAG, SDValue Val,
Val = convertToScalableVector(LocVT, Val, DAG, Subtarget);
break;
case CCValAssign::BCvt:
- if (LocVT.isInteger() &&
- (VA.getValVT() == MVT::f16 || VA.getValVT() == MVT::bf16)) {
- Val = DAG.getNode(RISCVISD::FMV_X_ANYEXTH, DL, LocVT, Val);
- } else if (LocVT == MVT::i64 && VA.getValVT() == MVT::f32) {
- Val = DAG.getNode(RISCVISD::FMV_X_ANYEXTW_RV64, DL, MVT::i64, Val);
- } else {
- Val = DAG.getNode(ISD::BITCAST, DL, LocVT, Val);
- }
+ Val = DAG.getNode(ISD::BITCAST, DL, LocVT, Val);
break;
}
return Val;
@@ -19793,9 +19812,8 @@ SDValue RISCVTargetLowering::LowerCall(CallLoweringInfo &CLI,
Glue = RetValue2.getValue(2);
RetValue = DAG.getNode(RISCVISD::BuildPairF64, DL, MVT::f64, RetValue,
RetValue2);
- }
-
- RetValue = convertLocVTToValVT(DAG, RetValue, VA, DL, Subtarget);
+ } else
+ RetValue = convertLocVTToValVT(DAG, RetValue, VA, DL, Subtarget);
InVals.push_back(RetValue);
}
diff --git a/llvm/lib/Target/RISCV/RISCVInstrGISel.td b/llvm/lib/Target/RISCV/RISCVInstrGISel.td
index ba40662c49c1df..ca58daa793b75b 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrGISel.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrGISel.td
@@ -17,6 +17,34 @@ class RISCVGenericInstruction : GenericInstruction {
let Namespace = "RISCV";
}
+def G_FMV_X_ANYEXTW_RV64 : RISCVGenericInstruction {
+ let OutOperandList = (outs unknown:$dst);
+ let InOperandList = (ins unknown:$src);
+ let hasSideEffects = false;
+}
+def : GINodeEquiv<G_FMV_X_ANYEXTW_RV64, riscv_fmv_x_anyextw_rv64>;
+
+def G_FMV_X_ANYEXTH : RISCVGenericInstruction {
+ let OutOperandList = (outs unknown:$dst);
+ let InOperandList = (ins unknown:$src);
+ let hasSideEffects = false;
+}
+def : GINodeEquiv<G_FMV_X_ANYEXTH, riscv_fmv_x_anyexth>;
+
+def G_FMV_W_X_RV64 : RISCVGenericInstruction {
+ let OutOperandList = (outs unknown:$dst);
+ let InOperandList = (ins unknown:$src);
+ let hasSideEffects = false;
+}
+def : GINodeEquiv<G_FMV_W_X_RV64, riscv_fmv_w_x_rv64>;
+
+def G_FMV_H_X : RISCVGenericInstruction {
+ let OutOperandList = (outs unknown:$dst);
+ let InOperandList = (ins unknown:$src);
+ let hasSideEffects = false;
+}
+def : GINodeEquiv<G_FMV_H_X, riscv_fmv_h_x>;
+
// Pseudo equivalent to a RISCVISD::FCLASS.
def G_FCLASS : RISCVGenericInstruction {
let OutOperandList = (outs type0:$dst);
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-half.ll b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-half.ll
index 04fa62b1950763..de1f005dcb841d 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-half.ll
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-half.ll
@@ -780,8 +780,8 @@ define half @callee_half_return_stack2(half %v1, half %v2, half %v3, half %v4, h
; RV32IZFH-NEXT: [[COPY6:%[0-9]+]]:_(s16) = COPY $f16_h
; RV32IZFH-NEXT: [[COPY7:%[0-9]+]]:_(s16) = COPY $f17_h
; RV32IZFH-NEXT: [[COPY8:%[0-9]+]]:_(s32) = COPY $x10
- ; RV32IZFH-NEXT: [[TRUNC:%[0-9]+]]:_(s16) = G_TRUNC [[COPY8]](s32)
- ; RV32IZFH-NEXT: $f10_h = COPY [[TRUNC]](s16)
+ ; RV32IZFH-NEXT: [[FMV_H_X:%[0-9]+]]:_(s16) = G_FMV_H_X [[COPY8]](s32)
+ ; RV32IZFH-NEXT: $f10_h = COPY [[FMV_H_X]](s16)
; RV32IZFH-NEXT: PseudoRET implicit $f10_h
;
; RV64I-LABEL: name: callee_half_return_stack2
@@ -832,8 +832,8 @@ define half @callee_half_return_stack2(half %v1, half %v2, half %v3, half %v4, h
; RV64IF-NEXT: [[COPY7:%[0-9]+]]:_(s32) = COPY $f17_f
; RV64IF-NEXT: [[TRUNC7:%[0-9]+]]:_(s16) = G_TRUNC [[COPY7]](s32)
; RV64IF-NEXT: [[COPY8:%[0-9]+]]:_(s64) = COPY $x10
- ; RV64IF-NEXT: [[TRUNC8:%[0-9]+]]:_(s16) = G_TRUNC [[COPY8]](s64)
- ; RV64IF-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[TRUNC8]](s16)
+ ; RV64IF-NEXT: [[FMV_W_X_RV64_:%[0-9]+]]:_(s16) = G_FMV_W_X_RV64 [[COPY8]](s64)
+ ; RV64IF-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[FMV_W_X_RV64_]](s16)
; RV64IF-NEXT: $f10_f = COPY [[ANYEXT]](s32)
; RV64IF-NEXT: PseudoRET implicit $f10_f
;
@@ -850,8 +850,8 @@ define half @callee_half_return_stack2(half %v1, half %v2, half %v3, half %v4, h
; RV64IZFH-NEXT: [[COPY6:%[0-9]+]]:_(s16) = COPY $f16_h
; RV64IZFH-NEXT: [[COPY7:%[0-9]+]]:_(s16) = COPY $f17_h
; RV64IZFH-NEXT: [[COPY8:%[0-9]+]]:_(s64) = COPY $x10
- ; RV64IZFH-NEXT: [[TRUNC:%[0-9]+]]:_(s16) = G_TRUNC [[COPY8]](s64)
- ; RV64IZFH-NEXT: $f10_h = COPY [[TRUNC]](s16)
+ ; RV64IZFH-NEXT: [[FMV_H_X:%[0-9]+]]:_(s16) = G_FMV_H_X [[COPY8]](s64)
+ ; RV64IZFH-NEXT: $f10_h = COPY [[FMV_H_X]](s16)
; RV64IZFH-NEXT: PseudoRET implicit $f10_h
ret half %x
}
@@ -951,8 +951,8 @@ define half @caller_half_return_stack2(half %x, half %y) nounwind {
; RV32IZFH-NEXT: $f15_h = COPY [[COPY1]](s16)
; RV32IZFH-NEXT: $f16_h = COPY [[COPY1]](s16)
; RV32IZFH-NEXT: $f17_h = COPY [[COPY1]](s16)
- ; RV32IZFH-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[COPY]](s16)
- ; RV32IZFH-NEXT: $x10 = COPY [[ANYEXT]](s32)
+ ; RV32IZFH-NEXT: [[FMV_X_ANYEXTH:%[0-9]+]]:_(s32) = G_FMV_X_ANYEXTH [[COPY]](s16)
+ ; RV32IZFH-NEXT: $x10 = COPY [[FMV_X_ANYEXTH]](s32)
; RV32IZFH-NEXT: PseudoCALL target-flags(riscv-call) @callee_half_return_stack2, csr_ilp32f_lp64f, implicit-def $x1, implicit $f10_h, implicit $f11_h, implicit $f12_h, implicit $f13_h, implicit $f14_h, implicit $f15_h, implicit $f16_h, implicit $f17_h, implicit $x10, implicit-def $f10_h
; RV32IZFH-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $x2, implicit $x2
; RV32IZFH-NEXT: [[COPY2:%[0-9]+]]:_(s16) = COPY $f10_h
@@ -1018,7 +1018,6 @@ define half @caller_half_return_stack2(half %x, half %y) nounwind {
; RV64IF-NEXT: [[ANYEXT5:%[0-9]+]]:_(s32) = G_ANYEXT [[TRUNC1]](s16)
; RV64IF-NEXT: [[ANYEXT6:%[0-9]+]]:_(s32) = G_ANYEXT [[TRUNC1]](s16)
; RV64IF-NEXT: [[ANYEXT7:%[0-9]+]]:_(s32) = G_ANYEXT [[TRUNC1]](s16)
- ; RV64IF-NEXT: [[ANYEXT8:%[0-9]+]]:_(s32) = G_ANYEXT [[TRUNC]](s16)
; RV64IF-NEXT: $f10_f = COPY [[ANYEXT]](s32)
; RV64IF-NEXT: $f11_f = COPY [[ANYEXT1]](s32)
; RV64IF-NEXT: $f12_f = COPY [[ANYEXT2]](s32)
@@ -1027,14 +1026,14 @@ define half @caller_half_return_stack2(half %x, half %y) nounwind {
; RV64IF-NEXT: $f15_f = COPY [[ANYEXT5]](s32)
; RV64IF-NEXT: $f16_f = COPY [[ANYEXT6]](s32)
; RV64IF-NEXT: $f17_f = COPY [[ANYEXT7]](s32)
- ; RV64IF-NEXT: [[ANYEXT9:%[0-9]+]]:_(s64) = G_ANYEXT [[ANYEXT8]](s32)
- ; RV64IF-NEXT: $x10 = COPY [[ANYEXT9]](s64)
+ ; RV64IF-NEXT: [[FMV_X_ANYEXTW_RV64_:%[0-9]+]]:_(s64) = G_FMV_X_ANYEXTW_RV64 [[TRUNC]](s16)
+ ; RV64IF-NEXT: $x10 = COPY [[FMV_X_ANYEXTW_RV64_]](s64)
; RV64IF-NEXT: PseudoCALL target-flags(riscv-call) @callee_half_return_stack2, csr_ilp32f_lp64f, implicit-def $x1, implicit $f10_f, implicit $f11_f, implicit $f12_f, implicit $f13_f, implicit $f14_f, implicit $f15_f, implicit $f16_f, implicit $f17_f, implicit $x10, implicit-def $f10_f
; RV64IF-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $x2, implicit $x2
; RV64IF-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $f10_f
; RV64IF-NEXT: [[TRUNC2:%[0-9]+]]:_(s16) = G_TRUNC [[COPY2]](s32)
- ; RV64IF-NEXT: [[ANYEXT10:%[0-9]+]]:_(s32) = G_ANYEXT [[TRUNC2]](s16)
- ; RV64IF-NEXT: $f10_f = COPY [[ANYEXT10]](s32)
+ ; RV64IF-NEXT: [[ANYEXT8:%[0-9]+]]:_(s32) = G_ANYEXT [[TRUNC2]](s16)
+ ; RV64IF-NEXT: $f10_f = COPY [[ANYEXT8]](s32)
; RV64IF-NEXT: PseudoRET implicit $f10_f
;
; RV64IZFH-LABEL: name: caller_half_return_stack2
@@ -1054,8 +1053,8 @@ define half @caller_half_return_stack2(half %x, half %y) nounwind {
; RV64IZFH-NEXT: $f15_h = COPY [[COPY1]](s16)
; RV64IZFH-NEXT: $f16_h = COPY [[COPY1]](s16)
; RV64IZFH-NEXT: $f17_h = COPY [[COPY1]](s16)
- ; RV64IZFH-NEXT: [[ANYEXT:%[0-9]+]]:_(s64) = G_ANYEXT [[COPY]](s16)
- ; RV64IZFH-NEXT: $x10 = COPY [[ANYEXT]](s64)
+ ; RV64IZFH-NEXT: [[FMV_X_ANYEXTH:%[0-9]+]]:_(s64) = G_FMV_X_ANYEXTH [[COPY]](s16)
+ ; RV64IZFH-NEXT: $x10 = COPY [[FMV_X_ANYEXTH]](s64)
; RV64IZFH-NEXT: PseudoCALL target-flags(riscv-call) @callee_half_return_stack2, csr_ilp32f_lp64f, implicit-def $x1, implicit $f10_h, implicit $f11_h, implicit $f12_h, implicit $f13_h, implicit $f14_h, implicit $f15_h, implicit $f16_h, implicit $f17_h, implicit $x10, implicit-def $f10_h
; RV64IZFH-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $x2, implicit $x2
; RV64IZFH-NEXT: [[COPY2:%[0-9]+]]:_(s16) = COPY $f10_h
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-lp64.ll b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-lp64.ll
index 9283f1f090ed55..bbcb5bea17ab1a 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-lp64.ll
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-lp64.ll
@@ -1,10 +1,10 @@
; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 3
; RUN: llc -mtriple=riscv64 -global-isel -stop-after=irtranslator \
; RUN: -verify-machineinstrs < %s \
-; RUN: | FileCheck -check-prefixes=RV64,RV64I %s
+; RUN: | FileCheck -check-prefixes=RV64I %s
; RUN: llc -mtriple=riscv64 -mattr=+f -target-abi=lp64 \
; RUN: -global-isel -stop-after=irtranslator -verify-machineinstrs < %s \
-; RUN: | FileCheck -check-prefixes=RV64,RV64F %s
+; RUN: | FileCheck -check-prefixes=RV64F %s
; Any tests that would have identical output for some combination of the lp64*
; ABIs belong in calling-conv-*-common.ll. This file contains tests that will
@@ -12,17 +12,29 @@
; passed according to the floating point ABI.
define i64 @callee_float_in_regs(i64 %a, float %b) nounwind {
- ; RV64-LABEL: name: callee_float_in_regs
- ; RV64: bb.1 (%ir-block.0):
- ; RV64-NEXT: liveins: $x10, $x11
- ; RV64-NEXT: {{ $}}
- ; RV64-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x10
- ; RV64-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x11
- ; RV64-NEXT: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC [[COPY1]](s64)
- ; RV64-NEXT: [[FPTOSI:%[0-9]+]]:_(s64) = G_FPTOSI [[TRUNC]](s32)
- ; RV64-NEXT: [[ADD:%[0-9]+]]:_(s64) = G_ADD [[COPY]], [[FPTOSI]]
- ; RV64-NEXT: $x10 = COPY [[ADD]](s64)
- ; RV64-NEXT: PseudoRET implicit $x10
+ ; RV64I-LABEL: name: callee_float_in_regs
+ ; RV64I: bb.1 (%ir-block.0):
+ ; RV64I-NEXT: liveins: $x10, $x11
+ ; RV64I-NEXT: {{ $}}
+ ; RV64I-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x10
+ ; RV64I-NEXT...
[truncated]
|
What kind of code is required to emit such a copy? I'd assume that could be directly handled in copyPhysReg. As as a side note, it's deeply annoying that the CC lowering code operates on legalized types and not the raw IR type |
It's just one instruction. I've just never found much evidence that other targets have mismatched copy sizes in copyPhysReg. |
I've remove the new G_ instructions for GISel and tried to match the original code. I feel like Custom is the right way to describe this for SelectionDAG. There's some additional cleanup that can be done in RISCVISelLowering, but I think it's easier to review without adding more changes. |
@@ -246,16 +256,29 @@ struct RISCVIncomingValueHandler : public CallLowering::IncomingValueHandler { | |||
unsigned assignCustomValue(CallLowering::ArgInfo &Arg, | |||
ArrayRef<CCValAssign> VAs, | |||
std::function<void()> *Thunk) override { | |||
const CCValAssign &VA = VAs[0]; | |||
if ((VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32) || | |||
(VA.getLocVT().isInteger() && VA.getValVT() == MVT::f16)) { |
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.
maybe consider bfloat but I guess that's totally busted in globalisel anyway
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.
I'll do it as a separate patch. I don't think it belongs in this one.
Ping |
Ping |
This gives us much better control of the generated code for GISel. I've tried to closely match the current gisel code, but it looks like we had 2 layers of G_ANYEXT in some cases before.
SelectionDAG now checks needsCustom() instead of detecting the special cases in the Bitcast handler.
Unfortunately, IRTranslator for bitcast still generates copies between register classes of different sizes. Because of this we can't handle i16<->f16 bitcasts without crashing. Not sure if I should teach RISCVInstrInfo::copyPhysReg to allow copies between FPR16 and GPR or if I should convert the copies to instructions in GISel.