aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Herron <philip.herron@embecosm.com>2021-02-10 17:51:58 +0000
committerPhilip Herron <herron.philip@googlemail.com>2021-02-10 18:10:57 +0000
commit0c7d0135663b6f0d94e0ffd931366ba2b32f8b2c (patch)
tree5955326e3e944c45de7a96eb989adb2cd7c4538a
parentd02ab5925b612678beb975d99951b1d2052958a1 (diff)
downloadgcc-0c7d0135663b6f0d94e0ffd931366ba2b32f8b2c.zip
gcc-0c7d0135663b6f0d94e0ffd931366ba2b32f8b2c.tar.gz
gcc-0c7d0135663b6f0d94e0ffd931366ba2b32f8b2c.tar.bz2
Add support to break from loops with a value
This adds support to make the break value assignable such that the loop now becomes akin to a BlockExpr Fixes #108 #106
-rw-r--r--gcc/rust/backend/rust-compile-context.h12
-rw-r--r--gcc/rust/backend/rust-compile-expr.h46
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-expr.h28
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check.h23
-rw-r--r--gcc/testsuite/rust.test/compilable/loop5.rs14
5 files changed, 119 insertions, 4 deletions
diff --git a/gcc/rust/backend/rust-compile-context.h b/gcc/rust/backend/rust-compile-context.h
index 8a74a05..288b917 100644
--- a/gcc/rust/backend/rust-compile-context.h
+++ b/gcc/rust/backend/rust-compile-context.h
@@ -208,6 +208,17 @@ public:
return false;
}
+ void push_loop_context (Bvariable *var) { loop_value_stack.push_back (var); }
+
+ Bvariable *peek_loop_context () { return loop_value_stack.back (); }
+
+ Bvariable *pop_loop_context ()
+ {
+ auto back = loop_value_stack.back ();
+ loop_value_stack.pop_back ();
+ return back;
+ }
+
private:
::Backend *backend;
Resolver::Resolver *resolver;
@@ -223,6 +234,7 @@ private:
std::map<HirId, ::Blabel *> compiled_labels;
std::vector< ::std::vector<Bstatement *> > statements;
std::vector< ::Bblock *> scope_stack;
+ std::vector< ::Bvariable *> loop_value_stack;
// To GCC middle-end
std::vector< ::Btype *> type_decls;
diff --git a/gcc/rust/backend/rust-compile-expr.h b/gcc/rust/backend/rust-compile-expr.h
index 189118b..7b25c5e 100644
--- a/gcc/rust/backend/rust-compile-expr.h
+++ b/gcc/rust/backend/rust-compile-expr.h
@@ -586,7 +586,31 @@ public:
void visit (HIR::LoopExpr &expr)
{
+ 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 ();
+ Bvariable *tmp = NULL;
+ bool needs_temp = block_tyty->get_kind () != TyTy::TypeKind::UNIT;
+ if (needs_temp)
+ {
+ 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;
+ 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);
+ ctx->push_loop_context (tmp);
+ }
+
if (expr.has_loop_label ())
{
HIR::LoopLabel &loop_label = expr.get_loop_label ();
@@ -608,10 +632,32 @@ public:
Bstatement *loop_stmt
= ctx->get_backend ()->expression_statement (fnctx.fndecl, loop_expr);
ctx->add_statement (loop_stmt);
+
+ if (tmp != NULL)
+ {
+ ctx->pop_loop_context ();
+ translated
+ = ctx->get_backend ()->var_expression (tmp, expr.get_locus ());
+ }
}
void visit (HIR::BreakExpr &expr)
{
+ if (expr.has_break_expr ())
+ {
+ fncontext fnctx = ctx->peek_fn ();
+ Bexpression *compiled_expr
+ = CompileExpr::Compile (expr.get_expr ().get (), ctx);
+
+ Bvariable *loop_result_holder = ctx->peek_loop_context ();
+ Bexpression *result_reference = ctx->get_backend ()->var_expression (
+ loop_result_holder, expr.get_expr ()->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_label ())
{
NodeId resolved_node_id = UNKNOWN_NODEID;
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h
index 6a45fef..87aeae6 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h
@@ -757,7 +757,19 @@ public:
void visit (HIR::LoopExpr &expr)
{
- infered = TypeCheckExpr::Resolve (expr.get_loop_block ().get (), true);
+ context->push_new_loop_context (expr.get_mappings ().get_hirid ());
+ TypeCheckExpr::Resolve (expr.get_loop_block ().get (), true);
+ TyTy::TyBase *loop_context_type = context->pop_loop_context ();
+
+ bool loop_context_type_infered
+ = (loop_context_type->get_kind () != TyTy::TypeKind::INFER)
+ || ((loop_context_type->get_kind () == TyTy::TypeKind::INFER)
+ && (((TyTy::InferType *) loop_context_type)->get_infer_kind ()
+ != TyTy::InferType::GENERAL));
+
+ infered = loop_context_type_infered
+ ? loop_context_type
+ : new TyTy::UnitType (expr.get_mappings ().get_hirid ());
}
void visit (HIR::BreakExpr &expr)
@@ -768,9 +780,17 @@ public:
return;
}
- infered = expr.has_break_expr ()
- ? TypeCheckExpr::Resolve (expr.get_expr ().get (), false)
- : new TyTy::UnitType (expr.get_mappings ().get_hirid ());
+ if (expr.has_break_expr ())
+ {
+ TyTy::TyBase *break_expr_tyty
+ = TypeCheckExpr::Resolve (expr.get_expr ().get (), false);
+
+ TyTy::TyBase *loop_context = context->peek_loop_context ();
+ TyTy::TyBase *combined = loop_context->combine (break_expr_tyty);
+ context->swap_head_loop_context (combined);
+ }
+
+ infered = new TyTy::UnitType (expr.get_mappings ().get_hirid ());
}
private:
diff --git a/gcc/rust/typecheck/rust-hir-type-check.h b/gcc/rust/typecheck/rust-hir-type-check.h
index d033878..531d241 100644
--- a/gcc/rust/typecheck/rust-hir-type-check.h
+++ b/gcc/rust/typecheck/rust-hir-type-check.h
@@ -56,6 +56,28 @@ public:
}
}
+ void push_new_loop_context (HirId id)
+ {
+ TyTy::TyBase *infer_var
+ = new TyTy::InferType (id, TyTy::InferType::InferTypeKind::GENERAL);
+ loop_type_stack.push_back (infer_var);
+ }
+
+ TyTy::TyBase *peek_loop_context () { return loop_type_stack.back (); }
+
+ TyTy::TyBase *pop_loop_context ()
+ {
+ auto back = peek_loop_context ();
+ loop_type_stack.pop_back ();
+ return back;
+ }
+
+ void swap_head_loop_context (TyTy::TyBase *val)
+ {
+ loop_type_stack.pop_back ();
+ loop_type_stack.push_back (val);
+ }
+
private:
TypeCheckContext ();
@@ -63,6 +85,7 @@ private:
std::map<HirId, TyTy::TyBase *> resolved;
std::vector<std::unique_ptr<TyTy::TyBase> > builtins;
std::vector<TyTy::TyBase *> return_type_stack;
+ std::vector<TyTy::TyBase *> loop_type_stack;
};
class TypeResolution
diff --git a/gcc/testsuite/rust.test/compilable/loop5.rs b/gcc/testsuite/rust.test/compilable/loop5.rs
new file mode 100644
index 0000000..4004cd3
--- /dev/null
+++ b/gcc/testsuite/rust.test/compilable/loop5.rs
@@ -0,0 +1,14 @@
+fn main() {
+ let mut a = 1;
+ let mut b = 1;
+
+ // first number in Fibonacci sequence over 10:
+ let _fib = loop {
+ if b > 10 {
+ break b;
+ }
+ let c = a + b;
+ a = b;
+ b = c;
+ };
+}