Implement OpenCL logical binary operations
authorTom Tromey <tom@tromey.com>
Mon, 8 Mar 2021 14:27:57 +0000 (07:27 -0700)
committerTom Tromey <tom@tromey.com>
Mon, 8 Mar 2021 14:28:31 +0000 (07:28 -0700)
This implements "&&" and "||" for OpenCL.

gdb/ChangeLog
2021-03-08  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
gdb/c-exp.h
gdb/opencl-lang.c

index 3c7d68374b28f7356da763e076b6cf86e70d7fbf..a729c7384274f28b08d0302c9536d180652e397e 100644 (file)
@@ -1,3 +1,9 @@
+2021-03-08  Tom Tromey  <tom@tromey.com>
+
+       * opencl-lang.c (opencl_logical_binop_operation::evaluate): New
+       method.
+       * c-exp.h (class opencl_logical_binop_operation): New.
+
 2021-03-08  Tom Tromey  <tom@tromey.com>
 
        * opencl-lang.c (opencl_structop_operation::evaluate): New
index 58a16d5c0c8eb3dbfa5efdbb210209985d360e0f..f75b4aed9524c4a67786e4393b0574976803a986 100644 (file)
@@ -186,6 +186,23 @@ public:
   { 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 */
index 317163966cd3e78074a15919ee74f5074ba4b8df..cca8505cfac2bf93aa7c9797766ae27847fceac6 100644 (file)
@@ -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 =