diff options
| author | gingerBill <bill@gingerbill.org> | 2022-05-28 15:41:11 +0100 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2022-05-28 15:41:11 +0100 |
| commit | d7eaf0f87b7677e84bf1f65c34305801748c39ee (patch) | |
| tree | 21fe8f1ea895bf2fdec7e551adfcaccea7f099c2 | |
| parent | 618d3bf62fbcfa6ca7f827ad4090143b8535b4a2 (diff) | |
Add `intrinsics.x86_cpuid` and `intrinsics.x86_xgetbv`
| -rw-r--r-- | core/intrinsics/intrinsics.odin | 4 | ||||
| -rw-r--r-- | core/simd/x86/ssse3.odin | 3 | ||||
| -rw-r--r-- | src/build_settings.cpp | 9 | ||||
| -rw-r--r-- | src/check_builtin.cpp | 60 | ||||
| -rw-r--r-- | src/checker_builtin_procs.hpp | 6 | ||||
| -rw-r--r-- | src/llvm_backend_proc.cpp | 63 |
6 files changed, 124 insertions, 21 deletions
diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index 8becd998d..89f9a5f20 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -278,6 +278,10 @@ wasm_memory_size :: proc(index: uintptr) -> int --- wasm_memory_atomic_wait32 :: proc(ptr: ^u32, expected: u32, timeout_ns: i64) -> u32 --- wasm_memory_atomic_notify32 :: proc(ptr: ^u32, waiters: u32) -> (waiters_woken_up: u32) --- +// x86 Targets (i386, amd64) +cpuid :: proc(ax, cx: u32) -> (eax, ebc, ecx, edx: u32) --- +xgetbv :: proc(cx: u32) -> (eax, edx: u32) --- + // Darwin targets only objc_object :: struct{} diff --git a/core/simd/x86/ssse3.odin b/core/simd/x86/ssse3.odin index 920dddd85..4abd4c84c 100644 --- a/core/simd/x86/ssse3.odin +++ b/core/simd/x86/ssse3.odin @@ -121,4 +121,5 @@ foreign _ { @(link_name = "llvm.x86.ssse3.psign.w.128") psignw128 :: proc(a, b: i16x8) -> i16x8 --- @(link_name = "llvm.x86.ssse3.psign.d.128") - psignd128 :: proc(a, b: i32x4) -> i32x4 ---}
\ No newline at end of file + psignd128 :: proc(a, b: i32x4) -> i32x4 --- +}
\ No newline at end of file diff --git a/src/build_settings.cpp b/src/build_settings.cpp index b458d8308..27e09a0db 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -629,6 +629,15 @@ bool is_arch_wasm(void) { return false; } +bool is_arch_x86(void) { + switch (build_context.metrics.arch) { + case TargetArch_i386: + case TargetArch_amd64: + return true; + } + return false; +} + bool allow_check_foreign_filepath(void) { switch (build_context.metrics.arch) { case TargetArch_wasm32: diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 9fa9cc590..f8ac545be 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1060,8 +1060,8 @@ bool check_builtin_simd_operation(CheckerContext *c, Operand *operand, Ast *call operand->type = t_untyped_integer; operand->mode = Addressing_Constant; operand->value = exact_value_i64(result); + return true; } - default: GB_PANIC("Unhandled simd intrinsic: %.*s", LIT(builtin_name)); } @@ -5275,6 +5275,64 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 } break; + case BuiltinProc_x86_cpuid: + { + if (!is_arch_x86()) { + error(call, "'%.*s' is only allowed on x86 targets (i386, amd64)", LIT(builtin_name)); + return false; + } + + Operand ax = {}; + Operand cx = {}; + + check_expr_with_type_hint(c, &ax, ce->args[0], t_u32); if (ax.mode == Addressing_Invalid) return false; + check_expr_with_type_hint(c, &cx, ce->args[1], t_u32); if (cx.mode == Addressing_Invalid) return false; + convert_to_typed(c, &ax, t_u32); if (ax.mode == Addressing_Invalid) return false; + convert_to_typed(c, &cx, t_u32); if (cx.mode == Addressing_Invalid) return false; + if (!are_types_identical(ax.type, t_u32)) { + gbString str = type_to_string(ax.type); + error(ax.expr, "'%.*s' expected a u32, got %s", LIT(builtin_name), str); + gb_string_free(str); + return false; + } + if (!are_types_identical(cx.type, t_u32)) { + gbString str = type_to_string(cx.type); + error(cx.expr, "'%.*s' expected a u32, got %s", LIT(builtin_name), str); + gb_string_free(str); + return false; + } + Type *types[4] = {t_u32, t_u32, t_u32, t_u32}; // eax ebc ecx edx + operand->type = alloc_type_tuple_from_field_types(types, gb_count_of(types), false, false); + operand->mode = Addressing_Value; + operand->value = {}; + return true; + } + break; + case BuiltinProc_x86_xgetbv: + { + if (!is_arch_x86()) { + error(call, "'%.*s' is only allowed on x86 targets (i386, amd64)", LIT(builtin_name)); + return false; + } + + Operand cx = {}; + check_expr_with_type_hint(c, &cx, ce->args[0], t_u32); if (cx.mode == Addressing_Invalid) return false; + convert_to_typed(c, &cx, t_u32); if (cx.mode == Addressing_Invalid) return false; + if (!are_types_identical(cx.type, t_u32)) { + gbString str = type_to_string(cx.type); + error(cx.expr, "'%.*s' expected a u32, got %s", LIT(builtin_name), str); + gb_string_free(str); + return false; + } + + Type *types[2] = {t_u32, t_u32}; + operand->type = alloc_type_tuple_from_field_types(types, gb_count_of(types), false, false); + operand->mode = Addressing_Value; + operand->value = {}; + return true; + } + break; + } return true; diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 1d7ee0a34..35f14c6a8 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -187,6 +187,9 @@ BuiltinProc__simd_end, // Platform specific intrinsics BuiltinProc_syscall, + BuiltinProc_x86_cpuid, + BuiltinProc_x86_xgetbv, + // Constant type tests BuiltinProc__type_begin, @@ -470,10 +473,13 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("simd_rotate_right"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_x86__MM_SHUFFLE"), 4, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("syscall"), 1, true, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("x86_cpuid"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("x86_xgetbv"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 4d0df2861..8cbb533bc 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1007,9 +1007,9 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const lbValue res = {}; res.type = tv.type; - lbValue arg0 = lb_build_expr(p, ce->args[0]); - lbValue arg1 = {}; - lbValue arg2 = {}; + lbValue arg0 = {}; if (ce->args.count > 0) arg0 = lb_build_expr(p, ce->args[0]); + lbValue arg1 = {}; if (ce->args.count > 1) arg0 = lb_build_expr(p, ce->args[1]); + lbValue arg2 = {}; if (ce->args.count > 2) arg0 = lb_build_expr(p, ce->args[2]); Type *elem = base_array_type(arg0.type); @@ -1024,7 +1024,6 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const case BuiltinProc_simd_mul: case BuiltinProc_simd_div: case BuiltinProc_simd_rem: - arg1 = lb_build_expr(p, ce->args[1]); if (is_float) { switch (builtin_id) { case BuiltinProc_simd_add: op_code = LLVMFAdd; break; @@ -1062,7 +1061,6 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const case BuiltinProc_simd_shr: // Odin logic case BuiltinProc_simd_shl_masked: // C logic case BuiltinProc_simd_shr_masked: // C logic - arg1 = lb_build_expr(p, ce->args[1]); { i64 sz = type_size_of(elem); GB_ASSERT(arg0.type->kind == Type_SimdVector); @@ -1098,7 +1096,6 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const case BuiltinProc_simd_or: case BuiltinProc_simd_xor: case BuiltinProc_simd_and_not: - arg1 = lb_build_expr(p, ce->args[1]); switch (builtin_id) { case BuiltinProc_simd_and: op_code = LLVMAnd; break; case BuiltinProc_simd_or: op_code = LLVMOr; break; @@ -1143,7 +1140,6 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const } return res; case BuiltinProc_simd_max: - arg1 = lb_build_expr(p, ce->args[1]); if (is_float) { LLVMValueRef cond = LLVMBuildFCmp(p->builder, LLVMRealOGT, arg0.value, arg1.value, ""); res.value = LLVMBuildSelect(p->builder, cond, arg0.value, arg1.value, ""); @@ -1158,7 +1154,6 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const case BuiltinProc_simd_lanes_le: case BuiltinProc_simd_lanes_gt: case BuiltinProc_simd_lanes_ge: - arg1 = lb_build_expr(p, ce->args[1]); if (is_float) { LLVMRealPredicate pred = cast(LLVMRealPredicate)0; switch (builtin_id) { @@ -1193,12 +1188,9 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const break; case BuiltinProc_simd_extract: - arg1 = lb_build_expr(p, ce->args[1]); res.value = LLVMBuildExtractElement(p->builder, arg0.value, arg1.value, ""); return res; case BuiltinProc_simd_replace: - arg1 = lb_build_expr(p, ce->args[1]); - arg2 = lb_build_expr(p, ce->args[2]); res.value = LLVMBuildInsertElement(p->builder, arg0.value, arg2.value, arg1.value, ""); return res; @@ -1283,12 +1275,9 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const case BuiltinProc_simd_shuffle: { - arg1 = lb_build_expr(p, ce->args[1]); - Type *vt = arg0.type; GB_ASSERT(vt->kind == Type_SimdVector); - i64 indices_count = ce->args.count-2; i64 max_count = vt->SimdVector.count*2; GB_ASSERT(indices_count <= max_count); @@ -1394,8 +1383,6 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const case BuiltinProc_simd_add_sat: case BuiltinProc_simd_sub_sat: { - arg1 = lb_build_expr(p, ce->args[1]); - char const *name = nullptr; switch (builtin_id) { case BuiltinProc_simd_add_sat: name = is_signed ? "llvm.sadd.sat" : "llvm.uadd.sat"; break; @@ -1417,9 +1404,6 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const case BuiltinProc_simd_clamp: { - arg1 = lb_build_expr(p, ce->args[1]); - arg2 = lb_build_expr(p, ce->args[2]); - LLVMValueRef v = arg0.value; LLVMValueRef min = arg1.value; LLVMValueRef max = arg2.value; @@ -2737,6 +2721,47 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, return res; } + + case BuiltinProc_x86_cpuid: + { + Type *param_types[2] = {t_u32, t_u32}; + Type *type = alloc_type_proc_from_types(param_types, gb_count_of(param_types), tv.type, false, ProcCC_None); + LLVMTypeRef func_type = LLVMGetElementType(lb_type(p->module, type)); + LLVMValueRef the_asm = llvm_get_inline_asm( + func_type, + str_lit("cpuid"), + str_lit("={ax},={bx},={cx},={dx},{ax},{cx}"), + true + ); + GB_ASSERT(the_asm != nullptr); + + LLVMValueRef args[2] = {}; + args[0] = lb_emit_conv(p, lb_build_expr(p, ce->args[0]), t_u32).value; + args[1] = lb_emit_conv(p, lb_build_expr(p, ce->args[1]), t_u32).value; + lbValue res = {}; + res.type = tv.type; + res.value = LLVMBuildCall2(p->builder, func_type, the_asm, args, gb_count_of(args), ""); + return res; + } + case BuiltinProc_x86_xgetbv: + { + Type *type = alloc_type_proc_from_types(&t_u32, 1, tv.type, false, ProcCC_None); + LLVMTypeRef func_type = LLVMGetElementType(lb_type(p->module, type)); + LLVMValueRef the_asm = llvm_get_inline_asm( + func_type, + str_lit("xgetbv"), + str_lit("={ax},={dx},{cx}"), + true + ); + GB_ASSERT(the_asm != nullptr); + + LLVMValueRef args[1] = {}; + args[0] = lb_emit_conv(p, lb_build_expr(p, ce->args[0]), t_u32).value; + lbValue res = {}; + res.type = tv.type; + res.value = LLVMBuildCall2(p->builder, func_type, the_asm, args, gb_count_of(args), ""); + return res; + } } GB_PANIC("Unhandled built-in procedure %.*s", LIT(builtin_procs[id].name)); |