From ef509a45670c206416ddad7b3eed5eb880c5bca8 Mon Sep 17 00:00:00 2001 From: Jeremy Johnson Date: Tue, 7 Sep 2021 13:59:47 +0100 Subject: Fix for ADD/SUB saturation in tests Change-Id: I4f05b256f4f439f72e5ee8bce60e4e92b6aaa6e7 Signed-off-by: Jeremy Johnson --- verif/tosa_test_gen.py | 62 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/verif/tosa_test_gen.py b/verif/tosa_test_gen.py index 942f75c..3e14c5b 100644 --- a/verif/tosa_test_gen.py +++ b/verif/tosa_test_gen.py @@ -1969,8 +1969,66 @@ class TosaTestGen: # Build the random tensor operands and the test tens = [] - # If test is ArithmeticRightShift, force value of operand[1] to be within [0, num_bits] - if op["op"] == Op.ARITHMETIC_RIGHT_SHIFT: + if (op["op"] == Op.ADD or op["op"] == Op.SUB) and dtypeList[0] == DType.INT32: + # Make sure the operation does not cause value saturation - where + # the number wraps due to limited number of bits to store the answer + assert ( + pCount == 2 and cCount == 0 + ), "Op.ADD / Op.SUB must have 2 placeholders, 0 consts" + + placeholders = [] + add = (op["op"] == Op.ADD) + a_arr = self.getRandTensor(shapeList[0], dtypeList[0]) + b_arr = self.getRandTensor(shapeList[1], dtypeList[1]) + if add: + res_arr = np.add(a_arr, b_arr, dtype=np.int64) + else: + res_arr = np.subtract(a_arr, b_arr, dtype=np.int64) + + # Work out the saturation limits + max_i32 = (1 << 31)-1 + min_i32 = -(1 << 31) + max_arr = np.full(shapeList[1], max_i32) + min_arr = np.full(shapeList[1], min_i32) + + # Find how much values exceed the maximum/minimums + sat_max_arr = np.maximum(res_arr - max_arr, 0) + sat_min_arr = np.minimum(res_arr - min_arr, 0) + + if not add: + # Swap saturation values and negate values as we need to perform opposite operations + sat_max_arr, sat_min_arr = -sat_min_arr, -sat_max_arr + + # Create new array of unsaturated values by clipping values as needed + b_unsat_arr = b_arr + if (sat_max_arr != 0).any(): + # Clip values that cause saturation + b_unsat_arr = np.subtract(b_unsat_arr, sat_max_arr, dtype=np.int32) + # Reduce axes in unsaturated tensor to match original tensor + for axis, dim in enumerate(b_arr.shape): + if dim != b_unsat_arr.shape[axis]: + assert ( dim == 1 ), "Op.ADD / SUB dimension must be 1 or matching to be broadcastable" + b_unsat_arr = np.amin(b_unsat_arr, axis=axis, keepdims=True) + + if (sat_min_arr != 0).any(): + # Clip values that cause saturation + b_unsat_arr = np.subtract(b_unsat_arr, sat_min_arr, dtype=np.int32) + # Reduce axes in unsaturated tensor to match original tensor + for axis, dim in enumerate(b_arr.shape): + if dim != b_unsat_arr.shape[axis]: + assert ( dim == 1 ), "Op.ADD / SUB dimension must be 1 or matching to be broadcastable" + b_unsat_arr = np.amax(b_unsat_arr, axis=axis, keepdims=True) + + placeholders.append( + self.ser.addPlaceholder(shapeList[0], dtypeList[0], a_arr) + ) + placeholders.append( + self.ser.addPlaceholder(shapeList[1], dtypeList[1], b_unsat_arr) + ) + + tens.extend(placeholders) + elif op["op"] == Op.ARITHMETIC_RIGHT_SHIFT: + # Force value of operand[1] to be within [0, num_bits] assert ( pCount == 2 and cCount == 0 ), "Op.ArithmeticRightShift must have 2 placeholders, 0 consts" -- cgit v1.2.1