authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-11-18 20:57:27-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-11-18 20:57:27-05:00
logbf7cde62c52b370f953db2cd6167a156771d8343
tree4f11799818dc793db8431332537b010620aad55f
parented31ae8867fd2d7b5274c6b127d42360b48fc49c

IR: support setDebugSafety builtin function


6 files changed, 167 insertions(+), 76 deletions(-)

src/all_types.hpp+8
......@@ -1449,6 +1449,7 @@ enum IrInstructionId {
14491449 IrInstructionIdToPtrType,
14501450 IrInstructionIdPtrTypeChild,
14511451 IrInstructionIdSetFnTest,
1452 IrInstructionIdSetDebugSafety,
14521453 IrInstructionIdArrayType,
14531454 IrInstructionIdSliceType,
14541455 IrInstructionIdAsm,
......@@ -1705,6 +1706,13 @@ struct IrInstructionSetFnTest {
17051706 IrInstruction *is_test;
17061707};
17071708
1709struct IrInstructionSetDebugSafety {
1710 IrInstruction base;
1711
1712 IrInstruction *scope_value;
1713 IrInstruction *debug_safety_on;
1714};
1715
17081716struct IrInstructionArrayType {
17091717 IrInstruction base;
17101718
src/ast_render.cpp+11-2
......@@ -669,6 +669,17 @@ static void render_node(AstRender *ar, AstNode *node) {
669669 render_node(ar, node->data.while_expr.body);
670670 break;
671671 }
672 case NodeTypeThisLiteral:
673 {
674 fprintf(ar->f, "this");
675 break;
676 }
677 case NodeTypeBoolLiteral:
678 {
679 const char *bool_str = node->data.bool_literal.value ? "true" : "false";
680 fprintf(ar->f, "%s", bool_str);
681 break;
682 }
672683 case NodeTypeFnDecl:
673684 case NodeTypeParamDecl:
674685 case NodeTypeErrorValueDecl:
......@@ -677,10 +688,8 @@ static void render_node(AstRender *ar, AstNode *node) {
677688 case NodeTypeStructField:
678689 case NodeTypeStructValueField:
679690 case NodeTypeUse:
680 case NodeTypeBoolLiteral:
681691 case NodeTypeNullLiteral:
682692 case NodeTypeZeroesLiteral:
683 case NodeTypeThisLiteral:
684693 case NodeTypeIfBoolExpr:
685694 case NodeTypeIfVarExpr:
686695 case NodeTypeForExpr:
src/codegen.cpp+1
......@@ -1681,6 +1681,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
16811681 case IrInstructionIdPtrTypeChild:
16821682 case IrInstructionIdFieldPtr:
16831683 case IrInstructionIdSetFnTest:
1684 case IrInstructionIdSetDebugSafety:
16841685 case IrInstructionIdArrayType:
16851686 case IrInstructionIdSliceType:
16861687 zig_unreachable();
src/ir.cpp+101-67
......@@ -201,6 +201,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSetFnTest *) {
201201 return IrInstructionIdSetFnTest;
202202}
203203
204static constexpr IrInstructionId ir_instruction_id(IrInstructionSetDebugSafety *) {
205 return IrInstructionIdSetDebugSafety;
206}
207
204208static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayType *) {
205209 return IrInstructionIdArrayType;
206210}
......@@ -786,6 +790,19 @@ static IrInstruction *ir_build_set_fn_test(IrBuilder *irb, AstNode *source_node,
786790 return &instruction->base;
787791}
788792
793static IrInstruction *ir_build_set_debug_safety(IrBuilder *irb, AstNode *source_node,
794 IrInstruction *scope_value, IrInstruction *debug_safety_on)
795{
796 IrInstructionSetDebugSafety *instruction = ir_build_instruction<IrInstructionSetDebugSafety>(irb, source_node);
797 instruction->scope_value = scope_value;
798 instruction->debug_safety_on = debug_safety_on;
799
800 ir_ref_instruction(scope_value);
801 ir_ref_instruction(debug_safety_on);
802
803 return &instruction->base;
804}
805
789806static IrInstruction *ir_build_array_type(IrBuilder *irb, AstNode *source_node, IrInstruction *size,
790807 IrInstruction *child_type)
791808{
......@@ -1291,6 +1308,20 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, AstNode *node) {
12911308
12921309 return ir_build_set_fn_test(irb, node, arg0_value, arg1_value);
12931310 }
1311 case BuiltinFnIdSetDebugSafety:
1312 {
1313 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
1314 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, node->block_context);
1315 if (arg0_value == irb->codegen->invalid_instruction)
1316 return arg0_value;
1317
1318 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
1319 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, node->block_context);
1320 if (arg1_value == irb->codegen->invalid_instruction)
1321 return arg1_value;
1322
1323 return ir_build_set_debug_safety(irb, node, arg0_value, arg1_value);
1324 }
12941325 case BuiltinFnIdMemcpy:
12951326 case BuiltinFnIdMemset:
12961327 case BuiltinFnIdSizeof:
......@@ -1325,7 +1356,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, AstNode *node) {
13251356 case BuiltinFnIdSetFnVisible:
13261357 case BuiltinFnIdSetFnStaticEval:
13271358 case BuiltinFnIdSetFnNoInline:
1328 case BuiltinFnIdSetDebugSafety:
13291359 zig_panic("TODO IR gen more builtin functions");
13301360 }
13311361 zig_unreachable();
......@@ -2260,6 +2290,15 @@ static TypeTableEntry *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value
22602290 return const_val->data.x_type;
22612291}
22622292
2293static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value) {
2294 if (value->static_value.special != ConstValSpecialStatic) {
2295 add_node_error(ira->codegen, value->source_node,
2296 buf_sprintf("unable to evaluate constant expression"));
2297 return nullptr;
2298 }
2299 return &value->static_value;
2300}
2301
22632302static bool ir_resolve_bool(IrAnalyze *ira, IrInstruction *bool_value, bool *out) {
22642303 if (bool_value == ira->codegen->invalid_instruction)
22652304 return false;
......@@ -2273,12 +2312,9 @@ static bool ir_resolve_bool(IrAnalyze *ira, IrInstruction *bool_value, bool *out
22732312 return false;
22742313 }
22752314
2276 ConstExprValue *const_val = &bool_value->static_value;
2277 if (const_val->special == ConstValSpecialRuntime) {
2278 add_node_error(ira->codegen, bool_value->source_node,
2279 buf_sprintf("unable to evaluate constant expression"));
2315 ConstExprValue *const_val = ir_resolve_const(ira, bool_value);
2316 if (!const_val)
22802317 return false;
2281 }
22822318
22832319 *out = const_val->data.x_bool;
22842320 return true;
......@@ -4027,12 +4063,67 @@ static TypeTableEntry *ir_analyze_instruction_set_fn_test(IrAnalyze *ira,
40274063 }
40284064 fn_entry->fn_test_set_node = source_node;
40294065
4030 ira->codegen->test_fn_count += 1;
4066 if (fn_entry->is_test)
4067 ira->codegen->test_fn_count += 1;
40314068
40324069 ir_build_const_from(ira, &set_fn_test_instruction->base, false);
40334070 return ira->codegen->builtin_types.entry_void;
40344071}
40354072
4073static TypeTableEntry *ir_analyze_instruction_set_debug_safety(IrAnalyze *ira,
4074 IrInstructionSetDebugSafety *set_debug_safety_instruction)
4075{
4076 IrInstruction *target_instruction = set_debug_safety_instruction->scope_value->other;
4077 TypeTableEntry *target_type = target_instruction->type_entry;
4078 if (target_type->id == TypeTableEntryIdInvalid)
4079 return ira->codegen->builtin_types.entry_invalid;
4080 ConstExprValue *target_val = ir_resolve_const(ira, target_instruction);
4081 if (!target_val)
4082 return ira->codegen->builtin_types.entry_invalid;
4083
4084 BlockContext *target_context;
4085 if (target_type->id == TypeTableEntryIdBlock) {
4086 target_context = target_val->data.x_block;
4087 } else if (target_type->id == TypeTableEntryIdFn) {
4088 target_context = target_val->data.x_fn->fn_def_node->data.fn_def.block_context;
4089 } else if (target_type->id == TypeTableEntryIdMetaType) {
4090 TypeTableEntry *type_arg = target_val->data.x_type;
4091 if (type_arg->id == TypeTableEntryIdStruct) {
4092 target_context = type_arg->data.structure.block_context;
4093 } else if (type_arg->id == TypeTableEntryIdEnum) {
4094 target_context = type_arg->data.enumeration.block_context;
4095 } else if (type_arg->id == TypeTableEntryIdUnion) {
4096 target_context = type_arg->data.unionation.block_context;
4097 } else {
4098 add_node_error(ira->codegen, target_instruction->source_node,
4099 buf_sprintf("expected scope reference, got type '%s'", buf_ptr(&type_arg->name)));
4100 return ira->codegen->builtin_types.entry_invalid;
4101 }
4102 } else {
4103 add_node_error(ira->codegen, target_instruction->source_node,
4104 buf_sprintf("expected scope reference, got type '%s'", buf_ptr(&target_type->name)));
4105 return ira->codegen->builtin_types.entry_invalid;
4106 }
4107
4108 IrInstruction *debug_safety_on_value = set_debug_safety_instruction->debug_safety_on->other;
4109 bool want_debug_safety;
4110 if (!ir_resolve_bool(ira, debug_safety_on_value, &want_debug_safety))
4111 return ira->codegen->builtin_types.entry_invalid;
4112
4113 AstNode *source_node = set_debug_safety_instruction->base.source_node;
4114 if (target_context->safety_set_node) {
4115 ErrorMsg *msg = add_node_error(ira->codegen, source_node,
4116 buf_sprintf("function test attribute set twice"));
4117 add_error_note(ira->codegen, msg, target_context->safety_set_node, buf_sprintf("first set here"));
4118 return ira->codegen->builtin_types.entry_invalid;
4119 }
4120 target_context->safety_set_node = source_node;
4121 target_context->safety_off = !want_debug_safety;
4122
4123 ir_build_const_from(ira, &set_debug_safety_instruction->base, false);
4124 return ira->codegen->builtin_types.entry_void;
4125}
4126
40364127static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira,
40374128 IrInstructionSliceType *slice_type_instruction)
40384129{
......@@ -4164,6 +4255,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
41644255 return ir_analyze_instruction_ptr_type_child(ira, (IrInstructionPtrTypeChild *)instruction);
41654256 case IrInstructionIdSetFnTest:
41664257 return ir_analyze_instruction_set_fn_test(ira, (IrInstructionSetFnTest *)instruction);
4258 case IrInstructionIdSetDebugSafety:
4259 return ir_analyze_instruction_set_debug_safety(ira, (IrInstructionSetDebugSafety *)instruction);
41674260 case IrInstructionIdSliceType:
41684261 return ir_analyze_instruction_slice_type(ira, (IrInstructionSliceType *)instruction);
41694262 case IrInstructionIdAsm:
......@@ -4257,6 +4350,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
42574350 case IrInstructionIdReturn:
42584351 case IrInstructionIdUnreachable:
42594352 case IrInstructionIdSetFnTest:
4353 case IrInstructionIdSetDebugSafety:
42604354 return true;
42614355 case IrInstructionIdPhi:
42624356 case IrInstructionIdUnOp:
......@@ -4854,64 +4948,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
48544948// return g->builtin_types.entry_void;
48554949//}
48564950//
4857//static TypeTableEntry *analyze_set_debug_safety(CodeGen *g, ImportTableEntry *import,
4858// BlockContext *parent_context, AstNode *node)
4859//{
4860// AstNode **target_node = &node->data.fn_call_expr.params.at(0);
4861// AstNode **value_node = &node->data.fn_call_expr.params.at(1);
4862//
4863// TypeTableEntry *target_type = analyze_expression(g, import, parent_context, nullptr, *target_node);
4864// BlockContext *target_context;
4865// ConstExprValue *const_val = &get_resolved_expr(*target_node)->const_val;
4866// if (target_type->id == TypeTableEntryIdInvalid) {
4867// return g->builtin_types.entry_invalid;
4868// }
4869// if (!const_val->ok) {
4870// add_node_error(g, *target_node, buf_sprintf("unable to evaluate constant expression"));
4871// return g->builtin_types.entry_invalid;
4872// }
4873// if (target_type->id == TypeTableEntryIdBlock) {
4874// target_context = const_val->data.x_block;
4875// } else if (target_type->id == TypeTableEntryIdFn) {
4876// target_context = const_val->data.x_fn->fn_def_node->data.fn_def.block_context;
4877// } else if (target_type->id == TypeTableEntryIdMetaType) {
4878// TypeTableEntry *type_arg = const_val->data.x_type;
4879// if (type_arg->id == TypeTableEntryIdStruct) {
4880// target_context = type_arg->data.structure.block_context;
4881// } else if (type_arg->id == TypeTableEntryIdEnum) {
4882// target_context = type_arg->data.enumeration.block_context;
4883// } else if (type_arg->id == TypeTableEntryIdUnion) {
4884// target_context = type_arg->data.unionation.block_context;
4885// } else {
4886// add_node_error(g, *target_node,
4887// buf_sprintf("expected scope reference, got type '%s'", buf_ptr(&type_arg->name)));
4888// return g->builtin_types.entry_invalid;
4889// }
4890// } else {
4891// add_node_error(g, *target_node,
4892// buf_sprintf("expected scope reference, got type '%s'", buf_ptr(&target_type->name)));
4893// return g->builtin_types.entry_invalid;
4894// }
4895//
4896// bool want_debug_safety;
4897// bool ok = resolve_const_expr_bool(g, import, parent_context, value_node, &want_debug_safety);
4898// if (!ok) {
4899// return g->builtin_types.entry_invalid;
4900// }
4901//
4902// if (target_context->safety_set_node) {
4903// ErrorMsg *msg = add_node_error(g, node, buf_sprintf("debug safety for scope set twice"));
4904// add_error_note(g, msg, target_context->safety_set_node, buf_sprintf("first set here"));
4905// return g->builtin_types.entry_invalid;
4906// }
4907// target_context->safety_set_node = node;
4908//
4909// target_context->safety_off = !want_debug_safety;
4910//
4911// return g->builtin_types.entry_void;
4912//}
4913
4914
49154951//static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
49164952// TypeTableEntry *expected_type, AstNode *node)
49174953//{
......@@ -5215,8 +5251,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
52155251// return analyze_set_fn_static_eval(g, import, context, node);
52165252// case BuiltinFnIdSetFnVisible:
52175253// return analyze_set_fn_visible(g, import, context, node);
5218// case BuiltinFnIdSetDebugSafety:
5219// return analyze_set_debug_safety(g, import, context, node);
52205254// }
52215255// zig_unreachable();
52225256//}
src/ir_print.cpp+11
......@@ -409,6 +409,14 @@ static void ir_print_set_fn_test(IrPrint *irp, IrInstructionSetFnTest *instructi
409409 fprintf(irp->f, ")");
410410}
411411
412static void ir_print_set_debug_safety(IrPrint *irp, IrInstructionSetDebugSafety *instruction) {
413 fprintf(irp->f, "@setDebugSafety(");
414 ir_print_other_instruction(irp, instruction->scope_value);
415 fprintf(irp->f, ", ");
416 ir_print_other_instruction(irp, instruction->debug_safety_on);
417 fprintf(irp->f, ")");
418}
419
412420static void ir_print_array_type(IrPrint *irp, IrInstructionArrayType *instruction) {
413421 fprintf(irp->f, "[");
414422 ir_print_other_instruction(irp, instruction->size);
......@@ -541,6 +549,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
541549 case IrInstructionIdSetFnTest:
542550 ir_print_set_fn_test(irp, (IrInstructionSetFnTest *)instruction);
543551 break;
552 case IrInstructionIdSetDebugSafety:
553 ir_print_set_debug_safety(irp, (IrInstructionSetDebugSafety *)instruction);
554 break;
544555 case IrInstructionIdArrayType:
545556 ir_print_array_type(irp, (IrInstructionArrayType *)instruction);
546557 break;
test/self_hosted2.zig+35-7
......@@ -1,13 +1,41 @@
1fn add(a: i32, b: i32) -> i32 {
2 a + b
1pub const SYS_write = 1;
2pub const SYS_exit = 60;
3pub const stdout_fileno = 1;
4const text = "hello\n";
5
6export nakedcc fn _start() -> unreachable {
7 myMain();
8}
9
10fn myMain() -> unreachable {
11 write(stdout_fileno, &text[0], text.len);
12 exit(0);
313}
414
5fn assert(ok: bool) {
6 if (!ok) @unreachable();
15pub inline fn syscall1(number: usize, arg1: usize) -> usize {
16 asm volatile ("syscall"
17 : [ret] "={rax}" (-> usize)
18 : [number] "{rax}" (number),
19 [arg1] "{rdi}" (arg1)
20 : "rcx", "r11")
721}
822
9fn testAdd() {
10 @setFnTest(this, true);
23pub inline fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) -> usize {
24 asm volatile ("syscall"
25 : [ret] "={rax}" (-> usize)
26 : [number] "{rax}" (number),
27 [arg1] "{rdi}" (arg1),
28 [arg2] "{rsi}" (arg2),
29 [arg3] "{rdx}" (arg3)
30 : "rcx", "r11")
31}
1132
12 assert(add(2, 3) == 5);
33pub fn write(fd: i32, buf: &const u8, count: usize) -> usize {
34 syscall3(SYS_write, usize(fd), usize(buf), count)
1335}
36
37pub fn exit(status: i32) -> unreachable {
38 syscall1(SYS_exit, usize(status));
39 @unreachable()
40}
41