Built-in Quaternions (Not just an April Fool's Joke any more)

This commit is contained in:
gingerBill
2019-08-26 11:33:05 +01:00
parent 59ab51acec
commit 7bc146e6fd
13 changed files with 909 additions and 66 deletions

View File

@@ -1129,6 +1129,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
case runtime.Type_Info_Rune: fmt_arg(fi, v, verb);
case runtime.Type_Info_Float: fmt_arg(fi, v, verb);
case runtime.Type_Info_Complex: fmt_arg(fi, v, verb);
case runtime.Type_Info_Quaternion: fmt_arg(fi, v, verb);
case runtime.Type_Info_String: fmt_arg(fi, v, verb);
case runtime.Type_Info_Pointer:
@@ -1386,6 +1387,31 @@ fmt_complex :: proc(fi: ^Info, c: complex128, bits: int, verb: rune) {
}
}
fmt_quaternion :: proc(fi: ^Info, q: quaternion256, bits: int, verb: rune) {
switch verb {
case 'f', 'F', 'v', 'h', 'H':
r, i, j, k := real(q), imag(q), jmag(q), kmag(q);
fmt_float(fi, r, bits/4, verb);
if !fi.plus && i >= 0 do strings.write_rune(fi.buf, '+');
fmt_float(fi, i, bits/4, verb);
strings.write_rune(fi.buf, 'i');
if !fi.plus && j >= 0 do strings.write_rune(fi.buf, '+');
fmt_float(fi, j, bits/4, verb);
strings.write_rune(fi.buf, 'j');
if !fi.plus && k >= 0 do strings.write_rune(fi.buf, '+');
fmt_float(fi, k, bits/4, verb);
strings.write_rune(fi.buf, 'k');
case:
fmt_bad_verb(fi, verb);
return;
}
}
fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
if arg == nil {
strings.write_string(fi.buf, "<nil>");
@@ -1434,6 +1460,9 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
case complex64: fmt_complex(fi, complex128(a), 64, verb);
case complex128: fmt_complex(fi, a, 128, verb);
case quaternion128: fmt_quaternion(fi, quaternion256(a), 128, verb);
case quaternion256: fmt_quaternion(fi, a, 256, verb);
case i8: fmt_int(fi, u64(a), true, 8, verb);
case u8: fmt_int(fi, u64(a), false, 8, verb);
case i16: fmt_int(fi, u64(a), true, 16, verb);

View File

@@ -12,6 +12,7 @@ Type_Kind :: enum {
Rune,
Float,
Complex,
Quaternion,
String,
Boolean,
Any,
@@ -42,6 +43,7 @@ type_kind :: proc(T: typeid) -> Type_Kind {
case runtime.Type_Info_Rune: return .Rune;
case runtime.Type_Info_Float: return .Float;
case runtime.Type_Info_Complex: return .Complex;
case runtime.Type_Info_Quaternion: return .Quaternion;
case runtime.Type_Info_String: return .String;
case runtime.Type_Info_Boolean: return .Boolean;
case runtime.Type_Info_Any: return .Any;

View File

@@ -47,16 +47,17 @@ Type_Info_Endianness :: enum u8 {
}
// Variant Types
Type_Info_Named :: struct {name: string, base: ^Type_Info};
Type_Info_Integer :: struct {signed: bool, endianness: Type_Info_Endianness};
Type_Info_Rune :: struct {};
Type_Info_Float :: struct {};
Type_Info_Complex :: struct {};
Type_Info_String :: struct {is_cstring: bool};
Type_Info_Boolean :: struct {};
Type_Info_Any :: struct {};
Type_Info_Type_Id :: struct {};
Type_Info_Pointer :: struct {
Type_Info_Named :: struct {name: string, base: ^Type_Info};
Type_Info_Integer :: struct {signed: bool, endianness: Type_Info_Endianness};
Type_Info_Rune :: struct {};
Type_Info_Float :: struct {};
Type_Info_Complex :: struct {};
Type_Info_Quaternion :: struct {};
Type_Info_String :: struct {is_cstring: bool};
Type_Info_Boolean :: struct {};
Type_Info_Any :: struct {};
Type_Info_Type_Id :: struct {};
Type_Info_Pointer :: struct {
elem: ^Type_Info // nil -> rawptr
};
Type_Info_Procedure :: struct {
@@ -135,6 +136,7 @@ Type_Info :: struct {
Type_Info_Rune,
Type_Info_Float,
Type_Info_Complex,
Type_Info_Quaternion,
Type_Info_String,
Type_Info_Boolean,
Type_Info_Any,
@@ -163,6 +165,7 @@ Typeid_Kind :: enum u8 {
Rune,
Float,
Complex,
Quaternion,
String,
Boolean,
Any,

View File

@@ -357,6 +357,11 @@ complex128_eq :: inline proc "contextless" (a, b: complex128) -> bool { return r
complex128_ne :: inline proc "contextless" (a, b: complex128) -> bool { return real(a) != real(b) || imag(a) != imag(b); }
quaternion128_eq :: inline proc "contextless" (a, b: quaternion128) -> bool { return real(a) == real(b) && imag(a) == imag(b) && jmag(a) == jmag(b) && kmag(a) == kmag(b); }
quaternion128_ne :: inline proc "contextless" (a, b: quaternion128) -> bool { return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b); }
quaternion256_eq :: inline proc "contextless" (a, b: quaternion256) -> bool { return real(a) == real(b) && imag(a) == imag(b) && jmag(a) == jmag(b) && kmag(a) == kmag(b); }
quaternion256_ne :: inline proc "contextless" (a, b: quaternion256) -> bool { return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b); }
bounds_check_error :: proc "contextless" (file: string, line, column: int, index, count: int) {
@@ -546,9 +551,16 @@ abs_complex128 :: inline proc "contextless" (x: complex128) -> f64 {
r, i := real(x), imag(x);
return _sqrt_f64(r*r + i*i);
}
abs_quaternion128 :: inline proc "contextless" (x: quaternion128) -> f32 {
r, i, j, k := real(x), imag(x), jmag(x), kmag(x);
return _sqrt_f32(r*r + i*i + j*j + k*k);
}
abs_quaternion256 :: inline proc "contextless" (x: quaternion256) -> f64 {
r, i, j, k := real(x), imag(x), jmag(x), kmag(x);
return _sqrt_f64(r*r + i*i + j*j + k*k);
}
quo_complex64 :: proc(n, m: complex64) -> complex64 {
quo_complex64 :: proc "contextless" (n, m: complex64) -> complex64 {
e, f: f32;
if abs(real(m)) >= abs(imag(m)) {
@@ -566,7 +578,7 @@ quo_complex64 :: proc(n, m: complex64) -> complex64 {
return complex(e, f);
}
quo_complex128 :: proc(n, m: complex128) -> complex128 {
quo_complex128 :: proc "contextless" (n, m: complex128) -> complex128 {
e, f: f64;
if abs(real(m)) >= abs(imag(m)) {
@@ -583,3 +595,55 @@ quo_complex128 :: proc(n, m: complex128) -> complex128 {
return complex(e, f);
}
mul_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
t0 := r0*q0 - r1*q1 - r2*q2 - r3*q3;
t1 := r0*q1 + r1*q0 - r2*q3 + r3*q2;
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1;
t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0;
return quaternion(t0, t1, t2, t3);
}
mul_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
t0 := r0*q0 - r1*q1 - r2*q2 - r3*q3;
t1 := r0*q1 + r1*q0 - r2*q3 + r3*q2;
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1;
t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0;
return quaternion(t0, t1, t2, t3);
}
quo_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
invmag2 := 1.0 / (r0*r0 + r1*r1 + r2*r2 + r3*r3);
t0 := (r0*q0 + r1*q1 + r2*q2 + r3*q3) * invmag2;
t1 := (r0*q1 - r1*q0 - r2*q3 - r3*q2) * invmag2;
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2;
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2;
return quaternion(t0, t1, t2, t3);
}
quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
invmag2 := 1.0 / (r0*r0 + r1*r1 + r2*r2 + r3*r3);
t0 := (r0*q0 + r1*q1 + r2*q2 + r3*q3) * invmag2;
t1 := (r0*q1 - r1*q0 - r2*q3 - r3*q2) * invmag2;
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2;
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2;
return quaternion(t0, t1, t2, t3);
}

View File

@@ -326,7 +326,7 @@ union_type :: proc() {
}
parametric_polymorphism :: proc() {
fmt.println("# parametric_polymorphism");
fmt.println("\n# parametric_polymorphism");
print_value :: proc(value: $T) {
fmt.printf("print_value: %T %v\n", value, value);
@@ -561,7 +561,7 @@ prefix_table := [?]string{
threading_example :: proc() {
when os.OS == "windows" {
fmt.println("# threading_example");
fmt.println("\n# threading_example");
worker_proc :: proc(t: ^thread.Thread) -> int {
for iteration in 1..5 {
@@ -601,7 +601,7 @@ threading_example :: proc() {
}
array_programming :: proc() {
fmt.println("# array_programming");
fmt.println("\n# array_programming");
{
a := [3]f32{1, 2, 3};
b := [3]f32{5, 6, 7};
@@ -646,7 +646,7 @@ array_programming :: proc() {
}
named_proc_return_parameters :: proc() {
fmt.println("# named proc return parameters");
fmt.println("\n# named proc return parameters");
foo0 :: proc() -> int {
return 123;
@@ -668,7 +668,7 @@ named_proc_return_parameters :: proc() {
using_enum :: proc() {
fmt.println("# using enum");
fmt.println("\n# using enum");
using Foo :: enum {A, B, C};
@@ -680,7 +680,7 @@ using_enum :: proc() {
}
map_type :: proc() {
fmt.println("# map type");
fmt.println("\n# map type");
// enums of type u16, u32, i16 & i32 also work
Enum_u8 :: enum u8 {
@@ -735,7 +735,7 @@ map_type :: proc() {
}
implicit_selector_expression :: proc() {
fmt.println("# implicit selector expression");
fmt.println("\n# implicit selector expression");
Foo :: enum {A, B, C};
@@ -763,7 +763,7 @@ implicit_selector_expression :: proc() {
}
explicit_procedure_overloading :: proc() {
fmt.println("# explicit procedure overloading");
fmt.println("\n# explicit procedure overloading");
add_ints :: proc(a, b: int) -> int {
x := a + b;
@@ -797,7 +797,7 @@ explicit_procedure_overloading :: proc() {
}
complete_switch :: proc() {
fmt.println("# complete_switch");
fmt.println("\n# complete_switch");
{ // enum
using Foo :: enum {
A,
@@ -947,7 +947,7 @@ deferred_procedure_associations :: proc() {
}
reflection :: proc() {
fmt.println("# reflection");
fmt.println("\n# reflection");
Foo :: struct {
x: int `tag1`,
@@ -981,6 +981,45 @@ reflection :: proc() {
}
}
quaternions :: proc() {
fmt.println("\n# quaternions");
{ // Quaternion operations
q := 1 + 2i + 3j + 4k;
r := quaternion(5, 6, 7, 8);
t := q * r;
fmt.printf("(%v) * (%v) = %v\n", q, r, t);
v := q / r;
fmt.printf("(%v) / (%v) = %v\n", q, r, v);
u := q + r;
fmt.printf("(%v) + (%v) = %v\n", q, r, u);
s := q - r;
fmt.printf("(%v) - (%v) = %v\n", q, r, s);
}
{ // The quaternion types
q128: quaternion128; // 4xf32
q256: quaternion256; // 4xf64
q128 = quaternion(1, 0, 0, 0);
q256 = 1; // quaternion(1, 0, 0, 0);
}
{ // Built-in procedures
q := 1 + 2i + 3j + 4k;
fmt.println("q =", q);
fmt.println("real(q) =", real(q));
fmt.println("imag(q) =", imag(q));
fmt.println("jmag(q) =", jmag(q));
fmt.println("kmag(q) =", kmag(q));
fmt.println("conj(q) =", conj(q));
fmt.println("abs(q) =", abs(q));
}
{ // Conversion of a complex type to a quaternion type
c := 1 + 2i;
q := quaternion256(c);
fmt.println(c);
fmt.println(q);
}
}
main :: proc() {
when true {
general_stuff();
@@ -1000,5 +1039,6 @@ main :: proc() {
diverging_procedures();
deferred_procedure_associations();
reflection();
quaternions();
}
}

View File

@@ -497,6 +497,14 @@ i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type
if (is_type_complex(dst)) {
return 1;
}
if (is_type_quaternion(dst)) {
return 2;
}
break;
case Basic_UntypedQuaternion:
if (is_type_quaternion(dst)) {
return 1;
}
break;
}
}
@@ -1438,7 +1446,7 @@ bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Typ
ExactValue imag = exact_value_imag(v);
if (real.kind != ExactValue_Invalid &&
imag.kind != ExactValue_Invalid) {
if (out_value) *out_value = exact_binary_operator_value(Token_Add, real, exact_value_make_imag(imag));
if (out_value) *out_value = exact_value_complex(exact_value_to_f64(real), exact_value_to_f64(imag));
return true;
}
break;
@@ -1449,6 +1457,36 @@ bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Typ
default: GB_PANIC("Compiler error: Unknown complex type!"); break;
}
return false;
} else if (is_type_quaternion(type)) {
ExactValue v = exact_value_to_quaternion(in_value);
if (v.kind != ExactValue_Quaternion) {
return false;
}
switch (type->Basic.kind) {
case Basic_quaternion128:
case Basic_quaternion256: {
ExactValue real = exact_value_real(v);
ExactValue imag = exact_value_imag(v);
ExactValue jmag = exact_value_jmag(v);
ExactValue kmag = exact_value_kmag(v);
if (real.kind != ExactValue_Invalid &&
imag.kind != ExactValue_Invalid) {
if (out_value) *out_value = exact_value_quaternion(exact_value_to_f64(real), exact_value_to_f64(imag), exact_value_to_f64(jmag), exact_value_to_f64(kmag));
return true;
}
break;
}
case Basic_UntypedComplex:
if (out_value) *out_value = exact_value_to_quaternion(*out_value);
return true;
case Basic_UntypedQuaternion:
return true;
default: GB_PANIC("Compiler error: Unknown complex type!"); break;
}
return false;
} else if (is_type_pointer(type)) {
if (in_value.kind == ExactValue_Pointer) {
@@ -1481,10 +1519,14 @@ void check_is_expressible(CheckerContext *c, Operand *o, Type *type) {
if (!is_type_integer(o->type) && is_type_integer(type)) {
error(o->expr, "'%s' truncated to '%s'", a, b);
} else {
#if 0
gbAllocator ha = heap_allocator();
String str = big_int_to_string(ha, &o->value.value_integer);
defer (gb_free(ha, str.text));
error(o->expr, "'%s = %.*s' overflows '%s'", a, LIT(str), b);
#else
error(o->expr, "Cannot convert '%s' to '%s'", a, b);
#endif
}
} else {
error(o->expr, "Cannot convert '%s' to '%s'", a, b);
@@ -1759,6 +1801,21 @@ void check_comparison(CheckerContext *c, Operand *x, Operand *y, TokenKind op) {
}
break;
}
} else if (is_type_quaternion(x->type) || is_type_quaternion(y->type)) {
switch (op) {
case Token_CmpEq:
switch (8*size) {
case 128: add_package_dependency(c, "runtime", "quaternion128_eq"); break;
case 256: add_package_dependency(c, "runtime", "quaternion256_eq"); break;
}
break;
case Token_NotEq:
switch (8*size) {
case 128: add_package_dependency(c, "runtime", "quaternion128_ne"); break;
case 256: add_package_dependency(c, "runtime", "quaternion256_ne"); break;
}
break;
}
}
}
@@ -1978,6 +2035,14 @@ bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y) {
return true;
}
if (is_type_complex(src) && is_type_quaternion(dst)) {
return true;
}
if (is_type_quaternion(src) && is_type_quaternion(dst)) {
return true;
}
if (is_type_bit_field_value(src) && is_type_integer(dst)) {
return true;
}
@@ -2557,6 +2622,8 @@ ExactValue convert_exact_value_for_type(ExactValue v, Type *type) {
v = exact_value_to_integer(v);
} else if (is_type_complex(t)) {
v = exact_value_to_complex(v);
} else if (is_type_quaternion(t)) {
v = exact_value_to_quaternion(v);
}
return v;
}
@@ -2652,6 +2719,7 @@ void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) {
case Basic_UntypedInteger:
case Basic_UntypedFloat:
case Basic_UntypedComplex:
case Basic_UntypedQuaternion:
case Basic_UntypedRune:
if (!is_type_numeric(target_type)) {
operand->mode = Addressing_Invalid;
@@ -3769,10 +3837,98 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
break;
}
case BuiltinProc_quaternion: {
// quaternion :: proc(real, imag, jmag, kmag: float_type) -> complex_type
Operand x = *operand;
Operand y = {};
Operand z = {};
Operand w = {};
// NOTE(bill): Invalid will be the default till fixed
operand->type = t_invalid;
operand->mode = Addressing_Invalid;
check_expr(c, &y, ce->args[1]);
if (y.mode == Addressing_Invalid) {
return false;
}
check_expr(c, &z, ce->args[2]);
if (y.mode == Addressing_Invalid) {
return false;
}
check_expr(c, &w, ce->args[3]);
if (y.mode == Addressing_Invalid) {
return false;
}
convert_to_typed(c, &x, y.type); if (x.mode == Addressing_Invalid) return false;
convert_to_typed(c, &y, x.type); if (y.mode == Addressing_Invalid) return false;
convert_to_typed(c, &z, x.type); if (z.mode == Addressing_Invalid) return false;
convert_to_typed(c, &w, x.type); if (w.mode == Addressing_Invalid) return false;
if (x.mode == Addressing_Constant &&
y.mode == Addressing_Constant &&
z.mode == Addressing_Constant &&
w.mode == Addressing_Constant) {
if (is_type_numeric(x.type) && exact_value_imag(x.value).value_float == 0) {
x.type = t_untyped_float;
}
if (is_type_numeric(y.type) && exact_value_imag(y.value).value_float == 0) {
y.type = t_untyped_float;
}
if (is_type_numeric(z.type) && exact_value_imag(z.value).value_float == 0) {
z.type = t_untyped_float;
}
if (is_type_numeric(w.type) && exact_value_imag(w.value).value_float == 0) {
w.type = t_untyped_float;
}
}
if (!(are_types_identical(x.type, y.type) && are_types_identical(x.type, z.type) && are_types_identical(x.type, w.type))) {
gbString tx = type_to_string(x.type);
gbString ty = type_to_string(y.type);
gbString tz = type_to_string(z.type);
gbString tw = type_to_string(w.type);
error(call, "Mismatched types to 'quaternion', '%s' vs '%s' vs '%s' vs '%s'", tx, ty, tz, tw);
gb_string_free(tw);
gb_string_free(tz);
gb_string_free(ty);
gb_string_free(tx);
return false;
}
if (!is_type_float(x.type)) {
gbString s = type_to_string(x.type);
error(call, "Arguments have type '%s', expected a floating point", s);
gb_string_free(s);
return false;
}
if (x.mode == Addressing_Constant && y.mode == Addressing_Constant && z.mode == Addressing_Constant && w.mode == Addressing_Constant) {
f64 r = exact_value_to_float(x.value).value_float;
f64 i = exact_value_to_float(y.value).value_float;
f64 j = exact_value_to_float(z.value).value_float;
f64 k = exact_value_to_float(w.value).value_float;
operand->value = exact_value_quaternion(r, i, j, k);
operand->mode = Addressing_Constant;
} else {
operand->mode = Addressing_Value;
}
BasicKind kind = core_type(x.type)->Basic.kind;
switch (kind) {
case Basic_f32: operand->type = t_quaternion128; break;
case Basic_f64: operand->type = t_quaternion256; break;
case Basic_UntypedFloat: operand->type = t_untyped_quaternion; break;
default: GB_PANIC("Invalid type"); break;
}
break;
}
case BuiltinProc_real:
case BuiltinProc_imag: {
// real :: proc(x: type) -> float_type
// proc imag(x: type) -> float_type
// imag :: proc(x: type) -> float_type
Operand *x = operand;
if (is_type_untyped(x->type)) {
@@ -3780,7 +3936,12 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
if (is_type_numeric(x->type)) {
x->type = t_untyped_complex;
}
} else {
} else if (is_type_quaternion(x->type)) {
convert_to_typed(c, x, t_quaternion256);
if (x->mode == Addressing_Invalid) {
return false;
}
} else{
convert_to_typed(c, x, t_complex128);
if (x->mode == Addressing_Invalid) {
return false;
@@ -3788,9 +3949,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
}
}
if (!is_type_complex(x->type)) {
if (!is_type_complex(x->type) && !is_type_quaternion(x->type)) {
gbString s = type_to_string(x->type);
error(call, "Argument has type '%s', expected a complex type", s);
error(call, "Argument has type '%s', expected a complex or quaternion type", s);
gb_string_free(s);
return false;
}
@@ -3808,7 +3969,57 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
switch (kind) {
case Basic_complex64: x->type = t_f32; break;
case Basic_complex128: x->type = t_f64; break;
case Basic_quaternion128: x->type = t_f32; break;
case Basic_quaternion256: x->type = t_f64; break;
case Basic_UntypedComplex: x->type = t_untyped_float; break;
case Basic_UntypedQuaternion: x->type = t_untyped_float; break;
default: GB_PANIC("Invalid type"); break;
}
break;
}
case BuiltinProc_jmag:
case BuiltinProc_kmag: {
// jmag :: proc(x: type) -> float_type
// kmag :: proc(x: type) -> float_type
Operand *x = operand;
if (is_type_untyped(x->type)) {
if (x->mode == Addressing_Constant) {
if (is_type_numeric(x->type)) {
x->type = t_untyped_complex;
}
} else{
convert_to_typed(c, x, t_quaternion256);
if (x->mode == Addressing_Invalid) {
return false;
}
}
}
if (!is_type_quaternion(x->type)) {
gbString s = type_to_string(x->type);
error(call, "Argument has type '%s', expected a quaternion type", s);
gb_string_free(s);
return false;
}
if (x->mode == Addressing_Constant) {
switch (id) {
case BuiltinProc_jmag: x->value = exact_value_jmag(x->value); break;
case BuiltinProc_kmag: x->value = exact_value_kmag(x->value); break;
}
} else {
x->mode = Addressing_Value;
}
BasicKind kind = core_type(x->type)->Basic.kind;
switch (kind) {
case Basic_quaternion128: x->type = t_f32; break;
case Basic_quaternion256: x->type = t_f64; break;
case Basic_UntypedComplex: x->type = t_untyped_float; break;
case Basic_UntypedQuaternion: x->type = t_untyped_float; break;
default: GB_PANIC("Invalid type"); break;
}
@@ -3822,12 +4033,24 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
if (x->mode == Addressing_Constant) {
ExactValue v = exact_value_to_complex(x->value);
f64 r = v.value_complex.real;
f64 i = v.value_complex.imag;
f64 i = -v.value_complex.imag;
x->value = exact_value_complex(r, i);
x->mode = Addressing_Constant;
} else {
x->mode = Addressing_Value;
}
} else if (is_type_quaternion(x->type)) {
if (x->mode == Addressing_Constant) {
ExactValue v = exact_value_to_quaternion(x->value);
f64 r = v.value_quaternion.real;
f64 i = -v.value_quaternion.imag;
f64 j = -v.value_quaternion.jmag;
f64 k = -v.value_quaternion.kmag;
x->value = exact_value_quaternion(r, i, j, k);
x->mode = Addressing_Constant;
} else {
x->mode = Addressing_Value;
}
} else {
gbString s = type_to_string(x->type);
error(call, "Expected a complex or quaternion, got '%s'", s);
@@ -4226,6 +4449,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
if (are_types_identical(bt, t_f64)) add_package_dependency(c, "runtime", "abs_f64");
if (are_types_identical(bt, t_complex64)) add_package_dependency(c, "runtime", "abs_complex64");
if (are_types_identical(bt, t_complex128)) add_package_dependency(c, "runtime", "abs_complex128");
if (are_types_identical(bt, t_quaternion128)) add_package_dependency(c, "runtime", "abs_quaternion128");
if (are_types_identical(bt, t_quaternion256)) add_package_dependency(c, "runtime", "abs_quaternion256");
}
}
@@ -6232,8 +6457,11 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
case Token_Imag: {
String s = bl->token.string;
Rune r = s[s.len-1];
// NOTE(bill, 2019-08-25): Allow for quaternions by having j and k imaginary numbers
switch (r) {
case 'i': t = t_untyped_complex; break;
case 'i': t = t_untyped_complex; break;
case 'j': t = t_untyped_quaternion; break;
case 'k': t = t_untyped_quaternion; break;
}
break;

View File

@@ -1610,6 +1610,10 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
str_lit("quo_complex64"),
str_lit("quo_complex128"),
str_lit("mul_quaternion128"),
str_lit("mul_quaternion256"),
str_lit("quo_quaternion128"),
str_lit("quo_quaternion256"),
str_lit("umodti3"),
str_lit("udivti3"),
@@ -1891,6 +1895,7 @@ void init_core_type_info(Checker *c) {
t_type_info_integer = find_core_type(c, str_lit("Type_Info_Integer"));
t_type_info_rune = find_core_type(c, str_lit("Type_Info_Rune"));
t_type_info_float = find_core_type(c, str_lit("Type_Info_Float"));
t_type_info_quaternion = find_core_type(c, str_lit("Type_Info_Quaternion"));
t_type_info_complex = find_core_type(c, str_lit("Type_Info_Complex"));
t_type_info_string = find_core_type(c, str_lit("Type_Info_String"));
t_type_info_boolean = find_core_type(c, str_lit("Type_Info_Boolean"));
@@ -1915,6 +1920,7 @@ void init_core_type_info(Checker *c) {
t_type_info_integer_ptr = alloc_type_pointer(t_type_info_integer);
t_type_info_rune_ptr = alloc_type_pointer(t_type_info_rune);
t_type_info_float_ptr = alloc_type_pointer(t_type_info_float);
t_type_info_quaternion_ptr = alloc_type_pointer(t_type_info_quaternion);
t_type_info_complex_ptr = alloc_type_pointer(t_type_info_complex);
t_type_info_string_ptr = alloc_type_pointer(t_type_info_string);
t_type_info_boolean_ptr = alloc_type_pointer(t_type_info_boolean);

View File

@@ -16,8 +16,11 @@ enum BuiltinProcId {
BuiltinProc_swizzle,
BuiltinProc_complex,
BuiltinProc_quaternion,
BuiltinProc_real,
BuiltinProc_imag,
BuiltinProc_jmag,
BuiltinProc_kmag,
BuiltinProc_conj,
BuiltinProc_expand_to_tuple,
@@ -172,8 +175,11 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("swizzle"), 1, true, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("complex"), 2, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("quaternion"), 4, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("real"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("imag"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("jmag"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("kmag"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("conj"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("expand_to_tuple"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},

View File

@@ -12,6 +12,19 @@ bool are_types_identical(Type *x, Type *y);
struct Complex128 {
f64 real, imag;
};
struct Quaternion256 {
f64 imag, jmag, kmag, real;
};
Quaternion256 quaternion256_inverse(Quaternion256 x) {
f64 invmag2 = 1.0 / (x.real*x.real + x.imag*x.imag + x.jmag*x.jmag + x.kmag*x.kmag);
x.real = +x.real * invmag2;
x.imag = -x.imag * invmag2;
x.jmag = -x.jmag * invmag2;
x.kmag = -x.kmag * invmag2;
return x;
}
enum ExactValueKind {
ExactValue_Invalid,
@@ -21,6 +34,7 @@ enum ExactValueKind {
ExactValue_Integer,
ExactValue_Float,
ExactValue_Complex,
ExactValue_Quaternion,
ExactValue_Pointer,
ExactValue_Compound, // TODO(bill): Is this good enough?
ExactValue_Procedure, // TODO(bill): Is this good enough?
@@ -37,6 +51,7 @@ struct ExactValue {
f64 value_float;
i64 value_pointer;
Complex128 value_complex;
Quaternion256 value_quaternion;
Ast * value_compound;
Ast * value_procedure;
};
@@ -61,7 +76,8 @@ HashKey hash_exact_value(ExactValue v) {
return hash_integer(v.value_pointer);
case ExactValue_Complex:
return hashing_proc(&v.value_complex, gb_size_of(Complex128));
case ExactValue_Quaternion:
return hashing_proc(&v.value_quaternion, gb_size_of(Quaternion256));
case ExactValue_Compound:
return hash_pointer(v.value_compound);
case ExactValue_Procedure:
@@ -116,6 +132,15 @@ ExactValue exact_value_complex(f64 real, f64 imag) {
return result;
}
ExactValue exact_value_quaternion(f64 real, f64 imag, f64 jmag, f64 kmag) {
ExactValue result = {ExactValue_Quaternion};
result.value_quaternion.real = real;
result.value_quaternion.imag = imag;
result.value_quaternion.jmag = jmag;
result.value_quaternion.kmag = kmag;
return result;
}
ExactValue exact_value_pointer(i64 ptr) {
ExactValue result = {ExactValue_Pointer};
result.value_pointer = ptr;
@@ -253,8 +278,10 @@ ExactValue exact_value_from_basic_literal(Token token) {
str.len--; // Ignore the 'i|j|k'
f64 imag = float_from_string(str);
if (last_rune == 'i') {
return exact_value_complex(0, imag);
switch (last_rune) {
case 'i': return exact_value_complex(0, imag);
case 'j': return exact_value_quaternion(0, 0, imag, 0);
case 'k': return exact_value_quaternion(0, 0, 0, imag);
}
}
case Token_Rune: {
@@ -318,11 +345,26 @@ ExactValue exact_value_to_complex(ExactValue v) {
return exact_value_complex(v.value_float, 0);
case ExactValue_Complex:
return v;
// case ExactValue_Quaternion:
// return exact_value_complex(v.value_quaternion.real, v.value_quaternion.imag);
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_to_quaternion(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return exact_value_quaternion(big_int_to_f64(&v.value_integer), 0, 0, 0);
case ExactValue_Float:
return exact_value_quaternion(v.value_float, 0, 0, 0);
case ExactValue_Complex:
return exact_value_quaternion(v.value_complex.real, v.value_complex.imag, 0, 0);
case ExactValue_Quaternion:
return v;
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_real(ExactValue v) {
switch (v.kind) {
@@ -331,6 +373,8 @@ ExactValue exact_value_real(ExactValue v) {
return v;
case ExactValue_Complex:
return exact_value_float(v.value_complex.real);
case ExactValue_Quaternion:
return exact_value_float(v.value_quaternion.real);
}
ExactValue r = {ExactValue_Invalid};
return r;
@@ -343,6 +387,34 @@ ExactValue exact_value_imag(ExactValue v) {
return exact_value_i64(0);
case ExactValue_Complex:
return exact_value_float(v.value_complex.imag);
case ExactValue_Quaternion:
return exact_value_float(v.value_quaternion.imag);
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_jmag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
case ExactValue_Float:
case ExactValue_Complex:
return exact_value_i64(0);
case ExactValue_Quaternion:
return exact_value_float(v.value_quaternion.jmag);
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_kmag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
case ExactValue_Float:
case ExactValue_Complex:
return exact_value_i64(0);
case ExactValue_Quaternion:
return exact_value_float(v.value_quaternion.kmag);
}
ExactValue r = {ExactValue_Invalid};
return r;
@@ -361,6 +433,32 @@ ExactValue exact_value_make_imag(ExactValue v) {
return r;
}
ExactValue exact_value_make_jmag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return exact_value_quaternion(0, 0, exact_value_to_float(v).value_float, 0);
case ExactValue_Float:
return exact_value_quaternion(0, 0, v.value_float, 0);
default:
GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'");
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_make_kmag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return exact_value_quaternion(0, 0, 0, exact_value_to_float(v).value_float);
case ExactValue_Float:
return exact_value_quaternion(0, 0, 0, v.value_float);
default:
GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'");
}
ExactValue r = {ExactValue_Invalid};
return r;
}
i64 exact_value_to_i64(ExactValue v) {
v = exact_value_to_integer(v);
if (v.kind == ExactValue_Integer) {
@@ -389,6 +487,7 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision,
case ExactValue_Integer:
case ExactValue_Float:
case ExactValue_Complex:
case ExactValue_Quaternion:
return v;
}
break;
@@ -413,6 +512,13 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision,
f64 imag = v.value_complex.imag;
return exact_value_complex(-real, -imag);
}
case ExactValue_Quaternion: {
f64 real = v.value_quaternion.real;
f64 imag = v.value_quaternion.imag;
f64 jmag = v.value_quaternion.jmag;
f64 kmag = v.value_quaternion.kmag;
return exact_value_quaternion(-real, -imag, -jmag, -kmag);
}
}
break;
}
@@ -463,8 +569,10 @@ i32 exact_value_order(ExactValue const &v) {
return 3;
case ExactValue_Complex:
return 4;
case ExactValue_Pointer:
case ExactValue_Quaternion:
return 5;
case ExactValue_Pointer:
return 6;
default:
GB_PANIC("How'd you get here? Invalid Value.kind");
@@ -485,7 +593,7 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
case ExactValue_Bool:
case ExactValue_String:
case ExactValue_Complex:
case ExactValue_Quaternion:
return;
case ExactValue_Integer:
@@ -499,6 +607,9 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
case ExactValue_Complex:
*x = exact_value_complex(big_int_to_f64(&x->value_integer), 0);
return;
case ExactValue_Quaternion:
*x = exact_value_quaternion(big_int_to_f64(&x->value_integer), 0, 0, 0);
return;
}
break;
@@ -509,6 +620,17 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
case ExactValue_Complex:
*x = exact_value_to_complex(*x);
return;
case ExactValue_Quaternion:
*x = exact_value_to_quaternion(*x);
return;
}
break;
case ExactValue_Complex:
switch (y->kind) {
case ExactValue_Quaternion:
*x = exact_value_to_quaternion(*x);
return;
}
break;
}
@@ -606,6 +728,56 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
break;
}
case ExactValue_Quaternion: {
y = exact_value_to_quaternion(y);
f64 xr = x.value_quaternion.real;
f64 xi = x.value_quaternion.imag;
f64 xj = x.value_quaternion.jmag;
f64 xk = x.value_quaternion.kmag;
f64 yr = y.value_quaternion.real;
f64 yi = y.value_quaternion.imag;
f64 yj = y.value_quaternion.jmag;
f64 yk = y.value_quaternion.kmag;
f64 real = 0;
f64 imag = 0;
f64 jmag = 0;
f64 kmag = 0;
switch (op) {
case Token_Add:
real = xr + yr;
imag = xi + yi;
jmag = xj + yj;
kmag = xk + yk;
break;
case Token_Sub:
real = xr - yr;
imag = xi - yi;
jmag = xj - yj;
kmag = xk - yk;
break;
case Token_Mul:
imag = xr * yi + xi * yr + xj * yk - xk * yj;
jmag = xr * yj - xi * yk + xj * yr + xk * yi;
kmag = xr * yk + xi * yj - xj * yi + xk * yr;
real = xr * yr - xi * yi - xj * yj - xk * yk;
break;
case Token_Quo: {
f64 invmag2 = 1.0 / (yr*yr + yi*yi + yj*yj + yk*yk);
imag = (xr * -yi + xi * +yr + xj * -yk - xk * -yj) * invmag2;
jmag = (xr * -yj - xi * -yk + xj * +yr + xk * -yi) * invmag2;
kmag = (xr * -yk + xi * -yj - xj * -yi + xk * +yr) * invmag2;
real = (xr * +yr - xi * -yi - xj * -yj - xk * -yk) * invmag2;
break;
}
default: goto error;
}
return exact_value_quaternion(real, imag, jmag, kmag);
break;
}
case ExactValue_String: {
if (op != Token_Add) goto error;

View File

@@ -3853,6 +3853,60 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *
return ir_emit_load(proc, res);
}
if (is_type_quaternion(t_left)) {
ir_emit_comment(proc, str_lit("complex.arith.begin"));
defer (ir_emit_comment(proc, str_lit("complex.arith.end")));
right = ir_emit_conv(proc, right, t_left);
Type *ft = base_complex_elem_type(t_left);
if (op == Token_Add || op == Token_Sub) {
irValue *res = ir_add_local_generated(proc, type, false); // NOTE: initialized in full later
irValue *x0 = ir_emit_struct_ev(proc, left, 0);
irValue *x1 = ir_emit_struct_ev(proc, left, 1);
irValue *x2 = ir_emit_struct_ev(proc, left, 2);
irValue *x3 = ir_emit_struct_ev(proc, left, 3);
irValue *y0 = ir_emit_struct_ev(proc, right, 0);
irValue *y1 = ir_emit_struct_ev(proc, right, 1);
irValue *y2 = ir_emit_struct_ev(proc, right, 2);
irValue *y3 = ir_emit_struct_ev(proc, right, 3);
irValue *z0 = ir_emit_arith(proc, op, x0, y0, ft);
irValue *z1 = ir_emit_arith(proc, op, x1, y1, ft);
irValue *z2 = ir_emit_arith(proc, op, x2, y2, ft);
irValue *z3 = ir_emit_arith(proc, op, x3, y3, ft);
ir_emit_store(proc, ir_emit_struct_ep(proc, res, 0), z0);
ir_emit_store(proc, ir_emit_struct_ep(proc, res, 1), z1);
ir_emit_store(proc, ir_emit_struct_ep(proc, res, 2), z2);
ir_emit_store(proc, ir_emit_struct_ep(proc, res, 3), z3);
return ir_emit_load(proc, res);
} else if (op == Token_Mul) {
auto args = array_make<irValue *>(heap_allocator(), 2);
args[0] = left;
args[1] = right;
switch (8*type_size_of(ft)) {
case 32: return ir_emit_runtime_call(proc, "mul_quaternion128", args);
case 64: return ir_emit_runtime_call(proc, "mul_quaternion256", args);
default: GB_PANIC("Unknown float type"); break;
}
} else if (op == Token_Quo) {
auto args = array_make<irValue *>(heap_allocator(), 2);
args[0] = left;
args[1] = right;
switch (8*type_size_of(ft)) {
case 32: return ir_emit_runtime_call(proc, "quo_quaternion128", args);
case 64: return ir_emit_runtime_call(proc, "quo_quaternion256", args);
default: GB_PANIC("Unknown float type"); break;
}
}
}
#if 0
if (op == Token_Add) {
@@ -4188,7 +4242,7 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal
}
if (is_type_complex(a)) {
char *runtime_proc = "";
char const *runtime_proc = "";
i64 sz = 8*type_size_of(a);
switch (sz) {
case 64:
@@ -4212,6 +4266,31 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal
return ir_emit_runtime_call(proc, runtime_proc, args);
}
if (is_type_quaternion(a)) {
char const *runtime_proc = "";
i64 sz = 8*type_size_of(a);
switch (sz) {
case 128:
switch (op_kind) {
case Token_CmpEq: runtime_proc = "quaternion128_eq"; break;
case Token_NotEq: runtime_proc = "quaternion128_ne"; break;
}
break;
case 256:
switch (op_kind) {
case Token_CmpEq: runtime_proc = "quaternion256_eq"; break;
case Token_NotEq: runtime_proc = "quaternion256_ne"; break;
}
break;
}
GB_ASSERT(runtime_proc != nullptr);
auto args = array_make<irValue *>(ir_allocator(), 2);
args[0] = left;
args[1] = right;
return ir_emit_runtime_call(proc, runtime_proc, args);
}
if (is_type_bit_set(a)) {
switch (op_kind) {
case Token_Lt:
@@ -4295,11 +4374,18 @@ irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) {
case 0: result_type = alloc_type_pointer(ft); break;
case 1: result_type = alloc_type_pointer(ft); break;
}
} else if (is_type_quaternion(t)) {
Type *ft = base_complex_elem_type(t);
switch (index) {
case 0: result_type = alloc_type_pointer(ft); break;
case 1: result_type = alloc_type_pointer(ft); break;
case 2: result_type = alloc_type_pointer(ft); break;
case 3: result_type = alloc_type_pointer(ft); break;
}
} else if (is_type_slice(t)) {
switch (index) {
case 0: result_type = alloc_type_pointer(alloc_type_pointer(t->Slice.elem)); break;
case 1: result_type = alloc_type_pointer(t_int); break;
case 2: result_type = alloc_type_pointer(t_int); break;
}
} else if (is_type_string(t)) {
switch (index) {
@@ -4370,6 +4456,17 @@ irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index) {
}
break;
}
case Basic_quaternion128: case Basic_quaternion256:
{
Type *ft = base_complex_elem_type(t);
switch (index) {
case 0: result_type = ft; break;
case 1: result_type = ft; break;
case 2: result_type = ft; break;
case 3: result_type = ft; break;
}
break;
}
}
break;
case Type_Struct:
@@ -4752,6 +4849,8 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
ev = exact_value_to_float(ev);
} else if (is_type_complex(dst)) {
ev = exact_value_to_complex(ev);
} else if (is_type_quaternion(dst)) {
ev = exact_value_to_quaternion(ev);
} else if (is_type_string(dst)) {
// Handled elsewhere
GB_ASSERT_MSG(ev.kind == ExactValue_String, "%d", ev.kind);
@@ -4875,6 +4974,49 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
return ir_emit_load(proc, gen);
}
if (is_type_quaternion(src) && is_type_quaternion(dst)) {
// @QuaternionLayout
Type *ft = base_complex_elem_type(dst);
irValue *gen = ir_add_local_generated(proc, dst, false);
irValue *q0 = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 0), ft);
irValue *q1 = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 1), ft);
irValue *q2 = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 2), ft);
irValue *q3 = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 3), ft);
ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 0), q0);
ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 1), q1);
ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 2), q2);
ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 3), q3);
return ir_emit_load(proc, gen);
}
if (is_type_float(src) && is_type_complex(dst)) {
Type *ft = base_complex_elem_type(dst);
irValue *gen = ir_add_local_generated(proc, dst, true);
irValue *real = ir_emit_conv(proc, value, ft);
ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 0), real);
return ir_emit_load(proc, gen);
}
if (is_type_float(src) && is_type_quaternion(dst)) {
Type *ft = base_complex_elem_type(dst);
irValue *gen = ir_add_local_generated(proc, dst, true);
irValue *real = ir_emit_conv(proc, value, ft);
// @QuaternionLayout
ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 3), real);
return ir_emit_load(proc, gen);
}
if (is_type_complex(src) && is_type_quaternion(dst)) {
Type *ft = base_complex_elem_type(dst);
irValue *gen = ir_add_local_generated(proc, dst, true);
irValue *real = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 0), ft);
irValue *imag = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 1), ft);
// @QuaternionLayout
ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 3), real);
ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 0), imag);
return ir_emit_load(proc, gen);
}
// float <-> integer
if (is_type_float(src) && is_type_integer(dst)) {
irConvKind kind = irConv_fptosi;
@@ -5315,6 +5457,7 @@ enum Typeid_Kind : u8 {
Typeid_Rune,
Typeid_Float,
Typeid_Complex,
Typeid_Quaternion,
Typeid_String,
Typeid_Boolean,
Typeid_Any,
@@ -6067,17 +6210,77 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu
return ir_emit_load(proc, dst);
}
case BuiltinProc_quaternion: {
ir_emit_comment(proc, str_lit("quaternion"));
irValue *real = ir_build_expr(proc, ce->args[0]);
irValue *imag = ir_build_expr(proc, ce->args[1]);
irValue *jmag = ir_build_expr(proc, ce->args[2]);
irValue *kmag = ir_build_expr(proc, ce->args[3]);
// @QuaternionLayout
irValue *dst = ir_add_local_generated(proc, tv.type, false);
Type *ft = base_complex_elem_type(tv.type);
real = ir_emit_conv(proc, real, ft);
imag = ir_emit_conv(proc, imag, ft);
jmag = ir_emit_conv(proc, jmag, ft);
kmag = ir_emit_conv(proc, kmag, ft);
ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 3), real);
ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 0), imag);
ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 1), jmag);
ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 2), kmag);
return ir_emit_load(proc, dst);
}
case BuiltinProc_real: {
ir_emit_comment(proc, str_lit("real"));
irValue *val = ir_build_expr(proc, ce->args[0]);
irValue *real = ir_emit_struct_ev(proc, val, 0);
return ir_emit_conv(proc, real, tv.type);
if (is_type_complex(ir_type(val))) {
irValue *real = ir_emit_struct_ev(proc, val, 0);
return ir_emit_conv(proc, real, tv.type);
} else if (is_type_quaternion(ir_type(val))) {
// @QuaternionLayout
irValue *real = ir_emit_struct_ev(proc, val, 3);
return ir_emit_conv(proc, real, tv.type);
}
GB_PANIC("invalid type for real");
return nullptr;
}
case BuiltinProc_imag: {
ir_emit_comment(proc, str_lit("imag"));
irValue *val = ir_build_expr(proc, ce->args[0]);
irValue *imag = ir_emit_struct_ev(proc, val, 1);
return ir_emit_conv(proc, imag, tv.type);
if (is_type_complex(ir_type(val))) {
irValue *imag = ir_emit_struct_ev(proc, val, 1);
return ir_emit_conv(proc, imag, tv.type);
} else if (is_type_quaternion(ir_type(val))) {
// @QuaternionLayout
irValue *imag = ir_emit_struct_ev(proc, val, 0);
return ir_emit_conv(proc, imag, tv.type);
}
GB_PANIC("invalid type for imag");
return nullptr;
}
case BuiltinProc_jmag: {
ir_emit_comment(proc, str_lit("jmag"));
irValue *val = ir_build_expr(proc, ce->args[0]);
if (is_type_quaternion(ir_type(val))) {
// @QuaternionLayout
irValue *imag = ir_emit_struct_ev(proc, val, 1);
return ir_emit_conv(proc, imag, tv.type);
}
GB_PANIC("invalid type for jmag");
return nullptr;
}
case BuiltinProc_kmag: {
ir_emit_comment(proc, str_lit("kmag"));
irValue *val = ir_build_expr(proc, ce->args[0]);
if (is_type_quaternion(ir_type(val))) {
// @QuaternionLayout
irValue *imag = ir_emit_struct_ev(proc, val, 2);
return ir_emit_conv(proc, imag, tv.type);
}
GB_PANIC("invalid type for kmag");
return nullptr;
}
case BuiltinProc_conj: {
@@ -6092,6 +6295,20 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu
imag = ir_emit_unary_arith(proc, Token_Sub, imag, ir_type(imag));
ir_emit_store(proc, ir_emit_struct_ep(proc, res, 0), real);
ir_emit_store(proc, ir_emit_struct_ep(proc, res, 1), imag);
} else if (is_type_quaternion(t)) {
// @QuaternionLayout
res = ir_add_local_generated(proc, tv.type, false);
irValue *real = ir_emit_struct_ev(proc, val, 3);
irValue *imag = ir_emit_struct_ev(proc, val, 0);
irValue *jmag = ir_emit_struct_ev(proc, val, 1);
irValue *kmag = ir_emit_struct_ev(proc, val, 2);
imag = ir_emit_unary_arith(proc, Token_Sub, imag, ir_type(imag));
jmag = ir_emit_unary_arith(proc, Token_Sub, jmag, ir_type(jmag));
kmag = ir_emit_unary_arith(proc, Token_Sub, kmag, ir_type(kmag));
ir_emit_store(proc, ir_emit_struct_ep(proc, res, 3), real);
ir_emit_store(proc, ir_emit_struct_ep(proc, res, 0), imag);
ir_emit_store(proc, ir_emit_struct_ep(proc, res, 1), jmag);
ir_emit_store(proc, ir_emit_struct_ep(proc, res, 2), kmag);
}
return ir_emit_load(proc, res);
}
@@ -6162,7 +6379,16 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu
return x;
}
ir_emit_comment(proc, str_lit("abs"));
if (is_type_complex(t)) {
if (is_type_quaternion(t)) {
i64 sz = 8*type_size_of(t);
auto args = array_make<irValue *>(ir_allocator(), 1);
args[0] = x;
switch (sz) {
case 128: return ir_emit_runtime_call(proc, "abs_quaternion128", args);
case 256: return ir_emit_runtime_call(proc, "abs_quaternion256", args);
}
GB_PANIC("Unknown complex type");
} else if (is_type_complex(t)) {
i64 sz = 8*type_size_of(t);
auto args = array_make<irValue *>(ir_allocator(), 1);
args[0] = x;
@@ -9876,6 +10102,11 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
tag = ir_emit_conv(proc, variant_ptr, t_type_info_complex_ptr);
break;
case Basic_quaternion128:
case Basic_quaternion256:
tag = ir_emit_conv(proc, variant_ptr, t_type_info_quaternion_ptr);
break;
case Basic_rawptr:
tag = ir_emit_conv(proc, variant_ptr, t_type_info_pointer_ptr);
break;

View File

@@ -418,20 +418,23 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct) {
}
return;
// case Basic_f16: ir_write_str_lit(f, "half"); return;
case Basic_f32: ir_write_str_lit(f, "float"); return;
case Basic_f64: ir_write_str_lit(f, "double"); return;
// case Basic_f16: ir_write_str_lit(f, "half"); return;
case Basic_f32: ir_write_str_lit(f, "float"); return;
case Basic_f64: ir_write_str_lit(f, "double"); return;
// case Basic_complex32: ir_write_str_lit(f, "%%..complex32"); return;
case Basic_complex64: ir_write_str_lit(f, "%..complex64"); return;
case Basic_complex128: ir_write_str_lit(f, "%..complex128"); return;
// case Basic_complex32: ir_write_str_lit(f, "%%..complex32"); return;
case Basic_complex64: ir_write_str_lit(f, "%..complex64"); return;
case Basic_complex128: ir_write_str_lit(f, "%..complex128"); return;
case Basic_any: ir_write_str_lit(f, "%..any"); return;
case Basic_rawptr: ir_write_str_lit(f, "%..rawptr"); return;
case Basic_string: ir_write_str_lit(f, "%..string"); return;
case Basic_cstring: ir_write_str_lit(f, "i8*"); return;
case Basic_quaternion128: ir_write_str_lit(f, "%..quaternion128"); return;
case Basic_quaternion256: ir_write_str_lit(f, "%..quaternion256"); return;
case Basic_typeid: ir_write_str_lit(f, "%..typeid"); return;
case Basic_any: ir_write_str_lit(f, "%..any"); return;
case Basic_rawptr: ir_write_str_lit(f, "%..rawptr"); return;
case Basic_string: ir_write_str_lit(f, "%..string"); return;
case Basic_cstring: ir_write_str_lit(f, "i8*"); return;
case Basic_typeid: ir_write_str_lit(f, "%..typeid"); return;
}
break;
@@ -811,6 +814,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
break;
}
case ExactValue_Complex: {
// xy/ri format
type = core_type(type);
GB_ASSERT_MSG(is_type_complex(type), "%s", type_to_string(type));
Type *ft = base_complex_elem_type(type);
@@ -823,6 +827,26 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
ir_write_byte(f, '}');
break;
}
case ExactValue_Quaternion: {
// xyzw/ijkr format
type = core_type(type);
GB_ASSERT_MSG(is_type_quaternion(type), "%s", type_to_string(type));
Type *ft = base_complex_elem_type(type);
ir_write_byte(f, ' ');
ir_write_byte(f, '{');
ir_print_type(f, m, ft); ir_write_byte(f, ' ');
ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.imag), ft);
ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' ');
ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.jmag), ft);
ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' ');
ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.kmag), ft);
ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' ');
ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.real), ft);
ir_write_byte(f, '}');
break;
}
case ExactValue_Pointer:
if (value.value_pointer == 0) {
if (is_type_typeid(type)) {
@@ -2246,6 +2270,13 @@ void print_llvm_ir(irGen *ir) {
ir_print_encoded_local(f, str_lit("..complex128"));
ir_write_str_lit(f, " = type {double, double} ; Basic_complex128\n");
ir_print_encoded_local(f, str_lit("..quaternion64"));
ir_write_str_lit(f, " = type {half, half, half, half} ; Basic_quaternion64\n");
ir_print_encoded_local(f, str_lit("..quaternion128"));
ir_write_str_lit(f, " = type {float, float, float, float} ; Basic_quaternion128\n");
ir_print_encoded_local(f, str_lit("..quaternion256"));
ir_write_str_lit(f, " = type {double, double, double, double} ; Basic_quaternion256\n");
ir_print_encoded_local(f, str_lit("..typeid"));
ir_write_str_lit(f, " = type ");
ir_print_type(f, m, t_uintptr);

View File

@@ -745,7 +745,10 @@ exponent:
scan_mantissa(t, 10);
}
if (t->curr_rune == 'i') {
switch (t->curr_rune) {
case 'i':
case 'j':
case 'k':
token.kind = Token_Imag;
advance_to_next_rune(t);
}

View File

@@ -32,6 +32,9 @@ enum BasicKind {
Basic_complex64,
Basic_complex128,
Basic_quaternion128,
Basic_quaternion256,
Basic_int,
Basic_uint,
Basic_uintptr,
@@ -66,6 +69,7 @@ enum BasicKind {
Basic_UntypedInteger,
Basic_UntypedFloat,
Basic_UntypedComplex,
Basic_UntypedQuaternion,
Basic_UntypedString,
Basic_UntypedRune,
Basic_UntypedNil,
@@ -82,17 +86,18 @@ enum BasicFlag {
BasicFlag_Unsigned = GB_BIT(2),
BasicFlag_Float = GB_BIT(3),
BasicFlag_Complex = GB_BIT(4),
BasicFlag_Pointer = GB_BIT(5),
BasicFlag_String = GB_BIT(6),
BasicFlag_Rune = GB_BIT(7),
BasicFlag_Untyped = GB_BIT(8),
BasicFlag_Quaternion = GB_BIT(5),
BasicFlag_Pointer = GB_BIT(6),
BasicFlag_String = GB_BIT(7),
BasicFlag_Rune = GB_BIT(8),
BasicFlag_Untyped = GB_BIT(9),
BasicFlag_LLVM = GB_BIT(10),
BasicFlag_LLVM = GB_BIT(11),
BasicFlag_EndianLittle = GB_BIT(13),
BasicFlag_EndianBig = GB_BIT(14),
BasicFlag_Numeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Complex,
BasicFlag_Numeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Complex | BasicFlag_Quaternion,
BasicFlag_Ordered = BasicFlag_Integer | BasicFlag_Float | BasicFlag_String | BasicFlag_Pointer | BasicFlag_Rune,
BasicFlag_OrderedNumeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Rune,
BasicFlag_ConstantType = BasicFlag_Boolean | BasicFlag_Numeric | BasicFlag_String | BasicFlag_Pointer | BasicFlag_Rune,
@@ -342,6 +347,9 @@ gb_global Type basic_types[] = {
{Type_Basic, {Basic_complex64, BasicFlag_Complex, 8, STR_LIT("complex64")}},
{Type_Basic, {Basic_complex128, BasicFlag_Complex, 16, STR_LIT("complex128")}},
{Type_Basic, {Basic_quaternion128, BasicFlag_Quaternion, 16, STR_LIT("quaternion128")}},
{Type_Basic, {Basic_quaternion256, BasicFlag_Quaternion, 32, STR_LIT("quaternion256")}},
{Type_Basic, {Basic_int, BasicFlag_Integer, -1, STR_LIT("int")}},
{Type_Basic, {Basic_uint, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uint")}},
{Type_Basic, {Basic_uintptr, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uintptr")}},
@@ -377,6 +385,7 @@ gb_global Type basic_types[] = {
{Type_Basic, {Basic_UntypedInteger, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped integer")}},
{Type_Basic, {Basic_UntypedFloat, BasicFlag_Float | BasicFlag_Untyped, 0, STR_LIT("untyped float")}},
{Type_Basic, {Basic_UntypedComplex, BasicFlag_Complex | BasicFlag_Untyped, 0, STR_LIT("untyped complex")}},
{Type_Basic, {Basic_UntypedQuaternion, BasicFlag_Quaternion | BasicFlag_Untyped, 0, STR_LIT("untyped quaternion")}},
{Type_Basic, {Basic_UntypedString, BasicFlag_String | BasicFlag_Untyped, 0, STR_LIT("untyped string")}},
{Type_Basic, {Basic_UntypedRune, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped rune")}},
{Type_Basic, {Basic_UntypedNil, BasicFlag_Untyped, 0, STR_LIT("untyped nil")}},
@@ -412,6 +421,9 @@ gb_global Type *t_f64 = &basic_types[Basic_f64];
gb_global Type *t_complex64 = &basic_types[Basic_complex64];
gb_global Type *t_complex128 = &basic_types[Basic_complex128];
gb_global Type *t_quaternion128 = &basic_types[Basic_quaternion128];
gb_global Type *t_quaternion256 = &basic_types[Basic_quaternion256];
gb_global Type *t_int = &basic_types[Basic_int];
gb_global Type *t_uint = &basic_types[Basic_uint];
gb_global Type *t_uintptr = &basic_types[Basic_uintptr];
@@ -446,6 +458,7 @@ gb_global Type *t_untyped_bool = &basic_types[Basic_UntypedBool];
gb_global Type *t_untyped_integer = &basic_types[Basic_UntypedInteger];
gb_global Type *t_untyped_float = &basic_types[Basic_UntypedFloat];
gb_global Type *t_untyped_complex = &basic_types[Basic_UntypedComplex];
gb_global Type *t_untyped_quaternion = &basic_types[Basic_UntypedQuaternion];
gb_global Type *t_untyped_string = &basic_types[Basic_UntypedString];
gb_global Type *t_untyped_rune = &basic_types[Basic_UntypedRune];
gb_global Type *t_untyped_nil = &basic_types[Basic_UntypedNil];
@@ -472,6 +485,7 @@ gb_global Type *t_type_info_integer = nullptr;
gb_global Type *t_type_info_rune = nullptr;
gb_global Type *t_type_info_float = nullptr;
gb_global Type *t_type_info_complex = nullptr;
gb_global Type *t_type_info_quaternion = nullptr;
gb_global Type *t_type_info_any = nullptr;
gb_global Type *t_type_info_typeid = nullptr;
gb_global Type *t_type_info_string = nullptr;
@@ -496,6 +510,7 @@ gb_global Type *t_type_info_integer_ptr = nullptr;
gb_global Type *t_type_info_rune_ptr = nullptr;
gb_global Type *t_type_info_float_ptr = nullptr;
gb_global Type *t_type_info_complex_ptr = nullptr;
gb_global Type *t_type_info_quaternion_ptr = nullptr;
gb_global Type *t_type_info_any_ptr = nullptr;
gb_global Type *t_type_info_typeid_ptr = nullptr;
gb_global Type *t_type_info_string_ptr = nullptr;
@@ -924,6 +939,13 @@ bool is_type_complex(Type *t) {
}
return false;
}
bool is_type_quaternion(Type *t) {
t = core_type(t);
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Quaternion) != 0;
}
return false;
}
bool is_type_f32(Type *t) {
t = core_type(t);
if (t->kind == Type_Basic) {
@@ -1063,12 +1085,15 @@ bool is_type_simple_compare(Type *t) {
Type *base_complex_elem_type(Type *t) {
t = core_type(t);
if (is_type_complex(t)) {
if (t->kind == Type_Basic) {
switch (t->Basic.kind) {
// case Basic_complex32: return t_f16;
case Basic_complex64: return t_f32;
case Basic_complex128: return t_f64;
case Basic_UntypedComplex: return t_untyped_float;
// case Basic_complex32: return t_f16;
case Basic_complex64: return t_f32;
case Basic_complex128: return t_f64;
case Basic_quaternion128: return t_f32;
case Basic_quaternion256: return t_f64;
case Basic_UntypedComplex: return t_untyped_float;
case Basic_UntypedQuaternion: return t_untyped_float;
}
}
GB_PANIC("Invalid complex type");
@@ -1818,6 +1843,7 @@ Type *default_type(Type *type) {
case Basic_UntypedInteger: return t_int;
case Basic_UntypedFloat: return t_f64;
case Basic_UntypedComplex: return t_complex128;
case Basic_UntypedQuaternion: return t_quaternion256;
case Basic_UntypedString: return t_string;
case Basic_UntypedRune: return t_rune;
}
@@ -2358,6 +2384,8 @@ i64 type_align_of_internal(Type *t, TypePath *path) {
case Basic_complex64: case Basic_complex128:
return type_size_of_internal(t, path) / 2;
case Basic_quaternion128: case Basic_quaternion256:
return type_size_of_internal(t, path) / 4;
}
} break;