(CMIX GPR:$rs1, GPR:$rs2, GPR:$rs3)>;
def : Pat<(riscv_selectcc GPR:$rs2, (XLenVT 0), (XLenVT 17), GPR:$rs3, GPR:$rs1),
(CMOV GPR:$rs1, GPR:$rs2, GPR:$rs3)>;
+} // Predicates = [HasStdExtZbt]
// fshl and fshr concatenate their operands in the same order. fsr and fsl
// instruction use different orders. fshl will return its first operand for
// shift of zero, fshr will return its second operand. fsl and fsr both return
// $rs1 so the patterns need to have different operand orders.
+//
+// fshl and fshr only read the lower log2(xlen) bits of the shift amount, but
+// fsl/fsr instructions read log2(xlen)+1 bits. DAG combine may have removed
+// an AND mask on the shift amount that we need to add back to avoid a one in
+// the extra bit.
+// FIXME: If we can prove that the extra bit in the shift amount is zero, we
+// don't need this mask.
+let Predicates = [HasStdExtZbt, IsRV32] in {
+def : Pat<(fshl GPR:$rs1, GPR:$rs3, GPR:$rs2),
+ (FSL GPR:$rs1, (ANDI GPR:$rs2, 31), GPR:$rs3)>;
+def : Pat<(fshr GPR:$rs3, GPR:$rs1, GPR:$rs2),
+ (FSR GPR:$rs1, (ANDI GPR:$rs2, 31), GPR:$rs3)>;
+}
+let Predicates = [HasStdExtZbt, IsRV64] in {
def : Pat<(fshl GPR:$rs1, GPR:$rs3, GPR:$rs2),
- (FSL GPR:$rs1, GPR:$rs2, GPR:$rs3)>;
+ (FSL GPR:$rs1, (ANDI GPR:$rs2, 63), GPR:$rs3)>;
def : Pat<(fshr GPR:$rs3, GPR:$rs1, GPR:$rs2),
- (FSR GPR:$rs1, GPR:$rs2, GPR:$rs3)>;
+ (FSR GPR:$rs1, (ANDI GPR:$rs2, 63), GPR:$rs3)>;
+}
+let Predicates = [HasStdExtZbt] in {
def : Pat<(fshr GPR:$rs3, GPR:$rs1, uimmlog2xlen:$shamt),
(FSRI GPR:$rs1, GPR:$rs3, uimmlog2xlen:$shamt)>;
// We can use FSRI for fshl by immediate if we subtract the immediate from
def : Pat<(sext_inreg (fshl GPR:$rs1, (shl GPR:$rs3, (i64 32)),
(and GPR:$rs2, (i64 31))),
i32),
- (FSLW GPR:$rs1, GPR:$rs2, GPR:$rs3)>;
+ (FSLW GPR:$rs1, (ANDI GPR:$rs2, 31), GPR:$rs3)>;
def : Pat<(sext_inreg (fshr GPR:$rs3, (shl GPR:$rs1, (i64 32)),
(or GPR:$rs2, (i64 32))),
i32),
- (FSRW GPR:$rs1, GPR:$rs2, GPR:$rs3)>;
+ (FSRW GPR:$rs1, (ANDI GPR:$rs2, 31), GPR:$rs3)>;
def : Pat<(sext_inreg (fshr GPR:$rs3, (shl GPR:$rs1, (i64 32)),
uimm6gt32:$shamt),
i32),
;
; RV32IB-LABEL: fshl_i32:
; RV32IB: # %bb.0:
+; RV32IB-NEXT: andi a2, a2, 31
; RV32IB-NEXT: fsl a0, a0, a1, a2
; RV32IB-NEXT: ret
;
; RV32IBT-LABEL: fshl_i32:
; RV32IBT: # %bb.0:
+; RV32IBT-NEXT: andi a2, a2, 31
; RV32IBT-NEXT: fsl a0, a0, a1, a2
; RV32IBT-NEXT: ret
%1 = tail call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
;
; RV32IB-LABEL: fshr_i32:
; RV32IB: # %bb.0:
+; RV32IB-NEXT: andi a2, a2, 31
; RV32IB-NEXT: fsr a0, a1, a0, a2
; RV32IB-NEXT: ret
;
; RV32IBT-LABEL: fshr_i32:
; RV32IBT: # %bb.0:
+; RV32IBT-NEXT: andi a2, a2, 31
; RV32IBT-NEXT: fsr a0, a1, a0, a2
; RV32IBT-NEXT: ret
%1 = tail call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
;
; RV64IB-LABEL: fshl_i32:
; RV64IB: # %bb.0:
+; RV64IB-NEXT: andi a2, a2, 31
; RV64IB-NEXT: fslw a0, a0, a1, a2
; RV64IB-NEXT: ret
;
; RV64IBT-LABEL: fshl_i32:
; RV64IBT: # %bb.0:
+; RV64IBT-NEXT: andi a2, a2, 31
; RV64IBT-NEXT: fslw a0, a0, a1, a2
; RV64IBT-NEXT: ret
%1 = tail call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
;
; RV64IB-LABEL: fshl_i64:
; RV64IB: # %bb.0:
+; RV64IB-NEXT: andi a2, a2, 63
; RV64IB-NEXT: fsl a0, a0, a1, a2
; RV64IB-NEXT: ret
;
; RV64IBT-LABEL: fshl_i64:
; RV64IBT: # %bb.0:
+; RV64IBT-NEXT: andi a2, a2, 63
; RV64IBT-NEXT: fsl a0, a0, a1, a2
; RV64IBT-NEXT: ret
%1 = tail call i64 @llvm.fshl.i64(i64 %a, i64 %b, i64 %c)
;
; RV64IB-LABEL: fshr_i32:
; RV64IB: # %bb.0:
+; RV64IB-NEXT: andi a2, a2, 31
; RV64IB-NEXT: fsrw a0, a1, a0, a2
; RV64IB-NEXT: ret
;
; RV64IBT-LABEL: fshr_i32:
; RV64IBT: # %bb.0:
+; RV64IBT-NEXT: andi a2, a2, 31
; RV64IBT-NEXT: fsrw a0, a1, a0, a2
; RV64IBT-NEXT: ret
%1 = tail call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
;
; RV64IB-LABEL: fshr_i64:
; RV64IB: # %bb.0:
+; RV64IB-NEXT: andi a2, a2, 63
; RV64IB-NEXT: fsr a0, a1, a0, a2
; RV64IB-NEXT: ret
;
; RV64IBT-LABEL: fshr_i64:
; RV64IBT: # %bb.0:
+; RV64IBT-NEXT: andi a2, a2, 63
; RV64IBT-NEXT: fsr a0, a1, a0, a2
; RV64IBT-NEXT: ret
%1 = tail call i64 @llvm.fshr.i64(i64 %a, i64 %b, i64 %c)