Index: lib/Target/RISCV/RISCVInstrInfo.td =================================================================== --- lib/Target/RISCV/RISCVInstrInfo.td +++ lib/Target/RISCV/RISCVInstrInfo.td @@ -205,6 +205,12 @@ // Standalone (codegen-only) immleaf patterns. def simm32 : ImmLeaf(Imm);}]>; def simm32hi20 : ImmLeaf(Imm);}]>; +// A mask value that won't affect significant shift bits. +def immshiftxlen : ImmLeafis64Bit()) + return countTrailingOnes(Imm) >= 6; + return countTrailingOnes(Imm) >= 5; +}]>; // Addressing modes. // Necessary because a frameindex can't be matched directly in a pattern. @@ -646,13 +652,24 @@ def : PatGprSimm12; def : PatGprGpr; def : PatGprSimm12; -def : PatGprGpr; def : PatGprUimmLog2XLen; -def : PatGprGpr; def : PatGprUimmLog2XLen; -def : PatGprGpr; def : PatGprUimmLog2XLen; +// Match both a plain shift and one where the shift amount is masked (this is +// typically introduced when the legalizer promotes the shift amount and +// zero-extends it). For RISC-V, the mask is unnecessary as shifts in the base +// ISA only read the least significant 5 bits (RV32I) or 6 bits (RV64I). +multiclass VarShiftXLenPat { + def : Pat<(ShiftOp GPR:$rs1, GPR:$rs2), (Inst GPR:$rs1, GPR:$rs2)>; + def : Pat<(ShiftOp GPR:$rs1, (and GPR:$rs2, immshiftxlen)), + (Inst GPR:$rs1, GPR:$rs2)>; +} + +defm : VarShiftXLenPat; +defm : VarShiftXLenPat; +defm : VarShiftXLenPat; + /// FrameIndex calculations def : Pat<(add (i32 AddrFI:$Rs), simm12:$imm12), Index: test/CodeGen/RISCV/alu16.ll =================================================================== --- test/CodeGen/RISCV/alu16.ll +++ test/CodeGen/RISCV/alu16.ll @@ -6,8 +6,6 @@ ; that legalisation of these non-native types doesn't introduce unnecessary ; inefficiencies. -; TODO: it's unnecessary to mask (zero-extend) the shift amount. - define i16 @addi(i16 %a) nounwind { ; RV32I-LABEL: addi: ; RV32I: # %bb.0: @@ -122,9 +120,6 @@ define i16 @sll(i16 %a, i16 %b) nounwind { ; RV32I-LABEL: sll: ; RV32I: # %bb.0: -; RV32I-NEXT: lui a2, 16 -; RV32I-NEXT: addi a2, a2, -1 -; RV32I-NEXT: and a1, a1, a2 ; RV32I-NEXT: sll a0, a0, a1 ; RV32I-NEXT: ret %1 = shl i16 %a, %b @@ -173,7 +168,6 @@ ; RV32I: # %bb.0: ; RV32I-NEXT: lui a2, 16 ; RV32I-NEXT: addi a2, a2, -1 -; RV32I-NEXT: and a1, a1, a2 ; RV32I-NEXT: and a0, a0, a2 ; RV32I-NEXT: srl a0, a0, a1 ; RV32I-NEXT: ret @@ -184,9 +178,6 @@ define i16 @sra(i16 %a, i16 %b) nounwind { ; RV32I-LABEL: sra: ; RV32I: # %bb.0: -; RV32I-NEXT: lui a2, 16 -; RV32I-NEXT: addi a2, a2, -1 -; RV32I-NEXT: and a1, a1, a2 ; RV32I-NEXT: slli a0, a0, 16 ; RV32I-NEXT: srai a0, a0, 16 ; RV32I-NEXT: sra a0, a0, a1 Index: test/CodeGen/RISCV/alu8.ll =================================================================== --- test/CodeGen/RISCV/alu8.ll +++ test/CodeGen/RISCV/alu8.ll @@ -6,8 +6,6 @@ ; that legalisation of these non-native types doesn't introduce unnecessary ; inefficiencies. -; TODO: it's unnecessary to mask (zero-extend) the shift amount. - define i8 @addi(i8 %a) nounwind { ; RV32I-LABEL: addi: ; RV32I: # %bb.0: @@ -118,7 +116,6 @@ define i8 @sll(i8 %a, i8 %b) nounwind { ; RV32I-LABEL: sll: ; RV32I: # %bb.0: -; RV32I-NEXT: andi a1, a1, 255 ; RV32I-NEXT: sll a0, a0, a1 ; RV32I-NEXT: ret %1 = shl i8 %a, %b @@ -163,7 +160,6 @@ define i8 @srl(i8 %a, i8 %b) nounwind { ; RV32I-LABEL: srl: ; RV32I: # %bb.0: -; RV32I-NEXT: andi a1, a1, 255 ; RV32I-NEXT: andi a0, a0, 255 ; RV32I-NEXT: srl a0, a0, a1 ; RV32I-NEXT: ret @@ -174,7 +170,6 @@ define i8 @sra(i8 %a, i8 %b) nounwind { ; RV32I-LABEL: sra: ; RV32I: # %bb.0: -; RV32I-NEXT: andi a1, a1, 255 ; RV32I-NEXT: slli a0, a0, 24 ; RV32I-NEXT: srai a0, a0, 24 ; RV32I-NEXT: sra a0, a0, a1 Index: test/CodeGen/RISCV/shift-masked-shamt.ll =================================================================== --- /dev/null +++ test/CodeGen/RISCV/shift-masked-shamt.ll @@ -0,0 +1,70 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV32I + +; This test checks that unnecessary masking of shift amount operands is +; eliminated during instruction selection. The test needs to ensure that the +; masking is not removed if it may affect the shift amount. + +define i32 @sll_redundant_mask(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: sll_redundant_mask: +; RV32I: # %bb.0: +; RV32I-NEXT: sll a0, a0, a1 +; RV32I-NEXT: ret + %1 = and i32 %b, 31 + %2 = shl i32 %a, %1 + ret i32 %2 +} + +define i32 @sll_non_redundant_mask(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: sll_non_redundant_mask: +; RV32I: # %bb.0: +; RV32I-NEXT: andi a1, a1, 15 +; RV32I-NEXT: sll a0, a0, a1 +; RV32I-NEXT: ret + %1 = and i32 %b, 15 + %2 = shl i32 %a, %1 + ret i32 %2 +} + +define i32 @srl_redundant_mask(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: srl_redundant_mask: +; RV32I: # %bb.0: +; RV32I-NEXT: srl a0, a0, a1 +; RV32I-NEXT: ret + %1 = and i32 %b, 4095 + %2 = lshr i32 %a, %1 + ret i32 %2 +} + +define i32 @srl_non_redundant_mask(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: srl_non_redundant_mask: +; RV32I: # %bb.0: +; RV32I-NEXT: andi a1, a1, 7 +; RV32I-NEXT: srl a0, a0, a1 +; RV32I-NEXT: ret + %1 = and i32 %b, 7 + %2 = lshr i32 %a, %1 + ret i32 %2 +} + +define i32 @sra_redundant_mask(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: sra_redundant_mask: +; RV32I: # %bb.0: +; RV32I-NEXT: sra a0, a0, a1 +; RV32I-NEXT: ret + %1 = and i32 %b, 65535 + %2 = ashr i32 %a, %1 + ret i32 %2 +} + +define i32 @sra_non_redundant_mask(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: sra_non_redundant_mask: +; RV32I: # %bb.0: +; RV32I-NEXT: andi a1, a1, 32 +; RV32I-NEXT: sra a0, a0, a1 +; RV32I-NEXT: ret + %1 = and i32 %b, 32 + %2 = ashr i32 %a, %1 + ret i32 %2 +}