simple add function works with IR

master
Andrew Kelley 2016-10-02 23:48:48 -04:00
parent 633781e31d
commit cd1bd78aa9
6 changed files with 1014 additions and 132 deletions

View File

@ -1420,6 +1420,7 @@ enum IrInstructionId {
IrInstructionIdBuiltinCall,
IrInstructionIdConst,
IrInstructionIdReturn,
IrInstructionIdCast,
};
struct IrInstruction {
@ -1539,5 +1540,12 @@ struct IrInstructionReturn {
IrInstruction *value;
};
struct IrInstructionCast {
IrInstruction base;
IrInstruction *value;
IrInstruction *dest_type;
bool is_implicit;
};
#endif

View File

@ -42,10 +42,8 @@ static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, As
TypeTableEntry *expected_type, uint64_t x, bool depends_on_compile_var);
static TypeTableEntry *resolve_expr_const_val_as_bool(CodeGen *g, AstNode *node, bool value,
bool depends_on_compile_var);
static AstNode *find_decl(BlockContext *context, Buf *name);
static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNode *decl_node,
bool pointer_only, BlockContext *block_context, bool depends_on_compile_var);
static TopLevelDecl *get_as_top_level_decl(AstNode *node);
static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import,
BlockContext *context, AstNode *source_node,
AstNodeVariableDeclaration *variable_declaration,
@ -1757,7 +1755,7 @@ static void preview_error_value_decl(CodeGen *g, AstNode *node) {
node->data.error_value_decl.top_level_decl.resolution = TldResolutionOk;
}
static void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only) {
void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only) {
TopLevelDecl *tld = get_as_top_level_decl(node);
if (tld->resolution != TldResolutionUnresolved) {
return;
@ -1978,7 +1976,7 @@ static bool num_lit_fits_in_other_type(CodeGen *g, AstNode *literal_node, TypeTa
return false;
}
static bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *actual_type) {
bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *actual_type) {
if (expected_type == actual_type)
return true;
@ -2302,7 +2300,7 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, ImportTableEntry *
return g->builtin_types.entry_invalid;
}
static TypeTableEntry *resolve_peer_type_compatibility(CodeGen *g, ImportTableEntry *import,
TypeTableEntry *resolve_peer_type_compatibility(CodeGen *g, ImportTableEntry *import,
BlockContext *block_context, AstNode *parent_source_node,
AstNode **child_nodes, TypeTableEntry **child_types, size_t child_count)
{
@ -2358,7 +2356,7 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) {
return context;
}
static AstNode *find_decl(BlockContext *context, Buf *name) {
AstNode *find_decl(BlockContext *context, Buf *name) {
while (context) {
auto entry = context->decl_table.maybe_get(name);
if (entry) {
@ -2369,7 +2367,7 @@ static AstNode *find_decl(BlockContext *context, Buf *name) {
return nullptr;
}
static VariableTableEntry *find_variable(CodeGen *g, BlockContext *orig_context, Buf *name) {
VariableTableEntry *find_variable(CodeGen *g, BlockContext *orig_context, Buf *name) {
BlockContext *context = orig_context;
while (context) {
auto entry = context->var_table.maybe_get(name);
@ -3248,10 +3246,6 @@ static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNod
static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node, bool pointer_only)
{
if (node->data.symbol_expr.override_type_entry) {
return resolve_expr_const_val_as_type(g, node, node->data.symbol_expr.override_type_entry, false);
}
Buf *variable_name = node->data.symbol_expr.symbol;
auto primitive_table_entry = g->primitive_type_table.maybe_get(variable_name);
@ -4091,11 +4085,6 @@ static TypeTableEntry *analyze_this_literal_expr(CodeGen *g, ImportTableEntry *i
static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry *import,
BlockContext *block_context, TypeTableEntry *expected_type, AstNode *node)
{
if (node->data.number_literal.overflow) {
add_node_error(g, node, buf_sprintf("number literal too large to be represented in any type"));
return g->builtin_types.entry_invalid;
}
return resolve_expr_const_val_as_bignum(g, node, expected_type, node->data.number_literal.bignum, false);
}
@ -7536,7 +7525,7 @@ Expr *get_resolved_expr(AstNode *node) {
zig_unreachable();
}
static TopLevelDecl *get_as_top_level_decl(AstNode *node) {
TopLevelDecl *get_as_top_level_decl(AstNode *node) {
switch (node->type) {
case NodeTypeVariableDeclaration:
return &node->data.variable_declaration.top_level_decl;

View File

@ -45,4 +45,14 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package,
AstNode *first_executing_node(AstNode *node);
TypeTableEntry *resolve_peer_type_compatibility(CodeGen *g, ImportTableEntry *import,
BlockContext *block_context, AstNode *parent_source_node,
AstNode **child_nodes, TypeTableEntry **child_types, size_t child_count);
bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *actual_type);
VariableTableEntry *find_variable(CodeGen *g, BlockContext *orig_context, Buf *name);
AstNode *find_decl(BlockContext *context, Buf *name);
void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only);
TopLevelDecl *get_as_top_level_decl(AstNode *node);
#endif

View File

@ -65,8 +65,6 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) {
g->is_test_build = false;
g->want_h_file = true;
g->invalid_instruction = allocate<IrInstruction>(1);
// the error.Ok value
g->error_decls.append(nullptr);
@ -252,10 +250,6 @@ static void set_debug_source_node(CodeGen *g, AstNode *node) {
ZigLLVMSetCurrentDebugLocation(g->builder, node->line + 1, node->column + 1, node->block_context->di_scope);
}
static void ir_set_debug(CodeGen *g, IrInstruction *instruction) {
set_debug_source_node(g, instruction->source_node);
}
static void clear_debug_source_node(CodeGen *g) {
ZigLLVMClearCurrentDebugLocation(g->builder);
}
@ -375,6 +369,10 @@ static bool want_debug_safety(CodeGen *g, AstNode *node) {
return want_debug_safety_recursive(g, node->block_context);
}
static bool ir_want_debug_safety(CodeGen *g, IrInstruction *instruction) {
return want_debug_safety(g, instruction->source_node);
}
static void gen_debug_safety_crash(CodeGen *g) {
LLVMBuildCall(g->builder, g->trap_fn_val, nullptr, 0, "");
LLVMBuildUnreachable(g->builder);
@ -2800,12 +2798,104 @@ static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) {
}
static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {
ir_set_debug(g, &return_instruction->base);
LLVMBuildRet(g->builder, return_instruction->value->llvm_value);
return nullptr;
}
static LLVMValueRef ir_render_load_var(CodeGen *g, IrExecutable *executable,
IrInstructionLoadVar *load_var_instruction)
{
VariableTableEntry *var = load_var_instruction->var;
if (!type_has_bits(var->type))
return nullptr;
assert(var->value_ref);
return get_handle_value(g, load_var_instruction->base.source_node, var->value_ref, var->type);
}
static LLVMValueRef ir_render_bin_op_bool(CodeGen *g, IrExecutable *executable,
IrInstructionBinOp *bin_op_instruction)
{
IrBinOp op_id = bin_op_instruction->op_id;
LLVMValueRef op1 = bin_op_instruction->op1->llvm_value;
LLVMValueRef op2 = bin_op_instruction->op2->llvm_value;
if (op_id == IrBinOpBoolOr) {
return LLVMBuildOr(g->builder, op1, op2, "");
} else if (op_id == IrBinOpBoolAnd) {
return LLVMBuildAnd(g->builder, op1, op2, "");
} else {
zig_unreachable();
}
}
static LLVMValueRef ir_render_bin_op_add(CodeGen *g, IrExecutable *executable,
IrInstructionBinOp *bin_op_instruction)
{
IrBinOp op_id = bin_op_instruction->op_id;
IrInstruction *op1 = bin_op_instruction->op1;
IrInstruction *op2 = bin_op_instruction->op2;
assert(op1->type_entry == op2->type_entry);
if (op1->type_entry->id == TypeTableEntryIdFloat) {
return LLVMBuildFAdd(g->builder, op1->llvm_value, op2->llvm_value, "");
} else if (op1->type_entry->id == TypeTableEntryIdInt) {
bool is_wrapping = (op_id == IrBinOpAddWrap);
if (is_wrapping) {
return LLVMBuildAdd(g->builder, op1->llvm_value, op2->llvm_value, "");
} else if (ir_want_debug_safety(g, &bin_op_instruction->base)) {
return gen_overflow_op(g, op1->type_entry, AddSubMulAdd, op1->llvm_value, op2->llvm_value);
} else if (op1->type_entry->data.integral.is_signed) {
return LLVMBuildNSWAdd(g->builder, op1->llvm_value, op2->llvm_value, "");
} else {
return LLVMBuildNUWAdd(g->builder, op1->llvm_value, op2->llvm_value, "");
}
} else {
zig_unreachable();
}
}
static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
IrInstructionBinOp *bin_op_instruction)
{
IrBinOp op_id = bin_op_instruction->op_id;
switch (op_id) {
case IrBinOpInvalid:
case IrBinOpArrayCat:
case IrBinOpArrayMult:
zig_unreachable();
case IrBinOpBoolOr:
case IrBinOpBoolAnd:
return ir_render_bin_op_bool(g, executable, bin_op_instruction);
case IrBinOpCmpEq:
case IrBinOpCmpNotEq:
case IrBinOpCmpLessThan:
case IrBinOpCmpGreaterThan:
case IrBinOpCmpLessOrEq:
case IrBinOpCmpGreaterOrEq:
zig_panic("TODO bin op cmp");
case IrBinOpAdd:
case IrBinOpAddWrap:
return ir_render_bin_op_add(g, executable, bin_op_instruction);
case IrBinOpBinOr:
case IrBinOpBinXor:
case IrBinOpBinAnd:
case IrBinOpBitShiftLeft:
case IrBinOpBitShiftLeftWrap:
case IrBinOpBitShiftRight:
case IrBinOpSub:
case IrBinOpSubWrap:
case IrBinOpMult:
case IrBinOpMultWrap:
case IrBinOpDiv:
case IrBinOpMod:
zig_panic("TODO render more bin ops to LLVM");
}
zig_unreachable();
}
static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, IrInstruction *instruction) {
set_debug_source_node(g, instruction->source_node);
switch (instruction->id) {
case IrInstructionIdInvalid:
zig_unreachable();
@ -2813,14 +2903,17 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return gen_const_val(g, instruction->type_entry, &instruction->static_value);
case IrInstructionIdReturn:
return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
case IrInstructionIdLoadVar:
return ir_render_load_var(g, executable, (IrInstructionLoadVar *)instruction);
case IrInstructionIdBinOp:
return ir_render_bin_op(g, executable, (IrInstructionBinOp *)instruction);
case IrInstructionIdCondBr:
case IrInstructionIdSwitchBr:
case IrInstructionIdPhi:
case IrInstructionIdBinOp:
case IrInstructionIdLoadVar:
case IrInstructionIdStoreVar:
case IrInstructionIdCall:
case IrInstructionIdBuiltinCall:
case IrInstructionIdCast:
zig_panic("TODO render more IR instructions to LLVM");
}
zig_unreachable();
@ -5013,6 +5106,9 @@ static void init(CodeGen *g, Buf *source_path) {
define_builtin_types(g);
define_builtin_fns(g);
g->invalid_instruction = allocate<IrInstruction>(1);
g->invalid_instruction->type_entry = g->builtin_types.entry_invalid;
}
void codegen_parseh(CodeGen *g, Buf *src_dirname, Buf *src_basename, Buf *source_code) {

File diff suppressed because it is too large Load Diff

View File

@ -25,12 +25,24 @@ static void ir_print_return(IrPrint *irp, IrInstructionReturn *return_instructio
static void ir_print_const(IrPrint *irp, IrInstructionConst *const_instruction) {
ir_print_prefix(irp, &const_instruction->base);
switch (const_instruction->base.type_entry->id) {
TypeTableEntry *type_entry = const_instruction->base.type_entry;
fprintf(irp->f, "%s ", buf_ptr(&type_entry->name));
switch (type_entry->id) {
case TypeTableEntryIdInvalid:
zig_unreachable();
case TypeTableEntryIdVoid:
fprintf(irp->f, "void\n");
fprintf(irp->f, "%s\n", "void");
break;
case TypeTableEntryIdNumLitFloat:
fprintf(irp->f, "%f\n", const_instruction->base.static_value.data.x_bignum.data.x_float);
break;
case TypeTableEntryIdNumLitInt:
{
BigNum *bignum = &const_instruction->base.static_value.data.x_bignum;
const char *negative_str = bignum->is_negative ? "-" : "";
fprintf(irp->f, "%s%llu\n", negative_str, bignum->data.x_uint);
break;
}
case TypeTableEntryIdVar:
case TypeTableEntryIdMetaType:
case TypeTableEntryIdBool:
@ -40,8 +52,6 @@ static void ir_print_const(IrPrint *irp, IrInstructionConst *const_instruction)
case TypeTableEntryIdPointer:
case TypeTableEntryIdArray:
case TypeTableEntryIdStruct:
case TypeTableEntryIdNumLitFloat:
case TypeTableEntryIdNumLitInt:
case TypeTableEntryIdUndefLit:
case TypeTableEntryIdNullLit:
case TypeTableEntryIdMaybe:
@ -58,6 +68,104 @@ static void ir_print_const(IrPrint *irp, IrInstructionConst *const_instruction)
}
}
static const char *ir_bin_op_id_str(IrBinOp op_id) {
switch (op_id) {
case IrBinOpInvalid:
zig_unreachable();
case IrBinOpBoolOr:
return "BoolOr";
case IrBinOpBoolAnd:
return "BoolAnd";
case IrBinOpCmpEq:
return "==";
case IrBinOpCmpNotEq:
return "!=";
case IrBinOpCmpLessThan:
return "<";
case IrBinOpCmpGreaterThan:
return ">";
case IrBinOpCmpLessOrEq:
return "<=";
case IrBinOpCmpGreaterOrEq:
return ">=";
case IrBinOpBinOr:
return "|";
case IrBinOpBinXor:
return "^";
case IrBinOpBinAnd:
return "&";
case IrBinOpBitShiftLeft:
return "<<";
case IrBinOpBitShiftLeftWrap:
return "<<%";
case IrBinOpBitShiftRight:
return ">>";
case IrBinOpAdd:
return "+";
case IrBinOpAddWrap:
return "+%";
case IrBinOpSub:
return "-";
case IrBinOpSubWrap:
return "-%";
case IrBinOpMult:
return "*";
case IrBinOpMultWrap:
return "*%";
case IrBinOpDiv:
return "/";
case IrBinOpMod:
return "%";
case IrBinOpArrayCat:
return "++";
case IrBinOpArrayMult:
return "**";
}
zig_unreachable();
}
static void ir_print_bin_op(IrPrint *irp, IrInstructionBinOp *bin_op_instruction) {
ir_print_prefix(irp, &bin_op_instruction->base);
fprintf(irp->f, "#%zu %s #%zu\n",
bin_op_instruction->op1->debug_id,
ir_bin_op_id_str(bin_op_instruction->op_id),
bin_op_instruction->op2->debug_id);
}
static void ir_print_load_var(IrPrint *irp, IrInstructionLoadVar *load_var_instruction) {
ir_print_prefix(irp, &load_var_instruction->base);
fprintf(irp->f, "%s\n",
buf_ptr(&load_var_instruction->var->name));
}
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
switch (instruction->id) {
case IrInstructionIdInvalid:
zig_unreachable();
case IrInstructionIdReturn:
ir_print_return(irp, (IrInstructionReturn *)instruction);
break;
case IrInstructionIdConst:
ir_print_const(irp, (IrInstructionConst *)instruction);
break;
case IrInstructionIdBinOp:
ir_print_bin_op(irp, (IrInstructionBinOp *)instruction);
break;
case IrInstructionIdLoadVar:
ir_print_load_var(irp, (IrInstructionLoadVar *)instruction);
break;
case IrInstructionIdCondBr:
case IrInstructionIdSwitchBr:
case IrInstructionIdPhi:
case IrInstructionIdStoreVar:
case IrInstructionIdCall:
case IrInstructionIdBuiltinCall:
case IrInstructionIdCast:
zig_panic("TODO print more IR instructions");
}
}
void ir_print(FILE *f, IrExecutable *executable, int indent_size) {
IrPrint ir_print = {};
IrPrint *irp = &ir_print;
@ -70,25 +178,7 @@ void ir_print(FILE *f, IrExecutable *executable, int indent_size) {
for (IrInstruction *instruction = current_block->first; instruction != nullptr;
instruction = instruction->next)
{
switch (instruction->id) {
case IrInstructionIdInvalid:
zig_unreachable();
case IrInstructionIdReturn:
ir_print_return(irp, (IrInstructionReturn *)instruction);
break;
case IrInstructionIdConst:
ir_print_const(irp, (IrInstructionConst *)instruction);
break;
case IrInstructionIdCondBr:
case IrInstructionIdSwitchBr:
case IrInstructionIdPhi:
case IrInstructionIdBinOp:
case IrInstructionIdLoadVar:
case IrInstructionIdStoreVar:
case IrInstructionIdCall:
case IrInstructionIdBuiltinCall:
zig_panic("TODO print more IR instructions");
}
ir_print_instruction(irp, instruction);
}
}
}