llvm/llvm/test/Transforms/InstCombine/conditional-negation.ll

; 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 [[X:%.*]], [[COND_SPLAT0]]
; 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 [[X:%.*]], [[COND_SPLAT]]
; 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> [[X:%.*]], [[COND_SPLAT]]
; 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 [[X:%.*]], [[COND_SPLAT]]
; 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 [[X:%.*]], [[COND_SPLAT]]
; 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 [[X:%.*]], [[COND_SPLAT0]]
; 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 [[X:%.*]], [[COND_SPLAT0]]
; 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 [[X:%.*]], [[COND_SPLAT0]]
; 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 [[X:%.*]], [[COND_SPLAT0]]
; 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()