GCC's contains many intermediate representations thought the different stages of compilations to achieve different things, but Generic is the main one which Front-End and to a lesser extend Middle-end developers will deal with. Generic refers to any time the 'tree' data type is used thought out the gcc internals.
In essence its a DAG form of representing data which means for example an expression such as:
x = 1 + 2 + 3
would be represented as:
= / \ x + / \ 1 + / \ 2 3
But here i will try to give an overview with code examples of how to represent different type of language constructs with GENERIC as this is a very daunting part of becoming a front-end developer in my opinion is know how to code the GENERIC tree's for all kinds language constructs.
So lets take the above for our first example lets pretend the code was:
int x; x = 1 + 2 + 3;
The tree code you could write would be:
tree var_decl = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifer("x"), integer_type_node); tree expr_tmp = build2 (PLUS_EXPR, integer_type_node, build_int_cst(integer_type_node, 2), build_int_cst (integer_type_node, 3)); tree expr = build2(PLUS_EXPR, integer_type_node, build_int_cst(integer_type_node, 1), expr_tmp); tree eval = build2 (MODIFY_EXPR, integer_type_node, var_decl, expr);
The nice thing about this is you dont have to worry about folding out the extras such as:
int x, T.1, T.2; T.1 = 2 + 3; T.2 = 1 + T.1; x = T.2;
Other Primitive Types
Other Binary Operators
- ... the others can be seen in tree.def along with their respective documentation
Lets look at some more complicated examples namely language structures.
Functions will be the real meat of generating code in front-ends, and GCC has a lot of flexibility in how you can create them quite easily.
tree ident = get_identifier ("foobar") tree fndecl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL, ident, fntype); DECL_EXTERNAL (fndecl) = 0; TREE_PUBLIC (fndecl) = 1; TREE_STATIC (fndecl) = 1; tree arglist = NULL_TREE; tree result_decl = build_decl (BUILTINS_LOCATION, RESULT_DECL, NULL_TREE, return_type); DECL_RESULT (fndecl) = result_decl; SET_DECL_ASSEMBLER_NAME (fndecl, ident); tree self_parm_decl = build_decl (BUILTINS_LOCATION, PARM_DECL, get_identifier ("argname"), type); DECL_CONTEXT (self_parm_decl) = fndecl; DECL_ARG_TYPE (self_parm_decl) = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (fndecl))); TREE_READONLY (self_parm_decl) = 1; arglist = chainon (arglist, self_parm_decl); TREE_USED (self_parm_decl) = 1; DECL_ARGUMENTS (fndecl) = arglist; append_to_statement_list (stmt, &block); DECL_INITIAL(fndecl) = block; tree bl = make_node(BLOCK); BLOCK_SUPERCONTEXT(bl) = fndecl; DECL_INITIAL(fndecl) = bl; BLOCK_VARS(bl) = NULL_TREE; TREE_USED(bl) = 1; tree bind = build3(BIND_EXPR, void_type_node, BLOCK_VARS(bl), NULL_TREE, bl); TREE_SIDE_EFFECTS(bind) = 1; BIND_EXPR_BODY(bind) = block; block = bind; DECL_SAVED_TREE(fndecl) = block; gimplify_function_tree (fndecl); cgraph_add_new_function (fndecl, false); cgraph_finalize_function (fndecl, true);