authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-04-09 08:55:53-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-04-09 08:55:53-07:00
log7a05e18efb35330475e7ee6253f9fec6103c560f
tree6f2f2d193a186b830caf968b60abb71843092965
parentd5d6c93da41b47f483e250b212e1d4459a962893

implement @err_name builtin function


6 files changed, 94 insertions(+), 9 deletions(-)

src/all_types.hpp+2-1
...@@ -1178,7 +1178,6 @@ struct CodeGen {...@@ -1178,7 +1178,6 @@ struct CodeGen {
1178 LLVMValueRef trap_fn_val;1178 LLVMValueRef trap_fn_val;
1179 bool error_during_imports;1179 bool error_during_imports;
1180 uint32_t next_node_index;1180 uint32_t next_node_index;
1181 ZigList<AstNode *> error_decls;
1182 TypeTableEntry *err_tag_type;1181 TypeTableEntry *err_tag_type;
1183 LLVMValueRef int_overflow_fns[2][3][4]; // [0-signed,1-unsigned][0-add,1-sub,2-mul][0-8,1-16,2-32,3-64]1182 LLVMValueRef int_overflow_fns[2][3][4]; // [0-signed,1-unsigned][0-add,1-sub,2-mul][0-8,1-16,2-32,3-64]
1184 LLVMValueRef int_builtin_fns[2][4]; // [0-ctz,1-clz][0-8,1-16,2-32,3-64]1183 LLVMValueRef int_builtin_fns[2][4]; // [0-ctz,1-clz][0-8,1-16,2-32,3-64]
...@@ -1191,7 +1190,9 @@ struct CodeGen {...@@ -1191,7 +1190,9 @@ struct CodeGen {
11911190
1192 bool check_unused;1191 bool check_unused;
11931192
1193 ZigList<AstNode *> error_decls;
1194 bool generate_error_name_table;1194 bool generate_error_name_table;
1195 LLVMValueRef err_name_table;
1195};1196};
11961197
1197struct VariableTableEntry {1198struct VariableTableEntry {
src/analyze.cpp+1-1
...@@ -454,7 +454,7 @@ static void slice_type_common_init(CodeGen *g, TypeTableEntry *child_type,...@@ -454,7 +454,7 @@ static void slice_type_common_init(CodeGen *g, TypeTableEntry *child_type,
454 entry->data.structure.fields[1].gen_index = 1;454 entry->data.structure.fields[1].gen_index = 1;
455}455}
456456
457static TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) {457TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) {
458 assert(child_type->id != TypeTableEntryIdInvalid);458 assert(child_type->id != TypeTableEntryIdInvalid);
459 TypeTableEntry **parent_pointer = &child_type->unknown_size_array_parent[(is_const ? 1 : 0)];459 TypeTableEntry **parent_pointer = &child_type->unknown_size_array_parent[(is_const ? 1 : 0)];
460460
src/analyze.hpp+1
...@@ -26,6 +26,7 @@ TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry *...@@ -26,6 +26,7 @@ TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry *
26TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id);26TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id);
27TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type);27TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type);
28TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t array_size);28TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t array_size);
29TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);
29TypeTableEntry *get_partial_container_type(CodeGen *g, ImportTableEntry *import,30TypeTableEntry *get_partial_container_type(CodeGen *g, ImportTableEntry *import,
30 ContainerKind kind, AstNode *decl_node, const char *name);31 ContainerKind kind, AstNode *decl_node, const char *name);
31TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x);32TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x);
src/codegen.cpp+80-6
...@@ -331,12 +331,45 @@ static LLVMValueRef get_handle_value(CodeGen *g, AstNode *source_node, LLVMValue...@@ -331,12 +331,45 @@ static LLVMValueRef get_handle_value(CodeGen *g, AstNode *source_node, LLVMValue
331}331}
332332
333static LLVMValueRef gen_err_name(CodeGen *g, AstNode *node) {333static LLVMValueRef gen_err_name(CodeGen *g, AstNode *node) {
334 zig_panic("TODO");334 assert(node->type == NodeTypeFnCallExpr);
335 //assert(node->type == NodeTypeFnCallExpr);335 assert(g->generate_error_name_table);
336 //assert(g->generate_error_name_table);336
337 //AstNode *err_val_node = node->data.fn_call_expr.params.at(0);337 if (g->error_decls.length == 1) {
338 //LLVMValueRef err_val = gen_expr(g, err_val_node);338 LLVMBuildUnreachable(g->builder);
339 //arg339 return nullptr;
340 }
341
342
343 AstNode *err_val_node = node->data.fn_call_expr.params.at(0);
344 LLVMValueRef err_val = gen_expr(g, err_val_node);
345 add_debug_source_node(g, node);
346
347 if (!g->is_release_build) {
348 LLVMBasicBlockRef bounds_check_fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoundsCheckFail");
349 LLVMBasicBlockRef lower_ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "LowerBoundsCheckOk");
350 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoundsCheckOk");
351
352 LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(err_val));
353 LLVMValueRef is_zero_val = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, zero, "");
354 LLVMBuildCondBr(g->builder, is_zero_val, bounds_check_fail_block, lower_ok_block);
355
356 LLVMPositionBuilderAtEnd(g->builder, bounds_check_fail_block);
357 LLVMBuildCall(g->builder, g->trap_fn_val, nullptr, 0, "");
358 LLVMBuildUnreachable(g->builder);
359
360 LLVMPositionBuilderAtEnd(g->builder, lower_ok_block);
361 LLVMValueRef end_val = LLVMConstInt(LLVMTypeOf(err_val), g->error_decls.length, false);
362 LLVMValueRef is_too_big_val = LLVMBuildICmp(g->builder, LLVMIntUGE, err_val, end_val, "");
363 LLVMBuildCondBr(g->builder, is_too_big_val, bounds_check_fail_block, ok_block);
364
365 LLVMPositionBuilderAtEnd(g->builder, ok_block);
366 }
367
368 LLVMValueRef indices[] = {
369 LLVMConstNull(g->builtin_types.entry_isize->type_ref),
370 err_val,
371 };
372 return LLVMBuildInBoundsGEP(g->builder, g->err_name_table, indices, 2, "");
340}373}
341374
342static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {375static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
...@@ -3030,6 +3063,46 @@ static LLVMValueRef gen_test_fn_val(CodeGen *g, FnTableEntry *fn_entry) {...@@ -3030,6 +3063,46 @@ static LLVMValueRef gen_test_fn_val(CodeGen *g, FnTableEntry *fn_entry) {
3030 return LLVMConstStruct(fields, 2, false);3063 return LLVMConstStruct(fields, 2, false);
3031}3064}
30323065
3066static void generate_error_name_table(CodeGen *g) {
3067 if (!g->generate_error_name_table || g->error_decls.length == 1) {
3068 return;
3069 }
3070
3071 assert(g->error_decls.length > 0);
3072
3073 TypeTableEntry *str_type = get_slice_type(g, g->builtin_types.entry_u8, true);
3074 TypeTableEntry *u8_ptr_type = str_type->data.structure.fields[0].type_entry;
3075
3076 LLVMValueRef *values = allocate<LLVMValueRef>(g->error_decls.length);
3077 values[0] = LLVMGetUndef(str_type->type_ref);
3078 for (int i = 1; i < g->error_decls.length; i += 1) {
3079 AstNode *error_decl_node = g->error_decls.at(i);
3080 assert(error_decl_node->type == NodeTypeErrorValueDecl);
3081 Buf *name = &error_decl_node->data.error_value_decl.name;
3082
3083 LLVMValueRef str_init = LLVMConstString(buf_ptr(name), buf_len(name), true);
3084 LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), "");
3085 LLVMSetInitializer(str_global, str_init);
3086 LLVMSetLinkage(str_global, LLVMPrivateLinkage);
3087 LLVMSetGlobalConstant(str_global, true);
3088 LLVMSetUnnamedAddr(str_global, true);
3089
3090 LLVMValueRef fields[] = {
3091 LLVMConstBitCast(str_global, u8_ptr_type->type_ref),
3092 LLVMConstInt(g->builtin_types.entry_isize->type_ref, buf_len(name), false),
3093 };
3094 values[i] = LLVMConstNamedStruct(str_type->type_ref, fields, 2);
3095 }
3096
3097 LLVMValueRef err_name_table_init = LLVMConstArray(str_type->type_ref, values, g->error_decls.length);
3098
3099 g->err_name_table = LLVMAddGlobal(g->module, LLVMTypeOf(err_name_table_init), "err_name_table");
3100 LLVMSetInitializer(g->err_name_table, err_name_table_init);
3101 LLVMSetLinkage(g->err_name_table, LLVMPrivateLinkage);
3102 LLVMSetGlobalConstant(g->err_name_table, true);
3103 LLVMSetUnnamedAddr(g->err_name_table, true);
3104}
3105
3033static void do_code_gen(CodeGen *g) {3106static void do_code_gen(CodeGen *g) {
3034 assert(!g->errors.length);3107 assert(!g->errors.length);
30353108
...@@ -3037,6 +3110,7 @@ static void do_code_gen(CodeGen *g) {...@@ -3037,6 +3110,7 @@ static void do_code_gen(CodeGen *g) {
30373110
30383111
3039 gen_const_globals(g);3112 gen_const_globals(g);
3113 generate_error_name_table(g);
30403114
3041 // Generate module level variables3115 // Generate module level variables
3042 for (int i = 0; i < g->global_vars.length; i += 1) {3116 for (int i = 0; i < g->global_vars.length; i += 1) {
std/index.zig+1-1
...@@ -9,7 +9,7 @@ pub fn assert(b: bool) {...@@ -9,7 +9,7 @@ pub fn assert(b: bool) {
99
10pub const str_eql = slice_eql(u8);10pub const str_eql = slice_eql(u8);
1111
12pub fn slice_eql(T: type)(a: []T, b: []T) -> bool {12pub fn slice_eql(T: type)(a: []const T, b: []const T) -> bool {
13 if (a.len != b.len) return false;13 if (a.len != b.len) return false;
14 for (a) |item, index| {14 for (a) |item, index| {
15 if (b[index] != item) return false;15 if (b[index] != item) return false;
test/self_hosted.zig+9
...@@ -566,3 +566,12 @@ fn accepts_string(foo: []u8) { }...@@ -566,3 +566,12 @@ fn accepts_string(foo: []u8) { }
566fn hex_escape() {566fn hex_escape() {
567 assert(str_eql("\x68\x65\x6c\x6c\x6f", "hello"));567 assert(str_eql("\x68\x65\x6c\x6c\x6f", "hello"));
568}568}
569
570
571error AnError;
572error ALongerErrorName;
573#attribute("test")
574fn error_name_string() {
575 assert(str_eql(@err_name(error.AnError), "AnError"));
576 assert(str_eql(@err_name(error.ALongerErrorName), "ALongerErrorName"));
577}