; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc -mtriple=riscv64 -mattr=+experimental-p,+zbb,+m -verify-machineinstrs \ ; RUN: < %s | FileCheck %s define i32 @abs_i32(i32 %x) { ; CHECK-LABEL: abs_i32: ; CHECK: # %bb.0: ; CHECK-NEXT: absw a0, a0 ; CHECK-NEXT: ret %abs = tail call i32 @llvm.abs.i32(i32 %x, i1 true) ret i32 %abs } define signext i32 @abs_i32_sext(i32 signext %x) { ; CHECK-LABEL: abs_i32_sext: ; CHECK: # %bb.0: ; CHECK-NEXT: absw a0, a0 ; CHECK-NEXT: ret %abs = tail call i32 @llvm.abs.i32(i32 %x, i1 true) ret i32 %abs } define i64 @abs_i64(i64 %x) { ; CHECK-LABEL: abs_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: abs a0, a0 ; CHECK-NEXT: ret %abs = tail call i64 @llvm.abs.i64(i64 %x, i1 true) ret i64 %abs } ; Test scalar saturating add/sub operations for i32 define i32 @test_scalar_psadd_w(i32 %a, i32 %b) { ; CHECK-LABEL: test_scalar_psadd_w: ; CHECK: # %bb.0: ; CHECK-NEXT: psadd.w a0, a0, a1 ; CHECK-NEXT: ret %res = call i32 @llvm.sadd.sat.i32(i32 %a, i32 %b) ret i32 %res } define i32 @test_scalar_psaddu_w(i32 %a, i32 %b) { ; CHECK-LABEL: test_scalar_psaddu_w: ; CHECK: # %bb.0: ; CHECK-NEXT: psaddu.w a0, a0, a1 ; CHECK-NEXT: ret %res = call i32 @llvm.uadd.sat.i32(i32 %a, i32 %b) ret i32 %res } define i32 @test_scalar_pssub_w(i32 %a, i32 %b) { ; CHECK-LABEL: test_scalar_pssub_w: ; CHECK: # %bb.0: ; CHECK-NEXT: pssub.w a0, a0, a1 ; CHECK-NEXT: ret %res = call i32 @llvm.ssub.sat.i32(i32 %a, i32 %b) ret i32 %res } define i32 @test_scalar_pssubu_w(i32 %a, i32 %b) { ; CHECK-LABEL: test_scalar_pssubu_w: ; CHECK: # %bb.0: ; CHECK-NEXT: pssubu.w a0, a0, a1 ; CHECK-NEXT: ret %res = call i32 @llvm.usub.sat.i32(i32 %a, i32 %b) ret i32 %res } define i64 @pack_i64_imm() { ; CHECK-LABEL: pack_i64_imm: ; CHECK: # %bb.0: ; CHECK-NEXT: lui a0, 16432 ; CHECK-NEXT: addi a0, a0, 513 ; CHECK-NEXT: pack a0, a0, a0 ; CHECK-NEXT: ret ret i64 u0x0403020104030201 } ; Make sure we prefer li over pli define i64 @li_imm() { ; CHECK-LABEL: li_imm: ; CHECK: # %bb.0: ; CHECK-NEXT: li a0, -1 ; CHECK-NEXT: ret ret i64 -1 } define i32 @pli_b_i32() { ; CHECK-LABEL: pli_b_i32: ; CHECK: # %bb.0: ; CHECK-NEXT: lui a0, 20560 ; CHECK-NEXT: addi a0, a0, 1285 ; CHECK-NEXT: ret ret i32 u0x05050505 } define i64 @pli_b_i64() { ; CHECK-LABEL: pli_b_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: pli.b a0, -128 ; CHECK-NEXT: ret ret i64 u0x8080808080808080 } define i32 @pli_h_i32() { ; CHECK-LABEL: pli_h_i32: ; CHECK: # %bb.0: ; CHECK-NEXT: lui a0, 1047840 ; CHECK-NEXT: addi a0, a0, -47 ; CHECK-NEXT: ret ret i32 u0xffd1ffd1 } define i64 @pli_h_i64() { ; CHECK-LABEL: pli_h_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: pli.h a0, 291 ; CHECK-NEXT: ret ret i64 u0x0123012301230123 } define i64 @pli_h_slli_i64() { ; CHECK-LABEL: pli_h_slli_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: pli.h a0, 511 ; CHECK-NEXT: slli a0, a0, 3 ; CHECK-NEXT: ret ret i64 u0x0ff80ff80ff80ff8 } define i64 @pli_h_srli_i64() { ; CHECK-LABEL: pli_h_srli_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: pli.h a0, -240 ; CHECK-NEXT: srli a0, a0, 4 ; CHECK-NEXT: ret ret i64 u0x0ff10ff10ff10ff1 } define i64 @pli_w_i64() { ; CHECK-LABEL: pli_w_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: pli.w a0, -292 ; CHECK-NEXT: ret ret i64 u0xfffffedcfffffedc } define i64 @pli_w_slli_i64() { ; CHECK-LABEL: pli_w_slli_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: pli.w a0, 511 ; CHECK-NEXT: slli a0, a0, 7 ; CHECK-NEXT: ret ret i64 u0x0000ff800000ff80 } define i64 @pli_w_srli_i64() { ; CHECK-LABEL: pli_w_srli_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: pli.w a0, -480 ; CHECK-NEXT: srli a0, a0, 5 ; CHECK-NEXT: ret ret i64 u0x07fffff107fffff1 } define void @pli_b_store_i32(ptr %p) { ; CHECK-LABEL: pli_b_store_i32: ; CHECK: # %bb.0: ; CHECK-NEXT: pli.b a1, 65 ; CHECK-NEXT: sw a1, 0(a0) ; CHECK-NEXT: ret store i32 u0x41414141, ptr %p ret void } define void @pli_b_store_i16(ptr %p) { ; CHECK-LABEL: pli_b_store_i16: ; CHECK: # %bb.0: ; CHECK-NEXT: pli.b a1, -127 ; CHECK-NEXT: sh a1, 0(a0) ; CHECK-NEXT: ret store i16 u0x8181, ptr %p ret void } define i64 @plui_h_i64() { ; CHECK-LABEL: plui_h_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: plui.h a0, -9 ; CHECK-NEXT: ret ret i64 u0xfdc0fdc0fdc0fdc0 } define void @plui_h_i32(ptr %p) { ; CHECK-LABEL: plui_h_i32: ; CHECK: # %bb.0: ; CHECK-NEXT: plui.h a1, -9 ; CHECK-NEXT: sw a1, 0(a0) ; CHECK-NEXT: ret store i32 u0xfdc0fdc0, ptr %p ret void } ; Make sure we use lui instead of plui.h. define void @lui_i32(ptr %p) { ; CHECK-LABEL: lui_i32: ; CHECK: # %bb.0: ; CHECK-NEXT: lui a1, 524296 ; CHECK-NEXT: sw a1, 0(a0) ; CHECK-NEXT: ret store i32 u0x80008000, ptr %p ret void } define i64 @plui_w_i64() { ; CHECK-LABEL: plui_w_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: plui.w a0, 473 ; CHECK-NEXT: ret ret i64 u0x7640000076400000 } define i64 @pack_i64(i64 %a, i64 %b) nounwind { ; CHECK-LABEL: pack_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: pack a0, a0, a1 ; CHECK-NEXT: ret %shl = and i64 %a, 4294967295 %shl1 = shl i64 %b, 32 %or = or i64 %shl1, %shl ret i64 %or } define i64 @pack_i64_2(i32 signext %a, i32 signext %b) nounwind { ; CHECK-LABEL: pack_i64_2: ; CHECK: # %bb.0: ; CHECK-NEXT: pack a0, a0, a1 ; CHECK-NEXT: ret %zexta = zext i32 %a to i64 %zextb = zext i32 %b to i64 %shl1 = shl i64 %zextb, 32 %or = or i64 %shl1, %zexta ret i64 %or } define i64 @pack_i64_3(ptr %0, ptr %1) { ; CHECK-LABEL: pack_i64_3: ; CHECK: # %bb.0: ; CHECK-NEXT: lw a0, 0(a0) ; CHECK-NEXT: lw a1, 0(a1) ; CHECK-NEXT: pack a0, a1, a0 ; CHECK-NEXT: ret %3 = load i32, ptr %0, align 4 %4 = zext i32 %3 to i64 %5 = shl i64 %4, 32 %6 = load i32, ptr %1, align 4 %7 = zext i32 %6 to i64 %8 = or i64 %5, %7 ret i64 %8 } define i8 @cls_i8(i8 %x) { ; CHECK-LABEL: cls_i8: ; CHECK: # %bb.0: ; CHECK-NEXT: sext.b a0, a0 ; CHECK-NEXT: cls a0, a0 ; CHECK-NEXT: addi a0, a0, -56 ; CHECK-NEXT: ret %a = ashr i8 %x, 7 %b = xor i8 %x, %a %c = call i8 @llvm.ctlz.i8(i8 %b, i1 false) %d = sub i8 %c, 1 ret i8 %d } define i8 @cls_i8_2(i8 %x) { ; CHECK-LABEL: cls_i8_2: ; CHECK: # %bb.0: ; CHECK-NEXT: sext.b a0, a0 ; CHECK-NEXT: cls a0, a0 ; CHECK-NEXT: addi a0, a0, -56 ; CHECK-NEXT: ret %a = ashr i8 %x, 7 %b = xor i8 %x, %a %c = shl i8 %b, 1 %d = or i8 %c, 1 %e = call i8 @llvm.ctlz.i8(i8 %d, i1 true) ret i8 %e } define i16 @cls_i16(i16 %x) { ; CHECK-LABEL: cls_i16: ; CHECK: # %bb.0: ; CHECK-NEXT: sext.h a0, a0 ; CHECK-NEXT: cls a0, a0 ; CHECK-NEXT: addi a0, a0, -48 ; CHECK-NEXT: ret %a = ashr i16 %x, 15 %b = xor i16 %x, %a %c = call i16 @llvm.ctlz.i16(i16 %b, i1 false) %d = sub i16 %c, 1 ret i16 %d } define i16 @cls_i16_2(i16 %x) { ; CHECK-LABEL: cls_i16_2: ; CHECK: # %bb.0: ; CHECK-NEXT: sext.h a0, a0 ; CHECK-NEXT: cls a0, a0 ; CHECK-NEXT: addi a0, a0, -48 ; CHECK-NEXT: ret %a = ashr i16 %x, 15 %b = xor i16 %x, %a %c = shl i16 %b, 1 %d = or i16 %c, 1 %e = call i16 @llvm.ctlz.i16(i16 %d, i1 true) ret i16 %e } define i32 @cls_i32(i32 %x) { ; CHECK-LABEL: cls_i32: ; CHECK: # %bb.0: ; CHECK-NEXT: clsw a0, a0 ; CHECK-NEXT: ret %a = ashr i32 %x, 31 %b = xor i32 %x, %a %c = call i32 @llvm.ctlz.i32(i32 %b, i1 false) %d = sub i32 %c, 1 ret i32 %d } define i32 @cls_i32_2(i32 %x) { ; CHECK-LABEL: cls_i32_2: ; CHECK: # %bb.0: ; CHECK-NEXT: clsw a0, a0 ; CHECK-NEXT: ret %a = ashr i32 %x, 31 %b = xor i32 %x, %a %c = shl i32 %b, 1 %d = or i32 %c, 1 %e = call i32 @llvm.ctlz.i32(i32 %d, i1 true) ret i32 %e } ; The result is in the range [1-31], so we don't need an andi after the cls. define i32 @cls_i32_knownbits(i32 %x) { ; CHECK-LABEL: cls_i32_knownbits: ; CHECK: # %bb.0: ; CHECK-NEXT: clsw a0, a0 ; CHECK-NEXT: ret %a = ashr i32 %x, 31 %b = xor i32 %x, %a %c = call i32 @llvm.ctlz.i32(i32 %b, i1 false) %d = sub i32 %c, 1 %e = and i32 %d, 31 ret i32 %e } ; There are at least 16 redundant sign bits so we don't need an ori after the clsw. define i32 @cls_i32_knownbits_2(i16 signext %x) { ; CHECK-LABEL: cls_i32_knownbits_2: ; CHECK: # %bb.0: ; CHECK-NEXT: clsw a0, a0 ; CHECK-NEXT: ret %sext = sext i16 %x to i32 %a = ashr i32 %sext, 31 %b = xor i32 %sext, %a %c = call i32 @llvm.ctlz.i32(i32 %b, i1 false) %d = sub i32 %c, 1 %e = or i32 %d, 16 ret i32 %e } ; There are at least 24 redundant sign bits so we don't need an ori after the clsw. define i32 @cls_i32_knownbits_3(i8 signext %x) { ; CHECK-LABEL: cls_i32_knownbits_3: ; CHECK: # %bb.0: ; CHECK-NEXT: clsw a0, a0 ; CHECK-NEXT: ret %sext = sext i8 %x to i32 %a = ashr i32 %sext, 31 %b = xor i32 %sext, %a %c = call i32 @llvm.ctlz.i32(i32 %b, i1 false) %d = sub i32 %c, 1 %e = or i32 %d, 24 ret i32 %e } ; Negative test. We only know there is at least 1 redundant sign bit. We can't ; remove the ori. define i32 @cls_i32_knownbits_4(i32 signext %x) { ; CHECK-LABEL: cls_i32_knownbits_4: ; CHECK: # %bb.0: ; CHECK-NEXT: slli a0, a0, 33 ; CHECK-NEXT: srai a0, a0, 33 ; CHECK-NEXT: clsw a0, a0 ; CHECK-NEXT: ori a0, a0, 1 ; CHECK-NEXT: ret %shl = shl i32 %x, 1 %ashr = ashr i32 %shl, 1 %a = ashr i32 %ashr, 31 %b = xor i32 %ashr, %a %c = call i32 @llvm.ctlz.i32(i32 %b, i1 false) %d = sub i32 %c, 1 %e = or i32 %d, 1 ret i32 %e } define i64 @cls_i64(i64 %x) { ; CHECK-LABEL: cls_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: cls a0, a0 ; CHECK-NEXT: ret %a = ashr i64 %x, 63 %b = xor i64 %x, %a %c = call i64 @llvm.ctlz.i64(i64 %b, i1 false) %d = sub i64 %c, 1 ret i64 %d } define i64 @cls_i64_2(i64 %x) { ; CHECK-LABEL: cls_i64_2: ; CHECK: # %bb.0: ; CHECK-NEXT: cls a0, a0 ; CHECK-NEXT: ret %a = ashr i64 %x, 63 %b = xor i64 %x, %a %c = shl i64 %b, 1 %d = or i64 %c, 1 %e = call i64 @llvm.ctlz.i64(i64 %d, i1 true) ret i64 %e } ; Check that the range max in ctls cls knownbits ; is not set to 32 define i64 @cls_i64_not_32(i64 %x) { ; CHECK-LABEL: cls_i64_not_32: ; CHECK: # %bb.0: ; CHECK-NEXT: srai a0, a0, 16 ; CHECK-NEXT: cls a0, a0 ; CHECK-NEXT: ori a0, a0, 16 ; CHECK-NEXT: ret %val = ashr i64 %x, 16 %a = ashr i64 %val, 63 %b = xor i64 %val, %a %c = shl i64 %b, 1 %d = or i64 %c, 1 %e = call i64 @llvm.ctlz.i64(i64 %d, i1 true) %f = or i64 %e, 16 ret i64 %f } define i128 @sll_i128(i128 %x, i128 %y) { ; CHECK-LABEL: sll_i128: ; CHECK: # %bb.0: ; CHECK-NEXT: sll a3, a0, a2 ; CHECK-NEXT: slx a1, a0, a2 ; CHECK-NEXT: slli a2, a2, 57 ; CHECK-NEXT: srai a2, a2, 63 ; CHECK-NEXT: mvm a1, a3, a2 ; CHECK-NEXT: andn a0, a3, a2 ; CHECK-NEXT: ret %b = shl i128 %x, %y ret i128 %b } define i128 @sll_small_i128(i128 %x, i128 %y) { ; CHECK-LABEL: sll_small_i128: ; CHECK: # %bb.0: ; CHECK-NEXT: sll a3, a0, a2 ; CHECK-NEXT: slx a1, a0, a2 ; CHECK-NEXT: mv a0, a3 ; CHECK-NEXT: ret %a = and i128 %y, 63 %b = shl i128 %x, %a ret i128 %b } define i128 @sll_large_i128(i128 %x, i128 %y) { ; CHECK-LABEL: sll_large_i128: ; CHECK: # %bb.0: ; CHECK-NEXT: sll a1, a0, a2 ; CHECK-NEXT: li a0, 0 ; CHECK-NEXT: ret %a = or i128 %y, 64 %b = shl i128 %x, %a ret i128 %b } define i128 @slli_i128(i128 %x) { ; CHECK-LABEL: slli_i128: ; CHECK: # %bb.0: ; CHECK-NEXT: li a2, 49 ; CHECK-NEXT: slx a1, a0, a2 ; CHECK-NEXT: slli a0, a0, 49 ; CHECK-NEXT: ret %a = shl i128 %x, 49 ret i128 %a } define i128 @slli_i128_large(i128 %x) { ; CHECK-LABEL: slli_i128_large: ; CHECK: # %bb.0: ; CHECK-NEXT: slli a1, a0, 7 ; CHECK-NEXT: li a0, 0 ; CHECK-NEXT: ret %a = shl i128 %x, 71 ret i128 %a } define i128 @srl_i128(i128 %x, i128 %y) { ; CHECK-LABEL: srl_i128: ; CHECK: # %bb.0: ; CHECK-NEXT: srl a3, a1, a2 ; CHECK-NEXT: srx a0, a1, a2 ; CHECK-NEXT: slli a2, a2, 57 ; CHECK-NEXT: srai a2, a2, 63 ; CHECK-NEXT: mvm a0, a3, a2 ; CHECK-NEXT: andn a1, a3, a2 ; CHECK-NEXT: ret %b = lshr i128 %x, %y ret i128 %b } define i128 @srl_small_i128(i128 %x, i128 %y) { ; CHECK-LABEL: srl_small_i128: ; CHECK: # %bb.0: ; CHECK-NEXT: srl a3, a1, a2 ; CHECK-NEXT: srx a0, a1, a2 ; CHECK-NEXT: mv a1, a3 ; CHECK-NEXT: ret %a = and i128 %y, 63 %b = lshr i128 %x, %a ret i128 %b } define i128 @srl_large_i128(i128 %x, i128 %y) { ; CHECK-LABEL: srl_large_i128: ; CHECK: # %bb.0: ; CHECK-NEXT: srl a0, a1, a2 ; CHECK-NEXT: li a1, 0 ; CHECK-NEXT: ret %a = or i128 %y, 64 %b = lshr i128 %x, %a ret i128 %b } define i128 @srli_i128(i128 %x) { ; CHECK-LABEL: srli_i128: ; CHECK: # %bb.0: ; CHECK-NEXT: li a2, 49 ; CHECK-NEXT: srx a0, a1, a2 ; CHECK-NEXT: srli a1, a1, 49 ; CHECK-NEXT: ret %a = lshr i128 %x, 49 ret i128 %a } define i128 @srli_i128_large(i128 %x) { ; CHECK-LABEL: srli_i128_large: ; CHECK: # %bb.0: ; CHECK-NEXT: srli a0, a1, 7 ; CHECK-NEXT: li a1, 0 ; CHECK-NEXT: ret %a = lshr i128 %x, 71 ret i128 %a } define i128 @sra_i128(i128 %x, i128 %y) { ; CHECK-LABEL: sra_i128: ; CHECK: # %bb.0: ; CHECK-NEXT: sra a3, a1, a2 ; CHECK-NEXT: srx a0, a1, a2 ; CHECK-NEXT: slli a2, a2, 57 ; CHECK-NEXT: srai a2, a2, 63 ; CHECK-NEXT: mvm a0, a3, a2 ; CHECK-NEXT: sra a1, a3, a2 ; CHECK-NEXT: ret %b = ashr i128 %x, %y ret i128 %b } define i128 @sra_small_i128(i128 %x, i128 %y) { ; CHECK-LABEL: sra_small_i128: ; CHECK: # %bb.0: ; CHECK-NEXT: sra a3, a1, a2 ; CHECK-NEXT: srx a0, a1, a2 ; CHECK-NEXT: mv a1, a3 ; CHECK-NEXT: ret %a = and i128 %y, 63 %b = ashr i128 %x, %a ret i128 %b } define i128 @sra_large_i128(i128 %x, i128 %y) { ; CHECK-LABEL: sra_large_i128: ; CHECK: # %bb.0: ; CHECK-NEXT: sra a0, a1, a2 ; CHECK-NEXT: srai a1, a1, 63 ; CHECK-NEXT: ret %a = or i128 %y, 64 %b = ashr i128 %x, %a ret i128 %b } define i128 @srai_i128(i128 %x) { ; CHECK-LABEL: srai_i128: ; CHECK: # %bb.0: ; CHECK-NEXT: li a2, 49 ; CHECK-NEXT: srx a0, a1, a2 ; CHECK-NEXT: srai a1, a1, 49 ; CHECK-NEXT: ret %a = ashr i128 %x, 49 ret i128 %a } define i128 @srai_i128_large(i128 %x) { ; CHECK-LABEL: srai_i128_large: ; CHECK: # %bb.0: ; CHECK-NEXT: srai a0, a1, 7 ; CHECK-NEXT: srai a1, a1, 63 ; CHECK-NEXT: ret %a = ashr i128 %x, 71 ret i128 %a } define i64 @slx_i64(i64 %a, i64 %b, i64 %shamt) { ; CHECK-LABEL: slx_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: slx a0, a1, a2 ; CHECK-NEXT: ret %1 = tail call i64 @llvm.fshl.i64(i64 %a, i64 %b, i64 %shamt) ret i64 %1 } define i64 @slxi_i64(i64 %a, i64 %b) { ; CHECK-LABEL: slxi_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: li a2, 25 ; CHECK-NEXT: slx a0, a1, a2 ; CHECK-NEXT: ret %1 = tail call i64 @llvm.fshl.i64(i64 %a, i64 %b, i64 25) ret i64 %1 } define i64 @srx_i64(i64 %a, i64 %b, i64 %shamt) { ; CHECK-LABEL: srx_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: srx a1, a0, a2 ; CHECK-NEXT: mv a0, a1 ; CHECK-NEXT: ret %1 = tail call i64 @llvm.fshr.i64(i64 %a, i64 %b, i64 %shamt) ret i64 %1 } define i64 @srxi_i64(i64 %a, i64 %b) { ; CHECK-LABEL: srxi_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: li a2, 25 ; CHECK-NEXT: srx a1, a0, a2 ; CHECK-NEXT: mv a0, a1 ; CHECK-NEXT: ret %1 = tail call i64 @llvm.fshr.i64(i64 %a, i64 %b, i64 25) ret i64 %1 } ; Test bitwise merge: (mask & b) | (~mask & a) define i64 @merge_i64(i64 %mask, i64 %a, i64 %b) nounwind { ; CHECK-LABEL: merge_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: merge a0, a1, a2 ; CHECK-NEXT: ret %and1 = and i64 %mask, %b %not = xor i64 %mask, -1 %and2 = and i64 %not, %a %or = or i64 %and1, %and2 ret i64 %or } ; Test MERGE with swapped a/b arguments define i64 @merge_i64_2(i64 %mask, i64 %b, i64 %a) nounwind { ; CHECK-LABEL: merge_i64_2: ; CHECK: # %bb.0: ; CHECK-NEXT: merge a0, a2, a1 ; CHECK-NEXT: ret %and1 = and i64 %mask, %b %not = xor i64 %mask, -1 %and2 = and i64 %not, %a %or = or i64 %and1, %and2 ret i64 %or } ; Test MVM: result overwrites rs1 (%a) define i64 @mvm_i64(i64 %a, i64 %mask, i64 %b) nounwind { ; CHECK-LABEL: mvm_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: mvm a0, a2, a1 ; CHECK-NEXT: ret %and1 = and i64 %mask, %b %not = xor i64 %mask, -1 %and2 = and i64 %not, %a %or = or i64 %and1, %and2 ret i64 %or } ; Test MVM with mask as last argument define i64 @mvm_i64_2(i64 %a, i64 %b, i64 %mask) nounwind { ; CHECK-LABEL: mvm_i64_2: ; CHECK: # %bb.0: ; CHECK-NEXT: mvm a0, a1, a2 ; CHECK-NEXT: ret %and1 = and i64 %mask, %b %not = xor i64 %mask, -1 %and2 = and i64 %not, %a %or = or i64 %and1, %and2 ret i64 %or } ; Test MVMN: result overwrites rs2 (%b) define i64 @mvmn_i64(i64 %b, i64 %mask, i64 %a) nounwind { ; CHECK-LABEL: mvmn_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: mvmn a0, a2, a1 ; CHECK-NEXT: ret %and1 = and i64 %mask, %b %not = xor i64 %mask, -1 %and2 = and i64 %not, %a %or = or i64 %and1, %and2 ret i64 %or } ; Test MVMN with mask as last argument define i64 @mvmn_i64_2(i64 %b, i64 %a, i64 %mask) nounwind { ; CHECK-LABEL: mvmn_i64_2: ; CHECK: # %bb.0: ; CHECK-NEXT: mvmn a0, a1, a2 ; CHECK-NEXT: ret %and1 = and i64 %mask, %b %not = xor i64 %mask, -1 %and2 = and i64 %not, %a %or = or i64 %and1, %and2 ret i64 %or } ; Test case where none of the source operands can be overwritten, ; requiring a mv before merge define i64 @merge_i64_mv(i64 %mask, i64 %a, i64 %b) nounwind { ; CHECK-LABEL: merge_i64_mv: ; CHECK: # %bb.0: ; CHECK-NEXT: mv a3, a0 ; CHECK-NEXT: merge a3, a1, a2 ; CHECK-NEXT: add a0, a0, a1 ; CHECK-NEXT: add a0, a3, a0 ; CHECK-NEXT: add a0, a0, a2 ; CHECK-NEXT: ret %and1 = and i64 %mask, %b %not = xor i64 %mask, -1 %and2 = and i64 %not, %a %or = or i64 %and1, %and2 %sum1 = add i64 %or, %mask %sum2 = add i64 %sum1, %a %sum3 = add i64 %sum2, %b ret i64 %sum3 } ; Test alternate merge pattern: (a ^ b) & mask ^ a define i64 @merge_xor_i64(i64 %mask, i64 %a, i64 %b) nounwind { ; CHECK-LABEL: merge_xor_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: merge a0, a1, a2 ; CHECK-NEXT: ret %xor1 = xor i64 %a, %b %and = and i64 %xor1, %mask %xor2 = xor i64 %and, %a ret i64 %xor2 } ; Test alternate merge pattern with different argument order for MVM define i64 @mvm_xor_i64(i64 %a, i64 %mask, i64 %b) nounwind { ; CHECK-LABEL: mvm_xor_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: mvm a0, a2, a1 ; CHECK-NEXT: ret %xor1 = xor i64 %a, %b %and = and i64 %xor1, %mask %xor2 = xor i64 %and, %a ret i64 %xor2 } ; Test alternate merge pattern with different argument order for MVMN define i64 @mvmn_xor_i64(i64 %b, i64 %mask, i64 %a) nounwind { ; CHECK-LABEL: mvmn_xor_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: mvmn a0, a2, a1 ; CHECK-NEXT: ret %xor1 = xor i64 %a, %b %and = and i64 %xor1, %mask %xor2 = xor i64 %and, %a ret i64 %xor2 } define signext i32 @mm_sati_8_i32(i32 signext %x) { ; CHECK-LABEL: mm_sati_8_i32: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: sati a0, a0, 8 ; CHECK-NEXT: ret entry: %0 = call i32 @llvm.smin.i32(i32 %x, i32 127) %1 = call i32 @llvm.smax.i32(i32 %0, i32 -128) ret i32 %1 } define signext i32 @mm_sati_16_i32(i32 signext %x) { ; CHECK-LABEL: mm_sati_16_i32: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: sati a0, a0, 16 ; CHECK-NEXT: ret entry: %0 = call i32 @llvm.smax.i32(i32 %x, i32 -32768) %1 = call i32 @llvm.smin.i32(i32 %0, i32 32767) ret i32 %1 } define signext i32 @mm_sati_24_i32(i32 signext %x) { ; CHECK-LABEL: mm_sati_24_i32: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: sati a0, a0, 24 ; CHECK-NEXT: ret entry: %0 = call i32 @llvm.smin.i32(i32 %x, i32 8388607) %1 = call i32 @llvm.smax.i32(i32 %0, i32 -8388608) ret i32 %1 } define signext i32 @mm_sati_32_i32(i32 signext %x) { ; CHECK-LABEL: mm_sati_32_i32: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: ret entry: %0 = call i32 @llvm.smax.i32(i32 %x, i32 -2147483648) %1 = call i32 @llvm.smin.i32(i32 %0, i32 2147483647) ret i32 %1 } define signext i32 @mm_sati_1_i32(i32 signext %x) { ; CHECK-LABEL: mm_sati_1_i32: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: sati a0, a0, 1 ; CHECK-NEXT: ret entry: %0 = call i32 @llvm.smin.i32(i32 %x, i32 0) %1 = call i32 @llvm.smax.i32(i32 %0, i32 -1) ret i32 %1 } define signext i32 @mm_sati_minallones_i32(i32 signext %x) { ; CHECK-LABEL: mm_sati_minallones_i32: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: li a0, 0 ; CHECK-NEXT: ret entry: %0 = call i32 @llvm.smin.i32(i32 %x, i32 -1) %1 = call i32 @llvm.smax.i32(i32 %0, i32 0) ret i32 %1 } define signext i32 @mm_sati_minallones2_i32(i32 signext %x) { ; CHECK-LABEL: mm_sati_minallones2_i32: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: li a0, -1 ; CHECK-NEXT: ret entry: %0 = call i32 @llvm.smax.i32(i32 %x, i32 0) %1 = call i32 @llvm.smin.i32(i32 %0, i32 -1) ret i32 %1 } define signext i32 @mm_usati_8_i32(i32 signext %x) { ; CHECK-LABEL: mm_usati_8_i32: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: usati a0, a0, 8 ; CHECK-NEXT: ret entry: %0 = call i32 @llvm.smin.i32(i32 %x, i32 255) %1 = call i32 @llvm.smax.i32(i32 %0, i32 0) ret i32 %1 } define signext i32 @mm_usati_16_i32(i32 signext %x) { ; CHECK-LABEL: mm_usati_16_i32: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: usati a0, a0, 16 ; CHECK-NEXT: ret entry: %0 = call i32 @llvm.smax.i32(i32 %x, i32 0) %1 = call i32 @llvm.smin.i32(i32 %0, i32 65535) ret i32 %1 } define signext i32 @mm_usati_1_i32(i32 signext %x) { ; CHECK-LABEL: mm_usati_1_i32: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: usati a0, a0, 1 ; CHECK-NEXT: ret entry: %0 = call i32 @llvm.smax.i32(i32 %x, i32 0) %1 = call i32 @llvm.smin.i32(i32 %0, i32 1) ret i32 %1 } define signext i32 @mm_usati_31_i32(i32 signext %x) { ; CHECK-LABEL: mm_usati_31_i32: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: max a0, a0, zero ; CHECK-NEXT: ret entry: %0 = call i32 @llvm.smin.i32(i32 %x, i32 2147483647) %1 = call i32 @llvm.smax.i32(i32 %0, i32 0) ret i32 %1 } define signext i32 @mm_usati_32_i32(i32 signext %x) { ; CHECK-LABEL: mm_usati_32_i32: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: li a0, -1 ; CHECK-NEXT: ret entry: %0 = call i32 @llvm.smax.i32(i32 %x, i32 0) %1 = call i32 @llvm.smin.i32(i32 %0, i32 4294967295) ret i32 %1 } define i64 @mm_sati_8_i64(i64 %x) { ; CHECK-LABEL: mm_sati_8_i64: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: sati a0, a0, 8 ; CHECK-NEXT: ret entry: %0 = call i64 @llvm.smin.i64(i64 %x, i64 127) %1 = call i64 @llvm.smax.i64(i64 %0, i64 -128) ret i64 %1 } define i64 @mm_sati_16_i64(i64 %x) { ; CHECK-LABEL: mm_sati_16_i64: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: sati a0, a0, 16 ; CHECK-NEXT: ret entry: %0 = call i64 @llvm.smax.i64(i64 %x, i64 -32768) %1 = call i64 @llvm.smin.i64(i64 %0, i64 32767) ret i64 %1 } define i64 @mm_sati_24_i64(i64 %x) { ; CHECK-LABEL: mm_sati_24_i64: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: sati a0, a0, 24 ; CHECK-NEXT: ret entry: %0 = call i64 @llvm.smin.i64(i64 %x, i64 8388607) %1 = call i64 @llvm.smax.i64(i64 %0, i64 -8388608) ret i64 %1 } define i64 @mm_sati_32_i64(i64 %x) { ; CHECK-LABEL: mm_sati_32_i64: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: sati a0, a0, 32 ; CHECK-NEXT: ret entry: %0 = call i64 @llvm.smax.i64(i64 %x, i64 -2147483648) %1 = call i64 @llvm.smin.i64(i64 %0, i64 2147483647) ret i64 %1 } define i64 @mm_sati_1_i64(i64 %x) { ; CHECK-LABEL: mm_sati_1_i64: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: sati a0, a0, 1 ; CHECK-NEXT: ret entry: %0 = call i64 @llvm.smin.i64(i64 %x, i64 0) %1 = call i64 @llvm.smax.i64(i64 %0, i64 -1) ret i64 %1 } define i64 @mm_sati_minallones_i64(i64 %x) { ; CHECK-LABEL: mm_sati_minallones_i64: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: li a0, 0 ; CHECK-NEXT: ret entry: %0 = call i64 @llvm.smin.i64(i64 %x, i64 -1) %1 = call i64 @llvm.smax.i64(i64 %0, i64 0) ret i64 %1 } define i64 @mm_sati_minallones2_i64(i64 %x) { ; CHECK-LABEL: mm_sati_minallones2_i64: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: li a0, -1 ; CHECK-NEXT: ret entry: %0 = call i64 @llvm.smax.i64(i64 %x, i64 0) %1 = call i64 @llvm.smin.i64(i64 %0, i64 -1) ret i64 %1 } define i64 @mm_usati_8_i64(i64 %x) { ; CHECK-LABEL: mm_usati_8_i64: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: usati a0, a0, 8 ; CHECK-NEXT: ret entry: %0 = call i64 @llvm.smin.i64(i64 %x, i64 255) %1 = call i64 @llvm.smax.i64(i64 %0, i64 0) ret i64 %1 } define i64 @mm_usati_16_i64(i64 %x) { ; CHECK-LABEL: mm_usati_16_i64: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: usati a0, a0, 16 ; CHECK-NEXT: ret entry: %0 = call i64 @llvm.smax.i64(i64 %x, i64 0) %1 = call i64 @llvm.smin.i64(i64 %0, i64 65535) ret i64 %1 } define i64 @mm_usati_1_i64(i64 %x) { ; CHECK-LABEL: mm_usati_1_i64: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: usati a0, a0, 1 ; CHECK-NEXT: ret entry: %0 = call i64 @llvm.smax.i64(i64 %x, i64 0) %1 = call i64 @llvm.smin.i64(i64 %0, i64 1) ret i64 %1 } define i64 @mm_usati_31_i64(i64 %x) { ; CHECK-LABEL: mm_usati_31_i64: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: usati a0, a0, 31 ; CHECK-NEXT: ret entry: %0 = call i64 @llvm.smin.i64(i64 %x, i64 2147483647) %1 = call i64 @llvm.smax.i64(i64 %0, i64 0) ret i64 %1 } define i64 @mm_usati_32_i64(i64 %x) { ; CHECK-LABEL: mm_usati_32_i64: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: usati a0, a0, 32 ; CHECK-NEXT: ret entry: %0 = call i64 @llvm.smax.i64(i64 %x, i64 0) %1 = call i64 @llvm.smin.i64(i64 %0, i64 4294967295) ret i64 %1 } define i64 @mm_usati_55_i64(i64 %x) { ; CHECK-LABEL: mm_usati_55_i64: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: usati a0, a0, 55 ; CHECK-NEXT: ret entry: %0 = call i64 @llvm.smax.i64(i64 %x, i64 0) %1 = call i64 @llvm.smin.i64(i64 %0, i64 u0x7FFFFFFFFFFFFF) ret i64 %1 } define i64 @mm_usati_64_i64(i64 %x) { ; CHECK-LABEL: mm_usati_64_i64: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: li a0, -1 ; CHECK-NEXT: ret entry: %0 = call i64 @llvm.smax.i64(i64 %x, i64 0) %1 = call i64 @llvm.smin.i64(i64 %0, i64 -1) ret i64 %1 } ; Test that we select remw. define signext i32 @mm_sati_32_numsignbits_i64(i64 %x, i32 %y) { ; CHECK-LABEL: mm_sati_32_numsignbits_i64: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: sati a0, a0, 32 ; CHECK-NEXT: remw a0, a0, a1 ; CHECK-NEXT: ret entry: %0 = call i64 @llvm.smax.i64(i64 %x, i64 -2147483648) %1 = call i64 @llvm.smin.i64(i64 %0, i64 2147483647) %2 = sext i32 %y to i64 %3 = srem i64 %1, %2 %4 = trunc i64 %3 to i32 ret i32 %4 } ; Test multiply patterns with one extended operand define i64 @mul_w00_sexti32_sext_inreg(i32 signext %a, i64 %b) nounwind { ; CHECK-LABEL: mul_w00_sexti32_sext_inreg: ; CHECK: # %bb.0: ; CHECK-NEXT: mul.w00 a0, a0, a1 ; CHECK-NEXT: ret %a_sext = sext i32 %a to i64 %b_trunc = trunc i64 %b to i32 %b_sext = sext i32 %b_trunc to i64 %mul = mul i64 %a_sext, %b_sext ret i64 %mul } define i64 @mul_w00_sexti32_sext_inreg_commute(i32 signext %a, i64 %b) nounwind { ; CHECK-LABEL: mul_w00_sexti32_sext_inreg_commute: ; CHECK: # %bb.0: ; CHECK-NEXT: mul.w00 a0, a0, a1 ; CHECK-NEXT: ret %a_sext = sext i32 %a to i64 %b_trunc = trunc i64 %b to i32 %b_sext = sext i32 %b_trunc to i64 %mul = mul i64 %b_sext, %a_sext ret i64 %mul } define i64 @mulu_w00_zexti32_and(i32 zeroext %a, i64 %b) nounwind { ; CHECK-LABEL: mulu_w00_zexti32_and: ; CHECK: # %bb.0: ; CHECK-NEXT: mulu.w00 a0, a0, a1 ; CHECK-NEXT: ret %a_zext = zext i32 %a to i64 %b_and = and i64 %b, 4294967295 %mul = mul i64 %a_zext, %b_and ret i64 %mul } define i64 @mulu_w00_zexti32_and_commute(i32 zeroext %a, i64 %b) nounwind { ; CHECK-LABEL: mulu_w00_zexti32_and_commute: ; CHECK: # %bb.0: ; CHECK-NEXT: mulu.w00 a0, a0, a1 ; CHECK-NEXT: ret %a_zext = zext i32 %a to i64 %b_and = and i64 %b, 4294967295 %mul = mul i64 %b_and, %a_zext ret i64 %mul } define i64 @mulsu_w00_sexti32_and(i32 signext %a, i64 %b) nounwind { ; CHECK-LABEL: mulsu_w00_sexti32_and: ; CHECK: # %bb.0: ; CHECK-NEXT: mulsu.w00 a0, a0, a1 ; CHECK-NEXT: ret %a_sext = sext i32 %a to i64 %b_and = and i64 %b, 4294967295 %mul = mul i64 %a_sext, %b_and ret i64 %mul } define i64 @mulsu_w00_sexti32_and_commute(i32 signext %a, i64 %b) nounwind { ; CHECK-LABEL: mulsu_w00_sexti32_and_commute: ; CHECK: # %bb.0: ; CHECK-NEXT: mulsu.w00 a0, a0, a1 ; CHECK-NEXT: ret %a_sext = sext i32 %a to i64 %b_and = and i64 %b, 4294967295 %mul = mul i64 %b_and, %a_sext ret i64 %mul } define i64 @mulsu_w00_sext_inreg_zexti32(i64 %a, i32 zeroext %b) nounwind { ; CHECK-LABEL: mulsu_w00_sext_inreg_zexti32: ; CHECK: # %bb.0: ; CHECK-NEXT: mulsu.w00 a0, a0, a1 ; CHECK-NEXT: ret %a_trunc = trunc i64 %a to i32 %a_sext = sext i32 %a_trunc to i64 %b_zext = zext i32 %b to i64 %mul = mul i64 %a_sext, %b_zext ret i64 %mul } define i64 @mulsu_w00_sext_inreg_zexti32_commute(i64 %a, i32 zeroext %b) nounwind { ; CHECK-LABEL: mulsu_w00_sext_inreg_zexti32_commute: ; CHECK: # %bb.0: ; CHECK-NEXT: mulsu.w00 a0, a0, a1 ; CHECK-NEXT: ret %a_trunc = trunc i64 %a to i32 %a_sext = sext i32 %a_trunc to i64 %b_zext = zext i32 %b to i64 %mul = mul i64 %b_zext, %a_sext ret i64 %mul } ; Test that we select pack. define i64 @mm_usati_32_knownbits_i64(i64 %x, i64 %y) { ; CHECK-LABEL: mm_usati_32_knownbits_i64: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: usati a0, a0, 32 ; CHECK-NEXT: pack a0, a0, a1 ; CHECK-NEXT: ret entry: %0 = call i64 @llvm.smax.i64(i64 %x, i64 0) %1 = call i64 @llvm.smin.i64(i64 %0, i64 4294967295) %2 = shl i64 %y, 32 %3 = or i64 %1, %2 ret i64 %3 } ; Test USATI select patterns define i3 @usati_i3_from_i64(i64 %x) { ; CHECK-LABEL: usati_i3_from_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: usati a0, a0, 3 ; CHECK-NEXT: ret %cmp1 = icmp ugt i64 %x, 7 %cmp2 = icmp sgt i64 %x, -1 %cmp2.ext = sext i1 %cmp2 to i3 %trunc = trunc i64 %x to i3 %sel = select i1 %cmp1, i3 %cmp2.ext, i3 %trunc ret i3 %sel } define i5 @usati_i5_from_i64(i64 %x) { ; CHECK-LABEL: usati_i5_from_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: usati a0, a0, 5 ; CHECK-NEXT: ret %cmp1 = icmp ugt i64 %x, 31 %cmp2 = icmp sgt i64 %x, -1 %cmp2.ext = sext i1 %cmp2 to i5 %trunc = trunc i64 %x to i5 %sel = select i1 %cmp1, i5 %cmp2.ext, i5 %trunc ret i5 %sel } define i7 @usati_i7_from_i64(i64 %x) { ; CHECK-LABEL: usati_i7_from_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: usati a0, a0, 7 ; CHECK-NEXT: ret %cmp1 = icmp ugt i64 %x, 127 %cmp2 = icmp sgt i64 %x, -1 %cmp2.ext = sext i1 %cmp2 to i7 %trunc = trunc i64 %x to i7 %sel = select i1 %cmp1, i7 %cmp2.ext, i7 %trunc ret i7 %sel } define i8 @usati_i8_from_i64(i64 %x) { ; CHECK-LABEL: usati_i8_from_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: usati a0, a0, 8 ; CHECK-NEXT: ret %cmp1 = icmp ugt i64 %x, 255 %cmp2 = icmp sgt i64 %x, -1 %cmp2.ext = sext i1 %cmp2 to i8 %trunc = trunc i64 %x to i8 %sel = select i1 %cmp1, i8 %cmp2.ext, i8 %trunc ret i8 %sel } define i10 @usati_i10_from_i64(i64 %x) { ; CHECK-LABEL: usati_i10_from_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: usati a0, a0, 10 ; CHECK-NEXT: ret %cmp1 = icmp ugt i64 %x, 1023 %cmp2 = icmp sgt i64 %x, -1 %cmp2.ext = sext i1 %cmp2 to i10 %trunc = trunc i64 %x to i10 %sel = select i1 %cmp1, i10 %cmp2.ext, i10 %trunc ret i10 %sel } define i16 @usati_i16_from_i64(i64 %x) { ; CHECK-LABEL: usati_i16_from_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: usati a0, a0, 16 ; CHECK-NEXT: ret %cmp1 = icmp ugt i64 %x, 65535 %cmp2 = icmp sgt i64 %x, -1 %cmp2.ext = sext i1 %cmp2 to i16 %trunc = trunc i64 %x to i16 %sel = select i1 %cmp1, i16 %cmp2.ext, i16 %trunc ret i16 %sel } define i20 @usati_i20_from_i64(i64 %x) { ; CHECK-LABEL: usati_i20_from_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: usati a0, a0, 20 ; CHECK-NEXT: ret %cmp1 = icmp ugt i64 %x, 1048575 %cmp2 = icmp sgt i64 %x, -1 %cmp2.ext = sext i1 %cmp2 to i20 %trunc = trunc i64 %x to i20 %sel = select i1 %cmp1, i20 %cmp2.ext, i20 %trunc ret i20 %sel } define i32 @usati_i32_from_i64(i64 %x) { ; CHECK-LABEL: usati_i32_from_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: usati a0, a0, 32 ; CHECK-NEXT: ret %cmp1 = icmp ugt i64 %x, 4294967295 %cmp2 = icmp sgt i64 %x, -1 %cmp2.ext = sext i1 %cmp2 to i32 %trunc = trunc i64 %x to i32 %sel = select i1 %cmp1, i32 %cmp2.ext, i32 %trunc ret i32 %sel } define i40 @usati_i40_from_i64(i64 %x) { ; CHECK-LABEL: usati_i40_from_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: usati a0, a0, 40 ; CHECK-NEXT: ret %cmp1 = icmp ugt i64 %x, 1099511627775 %cmp2 = icmp sgt i64 %x, -1 %cmp2.ext = sext i1 %cmp2 to i40 %trunc = trunc i64 %x to i40 %sel = select i1 %cmp1, i40 %cmp2.ext, i40 %trunc ret i40 %sel } define i48 @usati_i48_from_i64(i64 %x) { ; CHECK-LABEL: usati_i48_from_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: usati a0, a0, 48 ; CHECK-NEXT: ret %cmp1 = icmp ugt i64 %x, 281474976710655 %cmp2 = icmp sgt i64 %x, -1 %cmp2.ext = sext i1 %cmp2 to i48 %trunc = trunc i64 %x to i48 %sel = select i1 %cmp1, i48 %cmp2.ext, i48 %trunc ret i48 %sel } define i56 @usati_i56_from_i64(i64 %x) { ; CHECK-LABEL: usati_i56_from_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: usati a0, a0, 56 ; CHECK-NEXT: ret %cmp1 = icmp ugt i64 %x, 72057594037927935 %cmp2 = icmp sgt i64 %x, -1 %cmp2.ext = sext i1 %cmp2 to i56 %trunc = trunc i64 %x to i56 %sel = select i1 %cmp1, i56 %cmp2.ext, i56 %trunc ret i56 %sel } define i63 @usati_i63_from_i64(i64 %x) { ; CHECK-LABEL: usati_i63_from_i64: ; CHECK: # %bb.0: ; CHECK-NEXT: usati a0, a0, 63 ; CHECK-NEXT: ret %cmp1 = icmp ugt i64 %x, 9223372036854775807 %cmp2 = icmp sgt i64 %x, -1 %cmp2.ext = sext i1 %cmp2 to i63 %trunc = trunc i64 %x to i63 %sel = select i1 %cmp1, i63 %cmp2.ext, i63 %trunc ret i63 %sel } ; Test USATI with non-XLen source types (now supported by looking through truncates) define i8 @usati_i8_from_i16(i16 %x) { ; CHECK-LABEL: usati_i8_from_i16: ; CHECK: # %bb.0: ; CHECK-NEXT: sext.h a0, a0 ; CHECK-NEXT: usati a0, a0, 8 ; CHECK-NEXT: ret %cmp1 = icmp ugt i16 %x, 255 %cmp2 = icmp sgt i16 %x, -1 %cmp2.ext = sext i1 %cmp2 to i8 %trunc = trunc i16 %x to i8 %sel = select i1 %cmp1, i8 %cmp2.ext, i8 %trunc ret i8 %sel } define i8 @usati_i8_from_i32(i32 %x) { ; CHECK-LABEL: usati_i8_from_i32: ; CHECK: # %bb.0: ; CHECK-NEXT: sext.w a0, a0 ; CHECK-NEXT: usati a0, a0, 8 ; CHECK-NEXT: ret %cmp1 = icmp ugt i32 %x, 255 %cmp2 = icmp sgt i32 %x, -1 %cmp2.ext = sext i1 %cmp2 to i8 %trunc = trunc i32 %x to i8 %sel = select i1 %cmp1, i8 %cmp2.ext, i8 %trunc ret i8 %sel } define i16 @usati_i16_from_i32(i32 %x) { ; CHECK-LABEL: usati_i16_from_i32: ; CHECK: # %bb.0: ; CHECK-NEXT: sext.w a0, a0 ; CHECK-NEXT: usati a0, a0, 16 ; CHECK-NEXT: ret %cmp1 = icmp ugt i32 %x, 65535 %cmp2 = icmp sgt i32 %x, -1 %cmp2.ext = sext i1 %cmp2 to i16 %trunc = trunc i32 %x to i16 %sel = select i1 %cmp1, i16 %cmp2.ext, i16 %trunc ret i16 %sel } define i16 @usati_i16_from_i48(i48 %x) { ; CHECK-LABEL: usati_i16_from_i48: ; CHECK: # %bb.0: ; CHECK-NEXT: slli a0, a0, 16 ; CHECK-NEXT: srai a0, a0, 16 ; CHECK-NEXT: usati a0, a0, 16 ; CHECK-NEXT: ret %cmp1 = icmp ugt i48 %x, 65535 %cmp2 = icmp sgt i48 %x, -1 %cmp2.ext = sext i1 %cmp2 to i16 %trunc = trunc i48 %x to i16 %sel = select i1 %cmp1, i16 %cmp2.ext, i16 %trunc ret i16 %sel } define i32 @usati_i32_from_i48(i48 %x) { ; CHECK-LABEL: usati_i32_from_i48: ; CHECK: # %bb.0: ; CHECK-NEXT: slli a0, a0, 16 ; CHECK-NEXT: srai a0, a0, 16 ; CHECK-NEXT: usati a0, a0, 32 ; CHECK-NEXT: ret %cmp1 = icmp ugt i48 %x, 4294967295 %cmp2 = icmp sgt i48 %x, -1 %cmp2.ext = sext i1 %cmp2 to i32 %trunc = trunc i48 %x to i32 %sel = select i1 %cmp1, i32 %cmp2.ext, i32 %trunc ret i32 %sel } define i64 @macc_w00(i64 %rd, i32 %a, i32 %b) nounwind { ; CHECK-LABEL: macc_w00: ; CHECK: # %bb.0: ; CHECK-NEXT: macc.w00 a0, a1, a2 ; CHECK-NEXT: ret %aext = sext i32 %a to i64 %bext = sext i32 %b to i64 %mul = mul i64 %aext, %bext %result = add i64 %rd, %mul ret i64 %result } define i64 @macc_w00_commute(i64 %rd, i32 %a, i32 %b) nounwind { ; CHECK-LABEL: macc_w00_commute: ; CHECK: # %bb.0: ; CHECK-NEXT: macc.w00 a0, a1, a2 ; CHECK-NEXT: ret %aext = sext i32 %a to i64 %bext = sext i32 %b to i64 %mul = mul i64 %aext, %bext %result = add i64 %mul, %rd ret i64 %result } define i64 @maccu_w00(i64 %rd, i32 %a, i32 %b) nounwind { ; CHECK-LABEL: maccu_w00: ; CHECK: # %bb.0: ; CHECK-NEXT: maccu.w00 a0, a1, a2 ; CHECK-NEXT: ret %aext = zext i32 %a to i64 %bext = zext i32 %b to i64 %mul = mul i64 %aext, %bext %result = add i64 %rd, %mul ret i64 %result } define i64 @maccu_w00_commute(i64 %rd, i32 %a, i32 %b) nounwind { ; CHECK-LABEL: maccu_w00_commute: ; CHECK: # %bb.0: ; CHECK-NEXT: maccu.w00 a0, a1, a2 ; CHECK-NEXT: ret %aext = zext i32 %a to i64 %bext = zext i32 %b to i64 %mul = mul i64 %aext, %bext %result = add i64 %mul, %rd ret i64 %result } define i64 @maccsu_w00(i64 %rd, i32 %a, i32 %b) nounwind { ; CHECK-LABEL: maccsu_w00: ; CHECK: # %bb.0: ; CHECK-NEXT: maccsu.w00 a0, a1, a2 ; CHECK-NEXT: ret %aext = sext i32 %a to i64 %bext = zext i32 %b to i64 %mul = mul i64 %aext, %bext %result = add i64 %rd, %mul ret i64 %result } define i64 @maccsu_w00_commute(i64 %rd, i32 %a, i32 %b) nounwind { ; CHECK-LABEL: maccsu_w00_commute: ; CHECK: # %bb.0: ; CHECK-NEXT: maccsu.w00 a0, a1, a2 ; CHECK-NEXT: ret %aext = sext i32 %a to i64 %bext = zext i32 %b to i64 %mul = mul i64 %aext, %bext %result = add i64 %mul, %rd ret i64 %result } define i64 @maccsu_w00_swap_operands(i64 %rd, i32 %a, i32 %b) nounwind { ; CHECK-LABEL: maccsu_w00_swap_operands: ; CHECK: # %bb.0: ; CHECK-NEXT: maccsu.w00 a0, a2, a1 ; CHECK-NEXT: ret %aext = zext i32 %a to i64 %bext = sext i32 %b to i64 %mul = mul i64 %aext, %bext %result = add i64 %rd, %mul ret i64 %result } define i64 @maccsu_w00_swap_operands_commute(i64 %rd, i32 %a, i32 %b) nounwind { ; CHECK-LABEL: maccsu_w00_swap_operands_commute: ; CHECK: # %bb.0: ; CHECK-NEXT: maccsu.w00 a0, a2, a1 ; CHECK-NEXT: ret %aext = zext i32 %a to i64 %bext = sext i32 %b to i64 %mul = mul i64 %aext, %bext %result = add i64 %mul, %rd ret i64 %result } ; Negative test: multiply result has multiple uses, should not combine to macc define i64 @macc_w00_multiple_uses(i32 %a, i32 %b, i64 %c, ptr %out) nounwind { ; CHECK-LABEL: macc_w00_multiple_uses: ; CHECK: # %bb.0: ; CHECK-NEXT: mul.w00 a1, a0, a1 ; CHECK-NEXT: add a0, a2, a1 ; CHECK-NEXT: sd a1, 0(a3) ; CHECK-NEXT: ret %aext = sext i32 %a to i64 %bext = sext i32 %b to i64 %mul = mul i64 %aext, %bext %result = add i64 %c, %mul store i64 %mul, ptr %out ret i64 %result } ; Test that pli.b is rematerialized rather than spilled define i64 @test_pli_b_remat(ptr %p) nounwind { ; CHECK-LABEL: test_pli_b_remat: ; CHECK: # %bb.0: ; CHECK-NEXT: addi sp, sp, -112 ; CHECK-NEXT: sd ra, 104(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s0, 96(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s1, 88(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s2, 80(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s3, 72(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s4, 64(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s5, 56(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s6, 48(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s7, 40(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s8, 32(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s9, 24(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s10, 16(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s11, 8(sp) # 8-byte Folded Spill ; CHECK-NEXT: pli.b a1, 37 ; CHECK-NEXT: sd a1, 0(a0) ; CHECK-NEXT: #APP ; CHECK-NEXT: #NO_APP ; CHECK-NEXT: pli.b a0, 37 ; CHECK-NEXT: ld ra, 104(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s0, 96(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s1, 88(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s2, 80(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s3, 72(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s4, 64(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s5, 56(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s6, 48(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s7, 40(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s8, 32(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s9, 24(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s10, 16(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s11, 8(sp) # 8-byte Folded Reload ; CHECK-NEXT: addi sp, sp, 112 ; CHECK-NEXT: ret store volatile i64 u0x2525252525252525, ptr %p ; Clobber all registers to force rematerialization tail call void asm sideeffect "", "~{x1},~{x3},~{x4},~{x5},~{x6},~{x7},~{x8},~{x9},~{x10},~{x11},~{x12},~{x13},~{x14},~{x15},~{x16},~{x17},~{x18},~{x19},~{x20},~{x21},~{x22},~{x23},~{x24},~{x25},~{x26},~{x27},~{x28},~{x29},~{x30},~{x31}"() ; Use the constant again - it should be rematerialized, not spilled/reloaded ret i64 u0x2525252525252525 } ; Test that pli.h is rematerialized rather than spilled define i64 @test_pli_h_remat(ptr %p) nounwind { ; CHECK-LABEL: test_pli_h_remat: ; CHECK: # %bb.0: ; CHECK-NEXT: addi sp, sp, -112 ; CHECK-NEXT: sd ra, 104(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s0, 96(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s1, 88(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s2, 80(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s3, 72(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s4, 64(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s5, 56(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s6, 48(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s7, 40(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s8, 32(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s9, 24(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s10, 16(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s11, 8(sp) # 8-byte Folded Spill ; CHECK-NEXT: pli.h a1, 291 ; CHECK-NEXT: sd a1, 0(a0) ; CHECK-NEXT: #APP ; CHECK-NEXT: #NO_APP ; CHECK-NEXT: pli.h a0, 291 ; CHECK-NEXT: ld ra, 104(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s0, 96(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s1, 88(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s2, 80(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s3, 72(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s4, 64(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s5, 56(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s6, 48(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s7, 40(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s8, 32(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s9, 24(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s10, 16(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s11, 8(sp) # 8-byte Folded Reload ; CHECK-NEXT: addi sp, sp, 112 ; CHECK-NEXT: ret store volatile i64 u0x0123012301230123, ptr %p ; Clobber all registers to force rematerialization tail call void asm sideeffect "", "~{x1},~{x3},~{x4},~{x5},~{x6},~{x7},~{x8},~{x9},~{x10},~{x11},~{x12},~{x13},~{x14},~{x15},~{x16},~{x17},~{x18},~{x19},~{x20},~{x21},~{x22},~{x23},~{x24},~{x25},~{x26},~{x27},~{x28},~{x29},~{x30},~{x31}"() ; Use the constant again - it should be rematerialized, not spilled/reloaded ret i64 u0x0123012301230123 } ; Test that plui.h is rematerialized rather than spilled define i64 @test_plui_h_remat(ptr %p) nounwind { ; CHECK-LABEL: test_plui_h_remat: ; CHECK: # %bb.0: ; CHECK-NEXT: addi sp, sp, -112 ; CHECK-NEXT: sd ra, 104(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s0, 96(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s1, 88(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s2, 80(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s3, 72(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s4, 64(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s5, 56(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s6, 48(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s7, 40(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s8, 32(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s9, 24(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s10, 16(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s11, 8(sp) # 8-byte Folded Spill ; CHECK-NEXT: plui.h a1, -9 ; CHECK-NEXT: sd a1, 0(a0) ; CHECK-NEXT: #APP ; CHECK-NEXT: #NO_APP ; CHECK-NEXT: plui.h a0, -9 ; CHECK-NEXT: ld ra, 104(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s0, 96(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s1, 88(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s2, 80(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s3, 72(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s4, 64(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s5, 56(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s6, 48(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s7, 40(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s8, 32(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s9, 24(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s10, 16(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s11, 8(sp) # 8-byte Folded Reload ; CHECK-NEXT: addi sp, sp, 112 ; CHECK-NEXT: ret store volatile i64 u0xfdc0fdc0fdc0fdc0, ptr %p ; Clobber all registers to force rematerialization tail call void asm sideeffect "", "~{x1},~{x3},~{x4},~{x5},~{x6},~{x7},~{x8},~{x9},~{x10},~{x11},~{x12},~{x13},~{x14},~{x15},~{x16},~{x17},~{x18},~{x19},~{x20},~{x21},~{x22},~{x23},~{x24},~{x25},~{x26},~{x27},~{x28},~{x29},~{x30},~{x31}"() ; Use the constant again - it should be rematerialized, not spilled/reloaded ret i64 u0xfdc0fdc0fdc0fdc0 } ; Test that pli.w is rematerialized rather than spilled define i64 @test_pli_w_remat(ptr %p) nounwind { ; CHECK-LABEL: test_pli_w_remat: ; CHECK: # %bb.0: ; CHECK-NEXT: addi sp, sp, -112 ; CHECK-NEXT: sd ra, 104(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s0, 96(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s1, 88(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s2, 80(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s3, 72(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s4, 64(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s5, 56(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s6, 48(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s7, 40(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s8, 32(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s9, 24(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s10, 16(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s11, 8(sp) # 8-byte Folded Spill ; CHECK-NEXT: pli.w a1, -292 ; CHECK-NEXT: sd a1, 0(a0) ; CHECK-NEXT: #APP ; CHECK-NEXT: #NO_APP ; CHECK-NEXT: pli.w a0, -292 ; CHECK-NEXT: ld ra, 104(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s0, 96(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s1, 88(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s2, 80(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s3, 72(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s4, 64(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s5, 56(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s6, 48(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s7, 40(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s8, 32(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s9, 24(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s10, 16(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s11, 8(sp) # 8-byte Folded Reload ; CHECK-NEXT: addi sp, sp, 112 ; CHECK-NEXT: ret store volatile i64 u0xfffffedcfffffedc, ptr %p ; Clobber all registers to force rematerialization tail call void asm sideeffect "", "~{x1},~{x3},~{x4},~{x5},~{x6},~{x7},~{x8},~{x9},~{x10},~{x11},~{x12},~{x13},~{x14},~{x15},~{x16},~{x17},~{x18},~{x19},~{x20},~{x21},~{x22},~{x23},~{x24},~{x25},~{x26},~{x27},~{x28},~{x29},~{x30},~{x31}"() ; Use the constant again - it should be rematerialized, not spilled/reloaded ret i64 u0xfffffedcfffffedc } ; Test that plui.w is rematerialized rather than spilled define i64 @test_plui_w_remat(ptr %p) nounwind { ; CHECK-LABEL: test_plui_w_remat: ; CHECK: # %bb.0: ; CHECK-NEXT: addi sp, sp, -112 ; CHECK-NEXT: sd ra, 104(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s0, 96(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s1, 88(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s2, 80(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s3, 72(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s4, 64(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s5, 56(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s6, 48(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s7, 40(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s8, 32(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s9, 24(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s10, 16(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s11, 8(sp) # 8-byte Folded Spill ; CHECK-NEXT: plui.w a1, 473 ; CHECK-NEXT: sd a1, 0(a0) ; CHECK-NEXT: #APP ; CHECK-NEXT: #NO_APP ; CHECK-NEXT: plui.w a0, 473 ; CHECK-NEXT: ld ra, 104(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s0, 96(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s1, 88(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s2, 80(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s3, 72(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s4, 64(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s5, 56(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s6, 48(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s7, 40(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s8, 32(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s9, 24(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s10, 16(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s11, 8(sp) # 8-byte Folded Reload ; CHECK-NEXT: addi sp, sp, 112 ; CHECK-NEXT: ret store volatile i64 u0x7640000076400000, ptr %p ; Clobber all registers to force rematerialization tail call void asm sideeffect "", "~{x1},~{x3},~{x4},~{x5},~{x6},~{x7},~{x8},~{x9},~{x10},~{x11},~{x12},~{x13},~{x14},~{x15},~{x16},~{x17},~{x18},~{x19},~{x20},~{x21},~{x22},~{x23},~{x24},~{x25},~{x26},~{x27},~{x28},~{x29},~{x30},~{x31}"() ; Use the constant again - it should be rematerialized, not spilled/reloaded ret i64 u0x7640000076400000 } ; The 0x0101010101010101 can be materialized with pli.b ; The multiply makes the upper 10 bits of the and result unneeded ; causing the mask to become 0x0001010101010101. Make sure we can still match ; the pli.b define i64 @and_mul_32bitsplat(i64 %x) { ; CHECK-LABEL: and_mul_32bitsplat: ; CHECK: # %bb.0: ; CHECK-NEXT: pli.b a1, 1 ; CHECK-NEXT: lui a2, 65664 ; CHECK-NEXT: and a0, a0, a1 ; CHECK-NEXT: addi a1, a2, 1024 ; CHECK-NEXT: slli a2, a1, 27 ; CHECK-NEXT: add a1, a1, a2 ; CHECK-NEXT: mul a0, a0, a1 ; CHECK-NEXT: ret %a = and i64 %x, u0x0101010101010101 %b = mul i64 %a, u0x0080402010080400 ret i64 %b }