Bevin Hansson e412697451
[MemoryBuiltins] Cache the result of ObjectOffsetSizeVisitor::visit. #64796 (#65326)
visit will skip visiting instructions it already has visited
to avoid issues with cycles in the data graph. However,
the result of this skipping behavior is that if we
encounter the same instruction twice, and that instruction
has a well defined result and isn't part of a cycle, we
will introduce unknowns into the analysis even though we
knew the size and offset of the instruction's result.

Instead of skipping such instructions, keep a cache of
the result of visiting them. This result is initialized
to unknown() before visiting, so if we happen to visit
it again recursively (perhaps as the result of a cycle
or a phi), we will get unknown as the cached result and
exit out.
2023-09-15 10:30:45 +02:00

120 lines
4.1 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -passes=lower-constant-intrinsics -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 ptr @malloc(i64 noundef) local_unnamed_addr allocsize(0)
declare i64 @llvm.objectsize.i64.p0(ptr, 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: [[COND:%.*]] = icmp eq i32 [[N:%.*]], 0
; CHECK-NEXT: br i1 [[COND]], label [[IF_ELSE:%.*]], label [[IF_END:%.*]]
; CHECK: if.else:
; CHECK-NEXT: [[MALLOCED:%.*]] = call noalias dereferenceable_or_null(8) ptr @malloc(i64 noundef 8)
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[MALLOCED]], [[IF_ELSE]] ], [ @buffer, [[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) ptr @malloc(i64 noundef 8)
br label %if.end
if.end:
%p = phi ptr [ %malloced, %if.else ], [ @buffer, %entry ]
%size = call i64 @llvm.objectsize.i64.p0(ptr %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: [[COND:%.*]] = icmp eq i32 [[N:%.*]], 0
; CHECK-NEXT: br i1 [[COND]], label [[IF_ELSE:%.*]], label [[IF_END:%.*]]
; CHECK: if.else:
; CHECK-NEXT: [[MALLOCED:%.*]] = call noalias dereferenceable_or_null(8) ptr @malloc(i64 noundef 8)
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[MALLOCED]], [[IF_ELSE]] ], [ @buffer, [[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) ptr @malloc(i64 noundef 8)
br label %if.end
if.end:
%p = phi ptr [ %malloced, %if.else ], [ @buffer, %entry ]
%size = call i64 @llvm.objectsize.i64.p0(ptr %p, i1 true, i1 true, i1 false)
ret i64 %size
}
define i64 @pick_max_same(i32 %n) {
; CHECK-LABEL: @pick_max_same(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[BUFFER:%.*]] = alloca i8, i64 20, align 1
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[N:%.*]], 0
; CHECK-NEXT: br i1 [[COND]], label [[IF_ELSE:%.*]], label [[IF_END:%.*]]
; CHECK: if.else:
; CHECK-NEXT: [[OFFSETED:%.*]] = getelementptr i8, ptr [[BUFFER]], i64 10
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[OFFSETED]], [[IF_ELSE]] ], [ [[BUFFER]], [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i64 20
;
entry:
%buffer = alloca i8, i64 20
%cond = icmp eq i32 %n, 0
br i1 %cond, label %if.else, label %if.end
if.else:
%offseted = getelementptr i8, ptr %buffer, i64 10
br label %if.end
if.end:
%p = phi ptr [ %offseted, %if.else ], [ %buffer, %entry ]
%size = call i64 @llvm.objectsize.i64.p0(ptr %p, i1 false, i1 true, i1 false)
ret i64 %size
}
define i64 @pick_min_same(i32 %n) {
; CHECK-LABEL: @pick_min_same(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[BUFFER:%.*]] = alloca i8, i64 20, align 1
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[N:%.*]], 0
; CHECK-NEXT: br i1 [[COND]], label [[IF_ELSE:%.*]], label [[IF_END:%.*]]
; CHECK: if.else:
; CHECK-NEXT: [[OFFSETED:%.*]] = getelementptr i8, ptr [[BUFFER]], i64 10
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[OFFSETED]], [[IF_ELSE]] ], [ [[BUFFER]], [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i64 10
;
entry:
%buffer = alloca i8, i64 20
%cond = icmp eq i32 %n, 0
br i1 %cond, label %if.else, label %if.end
if.else:
%offseted = getelementptr i8, ptr %buffer, i64 10
br label %if.end
if.end:
%p = phi ptr [ %offseted, %if.else ], [ %buffer, %entry ]
%size = call i64 @llvm.objectsize.i64.p0(ptr %p, i1 true, i1 true, i1 false)
ret i64 %size
}