gdb/fortran: Additional builtin procedures
authorAndrew Burgess <andrew.burgess@embecosm.com>
Wed, 13 Feb 2019 17:10:18 +0000 (17:10 +0000)
committerAndrew Burgess <andrew.burgess@embecosm.com>
Tue, 30 Apr 2019 09:10:24 +0000 (10:10 +0100)
Add some additional builtin procedures for Fortran, these are MOD,
CEILING, FLOOR, MODULO, and CMPLX.

gdb/ChangeLog:

* f-exp.y (BINOP_INTRINSIC): New token.
(exp): New parser rule handling BINOP_INTRINSIC.
(f77_keywords): Add new builtin procedures.
* f-lang.c (evaluate_subexp_f): Handle BINOP_MOD, UNOP_FORTRAN_CEILING,
UNOP_FORTRAN_FLOOR, BINOP_FORTRAN_MODULO, BINOP_FORTRAN_CMPLX.
(operator_length_f): Handle UNOP_FORTRAN_CEILING,
UNOP_FORTRAN_FLOOR, BINOP_FORTRAN_MODULO, BINOP_FORTRAN_CMPLX.
(print_unop_subexp_f): New function.
(print_binop_subexp_f): New function.
(print_subexp_f): Handle UNOP_FORTRAN_CEILING, UNOP_FORTRAN_FLOOR,
BINOP_FORTRAN_MODULO, BINOP_FORTRAN_CMPLX.
(dump_subexp_body_f): Likewise.
(operator_check_f): Likewise.
* fortran-operator.def: Add UNOP_FORTRAN_CEILING, UNOP_FORTRAN_FLOOR,
BINOP_FORTRAN_MODULO, BINOP_FORTRAN_CMPLX

gdb/testsuite/ChangeLog:

* gdb.fortran/intrinsics.exp: Extend to cover MOD, CEILING, FLOOR,
MODULO, CMPLX.

gdb/ChangeLog
gdb/f-exp.y
gdb/f-lang.c
gdb/fortran-operator.def
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.fortran/intrinsics.exp

index 3e3ea935860d5e87ce8ba7b1c9a396a069c8d1be..f6a1976defffa6939df20b7e2c942d0d4472a170 100644 (file)
@@ -1,3 +1,23 @@
+2019-04-30  Andrew Burgess  <andrew.burgess@embecosm.com>
+           Chris January  <chris.january@arm.com>
+           David Lecomber  <david.lecomber@arm.com>
+
+       * f-exp.y (BINOP_INTRINSIC): New token.
+       (exp): New parser rule handling BINOP_INTRINSIC.
+       (f77_keywords): Add new builtin procedures.
+       * f-lang.c (evaluate_subexp_f): Handle BINOP_MOD, UNOP_FORTRAN_CEILING,
+       UNOP_FORTRAN_FLOOR, BINOP_FORTRAN_MODULO, BINOP_FORTRAN_CMPLX.
+       (operator_length_f): Handle UNOP_FORTRAN_CEILING,
+       UNOP_FORTRAN_FLOOR, BINOP_FORTRAN_MODULO, BINOP_FORTRAN_CMPLX.
+       (print_unop_subexp_f): New function.
+       (print_binop_subexp_f): New function.
+       (print_subexp_f): Handle UNOP_FORTRAN_CEILING, UNOP_FORTRAN_FLOOR,
+       BINOP_FORTRAN_MODULO, BINOP_FORTRAN_CMPLX.
+       (dump_subexp_body_f): Likewise.
+       (operator_check_f): Likewise.
+       * fortran-operator.def: Add UNOP_FORTRAN_CEILING, UNOP_FORTRAN_FLOOR,
+       BINOP_FORTRAN_MODULO, BINOP_FORTRAN_CMPLX
+
 2019-04-30  Andrew Burgess  <andrew.burgess@embecosm.com>
 
        * gdb/expprint.c (dump_subexp_body_standard): Remove use of
index dec8848bc00896b189f100bf54061c30a70ba5b5..14ea3869bb2d01c5c80e77af26e3937c24353fab 100644 (file)
@@ -174,7 +174,7 @@ static int parse_number (struct parser_state *, const char *, int,
 %token <voidval> DOLLAR_VARIABLE
 
 %token <opcode> ASSIGN_MODIFY
-%token <opcode> UNOP_INTRINSIC
+%token <opcode> UNOP_INTRINSIC BINOP_INTRINSIC
 
 %left ','
 %left ABOVE_COMMA
@@ -263,6 +263,10 @@ exp        :       UNOP_INTRINSIC '(' exp ')'
                        { write_exp_elt_opcode (pstate, $1); }
        ;
 
+exp    :       BINOP_INTRINSIC '(' exp ',' exp ')'
+                       { write_exp_elt_opcode (pstate, $1); }
+       ;
+
 arglist        :
        ;
 
@@ -959,7 +963,12 @@ static const struct token f77_keywords[] =
   /* The following correspond to actual functions in Fortran and are case
      insensitive.  */
   { "kind", KIND, BINOP_END, false },
-  { "abs", UNOP_INTRINSIC, UNOP_ABS, false }
+  { "abs", UNOP_INTRINSIC, UNOP_ABS, false },
+  { "mod", BINOP_INTRINSIC, BINOP_MOD, false },
+  { "floor", UNOP_INTRINSIC, UNOP_FORTRAN_FLOOR, false },
+  { "ceiling", UNOP_INTRINSIC, UNOP_FORTRAN_CEILING, false },
+  { "modulo", BINOP_INTRINSIC, BINOP_FORTRAN_MODULO, false },
+  { "cmplx", BINOP_INTRINSIC, BINOP_FORTRAN_CMPLX, false },
 };
 
 /* Implementation of a dynamically expandable buffer for processing input
index ecb69e76e61c0c840951b21fdc4549791b77ecbc..cc4e154f47ab4450f4ddb75e2e7cf9848994688f 100644 (file)
@@ -246,7 +246,7 @@ struct value *
 evaluate_subexp_f (struct type *expect_type, struct expression *exp,
                   int *pos, enum noside noside)
 {
-  struct value *arg1 = NULL;
+  struct value *arg1 = NULL, *arg2 = NULL;
   enum exp_opcode op;
   int pc;
   struct type *type;
@@ -284,6 +284,115 @@ evaluate_subexp_f (struct type *expect_type, struct expression *exp,
        }
       error (_("ABS of type %s not supported"), TYPE_SAFE_NAME (type));
 
+    case BINOP_MOD:
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       return eval_skip_value (exp);
+      type = value_type (arg1);
+      if (TYPE_CODE (type) != TYPE_CODE (value_type (arg2)))
+       error (_("non-matching types for parameters to MOD ()"));
+      switch (TYPE_CODE (type))
+       {
+       case TYPE_CODE_FLT:
+         {
+           double d1
+             = target_float_to_host_double (value_contents (arg1),
+                                            value_type (arg1));
+           double d2
+             = target_float_to_host_double (value_contents (arg2),
+                                            value_type (arg2));
+           double d3 = fmod (d1, d2);
+           return value_from_host_double (type, d3);
+         }
+       case TYPE_CODE_INT:
+         {
+           LONGEST v1 = value_as_long (arg1);
+           LONGEST v2 = value_as_long (arg2);
+           if (v2 == 0)
+             error (_("calling MOD (N, 0) is undefined"));
+           LONGEST v3 = v1 - (v1 / v2) * v2;
+           return value_from_longest (value_type (arg1), v3);
+         }
+       }
+      error (_("MOD of type %s not supported"), TYPE_SAFE_NAME (type));
+
+    case UNOP_FORTRAN_CEILING:
+      {
+       arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+       if (noside == EVAL_SKIP)
+         return eval_skip_value (exp);
+       type = value_type (arg1);
+       if (TYPE_CODE (type) != TYPE_CODE_FLT)
+         error (_("argument to CEILING must be of type float"));
+       double val
+         = target_float_to_host_double (value_contents (arg1),
+                                        value_type (arg1));
+       val = ceil (val);
+       return value_from_host_double (type, val);
+      }
+
+    case UNOP_FORTRAN_FLOOR:
+      {
+       arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+       if (noside == EVAL_SKIP)
+         return eval_skip_value (exp);
+       type = value_type (arg1);
+       if (TYPE_CODE (type) != TYPE_CODE_FLT)
+         error (_("argument to FLOOR must be of type float"));
+       double val
+         = target_float_to_host_double (value_contents (arg1),
+                                        value_type (arg1));
+       val = floor (val);
+       return value_from_host_double (type, val);
+      }
+
+    case BINOP_FORTRAN_MODULO:
+      {
+       arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+       arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
+       if (noside == EVAL_SKIP)
+         return eval_skip_value (exp);
+       type = value_type (arg1);
+       if (TYPE_CODE (type) != TYPE_CODE (value_type (arg2)))
+         error (_("non-matching types for parameters to MODULO ()"));
+        /* MODULO(A, P) = A - FLOOR (A / P) * P */
+       switch (TYPE_CODE (type))
+         {
+         case TYPE_CODE_INT:
+           {
+             LONGEST a = value_as_long (arg1);
+             LONGEST p = value_as_long (arg2);
+             LONGEST result = a - (a / p) * p;
+             if (result != 0 && (a < 0) != (p < 0))
+               result += p;
+             return value_from_longest (value_type (arg1), result);
+           }
+         case TYPE_CODE_FLT:
+           {
+             double a
+               = target_float_to_host_double (value_contents (arg1),
+                                              value_type (arg1));
+             double p
+               = target_float_to_host_double (value_contents (arg2),
+                                              value_type (arg2));
+             double result = fmod (a, p);
+             if (result != 0 && (a < 0.0) != (p < 0.0))
+               result += p;
+             return value_from_host_double (type, result);
+           }
+         }
+       error (_("MODULO of type %s not supported"), TYPE_SAFE_NAME (type));
+      }
+
+    case BINOP_FORTRAN_CMPLX:
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       return eval_skip_value (exp);
+      type = builtin_f_type(exp->gdbarch)->builtin_complex_s16;
+      return value_literal_complex (arg1, arg2, type);
+
     case UNOP_FORTRAN_KIND:
       arg1 = evaluate_subexp (NULL, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
       type = value_type (arg1);
@@ -335,15 +444,55 @@ operator_length_f (const struct expression *exp, int pc, int *oplenp,
       return;
 
     case UNOP_FORTRAN_KIND:
+    case UNOP_FORTRAN_FLOOR:
+    case UNOP_FORTRAN_CEILING:
       oplen = 1;
       args = 1;
       break;
+
+    case BINOP_FORTRAN_CMPLX:
+    case BINOP_FORTRAN_MODULO:
+      oplen = 1;
+      args = 2;
+      break;
     }
 
   *oplenp = oplen;
   *argsp = args;
 }
 
+/* Helper for PRINT_SUBEXP_F.  Arguments are as for PRINT_SUBEXP_F, except
+   the extra argument NAME which is the text that should be printed as the
+   name of this operation.  */
+
+static void
+print_unop_subexp_f (struct expression *exp, int *pos,
+                    struct ui_file *stream, enum precedence prec,
+                    const char *name)
+{
+  (*pos)++;
+  fprintf_filtered (stream, "%s(", name);
+  print_subexp (exp, pos, stream, PREC_SUFFIX);
+  fputs_filtered (")", stream);
+}
+
+/* Helper for PRINT_SUBEXP_F.  Arguments are as for PRINT_SUBEXP_F, except
+   the extra argument NAME which is the text that should be printed as the
+   name of this operation.  */
+
+static void
+print_binop_subexp_f (struct expression *exp, int *pos,
+                     struct ui_file *stream, enum precedence prec,
+                     const char *name)
+{
+  (*pos)++;
+  fprintf_filtered (stream, "%s(", name);
+  print_subexp (exp, pos, stream, PREC_SUFFIX);
+  fputs_filtered (",", stream);
+  print_subexp (exp, pos, stream, PREC_SUFFIX);
+  fputs_filtered (")", stream);
+}
+
 /* Special expression printing for Fortran.  */
 
 static void
@@ -360,10 +509,23 @@ print_subexp_f (struct expression *exp, int *pos,
       return;
 
     case UNOP_FORTRAN_KIND:
-      (*pos)++;
-      fputs_filtered ("KIND(", stream);
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      fputs_filtered (")", stream);
+      print_unop_subexp_f (exp, pos, stream, prec, "KIND");
+      return;
+
+    case UNOP_FORTRAN_FLOOR:
+      print_unop_subexp_f (exp, pos, stream, prec, "FLOOR");
+      return;
+
+    case UNOP_FORTRAN_CEILING:
+      print_unop_subexp_f (exp, pos, stream, prec, "CEILING");
+      return;
+
+    case BINOP_FORTRAN_CMPLX:
+      print_binop_subexp_f (exp, pos, stream, prec, "CMPLX");
+      return;
+
+    case BINOP_FORTRAN_MODULO:
+      print_binop_subexp_f (exp, pos, stream, prec, "MODULO");
       return;
     }
 }
@@ -401,6 +563,10 @@ dump_subexp_body_f (struct expression *exp,
       return dump_subexp_body_standard (exp, stream, elt);
 
     case UNOP_FORTRAN_KIND:
+    case UNOP_FORTRAN_FLOOR:
+    case UNOP_FORTRAN_CEILING:
+    case BINOP_FORTRAN_CMPLX:
+    case BINOP_FORTRAN_MODULO:
       operator_length_f (exp, (elt + 1), &oplen, &nargs);
       break;
     }
@@ -425,6 +591,10 @@ operator_check_f (struct expression *exp, int pos,
   switch (elts[pos].opcode)
     {
     case UNOP_FORTRAN_KIND:
+    case UNOP_FORTRAN_FLOOR:
+    case UNOP_FORTRAN_CEILING:
+    case BINOP_FORTRAN_CMPLX:
+    case BINOP_FORTRAN_MODULO:
       /* Any references to objfiles are held in the arguments to this
         expression, not within the expression itself, so no additional
         checking is required here, the outer expression iteration code
index c3176de428e241cc6fc02bbeaafc00b0f494ba33..cb40108aa8357f217da87ffe7f0fcf60ecef44ed 100644 (file)
@@ -19,4 +19,9 @@
 
 /* Single operand builtins.  */
 OP (UNOP_FORTRAN_KIND)
+OP (UNOP_FORTRAN_FLOOR)
+OP (UNOP_FORTRAN_CEILING)
 
+/* Two operand builtins.  */
+OP (BINOP_FORTRAN_CMPLX)
+OP (BINOP_FORTRAN_MODULO)
index 6d9ac5aa935f17c377433459004ad6e007699db1..7489ab9ec29c1b6793e1921a86ba120295400bc0 100644 (file)
@@ -1,3 +1,8 @@
+2019-04-30  Andrew Burgess  <andrew.burgess@embecosm.com>
+
+       * gdb.fortran/intrinsics.exp: Extend to cover MOD, CEILING, FLOOR,
+       MODULO, CMPLX.
+
 2019-04-29  Andrew Burgess  <andrew.burgess@embecosm.com>
            Richard Bunt  <richard.bunt@arm.com>
 
index 00396c74c2fa546afd5920384d5004087c5f0f8d..64d9e56daabfd555d49fe341b48ce6bce2e45b30 100644 (file)
@@ -49,3 +49,38 @@ gdb_test "p abs (11)" " = 11"
 # rounding, which can vary.
 gdb_test "p abs (-9.1)" " = 9.$decimal"
 gdb_test "p abs (9.1)" " = 9.$decimal"
+
+# Test MOD
+
+gdb_test "p mod (3.0, 2.0)" " = 1"
+gdb_test "ptype mod (3.0, 2.0)" "type = real\\*8"
+gdb_test "p mod (2.0, 3.0)" " = 2"
+gdb_test "p mod (8, 5)" " = 3"
+gdb_test "ptype mod (8, 5)" "type = int"
+gdb_test "p mod (-8, 5)" " = -3"
+gdb_test "p mod (8, -5)" " = 3"
+gdb_test "p mod (-8, -5)" " = -3"
+
+# Test CEILING
+
+gdb_test "p ceiling (3.7)" " = 4"
+gdb_test "p ceiling (-3.7)" " = -3"
+
+# Test FLOOR
+
+gdb_test "p floor (3.7)" " = 3"
+gdb_test "p floor (-3.7)" " = -4"
+
+# Test MODULO
+
+gdb_test "p MODULO (8,5)" " = 3"
+gdb_test "ptype MODULO (8,5)" "type = int"
+gdb_test "p MODULO (-8,5)" " = 2"
+gdb_test "p MODULO (8,-5)" " = -2"
+gdb_test "p MODULO (-8,-5)" " = -3"
+gdb_test "p MODULO (3.0,2.0)" " = 1"
+gdb_test "ptype MODULO (3.0,2.0)" "type = real\\*8"
+
+# Test CMPLX
+
+gdb_test "p CMPLX (4.1, 2.0)" " = \\(4.$decimal,2\\)"
This page took 0.031349 seconds and 4 git commands to generate.