setTargetDAGCombine({ISD::INTRINSIC_WO_CHAIN, ISD::ADD, ISD::SUB, ISD::AND,
ISD::OR, ISD::XOR});
+ if (Subtarget.is64Bit())
+ setTargetDAGCombine(ISD::SRA);
if (Subtarget.hasStdExtF())
setTargetDAGCombine({ISD::FADD, ISD::FMAXNUM, ISD::FMINNUM});
return Opcode;
}
+
+// Combine (sra (shl X, 32), 32 - C) -> (shl (sext_inreg X, i32), C)
+// FIXME: Should this be a generic combine? There's a similar combine on X86.
+static SDValue performSRACombine(SDNode *N, SelectionDAG &DAG,
+ const RISCVSubtarget &Subtarget) {
+ assert(N->getOpcode() == ISD::SRA && "Unexpected opcode");
+
+ if (N->getValueType(0) != MVT::i64 || !Subtarget.is64Bit())
+ return SDValue();
+
+ auto *C = dyn_cast<ConstantSDNode>(N->getOperand(1));
+ if (!C || C->getZExtValue() >= 32)
+ return SDValue();
+
+ SDValue N0 = N->getOperand(0);
+ if (N0.getOpcode() != ISD::SHL || !N0.hasOneUse() ||
+ !isa<ConstantSDNode>(N0.getOperand(1)) ||
+ N0.getConstantOperandVal(1) != 32)
+ return SDValue();
+
+ SDLoc DL(N);
+ SDValue SExt = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i64,
+ N0.getOperand(0), DAG.getValueType(MVT::i32));
+ return DAG.getNode(ISD::SHL, DL, MVT::i64, SExt,
+ DAG.getConstant(32 - C->getZExtValue(), DL, MVT::i64));
+}
+
SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N,
DAGCombinerInfo &DCI) const {
SelectionDAG &DAG = DCI.DAG;
break;
}
case ISD::SRA:
+ if (SDValue V = performSRACombine(N, DAG, Subtarget))
+ return V;
+ LLVM_FALLTHROUGH;
case ISD::SRL:
case ISD::SHL: {
SDValue ShAmt = N->getOperand(1);
define i64 @test1(i64 %a) nounwind {
; RV64I-LABEL: test1:
; RV64I: # %bb.0:
-; RV64I-NEXT: slli a0, a0, 32
-; RV64I-NEXT: srai a0, a0, 30
+; RV64I-NEXT: sext.w a0, a0
+; RV64I-NEXT: slli a0, a0, 2
; RV64I-NEXT: ret
%1 = shl i64 %a, 32
%2 = ashr i64 %1, 30
define i64 @test2(i32 signext %a) nounwind {
; RV64I-LABEL: test2:
; RV64I: # %bb.0:
-; RV64I-NEXT: slli a0, a0, 32
-; RV64I-NEXT: srai a0, a0, 29
+; RV64I-NEXT: slli a0, a0, 3
; RV64I-NEXT: ret
%1 = zext i32 %a to i64
%2 = shl i64 %1, 32
; RV64I-LABEL: test3:
; RV64I: # %bb.0:
; RV64I-NEXT: lw a0, 0(a0)
-; RV64I-NEXT: slli a0, a0, 32
-; RV64I-NEXT: srai a0, a0, 28
+; RV64I-NEXT: slli a0, a0, 4
; RV64I-NEXT: ret
%1 = load i32, i32* %a
%2 = zext i32 %1 to i64
; RV64I-LABEL: test4:
; RV64I: # %bb.0:
; RV64I-NEXT: addw a0, a0, a1
-; RV64I-NEXT: slli a0, a0, 32
-; RV64I-NEXT: srai a0, a0, 2
+; RV64I-NEXT: slli a0, a0, 30
; RV64I-NEXT: ret
%1 = add i32 %a, %b
%2 = zext i32 %1 to i64
; RV64I-LABEL: test5:
; RV64I: # %bb.0:
; RV64I-NEXT: xor a0, a0, a1
-; RV64I-NEXT: slli a0, a0, 32
-; RV64I-NEXT: srai a0, a0, 1
+; RV64I-NEXT: slli a0, a0, 31
; RV64I-NEXT: ret
%1 = xor i32 %a, %b
%2 = zext i32 %1 to i64
; RV64I-LABEL: test6:
; RV64I: # %bb.0:
; RV64I-NEXT: sllw a0, a0, a1
-; RV64I-NEXT: slli a0, a0, 32
-; RV64I-NEXT: srai a0, a0, 16
+; RV64I-NEXT: slli a0, a0, 16
; RV64I-NEXT: ret
%1 = shl i32 %a, %b
%2 = zext i32 %1 to i64