; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 ; RUN: opt -aa-pipeline=basic-aa -passes='require,loop-mssa(licm)' -S %s | FileCheck %s ; RUN: opt -S -passes=licm -verify-memoryssa < %s | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" declare void @f() nounwind ; Don't hoist load past nounwind call. define i32 @test1(ptr noalias nocapture readonly %a) nounwind uwtable { ; CHECK-LABEL: define i32 @test1( ; CHECK-SAME: ptr noalias readonly captures(none) [[A:%.*]]) #[[ATTR1:[0-9]+]] { ; CHECK-NEXT: [[ENTRY:.*]]: ; CHECK-NEXT: br label %[[FOR_BODY:.*]] ; CHECK: [[FOR_BODY]]: ; CHECK-NEXT: [[I_06:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[INC:%.*]], %[[FOR_BODY]] ] ; CHECK-NEXT: [[X_05:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[ADD:%.*]], %[[FOR_BODY]] ] ; CHECK-NEXT: tail call void @f() #[[ATTR0:[0-9]+]] ; CHECK-NEXT: [[I1:%.*]] = load i32, ptr [[A]], align 4 ; CHECK-NEXT: [[ADD]] = add nsw i32 [[I1]], [[X_05]] ; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_06]], 1 ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC]], 1000 ; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FOR_COND_CLEANUP:.*]], label %[[FOR_BODY]] ; CHECK: [[FOR_COND_CLEANUP]]: ; CHECK-NEXT: [[ADD_LCSSA:%.*]] = phi i32 [ [[ADD]], %[[FOR_BODY]] ] ; CHECK-NEXT: ret i32 [[ADD_LCSSA]] ; entry: br label %for.body for.body: %i.06 = phi i32 [ 0, %entry ], [ %inc, %for.body ] %x.05 = phi i32 [ 0, %entry ], [ %add, %for.body ] tail call void @f() nounwind %i1 = load i32, ptr %a, align 4 %add = add nsw i32 %i1, %x.05 %inc = add nuw nsw i32 %i.06, 1 %exitcond = icmp eq i32 %inc, 1000 br i1 %exitcond, label %for.cond.cleanup, label %for.body for.cond.cleanup: ret i32 %add } ; Don't hoist division past nounwind call. define i32 @test2(i32 %N, i32 %c) nounwind uwtable { ; CHECK-LABEL: define i32 @test2( ; CHECK-SAME: i32 [[N:%.*]], i32 [[C:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[ENTRY:.*:]] ; CHECK-NEXT: [[CMP4:%.*]] = icmp sgt i32 [[N]], 0 ; CHECK-NEXT: br i1 [[CMP4]], label %[[FOR_BODY_PREHEADER:.*]], label %[[FOR_COND_CLEANUP:.*]] ; CHECK: [[FOR_BODY_PREHEADER]]: ; CHECK-NEXT: br label %[[FOR_BODY:.*]] ; CHECK: [[FOR_BODY]]: ; CHECK-NEXT: [[I_05:%.*]] = phi i32 [ [[INC:%.*]], %[[FOR_BODY]] ], [ 0, %[[FOR_BODY_PREHEADER]] ] ; CHECK-NEXT: tail call void @f() #[[ATTR0]] ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 5, [[C]] ; CHECK-NEXT: [[ADD:%.*]] = add i32 [[I_05]], 1 ; CHECK-NEXT: [[INC]] = add i32 [[ADD]], [[DIV]] ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[INC]], [[N]] ; CHECK-NEXT: br i1 [[CMP]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT:.*]] ; CHECK: [[FOR_COND_CLEANUP_LOOPEXIT]]: ; CHECK-NEXT: br label %[[FOR_COND_CLEANUP]] ; CHECK: [[FOR_COND_CLEANUP]]: ; CHECK-NEXT: ret i32 0 ; entry: %cmp4 = icmp sgt i32 %N, 0 br i1 %cmp4, label %for.body, label %for.cond.cleanup for.body: %i.05 = phi i32 [ %inc, %for.body ], [ 0, %entry ] tail call void @f() nounwind %div = sdiv i32 5, %c %add = add i32 %i.05, 1 %inc = add i32 %add, %div %cmp = icmp slt i32 %inc, %N br i1 %cmp, label %for.body, label %for.cond.cleanup for.cond.cleanup: ret i32 0 } ; Do not hoist a non-volatile load past volatile load, because it may trap. define i32 @test3(ptr noalias nocapture readonly %a, ptr %v) nounwind uwtable { ; CHECK-LABEL: define i32 @test3( ; CHECK-SAME: ptr noalias readonly captures(none) [[A:%.*]], ptr [[V:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[ENTRY:.*]]: ; CHECK-NEXT: br label %[[FOR_BODY:.*]] ; CHECK: [[FOR_BODY]]: ; CHECK-NEXT: [[I_06:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[INC:%.*]], %[[FOR_BODY]] ] ; CHECK-NEXT: [[X_05:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[ADD:%.*]], %[[FOR_BODY]] ] ; CHECK-NEXT: [[XXX:%.*]] = load volatile i32, ptr [[V]], align 4 ; CHECK-NEXT: [[I1:%.*]] = load i32, ptr [[A]], align 4 ; CHECK-NEXT: [[ADD]] = add nsw i32 [[I1]], [[X_05]] ; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_06]], 1 ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC]], 1000 ; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FOR_COND_CLEANUP:.*]], label %[[FOR_BODY]] ; CHECK: [[FOR_COND_CLEANUP]]: ; CHECK-NEXT: [[ADD_LCSSA:%.*]] = phi i32 [ [[ADD]], %[[FOR_BODY]] ] ; CHECK-NEXT: ret i32 [[ADD_LCSSA]] ; entry: br label %for.body for.body: %i.06 = phi i32 [ 0, %entry ], [ %inc, %for.body ] %x.05 = phi i32 [ 0, %entry ], [ %add, %for.body ] %xxx = load volatile i32, ptr %v, align 4 %i1 = load i32, ptr %a, align 4 %add = add nsw i32 %i1, %x.05 %inc = add nuw nsw i32 %i.06, 1 %exitcond = icmp eq i32 %inc, 1000 br i1 %exitcond, label %for.cond.cleanup, label %for.body for.cond.cleanup: ret i32 %add } ; Don't a volatile load past volatile load. define i32 @test4(ptr noalias nocapture readonly %a, ptr %v) nounwind uwtable { ; CHECK-LABEL: define i32 @test4( ; CHECK-SAME: ptr noalias readonly captures(none) [[A:%.*]], ptr [[V:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[ENTRY:.*]]: ; CHECK-NEXT: br label %[[FOR_BODY:.*]] ; CHECK: [[FOR_BODY]]: ; CHECK-NEXT: [[I_06:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[INC:%.*]], %[[FOR_BODY]] ] ; CHECK-NEXT: [[X_05:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[ADD:%.*]], %[[FOR_BODY]] ] ; CHECK-NEXT: [[XXX:%.*]] = load volatile i32, ptr [[V]], align 4 ; CHECK-NEXT: [[I1:%.*]] = load volatile i32, ptr [[A]], align 4 ; CHECK-NEXT: [[ADD]] = add nsw i32 [[I1]], [[X_05]] ; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_06]], 1 ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC]], 1000 ; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FOR_COND_CLEANUP:.*]], label %[[FOR_BODY]] ; CHECK: [[FOR_COND_CLEANUP]]: ; CHECK-NEXT: [[ADD_LCSSA:%.*]] = phi i32 [ [[ADD]], %[[FOR_BODY]] ] ; CHECK-NEXT: ret i32 [[ADD_LCSSA]] ; entry: br label %for.body for.body: %i.06 = phi i32 [ 0, %entry ], [ %inc, %for.body ] %x.05 = phi i32 [ 0, %entry ], [ %add, %for.body ] %xxx = load volatile i32, ptr %v, align 4 %i1 = load volatile i32, ptr %a, align 4 %add = add nsw i32 %i1, %x.05 %inc = add nuw nsw i32 %i.06, 1 %exitcond = icmp eq i32 %inc, 1000 br i1 %exitcond, label %for.cond.cleanup, label %for.body for.cond.cleanup: ret i32 %add }