diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index 39ecf0a3dbedf6..b0e5d735b81e34 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -2795,12 +2795,24 @@ SDValue RISCVTargetLowering::LowerOperation(SDValue Op, if (Op.getOperand(2).getOpcode() == ISD::Constant) return Op; // FSL/FSR take a log2(XLen)+1 bit shift amount but XLenVT FSHL/FSHR only - // use log(XLen) bits. Mask the shift amount accordingly. + // use log(XLen) bits. Mask the shift amount accordingly to prevent + // accidentally setting the extra bit. unsigned ShAmtWidth = Subtarget.getXLen() - 1; SDValue ShAmt = DAG.getNode(ISD::AND, DL, VT, Op.getOperand(2), DAG.getConstant(ShAmtWidth, DL, VT)); - unsigned Opc = Op.getOpcode() == ISD::FSHL ? RISCVISD::FSL : RISCVISD::FSR; - return DAG.getNode(Opc, DL, VT, Op.getOperand(0), Op.getOperand(1), ShAmt); + // fshl and fshr concatenate their operands in the same order. fsr and fsl + // instruction use different orders. fshl will return its first operand for + // shift of zero, fshr will return its second operand. fsl and fsr both + // return rs1 so the ISD nodes need to have different operand orders. + // Shift amount is in rs2. + SDValue Op0 = Op.getOperand(0); + SDValue Op1 = Op.getOperand(1); + unsigned Opc = RISCVISD::FSL; + if (Op.getOpcode() == ISD::FSHR) { + std::swap(Op0, Op1); + Opc = RISCVISD::FSR; + } + return DAG.getNode(Opc, DL, VT, Op0, Op1, ShAmt); } case ISD::TRUNCATE: { SDLoc DL(Op); @@ -6232,15 +6244,23 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(0)); SDValue NewOp1 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(1)); - SDValue NewOp2 = + SDValue NewShAmt = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(2)); // FSLW/FSRW take a 6 bit shift amount but i32 FSHL/FSHR only use 5 bits. - // Mask the shift amount to 5 bits. - NewOp2 = DAG.getNode(ISD::AND, DL, MVT::i64, NewOp2, - DAG.getConstant(0x1f, DL, MVT::i64)); - unsigned Opc = - N->getOpcode() == ISD::FSHL ? RISCVISD::FSLW : RISCVISD::FSRW; - SDValue NewOp = DAG.getNode(Opc, DL, MVT::i64, NewOp0, NewOp1, NewOp2); + // Mask the shift amount to 5 bits to prevent accidentally setting bit 5. + NewShAmt = DAG.getNode(ISD::AND, DL, MVT::i64, NewShAmt, + DAG.getConstant(0x1f, DL, MVT::i64)); + // fshl and fshr concatenate their operands in the same order. fsrw and fslw + // instruction use different orders. fshl will return its first operand for + // shift of zero, fshr will return its second operand. fsl and fsr both + // return rs1 so the ISD nodes need to have different operand orders. + // Shift amount is in rs2. + unsigned Opc = RISCVISD::FSLW; + if (N->getOpcode() == ISD::FSHR) { + std::swap(NewOp0, NewOp1); + Opc = RISCVISD::FSRW; + } + SDValue NewOp = DAG.getNode(Opc, DL, MVT::i64, NewOp0, NewOp1, NewShAmt); Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, NewOp)); break; } @@ -7276,9 +7296,9 @@ SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N, case RISCVISD::FSL: case RISCVISD::FSR: { // Only the lower log2(Bitwidth)+1 bits of the the shift amount are read. - unsigned BitWidth = N->getOperand(2).getValueSizeInBits(); + unsigned BitWidth = N->getOperand(1).getValueSizeInBits(); assert(isPowerOf2_32(BitWidth) && "Unexpected bit width"); - if (SimplifyDemandedLowBitsHelper(2, Log2_32(BitWidth) + 1)) + if (SimplifyDemandedLowBitsHelper(1, Log2_32(BitWidth) + 1)) return SDValue(N, 0); break; } @@ -7287,8 +7307,8 @@ SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N, // Only the lower 32 bits of Values and lower 6 bits of shift amount are // read. if (SimplifyDemandedLowBitsHelper(0, 32) || - SimplifyDemandedLowBitsHelper(1, 32) || - SimplifyDemandedLowBitsHelper(2, 6)) + SimplifyDemandedLowBitsHelper(2, 32) || + SimplifyDemandedLowBitsHelper(1, 6)) return SDValue(N, 0); break; } diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h index cd423c9ecca09e..76b778831fae03 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.h +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h @@ -63,11 +63,11 @@ enum NodeType : unsigned { CLZW, CTZW, // RV64IB/RV32IB funnel shifts, with the semantics of the named RISC-V - // instructions, but the same operand order as fshl/fshr intrinsics. + // instructions. Operand order is rs1, rs3, rs2/shamt. FSR, FSL, - // RV64IB funnel shifts, with the semantics of the named RISC-V instructions, - // but the same operand order as fshl/fshr intrinsics. + // RV64IB funnel shifts, with the semantics of the named RISC-V instructions. + // Operand order is rs1, rs3, rs2/shamt. FSRW, FSLW, // FPR<->GPR transfer operations when the FPR is smaller than XLEN, needed as diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td index c2e7217df30fe3..74f617c8333a7e 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td @@ -901,16 +901,16 @@ def : Pat<(select GPR:$rs2, GPR:$rs1, GPR:$rs3), (CMOV GPR:$rs1, GPR:$rs2, GPR:$rs3)>; } // Predicates = [HasStdExtZbt] -// fshl and fshr concatenate their operands in the same order. fsr and fsl -// instruction use different orders. fshl will return its first operand for -// shift of zero, fshr will return its second operand. fsl and fsr both return -// $rs1 so the patterns need to have different operand orders. let Predicates = [HasStdExtZbt] in { def : Pat<(riscv_fsl GPR:$rs1, GPR:$rs3, GPR:$rs2), (FSL GPR:$rs1, GPR:$rs2, GPR:$rs3)>; -def : Pat<(riscv_fsr GPR:$rs3, GPR:$rs1, GPR:$rs2), +def : Pat<(riscv_fsr GPR:$rs1, GPR:$rs3, GPR:$rs2), (FSR GPR:$rs1, GPR:$rs2, GPR:$rs3)>; +// fshl and fshr concatenate their operands in the same order. fsr and fsl +// instruction use different orders. fshl will return its first operand for +// shift of zero, fshr will return its second operand. fsl and fsr both return +// $rs1 so the patterns need to have different operand orders. def : Pat<(fshr GPR:$rs3, GPR:$rs1, uimmlog2xlen:$shamt), (FSRI GPR:$rs1, GPR:$rs3, uimmlog2xlen:$shamt)>; // We can use FSRI for fshl by immediate if we subtract the immediate from @@ -1090,10 +1090,12 @@ def : PatGprImm; let Predicates = [HasStdExtZbt, IsRV64] in { def : Pat<(riscv_fslw GPR:$rs1, GPR:$rs3, GPR:$rs2), (FSLW GPR:$rs1, GPR:$rs2, GPR:$rs3)>; -def : Pat<(riscv_fsrw GPR:$rs3, GPR:$rs1, GPR:$rs2), +def : Pat<(riscv_fsrw GPR:$rs1, GPR:$rs3, GPR:$rs2), (FSRW GPR:$rs1, GPR:$rs2, GPR:$rs3)>; -def : Pat<(riscv_fsrw GPR:$rs3, GPR:$rs1, uimm5:$shamt), +def : Pat<(riscv_fsrw GPR:$rs1, GPR:$rs3, uimm5:$shamt), (FSRIW GPR:$rs1, GPR:$rs3, uimm5:$shamt)>; +// We can use FSRIW for FSLW by immediate if we subtract the immediate from +// 32 and swap the operands. def : Pat<(riscv_fslw GPR:$rs3, GPR:$rs1, uimm5:$shamt), (FSRIW GPR:$rs1, GPR:$rs3, (ImmSubFrom32 uimm5:$shamt))>; } // Predicates = [HasStdExtZbt, IsRV64]