; 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()