tagged unions
This commit is contained in:
+36
-4
@@ -711,9 +711,27 @@ emit_instruction_stream :: proc(
|
||||
}
|
||||
fmt.sbprintf(&emitter.builder, " %%union_slot%d = alloca %s, align %d\n", instruction_index, type_name, types.alignment_of(instruction.type, &emitter.module.types, emitter.module.target))
|
||||
fmt.sbprintf(&emitter.builder, " store %s zeroinitializer, ptr %%union_slot%d\n", type_name, instruction_index)
|
||||
// A tagged union writes the discriminant (the tag enum member matching the
|
||||
// active variant's name) at offset 0, then the payload after it; untagged
|
||||
// unions write the payload at offset 0.
|
||||
payload_ptr := fmt.tprintf("%%union_slot%d", instruction_index)
|
||||
tag_enum := types.union_tag_enum(instruction.type, &emitter.module.types)
|
||||
if types.is_valid(tag_enum) {
|
||||
tag_value: i128 = 0
|
||||
for member in types.enum_members_for(&emitter.module.types, tag_enum) {
|
||||
if member.name == fields[field_index].name {
|
||||
tag_value = member.value
|
||||
break
|
||||
}
|
||||
}
|
||||
fmt.sbprintf(&emitter.builder, " store %s %d, ptr %%union_slot%d\n", llvm_type(tag_enum, &emitter.module.types), tag_value, instruction_index)
|
||||
offset := types.union_payload_offset(instruction.type, &emitter.module.types, emitter.module.target)
|
||||
fmt.sbprintf(&emitter.builder, " %%union_payload%d = getelementptr i8, ptr %%union_slot%d, i64 %d\n", instruction_index, instruction_index, offset)
|
||||
payload_ptr = fmt.tprintf("%%union_payload%d", instruction_index)
|
||||
}
|
||||
fmt.sbprintf(&emitter.builder, " store %s ", llvm_type(fields[field_index].type, &emitter.module.types))
|
||||
write_operand(&emitter.builder, instructions, instruction.args[0], fields[field_index].type, &emitter.module.types)
|
||||
fmt.sbprintf(&emitter.builder, ", ptr %%union_slot%d\n", instruction_index)
|
||||
fmt.sbprintf(&emitter.builder, ", ptr %s\n", payload_ptr)
|
||||
fmt.sbprintf(&emitter.builder, " %%v%d = load %s, ptr %%union_slot%d\n", instruction_index, type_name, instruction_index)
|
||||
continue
|
||||
}
|
||||
@@ -941,7 +959,7 @@ emit_instruction_stream :: proc(
|
||||
continue
|
||||
}
|
||||
if types.is_union(base_type, &emitter.module.types) {
|
||||
fmt.sbprintf(&emitter.builder, " %%v%d = getelementptr i8, ptr %%v%d, i64 0\n", instruction_index, instruction.a)
|
||||
fmt.sbprintf(&emitter.builder, " %%v%d = getelementptr i8, ptr %%v%d, i64 %d\n", instruction_index, instruction.a, types.union_payload_offset(base_type, &emitter.module.types, emitter.module.target))
|
||||
} else {
|
||||
fmt.sbprintf(
|
||||
&emitter.builder,
|
||||
@@ -1804,10 +1822,24 @@ emit_types :: proc(emitter: ^Emitter) {
|
||||
fmt.sbprintf(&emitter.builder, "[%d x i8]\n", total_size)
|
||||
continue
|
||||
}
|
||||
// A tagged union lays out `{ tag, [pad], carrier, [pad] }`; the explicit i8
|
||||
// padding makes the LLVM type's size and field offsets match the byte offsets
|
||||
// used by construction and field access. Untagged unions have offset 0 and no tag.
|
||||
payload_offset := types.union_payload_offset(id, &emitter.module.types, emitter.module.target)
|
||||
strings.write_string(&emitter.builder, "{ ")
|
||||
if types.is_tagged_union(id, &emitter.module.types) {
|
||||
tag_type := types.union_tag_enum(id, &emitter.module.types)
|
||||
tag_size := types.size(tag_type, &emitter.module.types, emitter.module.target)
|
||||
strings.write_string(&emitter.builder, llvm_type(tag_type, &emitter.module.types))
|
||||
if payload_offset > tag_size {
|
||||
fmt.sbprintf(&emitter.builder, ", [%d x i8]", payload_offset-tag_size)
|
||||
}
|
||||
strings.write_string(&emitter.builder, ", ")
|
||||
}
|
||||
strings.write_string(&emitter.builder, llvm_type(carrier, &emitter.module.types))
|
||||
if carrier_size < total_size {
|
||||
fmt.sbprintf(&emitter.builder, ", [%d x i8]", total_size-carrier_size)
|
||||
used := payload_offset + carrier_size
|
||||
if used < total_size {
|
||||
fmt.sbprintf(&emitter.builder, ", [%d x i8]", total_size-used)
|
||||
}
|
||||
strings.write_string(&emitter.builder, " }\n")
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user