]> gcc.gnu.org Git - gcc.git/commitdiff
[ARC] Use -G option to control sdata behavior
authorClaudiu Zissulescu <claziss@synopsys.com>
Thu, 31 Aug 2017 14:25:55 +0000 (16:25 +0200)
committerClaudiu Zissulescu <claziss@gcc.gnu.org>
Thu, 31 Aug 2017 14:25:55 +0000 (16:25 +0200)
gcc/
2017-04-24  Claudiu Zissulescu  <claziss@synopsys.com>

* config.gcc: Use g.opt for arc.
* config/arc/arc.c (LEGITIMATE_SCALED_ADDRESS_P): Deleted,
functionality moved to ...
(legitimate_scaled_address_p): New function, ...here.
(LEGITIMATE_SMALL_DATA_OFFSET_P): New define.
(LEGITIMATE_SMALL_DATA_ADDRESS_P): Use the above define.
(legitimate_offset_address_p): Delete TARGET_NO_SDATA_SET
condition.
(arc_override_options): Handle G option.
(arc_output_pic_addr_const): Correct function definition.
(arc_legitimate_address_p): Use legitimate_scaled_address_p.
(arc_decl_anon_ns_mem_p): Delete.
(arc_in_small_data_p): Overhaul this function to take into
consideration the value given via G option.
(arc_rewrite_small_data_1): Renamed and corrected old
arc_rewrite_small_data function.
(arc_rewrite_small_data): New function.
(small_data_pattern): Don't use pic_offset_table_rtx.
* config/arc/arc.h (CC1_SPEC): Recognize G option.
* config/arc/simdext.md (movmisalignv2hi): Use
prepare_move_operands function.
(mov*): Likewise.
(movmisalign*): Likewise.

gcc/testsuite/
2017-04-24  Claudiu Zissulescu  <claziss@synopsys.com>

* gcc.target/arc/sdata-5.c: New test.
* gcc.target/arc/arc700-stld-hazard.c: Update test options.

Fix test

From-SVN: r251564

gcc/ChangeLog
gcc/config.gcc
gcc/config/arc/arc.c
gcc/config/arc/arc.h
gcc/config/arc/simdext.md
gcc/doc/invoke.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/arc/arc700-stld-hazard.c
gcc/testsuite/gcc.target/arc/sdata-5.c [new file with mode: 0755]

index f0be29fc339402e0d13b9c42635e3ef76da4d6fd..c0e032b1a77ad2b541f2d1a6e83fb5855c97db2f 100644 (file)
@@ -1,3 +1,30 @@
+2017-08-31  Claudiu Zissulescu  <claziss@synopsys.com>
+
+       * config.gcc: Use g.opt for arc.
+       * config/arc/arc.c (LEGITIMATE_SCALED_ADDRESS_P): Deleted,
+       functionality moved to ...
+       (legitimate_scaled_address_p): New function, ...here.
+       (LEGITIMATE_SMALL_DATA_OFFSET_P): New define.
+       (LEGITIMATE_SMALL_DATA_ADDRESS_P): Use the above define.
+       (legitimate_offset_address_p): Delete TARGET_NO_SDATA_SET
+       condition.
+       (arc_override_options): Handle G option.
+       (arc_output_pic_addr_const): Correct function definition.
+       (arc_legitimate_address_p): Use legitimate_scaled_address_p.
+       (arc_decl_anon_ns_mem_p): Delete.
+       (arc_in_small_data_p): Overhaul this function to take into
+       consideration the value given via G option.
+       (arc_rewrite_small_data_1): Renamed and corrected old
+       arc_rewrite_small_data function.
+       (arc_rewrite_small_data): New function.
+       (small_data_pattern): Don't use pic_offset_table_rtx.
+       * config/arc/arc.h (CC1_SPEC): Recognize G option.
+       * config/arc/simdext.md (movmisalignv2hi): Use
+       prepare_move_operands function.
+       (mov*): Likewise.
+       (movmisalign*): Likewise.
+       * doc/invoke.texi (ARC options): Document -G option.
+
 2017-08-31  Claudiu Zissulescu  <claziss@synopsys.com>
 
        * config/arc/arc-protos.h (compact_sda_memory_operand): Update
index cc56c576864649dad9d6e27b4853036e0623a102..b5229766b312e1ac406481e1e771146bcbad2514 100644 (file)
@@ -318,7 +318,7 @@ arc*-*-*)
        cpu_type=arc
        c_target_objs="arc-c.o"
        cxx_target_objs="arc-c.o"
-       extra_options="${extra_options} arc/arc-tables.opt"
+       extra_options="${extra_options} arc/arc-tables.opt g.opt"
        extra_headers="arc-simd.h"
        ;;
 arm*-*-*)
index c77a818bc6d22d75eba1b1d5ad7bbaa4f54ab5bc..4dcac1892a7501890637ed6322629f47837ed95b 100644 (file)
@@ -79,26 +79,21 @@ static const char *arc_cpu_string = arc_cpu_name;
                      ? 0 \
                      : -(-GET_MODE_SIZE (MODE) | -4) >> 1)))
 
-#define LEGITIMATE_SCALED_ADDRESS_P(MODE, X, STRICT) \
-(GET_CODE (X) == PLUS \
- && GET_CODE (XEXP (X, 0)) == MULT \
- && RTX_OK_FOR_INDEX_P (XEXP (XEXP (X, 0), 0), (STRICT)) \
- && GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT \
- && ((GET_MODE_SIZE (MODE) == 2 && INTVAL (XEXP (XEXP (X, 0), 1)) == 2) \
-     || (GET_MODE_SIZE (MODE) == 4 && INTVAL (XEXP (XEXP (X, 0), 1)) == 4)) \
- && (RTX_OK_FOR_BASE_P (XEXP (X, 1), (STRICT)) \
-     || (flag_pic ? CONST_INT_P (XEXP (X, 1)) : CONSTANT_P (XEXP (X, 1)))))
-
-#define LEGITIMATE_SMALL_DATA_ADDRESS_P(X) \
-  (GET_CODE (X) == PLUS \
-   && (REG_P (XEXP ((X), 0)) && REGNO (XEXP ((X), 0)) == SDATA_BASE_REGNUM) \
-   && ((GET_CODE (XEXP((X),1)) == SYMBOL_REF \
-       && SYMBOL_REF_SMALL_P (XEXP ((X), 1))) \
-       || (GET_CODE (XEXP ((X), 1)) == CONST \
-          && GET_CODE (XEXP (XEXP ((X), 1), 0)) == PLUS \
-          && GET_CODE (XEXP (XEXP (XEXP ((X), 1), 0), 0)) == SYMBOL_REF \
-          && SYMBOL_REF_SMALL_P (XEXP (XEXP (XEXP ((X), 1), 0), 0)) \
-          && GET_CODE (XEXP(XEXP (XEXP ((X), 1), 0), 1)) == CONST_INT)))
+#define LEGITIMATE_SMALL_DATA_OFFSET_P(X)                              \
+  (GET_CODE (X) == CONST                                               \
+   && GET_CODE (XEXP ((X), 0)) == PLUS                                 \
+   && GET_CODE (XEXP (XEXP ((X), 0), 0)) == SYMBOL_REF                 \
+   && SYMBOL_REF_SMALL_P (XEXP (XEXP ((X), 0), 0))                     \
+   && GET_CODE (XEXP(XEXP ((X), 0), 1)) == CONST_INT                   \
+   && INTVAL (XEXP (XEXP ((X), 0), 1)) <= g_switch_value)
+
+#define LEGITIMATE_SMALL_DATA_ADDRESS_P(X)                             \
+  (GET_CODE (X) == PLUS                                                        \
+     && REG_P (XEXP ((X), 0))                                          \
+     && REGNO (XEXP ((X), 0)) == SDATA_BASE_REGNUM                     \
+     && ((GET_CODE (XEXP ((X), 1)) == SYMBOL_REF                       \
+           && SYMBOL_REF_SMALL_P (XEXP ((X), 1)))                      \
+        || LEGITIMATE_SMALL_DATA_OFFSET_P (XEXP ((X), 1))))
 
 /* Array of valid operand punctuation characters.  */
 char arc_punct_chars[256];
@@ -276,6 +271,61 @@ static bool arc_use_by_pieces_infrastructure_p (unsigned HOST_WIDE_INT,
 /* Globally visible information about currently selected cpu.  */
 const arc_cpu_t *arc_selected_cpu;
 
+static bool
+legitimate_scaled_address_p (machine_mode mode, rtx op, bool strict)
+{
+  if (GET_CODE (op) != PLUS)
+    return false;
+
+  if (GET_CODE (XEXP (op, 0)) != MULT)
+    return false;
+
+  /* Check multiplication operands.  */
+  if (!RTX_OK_FOR_INDEX_P (XEXP (XEXP (op, 0), 0), strict))
+    return false;
+
+  if (!CONST_INT_P (XEXP (XEXP (op, 0), 1)))
+    return false;
+
+  switch (GET_MODE_SIZE (mode))
+    {
+    case 2:
+      if (INTVAL (XEXP (XEXP (op, 0), 1)) != 2)
+       return false;
+      break;
+    case 8:
+      if (!TARGET_LL64)
+       return false;
+      /*  Fall through. */
+    case 4:
+      if (INTVAL (XEXP (XEXP (op, 0), 1)) != 4)
+       return false;
+    default:
+      return false;
+    }
+
+  /* Check the base.  */
+  if (RTX_OK_FOR_BASE_P (XEXP (op, 1), (strict)))
+    return true;
+
+  if (flag_pic)
+    {
+      if (CONST_INT_P (XEXP (op, 1)))
+       return true;
+      return false;
+    }
+  if (CONSTANT_P (XEXP (op, 1)))
+    {
+      /* Scalled addresses for sdata is done other places.  */
+      if (GET_CODE (XEXP (op, 1)) == SYMBOL_REF
+         && SYMBOL_REF_SMALL_P (XEXP (op, 1)))
+       return false;
+      return true;
+    }
+
+  return false;
+}
+
 /* Check for constructions like REG + OFFS, where OFFS can be a
    register, an immediate or an long immediate. */
 
@@ -301,8 +351,7 @@ legitimate_offset_address_p (machine_mode mode, rtx x, bool index, bool strict)
       && (GET_MODE_SIZE (mode) <= 4)
       /* Avoid small data which ends in something like GP +
         symb@sda.  */
-      && (!SYMBOL_REF_SMALL_P (XEXP (x, 1))
-         || TARGET_NO_SDATA_SET))
+      && (!SYMBOL_REF_SMALL_P (XEXP (x, 1))))
     return true;
 
   return false;
@@ -1117,6 +1166,10 @@ arc_override_options (void)
   if (TARGET_COMPACT_CASESI)
     TARGET_CASE_VECTOR_PC_RELATIVE = 1;
 
+  /* Check for small data option */
+  if (!global_options_set.x_g_switch_value && !TARGET_NO_SDATA_SET)
+    g_switch_value = TARGET_LL64 ? 8 : 4;
+
   /* These need to be done at start up.  It's convenient to do them here.  */
   arc_init ();
 }
@@ -5422,7 +5475,7 @@ arc_legitimize_pic_address (rtx orig, rtx oldx)
 
 /* Output address constant X to FILE, taking PIC into account.  */
 
-void
+static void
 arc_output_pic_addr_const (FILE * file, rtx x, int code)
 {
   char buf[256];
@@ -5871,7 +5924,7 @@ arc_legitimate_address_p (machine_mode mode, rtx x, bool strict)
      return true;
   if (legitimate_offset_address_p (mode, x, TARGET_INDEXED_LOADS, strict))
      return true;
-  if (LEGITIMATE_SCALED_ADDRESS_P (mode, x, strict))
+  if (legitimate_scaled_address_p (mode, x, strict))
     return true;
   if (LEGITIMATE_SMALL_DATA_ADDRESS_P (x))
      return true;
@@ -7465,28 +7518,6 @@ valid_brcc_with_delay_p (rtx *operands)
   return brcc_nolimm_operator (operands[0], VOIDmode);
 }
 
-/* ??? Hack.  This should no really be here.  See PR32143.  */
-static bool
-arc_decl_anon_ns_mem_p (const_tree decl)
-{
-  while (1)
-    {
-      if (decl == NULL_TREE || decl == error_mark_node)
-       return false;
-      if (TREE_CODE (decl) == NAMESPACE_DECL
-         && DECL_NAME (decl) == NULL_TREE)
-       return true;
-      /* Classes and namespaces inside anonymous namespaces have
-        TREE_PUBLIC == 0, so we can shortcut the search.  */
-      else if (TYPE_P (decl))
-       return (TREE_PUBLIC (TYPE_NAME (decl)) == 0);
-      else if (TREE_CODE (decl) == NAMESPACE_DECL)
-       return (TREE_PUBLIC (decl) == 0);
-      else
-       decl = DECL_CONTEXT (decl);
-    }
-}
-
 /* Implement TARGET_IN_SMALL_DATA_P.  Return true if it would be safe to
    access DECL using %gp_rel(...)($gp).  */
 
@@ -7495,60 +7526,43 @@ arc_in_small_data_p (const_tree decl)
 {
   HOST_WIDE_INT size;
 
-  /* Strings and functions are never in small data area.  */
-  if (TREE_CODE (decl) == STRING_CST || TREE_CODE (decl) == FUNCTION_DECL)
+  /* Only variables are going into small data area.  */
+  if (TREE_CODE (decl) != VAR_DECL)
     return false;
 
   if (TARGET_NO_SDATA_SET)
     return false;
 
-  if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != 0)
-    {
-      const char *name;
-
-      /* Reject anything that isn't in a known small-data section.  */
-      name = DECL_SECTION_NAME (decl);
-      if (strcmp (name, ".sdata") != 0 && strcmp (name, ".sbss") != 0)
-       return false;
-
-      /* If a symbol is defined externally, the assembler will use the
-        usual -G rules when deciding how to implement macros.  */
-      if (!DECL_EXTERNAL (decl))
-         return true;
-    }
-  /* Only global variables go into sdata section for now.  */
-  else
-    {
-      /* Don't put constants into the small data section: we want them
-        to be in ROM rather than RAM.  */
-      if (TREE_CODE (decl) != VAR_DECL)
-       return false;
-
-      if (TREE_READONLY (decl)
-         && !TREE_SIDE_EFFECTS (decl)
-         && (!DECL_INITIAL (decl) || TREE_CONSTANT (DECL_INITIAL (decl))))
-       return false;
-
-      /* TREE_PUBLIC might change after the first call, because of the patch
-        for PR19238.  */
-      if (default_binds_local_p_1 (decl, 1)
-         || arc_decl_anon_ns_mem_p (decl))
-       return false;
-
-      /* To ensure -mvolatile-cache works
-        ld.di does not have a gp-relative variant.  */
-      if (TREE_THIS_VOLATILE (decl))
-       return false;
-    }
-
   /* Disable sdata references to weak variables.  */
   if (DECL_WEAK (decl))
     return false;
 
-  size = int_size_in_bytes (TREE_TYPE (decl));
+  /* Don't put constants into the small data section: we want them to
+     be in ROM rather than RAM.  */
+  if (TREE_READONLY (decl))
+    return false;
+
+  /* To ensure -mvolatile-cache works ld.di does not have a
+     gp-relative variant.  */
+  if (!TARGET_VOLATILE_CACHE_SET
+      && TREE_THIS_VOLATILE (decl))
+    return false;
 
-  /* Allow only <=4B long data types into sdata.  */
-  return (size > 0 && size <= 4);
+  if (DECL_SECTION_NAME (decl) != 0)
+    {
+      const char *name = DECL_SECTION_NAME (decl);
+      if (strcmp (name, ".sdata") == 0
+         || strcmp (name, ".sbss") == 0)
+       return true;
+    }
+  /* If it's not public, there's no need to put it in the small data
+     section.  */
+  else if (TREE_PUBLIC (decl))
+    {
+      size = int_size_in_bytes (TREE_TYPE (decl));
+      return (size > 0 && size <= g_switch_value);
+    }
+  return false;
 }
 
 /* Return true if X is a small data address that can be rewritten
@@ -7577,9 +7591,10 @@ arc_rewrite_small_data_p (const_rtx x)
 /* If possible, rewrite OP so that it refers to small data using
    explicit relocations.  */
 
-rtx
-arc_rewrite_small_data (rtx op)
+static rtx
+arc_rewrite_small_data_1 (rtx op)
 {
+  rtx rgp = gen_rtx_REG (Pmode, SDATA_BASE_REGNUM);
   op = copy_insn (op);
   subrtx_ptr_iterator::array_type array;
   FOR_EACH_SUBRTX_PTR (iter, array, &op, ALL)
@@ -7587,28 +7602,33 @@ arc_rewrite_small_data (rtx op)
       rtx *loc = *iter;
       if (arc_rewrite_small_data_p (*loc))
        {
-         gcc_assert (SDATA_BASE_REGNUM == PIC_OFFSET_TABLE_REGNUM);
-         *loc = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, *loc);
-         if (loc != &op)
-           {
-             if (GET_CODE (op) == MEM && &XEXP (op, 0) == loc)
-               ; /* OK.  */
-             else if (GET_CODE (op) == MEM
-                      && GET_CODE (XEXP (op, 0)) == PLUS
-                      && GET_CODE (XEXP (XEXP (op, 0), 0)) == MULT)
-               *loc = force_reg (Pmode, *loc);
-             else
-               gcc_unreachable ();
-           }
+         *loc = gen_rtx_PLUS (Pmode, rgp, *loc);
          iter.skip_subrtxes ();
        }
       else if (GET_CODE (*loc) == PLUS
-              && rtx_equal_p (XEXP (*loc, 0), pic_offset_table_rtx))
+              && rtx_equal_p (XEXP (*loc, 0), rgp))
        iter.skip_subrtxes ();
     }
   return op;
 }
 
+rtx
+arc_rewrite_small_data (rtx op)
+{
+  op = arc_rewrite_small_data_1 (op);
+
+  /* Check if we fit small data constraints.  */
+  if (MEM_P (op)
+      && !LEGITIMATE_SMALL_DATA_ADDRESS_P (XEXP (op, 0)))
+    {
+      rtx addr = XEXP (op, 0);
+      rtx tmp = gen_reg_rtx (Pmode);
+      emit_move_insn (tmp, addr);
+      op = replace_equiv_address_nv (op, tmp);
+    }
+  return op;
+}
+
 /* Return true if OP refers to small data symbols directly, not through
    a PLUS.  */
 
@@ -7617,12 +7637,14 @@ small_data_pattern (rtx op, machine_mode)
 {
   if (GET_CODE (op) == SEQUENCE)
     return false;
+
+  rtx rgp = gen_rtx_REG (Pmode, SDATA_BASE_REGNUM);
   subrtx_iterator::array_type array;
   FOR_EACH_SUBRTX (iter, array, op, ALL)
     {
       const_rtx x = *iter;
       if (GET_CODE (x) == PLUS
-         && rtx_equal_p (XEXP (x, 0), pic_offset_table_rtx))
+         && rtx_equal_p (XEXP (x, 0), rgp))
        iter.skip_subrtxes ();
       else if (arc_rewrite_small_data_p (x))
        return true;
index 82cd0ad621796b352ebe7aa3d85ca15725056048..2c06f9fc305fbd6681b1ff227dc324f270370c29 100644 (file)
@@ -65,9 +65,9 @@ along with GCC; see the file COPYING3.  If not see
 %(subtarget_cpp_spec)"
 
 #undef CC1_SPEC
-#define CC1_SPEC "\
-%{EB:%{EL:%emay not use both -EB and -EL}} \
-%{EB:-mbig-endian} %{EL:-mlittle-endian} \
+#define CC1_SPEC "%{EB:%{EL:%emay not use both -EB and -EL}}   \
+%{EB:-mbig-endian} %{EL:-mlittle-endian}                       \
+%{G*}                                                          \
 "
 extern const char *arc_cpu_to_as (int argc, const char **argv);
 
index 6c102d3c7f8daab9b51aaeff7661fa9cce62f105..9f5b4a82e566dfbfc835221aece84111551279fd 100644 (file)
  [(set (match_operand:V2HI 0 "general_operand" "")
        (match_operand:V2HI 1 "general_operand" ""))]
  ""
-{
- if (!register_operand (operands[0], V2HImode)
-      && !register_operand (operands[1], V2HImode))
-    operands[1] = force_reg (V2HImode, operands[1]);
-})
+ "{
+   if (prepare_move_operands (operands, V2HImode))
+     DONE;
+  }")
 
 (define_expand "mov<mode>"
   [(set (match_operand:VWH 0 "move_dest_operand" "")
        (match_operand:VWH 1 "general_operand" ""))]
   ""
   "{
-    if (GET_CODE (operands[0]) == MEM)
-     operands[1] = force_reg (<MODE>mode, operands[1]);
+    if (prepare_move_operands (operands, <MODE>mode))
+     DONE;
    }")
 
 (define_insn_and_split "*mov<mode>_insn"
  [(set (match_operand:VWH 0 "general_operand" "")
        (match_operand:VWH 1 "general_operand" ""))]
  ""
-{
- if (!register_operand (operands[0], <MODE>mode)
-      && !register_operand (operands[1], <MODE>mode))
-    operands[1] = force_reg (<MODE>mode, operands[1]);
-})
+ "{
+   if (prepare_move_operands (operands, <MODE>mode))
+     DONE;
+  }")
 
 (define_insn "bswapv2hi2"
   [(set (match_operand:V2HI 0 "register_operand" "=r,r")
index 64363e54a00c56a3de545735620189f7ec0cde04..1241b1840ef52c83cefee5d1be6d49cb10db3697 100644 (file)
@@ -614,7 +614,7 @@ Objective-C and Objective-C++ Dialects}.
 -mcrc  -mdsp-packa  -mdvbf  -mlock  -mmac-d16  -mmac-24  -mrtsc  -mswape @gol
 -mtelephony  -mxy  -misize  -mannotate-align  -marclinux  -marclinux_prof @gol
 -mlong-calls  -mmedium-calls  -msdata -mirq-ctrl-saved @gol
--mrgf-banked-regs @gol
+-mrgf-banked-regs -G @var{num} @gol
 -mvolatile-cache  -mtp-regno=@var{regno} @gol
 -malign-call  -mauto-modify-reg  -mbbit-peephole  -mno-brcc @gol
 -mcase-vector-pcrel  -mcompact-casesi  -mno-cond-exec  -mearly-cbranchsi @gol
@@ -14896,6 +14896,13 @@ allow use of the 25-bit range, rather than the 21-bit range with
 conditional branch-and-link.  This is the default for tool chains built
 for @w{@code{arc-linux-uclibc}} and @w{@code{arceb-linux-uclibc}} targets.
 
+@item -G @var{num}
+@opindex G
+Put definitions of externally-visible data in a small data section if
+that data is no bigger than @var{num} bytes.  The default value of
+@var{num} is 4 for any ARC configuration, or 8 when we have double
+load/store operations.
+
 @item -mno-sdata
 @opindex mno-sdata
 Do not generate sdata references.  This is the default for tool chains
index 9de87dd725b0b8ce7557297b33f81a9d98f4857a..cd63ace82501a13380d63dadc2b08777eb5c203a 100644 (file)
@@ -1,3 +1,8 @@
+2017-08-31  Claudiu Zissulescu  <claziss@synopsys.com>
+
+       * gcc.target/arc/sdata-5.c: New test.
+        * gcc.target/arc/arc700-stld-hazard.c: Update test options.
+
 2017-08-31  Claudiu Zissulescu  <claziss@synopsys.com>
 
        * gcc.target/arc/sdata-3.c: New file.
index bf6ae334284a475d73d94933b366c70c735f2a7f..eba03d8625681e7d0c42400fd92df7bb1871486b 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-mcpu=arc700" } */
+/* { dg-options "-mcpu=arc700 -mno-sdata" } */
 
 volatile int a;
 volatile int b;
diff --git a/gcc/testsuite/gcc.target/arc/sdata-5.c b/gcc/testsuite/gcc.target/arc/sdata-5.c
new file mode 100755 (executable)
index 0000000..0d4eae5
--- /dev/null
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -msdata" } */
+
+/* Check interaction between section anchors and small data. */
+
+const int a[1] = {};
+static short b[] = {};
+
+int c;
+
+const int* fn1 (void)
+{
+  return a + b[c];
+}
+/* { dg-final { scan-assembler "@c@sda" } } */
This page took 0.114375 seconds and 5 git commands to generate.