switch (IntNo) {
default:
llvm_unreachable("Unexpected Intrinsic");
- case Intrinsic::riscv_grev:
- return RISCVISD::GREVW;
- case Intrinsic::riscv_gorc:
- return RISCVISD::GORCW;
case Intrinsic::riscv_bcompress:
return RISCVISD::BCOMPRESSW;
case Intrinsic::riscv_bdecompress:
return RISCVISD::ROLW;
case ISD::ROTR:
return RISCVISD::RORW;
- case RISCVISD::GREV:
- return RISCVISD::GREVW;
- case RISCVISD::GORC:
- return RISCVISD::GORCW;
}
}
assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() &&
"Unexpected custom legalisation");
assert(isa<ConstantSDNode>(N->getOperand(1)) && "Expected constant");
- // This is similar to customLegalizeToWOp, except that we pass the second
- // operand (a TargetConstant) straight through: it is already of type
- // XLenVT.
- RISCVISD::NodeType WOpcode = getRISCVWOpcode(N->getOpcode());
SDValue NewOp0 =
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 NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0, NewOp1);
+ DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i64, N->getOperand(1));
+ SDValue NewRes = DAG.getNode(N->getOpcode(), DL, MVT::i64, NewOp0, NewOp1);
// ReplaceNodeResults requires we maintain the same type for the return
// value.
Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, NewRes));
// If this is BSWAP rather than BITREVERSE, clear the lower 3 bits.
if (N->getOpcode() == ISD::BSWAP)
Imm &= ~0x7U;
- unsigned Opc = Subtarget.is64Bit() ? RISCVISD::GREVW : RISCVISD::GREV;
- SDValue GREVI =
- DAG.getNode(Opc, DL, XLenVT, NewOp0, DAG.getConstant(Imm, DL, XLenVT));
+ SDValue GREVI = DAG.getNode(RISCVISD::GREV, DL, XLenVT, NewOp0,
+ DAG.getConstant(Imm, DL, XLenVT));
// ReplaceNodeResults requires we maintain the same type for the return
// value.
Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, GREVI));
llvm_unreachable(
"Don't know how to custom type legalize this intrinsic!");
case Intrinsic::riscv_grev:
- case Intrinsic::riscv_gorc:
+ case Intrinsic::riscv_gorc: {
+ assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() &&
+ "Unexpected custom legalisation");
+ SDValue NewOp1 =
+ DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(1));
+ SDValue NewOp2 =
+ DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(2));
+ unsigned Opc =
+ IntNo == Intrinsic::riscv_grev ? RISCVISD::GREVW : RISCVISD::GORCW;
+ // If the control is a constant, promote the node by clearing any extra
+ // bits bits in the control. isel will form greviw/gorciw if the result is
+ // sign extended.
+ if (isa<ConstantSDNode>(NewOp2)) {
+ NewOp2 = DAG.getNode(ISD::AND, DL, MVT::i64, NewOp2,
+ DAG.getConstant(0x1f, DL, MVT::i64));
+ Opc = IntNo == Intrinsic::riscv_grev ? RISCVISD::GREV : RISCVISD::GORC;
+ }
+ SDValue Res = DAG.getNode(Opc, DL, MVT::i64, NewOp1, NewOp2);
+ Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Res));
+ break;
+ }
case Intrinsic::riscv_bcompress:
case Intrinsic::riscv_bdecompress:
case Intrinsic::riscv_bfp: {
// Lower to the GORCI encoding for orc.b with the operand extended.
SDValue NewOp =
DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(1));
- // If Zbp is enabled, use GORCIW which will sign extend the result.
- unsigned Opc =
- Subtarget.hasStdExtZbp() ? RISCVISD::GORCW : RISCVISD::GORC;
- SDValue Res = DAG.getNode(Opc, DL, MVT::i64, NewOp,
+ SDValue Res = DAG.getNode(RISCVISD::GORC, DL, MVT::i64, NewOp,
DAG.getConstant(7, DL, MVT::i64));
Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Res));
return;
}
// Combine
-// ROTR ((GREV x, 24), 16) -> (GREVI x, 8) for RV32
-// ROTL ((GREV x, 24), 16) -> (GREVI x, 8) for RV32
-// ROTR ((GREV x, 56), 32) -> (GREVI x, 24) for RV64
-// ROTL ((GREV x, 56), 32) -> (GREVI x, 24) for RV64
-// RORW ((GREVW x, 24), 16) -> (GREVIW x, 8) for RV64
-// ROLW ((GREVW x, 24), 16) -> (GREVIW x, 8) for RV64
+// ROTR ((GREVI x, 24), 16) -> (GREVI x, 8) for RV32
+// ROTL ((GREVI x, 24), 16) -> (GREVI x, 8) for RV32
+// ROTR ((GREVI x, 56), 32) -> (GREVI x, 24) for RV64
+// ROTL ((GREVI x, 56), 32) -> (GREVI x, 24) for RV64
+// RORW ((GREVI x, 24), 16) -> (GREVIW x, 8) for RV64
+// ROLW ((GREVI x, 24), 16) -> (GREVIW x, 8) for RV64
// The grev patterns represents BSWAP.
// FIXME: This can be generalized to any GREV. We just need to toggle the MSB
// off the grev.
EVT VT = N->getValueType(0);
SDLoc DL(N);
- if (!Subtarget.hasStdExtZbp())
- return SDValue();
-
- unsigned GrevOpc = IsWInstruction ? RISCVISD::GREVW : RISCVISD::GREV;
- if (Src.getOpcode() != GrevOpc)
+ if (!Subtarget.hasStdExtZbp() || Src.getOpcode() != RISCVISD::GREV)
return SDValue();
if (!isa<ConstantSDNode>(N->getOperand(1)) ||
// RORW/ROLW. And the grev should be the encoding for bswap for this width.
unsigned ShAmt1 = N->getConstantOperandVal(1);
unsigned ShAmt2 = Src.getConstantOperandVal(1);
- if (BitWidth < 16 || ShAmt1 != (BitWidth / 2) || ShAmt2 != (BitWidth - 8))
+ if (BitWidth < 32 || ShAmt1 != (BitWidth / 2) || ShAmt2 != (BitWidth - 8))
return SDValue();
Src = Src.getOperand(0);
if (CombinedShAmt == 0)
return Src;
- return DAG.getNode(
- GrevOpc, DL, VT, Src,
+ SDValue Res = DAG.getNode(
+ RISCVISD::GREV, DL, VT, Src,
DAG.getConstant(CombinedShAmt, DL, N->getOperand(1).getValueType()));
+ if (!IsWInstruction)
+ return Res;
+
+ // Sign extend the result to match the behavior of the rotate. This will be
+ // selected to GREVIW in isel.
+ return DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, VT, Res,
+ DAG.getValueType(MVT::i32));
}
// Combine (GREVI (GREVI x, C2), C1) -> (GREVI x, C1^C2) when C1^C2 is
// Combine (GORCI (GORCI x, C2), C1) -> (GORCI x, C1|C2). Repeated stage does
// not undo itself, but they are redundant.
static SDValue combineGREVI_GORCI(SDNode *N, SelectionDAG &DAG) {
+ bool IsGORC = N->getOpcode() == RISCVISD::GORC;
+ assert((IsGORC || N->getOpcode() == RISCVISD::GREV) && "Unexpected opcode");
SDValue Src = N->getOperand(0);
if (Src.getOpcode() != N->getOpcode())
Src = Src.getOperand(0);
unsigned CombinedShAmt;
- if (N->getOpcode() == RISCVISD::GORC || N->getOpcode() == RISCVISD::GORCW)
+ if (IsGORC)
CombinedShAmt = ShAmt1 | ShAmt2;
else
CombinedShAmt = ShAmt1 ^ ShAmt2;
SimplifyDemandedLowBitsHelper(1, 5))
return SDValue(N, 0);
- return combineGREVI_GORCI(N, DAG);
+ break;
}
case RISCVISD::SHFL:
case RISCVISD::UNSHFL: {
Known.Zero.setBitsFrom(LowBits);
break;
}
- case RISCVISD::GREV:
- case RISCVISD::GREVW: {
+ case RISCVISD::GREV: {
if (auto *C = dyn_cast<ConstantSDNode>(Op.getOperand(1))) {
Known = DAG.computeKnownBits(Op.getOperand(0), Depth + 1);
- if (Opc == RISCVISD::GREVW)
- Known = Known.trunc(32);
unsigned ShAmt = C->getZExtValue();
computeGREV(Known.Zero, ShAmt);
computeGREV(Known.One, ShAmt);
- if (Opc == RISCVISD::GREVW)
- Known = Known.sext(BitWidth);
}
break;
}
;
; RV64ZBP-LABEL: gorc16_rotl_i32:
; RV64ZBP: # %bb.0:
-; RV64ZBP-NEXT: gorciw a0, a0, 16
+; RV64ZBP-NEXT: orc16.w a0, a0
; RV64ZBP-NEXT: ret
%rot = tail call i32 @llvm.fshl.i32(i32 %a, i32 %a, i32 16)
%or = or i32 %rot, %a
;
; RV64ZBP-LABEL: gorc16_rotr_i32:
; RV64ZBP: # %bb.0:
-; RV64ZBP-NEXT: gorciw a0, a0, 16
+; RV64ZBP-NEXT: orc16.w a0, a0
; RV64ZBP-NEXT: ret
%rot = tail call i32 @llvm.fshr.i32(i32 %a, i32 %a, i32 16)
%or = or i32 %rot, %a
;
; RV64ZBP-LABEL: grev7_i32_zext:
; RV64ZBP: # %bb.0:
-; RV64ZBP-NEXT: greviw a0, a0, 7
-; RV64ZBP-NEXT: slli a0, a0, 32
-; RV64ZBP-NEXT: srli a0, a0, 32
+; RV64ZBP-NEXT: rev.b a0, a0
; RV64ZBP-NEXT: ret
%and1 = shl i32 %a, 1
%shl1 = and i32 %and1, -1431655766
;
; RV64ZBP-LABEL: bswap_i16:
; RV64ZBP: # %bb.0:
-; RV64ZBP-NEXT: greviw a0, a0, 8
+; RV64ZBP-NEXT: rev8.h a0, a0
; RV64ZBP-NEXT: ret
%1 = tail call i16 @llvm.bswap.i16(i16 %a)
ret i16 %1
;
; RV64ZBP-LABEL: bswap_i32_nosext:
; RV64ZBP: # %bb.0:
-; RV64ZBP-NEXT: greviw a0, a0, 24
+; RV64ZBP-NEXT: rev8.w a0, a0
; RV64ZBP-NEXT: sw a0, 0(a1)
; RV64ZBP-NEXT: ret
%1 = tail call i32 @llvm.bswap.i32(i32 %a)
;
; RV64ZBP-LABEL: bitreverse_i8:
; RV64ZBP: # %bb.0:
-; RV64ZBP-NEXT: greviw a0, a0, 7
+; RV64ZBP-NEXT: rev.b a0, a0
; RV64ZBP-NEXT: ret
%1 = tail call i8 @llvm.bitreverse.i8(i8 %a)
ret i8 %1
;
; RV64ZBP-LABEL: bitreverse_i16:
; RV64ZBP: # %bb.0:
-; RV64ZBP-NEXT: greviw a0, a0, 15
+; RV64ZBP-NEXT: rev.h a0, a0
; RV64ZBP-NEXT: ret
%1 = tail call i16 @llvm.bitreverse.i16(i16 %a)
ret i16 %1
;
; RV64ZBP-LABEL: bitreverse_i32_nosext:
; RV64ZBP: # %bb.0:
-; RV64ZBP-NEXT: greviw a0, a0, 31
+; RV64ZBP-NEXT: rev.w a0, a0
; RV64ZBP-NEXT: sw a0, 0(a1)
; RV64ZBP-NEXT: ret
%1 = tail call i32 @llvm.bitreverse.i32(i32 %a)
;
; RV64ZBP-LABEL: bitreverse_bswap_i32:
; RV64ZBP: # %bb.0:
-; RV64ZBP-NEXT: greviw a0, a0, 7
+; RV64ZBP-NEXT: rev.b a0, a0
; RV64ZBP-NEXT: ret
%1 = call i32 @llvm.bitreverse.i32(i32 %a)
%2 = call i32 @llvm.bswap.i32(i32 %1)