forked from OSchip/llvm-project
[Attributor][FIX] Make value simplification aware of "complicated" attributes
We cannot simply replace arguments that carry attributes like `nest`, `inalloca`, `sret`, and `byval`. Except for the last one, which we can replace if it is not written, we bail for now.
This commit is contained in:
parent
c36e2ebf9f
commit
15cd90a2c4
|
@ -3628,8 +3628,26 @@ protected:
|
||||||
struct AAValueSimplifyArgument final : AAValueSimplifyImpl {
|
struct AAValueSimplifyArgument final : AAValueSimplifyImpl {
|
||||||
AAValueSimplifyArgument(const IRPosition &IRP) : AAValueSimplifyImpl(IRP) {}
|
AAValueSimplifyArgument(const IRPosition &IRP) : AAValueSimplifyImpl(IRP) {}
|
||||||
|
|
||||||
|
void initialize(Attributor &A) override {
|
||||||
|
AAValueSimplifyImpl::initialize(A);
|
||||||
|
if (!getAssociatedFunction() || getAssociatedFunction()->isDeclaration())
|
||||||
|
indicatePessimisticFixpoint();
|
||||||
|
if (hasAttr({Attribute::InAlloca, Attribute::StructRet, Attribute::Nest},
|
||||||
|
/* IgnoreSubsumingPositions */ true))
|
||||||
|
indicatePessimisticFixpoint();
|
||||||
|
}
|
||||||
|
|
||||||
/// See AbstractAttribute::updateImpl(...).
|
/// See AbstractAttribute::updateImpl(...).
|
||||||
ChangeStatus updateImpl(Attributor &A) override {
|
ChangeStatus updateImpl(Attributor &A) override {
|
||||||
|
// Byval is only replacable if it is readonly otherwise we would write into
|
||||||
|
// the replaced value and not the copy that byval creates implicitly.
|
||||||
|
Argument *Arg = getAssociatedArgument();
|
||||||
|
if (Arg->hasByValAttr()) {
|
||||||
|
const auto &MemAA = A.getAAFor<AAMemoryBehavior>(*this, getIRPosition());
|
||||||
|
if (!MemAA.isAssumedReadOnly())
|
||||||
|
return indicatePessimisticFixpoint();
|
||||||
|
}
|
||||||
|
|
||||||
bool HasValueBefore = SimplifiedAssociatedValue.hasValue();
|
bool HasValueBefore = SimplifiedAssociatedValue.hasValue();
|
||||||
|
|
||||||
auto PredForCallSite = [&](AbstractCallSite ACS) {
|
auto PredForCallSite = [&](AbstractCallSite ACS) {
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||||
; RUN: opt -attributor --attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s
|
; RUN: opt -attributor --attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s
|
||||||
; TODO: Add max-iteration check
|
; TODO: Add max-iteration check
|
||||||
|
|
||||||
|
; Disable update test checks and enable it where required.
|
||||||
|
; UTC_ARGS: --turn off
|
||||||
|
|
||||||
; ModuleID = 'value-simplify.ll'
|
; ModuleID = 'value-simplify.ll'
|
||||||
source_filename = "value-simplify.ll"
|
source_filename = "value-simplify.ll"
|
||||||
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
|
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
|
||||||
|
@ -192,3 +196,81 @@ define i32 @ipccp3() {
|
||||||
%r = call i32 @ipccp3i(i32 7)
|
%r = call i32 @ipccp3i(i32 7)
|
||||||
ret i32 %r
|
ret i32 %r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
; UTC_ARGS: --turn on
|
||||||
|
|
||||||
|
; Do not touch complicated arguments (for now)
|
||||||
|
%struct.X = type { i8* }
|
||||||
|
define internal i32* @test_inalloca(i32* inalloca %a) {
|
||||||
|
; CHECK-LABEL: define {{[^@]+}}@test_inalloca
|
||||||
|
; CHECK-SAME: (i32* inalloca noalias returned writeonly [[A:%.*]])
|
||||||
|
; CHECK-NEXT: ret i32* [[A]]
|
||||||
|
;
|
||||||
|
ret i32* %a
|
||||||
|
}
|
||||||
|
define i32* @complicated_args_inalloca() {
|
||||||
|
; CHECK-LABEL: define {{[^@]+}}@complicated_args_inalloca()
|
||||||
|
; CHECK-NEXT: [[CALL:%.*]] = call i32* @test_inalloca(i32* noalias null)
|
||||||
|
; CHECK-NEXT: ret i32* [[CALL]]
|
||||||
|
;
|
||||||
|
%call = call i32* @test_inalloca(i32* null)
|
||||||
|
ret i32* %call
|
||||||
|
}
|
||||||
|
|
||||||
|
define internal void @test_sret(%struct.X* sret %a, %struct.X** %b) {
|
||||||
|
; CHECK-LABEL: define {{[^@]+}}@test_sret
|
||||||
|
; CHECK-SAME: (%struct.X* sret writeonly [[A:%.*]], %struct.X** nocapture nonnull writeonly dereferenceable(8) [[B:%.*]])
|
||||||
|
; CHECK-NEXT: store %struct.X* [[A]], %struct.X** [[B]]
|
||||||
|
; CHECK-NEXT: ret void
|
||||||
|
;
|
||||||
|
store %struct.X* %a, %struct.X** %b
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
define void @complicated_args_sret(%struct.X** %b) {
|
||||||
|
; CHECK-LABEL: define {{[^@]+}}@complicated_args_sret
|
||||||
|
; CHECK-SAME: (%struct.X** nocapture writeonly [[B:%.*]])
|
||||||
|
; CHECK-NEXT: call void @test_sret(%struct.X* null, %struct.X** nocapture writeonly [[B]])
|
||||||
|
; CHECK-NEXT: ret void
|
||||||
|
;
|
||||||
|
call void @test_sret(%struct.X* null, %struct.X** %b)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define internal %struct.X* @test_nest(%struct.X* nest %a) {
|
||||||
|
; CHECK-LABEL: define {{[^@]+}}@test_nest
|
||||||
|
; CHECK-SAME: (%struct.X* nest noalias readnone returned [[A:%.*]])
|
||||||
|
; CHECK-NEXT: ret %struct.X* [[A]]
|
||||||
|
;
|
||||||
|
ret %struct.X* %a
|
||||||
|
}
|
||||||
|
define %struct.X* @complicated_args_nest() {
|
||||||
|
; CHECK-LABEL: define {{[^@]+}}@complicated_args_nest()
|
||||||
|
; CHECK-NEXT: [[CALL:%.*]] = call %struct.X* @test_nest(%struct.X* noalias null)
|
||||||
|
; CHECK-NEXT: ret %struct.X* [[CALL]]
|
||||||
|
;
|
||||||
|
%call = call %struct.X* @test_nest(%struct.X* null)
|
||||||
|
ret %struct.X* %call
|
||||||
|
}
|
||||||
|
|
||||||
|
@S = external global %struct.X
|
||||||
|
define internal void @test_byval(%struct.X* byval %a) {
|
||||||
|
; CHECK-LABEL: define {{[^@]+}}@test_byval
|
||||||
|
; CHECK-SAME: (%struct.X* nocapture nonnull writeonly byval align 8 dereferenceable(8) [[A:%.*]])
|
||||||
|
; CHECK-NEXT: [[G0:%.*]] = getelementptr [[STRUCT_X:%.*]], %struct.X* [[A]], i32 0, i32 0
|
||||||
|
; CHECK-NEXT: store i8* null, i8** [[G0]], align 8
|
||||||
|
; CHECK-NEXT: ret void
|
||||||
|
;
|
||||||
|
%g0 = getelementptr %struct.X, %struct.X* %a, i32 0, i32 0
|
||||||
|
store i8* null, i8** %g0
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
define void @complicated_args_byval() {
|
||||||
|
; CHECK-LABEL: define {{[^@]+}}@complicated_args_byval()
|
||||||
|
; CHECK-NEXT: call void @test_byval(%struct.X* nonnull align 8 dereferenceable(8) @S)
|
||||||
|
; CHECK-NEXT: ret void
|
||||||
|
;
|
||||||
|
call void @test_byval(%struct.X* @S)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
; UTC_ARGS: --turn off
|
||||||
|
|
Loading…
Reference in New Issue