Skip to content

Commit 963f898

Browse files
author
git apple-llvm automerger
committed
Merge commit '6b8ed78719d0' from llvm.org/main into next
2 parents 3e25f3d + 6b8ed78 commit 963f898

File tree

17 files changed

+210
-19
lines changed

17 files changed

+210
-19
lines changed

llvm/docs/LangRef.rst

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1532,6 +1532,30 @@ Currently, only the following parameter attributes are defined:
15321532
If a function reads from a writeonly pointer argument, the behavior is
15331533
undefined.
15341534

1535+
``writable``
1536+
This attribute is only meaningful in conjunction with ``dereferenceable(N)``
1537+
or another attribute that implies the first ``N`` bytes of the pointer
1538+
argument are dereferenceable.
1539+
1540+
In that case, the attribute indicates that the first ``N`` bytes will be
1541+
(non-atomically) loaded and stored back on entry to the function.
1542+
1543+
This implies that it's possible to introduce spurious stores on entry to
1544+
the function without introducing traps or data races. This does not
1545+
necessarily hold throughout the whole function, as the pointer may escape
1546+
to a different thread during the execution of the function. See also the
1547+
:ref:`atomic optimization guide <Optimization outside atomic>`
1548+
1549+
The "other attributes" that imply dereferenceability are
1550+
``dereferenceable_or_null`` (if the pointer is non-null) and the
1551+
``sret``, ``byval``, ``byref``, ``inalloca``, ``preallocated`` family of
1552+
attributes. Note that not all of these combinations are useful, e.g.
1553+
``byval`` arguments are known to be writable even without this attribute.
1554+
1555+
The ``writable`` attribute cannot be combined with ``readnone``,
1556+
``readonly`` or a ``memory`` attribute that does not contain
1557+
``argmem: write``.
1558+
15351559
.. _gc:
15361560

15371561
Garbage Collector Strategy Names

llvm/include/llvm/Analysis/AliasAnalysis.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -875,10 +875,16 @@ bool isNotVisibleOnUnwind(const Value *Object,
875875

876876
/// Return true if the Object is writable, in the sense that any location based
877877
/// on this pointer that can be loaded can also be stored to without trapping.
878+
/// Additionally, at the point Object is declared, stores can be introduced
879+
/// without data races. At later points, this is only the case if the pointer
880+
/// can not escape to a different thread.
878881
///
879-
/// By itself, this does not imply that introducing spurious stores is safe,
880-
/// for example due to thread-safety reasons.
881-
bool isWritableObject(const Value *Object);
882+
/// If ExplicitlyDereferenceableOnly is set to true, this property only holds
883+
/// for the part of Object that is explicitly marked as dereferenceable, e.g.
884+
/// using the dereferenceable(N) attribute. It does not necessarily hold for
885+
/// parts that are only known to be dereferenceable due to the presence of
886+
/// loads.
887+
bool isWritableObject(const Value *Object, bool &ExplicitlyDereferenceableOnly);
882888

883889
/// A manager for alias analyses.
884890
///

llvm/include/llvm/Bitcode/LLVMBitCodes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,7 @@ enum AttributeKindCodes {
717717
ATTR_KIND_MEMORY = 86,
718718
ATTR_KIND_NOFPCLASS = 87,
719719
ATTR_KIND_OPTIMIZE_FOR_DEBUGGING = 88,
720+
ATTR_KIND_WRITABLE = 89,
720721
};
721722

722723
enum ComdatSelectionKindCodes {

llvm/include/llvm/IR/Attributes.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,9 @@ def VScaleRange : IntAttr<"vscale_range", [FnAttr]>;
303303
/// Function always comes back to callsite.
304304
def WillReturn : EnumAttr<"willreturn", [FnAttr]>;
305305

306+
/// Pointer argument is writable.
307+
def Writable : EnumAttr<"writable", [ParamAttr]>;
308+
306309
/// Function only writes to memory.
307310
def WriteOnly : EnumAttr<"writeonly", [ParamAttr]>;
308311

llvm/lib/Analysis/AliasAnalysis.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -911,15 +911,23 @@ bool llvm::isNotVisibleOnUnwind(const Value *Object,
911911

912912
// We don't consider globals as writable: While the physical memory is writable,
913913
// we may not have provenance to perform the write.
914-
bool llvm::isWritableObject(const Value *Object) {
914+
bool llvm::isWritableObject(const Value *Object,
915+
bool &ExplicitlyDereferenceableOnly) {
916+
ExplicitlyDereferenceableOnly = false;
917+
915918
// TODO: Alloca might not be writable after its lifetime ends.
916919
// See https://github.com/llvm/llvm-project/issues/51838.
917920
if (isa<AllocaInst>(Object))
918921
return true;
919922

920-
// TODO: Also handle sret.
921-
if (auto *A = dyn_cast<Argument>(Object))
923+
if (auto *A = dyn_cast<Argument>(Object)) {
924+
if (A->hasAttribute(Attribute::Writable)) {
925+
ExplicitlyDereferenceableOnly = true;
926+
return true;
927+
}
928+
922929
return A->hasByValAttr();
930+
}
923931

924932
// TODO: Noalias shouldn't imply writability, this should check for an
925933
// allocator function instead.

llvm/lib/Bitcode/Reader/BitcodeReader.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2058,6 +2058,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
20582058
return Attribute::Hot;
20592059
case bitc::ATTR_KIND_PRESPLIT_COROUTINE:
20602060
return Attribute::PresplitCoroutine;
2061+
case bitc::ATTR_KIND_WRITABLE:
2062+
return Attribute::Writable;
20612063
}
20622064
}
20632065

llvm/lib/Bitcode/Writer/BitcodeWriter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
824824
return bitc::ATTR_KIND_MUSTPROGRESS;
825825
case Attribute::PresplitCoroutine:
826826
return bitc::ATTR_KIND_PRESPLIT_COROUTINE;
827+
case Attribute::Writable:
828+
return bitc::ATTR_KIND_WRITABLE;
827829
case Attribute::EndAttrKinds:
828830
llvm_unreachable("Can not encode end-attribute kinds marker.");
829831
case Attribute::None:

llvm/lib/IR/Attributes.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1961,7 +1961,8 @@ AttributeMask AttributeFuncs::typeIncompatible(Type *Ty,
19611961
.addAttribute(Attribute::ReadNone)
19621962
.addAttribute(Attribute::ReadOnly)
19631963
.addAttribute(Attribute::Dereferenceable)
1964-
.addAttribute(Attribute::DereferenceableOrNull);
1964+
.addAttribute(Attribute::DereferenceableOrNull)
1965+
.addAttribute(Attribute::Writable);
19651966
if (ASK & ASK_UNSAFE_TO_DROP)
19661967
Incompatible.addAttribute(Attribute::Nest)
19671968
.addAttribute(Attribute::SwiftError)

llvm/lib/IR/Verifier.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1999,6 +1999,14 @@ void Verifier::verifyParameterAttrs(AttributeSet Attrs, Type *Ty,
19991999
"'noinline and alwaysinline' are incompatible!",
20002000
V);
20012001

2002+
Check(!(Attrs.hasAttribute(Attribute::Writable) &&
2003+
Attrs.hasAttribute(Attribute::ReadNone)),
2004+
"Attributes writable and readnone are incompatible!", V);
2005+
2006+
Check(!(Attrs.hasAttribute(Attribute::Writable) &&
2007+
Attrs.hasAttribute(Attribute::ReadOnly)),
2008+
"Attributes writable and readonly are incompatible!", V);
2009+
20022010
AttributeMask IncompatibleAttrs = AttributeFuncs::typeIncompatible(Ty);
20032011
for (Attribute Attr : Attrs) {
20042012
if (!Attr.isStringAttribute() &&
@@ -2203,6 +2211,11 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs,
22032211
"Attributes 'minsize and optdebug' are incompatible!", V);
22042212
}
22052213

2214+
Check(!Attrs.hasAttrSomewhere(Attribute::Writable) ||
2215+
isModSet(Attrs.getMemoryEffects().getModRef(IRMemLocation::ArgMem)),
2216+
"Attribute writable and memory without argmem: write are incompatible!",
2217+
V);
2218+
22062219
if (Attrs.hasFnAttr("aarch64_pstate_sm_enabled")) {
22072220
Check(!Attrs.hasFnAttr("aarch64_pstate_sm_compatible"),
22082221
"Attributes 'aarch64_pstate_sm_enabled and "

llvm/lib/Transforms/IPO/AttributorAttributes.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7845,6 +7845,9 @@ struct AAMemoryBehaviorImpl : public AAMemoryBehavior {
78457845

78467846
// Clear existing attributes.
78477847
A.removeAttrs(IRP, AttrKinds);
7848+
// Clear conflicting writable attribute.
7849+
if (isAssumedReadOnly())
7850+
A.removeAttrs(IRP, Attribute::Writable);
78487851

78497852
// Use the generic manifest method.
78507853
return IRAttribute::manifest(A);
@@ -8032,6 +8035,10 @@ struct AAMemoryBehaviorFunction final : public AAMemoryBehaviorImpl {
80328035
ME = MemoryEffects::writeOnly();
80338036

80348037
A.removeAttrs(getIRPosition(), AttrKinds);
8038+
// Clear conflicting writable attribute.
8039+
if (ME.onlyReadsMemory())
8040+
for (Argument &Arg : F.args())
8041+
A.removeAttrs(IRPosition::argument(Arg), Attribute::Writable);
80358042
return A.manifestAttrs(getIRPosition(),
80368043
Attribute::getWithMemoryEffects(F.getContext(), ME));
80378044
}
@@ -8066,6 +8073,11 @@ struct AAMemoryBehaviorCallSite final
80668073
ME = MemoryEffects::writeOnly();
80678074

80688075
A.removeAttrs(getIRPosition(), AttrKinds);
8076+
// Clear conflicting writable attribute.
8077+
if (ME.onlyReadsMemory())
8078+
for (Use &U : CB.args())
8079+
A.removeAttrs(IRPosition::callsite_argument(CB, U.getOperandNo()),
8080+
Attribute::Writable);
80698081
return A.manifestAttrs(
80708082
getIRPosition(), Attribute::getWithMemoryEffects(CB.getContext(), ME));
80718083
}

llvm/lib/Transforms/IPO/FunctionAttrs.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,10 @@ static void addMemoryAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter,
285285
if (NewME != OldME) {
286286
++NumMemoryAttr;
287287
F->setMemoryEffects(NewME);
288+
// Remove conflicting writable attributes.
289+
if (!isModSet(NewME.getModRef(IRMemLocation::ArgMem)))
290+
for (Argument &A : F->args())
291+
A.removeAttr(Attribute::Writable);
288292
Changed.insert(F);
289293
}
290294
}
@@ -848,6 +852,9 @@ static bool addAccessAttr(Argument *A, Attribute::AttrKind R) {
848852
A->removeAttr(Attribute::WriteOnly);
849853
A->removeAttr(Attribute::ReadOnly);
850854
A->removeAttr(Attribute::ReadNone);
855+
// Remove conflicting writable attribute.
856+
if (R == Attribute::ReadNone || R == Attribute::ReadOnly)
857+
A->removeAttr(Attribute::Writable);
851858
A->addAttr(R);
852859
if (R == Attribute::ReadOnly)
853860
++NumReadOnlyArg;

llvm/lib/Transforms/Scalar/LICM.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2171,7 +2171,10 @@ bool llvm::promoteLoopAccessesToScalars(
21712171
// violating the memory model.
21722172
if (StoreSafety == StoreSafetyUnknown) {
21732173
Value *Object = getUnderlyingObject(SomePtr);
2174-
if (isWritableObject(Object) &&
2174+
bool ExplicitlyDereferenceableOnly;
2175+
if (isWritableObject(Object, ExplicitlyDereferenceableOnly) &&
2176+
(!ExplicitlyDereferenceableOnly ||
2177+
isDereferenceablePointer(SomePtr, AccessTy, MDL)) &&
21752178
isThreadLocalObject(Object, CurLoop, DT, TTI))
21762179
StoreSafety = StoreSafe;
21772180
}

llvm/lib/Transforms/Utils/CodeExtractor.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -994,6 +994,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs,
994994
case Attribute::ImmArg:
995995
case Attribute::ByRef:
996996
case Attribute::WriteOnly:
997+
case Attribute::Writable:
997998
// These are not really attributes.
998999
case Attribute::None:
9991000
case Attribute::EndAttrKinds:

llvm/test/Bitcode/attributes.ll

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -511,12 +511,16 @@ define void @f87() fn_ret_thunk_extern { ret void }
511511
; CHECK: define void @f88() [[SKIPPROFILE:#[0-9]+]]
512512
define void @f88() skipprofile { ret void }
513513

514-
define void @f89() optdebug
515514
; CHECK: define void @f89() [[OPTDEBUG:#[0-9]+]]
516-
{
515+
define void @f89() optdebug {
517516
ret void;
518517
}
519518

519+
; CHECK: define void @f90(ptr writable %p)
520+
define void @f90(ptr writable %p) {
521+
ret void
522+
}
523+
520524
; CHECK: attributes #0 = { noreturn }
521525
; CHECK: attributes #1 = { nounwind }
522526
; CHECK: attributes #2 = { memory(none) }

llvm/test/Transforms/FunctionAttrs/readattrs.ll

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -230,15 +230,15 @@ define void @test8_2(ptr %p) {
230230
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test8_2
231231
; ATTRIBUTOR-SAME: (ptr nocapture nofree writeonly [[P:%.*]]) #[[ATTR0]] {
232232
; ATTRIBUTOR-NEXT: entry:
233-
; ATTRIBUTOR-NEXT: [[CALL:%.*]] = call ptr @test8_1(ptr nofree readnone [[P]]) #[[ATTR13:[0-9]+]]
233+
; ATTRIBUTOR-NEXT: [[CALL:%.*]] = call ptr @test8_1(ptr nofree readnone [[P]]) #[[ATTR14:[0-9]+]]
234234
; ATTRIBUTOR-NEXT: store i32 10, ptr [[CALL]], align 4
235235
; ATTRIBUTOR-NEXT: ret void
236236
;
237237
; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(write)
238238
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test8_2
239239
; ATTRIBUTOR-CGSCC-SAME: (ptr nofree writeonly [[P:%.*]]) #[[ATTR5:[0-9]+]] {
240240
; ATTRIBUTOR-CGSCC-NEXT: entry:
241-
; ATTRIBUTOR-CGSCC-NEXT: [[CALL:%.*]] = call ptr @test8_1(ptr nofree readnone [[P]]) #[[ATTR13:[0-9]+]]
241+
; ATTRIBUTOR-CGSCC-NEXT: [[CALL:%.*]] = call ptr @test8_1(ptr nofree readnone [[P]]) #[[ATTR14:[0-9]+]]
242242
; ATTRIBUTOR-CGSCC-NEXT: store i32 10, ptr [[CALL]], align 4
243243
; ATTRIBUTOR-CGSCC-NEXT: ret void
244244
;
@@ -260,13 +260,13 @@ define void @test9(<4 x ptr> %ptrs, <4 x i32>%val) {
260260
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
261261
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test9
262262
; ATTRIBUTOR-SAME: (<4 x ptr> [[PTRS:%.*]], <4 x i32> [[VAL:%.*]]) #[[ATTR0]] {
263-
; ATTRIBUTOR-NEXT: call void @llvm.masked.scatter.v4i32.v4p0(<4 x i32> [[VAL]], <4 x ptr> [[PTRS]], i32 4, <4 x i1> <i1 true, i1 false, i1 true, i1 false>) #[[ATTR14:[0-9]+]]
263+
; ATTRIBUTOR-NEXT: call void @llvm.masked.scatter.v4i32.v4p0(<4 x i32> [[VAL]], <4 x ptr> [[PTRS]], i32 4, <4 x i1> <i1 true, i1 false, i1 true, i1 false>) #[[ATTR15:[0-9]+]]
264264
; ATTRIBUTOR-NEXT: ret void
265265
;
266266
; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
267267
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test9
268268
; ATTRIBUTOR-CGSCC-SAME: (<4 x ptr> [[PTRS:%.*]], <4 x i32> [[VAL:%.*]]) #[[ATTR0]] {
269-
; ATTRIBUTOR-CGSCC-NEXT: call void @llvm.masked.scatter.v4i32.v4p0(<4 x i32> [[VAL]], <4 x ptr> [[PTRS]], i32 4, <4 x i1> <i1 true, i1 false, i1 true, i1 false>) #[[ATTR14:[0-9]+]]
269+
; ATTRIBUTOR-CGSCC-NEXT: call void @llvm.masked.scatter.v4i32.v4p0(<4 x i32> [[VAL]], <4 x ptr> [[PTRS]], i32 4, <4 x i1> <i1 true, i1 false, i1 true, i1 false>) #[[ATTR15:[0-9]+]]
270270
; ATTRIBUTOR-CGSCC-NEXT: ret void
271271
;
272272
call void @llvm.masked.scatter.v4i32.v4p0(<4 x i32>%val, <4 x ptr> %ptrs, i32 4, <4 x i1><i1 true, i1 false, i1 true, i1 false>)
@@ -284,13 +284,13 @@ define <4 x i32> @test10(<4 x ptr> %ptrs) {
284284
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read)
285285
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test10
286286
; ATTRIBUTOR-SAME: (<4 x ptr> [[PTRS:%.*]]) #[[ATTR7:[0-9]+]] {
287-
; ATTRIBUTOR-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.masked.gather.v4i32.v4p0(<4 x ptr> [[PTRS]], i32 4, <4 x i1> <i1 true, i1 false, i1 true, i1 false>, <4 x i32> undef) #[[ATTR15:[0-9]+]]
287+
; ATTRIBUTOR-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.masked.gather.v4i32.v4p0(<4 x ptr> [[PTRS]], i32 4, <4 x i1> <i1 true, i1 false, i1 true, i1 false>, <4 x i32> undef) #[[ATTR16:[0-9]+]]
288288
; ATTRIBUTOR-NEXT: ret <4 x i32> [[RES]]
289289
;
290290
; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read)
291291
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test10
292292
; ATTRIBUTOR-CGSCC-SAME: (<4 x ptr> [[PTRS:%.*]]) #[[ATTR8:[0-9]+]] {
293-
; ATTRIBUTOR-CGSCC-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.masked.gather.v4i32.v4p0(<4 x ptr> [[PTRS]], i32 4, <4 x i1> <i1 true, i1 false, i1 true, i1 false>, <4 x i32> undef) #[[ATTR15:[0-9]+]]
293+
; ATTRIBUTOR-CGSCC-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.masked.gather.v4i32.v4p0(<4 x ptr> [[PTRS]], i32 4, <4 x i1> <i1 true, i1 false, i1 true, i1 false>, <4 x i32> undef) #[[ATTR16:[0-9]+]]
294294
; ATTRIBUTOR-CGSCC-NEXT: ret <4 x i32> [[RES]]
295295
;
296296
%res = call <4 x i32> @llvm.masked.gather.v4i32.v4p0(<4 x ptr> %ptrs, i32 4, <4 x i1><i1 true, i1 false, i1 true, i1 false>, <4 x i32>undef)
@@ -719,5 +719,48 @@ define void @op_bundle_readonly_unknown(ptr %p) {
719719
call void @readonly_param(ptr %p) ["unknown"()]
720720
ret void
721721
}
722+
723+
define i32 @writable_readonly(ptr writable dereferenceable(4) %p) {
724+
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
725+
; FNATTRS-LABEL: define {{[^@]+}}@writable_readonly
726+
; FNATTRS-SAME: (ptr nocapture readonly dereferenceable(4) [[P:%.*]]) #[[ATTR15:[0-9]+]] {
727+
; FNATTRS-NEXT: [[V:%.*]] = load i32, ptr [[P]], align 4
728+
; FNATTRS-NEXT: ret i32 [[V]]
729+
;
730+
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
731+
; ATTRIBUTOR-LABEL: define {{[^@]+}}@writable_readonly
732+
; ATTRIBUTOR-SAME: (ptr nocapture nofree nonnull readonly dereferenceable(4) [[P:%.*]]) #[[ATTR13:[0-9]+]] {
733+
; ATTRIBUTOR-NEXT: [[V:%.*]] = load i32, ptr [[P]], align 4
734+
; ATTRIBUTOR-NEXT: ret i32 [[V]]
735+
;
736+
; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
737+
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@writable_readonly
738+
; ATTRIBUTOR-CGSCC-SAME: (ptr nocapture nofree nonnull readonly dereferenceable(4) [[P:%.*]]) #[[ATTR13:[0-9]+]] {
739+
; ATTRIBUTOR-CGSCC-NEXT: [[V:%.*]] = load i32, ptr [[P]], align 4
740+
; ATTRIBUTOR-CGSCC-NEXT: ret i32 [[V]]
741+
;
742+
%v = load i32, ptr %p
743+
ret i32 %v
744+
}
745+
746+
define void @writable_readnone(ptr writable dereferenceable(4) %p) {
747+
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
748+
; FNATTRS-LABEL: define {{[^@]+}}@writable_readnone
749+
; FNATTRS-SAME: (ptr nocapture readnone dereferenceable(4) [[P:%.*]]) #[[ATTR1]] {
750+
; FNATTRS-NEXT: ret void
751+
;
752+
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
753+
; ATTRIBUTOR-LABEL: define {{[^@]+}}@writable_readnone
754+
; ATTRIBUTOR-SAME: (ptr nocapture nofree nonnull readnone dereferenceable(4) [[P:%.*]]) #[[ATTR1]] {
755+
; ATTRIBUTOR-NEXT: ret void
756+
;
757+
; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
758+
; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@writable_readnone
759+
; ATTRIBUTOR-CGSCC-SAME: (ptr nocapture nofree nonnull readnone dereferenceable(4) [[P:%.*]]) #[[ATTR1]] {
760+
; ATTRIBUTOR-CGSCC-NEXT: ret void
761+
;
762+
ret void
763+
}
764+
722765
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
723766
; COMMON: {{.*}}

llvm/test/Transforms/LICM/scalar-promote.ll

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -885,9 +885,40 @@ exit:
885885
ret void
886886
}
887887

888-
; TODO: The store can be promoted, as sret memory is writable.
889-
define void @sret_cond_store(ptr sret(i32) noalias %ptr) {
890-
; CHECK-LABEL: @sret_cond_store(
888+
define void @cond_store_writable_dereferenceable(ptr noalias writable dereferenceable(4) %ptr) {
889+
; CHECK-LABEL: @cond_store_writable_dereferenceable(
890+
; CHECK-NEXT: [[PTR_PROMOTED:%.*]] = load i32, ptr [[PTR:%.*]], align 4
891+
; CHECK-NEXT: br label [[LOOP:%.*]]
892+
; CHECK: loop:
893+
; CHECK-NEXT: [[V_INC1:%.*]] = phi i32 [ [[V_INC:%.*]], [[LOOP_LATCH:%.*]] ], [ [[PTR_PROMOTED]], [[TMP0:%.*]] ]
894+
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[V_INC1]], 10
895+
; CHECK-NEXT: br i1 [[C]], label [[LOOP_LATCH]], label [[EXIT:%.*]]
896+
; CHECK: loop.latch:
897+
; CHECK-NEXT: [[V_INC]] = add i32 [[V_INC1]], 1
898+
; CHECK-NEXT: br label [[LOOP]]
899+
; CHECK: exit:
900+
; CHECK-NEXT: [[V_INC1_LCSSA:%.*]] = phi i32 [ [[V_INC1]], [[LOOP]] ]
901+
; CHECK-NEXT: store i32 [[V_INC1_LCSSA]], ptr [[PTR]], align 4
902+
; CHECK-NEXT: ret void
903+
;
904+
br label %loop
905+
906+
loop:
907+
%v = load i32, ptr %ptr
908+
%c = icmp ult i32 %v, 10
909+
br i1 %c, label %loop.latch, label %exit
910+
911+
loop.latch:
912+
%v.inc = add i32 %v, 1
913+
store i32 %v.inc, ptr %ptr
914+
br label %loop
915+
916+
exit:
917+
ret void
918+
}
919+
920+
define void @cond_store_writable_not_sufficiently_dereferenceable(ptr noalias writable dereferenceable(2) %ptr) {
921+
; CHECK-LABEL: @cond_store_writable_not_sufficiently_dereferenceable(
891922
; CHECK-NEXT: [[PTR_PROMOTED:%.*]] = load i32, ptr [[PTR:%.*]], align 4
892923
; CHECK-NEXT: br label [[LOOP:%.*]]
893924
; CHECK: loop:

0 commit comments

Comments
 (0)