Index: clang/lib/CodeGen/CGCall.cpp =================================================================== --- clang/lib/CodeGen/CGCall.cpp +++ clang/lib/CodeGen/CGCall.cpp @@ -2121,6 +2121,16 @@ // The NoBuiltinAttr attached to the target FunctionDecl. const NoBuiltinAttr *NBA = nullptr; + // Some ABIs may result in additional accesses to arguments that may + // otherwise not be present. + auto AddPotentialArgAccess = [&]() { + llvm::Attribute A = FuncAttrs.getAttribute(llvm::Attribute::Memory); + if (A.isValid()) + FuncAttrs.addMemoryAttr( + A.getMemoryEffects() | + llvm::MemoryEffects::argMemOnly(llvm::ModRefInfo::ModRef)); + }; + // Collect function IR attributes based on declaration-specific // information. // FIXME: handle sseregparm someday... @@ -2167,18 +2177,19 @@ // 'const', 'pure' and 'noalias' attributed functions are also nounwind. if (TargetDecl->hasAttr()) { - FuncAttrs.addAttribute(llvm::Attribute::ReadNone); + FuncAttrs.addMemoryAttr(llvm::MemoryEffects::none()); FuncAttrs.addAttribute(llvm::Attribute::NoUnwind); // gcc specifies that 'const' functions have greater restrictions than // 'pure' functions, so they also cannot have infinite loops. FuncAttrs.addAttribute(llvm::Attribute::WillReturn); } else if (TargetDecl->hasAttr()) { - FuncAttrs.addAttribute(llvm::Attribute::ReadOnly); + FuncAttrs.addMemoryAttr(llvm::MemoryEffects::readOnly()); FuncAttrs.addAttribute(llvm::Attribute::NoUnwind); // gcc specifies that 'pure' functions cannot have infinite loops. FuncAttrs.addAttribute(llvm::Attribute::WillReturn); } else if (TargetDecl->hasAttr()) { - FuncAttrs.addAttribute(llvm::Attribute::ArgMemOnly); + FuncAttrs.addMemoryAttr( + llvm::MemoryEffects::argMemOnly(llvm::ModRefInfo::ModRef)); FuncAttrs.addAttribute(llvm::Attribute::NoUnwind); } if (TargetDecl->hasAttr()) @@ -2356,8 +2367,7 @@ case ABIArgInfo::InAlloca: case ABIArgInfo::Indirect: { // inalloca and sret disable readnone and readonly - FuncAttrs.removeAttribute(llvm::Attribute::ReadOnly) - .removeAttribute(llvm::Attribute::ReadNone); + AddPotentialArgAccess(); break; } @@ -2527,9 +2537,7 @@ Attrs.addAlignmentAttr(Align.getQuantity()); // byval disables readnone and readonly. - FuncAttrs.removeAttribute(llvm::Attribute::ReadOnly) - .removeAttribute(llvm::Attribute::ReadNone); - + AddPotentialArgAccess(); break; } case ABIArgInfo::IndirectAliased: { @@ -2545,8 +2553,7 @@ case ABIArgInfo::InAlloca: // inalloca disables readnone and readonly. - FuncAttrs.removeAttribute(llvm::Attribute::ReadOnly) - .removeAttribute(llvm::Attribute::ReadNone); + AddPotentialArgAccess(); continue; } Index: clang/lib/CodeGen/ItaniumCXXABI.cpp =================================================================== --- clang/lib/CodeGen/ItaniumCXXABI.cpp +++ clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -1325,8 +1325,9 @@ llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, Args, false); // Mark the function as nounwind readonly. - llvm::Attribute::AttrKind FuncAttrs[] = { llvm::Attribute::NoUnwind, - llvm::Attribute::ReadOnly }; + llvm::AttrBuilder FuncAttrs(CGF.getLLVMContext()); + FuncAttrs.addAttribute(llvm::Attribute::NoUnwind); + FuncAttrs.addMemoryAttr(llvm::MemoryEffects::readOnly()); llvm::AttributeList Attrs = llvm::AttributeList::get( CGF.getLLVMContext(), llvm::AttributeList::FunctionIndex, FuncAttrs); Index: clang/test/CodeGen/asm-attrs.c =================================================================== --- clang/test/CodeGen/asm-attrs.c +++ clang/test/CodeGen/asm-attrs.c @@ -10,9 +10,9 @@ // CHECK: call void asm sideeffect "foo7", {{.*}} [[NOATTRS]] // CHECK: call i32 asm "foo8", {{.*}} [[READNONE]] -// CHECK: attributes [[READNONE]] = { nounwind readnone } +// CHECK: attributes [[READNONE]] = { nounwind memory(none) } // CHECK: attributes [[NOATTRS]] = { nounwind } -// CHECK: attributes [[READONLY]] = { nounwind readonly } +// CHECK: attributes [[READONLY]] = { nounwind memory(read) } int g0, g1; Index: clang/test/CodeGen/builtin-sqrt.c =================================================================== --- clang/test/CodeGen/builtin-sqrt.c +++ clang/test/CodeGen/builtin-sqrt.c @@ -8,8 +8,8 @@ } // HAS_ERRNO: declare float @sqrtf(float noundef) [[ATTR:#[0-9]+]] -// HAS_ERRNO-NOT: attributes [[ATTR]] = {{{.*}} readnone +// HAS_ERRNO-NOT: attributes [[ATTR]] = {{{.*}} memory(none) // NO_ERRNO: declare float @llvm.sqrt.f32(float) [[ATTR:#[0-9]+]] -// NO_ERRNO: attributes [[ATTR]] = { nocallback nofree nosync nounwind readnone {{.*}}} +// NO_ERRNO: attributes [[ATTR]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } Index: clang/test/CodeGen/complex-builtins.c =================================================================== --- clang/test/CodeGen/complex-builtins.c +++ clang/test/CodeGen/complex-builtins.c @@ -197,9 +197,9 @@ // HAS_ERRNO: declare { x86_fp80, x86_fp80 } @ctanhl(ptr noundef byval({ x86_fp80, x86_fp80 }) align 16) [[NOT_READNONE]] }; -// NO__ERRNO: attributes [[READNONE]] = { {{.*}}readnone{{.*}} } +// NO__ERRNO: attributes [[READNONE]] = { {{.*}}memory(none){{.*}} } // NO__ERRNO: attributes [[NOT_READNONE]] = { nounwind {{.*}} } // HAS_ERRNO: attributes [[NOT_READNONE]] = { nounwind {{.*}} } -// HAS_ERRNO: attributes [[READNONE]] = { {{.*}}readnone{{.*}} } +// HAS_ERRNO: attributes [[READNONE]] = { {{.*}}memory(none){{.*}} } // HAS_ERRNO: attributes [[WILLRETURN_NOT_READNONE]] = { nounwind willreturn {{.*}} } Index: clang/test/CodeGen/complex-libcalls.c =================================================================== --- clang/test/CodeGen/complex-libcalls.c +++ clang/test/CodeGen/complex-libcalls.c @@ -197,9 +197,9 @@ // HAS_ERRNO: declare { x86_fp80, x86_fp80 } @ctanhl(ptr noundef byval({ x86_fp80, x86_fp80 }) align 16) [[NOT_READNONE]] }; -// NO__ERRNO: attributes [[READNONE]] = { {{.*}}readnone{{.*}} } +// NO__ERRNO: attributes [[READNONE]] = { {{.*}}memory(none){{.*}} } // NO__ERRNO: attributes [[NOT_READNONE]] = { nounwind {{.*}} } // HAS_ERRNO: attributes [[NOT_READNONE]] = { nounwind {{.*}} } -// HAS_ERRNO: attributes [[READNONE]] = { {{.*}}readnone{{.*}} } +// HAS_ERRNO: attributes [[READNONE]] = { {{.*}}memory(none){{.*}} } // HAS_ERRNO: attributes [[WILLRETURN_NOT_READNONE]] = { nounwind willreturn {{.*}} } Index: clang/test/CodeGen/function-attributes.c =================================================================== --- clang/test/CodeGen/function-attributes.c +++ clang/test/CodeGen/function-attributes.c @@ -111,9 +111,9 @@ // CHECK: attributes [[NUW]] = { nounwind optsize{{.*}} } // CHECK: attributes [[AI]] = { alwaysinline nounwind optsize{{.*}} } -// CHECK: attributes [[NUW_OS_RN]] = { nounwind optsize readnone{{.*}} } +// CHECK: attributes [[NUW_OS_RN]] = { nounwind optsize willreturn memory(none){{.*}} } // CHECK: attributes [[SR]] = { nounwind optsize{{.*}} "stackrealign"{{.*}} } // CHECK: attributes [[RT]] = { nounwind optsize returns_twice{{.*}} } // CHECK: attributes [[NR]] = { noreturn optsize } -// CHECK: attributes [[NUW_RN]] = { nounwind optsize readnone willreturn } +// CHECK: attributes [[NUW_RN]] = { nounwind optsize willreturn memory(none) } // CHECK: attributes [[RT_CALL]] = { optsize returns_twice } Index: clang/test/CodeGen/libcall-declarations.c =================================================================== --- clang/test/CodeGen/libcall-declarations.c +++ clang/test/CodeGen/libcall-declarations.c @@ -614,8 +614,8 @@ // CHECK-ERRNO: declare { double, double } @ctanh(double noundef, double noundef) [[NONCONST]] // CHECK-ERRNO: declare <2 x float> @ctanhf(<2 x float> noundef) [[NONCONST]] -// CHECK-NOERRNO: attributes [[NUWRN]] = { nounwind readnone{{.*}} } -// CHECK-NOERRNO: attributes [[NUWRO]] = { nounwind readonly{{.*}} } +// CHECK-NOERRNO: attributes [[NUWRN]] = { nounwind willreturn memory(none){{.*}} } +// CHECK-NOERRNO: attributes [[NUWRO]] = { nounwind willreturn memory(read){{.*}} } -// CHECK-ERRNO: attributes [[NUWRN]] = { nounwind readnone{{.*}} } -// CHECK-ERRNO: attributes [[NUWRO]] = { nounwind readonly{{.*}} } +// CHECK-ERRNO: attributes [[NUWRN]] = { nounwind willreturn memory(none){{.*}} } +// CHECK-ERRNO: attributes [[NUWRO]] = { nounwind willreturn memory(read){{.*}} } Index: clang/test/CodeGen/libcalls.c =================================================================== --- clang/test/CodeGen/libcalls.c +++ clang/test/CodeGen/libcalls.c @@ -124,5 +124,5 @@ } // CHECK-YES: attributes [[NUW]] = { nounwind "frame-pointer"="none" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+x87" } -// CHECK-NO-DAG: attributes [[NUW_RN]] = { nounwind readnone{{.*}} } -// CHECK-NO-DAG: attributes [[NUW_RNI]] = { nocallback nofree nosync nounwind readnone speculatable willreturn } +// CHECK-NO-DAG: attributes [[NUW_RN]] = { nounwind willreturn memory(none){{.*}} } +// CHECK-NO-DAG: attributes [[NUW_RNI]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } Index: clang/test/CodeGen/math-builtins.c =================================================================== --- clang/test/CodeGen/math-builtins.c +++ clang/test/CodeGen/math-builtins.c @@ -680,16 +680,16 @@ // HAS_ERRNO: declare fp128 @llvm.trunc.f128(fp128) [[READNONE_INTRINSIC]] }; -// NO__ERRNO: attributes [[READNONE]] = { {{.*}}readnone{{.*}} } -// NO__ERRNO: attributes [[READNONE_INTRINSIC]] = { {{.*}}readnone{{.*}} } +// NO__ERRNO: attributes [[READNONE]] = { {{.*}}memory(none){{.*}} } +// NO__ERRNO: attributes [[READNONE_INTRINSIC]] = { {{.*}}memory(none){{.*}} } // NO__ERRNO: attributes [[NOT_READNONE]] = { nounwind {{.*}} } -// NO__ERRNO: attributes [[PURE]] = { {{.*}}readonly{{.*}} } +// NO__ERRNO: attributes [[PURE]] = { {{.*}}memory(read){{.*}} } // HAS_ERRNO: attributes [[NOT_READNONE]] = { nounwind {{.*}} } -// HAS_ERRNO: attributes [[READNONE_INTRINSIC]] = { {{.*}}readnone{{.*}} } -// HAS_ERRNO: attributes [[PURE]] = { {{.*}}readonly{{.*}} } -// HAS_ERRNO: attributes [[READNONE]] = { {{.*}}readnone{{.*}} } +// HAS_ERRNO: attributes [[READNONE_INTRINSIC]] = { {{.*}}memory(none){{.*}} } +// HAS_ERRNO: attributes [[PURE]] = { {{.*}}memory(read){{.*}} } +// HAS_ERRNO: attributes [[READNONE]] = { {{.*}}memory(none){{.*}} } -// HAS_ERRNO_GNU: attributes [[READNONE_INTRINSIC]] = { {{.*}}readnone{{.*}} } -// HAS_ERRNO_WIN: attributes [[READNONE_INTRINSIC]] = { {{.*}}readnone{{.*}} } +// HAS_ERRNO_GNU: attributes [[READNONE_INTRINSIC]] = { {{.*}}memory(none){{.*}} } +// HAS_ERRNO_WIN: attributes [[READNONE_INTRINSIC]] = { {{.*}}memory(none){{.*}} } Index: clang/test/CodeGen/math-libcalls.c =================================================================== --- clang/test/CodeGen/math-libcalls.c +++ clang/test/CodeGen/math-libcalls.c @@ -704,18 +704,18 @@ // HAS_ERRNO: declare x86_fp80 @llvm.trunc.f80(x86_fp80) [[READNONE_INTRINSIC]] }; -// NO__ERRNO: attributes [[READNONE]] = { {{.*}}readnone{{.*}} } -// NO__ERRNO: attributes [[READNONE_INTRINSIC]] = { {{.*}}readnone{{.*}} } +// NO__ERRNO: attributes [[READNONE]] = { {{.*}}memory(none){{.*}} } +// NO__ERRNO: attributes [[READNONE_INTRINSIC]] = { {{.*}}memory(none){{.*}} } // NO__ERRNO: attributes [[NOT_READNONE]] = { nounwind {{.*}} } -// NO__ERRNO: attributes [[READONLY]] = { {{.*}}readonly{{.*}} } +// NO__ERRNO: attributes [[READONLY]] = { {{.*}}memory(read){{.*}} } // HAS_ERRNO: attributes [[NOT_READNONE]] = { nounwind {{.*}} } -// HAS_ERRNO: attributes [[READNONE_INTRINSIC]] = { {{.*}}readnone{{.*}} } -// HAS_ERRNO: attributes [[READONLY]] = { {{.*}}readonly{{.*}} } -// HAS_ERRNO: attributes [[READNONE]] = { {{.*}}readnone{{.*}} } +// HAS_ERRNO: attributes [[READNONE_INTRINSIC]] = { {{.*}}memory(none){{.*}} } +// HAS_ERRNO: attributes [[READONLY]] = { {{.*}}memory(read){{.*}} } +// HAS_ERRNO: attributes [[READNONE]] = { {{.*}}memory(none){{.*}} } // HAS_MAYTRAP: attributes [[NOT_READNONE]] = { nounwind {{.*}} } -// HAS_MAYTRAP: attributes [[READNONE]] = { {{.*}}readnone{{.*}} } +// HAS_MAYTRAP: attributes [[READNONE]] = { {{.*}}memory(none){{.*}} } -// HAS_ERRNO_GNU: attributes [[READNONE_INTRINSIC]] = { {{.*}}readnone{{.*}} } -// HAS_ERRNO_WIN: attributes [[READNONE_INTRINSIC]] = { {{.*}}readnone{{.*}} } +// HAS_ERRNO_GNU: attributes [[READNONE_INTRINSIC]] = { {{.*}}memory(none){{.*}} } +// HAS_ERRNO_WIN: attributes [[READNONE_INTRINSIC]] = { {{.*}}memory(none){{.*}} } Index: clang/test/CodeGen/ms-declspecs.c =================================================================== --- clang/test/CodeGen/ms-declspecs.c +++ clang/test/CodeGen/ms-declspecs.c @@ -41,4 +41,4 @@ // CHECK: attributes [[NUW]] = { nounwind{{.*}} } // CHECK: attributes [[NI]] = { noinline nounwind{{.*}} } // CHECK: attributes [[NR]] = { noreturn } -// CHECK: attributes [[NA]] = { argmemonly nounwind{{.*}} } +// CHECK: attributes [[NA]] = { nounwind memory(argmem: readwrite){{.*}} } Index: clang/test/CodeGen/pragma-weak.c =================================================================== --- clang/test/CodeGen/pragma-weak.c +++ clang/test/CodeGen/pragma-weak.c @@ -202,4 +202,4 @@ int correct_linkage; // CHECK: attributes [[NI]] = { noinline nounwind{{.*}} } -// CHECK: attributes [[RN]] = { noinline nounwind optnone readnone{{.*}} } +// CHECK: attributes [[RN]] = { noinline nounwind optnone willreturn memory(none){{.*}} } Index: clang/test/CodeGen/struct-passing.c =================================================================== --- clang/test/CodeGen/struct-passing.c +++ clang/test/CodeGen/struct-passing.c @@ -23,5 +23,5 @@ // CHECK: declare void @f4({{.*}} byval({{.*}}) align 4) // CHECK: declare void @f5({{.*}} byval({{.*}}) align 4) -// CHECK: attributes [[RN]] = { nounwind readnone{{.*}} } -// CHECK: attributes [[RO]] = { nounwind readonly{{.*}} } +// CHECK: attributes [[RN]] = { nounwind willreturn memory(none){{.*}} } +// CHECK: attributes [[RO]] = { nounwind willreturn memory(read){{.*}} } Index: clang/test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp =================================================================== --- clang/test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp +++ clang/test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp @@ -15,8 +15,8 @@ // CHECK: declare noundef i32 @_Z1tv() [[TF2:#[0-9]+]] // CHECK: attributes [[TF]] = { {{.*}} } -// CHECK: attributes [[NUW_RN]] = { nounwind readnone willreturn{{.*}} } -// CHECK: attributes [[NUW_RO]] = { nounwind readonly willreturn{{.*}} } +// CHECK: attributes [[NUW_RN]] = { nounwind willreturn memory(none){{.*}} } +// CHECK: attributes [[NUW_RO]] = { nounwind willreturn memory(read){{.*}} } // CHECK: attributes [[TF2]] = { {{.*}} } -// CHECK: attributes [[NUW_RN_CALL]] = { nounwind readnone willreturn } -// CHECK: attributes [[NUW_RO_CALL]] = { nounwind readonly willreturn } +// CHECK: attributes [[NUW_RN_CALL]] = { nounwind willreturn memory(none) } +// CHECK: attributes [[NUW_RO_CALL]] = { nounwind willreturn memory(read) } Index: clang/test/CodeGenCXX/dynamic-cast.cpp =================================================================== --- clang/test/CodeGenCXX/dynamic-cast.cpp +++ clang/test/CodeGenCXX/dynamic-cast.cpp @@ -20,5 +20,5 @@ // CHECK: declare ptr @__dynamic_cast(ptr, ptr, ptr, i64) [[NUW_RO:#[0-9]+]] -// CHECK: attributes [[NUW_RO]] = { nounwind readonly } +// CHECK: attributes [[NUW_RO]] = { nounwind memory(read) } // CHECK: attributes [[NR]] = { noreturn } Index: clang/test/CodeGenCXX/threadlocal_address.cpp =================================================================== --- clang/test/CodeGenCXX/threadlocal_address.cpp +++ clang/test/CodeGenCXX/threadlocal_address.cpp @@ -51,4 +51,4 @@ // CHECK-O1-NEXT: store i32 %[[INC]], ptr %[[J_ADDR]] // CHECK-O1-NEXT: ret i32 %[[INC]] // -// CHECK: attributes #[[ATTR_NUM]] = { nocallback nofree nosync nounwind readnone speculatable willreturn } +// CHECK: attributes #[[ATTR_NUM]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } Index: clang/test/CodeGenOpenCL/builtins-amdgcn.cl =================================================================== --- clang/test/CodeGenOpenCL/builtins-amdgcn.cl +++ clang/test/CodeGenOpenCL/builtins-amdgcn.cl @@ -796,7 +796,7 @@ // CHECK-DAG: [[$WI_RANGE]] = !{i32 0, i32 1024} // CHECK-DAG: [[$WS_RANGE]] = !{i16 1, i16 1025} -// CHECK-DAG: attributes #[[$NOUNWIND_READONLY:[0-9]+]] = { nofree nounwind readonly } +// CHECK-DAG: attributes #[[$NOUNWIND_READONLY:[0-9]+]] = { nofree nounwind memory(read) } // CHECK-DAG: attributes #[[$READ_EXEC_ATTRS]] = { convergent } // CHECK-DAG: ![[$EXEC]] = !{!"exec"} // CHECK-DAG: ![[$EXEC_LO]] = !{!"exec_lo"} Index: clang/test/CodeGenOpenCL/convergent.cl =================================================================== --- clang/test/CodeGenOpenCL/convergent.cl +++ clang/test/CodeGenOpenCL/convergent.cl @@ -133,7 +133,7 @@ __asm__ volatile("s_barrier"); } -// CHECK: attributes #0 = { nofree noinline norecurse nounwind " +// CHECK: attributes #0 = { nofree noinline norecurse nounwind memory({{.*}}) " // CHECK: attributes #1 = { {{[^}]*}}convergent{{[^}]*}} } // CHECK: attributes #2 = { {{[^}]*}}convergent{{[^}]*}} } // CHECK: attributes #3 = { {{[^}]*}}convergent noduplicate{{[^}]*}} } Index: clang/test/CodeGenOpenCL/fdeclare-opencl-builtins.cl =================================================================== --- clang/test/CodeGenOpenCL/fdeclare-opencl-builtins.cl +++ clang/test/CodeGenOpenCL/fdeclare-opencl-builtins.cl @@ -49,6 +49,6 @@ } // CHECK: attributes [[ATTR_CONST]] = -// CHECK-SAME: readnone +// CHECK-SAME: memory(none) // CHECK: attributes [[ATTR_PURE]] = -// CHECK-SAME: readonly +// CHECK-SAME: memory(read) Index: clang/test/Sema/libbuiltins-ctype-powerpc64.c =================================================================== --- clang/test/Sema/libbuiltins-ctype-powerpc64.c +++ clang/test/Sema/libbuiltins-ctype-powerpc64.c @@ -61,5 +61,5 @@ // CHECK: declare signext i32 @tolower(i32 noundef signext) [[NUW_RO:#[0-9]+]] // CHECK: declare signext i32 @toupper(i32 noundef signext) [[NUW_RO:#[0-9]+]] -// CHECK: attributes [[NUW_RO]] = { nounwind readonly{{.*}} } -// CHECK: attributes [[NUW_RO_CALL]] = { nounwind readonly willreturn } +// CHECK: attributes [[NUW_RO]] = { nounwind willreturn memory(read){{.*}} } +// CHECK: attributes [[NUW_RO_CALL]] = { nounwind willreturn memory(read) } Index: clang/test/Sema/libbuiltins-ctype-x86_64.c =================================================================== --- clang/test/Sema/libbuiltins-ctype-x86_64.c +++ clang/test/Sema/libbuiltins-ctype-x86_64.c @@ -61,5 +61,5 @@ // CHECK: declare i32 @tolower(i32 noundef) [[NUW_RO:#[0-9]+]] // CHECK: declare i32 @toupper(i32 noundef) [[NUW_RO:#[0-9]+]] -// CHECK: attributes [[NUW_RO]] = { nounwind readonly{{.*}} } -// CHECK: attributes [[NUW_RO_CALL]] = { nounwind readonly willreturn } +// CHECK: attributes [[NUW_RO]] = { nounwind willreturn memory(read){{.*}} } +// CHECK: attributes [[NUW_RO_CALL]] = { nounwind willreturn memory(read) } Index: llvm/include/llvm/IR/Attributes.h =================================================================== --- llvm/include/llvm/IR/Attributes.h +++ llvm/include/llvm/IR/Attributes.h @@ -146,6 +146,7 @@ static Attribute getWithPreallocatedType(LLVMContext &Context, Type *Ty); static Attribute getWithInAllocaType(LLVMContext &Context, Type *Ty); static Attribute getWithUWTableKind(LLVMContext &Context, UWTableKind Kind); + static Attribute getWithMemoryEffects(LLVMContext &Context, MemoryEffects ME); /// For a typed attribute, return the equivalent attribute with the type /// changed to \p ReplacementTy. @@ -379,6 +380,7 @@ Optional getVScaleRangeMax() const; UWTableKind getUWTableKind() const; AllocFnKind getAllocKind() const; + MemoryEffects getMemoryEffects() const; std::string getAsString(bool InAttrGrp = false) const; /// Return true if this attribute set belongs to the LLVMContext. Index: llvm/include/llvm/IR/Function.h =================================================================== --- llvm/include/llvm/IR/Function.h +++ llvm/include/llvm/IR/Function.h @@ -491,54 +491,35 @@ void setPresplitCoroutine() { addFnAttr(Attribute::PresplitCoroutine); } void setSplittedCoroutine() { removeFnAttr(Attribute::PresplitCoroutine); } + MemoryEffects getMemoryEffects() const; + void setMemoryEffects(MemoryEffects ME); + /// Determine if the function does not access memory. - bool doesNotAccessMemory() const { - return hasFnAttribute(Attribute::ReadNone); - } - void setDoesNotAccessMemory() { - addFnAttr(Attribute::ReadNone); - } + bool doesNotAccessMemory() const; + void setDoesNotAccessMemory(); /// Determine if the function does not access or only reads memory. - bool onlyReadsMemory() const { - return doesNotAccessMemory() || hasFnAttribute(Attribute::ReadOnly); - } - void setOnlyReadsMemory() { - addFnAttr(Attribute::ReadOnly); - } + bool onlyReadsMemory() const; + void setOnlyReadsMemory(); /// Determine if the function does not access or only writes memory. - bool onlyWritesMemory() const { - return doesNotAccessMemory() || hasFnAttribute(Attribute::WriteOnly); - } - void setOnlyWritesMemory() { - addFnAttr(Attribute::WriteOnly); - } + bool onlyWritesMemory() const; + void setOnlyWritesMemory(); /// Determine if the call can access memmory only using pointers based /// on its arguments. - bool onlyAccessesArgMemory() const { - return hasFnAttribute(Attribute::ArgMemOnly); - } - void setOnlyAccessesArgMemory() { addFnAttr(Attribute::ArgMemOnly); } + bool onlyAccessesArgMemory() const; + void setOnlyAccessesArgMemory(); /// Determine if the function may only access memory that is /// inaccessible from the IR. - bool onlyAccessesInaccessibleMemory() const { - return hasFnAttribute(Attribute::InaccessibleMemOnly); - } - void setOnlyAccessesInaccessibleMemory() { - addFnAttr(Attribute::InaccessibleMemOnly); - } + bool onlyAccessesInaccessibleMemory() const; + void setOnlyAccessesInaccessibleMemory(); /// Determine if the function may only access memory that is /// either inaccessible from the IR or pointed to by its arguments. - bool onlyAccessesInaccessibleMemOrArgMem() const { - return hasFnAttribute(Attribute::InaccessibleMemOrArgMemOnly); - } - void setOnlyAccessesInaccessibleMemOrArgMem() { - addFnAttr(Attribute::InaccessibleMemOrArgMemOnly); - } + bool onlyAccessesInaccessibleMemOrArgMem() const; + void setOnlyAccessesInaccessibleMemOrArgMem(); /// Determine if the function cannot return. bool doesNotReturn() const { Index: llvm/include/llvm/IR/InstrTypes.h =================================================================== --- llvm/include/llvm/IR/InstrTypes.h +++ llvm/include/llvm/IR/InstrTypes.h @@ -1847,47 +1847,37 @@ /// Return true if the call should not be inlined. bool isNoInline() const { return hasFnAttr(Attribute::NoInline); } void setIsNoInline() { addFnAttr(Attribute::NoInline); } + + MemoryEffects getMemoryEffects() const; + void setMemoryEffects(MemoryEffects ME); + /// Determine if the call does not access memory. - bool doesNotAccessMemory() const { return hasFnAttr(Attribute::ReadNone); } - void setDoesNotAccessMemory() { addFnAttr(Attribute::ReadNone); } + bool doesNotAccessMemory() const; + void setDoesNotAccessMemory(); /// Determine if the call does not access or only reads memory. - bool onlyReadsMemory() const { - return hasImpliedFnAttr(Attribute::ReadOnly); - } - - void setOnlyReadsMemory() { addFnAttr(Attribute::ReadOnly); } + bool onlyReadsMemory() const; + void setOnlyReadsMemory(); /// Determine if the call does not access or only writes memory. - bool onlyWritesMemory() const { - return hasImpliedFnAttr(Attribute::WriteOnly); - } - void setOnlyWritesMemory() { addFnAttr(Attribute::WriteOnly); } + bool onlyWritesMemory() const; + void setOnlyWritesMemory(); /// Determine if the call can access memmory only using pointers based /// on its arguments. - bool onlyAccessesArgMemory() const { - return hasFnAttr(Attribute::ArgMemOnly); - } - void setOnlyAccessesArgMemory() { addFnAttr(Attribute::ArgMemOnly); } + bool onlyAccessesArgMemory() const; + void setOnlyAccessesArgMemory(); /// Determine if the function may only access memory that is /// inaccessible from the IR. - bool onlyAccessesInaccessibleMemory() const { - return hasFnAttr(Attribute::InaccessibleMemOnly); - } - void setOnlyAccessesInaccessibleMemory() { - addFnAttr(Attribute::InaccessibleMemOnly); - } + bool onlyAccessesInaccessibleMemory() const; + void setOnlyAccessesInaccessibleMemory(); /// Determine if the function may only access memory that is /// either inaccessible from the IR or pointed to by its arguments. - bool onlyAccessesInaccessibleMemOrArgMem() const { - return hasFnAttr(Attribute::InaccessibleMemOrArgMemOnly); - } - void setOnlyAccessesInaccessibleMemOrArgMem() { - addFnAttr(Attribute::InaccessibleMemOrArgMemOnly); - } + bool onlyAccessesInaccessibleMemOrArgMem() const; + void setOnlyAccessesInaccessibleMemOrArgMem(); + /// Determine if the call cannot return. bool doesNotReturn() const { return hasFnAttr(Attribute::NoReturn); } void setDoesNotReturn() { addFnAttr(Attribute::NoReturn); } Index: llvm/lib/Analysis/BasicAliasAnalysis.cpp =================================================================== --- llvm/lib/Analysis/BasicAliasAnalysis.cpp +++ llvm/lib/Analysis/BasicAliasAnalysis.cpp @@ -740,30 +740,10 @@ return II && II->getIntrinsicID() == IID; } -static MemoryEffects getMemoryEffectsFromAttrs(AttributeSet Attrs) { - if (Attrs.hasAttribute(Attribute::ReadNone)) - return MemoryEffects::none(); - - ModRefInfo MR = ModRefInfo::ModRef; - if (Attrs.hasAttribute(Attribute::ReadOnly)) - MR = ModRefInfo::Ref; - else if (Attrs.hasAttribute(Attribute::WriteOnly)) - MR = ModRefInfo::Mod; - - if (Attrs.hasAttribute(Attribute::ArgMemOnly)) - return MemoryEffects::argMemOnly(MR); - if (Attrs.hasAttribute(Attribute::InaccessibleMemOnly)) - return MemoryEffects::inaccessibleMemOnly(MR); - if (Attrs.hasAttribute(Attribute::InaccessibleMemOrArgMemOnly)) - return MemoryEffects::inaccessibleOrArgMemOnly(MR); - return MemoryEffects(MR); -} - /// Returns the behavior when calling the given call site. MemoryEffects BasicAAResult::getMemoryEffects(const CallBase *Call, AAQueryInfo &AAQI) { - MemoryEffects Min = - getMemoryEffectsFromAttrs(Call->getAttributes().getFnAttrs()); + MemoryEffects Min = Call->getAttributes().getFnAttrs().getMemoryEffects(); if (const Function *F = dyn_cast(Call->getCalledOperand())) { MemoryEffects FuncME = AAQI.AAR.getMemoryEffects(F); @@ -791,7 +771,7 @@ MemoryEffects::inaccessibleMemOnly(ModRefInfo::ModRef); } - return getMemoryEffectsFromAttrs(F->getAttributes().getFnAttrs()); + return F->getMemoryEffects(); } /// Returns true if this is a writeonly (i.e Mod only) parameter. Index: llvm/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/lib/AsmParser/LLParser.cpp +++ llvm/lib/AsmParser/LLParser.cpp @@ -148,6 +148,43 @@ std::make_pair(I.first, std::make_pair(I.second, LocTy()))); } +// TODO: This is only a temporary upgrade path, drop it once tests are updated. +static void upgradeMemoryAttrs(AttrBuilder &B) { + if (B.contains(Attribute::Memory)) + return; + + if (B.contains(Attribute::ReadNone)) { + B.removeAttribute(Attribute::ReadNone); + B.addMemoryAttr(MemoryEffects::none()); + return; + } + + ModRefInfo MR = ModRefInfo::ModRef; + if (B.contains(Attribute::ReadOnly)) { + MR = ModRefInfo::Ref; + B.removeAttribute(Attribute::ReadOnly); + } else if (B.contains(Attribute::WriteOnly)) { + MR = ModRefInfo::Mod; + B.removeAttribute(Attribute::WriteOnly); + } + + MemoryEffects ME(MR); + if (B.contains(Attribute::ArgMemOnly)) { + ME = MemoryEffects::argMemOnly(MR); + B.removeAttribute(Attribute::ArgMemOnly); + B.removeAttribute(Attribute::InaccessibleMemOrArgMemOnly); + } else if (B.contains(Attribute::InaccessibleMemOnly)) { + ME = MemoryEffects::inaccessibleMemOnly(MR); + B.removeAttribute(Attribute::InaccessibleMemOnly); + } else if (B.contains(Attribute::InaccessibleMemOrArgMemOnly)) { + ME = MemoryEffects::inaccessibleMemOnly(MR) | MemoryEffects::argMemOnly(MR); + B.removeAttribute(Attribute::InaccessibleMemOrArgMemOnly); + } + + if (ME != MemoryEffects::unknown()) + B.addMemoryAttr(ME); +} + /// validateEndOfModule - Do final validity and basic correctness checks at the /// end of the module. bool LLParser::validateEndOfModule(bool UpgradeDebugInfo) { @@ -165,6 +202,8 @@ B.merge(R->second); } + upgradeMemoryAttrs(B); + if (Function *Fn = dyn_cast(V)) { AttributeList AS = Fn->getAttributes(); AttrBuilder FnAttrs(M->getContext(), AS.getFnAttrs()); @@ -5826,6 +5865,8 @@ FuncAttrs.removeAttribute(Attribute::Alignment); } + upgradeMemoryAttrs(FuncAttrs); + // Okay, if we got here, the function is syntactically valid. Convert types // and do semantic checks. std::vector ParamTypeList; @@ -6596,6 +6637,8 @@ if (I != E) return error(CallLoc, "not enough parameters specified for call"); + upgradeMemoryAttrs(FnAttrs); + // Finish off the Attribute and check them AttributeList PAL = AttributeList::get(Context, AttributeSet::get(Context, FnAttrs), @@ -7304,6 +7347,8 @@ if (I != E) return error(CallLoc, "not enough parameters specified for call"); + upgradeMemoryAttrs(FnAttrs); + // Finish off the Attribute and check them AttributeList PAL = AttributeList::get(Context, AttributeSet::get(Context, FnAttrs), Index: llvm/lib/IR/AttributeImpl.h =================================================================== --- llvm/lib/IR/AttributeImpl.h +++ llvm/lib/IR/AttributeImpl.h @@ -263,6 +263,7 @@ Optional getVScaleRangeMax() const; UWTableKind getUWTableKind() const; AllocFnKind getAllocKind() const; + MemoryEffects getMemoryEffects() const; std::string getAsString(bool InAttrGrp) const; Type *getAttributeType(Attribute::AttrKind Kind) const; Index: llvm/lib/IR/Attributes.cpp =================================================================== --- llvm/lib/IR/Attributes.cpp +++ llvm/lib/IR/Attributes.cpp @@ -211,6 +211,11 @@ return get(Context, UWTable, uint64_t(Kind)); } +Attribute Attribute::getWithMemoryEffects(LLVMContext &Context, + MemoryEffects ME) { + return get(Context, Memory, ME.toIntValue()); +} + Attribute Attribute::getWithAllocSizeArgs(LLVMContext &Context, unsigned ElemSizeArg, const Optional &NumElemsArg) { @@ -831,6 +836,10 @@ return SetNode ? SetNode->getAllocKind() : AllocFnKind::Unknown; } +MemoryEffects AttributeSet::getMemoryEffects() const { + return SetNode ? SetNode->getMemoryEffects() : MemoryEffects::unknown(); +} + std::string AttributeSet::getAsString(bool InAttrGrp) const { return SetNode ? SetNode->getAsString(InAttrGrp) : ""; } @@ -1009,6 +1018,12 @@ return AllocFnKind::Unknown; } +MemoryEffects AttributeSetNode::getMemoryEffects() const { + if (auto A = findEnumAttribute(Attribute::Memory)) + return A->getMemoryEffects(); + return MemoryEffects::unknown(); +} + std::string AttributeSetNode::getAsString(bool InAttrGrp) const { std::string Str; for (iterator I = begin(), E = end(); I != E; ++I) { Index: llvm/lib/IR/Function.cpp =================================================================== --- llvm/lib/IR/Function.cpp +++ llvm/lib/IR/Function.cpp @@ -51,6 +51,7 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/IR/MDBuilder.h" #include "llvm/IR/Metadata.h" +#include "llvm/IR/ModRef.h" #include "llvm/IR/Module.h" #include "llvm/IR/Operator.h" #include "llvm/IR/SymbolTableListTraits.h" @@ -727,6 +728,68 @@ setPrologueData(Src->getPrologueData()); } +MemoryEffects Function::getMemoryEffects() const { + return getAttributes().getFnAttrs().getMemoryEffects(); +} +void Function::setMemoryEffects(MemoryEffects ME) { + addFnAttr(Attribute::getWithMemoryEffects(getContext(), ME)); +} + +/// Determine if the function does not access memory. +bool Function::doesNotAccessMemory() const { + return getMemoryEffects().doesNotAccessMemory(); +} +void Function::setDoesNotAccessMemory() { + setMemoryEffects(MemoryEffects::none()); +} + +/// Determine if the function does not access or only reads memory. +bool Function::onlyReadsMemory() const { + return getMemoryEffects().onlyReadsMemory(); +} +void Function::setOnlyReadsMemory() { + setMemoryEffects(getMemoryEffects() & MemoryEffects::readOnly()); +} + +/// Determine if the function does not access or only writes memory. +bool Function::onlyWritesMemory() const { + return getMemoryEffects().onlyWritesMemory(); +} +void Function::setOnlyWritesMemory() { + setMemoryEffects(getMemoryEffects() & MemoryEffects::writeOnly()); +} + +/// Determine if the call can access memmory only using pointers based +/// on its arguments. +bool Function::onlyAccessesArgMemory() const { + return getMemoryEffects().onlyAccessesArgPointees(); +} +void Function::setOnlyAccessesArgMemory() { + setMemoryEffects(getMemoryEffects() & + MemoryEffects::argMemOnly(ModRefInfo::ModRef)); +} + +/// Determine if the function may only access memory that is +/// inaccessible from the IR. +bool Function::onlyAccessesInaccessibleMemory() const { + return getMemoryEffects().onlyAccessesInaccessibleMem(); +} +void Function::setOnlyAccessesInaccessibleMemory() { + setMemoryEffects(getMemoryEffects() & + MemoryEffects::inaccessibleMemOnly(ModRefInfo::ModRef)); +} + +/// Determine if the function may only access memory that is +/// either inaccessible from the IR or pointed to by its arguments. +bool Function::onlyAccessesInaccessibleMemOrArgMem() const { + return getMemoryEffects().onlyAccessesInaccessibleOrArgMem(); +} +void Function::setOnlyAccessesInaccessibleMemOrArgMem() { + MemoryEffects ME = MemoryEffects::argMemOnly(ModRefInfo::ModRef) | + MemoryEffects::inaccessibleMemOnly(ModRefInfo::ModRef); + setMemoryEffects(getMemoryEffects() & ME); +} + /// Table of string intrinsic names indexed by enum value. static const char * const IntrinsicNameTable[] = { "not_intrinsic", Index: llvm/lib/IR/Instructions.cpp =================================================================== --- llvm/lib/IR/Instructions.cpp +++ llvm/lib/IR/Instructions.cpp @@ -30,6 +30,7 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/IR/MDBuilder.h" #include "llvm/IR/Metadata.h" +#include "llvm/IR/ModRef.h" #include "llvm/IR/Module.h" #include "llvm/IR/Operator.h" #include "llvm/IR/Type.h" @@ -518,6 +519,80 @@ getIntrinsicID() != Intrinsic::assume; } +MemoryEffects CallBase::getMemoryEffects() const { + MemoryEffects ME = getAttributes().getFnAttrs().getMemoryEffects(); + if (auto *Fn = dyn_cast(getCalledOperand())) { + MemoryEffects FnME = Fn->getMemoryEffects(); + if (hasOperandBundles()) { + // TODO: Add a method to get memory effects for operand bundles instead. + if (hasReadingOperandBundles()) + FnME |= MemoryEffects::readOnly(); + if (hasClobberingOperandBundles()) + FnME |= MemoryEffects::writeOnly(); + } + ME &= FnME; + } + return ME; +} +void CallBase::setMemoryEffects(MemoryEffects ME) { + addFnAttr(Attribute::getWithMemoryEffects(getContext(), ME)); +} + +/// Determine if the function does not access memory. +bool CallBase::doesNotAccessMemory() const { + return getMemoryEffects().doesNotAccessMemory(); +} +void CallBase::setDoesNotAccessMemory() { + setMemoryEffects(MemoryEffects::none()); +} + +/// Determine if the function does not access or only reads memory. +bool CallBase::onlyReadsMemory() const { + return getMemoryEffects().onlyReadsMemory(); +} +void CallBase::setOnlyReadsMemory() { + setMemoryEffects(getMemoryEffects() & MemoryEffects::readOnly()); +} + +/// Determine if the function does not access or only writes memory. +bool CallBase::onlyWritesMemory() const { + return getMemoryEffects().onlyWritesMemory(); +} +void CallBase::setOnlyWritesMemory() { + setMemoryEffects(getMemoryEffects() & MemoryEffects::writeOnly()); +} + +/// Determine if the call can access memmory only using pointers based +/// on its arguments. +bool CallBase::onlyAccessesArgMemory() const { + return getMemoryEffects().onlyAccessesArgPointees(); +} +void CallBase::setOnlyAccessesArgMemory() { + setMemoryEffects(getMemoryEffects() & + MemoryEffects::argMemOnly(ModRefInfo::ModRef)); +} + +/// Determine if the function may only access memory that is +/// inaccessible from the IR. +bool CallBase::onlyAccessesInaccessibleMemory() const { + return getMemoryEffects().onlyAccessesInaccessibleMem(); +} +void CallBase::setOnlyAccessesInaccessibleMemory() { + setMemoryEffects(getMemoryEffects() & + MemoryEffects::inaccessibleMemOnly(ModRefInfo::ModRef)); +} + +/// Determine if the function may only access memory that is +/// either inaccessible from the IR or pointed to by its arguments. +bool CallBase::onlyAccessesInaccessibleMemOrArgMem() const { + return getMemoryEffects().onlyAccessesInaccessibleOrArgMem(); +} +void CallBase::setOnlyAccessesInaccessibleMemOrArgMem() { + MemoryEffects FMRB = MemoryEffects::argMemOnly(ModRefInfo::ModRef) | + MemoryEffects::inaccessibleMemOnly(ModRefInfo::ModRef); + setMemoryEffects(getMemoryEffects() & FMRB); +} + //===----------------------------------------------------------------------===// // CallInst Implementation //===----------------------------------------------------------------------===// Index: llvm/lib/Transforms/IPO/FunctionAttrs.cpp =================================================================== --- llvm/lib/Transforms/IPO/FunctionAttrs.cpp +++ llvm/lib/Transforms/IPO/FunctionAttrs.cpp @@ -69,10 +69,7 @@ #define DEBUG_TYPE "function-attrs" -STATISTIC(NumArgMemOnly, "Number of functions marked argmemonly"); -STATISTIC(NumReadNone, "Number of functions marked readnone"); -STATISTIC(NumReadOnly, "Number of functions marked readonly"); -STATISTIC(NumWriteOnly, "Number of functions marked writeonly"); +STATISTIC(NumMemoryAttr, "Number of functions with improved memory attribute"); STATISTIC(NumNoCapture, "Number of arguments marked nocapture"); STATISTIC(NumReturned, "Number of arguments marked returned"); STATISTIC(NumReadNoneArg, "Number of arguments marked readnone"); @@ -253,79 +250,14 @@ return; } - ModRefInfo MR = ME.getModRef(); - for (Function *F : SCCNodes) { - if (F->doesNotAccessMemory()) - // Already perfect! - continue; - - if (ME.doesNotAccessMemory()) { - // For readnone, remove all other memory attributes. - AttributeMask AttrsToRemove; - AttrsToRemove.addAttribute(Attribute::ReadOnly); - AttrsToRemove.addAttribute(Attribute::WriteOnly); - AttrsToRemove.addAttribute(Attribute::ArgMemOnly); - AttrsToRemove.addAttribute(Attribute::InaccessibleMemOnly); - AttrsToRemove.addAttribute(Attribute::InaccessibleMemOrArgMemOnly); - - ++NumReadNone; - F->removeFnAttrs(AttrsToRemove); - F->addFnAttr(Attribute::ReadNone); - Changed.insert(F); - continue; - } - - // Add argmemonly, inaccessiblememonly, or inaccessible_or_argmemonly - // attributes if possible. - AttributeMask AttrsToRemove; - AttrsToRemove.addAttribute(Attribute::ArgMemOnly); - AttrsToRemove.addAttribute(Attribute::InaccessibleMemOnly); - AttrsToRemove.addAttribute(Attribute::InaccessibleMemOrArgMemOnly); - if (ME.onlyAccessesArgPointees()) { - if (!F->onlyAccessesArgMemory()) { - NumArgMemOnly++; - F->removeFnAttrs(AttrsToRemove); - F->addFnAttr(Attribute::ArgMemOnly); - Changed.insert(F); - } - } else if (ME.onlyAccessesInaccessibleMem()) { - if (!F->onlyAccessesInaccessibleMemory()) { - F->removeFnAttrs(AttrsToRemove); - F->addFnAttr(Attribute::InaccessibleMemOnly); - Changed.insert(F); - } - } else if (ME.onlyAccessesInaccessibleOrArgMem() && - !F->onlyAccessesInaccessibleMemOrArgMem()) { - F->removeFnAttrs(AttrsToRemove); - F->addFnAttr(Attribute::InaccessibleMemOrArgMemOnly); + MemoryEffects OldME = F->getMemoryEffects(); + MemoryEffects NewME = ME & OldME; + if (NewME != OldME) { + ++NumMemoryAttr; + F->addFnAttr(Attribute::getWithMemoryEffects(F->getContext(), NewME)); Changed.insert(F); } - - // The SCC contains functions both writing and reading from memory. We - // cannot add readonly or writeonline attributes. - if (MR == ModRefInfo::ModRef) - continue; - - if (F->onlyReadsMemory() && MR == ModRefInfo::Ref) - continue; - - if (F->onlyWritesMemory() && MR == ModRefInfo::Mod) - continue; - - Changed.insert(F); - - // Add in the new attribute. - if (MR == ModRefInfo::Mod) { - ++NumWriteOnly; - F->removeFnAttr(Attribute::ReadOnly); - F->addFnAttr(Attribute::WriteOnly); - } else { - ++NumReadOnly; - assert(MR == ModRefInfo::Ref); - F->removeFnAttr(Attribute::WriteOnly); - F->addFnAttr(Attribute::ReadOnly); - } } } Index: llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp =================================================================== --- llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp +++ llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp @@ -1430,10 +1430,7 @@ // machine model for purposes of optimization. We have to strip these on // both function declarations and call sites. static constexpr Attribute::AttrKind FnAttrsToStrip[] = - {Attribute::ReadNone, Attribute::ReadOnly, Attribute::WriteOnly, - Attribute::ArgMemOnly, Attribute::InaccessibleMemOnly, - Attribute::InaccessibleMemOrArgMemOnly, - Attribute::NoSync, Attribute::NoFree}; + {Attribute::Memory, Attribute::NoSync, Attribute::NoFree}; // Create new attribute set containing only attributes which can be transferred // from original call to the safepoint. Index: llvm/lib/Transforms/Scalar/SCCP.cpp =================================================================== --- llvm/lib/Transforms/Scalar/SCCP.cpp +++ llvm/lib/Transforms/Scalar/SCCP.cpp @@ -590,21 +590,27 @@ } } - // If we replaced an argument, the argmemonly and - // inaccessiblemem_or_argmemonly attributes do not hold any longer. Remove - // them from both the function and callsites. + // If we replaced an argument, we may not also access a global (currently + // classified as "other" memory). Update memory attribute to reflect this. if (ReplacedPointerArg) { - AttributeMask AttributesToRemove; - AttributesToRemove.addAttribute(Attribute::ArgMemOnly); - AttributesToRemove.addAttribute(Attribute::InaccessibleMemOrArgMemOnly); - F.removeFnAttrs(AttributesToRemove); - + auto UpdateAttrs = [&](AttributeList AL) { + MemoryEffects ME = AL.getFnAttrs().getMemoryEffects(); + if (ME == MemoryEffects::unknown()) + return AL; + + ME |= MemoryEffects(MemoryEffects::Other, ModRefInfo::ModRef); + return AL.addFnAttribute( + F.getContext(), + Attribute::getWithMemoryEffects(F.getContext(), ME)); + }; + + F.setAttributes(UpdateAttrs(F.getAttributes())); for (User *U : F.users()) { auto *CB = dyn_cast(U); if (!CB || CB->getCalledFunction() != &F) continue; - CB->removeFnAttrs(AttributesToRemove); + CB->setAttributes(UpdateAttrs(CB->getAttributes())); } } MadeChanges |= ReplacedPointerArg; Index: llvm/test/Analysis/BasicAA/cs-cs.ll =================================================================== --- llvm/test/Analysis/BasicAA/cs-cs.ll +++ llvm/test/Analysis/BasicAA/cs-cs.ll @@ -429,19 +429,19 @@ } -; CHECK: attributes #0 = { argmemonly nocallback nofree nounwind willreturn writeonly } -; CHECK-NEXT: attributes #1 = { argmemonly nocallback nofree nounwind willreturn } -; CHECK-NEXT: attributes #2 = { argmemonly nosync nounwind willreturn } -; CHECK-NEXT: attributes #3 = { noinline nounwind readonly } -; CHECK-NEXT: attributes #4 = { noinline nounwind writeonly } +; CHECK: attributes #0 = { nocallback nofree nounwind willreturn memory(argmem: write) } +; CHECK-NEXT: attributes #1 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) } +; CHECK-NEXT: attributes #2 = { nosync nounwind willreturn memory(argmem: readwrite) } +; CHECK-NEXT: attributes #3 = { noinline nounwind memory(read) } +; CHECK-NEXT: attributes #4 = { noinline nounwind memory(write) } ; CHECK-NEXT: attributes #5 = { nounwind ssp } -; CHECK-NEXT: attributes #6 = { inaccessiblememonly nounwind } -; CHECK-NEXT: attributes #7 = { inaccessiblemem_or_argmemonly nounwind } -; CHECK-NEXT: attributes #8 = { argmemonly nounwind } -; CHECK-NEXT: attributes #9 = { readonly } -; CHECK-NEXT: attributes #10 = { inaccessiblememonly } -; CHECK-NEXT: attributes #11 = { inaccessiblemem_or_argmemonly } -; CHECK-NEXT: attributes #12 = { argmemonly } +; CHECK-NEXT: attributes #6 = { nounwind memory(inaccessiblemem: readwrite) } +; CHECK-NEXT: attributes #7 = { nounwind memory(argmem: readwrite, inaccessiblemem: readwrite) } +; CHECK-NEXT: attributes #8 = { nounwind memory(argmem: readwrite) } +; CHECK-NEXT: attributes #9 = { memory(read) } +; CHECK-NEXT: attributes #10 = { memory(inaccessiblemem: readwrite) } +; CHECK-NEXT: attributes #11 = { memory(argmem: readwrite, inaccessiblemem: readwrite) } +; CHECK-NEXT: attributes #12 = { memory(argmem: readwrite) } attributes #0 = { argmemonly nounwind } attributes #1 = { noinline nounwind readonly } Index: llvm/test/Analysis/BasicAA/intrinsics.ll =================================================================== --- llvm/test/Analysis/BasicAA/intrinsics.ll +++ llvm/test/Analysis/BasicAA/intrinsics.ll @@ -22,6 +22,6 @@ declare <8 x i16> @llvm.masked.load.v8i16.p0v8i16(<8 x i16>*, i32, <8 x i1>, <8 x i16>) nounwind readonly declare void @llvm.masked.store.v8i16.p0v8i16(<8 x i16>, <8 x i16>*, i32, <8 x i1>) nounwind -; CHECK: attributes #0 = { argmemonly nocallback nofree nosync nounwind readonly willreturn } -; CHECK: attributes #1 = { argmemonly nocallback nofree nosync nounwind willreturn writeonly } +; CHECK: attributes #0 = { nocallback nofree nosync nounwind willreturn memory(argmem: read) } +; CHECK: attributes #1 = { nocallback nofree nosync nounwind willreturn memory(argmem: write) } ; CHECK: attributes [[ATTR]] = { nounwind } Index: llvm/test/Analysis/BasicAA/pure-const-dce.ll =================================================================== --- llvm/test/Analysis/BasicAA/pure-const-dce.ll +++ llvm/test/Analysis/BasicAA/pure-const-dce.ll @@ -50,5 +50,5 @@ declare i32 @TestNone(i32) -; CHECK: attributes [[READNONE]] = { readnone } -; CHECK: attributes [[READONLY]] = { readonly } +; CHECK: attributes [[READNONE]] = { memory(none) } +; CHECK: attributes [[READONLY]] = { memory(read) } Index: llvm/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll =================================================================== --- llvm/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll +++ llvm/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll @@ -72,14 +72,14 @@ declare void @callee(i32* %p) nounwind declare void @llvm.memcpy.p0i8.p0i8.i64(i8*, i8*, i64, i1) nounwind -; CHECK: attributes #0 = { mustprogress nofree norecurse nosync nounwind readnone willreturn } -; CHECK: attributes #1 = { argmemonly mustprogress nofree norecurse nosync nounwind willreturn writeonly } -; CHECK: attributes #2 = { nofree nosync nounwind readnone } +; CHECK: attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) } +; CHECK: attributes #1 = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) } +; CHECK: attributes #2 = { nofree nosync nounwind memory(none) } ; CHECK: attributes #3 = { nounwind } -; CHECK: attributes #4 = { mustprogress nofree nosync nounwind readnone willreturn } -; CHECK: attributes #5 = { argmemonly mustprogress nofree nosync nounwind willreturn } -; CHECK: attributes #6 = { argmemonly mustprogress nofree norecurse nosync nounwind willreturn } -; CHECK: attributes #7 = { argmemonly nocallback nofree nounwind willreturn } +; CHECK: attributes #4 = { mustprogress nofree nosync nounwind willreturn memory(none) } +; CHECK: attributes #5 = { mustprogress nofree nosync nounwind willreturn memory(argmem: readwrite) } +; CHECK: attributes #6 = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) } +; CHECK: attributes #7 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) } ; Root note. !0 = !{ } Index: llvm/test/Analysis/TypeBasedAliasAnalysis/intrinsics.ll =================================================================== --- llvm/test/Analysis/TypeBasedAliasAnalysis/intrinsics.ll +++ llvm/test/Analysis/TypeBasedAliasAnalysis/intrinsics.ll @@ -22,8 +22,8 @@ declare <8 x i16> @llvm.masked.load.v8i16.p0v8i16(<8 x i16>*, i32, <8 x i1>, <8 x i16>) nounwind readonly declare void @llvm.masked.store.v8i16.p0v8i16(<8 x i16>, <8 x i16>*, i32, <8 x i1>) nounwind -; CHECK: attributes #0 = { argmemonly nocallback nofree nosync nounwind readonly willreturn } -; CHECK: attributes #1 = { argmemonly nocallback nofree nosync nounwind willreturn writeonly } +; CHECK: attributes #0 = { nocallback nofree nosync nounwind willreturn memory(argmem: read) } +; CHECK: attributes #1 = { nocallback nofree nosync nounwind willreturn memory(argmem: write) } ; CHECK: attributes [[NUW]] = { nounwind } !0 = !{!"tbaa root"} Index: llvm/test/Assembler/aarch64-intrinsics-attributes.ll =================================================================== --- llvm/test/Assembler/aarch64-intrinsics-attributes.ll +++ llvm/test/Assembler/aarch64-intrinsics-attributes.ll @@ -23,4 +23,4 @@ declare @llvm.aarch64.sve.dup.nxv4i32(, , i32) ; CHECK: attributes [[NOFREE_NOUNWIND_WILLRETURN]] = { nofree nounwind willreturn } -; CHECK: attributes [[NO_CALLBACK_NOFREE_NOSYNC_NOUNWIND_READNONE_WILLRETURN]] = { nocallback nofree nosync nounwind readnone willreturn } +; CHECK: attributes [[NO_CALLBACK_NOFREE_NOSYNC_NOUNWIND_READNONE_WILLRETURN]] = { nocallback nofree nosync nounwind willreturn memory(none) } Index: llvm/test/Transforms/DeadArgElim/2010-04-30-DbgInfo.ll =================================================================== --- llvm/test/Transforms/DeadArgElim/2010-04-30-DbgInfo.ll +++ llvm/test/Transforms/DeadArgElim/2010-04-30-DbgInfo.ll @@ -45,7 +45,7 @@ declare void @llvm.dbg.value(metadata, metadata, metadata) nounwind readnone ; CHECK: attributes #0 = { nounwind ssp } -; CHECK: attributes #1 = { nocallback nofree nosync nounwind readnone speculatable willreturn } +; CHECK: attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } ; CHECK: attributes #2 = { noinline nounwind ssp } ; CHECK: attributes [[NUW]] = { nounwind } Index: llvm/test/Transforms/FunctionAttrs/2008-09-03-Mutual.ll =================================================================== --- llvm/test/Transforms/FunctionAttrs/2008-09-03-Mutual.ll +++ llvm/test/Transforms/FunctionAttrs/2008-09-03-Mutual.ll @@ -2,7 +2,7 @@ ; RUN: opt < %s -passes=function-attrs -S | FileCheck %s define i32 @a() { -; CHECK: Function Attrs: nofree nosync nounwind readnone +; CHECK: Function Attrs: nofree nosync nounwind memory(none) ; CHECK-LABEL: define {{[^@]+}}@a ; CHECK-SAME: () #[[ATTR0:[0-9]+]] { ; CHECK-NEXT: [[TMP:%.*]] = call i32 @b() @@ -13,7 +13,7 @@ } define i32 @b() { -; CHECK: Function Attrs: nofree nosync nounwind readnone +; CHECK: Function Attrs: nofree nosync nounwind memory(none) ; CHECK-LABEL: define {{[^@]+}}@b ; CHECK-SAME: () #[[ATTR0]] { ; CHECK-NEXT: [[TMP:%.*]] = call i32 @a() Index: llvm/test/Transforms/FunctionAttrs/2008-09-03-ReadNone.ll =================================================================== --- llvm/test/Transforms/FunctionAttrs/2008-09-03-ReadNone.ll +++ llvm/test/Transforms/FunctionAttrs/2008-09-03-ReadNone.ll @@ -6,7 +6,7 @@ declare i32 @e() readnone define i32 @f() { -; CHECK: Function Attrs: nofree nosync readnone +; CHECK: Function Attrs: nofree nosync memory(none) ; CHECK-LABEL: @f( ; CHECK-NEXT: [[TMP:%.*]] = call i32 @e() ; CHECK-NEXT: ret i32 [[TMP]] @@ -16,7 +16,7 @@ } define i32 @g() readonly { -; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: @g( ; CHECK-NEXT: ret i32 0 ; @@ -24,7 +24,7 @@ } define i32 @h() readnone { -; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: @h( ; CHECK-NEXT: [[TMP:%.*]] = load i32, ptr @x, align 4 ; CHECK-NEXT: ret i32 [[TMP]] Index: llvm/test/Transforms/FunctionAttrs/2008-09-03-ReadOnly.ll =================================================================== --- llvm/test/Transforms/FunctionAttrs/2008-09-03-ReadOnly.ll +++ llvm/test/Transforms/FunctionAttrs/2008-09-03-ReadOnly.ll @@ -2,7 +2,7 @@ ; RUN: opt < %s -passes=function-attrs -S | FileCheck %s define i32 @f() { -; CHECK: Function Attrs: nofree readonly +; CHECK: Function Attrs: nofree memory(read) ; CHECK-LABEL: @f( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP:%.*]] = call i32 @e() Index: llvm/test/Transforms/FunctionAttrs/2008-12-29-Constant.ll =================================================================== --- llvm/test/Transforms/FunctionAttrs/2008-12-29-Constant.ll +++ llvm/test/Transforms/FunctionAttrs/2008-12-29-Constant.ll @@ -4,7 +4,7 @@ @s = external constant i8 define i8 @f() { -; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: @f( ; CHECK-NEXT: [[TMP:%.*]] = load i8, ptr @s, align 1 ; CHECK-NEXT: ret i8 [[TMP]] Index: llvm/test/Transforms/FunctionAttrs/argmemonly.ll =================================================================== --- llvm/test/Transforms/FunctionAttrs/argmemonly.ll +++ llvm/test/Transforms/FunctionAttrs/argmemonly.ll @@ -4,7 +4,7 @@ @g = global i32 20 define void @test_no_read_or_write() { -; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: @test_no_read_or_write( ; CHECK-NEXT: entry: ; CHECK-NEXT: ret void @@ -14,7 +14,7 @@ } define i32 @test_only_read_arg(ptr %ptr) { -; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind readonly willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) ; CHECK-LABEL: @test_only_read_arg( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[L:%.*]] = load i32, ptr [[PTR:%.*]], align 4 @@ -26,7 +26,7 @@ } define i32 @test_only_read_arg_already_has_argmemonly(ptr %ptr) argmemonly { -; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind readonly willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) ; CHECK-LABEL: @test_only_read_arg_already_has_argmemonly( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[L:%.*]] = load i32, ptr [[PTR:%.*]], align 4 @@ -38,7 +38,7 @@ } define i32 @test_read_global() { -; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readonly willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, argmem: none, inaccessiblemem: none) ; CHECK-LABEL: @test_read_global( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[L:%.*]] = load i32, ptr @g, align 4 @@ -50,7 +50,7 @@ } define i32 @test_read_loaded_ptr(ptr %ptr) { -; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readonly willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, inaccessiblemem: none) ; CHECK-LABEL: @test_read_loaded_ptr( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[L:%.*]] = load ptr, ptr [[PTR:%.*]], align 8 @@ -64,7 +64,7 @@ } define void @test_only_write_arg(ptr %ptr) { -; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind willreturn writeonly +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) ; CHECK-LABEL: @test_only_write_arg( ; CHECK-NEXT: entry: ; CHECK-NEXT: store i32 0, ptr [[PTR:%.*]], align 4 @@ -76,7 +76,7 @@ } define void @test_write_global() { -; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn writeonly +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none) ; CHECK-LABEL: @test_write_global( ; CHECK-NEXT: entry: ; CHECK-NEXT: store i32 0, ptr @g, align 4 @@ -103,7 +103,7 @@ declare i32 @fn_readnone() readnone define void @test_call_readnone(ptr %ptr) { -; CHECK: Function Attrs: argmemonly writeonly +; CHECK: Function Attrs: memory(argmem: write) ; CHECK-LABEL: @test_call_readnone( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[C:%.*]] = call i32 @fn_readnone() @@ -119,7 +119,7 @@ declare i32 @fn_argmemonly(ptr) argmemonly define i32 @test_call_argmemonly(ptr %ptr) { -; CHECK: Function Attrs: argmemonly +; CHECK: Function Attrs: memory(argmem: readwrite) ; CHECK-LABEL: @test_call_argmemonly( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[C:%.*]] = call i32 @fn_argmemonly(ptr [[PTR:%.*]]) @@ -131,7 +131,7 @@ } define i32 @test_call_fn_where_argmemonly_can_be_inferred(ptr %ptr) { -; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind readonly willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) ; CHECK-LABEL: @test_call_fn_where_argmemonly_can_be_inferred( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[C:%.*]] = call i32 @test_only_read_arg(ptr [[PTR:%.*]]) @@ -143,7 +143,7 @@ } define void @test_memcpy_argonly(ptr %dst, ptr %src) { -; CHECK: Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn +; CHECK: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: readwrite) ; CHECK-LABEL: @test_memcpy_argonly( ; CHECK-NEXT: entry: ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[DST:%.*]], ptr [[SRC:%.*]], i64 32, i1 false) @@ -159,7 +159,7 @@ @arr = global [32 x i8] zeroinitializer define void @test_memcpy_src_global(ptr %dst) { -; CHECK: Function Attrs: mustprogress nofree nosync nounwind willreturn +; CHECK: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(readwrite, inaccessiblemem: none) ; CHECK-LABEL: @test_memcpy_src_global( ; CHECK-NEXT: entry: ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[DST:%.*]], ptr @arr, i64 32, i1 false) @@ -171,7 +171,7 @@ } define void @test_memcpy_dst_global(ptr %src) { -; CHECK: Function Attrs: mustprogress nofree nosync nounwind willreturn +; CHECK: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(readwrite, inaccessiblemem: none) ; CHECK-LABEL: @test_memcpy_dst_global( ; CHECK-NEXT: entry: ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr @arr, ptr [[SRC:%.*]], i64 32, i1 false) @@ -183,7 +183,7 @@ } define i32 @test_read_arg_access_alloca(ptr %ptr) { -; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind readonly willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) ; CHECK-LABEL: @test_read_arg_access_alloca( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 @@ -203,7 +203,7 @@ declare void @fn_inaccessiblememonly() inaccessiblememonly define void @test_inaccessiblememonly() { -; CHECK: Function Attrs: inaccessiblememonly +; CHECK: Function Attrs: memory(inaccessiblemem: readwrite) ; CHECK-LABEL: @test_inaccessiblememonly( ; CHECK-NEXT: call void @fn_inaccessiblememonly() ; CHECK-NEXT: ret void @@ -213,9 +213,9 @@ } define void @test_inaccessiblememonly_readonly() { -; CHECK: Function Attrs: inaccessiblememonly nofree readonly +; CHECK: Function Attrs: nofree memory(inaccessiblemem: read) ; CHECK-LABEL: @test_inaccessiblememonly_readonly( -; CHECK-NEXT: call void @fn_inaccessiblememonly() #[[ATTR15:[0-9]+]] +; CHECK-NEXT: call void @fn_inaccessiblememonly() #[[ATTR16:[0-9]+]] ; CHECK-NEXT: ret void ; call void @fn_inaccessiblememonly() readonly @@ -223,10 +223,10 @@ } define void @test_inaccessibleorargmemonly_readonly(ptr %arg) { -; CHECK: Function Attrs: inaccessiblemem_or_argmemonly nofree readonly +; CHECK: Function Attrs: nofree memory(argmem: read, inaccessiblemem: read) ; CHECK-LABEL: @test_inaccessibleorargmemonly_readonly( ; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[ARG:%.*]], align 4 -; CHECK-NEXT: call void @fn_inaccessiblememonly() #[[ATTR15]] +; CHECK-NEXT: call void @fn_inaccessiblememonly() #[[ATTR16]] ; CHECK-NEXT: ret void ; load i32, ptr %arg @@ -235,10 +235,10 @@ } define void @test_inaccessibleorargmemonly_readwrite(ptr %arg) { -; CHECK: Function Attrs: inaccessiblemem_or_argmemonly +; CHECK: Function Attrs: memory(argmem: write, inaccessiblemem: read) ; CHECK-LABEL: @test_inaccessibleorargmemonly_readwrite( ; CHECK-NEXT: store i32 0, ptr [[ARG:%.*]], align 4 -; CHECK-NEXT: call void @fn_inaccessiblememonly() #[[ATTR15]] +; CHECK-NEXT: call void @fn_inaccessiblememonly() #[[ATTR16]] ; CHECK-NEXT: ret void ; store i32 0, ptr %arg Index: llvm/test/Transforms/FunctionAttrs/atomic.ll =================================================================== --- llvm/test/Transforms/FunctionAttrs/atomic.ll +++ llvm/test/Transforms/FunctionAttrs/atomic.ll @@ -4,7 +4,7 @@ ; Atomic load/store to local doesn't affect whether a function is ; readnone/readonly. define i32 @test1(i32 %x) uwtable ssp { -; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readnone ssp willreturn uwtable +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind ssp willreturn memory(none) uwtable ; CHECK-LABEL: @test1( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4 @@ -21,7 +21,7 @@ ; A function with an Acquire load is not readonly. define i32 @test2(ptr %x) uwtable ssp { -; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nounwind ssp willreturn uwtable +; CHECK: Function Attrs: mustprogress nofree norecurse nounwind ssp willreturn memory(argmem: readwrite) uwtable ; CHECK-LABEL: @test2( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[R:%.*]] = load atomic i32, ptr [[X:%.*]] seq_cst, align 4 Index: llvm/test/Transforms/FunctionAttrs/convergent.ll =================================================================== --- llvm/test/Transforms/FunctionAttrs/convergent.ll +++ llvm/test/Transforms/FunctionAttrs/convergent.ll @@ -2,7 +2,7 @@ ; RUN: opt -passes=function-attrs -S < %s | FileCheck %s define i32 @nonleaf() convergent { -; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define {{[^@]+}}@nonleaf ; CHECK-SAME: () #[[ATTR0:[0-9]+]] { ; CHECK-NEXT: [[A:%.*]] = call i32 @leaf() @@ -13,7 +13,7 @@ } define i32 @leaf() convergent { -; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define {{[^@]+}}@leaf ; CHECK-SAME: () #[[ATTR0]] { ; CHECK-NEXT: ret i32 0 @@ -85,7 +85,7 @@ } define i32 @recursive1() convergent { -; CHECK: Function Attrs: nofree nosync nounwind readnone +; CHECK: Function Attrs: nofree nosync nounwind memory(none) ; CHECK-LABEL: define {{[^@]+}}@recursive1 ; CHECK-SAME: () #[[ATTR5:[0-9]+]] { ; CHECK-NEXT: [[A:%.*]] = call i32 @recursive2() #[[ATTR1]] @@ -96,7 +96,7 @@ } define i32 @recursive2() convergent { -; CHECK: Function Attrs: nofree nosync nounwind readnone +; CHECK: Function Attrs: nofree nosync nounwind memory(none) ; CHECK-LABEL: define {{[^@]+}}@recursive2 ; CHECK-SAME: () #[[ATTR5]] { ; CHECK-NEXT: [[A:%.*]] = call i32 @recursive1() #[[ATTR1]] Index: llvm/test/Transforms/FunctionAttrs/incompatible_fn_attrs.ll =================================================================== --- llvm/test/Transforms/FunctionAttrs/incompatible_fn_attrs.ll +++ llvm/test/Transforms/FunctionAttrs/incompatible_fn_attrs.ll @@ -5,7 +5,7 @@ ; function attributes when we derive readnone. define ptr @given_argmem_infer_readnone(ptr %p) #0 { -; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: @given_argmem_infer_readnone( ; CHECK-NEXT: entry: ; CHECK-NEXT: ret ptr [[P:%.*]] @@ -15,7 +15,7 @@ } define ptr @given_inaccessible_infer_readnone(ptr %p) #1 { -; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: @given_inaccessible_infer_readnone( ; CHECK-NEXT: entry: ; CHECK-NEXT: ret ptr [[P:%.*]] @@ -25,7 +25,7 @@ } define ptr @given_inaccessible_or_argmem_infer_readnone(ptr %p) #2 { -; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: @given_inaccessible_or_argmem_infer_readnone( ; CHECK-NEXT: entry: ; CHECK-NEXT: ret ptr [[P:%.*]] Index: llvm/test/Transforms/FunctionAttrs/int_sideeffect.ll =================================================================== --- llvm/test/Transforms/FunctionAttrs/int_sideeffect.ll +++ llvm/test/Transforms/FunctionAttrs/int_sideeffect.ll @@ -7,7 +7,7 @@ ; is present. define void @test() { -; CHECK: Function Attrs: inaccessiblememonly mustprogress nofree nosync nounwind willreturn +; CHECK: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(inaccessiblemem: readwrite) ; CHECK-LABEL: @test( ; CHECK-NEXT: call void @llvm.sideeffect() ; CHECK-NEXT: ret void @@ -17,7 +17,7 @@ } define void @loop() { -; CHECK: Function Attrs: inaccessiblememonly nofree noreturn nosync nounwind +; CHECK: Function Attrs: nofree noreturn nosync nounwind memory(inaccessiblemem: readwrite) ; CHECK-LABEL: @loop( ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: Index: llvm/test/Transforms/FunctionAttrs/nofree-attributor.ll =================================================================== --- llvm/test/Transforms/FunctionAttrs/nofree-attributor.ll +++ llvm/test/Transforms/FunctionAttrs/nofree-attributor.ll @@ -14,7 +14,7 @@ ; TEST 1 (positive case) define void @only_return() #0 { -; FNATTR: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind readnone willreturn uwtable +; FNATTR: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable ; FNATTR-LABEL: define {{[^@]+}}@only_return ; FNATTR-SAME: () #[[ATTR3:[0-9]+]] { ; FNATTR-NEXT: ret void @@ -101,7 +101,7 @@ define void @mutual_recursion1() #0 { -; FNATTR: Function Attrs: nofree noinline nosync nounwind readnone uwtable +; FNATTR: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable ; FNATTR-LABEL: define {{[^@]+}}@mutual_recursion1 ; FNATTR-SAME: () #[[ATTR4:[0-9]+]] { ; FNATTR-NEXT: call void @mutual_recursion2() @@ -112,7 +112,7 @@ } define void @mutual_recursion2() #0 { -; FNATTR: Function Attrs: nofree noinline nosync nounwind readnone uwtable +; FNATTR: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable ; FNATTR-LABEL: define {{[^@]+}}@mutual_recursion2 ; FNATTR-SAME: () #[[ATTR4]] { ; FNATTR-NEXT: call void @mutual_recursion1() @@ -174,7 +174,7 @@ declare void @nofree_function() nofree readnone #0 define void @call_nofree_function() #0 { -; FNATTR: Function Attrs: nofree noinline nosync nounwind readnone uwtable +; FNATTR: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable ; FNATTR-LABEL: define {{[^@]+}}@call_nofree_function ; FNATTR-SAME: () #[[ATTR4]] { ; FNATTR-NEXT: tail call void @nofree_function() @@ -225,7 +225,7 @@ declare float @llvm.floor.f32(float) define void @call_floor(float %a) #0 { -; FNATTR: Function Attrs: mustprogress nofree noinline nosync nounwind readnone willreturn uwtable +; FNATTR: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable ; FNATTR-LABEL: define {{[^@]+}}@call_floor ; FNATTR-SAME: (float [[A:%.*]]) #[[ATTR7:[0-9]+]] { ; FNATTR-NEXT: [[TMP1:%.*]] = tail call float @llvm.floor.f32(float [[A]]) @@ -239,7 +239,7 @@ ; Check propagation. define void @f1() #0 { -; FNATTR: Function Attrs: nofree noinline nosync nounwind readnone uwtable +; FNATTR: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable ; FNATTR-LABEL: define {{[^@]+}}@f1 ; FNATTR-SAME: () #[[ATTR4]] { ; FNATTR-NEXT: tail call void @nofree_function() @@ -250,7 +250,7 @@ } define void @f2() #0 { -; FNATTR: Function Attrs: nofree noinline nosync nounwind readnone uwtable +; FNATTR: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable ; FNATTR-LABEL: define {{[^@]+}}@f2 ; FNATTR-SAME: () #[[ATTR4]] { ; FNATTR-NEXT: tail call void @f1() Index: llvm/test/Transforms/FunctionAttrs/nofree.ll =================================================================== --- llvm/test/Transforms/FunctionAttrs/nofree.ll +++ llvm/test/Transforms/FunctionAttrs/nofree.ll @@ -34,7 +34,7 @@ declare void @free(ptr nocapture) local_unnamed_addr #2 define i32 @_Z4foo3Pi(ptr nocapture readonly %a) local_unnamed_addr #3 { -; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind readonly willreturn uwtable +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) uwtable ; CHECK-LABEL: @_Z4foo3Pi( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A:%.*]], align 4 @@ -81,8 +81,8 @@ ; CHECK: Function Attrs: nounwind uwtable ; CHECK-LABEL: @_Z4foo6Pm( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr [[A:%.*]], align 8 -; CHECK-NEXT: [[CALL:%.*]] = tail call ptr @realloc(ptr [[A]], i64 [[TMP1]]) #[[ATTR2]] +; CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr [[A:%.*]], align 8 +; CHECK-NEXT: [[CALL:%.*]] = tail call ptr @realloc(ptr [[A]], i64 [[TMP0]]) #[[ATTR2]] ; CHECK-NEXT: ret ptr [[CALL]] ; entry: Index: llvm/test/Transforms/FunctionAttrs/norecurse.ll =================================================================== --- llvm/test/Transforms/FunctionAttrs/norecurse.ll +++ llvm/test/Transforms/FunctionAttrs/norecurse.ll @@ -2,7 +2,7 @@ ; RUN: opt < %s -aa-pipeline=basic-aa -passes='cgscc(function-attrs),rpo-function-attrs' -S | FileCheck %s define i32 @leaf() { -; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define {{[^@]+}}@leaf ; CHECK-SAME: () #[[ATTR0:[0-9]+]] { ; CHECK-NEXT: ret i32 1 @@ -11,7 +11,7 @@ } define i32 @self_rec() { -; CHECK: Function Attrs: nofree nosync nounwind readnone +; CHECK: Function Attrs: nofree nosync nounwind memory(none) ; CHECK-LABEL: define {{[^@]+}}@self_rec ; CHECK-SAME: () #[[ATTR1:[0-9]+]] { ; CHECK-NEXT: [[A:%.*]] = call i32 @self_rec() @@ -22,7 +22,7 @@ } define i32 @indirect_rec() { -; CHECK: Function Attrs: nofree nosync nounwind readnone +; CHECK: Function Attrs: nofree nosync nounwind memory(none) ; CHECK-LABEL: define {{[^@]+}}@indirect_rec ; CHECK-SAME: () #[[ATTR1]] { ; CHECK-NEXT: [[A:%.*]] = call i32 @indirect_rec2() @@ -33,7 +33,7 @@ } define i32 @indirect_rec2() { -; CHECK: Function Attrs: nofree nosync nounwind readnone +; CHECK: Function Attrs: nofree nosync nounwind memory(none) ; CHECK-LABEL: define {{[^@]+}}@indirect_rec2 ; CHECK-SAME: () #[[ATTR1]] { ; CHECK-NEXT: [[A:%.*]] = call i32 @indirect_rec() @@ -44,7 +44,7 @@ } define i32 @extern() { -; CHECK: Function Attrs: nofree nosync readnone +; CHECK: Function Attrs: nofree nosync memory(none) ; CHECK-LABEL: define {{[^@]+}}@extern ; CHECK-SAME: () #[[ATTR2:[0-9]+]] { ; CHECK-NEXT: [[A:%.*]] = call i32 @k() @@ -57,7 +57,7 @@ declare i32 @k() readnone define void @intrinsic(ptr %dest, ptr %src, i32 %len) { -; CHECK: Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn +; CHECK: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: readwrite) ; CHECK-LABEL: define {{[^@]+}}@intrinsic ; CHECK-SAME: (ptr nocapture writeonly [[DEST:%.*]], ptr nocapture readonly [[SRC:%.*]], i32 [[LEN:%.*]]) #[[ATTR4:[0-9]+]] { ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr [[DEST]], ptr [[SRC]], i32 [[LEN]], i1 false) @@ -70,7 +70,7 @@ declare void @llvm.memcpy.p0.p0.i32(ptr, ptr, i32, i1) define internal i32 @called_by_norecurse() { -; CHECK: Function Attrs: nofree norecurse nosync readnone +; CHECK: Function Attrs: nofree norecurse nosync memory(none) ; CHECK-LABEL: define {{[^@]+}}@called_by_norecurse ; CHECK-SAME: () #[[ATTR6:[0-9]+]] { ; CHECK-NEXT: [[A:%.*]] = call i32 @k() @@ -81,7 +81,7 @@ } define void @m() norecurse { -; CHECK: Function Attrs: nofree norecurse nosync readnone +; CHECK: Function Attrs: nofree norecurse nosync memory(none) ; CHECK-LABEL: define {{[^@]+}}@m ; CHECK-SAME: () #[[ATTR6]] { ; CHECK-NEXT: [[A:%.*]] = call i32 @called_by_norecurse() @@ -92,7 +92,7 @@ } define internal i32 @called_by_norecurse_indirectly() { -; CHECK: Function Attrs: nofree norecurse nosync readnone +; CHECK: Function Attrs: nofree norecurse nosync memory(none) ; CHECK-LABEL: define {{[^@]+}}@called_by_norecurse_indirectly ; CHECK-SAME: () #[[ATTR6]] { ; CHECK-NEXT: [[A:%.*]] = call i32 @k() @@ -103,7 +103,7 @@ } define internal void @o() { -; CHECK: Function Attrs: nofree norecurse nosync readnone +; CHECK: Function Attrs: nofree norecurse nosync memory(none) ; CHECK-LABEL: define {{[^@]+}}@o ; CHECK-SAME: () #[[ATTR6]] { ; CHECK-NEXT: [[A:%.*]] = call i32 @called_by_norecurse_indirectly() @@ -114,7 +114,7 @@ } define void @p() norecurse { -; CHECK: Function Attrs: nofree norecurse nosync readnone +; CHECK: Function Attrs: nofree norecurse nosync memory(none) ; CHECK-LABEL: define {{[^@]+}}@p ; CHECK-SAME: () #[[ATTR6]] { ; CHECK-NEXT: call void @o() @@ -125,7 +125,7 @@ } define internal i32 @escapes_as_parameter(ptr %p) { -; CHECK: Function Attrs: nofree nosync readnone +; CHECK: Function Attrs: nofree nosync memory(none) ; CHECK-LABEL: define {{[^@]+}}@escapes_as_parameter ; CHECK-SAME: (ptr nocapture readnone [[P:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: [[A:%.*]] = call i32 @k() @@ -136,7 +136,7 @@ } define internal void @q() { -; CHECK: Function Attrs: nofree norecurse nosync readnone +; CHECK: Function Attrs: nofree norecurse nosync memory(none) ; CHECK-LABEL: define {{[^@]+}}@q ; CHECK-SAME: () #[[ATTR6]] { ; CHECK-NEXT: [[A:%.*]] = call i32 @escapes_as_parameter(ptr @escapes_as_parameter) @@ -147,7 +147,7 @@ } define void @r() norecurse { -; CHECK: Function Attrs: nofree norecurse nosync readnone +; CHECK: Function Attrs: nofree norecurse nosync memory(none) ; CHECK-LABEL: define {{[^@]+}}@r ; CHECK-SAME: () #[[ATTR6]] { ; CHECK-NEXT: call void @q() Index: llvm/test/Transforms/FunctionAttrs/nosync.ll =================================================================== --- llvm/test/Transforms/FunctionAttrs/nosync.ll +++ llvm/test/Transforms/FunctionAttrs/nosync.ll @@ -6,7 +6,7 @@ ; Base case, empty function define void @test1() { -; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: @test1( ; CHECK-NEXT: ret void ; @@ -15,7 +15,7 @@ ; Show the bottom up walk define void @test2() { -; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: @test2( ; CHECK-NEXT: call void @test1() ; CHECK-NEXT: ret void @@ -38,7 +38,7 @@ } define i32 @test4(i32 %a, i32 %b) { -; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: @test4( ; CHECK-NEXT: [[ADD:%.*]] = add i32 [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: ret i32 [[A]] @@ -49,7 +49,7 @@ ; negative case - explicit sync define void @test5(ptr %p) { -; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nounwind willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) ; CHECK-LABEL: @test5( ; CHECK-NEXT: store atomic i8 0, ptr [[P:%.*]] seq_cst, align 1 ; CHECK-NEXT: ret void @@ -60,7 +60,7 @@ ; negative case - explicit sync define i8 @test6(ptr %p) { -; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nounwind willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) ; CHECK-LABEL: @test6( ; CHECK-NEXT: [[V:%.*]] = load atomic i8, ptr [[P:%.*]] seq_cst, align 1 ; CHECK-NEXT: ret i8 [[V]] @@ -71,7 +71,7 @@ ; negative case - explicit sync define void @test7(ptr %p) { -; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nounwind willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) ; CHECK-LABEL: @test7( ; CHECK-NEXT: [[TMP1:%.*]] = atomicrmw add ptr [[P:%.*]], i8 0 seq_cst, align 1 ; CHECK-NEXT: ret void @@ -104,7 +104,7 @@ ; atomic load with monotonic ordering define i32 @load_monotonic(ptr nocapture readonly %0) norecurse nounwind uwtable { -; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nounwind willreturn uwtable +; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) uwtable ; CHECK-LABEL: @load_monotonic( ; CHECK-NEXT: [[TMP2:%.*]] = load atomic i32, ptr [[TMP0:%.*]] monotonic, align 4 ; CHECK-NEXT: ret i32 [[TMP2]] @@ -115,7 +115,7 @@ ; atomic store with monotonic ordering. define void @store_monotonic(ptr nocapture %0) norecurse nounwind uwtable { -; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nounwind willreturn uwtable +; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) uwtable ; CHECK-LABEL: @store_monotonic( ; CHECK-NEXT: store atomic i32 10, ptr [[TMP0:%.*]] monotonic, align 4 ; CHECK-NEXT: ret void @@ -127,7 +127,7 @@ ; negative, should not deduce nosync ; atomic load with acquire ordering. define i32 @load_acquire(ptr nocapture readonly %0) norecurse nounwind uwtable { -; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nounwind willreturn uwtable +; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) uwtable ; CHECK-LABEL: @load_acquire( ; CHECK-NEXT: [[TMP2:%.*]] = load atomic i32, ptr [[TMP0:%.*]] acquire, align 4 ; CHECK-NEXT: ret i32 [[TMP2]] @@ -137,7 +137,7 @@ } define i32 @load_unordered(ptr nocapture readonly %0) norecurse nounwind uwtable { -; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind readonly willreturn uwtable +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) uwtable ; CHECK-LABEL: @load_unordered( ; CHECK-NEXT: [[TMP2:%.*]] = load atomic i32, ptr [[TMP0:%.*]] unordered, align 4 ; CHECK-NEXT: ret i32 [[TMP2]] @@ -148,7 +148,7 @@ ; atomic store with unordered ordering. define void @store_unordered(ptr nocapture %0) norecurse nounwind uwtable { -; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind willreturn writeonly uwtable +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) uwtable ; CHECK-LABEL: @store_unordered( ; CHECK-NEXT: store atomic i32 10, ptr [[TMP0:%.*]] unordered, align 4 ; CHECK-NEXT: ret void @@ -161,7 +161,7 @@ ; negative, should not deduce nosync ; atomic load with release ordering define void @load_release(ptr nocapture %0) norecurse nounwind uwtable { -; CHECK: Function Attrs: inaccessiblemem_or_argmemonly nofree norecurse nounwind uwtable +; CHECK: Function Attrs: nofree norecurse nounwind memory(argmem: readwrite, inaccessiblemem: readwrite) uwtable ; CHECK-LABEL: @load_release( ; CHECK-NEXT: store atomic volatile i32 10, ptr [[TMP0:%.*]] release, align 4 ; CHECK-NEXT: ret void @@ -172,7 +172,7 @@ ; negative volatile, relaxed atomic define void @load_volatile_release(ptr nocapture %0) norecurse nounwind uwtable { -; CHECK: Function Attrs: inaccessiblemem_or_argmemonly nofree norecurse nounwind uwtable +; CHECK: Function Attrs: nofree norecurse nounwind memory(argmem: readwrite, inaccessiblemem: readwrite) uwtable ; CHECK-LABEL: @load_volatile_release( ; CHECK-NEXT: store atomic volatile i32 10, ptr [[TMP0:%.*]] release, align 4 ; CHECK-NEXT: ret void @@ -183,7 +183,7 @@ ; volatile store. define void @volatile_store(ptr %0) norecurse nounwind uwtable { -; CHECK: Function Attrs: inaccessiblemem_or_argmemonly nofree norecurse nounwind uwtable +; CHECK: Function Attrs: nofree norecurse nounwind memory(argmem: readwrite, inaccessiblemem: readwrite) uwtable ; CHECK-LABEL: @volatile_store( ; CHECK-NEXT: store volatile i32 14, ptr [[TMP0:%.*]], align 4 ; CHECK-NEXT: ret void @@ -195,7 +195,7 @@ ; negative, should not deduce nosync ; volatile load. define i32 @volatile_load(ptr %0) norecurse nounwind uwtable { -; CHECK: Function Attrs: inaccessiblemem_or_argmemonly mustprogress nofree norecurse nounwind willreturn uwtable +; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite, inaccessiblemem: readwrite) uwtable ; CHECK-LABEL: @volatile_load( ; CHECK-NEXT: [[TMP2:%.*]] = load volatile i32, ptr [[TMP0:%.*]], align 4 ; CHECK-NEXT: ret i32 [[TMP2]] @@ -237,7 +237,7 @@ ; negative, checking volatile intrinsics. define i32 @memcpy_volatile(ptr %ptr1, ptr %ptr2) { -; CHECK: Function Attrs: argmemonly mustprogress nofree nounwind willreturn +; CHECK: Function Attrs: mustprogress nofree nounwind willreturn memory(argmem: readwrite) ; CHECK-LABEL: @memcpy_volatile( ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr [[PTR1:%.*]], ptr [[PTR2:%.*]], i32 8, i1 true) ; CHECK-NEXT: ret i32 4 @@ -248,7 +248,7 @@ ; positive, non-volatile intrinsic. define i32 @memset_non_volatile(ptr %ptr1, i8 %val) { -; CHECK: Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn writeonly +; CHECK: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: write) ; CHECK-LABEL: @memset_non_volatile( ; CHECK-NEXT: call void @llvm.memset.p0.i32(ptr [[PTR1:%.*]], i8 [[VAL:%.*]], i32 8, i1 false) ; CHECK-NEXT: ret i32 4 @@ -271,7 +271,7 @@ ; negative. Convergent define void @convergent_readnone(){ -; CHECK: Function Attrs: nofree nosync readnone +; CHECK: Function Attrs: nofree nosync memory(none) ; CHECK-LABEL: @convergent_readnone( ; CHECK-NEXT: call void @readnone_test() ; CHECK-NEXT: ret void @@ -299,7 +299,7 @@ declare float @llvm.cos(float %val) readnone define float @cos_test(float %x) { -; CHECK: Function Attrs: mustprogress nofree nosync nounwind readnone willreturn +; CHECK: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none) ; CHECK-LABEL: @cos_test( ; CHECK-NEXT: [[C:%.*]] = call float @llvm.cos.f32(float [[X:%.*]]) ; CHECK-NEXT: ret float [[C]] Index: llvm/test/Transforms/FunctionAttrs/nounwind.ll =================================================================== --- llvm/test/Transforms/FunctionAttrs/nounwind.ll +++ llvm/test/Transforms/FunctionAttrs/nounwind.ll @@ -3,7 +3,7 @@ ; TEST 1 define i32 @foo1() { -; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define {{[^@]+}}@foo1 ; CHECK-SAME: () #[[ATTR0:[0-9]+]] { ; CHECK-NEXT: ret i32 1 @@ -13,7 +13,7 @@ ; TEST 2 define i32 @scc1_foo() { -; CHECK: Function Attrs: nofree nosync nounwind readnone +; CHECK: Function Attrs: nofree nosync nounwind memory(none) ; CHECK-LABEL: define {{[^@]+}}@scc1_foo ; CHECK-SAME: () #[[ATTR1:[0-9]+]] { ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @scc1_bar() @@ -26,7 +26,7 @@ ; TEST 3 define i32 @scc1_bar() { -; CHECK: Function Attrs: nofree nosync nounwind readnone +; CHECK: Function Attrs: nofree nosync nounwind memory(none) ; CHECK-LABEL: define {{[^@]+}}@scc1_bar ; CHECK-SAME: () #[[ATTR1]] { ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @scc1_foo() Index: llvm/test/Transforms/FunctionAttrs/optnone.ll =================================================================== --- llvm/test/Transforms/FunctionAttrs/optnone.ll +++ llvm/test/Transforms/FunctionAttrs/optnone.ll @@ -20,6 +20,6 @@ ; CHECK: (ptr) #1 ; CHECK-LABEL: attributes #0 -; CHECK: = { mustprogress nofree norecurse nosync nounwind readnone willreturn } +; CHECK: = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) } ; CHECK-LABEL: attributes #1 ; CHECK: = { noinline optnone } Index: llvm/test/Transforms/FunctionAttrs/readattrs.ll =================================================================== --- llvm/test/Transforms/FunctionAttrs/readattrs.ll +++ llvm/test/Transforms/FunctionAttrs/readattrs.ll @@ -18,7 +18,7 @@ } define ptr @test2(ptr %p) { -; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn writeonly +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none) ; CHECK-LABEL: define {{[^@]+}}@test2 ; CHECK-SAME: (ptr readnone returned [[P:%.*]]) #[[ATTR0:[0-9]+]] { ; CHECK-NEXT: store i32 0, ptr @x, align 4 @@ -29,7 +29,7 @@ } define i1 @test3(ptr %p, ptr %q) { -; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define {{[^@]+}}@test3 ; CHECK-SAME: (ptr readnone [[P:%.*]], ptr readnone [[Q:%.*]]) #[[ATTR1:[0-9]+]] { ; CHECK-NEXT: [[A:%.*]] = icmp ult ptr [[P]], [[Q]] @@ -42,7 +42,7 @@ declare void @test4_1(ptr nocapture) readonly define void @test4_2(ptr %p) { -; CHECK: Function Attrs: nofree readonly +; CHECK: Function Attrs: nofree memory(read) ; CHECK-LABEL: define {{[^@]+}}@test4_2 ; CHECK-SAME: (ptr nocapture readonly [[P:%.*]]) #[[ATTR3:[0-9]+]] { ; CHECK-NEXT: call void @test4_1(ptr [[P]]) @@ -54,7 +54,7 @@ ; Missed optz'n: we could make %q readnone, but don't break test6! define void @test5(ptr %p, ptr %q) { -; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind willreturn writeonly +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) ; CHECK-LABEL: define {{[^@]+}}@test5 ; CHECK-SAME: (ptr nocapture writeonly [[P:%.*]], ptr [[Q:%.*]]) #[[ATTR4:[0-9]+]] { ; CHECK-NEXT: store ptr [[Q]], ptr [[P]], align 8 @@ -81,7 +81,7 @@ ; inalloca parameters are always considered written define void @test7_1(ptr inalloca(i32) %a) { -; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) ; CHECK-LABEL: define {{[^@]+}}@test7_1 ; CHECK-SAME: (ptr nocapture inalloca(i32) [[A:%.*]]) #[[ATTR5:[0-9]+]] { ; CHECK-NEXT: ret void @@ -91,7 +91,7 @@ ; preallocated parameters are always considered written define void @test7_2(ptr preallocated(i32) %a) { -; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) ; CHECK-LABEL: define {{[^@]+}}@test7_2 ; CHECK-SAME: (ptr nocapture preallocated(i32) [[A:%.*]]) #[[ATTR5]] { ; CHECK-NEXT: ret void @@ -100,7 +100,7 @@ } define ptr @test8_1(ptr %p) { -; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define {{[^@]+}}@test8_1 ; CHECK-SAME: (ptr readnone returned [[P:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: entry: @@ -111,7 +111,7 @@ } define void @test8_2(ptr %p) { -; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind willreturn writeonly +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) ; CHECK-LABEL: define {{[^@]+}}@test8_2 ; CHECK-SAME: (ptr writeonly [[P:%.*]]) #[[ATTR4]] { ; CHECK-NEXT: entry: @@ -128,7 +128,7 @@ declare void @llvm.masked.scatter.v4i32.v4p0(<4 x i32>%val, <4 x ptr>, i32, <4 x i1>) define void @test9(<4 x ptr> %ptrs, <4 x i32>%val) { -; CHECK: Function Attrs: mustprogress nofree nosync nounwind willreturn writeonly +; CHECK: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(write) ; CHECK-LABEL: define {{[^@]+}}@test9 ; CHECK-SAME: (<4 x ptr> [[PTRS:%.*]], <4 x i32> [[VAL:%.*]]) #[[ATTR7:[0-9]+]] { ; CHECK-NEXT: call void @llvm.masked.scatter.v4i32.v4p0(<4 x i32> [[VAL]], <4 x ptr> [[PTRS]], i32 4, <4 x i1> ) @@ -140,7 +140,7 @@ declare <4 x i32> @llvm.masked.gather.v4i32.v4p0(<4 x ptr>, i32, <4 x i1>, <4 x i32>) define <4 x i32> @test10(<4 x ptr> %ptrs) { -; CHECK: Function Attrs: mustprogress nofree nosync nounwind readonly willreturn +; CHECK: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(read) ; CHECK-LABEL: define {{[^@]+}}@test10 ; CHECK-SAME: (<4 x ptr> [[PTRS:%.*]]) #[[ATTR9:[0-9]+]] { ; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.masked.gather.v4i32.v4p0(<4 x ptr> [[PTRS]], i32 4, <4 x i1> , <4 x i32> undef) @@ -152,7 +152,7 @@ declare <4 x i32> @test11_1(<4 x ptr>) argmemonly nounwind readonly define <4 x i32> @test11_2(<4 x ptr> %ptrs) { -; CHECK: Function Attrs: argmemonly nofree nounwind readonly +; CHECK: Function Attrs: nofree nounwind memory(argmem: read) ; CHECK-LABEL: define {{[^@]+}}@test11_2 ; CHECK-SAME: (<4 x ptr> [[PTRS:%.*]]) #[[ATTR11:[0-9]+]] { ; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @test11_1(<4 x ptr> [[PTRS]]) @@ -164,7 +164,7 @@ declare <4 x i32> @test12_1(<4 x ptr>) argmemonly nounwind define <4 x i32> @test12_2(<4 x ptr> %ptrs) { -; CHECK: Function Attrs: argmemonly nounwind +; CHECK: Function Attrs: nounwind memory(argmem: readwrite) ; CHECK-LABEL: define {{[^@]+}}@test12_2 ; CHECK-SAME: (<4 x ptr> [[PTRS:%.*]]) #[[ATTR12:[0-9]+]] { ; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @test12_1(<4 x ptr> [[PTRS]]) @@ -175,7 +175,7 @@ } define i32 @volatile_load(ptr %p) { -; CHECK: Function Attrs: inaccessiblemem_or_argmemonly mustprogress nofree norecurse nounwind willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite, inaccessiblemem: readwrite) ; CHECK-LABEL: define {{[^@]+}}@volatile_load ; CHECK-SAME: (ptr [[P:%.*]]) #[[ATTR13:[0-9]+]] { ; CHECK-NEXT: [[LOAD:%.*]] = load volatile i32, ptr [[P]], align 4 @@ -246,7 +246,7 @@ } define void @fptr_test1c(ptr %p, ptr %f) { -; CHECK: Function Attrs: nofree readonly +; CHECK: Function Attrs: nofree memory(read) ; CHECK-LABEL: define {{[^@]+}}@fptr_test1c ; CHECK-SAME: (ptr readnone [[P:%.*]], ptr nocapture readonly [[F:%.*]]) #[[ATTR3]] { ; CHECK-NEXT: call void [[F]](ptr readnone [[P]]) #[[ATTR2:[0-9]+]] @@ -278,7 +278,7 @@ } define void @fptr_test2c(ptr %p, ptr %f) { -; CHECK: Function Attrs: nofree readonly +; CHECK: Function Attrs: nofree memory(read) ; CHECK-LABEL: define {{[^@]+}}@fptr_test2c ; CHECK-SAME: (ptr readonly [[P:%.*]], ptr nocapture readonly [[F:%.*]]) #[[ATTR3]] { ; CHECK-NEXT: call void [[F]](ptr readonly [[P]]) #[[ATTR2]] @@ -289,7 +289,7 @@ } define void @alloca_recphi() { -; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone +; CHECK: Function Attrs: nofree norecurse nosync nounwind memory(none) ; CHECK-LABEL: define {{[^@]+}}@alloca_recphi ; CHECK-SAME: () #[[ATTR14:[0-9]+]] { ; CHECK-NEXT: entry: Index: llvm/test/Transforms/FunctionAttrs/stats.ll =================================================================== --- llvm/test/Transforms/FunctionAttrs/stats.ll +++ llvm/test/Transforms/FunctionAttrs/stats.ll @@ -16,13 +16,11 @@ ret void } -; CHECK: 1 function-attrs - Number of functions marked argmemonly +; CHECK: 2 function-attrs - Number of functions with improved memory attribute ; CHECK-NEXT: 1 function-attrs - Number of arguments marked nocapture ; CHECK-NEXT: 1 function-attrs - Number of functions marked as nofree ; CHECK-NEXT: 2 function-attrs - Number of functions marked as norecurse ; CHECK-NEXT: 2 function-attrs - Number of functions marked as nosync ; CHECK-NEXT: 2 function-attrs - Number of functions marked as nounwind -; CHECK-NEXT: 1 function-attrs - Number of functions marked readonly ; CHECK-NEXT: 1 function-attrs - Number of arguments marked readonly ; CHECK-NEXT: 2 function-attrs - Number of functions marked as willreturn -; CHECK-NEXT: 1 function-attrs - Number of functions marked writeonly Index: llvm/test/Transforms/FunctionAttrs/willreturn-callsites.ll =================================================================== --- llvm/test/Transforms/FunctionAttrs/willreturn-callsites.ll +++ llvm/test/Transforms/FunctionAttrs/willreturn-callsites.ll @@ -38,7 +38,7 @@ } define void @test_fn_mustprogress_readonly_calls(ptr %ptr) mustprogress { -; CHECK: Function Attrs: mustprogress nofree readonly willreturn +; CHECK: Function Attrs: mustprogress nofree willreturn memory(read) ; CHECK-LABEL: @test_fn_mustprogress_readonly_calls( ; CHECK-NOT: call void @decl_readonly() # ; CHECK-NOT: call void @decl_readnone() # Index: llvm/test/Transforms/FunctionAttrs/willreturn.ll =================================================================== --- llvm/test/Transforms/FunctionAttrs/willreturn.ll +++ llvm/test/Transforms/FunctionAttrs/willreturn.ll @@ -2,7 +2,7 @@ ; RUN: opt -function-attrs -S %s | FileCheck %s define void @mustprogress_readnone() mustprogress { -; CHECK: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind readnone willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind willreturn memory(none) ; CHECK-LABEL: @mustprogress_readnone( ; CHECK-NEXT: entry: ; CHECK-NEXT: br label [[WHILE_BODY:%.*]] @@ -17,7 +17,7 @@ } define i32 @mustprogress_load(ptr %ptr) mustprogress { -; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse noreturn nosync nounwind readonly willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind willreturn memory(argmem: read) ; CHECK-LABEL: @mustprogress_load( ; CHECK-NEXT: entry: ; CHECK-NEXT: br label [[WHILE_BODY:%.*]] @@ -34,7 +34,7 @@ } define void @mustprogress_store(ptr %ptr) mustprogress { -; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse noreturn nosync nounwind writeonly +; CHECK: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind memory(argmem: write) ; CHECK-LABEL: @mustprogress_store( ; CHECK-NEXT: entry: ; CHECK-NEXT: br label [[WHILE_BODY:%.*]] @@ -63,7 +63,7 @@ } define i32 @mustprogress_call_known_functions(ptr %ptr) mustprogress { -; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse noreturn nosync nounwind readonly willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind willreturn memory(argmem: read) ; CHECK-LABEL: @mustprogress_call_known_functions( ; CHECK-NEXT: call void @mustprogress_readnone() ; CHECK-NEXT: [[R:%.*]] = call i32 @mustprogress_load(ptr [[PTR:%.*]]) @@ -77,7 +77,7 @@ declare i32 @__gxx_personality_v0(...) define i64 @mustprogress_mayunwind() mustprogress personality ptr @__gxx_personality_v0 { -; CHECK: Function Attrs: mustprogress nofree nosync nounwind readnone willreturn +; CHECK: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none) ; CHECK-LABEL: @mustprogress_mayunwind( ; CHECK-NEXT: [[A:%.*]] = invoke i64 @fn_noread() ; CHECK-NEXT: to label [[A:%.*]] unwind label [[B:%.*]] @@ -141,7 +141,7 @@ ; Infinite loop without mustprogress, will not return. define void @willreturn_loop() { -; CHECK: Function Attrs: nofree norecurse noreturn nosync nounwind readnone +; CHECK: Function Attrs: nofree norecurse noreturn nosync nounwind memory(none) ; CHECK-LABEL: @willreturn_loop( ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: @@ -156,7 +156,7 @@ ; Finite loop. Could be willreturn but not detected. ; FIXME define void @willreturn_finite_loop() { -; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone +; CHECK: Function Attrs: nofree norecurse nosync nounwind memory(none) ; CHECK-LABEL: @willreturn_finite_loop( ; CHECK-NEXT: entry: ; CHECK-NEXT: br label [[LOOP:%.*]] @@ -183,7 +183,7 @@ ; Infinite recursion without mustprogress, will not return. define void @willreturn_recursion() { -; CHECK: Function Attrs: nofree nosync nounwind readnone +; CHECK: Function Attrs: nofree nosync nounwind memory(none) ; CHECK-LABEL: @willreturn_recursion( ; CHECK-NEXT: tail call void @willreturn_recursion() ; CHECK-NEXT: ret void @@ -194,7 +194,7 @@ ; Irreducible infinite loop, will not return. define void @willreturn_irreducible(i1 %c) { -; CHECK: Function Attrs: nofree norecurse noreturn nosync nounwind readnone +; CHECK: Function Attrs: nofree norecurse noreturn nosync nounwind memory(none) ; CHECK-LABEL: @willreturn_irreducible( ; CHECK-NEXT: br i1 [[C:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ; CHECK: bb1: Index: llvm/test/Transforms/FunctionAttrs/writeonly.ll =================================================================== --- llvm/test/Transforms/FunctionAttrs/writeonly.ll +++ llvm/test/Transforms/FunctionAttrs/writeonly.ll @@ -2,7 +2,7 @@ ; RUN: opt < %s -passes=function-attrs -S | FileCheck %s define void @nouses-argworn-funrn(ptr writeonly %.aaa) { -; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define {{[^@]+}}@nouses-argworn-funrn ; CHECK-SAME: (ptr nocapture readnone [[DOTAAA:%.*]]) #[[ATTR0:[0-9]+]] { ; CHECK-NEXT: nouses-argworn-funrn_entry: @@ -13,7 +13,7 @@ } define void @nouses-argworn-funro(ptr writeonly %.aaa, ptr %.bbb) { -; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind readonly willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) ; CHECK-LABEL: define {{[^@]+}}@nouses-argworn-funro ; CHECK-SAME: (ptr nocapture readnone [[DOTAAA:%.*]], ptr nocapture readonly [[DOTBBB:%.*]]) #[[ATTR1:[0-9]+]] { ; CHECK-NEXT: nouses-argworn-funro_entry: @@ -30,7 +30,7 @@ @d-ccc = internal global %_type_of_d-ccc <{ ptr null, i8 1, i8 13, i8 0, i8 -127 }>, align 8 define void @nouses-argworn-funwo(ptr writeonly %.aaa) { -; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn writeonly +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none) ; CHECK-LABEL: define {{[^@]+}}@nouses-argworn-funwo ; CHECK-SAME: (ptr nocapture readnone [[DOTAAA:%.*]]) #[[ATTR2:[0-9]+]] { ; CHECK-NEXT: nouses-argworn-funwo_entry: @@ -43,7 +43,7 @@ } define void @test_store(ptr %p) { -; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind willreturn writeonly +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) ; CHECK-LABEL: define {{[^@]+}}@test_store ; CHECK-SAME: (ptr nocapture writeonly [[P:%.*]]) #[[ATTR3:[0-9]+]] { ; CHECK-NEXT: store i8 0, ptr [[P]], align 1 @@ -55,7 +55,7 @@ @G = external global ptr define i8 @test_store_capture(ptr %p) { -; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, argmem: read, inaccessiblemem: none) ; CHECK-LABEL: define {{[^@]+}}@test_store_capture ; CHECK-SAME: (ptr [[P:%.*]]) #[[ATTR4:[0-9]+]] { ; CHECK-NEXT: store ptr [[P]], ptr @G, align 8 @@ -70,7 +70,7 @@ } define void @test_addressing(ptr %p) { -; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind willreturn writeonly +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) ; CHECK-LABEL: define {{[^@]+}}@test_addressing ; CHECK-SAME: (ptr nocapture writeonly [[P:%.*]]) #[[ATTR3]] { ; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8 @@ -83,7 +83,7 @@ } define void @test_readwrite(ptr %p) { -; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) ; CHECK-LABEL: define {{[^@]+}}@test_readwrite ; CHECK-SAME: (ptr nocapture [[P:%.*]]) #[[ATTR5:[0-9]+]] { ; CHECK-NEXT: [[V:%.*]] = load i8, ptr [[P]], align 1 @@ -96,7 +96,7 @@ } define void @test_volatile(ptr %p) { -; CHECK: Function Attrs: inaccessiblemem_or_argmemonly nofree norecurse nounwind +; CHECK: Function Attrs: nofree norecurse nounwind memory(argmem: readwrite, inaccessiblemem: readwrite) ; CHECK-LABEL: define {{[^@]+}}@test_volatile ; CHECK-SAME: (ptr [[P:%.*]]) #[[ATTR6:[0-9]+]] { ; CHECK-NEXT: store volatile i8 0, ptr [[P]], align 1 @@ -107,7 +107,7 @@ } define void @test_atomicrmw(ptr %p) { -; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nounwind willreturn +; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) ; CHECK-LABEL: define {{[^@]+}}@test_atomicrmw ; CHECK-SAME: (ptr nocapture [[P:%.*]]) #[[ATTR7:[0-9]+]] { ; CHECK-NEXT: [[TMP1:%.*]] = atomicrmw add ptr [[P]], i8 0 seq_cst, align 1 @@ -134,7 +134,7 @@ ; writeonly w/o nocapture is not enough define void @direct2(ptr %p) { -; CHECK: Function Attrs: writeonly +; CHECK: Function Attrs: memory(write) ; CHECK-LABEL: define {{[^@]+}}@direct2 ; CHECK-SAME: (ptr [[P:%.*]]) #[[ATTR8:[0-9]+]] { ; CHECK-NEXT: call void @direct2_callee(ptr [[P]]) @@ -146,9 +146,9 @@ } define void @direct2b(ptr %p) { -; CHECK: Function Attrs: writeonly +; CHECK: Function Attrs: memory(write) ; CHECK-LABEL: define {{[^@]+}}@direct2b -; CHECK-SAME: (ptr nocapture writeonly [[P:%.*]]) #[[ATTR8]] { +; CHECK-SAME: (ptr nocapture [[P:%.*]]) #[[ATTR8]] { ; CHECK-NEXT: call void @direct2_callee(ptr nocapture [[P]]) ; CHECK-NEXT: ret void ; @@ -199,9 +199,9 @@ } define void @fptr_test3(ptr %p, ptr %f) { -; CHECK: Function Attrs: writeonly +; CHECK: Function Attrs: memory(write) ; CHECK-LABEL: define {{[^@]+}}@fptr_test3 -; CHECK-SAME: (ptr nocapture writeonly [[P:%.*]], ptr nocapture readonly [[F:%.*]]) #[[ATTR8]] { +; CHECK-SAME: (ptr nocapture [[P:%.*]], ptr nocapture readonly [[F:%.*]]) #[[ATTR8]] { ; CHECK-NEXT: call void [[F]](ptr nocapture [[P]]) #[[ATTR8]] ; CHECK-NEXT: ret void ; Index: llvm/test/Transforms/InstCombine/AArch64/2012-04-23-Neon-Intrinsics.ll =================================================================== --- llvm/test/Transforms/InstCombine/AArch64/2012-04-23-Neon-Intrinsics.ll +++ llvm/test/Transforms/InstCombine/AArch64/2012-04-23-Neon-Intrinsics.ll @@ -65,6 +65,6 @@ declare <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16>, <4 x i16>) nounwind readnone declare <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16>, <4 x i16>) nounwind readnone -; CHECK: attributes #0 = { nounwind readnone ssp } -; CHECK: attributes #1 = { nocallback nofree nosync nounwind readnone willreturn } +; CHECK: attributes #0 = { nounwind ssp memory() } +; CHECK: attributes #1 = { nocallback nofree nosync nounwind willreturn memory() } ; CHECK: attributes [[NUW]] = { nounwind } Index: llvm/test/Transforms/InstCombine/stpncpy-1.ll =================================================================== --- llvm/test/Transforms/InstCombine/stpncpy-1.ll +++ llvm/test/Transforms/InstCombine/stpncpy-1.ll @@ -463,6 +463,6 @@ ret void } ;. -; ANY: attributes #[[ATTR0:[0-9]+]] = { argmemonly nocallback nofree nounwind willreturn writeonly } -; ANY: attributes #[[ATTR1:[0-9]+]] = { argmemonly nocallback nofree nounwind willreturn } +; ANY: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: write) } +; ANY: attributes #[[ATTR1:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: readwrite) } ;. Index: llvm/test/Transforms/LICM/scalar-promote.ll =================================================================== --- llvm/test/Transforms/LICM/scalar-promote.ll +++ llvm/test/Transforms/LICM/scalar-promote.ll @@ -600,7 +600,7 @@ } define i8 @test_hoistable_existing_load_sinkable_store_writeonly(ptr dereferenceable(8) %ptr, i8 %start) writeonly { -; CHECK: Function Attrs: writeonly +; CHECK: Function Attrs: memory(write) ; CHECK-LABEL: @test_hoistable_existing_load_sinkable_store_writeonly( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[PTR_PROMOTED:%.*]] = load i8, ptr [[PTR:%.*]], align 1 @@ -641,7 +641,7 @@ ; Test case for PR51248. define void @test_sink_store_only() writeonly { -; CHECK: Function Attrs: writeonly +; CHECK: Function Attrs: memory(write) ; CHECK-LABEL: @test_sink_store_only( ; CHECK-NEXT: entry: ; CHECK-NEXT: br label [[LOOP_HEADER:%.*]] @@ -678,7 +678,7 @@ } define void @test_sink_store_to_local_object_only_loop_must_execute() writeonly { -; CHECK: Function Attrs: writeonly +; CHECK: Function Attrs: memory(write) ; CHECK-LABEL: @test_sink_store_to_local_object_only_loop_must_execute( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[A:%.*]] = alloca i8, align 1 @@ -719,7 +719,7 @@ ; The store in the loop may not execute, so we need to introduce a load in the ; pre-header. Make sure the writeonly attribute is dropped. define void @test_sink_store_to_local_object_only_loop_may_not_execute(i8 %n) writeonly { -; CHECK: Function Attrs: writeonly +; CHECK: Function Attrs: memory(write) ; CHECK-LABEL: @test_sink_store_to_local_object_only_loop_may_not_execute( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[A:%.*]] = alloca i8, align 1 @@ -761,7 +761,7 @@ declare dereferenceable(8) noalias ptr @alloc_writeonly() writeonly define void @test_sink_store_to_noalias_call_object_only_loop_may_not_execute1(i8 %n) writeonly { -; CHECK: Function Attrs: writeonly +; CHECK: Function Attrs: memory(write) ; CHECK-LABEL: @test_sink_store_to_noalias_call_object_only_loop_may_not_execute1( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[A:%.*]] = call noalias dereferenceable(8) ptr @alloc_writeonly() @@ -801,7 +801,7 @@ } define void @test_sink_store_only_no_phi_needed() writeonly { -; CHECK: Function Attrs: writeonly +; CHECK: Function Attrs: memory(write) ; CHECK-LABEL: @test_sink_store_only_no_phi_needed( ; CHECK-NEXT: entry: ; CHECK-NEXT: br label [[LOOP:%.*]] Index: llvm/test/Transforms/LICM/strlen.ll =================================================================== --- llvm/test/Transforms/LICM/strlen.ll +++ llvm/test/Transforms/LICM/strlen.ll @@ -13,7 +13,7 @@ } ; CHECK: declare i64 @strlen(ptr nocapture) #0 -; CHECK: attributes #0 = { argmemonly mustprogress nofree nounwind readonly willreturn } +; CHECK: attributes #0 = { mustprogress nofree nounwind willreturn memory(argmem: read) } declare i64 @strlen(ptr) Index: llvm/test/Transforms/RewriteStatepointsForGC/X86/intrinsic-attributes.ll =================================================================== --- llvm/test/Transforms/RewriteStatepointsForGC/X86/intrinsic-attributes.ll +++ llvm/test/Transforms/RewriteStatepointsForGC/X86/intrinsic-attributes.ll @@ -1,6 +1,6 @@ ; RUN: opt < %s -S -rewrite-statepoints-for-gc | FileCheck %s -; CHECK: Function Attrs: nounwind readnone +; CHECK: Function Attrs: nounwind memory(none) ; CHECK: declare i64 @llvm.x86.sse2.cvttsd2si64(<2 x double>) declare i64 @llvm.x86.sse2.cvttsd2si64(<2 x double>) Index: llvm/test/Transforms/RewriteStatepointsForGC/statepoint-attrs.ll =================================================================== --- llvm/test/Transforms/RewriteStatepointsForGC/statepoint-attrs.ll +++ llvm/test/Transforms/RewriteStatepointsForGC/statepoint-attrs.ll @@ -20,6 +20,6 @@ attributes #1 = { norecurse noimplicitfloat } ;. -; CHECK: attributes #[[ATTR0:[0-9]+]] = { nounwind readnone } +; CHECK: attributes #[[ATTR0:[0-9]+]] = { nounwind memory(none) } ; CHECK: attributes #[[ATTR1]] = { noimplicitfloat norecurse } ;. Index: llvm/test/Transforms/SCCP/ipscp-drop-argmemonly.ll =================================================================== --- llvm/test/Transforms/SCCP/ipscp-drop-argmemonly.ll +++ llvm/test/Transforms/SCCP/ipscp-drop-argmemonly.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes --check-globals ; RUN: opt -passes=ipsccp -S %s | FileCheck %s ; Test cases to ensure argmemonly/inaccessiblemem_or_argmemonly attributes are @@ -10,8 +10,11 @@ ; Here the pointer argument %arg will be replaced by a constant. We need to ; drop argmemonly. +;. +; CHECK: @[[G:[a-zA-Z0-9_$"\\.-]+]] = internal global i32 0 +;. define internal void @ptrarg.1(i32* %arg, i32 %val) argmemonly nounwind { -; CHECK: Function Attrs: nounwind +; CHECK: Function Attrs: nounwind memory(readwrite, inaccessiblemem: none) ; CHECK-LABEL: @ptrarg.1( ; CHECK-NEXT: store i32 10, i32* @g, align 4 ; CHECK-NEXT: ret void @@ -37,7 +40,7 @@ ; Here only the non-pointer argument %val is replaced, no need ; to drop the argmemonly attribute. define internal void @ptrarg.2(i32* %arg, i32 %val) argmemonly nounwind { -; CHECK: Function Attrs: argmemonly nounwind +; CHECK: Function Attrs: nounwind memory(argmem: readwrite) ; CHECK-LABEL: @ptrarg.2( ; CHECK-NEXT: store i32 10, i32* [[ARG:%.*]], align 4 ; CHECK-NEXT: ret void @@ -59,7 +62,7 @@ ; Here the pointer argument %arg will be replaced by a constant. We need to ; drop inaccessiblemem_or_argmemonly. define internal void @ptrarg.3(i32* %arg, i32 %val) inaccessiblemem_or_argmemonly nounwind { -; CHECK: Function Attrs: nounwind +; CHECK: Function Attrs: nounwind memory(readwrite) ; CHECK-LABEL: @ptrarg.3( ; CHECK-NEXT: store i32 10, i32* @g, align 4 ; CHECK-NEXT: ret void @@ -85,7 +88,7 @@ ; Here only the non-pointer argument %val is replaced, no need ; to drop the inaccessiblemem_or_argmemonly attribute. define internal void @ptrarg.4(i32* %arg, i32 %val) inaccessiblemem_or_argmemonly nounwind { -; CHECK: Function Attrs: inaccessiblemem_or_argmemonly nounwind +; CHECK: Function Attrs: nounwind memory(argmem: readwrite, inaccessiblemem: readwrite) ; CHECK-LABEL: @ptrarg.4( ; CHECK-NEXT: store i32 10, i32* [[ARG:%.*]], align 4 ; CHECK-NEXT: ret void @@ -107,7 +110,7 @@ ; Here the pointer argument %arg will be replaced by a constant. We need to ; drop inaccessiblemem_or_argmemonly. define internal void @ptrarg.5(i32* %arg, i32 %val) argmemonly inaccessiblemem_or_argmemonly nounwind { -; CHECK: Function Attrs: nounwind +; CHECK: Function Attrs: nounwind memory(readwrite, inaccessiblemem: none) ; CHECK-LABEL: @ptrarg.5( ; CHECK-NEXT: store i32 10, i32* @g, align 4 ; CHECK-NEXT: ret void @@ -143,10 +146,10 @@ define i32 @caller.6.cs.attributes(i32 %n) { ; CHECK-LABEL: @caller.6.cs.attributes( ; CHECK-NEXT: store i32 1, i32* @g, align 4 -; CHECK-NEXT: tail call void @ptrarg.5(i32* @g, i32 10) [[NOUNWIND:#[0-9]+]] -; CHECK-NEXT: tail call void @ptrarg.5(i32* @g, i32 10) [[NOUNWIND:#[0-9]+]] -; CHECK-NEXT: tail call void @ptrarg.5(i32* @g, i32 10) [[NOUNWIND:#[0-9]+]] -; CHECK-NEXT: tail call void @ptrarg.5(i32* @g, i32 10) [[NOUNWIND:#[0-9]+]] +; CHECK-NEXT: tail call void @ptrarg.5(i32* @g, i32 10) #[[ATTR0:[0-9]+]] +; CHECK-NEXT: tail call void @ptrarg.5(i32* @g, i32 10) #[[ATTR2:[0-9]+]] +; CHECK-NEXT: tail call void @ptrarg.5(i32* @g, i32 10) #[[ATTR0]] +; CHECK-NEXT: tail call void @ptrarg.5(i32* @g, i32 10) #[[ATTR4:[0-9]+]] ; CHECK-NEXT: [[G_VAL:%.*]] = load i32, i32* @g, align 4 ; CHECK-NEXT: ret i32 [[G_VAL]] ; @@ -159,4 +162,10 @@ ret i32 %g.val } -; CHECK: [[NOUNWIND]] = { nounwind } +;. +; CHECK: attributes #[[ATTR0]] = { nounwind memory(readwrite, inaccessiblemem: none) } +; CHECK: attributes #[[ATTR1:[0-9]+]] = { nounwind memory(argmem: readwrite) } +; CHECK: attributes #[[ATTR2]] = { nounwind memory(readwrite) } +; CHECK: attributes #[[ATTR3:[0-9]+]] = { nounwind memory(argmem: readwrite, inaccessiblemem: readwrite) } +; CHECK: attributes #[[ATTR4]] = { nounwind } +;. Index: llvm/test/Transforms/SCCP/remove-call-inst.ll =================================================================== --- llvm/test/Transforms/SCCP/remove-call-inst.ll +++ llvm/test/Transforms/SCCP/remove-call-inst.ll @@ -36,4 +36,4 @@ } ; CHECK: attributes #0 = { noreturn nounwind } -; CHECK: attributes #1 = { nounwind readnone willreturn } +; CHECK: attributes #1 = { nounwind willreturn memory(none) } Index: llvm/test/Transforms/SimplifyCFG/X86/merge-compatible-invokes-of-landingpad-debuginfo.ll =================================================================== --- llvm/test/Transforms/SimplifyCFG/X86/merge-compatible-invokes-of-landingpad-debuginfo.ll +++ llvm/test/Transforms/SimplifyCFG/X86/merge-compatible-invokes-of-landingpad-debuginfo.ll @@ -68,7 +68,7 @@ declare dso_local i32 @__gxx_personality_v0(...) ;. ; CHECK: attributes #[[ATTR0:[0-9]+]] = { noreturn } -; CHECK: attributes #[[ATTR1:[0-9]+]] = { nocallback nofree nosync nounwind readnone speculatable willreturn } +; CHECK: attributes #[[ATTR1:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } ;. ; CHECK: [[META0:![0-9]+]] = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug) ; CHECK: [[META1:![0-9]+]] = !DIFile(filename: "", directory: "/") Index: llvm/test/Transforms/SimplifyCFG/X86/merge-compatible-invokes-of-landingpad.ll =================================================================== --- llvm/test/Transforms/SimplifyCFG/X86/merge-compatible-invokes-of-landingpad.ll +++ llvm/test/Transforms/SimplifyCFG/X86/merge-compatible-invokes-of-landingpad.ll @@ -2475,5 +2475,5 @@ ;. ; CHECK: attributes #[[ATTR0:[0-9]+]] = { noreturn } ; CHECK: attributes #[[ATTR1]] = { nomerge } -; CHECK: attributes #[[ATTR2]] = { readnone } +; CHECK: attributes #[[ATTR2]] = { memory(none) } ;. Index: llvm/test/Transforms/SimplifyCFG/preserve-branchweights.ll =================================================================== --- llvm/test/Transforms/SimplifyCFG/preserve-branchweights.ll +++ llvm/test/Transforms/SimplifyCFG/preserve-branchweights.ll @@ -1133,7 +1133,7 @@ ;. ; CHECK: attributes #[[ATTR0:[0-9]+]] = { nounwind uwtable } ; CHECK: attributes #[[ATTR1]] = { nounwind } -; CHECK: attributes #[[ATTR2:[0-9]+]] = { noredzone nounwind readnone ssp } +; CHECK: attributes #[[ATTR2:[0-9]+]] = { noredzone nounwind ssp memory(none) } ;. ; CHECK: [[PROF0]] = !{!"branch_weights", i32 5, i32 11} ; CHECK: [[PROF1]] = !{!"branch_weights", i32 1, i32 3} Index: llvm/utils/TableGen/IntrinsicEmitter.cpp =================================================================== --- llvm/utils/TableGen/IntrinsicEmitter.cpp +++ llvm/utils/TableGen/IntrinsicEmitter.cpp @@ -776,49 +776,56 @@ case CodeGenIntrinsic::NoMem: if (Intrinsic.hasSideEffects) break; - OS << " Attribute::get(C, Attribute::ReadNone),\n"; + OS << " Attribute::getWithMemoryEffects(C, " + << "MemoryEffects::none()),\n"; break; case CodeGenIntrinsic::ReadArgMem: - OS << " Attribute::get(C, Attribute::ReadOnly),\n"; - OS << " Attribute::get(C, Attribute::ArgMemOnly),\n"; + OS << " Attribute::getWithMemoryEffects(C, " + << "MemoryEffects::argMemOnly(ModRefInfo::Ref)),\n"; break; case CodeGenIntrinsic::ReadMem: - OS << " Attribute::get(C, Attribute::ReadOnly),\n"; + OS << " Attribute::getWithMemoryEffects(C, " + << "MemoryEffects::readOnly()),\n"; break; case CodeGenIntrinsic::ReadInaccessibleMem: - OS << " Attribute::get(C, Attribute::ReadOnly),\n"; - OS << " Attribute::get(C, Attribute::InaccessibleMemOnly),\n"; + OS << " Attribute::getWithMemoryEffects(C, " + << "MemoryEffects::inaccessibleMemOnly(ModRefInfo::Ref)),\n"; break; case CodeGenIntrinsic::ReadInaccessibleMemOrArgMem: - OS << " Attribute::get(C, Attribute::ReadOnly),\n"; - OS << " Attribute::get(C, " - << "Attribute::InaccessibleMemOrArgMemOnly),\n"; + OS << " Attribute::getWithMemoryEffects(C, " + << "MemoryEffects::inaccessibleMemOnly(ModRefInfo::Ref) | " + << "MemoryEffects::argMemOnly(ModRefInfo::Ref)),\n"; + break; break; case CodeGenIntrinsic::WriteArgMem: - OS << " Attribute::get(C, Attribute::WriteOnly),\n"; - OS << " Attribute::get(C, Attribute::ArgMemOnly),\n"; + OS << " Attribute::getWithMemoryEffects(C, " + << "MemoryEffects::argMemOnly(ModRefInfo::Mod)),\n"; break; case CodeGenIntrinsic::WriteMem: - OS << " Attribute::get(C, Attribute::WriteOnly),\n"; + OS << " Attribute::getWithMemoryEffects(C, " + << "MemoryEffects::writeOnly()),\n"; break; case CodeGenIntrinsic::WriteInaccessibleMem: - OS << " Attribute::get(C, Attribute::WriteOnly),\n"; - OS << " Attribute::get(C, Attribute::InaccessibleMemOnly),\n"; + OS << " Attribute::getWithMemoryEffects(C, " + << "MemoryEffects::inaccessibleMemOnly(ModRefInfo::Mod)),\n"; break; case CodeGenIntrinsic::WriteInaccessibleMemOrArgMem: - OS << " Attribute::get(C, Attribute::WriteOnly),\n"; - OS << " Attribute::get(C, " - << "Attribute::InaccessibleMemOrArgMemOnly),\n"; + OS << " Attribute::getWithMemoryEffects(C, " + << "MemoryEffects::inaccessibleMemOnly(ModRefInfo::Mod) | " + << "MemoryEffects::argMemOnly(ModRefInfo::Mod)),\n"; break; case CodeGenIntrinsic::ReadWriteArgMem: - OS << " Attribute::get(C, Attribute::ArgMemOnly),\n"; + OS << " Attribute::getWithMemoryEffects(C, " + << "MemoryEffects::argMemOnly(ModRefInfo::ModRef)),\n"; break; case CodeGenIntrinsic::ReadWriteInaccessibleMem: - OS << " Attribute::get(C, Attribute::InaccessibleMemOnly),\n"; + OS << " Attribute::getWithMemoryEffects(C, " + << "MemoryEffects::inaccessibleMemOnly(ModRefInfo::ModRef)),\n"; break; case CodeGenIntrinsic::ReadWriteInaccessibleMemOrArgMem: - OS << " Attribute::get(C, " - << "Attribute::InaccessibleMemOrArgMemOnly),\n"; + OS << " Attribute::getWithMemoryEffects(C, " + << "MemoryEffects::inaccessibleMemOnly(ModRefInfo::ModRef) | " + << "MemoryEffects::argMemOnly(ModRefInfo::ModRef)),\n"; break; case CodeGenIntrinsic::ReadWriteMem: break; Index: llvm/utils/UpdateTestChecks/common.py =================================================================== --- llvm/utils/UpdateTestChecks/common.py +++ llvm/utils/UpdateTestChecks/common.py @@ -327,7 +327,7 @@ UNUSED_NOTE = 'NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:' OPT_FUNCTION_RE = re.compile( - r'^(\s*;\s*Function\sAttrs:\s(?P[\w\s]+?))?\s*define\s+(?:internal\s+)?[^@]*@(?P[\w.$-]+?)\s*' + r'^(\s*;\s*Function\sAttrs:\s(?P[\w\s():,]+?))?\s*define\s+(?:internal\s+)?[^@]*@(?P[\w.$-]+?)\s*' r'(?P\((\)|(.*?[\w.-]+?)\))[^{]*\{)\n(?P.*?)^\}$', flags=(re.M | re.S))