From dc303cde21d23b1b57a4cb4f667b2cfbe2a39ffd Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Sat, 1 Apr 2017 12:07:41 +0100 Subject: Complex numbers: complex64 complex128 --- code/demo.odin | 315 +-------------------------------------------------------- 1 file changed, 2 insertions(+), 313 deletions(-) (limited to 'code') diff --git a/code/demo.odin b/code/demo.odin index 3b78f7de3..e9eba17c8 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -1,320 +1,9 @@ -#import "atomic.odin"; -#import "hash.odin"; -#import "mem.odin"; -#import "opengl.odin"; -#import "strconv.odin"; -#import "sync.odin"; -#import win32 "sys/windows.odin"; - #import "fmt.odin"; #import "os.odin"; #import "math.odin"; main :: proc() { -when true { -/* - Added: - * Unexported entities and fields using an underscore prefix - - See `sync.odin` and explain - - Removed: - * Maybe/option types - * Remove `type` keyword and other "reserved" keywords - * ..< and ... removed and replace with .. (half-closed range) - - Changed: - * `compile_assert` and `assert`return the value of the condition for semantic reasons - * thread_local -> #thread_local - * #include -> #load - * Files only get checked if they are actually used - * match x in y {} // For type match statements - * Version numbering now starts from 0.1.0 and uses the convention: - - major.minor.patch - * Core library additions to Windows specific stuff - */ - - { - Fruit :: enum { - APPLE, - BANANA, - COCONUT, - } - fmt.println(Fruit.names); - } - - { - A :: struct {x, y: f32}; - B :: struct #align 16 {x, y: f32}; - fmt.println("align_of(A) =", align_of(A)); - fmt.println("align_of(B) =", align_of(B)); - } - - { - // Removal of ..< and ... - for i in 0..16 { - } - // Is similar to - for _i := 0; _i < 16; _i++ { immutable i := _i; - } - } - - { - #label thing - for i in 0..10 { - for j in i+1..10 { - if j == 2 { - fmt.println(i, j); - continue thing; - } - if j == 3 { - break thing; - } - } - } - - // Works with, `for`, `for in`, `match`, `match in` - // NOTE(bill): This solves most of the problems I need `goto` for - } - - { - t := type_info(int); - using Type_Info; - match i in t { - case Integer, Float: - fmt.println("It's a number"); - } - - - x: any = 123; - #label foo - match i in x { - case int, f32: - fmt.println("It's an int or f32"); - break foo; - } - } - - { - cond := true; - x: int; - if cond { - x = 3; - } else { - x = 4; - } - - - // Ternary operator - y := cond ? 3 : 4; - - FOO :: true ? 123 : 432; // Constant ternary expression - fmt.println("Ternary values:", y, FOO); - } - - { - // Slices now store a capacity - buf: [256]byte; - s: []byte; - s = buf[..0]; // == buf[0..0]; - fmt.println("count =", s.count); - fmt.println("capacity =", s.capacity); - append(s, 1, 2, 3); - fmt.println(s); - - s = buf[1..2..3]; - fmt.println("count =", s.count); - fmt.println("capacity =", s.capacity); - fmt.println(s); - - clear(s); // Sets count to zero - s.count = 0; // Equivalent - } - - { - Foo :: struct { - x, y, z: f32, - ok: bool, - flags: u32, - } - foo_array: [256]Foo; - foo_as_bytes: []byte = slice_to_bytes(foo_array[..]); - // Useful for things like - // os.write(handle, foo_as_bytes); - - foo_slice := slice_ptr(cast(^Foo)foo_as_bytes.data, foo_as_bytes.count/size_of(Foo), foo_as_bytes.capacity/size_of(Foo)); - // Question: Should there be a bytes_to_slice procedure or is it clearer to do this even if it is error prone? - // And if so what would the syntax be? - // slice_transmute([]Foo, foo_as_bytes); - } - - { - Vec3 :: [vector 3]f32; - - x := Vec3{1, 2, 3}; - y := Vec3{4, 5, 6}; - fmt.println(x < y); - fmt.println(x + y); - fmt.println(x - y); - fmt.println(x * y); - fmt.println(x / y); - - for i in x { - fmt.println(i); - } - - compile_assert(size_of([vector 7]bool) == size_of([7]bool)); - compile_assert(size_of([vector 7]i32) == size_of([7]i32)); - // align_of([vector 7]i32) != align_of([7]i32) // this may be the case - } - - { - // fmt.* changes - // bprint* returns `int` (bytes written) - // sprint* returns `string` (bytes written as a string) - - data: [256]byte; - str := fmt.sprintf(data[..0], "Hellope %d %s %c", 123, "others", '!'); - fmt.println(str); - - buf := data[..0]; - count := fmt.bprintf(^buf, "Hellope %d %s %c", 123, "others", '!'); - fmt.println(cast(string)buf[..count]); - - // NOTE(bill): We may change this but because this is a library feature, I am not that bothered yet - } - - { - x: [dynamic]f64; - reserve(x, 16); - defer free(x); // `free` is overloaded for numerous types - // Number literals can have underscores in them for readability - append(x, 2_000_000.500_000, 3, 5, 7); // variadic append - - for p, i in x { - if i > 0 { fmt.print(", "); } - fmt.print(p); - } - fmt.println(); - } - - { - // Dynamic array "literals" - x := [dynamic]f64{2_000_000.500_000, 3, 5, 7}; - defer free(x); - fmt.println(x); // fmt.print* supports printing of dynamic types - clear(x); - fmt.println(x); - } - - { - m: map[f32]int; - reserve(m, 16); - defer free(m); - - m[1.0] = 1278; - m[2.0] = 7643; - m[3.0] = 564; - _, ok := m[3.0]; - c := m[3.0]; - assert(ok && c == 564); - - fmt.print("map["); - i := 0; - for val, key in m { - if i > 0 { - fmt.print(", "); - } - fmt.printf("%v=%v", key, val); - i += 1; - } - fmt.println("]"); - } - { - m := map[string]u32{ - "a" = 56, - "b" = 13453, - "c" = 7654, - }; - defer free(m); - - c := m["c"]; - _, ok := m["c"]; - assert(ok && c == 7654); - fmt.println(m); - - delete(m, "c"); // deletes entry with key "c" - _, found := m["c"]; - assert(!found); - - fmt.println(m); - clear(m); - fmt.println(m); - - // NOTE: Fixed size maps are planned but we have not yet implemented - // them as we have had no need for them as of yet - } - - { - Vector3 :: struct{x, y, z: f32}; - Quaternion :: struct{x, y, z, w: f32}; - - Entity :: union { - // Common Fields - id: u64, - name: string, - using position: Vector3, - orientation: Quaternion, - flags: u32, - - // Variants - Frog{ - ribbit_volume: f32, - jump_height: f32, - }, - Door{ - openness: f32, - }, - Map{ - width, height: f32, - place_positions: []Vector3, - place_names: []string, - }, - } - - entity: Entity; - // implicit conversion from variant to base type - entity = Entity.Frog{ - id = 1337, - ribbit_volume = 0.5, - jump_height = 2.1, - /*other data */ - }; - - entity.name = "Frank"; - entity.position = Vector3{1, 4, 9}; - - using Entity; - match e in entity { - case Frog: - fmt.println("Ribbit"); - case Door: - fmt.println("Creak"); - case Map: - fmt.println("Rustle"); - default: - fmt.println("Just a normal entity"); - } - - if frog, ok := union_cast(Frog)entity; ok { - fmt.printf("The frog jumps %f feet high at %v\n", frog.jump_height, frog.position); - } - - // Panics if not the correct type - frog: Frog; - frog = union_cast(Frog)entity; - frog, _ = union_cast(Frog)entity; // ignore error and force cast - } -} + x := 1+2i; + fmt.printf("%v\n", x); } - -- cgit v1.2.3 From 90fc9abeae5c580202909a35ccb0dd367a142f99 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Sat, 1 Apr 2017 12:12:08 +0100 Subject: Fix constant conversion for complex numbers from integers --- code/demo.odin | 2 ++ 1 file changed, 2 insertions(+) (limited to 'code') diff --git a/code/demo.odin b/code/demo.odin index e9eba17c8..f56f82aef 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -5,5 +5,7 @@ main :: proc() { x := 1+2i; + y := 3-4i; + x = x*y; fmt.printf("%v\n", x); } -- cgit v1.2.3 From 5008e2c88b314156e0388db7f7ed789fb828c7e4 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Sat, 1 Apr 2017 22:41:23 +0100 Subject: Add Quaternions: quaternion128, quaternion256 --- code/demo.odin | 8 +- core/_preload.odin | 70 ++++++++-- core/fmt.odin | 55 ++++++-- core/math.odin | 4 +- core/types.odin | 130 ++++++------------- src/check_expr.c | 375 ++++++++++++++++++++++++++++++++++++++++------------- src/checker.c | 51 +++++--- src/common.c | 6 + src/exact_value.c | 207 ++++++++++++++++++++++++++--- src/ir.c | 273 ++++++++++++++++++++++++++++++++++---- src/ir_print.c | 161 ++++++++++++++++++----- src/tokenizer.c | 4 +- src/types.c | 158 +++++++++++++--------- 13 files changed, 1149 insertions(+), 353 deletions(-) (limited to 'code') diff --git a/code/demo.odin b/code/demo.odin index f56f82aef..aa75411d8 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -4,8 +4,8 @@ main :: proc() { - x := 1+2i; - y := 3-4i; - x = x*y; - fmt.printf("%v\n", x); + x := 1+2i+3j+4k; + y := 3-4i-5j-6k; + z := x/y; + fmt.println(z, abs(z)); } diff --git a/core/_preload.odin b/core/_preload.odin index fd61abf69..f06d9bafb 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -2,9 +2,7 @@ #import "os.odin"; #import "fmt.odin"; -#import "mem.odin"; #import "utf8.odin"; -#import "hash.odin"; // IMPORTANT NOTE(bill): `type_info` & `type_info_val` cannot be used within a // #shared_global_scope due to the internals of the compiler. @@ -42,6 +40,7 @@ Type_Info :: union { Integer{size: int, signed: bool}, Float{size: int}, Complex{size: int}, + Quaternion{size: int}, String{}, Boolean{}, Any{}, @@ -130,8 +129,6 @@ __trap :: proc() #foreign __llvm_core "llvm.trap"; read_cycle_counter :: proc() -> u64 #foreign __llvm_core "llvm.readcyclecounter"; - - // IMPORTANT NOTE(bill): Must be in this order (as the compiler relies upon it) Allocator_Mode :: enum u8 { ALLOC, @@ -231,7 +228,7 @@ default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: return nil; } - mem.copy(new_memory, old_memory, min(old_size, new_size));; + __mem_copy(new_memory, old_memory, min(old_size, new_size));; free(old_memory); return new_memory; } @@ -290,7 +287,7 @@ __string_eq :: proc(a, b: string) -> bool { } __string_cmp :: proc(a, b: string) -> int { - return mem.compare(cast([]byte)a, cast([]byte)b); + return __mem_compare(a.data, b.data, min(a.count, b.count)); } __string_ne :: proc(a, b: string) -> bool #inline { return !__string_eq(a, b); } @@ -300,6 +297,26 @@ __string_le :: proc(a, b: string) -> bool #inline { return __string_cmp(a, b) <= __string_ge :: proc(a, b: string) -> bool #inline { return __string_cmp(a, b) >= 0; } +__complex64_eq :: proc(a, b: complex64) -> bool #inline { return real(a) == real(b) && imag(a) == imag(b); } +__complex64_ne :: proc(a, b: complex64) -> bool #inline { return real(a) != real(b) || imag(a) != imag(b); } + +__complex128_eq :: proc(a, b: complex128) -> bool #inline { return real(a) == real(b) && imag(a) == imag(b); } +__complex128_ne :: proc(a, b: complex128) -> bool #inline { return real(a) != real(b) || imag(a) != imag(b); } + + +__quaternion128_eq :: proc(a, b: quaternion128) -> bool #inline { + return real(a) == real(b) && imag(a) == imag(b) && jmag(a) == jmag(b) && kmag(a) == kmag(b); +} +__quaternion128_ne :: proc(a, b: quaternion128) -> bool #inline { + return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b); +} +__quaternion256_eq :: proc(a, b: quaternion256) -> bool #inline { + return real(a) == real(b) && imag(a) == imag(b) && jmag(a) == jmag(b) && kmag(a) == kmag(b); +} +__quaternion256_ne :: proc(a, b: quaternion256) -> bool #inline { + return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b); +} + __assert :: proc(file: string, line, column: int, msg: string) #inline { fmt.fprintf(os.stderr, "%s(%d:%d) Runtime assertion: %s\n", file, line, column, msg); @@ -381,6 +398,26 @@ __mem_compare :: proc(a, b: ^byte, n: int) -> int { return 0; } +__sqrt_f32 :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.sqrt.f32"; +__sqrt_f64 :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.sqrt.f64"; +__abs_complex64 :: proc(x: complex64) -> f32 #inline { + r, i := real(x), imag(x); + return __sqrt_f32(r*r + i*i); +} +__abs_complex128 :: proc(x: complex128) -> f64 #inline { + r, i := real(x), imag(x); + return __sqrt_f64(r*r + i*i); +} +__abs_quaternion128 :: proc(x: quaternion128) -> f32 #inline { + 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 :: proc(x: quaternion256) -> f64 #inline { + r, i, j, k := real(x), imag(x), jmag(x), kmag(x); + return __sqrt_f64(r*r + i*i + j*j + k*k); +} + + Raw_Any :: struct #ordered { type_info: ^Type_Info, @@ -460,7 +497,7 @@ __dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int, } data := cast(^byte)array.data; assert(data != nil); - mem.copy(data + (elem_size*array.count), items, elem_size * item_count); + __mem_copy(data + (elem_size*array.count), items, elem_size * item_count); array.count += item_count; return array.count; } @@ -479,7 +516,7 @@ __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: in } data := cast(^byte)array.data; assert(data != nil); - mem.zero(data + (elem_size*array.count), elem_size); + __mem_zero(data + (elem_size*array.count), elem_size); array.count++; return array.count; } @@ -496,7 +533,7 @@ __slice_append :: proc(slice_: rawptr, elem_size, elem_align: int, if item_count > 0 { data := cast(^byte)slice.data; assert(data != nil); - mem.copy(data + (elem_size*slice.count), items, elem_size * item_count); + __mem_copy(data + (elem_size*slice.count), items, elem_size * item_count); slice.count += item_count; } return slice.count; @@ -506,7 +543,14 @@ __slice_append :: proc(slice_: rawptr, elem_size, elem_align: int, // Map stuff __default_hash :: proc(data: []byte) -> u64 { - return hash.fnv64a(data); + fnv64a :: proc(data: []byte) -> u64 { + h: u64 = 0xcbf29ce484222325; + for b in data { + h = (h ~ cast(u64)b) * 0x100000001b3; + } + return h; + } + return fnv64a(data); } __default_hash_string :: proc(s: string) -> u64 { return __default_hash(cast([]byte)s); @@ -577,7 +621,7 @@ __dynamic_map_rehash :: proc(using header: __Map_Header, new_count: int) { e := __dynamic_map_get_entry(new_header, j); e.next = fr.entry_index; ndata := cast(^byte)e; - mem.copy(ndata+value_offset, data+value_offset, entry_size-value_offset); + __mem_copy(ndata+value_offset, data+value_offset, entry_size-value_offset); if __dynamic_map_full(new_header) { __dynamic_map_grow(new_header); } @@ -618,7 +662,7 @@ __dynamic_map_set :: proc(using h: __Map_Header, key: __Map_Key, value: rawptr) { data := cast(^byte)__dynamic_map_get_entry(h, index); val := data+value_offset; - mem.copy(val, value, entry_size-value_offset); + __mem_copy(val, value, entry_size-value_offset); } if __dynamic_map_full(h) { @@ -698,7 +742,7 @@ __dynamic_map_erase :: proc(using h: __Map_Header, fr: __Map_Find_Result) { if fr.entry_index == m.entries.count-1 { m.entries.count--; } - mem.copy(__dynamic_map_get_entry(h, fr.entry_index), __dynamic_map_get_entry(h, m.entries.count-1), entry_size); + __mem_copy(__dynamic_map_get_entry(h, fr.entry_index), __dynamic_map_get_entry(h, m.entries.count-1), entry_size); last := __dynamic_map_find(h, __dynamic_map_get_entry(h, fr.entry_index).key); if last.entry_prev >= 0 { __dynamic_map_get_entry(h, last.entry_prev).next = fr.entry_index; diff --git a/core/fmt.odin b/core/fmt.odin index 1a8766b3d..480155c08 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -115,6 +115,11 @@ write_type :: proc(buf: ^[]byte, ti: ^Type_Info) { case 8: write_string(buf, "complex64"); case 16: write_string(buf, "complex128"); } + case Quaternion: + match info.size { + case 16: write_string(buf, "quaternion128"); + case 32: write_string(buf, "quaternion"); + } case String: write_string(buf, "string"); case Boolean: write_string(buf, "bool"); case Pointer: @@ -736,11 +741,12 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { fmt_value(fi, any{info.base, v.data}, verb); } - case Boolean: fmt_arg(fi, v, verb); - case Float: fmt_arg(fi, v, verb); - case Complex: fmt_arg(fi, v, verb); - case Integer: fmt_arg(fi, v, verb); - case String: fmt_arg(fi, v, verb); + case Boolean: fmt_arg(fi, v, verb); + case Integer: fmt_arg(fi, v, verb); + case Float: fmt_arg(fi, v, verb); + case Complex: fmt_arg(fi, v, verb); + case Quaternion: fmt_arg(fi, v, verb); + case String: fmt_arg(fi, v, verb); case Pointer: if v.type_info == type_info(^Type_Info) { @@ -907,6 +913,33 @@ fmt_complex :: proc(fi: ^Fmt_Info, c: complex128, bits: int, verb: rune) { } } +fmt_quaternion :: proc(fi: ^Fmt_Info, c: quaternion256, bits: int, verb: rune) { + match verb { + case 'f', 'F', 'v': + r := real(c); + i := imag(c); + j := jmag(c); + k := kmag(c); + fmt_float(fi, r, bits/4, verb); + + if !fi.plus && i >= 0 { write_rune(fi.buf, '+'); } + fmt_float(fi, i, bits/4, verb); + write_rune(fi.buf, 'i'); + + if !fi.plus && j >= 0 { write_rune(fi.buf, '+'); } + fmt_float(fi, j, bits/4, verb); + write_rune(fi.buf, 'j'); + + if !fi.plus && k >= 0 { write_rune(fi.buf, '+'); } + fmt_float(fi, k, bits/4, verb); + write_rune(fi.buf, 'k'); + + default: + fmt_bad_verb(fi, verb); + return; + } +} + fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) { if arg.data == nil || arg.type_info == nil { write_string(fi.buf, ""); @@ -927,11 +960,13 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) { base_arg := arg; base_arg.type_info = type_info_base(base_arg.type_info); match a in base_arg { - case bool: fmt_bool(fi, a, verb); - case f32: fmt_float(fi, cast(f64)a, 32, verb); - case f64: fmt_float(fi, a, 64, verb); - case complex64: fmt_complex(fi, cast(complex128)a, 64, verb); - case complex128: fmt_complex(fi, a, 128, verb); + case bool: fmt_bool(fi, a, verb); + case f32: fmt_float(fi, cast(f64)a, 32, verb); + case f64: fmt_float(fi, a, 64, verb); + case complex64: fmt_complex(fi, cast(complex128)a, 64, verb); + case complex128: fmt_complex(fi, a, 128, verb); + case quaternion128: fmt_quaternion(fi, cast(quaternion256)a, 128, verb); + case quaternion256: fmt_quaternion(fi, a, 256, verb); case int: fmt_int(fi, cast(u64)a, true, 8*size_of(int), verb); case i8: fmt_int(fi, cast(u64)a, true, 8, verb); diff --git a/core/math.odin b/core/math.odin index 15a445831..b52855746 100644 --- a/core/math.odin +++ b/core/math.odin @@ -43,8 +43,8 @@ pow :: proc(x, power: f64) -> f64 #foreign __llvm_core "llvm.pow.f64"; lerp :: proc(a, b, t: f32) -> f32 { return a*(1-t) + b*t; } lerp :: proc(a, b, t: f64) -> f64 { return a*(1-t) + b*t; } -sign :: proc(x: f32) -> f32 { if x >= 0 { return +1; } return -1; } -sign :: proc(x: f64) -> f64 { if x >= 0 { return +1; } return -1; } +sign :: proc(x: f32) -> f32 { return x >= 0 ? +1 : -1; } +sign :: proc(x: f64) -> f64 { return x >= 0 ? +1 : -1; } bit_reverse :: proc(b: u16) -> u16 #foreign __llvm_core "llvm.bitreverse.i16"; bit_reverse :: proc(b: u32) -> u32 #foreign __llvm_core "llvm.bitreverse.i32"; diff --git a/core/types.odin b/core/types.odin index c541aaac5..459af5752 100644 --- a/core/types.odin +++ b/core/types.odin @@ -1,146 +1,100 @@ is_signed :: proc(info: ^Type_Info) -> bool { - if is_integer(info) { - i := union_cast(^Type_Info.Integer)info; + info = type_info_base(info); + if i, ok := union_cast(^Type_Info.Integer)info; ok { return i.signed; } - if is_float(info) { + if _, ok := union_cast(^Type_Info.Float)info; ok { return true; } return false; } is_integer :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - - match i in type_info_base(info) { - case Type_Info.Integer: return true; - } - return false; + _, ok := union_cast(^Type_Info.Integer)type_info_base(info); + return ok; } is_float :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - - match i in type_info_base(info) { - case Type_Info.Float: return true; - } - return false; + _, ok := union_cast(^Type_Info.Float)type_info_base(info); + return ok; +} +is_complex :: proc(info: ^Type_Info) -> bool { + if info == nil { return false; } + _, ok := union_cast(^Type_Info.Complex)type_info_base(info); + return ok; } is_any :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - - match i in type_info_base(info) { - case Type_Info.Any: return true; - } - return false; + _, ok := union_cast(^Type_Info.Any)type_info_base(info); + return ok; } is_string :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - - match i in type_info_base(info) { - case Type_Info.String: return true; - } - return false; + _, ok := union_cast(^Type_Info.String)type_info_base(info); + return ok; } is_boolean :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - - match i in type_info_base(info) { - case Type_Info.Boolean: return true; - } - return false; + _, ok := union_cast(^Type_Info.Boolean)type_info_base(info); + return ok; } is_pointer :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - - match i in type_info_base(info) { - case Type_Info.Pointer: return true; - } - return false; + _, ok := union_cast(^Type_Info.Pointer)type_info_base(info); + return ok; } is_procedure :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - - match i in type_info_base(info) { - case Type_Info.Procedure: return true; - } - return false; + _, ok := union_cast(^Type_Info.Procedure)type_info_base(info); + return ok; } is_array :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - - match i in type_info_base(info) { - case Type_Info.Array: return true; - } - return false; + _, ok := union_cast(^Type_Info.Array)type_info_base(info); + return ok; } is_dynamic_array :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - - match i in type_info_base(info) { - case Type_Info.Dynamic_Array: return true; - } - return false; + _, ok := union_cast(^Type_Info.Dynamic_Array)type_info_base(info); + return ok; } is_dynamic_map :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - - match i in type_info_base(info) { - case Type_Info.Map: return i.count == 0; - } - return false; + _, ok := union_cast(^Type_Info.Map)type_info_base(info); + return ok; } is_slice :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - - match i in type_info_base(info) { - case Type_Info.Slice: return true; - } - return false; + _, ok := union_cast(^Type_Info.Slice)type_info_base(info); + return ok; } is_vector :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - - match i in type_info_base(info) { - case Type_Info.Vector: return true; - } - return false; + _, ok := union_cast(^Type_Info.Vector)type_info_base(info); + return ok; } is_tuple :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - - match i in type_info_base(info) { - case Type_Info.Tuple: return true; - } - return false; + _, ok := union_cast(^Type_Info.Tuple)type_info_base(info); + return ok; } is_struct :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - - match i in type_info_base(info) { - case Type_Info.Struct: return true; - } - return false; + _, ok := union_cast(^Type_Info.Struct)type_info_base(info); + return ok; } is_union :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - - match i in type_info_base(info) { - case Type_Info.Union: return true; - } - return false; + _, ok := union_cast(^Type_Info.Union)type_info_base(info); + return ok; } is_raw_union :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - - match i in type_info_base(info) { - case Type_Info.Raw_Union: return true; - } - return false; + _, ok := union_cast(^Type_Info.Raw_Union)type_info_base(info); + return ok; } is_enum :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - - match i in type_info_base(info) { - case Type_Info.Enum: return true; - } - return false; + _, ok := union_cast(^Type_Info.Enum)type_info_base(info); + return ok; } diff --git a/src/check_expr.c b/src/check_expr.c index 8c162e034..55dcdb941 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -1782,10 +1782,41 @@ bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type return true; } } break; + case Basic_UntypedComplex: + return true; + } + + 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 && + jmag.kind != ExactValue_Invalid && + kmag.kind != ExactValue_Invalid) { + ExactValue ov = exact_binary_operator_value(Token_Add, real, exact_value_make_imag(imag)); + ov = exact_binary_operator_value(Token_Add, ov, exact_value_make_jmag(jmag)); + ov = exact_binary_operator_value(Token_Add, ov, exact_value_make_kmag(kmag)); + if (out_value) *out_value = ov; + return true; + } + } break; + case Basic_UntypedQuaternion: + return true; } return false; - } else if (is_type_pointer(type)) { + }else if (is_type_pointer(type)) { if (in_value.kind == ExactValue_Pointer) { return true; } @@ -2213,6 +2244,10 @@ bool check_is_castable_to(Checker *c, Operand *operand, Type *y) { return true; } + if (is_type_quaternion(src) && is_type_quaternion(dst)) { + return true; + } + // Cast between pointers if (is_type_pointer(src) && is_type_pointer(dst)) { Type *s = base_type(type_deref(src)); @@ -2613,6 +2648,8 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type, i32 level break; 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; @@ -3605,44 +3642,24 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id return false; } - u32 flag = 0; - if (is_type_untyped(x.type)) { - flag |= 1; - } - if (is_type_untyped(y.type)) { - flag |= 2; - } - switch (flag) { - case 0: break; - case 1: convert_to_typed(c, &x, y.type, 0); break; - case 2: convert_to_typed(c, &y, x.type, 0); break; - case 3: { - if (x.mode == Addressing_Constant && y.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; - } - } else { - convert_to_typed(c, &x, t_f64, 0); - convert_to_typed(c, &y, t_f64, 0); + convert_to_typed(c, &x, y.type, 0); if (x.mode == Addressing_Invalid) return false; + convert_to_typed(c, &y, x.type, 0); if (y.mode == Addressing_Invalid) return false; + if (x.mode == Addressing_Constant && + y.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; } - } break; - } - - if (x.mode == Addressing_Invalid || y.mode == Addressing_Invalid) { - return false; } if (!are_types_identical(x.type, y.type)) { - gbString type_x = type_to_string(x.type); - gbString type_y = type_to_string(y.type); - error_node(call, - "Mismatched types to `complex`, `%s` vs `%s`", - type_x, type_y); - gb_string_free(type_y); - gb_string_free(type_x); + gbString tx = type_to_string(x.type); + gbString ty = type_to_string(y.type); + error_node(call, "Mismatched types to `complex`, `%s` vs `%s`", tx, ty); + gb_string_free(ty); + gb_string_free(tx); return false; } @@ -3669,37 +3686,170 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id } } break; + case BuiltinProc_quaternion: { + // quaternion :: proc(real, imag, jmag, kmag: float_type) -> quaternion_type + Operand x = *operand; + Operand y = {0}; + Operand z = {0}; + Operand w = {0}; + + GB_PANIC("BuiltinProc_quaternion"); + + // NOTE(bill): Invalid will be the default till fixed + operand->type = t_invalid; + operand->mode = Addressing_Invalid; + + check_expr(c, &y, ce->args.e[1]); if (y.mode == Addressing_Invalid) return false; + check_expr(c, &z, ce->args.e[2]); if (z.mode == Addressing_Invalid) return false; + check_expr(c, &w, ce->args.e[3]); if (w.mode == Addressing_Invalid) return false; + + convert_to_typed(c, &x, y.type, 0); if (x.mode == Addressing_Invalid) return false; + convert_to_typed(c, &x, z.type, 0); if (x.mode == Addressing_Invalid) return false; + convert_to_typed(c, &x, w.type, 0); if (x.mode == Addressing_Invalid) return false; + + convert_to_typed(c, &y, z.type, 0); if (y.mode == Addressing_Invalid) return false; + convert_to_typed(c, &y, w.type, 0); if (y.mode == Addressing_Invalid) return false; + convert_to_typed(c, &y, x.type, 0); if (y.mode == Addressing_Invalid) return false; + + convert_to_typed(c, &z, y.type, 0); if (z.mode == Addressing_Invalid) return false; + convert_to_typed(c, &z, w.type, 0); if (z.mode == Addressing_Invalid) return false; + convert_to_typed(c, &z, x.type, 0); if (z.mode == Addressing_Invalid) return false; + + convert_to_typed(c, &w, x.type, 0); if (w.mode == Addressing_Invalid) return false; + convert_to_typed(c, &w, y.type, 0); if (w.mode == Addressing_Invalid) return false; + convert_to_typed(c, &w, z.type, 0); 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 && + exact_value_jmag(x.value).value_float == 0 && + exact_value_kmag(x.value).value_float == 0) { + x.type = t_untyped_float; + } + if (is_type_numeric(y.type) && + exact_value_imag(y.value).value_float == 0 && + exact_value_jmag(y.value).value_float == 0 && + exact_value_kmag(y.value).value_float == 0) { + y.type = t_untyped_float; + } + if (is_type_numeric(z.type) && + exact_value_imag(z.value).value_float == 0 && + exact_value_jmag(z.value).value_float == 0 && + exact_value_kmag(z.value).value_float == 0) { + z.type = t_untyped_float; + } + if (is_type_numeric(w.type) && + exact_value_imag(w.value).value_float == 0 && + exact_value_jmag(w.value).value_float == 0 && + exact_value_kmag(w.value).value_float == 0) { + w.type = t_untyped_float; + } + } + + if (!are_types_identical(x.type, y.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_node(call, "Mismatched types to `complex`, `%s`, `%s` `%s`, `%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_node(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) { + ExactValue v = exact_binary_operator_value(Token_Add, x.value, y.value); + v = exact_binary_operator_value(Token_Add, v, z.value); + v = exact_binary_operator_value(Token_Add, v, w.value); + operand->value = v; + operand->mode = Addressing_Constant; + } else { + operand->mode = Addressing_Value; + } + + BasicKind kind = core_type(x.type)->Basic.kind; + switch (kind) { + case Basic_complex64: x.type = t_f32; break; + case Basic_complex128: x.type = t_f64; break; + case Basic_UntypedComplex: x.type = t_untyped_float; break; + case Basic_quaternion128: x.type = t_f32; break; + case Basic_quaternion256: x.type = t_f64; break; + case Basic_UntypedQuaternion: x.type = t_untyped_float; break; + default: GB_PANIC("Invalid type"); break; + } + } break; + case BuiltinProc_real: - case BuiltinProc_imag: { - // real :: proc(c: complex_type) -> float_type - // imag :: proc(c: complex_type) -> float_type + case BuiltinProc_imag: + case BuiltinProc_jmag: + case BuiltinProc_kmag: { + // real :: proc(x: type) -> float_type + // imag :: proc(x: type) -> float_type + // 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; + if (id == BuiltinProc_jmag || + id == BuiltinProc_kmag) { + x->type = t_untyped_quaternion; + } else { + x->type = t_untyped_complex; + } } } else { - convert_to_typed(c, x, t_complex128, 0); + if (id == BuiltinProc_jmag || + id == BuiltinProc_kmag) { + convert_to_typed(c, x, t_quaternion256, 0); + } else { + convert_to_typed(c, x, t_complex128, 0); + } if (x->mode == Addressing_Invalid) { return false; } } } - if (!is_type_complex(x->type)) { - gbString s = type_to_string(x->type); - error_node(call, "Argument has type `%s`, expected a complex type", s); - gb_string_free(s); - return false; + if (id == BuiltinProc_jmag || + id == BuiltinProc_kmag) { + if (!is_type_quaternion(x->type)) { + gbString s = type_to_string(x->type); + error_node(call, "Argument has type `%s`, expected a complex type", s); + gb_string_free(s); + return false; + } + } else { + if (!is_type_complex(x->type) && !is_type_quaternion(x->type)) { + gbString s = type_to_string(x->type); + error_node(call, "Argument has type `%s`, expected a complex or quaternion type", s); + gb_string_free(s); + return false; + } } if (x->mode == Addressing_Constant) { - if (id == BuiltinProc_real) { - x->value = exact_value_real(x->value); - } else { - x->value = exact_value_imag(x->value); + switch (id) { + case BuiltinProc_real: x->value = exact_value_real(x->value); break; + case BuiltinProc_imag: x->value = exact_value_imag(x->value); break; + 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; @@ -3707,13 +3857,50 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id BasicKind kind = core_type(x->type)->Basic.kind; switch (kind) { - case Basic_complex64: x->type = t_f32; break; - case Basic_complex128: x->type = t_f64; break; - case Basic_UntypedComplex: x->type = t_untyped_float; break; + case Basic_complex64: x->type = t_f32; break; + case Basic_complex128: x->type = t_f64; break; + case Basic_UntypedComplex: x->type = t_untyped_float; break; + case Basic_quaternion128: x->type = t_f32; break; + case Basic_quaternion256: x->type = t_f64; break; + case Basic_UntypedQuaternion: x->type = t_untyped_float; break; default: GB_PANIC("Invalid type"); break; } } break; + case BuiltinProc_conj: { + // conj :: proc(x: type) -> type + Operand *x = operand; + if (is_type_complex(x->type)) { + 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; + 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_node(call, "Expected a complex or quaternion, got `%s`", s); + gb_string_free(s); + return false; + } + + } break; + case BuiltinProc_slice_ptr: { // slice_ptr :: proc(a: ^T, len: int) -> []T // slice_ptr :: proc(a: ^T, len, cap: int) -> []T @@ -3721,16 +3908,13 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id Type *ptr_type = base_type(operand->type); if (!is_type_pointer(ptr_type)) { gbString type_str = type_to_string(operand->type); - error_node(call, - "Expected a pointer to `slice_ptr`, got `%s`", - type_str); + error_node(call, "Expected a pointer to `slice_ptr`, got `%s`", type_str); gb_string_free(type_str); return false; } if (ptr_type == t_rawptr) { - error_node(call, - "`rawptr` cannot have pointer arithmetic"); + error_node(call, "`rawptr` cannot have pointer arithmetic"); return false; } @@ -3775,11 +3959,11 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id } break; case BuiltinProc_min: { - // min :: proc(a, b: comparable) -> comparable + // min :: proc(a, b: ordered) -> ordered Type *type = base_type(operand->type); - if (!is_type_comparable(type) || !(is_type_numeric(type) || is_type_string(type))) { + if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) { gbString type_str = type_to_string(operand->type); - error_node(call, "Expected a comparable numeric type to `min`, got `%s`", type_str); + error_node(call, "Expected a ordered numeric type to `min`, got `%s`", type_str); gb_string_free(type_str); return false; } @@ -3791,10 +3975,10 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id if (b.mode == Addressing_Invalid) { return false; } - if (!is_type_comparable(b.type) || !(is_type_numeric(b.type) || is_type_string(b.type))) { + if (!is_type_ordered(b.type) || !(is_type_numeric(b.type) || is_type_string(b.type))) { gbString type_str = type_to_string(b.type); error_node(call, - "Expected a comparable numeric type to `min`, got `%s`", + "Expected a ordered numeric type to `min`, got `%s`", type_str); gb_string_free(type_str); return false; @@ -3841,12 +4025,12 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id } break; case BuiltinProc_max: { - // min :: proc(a, b: comparable) -> comparable + // min :: proc(a, b: ordered) -> ordered Type *type = base_type(operand->type); - if (!is_type_comparable(type) || !(is_type_numeric(type) || is_type_string(type))) { + if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) { gbString type_str = type_to_string(operand->type); error_node(call, - "Expected a comparable numeric or string type to `max`, got `%s`", + "Expected a ordered numeric or string type to `max`, got `%s`", type_str); gb_string_free(type_str); return false; @@ -3859,10 +4043,10 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id if (b.mode == Addressing_Invalid) { return false; } - if (!is_type_comparable(b.type) || !(is_type_numeric(b.type) || is_type_string(b.type))) { + if (!is_type_ordered(b.type) || !(is_type_numeric(b.type) || is_type_string(b.type))) { gbString type_str = type_to_string(b.type); error_node(call, - "Expected a comparable numeric or string type to `max`, got `%s`", + "Expected a ordered numeric or string type to `max`, got `%s`", type_str); gb_string_free(type_str); return false; @@ -3910,12 +4094,9 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id case BuiltinProc_abs: { // abs :: proc(n: numeric) -> numeric - Type *type = base_type(operand->type); - if (!is_type_numeric(type)) { + if (!is_type_numeric(operand->type) && !is_type_vector(operand->type)) { gbString type_str = type_to_string(operand->type); - error_node(call, - "Expected a numeric type to `abs`, got `%s`", - type_str); + error_node(call, "Expected a numeric type to `abs`, got `%s`", type_str); gb_string_free(type_str); return false; } @@ -3928,6 +4109,18 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id case ExactValue_Float: operand->value.value_float = gb_abs(operand->value.value_float); break; + case ExactValue_Complex: { + f64 r = operand->value.value_complex.real; + f64 i = operand->value.value_complex.imag; + operand->value = exact_value_float(gb_sqrt(r*r + i*i)); + } break; + case ExactValue_Quaternion: { + f64 r = operand->value.value_complex.real; + f64 i = operand->value.value_complex.imag; + f64 j = operand->value.value_complex.imag; + f64 k = operand->value.value_complex.imag; + operand->value = exact_value_float(gb_sqrt(r*r + i*i + j*j + k*k)); + } break; default: GB_PANIC("Invalid numeric constant"); break; @@ -3936,17 +4129,20 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id operand->mode = Addressing_Value; } - operand->type = type; + if (is_type_complex(operand->type)) { + operand->type = base_complex_elem_type(operand->type); + } else if (is_type_quaternion(operand->type)) { + operand->type = base_quaternion_elem_type(operand->type); + } + GB_ASSERT(!is_type_complex(operand->type) && !is_type_quaternion(operand->type)); } break; case BuiltinProc_clamp: { - // clamp :: proc(a, min, max: comparable) -> comparable + // clamp :: proc(a, min, max: ordered) -> ordered Type *type = base_type(operand->type); - if (!is_type_comparable(type) || !(is_type_numeric(type) || is_type_string(type))) { + if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) { gbString type_str = type_to_string(operand->type); - error_node(call, - "Expected a comparable numeric or string type to `clamp`, got `%s`", - type_str); + error_node(call, "Expected a ordered numeric or string type to `clamp`, got `%s`", type_str); gb_string_free(type_str); return false; } @@ -3961,11 +4157,9 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id if (y.mode == Addressing_Invalid) { return false; } - if (!is_type_comparable(y.type) || !(is_type_numeric(y.type) || is_type_string(y.type))) { + if (!is_type_ordered(y.type) || !(is_type_numeric(y.type) || is_type_string(y.type))) { gbString type_str = type_to_string(y.type); - error_node(call, - "Expected a comparable numeric or string type to `clamp`, got `%s`", - type_str); + error_node(call, "Expected a ordered numeric or string type to `clamp`, got `%s`", type_str); gb_string_free(type_str); return false; } @@ -3974,11 +4168,9 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id if (z.mode == Addressing_Invalid) { return false; } - if (!is_type_comparable(z.type) || !(is_type_numeric(z.type) || is_type_string(z.type))) { + if (!is_type_ordered(z.type) || !(is_type_numeric(z.type) || is_type_string(z.type))) { gbString type_str = type_to_string(z.type); - error_node(call, - "Expected a comparable numeric or string type to `clamp`, got `%s`", - type_str); + error_node(call, "Expected a ordered numeric or string type to `clamp`, got `%s`", type_str); gb_string_free(type_str); return false; } @@ -4551,9 +4743,18 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t switch (bl->kind) { case Token_Integer: t = t_untyped_integer; break; case Token_Float: t = t_untyped_float; break; - case Token_Imag: t = t_untyped_complex; break; case Token_String: t = t_untyped_string; break; case Token_Rune: t = t_untyped_rune; break; + case Token_Imag: { + String s = bl->string; + Rune r = s.text[s.len-1]; + switch (r) { + case 'i': t = t_untyped_complex; break; + case 'j': case 'k': + t = t_untyped_quaternion; + break; + } + } break; default: GB_PANIC("Unknown literal"); break; } o->mode = Addressing_Constant; diff --git a/src/checker.c b/src/checker.c index 5f1352a29..c594bbe8a 100644 --- a/src/checker.c +++ b/src/checker.c @@ -53,8 +53,12 @@ typedef enum BuiltinProcId { BuiltinProc_swizzle, BuiltinProc_complex, + BuiltinProc_quaternion, BuiltinProc_real, BuiltinProc_imag, + BuiltinProc_jmag, + BuiltinProc_kmag, + BuiltinProc_conj, // BuiltinProc_ptr_offset, // BuiltinProc_ptr_sub, @@ -101,8 +105,12 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = { {STR_LIT("swizzle"), 1, true, Expr_Expr}, {STR_LIT("complex"), 2, false, Expr_Expr}, + {STR_LIT("quaternion"), 4, false, Expr_Expr}, {STR_LIT("real"), 1, false, Expr_Expr}, {STR_LIT("imag"), 1, false, Expr_Expr}, + {STR_LIT("jmag"), 1, false, Expr_Expr}, + {STR_LIT("kmag"), 1, false, Expr_Expr}, + {STR_LIT("conj"), 1, false, Expr_Expr}, // {STR_LIT("ptr_offset"), 2, false, Expr_Expr}, // {STR_LIT("ptr_sub"), 2, false, Expr_Expr}, @@ -957,6 +965,15 @@ void add_type_info_type(Checker *c, Type *t) { add_type_info_type(c, t_type_info_float); add_type_info_type(c, t_f64); break; + + case Basic_quaternion128: + add_type_info_type(c, t_type_info_float); + add_type_info_type(c, t_f32); + break; + case Basic_quaternion256: + add_type_info_type(c, t_type_info_float); + add_type_info_type(c, t_f64); + break; } } break; @@ -1145,33 +1162,35 @@ void init_preload(Checker *c) { - if (record->variant_count != 20) { + if (record->variant_count != 21) { compiler_error("Invalid `Type_Info` layout"); } t_type_info_named = record->variants[ 1]->type; t_type_info_integer = record->variants[ 2]->type; t_type_info_float = record->variants[ 3]->type; t_type_info_complex = record->variants[ 4]->type; - t_type_info_string = record->variants[ 5]->type; - t_type_info_boolean = record->variants[ 6]->type; - t_type_info_any = record->variants[ 7]->type; - t_type_info_pointer = record->variants[ 8]->type; - t_type_info_procedure = record->variants[ 9]->type; - t_type_info_array = record->variants[10]->type; - t_type_info_dynamic_array = record->variants[11]->type; - t_type_info_slice = record->variants[12]->type; - t_type_info_vector = record->variants[13]->type; - t_type_info_tuple = record->variants[14]->type; - t_type_info_struct = record->variants[15]->type; - t_type_info_raw_union = record->variants[16]->type; - t_type_info_union = record->variants[17]->type; - t_type_info_enum = record->variants[18]->type; - t_type_info_map = record->variants[19]->type; + t_type_info_quaternion = record->variants[ 5]->type; + t_type_info_string = record->variants[ 6]->type; + t_type_info_boolean = record->variants[ 7]->type; + t_type_info_any = record->variants[ 8]->type; + t_type_info_pointer = record->variants[ 9]->type; + t_type_info_procedure = record->variants[10]->type; + t_type_info_array = record->variants[11]->type; + t_type_info_dynamic_array = record->variants[12]->type; + t_type_info_slice = record->variants[13]->type; + t_type_info_vector = record->variants[14]->type; + t_type_info_tuple = record->variants[15]->type; + t_type_info_struct = record->variants[16]->type; + t_type_info_raw_union = record->variants[17]->type; + t_type_info_union = record->variants[18]->type; + t_type_info_enum = record->variants[19]->type; + t_type_info_map = record->variants[20]->type; t_type_info_named_ptr = make_type_pointer(c->allocator, t_type_info_named); t_type_info_integer_ptr = make_type_pointer(c->allocator, t_type_info_integer); t_type_info_float_ptr = make_type_pointer(c->allocator, t_type_info_float); t_type_info_complex_ptr = make_type_pointer(c->allocator, t_type_info_complex); + t_type_info_quaternion_ptr = make_type_pointer(c->allocator, t_type_info_quaternion); t_type_info_string_ptr = make_type_pointer(c->allocator, t_type_info_string); t_type_info_boolean_ptr = make_type_pointer(c->allocator, t_type_info_boolean); t_type_info_any_ptr = make_type_pointer(c->allocator, t_type_info_any); diff --git a/src/common.c b/src/common.c index 2c40e22ed..fe07dc175 100644 --- a/src/common.c +++ b/src/common.c @@ -2,6 +2,8 @@ #define GB_IMPLEMENTATION #include "gb/gb.h" +#include + gbAllocator heap_allocator(void) { return gb_heap_allocator(); } @@ -104,6 +106,10 @@ i16 f32_to_f16(f32 value) { } } +f64 gb_sqrt(f64 x) { + return sqrt(x); +} + #define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++) diff --git a/src/exact_value.c b/src/exact_value.c index f1da88fc6..eec5d157a 100644 --- a/src/exact_value.c +++ b/src/exact_value.c @@ -5,6 +5,14 @@ typedef struct AstNode AstNode; +typedef struct Complex128 { + f64 real, imag; +} Complex128; + +typedef struct Quaternion256 { + f64 real, imag, jmag, kmag; +} Quaternion256; + typedef enum ExactValueKind { ExactValue_Invalid, @@ -13,26 +21,24 @@ typedef enum ExactValueKind { ExactValue_Integer, ExactValue_Float, ExactValue_Complex, + ExactValue_Quaternion, ExactValue_Pointer, ExactValue_Compound, // TODO(bill): Is this good enough? ExactValue_Count, } ExactValueKind; -typedef struct Complex128 { - f64 real, imag; -} Complex128; - typedef struct ExactValue { ExactValueKind kind; union { - bool value_bool; - String value_string; - i64 value_integer; // NOTE(bill): This must be an integer and not a pointer - f64 value_float; - i64 value_pointer; - Complex128 value_complex; - AstNode * value_compound; + bool value_bool; + String value_string; + i64 value_integer; // NOTE(bill): This must be an integer and not a pointer + f64 value_float; + i64 value_pointer; + Complex128 value_complex; + Quaternion256 value_quaternion; + AstNode * value_compound; }; } ExactValue; @@ -79,6 +85,16 @@ 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; @@ -216,9 +232,15 @@ ExactValue exact_value_from_basic_literal(Token token) { case Token_Float: return exact_value_float_from_string(token.string); case Token_Imag: { String str = token.string; - str.len--; // Ignore the `i` + Rune last_rune = cast(Rune)str.text[str.len-1]; + str.len--; // Ignore the `i|j|k` f64 imag = float_from_string(str); - 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: { Rune r = GB_RUNE_INVALID; @@ -278,6 +300,23 @@ ExactValue exact_value_to_complex(ExactValue v) { return r; } + +ExactValue exact_value_to_quaternion(ExactValue v) { + switch (v.kind) { + case ExactValue_Integer: + return exact_value_quaternion(cast(i64)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) { case ExactValue_Integer: @@ -285,6 +324,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; @@ -297,11 +338,39 @@ ExactValue exact_value_imag(ExactValue v) { return exact_value_integer(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_integer(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_integer(0); + case ExactValue_Quaternion: + return exact_value_float(v.value_quaternion.kmag); + } + ExactValue r = {ExactValue_Invalid}; + return r; +} + + ExactValue exact_value_make_imag(ExactValue v) { switch (v.kind) { case ExactValue_Integer: @@ -314,6 +383,30 @@ ExactValue exact_value_make_imag(ExactValue v) { ExactValue r = {ExactValue_Invalid}; 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_jmag`"); + } + 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_kmag`"); + } + ExactValue r = {ExactValue_Invalid}; + return r; +} @@ -325,6 +418,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; @@ -348,6 +442,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; @@ -403,8 +504,10 @@ i32 exact_value_order(ExactValue 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"); @@ -426,6 +529,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: @@ -439,15 +543,22 @@ void match_exact_values(ExactValue *x, ExactValue *y) { case ExactValue_Complex: *x = exact_value_complex(cast(f64)x->value_integer, 0); return; + case ExactValue_Quaternion: + *x = exact_value_quaternion(cast(f64)x->value_integer, 0, 0, 0); + return; } break; case ExactValue_Float: - if (y->kind == ExactValue_Float) { + switch (y->kind) { + case ExactValue_Float: return; - } else if (y->kind == ExactValue_Complex) { + case ExactValue_Complex: *x = exact_value_to_complex(*x); return; + case ExactValue_Quaternion: + *x = exact_value_to_quaternion(*x); + return; } break; } @@ -538,6 +649,53 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y) } return exact_value_complex(real, imag); } break; + + case ExactValue_Quaternion: { + y = exact_value_to_quaternion(y); + f64 a = x.value_quaternion.real; + f64 b = x.value_quaternion.imag; + f64 c = x.value_quaternion.jmag; + f64 d = x.value_quaternion.kmag; + + f64 e = x.value_quaternion.real; + f64 f = x.value_quaternion.imag; + f64 g = x.value_quaternion.jmag; + f64 h = x.value_quaternion.kmag; + + f64 real = 0; + f64 imag = 0; + f64 jmag = 0; + f64 kmag = 0; + switch (op) { + case Token_Add: + real = a + e; + imag = b + f; + jmag = c + g; + kmag = d + h; + break; + case Token_Sub: + real = a - e; + imag = b - f; + jmag = c - g; + kmag = d - h; + break; + case Token_Mul: + real = a*f + b*e + c*h - d*g; + imag = a*g - b*h + c*e + d*f; + jmag = a*h + b*g - c*f + d*e; + kmag = a*e - b*f - c*g - d*h; + break; + case Token_Quo: { + f64 s = e*e + f*f + g*g + h*h; + real = (+a*e + b*f + c*g + d*h)/s; + imag = (-a*f + b*e - c*h + d*h)/s; + jmag = (-a*g + b*h + c*e - d*f)/s; + kmag = (-a*h - b*g + c*f + d*e)/s; + } break; + default: goto error; + } + return exact_value_quaternion(real, imag, jmag, kmag); + } break; } error: @@ -609,6 +767,23 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) { } } break; + case ExactValue_Quaternion: { + f64 a = x.value_quaternion.real; + f64 b = x.value_quaternion.imag; + f64 c = x.value_quaternion.jmag; + f64 d = x.value_quaternion.kmag; + + f64 e = y.value_quaternion.real; + f64 f = y.value_quaternion.imag; + f64 g = y.value_quaternion.jmag; + f64 h = y.value_quaternion.kmag; + + switch (op) { + case Token_CmpEq: return cmp_f64(a, e) == 0 && cmp_f64(b, f) == 0 && cmp_f64(c, g) == 0 && cmp_f64(d, h) == 0; + case Token_NotEq: return cmp_f64(a, e) != 0 || cmp_f64(b, f) != 0 || cmp_f64(c, g) != 0 || cmp_f64(d, h) != 0; + } + } break; + case ExactValue_String: { String a = x.value_string; String b = y.value_string; diff --git a/src/ir.c b/src/ir.c index b5e01ee34..374aea0a2 100644 --- a/src/ir.c +++ b/src/ir.c @@ -1351,6 +1351,7 @@ irValue *ir_emit_store(irProcedure *p, irValue *address, irValue *value) { return ir_emit(p, ir_instr_store(p, address, value)); } irValue *ir_emit_load(irProcedure *p, irValue *address) { + GB_ASSERT(address != NULL); return ir_emit(p, ir_instr_load(p, address)); } irValue *ir_emit_select(irProcedure *p, irValue *cond, irValue *t, irValue *f) { @@ -1719,11 +1720,7 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue * if (is_type_complex(t_left)) { ir_emit_comment(proc, str_lit("complex.arith.begin")); - Type *tl = core_type(t_left); - Type *ft = t_f32; - if (tl->Basic.kind == Basic_complex128) { - ft = t_f64; - } + Type *ft = base_complex_elem_type(t_left); irValue *res = ir_add_local_generated(proc, type); irValue *a = ir_emit_struct_ev(proc, left, 0); @@ -1773,6 +1770,126 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue * ir_emit_comment(proc, str_lit("complex.end.begin")); return ir_emit_load(proc, res); + } else if (is_type_quaternion(t_left)) { + ir_emit_comment(proc, str_lit("quaternion.arith.begin")); + Type *ft = base_quaternion_elem_type(t_left); + + irValue *res = ir_add_local_generated(proc, type); + irValue *a = ir_emit_struct_ev(proc, left, 0); + irValue *b = ir_emit_struct_ev(proc, left, 1); + irValue *c = ir_emit_struct_ev(proc, left, 2); + irValue *d = ir_emit_struct_ev(proc, left, 3); + + irValue *e = ir_emit_struct_ev(proc, right, 0); + irValue *f = ir_emit_struct_ev(proc, right, 1); + irValue *g = ir_emit_struct_ev(proc, right, 2); + irValue *h = ir_emit_struct_ev(proc, right, 3); + + irValue *real = NULL; + irValue *imag = NULL; + irValue *jmag = NULL; + irValue *kmag = NULL; + + switch (op) { + case Token_Add: + real = ir_emit_arith(proc, Token_Add, a, e, ft); + imag = ir_emit_arith(proc, Token_Add, b, f, ft); + jmag = ir_emit_arith(proc, Token_Add, c, g, ft); + kmag = ir_emit_arith(proc, Token_Add, d, h, ft); + break; + case Token_Sub: + real = ir_emit_arith(proc, Token_Sub, a, e, ft); + imag = ir_emit_arith(proc, Token_Sub, b, f, ft); + jmag = ir_emit_arith(proc, Token_Sub, c, g, ft); + kmag = ir_emit_arith(proc, Token_Sub, d, h, ft); + break; + case Token_Mul: { + irValue *r0 = ir_emit_arith(proc, Token_Mul, a, e, ft); + irValue *r1 = ir_emit_arith(proc, Token_Mul, b, f, ft); + irValue *r2 = ir_emit_arith(proc, Token_Mul, c, h, ft); + irValue *r3 = ir_emit_arith(proc, Token_Mul, d, g, ft); + real = ir_emit_arith(proc, Token_Add, r0, r1, ft); + real = ir_emit_arith(proc, Token_Add, real, r2, ft); + real = ir_emit_arith(proc, Token_Add, real, r3, ft); + + irValue *i0 = ir_emit_arith(proc, Token_Mul, a, g, ft); + irValue *i1 = ir_emit_arith(proc, Token_Mul, b, h, ft); + irValue *i2 = ir_emit_arith(proc, Token_Mul, c, e, ft); + irValue *i3 = ir_emit_arith(proc, Token_Mul, d, f, ft); + imag = ir_emit_arith(proc, Token_Sub, i0, i1, ft); + imag = ir_emit_arith(proc, Token_Add, imag, i2, ft); + imag = ir_emit_arith(proc, Token_Add, imag, i3, ft); + + irValue *j0 = ir_emit_arith(proc, Token_Mul, a, h, ft); + irValue *j1 = ir_emit_arith(proc, Token_Mul, b, g, ft); + irValue *j2 = ir_emit_arith(proc, Token_Mul, c, f, ft); + irValue *j3 = ir_emit_arith(proc, Token_Mul, d, e, ft); + jmag = ir_emit_arith(proc, Token_Add, j0, j1, ft); + jmag = ir_emit_arith(proc, Token_Sub, imag, j2, ft); + jmag = ir_emit_arith(proc, Token_Sub, imag, j3, ft); + + irValue *k0 = ir_emit_arith(proc, Token_Mul, a, e, ft); + irValue *k1 = ir_emit_arith(proc, Token_Mul, b, f, ft); + irValue *k2 = ir_emit_arith(proc, Token_Mul, c, g, ft); + irValue *k3 = ir_emit_arith(proc, Token_Mul, d, h, ft); + kmag = ir_emit_arith(proc, Token_Sub, j0, j1, ft); + kmag = ir_emit_arith(proc, Token_Sub, imag, j2, ft); + kmag = ir_emit_arith(proc, Token_Sub, imag, j3, ft); + } break; + case Token_Quo: { + irValue *s0 = ir_emit_arith(proc, Token_Mul, e, e, ft); + irValue *s1 = ir_emit_arith(proc, Token_Mul, f, f, ft); + irValue *s2 = ir_emit_arith(proc, Token_Mul, g, g, ft); + irValue *s3 = ir_emit_arith(proc, Token_Mul, h, h, ft); + irValue *s = ir_emit_arith(proc, Token_Add, s0, s1, ft); + s = ir_emit_arith(proc, Token_Add, s, s2, ft); + s = ir_emit_arith(proc, Token_Add, s, s3, ft); + + irValue *r0 = ir_emit_arith(proc, Token_Mul, a, e, ft); + irValue *r1 = ir_emit_arith(proc, Token_Mul, b, f, ft); + irValue *r2 = ir_emit_arith(proc, Token_Mul, c, h, ft); + irValue *r3 = ir_emit_arith(proc, Token_Mul, d, g, ft); + real = ir_emit_arith(proc, Token_Add, r0, r1, ft); + real = ir_emit_arith(proc, Token_Add, real, r2, ft); + real = ir_emit_arith(proc, Token_Add, real, r3, ft); + real = ir_emit_arith(proc, Token_Quo, real, s, ft); + + irValue *i0 = ir_emit_arith(proc, Token_Mul, a, f, ft); + irValue *i1 = ir_emit_arith(proc, Token_Mul, b, e, ft); + irValue *i2 = ir_emit_arith(proc, Token_Mul, c, h, ft); + irValue *i3 = ir_emit_arith(proc, Token_Mul, d, g, ft); + imag = ir_emit_arith(proc, Token_Sub, i1, i0, ft); + imag = ir_emit_arith(proc, Token_Sub, imag, i2, ft); + imag = ir_emit_arith(proc, Token_Add, imag, i3, ft); + imag = ir_emit_arith(proc, Token_Quo, imag, s, ft); + + irValue *j0 = ir_emit_arith(proc, Token_Mul, a, g, ft); + irValue *j1 = ir_emit_arith(proc, Token_Mul, b, h, ft); + irValue *j2 = ir_emit_arith(proc, Token_Mul, c, e, ft); + irValue *j3 = ir_emit_arith(proc, Token_Mul, d, f, ft); + jmag = ir_emit_arith(proc, Token_Sub, j1, j0, ft); + jmag = ir_emit_arith(proc, Token_Add, imag, j2, ft); + jmag = ir_emit_arith(proc, Token_Sub, imag, j3, ft); + jmag = ir_emit_arith(proc, Token_Quo, jmag, s, ft); + + irValue *k0 = ir_emit_arith(proc, Token_Mul, a, h, ft); + irValue *k1 = ir_emit_arith(proc, Token_Mul, b, g, ft); + irValue *k2 = ir_emit_arith(proc, Token_Mul, c, f, ft); + irValue *k3 = ir_emit_arith(proc, Token_Mul, d, e, ft); + kmag = ir_emit_arith(proc, Token_Add, k2, k3, ft); + kmag = ir_emit_arith(proc, Token_Sub, imag, k0, ft); + kmag = ir_emit_arith(proc, Token_Sub, imag, k1, ft); + kmag = ir_emit_arith(proc, Token_Quo, kmag, s, ft); + } break; + } + + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 0), real); + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 1), imag); + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 2), jmag); + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 3), kmag); + + ir_emit_comment(proc, str_lit("quaternion.end.begin")); + return ir_emit_load(proc, res); } @@ -1950,13 +2067,18 @@ irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) { GB_ASSERT(gb_is_between(index, 0, t->Tuple.variable_count-1)); result_type = make_type_pointer(a, t->Tuple.variables[index]->type); } else if (is_type_complex(t)) { - Type *ft = t_f32; - if (core_type(t)->Basic.kind == Basic_complex128) { - ft = t_f64; + Type *ft = base_complex_elem_type(t); + switch (index) { + case 0: result_type = make_type_pointer(a, ft); break; + case 1: result_type = make_type_pointer(a, ft); break; } + } else if (is_type_quaternion(t)) { + Type *ft = base_quaternion_elem_type(t); switch (index) { case 0: result_type = make_type_pointer(a, ft); break; case 1: result_type = make_type_pointer(a, ft); break; + case 2: result_type = make_type_pointer(a, ft); break; + case 3: result_type = make_type_pointer(a, ft); break; } } else if (is_type_slice(t)) { switch (index) { @@ -2025,13 +2147,18 @@ irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index) { GB_ASSERT(gb_is_between(index, 0, t->Tuple.variable_count-1)); result_type = t->Tuple.variables[index]->type; } else if (is_type_complex(t)) { - Type *ft = t_f32; - if (core_type(t)->Basic.kind == Basic_complex128) { - ft = t_f64; + Type *ft = base_complex_elem_type(t); + switch (index) { + case 0: result_type = ft; break; + case 1: result_type = ft; break; } + } else if (is_type_quaternion(t)) { + Type *ft = base_quaternion_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; } } else if (is_type_slice(t)) { switch (index) { @@ -2364,6 +2491,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(ev.kind == ExactValue_String); @@ -2439,6 +2568,20 @@ 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)) { + Type *ft = base_quaternion_elem_type(dst); + irValue *gen = ir_add_local_generated(proc, dst); + 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); + irValue *jmag = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 2), ft); + irValue *kmag = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 3), ft); + ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 0), real); + ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 1), imag); + ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 2), jmag); + ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 3), kmag); + return ir_emit_load(proc, gen); + } + // float <-> integer if (is_type_float(src) && is_type_integer(dst)) { irConvKind kind = irConv_fptosi; @@ -3800,29 +3943,88 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { irValue *dst = ir_add_local_generated(proc, tv->type); Type *ft = base_complex_elem_type(tv->type); - irValue *rp = ir_emit_struct_ep(proc, dst, 0); - irValue *ip = ir_emit_struct_ep(proc, dst, 1); + real = ir_emit_conv(proc, real, ft); + imag = ir_emit_conv(proc, imag, ft); + ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 0), real); + ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 1), imag); + + return ir_emit_load(proc, dst); + } break; + + case BuiltinProc_quaternion: { + ir_emit_comment(proc, str_lit("quaternion")); + irValue *real = ir_build_expr(proc, ce->args.e[0]); + irValue *imag = ir_build_expr(proc, ce->args.e[1]); + irValue *jmag = ir_build_expr(proc, ce->args.e[2]); + irValue *kmag = ir_build_expr(proc, ce->args.e[3]); + irValue *dst = ir_add_local_generated(proc, tv->type); + Type *ft = base_complex_elem_type(tv->type); real = ir_emit_conv(proc, real, ft); imag = ir_emit_conv(proc, imag, ft); - ir_emit_store(proc, rp, real); - ir_emit_store(proc, ip, imag); + jmag = ir_emit_conv(proc, jmag, ft); + kmag = ir_emit_conv(proc, kmag, ft); + ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 0), real); + ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 1), imag); + ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 2), jmag); + ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 3), kmag); return ir_emit_load(proc, dst); } break; case BuiltinProc_real: { ir_emit_comment(proc, str_lit("real")); - irValue *complex = ir_build_expr(proc, ce->args.e[0]); - irValue *real = ir_emit_struct_ev(proc, complex, 0); + irValue *val = ir_build_expr(proc, ce->args.e[0]); + irValue *real = ir_emit_struct_ev(proc, val, 0); return ir_emit_conv(proc, real, tv->type); } break; case BuiltinProc_imag: { ir_emit_comment(proc, str_lit("imag")); - irValue *complex = ir_build_expr(proc, ce->args.e[0]); - irValue *imag = ir_emit_struct_ev(proc, complex, 1); + irValue *val = ir_build_expr(proc, ce->args.e[0]); + irValue *imag = ir_emit_struct_ev(proc, val, 1); return ir_emit_conv(proc, imag, tv->type); } break; + case BuiltinProc_jmag: { + ir_emit_comment(proc, str_lit("jmag")); + irValue *val = ir_build_expr(proc, ce->args.e[0]); + irValue *jmag = ir_emit_struct_ev(proc, val, 2); + return ir_emit_conv(proc, jmag, tv->type); + } break; + case BuiltinProc_kmag: { + ir_emit_comment(proc, str_lit("kmag")); + irValue *val = ir_build_expr(proc, ce->args.e[0]); + irValue *kmag = ir_emit_struct_ev(proc, val, 3); + return ir_emit_conv(proc, kmag, tv->type); + } break; + + case BuiltinProc_conj: { + ir_emit_comment(proc, str_lit("conj")); + irValue *val = ir_build_expr(proc, ce->args.e[0]); + irValue *res = NULL; + Type *t = ir_type(val); + if (is_type_complex(t)) { + irValue *res = ir_add_local_generated(proc, tv->type); + irValue *real = ir_emit_struct_ev(proc, val, 0); + irValue *imag = ir_emit_struct_ev(proc, val, 1); + 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)) { + irValue *res = ir_add_local_generated(proc, tv->type); + irValue *real = ir_emit_struct_ev(proc, val, 0); + irValue *imag = ir_emit_struct_ev(proc, val, 1); + irValue *jmag = ir_emit_struct_ev(proc, val, 2); + irValue *kmag = ir_emit_struct_ev(proc, val, 3); + 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, 0), real); + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 1), imag); + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 2), jmag); + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 3), kmag); + } + return ir_emit_load(proc, res); + } break; case BuiltinProc_slice_ptr: { ir_emit_comment(proc, str_lit("slice_ptr")); @@ -3880,6 +4082,27 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { ir_emit_comment(proc, str_lit("abs")); irValue *x = ir_build_expr(proc, ce->args.e[0]); Type *t = ir_type(x); + if (is_type_complex(t)) { + gbAllocator a = proc->module->allocator; + i64 sz = 8*type_size_of(a, t); + irValue **args = gb_alloc_array(a, irValue *, 1); + args[0] = x; + switch (sz) { + case 64: return ir_emit_global_call(proc, "__abs_complex64", args, 1); + case 128: return ir_emit_global_call(proc, "__abs_complex128", args, 1); + } + GB_PANIC("Unknown complex type"); + } else if (is_type_quaternion(t)) { + gbAllocator a = proc->module->allocator; + i64 sz = 8*type_size_of(a, t); + irValue **args = gb_alloc_array(a, irValue *, 1); + args[0] = x; + switch (sz) { + case 128: return ir_emit_global_call(proc, "__abs_quaternion128", args, 1); + case 256: return ir_emit_global_call(proc, "__abs_quaternion256", args, 1); + } + GB_PANIC("Unknown quaternion type"); + } irValue *zero = ir_emit_conv(proc, v_zero, t); irValue *cond = ir_emit_comp(proc, Token_Lt, x, zero); irValue *neg = ir_emit(proc, ir_instr_unary_op(proc, Token_Sub, x, t)); @@ -6659,21 +6882,25 @@ void ir_gen_tree(irGen *s) { } break; case Basic_f32: - case Basic_f64: - { + case Basic_f64: { tag = ir_emit_conv(proc, ti_ptr, t_type_info_float_ptr); irValue *bits = ir_const_int(a, type_size_of(a, t)); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), bits); } break; case Basic_complex64: - case Basic_complex128: - { + case Basic_complex128: { tag = ir_emit_conv(proc, ti_ptr, t_type_info_complex_ptr); irValue *bits = ir_const_int(a, type_size_of(a, t)); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), bits); } break; + case Basic_quaternion128: + case Basic_quaternion256: { + tag = ir_emit_conv(proc, ti_ptr, t_type_info_quaternion_ptr); + irValue *bits = ir_const_int(a, type_size_of(a, t)); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), bits); + } break; case Basic_rawptr: tag = ir_emit_conv(proc, ti_ptr, t_type_info_pointer_ptr); diff --git a/src/ir_print.c b/src/ir_print.c index 39486c11f..ab5926bd0 100644 --- a/src/ir_print.c +++ b/src/ir_print.c @@ -145,28 +145,30 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) { switch (t->kind) { case Type_Basic: switch (t->Basic.kind) { - case Basic_bool: ir_fprintf(f, "i1"); return; - case Basic_i8: ir_fprintf(f, "i8"); return; - case Basic_u8: ir_fprintf(f, "i8"); return; - case Basic_i16: ir_fprintf(f, "i16"); return; - case Basic_u16: ir_fprintf(f, "i16"); return; - case Basic_i32: ir_fprintf(f, "i32"); return; - case Basic_u32: ir_fprintf(f, "i32"); return; - case Basic_i64: ir_fprintf(f, "i64"); return; - case Basic_u64: ir_fprintf(f, "i64"); return; - - case Basic_f32: ir_fprintf(f, "float"); return; - case Basic_f64: ir_fprintf(f, "double"); return; - - case Basic_complex64: ir_fprintf(f, "%%..complex64"); return; - case Basic_complex128: ir_fprintf(f, "%%..complex128"); return; - - - case Basic_rawptr: ir_fprintf(f, "%%..rawptr"); return; - case Basic_string: ir_fprintf(f, "%%..string"); return; - case Basic_uint: ir_fprintf(f, "i%lld", word_bits); return; - case Basic_int: ir_fprintf(f, "i%lld", word_bits); return; - case Basic_any: ir_fprintf(f, "%%..any"); return; + case Basic_bool: ir_fprintf(f, "i1"); return; + case Basic_i8: ir_fprintf(f, "i8"); return; + case Basic_u8: ir_fprintf(f, "i8"); return; + case Basic_i16: ir_fprintf(f, "i16"); return; + case Basic_u16: ir_fprintf(f, "i16"); return; + case Basic_i32: ir_fprintf(f, "i32"); return; + case Basic_u32: ir_fprintf(f, "i32"); return; + case Basic_i64: ir_fprintf(f, "i64"); return; + case Basic_u64: ir_fprintf(f, "i64"); return; + + case Basic_f32: ir_fprintf(f, "float"); return; + case Basic_f64: ir_fprintf(f, "double"); return; + + case Basic_complex64: ir_fprintf(f, "%%..complex64"); return; + case Basic_complex128: ir_fprintf(f, "%%..complex128"); return; + + case Basic_quaternion128: ir_fprintf(f, "%%..quaternion128"); return; + case Basic_quaternion256: ir_fprintf(f, "%%..quaternion256"); return; + + case Basic_rawptr: ir_fprintf(f, "%%..rawptr"); return; + case Basic_string: ir_fprintf(f, "%%..string"); return; + case Basic_uint: ir_fprintf(f, "i%lld", word_bits); return; + case Basic_int: ir_fprintf(f, "i%lld", word_bits); return; + case Basic_any: ir_fprintf(f, "%%..any"); return; } break; case Type_Pointer: @@ -391,17 +393,42 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * } break; case ExactValue_Complex: { - GB_ASSERT_MSG(is_type_complex(type), "%s", type_to_string(type)); type = core_type(type); - Type *ft = base_complex_elem_type(type); - ir_fprintf(f, " {"); - ir_print_type(f, m, ft); - ir_fprintf(f, " "); - ir_print_exact_value(f, m, exact_value_float(value.value_complex.real), ft); - ir_fprintf(f, ", "); - ir_print_type(f, m, ft); - ir_fprintf(f, " "); - ir_print_exact_value(f, m, exact_value_float(value.value_complex.imag), ft); + if (is_type_quaternion(type)) { + Type *ft = base_quaternion_elem_type(type); + ir_fprintf(f, " {"); ir_print_type(f, m, ft); ir_fprintf(f, " "); + ir_print_exact_value(f, m, exact_value_float(value.value_complex.real), ft); + ir_fprintf(f, ", "); ir_print_type(f, m, ft); ir_fprintf(f, " "); + ir_print_exact_value(f, m, exact_value_float(value.value_complex.imag), ft); + ir_fprintf(f, ", "); ir_print_type(f, m, ft); ir_fprintf(f, " "); + ir_print_exact_value(f, m, exact_value_float(0), ft); + ir_fprintf(f, ", "); ir_print_type(f, m, ft); ir_fprintf(f, " "); + ir_print_exact_value(f, m, exact_value_float(0), ft); + ir_fprintf(f, "}"); + + } else { + GB_ASSERT_MSG(is_type_complex(type), "%s", type_to_string(type)); + Type *ft = base_complex_elem_type(type); + ir_fprintf(f, " {"); ir_print_type(f, m, ft); ir_fprintf(f, " "); + ir_print_exact_value(f, m, exact_value_float(value.value_complex.real), ft); + ir_fprintf(f, ", "); ir_print_type(f, m, ft); ir_fprintf(f, " "); + ir_print_exact_value(f, m, exact_value_float(value.value_complex.imag), ft); + ir_fprintf(f, "}"); + } + } break; + + case ExactValue_Quaternion: { + GB_ASSERT_MSG(is_type_quaternion(type), "%s", type_to_string(type)); + type = core_type(type); + Type *ft = base_quaternion_elem_type(type); + ir_fprintf(f, " {"); ir_print_type(f, m, ft); ir_fprintf(f, " "); + ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.real), ft); + ir_fprintf(f, ", "); ir_print_type(f, m, ft); ir_fprintf(f, " "); + ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.imag), ft); + ir_fprintf(f, ", "); ir_print_type(f, m, ft); ir_fprintf(f, " "); + ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.jmag), ft); + ir_fprintf(f, ", "); ir_print_type(f, m, ft); ir_fprintf(f, " "); + ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.kmag), ft); ir_fprintf(f, "}"); } break; @@ -1008,6 +1035,72 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { case Token_LtEq: ir_fprintf(f, "ole"); break; case Token_GtEq: ir_fprintf(f, "oge"); break; } + } else if (is_type_complex(elem_type)) { + ir_fprintf(f, "call "); + ir_print_calling_convention(f, m, ProcCC_Odin); + ir_print_type(f, m, t_bool); + char *runtime_proc = ""; + i64 sz = 8*type_size_of(m->allocator, elem_type); + switch (sz) { + case 64: + switch (bo->op) { + case Token_CmpEq: runtime_proc = "__complex64_eq"; break; + case Token_NotEq: runtime_proc = "__complex64_ne"; break; + } + break; + case 128: + switch (bo->op) { + case Token_CmpEq: runtime_proc = "__complex128_eq"; break; + case Token_NotEq: runtime_proc = "__complex128_ne"; break; + } + break; + } + + ir_fprintf(f, " "); + ir_print_encoded_global(f, make_string_c(runtime_proc), false); + ir_fprintf(f, "("); + ir_print_type(f, m, type); + ir_fprintf(f, " "); + ir_print_value(f, m, bo->left, type); + ir_fprintf(f, ", "); + ir_print_type(f, m, type); + ir_fprintf(f, " "); + ir_print_value(f, m, bo->right, type); + ir_fprintf(f, ")\n"); + return; + } else if (is_type_quaternion(elem_type)) { + ir_fprintf(f, "call "); + ir_print_calling_convention(f, m, ProcCC_Odin); + ir_print_type(f, m, t_bool); + char *runtime_proc = ""; + i64 sz = 8*type_size_of(m->allocator, elem_type); + switch (sz) { + case 128: + switch (bo->op) { + case Token_CmpEq: runtime_proc = "__quaternion128_eq"; break; + case Token_NotEq: runtime_proc = "__quaternion128_ne"; break; + } + break; + case 256: + switch (bo->op) { + case Token_CmpEq: runtime_proc = "__quaternion256_eq"; break; + case Token_NotEq: runtime_proc = "__quaternion256_ne"; break; + } + break; + } + + ir_fprintf(f, " "); + ir_print_encoded_global(f, make_string_c(runtime_proc), false); + ir_fprintf(f, "("); + ir_print_type(f, m, type); + ir_fprintf(f, " "); + ir_print_value(f, m, bo->left, type); + ir_fprintf(f, ", "); + ir_print_type(f, m, type); + ir_fprintf(f, " "); + ir_print_value(f, m, bo->right, type); + ir_fprintf(f, ")\n"); + return; } else { ir_fprintf(f, "icmp "); if (bo->op != Token_CmpEq && @@ -1420,6 +1513,10 @@ void print_llvm_ir(irGen *ir) { ir_fprintf(f, " = type {float, float} ; Basic_complex64\n"); ir_print_encoded_local(f, str_lit("..complex128")); ir_fprintf(f, " = type {double, double} ; Basic_complex128\n"); + ir_print_encoded_local(f, str_lit("..quaternion128")); + ir_fprintf(f, " = type {float, float, float, float} ; Basic_quaternion128\n"); + ir_print_encoded_local(f, str_lit("..quaternion256")); + ir_fprintf(f, " = type {double, double, double, double} ; Basic_quaternion256\n"); ir_print_encoded_local(f, str_lit("..any")); diff --git a/src/tokenizer.c b/src/tokenizer.c index bd012519b..398f39f98 100644 --- a/src/tokenizer.c +++ b/src/tokenizer.c @@ -578,9 +578,11 @@ 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); + break; } end: diff --git a/src/types.c b/src/types.c index 338489234..9735e6e38 100644 --- a/src/types.c +++ b/src/types.c @@ -18,6 +18,9 @@ typedef enum BasicKind { Basic_complex64, Basic_complex128, + Basic_quaternion128, + Basic_quaternion256, + Basic_int, Basic_uint, Basic_rawptr, @@ -28,6 +31,7 @@ typedef enum BasicKind { Basic_UntypedInteger, Basic_UntypedFloat, Basic_UntypedComplex, + Basic_UntypedQuaternion, Basic_UntypedString, Basic_UntypedRune, Basic_UntypedNil, @@ -39,18 +43,19 @@ typedef enum BasicKind { } BasicKind; typedef enum BasicFlag { - BasicFlag_Boolean = GB_BIT(0), - BasicFlag_Integer = GB_BIT(1), - 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_Numeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Complex, - BasicFlag_Ordered = BasicFlag_Numeric | BasicFlag_String | BasicFlag_Pointer, + BasicFlag_Boolean = GB_BIT(0), + BasicFlag_Integer = GB_BIT(1), + BasicFlag_Unsigned = GB_BIT(2), + BasicFlag_Float = GB_BIT(3), + BasicFlag_Complex = GB_BIT(4), + 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_Numeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Complex | BasicFlag_Quaternion, + BasicFlag_Ordered = BasicFlag_Integer | BasicFlag_Float | BasicFlag_String | BasicFlag_Pointer, BasicFlag_ConstantType = BasicFlag_Boolean | BasicFlag_Numeric | BasicFlag_Pointer | BasicFlag_String | BasicFlag_Rune, } BasicFlag; @@ -198,39 +203,43 @@ void selection_add_index(Selection *s, isize index) { gb_global Type basic_types[] = { - {Type_Basic, {Basic_Invalid, 0, 0, STR_LIT("invalid type")}}, - - {Type_Basic, {Basic_bool, BasicFlag_Boolean, 1, STR_LIT("bool")}}, - - {Type_Basic, {Basic_i8, BasicFlag_Integer, 1, STR_LIT("i8")}}, - {Type_Basic, {Basic_u8, BasicFlag_Integer | BasicFlag_Unsigned, 1, STR_LIT("u8")}}, - {Type_Basic, {Basic_i16, BasicFlag_Integer, 2, STR_LIT("i16")}}, - {Type_Basic, {Basic_u16, BasicFlag_Integer | BasicFlag_Unsigned, 2, STR_LIT("u16")}}, - {Type_Basic, {Basic_i32, BasicFlag_Integer, 4, STR_LIT("i32")}}, - {Type_Basic, {Basic_u32, BasicFlag_Integer | BasicFlag_Unsigned, 4, STR_LIT("u32")}}, - {Type_Basic, {Basic_i64, BasicFlag_Integer, 8, STR_LIT("i64")}}, - {Type_Basic, {Basic_u64, BasicFlag_Integer | BasicFlag_Unsigned, 8, STR_LIT("u64")}}, - - {Type_Basic, {Basic_f32, BasicFlag_Float, 4, STR_LIT("f32")}}, - {Type_Basic, {Basic_f64, BasicFlag_Float, 8, STR_LIT("f64")}}, - - {Type_Basic, {Basic_complex64, BasicFlag_Complex, 8, STR_LIT("complex64")}}, - {Type_Basic, {Basic_complex128, BasicFlag_Complex, 16, STR_LIT("complex128")}}, - - {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_rawptr, BasicFlag_Pointer, -1, STR_LIT("rawptr")}}, - {Type_Basic, {Basic_string, BasicFlag_String, -1, STR_LIT("string")}}, - {Type_Basic, {Basic_any, 0, -1, STR_LIT("any")}}, - - {Type_Basic, {Basic_UntypedBool, BasicFlag_Boolean | BasicFlag_Untyped, 0, STR_LIT("untyped bool")}}, - {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_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")}}, + {Type_Basic, {Basic_Invalid, 0, 0, STR_LIT("invalid type")}}, + + {Type_Basic, {Basic_bool, BasicFlag_Boolean, 1, STR_LIT("bool")}}, + + {Type_Basic, {Basic_i8, BasicFlag_Integer, 1, STR_LIT("i8")}}, + {Type_Basic, {Basic_u8, BasicFlag_Integer | BasicFlag_Unsigned, 1, STR_LIT("u8")}}, + {Type_Basic, {Basic_i16, BasicFlag_Integer, 2, STR_LIT("i16")}}, + {Type_Basic, {Basic_u16, BasicFlag_Integer | BasicFlag_Unsigned, 2, STR_LIT("u16")}}, + {Type_Basic, {Basic_i32, BasicFlag_Integer, 4, STR_LIT("i32")}}, + {Type_Basic, {Basic_u32, BasicFlag_Integer | BasicFlag_Unsigned, 4, STR_LIT("u32")}}, + {Type_Basic, {Basic_i64, BasicFlag_Integer, 8, STR_LIT("i64")}}, + {Type_Basic, {Basic_u64, BasicFlag_Integer | BasicFlag_Unsigned, 8, STR_LIT("u64")}}, + + {Type_Basic, {Basic_f32, BasicFlag_Float, 4, STR_LIT("f32")}}, + {Type_Basic, {Basic_f64, BasicFlag_Float, 8, STR_LIT("f64")}}, + + {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_rawptr, BasicFlag_Pointer, -1, STR_LIT("rawptr")}}, + {Type_Basic, {Basic_string, BasicFlag_String, -1, STR_LIT("string")}}, + {Type_Basic, {Basic_any, 0, -1, STR_LIT("any")}}, + + {Type_Basic, {Basic_UntypedBool, BasicFlag_Boolean | BasicFlag_Untyped, 0, STR_LIT("untyped bool")}}, + {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")}}, }; gb_global Type basic_type_aliases[] = { @@ -255,6 +264,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]; @@ -262,15 +274,16 @@ gb_global Type *t_rawptr = &basic_types[Basic_rawptr]; gb_global Type *t_string = &basic_types[Basic_string]; gb_global Type *t_any = &basic_types[Basic_any]; -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_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]; -gb_global Type *t_byte = &basic_type_aliases[0]; -gb_global Type *t_rune = &basic_type_aliases[1]; +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]; +gb_global Type *t_byte = &basic_type_aliases[0]; +gb_global Type *t_rune = &basic_type_aliases[1]; gb_global Type *t_u8_ptr = NULL; @@ -293,6 +306,7 @@ gb_global Type *t_type_info_named = NULL; gb_global Type *t_type_info_integer = NULL; gb_global Type *t_type_info_float = NULL; gb_global Type *t_type_info_complex = NULL; +gb_global Type *t_type_info_quaternion = NULL; gb_global Type *t_type_info_any = NULL; gb_global Type *t_type_info_string = NULL; gb_global Type *t_type_info_boolean = NULL; @@ -313,6 +327,7 @@ gb_global Type *t_type_info_named_ptr = NULL; gb_global Type *t_type_info_integer_ptr = NULL; gb_global Type *t_type_info_float_ptr = NULL; gb_global Type *t_type_info_complex_ptr = NULL; +gb_global Type *t_type_info_quaternion_ptr = NULL; gb_global Type *t_type_info_any_ptr = NULL; gb_global Type *t_type_info_string_ptr = NULL; gb_global Type *t_type_info_boolean_ptr = NULL; @@ -623,6 +638,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) { @@ -715,6 +737,18 @@ Type *base_complex_elem_type(Type *t) { GB_PANIC("Invalid complex type"); return t_invalid; } +Type *base_quaternion_elem_type(Type *t) { + t = core_type(t); + if (is_type_quaternion(t)) { + switch (t->Basic.kind) { + case Basic_quaternion128: return t_f32; + case Basic_quaternion256: return t_f64; + case Basic_UntypedQuaternion: return t_untyped_float; + } + } + GB_PANIC("Invalid quaternion type"); + return t_invalid; +} bool is_type_struct(Type *t) { @@ -971,12 +1005,13 @@ Type *default_type(Type *type) { } if (type->kind == Type_Basic) { switch (type->Basic.kind) { - case Basic_UntypedBool: return t_bool; - case Basic_UntypedInteger: return t_int; - case Basic_UntypedFloat: return t_f64; - case Basic_UntypedComplex: return t_complex128; - case Basic_UntypedString: return t_string; - case Basic_UntypedRune: return t_rune; + case Basic_UntypedBool: return t_bool; + 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; } } return type; @@ -1567,8 +1602,9 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) { return build_context.word_size; case Basic_complex64: case Basic_complex128: - // complex{64,128} align as [2]f{32,64} return type_size_of_internal(allocator, t, path) / 2; + case Basic_quaternion128: case Basic_quaternion256: + return type_size_of_internal(allocator, t, path) / 4; } } break; -- cgit v1.2.3 From 2c8b99337bb33d0f713026c5c38e05428cc52143 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Sat, 1 Apr 2017 22:55:33 +0100 Subject: Fix `conj` --- code/demo.odin | 3 +-- src/ir.c | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'code') diff --git a/code/demo.odin b/code/demo.odin index aa75411d8..197aa83fe 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -2,10 +2,9 @@ #import "os.odin"; #import "math.odin"; - main :: proc() { x := 1+2i+3j+4k; - y := 3-4i-5j-6k; + y := conj(x); z := x/y; fmt.println(z, abs(z)); } diff --git a/src/ir.c b/src/ir.c index 374aea0a2..bfe4f3781 100644 --- a/src/ir.c +++ b/src/ir.c @@ -4003,14 +4003,14 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { irValue *res = NULL; Type *t = ir_type(val); if (is_type_complex(t)) { - irValue *res = ir_add_local_generated(proc, tv->type); + res = ir_add_local_generated(proc, tv->type); irValue *real = ir_emit_struct_ev(proc, val, 0); irValue *imag = ir_emit_struct_ev(proc, val, 1); 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)) { - irValue *res = ir_add_local_generated(proc, tv->type); + res = ir_add_local_generated(proc, tv->type); irValue *real = ir_emit_struct_ev(proc, val, 0); irValue *imag = ir_emit_struct_ev(proc, val, 1); irValue *jmag = ir_emit_struct_ev(proc, val, 2); -- cgit v1.2.3