[PATCH 150/203] Implement OpenCL ternary conditional operator

Tom Tromey
2021-01-01T21:49:19Z

This implements the ?: ternary conditional operator for OpenCL.

gdb/ChangeLog
2021-01-01 Tom Tromey <tom@tromey.com>

* opencl-lang.c (opencl_ternop_cond_operation::evaluate): New
method.
* c-exp.h (class opencl_ternop_cond_operation): New.
---
gdb/ChangeLog | 6 ++++
gdb/c-exp.h | 16 +++++++++
gdb/opencl-lang.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 107 insertions(+)

diff --git a/gdb/c-exp.h b/gdb/c-exp.h
index f75b4aed952..0ce2bd6eb22 100644
--- a/gdb/c-exp.h
+++ b/gdb/c-exp.h
@@ -203,6 +203,22 @@ class opencl_logical_binop_operation
{ return std::get<0> (m_storage); }
};

+/* The ?: ternary operator for OpenCL. */
+class opencl_ternop_cond_operation
+ : public tuple_holding_operation<operation_up, operation_up, operation_up>
+{
+public:
+
+ using tuple_holding_operation::tuple_holding_operation;
+
+ value *evaluate (struct type *expect_type,
+ struct expression *exp,
+ enum noside noside) override;
+
+ enum exp_opcode opcode () const override
+ { return TERNOP_COND; }
+};
+
}/* namespace expr */

#endif /* C_EXP_H */
diff --git a/gdb/opencl-lang.c b/gdb/opencl-lang.c
index cca8505cfac..c5150953022 100644
--- a/gdb/opencl-lang.c
+++ b/gdb/opencl-lang.c
@@ -1032,6 +1032,91 @@ opencl_logical_binop_operation::evaluate (struct type *expect_type,
}
}

+value *
+opencl_ternop_cond_operation::evaluate (struct type *expect_type,
+ struct expression *exp,
+ enum noside noside)
+{
+ value *arg1 = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+ struct type *type1 = check_typedef (value_type (arg1));
+ if (type1->code () == TYPE_CODE_ARRAY && type1->is_vector ())
+ {
+ struct value *arg2, *arg3, *tmp, *ret;
+ struct type *eltype2, *type2, *type3, *eltype3;
+ int t2_is_vec, t3_is_vec, i;
+ LONGEST lowb1, lowb2, lowb3, highb1, highb2, highb3;
+
+ arg2 = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+ arg3 = std::get<2> (m_storage)->evaluate (nullptr, exp, noside);
+ type2 = check_typedef (value_type (arg2));
+ type3 = check_typedef (value_type (arg3));
+ t2_is_vec
+ = type2->code () == TYPE_CODE_ARRAY && type2->is_vector ();
+ t3_is_vec
+ = type3->code () == TYPE_CODE_ARRAY && type3->is_vector ();
+
+ /* Widen the scalar operand to a vector if necessary. */
+ if (t2_is_vec || !t3_is_vec)
+ {
+ arg3 = opencl_value_cast (type2, arg3);
+ type3 = value_type (arg3);
+ }
+ else if (!t2_is_vec || t3_is_vec)
+ {
+ arg2 = opencl_value_cast (type3, arg2);
+ type2 = value_type (arg2);
+ }
+ else if (!t2_is_vec || !t3_is_vec)
+ {
+ /* Throw an error if arg2 or arg3 aren't vectors. */
+ error (_("\
+Cannot perform conditional operation on incompatible types"));
+ }
+
+ eltype2 = check_typedef (TYPE_TARGET_TYPE (type2));
+ eltype3 = check_typedef (TYPE_TARGET_TYPE (type3));
+
+ if (!get_array_bounds (type1, &lowb1, &highb1)
+ || !get_array_bounds (type2, &lowb2, &highb2)
+ || !get_array_bounds (type3, &lowb3, &highb3))
+ error (_("Could not determine the vector bounds"));
+
+ /* Throw an error if the types of arg2 or arg3 are incompatible. */
+ if (eltype2->code () != eltype3->code ()
+ || TYPE_LENGTH (eltype2) != TYPE_LENGTH (eltype3)
+ || eltype2->is_unsigned () != eltype3->is_unsigned ()
+ || lowb2 != lowb3 || highb2 != highb3)
+ error (_("\
+Cannot perform operation on vectors with different types"));
+
+ /* Throw an error if the sizes of arg1 and arg2/arg3 differ. */
+ if (lowb1 != lowb2 || lowb1 != lowb3
+ || highb1 != highb2 || highb1 != highb3)
+ error (_("\
+Cannot perform conditional operation on vectors with different sizes"));
+
+ ret = allocate_value (type2);
+
+ for (i = 0; i < highb1 - lowb1 + 1; i++)
+ {
+ tmp = value_logical_not (value_subscript (arg1, i)) ?
+ value_subscript (arg3, i) : value_subscript (arg2, i);
+ memcpy (value_contents_writeable (ret) +
+ i * TYPE_LENGTH (eltype2), value_contents_all (tmp),
+ TYPE_LENGTH (eltype2));
+ }
+
+ return ret;
+ }
+ else
+ {
+ if (value_logical_not (arg1))
+ return std::get<2> (m_storage)->evaluate (nullptr, exp, noside);
+ else
+ return std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+ }
+}
+
} /* namespace expr */

const struct exp_descriptor exp_descriptor_opencl =
--
2.26.2