for referenced values, use allocas instead of phi nodes

This commit is contained in:
Brendan Hansknecht 2024-07-20 19:52:11 -07:00
parent ee7f1e39c7
commit c5a74bdc12
No known key found for this signature in database
GPG key ID: 0EA784685083E75B
3 changed files with 87 additions and 16 deletions

View file

@ -3292,14 +3292,18 @@ pub(crate) fn build_exp_stmt<'a, 'ctx>(
layout_interner.get_repr(param.layout),
);
let phi_type = if layout_interner.is_passed_by_reference(param.layout) {
basic_type.ptr_type(AddressSpace::default()).into()
use crate::llvm::scope::JoinPointArg::*;
let joinpoint_arg = if layout_interner.is_passed_by_reference(param.layout) {
Alloca(create_entry_block_alloca(
env,
basic_type,
"joinpoint_arg_alloca",
))
} else {
basic_type
Phi(env.builder.new_build_phi(basic_type, "joinpointarg"))
};
let phi_node = env.builder.new_build_phi(phi_type, "joinpointarg");
joinpoint_args.push(phi_node);
joinpoint_args.push(joinpoint_arg);
}
builder.position_at_end(current);
@ -3351,14 +3355,30 @@ pub(crate) fn build_exp_stmt<'a, 'ctx>(
Jump(join_point, arguments) => {
let builder = env.builder;
let context = env.context;
let (cont_block, argument_phi_values) = scope.get_join_point(*join_point).unwrap();
let (cont_block, joinpoint_args) = scope.get_join_point(*join_point).unwrap();
let current_block = builder.get_insert_block().unwrap();
for (phi_value, argument) in argument_phi_values.iter().zip(arguments.iter()) {
let (value, _) = scope.load_symbol_and_layout(argument);
for (joinpoint_arg, argument) in joinpoint_args.iter().zip(arguments.iter()) {
let (value, layout) = scope.load_symbol_and_layout(argument);
phi_value.add_incoming(&[(&value, current_block)]);
match joinpoint_arg {
crate::llvm::scope::JoinPointArg::Alloca(alloca) => {
let (size, alignment) = layout_interner.stack_size_and_alignment(layout);
builder
.build_memcpy(
*alloca,
alignment,
value.into_pointer_value(),
alignment,
env.ptr_int().const_int(size as _, false),
)
.unwrap();
}
crate::llvm::scope::JoinPointArg::Phi(phi) => {
phi.add_incoming(&[(&value, current_block)]);
}
}
}
builder.new_build_unconditional_branch(*cont_block);

View file

@ -1,6 +1,6 @@
use inkwell::{
basic_block::BasicBlock,
values::{BasicValueEnum, FunctionValue, PhiValue},
values::{BasicValue, BasicValueEnum, FunctionValue, PhiValue, PointerValue},
};
use roc_collections::ImMap;
use roc_module::symbol::{ModuleId, Symbol};
@ -13,12 +13,18 @@ use roc_mono::{
pub(crate) struct Scope<'a, 'ctx> {
symbols: ImMap<Symbol, (InLayout<'a>, BasicValueEnum<'ctx>)>,
top_level_thunks: ImMap<Symbol, (ProcLayout<'a>, FunctionValue<'ctx>)>,
join_points: ImMap<JoinPointId, (BasicBlock<'ctx>, Vec<PhiValue<'ctx>>)>,
join_points: ImMap<JoinPointId, (BasicBlock<'ctx>, Vec<JoinPointArg<'ctx>>)>,
}
#[derive(Debug)]
pub(crate) struct JoinPointNotFound;
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) enum JoinPointArg<'ctx> {
Alloca(PointerValue<'ctx>),
Phi(PhiValue<'ctx>),
}
impl<'a, 'ctx> Scope<'a, 'ctx> {
pub fn insert(&mut self, symbol: Symbol, layout: InLayout<'a>, value: BasicValueEnum<'ctx>) {
self.symbols.insert(symbol, (layout, value));
@ -62,7 +68,7 @@ impl<'a, 'ctx> Scope<'a, 'ctx> {
&mut self,
join_point_id: JoinPointId,
bb: BasicBlock<'ctx>,
phis: Vec<PhiValue<'ctx>>,
phis: Vec<JoinPointArg<'ctx>>,
) {
self.join_points.insert(join_point_id, (bb, phis));
}
@ -74,7 +80,7 @@ impl<'a, 'ctx> Scope<'a, 'ctx> {
pub fn get_join_point(
&self,
join_point_id: JoinPointId,
) -> Option<&(BasicBlock<'ctx>, Vec<PhiValue<'ctx>>)> {
) -> Option<&(BasicBlock<'ctx>, Vec<JoinPointArg<'ctx>>)> {
self.join_points.get(&join_point_id)
}
@ -89,9 +95,17 @@ impl<'a, 'ctx> Scope<'a, 'ctx> {
.ok_or(JoinPointNotFound)?
.1;
for (phi_value, param) in ref_join_points.iter().zip(parameters.into_iter()) {
let value = phi_value.as_basic_value();
self.symbols.insert(param.symbol, (param.layout, value));
for (joinpoint_arg, param) in ref_join_points.iter().zip(parameters.into_iter()) {
match joinpoint_arg {
crate::llvm::scope::JoinPointArg::Alloca(alloca) => {
self.symbols
.insert(param.symbol, (param.layout, alloca.as_basic_value_enum()));
}
crate::llvm::scope::JoinPointArg::Phi(phi) => {
self.symbols
.insert(param.symbol, (param.layout, phi.as_basic_value()));
}
}
}
Ok(())

View file

@ -4664,3 +4664,40 @@ fn multiple_uses_of_bool_true_tag_union() {
bool
);
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
fn issue_6139() {
assert_evals_to!(
indoc!(
r#"
buggy = \node, seen ->
if List.contains seen node then
seen
else
# node = "B"
nextNode = stepNode node
# node = "C"
buggy nextNode (List.append seen node)
stepNode = \node ->
when node is
"A" -> "B"
"B" -> "C"
"C" -> "D"
"D" -> "A"
_ -> crash ""
buggy "A" []
"#
),
RocList::from_slice(&[
RocStr::from("A"),
RocStr::from("B"),
RocStr::from("C"),
RocStr::from("D"),
]),
RocList<RocStr>
);
}