[AssumeBundles] Dereferenceable used in bundle only applies at assume. (#126117)
Update LangRef and code using `Dereferenceable` in assume bundles to only use the information if it is safe at the point of use. `Dereferenceable` in an assume bundle is only guaranteed at the point of the assumption, but may not be guaranteed at later points, because the pointer may have been freed. Update code using `Dereferenceable` to only use it if the pointer cannot be freed. This can further be refined to check if the pointer could be freed between assume and use. This follows up on https://github.com/llvm/llvm-project/pull/123196. With that change, it should be safe to expose dereferenceable assumptions more widely as in https://github.com/llvm/llvm-project/pull/121789 PR: https://github.com/llvm/llvm-project/pull/126117
This commit is contained in:
parent
5decab178f
commit
65640c1d4c
@ -1474,7 +1474,9 @@ Currently, only the following parameter attributes are defined:
|
|||||||
``null_pointer_is_valid`` function attribute is present.
|
``null_pointer_is_valid`` function attribute is present.
|
||||||
``n`` should be a positive number. The pointer should be well defined,
|
``n`` should be a positive number. The pointer should be well defined,
|
||||||
otherwise it is undefined behavior. This means ``dereferenceable(<n>)``
|
otherwise it is undefined behavior. This means ``dereferenceable(<n>)``
|
||||||
implies ``noundef``.
|
implies ``noundef``. When used in an assume operand bundle, more restricted
|
||||||
|
semantics apply. See :ref:`assume operand bundles <assume_opbundles>` for
|
||||||
|
more details.
|
||||||
|
|
||||||
``dereferenceable_or_null(<n>)``
|
``dereferenceable_or_null(<n>)``
|
||||||
This indicates that the parameter or return value isn't both
|
This indicates that the parameter or return value isn't both
|
||||||
@ -2929,6 +2931,11 @@ the behavior is undefined, unless one of the following exceptions applies:
|
|||||||
(including a zero alignment). If this is the case, then the pointer value
|
(including a zero alignment). If this is the case, then the pointer value
|
||||||
must be a null pointer, otherwise the behavior is undefined.
|
must be a null pointer, otherwise the behavior is undefined.
|
||||||
|
|
||||||
|
* ``dereferenceable(<n>)`` operand bundles only guarantee the pointer is
|
||||||
|
dereferenceable at the point of the assumption. The pointer may not be
|
||||||
|
dereferenceable at later pointers, e.g. because it could have been
|
||||||
|
freed.
|
||||||
|
|
||||||
In addition to allowing operand bundles encoding function and parameter
|
In addition to allowing operand bundles encoding function and parameter
|
||||||
attributes, an assume operand bundle my also encode a ``separate_storage``
|
attributes, an assume operand bundle my also encode a ``separate_storage``
|
||||||
operand bundle. This has the form:
|
operand bundle. This has the form:
|
||||||
|
@ -26,8 +26,6 @@
|
|||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
extern cl::opt<bool> UseDerefAtPointSemantics;
|
|
||||||
|
|
||||||
static bool isAligned(const Value *Base, Align Alignment,
|
static bool isAligned(const Value *Base, Align Alignment,
|
||||||
const DataLayout &DL) {
|
const DataLayout &DL) {
|
||||||
return Base->getPointerAlignment(DL) >= Alignment;
|
return Base->getPointerAlignment(DL) >= Alignment;
|
||||||
@ -171,7 +169,12 @@ static bool isDereferenceableAndAlignedPointer(
|
|||||||
Size, DL, CtxI, AC, DT, TLI,
|
Size, DL, CtxI, AC, DT, TLI,
|
||||||
Visited, MaxDepth);
|
Visited, MaxDepth);
|
||||||
|
|
||||||
if (CtxI && (!UseDerefAtPointSemantics || !V->canBeFreed())) {
|
// Dereferenceable information from assumptions is only valid if the value
|
||||||
|
// cannot be freed between the assumption and use. For now just use the
|
||||||
|
// information for values that cannot be freed in the function.
|
||||||
|
// TODO: More precisely check if the pointer can be freed between assumption
|
||||||
|
// and use.
|
||||||
|
if (CtxI && !V->canBeFreed()) {
|
||||||
/// Look through assumes to see if both dereferencability and alignment can
|
/// Look through assumes to see if both dereferencability and alignment can
|
||||||
/// be proven by an assume if needed.
|
/// be proven by an assume if needed.
|
||||||
RetainedKnowledge AlignRK;
|
RetainedKnowledge AlignRK;
|
||||||
|
@ -47,7 +47,7 @@ define dso_local i1 @test2(ptr readonly %0) {
|
|||||||
ret i1 %2
|
ret i1 %2
|
||||||
}
|
}
|
||||||
|
|
||||||
define dso_local i32 @test4(ptr readonly %0, i1 %cond) {
|
define dso_local i32 @test4(ptr readonly %0, i1 %cond) nofree nosync {
|
||||||
; COUNTER1-LABEL: @test4(
|
; COUNTER1-LABEL: @test4(
|
||||||
; COUNTER1-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[TMP0:%.*]], i32 4) ]
|
; COUNTER1-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[TMP0:%.*]], i32 4) ]
|
||||||
; COUNTER1-NEXT: br i1 [[COND:%.*]], label [[A:%.*]], label [[B:%.*]]
|
; COUNTER1-NEXT: br i1 [[COND:%.*]], label [[A:%.*]], label [[B:%.*]]
|
||||||
|
@ -57,7 +57,7 @@ define dso_local i1 @test2(ptr readonly %0) {
|
|||||||
ret i1 %2
|
ret i1 %2
|
||||||
}
|
}
|
||||||
|
|
||||||
define dso_local i32 @test4(ptr readonly %0, i1 %cond) {
|
define dso_local i32 @test4(ptr readonly %0, i1 %cond) nofree nosync {
|
||||||
; CHECK-LABEL: @test4(
|
; CHECK-LABEL: @test4(
|
||||||
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[TMP0:%.*]], i32 4) ]
|
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[TMP0:%.*]], i32 4) ]
|
||||||
; CHECK-NEXT: br i1 [[COND:%.*]], label [[A:%.*]], label [[B:%.*]]
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[A:%.*]], label [[B:%.*]]
|
||||||
@ -91,7 +91,7 @@ A:
|
|||||||
ret i32 %6
|
ret i32 %6
|
||||||
}
|
}
|
||||||
|
|
||||||
define dso_local i32 @test4a(ptr readonly %0, i1 %cond) {
|
define dso_local i32 @test4a(ptr readonly %0, i1 %cond) nofree nosync {
|
||||||
; CHECK-LABEL: @test4a(
|
; CHECK-LABEL: @test4a(
|
||||||
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[TMP0:%.*]], i32 4), "align"(ptr [[TMP0]], i32 8) ]
|
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[TMP0:%.*]], i32 4), "align"(ptr [[TMP0]], i32 8) ]
|
||||||
; CHECK-NEXT: br i1 [[COND:%.*]], label [[A:%.*]], label [[B:%.*]]
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[A:%.*]], label [[B:%.*]]
|
||||||
|
@ -11,12 +11,12 @@ define void @f(i32 %ptr_i, ptr %ptr2, i1 %cond) {
|
|||||||
; CHECK-NEXT: store i32 0, ptr [[PTR2:%.*]], align 4
|
; CHECK-NEXT: store i32 0, ptr [[PTR2:%.*]], align 4
|
||||||
; CHECK-NEXT: br label [[FOR_BODY_LR_PH]]
|
; CHECK-NEXT: br label [[FOR_BODY_LR_PH]]
|
||||||
; CHECK: for.body.lr.ph:
|
; CHECK: for.body.lr.ph:
|
||||||
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[PTR]], align 4
|
|
||||||
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
|
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
|
||||||
; CHECK: for.body:
|
; CHECK: for.body:
|
||||||
; CHECK-NEXT: [[I_08:%.*]] = phi i32 [ 0, [[FOR_BODY_LR_PH]] ], [ [[INC:%.*]], [[IF_END:%.*]] ]
|
; CHECK-NEXT: [[I_08:%.*]] = phi i32 [ 0, [[FOR_BODY_LR_PH]] ], [ [[INC:%.*]], [[IF_END:%.*]] ]
|
||||||
; CHECK-NEXT: br i1 [[COND]], label [[IF_END]], label [[IF:%.*]]
|
; CHECK-NEXT: br i1 [[COND]], label [[IF_END]], label [[IF:%.*]]
|
||||||
; CHECK: if:
|
; CHECK: if:
|
||||||
|
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[PTR]], align 4, !invariant.load [[META0:![0-9]+]]
|
||||||
; CHECK-NEXT: store i32 [[TMP0]], ptr [[PTR2]], align 4
|
; CHECK-NEXT: store i32 [[TMP0]], ptr [[PTR2]], align 4
|
||||||
; CHECK-NEXT: br label [[IF_END]]
|
; CHECK-NEXT: br label [[IF_END]]
|
||||||
; CHECK: if.end:
|
; CHECK: if.end:
|
||||||
@ -56,4 +56,112 @@ exit: ; preds = %if.end, %entry
|
|||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define void @f_nofree_nosync(i32 %ptr_i, ptr %ptr2, i1 %cond) nofree nosync {
|
||||||
|
; CHECK-LABEL: @f_nofree_nosync(
|
||||||
|
; CHECK-NEXT: entry:
|
||||||
|
; CHECK-NEXT: [[PTR:%.*]] = inttoptr i32 [[PTR_I:%.*]] to ptr
|
||||||
|
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[PTR]], i32 16), "dereferenceable"(ptr [[PTR]], i32 16) ]
|
||||||
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[FOR_BODY_LR_PH:%.*]], label [[IF0:%.*]]
|
||||||
|
; CHECK: if0:
|
||||||
|
; CHECK-NEXT: store i32 0, ptr [[PTR2:%.*]], align 4
|
||||||
|
; CHECK-NEXT: br label [[FOR_BODY_LR_PH]]
|
||||||
|
; CHECK: for.body.lr.ph:
|
||||||
|
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
|
||||||
|
; CHECK: for.body:
|
||||||
|
; CHECK-NEXT: [[I_08:%.*]] = phi i32 [ 0, [[FOR_BODY_LR_PH]] ], [ [[INC:%.*]], [[IF_END:%.*]] ]
|
||||||
|
; CHECK-NEXT: br i1 [[COND]], label [[IF_END]], label [[IF:%.*]]
|
||||||
|
; CHECK: if:
|
||||||
|
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[PTR]], align 4, !invariant.load [[META0]]
|
||||||
|
; CHECK-NEXT: store i32 [[TMP0]], ptr [[PTR2]], align 4
|
||||||
|
; CHECK-NEXT: br label [[IF_END]]
|
||||||
|
; CHECK: if.end:
|
||||||
|
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_08]], 1
|
||||||
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[INC]], 2
|
||||||
|
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[EXIT:%.*]]
|
||||||
|
; CHECK: exit:
|
||||||
|
; CHECK-NEXT: ret void
|
||||||
|
;
|
||||||
|
entry:
|
||||||
|
%ptr = inttoptr i32 %ptr_i to ptr
|
||||||
|
call void @llvm.assume(i1 true) [ "align"(ptr %ptr, i32 16), "dereferenceable"(ptr %ptr, i32 16) ]
|
||||||
|
br i1 %cond, label %for.body.lr.ph, label %if0
|
||||||
|
|
||||||
|
if0:
|
||||||
|
store i32 0, ptr %ptr2, align 4
|
||||||
|
br label %for.body.lr.ph
|
||||||
|
|
||||||
|
for.body.lr.ph: ; preds = %entry
|
||||||
|
br label %for.body
|
||||||
|
|
||||||
|
for.body: ; preds = %for.body.lr.ph, %if.end
|
||||||
|
%i.08 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %if.end ]
|
||||||
|
br i1 %cond, label %if.end, label %if
|
||||||
|
|
||||||
|
if:
|
||||||
|
%0 = load i32, ptr %ptr, align 4, !invariant.load !{}
|
||||||
|
store i32 %0, ptr %ptr2, align 4
|
||||||
|
br label %if.end
|
||||||
|
|
||||||
|
if.end: ; preds = %for.body
|
||||||
|
%inc = add nuw nsw i32 %i.08, 1
|
||||||
|
%cmp = icmp slt i32 %inc, 2
|
||||||
|
br i1 %cmp, label %for.body, label %exit
|
||||||
|
|
||||||
|
exit: ; preds = %if.end, %entry
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @f_without_ptrtoint_and_with_nofree_nosync(ptr %ptr, ptr %ptr2, i1 %cond) nofree nosync {
|
||||||
|
; CHECK-LABEL: @f_without_ptrtoint_and_with_nofree_nosync(
|
||||||
|
; CHECK-NEXT: entry:
|
||||||
|
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[PTR:%.*]], i32 16), "dereferenceable"(ptr [[PTR]], i32 16) ]
|
||||||
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[FOR_BODY_LR_PH:%.*]], label [[IF0:%.*]]
|
||||||
|
; CHECK: if0:
|
||||||
|
; CHECK-NEXT: store i32 0, ptr [[PTR2:%.*]], align 4
|
||||||
|
; CHECK-NEXT: br label [[FOR_BODY_LR_PH]]
|
||||||
|
; CHECK: for.body.lr.ph:
|
||||||
|
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[PTR]], align 4
|
||||||
|
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
|
||||||
|
; CHECK: for.body:
|
||||||
|
; CHECK-NEXT: [[I_08:%.*]] = phi i32 [ 0, [[FOR_BODY_LR_PH]] ], [ [[INC:%.*]], [[IF_END:%.*]] ]
|
||||||
|
; CHECK-NEXT: br i1 [[COND]], label [[IF_END]], label [[IF:%.*]]
|
||||||
|
; CHECK: if:
|
||||||
|
; CHECK-NEXT: store i32 [[TMP0]], ptr [[PTR2]], align 4
|
||||||
|
; CHECK-NEXT: br label [[IF_END]]
|
||||||
|
; CHECK: if.end:
|
||||||
|
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_08]], 1
|
||||||
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[INC]], 2
|
||||||
|
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[EXIT:%.*]]
|
||||||
|
; CHECK: exit:
|
||||||
|
; CHECK-NEXT: ret void
|
||||||
|
;
|
||||||
|
entry:
|
||||||
|
call void @llvm.assume(i1 true) [ "align"(ptr %ptr, i32 16), "dereferenceable"(ptr %ptr, i32 16) ]
|
||||||
|
br i1 %cond, label %for.body.lr.ph, label %if0
|
||||||
|
|
||||||
|
if0:
|
||||||
|
store i32 0, ptr %ptr2, align 4
|
||||||
|
br label %for.body.lr.ph
|
||||||
|
|
||||||
|
for.body.lr.ph: ; preds = %entry
|
||||||
|
br label %for.body
|
||||||
|
|
||||||
|
for.body: ; preds = %for.body.lr.ph, %if.end
|
||||||
|
%i.08 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %if.end ]
|
||||||
|
br i1 %cond, label %if.end, label %if
|
||||||
|
|
||||||
|
if:
|
||||||
|
%0 = load i32, ptr %ptr, align 4, !invariant.load !{}
|
||||||
|
store i32 %0, ptr %ptr2, align 4
|
||||||
|
br label %if.end
|
||||||
|
|
||||||
|
if.end: ; preds = %for.body
|
||||||
|
%inc = add nuw nsw i32 %i.08, 1
|
||||||
|
%cmp = icmp slt i32 %inc, 2
|
||||||
|
br i1 %cmp, label %for.body, label %exit
|
||||||
|
|
||||||
|
exit: ; preds = %if.end, %entry
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
declare void @llvm.assume(i1 noundef)
|
declare void @llvm.assume(i1 noundef)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
|
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
|
||||||
; RUN: opt -p loop-vectorize -force-vector-width=2 -use-dereferenceable-at-point-semantics -S %s | FileCheck %s
|
; RUN: opt -p loop-vectorize -force-vector-width=2 -S %s | FileCheck %s
|
||||||
|
|
||||||
declare void @llvm.assume(i1)
|
declare void @llvm.assume(i1)
|
||||||
|
|
||||||
@ -1411,7 +1411,6 @@ exit:
|
|||||||
}
|
}
|
||||||
|
|
||||||
; %a may be freed between the dereferenceable assumption and accesses.
|
; %a may be freed between the dereferenceable assumption and accesses.
|
||||||
; It is not safe to use with -use-dereferenceable-at-point-semantics.
|
|
||||||
define void @may_free_align_deref_assumption_in_header_constant_trip_count_loop_invariant_ptr(ptr noalias %a, ptr noalias %b, ptr noalias %c) {
|
define void @may_free_align_deref_assumption_in_header_constant_trip_count_loop_invariant_ptr(ptr noalias %a, ptr noalias %b, ptr noalias %c) {
|
||||||
; CHECK-LABEL: define void @may_free_align_deref_assumption_in_header_constant_trip_count_loop_invariant_ptr(
|
; CHECK-LABEL: define void @may_free_align_deref_assumption_in_header_constant_trip_count_loop_invariant_ptr(
|
||||||
; CHECK-SAME: ptr noalias [[A:%.*]], ptr noalias [[B:%.*]], ptr noalias [[C:%.*]]) {
|
; CHECK-SAME: ptr noalias [[A:%.*]], ptr noalias [[B:%.*]], ptr noalias [[C:%.*]]) {
|
||||||
@ -1505,7 +1504,6 @@ exit:
|
|||||||
}
|
}
|
||||||
|
|
||||||
; %a may be freed between the dereferenceable assumption and accesses.
|
; %a may be freed between the dereferenceable assumption and accesses.
|
||||||
; It is not safe to use with -use-dereferenceable-at-point-semantics.
|
|
||||||
define void @may_free_local_ptr_align_deref_assumption_in_header_constant_trip_count_loop_invariant_ptr(ptr noalias %b, ptr noalias %c) nofree nosync {
|
define void @may_free_local_ptr_align_deref_assumption_in_header_constant_trip_count_loop_invariant_ptr(ptr noalias %b, ptr noalias %c) nofree nosync {
|
||||||
; CHECK-LABEL: define void @may_free_local_ptr_align_deref_assumption_in_header_constant_trip_count_loop_invariant_ptr(
|
; CHECK-LABEL: define void @may_free_local_ptr_align_deref_assumption_in_header_constant_trip_count_loop_invariant_ptr(
|
||||||
; CHECK-SAME: ptr noalias [[B:%.*]], ptr noalias [[C:%.*]]) #[[ATTR1]] {
|
; CHECK-SAME: ptr noalias [[B:%.*]], ptr noalias [[C:%.*]]) #[[ATTR1]] {
|
||||||
|
@ -4,11 +4,37 @@
|
|||||||
define i64 @align_deref_align(i1 %c, ptr %p) {
|
define i64 @align_deref_align(i1 %c, ptr %p) {
|
||||||
; CHECK-LABEL: define i64 @align_deref_align(
|
; CHECK-LABEL: define i64 @align_deref_align(
|
||||||
; CHECK-SAME: i1 [[C:%.*]], ptr [[P:%.*]]) {
|
; CHECK-SAME: i1 [[C:%.*]], ptr [[P:%.*]]) {
|
||||||
|
; CHECK-NEXT: [[ENTRY:.*]]:
|
||||||
|
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 8), "align"(ptr [[P]], i64 8) ]
|
||||||
|
; CHECK-NEXT: br i1 [[C]], label %[[IF:.*]], label %[[EXIT:.*]]
|
||||||
|
; CHECK: [[IF]]:
|
||||||
|
; CHECK-NEXT: [[V:%.*]] = load i64, ptr [[P]], align 8
|
||||||
|
; CHECK-NEXT: br label %[[EXIT]]
|
||||||
|
; CHECK: [[EXIT]]:
|
||||||
|
; CHECK-NEXT: [[RES:%.*]] = phi i64 [ [[V]], %[[IF]] ], [ 0, %[[ENTRY]] ]
|
||||||
|
; CHECK-NEXT: ret i64 [[RES]]
|
||||||
|
;
|
||||||
|
entry:
|
||||||
|
call void @llvm.assume(i1 true) [ "dereferenceable"(ptr %p, i64 8), "align"(ptr %p, i64 8) ]
|
||||||
|
br i1 %c, label %if, label %exit
|
||||||
|
|
||||||
|
if:
|
||||||
|
%v = load i64, ptr %p, align 8
|
||||||
|
br label %exit
|
||||||
|
|
||||||
|
exit:
|
||||||
|
%res = phi i64 [ %v, %if ], [ 0, %entry ]
|
||||||
|
ret i64 %res
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @align_deref_align_nofree_nosync(i1 %c, ptr %p) nofree nosync {
|
||||||
|
; CHECK-LABEL: define i64 @align_deref_align_nofree_nosync(
|
||||||
|
; CHECK-SAME: i1 [[C:%.*]], ptr [[P:%.*]]) #[[ATTR0:[0-9]+]] {
|
||||||
; CHECK-NEXT: [[ENTRY:.*:]]
|
; CHECK-NEXT: [[ENTRY:.*:]]
|
||||||
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 8), "align"(ptr [[P]], i64 8) ]
|
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 8), "align"(ptr [[P]], i64 8) ]
|
||||||
; CHECK-NEXT: [[V:%.*]] = load i64, ptr [[P]], align 8
|
; CHECK-NEXT: [[V:%.*]] = load i64, ptr [[P]], align 8
|
||||||
; CHECK-NEXT: [[RES:%.*]] = select i1 [[C]], i64 [[V]], i64 0
|
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[C]], i64 [[V]], i64 0
|
||||||
; CHECK-NEXT: ret i64 [[RES]]
|
; CHECK-NEXT: ret i64 [[SPEC_SELECT]]
|
||||||
;
|
;
|
||||||
entry:
|
entry:
|
||||||
call void @llvm.assume(i1 true) [ "dereferenceable"(ptr %p, i64 8), "align"(ptr %p, i64 8) ]
|
call void @llvm.assume(i1 true) [ "dereferenceable"(ptr %p, i64 8), "align"(ptr %p, i64 8) ]
|
||||||
@ -26,6 +52,39 @@ exit:
|
|||||||
define i64 @assume_deref_align2(i1 %c1, i32 %x, ptr %p) {
|
define i64 @assume_deref_align2(i1 %c1, i32 %x, ptr %p) {
|
||||||
; CHECK-LABEL: define i64 @assume_deref_align2(
|
; CHECK-LABEL: define i64 @assume_deref_align2(
|
||||||
; CHECK-SAME: i1 [[C1:%.*]], i32 [[X:%.*]], ptr [[P:%.*]]) {
|
; CHECK-SAME: i1 [[C1:%.*]], i32 [[X:%.*]], ptr [[P:%.*]]) {
|
||||||
|
; CHECK-NEXT: [[ENTRY:.*]]:
|
||||||
|
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 8), "align"(ptr [[P]], i64 8) ]
|
||||||
|
; CHECK-NEXT: br i1 [[C1]], label %[[IF1:.*]], label %[[EXIT:.*]]
|
||||||
|
; CHECK: [[IF1]]:
|
||||||
|
; CHECK-NEXT: [[C2:%.*]] = icmp ugt i32 [[X]], 10
|
||||||
|
; CHECK-NEXT: br i1 [[C2]], label %[[IF2:.*]], label %[[EXIT]]
|
||||||
|
; CHECK: [[IF2]]:
|
||||||
|
; CHECK-NEXT: [[V:%.*]] = load i64, ptr [[P]], align 8
|
||||||
|
; CHECK-NEXT: br label %[[EXIT]]
|
||||||
|
; CHECK: [[EXIT]]:
|
||||||
|
; CHECK-NEXT: [[RES:%.*]] = phi i64 [ [[V]], %[[IF2]] ], [ 1, %[[IF1]] ], [ 0, %[[ENTRY]] ]
|
||||||
|
; CHECK-NEXT: ret i64 [[RES]]
|
||||||
|
;
|
||||||
|
entry:
|
||||||
|
call void @llvm.assume(i1 true) [ "dereferenceable"(ptr %p, i64 8), "align"(ptr %p, i64 8) ]
|
||||||
|
br i1 %c1, label %if1, label %exit
|
||||||
|
|
||||||
|
if1:
|
||||||
|
%c2 = icmp ugt i32 %x, 10
|
||||||
|
br i1 %c2, label %if2, label %exit
|
||||||
|
|
||||||
|
if2:
|
||||||
|
%v = load i64, ptr %p, align 8
|
||||||
|
br label %exit
|
||||||
|
|
||||||
|
exit:
|
||||||
|
%res = phi i64 [ %v, %if2 ], [ 1, %if1 ], [ 0, %entry ]
|
||||||
|
ret i64 %res
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @assume_deref_align2_nofree_nosync(i1 %c1, i32 %x, ptr %p) nofree nosync {
|
||||||
|
; CHECK-LABEL: define i64 @assume_deref_align2_nofree_nosync(
|
||||||
|
; CHECK-SAME: i1 [[C1:%.*]], i32 [[X:%.*]], ptr [[P:%.*]]) #[[ATTR0]] {
|
||||||
; CHECK-NEXT: [[ENTRY:.*:]]
|
; CHECK-NEXT: [[ENTRY:.*:]]
|
||||||
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 8), "align"(ptr [[P]], i64 8) ]
|
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 8), "align"(ptr [[P]], i64 8) ]
|
||||||
; CHECK-NEXT: [[C2:%.*]] = icmp ugt i32 [[X]], 10
|
; CHECK-NEXT: [[C2:%.*]] = icmp ugt i32 [[X]], 10
|
||||||
@ -51,9 +110,10 @@ exit:
|
|||||||
ret i64 %res
|
ret i64 %res
|
||||||
}
|
}
|
||||||
|
|
||||||
define i64 @assume_deref_align_not_dominating(i1 %c, ptr %p) {
|
|
||||||
|
define i64 @assume_deref_align_not_dominating(i1 %c, ptr %p) nofree nosync {
|
||||||
; CHECK-LABEL: define i64 @assume_deref_align_not_dominating(
|
; CHECK-LABEL: define i64 @assume_deref_align_not_dominating(
|
||||||
; CHECK-SAME: i1 [[C:%.*]], ptr [[P:%.*]]) {
|
; CHECK-SAME: i1 [[C:%.*]], ptr [[P:%.*]]) #[[ATTR0]] {
|
||||||
; CHECK-NEXT: [[ENTRY:.*]]:
|
; CHECK-NEXT: [[ENTRY:.*]]:
|
||||||
; CHECK-NEXT: br i1 [[C]], label %[[IF:.*]], label %[[EXIT:.*]]
|
; CHECK-NEXT: br i1 [[C]], label %[[IF:.*]], label %[[EXIT:.*]]
|
||||||
; CHECK: [[IF]]:
|
; CHECK: [[IF]]:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user