fix let lazy/inline chains re-using the same variable

This commit is contained in:
2022-05-07 18:33:26 +02:00
parent 1e746be750
commit a52fe53a01
2 changed files with 16 additions and 5 deletions

View File

@@ -289,7 +289,7 @@ struct FunctionContext<'a> {
functions: &'a HashMap<String, u32>, functions: &'a HashMap<String, u32>,
locals: &'a ast::Locals, locals: &'a ast::Locals,
labels: Vec<String>, labels: Vec<String>,
let_values: HashMap<u32, (&'a ast::Expression, ast::LetType)>, let_values: HashMap<u32, Vec<(&'a ast::Expression, ast::LetType)>>,
intrinsics: &'a Intrinsics, intrinsics: &'a Intrinsics,
} }
@@ -385,7 +385,10 @@ fn emit_expression<'a>(ctx: &mut FunctionContext<'a>, expr: &'a ast::Expression)
.instruction(&Instruction::LocalSet(local.index.unwrap())); .instruction(&Instruction::LocalSet(local.index.unwrap()));
} }
ast::LetType::Lazy | ast::LetType::Inline => { ast::LetType::Lazy | ast::LetType::Inline => {
ctx.let_values.insert(local_id.unwrap(), (value, *let_type)); ctx.let_values
.entry(local_id.unwrap())
.or_default()
.push((value, *let_type));
} }
} }
} }
@@ -612,17 +615,17 @@ fn emit_expression<'a>(ctx: &mut FunctionContext<'a>, expr: &'a ast::Expression)
} }
ast::Expr::Variable { name, local_id } => { ast::Expr::Variable { name, local_id } => {
if let &Some(id) = local_id { if let &Some(id) = local_id {
if let Some((expr, let_type)) = ctx.let_values.get(&id) { if let Some((expr, let_type)) = ctx.let_values.get_mut(&id).and_then(|s| s.pop()) {
match let_type { match let_type {
ast::LetType::Lazy => { ast::LetType::Lazy => {
let expr = ctx.let_values.remove(&id).unwrap().0;
emit_expression(ctx, expr); emit_expression(ctx, expr);
ctx.let_values.get_mut(&id).unwrap().clear();
ctx.function ctx.function
.instruction(&Instruction::LocalTee(ctx.locals[id].index.unwrap())); .instruction(&Instruction::LocalTee(ctx.locals[id].index.unwrap()));
} }
ast::LetType::Inline => { ast::LetType::Inline => {
let expr = *expr;
emit_expression(ctx, expr); emit_expression(ctx, expr);
ctx.let_values.get_mut(&id).unwrap().push((expr, let_type));
} }
_ => unreachable!(), _ => unreachable!(),
} }

8
test/xorshift.cwa Normal file
View File

@@ -0,0 +1,8 @@
// simple test to see whether lazy/inline chains with the same variable compile correctly
fn xorshift(x: i32) -> i32 {
let lazy x = x ^ (x << 13);
let lazy x = x ^ (x #>> 17);
let inline x = x ^ (x << 5);
x
}