IR: re-organize where state goes to prepare for generics

* Rip out legacy code for generics
 * put scope in instruction instead of AST nodes
 * separate top level decl stuff from AST nodes
   - remove the assumption that there is a 1:1 correspondence
     between an output instruction and an AST node
   - This way we won't have to clone AST nodes for generics.
This commit is contained in:
Andrew Kelley
2016-12-01 23:25:09 -05:00
parent f6cbb73c74
commit 2f259b8176
10 changed files with 1508 additions and 1899 deletions

View File

@@ -60,7 +60,6 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) {
g->primitive_type_table.init(32);
g->fn_type_table.init(32);
g->error_table.init(16);
g->generic_table.init(16);
g->is_release_build = false;
g->is_test_build = false;
g->want_h_file = true;
@@ -227,13 +226,59 @@ void codegen_set_rdynamic(CodeGen *g, bool rdynamic) {
static void render_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val);
static void render_const_val_global(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val);
static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
if (fn_table_entry->llvm_value)
return fn_table_entry->llvm_value;
Buf *symbol_name;
if (!fn_table_entry->internal_linkage) {
symbol_name = &fn_table_entry->symbol_name;
} else {
symbol_name = buf_sprintf("_%s", buf_ptr(&fn_table_entry->symbol_name));
}
TypeTableEntry *fn_type = fn_table_entry->type_entry;
fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_type->data.fn.raw_type_ref);
switch (fn_table_entry->fn_inline) {
case FnInlineAlways:
LLVMAddFunctionAttr(fn_table_entry->llvm_value, LLVMAlwaysInlineAttribute);
break;
case FnInlineNever:
LLVMAddFunctionAttr(fn_table_entry->llvm_value, LLVMNoInlineAttribute);
break;
case FnInlineAuto:
break;
}
if (fn_type->data.fn.fn_type_id.is_naked) {
LLVMAddFunctionAttr(fn_table_entry->llvm_value, LLVMNakedAttribute);
}
LLVMSetLinkage(fn_table_entry->llvm_value, fn_table_entry->internal_linkage ?
LLVMInternalLinkage : LLVMExternalLinkage);
if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdUnreachable) {
LLVMAddFunctionAttr(fn_table_entry->llvm_value, LLVMNoReturnAttribute);
}
LLVMSetFunctionCallConv(fn_table_entry->llvm_value, fn_type->data.fn.calling_convention);
if (!fn_type->data.fn.fn_type_id.is_extern) {
LLVMAddFunctionAttr(fn_table_entry->llvm_value, LLVMNoUnwindAttribute);
}
if (!g->is_release_build && fn_table_entry->fn_inline != FnInlineAlways) {
ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim", "true");
ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim-non-leaf", nullptr);
}
return fn_table_entry->llvm_value;
}
static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
if (scope->di_scope)
return scope->di_scope;
if (scope->node->type == NodeTypeFnDef) {
assert(scope->parent);
ScopeFnBody *fn_scope = (ScopeFnBody *)scope;
ScopeFnDef *fn_scope = (ScopeFnDef *)scope;
FnTableEntry *fn_table_entry = fn_scope->fn_entry;
unsigned line_number = fn_table_entry->proto_node->line + 1;
unsigned scope_line = line_number;
@@ -247,11 +292,13 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
is_definition, scope_line, flags, is_optimized, nullptr);
scope->di_scope = ZigLLVMSubprogramToScope(subprogram);
ZigLLVMFnSetSubprogram(fn_table_entry->fn_value, subprogram);
} else if (scope->node->type == NodeTypeRoot ||
scope->node->type == NodeTypeContainerDecl)
{
ZigLLVMFnSetSubprogram(fn_llvm_value(g, fn_table_entry), subprogram);
} else if (scope->node->type == NodeTypeRoot) {
scope->di_scope = ZigLLVMFileToScope(scope->node->owner->di_file);
} else if (scope->node->type == NodeTypeContainerDecl) {
ScopeDecls *decls_scope = (ScopeDecls *)scope;
assert(decls_scope->container_type);
scope->di_scope = ZigLLVMTypeToScope(decls_scope->container_type->di_type);
} else {
assert(scope->parent);
ZigLLVMDILexicalBlock *di_block = ZigLLVMCreateLexicalBlock(g->dbuilder,
@@ -265,11 +312,6 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
return scope->di_scope;
}
static void set_debug_source_node(CodeGen *g, AstNode *node) {
assert(node->scope);
ZigLLVMSetCurrentDebugLocation(g->builder, node->line + 1, node->column + 1, get_di_scope(g, node->scope));
}
static void clear_debug_source_node(CodeGen *g) {
ZigLLVMClearCurrentDebugLocation(g->builder);
}
@@ -350,24 +392,25 @@ static LLVMValueRef get_handle_value(CodeGen *g, LLVMValueRef ptr, TypeTableEntr
}
}
static bool want_debug_safety_recursive(CodeGen *g, Scope *context) {
if (context->safety_set_node || !context->parent) {
return !context->safety_off;
}
context->safety_off = !want_debug_safety_recursive(g, context->parent);
context->safety_set_node = context->parent->safety_set_node;
return !context->safety_off;
}
static bool want_debug_safety(CodeGen *g, AstNode *node) {
if (g->is_release_build) {
return false;
}
return want_debug_safety_recursive(g, node->scope);
}
static bool ir_want_debug_safety(CodeGen *g, IrInstruction *instruction) {
return want_debug_safety(g, instruction->source_node);
if (g->is_release_build)
return false;
// TODO memoize
Scope *scope = instruction->scope;
while (scope) {
if (scope->node->type == NodeTypeBlock) {
ScopeBlock *block_scope = (ScopeBlock *)scope;
if (block_scope->safety_set_node)
return !block_scope->safety_off;
} else if (scope->node->type == NodeTypeRoot || scope->node->type == NodeTypeContainerDecl) {
ScopeDecls *decls_scope = (ScopeDecls *)scope;
if (decls_scope->safety_set_node)
return !decls_scope->safety_off;
}
scope = scope->parent;
}
return true;
}
static void gen_debug_safety_crash(CodeGen *g) {
@@ -388,10 +431,10 @@ static void add_bounds_check(CodeGen *g, LLVMValueRef target_val,
upper_value = nullptr;
}
LLVMBasicBlockRef bounds_check_fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoundsCheckFail");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoundsCheckOk");
LLVMBasicBlockRef bounds_check_fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "BoundsCheckFail");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "BoundsCheckOk");
LLVMBasicBlockRef lower_ok_block = upper_value ?
LLVMAppendBasicBlock(g->cur_fn->fn_value, "FirstBoundsCheckOk") : ok_block;
LLVMAppendBasicBlock(g->cur_fn_val, "FirstBoundsCheckOk") : ok_block;
LLVMValueRef lower_ok_val = LLVMBuildICmp(g->builder, lower_pred, target_val, lower_value, "");
LLVMBuildCondBr(g->builder, lower_ok_val, lower_ok_block, bounds_check_fail_block);
@@ -408,7 +451,7 @@ static void add_bounds_check(CodeGen *g, LLVMValueRef target_val,
LLVMPositionBuilderAtEnd(g->builder, ok_block);
}
static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeTableEntry *actual_type_non_canon,
static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_debug_safety, TypeTableEntry *actual_type_non_canon,
TypeTableEntry *wanted_type_non_canon, LLVMValueRef expr_val)
{
TypeTableEntry *actual_type = get_underlying_type(actual_type_non_canon);
@@ -430,13 +473,13 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeT
if (actual_bits >= wanted_bits && actual_type->id == TypeTableEntryIdInt &&
!wanted_type->data.integral.is_signed && actual_type->data.integral.is_signed &&
want_debug_safety(g, source_node))
want_debug_safety)
{
LLVMValueRef zero = LLVMConstNull(actual_type->type_ref);
LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntSGE, expr_val, zero, "");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SignCastOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SignCastFail");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "SignCastOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "SignCastFail");
LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
LLVMPositionBuilderAtEnd(g->builder, fail_block);
@@ -464,7 +507,7 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeT
return LLVMBuildFPTrunc(g->builder, expr_val, wanted_type->type_ref, "");
} else if (actual_type->id == TypeTableEntryIdInt) {
LLVMValueRef trunc_val = LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, "");
if (!want_debug_safety(g, source_node)) {
if (!want_debug_safety) {
return trunc_val;
}
LLVMValueRef orig_val;
@@ -474,8 +517,8 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeT
orig_val = LLVMBuildZExt(g->builder, trunc_val, actual_type->type_ref, "");
}
LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, expr_val, orig_val, "");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "CastShortenOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "CastShortenFail");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenFail");
LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
LLVMPositionBuilderAtEnd(g->builder, fail_block);
@@ -502,8 +545,8 @@ static LLVMValueRef gen_overflow_op(CodeGen *g, TypeTableEntry *type_entry, AddS
LLVMValueRef result_struct = LLVMBuildCall(g->builder, fn_val, params, 2, "");
LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, "");
LLVMValueRef overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, "");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowFail");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk");
LLVMBuildCondBr(g->builder, overflow_bit, fail_block, ok_block);
LLVMPositionBuilderAtEnd(g->builder, fail_block);
@@ -645,8 +688,8 @@ static LLVMValueRef gen_overflow_shl_op(CodeGen *g, TypeTableEntry *type_entry,
}
LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, orig_val, "");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowFail");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail");
LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
LLVMPositionBuilderAtEnd(g->builder, fail_block);
@@ -656,11 +699,11 @@ static LLVMValueRef gen_overflow_shl_op(CodeGen *g, TypeTableEntry *type_entry,
return result;
}
static LLVMValueRef gen_div(CodeGen *g, AstNode *source_node, LLVMValueRef val1, LLVMValueRef val2,
static LLVMValueRef gen_div(CodeGen *g, bool want_debug_safety, LLVMValueRef val1, LLVMValueRef val2,
TypeTableEntry *type_entry, bool exact)
{
if (want_debug_safety(g, source_node)) {
if (want_debug_safety) {
LLVMValueRef zero = LLVMConstNull(type_entry->type_ref);
LLVMValueRef is_zero_bit;
if (type_entry->id == TypeTableEntryIdInt) {
@@ -670,8 +713,8 @@ static LLVMValueRef gen_div(CodeGen *g, AstNode *source_node, LLVMValueRef val1,
} else {
zig_unreachable();
}
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivZeroOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivZeroFail");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivZeroOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivZeroFail");
LLVMBuildCondBr(g->builder, is_zero_bit, fail_block, ok_block);
LLVMPositionBuilderAtEnd(g->builder, fail_block);
@@ -688,7 +731,7 @@ static LLVMValueRef gen_div(CodeGen *g, AstNode *source_node, LLVMValueRef val1,
assert(type_entry->id == TypeTableEntryIdInt);
if (exact) {
if (want_debug_safety(g, source_node)) {
if (want_debug_safety) {
LLVMValueRef remainder_val;
if (type_entry->data.integral.is_signed) {
remainder_val = LLVMBuildSRem(g->builder, val1, val2, "");
@@ -698,8 +741,8 @@ static LLVMValueRef gen_div(CodeGen *g, AstNode *source_node, LLVMValueRef val1,
LLVMValueRef zero = LLVMConstNull(type_entry->type_ref);
LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, "");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivExactOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivExactFail");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail");
LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
LLVMPositionBuilderAtEnd(g->builder, fail_block);
@@ -727,7 +770,6 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
IrBinOp op_id = bin_op_instruction->op_id;
IrInstruction *op1 = bin_op_instruction->op1;
IrInstruction *op2 = bin_op_instruction->op2;
AstNode *source_node = bin_op_instruction->base.source_node;
assert(op1->type_entry == op2->type_entry);
@@ -801,7 +843,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
bool is_wrapping = (op_id == IrBinOpBitShiftLeftWrap);
if (is_wrapping) {
return LLVMBuildShl(g->builder, op1_value, op2_value, "");
} else if (want_debug_safety(g, source_node)) {
} else if (ir_want_debug_safety(g, &bin_op_instruction->base)) {
return gen_overflow_shl_op(g, op1->type_entry, op1_value, op2_value);
} else if (op1->type_entry->data.integral.is_signed) {
return ZigLLVMBuildNSWShl(g->builder, op1_value, op2_value, "");
@@ -824,7 +866,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
bool is_wrapping = (op_id == IrBinOpSubWrap);
if (is_wrapping) {
return LLVMBuildSub(g->builder, op1_value, op2_value, "");
} else if (want_debug_safety(g, source_node)) {
} else if (ir_want_debug_safety(g, &bin_op_instruction->base)) {
return gen_overflow_op(g, op1->type_entry, AddSubMulSub, op1_value, op2_value);
} else if (op1->type_entry->data.integral.is_signed) {
return LLVMBuildNSWSub(g->builder, op1_value, op2_value, "");
@@ -842,7 +884,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
bool is_wrapping = (op_id == IrBinOpMultWrap);
if (is_wrapping) {
return LLVMBuildMul(g->builder, op1_value, op2_value, "");
} else if (want_debug_safety(g, source_node)) {
} else if (ir_want_debug_safety(g, &bin_op_instruction->base)) {
return gen_overflow_op(g, op1->type_entry, AddSubMulMul, op1_value, op2_value);
} else if (op1->type_entry->data.integral.is_signed) {
return LLVMBuildNSWMul(g->builder, op1_value, op2_value, "");
@@ -853,7 +895,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
zig_unreachable();
}
case IrBinOpDiv:
return gen_div(g, source_node, op1_value, op2_value, op1->type_entry, false);
return gen_div(g, ir_want_debug_safety(g, &bin_op_instruction->base),
op1_value, op2_value, op1->type_entry, false);
case IrBinOpMod:
if (op1->type_entry->id == TypeTableEntryIdFloat) {
return LLVMBuildFRem(g->builder, op1_value, op2_value, "");
@@ -885,8 +928,8 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
case CastOpErrToInt:
assert(actual_type->id == TypeTableEntryIdErrorUnion);
if (!type_has_bits(actual_type->data.error.child_type)) {
return gen_widen_or_shorten(g, cast_instruction->base.source_node,
g->err_tag_type, wanted_type, expr_val);
return gen_widen_or_shorten(g, ir_want_debug_safety(g, &cast_instruction->base),
g->err_tag_type, wanted_type, expr_val);
} else {
zig_panic("TODO");
}
@@ -954,7 +997,8 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
case CastOpPointerReinterpret:
return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, "");
case CastOpWidenOrShorten:
return gen_widen_or_shorten(g, cast_instruction->base.source_node, actual_type, wanted_type, expr_val);
return gen_widen_or_shorten(g, ir_want_debug_safety(g, &cast_instruction->base),
actual_type, wanted_type, expr_val);
case CastOpToUnknownSizeArray:
{
assert(cast_instruction->tmp_ptr);
@@ -1021,8 +1065,8 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
LLVMValueRef remainder_val = LLVMBuildURem(g->builder, src_len, dest_size_val, "");
LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_usize->type_ref);
LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, "");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SliceWidenOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SliceWidenFail");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "SliceWidenOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "SliceWidenFail");
LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
LLVMPositionBuilderAtEnd(g->builder, fail_block);
@@ -1087,10 +1131,10 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, "");
case CastOpIntToEnum:
return gen_widen_or_shorten(g, cast_instruction->base.source_node,
return gen_widen_or_shorten(g, ir_want_debug_safety(g, &cast_instruction->base),
actual_type, wanted_type->data.enumeration.tag_type, expr_val);
case CastOpEnumToInt:
return gen_widen_or_shorten(g, cast_instruction->base.source_node,
return gen_widen_or_shorten(g, ir_want_debug_safety(g, &cast_instruction->base),
actual_type->data.enumeration.tag_type, wanted_type, expr_val);
}
zig_unreachable();
@@ -1197,8 +1241,8 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst
}
LLVMValueRef zero = LLVMConstNull(g->err_tag_type->type_ref);
LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, zero, "");
LLVMBasicBlockRef err_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapErrError");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapErrOk");
LLVMBasicBlockRef err_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrError");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrOk");
LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block);
LLVMPositionBuilderAtEnd(g->builder, err_block);
@@ -1231,8 +1275,8 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst
cond_val = LLVMBuildLoad(g->builder, maybe_null_ptr, "");
}
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapMaybeOk");
LLVMBasicBlockRef null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapMaybeNull");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeOk");
LLVMBasicBlockRef null_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeNull");
LLVMBuildCondBr(g->builder, cond_val, ok_block, null_block);
LLVMPositionBuilderAtEnd(g->builder, null_block);
@@ -1408,7 +1452,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
LLVMValueRef fn_val;
TypeTableEntry *fn_type;
if (instruction->fn_entry) {
fn_val = instruction->fn_entry->fn_value;
fn_val = fn_llvm_value(g, instruction->fn_entry);
fn_type = instruction->fn_entry->type_entry;
} else {
assert(instruction->fn_ref);
@@ -1563,7 +1607,7 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru
}
if (!is_return) {
VariableTableEntry *variable = asm_output->variable;
VariableTableEntry *variable = instruction->output_vars[i];
assert(variable);
param_types[param_index] = LLVMTypeOf(variable->value_ref);
param_values[param_index] = variable->value_ref;
@@ -1638,8 +1682,8 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->value);
if (ir_want_debug_safety(g, &instruction->base) && instruction->safety_check_on) {
LLVMValueRef nonnull_bit = gen_null_bit(g, ptr_type, maybe_ptr);
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapMaybeOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapMaybeFail");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeFail");
LLVMBuildCondBr(g->builder, nonnull_bit, ok_block, fail_block);
LLVMPositionBuilderAtEnd(g->builder, fail_block);
@@ -1730,8 +1774,18 @@ static LLVMValueRef ir_render_ref(CodeGen *g, IrExecutable *executable, IrInstru
}
}
static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
AstNode *source_node = instruction->source_node;
Scope *scope = instruction->scope;
assert(source_node);
assert(scope);
ZigLLVMSetCurrentDebugLocation(g->builder, source_node->line + 1, source_node->column + 1, get_di_scope(g, scope));
}
static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, IrInstruction *instruction) {
set_debug_source_node(g, instruction->source_node);
set_debug_location(g, instruction);
switch (instruction->id) {
case IrInstructionIdInvalid:
@@ -1961,7 +2015,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
}
}
case TypeTableEntryIdFn:
return const_val->data.x_fn->fn_value;
return fn_llvm_value(g, const_val->data.x_fn);
case TypeTableEntryIdPointer:
{
TypeTableEntry *child_type = type_entry->data.pointer.child_type;
@@ -2021,7 +2075,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
case TypeTableEntryIdNullLit:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdGenericFn:
case TypeTableEntryIdBoundFn:
case TypeTableEntryIdVar:
zig_unreachable();
@@ -2107,7 +2160,7 @@ static LLVMValueRef gen_test_fn_val(CodeGen *g, FnTableEntry *fn_entry) {
LLVMValueRef name_val = LLVMConstStruct(name_fields, 2, false);
LLVMValueRef fields[] = {
name_val,
fn_entry->fn_value,
fn_llvm_value(g, fn_entry),
};
return LLVMConstStruct(fields, 2, false);
}
@@ -2157,7 +2210,7 @@ static void build_all_basic_blocks(CodeGen *g, FnTableEntry *fn) {
assert(executable->basic_block_list.length > 0);
for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) {
IrBasicBlock *bb = executable->basic_block_list.at(block_i);
bb->llvm_block = LLVMAppendBasicBlock(fn->fn_value, bb->name_hint);
bb->llvm_block = LLVMAppendBasicBlock(fn_llvm_value(g, fn), bb->name_hint);
}
IrBasicBlock *entry_bb = executable->basic_block_list.at(0);
LLVMPositionBuilderAtEnd(g->builder, entry_bb->llvm_block);
@@ -2167,11 +2220,14 @@ static void gen_global_var(CodeGen *g, VariableTableEntry *var, LLVMValueRef ini
TypeTableEntry *type_entry)
{
assert(var->gen_is_const);
assert(var->import);
assert(type_entry);
ImportTableEntry *import = get_scope_import(var->parent_scope);
assert(import);
bool is_local_to_unit = true;
ZigLLVMCreateGlobalVariable(g->dbuilder, get_di_scope(g, var->parent_scope), buf_ptr(&var->name),
buf_ptr(&var->name), var->import->di_file, var->decl_node->line + 1,
buf_ptr(&var->name), import->di_file, var->decl_node->line + 1,
type_entry->di_type, is_local_to_unit, init_val);
}
@@ -2187,7 +2243,7 @@ static void do_code_gen(CodeGen *g) {
if (var->type->id == TypeTableEntryIdNumLitFloat) {
// Generate debug info for it but that's it.
ConstExprValue *const_val = &var->decl_node->data.variable_declaration.top_level_decl.value->static_value;
ConstExprValue *const_val = var->value;
assert(const_val->special != ConstValSpecialRuntime);
TypeTableEntry *var_type = g->builtin_types.entry_f64;
LLVMValueRef init_val = LLVMConstReal(var_type->type_ref, const_val->data.x_bignum.data.x_float);
@@ -2197,7 +2253,7 @@ static void do_code_gen(CodeGen *g) {
if (var->type->id == TypeTableEntryIdNumLitInt) {
// Generate debug info for it but that's it.
ConstExprValue *const_val = &var->decl_node->data.variable_declaration.top_level_decl.value->static_value;
ConstExprValue *const_val = var->value;
assert(const_val->special != ConstValSpecialRuntime);
TypeTableEntry *var_type = const_val->data.x_bignum.is_negative ?
g->builtin_types.entry_isize : g->builtin_types.entry_usize;
@@ -2222,13 +2278,12 @@ static void do_code_gen(CodeGen *g) {
LLVMSetLinkage(global_value, LLVMExternalLinkage);
} else {
IrInstruction *instruction = var->decl_node->data.variable_declaration.top_level_decl.value;
render_const_val(g, instruction->type_entry, &instruction->static_value);
render_const_val_global(g, instruction->type_entry, &instruction->static_value);
global_value = instruction->static_value.llvm_global;
render_const_val(g, var->type, var->value);
render_const_val_global(g, var->type, var->value);
global_value = var->value->llvm_global;
// TODO debug info for function pointers
if (var->gen_is_const && var->type->id != TypeTableEntryIdFn) {
gen_global_var(g, var, instruction->static_value.llvm_value, var->type);
gen_global_var(g, var, var->value->llvm_value, var->type);
}
}
@@ -2246,12 +2301,8 @@ static void do_code_gen(CodeGen *g) {
// Generate function prototypes
for (size_t fn_proto_i = 0; fn_proto_i < g->fn_protos.length; fn_proto_i += 1) {
FnTableEntry *fn_table_entry = g->fn_protos.at(fn_proto_i);
if (should_skip_fn_codegen(g, fn_table_entry)) {
// huge time saver
LLVMDeleteFunction(fn_table_entry->fn_value);
fn_table_entry->fn_value = nullptr;
if (should_skip_fn_codegen(g, fn_table_entry))
continue;
}
AstNode *proto_node = fn_table_entry->proto_node;
assert(proto_node->type == NodeTypeFnProto);
@@ -2259,16 +2310,18 @@ static void do_code_gen(CodeGen *g) {
TypeTableEntry *fn_type = fn_table_entry->type_entry;
LLVMValueRef fn_val = fn_llvm_value(g, fn_table_entry);
if (!type_has_bits(fn_type->data.fn.fn_type_id.return_type)) {
// nothing to do
} else if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdPointer) {
ZigLLVMAddNonNullAttr(fn_table_entry->fn_value, 0);
ZigLLVMAddNonNullAttr(fn_val, 0);
} else if (handle_is_ptr(fn_type->data.fn.fn_type_id.return_type) &&
!fn_type->data.fn.fn_type_id.is_extern)
{
LLVMValueRef first_arg = LLVMGetParam(fn_table_entry->fn_value, 0);
LLVMValueRef first_arg = LLVMGetParam(fn_val, 0);
LLVMAddAttribute(first_arg, LLVMStructRetAttribute);
ZigLLVMAddNonNullAttr(fn_table_entry->fn_value, 1);
ZigLLVMAddNonNullAttr(fn_val, 1);
}
@@ -2286,7 +2339,7 @@ static void do_code_gen(CodeGen *g) {
}
TypeTableEntry *param_type = info->type;
LLVMValueRef argument_val = LLVMGetParam(fn_table_entry->fn_value, gen_index);
LLVMValueRef argument_val = LLVMGetParam(fn_val, gen_index);
bool param_is_noalias = param_node->data.param_decl.is_noalias;
if (param_is_noalias) {
LLVMAddAttribute(argument_val, LLVMNoAliasAttribute);
@@ -2295,7 +2348,7 @@ static void do_code_gen(CodeGen *g) {
LLVMAddAttribute(argument_val, LLVMReadOnlyAttribute);
}
if (param_type->id == TypeTableEntryIdPointer) {
ZigLLVMAddNonNullAttr(fn_table_entry->fn_value, gen_index + 1);
ZigLLVMAddNonNullAttr(fn_val, gen_index + 1);
}
if (is_byval) {
// TODO
@@ -2345,14 +2398,13 @@ static void do_code_gen(CodeGen *g) {
// Generate function definitions.
for (size_t fn_i = 0; fn_i < g->fn_defs.length; fn_i += 1) {
FnTableEntry *fn_table_entry = g->fn_defs.at(fn_i);
if (should_skip_fn_codegen(g, fn_table_entry)) {
// huge time saver
if (should_skip_fn_codegen(g, fn_table_entry))
continue;
}
ImportTableEntry *import = fn_table_entry->import_entry;
LLVMValueRef fn = fn_table_entry->fn_value;
LLVMValueRef fn = fn_llvm_value(g, fn_table_entry);
g->cur_fn = fn_table_entry;
g->cur_fn_val = fn;
if (handle_is_ptr(fn_table_entry->type_entry->data.fn.fn_type_id.return_type)) {
g->cur_ret_ptr = LLVMGetParam(fn, 0);
} else {
@@ -2401,7 +2453,18 @@ static void do_code_gen(CodeGen *g) {
if (var->is_inline)
continue;
if (var->parent_scope->node->type == NodeTypeFnDef) {
if (var->src_arg_index == SIZE_MAX) {
var->value_ref = LLVMBuildAlloca(g->builder, var->type->type_ref, buf_ptr(&var->name));
unsigned align_bytes = ZigLLVMGetPrefTypeAlignment(g->target_data_ref, var->type->type_ref);
LLVMSetAlignment(var->value_ref, align_bytes);
var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
buf_ptr(&var->name), import->di_file, var->decl_node->line + 1,
var->type->di_type, !g->strip_debug_symbols, 0);
} else {
assert(var->gen_arg_index != SIZE_MAX);
TypeTableEntry *gen_type;
if (handle_is_ptr(var->type)) {
@@ -2417,31 +2480,21 @@ static void do_code_gen(CodeGen *g) {
buf_ptr(&var->name), import->di_file, var->decl_node->line + 1,
gen_type->di_type, !g->strip_debug_symbols, 0, var->gen_arg_index + 1);
} else {
var->value_ref = LLVMBuildAlloca(g->builder, var->type->type_ref, buf_ptr(&var->name));
unsigned align_bytes = ZigLLVMGetPrefTypeAlignment(g->target_data_ref, var->type->type_ref);
LLVMSetAlignment(var->value_ref, align_bytes);
var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
buf_ptr(&var->name), import->di_file, var->decl_node->line + 1,
var->type->di_type, !g->strip_debug_symbols, 0);
}
}
// create debug variable declarations for parameters
// rely on the first variables in the variable_list being parameters.
size_t next_var_i = 0;
for (size_t param_i = 0; param_i < fn_proto->params.length; param_i += 1) {
AstNode *param_decl = fn_proto->params.at(param_i);
assert(param_decl->type == NodeTypeParamDecl);
FnGenParamInfo *info = &fn_table_entry->type_entry->data.fn.gen_param_info[param_i];
if (info->gen_index == SIZE_MAX) {
if (info->gen_index == SIZE_MAX)
continue;
}
VariableTableEntry *variable = param_decl->data.param_decl.variable;
VariableTableEntry *variable = fn_table_entry->variable_list.at(next_var_i);
assert(variable->src_arg_index != SIZE_MAX);
next_var_i += 1;
assert(variable);
assert(variable->value_ref);
@@ -3308,7 +3361,6 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) {
zig_panic("TODO");
case TypeTableEntryIdInvalid:
case TypeTableEntryIdMetaType:
case TypeTableEntryIdGenericFn:
case TypeTableEntryIdBoundFn:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
@@ -3343,7 +3395,7 @@ void codegen_generate_h_file(CodeGen *g) {
assert(proto_node->type == NodeTypeFnProto);
AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
if (fn_proto->top_level_decl.visib_mod != VisibModExport)
if (fn_proto->visib_mod != VisibModExport)
continue;
FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id;