[v3,152/206] Implement OpenCL logical binary operations

Message ID 20210220201609.838264-153-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 "&&" and "||" for OpenCL.

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

	* opencl-lang.c (opencl_logical_binop_operation::evaluate): New
	method.
	* c-exp.h (class opencl_logical_binop_operation): New.
---
 gdb/ChangeLog     |  6 ++++++
 gdb/c-exp.h       | 17 +++++++++++++++++
 gdb/opencl-lang.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 71 insertions(+)

-- 
2.26.2

Patch

diff --git a/gdb/c-exp.h b/gdb/c-exp.h
index 58a16d5c0c8..f75b4aed952 100644
--- a/gdb/c-exp.h
+++ b/gdb/c-exp.h
@@ -186,6 +186,23 @@  class opencl_structop_operation
   { return STRUCTOP_STRUCT; }
 };
 
+/* This handles the "&&" and "||" operations for OpenCL.  */
+class opencl_logical_binop_operation
+  : public tuple_holding_operation<enum exp_opcode,
+				   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 std::get<0> (m_storage); }
+};
+
 }/* namespace expr */
 
 #endif /* C_EXP_H */
diff --git a/gdb/opencl-lang.c b/gdb/opencl-lang.c
index 317163966cd..cca8505cfac 100644
--- a/gdb/opencl-lang.c
+++ b/gdb/opencl-lang.c
@@ -984,6 +984,54 @@  opencl_structop_operation::evaluate (struct type *expect_type,
     }
 }
 
+value *
+opencl_logical_binop_operation::evaluate (struct type *expect_type,
+					  struct expression *exp,
+					  enum noside noside)
+{
+  enum exp_opcode op = std::get<0> (m_storage);
+  value *arg1 = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+
+  /* For scalar operations we need to avoid evaluating operands
+     unnecessarily.  However, for vector operations we always need to
+     evaluate both operands.  Unfortunately we only know which of the
+     two cases apply after we know the type of the second operand.
+     Therefore we evaluate it once using EVAL_AVOID_SIDE_EFFECTS.  */
+  value *arg2 = std::get<2> (m_storage)->evaluate (nullptr, exp,
+						   EVAL_AVOID_SIDE_EFFECTS);
+  struct type *type1 = check_typedef (value_type (arg1));
+  struct type *type2 = check_typedef (value_type (arg2));
+
+  if ((type1->code () == TYPE_CODE_ARRAY && type1->is_vector ())
+      || (type2->code () == TYPE_CODE_ARRAY && type2->is_vector ()))
+    {
+      arg2 = std::get<2> (m_storage)->evaluate (nullptr, exp, noside);
+
+      return opencl_relop (nullptr, exp, noside, op, arg1, arg2);
+    }
+  else
+    {
+      /* For scalar built-in types, only evaluate the right
+	 hand operand if the left hand operand compares
+	 unequal(&&)/equal(||) to 0.  */
+      int tmp = value_logical_not (arg1);
+
+      if (op == BINOP_LOGICAL_OR)
+	tmp = !tmp;
+
+      if (!tmp)
+	{
+	  arg2 = std::get<2> (m_storage)->evaluate (nullptr, exp, noside);
+	  tmp = value_logical_not (arg2);
+	  if (op == BINOP_LOGICAL_OR)
+	    tmp = !tmp;
+	}
+
+      type1 = language_bool_type (exp->language_defn, exp->gdbarch);
+      return value_from_longest (type1, tmp);
+    }
+}
+
 } /* namespace expr */
 
 const struct exp_descriptor exp_descriptor_opencl =