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