mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 21:39:07 +00:00
for referenced values, use allocas instead of phi nodes
This commit is contained in:
parent
ee7f1e39c7
commit
c5a74bdc12
3 changed files with 87 additions and 16 deletions
|
@ -3292,14 +3292,18 @@ pub(crate) fn build_exp_stmt<'a, 'ctx>(
|
||||||
layout_interner.get_repr(param.layout),
|
layout_interner.get_repr(param.layout),
|
||||||
);
|
);
|
||||||
|
|
||||||
let phi_type = if layout_interner.is_passed_by_reference(param.layout) {
|
use crate::llvm::scope::JoinPointArg::*;
|
||||||
basic_type.ptr_type(AddressSpace::default()).into()
|
let joinpoint_arg = if layout_interner.is_passed_by_reference(param.layout) {
|
||||||
|
Alloca(create_entry_block_alloca(
|
||||||
|
env,
|
||||||
|
basic_type,
|
||||||
|
"joinpoint_arg_alloca",
|
||||||
|
))
|
||||||
} else {
|
} 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(joinpoint_arg);
|
||||||
joinpoint_args.push(phi_node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.position_at_end(current);
|
builder.position_at_end(current);
|
||||||
|
@ -3351,14 +3355,30 @@ pub(crate) fn build_exp_stmt<'a, 'ctx>(
|
||||||
Jump(join_point, arguments) => {
|
Jump(join_point, arguments) => {
|
||||||
let builder = env.builder;
|
let builder = env.builder;
|
||||||
let context = env.context;
|
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();
|
let current_block = builder.get_insert_block().unwrap();
|
||||||
|
|
||||||
for (phi_value, argument) in argument_phi_values.iter().zip(arguments.iter()) {
|
for (joinpoint_arg, argument) in joinpoint_args.iter().zip(arguments.iter()) {
|
||||||
let (value, _) = scope.load_symbol_and_layout(argument);
|
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);
|
builder.new_build_unconditional_branch(*cont_block);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use inkwell::{
|
use inkwell::{
|
||||||
basic_block::BasicBlock,
|
basic_block::BasicBlock,
|
||||||
values::{BasicValueEnum, FunctionValue, PhiValue},
|
values::{BasicValue, BasicValueEnum, FunctionValue, PhiValue, PointerValue},
|
||||||
};
|
};
|
||||||
use roc_collections::ImMap;
|
use roc_collections::ImMap;
|
||||||
use roc_module::symbol::{ModuleId, Symbol};
|
use roc_module::symbol::{ModuleId, Symbol};
|
||||||
|
@ -13,12 +13,18 @@ use roc_mono::{
|
||||||
pub(crate) struct Scope<'a, 'ctx> {
|
pub(crate) struct Scope<'a, 'ctx> {
|
||||||
symbols: ImMap<Symbol, (InLayout<'a>, BasicValueEnum<'ctx>)>,
|
symbols: ImMap<Symbol, (InLayout<'a>, BasicValueEnum<'ctx>)>,
|
||||||
top_level_thunks: ImMap<Symbol, (ProcLayout<'a>, FunctionValue<'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)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct JoinPointNotFound;
|
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> {
|
impl<'a, 'ctx> Scope<'a, 'ctx> {
|
||||||
pub fn insert(&mut self, symbol: Symbol, layout: InLayout<'a>, value: BasicValueEnum<'ctx>) {
|
pub fn insert(&mut self, symbol: Symbol, layout: InLayout<'a>, value: BasicValueEnum<'ctx>) {
|
||||||
self.symbols.insert(symbol, (layout, value));
|
self.symbols.insert(symbol, (layout, value));
|
||||||
|
@ -62,7 +68,7 @@ impl<'a, 'ctx> Scope<'a, 'ctx> {
|
||||||
&mut self,
|
&mut self,
|
||||||
join_point_id: JoinPointId,
|
join_point_id: JoinPointId,
|
||||||
bb: BasicBlock<'ctx>,
|
bb: BasicBlock<'ctx>,
|
||||||
phis: Vec<PhiValue<'ctx>>,
|
phis: Vec<JoinPointArg<'ctx>>,
|
||||||
) {
|
) {
|
||||||
self.join_points.insert(join_point_id, (bb, phis));
|
self.join_points.insert(join_point_id, (bb, phis));
|
||||||
}
|
}
|
||||||
|
@ -74,7 +80,7 @@ impl<'a, 'ctx> Scope<'a, 'ctx> {
|
||||||
pub fn get_join_point(
|
pub fn get_join_point(
|
||||||
&self,
|
&self,
|
||||||
join_point_id: JoinPointId,
|
join_point_id: JoinPointId,
|
||||||
) -> Option<&(BasicBlock<'ctx>, Vec<PhiValue<'ctx>>)> {
|
) -> Option<&(BasicBlock<'ctx>, Vec<JoinPointArg<'ctx>>)> {
|
||||||
self.join_points.get(&join_point_id)
|
self.join_points.get(&join_point_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,9 +95,17 @@ impl<'a, 'ctx> Scope<'a, 'ctx> {
|
||||||
.ok_or(JoinPointNotFound)?
|
.ok_or(JoinPointNotFound)?
|
||||||
.1;
|
.1;
|
||||||
|
|
||||||
for (phi_value, param) in ref_join_points.iter().zip(parameters.into_iter()) {
|
for (joinpoint_arg, param) in ref_join_points.iter().zip(parameters.into_iter()) {
|
||||||
let value = phi_value.as_basic_value();
|
match joinpoint_arg {
|
||||||
self.symbols.insert(param.symbol, (param.layout, value));
|
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(())
|
Ok(())
|
||||||
|
|
|
@ -4664,3 +4664,40 @@ fn multiple_uses_of_bool_true_tag_union() {
|
||||||
bool
|
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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue