diff options
-rw-r--r-- | clang/include/clang/AST/Decl.h | 9 | ||||
-rw-r--r-- | clang/include/clang/Driver/Options.td | 2 | ||||
-rw-r--r-- | clang/include/clang/Frontend/CodeGenOptions.def | 2 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGCall.cpp | 19 | ||||
-rw-r--r-- | clang/lib/Driver/ToolChains/Clang.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Frontend/CompilerInvocation.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprObjC.cpp | 5 | ||||
-rw-r--r-- | clang/lib/Sema/SemaPseudoObject.cpp | 1 | ||||
-rw-r--r-- | clang/test/CodeGenObjC/disable-tail-call-escaping-block.m | 54 | ||||
-rw-r--r-- | clang/test/Driver/fno-escaping-block-tail-calls.c | 7 |
11 files changed, 103 insertions, 5 deletions
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 5b5ad34b0d4..57c6f453363 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -3802,6 +3802,10 @@ private: 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 @@ protected: 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 @@ public: 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, diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 6824858b992..d813bab99d2 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1430,6 +1430,8 @@ def fopenmp_cuda_mode : Flag<["-"], "fopenmp-cuda-mode">, Group<f_Group>, Flags< 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">; diff --git a/clang/include/clang/Frontend/CodeGenOptions.def b/clang/include/clang/Frontend/CodeGenOptions.def index 2b3ab5d7454..edf266f743c 100644 --- a/clang/include/clang/Frontend/CodeGenOptions.def +++ b/clang/include/clang/Frontend/CodeGenOptions.def @@ -62,6 +62,8 @@ CODEGENOPT(DebugPassManager, 1, 0) ///< Prints debug information for the new ///< 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 diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index d1b07f86819..08e0ec3eda0 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -1887,10 +1887,21 @@ void CodeGenModule::ConstructAttributeList( } 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); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 60a04b6581f..3c08e88bcdc 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -3454,6 +3454,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, 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); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index a8b7dd96644..23f3c8fbbdc 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -640,6 +640,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, 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) || diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 134415646d3..8c22c0e6435 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -4841,6 +4841,10 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, FunctionDecl *FDecl, (!Param || !Param->hasAttr<CFConsumedAttr>())) CFAudited = true; + if (Proto->getExtParameterInfo(i).isNoEscape()) + if (auto *BE = dyn_cast<BlockExpr>(Arg->IgnoreParenNoopCasts(Context))) + BE->getBlockDecl()->setDoesNotEscape(); + InitializedEntity Entity = Param ? InitializedEntity::InitializeParameter(Context, Param, ProtoArgType) diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 6a725c485d5..8d017af9912 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -1613,6 +1613,11 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, 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) && diff --git a/clang/lib/Sema/SemaPseudoObject.cpp b/clang/lib/Sema/SemaPseudoObject.cpp index f09a6f7158f..5fa4342f18b 100644 --- a/clang/lib/Sema/SemaPseudoObject.cpp +++ b/clang/lib/Sema/SemaPseudoObject.cpp @@ -993,6 +993,7 @@ ObjCSubscriptOpBuilder::buildAssignmentOperation(Scope *Sc, SourceLocation opcLoc, BinaryOperatorKind opcode, Expr *LHS, Expr *RHS) { + assert(false); assert(BinaryOperator::isAssignmentOp(opcode)); // There must be a method to do the Index'ed assignment. if (!findAtIndexSetter()) diff --git a/clang/test/CodeGenObjC/disable-tail-call-escaping-block.m b/clang/test/CodeGenObjC/disable-tail-call-escaping-block.m new file mode 100644 index 00000000000..48b0eda5a56 --- /dev/null +++ b/clang/test/CodeGenObjC/disable-tail-call-escaping-block.m @@ -0,0 +1,54 @@ +// 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: store i8* bitcast (void (i8*)* @[[TEST_BLOCK_INVOKE6:.*]] 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: define internal void @[[TEST_BLOCK_INVOKE6]]({{.*}}) #[[ENABLEATTR]] { + +// CHECK: attributes #[[ENABLEATTR]] = {{{.*}}"disable-tail-calls"="false"{{.*}}} +// CHECK: attributes #[[DISABLEATTR]] = {{{.*}}"disable-tail-calls"="true"{{.*}}} + +typedef void (^BlockTy)(void); +typedef void (*NoEscapeFnTy)(__attribute__((noescape)) BlockTy); + +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 + +NoEscapeFnTy noescapefunc; + +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. + + noescapefunc(^{ (void)a; }); // enable tail-call optimization. +} diff --git a/clang/test/Driver/fno-escaping-block-tail-calls.c b/clang/test/Driver/fno-escaping-block-tail-calls.c new file mode 100644 index 00000000000..2d1b0a373e4 --- /dev/null +++ b/clang/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" |