def generate_llvm_config(args=None, **kwargs): constants = [] # get config full string out = mx.OutputCapture() mx_sulong.llvm_tool(["llvm-config", "--version"] + list(args), out=out) full_version = out.data.strip() # NOTE: do not add full version until we need it to avoid regeneration # constants.append(("VERSION_FULL", full_version, "Full LLVM version string.")) # version without suffix s = full_version.split("-", 3) version = s[0] constants.append(("VERSION", version, "LLVM version string.")) # major, minor, patch s = version.split(".", 3) major_version, minor_version, patch_version = s[0], s[1], s[2] constants.append(("VERSION_MAJOR", int(major_version), "Major version of the LLVM API.")) constants.append(("VERSION_MINOR", int(minor_version), "Minor version of the LLVM API.")) constants.append(("VERSION_PATCH", int(patch_version), "Patch version of the LLVM API.")) file_comment = "GENERATED BY 'mx {}'. DO NOT MODIFY.".format( GENERATE_LLVM_CONFIG) _write_llvm_config_java(constants, file_comment) _write_llvm_config_mx(constants, file_comment)
def run_lli(input_f, out_f, err_f): additional_clang_input = [ mx_subst.path_substitutions.substitute(ci) for ci in parsed_args.clang_input or [] ] toolchain_clang = mx_sulong._get_toolchain_tool("native,CC") mx_sulong.llvm_tool([ toolchain_clang, "-O0", "-Wno-everything", "-o", tmp_out, input_f ] + additional_clang_input) with open(out_f, 'w') as o, open(err_f, 'w') as e: mx.command_function('lli')(parsed_args.lli_arg + [tmp_out], timeout=lli_timeout, nonZeroIsFatal=False, out=o, err=e)
def fuzz(args=None, out=None): parser = ArgumentParser(prog='mx fuzz', description='') parser.add_argument('--seed', help='Seed used for randomness.', metavar='<seed>', type=int, default=int(time.time())) parser.add_argument( '--size', help= 'Approximate size for the generated testcases in lines of code. (default: %(default)s)', metavar='<size>', type=int, default=30) parser.add_argument( '--timeout', help= 'Timeout for running the generated program. (default: %(default)s)', metavar='<timeout>', type=int, default=10) parser.add_argument( '--generator', help='Tool used for generating the testcases. (default: %(default)s)', choices=("llvm-stress", "csmith"), default="llvm-stress") parser.add_argument( '--nrtestcases', help='Number of testcases to be generated. (default: %(default)s)', metavar='<nrtestcases>', type=int, default=10) parser.add_argument('outdir', help='The output directory.', metavar='<outdir>') parsed_args = parser.parse_args(args) tmp_dir = None try: tmp_dir = tempfile.mkdtemp() tmp_ll = os.path.join(tmp_dir, 'tmp.ll') tmp_main_ll = os.path.join(tmp_dir, 'tmp.main.ll') tmp_c = os.path.join(tmp_dir, 'tmp.c') tmp_out = os.path.join(tmp_dir, 'tmp.out') tmp_sulong_out = os.path.join(tmp_dir, 'tmp_sulong_out.txt') tmp_bin_out = os.path.join(tmp_dir, 'tmp_bin_out.txt') tmp_sulong_err = os.path.join(tmp_dir, 'tmp_sulong_err.txt') tmp_bin_err = os.path.join(tmp_dir, 'tmp_bin_err.txt') rand = Random(parsed_args.seed) passed = 0 invalid = 0 gen = [] for _ in range(parsed_args.nrtestcases): toolchain_clang = mx_sulong._get_toolchain_tool("native,CC") if parsed_args.generator == "llvm-stress": _run_fuzz_tool("llvm-stress", [ "-o", tmp_ll, "--size", str(parsed_args.size), "--seed", str(rand.randint(0, 10000000)) ]) fuzz_main = os.path.join( mx.dependency('SULONG_TOOLS', fatalIfMissing=True).get_output(), "src", "fuzzmain.c") mx.run([ toolchain_clang, "-O0", "-Wno-everything", "-o", tmp_out, tmp_ll, fuzz_main ]) mx_sulong.llvm_tool([ "clang", "-O0", "-Wno-everything", "-S", "-emit-llvm", "-o", tmp_main_ll, fuzz_main ]) mx_sulong.llvm_tool( ["llvm-link", "-o", tmp_ll, tmp_ll, tmp_main_ll]) mx_sulong.llvm_tool(["llvm-dis", "-o", tmp_ll, tmp_ll]) else: csmith_exe = "csmith" csmith_headers = mx.get_env('CSMITH_HEADERS', None) if not csmith_headers: mx.abort("Environment variable `CSMITH_HEADERS` not set") mx.run([ csmith_exe, "-o", tmp_c, "--seed", str(rand.randint(0, 10000000)) ]) mx.run([ toolchain_clang, "-O0", "-Wno-everything", "-I" + csmith_headers, "-o", tmp_out, tmp_c ]) mx_sulong.llvm_tool([ "clang", "-O0", "-Wno-everything", "-S", "-emit-llvm", "-I" + csmith_headers, "-o", tmp_ll, tmp_c ]) gen.append((tmp_c, 'autogen.c')) timeout = parsed_args.timeout with open(tmp_sulong_out, 'w') as o, open(tmp_sulong_err, 'w') as e: mx_sulong.runLLVM([ '--llvm.llDebug', '--llvm.traceIR', '--experimental-options', tmp_out ], timeout=timeout, nonZeroIsFatal=False, out=o, err=e) with open(tmp_bin_out, 'w') as o, open(tmp_bin_err, 'w') as e: try: mx.run([tmp_out], timeout=timeout, out=o, err=e) except SystemExit: invalid += 1 continue if all( filecmp.cmp(sulong_f, bin_f, shallow=False) for sulong_f, bin_f in ((tmp_sulong_out, tmp_bin_out), (tmp_sulong_err, tmp_bin_err))): passed += 1 else: now = str(datetime.datetime.now()) now = now.replace(":", "_").replace(" ", "_") current_out_dir = os.path.join( parsed_args.outdir, now + "_" + parsed_args.generator) os.makedirs(current_out_dir) gen += [ (tmp_ll, 'autogen.ll'), (tmp_out, 'autogen'), (tmp_sulong_out, 'sulong_out.txt'), (tmp_bin_out, 'bin_out.txt'), (tmp_sulong_err, 'sulong_err.txt'), (tmp_bin_err, 'bin_err.txt'), ] for tmp_f, gen_f_name in gen: shutil.copy(tmp_f, os.path.join(current_out_dir, gen_f_name)) finally: if tmp_dir: shutil.rmtree(tmp_dir) mx.log("Test report") mx.log("total testcases: {} seed: {}".format(parsed_args.nrtestcases, parsed_args.seed)) mx.log("interesting testcases: {} invalid testcases: {}".format( parsed_args.nrtestcases - invalid - passed, invalid))
def ll_reduce(args=None, out=None): parser = ArgumentParser(prog='mx ll-reduce', description='') parser.add_argument( '--interestingness-test', help= 'Command which exits with code 1 if a given .ll file is interesting and exits with code 0 otherwise. (default: %(default)s)', metavar='<interestingnesstest>', default='mx check-interesting') parser.add_argument('--seed', help='Seed used for randomness.', metavar='<seed>', type=int, default=int(time.time())) parser.add_argument( '--timeout', help= 'Time in seconds until no new reduction operations are permitted to start.', metavar='<timeout>', type=int, default=None) parser.add_argument( '--timeout-stabilized', help= 'Time in seconds that should pass since no successful minimal reduction operation has been performed until no new reduction operations are permitted to start.', metavar='<timeout-stabilized>', type=int, default=10) parser.add_argument( '--clang-input', help= 'Additional input files that should be forwarded to clang. No reductions will be performed on these files. Mx path substitutions are enabled.', metavar='<clanginputs>', nargs='*') parser.add_argument('--lli-arg', help='Additional arguments passed to lli.', metavar='<lli arg>', nargs='*') parser.add_argument( '--output', help='The output file. If omitted, <input>.reduced.ll is used.', metavar='<output>', default=None) parser.add_argument('input', help='The input file.', metavar='<input>') parsed_args = parser.parse_args(args) mx.log("Running ll-reduce with the following configuration:") for k, v in vars(parsed_args).items(): mx.log("{:>30}: {}".format(k, v)) tmp_dir = None nrmutations = 4 starttime = time.time() starttime_stabilized = None tmp_ll = None try: tmp_dir = tempfile.mkdtemp() tmp_bc = os.path.join(tmp_dir, 'tmp.bc') tmp_ll = os.path.join(tmp_dir, 'tmp1.ll') tmp_ll_reduced = os.path.join(tmp_dir, 'tmp2.ll') tmp_out = os.path.join(tmp_dir, 'tmp.out') tmp_sulong_out_original = os.path.join(tmp_dir, 'tmp_sulong_out_original.txt') tmp_sulong_err_original = os.path.join(tmp_dir, 'tmp_sulong_err_original.txt') rand = Random(parsed_args.seed) lli_timeout = 10 def count_lines(file_name): i = 0 with open(file_name) as f: for i, _ in enumerate(f, 1): pass return i def run_lli(input_f, out_f, err_f): additional_clang_input = [ mx_subst.path_substitutions.substitute(ci) for ci in parsed_args.clang_input or [] ] toolchain_clang = mx_sulong._get_toolchain_tool("native,CC") mx_sulong.llvm_tool([ toolchain_clang, "-O0", "-Wno-everything", "-o", tmp_out, input_f ] + additional_clang_input) with open(out_f, 'w') as o, open(err_f, 'w') as e: mx.command_function('lli')(parsed_args.lli_arg + [tmp_out], timeout=lli_timeout, nonZeroIsFatal=False, out=o, err=e) def run_interestingness_test(interestingness_test, input_file): return mx.run(shlex.split(interestingness_test) + [input_file], nonZeroIsFatal=False) def run_llvm_reduce(nrmutations, input_bc, output_ll): reduce_out = mx.OutputCapture() try: args = [ input_bc, "-ignore_remaining_args=1", "-mtriple", "x86_64-unknown-linux-gnu", "-nrmutations", str(nrmutations), "-seed", str(rand.randint(0, 10000000)), "-o", output_ll ] _run_fuzz_tool("llvm-reduce", args, out=reduce_out, err=reduce_out) except SystemExit as se: mx.log_error(reduce_out.data) mx.abort("Error executing llvm-reduce: {}".format(se)) shutil.copy(parsed_args.input, tmp_ll) # check whether the input is interesting orig_interesting = run_interestingness_test( parsed_args.interestingness_test, tmp_ll) if not orig_interesting: mx.abort("Input program is not interesting!") run_lli(tmp_ll, tmp_sulong_out_original, tmp_sulong_err_original) while True: if parsed_args.timeout and time.time( ) - starttime > parsed_args.timeout: mx.log("Timeout exceeded") break if starttime_stabilized and time.time( ) - starttime_stabilized > parsed_args.timeout_stabilized: mx.log("Result stabilized (no more progress)") break mx_sulong.llvm_tool(["llvm-as", "-o", tmp_bc, tmp_ll]) mx.log( "nrmutations: {} filesize: {} bytes (bc), number of lines {} (ll)" .format(nrmutations, os.path.getsize(tmp_bc), count_lines(tmp_ll))) run_llvm_reduce(nrmutations, tmp_bc, tmp_ll_reduced) reduced_interesting = run_interestingness_test( parsed_args.interestingness_test, tmp_ll_reduced) if reduced_interesting: if not filecmp.cmp(tmp_ll, tmp_ll_reduced, shallow=False): tmp_ll, tmp_ll_reduced = tmp_ll_reduced, tmp_ll nrmutations *= 2 starttime_stabilized = None continue mx.log("Reduced file is identical to input file!") if nrmutations > 1: nrmutations //= 2 else: if not starttime_stabilized: starttime_stabilized = time.time() finally: if tmp_ll and os.path.isfile(tmp_ll): result = parsed_args.output or ( os.path.splitext(parsed_args.input)[0] + ".reduced.ll") mx.log("Writing reduced ll file to {}".format(result)) shutil.copy(tmp_ll, result) if tmp_dir: shutil.rmtree(tmp_dir)