Skip to content

Commit f993a8b

Browse files
authored
[Lint] Lint mismatch in ABI attributes (#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.
1 parent 92e575d commit f993a8b

File tree

2 files changed

+130
-0
lines changed

2 files changed

+130
-0
lines changed

llvm/lib/Analysis/Lint.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,30 @@ void Lint::visitCallBase(CallBase &I) {
266266
visitMemoryReference(I, Loc, DL->getABITypeAlign(Ty), Ty,
267267
MemRef::Read | MemRef::Write);
268268
}
269+
270+
// Check that ABI attributes for the function and call-site match.
271+
unsigned ArgNo = AI->getOperandNo();
272+
Attribute::AttrKind ABIAttributes[] = {
273+
Attribute::ZExt, Attribute::SExt, Attribute::InReg,
274+
Attribute::ByVal, Attribute::ByRef, Attribute::InAlloca,
275+
Attribute::Preallocated, Attribute::StructRet};
276+
AttributeList CallAttrs = I.getAttributes();
277+
for (Attribute::AttrKind Attr : ABIAttributes) {
278+
Attribute CallAttr = CallAttrs.getParamAttr(ArgNo, Attr);
279+
Attribute FnAttr = F->getParamAttribute(ArgNo, Attr);
280+
Check(CallAttr.isValid() == FnAttr.isValid(),
281+
Twine("Undefined behavior: ABI attribute ") +
282+
Attribute::getNameFromAttrKind(Attr) +
283+
" not present on both function and call-site",
284+
&I);
285+
if (CallAttr.isValid() && FnAttr.isValid()) {
286+
Check(CallAttr == FnAttr,
287+
Twine("Undefined behavior: ABI attribute ") +
288+
Attribute::getNameFromAttrKind(Attr) +
289+
" does not have same argument for function and call-site",
290+
&I);
291+
}
292+
}
269293
}
270294
}
271295
}

llvm/test/Analysis/Lint/abi-attrs.ll

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
; RUN: opt < %s -passes=lint -disable-output 2>&1 | FileCheck %s
2+
3+
declare void @fn_nothing_i8(i8 %x)
4+
declare void @fn_zeroext(i8 zeroext %x)
5+
declare void @fn_signext(i8 signext %x)
6+
declare void @fn_inreg(i8 inreg %x)
7+
8+
declare void @fn_nothing_ptr(ptr %x)
9+
declare void @fn_byval(ptr byval(i8) %x)
10+
declare void @fn_byref(ptr byref(i8) %x)
11+
declare void @fn_inalloca(ptr inalloca(i8) %x)
12+
declare void @fn_preallocated(ptr preallocated(i8) %x)
13+
declare void @fn_sret(ptr sret(i8) %x)
14+
15+
define void @caller_zeroext(i8 %x) {
16+
; CHECK: Undefined behavior: ABI attribute zeroext not present on both function and call-site
17+
; CHECK: call void @fn_zeroext(i8 %x)
18+
call void @fn_zeroext(i8 %x)
19+
20+
; CHECK: Undefined behavior: ABI attribute zeroext not present on both function and call-site
21+
; CHECK: call void @fn_nothing_i8(i8 zeroext %x)
22+
call void @fn_nothing_i8(i8 zeroext %x)
23+
ret void
24+
}
25+
26+
define void @caller_signext(i8 %x) {
27+
; CHECK: Undefined behavior: ABI attribute signext not present on both function and call-site
28+
; CHECK: call void @fn_signext(i8 %x)
29+
call void @fn_signext(i8 %x)
30+
31+
; CHECK: Undefined behavior: ABI attribute signext not present on both function and call-site
32+
; CHECK: call void @fn_nothing_i8(i8 signext %x)
33+
call void @fn_nothing_i8(i8 signext %x)
34+
ret void
35+
}
36+
37+
define void @caller_inreg(i8 %x) {
38+
; CHECK: Undefined behavior: ABI attribute inreg not present on both function and call-site
39+
; CHECK: call void @fn_inreg(i8 %x)
40+
call void @fn_inreg(i8 %x)
41+
42+
; CHECK: Undefined behavior: ABI attribute inreg not present on both function and call-site
43+
; CHECK: call void @fn_nothing_i8(i8 inreg %x)
44+
call void @fn_nothing_i8(i8 inreg %x)
45+
ret void
46+
}
47+
48+
define void @caller_byval(ptr %x) {
49+
; CHECK: Undefined behavior: ABI attribute byval not present on both function and call-site
50+
; CHECK: call void @fn_byval(ptr %x)
51+
call void @fn_byval(ptr %x)
52+
53+
; CHECK: Undefined behavior: ABI attribute byval not present on both function and call-site
54+
; CHECK: call void @fn_nothing_ptr(ptr byval(i8) %x)
55+
call void @fn_nothing_ptr(ptr byval(i8) %x)
56+
57+
; CHECK: Undefined behavior: ABI attribute byval does not have same argument for function and call-site
58+
; CHECK: call void @fn_byval(ptr byval(i16) %x)
59+
call void @fn_byval(ptr byval(i16) %x)
60+
ret void
61+
}
62+
63+
define void @caller_byref(ptr %x) {
64+
; CHECK: Undefined behavior: ABI attribute byref not present on both function and call-site
65+
; CHECK: call void @fn_byref(ptr %x)
66+
call void @fn_byref(ptr %x)
67+
68+
; CHECK: Undefined behavior: ABI attribute byref not present on both function and call-site
69+
; CHECK: call void @fn_nothing_ptr(ptr byref(i8) %x)
70+
call void @fn_nothing_ptr(ptr byref(i8) %x)
71+
72+
; CHECK: Undefined behavior: ABI attribute byref does not have same argument for function and call-site
73+
; CHECK: call void @fn_byref(ptr byref(i16) %x)
74+
call void @fn_byref(ptr byref(i16) %x)
75+
ret void
76+
}
77+
78+
define void @caller_inalloca(ptr %x) {
79+
; CHECK: Undefined behavior: ABI attribute inalloca not present on both function and call-site
80+
; CHECK: call void @fn_inalloca(ptr %x)
81+
call void @fn_inalloca(ptr %x)
82+
83+
; CHECK: Undefined behavior: ABI attribute inalloca not present on both function and call-site
84+
; CHECK: call void @fn_nothing_ptr(ptr inalloca(i8) %x)
85+
call void @fn_nothing_ptr(ptr inalloca(i8) %x)
86+
87+
; CHECK: Undefined behavior: ABI attribute inalloca does not have same argument for function and call-site
88+
; CHECK: call void @fn_inalloca(ptr inalloca(i16) %x)
89+
call void @fn_inalloca(ptr inalloca(i16) %x)
90+
ret void
91+
}
92+
93+
define void @caller_sret(ptr %x) {
94+
; CHECK: Undefined behavior: ABI attribute sret not present on both function and call-site
95+
; CHECK: call void @fn_sret(ptr %x)
96+
call void @fn_sret(ptr %x)
97+
98+
; CHECK: Undefined behavior: ABI attribute sret not present on both function and call-site
99+
; CHECK: call void @fn_nothing_ptr(ptr sret(i8) %x)
100+
call void @fn_nothing_ptr(ptr sret(i8) %x)
101+
102+
; CHECK: Undefined behavior: ABI attribute sret does not have same argument for function and call-site
103+
; CHECK: call void @fn_sret(ptr sret(i16) %x)
104+
call void @fn_sret(ptr sret(i16) %x)
105+
ret void
106+
}

0 commit comments

Comments
 (0)