[PATCH 06/27] arc: semfunc.c tcg code generator.
cupertinomiranda at gmail.com
cupertinomiranda at gmail.com
Mon Apr 5 15:31:17 BST 2021
From: Cupertino Miranda <cmiranda at synopsys.com>
TCG generator scripts for semfunc.c file.
Signed-off-by: Cupertino Miranda <cmiranda at synopsys.com>
---
target/arc/semfunc_generator/Gemfile | 3 +
target/arc/semfunc_generator/README | 35 ++
.../classes/CreateInternalVars.rb | 117 ++++
.../classes/DecomposeExpressions.rb | 45 ++
.../classes/IdentifyQEmuStaticInferedParts.rb | 91 +++
.../semfunc_generator/classes/QEmuCompiler.rb | 15 +
.../classes/QEmuTranslator.rb | 269 +++++++++
.../classes/SemanticFunctionAST.rb | 466 +++++++++++++++
.../classes/SpaghettiCodePass.rb | 55 ++
.../classes/SpaghettiCodePass1.rb | 66 +++
.../semfunc_generator/classes/UnfoldCode.rb | 305 ++++++++++
target/arc/semfunc_generator/init.rb | 15 +
.../arc/semfunc_generator/modules/Compiler.rb | 42 ++
.../modules/ConstantTables.rb | 57 ++
target/arc/semfunc_generator/modules/Pass.rb | 11 +
.../SemanticFunctionASTBlockOperators.rb | 145 +++++
.../modules/SemanticFunctionASTFactory.rb | 55 ++
.../semfunc_generator/modules/Translator.rb | 102 ++++
.../modules/TranslatorAST.rb | 80 +++
.../modules/TranslatorFinal.rb | 103 ++++
.../parsers/SemanticFunctionParser.tab.rb | 553 ++++++++++++++++++
.../parsers/SemanticFunctionParser.y | 126 ++++
.../semfunc_generator/regenerate_semfunc.rb | 245 ++++++++
23 files changed, 3001 insertions(+)
create mode 100644 target/arc/semfunc_generator/Gemfile
create mode 100644 target/arc/semfunc_generator/README
create mode 100644 target/arc/semfunc_generator/classes/CreateInternalVars.rb
create mode 100644 target/arc/semfunc_generator/classes/DecomposeExpressions.rb
create mode 100644 target/arc/semfunc_generator/classes/IdentifyQEmuStaticInferedParts.rb
create mode 100644 target/arc/semfunc_generator/classes/QEmuCompiler.rb
create mode 100644 target/arc/semfunc_generator/classes/QEmuTranslator.rb
create mode 100644 target/arc/semfunc_generator/classes/SemanticFunctionAST.rb
create mode 100644 target/arc/semfunc_generator/classes/SpaghettiCodePass.rb
create mode 100644 target/arc/semfunc_generator/classes/SpaghettiCodePass1.rb
create mode 100644 target/arc/semfunc_generator/classes/UnfoldCode.rb
create mode 100644 target/arc/semfunc_generator/init.rb
create mode 100644 target/arc/semfunc_generator/modules/Compiler.rb
create mode 100644 target/arc/semfunc_generator/modules/ConstantTables.rb
create mode 100644 target/arc/semfunc_generator/modules/Pass.rb
create mode 100644 target/arc/semfunc_generator/modules/SemanticFunctionASTBlockOperators.rb
create mode 100644 target/arc/semfunc_generator/modules/SemanticFunctionASTFactory.rb
create mode 100644 target/arc/semfunc_generator/modules/Translator.rb
create mode 100644 target/arc/semfunc_generator/modules/TranslatorAST.rb
create mode 100644 target/arc/semfunc_generator/modules/TranslatorFinal.rb
create mode 100644 target/arc/semfunc_generator/parsers/SemanticFunctionParser.tab.rb
create mode 100644 target/arc/semfunc_generator/parsers/SemanticFunctionParser.y
create mode 100644 target/arc/semfunc_generator/regenerate_semfunc.rb
diff --git a/target/arc/semfunc_generator/Gemfile b/target/arc/semfunc_generator/Gemfile
new file mode 100644
index 0000000000..ad695b4d11
--- /dev/null
+++ b/target/arc/semfunc_generator/Gemfile
@@ -0,0 +1,3 @@
+source 'http://rubygems.org'
+
+gem 'racc'
diff --git a/target/arc/semfunc_generator/README b/target/arc/semfunc_generator/README
new file mode 100644
index 0000000000..965e79b894
--- /dev/null
+++ b/target/arc/semfunc_generator/README
@@ -0,0 +1,35 @@
+Helper file for ARC instruction traslation functions.
+
+The code generator was implemented using ruby language.
+In order to change the content of semfunc.c file these scripts should be used.
+
+Ruby instalation process:
+
+The recommended way to obtain a compatible ruby is to install it in a user
+local directory using RVM.
+Instructions to install RVM can be found in https://rvm.io/.
+
+Using RVM one can install Ruby interpreter executing the following
+steps/commands.
+
+Install Ruby version 2.6:
+ # rvm install ruby-2.6
+Set ruby version 2.6 as current in use.
+ # rvm use 2.6
+Create an isolated environment for the required ruby dependencies.
+ # rvm gemset create arc_generator
+Install bundler tool
+ # gem install bundler
+Bundle tool reads the Gemfile file and installs project dependencies.
+ # cd ${QEMU_SOURCE}/target/arc/semfunc_generator & bundle install
+
+
+In order to regenerate the semfunc.c file, please execute the following command.
+ # ruby regenerate_semfunc.rb > ../semfunc.c
+
+By default the tool reads the semfunc.c file and prints the new content for
+the same file.
+The information of what is generated is presented as comment in the file.
+In order to change the functionality of those functions one should change the
+"pseudo code" in the comments, which is what is used to generate the
+semantically similar TCG code.
diff --git a/target/arc/semfunc_generator/classes/CreateInternalVars.rb b/target/arc/semfunc_generator/classes/CreateInternalVars.rb
new file mode 100644
index 0000000000..05b2eac7ab
--- /dev/null
+++ b/target/arc/semfunc_generator/classes/CreateInternalVars.rb
@@ -0,0 +1,117 @@
+class CreateInternalVars
+ private
+
+ # extend SemanticFunctionASTFactory
+ include Pass
+ include ConstantTables
+ extend TranslatorAST
+
+
+
+ def self.translation_rules
+ ret = {}
+
+ create_var = Proc.new { |stmt, repl, mappings, to_do|
+
+ var = stmt.object[:lhs]
+ rhs = stmt.object[:rhs]
+ if(@@vars[var.object[:name]].nil? && var.object[:name] !~ /@.+/)
+ # puts "VAR = #{var.object[:name]}"
+ if(var.hasAttr?(:static))
+ defVar = SemanticFunctionAST.function("defStaticVariable", stmt.getAttr(:static), stmt.object[:lhs])
+ else
+ #puts "NAME = #{rhs.object.inspect}"
+ #puts "L = #{LIST_OF_FUNCTIONS.index(rhs.object[:name])}"
+
+
+ defVar = SemanticFunctionAST.function("defVariable", stmt.object[:lhs])
+ #if(rhs.object[:type] == :func && !TEMP_CREATING_FUNCTIONS.index(rhs.object[:name]).nil?)
+ # #puts " IN HERE"
+ # stmt.object[:lhs].setAttr(:reference, true)
+ # defVar = SemanticFunctionAST.function("defReference", stmt.object[:lhs])
+ #else
+ # defVar = SemanticFunctionAST.function("defVariable", stmt.object[:lhs])
+
+
+
+ #end
+ end
+ # to_do[:pre_pend].push(defVar)
+ @@vars[var.object[:name]] = defVar
+ # @@vars1[var.object[:name]] = {
+ # defVar: defVar,
+ # stmt: stmt,
+ # block: stmt.find_parent_node_with_type(:block)
+ # }
+ # elsif(@@vars[var.object[:name]].nil? && var.object[:name] =~ /@.+/)
+ end
+ }
+
+ match = SemanticFunctionAST.new(type: :assign,
+ lhs: SemanticFunctionAST.var("a"),
+ rhs: SemanticFunctionAST.var("_"))
+ ret[match] = create_var
+
+ match = Proc.new { |ast|
+ ret = { result: false, mappings: {} }
+ ret = { result: true, mappings: {} } if(ast.object[:type] == :if)
+ ret
+ }
+ ret[match] = Proc.new { |stmt_ast, repl, mappings, to_do|
+ generate(stmt_ast.object[:then])
+ generate(stmt_ast.object[:else])
+ nil
+ }
+
+ return ret
+ end
+
+
+ public
+ def self.task(ast)
+ @@vars = {}
+ # @@vars1 = {}
+ self.generate(ast)
+ # puts "AST = #{ast.class}"
+ # puts ast.debug
+
+ # NOTE: Add free variables to end of semfunc.
+ new_stmt_list = SemanticFunctionAST.createStmtListFromArray(@@vars.values)
+ new_stmt_list.append_in_stmt_list(ast)
+ ast = new_stmt_list
+
+ list = []
+ @@vars.each_pair do |var_name, func|
+
+ # puts "VAR: #{var_name}"
+ # puts "STMT: #{@@vars1[var_name][:stmt]}"
+ # puts "BLOCK:\n#{@@vars1[var_name][:block].class}"
+
+ # list.push(var_name) if func.object[:type] == :func &&
+ # (func.object[:name] == "defVariable" ||
+ # func.object[:name] == "defReference")
+
+ if(func.object[:type] == :func)
+ if(func.object[:name] == "defVariable")
+ list.push(SemanticFunctionAST.function("freeVariable", SemanticFunctionAST.var(var_name)))
+ elsif(func.object[:name] == "defReference")
+ list.push(SemanticFunctionAST.function("freeReference", SemanticFunctionAST.var(var_name)))
+ end
+ end
+ end
+ # list = list.map do |var_name|
+ # SemanticFunctionAST.function("freeVariable", SemanticFunctionAST.var(var_name))
+ # end
+ stmt_list = SemanticFunctionAST.createStmtListFromArray(list)
+ ast.append_in_stmt_list(stmt_list)
+
+ # @@vars.each_pair do |k, v|
+ # puts "FREE: #{k} : #{v.pp}"
+ # ast.prepend_in_stmt_list(SemanticFunctionAST.function("freeVariable", SemanticFunctionAST.createVar(k)))
+ # end
+
+ # puts ast.pp
+
+ return ast
+ end
+end
diff --git a/target/arc/semfunc_generator/classes/DecomposeExpressions.rb b/target/arc/semfunc_generator/classes/DecomposeExpressions.rb
new file mode 100644
index 0000000000..c353cc90bb
--- /dev/null
+++ b/target/arc/semfunc_generator/classes/DecomposeExpressions.rb
@@ -0,0 +1,45 @@
+class DecomposeExpressions
+ private
+
+ extend SemanticFunctionASTFactory
+ include Pass
+
+ def self.traverse(ast)
+ end
+
+ def self.expandConditions(ast)
+ object = ast.object
+ case(object[:type])
+ when :var
+ else
+ return ast
+ end
+ return ret
+ end
+
+ public
+ def self.task(ast)
+ # reset_counters
+ tmp_vars_for_nodes = {}
+ current_stmt = nil
+
+ ast.traverse_LR_TB() do |ast, to_do|
+ object = ast.object
+ case(object[:type])
+ when :func
+ if(object[:name] == "IF")
+ to_do[:pre_pend] += ast.object[:args][0].create_stmts_for_expression()
+
+ var = to_do[:pre_pend][-1].object[:lhs]
+
+ ast.object[:args][0] = SemanticFunctionAST.new(type: :bincond, name: "==", lhs: var, rhs: createVar("true"))
+ end
+ else
+
+ end
+ true
+ end
+
+ return ast
+ end
+end
diff --git a/target/arc/semfunc_generator/classes/IdentifyQEmuStaticInferedParts.rb b/target/arc/semfunc_generator/classes/IdentifyQEmuStaticInferedParts.rb
new file mode 100644
index 0000000000..536f9fdd49
--- /dev/null
+++ b/target/arc/semfunc_generator/classes/IdentifyQEmuStaticInferedParts.rb
@@ -0,0 +1,91 @@
+class IdentifyQEmuStaticInferedParts
+ private
+
+ # extend SemanticFunctionASTFactory
+ include Pass
+ extend Translator
+
+ public
+
+ rules = {}
+ def self.translation_rules
+ ret = {}
+ functions = {
+ "shouldExecuteDelaySlot" => "bool",
+ "getAAFlag" => "int",
+ "getZZFlag" => "int",
+ "getFFlag" => "int",
+ "getFlagX" => "bool",
+ "nextReg" => "TCGvPtr",
+ "instructionHasRegisterOperandIn" => "bool",
+ "targetHasOption" => "bool",
+ "Ext64" => "TCGv_i64",
+ "SignExt64" => "TCGv_i64",
+ "SignExtend" => "TCGv",
+ "getNFlag" => "TCGv",
+ "Zero" => "TCGv",
+ }.each_pair do |name, type|
+ ret[SemanticFunctionAST.function(name)] = SemanticFunctionAST.var(type)
+ end
+ # ret[SemanticFunctionAST.function("shouldExecuteDelaySlot")] = SemanticFunctionAST.var("bool")
+ # ret[SemanticFunctionAST.function("getAAFlag")] = SemanticFunctionAST.var("int")
+ # ret[SemanticFunctionAST.function("getZZFlag")] = SemanticFunctionAST.var("int")
+ return ret;
+ end
+ def self.task(ast)
+ static_variables = {}
+
+ ast.traverse_LR_BT do |ast|
+
+ rules = {
+ }
+
+ match = self.find_matching_rule(ast)
+ if(match)
+ if(match[:replacement])
+ ast.setAttr(:static, match[:replacement])
+ end
+ else
+ case(ast.object[:type])
+ when :var
+ name = ast.object[:name]
+ ast.setAttr(:static, static_variables[name]) if static_variables[name] != nil && ast.object[:name] !~ /@.+/
+ when :assign
+ name = ast.object[:lhs].object[:name]
+ if(ast.object[:rhs].hasAttr?(:static))
+ ast.object[:lhs].setAttr(:static, ast.object[:rhs].getAttr(:static))
+ ast.setAttr(:static, ast.object[:rhs].getAttr(:static))
+ static_variables[name] = ast.object[:rhs].getAttr(:static) if static_variables[name].nil?
+ end
+ when :if
+ ast.setAttr(:static, ast.object[:cond].getAttr(:static)) if(ast.object[:cond].hasAttr?(:static))
+ when :unicond
+ ast.setAttr(:static, ast.object[:rhs].getAttr(:static)) if(ast.object[:rhs].hasAttr?(:static))
+ when :bincond
+ if(ast.object[:lhs].hasAttr?(:static) && ast.object[:rhs].hasAttr?(:static))
+ # TODO: Static elements might not have same type. Create a warning
+ ast.setAttr(:static, ast.object[:lhs].getAttr(:static))
+
+ elsif(ast.object[:lhs].hasAttr?(:static))
+ tmp = ast.object[:rhs]
+ if(tmp.object[:type] == :number || tmp.object[:type] == :var )
+ tmp.setAttr(:static, ast.object[:lhs].getAttr(:static))
+ ast.setAttr(:static, ast.object[:lhs].getAttr(:static))
+ end
+
+ # TODO: Verify if other conditions are possible as well.
+ # For example, verify if bincond for static and non static conjunctions.
+ # Currently no validation is being performed.
+ elsif(ast.object[:rhs].hasAttr?(:static))
+ tmp = ast.object[:lhs]
+ if(tmp.object[:type] == :number || tmp.object[:type] == :var )
+ tmp.setAttr(:static, ast.object[:rhs].getAttr(:static))
+ ast.setAttr(:static, ast.object[:rhs].getAttr(:static))
+ end
+ end
+ end
+ end
+ false
+ end
+ end
+end
diff --git a/target/arc/semfunc_generator/classes/QEmuCompiler.rb b/target/arc/semfunc_generator/classes/QEmuCompiler.rb
new file mode 100644
index 0000000000..9860d878bc
--- /dev/null
+++ b/target/arc/semfunc_generator/classes/QEmuCompiler.rb
@@ -0,0 +1,15 @@
+class QEmuCompiler
+ include Compiler
+
+ def initialize()
+ @passes = [
+ IdentifyQEmuStaticInferedParts,
+ SpaghettiCodePass,
+ DecomposeExpressions,
+ UnfoldCode,
+ CreateInternalVars,
+ ]
+ @translator = QEmuTranslator
+ end
+
+end
diff --git a/target/arc/semfunc_generator/classes/QEmuTranslator.rb b/target/arc/semfunc_generator/classes/QEmuTranslator.rb
new file mode 100644
index 0000000000..1b739d2614
--- /dev/null
+++ b/target/arc/semfunc_generator/classes/QEmuTranslator.rb
@@ -0,0 +1,269 @@
+class QEmuTranslator
+
+ extend TranslatorFinal
+ include ConstantTables
+
+ def self.translation_rules
+ ret = {
+ SemanticFunctionAST.function("defLabel", SemanticFunctionAST.var("name")) =>
+ "TCGLabel *$name = gen_new_label()",
+ SemanticFunctionAST.function("setLabel", SemanticFunctionAST.var("name")) =>
+ "gen_set_label($name)",
+ SemanticFunctionAST.function("createTmpVar", SemanticFunctionAST.var("name")) =>
+ "TCGv $name = tcg_temp_new()",
+ SemanticFunctionAST.function("defVariable", SemanticFunctionAST.var("name")) =>
+ "TCGv $name = tcg_temp_local_new()",
+ SemanticFunctionAST.function("freeVariable", SemanticFunctionAST.var("name")) =>
+ "tcg_temp_free($name)",
+ SemanticFunctionAST.function("freeReference", SemanticFunctionAST.var("name")) =>
+ "if($name != NULL) tcg_temp_free($name)",
+ SemanticFunctionAST.function("defReference", SemanticFunctionAST.var("name")) =>
+ "TCGv $name = NULL /* REFERENCE */",
+
+ SemanticFunctionAST.assign(
+ SemanticFunctionAST.var("a"),
+ SemanticFunctionAST.function("HELPER",
+ SemanticFunctionAST.var("helper"),
+ SemanticFunctionAST.var("..."))) =>
+ "ARC_HELPER($helper, $a, $varargs_)",
+ SemanticFunctionAST.function("HELPER",
+ SemanticFunctionAST.var("helper"),
+ SemanticFunctionAST.var("...")) =>
+ "ARC_HELPER($helper, NULL, $varargs_)",
+
+ SemanticFunctionAST.function("goto", SemanticFunctionAST.var("label")) => "tcg_gen_br($label)",
+
+ # SemanticFunctionAST.function("_func", SemanticFunctionAST.var("a")) => "$func($a)",
+ # SemanticFunctionAST.function("_func", SemanticFunctionAST.number("1")) => "$func($1)",
+
+ SemanticFunctionAST.parse_stmt("a = b") => "tcg_gen_mov_tl($a, $b)",
+ SemanticFunctionAST.parse_stmt("a = 1") => "tcg_gen_movi_tl($a, $1)",
+ }
+
+ match = SemanticFunctionAST.function("defStaticVariable", SemanticFunctionAST.var("type"), SemanticFunctionAST.var("name"))
+ ret[match] = Proc.new { |stmt_ast, repl, mappings, to_do|
+ ret = "#{mappings["type"]} #{mappings["name"]}"
+ if mappings["type"] == "TCGvPtr"
+ ret = "TCGv #{mappings["name"]} = NULL"
+ end
+ if mappings["type"] == "TCGv"
+ ret = "TCGv #{mappings["name"]} = tcg_temp_local_new()"
+ end
+ ret
+ }
+
+ match = Proc.new { |ast|
+ ret = { result: false, mappings: {} }
+ ret = { result: true, mappings: {} } if(ast.object[:type] == :if)
+ ret
+ }
+ ret[match] = Proc.new { |stmt_ast, repl, mappings, to_do|
+ tmp = " if (#{stmt_ast.object[:cond].pp}) {\n"
+ tmp += @translator.generate(stmt_ast.object[:then], false)
+ tmp += " }\n"
+ if(stmt_ast.object[:else].valid?)
+ tmp += " else {\n"
+ tmp += @translator.generate(stmt_ast.object[:else], false)
+ tmp += " }\n"
+ end
+ return tmp
+ }
+
+ # Any other static statement.
+ match = Proc.new { |ast|
+ ret = { result: false, mappings: {} }
+ ret = { result: true, mappings: {} } if(ast.hasAttr?(:static))
+ ret
+ }
+ ret[match] = Proc.new { |stmt_ast, repl, mappings, to_do|
+ tmp = stmt_ast.pp
+ tmp
+ }
+
+
+ {
+ "+": "add",
+ "-": "sub",
+ "*": "mul",
+ "/": "div",
+ "&": "and",
+ "|": "or",
+ "^": "xor",
+ "<<": "shl",
+ ">>": "shr",
+
+ }.each_pair do |k, v|
+ ret[SemanticFunctionAST.parse_stmt("a = b #{k} c")] = "tcg_gen_#{v}_tl($a, $b, $c)"
+ ret[SemanticFunctionAST.parse_stmt("a = b #{k} 1")] = "tcg_gen_#{v}i_tl($a, $b, $1)"
+ ret[SemanticFunctionAST.parse_stmt("a = 2 #{k} c")] = "tcg_gen_#{v}fi_tl($a, $2, $c)"
+ end
+
+
+ options1 = {
+ SemanticFunctionAST.var("b") => "$b",
+ SemanticFunctionAST.number("1") => "$1",
+ SemanticFunctionAST.function("_func1", SemanticFunctionAST.var("...")) => "$func1($varargs_func1)"
+ }
+ options2 = {
+ SemanticFunctionAST.var("c") => "$c",
+ SemanticFunctionAST.number("2") => "$2",
+ SemanticFunctionAST.function("_func2", SemanticFunctionAST.var("...")) => "$func2($varargs_func2)"
+ }
+
+
+ # Combinations of options
+ options1.each_pair do |m1, r1|
+ options2.each_pair do |m2, r2|
+ next if m1.object[:type] == :number && m2.object[:type] == :number
+
+ reverted_immediate = false
+ #Revert immediate value and condition
+ if(m1.object[:type] == :number)
+ tmp = [m1, r1]
+ m1 = m2; r2 = r1
+ reverted_immediate = true
+ m2 = tmp[0]; r2 = tmp[1]
+ end
+ type = "i" if(m2.object[:type] == :number)
+
+ {
+ "&&": "and",
+ "||": "or",
+ "^^": "xor",
+ }.each_pair do |k, v|
+ op = v
+
+ # A = B && C (for example)
+ rhs = SemanticFunctionAST.new(type: :bincond, name: k.to_s, lhs: m1.clone, rhs: m2.clone)
+ match = SemanticFunctionAST.new(type: :assign, lhs: SemanticFunctionAST.var("a"), rhs: rhs)
+ ret[match] = "tcg_gen_#{op}_tl($a, #{r1}, #{r2})"
+
+ end
+
+ {
+ "==": "TCG_COND_EQ",
+ "!=": "TCG_COND_NE",
+ "<": "TCG_COND_LT",
+ ">": "TCG_COND_GT",
+ "<=": "TCG_COND_LE",
+ ">=": "TCG_COND_GE",
+ }.each_pair do |k, v|
+
+ op = v
+ if(reverted_immediate == true)
+ case (k)
+ when "<"
+ op = "TCG_COND_GE"
+ when ">"
+ op = "TCG_COND_LE"
+ when "<="
+ op = "TCG_COND_GT"
+ when ">="
+ op = "TCG_COND_LT"
+ end
+ end
+
+ # A = B == C (for example)
+ rhs = SemanticFunctionAST.new(type: :bincond, name: k.to_s, lhs: m1.clone, rhs: m2.clone)
+ match = SemanticFunctionAST.new(type: :assign, lhs: SemanticFunctionAST.var("a"), rhs: rhs)
+ ret[match] = "tcg_gen_setcond#{type}_tl(#{op}, $a, #{r1}, #{r2})"
+
+ # IF(cond, label1, label2) # TODO: Label2 is expected to be equal to label1
+ cond = SemanticFunctionAST.new(type: :bincond, name: k.to_s, lhs: m1.clone, rhs: m2.clone)
+ ifcond_match = SemanticFunctionAST.function("IF", cond,
+ SemanticFunctionAST.var("label1"),
+ SemanticFunctionAST.var("label2")
+ )
+ ret[ifcond_match] = "tcg_gen_brcond#{type}_tl(#{op}, #{r1}, #{r2}, $label1)"
+ # Proc.new { |stmt_ast, repl, mappings, to_do|
+ # mappings.each_pair do |k, v|
+ # mappings[k] = "arc_#{v}" if (v =~ /^(true|false)$/)
+ # end
+ # }
+ end
+ end
+ end
+
+ {
+ "!": nil,
+ }.each_pair do |k, v|
+ [:unicond, :uniop].each do |type|
+ rhs = SemanticFunctionAST.new(type: type, name: k.to_s, rhs: SemanticFunctionAST.var("b"))
+ match = SemanticFunctionAST.new(type: :assign, lhs: SemanticFunctionAST.var("a"), rhs: rhs)
+ ret[match] = "tcg_gen_xori_tl($a, $b, 1);\ntcg_gen_andi_tl($a, $a, 1)"
+
+ rhs1 = SemanticFunctionAST.new(type: type, name: k.to_s, rhs: SemanticFunctionAST.function("_func", SemanticFunctionAST.var("...")))
+ match1 = SemanticFunctionAST.new(type: :assign, lhs: SemanticFunctionAST.var("a"), rhs: rhs1)
+ ret[match1] = "tcg_gen_xori_tl($a, $func($varargs_func), 1);\ntcg_gen_andi_tl($a, $a, 1)"
+ end
+ end
+
+ {
+ "~": "not",
+ }.each_pair do |k, v|
+ [:unicond, :uniop].each do |type|
+ rhs = SemanticFunctionAST.new(type: type, name: k.to_s, rhs: SemanticFunctionAST.var("b"))
+ match = SemanticFunctionAST.new(type: :assign, lhs: SemanticFunctionAST.var("a"), rhs: rhs)
+ ret[match] = "tcg_gen_#{v}_tl($a, $b)"
+
+ rhs1 = SemanticFunctionAST.new(type: type, name: k.to_s, rhs: SemanticFunctionAST.function("_func", SemanticFunctionAST.var("...")))
+ match1 = SemanticFunctionAST.new(type: :assign, lhs: SemanticFunctionAST.var("a"), rhs: rhs1)
+ ret[match1] = "tcg_gen_#{v}_tl($a, $func($varargs_func))"
+ end
+ end
+
+ DIRECT_TCG_FUNC_TRANSLATIONS.each_pair do |f1, f2|
+ #ret[SemanticFunctionAST.assign(SemanticFunctionAST.var("a"), SemanticFunctionAST.function(f, SemanticFunctionAST.var("...")))] = "#{f}($a, $varargs_)"
+ match = SemanticFunctionAST.assign(SemanticFunctionAST.var("a"), SemanticFunctionAST.function(f1, SemanticFunctionAST.var("...")))
+ ret[match] = Proc.new { |stmt_ast, repl, mappings, to_do|
+ ret = ""
+ if(mappings["varargs_"].class == Array)
+ mappings["varargs_"] = mappings["varargs_"].map { |a| a.debug() }.join(", ")
+ end
+ if(mappings["varargs_"] =~ /^$/)
+ ret = "#{f2}($a)"
+ else
+ ret = "#{f2}($a, $varargs_)"
+ end
+ ret
+ }
+ end
+
+ TEMP_CREATING_FUNCTIONS.each do |f|
+ #ret[SemanticFunctionAST.assign(SemanticFunctionAST.var("a"), SemanticFunctionAST.function(f, SemanticFunctionAST.var("...")))] = "#{f}($a, $varargs_)"
+ match = SemanticFunctionAST.assign(SemanticFunctionAST.var("a"), SemanticFunctionAST.function(f, SemanticFunctionAST.var("...")))
+ ret[match] = Proc.new { |stmt_ast, repl, mappings, to_do|
+ ret = ""
+ if(mappings["varargs_"].class == Array)
+ mappings["varargs_"] = mappings["varargs_"].map { |a| a.debug() }.join(", ")
+ end
+ if(mappings["varargs_"] =~ /^$/)
+ ret = "#{f}($a)"
+ else
+ ret = "#{f}($a, $varargs_)"
+ end
+ ret
+ }
+ end
+
+ ret[SemanticFunctionAST.assign(SemanticFunctionAST.var("a"), SemanticFunctionAST.function("_func", SemanticFunctionAST.var("...")))] =
+ "tcg_gen_mov_tl($a, $func($varargs_func))"
+
+ # "$a = $func($varargs_func)"
+ #ret[SemanticFunctionAST.assign(SemanticFunctionAST.var("a"), SemanticFunctionAST.function("_func", SemanticFunctionAST.var("...")))] = Proc.new { |stmt_ast, repl, mappings, to_do|
+ # lhs = stmt_ast.object[:lhs]
+ # if(lhs.hasAttr?(:reference))
+ # tmp = stmt_ast.pp
+ # else
+ # tmp = "tcg_gen_mov_tl()"
+ # end
+ # tmp = "tcg_gen_mov_tl()"
+ # tmp
+ #}
+ ret[SemanticFunctionAST.function("_func", SemanticFunctionAST.var("..."))] = "$func($varargs_func)"
+
+
+
+ return ret
+ end
+end
diff --git a/target/arc/semfunc_generator/classes/SemanticFunctionAST.rb b/target/arc/semfunc_generator/classes/SemanticFunctionAST.rb
new file mode 100644
index 0000000000..b617bb7093
--- /dev/null
+++ b/target/arc/semfunc_generator/classes/SemanticFunctionAST.rb
@@ -0,0 +1,466 @@
+class SemanticFunctionAST
+
+ include Enumerable
+ extend SemanticFunctionASTFactory
+ include SemanticFunctionASTBlockOperators
+
+ def each(&block)
+ yield self
+ @object.each_pair do |k, e|
+ if(e.class == SemanticFunctionAST)
+ e.each(&block)
+ end
+ end
+ end
+
+ def find_parent_node_with_type(type, parents = {})
+ if(self.object[:type] == type)
+ return self
+ else
+ if(parents[self] != nil)
+ parents[self].find_parent_node_with_type(type, parents)
+ else
+ return nil
+ end
+ end
+ end
+
+
+ def initialize(params)
+ @object = params
+ end
+
+ def clone
+ new_elem = SemanticFunctionAST.new({})
+ self.object.each_pair do |k, v|
+ if(v.class == SemanticFunctionAST)
+ new_elem.object[k] = v.clone
+ elsif v.class == Array
+ new_elem.object[k] = Array.new
+ v.each_with_index do |e, i|
+ new_elem.object[k][i] = e.clone
+ end
+ else
+ begin
+ new_elem.object[k] = v.clone
+ rescue
+ new_elem.object[k] = v
+ end
+ end
+ end
+ return new_elem
+ end
+
+ def self.error(string)
+ SemanticFunctionAST.new({ type: 'error', message: string })
+ end
+
+ def self.nothing
+ SemanticFunctionAST.new({ type: :nothing })
+ end
+
+ def self.var(name)
+ SemanticFunctionAST.new({ type: :var, name: name })
+ end
+
+ def self.number(number)
+ SemanticFunctionAST.new({ type: :number, number: number })
+ end
+
+ def self.assign(lhs, rhs)
+ return SemanticFunctionAST.new({ type: :assign, lhs: lhs, rhs: rhs })
+ end
+
+ def self.function(name, *args)
+ return SemanticFunctionAST.new({ type: :func, name: name, args: args || [] })
+ end
+
+ def self.bincond(name, lhs, rhs)
+ return SemanticFunctionAST.new({ type: :bincond, name: name, lhs: lhs, rhs: rhs })
+ end
+
+ def self.unicond(name, rhs)
+ return SemanticFunctionAST.new({ type: :unicond, name: name, rhs: rhs })
+ end
+
+ def self.parse(string)
+ #puts "Parsing: #{string}"
+ SemanticFunctionParser.new.parse(string)
+ end
+ def self.parse_stmt(str)
+ ast = self.parse(str)
+ return ast.object[:list].object[:head]
+ end
+
+ def getAttr(name)
+ return nil if(object[:attrs] == nil || object[:attrs][name] == nil)
+ return object[:attrs][name]
+ end
+ def hasAttr?(name)
+ getAttr(name) != nil
+ end
+ def setAttr(name, value)
+ object[:attrs] = object[:attrs] || {}
+ object[:attrs][name] = value
+ end
+
+ def valid?
+ @object[:type] != :nothing
+ end
+ def shouldSeparate?
+ # return true
+ return (@object[:type] != :block)
+ end
+
+ def object
+ return @object
+ end
+
+ def traverse(data, &block)
+ cont = yield @object, data
+ if(cont)
+ @object.each_pair do |k,v|
+ v.traverse(data, &block) if v.class == SemanticFunctionAST
+ v.each { |v1| v1.traverse(data, &block) } if v.class == Array
+ end
+ end
+ end
+
+ def graphviz(filename = "/tmp/tmp.png", g = nil, parent = nil)
+ first_call = false
+ if(g == nil)
+ first_call = true
+ g = GraphViz.new( :G, :type => :digraph )
+ end
+
+ label = []
+
+ node = g.add_nodes("n#{g.node_count}")
+ @object.each_pair do |k,v|
+ if v.class == SemanticFunctionAST
+ v.graphviz(filename, g, node)
+ elsif v.class == Array
+ v.each do |v1|
+ v1.graphviz(filename, g, node)
+ end
+ else
+ label.push("#{k}: #{v}")
+ end
+ end
+ node[:label] = label.join("\n")
+ g.add_edges(parent, node) if(parent != nil)
+
+ if(first_call)
+ g.output(:png => filename)
+ end
+ end
+
+ def traverseASTWithMethodName(data, method_name)
+ cont = self.send(method_name, data)
+ if(cont)
+ @object.each_pair do |k,v|
+ v.traverseASTWithMethodName(data, method_name) if v.class == SemanticFunctionAST
+ end
+ end
+ end
+
+ def SemanticFunctionAST.IF(cond, ifthen, ifelse)
+ ifthen = ifthen || SemanticFunctionAST.nothing
+ ifelse = ifelse || SemanticFunctionAST.nothing
+ return SemanticFunctionAST.new(type: :function, name: "IF", args: [cond, ifthen, ifelse])
+ end
+
+ def constructDefinitions(data = {})
+ #puts " -- #{ object[:type] } ------------------------ "
+ data.each_pair do |k, v|
+ #puts k
+ #puts (v == nil) ? "NIL" : v.debug
+ end
+
+ case object[:type]
+ when :assign
+ # #puts " =========> #{self.debug}"
+ new_data = object[:rhs].constructDefinitions(data)
+ data[object[:lhs].object[:name]] = new_data["_"]
+ #puts "================== #{object[:lhs].object[:name]} => #{new_data["_"].inspect}"
+ return data
+ when :var
+ if data[object[:name]]
+ #puts " VAR NAME = #{object[:name]} = #{data[object[:name]].debug}"
+ data["_"] = data[object[:name]].clone
+ else
+ data["_"] = self.clone
+ end
+ return data
+ when :func
+ new_func = self.object.clone
+
+ new_func[:args].map! do |arg|
+ if(arg.valid?)
+ new_data = arg.constructDefinitions(data.clone)
+ arg = new_data["_"]
+ end
+ arg
+ end
+ data[object[:name]] = SemanticFunctionAST.new(new_func)
+ data["_"] = data[object[:name]]
+
+
+ return data
+ when :if
+ # One function IF(COND, THEN, ELSE)
+ cond_data = object[:cond].constructDefinitions(data.clone)
+ then_data = object[:then].constructDefinitions(data.clone)
+ else_data = object[:else].constructDefinitions(data.clone)
+
+ elems = (then_data.keys + else_data.keys).uniq
+
+ elems.each do |k|
+ td = then_data[k] || SemanticFunctionAST.nothing
+ ed = else_data[k] || SemanticFunctionAST.nothing
+
+ if(data[k] != then_data[k] || data[k] != else_data[k] || data[k])
+ #puts "SAME #{k}"
+ #puts "SAME1 #{then_data[k].debug}" if then_data[k]
+ #puts "SAME2 #{else_data[k].debug}" if else_data[k]
+ data[k] = SemanticFunctionAST.IF(cond_data["_"], td, ed)
+ else
+ #puts "DIFFERENT #{k}"
+ #puts "DIFFERENT1 #{then_data[k].debug}" if then_data[k]
+ #puts "DIFFERENT2 #{else_data[k].debug}" if else_data[k]
+ end
+ end
+
+ cond_data.each_pair do |k, v|
+ data[k] = v if (data[k] != v)
+ end
+
+ # puts " == #{SemanticFunctionAST.new(object).debug(false) } =="
+ # data.each_pair do |k, v|
+ # puts " #{k} : #{v.debug(false)}"
+ # end
+
+ data["_"] = SemanticFunctionAST.nothing
+ return {}
+
+ # when :while
+ # cond_data = object[:cond].constructDefinitions(data.clone)
+ # loop_data = object[:loop].constructDefinitions(data.clone)
+ #
+ # loop_dat.each { |k| data[k] = SemanticFunctionAST.new(type: :function, name: "WHILE", args: [cond_data["_"], loop_data[k]]) }
+ # data["_"] = SemanticFunctionAST.nothing
+ else
+ # puts self.inspect
+ # puts self.object[:type]
+ elems = {} #Pre-fill semantic function table
+
+ object.clone.each_pair do |k, v|
+ if (v.class == SemanticFunctionAST)
+ data.merge!(v.constructDefinitions(data))
+ elems[k] = data["_"] || SemanticFunctionAST.nothing
+ elsif (v.class == Array)
+ v = v.map do |v1|
+ v1.constructDefinitions(data)
+ data["_"] || SemanticFunctionAST.nothing
+ end
+ elems[k] = v
+ else
+ elems[k] = v
+ end
+ # v.traverseASTWithMethodName(data, :constructDefinitions) if(v.class == SemanticFunctionAST)
+ end
+ data["_"] = SemanticFunctionAST.new(elems)
+ end
+
+ return data
+ end
+
+ def debug(pn = false)
+ begin
+ case @object[:type]
+ when /error/
+ return "--- ERROR: #{@object[:message]} ---"
+ when /block/
+ return "{ #{@object[:list].debug(pn)} }"
+ when /stmt_list/
+ return "#{@object[:head].debug(pn)}; #{@object[:tail].debug(pn)}"
+ when /if/
+ ret = "if(#{@object[:cond].debug(pn)}) #{@object[:then].debug(pn)}"
+ ret += " else #{@object[:else].debug(pn)}" if @object[:else].valid?
+ return ret
+ when /while/
+ return "while(#{@object[:cond].debug(pn)}) #{@object[:loop].debug(pn)}"
+ when /bincond/
+ return "#{@object[:lhs].debug(pn)} #{@object[:name]} #{@object[:rhs].debug(pn)}"
+ when /unicond/
+ return "#{@object[:name]} #{@object[:rhs].debug(pn)}"
+ when /cond/
+ return @object[:value].debug(pn)
+ when /func/
+ return "#{@object[:name]} (#{@object[:args].map{|a| a.debug(pn)}.join(", ")})"
+ when /expr_block/
+ return "(#{@object[:value].debug(pn)})"
+ when /assign/
+ return "#{@object[:lhs].debug(pn)} = #{@object[:rhs].debug(pn)}"
+ when /binop/
+ return "#{@object[:lhs].debug(pn)}#{@object[:name]}#{@object[:rhs].debug(pn)}"
+ when /uniop/
+ return "#{@object[:name]}#{@object[:rhs].debug(pn)}"
+ when /var/
+ return "#{@object[:name]}"
+ when /number/
+ return "#{@object[:number]}"
+ when /nothing/
+ return "NOTHING" if(pn == true)
+ else
+ puts @object.inspect
+ raise "Object type is invalid"
+ end
+ rescue Exception => e
+ return "FAILED TO _DEBUG\n#{self.inspect}\nException at: #{e.backtrace}"
+ end
+ end
+
+ def debug_encoded()
+ ret = debug(false)
+ begin
+ ret = ret.gsub("+","%2B")
+ ret = ret.gsub(";","%3B")
+ ret = URI.encode(ret)
+ rescue
+ ret = "ERROR"
+ end
+ return ret
+ end
+
+ def pp(ind = 0)
+ ss = " " * ind
+
+ begin
+ case @object[:type]
+ when /error/
+ return "--- ERROR: #{@object[:message]} ---"
+ when /block/
+ ret = "#{ss}{\n"
+ ret+= "#{@object[:list].pp(ind + 2)}"
+ ret+= "#{ss}}"
+ return ret
+ when /stmt_list/
+ ret = ""
+ if(object[:head].is_a?(SemanticFunctionAST))
+ ret += "#{ss}#{@object[:head].pp(ind)}" if @object[:head].valid?
+ ret += ";" if @object[:head].shouldSeparate?
+ else
+ ret += "// INVALID (#{object[:head].inspect})"
+ end
+ ret += " (static)" if @object[:head].hasAttr?(:static)
+ # ret += " (#{@object[:head].object[:attrs].inspect})"
+ ret += "\n"
+ # ret += "#{ss}" if @object[:tail][:type] != "stmt_list"
+ if(object[:tail].is_a?(SemanticFunctionAST))
+ ret += "#{@object[:tail].pp(ind)}" if @object[:tail].valid?
+ else
+ ret += "// INVALID (#{object[:tail].inspect})"
+ end
+ # puts " --- \n#{ret}"
+ return ret
+ when /if/
+ ret = "if(#{@object[:cond].pp(ind)})\n"
+ ret += "#{@object[:then].pp(ind+2)}"
+ if @object[:else].valid?
+ ret += "\n"
+ ret += "#{ss}else\n"
+ ret += "#{@object[:else].pp(ind+2)}"
+ end
+ return ret
+ when /while/
+ return "#{ss}while(#{@object[:cond].pp(ind)})\n#{@object[:loop].pp(ind )}"
+ when /bincond/
+ ret = ""
+ ret += "(#{@object[:lhs].pp(ind)} #{@object[:name]} #{@object[:rhs].pp(ind)})"
+ return ret
+ when /unicond/
+ return "#{@object[:name]}#{@object[:rhs].pp(ind)}"
+ when /cond/
+ return @object[:value].pp(ind)
+ when /func/
+ ret = ""
+ ret += "#{@object[:name]} (#{@object[:args].map{|a| a.pp(ind)}.join(", ")})"
+ when /expr_block/
+ return "(#{@object[:value].pp(ind)})"
+ when /assign/
+ return "#{@object[:lhs].pp(ind)} = #{@object[:rhs].pp(ind)}"
+ when /binop/
+ return "(#{@object[:lhs].pp(ind)} #{@object[:name]} #{@object[:rhs].pp(ind)})"
+ when /uniop/
+ return "#{@object[:name]}#{@object[:rhs].pp(ind)}"
+ when /var/
+ return "#{@object[:name]}"
+ when /number/
+ return "#{@object[:number]}"
+ when /nothing/
+ return ""
+ else
+ raise "Object type is invalid"
+ end
+ rescue
+ raise "Failed pretty printing #{stmt.inspect}"
+ end
+ end
+
+ def ppf(ind = 0)
+ ss = " " * ind
+
+ case @object[:type]
+ when /error/
+ return "--- ERROR: #{@object[:message]} ---"
+ when /bincond/
+ return "#{@object[:lhs].ppf(ind)} #{@object[:name]} #{@object[:rhs].ppf(ind)}"
+ when /unicond/
+ return "#{@object[:name]} #{@object[:rhs].ppf(ind)}"
+ when /cond/
+ return @object[:value].ppf(ind)
+ when /func/
+ return "#{@object[:name]} (\n#{ss} #{@object[:args].map{ |a| a.ppf(ind+2) }.join(",\n#{ss} ")})"
+ when /expr_block/
+ return "(#{@object[:value].ppf(ind)})"
+ when /assign/
+ return "#{@object[:lhs].ppf(ind)} = #{@object[:rhs].ppf(ind)}"
+ when /binop/
+ return "#{@object[:lhs].ppf(ind)}#{@object[:name]}#{@object[:rhs].ppf(ind)}"
+ when /uniop/
+ return "#{@object[:name]}#{@object[:rhs].ppf(ind)}"
+ when /var/
+ return "#{@object[:name]}"
+ when /number/
+ return "#{@object[:number]}"
+ when /nothing/
+ return "NOTHING"
+ return ""
+ else
+ raise "Object type is invalid"
+ end
+ end
+
+
+ def to_c(r={})
+ case @object[:type]
+ when /binop/
+ return "( #{@object[:lhs].to_c(r)} #{@object[:name]} #{@object[:rhs].to_c(r)} )"
+ when /uniop/
+ return "( #{@object[:name]}#{@object[:rhs].to_c(r)} )"
+ when /func/
+ return "( #{@object[:name]} ( #{@object[:param].map {|p| p.to_c(r) }.join(",") } ) )"
+ when /var/
+ var_name = @object[:var].to_sym
+ #puts "VAR_NAME= #{var_name}"
+ return r[var_name] if r[var_name] != nil
+ return @object[:var]
+ when /number/
+ return "#{@object[:number]}"
+ else
+ raise "Object type is invalid #{self}"
+ end
+
+ end
+end
diff --git a/target/arc/semfunc_generator/classes/SpaghettiCodePass.rb b/target/arc/semfunc_generator/classes/SpaghettiCodePass.rb
new file mode 100644
index 0000000000..0c9ff3e013
--- /dev/null
+++ b/target/arc/semfunc_generator/classes/SpaghettiCodePass.rb
@@ -0,0 +1,55 @@
+class SpaghettiCodePass
+ private
+
+ # extend SemanticFunctionASTFactory
+ include Pass
+
+ def self.spaghetify(ast)
+ ret = []
+ object = ast.object
+
+ case(object[:type])
+ when :block
+ ret += spaghetify(object[:list])
+ when :stmt_list
+ ret += spaghetify(object[:head])
+ ret += spaghetify(object[:tail])
+ when :if
+
+ cond = ast.object[:cond]
+
+ if(cond.hasAttr?(:static))
+ ast.object[:then] = SemanticFunctionAST.block(SemanticFunctionAST.createStmtListFromArray(spaghetify(ast.object[:then])))
+ ast.object[:else] = SemanticFunctionAST.block(SemanticFunctionAST.createStmtListFromArray(spaghetify(ast.object[:else])))
+ ret.push(ast)
+ else
+ done_label = SemanticFunctionAST.createTmpVar("done")
+ else_label = SemanticFunctionAST.createTmpVar("else")
+ else_label = done_label unless object[:else].valid?
+
+ ret.push(SemanticFunctionAST.defLabel(else_label)) if object[:else].valid?
+ ret.push(SemanticFunctionAST.defLabel(done_label))
+
+ ret.push(SemanticFunctionAST.function("IF", SemanticFunctionAST.notCond(object[:cond].clone), else_label, done_label))
+
+ ret += spaghetify(object[:then])
+ if object[:else].valid?
+ ret.push(SemanticFunctionAST.function("goto", done_label))
+ ret.push(SemanticFunctionAST.setLabel(else_label))
+ ret += spaghetify(object[:else])
+ end
+ ret.push(SemanticFunctionAST.setLabel(done_label))
+ end
+ else
+ ret.push(ast) if ast.valid?
+ end
+
+ return ret
+ end
+
+ public
+ def self.task(ast)
+ # reset_counters
+ return SemanticFunctionAST.createStmtListFromArray(spaghetify(ast))
+ end
+end
diff --git a/target/arc/semfunc_generator/classes/SpaghettiCodePass1.rb b/target/arc/semfunc_generator/classes/SpaghettiCodePass1.rb
new file mode 100644
index 0000000000..c38b279c48
--- /dev/null
+++ b/target/arc/semfunc_generator/classes/SpaghettiCodePass1.rb
@@ -0,0 +1,66 @@
+class SpaghettiCodePass1
+ private
+
+ # extend SemanticFunctionASTFactory
+ include Pass
+ extend Translator
+
+ def self.translation_rules
+ ret = {}
+
+ match = SemanticFunctionAST.new(type: :if, name: "_")
+ ret[match] =
+ Proc.new { |stmt, repl, mappings, to_do|
+
+ binop_lhs = stmt.object[:rhs].object[:lhs]
+ binop_rhs = stmt.object[:rhs].object[:rhs]
+ changed_lhs = false
+ changed_rhs = false
+
+ if(binop_lhs.object[:type] != :var && binop_lhs.object[:type] != :number)
+ # puts "IN 1 #{binop_lhs.inspect}"
+ var = SemanticFunctionAST.createTmpVar("temp")
+ tmp = [
+ # SemanticFunctionAST.function("createTmpVar", var),
+ ]
+ to_do[:pre_pend] = tmp + to_do[:pre_pend]
+ assign = SemanticFunctionAST.new(type: :assign, lhs: var, rhs: binop_lhs)
+ self.replace(assign, to_do)
+ binop_lhs = var
+ changed_lhs = true
+ end
+
+ if(binop_rhs.object[:type] != :var && binop_rhs.object[:type] != :number)
+ # puts "IN 2 #{binop_rhs.inspect}"
+ var = SemanticFunctionAST.createTmpVar("temp")
+ tmp = [
+ # SemanticFunctionAST.function("createTmpVar", var),
+ assign = SemanticFunctionAST.new(type: :assign, lhs: var, rhs: binop_rhs)
+ ]
+ to_do[:pre_pend] = tmp + to_do[:pre_pend]
+ self.replace(assign, to_do)
+ binop_rhs = var
+ changed_rhs = true
+ end
+
+ if(changed_lhs == true || changed_rhs == true)
+ new_stmt = stmt.clone
+ new_stmt.object[:rhs].object[:lhs] = binop_lhs
+ new_stmt.object[:rhs].object[:rhs] = binop_rhs
+ to_do[:pre_pend].push(new_stmt)
+ # to_do[:remove] = true
+ stmt.object[:type] = :nothing
+ end
+ }
+
+ return ret
+ end
+
+ public
+ def self.task(ast)
+ self.generate(ast)
+ # puts "AST = #{ast.class}"
+ # puts ast.debug
+ return ast
+ end
+end
diff --git a/target/arc/semfunc_generator/classes/UnfoldCode.rb b/target/arc/semfunc_generator/classes/UnfoldCode.rb
new file mode 100644
index 0000000000..0146407a96
--- /dev/null
+++ b/target/arc/semfunc_generator/classes/UnfoldCode.rb
@@ -0,0 +1,305 @@
+class UnfoldCode
+ private
+
+ # extend SemanticFunctionASTFactory
+ include Pass
+ include ConstantTables
+ extend TranslatorAST
+
+ def self.translation_rules
+ ret = {}
+
+ match = Proc.new { |ast|
+ ret = { result: false, mappings: {} }
+ # ret = { result: true, mappings: {} } if(ast.hasAttr?(static))
+ ret = { result: true, mappings: {} } if(ast.object[:type] == :if)
+ ret
+ }
+ ret[match] = Proc.new { |stmt_ast, repl, mappings, to_do|
+ case(stmt_ast.object[:type])
+ when :if
+ self.generate(stmt_ast.object[:then])
+ self.generate(stmt_ast.object[:else])
+ end
+ }
+
+ # match = Proc.new { |ast|
+ # ret = { result: false, mappings: {} }
+ # ret = {result: true, mappings: {} } if (ast.object[:type] == :variable && ast.object[:name] =~ /^(true|false)$/ && !ast.hasAttr?(:static))
+ # }
+ # ret[match] = Proc.new { |ast|
+ # return SemanticFunctionAST.variable("arc_#{ast.object[:name]}")
+ # }
+
+ match = SemanticFunctionAST.new(type: :assign,
+ lhs: SemanticFunctionAST.var("a"),
+ rhs: SemanticFunctionAST.new(type: :binop, name: "_"))
+
+ # match = Proc.new { |ast|
+ # ret = { result: false, mappings: {} }
+ # # ret = { result: true, mappings: {} } if(ast.hasAttr?(static))
+ # if(ast.object[:type] == :assign &&
+ # ast.object[:rhs].object[:type] != :func &&
+ # ast.object[:rhs].object[:type] != :var &&
+ # ast.object[:rhs].object[:type] != :number)
+ # ret = { result: true, mappings: {} }
+ # end
+ # ret
+ # }
+
+
+ def self.binOpProcess(stmt, repl, mappings, to_do)
+ # puts "STMT = #{stmt.debug}"
+
+ binop_lhs = stmt.object[:rhs].object[:lhs]
+ binop_rhs = stmt.object[:rhs].object[:rhs]
+ changed_lhs = false
+ changed_rhs = false
+
+ if(binop_lhs.object[:type] != :var && binop_lhs.object[:type] != :number)
+ # puts "IN 1 #{binop_lhs.inspect}"
+ var = SemanticFunctionAST.createTmpVar("temp")
+ tmp = [
+ # SemanticFunctionAST.function("createTmpVar", var),
+ assign = SemanticFunctionAST.new(type: :assign, lhs: var, rhs: binop_lhs)
+ ]
+ to_do[:pre_pend] = tmp + to_do[:pre_pend]
+ self.replace(assign, to_do)
+ binop_lhs = var
+ changed_lhs = true
+ end
+
+ if(binop_rhs.object[:type] != :var && binop_rhs.object[:type] != :number)
+ # puts "IN 2 #{binop_rhs.inspect}"
+ var = SemanticFunctionAST.createTmpVar("temp")
+ tmp = [
+ # SemanticFunctionAST.function("createTmpVar", var),
+ assign = SemanticFunctionAST.new(type: :assign, lhs: var, rhs: binop_rhs)
+ ]
+ to_do[:pre_pend] = tmp + to_do[:pre_pend]
+ self.replace(assign, to_do)
+ binop_rhs = var
+ changed_rhs = true
+ end
+
+ if(changed_lhs == true || changed_rhs == true)
+ new_stmt = stmt.clone
+ new_stmt.object[:rhs].object[:lhs] = binop_lhs
+ new_stmt.object[:rhs].object[:rhs] = binop_rhs
+ to_do[:pre_pend].push(new_stmt)
+ # to_do[:remove] = true
+ stmt.object[:type] = :nothing
+ end
+ end
+ # puts "IAMHERE"
+ ret[match] =
+ Proc.new { |stmt, repl, mappings, to_do|
+ self.binOpProcess(stmt, repl, mappings, to_do)
+ }
+
+
+ # Do not convert special IF function
+ func_match =
+ Proc.new { |stmt, repl, mappings, to_do|
+ changed = false
+ new_stmt = nil
+ # puts "BLA => #{stmt.debug}"
+ args = stmt.object[:args]
+ new_args = []
+ args.each_with_index do |arg, i|
+ new_args[i] = arg
+
+ if(arg.object[:type] != :var) # && arg.object[:type] != :number)
+ var = SemanticFunctionAST.createTmpVar("temp")
+ # arg_var = self.replace(arg.clone, to_do)
+ # puts arg_var.inspect
+ tmp = [
+ # SemanticFunctionAST.function("createTmpVar", var),
+ assign = SemanticFunctionAST.new(type: :assign, lhs: var, rhs: arg)
+ ]
+ to_do[:pre_pend] = tmp + to_do[:pre_pend]
+ self.replace(assign, to_do)
+ arg = var
+ new_args[i] = var
+ changed = true
+ end
+ end
+
+ if(changed)
+ new_stmt = SemanticFunctionAST.function(stmt.object[:name], *new_args)
+ to_do[:pre_pend].push(new_stmt)
+ stmt.object[:type] = :nothing
+ end
+
+ new_stmt
+ }
+
+ assign_func_match =
+ Proc.new { |stmt, repl, mappings, to_do|
+ # puts "FUNC_MATCH"
+ lhs = stmt.object[:lhs]
+ rhs = stmt.object[:rhs]
+
+ if(lhs.object[:type] == :var &&
+ rhs.object[:type] == :func && TEMP_CREATING_FUNCTIONS.index(rhs.object[:name]))
+ # puts "INSIDE"
+ var = SemanticFunctionAST.createTmpVar("temp")
+ assign = SemanticFunctionAST.assign(var, rhs)
+ new_stmt = func_match.call(rhs, repl, mappings, to_do)
+ if(new_stmt != nil)
+ assign = SemanticFunctionAST.assign(var, to_do[:pre_pend].pop)
+ end
+ to_do[:pre_pend].push(assign)
+ assign = SemanticFunctionAST.assign(lhs, var)
+ to_do[:pre_pend].push(assign)
+
+ stmt.object[:type] = :nothing
+ else
+ new_stmt = func_match.call(stmt.object[:rhs], repl, mappings, to_do)
+ if(new_stmt != nil)
+ new_stmt = SemanticFunctionAST.assign(stmt.object[:lhs], to_do[:pre_pend].pop)
+ to_do[:pre_pend].push(new_stmt)
+ stmt.object[:type] = :nothing
+ end
+ end
+ }
+
+
+ ret[SemanticFunctionAST.function("IF", SemanticFunctionAST.var("..."))] = nil
+ ret[SemanticFunctionAST.function("_", SemanticFunctionAST.var("..."))] = func_match
+
+ match = Proc.new { |ast|
+ ret = { result: false, mappings: {} }
+ # ret = { result: true, mappings: {} } if(ast.hasAttr?(static))
+ if(ast.object[:type] == :assign && ast.object[:rhs].object[:type] == :func)
+ ret = { result: true, mappings: {} }
+ end
+ ret
+ }
+ ret[match] = assign_func_match
+
+
+ assign_cond_match =
+ Proc.new { |stmt, repl, mappings, to_do|
+ # puts " BINCOND = #{stmt.pp}"
+
+ cond = stmt.object[:rhs]
+ changed = false
+
+ if(cond.object[:type] == :bincond)
+ elems = { lhs: cond.object[:lhs], rhs: cond.object[:rhs] }
+ elsif(cond.object[:type] == :unicond)
+ elems = { rhs: cond.object[:rhs] }
+ end
+
+ elems.clone.each_pair do |k, v|
+ if(v.object[:type] == :func && TEMP_CREATING_FUNCTIONS.index(v.object[:name]))
+ var = SemanticFunctionAST.createTmpVar("temp")
+ assign = SemanticFunctionAST.assign(var, v)
+ new_stmt = func_match.call(v, repl, mappings, to_do)
+ if(new_stmt != nil)
+ assign = SemanticFunctionAST.assign(var, to_do[:pre_pend].pop)
+ end
+ to_do[:pre_pend].push(assign)
+ elems[k] = var
+ changed = true
+ end
+ end
+
+ if(changed == true)
+ if(cond.object[:type] == :bincond)
+ new_cond = SemanticFunctionAST.bincond(cond.object[:name], elems[:lhs], elems[:rhs])
+ new_stmt = SemanticFunctionAST.assign(stmt.object[:lhs], new_cond)
+ elsif(cond.object[:type] == :unicond)
+ new_cond = SemanticFunctionAST.unicond(cond.object[:name], elems[:rhs])
+ new_stmt = SemanticFunctionAST.assign(stmt.object[:lhs], new_cond)
+ end
+ to_do[:pre_pend].push(new_stmt)
+ stmt.object[:type] = :nothing
+ end
+ }
+ match = Proc.new { |ast|
+ ret = { result: false, mappings: {} }
+ # ret = { result: true, mappings: {} } if(ast.hasAttr?(static))
+ if(ast.object[:type] == :assign && ast.object[:rhs].object[:type] == :bincond)
+ ret = { result: true, mappings: {} }
+ end
+ if(ast.object[:type] == :assign && ast.object[:rhs].object[:type] == :unicond)
+ ret = { result: true, mappings: {} }
+ end
+ ret
+ }
+ ret[match] = assign_cond_match
+
+
+ if_cond_match =
+ Proc.new { |stmt, repl, mappings, to_do|
+ # puts " BINCOND = #{stmt.pp}"
+ cond = stmt.object[:cond]
+
+ changed = false
+ elems = { cond: bincond.object[:cond] }
+
+ elems.clone.each_pair do |k, v|
+ if(v.object[:type] == :func && TEMP_CREATING_FUNCTIONS.index(v.object[:name]))
+ var = SemanticFunctionAST.createTmpVar("temp")
+ assign = SemanticFunctionAST.assign(var, v)
+ new_stmt = func_match.call(v, repl, mappings, to_do)
+ if(new_stmt != nil)
+ assign = SemanticFunctionAST.assign(var, to_do[:pre_pend].pop)
+ end
+ to_do[:pre_pend].push(assign)
+ elems[k] = var
+ changed = true
+ end
+ end
+
+ if(changed == true)
+ new_bincond = SemanticFunctionAST.bincond(bincond.object[:name], elems[:lhs], elems[:rhs])
+ new_stmt = SemanticFunctionAST.assign(stmt.object[:lhs], new_bincond)
+ to_do[:pre_pend].push(new_stmt)
+ stmt.object[:type] = :nothing
+ end
+ }
+ match = Proc.new { |ast|
+ ret = { result: false, mappings: {} }
+ # ret = { result: true, mappings: {} } if(ast.hasAttr?(static))
+ if(ast.object[:type] == :if)
+ ret = { result: true, mappings: {} }
+ end
+ ret
+ }
+ ret[match] = if_cond_match
+
+
+ # match = SemanticFunctionAST.new(type: :assign,
+ # lhs: SemanticFunctionAST.var("a"),
+ # rhs: SemanticFunctionAST.function("_", SemanticFunctionAST.var("...")))
+ # ret[match] = Proc.new { |stmt, repl, mappings, to_do|
+ # # puts "BLA -------------"
+ # # puts stmt.debug
+ # # puts " ------------- "
+ #
+ # new_func = func_match.call(stmt.object[:rhs], repl, mappings, to_do)
+ #
+ # if(new_func != nil)
+ # new_stmt = SemanticFunctionAST.assign(stmt.object[:lhs], new_func)
+ # to_do[:pre_pend].push(new_stmt)
+ # stmt.object[:type] = :nothing
+ # end
+ # }
+
+ return ret
+
+ end
+
+
+ public
+ def self.task(ast)
+ # SemanticFunctionAST.reset_counters()
+ self.generate(ast)
+ # puts "AST = #{ast.class}"
+ # puts ast.debug
+ return ast
+ end
+end
diff --git a/target/arc/semfunc_generator/init.rb b/target/arc/semfunc_generator/init.rb
new file mode 100644
index 0000000000..20a51a9fbf
--- /dev/null
+++ b/target/arc/semfunc_generator/init.rb
@@ -0,0 +1,15 @@
+require 'rubygems'
+#require 'graphviz'
+
+project_root = File.dirname(File.absolute_path(__FILE__))
+Dir.glob(project_root + "/parsers/*.rb").each do |file|
+ require file
+end
+
+Dir.glob(project_root + "/modules/*.rb").each do |file|
+ require file
+end
+
+Dir.glob(project_root + "/classes/*.rb").each do |file|
+ require file
+end
diff --git a/target/arc/semfunc_generator/modules/Compiler.rb b/target/arc/semfunc_generator/modules/Compiler.rb
new file mode 100644
index 0000000000..c63f55c1ff
--- /dev/null
+++ b/target/arc/semfunc_generator/modules/Compiler.rb
@@ -0,0 +1,42 @@
+module Compiler
+ def optimize(ast, log = [], debug = false)
+ log.push({ name: 'start', ast: ast })
+ SemanticFunctionAST.reset_counters()
+ @passes.each do |pass|
+ ast = ast.clone
+ ast = pass.task(ast)
+ log.push({ name: pass.name, ast: ast })
+ # puts " -- #{pass.name} --"
+ # puts ast.pp
+ end
+ if(debug == true)
+ log.each do |v|
+ puts v[:name] + ":"
+ puts " => #{v[:ast].pp}"
+ end
+ end
+ return ast
+ end
+
+ def getAST(input)
+ if(input.class == String)
+ input = SemanticFunctionAST.parse(input)
+ elsif(input.class != SemanticFunctionAST)
+ abort()
+ end
+ return input
+ end
+
+ def generate(input, log = [], debug = false)
+ ast = getAST(input)
+ ast = self.optimize(ast, log, debug)
+ # puts ast.class
+ return @translator.generate(ast, debug)
+ end
+
+ def compile(code, log = [], debug = false)
+ ast = getAST(code)
+ ast = optimize(ast, log, debug)
+ return ast
+ end
+end
diff --git a/target/arc/semfunc_generator/modules/ConstantTables.rb b/target/arc/semfunc_generator/modules/ConstantTables.rb
new file mode 100644
index 0000000000..047665c4ab
--- /dev/null
+++ b/target/arc/semfunc_generator/modules/ConstantTables.rb
@@ -0,0 +1,57 @@
+module ConstantTables
+
+ TEMP_CREATING_FUNCTIONS = [
+ "CarryADD",
+ "CarrySUB",
+ "OverflowADD",
+ "OverflowSUB",
+ "getCCFlag",
+
+ "Carry",
+
+ "getCFlag",
+ "getMemory",
+ # "SignExtend",
+ # "getNFlag",
+ "getPC",
+ "nextInsnAddressAfterDelaySlot",
+ "nextInsnAddress",
+ "getPCL",
+ "unsignedLT",
+ "unsignedGE",
+ "logicalShiftRight",
+ "logicalShiftLeft",
+ "arithmeticShiftRight",
+ "rotateLeft",
+ "rotateRight",
+ "getBit",
+ "getRegIndex",
+ "readAuxReg",
+ "extractBits",
+ "getRegister",
+ "ARC_HELPER",
+ # "nextReg",
+ "CLZ",
+ "CTZ",
+
+ "MAC",
+ "MACU",
+
+ "divSigned",
+ "divUnsigned",
+ "divRemainingSigned",
+ "divRemainingUnsigned",
+ "getLF",
+ "setLF",
+ "hasInterrupts",
+ "NoFurtherLoadsPending"
+ ]
+
+
+ DIRECT_TCG_FUNC_TRANSLATIONS = {
+ "CLZ" => "tcg_gen_clz_tl",
+ "CTZ" => "tcg_gen_ctz_tl",
+ "CRLSB" => "tcg_gen_clrsb_tl",
+ "SignExtend16to32" => "tcg_gen_ext16s_tl"
+ }
+end
diff --git a/target/arc/semfunc_generator/modules/Pass.rb b/target/arc/semfunc_generator/modules/Pass.rb
new file mode 100644
index 0000000000..b4f0382d6a
--- /dev/null
+++ b/target/arc/semfunc_generator/modules/Pass.rb
@@ -0,0 +1,11 @@
+module Pass
+
+ def name
+ return self.class
+ end
+
+ def execute(ast)
+ return task(ast)
+ end
+
+end
diff --git a/target/arc/semfunc_generator/modules/SemanticFunctionASTBlockOperators.rb b/target/arc/semfunc_generator/modules/SemanticFunctionASTBlockOperators.rb
new file mode 100644
index 0000000000..774c43dcc8
--- /dev/null
+++ b/target/arc/semfunc_generator/modules/SemanticFunctionASTBlockOperators.rb
@@ -0,0 +1,145 @@
+module SemanticFunctionASTBlockOperators
+
+ def prepend_in_stmt_list(elem, parents = {})
+ parent = parents[self]
+ # puts self
+ # parent = parents[parent] if parent.object[:type] != :stmt_list && parent.object[:type] != :block
+
+ if(parent != nil)
+ new_stmt_list = SemanticFunctionAST.new(type: :stmt_list, head: elem, tail: self)
+ parents[new_stmt_list] = parent
+ parents[self] = new_stmt_list
+
+ parent.object.each_pair do |k, v|
+ parent.object[k] = new_stmt_list if(v == self)
+ end
+ end
+ end
+
+ def append_in_stmt_list(stmt_list, parents = {})
+ return stmt_list if self.object[:type] == :nothing
+ raise "self is not of type :stmt_list\n#{self.inspect}" if self.object[:type] != :stmt_list
+
+ if(self.object[:tail].object[:type] == :nothing)
+ self.object[:tail] = stmt_list
+ else
+ self.object[:tail].append_in_stmt_list(stmt_list, parents)
+ end
+ end
+
+ def remove_from_stmt_list(parents = {})
+ elem = self.find_parent_node_with_type(:stmt_list, parents)
+ # puts parents.inspect
+ parent = parents[elem]
+ puts "BLING => #{parent.debug}"
+ parents.each_pair do |k, v|
+ puts "#{k.debug} => #{v.debug}"
+ end
+ puts parent
+ parent.object.each_pair do |k, v|
+ if(v == elem)
+ parent.object[k] = elem.object[:tail]
+ parents[parent.object[k]] = parent
+ end
+ end
+ end
+
+ def create_stmts_for_expression(tmp_vars = {})
+ ret = []
+ self.object.each_pair do |k, v|
+ if(v.class == SemanticFunctionAST && v.valid?)
+ ret += v.create_stmts_for_expression(tmp_vars)
+ end
+ end
+
+ case(object[:type])
+ when :binop
+ when :bincond
+ var = SemanticFunctionAST.createTmpVar("temp")
+ rhs = SemanticFunctionAST.new(type: object[:type], name: object[:name], lhs: tmp_vars[object[:lhs]], rhs: tmp_vars[object[:rhs]])
+ ret += [
+ # SemanticFunctionAST.function("createTmpVar", var),
+ SemanticFunctionAST.new(type: :assign, lhs: var, rhs: rhs)
+ ]
+ tmp_vars[self] = var
+ when :uniop
+ when :unicond
+ var = SemanticFunctionAST.createTmpVar("temp")
+ rhs = SemanticFunctionAST.new(type: object[:type], name: object[:name], rhs: tmp_vars[object[:rhs]])
+ ret += [
+ # SemanticFunctionAST.function("createTmpVar", var),
+ SemanticFunctionAST.new(type: :assign, lhs: var, rhs: rhs)
+ ]
+ tmp_vars[self] = var
+ else
+ tmp_vars[self] = self
+ end
+ return ret
+ end
+
+
+ def traverse_LR_TB(to_do = {}, parents = {}, &block)
+ to_do[self] ||= { pre_pend: [], post_pend: [], remove: false }
+
+ do_childs = yield self, to_do[self]
+
+ if(do_childs == true)
+ @object.each_pair do |k, e|
+ if(e.class == SemanticFunctionAST)
+ if(self.object[:type] == :stmt_list || self.object[:type] == :block)
+ parents[e] = self
+ else
+ parents[e] = parents[self]
+ end
+ e.traverse_LR_TB(to_do, parents, &block)
+ end
+ end
+ end
+
+ # If it is back to the head of the recursion
+ if(parents[self] == nil)
+ to_do.each_pair do |elem, to_do|
+ to_do[:pre_pend].each do |elem1|
+ elem.prepend_in_stmt_list(elem1, parents)
+ end
+
+ if(to_do[:remove] == true)
+ elem.remove_from_stmt_list(parents)
+ end
+ end
+ end
+ return self
+ end
+
+ def traverse_LR_BT(to_do = {}, parents = {}, &block)
+ to_do[self] ||= { pre_pend: [], post_pend: [], remove: false }
+
+ @object.each_pair do |k, e|
+ if(e.class == SemanticFunctionAST)
+ if(self.object[:type] == :stmt_list || self.object[:type] == :block)
+ parents[e] = self
+ else
+ parents[e] = parents[self]
+ end
+ e.traverse_LR_BT(to_do, parents, &block)
+ end
+ end
+
+ yield self, to_do[self]
+
+ # If it is back to the head of the recursion
+ if(parents[self] == nil)
+ to_do.each_pair do |elem, to_do|
+ to_do[:pre_pend].each do |elem1|
+ elem.prepend_in_stmt_list(elem1, parents)
+ end
+
+ if(to_do[:remove] == true)
+ elem.remove_from_stmt_list(parents)
+ end
+ end
+ end
+ return self
+ end
+
+end
diff --git a/target/arc/semfunc_generator/modules/SemanticFunctionASTFactory.rb b/target/arc/semfunc_generator/modules/SemanticFunctionASTFactory.rb
new file mode 100644
index 0000000000..14df3bcd67
--- /dev/null
+++ b/target/arc/semfunc_generator/modules/SemanticFunctionASTFactory.rb
@@ -0,0 +1,55 @@
+module SemanticFunctionASTFactory
+
+ def createIf(cond, else_label, done_label)
+ return SemanticFunctionAST.function("IF", cond.clone,
+ SemanticFunctionAST.function("goto", else_label),
+ SemanticFunctionAST.function("goto", done_label))
+ return SemanticFunctionAST.new(type: :func, name: "IF", args: [
+ cond.clone,
+ SemanticFunctionAST.new(type: :func, name: "goto", args: [ else_label ]),
+ SemanticFunctionAST.new(type: :func, name: "goto", args: [ done_label ])
+ ])
+ end
+
+ def createVar(varname)
+ return SemanticFunctionAST.new(type: :var, name: varname)
+ end
+
+ def notCond(cond)
+ return SemanticFunctionAST.new(type: :unicond, name: "!", rhs: cond)
+ end
+
+ def defLabel(label)
+ return SemanticFunctionAST.new(type: :func, name: "defLabel", args: [ label ])
+ end
+
+ def setLabel(label)
+ return SemanticFunctionAST.new(type: :func, name: "setLabel", args: [ label ])
+ end
+
+ def block(stmt_list)
+ return SemanticFunctionAST.new(type: :block, list: stmt_list)
+ end
+
+ def reset_counters
+ @__Label_counts = {}
+ end
+ def createTmpVar(label_prefix)
+ @__Label_counts ||= {}
+ @__Label_counts[label_prefix] ||= 0
+ @__Label_counts[label_prefix] += 1
+ count = @__Label_counts[label_prefix]
+ ret = createVar("#{label_prefix}_#{count}")
+ # puts ret.inspect
+ return ret
+ end
+
+ def createStmtListFromArray(array)
+ if(array.count > 0)
+ return SemanticFunctionAST.new(type: :stmt_list, head: array.shift, tail: createStmtListFromArray(array))
+ else
+ return SemanticFunctionAST.nothing
+ end
+ end
+
+end
diff --git a/target/arc/semfunc_generator/modules/Translator.rb b/target/arc/semfunc_generator/modules/Translator.rb
new file mode 100644
index 0000000000..d532e96363
--- /dev/null
+++ b/target/arc/semfunc_generator/modules/Translator.rb
@@ -0,0 +1,102 @@
+module Translator
+
+ # def map_for_variable
+ # if(rule_pattern.object[:name] =~ /^_(.*)$/)
+ # name = $1
+ # if name == ""
+ # name = "unname#{unname}"
+ # unname += 1
+ # end
+ # return name
+ # end
+
+ # Function that verifies is AST is compatible with AST Pattern
+ # The function results a hash of the mapping of variables and number elements
+ # the rule pattern
+ def is_a_match(ast, rule_pattern, unname = 1)
+ ret = { result: true, mappings: {} }
+
+ if(rule_pattern.class == Proc)
+
+ return rule_pattern.call(ast)
+ end
+
+ return ret if(rule_pattern.class == TrueClass)
+ ret[:result] &= false if(rule_pattern == nil || ast == nil)
+
+ if(ret[:result] == false)
+ return ret
+ end
+
+ if(rule_pattern.object[:name] =~ /^_(.*)$/)
+ name = $1
+ if name == ""
+ name = "unname#{unname}"
+ unname += 1
+ end
+
+ ret[:result] &= false if(ast.object[:type] != rule_pattern.object[:type]) if(rule_pattern.object[:type] != :var)
+ ret[:mappings][name] = ast.object[:name]
+ else
+ ret[:result] &= false if(ast.object[:type] != rule_pattern.object[:type])
+
+ # if(ast.object[:type] == :func)
+ if(ast.object[:name].class == String && ast.object[:type] != :var)
+ # puts "NOW THIS"
+ # puts ast.debug
+ # puts rule_pattern.inspect
+ ret[:result] = false if (ast.object[:name] != rule_pattern.object[:name])
+ end
+
+ if(ast.object[:type] == :var)
+ ret[:mappings][rule_pattern.object[:name]] = ast.object[:name]
+ elsif(ast.object[:type] == :number)
+ ret[:mappings][rule_pattern.object[:number]] = ast.object[:number].to_s
+ end
+ end
+
+ # puts "RULE = #{rule_pattern.debug}"
+ # puts "AST = #{ast.debug}"
+
+ if(ret[:result] == true)
+
+ if(rule_pattern.object[:type] == :func)
+ rule_pattern.object[:args].each_with_index do |arg_rule, i|
+ if(arg_rule.object[:type] == :var && arg_rule.object[:name] == "...")
+ # puts ast.inspect
+ ret[:mappings]["varargs_#{name}"] = ast.object[:args][i..-1] || []
+ elsif(ast.object[:args][i])
+ tmp = is_a_match(ast.object[:args][i], arg_rule, unname)
+ ret[:result] &= tmp[:result]
+ ret[:mappings].merge!(tmp[:mappings])
+ else
+ ret[:result] &= false
+ end
+ end
+ end
+
+ rule_pattern.object.each_pair do |k, v|
+ if(v.class == SemanticFunctionAST)
+ tmp = is_a_match(ast.object[k], v, unname)
+ ret[:result] &= tmp[:result]
+ ret[:mappings].merge!(tmp[:mappings])
+ end
+ end
+ end
+
+ return ret
+ end
+
+ def find_matching_rule(ast)
+ rules = self.translation_rules
+
+ rules.each_pair do |k, v|
+ tmp = is_a_match(ast, k)
+ if(tmp[:result] == true)
+ return { replacement: v, mappings: tmp[:mappings], index: rules.keys.index(k) }
+ end
+ end
+ return nil
+ end
+
+end
diff --git a/target/arc/semfunc_generator/modules/TranslatorAST.rb b/target/arc/semfunc_generator/modules/TranslatorAST.rb
new file mode 100644
index 0000000000..595b9437e6
--- /dev/null
+++ b/target/arc/semfunc_generator/modules/TranslatorAST.rb
@@ -0,0 +1,80 @@
+require_relative "Translator.rb"
+
+module TranslatorAST
+
+ include Translator
+
+ def replace_variable(str, variable, replace)
+ return str.gsub(/(\$#{variable})([^$a-zA-Z_])/, "#{replace}\\2")
+ end
+
+ def replace(stmt_ast, to_do = {})
+ match = find_matching_rule(stmt_ast)
+ if(match)
+ repl = match[:replacement]
+ mappings = match[:mappings]
+
+ if(repl.class == SemanticFunctionAST)
+ repl.traverse_LR_TB do |ast|
+ ast.object.each_pair do |ok1, ov1|
+ if(ov1.class == String && ov1 =~ /^\$(.+)$/)
+ repl.object[ok1] = mappings[$1]
+ end
+ end
+ end
+
+ # mappings.each_pair do |k, v|
+ # if(v.class == String)
+ # # repl = repl.gsub(/(\$#{k})([^a-zA-Z_]+)/, "#{v}\\2")
+ # repl = replace_variable(repl, k, v)
+ # elsif(v.class == Array)
+ # tmp = v.map { |e| e.debug }.join(", ")
+ # repl = replace_variable(repl, k, tmp)
+ # end
+ # end
+ return repl
+ elsif(repl.class == Proc)
+ repl.call(stmt_ast, repl, mappings, to_do)
+ elsif(repl == nil)
+ # Do nothing
+ else
+ return "CAN'T REPLACE ELEMENT OF CLASS #{repl.class}"
+ end
+ else
+ ret = "/*\n"
+ ret += "FAILED TO MATCH { #{stmt_ast.debug }}\n"
+ ret += " -----------------------\n"
+ ret += stmt_ast.inspect
+ ret += "\n -----------------------\n"
+ ret += "*/"
+ return ret
+ end
+ end
+
+ def generate_for_stmt(ast, to_do)
+ object = ast.object
+ case(object[:type])
+ when :assign, :func, :if
+ # puts ast.inspect
+ # puts "HERE at #{object[:type]} (#{ast.debug})"
+ tmp = replace(ast, to_do)
+ ret = false
+ when :stmt_list, :block
+ ret = true
+ else
+ # puts "Stopping at #{object[:type]}"
+ ret = false
+ end
+ return ret
+ end
+
+ def generate(full_ast)
+ result = ""
+ full_ast.traverse_LR_TB do |ast, to_do|
+ ret = generate_for_stmt(ast, to_do)
+ ret
+ end
+ return result
+ end
+
+end
diff --git a/target/arc/semfunc_generator/modules/TranslatorFinal.rb b/target/arc/semfunc_generator/modules/TranslatorFinal.rb
new file mode 100644
index 0000000000..9ca9e080b5
--- /dev/null
+++ b/target/arc/semfunc_generator/modules/TranslatorFinal.rb
@@ -0,0 +1,103 @@
+require_relative 'Translator.rb'
+
+module TranslatorFinal
+
+ include Translator
+
+ def replace_variable(str, variable, replace)
+ # puts "REPLACE #{str}. #{variable}, #{replace}"
+ replace = replace.gsub("@", "")
+ # = $1 if replace =~ /\@(.+)/
+ return str.gsub(/(\$#{variable})([^$a-zA-Z_])?/, "#{replace}\\2")
+ end
+
+ def replace(stmt_ast, to_do = {}, debug = true)
+ ret = ""
+ match = find_matching_rule(stmt_ast)
+ if(match)
+ repl = match[:replacement]
+ mappings = match[:mappings]
+
+ ret += " // Rule with index #{match[:index]}\n" if debug == true
+
+ if(repl.class == String)
+ mappings.each_pair do |k, v|
+
+ if(v.class == String)
+ # puts v.inspect
+ # puts "TRUE" if(v =~ /(true|false)/)
+
+ # repl = repl.gsub(/(\$#{k})([^a-zA-Z_]+)/, "#{v}\\2")
+ # if(!stmt_ast.hasAttr?(:static))
+ v = "arc_#{v}" if (v =~ /(true|false)/)
+ # end
+ repl = replace_variable(repl, k, v)
+
+ elsif(v.class == Array)
+ # puts "STMT_AST = #{stmt_ast.pp}"
+ tmp = v.map { |e| e.debug }.join(", ")
+ repl = replace_variable(repl, k, tmp)
+ end
+ end
+ return ret + repl
+ elsif(repl.class == Proc)
+ repl = repl.call(stmt_ast, repl, mappings, to_do)
+ if(repl.class == String)
+ if(!stmt_ast.hasAttr?(:static))
+ v = "arc_#{v}" if (v =~ /(true|false)/)
+ end
+ mappings.each_pair { |k, v| repl = replace_variable(repl, k, v) }
+ ret += repl
+ else
+ ret += "RESULT SHOULD BE A String ELEMENT."
+ end
+ return ret
+ else
+ return "CAN'T REPLACE ELEMENT OF CLASS #{repl.class}"
+ end
+ else
+ ret = "/*\n"
+ ret += "FAILED TO MATCH { #{stmt_ast.debug }}\n"
+ ret += " -----------------------\n"
+ ret += stmt_ast.inspect
+ ret += "\n -----------------------\n"
+ ret += "*/"
+ return ret
+ end
+ end
+
+ def generate(full_ast, debug = false)
+ result = ""
+ full_ast.traverse_LR_TB do |ast, to_do|
+ ret = true
+ object = ast.object
+ case(object[:type])
+ when :if
+ result += " if (#{object[:cond].pp}) {\n"
+ tmp = generate(object[:then], debug)
+ result += " #{tmp};\n"
+ result += " }\n"
+ if(object[:else].valid?)
+ result += " else {\n"
+ tmp = generate(object[:else], debug)
+ result += " #{tmp};\n"
+ result += " }\n"
+ end
+ ret = false
+ when :assign, :func
+ # puts "HERE at #{object[:type]} (#{ast.debug})"
+ tmp = replace(ast, to_do, debug)
+ result += " #{tmp};\n"
+ ret = false
+ when :stmt_list, :block
+ ret = true
+ else
+ # puts "Stopping at #{object[:type]}"
+ ret = false
+ end
+ ret
+ end
+ return result
+ end
+
+end
diff --git a/target/arc/semfunc_generator/parsers/SemanticFunctionParser.tab.rb b/target/arc/semfunc_generator/parsers/SemanticFunctionParser.tab.rb
new file mode 100644
index 0000000000..e0634d5a33
--- /dev/null
+++ b/target/arc/semfunc_generator/parsers/SemanticFunctionParser.tab.rb
@@ -0,0 +1,553 @@
+#
+# DO NOT MODIFY!!!!
+# This file is automatically generated by Racc 1.4.12
+# from Racc grammer file "".
+#
+
+require 'racc/parser.rb'
+class SemanticFunctionParser < Racc::Parser
+
+module_eval(<<'...end SemanticFunctionParser.y/module_eval...', 'SemanticFunctionParser.y', 66)
+
+def parse(str)
+ orig_str = str
+ str = str.gsub(" ", "").gsub("\n", "").gsub("\r", "")
+ @yydebug = true
+ @q = []
+ until str.empty?
+ append = ""
+ case str
+ when /\A(if)/
+ @q.push [:IF, $1]
+ when /\A(else)/
+ @q.push [:ELSE, $1]
+ when /\A(while)/
+ @q.push [:WHILE, $1]
+ when /\A(&&|\|\||\^\^)/
+ @q.push [:BINCOND, $1]
+ when /\A(&|\||\^|<<|>>|-|\+|\/|\*)/
+ @q.push [:BINOP, $1]
+ when /\A(==|!=|<=|<|>=|>)/
+ @q.push [:BINCOMP, $1]
+ when /\A([\~!])/
+ @q.push [:UNIOP, $1]
+ when /\A(a)\]/
+ @q.push [:STRING, $1]
+ append = "]"
+ when /\A(^[a-zA-Z][a-zA-Z0-9]*)\(/
+ @q.push [:FUNC, $1]
+ append = '('
+ when /\A(@?[a-zA-Z_][a-zA-Z0-9_]*)/
+ @q.push [:VAR, $1]
+ when /\A0x([0-9a-fA-F])+/
+ @q.push [:HEX_NUMBER, $&.to_i(16)]
+ when /\A\d+/
+ @q.push [:NUMBER, $&.to_i]
+ when /\A.|\n/o
+ s = $&
+ @q.push [s, s]
+# # when /\A([\+\-\*\/]|<<|>>|&)/
+# # @q.push [:BINOP, $1]
+ end
+ str = append + $'
+ end
+ @q.push [false, '$end']
+# begin
+ do_parse
+# rescue
+# return SemanticFunctionAST.error("Error parsing: --#{orig_str}--")
+# end
+end
+
+ def next_token
+ @q.shift
+ end
+
+ def on_error(t, val, vstack)
+ raise ParseError, sprintf("\nparse error on value %s (%s)",
+ val.inspect, token_to_str(t) || '?')
+ end
+
+...end SemanticFunctionParser.y/module_eval...
+##### State transition tables begin ###
+
+racc_action_table = [
+ 7, 7, 8, 8, 53, 52, 2, 2, 12, 11,
+ 51, 9, 9, 7, 7, 8, 8, 7, 17, 8,
+ 10, 10, 18, 2, 9, 9, 53, 52, 9, 7,
+ 7, 8, 8, 10, 10, 2, 2, 10, 19, 47,
+ 9, 9, 29, 20, 9, 28, 62, 21, 33, 10,
+ 10, 34, 35, 10, 39, 47, 9, 37, 53, 52,
+ 33, 22, 62, 34, 35, 10, 39, 23, 9, 37,
+ 24, 24, 33, 53, 52, 34, 35, 10, 39, 58,
+ 9, 37, 47, 50, 33, 53, 52, 34, 35, 10,
+ 29, 67, 9, 28, 47, 59, 33, 60, 47, 34,
+ 35, 10, 29, 63, 9, 28, 47, 70, 33, 53,
+ nil, 34, 35, 10, 39, nil, 9, 37, nil, nil,
+ 33, nil, nil, 34, 35, 10, 39, nil, 9, 37,
+ nil, nil, 33, nil, nil, 34, 35, 10, 29, nil,
+ 9, 28, nil, nil, 33, nil, nil, 34, 35, 10,
+ 39, nil, 9, 37, nil, nil, 33, nil, nil, 34,
+ 35, 10, 39, nil, 9, 37, nil, nil, 33, nil,
+ nil, 34, 35, 10, 39, nil, 9, 37, nil, nil,
+ 33, nil, nil, 34, 35, 10, 47, -26, -26 ]
+
+racc_action_check = [
+ 0, 2, 0, 2, 36, 36, 0, 2, 2, 1,
+ 36, 0, 2, 16, 24, 16, 24, 51, 5, 51,
+ 0, 2, 7, 51, 16, 24, 44, 44, 51, 58,
+ 70, 58, 70, 16, 24, 58, 70, 51, 8, 49,
+ 58, 70, 17, 9, 17, 17, 49, 11, 17, 58,
+ 70, 17, 17, 17, 18, 56, 18, 18, 55, 55,
+ 18, 13, 56, 18, 18, 18, 19, 14, 19, 19,
+ 15, 25, 19, 41, 41, 19, 19, 19, 20, 41,
+ 20, 20, 27, 33, 20, 57, 57, 20, 20, 20,
+ 28, 57, 28, 28, 38, 42, 28, 45, 48, 28,
+ 28, 28, 29, 50, 29, 29, 54, 64, 29, 65,
+ nil, 29, 29, 29, 37, nil, 37, 37, nil, nil,
+ 37, nil, nil, 37, 37, 37, 39, nil, 39, 39,
+ nil, nil, 39, nil, nil, 39, 39, 39, 47, nil,
+ 47, 47, nil, nil, 47, nil, nil, 47, 47, 47,
+ 52, nil, 52, 52, nil, nil, 52, nil, nil, 52,
+ 52, 52, 53, nil, 53, 53, nil, nil, 53, nil,
+ nil, 53, 53, 53, 60, nil, 60, 60, nil, nil,
+ 60, nil, nil, 60, 60, 60, 43, 43, 43 ]
+
+racc_action_pointer = [
+ -3, 9, -2, nil, nil, 7, nil, 10, 26, 31,
+ nil, 47, nil, 51, 57, 53, 10, 30, 42, 54,
+ 66, nil, nil, nil, 11, 54, nil, 76, 78, 90,
+ nil, nil, nil, 64, nil, nil, -3, 102, 88, 114,
+ nil, 66, 82, 180, 19, 81, nil, 126, 92, 33,
+ 83, 14, 138, 150, 100, 51, 49, 78, 26, nil,
+ 162, nil, nil, nil, 103, 102, nil, nil, nil, nil,
+ 27, nil ]
+
+racc_action_default = [
+ -37, -37, -37, -4, -5, -37, -7, -37, -37, -37,
+ -36, -37, -1, -37, -37, -4, -5, -37, -37, -37,
+ -21, 72, -2, -3, -30, -31, -29, -6, -37, -37,
+ -15, -16, -32, -37, -34, -35, -37, -37, -26, -37,
+ -16, -37, -37, -17, -18, -20, -28, -37, -12, -37,
+ -37, -37, -37, -37, -12, -25, -26, -37, -37, -11,
+ -21, -13, -14, -33, -9, -23, -24, -22, -10, -19,
+ -37, -8 ]
+
+racc_goto_table = [
+ 1, 5, 13, 5, 6, 42, 6, 27, nil, nil,
+ 43, 31, 36, 41, nil, nil, 14, 5, 48, 49,
+ 6, 15, 31, 31, nil, 5, 16, 54, 6, 56,
+ 26, 55, nil, 57, nil, 25, nil, 61, 46, nil,
+ 16, 31, nil, 25, nil, 69, 65, 66, 16, nil,
+ 43, 64, 5, nil, nil, 6, nil, nil, 68, 5,
+ nil, nil, 6, nil, nil, nil, nil, nil, nil, nil,
+ 71, 5, nil, nil, 6 ]
+
+racc_goto_check = [
+ 1, 5, 1, 5, 7, 9, 7, 6, nil, nil,
+ 6, 10, 8, 8, nil, nil, 2, 5, 6, 6,
+ 7, 3, 10, 10, nil, 5, 4, 6, 7, 6,
+ 2, 8, nil, 8, nil, 3, nil, 6, 2, nil,
+ 4, 10, nil, 3, nil, 9, 8, 8, 4, nil,
+ 6, 1, 5, nil, nil, 7, nil, nil, 1, 5,
+ nil, nil, 7, nil, nil, nil, nil, nil, nil, nil,
+ 1, 5, nil, nil, 7 ]
+
+racc_goto_pointer = [
+ nil, 0, 14, 19, 24, 1, -10, 4, -6, -15,
+ -6, nil ]
+
+racc_goto_default = [
+ nil, nil, nil, 3, 4, 32, 38, 30, 44, nil,
+ 40, 45 ]
+
+racc_reduce_table = [
+ 0, 0, :racc_error,
+ 2, 25, :_reduce_1,
+ 3, 25, :_reduce_2,
+ 3, 25, :_reduce_3,
+ 1, 25, :_reduce_4,
+ 1, 27, :_reduce_5,
+ 3, 27, :_reduce_6,
+ 1, 27, :_reduce_7,
+ 7, 28, :_reduce_8,
+ 5, 28, :_reduce_9,
+ 5, 28, :_reduce_10,
+ 4, 31, :_reduce_11,
+ 2, 30, :_reduce_12,
+ 3, 30, :_reduce_13,
+ 3, 30, :_reduce_14,
+ 1, 30, :_reduce_15,
+ 1, 30, :_reduce_16,
+ 1, 35, :_reduce_17,
+ 1, 35, :_reduce_18,
+ 3, 33, :_reduce_19,
+ 1, 33, :_reduce_20,
+ 0, 33, :_reduce_21,
+ 3, 32, :_reduce_22,
+ 3, 32, :_reduce_23,
+ 3, 32, :_reduce_24,
+ 2, 32, :_reduce_25,
+ 1, 32, :_reduce_26,
+ 1, 32, :_reduce_27,
+ 3, 26, :_reduce_28,
+ 2, 26, :_reduce_29,
+ 2, 26, :_reduce_30,
+ 1, 26, :_reduce_31,
+ 1, 34, :_reduce_32,
+ 3, 34, :_reduce_33,
+ 1, 34, :_reduce_34,
+ 1, 34, :_reduce_35,
+ 1, 29, :_reduce_36 ]
+
+racc_reduce_n = 37
+
+racc_shift_n = 72
+
+racc_token_table = {
+ false => 0,
+ :error => 1,
+ :UMINUS => 2,
+ :IF => 3,
+ :ELSE => 4,
+ :WHILE => 5,
+ :BINOP => 6,
+ :BINCOMP => 7,
+ :BINCOND => 8,
+ "{" => 9,
+ "}" => 10,
+ "=" => 11,
+ "(" => 12,
+ ")" => 13,
+ :FUNC => 14,
+ :UNIOP => 15,
+ "," => 16,
+ ";" => 17,
+ "[" => 18,
+ :STRING => 19,
+ "]" => 20,
+ :NUMBER => 21,
+ :HEX_NUMBER => 22,
+ :VAR => 23 }
+
+racc_nt_base = 24
+
+racc_use_result_var = true
+
+Racc_arg = [
+ racc_action_table,
+ racc_action_check,
+ racc_action_default,
+ racc_action_pointer,
+ racc_goto_table,
+ racc_goto_check,
+ racc_goto_default,
+ racc_goto_pointer,
+ racc_nt_base,
+ racc_reduce_table,
+ racc_token_table,
+ racc_shift_n,
+ racc_reduce_n,
+ racc_use_result_var ]
+
+Racc_token_to_s_table = [
+ "$end",
+ "error",
+ "UMINUS",
+ "IF",
+ "ELSE",
+ "WHILE",
+ "BINOP",
+ "BINCOMP",
+ "BINCOND",
+ "\"{\"",
+ "\"}\"",
+ "\"=\"",
+ "\"(\"",
+ "\")\"",
+ "FUNC",
+ "UNIOP",
+ "\",\"",
+ "\";\"",
+ "\"[\"",
+ "STRING",
+ "\"]\"",
+ "NUMBER",
+ "HEX_NUMBER",
+ "VAR",
+ "$start",
+ "block",
+ "stmt_list",
+ "stmt",
+ "block_stmt",
+ "var",
+ "expr",
+ "func",
+ "cond",
+ "func_args",
+ "leaf",
+ "arg" ]
+
+Racc_debug_parser = false
+
+##### State transition tables end #####
+
+# reduce 0 omitted
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 12)
+ def _reduce_1(val, _values, result)
+ return SemanticFunctionAST.new({ type: :block, list: SemanticFunctionAST.nothing })
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 13)
+ def _reduce_2(val, _values, result)
+ return val[1]
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 14)
+ def _reduce_3(val, _values, result)
+ return SemanticFunctionAST.new({ type: :block, list: val[1] })
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 15)
+ def _reduce_4(val, _values, result)
+ return SemanticFunctionAST.new({ type: :block, list: SemanticFunctionAST.new({ type: :stmt_list, head: val[0], tail: SemanticFunctionAST.nothing }) })
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 17)
+ def _reduce_5(val, _values, result)
+ return val[0]
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 18)
+ def _reduce_6(val, _values, result)
+ return SemanticFunctionAST.new({ type: :assign, lhs: val[0], rhs: val[2] })
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 19)
+ def _reduce_7(val, _values, result)
+ return val[0]
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 21)
+ def _reduce_8(val, _values, result)
+ return SemanticFunctionAST.new({ type: :if, cond: val[2], then: val[4], else: val[6] })
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 22)
+ def _reduce_9(val, _values, result)
+ return SemanticFunctionAST.new({ type: :if, cond: val[2], then: val[4], else: SemanticFunctionAST.nothing })
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 23)
+ def _reduce_10(val, _values, result)
+ return SemanticFunctionAST.new({ type: :while, cond: val[2], loop: val[4] })
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 25)
+ def _reduce_11(val, _values, result)
+ return SemanticFunctionAST.new({ type: :func, name: val[0], args: val[2] })
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 27)
+ def _reduce_12(val, _values, result)
+ return SemanticFunctionAST.new({ type: :uniop, name: val[0], rhs: val[1] })
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 28)
+ def _reduce_13(val, _values, result)
+ return SemanticFunctionAST.new({ type: :binop, name: val[1], lhs: val[0], rhs: val[2] })
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 29)
+ def _reduce_14(val, _values, result)
+ return val[1]
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 30)
+ def _reduce_15(val, _values, result)
+ return val[0]
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 31)
+ def _reduce_16(val, _values, result)
+ return val[0]
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 33)
+ def _reduce_17(val, _values, result)
+ val[0]
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 34)
+ def _reduce_18(val, _values, result)
+ val[0]
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 37)
+ def _reduce_19(val, _values, result)
+ return [val[0]] + val[2]
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 38)
+ def _reduce_20(val, _values, result)
+ return [val[0]]
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 39)
+ def _reduce_21(val, _values, result)
+ return []
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 41)
+ def _reduce_22(val, _values, result)
+ return val[1]
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 42)
+ def _reduce_23(val, _values, result)
+ return SemanticFunctionAST.new({ type: :bincond, name: val[1], lhs: val[0], rhs: val[2] })
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 43)
+ def _reduce_24(val, _values, result)
+ return SemanticFunctionAST.new({ type: :bincond, name: val[1], lhs: val[0], rhs: val[2] })
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 44)
+ def _reduce_25(val, _values, result)
+ return SemanticFunctionAST.new({ type: :unicond, name: val[0], rhs: val[1] })
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 45)
+ def _reduce_26(val, _values, result)
+ val[0]
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 46)
+ def _reduce_27(val, _values, result)
+ val[0]
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 50)
+ def _reduce_28(val, _values, result)
+ return SemanticFunctionAST.new({ type: :stmt_list, head: val[0], tail: val[2]})
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 51)
+ def _reduce_29(val, _values, result)
+ return SemanticFunctionAST.new({ type: :stmt_list, head: val[0], tail: val[1]})
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 52)
+ def _reduce_30(val, _values, result)
+ return SemanticFunctionAST.new({ type: :stmt_list, head: val[0], tail: SemanticFunctionAST.nothing })
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 53)
+ def _reduce_31(val, _values, result)
+ return SemanticFunctionAST.new({ type: :stmt_list, head: val[0], tail: SemanticFunctionAST.nothing })
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 55)
+ def _reduce_32(val, _values, result)
+ return val[0]
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 56)
+ def _reduce_33(val, _values, result)
+ return SemanticFunctionAST.new(type: :string, value: val[0])
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 57)
+ def _reduce_34(val, _values, result)
+ return SemanticFunctionAST.new(type: :number, number: val[0])
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 58)
+ def _reduce_35(val, _values, result)
+ return SemanticFunctionAST.new(type: :number, number: val[0])
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'SemanticFunctionParser.y', 60)
+ def _reduce_36(val, _values, result)
+ return SemanticFunctionAST.new(type: :var, name: val[0])
+ result
+ end
+.,.,
+
+def _reduce_none(val, _values, result)
+ val[0]
+end
+
+end # class SemanticFunctionParser
diff --git a/target/arc/semfunc_generator/parsers/SemanticFunctionParser.y b/target/arc/semfunc_generator/parsers/SemanticFunctionParser.y
new file mode 100644
index 0000000000..31cec1734c
--- /dev/null
+++ b/target/arc/semfunc_generator/parsers/SemanticFunctionParser.y
@@ -0,0 +1,126 @@
+class SemanticFunctionParser
+
+prechigh
+ nonassoc UMINUS IF ELSE WHILE
+# left '*' '/'
+# left '+' '-'
+ left BINOP BINCOMP
+ left BINCOND
+preclow
+
+rule
+
+ block: '{' '}' { return SemanticFunctionAST.new({ type: :block, list: SemanticFunctionAST.nothing }) }
+ block: '{' block '}' { return val[1] }
+ | '{' stmt_list '}' { return SemanticFunctionAST.new({ type: :block, list: val[1] }) }
+ | stmt { return SemanticFunctionAST.new({ type: :block, list: SemanticFunctionAST.new({ type: :stmt_list, head: val[0], tail: SemanticFunctionAST.nothing }) }) }
+
+ stmt: block_stmt { return val[0] }
+ | var '=' expr { return SemanticFunctionAST.new({ type: :assign, lhs: val[0], rhs: val[2] }) }
+ | func { return val[0] }
+
+ block_stmt: IF '(' cond ')' block ELSE block { return SemanticFunctionAST.new({ type: :if, cond: val[2], then: val[4], else: val[6] }) }
+ | IF '(' cond ')' block { return SemanticFunctionAST.new({ type: :if, cond: val[2], then: val[4], else: SemanticFunctionAST.nothing }) }
+ | WHILE '(' cond ')' block { return SemanticFunctionAST.new({ type: :while, cond: val[2], loop: val[4] }) }
+
+ func: FUNC '(' func_args ')' { return SemanticFunctionAST.new({ type: :func, name: val[0], args: val[2] }) }
+
+ expr: UNIOP expr { return SemanticFunctionAST.new({ type: :uniop, name: val[0], rhs: val[1] }) }
+ | expr BINOP expr { return SemanticFunctionAST.new({ type: :binop, name: val[1], lhs: val[0], rhs: val[2] }) }
+ | '(' expr ')' { return val[1] }
+ | func { return val[0] }
+ | leaf { return val[0] }
+
+ arg: expr {val[0]}
+ | cond {val[0]}
+# | '{' stmt_list '}' { return SemanticFunctionAST.new({ type: :block, list: val[1] }) }
+
+ func_args: arg ',' func_args { return [val[0]] + val[2] }
+ | arg { return [val[0]] }
+ | { return [] }
+
+ cond: '(' cond ')' { return val[1] }
+ | cond BINCOND cond { return SemanticFunctionAST.new({ type: :bincond, name: val[1], lhs: val[0], rhs: val[2] }) }
+ | cond BINCOMP cond { return SemanticFunctionAST.new({ type: :bincond, name: val[1], lhs: val[0], rhs: val[2] }) }
+ | UNIOP cond { return SemanticFunctionAST.new({ type: :unicond, name: val[0], rhs: val[1] }) }
+ | expr { val[0] }
+ | leaf { val[0] }
+# | expr { return SemanticFunctionAST.new({ type: :cond, value: val[0] }) }
+# | leaf { return SemanticFunctionAST.new({ type: :cond, value: val[0] }) }
+
+ stmt_list: stmt ';' stmt_list { return SemanticFunctionAST.new({ type: :stmt_list, head: val[0], tail: val[2]}) }
+ | block_stmt stmt_list { return SemanticFunctionAST.new({ type: :stmt_list, head: val[0], tail: val[1]}) }
+ | stmt ';' { return SemanticFunctionAST.new({ type: :stmt_list, head: val[0], tail: SemanticFunctionAST.nothing }) }
+ | stmt { return SemanticFunctionAST.new({ type: :stmt_list, head: val[0], tail: SemanticFunctionAST.nothing }) }
+
+ leaf: var { return val[0] }
+ | '[' STRING ']' { return SemanticFunctionAST.new(type: :string, value: val[0]) }
+ | NUMBER { return SemanticFunctionAST.new(type: :number, number: val[0]) }
+ | HEX_NUMBER { return SemanticFunctionAST.new(type: :number, number: val[0]) }
+
+ var: VAR { return SemanticFunctionAST.new(type: :var, name: val[0]) }
+
+end
+
+---- inner
+
+def parse(str)
+ orig_str = str
+ str = str.gsub(" ", "").gsub("\n", "").gsub("\r", "")
+ @yydebug = true
+ @q = []
+ until str.empty?
+ append = ""
+ case str
+ when /\A(if)/
+ @q.push [:IF, $1]
+ when /\A(else)/
+ @q.push [:ELSE, $1]
+ when /\A(while)/
+ @q.push [:WHILE, $1]
+ when /\A(&&|\|\||\^\^)/
+ @q.push [:BINCOND, $1]
+ when /\A(&|\||\^|<<|>>|-|\+|\/|\*)/
+ @q.push [:BINOP, $1]
+ when /\A(==|!=|<=|<|>=|>)/
+ @q.push [:BINCOMP, $1]
+ when /\A([\~!])/
+ @q.push [:UNIOP, $1]
+ when /\A(a)\]/
+ @q.push [:STRING, $1]
+ append = "]"
+ when /\A(^[a-zA-Z][a-zA-Z0-9]*)\(/
+ @q.push [:FUNC, $1]
+ append = '('
+ when /\A(@?[a-zA-Z_][a-zA-Z0-9_]*)/
+ @q.push [:VAR, $1]
+ when /\A0x([0-9a-fA-F])+/
+ @q.push [:HEX_NUMBER, $&.to_i(16)]
+ when /\A\d+/
+ @q.push [:NUMBER, $&.to_i]
+ when /\A.|\n/o
+ s = $&
+ @q.push [s, s]
+# # when /\A([\+\-\*\/]|<<|>>|&)/
+# # @q.push [:BINOP, $1]
+ end
+ str = append + $'
+ end
+ @q.push [false, '$end']
+# begin
+ do_parse
+# rescue
+# return SemanticFunctionAST.error("Error parsing: --#{orig_str}--")
+# end
+end
+
+ def next_token
+ @q.shift
+ end
+
+ def on_error(t, val, vstack)
+ raise ParseError, sprintf("\nparse error on value %s (%s)",
+ val.inspect, token_to_str(t) || '?')
+ end
+
+---- footer
diff --git a/target/arc/semfunc_generator/regenerate_semfunc.rb b/target/arc/semfunc_generator/regenerate_semfunc.rb
new file mode 100644
index 0000000000..61936f9d7c
--- /dev/null
+++ b/target/arc/semfunc_generator/regenerate_semfunc.rb
@@ -0,0 +1,245 @@
+#!/usr/bin/env ruby
+
+require 'erb'
+require_relative 'init.rb'
+
+HEADER = <<EOF
+/*
+ * QEMU ARC CPU
+ *
+ * Copyright (c) 2020 Synppsys Inc.
+ * Contributed by Cupertino Miranda <cmiranda at synopsys.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * http://www.gnu.org/licenses/lgpl-2.1.html
+ */
+
+#include "qemu/osdep.h"
+#include "translate.h"
+#include "target/arc/semfunc.h"
+
+EOF
+
+ERB_TEMPLATE = <<EOF
+/*
+ * <%= @name %>
+<%= print_lists(" Variables", @variables) %>
+<%= print_lists(" Functions", @functions) %>
+ * --- code ---
+<%= @pretty_code %>
+ */
+
+int
+arc_gen_<%= @name %>(DisasCtxt *ctx<%= @tcg_variables %>)
+{
+ int ret = DISAS_NEXT;
+<%= @tcg_code %>
+ return ret;
+}
+
+
+EOF
+
+def print_lists(name, elems, max_length = 80, prefix: " * ")
+ ret = ""
+ to_print = prefix + name + ": "
+
+ elems.each_with_index do |e, i|
+ if(to_print.length + e.length + 2 > max_length)
+ ret += to_print.gsub(/ $/, "") + "\n"
+ to_print = prefix + (" " * (name.length + 2))
+ end
+
+ to_print += e
+ to_print += ", " if i + 1 != elems.length
+ end
+
+ ret += to_print
+ return ret.split("\n").map { |a| a.gsub(/[ \t]+$/, "") }.join("\n")
+end
+
+
+def error(line_num, message)
+ puts "Error at semfunc.c:#{line_num} -- #{message}"
+ exit(-1)
+end
+
+EMPTY_ENTRY = {
+ name: "invalid",
+ code: ""
+}
+
+funcs = {}
+funcs_in_order = []
+
+current_func = nil
+func_name = nil
+in_comment = false
+in_code = false
+in_field_read = nil
+line_num = 1;
+File.read("../semfunc.c").each_line do |l|
+ if(l =~ /^\/[*]/)
+ # puts "ENTERED IN COMMENT at line #{line_num}"
+ in_comment = true
+ elsif (in_comment == true && l =~ /\*\/[ \t]*$/)
+ in_comment = false
+ if(in_code == true)
+ # puts "END_COMMENT at line #{line_num}"
+ # puts current_func[:code]
+ current_func[:ast] = SemanticFunctionParser.new.parse(current_func[:code])
+ funcs[func_name] = current_func
+ funcs_in_order.push(func_name)
+ end
+ in_code = false
+ elsif (in_comment == true)
+ if(l =~ /^ [*][ ]+([A-Z0-9_]+)$/)
+ func_name = $1
+ current_func = EMPTY_ENTRY.clone()
+ current_func["Variables"] = []
+ current_func["Functions"] = []
+ current_func[:name] = func_name
+ current_func[:code] = ""
+ elsif(in_field_read != nil && l =~ /^ [*][ \t]+([@a-zA-Z0-9, ]+)$/)
+ data = $1
+ data.split(/,[ ]*/).each do |d_entry|
+ current_func[in_field_read].push(d_entry)
+ end
+ elsif(l =~ /^ [*][ \t]+([a-zA-Z]+): ([@a-zA-Z0-9, ]+)$/)
+ field = $1
+ data = $2
+ if(current_func[field].nil?)
+ error(line_num, "Field '#{field}' not valid.")
+ end
+ data.split(/,[ ]*/).each do |d_entry|
+ #puts "#{field} = #{d_entry}"
+ current_func[field].push(d_entry)
+ end
+ in_field_read = field
+ elsif(l =~ /^ [*] --- code ---$/)
+ in_field_read = nil
+ in_code = true
+ elsif(in_code)
+ current_func[:code] = "#{current_func[:code]}#{l[3..-1]}"
+ end
+ end
+ line_num += 1
+end
+
+def fix_indentation_tcg_code(code)
+
+ ret = ""
+ in_comment = false
+ indent = 0
+ #puts code
+
+ code.split("\n").each_with_index do |line, idx|
+
+ if(in_comment == false)
+ if(line =~ /^[ \t]+$/)
+ #ret += "1: "
+ ret += "\n"
+ elsif(line =~ /^[ \t;]+$/)
+ #ret += "2: \n"
+ ret += ""
+ else
+ indent -= (line.scan(/}/).size - 1) * 4
+
+ #ret += "9: "
+ line =~ /^[ \t]*(.+)$/
+ code = $1
+ ret += "#{" "*indent}#{$1}\n"
+
+ indent += (line.scan(/{/).size - 1) * 4
+ end
+ end
+
+ end
+
+ ret1 = ""
+ in_else = nil
+ else_content = ""
+ perhaps_else = false;
+ ret.split("\n").each_with_index do |line, i|
+ if(line.index("else {") != nil)
+ #puts "1- #{line}"
+ in_else = i
+ else_content = " else {\n"
+ elsif(line.index("}") != nil && in_else != nil)
+ if(in_else + 1 != i)
+ #puts "2- #{line}"
+ else_content += line
+ ret1 += else_content + "\n"
+ end
+ else_content = ""
+ in_else = nil
+ elsif(line.index("}") != nil && in_else == nil)
+ ret1 += line
+ else_content += line
+ perhaps_else = true
+ else
+ if(in_else != nil)
+ perhaps_else = false
+ #puts "3- #{line}"
+ else_content += line + "\n"
+ else
+ #puts "4- #{line}"
+ ret1 += "\n" if(perhaps_else == true)
+ ret1 += "#{line}\n"
+ perhaps_else = false
+ end
+ end
+ end
+ return ret1
+end
+
+
+class FuncBinding
+ def initialize(data, opts)
+ @name = data[:name]
+ @functions = data["Functions"]
+ @variables = data["Variables"]
+ @code = data[:code].gsub(/\t/, '')
+ @pretty_code = data[:code].split("\n").map { |l| " * #{l}" }.join("\n")
+ @ast = SemanticFunctionParser.new.parse(@code)
+ tcg_code = QEmuCompiler.new.generate(@ast, [], opts[:debug])
+ @tcg_code = fix_indentation_tcg_code(tcg_code)
+ @tcg_variables = @variables.map { |a| "TCGv #{a.gsub("@", "")}"}.unshift("").join(", ")
+ end
+end
+
+
+# Options parsing
+opts = { debug: false }
+while(ARGV.count > 0)
+ opt = ARGV.shift
+ if(opt == '-f' && (tmp = ARGV.shift) != nil)
+ opts[:filter] = tmp
+ elsif(opt == '-d')
+ puts "HERE"
+ opts[:debug] = true
+ end
+end
+
+puts HEADER
+funcs_in_order.each do |name|
+ next if(opts[:filter] && opts[:filter] != name)
+ data = funcs[name]
+ #puts name
+ next if data[:code].nil?
+ erb = ERB.new(ERB_TEMPLATE)
+ MyClass = erb.def_class(FuncBinding, 'render()')
+ puts MyClass.new(data, opts).render()
+ self.class.send(:remove_const, :MyClass)
+end
--
2.20.1
More information about the linux-snps-arc
mailing list