aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorPhilip Herron <philip.herron@embecosm.com>2021-02-05 16:49:26 +0000
committerPhilip Herron <herron.philip@googlemail.com>2021-02-06 15:17:08 +0000
commit599b04aa7d928a305029d8e8cf5d6f5c5a683da8 (patch)
treed4d464c29ebab1df3ddaa8d9a39383a56e0f1dce /gcc
parentc4be77f7e0f6b35c019940200f94c7a7b30fff84 (diff)
downloadgcc-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.h6
-rw-r--r--gcc/rust/backend/rust-compile-block.h41
-rw-r--r--gcc/rust/backend/rust-compile-context.h5
-rw-r--r--gcc/rust/backend/rust-compile-expr.h52
-rw-r--r--gcc/rust/backend/rust-compile-implitem.h24
-rw-r--r--gcc/rust/backend/rust-compile-item.h25
-rw-r--r--gcc/rust/backend/rust-compile-stmt.h26
-rw-r--r--gcc/rust/backend/rust-compile.cc124
-rw-r--r--gcc/rust/hir/tree/rust-hir-expr.h4
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check.cc19
-rw-r--r--gcc/testsuite/rust.test/compilable/block_expr1.rs27
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
+ };
+}