summaryrefslogtreecommitdiffstats
path: root/llvm
diff options
context:
space:
mode:
Diffstat (limited to 'llvm')
-rw-r--r--llvm/lib/Analysis/Lint.cpp25
-rw-r--r--llvm/test/Analysis/Lint/tail-call-byval.ll33
2 files changed, 50 insertions, 8 deletions
diff --git a/llvm/lib/Analysis/Lint.cpp b/llvm/lib/Analysis/Lint.cpp
index ae92f502f5c..7b792ed0a2e 100644
--- a/llvm/lib/Analysis/Lint.cpp
+++ b/llvm/lib/Analysis/Lint.cpp
@@ -285,15 +285,24 @@ void Lint::visitCallSite(CallSite CS) {
}
}
- if (CS.isCall() && cast<CallInst>(CS.getInstruction())->isTailCall())
- for (CallSite::arg_iterator AI = CS.arg_begin(), AE = CS.arg_end();
- AI != AE; ++AI) {
- Value *Obj = findValue(*AI, /*OffsetOk=*/true);
- Assert(!isa<AllocaInst>(Obj),
- "Undefined behavior: Call with \"tail\" keyword references "
- "alloca",
- &I);
+ if (CS.isCall()) {
+ const CallInst *CI = cast<CallInst>(CS.getInstruction());
+ if (CI->isTailCall()) {
+ const AttributeList &PAL = CI->getAttributes();
+ unsigned ArgNo = 0;
+ for (Value *Arg : CS.args()) {
+ // Skip ByVal arguments since they will be memcpy'd to the callee's
+ // stack anyway.
+ if (PAL.hasParamAttribute(ArgNo++, Attribute::ByVal))
+ continue;
+ Value *Obj = findValue(Arg, /*OffsetOk=*/true);
+ Assert(!isa<AllocaInst>(Obj),
+ "Undefined behavior: Call with \"tail\" keyword references "
+ "alloca",
+ &I);
+ }
}
+ }
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I))
diff --git a/llvm/test/Analysis/Lint/tail-call-byval.ll b/llvm/test/Analysis/Lint/tail-call-byval.ll
new file mode 100644
index 00000000000..9f274981898
--- /dev/null
+++ b/llvm/test/Analysis/Lint/tail-call-byval.ll
@@ -0,0 +1,33 @@
+; RUN: opt < %s -lint -disable-output 2>&1 | FileCheck %s
+
+%s = type { i8 }
+
+declare void @f1(%s*)
+
+define void @f2() {
+entry:
+ %c = alloca %s
+ tail call void @f1(%s* %c)
+ ret void
+}
+
+; Lint should complain about the tail call passing the alloca'd value %c to f1.
+; CHECK: Undefined behavior: Call with "tail" keyword references alloca
+; CHECK-NEXT: tail call void @f1(%s* %c)
+
+declare void @f3(%s* byval)
+
+define void @f4() {
+entry:
+ %c = alloca %s
+ tail call void @f3(%s* byval %c)
+ ret void
+}
+
+; Lint should not complain about passing the alloca'd %c since it's passed
+; byval, effectively copying the data to the stack instead of leaking the
+; pointer itself.
+; CHECK-NOT: Undefined behavior: Call with "tail" keyword references alloca
+; CHECK-NOT: tail call void @f3(%s* byval %c)
+
+
OpenPOWER on IntegriCloud