[llvm] 470bf7b - [Preallocated] Add @llvm.call.preallocated.teardown
Arthur Eubanks via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 8 08:49:12 PDT 2020
Author: Arthur Eubanks
Date: 2020-07-08T08:48:44-07:00
New Revision: 470bf7b5a2976b5792a97b2d053a59d4b1082a5f
URL: https://github.com/llvm/llvm-project/commit/470bf7b5a2976b5792a97b2d053a59d4b1082a5f
DIFF: https://github.com/llvm/llvm-project/commit/470bf7b5a2976b5792a97b2d053a59d4b1082a5f.diff
LOG: [Preallocated] Add @llvm.call.preallocated.teardown
This cleans up the stack allocated by a @llvm.call.preallocated.setup.
Should either call the teardown or the preallocated call to clean up the
stack. Calling both is UB.
Add LangRef.
Add verifier check that the token argument is a @llvm.call.preallocated.setup.
Reviewed By: efriedma
Differential Revision: https://reviews.llvm.org/D83354
Added:
Modified:
llvm/docs/LangRef.rst
llvm/include/llvm/IR/Intrinsics.td
llvm/lib/IR/Verifier.cpp
llvm/test/Verifier/preallocated-invalid.ll
llvm/test/Verifier/preallocated-valid.ll
Removed:
################################################################################
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 9e99f4daa90a..cc2f6d1b3a09 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -12103,6 +12103,65 @@ It is undefined behavior if this is called with a token from an
preallocated call corresponding to the '``llvm.call.preallocated.setup``'
has already been called.
+.. _int_call_preallocated_teardown:
+
+'``llvm.call.preallocated.teardown``' Intrinsic
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Syntax:
+"""""""
+
+::
+
+ declare i8* @llvm.call.preallocated.teardown(token %setup_token)
+
+Overview:
+"""""""""
+
+The '``llvm.call.preallocated.teardown``' intrinsic cleans up the stack
+created by a '``llvm.call.preallocated.setup``'.
+
+Semantics:
+""""""""""
+
+The token argument must be a '``llvm.call.preallocated.setup``'.
+
+The '``llvm.call.preallocated.teardown``' intrinsic cleans up the stack
+allocated by the corresponding '``llvm.call.preallocated.setup``'. Exactly
+one of this or the preallocated call must be called to prevent stack leaks.
+It is undefined behavior to call both a '``llvm.call.preallocated.teardown``'
+and the preallocated call for a given '``llvm.call.preallocated.setup``'.
+
+For example, if the stack is allocated for a preallocated call by a
+'``llvm.call.preallocated.setup``', then an initializer function called on an
+allocated argument throws an exception, there should be a
+'``llvm.call.preallocated.teardown``' in the exception handler to prevent
+stack leaks.
+
+Following the nesting rules in '``llvm.call.preallocated.setup``', nested
+calls to '``llvm.call.preallocated.setup``' and
+'``llvm.call.preallocated.teardown``' are allowed but must be properly
+nested.
+
+Example:
+""""""""
+
+.. code-block:: llvm
+
+ %cs = call token @llvm.call.preallocated.setup(i32 1)
+ %x = call i8* @llvm.call.preallocated.arg(token %cs, i32 0) preallocated(i32)
+ %y = bitcast i8* %x to i32*
+ invoke void @constructor(i32* %y) to label %conta unwind label %contb
+ conta:
+ call void @foo1(i32* preallocated(i32) %y) ["preallocated"(token %cs)]
+ ret void
+ contb:
+ %s = catchswitch within none [label %catch] unwind to caller
+ catch:
+ %p = catchpad within %s []
+ call void @llvm.call.preallocated.teardown(token %cs)
+ ret void
+
Standard C Library Intrinsics
-----------------------------
diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td
index 433e24979ab9..94741229a2a7 100644
--- a/llvm/include/llvm/IR/Intrinsics.td
+++ b/llvm/include/llvm/IR/Intrinsics.td
@@ -534,6 +534,7 @@ def int_instrprof_value_profile : Intrinsic<[],
def int_call_preallocated_setup : Intrinsic<[llvm_token_ty], [llvm_i32_ty]>;
def int_call_preallocated_arg : Intrinsic<[llvm_ptr_ty], [llvm_token_ty, llvm_i32_ty]>;
+def int_call_preallocated_teardown : Intrinsic<[], [llvm_token_ty]>;
//===------------------- Standard C Library Intrinsics --------------------===//
//
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index b5e4ce9f44b3..8fa87b748901 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -4566,6 +4566,9 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
"llvm.call.preallocated.alloc arg index must be between 0 and "
"corresponding "
"llvm.call.preallocated.setup's argument count");
+ } else if (Fn && Fn->getIntrinsicID() ==
+ Intrinsic::call_preallocated_teardown) {
+ // nothing to do
} else {
Assert(!FoundCall, "Can have at most one call corresponding to a "
"llvm.call.preallocated.setup");
@@ -4614,6 +4617,14 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
"call site attribute");
break;
}
+ case Intrinsic::call_preallocated_teardown: {
+ auto *Token = dyn_cast<CallBase>(Call.getArgOperand(0));
+ Assert(Token && Token->getCalledFunction()->getIntrinsicID() ==
+ Intrinsic::call_preallocated_setup,
+ "llvm.call.preallocated.teardown token argument must be a "
+ "llvm.call.preallocated.setup");
+ break;
+ }
case Intrinsic::gcroot:
case Intrinsic::gcwrite:
case Intrinsic::gcread:
diff --git a/llvm/test/Verifier/preallocated-invalid.ll b/llvm/test/Verifier/preallocated-invalid.ll
index 7fdab33167e5..879d4ed8a24f 100644
--- a/llvm/test/Verifier/preallocated-invalid.ll
+++ b/llvm/test/Verifier/preallocated-invalid.ll
@@ -2,6 +2,7 @@
declare token @llvm.call.preallocated.setup(i32)
declare i8* @llvm.call.preallocated.arg(token, i32)
+declare void @llvm.call.preallocated.teardown(token)
; Fake LLVM intrinsic to return a token
declare token @llvm.what()
@@ -136,3 +137,10 @@ define void @musttail_attr_no_match(i32* preallocated(i32) %a) {
musttail call void @musttail_and_bundle(i32* %a)
ret void
}
+
+; CHECK: token argument must be a llvm.call.preallocated.setup
+define void @teardown_token_not_from_setup() {
+ %cs = call token @llvm.what()
+ call void @llvm.call.preallocated.teardown(token %cs)
+ ret void
+}
diff --git a/llvm/test/Verifier/preallocated-valid.ll b/llvm/test/Verifier/preallocated-valid.ll
index 483493c0c747..bbb663b94ebf 100644
--- a/llvm/test/Verifier/preallocated-valid.ll
+++ b/llvm/test/Verifier/preallocated-valid.ll
@@ -2,11 +2,16 @@
declare token @llvm.call.preallocated.setup(i32)
declare i8* @llvm.call.preallocated.arg(token, i32)
+declare void @llvm.call.preallocated.teardown(token)
+
+declare i32 @__CxxFrameHandler3(...)
declare void @foo1(i32* preallocated(i32))
declare i64 @foo1_i64(i32* preallocated(i32))
declare void @foo2(i32* preallocated(i32), i32*, i32* preallocated(i32))
+declare void @constructor(i32*)
+
define void @preallocated() {
%cs = call token @llvm.call.preallocated.setup(i32 1)
%x = call i8* @llvm.call.preallocated.arg(token %cs, i32 0) preallocated(i32)
@@ -40,12 +45,34 @@ define void @preallocated_num_args() {
ret void
}
-define void @preallocate_musttail(i32* preallocated(i32) %a) {
+define void @preallocated_musttail(i32* preallocated(i32) %a) {
musttail call void @foo1(i32* preallocated(i32) %a)
ret void
}
-define i64 @preallocate_musttail_i64(i32* preallocated(i32) %a) {
+define i64 @preallocated_musttail_i64(i32* preallocated(i32) %a) {
%r = musttail call i64 @foo1_i64(i32* preallocated(i32) %a)
ret i64 %r
}
+
+define void @preallocated_teardown() {
+ %cs = call token @llvm.call.preallocated.setup(i32 1)
+ call void @llvm.call.preallocated.teardown(token %cs)
+ ret void
+}
+
+define void @preallocated_teardown_invoke() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
+ %cs = call token @llvm.call.preallocated.setup(i32 1)
+ %x = call i8* @llvm.call.preallocated.arg(token %cs, i32 0) preallocated(i32)
+ %y = bitcast i8* %x to i32*
+ invoke void @constructor(i32* %y) to label %conta unwind label %contb
+conta:
+ call void @foo1(i32* preallocated(i32) %y) ["preallocated"(token %cs)]
+ ret void
+contb:
+ %s = catchswitch within none [label %catch] unwind to caller
+catch:
+ %p = catchpad within %s []
+ call void @llvm.call.preallocated.teardown(token %cs)
+ ret void
+}
More information about the llvm-commits
mailing list