IR: support setDebugSafety builtin function
parent
ed31ae8867
commit
bf7cde62c5
|
@ -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;
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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();
|
||||
|
|
166
src/ir.cpp
166
src/ir.cpp
|
@ -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();
|
||||
//}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue