Select SRLI+SLLI for and i64 %x, imm if the imm is a leading ones mask.
It's useful in RV64 when the mask exceeds simm32 (cannot be generated by LUI).
Reviewed By: craig.topper
Differential Revision: https://reviews.llvm.org/D121598
N->getValueType(0));
}]>;
+def TrailingZeros : SDNodeXForm<imm, [{
+ return CurDAG->getTargetConstant(N->getAPIntValue().countTrailingZeros(),
+ SDLoc(N), N->getValueType(0));
+}]>;
+
def XLenSubTrailingOnes : SDNodeXForm<imm, [{
uint64_t XLen = Subtarget->getXLen();
uint64_t TrailingOnes = N->getAPIntValue().countTrailingOnes();
}]>;
// Checks if this mask is a non-empty sequence of ones starting at the
-// least significant bit with the remainder zero and exceeds simm12.
+// most/least significant bit with the remainder zero and exceeds simm32/simm12.
+def LeadingOnesMask : PatLeaf<(imm), [{
+ if (!N->hasOneUse())
+ return false;
+ return !isInt<32>(N->getSExtValue()) && isMask_64(~N->getSExtValue());
+}], TrailingZeros>;
+
def TrailingOnesMask : PatLeaf<(imm), [{
if (!N->hasOneUse())
return false;
def : PatGprUimmLog2XLen<srl, SRLI>;
def : PatGprUimmLog2XLen<sra, SRAI>;
-// AND with trailing ones mask exceeding simm12.
+// AND with leading/trailing ones mask exceeding simm32/simm12.
+def : Pat<(i64 (and GPR:$rs, LeadingOnesMask:$mask)),
+ (SLLI (SRLI $rs, LeadingOnesMask:$mask), LeadingOnesMask:$mask)>;
def : Pat<(XLenVT (and GPR:$rs, TrailingOnesMask:$mask)),
(SRLI (SLLI $rs, TrailingOnesMask:$mask), TrailingOnesMask:$mask)>;
ret i64 %a
}
+; Test for handling of AND with constant. If this constant exceeds simm32 and
+; also is a non-empty sequence of ones starting at the most significant bit
+; with the remainder zero, we can replace it with SRLI + SLLI.
+
+define i32 @and32_0x7ffff000(i32 %x) {
+; RV32I-LABEL: and32_0x7ffff000:
+; RV32I: # %bb.0:
+; RV32I-NEXT: lui a1, 524287
+; RV32I-NEXT: and a0, a0, a1
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: and32_0x7ffff000:
+; RV64I: # %bb.0:
+; RV64I-NEXT: lui a1, 524287
+; RV64I-NEXT: and a0, a0, a1
+; RV64I-NEXT: ret
+ %a = and i32 %x, 2147479552
+ ret i32 %a
+}
+
define i32 @and32_0xfffff000(i32 %x) {
; RV32I-LABEL: and32_0xfffff000:
; RV32I: # %bb.0:
%a = and i32 %x, -1536
ret i32 %a
}
+
+define i64 @and64_0x7ffffffffffff000(i64 %x) {
+; RV32I-LABEL: and64_0x7ffffffffffff000:
+; RV32I: # %bb.0:
+; RV32I-NEXT: lui a2, 1048575
+; RV32I-NEXT: and a0, a0, a2
+; RV32I-NEXT: slli a1, a1, 1
+; RV32I-NEXT: srli a1, a1, 1
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: and64_0x7ffffffffffff000:
+; RV64I: # %bb.0:
+; RV64I-NEXT: lui a1, 1048574
+; RV64I-NEXT: srli a1, a1, 1
+; RV64I-NEXT: and a0, a0, a1
+; RV64I-NEXT: ret
+ %a = and i64 %x, 9223372036854771712
+ ret i64 %a
+}
+
+define i64 @and64_0xfffffffffffff000(i64 %x) {
+; RV32I-LABEL: and64_0xfffffffffffff000:
+; RV32I: # %bb.0:
+; RV32I-NEXT: lui a2, 1048575
+; RV32I-NEXT: and a0, a0, a2
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: and64_0xfffffffffffff000:
+; RV64I: # %bb.0:
+; RV64I-NEXT: lui a1, 1048575
+; RV64I-NEXT: and a0, a0, a1
+; RV64I-NEXT: ret
+ %a = and i64 %x, -4096
+ ret i64 %a
+}
+
+define i64 @and64_0xfffffffffffffa00(i64 %x) {
+; RV32I-LABEL: and64_0xfffffffffffffa00:
+; RV32I: # %bb.0:
+; RV32I-NEXT: andi a0, a0, -1536
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: and64_0xfffffffffffffa00:
+; RV64I: # %bb.0:
+; RV64I-NEXT: andi a0, a0, -1536
+; RV64I-NEXT: ret
+ %a = and i64 %x, -1536
+ ret i64 %a
+}
+
+define i64 @and64_0xffffffff00000000(i64 %x) {
+; RV32I-LABEL: and64_0xffffffff00000000:
+; RV32I: # %bb.0:
+; RV32I-NEXT: li a0, 0
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: and64_0xffffffff00000000:
+; RV64I: # %bb.0:
+; RV64I-NEXT: srli a0, a0, 32
+; RV64I-NEXT: slli a0, a0, 32
+; RV64I-NEXT: ret
+ %a = and i64 %x, -4294967296
+ ret i64 %a
+}
+
+define i64 @and64_0x7fffffff00000000(i64 %x) {
+; RV32I-LABEL: and64_0x7fffffff00000000:
+; RV32I: # %bb.0:
+; RV32I-NEXT: slli a0, a1, 1
+; RV32I-NEXT: srli a1, a0, 1
+; RV32I-NEXT: li a0, 0
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: and64_0x7fffffff00000000:
+; RV64I: # %bb.0:
+; RV64I-NEXT: lui a1, 524288
+; RV64I-NEXT: addiw a1, a1, -1
+; RV64I-NEXT: slli a1, a1, 32
+; RV64I-NEXT: and a0, a0, a1
+; RV64I-NEXT: ret
+ %a = and i64 %x, 9223372032559808512
+ ret i64 %a
+}
+
+define i64 @and64_0xffffffff80000000(i64 %x) {
+; RV32I-LABEL: and64_0xffffffff80000000:
+; RV32I: # %bb.0:
+; RV32I-NEXT: lui a2, 524288
+; RV32I-NEXT: and a0, a0, a2
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: and64_0xffffffff80000000:
+; RV64I: # %bb.0:
+; RV64I-NEXT: lui a1, 524288
+; RV64I-NEXT: and a0, a0, a1
+; RV64I-NEXT: ret
+ %a = and i64 %x, -2147483648
+ ret i64 %a
+}
;
; RV64I-LABEL: fold_demote_s_d:
; RV64I: # %bb.0:
-; RV64I-NEXT: li a2, -1
-; RV64I-NEXT: slli a2, a2, 63
-; RV64I-NEXT: and a1, a1, a2
-; RV64I-NEXT: srli a1, a1, 32
; RV64I-NEXT: slli a0, a0, 33
; RV64I-NEXT: srli a0, a0, 33
+; RV64I-NEXT: srli a1, a1, 63
+; RV64I-NEXT: slli a1, a1, 63
+; RV64I-NEXT: srli a1, a1, 32
; RV64I-NEXT: or a0, a0, a1
; RV64I-NEXT: ret
;
;
; RV64I-LABEL: fold_demote_h_d:
; RV64I: # %bb.0:
-; RV64I-NEXT: li a2, -1
-; RV64I-NEXT: slli a2, a2, 63
-; RV64I-NEXT: and a1, a1, a2
-; RV64I-NEXT: srli a1, a1, 48
; RV64I-NEXT: slli a0, a0, 49
; RV64I-NEXT: srli a0, a0, 49
+; RV64I-NEXT: srli a1, a1, 63
+; RV64I-NEXT: slli a1, a1, 63
+; RV64I-NEXT: srli a1, a1, 48
; RV64I-NEXT: or a0, a0, a1
; RV64I-NEXT: ret
;
;
; RV64IFD-LABEL: fold_demote_h_d:
; RV64IFD: # %bb.0:
-; RV64IFD-NEXT: fmv.x.w a0, fa0
-; RV64IFD-NEXT: fmv.x.d a1, fa1
-; RV64IFD-NEXT: li a2, -1
-; RV64IFD-NEXT: slli a2, a2, 63
-; RV64IFD-NEXT: and a1, a1, a2
-; RV64IFD-NEXT: srli a1, a1, 48
-; RV64IFD-NEXT: slli a0, a0, 49
-; RV64IFD-NEXT: srli a0, a0, 49
-; RV64IFD-NEXT: or a0, a0, a1
+; RV64IFD-NEXT: fmv.x.d a0, fa1
+; RV64IFD-NEXT: fmv.x.w a1, fa0
+; RV64IFD-NEXT: slli a1, a1, 49
+; RV64IFD-NEXT: srli a1, a1, 49
+; RV64IFD-NEXT: srli a0, a0, 63
+; RV64IFD-NEXT: slli a0, a0, 63
+; RV64IFD-NEXT: srli a0, a0, 48
+; RV64IFD-NEXT: or a0, a1, a0
; RV64IFD-NEXT: lui a1, 1048560
; RV64IFD-NEXT: or a0, a0, a1
; RV64IFD-NEXT: fmv.w.x fa0, a0
;
; RV64I-LABEL: fsgnj_d:
; RV64I: # %bb.0:
-; RV64I-NEXT: li a2, -1
-; RV64I-NEXT: slli a2, a2, 63
-; RV64I-NEXT: and a1, a1, a2
+; RV64I-NEXT: srli a1, a1, 63
+; RV64I-NEXT: slli a1, a1, 63
; RV64I-NEXT: slli a0, a0, 1
; RV64I-NEXT: srli a0, a0, 1
; RV64I-NEXT: or a0, a0, a1
; RV64I-LABEL: fsgnjn_d:
; RV64I: # %bb.0:
; RV64I-NEXT: not a1, a1
-; RV64I-NEXT: li a2, -1
-; RV64I-NEXT: slli a2, a2, 63
-; RV64I-NEXT: and a1, a1, a2
; RV64I-NEXT: slli a0, a0, 1
; RV64I-NEXT: srli a0, a0, 1
+; RV64I-NEXT: srli a1, a1, 63
+; RV64I-NEXT: slli a1, a1, 63
; RV64I-NEXT: or a0, a0, a1
; RV64I-NEXT: ret
%1 = fsub double -0.0, %b
; RV64I-LABEL: fcopysign_fneg:
; RV64I: # %bb.0:
; RV64I-NEXT: not a1, a1
-; RV64I-NEXT: li a2, -1
-; RV64I-NEXT: slli a2, a2, 63
-; RV64I-NEXT: and a1, a1, a2
; RV64I-NEXT: slli a0, a0, 1
; RV64I-NEXT: srli a0, a0, 1
+; RV64I-NEXT: srli a1, a1, 63
+; RV64I-NEXT: slli a1, a1, 63
; RV64I-NEXT: or a0, a0, a1
; RV64I-NEXT: ret
;
;
; RV64I-LABEL: copysign_f64:
; RV64I: # %bb.0:
-; RV64I-NEXT: li a2, -1
-; RV64I-NEXT: slli a2, a2, 63
-; RV64I-NEXT: and a1, a1, a2
+; RV64I-NEXT: srli a1, a1, 63
+; RV64I-NEXT: slli a1, a1, 63
; RV64I-NEXT: slli a0, a0, 1
; RV64I-NEXT: srli a0, a0, 1
; RV64I-NEXT: or a0, a0, a1
; RV64I-LABEL: packu_i64:
; RV64I: # %bb.0:
; RV64I-NEXT: srli a0, a0, 32
-; RV64I-NEXT: li a2, -1
-; RV64I-NEXT: slli a2, a2, 32
-; RV64I-NEXT: and a1, a1, a2
+; RV64I-NEXT: srli a1, a1, 32
+; RV64I-NEXT: slli a1, a1, 32
; RV64I-NEXT: or a0, a1, a0
; RV64I-NEXT: ret
;