Skip to content

Commit c6aca6d

Browse files
asbDisasm
authored andcommitted
[RISCV] Add RV64F codegen support
This requires a little extra work due tothe fact i32 is not a legal type. When call lowering happens post-legalisation (e.g. when an intrinsic was inserted during legalisation). A bitcast from f32 to i32 can't be introduced. This is similar to the challenges with RV32D. To handle this, we introduce target-specific DAG nodes that perform bitcast+anyext for f32->i64 and trunc+bitcast for i64->f32. Differential Revision: https://reviews.llvm.org/D53235 llvm-svn: 352807
1 parent 1548150 commit c6aca6d

13 files changed

+1466
-2
lines changed

llvm/lib/Target/RISCV/RISCVISelLowering.cpp

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
138138
setOperationAction(Op, MVT::f32, Expand);
139139
}
140140

141+
if (Subtarget.hasStdExtF() && Subtarget.is64Bit())
142+
setOperationAction(ISD::BITCAST, MVT::i32, Custom);
143+
141144
if (Subtarget.hasStdExtD()) {
142145
setOperationAction(ISD::FMINNUM, MVT::f64, Legal);
143146
setOperationAction(ISD::FMAXNUM, MVT::f64, Legal);
@@ -339,6 +342,17 @@ SDValue RISCVTargetLowering::LowerOperation(SDValue Op,
339342
return lowerFRAMEADDR(Op, DAG);
340343
case ISD::RETURNADDR:
341344
return lowerRETURNADDR(Op, DAG);
345+
case ISD::BITCAST: {
346+
assert(Subtarget.is64Bit() && Subtarget.hasStdExtF() &&
347+
"Unexpected custom legalisation");
348+
SDLoc DL(Op);
349+
SDValue Op0 = Op.getOperand(0);
350+
if (Op.getValueType() != MVT::f32 || Op0.getValueType() != MVT::i32)
351+
return SDValue();
352+
SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op0);
353+
SDValue FPConv = DAG.getNode(RISCVISD::FMV_W_X_RV64, DL, MVT::f32, NewOp0);
354+
return FPConv;
355+
}
342356
}
343357
}
344358

@@ -580,6 +594,18 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N,
580594
return;
581595
Results.push_back(customLegalizeToWOp(N, DAG));
582596
break;
597+
case ISD::BITCAST: {
598+
assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() &&
599+
Subtarget.hasStdExtF() && "Unexpected custom legalisation");
600+
SDLoc DL(N);
601+
SDValue Op0 = N->getOperand(0);
602+
if (Op0.getValueType() != MVT::f32)
603+
return;
604+
SDValue FPConv =
605+
DAG.getNode(RISCVISD::FMV_X_ANYEXTW_RV64, DL, MVT::i64, Op0);
606+
Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, FPConv));
607+
break;
608+
}
583609
}
584610
}
585611

@@ -634,6 +660,38 @@ SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N,
634660
return SDValue();
635661
break;
636662
}
663+
case RISCVISD::FMV_X_ANYEXTW_RV64: {
664+
SDLoc DL(N);
665+
SDValue Op0 = N->getOperand(0);
666+
// If the input to FMV_X_ANYEXTW_RV64 is just FMV_W_X_RV64 then the
667+
// conversion is unnecessary and can be replaced with an ANY_EXTEND
668+
// of the FMV_W_X_RV64 operand.
669+
if (Op0->getOpcode() == RISCVISD::FMV_W_X_RV64) {
670+
SDValue AExtOp =
671+
DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op0.getOperand(0));
672+
return DCI.CombineTo(N, AExtOp);
673+
}
674+
675+
// This is a target-specific version of a DAGCombine performed in
676+
// DAGCombiner::visitBITCAST. It performs the equivalent of:
677+
// fold (bitconvert (fneg x)) -> (xor (bitconvert x), signbit)
678+
// fold (bitconvert (fabs x)) -> (and (bitconvert x), (not signbit))
679+
if (!(Op0.getOpcode() == ISD::FNEG || Op0.getOpcode() == ISD::FABS) ||
680+
!Op0.getNode()->hasOneUse())
681+
break;
682+
SDValue NewFMV = DAG.getNode(RISCVISD::FMV_X_ANYEXTW_RV64, DL, MVT::i64,
683+
Op0.getOperand(0));
684+
APInt SignBit = APInt::getSignMask(32).sext(64);
685+
if (Op0.getOpcode() == ISD::FNEG) {
686+
return DCI.CombineTo(N,
687+
DAG.getNode(ISD::XOR, DL, MVT::i64, NewFMV,
688+
DAG.getConstant(SignBit, DL, MVT::i64)));
689+
}
690+
assert(Op0.getOpcode() == ISD::FABS);
691+
return DCI.CombineTo(N,
692+
DAG.getNode(ISD::AND, DL, MVT::i64, NewFMV,
693+
DAG.getConstant(~SignBit, DL, MVT::i64)));
694+
}
637695
}
638696

639697
return SDValue();
@@ -875,7 +933,7 @@ static bool CC_RISCV(const DataLayout &DL, unsigned ValNo, MVT ValVT, MVT LocVT,
875933
assert(XLen == 32 || XLen == 64);
876934
MVT XLenVT = XLen == 32 ? MVT::i32 : MVT::i64;
877935
if (ValVT == MVT::f32) {
878-
LocVT = MVT::i32;
936+
LocVT = XLenVT;
879937
LocInfo = CCValAssign::BCvt;
880938
}
881939

@@ -1048,6 +1106,10 @@ static SDValue convertLocVTToValVT(SelectionDAG &DAG, SDValue Val,
10481106
case CCValAssign::Full:
10491107
break;
10501108
case CCValAssign::BCvt:
1109+
if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32) {
1110+
Val = DAG.getNode(RISCVISD::FMV_W_X_RV64, DL, MVT::f32, Val);
1111+
break;
1112+
}
10511113
Val = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Val);
10521114
break;
10531115
}
@@ -1083,6 +1145,10 @@ static SDValue convertValVTToLocVT(SelectionDAG &DAG, SDValue Val,
10831145
case CCValAssign::Full:
10841146
break;
10851147
case CCValAssign::BCvt:
1148+
if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32) {
1149+
Val = DAG.getNode(RISCVISD::FMV_X_ANYEXTW_RV64, DL, MVT::i64, Val);
1150+
break;
1151+
}
10861152
Val = DAG.getNode(ISD::BITCAST, DL, LocVT, Val);
10871153
break;
10881154
}
@@ -1109,9 +1175,12 @@ static SDValue unpackFromMemLoc(SelectionDAG &DAG, SDValue Chain,
11091175
llvm_unreachable("Unexpected CCValAssign::LocInfo");
11101176
case CCValAssign::Full:
11111177
case CCValAssign::Indirect:
1178+
case CCValAssign::BCvt:
11121179
ExtType = ISD::NON_EXTLOAD;
11131180
break;
11141181
}
1182+
if (ValVT == MVT::f32)
1183+
LocVT = MVT::f32;
11151184
Val = DAG.getExtLoad(
11161185
ExtType, DL, LocVT, Chain, FIN,
11171186
MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI), ValVT);
@@ -1760,6 +1829,10 @@ const char *RISCVTargetLowering::getTargetNodeName(unsigned Opcode) const {
17601829
return "RISCVISD::DIVUW";
17611830
case RISCVISD::REMUW:
17621831
return "RISCVISD::REMUW";
1832+
case RISCVISD::FMV_W_X_RV64:
1833+
return "RISCVISD::FMV_W_X_RV64";
1834+
case RISCVISD::FMV_X_ANYEXTW_RV64:
1835+
return "RISCVISD::FMV_X_ANYEXTW_RV64";
17631836
}
17641837
return nullptr;
17651838
}

llvm/lib/Target/RISCV/RISCVISelLowering.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,14 @@ enum NodeType : unsigned {
4242
// at instruction selection time.
4343
DIVW,
4444
DIVUW,
45-
REMUW
45+
REMUW,
46+
// FPR32<->GPR transfer operations for RV64. Needed as an i32<->f32 bitcast
47+
// is not legal on RV64. FMV_W_X_RV64 matches the semantics of the FMV.W.X.
48+
// FMV_X_ANYEXTW_RV64 is similar to FMV.X.W but has an any-extended result.
49+
// This is a more convenient semantic for producing dagcombines that remove
50+
// unnecessary GPR->FPR->GPR moves.
51+
FMV_W_X_RV64,
52+
FMV_X_ANYEXTW_RV64
4653
};
4754
}
4855

llvm/lib/Target/RISCV/RISCVInstrInfoF.td

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,20 @@
1212
//
1313
//===----------------------------------------------------------------------===//
1414

15+
//===----------------------------------------------------------------------===//
16+
// RISC-V specific DAG Nodes.
17+
//===----------------------------------------------------------------------===//
18+
19+
def SDT_RISCVFMV_W_X_RV64
20+
: SDTypeProfile<1, 1, [SDTCisVT<0, f32>, SDTCisVT<1, i64>]>;
21+
def SDT_RISCVFMV_X_ANYEXTW_RV64
22+
: SDTypeProfile<1, 1, [SDTCisVT<0, i64>, SDTCisVT<1, f32>]>;
23+
24+
def riscv_fmv_w_x_rv64
25+
: SDNode<"RISCVISD::FMV_W_X_RV64", SDT_RISCVFMV_W_X_RV64>;
26+
def riscv_fmv_x_anyextw_rv64
27+
: SDNode<"RISCVISD::FMV_X_ANYEXTW_RV64", SDT_RISCVFMV_X_ANYEXTW_RV64>;
28+
1529
//===----------------------------------------------------------------------===//
1630
// Operand and SDNode transformation definitions.
1731
//===----------------------------------------------------------------------===//
@@ -334,3 +348,37 @@ def : Pat<(fp_to_uint FPR32:$rs1), (FCVT_WU_S $rs1, 0b001)>;
334348
def : Pat<(sint_to_fp GPR:$rs1), (FCVT_S_W $rs1, 0b111)>;
335349
def : Pat<(uint_to_fp GPR:$rs1), (FCVT_S_WU $rs1, 0b111)>;
336350
} // Predicates = [HasStdExtF, IsRV32]
351+
352+
let Predicates = [HasStdExtF, IsRV32] in {
353+
// FP->[u]int. Round-to-zero must be used
354+
def : Pat<(fp_to_sint FPR32:$rs1), (FCVT_W_S $rs1, 0b001)>;
355+
def : Pat<(fp_to_uint FPR32:$rs1), (FCVT_WU_S $rs1, 0b001)>;
356+
357+
// [u]int->fp. Match GCC and default to using dynamic rounding mode.
358+
def : Pat<(sint_to_fp GPR:$rs1), (FCVT_S_W $rs1, 0b111)>;
359+
def : Pat<(uint_to_fp GPR:$rs1), (FCVT_S_WU $rs1, 0b111)>;
360+
} // Predicates = [HasStdExtF, IsRV32]
361+
362+
let Predicates = [HasStdExtF, IsRV64] in {
363+
def : Pat<(riscv_fmv_w_x_rv64 GPR:$src), (FMV_W_X GPR:$src)>;
364+
def : Pat<(riscv_fmv_x_anyextw_rv64 FPR32:$src), (FMV_X_W FPR32:$src)>;
365+
def : Pat<(sexti32 (riscv_fmv_x_anyextw_rv64 FPR32:$src)),
366+
(FMV_X_W FPR32:$src)>;
367+
368+
// FP->[u]int32 is mostly handled by the FP->[u]int64 patterns. This is safe
369+
// because fpto[u|s]i produces poison if the value can't fit into the target.
370+
// We match the single case below because fcvt.wu.s sign-extends its result so
371+
// is cheaper than fcvt.lu.s+sext.w.
372+
def : Pat<(sext_inreg (assertzexti32 (fp_to_uint FPR32:$rs1)), i32),
373+
(FCVT_WU_S $rs1, 0b001)>;
374+
375+
// FP->[u]int64
376+
def : Pat<(fp_to_sint FPR32:$rs1), (FCVT_L_S $rs1, 0b001)>;
377+
def : Pat<(fp_to_uint FPR32:$rs1), (FCVT_LU_S $rs1, 0b001)>;
378+
379+
// [u]int->fp. Match GCC and default to using dynamic rounding mode.
380+
def : Pat<(sint_to_fp (sext_inreg GPR:$rs1, i32)), (FCVT_S_W $rs1, 0b111)>;
381+
def : Pat<(uint_to_fp (zexti32 GPR:$rs1)), (FCVT_S_WU $rs1, 0b111)>;
382+
def : Pat<(sint_to_fp GPR:$rs1), (FCVT_S_L $rs1, 0b111)>;
383+
def : Pat<(uint_to_fp GPR:$rs1), (FCVT_S_LU $rs1, 0b111)>;
384+
} // Predicates = [HasStdExtF, IsRV64]

0 commit comments

Comments
 (0)