[v3,153/206] Implement OpenCL ternary conditional operator

Message ID 20210220201609.838264-154-tom@tromey.com
State New
Headers show
Series
  • Refactor expressions
Related show

Commit Message

Tom Tromey Feb. 20, 2021, 8:15 p.m.
This implements the ?: ternary conditional operator for OpenCL.

gdb/ChangeLog
2021-02-20  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(+)

-- 
2.26.2

Patch

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 =