| OLD | NEW |
| (Empty) |
| 1 # -*- python -*- | |
| 2 # Copyright (c) 2011 The Native Client Authors. All rights reserved. | |
| 3 # Use of this source code is governed by a BSD-style license that can be | |
| 4 # found in the LICENSE file. | |
| 5 | |
| 6 | |
| 7 import os | |
| 8 import sys | |
| 9 Import('env') | |
| 10 | |
| 11 # | |
| 12 # | |
| 13 # Build x86 only pieces | |
| 14 # | |
| 15 # | |
| 16 if not env.Bit('target_x86'): Return() | |
| 17 | |
| 18 # ------------------------------------------------------ | |
| 19 # General adjustments to the environment for builds. | |
| 20 | |
| 21 # Defines which test sets tests should be added to. | |
| 22 STANDARD_TESTS = ['small_tests', 'validator_tests'] | |
| 23 | |
| 24 # Define which test sets modeling test should be added to | |
| 25 MODELING_TESTS = STANDARD_TESTS + ['validator_modeling'] | |
| 26 | |
| 27 # TODO(bradchen): eliminate need for the following line | |
| 28 env.FilterOut(CCFLAGS=['-Wextra', '-Wswitch-enum', '-Wsign-compare']) | |
| 29 | |
| 30 # Defines this source directory. | |
| 31 src_dir = '$MAIN_DIR/src/trusted/validator/x86/decoder/generator' | |
| 32 | |
| 33 # Defines the source directory for locally generated files. | |
| 34 local_src_dir = '$MAIN_DIR/src/trusted/validator/x86/decoder/generator/gen' | |
| 35 | |
| 36 # Defines the source directory where validator generated files should be added. | |
| 37 tables_src_dir = '$MAIN_DIR/src/trusted/validator/x86/decoder/gen' | |
| 38 | |
| 39 # Create environment for command-line tools and testing, rather than | |
| 40 # part of the TCB. Then define compile-time flag that communicates | |
| 41 # that we are compiling in the test environment (rather than for the TCB). | |
| 42 test_env = env.Clone() | |
| 43 test_env.Append(CCFLAGS=['-DNACL_TRUSTED_BUT_NOT_TCB']) | |
| 44 | |
| 45 # ------------------------------------------------------ | |
| 46 # Source generation: | |
| 47 # | |
| 48 # Source generation is done in three steps. The first generates | |
| 49 # enumerated types. The second generates decoder tables needed by | |
| 50 # the decoders. In between these two steps we generate the executables | |
| 51 # that build the decoder tables. | |
| 52 # | |
| 53 # Source generation is controlled by to command line directives, and can be | |
| 54 # built in either the x86-32 or the x86-64 platform. The two directives are: | |
| 55 # | |
| 56 # valclean : Delete the existing versions of the generated files. | |
| 57 # This step should be done whenever ANY change may effect | |
| 58 # the generated sources. | |
| 59 # | |
| 60 # valgen : Regenerate any deleted source files. Note: some generated | |
| 61 # source files do understand dependencies and do not need to be | |
| 62 # deleted before calling valgen. However, do not count on this, | |
| 63 # as some dependencies are not caught. To be safe, if you have | |
| 64 # modified a file that effects source generation, run "valclean" | |
| 65 # followed by a "valgen" to guarantee that generated sources are | |
| 66 # up to date. | |
| 67 | |
| 68 gen_env = env.Clone() | |
| 69 gen_env.Append(CCFLAGS=['-DNACL_TRUSTED_BUT_NOT_TCB']) | |
| 70 | |
| 71 generate = False | |
| 72 if 'valgen' in COMMAND_LINE_TARGETS: generate = True | |
| 73 if 'valclean' in COMMAND_LINE_TARGETS: generate = True | |
| 74 | |
| 75 # Set of generated (source) decoder tables. | |
| 76 tables = [] | |
| 77 | |
| 78 # Set of generated (source) enumeration files. | |
| 79 enum_headers = [] | |
| 80 | |
| 81 # ------------------------------------------------------ | |
| 82 # Source generation step 1: Generate enumerated types. | |
| 83 # | |
| 84 # Only generate/clean these files if the alias is specified on the | |
| 85 # command line. We conditionally add these pieces to scons to prevent | |
| 86 # a normal invocation from accidentally regenerating the files. | |
| 87 # | |
| 88 if generate: | |
| 89 # | |
| 90 # valgen - Table Generator | |
| 91 # | |
| 92 # We create an alias 'valgen' which we use to generate the various | |
| 93 # headers used by the x86 validator. This target will generate | |
| 94 # *.h, *_impl.h from the *.enum files, as well as the executables | |
| 95 # ncdecode_table and ncdecode_tablegen which are used to generate | |
| 96 # the large opcode tables. | |
| 97 # | |
| 98 # Get the directory in which we will generate checking in files. | |
| 99 header_prefix = gen_env.subst('${MAIN_DIR}') | |
| 100 if header_prefix.endswith('/native_client'): | |
| 101 header_prefix = header_prefix[0:header_prefix.rfind('native_client')] | |
| 102 elif header_prefix.endswith('/native_client/'): | |
| 103 header_prefix = header_prefix[0:header_prefix.rfind('native_client/')] | |
| 104 | |
| 105 #------------------------------------------------------ | |
| 106 # Generate the needed header files for enumerated types. | |
| 107 # Note that we use the same directory for all platforms. | |
| 108 | |
| 109 # Define enumerate type files, and the options to process. | |
| 110 ncv_enum_pairs = { | |
| 111 'nacl_disallows': '--name=NaClDisallowsFlag --add_size=1', | |
| 112 } | |
| 113 | |
| 114 # Now code generate the enumerated types. | |
| 115 for ncv_enum in ncv_enum_pairs: | |
| 116 ncv_options = ncv_enum_pairs[ncv_enum] | |
| 117 ncv_enum_file = gen_env.File(ncv_enum + '.enum') | |
| 118 ncv_header_1 = gen_env.File('%s/%s.h' % (local_src_dir, ncv_enum)) | |
| 119 ncv_header_2 = gen_env.File('%s/%s_impl.h' % (local_src_dir, ncv_enum)) | |
| 120 | |
| 121 cmd_line = ( | |
| 122 '${PYTHON} %s --header="%s" --source="%s" --path_prefix="%s" %s %s' % | |
| 123 (gen_env.File('%s/../../../../validator_x86/enum_gen.py' % src_dir), | |
| 124 ncv_header_1, ncv_header_2, header_prefix, | |
| 125 ncv_options, ncv_enum_file)) | |
| 126 | |
| 127 gen_env.Command([ncv_header_1, ncv_header_2], ncv_enum_file, cmd_line) | |
| 128 enum_headers.append(ncv_header_1) | |
| 129 enum_headers.append(ncv_header_2) | |
| 130 | |
| 131 # ------------------------------------------------------ | |
| 132 # Table generators: | |
| 133 # | |
| 134 # In the middle of generating, we unconditionally add ncdecode_table and | |
| 135 # ncdecode_tablegen so that the tests which depend on it, can run correctly. | |
| 136 # This step sits in the middle because of dependency order, where the next | |
| 137 # generation step requires this executable. | |
| 138 | |
| 139 # Add new x86 table generator. | |
| 140 # | |
| 141 # | |
| 142 ncdecode_tablegen = gen_env.ComponentProgram( | |
| 143 'ncdecode_tablegen', | |
| 144 ['ncdecode_tablegen.c', | |
| 145 'nc_compress.c', | |
| 146 'ncval_simplify.c', | |
| 147 'ncdecode_forms.c', | |
| 148 'zero_extends.c', | |
| 149 'nc_def_jumps.c', | |
| 150 'long_mode.c', | |
| 151 'nc_rep_prefix.c', | |
| 152 'defsize64.c', | |
| 153 'nacl_illegal.c', | |
| 154 'lock_insts.c', | |
| 155 'ncdecode_st.c', | |
| 156 'ncdecode_onebyte.c', | |
| 157 'ncdecode_0F.c', | |
| 158 'ncdecode_sse.c', | |
| 159 'ncdecodeX87.c', | |
| 160 'nacl_regsgen.c', | |
| 161 'modeled_nacl_inst.c', | |
| 162 ], | |
| 163 EXTRA_LIBS=[gen_env.NaClTargetArchSuffix('nc_opcode_modeling_verbose'), | |
| 164 'utils']) | |
| 165 | |
| 166 | |
| 167 # ------------------------------------------------------ | |
| 168 # Source generation step 2: Generate decoder tables. | |
| 169 # | |
| 170 # Now we are back to conditionally defining the large tables generated | |
| 171 # by ncdecode_tablegen. | |
| 172 # | |
| 173 if generate: | |
| 174 # | |
| 175 # Generate 32 and 64 bit versions of nc_opcode_table and nc_subregs | |
| 176 # | |
| 177 for filename in ['nc_opcode_table', 'nc_subregs', 'ncval_reg_sfi_opcode_table'
]: | |
| 178 for bits in ['32', '64']: | |
| 179 fullname = '%s/%s_%s.h' % (tables_src_dir, filename, bits) | |
| 180 exe_path = '${STAGING_DIR}/${PROGPREFIX}ncdecode_tablegen${PROGSUFFIX}' | |
| 181 if filename == 'nc_subregs': | |
| 182 cmd_line = '%s -m%s -nacl_subregs %s'% (exe_path, bits, fullname) | |
| 183 elif filename == 'ncval_reg_sfi_opcode_table': | |
| 184 cmd_line = '%s -m%s -validator_decoder %s'% (exe_path, bits, fullname) | |
| 185 else: | |
| 186 cmd_line = '%s -m%s %s'% (exe_path, bits, fullname) | |
| 187 out = gen_env.Command(env.File(fullname), exe_path, cmd_line) | |
| 188 tables.append(fullname) | |
| 189 | |
| 190 # Generate 32 and 64 bit versions of ncval_opcode_table (validator | |
| 191 # decoder tables) | |
| 192 gen_list = enum_headers + tables | |
| 193 gen_env.AlwaysBuild( | |
| 194 gen_env.Alias('valgen', gen_list)) | |
| 195 gen_env.AlwaysBuild( | |
| 196 gen_env.Alias('valclean', action=[Delete(x) for x in gen_list])) | |
| 197 | |
| 198 # ====================================================================== | |
| 199 # Helper functions for getting automated tests from the corresponding | |
| 200 # test directory. | |
| 201 | |
| 202 TESTDATA_DIR = 'testdata/' | |
| 203 TESTDATA_SUBARCH_DIR = TESTDATA_DIR + env['TARGET_SUBARCH'] + '/' | |
| 204 | |
| 205 # Generates the set of test files with the given extension. | |
| 206 def __GoldenFiles(ext): | |
| 207 return Glob(TESTDATA_SUBARCH_DIR + '*.' + ext) | |
| 208 | |
| 209 # Generates base names (i.e. minus path and extention (ext) suffix) of | |
| 210 # all test data input files. | |
| 211 def __FilterOutTestFileBaseGen(files, ext): | |
| 212 for f in files: | |
| 213 yield os.path.basename(f.path).replace('.' + ext, '') | |
| 214 | |
| 215 # Generates the set of golden bases for the given extension. | |
| 216 def __GoldenBases(ext): | |
| 217 return __FilterOutTestFileBaseGen(__GoldenFiles(ext), ext) | |
| 218 | |
| 219 # Generates the corresponding test file from the given base. | |
| 220 def __BaseTestFile(base, ext): | |
| 221 return test_env.File(TESTDATA_SUBARCH_DIR + base + '.' + ext) | |
| 222 | |
| 223 # Generates the corresponding output file from the given base. | |
| 224 def __OutTestFile(test, base, ext): | |
| 225 return test + '_' + base + '.' + ext + '.out' | |
| 226 | |
| 227 def __AddTest(test, test_env, base, ext, command, groups): | |
| 228 test_env.AddNodeToTestSuite(command, | |
| 229 groups, | |
| 230 'run_%s_%s_%s_test' % (test, base, ext)) | |
| 231 | |
| 232 #------------------------------------------------------------------ | |
| 233 # Generate the header files containing the modeled x86 instructions. | |
| 234 | |
| 235 def TestGeneratedInstructionTables(target_subarch, golden_filename, | |
| 236 validator_decoder, groups): | |
| 237 | |
| 238 test_name = 'ncdecode_tablegen_%s_%s' % (golden_filename, target_subarch) | |
| 239 golden_output = env.File('%s/%s_%s.h' | |
| 240 % (tables_src_dir, golden_filename, target_subarch)) | |
| 241 cmd_line = [ncdecode_tablegen, '-m%s' % (target_subarch,)] | |
| 242 if validator_decoder: | |
| 243 cmd_line += ['-validator_decoder'] | |
| 244 test = test_env.CommandTest(test_name + '.out', | |
| 245 cmd_line, | |
| 246 stdout_golden = golden_output) | |
| 247 test_env.AddNodeToTestSuite(test, groups, 'run_%s_test' % test_name) | |
| 248 | |
| 249 | |
| 250 def TestGeneratedSubregisterTables(target_subarch, golden_filename, groups): | |
| 251 test_name = 'ncdecode_tablegen_subreg_tables_' + target_subarch | |
| 252 golden_output = env.File('%s/%s_%s.h' | |
| 253 % (tables_src_dir, golden_filename, target_subarch)) | |
| 254 test = test_env.CommandTest( | |
| 255 test_name + '.out', | |
| 256 [ncdecode_tablegen, '-m%s -nacl_subregs' % (target_subarch,)], | |
| 257 stdout_golden = golden_output) | |
| 258 test_env.AddNodeToTestSuite(test, groups, 'run_%s_test' % test_name) | |
| 259 | |
| 260 | |
| 261 # The following verifies that we generate the same source files, independent of | |
| 262 # whether the 32 bit or 64 bit table generator is used. | |
| 263 # Note: This is important in the 64-bit case on Windows, in that we want | |
| 264 # to make sure if the 32-bit generator is used, we still generate the | |
| 265 # same source files. | |
| 266 for test_subarch in ['32', '64']: | |
| 267 TestGeneratedInstructionTables(test_subarch, 'nc_opcode_table', | |
| 268 False, STANDARD_TESTS) | |
| 269 TestGeneratedInstructionTables(test_subarch, 'ncval_reg_sfi_opcode_table', | |
| 270 True, STANDARD_TESTS) | |
| 271 TestGeneratedSubregisterTables(test_subarch, 'nc_subregs', | |
| 272 STANDARD_TESTS) | |
| 273 | |
| 274 # Run test to see if we have changed the set of modeled instructions. | |
| 275 def __AddModeledInstsTest(): | |
| 276 prefixes = [''] | |
| 277 if test_env.Bit('build_x86_64'): | |
| 278 prefixes.append('ncval_reg_sfi_') | |
| 279 for prefix in prefixes: | |
| 280 test = 'test' | |
| 281 base = prefix + 'modeled_insts' | |
| 282 ext = 'txt' | |
| 283 command = [ncdecode_tablegen, | |
| 284 '-m%s' % (env['TARGET_SUBARCH']), | |
| 285 '-documentation'] | |
| 286 if prefix == 'ncval_reg_sfi_': | |
| 287 command.append('-validator_decoder') | |
| 288 model = test_env.CommandTest( | |
| 289 __OutTestFile(test, base, ext), | |
| 290 command, | |
| 291 stdout_golden = __BaseTestFile(base, ext)) | |
| 292 __AddTest(test, test_env, base, ext, model, | |
| 293 MODELING_TESTS) | |
| 294 | |
| 295 __AddModeledInstsTest() | |
| OLD | NEW |