aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2022-08-17 13:52:13 +0100
committergingerBill <bill@gingerbill.org>2022-08-17 13:52:13 +0100
commit82e840a0ca3fb547ac93e680a3dcbbb67958077f (patch)
tree7c2eeb580c952755c507292b12e2fe72dda16d37 /src
parent82765ca96e90f8ca3d2870e1b00bba3fecc0a78f (diff)
EXPERIMENTAL `intrinsics.valgrind_client_request`
Diffstat (limited to 'src')
-rw-r--r--src/build_settings.cpp3
-rw-r--r--src/check_builtin.cpp35
-rw-r--r--src/checker.cpp3
-rw-r--r--src/checker_builtin_procs.hpp4
-rw-r--r--src/llvm_backend_proc.cpp49
5 files changed, 94 insertions, 0 deletions
diff --git a/src/build_settings.cpp b/src/build_settings.cpp
index d49f1cecf..9d5c3e556 100644
--- a/src/build_settings.cpp
+++ b/src/build_settings.cpp
@@ -228,6 +228,7 @@ struct BuildContext {
bool ODIN_DISABLE_ASSERT; // Whether the default 'assert' et al is disabled in code or not
bool ODIN_DEFAULT_TO_NIL_ALLOCATOR; // Whether the default allocator is a "nil" allocator or not (i.e. it does nothing)
bool ODIN_FOREIGN_ERROR_PROCEDURES;
+ bool ODIN_VALGRIND_SUPPORT;
ErrorPosStyle ODIN_ERROR_POS_STYLE;
@@ -1190,6 +1191,8 @@ void init_build_context(TargetMetrics *cross_target) {
bc->optimization_level = gb_clamp(bc->optimization_level, 0, 3);
+ bc->ODIN_VALGRIND_SUPPORT = is_arch_x86() && build_context.metrics.os != TargetOs_windows;
+
#undef LINK_FLAG_X64
#undef LINK_FLAG_386
}
diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp
index 687f1694b..83136d576 100644
--- a/src/check_builtin.cpp
+++ b/src/check_builtin.cpp
@@ -5388,6 +5388,41 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
}
break;
+ case BuiltinProc_valgrind_client_request:
+ {
+ if (!is_arch_x86()) {
+ error(call, "'%.*s' is only allowed on x86 targets (i386, amd64)", LIT(builtin_name));
+ return false;
+ }
+
+ enum {ARG_COUNT = 7};
+ GB_ASSERT(builtin_procs[BuiltinProc_valgrind_client_request].arg_count == ARG_COUNT);
+
+ Operand operands[ARG_COUNT] = {};
+ for (isize i = 0; i < ARG_COUNT; i++) {
+ Operand *op = &operands[i];
+ check_expr_with_type_hint(c, op, ce->args[i], t_uintptr);
+ if (op->mode == Addressing_Invalid) {
+ return false;
+ }
+ convert_to_typed(c, op, t_uintptr);
+ if (op->mode == Addressing_Invalid) {
+ return false;
+ }
+ if (!are_types_identical(op->type, t_uintptr)) {
+ gbString str = type_to_string(op->type);
+ error(op->expr, "'%.*s' expected a uintptr, got %s", LIT(builtin_name), str);
+ gb_string_free(str);
+ return false;
+ }
+ }
+
+ operand->type = t_uintptr;
+ operand->mode = Addressing_Value;
+ operand->value = {};
+ return true;
+ }
+
}
return true;
diff --git a/src/checker.cpp b/src/checker.cpp
index d01dc5323..a7470a4c9 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -1037,6 +1037,9 @@ void init_universal(void) {
add_global_bool_constant("ODIN_FOREIGN_ERROR_PROCEDURES", bc->ODIN_FOREIGN_ERROR_PROCEDURES);
add_global_bool_constant("ODIN_DISALLOW_RTTI", bc->disallow_rtti);
+ add_global_bool_constant("ODIN_VALGRIND_SUPPORT", bc->ODIN_VALGRIND_SUPPORT);
+
+
// Builtin Procedures
for (isize i = 0; i < gb_count_of(builtin_procs); i++) {
diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp
index 8dd021255..717422df1 100644
--- a/src/checker_builtin_procs.hpp
+++ b/src/checker_builtin_procs.hpp
@@ -291,6 +291,8 @@ BuiltinProc__type_end,
BuiltinProc_wasm_memory_atomic_wait32,
BuiltinProc_wasm_memory_atomic_notify32,
+ BuiltinProc_valgrind_client_request,
+
BuiltinProc_COUNT,
};
gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
@@ -582,4 +584,6 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("wasm_memory_size"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("wasm_memory_atomic_wait32"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("wasm_memory_atomic_notify32"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+
+ {STR_LIT("valgrind_client_request"), 7, false, Expr_Expr, BuiltinProcPkg_intrinsics},
};
diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp
index d7055ea31..f85d8397c 100644
--- a/src/llvm_backend_proc.cpp
+++ b/src/llvm_backend_proc.cpp
@@ -2745,6 +2745,55 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
res.value = LLVMBuildCall2(p->builder, func_type, the_asm, args, gb_count_of(args), "");
return res;
}
+
+ case BuiltinProc_valgrind_client_request:
+ {
+ lbValue args[7] = {};
+ for (isize i = 0; i < 7; i++) {
+ args[i] = lb_emit_conv(p, lb_build_expr(p, ce->args[i]), t_uintptr);
+ }
+ if (!build_context.ODIN_VALGRIND_SUPPORT) {
+ return args[0];
+ }
+ lbValue array = lb_generate_local_array(p, t_uintptr, 6, false);
+ for (isize i = 0; i < 6; i++) {
+ lbValue gep = lb_emit_array_epi(p, array, i);
+ lb_emit_store(p, gep, args[i+1]);
+ }
+
+ switch (build_context.metrics.arch) {
+ case TargetArch_amd64:
+ {
+ Type *param_types[2] = {};
+ param_types[0] = t_uintptr;
+ param_types[1] = array.type;
+
+ Type *type = alloc_type_proc_from_types(param_types, gb_count_of(param_types), t_uintptr, false, ProcCC_None);
+ LLVMTypeRef func_type = lb_get_procedure_raw_type(p->module, type);
+ LLVMValueRef the_asm = llvm_get_inline_asm(
+ func_type,
+ str_lit("rolq $3, %rdi; rolq $13, %rdi\n rolq $61, %rdi; rolq $51, %rdi\n xchgq %rbx, %rbx"),
+ str_lit("={rdx},{rdx},{rax},cc,memory"),
+ true
+ );
+
+ LLVMValueRef asm_args[2] = {};
+ asm_args[0] = args[0].value;
+ asm_args[1] = array.value;
+
+ lbValue res = {};
+ res.type = t_uintptr;
+ res.value = LLVMBuildCall2(p->builder, func_type, the_asm, asm_args, gb_count_of(asm_args), "");
+ return res;
+ }
+ break;
+ default:
+ GB_PANIC("Unsupported architecture: %.*s", LIT(target_arch_names[build_context.metrics.arch]));
+ break;
+ }
+
+ }
+
}
GB_PANIC("Unhandled built-in procedure %.*s", LIT(builtin_procs[id].name));