📄 tree-ssa.texi
字号:
@end enumerateThe second sequence is not executed if the first sequence completes bycalling @code{setjmp} or @code{exit} or any other function that doesnot return. The second sequence is also not executed if the firstsequence completes via a non-local goto or a computed goto (in generalthe compiler does not know whether such a goto statement exits thefirst sequence or not, so we assume that it doesn't).After the second sequence is executed, if it completes normally byfalling off the end, execution continues wherever the first sequencewould have continued, by falling off the end, or doing a goto, etc.@code{TRY_FINALLY_EXPR} complicates the flow graph, since the cleanupneeds to appear on every edge out of the controlled block; thisreduces the freedom to move code across these edges. Therefore, theEH lowering pass which runs before most of the optimization passeseliminates these expressions by explicitly adding the cleanup to eachedge. Rethrowing the exception is represented using @code{RESX_EXPR}.@node GIMPLE Exception Handling@subsubsection Exception Handling@cindex GIMPLE Exception HandlingOther exception handling constructs are represented using@code{TRY_CATCH_EXPR}. @code{TRY_CATCH_EXPR} has two operands. Thefirst operand is a sequence of statements to execute. If executingthese statements does not throw an exception, then the second operandis ignored. Otherwise, if an exception is thrown, then the secondoperand of the @code{TRY_CATCH_EXPR} is checked. The second operandmay have the following forms:@enumerate@item A sequence of statements to execute. When an exception occurs,these statements are executed, and then the exception is rethrown.@item A sequence of @code{CATCH_EXPR} expressions. Each @code{CATCH_EXPR}has a list of applicable exception types and handler code. If thethrown exception matches one of the caught types, the associatedhandler code is executed. If the handler code falls off the bottom,execution continues after the original @code{TRY_CATCH_EXPR}.@item An @code{EH_FILTER_EXPR} expression. This has a list ofpermitted exception types, and code to handle a match failure. If thethrown exception does not match one of the allowed types, theassociated match failure code is executed. If the thrown exceptiondoes match, it continues unwinding the stack looking for the nexthandler.@end enumerateCurrently throwing an exception is not directly represented in GIMPLE,since it is implemented by calling a function. At some point in the futurewe will want to add some way to express that the call will throw anexception of a known type.Just before running the optimizers, the compiler lowers the high-levelEH constructs above into a set of @samp{goto}s, magic labels, and EHregions. Continuing to unwind at the end of a cleanup is representedwith a @code{RESX_EXPR}.@node GIMPLE Example@subsection GIMPLE Example@cindex GIMPLE Example@smallexamplestruct A @{ A(); ~A(); @};int i;int g();void f()@{ A a; int j = (--i, i ? 0 : 1); for (int x = 42; x > 0; --x) @{ i += g()*4 + 32; @}@}@end smallexamplebecomes@smallexamplevoid f()@{ int i.0; int T.1; int iftmp.2; int T.3; int T.4; int T.5; int T.6; @{ struct A a; int j; __comp_ctor (&a); try @{ i.0 = i; T.1 = i.0 - 1; i = T.1; i.0 = i; if (i.0 == 0) iftmp.2 = 1; else iftmp.2 = 0; j = iftmp.2; @{ int x; x = 42; goto test; loop:; T.3 = g (); T.4 = T.3 * 4; i.0 = i; T.5 = T.4 + i.0; T.6 = T.5 + 32; i = T.6; x = x - 1; test:; if (x > 0) goto loop; else goto break_; break_:; @} @} finally @{ __comp_dtor (&a); @} @}@}@end smallexample@node Rough GIMPLE Grammar@subsection Rough GIMPLE Grammar@cindex Rough GIMPLE Grammar@smallexample function : FUNCTION_DECL DECL_SAVED_TREE -> compound-stmt compound-stmt: STATEMENT_LIST members -> stmt stmt : block | if-stmt | switch-stmt | goto-stmt | return-stmt | resx-stmt | label-stmt | try-stmt | modify-stmt | call-stmt block : BIND_EXPR BIND_EXPR_VARS -> chain of DECLs BIND_EXPR_BLOCK -> BLOCK BIND_EXPR_BODY -> compound-stmt if-stmt : COND_EXPR op0 -> condition op1 -> compound-stmt op2 -> compound-stmt switch-stmt : SWITCH_EXPR op0 -> val op1 -> NULL op2 -> TREE_VEC of CASE_LABEL_EXPRs The CASE_LABEL_EXPRs are sorted by CASE_LOW, and default is last. goto-stmt : GOTO_EXPR op0 -> LABEL_DECL | val return-stmt : RETURN_EXPR op0 -> return-value return-value : NULL | RESULT_DECL | MODIFY_EXPR op0 -> RESULT_DECL op1 -> lhs resx-stmt : RESX_EXPR label-stmt : LABEL_EXPR op0 -> LABEL_DECL try-stmt : TRY_CATCH_EXPR op0 -> compound-stmt op1 -> handler | TRY_FINALLY_EXPR op0 -> compound-stmt op1 -> compound-stmt handler : catch-seq | EH_FILTER_EXPR | compound-stmt catch-seq : STATEMENT_LIST members -> CATCH_EXPR modify-stmt : MODIFY_EXPR op0 -> lhs op1 -> rhs call-stmt : CALL_EXPR op0 -> val | OBJ_TYPE_REF op1 -> call-arg-list call-arg-list: TREE_LIST members -> lhs | CONST addr-expr-arg: ID | compref addressable : addr-expr-arg | indirectref with-size-arg: addressable | call-stmt indirectref : INDIRECT_REF op0 -> val lhs : addressable | bitfieldref | WITH_SIZE_EXPR op0 -> with-size-arg op1 -> val min-lval : ID | indirectref bitfieldref : BIT_FIELD_REF op0 -> inner-compref op1 -> CONST op2 -> val compref : inner-compref | TARGET_MEM_REF op0 -> ID op1 -> val op2 -> val op3 -> CONST op4 -> CONST | REALPART_EXPR op0 -> inner-compref | IMAGPART_EXPR op0 -> inner-compref inner-compref: min-lval | COMPONENT_REF op0 -> inner-compref op1 -> FIELD_DECL op2 -> val | ARRAY_REF op0 -> inner-compref op1 -> val op2 -> val op3 -> val | ARRAY_RANGE_REF op0 -> inner-compref op1 -> val op2 -> val op3 -> val | VIEW_CONVERT_EXPR op0 -> inner-compref condition : val | RELOP op0 -> val op1 -> val val : ID | invariant ADDR_EXPR op0 -> addr-expr-arg | CONST rhs : lhs | CONST | call-stmt | ADDR_EXPR op0 -> addr-expr-arg | UNOP op0 -> val | BINOP op0 -> val op1 -> val | RELOP op0 -> val op1 -> val | COND_EXPR op0 -> condition op1 -> val op2 -> val@end smallexample@node Annotations@section Annotations@cindex annotationsThe optimizers need to associate attributes with statements andvariables during the optimization process. For instance, we need toknow what basic block a statement belongs to or whether a variablehas aliases. All these attributes are stored in data structurescalled annotations which are then linked to the field @code{ann} in@code{struct tree_common}.Presently, we define annotations for statements (@code{stmt_ann_t}),variables (@code{var_ann_t}) and SSA names (@code{ssa_name_ann_t}).Annotations are defined and documented in @file{tree-flow.h}.@node Statement Operands@section Statement Operands@cindex operands@cindex virtual operands@cindex real operands@findex update_stmtAlmost every GIMPLE statement will contain a reference to a variableor memory location. Since statements come in different shapes andsizes, their operands are going to be located at various spots insidethe statement's tree. To facilitate access to the statement'soperands, they are organized into lists associated inside eachstatement's annotation. Each element in an operand list is a pointerto a @code{VAR_DECL}, @code{PARM_DECL} or @code{SSA_NAME} tree node.This provides a very convenient way of examining and replacingoperands.Data flow analysis and optimization is done on all tree nodesrepresenting variables. Any node for which @code{SSA_VAR_P} returnsnonzero is considered when scanning statement operands. However, notall @code{SSA_VAR_P} variables are processed in the same way. For thepurposes of optimization, we need to distinguish between references tolocal scalar variables and references to globals, statics, structures,arrays, aliased variables, etc. The reason is simple, the compilercan gather complete data flow information for a local scalar. On theother hand, a global variable may be modified by a function call, itmay not be possible to keep track of all the elements of an array orthe fields of a structure, etc.The operand scanner gathers two kinds of operands: @dfn{real} and@dfn{virtual}. An operand for which @code{is_gimple_reg} returns trueis considered real, otherwise it is a virtual operand. We alsodistinguish between uses and definitions. An operand is used if itsvalue is loaded by the statement (e.g., the operand at the RHS of anassignment). If the statement assigns a new value to the operand, theoperand is considered a definition (e.g., the operand at the LHS ofan assignment).Virtual and real operands also have very different data flowproperties. Real operands are unambiguous references to thefull object that they represent. For instance, given@smallexample@{ int a, b; a = b@}@end smallexampleSince @code{a} and @code{b} are non-aliased locals, the statement@code{a = b} will have one real definition and one real use becausevariable @code{b} is completely modified with the contents ofvariable @code{a}. Real definition are also known as @dfn{killingdefinitions}. Similarly, the use of @code{a} reads all its bits.In contrast, virtual operands are used with variables that can havea partial or ambiguous reference. This includes structures, arrays,globals, and aliased variables. In these cases, we have two types ofdefinitions. For globals, structures, and arrays, we can determine froma statement whether a variable of these types has a killing definition.If the variable does, then the statement is marked as having a@dfn{must definition} of that variable. However, if a statement is onlydefining a part of the variable (i.e.@: a field in a structure), or if weknow that a statement might define the variable but we cannot say for sure,then we mark that statement as having a @dfn{may definition}. Forinstance, given@smallexample@{ int a, b, *p; if (@dots{}) p = &a; else p = &b; *p = 5; return *p;@}@end smallexampleThe assignment @code{*p = 5} may be a definition of @code{a} or@code{b}. If we cannot determine statically where @code{p} ispointing to at the time of the store operation, we create virtualdefinitions to mark that statement as a potential definition site for@code{a} and @code{b}. Memory loads are similarly marked with virtualuse operands. Virtual operands are shown in tree dumps right beforethe statement that contains them. To request a tree dump with virtualoperands, use the @option{-vops} option to @option{-fdump-tree}:@smallexample@{ int a, b, *p; if (@dots{}) p = &a; else p = &b; # a = VDEF <a> # b = VDEF <b> *p = 5; # VUSE <a> # VUSE <b> return *p;@}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -