| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | |
| ; RUN: opt -passes=reassociate -S %s | FileCheck %s | |
| ; ---- SHOULD transform ---- | |
| ; Basic case: a*8697 - (a+b)*6436 → a*2261 + b*(-6436) | |
| define i32 @test_basic(i32 %a, i32 %b) { | |
| ; CHECK-LABEL: @test_basic( | |
| ; CHECK-NEXT: [[MUL1_NEG:%.*]] = mul i32 [[B:%.*]], -6436 | |
| ; CHECK-NEXT: [[REASS_MUL:%.*]] = mul i32 [[A:%.*]], 2261 | |
| ; CHECK-NEXT: [[SUB:%.*]] = add i32 [[REASS_MUL]], [[MUL1_NEG]] | |
| ; CHECK-NEXT: ret i32 [[SUB]] | |
| ; | |
| %mul = mul nsw i32 %a, 8697 | |
| %add = add nsw i32 %a, %b | |
| %mul1 = mul nsw i32 %add, 6436 | |
| %sub = sub nsw i32 %mul, %mul1 | |
| ret i32 %sub | |
| } | |
| ; Sub instead of add inside: a*500 - (a-b)*300 | |
| define i32 @test_with_sub(i32 %a, i32 %b) { | |
| ; CHECK-LABEL: @test_with_sub( | |
| ; CHECK-NEXT: [[MUL2_NEG:%.*]] = mul i32 [[B:%.*]], 300 | |
| ; CHECK-NEXT: [[REASS_MUL:%.*]] = mul i32 [[A:%.*]], 200 | |
| ; CHECK-NEXT: [[SUB:%.*]] = add i32 [[REASS_MUL]], [[MUL2_NEG]] | |
| ; CHECK-NEXT: ret i32 [[SUB]] | |
| ; | |
| %mul = mul nsw i32 %a, 500 | |
| %sub1 = sub nsw i32 %a, %b | |
| %mul1 = mul nsw i32 %sub1, 300 | |
| %sub = sub nsw i32 %mul, %mul1 | |
| ret i32 %sub | |
| } | |
| ; b operand matches: b*11 + (a+b)*4 | |
| define i32 @test_b_matches(i32 %a, i32 %b) { | |
| ; CHECK-LABEL: @test_b_matches( | |
| ; CHECK-NEXT: [[MUL2:%.*]] = mul i32 [[A:%.*]], 4 | |
| ; CHECK-NEXT: [[REASS_MUL:%.*]] = mul i32 [[B:%.*]], 15 | |
| ; CHECK-NEXT: [[ADD2:%.*]] = add i32 [[REASS_MUL]], [[MUL2]] | |
| ; CHECK-NEXT: ret i32 [[ADD2]] | |
| ; | |
| %mul = mul nsw i32 %b, 11 | |
| %add = add nsw i32 %a, %b | |
| %mul1 = mul nsw i32 %add, 4 | |
| %add2 = add nsw i32 %mul, %mul1 | |
| ret i32 %add2 | |
| } | |
| ; NSW/NUW must be dropped on new instructions after distribution | |
| ; (x+y) *nsw 20 does NOT imply (x *nsw 20) + (y *nsw 20) | |
| define i16 @test_nsw_dropped(i16 %x, i16 %y) { | |
| ; CHECK-LABEL: @test_nsw_dropped( | |
| ; CHECK-NEXT: [[MUL1:%.*]] = mul i16 [[Y:%.*]], 25 | |
| ; CHECK-NEXT: [[REASS_MUL:%.*]] = mul i16 [[X:%.*]], 40 | |
| ; CHECK-NEXT: [[ADD2:%.*]] = add i16 [[MUL1]], [[REASS_MUL]] | |
| ; CHECK-NEXT: ret i16 [[ADD2]] | |
| ; | |
| %mul1 = mul nsw i16 %x, 15 | |
| %add = add nsw i16 %x, %y | |
| %mul2 = mul nsw i16 %add, 25 | |
| %add2 = add i16 %mul1, %mul2 | |
| ret i16 %add2 | |
| } | |
| ; ---- Should NOT transform ---- | |
| ; No sibling constant mul — nothing to combine with | |
| define i32 @test_no_match(i32 %a, i32 %b) { | |
| ; CHECK-LABEL: @test_no_match( | |
| ; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[B:%.*]], [[A:%.*]] | |
| ; CHECK-NEXT: [[MUL:%.*]] = mul nsw i32 [[ADD]], 999 | |
| ; CHECK-NEXT: ret i32 [[MUL]] | |
| ; | |
| %add = add nsw i32 %a, %b | |
| %mul = mul nsw i32 %add, 999 | |
| ret i32 %mul | |
| } | |
| ; AddSub has multiple uses (second use is an xor) — oneUse required for distribution | |
| define i32 @test_multi_use_add(i32 %a, i32 %b) { | |
| ; CHECK-LABEL: @test_multi_use_add( | |
| ; CHECK-NEXT: [[MUL:%.*]] = mul nsw i32 [[A:%.*]], 777 | |
| ; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[B:%.*]], [[A]] | |
| ; CHECK-NEXT: [[MUL1:%.*]] = mul nsw i32 [[ADD]], 444 | |
| ; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[MUL]], [[MUL1]] | |
| ; CHECK-NEXT: [[RET:%.*]] = xor i32 [[SUB]], [[ADD]] | |
| ; CHECK-NEXT: ret i32 [[RET]] | |
| ; | |
| %mul = mul nsw i32 %a, 777 | |
| %add = add nsw i32 %a, %b | |
| %mul1 = mul nsw i32 %add, 444 | |
| %sub = sub nsw i32 %mul, %mul1 | |
| %ret = xor i32 %sub, %add | |
| ret i32 %ret | |
| } | |
| ; Sibling mul has no constant operand — should not trigger | |
| define i32 @test_no_const_on_other_mul(i32 %a, i32 %b, i32 %c) { | |
| ; CHECK-LABEL: @test_no_const_on_other_mul( | |
| ; CHECK-NEXT: [[MUL:%.*]] = mul nsw i32 [[C:%.*]], [[A:%.*]] | |
| ; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[B:%.*]], [[A]] | |
| ; CHECK-NEXT: [[MUL1:%.*]] = mul nsw i32 [[ADD]], 555 | |
| ; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[MUL]], [[MUL1]] | |
| ; CHECK-NEXT: ret i32 [[SUB]] | |
| ; | |
| %mul = mul nsw i32 %a, %c | |
| %add = add nsw i32 %a, %b | |
| %mul1 = mul nsw i32 %add, 555 | |
| %sub = sub nsw i32 %mul, %mul1 | |
| ret i32 %sub | |
| } |