Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -1716,6 +1716,12 @@ let Documentation = [PcsDocs]; } +def WriteOnlyFunc : InheritableAttr { + let Spellings = [Clang<"write_only_func">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [WriteOnlyFuncDocs]; +} + def Pure : InheritableAttr { let Spellings = [GCC<"pure">]; let Documentation = [Undocumented]; Index: include/clang/Basic/AttrDocs.td =================================================================== --- include/clang/Basic/AttrDocs.td +++ include/clang/Basic/AttrDocs.td @@ -3324,3 +3324,21 @@ corresponding line within the inlined callee. }]; } + +def WriteOnlyFuncDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The ``write_only_func`` attribute can be applied to a function to indicate +that the function may write to, but does not read from, memory. A write-only +function always writes the same value to the same memory location when called +with the same set of arguments and global state. + +When the ``write_only_func`` attribute is applied, function calls may be +hoisted or eliminated when memory analysis determines it to be safe. When +applied to a virtual function, the overridden functions are expected to +adhere to be write-only functions. + +Mis-applying this attribute may lead to a memory location containing an +incorrect value. + }]; +} Index: lib/CodeGen/CGCall.cpp =================================================================== --- lib/CodeGen/CGCall.cpp +++ lib/CodeGen/CGCall.cpp @@ -1841,6 +1841,9 @@ FuncAttrs.addAttribute(llvm::Attribute::NoReturn); } + if (TargetDecl->hasAttr()) + FuncAttrs.addAttribute(llvm::Attribute::WriteOnly); + // 'const', 'pure' and 'noalias' attributed functions are also nounwind. if (TargetDecl->hasAttr()) { FuncAttrs.addAttribute(llvm::Attribute::ReadNone); Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -6206,6 +6206,9 @@ case AttributeList::AT_Sentinel: handleSentinelAttr(S, D, AL); break; + case AttributeList::AT_WriteOnlyFunc: + handleSimpleAttribute(S, D, AL); + break; case AttributeList::AT_Const: handleSimpleAttribute(S, D, AL); break; Index: test/CodeGen/function-attributes.c =================================================================== --- test/CodeGen/function-attributes.c +++ test/CodeGen/function-attributes.c @@ -109,11 +109,24 @@ _setjmp(0); } +// CHECK-LABEL: define void @f22() +// CHECK: [[WO:#[0-9]+]] +// CHECK: { +// CHECK: call void @f21() +// CHECK: [[WO_CALL:#[0-9]+]] +// CHECK: ret void +__attribute__ ((write_only_func)) void f21(void); +__attribute__ ((write_only_func)) void f22(void) { + f21(); +} + // CHECK: attributes [[NUW]] = { nounwind optsize{{.*}} } // CHECK: attributes [[AI]] = { alwaysinline nounwind optsize{{.*}} } // CHECK: attributes [[NUW_OS_RN]] = { nounwind optsize readnone{{.*}} } // CHECK: attributes [[SR]] = { nounwind optsize{{.*}} "stackrealign"{{.*}} } // CHECK: attributes [[RT]] = { nounwind optsize returns_twice{{.*}} } +// CHECK: attributes [[WO]] = { nounwind optsize writeonly{{.*}} } // CHECK: attributes [[NR]] = { noreturn optsize } // CHECK: attributes [[NUW_RN]] = { nounwind optsize readnone } // CHECK: attributes [[RT_CALL]] = { optsize returns_twice } +// CHECK: attributes [[WO_CALL]] = { optsize writeonly } Index: test/Misc/pragma-attribute-supported-attributes-list.test =================================================================== --- test/Misc/pragma-attribute-supported-attributes-list.test +++ test/Misc/pragma-attribute-supported-attributes-list.test @@ -2,7 +2,7 @@ // The number of supported attributes should never go down! -// CHECK: #pragma clang attribute supports 69 attributes: +// CHECK: #pragma clang attribute supports 70 attributes: // CHECK-NEXT: AMDGPUFlatWorkGroupSize (SubjectMatchRule_function) // CHECK-NEXT: AMDGPUNumSGPR (SubjectMatchRule_function) // CHECK-NEXT: AMDGPUNumVGPR (SubjectMatchRule_function) @@ -70,5 +70,6 @@ // CHECK-NEXT: TestTypestate (SubjectMatchRule_function_is_member) // CHECK-NEXT: TrivialABI (SubjectMatchRule_record) // CHECK-NEXT: WarnUnusedResult (SubjectMatchRule_objc_method, SubjectMatchRule_enum, SubjectMatchRule_record, SubjectMatchRule_hasType_functionType) +// CHECK-NEXT: WriteOnlyFunc (SubjectMatchRule_function) // CHECK-NEXT: XRayInstrument (SubjectMatchRule_function, SubjectMatchRule_objc_method) // CHECK-NEXT: XRayLogArgs (SubjectMatchRule_function, SubjectMatchRule_objc_method)