Skip to content

Commit

Permalink
[RISCV] Add isel patterns for SBCLRI/SBSETI/SBINVI(W) instruction
Browse files Browse the repository at this point in the history
We can use these instructions for single bit immediates that are too large for ANDI/ORI/CLRI.

The _10 test cases are to make sure that we still use ANDI/ORI/CLRI for small immediates.

Differential Revision: https://reviews.llvm.org/D92262
  • Loading branch information
topperc committed Dec 8, 2020
1 parent abd80ac commit 98bca0a
Show file tree
Hide file tree
Showing 5 changed files with 916 additions and 10 deletions.
53 changes: 53 additions & 0 deletions llvm/lib/Target/RISCV/RISCVInstrInfoB.td
Expand Up @@ -59,6 +59,44 @@ def ImmROTL2RW : SDNodeXForm<imm, [{
N->getValueType(0));
}]>;

// Checks if this mask has a single 0 bit and cannot be used with ANDI.
def SBCLRMask : ImmLeaf<XLenVT, [{
if (Subtarget->is64Bit())
return !isInt<12>(Imm) && isPowerOf2_64(~Imm);
return !isInt<12>(Imm) && isPowerOf2_32(~Imm);
}]>;

// Checks if this mask has a single 1 bit and cannot be used with ORI/XORI.
def SBSETINVMask : ImmLeaf<XLenVT, [{
if (Subtarget->is64Bit())
return !isInt<12>(Imm) && isPowerOf2_64(Imm);
return !isInt<12>(Imm) && isPowerOf2_32(Imm);
}]>;

def SBCLRXForm : SDNodeXForm<imm, [{
// Find the lowest 0.
return CurDAG->getTargetConstant(N->getAPIntValue().countTrailingOnes(),
SDLoc(N), N->getValueType(0));
}]>;

def SBSETINVXForm : SDNodeXForm<imm, [{
// Find the lowest 1.
return CurDAG->getTargetConstant(N->getAPIntValue().countTrailingZeros(),
SDLoc(N), N->getValueType(0));
}]>;

// Similar to above, but makes sure the immediate has 33 sign bits. When used
// with an AND/OR/XOR where the other operand has at least 33 sign bits, the
// result will have 33 sign bits. This can match SBCLRIW/SBSETIW/SBINVIW.
def SBCLRWMask : ImmLeaf<i64, [{
// After checking the sign bits, truncate to 32 bits for power of 2 check.
return isInt<32>(Imm) && !isInt<12>(Imm) && isPowerOf2_32(~Imm);
}]>;

def SBSETINVWMask : ImmLeaf<i64, [{
return isInt<32>(Imm) && !isInt<12>(Imm) && isPowerOf2_32(Imm);
}]>;

//===----------------------------------------------------------------------===//
// Instruction class templates
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -692,6 +730,13 @@ def : Pat<(and (shiftop<srl> GPR:$rs1, GPR:$rs2), 1),

def : Pat<(shiftop<shl> 1, GPR:$rs2),
(SBSET X0, GPR:$rs2)>;

def : Pat<(and GPR:$rs1, SBCLRMask:$mask),
(SBCLRI GPR:$rs1, (SBCLRXForm imm:$mask))>;
def : Pat<(or GPR:$rs1, SBSETINVMask:$mask),
(SBSETI GPR:$rs1, (SBSETINVXForm imm:$mask))>;
def : Pat<(xor GPR:$rs1, SBSETINVMask:$mask),
(SBINVI GPR:$rs1, (SBSETINVXForm imm:$mask))>;
}

let Predicates = [HasStdExtZbb] in {
Expand Down Expand Up @@ -902,6 +947,14 @@ def : Pat<(and (riscv_srlw GPR:$rs1, GPR:$rs2), 1),

def : Pat<(riscv_sllw 1, GPR:$rs2),
(SBSETW X0, GPR:$rs2)>;

def : Pat<(and (assertsexti32 GPR:$rs1), SBCLRWMask:$mask),
(SBCLRIW GPR:$rs1, (SBCLRXForm imm:$mask))>;
def : Pat<(or (assertsexti32 GPR:$rs1), SBSETINVWMask:$mask),
(SBSETIW GPR:$rs1, (SBSETINVXForm imm:$mask))>;
def : Pat<(xor (assertsexti32 GPR:$rs1), SBSETINVWMask:$mask),
(SBINVIW GPR:$rs1, (SBSETINVXForm imm:$mask))>;

} // Predicates = [HasStdExtZbs, IsRV64]

let Predicates = [HasStdExtZbb, IsRV64] in {
Expand Down
242 changes: 242 additions & 0 deletions llvm/test/CodeGen/RISCV/rv32Zbs.ll
Expand Up @@ -485,3 +485,245 @@ define i64 @sbexti_i64(i64 %a) nounwind {
%and = and i64 %shr, 1
ret i64 %and
}

define i32 @sbclri_i32_10(i32 %a) nounwind {
; RV32I-LABEL: sbclri_i32_10:
; RV32I: # %bb.0:
; RV32I-NEXT: andi a0, a0, -1025
; RV32I-NEXT: ret
;
; RV32IB-LABEL: sbclri_i32_10:
; RV32IB: # %bb.0:
; RV32IB-NEXT: andi a0, a0, -1025
; RV32IB-NEXT: ret
;
; RV32IBS-LABEL: sbclri_i32_10:
; RV32IBS: # %bb.0:
; RV32IBS-NEXT: andi a0, a0, -1025
; RV32IBS-NEXT: ret
%and = and i32 %a, -1025
ret i32 %and
}

define i32 @sbclri_i32_11(i32 %a) nounwind {
; RV32I-LABEL: sbclri_i32_11:
; RV32I: # %bb.0:
; RV32I-NEXT: lui a1, 1048575
; RV32I-NEXT: addi a1, a1, 2047
; RV32I-NEXT: and a0, a0, a1
; RV32I-NEXT: ret
;
; RV32IB-LABEL: sbclri_i32_11:
; RV32IB: # %bb.0:
; RV32IB-NEXT: sbclri a0, a0, 11
; RV32IB-NEXT: ret
;
; RV32IBS-LABEL: sbclri_i32_11:
; RV32IBS: # %bb.0:
; RV32IBS-NEXT: sbclri a0, a0, 11
; RV32IBS-NEXT: ret
%and = and i32 %a, -2049
ret i32 %and
}

define i32 @sbclri_i32_30(i32 %a) nounwind {
; RV32I-LABEL: sbclri_i32_30:
; RV32I: # %bb.0:
; RV32I-NEXT: lui a1, 786432
; RV32I-NEXT: addi a1, a1, -1
; RV32I-NEXT: and a0, a0, a1
; RV32I-NEXT: ret
;
; RV32IB-LABEL: sbclri_i32_30:
; RV32IB: # %bb.0:
; RV32IB-NEXT: sbclri a0, a0, 30
; RV32IB-NEXT: ret
;
; RV32IBS-LABEL: sbclri_i32_30:
; RV32IBS: # %bb.0:
; RV32IBS-NEXT: sbclri a0, a0, 30
; RV32IBS-NEXT: ret
%and = and i32 %a, -1073741825
ret i32 %and
}

define i32 @sbclri_i32_31(i32 %a) nounwind {
; RV32I-LABEL: sbclri_i32_31:
; RV32I: # %bb.0:
; RV32I-NEXT: lui a1, 524288
; RV32I-NEXT: addi a1, a1, -1
; RV32I-NEXT: and a0, a0, a1
; RV32I-NEXT: ret
;
; RV32IB-LABEL: sbclri_i32_31:
; RV32IB: # %bb.0:
; RV32IB-NEXT: sbclri a0, a0, 31
; RV32IB-NEXT: ret
;
; RV32IBS-LABEL: sbclri_i32_31:
; RV32IBS: # %bb.0:
; RV32IBS-NEXT: sbclri a0, a0, 31
; RV32IBS-NEXT: ret
%and = and i32 %a, -2147483649
ret i32 %and
}

define i32 @sbseti_i32_10(i32 %a) nounwind {
; RV32I-LABEL: sbseti_i32_10:
; RV32I: # %bb.0:
; RV32I-NEXT: ori a0, a0, 1024
; RV32I-NEXT: ret
;
; RV32IB-LABEL: sbseti_i32_10:
; RV32IB: # %bb.0:
; RV32IB-NEXT: ori a0, a0, 1024
; RV32IB-NEXT: ret
;
; RV32IBS-LABEL: sbseti_i32_10:
; RV32IBS: # %bb.0:
; RV32IBS-NEXT: ori a0, a0, 1024
; RV32IBS-NEXT: ret
%or = or i32 %a, 1024
ret i32 %or
}

define i32 @sbseti_i32_11(i32 %a) nounwind {
; RV32I-LABEL: sbseti_i32_11:
; RV32I: # %bb.0:
; RV32I-NEXT: lui a1, 1
; RV32I-NEXT: addi a1, a1, -2048
; RV32I-NEXT: or a0, a0, a1
; RV32I-NEXT: ret
;
; RV32IB-LABEL: sbseti_i32_11:
; RV32IB: # %bb.0:
; RV32IB-NEXT: sbseti a0, a0, 11
; RV32IB-NEXT: ret
;
; RV32IBS-LABEL: sbseti_i32_11:
; RV32IBS: # %bb.0:
; RV32IBS-NEXT: sbseti a0, a0, 11
; RV32IBS-NEXT: ret
%or = or i32 %a, 2048
ret i32 %or
}

define i32 @sbseti_i32_30(i32 %a) nounwind {
; RV32I-LABEL: sbseti_i32_30:
; RV32I: # %bb.0:
; RV32I-NEXT: lui a1, 262144
; RV32I-NEXT: or a0, a0, a1
; RV32I-NEXT: ret
;
; RV32IB-LABEL: sbseti_i32_30:
; RV32IB: # %bb.0:
; RV32IB-NEXT: sbseti a0, a0, 30
; RV32IB-NEXT: ret
;
; RV32IBS-LABEL: sbseti_i32_30:
; RV32IBS: # %bb.0:
; RV32IBS-NEXT: sbseti a0, a0, 30
; RV32IBS-NEXT: ret
%or = or i32 %a, 1073741824
ret i32 %or
}

define i32 @sbseti_i32_31(i32 %a) nounwind {
; RV32I-LABEL: sbseti_i32_31:
; RV32I: # %bb.0:
; RV32I-NEXT: lui a1, 524288
; RV32I-NEXT: or a0, a0, a1
; RV32I-NEXT: ret
;
; RV32IB-LABEL: sbseti_i32_31:
; RV32IB: # %bb.0:
; RV32IB-NEXT: sbseti a0, a0, 31
; RV32IB-NEXT: ret
;
; RV32IBS-LABEL: sbseti_i32_31:
; RV32IBS: # %bb.0:
; RV32IBS-NEXT: sbseti a0, a0, 31
; RV32IBS-NEXT: ret
%or = or i32 %a, 2147483648
ret i32 %or
}

define i32 @sbinvi_i32_10(i32 %a) nounwind {
; RV32I-LABEL: sbinvi_i32_10:
; RV32I: # %bb.0:
; RV32I-NEXT: xori a0, a0, 1024
; RV32I-NEXT: ret
;
; RV32IB-LABEL: sbinvi_i32_10:
; RV32IB: # %bb.0:
; RV32IB-NEXT: xori a0, a0, 1024
; RV32IB-NEXT: ret
;
; RV32IBS-LABEL: sbinvi_i32_10:
; RV32IBS: # %bb.0:
; RV32IBS-NEXT: xori a0, a0, 1024
; RV32IBS-NEXT: ret
%xor = xor i32 %a, 1024
ret i32 %xor
}

define i32 @sbinvi_i32_11(i32 %a) nounwind {
; RV32I-LABEL: sbinvi_i32_11:
; RV32I: # %bb.0:
; RV32I-NEXT: lui a1, 1
; RV32I-NEXT: addi a1, a1, -2048
; RV32I-NEXT: xor a0, a0, a1
; RV32I-NEXT: ret
;
; RV32IB-LABEL: sbinvi_i32_11:
; RV32IB: # %bb.0:
; RV32IB-NEXT: sbinvi a0, a0, 11
; RV32IB-NEXT: ret
;
; RV32IBS-LABEL: sbinvi_i32_11:
; RV32IBS: # %bb.0:
; RV32IBS-NEXT: sbinvi a0, a0, 11
; RV32IBS-NEXT: ret
%xor = xor i32 %a, 2048
ret i32 %xor
}

define i32 @sbinvi_i32_30(i32 %a) nounwind {
; RV32I-LABEL: sbinvi_i32_30:
; RV32I: # %bb.0:
; RV32I-NEXT: lui a1, 262144
; RV32I-NEXT: xor a0, a0, a1
; RV32I-NEXT: ret
;
; RV32IB-LABEL: sbinvi_i32_30:
; RV32IB: # %bb.0:
; RV32IB-NEXT: sbinvi a0, a0, 30
; RV32IB-NEXT: ret
;
; RV32IBS-LABEL: sbinvi_i32_30:
; RV32IBS: # %bb.0:
; RV32IBS-NEXT: sbinvi a0, a0, 30
; RV32IBS-NEXT: ret
%xor = xor i32 %a, 1073741824
ret i32 %xor
}

define i32 @sbinvi_i32_31(i32 %a) nounwind {
; RV32I-LABEL: sbinvi_i32_31:
; RV32I: # %bb.0:
; RV32I-NEXT: lui a1, 524288
; RV32I-NEXT: xor a0, a0, a1
; RV32I-NEXT: ret
;
; RV32IB-LABEL: sbinvi_i32_31:
; RV32IB: # %bb.0:
; RV32IB-NEXT: sbinvi a0, a0, 31
; RV32IB-NEXT: ret
;
; RV32IBS-LABEL: sbinvi_i32_31:
; RV32IBS: # %bb.0:
; RV32IBS-NEXT: sbinvi a0, a0, 31
; RV32IBS-NEXT: ret
%xor = xor i32 %a, 2147483648
ret i32 %xor
}
12 changes: 5 additions & 7 deletions llvm/test/CodeGen/RISCV/rv32Zbt.ll
Expand Up @@ -417,14 +417,12 @@ define i64 @fshr_i64(i64 %a, i64 %b, i64 %c) nounwind {
; RV32IB-NEXT: mv t0, zero
; RV32IB-NEXT: bgez a5, .LBB7_8
; RV32IB-NEXT: .LBB7_5:
; RV32IB-NEXT: fsri a1, a0, a1, 31
; RV32IB-NEXT: sll a1, a1, t1
; RV32IB-NEXT: sub a2, a6, a2
; RV32IB-NEXT: lui a5, 524288
; RV32IB-NEXT: addi a5, a5, -1
; RV32IB-NEXT: and a5, a0, a5
; RV32IB-NEXT: srl a2, a5, a2
; RV32IB-NEXT: fsri a0, a0, a1, 31
; RV32IB-NEXT: sll a0, a0, t1
; RV32IB-NEXT: or a1, a0, a2
; RV32IB-NEXT: sbclri a0, a0, 31
; RV32IB-NEXT: srl a0, a0, a2
; RV32IB-NEXT: or a1, a1, a0
; RV32IB-NEXT: or a0, t0, a7
; RV32IB-NEXT: bgez t2, .LBB7_9
; RV32IB-NEXT: .LBB7_6:
Expand Down
4 changes: 1 addition & 3 deletions llvm/test/CodeGen/RISCV/rv64Zbb.ll
Expand Up @@ -178,9 +178,7 @@ define i64 @sroiw_bug(i64 %a) nounwind {
; RV64IB-LABEL: sroiw_bug:
; RV64IB: # %bb.0:
; RV64IB-NEXT: srli a0, a0, 1
; RV64IB-NEXT: addi a1, zero, 1
; RV64IB-NEXT: slli a1, a1, 31
; RV64IB-NEXT: or a0, a0, a1
; RV64IB-NEXT: sbseti a0, a0, 31
; RV64IB-NEXT: ret
;
; RV64IBB-LABEL: sroiw_bug:
Expand Down

0 comments on commit 98bca0a

Please sign in to comment.