IR: support sizeOf builtin

This commit is contained in:
Andrew Kelley 2016-11-20 02:11:36 -05:00
parent 6c8b919d17
commit b47e2fa060
4 changed files with 94 additions and 21 deletions

View File

@ -1452,6 +1452,7 @@ enum IrInstructionId {
IrInstructionIdSliceType,
IrInstructionIdAsm,
IrInstructionIdCompileVar,
IrInstructionIdSizeOf,
};
struct IrInstruction {
@ -1742,6 +1743,12 @@ struct IrInstructionCompileVar {
IrInstruction *name;
};
struct IrInstructionSizeOf {
IrInstruction base;
IrInstruction *type_value;
};
enum LValPurpose {
LValPurposeNone,
LValPurposeAssign,

View File

@ -1444,6 +1444,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdArrayType:
case IrInstructionIdSliceType:
case IrInstructionIdCompileVar:
case IrInstructionIdSizeOf:
zig_unreachable();
case IrInstructionIdReturn:
return ir_render_return(g, executable, (IrInstructionReturn *)instruction);

View File

@ -222,6 +222,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCompileVar *) {
return IrInstructionIdCompileVar;
}
static constexpr IrInstructionId ir_instruction_id(IrInstructionSizeOf *) {
return IrInstructionIdSizeOf;
}
template<typename T>
static T *ir_create_instruction(IrExecutable *exec, AstNode *source_node) {
T *special_instruction = allocate<T>(1);
@ -865,6 +869,15 @@ static IrInstruction *ir_build_compile_var(IrBuilder *irb, AstNode *source_node,
return &instruction->base;
}
static IrInstruction *ir_build_size_of(IrBuilder *irb, AstNode *source_node, IrInstruction *type_value) {
IrInstructionSizeOf *instruction = ir_build_instruction<IrInstructionSizeOf>(irb, source_node);
instruction->type_value = type_value;
ir_ref_instruction(type_value);
return &instruction->base;
}
static void ir_gen_defers_for_block(IrBuilder *irb, BlockContext *inner_block, BlockContext *outer_block,
bool gen_error_defers, bool gen_maybe_defers)
{
@ -1356,9 +1369,17 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, AstNode *node) {
return ir_build_compile_var(irb, node, arg0_value);
}
case BuiltinFnIdSizeof:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, node->block_context);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
return ir_build_size_of(irb, node, arg0_value);
}
case BuiltinFnIdMemcpy:
case BuiltinFnIdMemset:
case BuiltinFnIdSizeof:
case BuiltinFnIdAlignof:
case BuiltinFnIdMaxValue:
case BuiltinFnIdMinValue:
@ -4417,6 +4438,56 @@ static TypeTableEntry *ir_analyze_instruction_compile_var(IrAnalyze *ira,
zig_unreachable();
}
static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,
IrInstructionSizeOf *size_of_instruction)
{
IrInstruction *type_value = size_of_instruction->type_value->other;
TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);
TypeTableEntry *canon_type_entry = get_underlying_type(type_entry);
switch (canon_type_entry->id) {
case TypeTableEntryIdInvalid:
return ira->codegen->builtin_types.entry_invalid;
case TypeTableEntryIdTypeDecl:
zig_unreachable();
case TypeTableEntryIdVar:
case TypeTableEntryIdUnreachable:
case TypeTableEntryIdUndefLit:
case TypeTableEntryIdNullLit:
case TypeTableEntryIdBlock:
case TypeTableEntryIdNumLitFloat:
case TypeTableEntryIdNumLitInt:
case TypeTableEntryIdGenericFn:
case TypeTableEntryIdMetaType:
case TypeTableEntryIdFn:
case TypeTableEntryIdNamespace:
add_node_error(ira->codegen, size_of_instruction->base.source_node,
buf_sprintf("no size available for type '%s'", buf_ptr(&type_entry->name)));
// TODO if this is a typedecl, add error note showing the declaration of the type decl
return ira->codegen->builtin_types.entry_invalid;
case TypeTableEntryIdVoid:
case TypeTableEntryIdBool:
case TypeTableEntryIdInt:
case TypeTableEntryIdFloat:
case TypeTableEntryIdPointer:
case TypeTableEntryIdArray:
case TypeTableEntryIdStruct:
case TypeTableEntryIdMaybe:
case TypeTableEntryIdErrorUnion:
case TypeTableEntryIdPureError:
case TypeTableEntryIdEnum:
case TypeTableEntryIdUnion:
{
uint64_t size_in_bytes = type_size(ira->codegen, type_entry);
bool depends_on_compile_var = false; // TODO types should be able to depend on compile var
ConstExprValue *out_val = ir_build_const_from(ira, &size_of_instruction->base,
depends_on_compile_var);
bignum_init_unsigned(&out_val->data.x_bignum, size_in_bytes);
return ira->codegen->builtin_types.entry_num_lit_int;
}
}
zig_unreachable();
}
static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
switch (instruction->id) {
case IrInstructionIdInvalid:
@ -4471,6 +4542,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_array_type(ira, (IrInstructionArrayType *)instruction);
case IrInstructionIdCompileVar:
return ir_analyze_instruction_compile_var(ira, (IrInstructionCompileVar *)instruction);
case IrInstructionIdSizeOf:
return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction);
case IrInstructionIdSwitchBr:
case IrInstructionIdCast:
case IrInstructionIdContainerInitList:
@ -4580,6 +4653,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdArrayType:
case IrInstructionIdSliceType:
case IrInstructionIdCompileVar:
case IrInstructionIdSizeOf:
return false;
case IrInstructionIdAsm:
{
@ -5248,24 +5322,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
//
// return builtin_fn->return_type;
// }
// case BuiltinFnIdSizeof:
// {
// AstNode *type_node = node->data.fn_call_expr.params.at(0);
// TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node);
// if (type_entry->id == TypeTableEntryIdInvalid) {
// return g->builtin_types.entry_invalid;
// } else if (type_entry->id == TypeTableEntryIdUnreachable) {
// add_node_error(g, first_executing_node(type_node),
// buf_sprintf("no size available for type '%s'", buf_ptr(&type_entry->name)));
// return g->builtin_types.entry_invalid;
// } else {
// uint64_t size_in_bytes = type_size(g, type_entry);
// bool depends_on_compile_var = (type_entry == g->builtin_types.entry_usize ||
// type_entry == g->builtin_types.entry_isize);
// return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type,
// size_in_bytes, depends_on_compile_var);
// }
// }
// case BuiltinFnIdAlignof:
// {
// AstNode *type_node = node->data.fn_call_expr.params.at(0);
@ -8044,7 +8100,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no
// LLVMBuildCall(g->builder, builtin_fn->fn_val, params, 5, "");
// return nullptr;
// }
// case BuiltinFnIdSizeof:
// case BuiltinFnIdAlignof:
// case BuiltinFnIdMinValue:
// case BuiltinFnIdMaxValue:

View File

@ -36,7 +36,8 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const
}
switch (type_entry->id) {
case TypeTableEntryIdInvalid:
zig_unreachable();
fprintf(irp->f, "(invalid)");
break;
case TypeTableEntryIdVoid:
fprintf(irp->f, "{}");
break;
@ -490,6 +491,12 @@ static void ir_print_compile_var(IrPrint *irp, IrInstructionCompileVar *instruct
fprintf(irp->f, ")");
}
static void ir_print_size_of(IrPrint *irp, IrInstructionSizeOf *instruction) {
fprintf(irp->f, "@sizeOf(");
ir_print_other_instruction(irp, instruction->type_value);
fprintf(irp->f, ")");
}
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
ir_print_prefix(irp, instruction);
switch (instruction->id) {
@ -582,6 +589,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdCompileVar:
ir_print_compile_var(irp, (IrInstructionCompileVar *)instruction);
break;
case IrInstructionIdSizeOf:
ir_print_size_of(irp, (IrInstructionSizeOf *)instruction);
break;
case IrInstructionIdSwitchBr:
zig_panic("TODO print more IR instructions");
}