| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt < %s -passes=instcombine -S | FileCheck %s |
| |
| ; Basic pattern |
| define i8 @t0(i8 %x, i1 %cond) { |
| ; CHECK-LABEL: @t0( |
| ; CHECK-NEXT: [[X_NEG:%.*]] = sub i8 0, [[X:%.*]] |
| ; CHECK-NEXT: [[XOR:%.*]] = select i1 [[COND:%.*]], i8 [[X_NEG]], i8 [[X]] |
| ; CHECK-NEXT: ret i8 [[XOR]] |
| ; |
| %cond.splat = sext i1 %cond to i8 |
| %sub = add i8 %cond.splat, %x |
| %xor = xor i8 %sub, %cond.splat |
| ret i8 %xor |
| } |
| define <2 x i8> @t0_vec(<2 x i8> %x, <2 x i1> %cond) { |
| ; CHECK-LABEL: @t0_vec( |
| ; CHECK-NEXT: [[X_NEG:%.*]] = sub <2 x i8> zeroinitializer, [[X:%.*]] |
| ; CHECK-NEXT: [[XOR:%.*]] = select <2 x i1> [[COND:%.*]], <2 x i8> [[X_NEG]], <2 x i8> [[X]] |
| ; CHECK-NEXT: ret <2 x i8> [[XOR]] |
| ; |
| %cond.splat = sext <2 x i1> %cond to <2 x i8> |
| %sub = add <2 x i8> %cond.splat, %x |
| %xor = xor <2 x i8> %sub, %cond.splat |
| ret <2 x i8> %xor |
| } |
| |
| ; Two different extensions are fine |
| define i8 @t1(i8 %x, i1 %cond) { |
| ; CHECK-LABEL: @t1( |
| ; CHECK-NEXT: [[X_NEG:%.*]] = sub i8 0, [[X:%.*]] |
| ; CHECK-NEXT: [[XOR:%.*]] = select i1 [[COND:%.*]], i8 [[X_NEG]], i8 [[X]] |
| ; CHECK-NEXT: ret i8 [[XOR]] |
| ; |
| %cond.splat0 = sext i1 %cond to i8 |
| %cond.splat1 = sext i1 %cond to i8 |
| %sub = add i8 %cond.splat0, %x |
| %xor = xor i8 %sub, %cond.splat1 |
| ret i8 %xor |
| } |
| |
| ; Two different extensions of different conditions are not fine |
| define i8 @t2(i8 %x, i1 %cond0, i1 %cond1) { |
| ; CHECK-LABEL: @t2( |
| ; CHECK-NEXT: [[COND_SPLAT0:%.*]] = sext i1 [[COND0:%.*]] to i8 |
| ; CHECK-NEXT: [[COND_SPLAT1:%.*]] = sext i1 [[COND1:%.*]] to i8 |
| ; CHECK-NEXT: [[SUB:%.*]] = add i8 [[COND_SPLAT0]], [[X:%.*]] |
| ; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[SUB]], [[COND_SPLAT1]] |
| ; CHECK-NEXT: ret i8 [[XOR]] |
| ; |
| %cond.splat0 = sext i1 %cond0 to i8 |
| %cond.splat1 = sext i1 %cond1 to i8 |
| %sub = add i8 %cond.splat0, %x |
| %xor = xor i8 %sub, %cond.splat1 |
| ret i8 %xor |
| } |
| |
| ; Condition must be boolean. |
| define i8 @t3(i8 %x, i2 %cond) { |
| ; CHECK-LABEL: @t3( |
| ; CHECK-NEXT: [[COND_SPLAT:%.*]] = sext i2 [[COND:%.*]] to i8 |
| ; CHECK-NEXT: [[SUB:%.*]] = add i8 [[COND_SPLAT]], [[X:%.*]] |
| ; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[SUB]], [[COND_SPLAT]] |
| ; CHECK-NEXT: ret i8 [[XOR]] |
| ; |
| %cond.splat = sext i2 %cond to i8 |
| %sub = add i8 %cond.splat, %x |
| %xor = xor i8 %sub, %cond.splat |
| ret i8 %xor |
| } |
| define <2 x i8> @t3_vec(<2 x i8> %x, <2 x i2> %cond) { |
| ; CHECK-LABEL: @t3_vec( |
| ; CHECK-NEXT: [[COND_SPLAT:%.*]] = sext <2 x i2> [[COND:%.*]] to <2 x i8> |
| ; CHECK-NEXT: [[SUB:%.*]] = add <2 x i8> [[COND_SPLAT]], [[X:%.*]] |
| ; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i8> [[SUB]], [[COND_SPLAT]] |
| ; CHECK-NEXT: ret <2 x i8> [[XOR]] |
| ; |
| %cond.splat = sext <2 x i2> %cond to <2 x i8> |
| %sub = add <2 x i8> %cond.splat, %x |
| %xor = xor <2 x i8> %sub, %cond.splat |
| ret <2 x i8> %xor |
| } |
| |
| ; add is commutative |
| ; xor is not commutative here because of complexity ordering |
| define i8 @xor.commuted(i1 %cond) { |
| ; CHECK-LABEL: @xor.commuted( |
| ; CHECK-NEXT: [[X:%.*]] = call i8 @gen.i8() |
| ; CHECK-NEXT: [[X_NEG:%.*]] = sub i8 0, [[X]] |
| ; CHECK-NEXT: [[XOR:%.*]] = select i1 [[COND:%.*]], i8 [[X_NEG]], i8 [[X]] |
| ; CHECK-NEXT: ret i8 [[XOR]] |
| ; |
| %cond.splat = sext i1 %cond to i8 |
| %x = call i8 @gen.i8() |
| %sub = add i8 %x, %cond.splat |
| %xor = xor i8 %sub, %cond.splat |
| ret i8 %xor |
| } |
| |
| ; Extra use tests |
| define i8 @extrause01_v1(i8 %x, i1 %cond) { |
| ; CHECK-LABEL: @extrause01_v1( |
| ; CHECK-NEXT: [[COND_SPLAT:%.*]] = sext i1 [[COND:%.*]] to i8 |
| ; CHECK-NEXT: call void @use.i8(i8 [[COND_SPLAT]]) |
| ; CHECK-NEXT: [[X_NEG:%.*]] = sub i8 0, [[X:%.*]] |
| ; CHECK-NEXT: [[XOR:%.*]] = select i1 [[COND]], i8 [[X_NEG]], i8 [[X]] |
| ; CHECK-NEXT: ret i8 [[XOR]] |
| ; |
| %cond.splat = sext i1 %cond to i8 |
| call void @use.i8(i8 %cond.splat) |
| %sub = add i8 %cond.splat, %x |
| %xor = xor i8 %sub, %cond.splat |
| ret i8 %xor |
| } |
| define i8 @extrause10_v1(i8 %x, i1 %cond) { |
| ; CHECK-LABEL: @extrause10_v1( |
| ; CHECK-NEXT: [[COND_SPLAT:%.*]] = sext i1 [[COND:%.*]] to i8 |
| ; CHECK-NEXT: [[SUB:%.*]] = add i8 [[COND_SPLAT]], [[X:%.*]] |
| ; CHECK-NEXT: call void @use.i8(i8 [[SUB]]) |
| ; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[SUB]], [[COND_SPLAT]] |
| ; CHECK-NEXT: ret i8 [[XOR]] |
| ; |
| %cond.splat = sext i1 %cond to i8 |
| %sub = add i8 %cond.splat, %x |
| call void @use.i8(i8 %sub) |
| %xor = xor i8 %sub, %cond.splat |
| ret i8 %xor |
| } |
| define i8 @extrause11_v1(i8 %x, i1 %cond) { |
| ; CHECK-LABEL: @extrause11_v1( |
| ; CHECK-NEXT: [[COND_SPLAT:%.*]] = sext i1 [[COND:%.*]] to i8 |
| ; CHECK-NEXT: call void @use.i8(i8 [[COND_SPLAT]]) |
| ; CHECK-NEXT: [[SUB:%.*]] = add i8 [[COND_SPLAT]], [[X:%.*]] |
| ; CHECK-NEXT: call void @use.i8(i8 [[SUB]]) |
| ; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[SUB]], [[COND_SPLAT]] |
| ; CHECK-NEXT: ret i8 [[XOR]] |
| ; |
| %cond.splat = sext i1 %cond to i8 |
| call void @use.i8(i8 %cond.splat) |
| %sub = add i8 %cond.splat, %x |
| call void @use.i8(i8 %sub) |
| %xor = xor i8 %sub, %cond.splat |
| ret i8 %xor |
| } |
| |
| ; Extra use tests with two extensions |
| define i8 @extrause001_v2(i8 %x, i1 %cond) { |
| ; CHECK-LABEL: @extrause001_v2( |
| ; CHECK-NEXT: [[COND_SPLAT0:%.*]] = sext i1 [[COND:%.*]] to i8 |
| ; CHECK-NEXT: call void @use.i8(i8 [[COND_SPLAT0]]) |
| ; CHECK-NEXT: [[X_NEG:%.*]] = sub i8 0, [[X:%.*]] |
| ; CHECK-NEXT: [[XOR:%.*]] = select i1 [[COND]], i8 [[X_NEG]], i8 [[X]] |
| ; CHECK-NEXT: ret i8 [[XOR]] |
| ; |
| %cond.splat0 = sext i1 %cond to i8 |
| call void @use.i8(i8 %cond.splat0) |
| %cond.splat1 = sext i1 %cond to i8 |
| %sub = add i8 %cond.splat0, %x |
| %xor = xor i8 %sub, %cond.splat1 |
| ret i8 %xor |
| } |
| define i8 @extrause010_v2(i8 %x, i1 %cond) { |
| ; CHECK-LABEL: @extrause010_v2( |
| ; CHECK-NEXT: [[COND_SPLAT1:%.*]] = sext i1 [[COND:%.*]] to i8 |
| ; CHECK-NEXT: call void @use.i8(i8 [[COND_SPLAT1]]) |
| ; CHECK-NEXT: [[X_NEG:%.*]] = sub i8 0, [[X:%.*]] |
| ; CHECK-NEXT: [[XOR:%.*]] = select i1 [[COND]], i8 [[X_NEG]], i8 [[X]] |
| ; CHECK-NEXT: ret i8 [[XOR]] |
| ; |
| %cond.splat0 = sext i1 %cond to i8 |
| %cond.splat1 = sext i1 %cond to i8 |
| call void @use.i8(i8 %cond.splat1) |
| %sub = add i8 %cond.splat0, %x |
| %xor = xor i8 %sub, %cond.splat1 |
| ret i8 %xor |
| } |
| define i8 @extrause011_v2(i8 %x, i1 %cond) { |
| ; CHECK-LABEL: @extrause011_v2( |
| ; CHECK-NEXT: [[COND_SPLAT0:%.*]] = sext i1 [[COND:%.*]] to i8 |
| ; CHECK-NEXT: call void @use.i8(i8 [[COND_SPLAT0]]) |
| ; CHECK-NEXT: [[COND_SPLAT1:%.*]] = sext i1 [[COND]] to i8 |
| ; CHECK-NEXT: call void @use.i8(i8 [[COND_SPLAT1]]) |
| ; CHECK-NEXT: [[X_NEG:%.*]] = sub i8 0, [[X:%.*]] |
| ; CHECK-NEXT: [[XOR:%.*]] = select i1 [[COND]], i8 [[X_NEG]], i8 [[X]] |
| ; CHECK-NEXT: ret i8 [[XOR]] |
| ; |
| %cond.splat0 = sext i1 %cond to i8 |
| call void @use.i8(i8 %cond.splat0) |
| %cond.splat1 = sext i1 %cond to i8 |
| call void @use.i8(i8 %cond.splat1) |
| %sub = add i8 %cond.splat0, %x |
| %xor = xor i8 %sub, %cond.splat1 |
| ret i8 %xor |
| } |
| define i8 @extrause100_v2(i8 %x, i1 %cond) { |
| ; CHECK-LABEL: @extrause100_v2( |
| ; CHECK-NEXT: [[COND_SPLAT0:%.*]] = sext i1 [[COND:%.*]] to i8 |
| ; CHECK-NEXT: [[SUB:%.*]] = add i8 [[COND_SPLAT0]], [[X:%.*]] |
| ; CHECK-NEXT: call void @use.i8(i8 [[SUB]]) |
| ; CHECK-NEXT: [[X_NEG:%.*]] = sub i8 0, [[X]] |
| ; CHECK-NEXT: [[XOR:%.*]] = select i1 [[COND]], i8 [[X_NEG]], i8 [[X]] |
| ; CHECK-NEXT: ret i8 [[XOR]] |
| ; |
| %cond.splat0 = sext i1 %cond to i8 |
| %cond.splat1 = sext i1 %cond to i8 |
| %sub = add i8 %cond.splat0, %x |
| call void @use.i8(i8 %sub) |
| %xor = xor i8 %sub, %cond.splat1 |
| ret i8 %xor |
| } |
| define i8 @extrause101_v2(i8 %x, i1 %cond) { |
| ; CHECK-LABEL: @extrause101_v2( |
| ; CHECK-NEXT: [[COND_SPLAT0:%.*]] = sext i1 [[COND:%.*]] to i8 |
| ; CHECK-NEXT: call void @use.i8(i8 [[COND_SPLAT0]]) |
| ; CHECK-NEXT: [[SUB:%.*]] = add i8 [[COND_SPLAT0]], [[X:%.*]] |
| ; CHECK-NEXT: call void @use.i8(i8 [[SUB]]) |
| ; CHECK-NEXT: [[X_NEG:%.*]] = sub i8 0, [[X]] |
| ; CHECK-NEXT: [[XOR:%.*]] = select i1 [[COND]], i8 [[X_NEG]], i8 [[X]] |
| ; CHECK-NEXT: ret i8 [[XOR]] |
| ; |
| %cond.splat0 = sext i1 %cond to i8 |
| call void @use.i8(i8 %cond.splat0) |
| %cond.splat1 = sext i1 %cond to i8 |
| %sub = add i8 %cond.splat0, %x |
| call void @use.i8(i8 %sub) |
| %xor = xor i8 %sub, %cond.splat1 |
| ret i8 %xor |
| } |
| define i8 @extrause110_v2(i8 %x, i1 %cond) { |
| ; CHECK-LABEL: @extrause110_v2( |
| ; CHECK-NEXT: [[COND_SPLAT0:%.*]] = sext i1 [[COND:%.*]] to i8 |
| ; CHECK-NEXT: [[COND_SPLAT1:%.*]] = sext i1 [[COND]] to i8 |
| ; CHECK-NEXT: call void @use.i8(i8 [[COND_SPLAT1]]) |
| ; CHECK-NEXT: [[SUB:%.*]] = add i8 [[COND_SPLAT0]], [[X:%.*]] |
| ; CHECK-NEXT: call void @use.i8(i8 [[SUB]]) |
| ; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[SUB]], [[COND_SPLAT1]] |
| ; CHECK-NEXT: ret i8 [[XOR]] |
| ; |
| %cond.splat0 = sext i1 %cond to i8 |
| %cond.splat1 = sext i1 %cond to i8 |
| call void @use.i8(i8 %cond.splat1) |
| %sub = add i8 %cond.splat0, %x |
| call void @use.i8(i8 %sub) |
| %xor = xor i8 %sub, %cond.splat1 |
| ret i8 %xor |
| } |
| define i8 @extrause111_v2(i8 %x, i1 %cond) { |
| ; CHECK-LABEL: @extrause111_v2( |
| ; CHECK-NEXT: [[COND_SPLAT0:%.*]] = sext i1 [[COND:%.*]] to i8 |
| ; CHECK-NEXT: call void @use.i8(i8 [[COND_SPLAT0]]) |
| ; CHECK-NEXT: [[COND_SPLAT1:%.*]] = sext i1 [[COND]] to i8 |
| ; CHECK-NEXT: call void @use.i8(i8 [[COND_SPLAT1]]) |
| ; CHECK-NEXT: [[SUB:%.*]] = add i8 [[COND_SPLAT0]], [[X:%.*]] |
| ; CHECK-NEXT: call void @use.i8(i8 [[SUB]]) |
| ; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[SUB]], [[COND_SPLAT1]] |
| ; CHECK-NEXT: ret i8 [[XOR]] |
| ; |
| %cond.splat0 = sext i1 %cond to i8 |
| call void @use.i8(i8 %cond.splat0) |
| %cond.splat1 = sext i1 %cond to i8 |
| call void @use.i8(i8 %cond.splat1) |
| %sub = add i8 %cond.splat0, %x |
| call void @use.i8(i8 %sub) |
| %xor = xor i8 %sub, %cond.splat1 |
| ret i8 %xor |
| } |
| |
| declare void @use.i8(i8) |
| declare i8 @gen.i8() |