Index: include/llvm/Analysis/MustExecute.h =================================================================== --- include/llvm/Analysis/MustExecute.h +++ include/llvm/Analysis/MustExecute.h @@ -39,7 +39,10 @@ struct LoopSafetyInfo { bool MayThrow = false; // The current loop contains an instruction which // may throw. - bool HeaderMayThrow = false; // Same as previous, but specific to loop header + /// This set keeps information about all the header instructions that are not + /// dominated by any instruction that may throw. This guarantees that they + /// will be executed when the loop executes. + SmallPtrSet GuaranteeToExecuteHeaderInstructions; // Used to update funclet bundle operands. DenseMap BlockColors; Index: lib/Analysis/MustExecute.cpp =================================================================== --- lib/Analysis/MustExecute.cpp +++ lib/Analysis/MustExecute.cpp @@ -30,12 +30,16 @@ BasicBlock *Header = CurLoop->getHeader(); // Setting default safety values. SafetyInfo->MayThrow = false; - SafetyInfo->HeaderMayThrow = false; + // Iterate over header and compute safety info. - SafetyInfo->HeaderMayThrow = - !isGuaranteedToTransferExecutionToSuccessor(Header); + for (const auto &I : *CurLoop->getHeader()) { + if (!isGuaranteedToTransferExecutionToSuccessor(&I)) { + SafetyInfo->MayThrow = true; + break; + } + SafetyInfo->GuaranteeToExecuteHeaderInstructions.insert(&I); + } - SafetyInfo->MayThrow = SafetyInfo->HeaderMayThrow; // Iterate over loop instructions and compute safety info. // Skip header as it has been computed and stored in HeaderMayThrow. // The first block in loopinfo.Blocks is guaranteed to be the header. @@ -107,10 +111,9 @@ // If the instruction is in the header block for the loop (which is very // common), it is always guaranteed to dominate the exit blocks. Since this // is a common case, and can save some work, check it now. - if (Inst.getParent() == CurLoop->getHeader()) - // If there's a throw in the header block, we can't guarantee we'll reach - // Inst. - return !SafetyInfo->HeaderMayThrow; + if (Inst.getParent() == CurLoop->getHeader()) { + return SafetyInfo->GuaranteeToExecuteHeaderInstructions.count(&Inst); + } // Somewhere in this loop there is an instruction which may throw and make us // exit the loop. Index: test/Transforms/LICM/hoist-invariant-load.ll =================================================================== --- test/Transforms/LICM/hoist-invariant-load.ll +++ test/Transforms/LICM/hoist-invariant-load.ll @@ -1,24 +1,25 @@ ; REQUIRES: asserts -; RUN: opt < %s -licm -disable-basicaa -stats -S 2>&1 | grep "1 licm" +; RUN: opt < %s -licm -disable-basicaa -stats -S 2>&1 | grep "2 licm" +; RUN: opt < %s -licm -disable-basicaa -S | FileCheck %s @"\01L_OBJC_METH_VAR_NAME_" = internal global [4 x i8] c"foo\00", section "__TEXT,__objc_methname,cstring_literals", align 1 @"\01L_OBJC_SELECTOR_REFERENCES_" = internal global i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"\01L_OBJC_METH_VAR_NAME_", i32 0, i32 0), section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip" @"\01L_OBJC_IMAGE_INFO" = internal constant [2 x i32] [i32 0, i32 16], section "__DATA, __objc_imageinfo, regular, no_dead_strip" @llvm.used = appending global [3 x i8*] [i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"\01L_OBJC_METH_VAR_NAME_", i32 0, i32 0), i8* bitcast (i8** @"\01L_OBJC_SELECTOR_REFERENCES_" to i8*), i8* bitcast ([2 x i32]* @"\01L_OBJC_IMAGE_INFO" to i8*)], section "llvm.metadata" - +; CHECK-LABEL: define void @test( define void @test(i8* %x) uwtable ssp { entry: %x.addr = alloca i8*, align 8 %i = alloca i32, align 4 store i8* %x, i8** %x.addr, align 8 store i32 0, i32* %i, align 4 +; CHECK: load i8*, i8** @"\01L_OBJC_SELECTOR_REFERENCES_"{{$}} br label %for.cond - +; CHECK: for.cond: for.cond: ; preds = %for.inc, %entry %0 = load i32, i32* %i, align 4 %cmp = icmp ult i32 %0, 10000 br i1 %cmp, label %for.body, label %for.end - for.body: ; preds = %for.cond %1 = load i8*, i8** %x.addr, align 8 %2 = load i8*, i8** @"\01L_OBJC_SELECTOR_REFERENCES_", !invariant.load !0 @@ -35,6 +36,33 @@ ret void } +; This test checks if we keep !invariant.load metadata on the instruction after +; hoisting. +; CHECK-LABEL: @keep_metadata( +define void @keep_metadata(i8** dereferenceable(8) %arg) { +entry: + + br i1 undef, label %while.end, label %while.body.lr.ph +; CHECK: while.body.lr.ph: +while.body.lr.ph: ; preds = %entry +; CHECK: load i8*, i8** %{{...}}, align 8, !invariant.load + br label %while.body +; CHECK: while.body: +while.body: ; preds = %while.body, %while.body.lr.ph + + %x = load i8*, i8** %arg, align 8, !invariant.load !0 + call void @foo(i8* %x) + + br i1 undef, label %while.end.loopexit, label %while.body + +while.end.loopexit: ; preds = %while.body + br label %while.end + +while.end: ; preds = %while.end.loopexit, %entry + ret void +} + declare i8* @objc_msgSend(i8*, i8*, ...) nonlazybind +declare void @foo(i8*) !0 = !{} Index: test/Transforms/LICM/preheader-safe.ll =================================================================== --- test/Transforms/LICM/preheader-safe.ll +++ test/Transforms/LICM/preheader-safe.ll @@ -21,16 +21,32 @@ call void @use_nothrow(i64 %div) br label %loop } -; Negative test -define void @throw_header(i64 %x, i64 %y, i1* %cond) { + +define void @throw_header_after(i64 %x, i64 %y, i1* %cond) { +; CHECK-LABEL: throw_header_after +; CHECK: %div = udiv i64 %x, %y +; CHECK-LABEL: loop +; CHECK: call void @use(i64 %div) +entry: + br label %loop + +loop: ; preds = %entry, %for.inc + %div = udiv i64 %x, %y + call void @use(i64 %div) + br label %loop +} + +define void @throw_header_before(i64 %x, i64 %y, i1* %cond) { ; CHECK-LABEL: throw_header ; CHECK-LABEL: loop +; CHECK: call void @use(i64 0) ; CHECK: %div = udiv i64 %x, %y ; CHECK: call void @use(i64 %div) entry: br label %loop loop: ; preds = %entry, %for.inc + call void @use(i64 0) ; this may throw %div = udiv i64 %x, %y call void @use(i64 %div) br label %loop