1b8021494Sopenharmony_ci# Copyright 2016, VIXL authors 2b8021494Sopenharmony_ci# All rights reserved. 3b8021494Sopenharmony_ci# 4b8021494Sopenharmony_ci# Redistribution and use in source and binary forms, with or without 5b8021494Sopenharmony_ci# modification, are permitted provided that the following conditions are met: 6b8021494Sopenharmony_ci# 7b8021494Sopenharmony_ci# * Redistributions of source code must retain the above copyright notice, 8b8021494Sopenharmony_ci# this list of conditions and the following disclaimer. 9b8021494Sopenharmony_ci# * Redistributions in binary form must reproduce the above copyright notice, 10b8021494Sopenharmony_ci# this list of conditions and the following disclaimer in the documentation 11b8021494Sopenharmony_ci# and/or other materials provided with the distribution. 12b8021494Sopenharmony_ci# * Neither the name of ARM Limited nor the names of its contributors may be 13b8021494Sopenharmony_ci# used to endorse or promote products derived from this software without 14b8021494Sopenharmony_ci# specific prior written permission. 15b8021494Sopenharmony_ci# 16b8021494Sopenharmony_ci# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND 17b8021494Sopenharmony_ci# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18b8021494Sopenharmony_ci# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19b8021494Sopenharmony_ci# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 20b8021494Sopenharmony_ci# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21b8021494Sopenharmony_ci# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22b8021494Sopenharmony_ci# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23b8021494Sopenharmony_ci# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24b8021494Sopenharmony_ci# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25b8021494Sopenharmony_ci# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26b8021494Sopenharmony_ci 27b8021494Sopenharmony_ciimport itertools 28b8021494Sopenharmony_ciimport random 29b8021494Sopenharmony_ciimport os.path 30b8021494Sopenharmony_cifrom copy import deepcopy 31b8021494Sopenharmony_ci 32b8021494Sopenharmony_ciclass OperandList(object): 33b8021494Sopenharmony_ci """ 34b8021494Sopenharmony_ci Convenience class representing a list of operand objects. It can be viewed is 35b8021494Sopenharmony_ci an iterator over operand objects. 36b8021494Sopenharmony_ci 37b8021494Sopenharmony_ci Attributes: 38b8021494Sopenharmony_ci operand_list 39b8021494Sopenharmony_ci """ 40b8021494Sopenharmony_ci 41b8021494Sopenharmony_ci def __init__(self, operand_list): 42b8021494Sopenharmony_ci self.operand_list = operand_list 43b8021494Sopenharmony_ci 44b8021494Sopenharmony_ci def __iter__(self): 45b8021494Sopenharmony_ci return iter(self.operand_list) 46b8021494Sopenharmony_ci 47b8021494Sopenharmony_ci def unwrap(self): 48b8021494Sopenharmony_ci """ 49b8021494Sopenharmony_ci Return a list of `Operand` objects, unwrapping `OperandWrapper` objects into 50b8021494Sopenharmony_ci `Operand` objects. For example: 51b8021494Sopenharmony_ci 52b8021494Sopenharmony_ci ~~~ 53b8021494Sopenharmony_ci Condition, Register, Operand(Register, Shift, Register) 54b8021494Sopenharmony_ci ~~~ 55b8021494Sopenharmony_ci 56b8021494Sopenharmony_ci Unwraps to: 57b8021494Sopenharmony_ci 58b8021494Sopenharmony_ci ~~~ 59b8021494Sopenharmony_ci Condition, Register, Register, Shift, Register 60b8021494Sopenharmony_ci ~~~ 61b8021494Sopenharmony_ci """ 62b8021494Sopenharmony_ci return itertools.chain(*self.operand_list) 63b8021494Sopenharmony_ci 64b8021494Sopenharmony_ci def ExcludeVariants(self, type_name, variant_to_exclude): 65b8021494Sopenharmony_ci """ 66b8021494Sopenharmony_ci Remove variants in `variant_to_exclude` from operands with type `type_name`. 67b8021494Sopenharmony_ci """ 68b8021494Sopenharmony_ci # Find the list of operand with type `type_name`. 69b8021494Sopenharmony_ci relevant_operands = filter(lambda operand: operand.type_name == type_name, 70b8021494Sopenharmony_ci self) 71b8021494Sopenharmony_ci for operand in relevant_operands: 72b8021494Sopenharmony_ci # Remove the intersection of the existing variants and variants we do not 73b8021494Sopenharmony_ci # want. 74b8021494Sopenharmony_ci for variant in set(operand.variants) & set(variant_to_exclude): 75b8021494Sopenharmony_ci operand.variants.remove(variant) 76b8021494Sopenharmony_ci 77b8021494Sopenharmony_ci def GetNames(self): 78b8021494Sopenharmony_ci """ 79b8021494Sopenharmony_ci Return the list of all `Operand` names, excluding `OperandWrapper` objects. 80b8021494Sopenharmony_ci """ 81b8021494Sopenharmony_ci return [operand.name for operand in self.unwrap()] 82b8021494Sopenharmony_ci 83b8021494Sopenharmony_ci 84b8021494Sopenharmony_ciclass InputList(object): 85b8021494Sopenharmony_ci """ 86b8021494Sopenharmony_ci Convenience class representing a list of input objects. 87b8021494Sopenharmony_ci 88b8021494Sopenharmony_ci This class is an iterator over input objects. 89b8021494Sopenharmony_ci 90b8021494Sopenharmony_ci Attributes: 91b8021494Sopenharmony_ci inputs 92b8021494Sopenharmony_ci """ 93b8021494Sopenharmony_ci 94b8021494Sopenharmony_ci def __init__(self, inputs): 95b8021494Sopenharmony_ci self.inputs = inputs 96b8021494Sopenharmony_ci 97b8021494Sopenharmony_ci def __iter__(self): 98b8021494Sopenharmony_ci return iter(self.inputs) 99b8021494Sopenharmony_ci 100b8021494Sopenharmony_ci def GetNames(self): 101b8021494Sopenharmony_ci """ 102b8021494Sopenharmony_ci Return the list of input names. 103b8021494Sopenharmony_ci """ 104b8021494Sopenharmony_ci return [input.name for input in self] 105b8021494Sopenharmony_ci 106b8021494Sopenharmony_ci 107b8021494Sopenharmony_ciclass TestCase(object): 108b8021494Sopenharmony_ci """ 109b8021494Sopenharmony_ci Object representation of a test case, as described in JSON. This object is 110b8021494Sopenharmony_ci used to build sets of operands and inputs that will be used by the generator 111b8021494Sopenharmony_ci to produce C++ arrays. 112b8021494Sopenharmony_ci 113b8021494Sopenharmony_ci Attributes: 114b8021494Sopenharmony_ci name Name of the test case, it is used to name the array to 115b8021494Sopenharmony_ci produce. 116b8021494Sopenharmony_ci seed Seed value to use for reproducible random generation. 117b8021494Sopenharmony_ci operand_names List of operand names this test case covers. 118b8021494Sopenharmony_ci input_names List of input names this test case covers. 119b8021494Sopenharmony_ci operand_filter Python expression as a string to filter out operands. 120b8021494Sopenharmony_ci input_filter Python expression as a string to filter out inputs. 121b8021494Sopenharmony_ci operand_limit Optional limit of the number of operands to generate. 122b8021494Sopenharmony_ci input_limit Optional limit of the number of inputs to generate. 123b8021494Sopenharmony_ci it_condition If not None, an IT instruction needs to be generated for the 124b8021494Sopenharmony_ci instruction under test to be valid. This member is a string 125b8021494Sopenharmony_ci template indicating the name of the condition operand, to be 126b8021494Sopenharmony_ci used with "format". For example, it will most likely have 127b8021494Sopenharmony_ci the value "{cond}". 128b8021494Sopenharmony_ci """ 129b8021494Sopenharmony_ci 130b8021494Sopenharmony_ci # Declare functions that will be callable from Python expressions in 131b8021494Sopenharmony_ci # `self.operand_filter`. 132b8021494Sopenharmony_ci operand_filter_runtime = { 133b8021494Sopenharmony_ci 'register_is_low': lambda register: 134b8021494Sopenharmony_ci register in ["r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7"] 135b8021494Sopenharmony_ci } 136b8021494Sopenharmony_ci 137b8021494Sopenharmony_ci def __init__(self, name, seed, operand_names, input_names, operand_filter, 138b8021494Sopenharmony_ci input_filter, operand_limit, input_limit, it_condition): 139b8021494Sopenharmony_ci self.name = name 140b8021494Sopenharmony_ci self.seed = seed 141b8021494Sopenharmony_ci self.operand_names = operand_names 142b8021494Sopenharmony_ci self.input_names = input_names 143b8021494Sopenharmony_ci self.operand_filter = operand_filter 144b8021494Sopenharmony_ci self.input_filter = input_filter 145b8021494Sopenharmony_ci self.operand_limit = operand_limit 146b8021494Sopenharmony_ci self.input_limit = input_limit 147b8021494Sopenharmony_ci self.it_condition = it_condition 148b8021494Sopenharmony_ci 149b8021494Sopenharmony_ci def GenerateOperands(self, operand_types): 150b8021494Sopenharmony_ci """ 151b8021494Sopenharmony_ci Generate a list of tuples, each tuple describing what operands to pass to an 152b8021494Sopenharmony_ci instruction to encode it. We use this to generate operand definitions. 153b8021494Sopenharmony_ci 154b8021494Sopenharmony_ci The algorithm used is a simple product of all operand variants. To limit 155b8021494Sopenharmony_ci what we generate, we choose to apply the product only on operands with their 156b8021494Sopenharmony_ci name in the `self.operand_names` list. 157b8021494Sopenharmony_ci 158b8021494Sopenharmony_ci Additionally, we use the Python expression in `self.operand_filter` to 159b8021494Sopenharmony_ci filter out tuples we do not want. 160b8021494Sopenharmony_ci 161b8021494Sopenharmony_ci Argument: 162b8021494Sopenharmony_ci operand_types The `OperandList` object that describe the form of the 163b8021494Sopenharmony_ci instruction to generate code for. 164b8021494Sopenharmony_ci """ 165b8021494Sopenharmony_ci # Build a list of all possible variants as a list of tuples. If the 166b8021494Sopenharmony_ci # operand's name is not in `self.operand_names`, then we restrict the list 167b8021494Sopenharmony_ci # to contain default variant. Each tuple in the list has the form 168b8021494Sopenharmony_ci # `(name, [variant1, variant2, ...])`. For example: 169b8021494Sopenharmony_ci # 170b8021494Sopenharmony_ci # [ 171b8021494Sopenharmony_ci # ('cond', ['al', 'ne', 'eq', ...]), # All condition variants. 172b8021494Sopenharmony_ci # ('rd', ['r0', 'r1', ...]), # All register variants. 173b8021494Sopenharmony_ci # ('rn', ['r0']) # Default register variant (r0). 174b8021494Sopenharmony_ci # ... 175b8021494Sopenharmony_ci # ] 176b8021494Sopenharmony_ci variants = [ 177b8021494Sopenharmony_ci [(operand_type.name, variant) for variant in operand_type.variants] 178b8021494Sopenharmony_ci if operand_type.name in self.operand_names 179b8021494Sopenharmony_ci else [(operand_type.name, operand_type.default)] 180b8021494Sopenharmony_ci for operand_type in operand_types.unwrap() 181b8021494Sopenharmony_ci ] 182b8021494Sopenharmony_ci lambda_string = "lambda {args}: {expression}".format( 183b8021494Sopenharmony_ci args=",".join(operand_types.GetNames()), 184b8021494Sopenharmony_ci expression=self.operand_filter) 185b8021494Sopenharmony_ci filter_lambda = eval(lambda_string, self.operand_filter_runtime) 186b8021494Sopenharmony_ci 187b8021494Sopenharmony_ci def BuildOperandDefinition(operands): 188b8021494Sopenharmony_ci """ 189b8021494Sopenharmony_ci Take a list of tuples describing the operands and build a definition from 190b8021494Sopenharmony_ci it. A definition is a tuple with a list of variants and a 191b8021494Sopenharmony_ci `expect_instruction_before` string. 192b8021494Sopenharmony_ci 193b8021494Sopenharmony_ci For example, we are turning this: 194b8021494Sopenharmony_ci 195b8021494Sopenharmony_ci [ 196b8021494Sopenharmony_ci ('cond', 'ne'), 197b8021494Sopenharmony_ci ('rd', 'r0'), 198b8021494Sopenharmony_ci ('rn', 'r1'), 199b8021494Sopenharmony_ci ('rm', 'r0) 200b8021494Sopenharmony_ci [ 201b8021494Sopenharmony_ci 202b8021494Sopenharmony_ci Into: 203b8021494Sopenharmony_ci 204b8021494Sopenharmony_ci (['ne', 'r0', 'r1', 'r0'], "It ne;") 205b8021494Sopenharmony_ci 206b8021494Sopenharmony_ci """ 207b8021494Sopenharmony_ci return ( 208b8021494Sopenharmony_ci # Build a list of operands by only keeping the second element of each 209b8021494Sopenharmony_ci # tuple. 210b8021494Sopenharmony_ci [operand[1] for operand in operands], 211b8021494Sopenharmony_ci # The next field is a boolean indicating if the test case needs to 212b8021494Sopenharmony_ci # generate an IT instruction. 213b8021494Sopenharmony_ci "true" if self.it_condition else "false", 214b8021494Sopenharmony_ci # If so, what condition should it be? 215b8021494Sopenharmony_ci self.it_condition.format(**dict(operands)) if self.it_condition else "al" 216b8021494Sopenharmony_ci ) 217b8021494Sopenharmony_ci 218b8021494Sopenharmony_ci # Build and return a list of operand definitions by computing the product of 219b8021494Sopenharmony_ci # all variants and filtering them with `filter_lambda`. 220b8021494Sopenharmony_ci # 221b8021494Sopenharmony_ci # Operand definitions consist of a list with a list of variants and an 222b8021494Sopenharmony_ci # optional `expect_instruction_before` string. For example: 223b8021494Sopenharmony_ci # 224b8021494Sopenharmony_ci # [ 225b8021494Sopenharmony_ci # (['al', 'r0', 'r1', 'r2'], ""), 226b8021494Sopenharmony_ci # (['ne', 'r0', 'r1', 'r0'], "It ne;"), 227b8021494Sopenharmony_ci # ... 228b8021494Sopenharmony_ci # ] 229b8021494Sopenharmony_ci # 230b8021494Sopenharmony_ci # Here, the filtered product of variants builds a list of lists of tuples, as such: 231b8021494Sopenharmony_ci # 232b8021494Sopenharmony_ci # [ 233b8021494Sopenharmony_ci # [('cond', 'al'), ('rd', 'r0'), ('rn', 'r1'), ('rn', 'r2')] 234b8021494Sopenharmony_ci # [('cond', 'ne'), ('rd', 'r0'), ('rn', 'r1'), ('rn', 'r0')], 235b8021494Sopenharmony_ci # ... 236b8021494Sopenharmony_ci # ] 237b8021494Sopenharmony_ci # 238b8021494Sopenharmony_ci # We then pass them to `BuildOperandDefinition` to produce the expected form 239b8021494Sopenharmony_ci # out of it. 240b8021494Sopenharmony_ci result = [ 241b8021494Sopenharmony_ci BuildOperandDefinition(operands) 242b8021494Sopenharmony_ci for operands in itertools.product(*variants) 243b8021494Sopenharmony_ci if filter_lambda(**dict(operands)) 244b8021494Sopenharmony_ci ] 245b8021494Sopenharmony_ci if self.operand_limit is None: 246b8021494Sopenharmony_ci return result 247b8021494Sopenharmony_ci else: 248b8021494Sopenharmony_ci # Use a fixed seed to randomly choose a limited set of operands. 249b8021494Sopenharmony_ci random.seed(self.seed) 250b8021494Sopenharmony_ci return random.sample(result, self.operand_limit) 251b8021494Sopenharmony_ci 252b8021494Sopenharmony_ci def GenerateInputs(self, input_types): 253b8021494Sopenharmony_ci """ 254b8021494Sopenharmony_ci Generate a list of tuples, each tuple describing what input to pass to an 255b8021494Sopenharmony_ci instruction at runtime. We use this to generate input definitions. 256b8021494Sopenharmony_ci 257b8021494Sopenharmony_ci The algorithm used is a simple product of all input values. To limit what 258b8021494Sopenharmony_ci we generate, we choose to apply the product only on inputs with their name 259b8021494Sopenharmony_ci in the `self.input_names` list. 260b8021494Sopenharmony_ci 261b8021494Sopenharmony_ci Additionally, we use the Python expression in `self.input_filter` to filter 262b8021494Sopenharmony_ci out tuples we do not want. 263b8021494Sopenharmony_ci 264b8021494Sopenharmony_ci Argument: 265b8021494Sopenharmony_ci input_types The `InputList` object describing the list of inputs the 266b8021494Sopenharmony_ci instruction can take. 267b8021494Sopenharmony_ci """ 268b8021494Sopenharmony_ci # Build a list of all possible values as a list of lists. If the input's 269b8021494Sopenharmony_ci # name is not in `self.input_names`, then we restrict the list to the 270b8021494Sopenharmony_ci # default value. 271b8021494Sopenharmony_ci values = [ 272b8021494Sopenharmony_ci input_type.values 273b8021494Sopenharmony_ci if input_type.name in self.input_names else [input_type.default] 274b8021494Sopenharmony_ci for input_type in input_types 275b8021494Sopenharmony_ci ] 276b8021494Sopenharmony_ci lambda_string = "lambda {args}: {expression}".format( 277b8021494Sopenharmony_ci args=", ".join(input_types.GetNames()), 278b8021494Sopenharmony_ci expression=self.input_filter) 279b8021494Sopenharmony_ci filter_lambda = eval(lambda_string) 280b8021494Sopenharmony_ci # Build and return a list of input definitions, such as 281b8021494Sopenharmony_ci # [('NoFlag', '0xffffffff', 0xabababab'), ...] for example. 282b8021494Sopenharmony_ci result = [ 283b8021494Sopenharmony_ci input_definition 284b8021494Sopenharmony_ci for input_definition in itertools.product(*values) 285b8021494Sopenharmony_ci if filter_lambda(*input_definition) 286b8021494Sopenharmony_ci ] 287b8021494Sopenharmony_ci if self.input_limit is None: 288b8021494Sopenharmony_ci return result 289b8021494Sopenharmony_ci else: 290b8021494Sopenharmony_ci # Use a fixed seed to randomly choose a limited set of inputs. 291b8021494Sopenharmony_ci random.seed(self.seed) 292b8021494Sopenharmony_ci return random.sample(result, self.input_limit) 293b8021494Sopenharmony_ci 294b8021494Sopenharmony_ci 295b8021494Sopenharmony_ciclass Generator(object): 296b8021494Sopenharmony_ci """ 297b8021494Sopenharmony_ci A `Generator` object contains all information needed to generate a test file. 298b8021494Sopenharmony_ci Each method will return a string used to fill a variable in a template. 299b8021494Sopenharmony_ci 300b8021494Sopenharmony_ci 301b8021494Sopenharmony_ci Attributes: 302b8021494Sopenharmony_ci test_name Name of the test inferred from the name of the configuration 303b8021494Sopenharmony_ci file. It has the following form: `type-op1-op2-op3-isa`. 304b8021494Sopenharmony_ci test_isa Instruction set supported by the test, either 'a32' or 't32'. 305b8021494Sopenharmony_ci test_type Type of the test, extracted from test_name. 306b8021494Sopenharmony_ci mnemonics List of instruction mnemonics. 307b8021494Sopenharmony_ci operands `OperandList` object. 308b8021494Sopenharmony_ci inputs `InputList` object. 309b8021494Sopenharmony_ci test_cases List of `TestCase` objects. 310b8021494Sopenharmony_ci """ 311b8021494Sopenharmony_ci 312b8021494Sopenharmony_ci def __init__(self, test_name, test_isa, test_type, mnemonics, operands, 313b8021494Sopenharmony_ci inputs, test_cases): 314b8021494Sopenharmony_ci self.test_name = test_name 315b8021494Sopenharmony_ci self.test_isa = test_isa 316b8021494Sopenharmony_ci self.test_type = test_type 317b8021494Sopenharmony_ci self.mnemonics = mnemonics 318b8021494Sopenharmony_ci self.inputs = inputs 319b8021494Sopenharmony_ci self.test_cases = test_cases 320b8021494Sopenharmony_ci 321b8021494Sopenharmony_ci # A simulator test cannot easily make use of the PC and SP registers. 322b8021494Sopenharmony_ci if self.test_type == "simulator": 323b8021494Sopenharmony_ci # We need to explicitly create our own deep copy the operands before we 324b8021494Sopenharmony_ci # can modify them. 325b8021494Sopenharmony_ci self.operands = deepcopy(operands) 326b8021494Sopenharmony_ci self.operands.ExcludeVariants("Register", ["r13", "r15"]) 327b8021494Sopenharmony_ci else: 328b8021494Sopenharmony_ci self.operands = operands 329b8021494Sopenharmony_ci 330b8021494Sopenharmony_ci def MnemonicToMethodName(self, mnemonic): 331b8021494Sopenharmony_ci if self.test_type in ["simulator", "macro-assembler"]: 332b8021494Sopenharmony_ci # Return a MacroAssembler method name 333b8021494Sopenharmony_ci return mnemonic.capitalize() 334b8021494Sopenharmony_ci else: 335b8021494Sopenharmony_ci # Return an Assembler method name 336b8021494Sopenharmony_ci method_name = mnemonic.lower() 337b8021494Sopenharmony_ci return "and_" if method_name == "and" else method_name 338b8021494Sopenharmony_ci 339b8021494Sopenharmony_ci def InstructionListDeclaration(self): 340b8021494Sopenharmony_ci """ 341b8021494Sopenharmony_ci ~~~ 342b8021494Sopenharmony_ci M(Adc) \ 343b8021494Sopenharmony_ci M(Adcs) \ 344b8021494Sopenharmony_ci M(Add) \ 345b8021494Sopenharmony_ci M(Adds) \ 346b8021494Sopenharmony_ci M(And) \ 347b8021494Sopenharmony_ci ... 348b8021494Sopenharmony_ci ~~~ 349b8021494Sopenharmony_ci """ 350b8021494Sopenharmony_ci return "".join([ 351b8021494Sopenharmony_ci "M({}) \\\n".format(self.MnemonicToMethodName(mnemonic)) 352b8021494Sopenharmony_ci for mnemonic in self.mnemonics 353b8021494Sopenharmony_ci ]) 354b8021494Sopenharmony_ci 355b8021494Sopenharmony_ci def OperandDeclarations(self): 356b8021494Sopenharmony_ci """ 357b8021494Sopenharmony_ci ~~~ 358b8021494Sopenharmony_ci Condition cond; 359b8021494Sopenharmony_ci Register rd; 360b8021494Sopenharmony_ci Register rn; 361b8021494Sopenharmony_ci ... 362b8021494Sopenharmony_ci ~~~ 363b8021494Sopenharmony_ci """ 364b8021494Sopenharmony_ci return "".join([operand.Declare() for operand in self.operands]) 365b8021494Sopenharmony_ci 366b8021494Sopenharmony_ci def InputDeclarations(self): 367b8021494Sopenharmony_ci """ 368b8021494Sopenharmony_ci ~~~ 369b8021494Sopenharmony_ci uint32_t cond; 370b8021494Sopenharmony_ci uint32_t rd; 371b8021494Sopenharmony_ci uint32_t rn; 372b8021494Sopenharmony_ci ... 373b8021494Sopenharmony_ci ~~~ 374b8021494Sopenharmony_ci """ 375b8021494Sopenharmony_ci return "".join([input.Declare() for input in self.inputs]) 376b8021494Sopenharmony_ci 377b8021494Sopenharmony_ci def InputDefinitions(self): 378b8021494Sopenharmony_ci """ 379b8021494Sopenharmony_ci ~~~ 380b8021494Sopenharmony_ci static const Inputs kCondition[] = {{...},{...}, ...}; 381b8021494Sopenharmony_ci static const Inputs kRdIsRd[] = {{...},{...}, ...}; 382b8021494Sopenharmony_ci ... 383b8021494Sopenharmony_ci ~~~ 384b8021494Sopenharmony_ci """ 385b8021494Sopenharmony_ci def InputDefinition(test_input): 386b8021494Sopenharmony_ci inputs = [ 387b8021494Sopenharmony_ci "{{{}}}".format(",".join(input)) 388b8021494Sopenharmony_ci for input in test_input.GenerateInputs(self.inputs) 389b8021494Sopenharmony_ci ] 390b8021494Sopenharmony_ci 391b8021494Sopenharmony_ci return """static const Inputs k{name}[] = {{ {input} }}; 392b8021494Sopenharmony_ci """.format(name=test_input.name, input=",".join(inputs)) 393b8021494Sopenharmony_ci 394b8021494Sopenharmony_ci return "\n".join(map(InputDefinition, self.test_cases)) 395b8021494Sopenharmony_ci 396b8021494Sopenharmony_ci def TestCaseDefinitions(self): 397b8021494Sopenharmony_ci """ 398b8021494Sopenharmony_ci For simulator tests: 399b8021494Sopenharmony_ci ~~~ 400b8021494Sopenharmony_ci {{eq, r0, r0, ...}, 401b8021494Sopenharmony_ci "eq r0 r0 ...", 402b8021494Sopenharmony_ci "Condition_eq_r0_...", 403b8021494Sopenharmony_ci ARRAY_SIZE(kCondition), kCondition}, 404b8021494Sopenharmony_ci ... 405b8021494Sopenharmony_ci {{eq, r0, r0, ...}, 406b8021494Sopenharmony_ci "eq r0 r0 ...", 407b8021494Sopenharmony_ci "RdIsRd_eq_r0_...", 408b8021494Sopenharmony_ci ARRAY_SIZE(kRdIsRd), kRdIsRn}, 409b8021494Sopenharmony_ci ... 410b8021494Sopenharmony_ci ~~~ 411b8021494Sopenharmony_ci 412b8021494Sopenharmony_ci For assembler tests: 413b8021494Sopenharmony_ci ~~~ 414b8021494Sopenharmony_ci {{eq, r0, r0, ...}, 415b8021494Sopenharmony_ci "", 416b8021494Sopenharmony_ci "eq r0 r0 ...", 417b8021494Sopenharmony_ci "Condition_eq_r0_...", 418b8021494Sopenharmony_ci ... 419b8021494Sopenharmony_ci {{eq, r0, r0, ...}, 420b8021494Sopenharmony_ci "", 421b8021494Sopenharmony_ci "eq r0 r0 ...", 422b8021494Sopenharmony_ci "RdIsRd_eq_r0_..."} 423b8021494Sopenharmony_ci ... 424b8021494Sopenharmony_ci {{eq, r0, r0, ...}, 425b8021494Sopenharmony_ci "It eq", 426b8021494Sopenharmony_ci "eq r0 r0 ...", 427b8021494Sopenharmony_ci "RdIsRd_eq_r0_..."} 428b8021494Sopenharmony_ci ... 429b8021494Sopenharmony_ci ~~~ 430b8021494Sopenharmony_ci """ 431b8021494Sopenharmony_ci def SimulatorTestCaseDefinition(test_case): 432b8021494Sopenharmony_ci test_cases = [ 433b8021494Sopenharmony_ci """{{ {{ {operands} }}, 434b8021494Sopenharmony_ci "{operands_description}", 435b8021494Sopenharmony_ci "{identifier}", 436b8021494Sopenharmony_ci ARRAY_SIZE(k{test_case_name}), 437b8021494Sopenharmony_ci k{test_case_name} }} 438b8021494Sopenharmony_ci """.format(operands=",".join(operand), 439b8021494Sopenharmony_ci operands_description=" ".join(operand), 440b8021494Sopenharmony_ci identifier=test_case.name + "_" + "_".join(operand), 441b8021494Sopenharmony_ci test_case_name=test_case.name) 442b8021494Sopenharmony_ci for operand, _, _ in test_case.GenerateOperands(self.operands) 443b8021494Sopenharmony_ci ] 444b8021494Sopenharmony_ci return ",\n".join(test_cases) 445b8021494Sopenharmony_ci 446b8021494Sopenharmony_ci def AssemblerTestCaseDefinition(test_case): 447b8021494Sopenharmony_ci test_cases = [ 448b8021494Sopenharmony_ci """{{ {{ {operands} }}, 449b8021494Sopenharmony_ci {in_it_block}, 450b8021494Sopenharmony_ci {it_condition}, 451b8021494Sopenharmony_ci "{operands_description}", 452b8021494Sopenharmony_ci "{identifier}" }} 453b8021494Sopenharmony_ci """.format(operands=",".join(operand), 454b8021494Sopenharmony_ci in_it_block=in_it_block, 455b8021494Sopenharmony_ci it_condition=it_condition, 456b8021494Sopenharmony_ci operands_description=" ".join(operand), 457b8021494Sopenharmony_ci identifier="_".join(operand)) 458b8021494Sopenharmony_ci for operand, in_it_block, it_condition 459b8021494Sopenharmony_ci in test_case.GenerateOperands(self.operands) 460b8021494Sopenharmony_ci ] 461b8021494Sopenharmony_ci return ",\n".join(test_cases) 462b8021494Sopenharmony_ci 463b8021494Sopenharmony_ci def MacroAssemblerTestCaseDefinition(test_case): 464b8021494Sopenharmony_ci test_cases = [ 465b8021494Sopenharmony_ci """{{ {{ {operands} }}, 466b8021494Sopenharmony_ci "{operands_description}", 467b8021494Sopenharmony_ci "{identifier}" }} 468b8021494Sopenharmony_ci """.format(operands=",".join(operand), 469b8021494Sopenharmony_ci operands_description=", ".join(operand), 470b8021494Sopenharmony_ci identifier="_".join(operand)) 471b8021494Sopenharmony_ci for operand, _, _ in test_case.GenerateOperands(self.operands) 472b8021494Sopenharmony_ci ] 473b8021494Sopenharmony_ci return ",\n".join(test_cases) 474b8021494Sopenharmony_ci 475b8021494Sopenharmony_ci if self.test_type == "simulator": 476b8021494Sopenharmony_ci return ",\n".join(map(SimulatorTestCaseDefinition, self.test_cases)) 477b8021494Sopenharmony_ci elif self.test_type == "assembler": 478b8021494Sopenharmony_ci return ",\n".join(map(AssemblerTestCaseDefinition, self.test_cases)) 479b8021494Sopenharmony_ci elif self.test_type == "macro-assembler": 480b8021494Sopenharmony_ci return ",\n".join(map(MacroAssemblerTestCaseDefinition, self.test_cases)) 481b8021494Sopenharmony_ci elif self.test_type == "assembler-negative": 482b8021494Sopenharmony_ci return ",\n".join(map(MacroAssemblerTestCaseDefinition, self.test_cases)) 483b8021494Sopenharmony_ci else: 484b8021494Sopenharmony_ci raise Exception("Unrecognized test type \"{}\".".format(self.test_type)) 485b8021494Sopenharmony_ci 486b8021494Sopenharmony_ci def IncludeTraceFiles(self): 487b8021494Sopenharmony_ci """ 488b8021494Sopenharmony_ci ~~~ 489b8021494Sopenharmony_ci #include "aarch32/traces/sim-...-a32.h" 490b8021494Sopenharmony_ci #include "aarch32/traces/sim-...-a32.h" 491b8021494Sopenharmony_ci ... 492b8021494Sopenharmony_ci ~~~ 493b8021494Sopenharmony_ci """ 494b8021494Sopenharmony_ci operands = "-".join(self.operands.GetNames()) 495b8021494Sopenharmony_ci return "".join([ 496b8021494Sopenharmony_ci "#include \"aarch32/traces/" + self.GetTraceFileName(mnemonic) + "\"\n" 497b8021494Sopenharmony_ci for mnemonic in self.mnemonics 498b8021494Sopenharmony_ci ]) 499b8021494Sopenharmony_ci 500b8021494Sopenharmony_ci def MacroAssemblerMethodArgs(self): 501b8021494Sopenharmony_ci """ 502b8021494Sopenharmony_ci ~~~ 503b8021494Sopenharmony_ci Condition cond, Register rd, Register rm, const Operand& immediate 504b8021494Sopenharmony_ci ~~~ 505b8021494Sopenharmony_ci """ 506b8021494Sopenharmony_ci return ", ".join([ 507b8021494Sopenharmony_ci operand.GetArgumentType() + " " + operand.name 508b8021494Sopenharmony_ci for operand in self.operands 509b8021494Sopenharmony_ci ]) 510b8021494Sopenharmony_ci 511b8021494Sopenharmony_ci def MacroAssemblerSetISA(self): 512b8021494Sopenharmony_ci """ 513b8021494Sopenharmony_ci Generate code to set the ISA. 514b8021494Sopenharmony_ci """ 515b8021494Sopenharmony_ci if self.test_isa == "t32": 516b8021494Sopenharmony_ci return "masm.UseT32();" 517b8021494Sopenharmony_ci else: 518b8021494Sopenharmony_ci return "masm.UseA32();" 519b8021494Sopenharmony_ci 520b8021494Sopenharmony_ci def CodeInstantiateOperands(self): 521b8021494Sopenharmony_ci """ 522b8021494Sopenharmony_ci ~~~ 523b8021494Sopenharmony_ci Condition cond = kTests[i].operands.cond; 524b8021494Sopenharmony_ci Register rd = kTests[i].operands.rd; 525b8021494Sopenharmony_ci ... 526b8021494Sopenharmony_ci ~~~ 527b8021494Sopenharmony_ci """ 528b8021494Sopenharmony_ci code = "".join([operand.Instantiate() for operand in self.operands]) 529b8021494Sopenharmony_ci if self.test_type in ["simulator", "macro-assembler"]: 530b8021494Sopenharmony_ci # Simulator tests need scratch registers to function and uses 531b8021494Sopenharmony_ci # `UseScratchRegisterScope` to dynamically allocate them. We need to 532b8021494Sopenharmony_ci # exclude all register operands from the list of available scratch 533b8021494Sopenharmony_ci # registers. 534b8021494Sopenharmony_ci # MacroAssembler tests also need to ensure that they don't try to run tests 535b8021494Sopenharmony_ci # with registers that are scratch registers; the MacroAssembler contains 536b8021494Sopenharmony_ci # assertions to protect against such usage. 537b8021494Sopenharmony_ci excluded_registers = [ 538b8021494Sopenharmony_ci "scratch_registers.Exclude({});".format(operand.name) 539b8021494Sopenharmony_ci for operand in self.operands.unwrap() 540b8021494Sopenharmony_ci if operand.type_name == "Register" 541b8021494Sopenharmony_ci ] 542b8021494Sopenharmony_ci return code + "\n".join(excluded_registers) 543b8021494Sopenharmony_ci return code 544b8021494Sopenharmony_ci 545b8021494Sopenharmony_ci def CodePrologue(self): 546b8021494Sopenharmony_ci """ 547b8021494Sopenharmony_ci ~~~ 548b8021494Sopenharmony_ci __ Ldr(rn, MemOperand(input_ptr, offsetof(Inputs, rn))); 549b8021494Sopenharmony_ci __ Ldr(rm, MemOperand(input_ptr, offsetof(Inputs, rm))); 550b8021494Sopenharmony_ci ... 551b8021494Sopenharmony_ci ~~~ 552b8021494Sopenharmony_ci """ 553b8021494Sopenharmony_ci return "".join([input.Prologue() for input in self.inputs]) 554b8021494Sopenharmony_ci 555b8021494Sopenharmony_ci def CodeEpilogue(self): 556b8021494Sopenharmony_ci """ 557b8021494Sopenharmony_ci ~~~ 558b8021494Sopenharmony_ci __ Str(rn, MemOperand(result_ptr, offsetof(Inputs, rn))); 559b8021494Sopenharmony_ci __ Str(rm, MemOperand(result_ptr, offsetof(Inputs, rm))); 560b8021494Sopenharmony_ci ... 561b8021494Sopenharmony_ci ~~~ 562b8021494Sopenharmony_ci """ 563b8021494Sopenharmony_ci return "".join([input.Epilogue() for input in self.inputs]) 564b8021494Sopenharmony_ci 565b8021494Sopenharmony_ci def CodeParameterList(self): 566b8021494Sopenharmony_ci """ 567b8021494Sopenharmony_ci ~~~ 568b8021494Sopenharmony_ci cond, rd, rn, immediate 569b8021494Sopenharmony_ci ~~~ 570b8021494Sopenharmony_ci """ 571b8021494Sopenharmony_ci return ", ".join([ 572b8021494Sopenharmony_ci operand.name 573b8021494Sopenharmony_ci for operand in self.operands 574b8021494Sopenharmony_ci ]) 575b8021494Sopenharmony_ci 576b8021494Sopenharmony_ci def TracePrintOutputs(self): 577b8021494Sopenharmony_ci """ 578b8021494Sopenharmony_ci ~~~ 579b8021494Sopenharmony_ci printf("0x%08" PRIx32, results[i]->outputs[j].cond); 580b8021494Sopenharmony_ci printf(", "); 581b8021494Sopenharmony_ci printf("0x%08" PRIx32, results[i]->outputs[j].rd); 582b8021494Sopenharmony_ci printf(", "); 583b8021494Sopenharmony_ci ... 584b8021494Sopenharmony_ci ~~~ 585b8021494Sopenharmony_ci """ 586b8021494Sopenharmony_ci return "printf(\", \");".join( 587b8021494Sopenharmony_ci [input.PrintOutput() for input in self.inputs]) 588b8021494Sopenharmony_ci 589b8021494Sopenharmony_ci 590b8021494Sopenharmony_ci def CheckInstantiateResults(self): 591b8021494Sopenharmony_ci """ 592b8021494Sopenharmony_ci ~~~ 593b8021494Sopenharmony_ci uint32_t cond = results[i]->outputs[j].cond; 594b8021494Sopenharmony_ci uint32_t rd = results[i]->outputs[j].rd; 595b8021494Sopenharmony_ci ... 596b8021494Sopenharmony_ci ~~~ 597b8021494Sopenharmony_ci """ 598b8021494Sopenharmony_ci return "".join([input.InstantiateResult() for input in self.inputs]) 599b8021494Sopenharmony_ci 600b8021494Sopenharmony_ci def CheckInstantiateInputs(self): 601b8021494Sopenharmony_ci """ 602b8021494Sopenharmony_ci ~~~ 603b8021494Sopenharmony_ci uint32_t cond_input = kTests[i].inputs[j].cond; 604b8021494Sopenharmony_ci uint32_t rd_input = kTests[i].inputs[j].rd; 605b8021494Sopenharmony_ci ... 606b8021494Sopenharmony_ci ~~~ 607b8021494Sopenharmony_ci """ 608b8021494Sopenharmony_ci return "".join([input.InstantiateInput("_input") for input in self.inputs]) 609b8021494Sopenharmony_ci 610b8021494Sopenharmony_ci def CheckInstantiateReferences(self): 611b8021494Sopenharmony_ci """ 612b8021494Sopenharmony_ci ~~~ 613b8021494Sopenharmony_ci uint32_t cond_ref = reference[i].outputs[j].cond; 614b8021494Sopenharmony_ci uint32_t rd_ref = reference[i].outputs[j].rd; 615b8021494Sopenharmony_ci ... 616b8021494Sopenharmony_ci ~~~ 617b8021494Sopenharmony_ci """ 618b8021494Sopenharmony_ci return "".join([input.InstantiateReference("_ref") for input in self.inputs]) 619b8021494Sopenharmony_ci 620b8021494Sopenharmony_ci def CheckResultsAgainstReferences(self): 621b8021494Sopenharmony_ci """ 622b8021494Sopenharmony_ci ~~~ 623b8021494Sopenharmony_ci (cond != cond_ref) || (rd != rd_ref) || ... 624b8021494Sopenharmony_ci ~~~ 625b8021494Sopenharmony_ci """ 626b8021494Sopenharmony_ci return " || ".join([input.Compare("", "!=", "_ref") for input in self.inputs]) 627b8021494Sopenharmony_ci 628b8021494Sopenharmony_ci def CheckPrintInput(self): 629b8021494Sopenharmony_ci """ 630b8021494Sopenharmony_ci ~~~ 631b8021494Sopenharmony_ci printf("0x%08" PRIx32, cond_input); 632b8021494Sopenharmony_ci printf(", "); 633b8021494Sopenharmony_ci printf("0x%08" PRIx32, rd_input); 634b8021494Sopenharmony_ci printf(", "); 635b8021494Sopenharmony_ci ... 636b8021494Sopenharmony_ci ~~~ 637b8021494Sopenharmony_ci """ 638b8021494Sopenharmony_ci return "printf(\", \");".join( 639b8021494Sopenharmony_ci [input.PrintInput("_input") for input in self.inputs]) 640b8021494Sopenharmony_ci 641b8021494Sopenharmony_ci def CheckPrintExpected(self): 642b8021494Sopenharmony_ci """ 643b8021494Sopenharmony_ci ~~~ 644b8021494Sopenharmony_ci printf("0x%08" PRIx32, cond_ref); 645b8021494Sopenharmony_ci printf(", "); 646b8021494Sopenharmony_ci printf("0x%08" PRIx32, rd_ref); 647b8021494Sopenharmony_ci printf(", "); 648b8021494Sopenharmony_ci ... 649b8021494Sopenharmony_ci ~~~ 650b8021494Sopenharmony_ci """ 651b8021494Sopenharmony_ci return "printf(\", \");".join( 652b8021494Sopenharmony_ci [input.PrintInput("_ref") for input in self.inputs]) 653b8021494Sopenharmony_ci 654b8021494Sopenharmony_ci def CheckPrintFound(self): 655b8021494Sopenharmony_ci """ 656b8021494Sopenharmony_ci ~~~ 657b8021494Sopenharmony_ci printf("0x%08" PRIx32, cond); 658b8021494Sopenharmony_ci printf(", "); 659b8021494Sopenharmony_ci printf("0x%08" PRIx32, rd); 660b8021494Sopenharmony_ci printf(", "); 661b8021494Sopenharmony_ci ... 662b8021494Sopenharmony_ci ~~~ 663b8021494Sopenharmony_ci """ 664b8021494Sopenharmony_ci return "printf(\", \");".join( 665b8021494Sopenharmony_ci [input.PrintInput("") for input in self.inputs]) 666b8021494Sopenharmony_ci 667b8021494Sopenharmony_ci def TestName(self): 668b8021494Sopenharmony_ci """ 669b8021494Sopenharmony_ci ~~~ 670b8021494Sopenharmony_ci SIMULATOR_COND_RD_RN_RM_... 671b8021494Sopenharmony_ci ~~~ 672b8021494Sopenharmony_ci """ 673b8021494Sopenharmony_ci return self.test_type.replace("-", "_").upper() + "_" + \ 674b8021494Sopenharmony_ci self.test_name.replace("-", "_").upper() 675b8021494Sopenharmony_ci 676b8021494Sopenharmony_ci def TestISA(self): 677b8021494Sopenharmony_ci return self.test_isa.upper() 678b8021494Sopenharmony_ci 679b8021494Sopenharmony_ci def GetTraceFileName(self, mnemonic): 680b8021494Sopenharmony_ci """ 681b8021494Sopenharmony_ci Return the name of a trace file for a given mnemonic. 682b8021494Sopenharmony_ci """ 683b8021494Sopenharmony_ci return self.test_type + "-" + self.test_name + "-" + \ 684b8021494Sopenharmony_ci mnemonic.lower() + "-" + self.test_isa + ".h" 685b8021494Sopenharmony_ci 686b8021494Sopenharmony_ci def WriteEmptyTraces(self, output_directory): 687b8021494Sopenharmony_ci """ 688b8021494Sopenharmony_ci Write out empty trace files so we can compile the new test cases. 689b8021494Sopenharmony_ci """ 690b8021494Sopenharmony_ci for mnemonic in self.mnemonics: 691b8021494Sopenharmony_ci # The MacroAssembler and negative assembler tests have no traces. 692b8021494Sopenharmony_ci if self.test_type in ["macro-assembler", "assembler-negative"]: continue 693b8021494Sopenharmony_ci 694b8021494Sopenharmony_ci with open(os.path.join(output_directory, self.GetTraceFileName(mnemonic)), 695b8021494Sopenharmony_ci "w") as f: 696b8021494Sopenharmony_ci code = "static const TestResult *kReference{} = NULL;\n" 697b8021494Sopenharmony_ci f.write(code.format(self.MnemonicToMethodName(mnemonic))) 698b8021494Sopenharmony_ci 699b8021494Sopenharmony_ci def GetIsaGuard(self): 700b8021494Sopenharmony_ci """ 701b8021494Sopenharmony_ci This guard ensure the ISA of the test is enabled. 702b8021494Sopenharmony_ci """ 703b8021494Sopenharmony_ci if self.test_isa == 'a32': 704b8021494Sopenharmony_ci return 'VIXL_INCLUDE_TARGET_A32' 705b8021494Sopenharmony_ci else: 706b8021494Sopenharmony_ci assert self.test_isa == 't32' 707b8021494Sopenharmony_ci return 'VIXL_INCLUDE_TARGET_T32' 708b8021494Sopenharmony_ci 709