ahatanak updated this revision to Diff 136580.
ahatanak marked 3 inline comments as done.
ahatanak added a comment.
Address review comments.
https://reviews.llvm.org/D43841
Files:
include/clang/AST/Decl.h
include/clang/Driver/Options.td
include/clang/Frontend/CodeGenOptions.def
lib/CodeGen/CGCall.cpp
lib/Driver/ToolChains/Clang.cpp
lib/Frontend/CompilerInvocation.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprObjC.cpp
test/CodeGenObjC/disable-tail-call-escaping-block.m
test/Driver/fno-escaping-block-tail-calls.c
Index: test/Driver/fno-escaping-block-tail-calls.c
===================================================================
--- /dev/null
+++ test/Driver/fno-escaping-block-tail-calls.c
@@ -0,0 +1,7 @@
+// RUN: %clang -### %s -fescaping-block-tail-calls -fno-escaping-block-tail-calls 2> %t
+// RUN: FileCheck --check-prefix=CHECK-DISABLE < %t %s
+// CHECK-DISABLE: "-fno-escaping-block-tail-calls"
+
+// RUN: %clang -### %s -fno-escaping-block-tail-calls -fescaping-block-tail-calls 2> %t
+// RUN: FileCheck --check-prefix=CHECK-NO-DISABLE < %t %s
+// CHECK-NO-DISABLE-NOT: "-fno-escaping-block-tail-calls"
Index: test/CodeGenObjC/disable-tail-call-escaping-block.m
===================================================================
--- /dev/null
+++ test/CodeGenObjC/disable-tail-call-escaping-block.m
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fblocks -fno-escaping-block-tail-calls -emit-llvm -o - %s | FileCheck %s
+
+// CHECK-LABEL: define void @test(
+// CHECK: store i8* bitcast (void (i8*)* @[[TEST_BLOCK_INVOKE0:.*]] to i8*)
+// CHECK: store i8* bitcast (void (i8*)* @[[TEST_BLOCK_INVOKE1:.*]] to i8*)
+// CHECK: store i8* bitcast (void (i8*)* @[[TEST_BLOCK_INVOKE2:.*]] to i8*)
+// CHECK: store i8* bitcast (void (i8*)* @[[TEST_BLOCK_INVOKE3:.*]] to i8*)
+// CHECK: store i8* bitcast (void (i8*)* @[[TEST_BLOCK_INVOKE4:.*]] to i8*)
+// CHECK: store i8* bitcast (void (i8*)* @[[TEST_BLOCK_INVOKE5:.*]] to i8*)
+
+// CHECK: define internal void @[[TEST_BLOCK_INVOKE0]]({{.*}}) #[[DISABLEATTR:.*]] {
+// CHECK: define internal void @[[TEST_BLOCK_INVOKE1]]({{.*}}) #[[ENABLEATTR:.*]] {
+// CHECK: define internal void @[[TEST_BLOCK_INVOKE2]]({{.*}}) #[[DISABLEATTR]] {
+// CHECK: define internal void @[[TEST_BLOCK_INVOKE3]]({{.*}}) #[[DISABLEATTR]] {
+// CHECK: define internal void @[[TEST_BLOCK_INVOKE4]]({{.*}}) #[[ENABLEATTR]] {
+// CHECK: define internal void @[[TEST_BLOCK_INVOKE5]]({{.*}}) #[[DISABLEATTR]] {
+
+// CHECK: attributes #[[ENABLEATTR]] = {{{.*}}"disable-tail-calls"="false"{{.*}}}
+// CHECK: attributes #[[DISABLEATTR]] = {{{.*}}"disable-tail-calls"="true"{{.*}}}
+
+typedef void (^BlockTy)(void);
+
+void callee0(__attribute__((noescape)) BlockTy);
+void callee1(BlockTy);
+
+__attribute__((objc_root_class))
+@interface C0
+-(void)m0:(__attribute__((noescape)) BlockTy)p;
+-(void)m1:(BlockTy)p;
+@end
+
+@implementation C0
+-(void)m0:(__attribute__((noescape)) BlockTy)p {}
+-(void)m1:(BlockTy)p {}
+@end
+
+void test(id a, C0 *c0) {
+ BlockTy b0 = ^{ (void)a; }; // disable tail-call optimization.
+ callee0(b0);
+ callee0(^{ (void)a; }); // enable tail-call optimization.
+ callee1(^{ (void)a; }); // disable tail-call optimization.
+
+ BlockTy b1 = ^{ (void)a; }; // disable tail-call optimization.
+ [c0 m0:b1];
+ [c0 m0:^{ (void)a; }]; // enable tail-call optimization.
+ [c0 m1:^{ (void)a; }]; // disable tail-call optimization.
+}
Index: lib/Sema/SemaExprObjC.cpp
===================================================================
--- lib/Sema/SemaExprObjC.cpp
+++ lib/Sema/SemaExprObjC.cpp
@@ -1613,6 +1613,11 @@
ParmVarDecl *param = Method->parameters()[i];
assert(argExpr && "CheckMessageArgumentTypes(): missing expression");
+ if (param->hasAttr<NoEscapeAttr>())
+ if (auto *BE = dyn_cast<BlockExpr>(
+ argExpr->IgnoreParenNoopCasts(Context)))
+ BE->getBlockDecl()->setDoesNotEscape();
+
// Strip the unbridged-cast placeholder expression off unless it's
// a consumed argument.
if (argExpr->hasPlaceholderType(BuiltinType::ARCUnbridgedCast) &&
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -4841,6 +4841,10 @@
(!Param || !Param->hasAttr<CFConsumedAttr>()))
CFAudited = true;
+ if (Param && Param->hasAttr<NoEscapeAttr>())
+ if (auto *BE = dyn_cast<BlockExpr>(Arg->IgnoreParenNoopCasts(Context)))
+ BE->getBlockDecl()->setDoesNotEscape();
+
InitializedEntity Entity =
Param ? InitializedEntity::InitializeParameter(Context, Param,
ProtoArgType)
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -640,6 +640,8 @@
Opts.DisableFree = Args.hasArg(OPT_disable_free);
Opts.DiscardValueNames = Args.hasArg(OPT_discard_value_names);
Opts.DisableTailCalls = Args.hasArg(OPT_mdisable_tail_calls);
+ Opts.NoEscapingBlockTailCalls =
+ Args.hasArg(OPT_fno_escaping_block_tail_calls);
Opts.FloatABI = Args.getLastArgValue(OPT_mfloat_abi);
Opts.LessPreciseFPMAD = Args.hasArg(OPT_cl_mad_enable) ||
Args.hasArg(OPT_cl_unsafe_math_optimizations) ||
Index: lib/Driver/ToolChains/Clang.cpp
===================================================================
--- lib/Driver/ToolChains/Clang.cpp
+++ lib/Driver/ToolChains/Clang.cpp
@@ -3454,6 +3454,9 @@
if (!Args.hasFlag(options::OPT_foptimize_sibling_calls,
options::OPT_fno_optimize_sibling_calls))
CmdArgs.push_back("-mdisable-tail-calls");
+ if (Args.hasFlag(options::OPT_fno_escaping_block_tail_calls,
+ options::OPT_fescaping_block_tail_calls))
+ CmdArgs.push_back("-fno-escaping-block-tail-calls");
Args.AddLastArg(CmdArgs, options::OPT_ffine_grained_bitfield_accesses,
options::OPT_fno_fine_grained_bitfield_accesses);
Index: lib/CodeGen/CGCall.cpp
===================================================================
--- lib/CodeGen/CGCall.cpp
+++ lib/CodeGen/CGCall.cpp
@@ -1887,10 +1887,21 @@
}
if (!AttrOnCallSite) {
- bool DisableTailCalls =
- CodeGenOpts.DisableTailCalls ||
- (TargetDecl && (TargetDecl->hasAttr<DisableTailCallsAttr>() ||
- TargetDecl->hasAttr<AnyX86InterruptAttr>()));
+ bool DisableTailCalls = false;
+
+ if (CodeGenOpts.DisableTailCalls)
+ DisableTailCalls = true;
+ else if (TargetDecl) {
+ if (TargetDecl->hasAttr<DisableTailCallsAttr>() ||
+ TargetDecl->hasAttr<AnyX86InterruptAttr>())
+ DisableTailCalls = true;
+ else if (CodeGenOpts.NoEscapingBlockTailCalls) {
+ if (const auto *BD = dyn_cast<BlockDecl>(TargetDecl))
+ if (!BD->doesNotEscape())
+ DisableTailCalls = true;
+ }
+ }
+
FuncAttrs.addAttribute("disable-tail-calls",
llvm::toStringRef(DisableTailCalls));
GetCPUAndFeaturesAttributes(TargetDecl, FuncAttrs);
Index: include/clang/Frontend/CodeGenOptions.def
===================================================================
--- include/clang/Frontend/CodeGenOptions.def
+++ include/clang/Frontend/CodeGenOptions.def
@@ -62,6 +62,8 @@
///< pass manager.
CODEGENOPT(DisableRedZone , 1, 0) ///< Set when -mno-red-zone is enabled.
CODEGENOPT(DisableTailCalls , 1, 0) ///< Do not emit tail calls.
+CODEGENOPT(NoEscapingBlockTailCalls, 1, 0) ///< Do not emit tail calls from
+ ///< escaping blocks.
CODEGENOPT(EmitDeclMetadata , 1, 0) ///< Emit special metadata indicating what
///< Decl* various IR entities came from.
///< Only useful when running CodeGen as a
Index: include/clang/Driver/Options.td
===================================================================
--- include/clang/Driver/Options.td
+++ include/clang/Driver/Options.td
@@ -1428,6 +1428,8 @@
def fno_openmp_cuda_mode : Flag<["-"], "fno-openmp-cuda-mode">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>;
def fno_optimize_sibling_calls : Flag<["-"], "fno-optimize-sibling-calls">, Group<f_Group>;
def foptimize_sibling_calls : Flag<["-"], "foptimize-sibling-calls">, Group<f_Group>;
+def fno_escaping_block_tail_calls : Flag<["-"], "fno-escaping-block-tail-calls">, Group<f_Group>, Flags<[CC1Option]>;
+def fescaping_block_tail_calls : Flag<["-"], "fescaping-block-tail-calls">, Group<f_Group>;
def force__cpusubtype__ALL : Flag<["-"], "force_cpusubtype_ALL">;
def force__flat__namespace : Flag<["-"], "force_flat_namespace">;
def force__load : Separate<["-"], "force_load">;
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h
+++ include/clang/AST/Decl.h
@@ -3802,6 +3802,10 @@
bool BlockMissingReturnType : 1;
bool IsConversionFromLambda : 1;
+ /// A bit that indicates this block is passed directly to a function as a
+ /// non-escaping parameter.
+ bool DoesNotEscape : 1;
+
/// A new[]'d array of pointers to ParmVarDecls for the formal
/// parameters of this function. This is null if a prototype or if there are
/// no formals.
@@ -3821,7 +3825,7 @@
BlockDecl(DeclContext *DC, SourceLocation CaretLoc)
: Decl(Block, DC, CaretLoc), DeclContext(Block), IsVariadic(false),
CapturesCXXThis(false), BlockMissingReturnType(true),
- IsConversionFromLambda(false) {}
+ IsConversionFromLambda(false), DoesNotEscape(false) {}
public:
static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L);
@@ -3893,6 +3897,9 @@
bool isConversionFromLambda() const { return IsConversionFromLambda; }
void setIsConversionFromLambda(bool val) { IsConversionFromLambda = val; }
+ bool doesNotEscape() const { return DoesNotEscape; }
+ void setDoesNotEscape() { DoesNotEscape = true; }
+
bool capturesVariable(const VarDecl *var) const;
void setCaptures(ASTContext &Context, ArrayRef<Capture> Captures,
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits