Commit 5acd670a authored by Jayke Meijer's avatar Jayke Meijer

Fixed merge conflict

parents 16a7f083 b8616183
......@@ -12,3 +12,5 @@ parsetab.py
coverage/
build/
src/Makefile_old
in.s
out.s
BUILD=build/
CLEAN=src/*.pyc src/optimize/*.pyc
CLEAN=*.pyc src/*.pyc src/optimize/*.pyc parser.out parsetab.py
# Fix pdflatex search path
TGT_DIR :=
TGT_DOC :=
TGT_DIR := report
# Default target is 'all'. The 'build' target is defined here so that all
# sub rules.mk can add prerequisites to the 'build' target.
all:
build:
d := tests/
d := report/
include base.mk
include $(d)/rules.mk
.PHONY: doc
d := tests/
include base.mk
include $(d)/rules.mk
all: doc build
all: report
clean:
rm -rf $(CLEAN)
......
.file 1 "pi.c"
# GNU C 2.7.2.3 [AL 1.1, MM 40, tma 0.1] SimpleScalar running sstrix compiled by GNU C
# Cc1 defaults:
# -mgas -mgpOPT
# Cc1 arguments (-G value = 8, Cpu = default, ISA = 1):
# -quiet -dumpbase -o
gcc2_compiled.:
__gnu_compiled_c:
.rdata
.align 2
$LC0:
.ascii "Usage: %s <iterations>\n\000"
.sdata
.align 2
$LC3:
.ascii "%.10f\n\000"
.align 3
$LC1:
.word 0xffc00000 # 2147483647
.word 0x41dfffff
.align 3
$LC2:
.word 0x00000000 # 1
.word 0x3ff00000
.align 3
$LC4:
.word 0x00000000 # 4
.word 0x40100000
.text
.align 2
.globl main
.extern stderr, 4
.text
.loc 1 5
.ent main
main:
.frame $fp,56,$31 # vars= 32, regs= 2/0, args= 16, extra= 0
.mask 0xc0000000,-4
.fmask 0x00000000,0
subu $sp,$sp,56
sw $31,52($sp)
sw $fp,48($sp)
move $fp,$sp
sw $4,56($fp)
sw $5,60($fp)
jal __main
sw $0,24($fp)
lw $2,56($fp)
li $3,0x00000002 # 2
beq $2,$3,$L2
lw $2,60($fp)
lw $4,stderr
la $5,$LC0
lw $6,0($2)
jal fprintf
move $4,$0
jal exit
$L2:
lw $3,60($fp)
addu $2,$3,4
lw $4,0($2)
jal atoi
sw $2,20($fp)
li $4,0x00000001 # 1
jal srandom
sw $0,16($fp)
$L3:
lw $2,16($fp)
lw $3,20($fp)
slt $2,$2,$3
bne $2,$0,$L6
j $L4
$L6:
jal random
mtc1 $2,$f0
#nop
cvt.d.w $f0,$f0
l.d $f2,$LC1
div.d $f0,$f0,$f2
s.d $f0,32($fp)
jal random
mtc1 $2,$f0
#nop
cvt.d.w $f0,$f0
l.d $f2,$LC1
div.d $f0,$f0,$f2
s.d $f0,40($fp)
l.d $f0,32($fp)
l.d $f2,32($fp)
mul.d $f0,$f0,$f2
l.d $f2,40($fp)
l.d $f4,40($fp)
mul.d $f2,$f2,$f4
add.d $f0,$f0,$f2
l.d $f2,$LC2
c.le.d $f0,$f2
bc1f $L7
lw $3,24($fp)
addu $2,$3,1
move $3,$2
sw $3,24($fp)
$L7:
$L5:
lw $3,16($fp)
addu $2,$3,1
move $3,$2
sw $3,16($fp)
j $L3
$L4:
l.s $f0,24($fp)
#nop
cvt.d.w $f0,$f0
l.s $f2,20($fp)
#nop
cvt.d.w $f2,$f2
div.d $f0,$f0,$f2
l.d $f2,$LC4
mul.d $f0,$f0,$f2
la $4,$LC3
dmfc1 $6,$f0
jal printf
li $2,0x00000001 # 1
j $L1
$L1:
move $sp,$fp # sp not trusted here
lw $31,52($sp)
lw $fp,48($sp)
addu $sp,$sp,56
j $31
.end main
\ No newline at end of file
#include <stdio.h>
int main(void)
{
int a = 3, b = 5, d = 5, x = 100;
int c;
if (a > b)
{
int c = a + b;
d = 2;
}
c = 4;
return b * d + c;
}
#!/usr/bin/python
from src.parser import parse_file
from src.optimize import optimize
from src.writer import write_statements
if __name__ == '__main__':
from sys import argv, exit
if len(argv) < 2:
print 'Usage: python %s FILE' % argv[0]
print 'Usage: python %s SOURCE_FILE [ OUT_FILE [ SOURCE_OUT_FILE ] ]' \
% argv[0]
exit(1)
# Parse File
original = parse_file(argv[1])
optimized = optimize(original, verbose=1)
# Parse file
program = parse_file(argv[1])
program.debug = True
if len(argv) > 3:
# Save input assembly in new file for easy comparison
program.save(argv[3])
optimize(program, verbose=1)
if len(argv) > 2:
# Save output assembly
out = write_statements(optimized)
f = open(argv[2], 'w+')
f.write(out)
f.close()
program.save(argv[2])
RM=rm -rf
all: report.pdf
report: report.pdf
%.pdf: %.tex
pdflatex $^
......
This diff is collapsed.
CLEAN := $(CLEAN) report/*.pdf report/*.aux report/*.log \
report/*.out report/*.toc report/*.snm report/*.nav
report: report/report.pdf
report/%.pdf: report/%.tex
cd report; \
pdflatex report.tex; \
pdflatex report.tex
#!/bin/sh
python main.py benchmarks/build/$1.s out.s in.s && meld in.s out.s
class Dag:
def __init__(self, block):
"""Create the Directed Acyclic Graph of all binary operations in a
basic block."""
self.nodes = []
for s in block:
if s.is_command('move') or s.is_monop():
rd, rs = s
y = self.find_reg_node(rs)
self.find_op_node(s.name, rd, y)
elif s.is_binop():
rd, rs, rt = s
y = self.find_reg_node(rs)
z = self.find_reg_node(rt)
self.find_op_node(s.name, rd, y, z)
def find_reg_node(self, reg):
for n in self.nodes:
if reg in n.reg:
return n
node = DagLeaf(reg)
self.nodes.append(node)
return node
def find_op_node(self, op, rd, *args):
for n in self.nodes:
if not isinstance(n, DagLeaf) and n.op == op and n.nodes == args:
n.labels.append(rd)
return n
node = DagNode(op, rd, *args)
self.nodes.append(node)
return node
class DagNode:
def __init__(self, op, label, *args):
self.op = op
self.labels = [label]
self.nodes = args
class DagLeaf:
def __init__(self, reg):
self.reg = reg
from copy import copy
from statement import Block
......@@ -11,10 +9,6 @@ class BasicBlock(Block):
self.dominates = []
self.dominated_by = []
self.in_set = set([])
self.out_set = set([])
self.gen_set = set([])
self.kill_set = set([])
def add_edge_to(self, block):
if block not in self.edges_to:
......@@ -26,84 +20,6 @@ class BasicBlock(Block):
self.dominates.append(block)
block.dominated_by.append(self)
def create_gen_kill(self, defs):
used = set()
self_defs = {}
# Get the last of each definition series and put in in the `def' set
self.gen_set = set()
for s in reversed(self):
for reg in s.get_def():
if reg not in self_defs:
print 'Found def:', s
self_defs[reg] = s.sid
self.gen_set.add(s.sid)
# Generate kill set
self.kill_set = set()
for reg, statement_ids in defs.iteritems():
if reg in self_defs:
add = statement_ids - set([self_defs[reg]])
else:
add = statement_ids
self.kill_set |= add
def defs(blocks):
# Collect definitions of all registers
defs = {}
for b in blocks:
for s in b:
for reg in s.get_def():
if reg not in defs:
defs[reg] = set([s.sid])
else:
defs[reg].add(s.sid)
return defs
def reaching_definitions(blocks):
"""Generate the `in' and `out' sets of the given blocks using the iterative
algorithm from the slides."""
defs = defs(blocks)
for b in blocks:
b.create_gen_kill(defs)
b.out_set = b.gen_set
change = True
while change:
change = False
for b in blocks:
b.in_set = set()
for pred in b.edges_from:
b.in_set |= pred.out_set
oldout = copy(p.out_set)
p.out_set = b.gen_set | (b.in_set - b.kill_set)
if b.out_set != oldout:
change = True
def pred(n, known=[]):
"""Recursively find all predecessors of a node."""
direct = filter(lambda b: b not in known, n.edges_from)
p = copy(direct)
for ancestor in direct:
p += pred(ancestor, direct)
return p
def find_leaders(statements):
"""Determine the leaders, which are:
......@@ -160,109 +76,10 @@ def generate_flow_graph(blocks):
if other[0].is_label(target):
b.add_edge_to(other)
# A branch instruction also creates an edge to the next block
if last_statement.is_branch() and i < len(blocks) - 1:
# A branch and jump-and-line instruction also creates an edge to
# the next block
if (last_statement.is_branch() or last_statement.name == 'jal') \
and i < len(blocks) - 1:
b.add_edge_to(blocks[i + 1])
elif i < len(blocks) - 1:
b.add_edge_to(blocks[i + 1])
#def generate_dominator_tree(nodes):
# """Add dominator administration to the given flow graph nodes."""
# # Dominator of the start node is the start itself
# nodes[0].dom = set([nodes[0]])
#
# # For all other nodes, set all nodes as the dominators
# for n in nodes[1:]:
# n.dom = set(copy(nodes))
#
# def pred(n, known=[]):
# """Recursively find all predecessors of a node."""
# direct = filter(lambda x: x not in known, n.edges_from)
# p = copy(direct)
#
# for ancestor in direct:
# p += pred(ancestor, direct)
#
# return p
#
# # Iteratively eliminate nodes that are not dominators
# changed = True
#
# while changed:
# changed = False
#
# for n in nodes[1:]:
# old_dom = n.dom
# intersection = lambda p1, p2: p1.dom & p2.dom
# n.dom = set([n]) | reduce(intersection, pred(n), set([]))
#
# if n.dom != old_dom:
# changed = True
#
# def idom(d, n):
# """Check if d immediately dominates n."""
# for b in n.dom:
# if b != d and b != n and b in n.dom:
# return False
#
# return True
#
# # Build tree using immediate dominators
# for n in nodes:
# for d in n.dom:
# if idom(d, n):
# d.set_dominates(n)
# break
class Dag:
def __init__(self, block):
"""Create the Directed Acyclic Graph of all binary operations in a
basic block."""
self.nodes = []
for s in block:
if s.is_command('move') or s.is_monop():
rd, rs = s
y = self.find_reg_node(rs)
self.find_op_node(s.name, rd, y)
elif s.is_binop():
rd, rs, rt = s
y = self.find_reg_node(rs)
z = self.find_reg_node(rt)
self.find_op_node(s.name, rd, y, z)
def find_reg_node(self, reg):
for n in self.nodes:
if reg in n.reg:
return n
node = DagLeaf(reg)
self.nodes.append(node)
return node
def find_op_node(self, op, rd, *args):
for n in self.nodes:
if not isinstance(n, DagLeaf) and n.op == op and n.nodes == args:
n.labels.append(rd)
return n
node = DagNode(op, rd, *args)
self.nodes.append(node)
return node
class DagNode:
def __init__(self, op, label, *args):
self.op = op
self.labels = [label]
self.nodes = args
class DagLeaf:
def __init__(self, reg):
self.reg = reg
from copy import copy
def generate_dominator_tree(nodes):
"""Add dominator administration to the given flow graph nodes."""
# Dominator of the start node is the start itself
nodes[0].dom = set([nodes[0]])
# For all other nodes, set all nodes as the dominators
for n in nodes[1:]:
n.dom = set(copy(nodes))
def pred(n, known=[]):
"""Recursively find all predecessors of a node."""
direct = filter(lambda x: x not in known, n.edges_from)
p = copy(direct)
for ancestor in direct:
p += pred(ancestor, direct)
return p
# Iteratively eliminate nodes that are not dominators
changed = True
while changed:
changed = False
for n in nodes[1:]:
old_dom = n.dom
intersection = lambda p1, p2: p1.dom & p2.dom
n.dom = set([n]) | reduce(intersection, pred(n), set([]))
if n.dom != old_dom:
changed = True
def idom(d, n):
"""Check if d immediately dominates n."""
for b in n.dom:
if b != d and b != n and b in n.dom:
return False
return True
# Build tree using immediate dominators
for n in nodes:
for d in n.dom:
if idom(d, n):
d.set_dominates(n)
break
from copy import copy
RESERVED_REGISTERS = ['$fp', '$sp', '$31']
def is_reg_dead_after(reg, block, index):
"""Check if a register is dead after a certain point in a basic block."""
if reg in RESERVED_REGISTERS:
return False
if index < len(block) - 1:
for s in block[index + 1:]:
# If used, the previous definition is live
if s.uses(reg):
return False
# If redefined, the previous definition is dead
if s.defines(reg):
return True
# If dead within the same block, check if the register is in the block's
# live_out set
return reg not in block.live_out
def create_use_def(block):
used = set()
defined = set()
# Get the last of each definition series and put in in the `def' set
block.use_set = set()
block.def_set = set()
for s in block:
# use[B] is the set of variables whose values may be used in B prior to
# any definition of the variable
for reg in s.get_use():
used.add(reg)
if reg not in defined:
block.use_set.add(reg)
# def[B] is the set of variables assigned values in B prior to any use
# of that variable in B
for reg in s.get_def():
defined.add(reg)
if reg not in used:
block.def_set.add(reg)
def succ(block, known=[]):
"""Recursively find all successors of a node."""
direct = filter(lambda b: b != block and b not in known, block.edges_to)
s = copy(direct)
for successor in direct:
s += succ(successor, known + direct)
return s
return s
def create_in_out(blocks):
for b in blocks:
create_use_def(b)
b.live_in = b.use_set
b.live_out = set()
change = True
while change:
change = False
for b in blocks:
# in[B] = use[B] | (out[B] - def[B])
new_in = b.use_set | (b.live_out - b.def_set)
# out[B] = union of in[S] for S in succ(B)
new_out = set()
for s in succ(b):
new_out |= s.live_in
# Check if either `in' or `out' changed
if new_in != b.live_in:
b.live_in = new_in
change = True
if new_out != b.live_out:
b.live_out = new_out
change = True
from src.dataflow import find_basic_blocks
from redundancies import remove_redundant_jumps, move_1, move_2, move_3, \
move_4, load, shift, add
from src.dataflow import find_basic_blocks, generate_flow_graph
from redundancies import remove_redundancies
from advanced import eliminate_common_subexpressions, fold_constants, \
copy_propagation, algebraic_transformations, eliminate_dead_code
def remove_redundancies(block):
"""Execute all functions that remove redundant statements."""
callbacks = [move_1, move_2, move_3, move_4, load, shift, add]
old_len = -1
changed = False
while old_len != len(block):
old_len = len(block)
while not block.end():
s = block.read()
for callback in callbacks:
if callback(s, block):
changed = True
break
return changed
copy_propagation, eliminate_dead_code
import src.liveness as liveness
import src.reaching_definitions as reaching_definitions
def optimize_block(block):
"""Optimize a basic block."""
while remove_redundancies(block) \
| eliminate_common_subexpressions(block) \
| fold_constants(block) \
| copy_propagation(block)\
| algebraic_transformations(block) \
| eliminate_dead_code(block):
pass
def optimize(statements, verbose=0):
def optimize(program, verbose=0):
"""Optimization wrapper function, calls global and basic-block level
optimization functions."""
# Remember original number of statements
o = program.count_instructions()
# Optimize on a global level
o = len(statements)
remove_redundant_jumps(statements)
g = len(statements)
program.optimize_global()
g = program.count_instructions()
# Perform dataflow analysis
program.perform_dataflow_analysis()
# Optimize basic blocks
blocks = find_basic_blocks(statements)
map(optimize_block, blocks)
block_statements = map(lambda b: b.statements, blocks)
opt_blocks = reduce(lambda a, b: a + b, block_statements)
b = len(opt_blocks)
program.optimize_blocks()
# - Common subexpression elimination
# - Constant folding
# - Copy propagation
# - Dead-code elimination
# - Temporary variable renaming
# - Interchange of independent statements
# Concatenate optimized blocks to obtain
b = program.count_instructions()
# Print results
if verbose:
print 'Original statements: %d' % o
print 'After global optimization: %d' % g
print 'After basic blocks optimization: %d' % b
print 'Optimization: %d (%d%%)' \
print 'Original statements: %d' % o
print 'After global optimization: %d (%d removed)' % (g, o - g)
print 'After basic block optimization: %d (%d removed)' % (b, g - b)
print 'Statements removed: %d (%d%%)' \
% (o - b, int((o - b) / float(b) * 100))
return opt_blocks
This diff is collapsed.
import re
def move_1(mov, statements):
def remove_redundancies(block):
"""Execute all functions that remove redundant statements."""
callbacks = [move_aa, move_inst, instr_move_jal, move_move, sw_ld, shift,
add_lw]
old_len = -1
changed = False
while old_len != len(block):
old_len = len(block)
block.reset()
while not block.end():
s = block.read()
for callback in callbacks:
if callback(s, block):
changed = True
break
return changed
def move_aa(mov, statements):
"""
mov $regA, $regA -> --- remove it
move $regA, $regA -> --- remove it
"""
if mov.is_command('move') and mov[0] == mov[1]:
statements.replace(1, [])
......@@ -11,9 +34,9 @@ def move_1(mov, statements):
return True
def move_2(mov, statements):
def move_inst(mov, statements):
"""
mov $regA, $regB -> instr $regA, $regB, ...
move $regA, $regB -> instr $regA, $regB, ...
instr $regA, $regA, ...
"""
if mov.is_command('move'):
......@@ -26,10 +49,10 @@ def move_2(mov, statements):
return True
def move_3(ins, statements):
def instr_move_jal(ins, statements):
"""
instr $regA, ... -> instr $4, ...
mov $4, $regA jal XX
move $4, $regA jal XX
jal XX
"""
if ins.is_command() and len(ins):
......@@ -47,10 +70,10 @@ def move_3(ins, statements):
return True
def move_4(mov1, statements):
def move_move(mov1, statements):
"""
mov $RegA, $RegB -> move $RegA, $RegB
mov $RegB, $RegA
move $RegA, $RegB -> move $RegA, $RegB
move $RegB, $RegA
"""
if mov1.is_command('move'):
mov2 = statements.peek()
......@@ -62,7 +85,7 @@ def move_4(mov1, statements):
return True
def load(sw, statements):
def sw_ld(sw, statements):
"""
sw $regA, XX -> sw $regA, XX
ld $regA, XX
......@@ -86,7 +109,7 @@ def shift(shift, statements):
return True
def add(add, statements):
def add_lw(add, statements):
"""
add $regA, $regA, X -> lw ..., X($regA)
lw ..., 0($regA)
......@@ -124,3 +147,5 @@ def remove_redundant_jumps(statements):
s.name = 'bne' if s.is_command('beq') else 'beq'
s[2] = j[0]
statements.replace(3, [s, label])
statements.reset()
import ply.lex as lex
import ply.yacc as yacc
from statement import Statement as S, Block
from statement import Statement as S
from program import Program
# Global statements administration
......@@ -46,6 +47,7 @@ def t_offset_address(t):
def t_int(t):
r'-?[0-9]+'
t.type = 'WORD'
t.value = int(t.value)
return t
def t_WORD(t):
......@@ -79,11 +81,12 @@ def p_line_instruction(p):
def p_line_comment(p):
'line : COMMENT NEWLINE'
statements.append(S('comment', p[1], inline=False))
statements.append(S('comment', p[1]))
def p_line_inline_comment(p):
'line : instruction COMMENT NEWLINE'
statements.append(S('comment', p[2], inline=True))
# Add the inline comment to the last parsed statement
statements[-1].options['comment'] = p[2]
def p_instruction_command(p):
'instruction : command'
......@@ -125,4 +128,4 @@ def parse_file(filename):
except IOError:
raise Exception('File "%s" could not be opened' % filename)
return Block(statements)
return Program(statements)
from statement import Statement as S, Block
from dataflow import find_basic_blocks, generate_flow_graph
from optimize.redundancies import remove_redundant_jumps, remove_redundancies
from optimize.advanced import eliminate_common_subexpressions, \
fold_constants, copy_propagation, eliminate_dead_code
from writer import write_statements
import liveness
import reaching_definitions
class Program(Block):
def __len__(self):
"""Get the number of statements in the program."""
return len(self.statements) if hasattr(self, 'statements') \
else reduce(lambda a, b: len(a) + len(b), self.blocks, 0)
def get_statements(self, add_block_comments=False):
"""Concatenate the statements of all blocks and return the resulting
list."""
if hasattr(self, 'statements'):
return self.statements
# Only add block start and end comments when in debug mode
if add_block_comments and self.debug:
get_id = lambda b: b.bid
statements = []
for b in self.blocks:
message = ' Block %d (%d statements), edges from: %s' \
% (b.bid, len(b), map(get_id, b.edges_from))
if hasattr(b, 'live_in'):
message += ', LIVE_in: %s' % list(b.live_in)
if hasattr(b, 'reach_in'):
message += ', REACH_in: %s' % list(b.reach_in)
statements.append(S('comment', message, block=False))
statements += b.statements
message = ' End of block %d, edges to: %s' \
% (b.bid, map(get_id, b.edges_to))
if hasattr(b, 'live_out'):
message += ', LIVE_out: %s' % list(b.live_out)
if hasattr(b, 'reach_out'):
message += ', REACH_out: %s' % list(b.reach_out)
statements.append(S('comment', message, block=False))
return statements
return reduce(lambda a, b: a + b,
[b.statements for b in self.blocks])
def count_instructions(self):
"""Count the number of statements that are commands or labels."""
return len(filter(lambda s: s.is_command() or s.is_label(),
self.get_statements()))
def optimize_global(self):
"""Optimize on a global level."""
remove_redundant_jumps(self)
def optimize_blocks(self):
"""Optimize on block level. Keep executing all optimizations until no
more changes occur."""
self.program_iterations = self.block_iterations = 0
program_changed = True
while program_changed:
self.program_iterations += 1
program_changed = False
for block in self.blocks:
self.block_iterations += 1
block_changed = True
while block_changed:
block_changed = False
if remove_redundancies(block):
block_changed = True
if eliminate_common_subexpressions(block):
block_changed = True
if fold_constants(block):
block_changed = True
if copy_propagation(block):
block_changed = True
if eliminate_dead_code(block):
block_changed = True
if block_changed:
program_changed = True
def find_basic_blocks(self):
"""Divide the statement list into basic blocks."""
self.blocks = find_basic_blocks(self.statements)
for b in self.blocks:
b.debug = self.debug
# Remove the old statement list, since it will probably change
del self.statements
def perform_dataflow_analysis(self):
"""Perform dataflow analysis:
- Divide the statement list into basic blocks
- Generate flow graph
- Create liveness sets: def, use, in, out
- Create reaching definitions sets: gen, kill, in, out"""
self.find_basic_blocks()
generate_flow_graph(self.blocks)
liveness.create_in_out(self.blocks)
reaching_definitions.create_in_out(self.blocks)
def save(self, filename):
"""Save the program in the specified file."""
f = open(filename, 'w+')
f.write(write_statements(self.get_statements(True)))
f.close()
from dataflow import BasicBlock as B
def get_defs(blocks):
"""Collect definitions of all registers."""
defs = {}
for b in blocks:
for s in b:
for reg in s.get_def():
if reg not in defs:
defs[reg] = set([s.sid])
else:
defs[reg].add(s.sid)
return defs
def create_gen_kill(block, global_defs):
block_defs = {}
# Get the last of each definition series and put in in the `def' set
block.gen_set = set()
for s in reversed(block):
for reg in s.get_def():
if reg not in block_defs:
block_defs[reg] = s.sid
block.gen_set.add(s.sid)
# Generate kill set
block.kill_set = set()
for reg, statement_ids in global_defs.iteritems():
if reg in block_defs:
block.kill_set |= statement_ids - set([block_defs[reg]])
def create_in_out(blocks):
"""Generate the `in' and `out' sets of the given blocks using the iterative
algorithm from the lecture slides."""
# Create gen/kill sets
defs = get_defs(blocks)
for b in blocks:
create_gen_kill(b, defs)
b.reach_out = b.gen_set
change = True
while change:
change = False
for b in blocks:
b.reach_in = set()
for pred in b.edges_from:
b.reach_in |= pred.reach_out
new_out = b.gen_set | (b.reach_in - b.kill_set)
if new_out != b.reach_out:
b.reach_out = new_out
change = True
This diff is collapsed.
* Apart python script maken die de generator genereert dmv config file
* 'verbose' argument in main.py
* Gaat fout:
li $5,0x00008000 -> l.d $f0,32768($4)
addu $4,$4,$5
l.d $f0,0($4)
from math import ceil
TABSIZE = 4 # Size in spaces of a single tab
INLINE_COMMENT_LEVEL = 6 # Number of tabs to inline commment level
COMMAND_SIZE = 8 # Default length of a command name, used for
# indenting
ADD_COMMENT_BLOCKS = True # Wether to add newlines before and after
# non-inline comment
ADD_ARGUMENT_SPACE = False # Wether to add a space between command arguments
# and the previous comma
def write_statements(statements):
"""Write a list of statements to valid assembly code."""
out = ''
indent_level = 0
prevline = ''
prev_comment = False
for i, s in enumerate(statements):
newline = '\n' if i else ''
current_comment = False
if s.is_label():
line = s.name + ':'
indent_level = 1
elif s.is_comment():
line = '#' + s.name
if s.is_inline_comment():
l = len(prevline.expandtabs(4))
tabs = int(ceil((24 - l) / 4.)) + 1
newline = '\t' * tabs
else:
line = '\t' * indent_level + line
line = '\t' * indent_level + '#' + s.name
current_comment = s.options.get('block', True)
elif s.is_directive():
line = '\t' + s.name
elif s.is_command():
line = '\t' + s.name
# If there are arguments, add tabs until the 8 character limit has
# been reached. If the command name is 8 or more characers long,
# add a single space
if len(s):
if len(s.name) < 8:
line += '\t'
l = len(s.name)
if l < COMMAND_SIZE:
line += '\t' * int(ceil((COMMAND_SIZE - l)
/ float(TABSIZE)))
else:
line += ' '
line += ','.join(s.args)
delim = ', ' if ADD_ARGUMENT_SPACE else ','
line += delim.join(map(str, s))
else:
raise Exception('Unsupported statement type "%s"' % s.stype)
out += newline + line
prevline = line
# Add the inline comment, if there is any
if s.has_inline_comment():
start = INLINE_COMMENT_LEVEL * TABSIZE
diff = start - len(line.expandtabs(TABSIZE))
# Add newline at end of file
out += '\n'
# The comment must not be directly adjacent to the command itself
if diff > 0:
tabs = '\t' * (int(ceil(diff / float(TABSIZE))) + 1)
else:
tabs = ' '
line += tabs + '#' + s.options['comment']
# Add newline at end of command
line += '\n'
if ADD_COMMENT_BLOCKS:
if prev_comment ^ current_comment:
out += '\n'
out += line
prev_comment = current_comment
return out
def write_to_file(filename, statements):
"""Convert a list of statements to valid assembly code and write it to a
file."""
......
#!/usr/bin/python
from testrunner import main
import sys
main(sys.argv[1:])
TESTS=$(wildcard tests/test_*.py)
COVERAGE_OUTPUT_DIR := coverage
OMIT := /usr/share/pyshared/*,test*,*__init__.py
CLEAN := $(CLEAN) tests/*.pyc
ifeq ($(findstring python-coverage,$(wildcard /usr/bin/*)), python-coverage)
COVERAGE=/usr/bin/python-coverage
......
import unittest
from src.statement import Statement as S
from src.dataflow import BasicBlock as B
from src.dag import Dag, DagNode, DagLeaf
class TestDag(unittest.TestCase):
def setUp(self):
pass
def tearDown(self):
pass
def test_dag_unary(self):
dag = Dag(B([S('command', 'neg.d', '$rd', '$rs')]))
expect = Dag([])
expect.nodes = [DagLeaf('$rs'), DagNode('neg.d', '$rd', \
DagLeaf('$rs'))]
self.assertEqualDag(dag, expect)
def test_dag_binary(self):
dag = Dag(B([S('command', 'addu', '$rd', '$r1', '$r2')]))
expect = Dag([])
expect.nodes = [DagLeaf('$r1'),
DagLeaf('$r2'),
DagNode('addu', '$rd', DagLeaf('$r1'), DagLeaf('$r2'))]
self.assertEqualDag(dag, expect)
# def test_dag_combinednode(self):
# dag = Dag(B([S('command', 'mult', '$rd1', '$r1', '$r2'),
# S('command', 'mult', '$rd2', '$r1', '$r2')]))
# expect = Dag([])
# multnode = DagNode('mult',
# DagLeaf('$r1'),
# DagLeaf('$r2'))
# multnode.labels = ['$rd1', '$rd2']
# expect.nodes = [DagLeaf('$r1'),
# DagLeaf('$r2'),
# multnode]
#
# self.assertEqualDag(dag, expect)
def assertEqualDag(self, dag1, dag2):
self.assertEqual(len(dag1.nodes), len(dag2.nodes))
for node1, node2 in zip(dag1.nodes, dag2.nodes):
self.assertEqualNodes(node1, node2)
def assertEqualNodes(self, node1, node2):
if isinstance(node1, DagLeaf):
self.assertIsInstance(node2, DagLeaf)
self.assertEqual(node1.reg, node2.reg)
elif isinstance(node2, DagLeaf):
raise AssertionError
else:
self.assertEqual(node1.op, node2.op)
self.assertEqual(node1.labels, node2.labels)
self.assertEqual(len(node1.nodes), len(node2.nodes))
for child1, child2 in zip(node1.nodes, node2.nodes):
self.assertEqualNodes(child1, child2)
......@@ -2,7 +2,7 @@ import unittest
from src.statement import Statement as S
from src.dataflow import BasicBlock as B, find_leaders, find_basic_blocks, \
generate_flow_graph, Dag, DagNode, DagLeaf, defs, reaching_definitions
generate_flow_graph
class TestDataflow(unittest.TestCase):
......@@ -24,42 +24,6 @@ class TestDataflow(unittest.TestCase):
[B(s[:2]).statements, B(s[2:4]).statements, \
B(s[4:]).statements])
# def test_get_gen(self):
# b1 = B([S('command', 'add', '$1', '$2', '$3'), \
# S('command', 'add', '$2', '$3', '$4'), \
# S('command', 'add', '$1', '$4', '$5')])
#
# self.assertEqual(b1.get_gen(), ['$1', '$2'])
# def test_get_out(self):
# b1 = B([S('command', 'add', '$1', '$2', '$3'), \
# S('command', 'add', '$2', '$3', '$4'), \
# S('command', 'add', '$1', '$4', '$5'), \
# S('command', 'j', 'b2')])
#
# b2 = B([S('command', 'add', '$3', '$5', '$6'), \
# S('command', 'add', '$1', '$2', '$3'), \
# S('command', 'add', '$6', '$4', '$5')])
#
# blocks = [b1, b2]
#
# # initialize out[B] = gen[B] for every block
# for block in blocks:
# block.out_set = block.get_gen()
# print 'block.out_set', block.out_set
#
# generate_flow_graph(blocks)
# change = True
# while change:
# for i, block in enumerate(blocks):
# block.get_in()
# oldout = block.out_set
# newout = block.get_out()
# if (block.out_set == block.get_out()):
# change = False
def test_generate_flow_graph_simple(self):
b1 = B([S('command', 'foo'), S('command', 'j', 'b2')])
b2 = B([S('label', 'b2'), S('command', 'bar')])
......@@ -80,94 +44,3 @@ class TestDataflow(unittest.TestCase):
self.assertEqual(b2.edges_to, [b3])
self.assertIn(b1, b3.edges_from)
self.assertIn(b2, b3.edges_from)
def test_dag_unary(self):
dag = Dag(B([S('command', 'neg.d', '$rd', '$rs')]))
expect = Dag([])
expect.nodes = [DagLeaf('$rs'), DagNode('neg.d', '$rd', \
DagLeaf('$rs'))]
self.assertEqualDag(dag, expect)
def test_dag_binary(self):
dag = Dag(B([S('command', 'addu', '$rd', '$r1', '$r2')]))
expect = Dag([])
expect.nodes = [DagLeaf('$r1'),
DagLeaf('$r2'),
DagNode('addu', '$rd', DagLeaf('$r1'), DagLeaf('$r2'))]
self.assertEqualDag(dag, expect)
# def test_dag_combinednode(self):
# dag = Dag(B([S('command', 'mult', '$rd1', '$r1', '$r2'),
# S('command', 'mult', '$rd2', '$r1', '$r2')]))
# expect = Dag([])
# multnode = DagNode('mult',
# DagLeaf('$r1'),
# DagLeaf('$r2'))
# multnode.labels = ['$rd1', '$rd2']
# expect.nodes = [DagLeaf('$r1'),
# DagLeaf('$r2'),
# multnode]
#
# self.assertEqualDag(dag, expect)
def test_defs(self):
s1 = S('command', 'addu', '$3', '$1', '$2')
s2 = S('command', 'addu', '$1', '$3', 10)
s3 = S('command', 'subu', '$3', '$1', 5)
s4 = S('command', 'li', '$4', '0x00000001')
block = B([s1, s2, s3, s4])
self.assertEqual(defs([block]), {
'$3': set([s1.sid, s3.sid]),
'$1': set([s2.sid]),
'$4': set([s4.sid])
})
#def test_defs(self):
# s1 = S('command', 'add', '$3', '$1', '$2')
# s2 = S('command', 'move', '$1', '$3')
# s3 = S('command', 'move', '$3', '$2')
# s4 = S('command', 'li', '$4', '0x00000001')
# block = B([s1, s2, s3, s4])
# self.assertEqual(defs([block]), {
# '$3': set([s1.sid, s3.sid]),
# '$1': set([s2.sid]),
# '$4': set([s4.sid])
# })
def test_create_gen_kill_gen(self):
s1 = S('command', 'addu', '$3', '$1', '$2')
s2 = S('command', 'addu', '$1', '$3', 10)
s3 = S('command', 'subu', '$3', '$1', 5)
s4 = S('command', 'li', '$4', '0x00000001')
block = B([s1, s2, s3, s4])
block.create_gen_kill(defs([block]))
self.assertEqual(block.gen_set, set([s2.sid, s3.sid, s4.sid]))
#def test_get_kill_used(self):
# block = B([S('command', 'move', '$1', '$3'),
# S('command', 'add', '$3', '$1', '$2'),
# S('command', 'move', '$1', '$3'),
# S('command', 'move', '$2', '$3')])
# self.assertEqual(block.get_kill(), set())
def assertEqualDag(self, dag1, dag2):
self.assertEqual(len(dag1.nodes), len(dag2.nodes))
for node1, node2 in zip(dag1.nodes, dag2.nodes):
self.assertEqualNodes(node1, node2)
def assertEqualNodes(self, node1, node2):
if isinstance(node1, DagLeaf):
self.assertIsInstance(node2, DagLeaf)
self.assertEqual(node1.reg, node2.reg)
elif isinstance(node2, DagLeaf):
raise AssertionError
else:
self.assertEqual(node1.op, node2.op)
self.assertEqual(node1.labels, node2.labels)
self.assertEqual(len(node1.nodes), len(node2.nodes))
for child1, child2 in zip(node1.nodes, node2.nodes):
self.assertEqualNodes(child1, child2)
import unittest
from src.statement import Statement as S
from src.dataflow import BasicBlock as B, find_basic_blocks, \
generate_flow_graph
from src.liveness import create_use_def, create_in_out
class TestLiveness(unittest.TestCase):
def setUp(self):
pass
def tearDown(self):
pass
def test_create_gen_kill(self):
s1 = S('command', 'addu', '$3', '$1', '$2')
s2 = S('command', 'addu', '$1', '$3', 10)
s3 = S('command', 'subu', '$3', '$1', 5)
s4 = S('command', 'li', '$4', '0x00000001')
block = B([s1, s2, s3, s4])
create_use_def(block)
self.assertEqual(block.use_set, set(['$1', '$2']))
self.assertEqual(block.def_set, set(['$3', '$4']))
def test_create_in_out(self):
s11 = S('command', 'li', 'a', 3)
s12 = S('command', 'li', 'b', 5)
s13 = S('command', 'li', 'd', 4)
s14 = S('command', 'li', 'x', 100)
s15 = S('command', 'beq', 'a', 'b', 'L1')
s21 = S('command', 'addu', 'c', 'a', 'b')
s22 = S('command', 'li', 'd', 2)
s31 = S('label', 'L1')
s32 = S('command', 'li', 'c', 4)
s33 = S('command', 'mult', 'b', 'd')
s34 = S('command', 'mflo', 'temp')
s35 = S('command', 'addu', 'return', 'temp', 'c')
b1, b2, b3 = find_basic_blocks([s11, s12, s13, s14, s15, s21, s22, \
s31, s32, s33, s34, s35])
generate_flow_graph([b1, b2, b3])
create_in_out([b1, b2, b3])
self.assertEqual(b1.use_set, set())
self.assertEqual(b1.def_set, set(['a', 'b', 'd', 'x']))
self.assertEqual(b2.use_set, set(['a', 'b']))
self.assertEqual(b2.def_set, set(['c', 'd']))
self.assertEqual(b3.use_set, set(['b', 'd']))
self.assertEqual(b3.def_set, set(['c', 'temp', 'return']))
self.assertEqual(b1.live_in, set())
self.assertEqual(b1.live_out, set(['a', 'b', 'd']))
self.assertEqual(b2.live_in, set(['a', 'b']))
self.assertEqual(b2.live_out, set(['b', 'd']))
self.assertEqual(b3.live_in, set(['b', 'd']))
self.assertEqual(b3.live_out, set())
import unittest
from src.optimize.redundancies import remove_redundant_jumps
from src.optimize import optimize_block
from src.optimize.redundancies import remove_redundancies, remove_redundant_jumps
from src.program import Program
from src.statement import Statement as S, Block as B
def optimize_block(block):
"""Optimize a basic block using a Program object."""
# program = Program([])
# program.blocks = [block]
# del program.statements
# program.optimize_blocks()
remove_redundancies(block)
eliminate_common_subexpressions(block)
fold_constants(block)
copy_propagation(block)
return program.blocks
class TestOptimize(unittest.TestCase):
def setUp(self):
......@@ -19,7 +36,7 @@ class TestOptimize(unittest.TestCase):
block = B([self.foo,
S('command', 'move', '$regA', '$regA'),
self.bar])
optimize_block(block)
remove_redundancies(block)
self.assertEquals(block.statements, [self.foo, self.bar])
def test_optimize_block_movab(self):
......@@ -27,7 +44,7 @@ class TestOptimize(unittest.TestCase):
block = B([self.foo,
move,
self.bar])
optimize_block(block)
remove_redundancies(block)
self.assertEquals(block.statements, [self.foo, move, self.bar])
def test_optimize_block_movinst_true(self):
......@@ -35,7 +52,7 @@ class TestOptimize(unittest.TestCase):
S('command', 'move', '$regA', '$regB'),
S('command', 'addu', '$regA', '$regA', 2),
self.bar])
optimize_block(block)
remove_redundancies(block)
self.assertEquals(block.statements, [self.foo,
S('command', 'addu', '$regA', '$regB', 2),
self.bar])
......@@ -43,11 +60,11 @@ class TestOptimize(unittest.TestCase):
def test_optimize_block_movinst_false(self):
statements = [self.foo, \
S('command', 'move', '$regA', '$regB'), \
S('command', 'addu', '$regA', '$regC', 2), \
S('command', 'addu', '$regD', '$regC', 2), \
self.bar]
block = B(statements)
optimize_block(block)
remove_redundancies(block)
self.assertEquals(block.statements, statements)
def test_optimize_block_instr_mov_jal_true(self):
......@@ -56,7 +73,7 @@ class TestOptimize(unittest.TestCase):
S('command', 'move', '$4', '$regA'),
S('command', 'jal', 'L1'),
self.bar])
optimize_block(block)
remove_redundancies(block)
self.assertEquals(block.statements, [self.foo,
S('command', 'addu', '$4', '$regC', 2),
......@@ -70,7 +87,7 @@ class TestOptimize(unittest.TestCase):
S('command', 'jal', 'L1'), \
self.bar]
block = B(arguments)
optimize_block(block)
remove_redundancies(block)
self.assertEquals(block.statements, arguments)
......@@ -79,7 +96,7 @@ class TestOptimize(unittest.TestCase):
S('command', 'sw', '$regA', '$regB'),
S('command', 'lw', '$regA', '$regB'),
self.bar])
optimize_block(block)
remove_redundancies(block)
self.assertEquals(block.statements, [self.foo,
S('command', 'sw', '$regA', '$regB'),
......@@ -91,7 +108,7 @@ class TestOptimize(unittest.TestCase):
S('command', 'lw', '$regD', '$regC'), \
self.bar]
block = B(arguments)
optimize_block(block)
remove_redundancies(block)
self.assertEquals(block.statements, arguments)
......@@ -99,7 +116,7 @@ class TestOptimize(unittest.TestCase):
block = B([self.foo,
S('command', 'sll', '$regA', '$regA', 0),
self.bar])
optimize_block(block)
remove_redundancies(block)
self.assertEquals(block.statements, [self.foo, self.bar])
......@@ -108,7 +125,7 @@ class TestOptimize(unittest.TestCase):
S('command', 'sll', '$regA', '$regB', 0), \
self.bar]
block = B(arguments)
optimize_block(block)
remove_redundancies(block)
self.assertEquals(block.statements, arguments)
......@@ -116,7 +133,7 @@ class TestOptimize(unittest.TestCase):
S('command', 'sll', '$regA', '$regA', 1), \
self.bar]
block2 = B(arguments2)
optimize_block(block2)
remove_redundancies(block2)
self.assertEquals(block2.statements, arguments2)
......@@ -125,7 +142,7 @@ class TestOptimize(unittest.TestCase):
S('command', 'addu', '$regA', '$regA', 10),
S('command', 'lw', '$regB', '0($regA)'),
self.bar])
optimize_block(block)
remove_redundancies(block)
self.assertEquals(block.statements, [self.foo,
S('command', 'lw', '$regB', '10($regA)'),
......@@ -137,7 +154,7 @@ class TestOptimize(unittest.TestCase):
S('command', 'lw', '$regB', '0($regC)'), \
self.bar]
block = B(arguments)
optimize_block(block)
remove_redundancies(block)
arguments2 = [self.foo, \
S('command', 'addu', '$regA', '$regB', 10), \
......@@ -150,7 +167,7 @@ class TestOptimize(unittest.TestCase):
S('command', 'lw', '$regB', '1($regA)'), \
self.bar]
block3 = B(arguments3)
optimize_block(block3)
remove_redundancies(block3)
self.assertEquals(block.statements, arguments)
self.assertEquals(block2.statements, arguments2)
......@@ -209,7 +226,7 @@ class TestOptimize(unittest.TestCase):
S('command', 'move', '$regA', '$regB'),
S('command', 'move', '$regB', '$regA'),
self.bar])
optimize_block(block)
remove_redundancies(block)
self.assertEquals(block.statements, [self.foo,
S('command', 'move', '$regA', '$regB'),
......@@ -221,6 +238,6 @@ class TestOptimize(unittest.TestCase):
S('command', 'move', '$regB', '$regC'), \
self.bar]
block = B(arguments)
optimize_block(block)
remove_redundancies(block)
self.assertEquals(block.statements, arguments)
......@@ -3,7 +3,9 @@ from copy import copy
from src.optimize.advanced import eliminate_common_subexpressions, \
fold_constants, copy_propagation, algebraic_transformations
from src.statement import Statement as S, Block as B
from src.statement import Statement as S
from src.dataflow import BasicBlock as B, generate_flow_graph
import src.liveness as liveness
class TestOptimizeAdvanced(unittest.TestCase):
......@@ -22,6 +24,7 @@ class TestOptimizeAdvanced(unittest.TestCase):
e = [S('command', 'addu', '$8', '$regA', '$regB'), \
S('command', 'move', '$regC', '$8'), \
S('command', 'move', '$regD', '$8')]
liveness.create_in_out([b])
eliminate_common_subexpressions(b)
self.assertEqual(b.statements, e)
......@@ -30,6 +33,7 @@ class TestOptimizeAdvanced(unittest.TestCase):
S('command', 'li', '$regA', '0x00000001'),
S('command', 'addu', '$regD', '$regA', '$regB')])
e = copy(b.statements)
liveness.create_in_out([b])
eliminate_common_subexpressions(b)
self.assertEqual(b.statements, e)
......@@ -49,7 +53,7 @@ class TestOptimizeAdvanced(unittest.TestCase):
self.foo,
S('command', 'addu', '$3', '$2', '$4'),
self.bar])
def test_copy_propagation_other_arg(self):
block = B([self.foo,
S('command', 'move', '$1', '$2'),
......
import unittest
from src.statement import Statement as S
from src.dataflow import BasicBlock as B, find_basic_blocks, \
generate_flow_graph
from src.reaching_definitions import get_defs, create_gen_kill, create_in_out
class TestReachingDefinitions(unittest.TestCase):
def setUp(self):
pass
def tearDown(self):
pass
def test_get_defs(self):
s1 = S('command', 'add', '$3', '$1', '$2')
s2 = S('command', 'move', '$1', '$3')
s3 = S('command', 'move', '$3', '$2')
s4 = S('command', 'li', '$4', '0x00000001')
block = B([s1, s2, s3, s4])
self.assertEqual(get_defs([block]), {
'$3': set([s1.sid, s3.sid]),
'$1': set([s2.sid]),
'$4': set([s4.sid])
})
def test_create_gen_kill(self):
s1 = S('command', 'addu', '$3', '$1', '$2')
s2 = S('command', 'addu', '$1', '$3', 10)
s3 = S('command', 'subu', '$3', '$1', 5)
s4 = S('command', 'li', '$4', '0x00000001')
block = B([s1, s2, s3, s4])
create_gen_kill(block, get_defs([block]))
self.assertEqual(block.gen_set, set([s2.sid, s3.sid, s4.sid]))
self.assertEqual(block.kill_set, set([s1.sid]))
def test_create_in_out(self):
s11 = S('command', 'li', 'a', 3)
s12 = S('command', 'li', 'b', 5)
s13 = S('command', 'li', 'd', 4)
s14 = S('command', 'li', 'x', 100)
s15 = S('command', 'beq', 'a', 'b', 'L1')
s21 = S('command', 'addu', 'c', 'a', 'b')
s22 = S('command', 'li', 'd', 2)
s31 = S('label', 'L1')
s32 = S('command', 'li', 'c', 4)
s33 = S('command', 'mult', 'b', 'd')
s34 = S('command', 'mflo', 'temp')
s35 = S('command', 'addu', 'return', 'temp', 'c')
b1, b2, b3 = find_basic_blocks([s11, s12, s13, s14, s15, s21, s22, \
s31, s32, s33, s34, s35])
generate_flow_graph([b1, b2, b3])
create_in_out([b1, b2, b3])
self.assertEqual(b1.gen_set, set([s11.sid, s12.sid, s13.sid,
s14.sid]))
self.assertEqual(b1.kill_set, set([s22.sid]))
self.assertEqual(b2.gen_set, set([s21.sid, s22.sid]))
self.assertEqual(b2.kill_set, set([s13.sid, s32.sid]))
self.assertEqual(b3.gen_set, set([s32.sid, s34.sid, s35.sid]))
self.assertEqual(b3.kill_set, set([s21.sid]))
self.assertEqual(b1.reach_in, set())
self.assertEqual(b1.reach_out, set([s11.sid, s12.sid, s13.sid,
s14.sid]))
self.assertEqual(b2.reach_in, set([s11.sid, s12.sid, s13.sid,
s14.sid]))
self.assertEqual(b2.reach_out, set([s21.sid, s22.sid, s11.sid, \
s12.sid, s14.sid]))
self.assertEqual(b3.reach_in, set([s21.sid, s22.sid, s11.sid, \
s12.sid, s13.sid, s14.sid]))
self.assertEqual(b3.reach_out, set([s32.sid, s34.sid, s35.sid, \
s22.sid, s11.sid, s12.sid, \
s13.sid, s14.sid]))
......@@ -36,9 +36,10 @@ class TestStatement(unittest.TestCase):
self.assertFalse(S('comment', 'foo', inline=False).is_label())
self.assertFalse(S('directive', 'foo').is_command())
def test_is_inline_comment(self):
self.assertTrue(S('comment', 'foo', inline=True).is_inline_comment())
self.assertFalse(S('comment', 'foo', inline=False).is_inline_comment())
def test_has_inline_comment(self):
self.assertTrue(S('comment', 'foo', comment='a').has_inline_comment())
self.assertFalse(S('comment', 'foo', comment='').has_inline_comment())
self.assertFalse(S('comment', 'foo').has_inline_comment())
def test_jump_target(self):
self.assertEqual(S('command', 'j', 'foo').jump_target(), 'foo')
......@@ -93,3 +94,79 @@ class TestStatement(unittest.TestCase):
self.assertTrue(S('command', 'addu', '$1', '$2', '$3').is_arith())
self.assertFalse(S('command', 'foo').is_arith())
self.assertFalse(S('label', 'addu').is_arith())
def test_get_def_true(self):
a = ['a']
self.assertEqual(S('command', 'move', 'a', 'b').get_def(), a)
self.assertEqual(S('command', 'subu', 'a', 'b', 'c').get_def(), a)
self.assertEqual(S('command', 'addu', 'a', 'b', 'c').get_def(), a)
self.assertEqual(S('command', 'div', 'a', 'b', 'c').get_def(), a)
self.assertEqual(S('command', 'sll', 'a', 'b', 'c').get_def(), a)
self.assertEqual(S('command', 'srl', 'a', 'b', 'c').get_def(), a)
self.assertEqual(S('command', 'la', 'a', '16($fp)').get_def(), a)
self.assertEqual(S('command', 'li', 'a', '16($fp)').get_def(), a)
self.assertEqual(S('command', 'lw', 'a', 'b').get_def(), a)
self.assertEqual(S('command', 'l.d', 'a', 'b').get_def(), a)
self.assertEqual(S('command', 'add.d', 'a', 'b', 'c').get_def(), a)
self.assertEqual(S('command', 'neg.d', 'a', 'b').get_def(), a)
self.assertEqual(S('command', 'sub.d', 'a', 'b', 'c').get_def(), a)
self.assertEqual(S('command', 'slt', 'a', 'b').get_def(), a)
self.assertEqual(S('command', 'xori', 'a', 'b', '0x0000').get_def(), a)
self.assertEqual(S('command', 'mov.d', 'a', 'b').get_def(), a)
self.assertEqual(S('command', 'dmfc1', 'a', '$f0').get_def(), a)
self.assertEqual(S('command', 'mtc1', 'b', 'a').get_def(), a)
self.assertEqual(S('command', 'trunc.w.d', 'a', 'b', 'c').get_def(), a)
def test_get_def_false(self):
self.assertEqual(S('command', 'bne', 'a', 'b', 'L1').get_def(), [])
self.assertEqual(S('command', 'beq', 'a', 'b', 'L1').get_def(), [])
def test_get_use_true(self):
arg1 = ['$1']
arg2 = ['$1', '$2']
self.assertEqual(S('command', 'addu', '$3', '$1', '$2').get_use(), \
arg2)
self.assertEqual(S('command', 'subu', '$3', '$1', '$2').get_use(), \
arg2)
self.assertEqual(S('command', 'mult', '$1', '$2').get_use(), arg2)
self.assertEqual(S('command', 'div', '$3', '$1', '$2').get_use(), arg2)
self.assertEqual(S('command', 'move', '$2', '$1').get_use(), arg1)
self.assertEqual(S('command', 'beq', '$1', '$2', '$L1').get_use(), \
arg2)
self.assertEqual(S('command', 'bne', '$1', '$2', '$L1').get_use(), \
arg2)
self.assertEqual(S('command', 'sll', '$2', '$1', 2).get_use(), arg1)
self.assertEqual(S('command', 'lb', '$2', '10($1)').get_use(), arg1)
self.assertEqual(S('command', 'lw', '$2', '10($1)').get_use(), arg1)
self.assertEqual(S('command', 'la', '$2', '10($1)').get_use(), arg1)
self.assertEqual(S('command', 'lb', '$2', 'n.7').get_use(), ['n.7'])
self.assertEqual(S('command', 'lbu', '$2', '10($1)').get_use(), arg1)
self.assertEqual(S('command', 'l.d', '$2', '10($1)').get_use(), arg1)
self.assertEqual(S('command', 's.d', '$1', '10($2)').get_use(), \
arg2)
self.assertEqual(S('command', 's.s', '$1', '10($2)').get_use(), \
arg2)
self.assertEqual(S('command', 'sw', '$1', '10($2)').get_use(), \
arg2)
self.assertEqual(S('command', 'sb', '$1', '10($2)').get_use(), \
arg2)
self.assertEqual(S('command', 'mtc1', '$1', '$2').get_use(), arg1)
self.assertEqual(S('command', 'add.d', '$3', '$1', '$2').get_use(), \
arg2)
self.assertEqual(S('command', 'sub.d', '$3', '$1', '$2').get_use(), \
arg2)
self.assertEqual(S('command', 'div.d', '$3', '$1', '$2').get_use(), \
arg2)
self.assertEqual(S('command', 'mul.d', '$3', '$1', '$2').get_use(), \
arg2)
self.assertEqual(S('command', 'neg.d', '$2', '$1').get_use(), arg1)
self.assertEqual(S('command', 'abs.d', '$2', '$1').get_use(), arg1)
self.assertEqual(S('command', 'dsz', '10($1)', '$2').get_use(), arg1)
self.assertEqual(S('command', 'dsw', '$1', '10($2)').get_use(), arg2)
self.assertEqual(S('command', 'c.lt.d', '$1', '$2').get_use(), arg2)
self.assertEqual(S('command', 'bgez', '$1', '$2').get_use(), arg1)
self.assertEqual(S('command', 'bltz', '$1', '$2').get_use(), arg1)
self.assertEqual(S('command', 'trunc.w.d', '$3', '$1', '$2').get_use(),
arg2)
import unittest
from src.writer import write_statements
from src.statement import Statement as S, Block as B
class TestWriter(unittest.TestCase):
def setUp(self):
self.foo = S('command', 'move', '$regA', '$regB')
self.bar = S('command', 'addu', '$regC', '$regA', '$regB')
def tearDown(self):
del self.foo
del self.bar
def test_writer_one(self):
output = write_statements([self.foo])
expect = "\tmove\t$regA,$regB\n"
self.assertEqual(output, expect)
def test_writer_longname(self):
command = S('command', 'movemovemove', '$regA', '$regB')
output = write_statements([command])
expect = "\tmovemovemove $regA,$regB\n"
self.assertEqual(output, expect)
def test_writer_several(self):
output = write_statements([self.foo, self.bar, self.foo])
expect = "\tmove\t$regA,$regB\n" \
+ "\taddu\t$regC,$regA,$regB\n" \
+ "\tmove\t$regA,$regB\n"
self.assertEqual(output, expect)
def test_writer_with_label(self):
label = S('label', '$L1')
output = write_statements([self.foo, label, self.bar])
expect = "\tmove\t$regA,$regB\n" \
+ "$L1:\n" \
+ "\taddu\t$regC,$regA,$regB\n"
self.assertEqual(output, expect)
def test_writer_with_comment(self):
comment = S('comment', 'tralala')
output = write_statements([self.foo, comment, self.bar])
expect = "\tmove\t$regA,$regB\n" \
+ "\n#tralala\n\n" \
+ "\taddu\t$regC,$regA,$regB\n"
self.assertEqual(output, expect)
def test_writer_with_comment_non_tabbed(self):
directive = S('comment', 'tralala')
output = write_statements([directive, self.foo, self.bar])
expect = "\n#tralala\n\n" \
+ "\tmove\t$regA,$regB\n" \
+ "\taddu\t$regC,$regA,$regB\n"
self.assertEqual(output, expect)
def test_writer_with_inlinecomment(self):
self.foo.options['comment'] = 'tralala'
output = write_statements([self.foo, self.bar])
expect = "\tmove\t$regA,$regB" \
+ "\t\t#tralala\n" \
+ "\taddu\t$regC,$regA,$regB\n"
self.assertEqual(output, expect)
def test_writer_with_directive(self):
directive = S('directive', '.tralala trololo')
output = write_statements([self.foo, directive, self.bar])
expect = "\tmove\t$regA,$regB\n" \
+ "\t.tralala trololo\n" \
+ "\taddu\t$regC,$regA,$regB\n"
self.assertEqual(output, expect)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment