ldc/ddmd/statement.h
Johan Engelen e0d9c58443 [PGO] Add PGO to LDC. Supported for LLVM >= 3.7
Add the commandline options -fprofile-instr-generate[=filename] and -profile-instr-use=filename
-fprofile-instr-generate
-- Add instrumentation on branches, switches, and function entry; uses LLVM's InstrProf pass.
-- Link to profile runtime that writes instrumentation counters to a file.
-fprofile-instr-use
-- Read profile data from a file and apply branch weights to branches and switches, and annotate functions with entrycount in LLVM IR.
-- Functions with low or high entrycount are marked with 'cold' or 'inlinehint'.

The only statement type without PGO yet is "try-finally".

A new pragma, `pragma(LDC_profile_instr, [ true | false ])`, is added to selectively disable/enable instrumentation of functions (granularity = whole functions).

The runtime library ldc-profile-rt is a copy of LLVM compiler-rt lib/profile. It has to be exactly in-sync with the LLVM version, and thus we need a copy for each PGO-supported LLVM (>=3.7).
import ldc.profile for a D interface to ldc-profile-rt (for example to reset execution counts after a program startup phase).

The instrumentation data is mainly passed on to LLVM: function-entry counts and branch counts/probabilities. LDC marks functions as hot when "execution count is 30% of the maximum function execution count", and marks functions as cold if their count is 1% of maximum function execution count.

The source of LLVM's llvm-profdata tool is hereby included in LDCs repository (different source for each LLVM version), and the binary is included in the install bin folder.
The executable is named "ldc-profdata" to avoid clashing with llvm-profdata on the same machine. This is needed because profdata executable has to be in-sync with the LLVM version used to build LDC.

Maintenance burden: for trunk LLVM, we have to keep ldc-profile-rt and llvm-profdata in sync. There is no diff with upstream; but because of active development there are the occasional API changes.
2016-06-20 17:28:22 +02:00

827 lines
21 KiB
C++

/* Compiler implementation of the D programming language
* Copyright (c) 1999-2014 by Digital Mars
* All Rights Reserved
* written by Walter Bright
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* http://www.boost.org/LICENSE_1_0.txt
* https://github.com/D-Programming-Language/dmd/blob/master/src/statement.h
*/
#ifndef DMD_STATEMENT_H
#define DMD_STATEMENT_H
#ifdef __DMC__
#pragma once
#endif /* __DMC__ */
#include "root.h"
#include "arraytypes.h"
#include "dsymbol.h"
#include "visitor.h"
#include "tokens.h"
struct OutBuffer;
struct Scope;
class Expression;
class LabelDsymbol;
class Identifier;
class IfStatement;
class ExpStatement;
class DefaultStatement;
class VarDeclaration;
class Condition;
class Module;
struct Token;
class ErrorStatement;
class ReturnStatement;
class CompoundStatement;
class Parameter;
class StaticAssert;
class AsmStatement;
class GotoStatement;
class ScopeStatement;
class TryCatchStatement;
class TryFinallyStatement;
class CaseStatement;
class DefaultStatement;
class LabelStatement;
#if IN_LLVM
namespace llvm
{
class Value;
class BasicBlock;
class ConstantInt;
}
class DValue;
typedef DValue elem;
struct AsmCode;
typedef AsmCode code;
#else
// Back end
struct code;
#endif
bool inferAggregate(ForeachStatement *fes, Scope *sc, Dsymbol *&sapply);
bool inferApplyArgTypes(ForeachStatement *fes, Scope *sc, Dsymbol *&sapply);
/* How a statement exits; this is returned by blockExit()
*/
enum BE
{
BEnone = 0,
BEfallthru = 1,
BEthrow = 2,
BEreturn = 4,
BEgoto = 8,
BEhalt = 0x10,
BEbreak = 0x20,
BEcontinue = 0x40,
BEerrthrow = 0x80,
BEany = (BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt),
};
class Statement : public RootObject
{
public:
Loc loc;
Statement(Loc loc);
virtual Statement *syntaxCopy();
void print();
char *toChars();
void error(const char *format, ...);
void warning(const char *format, ...);
void deprecation(const char *format, ...);
virtual Statement *semantic(Scope *sc);
Statement *semanticScope(Scope *sc, Statement *sbreak, Statement *scontinue);
Statement *semanticNoScope(Scope *sc);
virtual Statement *getRelatedLabeled() { return this; }
virtual bool hasBreak();
virtual bool hasContinue();
bool usesEH();
int blockExit(FuncDeclaration *func, bool mustNotThrow);
bool comeFrom();
bool hasCode();
virtual Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally);
virtual Statements *flatten(Scope *sc);
virtual Statement *last();
// Avoid dynamic_cast
virtual ErrorStatement *isErrorStatement() { return NULL; }
virtual ScopeStatement *isScopeStatement() { return NULL; }
virtual ExpStatement *isExpStatement() { return NULL; }
virtual CompoundStatement *isCompoundStatement() { return NULL; }
virtual ReturnStatement *isReturnStatement() { return NULL; }
virtual IfStatement *isIfStatement() { return NULL; }
virtual CaseStatement *isCaseStatement() { return NULL; }
virtual DefaultStatement *isDefaultStatement() { return NULL; }
virtual LabelStatement *isLabelStatement() { return NULL; }
virtual DtorExpStatement *isDtorExpStatement() { return NULL; }
virtual void accept(Visitor *v) { v->visit(this); }
#if IN_LLVM
virtual CompoundAsmStatement *isCompoundAsmBlockStatement() { return NULL; }
virtual CompoundAsmStatement *endsWithAsm();
#endif
};
/** Any Statement that fails semantic() or has a component that is an ErrorExp or
* a TypeError should return an ErrorStatement from semantic().
*/
class ErrorStatement : public Statement
{
public:
ErrorStatement();
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
ErrorStatement *isErrorStatement() { return this; }
void accept(Visitor *v) { v->visit(this); }
};
class PeelStatement : public Statement
{
public:
Statement *s;
PeelStatement(Statement *s);
Statement *semantic(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
class ExpStatement : public Statement
{
public:
Expression *exp;
ExpStatement(Loc loc, Expression *exp);
ExpStatement(Loc loc, Dsymbol *s);
static ExpStatement *create(Loc loc, Expression *exp);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally);
Statements *flatten(Scope *sc);
ExpStatement *isExpStatement() { return this; }
void accept(Visitor *v) { v->visit(this); }
};
class DtorExpStatement : public ExpStatement
{
public:
/* Wraps an expression that is the destruction of 'var'
*/
VarDeclaration *var;
DtorExpStatement(Loc loc, Expression *exp, VarDeclaration *v);
Statement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
DtorExpStatement *isDtorExpStatement() { return this; }
};
class CompileStatement : public Statement
{
public:
Expression *exp;
CompileStatement(Loc loc, Expression *exp);
Statement *syntaxCopy();
Statements *flatten(Scope *sc);
Statement *semantic(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
class CompoundStatement : public Statement
{
public:
Statements *statements;
CompoundStatement(Loc loc, Statements *s);
CompoundStatement(Loc loc, Statement *s1);
CompoundStatement(Loc loc, Statement *s1, Statement *s2);
static CompoundStatement *create(Loc loc, Statement *s1, Statement *s2);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
Statements *flatten(Scope *sc);
ReturnStatement *isReturnStatement();
Statement *last();
CompoundStatement *isCompoundStatement() { return this; }
void accept(Visitor *v) { v->visit(this); }
#if IN_LLVM
virtual CompoundAsmStatement *endsWithAsm();
#endif
};
class CompoundDeclarationStatement : public CompoundStatement
{
public:
CompoundDeclarationStatement(Loc loc, Statements *s);
Statement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
/* The purpose of this is so that continue will go to the next
* of the statements, and break will go to the end of the statements.
*/
class UnrolledLoopStatement : public Statement
{
public:
Statements *statements;
UnrolledLoopStatement(Loc loc, Statements *statements);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
bool hasBreak();
bool hasContinue();
void accept(Visitor *v) { v->visit(this); }
};
class ScopeStatement : public Statement
{
public:
Statement *statement;
ScopeStatement(Loc loc, Statement *s);
Statement *syntaxCopy();
ScopeStatement *isScopeStatement() { return this; }
ReturnStatement *isReturnStatement();
Statement *semantic(Scope *sc);
bool hasBreak();
bool hasContinue();
void accept(Visitor *v) { v->visit(this); }
};
class WhileStatement : public Statement
{
public:
Expression *condition;
Statement *_body;
Loc endloc; // location of closing curly bracket
WhileStatement(Loc loc, Expression *c, Statement *b, Loc endloc);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
bool hasBreak();
bool hasContinue();
void accept(Visitor *v) { v->visit(this); }
};
class DoStatement : public Statement
{
public:
Statement *_body;
Expression *condition;
DoStatement(Loc loc, Statement *b, Expression *c);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
bool hasBreak();
bool hasContinue();
void accept(Visitor *v) { v->visit(this); }
};
class ForStatement : public Statement
{
public:
Statement *_init;
Expression *condition;
Expression *increment;
Statement *_body;
Loc endloc; // location of closing curly bracket
// When wrapped in try/finally clauses, this points to the outermost one,
// which may have an associated label. Internal break/continue statements
// treat that label as referring to this loop.
Statement *relatedLabeled;
ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body, Loc endloc);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally);
Statement *getRelatedLabeled() { return relatedLabeled ? relatedLabeled : this; }
bool hasBreak();
bool hasContinue();
void accept(Visitor *v) { v->visit(this); }
};
class ForeachStatement : public Statement
{
public:
TOK op; // TOKforeach or TOKforeach_reverse
Parameters *parameters; // array of Parameter*'s
Expression *aggr;
Statement *_body;
Loc endloc; // location of closing curly bracket
VarDeclaration *key;
VarDeclaration *value;
FuncDeclaration *func; // function we're lexically in
Statements *cases; // put breaks, continues, gotos and returns here
ScopeStatements *gotos; // forward referenced goto's go here
ForeachStatement(Loc loc, TOK op, Parameters *parameters, Expression *aggr, Statement *body, Loc endloc);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
bool checkForArgTypes();
bool hasBreak();
bool hasContinue();
void accept(Visitor *v) { v->visit(this); }
};
class ForeachRangeStatement : public Statement
{
public:
TOK op; // TOKforeach or TOKforeach_reverse
Parameter *prm; // loop index variable
Expression *lwr;
Expression *upr;
Statement *_body;
Loc endloc; // location of closing curly bracket
VarDeclaration *key;
ForeachRangeStatement(Loc loc, TOK op, Parameter *prm,
Expression *lwr, Expression *upr, Statement *body, Loc endloc);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
bool hasBreak();
bool hasContinue();
void accept(Visitor *v) { v->visit(this); }
};
class IfStatement : public Statement
{
public:
Parameter *prm;
Expression *condition;
Statement *ifbody;
Statement *elsebody;
VarDeclaration *match; // for MatchExpression results
IfStatement(Loc loc, Parameter *prm, Expression *condition, Statement *ifbody, Statement *elsebody);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
IfStatement *isIfStatement() { return this; }
void accept(Visitor *v) { v->visit(this); }
};
class ConditionalStatement : public Statement
{
public:
Condition *condition;
Statement *ifbody;
Statement *elsebody;
ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
Statements *flatten(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
class PragmaStatement : public Statement
{
public:
Identifier *ident;
Expressions *args; // array of Expression's
Statement *_body;
PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
class StaticAssertStatement : public Statement
{
public:
StaticAssert *sa;
StaticAssertStatement(StaticAssert *sa);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
class SwitchStatement : public Statement
{
public:
Expression *condition;
Statement *_body;
bool isFinal;
DefaultStatement *sdefault;
TryFinallyStatement *tf;
GotoCaseStatements gotoCases; // array of unresolved GotoCaseStatement's
CaseStatements *cases; // array of CaseStatement's
int hasNoDefault; // !=0 if no default statement
int hasVars; // !=0 if has variable case values
#if IN_LLVM
bool hasGotoDefault; // true iff there is a `goto default` statement for this switch
#endif
SwitchStatement(Loc loc, Expression *c, Statement *b, bool isFinal);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
bool hasBreak();
void accept(Visitor *v) { v->visit(this); }
};
class CaseStatement : public Statement
{
public:
Expression *exp;
Statement *statement;
int index; // which case it is (since we sort this)
#if IN_LLVM
bool gototarget; // true iff this is the target of a 'goto case'
llvm::BasicBlock* bodyBB;
llvm::Value* llvmIdx;
#endif
CaseStatement(Loc loc, Expression *exp, Statement *s);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
int compare(RootObject *obj);
CaseStatement *isCaseStatement() { return this; }
void accept(Visitor *v) { v->visit(this); }
};
class CaseRangeStatement : public Statement
{
public:
Expression *first;
Expression *last;
Statement *statement;
CaseRangeStatement(Loc loc, Expression *first, Expression *last, Statement *s);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
class DefaultStatement : public Statement
{
public:
Statement *statement;
#if IN_LLVM
bool gototarget; // true iff this is the target of a 'goto default'
llvm::BasicBlock* bodyBB;
#endif
DefaultStatement(Loc loc, Statement *s);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
DefaultStatement *isDefaultStatement() { return this; }
void accept(Visitor *v) { v->visit(this); }
};
class GotoDefaultStatement : public Statement
{
public:
SwitchStatement *sw;
GotoDefaultStatement(Loc loc);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
class GotoCaseStatement : public Statement
{
public:
Expression *exp; // NULL, or which case to goto
CaseStatement *cs; // case statement it resolves to
#if IN_LLVM
SwitchStatement *sw;
#endif
GotoCaseStatement(Loc loc, Expression *exp);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
class SwitchErrorStatement : public Statement
{
public:
SwitchErrorStatement(Loc loc);
void accept(Visitor *v) { v->visit(this); }
};
class ReturnStatement : public Statement
{
public:
Expression *exp;
size_t caseDim;
ReturnStatement(Loc loc, Expression *exp);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
ReturnStatement *isReturnStatement() { return this; }
void accept(Visitor *v) { v->visit(this); }
};
class BreakStatement : public Statement
{
public:
Identifier *ident;
#if IN_LLVM
// LDC: only set if ident is set: label statement to jump to
LabelStatement *target;
#endif
BreakStatement(Loc loc, Identifier *ident);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
class ContinueStatement : public Statement
{
public:
Identifier *ident;
#if IN_LLVM
// LDC: only set if ident is set: label statement to jump to
LabelStatement *target;
#endif
ContinueStatement(Loc loc, Identifier *ident);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
class SynchronizedStatement : public Statement
{
public:
Expression *exp;
Statement *_body;
SynchronizedStatement(Loc loc, Expression *exp, Statement *body);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
bool hasBreak();
bool hasContinue();
void accept(Visitor *v) { v->visit(this); }
};
class WithStatement : public Statement
{
public:
Expression *exp;
Statement *_body;
VarDeclaration *wthis;
WithStatement(Loc loc, Expression *exp, Statement *body);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
class TryCatchStatement : public Statement
{
public:
Statement *_body;
Catches *catches;
TryCatchStatement(Loc loc, Statement *body, Catches *catches);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
bool hasBreak();
void accept(Visitor *v) { v->visit(this); }
};
class Catch : public RootObject
{
public:
Loc loc;
Type *type;
Identifier *ident;
VarDeclaration *var;
Statement *handler;
// was generated by the compiler,
// wasn't present in source code
bool internalCatch;
Catch(Loc loc, Type *t, Identifier *id, Statement *handler);
Catch *syntaxCopy();
void semantic(Scope *sc);
};
class TryFinallyStatement : public Statement
{
public:
Statement *_body;
Statement *finalbody;
TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody);
static TryFinallyStatement *create(Loc loc, Statement *body, Statement *finalbody);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
bool hasBreak();
bool hasContinue();
void accept(Visitor *v) { v->visit(this); }
};
class OnScopeStatement : public Statement
{
public:
TOK tok;
Statement *statement;
OnScopeStatement(Loc loc, TOK tok, Statement *statement);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally);
void accept(Visitor *v) { v->visit(this); }
};
class ThrowStatement : public Statement
{
public:
Expression *exp;
// was generated by the compiler,
// wasn't present in source code
bool internalThrow;
ThrowStatement(Loc loc, Expression *exp);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
class DebugStatement : public Statement
{
public:
Statement *statement;
DebugStatement(Loc loc, Statement *statement);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
Statements *flatten(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
class GotoStatement : public Statement
{
public:
Identifier *ident;
LabelDsymbol *label;
TryFinallyStatement *tf;
OnScopeStatement *os;
VarDeclaration *lastVar;
GotoStatement(Loc loc, Identifier *ident);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
bool checkLabel();
void accept(Visitor *v) { v->visit(this); }
};
class LabelStatement : public Statement
{
public:
Identifier *ident;
Statement *statement;
TryFinallyStatement *tf;
OnScopeStatement *os;
VarDeclaration *lastVar;
Statement *gotoTarget; // interpret
bool breaks; // someone did a 'break ident'
LabelStatement(Loc loc, Identifier *ident, Statement *statement);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
Statements *flatten(Scope *sc);
Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally);
LabelStatement *isLabelStatement() { return this; }
void accept(Visitor *v) { v->visit(this); }
};
class LabelDsymbol : public Dsymbol
{
public:
LabelStatement *statement;
LabelDsymbol(Identifier *ident);
static LabelDsymbol *create(Identifier *ident);
LabelDsymbol *isLabel();
void accept(Visitor *v) { v->visit(this); }
};
Statement* asmSemantic(AsmStatement *s, Scope *sc);
class AsmStatement : public Statement
{
public:
Token *tokens;
code *asmcode;
unsigned asmalign; // alignment of this statement
unsigned regs; // mask of registers modified (must match regm_t in back end)
bool refparam; // true if function parameter is referenced
bool naked; // true if function is to be naked
#if IN_LLVM
// non-zero if this is a branch, contains the target label
LabelDsymbol* isBranchToLabel;
#endif
AsmStatement(Loc loc, Token *tokens);
Statement *syntaxCopy();
Statement *semantic(Scope *sc)
{
return asmSemantic(this, sc);
}
void accept(Visitor *v) { v->visit(this); }
};
// a complete asm {} block
class CompoundAsmStatement : public CompoundStatement
{
public:
StorageClass stc; // postfix attributes like nothrow/pure/@trusted
#if IN_LLVM
llvm::Value* abiret;
#endif
CompoundAsmStatement(Loc loc, Statements *s, StorageClass stc);
CompoundAsmStatement *syntaxCopy();
CompoundAsmStatement *semantic(Scope *sc);
Statements *flatten(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
#if IN_LLVM
CompoundStatement *isCompoundStatement() { return NULL; }
CompoundAsmStatement *isCompoundAsmBlockStatement() { return this; }
CompoundAsmStatement* endsWithAsm();
#endif
};
class ImportStatement : public Statement
{
public:
Dsymbols *imports; // Array of Import's
ImportStatement(Loc loc, Dsymbols *imports);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
#endif /* DMD_STATEMENT_H */