[Attr] Add noipa function attribute (#203304)

This adds a `noipa` function attribute to LLVM IR. This new attribute
disables any interprocedural analysis that inspects the definition of
the function. Setting this attribute is equivalent to moving the
function definition to a separate, optimizer-opaque, module.

The `noipa` attribute does *not* control inlining or outlining. Add the
`noinline` and `nooutline` attributes as well in cases where inlining
and outlining should additionally be disabled.

Revival of https://reviews.llvm.org/D101011
Discussed in https://discourse.llvm.org/t/noipa-continues/74411

LLVM portion of https://github.com/llvm/llvm-project/issues/40819
This commit is contained in:
J. Ryan Stinnett authored and GitHub committed 2026-06-25 13:27:37 +01:00
1 parent 94ae3dd241
commit c07bc2962c
32 files changed
+453 -7

No files matched your search

+8
View File
@@ -2390,6 +2390,14 @@ For example:
This attribute indicates that the inliner should never inline this
function in any situation. This attribute may not be used together
with the ``alwaysinline`` attribute.
``noipa``
Disables any interprocedural analysis that inspects the definition of this
function. This attribute is equivalent to moving this function definition to
a separate, optimizer-opaque, module. Any attributes on the function are
still respected (as they would be if they remained on a function declaration
in this module). This attribute does *not* control inlining or outlining.
Add the ``noinline`` and ``nooutline`` attributes as well in cases where
inlining and outlining should additionally be disabled.
``nomerge``
This attribute indicates that calls to this function should never be merged
during optimization. For example, it will prevent tail merging otherwise
+5
View File
@@ -97,6 +97,11 @@ Makes programs 10x faster by doing Special New Thing.
* The ``modular-format`` attribute now supports the ``fixed`` aspect for C
ISO 18037 fixed-point ``printf`` specifiers.
* Added `noipa` attribute which disables interprocedural analyses that inspect
the definition of the function. This attribute does *not* control inlining or
outlining. Add the `noinline` and `nooutline` attributes as well in cases
where inlining and outlining should additionally be disabled.
### Changes to LLVM infrastructure
* Removed ``Constant::isZeroValue``. It was functionally identical to
+1
View File
@@ -820,6 +820,7 @@ enum AttributeKindCodes {
ATTR_KIND_DENORMAL_FPENV = 106,
ATTR_KIND_NOOUTLINE = 107,
ATTR_KIND_FLATTEN = 108,
ATTR_KIND_NOIPA = 109,
};
enum ComdatSelectionKindCodes {
+3
View File
@@ -218,6 +218,9 @@ def NoInline : EnumAttr<"noinline", IntersectPreserve, [FnAttr]>;
/// nooutline
def NoOutline : EnumAttr<"nooutline", IntersectPreserve, [FnAttr]>;
/// Do not do interprocedural analysis or optimization including this function
def NoIPA : EnumAttr<"noipa", IntersectPreserve, [FnAttr]>;
/// Function is called early and/or often, so lazy binding isn't worthwhile.
def NonLazyBind : EnumAttr<"nonlazybind", IntersectPreserve, [FnAttr]>;
+10 -2
View File
@@ -165,6 +165,10 @@ private:
/// attribute.
LLVM_ABI bool isNobuiltinFnDef() const;
/// Returns true if the global is a function definition with the noipa
/// attribute.
LLVM_ABI bool isNoipaFnDef() const;
protected:
/// The intrinsic ID for this subclass (which must be a Function).
///
@@ -506,8 +510,12 @@ public:
/// Return true if this global's definition can be substituted with an
/// *arbitrary* definition at link time or load time. We cannot do any IPO or
/// inlining across interposable call edges, since the callee can be
/// replaced with something arbitrary.
LLVM_ABI bool isInterposable() const;
/// replaced with something arbitrary. For most IPO passes, the `noipa`
/// attribute on a function definition is also treated as if it were
/// interposable (and thus blocking interprocedural analysis). Passes
/// which already have their own distinct control attributes (e.g. inlining)
/// may set `CheckNoIPA = false` when calling this.
LLVM_ABI bool isInterposable(bool CheckNoIPA = true) const;
LLVM_ABI bool canBenefitFromLocalAlias() const;
bool hasExternalLinkage() const { return isExternalLinkage(getLinkage()); }
+1 -1
View File
@@ -3245,7 +3245,7 @@ std::optional<InlineResult> llvm::getAttributeBasedInliningDecision(
return InlineResult::failure("optnone attribute");
// Don't inline functions which can be interposed at link-time.
if (Callee->isInterposable())
if (Callee->isInterposable(/*CheckNoIPA=*/false))
return InlineResult::failure("interposable");
// Don't inline functions marked noinline.
+2 -1
View File
@@ -17,7 +17,8 @@
using namespace llvm;
bool llvm::canTrackArgumentsInterprocedurally(Function *F) {
return F->hasLocalLinkage() && !F->hasAddressTaken();
return F->hasExactDefinition() && F->hasLocalLinkage() &&
!F->hasAddressTaken();
}
bool llvm::canTrackReturnsInterprocedurally(Function *F) {
@@ -2308,6 +2308,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
return Attribute::DenormalFPEnv;
case bitc::ATTR_KIND_NOOUTLINE:
return Attribute::NoOutline;
case bitc::ATTR_KIND_NOIPA:
return Attribute::NoIPA;
}
}
@@ -1008,6 +1008,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
return bitc::ATTR_KIND_DENORMAL_FPENV;
case Attribute::NoOutline:
return bitc::ATTR_KIND_NOOUTLINE;
case Attribute::NoIPA:
return bitc::ATTR_KIND_NOIPA;
case Attribute::EndAttrKinds:
llvm_unreachable("Can not encode end-attribute kinds marker.");
case Attribute::None:
+10 -1
View File
@@ -113,7 +113,9 @@ GlobalObject::~GlobalObject() {
setComdat(nullptr);
}
bool GlobalValue::isInterposable() const {
bool GlobalValue::isInterposable(bool CheckNoIPA) const {
if (CheckNoIPA && isNoipaFnDef())
return true;
if (isInterposableLinkage(getLinkage()))
return true;
return !isDSOLocal() && getParent() &&
@@ -334,6 +336,13 @@ bool GlobalValue::isNobuiltinFnDef() const {
return F->hasFnAttribute(Attribute::NoBuiltin);
}
bool GlobalValue::isNoipaFnDef() const {
const Function *F = dyn_cast<Function>(this);
if (!F || F->isDeclaration())
return false;
return F->hasFnAttribute(Attribute::NoIPA);
}
bool GlobalValue::isDeclaration() const {
// Globals are definitions if they have an initializer.
if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(this))
@@ -817,6 +817,10 @@ static Function *promoteArguments(Function *F, FunctionAnalysisManager &FAM,
if (!F->hasLocalLinkage())
return nullptr;
// Ensure function definition is available for interprocedural analysis.
if (!F->isDefinitionExact())
return nullptr;
// Don't promote arguments for variadic functions. Adding, removing, or
// changing non-pack parameters can change the classification of pack
// parameters. Frontends encode that classification at the call site in the
@@ -482,6 +482,12 @@ void DeadArgumentEliminationPass::surveyFunction(const Function &F) {
return;
}
// Ensure function definition is available for interprocedural analysis.
if (!F.isDefinitionExact()) {
markFrozen(F);
return;
}
unsigned RetCount = numRetVals(&F);
// Assume all return values are dead
+4
View File
@@ -1983,6 +1983,10 @@ OptimizeFunctions(Module &M,
if (!F.hasLocalLinkage())
continue;
// Ensure function definition is available for interprocedural analysis.
if (!F.isDefinitionExact())
continue;
// If we have an inalloca parameter that we can safely remove the
// inalloca attribute from, do so. This unlocks optimizations that
// wouldn't be safe in the presence of inalloca.
+3 -1
View File
@@ -428,6 +428,7 @@ static bool hasDistinctMetadataIntrinsic(const Function &F) {
/// Check whether \p F is eligible for function merging.
static bool isEligibleForMerging(Function &F) {
return !F.isDeclaration() && !F.hasAvailableExternallyLinkage() &&
!F.hasFnAttribute(Attribute::NoIPA) &&
!hasDistinctMetadataIntrinsic(F);
}
@@ -473,7 +474,8 @@ template <typename FuncContainer> bool MergeFunctions::run(FuncContainer &M) {
if (!I)
continue;
Function *F = cast<Function>(I);
if (!F->isDeclaration() && !F->hasAvailableExternallyLinkage()) {
if (!F->isDeclaration() && !F->hasAvailableExternallyLinkage() &&
!F->hasFnAttribute(Attribute::NoIPA)) {
Changed |= insert(F);
}
}
@@ -982,6 +982,7 @@ Function *CodeExtractor::constructFunctionDeclaration(
case Attribute::NoFree:
case Attribute::NoImplicitFloat:
case Attribute::NoInline:
case Attribute::NoIPA:
case Attribute::NoOutline:
case Attribute::NonLazyBind:
case Attribute::NoRedZone:
+6
View File
@@ -592,6 +592,11 @@ define void @dead_on_return_sized(ptr dead_on_return(4) %p) {
ret void
}
; CHECK: define void @noipa() [[NOIPA:#[0-9]+]]
define void @noipa() noipa {
ret void
}
; CHECK: attributes #0 = { noreturn }
; CHECK: attributes #1 = { nounwind }
; CHECK: attributes #2 = { memory(none) }
@@ -654,4 +659,5 @@ define void @dead_on_return_sized(ptr dead_on_return(4) %p) {
; CHECK: attributes [[SKIPPROFILE]] = { skipprofile }
; CHECK: attributes [[OPTDEBUG]] = { optdebug }
; CHECK: attributes [[NODIVERGENCESOURCE]] = { nodivergencesource }
; CHECK: attributes [[NOIPA]] = { noipa }
; CHECK: attributes #[[NOBUILTIN]] = { nobuiltin }
@@ -0,0 +1,27 @@
; RUN: opt -passes=argpromotion -S < %s | FileCheck %s
; ArgumentPromotion promoting a by-ref argument of a `noipa` function.
; If `noipa` is working, argpromotion should NOT promote the pointer argument,
; because it requires inspecting the function body to determine load patterns.
; CHECK: define internal i32 @foo(i32 %p.0.val)
define internal i32 @foo(ptr %p) noinline {
%v = load i32, ptr %p
ret i32 %v
}
; CHECK: define internal i32 @foo_noipa(ptr %p)
define internal i32 @foo_noipa(ptr %p) noipa noinline {
%v = load i32, ptr %p
ret i32 %v
}
define i32 @bar() {
%a = alloca i32
store i32 7, ptr %a
%r = call i32 @foo(ptr %a)
%b = alloca i32
store i32 %r, ptr %b
%s = call i32 @foo_noipa(ptr %b)
ret i32 %s
}
+23
View File
@@ -0,0 +1,23 @@
; RUN: opt -passes=deadargelim -S < %s | FileCheck %s
; DeadArgumentElimination removing unused args of a `noipa` function.
; If `noipa` is working, DAE should NOT remove the unused argument %y from @foo,
; because determining which arguments are dead requires inspecting the
; definition.
; CHECK: define internal i32 @foo(i32 %x)
define internal i32 @foo(i32 %x, i32 %y) noinline {
ret i32 %x
}
; CHECK: define internal i32 @foo_noipa(i32 %x, i32 %y)
define internal i32 @foo_noipa(i32 %x, i32 %y) noipa noinline {
ret i32 %x
}
define i32 @bar() {
%r = call i32 @foo(i32 1, i32 2)
%s = call i32 @foo_noipa(i32 1, i32 2)
%res = add i32 %r, %s
ret i32 %res
}
@@ -0,0 +1,24 @@
; RUN: opt -passes='ipsccp<func-spec>' -force-specialization -S < %s | FileCheck %s
; Function specialisation should not activate for `noipa` functions.
define i32 @foo(i32 %x, i32 %y) {
%r2 = add i32 %x, %y
ret i32 %r2
}
define i32 @foo_noipa(i32 %x, i32 %y) noipa {
%r2 = add i32 %x, %y
ret i32 %r2
}
; CHECK: call i32 @foo.specialized.1(
; CHECK: call i32 @foo_noipa(
; CHECK: define internal i32 @foo.specialized.1(
; CHECK-NOT: define internal i32 @foo_noipa.specialized.1(
define i32 @test() {
%r = call i32 @foo(i32 0, i32 5)
%s = call i32 @foo_noipa(i32 0, i32 5)
%res = add i32 %r, %s
ret i32 %res
}
@@ -0,0 +1,36 @@
; RUN: opt -passes=globalopt -S -o - < %s | FileCheck %s
; Calls to `noipa` functions in constructors prevent evaluation.
; CHECK: @object = local_unnamed_addr global i32 4
@object = local_unnamed_addr global i32 0
define void @ctor() {
store i32 4, ptr @object
%a = bitcast ptr @object to ptr
call void @test(ptr %a)
ret void
}
define void @test(ptr %ptr) {
ret void
}
; CHECK: @object_noipa = local_unnamed_addr global i32 0
@object_noipa = local_unnamed_addr global i32 0
define void @ctor_noipa() {
store i32 4, ptr @object_noipa
%a = bitcast ptr @object_noipa to ptr
call void @test_noipa(ptr %a)
ret void
}
define void @test_noipa(ptr %ptr) noipa {
ret void
}
@llvm.global_ctors = appending constant
[2 x { i32, ptr, ptr }]
[ { i32, ptr, ptr } { i32 65535, ptr @ctor, ptr null },
{ i32, ptr, ptr } { i32 65535, ptr @ctor_noipa, ptr null } ]
+22
View File
@@ -0,0 +1,22 @@
; RUN: opt -passes=globalopt -S < %s | FileCheck %s
; GlobalOpt changing calling convention of a `noipa` function.
; If `noipa` is working, GlobalOpt should NOT change the CC of @foo,
; because it requires analyzing callers/callees interprocedurally.
; CHECK: define internal fastcc i32 @foo(
define internal i32 @foo(i32 %x) noinline {
ret i32 %x
}
; CHECK: define internal i32 @foo_noipa(
define internal i32 @foo_noipa(i32 %x) noipa noinline {
ret i32 %x
}
define i32 @bar() {
%r = call i32 @foo(i32 5)
%s = call i32 @foo_noipa(i32 5)
%res = add i32 %r, %s
ret i32 %res
}
@@ -0,0 +1,76 @@
; REQUIRES: aarch64-registered-target
; RUN: opt --passes=globalopt -o - -S < %s | FileCheck %s
; `noipa` resolvers are not eligible for inspection
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
target triple = "aarch64-unknown-linux-gnu"
$callee.resolver = comdat any
$caller.resolver = comdat any
@__aarch64_cpu_features = external local_unnamed_addr global { i64 }
@callee = weak_odr ifunc i32 (), ptr @callee.resolver
@caller = weak_odr ifunc i32 (), ptr @caller.resolver
declare void @__init_cpu_features_resolver() local_unnamed_addr
declare i32 @callee.default() #0
declare i32 @callee._Msve() #1
declare i32 @callee._Msve2() #2
define weak_odr ptr @callee.resolver() noipa comdat {
resolver_entry:
tail call void @__init_cpu_features_resolver()
%0 = load i64, ptr @__aarch64_cpu_features, align 8
%1 = and i64 %0, 69793284352
%2 = icmp eq i64 %1, 69793284352
%3 = and i64 %0, 1073807616
%4 = icmp eq i64 %3, 1073807616
%callee._Msve.callee.default = select i1 %4, ptr @callee._Msve, ptr @callee.default
%common.ret.op = select i1 %2, ptr @callee._Msve2, ptr %callee._Msve.callee.default
ret ptr %common.ret.op
}
; CHECK: define i32 @caller._Msve()
; CHECK: tail call i32 @callee()
define i32 @caller._Msve() #1 {
entry:
%call = tail call i32 @callee()
ret i32 %call
}
; CHECK: define i32 @caller._Msve2()
; CHECK: tail call i32 @callee()
define i32 @caller._Msve2() #2 {
entry:
%call = tail call i32 @callee()
ret i32 %call
}
; CHECK: define i32 @caller.default()
; CHECK: tail call i32 @callee()
define i32 @caller.default() #0 {
entry:
%call = tail call i32 @callee()
ret i32 %call
}
define weak_odr ptr @caller.resolver() comdat {
resolver_entry:
tail call void @__init_cpu_features_resolver()
%0 = load i64, ptr @__aarch64_cpu_features, align 8
%1 = and i64 %0, 69793284352
%2 = icmp eq i64 %1, 69793284352
%3 = and i64 %0, 1073807616
%4 = icmp eq i64 %3, 1073807616
%caller._Msve.caller.default = select i1 %4, ptr @caller._Msve, ptr @caller.default
%common.ret.op = select i1 %2, ptr @caller._Msve2, ptr %caller._Msve.caller.default
ret ptr %common.ret.op
}
attributes #0 = { "fmv-features" }
attributes #1 = { "fmv-features"="sve" }
attributes #2 = { "fmv-features"="sve2" }
@@ -0,0 +1,29 @@
; RUN: opt --passes=globalopt -o - -S < %s | FileCheck %s
; `noipa` resolvers are not eligible for inspection
@static.ifunc = internal ifunc void (), ptr @static.resolver
define ptr @static.resolver() {
ret ptr @static._Msimd
}
define void @static._Msimd() {
ret void
}
define void @static.default() {
ret void
}
@static_noipa.ifunc = internal ifunc void (), ptr @static_noipa.resolver
define ptr @static_noipa.resolver() noipa {
ret ptr @static._Msimd
}
define void @caller() {
; CHECK: call void @static._Msimd()
call void @static.ifunc()
; CHECK: call void @static_noipa.ifunc()
call void @static_noipa.ifunc()
ret void
}
+23
View File
@@ -0,0 +1,23 @@
; RUN: opt -passes=inline -S < %s | FileCheck %s
; Ensure `noipa` does _not_ control inlining. The `noipa` attribute controls
; _other_ interprocedural optimisations by affecting the result of
; `isInterposable` and `isDefinitionExact` checks, but inlining is
; controlled separately by the `noinline` attribute.
define internal i32 @noipa(i32 %x) noipa {
ret i32 %x
}
define internal i32 @noipa_noinline(i32 %x) noipa noinline {
ret i32 %x
}
define i32 @bob() {
%a = call i32 @noipa(i32 1)
%b = call i32 @noipa_noinline(i32 %a)
ret i32 %b
}
; CHECK-NOT: call i32 @noipa(
; CHECK: call i32 @noipa_noinline(
+53
View File
@@ -0,0 +1,53 @@
; RUN: opt -passes=mergefunc -S < %s | FileCheck %s
; MergeFunctions merging a `noipa` function with an identical one.
; If `noipa` is working, MergeFunctions should NOT merge
; @foo_noipa into @baz_noipa (or vice versa), because it inspects
; the function definitions.
; CHECK-NOT: define internal i32 @foo(
define internal i32 @foo(i32 %x, i32 %y) noinline {
%sum = add i32 %x, %y
%mul = mul i32 %sum, %x
%sub = sub i32 %mul, %y
ret i32 %sub
}
; CHECK: define internal i32 @baz(
define internal i32 @baz(i32 %x, i32 %y) noinline {
%sum = add i32 %x, %y
%mul = mul i32 %sum, %x
%sub = sub i32 %mul, %y
ret i32 %sub
}
; CHECK: define internal i32 @foo_noipa(
define internal i32 @foo_noipa(i32 %x, i32 %y) noipa noinline {
%sum = add i32 %x, %y
%mul = mul i32 %sum, %x
%sub = sub i32 %mul, %y
ret i32 %sub
}
; CHECK: define internal i32 @baz_noipa(
define internal i32 @baz_noipa(i32 %x, i32 %y) noipa noinline {
%sum = add i32 %x, %y
%mul = mul i32 %sum, %x
%sub = sub i32 %mul, %y
ret i32 %sub
}
define i32 @bar() {
; CHECK: call i32 @baz(
%r1 = call i32 @foo(i32 1, i32 2)
; CHECK: call i32 @baz(
%r2 = call i32 @baz(i32 3, i32 4)
; CHECK: call i32 @foo_noipa(
%r3 = call i32 @foo_noipa(i32 1, i32 2)
; CHECK: call i32 @baz_noipa(
%r4 = call i32 @baz_noipa(i32 3, i32 4)
%res1 = add i32 %r1, %r2
%res2 = add i32 %r3, %r4
%res3 = add i32 %res1, %res2
ret i32 %res3
}
+25
View File
@@ -0,0 +1,25 @@
; RUN: opt -passes=ipsccp -S < %s | FileCheck %s
; IPSCCP constant-propagating through arguments of a `noipa` function.
; If `noipa` is working, IPSCCP should NOT propagate the constant 42 into @foo,
; because analyzing calls to @foo to determine argument values is IPA.
; CHECK: define internal i32 @foo(i32 %x)
; CHECK-NEXT: ret i32 poison
define internal i32 @foo(i32 %x) noinline {
ret i32 %x
}
; CHECK: define internal i32 @foo_noipa(i32 %x)
; CHECK-NEXT: ret i32 %x
define internal i32 @foo_noipa(i32 %x) noipa noinline {
ret i32 %x
}
define i32 @bar() {
%r = call i32 @foo(i32 42)
%s = call i32 @foo_noipa(i32 42)
; CHECK: %res = add i32 42, %s
%res = add i32 %r, %s
ret i32 %res
}
@@ -0,0 +1,30 @@
; RUN: opt -S -passes=wholeprogramdevirt -whole-program-visibility %s | FileCheck %s
; The `noipa` attribute prevents interprocedural function body inspection,
; including this virtual constant propagation transformation.
@vt1 = constant [1 x ptr] [ptr @vf1], !type !0
@vt2 = constant [1 x ptr] [ptr @vf2], !type !0
define i32 @vf1(ptr %this, i32 %arg) readnone noipa {
ret i32 %arg
}
define i32 @vf2(ptr %this, i32 %arg) readnone {
ret i32 %arg
}
; CHECK: define i32 @fn
define i32 @fn(ptr %obj) {
%vtable = load ptr, ptr %obj
%p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid")
call void @llvm.assume(i1 %p)
%fptr = load ptr, ptr %vtable
; CHECK: call i32 %
%result = call i32 %fptr(ptr %obj, i32 1)
ret i32 %result
}
declare i1 @llvm.type.test(ptr, metadata)
declare void @llvm.assume(i1)
!0 = !{i32 0, !"typeid"}
+13
View File
@@ -644,4 +644,17 @@ TEST(FunctionTest, LLVMGetOrInsertFunction) {
EXPECT_EQ(FuncRef, FuncRef2);
}
TEST(FunctionTest, NoIPAInterposable) {
LLVMContext Ctx;
std::unique_ptr<Module> M = parseIR(Ctx, R"(
define void @foo() { bb1: ret void }
define void @bar() #0 { bb1: ret void }
attributes #0 = { noipa }
)");
EXPECT_FALSE(M->getFunction("foo")->isInterposable());
EXPECT_TRUE(M->getFunction("foo")->isDefinitionExact());
EXPECT_TRUE(M->getFunction("bar")->isInterposable());
EXPECT_FALSE(M->getFunction("bar")->isDefinitionExact());
}
} // end namespace
+1 -1
View File
@@ -35,7 +35,7 @@
`(,(regexp-opt
'("alwaysinline" "argmemonly" "allocsize" "builtin" "cold" "convergent" "dereferenceable" "dereferenceable_or_null" "hot" "immarg" "inaccessiblememonly"
"inaccessiblemem_or_argmemonly" "inalloca" "inlinehint" "jumptable" "minsize" "mustprogress" "naked" "nobuiltin" "nonnull" "nocapture"
"nocallback" "nocf_check" "noduplicate" "noext" "nofree" "noimplicitfloat" "noinline" "nomerge" "nonlazybind" "noprofile" "noredzone" "noreturn"
"nocallback" "nocf_check" "noduplicate" "noext" "nofree" "noimplicitfloat" "noinline" "noipa" "nomerge" "nonlazybind" "noprofile" "noredzone" "noreturn"
"norecurse" "nosync" "noundef" "nounwind" "nosanitize_bounds" "nosanitize_coverage" "null_pointer_is_valid" "optdebug" "optforfuzzing" "optnone" "optsize" "preallocated" "readnone" "readonly" "returned" "returns_twice"
"shadowcallstack" "signext" "speculatable" "speculative_load_hardening" "ssp" "sspreq" "sspstrong" "safestack" "sanitize_address" "sanitize_alloc_token" "sanitize_hwaddress" "sanitize_memtag"
"sanitize_thread" "sanitize_memory" "strictfp" "swifterror" "uwtable" "vscale_range" "willreturn" "writeonly" "zeroext") 'symbols) . font-lock-constant-face)
+1
View File
@@ -104,6 +104,7 @@
<item> nofree </item>
<item> noimplicitfloat </item>
<item> noinline </item>
<item> noipa </item>
<item> nomerge </item>
<item> nooutline </item>
<item> noprofile </item>
+1
View File
@@ -132,6 +132,7 @@ syn keyword llvmKeyword
\ nofree
\ noimplicitfloat
\ noinline
\ noipa
\ nomerge
\ nooutline
\ nonlazybind
@@ -229,6 +229,7 @@ patterns:
\\bnofree\\b|\
\\bnoimplicitfloat\\b|\
\\bnoinline\\b|\
\\bnoipa\\b|\
\\bnomerge\\b|\
\\bnooutline\\b|\
\\bnonlazybind\\b|\