From 272fa582289da41854b102a5ccf680560809bf86 Mon Sep 17 00:00:00 2001 From: Alex Bradbury Date: Sat, 1 Dec 2018 05:00:00 +0000 Subject: [PATCH] [RISCV] Remove RV64I SLLW/SRLW/SRAW patterns and add new test cases As noted by Eli Friedman , the RV64I shift patterns for SLLW/SRLW/SRAW make some incorrect assumptions. SRAW assumed that (sext_inreg foo, i32) could only be produced when sign-extended an i32. However, it can be produced by input such as: define i64 @tricky_ashr(i64 %a, i64 %b) { %1 = shl i64 %a, 32 %2 = ashr i64 %1, 32 %3 = ashr i64 %2, %b ret i64 %3 } It's important not to select sraw in the above case, because sraw only uses bits lower 5 bits from the shift, while a shift of 32-63 would be valid. Similarly, the patterns for srlw assumed (and foo, 0xffffffff) would only be produced when zero-extending a value that was originally i32 in LLVM IR. This is obviously incorrect. This patch removes the SLLW/SRLW/SRAW shift patterns for the time being and adds test cases that would demonstrate a miscompile if the incorrect patterns were re-added. llvm-svn: 348067 --- lib/Target/RISCV/RISCVInstrInfo.td | 27 +-- test/CodeGen/RISCV/alu32.ll | 11 +- test/CodeGen/RISCV/alu64.ll | 17 +- .../CodeGen/RISCV/rv64i-exhaustive-w-insts.ll | 187 ++++++++++++------ test/CodeGen/RISCV/rv64i-tricky-shifts.ll | 44 +++++ 5 files changed, 198 insertions(+), 88 deletions(-) create mode 100644 test/CodeGen/RISCV/rv64i-tricky-shifts.ll diff --git a/lib/Target/RISCV/RISCVInstrInfo.td b/lib/Target/RISCV/RISCVInstrInfo.td index 9dbf8c6d88f..60c0f0b96a6 100644 --- a/lib/Target/RISCV/RISCVInstrInfo.td +++ b/lib/Target/RISCV/RISCVInstrInfo.td @@ -211,9 +211,6 @@ def immbottomxlenset : ImmLeaf(Imm) >= 6; return countTrailingOnes(Imm) >= 5; }]>; -def immshifti32 : ImmLeaf(Imm) >= 5; -}]>; // Addressing modes. // Necessary because a frameindex can't be matched directly in a pattern. @@ -890,13 +887,6 @@ def ADJCALLSTACKUP : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2), /// RV64 patterns -def assertzexti32 : PatFrag<(ops node:$src), (assertzext node:$src), [{ - return cast(N->getOperand(1))->getVT() == MVT::i32; -}]>; -def zexti32 : PatFrags<(ops node:$src), - [(and node:$src, 0xffffffff), - (assertzexti32 node:$src)]>; - let Predicates = [IsRV64] in { /// sext and zext @@ -919,22 +909,7 @@ def : Pat<(sext_inreg (shl GPR:$rs1, uimm5:$shamt), i32), def : Pat<(sra (sext_inreg GPR:$rs1, i32), uimm5:$shamt), (SRAIW GPR:$rs1, uimm5:$shamt)>; -def : Pat<(sext_inreg (shl GPR:$rs1, GPR:$rs2), i32), - (SLLW GPR:$rs1, GPR:$rs2)>; -def : Pat<(sext_inreg (shl GPR:$rs1, (and GPR:$rs2, immshifti32)), i32), - (SLLW GPR:$rs1, GPR:$rs2)>; -def : Pat<(srl (zexti32 GPR:$rs1), GPR:$rs2), - (SRLW GPR:$rs1, GPR:$rs2)>; -def : Pat<(srl (zexti32 GPR:$rs1), (and GPR:$rs2, immshifti32)), - (SRLW GPR:$rs1, GPR:$rs2)>; -def : Pat<(sext_inreg (srl (zexti32 GPR:$rs1), GPR:$rs2), i32), - (SRLW GPR:$rs1, GPR:$rs2)>; -def : Pat<(sext_inreg (srl (zexti32 GPR:$rs1), (and GPR:$rs2, immshifti32)), i32), - (SRLW GPR:$rs1, GPR:$rs2)>; -def : Pat<(sra (sext_inreg GPR:$rs1, i32), GPR:$rs2), - (SRAW GPR:$rs1, GPR:$rs2)>; -def : Pat<(sra (sext_inreg GPR:$rs1, i32), (and GPR:$rs2, immshifti32)), - (SRAW GPR:$rs1, GPR:$rs2)>; +// TODO: patterns for SLLW/SRLW/SRAW. /// Loads diff --git a/test/CodeGen/RISCV/alu32.ll b/test/CodeGen/RISCV/alu32.ll index 3c995e61101..6ee6ed76ee6 100644 --- a/test/CodeGen/RISCV/alu32.ll +++ b/test/CodeGen/RISCV/alu32.ll @@ -235,6 +235,8 @@ define i32 @xor(i32 %a, i32 %b) nounwind { ret i32 %1 } +; TODO: should select srlw for RV64. + define i32 @srl(i32 %a, i32 %b) nounwind { ; RV32I-LABEL: srl: ; RV32I: # %bb.0: @@ -243,12 +245,16 @@ define i32 @srl(i32 %a, i32 %b) nounwind { ; ; RV64I-LABEL: srl: ; RV64I: # %bb.0: -; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: slli a0, a0, 32 +; RV64I-NEXT: srli a0, a0, 32 +; RV64I-NEXT: srl a0, a0, a1 ; RV64I-NEXT: ret %1 = lshr i32 %a, %b ret i32 %1 } +; TODO: should select sraw for RV64. + define i32 @sra(i32 %a, i32 %b) nounwind { ; RV32I-LABEL: sra: ; RV32I: # %bb.0: @@ -257,7 +263,8 @@ define i32 @sra(i32 %a, i32 %b) nounwind { ; ; RV64I-LABEL: sra: ; RV64I: # %bb.0: -; RV64I-NEXT: sraw a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: sra a0, a0, a1 ; RV64I-NEXT: ret %1 = ashr i32 %a, %b ret i32 %1 diff --git a/test/CodeGen/RISCV/alu64.ll b/test/CodeGen/RISCV/alu64.ll index e66d1d62e55..021211b6f36 100644 --- a/test/CodeGen/RISCV/alu64.ll +++ b/test/CodeGen/RISCV/alu64.ll @@ -444,10 +444,13 @@ define signext i32 @subw(i32 signext %a, i32 signext %b) { ret i32 %1 } +; TODO: should select sllw for RV64. + define signext i32 @sllw(i32 signext %a, i32 zeroext %b) { ; RV64I-LABEL: sllw: ; RV64I: # %bb.0: -; RV64I-NEXT: sllw a0, a0, a1 +; RV64I-NEXT: sll a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 ; RV64I-NEXT: ret ; ; RV32I-LABEL: sllw: @@ -458,10 +461,15 @@ define signext i32 @sllw(i32 signext %a, i32 zeroext %b) { ret i32 %1 } +; TODO: should select srlw for RV64. + define signext i32 @srlw(i32 signext %a, i32 zeroext %b) { ; RV64I-LABEL: srlw: ; RV64I: # %bb.0: -; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: slli a0, a0, 32 +; RV64I-NEXT: srli a0, a0, 32 +; RV64I-NEXT: srl a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 ; RV64I-NEXT: ret ; ; RV32I-LABEL: srlw: @@ -472,10 +480,13 @@ define signext i32 @srlw(i32 signext %a, i32 zeroext %b) { ret i32 %1 } +; TODO: should select sraw for RV64. + define signext i32 @sraw(i64 %a, i32 zeroext %b) { ; RV64I-LABEL: sraw: ; RV64I: # %bb.0: -; RV64I-NEXT: sraw a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: sra a0, a0, a1 ; RV64I-NEXT: ret ; ; RV32I-LABEL: sraw: diff --git a/test/CodeGen/RISCV/rv64i-exhaustive-w-insts.ll b/test/CodeGen/RISCV/rv64i-exhaustive-w-insts.ll index d831f7c2394..52a59c04a32 100644 --- a/test/CodeGen/RISCV/rv64i-exhaustive-w-insts.ll +++ b/test/CodeGen/RISCV/rv64i-exhaustive-w-insts.ll @@ -624,12 +624,13 @@ define i32 @aext_sllw_zext_zext(i32 zeroext %a, i32 zeroext %b) nounwind { ret i32 %1 } -; Select sllw for all cases witha signext result. +; TODO: Select sllw for all cases witha signext result. define signext i32 @sext_sllw_aext_aext(i32 %a, i32 %b) nounwind { ; RV64I-LABEL: sext_sllw_aext_aext: ; RV64I: # %bb.0: -; RV64I-NEXT: sllw a0, a0, a1 +; RV64I-NEXT: sll a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 ; RV64I-NEXT: ret %1 = shl i32 %a, %b ret i32 %1 @@ -638,7 +639,8 @@ define signext i32 @sext_sllw_aext_aext(i32 %a, i32 %b) nounwind { define signext i32 @sext_sllw_aext_sext(i32 %a, i32 signext %b) nounwind { ; RV64I-LABEL: sext_sllw_aext_sext: ; RV64I: # %bb.0: -; RV64I-NEXT: sllw a0, a0, a1 +; RV64I-NEXT: sll a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 ; RV64I-NEXT: ret %1 = shl i32 %a, %b ret i32 %1 @@ -647,7 +649,8 @@ define signext i32 @sext_sllw_aext_sext(i32 %a, i32 signext %b) nounwind { define signext i32 @sext_sllw_aext_zext(i32 %a, i32 zeroext %b) nounwind { ; RV64I-LABEL: sext_sllw_aext_zext: ; RV64I: # %bb.0: -; RV64I-NEXT: sllw a0, a0, a1 +; RV64I-NEXT: sll a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 ; RV64I-NEXT: ret %1 = shl i32 %a, %b ret i32 %1 @@ -656,7 +659,8 @@ define signext i32 @sext_sllw_aext_zext(i32 %a, i32 zeroext %b) nounwind { define signext i32 @sext_sllw_sext_aext(i32 signext %a, i32 %b) nounwind { ; RV64I-LABEL: sext_sllw_sext_aext: ; RV64I: # %bb.0: -; RV64I-NEXT: sllw a0, a0, a1 +; RV64I-NEXT: sll a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 ; RV64I-NEXT: ret %1 = shl i32 %a, %b ret i32 %1 @@ -665,7 +669,8 @@ define signext i32 @sext_sllw_sext_aext(i32 signext %a, i32 %b) nounwind { define signext i32 @sext_sllw_sext_sext(i32 signext %a, i32 signext %b) nounwind { ; RV64I-LABEL: sext_sllw_sext_sext: ; RV64I: # %bb.0: -; RV64I-NEXT: sllw a0, a0, a1 +; RV64I-NEXT: sll a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 ; RV64I-NEXT: ret %1 = shl i32 %a, %b ret i32 %1 @@ -674,7 +679,8 @@ define signext i32 @sext_sllw_sext_sext(i32 signext %a, i32 signext %b) nounwind define signext i32 @sext_sllw_sext_zext(i32 signext %a, i32 zeroext %b) nounwind { ; RV64I-LABEL: sext_sllw_sext_zext: ; RV64I: # %bb.0: -; RV64I-NEXT: sllw a0, a0, a1 +; RV64I-NEXT: sll a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 ; RV64I-NEXT: ret %1 = shl i32 %a, %b ret i32 %1 @@ -683,7 +689,8 @@ define signext i32 @sext_sllw_sext_zext(i32 signext %a, i32 zeroext %b) nounwind define signext i32 @sext_sllw_zext_aext(i32 zeroext %a, i32 %b) nounwind { ; RV64I-LABEL: sext_sllw_zext_aext: ; RV64I: # %bb.0: -; RV64I-NEXT: sllw a0, a0, a1 +; RV64I-NEXT: sll a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 ; RV64I-NEXT: ret %1 = shl i32 %a, %b ret i32 %1 @@ -692,7 +699,8 @@ define signext i32 @sext_sllw_zext_aext(i32 zeroext %a, i32 %b) nounwind { define signext i32 @sext_sllw_zext_sext(i32 zeroext %a, i32 signext %b) nounwind { ; RV64I-LABEL: sext_sllw_zext_sext: ; RV64I: # %bb.0: -; RV64I-NEXT: sllw a0, a0, a1 +; RV64I-NEXT: sll a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 ; RV64I-NEXT: ret %1 = shl i32 %a, %b ret i32 %1 @@ -701,7 +709,8 @@ define signext i32 @sext_sllw_zext_sext(i32 zeroext %a, i32 signext %b) nounwind define signext i32 @sext_sllw_zext_zext(i32 zeroext %a, i32 zeroext %b) nounwind { ; RV64I-LABEL: sext_sllw_zext_zext: ; RV64I: # %bb.0: -; RV64I-NEXT: sllw a0, a0, a1 +; RV64I-NEXT: sll a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 ; RV64I-NEXT: ret %1 = shl i32 %a, %b ret i32 %1 @@ -808,12 +817,14 @@ define zeroext i32 @zext_sllw_zext_zext(i32 zeroext %a, i32 zeroext %b) nounwind ret i32 %1 } -; srlw must always be selected for 32-bit lshr with variable arguments. +; TODO: srlw should be selected for 32-bit lshr with variable arguments. define i32 @aext_srlw_aext_aext(i32 %a, i32 %b) nounwind { ; RV64I-LABEL: aext_srlw_aext_aext: ; RV64I: # %bb.0: -; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: slli a0, a0, 32 +; RV64I-NEXT: srli a0, a0, 32 +; RV64I-NEXT: srl a0, a0, a1 ; RV64I-NEXT: ret %1 = lshr i32 %a, %b ret i32 %1 @@ -822,7 +833,9 @@ define i32 @aext_srlw_aext_aext(i32 %a, i32 %b) nounwind { define i32 @aext_srlw_aext_sext(i32 %a, i32 signext %b) nounwind { ; RV64I-LABEL: aext_srlw_aext_sext: ; RV64I: # %bb.0: -; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: slli a0, a0, 32 +; RV64I-NEXT: srli a0, a0, 32 +; RV64I-NEXT: srl a0, a0, a1 ; RV64I-NEXT: ret %1 = lshr i32 %a, %b ret i32 %1 @@ -831,7 +844,9 @@ define i32 @aext_srlw_aext_sext(i32 %a, i32 signext %b) nounwind { define i32 @aext_srlw_aext_zext(i32 %a, i32 zeroext %b) nounwind { ; RV64I-LABEL: aext_srlw_aext_zext: ; RV64I: # %bb.0: -; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: slli a0, a0, 32 +; RV64I-NEXT: srli a0, a0, 32 +; RV64I-NEXT: srl a0, a0, a1 ; RV64I-NEXT: ret %1 = lshr i32 %a, %b ret i32 %1 @@ -840,7 +855,9 @@ define i32 @aext_srlw_aext_zext(i32 %a, i32 zeroext %b) nounwind { define i32 @aext_srlw_sext_aext(i32 signext %a, i32 %b) nounwind { ; RV64I-LABEL: aext_srlw_sext_aext: ; RV64I: # %bb.0: -; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: slli a0, a0, 32 +; RV64I-NEXT: srli a0, a0, 32 +; RV64I-NEXT: srl a0, a0, a1 ; RV64I-NEXT: ret %1 = lshr i32 %a, %b ret i32 %1 @@ -849,7 +866,9 @@ define i32 @aext_srlw_sext_aext(i32 signext %a, i32 %b) nounwind { define i32 @aext_srlw_sext_sext(i32 signext %a, i32 signext %b) nounwind { ; RV64I-LABEL: aext_srlw_sext_sext: ; RV64I: # %bb.0: -; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: slli a0, a0, 32 +; RV64I-NEXT: srli a0, a0, 32 +; RV64I-NEXT: srl a0, a0, a1 ; RV64I-NEXT: ret %1 = lshr i32 %a, %b ret i32 %1 @@ -858,7 +877,9 @@ define i32 @aext_srlw_sext_sext(i32 signext %a, i32 signext %b) nounwind { define i32 @aext_srlw_sext_zext(i32 signext %a, i32 zeroext %b) nounwind { ; RV64I-LABEL: aext_srlw_sext_zext: ; RV64I: # %bb.0: -; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: slli a0, a0, 32 +; RV64I-NEXT: srli a0, a0, 32 +; RV64I-NEXT: srl a0, a0, a1 ; RV64I-NEXT: ret %1 = lshr i32 %a, %b ret i32 %1 @@ -867,7 +888,7 @@ define i32 @aext_srlw_sext_zext(i32 signext %a, i32 zeroext %b) nounwind { define i32 @aext_srlw_zext_aext(i32 zeroext %a, i32 %b) nounwind { ; RV64I-LABEL: aext_srlw_zext_aext: ; RV64I: # %bb.0: -; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: srl a0, a0, a1 ; RV64I-NEXT: ret %1 = lshr i32 %a, %b ret i32 %1 @@ -876,7 +897,7 @@ define i32 @aext_srlw_zext_aext(i32 zeroext %a, i32 %b) nounwind { define i32 @aext_srlw_zext_sext(i32 zeroext %a, i32 signext %b) nounwind { ; RV64I-LABEL: aext_srlw_zext_sext: ; RV64I: # %bb.0: -; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: srl a0, a0, a1 ; RV64I-NEXT: ret %1 = lshr i32 %a, %b ret i32 %1 @@ -885,7 +906,7 @@ define i32 @aext_srlw_zext_sext(i32 zeroext %a, i32 signext %b) nounwind { define i32 @aext_srlw_zext_zext(i32 zeroext %a, i32 zeroext %b) nounwind { ; RV64I-LABEL: aext_srlw_zext_zext: ; RV64I: # %bb.0: -; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: srl a0, a0, a1 ; RV64I-NEXT: ret %1 = lshr i32 %a, %b ret i32 %1 @@ -894,7 +915,10 @@ define i32 @aext_srlw_zext_zext(i32 zeroext %a, i32 zeroext %b) nounwind { define signext i32 @sext_srlw_aext_aext(i32 %a, i32 %b) nounwind { ; RV64I-LABEL: sext_srlw_aext_aext: ; RV64I: # %bb.0: -; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: slli a0, a0, 32 +; RV64I-NEXT: srli a0, a0, 32 +; RV64I-NEXT: srl a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 ; RV64I-NEXT: ret %1 = lshr i32 %a, %b ret i32 %1 @@ -903,7 +927,10 @@ define signext i32 @sext_srlw_aext_aext(i32 %a, i32 %b) nounwind { define signext i32 @sext_srlw_aext_sext(i32 %a, i32 signext %b) nounwind { ; RV64I-LABEL: sext_srlw_aext_sext: ; RV64I: # %bb.0: -; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: slli a0, a0, 32 +; RV64I-NEXT: srli a0, a0, 32 +; RV64I-NEXT: srl a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 ; RV64I-NEXT: ret %1 = lshr i32 %a, %b ret i32 %1 @@ -912,7 +939,10 @@ define signext i32 @sext_srlw_aext_sext(i32 %a, i32 signext %b) nounwind { define signext i32 @sext_srlw_aext_zext(i32 %a, i32 zeroext %b) nounwind { ; RV64I-LABEL: sext_srlw_aext_zext: ; RV64I: # %bb.0: -; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: slli a0, a0, 32 +; RV64I-NEXT: srli a0, a0, 32 +; RV64I-NEXT: srl a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 ; RV64I-NEXT: ret %1 = lshr i32 %a, %b ret i32 %1 @@ -921,7 +951,10 @@ define signext i32 @sext_srlw_aext_zext(i32 %a, i32 zeroext %b) nounwind { define signext i32 @sext_srlw_sext_aext(i32 signext %a, i32 %b) nounwind { ; RV64I-LABEL: sext_srlw_sext_aext: ; RV64I: # %bb.0: -; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: slli a0, a0, 32 +; RV64I-NEXT: srli a0, a0, 32 +; RV64I-NEXT: srl a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 ; RV64I-NEXT: ret %1 = lshr i32 %a, %b ret i32 %1 @@ -930,7 +963,10 @@ define signext i32 @sext_srlw_sext_aext(i32 signext %a, i32 %b) nounwind { define signext i32 @sext_srlw_sext_sext(i32 signext %a, i32 signext %b) nounwind { ; RV64I-LABEL: sext_srlw_sext_sext: ; RV64I: # %bb.0: -; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: slli a0, a0, 32 +; RV64I-NEXT: srli a0, a0, 32 +; RV64I-NEXT: srl a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 ; RV64I-NEXT: ret %1 = lshr i32 %a, %b ret i32 %1 @@ -939,7 +975,10 @@ define signext i32 @sext_srlw_sext_sext(i32 signext %a, i32 signext %b) nounwind define signext i32 @sext_srlw_sext_zext(i32 signext %a, i32 zeroext %b) nounwind { ; RV64I-LABEL: sext_srlw_sext_zext: ; RV64I: # %bb.0: -; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: slli a0, a0, 32 +; RV64I-NEXT: srli a0, a0, 32 +; RV64I-NEXT: srl a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 ; RV64I-NEXT: ret %1 = lshr i32 %a, %b ret i32 %1 @@ -948,7 +987,8 @@ define signext i32 @sext_srlw_sext_zext(i32 signext %a, i32 zeroext %b) nounwind define signext i32 @sext_srlw_zext_aext(i32 zeroext %a, i32 %b) nounwind { ; RV64I-LABEL: sext_srlw_zext_aext: ; RV64I: # %bb.0: -; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: srl a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 ; RV64I-NEXT: ret %1 = lshr i32 %a, %b ret i32 %1 @@ -957,7 +997,8 @@ define signext i32 @sext_srlw_zext_aext(i32 zeroext %a, i32 %b) nounwind { define signext i32 @sext_srlw_zext_sext(i32 zeroext %a, i32 signext %b) nounwind { ; RV64I-LABEL: sext_srlw_zext_sext: ; RV64I: # %bb.0: -; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: srl a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 ; RV64I-NEXT: ret %1 = lshr i32 %a, %b ret i32 %1 @@ -966,7 +1007,8 @@ define signext i32 @sext_srlw_zext_sext(i32 zeroext %a, i32 signext %b) nounwind define signext i32 @sext_srlw_zext_zext(i32 zeroext %a, i32 zeroext %b) nounwind { ; RV64I-LABEL: sext_srlw_zext_zext: ; RV64I: # %bb.0: -; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: srl a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 ; RV64I-NEXT: ret %1 = lshr i32 %a, %b ret i32 %1 @@ -975,7 +1017,9 @@ define signext i32 @sext_srlw_zext_zext(i32 zeroext %a, i32 zeroext %b) nounwind define zeroext i32 @zext_srlw_aext_aext(i32 %a, i32 %b) nounwind { ; RV64I-LABEL: zext_srlw_aext_aext: ; RV64I: # %bb.0: -; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: slli a0, a0, 32 +; RV64I-NEXT: srli a0, a0, 32 +; RV64I-NEXT: srl a0, a0, a1 ; RV64I-NEXT: slli a0, a0, 32 ; RV64I-NEXT: srli a0, a0, 32 ; RV64I-NEXT: ret @@ -986,7 +1030,9 @@ define zeroext i32 @zext_srlw_aext_aext(i32 %a, i32 %b) nounwind { define zeroext i32 @zext_srlw_aext_sext(i32 %a, i32 signext %b) nounwind { ; RV64I-LABEL: zext_srlw_aext_sext: ; RV64I: # %bb.0: -; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: slli a0, a0, 32 +; RV64I-NEXT: srli a0, a0, 32 +; RV64I-NEXT: srl a0, a0, a1 ; RV64I-NEXT: slli a0, a0, 32 ; RV64I-NEXT: srli a0, a0, 32 ; RV64I-NEXT: ret @@ -997,7 +1043,9 @@ define zeroext i32 @zext_srlw_aext_sext(i32 %a, i32 signext %b) nounwind { define zeroext i32 @zext_srlw_aext_zext(i32 %a, i32 zeroext %b) nounwind { ; RV64I-LABEL: zext_srlw_aext_zext: ; RV64I: # %bb.0: -; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: slli a0, a0, 32 +; RV64I-NEXT: srli a0, a0, 32 +; RV64I-NEXT: srl a0, a0, a1 ; RV64I-NEXT: slli a0, a0, 32 ; RV64I-NEXT: srli a0, a0, 32 ; RV64I-NEXT: ret @@ -1008,7 +1056,9 @@ define zeroext i32 @zext_srlw_aext_zext(i32 %a, i32 zeroext %b) nounwind { define zeroext i32 @zext_srlw_sext_aext(i32 signext %a, i32 %b) nounwind { ; RV64I-LABEL: zext_srlw_sext_aext: ; RV64I: # %bb.0: -; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: slli a0, a0, 32 +; RV64I-NEXT: srli a0, a0, 32 +; RV64I-NEXT: srl a0, a0, a1 ; RV64I-NEXT: slli a0, a0, 32 ; RV64I-NEXT: srli a0, a0, 32 ; RV64I-NEXT: ret @@ -1019,7 +1069,9 @@ define zeroext i32 @zext_srlw_sext_aext(i32 signext %a, i32 %b) nounwind { define zeroext i32 @zext_srlw_sext_sext(i32 signext %a, i32 signext %b) nounwind { ; RV64I-LABEL: zext_srlw_sext_sext: ; RV64I: # %bb.0: -; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: slli a0, a0, 32 +; RV64I-NEXT: srli a0, a0, 32 +; RV64I-NEXT: srl a0, a0, a1 ; RV64I-NEXT: slli a0, a0, 32 ; RV64I-NEXT: srli a0, a0, 32 ; RV64I-NEXT: ret @@ -1030,7 +1082,9 @@ define zeroext i32 @zext_srlw_sext_sext(i32 signext %a, i32 signext %b) nounwind define zeroext i32 @zext_srlw_sext_zext(i32 signext %a, i32 zeroext %b) nounwind { ; RV64I-LABEL: zext_srlw_sext_zext: ; RV64I: # %bb.0: -; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: slli a0, a0, 32 +; RV64I-NEXT: srli a0, a0, 32 +; RV64I-NEXT: srl a0, a0, a1 ; RV64I-NEXT: slli a0, a0, 32 ; RV64I-NEXT: srli a0, a0, 32 ; RV64I-NEXT: ret @@ -1041,7 +1095,7 @@ define zeroext i32 @zext_srlw_sext_zext(i32 signext %a, i32 zeroext %b) nounwind define zeroext i32 @zext_srlw_zext_aext(i32 zeroext %a, i32 %b) nounwind { ; RV64I-LABEL: zext_srlw_zext_aext: ; RV64I: # %bb.0: -; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: srl a0, a0, a1 ; RV64I-NEXT: slli a0, a0, 32 ; RV64I-NEXT: srli a0, a0, 32 ; RV64I-NEXT: ret @@ -1052,7 +1106,7 @@ define zeroext i32 @zext_srlw_zext_aext(i32 zeroext %a, i32 %b) nounwind { define zeroext i32 @zext_srlw_zext_sext(i32 zeroext %a, i32 signext %b) nounwind { ; RV64I-LABEL: zext_srlw_zext_sext: ; RV64I: # %bb.0: -; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: srl a0, a0, a1 ; RV64I-NEXT: slli a0, a0, 32 ; RV64I-NEXT: srli a0, a0, 32 ; RV64I-NEXT: ret @@ -1063,7 +1117,7 @@ define zeroext i32 @zext_srlw_zext_sext(i32 zeroext %a, i32 signext %b) nounwind define zeroext i32 @zext_srlw_zext_zext(i32 zeroext %a, i32 zeroext %b) nounwind { ; RV64I-LABEL: zext_srlw_zext_zext: ; RV64I: # %bb.0: -; RV64I-NEXT: srlw a0, a0, a1 +; RV64I-NEXT: srl a0, a0, a1 ; RV64I-NEXT: slli a0, a0, 32 ; RV64I-NEXT: srli a0, a0, 32 ; RV64I-NEXT: ret @@ -1071,12 +1125,14 @@ define zeroext i32 @zext_srlw_zext_zext(i32 zeroext %a, i32 zeroext %b) nounwind ret i32 %1 } -; sraw must be selected if the first operand is not sign-extended. +; TODO: sraw should be selected if the first operand is not sign-extended. If the +; first operand is sign-extended, sra is equivalent for the test cases below. define i32 @aext_sraw_aext_aext(i32 %a, i32 %b) nounwind { ; RV64I-LABEL: aext_sraw_aext_aext: ; RV64I: # %bb.0: -; RV64I-NEXT: sraw a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: sra a0, a0, a1 ; RV64I-NEXT: ret %1 = ashr i32 %a, %b ret i32 %1 @@ -1085,7 +1141,8 @@ define i32 @aext_sraw_aext_aext(i32 %a, i32 %b) nounwind { define i32 @aext_sraw_aext_sext(i32 %a, i32 signext %b) nounwind { ; RV64I-LABEL: aext_sraw_aext_sext: ; RV64I: # %bb.0: -; RV64I-NEXT: sraw a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: sra a0, a0, a1 ; RV64I-NEXT: ret %1 = ashr i32 %a, %b ret i32 %1 @@ -1094,7 +1151,8 @@ define i32 @aext_sraw_aext_sext(i32 %a, i32 signext %b) nounwind { define i32 @aext_sraw_aext_zext(i32 %a, i32 zeroext %b) nounwind { ; RV64I-LABEL: aext_sraw_aext_zext: ; RV64I: # %bb.0: -; RV64I-NEXT: sraw a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: sra a0, a0, a1 ; RV64I-NEXT: ret %1 = ashr i32 %a, %b ret i32 %1 @@ -1130,7 +1188,8 @@ define i32 @aext_sraw_sext_zext(i32 signext %a, i32 zeroext %b) nounwind { define i32 @aext_sraw_zext_aext(i32 zeroext %a, i32 %b) nounwind { ; RV64I-LABEL: aext_sraw_zext_aext: ; RV64I: # %bb.0: -; RV64I-NEXT: sraw a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: sra a0, a0, a1 ; RV64I-NEXT: ret %1 = ashr i32 %a, %b ret i32 %1 @@ -1139,7 +1198,8 @@ define i32 @aext_sraw_zext_aext(i32 zeroext %a, i32 %b) nounwind { define i32 @aext_sraw_zext_sext(i32 zeroext %a, i32 signext %b) nounwind { ; RV64I-LABEL: aext_sraw_zext_sext: ; RV64I: # %bb.0: -; RV64I-NEXT: sraw a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: sra a0, a0, a1 ; RV64I-NEXT: ret %1 = ashr i32 %a, %b ret i32 %1 @@ -1148,7 +1208,8 @@ define i32 @aext_sraw_zext_sext(i32 zeroext %a, i32 signext %b) nounwind { define i32 @aext_sraw_zext_zext(i32 zeroext %a, i32 zeroext %b) nounwind { ; RV64I-LABEL: aext_sraw_zext_zext: ; RV64I: # %bb.0: -; RV64I-NEXT: sraw a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: sra a0, a0, a1 ; RV64I-NEXT: ret %1 = ashr i32 %a, %b ret i32 %1 @@ -1157,7 +1218,8 @@ define i32 @aext_sraw_zext_zext(i32 zeroext %a, i32 zeroext %b) nounwind { define signext i32 @sext_sraw_aext_aext(i32 %a, i32 %b) nounwind { ; RV64I-LABEL: sext_sraw_aext_aext: ; RV64I: # %bb.0: -; RV64I-NEXT: sraw a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: sra a0, a0, a1 ; RV64I-NEXT: ret %1 = ashr i32 %a, %b ret i32 %1 @@ -1166,7 +1228,8 @@ define signext i32 @sext_sraw_aext_aext(i32 %a, i32 %b) nounwind { define signext i32 @sext_sraw_aext_sext(i32 %a, i32 signext %b) nounwind { ; RV64I-LABEL: sext_sraw_aext_sext: ; RV64I: # %bb.0: -; RV64I-NEXT: sraw a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: sra a0, a0, a1 ; RV64I-NEXT: ret %1 = ashr i32 %a, %b ret i32 %1 @@ -1175,7 +1238,8 @@ define signext i32 @sext_sraw_aext_sext(i32 %a, i32 signext %b) nounwind { define signext i32 @sext_sraw_aext_zext(i32 %a, i32 zeroext %b) nounwind { ; RV64I-LABEL: sext_sraw_aext_zext: ; RV64I: # %bb.0: -; RV64I-NEXT: sraw a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: sra a0, a0, a1 ; RV64I-NEXT: ret %1 = ashr i32 %a, %b ret i32 %1 @@ -1211,7 +1275,8 @@ define signext i32 @sext_sraw_sext_zext(i32 signext %a, i32 zeroext %b) nounwind define signext i32 @sext_sraw_zext_aext(i32 zeroext %a, i32 %b) nounwind { ; RV64I-LABEL: sext_sraw_zext_aext: ; RV64I: # %bb.0: -; RV64I-NEXT: sraw a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: sra a0, a0, a1 ; RV64I-NEXT: ret %1 = ashr i32 %a, %b ret i32 %1 @@ -1220,7 +1285,8 @@ define signext i32 @sext_sraw_zext_aext(i32 zeroext %a, i32 %b) nounwind { define signext i32 @sext_sraw_zext_sext(i32 zeroext %a, i32 signext %b) nounwind { ; RV64I-LABEL: sext_sraw_zext_sext: ; RV64I: # %bb.0: -; RV64I-NEXT: sraw a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: sra a0, a0, a1 ; RV64I-NEXT: ret %1 = ashr i32 %a, %b ret i32 %1 @@ -1229,7 +1295,8 @@ define signext i32 @sext_sraw_zext_sext(i32 zeroext %a, i32 signext %b) nounwind define signext i32 @sext_sraw_zext_zext(i32 zeroext %a, i32 zeroext %b) nounwind { ; RV64I-LABEL: sext_sraw_zext_zext: ; RV64I: # %bb.0: -; RV64I-NEXT: sraw a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: sra a0, a0, a1 ; RV64I-NEXT: ret %1 = ashr i32 %a, %b ret i32 %1 @@ -1238,7 +1305,8 @@ define signext i32 @sext_sraw_zext_zext(i32 zeroext %a, i32 zeroext %b) nounwind define zeroext i32 @zext_sraw_aext_aext(i32 %a, i32 %b) nounwind { ; RV64I-LABEL: zext_sraw_aext_aext: ; RV64I: # %bb.0: -; RV64I-NEXT: sraw a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: sra a0, a0, a1 ; RV64I-NEXT: slli a0, a0, 32 ; RV64I-NEXT: srli a0, a0, 32 ; RV64I-NEXT: ret @@ -1249,7 +1317,8 @@ define zeroext i32 @zext_sraw_aext_aext(i32 %a, i32 %b) nounwind { define zeroext i32 @zext_sraw_aext_sext(i32 %a, i32 signext %b) nounwind { ; RV64I-LABEL: zext_sraw_aext_sext: ; RV64I: # %bb.0: -; RV64I-NEXT: sraw a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: sra a0, a0, a1 ; RV64I-NEXT: slli a0, a0, 32 ; RV64I-NEXT: srli a0, a0, 32 ; RV64I-NEXT: ret @@ -1260,7 +1329,8 @@ define zeroext i32 @zext_sraw_aext_sext(i32 %a, i32 signext %b) nounwind { define zeroext i32 @zext_sraw_aext_zext(i32 %a, i32 zeroext %b) nounwind { ; RV64I-LABEL: zext_sraw_aext_zext: ; RV64I: # %bb.0: -; RV64I-NEXT: sraw a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: sra a0, a0, a1 ; RV64I-NEXT: slli a0, a0, 32 ; RV64I-NEXT: srli a0, a0, 32 ; RV64I-NEXT: ret @@ -1304,7 +1374,8 @@ define zeroext i32 @zext_sraw_sext_zext(i32 signext %a, i32 zeroext %b) nounwind define zeroext i32 @zext_sraw_zext_aext(i32 zeroext %a, i32 %b) nounwind { ; RV64I-LABEL: zext_sraw_zext_aext: ; RV64I: # %bb.0: -; RV64I-NEXT: sraw a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: sra a0, a0, a1 ; RV64I-NEXT: slli a0, a0, 32 ; RV64I-NEXT: srli a0, a0, 32 ; RV64I-NEXT: ret @@ -1315,7 +1386,8 @@ define zeroext i32 @zext_sraw_zext_aext(i32 zeroext %a, i32 %b) nounwind { define zeroext i32 @zext_sraw_zext_sext(i32 zeroext %a, i32 signext %b) nounwind { ; RV64I-LABEL: zext_sraw_zext_sext: ; RV64I: # %bb.0: -; RV64I-NEXT: sraw a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: sra a0, a0, a1 ; RV64I-NEXT: slli a0, a0, 32 ; RV64I-NEXT: srli a0, a0, 32 ; RV64I-NEXT: ret @@ -1326,7 +1398,8 @@ define zeroext i32 @zext_sraw_zext_sext(i32 zeroext %a, i32 signext %b) nounwind define zeroext i32 @zext_sraw_zext_zext(i32 zeroext %a, i32 zeroext %b) nounwind { ; RV64I-LABEL: zext_sraw_zext_zext: ; RV64I: # %bb.0: -; RV64I-NEXT: sraw a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: sra a0, a0, a1 ; RV64I-NEXT: slli a0, a0, 32 ; RV64I-NEXT: srli a0, a0, 32 ; RV64I-NEXT: ret diff --git a/test/CodeGen/RISCV/rv64i-tricky-shifts.ll b/test/CodeGen/RISCV/rv64i-tricky-shifts.ll new file mode 100644 index 00000000000..73eeed7553c --- /dev/null +++ b/test/CodeGen/RISCV/rv64i-tricky-shifts.ll @@ -0,0 +1,44 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV64I + +; These tests must not compile to sllw/srlw/sraw, as this would be semantically +; incorrect in the case that %b holds a value between 32 and 63. Selection +; patterns might make the mistake of assuming that a (sext_inreg foo, i32) can +; only be produced when sign-extending an i32 type. + +define i64 @tricky_shl(i64 %a, i64 %b) { +; RV64I-LABEL: tricky_shl: +; RV64I: # %bb.0: +; RV64I-NEXT: sll a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: ret + %1 = shl i64 %a, %b + %2 = shl i64 %1, 32 + %3 = ashr i64 %2, 32 + ret i64 %3 +} + +define i64 @tricky_lshr(i64 %a, i64 %b) { +; RV64I-LABEL: tricky_lshr: +; RV64I: # %bb.0: +; RV64I-NEXT: slli a0, a0, 32 +; RV64I-NEXT: srli a0, a0, 32 +; RV64I-NEXT: srl a0, a0, a1 +; RV64I-NEXT: ret + %1 = and i64 %a, 4294967295 + %2 = lshr i64 %1, %b + ret i64 %2 +} + +define i64 @tricky_ashr(i64 %a, i64 %b) { +; RV64I-LABEL: tricky_ashr: +; RV64I: # %bb.0: +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: sra a0, a0, a1 +; RV64I-NEXT: ret + %1 = shl i64 %a, 32 + %2 = ashr i64 %1, 32 + %3 = ashr i64 %2, %b + ret i64 %3 +}