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