Files
clang-p2996/llvm/test/Transforms/PhaseOrdering/iterator-with-runtime-check.ll
Florian Hahn cd2fc73b49 Revert "[ValueTracking][InstCombine] Add a new API to allow to ignore poison generating flags or metadatas when implying poison"
This reverts commit 754f3ae655.

Unfortunately the change can cause regressions due to dropping flags
from instructions (like nuw,nsw,inbounds), prevent further optimizations
depending on those flags.

A simple example is the IR below, where `inbounds` is dropped with the
patch and the phase-ordering test added in 7c91d82ab9.

    define i1 @test(ptr %base, i64 noundef %len, ptr %p2) {
    bb:
      %gep = getelementptr inbounds i32, ptr %base, i64 %len
      %c.1 = icmp uge ptr %p2, %base
      %c.2 = icmp ult ptr %p2, %gep
      %select = select i1 %c.1, i1 %c.2, i1 false
      ret i1 %select
    }

For more discussion, see D149404.
2023-05-29 15:44:37 +01:00

125 lines
5.9 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
; RUN: opt -passes='default<O2>' -S %s | FileCheck %s
; Slightly reduced test case for a loop iterating over a std::span with libc++ hardening.
; TODO: The runtime check in the loop should be removed.
;
; #include <span>
; #include <iostream>
;
; void use(unsigned&);
;
; void fill_with_foreach(std::span<unsigned> elems) {
; for (unsigned& x : elems)
; use(x);
; }
%"class.std::__1::span" = type { ptr, i64 }
%"struct.std::__1::__bounded_iter" = type { ptr, ptr, ptr }
define void @test_fill_with_foreach([2 x i64] %elems.coerce) {
; CHECK-LABEL: define void @test_fill_with_foreach
; CHECK-SAME: ([2 x i64] [[ELEMS_COERCE:%.*]]) local_unnamed_addr {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[ELEMS_COERCE_FCA_0_EXTRACT:%.*]] = extractvalue [2 x i64] [[ELEMS_COERCE]], 0
; CHECK-NEXT: [[TMP0:%.*]] = inttoptr i64 [[ELEMS_COERCE_FCA_0_EXTRACT]] to ptr
; CHECK-NEXT: [[ELEMS_COERCE_FCA_1_EXTRACT:%.*]] = extractvalue [2 x i64] [[ELEMS_COERCE]], 1
; CHECK-NEXT: [[ADD_PTR_I:%.*]] = getelementptr inbounds i32, ptr [[TMP0]], i64 [[ELEMS_COERCE_FCA_1_EXTRACT]]
; CHECK-NEXT: [[CMP_NOT_I_I_I_I:%.*]] = icmp slt i64 [[ELEMS_COERCE_FCA_1_EXTRACT]], 0
; CHECK-NEXT: br i1 [[CMP_NOT_I_I_I_I]], label [[ERROR:%.*]], label [[FOR_COND_PREHEADER:%.*]]
; CHECK: for.cond.preheader:
; CHECK-NEXT: [[CMP_I_NOT2:%.*]] = icmp eq i64 [[ELEMS_COERCE_FCA_1_EXTRACT]], 0
; CHECK-NEXT: br i1 [[CMP_I_NOT2]], label [[COMMON_RET:%.*]], label [[FOR_BODY:%.*]]
; CHECK: common.ret:
; CHECK-NEXT: ret void
; CHECK: error:
; CHECK-NEXT: tail call void @error()
; CHECK-NEXT: br label [[COMMON_RET]]
; CHECK: for.body:
; CHECK-NEXT: [[__BEGIN1_SROA_0_03:%.*]] = phi ptr [ [[INCDEC_PTR_I:%.*]], [[FOR_LATCH:%.*]] ], [ [[TMP0]], [[FOR_COND_PREHEADER]] ]
; CHECK-NEXT: [[CMP2_I_I:%.*]] = icmp ult ptr [[__BEGIN1_SROA_0_03]], [[ADD_PTR_I]]
; CHECK-NEXT: br i1 [[CMP2_I_I]], label [[FOR_LATCH]], label [[ERROR]]
; CHECK: for.latch:
; CHECK-NEXT: tail call void @use(ptr noundef nonnull align 4 dereferenceable(4) [[__BEGIN1_SROA_0_03]])
; CHECK-NEXT: [[INCDEC_PTR_I]] = getelementptr inbounds i32, ptr [[__BEGIN1_SROA_0_03]], i64 1
; CHECK-NEXT: [[CMP_I_NOT:%.*]] = icmp eq ptr [[INCDEC_PTR_I]], [[ADD_PTR_I]]
; CHECK-NEXT: br i1 [[CMP_I_NOT]], label [[COMMON_RET]], label [[FOR_BODY]]
;
entry:
%elems = alloca %"class.std::__1::span", align 8
%__begin1 = alloca %"struct.std::__1::__bounded_iter", align 8
%__end1 = alloca %"struct.std::__1::__bounded_iter", align 8
%elems.coerce.fca.0.extract = extractvalue [2 x i64] %elems.coerce, 0
store i64 %elems.coerce.fca.0.extract, ptr %elems, align 8
%elems.coerce.fca.1.extract = extractvalue [2 x i64] %elems.coerce, 1
%elems.coerce.fca.1.gep = getelementptr inbounds [2 x i64], ptr %elems, i64 0, i64 1
store i64 %elems.coerce.fca.1.extract, ptr %elems.coerce.fca.1.gep, align 8
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %__begin1) #6
%0 = load ptr, ptr %elems, align 8
%__size_.i.i = getelementptr inbounds %"class.std::__1::span", ptr %elems, i64 0, i32 1
%1 = load i64, ptr %__size_.i.i, align 8
%add.ptr.i = getelementptr inbounds i32, ptr %0, i64 %1
store ptr %0, ptr %__begin1, align 8
%__begin_.i.i.i.i = getelementptr inbounds %"struct.std::__1::__bounded_iter", ptr %__begin1, i64 0, i32 1
store ptr %0, ptr %__begin_.i.i.i.i, align 8
%__end_.i.i.i.i = getelementptr inbounds %"struct.std::__1::__bounded_iter", ptr %__begin1, i64 0, i32 2
store ptr %add.ptr.i, ptr %__end_.i.i.i.i, align 8
%cmp.not.i.i.i.i = icmp slt i64 %1, 0
br i1 %cmp.not.i.i.i.i, label %error, label %check.2
check.2:
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %__end1) #6
%l4 = load ptr, ptr %elems, align 8
%__size_.i.i4 = getelementptr inbounds %"class.std::__1::span", ptr %elems, i64 0, i32 1
%l5 = load i64, ptr %__size_.i.i4, align 8
%add.ptr.i5 = getelementptr inbounds i32, ptr %l4, i64 %l5
store ptr %add.ptr.i5, ptr %__end1, align 8
%__begin_.i.i.i.i6 = getelementptr inbounds %"struct.std::__1::__bounded_iter", ptr %__end1, i64 0, i32 1
store ptr %l4, ptr %__begin_.i.i.i.i6, align 8
%__end_.i.i.i.i7 = getelementptr inbounds %"struct.std::__1::__bounded_iter", ptr %__end1, i64 0, i32 2
store ptr %add.ptr.i5, ptr %__end_.i.i.i.i7, align 8
%cmp.not.i.i.i.i8 = icmp slt i64 %l5, 0
br i1 %cmp.not.i.i.i.i8, label %error, label %for.cond
error:
call void @error()
ret void
for.cond:
%l8 = load ptr, ptr %__begin1, align 8
%l9 = load ptr, ptr %__end1, align 8
%cmp.i = icmp ne ptr %l8, %l9
br i1 %cmp.i, label %for.body, label %for.cond.cleanup
for.cond.cleanup: ; preds = %for.cond
call void @llvm.lifetime.end.p0(i64 24, ptr nonnull %__end1)
call void @llvm.lifetime.end.p0(i64 24, ptr nonnull %__begin1)
ret void
for.body: ; preds = %for.cond
%l10 = load ptr, ptr %__begin1, align 8
%__begin_.i.i = getelementptr inbounds %"struct.std::__1::__bounded_iter", ptr %__begin1, i64 0, i32 1
%l11 = load ptr, ptr %__begin_.i.i, align 8
%cmp.not.i.i = icmp uge ptr %l10, %l11
%__end_.i.i = getelementptr inbounds %"struct.std::__1::__bounded_iter", ptr %__begin1, i64 0, i32 2
%l12 = load ptr, ptr %__end_.i.i, align 8
%cmp2.i.i = icmp ult ptr %l10, %l12
%sel = select i1 %cmp.not.i.i, i1 %cmp2.i.i, i1 false
br i1 %sel, label %for.latch, label %error
for.latch:
call void @use(ptr noundef nonnull align 4 dereferenceable(4) %l10)
%l = load ptr, ptr %__begin1, align 8
%incdec.ptr.i = getelementptr inbounds i32, ptr %l, i64 1
store ptr %incdec.ptr.i, ptr %__begin1, align 8
br label %for.cond
}
declare void @error()
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture)
declare void @use(ptr noundef nonnull align 4 dereferenceable(4))
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture)