authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-02-09 02:50:03-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-02-09 03:09:25-05:00
logfc100d7b3b27bd514dca4e02c160e5b96d4da648
treeb365fbdf02c7a35d81d9037a15e1e3917a6e77de
parent8a859afd580f438f549ee69a3e3487eb5d119fad

lots of miscellaneous things all in one big commit

* add `@compileLog(...)` builtin function - Helps debug code running at compile time - See #240 * fix crash when there is an error on the start value of a slice * add implicit cast from int and float types to int and float literals if the value is known at compile time * make array concatenation work with slices in addition to arrays and c string literals * fix compile error message for something not having field access * fix crash when `@setDebugSafety()` was called from a function being evaluated at compile-time * fix compile-time evaluation of overflow math builtins. * avoid debug safety panic handler in builtin.o and compiler_rt.o since we use no debug safety in these modules anyway * add compiler_rt functions for division on ARM - Closes #254 * move default panic handler to std.debug so users can call it manually * std.io.printf supports a width in the format specifier

15 files changed, 622 insertions(+), 78 deletions(-)

doc/langref.md+16-3
...@@ -639,10 +639,23 @@ const b: u8 = @truncate(u8, a);...@@ -639,10 +639,23 @@ const b: u8 = @truncate(u8, a);
639639
640### @compileError(comptime msg: []u8)640### @compileError(comptime msg: []u8)
641641
642This function, when semantically analyzed, causes a compile error with the message `msg`.642This function, when semantically analyzed, causes a compile error with the
643message `msg`.
643644
644There are several ways that code avoids being semantically checked, such as using `if`645There are several ways that code avoids being semantically checked, such as
645or `switch` with compile time constants, and comptime functions.646using `if` or `switch` with compile time constants, and comptime functions.
647
648### @compileLog(args: ...)
649
650This function, when semantically analyzed, causes a compile error, but it does
651not prevent compile-time code from continuing to run, and it otherwise does not
652interfere with analysis.
653
654Each of the arguments will be serialized to a printable debug value and output
655to stderr, and then a newline at the end.
656
657This function can be used to do "printf debugging" on compile-time executing
658code.
646659
647### @intType(comptime is_signed: bool, comptime bit_count: u8) -> type660### @intType(comptime is_signed: bool, comptime bit_count: u8) -> type
648661
src/all_types.hpp+9
...@@ -1096,6 +1096,7 @@ enum BuiltinFnId {...@@ -1096,6 +1096,7 @@ enum BuiltinFnId {
1096 BuiltinFnIdCUndef,1096 BuiltinFnIdCUndef,
1097 BuiltinFnIdCompileVar,1097 BuiltinFnIdCompileVar,
1098 BuiltinFnIdCompileErr,1098 BuiltinFnIdCompileErr,
1099 BuiltinFnIdCompileLog,
1099 BuiltinFnIdGeneratedCode,1100 BuiltinFnIdGeneratedCode,
1100 BuiltinFnIdCtz,1101 BuiltinFnIdCtz,
1101 BuiltinFnIdClz,1102 BuiltinFnIdClz,
...@@ -1541,6 +1542,7 @@ enum IrInstructionId {...@@ -1541,6 +1542,7 @@ enum IrInstructionId {
1541 IrInstructionIdMinValue,1542 IrInstructionIdMinValue,
1542 IrInstructionIdMaxValue,1543 IrInstructionIdMaxValue,
1543 IrInstructionIdCompileErr,1544 IrInstructionIdCompileErr,
1545 IrInstructionIdCompileLog,
1544 IrInstructionIdErrName,1546 IrInstructionIdErrName,
1545 IrInstructionIdEmbedFile,1547 IrInstructionIdEmbedFile,
1546 IrInstructionIdCmpxchg,1548 IrInstructionIdCmpxchg,
...@@ -1993,6 +1995,13 @@ struct IrInstructionCompileErr {...@@ -1993,6 +1995,13 @@ struct IrInstructionCompileErr {
1993 IrInstruction *msg;1995 IrInstruction *msg;
1994};1996};
19951997
1998struct IrInstructionCompileLog {
1999 IrInstruction base;
2000
2001 size_t msg_count;
2002 IrInstruction **msg_list;
2003};
2004
1996struct IrInstructionErrName {2005struct IrInstructionErrName {
1997 IrInstruction base;2006 IrInstruction base;
19982007
src/analyze.cpp+23-1
...@@ -3439,7 +3439,8 @@ void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *...@@ -3439,7 +3439,8 @@ void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *
3439void render_const_value(Buf *buf, ConstExprValue *const_val) {3439void render_const_value(Buf *buf, ConstExprValue *const_val) {
3440 switch (const_val->special) {3440 switch (const_val->special) {
3441 case ConstValSpecialRuntime:3441 case ConstValSpecialRuntime:
3442 zig_unreachable();3442 buf_appendf(buf, "(runtime value)");
3443 return;
3443 case ConstValSpecialUndef:3444 case ConstValSpecialUndef:
3444 buf_appendf(buf, "undefined");3445 buf_appendf(buf, "undefined");
3445 return;3446 return;
...@@ -3522,7 +3523,28 @@ void render_const_value(Buf *buf, ConstExprValue *const_val) {...@@ -3522,7 +3523,28 @@ void render_const_value(Buf *buf, ConstExprValue *const_val) {
3522 }3523 }
3523 case TypeTableEntryIdArray:3524 case TypeTableEntryIdArray:
3524 {3525 {
3526 TypeTableEntry *child_type = canon_type->data.array.child_type;
3525 uint64_t len = canon_type->data.array.len;3527 uint64_t len = canon_type->data.array.len;
3528
3529 // if it's []u8, assume UTF-8 and output a string
3530 if (child_type->id == TypeTableEntryIdInt &&
3531 child_type->data.integral.bit_count == 8 &&
3532 !child_type->data.integral.is_signed)
3533 {
3534 buf_append_char(buf, '"');
3535 for (uint64_t i = 0; i < len; i += 1) {
3536 ConstExprValue *child_value = &const_val->data.x_array.elements[i];
3537 uint64_t x = child_value->data.x_bignum.data.x_uint;
3538 if (x == '"') {
3539 buf_append_str(buf, "\\\"");
3540 } else {
3541 buf_append_char(buf, x);
3542 }
3543 }
3544 buf_append_char(buf, '"');
3545 return;
3546 }
3547
3526 buf_appendf(buf, "%s{", buf_ptr(&canon_type->name));3548 buf_appendf(buf, "%s{", buf_ptr(&canon_type->name));
3527 for (uint64_t i = 0; i < len; i += 1) {3549 for (uint64_t i = 0; i < len; i += 1) {
3528 if (i != 0)3550 if (i != 0)
src/codegen.cpp+2
...@@ -2377,6 +2377,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -2377,6 +2377,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
2377 case IrInstructionIdMinValue:2377 case IrInstructionIdMinValue:
2378 case IrInstructionIdMaxValue:2378 case IrInstructionIdMaxValue:
2379 case IrInstructionIdCompileErr:2379 case IrInstructionIdCompileErr:
2380 case IrInstructionIdCompileLog:
2380 case IrInstructionIdArrayLen:2381 case IrInstructionIdArrayLen:
2381 case IrInstructionIdImport:2382 case IrInstructionIdImport:
2382 case IrInstructionIdCImport:2383 case IrInstructionIdCImport:
...@@ -3791,6 +3792,7 @@ static void define_builtin_fns(CodeGen *g) {...@@ -3791,6 +3792,7 @@ static void define_builtin_fns(CodeGen *g) {
3791 create_builtin_fn(g, BuiltinFnIdDivExact, "divExact", 2);3792 create_builtin_fn(g, BuiltinFnIdDivExact, "divExact", 2);
3792 create_builtin_fn(g, BuiltinFnIdTruncate, "truncate", 2);3793 create_builtin_fn(g, BuiltinFnIdTruncate, "truncate", 2);
3793 create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1);3794 create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1);
3795 create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX);
3794 create_builtin_fn(g, BuiltinFnIdIntType, "intType", 2);3796 create_builtin_fn(g, BuiltinFnIdIntType, "intType", 2);
3795 create_builtin_fn(g, BuiltinFnIdUnreachable, "unreachable", 0);3797 create_builtin_fn(g, BuiltinFnIdUnreachable, "unreachable", 0);
3796 create_builtin_fn(g, BuiltinFnIdSetFnTest, "setFnTest", 1);3798 create_builtin_fn(g, BuiltinFnIdSetFnTest, "setFnTest", 1);
src/ir.cpp+125-6
...@@ -375,6 +375,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCompileErr *) {...@@ -375,6 +375,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCompileErr *) {
375 return IrInstructionIdCompileErr;375 return IrInstructionIdCompileErr;
376}376}
377377
378static constexpr IrInstructionId ir_instruction_id(IrInstructionCompileLog *) {
379 return IrInstructionIdCompileLog;
380}
381
378static constexpr IrInstructionId ir_instruction_id(IrInstructionErrName *) {382static constexpr IrInstructionId ir_instruction_id(IrInstructionErrName *) {
379 return IrInstructionIdErrName;383 return IrInstructionIdErrName;
380}384}
...@@ -1510,6 +1514,20 @@ static IrInstruction *ir_build_compile_err(IrBuilder *irb, Scope *scope, AstNode...@@ -1510,6 +1514,20 @@ static IrInstruction *ir_build_compile_err(IrBuilder *irb, Scope *scope, AstNode
1510 return &instruction->base;1514 return &instruction->base;
1511}1515}
15121516
1517static IrInstruction *ir_build_compile_log(IrBuilder *irb, Scope *scope, AstNode *source_node,
1518 size_t msg_count, IrInstruction **msg_list)
1519{
1520 IrInstructionCompileLog *instruction = ir_build_instruction<IrInstructionCompileLog>(irb, scope, source_node);
1521 instruction->msg_count = msg_count;
1522 instruction->msg_list = msg_list;
1523
1524 for (size_t i = 0; i < msg_count; i += 1) {
1525 ir_ref_instruction(msg_list[i], irb->current_basic_block);
1526 }
1527
1528 return &instruction->base;
1529}
1530
1513static IrInstruction *ir_build_err_name(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {1531static IrInstruction *ir_build_err_name(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
1514 IrInstructionErrName *instruction = ir_build_instruction<IrInstructionErrName>(irb, scope, source_node);1532 IrInstructionErrName *instruction = ir_build_instruction<IrInstructionErrName>(irb, scope, source_node);
1515 instruction->value = value;1533 instruction->value = value;
...@@ -2461,6 +2479,12 @@ static IrInstruction *ir_instruction_compileerr_get_dep(IrInstructionCompileErr...@@ -2461,6 +2479,12 @@ static IrInstruction *ir_instruction_compileerr_get_dep(IrInstructionCompileErr
2461 }2479 }
2462}2480}
24632481
2482static IrInstruction *ir_instruction_compilelog_get_dep(IrInstructionCompileLog *instruction, size_t index) {
2483 if (index < instruction->msg_count)
2484 return instruction->msg_list[index];
2485 return nullptr;
2486}
2487
2464static IrInstruction *ir_instruction_errname_get_dep(IrInstructionErrName *instruction, size_t index) {2488static IrInstruction *ir_instruction_errname_get_dep(IrInstructionErrName *instruction, size_t index) {
2465 switch (index) {2489 switch (index) {
2466 case 0: return instruction->value;2490 case 0: return instruction->value;
...@@ -2848,6 +2872,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t...@@ -2848,6 +2872,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
2848 return ir_instruction_maxvalue_get_dep((IrInstructionMaxValue *) instruction, index);2872 return ir_instruction_maxvalue_get_dep((IrInstructionMaxValue *) instruction, index);
2849 case IrInstructionIdCompileErr:2873 case IrInstructionIdCompileErr:
2850 return ir_instruction_compileerr_get_dep((IrInstructionCompileErr *) instruction, index);2874 return ir_instruction_compileerr_get_dep((IrInstructionCompileErr *) instruction, index);
2875 case IrInstructionIdCompileLog:
2876 return ir_instruction_compilelog_get_dep((IrInstructionCompileLog *) instruction, index);
2851 case IrInstructionIdErrName:2877 case IrInstructionIdErrName:
2852 return ir_instruction_errname_get_dep((IrInstructionErrName *) instruction, index);2878 return ir_instruction_errname_get_dep((IrInstructionErrName *) instruction, index);
2853 case IrInstructionIdEmbedFile:2879 case IrInstructionIdEmbedFile:
...@@ -3767,7 +3793,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -3767,7 +3793,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
3767 BuiltinFnEntry *builtin_fn = entry->value;3793 BuiltinFnEntry *builtin_fn = entry->value;
3768 size_t actual_param_count = node->data.fn_call_expr.params.length;3794 size_t actual_param_count = node->data.fn_call_expr.params.length;
37693795
3770 if (builtin_fn->param_count != actual_param_count) {3796 if (builtin_fn->param_count != SIZE_MAX && builtin_fn->param_count != actual_param_count) {
3771 add_node_error(irb->codegen, node,3797 add_node_error(irb->codegen, node,
3772 buf_sprintf("expected %zu arguments, found %zu",3798 buf_sprintf("expected %zu arguments, found %zu",
3773 builtin_fn->param_count, actual_param_count));3799 builtin_fn->param_count, actual_param_count));
...@@ -3958,6 +3984,19 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -3958,6 +3984,19 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
39583984
3959 return ir_build_compile_err(irb, scope, node, arg0_value);3985 return ir_build_compile_err(irb, scope, node, arg0_value);
3960 }3986 }
3987 case BuiltinFnIdCompileLog:
3988 {
3989 IrInstruction **args = allocate<IrInstruction*>(actual_param_count);
3990
3991 for (size_t i = 0; i < actual_param_count; i += 1) {
3992 AstNode *arg_node = node->data.fn_call_expr.params.at(i);
3993 args[i] = ir_gen_node(irb, arg_node, scope);
3994 if (args[i] == irb->codegen->invalid_instruction)
3995 return irb->codegen->invalid_instruction;
3996 }
3997
3998 return ir_build_compile_log(irb, scope, node, actual_param_count, args);
3999 }
3961 case BuiltinFnIdErrName:4000 case BuiltinFnIdErrName:
3962 {4001 {
3963 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);4002 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
...@@ -5254,7 +5293,7 @@ static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node)...@@ -5254,7 +5293,7 @@ static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node)
5254 return irb->codegen->invalid_instruction;5293 return irb->codegen->invalid_instruction;
52555294
5256 IrInstruction *start_value = ir_gen_node(irb, start_node, scope);5295 IrInstruction *start_value = ir_gen_node(irb, start_node, scope);
5257 if (ptr_value == irb->codegen->invalid_instruction)5296 if (start_value == irb->codegen->invalid_instruction)
5258 return irb->codegen->invalid_instruction;5297 return irb->codegen->invalid_instruction;
52595298
5260 IrInstruction *end_value;5299 IrInstruction *end_value;
...@@ -5800,6 +5839,16 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,...@@ -5800,6 +5839,16 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
5800 }5839 }
5801 }5840 }
58025841
5842 // implicit typed number to integer or float literal.
5843 // works when the number is known
5844 if (value->value.special == ConstValSpecialStatic) {
5845 if (actual_type->id == TypeTableEntryIdInt && expected_type->id == TypeTableEntryIdNumLitInt) {
5846 return ImplicitCastMatchResultYes;
5847 } else if (actual_type->id == TypeTableEntryIdFloat && expected_type->id == TypeTableEntryIdNumLitFloat) {
5848 return ImplicitCastMatchResultYes;
5849 }
5850 }
5851
5803 // implicit undefined literal to anything5852 // implicit undefined literal to anything
5804 if (actual_type->id == TypeTableEntryIdUndefLit) {5853 if (actual_type->id == TypeTableEntryIdUndefLit) {
5805 return ImplicitCastMatchResultYes;5854 return ImplicitCastMatchResultYes;
...@@ -6654,6 +6703,19 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour...@@ -6654,6 +6703,19 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour
6654 return result;6703 return result;
6655}6704}
66566705
6706static IrInstruction *ir_analyze_number_to_literal(IrAnalyze *ira, IrInstruction *source_instr,
6707 IrInstruction *target, TypeTableEntry *wanted_type)
6708{
6709 ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
6710 if (!val)
6711 return ira->codegen->invalid_instruction;
6712
6713 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
6714 source_instr->source_node, wanted_type, true);
6715 bignum_init_bignum(&result->value.data.x_bignum, &val->data.x_bignum);
6716 return result;
6717}
6718
6657static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr,6719static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr,
6658 TypeTableEntry *wanted_type, IrInstruction *value)6720 TypeTableEntry *wanted_type, IrInstruction *value)
6659{6721{
...@@ -6858,6 +6920,15 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -6858,6 +6920,15 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
6858 }6920 }
6859 }6921 }
68606922
6923 // explicit cast from typed number to integer or float literal.
6924 // works when the number is known at compile time
6925 if (instr_is_comptime(value) &&
6926 ((actual_type->id == TypeTableEntryIdInt && wanted_type->id == TypeTableEntryIdNumLitInt) ||
6927 (actual_type->id == TypeTableEntryIdFloat && wanted_type->id == TypeTableEntryIdNumLitFloat)))
6928 {
6929 return ir_analyze_number_to_literal(ira, source_instr, value, wanted_type);
6930 }
6931
6861 // explicit cast from %void to integer type which can fit it6932 // explicit cast from %void to integer type which can fit it
6862 bool actual_type_is_void_err = actual_type->id == TypeTableEntryIdErrorUnion &&6933 bool actual_type_is_void_err = actual_type->id == TypeTableEntryIdErrorUnion &&
6863 !type_has_bits(actual_type->data.error.child_type);6934 !type_has_bits(actual_type->data.error.child_type);
...@@ -7552,6 +7623,13 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *...@@ -7552,6 +7623,13 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *
7552 op1_array_val = op1_val->data.x_ptr.base_ptr;7623 op1_array_val = op1_val->data.x_ptr.base_ptr;
7553 op1_array_index = op1_val->data.x_ptr.index;7624 op1_array_index = op1_val->data.x_ptr.index;
7554 op1_array_end = op1_array_val->data.x_array.size - 1;7625 op1_array_end = op1_array_val->data.x_array.size - 1;
7626 } else if (is_slice(op1_canon_type)) {
7627 TypeTableEntry *ptr_type = op1_canon_type->data.structure.fields[slice_ptr_index].type_entry;
7628 child_type = ptr_type->data.pointer.child_type;
7629 ConstExprValue *ptr_val = &op1_val->data.x_struct.fields[slice_ptr_index];
7630 op1_array_val = ptr_val->data.x_ptr.base_ptr;
7631 op1_array_index = ptr_val->data.x_ptr.index;
7632 op1_array_end = op1_array_val->data.x_array.size;
7555 } else {7633 } else {
7556 ir_add_error(ira, op1,7634 ir_add_error(ira, op1,
7557 buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op1->value.type->name)));7635 buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op1->value.type->name)));
...@@ -7585,6 +7663,18 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *...@@ -7585,6 +7663,18 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *
7585 op2_array_val = op2_val->data.x_ptr.base_ptr;7663 op2_array_val = op2_val->data.x_ptr.base_ptr;
7586 op2_array_index = op2_val->data.x_ptr.index;7664 op2_array_index = op2_val->data.x_ptr.index;
7587 op2_array_end = op2_array_val->data.x_array.size - 1;7665 op2_array_end = op2_array_val->data.x_array.size - 1;
7666 } else if (is_slice(op2_canon_type)) {
7667 TypeTableEntry *ptr_type = op2_canon_type->data.structure.fields[slice_ptr_index].type_entry;
7668 if (ptr_type->data.pointer.child_type != child_type) {
7669 ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'",
7670 buf_ptr(&child_type->name),
7671 buf_ptr(&op2->value.type->name)));
7672 return ira->codegen->builtin_types.entry_invalid;
7673 }
7674 ConstExprValue *ptr_val = &op2_val->data.x_struct.fields[slice_ptr_index];
7675 op2_array_val = ptr_val->data.x_ptr.base_ptr;
7676 op2_array_index = ptr_val->data.x_ptr.index;
7677 op2_array_end = op2_array_val->data.x_array.size;
7588 } else {7678 } else {
7589 ir_add_error(ira, op2,7679 ir_add_error(ira, op2,
7590 buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op2->value.type->name)));7680 buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op2->value.type->name)));
...@@ -9177,7 +9267,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru...@@ -9177,7 +9267,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
9177 }9267 }
9178 } else {9268 } else {
9179 ir_add_error(ira, &field_ptr_instruction->base,9269 ir_add_error(ira, &field_ptr_instruction->base,
9180 buf_sprintf("type '%s' does not support field access", buf_ptr(&container_type->name)));9270 buf_sprintf("type '%s' does not support field access", buf_ptr(&child_type->name)));
9181 return ira->codegen->builtin_types.entry_invalid;9271 return ira->codegen->builtin_types.entry_invalid;
9182 }9272 }
9183 } else if (container_type->id == TypeTableEntryIdNamespace) {9273 } else if (container_type->id == TypeTableEntryIdNamespace) {
...@@ -9528,6 +9618,12 @@ static TypeTableEntry *ir_analyze_instruction_set_debug_safety(IrAnalyze *ira,...@@ -9528,6 +9618,12 @@ static TypeTableEntry *ir_analyze_instruction_set_debug_safety(IrAnalyze *ira,
9528 if (!target_val)9618 if (!target_val)
9529 return ira->codegen->builtin_types.entry_invalid;9619 return ira->codegen->builtin_types.entry_invalid;
95309620
9621 if (ira->new_irb.exec->is_inline) {
9622 // ignore setDebugSafety when running functions at compile time
9623 ir_build_const_from(ira, &set_debug_safety_instruction->base, false);
9624 return ira->codegen->builtin_types.entry_void;
9625 }
9626
9531 bool *safety_off_ptr;9627 bool *safety_off_ptr;
9532 AstNode **safety_set_node_ptr;9628 AstNode **safety_set_node_ptr;
9533 if (target_type->id == TypeTableEntryIdBlock) {9629 if (target_type->id == TypeTableEntryIdBlock) {
...@@ -10703,6 +10799,26 @@ static TypeTableEntry *ir_analyze_instruction_compile_err(IrAnalyze *ira,...@@ -10703,6 +10799,26 @@ static TypeTableEntry *ir_analyze_instruction_compile_err(IrAnalyze *ira,
10703 return ira->codegen->builtin_types.entry_invalid;10799 return ira->codegen->builtin_types.entry_invalid;
10704}10800}
1070510801
10802static TypeTableEntry *ir_analyze_instruction_compile_log(IrAnalyze *ira, IrInstructionCompileLog *instruction) {
10803 Buf buf = BUF_INIT;
10804 fprintf(stderr, "| ");
10805 for (size_t i = 0; i < instruction->msg_count; i += 1) {
10806 IrInstruction *msg = instruction->msg_list[i]->other;
10807 if (msg->value.type->id == TypeTableEntryIdInvalid)
10808 return ira->codegen->builtin_types.entry_invalid;
10809 buf_resize(&buf, 0);
10810 render_const_value(&buf, &msg->value);
10811 const char *comma_str = (i != 0) ? ", " : "";
10812 fprintf(stderr, "%s%s", comma_str, buf_ptr(&buf));
10813 }
10814 fprintf(stderr, "\n");
10815
10816 ir_add_error(ira, &instruction->base, buf_sprintf("found compile log statement"));
10817
10818 ir_build_const_from(ira, &instruction->base, false);
10819 return ira->codegen->builtin_types.entry_void;
10820}
10821
10706static TypeTableEntry *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstructionErrName *instruction) {10822static TypeTableEntry *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstructionErrName *instruction) {
10707 IrInstruction *value = instruction->value->other;10823 IrInstruction *value = instruction->value->other;
10708 if (value->value.type->id == TypeTableEntryIdInvalid)10824 if (value->value.type->id == TypeTableEntryIdInvalid)
...@@ -11602,13 +11718,13 @@ static TypeTableEntry *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInst...@@ -11602,13 +11718,13 @@ static TypeTableEntry *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInst
11602 out_val->data.x_bool = bignum_add(dest_bignum, op1_bignum, op2_bignum);11718 out_val->data.x_bool = bignum_add(dest_bignum, op1_bignum, op2_bignum);
11603 break;11719 break;
11604 case IrOverflowOpSub:11720 case IrOverflowOpSub:
11605 out_val->data.x_bool = bignum_add(dest_bignum, op1_bignum, op2_bignum);11721 out_val->data.x_bool = bignum_sub(dest_bignum, op1_bignum, op2_bignum);
11606 break;11722 break;
11607 case IrOverflowOpMul:11723 case IrOverflowOpMul:
11608 out_val->data.x_bool = bignum_add(dest_bignum, op1_bignum, op2_bignum);11724 out_val->data.x_bool = bignum_mul(dest_bignum, op1_bignum, op2_bignum);
11609 break;11725 break;
11610 case IrOverflowOpShl:11726 case IrOverflowOpShl:
11611 out_val->data.x_bool = bignum_add(dest_bignum, op1_bignum, op2_bignum);11727 out_val->data.x_bool = bignum_shl(dest_bignum, op1_bignum, op2_bignum);
11612 break;11728 break;
11613 }11729 }
11614 if (!bignum_fits_in_bits(dest_bignum, canon_type->data.integral.bit_count,11730 if (!bignum_fits_in_bits(dest_bignum, canon_type->data.integral.bit_count,
...@@ -12007,6 +12123,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -12007,6 +12123,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
12007 return ir_analyze_instruction_max_value(ira, (IrInstructionMaxValue *)instruction);12123 return ir_analyze_instruction_max_value(ira, (IrInstructionMaxValue *)instruction);
12008 case IrInstructionIdCompileErr:12124 case IrInstructionIdCompileErr:
12009 return ir_analyze_instruction_compile_err(ira, (IrInstructionCompileErr *)instruction);12125 return ir_analyze_instruction_compile_err(ira, (IrInstructionCompileErr *)instruction);
12126 case IrInstructionIdCompileLog:
12127 return ir_analyze_instruction_compile_log(ira, (IrInstructionCompileLog *)instruction);
12010 case IrInstructionIdErrName:12128 case IrInstructionIdErrName:
12011 return ir_analyze_instruction_err_name(ira, (IrInstructionErrName *)instruction);12129 return ir_analyze_instruction_err_name(ira, (IrInstructionErrName *)instruction);
12012 case IrInstructionIdTypeName:12130 case IrInstructionIdTypeName:
...@@ -12164,6 +12282,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -12164,6 +12282,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
12164 case IrInstructionIdSetDebugSafety:12282 case IrInstructionIdSetDebugSafety:
12165 case IrInstructionIdImport:12283 case IrInstructionIdImport:
12166 case IrInstructionIdCompileErr:12284 case IrInstructionIdCompileErr:
12285 case IrInstructionIdCompileLog:
12167 case IrInstructionIdCImport:12286 case IrInstructionIdCImport:
12168 case IrInstructionIdCInclude:12287 case IrInstructionIdCInclude:
12169 case IrInstructionIdCDefine:12288 case IrInstructionIdCDefine:
src/ir_print.cpp+14
...@@ -532,6 +532,17 @@ static void ir_print_compile_err(IrPrint *irp, IrInstructionCompileErr *instruct...@@ -532,6 +532,17 @@ static void ir_print_compile_err(IrPrint *irp, IrInstructionCompileErr *instruct
532 fprintf(irp->f, ")");532 fprintf(irp->f, ")");
533}533}
534534
535static void ir_print_compile_log(IrPrint *irp, IrInstructionCompileLog *instruction) {
536 fprintf(irp->f, "@compileLog(");
537 for (size_t i = 0; i < instruction->msg_count; i += 1) {
538 if (i != 0)
539 fprintf(irp->f, ",");
540 IrInstruction *msg = instruction->msg_list[i];
541 ir_print_other_instruction(irp, msg);
542 }
543 fprintf(irp->f, ")");
544}
545
535static void ir_print_err_name(IrPrint *irp, IrInstructionErrName *instruction) {546static void ir_print_err_name(IrPrint *irp, IrInstructionErrName *instruction) {
536 fprintf(irp->f, "@errorName(");547 fprintf(irp->f, "@errorName(");
537 ir_print_other_instruction(irp, instruction->value);548 ir_print_other_instruction(irp, instruction->value);
...@@ -990,6 +1001,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -990,6 +1001,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
990 case IrInstructionIdCompileErr:1001 case IrInstructionIdCompileErr:
991 ir_print_compile_err(irp, (IrInstructionCompileErr *)instruction);1002 ir_print_compile_err(irp, (IrInstructionCompileErr *)instruction);
992 break;1003 break;
1004 case IrInstructionIdCompileLog:
1005 ir_print_compile_log(irp, (IrInstructionCompileLog *)instruction);
1006 break;
993 case IrInstructionIdErrName:1007 case IrInstructionIdErrName:
994 ir_print_err_name(irp, (IrInstructionErrName *)instruction);1008 ir_print_err_name(irp, (IrInstructionErrName *)instruction);
995 break;1009 break;
std/builtin.zig+5
...@@ -29,3 +29,8 @@ export fn memcpy(noalias dest: ?&u8, noalias src: ?&const u8, n: usize) {...@@ -29,3 +29,8 @@ export fn memcpy(noalias dest: ?&u8, noalias src: ?&const u8, n: usize) {
29 while (index != n; index += 1)29 while (index != n; index += 1)
30 d[index] = s[index];30 d[index] = s[index];
31}31}
32
33// Avoid dragging in the debug safety mechanisms into this .o file.
34pub fn panic(message: []const u8) -> unreachable {
35 @unreachable();
36}
std/compiler_rt.zig+261-2
...@@ -1,3 +1,13 @@...@@ -1,3 +1,13 @@
1// Avoid dragging in the debug safety mechanisms into this .o file,
2// unless we're trying to test this file.
3pub fn panic(message: []const u8) -> unreachable {
4 if (@compileVar("is_test")) {
5 @import("std").debug.panic(message);
6 } else {
7 @unreachable();
8 }
9}
10
1const CHAR_BIT = 8;11const CHAR_BIT = 8;
2const du_int = u64;12const du_int = u64;
3const di_int = i64;13const di_int = i64;
...@@ -212,6 +222,106 @@ export fn __umoddi3(a: du_int, b: du_int) -> du_int {...@@ -212,6 +222,106 @@ export fn __umoddi3(a: du_int, b: du_int) -> du_int {
212 return r;222 return r;
213}223}
214224
225fn isArmArch() -> bool {
226 return switch (@compileVar("arch")) {
227 Arch.armv8_2a,
228 Arch.armv8_1a,
229 Arch.armv8,
230 Arch.armv8m_baseline,
231 Arch.armv8m_mainline,
232 Arch.armv7,
233 Arch.armv7em,
234 Arch.armv7m,
235 Arch.armv7s,
236 Arch.armv7k,
237 Arch.armv6,
238 Arch.armv6m,
239 Arch.armv6k,
240 Arch.armv6t2,
241 Arch.armv5,
242 Arch.armv5te,
243 Arch.armv4t,
244 Arch.armeb => true,
245 else => false,
246 };
247}
248
249export nakedcc fn __aeabi_uidivmod() {
250 @setDebugSafety(this, false);
251
252 if (comptime isArmArch()) {
253 asm volatile (
254 \\ push { lr }
255 \\ sub sp, sp, #4
256 \\ mov r2, sp
257 \\ bl __udivmodsi4
258 \\ ldr r1, [sp]
259 \\ add sp, sp, #4
260 \\ pop { pc }
261 ::: "r2", "r1");
262 @unreachable();
263 }
264
265 @setFnVisible(this, false);
266}
267
268export fn __udivmodsi4(a: su_int, b: su_int, rem: &su_int) -> su_int {
269 @setDebugSafety(this, false);
270
271 const d = __udivsi3(a, b);
272 *rem = su_int(si_int(a) -% (si_int(d) * si_int(b)));
273 return d;
274}
275
276
277// TODO make this an alias instead of an extra function call
278// https://github.com/andrewrk/zig/issues/256
279
280export fn __aeabi_uidiv(n: su_int, d: su_int) -> su_int {
281 @setDebugSafety(this, false);
282
283 return __udivsi3(n, d);
284}
285
286export fn __udivsi3(n: su_int, d: su_int) -> su_int {
287 @setDebugSafety(this, false);
288
289 const n_uword_bits: c_uint = @sizeOf(su_int) * CHAR_BIT;
290 // special cases
291 if (d == 0)
292 return 0; // ?!
293 if (n == 0)
294 return 0;
295 var sr: c_uint = @clz(d) - @clz(n);
296 // 0 <= sr <= n_uword_bits - 1 or sr large
297 if (sr > n_uword_bits - 1) // d > r
298 return 0;
299 if (sr == n_uword_bits - 1) // d == 1
300 return n;
301 sr += 1;
302 // 1 <= sr <= n_uword_bits - 1
303 // Not a special case
304 var q: su_int = n << (n_uword_bits - sr);
305 var r: su_int = n >> sr;
306 var carry: su_int = 0;
307 while (sr > 0; sr -= 1) {
308 // r:q = ((r:q) << 1) | carry
309 r = (r << 1) | (q >> (n_uword_bits - 1));
310 q = (q << 1) | carry;
311 // carry = 0;
312 // if (r.all >= d.all)
313 // {
314 // r.all -= d.all;
315 // carry = 1;
316 // }
317 const s = si_int(d - r - 1) >> si_int(n_uword_bits - 1);
318 carry = su_int(s & 1);
319 r -= d & su_int(s);
320 }
321 q = (q << 1) | carry;
322 return q;
323}
324
215fn test_umoddi3() {325fn test_umoddi3() {
216 @setFnTest(this);326 @setFnTest(this);
217327
...@@ -257,6 +367,155 @@ fn test_one_udivmoddi4(a: du_int, b: du_int, expected_q: du_int, expected_r: du_...@@ -257,6 +367,155 @@ fn test_one_udivmoddi4(a: du_int, b: du_int, expected_q: du_int, expected_r: du_
257 assert(r == expected_r);367 assert(r == expected_r);
258}368}
259369
260fn assert(b: bool) {370fn test_udivsi3() {
261 if (!b) @unreachable();371 @setFnTest(this);
372
373 const cases = [][3]su_int {
374 []su_int{0x00000000, 0x00000001, 0x00000000},
375 []su_int{0x00000000, 0x00000002, 0x00000000},
376 []su_int{0x00000000, 0x00000003, 0x00000000},
377 []su_int{0x00000000, 0x00000010, 0x00000000},
378 []su_int{0x00000000, 0x078644FA, 0x00000000},
379 []su_int{0x00000000, 0x0747AE14, 0x00000000},
380 []su_int{0x00000000, 0x7FFFFFFF, 0x00000000},
381 []su_int{0x00000000, 0x80000000, 0x00000000},
382 []su_int{0x00000000, 0xFFFFFFFD, 0x00000000},
383 []su_int{0x00000000, 0xFFFFFFFE, 0x00000000},
384 []su_int{0x00000000, 0xFFFFFFFF, 0x00000000},
385 []su_int{0x00000001, 0x00000001, 0x00000001},
386 []su_int{0x00000001, 0x00000002, 0x00000000},
387 []su_int{0x00000001, 0x00000003, 0x00000000},
388 []su_int{0x00000001, 0x00000010, 0x00000000},
389 []su_int{0x00000001, 0x078644FA, 0x00000000},
390 []su_int{0x00000001, 0x0747AE14, 0x00000000},
391 []su_int{0x00000001, 0x7FFFFFFF, 0x00000000},
392 []su_int{0x00000001, 0x80000000, 0x00000000},
393 []su_int{0x00000001, 0xFFFFFFFD, 0x00000000},
394 []su_int{0x00000001, 0xFFFFFFFE, 0x00000000},
395 []su_int{0x00000001, 0xFFFFFFFF, 0x00000000},
396 []su_int{0x00000002, 0x00000001, 0x00000002},
397 []su_int{0x00000002, 0x00000002, 0x00000001},
398 []su_int{0x00000002, 0x00000003, 0x00000000},
399 []su_int{0x00000002, 0x00000010, 0x00000000},
400 []su_int{0x00000002, 0x078644FA, 0x00000000},
401 []su_int{0x00000002, 0x0747AE14, 0x00000000},
402 []su_int{0x00000002, 0x7FFFFFFF, 0x00000000},
403 []su_int{0x00000002, 0x80000000, 0x00000000},
404 []su_int{0x00000002, 0xFFFFFFFD, 0x00000000},
405 []su_int{0x00000002, 0xFFFFFFFE, 0x00000000},
406 []su_int{0x00000002, 0xFFFFFFFF, 0x00000000},
407 []su_int{0x00000003, 0x00000001, 0x00000003},
408 []su_int{0x00000003, 0x00000002, 0x00000001},
409 []su_int{0x00000003, 0x00000003, 0x00000001},
410 []su_int{0x00000003, 0x00000010, 0x00000000},
411 []su_int{0x00000003, 0x078644FA, 0x00000000},
412 []su_int{0x00000003, 0x0747AE14, 0x00000000},
413 []su_int{0x00000003, 0x7FFFFFFF, 0x00000000},
414 []su_int{0x00000003, 0x80000000, 0x00000000},
415 []su_int{0x00000003, 0xFFFFFFFD, 0x00000000},
416 []su_int{0x00000003, 0xFFFFFFFE, 0x00000000},
417 []su_int{0x00000003, 0xFFFFFFFF, 0x00000000},
418 []su_int{0x00000010, 0x00000001, 0x00000010},
419 []su_int{0x00000010, 0x00000002, 0x00000008},
420 []su_int{0x00000010, 0x00000003, 0x00000005},
421 []su_int{0x00000010, 0x00000010, 0x00000001},
422 []su_int{0x00000010, 0x078644FA, 0x00000000},
423 []su_int{0x00000010, 0x0747AE14, 0x00000000},
424 []su_int{0x00000010, 0x7FFFFFFF, 0x00000000},
425 []su_int{0x00000010, 0x80000000, 0x00000000},
426 []su_int{0x00000010, 0xFFFFFFFD, 0x00000000},
427 []su_int{0x00000010, 0xFFFFFFFE, 0x00000000},
428 []su_int{0x00000010, 0xFFFFFFFF, 0x00000000},
429 []su_int{0x078644FA, 0x00000001, 0x078644FA},
430 []su_int{0x078644FA, 0x00000002, 0x03C3227D},
431 []su_int{0x078644FA, 0x00000003, 0x028216FE},
432 []su_int{0x078644FA, 0x00000010, 0x0078644F},
433 []su_int{0x078644FA, 0x078644FA, 0x00000001},
434 []su_int{0x078644FA, 0x0747AE14, 0x00000001},
435 []su_int{0x078644FA, 0x7FFFFFFF, 0x00000000},
436 []su_int{0x078644FA, 0x80000000, 0x00000000},
437 []su_int{0x078644FA, 0xFFFFFFFD, 0x00000000},
438 []su_int{0x078644FA, 0xFFFFFFFE, 0x00000000},
439 []su_int{0x078644FA, 0xFFFFFFFF, 0x00000000},
440 []su_int{0x0747AE14, 0x00000001, 0x0747AE14},
441 []su_int{0x0747AE14, 0x00000002, 0x03A3D70A},
442 []su_int{0x0747AE14, 0x00000003, 0x026D3A06},
443 []su_int{0x0747AE14, 0x00000010, 0x00747AE1},
444 []su_int{0x0747AE14, 0x078644FA, 0x00000000},
445 []su_int{0x0747AE14, 0x0747AE14, 0x00000001},
446 []su_int{0x0747AE14, 0x7FFFFFFF, 0x00000000},
447 []su_int{0x0747AE14, 0x80000000, 0x00000000},
448 []su_int{0x0747AE14, 0xFFFFFFFD, 0x00000000},
449 []su_int{0x0747AE14, 0xFFFFFFFE, 0x00000000},
450 []su_int{0x0747AE14, 0xFFFFFFFF, 0x00000000},
451 []su_int{0x7FFFFFFF, 0x00000001, 0x7FFFFFFF},
452 []su_int{0x7FFFFFFF, 0x00000002, 0x3FFFFFFF},
453 []su_int{0x7FFFFFFF, 0x00000003, 0x2AAAAAAA},
454 []su_int{0x7FFFFFFF, 0x00000010, 0x07FFFFFF},
455 []su_int{0x7FFFFFFF, 0x078644FA, 0x00000011},
456 []su_int{0x7FFFFFFF, 0x0747AE14, 0x00000011},
457 []su_int{0x7FFFFFFF, 0x7FFFFFFF, 0x00000001},
458 []su_int{0x7FFFFFFF, 0x80000000, 0x00000000},
459 []su_int{0x7FFFFFFF, 0xFFFFFFFD, 0x00000000},
460 []su_int{0x7FFFFFFF, 0xFFFFFFFE, 0x00000000},
461 []su_int{0x7FFFFFFF, 0xFFFFFFFF, 0x00000000},
462 []su_int{0x80000000, 0x00000001, 0x80000000},
463 []su_int{0x80000000, 0x00000002, 0x40000000},
464 []su_int{0x80000000, 0x00000003, 0x2AAAAAAA},
465 []su_int{0x80000000, 0x00000010, 0x08000000},
466 []su_int{0x80000000, 0x078644FA, 0x00000011},
467 []su_int{0x80000000, 0x0747AE14, 0x00000011},
468 []su_int{0x80000000, 0x7FFFFFFF, 0x00000001},
469 []su_int{0x80000000, 0x80000000, 0x00000001},
470 []su_int{0x80000000, 0xFFFFFFFD, 0x00000000},
471 []su_int{0x80000000, 0xFFFFFFFE, 0x00000000},
472 []su_int{0x80000000, 0xFFFFFFFF, 0x00000000},
473 []su_int{0xFFFFFFFD, 0x00000001, 0xFFFFFFFD},
474 []su_int{0xFFFFFFFD, 0x00000002, 0x7FFFFFFE},
475 []su_int{0xFFFFFFFD, 0x00000003, 0x55555554},
476 []su_int{0xFFFFFFFD, 0x00000010, 0x0FFFFFFF},
477 []su_int{0xFFFFFFFD, 0x078644FA, 0x00000022},
478 []su_int{0xFFFFFFFD, 0x0747AE14, 0x00000023},
479 []su_int{0xFFFFFFFD, 0x7FFFFFFF, 0x00000001},
480 []su_int{0xFFFFFFFD, 0x80000000, 0x00000001},
481 []su_int{0xFFFFFFFD, 0xFFFFFFFD, 0x00000001},
482 []su_int{0xFFFFFFFD, 0xFFFFFFFE, 0x00000000},
483 []su_int{0xFFFFFFFD, 0xFFFFFFFF, 0x00000000},
484 []su_int{0xFFFFFFFE, 0x00000001, 0xFFFFFFFE},
485 []su_int{0xFFFFFFFE, 0x00000002, 0x7FFFFFFF},
486 []su_int{0xFFFFFFFE, 0x00000003, 0x55555554},
487 []su_int{0xFFFFFFFE, 0x00000010, 0x0FFFFFFF},
488 []su_int{0xFFFFFFFE, 0x078644FA, 0x00000022},
489 []su_int{0xFFFFFFFE, 0x0747AE14, 0x00000023},
490 []su_int{0xFFFFFFFE, 0x7FFFFFFF, 0x00000002},
491 []su_int{0xFFFFFFFE, 0x80000000, 0x00000001},
492 []su_int{0xFFFFFFFE, 0xFFFFFFFD, 0x00000001},
493 []su_int{0xFFFFFFFE, 0xFFFFFFFE, 0x00000001},
494 []su_int{0xFFFFFFFE, 0xFFFFFFFF, 0x00000000},
495 []su_int{0xFFFFFFFF, 0x00000001, 0xFFFFFFFF},
496 []su_int{0xFFFFFFFF, 0x00000002, 0x7FFFFFFF},
497 []su_int{0xFFFFFFFF, 0x00000003, 0x55555555},
498 []su_int{0xFFFFFFFF, 0x00000010, 0x0FFFFFFF},
499 []su_int{0xFFFFFFFF, 0x078644FA, 0x00000022},
500 []su_int{0xFFFFFFFF, 0x0747AE14, 0x00000023},
501 []su_int{0xFFFFFFFF, 0x7FFFFFFF, 0x00000002},
502 []su_int{0xFFFFFFFF, 0x80000000, 0x00000001},
503 []su_int{0xFFFFFFFF, 0xFFFFFFFD, 0x00000001},
504 []su_int{0xFFFFFFFF, 0xFFFFFFFE, 0x00000001},
505 []su_int{0xFFFFFFFF, 0xFFFFFFFF, 0x00000001},
506 };
507
508 for (cases) |case| {
509 test_one_udivsi3(case[0], case[1], case[2]);
510 }
511}
512
513fn test_one_udivsi3(a: su_int, b: su_int, expected_q: su_int) {
514 const q: su_int = __udivsi3(a, b);
515 assert(q == expected_q);
516}
517
518
519fn assert(ok: bool) {
520 if (!ok) @unreachable();
262}521}
std/debug.zig+21
...@@ -13,6 +13,27 @@ pub fn assert(ok: bool) {...@@ -13,6 +13,27 @@ pub fn assert(ok: bool) {
13 if (!ok) @unreachable()13 if (!ok) @unreachable()
14}14}
1515
16var panicking = false;
17/// This is the default panic implementation.
18pub coldcc fn panic(message: []const u8) -> unreachable {
19 // TODO
20 // if (@atomicRmw(AtomicOp.XChg, &panicking, true, AtomicOrder.SeqCst)) { }
21 if (panicking) {
22 // Panicked during a panic.
23 // TODO detect if a different thread caused the panic, because in that case
24 // we would want to return here instead of calling abort, so that the thread
25 // which first called panic can finish printing a stack trace.
26 os.abort();
27 } else {
28 panicking = true;
29 }
30
31 %%io.stderr.printf("{}\n", message);
32 %%printStackTrace();
33
34 os.abort();
35}
36
16pub fn printStackTrace() -> %void {37pub fn printStackTrace() -> %void {
17 %return writeStackTrace(&io.stderr);38 %return writeStackTrace(&io.stderr);
18 %return io.stderr.flush();39 %return io.stderr.flush();
std/io.zig+94-40
...@@ -100,14 +100,20 @@ pub const OutStream = struct {...@@ -100,14 +100,20 @@ pub const OutStream = struct {
100 Start,100 Start,
101 OpenBrace,101 OpenBrace,
102 CloseBrace,102 CloseBrace,
103 Hex: bool,103 Integer,
104 IntegerWidth,
104 };105 };
105106
106 /// Calls print and then flushes the buffer.107 /// Calls print and then flushes the buffer.
107 pub fn printf(self: &OutStream, comptime format: []const u8, args: ...) -> %void {108 pub fn printf(self: &OutStream, comptime format: []const u8, args: ...) -> %void {
108 comptime var start_index: usize = 0;109 comptime var start_index = 0;
109 comptime var state = State.Start;110 comptime var state = State.Start;
110 comptime var next_arg: usize = 0;111 comptime var next_arg = 0;
112 comptime var radix = 0;
113 comptime var uppercase = false;
114 comptime var width = 0;
115 comptime var width_start = 0;
116
111 inline for (format) |c, i| {117 inline for (format) |c, i| {
112 switch (state) {118 switch (state) {
113 State.Start => switch (c) {119 State.Start => switch (c) {
...@@ -132,11 +138,23 @@ pub const OutStream = struct {...@@ -132,11 +138,23 @@ pub const OutStream = struct {
132 state = State.Start;138 state = State.Start;
133 start_index = i + 1;139 start_index = i + 1;
134 },140 },
141 'd' => {
142 radix = 10;
143 uppercase = false;
144 width = 0;
145 state = State.Integer;
146 },
135 'x' => {147 'x' => {
136 state = State.Hex { false };148 radix = 16;
149 uppercase = false;
150 width = 0;
151 state = State.Integer;
137 },152 },
138 'X' => {153 'X' => {
139 state = State.Hex { true };154 radix = 16;
155 uppercase = true;
156 width = 0;
157 state = State.Integer;
140 },158 },
141 else => @compileError("Unknown format character: " ++ c),159 else => @compileError("Unknown format character: " ++ c),
142 },160 },
...@@ -147,14 +165,29 @@ pub const OutStream = struct {...@@ -147,14 +165,29 @@ pub const OutStream = struct {
147 },165 },
148 else => @compileError("Single '}' encountered in format string"),166 else => @compileError("Single '}' encountered in format string"),
149 },167 },
150 State.Hex => |uppercase| switch (c) {168 State.Integer => switch (c) {
169 '}' => {
170 self.printInt(args[next_arg], radix, uppercase, width);
171 next_arg += 1;
172 state = State.Start;
173 start_index = i + 1;
174 },
175 '0' ... '9' => {
176 width_start = i;
177 state = State.IntegerWidth;
178 },
179 else => @compileError("Unexpected character in format string: " ++ []u8{c}),
180 },
181 State.IntegerWidth => switch (c) {
151 '}' => {182 '}' => {
152 self.printInt(args[next_arg], 16, uppercase);183 width = comptime %%parseUnsigned(usize, format[width_start...i], 10);
184 self.printInt(args[next_arg], radix, uppercase, width);
153 next_arg += 1;185 next_arg += 1;
154 state = State.Start;186 state = State.Start;
155 start_index = i + 1;187 start_index = i + 1;
156 },188 },
157 else => @compileError("Expected '}' after 'x'/'X' in format string"),189 '0' ... '9' => {},
190 else => @compileError("Unexpected character in format string: " ++ []u8{c}),
158 },191 },
159 }192 }
160 }193 }
...@@ -162,10 +195,8 @@ pub const OutStream = struct {...@@ -162,10 +195,8 @@ pub const OutStream = struct {
162 if (args.len != next_arg) {195 if (args.len != next_arg) {
163 @compileError("Unused arguments");196 @compileError("Unused arguments");
164 }197 }
165 // TODO https://github.com/andrewrk/zig/issues/253198 if (state != State.Start) {
166 switch (state) {199 @compileError("Incomplete format string: " ++ format);
167 State.Start => {},
168 else => @compileError("Incomplete format string: " ++ format),
169 }200 }
170 }201 }
171 if (start_index < format.len) {202 if (start_index < format.len) {
...@@ -177,7 +208,7 @@ pub const OutStream = struct {...@@ -177,7 +208,7 @@ pub const OutStream = struct {
177 pub fn printValue(self: &OutStream, value: var) -> %void {208 pub fn printValue(self: &OutStream, value: var) -> %void {
178 const T = @typeOf(value);209 const T = @typeOf(value);
179 if (@isInteger(T)) {210 if (@isInteger(T)) {
180 return self.printInt(value, 10, false);211 return self.printInt(value, 10, false, 0);
181 } else if (@isFloat(T)) {212 } else if (@isFloat(T)) {
182 return self.printFloat(T, value);213 return self.printFloat(T, value);
183 } else if (@canImplicitCast([]const u8, value)) {214 } else if (@canImplicitCast([]const u8, value)) {
...@@ -190,11 +221,11 @@ pub const OutStream = struct {...@@ -190,11 +221,11 @@ pub const OutStream = struct {
190 }221 }
191 }222 }
192223
193 pub fn printInt(self: &OutStream, x: var, base: u8, uppercase: bool) -> %void {224 pub fn printInt(self: &OutStream, x: var, base: u8, uppercase: bool, width: usize) -> %void {
194 if (self.index + max_int_digits >= self.buffer.len) {225 if (self.index + max_int_digits >= self.buffer.len) {
195 %return self.flush();226 %return self.flush();
196 }227 }
197 const amt_printed = bufPrintInt(self.buffer[self.index...], x, base, uppercase);228 const amt_printed = bufPrintInt(self.buffer[self.index...], x, base, uppercase, width);
198 self.index += amt_printed;229 self.index += amt_printed;
199 }230 }
200231
...@@ -474,24 +505,29 @@ fn digitToChar(digit: u8, uppercase: bool) -> u8 {...@@ -474,24 +505,29 @@ fn digitToChar(digit: u8, uppercase: bool) -> u8 {
474}505}
475506
476/// Guaranteed to not use more than max_int_digits507/// Guaranteed to not use more than max_int_digits
477pub fn bufPrintInt(out_buf: []u8, x: var, base: u8, uppercase: bool) -> usize {508pub fn bufPrintInt(out_buf: []u8, x: var, base: u8, uppercase: bool, width: usize) -> usize {
478 if (@typeOf(x).is_signed)509 if (@typeOf(x).is_signed)
479 bufPrintSigned(out_buf, x, base, uppercase)510 bufPrintSigned(out_buf, x, base, uppercase, width)
480 else511 else
481 bufPrintUnsigned(out_buf, x, base, uppercase)512 bufPrintUnsigned(out_buf, x, base, uppercase, width)
482}513}
483514
484fn bufPrintSigned(out_buf: []u8, x: var, base: u8, uppercase: bool) -> usize {515fn bufPrintSigned(out_buf: []u8, x: var, base: u8, uppercase: bool, width: usize) -> usize {
485 const uint = @intType(false, @typeOf(x).bit_count);516 const uint = @intType(false, @typeOf(x).bit_count);
517 // include the sign in the width
518 const new_width = if (width == 0) 0 else (width - 1);
519 var new_value: uint = undefined;
486 if (x < 0) {520 if (x < 0) {
487 out_buf[0] = '-';521 out_buf[0] = '-';
488 return 1 + bufPrintUnsigned(out_buf[1...], uint(-(x + 1)) + 1, base, uppercase);522 new_value = uint(-(x + 1)) + 1;
489 } else {523 } else {
490 return bufPrintUnsigned(out_buf, uint(x), base, uppercase);524 out_buf[0] = '+';
525 new_value = uint(x);
491 }526 }
527 return 1 + bufPrintUnsigned(out_buf[1...], new_value, base, uppercase, new_width);
492}528}
493529
494fn bufPrintUnsigned(out_buf: []u8, x: var, base: u8, uppercase: bool) -> usize {530fn bufPrintUnsigned(out_buf: []u8, x: var, base: u8, uppercase: bool, width: usize) -> usize {
495 // max_int_digits accounts for the minus sign. when printing an unsigned531 // max_int_digits accounts for the minus sign. when printing an unsigned
496 // number we don't need to do that.532 // number we don't need to do that.
497 var buf: [max_int_digits - 1]u8 = undefined;533 var buf: [max_int_digits - 1]u8 = undefined;
...@@ -508,18 +544,11 @@ fn bufPrintUnsigned(out_buf: []u8, x: var, base: u8, uppercase: bool) -> usize {...@@ -508,18 +544,11 @@ fn bufPrintUnsigned(out_buf: []u8, x: var, base: u8, uppercase: bool) -> usize {
508 }544 }
509545
510 const src_buf = buf[index...];546 const src_buf = buf[index...];
511 mem.copy(u8, out_buf, src_buf);547 const padding = if (width > src_buf.len) (width - src_buf.len) else 0;
512 return src_buf.len;
513}
514
515fn parseU64DigitTooBig() {
516 @setFnTest(this);
517548
518 parseUnsigned(u64, "123a", 10) %% |err| {549 mem.set(u8, out_buf[0...padding], '0');
519 if (err == error.InvalidChar) return;550 mem.copy(u8, out_buf[padding...], src_buf);
520 @unreachable();551 return src_buf.len + padding;
521 };
522 @unreachable();
523}552}
524553
525pub fn openSelfExe(stream: &InStream) -> %void {554pub fn openSelfExe(stream: &InStream) -> %void {
...@@ -535,18 +564,43 @@ pub fn openSelfExe(stream: &InStream) -> %void {...@@ -535,18 +564,43 @@ pub fn openSelfExe(stream: &InStream) -> %void {
535 }564 }
536}565}
537566
538fn bufPrintIntToSlice(buf: []u8, x: var, base: u8, uppercase: bool) -> []u8 {567fn bufPrintIntToSlice(buf: []u8, value: var, base: u8, uppercase: bool, width: usize) -> []u8 {
539 return buf[0...bufPrintInt(buf, x, base, uppercase)];568 return buf[0...bufPrintInt(buf, value, base, uppercase, width)];
569}
570
571fn testParseU64DigitTooBig() {
572 @setFnTest(this);
573
574 parseUnsigned(u64, "123a", 10) %% |err| {
575 if (err == error.InvalidChar) return;
576 @unreachable();
577 };
578 @unreachable();
579}
580
581fn testParseUnsignedComptime() {
582 @setFnTest(this);
583
584 comptime {
585 assert(%%parseUnsigned(usize, "2", 10) == 2);
586 }
540}587}
541588
542fn testBufPrintInt() {589fn testBufPrintInt() {
543 @setFnTest(this);590 @setFnTest(this);
544591
545 var buf: [max_int_digits]u8 = undefined;592 var buf: [max_int_digits]u8 = undefined;
546 assert(mem.eql(bufPrintIntToSlice(buf, i32(-12345678), 2, false), "-101111000110000101001110"));593 assert(mem.eql(bufPrintIntToSlice(buf, i32(-12345678), 2, false, 0), "-101111000110000101001110"));
547 assert(mem.eql(bufPrintIntToSlice(buf, i32(-12345678), 10, false), "-12345678"));594 assert(mem.eql(bufPrintIntToSlice(buf, i32(-12345678), 10, false, 0), "-12345678"));
548 assert(mem.eql(bufPrintIntToSlice(buf, i32(-12345678), 16, false), "-bc614e"));595 assert(mem.eql(bufPrintIntToSlice(buf, i32(-12345678), 16, false, 0), "-bc614e"));
549 assert(mem.eql(bufPrintIntToSlice(buf, i32(-12345678), 16, true), "-BC614E"));596 assert(mem.eql(bufPrintIntToSlice(buf, i32(-12345678), 16, true, 0), "-BC614E"));
597
598 assert(mem.eql(bufPrintIntToSlice(buf, u32(12345678), 10, true, 0), "12345678"));
599
600 assert(mem.eql(bufPrintIntToSlice(buf, u32(666), 10, false, 6), "000666"));
601 assert(mem.eql(bufPrintIntToSlice(buf, u32(0x1234), 16, false, 6), "001234"));
602 assert(mem.eql(bufPrintIntToSlice(buf, u32(0x1234), 16, false, 1), "1234"));
550603
551 assert(mem.eql(bufPrintIntToSlice(buf, u32(12345678), 10, true), "12345678"));604 assert(mem.eql(bufPrintIntToSlice(buf, i32(42), 10, false, 3), "+42"));
605 assert(mem.eql(bufPrintIntToSlice(buf, i32(-42), 10, false, 3), "-42"));
552}606}
std/math.zig+17
...@@ -1,3 +1,5 @@...@@ -1,3 +1,5 @@
1const assert = @import("debug.zig").assert;
2
1pub const Cmp = enum {3pub const Cmp = enum {
2 Equal,4 Equal,
3 Greater,5 Greater,
...@@ -66,3 +68,18 @@ fn getReturnTypeForAbs(comptime T: type) -> type {...@@ -66,3 +68,18 @@ fn getReturnTypeForAbs(comptime T: type) -> type {
66 }68 }
67}69}
6870
71fn testMath() {
72 @setFnTest(this);
73
74 assert(%%mulOverflow(i32, 3, 4) == 12);
75 assert(%%addOverflow(i32, 3, 4) == 7);
76 assert(%%subOverflow(i32, 3, 4) == -1);
77 assert(%%shlOverflow(i32, 0b11, 4) == 0b110000);
78
79 comptime {
80 assert(%%mulOverflow(i32, 3, 4) == 12);
81 assert(%%addOverflow(i32, 3, 4) == 7);
82 assert(%%subOverflow(i32, 3, 4) == -1);
83 assert(%%shlOverflow(i32, 0b11, 4) == 0b110000);
84 }
85}
std/panic.zig+1-22
...@@ -3,31 +3,10 @@...@@ -3,31 +3,10 @@
3// If this file wants to import other files *by name*, support for that would3// If this file wants to import other files *by name*, support for that would
4// have to be added in the compiler.4// have to be added in the compiler.
55
6var panicking = false;
7pub coldcc fn panic(message: []const u8) -> unreachable {6pub coldcc fn panic(message: []const u8) -> unreachable {
8 if (@compileVar("os") == Os.freestanding) {7 if (@compileVar("os") == Os.freestanding) {
9 while (true) {}8 while (true) {}
10 } else {9 } else {
11 const std = @import("std");10 @import("std").debug.panic(message);
12 const io = std.io;
13 const debug = std.debug;
14 const os = std.os;
15
16 // TODO
17 // if (@atomicRmw(AtomicOp.XChg, &panicking, true, AtomicOrder.SeqCst)) {
18 if (panicking) {
19 // Panicked during a panic.
20 // TODO detect if a different thread caused the panic, because in that case
21 // we would want to return here instead of calling abort, so that the thread
22 // which first called panic can finish printing a stack trace.
23 os.abort();
24 } else {
25 panicking = true;
26 }
27
28 %%io.stderr.printf("{}\n", message);
29 %%debug.printStackTrace();
30
31 os.abort();
32 }11 }
33}12}
test/cases/enum_with_members.zig+2-2
...@@ -8,8 +8,8 @@ const ET = enum {...@@ -8,8 +8,8 @@ const ET = enum {
88
9 pub fn print(a: &const ET, buf: []u8) -> %usize {9 pub fn print(a: &const ET, buf: []u8) -> %usize {
10 return switch (*a) {10 return switch (*a) {
11 ET.SINT => |x| { io.bufPrintInt(buf, x, 10, false) },11 ET.SINT => |x| { io.bufPrintInt(buf, x, 10, false, 0) },
12 ET.UINT => |x| { io.bufPrintInt(buf, x, 10, false) },12 ET.UINT => |x| { io.bufPrintInt(buf, x, 10, false, 0) },
13 }13 }
14 }14 }
15};15};
test/cases/eval.zig+12
...@@ -251,3 +251,15 @@ fn comptimeIterateOverFnPtrList() {...@@ -251,3 +251,15 @@ fn comptimeIterateOverFnPtrList() {
251 assert(performFn('o', 0) == 1);251 assert(performFn('o', 0) == 1);
252 assert(performFn('w', 99) == 99);252 assert(performFn('w', 99) == 99);
253}253}
254
255fn evalSetDebugSafetyAtCompileTime() {
256 @setFnTest(this);
257
258 const result = comptime fnWithSetDebugSafety();
259 assert(result == 1234);
260}
261
262fn fnWithSetDebugSafety() -> i32{
263 @setDebugSafety(this, true);
264 return 1234;
265}
test/run_tests.cpp+20-2
...@@ -1015,8 +1015,9 @@ const x = foo();...@@ -1015,8 +1015,9 @@ const x = foo();
10151015
1016 add_compile_fail_case("array concatenation with wrong type", R"SOURCE(1016 add_compile_fail_case("array concatenation with wrong type", R"SOURCE(
1017const src = "aoeu";1017const src = "aoeu";
1018const a = src[0...] ++ "foo";1018const derp = usize(1234);
1019 )SOURCE", 1, ".tmp_source.zig:3:14: error: expected array or C string literal, found '[]u8'");1019const a = derp ++ "foo";
1020 )SOURCE", 1, ".tmp_source.zig:4:11: error: expected array or C string literal, found 'usize'");
10201021
1021 add_compile_fail_case("non compile time array concatenation", R"SOURCE(1022 add_compile_fail_case("non compile time array concatenation", R"SOURCE(
1022fn f(s: [10]u8) -> []u8 {1023fn f(s: [10]u8) -> []u8 {
...@@ -1632,6 +1633,23 @@ const some_data: [100]u8 = {...@@ -1632,6 +1633,23 @@ const some_data: [100]u8 = {
1632};1633};
1633 )SOURCE", 1, ".tmp_source.zig:3:32: error: alignment value must be power of 2");1634 )SOURCE", 1, ".tmp_source.zig:3:32: error: alignment value must be power of 2");
16341635
1636 add_compile_fail_case("compile log", R"SOURCE(
1637fn foo() {
1638 comptime bar(12, "hi");
1639}
1640fn bar(a: i32, b: []const u8) {
1641 @compileLog("begin");
1642 @compileLog("a", a, "b", b);
1643 @compileLog("end");
1644}
1645 )SOURCE", 6,
1646 ".tmp_source.zig:6:5: error: found compile log statement",
1647 ".tmp_source.zig:3:17: note: called from here",
1648 ".tmp_source.zig:7:5: error: found compile log statement",
1649 ".tmp_source.zig:3:17: note: called from here",
1650 ".tmp_source.zig:8:5: error: found compile log statement",
1651 ".tmp_source.zig:3:17: note: called from here");
1652
1635}1653}
16361654
1637//////////////////////////////////////////////////////////////////////////////1655//////////////////////////////////////////////////////////////////////////////