Example #1
0
 def test_to_crasher(self):
     s = sample.Sample(
         'fn main(x: u8, y: u8) -> u8 {\nx + y\n}',
         sample.SampleOptions(input_is_dslx=True,
                              codegen=True,
                              codegen_args=('--generator=pipeline',
                                            '--pipeline_stages=2'),
                              simulate=True,
                              simulator='goat simulator',
                              use_system_verilog=True),
         sample.parse_args_batch(
             'bits[8]:42; bits[8]:11\nbits[8]:44; bits[8]:99'))
     crasher = s.to_crasher()
     self.assertTrue(
         crasher.startswith('// Copyright'),
         msg=f'Crasher does not start with copyright:\n{crasher}')
     self.assertIn(
         textwrap.dedent("""\
     // options: {"codegen": true, "codegen_args": ["--generator=pipeline", "--pipeline_stages=2"], "convert_to_ir": true, "input_is_dslx": true, "optimize_ir": true, "simulate": true, "simulator": "goat simulator", "use_jit": true, "use_system_verilog": true}
     // args: bits[8]:0x2a; bits[8]:0xb
     // args: bits[8]:0x2c; bits[8]:0x63
     fn main(x: u8, y: u8) -> u8 {
     x + y
     }
     """), crasher)
Example #2
0
 def test_minimize_ir_minimization_possible(self):
     # Add an invalid codegen flag to inject an error into the running of the
     # sample. The error is unconditional so IR minimization should be able to
     # reduce the sample to a minimal function (just returns a parameter).
     s = sample.Sample(
         'fn main(x: u8) -> u8 { -x }',
         sample.SampleOptions(codegen=True,
                              codegen_args=('--invalid_flag!!!', )),
         sample.parse_args_batch('bits[8]:7\nbits[8]:100'))
     success = test_base.TempFileCleanup.SUCCESS  # type: test_base.TempFileCleanup
     run_dir = self.create_tempdir(cleanup=success).full_path
     with self.assertRaises(sample_runner.SampleError):
         run_fuzz.run_sample(s, run_dir=run_dir)
     minimized_ir_path = run_fuzz.minimize_ir(s, run_dir)
     self.assertIsNotNone(minimized_ir_path)
     self.assertIn('ir_minimizer_test.sh', os.listdir(run_dir))
     # Sanity check the minimized IR.
     with open(minimized_ir_path, 'r') as f:
         contents = f.read()
         self.assertIn('package ', contents)
         self.assertIn('fn ', contents)
         # It should be reduced to simply a literal.
         self.assertIn('ret literal', contents)
     # And verify the minimized IR parses.
     subprocess.check_call([PARSE_IR, minimized_ir_path])
Example #3
0
 def test_from_crasher_without_codegen(self):
     crasher = textwrap.dedent("""\
   // options: {"input_is_dslx": false, "convert_to_ir": false, "optimize_ir": true, "codegen": true, "codegen_args": null, "simulate": false, "simulator": null, "use_system_verilog": true}
   // args: bits[8]:0x2a; bits[8]:0xb
   // args: bits[8]:0x2c; bits[8]:0x63
   package foo
   fn bar(x: bits[16], y: bits[16) -> bits[16] {
     ret add.1: bits[16] = add(x, y)
   }""")
     got = sample.Sample.from_crasher(crasher)
     want = sample.Sample(
         textwrap.dedent("""\
         package foo
         fn bar(x: bits[16], y: bits[16) -> bits[16] {
           ret add.1: bits[16] = add(x, y)
         }"""),
         sample.SampleOptions(input_is_dslx=False,
                              convert_to_ir=False,
                              codegen=True,
                              codegen_args=None,
                              simulate=False,
                              simulator=None,
                              use_system_verilog=True),
         sample.parse_args_batch(
             'bits[8]:0x2a; bits[8]:0xb\nbits[8]:0x2c; bits[8]:0x63'))
     self.assertEqual(got, want)
Example #4
0
 def test_from_ir_crasher_with_codegen(self):
     crasher = textwrap.dedent("""\
 // options: {"codegen": true, "codegen_args": ["--generator=pipeline", "--pipeline_stages=2"], "convert_to_ir": false, "input_is_dslx": false, "optimize_ir": true, "simulate": true, "simulator": "goat simulator", "use_system_verilog": false}
 // args: bits[8]:0x2a; bits[8]:0xb
 // args: bits[8]:0x2c; bits[8]:0x63
 package foo
 fn bar(x: bits[16], y: bits[16) -> bits[16] {
   ret add.1: bits[16] = add(x, y)
 }
 """)
     got = sample.Sample.from_crasher(crasher)
     want = sample.Sample(
         textwrap.dedent("""\
       package foo
       fn bar(x: bits[16], y: bits[16) -> bits[16] {
         ret add.1: bits[16] = add(x, y)
       }"""),
         sample.SampleOptions(input_is_dslx=False,
                              convert_to_ir=False,
                              optimize_ir=True,
                              codegen=True,
                              codegen_args=('--generator=pipeline',
                                            '--pipeline_stages=2'),
                              simulate=True,
                              simulator='goat simulator',
                              use_system_verilog=False),
         sample.parse_args_batch(
             'bits[8]:0x2a; bits[8]:0xb\nbits[8]:0x2c; bits[8]:0x63'))
     self.assertMultiLineEqual(want.to_crasher(), got.to_crasher())
     self.assertEqual(got, want)
Example #5
0
 def test_to_crasher_with_error_message(self):
     s = sample.Sample(
         'fn main(x: u8, y: u8) -> u8 {\nx + y\n}',
         sample.SampleOptions(input_is_dslx=True,
                              codegen=True,
                              codegen_args=('--generator=pipeline',
                                            '--pipeline_stages=2'),
                              simulate=True,
                              simulator='goat simulator',
                              use_system_verilog=True),
         sample.parse_args_batch(
             'bits[8]:42; bits[8]:11\nbits[8]:44; bits[8]:99'))
     crasher = s.to_crasher('oh no\nI crashed\n')
     self.assertTrue(
         crasher.startswith('// Copyright'),
         msg=f'Crasher does not start with copyright:\n{crasher}')
     # Split D.N.S. string to avoid triggering presubmit checks.
     self.assertIn(
         'Issue: DO NOT ' + 'SUBMIT Insert link to GitHub issue here.',
         crasher)
     self.assertIn(
         textwrap.dedent("""\
     // Exception:
     // oh no
     // I crashed"""), crasher)
     self.assertIn(
         textwrap.dedent("""\
     // options: {"codegen": true, "codegen_args": ["--generator=pipeline", "--pipeline_stages=2"], "convert_to_ir": true, "input_is_dslx": true, "optimize_ir": true, "simulate": true, "simulator": "goat simulator", "use_jit": true, "use_system_verilog": true}
     // args: bits[8]:0x2a; bits[8]:0xb
     // args: bits[8]:0x2c; bits[8]:0x63
     fn main(x: u8, y: u8) -> u8 {
     x + y
     }
     """), crasher)
Example #6
0
 def test_interpret_mixed_signedness_unsigned_inputs(self):
     sample_dir = self._make_sample_dir()
     runner = sample_runner.SampleRunner(sample_dir)
     dslx_text = 'fn main(x: u8, y: s8) -> s8 { (x as s8) + y }'
     runner.run(
         sample.Sample(
             dslx_text, sample.SampleOptions(optimize_ir=False),
             sample.parse_args_batch('bits[8]:0xb0; bits[8]:0x0a')))
     self.assertEqual(
         _read_file(sample_dir, 'sample.x.results').strip(), 'bits[8]:0xba')
Example #7
0
 def test_minimize_ir_no_minimization_possible(self):
     # Verify that IR minimization at least generates a minimization test script
     # and doesn't blow up if the IR is not minimizable. In this case, "not
     # minimizable" means that no error is ever generated when running the
     # sample.
     s = sample.Sample('fn main(x: u8) -> u8 { -x }',
                       sample.SampleOptions(),
                       sample.parse_args_batch('bits[8]:7\nbits[8]:100'))
     success = test_base.TempFileCleanup.SUCCESS  # type: test_base.TempFileCleanup
     run_dir = self.create_tempdir(cleanup=success).full_path
     run_fuzz.run_sample(s, run_dir=run_dir)
     self.assertIsNone(run_fuzz.minimize_ir(s, run_dir))
     dir_contents = os.listdir(run_dir)
     self.assertIn('ir_minimizer_test.sh', dir_contents)
Example #8
0
 def test_minimize_jit_interpreter_mismatch(self):
     s = sample.Sample(
         'fn main(x: u8) -> u8 { !x }', sample.SampleOptions(),
         sample.parse_args_batch('bits[8]:0xff\nbits[8]:0x42'))
     success = test_base.TempFileCleanup.SUCCESS  # type: test_base.TempFileCleanup
     run_dir = self.create_tempdir(cleanup=success).full_path
     run_fuzz.run_sample(s, run_dir=run_dir)
     minimized_ir_path = run_fuzz.minimize_ir(
         s, run_dir, inject_jit_result='bits[32]:0x0')
     self.assertIsNotNone(minimized_ir_path)
     with open(minimized_ir_path, 'r') as f:
         contents = f.read()
         self.assertIn('package ', contents)
         self.assertIn('fn ', contents)
         # It should be reduced to simply a literal.
         self.assertIn('ret literal', contents)
     # And verify the minimized IR parses.
     subprocess.check_call([PARSE_IR, minimized_ir_path])
Example #9
0
    def run_from_files(self, input_filename: Text, json_options_filename: Text,
                       args_filename: Text):
        """Runs a sample which is read from files.

    Each filename must be the name of a file (not a full path) which is
    contained in the SampleRunner's run directory.

    Args:
      input_filename: The filename of the sample code.
      json_options_filename: The filename of the JSON-serialized SampleOptions.
      args_filename: The optional filename of the serialized ArgsBatch.

    Raises:
      SampleError: If an error was encountered.
    """
        logging.vlog(1, 'Reading sample files.')
        input_text = self._read_file(input_filename)
        options = sample.SampleOptions.from_json(
            self._read_file(json_options_filename))
        args_batch: Optional[ArgsBatch] = None
        if args_filename:
            args_batch = sample.parse_args_batch(
                self._read_file(args_filename))

        self._write_file('revision.txt', revision.get_revision())

        # Gather results in an OrderedDict because the first entered result is used
        # as a reference.
        results = collections.OrderedDict(
        )  # type: Dict[Text, Sequence[Value]]

        try:
            if options.input_is_dslx:
                if args_batch:
                    logging.vlog(1, 'Interpreting DSLX file.')
                    with Timer() as t:
                        results['interpreted DSLX'] = self._interpret_dslx(
                            input_text, 'main', args_batch)
                    logging.vlog(1,
                                 'Interpreting DSLX complete, elapsed %0.2fs',
                                 t.elapsed_ns / 1e9)
                    self.timing.interpret_dslx_ns = t.elapsed_ns

                if not options.convert_to_ir:
                    return

                with Timer() as t:
                    ir_filename = self._dslx_to_ir(input_filename)
                self.timing.convert_ir_ns = t.elapsed_ns
            else:
                ir_filename = self._write_file('sample.ir', input_text)

            if args_filename is not None:
                # Unconditionally evaluate with the interpreter even if using the
                # JIT. This exercises the interpreter and serves as a reference.
                with Timer() as t:
                    results[
                        'evaluated unopt IR (interpreter)'] = self._evaluate_ir(
                            ir_filename, args_filename, False)
                self.timing.unoptimized_interpret_ir_ns = t.elapsed_ns

                if options.use_jit:
                    with Timer() as t:
                        results[
                            'evaluated unopt IR (JIT)'] = self._evaluate_ir(
                                ir_filename, args_filename, True)
                    self.timing.unoptimized_jit_ns = t.elapsed_ns

            if options.optimize_ir:
                with Timer() as t:
                    opt_ir_filename = self._optimize_ir(ir_filename)
                self.timing.optimize_ns = t.elapsed_ns

                if args_filename is not None:
                    if options.use_jit:
                        with Timer() as t:
                            results[
                                'evaluated opt IR (JIT)'] = self._evaluate_ir(
                                    opt_ir_filename, args_filename, True)
                        self.timing.optimized_jit_ns = t.elapsed_ns
                    with Timer() as t:
                        results[
                            'evaluated opt IR (interpreter)'] = self._evaluate_ir(
                                opt_ir_filename, args_filename, False)
                    self.timing.optimized_interpret_ir_ns = t.elapsed_ns

                if options.codegen:
                    with Timer() as t:
                        verilog_filename = self._codegen(
                            opt_ir_filename, options.codegen_args)
                    self.timing.codegen_ns = t.elapsed_ns

                    if options.simulate:
                        assert args_filename is not None
                        with Timer() as t:
                            results['simulated'] = self._simulate(
                                verilog_filename, 'module_sig.textproto',
                                args_filename, options.simulator)
                        self.timing.simulate_ns = t.elapsed_ns

            self._compare_results(results, args_batch)
        except Exception as e:  # pylint: disable=broad-except
            # Note: this is a bit of a hack because pybind11 doesn't make it very
            # possible to define custom __str__ on exception types. Our C++ exception
            # types have a field called "message" generally so we look for that.
            msg = e.message if hasattr(e, 'message') else str(e)
            logging.exception('Exception when running sample: %s', msg)
            self._write_file('exception.txt', msg)
            raise SampleError(msg)