[llvm] f2ba88c - [IR] Mark whether param/ret attributes are ABI relevant (#222575)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 10 03:48:50 PDT 2026
Author: Nikita Popov
Date: 2026-09-10T10:48:44Z
New Revision: f2ba88c9a5ce27c4a90a14c4190f3c41c6069e92
URL: https://github.com/llvm/llvm-project/commit/f2ba88c9a5ce27c4a90a14c4190f3c41c6069e92
DIFF: https://github.com/llvm/llvm-project/commit/f2ba88c9a5ce27c4a90a14c4190f3c41c6069e92.diff
LOG: [IR] Mark whether param/ret attributes are ABI relevant (#222575)
This is specified using ABIAttr in TableGen and queried using
isABIAttr().
Make use of this in the Lint pass, instead of maintaining its own
(outdated) list of ABI attributes.
This has been split out from #207173.
Added:
Modified:
llvm/include/llvm/IR/Attributes.h
llvm/include/llvm/IR/Attributes.td
llvm/lib/Analysis/Lint.cpp
llvm/lib/IR/Attributes.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/IR/Attributes.h b/llvm/include/llvm/IR/Attributes.h
index f8185c76dfb5c..d9ab56cdcc1f6 100644
--- a/llvm/include/llvm/IR/Attributes.h
+++ b/llvm/include/llvm/IR/Attributes.h
@@ -162,6 +162,9 @@ class Attribute {
LLVM_ABI static bool intersectWithMin(AttrKind Kind);
LLVM_ABI static bool intersectWithCustom(AttrKind Kind);
+ /// Whether this is an ABI attribute (for returns or arguments).
+ LLVM_ABI static bool isABIAttr(AttrKind Kind);
+
private:
AttributeImpl *pImpl = nullptr;
diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td
index ea523cad69cd5..c43b499061ddc 100644
--- a/llvm/include/llvm/IR/Attributes.td
+++ b/llvm/include/llvm/IR/Attributes.td
@@ -22,7 +22,8 @@ def ParamAttr : AttrProperty;
/// Can be used as return attribute.
def RetAttr : AttrProperty;
-
+/// This is an ABI-affecting attribute.
+def ABIAttr : AttrProperty;
/// Intersection rules. Used for example in sinking/hoisting two
/// callbases to find a set of attributes that apply to both.
@@ -103,10 +104,10 @@ def AlwaysInline : EnumAttr<"alwaysinline", IntersectPreserve, [FnAttr]>;
def Builtin : EnumAttr<"builtin", IntersectPreserve, [FnAttr]>;
/// Pass structure by value.
-def ByVal : TypeAttr<"byval", IntersectPreserve, [ParamAttr]>;
+def ByVal : TypeAttr<"byval", IntersectPreserve, [ParamAttr, ABIAttr]>;
/// Mark in-memory ABI type.
-def ByRef : TypeAttr<"byref", IntersectPreserve, [ParamAttr]>;
+def ByRef : TypeAttr<"byref", IntersectPreserve, [ParamAttr, ABIAttr]>;
/// Parameter or return value may not contain uninitialized or poison bits.
def NoUndef : EnumAttr<"noundef", IntersectAnd, [ParamAttr, RetAttr]>;
@@ -145,7 +146,7 @@ def FnRetThunkExtern : EnumAttr<"fn_ret_thunk_extern", IntersectPreserve, [FnAtt
def HybridPatchable : EnumAttr<"hybrid_patchable", IntersectPreserve, [FnAttr]>;
/// Pass structure in an alloca.
-def InAlloca : TypeAttr<"inalloca", IntersectPreserve, [ParamAttr]>;
+def InAlloca : TypeAttr<"inalloca", IntersectPreserve, [ParamAttr, ABIAttr]>;
/// Pointer argument memory is initialized.
def Initializes : ConstantRangeListAttr<"initializes", IntersectPreserve, [ParamAttr]>;
@@ -154,7 +155,7 @@ def Initializes : ConstantRangeListAttr<"initializes", IntersectPreserve, [Param
def InlineHint : EnumAttr<"inlinehint", IntersectAnd, [FnAttr]>;
/// Force argument to be passed in register.
-def InReg : EnumAttr<"inreg", IntersectPreserve, [ParamAttr, RetAttr]>;
+def InReg : EnumAttr<"inreg", IntersectPreserve, [ParamAttr, RetAttr, ABIAttr]>;
/// Build jump-instruction tables and replace refs.
def JumpTable : EnumAttr<"jumptable", IntersectPreserve, [FnAttr]>;
@@ -172,7 +173,7 @@ def MinSize : EnumAttr<"minsize", IntersectPreserve, [FnAttr]>;
def Naked : EnumAttr<"naked", IntersectPreserve, [FnAttr]>;
/// Nested function static chain.
-def Nest : EnumAttr<"nest", IntersectPreserve, [ParamAttr]>;
+def Nest : EnumAttr<"nest", IntersectPreserve, [ParamAttr, ABIAttr]>;
/// Considered to not alias after call.
def NoAlias : EnumAttr<"noalias", IntersectAnd, [ParamAttr, RetAttr]>;
@@ -198,7 +199,7 @@ def NoDivergenceSource : EnumAttr<"nodivergencesource", IntersectAnd, [FnAttr]>;
def NoDuplicate : EnumAttr<"noduplicate", IntersectPreserve, [FnAttr]>;
/// No extension needed before/after call (high bits are undefined).
-def NoExt : EnumAttr<"noext", IntersectPreserve, [ParamAttr, RetAttr]>;
+def NoExt : EnumAttr<"noext", IntersectPreserve, [ParamAttr, RetAttr, ABIAttr]>;
/// Function does not deallocate memory.
/// Argument cannot be freed based on the argument pointer.
@@ -281,7 +282,8 @@ def OptimizeForSize : EnumAttr<"optsize", IntersectPreserve, [FnAttr]>;
def OptimizeNone : EnumAttr<"optnone", IntersectPreserve, [FnAttr]>;
/// Similar to byval but without a copy.
-def Preallocated : TypeAttr<"preallocated", IntersectPreserve, [FnAttr, ParamAttr]>;
+def Preallocated : TypeAttr<"preallocated", IntersectPreserve,
+ [FnAttr, ParamAttr, ABIAttr]>;
/// Parameter or return value is within the specified range.
def Range : ConstantRangeAttr<"range", IntersectCustom, [ParamAttr, RetAttr]>;
@@ -308,11 +310,13 @@ def SafeStack : EnumAttr<"safestack", IntersectPreserve, [FnAttr]>;
def ShadowCallStack : EnumAttr<"shadowcallstack", IntersectPreserve, [FnAttr]>;
/// Sign extended before/after call.
-def SExt : EnumAttr<"signext", IntersectPreserve, [ParamAttr, RetAttr]>;
+def SExt : EnumAttr<"signext", IntersectPreserve,
+ [ParamAttr, RetAttr, ABIAttr]>;
/// Alignment of stack for function (3 bits) stored as log2 of alignment with
/// +1 bias 0 means unaligned (
diff erent from alignstack=(1)).
-def StackAlignment : IntAttr<"alignstack", IntersectPreserve, [FnAttr, ParamAttr, RetAttr]>;
+def StackAlignment : IntAttr<"alignstack", IntersectPreserve,
+ [FnAttr, ParamAttr, RetAttr, ABIAttr]>;
/// Function can be speculated.
def Speculatable : EnumAttr<"speculatable", IntersectAnd, [FnAttr]>;
@@ -330,7 +334,7 @@ def StackProtectStrong : EnumAttr<"sspstrong", IntersectPreserve, [FnAttr]>;
def StrictFP : EnumAttr<"strictfp", IntersectPreserve, [FnAttr]>;
/// Hidden pointer to structure to return.
-def StructRet : TypeAttr<"sret", IntersectPreserve, [ParamAttr]>;
+def StructRet : TypeAttr<"sret", IntersectPreserve, [ParamAttr, ABIAttr]>;
/// AddressSanitizer is on.
def SanitizeAddress : EnumAttr<"sanitize_address", IntersectPreserve, [FnAttr]>;
@@ -374,13 +378,13 @@ def SpeculativeLoadHardening : EnumAttr<"speculative_load_hardening",
[FnAttr]>;
/// Argument is swift error.
-def SwiftError : EnumAttr<"swifterror", IntersectPreserve, [ParamAttr]>;
+def SwiftError : EnumAttr<"swifterror", IntersectPreserve, [ParamAttr, ABIAttr]>;
/// Argument is swift self/context.
-def SwiftSelf : EnumAttr<"swiftself", IntersectPreserve, [ParamAttr]>;
+def SwiftSelf : EnumAttr<"swiftself", IntersectPreserve, [ParamAttr, ABIAttr]>;
/// Argument is swift async context.
-def SwiftAsync : EnumAttr<"swiftasync", IntersectPreserve, [ParamAttr]>;
+def SwiftAsync : EnumAttr<"swiftasync", IntersectPreserve, [ParamAttr, ABIAttr]>;
/// Function must be in a unwind table.
def UWTable : IntAttr<"uwtable", IntersectPreserve, [FnAttr]>;
@@ -398,7 +402,8 @@ def Writable : EnumAttr<"writable", IntersectAnd, [ParamAttr]>;
def WriteOnly : EnumAttr<"writeonly", IntersectAnd, [ParamAttr]>;
/// Zero extended before/after call.
-def ZExt : EnumAttr<"zeroext", IntersectPreserve, [ParamAttr, RetAttr]>;
+def ZExt : EnumAttr<"zeroext", IntersectPreserve,
+ [ParamAttr, RetAttr, ABIAttr]>;
/// Function is required to make Forward Progress.
def MustProgress : EnumAttr<"mustprogress", IntersectAnd, [FnAttr]>;
diff --git a/llvm/lib/Analysis/Lint.cpp b/llvm/lib/Analysis/Lint.cpp
index 26e78826848e7..54df723c69e85 100644
--- a/llvm/lib/Analysis/Lint.cpp
+++ b/llvm/lib/Analysis/Lint.cpp
@@ -264,12 +264,13 @@ void Lint::visitCallBase(CallBase &I) {
// Check that ABI attributes for the function and call-site match.
unsigned ArgNo = AI->getOperandNo();
- Attribute::AttrKind ABIAttributes[] = {
- Attribute::ZExt, Attribute::SExt, Attribute::InReg,
- Attribute::ByVal, Attribute::ByRef, Attribute::InAlloca,
- Attribute::Preallocated, Attribute::StructRet};
AttributeList CallAttrs = I.getAttributes();
- for (Attribute::AttrKind Attr : ABIAttributes) {
+ for (Attribute::AttrKind Attr :
+ drop_begin(enum_seq(Attribute::None, Attribute::EndAttrKinds,
+ force_iteration_on_noniterable_enum))) {
+ if (!Attribute::isABIAttr(Attr))
+ continue;
+
Attribute CallAttr = CallAttrs.getParamAttr(ArgNo, Attr);
Attribute FnAttr = F->getParamAttribute(ArgNo, Attr);
Check(CallAttr.isValid() == FnAttr.isValid(),
diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp
index 727a7bcb6a144..7f5f5f34af389 100644
--- a/llvm/lib/IR/Attributes.cpp
+++ b/llvm/lib/IR/Attributes.cpp
@@ -811,6 +811,7 @@ enum AttributeProperty {
IntersectMin = (2 << 3),
IntersectCustom = (3 << 3),
IntersectPropertyMask = (3 << 3),
+ ABIAttr = (1 << 5),
};
#define GET_ATTR_PROP_TABLE
@@ -839,6 +840,10 @@ bool Attribute::canUseAsRetAttr(AttrKind Kind) {
return hasAttributeProperty(Kind, AttributeProperty::RetAttr);
}
+bool Attribute::isABIAttr(AttrKind Kind) {
+ return hasAttributeProperty(Kind, AttributeProperty::ABIAttr);
+}
+
static bool hasIntersectProperty(Attribute::AttrKind Kind,
AttributeProperty Prop) {
assert((Prop == AttributeProperty::IntersectPreserve ||
More information about the llvm-commits
mailing list