Added initial intvec/floatvec operator

This commit is contained in:
Christoffer Lerno
2022-09-11 02:28:12 +02:00
committed by Christoffer Lerno
parent 3d110850df
commit 3a09f71830
15 changed files with 265 additions and 71 deletions

View File

@@ -3,7 +3,7 @@ module std::bits;
/**
* @require types::is_intlike($typeof(i)) `The input must be an integer or integer vector`
**/
macro popcount(i)
macro popcount(i) @operator(intvec)
{
return $$popcount(i);
}
@@ -27,7 +27,7 @@ macro bswap(i) @builtin
/**
* @require types::is_intlike($typeof(i)) `The input must be an integer or integer vector`
**/
macro ctz(i) @builtin
macro ctz(i) @operator(intvec) @builtin
{
return $$ctz(i);
}
@@ -35,15 +35,14 @@ macro ctz(i) @builtin
/**
* @require types::is_intlike($typeof(i)) `The input must be an integer or integer vector`
**/
macro clz(i) @builtin
macro clz(i) @operator(intvec) @builtin
{
return $$clz(i);
}
/**
* @require types::is_intlike($typeof(hi)) && types::is_intlike($typeof(lo)) && types::is_intlike($typeof(shift)) `The input must be an integer or integer vector`
* @require types::is_same_type(hi, lo) `Hi and low arguments must have the same type`
* @require types::is_same_type(hi, shift) `The shift value must have the same type as shifted types`
* @require types::@has_same(hi, lo, shift) `Hi, low and shift arguments must have the same type`
**/
macro fshl(hi, lo, shift) @builtin
{
@@ -52,8 +51,7 @@ macro fshl(hi, lo, shift) @builtin
/**
* @require types::is_intlike($typeof(hi)) && types::is_intlike($typeof(lo)) && types::is_intlike($typeof(shift)) `The input must be an integer or integer vector`
* @require types::is_same_type(hi, lo) `Hi and low arguments must have the same type`
* @require types::is_same_type(hi, shift) `The shift value must have the same type as shifted types`
* @require types::@has_same(hi, lo, shift) `Hi, low and shift arguments must have the same type`
**/
macro fshr(hi, lo, shift) @builtin
{
@@ -62,18 +60,18 @@ macro fshr(hi, lo, shift) @builtin
/**
* @require types::is_intlike($typeof(i)) && types::is_intlike($typeof(shift)) `The input must be an integer or integer vector`
* @require types::is_same_type(i, shift) `The shift value must have the same type as shifted types`
* @require types::@has_same(i, shift) `The shift value must have the same type as shifted types`
**/
macro rotl(i, shift) @builtin
macro rotl(i, shift) @operator(intvec) @builtin
{
return $$fshl(i, i, shift);
}
/**
* @require types::is_intlike($typeof(i)) && types::is_intlike($typeof(shift)) `The input must be an integer or integer vector`
* @require types::is_same_type(i, shift) `The shift value must have the same type as shifted types`
* @require types::@has_same(i, shift) `The shift value must have the same type as shifted types`
**/
macro rotr(i, shift) @builtin
macro rotr(i, shift) @operator(intvec) @builtin
{
return $$fshr(i, i, shift);
}

View File

@@ -134,6 +134,18 @@ macro bool is_intlike($Type)
$endswitch;
}
macro bool is_floatlike($Type)
{
$switch ($Type.kind):
$case FLOAT:
return true;
$case VECTOR:
return $Type.inner.kind == TypeKind.FLOAT;
$default:
return false;
$endswitch;
}
macro bool is_vector($Type)
{
return $Type.kind == TypeKind.VECTOR;
@@ -144,9 +156,18 @@ macro bool is_same($TypeA, $TypeB)
return $TypeA.typeid == $TypeB.typeid;
}
macro bool is_same_type(a, b)
macro bool @has_same(#a, #b, ...)
{
return $typeof(a).typeid == $typeof(b).typeid;
var $type_a = $typeof(#a).typeid;
$if ($type_a != $typeof(#b).typeid):
return false;
$endif;
$for (var $i = 0; $i < $vacount; $i++):
$if ($typeof($vaexpr($i)).typeid != $type_a):
return false;
$endif;
$endfor;
return true;
}
macro bool is_equatable_value(value)

View File

@@ -96,47 +96,60 @@ fn double log2(double x) @inline
return $$log2(x);
}
fn double log(double x) @inline
/**
* @require types::is_floatlike($typeof(f)) `The input must be a floating point value or float vector`
**/
macro log(f)
{
return $$log(x);
return $$log(f);
}
fn double cos(double x) @inline
/**
* @require types::is_floatlike($typeof(f)) `The input must be a floating point value or float vector`
**/
macro cos(f)
{
return $$cos(x);
return $$cos(f);
}
fn float cosf(float x) @inline
/**
* @require types::is_floatlike($typeof(f)) `The input must be a floating point value or float vector`
**/
macro sin(f)
{
return $$cos(x);
return $$sin(f);
}
fn double sin(double x) @inline
/**
* @require types::is_floatlike($typeof(f)) `The input must be a floating point value or float vector`
**/
macro exp(f)
{
return $$sin(x);
return $$exp(f);
}
fn float sinf(float x) @inline
/**
* @require types::is_floatlike($typeof(f)) `The input must be a floating point value or float vector`
* @require types::@has_same(f, exp) `Parameters must have the same type`
**/
macro pow(f, exp) @operator(floatvec)
{
return $$sin(x);
return $$pow(f, exp);
}
fn double exp(double x) @inline
{
return $$exp(x);
}
fn double pow(double x, double y) @inline
{
return $$pow(x, y);
}
fn double trunc(double x) @inline
/**
* @require types::is_floatlike($typeof(f)) `The input must be a floating point value or float vector`
**/
macro trunc(x) @operator(floatvec)
{
return $$trunc(x);
}
fn double ceil(double x) @inline
/**
* @require types::is_floatlike($typeof(f)) `The input must be a floating point value or float vector`
**/
macro ceil(x) @operator(floatvec)
{
return $$ceil(x);
}

View File

@@ -341,8 +341,8 @@ fn Matrix4x4 Matrix4x4.translate(Matrix4x4* m, float[<3>] v)
fn Matrix3x3 Matrix3x3.rotate(Matrix3x3* m, float r)
{
return m.mul(Matrix3x3 {
math::cosf(r), -math::sinf(r), 0,
math::sinf(r), math::cosf(r), 0,
math::cos(r), -math::sin(r), 0,
math::sin(r), math::cos(r), 0,
0, 0, 1,
});
}
@@ -351,8 +351,8 @@ fn Matrix3x3 Matrix3x3.rotate(Matrix3x3* m, float r)
fn Matrix4x4 Matrix4x4.rotate_z(Matrix4x4* m, float r)
{
return m.mul(Matrix4x4 {
math::cosf(r), -math::sinf(r), 0, 0,
math::sinf(r), math::cosf(r), 0, 0,
math::cos(r), -math::sin(r), 0, 0,
math::sin(r), math::cos(r), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
});
@@ -362,9 +362,9 @@ fn Matrix4x4 Matrix4x4.rotate_z(Matrix4x4* m, float r)
fn Matrix4x4 Matrix4x4.rotate_y(Matrix4x4* m, float r)
{
return m.mul(Matrix4x4 {
math::cosf(r), 0, -math::sinf(r), 0,
math::cos(r), 0, -math::sin(r), 0,
0, 1, 0, 0,
math::sinf(r), 0, math::cosf(r), 0,
math::sin(r), 0, math::cos(r), 0,
0, 0, 0, 1,
});
}
@@ -374,8 +374,8 @@ fn Matrix4x4 Matrix4x4.rotate_x(Matrix4x4* m, float r)
{
return m.mul(Matrix4x4 {
1, 0, 0, 0,
0, math::cosf(r), -math::sinf(r), 0,
0, math::sinf(r), math::cosf(r), 0,
0, math::cos(r), -math::sin(r), 0,
0, math::sin(r), math::cos(r), 0,
0, 0, 0, 1,
});
}

View File

@@ -532,6 +532,8 @@ typedef struct
};
struct
{
bool attr_intvec : 1;
bool attr_floatvec : 1;
DeclId body_param;
CompilationUnit *unit;
};
@@ -1438,6 +1440,8 @@ typedef struct Module_
Ast **files; // Asts
Decl** method_extensions;
Decl** intvec_extensions;
Decl** floatvec_extensions;
Decl** generic_cache;
HTable symbols;
struct CompilationUnit_ **units;
@@ -1804,6 +1808,8 @@ extern const char *kw_out;
extern const char *kw_inout;
extern const char *kw_deprecated;
extern const char *kw_distinct;
extern const char *kw_intvec;
extern const char *kw_floatvec;
extern const char *kw_inline;
extern const char *kw_inf;
extern const char *kw_kind;

View File

@@ -720,7 +720,7 @@ typedef enum
OVERLOAD_ELEMENT_AT = 1,
OVERLOAD_ELEMENT_REF,
OVERLOAD_ELEMENT_SET,
OVERLOAD_LEN
OVERLOAD_LEN,
} OperatorOverload;
typedef enum

View File

@@ -185,7 +185,7 @@ static bool sema_analyse_union_members(SemaContext *context, Decl *decl, Decl **
if (decl->is_packed && !decl->alignment) decl->alignment = 1;
// 2. Otherwise pick the highest of the natural alignment and the given alignment.
if (!decl->is_packed) decl->alignment = MAX(decl->alignment, max_alignment);
if (!decl->is_packed && decl->alignment < max_alignment) decl->alignment = max_alignment;
// We're only packed if the max alignment is > 1
decl->is_packed = decl->is_packed && max_alignment > 1;
@@ -333,7 +333,7 @@ static bool sema_analyse_struct_members(SemaContext *context, Decl *decl, Decl *
if (decl->is_packed && !decl->alignment) decl->alignment = 1;
// 2. Otherwise pick the highest of the natural alignment and the given alignment.
if (!decl->is_packed) decl->alignment = MAX(decl->alignment, natural_alignment);
if (!decl->is_packed && decl->alignment < natural_alignment) decl->alignment = natural_alignment;
// We must now possibly add the end padding.
// First we calculate the actual size
@@ -1172,6 +1172,68 @@ Decl *sema_find_operator(SemaContext *context, Expr *expr, OperatorOverload oper
return NULL;
}
INLINE Decl *sema_find_vec_operator_in_module(Module *module, const char *kw, bool is_int, bool allow_private, Decl *prev, Decl **private, SourceSpan span)
{
Decl **funcs = is_int ? module->intvec_extensions : module->floatvec_extensions;
Decl *found = NULL;
FOREACH_BEGIN(Decl *func, funcs)
if (func->name == kw)
{
if (func->visibility != VISIBLE_PUBLIC && !allow_private)
{
if (!prev) *private = func;
continue;
}
found = func;
// Assume only one per module.
break;
}
FOREACH_END();
if (!found) return prev;
*private = NULL;
if (prev)
{
sema_error_at(span, "Ambiguous name '%s', try to import fewer modules.", kw);
return poisoned_decl;
}
return found;
}
INLINE Decl *sema_find_vec_operator_in_module_recursively(Module *module, const char *kw, bool is_int, bool allow_private, Decl *prev, Decl **private_ref, SourceSpan span)
{
Decl *decl = sema_find_vec_operator_in_module(module, kw, is_int, allow_private, prev, private_ref, span);
if (decl) return decl;
FOREACH_BEGIN(Module *sub_module, module->sub_modules)
decl = sema_find_vec_operator_in_module(sub_module, kw, is_int, false, decl, private_ref, span);
if (!decl) continue;
if (!decl_ok(decl)) return decl;
FOREACH_END();
return decl;
}
Decl *sema_find_vec_operator(SemaContext *context, const char *kw, Type *base_type, SourceSpan span)
{
bool is_int = type_is_integer(base_type);
Decl *private = NULL;
Decl *decl = sema_find_vec_operator_in_module(context->compilation_unit->module, kw, is_int, true, NULL, &private, span);
if (decl) return decl;
Decl **imports = context->unit->imports;
FOREACH_BEGIN(Decl *import, context->unit->imports)
Module *imported_module = import->import.module;
bool is_private = import->import.private;
decl = sema_find_vec_operator_in_module_recursively(imported_module, kw, is_int, is_private, decl, &private, span);
if (!decl) continue;
if (!decl_ok(decl)) return decl;
FOREACH_END();
if (!decl && private)
{
sema_error_at(span, "The vector operator '%s' could not be found except the private implementation in '%s'.", private->unit->module->name->module);
return poisoned_decl;
}
return decl;
}
static inline bool sema_analyse_operator_element_at(Decl *method)
{
@@ -1223,9 +1285,8 @@ static bool sema_check_operator_method_validity(Decl *method)
return sema_analyse_operator_element_at(method);
case OVERLOAD_LEN:
return sema_analyse_operator_len(method);
default:
UNREACHABLE
}
UNREACHABLE
}
static inline bool unit_add_method_like(CompilationUnit *unit, Type *parent_type, Decl *method_like)
@@ -1443,20 +1504,68 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
const char *kw = expr->identifier_expr.ident;
if (kw == kw_elementat)
{
if (!decl->func_decl.type_parent)
{
SEMA_ERROR(expr, "@operator(elementat) can only be used with methods.");
return false;
}
decl->operator = OVERLOAD_ELEMENT_AT;
}
else if (kw == kw_elementref)
{
if (!decl->func_decl.type_parent)
{
SEMA_ERROR(expr, "@operator(elementref) can only be used with methods.");
return false;
}
decl->operator = OVERLOAD_ELEMENT_REF;
}
else if (kw == kw_elementset)
{
if (!decl->func_decl.type_parent)
{
SEMA_ERROR(expr, "@operator(elementset) can only be used with methods.");
return false;
}
decl->operator = OVERLOAD_ELEMENT_SET;
}
else if (kw == kw_len)
{
if (!decl->func_decl.type_parent)
{
SEMA_ERROR(expr, "@operator(len) can only be used with methods.");
return false;
}
decl->operator = OVERLOAD_LEN;
}
else if (kw == kw_floatvec)
{
if (decl->decl_kind != DECL_MACRO)
{
SEMA_ERROR(expr, "@operator(floatvec) can only be used with macros.");
return false;
}
if (decl->func_decl.type_parent)
{
SEMA_ERROR(expr, "@operator(floatvec) cannot be used with methods.");
return false;
}
decl->func_decl.attr_floatvec = true;
}
else if (kw == kw_intvec)
{
if (decl->decl_kind != DECL_MACRO)
{
SEMA_ERROR(expr, "@operator(intvec) can only be used with macros.");
return false;
}
if (decl->func_decl.type_parent)
{
SEMA_ERROR(expr, "@operator(intvec) cannot be used with methods.");
return false;
}
decl->func_decl.attr_intvec = true;
}
else
{
goto FAILED_OP_TYPE;
@@ -2037,7 +2146,6 @@ static inline bool sema_analyse_macro(SemaContext *context, Decl *decl)
}
Decl **parameters = decl->func_decl.signature.params;
unsigned param_count = vec_size(parameters);
DeclId body_param = decl->func_decl.body_param;
Decl **body_parameters = body_param ? declptr(body_param)->body_params : NULL;
@@ -2080,6 +2188,17 @@ static inline bool sema_analyse_macro(SemaContext *context, Decl *decl)
{
if (!sema_analyse_macro_method(context, decl)) return decl_poison(decl);
}
else
{
if (decl->func_decl.attr_floatvec)
{
vec_add(context->unit->module->floatvec_extensions, decl);
}
if (decl->func_decl.attr_intvec)
{
vec_add(context->unit->module->intvec_extensions, decl);
}
}
decl->type = type_void;
return true;
}

View File

@@ -4,6 +4,7 @@
#include "sema_internal.h"
#include <math.h>
/*
* TODOs
* - Disallow jumping in and out of an expression block.
@@ -2846,12 +2847,18 @@ static inline bool sema_expr_analyse_call(SemaContext *context, Expr *expr)
switch (decl->decl_kind)
{
case DECL_MACRO:
if (decl->func_decl.attr_intvec || decl->func_decl.attr_floatvec)
{
struct_var = func_expr->access_expr.parent;
break;
}
FALLTHROUGH;
case DECL_FUNC:
struct_var = func_expr->access_expr.parent;
if (decl->func_decl.signature.params[0]->type->type_kind == TYPE_POINTER)
{
expr_insert_addr(func_expr->access_expr.parent);
expr_insert_addr(struct_var);
}
struct_var = func_expr->access_expr.parent;
break;
default:
break;
@@ -4096,6 +4103,19 @@ CHECK_DEEPER:
}
}
if (type_flat_is_vector(type))
{
Type *vec = type_flatten(type);
assert(vec->type_kind == TYPE_VECTOR);
Type *base = vec->array.base;
Decl *func = sema_find_vec_operator(context, kw, base, expr->span);
if (!decl_ok(func)) return false;
if (func)
{
expr->access_expr.ref = func;
return true;
}
}
// 9. At this point we may only have distinct, struct, union, error, enum
if (!type_may_have_sub_elements(type))
{

View File

@@ -73,6 +73,7 @@ void sema_analysis_pass_ct_assert(Module *module);
void sema_analysis_pass_functions(Module *module);
void sema_analyze_stage(Module *module, AnalysisStage stage);
Decl *sema_find_operator(SemaContext *context, Expr *expr, OperatorOverload operator_overload);
Decl *sema_find_vec_operator(SemaContext *context, const char *kw, Type *base_type, SourceSpan span);
bool sema_insert_method_call(SemaContext *context, Expr *method_call, Decl *method_decl, Expr *parent, Expr **arguments);
bool sema_analyse_expr_lvalue(SemaContext *context, Expr *expr);
bool sema_analyse_expr_lvalue_fold_const(SemaContext *context, Expr *expr);

View File

@@ -60,12 +60,14 @@ const char *kw_elementat;
const char *kw_elementref;
const char *kw_elementset;
const char *kw_elements;
const char *kw_floatvec;
const char *kw_in;
const char *kw_incr;
const char *kw_inf;
const char *kw_inline;
const char *kw_inner;
const char *kw_inout;
const char *kw_in;
const char *kw_intvec;
const char *kw_kind;
const char *kw_len;
const char *kw_mainstub;
@@ -148,12 +150,14 @@ void symtab_init(uint32_t capacity)
kw_elementref = KW_DEF("elementref");
kw_elementset = KW_DEF("elementset");
kw_elements = KW_DEF("elements");
kw_floatvec = KW_DEF("floatvec");
kw_in = KW_DEF("in");
kw_incr = KW_DEF("incr");
kw_inf = KW_DEF("inf");
kw_inline = KW_DEF("inline");
kw_inner = KW_DEF("inner");
kw_inout = KW_DEF("inout");
kw_in = KW_DEF("in");
kw_intvec = KW_DEF("intvec");
kw_kind = KW_DEF("kind");
kw_len = KW_DEF("len");
kw_mainstub = KW_DEF("_$mainstub");

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.3.38"
#define COMPILER_VERSION "0.3.39"

View File

@@ -1,24 +1,23 @@
// #target: macos-x64
module foo;
import std::math;
import libc;
fn void main()
{
void* foekf = &math::log;
double* xok = &math::DIV_1_SQRT2;
void* foekf = &libc::printf;
int* xok = &libc::EXIT_SUCCESS;
}
/* #expect: foo.ll
@std_math_DIV_1_SQRT2 = external global double
@libc_EXIT_SUCCESS = external global i32, align 4
define void @foo_main() #0 {
entry:
%foekf = alloca i8*, align 8
%xok = alloca double*, align 8
store i8* bitcast (double (double)* @std_math_log to i8*), i8** %foekf, align 8
store double* @std_math_DIV_1_SQRT2, double** %xok, align 8
%xok = alloca i32*, align 8
store i8* bitcast (i32 (i8*, ...)* @printf to i8*), i8** %foekf, align 8
store i32* @libc_EXIT_SUCCESS, i32** %xok, align 8
ret void
}
declare double @std_math_log(double)
declare i32 @printf(i8*, ...)

View File

@@ -0,0 +1,7 @@
struct Foo { int x; }
fn void Foo.test(Foo f) @operator(intvec) {} // #error: @operator(intvec) can only be used with macros.
fn void Foo.test(Foo f) @operator(floatvec) {} // #error: @operator(floatvec) can only be used with macros.
macro void Foo.test(Foo f) @operator(intvec) {} // #error: @operator(intvec) cannot be used with methods
macro void Foo.test(Foo f) @operator(floatvec) {} // #error: @operator(floatvec) cannot be used with methods

View File

@@ -1,24 +1,23 @@
// #target: macos-x64
module foo;
import std::math;
import libc;
fn void main()
{
void* foekf = &math::log;
double* xok = &math::DIV_1_SQRT2;
void* foekf = &libc::printf;
int* xok = &libc::EXIT_SUCCESS;
}
/* #expect: foo.ll
@std_math_DIV_1_SQRT2 = external global double, align 8
@libc_EXIT_SUCCESS = external global i32, align 4
define void @foo_main() #0 {
entry:
%foekf = alloca ptr, align 8
%xok = alloca ptr, align 8
store ptr @std_math_log, ptr %foekf, align 8
store ptr @std_math_DIV_1_SQRT2, ptr %xok, align 8
store ptr @printf, ptr %foekf, align 8
store ptr @libc_EXIT_SUCCESS, ptr %xok, align 8
ret void
}
declare double @std_math_log(double)
declare i32 @printf(ptr, ...)

View File

@@ -0,0 +1,7 @@
struct Foo { int x; }
fn void Foo.test(Foo f) @operator(intvec) {} // #error: @operator(intvec) can only be used with macros.
fn void Foo.test(Foo f) @operator(floatvec) {} // #error: @operator(floatvec) can only be used with macros.
macro void Foo.test(Foo f) @operator(intvec) {} // #error: @operator(intvec) cannot be used with methods
macro void Foo.test(Foo f) @operator(floatvec) {} // #error: @operator(floatvec) cannot be used with methods