mirror of
https://github.com/michaelcmartin/Ophis.git
synced 2024-05-28 09:41:29 +00:00
f8bc917601
This pass actually isn't an optimizer in that it produces larger binaries when it triggers. However, the larger binaries created will actually assemble properly. The ExtendBranches pass detects Relative instructions (that is, branches) that extend past the signed-8-bit range Relative instructions permit, and replaces them with a branch-jump combination with identical semantics. Since this may be evidence of a program bug, Ophis will warn when the optimization is triggered. Due to similarities between this pass and UpdateLabels, both passes have been refactored in passing.
161 lines
5.4 KiB
Python
161 lines
5.4 KiB
Python
"""Ophis Intermediate Representation
|
|
|
|
Classes for representing the Intermediate nodes upon which the
|
|
assembler passes operate."""
|
|
|
|
# Copyright 2002-2012 Michael C. Martin and additional contributors.
|
|
# You may use, modify, and distribute this file under the MIT
|
|
# license: See README for details.
|
|
|
|
import Ophis.Errors as Err
|
|
|
|
class Node:
|
|
"""The default IR Node
|
|
Instances of Node always have the three fields ppt(Program Point),
|
|
nodetype(a string), and data (a list)."""
|
|
def __init__(self, ppt, nodetype, *data):
|
|
self.ppt = ppt
|
|
self.nodetype = nodetype
|
|
self.data = list(data)
|
|
def accept(self, asmpass, env=None):
|
|
"""Implements the Visitor pattern for an assembler pass.
|
|
Calls the routine 'asmpass.visitTYPE(self, env)' where
|
|
TYPE is the value of self.nodetype."""
|
|
Err.currentpoint = self.ppt
|
|
routine = getattr(asmpass, "visit"+self.nodetype, asmpass.visitUnknown)
|
|
routine(self, env)
|
|
def __str__(self):
|
|
if self.nodetype != "SEQUENCE":
|
|
return str(self.ppt)+": "+self.nodetype+" - "+" ".join(map(str, self.data))
|
|
else:
|
|
return "\n".join(map(str, self.data))
|
|
def __repr__(self):
|
|
args = [self.ppt, self.nodetype] + self.data
|
|
return "Node(" + ", ".join(map(repr, args)) + ")"
|
|
|
|
NullNode = Node("<none>", "None")
|
|
|
|
def SequenceNode(ppt, nodelist):
|
|
return Node(ppt, "SEQUENCE", *nodelist)
|
|
|
|
class Expr:
|
|
"""Base class for Ophis expressions
|
|
All expressions have a field called "data" and a boolean field
|
|
called "hardcoded". An expression is hardcoded if it has no
|
|
symbolic values in it."""
|
|
def __init__(self, data):
|
|
self.data = data
|
|
self.hardcoded = 0
|
|
def __str__(self):
|
|
return "<UNKNOWN: "+`self.data`+">"
|
|
def valid(self, env=None, PCvalid=0):
|
|
"""Returns true if the the expression can be successfully
|
|
evaluated in the specified environment."""
|
|
return 0
|
|
def value(self, env=None):
|
|
"Evaluates this expression in the given environment."
|
|
return None
|
|
|
|
class ConstantExpr(Expr):
|
|
"Represents a numeric constant"
|
|
def __init__(self, data):
|
|
self.data = data
|
|
self.hardcoded = 1
|
|
def __str__(self):
|
|
return str(self.data)
|
|
def valid(self, env=None, PCvalid=0):
|
|
return 1
|
|
def value(self, env=None):
|
|
return self.data
|
|
|
|
class LabelExpr(Expr):
|
|
"Represents a symbolic constant"
|
|
def __init__(self, data):
|
|
self.data = data
|
|
self.hardcoded = 0
|
|
def __str__(self):
|
|
return self.data
|
|
def valid(self, env=None, PCvalid=0):
|
|
return (env is not None) and self.data in env
|
|
def value(self, env=None):
|
|
return env[self.data]
|
|
|
|
class PCExpr(Expr):
|
|
"Represents the current program counter: ^"
|
|
def __init__(self):
|
|
self.hardcoded = 0
|
|
def __str__(self):
|
|
return "^"
|
|
def valid(self, env=None, PCvalid=0):
|
|
return env is not None and PCvalid
|
|
def value(self, env=None):
|
|
return env.getPC()
|
|
|
|
class HighByteExpr(Expr):
|
|
"Represents the expression >{data}"
|
|
def __init__(self, data):
|
|
self.data = data
|
|
self.hardcoded = data.hardcoded
|
|
def __str__(self):
|
|
return ">"+str(self.data)
|
|
def valid(self, env=None, PCvalid=0):
|
|
return self.data.valid(env, PCvalid)
|
|
def value(self, env=None):
|
|
val = self.data.value(env)
|
|
return (val >> 8) & 0xff
|
|
|
|
class LowByteExpr(Expr):
|
|
"Represents the expression <{data}"
|
|
def __init__(self, data):
|
|
self.data = data
|
|
self.hardcoded = data.hardcoded
|
|
def __str__(self):
|
|
return "<"+str(self.data)
|
|
def valid(self, env=None, PCvalid=0):
|
|
return self.data.valid(env, PCvalid)
|
|
def value(self, env=None):
|
|
val = self.data.value(env)
|
|
return val & 0xff
|
|
|
|
class SequenceExpr(Expr):
|
|
"""Represents an interleaving of operands (of type Expr) and
|
|
operators (of type String). Subclasses must provide a routine
|
|
operate(self, firstarg, op, secondarg) that evaluates the
|
|
operator."""
|
|
def __init__(self, data):
|
|
"""Constructor for Sequence Expressions. Results will be
|
|
screwy if the data inpot isn't a list with types
|
|
[Expr, str, Expr, str, Expr, str, ... Expr, str, Expr]."""
|
|
self.data = data
|
|
self.operands = [x for x in data if isinstance(x, Expr)]
|
|
self.operators = [x for x in data if type(x)==str]
|
|
for i in self.operands:
|
|
if not i.hardcoded:
|
|
self.hardcoded = 0
|
|
break
|
|
else:
|
|
self.hardcoded = 1
|
|
def __str__(self):
|
|
return "["+" ".join(map(str, self.data))+"]"
|
|
def valid(self, env=None, PCvalid=0):
|
|
for i in self.operands:
|
|
if not i.valid(env, PCvalid):
|
|
return 0
|
|
return 1
|
|
def value(self, env=None):
|
|
subs = map((lambda x: x.value(env)), self.operands)
|
|
result = subs[0]
|
|
index = 1
|
|
for op in self.operators:
|
|
result = self.operate(result, op, subs[index])
|
|
index += 1
|
|
return result
|
|
def operate(self, start, op, other):
|
|
if op=="*": return start * other
|
|
if op=="/": return start // other
|
|
if op=="+": return start + other
|
|
if op=="-": return start - other
|
|
if op=="&": return start & other
|
|
if op=="|": return start | other
|
|
if op=="^": return start ^ other
|