old_runtime.odin 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. #include "win32.odin"
  2. assume :: proc(cond: bool) #foreign "llvm.assume"
  3. __debug_trap :: proc() #foreign "llvm.debugtrap"
  4. __trap :: proc() #foreign "llvm.trap"
  5. read_cycle_counter :: proc() -> u64 #foreign "llvm.readcyclecounter"
  6. bit_reverse16 :: proc(b: u16) -> u16 #foreign "llvm.bitreverse.i16"
  7. bit_reverse32 :: proc(b: u32) -> u32 #foreign "llvm.bitreverse.i32"
  8. bit_reverse64 :: proc(b: u64) -> u64 #foreign "llvm.bitreverse.i64"
  9. byte_swap16 :: proc(b: u16) -> u16 #foreign "llvm.bswap.i16"
  10. byte_swap32 :: proc(b: u32) -> u32 #foreign "llvm.bswap.i32"
  11. byte_swap64 :: proc(b: u64) -> u64 #foreign "llvm.bswap.i64"
  12. fmuladd_f32 :: proc(a, b, c: f32) -> f32 #foreign "llvm.fmuladd.f32"
  13. fmuladd_f64 :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64"
  14. // TODO(bill): make custom heap procedures
  15. heap_alloc :: proc(len: int) -> rawptr #foreign "malloc"
  16. heap_dealloc :: proc(ptr: rawptr) #foreign "free"
  17. memory_zero :: proc(data: rawptr, len: int) {
  18. d := slice_ptr(data as ^byte, len)
  19. for i := 0; i < len; i++ {
  20. d[i] = 0
  21. }
  22. }
  23. memory_compare :: proc(dst, src: rawptr, len: int) -> int {
  24. s1, s2: ^byte = dst, src
  25. for i := 0; i < len; i++ {
  26. a := ptr_offset(s1, i)^
  27. b := ptr_offset(s2, i)^
  28. if a != b {
  29. return (a - b) as int
  30. }
  31. }
  32. return 0
  33. }
  34. memory_copy :: proc(dst, src: rawptr, n: int) #inline {
  35. if dst == src {
  36. return
  37. }
  38. v128b :: type {4}u32
  39. #assert(align_of(v128b) == 16)
  40. d, s: ^byte = dst, src
  41. for ; s as uint % 16 != 0 && n != 0; n-- {
  42. d^ = s^
  43. d, s = ptr_offset(d, 1), ptr_offset(s, 1)
  44. }
  45. if d as uint % 16 == 0 {
  46. for ; n >= 16; d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16 {
  47. (d as ^v128b)^ = (s as ^v128b)^
  48. }
  49. if n&8 != 0 {
  50. (d as ^u64)^ = (s as ^u64)^
  51. d, s = ptr_offset(d, 8), ptr_offset(s, 8)
  52. }
  53. if n&4 != 0 {
  54. (d as ^u32)^ = (s as ^u32)^;
  55. d, s = ptr_offset(d, 4), ptr_offset(s, 4)
  56. }
  57. if n&2 != 0 {
  58. (d as ^u16)^ = (s as ^u16)^
  59. d, s = ptr_offset(d, 2), ptr_offset(s, 2)
  60. }
  61. if n&1 != 0 {
  62. d^ = s^
  63. d, s = ptr_offset(d, 1), ptr_offset(s, 1)
  64. }
  65. return;
  66. }
  67. // IMPORTANT NOTE(bill): Little endian only
  68. LS :: proc(a, b: u32) -> u32 #inline { return a << b }
  69. RS :: proc(a, b: u32) -> u32 #inline { return a >> b }
  70. /* NOTE(bill): Big endian version
  71. LS :: proc(a, b: u32) -> u32 #inline { return a >> b; }
  72. RS :: proc(a, b: u32) -> u32 #inline { return a << b; }
  73. */
  74. w, x: u32
  75. if d as uint % 4 == 1 {
  76. w = (s as ^u32)^
  77. d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1)
  78. d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1)
  79. d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1)
  80. n -= 3
  81. for n > 16 {
  82. d32 := d as ^u32
  83. s32 := ptr_offset(s, 1) as ^u32
  84. x = s32^; d32^ = LS(w, 24) | RS(x, 8)
  85. d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
  86. w = s32^; d32^ = LS(x, 24) | RS(w, 8)
  87. d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
  88. x = s32^; d32^ = LS(w, 24) | RS(x, 8)
  89. d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
  90. w = s32^; d32^ = LS(x, 24) | RS(w, 8)
  91. d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
  92. d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16
  93. }
  94. } else if d as uint % 4 == 2 {
  95. w = (s as ^u32)^
  96. d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1)
  97. d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1)
  98. n -= 2
  99. for n > 17 {
  100. d32 := d as ^u32
  101. s32 := ptr_offset(s, 2) as ^u32
  102. x = s32^; d32^ = LS(w, 16) | RS(x, 16)
  103. d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
  104. w = s32^; d32^ = LS(x, 16) | RS(w, 16)
  105. d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
  106. x = s32^; d32^ = LS(w, 16) | RS(x, 16)
  107. d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
  108. w = s32^; d32^ = LS(x, 16) | RS(w, 16)
  109. d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
  110. d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16
  111. }
  112. } else if d as uint % 4 == 3 {
  113. w = (s as ^u32)^
  114. d^ = s^
  115. n -= 1
  116. for n > 18 {
  117. d32 := d as ^u32
  118. s32 := ptr_offset(s, 3) as ^u32
  119. x = s32^; d32^ = LS(w, 8) | RS(x, 24)
  120. d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
  121. w = s32^; d32^ = LS(x, 8) | RS(w, 24)
  122. d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
  123. x = s32^; d32^ = LS(w, 8) | RS(x, 24)
  124. d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
  125. w = s32^; d32^ = LS(x, 8) | RS(w, 24)
  126. d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
  127. d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16
  128. }
  129. }
  130. if n&16 != 0 {
  131. (d as ^v128b)^ = (s as ^v128b)^
  132. d, s = ptr_offset(d, 16), ptr_offset(s, 16)
  133. }
  134. if n&8 != 0 {
  135. (d as ^u64)^ = (s as ^u64)^
  136. d, s = ptr_offset(d, 8), ptr_offset(s, 8)
  137. }
  138. if n&4 != 0 {
  139. (d as ^u32)^ = (s as ^u32)^;
  140. d, s = ptr_offset(d, 4), ptr_offset(s, 4)
  141. }
  142. if n&2 != 0 {
  143. (d as ^u16)^ = (s as ^u16)^
  144. d, s = ptr_offset(d, 2), ptr_offset(s, 2)
  145. }
  146. if n&1 != 0 {
  147. d^ = s^
  148. }
  149. }
  150. memory_move :: proc(dst, src: rawptr, n: int) #inline {
  151. d, s: ^byte = dst, src
  152. if d == s {
  153. return
  154. }
  155. if d >= ptr_offset(s, n) || ptr_offset(d, n) <= s {
  156. memory_copy(d, s, n)
  157. return
  158. }
  159. // TODO(bill): Vectorize the shit out of this
  160. if d < s {
  161. if s as int % size_of(int) == d as int % size_of(int) {
  162. for d as int % size_of(int) != 0 {
  163. if n == 0 {
  164. return
  165. }
  166. n--
  167. d^ = s^
  168. d, s = ptr_offset(d, 1), ptr_offset(s, 1)
  169. }
  170. di, si := d as ^int, s as ^int
  171. for n >= size_of(int) {
  172. di^ = si^
  173. di, si = ptr_offset(di, 1), ptr_offset(si, 1)
  174. n -= size_of(int)
  175. }
  176. }
  177. for ; n > 0; n-- {
  178. d^ = s^
  179. d, s = ptr_offset(d, 1), ptr_offset(s, 1)
  180. }
  181. } else {
  182. if s as int % size_of(int) == d as int % size_of(int) {
  183. for ptr_offset(d, n) as int % size_of(int) != 0 {
  184. if n == 0 {
  185. return
  186. }
  187. n--
  188. d^ = s^
  189. d, s = ptr_offset(d, 1), ptr_offset(s, 1)
  190. }
  191. for n >= size_of(int) {
  192. n -= size_of(int)
  193. di := ptr_offset(d, n) as ^int
  194. si := ptr_offset(s, n) as ^int
  195. di^ = si^
  196. }
  197. for ; n > 0; n-- {
  198. d^ = s^
  199. d, s = ptr_offset(d, 1), ptr_offset(s, 1)
  200. }
  201. }
  202. for n > 0 {
  203. n--
  204. dn := ptr_offset(d, n)
  205. sn := ptr_offset(s, n)
  206. dn^ = sn^
  207. }
  208. }
  209. }
  210. __string_eq :: proc(a, b: string) -> bool {
  211. if len(a) != len(b) {
  212. return false
  213. }
  214. if ^a[0] == ^b[0] {
  215. return true
  216. }
  217. return memory_compare(^a[0], ^b[0], len(a)) == 0
  218. }
  219. __string_cmp :: proc(a, b : string) -> int {
  220. min_len := len(a)
  221. if len(b) < min_len {
  222. min_len = len(b)
  223. }
  224. for i := 0; i < min_len; i++ {
  225. x := a[i]
  226. y := b[i]
  227. if x < y {
  228. return -1
  229. } else if x > y {
  230. return +1
  231. }
  232. }
  233. if len(a) < len(b) {
  234. return -1
  235. } else if len(a) > len(b) {
  236. return +1
  237. }
  238. return 0
  239. }
  240. __string_ne :: proc(a, b : string) -> bool #inline { return !__string_eq(a, b) }
  241. __string_lt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) < 0 }
  242. __string_gt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) > 0 }
  243. __string_le :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) <= 0 }
  244. __string_ge :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) >= 0 }
  245. Allocation_Mode :: type enum {
  246. ALLOC,
  247. DEALLOC,
  248. DEALLOC_ALL,
  249. RESIZE,
  250. }
  251. Allocator_Proc :: type proc(allocator_data: rawptr, mode: Allocation_Mode,
  252. size, alignment: int,
  253. old_memory: rawptr, old_size: int, flags: u64) -> rawptr
  254. Allocator :: type struct {
  255. procedure: Allocator_Proc;
  256. data: rawptr
  257. }
  258. Context :: type struct {
  259. thread_ptr: rawptr
  260. user_data: rawptr
  261. user_index: int
  262. allocator: Allocator
  263. }
  264. #thread_local context: Context
  265. DEFAULT_ALIGNMENT :: 2*size_of(int)
  266. __check_context :: proc() {
  267. if context.allocator.procedure == null {
  268. context.allocator = __default_allocator()
  269. }
  270. if context.thread_ptr == null {
  271. // TODO(bill):
  272. // context.thread_ptr = current_thread_pointer()
  273. }
  274. }
  275. alloc :: proc(size: int) -> rawptr #inline { return alloc_align(size, DEFAULT_ALIGNMENT) }
  276. alloc_align :: proc(size, alignment: int) -> rawptr #inline {
  277. __check_context()
  278. a := context.allocator
  279. return a.procedure(a.data, Allocation_Mode.ALLOC, size, alignment, null, 0, 0)
  280. }
  281. dealloc :: proc(ptr: rawptr) #inline {
  282. __check_context()
  283. a := context.allocator
  284. _ = a.procedure(a.data, Allocation_Mode.DEALLOC, 0, 0, ptr, 0, 0)
  285. }
  286. dealloc_all :: proc(ptr: rawptr) #inline {
  287. __check_context()
  288. a := context.allocator
  289. _ = a.procedure(a.data, Allocation_Mode.DEALLOC_ALL, 0, 0, ptr, 0, 0)
  290. }
  291. resize :: proc(ptr: rawptr, old_size, new_size: int) -> rawptr #inline { return resize_align(ptr, old_size, new_size, DEFAULT_ALIGNMENT) }
  292. resize_align :: proc(ptr: rawptr, old_size, new_size, alignment: int) -> rawptr #inline {
  293. __check_context()
  294. a := context.allocator
  295. return a.procedure(a.data, Allocation_Mode.RESIZE, new_size, alignment, ptr, old_size, 0)
  296. }
  297. default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int) -> rawptr {
  298. if old_memory == null {
  299. return alloc_align(new_size, alignment)
  300. }
  301. if new_size == 0 {
  302. dealloc(old_memory)
  303. return null
  304. }
  305. if new_size == old_size {
  306. return old_memory
  307. }
  308. new_memory := alloc_align(new_size, alignment)
  309. if new_memory == null {
  310. return null
  311. }
  312. memory_copy(new_memory, old_memory, min(old_size, new_size));
  313. dealloc(old_memory)
  314. return new_memory
  315. }
  316. __default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocation_Mode,
  317. size, alignment: int,
  318. old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
  319. using Allocation_Mode
  320. match mode {
  321. case ALLOC:
  322. return heap_alloc(size)
  323. case RESIZE:
  324. return default_resize_align(old_memory, old_size, size, alignment)
  325. case DEALLOC:
  326. heap_dealloc(old_memory)
  327. case DEALLOC_ALL:
  328. // NOTE(bill): Does nothing
  329. }
  330. return null
  331. }
  332. __default_allocator :: proc() -> Allocator {
  333. return Allocator{
  334. __default_allocator_proc,
  335. null,
  336. }
  337. }
  338. __assert :: proc(msg: string) {
  339. file_write(file_get_standard(File_Standard.ERROR), msg as []byte)
  340. // TODO(bill): Which is better?
  341. // __trap()
  342. __debug_trap()
  343. }