Intel SPMD Program Compiler  1.3.0
stmt.h
Go to the documentation of this file.
00001 /*
00002   Copyright (c) 2010-2012, Intel Corporation
00003   All rights reserved.
00004 
00005   Redistribution and use in source and binary forms, with or without
00006   modification, are permitted provided that the following conditions are
00007   met:
00008 
00009     * Redistributions of source code must retain the above copyright
00010       notice, this list of conditions and the following disclaimer.
00011 
00012     * Redistributions in binary form must reproduce the above copyright
00013       notice, this list of conditions and the following disclaimer in the
00014       documentation and/or other materials provided with the distribution.
00015 
00016     * Neither the name of Intel Corporation nor the names of its
00017       contributors may be used to endorse or promote products derived from
00018       this software without specific prior written permission.
00019 
00020 
00021    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
00022    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
00023    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00024    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
00025    OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00026    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00027    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00028    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00029    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00030    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00031    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
00032 */
00033 
00034 /** @file stmt.h
00035     @brief File with declarations for classes related to statements in the language
00036 */
00037 
00038 #ifndef ISPC_STMT_H
00039 #define ISPC_STMT_H 1
00040 
00041 #include "ispc.h"
00042 #include "ast.h"
00043 
00044 /** @brief Interface class for statements in the ispc language.
00045 
00046     This abstract base-class encapsulates methods that AST nodes for
00047     statements in the language must implement.
00048  */
00049 class Stmt : public ASTNode {
00050 public:
00051     Stmt(SourcePos p) : ASTNode(p) { }
00052 
00053     /** Emit LLVM IR for the statement, using the FunctionEmitContext to create the
00054         necessary instructions.
00055      */
00056     virtual void EmitCode(FunctionEmitContext *ctx) const = 0;
00057 
00058     /** Print a representation of the statement (and any children AST
00059         nodes) to standard output.  This method is used for debuggins. */
00060     virtual void Print(int indent) const = 0;
00061 
00062     // Redeclare these methods with Stmt * return values, rather than
00063     // ASTNode *s, as in the original ASTNode declarations of them.  We'll
00064     // also provide a default implementation of Optimize(), since most
00065     // Stmts don't have anything to do here.
00066     virtual Stmt *Optimize();
00067     virtual Stmt *TypeCheck() = 0;
00068 };
00069 
00070 
00071 /** @brief Statement representing a single expression */
00072 class ExprStmt : public Stmt {
00073 public:
00074     ExprStmt(Expr *expr, SourcePos pos);
00075 
00076     void EmitCode(FunctionEmitContext *ctx) const;
00077     void Print(int indent) const;
00078 
00079     Stmt *TypeCheck();
00080     int EstimateCost() const;
00081 
00082     Expr *expr;
00083 };
00084 
00085 
00086 struct VariableDeclaration {
00087     VariableDeclaration(Symbol *s = NULL, Expr *i = NULL) { 
00088         sym = s; init = i; 
00089     }
00090     Symbol *sym;
00091     Expr *init;
00092 };
00093 
00094 /** @brief Statement representing a single declaration (which in turn may declare
00095     a number of variables. */
00096 class DeclStmt : public Stmt {
00097 public:
00098     DeclStmt(const std::vector<VariableDeclaration> &v, SourcePos pos);
00099 
00100     void EmitCode(FunctionEmitContext *ctx) const;
00101     void Print(int indent) const;
00102 
00103     Stmt *Optimize();
00104     Stmt *TypeCheck();
00105     int EstimateCost() const;
00106 
00107     std::vector<VariableDeclaration> vars;
00108 };
00109 
00110 
00111 /** @brief Statement representing a single if statement, possibly with an
00112     else clause. */
00113 class IfStmt : public Stmt {
00114 public:
00115     IfStmt(Expr *testExpr, Stmt *trueStmts, Stmt *falseStmts,
00116            bool doAllCheck, SourcePos pos);
00117 
00118     void EmitCode(FunctionEmitContext *ctx) const;
00119     void Print(int indent) const;
00120 
00121     Stmt *TypeCheck();
00122     int EstimateCost() const;
00123 
00124     // @todo these are only public for lHasVaryingBreakOrContinue(); would
00125     // be nice to clean that up...
00126     /** Expression giving the 'if' test. */
00127     Expr *test;
00128     /** Statements to run if the 'if' test returns a true value */
00129     Stmt *trueStmts;
00130     /** Statements to run if the 'if' test returns a false value */
00131     Stmt *falseStmts;
00132 
00133 private:
00134     /** This value records if this was a 'coherent' if statement in the
00135         source and thus, if the emitted code should check to see if all
00136         active program instances want to follow just one of the 'true' or
00137         'false' blocks. */
00138     const bool doAllCheck;
00139 
00140     void emitMaskedTrueAndFalse(FunctionEmitContext *ctx, llvm::Value *oldMask, 
00141                                 llvm::Value *test) const;
00142     void emitVaryingIf(FunctionEmitContext *ctx, llvm::Value *test) const;
00143     void emitMaskAllOn(FunctionEmitContext *ctx,
00144                        llvm::Value *test, llvm::BasicBlock *bDone) const;
00145     void emitMaskMixed(FunctionEmitContext *ctx, llvm::Value *oldMask, 
00146                        llvm::Value *test, llvm::BasicBlock *bDone) const;
00147 };
00148 
00149 
00150 /** @brief Statement implementation representing a 'do' statement in the
00151     program.
00152  */
00153 class DoStmt : public Stmt {
00154 public:
00155     DoStmt(Expr *testExpr, Stmt *bodyStmts, bool doCoherentCheck, 
00156            SourcePos pos);
00157 
00158     void EmitCode(FunctionEmitContext *ctx) const;
00159     void Print(int indent) const;
00160 
00161     Stmt *TypeCheck();
00162     int EstimateCost() const;
00163 
00164     Expr *testExpr;
00165     Stmt *bodyStmts;
00166     const bool doCoherentCheck;
00167 };
00168 
00169 
00170 /** @brief Statement implementation for 'for' loops (as well as for 'while'
00171     loops).
00172  */
00173 class ForStmt : public Stmt {
00174 public:
00175     ForStmt(Stmt *initializer, Expr *testExpr, Stmt *stepStatements,
00176             Stmt *bodyStatements, bool doCoherentCheck, SourcePos pos);
00177 
00178     void EmitCode(FunctionEmitContext *ctx) const;
00179     void Print(int indent) const;
00180 
00181     Stmt *TypeCheck();
00182     int EstimateCost() const;
00183 
00184     /** 'for' statment initializer; may be NULL, indicating no intitializer */
00185     Stmt *init;
00186     /** expression that returns a value indicating whether the loop should
00187         continue for the next iteration */
00188     Expr *test;
00189     /** Statements to run at the end of the loop for the loop step, before
00190         the test expression is evaluated. */
00191     Stmt *step;
00192     /** Loop body statements */
00193     Stmt *stmts;
00194     const bool doCoherentCheck;
00195 };
00196 
00197 
00198 /** @brief Statement implementation for a break or 'coherent' break
00199     statement in the program. */
00200 class BreakStmt : public Stmt {
00201 public:
00202     BreakStmt(bool doCoherenceCheck, SourcePos pos);
00203 
00204     void EmitCode(FunctionEmitContext *ctx) const;
00205     void Print(int indent) const;
00206 
00207     Stmt *TypeCheck();
00208     int EstimateCost() const;
00209 
00210 private:
00211     /** This indicates whether the generated code will check to see if no
00212         more program instances are currently running after the break, in
00213         which case the code can have a jump to the end of the current
00214         loop. */
00215     const bool doCoherenceCheck;
00216 };
00217 
00218 
00219 /** @brief Statement implementation for a continue or 'coherent' continue
00220     statement in the program. */
00221 class ContinueStmt : public Stmt {
00222 public:
00223     ContinueStmt(bool doCoherenceCheck, SourcePos pos);
00224 
00225     void EmitCode(FunctionEmitContext *ctx) const;
00226     void Print(int indent) const;
00227 
00228     Stmt *TypeCheck();
00229     int EstimateCost() const;
00230 
00231 private:
00232     /** This indicates whether the generated code will check to see if no
00233         more program instances are currently running after the continue, in
00234         which case the code can have a jump to the end of the current
00235         loop. */
00236     const bool doCoherenceCheck;
00237 };
00238 
00239 
00240 /** @brief Statement implementation for parallel 'foreach' loops.
00241  */
00242 class ForeachStmt : public Stmt {
00243 public:
00244     ForeachStmt(const std::vector<Symbol *> &loopVars, 
00245                 const std::vector<Expr *> &startExprs, 
00246                 const std::vector<Expr *> &endExprs, 
00247                 Stmt *bodyStatements, bool tiled, SourcePos pos);
00248 
00249     void EmitCode(FunctionEmitContext *ctx) const;
00250     void Print(int indent) const;
00251 
00252     Stmt *TypeCheck();
00253     int EstimateCost() const;
00254 
00255     std::vector<Symbol *> dimVariables;
00256     std::vector<Expr *> startExprs;
00257     std::vector<Expr *> endExprs;
00258     bool isTiled;
00259     Stmt *stmts;
00260 };
00261 
00262 
00263 /** Iteration over each executing program instance.
00264  */
00265 class ForeachActiveStmt : public Stmt {
00266 public:
00267     ForeachActiveStmt(Symbol *iterSym, Stmt *stmts, SourcePos pos);
00268 
00269     void EmitCode(FunctionEmitContext *ctx) const;
00270     void Print(int indent) const;
00271 
00272     Stmt *TypeCheck();
00273     int EstimateCost() const;
00274 
00275     Symbol *sym;
00276     Stmt *stmts;
00277 };
00278 
00279 
00280 /** Parallel iteration over each unique value in the given (varying)
00281     expression.
00282  */
00283 class ForeachUniqueStmt : public Stmt {
00284 public:
00285     ForeachUniqueStmt(const char *iterName, Expr *expr, Stmt *stmts,
00286                       SourcePos pos);
00287 
00288     void EmitCode(FunctionEmitContext *ctx) const;
00289     void Print(int indent) const;
00290 
00291     Stmt *TypeCheck();
00292     int EstimateCost() const;
00293 
00294     Symbol *sym;
00295     Expr *expr;
00296     Stmt *stmts;
00297 };
00298 
00299 
00300 /** 
00301  */
00302 class UnmaskedStmt : public Stmt {
00303 public:
00304     UnmaskedStmt(Stmt *stmt, SourcePos pos);
00305 
00306     void EmitCode(FunctionEmitContext *ctx) const;
00307     void Print(int indent) const;
00308 
00309     Stmt *TypeCheck();
00310     int EstimateCost() const;
00311 
00312     Stmt *stmts;
00313 };
00314 
00315 
00316 
00317 /** @brief Statement implementation for a 'return' or 'coherent' return
00318     statement in the program. */
00319 class ReturnStmt : public Stmt {
00320 public:
00321     ReturnStmt(Expr *e, bool cc, SourcePos p);
00322 
00323     void EmitCode(FunctionEmitContext *ctx) const;
00324     void Print(int indent) const;
00325 
00326     Stmt *TypeCheck();
00327     int EstimateCost() const;
00328 
00329     Expr *expr;
00330     /** This indicates whether the generated code will check to see if no
00331         more program instances are currently running after the return, in
00332         which case the code can possibly jump to the end of the current
00333         function. */
00334     const bool doCoherenceCheck;
00335 };
00336 
00337 
00338 /** Statement corresponding to a "case" label in the program.  In addition
00339     to the value associated with the "case", this statement also stores the
00340     statements following it. */
00341 class CaseStmt : public Stmt {
00342 public:
00343     CaseStmt(int value, Stmt *stmt, SourcePos pos);
00344 
00345     void EmitCode(FunctionEmitContext *ctx) const;
00346     void Print(int indent) const;
00347 
00348     Stmt *TypeCheck();
00349     int EstimateCost() const;
00350 
00351     /** Integer value after the "case" statement */
00352     const int value;
00353     Stmt *stmts;
00354 };
00355 
00356 
00357 /** Statement for a "default" label (as would be found inside a "switch"
00358     statement). */
00359 class DefaultStmt : public Stmt {
00360 public:
00361     DefaultStmt(Stmt *stmt, SourcePos pos);
00362 
00363     void EmitCode(FunctionEmitContext *ctx) const;
00364     void Print(int indent) const;
00365 
00366     Stmt *TypeCheck();
00367     int EstimateCost() const;
00368 
00369     Stmt *stmts;
00370 };
00371 
00372 
00373 /** A "switch" statement in the program. */
00374 class SwitchStmt : public Stmt {
00375 public:
00376     SwitchStmt(Expr *expr, Stmt *stmts, SourcePos pos);
00377 
00378     void EmitCode(FunctionEmitContext *ctx) const;
00379     void Print(int indent) const;
00380 
00381     Stmt *TypeCheck();
00382     int EstimateCost() const;
00383 
00384     /** Expression that is used to determine which label to jump to. */
00385     Expr *expr;
00386     /** Statement block after the "switch" expression. */
00387     Stmt *stmts;
00388 };
00389 
00390 
00391 /** A "goto" in an ispc program. */
00392 class GotoStmt : public Stmt {
00393 public:
00394     GotoStmt(const char *label, SourcePos gotoPos, SourcePos idPos);
00395 
00396     void EmitCode(FunctionEmitContext *ctx) const;
00397     void Print(int indent) const;
00398 
00399     Stmt *Optimize();
00400     Stmt *TypeCheck();
00401     int EstimateCost() const;
00402 
00403     /** Name of the label to jump to when the goto is executed. */
00404     std::string label;
00405     SourcePos identifierPos;
00406 };
00407 
00408 
00409 /** Statement corresponding to a label (as would be used as a goto target)
00410     in the program. */
00411 class LabeledStmt : public Stmt {
00412 public:
00413     LabeledStmt(const char *label, Stmt *stmt, SourcePos p);
00414 
00415     void EmitCode(FunctionEmitContext *ctx) const;
00416     void Print(int indent) const;
00417 
00418     Stmt *Optimize();
00419     Stmt *TypeCheck();
00420     int EstimateCost() const;
00421 
00422     /** Name of the label. */
00423     std::string name;
00424     /** Statements following the label. */
00425     Stmt *stmt;
00426 };
00427 
00428 
00429 /** @brief Representation of a list of statements in the program.
00430  */
00431 class StmtList : public Stmt {
00432 public:
00433     StmtList(SourcePos p) : Stmt(p) { }
00434 
00435     void EmitCode(FunctionEmitContext *ctx) const;
00436     void Print(int indent) const;
00437 
00438     Stmt *TypeCheck();
00439     int EstimateCost() const;
00440 
00441     void Add(Stmt *s) { if (s) stmts.push_back(s); }
00442 
00443     std::vector<Stmt *> stmts;
00444 };
00445 
00446 
00447 /** @brief Representation of a print() statement in the program.
00448 
00449     It's currently necessary to have a special statement type for print()
00450     since strings aren't supported as first-class types in the language,
00451     but we need to be able to pass a formatting string as the first
00452     argument to print().  We also need this to be a variable argument
00453     function, which also isn't supported.  Representing print() as a
00454     statement lets us work around both of those ugly little issues...
00455   */
00456 class PrintStmt : public Stmt {
00457 public:
00458     PrintStmt(const std::string &f, Expr *v, SourcePos p);
00459 
00460     void EmitCode(FunctionEmitContext *ctx) const;
00461     void Print(int indent) const;
00462 
00463     Stmt *TypeCheck();
00464     int EstimateCost() const;
00465 
00466     /** Format string for the print() statement. */
00467     const std::string format;
00468     /** This holds the arguments passed to the print() statement.  If more
00469         than one was provided, this will be an ExprList. */
00470     Expr *values;
00471 };
00472 
00473 
00474 /** @brief Representation of an assert statement in the program.
00475 
00476     Like print() above, since we don't have strings as first-class types in
00477     the language, we need to do some gymnastics to support it.  Like
00478     assert() in C, assert() checks the given condition and prints an error
00479     and calls abort if the condition fails.  For varying conditions, the
00480     assert triggers if it's true for any of the program instances.
00481 */
00482 class AssertStmt : public Stmt {
00483 public:
00484     AssertStmt(const std::string &msg, Expr *e, SourcePos p);
00485 
00486     void EmitCode(FunctionEmitContext *ctx) const;
00487     void Print(int indent) const;
00488 
00489     Stmt *TypeCheck();
00490     int EstimateCost() const;
00491 
00492     /** Message to print if the assertion fails. */
00493     const std::string message;
00494     /** The expression to be evaluated (that is asserted to be true). */
00495     Expr *expr;
00496 };
00497 
00498 
00499 /** Representation of a delete statement in the program.
00500 */
00501 class DeleteStmt : public Stmt {
00502 public:
00503     DeleteStmt(Expr *e, SourcePos p);
00504 
00505     void EmitCode(FunctionEmitContext *ctx) const;
00506     void Print(int indent) const;
00507 
00508     Stmt *TypeCheck();
00509     int EstimateCost() const;
00510 
00511     /** Expression that gives the pointer value to be deleted. */
00512     Expr *expr;
00513 };
00514 
00515 extern Stmt *CreateForeachActiveStmt(Symbol *iterSym, Stmt *stmts, 
00516                                      SourcePos pos);
00517 
00518 #endif // ISPC_STMT_H