| ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py | |
| ; RUN: llc -mtriple=aarch64-none-elf < %s | FileCheck %s --check-prefixes=CHECK,CHECK-SD | |
| ; RUN: llc -mtriple=aarch64-none-elf -global-isel < %s | FileCheck %s --check-prefixes=CHECK,CHECK-GI | |
| ; Add pure 12-bit immediates: | |
| define i32 @add_small_i32(i32 %val32) { | |
| ; CHECK-LABEL: add_small_i32: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: add w0, w0, #4095 | |
| ; CHECK-NEXT: ret | |
| %newval32 = add i32 %val32, 4095 | |
| ret i32 %newval32 | |
| } | |
| define i64 @add_small_i64(i64 %val64) { | |
| ; CHECK-LABEL: add_small_i64: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: add x0, x0, #52 | |
| ; CHECK-NEXT: ret | |
| %newval64 = add i64 %val64, 52 | |
| ret i64 %newval64 | |
| } | |
| define void @add_small_imm(ptr %p, ptr %q, i32 %b, ptr %addr) { | |
| ; CHECK-LABEL: add_small_imm: | |
| ; CHECK: // %bb.0: // %entry | |
| ; CHECK-NEXT: ldrb w8, [x0] | |
| ; CHECK-NEXT: add w9, w8, w2 | |
| ; CHECK-NEXT: add x8, x8, #12 | |
| ; CHECK-NEXT: str w9, [x3] | |
| ; CHECK-NEXT: str x8, [x1] | |
| ; CHECK-NEXT: ret | |
| entry: | |
| %t = load i8, ptr %p | |
| %promoted = zext i8 %t to i64 | |
| %zextt = zext i8 %t to i32 | |
| %add = add nuw i32 %zextt, %b | |
| %add2 = add nuw i64 %promoted, 12 | |
| store i32 %add, ptr %addr | |
| store i64 %add2, ptr %q | |
| ret void | |
| } | |
| ; Add 12-bit immediates, shifted left by 12 bits | |
| define i32 @add_med_i32(i32 %val32) { | |
| ; CHECK-LABEL: add_med_i32: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: add w0, w0, #3567, lsl #12 // =14610432 | |
| ; CHECK-NEXT: ret | |
| %newval32 = add i32 %val32, 14610432 ; =0xdef000 | |
| ret i32 %newval32 | |
| } | |
| define i64 @add_med_i64(i64 %val64) { | |
| ; CHECK-LABEL: add_med_i64: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: add x0, x0, #4095, lsl #12 // =16773120 | |
| ; CHECK-NEXT: ret | |
| %newval64 = add i64 %val64, 16773120 ; =0xfff000 | |
| ret i64 %newval64 | |
| } | |
| ; Subtract 12-bit immediates | |
| define i32 @sub_small_i32(i32 %val32) { | |
| ; CHECK-LABEL: sub_small_i32: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: sub w0, w0, #4095 | |
| ; CHECK-NEXT: ret | |
| %newval32 = sub i32 %val32, 4095 | |
| ret i32 %newval32 | |
| } | |
| define i64 @sub_small_i64(i64 %val64) { | |
| ; CHECK-LABEL: sub_small_i64: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: sub x0, x0, #52 | |
| ; CHECK-NEXT: ret | |
| %newval64 = sub i64 %val64, 52 | |
| ret i64 %newval64 | |
| } | |
| ; Subtract 12-bit immediates, shifted left by 12 bits | |
| define i32 @sub_med_i32(i32 %val32) { | |
| ; CHECK-LABEL: sub_med_i32: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: sub w0, w0, #3567, lsl #12 // =14610432 | |
| ; CHECK-NEXT: ret | |
| %newval32 = sub i32 %val32, 14610432 ; =0xdef000 | |
| ret i32 %newval32 | |
| } | |
| define i64 @sub_med_i64(i64 %val64) { | |
| ; CHECK-LABEL: sub_med_i64: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: sub x0, x0, #4095, lsl #12 // =16773120 | |
| ; CHECK-NEXT: ret | |
| %newval64 = sub i64 %val64, 16773120 ; =0xfff000 | |
| ret i64 %newval64 | |
| } | |
| define i64 @add_two_parts_imm_i64(i64 %a) { | |
| ; CHECK-LABEL: add_two_parts_imm_i64: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: add x8, x0, #2730, lsl #12 // =11182080 | |
| ; CHECK-NEXT: add x0, x8, #1365 | |
| ; CHECK-NEXT: ret | |
| %b = add i64 %a, 11183445 | |
| ret i64 %b | |
| } | |
| define i32 @add_two_parts_imm_i32(i32 %a) { | |
| ; CHECK-LABEL: add_two_parts_imm_i32: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: add w8, w0, #2730, lsl #12 // =11182080 | |
| ; CHECK-NEXT: add w0, w8, #1365 | |
| ; CHECK-NEXT: ret | |
| %b = add i32 %a, 11183445 | |
| ret i32 %b | |
| } | |
| define i64 @add_two_parts_imm_i64_neg(i64 %a) { | |
| ; CHECK-LABEL: add_two_parts_imm_i64_neg: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: sub x8, x0, #2730, lsl #12 // =11182080 | |
| ; CHECK-NEXT: sub x0, x8, #1365 | |
| ; CHECK-NEXT: ret | |
| %b = add i64 %a, -11183445 | |
| ret i64 %b | |
| } | |
| define i32 @add_two_parts_imm_i32_neg(i32 %a) { | |
| ; CHECK-LABEL: add_two_parts_imm_i32_neg: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: sub w8, w0, #2730, lsl #12 // =11182080 | |
| ; CHECK-NEXT: sub w0, w8, #1365 | |
| ; CHECK-NEXT: ret | |
| %b = add i32 %a, -11183445 | |
| ret i32 %b | |
| } | |
| define i64 @sub_two_parts_imm_i64(i64 %a) { | |
| ; CHECK-LABEL: sub_two_parts_imm_i64: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: sub x8, x0, #2730, lsl #12 // =11182080 | |
| ; CHECK-NEXT: sub x0, x8, #1365 | |
| ; CHECK-NEXT: ret | |
| %b = sub i64 %a, 11183445 | |
| ret i64 %b | |
| } | |
| define i32 @sub_two_parts_imm_i32(i32 %a) { | |
| ; CHECK-LABEL: sub_two_parts_imm_i32: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: sub w8, w0, #2730, lsl #12 // =11182080 | |
| ; CHECK-NEXT: sub w0, w8, #1365 | |
| ; CHECK-NEXT: ret | |
| %b = sub i32 %a, 11183445 | |
| ret i32 %b | |
| } | |
| define i64 @sub_two_parts_imm_i64_neg(i64 %a) { | |
| ; CHECK-LABEL: sub_two_parts_imm_i64_neg: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: add x8, x0, #2730, lsl #12 // =11182080 | |
| ; CHECK-NEXT: add x0, x8, #1365 | |
| ; CHECK-NEXT: ret | |
| %b = sub i64 %a, -11183445 | |
| ret i64 %b | |
| } | |
| define i32 @sub_two_parts_imm_i32_neg(i32 %a) { | |
| ; CHECK-LABEL: sub_two_parts_imm_i32_neg: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: add w8, w0, #2730, lsl #12 // =11182080 | |
| ; CHECK-NEXT: add w0, w8, #1365 | |
| ; CHECK-NEXT: ret | |
| %b = sub i32 %a, -11183445 | |
| ret i32 %b | |
| } | |
| define i32 @add_27962026(i32 %a) { | |
| ; CHECK-LABEL: add_27962026: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: mov w8, #43690 // =0xaaaa | |
| ; CHECK-NEXT: movk w8, #426, lsl #16 | |
| ; CHECK-NEXT: add w0, w0, w8 | |
| ; CHECK-NEXT: ret | |
| %b = add i32 %a, 27962026 | |
| ret i32 %b | |
| } | |
| define i32 @add_65534(i32 %a) { | |
| ; CHECK-LABEL: add_65534: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: mov w8, #65534 // =0xfffe | |
| ; CHECK-NEXT: add w0, w0, w8 | |
| ; CHECK-NEXT: ret | |
| %b = add i32 %a, 65534 | |
| ret i32 %b | |
| } | |
| declare i32 @foox(i32) | |
| define void @add_in_loop(i32 %0) { | |
| ; CHECK-LABEL: add_in_loop: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: stp x30, x19, [sp, #-16]! // 16-byte Folded Spill | |
| ; CHECK-NEXT: .cfi_def_cfa_offset 16 | |
| ; CHECK-NEXT: .cfi_offset w19, -8 | |
| ; CHECK-NEXT: .cfi_offset w30, -16 | |
| ; CHECK-NEXT: mov w19, #43690 // =0xaaaa | |
| ; CHECK-NEXT: movk w19, #170, lsl #16 | |
| ; CHECK-NEXT: .LBB19_1: // =>This Inner Loop Header: Depth=1 | |
| ; CHECK-NEXT: add w0, w0, w19 | |
| ; CHECK-NEXT: bl foox | |
| ; CHECK-NEXT: b .LBB19_1 | |
| br label %2 | |
| 2: | |
| %3 = phi i32 [ %0, %1 ], [ %5, %2 ] | |
| %4 = add nsw i32 %3, 11184810 | |
| %5 = tail call i32 @foox(i32 %4) #2 | |
| br label %2 | |
| } | |
| define void @testing(ptr %var_i32, ptr %var2_i32) { | |
| ; CHECK-SD-LABEL: testing: | |
| ; CHECK-SD: // %bb.0: | |
| ; CHECK-SD-NEXT: ldr w8, [x0] | |
| ; CHECK-SD-NEXT: cmp w8, #4095 | |
| ; CHECK-SD-NEXT: b.ne .LBB20_6 | |
| ; CHECK-SD-NEXT: // %bb.1: // %test2 | |
| ; CHECK-SD-NEXT: ldr w9, [x1] | |
| ; CHECK-SD-NEXT: add w10, w8, #1 | |
| ; CHECK-SD-NEXT: str w10, [x0] | |
| ; CHECK-SD-NEXT: cmp w9, #3567, lsl #12 // =14610432 | |
| ; CHECK-SD-NEXT: b.lo .LBB20_6 | |
| ; CHECK-SD-NEXT: // %bb.2: // %test3 | |
| ; CHECK-SD-NEXT: add w10, w8, #2 | |
| ; CHECK-SD-NEXT: cmp w8, #123 | |
| ; CHECK-SD-NEXT: str w10, [x0] | |
| ; CHECK-SD-NEXT: b.lt .LBB20_6 | |
| ; CHECK-SD-NEXT: // %bb.3: // %test4 | |
| ; CHECK-SD-NEXT: add w10, w8, #3 | |
| ; CHECK-SD-NEXT: cmp w9, #321 | |
| ; CHECK-SD-NEXT: str w10, [x0] | |
| ; CHECK-SD-NEXT: b.gt .LBB20_6 | |
| ; CHECK-SD-NEXT: // %bb.4: // %test5 | |
| ; CHECK-SD-NEXT: add w10, w8, #4 | |
| ; CHECK-SD-NEXT: cmn w9, #443 | |
| ; CHECK-SD-NEXT: str w10, [x0] | |
| ; CHECK-SD-NEXT: b.ge .LBB20_6 | |
| ; CHECK-SD-NEXT: // %bb.5: // %test6 | |
| ; CHECK-SD-NEXT: add w8, w8, #5 | |
| ; CHECK-SD-NEXT: str w8, [x0] | |
| ; CHECK-SD-NEXT: .LBB20_6: // %common.ret | |
| ; CHECK-SD-NEXT: ret | |
| ; | |
| ; CHECK-GI-LABEL: testing: | |
| ; CHECK-GI: // %bb.0: | |
| ; CHECK-GI-NEXT: ldr w8, [x0] | |
| ; CHECK-GI-NEXT: cmp w8, #4095 | |
| ; CHECK-GI-NEXT: b.ne .LBB20_6 | |
| ; CHECK-GI-NEXT: // %bb.1: // %test2 | |
| ; CHECK-GI-NEXT: ldr w9, [x1] | |
| ; CHECK-GI-NEXT: add w10, w8, #1 | |
| ; CHECK-GI-NEXT: str w10, [x0] | |
| ; CHECK-GI-NEXT: cmp w9, #3567, lsl #12 // =14610432 | |
| ; CHECK-GI-NEXT: b.lo .LBB20_6 | |
| ; CHECK-GI-NEXT: // %bb.2: // %test3 | |
| ; CHECK-GI-NEXT: add w10, w8, #2 | |
| ; CHECK-GI-NEXT: cmp w8, #123 | |
| ; CHECK-GI-NEXT: str w10, [x0] | |
| ; CHECK-GI-NEXT: b.lt .LBB20_6 | |
| ; CHECK-GI-NEXT: // %bb.3: // %test4 | |
| ; CHECK-GI-NEXT: add w10, w8, #3 | |
| ; CHECK-GI-NEXT: cmp w9, #321 | |
| ; CHECK-GI-NEXT: str w10, [x0] | |
| ; CHECK-GI-NEXT: b.gt .LBB20_6 | |
| ; CHECK-GI-NEXT: // %bb.4: // %test5 | |
| ; CHECK-GI-NEXT: add w10, w8, #4 | |
| ; CHECK-GI-NEXT: cmn w9, #444 | |
| ; CHECK-GI-NEXT: str w10, [x0] | |
| ; CHECK-GI-NEXT: b.gt .LBB20_6 | |
| ; CHECK-GI-NEXT: // %bb.5: // %test6 | |
| ; CHECK-GI-NEXT: add w8, w8, #5 | |
| ; CHECK-GI-NEXT: str w8, [x0] | |
| ; CHECK-GI-NEXT: .LBB20_6: // %common.ret | |
| ; CHECK-GI-NEXT: ret | |
| %val = load i32, ptr %var_i32 | |
| %val2 = load i32, ptr %var2_i32 | |
| %cmp_pos_small = icmp ne i32 %val, 4095 | |
| br i1 %cmp_pos_small, label %ret, label %test2 | |
| test2: | |
| %newval2 = add i32 %val, 1 | |
| store i32 %newval2, ptr %var_i32 | |
| %cmp_pos_big = icmp ult i32 %val2, 14610432 | |
| br i1 %cmp_pos_big, label %ret, label %test3 | |
| test3: | |
| %newval3 = add i32 %val, 2 | |
| store i32 %newval3, ptr %var_i32 | |
| %cmp_pos_slt = icmp slt i32 %val, 123 | |
| br i1 %cmp_pos_slt, label %ret, label %test4 | |
| test4: | |
| %newval4 = add i32 %val, 3 | |
| store i32 %newval4, ptr %var_i32 | |
| %cmp_pos_sgt = icmp sgt i32 %val2, 321 | |
| br i1 %cmp_pos_sgt, label %ret, label %test5 | |
| test5: | |
| %newval5 = add i32 %val, 4 | |
| store i32 %newval5, ptr %var_i32 | |
| %cmp_neg_uge = icmp sgt i32 %val2, -444 | |
| br i1 %cmp_neg_uge, label %ret, label %test6 | |
| test6: | |
| %newval6 = add i32 %val, 5 | |
| store i32 %newval6, ptr %var_i32 | |
| ret void | |
| ret: | |
| ret void | |
| } | |
| declare {i32, i1} @llvm.sadd.with.overflow.i32(i32 %a, i32 %b) | |
| define i1 @sadd_add(i32 %a, i32 %b, ptr %p) { | |
| ; CHECK-LABEL: sadd_add: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: mvn w8, w0 | |
| ; CHECK-NEXT: adds w8, w8, w1 | |
| ; CHECK-NEXT: cset w0, vs | |
| ; CHECK-NEXT: add w8, w8, #1 | |
| ; CHECK-NEXT: str w8, [x2] | |
| ; CHECK-NEXT: ret | |
| %nota = xor i32 %a, -1 | |
| %a0 = call {i32, i1} @llvm.sadd.with.overflow.i32(i32 %nota, i32 %b) | |
| %e0 = extractvalue {i32, i1} %a0, 0 | |
| %e1 = extractvalue {i32, i1} %a0, 1 | |
| %res = add i32 %e0, 1 | |
| store i32 %res, ptr %p | |
| ret i1 %e1 | |
| } | |
| declare {i8, i1} @llvm.uadd.with.overflow.i8(i8 %a, i8 %b) | |
| define i1 @uadd_add(i8 %a, i8 %b, ptr %p) { | |
| ; CHECK-SD-LABEL: uadd_add: | |
| ; CHECK-SD: // %bb.0: | |
| ; CHECK-SD-NEXT: mov w8, #255 // =0xff | |
| ; CHECK-SD-NEXT: bic w8, w8, w0 | |
| ; CHECK-SD-NEXT: add w8, w8, w1, uxtb | |
| ; CHECK-SD-NEXT: lsr w0, w8, #8 | |
| ; CHECK-SD-NEXT: add w8, w8, #1 | |
| ; CHECK-SD-NEXT: strb w8, [x2] | |
| ; CHECK-SD-NEXT: ret | |
| ; | |
| ; CHECK-GI-LABEL: uadd_add: | |
| ; CHECK-GI: // %bb.0: | |
| ; CHECK-GI-NEXT: mvn w8, w0 | |
| ; CHECK-GI-NEXT: and w9, w1, #0xff | |
| ; CHECK-GI-NEXT: add w8, w9, w8, uxtb | |
| ; CHECK-GI-NEXT: cmp w8, w8, uxtb | |
| ; CHECK-GI-NEXT: add w8, w8, #1 | |
| ; CHECK-GI-NEXT: cset w0, ne | |
| ; CHECK-GI-NEXT: strb w8, [x2] | |
| ; CHECK-GI-NEXT: ret | |
| %nota = xor i8 %a, -1 | |
| %a0 = call {i8, i1} @llvm.uadd.with.overflow.i8(i8 %nota, i8 %b) | |
| %e0 = extractvalue {i8, i1} %a0, 0 | |
| %e1 = extractvalue {i8, i1} %a0, 1 | |
| %res = add i8 %e0, 1 | |
| store i8 %res, ptr %p | |
| ret i1 %e1 | |
| } | |
| ; This is a unique edge case that will generate the following MIR | |
| ; MOVi32imm -1000000 | |
| ; SUBREG_TO_REG killed %1, %subreg.sub_32 | |
| ; When using a 64-bit unsigned for the "-1000000" immediate, the code | |
| ; must make sure to zero out the top 32 bits since SUBREG_TO_REG is | |
| ; zero extending the value | |
| define i64 @addl_0x80000000(i64 %a) { | |
| ; CHECK-LABEL: addl_0x80000000: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: mov w8, #48576 // =0xbdc0 | |
| ; CHECK-NEXT: movk w8, #65520, lsl #16 | |
| ; CHECK-NEXT: add x0, x0, x8 | |
| ; CHECK-NEXT: ret | |
| %b = add i64 %a, 4293967296 | |
| ret i64 %b | |
| } | |
| ; ADDS and SUBS Optimizations | |
| ; Checks with all types first, then checks that only EQ and NE optimize | |
| define i1 @eq_i(i32 %0) { | |
| ; CHECK-LABEL: eq_i: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: sub w8, w0, #273, lsl #12 // =1118208 | |
| ; CHECK-NEXT: cmp w8, #273 | |
| ; CHECK-NEXT: cset w0, eq | |
| ; CHECK-NEXT: ret | |
| %2 = icmp eq i32 %0, 1118481 | |
| ret i1 %2 | |
| } | |
| define i1 @eq_l(i64 %0) { | |
| ; CHECK-LABEL: eq_l: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: sub x8, x0, #273, lsl #12 // =1118208 | |
| ; CHECK-NEXT: cmp x8, #273 | |
| ; CHECK-NEXT: cset w0, eq | |
| ; CHECK-NEXT: ret | |
| %2 = icmp eq i64 %0, 1118481 | |
| ret i1 %2 | |
| } | |
| define i1 @ne_i(i32 %0) { | |
| ; CHECK-LABEL: ne_i: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: sub w8, w0, #273, lsl #12 // =1118208 | |
| ; CHECK-NEXT: cmp w8, #273 | |
| ; CHECK-NEXT: cset w0, ne | |
| ; CHECK-NEXT: ret | |
| %2 = icmp ne i32 %0, 1118481 | |
| ret i1 %2 | |
| } | |
| define i1 @ne_l(i64 %0) { | |
| ; CHECK-LABEL: ne_l: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: sub x8, x0, #273, lsl #12 // =1118208 | |
| ; CHECK-NEXT: cmp x8, #273 | |
| ; CHECK-NEXT: cset w0, ne | |
| ; CHECK-NEXT: ret | |
| %2 = icmp ne i64 %0, 1118481 | |
| ret i1 %2 | |
| } | |
| define i1 @eq_in(i32 %0) { | |
| ; CHECK-LABEL: eq_in: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: add w8, w0, #273, lsl #12 // =1118208 | |
| ; CHECK-NEXT: cmn w8, #273 | |
| ; CHECK-NEXT: cset w0, eq | |
| ; CHECK-NEXT: ret | |
| %2 = icmp eq i32 %0, -1118481 | |
| ret i1 %2 | |
| } | |
| define i1 @eq_ln(i64 %0) { | |
| ; CHECK-LABEL: eq_ln: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: add x8, x0, #273, lsl #12 // =1118208 | |
| ; CHECK-NEXT: cmn x8, #273 | |
| ; CHECK-NEXT: cset w0, eq | |
| ; CHECK-NEXT: ret | |
| %2 = icmp eq i64 %0, -1118481 | |
| ret i1 %2 | |
| } | |
| define i1 @ne_in(i32 %0) { | |
| ; CHECK-LABEL: ne_in: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: add w8, w0, #273, lsl #12 // =1118208 | |
| ; CHECK-NEXT: cmn w8, #273 | |
| ; CHECK-NEXT: cset w0, ne | |
| ; CHECK-NEXT: ret | |
| %2 = icmp ne i32 %0, -1118481 | |
| ret i1 %2 | |
| } | |
| define i1 @ne_ln(i64 %0) { | |
| ; CHECK-LABEL: ne_ln: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: add x8, x0, #273, lsl #12 // =1118208 | |
| ; CHECK-NEXT: cmn x8, #273 | |
| ; CHECK-NEXT: cset w0, ne | |
| ; CHECK-NEXT: ret | |
| %2 = icmp ne i64 %0, -1118481 | |
| ret i1 %2 | |
| } | |
| define i1 @reject_eq(i32 %0) { | |
| ; CHECK-LABEL: reject_eq: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: mov w8, #51712 // =0xca00 | |
| ; CHECK-NEXT: movk w8, #15258, lsl #16 | |
| ; CHECK-NEXT: cmp w0, w8 | |
| ; CHECK-NEXT: cset w0, eq | |
| ; CHECK-NEXT: ret | |
| %2 = icmp eq i32 %0, 1000000000 | |
| ret i1 %2 | |
| } | |
| define i1 @reject_non_eqne_csinc(i32 %0) { | |
| ; CHECK-LABEL: reject_non_eqne_csinc: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: mov w8, #4369 // =0x1111 | |
| ; CHECK-NEXT: movk w8, #17, lsl #16 | |
| ; CHECK-NEXT: cmp w0, w8 | |
| ; CHECK-NEXT: cset w0, lo | |
| ; CHECK-NEXT: ret | |
| %2 = icmp ult i32 %0, 1118481 | |
| ret i1 %2 | |
| } | |
| define i32 @accept_csel(i32 %0) { | |
| ; CHECK-SD-LABEL: accept_csel: | |
| ; CHECK-SD: // %bb.0: | |
| ; CHECK-SD-NEXT: sub w9, w0, #273, lsl #12 // =1118208 | |
| ; CHECK-SD-NEXT: mov w8, #17 // =0x11 | |
| ; CHECK-SD-NEXT: cmp w9, #273 | |
| ; CHECK-SD-NEXT: mov w9, #11 // =0xb | |
| ; CHECK-SD-NEXT: csel w0, w9, w8, eq | |
| ; CHECK-SD-NEXT: ret | |
| ; | |
| ; CHECK-GI-LABEL: accept_csel: | |
| ; CHECK-GI: // %bb.0: | |
| ; CHECK-GI-NEXT: sub w8, w0, #273, lsl #12 // =1118208 | |
| ; CHECK-GI-NEXT: mov w9, #17 // =0x11 | |
| ; CHECK-GI-NEXT: mov w10, #11 // =0xb | |
| ; CHECK-GI-NEXT: cmp w8, #273 | |
| ; CHECK-GI-NEXT: csel w0, w10, w9, eq | |
| ; CHECK-GI-NEXT: ret | |
| %2 = icmp eq i32 %0, 1118481 | |
| %3 = select i1 %2, i32 11, i32 17 | |
| ret i32 %3 | |
| } | |
| define i32 @reject_non_eqne_csel(i32 %0) { | |
| ; CHECK-SD-LABEL: reject_non_eqne_csel: | |
| ; CHECK-SD: // %bb.0: | |
| ; CHECK-SD-NEXT: mov w8, #4369 // =0x1111 | |
| ; CHECK-SD-NEXT: mov w9, #11 // =0xb | |
| ; CHECK-SD-NEXT: movk w8, #17, lsl #16 | |
| ; CHECK-SD-NEXT: cmp w0, w8 | |
| ; CHECK-SD-NEXT: mov w8, #17 // =0x11 | |
| ; CHECK-SD-NEXT: csel w0, w9, w8, lo | |
| ; CHECK-SD-NEXT: ret | |
| ; | |
| ; CHECK-GI-LABEL: reject_non_eqne_csel: | |
| ; CHECK-GI: // %bb.0: | |
| ; CHECK-GI-NEXT: mov w8, #4369 // =0x1111 | |
| ; CHECK-GI-NEXT: mov w9, #17 // =0x11 | |
| ; CHECK-GI-NEXT: mov w10, #11 // =0xb | |
| ; CHECK-GI-NEXT: movk w8, #17, lsl #16 | |
| ; CHECK-GI-NEXT: cmp w0, w8 | |
| ; CHECK-GI-NEXT: csel w0, w10, w9, lo | |
| ; CHECK-GI-NEXT: ret | |
| %2 = icmp ult i32 %0, 1118481 | |
| %3 = select i1 %2, i32 11, i32 17 | |
| ret i32 %3 | |
| } | |
| declare void @fooy() | |
| define void @accept_branch(i32 %0) { | |
| ; CHECK-LABEL: accept_branch: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: sub w8, w0, #291, lsl #12 // =1191936 | |
| ; CHECK-NEXT: cmp w8, #1110 | |
| ; CHECK-NEXT: b.eq .LBB36_2 | |
| ; CHECK-NEXT: // %bb.1: | |
| ; CHECK-NEXT: ret | |
| ; CHECK-NEXT: .LBB36_2: | |
| ; CHECK-NEXT: b fooy | |
| %2 = icmp ne i32 %0, 1193046 | |
| br i1 %2, label %4, label %3 | |
| 3: ; preds = %1 | |
| tail call void @fooy() | |
| br label %4 | |
| 4: ; preds = %3, %1 | |
| ret void | |
| } | |
| define void @reject_non_eqne_branch(i32 %0) { | |
| ; CHECK-LABEL: reject_non_eqne_branch: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: mov w8, #13398 // =0x3456 | |
| ; CHECK-NEXT: movk w8, #18, lsl #16 | |
| ; CHECK-NEXT: cmp w0, w8 | |
| ; CHECK-NEXT: b.le .LBB37_2 | |
| ; CHECK-NEXT: // %bb.1: | |
| ; CHECK-NEXT: ret | |
| ; CHECK-NEXT: .LBB37_2: | |
| ; CHECK-NEXT: b fooy | |
| %2 = icmp sgt i32 %0, 1193046 | |
| br i1 %2, label %4, label %3 | |
| 3: ; preds = %1 | |
| tail call void @fooy() | |
| br label %4 | |
| 4: ; preds = %3, %1 | |
| ret void | |
| } | |
| define i32 @reject_multiple_usages(i32 %0) { | |
| ; CHECK-SD-LABEL: reject_multiple_usages: | |
| ; CHECK-SD: // %bb.0: | |
| ; CHECK-SD-NEXT: mov w8, #4369 // =0x1111 | |
| ; CHECK-SD-NEXT: mov w9, #3 // =0x3 | |
| ; CHECK-SD-NEXT: mov w10, #17 // =0x11 | |
| ; CHECK-SD-NEXT: movk w8, #17, lsl #16 | |
| ; CHECK-SD-NEXT: mov w11, #12 // =0xc | |
| ; CHECK-SD-NEXT: cmp w0, w8 | |
| ; CHECK-SD-NEXT: mov w8, #9 // =0x9 | |
| ; CHECK-SD-NEXT: csel w8, w8, w9, eq | |
| ; CHECK-SD-NEXT: csel w9, w11, w10, hi | |
| ; CHECK-SD-NEXT: mov w10, #53312 // =0xd040 | |
| ; CHECK-SD-NEXT: movk w10, #2, lsl #16 | |
| ; CHECK-SD-NEXT: add w8, w8, w9 | |
| ; CHECK-SD-NEXT: mov w9, #26304 // =0x66c0 | |
| ; CHECK-SD-NEXT: cmp w0, w10 | |
| ; CHECK-SD-NEXT: movk w9, #1433, lsl #16 | |
| ; CHECK-SD-NEXT: csel w0, w8, w9, hi | |
| ; CHECK-SD-NEXT: ret | |
| ; | |
| ; CHECK-GI-LABEL: reject_multiple_usages: | |
| ; CHECK-GI: // %bb.0: | |
| ; CHECK-GI-NEXT: mov w8, #4369 // =0x1111 | |
| ; CHECK-GI-NEXT: mov w9, #3 // =0x3 | |
| ; CHECK-GI-NEXT: mov w10, #9 // =0x9 | |
| ; CHECK-GI-NEXT: movk w8, #17, lsl #16 | |
| ; CHECK-GI-NEXT: mov w11, #12 // =0xc | |
| ; CHECK-GI-NEXT: cmp w0, w8 | |
| ; CHECK-GI-NEXT: mov w8, #17 // =0x11 | |
| ; CHECK-GI-NEXT: csel w9, w10, w9, eq | |
| ; CHECK-GI-NEXT: csel w8, w11, w8, hi | |
| ; CHECK-GI-NEXT: mov w10, #53312 // =0xd040 | |
| ; CHECK-GI-NEXT: movk w10, #2, lsl #16 | |
| ; CHECK-GI-NEXT: add w8, w9, w8 | |
| ; CHECK-GI-NEXT: mov w9, #26304 // =0x66c0 | |
| ; CHECK-GI-NEXT: movk w9, #1433, lsl #16 | |
| ; CHECK-GI-NEXT: cmp w0, w10 | |
| ; CHECK-GI-NEXT: csel w0, w8, w9, hi | |
| ; CHECK-GI-NEXT: ret | |
| %2 = icmp eq i32 %0, 1118481 | |
| %3 = icmp ugt i32 %0, 1118481 | |
| %4 = select i1 %2, i32 9, i32 3 | |
| %5 = select i1 %3, i32 12, i32 17 | |
| %6 = add i32 %4, %5 | |
| %7 = icmp ugt i32 %0, 184384 | |
| %8 = select i1 %7, i32 %6, i32 93939392 | |
| ret i32 %8 | |
| } | |
| ; Unique case found in ClangBuiltLinux where the DstReg is not Virtual and | |
| ; caused an assertion failure | |
| define dso_local i32 @neigh_periodic_work_tbl_1() { | |
| ; CHECK-LABEL: neigh_periodic_work_tbl_1: | |
| ; CHECK: // %bb.0: // %entry | |
| ; CHECK-NEXT: adrp x8, neigh_periodic_work_tbl_1 | |
| ; CHECK-NEXT: add x8, x8, :lo12:neigh_periodic_work_tbl_1 | |
| ; CHECK-NEXT: add x8, x8, #18, lsl #12 // =73728 | |
| ; CHECK-NEXT: cmn x8, #1272 | |
| ; CHECK-NEXT: b.mi .LBB39_2 | |
| ; CHECK-NEXT: // %bb.1: // %if.end | |
| ; CHECK-NEXT: ret | |
| ; CHECK-NEXT: .LBB39_2: // %for.cond | |
| ; CHECK-NEXT: // =>This Inner Loop Header: Depth=1 | |
| ; CHECK-NEXT: b .LBB39_2 | |
| entry: | |
| %cmp = icmp slt i64 add (i64 ptrtoint (ptr @neigh_periodic_work_tbl_1 to i64), i64 75000), 0 | |
| br i1 %cmp, label %for.cond, label %if.end | |
| for.cond: ; preds = %entry, %for.cond | |
| br label %for.cond | |
| if.end: ; preds = %entry | |
| ret i32 undef | |
| } | |
| @jiffies = dso_local local_unnamed_addr global i32 0, align 4 | |
| @primary_crng = dso_local local_unnamed_addr global i32 0, align 4 | |
| @input_pool = dso_local global i32 0, align 4 | |
| declare dso_local i32 @crng_reseed(...) local_unnamed_addr | |
| ; Function Attrs: nounwind uwtable | |
| define dso_local i32 @_extract_crng_crng() { | |
| ; CHECK-LABEL: _extract_crng_crng: | |
| ; CHECK: // %bb.0: // %entry | |
| ; CHECK-NEXT: adrp x8, _extract_crng_crng | |
| ; CHECK-NEXT: add x8, x8, :lo12:_extract_crng_crng | |
| ; CHECK-NEXT: tbnz x8, #63, .LBB40_2 | |
| ; CHECK-NEXT: // %bb.1: // %lor.lhs.false | |
| ; CHECK-NEXT: adrp x9, jiffies | |
| ; CHECK-NEXT: ldrsw x9, [x9, :lo12:jiffies] | |
| ; CHECK-NEXT: sub x8, x8, x9 | |
| ; CHECK-NEXT: add x8, x8, #18, lsl #12 // =73728 | |
| ; CHECK-NEXT: cmn x8, #1272 | |
| ; CHECK-NEXT: b.pl .LBB40_3 | |
| ; CHECK-NEXT: .LBB40_2: // %if.then | |
| ; CHECK-NEXT: adrp x8, primary_crng | |
| ; CHECK-NEXT: ldr w8, [x8, :lo12:primary_crng] | |
| ; CHECK-NEXT: cmp w8, #0 | |
| ; CHECK-NEXT: adrp x8, input_pool | |
| ; CHECK-NEXT: add x8, x8, :lo12:input_pool | |
| ; CHECK-NEXT: csel x0, xzr, x8, eq | |
| ; CHECK-NEXT: b crng_reseed | |
| ; CHECK-NEXT: .LBB40_3: // %if.end | |
| ; CHECK-NEXT: ret | |
| entry: | |
| %cmp2 = icmp slt ptr @_extract_crng_crng, null | |
| br i1 %cmp2, label %if.then, label %lor.lhs.false | |
| lor.lhs.false: ; preds = %entry | |
| %0 = load i32, ptr @jiffies, align 4 | |
| %idx.ext = sext i32 %0 to i64 | |
| %idx.neg = sub nsw i64 0, %idx.ext | |
| %add.ptr = getelementptr i8, ptr getelementptr (i8, ptr @_extract_crng_crng, i64 75000), i64 %idx.neg | |
| %cmp = icmp slt ptr %add.ptr, null | |
| br i1 %cmp, label %if.then, label %if.end | |
| if.then: ; preds = %lor.lhs.false, %entry | |
| %1 = load i32, ptr @primary_crng, align 4 | |
| %tobool.not = icmp eq i32 %1, 0 | |
| %cond = select i1 %tobool.not, ptr null, ptr @input_pool | |
| %call = tail call i32 @crng_reseed(ptr noundef %cond) | |
| br label %if.end | |
| if.end: ; preds = %if.then, %lor.lhs.false | |
| ret i32 undef | |
| } | |
| ; ((X << C) - Y) + Z --> (Z - Y) + (X << C) | |
| define i32 @commute_subop0(i32 %x, i32 %y, i32 %z) { | |
| ; CHECK-SD-LABEL: commute_subop0: | |
| ; CHECK-SD: // %bb.0: | |
| ; CHECK-SD-NEXT: sub w8, w2, w1 | |
| ; CHECK-SD-NEXT: add w0, w8, w0, lsl #3 | |
| ; CHECK-SD-NEXT: ret | |
| ; | |
| ; CHECK-GI-LABEL: commute_subop0: | |
| ; CHECK-GI: // %bb.0: | |
| ; CHECK-GI-NEXT: lsl w8, w0, #3 | |
| ; CHECK-GI-NEXT: sub w8, w8, w1 | |
| ; CHECK-GI-NEXT: add w0, w8, w2 | |
| ; CHECK-GI-NEXT: ret | |
| %shl = shl i32 %x, 3 | |
| %sub = sub i32 %shl, %y | |
| %add = add i32 %sub, %z | |
| ret i32 %add | |
| } | |
| ; ((X >> C) - Y) + Z --> (Z - Y) + (X >> C) | |
| define i32 @commute_subop0_lshr(i32 %x, i32 %y, i32 %z) { | |
| ; CHECK-SD-LABEL: commute_subop0_lshr: | |
| ; CHECK-SD: // %bb.0: | |
| ; CHECK-SD-NEXT: sub w8, w2, w1 | |
| ; CHECK-SD-NEXT: add w0, w8, w0, lsr #3 | |
| ; CHECK-SD-NEXT: ret | |
| ; | |
| ; CHECK-GI-LABEL: commute_subop0_lshr: | |
| ; CHECK-GI: // %bb.0: | |
| ; CHECK-GI-NEXT: lsr w8, w0, #3 | |
| ; CHECK-GI-NEXT: sub w8, w8, w1 | |
| ; CHECK-GI-NEXT: add w0, w8, w2 | |
| ; CHECK-GI-NEXT: ret | |
| %lshr = lshr i32 %x, 3 | |
| %sub = sub i32 %lshr, %y | |
| %add = add i32 %sub, %z | |
| ret i32 %add | |
| } | |
| ; ((X >> C) - Y) + Z --> (Z - Y) + (X >> C) | |
| define i32 @commute_subop0_ashr(i32 %x, i32 %y, i32 %z) { | |
| ; CHECK-SD-LABEL: commute_subop0_ashr: | |
| ; CHECK-SD: // %bb.0: | |
| ; CHECK-SD-NEXT: sub w8, w2, w1 | |
| ; CHECK-SD-NEXT: add w0, w8, w0, asr #3 | |
| ; CHECK-SD-NEXT: ret | |
| ; | |
| ; CHECK-GI-LABEL: commute_subop0_ashr: | |
| ; CHECK-GI: // %bb.0: | |
| ; CHECK-GI-NEXT: asr w8, w0, #3 | |
| ; CHECK-GI-NEXT: sub w8, w8, w1 | |
| ; CHECK-GI-NEXT: add w0, w8, w2 | |
| ; CHECK-GI-NEXT: ret | |
| %ashr = ashr i32 %x, 3 | |
| %sub = sub i32 %ashr, %y | |
| %add = add i32 %sub, %z | |
| ret i32 %add | |
| } | |
| ; ((sext X) - Y) + Z --> (Z - Y) + (sext X) | |
| define i64 @commute_subop0_sext(i32 %x, i64 %y, i64 %z) { | |
| ; CHECK-SD-LABEL: commute_subop0_sext: | |
| ; CHECK-SD: // %bb.0: | |
| ; CHECK-SD-NEXT: sub x8, x2, x1 | |
| ; CHECK-SD-NEXT: add x0, x8, w0, sxtw | |
| ; CHECK-SD-NEXT: ret | |
| ; | |
| ; CHECK-GI-LABEL: commute_subop0_sext: | |
| ; CHECK-GI: // %bb.0: | |
| ; CHECK-GI-NEXT: // kill: def $w0 killed $w0 def $x0 | |
| ; CHECK-GI-NEXT: sxtw x8, w0 | |
| ; CHECK-GI-NEXT: sub x8, x8, x1 | |
| ; CHECK-GI-NEXT: add x0, x8, x2 | |
| ; CHECK-GI-NEXT: ret | |
| %sext = sext i32 %x to i64 | |
| %sub = sub i64 %sext, %y | |
| %add = add i64 %sub, %z | |
| ret i64 %add | |
| } | |
| ; ((sext_inreg X) - Y) + Z --> (Z - Y) + (sext_inreg X) | |
| define i64 @commute_subop0_sext_inreg(i64 %x, i64 %y, i64 %z) { | |
| ; CHECK-SD-LABEL: commute_subop0_sext_inreg: | |
| ; CHECK-SD: // %bb.0: | |
| ; CHECK-SD-NEXT: sub x8, x2, x1 | |
| ; CHECK-SD-NEXT: add x0, x8, w0, sxth | |
| ; CHECK-SD-NEXT: ret | |
| ; | |
| ; CHECK-GI-LABEL: commute_subop0_sext_inreg: | |
| ; CHECK-GI: // %bb.0: | |
| ; CHECK-GI-NEXT: sxth x8, w0 | |
| ; CHECK-GI-NEXT: sub x8, x8, x1 | |
| ; CHECK-GI-NEXT: add x0, x8, x2 | |
| ; CHECK-GI-NEXT: ret | |
| %shl = shl i64 %x, 48 | |
| %ashr = ashr i64 %shl, 48 | |
| %sub = sub i64 %ashr, %y | |
| %add = add i64 %sub, %z | |
| ret i64 %add | |
| } | |
| ; ((zext X) - Y) + Z --> (Z - Y) + (zext X) | |
| define i32 @commute_subop0_zext(i16 %x, i32 %y, i32 %z) { | |
| ; CHECK-SD-LABEL: commute_subop0_zext: | |
| ; CHECK-SD: // %bb.0: | |
| ; CHECK-SD-NEXT: sub w8, w2, w1 | |
| ; CHECK-SD-NEXT: add w0, w8, w0, uxth | |
| ; CHECK-SD-NEXT: ret | |
| ; | |
| ; CHECK-GI-LABEL: commute_subop0_zext: | |
| ; CHECK-GI: // %bb.0: | |
| ; CHECK-GI-NEXT: and w8, w0, #0xffff | |
| ; CHECK-GI-NEXT: sub w8, w8, w1 | |
| ; CHECK-GI-NEXT: add w0, w8, w2 | |
| ; CHECK-GI-NEXT: ret | |
| %zext = zext i16 %x to i32 | |
| %sub = sub i32 %zext, %y | |
| %add = add i32 %sub, %z | |
| ret i32 %add | |
| } | |
| ; ((anyext X) - Y) + Z --> (Z - Y) + (anyext X) | |
| define i8 @commute_subop0_anyext(i16 %a, i16 %b, i32 %c) { | |
| ; CHECK-SD-LABEL: commute_subop0_anyext: | |
| ; CHECK-SD: // %bb.0: | |
| ; CHECK-SD-NEXT: mov w8, #111 // =0x6f | |
| ; CHECK-SD-NEXT: sub w9, w2, w1 | |
| ; CHECK-SD-NEXT: madd w8, w0, w8, w9 | |
| ; CHECK-SD-NEXT: lsl w8, w8, #3 | |
| ; CHECK-SD-NEXT: sub w0, w8, #1776 | |
| ; CHECK-SD-NEXT: ret | |
| ; | |
| ; CHECK-GI-LABEL: commute_subop0_anyext: | |
| ; CHECK-GI: // %bb.0: | |
| ; CHECK-GI-NEXT: mov w8, #111 // =0x6f | |
| ; CHECK-GI-NEXT: add w9, w1, #222 | |
| ; CHECK-GI-NEXT: mul w8, w0, w8 | |
| ; CHECK-GI-NEXT: and w8, w8, #0xffff | |
| ; CHECK-GI-NEXT: sub w8, w8, w9, uxth | |
| ; CHECK-GI-NEXT: add w8, w8, w2 | |
| ; CHECK-GI-NEXT: lsl w0, w8, #3 | |
| ; CHECK-GI-NEXT: ret | |
| %aa = mul i16 %a, 111 | |
| %bb = add i16 %b, 222 | |
| %a_32 = zext i16 %aa to i32 | |
| %b_32 = zext i16 %bb to i32 | |
| %sub = sub i32 %a_32, %b_32 | |
| %add = add i32 %sub, %c | |
| %trunc = trunc i32 %add to i8 | |
| %r = shl i8 %trunc, 3 | |
| ret i8 %r | |
| } | |
| ; ((X and C) - Y) + Z --> (Z - Y) + (X and C) | |
| define i32 @commute_subop0_and(i32 %x, i32 %y, i32 %z) { | |
| ; CHECK-SD-LABEL: commute_subop0_and: | |
| ; CHECK-SD: // %bb.0: | |
| ; CHECK-SD-NEXT: sub w8, w2, w1 | |
| ; CHECK-SD-NEXT: add w0, w8, w0, uxtb | |
| ; CHECK-SD-NEXT: ret | |
| ; | |
| ; CHECK-GI-LABEL: commute_subop0_and: | |
| ; CHECK-GI: // %bb.0: | |
| ; CHECK-GI-NEXT: and w8, w0, #0xff | |
| ; CHECK-GI-NEXT: sub w8, w8, w1 | |
| ; CHECK-GI-NEXT: add w0, w8, w2 | |
| ; CHECK-GI-NEXT: ret | |
| %and = and i32 %x, 255 | |
| %sub = sub i32 %and, %y | |
| %add = add i32 %sub, %z | |
| ret i32 %add | |
| } | |
| ; Z + ((X << C) - Y) --> (Z - Y) + (X << C) | |
| define i32 @commute_subop0_cadd(i32 %x, i32 %y, i32 %z) { | |
| ; CHECK-SD-LABEL: commute_subop0_cadd: | |
| ; CHECK-SD: // %bb.0: | |
| ; CHECK-SD-NEXT: sub w8, w2, w1 | |
| ; CHECK-SD-NEXT: add w0, w8, w0, lsl #3 | |
| ; CHECK-SD-NEXT: ret | |
| ; | |
| ; CHECK-GI-LABEL: commute_subop0_cadd: | |
| ; CHECK-GI: // %bb.0: | |
| ; CHECK-GI-NEXT: lsl w8, w0, #3 | |
| ; CHECK-GI-NEXT: sub w8, w8, w1 | |
| ; CHECK-GI-NEXT: add w0, w2, w8 | |
| ; CHECK-GI-NEXT: ret | |
| %shl = shl i32 %x, 3 | |
| %sub = sub i32 %shl, %y | |
| %add = add i32 %z, %sub | |
| ret i32 %add | |
| } | |
| ; Y + ((X << C) - X) --> (Y - X) + (X << C) | |
| define i32 @commute_subop0_mul(i32 %x, i32 %y) { | |
| ; CHECK-SD-LABEL: commute_subop0_mul: | |
| ; CHECK-SD: // %bb.0: | |
| ; CHECK-SD-NEXT: sub w8, w1, w0 | |
| ; CHECK-SD-NEXT: add w0, w8, w0, lsl #3 | |
| ; CHECK-SD-NEXT: ret | |
| ; | |
| ; CHECK-GI-LABEL: commute_subop0_mul: | |
| ; CHECK-GI: // %bb.0: | |
| ; CHECK-GI-NEXT: lsl w8, w0, #3 | |
| ; CHECK-GI-NEXT: sub w8, w8, w0 | |
| ; CHECK-GI-NEXT: add w0, w8, w1 | |
| ; CHECK-GI-NEXT: ret | |
| %mul = mul i32 %x, 7 | |
| %add = add i32 %mul, %y | |
| ret i32 %add | |
| } | |
| ; negative case for ((X << C) - Y) + Z --> (Z - Y) + (X << C) | |
| ; Y can't be constant to avoid dead loop | |
| define i32 @commute_subop0_zconst(i32 %x, i32 %y) { | |
| ; CHECK-LABEL: commute_subop0_zconst: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: lsl w8, w0, #3 | |
| ; CHECK-NEXT: sub w8, w8, w1 | |
| ; CHECK-NEXT: add w0, w8, #1 | |
| ; CHECK-NEXT: ret | |
| %shl = shl i32 %x, 3 | |
| %sub = sub i32 %shl, %y | |
| %add = add i32 %sub, 1 | |
| ret i32 %add | |
| } | |
| ; negative case for ((X << C) - Y) + Z --> (Z - Y) + (X << C) | |
| ; Y can't be shift C also to avoid dead loop | |
| define i32 @commute_subop0_zshiftc_oneuse(i32 %x, i32 %y, i32 %z) { | |
| ; CHECK-LABEL: commute_subop0_zshiftc_oneuse: | |
| ; CHECK: // %bb.0: | |
| ; CHECK-NEXT: lsl w8, w0, #3 | |
| ; CHECK-NEXT: sub w8, w8, w1 | |
| ; CHECK-NEXT: add w0, w8, w2, lsl #2 | |
| ; CHECK-NEXT: ret | |
| %xshl = shl i32 %x, 3 | |
| %sub = sub i32 %xshl, %y | |
| %zshl = shl i32 %z, 2 | |
| %add = add i32 %sub, %zshl | |
| ret i32 %add | |
| } | |
| define i32 @commute_subop0_zshiftc(i32 %x, i32 %y, i32 %z) { | |
| ; CHECK-SD-LABEL: commute_subop0_zshiftc: | |
| ; CHECK-SD: // %bb.0: | |
| ; CHECK-SD-NEXT: lsl w8, w2, #2 | |
| ; CHECK-SD-NEXT: sub w9, w8, w1 | |
| ; CHECK-SD-NEXT: add w9, w9, w0, lsl #3 | |
| ; CHECK-SD-NEXT: eor w0, w8, w9 | |
| ; CHECK-SD-NEXT: ret | |
| ; | |
| ; CHECK-GI-LABEL: commute_subop0_zshiftc: | |
| ; CHECK-GI: // %bb.0: | |
| ; CHECK-GI-NEXT: lsl w8, w0, #3 | |
| ; CHECK-GI-NEXT: lsl w9, w2, #2 | |
| ; CHECK-GI-NEXT: sub w8, w8, w1 | |
| ; CHECK-GI-NEXT: add w8, w8, w9 | |
| ; CHECK-GI-NEXT: eor w0, w9, w8 | |
| ; CHECK-GI-NEXT: ret | |
| %xshl = shl i32 %x, 3 | |
| %sub = sub i32 %xshl, %y | |
| %zshl = shl i32 %z, 2 | |
| %add = add i32 %sub, %zshl | |
| %r = xor i32 %zshl, %add | |
| ret i32 %r | |
| } |