Skip to content

Commit 91bab1f

Browse files
MrSmith33deadalnix
authored andcommitted
Add pragma(musttail)
1 parent 4406376 commit 91bab1f

12 files changed

Lines changed: 96 additions & 5 deletions

File tree

dmd/expression.d

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3022,6 +3022,10 @@ extern (C++) final class CallExp : UnaExp
30223022
bool inDebugStatement; /// true if this was in a debug statement
30233023
bool ignoreAttributes; /// don't enforce attributes (e.g. call @gc function in @nogc code)
30243024
bool isUfcsRewrite; /// the first argument was pushed in here by a UFCS rewrite
3025+
version (IN_LLVM) {
3026+
bool isMustTail; // If marked with pragma(musttail)
3027+
}
3028+
30253029
VarDeclaration vthis2; // container for multi-context
30263030
Expression loweredFrom; // set if this is the result of a lowering
30273031

dmd/expression.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -845,6 +845,10 @@ class CallExp final : public UnaExp
845845
d_bool inDebugStatement; // true if this was in a debug statement
846846
d_bool ignoreAttributes; // don't enforce attributes (e.g. call @gc function in @nogc code)
847847
d_bool isUfcsRewrite; // the first argument was pushed in here by a UFCS rewrite
848+
#if IN_LLVM
849+
d_bool isMustTail; // If marked with pragma(musttail)
850+
#endif
851+
848852
VarDeclaration *vthis2; // container for multi-context
849853
Expression* loweredFrom; // set if this is the result of a lowering
850854

dmd/id.d

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,7 @@ immutable Msgtable[] msgtable =
564564
{ "LDC_global_crt_dtor" },
565565
{ "LDC_extern_weak" },
566566
{ "LDC_profile_instr" },
567+
{ "musttail" },
567568

568569
// IN_LLVM: LDC-specific traits
569570
{ "targetCPU" },

dmd/id.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ struct Id
7676
static Identifier *LDC_inline_ir;
7777
static Identifier *LDC_extern_weak;
7878
static Identifier *LDC_profile_instr;
79+
static Identifier *musttail;
7980
static Identifier *dcReflect;
8081
static Identifier *opencl;
8182
static Identifier *criticalenter;

dmd/pragmasem.d

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,14 @@ bool pragmaStmtSemantic(PragmaStatement ps, Scope* sc)
398398
if (!pragmaMangleSemantic(ps.loc, sc, ps.args, decls.length ? &decls : null))
399399
return false;
400400
}
401+
else if (ps.ident == Id.musttail)
402+
{
403+
version (IN_LLVM)
404+
{
405+
if (!pragmaMustTailSemantic(ps))
406+
return false;
407+
}
408+
}
401409
else if (!global.params.ignoreUnsupportedPragmas)
402410
{
403411
error(ps.loc, "unrecognized `pragma(%s)`", ps.ident.toChars());
@@ -777,3 +785,36 @@ private bool pragmaMangleSemantic(Loc loc, Scope* sc, Expressions* args, Dsymbol
777785
}
778786
return true;
779787
}
788+
789+
version (IN_LLVM)
790+
private bool pragmaMustTailSemantic(PragmaStatement ps)
791+
{
792+
if (!ps._body)
793+
{
794+
error(ps.loc, "`pragma(musttail)` must be attached to a return statement");
795+
return false;
796+
}
797+
798+
auto rs = ps._body.isReturnStatement();
799+
if (!rs)
800+
{
801+
error(ps.loc, "`pragma(musttail)` must be attached to a return statement");
802+
return false;
803+
}
804+
805+
if (!rs.exp)
806+
{
807+
error(ps.loc, "`pragma(musttail)` must be attached to a return statement returning result of a function call");
808+
return false;
809+
}
810+
811+
auto ce = rs.exp.isCallExp();
812+
if (!ce)
813+
{
814+
error(ps.loc, "`pragma(musttail)` must be attached to a return statement returning result of a function call");
815+
return false;
816+
}
817+
818+
ce.isMustTail = true;
819+
return true;
820+
}

gen/dpragma.d

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ extern (C++) enum LDCPragma : int {
4444
LLVMbitop_bts,
4545
LLVMbitop_vld,
4646
LLVMbitop_vst,
47-
LLVMextern_weak
47+
LLVMextern_weak,
48+
LLVMmusttail,
4849
};
4950

5051
extern (C++) LDCPragma DtoGetPragma(Scope* sc, PragmaDeclaration decl, ref const(char)* arg1str);

gen/llvmhelpers.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,8 @@ bool DtoLowerMagicIntrinsic(IRState *p, FuncDeclaration *fndecl, CallExp *e,
205205

206206
///
207207
DValue *DtoCallFunction(Loc loc, Type *resulttype, DValue *fnval,
208-
Expressions *arguments, LLValue *sretPointer = nullptr, bool directcall = false);
208+
Expressions *arguments, LLValue *sretPointer = nullptr,
209+
bool directcall = false, bool isMustTail = false);
209210

210211
Type *stripModifiers(Type *type, bool transitive = false);
211212

gen/pragma.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,15 @@ LDCPragma DtoGetPragma(Scope *sc, PragmaDeclaration *decl,
337337
return LLVMprofile_instr;
338338
}
339339

340+
// pragma(musttail)
341+
if (ident == Id::musttail) {
342+
if (args && args->length > 0) {
343+
pragmaError("takes no parameters");
344+
fatal();
345+
}
346+
return LLVMmusttail;
347+
}
348+
340349
return LLVMnone;
341350
}
342351

gen/pragma.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ enum LDCPragma {
4848
LLVMbitop_vld,
4949
LLVMbitop_vst,
5050
LLVMextern_weak,
51-
LLVMprofile_instr
51+
LLVMprofile_instr,
52+
LLVMmusttail,
5253
};
5354

5455
LDCPragma DtoGetPragma(Scope *sc, PragmaDeclaration *decl, const char *&arg1str);

gen/tocall.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -839,7 +839,8 @@ static LLValue *DtoCallableValue(DValue *fn) {
839839

840840
// FIXME: this function is a mess !
841841
DValue *DtoCallFunction(Loc loc, Type *resulttype, DValue *fnval,
842-
Expressions *arguments, LLValue *sretPointer, bool directcall) {
842+
Expressions *arguments, LLValue *sretPointer,
843+
bool directcall, bool isMustTail) {
843844
IF_LOG Logger::println("DtoCallFunction()");
844845
LOG_SCOPE
845846

@@ -1060,6 +1061,18 @@ DValue *DtoCallFunction(Loc loc, Type *resulttype, DValue *fnval,
10601061
attrlist = attrlist.addFnAttributes(
10611062
gIR->context(), llvm::AttrBuilder(gIR->context(), attrbuildattribs));
10621063
call->setAttributes(attrlist);
1064+
if (isMustTail) {
1065+
if (auto ci = llvm::dyn_cast<llvm::CallInst>(call)) {
1066+
ci->setTailCallKind(llvm::CallInst::TCK_MustTail);
1067+
} else {
1068+
if (!tf->isNothrow()) {
1069+
error(loc, "cannot perform tail-call - callee must be nothrow");
1070+
} else {
1071+
error(loc, "cannot perform tail-call - no code like destructors or scope(exit) should run after the call");
1072+
}
1073+
fatal();
1074+
}
1075+
}
10631076

10641077
// Special case for struct constructor calls: For temporaries, using the
10651078
// this pointer value returned from the constructor instead of the alloca

0 commit comments

Comments
 (0)