diff --git a/lib/std/core/builtin.c3 b/lib/std/core/builtin.c3 index 4d4e45abb..c101cae80 100644 --- a/lib/std/core/builtin.c3 +++ b/lib/std/core/builtin.c3 @@ -159,6 +159,14 @@ macro void unsupported(String string = "Unsupported function invoked") @builtin $$unreachable(); } +/** + * Unconditionally break into an attached debugger when reached. + **/ +macro void breakpoint() @builtin +{ + $$breakpoint(); +} + macro any_make(void* ptr, typeid type) @builtin { return $$any_make(ptr, type); diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 052878e90..ffb33792a 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -888,6 +888,7 @@ typedef enum BUILTIN_ATOMIC_FETCH_INC_WRAP, BUILTIN_ATOMIC_FETCH_DEC_WRAP, BUILTIN_BITREVERSE, + BUILTIN_BREAKPOINT, BUILTIN_BSWAP, BUILTIN_CEIL, BUILTIN_COMPARE_EXCHANGE, diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 65fb2cedb..255d72298 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -740,6 +740,7 @@ static void llvm_codegen_setup() intrinsic_id.ctlz = lookup_intrinsic("llvm.ctlz"); intrinsic_id.ctpop = lookup_intrinsic("llvm.ctpop"); intrinsic_id.cttz = lookup_intrinsic("llvm.cttz"); + intrinsic_id.debugtrap = lookup_intrinsic("llvm.debugtrap"); intrinsic_id.exp = lookup_intrinsic("llvm.exp"); intrinsic_id.exp2 = lookup_intrinsic("llvm.exp2"); intrinsic_id.expect = lookup_intrinsic("llvm.expect"); diff --git a/src/compiler/llvm_codegen_builtins.c b/src/compiler/llvm_codegen_builtins.c index fdf2a70ee..0050c4080 100644 --- a/src/compiler/llvm_codegen_builtins.c +++ b/src/compiler/llvm_codegen_builtins.c @@ -888,6 +888,9 @@ void llvm_emit_builtin_call(GenContext *c, BEValue *result_value, Expr *expr) case BUILTIN_TRAP: llvm_value_set(result_value, llvm_emit_call_intrinsic(c, intrinsic_id.trap, NULL, 0, NULL, 0), type_void); return; + case BUILTIN_BREAKPOINT: + llvm_value_set(result_value, llvm_emit_call_intrinsic(c, intrinsic_id.debugtrap, NULL, 0, NULL, 0), type_void); + return; case BUILTIN_PREFETCH: llvm_emit_prefetch(c, result_value, expr); return; diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index dbc67e5b2..2055619c6 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -221,6 +221,7 @@ typedef struct unsigned ssub_overflow; unsigned ssub_sat; unsigned trap; + unsigned debugtrap; unsigned trunc; unsigned uadd_overflow; unsigned uadd_sat; diff --git a/src/compiler/sema_builtins.c b/src/compiler/sema_builtins.c index e5395306e..6665a4f2b 100644 --- a/src/compiler/sema_builtins.c +++ b/src/compiler/sema_builtins.c @@ -415,8 +415,10 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr) return sema_expr_analyse_syscall(context, expr); case BUILTIN_TRAP: case BUILTIN_UNREACHABLE: - expr->type = type_void; expr->call_expr.no_return = true; + FALLTHROUGH; + case BUILTIN_BREAKPOINT: + expr->type = type_void; return true; case BUILTIN_SYSCLOCK: expr->type = type_ulong; @@ -1002,6 +1004,7 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr) case BUILTIN_SWIZZLE2: case BUILTIN_SYSCLOCK: case BUILTIN_TRAP: + case BUILTIN_BREAKPOINT: case BUILTIN_UNREACHABLE: UNREACHABLE } @@ -1022,6 +1025,7 @@ static inline int builtin_expected_args(BuiltinFunction func) case BUILTIN_GET_ROUNDING_MODE: case BUILTIN_SYSCLOCK: case BUILTIN_TRAP: + case BUILTIN_BREAKPOINT: case BUILTIN_UNREACHABLE: return 0; case BUILTIN_ABS: diff --git a/src/compiler/symtab.c b/src/compiler/symtab.c index 9c62fbf03..75090c846 100644 --- a/src/compiler/symtab.c +++ b/src/compiler/symtab.c @@ -190,6 +190,7 @@ void symtab_init(uint32_t capacity) builtin_list[BUILTIN_ATOMIC_FETCH_INC_WRAP] = KW_DEF("atomic_fetch_inc_wrap"); builtin_list[BUILTIN_ATOMIC_FETCH_DEC_WRAP] = KW_DEF("atomic_fetch_dec_wrap"); builtin_list[BUILTIN_BITREVERSE] = KW_DEF("bitreverse"); + builtin_list[BUILTIN_BREAKPOINT] = KW_DEF("breakpoint"); builtin_list[BUILTIN_BSWAP] = KW_DEF("bswap"); builtin_list[BUILTIN_CEIL] = KW_DEF("ceil"); builtin_list[BUILTIN_COMPARE_EXCHANGE] = KW_DEF(("compare_exchange")); diff --git a/test/test_suite/builtins/trap.c3t b/test/test_suite/builtins/trap.c3t new file mode 100644 index 000000000..c2eb5bd07 --- /dev/null +++ b/test/test_suite/builtins/trap.c3t @@ -0,0 +1,12 @@ +module test; + +fn void main() +{ + $$breakpoint(); + $$trap(); +} + +/* #expect: test.ll + + call void @llvm.debugtrap() + call void @llvm.trap()