OSDN Git Service

Use the backend interface for select statements.
[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 "gogo.h"
41 #include "backend.h"
42
43 // A class wrapping a tree.
44
45 class Gcc_tree
46 {
47  public:
48   Gcc_tree(tree t)
49     : t_(t)
50   { }
51
52   tree
53   get_tree()
54   { return this->t_; }
55
56  private:
57   tree t_;
58 };
59
60 // In gcc, types, expressions, and statements are all trees.
61 class Btype : public Gcc_tree
62 {
63  public:
64   Btype(tree t)
65     : Gcc_tree(t)
66   { }
67 };
68
69 class Bexpression : public Gcc_tree
70 {
71  public:
72   Bexpression(tree t)
73     : Gcc_tree(t)
74   { }
75 };
76
77 class Bstatement : public Gcc_tree
78 {
79  public:
80   Bstatement(tree t)
81     : Gcc_tree(t)
82   { }
83 };
84
85 class Bfunction : public Gcc_tree
86 {
87  public:
88   Bfunction(tree t)
89     : Gcc_tree(t)
90   { }
91 };
92
93 class Blabel : public Gcc_tree
94 {
95  public:
96   Blabel(tree t)
97     : Gcc_tree(t)
98   { }
99 };
100
101 // This file implements the interface between the Go frontend proper
102 // and the gcc IR.  This implements specific instantiations of
103 // abstract classes defined by the Go frontend proper.  The Go
104 // frontend proper class methods of these classes to generate the
105 // backend representation.
106
107 class Gcc_backend : public Backend
108 {
109  public:
110   // Types.
111
112   Btype*
113   error_type()
114   { gcc_unreachable(); }
115
116   Btype*
117   void_type()
118   { gcc_unreachable(); }
119
120   Btype*
121   bool_type()
122   { gcc_unreachable(); }
123
124   Btype*
125   integer_type(bool /* is_unsigned */, int /* bits */)
126   { gcc_unreachable(); }
127
128   Btype*
129   float_type(int /* bits */)
130   { gcc_unreachable(); }
131
132   Btype*
133   string_type()
134   { gcc_unreachable(); }
135
136   Btype*
137   function_type(const Function_type*, Btype* /* receiver */,
138                 const Btypes* /* parameters */,
139                 const Btypes* /* results */)
140   { gcc_unreachable(); }
141
142   Btype*
143   struct_type(const Struct_type*, const Btypes* /* field_types */)
144   { gcc_unreachable(); }
145
146   Btype*
147   array_type(const Btype* /* element_type */, const Bexpression* /* length */)
148   { gcc_unreachable(); }
149
150   Btype*
151   slice_type(const Btype* /* element_type */)
152   { gcc_unreachable(); }
153
154   Btype*
155   map_type(const Btype* /* key_type */, const Btype* /* value_type */,
156            source_location)
157   { gcc_unreachable(); }
158
159   Btype*
160   channel_type(const Btype* /* element_type */)
161   { gcc_unreachable(); }
162
163   Btype*
164   interface_type(const Interface_type*, const Btypes* /* method_types */)
165   { gcc_unreachable(); }
166
167   // Statements.
168
169   Bstatement*
170   error_statement()
171   { return this->make_statement(error_mark_node); }
172
173   Bstatement*
174   expression_statement(Bexpression*);
175
176   Bstatement*
177   assignment_statement(Bexpression* lhs, Bexpression* rhs, source_location);
178
179   Bstatement*
180   return_statement(Bfunction*, const std::vector<Bexpression*>&,
181                    source_location);
182
183   Bstatement*
184   if_statement(Bexpression* condition, Bstatement* then_block,
185                Bstatement* else_block, source_location);
186
187   Bstatement*
188   switch_statement(Bexpression* value,
189                    const std::vector<std::vector<Bexpression*> >& cases,
190                    const std::vector<Bstatement*>& statements,
191                    source_location);
192
193   Bstatement*
194   statement_list(const std::vector<Bstatement*>&);
195
196   // Labels.
197
198   Blabel*
199   label(Bfunction*, const std::string& name, source_location);
200
201   Bstatement*
202   label_definition_statement(Blabel*);
203
204   Bstatement*
205   goto_statement(Blabel*, source_location);
206
207   Bexpression*
208   label_address(Blabel*, source_location);
209
210  private:
211   // Make a Bexpression from a tree.
212   Bexpression*
213   make_expression(tree t)
214   { return new Bexpression(t); }
215
216   // Make a Bstatement from a tree.
217   Bstatement*
218   make_statement(tree t)
219   { return new Bstatement(t); }
220 };
221
222 // A helper function.
223
224 static inline tree
225 get_identifier_from_string(const std::string& str)
226 {
227   return get_identifier_with_length(str.data(), str.length());
228 }
229
230 // An expression as a statement.
231
232 Bstatement*
233 Gcc_backend::expression_statement(Bexpression* expr)
234 {
235   return this->make_statement(expr->get_tree());
236 }
237
238 // Assignment.
239
240 Bstatement*
241 Gcc_backend::assignment_statement(Bexpression* lhs, Bexpression* rhs,
242                                   source_location location)
243 {
244   tree lhs_tree = lhs->get_tree();
245   tree rhs_tree = rhs->get_tree();
246   if (lhs_tree == error_mark_node || rhs_tree == error_mark_node)
247     return this->make_statement(error_mark_node);
248   return this->make_statement(fold_build2_loc(location, MODIFY_EXPR,
249                                               void_type_node,
250                                               lhs_tree, rhs_tree));
251 }
252
253 // Return.
254
255 Bstatement*
256 Gcc_backend::return_statement(Bfunction* bfunction,
257                               const std::vector<Bexpression*>& vals,
258                               source_location location)
259 {
260   tree fntree = bfunction->get_tree();
261   if (fntree == error_mark_node)
262     return this->make_statement(error_mark_node);
263   tree result = DECL_RESULT(fntree);
264   if (result == error_mark_node)
265     return this->make_statement(error_mark_node);
266   tree ret;
267   if (vals.empty())
268     ret = fold_build1_loc(location, RETURN_EXPR, void_type_node, NULL_TREE);
269   else if (vals.size() == 1)
270     {
271       tree val = vals.front()->get_tree();
272       if (val == error_mark_node)
273         return this->make_statement(error_mark_node);
274       tree set = fold_build2_loc(location, MODIFY_EXPR, void_type_node,
275                                  result, vals.front()->get_tree());
276       ret = fold_build1_loc(location, RETURN_EXPR, void_type_node, set);
277     }
278   else
279     {
280       // To return multiple values, copy the values into a temporary
281       // variable of the right structure type, and then assign the
282       // temporary variable to the DECL_RESULT in the return
283       // statement.
284       tree stmt_list = NULL_TREE;
285       tree rettype = TREE_TYPE(result);
286       tree rettmp = create_tmp_var(rettype, "RESULT");
287       tree field = TYPE_FIELDS(rettype);
288       for (std::vector<Bexpression*>::const_iterator p = vals.begin();
289            p != vals.end();
290            p++, field = DECL_CHAIN(field))
291         {
292           gcc_assert(field != NULL_TREE);
293           tree ref = fold_build3_loc(location, COMPONENT_REF, TREE_TYPE(field),
294                                      rettmp, field, NULL_TREE);
295           tree val = (*p)->get_tree();
296           if (val == error_mark_node)
297             return this->make_statement(error_mark_node);
298           tree set = fold_build2_loc(location, MODIFY_EXPR, void_type_node,
299                                      ref, (*p)->get_tree());
300           append_to_statement_list(set, &stmt_list);
301         }
302       gcc_assert(field == NULL_TREE);
303       tree set = fold_build2_loc(location, MODIFY_EXPR, void_type_node,
304                                  result, rettmp);
305       tree ret_expr = fold_build1_loc(location, RETURN_EXPR, void_type_node,
306                                       set);
307       append_to_statement_list(ret_expr, &stmt_list);
308       ret = stmt_list;
309     }
310   return this->make_statement(ret);
311 }
312
313 // If.
314
315 Bstatement*
316 Gcc_backend::if_statement(Bexpression* condition, Bstatement* then_block,
317                           Bstatement* else_block, source_location location)
318 {
319   tree cond_tree = condition->get_tree();
320   tree then_tree = then_block->get_tree();
321   tree else_tree = else_block == NULL ? NULL_TREE : else_block->get_tree();
322   if (cond_tree == error_mark_node
323       || then_tree == error_mark_node
324       || else_tree == error_mark_node)
325     return this->make_statement(error_mark_node);
326   tree ret = build3_loc(location, COND_EXPR, void_type_node, cond_tree,
327                         then_tree, else_tree);
328   return this->make_statement(ret);
329 }
330
331 // Switch.
332
333 Bstatement*
334 Gcc_backend::switch_statement(
335     Bexpression* value,
336     const std::vector<std::vector<Bexpression*> >& cases,
337     const std::vector<Bstatement*>& statements,
338     source_location switch_location)
339 {
340   gcc_assert(cases.size() == statements.size());
341
342   tree stmt_list = NULL_TREE;
343   std::vector<std::vector<Bexpression*> >::const_iterator pc = cases.begin();
344   for (std::vector<Bstatement*>::const_iterator ps = statements.begin();
345        ps != statements.end();
346        ++ps, ++pc)
347     {
348       if (pc->empty())
349         {
350           source_location loc = (*ps != NULL
351                                  ? EXPR_LOCATION((*ps)->get_tree())
352                                  : UNKNOWN_LOCATION);
353           tree label = create_artificial_label(loc);
354           tree c = build3_loc(loc, CASE_LABEL_EXPR, void_type_node, NULL_TREE,
355                               NULL_TREE, label);
356           append_to_statement_list(c, &stmt_list);
357         }
358       else
359         {
360           for (std::vector<Bexpression*>::const_iterator pcv = pc->begin();
361                pcv != pc->end();
362                ++pcv)
363             {
364               tree t = (*pcv)->get_tree();
365               if (t == error_mark_node)
366                 return this->make_statement(error_mark_node);
367               source_location loc = EXPR_LOCATION(t);
368               tree label = create_artificial_label(loc);
369               tree c = build3_loc(loc, CASE_LABEL_EXPR, void_type_node,
370                                   (*pcv)->get_tree(), NULL_TREE, label);
371               append_to_statement_list(c, &stmt_list);
372             }
373         }
374
375       if (*ps != NULL)
376         {
377           tree t = (*ps)->get_tree();
378           if (t == error_mark_node)
379             return this->make_statement(error_mark_node);
380           append_to_statement_list(t, &stmt_list);
381         }
382     }
383
384   tree tv = value->get_tree();
385   if (tv == error_mark_node)
386     return this->make_statement(error_mark_node);
387   tree t = build3_loc(switch_location, SWITCH_EXPR, void_type_node,
388                       tv, stmt_list, NULL_TREE);
389   return this->make_statement(t);
390 }
391
392 // List of statements.
393
394 Bstatement*
395 Gcc_backend::statement_list(const std::vector<Bstatement*>& statements)
396 {
397   tree stmt_list = NULL_TREE;
398   for (std::vector<Bstatement*>::const_iterator p = statements.begin();
399        p != statements.end();
400        ++p)
401     {
402       tree t = (*p)->get_tree();
403       if (t == error_mark_node)
404         return this->make_statement(error_mark_node);
405       append_to_statement_list(t, &stmt_list);
406     }
407   return this->make_statement(stmt_list);
408 }
409
410 // Make a label.
411
412 Blabel*
413 Gcc_backend::label(Bfunction* function, const std::string& name,
414                    source_location location)
415 {
416   tree decl;
417   if (name.empty())
418     decl = create_artificial_label(location);
419   else
420     {
421       tree id = get_identifier_from_string(name);
422       decl = build_decl(location, LABEL_DECL, id, void_type_node);
423       DECL_CONTEXT(decl) = function->get_tree();
424     }
425   return new Blabel(decl);
426 }
427
428 // Make a statement which defines a label.
429
430 Bstatement*
431 Gcc_backend::label_definition_statement(Blabel* label)
432 {
433   tree lab = label->get_tree();
434   tree ret = fold_build1_loc(DECL_SOURCE_LOCATION(lab), LABEL_EXPR,
435                              void_type_node, lab);
436   return this->make_statement(ret);
437 }
438
439 // Make a goto statement.
440
441 Bstatement*
442 Gcc_backend::goto_statement(Blabel* label, source_location location)
443 {
444   tree lab = label->get_tree();
445   tree ret = fold_build1_loc(location, GOTO_EXPR, void_type_node, lab);
446   return this->make_statement(ret);
447 }
448
449 // Get the address of a label.
450
451 Bexpression*
452 Gcc_backend::label_address(Blabel* label, source_location location)
453 {
454   tree lab = label->get_tree();
455   TREE_USED(lab) = 1;
456   TREE_ADDRESSABLE(lab) = 1;
457   tree ret = fold_convert_loc(location, ptr_type_node,
458                               build_fold_addr_expr_loc(location, lab));
459   return this->make_expression(ret);
460 }
461
462 // The single backend.
463
464 static Gcc_backend gcc_backend;
465
466 // Return the backend generator.
467
468 Backend*
469 go_get_backend()
470 {
471   return &gcc_backend;
472 }
473
474 // FIXME: Temporary functions while converting to the new backend
475 // interface.
476
477 Bexpression*
478 tree_to_expr(tree t)
479 {
480   return new Bexpression(t);
481 }
482
483 Bstatement*
484 tree_to_stat(tree t)
485 {
486   return new Bstatement(t);
487 }
488
489 Bfunction*
490 tree_to_function(tree t)
491 {
492   return new Bfunction(t);
493 }
494
495 tree
496 expr_to_tree(Bexpression* be)
497 {
498   return be->get_tree();
499 }
500
501 tree
502 stat_to_tree(Bstatement* bs)
503 {
504   return bs->get_tree();
505 }