IR: pass intToEnum test
parent
c8a7ab7eff
commit
66a83d8738
|
@ -437,7 +437,6 @@ enum CastOp {
|
|||
CastOpFloatToInt,
|
||||
CastOpBoolToInt,
|
||||
CastOpResizeSlice,
|
||||
CastOpIntToEnum,
|
||||
CastOpBytesToSlice,
|
||||
};
|
||||
|
||||
|
@ -1458,6 +1457,7 @@ enum IrInstructionId {
|
|||
IrInstructionIdWidenOrShorten,
|
||||
IrInstructionIdIntToPtr,
|
||||
IrInstructionIdPtrToInt,
|
||||
IrInstructionIdIntToEnum,
|
||||
};
|
||||
|
||||
struct IrInstruction {
|
||||
|
@ -2118,6 +2118,12 @@ struct IrInstructionIntToPtr {
|
|||
IrInstruction *target;
|
||||
};
|
||||
|
||||
struct IrInstructionIntToEnum {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *target;
|
||||
};
|
||||
|
||||
enum LValPurpose {
|
||||
LValPurposeNone,
|
||||
LValPurposeAssign,
|
||||
|
|
|
@ -1075,10 +1075,6 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
|
|||
assert(wanted_type->id == TypeTableEntryIdInt);
|
||||
assert(actual_type->id == TypeTableEntryIdBool);
|
||||
return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, "");
|
||||
|
||||
case CastOpIntToEnum:
|
||||
return gen_widen_or_shorten(g, ir_want_debug_safety(g, &cast_instruction->base),
|
||||
actual_type, wanted_type->data.enumeration.tag_type, expr_val);
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
@ -1122,6 +1118,24 @@ static LLVMValueRef ir_render_ptr_to_int(CodeGen *g, IrExecutable *executable, I
|
|||
return LLVMBuildPtrToInt(g->builder, target_val, wanted_type->type_ref, "");
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable, IrInstructionIntToEnum *instruction) {
|
||||
TypeTableEntry *wanted_type = instruction->base.value.type;
|
||||
assert(wanted_type->id == TypeTableEntryIdEnum);
|
||||
TypeTableEntry *tag_type = wanted_type->data.enumeration.tag_type;
|
||||
TypeTableEntry *wanted_int_type;
|
||||
if (tag_type->id == TypeTableEntryIdEnumTag) {
|
||||
wanted_int_type = tag_type->data.enum_tag.int_type;
|
||||
} else if (tag_type->id == TypeTableEntryIdInt) {
|
||||
wanted_int_type = tag_type;
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
|
||||
return gen_widen_or_shorten(g, ir_want_debug_safety(g, &instruction->base),
|
||||
instruction->target->value.type, wanted_int_type, target_val);
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_render_unreachable(CodeGen *g, IrExecutable *executable,
|
||||
IrInstructionUnreachable *unreachable_instruction)
|
||||
{
|
||||
|
@ -2359,6 +2373,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
|
|||
return ir_render_ptr_to_int(g, executable, (IrInstructionPtrToInt *)instruction);
|
||||
case IrInstructionIdIntToPtr:
|
||||
return ir_render_int_to_ptr(g, executable, (IrInstructionIntToPtr *)instruction);
|
||||
case IrInstructionIdIntToEnum:
|
||||
return ir_render_int_to_enum(g, executable, (IrInstructionIntToEnum *)instruction);
|
||||
case IrInstructionIdContainerInitList:
|
||||
return ir_render_container_init_list(g, executable, (IrInstructionContainerInitList *)instruction);
|
||||
case IrInstructionIdSwitchVar:
|
||||
|
|
51
src/ir.cpp
51
src/ir.cpp
|
@ -468,6 +468,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToPtr *) {
|
|||
return IrInstructionIdIntToPtr;
|
||||
}
|
||||
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToEnum *) {
|
||||
return IrInstructionIdIntToEnum;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) {
|
||||
T *special_instruction = allocate<T>(1);
|
||||
|
@ -1932,6 +1936,18 @@ static IrInstruction *ir_build_ptr_to_int(IrBuilder *irb, Scope *scope, AstNode
|
|||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_int_to_enum(IrBuilder *irb, Scope *scope, AstNode *source_node,
|
||||
IrInstruction *target)
|
||||
{
|
||||
IrInstructionIntToEnum *instruction = ir_build_instruction<IrInstructionIntToEnum>(
|
||||
irb, scope, source_node);
|
||||
instruction->target = target;
|
||||
|
||||
ir_ref_instruction(target);
|
||||
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
|
||||
results[ReturnKindUnconditional] = 0;
|
||||
results[ReturnKindError] = 0;
|
||||
|
@ -4720,16 +4736,6 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
|
|||
bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_bool ? 1 : 0);
|
||||
const_val->special = ConstValSpecialStatic;
|
||||
break;
|
||||
case CastOpIntToEnum:
|
||||
{
|
||||
uint64_t value = other_val->data.x_bignum.data.x_uint;
|
||||
assert(new_type->id == TypeTableEntryIdEnum);
|
||||
assert(value < new_type->data.enumeration.src_field_count);
|
||||
const_val->data.x_enum.tag = value;
|
||||
const_val->data.x_enum.payload = NULL;
|
||||
const_val->special = ConstValSpecialStatic;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
|
||||
|
@ -5311,6 +5317,27 @@ static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *sourc
|
|||
return result;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *source_instr,
|
||||
IrInstruction *target, TypeTableEntry *wanted_type)
|
||||
{
|
||||
assert(wanted_type->id == TypeTableEntryIdEnum);
|
||||
|
||||
if (instr_is_comptime(target)) {
|
||||
ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
|
||||
if (!val)
|
||||
return ira->codegen->invalid_instruction;
|
||||
IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
|
||||
source_instr->source_node, wanted_type, val->depends_on_compile_var);
|
||||
result->value.data.x_enum.tag = val->data.x_bignum.data.x_uint;
|
||||
return result;
|
||||
}
|
||||
|
||||
IrInstruction *result = ir_build_int_to_enum(&ira->new_irb, source_instr->scope,
|
||||
source_instr->source_node, target);
|
||||
result->value.type = wanted_type;
|
||||
return result;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr,
|
||||
TypeTableEntry *wanted_type, IrInstruction *value)
|
||||
{
|
||||
|
@ -5533,7 +5560,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
|
|||
wanted_type->id == TypeTableEntryIdEnum &&
|
||||
wanted_type->data.enumeration.gen_field_count == 0)
|
||||
{
|
||||
return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpIntToEnum, false);
|
||||
return ir_analyze_int_to_enum(ira, source_instr, value, wanted_type);
|
||||
}
|
||||
|
||||
// explicit cast from enum type with no payload to integer
|
||||
|
@ -10016,6 +10043,7 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
|
|||
case IrInstructionIdWidenOrShorten:
|
||||
case IrInstructionIdIntToPtr:
|
||||
case IrInstructionIdPtrToInt:
|
||||
case IrInstructionIdIntToEnum:
|
||||
case IrInstructionIdStructInit:
|
||||
case IrInstructionIdStructFieldPtr:
|
||||
case IrInstructionIdEnumFieldPtr:
|
||||
|
@ -10325,6 +10353,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
|
|||
case IrInstructionIdWidenOrShorten:
|
||||
case IrInstructionIdPtrToInt:
|
||||
case IrInstructionIdIntToPtr:
|
||||
case IrInstructionIdIntToEnum:
|
||||
return false;
|
||||
case IrInstructionIdAsm:
|
||||
{
|
||||
|
|
|
@ -952,6 +952,12 @@ static void ir_print_int_to_ptr(IrPrint *irp, IrInstructionIntToPtr *instruction
|
|||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_int_to_enum(IrPrint *irp, IrInstructionIntToEnum *instruction) {
|
||||
fprintf(irp->f, "@intToEnum(");
|
||||
ir_print_other_instruction(irp, instruction->target);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
ir_print_prefix(irp, instruction);
|
||||
switch (instruction->id) {
|
||||
|
@ -1203,6 +1209,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
|||
case IrInstructionIdIntToPtr:
|
||||
ir_print_int_to_ptr(irp, (IrInstructionIntToPtr *)instruction);
|
||||
break;
|
||||
case IrInstructionIdIntToEnum:
|
||||
ir_print_int_to_enum(irp, (IrInstructionIntToEnum *)instruction);
|
||||
break;
|
||||
}
|
||||
fprintf(irp->f, "\n");
|
||||
}
|
||||
|
|
|
@ -96,6 +96,23 @@ fn shouldEqual(n: Number, expected: usize) {
|
|||
}
|
||||
|
||||
|
||||
fn intToEnum() {
|
||||
@setFnTest(this);
|
||||
|
||||
testIntToEnumEval(3);
|
||||
}
|
||||
fn testIntToEnumEval(x: i32) {
|
||||
assert(IntToEnumNumber(x) == IntToEnumNumber.Three);
|
||||
}
|
||||
const IntToEnumNumber = enum {
|
||||
Zero,
|
||||
One,
|
||||
Two,
|
||||
Three,
|
||||
Four,
|
||||
};
|
||||
|
||||
|
||||
// TODO import from std
|
||||
fn assert(ok: bool) {
|
||||
if (!ok)
|
||||
|
|
|
@ -80,20 +80,3 @@ fn castSliceToU8Slice() {
|
|||
assert(bytes[10] == @maxValue(u8));
|
||||
assert(bytes[11] == @maxValue(u8));
|
||||
}
|
||||
|
||||
// TODO not passing
|
||||
fn intToEnum() {
|
||||
@setFnTest(this);
|
||||
|
||||
testIntToEnumEval(3);
|
||||
}
|
||||
fn testIntToEnumEval(x: i32) {
|
||||
assert(IntToEnumNumber(x) == IntToEnumNumber.Three);
|
||||
}
|
||||
const IntToEnumNumber = enum {
|
||||
Zero,
|
||||
One,
|
||||
Two,
|
||||
Three,
|
||||
Four,
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue