authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-01-14 16:26:06-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-01-14 16:26:06-05:00
logf0df2cdde9181f954dc124dab004663e56c86d0f
treefc84680c0922149bcb6cbcb7dc9edfb44441d984
parentfa024f80924d35e4aac4b4edcac88193def03175

error return traces use a zig-provided function to save binary size


2 files changed, 87 insertions(+), 27 deletions(-)

src/all_types.hpp+2
...@@ -1574,6 +1574,8 @@ struct CodeGen {...@@ -1574,6 +1574,8 @@ struct CodeGen {
1574 size_t largest_err_name_len;1574 size_t largest_err_name_len;
1575 LLVMValueRef safety_crash_err_fn;1575 LLVMValueRef safety_crash_err_fn;
15761576
1577 LLVMValueRef return_err_fn;
1578
1577 IrInstruction *invalid_instruction;1579 IrInstruction *invalid_instruction;
1578 ConstExprValue const_void_val;1580 ConstExprValue const_void_val;
15791581
src/codegen.cpp+85-27
...@@ -892,7 +892,8 @@ static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace...@@ -892,7 +892,8 @@ static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace
892 msg_arg,892 msg_arg,
893 stack_trace_arg,893 stack_trace_arg,
894 };894 };
895 ZigLLVMBuildCall(g->builder, fn_val, args, 2, llvm_cc, ZigLLVM_FnInlineAuto, "");895 LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, fn_val, args, 2, llvm_cc, ZigLLVM_FnInlineAuto, "");
896 LLVMSetTailCall(call_instruction, true);
896 LLVMBuildUnreachable(g->builder);897 LLVMBuildUnreachable(g->builder);
897}898}
898899
...@@ -919,6 +920,79 @@ static LLVMValueRef get_memcpy_fn_val(CodeGen *g) {...@@ -919,6 +920,79 @@ static LLVMValueRef get_memcpy_fn_val(CodeGen *g) {
919 return g->memcpy_fn_val;920 return g->memcpy_fn_val;
920}921}
921922
923static LLVMValueRef get_return_err_fn(CodeGen *g) {
924 if (g->return_err_fn != nullptr)
925 return g->return_err_fn;
926
927 assert(g->err_tag_type != nullptr);
928
929 LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
930
931 LLVMTypeRef arg_types[] = {
932 // error return trace pointer
933 get_ptr_to_stack_trace_type(g)->type_ref,
934 // return address
935 ptr_u8,
936 };
937 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false);
938
939 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_return_error"), false);
940 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
941 addLLVMFnAttr(fn_val, "cold");
942 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
943 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
944 addLLVMFnAttr(fn_val, "nounwind");
945 add_uwtable_attr(g, fn_val);
946 addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
947 addLLVMArgAttr(fn_val, (unsigned)1, "nonnull");
948 if (g->build_mode == BuildModeDebug) {
949 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
950 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
951 }
952
953 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
954 LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
955 LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder);
956 LLVMPositionBuilderAtEnd(g->builder, entry_block);
957 ZigLLVMClearCurrentDebugLocation(g->builder);
958
959 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->type_ref;
960
961 // stack_trace.instruction_addresses[stack_trace.index % stack_trace_ptr_count] = return_address;
962
963 LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0);
964 size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
965 LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, err_ret_trace_ptr, (unsigned)index_field_index, "");
966 size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
967 LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, err_ret_trace_ptr, (unsigned)addresses_field_index, "");
968
969 LLVMValueRef index_val = gen_load_untyped(g, index_field_ptr, 0, false, "");
970 LLVMValueRef modded_val = LLVMBuildURem(g->builder, index_val, LLVMConstInt(usize_type_ref, stack_trace_ptr_count, false), "");
971 LLVMValueRef address_indices[] = {
972 LLVMConstNull(usize_type_ref),
973 modded_val,
974 };
975 LLVMValueRef address_slot = LLVMBuildInBoundsGEP(g->builder, addresses_field_ptr, address_indices, 2, "");
976
977 LLVMValueRef return_address = LLVMBuildPtrToInt(g->builder, LLVMGetParam(fn_val, 1), usize_type_ref, "");
978
979 LLVMValueRef address_value = LLVMBuildPtrToInt(g->builder, return_address, usize_type_ref, "");
980 gen_store_untyped(g, address_value, address_slot, 0, false);
981
982 // stack_trace.index += 1;
983 LLVMValueRef index_plus_one_val = LLVMBuildAdd(g->builder, index_val, LLVMConstInt(usize_type_ref, 1, false), "");
984 gen_store_untyped(g, index_plus_one_val, index_field_ptr, 0, false);
985
986 // return;
987 LLVMBuildRetVoid(g->builder);
988
989 LLVMPositionBuilderAtEnd(g->builder, prev_block);
990 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
991
992 g->return_err_fn = fn_val;
993 return fn_val;
994}
995
922static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {996static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
923 if (g->safety_crash_err_fn != nullptr)997 if (g->safety_crash_err_fn != nullptr)
924 return g->safety_crash_err_fn;998 return g->safety_crash_err_fn;
...@@ -1053,8 +1127,9 @@ static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) {...@@ -1053,8 +1127,9 @@ static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) {
1053 err_val,1127 err_val,
1054 err_ret_trace_val,1128 err_ret_trace_val,
1055 };1129 };
1056 ZigLLVMBuildCall(g->builder, safety_crash_err_fn, args, 2, get_llvm_cc(g, CallingConventionUnspecified),1130 LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, safety_crash_err_fn, args, 2, get_llvm_cc(g, CallingConventionUnspecified),
1057 ZigLLVM_FnInlineAuto, "");1131 ZigLLVM_FnInlineAuto, "");
1132 LLVMSetTailCall(call_instruction, true);
1058 LLVMBuildUnreachable(g->builder);1133 LLVMBuildUnreachable(g->builder);
1059}1134}
10601135
...@@ -1346,36 +1421,19 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns...@@ -1346,36 +1421,19 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns
1346 is_err_return = true;1421 is_err_return = true;
1347 }1422 }
1348 if (is_err_return) {1423 if (is_err_return) {
1349 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->type_ref;
1350
1351 // stack_trace.instruction_addresses[stack_trace.index % stack_trace_ptr_count] = @instructionPointer();
1352 // stack_trace.index += 1;
1353
1354 LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn_val, "ReturnError");1424 LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn_val, "ReturnError");
1355
1356 LLVMValueRef block_address = LLVMBlockAddress(g->cur_fn_val, return_block);1425 LLVMValueRef block_address = LLVMBlockAddress(g->cur_fn_val, return_block);
1357 size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
1358 LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val, (unsigned)index_field_index, "");
1359 size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
1360 LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val, (unsigned)addresses_field_index, "");
1361
1362 // stack_trace.instruction_addresses[stack_trace.index % stack_trace_ptr_count] = @instructionPointer();
1363 LLVMValueRef index_val = gen_load_untyped(g, index_field_ptr, 0, false, "");
1364 LLVMValueRef modded_val = LLVMBuildURem(g->builder, index_val, LLVMConstInt(usize_type_ref, stack_trace_ptr_count, false), "");
1365 LLVMValueRef address_indices[] = {
1366 LLVMConstNull(usize_type_ref),
1367 modded_val,
1368 };
1369 LLVMValueRef address_slot = LLVMBuildInBoundsGEP(g->builder, addresses_field_ptr, address_indices, 2, "");
1370 LLVMValueRef address_value = LLVMBuildPtrToInt(g->builder, block_address, usize_type_ref, "");
1371 gen_store_untyped(g, address_value, address_slot, 0, false);
1372
1373 // stack_trace.index += 1;
1374 LLVMValueRef index_plus_one_val = LLVMBuildAdd(g->builder, index_val, LLVMConstInt(usize_type_ref, 1, false), "");
1375 gen_store_untyped(g, index_plus_one_val, index_field_ptr, 0, false);
13761426
1427 LLVMValueRef return_err_fn = get_return_err_fn(g);
1428 LLVMValueRef args[] = {
1429 g->cur_err_ret_trace_val,
1430 block_address,
1431 };
1377 LLVMBuildBr(g->builder, return_block);1432 LLVMBuildBr(g->builder, return_block);
1378 LLVMPositionBuilderAtEnd(g->builder, return_block);1433 LLVMPositionBuilderAtEnd(g->builder, return_block);
1434 LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 2,
1435 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
1436 LLVMSetTailCall(call_instruction, true);
1379 }1437 }
1380 if (handle_is_ptr(return_type)) {1438 if (handle_is_ptr(return_type)) {
1381 if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) {1439 if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) {