ir_util.mx raw
1 package main
2
3 import (
4 "git.smesh.lol/moxie/pkg/mxutil"
5 . "git.smesh.lol/moxie/pkg/types"
6 )
7
8 func lIndexByte(b []byte, c byte) (n int32) {
9 for i := int32(0); i < int32(len(b)); i++ {
10 if b[i] == c { return i }
11 }
12 return -1
13 }
14
15 func lIndex(s, sep []byte) (n int32) {
16 n := len(sep)
17 if n == 0 { return 0 }
18 if n > len(s) { return -1 }
19 c0 := sep[0]
20 for i := int32(0); i <= int32(len(s))-int32(n); i++ {
21 if s[i] == c0 {
22 match := true
23 for j := int32(1); j < int32(n); j++ {
24 if s[i+j] != sep[j] { match = false; break }
25 }
26 if match { return i }
27 }
28 }
29 return -1
30 }
31
32 func lTrimSpace(s []byte) (buf []byte) {
33 start := int32(0)
34 for start < int32(len(s)) && (s[start] == ' ' || s[start] == '\t' || s[start] == '\n' || s[start] == '\r') {
35 start++
36 }
37 stop := int32(len(s))
38 for stop > start && (s[stop-1] == ' ' || s[stop-1] == '\t' || s[stop-1] == '\n' || s[stop-1] == '\r') {
39 stop--
40 }
41 return s[start:stop]
42 }
43
44 func lHasPrefix(s, prefix []byte) (ok bool) {
45 if len(s) < len(prefix) { return false }
46 for i := int32(0); i < int32(len(prefix)); i++ {
47 if s[i] != prefix[i] { return false }
48 }
49 return true
50 }
51
52
53 func sortedKeys(m map[string]bool) (ss []string) {
54 var keys []string
55 for k := range m {
56 push(keys, k)
57 }
58 for i := 1; i < len(keys); i++ {
59 for j := i; j > 0 && keys[j] < keys[j-1]; j-- {
60 keys[j], keys[j-1] = keys[j-1], keys[j]
61 }
62 }
63 return keys
64 }
65
66
67 func safeSSAName(v SSAValue) (s string) {
68 switch v.(type) {
69 case *SSAAlloc:
70 return v.SSAName()
71 case *SSABinOp:
72 return v.SSAName()
73 case *SSAUnOp:
74 return v.SSAName()
75 case *SSACall:
76 return v.SSAName()
77 case *SSAConst:
78 return v.SSAName()
79 case *SSAConvert:
80 return v.SSAName()
81 case *SSAChangeType:
82 return v.SSAName()
83 case *SSAFieldAddr:
84 return v.SSAName()
85 case *SSAIndexAddr:
86 return v.SSAName()
87 case *SSAExtract:
88 return v.SSAName()
89 case *SSAGlobal:
90 return v.SSAName()
91 case *SSAFunction:
92 return v.SSAName()
93 case *SSAFreeVar:
94 return v.SSAName()
95 case *SSAMakeInterface:
96 return v.SSAName()
97 case *SSAMakeClosure:
98 return v.SSAName()
99 case *SSAMakeSlice:
100 return v.SSAName()
101 case *SSAMakeMap:
102 return v.SSAName()
103 case *SSAMakeChan:
104 return v.SSAName()
105 case *SSASlice:
106 return v.SSAName()
107 case *SSATypeAssert:
108 return v.SSAName()
109 case *SSAPhi:
110 return v.SSAName()
111 case *SSASelect:
112 return v.SSAName()
113 case *SSALookup:
114 return v.SSAName()
115 case *SSARange:
116 return v.SSAName()
117 case *SSANext:
118 return v.SSAName()
119 case *SSABuiltin:
120 return v.SSAName()
121 case *SSAInvoke:
122 return v.SSAName()
123 }
124 mxutil.WriteStr(2, "BUG: unknown SSAValue type in safeSSAName\n")
125 return "UNKNOWN"
126 }
127
128
129 func irEscapeString(s string) (sv string) {
130 var buf []byte
131 for i := 0; i < len(s); i++ {
132 c := s[i]
133 if c >= 32 && c < 127 && c != '\\' && c != '"' {
134 push(buf, c)
135 } else {
136 push(buf, '\\')
137 push(buf, "0123456789ABCDEF"[c>>4])
138 push(buf, "0123456789ABCDEF"[c&0xf])
139 }
140 }
141 return string(buf)
142 }
143
144
145 func irNeedsQuote(s string) (ok bool) {
146 for i := 0; i < len(s); i++ {
147 c := s[i]
148 if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '.' || c == '_' || c == '$' {
149 continue
150 }
151 return true
152 }
153 return false
154 }
155
156 func irGlobalSymbol(pkg, name string) (s string) {
157 sym := pkg | "." | name
158 if irNeedsQuote(sym) {
159 return "@\"" | sym | "\""
160 }
161 return "@" | sym
162 }
163
164
165 func needsSret(retType string) (ok bool) {
166 return false
167 }
168
169
170 func parseStructFields(s string) (ss []string) {
171 if len(s) < 2 || s[0] != '{' || s[len(s)-1] != '}' {
172 return nil
173 }
174 inner := s[1 : len(s)-1]
175 var fields []string
176 depth := 0
177 start := int32(0)
178 for i := int32(0); i < int32(len(inner)); i++ {
179 switch inner[i] {
180 case '{':
181 depth++
182 case '}':
183 depth--
184 case ',':
185 if depth == 0 {
186 fv := llvmTrimSpace(string(inner[start:i]))
187 push(fields, fv)
188 start = i + 1
189 }
190 }
191 }
192 f := llvmTrimSpace(string(inner[start:]))
193 if f != "" {
194 push(fields, f)
195 }
196 return fields
197 }
198
199 func llvmTrimSpace(s string) (sv string) {
200 i := int32(0)
201 for i < int32(len(s)) && s[i] == ' ' {
202 i++
203 }
204 j := int32(len(s))
205 for j > i && s[j-1] == ' ' {
206 j--
207 }
208 return string(s[i:j])
209 }
210
211
212 func looksLikeFloat(s string) (ok bool) {
213 if len(s) == 0 {
214 return false
215 }
216 if s[0] != '-' && s[0] != '+' && (s[0] < '0' || s[0] > '9') {
217 return false
218 }
219 for i := 0; i < len(s); i++ {
220 if s[i] == '.' || s[i] == 'e' || s[i] == 'E' {
221 return true
222 }
223 }
224 return false
225 }
226
227 func floatLitToInt(s string) (v int64, ok bool) {
228 if len(s) == 0 {
229 return 0, false
230 }
231 i := 0
232 neg := false
233 if s[0] == '-' {
234 neg = true
235 i = 1
236 } else if s[0] == '+' {
237 i = 1
238 }
239 var intPart int64
240 for ; i < len(s); i++ {
241 ch := s[i]
242 if ch == '_' {
243 continue
244 }
245 if ch < '0' || ch > '9' {
246 break
247 }
248 intPart = intPart*10 + int64(ch-'0')
249 }
250 var fracDigits int32
251 if i < len(s) && s[i] == '.' {
252 i++
253 for ; i < len(s); i++ {
254 ch := s[i]
255 if ch == '_' {
256 continue
257 }
258 if ch < '0' || ch > '9' {
259 break
260 }
261 if ch != '0' {
262 return 0, false
263 }
264 fracDigits++
265 }
266 }
267 _ = fracDigits
268 exp := 0
269 if i < len(s) && (s[i] == 'e' || s[i] == 'E') {
270 i++
271 expNeg := false
272 if i < len(s) && s[i] == '-' {
273 expNeg = true
274 i++
275 } else if i < len(s) && s[i] == '+' {
276 i++
277 }
278 for ; i < len(s); i++ {
279 ch := s[i]
280 if ch < '0' || ch > '9' {
281 break
282 }
283 exp = exp*10 + int32(ch-'0')
284 }
285 if expNeg {
286 return 0, false
287 }
288 }
289 result := intPart
290 for j := 0; j < exp; j++ {
291 result = result * 10
292 if result < 0 {
293 return 0, false
294 }
295 }
296 if neg {
297 result = -result
298 }
299 if result == 0 {
300 return 0, false
301 }
302 return result, true
303 }
304
305 func isConstOperand(s string) (ok bool) {
306 if len(s) == 0 {
307 return false
308 }
309 return s[0] != '%' && s[0] != '@'
310 }
311
312 func ensureFloatLit(s string) (sv string) {
313 if len(s) == 0 || s[0] == '%' || s[0] == '@' {
314 return s
315 }
316 if len(s) >= 2 && s[0] == '0' && s[1] == 'x' {
317 return s
318 }
319 hasDecimal := false
320 for i := 0; i < len(s); i++ {
321 if s[i] == '.' || s[i] == 'e' || s[i] == 'E' {
322 hasDecimal = true
323 break
324 }
325 }
326 if !hasDecimal {
327 return s | ".0"
328 }
329 return s
330 }
331
332
333 func isBareLiteral(s string) (ok bool) {
334 if len(s) == 0 { return false }
335 return s[0] >= '0' && s[0] <= '9'
336 }
337
338
339 func parseArrayType(lt string) (count int32, elem string) {
340 if len(lt) < 5 || lt[0] != '[' {
341 return 0, ""
342 }
343 i := 1
344 for i < len(lt) && lt[i] >= '0' && lt[i] <= '9' {
345 i++
346 }
347 n := 0
348 for j := 1; j < i; j++ {
349 n = n*10 + int32(lt[j]-'0')
350 }
351 if i+3 >= len(lt) || lt[i] != ' ' || lt[i+1] != 'x' || lt[i+2] != ' ' {
352 return 0, ""
353 }
354 et := lt[i+3 : len(lt)-1]
355 return n, et
356 }
357
358
359 func isNumericLiteral(s string) (ok bool) {
360 if len(s) == 0 {
361 return false
362 }
363 c := s[0]
364 if c == '-' && len(s) > 1 {
365 c = s[1]
366 }
367 return c >= '0' && c <= '9'
368 }
369
370
371 func blockHasReturn(b *SSABasicBlock) (ok bool) {
372 for _, instr := range b.Instrs {
373 if _, ok2 := instr.(*SSAReturn); ok2 {
374 return true
375 }
376 }
377 return false
378 }
379
380
381 func isComparisonOp(op SSAOp) (ok bool) {
382 return op == OpEql || op == OpNeq || op == OpLss || op == OpLeq || op == OpGtr || op == OpGeq
383 }
384
385
386 func extractTupleField(tupType string, index int32) (s string) {
387 if len(tupType) < 3 || tupType[0] != '{' {
388 return ""
389 }
390 inner := tupType[1 : len(tupType)-1]
391 depth := 0
392 field := 0
393 start := 0
394 for i := 0; i < len(inner); i++ {
395 c := inner[i]
396 if c == '{' {
397 depth++
398 } else if c == '}' {
399 depth--
400 } else if c == ',' && depth == 0 {
401 if field == index {
402 sv := inner[start:i]
403 for len(sv) > 0 && sv[0] == ' ' { sv = sv[1:] }
404 for len(sv) > 0 && sv[len(sv)-1] == ' ' { sv = sv[:len(sv)-1] }
405 return sv
406 }
407 field++
408 start = i + 1
409 }
410 }
411 if field == index {
412 sv := inner[start:]
413 for len(sv) > 0 && sv[0] == ' ' { sv = sv[1:] }
414 for len(sv) > 0 && sv[len(sv)-1] == ' ' { sv = sv[:len(sv)-1] }
415 return sv
416 }
417 return ""
418 }
419
420
421 func fnv1a64(s string) (h uint64) {
422 h = 14695981039346656037
423 for i := 0; i < len(s); i++ {
424 h = h ^ uint64(s[i])
425 h = h * 1099511628211
426 }
427 return h
428 }
429
430 // hashToIntptr folds a 64-bit FNV-1a hash to intptr width (32-bit on wasm32).
431
432 func irUitoa64(v uint64) (s string) {
433 if v == 0 {
434 return "0"
435 }
436 var buf [20]byte
437 i := 19
438 for v > 0 {
439 buf[i] = byte(v%10) + '0'
440 v = v / 10
441 i--
442 }
443 return string(buf[i+1:])
444 }
445
446
447 func underlyingBasic(t Type) (b *Basic) {
448 if t == nil {
449 return nil
450 }
451 u := SafeUnderlying(t)
452 if u == nil {
453 return nil
454 }
455 b, ok := u.(*Basic)
456 if !ok {
457 return nil
458 }
459 return b
460 }
461
462 func newTCPackageWithUniverse(path, name string) (t *TCPackage) {
463 return &TCPackage{
464 Path: path,
465 Name: name,
466 Scope: NewScope(Universe),
467 }
468 }
469
470 func irParseIntWidth(t string) (n int32) {
471 if len(t) < 2 || t[0] != 'i' {
472 return 0
473 }
474 n := 0
475 for i := 1; i < len(t); i++ {
476 if t[i] < '0' || t[i] > '9' {
477 return 0
478 }
479 n = n*10 + int32(t[i]-'0')
480 }
481 return n
482 }
483
484
485 func irItoa(n int32) (s string) {
486 if n == 0 {
487 return "0"
488 }
489 neg := n < 0
490 if neg {
491 n = -n
492 }
493 buf := []byte{:0:20}
494 for n > 0 {
495 push(buf, byte('0'+n%10))
496 n /= 10
497 }
498 if neg {
499 push(buf, '-')
500 }
501 for i, j := 0, len(buf)-1; i < j; i, j = i+1, j-1 {
502 buf[i], buf[j] = buf[j], buf[i]
503 }
504 return string(buf)
505 }
506
507 func irItoa64(n int64) (s string) {
508 if n == 0 {
509 return "0"
510 }
511 neg := n < 0
512 if neg {
513 n = -n
514 }
515 if n < 0 {
516 return "-9223372036854775808"
517 }
518 buf := []byte{:0:20}
519 for n > 0 {
520 push(buf, byte('0'+n%10))
521 n /= 10
522 }
523 if neg {
524 push(buf, '-')
525 }
526 for i, j := 0, len(buf)-1; i < j; i, j = i+1, j-1 {
527 buf[i], buf[j] = buf[j], buf[i]
528 }
529 return string(buf)
530 }
531
532 func irHex64(v uint64) (s string) {
533 digits := "0123456789ABCDEF"
534 buf := []byte{:16}
535 for i := 15; i >= 0; i-- {
536 buf[i] = digits[v&0xf]
537 v >>= 4
538 }
539 return string(buf)
540 }
541
542 func irFtoa(f float64) (s string) {
543 return "0.0"
544 }
545
546 func irParseInt64(s string) (n int64) {
547 for i := 0; i < len(s); i++ {
548 c := s[i]
549 if c < '0' || c > '9' {
550 break
551 }
552 n = n*10 + int64(c-'0')
553 }
554 return n
555 }
556
557 func runeToUTF8(r rune) (s string) {
558 if r < 0 || r > 0x10FFFF {
559 r = 0xFFFD
560 }
561 var out []byte
562 if r <= 0x7F {
563 push(out, byte(r))
564 } else if r <= 0x7FF {
565 push(out, byte(0xC0|(r>>6)), byte(0x80|(r&0x3F)))
566 } else if r <= 0xFFFF {
567 push(out, byte(0xE0|(r>>12)), byte(0x80|((r>>6)&0x3F)), byte(0x80|(r&0x3F)))
568 } else {
569 push(out, byte(0xF0|(r>>18)), byte(0x80|((r>>12)&0x3F)), byte(0x80|((r>>6)&0x3F)), byte(0x80|(r&0x3F)))
570 }
571 return string(out)
572 }
573
574
575 func simpleItoa(n int32) (s string) {
576 if n == 0 {
577 return "0"
578 }
579 neg := n < 0
580 if neg {
581 n = -n
582 }
583 buf := []byte{:0:20}
584 for n > 0 {
585 push(buf, byte('0'+n%10))
586 n /= 10
587 }
588 if neg {
589 push(buf, '-')
590 }
591 for i, j := 0, len(buf)-1; i < j; i, j = i+1, j-1 {
592 buf[i], buf[j] = buf[j], buf[i]
593 }
594 return string(buf)
595 }
596
597 func simpleItoa64(n int64) (s string) {
598 if n == 0 {
599 return "0"
600 }
601 neg := n < 0
602 if neg {
603 n = -n
604 }
605 buf := []byte{:0:20}
606 for n > 0 {
607 push(buf, byte('0'+n%10))
608 n /= 10
609 }
610 if neg {
611 push(buf, '-')
612 }
613 for i, j := int32(0), len(buf)-1; i < j; i, j = i+1, j-1 {
614 buf[i], buf[j] = buf[j], buf[i]
615 }
616 return string(buf)
617 }
618
619