fix ternary if (#250)
Use store and load to handle if expression as the blocks might be changed when generating sub-expressions. Reviewed-on: #250 Co-authored-by: ychenfo <yc@m-labs.hk> Co-committed-by: ychenfo <yc@m-labs.hk>
This commit is contained in:
parent
94eebde4ea
commit
1f5826d352
|
@ -1226,21 +1226,44 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx, generator)?
|
.to_basic_value_enum(ctx, generator)?
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
|
let body_ty = body.custom.unwrap();
|
||||||
|
let is_none = ctx.unifier.get_representative(body_ty) == ctx.primitives.none;
|
||||||
|
let result = if !is_none {
|
||||||
|
let llvm_ty = ctx.get_llvm_type(generator, body_ty);
|
||||||
|
Some(ctx.builder.build_alloca(llvm_ty, "if_exp_result"))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
||||||
let then_bb = ctx.ctx.append_basic_block(current, "then");
|
let then_bb = ctx.ctx.append_basic_block(current, "then");
|
||||||
let else_bb = ctx.ctx.append_basic_block(current, "else");
|
let else_bb = ctx.ctx.append_basic_block(current, "else");
|
||||||
let cont_bb = ctx.ctx.append_basic_block(current, "cont");
|
let cont_bb = ctx.ctx.append_basic_block(current, "cont");
|
||||||
ctx.builder.build_conditional_branch(test, then_bb, else_bb);
|
ctx.builder.build_conditional_branch(test, then_bb, else_bb);
|
||||||
ctx.builder.position_at_end(then_bb);
|
ctx.builder.position_at_end(then_bb);
|
||||||
let a = generator.gen_expr(ctx, body)?.unwrap().to_basic_value_enum(ctx, generator)?;
|
let a = generator.gen_expr(ctx, body)?;
|
||||||
|
match result {
|
||||||
|
None => None,
|
||||||
|
Some(v) => {
|
||||||
|
let a = a.unwrap().to_basic_value_enum(ctx, generator)?;
|
||||||
|
Some(ctx.builder.build_store(v, a))
|
||||||
|
}
|
||||||
|
};
|
||||||
ctx.builder.build_unconditional_branch(cont_bb);
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
ctx.builder.position_at_end(else_bb);
|
ctx.builder.position_at_end(else_bb);
|
||||||
let b = generator.gen_expr(ctx, orelse)?.unwrap().to_basic_value_enum(ctx, generator)?;
|
let b = generator.gen_expr(ctx, orelse)?;
|
||||||
|
match result {
|
||||||
|
None => None,
|
||||||
|
Some(v) => {
|
||||||
|
let b = b.unwrap().to_basic_value_enum(ctx, generator)?;
|
||||||
|
Some(ctx.builder.build_store(v, b))
|
||||||
|
}
|
||||||
|
};
|
||||||
ctx.builder.build_unconditional_branch(cont_bb);
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
ctx.builder.position_at_end(cont_bb);
|
ctx.builder.position_at_end(cont_bb);
|
||||||
let phi = ctx.builder.build_phi(a.get_type(), "ifexpr");
|
match result {
|
||||||
phi.add_incoming(&[(&a, then_bb), (&b, else_bb)]);
|
None => return Ok(None),
|
||||||
phi.as_basic_value().into()
|
Some(v) => return Ok(Some(ctx.builder.build_load(v, "if_exp_val_load").into()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ExprKind::Call { func, args, keywords } => {
|
ExprKind::Call { func, args, keywords } => {
|
||||||
let mut params = args
|
let mut params = args
|
||||||
|
|
|
@ -185,8 +185,17 @@ fn test_primitives() {
|
||||||
init:
|
init:
|
||||||
%add = add i32 %0, %1
|
%add = add i32 %0, %1
|
||||||
%cmp = icmp eq i32 %add, 1
|
%cmp = icmp eq i32 %add, 1
|
||||||
%ifexpr = select i1 %cmp, i32 %0, i32 0
|
br i1 %cmp, label %then, label %else
|
||||||
ret i32 %ifexpr
|
|
||||||
|
then: ; preds = %init
|
||||||
|
br label %cont
|
||||||
|
|
||||||
|
else: ; preds = %init
|
||||||
|
br label %cont
|
||||||
|
|
||||||
|
cont: ; preds = %else, %then
|
||||||
|
%if_exp_result.0 = phi i32 [ %0, %then ], [ 0, %else ]
|
||||||
|
ret i32 %if_exp_result.0
|
||||||
}
|
}
|
||||||
"}
|
"}
|
||||||
.trim();
|
.trim();
|
||||||
|
|
Loading…
Reference in New Issue