diff options
author | Philip Herron <philip.herron@embecosm.com> | 2021-02-05 16:49:26 +0000 |
---|---|---|
committer | Philip Herron <herron.philip@googlemail.com> | 2021-02-06 15:17:08 +0000 |
commit | 599b04aa7d928a305029d8e8cf5d6f5c5a683da8 (patch) | |
tree | d4d464c29ebab1df3ddaa8d9a39383a56e0f1dce /gcc | |
parent | c4be77f7e0f6b35c019940200f94c7a7b30fff84 (diff) | |
download | gcc-599b04aa7d928a305029d8e8cf5d6f5c5a683da8.zip gcc-599b04aa7d928a305029d8e8cf5d6f5c5a683da8.tar.gz gcc-599b04aa7d928a305029d8e8cf5d6f5c5a683da8.tar.bz2 |
This adds support for basic BlockExpressions
We keep temporary's for each block in order for the result to be
referenced. For example:
let x = { test() + 1 };
This can be resolved into:
{
let x:i32;
_tmp1:i32;
{
_tmp2:i32 = test();
_tmp1 = _tmp2 + 1;
}
x = _tmp1;
}
Fixes #189
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/rust/backend/rust-compile-base.h | 6 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-block.h | 41 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-context.h | 5 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-expr.h | 52 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-implitem.h | 24 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-item.h | 25 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-stmt.h | 26 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile.cc | 124 | ||||
-rw-r--r-- | gcc/rust/hir/tree/rust-hir-expr.h | 4 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check.cc | 19 | ||||
-rw-r--r-- | gcc/testsuite/rust.test/compilable/block_expr1.rs | 27 |
11 files changed, 236 insertions, 117 deletions
diff --git a/gcc/rust/backend/rust-compile-base.h b/gcc/rust/backend/rust-compile-base.h index fdc5ad9..ec7c13a 100644 --- a/gcc/rust/backend/rust-compile-base.h +++ b/gcc/rust/backend/rust-compile-base.h @@ -237,9 +237,13 @@ public: protected: HIRCompileBase (Context *ctx) : ctx (ctx) {} + Context *ctx; + Context *get_context () { return ctx; } - Context *ctx; + void compile_function_body (Bfunction *fndecl, + std::unique_ptr<HIR::BlockExpr> &function_body, + bool has_return_type); }; } // namespace Compile diff --git a/gcc/rust/backend/rust-compile-block.h b/gcc/rust/backend/rust-compile-block.h index b17fb05..879e32d 100644 --- a/gcc/rust/backend/rust-compile-block.h +++ b/gcc/rust/backend/rust-compile-block.h @@ -28,35 +28,35 @@ namespace Compile { class CompileBlock : public HIRCompileBase { public: - static Bblock *compile (HIR::BlockExpr *expr, Context *ctx) + static Bblock *compile (HIR::BlockExpr *expr, Context *ctx, Bvariable *result) { - CompileBlock compiler (ctx); + CompileBlock compiler (ctx, result); expr->accept_vis (compiler); return compiler.translated; } - ~CompileBlock () {} - void visit (HIR::BlockExpr &expr); private: - CompileBlock (Context *ctx) : HIRCompileBase (ctx), translated (nullptr) {} + CompileBlock (Context *ctx, Bvariable *result) + : HIRCompileBase (ctx), translated (nullptr), result (result) + {} Bblock *translated; + Bvariable *result; }; class CompileConditionalBlocks : public HIRCompileBase { public: - static Bstatement *compile (HIR::IfExpr *expr, Context *ctx) + static Bstatement *compile (HIR::IfExpr *expr, Context *ctx, + Bvariable *result) { - CompileConditionalBlocks resolver (ctx); + CompileConditionalBlocks resolver (ctx, result); expr->accept_vis (resolver); return resolver.translated; } - ~CompileConditionalBlocks () {} - void visit (HIR::IfExpr &expr); void visit (HIR::IfExprConseqElse &expr); @@ -64,46 +64,47 @@ public: void visit (HIR::IfExprConseqIf &expr); private: - CompileConditionalBlocks (Context *ctx) - : HIRCompileBase (ctx), translated (nullptr) + CompileConditionalBlocks (Context *ctx, Bvariable *result) + : HIRCompileBase (ctx), translated (nullptr), result (result) {} Bstatement *translated; + Bvariable *result; }; class CompileExprWithBlock : public HIRCompileBase { public: - static Bstatement *compile (HIR::ExprWithBlock *expr, Context *ctx) + static Bstatement *compile (HIR::ExprWithBlock *expr, Context *ctx, + Bvariable *result) { - CompileExprWithBlock resolver (ctx); + CompileExprWithBlock resolver (ctx, result); expr->accept_vis (resolver); return resolver.translated; } - ~CompileExprWithBlock () {} - void visit (HIR::IfExpr &expr) { - translated = CompileConditionalBlocks::compile (&expr, ctx); + translated = CompileConditionalBlocks::compile (&expr, ctx, result); } void visit (HIR::IfExprConseqElse &expr) { - translated = CompileConditionalBlocks::compile (&expr, ctx); + translated = CompileConditionalBlocks::compile (&expr, ctx, result); } void visit (HIR::IfExprConseqIf &expr) { - translated = CompileConditionalBlocks::compile (&expr, ctx); + translated = CompileConditionalBlocks::compile (&expr, ctx, result); } private: - CompileExprWithBlock (Context *ctx) - : HIRCompileBase (ctx), translated (nullptr) + CompileExprWithBlock (Context *ctx, Bvariable *result) + : HIRCompileBase (ctx), translated (nullptr), result (result) {} Bstatement *translated; + Bvariable *result; }; } // namespace Compile diff --git a/gcc/rust/backend/rust-compile-context.h b/gcc/rust/backend/rust-compile-context.h index 034568f..194ee06 100644 --- a/gcc/rust/backend/rust-compile-context.h +++ b/gcc/rust/backend/rust-compile-context.h @@ -110,6 +110,11 @@ public: return scope_stack.back (); } + void add_statement_to_enclosing_scope (Bstatement *stmt) + { + statements.at (statements.size () - 2).push_back (stmt); + } + void add_statement (Bstatement *stmt) { statements.back ().push_back (stmt); } void insert_var_decl (HirId id, ::Bvariable *decl) diff --git a/gcc/rust/backend/rust-compile-expr.h b/gcc/rust/backend/rust-compile-expr.h index ccff51a..fad5ce0 100644 --- a/gcc/rust/backend/rust-compile-expr.h +++ b/gcc/rust/backend/rust-compile-expr.h @@ -409,27 +409,71 @@ public: void visit (HIR::IfExpr &expr) { - auto stmt = CompileConditionalBlocks::compile (&expr, ctx); + auto stmt = CompileConditionalBlocks::compile (&expr, ctx, nullptr); ctx->add_statement (stmt); } void visit (HIR::IfExprConseqElse &expr) { - auto stmt = CompileConditionalBlocks::compile (&expr, ctx); + // this can be a return expression + TyTy::TyBase *if_type = nullptr; + if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), + &if_type)) + { + rust_error_at (expr.get_locus (), + "failed to lookup type of IfExprConseqElse"); + return; + } + + fncontext fnctx = ctx->peek_fn (); + Bblock *enclosing_scope = ctx->peek_enclosing_scope (); + Btype *block_type = TyTyResolveCompile::compile (ctx, if_type); + + bool is_address_taken = false; + Bstatement *ret_var_stmt = nullptr; + Bvariable *tmp = ctx->get_backend ()->temporary_variable ( + fnctx.fndecl, enclosing_scope, block_type, NULL, is_address_taken, + expr.get_locus (), &ret_var_stmt); + ctx->add_statement (ret_var_stmt); + + auto stmt = CompileConditionalBlocks::compile (&expr, ctx, tmp); ctx->add_statement (stmt); + + translated = ctx->get_backend ()->var_expression (tmp, expr.get_locus ()); } void visit (HIR::IfExprConseqIf &expr) { - auto stmt = CompileConditionalBlocks::compile (&expr, ctx); + auto stmt = CompileConditionalBlocks::compile (&expr, ctx, nullptr); ctx->add_statement (stmt); } void visit (HIR::BlockExpr &expr) { - auto code_block = CompileBlock::compile (&expr, ctx); + TyTy::TyBase *block_tyty = nullptr; + if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), + &block_tyty)) + { + rust_error_at (expr.get_locus (), "failed to lookup type of BlockExpr"); + return; + } + + fncontext fnctx = ctx->peek_fn (); + Bblock *enclosing_scope = ctx->peek_enclosing_scope (); + Btype *block_type = TyTyResolveCompile::compile (ctx, block_tyty); + + bool is_address_taken = false; + Bstatement *ret_var_stmt = nullptr; + Bvariable *tmp = ctx->get_backend ()->temporary_variable ( + fnctx.fndecl, enclosing_scope, block_type, NULL, is_address_taken, + expr.get_locus (), &ret_var_stmt); + ctx->add_statement (ret_var_stmt); + + auto code_block = CompileBlock::compile (&expr, ctx, tmp); auto block_stmt = ctx->get_backend ()->block_statement (code_block); ctx->add_statement (block_stmt); + + translated = ctx->get_backend ()->var_expression (tmp, expr.get_locus ()); } void visit (HIR::StructExprStructFields &struct_expr) diff --git a/gcc/rust/backend/rust-compile-implitem.h b/gcc/rust/backend/rust-compile-implitem.h index fe2abf1..8286a5c 100644 --- a/gcc/rust/backend/rust-compile-implitem.h +++ b/gcc/rust/backend/rust-compile-implitem.h @@ -213,28 +213,8 @@ public: ctx->push_fn (fndecl, return_address); - // compile the block - function_body->iterate_stmts ([&] (HIR::Stmt *s) mutable -> bool { - CompileStmt::Compile (s, ctx); - return true; - }); - - if (function_body->has_expr () && function_body->tail_expr_reachable ()) - { - // the previous passes will ensure this is a valid return - // dead code elimination should remove any bad trailing expressions - Bexpression *compiled_expr - = CompileExpr::Compile (function_body->expr.get (), ctx); - rust_assert (compiled_expr != nullptr); - - auto fncontext = ctx->peek_fn (); - - std::vector<Bexpression *> retstmts; - retstmts.push_back (compiled_expr); - auto s = ctx->get_backend ()->return_statement ( - fncontext.fndecl, retstmts, function_body->expr->get_locus_slow ()); - ctx->add_statement (s); - } + compile_function_body (fndecl, function.function_body, + function.has_function_return_type ()); ctx->pop_block (); auto body = ctx->get_backend ()->block_statement (code_block); diff --git a/gcc/rust/backend/rust-compile-item.h b/gcc/rust/backend/rust-compile-item.h index 83e4451..b08c49e 100644 --- a/gcc/rust/backend/rust-compile-item.h +++ b/gcc/rust/backend/rust-compile-item.h @@ -265,28 +265,8 @@ public: ctx->push_fn (fndecl, return_address); - // compile the block - function_body->iterate_stmts ([&] (HIR::Stmt *s) mutable -> bool { - CompileStmt::Compile (s, ctx); - return true; - }); - - if (function_body->has_expr () && function_body->tail_expr_reachable ()) - { - // the previous passes will ensure this is a valid return - // dead code elimination should remove any bad trailing expressions - Bexpression *compiled_expr - = CompileExpr::Compile (function_body->expr.get (), ctx); - rust_assert (compiled_expr != nullptr); - - auto fncontext = ctx->peek_fn (); - - std::vector<Bexpression *> retstmts; - retstmts.push_back (compiled_expr); - auto s = ctx->get_backend ()->return_statement ( - fncontext.fndecl, retstmts, function_body->expr->get_locus_slow ()); - ctx->add_statement (s); - } + compile_function_body (fndecl, function.function_body, + function.has_function_return_type ()); ctx->pop_block (); auto body = ctx->get_backend ()->block_statement (code_block); @@ -297,7 +277,6 @@ public: } ctx->pop_fn (); - ctx->push_function (fndecl); } diff --git a/gcc/rust/backend/rust-compile-stmt.h b/gcc/rust/backend/rust-compile-stmt.h index c52f605..d021240e4 100644 --- a/gcc/rust/backend/rust-compile-stmt.h +++ b/gcc/rust/backend/rust-compile-stmt.h @@ -29,37 +29,24 @@ namespace Compile { class CompileStmt : public HIRCompileBase { public: - static void Compile (HIR::Stmt *stmt, Context *ctx) + static Bexpression *Compile (HIR::Stmt *stmt, Context *ctx) { CompileStmt compiler (ctx); stmt->accept_vis (compiler); rust_assert (compiler.ok); + return compiler.translated; } - virtual ~CompileStmt () {} - void visit (HIR::ExprStmtWithBlock &stmt) { ok = true; - auto translated = CompileExpr::Compile (stmt.get_expr (), ctx); - - // these can be null - if (translated == nullptr) - return; - - gcc_unreachable (); + translated = CompileExpr::Compile (stmt.get_expr (), ctx); } void visit (HIR::ExprStmtWithoutBlock &stmt) { ok = true; - auto translated = CompileExpr::Compile (stmt.get_expr (), ctx); - - // these can be null - if (translated == nullptr) - return; - - gcc_unreachable (); + translated = CompileExpr::Compile (stmt.get_expr (), ctx); } void visit (HIR::LetStmt &stmt) @@ -99,9 +86,12 @@ public: } private: - CompileStmt (Context *ctx) : HIRCompileBase (ctx), ok (false) {} + CompileStmt (Context *ctx) + : HIRCompileBase (ctx), ok (false), translated (nullptr) + {} bool ok; + Bexpression *translated; }; } // namespace Compile diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc index ce6d827..f72cf4c 100644 --- a/gcc/rust/backend/rust-compile.cc +++ b/gcc/rust/backend/rust-compile.cc @@ -135,10 +135,30 @@ CompileBlock::visit (HIR::BlockExpr &expr) start_location, end_location); ctx->push_block (new_block); - expr.iterate_stmts ([&] (HIR::Stmt *s) mutable -> bool { - CompileStmt::Compile (s, ctx); - return true; - }); + for (auto &s : expr.get_statements ()) + { + auto compiled_expr = CompileStmt::Compile (s.get (), ctx); + if (compiled_expr == nullptr) + continue; + + if (result == nullptr) + { + Bstatement *final_stmt + = ctx->get_backend ()->expression_statement (fnctx.fndecl, + compiled_expr); + ctx->add_statement (final_stmt); + } + else + { + Bexpression *result_reference + = ctx->get_backend ()->var_expression (result, + s->get_locus_slow ()); + + Bstatement *assignment = ctx->get_backend ()->assignment_statement ( + fnctx.fndecl, result_reference, compiled_expr, expr.get_locus ()); + ctx->add_statement (assignment); + } + } if (expr.has_expr () && expr.tail_expr_reachable ()) { @@ -147,14 +167,22 @@ CompileBlock::visit (HIR::BlockExpr &expr) Bexpression *compiled_expr = CompileExpr::Compile (expr.expr.get (), ctx); rust_assert (compiled_expr != nullptr); - auto fncontext = ctx->peek_fn (); + if (result == nullptr) + { + Bstatement *final_stmt + = ctx->get_backend ()->expression_statement (fnctx.fndecl, + compiled_expr); + ctx->add_statement (final_stmt); + } + else + { + Bexpression *result_reference = ctx->get_backend ()->var_expression ( + result, expr.get_final_expr ()->get_locus_slow ()); - std::vector<Bexpression *> retstmts; - retstmts.push_back (compiled_expr); - auto s - = ctx->get_backend ()->return_statement (fncontext.fndecl, retstmts, - expr.expr->get_locus_slow ()); - ctx->add_statement (s); + Bstatement *assignment = ctx->get_backend ()->assignment_statement ( + fnctx.fndecl, result_reference, compiled_expr, expr.get_locus ()); + ctx->add_statement (assignment); + } } ctx->pop_block (); @@ -168,7 +196,8 @@ CompileConditionalBlocks::visit (HIR::IfExpr &expr) Bfunction *fndecl = fnctx.fndecl; Bexpression *condition_expr = CompileExpr::Compile (expr.get_if_condition (), ctx); - Bblock *then_block = CompileBlock::compile (expr.get_if_block (), ctx); + Bblock *then_block + = CompileBlock::compile (expr.get_if_block (), ctx, result); translated = ctx->get_backend ()->if_statement (fndecl, condition_expr, then_block, @@ -182,8 +211,10 @@ CompileConditionalBlocks::visit (HIR::IfExprConseqElse &expr) Bfunction *fndecl = fnctx.fndecl; Bexpression *condition_expr = CompileExpr::Compile (expr.get_if_condition (), ctx); - Bblock *then_block = CompileBlock::compile (expr.get_if_block (), ctx); - Bblock *else_block = CompileBlock::compile (expr.get_else_block (), ctx); + Bblock *then_block + = CompileBlock::compile (expr.get_if_block (), ctx, result); + Bblock *else_block + = CompileBlock::compile (expr.get_else_block (), ctx, result); translated = ctx->get_backend ()->if_statement (fndecl, condition_expr, then_block, @@ -197,7 +228,8 @@ CompileConditionalBlocks::visit (HIR::IfExprConseqIf &expr) Bfunction *fndecl = fnctx.fndecl; Bexpression *condition_expr = CompileExpr::Compile (expr.get_if_condition (), ctx); - Bblock *then_block = CompileBlock::compile (expr.get_if_block (), ctx); + Bblock *then_block + = CompileBlock::compile (expr.get_if_block (), ctx, result); // else block std::vector<Bvariable *> locals; @@ -210,7 +242,8 @@ CompileConditionalBlocks::visit (HIR::IfExprConseqIf &expr) ctx->push_block (else_block); Bstatement *else_stmt_decl - = CompileConditionalBlocks::compile (expr.get_conseq_if_expr (), ctx); + = CompileConditionalBlocks::compile (expr.get_conseq_if_expr (), ctx, + result); ctx->add_statement (else_stmt_decl); ctx->pop_block (); @@ -244,5 +277,64 @@ CompileStructExprField::visit (HIR::StructExprFieldIdentifier &field) translated = CompileExpr::Compile (&expr, ctx); } +// Shared methods in compilation + +void +HIRCompileBase::compile_function_body ( + Bfunction *fndecl, std::unique_ptr<HIR::BlockExpr> &function_body, + bool has_return_type) +{ + for (auto &s : function_body->get_statements ()) + { + auto compiled_expr = CompileStmt::Compile (s.get (), ctx); + if (compiled_expr != nullptr) + { + if (has_return_type) + { + std::vector<Bexpression *> retstmts; + retstmts.push_back (compiled_expr); + + auto ret + = ctx->get_backend ()->return_statement (fndecl, retstmts, + s->get_locus_slow ()); + ctx->add_statement (ret); + } + else + { + Bstatement *final_stmt + = ctx->get_backend ()->expression_statement (fndecl, + compiled_expr); + ctx->add_statement (final_stmt); + } + } + } + + if (function_body->has_expr () && function_body->tail_expr_reachable ()) + { + // the previous passes will ensure this is a valid return + // dead code elimination should remove any bad trailing expressions + Bexpression *compiled_expr + = CompileExpr::Compile (function_body->expr.get (), ctx); + rust_assert (compiled_expr != nullptr); + + if (has_return_type) + { + std::vector<Bexpression *> retstmts; + retstmts.push_back (compiled_expr); + + auto ret = ctx->get_backend ()->return_statement ( + fndecl, retstmts, + function_body->get_final_expr ()->get_locus_slow ()); + ctx->add_statement (ret); + } + else + { + Bstatement *final_stmt + = ctx->get_backend ()->expression_statement (fndecl, compiled_expr); + ctx->add_statement (final_stmt); + } + } +} + } // namespace Compile } // namespace Rust diff --git a/gcc/rust/hir/tree/rust-hir-expr.h b/gcc/rust/hir/tree/rust-hir-expr.h index 69b680d..8f0c206 100644 --- a/gcc/rust/hir/tree/rust-hir-expr.h +++ b/gcc/rust/hir/tree/rust-hir-expr.h @@ -2585,6 +2585,10 @@ public: return statements[statements.size () - 1]->get_locus_slow (); } + std::unique_ptr<ExprWithoutBlock> &get_final_expr () { return expr; } + + std::vector<std::unique_ptr<Stmt> > &get_statements () { return statements; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc b/gcc/rust/typecheck/rust-hir-type-check.cc index 416cd89..681d023 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.cc +++ b/gcc/rust/typecheck/rust-hir-type-check.cc @@ -127,19 +127,12 @@ TypeCheckExpr::visit (HIR::BlockExpr &expr) return true; }); - // tail expression must be checked as part of the caller since - // the result of this is very dependant on what we expect it to be - - // now that the stmts have been resolved we must resolve the block of locals - // and make sure the variables have been resolved - // auto body_mappings = expr.get_mappings (); - // Rib *rib = nullptr; - // if (!resolver->find_name_rib (body_mappings.get_nodeid (), &rib)) - // { - // rust_fatal_error (expr.get_locus (), "failed to lookup locals per - // block"); return; - // } - // TyTyResolver::Resolve (rib, mappings, resolver, context); + if (expr.has_expr ()) + { + delete block_tyty; + + block_tyty = TypeCheckExpr::Resolve (expr.get_final_expr ().get (), true); + } infered = block_tyty->clone (); } diff --git a/gcc/testsuite/rust.test/compilable/block_expr1.rs b/gcc/testsuite/rust.test/compilable/block_expr1.rs new file mode 100644 index 0000000..fe63252 --- /dev/null +++ b/gcc/testsuite/rust.test/compilable/block_expr1.rs @@ -0,0 +1,27 @@ +fn test3(x: i32) -> i32 { + if x > 1 { + 5 + } else { + 0 + } +} + +fn test5(x: i32) -> i32 { + if x > 1 { + if x == 5 { + 7 + } else { + 9 + } + } else { + 0 + } +} + +fn main() { + let call3: i32 = { test3(3) + 2 }; + let call5 = { + let a = test5(5); + a + 1 + }; +} |