1 // go-gcc.cc -- Go frontend to gcc IR.
2 // Copyright (C) 2011 Free Software Foundation, Inc.
3 // Contributed by Ian Lance Taylor, Google.
5 // This file is part of GCC.
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
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
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/>.
21 #include "go-system.h"
23 // This has to be included outside of extern "C", so we have to
24 // include it here before tree.h includes it later.
27 #ifndef ENABLE_BUILD_WITH_CXX
33 #include "tree-iterator.h"
36 #ifndef ENABLE_BUILD_WITH_CXX
43 // A class wrapping a tree.
60 // In gcc, types, expressions, and statements are all trees.
61 class Btype : public Gcc_tree
69 class Bexpression : public Gcc_tree
77 class Bstatement : public Gcc_tree
85 class Bfunction : public Gcc_tree
93 class Blabel : public Gcc_tree
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.
107 class Gcc_backend : public Backend
114 { gcc_unreachable(); }
118 { gcc_unreachable(); }
122 { gcc_unreachable(); }
125 integer_type(bool /* is_unsigned */, int /* bits */)
126 { gcc_unreachable(); }
129 float_type(int /* bits */)
130 { gcc_unreachable(); }
134 { gcc_unreachable(); }
137 function_type(const Function_type*, Btype* /* receiver */,
138 const Btypes* /* parameters */,
139 const Btypes* /* results */)
140 { gcc_unreachable(); }
143 struct_type(const Struct_type*, const Btypes* /* field_types */)
144 { gcc_unreachable(); }
147 array_type(const Btype* /* element_type */, const Bexpression* /* length */)
148 { gcc_unreachable(); }
151 slice_type(const Btype* /* element_type */)
152 { gcc_unreachable(); }
155 map_type(const Btype* /* key_type */, const Btype* /* value_type */,
157 { gcc_unreachable(); }
160 channel_type(const Btype* /* element_type */)
161 { gcc_unreachable(); }
164 interface_type(const Interface_type*, const Btypes* /* method_types */)
165 { gcc_unreachable(); }
171 { return this->make_statement(error_mark_node); }
174 expression_statement(Bexpression*);
177 assignment_statement(Bexpression* lhs, Bexpression* rhs, source_location);
180 return_statement(Bfunction*, const std::vector<Bexpression*>&,
184 if_statement(Bexpression* condition, Bstatement* then_block,
185 Bstatement* else_block, source_location);
188 switch_statement(Bexpression* value,
189 const std::vector<std::vector<Bexpression*> >& cases,
190 const std::vector<Bstatement*>& statements,
194 statement_list(const std::vector<Bstatement*>&);
199 label(Bfunction*, const std::string& name, source_location);
202 label_definition_statement(Blabel*);
205 goto_statement(Blabel*, source_location);
208 label_address(Blabel*, source_location);
211 // Make a Bexpression from a tree.
213 make_expression(tree t)
214 { return new Bexpression(t); }
216 // Make a Bstatement from a tree.
218 make_statement(tree t)
219 { return new Bstatement(t); }
222 // A helper function.
225 get_identifier_from_string(const std::string& str)
227 return get_identifier_with_length(str.data(), str.length());
230 // An expression as a statement.
233 Gcc_backend::expression_statement(Bexpression* expr)
235 return this->make_statement(expr->get_tree());
241 Gcc_backend::assignment_statement(Bexpression* lhs, Bexpression* rhs,
242 source_location location)
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,
250 lhs_tree, rhs_tree));
256 Gcc_backend::return_statement(Bfunction* bfunction,
257 const std::vector<Bexpression*>& vals,
258 source_location location)
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);
268 ret = fold_build1_loc(location, RETURN_EXPR, void_type_node, NULL_TREE);
269 else if (vals.size() == 1)
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);
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
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();
290 p++, field = DECL_CHAIN(field))
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);
302 gcc_assert(field == NULL_TREE);
303 tree set = fold_build2_loc(location, MODIFY_EXPR, void_type_node,
305 tree ret_expr = fold_build1_loc(location, RETURN_EXPR, void_type_node,
307 append_to_statement_list(ret_expr, &stmt_list);
310 return this->make_statement(ret);
316 Gcc_backend::if_statement(Bexpression* condition, Bstatement* then_block,
317 Bstatement* else_block, source_location location)
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);
334 Gcc_backend::switch_statement(
336 const std::vector<std::vector<Bexpression*> >& cases,
337 const std::vector<Bstatement*>& statements,
338 source_location switch_location)
340 gcc_assert(cases.size() == statements.size());
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();
350 source_location loc = (*ps != NULL
351 ? EXPR_LOCATION((*ps)->get_tree())
353 tree label = create_artificial_label(loc);
354 tree c = build3_loc(loc, CASE_LABEL_EXPR, void_type_node, NULL_TREE,
356 append_to_statement_list(c, &stmt_list);
360 for (std::vector<Bexpression*>::const_iterator pcv = pc->begin();
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);
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);
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);
392 // List of statements.
395 Gcc_backend::statement_list(const std::vector<Bstatement*>& statements)
397 tree stmt_list = NULL_TREE;
398 for (std::vector<Bstatement*>::const_iterator p = statements.begin();
399 p != statements.end();
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);
407 return this->make_statement(stmt_list);
413 Gcc_backend::label(Bfunction* function, const std::string& name,
414 source_location location)
418 decl = create_artificial_label(location);
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();
425 return new Blabel(decl);
428 // Make a statement which defines a label.
431 Gcc_backend::label_definition_statement(Blabel* label)
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);
439 // Make a goto statement.
442 Gcc_backend::goto_statement(Blabel* label, source_location location)
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);
449 // Get the address of a label.
452 Gcc_backend::label_address(Blabel* label, source_location location)
454 tree lab = label->get_tree();
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);
462 // The single backend.
464 static Gcc_backend gcc_backend;
466 // Return the backend generator.
474 // FIXME: Temporary functions while converting to the new backend
480 return new Bexpression(t);
486 return new Bstatement(t);
490 tree_to_function(tree t)
492 return new Bfunction(t);
496 expr_to_tree(Bexpression* be)
498 return be->get_tree();
502 stat_to_tree(Bstatement* bs)
504 return bs->get_tree();