blob: b9d2dadfc3b1ddd5f2564cd0441c9de838d30936 [file] [edit]
; 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
}