OSDN Git Service

Use backend interface for blocks.
[pf3gnuchains/gcc-fork.git] / gcc / go / go-gcc.cc
1 // go-gcc.cc -- Go frontend to gcc IR.
2 // Copyright (C) 2011 Free Software Foundation, Inc.
3 // Contributed by Ian Lance Taylor, Google.
4
5 // This file is part of GCC.
6
7 // GCC is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU General Public License as published by the Free
9 // Software Foundation; either version 3, or (at your option) any later
10 // version.
11
12 // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 // for more details.
16
17 // You should have received a copy of the GNU General Public License
18 // along with GCC; see the file COPYING3.  If not see
19 // <http://www.gnu.org/licenses/>.
20
21 #include "go-system.h"
22
23 // This has to be included outside of extern "C", so we have to
24 // include it here before tree.h includes it later.
25 #include <gmp.h>
26
27 #ifndef ENABLE_BUILD_WITH_CXX
28 extern "C"
29 {
30 #endif
31
32 #include "tree.h"
33 #include "tree-iterator.h"
34 #include "gimple.h"
35
36 #ifndef ENABLE_BUILD_WITH_CXX
37 }
38 #endif
39
40 #include "go-c.h"
41
42 #include "gogo.h"
43 #include "backend.h"
44
45 // A class wrapping a tree.
46
47 class Gcc_tree
48 {
49  public:
50   Gcc_tree(tree t)
51     : t_(t)
52   { }
53
54   tree
55   get_tree()
56   { return this->t_; }
57
58  private:
59   tree t_;
60 };
61
62 // In gcc, types, expressions, and statements are all trees.
63 class Btype : public Gcc_tree
64 {
65  public:
66   Btype(tree t)
67     : Gcc_tree(t)
68   { }
69 };
70
71 class Bexpression : public Gcc_tree
72 {
73  public:
74   Bexpression(tree t)
75     : Gcc_tree(t)
76   { }
77 };
78
79 class Bstatement : public Gcc_tree
80 {
81  public:
82   Bstatement(tree t)
83     : Gcc_tree(t)
84   { }
85 };
86
87 class Bfunction : public Gcc_tree
88 {
89  public:
90   Bfunction(tree t)
91     : Gcc_tree(t)
92   { }
93 };
94
95 class Bblock : public Gcc_tree
96 {
97  public:
98   Bblock(tree t)
99     : Gcc_tree(t)
100   { }
101 };
102
103 class Bvariable : public Gcc_tree
104 {
105  public:
106   Bvariable(tree t)
107     : Gcc_tree(t)
108   { }
109 };
110
111 class Blabel : public Gcc_tree
112 {
113  public:
114   Blabel(tree t)
115     : Gcc_tree(t)
116   { }
117 };
118
119 // This file implements the interface between the Go frontend proper
120 // and the gcc IR.  This implements specific instantiations of
121 // abstract classes defined by the Go frontend proper.  The Go
122 // frontend proper class methods of these classes to generate the
123 // backend representation.
124
125 class Gcc_backend : public Backend
126 {
127  public:
128   // Types.
129
130   Btype*
131   error_type()
132   { gcc_unreachable(); }
133
134   Btype*
135   void_type()
136   { gcc_unreachable(); }
137
138   Btype*
139   bool_type()
140   { gcc_unreachable(); }
141
142   Btype*
143   integer_type(bool /* is_unsigned */, int /* bits */)
144   { gcc_unreachable(); }
145
146   Btype*
147   float_type(int /* bits */)
148   { gcc_unreachable(); }
149
150   Btype*
151   string_type()
152   { gcc_unreachable(); }
153
154   Btype*
155   function_type(const Function_type*, Btype* /* receiver */,
156                 const Btypes* /* parameters */,
157                 const Btypes* /* results */)
158   { gcc_unreachable(); }
159
160   Btype*
161   struct_type(const Struct_type*, const Btypes* /* field_types */)
162   { gcc_unreachable(); }
163
164   Btype*
165   array_type(const Btype* /* element_type */, const Bexpression* /* length */)
166   { gcc_unreachable(); }
167
168   Btype*
169   slice_type(const Btype* /* element_type */)
170   { gcc_unreachable(); }
171
172   Btype*
173   map_type(const Btype* /* key_type */, const Btype* /* value_type */,
174            source_location)
175   { gcc_unreachable(); }
176
177   Btype*
178   channel_type(const Btype* /* element_type */)
179   { gcc_unreachable(); }
180
181   Btype*
182   interface_type(const Interface_type*, const Btypes* /* method_types */)
183   { gcc_unreachable(); }
184
185   // Statements.
186
187   Bstatement*
188   error_statement()
189   { return this->make_statement(error_mark_node); }
190
191   Bstatement*
192   expression_statement(Bexpression*);
193
194   Bstatement*
195   init_statement(Bvariable* var, Bexpression* init);
196
197   Bstatement*
198   assignment_statement(Bexpression* lhs, Bexpression* rhs, source_location);
199
200   Bstatement*
201   return_statement(Bfunction*, const std::vector<Bexpression*>&,
202                    source_location);
203
204   Bstatement*
205   if_statement(Bexpression* condition, Bblock* then_block, Bblock* else_block,
206                source_location);
207
208   Bstatement*
209   switch_statement(Bexpression* value,
210                    const std::vector<std::vector<Bexpression*> >& cases,
211                    const std::vector<Bstatement*>& statements,
212                    source_location);
213
214   Bstatement*
215   compound_statement(Bstatement*, Bstatement*);
216
217   Bstatement*
218   statement_list(const std::vector<Bstatement*>&);
219
220   // Blocks.
221
222   Bblock*
223   block(Bfunction*, Bblock*, const std::vector<Bvariable*>&,
224         source_location, source_location);
225
226   void
227   block_add_statements(Bblock*, const std::vector<Bstatement*>&);
228
229   Bstatement*
230   block_statement(Bblock*);
231
232   // Variables.
233
234   Bvariable*
235   error_variable()
236   { return new Bvariable(error_mark_node); }
237
238   Bvariable*
239   global_variable(const std::string& package_name,
240                   const std::string& unique_prefix,
241                   const std::string& name,
242                   Btype* btype,
243                   bool is_external,
244                   bool is_hidden,
245                   source_location location);
246
247   void
248   global_variable_set_init(Bvariable*, Bexpression*);
249
250   Bvariable*
251   local_variable(Bfunction*, const std::string& name, Btype* type,
252                  source_location);
253
254   Bvariable*
255   parameter_variable(Bfunction*, const std::string& name, Btype* type,
256                      source_location);
257
258   // Labels.
259
260   Blabel*
261   label(Bfunction*, const std::string& name, source_location);
262
263   Bstatement*
264   label_definition_statement(Blabel*);
265
266   Bstatement*
267   goto_statement(Blabel*, source_location);
268
269   Bexpression*
270   label_address(Blabel*, source_location);
271
272  private:
273   // Make a Bexpression from a tree.
274   Bexpression*
275   make_expression(tree t)
276   { return new Bexpression(t); }
277
278   // Make a Bstatement from a tree.
279   Bstatement*
280   make_statement(tree t)
281   { return new Bstatement(t); }
282 };
283
284 // A helper function.
285
286 static inline tree
287 get_identifier_from_string(const std::string& str)
288 {
289   return get_identifier_with_length(str.data(), str.length());
290 }
291
292 // An expression as a statement.
293
294 Bstatement*
295 Gcc_backend::expression_statement(Bexpression* expr)
296 {
297   return this->make_statement(expr->get_tree());
298 }
299
300 // Variable initialization.
301
302 Bstatement*
303 Gcc_backend::init_statement(Bvariable* var, Bexpression* init)
304 {
305   tree var_tree = var->get_tree();
306   tree init_tree = init->get_tree();
307   if (var_tree == error_mark_node || init_tree == error_mark_node)
308     return this->error_statement();
309   gcc_assert(TREE_CODE(var_tree) == VAR_DECL);
310   DECL_INITIAL(var_tree) = init_tree;
311   return this->make_statement(build1_loc(DECL_SOURCE_LOCATION(var_tree),
312                                          DECL_EXPR, void_type_node, var_tree));
313 }
314
315 // Assignment.
316
317 Bstatement*
318 Gcc_backend::assignment_statement(Bexpression* lhs, Bexpression* rhs,
319                                   source_location location)
320 {
321   tree lhs_tree = lhs->get_tree();
322   tree rhs_tree = rhs->get_tree();
323   if (lhs_tree == error_mark_node || rhs_tree == error_mark_node)
324     return this->error_statement();
325   return this->make_statement(fold_build2_loc(location, MODIFY_EXPR,
326                                               void_type_node,
327                                               lhs_tree, rhs_tree));
328 }
329
330 // Return.
331
332 Bstatement*
333 Gcc_backend::return_statement(Bfunction* bfunction,
334                               const std::vector<Bexpression*>& vals,
335                               source_location location)
336 {
337   tree fntree = bfunction->get_tree();
338   if (fntree == error_mark_node)
339     return this->error_statement();
340   tree result = DECL_RESULT(fntree);
341   if (result == error_mark_node)
342     return this->error_statement();
343   tree ret;
344   if (vals.empty())
345     ret = fold_build1_loc(location, RETURN_EXPR, void_type_node, NULL_TREE);
346   else if (vals.size() == 1)
347     {
348       tree val = vals.front()->get_tree();
349       if (val == error_mark_node)
350         return this->error_statement();
351       tree set = fold_build2_loc(location, MODIFY_EXPR, void_type_node,
352                                  result, vals.front()->get_tree());
353       ret = fold_build1_loc(location, RETURN_EXPR, void_type_node, set);
354     }
355   else
356     {
357       // To return multiple values, copy the values into a temporary
358       // variable of the right structure type, and then assign the
359       // temporary variable to the DECL_RESULT in the return
360       // statement.
361       tree stmt_list = NULL_TREE;
362       tree rettype = TREE_TYPE(result);
363       tree rettmp = create_tmp_var(rettype, "RESULT");
364       tree field = TYPE_FIELDS(rettype);
365       for (std::vector<Bexpression*>::const_iterator p = vals.begin();
366            p != vals.end();
367            p++, field = DECL_CHAIN(field))
368         {
369           gcc_assert(field != NULL_TREE);
370           tree ref = fold_build3_loc(location, COMPONENT_REF, TREE_TYPE(field),
371                                      rettmp, field, NULL_TREE);
372           tree val = (*p)->get_tree();
373           if (val == error_mark_node)
374             return this->error_statement();
375           tree set = fold_build2_loc(location, MODIFY_EXPR, void_type_node,
376                                      ref, (*p)->get_tree());
377           append_to_statement_list(set, &stmt_list);
378         }
379       gcc_assert(field == NULL_TREE);
380       tree set = fold_build2_loc(location, MODIFY_EXPR, void_type_node,
381                                  result, rettmp);
382       tree ret_expr = fold_build1_loc(location, RETURN_EXPR, void_type_node,
383                                       set);
384       append_to_statement_list(ret_expr, &stmt_list);
385       ret = stmt_list;
386     }
387   return this->make_statement(ret);
388 }
389
390 // If.
391
392 Bstatement*
393 Gcc_backend::if_statement(Bexpression* condition, Bblock* then_block,
394                           Bblock* else_block, source_location location)
395 {
396   tree cond_tree = condition->get_tree();
397   tree then_tree = then_block->get_tree();
398   tree else_tree = else_block == NULL ? NULL_TREE : else_block->get_tree();
399   if (cond_tree == error_mark_node
400       || then_tree == error_mark_node
401       || else_tree == error_mark_node)
402     return this->error_statement();
403   tree ret = build3_loc(location, COND_EXPR, void_type_node, cond_tree,
404                         then_tree, else_tree);
405   return this->make_statement(ret);
406 }
407
408 // Switch.
409
410 Bstatement*
411 Gcc_backend::switch_statement(
412     Bexpression* value,
413     const std::vector<std::vector<Bexpression*> >& cases,
414     const std::vector<Bstatement*>& statements,
415     source_location switch_location)
416 {
417   gcc_assert(cases.size() == statements.size());
418
419   tree stmt_list = NULL_TREE;
420   std::vector<std::vector<Bexpression*> >::const_iterator pc = cases.begin();
421   for (std::vector<Bstatement*>::const_iterator ps = statements.begin();
422        ps != statements.end();
423        ++ps, ++pc)
424     {
425       if (pc->empty())
426         {
427           source_location loc = (*ps != NULL
428                                  ? EXPR_LOCATION((*ps)->get_tree())
429                                  : UNKNOWN_LOCATION);
430           tree label = create_artificial_label(loc);
431           tree c = build3_loc(loc, CASE_LABEL_EXPR, void_type_node, NULL_TREE,
432                               NULL_TREE, label);
433           append_to_statement_list(c, &stmt_list);
434         }
435       else
436         {
437           for (std::vector<Bexpression*>::const_iterator pcv = pc->begin();
438                pcv != pc->end();
439                ++pcv)
440             {
441               tree t = (*pcv)->get_tree();
442               if (t == error_mark_node)
443                 return this->error_statement();
444               source_location loc = EXPR_LOCATION(t);
445               tree label = create_artificial_label(loc);
446               tree c = build3_loc(loc, CASE_LABEL_EXPR, void_type_node,
447                                   (*pcv)->get_tree(), NULL_TREE, label);
448               append_to_statement_list(c, &stmt_list);
449             }
450         }
451
452       if (*ps != NULL)
453         {
454           tree t = (*ps)->get_tree();
455           if (t == error_mark_node)
456             return this->error_statement();
457           append_to_statement_list(t, &stmt_list);
458         }
459     }
460
461   tree tv = value->get_tree();
462   if (tv == error_mark_node)
463     return this->error_statement();
464   tree t = build3_loc(switch_location, SWITCH_EXPR, void_type_node,
465                       tv, stmt_list, NULL_TREE);
466   return this->make_statement(t);
467 }
468
469 // Pair of statements.
470
471 Bstatement*
472 Gcc_backend::compound_statement(Bstatement* s1, Bstatement* s2)
473 {
474   tree stmt_list = NULL_TREE;
475   tree t = s1->get_tree();
476   if (t == error_mark_node)
477     return this->error_statement();
478   append_to_statement_list(t, &stmt_list);
479   t = s2->get_tree();
480   if (t == error_mark_node)
481     return this->error_statement();
482   append_to_statement_list(t, &stmt_list);
483   return this->make_statement(stmt_list);
484 }
485
486 // List of statements.
487
488 Bstatement*
489 Gcc_backend::statement_list(const std::vector<Bstatement*>& statements)
490 {
491   tree stmt_list = NULL_TREE;
492   for (std::vector<Bstatement*>::const_iterator p = statements.begin();
493        p != statements.end();
494        ++p)
495     {
496       tree t = (*p)->get_tree();
497       if (t == error_mark_node)
498         return this->error_statement();
499       append_to_statement_list(t, &stmt_list);
500     }
501   return this->make_statement(stmt_list);
502 }
503
504 // Make a block.  For some reason gcc uses a dual structure for
505 // blocks: BLOCK tree nodes and BIND_EXPR tree nodes.  Since the
506 // BIND_EXPR node points to the BLOCK node, we store the BIND_EXPR in
507 // the Bblock.
508
509 Bblock*
510 Gcc_backend::block(Bfunction* function, Bblock* enclosing,
511                    const std::vector<Bvariable*>& vars,
512                    source_location start_location,
513                    source_location)
514 {
515   tree block_tree = make_node(BLOCK);
516   if (enclosing == NULL)
517     {
518       // FIXME: Permitting FUNCTION to be NULL is a temporary measure
519       // until we have a proper representation of the init function.
520       tree fndecl;
521       if (function == NULL)
522         fndecl = current_function_decl;
523       else
524         fndecl = function->get_tree();
525       gcc_assert(fndecl != NULL_TREE);
526
527       // We may have already created a block for local variables when
528       // we take the address of a parameter.
529       if (DECL_INITIAL(fndecl) == NULL_TREE)
530         {
531           BLOCK_SUPERCONTEXT(block_tree) = fndecl;
532           DECL_INITIAL(fndecl) = block_tree;
533         }
534       else
535         {
536           tree superblock_tree = DECL_INITIAL(fndecl);
537           BLOCK_SUPERCONTEXT(block_tree) = superblock_tree;
538           tree* pp;
539           for (pp = &BLOCK_SUBBLOCKS(superblock_tree);
540                *pp != NULL_TREE;
541                pp = &BLOCK_CHAIN(*pp))
542             ;
543           *pp = block_tree;
544         }
545     }
546   else
547     {
548       tree superbind_tree = enclosing->get_tree();
549       tree superblock_tree = BIND_EXPR_BLOCK(superbind_tree);
550       gcc_assert(TREE_CODE(superblock_tree) == BLOCK);
551
552       BLOCK_SUPERCONTEXT(block_tree) = superblock_tree;
553       tree* pp;
554       for (pp = &BLOCK_SUBBLOCKS(superblock_tree);
555            *pp != NULL_TREE;
556            pp = &BLOCK_CHAIN(*pp))
557         ;
558       *pp = block_tree;
559     }
560
561   tree* pp = &BLOCK_VARS(block_tree);
562   for (std::vector<Bvariable*>::const_iterator pv = vars.begin();
563        pv != vars.end();
564        ++pv)
565     {
566       *pp = (*pv)->get_tree();
567       if (*pp != error_mark_node)
568         pp = &DECL_CHAIN(*pp);
569     }
570   *pp = NULL_TREE;
571
572   TREE_USED(block_tree) = 1;
573
574   tree bind_tree = build3_loc(start_location, BIND_EXPR, void_type_node,
575                               BLOCK_VARS(block_tree), NULL_TREE, block_tree);
576   TREE_SIDE_EFFECTS(bind_tree) = 1;
577
578   return new Bblock(bind_tree);
579 }
580
581 // Add statements to a block.
582
583 void
584 Gcc_backend::block_add_statements(Bblock* bblock,
585                                   const std::vector<Bstatement*>& statements)
586 {
587   tree stmt_list = NULL_TREE;
588   for (std::vector<Bstatement*>::const_iterator p = statements.begin();
589        p != statements.end();
590        ++p)
591     {
592       tree s = (*p)->get_tree();
593       if (s != error_mark_node)
594         append_to_statement_list(s, &stmt_list);
595     }
596
597   tree bind_tree = bblock->get_tree();
598   gcc_assert(TREE_CODE(bind_tree) == BIND_EXPR);
599   BIND_EXPR_BODY(bind_tree) = stmt_list;
600 }
601
602 // Return a block as a statement.
603
604 Bstatement*
605 Gcc_backend::block_statement(Bblock* bblock)
606 {
607   tree bind_tree = bblock->get_tree();
608   gcc_assert(TREE_CODE(bind_tree) == BIND_EXPR);
609   return this->make_statement(bind_tree);
610 }
611
612 // Make a global variable.
613
614 Bvariable*
615 Gcc_backend::global_variable(const std::string& package_name,
616                              const std::string& unique_prefix,
617                              const std::string& name,
618                              Btype* btype,
619                              bool is_external,
620                              bool is_hidden,
621                              source_location location)
622 {
623   tree type_tree = btype->get_tree();
624   if (type_tree == error_mark_node)
625     return this->error_variable();
626
627   std::string var_name(package_name);
628   var_name.push_back('.');
629   var_name.append(name);
630   tree decl = build_decl(location, VAR_DECL,
631                          get_identifier_from_string(var_name),
632                          type_tree);
633   if (is_external)
634     DECL_EXTERNAL(decl) = 1;
635   else
636     TREE_STATIC(decl) = 1;
637   if (!is_hidden)
638     {
639       TREE_PUBLIC(decl) = 1;
640
641       std::string asm_name(unique_prefix);
642       asm_name.push_back('.');
643       asm_name.append(var_name);
644       SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name));
645     }
646   TREE_USED(decl) = 1;
647
648   go_preserve_from_gc(decl);
649
650   return new Bvariable(decl);
651 }
652
653 // Set the initial value of a global variable.
654
655 void
656 Gcc_backend::global_variable_set_init(Bvariable* var, Bexpression* expr)
657 {
658   tree expr_tree = expr->get_tree();
659   if (expr_tree == error_mark_node)
660     return;
661   gcc_assert(TREE_CONSTANT(expr_tree));
662   tree var_decl = var->get_tree();
663   if (var_decl == error_mark_node)
664     return;
665   DECL_INITIAL(var_decl) = expr_tree;
666 }
667
668 // Make a local variable.
669
670 Bvariable*
671 Gcc_backend::local_variable(Bfunction* function, const std::string& name,
672                             Btype* btype, source_location location)
673 {
674   tree type_tree = btype->get_tree();
675   if (type_tree == error_mark_node)
676     return this->error_variable();
677   tree decl = build_decl(location, VAR_DECL,
678                          get_identifier_from_string(name),
679                          type_tree);
680   DECL_CONTEXT(decl) = function->get_tree();
681   TREE_USED(decl) = 1;
682   go_preserve_from_gc(decl);
683   return new Bvariable(decl);
684 }
685
686 // Make a function parameter variable.
687
688 Bvariable*
689 Gcc_backend::parameter_variable(Bfunction* function, const std::string& name,
690                                 Btype* btype, source_location location)
691 {
692   tree type_tree = btype->get_tree();
693   if (type_tree == error_mark_node)
694     return this->error_variable();
695   tree decl = build_decl(location, PARM_DECL,
696                          get_identifier_from_string(name),
697                          type_tree);
698   DECL_CONTEXT(decl) = function->get_tree();
699   DECL_ARG_TYPE(decl) = type_tree;
700   TREE_USED(decl) = 1;
701   go_preserve_from_gc(decl);
702   return new Bvariable(decl);
703 }
704
705 // Make a label.
706
707 Blabel*
708 Gcc_backend::label(Bfunction* function, const std::string& name,
709                    source_location location)
710 {
711   tree decl;
712   if (name.empty())
713     decl = create_artificial_label(location);
714   else
715     {
716       tree id = get_identifier_from_string(name);
717       decl = build_decl(location, LABEL_DECL, id, void_type_node);
718       DECL_CONTEXT(decl) = function->get_tree();
719     }
720   return new Blabel(decl);
721 }
722
723 // Make a statement which defines a label.
724
725 Bstatement*
726 Gcc_backend::label_definition_statement(Blabel* label)
727 {
728   tree lab = label->get_tree();
729   tree ret = fold_build1_loc(DECL_SOURCE_LOCATION(lab), LABEL_EXPR,
730                              void_type_node, lab);
731   return this->make_statement(ret);
732 }
733
734 // Make a goto statement.
735
736 Bstatement*
737 Gcc_backend::goto_statement(Blabel* label, source_location location)
738 {
739   tree lab = label->get_tree();
740   tree ret = fold_build1_loc(location, GOTO_EXPR, void_type_node, lab);
741   return this->make_statement(ret);
742 }
743
744 // Get the address of a label.
745
746 Bexpression*
747 Gcc_backend::label_address(Blabel* label, source_location location)
748 {
749   tree lab = label->get_tree();
750   TREE_USED(lab) = 1;
751   TREE_ADDRESSABLE(lab) = 1;
752   tree ret = fold_convert_loc(location, ptr_type_node,
753                               build_fold_addr_expr_loc(location, lab));
754   return this->make_expression(ret);
755 }
756
757 // The single backend.
758
759 static Gcc_backend gcc_backend;
760
761 // Return the backend generator.
762
763 Backend*
764 go_get_backend()
765 {
766   return &gcc_backend;
767 }
768
769 // FIXME: Temporary functions while converting to the new backend
770 // interface.
771
772 Btype*
773 tree_to_type(tree t)
774 {
775   return new Btype(t);
776 }
777
778 Bexpression*
779 tree_to_expr(tree t)
780 {
781   return new Bexpression(t);
782 }
783
784 Bstatement*
785 tree_to_stat(tree t)
786 {
787   return new Bstatement(t);
788 }
789
790 Bfunction*
791 tree_to_function(tree t)
792 {
793   return new Bfunction(t);
794 }
795
796 Bblock*
797 tree_to_block(tree t)
798 {
799   gcc_assert(TREE_CODE(t) == BIND_EXPR);
800   return new Bblock(t);
801 }
802
803 tree
804 expr_to_tree(Bexpression* be)
805 {
806   return be->get_tree();
807 }
808
809 tree
810 stat_to_tree(Bstatement* bs)
811 {
812   return bs->get_tree();
813 }
814
815 tree
816 block_to_tree(Bblock* bb)
817 {
818   return bb->get_tree();
819 }
820
821 tree
822 var_to_tree(Bvariable* bv)
823 {
824   return bv->get_tree();
825 }