mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-07 16:18:52 +00:00
Enforce naming the parameters with builtin.quaternion to reduce confusion
This commit is contained in:
@@ -137,9 +137,9 @@ assign_float :: proc(val: any, f: $T) -> bool {
|
|||||||
case complex64: dst = complex(f32(f), 0)
|
case complex64: dst = complex(f32(f), 0)
|
||||||
case complex128: dst = complex(f64(f), 0)
|
case complex128: dst = complex(f64(f), 0)
|
||||||
|
|
||||||
case quaternion64: dst = quaternion(f16(f), 0, 0, 0)
|
case quaternion64: dst = quaternion(w=f16(f), x=0, y=0, z=0)
|
||||||
case quaternion128: dst = quaternion(f32(f), 0, 0, 0)
|
case quaternion128: dst = quaternion(w=f32(f), x=0, y=0, z=0)
|
||||||
case quaternion256: dst = quaternion(f64(f), 0, 0, 0)
|
case quaternion256: dst = quaternion(w=f64(f), x=0, y=0, z=0)
|
||||||
|
|
||||||
case: return false
|
case: return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ outer_product :: builtin.outer_product
|
|||||||
|
|
||||||
@(require_results)
|
@(require_results)
|
||||||
quaternion_inverse :: proc "contextless" (q: $Q) -> Q where IS_QUATERNION(Q) {
|
quaternion_inverse :: proc "contextless" (q: $Q) -> Q where IS_QUATERNION(Q) {
|
||||||
return conj(q) * quaternion(1.0/dot(q, q), 0, 0, 0)
|
return conj(q) * quaternion(w=1.0/dot(q, q), x=0, y=0, z=0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -730,7 +730,7 @@ mul_quaternion64 :: proc "contextless" (q, r: quaternion64) -> quaternion64 {
|
|||||||
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1
|
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1
|
||||||
t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0
|
t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0
|
||||||
|
|
||||||
return quaternion(t0, t1, t2, t3)
|
return quaternion(w=t0, x=t1, y=t2, z=t3)
|
||||||
}
|
}
|
||||||
|
|
||||||
mul_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
|
mul_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
|
||||||
@@ -742,7 +742,7 @@ mul_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
|
|||||||
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1
|
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1
|
||||||
t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0
|
t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0
|
||||||
|
|
||||||
return quaternion(t0, t1, t2, t3)
|
return quaternion(w=t0, x=t1, y=t2, z=t3)
|
||||||
}
|
}
|
||||||
|
|
||||||
mul_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
|
mul_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
|
||||||
@@ -754,7 +754,7 @@ mul_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
|
|||||||
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1
|
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1
|
||||||
t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0
|
t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0
|
||||||
|
|
||||||
return quaternion(t0, t1, t2, t3)
|
return quaternion(w=t0, x=t1, y=t2, z=t3)
|
||||||
}
|
}
|
||||||
|
|
||||||
quo_quaternion64 :: proc "contextless" (q, r: quaternion64) -> quaternion64 {
|
quo_quaternion64 :: proc "contextless" (q, r: quaternion64) -> quaternion64 {
|
||||||
@@ -768,7 +768,7 @@ quo_quaternion64 :: proc "contextless" (q, r: quaternion64) -> quaternion64 {
|
|||||||
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2
|
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2
|
||||||
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2
|
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2
|
||||||
|
|
||||||
return quaternion(t0, t1, t2, t3)
|
return quaternion(w=t0, x=t1, y=t2, z=t3)
|
||||||
}
|
}
|
||||||
|
|
||||||
quo_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
|
quo_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
|
||||||
@@ -782,7 +782,7 @@ quo_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
|
|||||||
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2
|
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2
|
||||||
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2
|
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2
|
||||||
|
|
||||||
return quaternion(t0, t1, t2, t3)
|
return quaternion(w=t0, x=t1, y=t2, z=t3)
|
||||||
}
|
}
|
||||||
|
|
||||||
quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
|
quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
|
||||||
@@ -796,7 +796,7 @@ quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
|
|||||||
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2
|
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2
|
||||||
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2
|
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2
|
||||||
|
|
||||||
return quaternion(t0, t1, t2, t3)
|
return quaternion(w=t0, x=t1, y=t2, z=t3)
|
||||||
}
|
}
|
||||||
|
|
||||||
@(link_name="__truncsfhf2", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
|
@(link_name="__truncsfhf2", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
|
||||||
|
|||||||
@@ -13,6 +13,11 @@ foreign advapi32 {
|
|||||||
DesiredAccess: DWORD,
|
DesiredAccess: DWORD,
|
||||||
TokenHandle: ^HANDLE) -> BOOL ---
|
TokenHandle: ^HANDLE) -> BOOL ---
|
||||||
|
|
||||||
|
OpenThreadToken :: proc(ThreadHandle: HANDLE,
|
||||||
|
DesiredAccess: DWORD,
|
||||||
|
OpenAsSelf: BOOL,
|
||||||
|
TokenHandle: ^HANDLE) -> BOOL ---
|
||||||
|
|
||||||
CryptAcquireContextW :: proc(hProv: ^HCRYPTPROV, szContainer, szProvider: wstring, dwProvType, dwFlags: DWORD) -> DWORD ---
|
CryptAcquireContextW :: proc(hProv: ^HCRYPTPROV, szContainer, szProvider: wstring, dwProvType, dwFlags: DWORD) -> DWORD ---
|
||||||
CryptGenRandom :: proc(hProv: HCRYPTPROV, dwLen: DWORD, buf: LPVOID) -> DWORD ---
|
CryptGenRandom :: proc(hProv: HCRYPTPROV, dwLen: DWORD, buf: LPVOID) -> DWORD ---
|
||||||
CryptReleaseContext :: proc(hProv: HCRYPTPROV, dwFlags: DWORD) -> DWORD ---
|
CryptReleaseContext :: proc(hProv: HCRYPTPROV, dwFlags: DWORD) -> DWORD ---
|
||||||
|
|||||||
@@ -1514,7 +1514,7 @@ quaternions :: proc() {
|
|||||||
|
|
||||||
{ // Quaternion operations
|
{ // Quaternion operations
|
||||||
q := 1 + 2i + 3j + 4k
|
q := 1 + 2i + 3j + 4k
|
||||||
r := quaternion(5, 6, 7, 8)
|
r := quaternion(real=5, imag=6, jmag=7, kmag=8)
|
||||||
t := q * r
|
t := q * r
|
||||||
fmt.printf("(%v) * (%v) = %v\n", q, r, t)
|
fmt.printf("(%v) * (%v) = %v\n", q, r, t)
|
||||||
v := q / r
|
v := q / r
|
||||||
@@ -1527,8 +1527,10 @@ quaternions :: proc() {
|
|||||||
{ // The quaternion types
|
{ // The quaternion types
|
||||||
q128: quaternion128 // 4xf32
|
q128: quaternion128 // 4xf32
|
||||||
q256: quaternion256 // 4xf64
|
q256: quaternion256 // 4xf64
|
||||||
q128 = quaternion(1, 0, 0, 0)
|
q128 = quaternion(w=1, x=0, y=0, z=0)
|
||||||
q256 = 1 // quaternion(1, 0, 0, 0)
|
q256 = 1 // quaternion(x=0, y=0, z=0, w=1)
|
||||||
|
|
||||||
|
// NOTE: The internal memory layout of a quaternion is xyzw
|
||||||
}
|
}
|
||||||
{ // Built-in procedures
|
{ // Built-in procedures
|
||||||
q := 1 + 2i + 3j + 4k
|
q := 1 + 2i + 3j + 4k
|
||||||
|
|||||||
+115
-6
@@ -1666,7 +1666,12 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
|||||||
|
|
||||||
if (ce->args.count > 0) {
|
if (ce->args.count > 0) {
|
||||||
if (ce->args[0]->kind == Ast_FieldValue) {
|
if (ce->args[0]->kind == Ast_FieldValue) {
|
||||||
if (id != BuiltinProc_soa_zip) {
|
switch (id) {
|
||||||
|
case BuiltinProc_soa_zip:
|
||||||
|
case BuiltinProc_quaternion:
|
||||||
|
// okay
|
||||||
|
break;
|
||||||
|
default:
|
||||||
error(call, "'field = value' calling is not allowed on built-in procedures");
|
error(call, "'field = value' calling is not allowed on built-in procedures");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2299,8 +2304,32 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
|||||||
}
|
}
|
||||||
|
|
||||||
case BuiltinProc_quaternion: {
|
case BuiltinProc_quaternion: {
|
||||||
|
bool first_is_field_value = (ce->args[0]->kind == Ast_FieldValue);
|
||||||
|
|
||||||
|
bool fail = false;
|
||||||
|
for (Ast *arg : ce->args) {
|
||||||
|
bool mix = false;
|
||||||
|
if (first_is_field_value) {
|
||||||
|
mix = arg->kind != Ast_FieldValue;
|
||||||
|
} else {
|
||||||
|
mix = arg->kind == Ast_FieldValue;
|
||||||
|
}
|
||||||
|
if (mix) {
|
||||||
|
error(arg, "Mixture of 'field = value' and value elements in the procedure call '%.*s' is not allowed", LIT(builtin_name));
|
||||||
|
fail = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fail) {
|
||||||
|
operand->type = t_untyped_quaternion;
|
||||||
|
operand->mode = Addressing_Constant;
|
||||||
|
operand->value = exact_value_quaternion(0.0, 0.0, 0.0, 0.0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// quaternion :: proc(real, imag, jmag, kmag: float_type) -> complex_type
|
// quaternion :: proc(real, imag, jmag, kmag: float_type) -> complex_type
|
||||||
Operand x = *operand;
|
Operand x = {};
|
||||||
Operand y = {};
|
Operand y = {};
|
||||||
Operand z = {};
|
Operand z = {};
|
||||||
Operand w = {};
|
Operand w = {};
|
||||||
@@ -2309,23 +2338,103 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
|||||||
operand->type = t_invalid;
|
operand->type = t_invalid;
|
||||||
operand->mode = Addressing_Invalid;
|
operand->mode = Addressing_Invalid;
|
||||||
|
|
||||||
|
if (first_is_field_value) {
|
||||||
|
u32 fields_set[4] = {}; // 0 unset, 1 xyzw, 2 real/etc
|
||||||
|
|
||||||
|
auto const check_field = [&fields_set, &builtin_name](CheckerContext *c, Operand *o, Ast *arg, i32 *index) -> bool {
|
||||||
|
*index = -1;
|
||||||
|
|
||||||
|
ast_node(field, FieldValue, arg);
|
||||||
|
String name = {};
|
||||||
|
if (field->field->kind == Ast_Ident) {
|
||||||
|
name = field->field->Ident.token.string;
|
||||||
|
} else {
|
||||||
|
error(field->field, "Expected an identifier for field argument");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 style = 0;
|
||||||
|
|
||||||
|
if (name == "x") {
|
||||||
|
*index = 1; style = 1;
|
||||||
|
} else if (name == "y") {
|
||||||
|
*index = 2; style = 1;
|
||||||
|
} else if (name == "z") {
|
||||||
|
*index = 3; style = 1;
|
||||||
|
} else if (name == "w") {
|
||||||
|
*index = 0; style = 1;
|
||||||
|
} else if (name == "imag") {
|
||||||
|
*index = 1; style = 2;
|
||||||
|
} else if (name == "jmag") {
|
||||||
|
*index = 2; style = 2;
|
||||||
|
} else if (name == "kmag") {
|
||||||
|
*index = 3; style = 2;
|
||||||
|
} else if (name == "real") {
|
||||||
|
*index = 0; style = 2;
|
||||||
|
} else {
|
||||||
|
error(field->field, "Unknown name for '%.*s', expected (w, x, y, z; or real, imag, jmag, kmag), got '%.*s'", LIT(builtin_name), LIT(name));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fields_set[*index]) {
|
||||||
|
error(field->field, "Previously assigned field: '%.*s'", LIT(name));
|
||||||
|
}
|
||||||
|
fields_set[*index] = style;
|
||||||
|
|
||||||
|
check_expr(c, o, field->value);
|
||||||
|
return o->mode != Addressing_Invalid;
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO(bill): disallow style mixing
|
||||||
|
|
||||||
|
Operand *refs[4] = {&x, &y, &z, &w};
|
||||||
|
|
||||||
|
for (i32 i = 0; i < 4; i++) {
|
||||||
|
i32 index = -1;
|
||||||
|
Operand o = {};
|
||||||
|
bool ok = check_field(c, &o, ce->args[i], &index);
|
||||||
|
if (!ok) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*refs[index] = o;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i32 i = 0; i < 4; i++) {
|
||||||
|
GB_ASSERT(fields_set[i]);
|
||||||
|
}
|
||||||
|
for (i32 i = 1; i < 4; i++) {
|
||||||
|
if (fields_set[i] != fields_set[i-1]) {
|
||||||
|
error(call, "Mixture of xyzw and real/etc is not allowed with '%.*s'", LIT(builtin_name));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error(call, "'%.*s' requires that all arguments are named (w, x, y, z; or real, imag, jmag, kmag)", LIT(builtin_name));
|
||||||
|
|
||||||
|
check_expr(c, &x, ce->args[0]);
|
||||||
|
if (x.mode == Addressing_Invalid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
check_expr(c, &y, ce->args[1]);
|
check_expr(c, &y, ce->args[1]);
|
||||||
if (y.mode == Addressing_Invalid) {
|
if (y.mode == Addressing_Invalid) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
check_expr(c, &z, ce->args[2]);
|
check_expr(c, &z, ce->args[2]);
|
||||||
if (y.mode == Addressing_Invalid) {
|
if (z.mode == Addressing_Invalid) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
check_expr(c, &w, ce->args[3]);
|
check_expr(c, &w, ce->args[3]);
|
||||||
if (y.mode == Addressing_Invalid) {
|
if (w.mode == Addressing_Invalid) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
convert_to_typed(c, &x, y.type); if (x.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, &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, &z, x.type); if (z.mode == Addressing_Invalid) return false;
|
||||||
convert_to_typed(c, &w, x.type); if (w.mode == Addressing_Invalid) return false;
|
convert_to_typed(c, &w, x.type); if (w.mode == Addressing_Invalid) return false;
|
||||||
|
|
||||||
if (x.mode == Addressing_Constant &&
|
if (x.mode == Addressing_Constant &&
|
||||||
y.mode == Addressing_Constant &&
|
y.mode == Addressing_Constant &&
|
||||||
z.mode == Addressing_Constant &&
|
z.mode == Addressing_Constant &&
|
||||||
@@ -3092,7 +3201,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
|||||||
mix = arg->kind == Ast_FieldValue;
|
mix = arg->kind == Ast_FieldValue;
|
||||||
}
|
}
|
||||||
if (mix) {
|
if (mix) {
|
||||||
error(arg, "Mixture of 'field = value' and value elements in the procedure call 'soa_zip' is not allowed");
|
error(arg, "Mixture of 'field = value' and value elements in the procedure call '%.*s' is not allowed", LIT(builtin_name));
|
||||||
fail = true;
|
fail = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
+29
-12
@@ -1826,24 +1826,41 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
|
|||||||
}
|
}
|
||||||
|
|
||||||
case BuiltinProc_quaternion: {
|
case BuiltinProc_quaternion: {
|
||||||
lbValue real = lb_build_expr(p, ce->args[0]);
|
lbValue xyzw[4] = {};
|
||||||
lbValue imag = lb_build_expr(p, ce->args[1]);
|
for (i32 i = 0; i < 4; i++) {
|
||||||
lbValue jmag = lb_build_expr(p, ce->args[2]);
|
ast_node(f, FieldValue, ce->args[i]);
|
||||||
lbValue kmag = lb_build_expr(p, ce->args[3]);
|
GB_ASSERT(f->field->kind == Ast_Ident);
|
||||||
|
String name = f->field->Ident.token.string;
|
||||||
|
i32 index = -1;
|
||||||
|
|
||||||
// @QuaternionLayout
|
// @QuaternionLayout
|
||||||
|
if (name == "x" || name == "imag") {
|
||||||
|
index = 0;
|
||||||
|
} else if (name == "y" || name == "jmag") {
|
||||||
|
index = 1;
|
||||||
|
} else if (name == "z" || name == "kmag") {
|
||||||
|
index = 2;
|
||||||
|
} else if (name == "w" || name == "real") {
|
||||||
|
index = 3;
|
||||||
|
}
|
||||||
|
GB_ASSERT(index >= 0);
|
||||||
|
|
||||||
|
xyzw[index] = lb_build_expr(p, ce->args[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
lbAddr dst_addr = lb_add_local_generated(p, tv.type, false);
|
lbAddr dst_addr = lb_add_local_generated(p, tv.type, false);
|
||||||
lbValue dst = lb_addr_get_ptr(p, dst_addr);
|
lbValue dst = lb_addr_get_ptr(p, dst_addr);
|
||||||
|
|
||||||
Type *ft = base_complex_elem_type(tv.type);
|
Type *ft = base_complex_elem_type(tv.type);
|
||||||
real = lb_emit_conv(p, real, ft);
|
xyzw[0] = lb_emit_conv(p, xyzw[0], ft);
|
||||||
imag = lb_emit_conv(p, imag, ft);
|
xyzw[1] = lb_emit_conv(p, xyzw[1], ft);
|
||||||
jmag = lb_emit_conv(p, jmag, ft);
|
xyzw[2] = lb_emit_conv(p, xyzw[2], ft);
|
||||||
kmag = lb_emit_conv(p, kmag, ft);
|
xyzw[3] = lb_emit_conv(p, xyzw[3], ft);
|
||||||
lb_emit_store(p, lb_emit_struct_ep(p, dst, 3), real);
|
lb_emit_store(p, lb_emit_struct_ep(p, dst, 0), xyzw[0]);
|
||||||
lb_emit_store(p, lb_emit_struct_ep(p, dst, 0), imag);
|
lb_emit_store(p, lb_emit_struct_ep(p, dst, 1), xyzw[1]);
|
||||||
lb_emit_store(p, lb_emit_struct_ep(p, dst, 1), jmag);
|
lb_emit_store(p, lb_emit_struct_ep(p, dst, 2), xyzw[2]);
|
||||||
lb_emit_store(p, lb_emit_struct_ep(p, dst, 2), kmag);
|
lb_emit_store(p, lb_emit_struct_ep(p, dst, 3), xyzw[3]);
|
||||||
|
|
||||||
return lb_emit_load(p, dst);
|
return lb_emit_load(p, dst);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user