Implement statement::clone_into for asm statements
diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc
index 84ccc6d..4e83d7b 100644
--- a/gcc/jit/jit-recording.cc
+++ b/gcc/jit/jit-recording.cc
@@ -4805,7 +4805,13 @@
 {
   if (block **existing = m_map.get (orig))
     return *existing;
-  block *clone = m_func->new_block (NULL);
+  /* Give the clone the original's name.  Block names need not be unique
+     (blocks are identified by pointer, and only dumps and error messages
+     use the name), and reusing it keeps the label's identifier, so an
+     "asm goto" template referring to a label symbolically ("%l[name]")
+     still resolves in the clone.  */
+  block *clone
+    = m_func->new_block (orig->m_name ? orig->m_name->c_str () : NULL);
   clone->m_is_reachable = orig->m_is_reachable;
   m_map.put (orig, clone);
   m_all.safe_push (orig);
@@ -7994,23 +8000,12 @@
     m_loc = d.make_location ();
 }
 
-/* Default implementation of recording::statement::clone_into: reject
-   statement kinds that carry state which cannot be safely duplicated (e.g.
-   extended asm).  The kinds that appear in cleanup bodies override this.  */
-
-void
-recording::statement::clone_into (block_cloner &, block *) const
-{
-  m_ctxt->add_error (get_loc (),
-		     "cloning this kind of statement is not supported");
-}
-
 /* clone_into / get_inlined_blocks implementations for the concrete
-   statement kinds that a cleanup body may contain.  Each re-emits itself
-   into DEST via the normal recording API (so all bookkeeping -- context
-   recording, termination flags, reachability -- is reused), remapping block
-   references through CLONER.  References to blocks inside the cloned set
-   become the clones; references outside it are preserved.  */
+   statement kinds.  Each re-emits itself into DEST via the normal recording
+   API (so all bookkeeping -- context recording, termination flags,
+   reachability -- is reused), remapping block references through CLONER.
+   References to blocks inside the cloned set become the clones; references
+   outside it are preserved.  */
 
 void
 recording::eval::clone_into (block_cloner &cloner, block *dest) const
@@ -8114,6 +8109,66 @@
     out.safe_push (b);
 }
 
+/* Copy the flags, operands and clobbers of this extended asm into DEST, a
+   freshly-created clone of it.  The asm template and the operands' symbolic
+   names and constraints are immutable strings, so they are simply re-added;
+   the operands' lvalues/rvalues are cloned through CLONER.  */
+
+void
+recording::extended_asm::clone_contents_into (block_cloner &cloner,
+					      extended_asm *dest) const
+{
+  dest->set_volatile_flag (m_is_volatile);
+  dest->set_inline_flag (m_is_inline);
+
+  unsigned i;
+  output_asm_operand *output_op;
+  FOR_EACH_VEC_ELT (m_output_ops, i, output_op)
+    dest->add_output_operand (output_op->get_symbolic_name (),
+			      output_op->get_constraint (),
+			      cloner.clone_lvalue (output_op->get_lvalue ()));
+
+  input_asm_operand *input_op;
+  FOR_EACH_VEC_ELT (m_input_ops, i, input_op)
+    dest->add_input_operand (input_op->get_symbolic_name (),
+			     input_op->get_constraint (),
+			     cloner.clone_rvalue (input_op->get_rvalue ()));
+
+  string *clobber;
+  FOR_EACH_VEC_ELT (m_clobbers, i, clobber)
+    dest->add_clobber (clobber->c_str ());
+}
+
+void
+recording::extended_asm_simple::clone_into (block_cloner &cloner,
+					    block *dest) const
+{
+  extended_asm *clone
+    = dest->add_extended_asm (get_loc (), m_asm_template->c_str ());
+  clone_contents_into (cloner, clone);
+}
+
+void
+recording::extended_asm_goto::clone_into (block_cloner &cloner,
+					  block *dest) const
+{
+  auto_vec<block *> goto_blocks (m_goto_blocks.length ());
+  unsigned i;
+  block *b;
+  FOR_EACH_VEC_ELT (m_goto_blocks, i, b)
+    goto_blocks.quick_push (cloner.remap (b));
+
+  extended_asm *clone
+    = dest->end_with_extended_asm_goto (get_loc (),
+					m_asm_template->c_str (),
+					goto_blocks.length (),
+					goto_blocks.address (),
+					(m_fallthrough_block
+					 ? cloner.remap (m_fallthrough_block)
+					 : NULL));
+  clone_contents_into (cloner, clone);
+}
+
 /* The implementation of class gcc::jit::recording::memento_of_set_personality_function.  */
 
 /* Implementation of pure virtual hook recording::memento::replay_into
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index 0f65997..acb70d0 100644
--- a/gcc/jit/jit-recording.h
+++ b/gcc/jit/jit-recording.h
@@ -3011,10 +3011,10 @@
 
   /* Re-emit this statement into DEST (a clone block), remapping any block
      references through CLONER so a duplicated subgraph is self-contained.
-     The base implementation reports an error for statement kinds that carry
-     state which cannot be safely duplicated (e.g. extended asm); the kinds
-     that appear in cleanup bodies override it.  See block_cloner.  */
-  virtual void clone_into (block_cloner &cloner, block *dest) const;
+     Pure so every concrete statement kind must provide a clone --
+     gcc_jit_blocks_clone stays fully generic, and adding a new statement
+     kind forces a clone at compile time.  See block_cloner.  */
+  virtual void clone_into (block_cloner &cloner, block *dest) const = 0;
 
   /* Append to OUT the blocks whose statements this statement *inlines*
      (rather than merely branching to): a try/catch's try and handler blocks,
@@ -3465,6 +3465,11 @@
   void write_flags (reproducer &r);
   void write_clobbers (reproducer &r);
 
+  /* Copy the flags, operands and clobbers of this extended asm into DEST
+     (a freshly-created clone of it), cloning the operands' rvalues through
+     CLONER.  Used by the clone_into of both concrete subclasses.  */
+  void clone_contents_into (block_cloner &cloner, extended_asm *dest) const;
+
 private:
   string * make_debug_string () final override;
   virtual void maybe_populate_playback_blocks
@@ -3495,6 +3500,8 @@
   bool is_goto () const final override { return false; }
   void maybe_print_gotos (pretty_printer *) const final override {}
 
+  void clone_into (block_cloner &cloner, block *dest) const final override;
+
 private:
   void maybe_populate_playback_blocks
     (auto_vec <playback::block *> *) final override
@@ -3522,6 +3529,8 @@
   bool is_goto () const final override { return true; }
   void maybe_print_gotos (pretty_printer *) const final override;
 
+  void clone_into (block_cloner &cloner, block *dest) const final override;
+
 private:
   void maybe_populate_playback_blocks
     (auto_vec <playback::block *> *out) final override;