diff --git a/llvm/lib/Analysis/MemoryBuiltins.cpp b/llvm/lib/Analysis/MemoryBuiltins.cpp --- a/llvm/lib/Analysis/MemoryBuiltins.cpp +++ b/llvm/lib/Analysis/MemoryBuiltins.cpp @@ -812,8 +812,32 @@ return unknown(); } -SizeOffsetType ObjectSizeOffsetVisitor::visitPHINode(PHINode&) { +SizeOffsetType ObjectSizeOffsetVisitor::visitPHINode(PHINode &PN) { // too complex to analyze statically. + SmallVector> Results; + for (Value *IV : PN.incoming_values()) { + SizeOffsetType SOT = compute(IV); + if (!bothKnown(SOT)) + return unknown(); + APInt Size = getSizeWithOverflow(SOT); + Results.push_back(std::make_pair(SOT, Size)); + } + + if (Options.EvalMode == ObjectSizeOpts::Mode::Min) { + return std::min_element(Results.begin(), Results.end(), + [](auto const &LHS, auto const &RHS) { + return LHS.second.slt(RHS.second); + }) + ->first; + } + if (Options.EvalMode == ObjectSizeOpts::Mode::Max) { + return std::max_element(Results.begin(), Results.end(), + [](auto const &LHS, auto const &RHS) { + return LHS.second.slt(RHS.second); + }) + ->first; + } + return unknown(); } diff --git a/llvm/test/Transforms/InstCombine/builtin-object-size-phi.ll b/llvm/test/Transforms/InstCombine/builtin-object-size-phi.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/builtin-object-size-phi.ll @@ -0,0 +1,46 @@ +; RUN: opt -O1 -S < %s | FileCheck %s + + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +declare dso_local noalias noundef i8* @malloc(i64 noundef) local_unnamed_addr +declare i64 @llvm.objectsize.i64.p0i8(i8*, i1 immarg, i1 immarg, i1 immarg) + +@buffer = dso_local global [4 x i8] zeroinitializer, align 1 + +define dso_local i64 @pick_max(i32 noundef %n) local_unnamed_addr { +; CHECK-LABEL: @pick_max( +; CHECK-NEXT: entry: +; CHECK-NEXT: ret i64 8 +entry: + %cond = icmp eq i32 %n, 0 + br i1 %cond, label %if.else, label %if.end + +if.else: + %malloced = call noalias dereferenceable_or_null(8) i8* @malloc(i64 noundef 8) + br label %if.end + +if.end: + %p = phi i8* [ %malloced, %if.else ], [ getelementptr inbounds ([4 x i8], [4 x i8]* @buffer, i64 0, i64 0), %entry ] + %size = call i64 @llvm.objectsize.i64.p0i8(i8* %p, i1 false, i1 true, i1 false) + ret i64 %size +} + +define dso_local i64 @pick_min(i32 noundef %n) local_unnamed_addr { +; CHECK-LABEL: @pick_min( +; CHECK-NEXT: entry: +; CHECK-NEXT: ret i64 4 +entry: + %cond = icmp eq i32 %n, 0 + br i1 %cond, label %if.else, label %if.end + +if.else: + %malloced = call noalias dereferenceable_or_null(8) i8* @malloc(i64 noundef 8) + br label %if.end + +if.end: + %p = phi i8* [ %malloced, %if.else ], [ getelementptr inbounds ([4 x i8], [4 x i8]* @buffer, i64 0, i64 0), %entry ] + %size = call i64 @llvm.objectsize.i64.p0i8(i8* %p, i1 true, i1 true, i1 false) + ret i64 %size +}