-
-
Notifications
You must be signed in to change notification settings - Fork 312
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tail Recursion Modulo Cons for record payloads #6071
base: main
Are you sure you want to change the base?
Changes from all commits
a0e0d1f
c182ad5
3a2f974
f7c905d
c15c7a3
032a943
4514060
9f69250
b735363
e7ce8c4
3de6775
607ffc0
d234adb
ecb3bc9
307dc13
becd2a1
3f828b6
df6d0e8
16133b4
7597cee
64ff005
91714d2
48d8c26
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3434,25 +3434,27 @@ impl< | |
&mut self, | ||
sym: &Symbol, | ||
structure: &Symbol, | ||
tag_id: TagIdIntType, | ||
index: u64, | ||
indices: &[u64], | ||
union_layout: &UnionLayout<'a>, | ||
) { | ||
let tag_id = indices[0] as TagIdIntType; | ||
let ptr_reg = self | ||
.storage_manager | ||
.load_to_general_reg(&mut self.buf, structure); | ||
|
||
let sym_reg = self.storage_manager.claim_general_reg(&mut self.buf, sym); | ||
|
||
let indices = &indices[1..]; | ||
match union_layout { | ||
UnionLayout::NonRecursive(_) => { | ||
unreachable!("operation not supported") | ||
} | ||
UnionLayout::NonNullableUnwrapped(field_layouts) => { | ||
let mut offset = 0; | ||
for field in &field_layouts[..index as usize] { | ||
offset += self.layout_interner.stack_size(*field); | ||
} | ||
let offset = load_union_field_ptr_at_index_help( | ||
self.layout_interner, | ||
indices, | ||
field_layouts, | ||
0, | ||
); | ||
|
||
ASM::add_reg64_reg64_imm32(&mut self.buf, sym_reg, ptr_reg, offset as i32); | ||
} | ||
|
@@ -3462,10 +3464,12 @@ impl< | |
} => { | ||
debug_assert_ne!(tag_id, *nullable_id as TagIdIntType); | ||
|
||
let mut offset = 0; | ||
for field in &other_fields[..index as usize] { | ||
offset += self.layout_interner.stack_size(*field); | ||
} | ||
let offset = load_union_field_ptr_at_index_help( | ||
self.layout_interner, | ||
indices, | ||
other_fields, | ||
0, | ||
); | ||
|
||
ASM::add_reg64_reg64_imm32(&mut self.buf, sym_reg, ptr_reg, offset as i32); | ||
} | ||
|
@@ -3484,10 +3488,12 @@ impl< | |
|
||
let (mask_symbol, mask_reg) = self.clear_tag_id(ptr_reg); | ||
|
||
let mut offset = 0; | ||
for field in &other_fields[..index as usize] { | ||
offset += self.layout_interner.stack_size(*field); | ||
} | ||
let offset = load_union_field_ptr_at_index_help( | ||
self.layout_interner, | ||
indices, | ||
other_fields, | ||
0, | ||
); | ||
|
||
ASM::add_reg64_reg64_imm32(&mut self.buf, sym_reg, mask_reg, offset as i32); | ||
|
||
|
@@ -3509,10 +3515,12 @@ impl< | |
(Some(mask_symbol), mask_reg) | ||
}; | ||
|
||
let mut offset = 0; | ||
for field in &other_fields[..index as usize] { | ||
offset += self.layout_interner.stack_size(*field); | ||
} | ||
let offset = load_union_field_ptr_at_index_help( | ||
self.layout_interner, | ||
indices, | ||
other_fields, | ||
0, | ||
); | ||
|
||
ASM::add_reg64_reg64_imm32(&mut self.buf, sym_reg, unmasked_reg, offset as i32); | ||
|
||
|
@@ -5367,6 +5375,46 @@ impl< | |
} | ||
} | ||
|
||
fn load_union_field_ptr_at_index_help<'a>( | ||
layout_interner: &'a STLayoutInterner<'a>, | ||
indices: &[u64], | ||
layouts: &[InLayout<'a>], | ||
mut offset: u32, | ||
) -> u32 { | ||
debug_assert_ne!(indices.len(), 0); | ||
|
||
let idx = indices[0]; | ||
for field in &layouts[..idx as usize] { | ||
offset += layout_interner.stack_size(*field); | ||
} | ||
|
||
if indices.len() <= 1 { | ||
return offset; | ||
} | ||
use LayoutRepr::*; | ||
let enclosing_layout = layouts[idx as usize]; | ||
return match layout_interner.get_repr(enclosing_layout) { | ||
Struct(layouts) => { | ||
load_union_field_ptr_at_index_help(layout_interner, &indices[1..], layouts, offset) | ||
}, | ||
Union(UnionLayout::NonRecursive(tags)) => { | ||
// apart from the current index, to get information out of a | ||
// non-recursive tag union we need 2 more number: a tag id and an index | ||
debug_assert!(indices.len() >= 3); | ||
let tag_id = indices[1] as usize; | ||
let tag_layout = tags[tag_id]; | ||
|
||
load_union_field_ptr_at_index_help(layout_interner, &indices[2..], tag_layout, offset) | ||
} | ||
//TODO: can any of these be a valid target for getting a pointer out of their inner layouts? | ||
//(so not them being pointers) | ||
Union(_) | Builtin(_) | Ptr(_) | RecursivePointer(_) | LambdaSet(_) | FunctionPointer(_) | ||
| Erased(_) => unreachable!( | ||
"Following the path of the indices, a layout has been reached where the address of the desired pointer is behind another pointer" | ||
), | ||
Comment on lines
+5409
to
+5414
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. lambda set probably could (it should just recurse on its inner type). Also the error message is not correct for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the lambda set case, I believe the access path should be at most 1 right? Since I believe we will never explicitly TR-optimize a lambda set. If so, let's add a debug assertion for the size of the |
||
}; | ||
} | ||
|
||
#[macro_export] | ||
macro_rules! sign_extended_int_builtins { | ||
() => { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't need to happen now, but it would be nice if we could transform this into a loop instead of performing recursive calls. I think it would also simplify the logic. Something like