
After D141386 !nonnull violation returns poison rather than resulting in immediate undefined behavior. However, converting it into an assume would result in IUB. As such, we can only perform this transform if !noundef is also present.
183 lines
5.5 KiB
LLVM
183 lines
5.5 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt < %s -passes=mem2reg -S | FileCheck %s
|
|
|
|
; This tests that mem2reg preserves the !nonnull metadata on loads
|
|
; from allocas that get optimized out.
|
|
|
|
; Check the case where the alloca in question has a single store.
|
|
define ptr @single_store_noundef(ptr %arg) {
|
|
; CHECK-LABEL: @single_store_noundef(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[ARG_LOAD:%.*]] = load ptr, ptr [[ARG:%.*]], align 8
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp ne ptr [[ARG_LOAD]], null
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]])
|
|
; CHECK-NEXT: ret ptr [[ARG_LOAD]]
|
|
;
|
|
entry:
|
|
%buf = alloca ptr
|
|
%arg.load = load ptr, ptr %arg, align 8
|
|
store ptr %arg.load, ptr %buf, align 8
|
|
%buf.load = load ptr, ptr %buf, !nonnull !0, !noundef !0
|
|
ret ptr %buf.load
|
|
}
|
|
|
|
define ptr @single_store_missing_noundef(ptr %arg) {
|
|
; CHECK-LABEL: @single_store_missing_noundef(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[ARG_LOAD:%.*]] = load ptr, ptr [[ARG:%.*]], align 8
|
|
; CHECK-NEXT: ret ptr [[ARG_LOAD]]
|
|
;
|
|
entry:
|
|
%buf = alloca ptr
|
|
%arg.load = load ptr, ptr %arg, align 8
|
|
store ptr %arg.load, ptr %buf, align 8
|
|
%buf.load = load ptr, ptr %buf, !nonnull !0
|
|
ret ptr %buf.load
|
|
}
|
|
|
|
; Check the case where the alloca in question has more than one
|
|
; store but still within one basic block.
|
|
define ptr @single_block_noundef(ptr %arg) {
|
|
; CHECK-LABEL: @single_block_noundef(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[ARG_LOAD:%.*]] = load ptr, ptr [[ARG:%.*]], align 8
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp ne ptr [[ARG_LOAD]], null
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]])
|
|
; CHECK-NEXT: ret ptr [[ARG_LOAD]]
|
|
;
|
|
entry:
|
|
%buf = alloca ptr
|
|
%arg.load = load ptr, ptr %arg, align 8
|
|
store ptr null, ptr %buf, align 8
|
|
store ptr %arg.load, ptr %buf, align 8
|
|
%buf.load = load ptr, ptr %buf, !nonnull !0, !noundef !0
|
|
ret ptr %buf.load
|
|
}
|
|
|
|
define ptr @single_block_missing_noundef(ptr %arg) {
|
|
; CHECK-LABEL: @single_block_missing_noundef(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[ARG_LOAD:%.*]] = load ptr, ptr [[ARG:%.*]], align 8
|
|
; CHECK-NEXT: ret ptr [[ARG_LOAD]]
|
|
;
|
|
entry:
|
|
%buf = alloca ptr
|
|
%arg.load = load ptr, ptr %arg, align 8
|
|
store ptr null, ptr %buf, align 8
|
|
store ptr %arg.load, ptr %buf, align 8
|
|
%buf.load = load ptr, ptr %buf, !nonnull !0
|
|
ret ptr %buf.load
|
|
}
|
|
|
|
; Check the case where the alloca in question has more than one
|
|
; store and also reads ands writes in multiple blocks.
|
|
define ptr @multi_block_noundef(ptr %arg) {
|
|
; CHECK-LABEL: @multi_block_noundef(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[ARG_LOAD:%.*]] = load ptr, ptr [[ARG:%.*]], align 8
|
|
; CHECK-NEXT: br label [[NEXT:%.*]]
|
|
; CHECK: next:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp ne ptr [[ARG_LOAD]], null
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]])
|
|
; CHECK-NEXT: ret ptr [[ARG_LOAD]]
|
|
;
|
|
entry:
|
|
%buf = alloca ptr
|
|
%arg.load = load ptr, ptr %arg, align 8
|
|
store ptr null, ptr %buf, align 8
|
|
br label %next
|
|
next:
|
|
store ptr %arg.load, ptr %buf, align 8
|
|
%buf.load = load ptr, ptr %buf, !nonnull !0, !noundef !0
|
|
ret ptr %buf.load
|
|
}
|
|
|
|
define ptr @multi_block_missing_noundef(ptr %arg) {
|
|
; CHECK-LABEL: @multi_block_missing_noundef(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[ARG_LOAD:%.*]] = load ptr, ptr [[ARG:%.*]], align 8
|
|
; CHECK-NEXT: br label [[NEXT:%.*]]
|
|
; CHECK: next:
|
|
; CHECK-NEXT: ret ptr [[ARG_LOAD]]
|
|
;
|
|
entry:
|
|
%buf = alloca ptr
|
|
%arg.load = load ptr, ptr %arg, align 8
|
|
store ptr null, ptr %buf, align 8
|
|
br label %next
|
|
next:
|
|
store ptr %arg.load, ptr %buf, align 8
|
|
%buf.load = load ptr, ptr %buf, !nonnull !0
|
|
ret ptr %buf.load
|
|
}
|
|
|
|
; Check that we don't add an assume if it's not
|
|
; necessary i.e. the value is already implied to be nonnull
|
|
define ptr @no_assume(ptr %arg) {
|
|
; CHECK-LABEL: @no_assume(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[ARG_LOAD:%.*]] = load ptr, ptr [[ARG:%.*]], align 8
|
|
; CHECK-NEXT: [[CN:%.*]] = icmp ne ptr [[ARG_LOAD]], null
|
|
; CHECK-NEXT: br i1 [[CN]], label [[NEXT:%.*]], label [[FIN:%.*]]
|
|
; CHECK: next:
|
|
; CHECK-NEXT: ret ptr [[ARG_LOAD]]
|
|
; CHECK: fin:
|
|
; CHECK-NEXT: ret ptr null
|
|
;
|
|
entry:
|
|
%buf = alloca ptr
|
|
%arg.load = load ptr, ptr %arg, align 8
|
|
%cn = icmp ne ptr %arg.load, null
|
|
br i1 %cn, label %next, label %fin
|
|
next:
|
|
; At this point the above nonnull check ensures that
|
|
; the value %arg.load is nonnull in this block and thus
|
|
; we need not add the assume.
|
|
store ptr %arg.load, ptr %buf, align 8
|
|
%buf.load = load ptr, ptr %buf, !nonnull !0
|
|
ret ptr %buf.load
|
|
fin:
|
|
ret ptr null
|
|
}
|
|
|
|
define ptr @no_store_single_load() {
|
|
; CHECK-LABEL: @no_store_single_load(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp ne ptr undef, null
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]])
|
|
; CHECK-NEXT: ret ptr undef
|
|
;
|
|
entry:
|
|
%buf = alloca ptr
|
|
%buf.load = load ptr, ptr %buf, !nonnull !0, !noundef !0
|
|
ret ptr %buf.load
|
|
}
|
|
|
|
define ptr @no_store_multiple_loads(i1 %c) {
|
|
; CHECK-LABEL: @no_store_multiple_loads(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
|
|
; CHECK: if:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp ne ptr undef, null
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]])
|
|
; CHECK-NEXT: ret ptr undef
|
|
; CHECK: else:
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ne ptr undef, null
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[TMP1]])
|
|
; CHECK-NEXT: ret ptr undef
|
|
;
|
|
entry:
|
|
%buf = alloca ptr
|
|
br i1 %c, label %if, label %else
|
|
|
|
if:
|
|
%buf.load = load ptr, ptr %buf, !nonnull !0, !noundef !0
|
|
ret ptr %buf.load
|
|
|
|
else:
|
|
%buf.load2 = load ptr, ptr %buf, !nonnull !0, !noundef !0
|
|
ret ptr %buf.load2
|
|
}
|
|
|
|
!0 = !{}
|