Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -1794,6 +1794,13 @@ let Documentation = [Undocumented]; } +def NoMerge : InheritableAttr { + let Spellings = [Clang<"nomerge">]; + let Subjects = SubjectList<[FunctionLike]>; + let Documentation = [NoMergeDocs]; + let SimpleHandler = 1; +} + def NoInstrumentFunction : InheritableAttr { let Spellings = [GCC<"no_instrument_function">]; let Subjects = SubjectList<[Function]>; Index: clang/include/clang/Basic/AttrDocs.td =================================================================== --- clang/include/clang/Basic/AttrDocs.td +++ clang/include/clang/Basic/AttrDocs.td @@ -350,6 +350,19 @@ }]; } +def NoMergeDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Calls to functions marked `nomerge` will not be merged during optimization. +This attribute can be used to prevent the optimizer from obscuring the source +location of certain calls. For example, it will prevent tail merging otherwise +identical code sequences that raise an exception or terminate the program. Tail +merging normally reduces the precision of source location information, making +stack traces less useful for debugging. This attribute gives the user control +over the tradeoff between code size and debug information precision. + }]; +} + def AssertCapabilityDocs : Documentation { let Category = DocCatFunction; let Heading = "assert_capability, assert_shared_capability"; Index: clang/lib/CodeGen/CGCall.cpp =================================================================== --- clang/lib/CodeGen/CGCall.cpp +++ clang/lib/CodeGen/CGCall.cpp @@ -1905,6 +1905,8 @@ FuncAttrs.addAttribute(llvm::Attribute::NoDuplicate); if (TargetDecl->hasAttr()) FuncAttrs.addAttribute(llvm::Attribute::Convergent); + if (TargetDecl->hasAttr()) + FuncAttrs.addAttribute(llvm::Attribute::NoMerge); if (const FunctionDecl *Fn = dyn_cast(TargetDecl)) { AddAttributesFromFunctionProtoType( Index: clang/test/CodeGen/attr-nomerge.c =================================================================== --- /dev/null +++ clang/test/CodeGen/attr-nomerge.c @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -S -emit-llvm %s -o - | FileCheck %s + +void bar() __attribute__((nomerge)); + +void foo(int i) { + if (i == 5) { + bar(); + } else if (i == 7) { + bar(); + } + bar(); +} +// CHECK: declare void @bar(...) #[[NOMERGEATTR:[0-9]+]] +// CHECK: attributes #[[NOMERGEATTR]] = { nomerge {{.*}} } Index: clang/test/Misc/pragma-attribute-supported-attributes-list.test =================================================================== --- clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -89,6 +89,7 @@ // CHECK-NEXT: NoEscape (SubjectMatchRule_variable_is_parameter) // CHECK-NEXT: NoInline (SubjectMatchRule_function) // CHECK-NEXT: NoInstrumentFunction (SubjectMatchRule_function) +// CHECK-NEXT: NoMerge (SubjectMatchRule_function) // CHECK-NEXT: NoMicroMips (SubjectMatchRule_function) // CHECK-NEXT: NoMips16 (SubjectMatchRule_function) // CHECK-NEXT: NoSanitize (SubjectMatchRule_function, SubjectMatchRule_objc_method, SubjectMatchRule_variable_is_global)