mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 22:34:45 +00:00
(llvm) Generate code for tag unions less than 64 bits in size correctly
Previously, we assumed that a union layout always lived on >= 1 64-bit boundary when generating an LLVM type for it. For small tags unions, like `[ Ok i8, Err ]` this need not be the case; indeed, a tag union like that is actually only 2 bits - 1 bit for the "i8" data, and one bit of the tag kind. This led to a discrepancy between what the layout IR and generated LLVM code would assume about the size of tag unions. In the case above, the layout IR would assume the tag data is 2 bits wide, and the tag id is 1 bit into the data. But the LLVM code would generate a type that was 65 bits wide, the first 64 bits being for the "i8" data and the last 1 bit being for the tag kind. Usually, just running the LLVM-emitted code would not present a problem. But it does present a problem when we use the layout IR to inspect the result of LLVM-run code, in particular when we try to look up the tag ID, as the repl does. This patch fixes that issue. Note that this bug did not present itself in `test_gen` previously because the data that most tests check against is stored in the front of the representation. Closes #2149
This commit is contained in:
parent
f314abfed9
commit
5e5eb6dca8
4 changed files with 54 additions and 40 deletions
|
@ -338,14 +338,9 @@ impl<'a> UnionLayout<'a> {
|
|||
|
||||
pub fn tag_id_builtin(&self) -> Builtin<'a> {
|
||||
match self {
|
||||
UnionLayout::NonRecursive(_tags) => {
|
||||
// let union_size = tags.len();
|
||||
// Self::tag_id_builtin_help(union_size)
|
||||
|
||||
// The quicksort-benchmarks version of Quicksort.roc segfaults when
|
||||
// this number is not I64. There must be some dependence on that fact
|
||||
// somewhere in the code, I have not found where that is yet...
|
||||
Builtin::Int(IntWidth::U64)
|
||||
UnionLayout::NonRecursive(tags) => {
|
||||
let union_size = tags.len();
|
||||
Self::tag_id_builtin_help(union_size)
|
||||
}
|
||||
UnionLayout::Recursive(tags) => {
|
||||
let union_size = tags.len();
|
||||
|
@ -445,6 +440,27 @@ impl<'a> UnionLayout<'a> {
|
|||
None
|
||||
};
|
||||
|
||||
self.data_size_and_alignment_help_match(id_data_layout, pointer_size)
|
||||
}
|
||||
|
||||
/// Size of the data before the tag_id, if it exists.
|
||||
/// Returns None if the tag_id is not stored as data in the layout.
|
||||
pub fn data_size_without_tag_id(&self, pointer_size: u32) -> Option<u32> {
|
||||
if !self.stores_tag_id_as_data(pointer_size) {
|
||||
return None;
|
||||
};
|
||||
|
||||
return Some(
|
||||
self.data_size_and_alignment_help_match(None, pointer_size)
|
||||
.0,
|
||||
);
|
||||
}
|
||||
|
||||
fn data_size_and_alignment_help_match(
|
||||
&self,
|
||||
id_data_layout: Option<Layout>,
|
||||
pointer_size: u32,
|
||||
) -> (u32, u32) {
|
||||
match self {
|
||||
Self::NonRecursive(tags) => {
|
||||
Self::data_size_and_alignment_help(tags, id_data_layout, pointer_size)
|
||||
|
@ -788,7 +804,7 @@ impl<'a, 'b> Env<'a, 'b> {
|
|||
}
|
||||
}
|
||||
|
||||
const fn round_up_to_alignment(width: u32, alignment: u32) -> u32 {
|
||||
pub const fn round_up_to_alignment(width: u32, alignment: u32) -> u32 {
|
||||
if alignment != 0 && width % alignment > 0 {
|
||||
width + alignment - (width % alignment)
|
||||
} else {
|
||||
|
@ -934,23 +950,7 @@ impl<'a> Layout<'a> {
|
|||
use UnionLayout::*;
|
||||
|
||||
match variant {
|
||||
NonRecursive(fields) => {
|
||||
let tag_id_builtin = variant.tag_id_builtin();
|
||||
|
||||
fields
|
||||
.iter()
|
||||
.map(|tag_layout| {
|
||||
tag_layout
|
||||
.iter()
|
||||
.map(|field| field.stack_size(pointer_size))
|
||||
.sum::<u32>()
|
||||
})
|
||||
.max()
|
||||
.map(|w| round_up_to_alignment(w, tag_id_builtin.alignment_bytes(pointer_size)))
|
||||
.unwrap_or_default()
|
||||
// the size of the tag_id
|
||||
+ tag_id_builtin.stack_size(pointer_size)
|
||||
}
|
||||
NonRecursive(_) => variant.data_size_and_alignment(pointer_size).0,
|
||||
|
||||
Recursive(_)
|
||||
| NullableWrapped { .. }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue