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 {
11781178 LLVMValueRef trap_fn_val;
11791179 bool error_during_imports;
11801180 uint32_t next_node_index;
1181 ZigList<AstNode *> error_decls;
11821181 TypeTableEntry *err_tag_type;
11831182 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]
11841183 LLVMValueRef int_builtin_fns[2][4]; // [0-ctz,1-clz][0-8,1-16,2-32,3-64]
......@@ -1191,7 +1190,9 @@ struct CodeGen {
11911190
11921191 bool check_unused;
11931192
1193 ZigList<AstNode *> error_decls;
11941194 bool generate_error_name_table;
1195 LLVMValueRef err_name_table;
11951196};
11961197
11971198struct VariableTableEntry {
src/analyze.cpp+1-1
......@@ -454,7 +454,7 @@ static void slice_type_common_init(CodeGen *g, TypeTableEntry *child_type,
454454 entry->data.structure.fields[1].gen_index = 1;
455455}
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) {
458458 assert(child_type->id != TypeTableEntryIdInvalid);
459459 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 *
2626TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id);
2727TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type);
2828TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t array_size);
29TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);
2930TypeTableEntry *get_partial_container_type(CodeGen *g, ImportTableEntry *import,
3031 ContainerKind kind, AstNode *decl_node, const char *name);
3132TypeTableEntry *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
331331}
332332
333333static LLVMValueRef gen_err_name(CodeGen *g, AstNode *node) {
334 zig_panic("TODO");
335 //assert(node->type == NodeTypeFnCallExpr);
336 //assert(g->generate_error_name_table);
337 //AstNode *err_val_node = node->data.fn_call_expr.params.at(0);
338 //LLVMValueRef err_val = gen_expr(g, err_val_node);
339 //arg
334 assert(node->type == NodeTypeFnCallExpr);
335 assert(g->generate_error_name_table);
336
337 if (g->error_decls.length == 1) {
338 LLVMBuildUnreachable(g->builder);
339 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, "");
340373}
341374
342375static 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) {
30303063 return LLVMConstStruct(fields, 2, false);
30313064}
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
30333106static void do_code_gen(CodeGen *g) {
30343107 assert(!g->errors.length);
30353108
......@@ -3037,6 +3110,7 @@ static void do_code_gen(CodeGen *g) {
30373110
30383111
30393112 gen_const_globals(g);
3113 generate_error_name_table(g);
30403114
30413115 // Generate module level variables
30423116 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) {
99
1010pub 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 {
1313 if (a.len != b.len) return false;
1414 for (a) |item, index| {
1515 if (b[index] != item) return false;
test/self_hosted.zig+9
......@@ -566,3 +566,12 @@ fn accepts_string(foo: []u8) { }
566566fn hex_escape() {
567567 assert(str_eql("\x68\x65\x6c\x6c\x6f", "hello"));
568568}
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}