import os
import os.path
from subprocess import Popen, PIPE
import argparse
asm_dir = './asm'
files = set()
verbose = False
def arm_triplet(arch) :
triples = { 'armv7' : 'armv7-unknown-linux-gnueabihf',
'armv8' : 'aarch64-unknown-linux-gnu' }
return triples[arch]
class File(object):
def __init__(self, path_rs):
self.path_rs = path_rs
self.path_asm_should = os.path.join(os.path.splitext(path_rs)[0] + ".asm")
self.path_asm_output = os.path.join(os.path.splitext(path_rs)[0] + "_output.asm")
self.path_llvmir_output = os.path.join(os.path.splitext(path_rs)[0] + "_ir.ll")
self.name = os.path.splitext(os.path.basename(path_rs))[0]
self.feature = self.name.split("_")[1]
self.arch = self.name.split("_")[0]
if self.feature == "none":
self.feature = None
def __str__(self):
return "name: " + self.name + ", path-rs: " + self.path_rs + ", path-asm: " + self.path_asm_should + ', arch: ' + self.arch + ", feature: " + str(self.feature)
def __hash__(self):
return hash(self.name)
def find_files():
for dirpath, dirnames, filenames in os.walk(asm_dir):
for filename in [f for f in filenames if f.endswith(".rs")]:
files.add(File(os.path.join(dirpath, filename)))
def call(args):
if verbose:
print "command: " + str(args)
p = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE, shell=True)
output, err = p.communicate(b"input data that is passed to subprocess' stdin")
rc = p.returncode
if verbose:
print output
print err
def compile_file(file):
if verbose:
print "Checking: " + str(file) + "..."
cargo_args = 'cargo rustc --verbose --release -- -C panic=abort -C codegen-units=1 -C lto=fat --cfg=\'bitintr_nightly\' '
if file.feature:
cargo_args = cargo_args + '-C target-feature=+{}'.format(file.feature)
if file.arch == 'armv7' or file.arch == 'armv8':
cargo_args = cargo_args + '--target={}'.format(arm_triplet(file.arch))
call(str(cargo_args))
rustc_args = 'rustc --verbose -C opt-level=3 -C codegen-units=1 -C lto=fat -C panic="abort" --extern bitintr=target/release/libbitintr.rlib --crate-type lib';
if file.feature:
rustc_args = rustc_args + ' -C target-feature=+{}'.format(file.feature)
if file.arch == 'armv7' or file.arch == 'armv8':
rustc_args = rustc_args + ' --target={}'.format(arm_triplet(file.arch))
rustc_args_asm = rustc_args + ' --emit asm {} -o {}'.format(file.path_rs, file.path_asm_output)
call(rustc_args_asm)
rustc_args_ll = rustc_args + ' --emit llvm-ir {} -o {}'.format(file.path_rs, file.path_llvmir_output)
call(rustc_args_ll)
if verbose:
print "...done!"
def diff_files(rustc_output, asm_snippet):
with open(rustc_output, 'r') as rustc_output_file:
rustc_output_lines = rustc_output_file.readlines()
with open(asm_snippet, 'r') as asm_snippet_file:
asm_snippet_lines = asm_snippet_file.readlines()
rustc_output_lines = [l.strip() for l in rustc_output_lines]
rustc_output_lines = [l for l in rustc_output_lines if not l.startswith(".") and not len(l) == 0]
asm_snippet_lines = [l.strip() for l in asm_snippet_lines]
asm_snippet_lines = [l for l in asm_snippet_lines if not l.startswith(".") and not len(l) == 0]
results_differ = False
if len(rustc_output_lines) != len(asm_snippet_lines):
results_differ = True
for line_is, line_should in zip(rustc_output_lines, asm_snippet_lines):
if line_is != line_should:
results_differ = True
if results_differ:
print "Error: results differ"
print "Is:"
print rustc_output_lines
print "Should:"
print asm_snippet_lines
return False
return True
def check_file(file):
compile_file(file)
return diff_files(file.path_asm_output, file.path_asm_should)
def main():
parser = argparse.ArgumentParser(description='Checks ASM code')
parser.add_argument('-verbose', action="store_true", default=False)
results = parser.parse_args()
global verbose
if results.verbose:
verbose = True
find_files()
if verbose:
for f in files:
print f
error = False
for f in files:
result = check_file(f)
if not result:
error = True
if error == True:
exit(1)
else:
exit(0)
if __name__ == "__main__":
main()