IR: support setDebugSafety builtin function

master
Andrew Kelley 2016-11-18 20:57:27 -05:00
parent ed31ae8867
commit bf7cde62c5
6 changed files with 168 additions and 77 deletions

View File

@ -1449,6 +1449,7 @@ enum IrInstructionId {
IrInstructionIdToPtrType,
IrInstructionIdPtrTypeChild,
IrInstructionIdSetFnTest,
IrInstructionIdSetDebugSafety,
IrInstructionIdArrayType,
IrInstructionIdSliceType,
IrInstructionIdAsm,
@ -1705,6 +1706,13 @@ struct IrInstructionSetFnTest {
IrInstruction *is_test;
};
struct IrInstructionSetDebugSafety {
IrInstruction base;
IrInstruction *scope_value;
IrInstruction *debug_safety_on;
};
struct IrInstructionArrayType {
IrInstruction base;

View File

@ -669,6 +669,17 @@ static void render_node(AstRender *ar, AstNode *node) {
render_node(ar, node->data.while_expr.body);
break;
}
case NodeTypeThisLiteral:
{
fprintf(ar->f, "this");
break;
}
case NodeTypeBoolLiteral:
{
const char *bool_str = node->data.bool_literal.value ? "true" : "false";
fprintf(ar->f, "%s", bool_str);
break;
}
case NodeTypeFnDecl:
case NodeTypeParamDecl:
case NodeTypeErrorValueDecl:
@ -677,10 +688,8 @@ static void render_node(AstRender *ar, AstNode *node) {
case NodeTypeStructField:
case NodeTypeStructValueField:
case NodeTypeUse:
case NodeTypeBoolLiteral:
case NodeTypeNullLiteral:
case NodeTypeZeroesLiteral:
case NodeTypeThisLiteral:
case NodeTypeIfBoolExpr:
case NodeTypeIfVarExpr:
case NodeTypeForExpr:

View File

@ -1681,6 +1681,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdPtrTypeChild:
case IrInstructionIdFieldPtr:
case IrInstructionIdSetFnTest:
case IrInstructionIdSetDebugSafety:
case IrInstructionIdArrayType:
case IrInstructionIdSliceType:
zig_unreachable();

View File

@ -201,6 +201,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSetFnTest *) {
return IrInstructionIdSetFnTest;
}
static constexpr IrInstructionId ir_instruction_id(IrInstructionSetDebugSafety *) {
return IrInstructionIdSetDebugSafety;
}
static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayType *) {
return IrInstructionIdArrayType;
}
@ -786,6 +790,19 @@ static IrInstruction *ir_build_set_fn_test(IrBuilder *irb, AstNode *source_node,
return &instruction->base;
}
static IrInstruction *ir_build_set_debug_safety(IrBuilder *irb, AstNode *source_node,
IrInstruction *scope_value, IrInstruction *debug_safety_on)
{
IrInstructionSetDebugSafety *instruction = ir_build_instruction<IrInstructionSetDebugSafety>(irb, source_node);
instruction->scope_value = scope_value;
instruction->debug_safety_on = debug_safety_on;
ir_ref_instruction(scope_value);
ir_ref_instruction(debug_safety_on);
return &instruction->base;
}
static IrInstruction *ir_build_array_type(IrBuilder *irb, AstNode *source_node, IrInstruction *size,
IrInstruction *child_type)
{
@ -1291,6 +1308,20 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, AstNode *node) {
return ir_build_set_fn_test(irb, node, arg0_value, arg1_value);
}
case BuiltinFnIdSetDebugSafety:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, node->block_context);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, node->block_context);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
return ir_build_set_debug_safety(irb, node, arg0_value, arg1_value);
}
case BuiltinFnIdMemcpy:
case BuiltinFnIdMemset:
case BuiltinFnIdSizeof:
@ -1325,7 +1356,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, AstNode *node) {
case BuiltinFnIdSetFnVisible:
case BuiltinFnIdSetFnStaticEval:
case BuiltinFnIdSetFnNoInline:
case BuiltinFnIdSetDebugSafety:
zig_panic("TODO IR gen more builtin functions");
}
zig_unreachable();
@ -2260,6 +2290,15 @@ static TypeTableEntry *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value
return const_val->data.x_type;
}
static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value) {
if (value->static_value.special != ConstValSpecialStatic) {
add_node_error(ira->codegen, value->source_node,
buf_sprintf("unable to evaluate constant expression"));
return nullptr;
}
return &value->static_value;
}
static bool ir_resolve_bool(IrAnalyze *ira, IrInstruction *bool_value, bool *out) {
if (bool_value == ira->codegen->invalid_instruction)
return false;
@ -2273,12 +2312,9 @@ static bool ir_resolve_bool(IrAnalyze *ira, IrInstruction *bool_value, bool *out
return false;
}
ConstExprValue *const_val = &bool_value->static_value;
if (const_val->special == ConstValSpecialRuntime) {
add_node_error(ira->codegen, bool_value->source_node,
buf_sprintf("unable to evaluate constant expression"));
ConstExprValue *const_val = ir_resolve_const(ira, bool_value);
if (!const_val)
return false;
}
*out = const_val->data.x_bool;
return true;
@ -4027,12 +4063,67 @@ static TypeTableEntry *ir_analyze_instruction_set_fn_test(IrAnalyze *ira,
}
fn_entry->fn_test_set_node = source_node;
if (fn_entry->is_test)
ira->codegen->test_fn_count += 1;
ir_build_const_from(ira, &set_fn_test_instruction->base, false);
return ira->codegen->builtin_types.entry_void;
}
static TypeTableEntry *ir_analyze_instruction_set_debug_safety(IrAnalyze *ira,
IrInstructionSetDebugSafety *set_debug_safety_instruction)
{
IrInstruction *target_instruction = set_debug_safety_instruction->scope_value->other;
TypeTableEntry *target_type = target_instruction->type_entry;
if (target_type->id == TypeTableEntryIdInvalid)
return ira->codegen->builtin_types.entry_invalid;
ConstExprValue *target_val = ir_resolve_const(ira, target_instruction);
if (!target_val)
return ira->codegen->builtin_types.entry_invalid;
BlockContext *target_context;
if (target_type->id == TypeTableEntryIdBlock) {
target_context = target_val->data.x_block;
} else if (target_type->id == TypeTableEntryIdFn) {
target_context = target_val->data.x_fn->fn_def_node->data.fn_def.block_context;
} else if (target_type->id == TypeTableEntryIdMetaType) {
TypeTableEntry *type_arg = target_val->data.x_type;
if (type_arg->id == TypeTableEntryIdStruct) {
target_context = type_arg->data.structure.block_context;
} else if (type_arg->id == TypeTableEntryIdEnum) {
target_context = type_arg->data.enumeration.block_context;
} else if (type_arg->id == TypeTableEntryIdUnion) {
target_context = type_arg->data.unionation.block_context;
} else {
add_node_error(ira->codegen, target_instruction->source_node,
buf_sprintf("expected scope reference, got type '%s'", buf_ptr(&type_arg->name)));
return ira->codegen->builtin_types.entry_invalid;
}
} else {
add_node_error(ira->codegen, target_instruction->source_node,
buf_sprintf("expected scope reference, got type '%s'", buf_ptr(&target_type->name)));
return ira->codegen->builtin_types.entry_invalid;
}
IrInstruction *debug_safety_on_value = set_debug_safety_instruction->debug_safety_on->other;
bool want_debug_safety;
if (!ir_resolve_bool(ira, debug_safety_on_value, &want_debug_safety))
return ira->codegen->builtin_types.entry_invalid;
AstNode *source_node = set_debug_safety_instruction->base.source_node;
if (target_context->safety_set_node) {
ErrorMsg *msg = add_node_error(ira->codegen, source_node,
buf_sprintf("function test attribute set twice"));
add_error_note(ira->codegen, msg, target_context->safety_set_node, buf_sprintf("first set here"));
return ira->codegen->builtin_types.entry_invalid;
}
target_context->safety_set_node = source_node;
target_context->safety_off = !want_debug_safety;
ir_build_const_from(ira, &set_debug_safety_instruction->base, false);
return ira->codegen->builtin_types.entry_void;
}
static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira,
IrInstructionSliceType *slice_type_instruction)
{
@ -4164,6 +4255,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_ptr_type_child(ira, (IrInstructionPtrTypeChild *)instruction);
case IrInstructionIdSetFnTest:
return ir_analyze_instruction_set_fn_test(ira, (IrInstructionSetFnTest *)instruction);
case IrInstructionIdSetDebugSafety:
return ir_analyze_instruction_set_debug_safety(ira, (IrInstructionSetDebugSafety *)instruction);
case IrInstructionIdSliceType:
return ir_analyze_instruction_slice_type(ira, (IrInstructionSliceType *)instruction);
case IrInstructionIdAsm:
@ -4257,6 +4350,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdReturn:
case IrInstructionIdUnreachable:
case IrInstructionIdSetFnTest:
case IrInstructionIdSetDebugSafety:
return true;
case IrInstructionIdPhi:
case IrInstructionIdUnOp:
@ -4854,64 +4948,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
// return g->builtin_types.entry_void;
//}
//
//static TypeTableEntry *analyze_set_debug_safety(CodeGen *g, ImportTableEntry *import,
// BlockContext *parent_context, AstNode *node)
//{
// AstNode **target_node = &node->data.fn_call_expr.params.at(0);
// AstNode **value_node = &node->data.fn_call_expr.params.at(1);
//
// TypeTableEntry *target_type = analyze_expression(g, import, parent_context, nullptr, *target_node);
// BlockContext *target_context;
// ConstExprValue *const_val = &get_resolved_expr(*target_node)->const_val;
// if (target_type->id == TypeTableEntryIdInvalid) {
// return g->builtin_types.entry_invalid;
// }
// if (!const_val->ok) {
// add_node_error(g, *target_node, buf_sprintf("unable to evaluate constant expression"));
// return g->builtin_types.entry_invalid;
// }
// if (target_type->id == TypeTableEntryIdBlock) {
// target_context = const_val->data.x_block;
// } else if (target_type->id == TypeTableEntryIdFn) {
// target_context = const_val->data.x_fn->fn_def_node->data.fn_def.block_context;
// } else if (target_type->id == TypeTableEntryIdMetaType) {
// TypeTableEntry *type_arg = const_val->data.x_type;
// if (type_arg->id == TypeTableEntryIdStruct) {
// target_context = type_arg->data.structure.block_context;
// } else if (type_arg->id == TypeTableEntryIdEnum) {
// target_context = type_arg->data.enumeration.block_context;
// } else if (type_arg->id == TypeTableEntryIdUnion) {
// target_context = type_arg->data.unionation.block_context;
// } else {
// add_node_error(g, *target_node,
// buf_sprintf("expected scope reference, got type '%s'", buf_ptr(&type_arg->name)));
// return g->builtin_types.entry_invalid;
// }
// } else {
// add_node_error(g, *target_node,
// buf_sprintf("expected scope reference, got type '%s'", buf_ptr(&target_type->name)));
// return g->builtin_types.entry_invalid;
// }
//
// bool want_debug_safety;
// bool ok = resolve_const_expr_bool(g, import, parent_context, value_node, &want_debug_safety);
// if (!ok) {
// return g->builtin_types.entry_invalid;
// }
//
// if (target_context->safety_set_node) {
// ErrorMsg *msg = add_node_error(g, node, buf_sprintf("debug safety for scope set twice"));
// add_error_note(g, msg, target_context->safety_set_node, buf_sprintf("first set here"));
// return g->builtin_types.entry_invalid;
// }
// target_context->safety_set_node = node;
//
// target_context->safety_off = !want_debug_safety;
//
// return g->builtin_types.entry_void;
//}
//static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
// TypeTableEntry *expected_type, AstNode *node)
//{
@ -5215,8 +5251,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
// return analyze_set_fn_static_eval(g, import, context, node);
// case BuiltinFnIdSetFnVisible:
// return analyze_set_fn_visible(g, import, context, node);
// case BuiltinFnIdSetDebugSafety:
// return analyze_set_debug_safety(g, import, context, node);
// }
// zig_unreachable();
//}

View File

@ -409,6 +409,14 @@ static void ir_print_set_fn_test(IrPrint *irp, IrInstructionSetFnTest *instructi
fprintf(irp->f, ")");
}
static void ir_print_set_debug_safety(IrPrint *irp, IrInstructionSetDebugSafety *instruction) {
fprintf(irp->f, "@setDebugSafety(");
ir_print_other_instruction(irp, instruction->scope_value);
fprintf(irp->f, ", ");
ir_print_other_instruction(irp, instruction->debug_safety_on);
fprintf(irp->f, ")");
}
static void ir_print_array_type(IrPrint *irp, IrInstructionArrayType *instruction) {
fprintf(irp->f, "[");
ir_print_other_instruction(irp, instruction->size);
@ -541,6 +549,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdSetFnTest:
ir_print_set_fn_test(irp, (IrInstructionSetFnTest *)instruction);
break;
case IrInstructionIdSetDebugSafety:
ir_print_set_debug_safety(irp, (IrInstructionSetDebugSafety *)instruction);
break;
case IrInstructionIdArrayType:
ir_print_array_type(irp, (IrInstructionArrayType *)instruction);
break;

View File

@ -1,13 +1,41 @@
fn add(a: i32, b: i32) -> i32 {
a + b
pub const SYS_write = 1;
pub const SYS_exit = 60;
pub const stdout_fileno = 1;
const text = "hello\n";
export nakedcc fn _start() -> unreachable {
myMain();
}
fn assert(ok: bool) {
if (!ok) @unreachable();
fn myMain() -> unreachable {
write(stdout_fileno, &text[0], text.len);
exit(0);
}
fn testAdd() {
@setFnTest(this, true);
assert(add(2, 3) == 5);
pub inline fn syscall1(number: usize, arg1: usize) -> usize {
asm volatile ("syscall"
: [ret] "={rax}" (-> usize)
: [number] "{rax}" (number),
[arg1] "{rdi}" (arg1)
: "rcx", "r11")
}
pub inline fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) -> usize {
asm volatile ("syscall"
: [ret] "={rax}" (-> usize)
: [number] "{rax}" (number),
[arg1] "{rdi}" (arg1),
[arg2] "{rsi}" (arg2),
[arg3] "{rdx}" (arg3)
: "rcx", "r11")
}
pub fn write(fd: i32, buf: &const u8, count: usize) -> usize {
syscall3(SYS_write, usize(fd), usize(buf), count)
}
pub fn exit(status: i32) -> unreachable {
syscall1(SYS_exit, usize(status));
@unreachable()
}