aboutsummaryrefslogtreecommitdiff
path: root/src/codegen.cpp
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2016-12-01 23:25:09 -0500
committerAndrew Kelley <superjoe30@gmail.com>2016-12-04 03:40:40 -0500
commit2f259b8176184f063f555aed34087cf7560124fb (patch)
treeb4e1cc89b32673c159c68a46ba1e0683ea208102 /src/codegen.cpp
parentf6cbb73c7402fc100bbfb26c1a35c9f23b3f36ff (diff)
downloadzig-2f259b8176184f063f555aed34087cf7560124fb.tar.gz
zig-2f259b8176184f063f555aed34087cf7560124fb.zip
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.
Diffstat (limited to 'src/codegen.cpp')
-rw-r--r--src/codegen.cpp284
1 files changed, 168 insertions, 116 deletions
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 26ca633b8d..8b8650a546 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -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) {
+static bool ir_want_debug_safety(CodeGen *g, IrInstruction *instruction) {
+ 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);
+ // 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;