Index: llvm/lib/Analysis/StackLifetime.cpp =================================================================== --- llvm/lib/Analysis/StackLifetime.cpp +++ llvm/lib/Analysis/StackLifetime.cpp @@ -85,8 +85,8 @@ while (!WorkList.empty()) { const Instruction *I = WorkList.pop_back_val(); for (const User *U : I->users()) { - if (auto *BI = dyn_cast(U)) { - WorkList.push_back(BI); + if (U->stripPointerCasts() == AI) { + WorkList.push_back(cast(U)); continue; } auto *UI = dyn_cast(U); Index: llvm/unittests/Analysis/CMakeLists.txt =================================================================== --- llvm/unittests/Analysis/CMakeLists.txt +++ llvm/unittests/Analysis/CMakeLists.txt @@ -40,6 +40,7 @@ ScalarEvolutionTest.cpp VectorFunctionABITest.cpp SparsePropagation.cpp + StackLifetimeTest.cpp TargetLibraryInfoTest.cpp TBAATest.cpp UnrollAnalyzerTest.cpp Index: llvm/unittests/Analysis/StackLifetimeTest.cpp =================================================================== --- /dev/null +++ llvm/unittests/Analysis/StackLifetimeTest.cpp @@ -0,0 +1,82 @@ +//===- LoadsTest.cpp - StackLifetime unit tests ---------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/StackLifetime.h" +#include "llvm/AsmParser/Parser.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/SourceMgr.h" +#include "gtest/gtest.h" + +using namespace llvm; + +static std::unique_ptr parseIR(LLVMContext &C, const char *IR) { + SMDiagnostic Err; + std::unique_ptr Mod = parseAssemblyString(IR, Err, C); + if (!Mod) + Err.print("AnalysisTests", errs()); + return Mod; +} + +TEST(StackLifetimeTest, TestsForAnalysisForArrayOfInt8Type) { + LLVMContext C; + std::unique_ptr M = parseIR(C, + R"IR( +%struct.char_array = type { [500 x i8] } + +; Function Attrs: nounwind uwtable +define dso_local void @foo(i32 %cond) local_unnamed_addr #0 { +entry: + %a = alloca %struct.char_array, align 8 + %b = alloca %struct.char_array, align 8 + %tobool.not = icmp eq i32 %cond, 0 + br i1 %tobool.not, label %if.else, label %if.then + +if.then: ; preds = %entry + %0 = getelementptr inbounds %struct.char_array, %struct.char_array* %a, i64 0, i32 0, i64 0 + call void @llvm.lifetime.start.p0i8(i64 500, i8* nonnull %0) #3 + tail call void @consume(%struct.char_array* nonnull byval(%struct.char_array) align 8 %a) #3 + call void @llvm.lifetime.end.p0i8(i64 500, i8* nonnull %0) #3 + br label %if.end + +if.else: ; preds = %entry + %1 = getelementptr inbounds %struct.char_array, %struct.char_array* %b, i64 0, i32 0, i64 0 + call void @llvm.lifetime.start.p0i8(i64 500, i8* nonnull %1) #3 + tail call void @consume(%struct.char_array* nonnull byval(%struct.char_array) align 8 %b) #3 + call void @llvm.lifetime.end.p0i8(i64 500, i8* nonnull %1) #3 + br label %if.end + +if.end: ; preds = %if.else, %if.then + ret void +} + +declare dso_local void @consume(%struct.char_array* byval(%struct.char_array) align 8) local_unnamed_addr #2 +; Function Attrs: argmemonly nounwind willreturn +declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1 +; Function Attrs: argmemonly nounwind willreturn +declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1 +)IR"); + auto *GV = M->getNamedValue("foo"); + ASSERT_TRUE(GV); + auto *F = dyn_cast(GV); + ASSERT_TRUE(F); + + SmallVector Allocas; + for (auto &I : instructions(F)) + if (const AllocaInst *AI = dyn_cast(&I)) + Allocas.push_back(AI); + + StackLifetime SL(*F, Allocas, StackLifetime::LivenessType::Must); + SL.run(); + ASSERT_TRUE(Allocas.size() == 2); + ASSERT_FALSE(SL.getLiveRange(Allocas[0]).overlaps( + SL.getLiveRange(Allocas[1]) + )); +} \ No newline at end of file