From f3f6c12a7cc6dca745ae40744a5220878ff9261e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 26 May 2022 11:58:55 +0100 Subject: [PATCH] Add `simd_clamp` --- core/intrinsics/intrinsics.odin | 6 ++-- core/simd/simd.odin | 8 ++++-- src/check_builtin.cpp | 51 +++++++++++++++++++++++++++++++++ src/checker_builtin_procs.hpp | 5 ++++ src/llvm_backend_proc.cpp | 22 ++++++++++++++ 5 files changed, 87 insertions(+), 5 deletions(-) diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index f8e138ef6..484cd945c 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -212,8 +212,10 @@ simd_xor :: proc(a, b: #simd[N]T) -> #simd[N]T --- simd_neg :: proc(a: #simd[N]T) -> #simd[N]T --- simd_abs :: proc(a: #simd[N]T) -> #simd[N]T --- -simd_min :: proc(a, b: #simd[N]T) -> #simd[N]T --- -simd_max :: proc(a, b: #simd[N]T) -> #simd[N]T --- + +simd_min :: proc(a, b: #simd[N]T) -> #simd[N]T --- +simd_max :: proc(a, b: #simd[N]T) -> #simd[N]T --- +simd_clamp :: proc(v, min, max: #simd[N]T) -> #simd[N]T --- // Return an unsigned integer of the same size as the input type // NOT A BOOLEAN diff --git a/core/simd/simd.odin b/core/simd/simd.odin index 5d2b5edab..1da0bd3e5 100644 --- a/core/simd/simd.odin +++ b/core/simd/simd.odin @@ -49,9 +49,11 @@ xor :: intrinsics.simd_xor neg :: intrinsics.simd_neg -abs :: intrinsics.simd_abs -min :: intrinsics.simd_min -max :: intrinsics.simd_max +abs :: intrinsics.simd_abs + +min :: intrinsics.simd_min +max :: intrinsics.simd_max +clamp :: intrinsics.simd_clamp // Return an unsigned integer of the same size as the input type // NOT A BOOLEAN diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 54bede3a8..45c9c93c5 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -956,6 +956,57 @@ bool check_builtin_simd_operation(CheckerContext *c, Operand *operand, Ast *call return true; } + case BuiltinProc_simd_clamp: + { + Operand x = {}; + Operand y = {}; + Operand z = {}; + check_expr(c, &x, ce->args[0]); if (x.mode == Addressing_Invalid) { return false; } + check_expr_with_type_hint(c, &y, ce->args[1], x.type); if (y.mode == Addressing_Invalid) { return false; } + check_expr_with_type_hint(c, &z, ce->args[2], x.type); if (z.mode == Addressing_Invalid) { return false; } + convert_to_typed(c, &y, x.type); + convert_to_typed(c, &z, x.type); + if (!is_type_simd_vector(x.type)) { + error(x.expr, "'%.*s' expected a simd vector type", LIT(builtin_name)); + return false; + } + if (!is_type_simd_vector(y.type)) { + error(y.expr, "'%.*s' expected a simd vector type", LIT(builtin_name)); + return false; + } + if (!is_type_simd_vector(z.type)) { + error(z.expr, "'%.*s' expected a simd vector type", LIT(builtin_name)); + return false; + } + if (!are_types_identical(x.type, y.type)) { + gbString xs = type_to_string(x.type); + gbString ys = type_to_string(y.type); + error(x.expr, "'%.*s' expected 2 arguments of the same type, got '%s' vs '%s'", LIT(builtin_name), xs, ys); + gb_string_free(ys); + gb_string_free(xs); + return false; + } + if (!are_types_identical(x.type, z.type)) { + gbString xs = type_to_string(x.type); + gbString zs = type_to_string(z.type); + error(x.expr, "'%.*s' expected 2 arguments of the same type, got '%s' vs '%s'", LIT(builtin_name), xs, zs); + gb_string_free(zs); + gb_string_free(xs); + return false; + } + Type *elem = base_array_type(x.type); + if (!is_type_integer(elem) && !is_type_float(elem)) { + gbString xs = type_to_string(x.type); + error(x.expr, "'%.*s' expected a #simd type with an integer or floating point element, got '%s'", LIT(builtin_name), xs); + gb_string_free(xs); + return false; + } + + operand->mode = Addressing_Value; + operand->type = x.type; + return true; + } + default: GB_PANIC("Unhandled simd intrinsic: %.*s", LIT(builtin_name)); } diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 13fe2822c..eea4d0a8b 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -141,6 +141,7 @@ BuiltinProc__simd_begin, BuiltinProc_simd_min, BuiltinProc_simd_max, + BuiltinProc_simd_clamp, BuiltinProc_simd_eq, BuiltinProc_simd_ne, @@ -415,9 +416,13 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("simd_or"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_xor"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_neg"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_abs"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_min"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_max"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_clamp"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_eq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_ne"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_lt"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index c433334d1..97bb02ba3 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1412,6 +1412,28 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const return res; } + 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; + + if (is_float) { + v = LLVMBuildSelect(p->builder, LLVMBuildFCmp(p->builder, LLVMRealOLT, v, min, ""), min, v, ""); + res.value = LLVMBuildSelect(p->builder, LLVMBuildFCmp(p->builder, LLVMRealOGT, v, max, ""), max, v, ""); + } else if (is_signed) { + v = LLVMBuildSelect(p->builder, LLVMBuildICmp(p->builder, LLVMIntSLT, v, min, ""), min, v, ""); + res.value = LLVMBuildSelect(p->builder, LLVMBuildICmp(p->builder, LLVMIntSGT, v, max, ""), max, v, ""); + } else { + v = LLVMBuildSelect(p->builder, LLVMBuildICmp(p->builder, LLVMIntULT, v, min, ""), min, v, ""); + res.value = LLVMBuildSelect(p->builder, LLVMBuildICmp(p->builder, LLVMIntUGT, v, max, ""), max, v, ""); + } + return res; + } + } GB_PANIC("Unhandled simd intrinsic: '%.*s'", LIT(builtin_procs[builtin_id].name));