[llvm] [Lint] Lint mismatch in ABI attributes (PR #121929)
Nikita Popov via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 7 05:05:35 PST 2025
https://github.com/nikic created https://github.com/llvm/llvm-project/pull/121929
Detect cases where ABI attributes between the call-site and the called function differ. For now this only handles argument attributes.
Inspired by https://discourse.llvm.org/t/difference-between-call-site-attributes-and-declaration-attributes/83902.
>From 135fd6fd025917f05737cca5b1f238ff5785186a Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Tue, 7 Jan 2025 14:02:22 +0100
Subject: [PATCH] [Lint] Lint mismatch in ABI attributes
Detect cases where ABI attributes between the call-site and the
called function differ. For now this only handles argument
attributes.
Inspired by https://discourse.llvm.org/t/difference-between-call-site-attributes-and-declaration-attributes/83902.
---
llvm/lib/Analysis/Lint.cpp | 24 ++++++
llvm/test/Analysis/Lint/abi-attrs.ll | 106 +++++++++++++++++++++++++++
2 files changed, 130 insertions(+)
create mode 100644 llvm/test/Analysis/Lint/abi-attrs.ll
diff --git a/llvm/lib/Analysis/Lint.cpp b/llvm/lib/Analysis/Lint.cpp
index 4689451243cd96..e9d96a0c2972ad 100644
--- a/llvm/lib/Analysis/Lint.cpp
+++ b/llvm/lib/Analysis/Lint.cpp
@@ -266,6 +266,30 @@ void Lint::visitCallBase(CallBase &I) {
visitMemoryReference(I, Loc, DL->getABITypeAlign(Ty), Ty,
MemRef::Read | MemRef::Write);
}
+
+ // 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) {
+ Attribute CallAttr = CallAttrs.getParamAttr(ArgNo, Attr);
+ Attribute FnAttr = F->getParamAttribute(ArgNo, Attr);
+ Check(CallAttr.isValid() == FnAttr.isValid(),
+ Twine("Undefined behavior: ABI attribute ") +
+ Attribute::getNameFromAttrKind(Attr) +
+ " not present on both function and call-site",
+ &I);
+ if (CallAttr.isValid() && FnAttr.isValid()) {
+ Check(CallAttr == FnAttr,
+ Twine("Undefined behavior: ABI attribute ") +
+ Attribute::getNameFromAttrKind(Attr) +
+ " does not have same argument for function and call-site",
+ &I);
+ }
+ }
}
}
}
diff --git a/llvm/test/Analysis/Lint/abi-attrs.ll b/llvm/test/Analysis/Lint/abi-attrs.ll
new file mode 100644
index 00000000000000..5a3ece6602f9c1
--- /dev/null
+++ b/llvm/test/Analysis/Lint/abi-attrs.ll
@@ -0,0 +1,106 @@
+; RUN: opt < %s -passes=lint -disable-output 2>&1 | FileCheck %s
+
+declare void @fn_nothing_i8(i8 %x)
+declare void @fn_zeroext(i8 zeroext %x)
+declare void @fn_signext(i8 signext %x)
+declare void @fn_inreg(i8 inreg %x)
+
+declare void @fn_nothing_ptr(ptr %x)
+declare void @fn_byval(ptr byval(i8) %x)
+declare void @fn_byref(ptr byref(i8) %x)
+declare void @fn_inalloca(ptr inalloca(i8) %x)
+declare void @fn_preallocated(ptr preallocated(i8) %x)
+declare void @fn_sret(ptr sret(i8) %x)
+
+define void @caller_zeroext(i8 %x) {
+; CHECK: Undefined behavior: ABI attribute zeroext not present on both function and call-site
+; CHECK: call void @fn_zeroext(i8 %x)
+ call void @fn_zeroext(i8 %x)
+
+; CHECK: Undefined behavior: ABI attribute zeroext not present on both function and call-site
+; CHECK: call void @fn_nothing_i8(i8 zeroext %x)
+ call void @fn_nothing_i8(i8 zeroext %x)
+ ret void
+}
+
+define void @caller_signext(i8 %x) {
+; CHECK: Undefined behavior: ABI attribute signext not present on both function and call-site
+; CHECK: call void @fn_signext(i8 %x)
+ call void @fn_signext(i8 %x)
+
+; CHECK: Undefined behavior: ABI attribute signext not present on both function and call-site
+; CHECK: call void @fn_nothing_i8(i8 signext %x)
+ call void @fn_nothing_i8(i8 signext %x)
+ ret void
+}
+
+define void @caller_inreg(i8 %x) {
+; CHECK: Undefined behavior: ABI attribute inreg not present on both function and call-site
+; CHECK: call void @fn_inreg(i8 %x)
+ call void @fn_inreg(i8 %x)
+
+; CHECK: Undefined behavior: ABI attribute inreg not present on both function and call-site
+; CHECK: call void @fn_nothing_i8(i8 inreg %x)
+ call void @fn_nothing_i8(i8 inreg %x)
+ ret void
+}
+
+define void @caller_byval(ptr %x) {
+; CHECK: Undefined behavior: ABI attribute byval not present on both function and call-site
+; CHECK: call void @fn_byval(ptr %x)
+ call void @fn_byval(ptr %x)
+
+; CHECK: Undefined behavior: ABI attribute byval not present on both function and call-site
+; CHECK: call void @fn_nothing_ptr(ptr byval(i8) %x)
+ call void @fn_nothing_ptr(ptr byval(i8) %x)
+
+; CHECK: Undefined behavior: ABI attribute byval does not have same argument for function and call-site
+; CHECK: call void @fn_byval(ptr byval(i16) %x)
+ call void @fn_byval(ptr byval(i16) %x)
+ ret void
+}
+
+define void @caller_byref(ptr %x) {
+; CHECK: Undefined behavior: ABI attribute byref not present on both function and call-site
+; CHECK: call void @fn_byref(ptr %x)
+ call void @fn_byref(ptr %x)
+
+; CHECK: Undefined behavior: ABI attribute byref not present on both function and call-site
+; CHECK: call void @fn_nothing_ptr(ptr byref(i8) %x)
+ call void @fn_nothing_ptr(ptr byref(i8) %x)
+
+; CHECK: Undefined behavior: ABI attribute byref does not have same argument for function and call-site
+; CHECK: call void @fn_byref(ptr byref(i16) %x)
+ call void @fn_byref(ptr byref(i16) %x)
+ ret void
+}
+
+define void @caller_inalloca(ptr %x) {
+; CHECK: Undefined behavior: ABI attribute inalloca not present on both function and call-site
+; CHECK: call void @fn_inalloca(ptr %x)
+ call void @fn_inalloca(ptr %x)
+
+; CHECK: Undefined behavior: ABI attribute inalloca not present on both function and call-site
+; CHECK: call void @fn_nothing_ptr(ptr inalloca(i8) %x)
+ call void @fn_nothing_ptr(ptr inalloca(i8) %x)
+
+; CHECK: Undefined behavior: ABI attribute inalloca does not have same argument for function and call-site
+; CHECK: call void @fn_inalloca(ptr inalloca(i16) %x)
+ call void @fn_inalloca(ptr inalloca(i16) %x)
+ ret void
+}
+
+define void @caller_sret(ptr %x) {
+; CHECK: Undefined behavior: ABI attribute sret not present on both function and call-site
+; CHECK: call void @fn_sret(ptr %x)
+ call void @fn_sret(ptr %x)
+
+; CHECK: Undefined behavior: ABI attribute sret not present on both function and call-site
+; CHECK: call void @fn_nothing_ptr(ptr sret(i8) %x)
+ call void @fn_nothing_ptr(ptr sret(i8) %x)
+
+; CHECK: Undefined behavior: ABI attribute sret does not have same argument for function and call-site
+; CHECK: call void @fn_sret(ptr sret(i16) %x)
+ call void @fn_sret(ptr sret(i16) %x)
+ ret void
+}
More information about the llvm-commits
mailing list