From 188850c5871a5feb9b22c0af032ae31f491afdd1 Mon Sep 17 00:00:00 2001 From: Sandro Grebant <sandro.grebant@univ-lille.fr> Date: Fri, 31 Mar 2023 14:17:02 +0200 Subject: [PATCH] Add optimized compiler to repository --- compiler/AUTHORS | 2 + compiler/compiler.py | 281 +++++++++++++++++++++++++++++++++++++++++++ compiler/test.c | 28 +++++ 3 files changed, 311 insertions(+) create mode 100644 compiler/AUTHORS create mode 100644 compiler/compiler.py create mode 100644 compiler/test.c diff --git a/compiler/AUTHORS b/compiler/AUTHORS new file mode 100644 index 0000000..4564a4f --- /dev/null +++ b/compiler/AUTHORS @@ -0,0 +1,2 @@ +Clement Ballabriga <Clement.Ballabriga@univ-lille.fr> +Sandro Grebant <sandro.grebant@univ-lille.fr> \ No newline at end of file diff --git a/compiler/compiler.py b/compiler/compiler.py new file mode 100644 index 0000000..3442e68 --- /dev/null +++ b/compiler/compiler.py @@ -0,0 +1,281 @@ +#!/usr/bin/env python3 + +LOOP_TOP = -1 #whole program + +_id = -1 +def new_id(): + global _id + _id = _id + 1 + return _id + +indent_size = 4 +indent = " " * indent_size + +statements = "" +params = set() +vars = set() +def var(s): + global vars + global declarations + if s not in vars: + vars.add(s) + declarations = declarations + indent + "int " + s + ";\n" + return s + +def param(p): + global params + if p not in params: + params.add(p) + return p + +declarations = "" +def code(s): + global statements + statements = statements + indent + s + "\n" + +class Expression(object): + def __init__(self): + raise NotImplementedError("Is abstract class") + +class Seq(Expression): + def __init__(self, children): + self.children = children + + def generate(self): + my_id = new_id() + children_results = [c.generate() for c in self.children] + + eta_count = max([len(cr[1]) for cr in children_results]) + eta_vars = [] + loop_id_var = var("seq_" + str(my_id) + "_loop_id") + my_loop_id = max([cr[0] for cr in children_results]) #assume loop id are in topological order + code(loop_id_var + " = " + str(my_loop_id) + ";") + for i in range(eta_count): + eta_vars.append(var("seq_" + str(my_id) + "_eta_" + str(i))) + + eta_vars_code = [ev + " = 0" for ev in eta_vars] + + for cr in children_results: + (child_loop_id, child_vars ) = cr + for cv in range(eta_count): + if cv < len(child_vars): + eta_vars_code[cv] += " + " + child_vars[cv] + else: + eta_vars_code[cv] += " + " + child_vars[-1] + + for evc in eta_vars_code: + code(evc + ";") + + + return (my_loop_id, eta_vars) + +class Alt(Expression): + + def __init__(self, left, right): + self.left = left + self.right = right + + def __init__(self, children): + if len(children) == 1: + self.left = children[0] + self.right = Constant(LOOP_TOP, [0]) + return + middle = len(children)//2 + + left = children[0:middle] + right = children[middle:] + + if len(left) == 1: + self.left = left[0] + else: + self.left = Alt(left) + + if len(right) == 1: + self.right = right[0] + else: + self.right = Alt(right) + + def helper(self, result_vars, big_vars, small_vars, last_expr=None, indent=0): + if small_vars > big_vars: + (small_vars, big_vars) = (big_vars, small_vars) + if len(small_vars) == 0: + for i in range(len(result_vars)): + bi = i + if bi >= len(big_vars): + bi = len(big_vars) - 1 + if last_expr: + code(indent*" " + result_vars[i] + " = " + last_expr + ";") + else: + code(indent*" " + result_vars[i] + " = " + big_vars[bi] + ";") + return + code(indent*" " + "if (" + big_vars[0] + " > " + small_vars[0] + ") {") + code((indent + indent_size)*" " + result_vars[0] + " = " + big_vars[0] + ";") + self.helper(result_vars[1:], big_vars[1:], small_vars, big_vars[0], indent + indent_size) + code(indent*" " + "} else {") + code((indent + indent_size) *" " + result_vars[0] + " = " + small_vars[0] + ";") + self.helper(result_vars[1:], big_vars, small_vars[1:], small_vars[0], indent + indent_size) + code(indent*" " + "}") + + def generate(self): + my_id = new_id() + (left_loop_id, left_vars) = self.left.generate() + (right_loop_id, right_vars) = self.right.generate() + result_vars = [] + for i in range(len(left_vars) + len(right_vars) - 1): + result_vars.append(var("alt_" + str(my_id) + "_eta_" + str(i))) + + self.helper(result_vars, left_vars, right_vars) + + return (max(left_loop_id, right_loop_id), result_vars) + +class Loop(Expression): + def __init__(self, body, loop_id, bound): + self.body = body + self.loop_id = loop_id + self.bound = bound + + def generate(self): + my_id = self.loop_id + (body_loop_id, body_vars) = self.body.generate() + + if isinstance(self.bound, ParamBound): + bound_var = var("loop_" + str(my_id) + "_bound") + code(bound_var + " = " + self.bound.param_bound + ";") + else: + bound_var = var("loop_" + str(my_id) + "_bound") + code(bound_var + " = " + str(self.bound.bound_value) + ";") + + if body_loop_id == self.loop_id: + result_var = var("loop_" + str(my_id) + "_eta_0") + for i in range(len(body_vars)): + if i == 0: + code("if (" + str(bound_var) + " == " + str(i) + ") " + result_var + " = 0;") + elif i < len(body_vars) - 1: + code("if (" + str(bound_var) + " == " + str(i) + ") " + result_var + " = (" + " + ".join(body_vars[0:i]) + ");") + else: + code("if (" + str(bound_var) + " >= " + str(i) + ") " + result_var + " = (" + " + ".join(body_vars[0:-1]) + ") + " + body_vars[-1] + "*(" + bound_var + " - " + str(i) + ");") + return (LOOP_TOP, [result_var]) + else: + result_vars = [] + for i in range(len(body_vars)): + result_vars.append(var("loop_" + str(my_id) + "_eta_" + str(i))) + for i in range(len(body_vars) + 1): + paquets = "" + j = 0 + if i == 0: + while j < len(body_vars): + paquets += result_vars[j] + " = 0; " + j += 1 + else: + k = 0 + if i == len(body_vars): + bound_expr = bound_var + else: + bound_expr = str(i) + while j < len(body_vars): + paquets += result_vars[k] + " = " + paquets += " + ".join(body_vars[j: j + i]) + if (j + i) > len(body_vars): + paquets += " + " + body_vars[-1] + "*" + str((j + i) - len(body_vars)) + if i == len(body_vars): + paquets += " + (" + bound_expr + " - " + str(i) + ")*" + body_vars[-1] + paquets += "; " + j = j + i + k = k + 1 + while k < len(body_vars): + paquets += result_vars[k] + " = " + body_vars[-1] + "*" + bound_expr + "; " + k = k + 1 + + if i == len(body_vars): + cond = ">=" + else: + cond = "==" + code("if (" + str(bound_var) + " " + cond + " " + str(i) + ") { " + paquets + "}") + return (body_loop_id, result_vars) + + +class Constant(Expression): + def __init__(self, loop_id, eta): + self.eta = eta + self.loop_id = loop_id + + def generate(self): + my_id = new_id() + code(var("cst_" + str(my_id) + "_loop_id") + " = " + str(self.loop_id) + ";") + for i in range(len(self.eta)): + code(var("cst_" + str(my_id) + "_eta_" + str(i)) + " = " + str(self.eta[i]) + ";") + return (self.loop_id, ["cst_" + str(my_id) + "_eta_" + str(i) for i in range(len(self.eta))]) + +class Conditional(Expression): + def __init__(self, test, tree): + self.test = test + self.tree = tree + + def generate(self): + my_id = new_id() + result = self.tree.generate() + + # compute the params + for i in range(4): + param_str = "param_" + str(i) + if param_str in self.test: + param(param_str) + + # compute the result + loop_id = result[0] + eta = result[1] + eta_count = len(eta) + for i in range(eta_count): + code(eta[i] + " = (" + self.test + ") ? " + eta[i] + " : 0;") + return (loop_id, eta) + +class Bound(object): + def __init__(self): + raise NotImplementedError("Is abstract class") + +class ParamBound(Bound): + def __init__(self, param_bound): + # compute the params + for i in range(4): + param_str = "param_" + str(i) + if param_str in param_bound: + param(param_str) + + self.param_bound = param_bound + +class ConstantBound(Bound): + def __init__(self, bound_value): + self.bound_value = bound_value + + +def generate(formula): + (loop_id, eta_vars) = formula.generate() + code("return " + eta_vars[0] + ";") + # Documentation print + print("/*") + print(" * WCET evaluation function") + for p in sorted(list(params)): + pnum = int(p.replace("param_",""))+1 + print(" * @param " + p + " ", pnum, "th procedure argument") + print(" * @return The WCET of the procedure depending on its arguments") + print(" */") + # End of documentation + print("int eval(", end="") + first = True + for p in sorted(list(params)): + if not first: + print(", ", end="") + print("int " + p, end="") + first = False + print(") {\n" + declarations + "\n" + statements + "}\n") + +#audiobeam_find_max_in_arr = Alt([Constant(0, [1331, 1321, 500, 40, 30, 10]), Loop(Constant(2, [325, 265, 100, 50, 20]), 0, ParamBound(1))]) +#audiobeam_find_max_in_arr = Seq([Constant(0, [1331, 1321]), Loop(Constant(2, [325, 265]), 2, ConstantBound(2))]) +#generate(audiobeam_find_max_in_arr) + +#toto = Loop(Seq([Constant(0, [20, 10]), Constant(0, [100])]), 0, ParamBound(1)) +#generate(toto) + + + + diff --git a/compiler/test.c b/compiler/test.c new file mode 100644 index 0000000..2af6dec --- /dev/null +++ b/compiler/test.c @@ -0,0 +1,28 @@ +#include <stdio.h> +#include <time.h> + +extern int eval(int param); + +#define NANO 1000000000 +#define ITERATIONS 50000000 + +int main(int argc, char *argv) { + /* Volatile to force evaluation each loop iteration */ + volatile int paramval = 0; + volatile int result = 0; + + struct timespec ts1, ts2; + while (scanf("%d", ¶mval) == 1) { + volatile int result = 0; + clock_gettime(CLOCK_REALTIME, &ts1); + for (int i = 0; i < ITERATIONS; i++) { + result = eval(paramval); + } + clock_gettime(CLOCK_REALTIME, &ts2); + long long nsec = ts2.tv_nsec; + nsec -= ts1.tv_nsec; + if (ts2.tv_sec > ts1.tv_sec) + nsec += (ts2.tv_sec - ts1.tv_sec)*NANO; + printf("Param=%d WCET=%d, time=%llu nsec for %u iters (%llu nsec/iter)\n", paramval, result, nsec, ITERATIONS, nsec/ITERATIONS); + } +} -- GitLab