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 {
|
||||
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(...).
|
||||
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();
|
||||
|
||||
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
|
||||
; TODO: Add max-iteration check
|
||||
|
||||
; Disable update test checks and enable it where required.
|
||||
; UTC_ARGS: --turn off
|
||||
|
||||
; ModuleID = 'value-simplify.ll'
|
||||
source_filename = "value-simplify.ll"
|
||||
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)
|
||||
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