summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog.MELT4
-rw-r--r--gcc/melt/xtramelt-c-generator.melt930
2 files changed, 934 insertions, 0 deletions
diff --git a/gcc/ChangeLog.MELT b/gcc/ChangeLog.MELT
index dbc5100d69a..c69b5646cec 100644
--- a/gcc/ChangeLog.MELT
+++ b/gcc/ChangeLog.MELT
@@ -1,3 +1,7 @@
+2010-08-31 Jeremie salvucci <jeremie.salvucci@free.fr>
+ * xtramelt-ana-base.melt (gimple_iterator): Iterator added for gimple.
+ * xtramelt-c-generator.melt: Added new file.
+
2010-08-16 Jeremie salvucci <jeremie.salvucci@free.fr>
* xtramelt-ana-base.melt (tree_void_type) : Pattern added for void type.
(tree_indirect_reference) : Pattern added for indirect reference.
diff --git a/gcc/melt/xtramelt-c-generator.melt b/gcc/melt/xtramelt-c-generator.melt
new file mode 100644
index 00000000000..48a7dc52aa3
--- /dev/null
+++ b/gcc/melt/xtramelt-c-generator.melt
@@ -0,0 +1,930 @@
+(comment "***
+ Copyright 2010 Free Software Foundation, Inc.
+ Contributed by Jeremie Salvucci <jeremie.salvucci@free.fr>
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>.
+***")
+
+; Generation of C code from the GIMPLE representation.
+;
+; Beta status !
+;
+; TODO list :
+;
+; - Handler for structures declaration
+; - Handler for unions declaration
+; - Handler for #pragma
+; - ...
+;
+; The main idea of this program is to build a representation between GIMPLE
+; and generated C code. We need a middle representation because GCC make
+; changes in place. So if we use the at_finish_unit_last hook, we can not be
+; sure to get what we want.
+;
+; The first part is about MELT objects useful to copy the GIMPLE representation.
+; We need to find a place for our pass. We choose the Control Flo Graph one. At
+; this step, the code has been linearized.
+;
+; Objects needed :
+;
+; - function,
+; - header,
+; - body,
+; - block (basic_block),
+; - typed element (variables, ...),
+; - fields (useful for structures, unions, ...),
+; - structures,
+; - expressions,
+; - conditions,
+; - ...
+;
+(defclass class_c_generator_generator
+ :super class_proped
+ :fields ())
+
+(defclass class_c_generator_sets
+ :super class_proped
+ :fields (sets_header
+ sets_variables
+ sets_labels
+ sets_structures))
+
+(defclass class_c_generator_functions
+ :super class_c_generator_generator
+ :fields (functions_root
+ structures_declarations))
+
+(defclass class_c_generator_function
+ :super class_c_generator_generator
+ :fields (function_header
+ function_local_variables
+ function_blocks))
+
+(defclass class_c_generator_typed_element
+ :super class_c_generator_generator
+ :fields (element_type
+ element_name))
+
+(defclass class_c_generator_header
+ :super class_c_generator_typed_element
+ :fields (header_parameters))
+
+(defclass class_c_generator_declaration
+ :super class_c_generator_typed_element
+ :fields ())
+
+(defclass class_c_generator_field
+ :super class_c_generator_typed_element
+ :fields ())
+
+(defclass class_c_generator_structure
+ :super class_c_generator_typed_element
+ :fields (structure_fields))
+
+(defclass class_c_generator_expression
+ :super class_c_generator_generator
+ :fields (expression_operand1
+ expression_operator
+ expression_operand2))
+
+(defclass class_c_generator_call
+ :super class_c_generator_typed_element
+ :fields (call_lvalue
+ call_parameters))
+
+(defclass class_c_generator_assignment
+ :super class_c_generator_expression
+ :fields (assignment_lvalue))
+
+(defclass class_c_generator_condition
+ :super class_c_generator_expression
+ :fields (condition_iftrue
+ condition_iffalse))
+
+(defclass class_c_generator_goto
+ :super class_c_generator_generator
+ :fields (goto_value))
+
+(defclass class_c_generator_return
+ :super class_c_generator_generator
+ :fields (return_value))
+
+(defclass class_c_generator_block
+ :super class_c_generator_generator
+ :fields (block_id
+ block_successors
+ block_id_successor
+ block_instructions))
+
+(defclass class_c_generator_body
+ :super class_c_generator_generator
+ :fields (body_blocks))
+
+(defselector add_to_buffer class_selector
+ :formals (object buffer))
+
+(defselector add_prototype_to_buffer class_selector
+ :formals (object buffer))
+
+(defprimitive basic_block_index (:basic_block b) :long
+ #{
+ (($b) ? ($b)->index : -1)
+ }#)
+
+(defprimitive is_gimple_cond (:gimple g) :long
+ #{
+ (($g) ? gimple_code ($g) == GIMPLE_COND : 0)
+ }#)
+
+(defprimitive is_gimple_assign (:gimple g) :long
+ #{
+ (($g) ? gimple_code ($g) == GIMPLE_ASSIGN : 0)
+ }#)
+
+(defprimitive is_gimple_return (:gimple g) :long
+ #{
+ (($g) ? gimple_code ($g) == GIMPLE_RETURN : 0)
+ }#)
+
+(defprimitive is_gimple_call (:gimple g) :long
+ #{
+ (($g) ? gimple_code ($g) == GIMPLE_CALL : 0)
+ }#)
+
+(defprimitive is_gimple_goto (:gimple g) :long
+ #{
+ (($g) ? gimple_code ($g) == GIMPLE_GOTO : 0)
+ }#)
+
+;; Traverse tree
+
+(defun traverse_header_parameters_function (parameters)
+ (foreach_in_list
+ (parameters)
+ (pair parameter)
+ (let ((type (get_field :element_type parameter))
+ (name (get_field :element_name parameter)))
+ (debug_msg type "Type : ")
+ (debug_msg name "Name : ")
+ (debug_msg '1 ","))))
+
+(defun traverse_header_function (header)
+ (let ((type (get_field :element_type header))
+ (name (get_field :element_name header))
+ (parameters (get_field :header_parameters header)))
+ (debug_msg '1 "Header : ")
+ (debug_msg type "Type : ")
+ (debug_msg name "Name : ")
+ (traverse_header_parameters_function parameters)))
+
+(defun traverse_local_variables_function (local_variables)
+ (debug_msg local_variables "Local variables :")
+ (foreach_in_list
+ (local_variables)
+ (pair declaration)
+ (let ((type (get_field :element_type declaration))
+ (name (get_field :element_name declaration)))
+ (debug_msg type "Type : ")
+ (debug_msg name "Name : "))))
+
+(defun traverse_block_instructions_function (_block_)
+ (let ((id (get_field :block_id _block_))
+ (instructions (get_field :block_instructions _block_)))
+ (foreach_in_list
+ (instructions)
+ (pair instruction)
+ (debug_msg instruction "Instruction : "))))
+
+(defun traverse_blocks_function (blocks)
+ (foreach_in_list
+ (blocks)
+ (pair block)
+ (traverse_block_instructions_function block)))
+
+(defun traverse_function_structure (function)
+ (let ((header (get_field :function_header function))
+ (local_variables (get_field :function_local_variables function))
+ (blocks (get_field :function_blocks function)))
+ (traverse_header_function header)
+ (traverse_local_variables_function local_variables)
+ (traverse_blocks_function blocks)))
+
+(defun traverse_main_structure (structure)
+ (foreach_in_list
+ (structure)
+ (pair node)
+ (traverse_function_structure node)))
+
+; We build a tree thanks to previous objects. Each object has its own method
+; add_to_buffer. For example, when we have a condition node, the method adds
+;
+; if <condition> {
+; <goto label>
+; }
+; else {
+; <goto label>
+; }
+;
+; Following functions are useful to get C code.
+;
+
+;; Get structures
+
+(defun add_structure_declaration_to_buffer (structure buffer)
+ (let ((name (get_field :element_name structure))
+ (fields (get_field :structure_fields structure)))
+ (add2sbuf_strconst buffer "struct ")
+ (add2sbuf_string buffer name)
+ (add2sbuf_strconst buffer "{")
+ (foreach_in_list
+ (fields)
+ (pair current_element)
+ (let ((field_type (get_field :element_type current_element))
+ (field_name (get_field :element_name current_element)))
+ (add2sbuf_string buffer field_type)
+ (add2sbuf_strconst buffer " ")
+ (add2sbuf_string buffer field_name)
+ (add2sbuf_strconst buffer ";")))
+ (add2sbuf_strconst buffer "};")))
+
+(install_method class_c_generator_structure add_to_buffer add_structure_declaration_to_buffer)
+
+(defun add_structures_declarations_to_buffer (structures buffer)
+ (foreach_in_list
+ (structures)
+ (pair current_element)
+ (debug_msg current_element "Current : ")
+ (add_to_buffer current_element buffer)))
+
+;; Get prototypes
+
+(defun add_function_prototype_to_buffer (function buffer)
+ (let ((header (get_field :function_header function)))
+ (add_to_buffer header buffer)
+ (add2sbuf_strconst buffer ";")))
+
+(install_method class_c_generator_function add_prototype_to_buffer add_function_prototype_to_buffer)
+
+(defun add_functions_prototypes_to_buffer (root buffer)
+ (let ((functions (get_field :functions_root root)))
+ (foreach_in_list
+ (functions)
+ (pair current_element)
+ (add_prototype_to_buffer current_element buffer))))
+
+(install_method class_c_generator_functions add_prototype_to_buffer add_functions_prototypes_to_buffer)
+
+;; Get code
+
+(defun add_functions_to_buffer (root buffer)
+ (let ((functions (get_field :functions_root root)))
+ (foreach_in_list
+ (functions)
+ (pair current_element)
+ (add_to_buffer current_element buffer))))
+
+(install_method class_c_generator_functions add_to_buffer add_functions_to_buffer)
+
+(defun add_local_variables_to_buffer (local_variables buffer)
+ (foreach_in_list
+ (local_variables)
+ (pair current_element)
+ (let ((type (get_field :element_type current_element))
+ (name (get_field :element_name current_element)))
+ (add2sbuf_string buffer type)
+ (add2sbuf_strconst buffer " ")
+ (add2sbuf_string buffer name)
+ (add2sbuf_strconst buffer ";"))))
+
+(defun add_blocks_to_buffer (blocks buffer)
+ (foreach_in_list
+ (blocks)
+ (pair current_element)
+ (add2sbuf_string buffer (add_to_buffer current_element buffer))))
+
+(defun add_function_to_buffer (function buffer)
+ (let ((header (get_field :function_header function))
+ (local_variables (get_field :function_local_variables function))
+ (body (get_field :function_blocks function)))
+ (add_to_buffer header buffer)
+ (add2sbuf_strconst buffer "{")
+ (add_local_variables_to_buffer local_variables buffer)
+ (add_blocks_to_buffer body buffer)
+ (add2sbuf_strconst buffer "}")))
+
+(install_method class_c_generator_function add_to_buffer add_function_to_buffer)
+
+(defun add_parameters_to_buffer (parameters buffer)
+ (let ((count (make_integerbox discr_integer 0)))
+ (foreach_in_list
+ (parameters)
+ (pair current_node)
+ (let ((type (get_field :element_type current_node))
+ (name (get_field :element_name current_node)))
+ (if (>i (get_int count) 0)
+ (add2sbuf_strconst buffer ","))
+ (add2sbuf_string buffer type)
+ (add2sbuf_strconst buffer " ")
+ (add2sbuf_string buffer name)
+ (put_int count (+i 1 (get_int count)))))))
+
+(defun add_header_to_buffer (header buffer)
+ (let ((return_type (get_field :element_type header))
+ (name (get_field :element_name header))
+ (parameters (get_field :header_parameters header)))
+ (add2sbuf_string buffer return_type)
+ (add2sbuf_strconst buffer " ")
+ (add2sbuf_string buffer name)
+ (add2sbuf_strconst buffer "(")
+ (add_parameters_to_buffer parameters buffer)
+ (add2sbuf_strconst buffer ")")))
+
+(install_method class_c_generator_header add_to_buffer add_header_to_buffer)
+
+(defun add_block_to_buffer (block_s buffer)
+ (let ((id (get_field :block_id block_s))
+ (successors (get_field :block_successors block_s))
+ (successor_id (get_field :block_id_successor block_s))
+ (instructions (get_field :block_instructions block_s))
+ (count (make_integerbox discr_integer 0)))
+ (add2sbuf_strconst buffer "melt_label_")
+ (add2sbuf_longdec buffer (get_int id))
+ (add2sbuf_strconst buffer ":")
+ (foreach_in_list
+ (instructions)
+ (pair current_element)
+ (add2sbuf_string buffer (add_to_buffer current_element buffer))
+ (put_int count (+i 1 (get_int count))))
+ (if (==i 0 (get_int count))
+ (progn
+ (add2sbuf_strconst buffer "goto melt_label_")
+ (add2sbuf_longdec buffer (get_int successor_id))
+ (add2sbuf_strconst buffer ";")))))
+
+(install_method class_c_generator_block add_to_buffer add_block_to_buffer)
+
+(defun add_variable_declaration_to_buffer (declaration buffer)
+ (let ((type (get_field :element_type declaration))
+ (name (get_field :element_name declaration)))
+ (add2sbuf_string buffer type)
+ (add2sbuf_strconst buffer " ")
+ (add2sbuf_string buffer name)
+ (add2sbuf_strconst buffer ";")))
+
+(install_method class_c_generator_declaration add_to_buffer add_variable_declaration_to_buffer)
+
+(defun add_assignment_to_buffer (assignment buffer)
+ (let ((lvalue (get_field :assignment_lvalue assignment))
+ (operand1 (get_field :expression_operand1 assignment))
+ (operand2 (get_field :expression_operand2 assignment))
+ (operator (get_field :expression_operator assignment)))
+ (add2sbuf_string buffer lvalue)
+ (add2sbuf_strconst buffer "=")
+ (add2sbuf_string buffer operand1)
+ (add2sbuf_string buffer operator)
+ (add2sbuf_string buffer operand2)
+ (add2sbuf_strconst buffer ";")))
+
+(install_method class_c_generator_assignment add_to_buffer add_assignment_to_buffer)
+
+(defun add_condition_to_buffer (condition buffer)
+ (let ((left (get_field :expression_operand1 condition))
+ (right (get_field :expression_operand2 condition))
+ (operator (get_field :expression_operator condition))
+ (true_branch (get_field :condition_iftrue condition))
+ (false_branch (get_field :condition_iffalse condition)))
+ (add2sbuf_strconst buffer "if(")
+ (add2sbuf_string buffer left)
+ (add2sbuf_string buffer operator)
+ (add2sbuf_string buffer right)
+ (add2sbuf_strconst buffer "){")
+ (add2sbuf_strconst buffer "goto ")
+ (add2sbuf_string buffer true_branch)
+ (add2sbuf_strconst buffer";}else{goto ")
+ (add2sbuf_string buffer false_branch)
+ (add2sbuf_strconst buffer ";}")))
+
+(install_method class_c_generator_condition add_to_buffer add_condition_to_buffer)
+
+(defun add_return_to_buffer (return_i buffer)
+ (let ((value (get_field :return_value return_i)))
+ (add2sbuf_strconst buffer "return ")
+ (add2sbuf_string buffer value)
+ (add2sbuf_strconst buffer ";")))
+
+(install_method class_c_generator_return add_to_buffer add_return_to_buffer)
+
+(defun add_call_parameters_to_buffer (parameters buffer)
+ (let ((count (make_integerbox discr_integer 0)))
+ (foreach_in_list
+ (parameters)
+ (pair current_node)
+ (let ((type (get_field :element_type current_node))
+ (name (get_field :element_name current_node)))
+ (if (>i (get_int count) 0)
+ (add2sbuf_strconst buffer ","))
+ (add2sbuf_string buffer name)
+ (put_int count (+i 1 (get_int count)))))))
+
+(defun add_call_to_buffer (call buffer)
+ (let ((lvalue (get_field :call_lvalue call))
+ (type (get_field :element_type call))
+ (name (get_field :element_name call))
+ (parameters (get_field :call_parameters call)))
+ (if lvalue
+ (progn
+ (add2sbuf_string buffer lvalue)
+ (add2sbuf_strconst buffer "=")))
+ (add2sbuf_string buffer name)
+ (add2sbuf_strconst buffer "(")
+ (add_call_parameters_to_buffer parameters buffer)
+ (add2sbuf_strconst buffer ");")))
+
+(install_method class_c_generator_call add_to_buffer add_call_to_buffer)
+
+; Build tree
+
+; Following functions get informations from tree and gimple structures.
+; They copy useful content in new MELT structures. The main technique
+; used here is the pattern matching.
+;
+
+
+(defun get_function_type (function :tree header)
+ (match header
+ (?(tree_function_type ?(tree_void_type
+ ?(tree_type_declaration
+ ?(tree_identifier ?name))))
+ (make_stringconst discr_string name))
+ (?(tree_function_type ?(tree_integer_type
+ ?(tree_type_declaration
+ ?(tree_identifier ?name)) ?_ ?_ ?_))
+ (make_stringconst discr_string name))
+ (?(tree_function_type ?(tree_real_type
+ ?(tree_type_declaration
+ ?(tree_identifier ?name)) ?_))
+ (make_stringconst discr_string name))
+ (?_ )))
+
+(defun get_function_name (function :tree header)
+ (match header
+ (?(tree_function_decl ?name ?_)
+ (make_stringconst discr_string name))
+ (?_)))
+
+(defun build_pointer_parameter (parameter buffer :tree type)
+ (match type
+ (?(tree_pointer_type_p ?sub_type)
+ (add2sbuf_strconst buffer "*")
+ (build_pointer_parameter parameter buffer sub_type))
+ (?(tree_integer_type
+ ?(tree_type_declaration
+ ?(tree_identifier ?type_name)) ?_ ?_ ?_)
+ (let ((type_buffer (make_strbuf discr_strbuf)))
+ (add2sbuf_strconst type_buffer type_name)
+ (add2sbuf_sbuf type_buffer buffer)
+ (add2sbuf_strconst type_buffer " ")
+ (put_fields parameter :element_type (strbuf2string discr_string type_buffer))))
+ (?(tree_real_type
+ ?(tree_type_declaration
+ ?(tree_identifier ?type_name)) ?_)
+ (let ((type_buffer (make_strbuf discr_strbuf)))
+ (add2sbuf_strconst type_buffer type_name)
+ (add2sbuf_sbuf type_buffer buffer)
+ (add2sbuf_strconst type_buffer " ")
+ (put_fields parameter :element_type (strbuf2string discr_string type_buffer))))))
+
+(defun build_parameter (function :tree type :cstring name)
+ (let ((parameter (instance class_c_generator_typed_element
+ :element_type ()
+ :element_name ())))
+ (match type
+ (?(tree_integer_type
+ ?(tree_type_declaration
+ ?(tree_identifier ?type_name)) ?_ ?_ ?_)
+ (put_fields parameter :element_type (make_stringconst discr_string type_name)))
+ (?(tree_real_type
+ ?(tree_type_declaration
+ ?(tree_identifier ?type_name)) ?_)
+ (put_fields parameter :element_type (make_stringconst discr_string type_name)))
+ (?(tree_pointer_type_p ?_)
+ (let ((buffer (make_strbuf discr_strbuf)))
+ (build_pointer_parameter parameter buffer type)))
+ (?(tree_record_type
+ ?(tree_type_declaration
+ ?(tree_identifier ?type_name)))
+ (put_fields parameter :element_type (make_stringconst discr_string type_name)))
+ (?_ (debugtree "Type : " type)))
+ (put_fields parameter :element_name (make_stringconst discr_string name))
+ (return parameter)))
+
+(defun get_function_parameters (function :tree header)
+ (let ((parameters (list)))
+ (each_param_in_fundecl
+ (header)
+ (:tree parameter)
+ (match parameter
+ (?(tree_parm_decl ?type ?_ ?name)
+ (let ((boxed_parameter (build_parameter function type name)))
+ (list_append parameters boxed_parameter)))
+ (?_ )))
+ (return parameters)))
+
+(defun build_header (datas function :tree header)
+ (let ((type (get_function_type function (tree_type header)))
+ (name (get_function_name function header))
+ (parameters (get_function_parameters function header)))
+ (instance class_c_generator_header
+ :element_type type
+ :element_name name
+ :header_parameters parameters)))
+
+(defun traverse_function_header (datas function sets :tree header)
+ (let ((header_set (get_field :sets_header sets))
+ (m (maptree_get header_set header)))
+ (if m
+ ()
+ (progn
+ (maptree_put header_set header '1)
+ (put_fields function :function_header (build_header datas function header))))))
+
+; Getting type of a tree required a recursion for some case. For
+; example, when you get a pointer to int, you have to know this
+; is a pointer and which is pointed type.
+
+(defun get_tree_type_rec (buffer accumulator :tree type)
+ (match type
+ (?(tree_integer_type
+ ?(tree_type_declaration
+ ?(tree_identifier ?name)) ?_ ?_ ?_)
+ (add2sbuf_strconst buffer name)
+ (add2sbuf_strconst buffer " ")
+ (add2sbuf_sbuf buffer accumulator))
+ (?(tree_real_type
+ ?(tree_type_declaration
+ ?(tree_identifier ?name)) ?_)
+ (add2sbuf_strconst buffer name)
+ (add2sbuf_strconst buffer " ")
+ (add2sbuf_sbuf buffer accumulator))
+ (?(tree_pointer_type_p ?sub_type)
+ (add2sbuf_strconst accumulator "*")
+ (get_tree_type_rec buffer accumulator sub_type))
+ (?(tree_record_type
+ ?(tree_identifier ?name))
+ (add2sbuf_strconst buffer "struct ")
+ (add2sbuf_strconst buffer name)
+ (debug_msg buffer "Debug msg : ")
+ (add2sbuf_sbuf buffer accumulator))
+ (?_ )))
+
+(defun get_tree_type (value :tree type)
+ (let ((buffer (make_strbuf discr_strbuf))
+ (accumulator (make_strbuf discr_strbuf)))
+ (get_tree_type_rec buffer accumulator type)
+ (strbuf2string discr_string buffer)))
+
+
+(defun handle_variables_declaration (function sets
+ :tree decl type
+ :cstring name
+ :long uid)
+ (let ((m (maptree_get (get_field :sets_variables sets) decl))
+ (buffer (make_strbuf discr_strbuf)))
+ (if m
+ ()
+ (let ((declaration (instance class_c_generator_declaration
+ :element_type (get_tree_type '1 type)
+ :element_name ())))
+ (if name
+ (add2sbuf_strconst buffer name)
+ (progn
+ (add2sbuf_strconst buffer "melt_tmp_")
+ (add2sbuf_longdec buffer uid)))
+ (put_fields declaration :element_name (strbuf2string discr_string buffer))
+ (maptree_put (get_field :sets_variables sets) decl '1)
+ (list_append (get_field :function_local_variables function) declaration)))))
+
+; TODO !
+;
+; We need to add the structure object to the list of structure declarations.
+
+(defun handle_structure_declaration (datas function sets :tree value type arg0 arg1)
+ (let ((m (maptree_get (get_field :sets_structures sets) type)))
+ (if m
+ ()
+ (let ((structures (get_field :structures_declarations datas))
+ (structure (instance class_c_generator_structure
+ :element_type (get_tree_type '1 type)
+ :element_name ()
+ :structure_fields (list))))
+ (foreach_field_in_record_type
+ (arg1)
+ (:tree current_field)
+ (let ((field (instance class_c_generator_field
+ :element_type (get_tree_type '1 current_field)
+ :element_name ()))
+ (tmp (get_field :element_type field)))
+ (list_append (get_field :structure_fields structure) field)))
+ (maptree_put (get_field :sets_structures sets) value '1)
+ (list_append (get_field :structures_declarations datas) structure)))))
+
+; For the same reason that pointer type, we need a recursive examination of
+; value. When you have a record type, you need to have an access to a field.
+
+(defun get_tree_value_rec (datas function sets buffer :tree value)
+ (match value
+ (?(tree_var_decl ?type ?name ?uid)
+ (handle_variables_declaration function sets value type name uid)
+ (if name
+ (add2sbuf_strconst buffer name)
+ (progn
+ (add2sbuf_strconst buffer "melt_tmp_")
+ (add2sbuf_longdec buffer uid))))
+ (?(tree_parm_decl ?_ ?_ ?name)
+ (add2sbuf_strconst buffer name))
+ (?(tree_integer_cst ?integer)
+ (add2sbuf_longdec buffer integer))
+ (?(tree_indirect_reference ?_ ?reference)
+ (add2sbuf_strconst buffer "*")
+ (get_tree_value_rec function sets buffer reference))
+ (?(tree_address_expression ?_ ?expression)
+ (add2sbuf_strconst buffer "&")
+ (get_tree_value_rec function sets buffer expression))
+ (?(tree_component_ref ?type ?arg0 ?arg1)
+ (match type
+ (?(tree_record_type ?_)
+ (handle_structure_declaration datas function sets value type arg0 arg1))
+ (?_ ))
+ (get_tree_value_rec datas function sets buffer arg0)
+ (add2sbuf_strconst buffer ".")
+ (get_tree_value_rec datas function sets buffer arg1))
+ (?(tree_field_declaration ?(tree_identifier ?name))
+ (add2sbuf_strconst buffer name))
+ (?_
+ (debugtree "Unknown tree : " value))))
+
+(defun get_tree_value (datas function sets :tree value)
+ (let ((buffer (make_strbuf discr_strbuf)))
+ (get_tree_value_rec datas function sets buffer value)
+ (strbuf2string discr_string buffer)))
+
+(defun get_edge_value (melt_value :edge edge)
+ (let ((buffer (make_strbuf discr_strbuf)))
+ (add2sbuf_strconst buffer "melt_label_")
+ (add2sbuf_longdec buffer (basic_block_index (edge_dest_bb edge)))
+ (return (strbuf2string discr_string buffer))))
+
+(defun get_gimple_call_parameters (function :gimple instruction)
+ (let ((parameters (list)))
+ (foreach_argument_of_gimple_call
+ (instruction)
+ (:tree argument)
+ (match argument
+ (?(tree_parm_decl ?type ?_ ?name)
+ (let ((boxed_parameter (build_parameter function type name)))
+ (list_append parameters boxed_parameter)))
+ (?_ )))
+ (return parameters)))
+
+(defun fill_instruction_gimple_call (datas function sets call
+ :tree left declaration
+ :gimple instruction)
+ (let ((lvalue (get_tree_value datas function sets left))
+ (type (get_function_type function (tree_type declaration)))
+ (name (get_function_name function declaration)))
+ (put_fields call :call_lvalue lvalue
+ :element_type type
+ :element_name name
+ :call_parameters (get_gimple_call_parameters function instruction))))
+
+(defun build_instruction_gimple_call (datas function sets :gimple instruction)
+ (let ((build (instance class_c_generator_call
+ :call_lvalue ()
+ :element_type ()
+ :element_name ()
+ :call_parameters ())))
+ (match instruction
+ (?(gimple_call ?left ?declaration ?_)
+ (fill_instruction_gimple_call datas function sets build left declaration instruction))
+ (?_ ))
+ (return build)))
+
+(defun build_instruction_goto (datas function sets :gimple instruction)
+ (let ((build (instance class_c_generator_goto
+ :goto_value ())))
+ (match instruction
+ (?(gimple_goto ?label)
+ (debugtree "Label : " label))
+ (?_ ))))
+
+(defun fill_instruction_assignment (datas function sets assignment
+ :tree left right1 right2
+ :cstring operator)
+ (let ((operand1 (get_tree_value datas function sets right1))
+ (operand2 (get_tree_value datas function sets right2)))
+ (put_fields assignment :assignment_lvalue (get_tree_value datas function sets left)
+ :expression_operand1 operand1
+ :expression_operator (make_stringconst discr_string operator)
+ :expression_operand2 operand2)))
+
+(defun build_instruction_assignment (datas function sets :gimple instruction)
+ (let ((build (instance class_c_generator_assignment
+ :assignment_lvalue ()
+ :expression_operand1 ()
+ :expression_operator ()
+ :expression_operand2 ())))
+ (match instruction
+ (?(gimple_assign_unary_minus ?left ?right)
+ (fill_instruction_assignment function sets build left (null_tree) right "-"))
+ (?(gimple_assign_single ?left ?right)
+ (debugtree "Right : " right)
+ (fill_instruction_assignment datas function sets build left right))
+ (?(gimple_assign_plus ?left ?right1 ?right2)
+ (fill_instruction_assignment datas function sets build left right1 right2 "+"))
+ (?(gimple_assign_minus ?left ?right1 ?right2)
+ (fill_instruction_assignment datas function sets build left right1 right2 "-"))
+ (?(gimple_assign_mult ?left ?right1 ?right2)
+ (fill_instruction_assignment datas function sets build left right1 right2 "*"))
+ (?(gimple_assign_trunc_div ?left ?right1 ?right2)
+ (fill_instruction_assignment datas function sets build left right1 right2 "/"))
+ (?(gimple_assign_ceil_div ?left ?right1 ?right2)
+ (fill_instruction_assignment datas function sets build left right1 right2 "/"))
+ (?(gimple_assign_floor_div ?left ?right1 ?right2)
+ (fill_instruction_assignment datas function sets build left right1 right2 "/"))
+ (?(gimple_assign_round_div ?left ?right1 ?right2)
+ (fill_instruction_assignment datas function sets build left right1 right2 "/"))
+ (?(gimple_assign_rdiv ?left ?right1 ?right2)
+ (fill_instruction_assignment datas function sets build left right1 right2 "/"))
+ (?(gimple_assign_exact_div ?left ?right1 ?right2)
+ (fill_instruction_assignment datas function sets build left right1 right2 "/"))
+ (?(gimple_assign_trunc_mod ?left ?right1 ?right2)
+ (fill_instruction_assignment datas function sets build left right1 right2 "%"))
+ (?(gimple_assign_ceil_mod ?left ?right1 ?right2)
+ (fill_instruction_assignment datas function sets build left right1 right2 "%"))
+ (?(gimple_assign_floor_mod ?left ?right1 ?right2)
+ (fill_instruction_assignment datas function sets build left right1 right2 "%"))
+ (?(gimple_assign_round_mod ?left ?right1 ?right2)
+ (fill_instruction_assignment datas function sets build left right1 right2 "%"))
+ (?_ ))
+ (return build)))
+
+(defun fill_instruction_condition (datas function sets condition
+ :tree lhs rhs
+ :edge iftrue iffalse
+ :cstring op)
+ (put_fields condition :expression_operand1 (get_tree_value datas function sets lhs)
+ :expression_operator (make_stringconst discr_string op)
+ :expression_operand2 (get_tree_value datas function sets rhs)
+ :condition_iftrue (get_edge_value '1 iftrue)
+ :condition_iffalse (get_edge_value '1 iffalse)))
+
+(defun build_instruction_condition (datas function sets :gimple instruction)
+ (let ((build (instance class_c_generator_condition
+ :expression_operand1 ()
+ :expression_operator ()
+ :expression_operand2 ()
+ :condition_iftrue ()
+ :condition_iffalse ())))
+ (match instruction
+ (?(and ?(gimple_cond_less ?lhs ?rhs)
+ ?(gimple_cond_with_edges ?iftrue ?iffalse))
+ (fill_instruction_condition datas function sets build lhs rhs iftrue iffalse "<"))
+ (?(and ?(gimple_cond_lessequal ?lhs ?rhs)
+ ?(gimple_cond_with_edges ?iftrue ?iffalse))
+ (fill_instruction_condition datas function sets build lhs rhs iftrue iffalse "<="))
+ (?(and ?(gimple_cond_notequal ?lhs ?rhs)
+ ?(gimple_cond_with_edges ?iftrue ?iffalse))
+ (fill_instruction_condition datas function sets build lhs rhs iftrue iffalse "!="))
+ (?(and ?(gimple_cond_equal ?lhs ?rhs)
+ ?(gimple_cond_with_edges ?iftrue ?iffalse))
+ (fill_instruction_condition datas function sets build lhs rhs iftrue iffalse "=="))
+ (?(and ?(gimple_cond_greater ?lhs ?rhs)
+ ?(gimple_cond_with_edges ?iftrue ?iffalse))
+ (fill_instruction_condition datas function sets build lhs rhs iftrue iffalse ">"))
+ (?(and ?(gimple_cond_greater_or_equal ?lhs ?rhs)
+ ?(gimple_cond_with_edges ?iftrue ?iffalse))
+ (fill_instruction_condition datas function sets build lhs rhs iftrue iffalse ">="))
+ (?_ ))
+ (return build)))
+
+(defun fill_instruction_return (datas function sets return_i :tree value)
+ (put_fields return_i :return_value (get_tree_value datas function sets value)))
+
+(defun build_instruction_return (datas function sets :gimple instruction)
+ (let ((build (instance class_c_generator_return
+ :return_value ())))
+ (match instruction
+ (?(gimple_return ?value)
+ (fill_instruction_return datas function sets build value))
+ (?_ ))
+ (return build)))
+
+(defun build_instruction (datas function sets :gimple instruction)
+ (cond ((is_gimple_call instruction)
+ (build_instruction_gimple_call datas function sets instruction))
+ ((is_gimple_assign instruction)
+ (build_instruction_assignment datas function sets instruction))
+ ((is_gimple_cond instruction)
+ (build_instruction_condition datas function sets instruction))
+ ((is_gimple_return instruction)
+ (build_instruction_return datas function sets instruction))
+ ((is_gimple_goto instruction)
+ (build_instruction_goto datas function sets instruction))))
+
+(defun traverse_function_body (datas function sets :basic_block body)
+ (let ((successor (basicblock_single_succ body))
+ (successor_index (make_integerbox discr_integer (basic_block_index successor)))
+ (function_block (instance class_c_generator_block
+ :block_id (make_integerbox discr_integer (basic_block_index body))
+ :block_successors (make_integerbox discr_integer (basicblock_nb_succ body))
+ :block_id_successor successor_index
+ :block_instructions (list)))
+ (instructions_list (get_field :block_instructions function_block))
+ (:gimple_seq instructions (gimple_seq_of_basic_block body)))
+ (each_in_gimpleseq
+ (instructions)
+ (:gimple instruction)
+ (list_append instructions_list (build_instruction datas function sets instruction)))
+ (list_append (get_field :function_blocks function) function_block)))
+
+(defun traverse_function (datas function sets :tree header :basic_block body)
+ (progn
+ (traverse_function_header datas function sets header)
+ (traverse_function_body datas function sets body)))
+
+; This is the main function, it allows us to traverse all basic blocks which
+; composed the source program.
+
+(defun traverse (datas)
+ (let ((header_set (make_maptree discr_map_trees 100))
+ (variables_set (make_maptree discr_map_trees 100))
+ (labels_set (make_mapbasicblock discr_map_basic_blocks 100))
+ (structures_set (make_maptree discr_map_trees 100))
+ (function (instance class_c_generator_function
+ :function_header ()
+ :function_local_variables (list)
+ :function_blocks (list)))
+ (sets (instance class_c_generator_sets
+ :sets_header header_set
+ :sets_variables variables_set
+ :sets_labels labels_set
+ :sets_structures structures_set))
+ (structures (get_field :structures_declarations datas)))
+ (each_bb_cfun
+ ()
+ (:basic_block body :tree header)
+ (traverse_function datas function sets header body))
+ (list_append (get_field :functions_root (get_field :gccpass_data datas)) function)))
+
+(defun generator_gate (value)
+ value)
+
+(defun generator_exec (datas)
+ (traverse datas))
+
+; Here we use a hook because the pass is called once on each function, so we need
+; to collect datas for building a tree representation. But to start traverseing the
+; tree and make treatments, we need a function called at the end of the pass. This
+; function is at_finish_unit_last.
+
+(defun generator_run (cmd datas)
+ (let ((generator (instance class_gcc_gimple_pass
+ :named_name '"melt_generator_pass"
+ :gccpass_gate generator_gate
+ :gccpass_exec generator_exec
+ :gccpass_data (instance class_c_generator_functions
+ :functions_root (list)
+ :structures_declarations (list))
+ :gccpass_properties_required ())))
+ (install_melt_gcc_pass generator "after" "cfg" 0)
+ (at_finish_unit_last
+ (lambda ()
+ (let ((root (get_field :gccpass_data generator))
+ (structures (get_field :structures_declarations root))
+ (buffer (make_strbuf discr_strbuf)))
+ (add_structures_declarations_to_buffer structures buffer)
+ (add_prototype_to_buffer root buffer)
+ (add_to_buffer root buffer)
+ (output_sbuf_strconst buffer "./generated_file"))))
+ (return generator)))
+
+(definstance generator_mode class_melt_mode
+ :named_name '"generator"
+ :meltmode_help '"MELT C generator"
+ :meltmode_fun generator_run)
+(install_melt_mode generator_mode)
+