llvm/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
; RUN: opt -S -passes=instcombine < %s | FileCheck %s

define i1 @test1(float %x) {
; CHECK-LABEL: define i1 @test1(
; CHECK-SAME: float [[X:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[COND:%.*]] = fcmp ueq float [[X]], 0.000000e+00
; CHECK-NEXT:    br i1 [[COND]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    ret i1 false
; CHECK:       if.else:
; CHECK-NEXT:    [[RET:%.*]] = call i1 @llvm.is.fpclass.f32(float [[X]], i32 780)
; CHECK-NEXT:    ret i1 [[RET]]
;
entry:
  %cond = fcmp ueq float %x, 0.000000e+00
  br i1 %cond, label %if.then, label %if.else

if.then:
  ret i1 false

if.else:
  %ret = call i1 @llvm.is.fpclass.f32(float %x, i32 783)
  ret i1 %ret
}

define i1 @test2(double %x) {
; CHECK-LABEL: define i1 @test2(
; CHECK-SAME: double [[X:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP:%.*]] = fcmp olt double [[X]], 0x3EB0C6F7A0000000
; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    ret i1 false
; CHECK:       if.end:
; CHECK-NEXT:    ret i1 false
;
entry:
  %cmp = fcmp olt double %x, 0x3EB0C6F7A0000000
  br i1 %cmp, label %if.then, label %if.end
if.then:
  ret i1 false
if.end:
  %cmp.i = fcmp oeq double %x, 0.000000e+00
  ret i1 %cmp.i
}

define i1 @test3(float %x) {
; CHECK-LABEL: define i1 @test3(
; CHECK-SAME: float [[X:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP:%.*]] = fcmp ogt float [[X]], 3.000000e+00
; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    [[RET:%.*]] = fcmp oeq float [[X]], 0x7FF0000000000000
; CHECK-NEXT:    ret i1 [[RET]]
; CHECK:       if.else:
; CHECK-NEXT:    ret i1 false
;
entry:
  %cmp = fcmp ogt float %x, 3.000000e+00
  br i1 %cmp, label %if.then, label %if.else
if.then:
  %abs = call float @llvm.fabs.f32(float %x)
  %ret = fcmp oeq float %abs, 0x7FF0000000000000
  ret i1 %ret
if.else:
  ret i1 false
}

define float @test4(float %x) {
; CHECK-LABEL: define float @test4(
; CHECK-SAME: float [[X:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP:%.*]] = fcmp olt float [[X]], 0x3EB0C6F7A0000000
; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    ret float 1.000000e+00
; CHECK:       if.end:
; CHECK-NEXT:    [[DIV:%.*]] = fdiv float 1.000000e+00, [[X]]
; CHECK-NEXT:    ret float [[DIV]]
;
entry:
  %cmp = fcmp olt float %x, 0x3EB0C6F7A0000000
  br i1 %cmp, label %if.then, label %if.end

if.then:
  ret float 1.0

if.end:
  %cmp.i = fcmp oeq float %x, 0.000000e+00
  %div = fdiv float 1.000000e+00, %x
  %ret = select i1 %cmp.i, float 1.000000e+00, float %div
  ret float %ret
}

define i1 @test5(double %x, i1 %cond) {
; CHECK-LABEL: define i1 @test5(
; CHECK-SAME: double [[X:%.*]], i1 [[COND:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br i1 [[COND]], label [[IF:%.*]], label [[EXIT:%.*]]
; CHECK:       if:
; CHECK-NEXT:    [[CMP:%.*]] = fcmp uno double [[X]], 0.000000e+00
; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    ret i1 false
; CHECK:       if.end:
; CHECK-NEXT:    br label [[EXIT]]
; CHECK:       exit:
; CHECK-NEXT:    [[Y:%.*]] = phi double [ -1.000000e+00, [[ENTRY:%.*]] ], [ [[X]], [[IF_END]] ]
; CHECK-NEXT:    [[RET:%.*]] = tail call i1 @llvm.is.fpclass.f64(double [[Y]], i32 408)
; CHECK-NEXT:    ret i1 [[RET]]
;
entry:
  br i1 %cond, label %if, label %exit
if:
  %cmp = fcmp uno double %x, 0.000000e+00
  br i1 %cmp, label %if.then, label %if.end
if.then:
  ret i1 false
if.end:
  br label %exit
exit:
  %y = phi double [ -1.000000e+00, %entry ], [ %x, %if.end ]
  %ret = tail call i1 @llvm.is.fpclass.f64(double %y, i32 411)
  ret i1 %ret
}

define i1 @test6(double %x) {
; CHECK-LABEL: define i1 @test6(
; CHECK-SAME: double [[X:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP:%.*]] = fcmp ogt double [[X]], 0.000000e+00
; CHECK-NEXT:    br i1 [[CMP]], label [[LAND_RHS:%.*]], label [[LAND_END:%.*]]
; CHECK:       land.rhs:
; CHECK-NEXT:    [[CMP_I:%.*]] = fcmp oeq double [[X]], 0x7FF0000000000000
; CHECK-NEXT:    br label [[LAND_END]]
; CHECK:       land.end:
; CHECK-NEXT:    [[RET:%.*]] = phi i1 [ false, [[ENTRY:%.*]] ], [ [[CMP_I]], [[LAND_RHS]] ]
; CHECK-NEXT:    ret i1 [[RET]]
;
entry:
  %cmp = fcmp ogt double %x, 0.000000e+00
  br i1 %cmp, label %land.rhs, label %land.end

land.rhs:
  %abs = tail call double @llvm.fabs.f64(double %x)
  %and.i = bitcast double %abs to i64
  %cmp.i = icmp eq i64 %and.i, 9218868437227405312
  br label %land.end

land.end:
  %ret = phi i1 [ false, %entry ], [ %cmp.i, %land.rhs ]
  ret i1 %ret
}

define i1 @test7(float %x) {
; CHECK-LABEL: define i1 @test7(
; CHECK-SAME: float [[X:%.*]]) {
; CHECK-NEXT:    [[COND:%.*]] = call i1 @llvm.is.fpclass.f32(float [[X]], i32 345)
; CHECK-NEXT:    br i1 [[COND]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    [[RET1:%.*]] = call i1 @llvm.is.fpclass.f32(float [[X]], i32 328)
; CHECK-NEXT:    ret i1 [[RET1]]
; CHECK:       if.else:
; CHECK-NEXT:    [[RET2:%.*]] = call i1 @llvm.is.fpclass.f32(float [[X]], i32 128)
; CHECK-NEXT:    ret i1 [[RET2]]
;
  %cond = call i1 @llvm.is.fpclass.f32(float %x, i32 345)
  br i1 %cond, label %if.then, label %if.else
if.then:
  %ret1 = call i1 @llvm.is.fpclass.f32(float %x, i32 456)
  ret i1 %ret1
if.else:
  %ret2 = call i1 @llvm.is.fpclass.f32(float %x, i32 456)
  ret i1 %ret2
}

; TODO: These two is.fpclass can be simplified.
define i1 @test8(float %x) {
; CHECK-LABEL: define i1 @test8(
; CHECK-SAME: float [[X:%.*]]) {
; CHECK-NEXT:    [[ABS:%.*]] = call float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT:    [[COND:%.*]] = fcmp oeq float [[ABS]], 0x7FF0000000000000
; CHECK-NEXT:    br i1 [[COND]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    ret i1 true
; CHECK:       if.else:
; CHECK-NEXT:    [[RET2:%.*]] = call i1 @llvm.is.fpclass.f32(float [[X]], i32 59)
; CHECK-NEXT:    ret i1 [[RET2]]
;
  %abs = call float @llvm.fabs.f32(float %x)
  %cond = fcmp oeq float %abs, 0x7FF0000000000000
  br i1 %cond, label %if.then, label %if.else
if.then:
  %ret1 = call i1 @llvm.is.fpclass.f32(float %x, i32 575)
  ret i1 %ret1
if.else:
  %ret2 = call i1 @llvm.is.fpclass.f32(float %x, i32 575)
  ret i1 %ret2
}

define i1 @test9(float %x) {
; CHECK-LABEL: define i1 @test9(
; CHECK-SAME: float [[X:%.*]]) {
; CHECK-NEXT:    [[COND:%.*]] = fcmp olt float [[X]], -1.000000e+00
; CHECK-NEXT:    br i1 [[COND]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    ret i1 false
; CHECK:       if.else:
; CHECK-NEXT:    ret i1 false
;
  %cond = fcmp olt float %x, -1.0
  br i1 %cond, label %if.then, label %if.else
if.then:
  %ret1 = fcmp oeq float %x, 0x7FF0000000000000
  ret i1 %ret1
if.else:
  ret i1 false
}

define i1 @test10(float %x) {
; CHECK-LABEL: define i1 @test10(
; CHECK-SAME: float [[X:%.*]]) {
; CHECK-NEXT:    [[COND:%.*]] = fcmp olt float [[X]], -1.000000e+00
; CHECK-NEXT:    br i1 [[COND]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    ret i1 false
; CHECK:       if.else:
; CHECK-NEXT:    ret i1 false
;
  %cond = fcmp olt float %x, -1.0
  %neg = fneg float %x
  br i1 %cond, label %if.then, label %if.else
if.then:
  %ret1 = fcmp oeq float %neg, 0xFFF0000000000000
  ret i1 %ret1
if.else:
  ret i1 false
}

; TODO: handle and/or conditions
define i1 @test11_and(float %x, i1 %cond2) {
; CHECK-LABEL: define i1 @test11_and(
; CHECK-SAME: float [[X:%.*]], i1 [[COND2:%.*]]) {
; CHECK-NEXT:    [[COND:%.*]] = fcmp olt float [[X]], -1.000000e+00
; CHECK-NEXT:    [[AND:%.*]] = and i1 [[COND]], [[COND2]]
; CHECK-NEXT:    br i1 [[AND]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    [[RET1:%.*]] = fcmp oeq float [[X]], 0x7FF0000000000000
; CHECK-NEXT:    ret i1 [[RET1]]
; CHECK:       if.else:
; CHECK-NEXT:    ret i1 false
;
  %cond = fcmp olt float %x, -1.0
  %neg = fneg float %x
  %and = and i1 %cond, %cond2
  br i1 %and, label %if.then, label %if.else
if.then:
  %ret1 = fcmp oeq float %neg, 0xFFF0000000000000
  ret i1 %ret1
if.else:
  ret i1 false
}

; TODO: handle and/or conditions
define i1 @test12_or(float %x, i1 %cond2) {
; CHECK-LABEL: define i1 @test12_or(
; CHECK-SAME: float [[X:%.*]], i1 [[COND2:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[COND:%.*]] = fcmp ueq float [[X]], 0.000000e+00
; CHECK-NEXT:    [[OR:%.*]] = or i1 [[COND]], [[COND2]]
; CHECK-NEXT:    br i1 [[OR]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    ret i1 false
; CHECK:       if.else:
; CHECK-NEXT:    [[RET:%.*]] = call i1 @llvm.is.fpclass.f32(float [[X]], i32 783)
; CHECK-NEXT:    ret i1 [[RET]]
;
entry:
  %cond = fcmp ueq float %x, 0.000000e+00
  %or = or i1 %cond, %cond2
  br i1 %or, label %if.then, label %if.else

if.then:
  ret i1 false

if.else:
  %ret = call i1 @llvm.is.fpclass.f32(float %x, i32 783)
  ret i1 %ret
}

define i1 @test1_no_dominating(float %x, i1 %c) {
; CHECK-LABEL: define i1 @test1_no_dominating(
; CHECK-SAME: float [[X:%.*]], i1 [[C:%.*]]) {
; CHECK-NEXT:  entry0:
; CHECK-NEXT:    br i1 [[C]], label [[ENTRY:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       entry:
; CHECK-NEXT:    [[COND:%.*]] = fcmp ueq float [[X]], 0.000000e+00
; CHECK-NEXT:    br i1 [[COND]], label [[IF_THEN:%.*]], label [[IF_ELSE]]
; CHECK:       if.then:
; CHECK-NEXT:    ret i1 false
; CHECK:       if.else:
; CHECK-NEXT:    [[RET:%.*]] = call i1 @llvm.is.fpclass.f32(float [[X]], i32 783)
; CHECK-NEXT:    ret i1 [[RET]]
;
entry0:
  br i1 %c, label %entry, label %if.else

entry:
  %cond = fcmp ueq float %x, 0.000000e+00
  br i1 %cond, label %if.then, label %if.else

if.then:
  ret i1 false

if.else:
  %ret = call i1 @llvm.is.fpclass.f32(float %x, i32 783)
  ret i1 %ret
}

define float @test_signbit_check(float %x, i1 %cond) {
; CHECK-LABEL: define float @test_signbit_check(
; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) {
; CHECK-NEXT:    [[I32:%.*]] = bitcast float [[X]] to i32
; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[I32]], 0
; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN1:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then1:
; CHECK-NEXT:    [[FNEG:%.*]] = fneg float [[X]]
; CHECK-NEXT:    br label [[IF_END:%.*]]
; CHECK:       if.else:
; CHECK-NEXT:    br i1 [[COND]], label [[IF_THEN2:%.*]], label [[IF_END]]
; CHECK:       if.then2:
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    [[VALUE:%.*]] = phi float [ [[FNEG]], [[IF_THEN1]] ], [ [[X]], [[IF_THEN2]] ], [ [[X]], [[IF_ELSE]] ]
; CHECK-NEXT:    ret float [[VALUE]]
;
  %i32 = bitcast float %x to i32
  %cmp = icmp slt i32 %i32, 0
  br i1 %cmp, label %if.then1, label %if.else

if.then1:
  %fneg = fneg float %x
  br label %if.end

if.else:
  br i1 %cond, label %if.then2, label %if.end

if.then2:
  br label %if.end

if.end:
  %value = phi float [ %fneg, %if.then1 ], [ %x, %if.then2 ], [ %x, %if.else ]
  %ret = call float @llvm.fabs.f32(float %value)
  ret float %ret
}

define float @test_signbit_check_fail(float %x, i1 %cond) {
; CHECK-LABEL: define float @test_signbit_check_fail(
; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) {
; CHECK-NEXT:    [[I32:%.*]] = bitcast float [[X]] to i32
; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[I32]], 0
; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN1:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then1:
; CHECK-NEXT:    [[FNEG:%.*]] = fneg float [[X]]
; CHECK-NEXT:    br label [[IF_END:%.*]]
; CHECK:       if.else:
; CHECK-NEXT:    br i1 [[COND]], label [[IF_THEN2:%.*]], label [[IF_END]]
; CHECK:       if.then2:
; CHECK-NEXT:    [[FNEG2:%.*]] = fneg float [[X]]
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    [[VALUE:%.*]] = phi float [ [[FNEG]], [[IF_THEN1]] ], [ [[FNEG2]], [[IF_THEN2]] ], [ [[X]], [[IF_ELSE]] ]
; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.fabs.f32(float [[VALUE]])
; CHECK-NEXT:    ret float [[RET]]
;
  %i32 = bitcast float %x to i32
  %cmp = icmp slt i32 %i32, 0
  br i1 %cmp, label %if.then1, label %if.else

if.then1:
  %fneg = fneg float %x
  br label %if.end

if.else:
  br i1 %cond, label %if.then2, label %if.end

if.then2:
  %fneg2 = fneg float %x
  br label %if.end

if.end:
  %value = phi float [ %fneg, %if.then1 ], [ %fneg2, %if.then2 ], [ %x, %if.else ]
  %ret = call float @llvm.fabs.f32(float %value)
  ret float %ret
}

define <2 x float> @test_signbit_check_wrong_type(<2 x float> %x, i1 %cond) {
; CHECK-LABEL: define <2 x float> @test_signbit_check_wrong_type(
; CHECK-SAME: <2 x float> [[X:%.*]], i1 [[COND:%.*]]) {
; CHECK-NEXT:    [[I32:%.*]] = bitcast <2 x float> [[X]] to i64
; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i64 [[I32]], 0
; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN1:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then1:
; CHECK-NEXT:    [[FNEG:%.*]] = fneg <2 x float> [[X]]
; CHECK-NEXT:    br label [[IF_END:%.*]]
; CHECK:       if.else:
; CHECK-NEXT:    br i1 [[COND]], label [[IF_THEN2:%.*]], label [[IF_END]]
; CHECK:       if.then2:
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    [[VALUE:%.*]] = phi <2 x float> [ [[FNEG]], [[IF_THEN1]] ], [ [[X]], [[IF_THEN2]] ], [ [[X]], [[IF_ELSE]] ]
; CHECK-NEXT:    [[RET:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> [[VALUE]])
; CHECK-NEXT:    ret <2 x float> [[RET]]
;
  %i32 = bitcast <2 x float> %x to i64
  %cmp = icmp slt i64 %i32, 0
  br i1 %cmp, label %if.then1, label %if.else

if.then1:
  %fneg = fneg <2 x float> %x
  br label %if.end

if.else:
  br i1 %cond, label %if.then2, label %if.end

if.then2:
  br label %if.end

if.end:
  %value = phi <2 x float> [ %fneg, %if.then1 ], [ %x, %if.then2 ], [ %x, %if.else ]
  %ret = call <2 x float> @llvm.fabs.v2f32(<2 x float> %value)
  ret <2 x float> %ret
}