diff --git a/README.md b/README.md index 3afdb63..1b5ebb1 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Optimization Level: - modify variables without using a temporary 2. more optimizations - remove uncalled functions + - constant folding 3. turns on some potentially unsafe optimizations - augmented assignment and pre/postincrement/decrement don't modify `__rax` - returning from main becomes equivalent to `end` diff --git a/c2logic/compiler.py b/c2logic/compiler.py index 5ca0604..05a25d5 100644 --- a/c2logic/compiler.py +++ b/c2logic/compiler.py @@ -5,10 +5,11 @@ from dataclasses import dataclass from pycparser import c_ast, parse_file from pycparser.c_ast import ( - Compound, Constant, DeclList, Enum, FileAST, FuncDecl, Struct, TypeDecl, Typename + Compound, Constant, DeclList, Enum, FileAST, FuncDecl, Struct, TypeDecl, Typename, BinaryOp as + ast_BinaryOp ) -from .consts import func_binary_ops, func_unary_ops, SPECIAL_VARS +from .consts import func_binary_ops, func_unary_ops, SPECIAL_VARS, binary_ops_python from .instructions import ( Instruction, Noop, @@ -54,6 +55,29 @@ class Variable(): name: str """ +def int_constant_fold(node): + if isinstance(node, ast_BinaryOp): + left = int_constant_fold(node.left) + right = int_constant_fold(node.right) + if isinstance(left, Constant) and isinstance( + right, Constant + ) and left.type == 'int' and right.type == 'int': + try: + new_constant = Constant( + 'int', str(binary_ops_python[node.op](int(left.value), int(right.value))) + ) + return new_constant + except KeyError: + node.left = left + node.right = right + return node + else: + node.left = left + node.right = right + return node + else: + return node + class Compiler(c_ast.NodeVisitor): def __init__(self, opt_level=0): self.opt_level = opt_level @@ -345,6 +369,16 @@ class Compiler(c_ast.NodeVisitor): self.push(Set("__rax", varname)) def visit_BinaryOp(self, node): + if self.opt_level >= 2: + new_node = int_constant_fold(node) + if isinstance(new_node, ast_BinaryOp): + self.visit_BinaryOp_base(new_node) + else: + self.visit(new_node) + else: + self.visit_BinaryOp_base(node) + + def visit_BinaryOp_base(self, node): self.visit(node.left) left = self.get_special_var("__rbx") self.set_to_rax(left) diff --git a/c2logic/consts.py b/c2logic/consts.py index 2ef1d36..f06a0ee 100644 --- a/c2logic/consts.py +++ b/c2logic/consts.py @@ -1,4 +1,6 @@ # see https://github.com/Anuken/Mindustry/blob/master/core/src/mindustry/logic/LogicOp.java +import operator + binary_ops = { "+": "add", "-": "sub", @@ -17,7 +19,24 @@ binary_ops = { "&": "and", "^": "xor" } - +binary_ops_python = { + "+": operator.add, + "-": operator.sub, + "*": operator.mul, + "/": operator.floordiv, + "%": operator.mod, + "==": operator.eq, + "!=": operator.ne, + "<": operator.lt, + "<=": operator.le, + ">": operator.gt, + ">=": operator.ge, + ">>": operator.rshift, + "<<": operator.lshift, + "|": operator.or_, + "&": operator.and_, + "^": operator.xor, +} condition_ops = { "==": "equal", "!=": "notEqual",