llvm/llvm/test/Transforms/SimplifyCFG/HoistCode.ll

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -passes=simplifycfg -hoist-common-insts=true -S | FileCheck %s
; RUN: opt < %s -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -hoist-common-insts=true -S | FileCheck %s

define void @foo(i1 %C, ptr %P) {
; CHECK-LABEL: @foo(
; CHECK-NEXT:  common.ret:
; CHECK-NEXT:    store i32 7, ptr [[P:%.*]], align 4
; CHECK-NEXT:    ret void
;
  br i1 %C, label %T, label %F
T:              ; preds = %0
  store i32 7, ptr %P
  ret void
F:              ; preds = %0
  store i32 7, ptr %P
  ret void
}

define void @foo_switch(i64 %C, ptr %P) {
; CHECK-LABEL: @foo_switch(
; CHECK-NEXT:  common.ret:
; CHECK-NEXT:    store i32 7, ptr [[P:%.*]], align 4
; CHECK-NEXT:    ret void
;
  switch i64 %C, label %bb0 [
  i64 1, label %bb1
  i64 2, label %bb2
  ]
bb0:              ; preds = %0
  store i32 7, ptr %P
  ret void
bb1:              ; preds = %0
  store i32 7, ptr %P
  ret void
bb2:              ; preds = %0
  store i32 7, ptr %P
  ret void
}

define float @PR39535min(float %x) {
; CHECK-LABEL: @PR39535min(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[TOBOOL:%.*]] = fcmp une float [[X:%.*]], 0.000000e+00
; CHECK-NEXT:    [[DOTX:%.*]] = select fast i1 [[TOBOOL]], float 0.000000e+00, float [[X]]
; CHECK-NEXT:    ret float [[DOTX]]
;
entry:
  %tobool = fcmp une float %x, 0.0
  br i1 %tobool, label %cond.true, label %cond.false

cond.true:
  br label %cond.end

cond.false:
  br label %cond.end

cond.end:
  %cond = phi fast float [ 0.0, %cond.true ], [ %x, %cond.false ]
  ret float %cond
}

define float @PR39535min_switch(i64 %i, float %x) {
; CHECK-LABEL: @PR39535min_switch(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    switch i64 [[I:%.*]], label [[END:%.*]] [
; CHECK-NEXT:      i64 1, label [[BB1:%.*]]
; CHECK-NEXT:      i64 2, label [[BB2:%.*]]
; CHECK-NEXT:    ]
; CHECK:       bb1:
; CHECK-NEXT:    br label [[END]]
; CHECK:       bb2:
; CHECK-NEXT:    br label [[END]]
; CHECK:       end:
; CHECK-NEXT:    [[COND:%.*]] = phi fast float [ [[X:%.*]], [[BB1]] ], [ [[X]], [[BB2]] ], [ 0.000000e+00, [[ENTRY:%.*]] ]
; CHECK-NEXT:    ret float [[COND]]
;
entry:
  switch i64 %i, label %bb0 [
  i64 1, label %bb1
  i64 2, label %bb2
  ]

bb0:
  br label %end

bb1:
  br label %end

bb2:
  br label %end

end:
  %cond = phi fast float [ 0.0, %bb0 ], [ %x, %bb1 ], [ %x, %bb2 ]
  ret float %cond
}

define i32 @hoist_zext_flags_preserve(i1 %C, i8 %x) {
; CHECK-LABEL: @hoist_zext_flags_preserve(
; CHECK-NEXT:  common.ret:
; CHECK-NEXT:    [[Z1:%.*]] = zext nneg i8 [[X:%.*]] to i32
; CHECK-NEXT:    ret i32 [[Z1]]
;
  br i1 %C, label %T, label %F
T:
  %z1 = zext nneg i8 %x to i32
  ret i32 %z1
F:
  %z2 = zext nneg i8 %x to i32
  ret i32 %z2
}

define i32 @hoist_zext_flags_drop(i1 %C, i8 %x) {
; CHECK-LABEL: @hoist_zext_flags_drop(
; CHECK-NEXT:  common.ret:
; CHECK-NEXT:    [[Z1:%.*]] = zext i8 [[X:%.*]] to i32
; CHECK-NEXT:    ret i32 [[Z1]]
;
  br i1 %C, label %T, label %F
T:
  %z1 = zext nneg i8 %x to i32
  ret i32 %z1
F:
  %z2 = zext i8 %x to i32
  ret i32 %z2
}


define float @hoist_uitofp_flags_preserve(i1 %C, i8 %x) {
; CHECK-LABEL: @hoist_uitofp_flags_preserve(
; CHECK-NEXT:  common.ret:
; CHECK-NEXT:    [[Z1:%.*]] = uitofp nneg i8 [[X:%.*]] to float
; CHECK-NEXT:    ret float [[Z1]]
;
  br i1 %C, label %T, label %F
T:
  %z1 = uitofp nneg i8 %x to float
  ret float %z1
F:
  %z2 = uitofp nneg i8 %x to float
  ret float %z2
}

define float @hoist_uitofp_flags_drop(i1 %C, i8 %x) {
; CHECK-LABEL: @hoist_uitofp_flags_drop(
; CHECK-NEXT:  common.ret:
; CHECK-NEXT:    [[Z1:%.*]] = uitofp i8 [[X:%.*]] to float
; CHECK-NEXT:    ret float [[Z1]]
;
  br i1 %C, label %T, label %F
T:
  %z1 = uitofp nneg i8 %x to float
  ret float %z1
F:
  %z2 = uitofp i8 %x to float
  ret float %z2
}

define i32 @hoist_or_flags_preserve(i1 %C, i32 %x, i32 %y) {
; CHECK-LABEL: @hoist_or_flags_preserve(
; CHECK-NEXT:  common.ret:
; CHECK-NEXT:    [[Z1:%.*]] = or disjoint i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT:    ret i32 [[Z1]]
;
  br i1 %C, label %T, label %F
T:
  %z1 = or disjoint i32 %x, %y
  ret i32 %z1
F:
  %z2 = or disjoint i32 %x, %y
  ret i32 %z2
}

define i32 @hoist_or_flags_drop(i1 %C, i32 %x, i32 %y) {
; CHECK-LABEL: @hoist_or_flags_drop(
; CHECK-NEXT:  common.ret:
; CHECK-NEXT:    [[Z1:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT:    ret i32 [[Z1]]
;
  br i1 %C, label %T, label %F
T:
  %z1 = or i32 %x, %y
  ret i32 %z1
F:
  %z2 = or disjoint i32 %x, %y
  ret i32 %z2
}

define i16 @hoist_trunc_flags_preserve(i1 %C, i32 %x) {
; CHECK-LABEL: @hoist_trunc_flags_preserve(
; CHECK-NEXT:  common.ret:
; CHECK-NEXT:    [[Z1:%.*]] = trunc nuw nsw i32 [[X:%.*]] to i16
; CHECK-NEXT:    ret i16 [[Z1]]
;
  br i1 %C, label %T, label %F
T:
  %z1 = trunc nsw nuw i32 %x to i16
  ret i16 %z1
F:
  %z2 = trunc nsw nuw i32 %x to i16
  ret i16 %z2
}

define i16 @hoist_trunc_flags_drop(i1 %C, i32 %x) {
; CHECK-LABEL: @hoist_trunc_flags_drop(
; CHECK-NEXT:  common.ret:
; CHECK-NEXT:    [[Z1:%.*]] = trunc i32 [[X:%.*]] to i16
; CHECK-NEXT:    ret i16 [[Z1]]
;
  br i1 %C, label %T, label %F
T:
  %z1 = trunc i32 %x to i16
  ret i16 %z1
F:
  %z2 = trunc nsw nuw i32 %x to i16
  ret i16 %z2
}

define ptr @hoist_gep_flags_both_nuw(i1 %C, ptr %p) {
; CHECK-LABEL: @hoist_gep_flags_both_nuw(
; CHECK-NEXT:  common.ret:
; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr nuw i8, ptr [[P:%.*]], i64 1
; CHECK-NEXT:    ret ptr [[GEP1]]
;
  br i1 %C, label %T, label %F
T:
  %gep1 = getelementptr nuw i8, ptr %p, i64 1
  ret ptr %gep1
F:
  %gep2 = getelementptr nuw i8, ptr %p, i64 1
  ret ptr %gep2
}

define ptr @hoist_gep_flags_both_nusw(i1 %C, ptr %p) {
; CHECK-LABEL: @hoist_gep_flags_both_nusw(
; CHECK-NEXT:  common.ret:
; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr nusw i8, ptr [[P:%.*]], i64 1
; CHECK-NEXT:    ret ptr [[GEP1]]
;
  br i1 %C, label %T, label %F
T:
  %gep1 = getelementptr nusw i8, ptr %p, i64 1
  ret ptr %gep1
F:
  %gep2 = getelementptr nusw i8, ptr %p, i64 1
  ret ptr %gep2
}

define ptr @hoist_gep_flags_intersect1(i1 %C, ptr %p) {
; CHECK-LABEL: @hoist_gep_flags_intersect1(
; CHECK-NEXT:  common.ret:
; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr nusw i8, ptr [[P:%.*]], i64 1
; CHECK-NEXT:    ret ptr [[GEP1]]
;
  br i1 %C, label %T, label %F
T:
  %gep1 = getelementptr inbounds nuw i8, ptr %p, i64 1
  ret ptr %gep1
F:
  %gep2 = getelementptr nusw i8, ptr %p, i64 1
  ret ptr %gep2
}

define ptr @hoist_gep_flags_intersect2(i1 %C, ptr %p) {
; CHECK-LABEL: @hoist_gep_flags_intersect2(
; CHECK-NEXT:  common.ret:
; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 1
; CHECK-NEXT:    ret ptr [[GEP1]]
;
  br i1 %C, label %T, label %F
T:
  %gep1 = getelementptr inbounds i8, ptr %p, i64 1
  ret ptr %gep1
F:
  %gep2 = getelementptr nuw i8, ptr %p, i64 1
  ret ptr %gep2
}