def gen_test_case_with_const(self): """generate tests calling function with const""" cnt = 0 cases = '\n\n;; Const vs const' for op in self.BINARY_OPS: for param_1, param_2 in self.get_test_data_with_const: result = [] for idx in range(0, len(param_1)): result.append( IntOp.binary_op(op, param_1[idx], param_2[idx], self.lane_width)) cases += '\n' + str( AssertReturn( '{lane_type}.{op}_with_const_{cnt}'.format( lane_type=self.LANE_TYPE, op=op, cnt=cnt), [], SIMD.v128_const(result, self.LANE_TYPE))) cnt += 1 cases += '\n\n;; Param vs const' for op in self.BINARY_OPS: for param_1, param_2 in self.get_test_data_with_const: result = [] for idx in range(0, len(param_1)): result.append( IntOp.binary_op(op, param_1[idx], param_2[idx], self.lane_width)) cases += '\n' + str( AssertReturn( '{lane_type}.{op}_with_const_{cnt}'.format( lane_type=self.LANE_TYPE, op=op, cnt=cnt), [SIMD.v128_const(param_2, self.LANE_TYPE)], SIMD.v128_const(result, self.LANE_TYPE))) cnt += 1 return cases
def get_combine_cases(self): combine_cases = [';; combination\n(module'] ternary_func_template = ' (func (export "{func}") (param v128 v128 v128) (result v128)\n' \ ' ({lane}.{op1} ({lane}.{op2} (local.get 0) (local.get 1))'\ '(local.get 2)))' for func in sorted(self.combine_ternary_arith_test_data): func_parts = func.split('-') op1 = func_parts[1].replace('_', '_saturate_') op2 = func_parts[2].replace('_', '_saturate_') combine_cases.append(ternary_func_template.format(func=func, lane=self.LANE_TYPE, op1=op1, op2=op2)) binary_func_template = ' (func (export "{func}") (param v128 v128) (result v128)\n'\ ' ({lane}.{op1} ({lane}.{op2} (local.get 0)) (local.get 1)))' for func in sorted(self.combine_binary_arith_test_data): func_parts = func.split('-') op1 = func_parts[1].replace('_', '_saturate_') combine_cases.append(binary_func_template.format(func=func, lane=self.LANE_TYPE, op1=op1, op2=func_parts[2])) combine_cases.append(')\n') for func, test in sorted(self.combine_ternary_arith_test_data.items()): combine_cases.append(str(AssertReturn(func, [SIMD.v128_const(elem, self.LANE_TYPE) for elem in test[:-1]], SIMD.v128_const(test[-1], self.LANE_TYPE)))) for func, test in sorted(self.combine_binary_arith_test_data.items()): combine_cases.append(str(AssertReturn(func, [SIMD.v128_const(elem, self.LANE_TYPE) for elem in test[:-1]], SIMD.v128_const(test[-1], self.LANE_TYPE)))) return '\n'.join(combine_cases)
def get_normal_case(self): s = SIMD() cases = [] # store using arg for (addr, ret) in self.get_case_data(): i32_addr = s.const(addr, "i32") v128_val = s.v128_const(list_stringify(ret), self.LANE_TYPE) result = s.const(ret[addr], "i64") instr = "v128.store{lane_len}_lane_{idx}".format( lane_len=self.LANE_LEN, idx=addr) cases.append(str(AssertReturn(instr, [i32_addr, v128_val], result))) # store using offset for (addr, ret) in self.get_case_data(): v128_val = s.v128_const(list_stringify(ret), self.LANE_TYPE) result = s.const(ret[addr], "i64") instr = "v128.store{lane_len}_lane_{idx}_offset_{idx}".format( lane_len=self.LANE_LEN, idx=addr) cases.append(str(AssertReturn(instr, [v128_val], result))) # store using offset with alignment for (addr, ret) in self.get_case_data(): for align in self.valid_alignments(): i32_addr = s.const(addr, "i32") v128_val = s.v128_const(list_stringify(ret), self.LANE_TYPE) result = s.const(ret[addr], "i64") instr = "v128.store{lane_len}_lane_{idx}_align_{align}".format( lane_len=self.LANE_LEN, idx=addr, align=align) cases.append( str(AssertReturn(instr, [i32_addr, v128_val], result))) return '\n'.join(cases)
def get_normal_case(self): s = SIMD() case_data = self.get_case_data() cases = [] for item in case_data: # Recognize '#' as a commentary if item[0] == '#': cases.append('\n;; {}'.format(item[1])) continue """ Generate assert_return Params: instruction: instruction name; param: param for instruction; ret: excepted result; lane_type: lane type """ instruction, param, ret, lane_type = item cases.append( str( AssertReturn(instruction, [ s.v128_const(param[0], lane_type[0]), s.v128_const(param[1], lane_type[1]) ], s.v128_const(ret, lane_type[2])))) return '\n'.join(cases)
def gen_test_case_combination(self): """generate combination test cases""" cases = '\n' binary_ops = list(self.BINARY_OPS) binary_ops.reverse() for op1 in self.BINARY_OPS: for op2 in binary_ops: result = [] ret = IntOp.binary_op(op2, '0', '1', self.lane_width) ret = IntOp.binary_op(op1, ret, '2', self.lane_width) result.append(ret) cases += '\n' + str( AssertReturn( '{lane_type}.{op1}-{lane_type}.{op2}'.format( lane_type=self.LANE_TYPE, op1=op1, op2=op2), [ SIMD.v128_const('0', self.LANE_TYPE), SIMD.v128_const('1', self.LANE_TYPE), SIMD.v128_const('2', self.LANE_TYPE) ], SIMD.v128_const(result, self.LANE_TYPE))) cases += '\n' return cases
def get_normal_case(self): cases = [] for op in self.UNARY_OPS: src_lane_type = self.src_lane_type(op) src_value = self.LANE_VALUE[src_lane_type] operands = self.get_test_cases(src_value) for (low, high) in operands: result = low if "low" in op else high if self.is_unsigned(op): # Unsign-extend, mask top bits. result = result & src_value.mask cases.append( str( AssertReturn( op, [SIMD.v128_const([str(low), str(high)], src_lane_type)], SIMD.v128_const(str(result), self.dst_lane_type(op)), ) ) ) cases.append("") return "\n".join(cases)
def gen(case_data): cases = '' for op in self.BINARY_OPS: for param_1, param_2 in case_data: result = [] for idx in range(0, len(param_1)): result.append(IntOp.binary_op(op, param_1[idx], param_2[idx], self.lane_width)) cases += '\n' + str(AssertReturn('{lane_type}.{op}'.format(lane_type=self.LANE_TYPE, op=op), [SIMD.v128_const(param_1, self.LANE_TYPE), SIMD.v128_const(param_2, self.LANE_TYPE)], SIMD.v128_const(result, self.LANE_TYPE))) return cases
def gen_unary(case_data): cases = '' for op in self.UNARY_OPS: o = ArithmeticOp(op) for param in case_data: result = [] for idx in range(0, len(param)): result.append(o.unary_op(param[idx], self.LANE_VALUE)) cases += '\n' + str( AssertReturn( '{lane_type}.{op}'.format(lane_type=self.LANE_TYPE, op=op), [SIMD.v128_const(param, self.LANE_TYPE)], SIMD.v128_const(result, self.LANE_TYPE))) return cases
def get_normal_case(self): """ Generate normal case with test data """ lst_i_p_r = self.init_case_data(self.get_case_data()) cases = [] for ipr in lst_i_p_r: if ipr[0] == '#': cases.append(ipr[1]) continue cases.append(str(AssertReturn(ipr[0], ipr[1], ipr[2]))) return '\n'.join(cases)
def get_normal_case(self): s = SIMD() case_data = self.get_case_data() cases = [] for item in case_data: # Recognize '#' as a commentary if item[0] == '#': cases.append('\n;; {}'.format(item[1])) continue instruction, param, ret, lane_type = item v128_result = s.v128_const(ret, lane_type[-1]) v128_params = [] for i, p in enumerate(param): v128_params.append(s.v128_const(p, lane_type[i])) cases.append( str(AssertReturn(instruction, v128_params, v128_result))) return '\n'.join(cases)
def get_normal_case(self): """Normal test cases from WebAssembly core tests """ cases = [] binary_test_data = [] unary_test_data = [] for op in self.BINARY_OPS: op_name = self.full_op_name(op) for p1 in self.FLOAT_NUMBERS: for p2 in self.FLOAT_NUMBERS: result = self.floatOp.binary_op(op, p1, p2) if 'nan' not in result: # Normal floating point numbers as the results binary_test_data.append( ['assert_return', op_name, p1, p2, result]) else: # Since the results contain the 'nan' string, the result literals would be # nan:canonical binary_test_data.append([ 'assert_return', op_name, p1, p2, 'nan:canonical' ]) for p1 in self.NAN_NUMBERS: for p2 in self.FLOAT_NUMBERS: if 'nan:' in p1 or 'nan:' in p2: # When the arguments contain 'nan:', the result literal is nan:arithmetic binary_test_data.append([ 'assert_return', op_name, p1, p2, 'nan:arithmetic' ]) else: # No 'nan' string found, then the result literal is nan:canonical binary_test_data.append([ 'assert_return', op_name, p1, p2, 'nan:canonical' ]) for p2 in self.NAN_NUMBERS: if 'nan:' in p1 or 'nan:' in p2: binary_test_data.append([ 'assert_return', op_name, p1, p2, 'nan:arithmetic' ]) else: binary_test_data.append([ 'assert_return', op_name, p1, p2, 'nan:canonical' ]) for p1 in self.LITERAL_NUMBERS: for p2 in self.LITERAL_NUMBERS: result = self.floatOp.binary_op(op, p1, p2, hex_form=False) binary_test_data.append( ['assert_return', op_name, p1, p2, result]) for case in binary_test_data: cases.append(self.single_binary_test(case)) # Test opposite signs of zero lst_oppo_signs_0 = [ '\n;; Test opposite signs of zero', [ 'f64x2.min', [['0', '0'], ['+0', '-0']], [['0', '-0']], ['f64x2', 'f64x2', 'f64x2'] ], [ 'f64x2.min', [['-0', '+0'], ['+0', '-0']], [['-0', '-0']], ['f64x2', 'f64x2', 'f64x2'] ], [ 'f64x2.min', [['-0', '-0'], ['+0', '+0']], [['-0', '-0']], ['f64x2', 'f64x2', 'f64x2'] ], [ 'f64x2.max', [['0', '0'], ['+0', '-0']], [['0', '0']], ['f64x2', 'f64x2', 'f64x2'] ], [ 'f64x2.max', [['-0', '+0'], ['+0', '-0']], [['0', '0']], ['f64x2', 'f64x2', 'f64x2'] ], [ 'f64x2.max', [['-0', '-0'], ['+0', '+0']], [['+0', '+0']], ['f64x2', 'f64x2', 'f64x2'] ], '\n' ] # Generate test case for opposite signs of zero for case_data in lst_oppo_signs_0: if isinstance(case_data, str): cases.append(case_data) continue cases.append( str( AssertReturn( case_data[0], [ self.v128_const(case_data[3][0], case_data[1][0]), self.v128_const(case_data[3][1], case_data[1][1]) ], self.v128_const(case_data[3][2], case_data[2][0])))) for p in self.FLOAT_NUMBERS + self.LITERAL_NUMBERS: op_name = self.full_op_name('abs') hex_literal = True if p in self.LITERAL_NUMBERS: hex_literal = False result = self.floatOp.unary_op('abs', p, hex_form=hex_literal) # Abs operation is valid for all the floating point numbers unary_test_data.append(['assert_return', op_name, p, result]) for case in unary_test_data: cases.append(self.single_unary_test(case)) return '\n'.join(cases)
def gen_test_func_template(self): # Get function code template = Simdf32x4ArithmeticCase.gen_test_func_template(self) # Function template tpl_func = ' (func (export "{func}"){params} (result v128) ({op} {operand_1}{operand_2}))' # Raw data list specific for "const vs const" and "param vs const" tests" const_test_raw_data = [[[['0', '1'], ['0', '2']], [['0', '1'], ['0', '2']]], [[['2', '-3'], ['1', '3']], [['1', '-3'], ['2', '3']]], [[['0', '1'], ['0', '1']], [['0', '1'], ['0', '1']]], [[['2', '3'], ['2', '3']], [['2', '3'], ['2', '3']]], [[['0x00', '0x01'], ['0x00', '0x02']], [['0x00', '0x01'], ['0x00', '0x02']]], [[['0x02', '0x80000000'], ['0x01', '2147483648']], [['0x01', '0x80000000'], ['0x02', '2147483648']]], [[['0x00', '0x01'], ['0x00', '0x01']], [['0x00', '0x01'], ['0x00', '0x01']]], [[['0x02', '0x80000000'], ['0x02', '0x80000000']], [['0x02', '0x80000000'], ['0x02', '0x80000000']]]] # Test data list combined with `const_test_raw_data` and corresponding ops and function names # specific for "const vs const" and "param vs const" tests const_test_data = {} # Generate func and assert for op in self.BINARY_OPS: op_name = self.full_op_name(op) # Add comment for the case script " ;; [f64x2.min, f64x2.max] const vs const" template.insert( len(template) - 1, ' ;; {} const vs const'.format(op_name)) # Add const vs const cases for case_data in const_test_raw_data: func = "{op}_with_const_{index}".format(op=op_name, index=len(template) - 7) template.insert( len(template) - 1, tpl_func.format(func=func, params='', op=op_name, operand_1=self.v128_const( 'f64x2', case_data[0][0]), operand_2=' ' + self.v128_const('f64x2', case_data[0][1]))) ret_idx = 0 if op == 'min' else 1 if op not in const_test_data: const_test_data[op] = [] const_test_data[op].append([func, case_data[1][ret_idx]]) # Add comment for the case script " ;; [f64x2.min, f64x2.max] param vs const" template.insert( len(template) - 1, ' ;; {} param vs const'.format(op_name)) case_cnt = 0 # Add param vs const cases for case_data in const_test_raw_data: func = "{op}_with_const_{index}".format(op=op_name, index=len(template) - 7) # Cross parameters and constants if case_cnt in (0, 3): operand_1 = '(local.get 0)' operand_2 = self.v128_const('f64x2', case_data[0][0]) else: operand_1 = self.v128_const('f64x2', case_data[0][0]) operand_2 = '(local.get 0)' template.insert( len(template) - 1, tpl_func.format(func=func, params=' (param v128)', op=op_name, operand_1=operand_1, operand_2=' ' + operand_2)) ret_idx = 0 if op == 'min' else 1 if op not in const_test_data: const_test_data[op] = [] const_test_data[op].append( [func, case_data[0][1], case_data[1][ret_idx]]) case_cnt += 1 # Generate func for abs op_name = self.full_op_name('abs') template.insert(len(template) - 1, '') func = "{op}_with_const_{index}".format(op=op_name, index=35) template.insert( len(template) - 1, tpl_func.format(func=func, params='', op=op_name, operand_1=self.v128_const('f64x2', ['-0', '-1']), operand_2='')) func = "{op}_with_const_{index}".format(op=op_name, index=36) template.insert( len(template) - 1, tpl_func.format(func=func, params='', op=op_name, operand_1=self.v128_const('f64x2', ['-2', '-3']), operand_2='')) # Test different lanes go through different if-then clauses lst_diff_lane_vs_clause = [[ 'f64x2.min', [['nan', '0'], ['0', '1']], [['nan', '0']], ['f64x2', 'f64x2', 'f64x2'] ], [ 'f64x2.min', [['0', '1'], ['-nan', '0']], [['-nan', '0']], ['f64x2', 'f64x2', 'f64x2'] ], [ 'f64x2.min', [['0', '1'], ['-nan', '1']], [['nan:canonical', '1']], ['f64x2', 'f64x2', 'f64x2'] ], [ 'f64x2.max', [['nan', '0'], ['0', '1']], [['nan:canonical', '1']], ['f64x2', 'f64x2', 'f64x2'] ], [ 'f64x2.max', [['0', '1'], ['-nan', '0']], [['nan:canonical', '1']], ['f64x2', 'f64x2', 'f64x2'] ], [ 'f64x2.max', [['0', '1'], ['-nan', '1']], [['nan:canonical', '1']], ['f64x2', 'f64x2', 'f64x2'] ]] # Template for assert tpl_assert = '(assert_return\n' \ ' (invoke "{func}"\n' \ ' {operand_1}\n' \ ' {operand_2}\n' \ ' )\n' \ ' {expected_result}\n' \ ')' lst_diff_lane_vs_clause_assert = [] # Add comment in wast script lst_diff_lane_vs_clause_assert.append('') lst_diff_lane_vs_clause_assert.append( ';; Test different lanes go through different if-then clauses') for case_data in lst_diff_lane_vs_clause: lst_diff_lane_vs_clause_assert.append( ';; {lane_type}'.format(lane_type=case_data[0])) lst_diff_lane_vs_clause_assert.append( tpl_assert.format( func=case_data[0], operand_1=self.v128_const(case_data[3][0], case_data[1][0]), operand_2=self.v128_const(case_data[3][1], case_data[1][1]), expected_result=self.v128_const(case_data[3][2], case_data[2][0]))) lst_diff_lane_vs_clause_assert.append('') # Add test for operations with constant operands for key in const_test_data: op_name = self.full_op_name(key) case_cnt = 0 for case_data in const_test_data[key]: # Add comment for the param combination if case_cnt == 0: template.append(';; {} const vs const'.format(op_name)) if case_cnt == 4: template.append(';; {} param vs const'.format(op_name)) # Cross parameters and constants if case_cnt < 8: template.append( str( AssertReturn( case_data[0], [], self.v128_const('f64x2', case_data[1])))) else: template.append( str( AssertReturn( case_data[0], [self.v128_const('f64x2', case_data[1])], self.v128_const('f64x2', case_data[2])))) case_cnt += 1 # Generate and append f64x2.abs assert op_name = self.full_op_name('abs') template.append('') func = "{op}_with_const_{index}".format(op=op_name, index=35) template.append( str(AssertReturn(func, [], self.v128_const('f64x2', ['0', '1'])))) func = "{op}_with_const_{index}".format(op=op_name, index=36) template.append( str(AssertReturn(func, [], self.v128_const('f64x2', ['2', '3'])))) template.extend(lst_diff_lane_vs_clause_assert) return template
def get_normal_case(self): """Normal test cases from WebAssembly core tests, 4 assert statements: assert_return assert_return_canonical_nan assert_return_arithmetic_nan assert_malformed """ cases = [] binary_test_data = [] unary_test_data = [] for op in self.BINARY_OPS: op_name = self.full_op_name(op) for p1 in self.FLOAT_NUMBERS: for p2 in self.FLOAT_NUMBERS: result = self.floatOp.binary_op(op, p1, p2) if 'nan' not in result: # Normal floating point numbers as the results binary_test_data.append( ['assert_return', op_name, p1, p2, result]) else: # Since the results contain the 'nan' string, it should be in the # assert_return_canonical_nan statements binary_test_data.append([ 'assert_return_canonical_nan_f64x2', op_name, p1, p2 ]) # assert_return_canonical_nan and assert_return_arithmetic_nan cases for p1 in self.NAN_NUMBERS: for p2 in self.FLOAT_NUMBERS: if 'nan:' in p1 or 'nan:' in p2: # When the arguments contain 'nan:', always use assert_return_arithmetic_nan # statements for the cases. Since there 2 parameters for binary operation and # the order of the parameters matter. Different order makes different cases. binary_test_data.append([ 'assert_return_arithmetic_nan_f64x2', op_name, p1, p2 ]) binary_test_data.append([ 'assert_return_arithmetic_nan_f64x2', op_name, p2, p1 ]) else: # No 'nan' string found, then it should be assert_return_canonical_nan. binary_test_data.append([ 'assert_return_canonical_nan_f64x2', op_name, p1, p2 ]) binary_test_data.append([ 'assert_return_canonical_nan_f64x2', op_name, p2, p1 ]) for p2 in self.NAN_NUMBERS: # Both parameters contain 'nan', then there must be no assert_return. if 'nan:' in p1 or 'nan:' in p2: binary_test_data.append([ 'assert_return_arithmetic_nan_f64x2', op_name, p1, p2 ]) else: binary_test_data.append([ 'assert_return_canonical_nan_f64x2', op_name, p1, p2 ]) for case in binary_test_data: cases.append(self.single_binary_test(case)) # Test opposite signs of zero lst_oppo_signs_0 = [ '\n;; Test opposite signs of zero', [ 'f64x2.min', [['0', '0'], ['+0', '-0']], [['0', '-0']], ['f64x2', 'f64x2', 'f64x2'] ], [ 'f64x2.min', [['-0', '+0'], ['+0', '-0']], [['-0', '-0']], ['f64x2', 'f64x2', 'f64x2'] ], [ 'f64x2.min', [['-0', '-0'], ['+0', '+0']], [['-0', '-0']], ['f64x2', 'f64x2', 'f64x2'] ], [ 'f64x2.max', [['0', '0'], ['+0', '-0']], [['0', '0']], ['f64x2', 'f64x2', 'f64x2'] ], [ 'f64x2.max', [['-0', '+0'], ['+0', '-0']], [['0', '0']], ['f64x2', 'f64x2', 'f64x2'] ], [ 'f64x2.max', [['-0', '-0'], ['+0', '+0']], [['+0', '+0']], ['f64x2', 'f64x2', 'f64x2'] ], '\n' ] # Generate test case for opposite signs of zero for case_data in lst_oppo_signs_0: if isinstance(case_data, str): cases.append(case_data) continue cases.append( str( AssertReturn( case_data[0], [ self.v128_const(case_data[3][0], case_data[1][0]), self.v128_const(case_data[3][1], case_data[1][1]) ], self.v128_const(case_data[3][2], case_data[2][0])))) for p in self.FLOAT_NUMBERS: op_name = self.full_op_name('abs') result = self.floatOp.unary_op('abs', p) # Abs operation is valid for all the floating point numbers unary_test_data.append(['assert_return', op_name, p, result]) for case in unary_test_data: cases.append(self.single_unary_test(case)) return '\n'.join(cases)
def gen_test_fn_template(self): # Get function code template = Simdf32x4ArithmeticCase.gen_test_fn_template(self) # Function template tpl_func = ' (func (export "{}"){} (result v128) ({} {}{}))' # Raw data list specific for "const vs const" and "param vs const" tests const_test_raw_data = [[[['0', '1'], ['0', '2']], [['0', '1'], ['0', '2']]], [[['2', '-3'], ['1', '3']], [['1', '-3'], ['2', '3']]], [[['0', '1'], ['0', '1']], [['0', '1'], ['0', '1']]], [[['2', '3'], ['2', '3']], [['2', '3'], ['2', '3']]], [[['0x00', '0x01'], ['0x00', '0x02']], [['0x00', '0x01'], ['0x00', '0x02']]], [[['0x02', '0x80000000'], ['0x01', '2147483648']], [['0x01', '0x80000000'], ['0x02', '2147483648']]], [[['0x00', '0x01'], ['0x00', '0x01']], [['0x00', '0x01'], ['0x00', '0x01']]], [[['0x02', '0x80000000'], ['0x02', '0x80000000']], [['0x02', '0x80000000'], ['0x02', '0x80000000']]]] # Test data list combined with `const_test_raw_data` and corresponding ops and function names # specific for "const vs const" and "param vs const" tests const_test_data = {} # Generate func and assert for op in self.BINARY_OPS: op_name = self.full_op_name(op) # Add comment for the case script " ;; [f64x2.min, f64x2.max] const vs const" template.insert( len(template) - 1, ' ;; {} const vs const'.format(op_name)) # Add const vs const cases for case_data in const_test_raw_data: func_name = "{}_with_const_{}".format(op_name, len(template) - 7) template.insert( len(template) - 1, tpl_func.format( func_name, '', op_name, self.v128_const('f64x2', case_data[0][0]), ' ' + self.v128_const('f64x2', case_data[0][1]))) ret_idx = 0 if op == 'min' else 1 if op not in const_test_data: const_test_data[op] = [] const_test_data[op].append([func_name, case_data[1][ret_idx]]) # Add comment for the case script " ;; [f64x2.min, f64x2.max] param vs const" template.insert( len(template) - 1, ' ;; {} param vs const'.format(op_name)) case_cnt = 0 # Add param vs const cases for case_data in const_test_raw_data: func_name = "{}_with_const_{}".format(op_name, len(template) - 7) # Cross parameters and constants if case_cnt in (0, 3): func_param_0 = '(local.get 0)' func_param_1 = self.v128_const('f64x2', case_data[0][0]) else: func_param_0 = self.v128_const('f64x2', case_data[0][0]) func_param_1 = '(local.get 0)' template.insert( len(template) - 1, tpl_func.format(func_name, ' (param v128)', op_name, func_param_0, ' ' + func_param_1)) ret_idx = 0 if op == 'min' else 1 if op not in const_test_data: const_test_data[op] = [] const_test_data[op].append( [func_name, case_data[0][1], case_data[1][ret_idx]]) case_cnt += 1 # Generate func for abs op_name = self.full_op_name('abs') template.insert(len(template) - 1, '') func_name = "{}_with_const_{}".format(op_name, 35) template.insert( len(template) - 1, tpl_func.format(func_name, '', op_name, self.v128_const('f64x2', ['-0', '-1']), '')) func_name = "{}_with_const_{}".format(op_name, 36) template.insert( len(template) - 1, tpl_func.format(func_name, '', op_name, self.v128_const('f64x2', ['-2', '-3']), '')) # Test different lanes go through different if-then clauses lst_diff_lane_vs_clause = [[ 'f64x2.min', [['nan', '0'], ['0', '1']], [['nan', '0']], ['f64x2', 'f64x2', 'f64x2'] ], [ 'f64x2.min', [['0', '1'], ['-nan', '0']], [['-nan', '0']], ['f64x2', 'f64x2', 'f64x2'] ], [ 'f64x2.min', [['0', '1'], ['-nan', '1']], [['-nan', '1']], ['f64x2', 'f64x2', 'f64x2'] ], [ 'f64x2.max', [['nan', '0'], ['0', '1']], [['nan', '1']], ['f64x2', 'f64x2', 'f64x2'] ], [ 'f64x2.max', [['0', '1'], ['-nan', '0']], [['-nan', '1']], ['f64x2', 'f64x2', 'f64x2'] ], [ 'f64x2.max', [['0', '1'], ['-nan', '1']], [['-nan', '1']], ['f64x2', 'f64x2', 'f64x2'] ]] # Case number case_cnt = 0 # Template for func name to extract a lane tpl_func_name_by_lane = 'call_indirect_vv_v_f64x2_extract_lane_{}' # Template for assert tpl_assert = '({}\n' \ ' (invoke "{}"\n' \ ' {}\n' \ ' {}\n' \ ' {}\n' \ ' )\n' \ '{}' \ ')' lst_diff_lane_vs_clause_assert = [] # Add comment in wast script lst_diff_lane_vs_clause_assert.append('') lst_diff_lane_vs_clause_assert.append( ';; Test different lanes go through different if-then clauses') template.insert(len(template) - 1, '') template.insert( len(template) - 1, ' ;; Test different lanes go through different if-then clauses') # Add test case for test different lanes go through different if-then clauses template.insert( len(template) - 1, ' (type $vv_v (func (param v128 v128) (result v128)))\n' ' (table funcref (elem $f64x2_min $f64x2_max))\n' '\n' ' (func $f64x2_min (type $vv_v)\n' ' (f64x2.min (local.get 0) (local.get 1))\n' ' )\n' '\n' ' (func $f64x2_max (type $vv_v)\n' ' (f64x2.max (local.get 0) (local.get 1))\n' ' )\n' '\n' ' (func (export "call_indirect_vv_v_f64x2_extract_lane_0")\n' ' (param v128 v128 i32) (result f64)\n' ' (f64x2.extract_lane 0\n' ' (call_indirect (type $vv_v) (local.get 0) (local.get 1) (local.get 2))\n' ' )\n' ' )\n' ' (func (export "call_indirect_vv_v_f64x2_extract_lane_1")\n' ' (param v128 v128 i32) (result f64)\n' ' (f64x2.extract_lane 1\n' ' (call_indirect (type $vv_v) (local.get 0) (local.get 1) (local.get 2))\n' ' )\n' ' )') for case_data in lst_diff_lane_vs_clause: lst_diff_lane_vs_clause_assert.append(';; {} {}'.format( case_data[0], case_cnt)) # generate assert for every data lane for lane_idx in range(0, len(case_data[2][0])): # get the result by lane ret = case_data[2][0][lane_idx] idx_func = '0' if 'min' in case_data[0] else '1' # append assert if 'nan' in ret: lst_diff_lane_vs_clause_assert.append( tpl_assert.format( 'assert_return_canonical_nan', tpl_func_name_by_lane.format(lane_idx), self.v128_const('f64x2', case_data[1][0]), self.v128_const('f64x2', case_data[1][1]), self.v128_const('i32', idx_func), '')) else: lst_diff_lane_vs_clause_assert.append( tpl_assert.format( 'assert_return', tpl_func_name_by_lane.format(lane_idx), self.v128_const('f64x2', case_data[1][0]), self.v128_const('f64x2', case_data[1][1]), self.v128_const('i32', idx_func), ' ' + self.v128_const('f64', ret) + '\n')) case_cnt += 1 if case_cnt == 2: case_cnt = 0 lst_diff_lane_vs_clause_assert.append('') # Add test for operations with constant operands for key in const_test_data: case_cnt = 0 for case_data in const_test_data[key]: # Add comment for the param combination if case_cnt == 0: template.append(';; {} const vs const'.format(op_name)) if case_cnt == 4: template.append(';; {} param vs const'.format(op_name)) # Cross parameters and constants if case_cnt < 8: template.append( str( AssertReturn( case_data[0], [], self.v128_const('f64x2', case_data[1])))) else: template.append( str( AssertReturn( case_data[0], [self.v128_const('f64x2', case_data[1])], self.v128_const('f64x2', case_data[2])))) case_cnt += 1 # Generate and append f64x2.abs assert op_name = self.full_op_name('abs') template.append('') func_name = "{}_with_const_{}".format(op_name, 35) template.append( str( AssertReturn(func_name, [], self.v128_const('f64x2', ['0', '1'])))) func_name = "{}_with_const_{}".format(op_name, 36) template.append( str( AssertReturn(func_name, [], self.v128_const('f64x2', ['2', '3'])))) template.extend(lst_diff_lane_vs_clause_assert) return template
def gen_test_case_combination(self): """generate combination test cases""" cases = '\n' binary_ops = list(self.BINARY_OPS) binary_ops.reverse() unary_ops = list(self.UNARY_OPS) unary_ops.reverse() for op1 in self.BINARY_OPS: """binary vs binary""" o1 = ArithmeticOp(op1) for op2 in binary_ops: o2 = ArithmeticOp(op2) result = [] ret = o2.binary_op('0', '1', self.LANE_VALUE) ret = o1.binary_op(ret, '2', self.LANE_VALUE) result.append(ret) cases += '\n' + str( AssertReturn( '{lane_type}.{op1}-{lane_type}.{op2}'.format( lane_type=self.LANE_TYPE, op1=op1, op2=op2), [ SIMD.v128_const('0', self.LANE_TYPE), SIMD.v128_const('1', self.LANE_TYPE), SIMD.v128_const('2', self.LANE_TYPE) ], SIMD.v128_const(result, self.LANE_TYPE))) for op2 in self.UNARY_OPS: """binary vs unary""" o2 = ArithmeticOp(op2) result1 = [] ret1 = o2.unary_op('-1', self.LANE_VALUE) ret1 = o1.binary_op(ret1, '0', self.LANE_VALUE) result1.append(ret1) cases += '\n' + str( AssertReturn( '{lane_type}.{op1}-{lane_type}.{op2}'.format( lane_type=self.LANE_TYPE, op1=op1, op2=op2), [ SIMD.v128_const('-1', self.LANE_TYPE), SIMD.v128_const('0', self.LANE_TYPE) ], SIMD.v128_const(result1, self.LANE_TYPE))) """unary vs binary""" result2 = [] ret2 = o1.binary_op('0', '-1', self.LANE_VALUE) ret2 = o2.unary_op(ret2, self.LANE_VALUE) result2.append(ret2) cases += '\n' + str( AssertReturn( '{lane_type}.{op1}-{lane_type}.{op2}'.format( lane_type=self.LANE_TYPE, op1=op2, op2=op1), [ SIMD.v128_const('0', self.LANE_TYPE), SIMD.v128_const('-1', self.LANE_TYPE) ], SIMD.v128_const(result2, self.LANE_TYPE))) for op1 in self.UNARY_OPS: """unary vs unary""" o1 = ArithmeticOp(op1) for op2 in unary_ops: o2 = ArithmeticOp(op2) result3 = [] ret3 = o2.unary_op('-1', self.LANE_VALUE) ret3 = o1.unary_op(ret3, self.LANE_VALUE) result3.append(ret3) cases += '\n' + str( AssertReturn( '{lane_type}.{op1}-{lane_type}.{op2}'.format( lane_type=self.LANE_TYPE, op1=op1, op2=op2), [SIMD.v128_const('-1', self.LANE_TYPE)], SIMD.v128_const(result3, self.LANE_TYPE))) cases += '\n' return cases
def gen_test_func_template(self): # Get function code template = Simdf32x4ArithmeticCase.gen_test_func_template(self) # Function template tpl_func = ' (func (export "{func}"){params} (result v128) ({op} {operand_1}{operand_2}))' # Const data for min and max lst_instr_with_const = [[[['0', '1', '2', '-3'], ['0', '2', '1', '3']], [['0', '1', '1', '-3'], ['0', '2', '2', '3']]], [[['0', '1', '2', '3'], ['0', '1', '2', '3']], [['0', '1', '2', '3'], ['0', '1', '2', '3']]], [[['0x00', '0x01', '0x02', '0x80000000'], ['0x00', '0x02', '0x01', '2147483648']], [['0x00', '0x01', '0x01', '0x80000000'], ['0x00', '0x02', '0x02', '2147483648']]], [[['0x00', '0x01', '0x02', '0x80000000'], ['0x00', '0x01', '0x02', '0x80000000']], [['0x00', '0x01', '0x02', '0x80000000'], ['0x00', '0x01', '0x02', '0x80000000']]]] # Assert data lst_oprt_with_const_assert = {} # Generate func and assert for op in self.BINARY_OPS: op_name = self.full_op_name(op) # Add comment for the case script " ;; [f32x4.min, f32x4.max] const vs const" template.insert( len(template) - 1, ' ;; {} const vs const'.format(op_name)) # Add const vs const cases for case_data in lst_instr_with_const: func = "{op}_with_const_{index}".format(op=op_name, index=len(template) - 7) template.insert( len(template) - 1, tpl_func.format(func=func, params='', op=op_name, operand_1=self.v128_const( 'f32x4', case_data[0][0]), operand_2=' ' + self.v128_const('f32x4', case_data[0][1]))) ret_idx = 0 if op == 'min' else 1 if op not in lst_oprt_with_const_assert: lst_oprt_with_const_assert[op] = [] lst_oprt_with_const_assert[op].append( [func, case_data[1][ret_idx]]) # Add comment for the case script " ;; [f32x4.min, f32x4.max] param vs const" template.insert( len(template) - 1, ' ;; {} param vs const'.format(op_name)) case_cnt = 0 # Add param vs const cases for case_data in lst_instr_with_const: func = "{}_with_const_{}".format(op_name, len(template) - 7) # Cross parameters and constants if case_cnt in (0, 3): operand_1 = '(local.get 0)' operand_2 = self.v128_const('f32x4', case_data[0][0]) else: operand_1 = self.v128_const('f32x4', case_data[0][0]) operand_2 = '(local.get 0)' template.insert( len(template) - 1, tpl_func.format(func=func, params='(param v128)', op=op_name, operand_1=operand_1, operand_2=' ' + operand_2)) ret_idx = 0 if op == 'min' else 1 if op not in lst_oprt_with_const_assert: lst_oprt_with_const_assert[op] = [] lst_oprt_with_const_assert[op].append( [func, case_data[0][1], case_data[1][ret_idx]]) case_cnt += 1 # Generate func for abs op_name = self.full_op_name('abs') func = "{}_with_const".format(op_name) template.insert(len(template) - 1, '') template.insert( len(template) - 1, tpl_func.format(func=func, params='', op=op_name, operand_1=self.v128_const( 'f32x4', ['-0', '-1', '-2', '-3']), operand_2='')) # Test different lanes go through different if-then clauses lst_diff_lane_vs_clause = [[ 'f32x4.min', [['nan', '0', '0', '1'], ['0', '-nan', '1', '0']], [['nan', '-nan', '0', '0']], ['f32x4', 'f32x4', 'f32x4'] ], [ 'f32x4.min', [['nan', '0', '0', '0'], ['0', '-nan', '1', '0']], [['nan', '-nan', '0', '0']], ['f32x4', 'f32x4', 'f32x4'] ], [ 'f32x4.max', [['nan', '0', '0', '1'], ['0', '-nan', '1', '0']], [['nan', '-nan', '1', '1']], ['f32x4', 'f32x4', 'f32x4'] ], [ 'f32x4.max', [['nan', '0', '0', '0'], ['0', '-nan', '1', '0']], [['nan', '-nan', '1', '0']], ['f32x4', 'f32x4', 'f32x4'] ]] # Case number case_cnt = 0 # Template for func name to extract a lane tpl_func_by_lane = 'call_indirect_vv_v_f32x4_extract_lane_{}' # Template for assert tpl_assert = '({assert_type}\n' \ ' (invoke "{func}"\n' \ ' {operand_1}\n' \ ' {operand_2}\n' \ ' {operand_3}\n' \ ' )\n' \ '{expected_result}' \ ')' lst_diff_lane_vs_clause_assert = [] # Add comment in wast script lst_diff_lane_vs_clause_assert.append('') lst_diff_lane_vs_clause_assert.append( ';; Test different lanes go through different if-then clauses') template.insert(len(template) - 1, '') template.insert( len(template) - 1, ' ;; Test different lanes go through different if-then clauses') # Add test case for test different lanes go through different if-then clauses template.insert( len(template) - 1, ' (type $vv_v (func (param v128 v128) (result v128)))\n' ' (table funcref (elem $f32x4_min $f32x4_max))\n' '\n' ' (func $f32x4_min (type $vv_v)\n' ' (f32x4.min (local.get 0) (local.get 1))\n' ' )\n' '\n' ' (func $f32x4_max (type $vv_v)\n' ' (f32x4.max (local.get 0) (local.get 1))\n' ' )\n' '\n' ' (func (export "call_indirect_vv_v_f32x4_extract_lane_0")\n' ' (param v128 v128 i32) (result f32)\n' ' (f32x4.extract_lane 0\n' ' (call_indirect (type $vv_v) (local.get 0) (local.get 1) (local.get 2))\n' ' )\n' ' )\n' ' (func (export "call_indirect_vv_v_f32x4_extract_lane_1")\n' ' (param v128 v128 i32) (result f32)\n' ' (f32x4.extract_lane 1\n' ' (call_indirect (type $vv_v) (local.get 0) (local.get 1) (local.get 2))\n' ' )\n' ' )\n' ' (func (export "call_indirect_vv_v_f32x4_extract_lane_2")\n' ' (param v128 v128 i32) (result f32)\n' ' (f32x4.extract_lane 2\n' ' (call_indirect (type $vv_v) (local.get 0) (local.get 1) (local.get 2))\n' ' )\n' ' )\n' ' (func (export "call_indirect_vv_v_f32x4_extract_lane_3")\n' ' (param v128 v128 i32) (result f32)\n' ' (f32x4.extract_lane 3\n' ' (call_indirect (type $vv_v) (local.get 0) (local.get 1) (local.get 2))\n' ' )\n' ' )') for case_data in lst_diff_lane_vs_clause: lst_diff_lane_vs_clause_assert.append( ';; {lane_type} {index}'.format(lane_type=case_data[0], index=case_cnt)) # generate assert for every data lane for lane_idx in range(0, len(case_data[2][0])): # get the result by lane ret = case_data[2][0][lane_idx] idx_func = '0' if 'min' in case_data[0] else '1' # append assert if 'nan' in ret: lst_diff_lane_vs_clause_assert.append( tpl_assert.format( assert_type='assert_return_canonical_nan', func=tpl_func_by_lane.format(lane_idx), operand_1=self.v128_const('f32x4', case_data[1][0]), operand_2=self.v128_const('f32x4', case_data[1][1]), operand_3=self.v128_const('i32', idx_func), expected_result='')) else: lst_diff_lane_vs_clause_assert.append( tpl_assert.format( assert_type='assert_return', func=tpl_func_by_lane.format(lane_idx), operand_1=self.v128_const('f32x4', case_data[1][0]), operand_2=self.v128_const('f32x4', case_data[1][1]), operand_3=self.v128_const('i32', idx_func), expected_result=' ' + self.v128_const('f32', ret) + '\n')) case_cnt += 1 if case_cnt == 2: case_cnt = 0 lst_diff_lane_vs_clause_assert.append('') # Add test for operations with constant operands for key in lst_oprt_with_const_assert: case_cnt = 0 for case_data in lst_oprt_with_const_assert[key]: # Add comment for the param combination if case_cnt == 0: template.append(';; {} const vs const'.format(op_name)) if case_cnt == 4: template.append(';; {} param vs const'.format(op_name)) # Cross parameters and constants if case_cnt < 4: template.append( str( AssertReturn( case_data[0], [], self.v128_const('f32x4', case_data[1])))) else: template.append( str( AssertReturn( case_data[0], [self.v128_const('f32x4', case_data[1])], self.v128_const('f32x4', case_data[2])))) case_cnt += 1 # Generate and append f32x4.abs assert op_name = self.full_op_name('abs') func = "{}_with_const".format(op_name) template.append('') template.append( str( AssertReturn(func, [], self.v128_const('f32x4', ['0', '1', '2', '3'])))) template.extend(lst_diff_lane_vs_clause_assert) return template