# Helper function
regs = ['RA', 'RS', 'RB', 'RC', 'RT']
-fregs = ['FRA', 'FRS', 'FRB', 'FRC', 'FRT']
+fregs = ['FRA', 'FRS', 'FRB', 'FRC', 'FRT', 'FRS']
+SPECIAL_HELPERS = {'concat', 'MEM', 'GPR', 'FPR', 'SPR'}
+
def Assign(autoassign, assignname, left, right, iea_mode):
names = []
- print("Assign", assignname, left, right)
+ print("Assign", autoassign, assignname, left, right)
if isinstance(left, ast.Name):
# Single assignment on left
# XXX when doing IntClass, which will have an "eq" function,
elif isinstance(left, ast.Tuple):
# List of things - make sure they are Name nodes
names = []
- for child in left.getChildren():
+ for child in left.elts:
if not isinstance(child, ast.Name):
raise SyntaxError("that assignment not supported")
- names.append(child.name)
- ass_list = [ast.AssName(name, 'OP_ASSIGN') for name in names]
- return ast.Assign([ast.AssTuple(ass_list)], right)
+ names.append(child.id)
+ ass_list = [ast.Name(name, ast.Store()) for name in names]
+ return ast.Assign([ast.Tuple(ass_list)], right)
elif isinstance(left, ast.Subscript):
ls = left.slice
# XXX changing meaning of "undefined" to a function
- #if (isinstance(ls, ast.Slice) and isinstance(right, ast.Name) and
+ # if (isinstance(ls, ast.Slice) and isinstance(right, ast.Name) and
# right.id == 'undefined'):
# # undefined needs to be copied the exact same slice
# right = ast.Subscript(right, ls, ast.Load())
# the declaration makes the slice-assignment "work"
lower, upper, step = ls.lower, ls.upper, ls.step
print("lower, upper, step", repr(lower), repr(upper), step)
- if not isinstance(lower, ast.Constant) or \
- not isinstance(upper, ast.Constant):
- return res
- qty = ast.Num(upper.value-lower.value)
+ # XXX relax constraint that indices on auto-assign have
+ # to be constants x[0:32]
+ # if not isinstance(lower, ast.Constant) or \
+ # not isinstance(upper, ast.Constant):
+ # return res
+ qty = ast.BinOp(upper, binary_ops['-'], lower)
keywords = [ast.keyword(arg='repeat', value=qty)]
l = [ast.Num(0)]
right = ast.Call(ast.Name("concat", ast.Load()), l, keywords)
# identify SelectableInt pattern [something] * N
# must return concat(something, repeat=N)
+# here is a TEMPORARY hack to support minimal expressions
+# such as (XLEN-16), looking for ast.BinOp
+# have to keep an eye on this
def identify_sint_mul_pattern(p):
+ """here we are looking for patterns of this type:
+ [item] * something
+ these must specifically be returned as concat(item, repeat=something)
+ """
+ #print ("identify_sint_mul_pattern")
+ # for pat in p:
+ # print(" ", astor.dump_tree(pat))
if p[2] != '*': # multiply
return False
- if not isinstance(p[3], ast.Constant): # rhs = Num
+ if (not isinstance(p[3], ast.Constant) and # rhs = Num
+ not isinstance(p[3], ast.BinOp) and # rhs = (XLEN-something)
+ (not isinstance(p[3], ast.Name) and # rhs = {a variable}
+ not isinstance(p[3], ast.Attribute))): # rhs = XLEN
return False
if not isinstance(p[1], ast.List): # lhs is a list
return False
name = arg.id
if name in regs + fregs:
read_regs.add(name)
+ # special-case, these functions must NOT be made "self.xxxx"
+ if atom.id not in SPECIAL_HELPERS:
+ name = ast.Name("self", ast.Load())
+ atom = ast.Attribute(name, atom, ast.Load())
return ast.Call(atom, trailer[1], [])
# if p[1].id == 'print':
# p[0] = ast.Printnl(ast.Tuple(p[2][1]), None, None)
if isinstance(idx, ast.Name) and idx.id in regs + fregs:
read_regs.add(idx.id)
if isinstance(idx, ast.Name) and idx.id in regs:
- print ("single atom subscript, underscored", idx.id)
+ print("single atom subscript, underscored", idx.id)
idx = ast.Name("_%s" % idx.id, ast.Load())
else:
idx = ast.Slice(subs[0], subs[1], None)
("left", "INVERT"),
)
- def __init__(self, form, include_carry_in_write=False):
- self.include_ca_in_write = include_carry_in_write
+ def reset(self):
self.gprs = {}
- form = self.sd.sigforms[form]
- print(form)
- formkeys = form._asdict().keys()
+ if self.form is not None:
+ form = self.sd.sigforms[self.form]
+ print(form)
+ formkeys = form._asdict().keys()
+ else:
+ formkeys = []
self.declared_vars = set()
+ self.fnparm_vars = set()
for rname in regs + fregs:
self.gprs[rname] = None
self.declared_vars.add(rname)
self.write_regs = OrderedSet()
self.special_regs = OrderedSet() # see p_atom_name
+ def __init__(self, form, include_carry_in_write=False, helper=False):
+ self.include_ca_in_write = include_carry_in_write
+ self.helper = helper
+ self.form = form
+ self.reset()
+
# The grammar comments come from Python's Grammar/Grammar file
# NB: compound_stmt in single_input is followed by extra NEWLINE!
def p_funcdef(self, p):
"funcdef : DEF NAME parameters COLON suite"
- p[0] = ast.FunctionDef(p[2], p[3], p[5], ())
+ p[0] = ast.FunctionDef(p[2], p[3], p[5], (), lineno=p.lineno(2))
+ # reset function parameters after suite is identified
+ self.fnparm_vars = set()
# parameters: '(' [varargslist] ')'
def p_parameters(self, p):
"""parameters : LPAR RPAR
| LPAR varargslist RPAR"""
- if len(p) == 3:
- args = []
- else:
- args = p[2]
+ args = []
+ if self.helper:
+ args.append("self")
+ if len(p) != 3:
+ args += p[2]
p[0] = ast.arguments(args=args, vararg=None, kwarg=None, defaults=[])
+ # during the time between parameters identified and suite is not
+ # there is a window of opportunity to declare the function parameters
+ # in-scope, for use to not overwrite them with auto-assign
+ self.fnparm_vars = set()
+ for arg in args:
+ print("adding fn parm", arg)
+ self.fnparm_vars.add(arg)
# varargslist: (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] |
# '**' NAME) |
"""varargslist : varargslist COMMA NAME
| NAME"""
if len(p) == 4:
- p[0] = p[1] + p[3]
+ print(p[1], p[3])
+ p[0] = p[1] + [p[3]]
else:
p[0] = [p[1]]
| expr_stmt"""
if isinstance(p[1], ast.Call):
p[0] = ast.Expr(p[1])
- elif isinstance(p[1], ast.Name) and p[1].id == 'TRAP':
- # TRAP needs to actually be a function
+ elif isinstance(p[1], ast.Name) and p[1].id not in SPECIAL_HELPERS:
+ fname = p[1].id
name = ast.Name("self", ast.Load())
- name = ast.Attribute(name, "TRAP", ast.Load())
+ name = ast.Attribute(name, fname, ast.Load())
p[0] = ast.Call(name, [], [])
else:
p[0] = p[1]
if isinstance(p[1], ast.Name):
name = p[1].id
elif isinstance(p[1], ast.Subscript):
+ print("assign subscript", p[1].value,
+ self.declared_vars,
+ self.fnparm_vars,
+ self.special_regs)
+ print(astor.dump_tree(p[1]))
if isinstance(p[1].value, ast.Name):
name = p[1].value.id
+ print("assign subscript value to name", name)
if name in self.gprs:
# add to list of uninitialised
self.uninit_regs.add(name)
+ # work out if this is an ininitialised variable
+ # that should be auto-assigned simply by being "sliced"
autoassign = (name not in self.declared_vars and
+ name not in self.fnparm_vars and
name not in self.special_regs)
elif isinstance(p[1], ast.Call) and p[1].func.id in \
- ['GPR', 'FPR', 'SPR']:
+ ['GPR', 'FPR', 'SPR']:
print(astor.dump_tree(p[1]))
# replace GPR(x) with GPR[x]
idx = p[1].args[0].id
- ridx = ast.Name("_%s" % idx, ast.Load())
+ if idx in regs + fregs:
+ ridx = ast.Name("_%s" % idx, ast.Load())
+ else:
+ ridx = ast.Name(idx, ast.Load())
p[1] = ast.Subscript(p[1].func, ridx, ast.Load())
- self.read_regs.add(idx) # add to list of regs to read
+ if idx in self.gprs:
+ self.read_regs.add(idx) # add to list of regs to read
elif isinstance(p[1], ast.Call) and p[1].func.id == 'MEM':
print("mem assign")
print(astor.dump_tree(p[1]))
p[0] = ast.Break()
def p_for_stmt(self, p):
- """for_stmt : FOR atom EQ test TO test COLON suite
- | DO atom EQ test TO test COLON suite
+ """for_stmt : FOR atom EQ comparison TO comparison COLON suite
+ | DO atom EQ comparison TO comparison COLON suite
"""
start = p[4]
end = p[6]
- if start.value > end.value: # start greater than end, must go -ve
- # auto-subtract-one (sigh) due to python range
- end = ast.BinOp(p[6], ast.Add(), ast.Constant(-1))
- arange = [start, end, ast.Constant(-1)]
- else:
- # auto-add-one (sigh) due to python range
- end = ast.BinOp(p[6], ast.Add(), ast.Constant(1))
- arange = [start, end]
- it = ast.Call(ast.Name("range", ast.Load()), arange, [])
+ it = ast.Call(ast.Name("RANGE", ast.Load()), (start, end), [])
p[0] = ast.For(p[2], it, p[8], [])
def p_while_stmt(self, p):
| comparison BITXOR comparison
| comparison BITAND comparison
| PLUS comparison
- | comparison MINUS
+ | MINUS comparison
| INVERT comparison
| comparison APPEND comparison
| power"""
p[0] = ast.Call(ast.Name("concat", ast.Load()), l, keywords)
else:
p[0] = ast.BinOp(p[1], binary_ops[p[2]], p[3])
+ # HORRENDOUS hack, add brackets around the bin-op by
+ # creating a function call with a *blank* function name!
+ # XXX argh doesn't work because of analysis of
+ # identify_sint_pattern
+ #p[0] = ast.Call(ast.Name("", ast.Load()), [p[0]], [])
elif len(p) == 3:
if isinstance(p[2], str) and p[2] == '-':
p[0] = ast.UnaryOp(unary_ops[p[2]], p[1])
name = p[1]
if name in self.available_op_fields:
self.op_fields.add(name)
- if name == 'overflow':
+ if name in ['overflow', 'CR0']:
self.write_regs.add(name)
if self.include_ca_in_write:
if name in ['CA', 'CA32']:
self.write_regs.add(name)
- if name in ['CR', 'LR', 'CTR', 'TAR', 'FPSCR', 'MSR', 'SVSTATE']:
+ if name in ['CR', 'LR', 'CTR', 'TAR', 'FPSCR', 'MSR',
+ 'SVSTATE', 'SVREMAP',
+ 'SVSHAPE0', 'SVSHAPE1', 'SVSHAPE2', 'SVSHAPE3']:
self.special_regs.add(name)
self.write_regs.add(name) # and add to list to write
- p[0] = ast.Name(id=name, ctx=ast.Load())
+ if name in {'XLEN'}:
+ attr = ast.Name("self", ast.Load())
+ p[0] = ast.Attribute(attr, name, ast.Load(), lineno=p.lineno(1))
+ else:
+ p[0] = ast.Name(id=name, ctx=ast.Load(), lineno=p.lineno(1))
def p_atom_number(self, p):
"""atom : BINARY
raise SyntaxError(p)
+_CACHE_DECODER = True
+_CACHED_DECODER = None
+
+
+def _create_cached_decoder():
+ global _CACHED_DECODER
+ if _CACHE_DECODER:
+ if _CACHED_DECODER is None:
+ _CACHED_DECODER = create_pdecode()
+ return _CACHED_DECODER
+ return create_pdecode()
+
+
class GardenSnakeParser(PowerParser):
- def __init__(self, lexer=None, debug=False, form=None, incl_carry=False):
- self.sd = create_pdecode()
- PowerParser.__init__(self, form, incl_carry)
+ def __init__(self, debug=False, form=None, incl_carry=False, helper=False):
+ if form is not None:
+ self.sd = _create_cached_decoder()
+ PowerParser.__init__(self, form, incl_carry, helper=helper)
self.debug = debug
- if lexer is None:
- lexer = IndentLexer(debug=0)
- self.lexer = lexer
- self.tokens = lexer.tokens
+ self.lexer = IndentLexer(debug=0)
+ self.tokens = self.lexer.tokens
self.parser = yacc.yacc(module=self, start="file_input_end",
debug=debug, write_tables=False)
def parse(self, code):
- # self.lexer.input(code)
+ self.reset()
result = self.parser.parse(code, lexer=self.lexer, debug=self.debug)
+ if self.helper:
+ result = [ast.ClassDef("ISACallerFnHelper", [
+ "ISACallerHelper"], [], result, decorator_list=[])]
return ast.Module(result)
class GardenSnakeCompiler(object):
- def __init__(self, debug=False, form=None, incl_carry=False):
+ def __init__(self, debug=False, form=None, incl_carry=False, helper=False):
if _CACHE_PARSERS:
try:
- parser = _CACHED_PARSERS[debug, form, incl_carry]
+ self.parser = _CACHED_PARSERS[debug, form, incl_carry, helper]
except KeyError:
- parser = GardenSnakeParser(debug=debug, form=form,
- incl_carry=incl_carry)
- _CACHED_PARSERS[debug, form, incl_carry] = parser
-
- self.parser = deepcopy(parser)
+ self.parser = GardenSnakeParser(
+ debug=debug, form=form, incl_carry=incl_carry,
+ helper=helper)
+ _CACHED_PARSERS[debug, form, incl_carry, helper] = self.parser
else:
self.parser = GardenSnakeParser(debug=debug, form=form,
- incl_carry=incl_carry)
+ incl_carry=incl_carry, helper=helper)
def compile(self, code, mode="exec", filename="<string>"):
tree = self.parser.parse(code)