aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2022-05-26 17:09:46 +0100
committergingerBill <bill@gingerbill.org>2022-05-26 17:09:46 +0100
commitd0e8a735bae52eaa7d1d852953da721071571020 (patch)
tree76d4fdf971f7a8a4f85992e228c01b53a8b92fbe /src
parent208226dba29d46514c8c2b7a8fcd023f1ebf7bd8 (diff)
Add arithmetic operator support for simd vectors; Add `intrinsics.simd_and_not`
Diffstat (limited to 'src')
-rw-r--r--src/check_builtin.cpp1
-rw-r--r--src/check_expr.cpp7
-rw-r--r--src/checker_builtin_procs.hpp3
-rw-r--r--src/llvm_backend_expr.cpp40
-rw-r--r--src/llvm_backend_proc.cpp4
-rw-r--r--src/types.cpp3
6 files changed, 52 insertions, 6 deletions
diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp
index 34b7d14e9..bfaa91cf8 100644
--- a/src/check_builtin.cpp
+++ b/src/check_builtin.cpp
@@ -464,6 +464,7 @@ bool check_builtin_simd_operation(CheckerContext *c, Operand *operand, Ast *call
case BuiltinProc_simd_and:
case BuiltinProc_simd_or:
case BuiltinProc_simd_xor:
+ case BuiltinProc_simd_and_not:
{
Operand x = {};
Operand y = {};
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index b7568aa70..7fe9b8acf 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -1590,11 +1590,6 @@ bool check_unary_op(CheckerContext *c, Operand *o, Token op) {
bool check_binary_op(CheckerContext *c, Operand *o, Token op) {
Type *main_type = o->type;
- if (is_type_simd_vector(main_type)) {
- error(op, "Operator '%.*s' is not supported on #simd vector types, please use the intrinsics.simd_*", LIT(op.string));
- return false;
- }
-
// TODO(bill): Handle errors correctly
Type *type = base_type(core_array_type(main_type));
Type *ct = core_type(type);
@@ -2500,6 +2495,8 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node, Type *typ
gb_string_free(err_str);
}
+ // TODO(bill): Should we support shifts for fixed arrays and #simd vectors?
+
if (!is_type_integer(x->type)) {
gbString err_str = expr_to_string(y->expr);
error(node, "Shift operand '%s' must be an integer", err_str);
diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp
index 350213de2..eb4bc1498 100644
--- a/src/checker_builtin_procs.hpp
+++ b/src/checker_builtin_procs.hpp
@@ -135,6 +135,7 @@ BuiltinProc__simd_begin,
BuiltinProc_simd_and,
BuiltinProc_simd_or,
BuiltinProc_simd_xor,
+ BuiltinProc_simd_and_not,
BuiltinProc_simd_neg,
BuiltinProc_simd_abs,
@@ -417,6 +418,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("simd_and"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("simd_or"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("simd_xor"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+ {STR_LIT("simd_and_not"), 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},
diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp
index 10c337650..55b76b93a 100644
--- a/src/llvm_backend_expr.cpp
+++ b/src/llvm_backend_expr.cpp
@@ -258,7 +258,13 @@ lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, Type *type)
LLVMBuildStore(p->builder, v2, LLVMBuildStructGEP(p->builder, addr.addr.value, 2, ""));
LLVMBuildStore(p->builder, v3, LLVMBuildStructGEP(p->builder, addr.addr.value, 3, ""));
return lb_addr_load(p, addr);
-
+ } else if (is_type_simd_vector(x.type)) {
+ Type *elem = base_array_type(x.type);
+ if (is_type_float(elem)) {
+ res.value = LLVMBuildFNeg(p->builder, x.value, "");
+ } else {
+ res.value = LLVMBuildNeg(p->builder, x.value, "");
+ }
} else {
GB_PANIC("Unhandled type %s", type_to_string(x.type));
}
@@ -2559,6 +2565,38 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri
case Token_NotEq: pred = LLVMIntNE; break;
}
res.value = LLVMBuildICmp(p->builder, pred, left.value, right.value, "");
+ } else if (is_type_simd_vector(a)) {
+ LLVMValueRef mask = nullptr;
+ Type *elem = base_array_type(a);
+ if (is_type_float(elem)) {
+ LLVMRealPredicate pred = {};
+ switch (op_kind) {
+ case Token_CmpEq: pred = LLVMRealOEQ; break;
+ case Token_NotEq: pred = LLVMRealONE; break;
+ }
+ mask = LLVMBuildFCmp(p->builder, pred, left.value, right.value, "");
+ } else {
+ LLVMIntPredicate pred = {};
+ switch (op_kind) {
+ case Token_CmpEq: pred = LLVMIntEQ; break;
+ case Token_NotEq: pred = LLVMIntNE; break;
+ }
+ mask = LLVMBuildICmp(p->builder, pred, left.value, right.value, "");
+ }
+ GB_ASSERT_MSG(mask != nullptr, "Unhandled comparison kind %s (%s) %.*s %s (%s)", type_to_string(left.type), type_to_string(base_type(left.type)), LIT(token_strings[op_kind]), type_to_string(right.type), type_to_string(base_type(right.type)));
+
+ // TODO(bill): is this a good approach to dealing with comparisons of vectors?
+ char const *name = "llvm.vector.reduce.umax";
+ LLVMTypeRef types[1] = {LLVMTypeOf(mask)};
+ unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
+ GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
+ LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
+
+ LLVMValueRef args[1] = {};
+ args[0] = mask;
+ res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
+ return res;
+
} else {
GB_PANIC("Unhandled comparison kind %s (%s) %.*s %s (%s)", type_to_string(left.type), type_to_string(base_type(left.type)), LIT(token_strings[op_kind]), type_to_string(right.type), type_to_string(base_type(right.type)));
}
diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp
index a56aa862a..99c023311 100644
--- a/src/llvm_backend_proc.cpp
+++ b/src/llvm_backend_proc.cpp
@@ -1097,11 +1097,15 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const
case BuiltinProc_simd_and:
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;
case BuiltinProc_simd_xor: op_code = LLVMXor; break;
+ case BuiltinProc_simd_and_not:
+ res.value = LLVMBuildAnd(p->builder, arg0.value, LLVMBuildNot(p->builder, arg1.value, ""), "");
+ return res;
}
if (op_code) {
res.value = LLVMBuildBinOp(p->builder, op_code, arg0.value, arg1.value, "");
diff --git a/src/types.cpp b/src/types.cpp
index 6f61015d3..ad83e0568 100644
--- a/src/types.cpp
+++ b/src/types.cpp
@@ -2306,6 +2306,9 @@ bool is_type_comparable(Type *t) {
}
}
return true;
+
+ case Type_SimdVector:
+ return true;
}
return false;
}