2019-07-05 17:49:53 +00:00
|
|
|
; RUN: opt < %s -inferattrs -S | FileCheck %s
|
[Attributor][MustExec] Deduce dereferenceable and nonnull attribute using MustBeExecutedContextExplorer
Summary:
In D65186 and related patches, MustBeExecutedContextExplorer is introduced. This enables us to traverse instructions guaranteed to execute from function entry. If we can know the argument is used as `dereferenceable` or `nonnull` in these instructions, we can mark `dereferenceable` or `nonnull` in the argument definition:
1. Memory instruction (similar to D64258)
Trace memory instruction pointer operand. Currently, only inbounds GEPs are traced.
```
define i64* @f(i64* %a) {
entry:
%add.ptr = getelementptr inbounds i64, i64* %a, i64 1
; (because of inbounds GEP we can know that %a is at least dereferenceable(16))
store i64 1, i64* %add.ptr, align 8
ret i64* %add.ptr ; dereferenceable 8 (because above instruction stores into it)
}
```
2. Propagation from callsite (similar to D27855)
If `deref` or `nonnull` are known in call site parameter attributes we can also say that argument also that attribute.
```
declare void @use3(i8* %x, i8* %y, i8* %z);
declare void @use3nonnull(i8* nonnull %x, i8* nonnull %y, i8* nonnull %z);
define void @parent1(i8* %a, i8* %b, i8* %c) {
call void @use3nonnull(i8* %b, i8* %c, i8* %a)
; Above instruction is always executed so we can say that@parent1(i8* nonnnull %a, i8* nonnull %b, i8* nonnull %c)
call void @use3(i8* %c, i8* %a, i8* %b)
ret void
}
```
Reviewers: jdoerfert, sstefan1, spatel, reames
Reviewed By: jdoerfert
Subscribers: xbolva00, hiraditya, jfb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65402
llvm-svn: 374063
2019-10-08 15:25:56 +00:00
|
|
|
|
|
|
|
|
2019-07-05 17:49:53 +00:00
|
|
|
|
|
|
|
; Determine dereference-ability before unused loads get deleted:
|
|
|
|
; https://bugs.llvm.org/show_bug.cgi?id=21780
|
|
|
|
|
|
|
|
define <4 x double> @PR21780(double* %ptr) {
|
|
|
|
; CHECK-LABEL: @PR21780(double* %ptr)
|
[Attributor][MustExec] Deduce dereferenceable and nonnull attribute using MustBeExecutedContextExplorer
Summary:
In D65186 and related patches, MustBeExecutedContextExplorer is introduced. This enables us to traverse instructions guaranteed to execute from function entry. If we can know the argument is used as `dereferenceable` or `nonnull` in these instructions, we can mark `dereferenceable` or `nonnull` in the argument definition:
1. Memory instruction (similar to D64258)
Trace memory instruction pointer operand. Currently, only inbounds GEPs are traced.
```
define i64* @f(i64* %a) {
entry:
%add.ptr = getelementptr inbounds i64, i64* %a, i64 1
; (because of inbounds GEP we can know that %a is at least dereferenceable(16))
store i64 1, i64* %add.ptr, align 8
ret i64* %add.ptr ; dereferenceable 8 (because above instruction stores into it)
}
```
2. Propagation from callsite (similar to D27855)
If `deref` or `nonnull` are known in call site parameter attributes we can also say that argument also that attribute.
```
declare void @use3(i8* %x, i8* %y, i8* %z);
declare void @use3nonnull(i8* nonnull %x, i8* nonnull %y, i8* nonnull %z);
define void @parent1(i8* %a, i8* %b, i8* %c) {
call void @use3nonnull(i8* %b, i8* %c, i8* %a)
; Above instruction is always executed so we can say that@parent1(i8* nonnnull %a, i8* nonnull %b, i8* nonnull %c)
call void @use3(i8* %c, i8* %a, i8* %b)
ret void
}
```
Reviewers: jdoerfert, sstefan1, spatel, reames
Reviewed By: jdoerfert
Subscribers: xbolva00, hiraditya, jfb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65402
llvm-svn: 374063
2019-10-08 15:25:56 +00:00
|
|
|
|
2019-07-05 17:49:53 +00:00
|
|
|
; GEP of index 0 is simplified away.
|
|
|
|
%arrayidx1 = getelementptr inbounds double, double* %ptr, i64 1
|
|
|
|
%arrayidx2 = getelementptr inbounds double, double* %ptr, i64 2
|
|
|
|
%arrayidx3 = getelementptr inbounds double, double* %ptr, i64 3
|
|
|
|
|
|
|
|
%t0 = load double, double* %ptr, align 8
|
|
|
|
%t1 = load double, double* %arrayidx1, align 8
|
|
|
|
%t2 = load double, double* %arrayidx2, align 8
|
|
|
|
%t3 = load double, double* %arrayidx3, align 8
|
|
|
|
|
|
|
|
%vecinit0 = insertelement <4 x double> undef, double %t0, i32 0
|
|
|
|
%vecinit1 = insertelement <4 x double> %vecinit0, double %t1, i32 1
|
|
|
|
%vecinit2 = insertelement <4 x double> %vecinit1, double %t2, i32 2
|
|
|
|
%vecinit3 = insertelement <4 x double> %vecinit2, double %t3, i32 3
|
|
|
|
%shuffle = shufflevector <4 x double> %vecinit3, <4 x double> %vecinit3, <4 x i32> <i32 0, i32 0, i32 2, i32 2>
|
|
|
|
ret <4 x double> %shuffle
|
|
|
|
}
|
|
|
|
|
[Attributor][MustExec] Deduce dereferenceable and nonnull attribute using MustBeExecutedContextExplorer
Summary:
In D65186 and related patches, MustBeExecutedContextExplorer is introduced. This enables us to traverse instructions guaranteed to execute from function entry. If we can know the argument is used as `dereferenceable` or `nonnull` in these instructions, we can mark `dereferenceable` or `nonnull` in the argument definition:
1. Memory instruction (similar to D64258)
Trace memory instruction pointer operand. Currently, only inbounds GEPs are traced.
```
define i64* @f(i64* %a) {
entry:
%add.ptr = getelementptr inbounds i64, i64* %a, i64 1
; (because of inbounds GEP we can know that %a is at least dereferenceable(16))
store i64 1, i64* %add.ptr, align 8
ret i64* %add.ptr ; dereferenceable 8 (because above instruction stores into it)
}
```
2. Propagation from callsite (similar to D27855)
If `deref` or `nonnull` are known in call site parameter attributes we can also say that argument also that attribute.
```
declare void @use3(i8* %x, i8* %y, i8* %z);
declare void @use3nonnull(i8* nonnull %x, i8* nonnull %y, i8* nonnull %z);
define void @parent1(i8* %a, i8* %b, i8* %c) {
call void @use3nonnull(i8* %b, i8* %c, i8* %a)
; Above instruction is always executed so we can say that@parent1(i8* nonnnull %a, i8* nonnull %b, i8* nonnull %c)
call void @use3(i8* %c, i8* %a, i8* %b)
ret void
}
```
Reviewers: jdoerfert, sstefan1, spatel, reames
Reviewed By: jdoerfert
Subscribers: xbolva00, hiraditya, jfb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65402
llvm-svn: 374063
2019-10-08 15:25:56 +00:00
|
|
|
|
|
|
|
define double @PR21780_only_access3_with_inbounds(double* %ptr) {
|
|
|
|
; CHECK-LABEL: @PR21780_only_access3_with_inbounds(double* %ptr)
|
|
|
|
|
|
|
|
%arrayidx3 = getelementptr inbounds double, double* %ptr, i64 3
|
|
|
|
%t3 = load double, double* %arrayidx3, align 8
|
|
|
|
ret double %t3
|
|
|
|
}
|
|
|
|
|
|
|
|
define double @PR21780_only_access3_without_inbounds(double* %ptr) {
|
|
|
|
; CHECK-LABEL: @PR21780_only_access3_without_inbounds(double* %ptr)
|
|
|
|
%arrayidx3 = getelementptr double, double* %ptr, i64 3
|
|
|
|
%t3 = load double, double* %arrayidx3, align 8
|
|
|
|
ret double %t3
|
|
|
|
}
|
|
|
|
|
|
|
|
define double @PR21780_without_inbounds(double* %ptr) {
|
|
|
|
; CHECK-LABEL: @PR21780_without_inbounds(double* %ptr)
|
|
|
|
|
|
|
|
%arrayidx1 = getelementptr double, double* %ptr, i64 1
|
|
|
|
%arrayidx2 = getelementptr double, double* %ptr, i64 2
|
|
|
|
%arrayidx3 = getelementptr double, double* %ptr, i64 3
|
|
|
|
|
|
|
|
%t0 = load double, double* %ptr, align 8
|
|
|
|
%t1 = load double, double* %arrayidx1, align 8
|
|
|
|
%t2 = load double, double* %arrayidx2, align 8
|
|
|
|
%t3 = load double, double* %arrayidx3, align 8
|
|
|
|
|
|
|
|
ret double %t3
|
|
|
|
}
|
|
|
|
|
2019-07-05 17:49:53 +00:00
|
|
|
; Unsimplified, but still valid. Also, throw in some bogus arguments.
|
|
|
|
|
|
|
|
define void @gep0(i8* %unused, i8* %other, i8* %ptr) {
|
|
|
|
; CHECK-LABEL: @gep0(i8* %unused, i8* %other, i8* %ptr)
|
|
|
|
%arrayidx0 = getelementptr i8, i8* %ptr, i64 0
|
|
|
|
%arrayidx1 = getelementptr i8, i8* %ptr, i64 1
|
|
|
|
%arrayidx2 = getelementptr i8, i8* %ptr, i64 2
|
|
|
|
%t0 = load i8, i8* %arrayidx0
|
|
|
|
%t1 = load i8, i8* %arrayidx1
|
|
|
|
%t2 = load i8, i8* %arrayidx2
|
|
|
|
store i8 %t2, i8* %other
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
|
|
|
; Order of accesses does not change computation.
|
2019-07-09 14:43:03 +00:00
|
|
|
; Multiple arguments may be dereferenceable.
|
|
|
|
|
|
|
|
define void @ordering(i8* %ptr1, i32* %ptr2) {
|
|
|
|
; CHECK-LABEL: @ordering(i8* %ptr1, i32* %ptr2)
|
|
|
|
%a20 = getelementptr i32, i32* %ptr2, i64 0
|
|
|
|
%a12 = getelementptr i8, i8* %ptr1, i64 2
|
|
|
|
%t12 = load i8, i8* %a12
|
|
|
|
%a11 = getelementptr i8, i8* %ptr1, i64 1
|
|
|
|
%t20 = load i32, i32* %a20
|
|
|
|
%a10 = getelementptr i8, i8* %ptr1, i64 0
|
|
|
|
%t10 = load i8, i8* %a10
|
|
|
|
%t11 = load i8, i8* %a11
|
|
|
|
%a21 = getelementptr i32, i32* %ptr2, i64 1
|
|
|
|
%t21 = load i32, i32* %a21
|
2019-07-05 17:49:53 +00:00
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
|
|
|
; Not in entry block.
|
|
|
|
|
|
|
|
define void @not_entry_but_guaranteed_to_execute(i8* %ptr) {
|
|
|
|
; CHECK-LABEL: @not_entry_but_guaranteed_to_execute(i8* %ptr)
|
|
|
|
entry:
|
|
|
|
br label %exit
|
|
|
|
exit:
|
|
|
|
%arrayidx0 = getelementptr i8, i8* %ptr, i64 0
|
|
|
|
%arrayidx1 = getelementptr i8, i8* %ptr, i64 1
|
|
|
|
%arrayidx2 = getelementptr i8, i8* %ptr, i64 2
|
|
|
|
%t0 = load i8, i8* %arrayidx0
|
|
|
|
%t1 = load i8, i8* %arrayidx1
|
|
|
|
%t2 = load i8, i8* %arrayidx2
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
|
|
|
; Not in entry block and not guaranteed to execute.
|
|
|
|
|
|
|
|
define void @not_entry_not_guaranteed_to_execute(i8* %ptr, i1 %cond) {
|
|
|
|
; CHECK-LABEL: @not_entry_not_guaranteed_to_execute(i8* %ptr, i1 %cond)
|
|
|
|
entry:
|
|
|
|
br i1 %cond, label %loads, label %exit
|
|
|
|
loads:
|
|
|
|
%arrayidx0 = getelementptr i8, i8* %ptr, i64 0
|
|
|
|
%arrayidx1 = getelementptr i8, i8* %ptr, i64 1
|
|
|
|
%arrayidx2 = getelementptr i8, i8* %ptr, i64 2
|
|
|
|
%t0 = load i8, i8* %arrayidx0
|
|
|
|
%t1 = load i8, i8* %arrayidx1
|
|
|
|
%t2 = load i8, i8* %arrayidx2
|
|
|
|
ret void
|
|
|
|
exit:
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
|
|
|
; The last load may not execute, so derefenceable bytes only covers the 1st two loads.
|
|
|
|
|
|
|
|
define void @partial_in_entry(i16* %ptr, i1 %cond) {
|
|
|
|
; CHECK-LABEL: @partial_in_entry(i16* %ptr, i1 %cond)
|
|
|
|
entry:
|
|
|
|
%arrayidx0 = getelementptr i16, i16* %ptr, i64 0
|
|
|
|
%arrayidx1 = getelementptr i16, i16* %ptr, i64 1
|
|
|
|
%arrayidx2 = getelementptr i16, i16* %ptr, i64 2
|
|
|
|
%t0 = load i16, i16* %arrayidx0
|
|
|
|
%t1 = load i16, i16* %arrayidx1
|
|
|
|
br i1 %cond, label %loads, label %exit
|
|
|
|
loads:
|
|
|
|
%t2 = load i16, i16* %arrayidx2
|
|
|
|
ret void
|
|
|
|
exit:
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
2019-07-10 14:41:47 +00:00
|
|
|
; The volatile load can't be used to prove a non-volatile access is allowed.
|
|
|
|
; The 2nd and 3rd loads may never execute.
|
2019-07-05 17:49:53 +00:00
|
|
|
|
2019-07-10 14:41:47 +00:00
|
|
|
define void @volatile_is_not_dereferenceable(i16* %ptr) {
|
|
|
|
; CHECK-LABEL: @volatile_is_not_dereferenceable(i16* %ptr)
|
2019-07-05 17:49:53 +00:00
|
|
|
%arrayidx0 = getelementptr i16, i16* %ptr, i64 0
|
|
|
|
%arrayidx1 = getelementptr i16, i16* %ptr, i64 1
|
|
|
|
%arrayidx2 = getelementptr i16, i16* %ptr, i64 2
|
|
|
|
%t0 = load volatile i16, i16* %arrayidx0
|
|
|
|
%t1 = load i16, i16* %arrayidx1
|
|
|
|
%t2 = load i16, i16* %arrayidx2
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
2019-11-26 09:07:17 -05:00
|
|
|
; TODO: We should allow inference for atomic (but not volatile) ops.
|
|
|
|
|
|
|
|
define void @atomic_is_alright(i16* %ptr) {
|
|
|
|
; CHECK-LABEL: @atomic_is_alright(i16* %ptr)
|
|
|
|
%arrayidx0 = getelementptr i16, i16* %ptr, i64 0
|
|
|
|
%arrayidx1 = getelementptr i16, i16* %ptr, i64 1
|
|
|
|
%arrayidx2 = getelementptr i16, i16* %ptr, i64 2
|
|
|
|
%t0 = load atomic i16, i16* %arrayidx0 unordered, align 2
|
|
|
|
%t1 = load i16, i16* %arrayidx1
|
|
|
|
%t2 = load i16, i16* %arrayidx2
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
2019-07-10 14:41:47 +00:00
|
|
|
declare void @may_not_return()
|
|
|
|
|
|
|
|
define void @not_guaranteed_to_transfer_execution(i16* %ptr) {
|
|
|
|
; CHECK-LABEL: @not_guaranteed_to_transfer_execution(i16* %ptr)
|
|
|
|
%arrayidx0 = getelementptr i16, i16* %ptr, i64 0
|
|
|
|
%arrayidx1 = getelementptr i16, i16* %ptr, i64 1
|
|
|
|
%arrayidx2 = getelementptr i16, i16* %ptr, i64 2
|
|
|
|
%t0 = load i16, i16* %arrayidx0
|
|
|
|
call void @may_not_return()
|
|
|
|
%t1 = load i16, i16* %arrayidx1
|
|
|
|
%t2 = load i16, i16* %arrayidx2
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
2019-07-05 17:49:53 +00:00
|
|
|
; We must have consecutive accesses.
|
|
|
|
|
|
|
|
define void @variable_gep_index(i8* %unused, i8* %ptr, i64 %variable_index) {
|
|
|
|
; CHECK-LABEL: @variable_gep_index(i8* %unused, i8* %ptr, i64 %variable_index)
|
|
|
|
%arrayidx1 = getelementptr i8, i8* %ptr, i64 %variable_index
|
|
|
|
%arrayidx2 = getelementptr i8, i8* %ptr, i64 2
|
|
|
|
%t0 = load i8, i8* %ptr
|
|
|
|
%t1 = load i8, i8* %arrayidx1
|
|
|
|
%t2 = load i8, i8* %arrayidx2
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
|
|
|
; Deal with >1 GEP index.
|
|
|
|
|
|
|
|
define void @multi_index_gep(<4 x i8>* %ptr) {
|
|
|
|
; CHECK-LABEL: @multi_index_gep(<4 x i8>* %ptr)
|
[Attributor] Deduce dereferenceable based on accessed bytes map
Summary:
This patch introduces the deduction based on load/store instructions whose pointer operand is a non-inbounds GEP instruction.
For example if we have,
```
void f(int *u){
u[0] = 0;
u[1] = 1;
u[2] = 2;
}
```
then u must be dereferenceable(12).
This patch is inspired by D64258
Reviewers: jdoerfert, spatel, hfinkel, RKSimon, sstefan1, xbolva00, dtemirbulatov
Reviewed By: jdoerfert
Subscribers: jfb, lebedev.ri, xbolva00, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D70714
2019-11-29 06:55:58 +00:00
|
|
|
; FIXME: %ptr should be dereferenceable(4)
|
2019-07-05 17:49:53 +00:00
|
|
|
%arrayidx00 = getelementptr <4 x i8>, <4 x i8>* %ptr, i64 0, i64 0
|
|
|
|
%t0 = load i8, i8* %arrayidx00
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
|
|
|
; Could round weird bitwidths down?
|
|
|
|
|
|
|
|
define void @not_byte_multiple(i9* %ptr) {
|
|
|
|
; CHECK-LABEL: @not_byte_multiple(i9* %ptr)
|
|
|
|
%arrayidx0 = getelementptr i9, i9* %ptr, i64 0
|
|
|
|
%t0 = load i9, i9* %arrayidx0
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
|
|
|
; Missing direct access from the pointer.
|
|
|
|
|
|
|
|
define void @no_pointer_deref(i16* %ptr) {
|
|
|
|
; CHECK-LABEL: @no_pointer_deref(i16* %ptr)
|
|
|
|
%arrayidx1 = getelementptr i16, i16* %ptr, i64 1
|
|
|
|
%arrayidx2 = getelementptr i16, i16* %ptr, i64 2
|
|
|
|
%t1 = load i16, i16* %arrayidx1
|
|
|
|
%t2 = load i16, i16* %arrayidx2
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
|
|
|
; Out-of-order is ok, but missing access concludes dereferenceable range.
|
|
|
|
|
|
|
|
define void @non_consecutive(i32* %ptr) {
|
|
|
|
; CHECK-LABEL: @non_consecutive(i32* %ptr)
|
|
|
|
%arrayidx1 = getelementptr i32, i32* %ptr, i64 1
|
|
|
|
%arrayidx0 = getelementptr i32, i32* %ptr, i64 0
|
|
|
|
%arrayidx3 = getelementptr i32, i32* %ptr, i64 3
|
|
|
|
%t1 = load i32, i32* %arrayidx1
|
|
|
|
%t0 = load i32, i32* %arrayidx0
|
|
|
|
%t3 = load i32, i32* %arrayidx3
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
|
|
|
; Improve on existing dereferenceable attribute.
|
|
|
|
|
|
|
|
define void @more_bytes(i32* dereferenceable(8) %ptr) {
|
|
|
|
; CHECK-LABEL: @more_bytes(i32* dereferenceable(8) %ptr)
|
|
|
|
%arrayidx3 = getelementptr i32, i32* %ptr, i64 3
|
|
|
|
%arrayidx1 = getelementptr i32, i32* %ptr, i64 1
|
|
|
|
%arrayidx0 = getelementptr i32, i32* %ptr, i64 0
|
|
|
|
%arrayidx2 = getelementptr i32, i32* %ptr, i64 2
|
|
|
|
%t3 = load i32, i32* %arrayidx3
|
|
|
|
%t1 = load i32, i32* %arrayidx1
|
|
|
|
%t2 = load i32, i32* %arrayidx2
|
|
|
|
%t0 = load i32, i32* %arrayidx0
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
2019-11-26 09:07:17 -05:00
|
|
|
; Improve on existing dereferenceable_or_null attribute.
|
|
|
|
|
|
|
|
define void @more_bytes_and_not_null(i32* dereferenceable_or_null(8) %ptr) {
|
|
|
|
; CHECK-LABEL: @more_bytes_and_not_null(i32* dereferenceable_or_null(8) %ptr)
|
|
|
|
%arrayidx3 = getelementptr i32, i32* %ptr, i64 3
|
|
|
|
%arrayidx1 = getelementptr i32, i32* %ptr, i64 1
|
|
|
|
%arrayidx0 = getelementptr i32, i32* %ptr, i64 0
|
|
|
|
%arrayidx2 = getelementptr i32, i32* %ptr, i64 2
|
|
|
|
%t3 = load i32, i32* %arrayidx3
|
|
|
|
%t1 = load i32, i32* %arrayidx1
|
|
|
|
%t2 = load i32, i32* %arrayidx2
|
|
|
|
%t0 = load i32, i32* %arrayidx0
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
2019-07-05 17:49:53 +00:00
|
|
|
; But don't pessimize existing dereferenceable attribute.
|
|
|
|
|
|
|
|
define void @better_bytes(i32* dereferenceable(100) %ptr) {
|
|
|
|
; CHECK-LABEL: @better_bytes(i32* dereferenceable(100) %ptr)
|
|
|
|
%arrayidx3 = getelementptr i32, i32* %ptr, i64 3
|
|
|
|
%arrayidx1 = getelementptr i32, i32* %ptr, i64 1
|
|
|
|
%arrayidx0 = getelementptr i32, i32* %ptr, i64 0
|
|
|
|
%arrayidx2 = getelementptr i32, i32* %ptr, i64 2
|
|
|
|
%t3 = load i32, i32* %arrayidx3
|
|
|
|
%t1 = load i32, i32* %arrayidx1
|
|
|
|
%t2 = load i32, i32* %arrayidx2
|
|
|
|
%t0 = load i32, i32* %arrayidx0
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
2019-07-09 14:43:03 +00:00
|
|
|
define void @bitcast(i32* %arg) {
|
|
|
|
; CHECK-LABEL: @bitcast(i32* %arg)
|
|
|
|
%ptr = bitcast i32* %arg to float*
|
|
|
|
%arrayidx0 = getelementptr float, float* %ptr, i64 0
|
|
|
|
%arrayidx1 = getelementptr float, float* %ptr, i64 1
|
|
|
|
%t0 = load float, float* %arrayidx0
|
|
|
|
%t1 = load float, float* %arrayidx1
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
|
|
|
define void @bitcast_different_sizes(double* %arg1, i8* %arg2) {
|
|
|
|
; CHECK-LABEL: @bitcast_different_sizes(double* %arg1, i8* %arg2)
|
|
|
|
%ptr1 = bitcast double* %arg1 to float*
|
|
|
|
%a10 = getelementptr float, float* %ptr1, i64 0
|
|
|
|
%a11 = getelementptr float, float* %ptr1, i64 1
|
|
|
|
%a12 = getelementptr float, float* %ptr1, i64 2
|
|
|
|
%ld10 = load float, float* %a10
|
|
|
|
%ld11 = load float, float* %a11
|
|
|
|
%ld12 = load float, float* %a12
|
|
|
|
|
|
|
|
%ptr2 = bitcast i8* %arg2 to i64*
|
|
|
|
%a20 = getelementptr i64, i64* %ptr2, i64 0
|
|
|
|
%a21 = getelementptr i64, i64* %ptr2, i64 1
|
|
|
|
%ld20 = load i64, i64* %a20
|
|
|
|
%ld21 = load i64, i64* %a21
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
|
|
|
define void @negative_offset(i32* %arg) {
|
|
|
|
; CHECK-LABEL: @negative_offset(i32* %arg)
|
|
|
|
%ptr = bitcast i32* %arg to float*
|
|
|
|
%arrayidx0 = getelementptr float, float* %ptr, i64 0
|
|
|
|
%arrayidx1 = getelementptr float, float* %ptr, i64 -1
|
|
|
|
%t0 = load float, float* %arrayidx0
|
|
|
|
%t1 = load float, float* %arrayidx1
|
|
|
|
ret void
|
|
|
|
}
|
2019-07-10 14:41:47 +00:00
|
|
|
|
|
|
|
define void @stores(i32* %arg) {
|
|
|
|
; CHECK-LABEL: @stores(i32* %arg)
|
|
|
|
%ptr = bitcast i32* %arg to float*
|
|
|
|
%arrayidx0 = getelementptr float, float* %ptr, i64 0
|
|
|
|
%arrayidx1 = getelementptr float, float* %ptr, i64 1
|
|
|
|
store float 1.0, float* %arrayidx0
|
|
|
|
store float 2.0, float* %arrayidx1
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
|
|
|
define void @load_store(i32* %arg) {
|
|
|
|
; CHECK-LABEL: @load_store(i32* %arg)
|
|
|
|
%ptr = bitcast i32* %arg to float*
|
|
|
|
%arrayidx0 = getelementptr float, float* %ptr, i64 0
|
|
|
|
%arrayidx1 = getelementptr float, float* %ptr, i64 1
|
|
|
|
%t1 = load float, float* %arrayidx0
|
|
|
|
store float 2.0, float* %arrayidx1
|
|
|
|
ret void
|
|
|
|
}
|
[Attributor] Deduce dereferenceable based on accessed bytes map
Summary:
This patch introduces the deduction based on load/store instructions whose pointer operand is a non-inbounds GEP instruction.
For example if we have,
```
void f(int *u){
u[0] = 0;
u[1] = 1;
u[2] = 2;
}
```
then u must be dereferenceable(12).
This patch is inspired by D64258
Reviewers: jdoerfert, spatel, hfinkel, RKSimon, sstefan1, xbolva00, dtemirbulatov
Reviewed By: jdoerfert
Subscribers: jfb, lebedev.ri, xbolva00, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D70714
2019-11-29 06:55:58 +00:00
|
|
|
|
|
|
|
define void @different_size1(i32* %arg) {
|
|
|
|
; CHECK-LABEL: @different_size1(i32* %arg)
|
|
|
|
%arg-cast = bitcast i32* %arg to double*
|
|
|
|
store double 0.000000e+00, double* %arg-cast
|
|
|
|
store i32 0, i32* %arg
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
|
|
|
define void @different_size2(i32* %arg) {
|
|
|
|
; CHECK-LABEL: @different_size2(i32* %arg)
|
|
|
|
store i32 0, i32* %arg
|
|
|
|
%arg-cast = bitcast i32* %arg to double*
|
|
|
|
store double 0.000000e+00, double* %arg-cast
|
|
|
|
ret void
|
|
|
|
}
|