mirror of
https://github.com/ziglang/zig.git
synced 2024-11-30 17:12:31 +00:00
IR: fix switching on enum
This commit is contained in:
parent
12fcbecbf8
commit
c64f9991d5
@ -1420,12 +1420,12 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa
|
||||
static LLVMValueRef ir_render_enum_field_ptr(CodeGen *g, IrExecutable *executable,
|
||||
IrInstructionEnumFieldPtr *instruction)
|
||||
{
|
||||
LLVMValueRef enum_ptr = ir_llvm_value(g, instruction->enum_ptr);
|
||||
TypeEnumField *field = instruction->field;
|
||||
|
||||
if (!type_has_bits(field->type_entry))
|
||||
return nullptr;
|
||||
|
||||
LLVMValueRef enum_ptr = ir_llvm_value(g, instruction->enum_ptr);
|
||||
LLVMTypeRef field_type_ref = LLVMPointerType(field->type_entry->type_ref, 0);
|
||||
LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, enum_ptr, enum_gen_union_index, "");
|
||||
LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, "");
|
||||
@ -2140,6 +2140,20 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa
|
||||
return instruction->tmp_ptr;
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_render_enum_tag(CodeGen *g, IrExecutable *executable, IrInstructionEnumTag *instruction) {
|
||||
TypeTableEntry *enum_type = instruction->value->type_entry;
|
||||
TypeTableEntry *tag_type = enum_type->data.enumeration.tag_type;
|
||||
if (!type_has_bits(tag_type))
|
||||
return nullptr;
|
||||
|
||||
LLVMValueRef enum_val = ir_llvm_value(g, instruction->value);
|
||||
if (enum_type->data.enumeration.gen_field_count == 0)
|
||||
return enum_val;
|
||||
|
||||
LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, enum_val, enum_gen_tag_index, "");
|
||||
return get_handle_value(g, tag_field_ptr, tag_type);
|
||||
}
|
||||
|
||||
static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
|
||||
AstNode *source_node = instruction->source_node;
|
||||
Scope *scope = instruction->scope;
|
||||
@ -2271,10 +2285,11 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
|
||||
return ir_render_err_wrap_code(g, executable, (IrInstructionErrWrapCode *)instruction);
|
||||
case IrInstructionIdErrWrapPayload:
|
||||
return ir_render_err_wrap_payload(g, executable, (IrInstructionErrWrapPayload *)instruction);
|
||||
case IrInstructionIdEnumTag:
|
||||
return ir_render_enum_tag(g, executable, (IrInstructionEnumTag *)instruction);
|
||||
case IrInstructionIdSwitchVar:
|
||||
case IrInstructionIdContainerInitList:
|
||||
case IrInstructionIdStructInit:
|
||||
case IrInstructionIdEnumTag:
|
||||
zig_panic("TODO render more IR instructions to LLVM");
|
||||
}
|
||||
zig_unreachable();
|
||||
@ -3240,7 +3255,7 @@ static void define_builtin_types(CodeGen *g) {
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
|
||||
entry->zero_bits = true; // only allowed at compile time
|
||||
buf_init_from_str(&entry->name, "@OS");
|
||||
buf_init_from_str(&entry->name, "Os");
|
||||
uint32_t field_count = target_os_count();
|
||||
entry->data.enumeration.src_field_count = field_count;
|
||||
entry->data.enumeration.fields = allocate<TypeEnumField>(field_count);
|
||||
@ -3249,6 +3264,7 @@ static void define_builtin_types(CodeGen *g) {
|
||||
ZigLLVM_OSType os_type = get_target_os(i);
|
||||
type_enum_field->name = buf_create_from_str(get_target_os_name(os_type));
|
||||
type_enum_field->value = i;
|
||||
type_enum_field->type_entry = g->builtin_types.entry_void;
|
||||
|
||||
if (os_type == g->zig_target.os) {
|
||||
g->target_os_index = i;
|
||||
@ -3260,12 +3276,13 @@ static void define_builtin_types(CodeGen *g) {
|
||||
entry->data.enumeration.tag_type = tag_type_entry;
|
||||
|
||||
g->builtin_types.entry_os_enum = entry;
|
||||
g->primitive_type_table.put(&entry->name, entry);
|
||||
}
|
||||
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
|
||||
entry->zero_bits = true; // only allowed at compile time
|
||||
buf_init_from_str(&entry->name, "@Arch");
|
||||
buf_init_from_str(&entry->name, "Arch");
|
||||
uint32_t field_count = target_arch_count();
|
||||
entry->data.enumeration.src_field_count = field_count;
|
||||
entry->data.enumeration.fields = allocate<TypeEnumField>(field_count);
|
||||
@ -3278,6 +3295,7 @@ static void define_builtin_types(CodeGen *g) {
|
||||
buf_resize(type_enum_field->name, strlen(buf_ptr(type_enum_field->name)));
|
||||
|
||||
type_enum_field->value = i;
|
||||
type_enum_field->type_entry = g->builtin_types.entry_void;
|
||||
|
||||
if (arch_type->arch == g->zig_target.arch.arch &&
|
||||
arch_type->sub_arch == g->zig_target.arch.sub_arch)
|
||||
@ -3291,12 +3309,13 @@ static void define_builtin_types(CodeGen *g) {
|
||||
entry->data.enumeration.tag_type = tag_type_entry;
|
||||
|
||||
g->builtin_types.entry_arch_enum = entry;
|
||||
g->primitive_type_table.put(&entry->name, entry);
|
||||
}
|
||||
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
|
||||
entry->zero_bits = true; // only allowed at compile time
|
||||
buf_init_from_str(&entry->name, "@Environ");
|
||||
buf_init_from_str(&entry->name, "Environ");
|
||||
uint32_t field_count = target_environ_count();
|
||||
entry->data.enumeration.src_field_count = field_count;
|
||||
entry->data.enumeration.fields = allocate<TypeEnumField>(field_count);
|
||||
@ -3317,12 +3336,13 @@ static void define_builtin_types(CodeGen *g) {
|
||||
entry->data.enumeration.tag_type = tag_type_entry;
|
||||
|
||||
g->builtin_types.entry_environ_enum = entry;
|
||||
g->primitive_type_table.put(&entry->name, entry);
|
||||
}
|
||||
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
|
||||
entry->zero_bits = true; // only allowed at compile time
|
||||
buf_init_from_str(&entry->name, "@ObjectFormat");
|
||||
buf_init_from_str(&entry->name, "ObjectFormat");
|
||||
uint32_t field_count = target_oformat_count();
|
||||
entry->data.enumeration.src_field_count = field_count;
|
||||
entry->data.enumeration.fields = allocate<TypeEnumField>(field_count);
|
||||
@ -3343,6 +3363,7 @@ static void define_builtin_types(CodeGen *g) {
|
||||
entry->data.enumeration.tag_type = tag_type_entry;
|
||||
|
||||
g->builtin_types.entry_oformat_enum = entry;
|
||||
g->primitive_type_table.put(&entry->name, entry);
|
||||
}
|
||||
|
||||
{
|
||||
|
53
src/ir.cpp
53
src/ir.cpp
@ -5690,8 +5690,10 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
|
||||
var_type = decl_var_instruction->var_type->other;
|
||||
TypeTableEntry *proposed_type = ir_resolve_type(ira, var_type);
|
||||
explicit_type = validate_var_type(ira->codegen, var_type->source_node, proposed_type);
|
||||
if (explicit_type->id == TypeTableEntryIdInvalid)
|
||||
return explicit_type;
|
||||
if (explicit_type->id == TypeTableEntryIdInvalid) {
|
||||
var->type = ira->codegen->builtin_types.entry_invalid;
|
||||
return var->type;
|
||||
}
|
||||
}
|
||||
|
||||
AstNode *source_node = decl_var_instruction->base.source_node;
|
||||
@ -7596,6 +7598,33 @@ static TypeTableEntry *ir_analyze_instruction_clz(IrAnalyze *ira, IrInstructionC
|
||||
}
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_enum_tag(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value) {
|
||||
if (value->type_entry->id == TypeTableEntryIdInvalid)
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
if (value->type_entry->id != TypeTableEntryIdEnum) {
|
||||
ir_add_error(ira, source_instr,
|
||||
buf_sprintf("expected enum type, found '%s'", buf_ptr(&value->type_entry->name)));
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
if (instr_is_comptime(value)) {
|
||||
ConstExprValue *val = ir_resolve_const(ira, value);
|
||||
if (!val)
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(ira->new_irb.exec,
|
||||
source_instr->scope, source_instr->source_node);
|
||||
const_instruction->base.type_entry = value->type_entry->data.enumeration.tag_type;
|
||||
const_instruction->base.static_value.special = ConstValSpecialStatic;
|
||||
const_instruction->base.static_value.depends_on_compile_var = val->depends_on_compile_var;
|
||||
bignum_init_unsigned(&const_instruction->base.static_value.data.x_bignum, val->data.x_enum.tag);
|
||||
return &const_instruction->base;
|
||||
}
|
||||
|
||||
zig_panic("TODO runtime enum tag instruction");
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira,
|
||||
IrInstructionSwitchBr *switch_br_instruction)
|
||||
{
|
||||
@ -7651,6 +7680,12 @@ static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira,
|
||||
if (new_value->type_entry->id == TypeTableEntryIdInvalid)
|
||||
continue;
|
||||
|
||||
if (new_value->type_entry->id == TypeTableEntryIdEnum) {
|
||||
new_value = ir_analyze_enum_tag(ira, &switch_br_instruction->base, new_value);
|
||||
if (new_value->type_entry->id == TypeTableEntryIdInvalid)
|
||||
continue;
|
||||
}
|
||||
|
||||
IrInstruction *casted_new_value = ir_implicit_cast(ira, new_value, target_value->type_entry);
|
||||
if (casted_new_value->type_entry->id == TypeTableEntryIdInvalid)
|
||||
continue;
|
||||
@ -7719,7 +7754,10 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
|
||||
return tag_type;
|
||||
}
|
||||
|
||||
ir_build_enum_tag_from(&ira->new_irb, &switch_target_instruction->base, target_value_ptr);
|
||||
IrInstruction *enum_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope,
|
||||
switch_target_instruction->base.source_node, target_value_ptr);
|
||||
enum_value->type_entry = target_type;
|
||||
ir_build_enum_tag_from(&ira->new_irb, &switch_target_instruction->base, enum_value);
|
||||
return tag_type;
|
||||
}
|
||||
case TypeTableEntryIdErrorUnion:
|
||||
@ -7748,10 +7786,11 @@ static TypeTableEntry *ir_analyze_instruction_switch_var(IrAnalyze *ira,
|
||||
zig_panic("TODO switch var analyze");
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_enum_tag(IrAnalyze *ira,
|
||||
IrInstructionEnumTag *enum_tag_instruction)
|
||||
{
|
||||
zig_panic("TODO ir_analyze_instruction_enum_tag");
|
||||
static TypeTableEntry *ir_analyze_instruction_enum_tag(IrAnalyze *ira, IrInstructionEnumTag *enum_tag_instruction) {
|
||||
IrInstruction *value = enum_tag_instruction->value->other;
|
||||
IrInstruction *new_instruction = ir_analyze_enum_tag(ira, &enum_tag_instruction->base, value);
|
||||
ir_link_new_instruction(new_instruction, &enum_tag_instruction->base);
|
||||
return new_instruction->type_entry;
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_static_eval(IrAnalyze *ira,
|
||||
|
@ -5,7 +5,7 @@ const linux = @import("linux.zig");
|
||||
const cstr = @import("cstr.zig");
|
||||
|
||||
const want_start_symbol = switch(@compileVar("os")) {
|
||||
linux => true,
|
||||
Os.linux => true,
|
||||
else => false,
|
||||
};
|
||||
const want_main_symbol = !want_start_symbol;
|
||||
@ -17,11 +17,11 @@ export nakedcc fn _start() -> unreachable {
|
||||
@setFnVisible(this, want_start_symbol);
|
||||
|
||||
switch (@compileVar("arch")) {
|
||||
x86_64 => {
|
||||
Arch.x86_64 => {
|
||||
argc = asm("mov (%%rsp), %[argc]": [argc] "=r" (-> usize));
|
||||
argv = asm("lea 0x8(%%rsp), %[argv]": [argv] "=r" (-> &&u8));
|
||||
},
|
||||
i386 => {
|
||||
Arch.i386 => {
|
||||
argc = asm("mov (%%esp), %[argc]": [argc] "=r" (-> usize));
|
||||
argv = asm("lea 0x4(%%esp), %[argv]": [argv] "=r" (-> &&u8));
|
||||
},
|
||||
@ -31,7 +31,7 @@ export nakedcc fn _start() -> unreachable {
|
||||
}
|
||||
|
||||
fn callMain() -> %void {
|
||||
var args: [argc][]u8 = undefined;
|
||||
const args = @alloca([]u8, argc);
|
||||
for (args) |arg, i| {
|
||||
const ptr = argv[i];
|
||||
args[i] = ptr[0...cstr.len(ptr)];
|
||||
|
42
std/io.zig
42
std/io.zig
@ -34,31 +34,31 @@ pub var stderr = OutStream {
|
||||
|
||||
/// The function received invalid input at runtime. An Invalid error means a
|
||||
/// bug in the program that called the function.
|
||||
pub error Invalid;
|
||||
error Invalid;
|
||||
|
||||
/// When an Unexpected error occurs, code that emitted the error likely needs
|
||||
/// a patch to recognize the unexpected case so that it can handle it and emit
|
||||
/// a more specific error.
|
||||
pub error Unexpected;
|
||||
error Unexpected;
|
||||
|
||||
pub error DiskQuota;
|
||||
pub error FileTooBig;
|
||||
pub error Io;
|
||||
pub error NoSpaceLeft;
|
||||
pub error BadPerm;
|
||||
pub error PipeFail;
|
||||
pub error BadFd;
|
||||
pub error IsDir;
|
||||
pub error NotDir;
|
||||
pub error SymLinkLoop;
|
||||
pub error ProcessFdQuotaExceeded;
|
||||
pub error SystemFdQuotaExceeded;
|
||||
pub error NameTooLong;
|
||||
pub error NoDevice;
|
||||
pub error PathNotFound;
|
||||
pub error NoMem;
|
||||
pub error Unseekable;
|
||||
pub error Eof;
|
||||
error DiskQuota;
|
||||
error FileTooBig;
|
||||
error Io;
|
||||
error NoSpaceLeft;
|
||||
error BadPerm;
|
||||
error PipeFail;
|
||||
error BadFd;
|
||||
error IsDir;
|
||||
error NotDir;
|
||||
error SymLinkLoop;
|
||||
error ProcessFdQuotaExceeded;
|
||||
error SystemFdQuotaExceeded;
|
||||
error NameTooLong;
|
||||
error NoDevice;
|
||||
error PathNotFound;
|
||||
error NoMem;
|
||||
error Unseekable;
|
||||
error Eof;
|
||||
|
||||
const buffer_size = 4 * 1024;
|
||||
const max_u64_base10_digits = 20;
|
||||
@ -374,7 +374,7 @@ pub fn parseUnsigned(inline T: type, buf: []u8, radix: u8) -> %T {
|
||||
return x;
|
||||
}
|
||||
|
||||
pub error InvalidChar;
|
||||
error InvalidChar;
|
||||
fn charToDigit(c: u8, radix: u8) -> %u8 {
|
||||
const value = if ('0' <= c && c <= '9') {
|
||||
c - '0'
|
||||
|
Loading…
Reference in New Issue
Block a user