internal.odin 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  1. package runtime
  2. import "intrinsics"
  3. bswap_16 :: proc "none" (x: u16) -> u16 {
  4. return x>>8 | x<<8;
  5. }
  6. bswap_32 :: proc "none" (x: u32) -> u32 {
  7. return x>>24 | (x>>8)&0xff00 | (x<<8)&0xff0000 | x<<24;
  8. }
  9. bswap_64 :: proc "none" (x: u64) -> u64 {
  10. z := x;
  11. z = (z & 0x00000000ffffffff) << 32 | (z & 0xffffffff00000000) >> 32;
  12. z = (z & 0x0000ffff0000ffff) << 16 | (z & 0xffff0000ffff0000) >> 16;
  13. z = (z & 0x00ff00ff00ff00ff) << 8 | (z & 0xff00ff00ff00ff00) >> 8;
  14. return z;
  15. }
  16. bswap_128 :: proc "none" (x: u128) -> u128 {
  17. z := transmute([4]u32)x;
  18. z[0] = bswap_32(z[3]);
  19. z[1] = bswap_32(z[2]);
  20. z[2] = bswap_32(z[1]);
  21. z[3] = bswap_32(z[0]);
  22. return transmute(u128)z;
  23. }
  24. bswap_f16 :: proc "none" (f: f16) -> f16 {
  25. x := transmute(u16)f;
  26. z := bswap_16(x);
  27. return transmute(f16)z;
  28. }
  29. bswap_f32 :: proc "none" (f: f32) -> f32 {
  30. x := transmute(u32)f;
  31. z := bswap_32(x);
  32. return transmute(f32)z;
  33. }
  34. bswap_f64 :: proc "none" (f: f64) -> f64 {
  35. x := transmute(u64)f;
  36. z := bswap_64(x);
  37. return transmute(f64)z;
  38. }
  39. ptr_offset :: #force_inline proc "contextless" (ptr: $P/^$T, n: int) -> P {
  40. new := int(uintptr(ptr)) + size_of(T)*n;
  41. return P(uintptr(new));
  42. }
  43. is_power_of_two_int :: #force_inline proc(x: int) -> bool {
  44. if x <= 0 {
  45. return false;
  46. }
  47. return (x & (x-1)) == 0;
  48. }
  49. align_forward_int :: #force_inline proc(ptr, align: int) -> int {
  50. assert(is_power_of_two_int(align));
  51. p := ptr;
  52. modulo := p & (align-1);
  53. if modulo != 0 {
  54. p += align - modulo;
  55. }
  56. return p;
  57. }
  58. is_power_of_two_uintptr :: #force_inline proc(x: uintptr) -> bool {
  59. if x <= 0 {
  60. return false;
  61. }
  62. return (x & (x-1)) == 0;
  63. }
  64. align_forward_uintptr :: #force_inline proc(ptr, align: uintptr) -> uintptr {
  65. assert(is_power_of_two_uintptr(align));
  66. p := ptr;
  67. modulo := p & (align-1);
  68. if modulo != 0 {
  69. p += align - modulo;
  70. }
  71. return p;
  72. }
  73. mem_zero :: proc "contextless" (data: rawptr, len: int) -> rawptr {
  74. if data == nil {
  75. return nil;
  76. }
  77. if len < 0 {
  78. return data;
  79. }
  80. memset(data, 0, len);
  81. return data;
  82. }
  83. mem_copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
  84. if src == nil {
  85. return dst;
  86. }
  87. // NOTE(bill): This _must_ be implemented like C's memmove
  88. foreign _ {
  89. when ODIN_USE_LLVM_API {
  90. when size_of(rawptr) == 8 {
  91. @(link_name="llvm.memmove.p0i8.p0i8.i64")
  92. llvm_memmove :: proc "none" (dst, src: rawptr, len: int, is_volatile: bool = false) ---;
  93. } else {
  94. @(link_name="llvm.memmove.p0i8.p0i8.i32")
  95. llvm_memmove :: proc "none" (dst, src: rawptr, len: int, is_volatile: bool = false) ---;
  96. }
  97. } else {
  98. when size_of(rawptr) == 8 {
  99. @(link_name="llvm.memmove.p0i8.p0i8.i64")
  100. llvm_memmove :: proc "none" (dst, src: rawptr, len: int, align: i32 = 1, is_volatile: bool = false) ---;
  101. } else {
  102. @(link_name="llvm.memmove.p0i8.p0i8.i32")
  103. llvm_memmove :: proc "none" (dst, src: rawptr, len: int, align: i32 = 1, is_volatile: bool = false) ---;
  104. }
  105. }
  106. }
  107. llvm_memmove(dst, src, len);
  108. return dst;
  109. }
  110. mem_copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
  111. if src == nil {
  112. return dst;
  113. }
  114. // NOTE(bill): This _must_ be implemented like C's memcpy
  115. foreign _ {
  116. when ODIN_USE_LLVM_API {
  117. when size_of(rawptr) == 8 {
  118. @(link_name="llvm.memcpy.p0i8.p0i8.i64")
  119. llvm_memcpy :: proc "none" (dst, src: rawptr, len: int, is_volatile: bool = false) ---;
  120. } else {
  121. @(link_name="llvm.memcpy.p0i8.p0i8.i32")
  122. llvm_memcpy :: proc "none" (dst, src: rawptr, len: int, is_volatile: bool = false) ---;
  123. }
  124. } else {
  125. when size_of(rawptr) == 8 {
  126. @(link_name="llvm.memcpy.p0i8.p0i8.i64")
  127. llvm_memcpy :: proc "none" (dst, src: rawptr, len: int, align: i32 = 1, is_volatile: bool = false) ---;
  128. } else {
  129. @(link_name="llvm.memcpy.p0i8.p0i8.i32")
  130. llvm_memcpy :: proc "none" (dst, src: rawptr, len: int, align: i32 = 1, is_volatile: bool = false) ---;
  131. }
  132. }
  133. }
  134. llvm_memcpy(dst, src, len);
  135. return dst;
  136. }
  137. DEFAULT_ALIGNMENT :: 2*align_of(rawptr);
  138. mem_alloc_bytes :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
  139. if size == 0 {
  140. return nil, nil;
  141. }
  142. if allocator.procedure == nil {
  143. return nil, nil;
  144. }
  145. return allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, loc);
  146. }
  147. mem_alloc :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (rawptr, Allocator_Error) {
  148. if size == 0 {
  149. return nil, nil;
  150. }
  151. if allocator.procedure == nil {
  152. return nil, nil;
  153. }
  154. data, err := allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, loc);
  155. return raw_data(data), err;
  156. }
  157. mem_free :: #force_inline proc(ptr: rawptr, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
  158. if ptr == nil {
  159. return .None;
  160. }
  161. if allocator.procedure == nil {
  162. return .None;
  163. }
  164. _, err := allocator.procedure(allocator.data, .Free, 0, 0, ptr, 0, loc);
  165. return err;
  166. }
  167. mem_free_all :: #force_inline proc(allocator := context.allocator, loc := #caller_location) -> (err: Allocator_Error) {
  168. if allocator.procedure != nil {
  169. _, err = allocator.procedure(allocator.data, .Free_All, 0, 0, nil, 0, loc);
  170. }
  171. return;
  172. }
  173. mem_resize :: #force_inline proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (new_ptr: rawptr, err: Allocator_Error) {
  174. new_data: []byte;
  175. switch {
  176. case allocator.procedure == nil:
  177. return;
  178. case new_size == 0:
  179. new_data, err = allocator.procedure(allocator.data, .Free, 0, 0, ptr, 0, loc);
  180. case ptr == nil:
  181. new_data, err = allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc);
  182. case:
  183. new_data, err = allocator.procedure(allocator.data, .Resize, new_size, alignment, ptr, old_size, loc);
  184. }
  185. new_ptr = raw_data(new_data);
  186. return;
  187. }
  188. memory_equal :: proc "contextless" (a, b: rawptr, n: int) -> bool {
  189. return memory_compare(a, b, n) == 0;
  190. }
  191. memory_compare :: proc "contextless" (a, b: rawptr, n: int) -> int #no_bounds_check {
  192. switch {
  193. case a == b: return 0;
  194. case a == nil: return -1;
  195. case b == nil: return +1;
  196. }
  197. x := uintptr(a);
  198. y := uintptr(b);
  199. n := uintptr(n);
  200. SU :: size_of(uintptr);
  201. fast := n/SU + 1;
  202. offset := (fast-1)*SU;
  203. curr_block := uintptr(0);
  204. if n < SU {
  205. fast = 0;
  206. }
  207. for /**/; curr_block < fast; curr_block += 1 {
  208. va := (^uintptr)(x + curr_block * size_of(uintptr))^;
  209. vb := (^uintptr)(y + curr_block * size_of(uintptr))^;
  210. if va ~ vb != 0 {
  211. for pos := curr_block*SU; pos < n; pos += 1 {
  212. a := (^byte)(x+pos)^;
  213. b := (^byte)(y+pos)^;
  214. if a ~ b != 0 {
  215. return -1 if (int(a) - int(b)) < 0 else +1;
  216. }
  217. }
  218. }
  219. }
  220. for /**/; offset < n; offset += 1 {
  221. a := (^byte)(x+offset)^;
  222. b := (^byte)(y+offset)^;
  223. if a ~ b != 0 {
  224. return -1 if (int(a) - int(b)) < 0 else +1;
  225. }
  226. }
  227. return 0;
  228. }
  229. memory_compare_zero :: proc "contextless" (a: rawptr, n: int) -> int #no_bounds_check {
  230. x := uintptr(a);
  231. n := uintptr(n);
  232. SU :: size_of(uintptr);
  233. fast := n/SU + 1;
  234. offset := (fast-1)*SU;
  235. curr_block := uintptr(0);
  236. if n < SU {
  237. fast = 0;
  238. }
  239. for /**/; curr_block < fast; curr_block += 1 {
  240. va := (^uintptr)(x + curr_block * size_of(uintptr))^;
  241. if va ~ 0 != 0 {
  242. for pos := curr_block*SU; pos < n; pos += 1 {
  243. a := (^byte)(x+pos)^;
  244. if a ~ 0 != 0 {
  245. return -1 if int(a) < 0 else +1;
  246. }
  247. }
  248. }
  249. }
  250. for /**/; offset < n; offset += 1 {
  251. a := (^byte)(x+offset)^;
  252. if a ~ 0 != 0 {
  253. return -1 if int(a) < 0 else +1;
  254. }
  255. }
  256. return 0;
  257. }
  258. string_eq :: proc "contextless" (a, b: string) -> bool {
  259. x := transmute(Raw_String)a;
  260. y := transmute(Raw_String)b;
  261. switch {
  262. case x.len != y.len: return false;
  263. case x.len == 0: return true;
  264. case x.data == y.data: return true;
  265. }
  266. return string_cmp(a, b) == 0;
  267. }
  268. string_cmp :: proc "contextless" (a, b: string) -> int {
  269. x := transmute(Raw_String)a;
  270. y := transmute(Raw_String)b;
  271. return memory_compare(x.data, y.data, min(x.len, y.len));
  272. }
  273. string_ne :: #force_inline proc "contextless" (a, b: string) -> bool { return !string_eq(a, b); }
  274. string_lt :: #force_inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) < 0; }
  275. string_gt :: #force_inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) > 0; }
  276. string_le :: #force_inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) <= 0; }
  277. string_ge :: #force_inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) >= 0; }
  278. cstring_len :: proc "contextless" (s: cstring) -> int {
  279. p0 := uintptr((^byte)(s));
  280. p := p0;
  281. for p != 0 && (^byte)(p)^ != 0 {
  282. p += 1;
  283. }
  284. return int(p - p0);
  285. }
  286. cstring_to_string :: proc "contextless" (s: cstring) -> string {
  287. if s == nil {
  288. return "";
  289. }
  290. ptr := (^byte)(s);
  291. n := cstring_len(s);
  292. return transmute(string)Raw_String{ptr, n};
  293. }
  294. complex64_eq :: #force_inline proc "contextless" (a, b: complex64) -> bool { return real(a) == real(b) && imag(a) == imag(b); }
  295. complex64_ne :: #force_inline proc "contextless" (a, b: complex64) -> bool { return real(a) != real(b) || imag(a) != imag(b); }
  296. complex128_eq :: #force_inline proc "contextless" (a, b: complex128) -> bool { return real(a) == real(b) && imag(a) == imag(b); }
  297. complex128_ne :: #force_inline proc "contextless" (a, b: complex128) -> bool { return real(a) != real(b) || imag(a) != imag(b); }
  298. quaternion128_eq :: #force_inline proc "contextless" (a, b: quaternion128) -> bool { return real(a) == real(b) && imag(a) == imag(b) && jmag(a) == jmag(b) && kmag(a) == kmag(b); }
  299. quaternion128_ne :: #force_inline proc "contextless" (a, b: quaternion128) -> bool { return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b); }
  300. quaternion256_eq :: #force_inline proc "contextless" (a, b: quaternion256) -> bool { return real(a) == real(b) && imag(a) == imag(b) && jmag(a) == jmag(b) && kmag(a) == kmag(b); }
  301. quaternion256_ne :: #force_inline proc "contextless" (a, b: quaternion256) -> bool { return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b); }
  302. string_decode_rune :: #force_inline proc "contextless" (s: string) -> (rune, int) {
  303. // NOTE(bill): Duplicated here to remove dependency on package unicode/utf8
  304. @static accept_sizes := [256]u8{
  305. 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f
  306. 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f
  307. 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f
  308. 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x30-0x3f
  309. 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x40-0x4f
  310. 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x50-0x5f
  311. 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x60-0x6f
  312. 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x70-0x7f
  313. 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x80-0x8f
  314. 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x90-0x9f
  315. 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xa0-0xaf
  316. 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xb0-0xbf
  317. 0xf1, 0xf1, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xc0-0xcf
  318. 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xd0-0xdf
  319. 0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, // 0xe0-0xef
  320. 0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xf0-0xff
  321. };
  322. Accept_Range :: struct {lo, hi: u8};
  323. @static accept_ranges := [5]Accept_Range{
  324. {0x80, 0xbf},
  325. {0xa0, 0xbf},
  326. {0x80, 0x9f},
  327. {0x90, 0xbf},
  328. {0x80, 0x8f},
  329. };
  330. MASKX :: 0b0011_1111;
  331. MASK2 :: 0b0001_1111;
  332. MASK3 :: 0b0000_1111;
  333. MASK4 :: 0b0000_0111;
  334. LOCB :: 0b1000_0000;
  335. HICB :: 0b1011_1111;
  336. RUNE_ERROR :: '\ufffd';
  337. n := len(s);
  338. if n < 1 {
  339. return RUNE_ERROR, 0;
  340. }
  341. s0 := s[0];
  342. x := accept_sizes[s0];
  343. if x >= 0xF0 {
  344. mask := rune(x) << 31 >> 31; // NOTE(bill): Create 0x0000 or 0xffff.
  345. return rune(s[0])&~mask | RUNE_ERROR&mask, 1;
  346. }
  347. sz := x & 7;
  348. accept := accept_ranges[x>>4];
  349. if n < int(sz) {
  350. return RUNE_ERROR, 1;
  351. }
  352. b1 := s[1];
  353. if b1 < accept.lo || accept.hi < b1 {
  354. return RUNE_ERROR, 1;
  355. }
  356. if sz == 2 {
  357. return rune(s0&MASK2)<<6 | rune(b1&MASKX), 2;
  358. }
  359. b2 := s[2];
  360. if b2 < LOCB || HICB < b2 {
  361. return RUNE_ERROR, 1;
  362. }
  363. if sz == 3 {
  364. return rune(s0&MASK3)<<12 | rune(b1&MASKX)<<6 | rune(b2&MASKX), 3;
  365. }
  366. b3 := s[3];
  367. if b3 < LOCB || HICB < b3 {
  368. return RUNE_ERROR, 1;
  369. }
  370. return rune(s0&MASK4)<<18 | rune(b1&MASKX)<<12 | rune(b2&MASKX)<<6 | rune(b3&MASKX), 4;
  371. }
  372. @(default_calling_convention = "none")
  373. foreign {
  374. @(link_name="llvm.sqrt.f32") _sqrt_f32 :: proc(x: f32) -> f32 ---
  375. @(link_name="llvm.sqrt.f64") _sqrt_f64 :: proc(x: f64) -> f64 ---
  376. }
  377. abs_f16 :: #force_inline proc "contextless" (x: f16) -> f16 {
  378. foreign {
  379. @(link_name="llvm.fabs.f16") _abs :: proc "none" (x: f16) -> f16 ---
  380. }
  381. return _abs(x);
  382. }
  383. abs_f32 :: #force_inline proc "contextless" (x: f32) -> f32 {
  384. foreign {
  385. @(link_name="llvm.fabs.f32") _abs :: proc "none" (x: f32) -> f32 ---
  386. }
  387. return _abs(x);
  388. }
  389. abs_f64 :: #force_inline proc "contextless" (x: f64) -> f64 {
  390. foreign {
  391. @(link_name="llvm.fabs.f64") _abs :: proc "none" (x: f64) -> f64 ---
  392. }
  393. return _abs(x);
  394. }
  395. min_f16 :: proc(a, b: f16) -> f16 {
  396. foreign {
  397. @(link_name="llvm.minnum.f16") _min :: proc "none" (a, b: f16) -> f16 ---
  398. }
  399. return _min(a, b);
  400. }
  401. min_f32 :: proc(a, b: f32) -> f32 {
  402. foreign {
  403. @(link_name="llvm.minnum.f32") _min :: proc "none" (a, b: f32) -> f32 ---
  404. }
  405. return _min(a, b);
  406. }
  407. min_f64 :: proc(a, b: f64) -> f64 {
  408. foreign {
  409. @(link_name="llvm.minnum.f64") _min :: proc "none" (a, b: f64) -> f64 ---
  410. }
  411. return _min(a, b);
  412. }
  413. max_f16 :: proc(a, b: f16) -> f16 {
  414. foreign {
  415. @(link_name="llvm.maxnum.f16") _max :: proc "none" (a, b: f16) -> f16 ---
  416. }
  417. return _max(a, b);
  418. }
  419. max_f32 :: proc(a, b: f32) -> f32 {
  420. foreign {
  421. @(link_name="llvm.maxnum.f32") _max :: proc "none" (a, b: f32) -> f32 ---
  422. }
  423. return _max(a, b);
  424. }
  425. max_f64 :: proc(a, b: f64) -> f64 {
  426. foreign {
  427. @(link_name="llvm.maxnum.f64") _max :: proc "none" (a, b: f64) -> f64 ---
  428. }
  429. return _max(a, b);
  430. }
  431. abs_complex32 :: #force_inline proc "contextless" (x: complex32) -> f16 {
  432. r, i := real(x), imag(x);
  433. return f16(_sqrt_f32(f32(r*r + i*i)));
  434. }
  435. abs_complex64 :: #force_inline proc "contextless" (x: complex64) -> f32 {
  436. r, i := real(x), imag(x);
  437. return _sqrt_f32(r*r + i*i);
  438. }
  439. abs_complex128 :: #force_inline proc "contextless" (x: complex128) -> f64 {
  440. r, i := real(x), imag(x);
  441. return _sqrt_f64(r*r + i*i);
  442. }
  443. abs_quaternion64 :: #force_inline proc "contextless" (x: quaternion64) -> f16 {
  444. r, i, j, k := real(x), imag(x), jmag(x), kmag(x);
  445. return f16(_sqrt_f32(f32(r*r + i*i + j*j + k*k)));
  446. }
  447. abs_quaternion128 :: #force_inline proc "contextless" (x: quaternion128) -> f32 {
  448. r, i, j, k := real(x), imag(x), jmag(x), kmag(x);
  449. return _sqrt_f32(r*r + i*i + j*j + k*k);
  450. }
  451. abs_quaternion256 :: #force_inline proc "contextless" (x: quaternion256) -> f64 {
  452. r, i, j, k := real(x), imag(x), jmag(x), kmag(x);
  453. return _sqrt_f64(r*r + i*i + j*j + k*k);
  454. }
  455. quo_complex32 :: proc "contextless" (n, m: complex32) -> complex32 {
  456. e, f: f16;
  457. if abs(real(m)) >= abs(imag(m)) {
  458. ratio := imag(m) / real(m);
  459. denom := real(m) + ratio*imag(m);
  460. e = (real(n) + imag(n)*ratio) / denom;
  461. f = (imag(n) - real(n)*ratio) / denom;
  462. } else {
  463. ratio := real(m) / imag(m);
  464. denom := imag(m) + ratio*real(m);
  465. e = (real(n)*ratio + imag(n)) / denom;
  466. f = (imag(n)*ratio - real(n)) / denom;
  467. }
  468. return complex(e, f);
  469. }
  470. quo_complex64 :: proc "contextless" (n, m: complex64) -> complex64 {
  471. e, f: f32;
  472. if abs(real(m)) >= abs(imag(m)) {
  473. ratio := imag(m) / real(m);
  474. denom := real(m) + ratio*imag(m);
  475. e = (real(n) + imag(n)*ratio) / denom;
  476. f = (imag(n) - real(n)*ratio) / denom;
  477. } else {
  478. ratio := real(m) / imag(m);
  479. denom := imag(m) + ratio*real(m);
  480. e = (real(n)*ratio + imag(n)) / denom;
  481. f = (imag(n)*ratio - real(n)) / denom;
  482. }
  483. return complex(e, f);
  484. }
  485. quo_complex128 :: proc "contextless" (n, m: complex128) -> complex128 {
  486. e, f: f64;
  487. if abs(real(m)) >= abs(imag(m)) {
  488. ratio := imag(m) / real(m);
  489. denom := real(m) + ratio*imag(m);
  490. e = (real(n) + imag(n)*ratio) / denom;
  491. f = (imag(n) - real(n)*ratio) / denom;
  492. } else {
  493. ratio := real(m) / imag(m);
  494. denom := imag(m) + ratio*real(m);
  495. e = (real(n)*ratio + imag(n)) / denom;
  496. f = (imag(n)*ratio - real(n)) / denom;
  497. }
  498. return complex(e, f);
  499. }
  500. mul_quaternion64 :: proc "contextless" (q, r: quaternion64) -> quaternion64 {
  501. q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
  502. r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
  503. t0 := r0*q0 - r1*q1 - r2*q2 - r3*q3;
  504. t1 := r0*q1 + r1*q0 - r2*q3 + r3*q2;
  505. t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1;
  506. t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0;
  507. return quaternion(t0, t1, t2, t3);
  508. }
  509. mul_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
  510. q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
  511. r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
  512. t0 := r0*q0 - r1*q1 - r2*q2 - r3*q3;
  513. t1 := r0*q1 + r1*q0 - r2*q3 + r3*q2;
  514. t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1;
  515. t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0;
  516. return quaternion(t0, t1, t2, t3);
  517. }
  518. mul_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
  519. q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
  520. r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
  521. t0 := r0*q0 - r1*q1 - r2*q2 - r3*q3;
  522. t1 := r0*q1 + r1*q0 - r2*q3 + r3*q2;
  523. t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1;
  524. t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0;
  525. return quaternion(t0, t1, t2, t3);
  526. }
  527. quo_quaternion64 :: proc "contextless" (q, r: quaternion64) -> quaternion64 {
  528. q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
  529. r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
  530. invmag2 := 1.0 / (r0*r0 + r1*r1 + r2*r2 + r3*r3);
  531. t0 := (r0*q0 + r1*q1 + r2*q2 + r3*q3) * invmag2;
  532. t1 := (r0*q1 - r1*q0 - r2*q3 - r3*q2) * invmag2;
  533. t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2;
  534. t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2;
  535. return quaternion(t0, t1, t2, t3);
  536. }
  537. quo_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
  538. q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
  539. r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
  540. invmag2 := 1.0 / (r0*r0 + r1*r1 + r2*r2 + r3*r3);
  541. t0 := (r0*q0 + r1*q1 + r2*q2 + r3*q3) * invmag2;
  542. t1 := (r0*q1 - r1*q0 - r2*q3 - r3*q2) * invmag2;
  543. t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2;
  544. t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2;
  545. return quaternion(t0, t1, t2, t3);
  546. }
  547. quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
  548. q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
  549. r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
  550. invmag2 := 1.0 / (r0*r0 + r1*r1 + r2*r2 + r3*r3);
  551. t0 := (r0*q0 + r1*q1 + r2*q2 + r3*q3) * invmag2;
  552. t1 := (r0*q1 - r1*q0 - r2*q3 - r3*q2) * invmag2;
  553. t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2;
  554. t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2;
  555. return quaternion(t0, t1, t2, t3);
  556. }
  557. @(link_name="__truncsfhf2")
  558. truncsfhf2 :: proc "c" (value: f32) -> u16 {
  559. v: struct #raw_union { i: u32, f: f32 };
  560. i, s, e, m: i32;
  561. v.f = value;
  562. i = i32(v.i);
  563. s = (i >> 16) & 0x00008000;
  564. e = ((i >> 23) & 0x000000ff) - (127 - 15);
  565. m = i & 0x007fffff;
  566. if (e <= 0) {
  567. if (e < -10) {
  568. return u16(s);
  569. }
  570. m = (m | 0x00800000) >> u32(1 - e);
  571. if (m & 0x00001000) != 0 {
  572. m += 0x00002000;
  573. }
  574. return u16(s | (m >> 13));
  575. } else if (e == 0xff - (127 - 15)) {
  576. if (m == 0) {
  577. return u16(s | 0x7c00); /* NOTE(bill): infinity */
  578. } else {
  579. /* NOTE(bill): NAN */
  580. m >>= 13;
  581. return u16(s | 0x7c00 | m | i32(m == 0));
  582. }
  583. } else {
  584. if (m & 0x00001000) != 0 {
  585. m += 0x00002000;
  586. if (m & 0x00800000) != 0 {
  587. m = 0;
  588. e += 1;
  589. }
  590. }
  591. if (e > 30) {
  592. f := 1e12;
  593. for j := 0; j < 10; j += 1 {
  594. /* NOTE(bill): Cause overflow */
  595. g := intrinsics.volatile_load(&f);
  596. g *= g;
  597. intrinsics.volatile_store(&f, g);
  598. }
  599. return u16(s | 0x7c00);
  600. }
  601. return u16(s | (e << 10) | (m >> 13));
  602. }
  603. }
  604. @(link_name="__truncdfhf2")
  605. truncdfhf2 :: proc "c" (value: f64) -> u16 {
  606. return truncsfhf2(f32(value));
  607. }
  608. @(link_name="__gnu_h2f_ieee")
  609. gnu_h2f_ieee :: proc "c" (value: u16) -> f32 {
  610. fp32 :: struct #raw_union { u: u32, f: f32 };
  611. v: fp32;
  612. magic, inf_or_nan: fp32;
  613. magic.u = u32((254 - 15) << 23);
  614. inf_or_nan.u = u32((127 + 16) << 23);
  615. v.u = u32(value & 0x7fff) << 13;
  616. v.f *= magic.f;
  617. if v.f >= inf_or_nan.f {
  618. v.u |= 255 << 23;
  619. }
  620. v.u |= u32(value & 0x8000) << 16;
  621. return v.f;
  622. }
  623. @(link_name="__gnu_f2h_ieee")
  624. gnu_f2h_ieee :: proc "c" (value: f32) -> u16 {
  625. return truncsfhf2(value);
  626. }
  627. @(link_name="__extendhfsf2")
  628. extendhfsf2 :: proc "c" (value: u16) -> f32 {
  629. return gnu_h2f_ieee(value);
  630. }