Index: llvm/lib/Target/RISCV/RISCVInstrInfo.td =================================================================== --- llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -1201,6 +1201,7 @@ return N->hasOneUse(); }]>; +def and_oneuse : binop_oneuse; def add_oneuse : binop_oneuse; def mul_oneuse : binop_oneuse; @@ -1238,6 +1239,13 @@ def : PatGprUimmLog2XLen; def : PatGprUimmLog2XLen; +// negate of low bit can be done via two (compressible) shifts. The negate +// is never compressible since rs1 and rd can't be the same register. +let Predicates = [IsRV64, HasStdExtC] in { +def : Pat<(XLenVT (sub 0x0, (and_oneuse GPR:$rs, 0x1))), + (SRAI (SLLI $rs, 63), 63)>; +} + // AND with leading/trailing ones mask exceeding simm32/simm12. def : Pat<(i64 (and GPR:$rs, LeadingOnesMask:$mask)), (SLLI (SRLI $rs, LeadingOnesMask:$mask), LeadingOnesMask:$mask)>; Index: llvm/test/CodeGen/RISCV/short-foward-branch-opt.ll =================================================================== --- llvm/test/CodeGen/RISCV/short-foward-branch-opt.ll +++ llvm/test/CodeGen/RISCV/short-foward-branch-opt.ll @@ -171,8 +171,8 @@ define i16 @select_xor_1(i16 %A, i8 %cond) { ; NOSFB-LABEL: select_xor_1: ; NOSFB: # %bb.0: # %entry -; NOSFB-NEXT: andi a1, a1, 1 -; NOSFB-NEXT: negw a1, a1 +; NOSFB-NEXT: slli a1, a1, 63 +; NOSFB-NEXT: srai a1, a1, 63 ; NOSFB-NEXT: andi a1, a1, 43 ; NOSFB-NEXT: xor a0, a0, a1 ; NOSFB-NEXT: ret @@ -199,8 +199,8 @@ define i16 @select_xor_1b(i16 %A, i8 %cond) { ; NOSFB-LABEL: select_xor_1b: ; NOSFB: # %bb.0: # %entry -; NOSFB-NEXT: andi a1, a1, 1 -; NOSFB-NEXT: negw a1, a1 +; NOSFB-NEXT: slli a1, a1, 63 +; NOSFB-NEXT: srai a1, a1, 63 ; NOSFB-NEXT: andi a1, a1, 43 ; NOSFB-NEXT: xor a0, a0, a1 ; NOSFB-NEXT: ret @@ -225,8 +225,8 @@ define i32 @select_xor_2(i32 %A, i32 %B, i8 %cond) { ; NOSFB-LABEL: select_xor_2: ; NOSFB: # %bb.0: # %entry -; NOSFB-NEXT: andi a2, a2, 1 -; NOSFB-NEXT: neg a2, a2 +; NOSFB-NEXT: slli a2, a2, 63 +; NOSFB-NEXT: srai a2, a2, 63 ; NOSFB-NEXT: and a1, a1, a2 ; NOSFB-NEXT: xor a0, a0, a1 ; NOSFB-NEXT: ret @@ -253,8 +253,8 @@ define i32 @select_xor_2b(i32 %A, i32 %B, i8 %cond) { ; NOSFB-LABEL: select_xor_2b: ; NOSFB: # %bb.0: # %entry -; NOSFB-NEXT: andi a2, a2, 1 -; NOSFB-NEXT: neg a2, a2 +; NOSFB-NEXT: slli a2, a2, 63 +; NOSFB-NEXT: srai a2, a2, 63 ; NOSFB-NEXT: and a1, a1, a2 ; NOSFB-NEXT: xor a0, a0, a1 ; NOSFB-NEXT: ret @@ -279,8 +279,8 @@ define i32 @select_or(i32 %A, i32 %B, i8 %cond) { ; NOSFB-LABEL: select_or: ; NOSFB: # %bb.0: # %entry -; NOSFB-NEXT: andi a2, a2, 1 -; NOSFB-NEXT: neg a2, a2 +; NOSFB-NEXT: slli a2, a2, 63 +; NOSFB-NEXT: srai a2, a2, 63 ; NOSFB-NEXT: and a1, a1, a2 ; NOSFB-NEXT: or a0, a0, a1 ; NOSFB-NEXT: ret @@ -307,8 +307,8 @@ define i32 @select_or_b(i32 %A, i32 %B, i8 %cond) { ; NOSFB-LABEL: select_or_b: ; NOSFB: # %bb.0: # %entry -; NOSFB-NEXT: andi a2, a2, 1 -; NOSFB-NEXT: neg a2, a2 +; NOSFB-NEXT: slli a2, a2, 63 +; NOSFB-NEXT: srai a2, a2, 63 ; NOSFB-NEXT: and a1, a1, a2 ; NOSFB-NEXT: or a0, a0, a1 ; NOSFB-NEXT: ret @@ -333,8 +333,8 @@ define i32 @select_or_1(i32 %A, i32 %B, i32 %cond) { ; NOSFB-LABEL: select_or_1: ; NOSFB: # %bb.0: # %entry -; NOSFB-NEXT: andi a2, a2, 1 -; NOSFB-NEXT: neg a2, a2 +; NOSFB-NEXT: slli a2, a2, 63 +; NOSFB-NEXT: srai a2, a2, 63 ; NOSFB-NEXT: and a1, a1, a2 ; NOSFB-NEXT: or a0, a0, a1 ; NOSFB-NEXT: ret @@ -361,8 +361,8 @@ define i32 @select_or_1b(i32 %A, i32 %B, i32 %cond) { ; NOSFB-LABEL: select_or_1b: ; NOSFB: # %bb.0: # %entry -; NOSFB-NEXT: andi a2, a2, 1 -; NOSFB-NEXT: neg a2, a2 +; NOSFB-NEXT: slli a2, a2, 63 +; NOSFB-NEXT: srai a2, a2, 63 ; NOSFB-NEXT: and a1, a1, a2 ; NOSFB-NEXT: or a0, a0, a1 ; NOSFB-NEXT: ret