If `Y` and `Z` are constant then we can simplify to `(X - W) + (Y - Z)`. If `Y == Z` we can fold to `X - W`. Note these transform exist outside of InstCombine. The purpose of this commit is primarily to make it so that folds can generate these simplifiable patterns without having to worry about creating an inf loop.
2629 lines
75 KiB
LLVM
2629 lines
75 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
|
|
|
|
target datalayout = "e-p:64:64:64-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
|
|
|
|
define i32 @sub_constant(i32 %x) {
|
|
; CHECK-LABEL: @sub_constant(
|
|
; CHECK-NEXT: [[R:%.*]] = add i32 [[X:%.*]], -42
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%r = sub i32 %x, 42
|
|
ret i32 %r
|
|
}
|
|
|
|
@g = global i32 0
|
|
|
|
define i32 @sub_constant_expression(i32 %x) {
|
|
; CHECK-LABEL: @sub_constant_expression(
|
|
; CHECK-NEXT: [[R:%.*]] = sub i32 [[X:%.*]], ptrtoint (ptr @g to i32)
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%r = sub i32 %x, ptrtoint (ptr @g to i32)
|
|
ret i32 %r
|
|
}
|
|
|
|
define <2 x i32> @sub_constant_vec(<2 x i32> %x) {
|
|
; CHECK-LABEL: @sub_constant_vec(
|
|
; CHECK-NEXT: [[R:%.*]] = add <2 x i32> [[X:%.*]], <i32 -42, i32 12>
|
|
; CHECK-NEXT: ret <2 x i32> [[R]]
|
|
;
|
|
%r = sub <2 x i32> %x, <i32 42, i32 -12>
|
|
ret <2 x i32> %r
|
|
}
|
|
|
|
define <3 x i33> @sub_constant_vec_weird_type(<3 x i33> %x) {
|
|
; CHECK-LABEL: @sub_constant_vec_weird_type(
|
|
; CHECK-NEXT: [[R:%.*]] = add <3 x i33> [[X:%.*]], <i33 42, i33 -42, i33 12>
|
|
; CHECK-NEXT: ret <3 x i33> [[R]]
|
|
;
|
|
%r = sub <3 x i33> %x, <i33 -42, i33 42, i33 -12>
|
|
ret <3 x i33> %r
|
|
}
|
|
|
|
define <4 x i32> @sub_constant_expression_vec(<4 x i32> %x) {
|
|
; CHECK-LABEL: @sub_constant_expression_vec(
|
|
; CHECK-NEXT: [[R:%.*]] = sub <4 x i32> [[X:%.*]], bitcast (i128 ptrtoint (ptr @g to i128) to <4 x i32>)
|
|
; CHECK-NEXT: ret <4 x i32> [[R]]
|
|
;
|
|
%r = sub <4 x i32> %x, bitcast (i128 ptrtoint (ptr @g to i128) to <4 x i32>)
|
|
ret <4 x i32> %r
|
|
}
|
|
|
|
define i32 @neg_sub(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @neg_sub(
|
|
; CHECK-NEXT: [[R:%.*]] = add i32 [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%neg = sub i32 0, %x
|
|
%r = sub i32 %y, %neg
|
|
ret i32 %r
|
|
}
|
|
|
|
define i32 @neg_nsw_sub(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @neg_nsw_sub(
|
|
; CHECK-NEXT: [[R:%.*]] = add i32 [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%neg = sub nsw i32 0, %x
|
|
%r = sub i32 %y, %neg
|
|
ret i32 %r
|
|
}
|
|
|
|
define i32 @neg_sub_nsw(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @neg_sub_nsw(
|
|
; CHECK-NEXT: [[R:%.*]] = add i32 [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%neg = sub i32 0, %x
|
|
%r = sub nsw i32 %y, %neg
|
|
ret i32 %r
|
|
}
|
|
|
|
define i32 @neg_nsw_sub_nsw(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @neg_nsw_sub_nsw(
|
|
; CHECK-NEXT: [[R:%.*]] = add nsw i32 [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%neg = sub nsw i32 0, %x
|
|
%r = sub nsw i32 %y, %neg
|
|
ret i32 %r
|
|
}
|
|
|
|
define <2 x i32> @neg_sub_vec(<2 x i32> %x, <2 x i32> %y) {
|
|
; CHECK-LABEL: @neg_sub_vec(
|
|
; CHECK-NEXT: [[R:%.*]] = add <2 x i32> [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: ret <2 x i32> [[R]]
|
|
;
|
|
%neg = sub <2 x i32> zeroinitializer, %x
|
|
%r = sub <2 x i32> %y, %neg
|
|
ret <2 x i32> %r
|
|
}
|
|
|
|
define <2 x i32> @neg_nsw_sub_vec(<2 x i32> %x, <2 x i32> %y) {
|
|
; CHECK-LABEL: @neg_nsw_sub_vec(
|
|
; CHECK-NEXT: [[R:%.*]] = add <2 x i32> [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: ret <2 x i32> [[R]]
|
|
;
|
|
%neg = sub nsw <2 x i32> zeroinitializer, %x
|
|
%r = sub <2 x i32> %y, %neg
|
|
ret <2 x i32> %r
|
|
}
|
|
|
|
define <2 x i32> @neg_sub_nsw_vec(<2 x i32> %x, <2 x i32> %y) {
|
|
; CHECK-LABEL: @neg_sub_nsw_vec(
|
|
; CHECK-NEXT: [[R:%.*]] = add <2 x i32> [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: ret <2 x i32> [[R]]
|
|
;
|
|
%neg = sub <2 x i32> zeroinitializer, %x
|
|
%r = sub nsw <2 x i32> %y, %neg
|
|
ret <2 x i32> %r
|
|
}
|
|
|
|
define <2 x i32> @neg_nsw_sub_nsw_vec(<2 x i32> %x, <2 x i32> %y) {
|
|
; CHECK-LABEL: @neg_nsw_sub_nsw_vec(
|
|
; CHECK-NEXT: [[R:%.*]] = add nsw <2 x i32> [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: ret <2 x i32> [[R]]
|
|
;
|
|
%neg = sub nsw <2 x i32> zeroinitializer, %x
|
|
%r = sub nsw <2 x i32> %y, %neg
|
|
ret <2 x i32> %r
|
|
}
|
|
|
|
define <2 x i32> @neg_sub_vec_undef(<2 x i32> %x, <2 x i32> %y) {
|
|
; CHECK-LABEL: @neg_sub_vec_undef(
|
|
; CHECK-NEXT: [[R:%.*]] = add <2 x i32> [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: ret <2 x i32> [[R]]
|
|
;
|
|
%neg = sub <2 x i32> <i32 0, i32 undef>, %x
|
|
%r = sub <2 x i32> %y, %neg
|
|
ret <2 x i32> %r
|
|
}
|
|
|
|
define <2 x i32> @neg_nsw_sub_vec_undef(<2 x i32> %x, <2 x i32> %y) {
|
|
; CHECK-LABEL: @neg_nsw_sub_vec_undef(
|
|
; CHECK-NEXT: [[R:%.*]] = add <2 x i32> [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: ret <2 x i32> [[R]]
|
|
;
|
|
%neg = sub nsw <2 x i32> <i32 undef, i32 0>, %x
|
|
%r = sub <2 x i32> %y, %neg
|
|
ret <2 x i32> %r
|
|
}
|
|
|
|
define <2 x i32> @neg_sub_nsw_vec_undef(<2 x i32> %x, <2 x i32> %y) {
|
|
; CHECK-LABEL: @neg_sub_nsw_vec_undef(
|
|
; CHECK-NEXT: [[R:%.*]] = add <2 x i32> [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: ret <2 x i32> [[R]]
|
|
;
|
|
%neg = sub <2 x i32> <i32 undef, i32 0>, %x
|
|
%r = sub nsw <2 x i32> %y, %neg
|
|
ret <2 x i32> %r
|
|
}
|
|
|
|
; This should not drop 'nsw'.
|
|
|
|
define <2 x i32> @neg_nsw_sub_nsw_vec_undef(<2 x i32> %x, <2 x i32> %y) {
|
|
; CHECK-LABEL: @neg_nsw_sub_nsw_vec_undef(
|
|
; CHECK-NEXT: [[R:%.*]] = add nsw <2 x i32> [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: ret <2 x i32> [[R]]
|
|
;
|
|
%neg = sub nsw <2 x i32> <i32 0, i32 undef>, %x
|
|
%r = sub nsw <2 x i32> %y, %neg
|
|
ret <2 x i32> %r
|
|
}
|
|
|
|
; (~X) - (~Y) --> Y - X
|
|
; Also, show that we can handle extra uses and vectors.
|
|
|
|
declare void @use8(i8)
|
|
|
|
define i8 @notnotsub(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @notnotsub(
|
|
; CHECK-NEXT: [[NX:%.*]] = xor i8 [[X:%.*]], -1
|
|
; CHECK-NEXT: [[NY:%.*]] = xor i8 [[Y:%.*]], -1
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[Y]], [[X]]
|
|
; CHECK-NEXT: call void @use8(i8 [[NX]])
|
|
; CHECK-NEXT: call void @use8(i8 [[NY]])
|
|
; CHECK-NEXT: ret i8 [[SUB]]
|
|
;
|
|
%nx = xor i8 %x, -1
|
|
%ny = xor i8 %y, -1
|
|
%sub = sub i8 %nx, %ny
|
|
call void @use8(i8 %nx)
|
|
call void @use8(i8 %ny)
|
|
ret i8 %sub
|
|
}
|
|
|
|
define <2 x i8> @notnotsub_vec(<2 x i8> %x, <2 x i8> %y) {
|
|
; CHECK-LABEL: @notnotsub_vec(
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub <2 x i8> [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: ret <2 x i8> [[SUB]]
|
|
;
|
|
%nx = xor <2 x i8> %x, <i8 -1, i8 -1>
|
|
%ny = xor <2 x i8> %y, <i8 -1, i8 -1>
|
|
%sub = sub <2 x i8> %nx, %ny
|
|
ret <2 x i8> %sub
|
|
}
|
|
|
|
define <2 x i8> @notnotsub_vec_undef_elts(<2 x i8> %x, <2 x i8> %y) {
|
|
; CHECK-LABEL: @notnotsub_vec_undef_elts(
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub <2 x i8> [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: ret <2 x i8> [[SUB]]
|
|
;
|
|
%nx = xor <2 x i8> %x, <i8 undef, i8 -1>
|
|
%ny = xor <2 x i8> %y, <i8 -1, i8 undef>
|
|
%sub = sub <2 x i8> %nx, %ny
|
|
ret <2 x i8> %sub
|
|
}
|
|
|
|
define i32 @test5(i32 %A, i32 %B, i32 %C) {
|
|
; CHECK-LABEL: @test5(
|
|
; CHECK-NEXT: [[D_NEG:%.*]] = sub i32 [[C:%.*]], [[B:%.*]]
|
|
; CHECK-NEXT: [[E:%.*]] = add i32 [[D_NEG]], [[A:%.*]]
|
|
; CHECK-NEXT: ret i32 [[E]]
|
|
;
|
|
%D = sub i32 %B, %C
|
|
%E = sub i32 %A, %D
|
|
ret i32 %E
|
|
}
|
|
|
|
define i32 @test6(i32 %A, i32 %B) {
|
|
; CHECK-LABEL: @test6(
|
|
; CHECK-NEXT: [[B_NOT:%.*]] = xor i32 [[B:%.*]], -1
|
|
; CHECK-NEXT: [[D:%.*]] = and i32 [[B_NOT]], [[A:%.*]]
|
|
; CHECK-NEXT: ret i32 [[D]]
|
|
;
|
|
%C = and i32 %A, %B
|
|
%D = sub i32 %A, %C
|
|
ret i32 %D
|
|
}
|
|
|
|
define i32 @test6commuted(i32 %A, i32 %B) {
|
|
; CHECK-LABEL: @test6commuted(
|
|
; CHECK-NEXT: [[B_NOT:%.*]] = xor i32 [[B:%.*]], -1
|
|
; CHECK-NEXT: [[D:%.*]] = and i32 [[B_NOT]], [[A:%.*]]
|
|
; CHECK-NEXT: ret i32 [[D]]
|
|
;
|
|
%C = and i32 %B, %A
|
|
%D = sub i32 %A, %C
|
|
ret i32 %D
|
|
}
|
|
|
|
define i32 @test7(i32 %A) {
|
|
; CHECK-LABEL: @test7(
|
|
; CHECK-NEXT: [[B:%.*]] = xor i32 [[A:%.*]], -1
|
|
; CHECK-NEXT: ret i32 [[B]]
|
|
;
|
|
%B = sub i32 -1, %A
|
|
ret i32 %B
|
|
}
|
|
|
|
define i32 @test8(i32 %A) {
|
|
; CHECK-LABEL: @test8(
|
|
; CHECK-NEXT: [[C:%.*]] = shl i32 [[A:%.*]], 3
|
|
; CHECK-NEXT: ret i32 [[C]]
|
|
;
|
|
%B = mul i32 9, %A
|
|
%C = sub i32 %B, %A
|
|
ret i32 %C
|
|
}
|
|
|
|
define i32 @test9(i32 %A) {
|
|
; CHECK-LABEL: @test9(
|
|
; CHECK-NEXT: [[C:%.*]] = mul i32 [[A:%.*]], -2
|
|
; CHECK-NEXT: ret i32 [[C]]
|
|
;
|
|
%B = mul i32 3, %A
|
|
%C = sub i32 %A, %B
|
|
ret i32 %C
|
|
}
|
|
|
|
define i1 @test11(i8 %A, i8 %B) {
|
|
; CHECK-LABEL: @test11(
|
|
; CHECK-NEXT: [[D:%.*]] = icmp ne i8 [[A:%.*]], [[B:%.*]]
|
|
; CHECK-NEXT: ret i1 [[D]]
|
|
;
|
|
%C = sub i8 %A, %B
|
|
%D = icmp ne i8 %C, 0
|
|
ret i1 %D
|
|
}
|
|
|
|
define <2 x i1> @test11vec(<2 x i8> %A, <2 x i8> %B) {
|
|
; CHECK-LABEL: @test11vec(
|
|
; CHECK-NEXT: [[D:%.*]] = icmp ne <2 x i8> [[A:%.*]], [[B:%.*]]
|
|
; CHECK-NEXT: ret <2 x i1> [[D]]
|
|
;
|
|
%C = sub <2 x i8> %A, %B
|
|
%D = icmp ne <2 x i8> %C, zeroinitializer
|
|
ret <2 x i1> %D
|
|
}
|
|
|
|
define i32 @test12(i32 %A) {
|
|
; CHECK-LABEL: @test12(
|
|
; CHECK-NEXT: [[B_NEG:%.*]] = lshr i32 [[A:%.*]], 31
|
|
; CHECK-NEXT: ret i32 [[B_NEG]]
|
|
;
|
|
%B = ashr i32 %A, 31
|
|
%C = sub i32 0, %B
|
|
ret i32 %C
|
|
}
|
|
|
|
define i32 @test13(i32 %A) {
|
|
; CHECK-LABEL: @test13(
|
|
; CHECK-NEXT: [[B_NEG:%.*]] = ashr i32 [[A:%.*]], 31
|
|
; CHECK-NEXT: ret i32 [[B_NEG]]
|
|
;
|
|
%B = lshr i32 %A, 31
|
|
%C = sub i32 0, %B
|
|
ret i32 %C
|
|
}
|
|
|
|
define <2 x i32> @test12vec(<2 x i32> %A) {
|
|
; CHECK-LABEL: @test12vec(
|
|
; CHECK-NEXT: [[B_NEG:%.*]] = lshr <2 x i32> [[A:%.*]], <i32 31, i32 31>
|
|
; CHECK-NEXT: ret <2 x i32> [[B_NEG]]
|
|
;
|
|
%B = ashr <2 x i32> %A, <i32 31, i32 31>
|
|
%C = sub <2 x i32> zeroinitializer, %B
|
|
ret <2 x i32> %C
|
|
}
|
|
|
|
define <2 x i32> @test13vec(<2 x i32> %A) {
|
|
; CHECK-LABEL: @test13vec(
|
|
; CHECK-NEXT: [[B_NEG:%.*]] = ashr <2 x i32> [[A:%.*]], <i32 31, i32 31>
|
|
; CHECK-NEXT: ret <2 x i32> [[B_NEG]]
|
|
;
|
|
%B = lshr <2 x i32> %A, <i32 31, i32 31>
|
|
%C = sub <2 x i32> zeroinitializer, %B
|
|
ret <2 x i32> %C
|
|
}
|
|
|
|
define i32 @test15(i32 %A, i32 %B) {
|
|
; CHECK-LABEL: @test15(
|
|
; CHECK-NEXT: [[C:%.*]] = sub i32 0, [[A:%.*]]
|
|
; CHECK-NEXT: [[D:%.*]] = srem i32 [[B:%.*]], [[C]]
|
|
; CHECK-NEXT: ret i32 [[D]]
|
|
;
|
|
%C = sub i32 0, %A
|
|
%D = srem i32 %B, %C
|
|
ret i32 %D
|
|
}
|
|
|
|
define i32 @test16(i32 %A) {
|
|
; CHECK-LABEL: @test16(
|
|
; CHECK-NEXT: [[X_NEG:%.*]] = sdiv i32 [[A:%.*]], -1123
|
|
; CHECK-NEXT: ret i32 [[X_NEG]]
|
|
;
|
|
%X = sdiv i32 %A, 1123
|
|
%Y = sub i32 0, %X
|
|
ret i32 %Y
|
|
}
|
|
|
|
; Can't fold subtract here because negation it might oveflow.
|
|
; PR3142
|
|
define i32 @test17(i32 %A) {
|
|
; CHECK-LABEL: @test17(
|
|
; CHECK-NEXT: [[B:%.*]] = sub i32 0, [[A:%.*]]
|
|
; CHECK-NEXT: [[C:%.*]] = sdiv i32 [[B]], 1234
|
|
; CHECK-NEXT: ret i32 [[C]]
|
|
;
|
|
%B = sub i32 0, %A
|
|
%C = sdiv i32 %B, 1234
|
|
ret i32 %C
|
|
}
|
|
|
|
define i64 @test18(i64 %Y) {
|
|
; CHECK-LABEL: @test18(
|
|
; CHECK-NEXT: ret i64 0
|
|
;
|
|
%i.4 = shl i64 %Y, 2
|
|
%i.12 = shl i64 %Y, 2
|
|
%i.8 = sub i64 %i.4, %i.12
|
|
ret i64 %i.8
|
|
}
|
|
|
|
define i1 @test20(i32 %g, i32 %h) {
|
|
; CHECK-LABEL: @test20(
|
|
; CHECK-NEXT: [[I_4:%.*]] = icmp ne i32 [[H:%.*]], 0
|
|
; CHECK-NEXT: ret i1 [[I_4]]
|
|
;
|
|
%i.2 = sub i32 %g, %h
|
|
%i.4 = icmp ne i32 %i.2, %g
|
|
ret i1 %i.4
|
|
}
|
|
|
|
define i1 @test21(i32 %g, i32 %h) {
|
|
; CHECK-LABEL: @test21(
|
|
; CHECK-NEXT: [[I_4:%.*]] = icmp ne i32 [[H:%.*]], 0
|
|
; CHECK-NEXT: ret i1 [[I_4]]
|
|
;
|
|
%i.2 = sub i32 %g, %h
|
|
%i.4 = icmp ne i32 %i.2, %g
|
|
ret i1 %i.4
|
|
}
|
|
|
|
; PR2298
|
|
define zeroext i1 @test22(i32 %a, i32 %b) nounwind {
|
|
; CHECK-LABEL: @test22(
|
|
; CHECK-NEXT: [[I5:%.*]] = icmp eq i32 [[B:%.*]], [[A:%.*]]
|
|
; CHECK-NEXT: ret i1 [[I5]]
|
|
;
|
|
%i2 = sub i32 0, %a
|
|
%i4 = sub i32 0, %b
|
|
%i5 = icmp eq i32 %i2, %i4
|
|
ret i1 %i5
|
|
}
|
|
|
|
define i32 @test26(i32 %x) {
|
|
; CHECK-LABEL: @test26(
|
|
; CHECK-NEXT: [[SHL_NEG:%.*]] = shl i32 -3, [[X:%.*]]
|
|
; CHECK-NEXT: ret i32 [[SHL_NEG]]
|
|
;
|
|
%shl = shl i32 3, %x
|
|
%neg = sub i32 0, %shl
|
|
ret i32 %neg
|
|
}
|
|
|
|
define i64 @test_neg_shl_sub(i64 %a, i64 %b) {
|
|
; CHECK-LABEL: @test_neg_shl_sub(
|
|
; CHECK-NEXT: [[SUB_NEG:%.*]] = sub i64 [[B:%.*]], [[A:%.*]]
|
|
; CHECK-NEXT: [[MUL_NEG:%.*]] = shl i64 [[SUB_NEG]], 2
|
|
; CHECK-NEXT: ret i64 [[MUL_NEG]]
|
|
;
|
|
%sub = sub i64 %a, %b
|
|
%mul = shl i64 %sub, 2
|
|
%neg = sub i64 0, %mul
|
|
ret i64 %neg
|
|
}
|
|
|
|
define i64 @test_neg_shl_sub_extra_use1(i64 %a, i64 %b, ptr %p) {
|
|
; CHECK-LABEL: @test_neg_shl_sub_extra_use1(
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub i64 [[A:%.*]], [[B:%.*]]
|
|
; CHECK-NEXT: store i64 [[SUB]], ptr [[P:%.*]], align 8
|
|
; CHECK-NEXT: [[MUL_NEG:%.*]] = mul i64 [[SUB]], -4
|
|
; CHECK-NEXT: ret i64 [[MUL_NEG]]
|
|
;
|
|
%sub = sub i64 %a, %b
|
|
store i64 %sub, ptr %p
|
|
%mul = shl i64 %sub, 2
|
|
%neg = sub i64 0, %mul
|
|
ret i64 %neg
|
|
}
|
|
|
|
define i64 @test_neg_shl_sub_extra_use2(i64 %a, i64 %b, ptr %p) {
|
|
; CHECK-LABEL: @test_neg_shl_sub_extra_use2(
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub i64 [[A:%.*]], [[B:%.*]]
|
|
; CHECK-NEXT: [[MUL:%.*]] = shl i64 [[SUB]], 2
|
|
; CHECK-NEXT: store i64 [[MUL]], ptr [[P:%.*]], align 8
|
|
; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[MUL]]
|
|
; CHECK-NEXT: ret i64 [[NEG]]
|
|
;
|
|
%sub = sub i64 %a, %b
|
|
%mul = shl i64 %sub, 2
|
|
store i64 %mul, ptr %p
|
|
%neg = sub i64 0, %mul
|
|
ret i64 %neg
|
|
}
|
|
|
|
define i64 @test_neg_shl_div(i64 %a) {
|
|
; CHECK-LABEL: @test_neg_shl_div(
|
|
; CHECK-NEXT: [[DIV_NEG:%.*]] = sdiv i64 [[A:%.*]], -3
|
|
; CHECK-NEXT: [[SHL_NEG:%.*]] = shl i64 [[DIV_NEG]], 2
|
|
; CHECK-NEXT: ret i64 [[SHL_NEG]]
|
|
;
|
|
%div = sdiv i64 %a, 3
|
|
%shl = shl i64 %div, 2
|
|
%neg = sub i64 0, %shl
|
|
ret i64 %neg
|
|
}
|
|
|
|
define i64 @test_neg_shl_zext_i1(i1 %a, i64 %b) {
|
|
; CHECK-LABEL: @test_neg_shl_zext_i1(
|
|
; CHECK-NEXT: [[EXT_NEG:%.*]] = sext i1 [[A:%.*]] to i64
|
|
; CHECK-NEXT: [[SHL_NEG:%.*]] = shl nsw i64 [[EXT_NEG]], [[B:%.*]]
|
|
; CHECK-NEXT: ret i64 [[SHL_NEG]]
|
|
;
|
|
%ext = zext i1 %a to i64
|
|
%shl = shl i64 %ext, %b
|
|
%neg = sub i64 0, %shl
|
|
ret i64 %neg
|
|
}
|
|
|
|
define i64 @test_neg_shl_sext_i1(i1 %a, i64 %b) {
|
|
; CHECK-LABEL: @test_neg_shl_sext_i1(
|
|
; CHECK-NEXT: [[EXT_NEG:%.*]] = zext i1 [[A:%.*]] to i64
|
|
; CHECK-NEXT: [[SHL_NEG:%.*]] = shl nuw i64 [[EXT_NEG]], [[B:%.*]]
|
|
; CHECK-NEXT: ret i64 [[SHL_NEG]]
|
|
;
|
|
%ext = sext i1 %a to i64
|
|
%shl = shl i64 %ext, %b
|
|
%neg = sub i64 0, %shl
|
|
ret i64 %neg
|
|
}
|
|
|
|
define i64 @test_neg_zext_i1_extra_use(i1 %a, i64 %b, ptr %p) {
|
|
; CHECK-LABEL: @test_neg_zext_i1_extra_use(
|
|
; CHECK-NEXT: [[EXT_NEG:%.*]] = sext i1 [[A:%.*]] to i64
|
|
; CHECK-NEXT: [[EXT:%.*]] = zext i1 [[A]] to i64
|
|
; CHECK-NEXT: store i64 [[EXT]], ptr [[P:%.*]], align 8
|
|
; CHECK-NEXT: ret i64 [[EXT_NEG]]
|
|
;
|
|
%ext = zext i1 %a to i64
|
|
%neg = sub i64 0, %ext
|
|
store i64 %ext, ptr %p
|
|
ret i64 %neg
|
|
}
|
|
|
|
define i64 @test_neg_sext_i1_extra_use(i1 %a, i64 %b, ptr %p) {
|
|
; CHECK-LABEL: @test_neg_sext_i1_extra_use(
|
|
; CHECK-NEXT: [[EXT_NEG:%.*]] = zext i1 [[A:%.*]] to i64
|
|
; CHECK-NEXT: [[EXT:%.*]] = sext i1 [[A]] to i64
|
|
; CHECK-NEXT: store i64 [[EXT]], ptr [[P:%.*]], align 8
|
|
; CHECK-NEXT: ret i64 [[EXT_NEG]]
|
|
;
|
|
%ext = sext i1 %a to i64
|
|
%neg = sub i64 0, %ext
|
|
store i64 %ext, ptr %p
|
|
ret i64 %neg
|
|
}
|
|
|
|
define i32 @test_neg_trunc_shl_sub(i64 %a, i64 %b) {
|
|
; CHECK-LABEL: @test_neg_trunc_shl_sub(
|
|
; CHECK-NEXT: [[SUB_NEG:%.*]] = sub i64 [[B:%.*]], [[A:%.*]]
|
|
; CHECK-NEXT: [[SUB_TR_NEG:%.*]] = trunc i64 [[SUB_NEG]] to i32
|
|
; CHECK-NEXT: [[TRUNC_NEG:%.*]] = shl i32 [[SUB_TR_NEG]], 2
|
|
; CHECK-NEXT: ret i32 [[TRUNC_NEG]]
|
|
;
|
|
%sub = sub i64 %a, %b
|
|
%shl = shl i64 %sub, 2
|
|
%trunc = trunc i64 %shl to i32
|
|
%neg = sub i32 0, %trunc
|
|
ret i32 %neg
|
|
}
|
|
|
|
define i32 @test_neg_trunc_shl_ashr(i64 %a, i64 %b) {
|
|
; CHECK-LABEL: @test_neg_trunc_shl_ashr(
|
|
; CHECK-NEXT: [[SHR_NEG:%.*]] = lshr i64 [[A:%.*]], 63
|
|
; CHECK-NEXT: [[SHL_NEG:%.*]] = shl nuw i64 [[SHR_NEG]], [[B:%.*]]
|
|
; CHECK-NEXT: [[TRUNC_NEG:%.*]] = trunc i64 [[SHL_NEG]] to i32
|
|
; CHECK-NEXT: ret i32 [[TRUNC_NEG]]
|
|
;
|
|
%shr = ashr i64 %a, 63
|
|
%shl = shl i64 %shr, %b
|
|
%trunc = trunc i64 %shl to i32
|
|
%neg = sub i32 0, %trunc
|
|
ret i32 %neg
|
|
}
|
|
|
|
define i32 @test_neg_trunc_shl_lshr(i64 %a, i64 %b) {
|
|
; CHECK-LABEL: @test_neg_trunc_shl_lshr(
|
|
; CHECK-NEXT: [[SHR_NEG:%.*]] = ashr i64 [[A:%.*]], 63
|
|
; CHECK-NEXT: [[SHL_NEG:%.*]] = shl nsw i64 [[SHR_NEG]], [[B:%.*]]
|
|
; CHECK-NEXT: [[TRUNC_NEG:%.*]] = trunc i64 [[SHL_NEG]] to i32
|
|
; CHECK-NEXT: ret i32 [[TRUNC_NEG]]
|
|
;
|
|
%shr = lshr i64 %a, 63
|
|
%shl = shl i64 %shr, %b
|
|
%trunc = trunc i64 %shl to i32
|
|
%neg = sub i32 0, %trunc
|
|
ret i32 %neg
|
|
}
|
|
|
|
define i64 @test_neg_mul_sub(i64 %a, i64 %b, i64 %c) {
|
|
; CHECK-LABEL: @test_neg_mul_sub(
|
|
; CHECK-NEXT: [[SUB_NEG:%.*]] = sub i64 [[B:%.*]], [[A:%.*]]
|
|
; CHECK-NEXT: [[MUL_NEG:%.*]] = mul i64 [[SUB_NEG]], [[C:%.*]]
|
|
; CHECK-NEXT: ret i64 [[MUL_NEG]]
|
|
;
|
|
%sub = sub i64 %a, %b
|
|
%mul = mul i64 %sub, %c
|
|
%neg = sub i64 0, %mul
|
|
ret i64 %neg
|
|
}
|
|
|
|
define i64 @test_neg_mul_sub_commuted(i64 %a, i64 %b, i64 %c) {
|
|
; CHECK-LABEL: @test_neg_mul_sub_commuted(
|
|
; CHECK-NEXT: [[COMPLEX:%.*]] = mul i64 [[C:%.*]], [[C]]
|
|
; CHECK-NEXT: [[SUB_NEG:%.*]] = sub i64 [[B:%.*]], [[A:%.*]]
|
|
; CHECK-NEXT: [[MUL_NEG:%.*]] = mul i64 [[SUB_NEG]], [[COMPLEX]]
|
|
; CHECK-NEXT: ret i64 [[MUL_NEG]]
|
|
;
|
|
%complex = mul i64 %c, %c
|
|
%sub = sub i64 %a, %b
|
|
%mul = mul i64 %complex, %sub
|
|
%neg = sub i64 0, %mul
|
|
ret i64 %neg
|
|
}
|
|
|
|
define i32 @test27(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @test27(
|
|
; CHECK-NEXT: [[MUL_NEG:%.*]] = shl i32 [[Y:%.*]], 3
|
|
; CHECK-NEXT: [[SUB:%.*]] = add i32 [[MUL_NEG]], [[X:%.*]]
|
|
; CHECK-NEXT: ret i32 [[SUB]]
|
|
;
|
|
%mul = mul i32 %y, -8
|
|
%sub = sub i32 %x, %mul
|
|
ret i32 %sub
|
|
}
|
|
|
|
define <2 x i32> @test27vec(<2 x i32> %x, <2 x i32> %y) {
|
|
; CHECK-LABEL: @test27vec(
|
|
; CHECK-NEXT: [[MUL_NEG:%.*]] = mul <2 x i32> [[Y:%.*]], <i32 8, i32 6>
|
|
; CHECK-NEXT: [[SUB:%.*]] = add <2 x i32> [[MUL_NEG]], [[X:%.*]]
|
|
; CHECK-NEXT: ret <2 x i32> [[SUB]]
|
|
;
|
|
%mul = mul <2 x i32> %y, <i32 -8, i32 -6>
|
|
%sub = sub <2 x i32> %x, %mul
|
|
ret <2 x i32> %sub
|
|
}
|
|
|
|
define <2 x i32> @test27vecsplat(<2 x i32> %x, <2 x i32> %y) {
|
|
; CHECK-LABEL: @test27vecsplat(
|
|
; CHECK-NEXT: [[MUL_NEG:%.*]] = shl <2 x i32> [[Y:%.*]], <i32 3, i32 3>
|
|
; CHECK-NEXT: [[SUB:%.*]] = add <2 x i32> [[MUL_NEG]], [[X:%.*]]
|
|
; CHECK-NEXT: ret <2 x i32> [[SUB]]
|
|
;
|
|
%mul = mul <2 x i32> %y, <i32 -8, i32 -8>
|
|
%sub = sub <2 x i32> %x, %mul
|
|
ret <2 x i32> %sub
|
|
}
|
|
|
|
define <2 x i32> @test27vecmixed(<2 x i32> %x, <2 x i32> %y) {
|
|
; CHECK-LABEL: @test27vecmixed(
|
|
; CHECK-NEXT: [[MUL_NEG:%.*]] = mul <2 x i32> [[Y:%.*]], <i32 8, i32 -8>
|
|
; CHECK-NEXT: [[SUB:%.*]] = add <2 x i32> [[MUL_NEG]], [[X:%.*]]
|
|
; CHECK-NEXT: ret <2 x i32> [[SUB]]
|
|
;
|
|
%mul = mul <2 x i32> %y, <i32 -8, i32 8>
|
|
%sub = sub <2 x i32> %x, %mul
|
|
ret <2 x i32> %sub
|
|
}
|
|
|
|
define i32 @test27commuted(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @test27commuted(
|
|
; CHECK-NEXT: [[MUL_NEG:%.*]] = shl i32 [[Y:%.*]], 3
|
|
; CHECK-NEXT: [[SUB:%.*]] = add i32 [[MUL_NEG]], [[X:%.*]]
|
|
; CHECK-NEXT: ret i32 [[SUB]]
|
|
;
|
|
%mul = mul i32 -8, %y
|
|
%sub = sub i32 %x, %mul
|
|
ret i32 %sub
|
|
}
|
|
|
|
define <2 x i32> @test27commutedvec(<2 x i32> %x, <2 x i32> %y) {
|
|
; CHECK-LABEL: @test27commutedvec(
|
|
; CHECK-NEXT: [[MUL_NEG:%.*]] = mul <2 x i32> [[Y:%.*]], <i32 8, i32 6>
|
|
; CHECK-NEXT: [[SUB:%.*]] = add <2 x i32> [[MUL_NEG]], [[X:%.*]]
|
|
; CHECK-NEXT: ret <2 x i32> [[SUB]]
|
|
;
|
|
%mul = mul <2 x i32> <i32 -8, i32 -6>, %y
|
|
%sub = sub <2 x i32> %x, %mul
|
|
ret <2 x i32> %sub
|
|
}
|
|
|
|
define <2 x i32> @test27commutedvecsplat(<2 x i32> %x, <2 x i32> %y) {
|
|
; CHECK-LABEL: @test27commutedvecsplat(
|
|
; CHECK-NEXT: [[MUL_NEG:%.*]] = shl <2 x i32> [[Y:%.*]], <i32 3, i32 3>
|
|
; CHECK-NEXT: [[SUB:%.*]] = add <2 x i32> [[MUL_NEG]], [[X:%.*]]
|
|
; CHECK-NEXT: ret <2 x i32> [[SUB]]
|
|
;
|
|
%mul = mul <2 x i32> <i32 -8, i32 -8>, %y
|
|
%sub = sub <2 x i32> %x, %mul
|
|
ret <2 x i32> %sub
|
|
}
|
|
|
|
define <2 x i32> @test27commutedvecmixed(<2 x i32> %x, <2 x i32> %y) {
|
|
; CHECK-LABEL: @test27commutedvecmixed(
|
|
; CHECK-NEXT: [[MUL_NEG:%.*]] = mul <2 x i32> [[Y:%.*]], <i32 8, i32 -8>
|
|
; CHECK-NEXT: [[SUB:%.*]] = add <2 x i32> [[MUL_NEG]], [[X:%.*]]
|
|
; CHECK-NEXT: ret <2 x i32> [[SUB]]
|
|
;
|
|
%mul = mul <2 x i32> <i32 -8, i32 8>, %y
|
|
%sub = sub <2 x i32> %x, %mul
|
|
ret <2 x i32> %sub
|
|
}
|
|
|
|
define i32 @test28(i32 %x, i32 %y, i32 %z) {
|
|
; CHECK-LABEL: @test28(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[Z:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[SUB:%.*]] = add i32 [[TMP1]], [[X:%.*]]
|
|
; CHECK-NEXT: ret i32 [[SUB]]
|
|
;
|
|
%neg = sub i32 0, %z
|
|
%mul = mul i32 %neg, %y
|
|
%sub = sub i32 %x, %mul
|
|
ret i32 %sub
|
|
}
|
|
|
|
define i32 @test28commuted(i32 %x, i32 %y, i32 %z) {
|
|
; CHECK-LABEL: @test28commuted(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[Z:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[SUB:%.*]] = add i32 [[TMP1]], [[X:%.*]]
|
|
; CHECK-NEXT: ret i32 [[SUB]]
|
|
;
|
|
%neg = sub i32 0, %z
|
|
%mul = mul i32 %y, %neg
|
|
%sub = sub i32 %x, %mul
|
|
ret i32 %sub
|
|
}
|
|
|
|
define <2 x i64> @test31(<2 x i64> %A) {
|
|
; CHECK-LABEL: @test31(
|
|
; CHECK-NEXT: [[SUB:%.*]] = add <2 x i64> [[A:%.*]], <i64 3, i64 4>
|
|
; CHECK-NEXT: ret <2 x i64> [[SUB]]
|
|
;
|
|
%xor = xor <2 x i64> %A, <i64 -1, i64 -1>
|
|
%sub = sub <2 x i64> <i64 2, i64 3>, %xor
|
|
ret <2 x i64> %sub
|
|
}
|
|
|
|
define <2 x i64> @test32(<2 x i64> %A) {
|
|
; CHECK-LABEL: @test32(
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub <2 x i64> <i64 3, i64 4>, [[A:%.*]]
|
|
; CHECK-NEXT: ret <2 x i64> [[SUB]]
|
|
;
|
|
%add = add <2 x i64> %A, <i64 -1, i64 -1>
|
|
%sub = sub <2 x i64> <i64 2, i64 3>, %add
|
|
ret <2 x i64> %sub
|
|
}
|
|
|
|
define <2 x i64> @test35(<2 x i64> %A) {
|
|
; CHECK-LABEL: @test35(
|
|
; CHECK-NEXT: [[SUB:%.*]] = mul <2 x i64> [[A:%.*]], <i64 -2, i64 -3>
|
|
; CHECK-NEXT: ret <2 x i64> [[SUB]]
|
|
;
|
|
%mul = mul <2 x i64> %A, <i64 3, i64 4>
|
|
%sub = sub <2 x i64> %A, %mul
|
|
ret <2 x i64> %sub
|
|
}
|
|
|
|
define <2 x i64> @test36(<2 x i64> %A) {
|
|
; CHECK-LABEL: @test36(
|
|
; CHECK-NEXT: [[SUB:%.*]] = mul <2 x i64> [[A:%.*]], <i64 7, i64 15>
|
|
; CHECK-NEXT: ret <2 x i64> [[SUB]]
|
|
;
|
|
%shl = shl <2 x i64> %A, <i64 3, i64 4>
|
|
%sub = sub <2 x i64> %shl, %A
|
|
ret <2 x i64> %sub
|
|
}
|
|
|
|
define <2 x i32> @test37(<2 x i32> %A) {
|
|
; CHECK-LABEL: @test37(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <2 x i32> [[A:%.*]], <i32 -2147483648, i32 -2147483648>
|
|
; CHECK-NEXT: [[DIV_NEG:%.*]] = sext <2 x i1> [[TMP1]] to <2 x i32>
|
|
; CHECK-NEXT: ret <2 x i32> [[DIV_NEG]]
|
|
;
|
|
%div = sdiv <2 x i32> %A, <i32 -2147483648, i32 -2147483648>
|
|
%sub = sub nsw <2 x i32> zeroinitializer, %div
|
|
ret <2 x i32> %sub
|
|
}
|
|
|
|
define i32 @test38(i32 %A) {
|
|
; CHECK-LABEL: @test38(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[A:%.*]], -2147483648
|
|
; CHECK-NEXT: [[DIV_NEG:%.*]] = sext i1 [[TMP1]] to i32
|
|
; CHECK-NEXT: ret i32 [[DIV_NEG]]
|
|
;
|
|
%div = sdiv i32 %A, -2147483648
|
|
%sub = sub nsw i32 0, %div
|
|
ret i32 %sub
|
|
}
|
|
|
|
define i16 @test40(i16 %a, i16 %b) {
|
|
; CHECK-LABEL: @test40(
|
|
; CHECK-NEXT: [[ASHR:%.*]] = ashr i16 [[A:%.*]], 1
|
|
; CHECK-NEXT: [[ASHR1:%.*]] = ashr i16 [[B:%.*]], 1
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i16 [[ASHR]], [[ASHR1]]
|
|
; CHECK-NEXT: ret i16 [[SUB]]
|
|
;
|
|
%ashr = ashr i16 %a, 1
|
|
%ashr1 = ashr i16 %b, 1
|
|
%sub = sub i16 %ashr, %ashr1
|
|
ret i16 %sub
|
|
}
|
|
|
|
define i32 @test41(i16 %a, i16 %b) {
|
|
; CHECK-LABEL: @test41(
|
|
; CHECK-NEXT: [[CONV:%.*]] = sext i16 [[A:%.*]] to i32
|
|
; CHECK-NEXT: [[CONV1:%.*]] = sext i16 [[B:%.*]] to i32
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[CONV]], [[CONV1]]
|
|
; CHECK-NEXT: ret i32 [[SUB]]
|
|
;
|
|
%conv = sext i16 %a to i32
|
|
%conv1 = sext i16 %b to i32
|
|
%sub = sub i32 %conv, %conv1
|
|
ret i32 %sub
|
|
}
|
|
|
|
define i4 @test42(i4 %x, i4 %y) {
|
|
; CHECK-LABEL: @test42(
|
|
; CHECK-NEXT: [[A:%.*]] = and i4 [[Y:%.*]], 7
|
|
; CHECK-NEXT: [[B:%.*]] = and i4 [[X:%.*]], 7
|
|
; CHECK-NEXT: [[C:%.*]] = sub nsw i4 [[A]], [[B]]
|
|
; CHECK-NEXT: ret i4 [[C]]
|
|
;
|
|
%a = and i4 %y, 7
|
|
%b = and i4 %x, 7
|
|
%c = sub i4 %a, %b
|
|
ret i4 %c
|
|
}
|
|
|
|
define i4 @test43(i4 %x, i4 %y) {
|
|
; CHECK-LABEL: @test43(
|
|
; CHECK-NEXT: [[A:%.*]] = or i4 [[X:%.*]], -8
|
|
; CHECK-NEXT: [[B:%.*]] = and i4 [[Y:%.*]], 7
|
|
; CHECK-NEXT: [[C:%.*]] = sub nuw i4 [[A]], [[B]]
|
|
; CHECK-NEXT: ret i4 [[C]]
|
|
;
|
|
%a = or i4 %x, -8
|
|
%b = and i4 %y, 7
|
|
%c = sub i4 %a, %b
|
|
ret i4 %c
|
|
}
|
|
|
|
define i32 @test44(i32 %x) {
|
|
; CHECK-LABEL: @test44(
|
|
; CHECK-NEXT: [[SUB:%.*]] = add nsw i32 [[X:%.*]], -32768
|
|
; CHECK-NEXT: ret i32 [[SUB]]
|
|
;
|
|
%sub = sub nsw i32 %x, 32768
|
|
ret i32 %sub
|
|
}
|
|
|
|
define <2 x i32> @test44vec(<2 x i32> %x) {
|
|
; CHECK-LABEL: @test44vec(
|
|
; CHECK-NEXT: [[SUB:%.*]] = add nsw <2 x i32> [[X:%.*]], <i32 -32768, i32 -32768>
|
|
; CHECK-NEXT: ret <2 x i32> [[SUB]]
|
|
;
|
|
%sub = sub nsw <2 x i32> %x, <i32 32768, i32 32768>
|
|
ret <2 x i32> %sub
|
|
}
|
|
|
|
define <vscale x 2 x i32> @test44scalablevec(<vscale x 2 x i32> %x) {
|
|
; CHECK-LABEL: @test44scalablevec(
|
|
; CHECK-NEXT: [[SUB:%.*]] = add nsw <vscale x 2 x i32> [[X:%.*]], shufflevector (<vscale x 2 x i32> insertelement (<vscale x 2 x i32> poison, i32 -32768, i64 0), <vscale x 2 x i32> poison, <vscale x 2 x i32> zeroinitializer)
|
|
; CHECK-NEXT: ret <vscale x 2 x i32> [[SUB]]
|
|
;
|
|
%sub = sub nsw <vscale x 2 x i32> %x, shufflevector (<vscale x 2 x i32> insertelement (<vscale x 2 x i32> undef, i32 32768, i32 0), <vscale x 2 x i32> undef, <vscale x 2 x i32> zeroinitializer)
|
|
ret <vscale x 2 x i32> %sub
|
|
}
|
|
|
|
define <2 x i16> @test44vecminval(<2 x i16> %x) {
|
|
; CHECK-LABEL: @test44vecminval(
|
|
; CHECK-NEXT: [[SUB:%.*]] = xor <2 x i16> [[X:%.*]], <i16 -32768, i16 -32768>
|
|
; CHECK-NEXT: ret <2 x i16> [[SUB]]
|
|
;
|
|
%sub = sub nsw <2 x i16> %x, <i16 -32768, i16 -32768>
|
|
ret <2 x i16> %sub
|
|
}
|
|
|
|
; FIXME: This isn't combined to xor as above because the pattern in visitSub
|
|
; uses m_ImmConstant which matches Constant but (explicitly) not ConstantExpr.
|
|
define <vscale x 2 x i16> @test44scalablevecminval(<vscale x 2 x i16> %x) {
|
|
; CHECK-LABEL: @test44scalablevecminval(
|
|
; CHECK-NEXT: [[SUB:%.*]] = add <vscale x 2 x i16> [[X:%.*]], shufflevector (<vscale x 2 x i16> insertelement (<vscale x 2 x i16> poison, i16 -32768, i64 0), <vscale x 2 x i16> poison, <vscale x 2 x i32> zeroinitializer)
|
|
; CHECK-NEXT: ret <vscale x 2 x i16> [[SUB]]
|
|
;
|
|
%sub = sub nsw <vscale x 2 x i16> %x, shufflevector (<vscale x 2 x i16> insertelement (<vscale x 2 x i16> undef, i16 -32768, i32 0), <vscale x 2 x i16> undef, <vscale x 2 x i32> zeroinitializer)
|
|
ret <vscale x 2 x i16> %sub
|
|
}
|
|
|
|
define i32 @test45(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @test45(
|
|
; CHECK-NEXT: [[SUB:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: ret i32 [[SUB]]
|
|
;
|
|
%or = or i32 %x, %y
|
|
%xor = xor i32 %x, %y
|
|
%sub = sub i32 %or, %xor
|
|
ret i32 %sub
|
|
}
|
|
|
|
define i32 @test45commuted(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @test45commuted(
|
|
; CHECK-NEXT: [[SUB:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: ret i32 [[SUB]]
|
|
;
|
|
%or = or i32 %x, %y
|
|
%xor = xor i32 %y, %x
|
|
%sub = sub i32 %or, %xor
|
|
ret i32 %sub
|
|
}
|
|
|
|
define i32 @test46(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @test46(
|
|
; CHECK-NEXT: [[X_NOT:%.*]] = xor i32 [[X:%.*]], -1
|
|
; CHECK-NEXT: [[SUB:%.*]] = and i32 [[X_NOT]], [[Y:%.*]]
|
|
; CHECK-NEXT: ret i32 [[SUB]]
|
|
;
|
|
%or = or i32 %x, %y
|
|
%sub = sub i32 %or, %x
|
|
ret i32 %sub
|
|
}
|
|
|
|
define i32 @test46commuted(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @test46commuted(
|
|
; CHECK-NEXT: [[X_NOT:%.*]] = xor i32 [[X:%.*]], -1
|
|
; CHECK-NEXT: [[SUB:%.*]] = and i32 [[X_NOT]], [[Y:%.*]]
|
|
; CHECK-NEXT: ret i32 [[SUB]]
|
|
;
|
|
%or = or i32 %y, %x
|
|
%sub = sub i32 %or, %x
|
|
ret i32 %sub
|
|
}
|
|
|
|
define i32 @test47(i1 %A, i32 %B, i32 %C, i32 %D) {
|
|
; CHECK-LABEL: @test47(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[D:%.*]], [[C:%.*]]
|
|
; CHECK-NEXT: [[SUB:%.*]] = select i1 [[A:%.*]], i32 [[TMP1]], i32 0
|
|
; CHECK-NEXT: ret i32 [[SUB]]
|
|
;
|
|
%sel0 = select i1 %A, i32 %D, i32 %B
|
|
%sel1 = select i1 %A, i32 %C, i32 %B
|
|
%sub = sub i32 %sel0, %sel1
|
|
ret i32 %sub
|
|
}
|
|
|
|
define i32 @test48(i1 %A, i32 %B, i32 %C, i32 %D) {
|
|
; CHECK-LABEL: @test48(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[D:%.*]], [[C:%.*]]
|
|
; CHECK-NEXT: [[SUB:%.*]] = select i1 [[A:%.*]], i32 0, i32 [[TMP1]]
|
|
; CHECK-NEXT: ret i32 [[SUB]]
|
|
;
|
|
%sel0 = select i1 %A, i32 %B, i32 %D
|
|
%sel1 = select i1 %A, i32 %B, i32 %C
|
|
%sub = sub i32 %sel0, %sel1
|
|
ret i32 %sub
|
|
}
|
|
|
|
define i32 @test49(i32 %X) {
|
|
; CHECK-LABEL: @test49(
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub i32 1, [[X:%.*]]
|
|
; CHECK-NEXT: [[RES:%.*]] = and i32 [[SUB]], 64
|
|
; CHECK-NEXT: ret i32 [[RES]]
|
|
;
|
|
%sub = sub i32 129, %X
|
|
%res = and i32 %sub, 64
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @test50(i32 %X) {
|
|
; CHECK-LABEL: @test50(
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub i32 1, [[X:%.*]]
|
|
; CHECK-NEXT: [[RES:%.*]] = and i32 [[SUB]], 127
|
|
; CHECK-NEXT: ret i32 [[RES]]
|
|
;
|
|
%sub = sub i32 129, %X
|
|
%res = and i32 %sub, 127
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @test51(i32 %X) {
|
|
; CHECK-LABEL: @test51(
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub i32 126, [[X:%.*]]
|
|
; CHECK-NEXT: [[RES:%.*]] = and i32 [[SUB]], 64
|
|
; CHECK-NEXT: ret i32 [[RES]]
|
|
;
|
|
%sub = sub i32 254, %X
|
|
%res = and i32 %sub, 64
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @test52(i32 %X) {
|
|
; CHECK-LABEL: @test52(
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub i32 126, [[X:%.*]]
|
|
; CHECK-NEXT: [[RES:%.*]] = and i32 [[SUB]], 127
|
|
; CHECK-NEXT: ret i32 [[RES]]
|
|
;
|
|
%sub = sub i32 254, %X
|
|
%res = and i32 %sub, 127
|
|
ret i32 %res
|
|
}
|
|
|
|
define <2 x i1> @test53(<2 x i1> %A, <2 x i1> %B) {
|
|
; CHECK-LABEL: @test53(
|
|
; CHECK-NEXT: [[SUB:%.*]] = xor <2 x i1> [[B:%.*]], [[A:%.*]]
|
|
; CHECK-NEXT: ret <2 x i1> [[SUB]]
|
|
;
|
|
%sub = sub <2 x i1> %A, %B
|
|
ret <2 x i1> %sub
|
|
}
|
|
|
|
define i32 @test54(i1 %C) {
|
|
; CHECK-LABEL: @test54(
|
|
; CHECK-NEXT: [[V:%.*]] = select i1 [[C:%.*]], i32 -877, i32 113
|
|
; CHECK-NEXT: ret i32 [[V]]
|
|
;
|
|
%A = select i1 %C, i32 1000, i32 10
|
|
%V = sub i32 123, %A
|
|
ret i32 %V
|
|
}
|
|
|
|
define <2 x i32> @test54vec(i1 %C) {
|
|
; CHECK-LABEL: @test54vec(
|
|
; CHECK-NEXT: [[V:%.*]] = select i1 [[C:%.*]], <2 x i32> <i32 -877, i32 -877>, <2 x i32> <i32 113, i32 113>
|
|
; CHECK-NEXT: ret <2 x i32> [[V]]
|
|
;
|
|
%A = select i1 %C, <2 x i32> <i32 1000, i32 1000>, <2 x i32> <i32 10, i32 10>
|
|
%V = sub <2 x i32> <i32 123, i32 123>, %A
|
|
ret <2 x i32> %V
|
|
}
|
|
|
|
define <2 x i32> @test54vec2(i1 %C) {
|
|
; CHECK-LABEL: @test54vec2(
|
|
; CHECK-NEXT: [[V:%.*]] = select i1 [[C:%.*]], <2 x i32> <i32 -877, i32 -2167>, <2 x i32> <i32 113, i32 303>
|
|
; CHECK-NEXT: ret <2 x i32> [[V]]
|
|
;
|
|
%A = select i1 %C, <2 x i32> <i32 1000, i32 2500>, <2 x i32> <i32 10, i32 30>
|
|
%V = sub <2 x i32> <i32 123, i32 333>, %A
|
|
ret <2 x i32> %V
|
|
}
|
|
|
|
define i32 @test55(i1 %which) {
|
|
; CHECK-LABEL: @test55(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[WHICH:%.*]], label [[FINAL:%.*]], label [[DELAY:%.*]]
|
|
; CHECK: delay:
|
|
; CHECK-NEXT: br label [[FINAL]]
|
|
; CHECK: final:
|
|
; CHECK-NEXT: [[A_NEG:%.*]] = phi i32 [ -877, [[ENTRY:%.*]] ], [ 113, [[DELAY]] ]
|
|
; CHECK-NEXT: ret i32 [[A_NEG]]
|
|
;
|
|
entry:
|
|
br i1 %which, label %final, label %delay
|
|
|
|
delay:
|
|
br label %final
|
|
|
|
final:
|
|
%A = phi i32 [ 1000, %entry ], [ 10, %delay ]
|
|
%value = sub i32 123, %A
|
|
ret i32 %value
|
|
}
|
|
|
|
define <2 x i32> @test55vec(i1 %which) {
|
|
; CHECK-LABEL: @test55vec(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[WHICH:%.*]], label [[FINAL:%.*]], label [[DELAY:%.*]]
|
|
; CHECK: delay:
|
|
; CHECK-NEXT: br label [[FINAL]]
|
|
; CHECK: final:
|
|
; CHECK-NEXT: [[A_NEG:%.*]] = phi <2 x i32> [ <i32 -877, i32 -877>, [[ENTRY:%.*]] ], [ <i32 113, i32 113>, [[DELAY]] ]
|
|
; CHECK-NEXT: ret <2 x i32> [[A_NEG]]
|
|
;
|
|
entry:
|
|
br i1 %which, label %final, label %delay
|
|
|
|
delay:
|
|
br label %final
|
|
|
|
final:
|
|
%A = phi <2 x i32> [ <i32 1000, i32 1000>, %entry ], [ <i32 10, i32 10>, %delay ]
|
|
%value = sub <2 x i32> <i32 123, i32 123>, %A
|
|
ret <2 x i32> %value
|
|
}
|
|
|
|
define <2 x i32> @test55vec2(i1 %which) {
|
|
; CHECK-LABEL: @test55vec2(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[WHICH:%.*]], label [[FINAL:%.*]], label [[DELAY:%.*]]
|
|
; CHECK: delay:
|
|
; CHECK-NEXT: br label [[FINAL]]
|
|
; CHECK: final:
|
|
; CHECK-NEXT: [[A_NEG:%.*]] = phi <2 x i32> [ <i32 -877, i32 -2167>, [[ENTRY:%.*]] ], [ <i32 113, i32 303>, [[DELAY]] ]
|
|
; CHECK-NEXT: ret <2 x i32> [[A_NEG]]
|
|
;
|
|
entry:
|
|
br i1 %which, label %final, label %delay
|
|
|
|
delay:
|
|
br label %final
|
|
|
|
final:
|
|
%A = phi <2 x i32> [ <i32 1000, i32 2500>, %entry ], [ <i32 10, i32 30>, %delay ]
|
|
%value = sub <2 x i32> <i32 123, i32 333>, %A
|
|
ret <2 x i32> %value
|
|
}
|
|
|
|
define i32 @test56(i32 %A, i32 %B) {
|
|
; CHECK-LABEL: @test56(
|
|
; CHECK-NEXT: [[Y:%.*]] = sub i32 0, [[B:%.*]]
|
|
; CHECK-NEXT: ret i32 [[Y]]
|
|
;
|
|
%X = add i32 %A, %B
|
|
%Y = sub i32 %A, %X
|
|
ret i32 %Y
|
|
}
|
|
|
|
define i32 @test57(i32 %A, i32 %B) {
|
|
; CHECK-LABEL: @test57(
|
|
; CHECK-NEXT: [[Y:%.*]] = sub i32 0, [[B:%.*]]
|
|
; CHECK-NEXT: ret i32 [[Y]]
|
|
;
|
|
%X = add i32 %B, %A
|
|
%Y = sub i32 %A, %X
|
|
ret i32 %Y
|
|
}
|
|
|
|
@dummy_global1 = external global ptr
|
|
@dummy_global2 = external global ptr
|
|
|
|
define i64 @test58(ptr %foo, i64 %i, i64 %j) {
|
|
; CHECK-LABEL: @test58(
|
|
; CHECK-NEXT: [[GEPDIFF:%.*]] = sub i64 [[I:%.*]], [[J:%.*]]
|
|
; CHECK-NEXT: ret i64 [[GEPDIFF]]
|
|
;
|
|
%gep1 = getelementptr inbounds [100 x [100 x i8]], ptr %foo, i64 0, i64 42, i64 %i
|
|
%gep2 = getelementptr inbounds [100 x [100 x i8]], ptr %foo, i64 0, i64 42, i64 %j
|
|
%cast1 = ptrtoint ptr %gep1 to i64
|
|
%cast2 = ptrtoint ptr %gep2 to i64
|
|
%sub = sub i64 %cast1, %cast2
|
|
ret i64 %sub
|
|
}
|
|
|
|
define i64 @test59(ptr %foo, i64 %i) {
|
|
; CHECK-LABEL: @test59(
|
|
; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds [100 x [100 x i8]], ptr [[FOO:%.*]], i64 0, i64 42, i64 [[I:%.*]]
|
|
; CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds [100 x [100 x i8]], ptr [[FOO]], i64 0, i64 42, i64 0
|
|
; CHECK-NEXT: store ptr [[GEP1]], ptr @dummy_global1, align 8
|
|
; CHECK-NEXT: store ptr [[GEP2]], ptr @dummy_global2, align 8
|
|
; CHECK-NEXT: ret i64 [[I]]
|
|
;
|
|
; gep1 and gep2 have more than one uses
|
|
%gep1 = getelementptr inbounds [100 x [100 x i8]], ptr %foo, i64 0, i64 42, i64 %i
|
|
%gep2 = getelementptr inbounds [100 x [100 x i8]], ptr %foo, i64 0, i64 42, i64 0
|
|
%cast1 = ptrtoint ptr %gep1 to i64
|
|
%cast2 = ptrtoint ptr %gep2 to i64
|
|
%sub = sub i64 %cast1, %cast2
|
|
store ptr %gep1, ptr @dummy_global1
|
|
store ptr %gep2, ptr @dummy_global2
|
|
ret i64 %sub
|
|
}
|
|
|
|
define i64 @test60(ptr %foo, i64 %i, i64 %j) {
|
|
; CHECK-LABEL: @test60(
|
|
; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds [100 x [100 x i8]], ptr [[FOO:%.*]], i64 0, i64 [[J:%.*]], i64 [[I:%.*]]
|
|
; CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds [100 x [100 x i8]], ptr [[FOO]], i64 0, i64 42, i64 0
|
|
; CHECK-NEXT: [[CAST1:%.*]] = ptrtoint ptr [[GEP1]] to i64
|
|
; CHECK-NEXT: [[CAST2:%.*]] = ptrtoint ptr [[GEP2]] to i64
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub i64 [[CAST1]], [[CAST2]]
|
|
; CHECK-NEXT: store ptr [[GEP1]], ptr @dummy_global1, align 8
|
|
; CHECK-NEXT: ret i64 [[SUB]]
|
|
;
|
|
; gep1 has a non-constant index and more than one uses. Shouldn't duplicate the arithmetic.
|
|
%gep1 = getelementptr inbounds [100 x [100 x i8]], ptr %foo, i64 0, i64 %j, i64 %i
|
|
%gep2 = getelementptr inbounds [100 x [100 x i8]], ptr %foo, i64 0, i64 42, i64 0
|
|
%cast1 = ptrtoint ptr %gep1 to i64
|
|
%cast2 = ptrtoint ptr %gep2 to i64
|
|
%sub = sub i64 %cast1, %cast2
|
|
store ptr %gep1, ptr @dummy_global1
|
|
ret i64 %sub
|
|
}
|
|
|
|
define i64 @test61(ptr %foo, i64 %i, i64 %j) {
|
|
; CHECK-LABEL: @test61(
|
|
; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds [100 x [100 x i8]], ptr [[FOO:%.*]], i64 0, i64 42, i64 0
|
|
; CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds [100 x [100 x i8]], ptr [[FOO]], i64 0, i64 [[J:%.*]], i64 [[I:%.*]]
|
|
; CHECK-NEXT: [[CAST1:%.*]] = ptrtoint ptr [[GEP1]] to i64
|
|
; CHECK-NEXT: [[CAST2:%.*]] = ptrtoint ptr [[GEP2]] to i64
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub i64 [[CAST1]], [[CAST2]]
|
|
; CHECK-NEXT: store ptr [[GEP2]], ptr @dummy_global2, align 8
|
|
; CHECK-NEXT: ret i64 [[SUB]]
|
|
;
|
|
; gep2 has a non-constant index and more than one uses. Shouldn't duplicate the arithmetic.
|
|
%gep1 = getelementptr inbounds [100 x [100 x i8]], ptr %foo, i64 0, i64 42, i64 0
|
|
%gep2 = getelementptr inbounds [100 x [100 x i8]], ptr %foo, i64 0, i64 %j, i64 %i
|
|
%cast1 = ptrtoint ptr %gep1 to i64
|
|
%cast2 = ptrtoint ptr %gep2 to i64
|
|
%sub = sub i64 %cast1, %cast2
|
|
store ptr %gep2, ptr @dummy_global2
|
|
ret i64 %sub
|
|
}
|
|
|
|
define i32 @test62(i32 %A) {
|
|
; CHECK-LABEL: @test62(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = shl i32 [[A:%.*]], 1
|
|
; CHECK-NEXT: [[C:%.*]] = sub i32 2, [[TMP1]]
|
|
; CHECK-NEXT: ret i32 [[C]]
|
|
;
|
|
%B = sub i32 1, %A
|
|
%C = shl i32 %B, 1
|
|
ret i32 %C
|
|
}
|
|
|
|
define <2 x i32> @test62vec(<2 x i32> %A) {
|
|
; CHECK-LABEL: @test62vec(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = shl <2 x i32> [[A:%.*]], <i32 1, i32 1>
|
|
; CHECK-NEXT: [[C:%.*]] = sub <2 x i32> <i32 2, i32 2>, [[TMP1]]
|
|
; CHECK-NEXT: ret <2 x i32> [[C]]
|
|
;
|
|
%B = sub <2 x i32> <i32 1, i32 1>, %A
|
|
%C = shl <2 x i32> %B, <i32 1, i32 1>
|
|
ret <2 x i32> %C
|
|
}
|
|
|
|
define i32 @test63(i32 %A) {
|
|
; CHECK-LABEL: @test63(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = shl i32 [[A:%.*]], 1
|
|
; CHECK-NEXT: ret i32 [[TMP1]]
|
|
;
|
|
%B = sub i32 1, %A
|
|
%C = shl i32 %B, 1
|
|
%D = sub i32 2, %C
|
|
ret i32 %D
|
|
}
|
|
|
|
define <2 x i32> @test63vec(<2 x i32> %A) {
|
|
; CHECK-LABEL: @test63vec(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = shl <2 x i32> [[A:%.*]], <i32 1, i32 1>
|
|
; CHECK-NEXT: ret <2 x i32> [[TMP1]]
|
|
;
|
|
%B = sub <2 x i32> <i32 1, i32 1>, %A
|
|
%C = shl <2 x i32> %B, <i32 1, i32 1>
|
|
%D = sub <2 x i32> <i32 2, i32 2>, %C
|
|
ret <2 x i32> %D
|
|
}
|
|
|
|
define i32 @test64(i32 %x) {
|
|
; CHECK-LABEL: @test64(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.smin.i32(i32 [[X:%.*]], i32 255)
|
|
; CHECK-NEXT: [[DOTNEG:%.*]] = add nsw i32 [[TMP1]], 1
|
|
; CHECK-NEXT: ret i32 [[DOTNEG]]
|
|
;
|
|
%1 = xor i32 %x, -1
|
|
%2 = icmp sgt i32 %1, -256
|
|
%3 = select i1 %2, i32 %1, i32 -256
|
|
%res = sub i32 0, %3
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @test65(i32 %x) {
|
|
; CHECK-LABEL: @test65(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.smax.i32(i32 [[X:%.*]], i32 -256)
|
|
; CHECK-NEXT: [[DOTNEG:%.*]] = add i32 [[TMP1]], 1
|
|
; CHECK-NEXT: ret i32 [[DOTNEG]]
|
|
;
|
|
%1 = xor i32 %x, -1
|
|
%2 = icmp slt i32 %1, 255
|
|
%3 = select i1 %2, i32 %1, i32 255
|
|
%res = sub i32 0, %3
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @test66(i32 %x) {
|
|
; CHECK-LABEL: @test66(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[X:%.*]], i32 -101)
|
|
; CHECK-NEXT: [[DOTNEG:%.*]] = add nuw i32 [[TMP1]], 1
|
|
; CHECK-NEXT: ret i32 [[DOTNEG]]
|
|
;
|
|
%1 = xor i32 %x, -1
|
|
%2 = icmp ugt i32 %1, 100
|
|
%3 = select i1 %2, i32 %1, i32 100
|
|
%res = sub i32 0, %3
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @test67(i32 %x) {
|
|
; CHECK-LABEL: @test67(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umax.i32(i32 [[X:%.*]], i32 100)
|
|
; CHECK-NEXT: [[DOTNEG:%.*]] = add i32 [[TMP1]], 1
|
|
; CHECK-NEXT: ret i32 [[DOTNEG]]
|
|
;
|
|
%1 = xor i32 %x, -1
|
|
%2 = icmp ult i32 %1, -101
|
|
%3 = select i1 %2, i32 %1, i32 -101
|
|
%res = sub i32 0, %3
|
|
ret i32 %res
|
|
}
|
|
|
|
; Check splat vectors too
|
|
define <2 x i32> @test68(<2 x i32> %x) {
|
|
; CHECK-LABEL: @test68(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i32> @llvm.smin.v2i32(<2 x i32> [[X:%.*]], <2 x i32> <i32 255, i32 255>)
|
|
; CHECK-NEXT: [[DOTNEG:%.*]] = add nsw <2 x i32> [[TMP1]], <i32 1, i32 1>
|
|
; CHECK-NEXT: ret <2 x i32> [[DOTNEG]]
|
|
;
|
|
%1 = xor <2 x i32> %x, <i32 -1, i32 -1>
|
|
%2 = icmp sgt <2 x i32> %1, <i32 -256, i32 -256>
|
|
%3 = select <2 x i1> %2, <2 x i32> %1, <2 x i32> <i32 -256, i32 -256>
|
|
%res = sub <2 x i32> zeroinitializer, %3
|
|
ret <2 x i32> %res
|
|
}
|
|
|
|
; And non-splat constant vectors.
|
|
define <2 x i32> @test69(<2 x i32> %x) {
|
|
; CHECK-LABEL: @test69(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i32> @llvm.smin.v2i32(<2 x i32> [[X:%.*]], <2 x i32> <i32 255, i32 127>)
|
|
; CHECK-NEXT: [[DOTNEG:%.*]] = add <2 x i32> [[TMP1]], <i32 1, i32 1>
|
|
; CHECK-NEXT: ret <2 x i32> [[DOTNEG]]
|
|
;
|
|
%1 = xor <2 x i32> %x, <i32 -1, i32 -1>
|
|
%2 = icmp sgt <2 x i32> %1, <i32 -256, i32 -128>
|
|
%3 = select <2 x i1> %2, <2 x i32> %1, <2 x i32> <i32 -256, i32 -128>
|
|
%res = sub <2 x i32> zeroinitializer, %3
|
|
ret <2 x i32> %res
|
|
}
|
|
|
|
; Check (X | Y) - Y --> X & ~Y when Y is a constant
|
|
define i32 @test70(i32 %A) {
|
|
; CHECK-LABEL: @test70(
|
|
; CHECK-NEXT: [[C:%.*]] = and i32 [[A:%.*]], -124
|
|
; CHECK-NEXT: ret i32 [[C]]
|
|
;
|
|
%B = or i32 %A, 123
|
|
%C = sub i32 %B, 123
|
|
ret i32 %C
|
|
}
|
|
|
|
; Check (X | Y) - Y --> (X | Y) ^ Y doesn't happen where (X | Y) has multiple uses
|
|
define i32 @test71(i32 %A, i32 %B) {
|
|
; CHECK-LABEL: @test71(
|
|
; CHECK-NEXT: [[C:%.*]] = or i32 [[A:%.*]], [[B:%.*]]
|
|
; CHECK-NEXT: [[D:%.*]] = sub i32 [[C]], [[B]]
|
|
; CHECK-NEXT: [[E:%.*]] = mul i32 [[C]], [[D]]
|
|
; CHECK-NEXT: ret i32 [[E]]
|
|
;
|
|
%C = or i32 %A, %B
|
|
%D = sub i32 %C, %B
|
|
%E = mul i32 %C, %D
|
|
ret i32 %E
|
|
}
|
|
|
|
; Check (X | Y) - Y --> X & ~Y where X and Y are vectors
|
|
define <2 x i32> @test72(<2 x i32> %A, <2 x i32> %B) {
|
|
; CHECK-LABEL: @test72(
|
|
; CHECK-NEXT: [[B_NOT:%.*]] = xor <2 x i32> [[B:%.*]], <i32 -1, i32 -1>
|
|
; CHECK-NEXT: [[D:%.*]] = and <2 x i32> [[B_NOT]], [[A:%.*]]
|
|
; CHECK-NEXT: ret <2 x i32> [[D]]
|
|
;
|
|
%C = or <2 x i32> %A, %B
|
|
%D = sub <2 x i32> %C, %B
|
|
ret <2 x i32> %D
|
|
}
|
|
|
|
; Check reversing sub operands won't trigger (X | Y) - Y --> X & ~Y
|
|
define i32 @test73(i32 %A, i32 %B) {
|
|
; CHECK-LABEL: @test73(
|
|
; CHECK-NEXT: [[C:%.*]] = or i32 [[A:%.*]], [[B:%.*]]
|
|
; CHECK-NEXT: [[D:%.*]] = sub i32 [[B]], [[C]]
|
|
; CHECK-NEXT: ret i32 [[D]]
|
|
;
|
|
%C = or i32 %A, %B
|
|
%D = sub i32 %B, %C
|
|
ret i32 %D
|
|
}
|
|
|
|
define i32 @nsw_inference1(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @nsw_inference1(
|
|
; CHECK-NEXT: [[X2:%.*]] = or i32 [[X:%.*]], 1024
|
|
; CHECK-NEXT: [[Y2:%.*]] = and i32 [[Y:%.*]], 1
|
|
; CHECK-NEXT: [[Z:%.*]] = sub nuw nsw i32 [[X2]], [[Y2]]
|
|
; CHECK-NEXT: ret i32 [[Z]]
|
|
;
|
|
%x2 = or i32 %x, 1024
|
|
%y2 = and i32 %y, 1
|
|
%z = sub i32 %x2, %y2
|
|
ret i32 %z
|
|
}
|
|
|
|
define i32 @nsw_inference2(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @nsw_inference2(
|
|
; CHECK-NEXT: [[X2:%.*]] = and i32 [[X:%.*]], -1025
|
|
; CHECK-NEXT: [[Y2:%.*]] = or i32 [[Y:%.*]], -2
|
|
; CHECK-NEXT: [[Z:%.*]] = sub nsw i32 [[X2]], [[Y2]]
|
|
; CHECK-NEXT: ret i32 [[Z]]
|
|
;
|
|
%x2 = and i32 %x, -1025
|
|
%y2 = or i32 %y, -2
|
|
%z = sub i32 %x2, %y2
|
|
ret i32 %z
|
|
}
|
|
|
|
define i8 @test74(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @test74(
|
|
; CHECK-NEXT: [[T0:%.*]] = and i8 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
|
; CHECK-NEXT: [[T1:%.*]] = sub i8 [[X]], [[T0]]
|
|
; CHECK-NEXT: ret i8 [[T1]]
|
|
;
|
|
%t0 = and i8 %x, %y
|
|
call void @use8(i8 %t0)
|
|
%t1 = sub i8 %x, %t0
|
|
ret i8 %t1
|
|
}
|
|
|
|
define i8 @test75(i8 %x) {
|
|
; CHECK-LABEL: @test75(
|
|
; CHECK-NEXT: [[T0:%.*]] = and i8 [[X:%.*]], -8
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
|
; CHECK-NEXT: [[T1:%.*]] = and i8 [[X]], 7
|
|
; CHECK-NEXT: ret i8 [[T1]]
|
|
;
|
|
%t0 = and i8 %x, -8
|
|
call void @use8(i8 %t0)
|
|
%t1 = sub i8 %x, %t0
|
|
ret i8 %t1
|
|
}
|
|
|
|
; ((w-x) + y) - z --> (w+y) - (x+z)
|
|
|
|
define i8 @sub_add_sub_reassoc(i8 %w, i8 %x, i8 %y, i8 %z) {
|
|
; CHECK-LABEL: @sub_add_sub_reassoc(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[W:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[TMP2:%.*]] = add i8 [[X:%.*]], [[Z:%.*]]
|
|
; CHECK-NEXT: [[S2:%.*]] = sub i8 [[TMP1]], [[TMP2]]
|
|
; CHECK-NEXT: ret i8 [[S2]]
|
|
;
|
|
%s1 = sub i8 %w, %x
|
|
%a = add i8 %s1, %y
|
|
%s2 = sub i8 %a, %z
|
|
ret i8 %s2
|
|
}
|
|
|
|
; vectors work too.
|
|
|
|
define <2 x i8> @sub_add_sub_reassoc_commute(<2 x i8> %w, <2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
|
|
; CHECK-LABEL: @sub_add_sub_reassoc_commute(
|
|
; CHECK-NEXT: [[D:%.*]] = sdiv <2 x i8> [[Y:%.*]], <i8 42, i8 -42>
|
|
; CHECK-NEXT: [[TMP1:%.*]] = add <2 x i8> [[D]], [[W:%.*]]
|
|
; CHECK-NEXT: [[TMP2:%.*]] = add <2 x i8> [[X:%.*]], [[Z:%.*]]
|
|
; CHECK-NEXT: [[S2:%.*]] = sub <2 x i8> [[TMP1]], [[TMP2]]
|
|
; CHECK-NEXT: ret <2 x i8> [[S2]]
|
|
;
|
|
%d = sdiv <2 x i8> %y, <i8 42, i8 -42> ; thwart complexity-based canonicalization
|
|
%s1 = sub <2 x i8> %w, %x
|
|
%a = add <2 x i8> %d, %s1
|
|
%s2 = sub <2 x i8> %a, %z
|
|
ret <2 x i8> %s2
|
|
}
|
|
|
|
; (v-w) + (x-y) - z --> (v+x) - (w+y+z)
|
|
|
|
define i8 @sub_add_sub_reassoc_twice(i8 %v, i8 %w, i8 %x, i8 %y, i8 %z) {
|
|
; CHECK-LABEL: @sub_add_sub_reassoc_twice(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[W:%.*]], [[Z:%.*]]
|
|
; CHECK-NEXT: [[TMP2:%.*]] = add i8 [[X:%.*]], [[V:%.*]]
|
|
; CHECK-NEXT: [[TMP3:%.*]] = add i8 [[TMP1]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[S3:%.*]] = sub i8 [[TMP2]], [[TMP3]]
|
|
; CHECK-NEXT: ret i8 [[S3]]
|
|
;
|
|
%s1 = sub i8 %v, %w
|
|
%s2 = sub i8 %x, %y
|
|
%a = add i8 %s1, %s2
|
|
%s3 = sub i8 %a, %z
|
|
ret i8 %s3
|
|
}
|
|
|
|
; negative test - uses
|
|
|
|
define i8 @sub_add_sub_reassoc_use1(i8 %w, i8 %x, i8 %y, i8 %z) {
|
|
; CHECK-LABEL: @sub_add_sub_reassoc_use1(
|
|
; CHECK-NEXT: [[S1:%.*]] = sub i8 [[W:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: call void @use8(i8 [[S1]])
|
|
; CHECK-NEXT: [[A:%.*]] = add i8 [[S1]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[S2:%.*]] = sub i8 [[A]], [[Z:%.*]]
|
|
; CHECK-NEXT: ret i8 [[S2]]
|
|
;
|
|
%s1 = sub i8 %w, %x
|
|
call void @use8(i8 %s1)
|
|
%a = add i8 %s1, %y
|
|
%s2 = sub i8 %a, %z
|
|
ret i8 %s2
|
|
}
|
|
|
|
; negative test - uses
|
|
|
|
define i8 @sub_add_sub_reassoc_use2(i8 %w, i8 %x, i8 %y, i8 %z) {
|
|
; CHECK-LABEL: @sub_add_sub_reassoc_use2(
|
|
; CHECK-NEXT: [[S1:%.*]] = sub i8 [[W:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: [[A:%.*]] = add i8 [[S1]], [[Y:%.*]]
|
|
; CHECK-NEXT: call void @use8(i8 [[A]])
|
|
; CHECK-NEXT: [[S2:%.*]] = sub i8 [[A]], [[Z:%.*]]
|
|
; CHECK-NEXT: ret i8 [[S2]]
|
|
;
|
|
%s1 = sub i8 %w, %x
|
|
%a = add i8 %s1, %y
|
|
call void @use8(i8 %a)
|
|
%s2 = sub i8 %a, %z
|
|
ret i8 %s2
|
|
}
|
|
|
|
define i8 @sub_mask_lowbits(i8 %x) {
|
|
; CHECK-LABEL: @sub_mask_lowbits(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X:%.*]], -4
|
|
; CHECK-NEXT: [[R:%.*]] = add i8 [[TMP1]], -108
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%a1 = add i8 %x, 148 ; 0x94
|
|
%a2 = and i8 %x, 3
|
|
%r = sub i8 %a1, %a2
|
|
ret i8 %r
|
|
}
|
|
|
|
; Negative test - low-bit mask must not overlap with offset
|
|
|
|
define i8 @sub_not_mask_lowbits(i8 %x) {
|
|
; CHECK-LABEL: @sub_not_mask_lowbits(
|
|
; CHECK-NEXT: [[A1:%.*]] = add i8 [[X:%.*]], 4
|
|
; CHECK-NEXT: [[A2:%.*]] = and i8 [[X]], 7
|
|
; CHECK-NEXT: [[R:%.*]] = sub i8 [[A1]], [[A2]]
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%a1 = add i8 %x, 4
|
|
%a2 = and i8 %x, 7
|
|
%r = sub i8 %a1, %a2
|
|
ret i8 %r
|
|
}
|
|
|
|
define <2 x i8> @sub_mask_lowbits_splat_extra_use(<2 x i8> %x, ptr %p) {
|
|
; CHECK-LABEL: @sub_mask_lowbits_splat_extra_use(
|
|
; CHECK-NEXT: [[A2:%.*]] = and <2 x i8> [[X:%.*]], <i8 10, i8 10>
|
|
; CHECK-NEXT: store <2 x i8> [[A2]], ptr [[P:%.*]], align 2
|
|
; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> [[X]], <i8 -11, i8 -11>
|
|
; CHECK-NEXT: [[R:%.*]] = add <2 x i8> [[TMP1]], <i8 -64, i8 -64>
|
|
; CHECK-NEXT: ret <2 x i8> [[R]]
|
|
;
|
|
%a1 = add <2 x i8> %x, <i8 192, i8 192> ; 0xc0
|
|
%a2 = and <2 x i8> %x, <i8 10, i8 10> ; 0x0a
|
|
store <2 x i8> %a2, ptr %p
|
|
%r = sub <2 x i8> %a1, %a2
|
|
ret <2 x i8> %r
|
|
}
|
|
|
|
define i16 @sub_nsw_mul_nsw(i16 %x, i16 %y) {
|
|
; CHECK-LABEL: @sub_nsw_mul_nsw(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = sub nsw i16 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[R:%.*]] = shl nsw i16 [[TMP1]], 3
|
|
; CHECK-NEXT: ret i16 [[R]]
|
|
;
|
|
%x8 = mul nsw i16 %x, 8
|
|
%y8 = mul nsw i16 %y, 8
|
|
%r = sub nsw i16 %x8, %y8
|
|
ret i16 %r
|
|
}
|
|
|
|
define i16 @sub_nuw_mul_nsw(i16 %x, i16 %y) {
|
|
; CHECK-LABEL: @sub_nuw_mul_nsw(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = sub i16 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[R:%.*]] = shl i16 [[TMP1]], 2
|
|
; CHECK-NEXT: ret i16 [[R]]
|
|
;
|
|
%x8 = mul nsw i16 %x, 4
|
|
%y8 = mul nsw i16 %y, 4
|
|
%r = sub nuw i16 %x8, %y8
|
|
ret i16 %r
|
|
}
|
|
|
|
define i16 @sub_mul_nsw(i16 %x, i16 %y) {
|
|
; CHECK-LABEL: @sub_mul_nsw(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = sub i16 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[R:%.*]] = shl i16 [[TMP1]], 4
|
|
; CHECK-NEXT: ret i16 [[R]]
|
|
;
|
|
%x8 = mul nsw i16 %x, 16
|
|
%y8 = mul nsw i16 %y, 16
|
|
%r = sub i16 %x8, %y8
|
|
ret i16 %r
|
|
}
|
|
|
|
define i16 @sub_nsw_mul_nuw(i16 %x, i16 %y) {
|
|
; CHECK-LABEL: @sub_nsw_mul_nuw(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = sub i16 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[R:%.*]] = shl i16 [[TMP1]], 3
|
|
; CHECK-NEXT: ret i16 [[R]]
|
|
;
|
|
%x8 = mul nuw i16 %x, 8
|
|
%y8 = mul nuw i16 %y, 8
|
|
%r = sub nsw i16 %x8, %y8
|
|
ret i16 %r
|
|
}
|
|
|
|
define i16 @sub_nuw_mul_nuw(i16 %x, i16 %y) {
|
|
; CHECK-LABEL: @sub_nuw_mul_nuw(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = sub nuw i16 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[R:%.*]] = shl nuw i16 [[TMP1]], 4
|
|
; CHECK-NEXT: ret i16 [[R]]
|
|
;
|
|
%x8 = mul nuw i16 %x, 16
|
|
%y8 = mul nuw i16 %y, 16
|
|
%r = sub nuw i16 %x8, %y8
|
|
ret i16 %r
|
|
}
|
|
|
|
define i16 @sub_mul_nuw(i16 %x, i16 %y) {
|
|
; CHECK-LABEL: @sub_mul_nuw(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = sub i16 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[R:%.*]] = shl i16 [[TMP1]], 5
|
|
; CHECK-NEXT: ret i16 [[R]]
|
|
;
|
|
%x8 = mul nuw i16 %x, 32
|
|
%y8 = mul nuw i16 %y, 32
|
|
%r = sub i16 %x8, %y8
|
|
ret i16 %r
|
|
}
|
|
define i32 @and_test(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @and_test(
|
|
; CHECK-NEXT: [[R:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add i32 %x, %y
|
|
%o = or i32 %x, %y
|
|
%r = sub i32 %a, %o
|
|
ret i32 %r
|
|
}
|
|
|
|
define i32 @and_test2(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @and_test2(
|
|
; CHECK-NEXT: [[R:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add i32 %x, %y
|
|
%o = or i32 %y, %x
|
|
%r = sub i32 %a, %o
|
|
ret i32 %r
|
|
}
|
|
|
|
define i32 @and_test3(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @and_test3(
|
|
; CHECK-NEXT: [[R:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add i32 %y, %x
|
|
%o = or i32 %x, %y
|
|
%r = sub i32 %a, %o
|
|
ret i32 %r
|
|
}
|
|
|
|
|
|
define <2 x i8> @and_vec(<2 x i8> %X, <2 x i8> %Y) {
|
|
; CHECK-LABEL: @and_vec(
|
|
; CHECK-NEXT: [[R:%.*]] = and <2 x i8> [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: ret <2 x i8> [[R]]
|
|
;
|
|
%a = add <2 x i8> %X, %Y
|
|
%o = or <2 x i8> %X, %Y
|
|
%r = sub <2 x i8> %a, %o
|
|
ret <2 x i8> %r
|
|
}
|
|
|
|
define i32 @or_test(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @or_test(
|
|
; CHECK-NEXT: [[R:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add i32 %x, %y
|
|
%b = and i32 %x, %y
|
|
%r = sub i32 %a, %b
|
|
ret i32 %r
|
|
}
|
|
|
|
define i32 @or_test2(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @or_test2(
|
|
; CHECK-NEXT: [[R:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add i32 %x, %y
|
|
%b = and i32 %y, %x
|
|
%r = sub i32 %a, %b
|
|
ret i32 %r
|
|
}
|
|
|
|
define i32 @or_test3(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @or_test3(
|
|
; CHECK-NEXT: [[R:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add i32 %y, %x
|
|
%b = and i32 %x, %y
|
|
%r = sub i32 %a, %b
|
|
ret i32 %r
|
|
}
|
|
|
|
define <2 x i8> @or_vec(<2 x i8> %X, <2 x i8> %Y) {
|
|
; CHECK-LABEL: @or_vec(
|
|
; CHECK-NEXT: [[R:%.*]] = or <2 x i8> [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: ret <2 x i8> [[R]]
|
|
;
|
|
%a = add <2 x i8> %X, %Y
|
|
%b = and <2 x i8> %X, %Y
|
|
%r = sub <2 x i8> %a, %b
|
|
ret <2 x i8> %r
|
|
}
|
|
|
|
define i32 @pr51584(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @pr51584(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[B:%.*]], [[A:%.*]]
|
|
; CHECK-NEXT: [[DOTNEG:%.*]] = sub i32 -11, [[TMP1]]
|
|
; CHECK-NEXT: ret i32 [[DOTNEG]]
|
|
;
|
|
%sub = sub i32 0, %a
|
|
%add = add nsw i32 11, %b
|
|
%sub1 = sub i32 %sub, %add
|
|
ret i32 %sub1
|
|
}
|
|
|
|
define i8 @sub_srem(i8 noundef %x, i8 %y) {
|
|
; CHECK-LABEL: @sub_srem(
|
|
; CHECK-NEXT: [[REM:%.*]] = srem i8 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i8 [[X]], [[REM]]
|
|
; CHECK-NEXT: ret i8 [[SUB]]
|
|
;
|
|
%rem = srem i8 %x, %y
|
|
%sub = sub i8 %x, %rem
|
|
ret i8 %sub
|
|
}
|
|
|
|
define <2 x i5> @sub_urem(<2 x i5> noundef %x, <2 x i5> %y) {
|
|
; CHECK-LABEL: @sub_urem(
|
|
; CHECK-NEXT: [[REM:%.*]] = urem <2 x i5> [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nuw <2 x i5> [[X]], [[REM]]
|
|
; CHECK-NEXT: ret <2 x i5> [[SUB]]
|
|
;
|
|
%rem = urem <2 x i5> %x, %y
|
|
%sub = sub <2 x i5> %x, %rem
|
|
ret <2 x i5> %sub
|
|
}
|
|
|
|
define <3 x i32> @nuw_const_zext(<3 x i8> %y) {
|
|
; CHECK-LABEL: @nuw_const_zext(
|
|
; CHECK-NEXT: [[ZY:%.*]] = zext <3 x i8> [[Y:%.*]] to <3 x i32>
|
|
; CHECK-NEXT: [[S:%.*]] = sub nuw nsw <3 x i32> <i32 255, i32 128, i32 0>, [[ZY]]
|
|
; CHECK-NEXT: ret <3 x i32> [[S]]
|
|
;
|
|
%zy = zext <3 x i8> %y to <3 x i32>
|
|
%s = sub nuw <3 x i32> <i32 255, i32 128, i32 0>, %zy
|
|
ret <3 x i32> %s
|
|
}
|
|
|
|
define i32 @nuw_const_zext_big(i8 %y) {
|
|
; CHECK-LABEL: @nuw_const_zext_big(
|
|
; CHECK-NEXT: [[ZY:%.*]] = zext i8 [[Y:%.*]] to i32
|
|
; CHECK-NEXT: [[S:%.*]] = sub nuw nsw i32 257, [[ZY]]
|
|
; CHECK-NEXT: ret i32 [[S]]
|
|
;
|
|
%zy = zext i8 %y to i32
|
|
%s = sub nuw i32 257, %zy
|
|
ret i32 %s
|
|
}
|
|
|
|
define i32 @nuw_zext_zext(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @nuw_zext_zext(
|
|
; CHECK-NEXT: [[ZX:%.*]] = zext i8 [[X:%.*]] to i32
|
|
; CHECK-NEXT: [[ZY:%.*]] = zext i8 [[Y:%.*]] to i32
|
|
; CHECK-NEXT: [[S:%.*]] = sub nuw nsw i32 [[ZX]], [[ZY]]
|
|
; CHECK-NEXT: ret i32 [[S]]
|
|
;
|
|
%zx = zext i8 %x to i32
|
|
%zy = zext i8 %y to i32
|
|
%s = sub nuw i32 %zx, %zy
|
|
ret i32 %s
|
|
}
|
|
|
|
define <2 x i16> @nuw_zext_sext(<2 x i8> %x, <2 x i8> %y) {
|
|
; CHECK-LABEL: @nuw_zext_sext(
|
|
; CHECK-NEXT: [[ZX:%.*]] = zext <2 x i8> [[X:%.*]] to <2 x i16>
|
|
; CHECK-NEXT: [[SY:%.*]] = sext <2 x i8> [[Y:%.*]] to <2 x i16>
|
|
; CHECK-NEXT: [[S:%.*]] = sub nuw nsw <2 x i16> [[ZX]], [[SY]]
|
|
; CHECK-NEXT: ret <2 x i16> [[S]]
|
|
;
|
|
%zx = zext <2 x i8> %x to <2 x i16>
|
|
%sy = sext <2 x i8> %y to <2 x i16>
|
|
%s = sub nuw <2 x i16> %zx, %sy
|
|
ret <2 x i16> %s
|
|
}
|
|
|
|
define i32 @nuw_sext_zext(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @nuw_sext_zext(
|
|
; CHECK-NEXT: [[SX:%.*]] = sext i8 [[X:%.*]] to i32
|
|
; CHECK-NEXT: [[ZY:%.*]] = zext i8 [[Y:%.*]] to i32
|
|
; CHECK-NEXT: [[S:%.*]] = sub nuw nsw i32 [[SX]], [[ZY]]
|
|
; CHECK-NEXT: ret i32 [[S]]
|
|
;
|
|
%sx = sext i8 %x to i32
|
|
%zy = zext i8 %y to i32
|
|
%s = sub nuw i32 %sx, %zy
|
|
ret i32 %s
|
|
}
|
|
|
|
define i8 @nuw_zext_zext_use1(i5 %x, i5 %y) {
|
|
; CHECK-LABEL: @nuw_zext_zext_use1(
|
|
; CHECK-NEXT: [[ZX:%.*]] = zext i5 [[X:%.*]] to i8
|
|
; CHECK-NEXT: call void @use8(i8 [[ZX]])
|
|
; CHECK-NEXT: [[ZY:%.*]] = zext i5 [[Y:%.*]] to i8
|
|
; CHECK-NEXT: [[S:%.*]] = sub nuw nsw i8 [[ZX]], [[ZY]]
|
|
; CHECK-NEXT: ret i8 [[S]]
|
|
;
|
|
%zx = zext i5 %x to i8
|
|
call void @use8(i8 %zx)
|
|
%zy = zext i5 %y to i8
|
|
%s = sub nuw i8 %zx, %zy
|
|
ret i8 %s
|
|
}
|
|
|
|
define i8 @nuw_zext_zext_use2(i5 %x, i5 %y) {
|
|
; CHECK-LABEL: @nuw_zext_zext_use2(
|
|
; CHECK-NEXT: [[ZX:%.*]] = zext i5 [[X:%.*]] to i8
|
|
; CHECK-NEXT: [[ZY:%.*]] = zext i5 [[Y:%.*]] to i8
|
|
; CHECK-NEXT: call void @use8(i8 [[ZY]])
|
|
; CHECK-NEXT: [[S:%.*]] = sub nuw nsw i8 [[ZX]], [[ZY]]
|
|
; CHECK-NEXT: ret i8 [[S]]
|
|
;
|
|
%zx = zext i5 %x to i8
|
|
%zy = zext i5 %y to i8
|
|
call void @use8(i8 %zy)
|
|
%s = sub nuw i8 %zx, %zy
|
|
ret i8 %s
|
|
}
|
|
|
|
define i8 @nuw_zext_zext_use3(i5 %x, i5 %y) {
|
|
; CHECK-LABEL: @nuw_zext_zext_use3(
|
|
; CHECK-NEXT: [[ZX:%.*]] = zext i5 [[X:%.*]] to i8
|
|
; CHECK-NEXT: call void @use8(i8 [[ZX]])
|
|
; CHECK-NEXT: [[ZY:%.*]] = zext i5 [[Y:%.*]] to i8
|
|
; CHECK-NEXT: call void @use8(i8 [[ZY]])
|
|
; CHECK-NEXT: [[S:%.*]] = sub nuw nsw i8 [[ZX]], [[ZY]]
|
|
; CHECK-NEXT: ret i8 [[S]]
|
|
;
|
|
%zx = zext i5 %x to i8
|
|
call void @use8(i8 %zx)
|
|
%zy = zext i5 %y to i8
|
|
call void @use8(i8 %zy)
|
|
%s = sub nuw i8 %zx, %zy
|
|
ret i8 %s
|
|
}
|
|
|
|
define i32 @nuw_zext_zext_different_width(i8 %x, i7 %y) {
|
|
; CHECK-LABEL: @nuw_zext_zext_different_width(
|
|
; CHECK-NEXT: [[ZX:%.*]] = zext i8 [[X:%.*]] to i32
|
|
; CHECK-NEXT: [[ZY:%.*]] = zext i7 [[Y:%.*]] to i32
|
|
; CHECK-NEXT: [[S:%.*]] = sub nuw nsw i32 [[ZX]], [[ZY]]
|
|
; CHECK-NEXT: ret i32 [[S]]
|
|
;
|
|
%zx = zext i8 %x to i32
|
|
%zy = zext i7 %y to i32
|
|
%s = sub nuw i32 %zx, %zy
|
|
ret i32 %s
|
|
}
|
|
|
|
define i16 @sext_nsw_noundef(i8 noundef %x, i8 %y) {
|
|
; CHECK-LABEL: @sext_nsw_noundef(
|
|
; CHECK-NEXT: [[Z:%.*]] = sext i8 [[Y:%.*]] to i16
|
|
; CHECK-NEXT: ret i16 [[Z]]
|
|
;
|
|
%d = sub nsw i8 %x, %y
|
|
%ex = sext i8 %x to i16
|
|
%ed = sext i8 %d to i16
|
|
%z = sub i16 %ex, %ed
|
|
ret i16 %z
|
|
}
|
|
|
|
; negative test - requires noundef
|
|
|
|
define i16 @sext_nsw(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @sext_nsw(
|
|
; CHECK-NEXT: [[D:%.*]] = sub nsw i8 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[EX:%.*]] = sext i8 [[X]] to i16
|
|
; CHECK-NEXT: [[ED:%.*]] = sext i8 [[D]] to i16
|
|
; CHECK-NEXT: [[Z:%.*]] = sub nsw i16 [[EX]], [[ED]]
|
|
; CHECK-NEXT: ret i16 [[Z]]
|
|
;
|
|
%d = sub nsw i8 %x, %y
|
|
%ex = sext i8 %x to i16
|
|
%ed = sext i8 %d to i16
|
|
%z = sub i16 %ex, %ed
|
|
ret i16 %z
|
|
}
|
|
|
|
; negative test - requires nsw
|
|
|
|
define i16 @sext_noundef(i8 noundef %x, i8 %y) {
|
|
; CHECK-LABEL: @sext_noundef(
|
|
; CHECK-NEXT: [[D:%.*]] = sub i8 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[EX:%.*]] = sext i8 [[X]] to i16
|
|
; CHECK-NEXT: [[ED:%.*]] = sext i8 [[D]] to i16
|
|
; CHECK-NEXT: [[Z:%.*]] = sub nsw i16 [[EX]], [[ED]]
|
|
; CHECK-NEXT: ret i16 [[Z]]
|
|
;
|
|
%d = sub i8 %x, %y
|
|
%ex = sext i8 %x to i16
|
|
%ed = sext i8 %d to i16
|
|
%z = sub i16 %ex, %ed
|
|
ret i16 %z
|
|
}
|
|
|
|
; negative test - must have common operand
|
|
|
|
define i16 @sext_nsw_noundef_wrong_val(i8 noundef %x, i8 noundef %y, i8 noundef %q) {
|
|
; CHECK-LABEL: @sext_nsw_noundef_wrong_val(
|
|
; CHECK-NEXT: [[D:%.*]] = sub nsw i8 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[EQ:%.*]] = sext i8 [[Q:%.*]] to i16
|
|
; CHECK-NEXT: [[ED:%.*]] = sext i8 [[D]] to i16
|
|
; CHECK-NEXT: [[Z:%.*]] = sub nsw i16 [[EQ]], [[ED]]
|
|
; CHECK-NEXT: ret i16 [[Z]]
|
|
;
|
|
%d = sub nsw i8 %x, %y
|
|
%eq = sext i8 %q to i16
|
|
%ed = sext i8 %d to i16
|
|
%z = sub i16 %eq, %ed
|
|
ret i16 %z
|
|
}
|
|
|
|
; two no-wrap analyses combine to allow reduction
|
|
|
|
define i16 @srem_sext_noundef(i8 noundef %x, i8 %y) {
|
|
; CHECK-LABEL: @srem_sext_noundef(
|
|
; CHECK-NEXT: [[R:%.*]] = srem i8 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[Z:%.*]] = sext i8 [[R]] to i16
|
|
; CHECK-NEXT: ret i16 [[Z]]
|
|
;
|
|
%r = srem i8 %x, %y
|
|
%d = sub i8 %x, %r
|
|
%sd = sext i8 %d to i16
|
|
%sx = sext i8 %x to i16
|
|
%z = sub i16 %sx, %sd
|
|
ret i16 %z
|
|
}
|
|
|
|
define i16 @zext_nuw_noundef(i8 noundef %x, i8 %y) {
|
|
; CHECK-LABEL: @zext_nuw_noundef(
|
|
; CHECK-NEXT: [[Z:%.*]] = zext i8 [[Y:%.*]] to i16
|
|
; CHECK-NEXT: ret i16 [[Z]]
|
|
;
|
|
%d = sub nuw i8 %x, %y
|
|
%ex = zext i8 %x to i16
|
|
%ed = zext i8 %d to i16
|
|
%z = sub i16 %ex, %ed
|
|
ret i16 %z
|
|
}
|
|
|
|
; negative test - requires noundef
|
|
|
|
define i16 @zext_nuw(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @zext_nuw(
|
|
; CHECK-NEXT: [[D:%.*]] = sub nuw i8 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[EX:%.*]] = zext i8 [[X]] to i16
|
|
; CHECK-NEXT: [[ED:%.*]] = zext i8 [[D]] to i16
|
|
; CHECK-NEXT: [[Z:%.*]] = sub nsw i16 [[EX]], [[ED]]
|
|
; CHECK-NEXT: ret i16 [[Z]]
|
|
;
|
|
%d = sub nuw i8 %x, %y
|
|
%ex = zext i8 %x to i16
|
|
%ed = zext i8 %d to i16
|
|
%z = sub i16 %ex, %ed
|
|
ret i16 %z
|
|
}
|
|
|
|
; negative test - requires nuw
|
|
|
|
define i16 @zext_noundef(i8 noundef %x, i8 %y) {
|
|
; CHECK-LABEL: @zext_noundef(
|
|
; CHECK-NEXT: [[D:%.*]] = sub i8 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[EX:%.*]] = zext i8 [[X]] to i16
|
|
; CHECK-NEXT: [[ED:%.*]] = zext i8 [[D]] to i16
|
|
; CHECK-NEXT: [[Z:%.*]] = sub nsw i16 [[EX]], [[ED]]
|
|
; CHECK-NEXT: ret i16 [[Z]]
|
|
;
|
|
%d = sub i8 %x, %y
|
|
%ex = zext i8 %x to i16
|
|
%ed = zext i8 %d to i16
|
|
%z = sub i16 %ex, %ed
|
|
ret i16 %z
|
|
}
|
|
|
|
; negative test - must have common operand
|
|
|
|
define i16 @zext_nsw_noundef_wrong_val(i8 noundef %x, i8 noundef %y, i8 noundef %q) {
|
|
; CHECK-LABEL: @zext_nsw_noundef_wrong_val(
|
|
; CHECK-NEXT: [[D:%.*]] = sub nuw i8 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[EQ:%.*]] = zext i8 [[Q:%.*]] to i16
|
|
; CHECK-NEXT: [[ED:%.*]] = zext i8 [[D]] to i16
|
|
; CHECK-NEXT: [[Z:%.*]] = sub nsw i16 [[EQ]], [[ED]]
|
|
; CHECK-NEXT: ret i16 [[Z]]
|
|
;
|
|
%d = sub nuw i8 %x, %y
|
|
%eq = zext i8 %q to i16
|
|
%ed = zext i8 %d to i16
|
|
%z = sub i16 %eq, %ed
|
|
ret i16 %z
|
|
}
|
|
|
|
; two no-wrap analyses combine to allow reduction
|
|
|
|
define i16 @urem_zext_noundef(i8 noundef %x, i8 %y) {
|
|
; CHECK-LABEL: @urem_zext_noundef(
|
|
; CHECK-NEXT: [[R:%.*]] = urem i8 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[Z:%.*]] = zext i8 [[R]] to i16
|
|
; CHECK-NEXT: ret i16 [[Z]]
|
|
;
|
|
%r = urem i8 %x, %y
|
|
%d = sub i8 %x, %r
|
|
%ed = zext i8 %d to i16
|
|
%ex = zext i8 %x to i16
|
|
%z = sub i16 %ex, %ed
|
|
ret i16 %z
|
|
}
|
|
|
|
; x * y - x --> (y - 1) * x
|
|
; TODO: The mul could retain nsw.
|
|
|
|
define i8 @mul_sub_common_factor_commute1(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @mul_sub_common_factor_commute1(
|
|
; CHECK-NEXT: [[X1:%.*]] = add i8 [[Y:%.*]], -1
|
|
; CHECK-NEXT: [[A:%.*]] = mul i8 [[X1]], [[X:%.*]]
|
|
; CHECK-NEXT: ret i8 [[A]]
|
|
;
|
|
%m = mul nsw i8 %x, %y
|
|
%a = sub nsw i8 %m, %x
|
|
ret i8 %a
|
|
}
|
|
|
|
; TODO: The mul could retain nuw.
|
|
|
|
define <2 x i8> @mul_sub_common_factor_commute2(<2 x i8> %x, <2 x i8> %y) {
|
|
; CHECK-LABEL: @mul_sub_common_factor_commute2(
|
|
; CHECK-NEXT: [[M1:%.*]] = add <2 x i8> [[Y:%.*]], <i8 -1, i8 -1>
|
|
; CHECK-NEXT: [[A:%.*]] = mul <2 x i8> [[M1]], [[X:%.*]]
|
|
; CHECK-NEXT: ret <2 x i8> [[A]]
|
|
;
|
|
%m = mul nuw <2 x i8> %y, %x
|
|
%a = sub nuw <2 x i8> %m, %x
|
|
ret <2 x i8> %a
|
|
}
|
|
|
|
; x - (x * y) --> (1 - y) * x
|
|
|
|
define i8 @mul_sub_common_factor_commute3(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @mul_sub_common_factor_commute3(
|
|
; CHECK-NEXT: [[M1:%.*]] = sub i8 1, [[Y:%.*]]
|
|
; CHECK-NEXT: [[A:%.*]] = mul i8 [[M1]], [[X:%.*]]
|
|
; CHECK-NEXT: ret i8 [[A]]
|
|
;
|
|
%m = mul nuw i8 %x, %y
|
|
%a = sub nsw i8 %x, %m
|
|
ret i8 %a
|
|
}
|
|
|
|
define i8 @mul_sub_common_factor_commute4(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @mul_sub_common_factor_commute4(
|
|
; CHECK-NEXT: [[M1:%.*]] = sub i8 1, [[Y:%.*]]
|
|
; CHECK-NEXT: [[A:%.*]] = mul i8 [[M1]], [[X:%.*]]
|
|
; CHECK-NEXT: ret i8 [[A]]
|
|
;
|
|
%m = mul nsw i8 %y, %x
|
|
%a = sub nuw i8 %x, %m
|
|
ret i8 %a
|
|
}
|
|
|
|
; negative test - uses
|
|
|
|
define i8 @mul_sub_common_factor_use(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @mul_sub_common_factor_use(
|
|
; CHECK-NEXT: [[M:%.*]] = mul i8 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: call void @use8(i8 [[M]])
|
|
; CHECK-NEXT: [[A:%.*]] = sub i8 [[M]], [[X]]
|
|
; CHECK-NEXT: ret i8 [[A]]
|
|
;
|
|
%m = mul i8 %x, %y
|
|
call void @use8(i8 %m)
|
|
%a = sub i8 %m, %x
|
|
ret i8 %a
|
|
}
|
|
|
|
define i5 @demand_low_bits_uses(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @demand_low_bits_uses(
|
|
; CHECK-NEXT: [[M:%.*]] = and i8 [[X:%.*]], 96
|
|
; CHECK-NEXT: [[A:%.*]] = sub i8 [[Y:%.*]], [[M]]
|
|
; CHECK-NEXT: call void @use8(i8 [[A]])
|
|
; CHECK-NEXT: [[R:%.*]] = trunc i8 [[Y]] to i5
|
|
; CHECK-NEXT: ret i5 [[R]]
|
|
;
|
|
%m = and i8 %x, 96 ; 0x60
|
|
%a = sub i8 %y, %m
|
|
call void @use8(i8 %a)
|
|
%r = trunc i8 %a to i5
|
|
ret i5 %r
|
|
}
|
|
|
|
; negative test - demands one more bit
|
|
|
|
define i6 @demand_low_bits_uses_extra_bit(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @demand_low_bits_uses_extra_bit(
|
|
; CHECK-NEXT: [[M:%.*]] = and i8 [[X:%.*]], 96
|
|
; CHECK-NEXT: [[A:%.*]] = sub i8 [[Y:%.*]], [[M]]
|
|
; CHECK-NEXT: call void @use8(i8 [[A]])
|
|
; CHECK-NEXT: [[R:%.*]] = trunc i8 [[A]] to i6
|
|
; CHECK-NEXT: ret i6 [[R]]
|
|
;
|
|
%m = and i8 %x, 96 ; 0x60
|
|
%a = sub i8 %y, %m
|
|
call void @use8(i8 %a)
|
|
%r = trunc i8 %a to i6
|
|
ret i6 %r
|
|
}
|
|
|
|
; negative test - must be operand 1
|
|
|
|
define i8 @demand_low_bits_uses_commute(i8 %x, i8 %y, i8 %z) {
|
|
; CHECK-LABEL: @demand_low_bits_uses_commute(
|
|
; CHECK-NEXT: [[M:%.*]] = and i8 [[X:%.*]], -64
|
|
; CHECK-NEXT: [[A:%.*]] = sub i8 [[M]], [[Y:%.*]]
|
|
; CHECK-NEXT: call void @use8(i8 [[A]])
|
|
; CHECK-NEXT: [[S:%.*]] = sub i8 [[A]], [[Z:%.*]]
|
|
; CHECK-NEXT: [[R:%.*]] = shl i8 [[S]], 2
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%m = and i8 %x, -64 ; 0xC0
|
|
%a = sub i8 %m, %y
|
|
call void @use8(i8 %a)
|
|
%s = sub i8 %a, %z
|
|
%r = shl i8 %s, 2
|
|
ret i8 %r
|
|
}
|
|
|
|
; sub becomes negate and combines with shl
|
|
|
|
define i8 @shrink_sub_from_constant_lowbits(i8 %x) {
|
|
; CHECK-LABEL: @shrink_sub_from_constant_lowbits(
|
|
; CHECK-NEXT: [[X000_NEG:%.*]] = mul i8 [[X:%.*]], -8
|
|
; CHECK-NEXT: ret i8 [[X000_NEG]]
|
|
;
|
|
%x000 = shl i8 %x, 3 ; 3 low bits are known zero
|
|
%sub = sub i8 7, %x000
|
|
%r = and i8 %sub, -8 ; 3 low bits are not demanded
|
|
ret i8 %r
|
|
}
|
|
|
|
; negative test - extra use prevents shrinking '7'
|
|
|
|
define i8 @shrink_sub_from_constant_lowbits_uses(i8 %x) {
|
|
; CHECK-LABEL: @shrink_sub_from_constant_lowbits_uses(
|
|
; CHECK-NEXT: [[X000:%.*]] = shl i8 [[X:%.*]], 3
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub i8 7, [[X000]]
|
|
; CHECK-NEXT: call void @use8(i8 [[SUB]])
|
|
; CHECK-NEXT: [[R:%.*]] = and i8 [[SUB]], -8
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%x000 = shl i8 %x, 3 ; 3 low bits are known zero
|
|
%sub = sub i8 7, %x000
|
|
call void @use8(i8 %sub)
|
|
%r = and i8 %sub, -8 ; 3 low bits are not demanded
|
|
ret i8 %r
|
|
}
|
|
|
|
; safe to clear 3 low bits (2 higher bits remain set)
|
|
|
|
define i8 @shrink_sub_from_constant_lowbits2(i8 %x) {
|
|
; CHECK-LABEL: @shrink_sub_from_constant_lowbits2(
|
|
; CHECK-NEXT: [[X000:%.*]] = and i8 [[X:%.*]], -8
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i8 24, [[X000]]
|
|
; CHECK-NEXT: [[R:%.*]] = and i8 [[SUB]], -16
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%x000 = and i8 %x, -8 ; 3 low bits are known zero
|
|
%sub = sub nsw i8 30, %x000 ; 0b0001_1110
|
|
%r = and i8 %sub, -16 ; 4 low bits are not demanded
|
|
ret i8 %r
|
|
}
|
|
|
|
; safe to clear 3 low bits (2 higher bits remain set)
|
|
|
|
define <2 x i8> @shrink_sub_from_constant_lowbits3(<2 x i8> %x) {
|
|
; CHECK-LABEL: @shrink_sub_from_constant_lowbits3(
|
|
; CHECK-NEXT: [[X0000:%.*]] = shl <2 x i8> [[X:%.*]], <i8 4, i8 4>
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nuw <2 x i8> <i8 24, i8 24>, [[X0000]]
|
|
; CHECK-NEXT: [[R:%.*]] = lshr exact <2 x i8> [[SUB]], <i8 3, i8 3>
|
|
; CHECK-NEXT: ret <2 x i8> [[R]]
|
|
;
|
|
%x0000 = shl <2 x i8> %x, <i8 4, i8 4> ; 4 low bits are known zero
|
|
%sub = sub nuw <2 x i8> <i8 31, i8 31>, %x0000
|
|
%r = lshr <2 x i8> %sub, <i8 3, i8 3> ; 3 low bits are not demanded
|
|
ret <2 x i8> %r
|
|
}
|
|
|
|
; eliminate the mask of y or the mask of the result
|
|
|
|
define i8 @demand_sub_from_variable_lowbits(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @demand_sub_from_variable_lowbits(
|
|
; CHECK-NEXT: [[X000:%.*]] = shl i8 [[X:%.*]], 3
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[Y:%.*]], [[X000]]
|
|
; CHECK-NEXT: [[R:%.*]] = and i8 [[SUB]], -8
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%x000 = shl i8 %x, 3 ; 3 low bits are known zero
|
|
%y000 = and i8 %y, -8
|
|
%sub = sub i8 %y000, %x000
|
|
%r = and i8 %sub, -8 ; 3 low bits are not demanded
|
|
ret i8 %r
|
|
}
|
|
|
|
; setting the low 3 bits of y doesn't change anything
|
|
|
|
define i8 @demand_sub_from_variable_lowbits2(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @demand_sub_from_variable_lowbits2(
|
|
; CHECK-NEXT: [[X0000:%.*]] = shl i8 [[X:%.*]], 4
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nuw nsw i8 [[Y:%.*]], [[X0000]]
|
|
; CHECK-NEXT: [[R:%.*]] = lshr i8 [[SUB]], 4
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%x0000 = shl i8 %x, 4 ; 4 low bits are known zero
|
|
%y111 = or i8 %y, 7
|
|
%sub = sub nsw nuw i8 %y111, %x0000
|
|
%r = lshr i8 %sub, 4 ; 4 low bits are not demanded
|
|
ret i8 %r
|
|
}
|
|
|
|
; negative test - the mask of y removes an extra bit, so that instruction is needed
|
|
|
|
define i8 @demand_sub_from_variable_lowbits3(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @demand_sub_from_variable_lowbits3(
|
|
; CHECK-NEXT: [[X0000:%.*]] = shl i8 [[X:%.*]], 4
|
|
; CHECK-NEXT: [[Y00000:%.*]] = and i8 [[Y:%.*]], -32
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[Y00000]], [[X0000]]
|
|
; CHECK-NEXT: [[R:%.*]] = lshr exact i8 [[SUB]], 4
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%x0000 = shl i8 %x, 4 ; 4 low bits are known zero
|
|
%y00000 = and i8 %y, -32
|
|
%sub = sub i8 %y00000, %x0000
|
|
%r = lshr i8 %sub, 4 ; 4 low bits are not demanded
|
|
ret i8 %r
|
|
}
|
|
|
|
; C - ((C3 - X) & C2) --> (C - (C2 & C3)) + (X & C2) when:
|
|
; (C3 - ((C2 & C3) - 1)) is pow2
|
|
; ((C2 + C3) & ((C2 & C3) - 1)) == ((C2 & C3) - 1)
|
|
; C2 is negative pow2
|
|
define i10 @sub_to_and_nuw(i10 %x) {
|
|
; CHECK-LABEL: @sub_to_and_nuw(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = and i10 [[X:%.*]], 120
|
|
; CHECK-NEXT: [[R:%.*]] = add nuw nsw i10 [[TMP1]], 379
|
|
; CHECK-NEXT: ret i10 [[R]]
|
|
;
|
|
%sub = sub nuw i10 71, %x
|
|
%and = and i10 %sub, 120
|
|
%r = sub i10 443, %and
|
|
ret i10 %r
|
|
}
|
|
|
|
; C - ((C3 -nuw X) & C2) --> (C - (C2 & C3)) + (X & C2) when:
|
|
; (C3 - ((C2 & C3) - 1)) is pow2
|
|
; ((C2 + C3) & ((C2 & C3) - 1)) == ((C2 & C3) - 1)
|
|
define i10 @sub_to_and_negpow2(i10 %x) {
|
|
; CHECK-LABEL: @sub_to_and_negpow2(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = and i10 [[X:%.*]], -8
|
|
; CHECK-NEXT: [[R:%.*]] = add i10 [[TMP1]], -31
|
|
; CHECK-NEXT: ret i10 [[R]]
|
|
;
|
|
%sub = sub i10 71, %x
|
|
%and = and i10 %sub, -8
|
|
%r = sub i10 33, %and
|
|
ret i10 %r
|
|
}
|
|
|
|
; TODO:
|
|
; C + ((C3 -nuw X) & C2) --> (C + (C2 & C3)) - (X & C2) when:
|
|
define i10 @add_to_and_nuw(i10 %x) {
|
|
; CHECK-LABEL: @add_to_and_nuw(
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nuw i10 71, [[X:%.*]]
|
|
; CHECK-NEXT: [[AND:%.*]] = and i10 [[SUB]], 120
|
|
; CHECK-NEXT: [[R:%.*]] = add nuw nsw i10 [[AND]], 224
|
|
; CHECK-NEXT: ret i10 [[R]]
|
|
;
|
|
%sub = sub nuw i10 71, %x
|
|
%and = and i10 %sub, 120
|
|
%r = add i10 224, %and
|
|
ret i10 %r
|
|
}
|
|
|
|
; (C3 - (C2 & C3) + 1) is not pow2
|
|
define i10 @sub_to_and_negative1(i10 %x) {
|
|
; CHECK-LABEL: @sub_to_and_negative1(
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub i10 71, [[X:%.*]]
|
|
; CHECK-NEXT: [[AND:%.*]] = and i10 [[SUB]], 248
|
|
; CHECK-NEXT: [[R:%.*]] = sub nuw nsw i10 444, [[AND]]
|
|
; CHECK-NEXT: ret i10 [[R]]
|
|
;
|
|
%sub = sub nuw i10 327, %x
|
|
%and = and i10 %sub, 248
|
|
%r = sub i10 444, %and
|
|
ret i10 %r
|
|
}
|
|
|
|
; ((C2 + C3) & ((C2 & C3) - 1)) == ((C2 & C3) - 1)
|
|
define i10 @sub_to_and_negative2(i10 %x) {
|
|
; CHECK-LABEL: @sub_to_and_negative2(
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nuw i10 71, [[X:%.*]]
|
|
; CHECK-NEXT: [[AND:%.*]] = and i10 [[SUB]], 88
|
|
; CHECK-NEXT: [[R:%.*]] = sub nsw i10 64, [[AND]]
|
|
; CHECK-NEXT: ret i10 [[R]]
|
|
;
|
|
%sub = sub nuw i10 71, %x
|
|
%and = and i10 %sub, 88
|
|
%r = sub i10 64, %and
|
|
ret i10 %r
|
|
}
|
|
|
|
; no nuw && C2 is not neg-pow2
|
|
define i10 @sub_to_and_negative3(i10 %x) {
|
|
; CHECK-LABEL: @sub_to_and_negative3(
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub i10 71, [[X:%.*]]
|
|
; CHECK-NEXT: [[AND:%.*]] = and i10 [[SUB]], 120
|
|
; CHECK-NEXT: [[R:%.*]] = sub nsw i10 64, [[AND]]
|
|
; CHECK-NEXT: ret i10 [[R]]
|
|
;
|
|
%sub = sub i10 71, %x
|
|
%and = and i10 %sub, 120
|
|
%r = sub i10 64, %and
|
|
ret i10 %r
|
|
}
|
|
|
|
declare void @use10(i10)
|
|
|
|
; and is not one-use
|
|
define i10 @sub_to_and_negative4(i10 %x) {
|
|
; CHECK-LABEL: @sub_to_and_negative4(
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub i10 71, [[X:%.*]]
|
|
; CHECK-NEXT: [[AND:%.*]] = and i10 [[SUB]], 120
|
|
; CHECK-NEXT: [[R:%.*]] = sub nsw i10 64, [[AND]]
|
|
; CHECK-NEXT: call void @use10(i10 [[AND]])
|
|
; CHECK-NEXT: ret i10 [[R]]
|
|
;
|
|
%sub = sub i10 71, %x
|
|
%and = and i10 %sub, 120
|
|
%r = sub i10 64, %and
|
|
call void @use10(i10 %and)
|
|
ret i10 %r
|
|
}
|
|
|
|
|
|
define <2 x i8> @sub_to_and_vector1(<2 x i8> %x) {
|
|
; CHECK-LABEL: @sub_to_and_vector1(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> [[X:%.*]], <i8 120, i8 120>
|
|
; CHECK-NEXT: [[R:%.*]] = add nsw <2 x i8> [[TMP1]], <i8 -9, i8 -9>
|
|
; CHECK-NEXT: ret <2 x i8> [[R]]
|
|
;
|
|
%sub = sub nuw <2 x i8> <i8 71, i8 71>, %x
|
|
%and = and <2 x i8> %sub, <i8 120, i8 120>
|
|
%r = sub <2 x i8> <i8 55, i8 55>, %and
|
|
ret <2 x i8> %r
|
|
}
|
|
|
|
|
|
define <2 x i8> @sub_to_and_vector2(<2 x i8> %x) {
|
|
; CHECK-LABEL: @sub_to_and_vector2(
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nuw <2 x i8> <i8 71, i8 undef>, [[X:%.*]]
|
|
; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[SUB]], <i8 120, i8 120>
|
|
; CHECK-NEXT: [[R:%.*]] = sub nsw <2 x i8> <i8 77, i8 77>, [[AND]]
|
|
; CHECK-NEXT: ret <2 x i8> [[R]]
|
|
;
|
|
%sub = sub nuw <2 x i8> <i8 71, i8 undef>, %x
|
|
%and = and <2 x i8> %sub, <i8 120, i8 120>
|
|
%r = sub <2 x i8> <i8 77, i8 77>, %and
|
|
ret <2 x i8> %r
|
|
}
|
|
|
|
|
|
define <2 x i8> @sub_to_and_vector3(<2 x i8> %x) {
|
|
; CHECK-LABEL: @sub_to_and_vector3(
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nuw <2 x i8> <i8 71, i8 71>, [[X:%.*]]
|
|
; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[SUB]], <i8 120, i8 undef>
|
|
; CHECK-NEXT: [[R:%.*]] = sub <2 x i8> <i8 44, i8 44>, [[AND]]
|
|
; CHECK-NEXT: ret <2 x i8> [[R]]
|
|
;
|
|
%sub = sub nuw <2 x i8> <i8 71, i8 71>, %x
|
|
%and = and <2 x i8> %sub, <i8 120, i8 undef>
|
|
%r = sub <2 x i8> <i8 44, i8 44>, %and
|
|
ret <2 x i8> %r
|
|
}
|
|
|
|
|
|
define <2 x i8> @sub_to_and_vector4(<2 x i8> %x) {
|
|
; CHECK-LABEL: @sub_to_and_vector4(
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nuw <2 x i8> <i8 71, i8 71>, [[X:%.*]]
|
|
; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[SUB]], <i8 120, i8 120>
|
|
; CHECK-NEXT: [[R:%.*]] = sub <2 x i8> <i8 88, i8 undef>, [[AND]]
|
|
; CHECK-NEXT: ret <2 x i8> [[R]]
|
|
;
|
|
%sub = sub nuw <2 x i8> <i8 71, i8 71>, %x
|
|
%and = and <2 x i8> %sub, <i8 120, i8 120>
|
|
%r = sub <2 x i8> <i8 88, i8 undef>, %and
|
|
ret <2 x i8> %r
|
|
}
|
|
|
|
; (X * X) - (Y * Y) --> (X + Y) * (X - Y)
|
|
|
|
define i8 @diff_of_squares(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @diff_of_squares(
|
|
; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[R:%.*]] = mul i8 [[ADD]], [[SUB]]
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%x2 = mul i8 %x, %x
|
|
%y2 = mul i8 %y, %y
|
|
%r = sub i8 %x2, %y2
|
|
ret i8 %r
|
|
}
|
|
|
|
; All-or-nothing for propagation of no-wrap flags (possibly conservative)
|
|
|
|
define i5 @diff_of_squares_nuw(i5 %x, i5 %y) {
|
|
; CHECK-LABEL: @diff_of_squares_nuw(
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nuw i5 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nuw i5 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[R:%.*]] = mul nuw i5 [[ADD]], [[SUB]]
|
|
; CHECK-NEXT: ret i5 [[R]]
|
|
;
|
|
%x2 = mul nuw i5 %x, %x
|
|
%y2 = mul nuw i5 %y, %y
|
|
%r = sub nuw i5 %x2, %y2
|
|
ret i5 %r
|
|
}
|
|
|
|
; All-or-nothing for propagation of no-wrap flags (possibly conservative)
|
|
|
|
define i5 @diff_of_squares_partial_nuw(i5 %x, i5 %y) {
|
|
; CHECK-LABEL: @diff_of_squares_partial_nuw(
|
|
; CHECK-NEXT: [[ADD:%.*]] = add i5 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub i5 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[R:%.*]] = mul i5 [[ADD]], [[SUB]]
|
|
; CHECK-NEXT: ret i5 [[R]]
|
|
;
|
|
%x2 = mul nuw i5 %x, %x
|
|
%y2 = mul nuw i5 %y, %y
|
|
%r = sub i5 %x2, %y2
|
|
ret i5 %r
|
|
}
|
|
|
|
; All-or-nothing for propagation of no-wrap flags (possibly conservative)
|
|
|
|
define <2 x i5> @diff_of_squares_nsw(<2 x i5> %x, <2 x i5> %y) {
|
|
; CHECK-LABEL: @diff_of_squares_nsw(
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nsw <2 x i5> [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nsw <2 x i5> [[X]], [[Y]]
|
|
; CHECK-NEXT: [[R:%.*]] = mul nsw <2 x i5> [[ADD]], [[SUB]]
|
|
; CHECK-NEXT: ret <2 x i5> [[R]]
|
|
;
|
|
%x2 = mul nsw <2 x i5> %x, %x
|
|
%y2 = mul nsw <2 x i5> %y, %y
|
|
%r = sub nsw <2 x i5> %x2, %y2
|
|
ret <2 x i5> %r
|
|
}
|
|
|
|
; All-or-nothing for propagation of no-wrap flags (possibly conservative)
|
|
|
|
define <2 x i5> @diff_of_squares_partial_nsw(<2 x i5> %x, <2 x i5> %y) {
|
|
; CHECK-LABEL: @diff_of_squares_partial_nsw(
|
|
; CHECK-NEXT: [[ADD:%.*]] = add <2 x i5> [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub <2 x i5> [[X]], [[Y]]
|
|
; CHECK-NEXT: [[R:%.*]] = mul <2 x i5> [[ADD]], [[SUB]]
|
|
; CHECK-NEXT: ret <2 x i5> [[R]]
|
|
;
|
|
%x2 = mul nsw <2 x i5> %x, %x
|
|
%y2 = mul <2 x i5> %y, %y
|
|
%r = sub nsw <2 x i5> %x2, %y2
|
|
ret <2 x i5> %r
|
|
}
|
|
|
|
define i1 @diff_of_squares_nsw_i1(i1 %x, i1 %y) {
|
|
; CHECK-LABEL: @diff_of_squares_nsw_i1(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%x2 = mul nsw i1 %x, %x
|
|
%y2 = mul nsw i1 %y, %y
|
|
%r = sub nsw i1 %x2, %y2
|
|
ret i1 %r
|
|
}
|
|
|
|
define i1 @diff_of_squares_nuw_i1(i1 %x, i1 %y) {
|
|
; CHECK-LABEL: @diff_of_squares_nuw_i1(
|
|
; CHECK-NEXT: [[R:%.*]] = xor i1 [[Y:%.*]], [[X:%.*]]
|
|
; CHECK-NEXT: ret i1 [[R]]
|
|
;
|
|
%x2 = mul nuw i1 %x, %x
|
|
%y2 = mul nuw i1 %y, %y
|
|
%r = sub nuw i1 %x2, %y2
|
|
ret i1 %r
|
|
}
|
|
|
|
; It is not correct to propagate nsw.
|
|
; TODO: This should reduce more.
|
|
|
|
define i2 @diff_of_squares_nsw_i2(i2 %x, i2 %y) {
|
|
; CHECK-LABEL: @diff_of_squares_nsw_i2(
|
|
; CHECK-NEXT: [[ADD:%.*]] = add i2 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub i2 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[R:%.*]] = mul i2 [[ADD]], [[SUB]]
|
|
; CHECK-NEXT: ret i2 [[R]]
|
|
;
|
|
%x2 = mul nsw i2 %x, %x
|
|
%y2 = mul nsw i2 %y, %y
|
|
%r = sub nsw i2 %x2, %y2
|
|
ret i2 %r
|
|
}
|
|
|
|
; TODO: This should reduce more.
|
|
|
|
define i2 @diff_of_squares_nuw_i2(i2 %x, i2 %y) {
|
|
; CHECK-LABEL: @diff_of_squares_nuw_i2(
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nuw i2 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nuw i2 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[R:%.*]] = mul nuw i2 [[ADD]], [[SUB]]
|
|
; CHECK-NEXT: ret i2 [[R]]
|
|
;
|
|
%x2 = mul nuw i2 %x, %x
|
|
%y2 = mul nuw i2 %y, %y
|
|
%r = sub nuw i2 %x2, %y2
|
|
ret i2 %r
|
|
}
|
|
|
|
; negative test
|
|
|
|
define i8 @diff_of_squares_use1(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @diff_of_squares_use1(
|
|
; CHECK-NEXT: [[X2:%.*]] = mul i8 [[X:%.*]], [[X]]
|
|
; CHECK-NEXT: call void @use8(i8 [[X2]])
|
|
; CHECK-NEXT: [[Y2:%.*]] = mul i8 [[Y:%.*]], [[Y]]
|
|
; CHECK-NEXT: [[R:%.*]] = sub i8 [[X2]], [[Y2]]
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%x2 = mul i8 %x, %x
|
|
call void @use8(i8 %x2)
|
|
%y2 = mul i8 %y, %y
|
|
%r = sub i8 %x2, %y2
|
|
ret i8 %r
|
|
}
|
|
|
|
; negative test
|
|
|
|
define i8 @diff_of_squares_use2(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @diff_of_squares_use2(
|
|
; CHECK-NEXT: [[X2:%.*]] = mul i8 [[X:%.*]], [[X]]
|
|
; CHECK-NEXT: [[Y2:%.*]] = mul i8 [[Y:%.*]], [[Y]]
|
|
; CHECK-NEXT: call void @use8(i8 [[Y2]])
|
|
; CHECK-NEXT: [[R:%.*]] = sub i8 [[X2]], [[Y2]]
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%x2 = mul i8 %x, %x
|
|
%y2 = mul i8 %y, %y
|
|
call void @use8(i8 %y2)
|
|
%r = sub i8 %x2, %y2
|
|
ret i8 %r
|
|
}
|
|
|
|
; negative test - must be squares
|
|
|
|
define i8 @diff_of_muls1(i8 %x, i8 %y, i8 %z) {
|
|
; CHECK-LABEL: @diff_of_muls1(
|
|
; CHECK-NEXT: [[M:%.*]] = mul i8 [[X:%.*]], [[Z:%.*]]
|
|
; CHECK-NEXT: [[Y2:%.*]] = mul i8 [[Y:%.*]], [[Y]]
|
|
; CHECK-NEXT: [[R:%.*]] = sub i8 [[M]], [[Y2]]
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%m = mul i8 %x, %z
|
|
%y2 = mul i8 %y, %y
|
|
%r = sub i8 %m, %y2
|
|
ret i8 %r
|
|
}
|
|
|
|
; negative test - must be squares
|
|
|
|
define i8 @diff_of_muls2(i8 %x, i8 %y, i8 %z) {
|
|
; CHECK-LABEL: @diff_of_muls2(
|
|
; CHECK-NEXT: [[X2:%.*]] = mul i8 [[X:%.*]], [[X]]
|
|
; CHECK-NEXT: [[M:%.*]] = mul i8 [[Y:%.*]], [[Z:%.*]]
|
|
; CHECK-NEXT: [[R:%.*]] = sub i8 [[X2]], [[M]]
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%x2 = mul i8 %x, %x
|
|
%m = mul i8 %y, %z
|
|
%r = sub i8 %x2, %m
|
|
ret i8 %r
|
|
}
|
|
|
|
define i8 @sub_of_adds_2xz_multiuse(i8 %x, i8 %y, i8 %z) {
|
|
; CHECK-LABEL: @sub_of_adds_2xz_multiuse(
|
|
; CHECK-NEXT: [[XZ:%.*]] = add i8 [[X:%.*]], [[Z:%.*]]
|
|
; CHECK-NEXT: [[YZ:%.*]] = add i8 [[Z]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[R:%.*]] = sub i8 [[X]], [[Y]]
|
|
; CHECK-NEXT: call void @use8(i8 [[XZ]])
|
|
; CHECK-NEXT: call void @use8(i8 [[YZ]])
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%xz = add i8 %x, %z
|
|
%yz = add i8 %z, %y
|
|
%r = sub i8 %xz, %yz
|
|
call void @use8(i8 %xz)
|
|
call void @use8(i8 %yz)
|
|
ret i8 %r
|
|
}
|
|
|
|
define i8 @sub_of_adds_2xc_multiuse2_fail(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @sub_of_adds_2xc_multiuse2_fail(
|
|
; CHECK-NEXT: [[XC:%.*]] = add i8 [[X:%.*]], 10
|
|
; CHECK-NEXT: [[YC:%.*]] = add i8 [[Y:%.*]], 11
|
|
; CHECK-NEXT: [[R:%.*]] = sub i8 [[XC]], [[YC]]
|
|
; CHECK-NEXT: call void @use8(i8 [[XC]])
|
|
; CHECK-NEXT: call void @use8(i8 [[YC]])
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%xc = add i8 %x, 10
|
|
%yc = add i8 %y, 11
|
|
%r = sub i8 %xc, %yc
|
|
call void @use8(i8 %xc)
|
|
call void @use8(i8 %yc)
|
|
ret i8 %r
|
|
}
|
|
|
|
define i8 @sub_of_adds_2xc(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @sub_of_adds_2xc(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = sub i8 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[R:%.*]] = add i8 [[TMP1]], 2
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%xc = add i8 %x, 10
|
|
%yc = add i8 %y, 8
|
|
%r = sub i8 %xc, %yc
|
|
ret i8 %r
|
|
}
|