Browse Source

EXPERIMENTAL `intrinsics.valgrind_client_request`

gingerBill 3 years ago
parent
commit
82e840a0ca

+ 3 - 0
core/intrinsics/intrinsics.odin

@@ -295,6 +295,9 @@ objc_register_selector :: proc($name: string) -> objc_SEL   ---
 objc_find_class        :: proc($name: string) -> objc_Class ---
 objc_find_class        :: proc($name: string) -> objc_Class ---
 objc_register_class    :: proc($name: string) -> objc_Class ---
 objc_register_class    :: proc($name: string) -> objc_Class ---
 
 
+
+valgrind_client_request :: proc(default: uintptr, request: uintptr, a0, a1, a2, a3, a4: uintptr) -> uintptr ---
+
 // Internal compiler use only
 // Internal compiler use only
 
 
 __entry_point :: proc() ---
 __entry_point :: proc() ---

+ 3 - 0
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_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_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_FOREIGN_ERROR_PROCEDURES;
+	bool   ODIN_VALGRIND_SUPPORT;
 
 
 	ErrorPosStyle ODIN_ERROR_POS_STYLE;
 	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->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_X64
 	#undef LINK_FLAG_386
 	#undef LINK_FLAG_386
 }
 }

+ 35 - 0
src/check_builtin.cpp

@@ -5388,6 +5388,41 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 		}
 		}
 		break;
 		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;
 	return true;

+ 3 - 0
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_FOREIGN_ERROR_PROCEDURES", bc->ODIN_FOREIGN_ERROR_PROCEDURES);
 	add_global_bool_constant("ODIN_DISALLOW_RTTI",            bc->disallow_rtti);
 	add_global_bool_constant("ODIN_DISALLOW_RTTI",            bc->disallow_rtti);
 
 
+	add_global_bool_constant("ODIN_VALGRIND_SUPPORT",         bc->ODIN_VALGRIND_SUPPORT);
+
+
 
 
 // Builtin Procedures
 // Builtin Procedures
 	for (isize i = 0; i < gb_count_of(builtin_procs); i++) {
 	for (isize i = 0; i < gb_count_of(builtin_procs); i++) {

+ 4 - 0
src/checker_builtin_procs.hpp

@@ -291,6 +291,8 @@ BuiltinProc__type_end,
 	BuiltinProc_wasm_memory_atomic_wait32,
 	BuiltinProc_wasm_memory_atomic_wait32,
 	BuiltinProc_wasm_memory_atomic_notify32,
 	BuiltinProc_wasm_memory_atomic_notify32,
 
 
+	BuiltinProc_valgrind_client_request,
+
 	BuiltinProc_COUNT,
 	BuiltinProc_COUNT,
 };
 };
 gb_global BuiltinProc builtin_procs[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_size"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
 	{STR_LIT("wasm_memory_atomic_wait32"), 3, 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("wasm_memory_atomic_notify32"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+
+	{STR_LIT("valgrind_client_request"), 7, false, Expr_Expr, BuiltinProcPkg_intrinsics},
 };
 };

+ 49 - 0
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), "");
 			res.value = LLVMBuildCall2(p->builder, func_type, the_asm, args, gb_count_of(args), "");
 			return res;
 			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));
 	GB_PANIC("Unhandled built-in procedure %.*s", LIT(builtin_procs[id].name));