defer.mx raw

   1  package emit
   2  
   3  import (
   4  	"math"
   5  	"git.smesh.lol/moxie/pkg/syntax"
   6  	"git.smesh.lol/moxie/pkg/ssa"
   7  	"git.smesh.lol/moxie/pkg/token"
   8  	"git.smesh.lol/moxie/pkg/types"
   9  )
  10  
  11  func (e *irEmitter) operandNoSideEffect(v ssa.SSAValue) string {
  12  	if v == nil {
  13  		return "zeroinitializer"
  14  	}
  15  	if c, ok := v.(*ssa.SSAConst); ok {
  16  		return e.constOperand(c)
  17  	}
  18  	if n, ok := e.valName[v]; ok {
  19  		return n
  20  	}
  21  	return ""
  22  }
  23  
  24  func (e *irEmitter) operand(v ssa.SSAValue) string {
  25  	if v == nil {
  26  		return "zeroinitializer"
  27  	}
  28  	if c, ok := v.(*ssa.SSAConst); ok {
  29  		return e.constOperand(c)
  30  	}
  31  	if b, ok := v.(*ssa.SSABuiltin); ok {
  32  		return "@runtime." | b.SSAName()
  33  	}
  34  	if f, ok := v.(*ssa.SSAFunction); ok {
  35  		e.declareExternalFunc(f)
  36  		return "{ ptr null, ptr " | e.funcSymbol(f) | " }"
  37  	}
  38  	if g, ok := v.(*ssa.SSAGlobal); ok {
  39  		e.declareExternalGlobal(g)
  40  		return e.globalName(g)
  41  	}
  42  	return e.regName(v)
  43  }
  44  
  45  func (e *irEmitter) constOperand(c *ssa.SSAConst) string {
  46  	if c.Value() == nil {
  47  		if c.SSAType() == nil {
  48  			return "null"
  49  		}
  50  		typ := e.llvmType(c.SSAType())
  51  		if typ == "ptr" {
  52  			return "null"
  53  		}
  54  		if typ == "i1" {
  55  			return "false"
  56  		}
  57  		return "zeroinitializer"
  58  	}
  59  	b := underlyingBasic(c.SSAType())
  60  	if b != nil {
  61  		switch b.Kind() {
  62  		case types.Bool, types.UntypedBool:
  63  			if cb, ok := c.Value().(*types.ConstBool); ok {
  64  				if cb.V {
  65  					return "true"
  66  				}
  67  				return "false"
  68  			}
  69  			s := c.Value().String()
  70  			if s == "true" {
  71  				return "true"
  72  			}
  73  			return "false"
  74  		case types.Int8, types.Int16, types.Int32, types.Int64, types.Uint8, types.Uint16, types.Uint32, types.Uint64,
  75  			types.UntypedInt, types.UntypedRune:
  76  			if ci, ok := c.Value().(*types.ConstInt); ok {
  77  				v := ci.V
  78  				switch b.Kind() {
  79  				case types.Int8:
  80  					v = int64(int8(v))
  81  				case types.Uint8:
  82  					v = int64(uint8(v))
  83  				case types.Int16:
  84  					v = int64(int16(v))
  85  				case types.Uint16:
  86  					v = int64(uint16(v))
  87  				case types.Int32:
  88  					v = int64(int32(v))
  89  				case types.Uint32:
  90  					v = int64(uint32(v))
  91  				case types.UntypedInt, types.UntypedRune:
  92  					if v < -2147483648 || v > 4294967295 {
  93  						e.allocTypes[c] = "i64"
  94  					}
  95  				}
  96  				return irItoa64(v)
  97  			}
  98  			if cf, ok := c.Value().(*types.ConstFloat); ok {
  99  				if len(cf.Lit) > 0 {
 100  					return irItoa64(parseIntFromTokenFloatLit(cf.Lit))
 101  				}
 102  				return irItoa64(int64(cf.V))
 103  			}
 104  			return c.Value().String()
 105  		case types.Float32:
 106  			if cf, ok := c.Value().(*types.ConstFloat); ok {
 107  				if len(cf.Lit) > 0 {
 108  					return floatLitForLLVM(cf.Lit)
 109  				}
 110  				bits := math.Float64bits(float64(float32(cf.V)))
 111  				return "0x" | irHex64(bits)
 112  			}
 113  			return "0.0"
 114  		case types.Float64, types.UntypedFloat:
 115  			if cf, ok := c.Value().(*types.ConstFloat); ok {
 116  				if len(cf.Lit) > 0 {
 117  					return floatLitForLLVM(cf.Lit)
 118  				}
 119  				bits := math.Float64bits(cf.V)
 120  				return "0x" | irHex64(bits)
 121  			}
 122  			return c.Value().String()
 123  		case types.TCString, types.UntypedString:
 124  			if cs, ok := c.Value().(*types.ConstStr); ok {
 125  				if len(cs.S) == 0 {
 126  					return "zeroinitializer"
 127  				}
 128  				idx := e.addStringConst(cs.S)
 129  				ipt := e.intptrType()
 130  				slen := irItoa64(int64(len(cs.S)))
 131  				return "{ ptr " | e.strConstGlobal(idx) | ", " | ipt | " " | slen | ", " | ipt | " " | slen | " }"
 132  			}
 133  			return "zeroinitializer"
 134  		}
 135  	}
 136  	if c.SSAType() == nil {
 137  		return c.Value().String()
 138  	}
 139  	return "zeroinitializer"
 140  }
 141  
 142  func underlyingBasic(t syntax.Type) *types.Basic {
 143  	if t == nil {
 144  		return nil
 145  	}
 146  	u := types.SafeUnderlying(t)
 147  	if u == nil {
 148  		return nil
 149  	}
 150  	b, ok := u.(*types.Basic)
 151  	if !ok {
 152  		return nil
 153  	}
 154  	return b
 155  }
 156  
 157  func newTCPackageWithUniverse(path, name string) *types.TCPackage {
 158  	return types.NewTCPackageWithParent(path, name, types.Universe)
 159  }
 160  
 161  func irParseIntWidth(t string) int32 {
 162  	if len(t) < 2 || t[0] != 'i' {
 163  		return 0
 164  	}
 165  	n := 0
 166  	for i := 1; i < len(t); i++ {
 167  		if t[i] < '0' || t[i] > '9' {
 168  			return 0
 169  		}
 170  		n = n*10 + int32(t[i]-'0')
 171  	}
 172  	return n
 173  }
 174  
 175  func (e *irEmitter) deferRetType(d *ssa.SSADefer) string {
 176  	if fn, ok := d.Call.Value.(*ssa.SSAFunction); ok {
 177  		if fn.Signature == nil {
 178  			return "void"
 179  		}
 180  		r := fn.Signature.Results()
 181  		if r == nil {
 182  			return "void"
 183  		}
 184  		return e.llvmType(r)
 185  	}
 186  	t := d.Call.Value.SSAType()
 187  	if t == nil {
 188  		return "void"
 189  	}
 190  	u := types.SafeUnderlying(t)
 191  	if sig, ok := u.(*types.Signature); ok {
 192  		r := sig.Results()
 193  		if r == nil || r.Len() == 0 {
 194  			return "void"
 195  		}
 196  		return e.llvmType(r)
 197  	}
 198  	return "void"
 199  }
 200  
 201  func (e *irEmitter) deferArgType(arg ssa.SSAValue) string {
 202  	t := e.llvmType(arg.SSAType())
 203  	if t == "void" {
 204  		return "ptr"
 205  	}
 206  	return t
 207  }
 208  
 209  func (e *irEmitter) deferIsDirectCall(d *ssa.SSADefer) bool {
 210  	if _, ok := d.Call.Value.(*ssa.SSAFunction); ok {
 211  		return true
 212  	}
 213  	if _, ok := d.Call.Value.(*ssa.SSABuiltin); ok {
 214  		return true
 215  	}
 216  	return false
 217  }
 218  
 219  func (e *irEmitter) deferStructType(d *ssa.SSADefer) string {
 220  	ipt := e.intptrType()
 221  	s := "{" | ipt | ", ptr"
 222  	if !e.deferIsDirectCall(d) {
 223  		s = s | ", {ptr, ptr}"
 224  	}
 225  	for _, arg := range d.Call.Args {
 226  		s = s | ", " | e.deferArgType(arg)
 227  	}
 228  	return s | "}"
 229  }
 230  
 231  func (e *irEmitter) emitDefer(d *ssa.SSADefer) {
 232  	idx := -1
 233  	for i, dd := range e.deferList {
 234  		if dd == d {
 235  			idx = i
 236  			break
 237  		}
 238  	}
 239  	if idx < 0 {
 240  		e.w("  ; defer: not found in list\n")
 241  		return
 242  	}
 243  	ipt := e.intptrType()
 244  	id := e.deferID
 245  	e.deferID++
 246  	pfx := "%df" | irItoa(id) | "."
 247  	sty := e.deferStructType(d)
 248  
 249  	e.w("  ") ; e.w(pfx) ; e.w("a = alloca ") ; e.w(sty) ; e.w("\n")
 250  
 251  	cbGep := pfx | "cb"
 252  	e.w("  ") ; e.w(cbGep) ; e.w(" = getelementptr inbounds ") ; e.w(sty)
 253  	e.w(", ptr ") ; e.w(pfx) ; e.w("a, i32 0, i32 0\n")
 254  	e.w("  store ") ; e.w(ipt) ; e.w(" ") ; e.w(irItoa(idx))
 255  	e.w(", ptr ") ; e.w(cbGep) ; e.w("\n")
 256  
 257  	nxGep := pfx | "nx"
 258  	e.w("  ") ; e.w(nxGep) ; e.w(" = getelementptr inbounds ") ; e.w(sty)
 259  	e.w(", ptr ") ; e.w(pfx) ; e.w("a, i32 0, i32 1\n")
 260  	prev := pfx | "prev"
 261  	e.w("  ") ; e.w(prev) ; e.w(" = load ptr, ptr %deferPtr\n")
 262  	e.w("  store ptr ") ; e.w(prev) ; e.w(", ptr ") ; e.w(nxGep) ; e.w("\n")
 263  
 264  	fieldIdx := int32(2)
 265  	if !e.deferIsDirectCall(d) {
 266  		fvGep := pfx | "fv"
 267  		e.w("  ") ; e.w(fvGep) ; e.w(" = getelementptr inbounds ") ; e.w(sty)
 268  		e.w(", ptr ") ; e.w(pfx) ; e.w("a, i32 0, i32 ") ; e.w(irItoa(int32(fieldIdx))) ; e.w("\n")
 269  		fvOp := e.operand(d.Call.Value)
 270  		e.w("  store {ptr, ptr} ") ; e.w(fvOp)
 271  		e.w(", ptr ") ; e.w(fvGep) ; e.w("\n")
 272  		fieldIdx++
 273  	}
 274  
 275  	for i, arg := range d.Call.Args {
 276  		_ = i
 277  		aGep := pfx | "a" | irItoa(int32(fieldIdx))
 278  		e.w("  ") ; e.w(aGep) ; e.w(" = getelementptr inbounds ") ; e.w(sty)
 279  		e.w(", ptr ") ; e.w(pfx) ; e.w("a, i32 0, i32 ") ; e.w(irItoa(int32(fieldIdx))) ; e.w("\n")
 280  		at := e.deferArgType(arg)
 281  		av := e.operand(arg)
 282  		e.w("  store ") ; e.w(at) ; e.w(" ") ; e.w(av)
 283  		e.w(", ptr ") ; e.w(aGep) ; e.w("\n")
 284  		fieldIdx++
 285  	}
 286  
 287  	e.w("  store ptr ") ; e.w(pfx) ; e.w("a, ptr %deferPtr\n")
 288  }
 289  
 290  func (e *irEmitter) emitRunDefers() {
 291  	if len(e.deferList) == 0 {
 292  		return
 293  	}
 294  	ipt := e.intptrType()
 295  	id := e.deferID
 296  	e.deferID++
 297  	pfx := "rundefers" | irItoa(id)
 298  
 299  	e.w("  br label %") ; e.w(pfx) ; e.w(".head\n")
 300  	e.w(pfx) ; e.w(".head:\n")
 301  	e.w("  %") ; e.w(pfx) ; e.w(".cur = load ptr, ptr %deferPtr\n")
 302  	e.w("  %") ; e.w(pfx) ; e.w(".nil = icmp eq ptr %") ; e.w(pfx) ; e.w(".cur, null\n")
 303  	e.w("  br i1 %") ; e.w(pfx) ; e.w(".nil, label %") ; e.w(pfx) ; e.w(".end, label %")
 304  	e.w(pfx) ; e.w(".body\n")
 305  
 306  	e.w(pfx) ; e.w(".body:\n")
 307  	e.w("  %") ; e.w(pfx) ; e.w(".cb = load ") ; e.w(ipt) ; e.w(", ptr %") ; e.w(pfx) ; e.w(".cur\n")
 308  	nxGep := "%" | pfx | ".nxp"
 309  	e.w("  ") ; e.w(nxGep) ; e.w(" = getelementptr inbounds {") ; e.w(ipt) ; e.w(", ptr}, ptr %")
 310  	e.w(pfx) ; e.w(".cur, i32 0, i32 1\n")
 311  	e.w("  %") ; e.w(pfx) ; e.w(".nx = load ptr, ptr ") ; e.w(nxGep) ; e.w("\n")
 312  	e.w("  store ptr %") ; e.w(pfx) ; e.w(".nx, ptr %deferPtr\n")
 313  
 314  	for i, d := range e.deferList {
 315  		checkLabel := pfx | ".c" | irItoa(i)
 316  		callLabel := pfx | ".k" | irItoa(i)
 317  		var nextLabel string
 318  		if i+1 < len(e.deferList) {
 319  			nextLabel = pfx | ".c" | irItoa(i+1)
 320  		} else {
 321  			nextLabel = pfx | ".head"
 322  		}
 323  		if i == 0 {
 324  			e.w("  %") ; e.w(checkLabel) ; e.w(".eq = icmp eq ") ; e.w(ipt) ; e.w(" %")
 325  			e.w(pfx) ; e.w(".cb, 0\n")
 326  			e.w("  br i1 %") ; e.w(checkLabel) ; e.w(".eq, label %") ; e.w(callLabel)
 327  			e.w(", label %") ; e.w(nextLabel) ; e.w("\n")
 328  		} else {
 329  			e.w(checkLabel) ; e.w(":\n")
 330  			e.w("  %") ; e.w(checkLabel) ; e.w(".eq = icmp eq ") ; e.w(ipt) ; e.w(" %")
 331  			e.w(pfx) ; e.w(".cb, ") ; e.w(irItoa(i)) ; e.w("\n")
 332  			e.w("  br i1 %") ; e.w(checkLabel) ; e.w(".eq, label %") ; e.w(callLabel)
 333  			e.w(", label %") ; e.w(nextLabel) ; e.w("\n")
 334  		}
 335  
 336  		e.w(callLabel) ; e.w(":\n")
 337  		e.emitDeferDispatch(d, pfx, i)
 338  		e.w("  br label %") ; e.w(pfx) ; e.w(".head\n")
 339  	}
 340  
 341  	e.w(pfx) ; e.w(".end:\n")
 342  }
 343  
 344  func (e *irEmitter) emitDeferBuiltin(d *ssa.SSADefer, bi *ssa.SSABuiltin, pfx string, idx int32, sty string, dp string) {
 345  	fieldIdx := int32(2)
 346  	var args []string
 347  	var argTypes []string
 348  	for i, arg := range d.Call.Args {
 349  		aGep := "%" | pfx | ".da" | irItoa(idx) | "f" | irItoa(i)
 350  		e.w("  ") ; e.w(aGep) ; e.w(" = getelementptr inbounds ") ; e.w(sty)
 351  		e.w(", ptr ") ; e.w(dp) ; e.w(", i32 0, i32 ") ; e.w(irItoa(int32(fieldIdx))) ; e.w("\n")
 352  		at := e.deferArgType(arg)
 353  		aVal := "%" | pfx | ".dv" | irItoa(idx) | "f" | irItoa(i)
 354  		e.w("  ") ; e.w(aVal) ; e.w(" = load ") ; e.w(at) ; e.w(", ptr ") ; e.w(aGep) ; e.w("\n")
 355  		args = append(args, aVal)
 356  		argTypes = append(argTypes, at)
 357  		fieldIdx++
 358  	}
 359  	name := bi.SSAName()
 360  	if name == "close" && len(args) == 1 {
 361  		e.declareRuntime("runtime.chanClose", "void", "ptr")
 362  		e.w("  call void @runtime.chanClose(") ; e.w(argTypes[0]) ; e.w(" ") ; e.w(args[0]) ; e.w(")\n")
 363  	} else if name == "panic" && len(args) == 1 {
 364  		e.declareRuntime("runtime._panicstr", "void", argTypes[0])
 365  		e.w("  call void @runtime._panicstr(") ; e.w(argTypes[0]) ; e.w(" ") ; e.w(args[0]) ; e.w(")\n")
 366  	} else if name == "println" || name == "print" {
 367  		e.declareRuntime("runtime.printlock", "void", "")
 368  		e.declareRuntime("runtime.printunlock", "void", "")
 369  		e.declareRuntime("runtime.printnl", "void", "")
 370  		e.w("  call void @runtime.printlock()\n")
 371  		for ai, av := range args {
 372  			if ai > 0 {
 373  				e.declareRuntime("runtime.printspace", "void", "")
 374  				e.w("  call void @runtime.printspace()\n")
 375  			}
 376  			at := argTypes[ai]
 377  			if at == e.sliceType() || at == "{ptr, i64, i64}" || at == "{ptr, i32, i32}" {
 378  				e.declareRuntime("runtime.printstring", "void", e.sliceType())
 379  				e.w("  call void @runtime.printstring(") ; e.w(at) ; e.w(" ") ; e.w(av) ; e.w(")\n")
 380  			} else if at == "i1" {
 381  				e.declareRuntime("runtime.printbool", "void", "i1")
 382  				e.w("  call void @runtime.printbool(i1 ") ; e.w(av) ; e.w(")\n")
 383  			} else if at == "i32" || at == "i64" || at == "i16" || at == "i8" {
 384  				fname := "runtime.printint" | at[1:]
 385  				e.declareRuntime(fname, "void", at)
 386  				e.w("  call void @") ; e.w(fname) ; e.w("(") ; e.w(at) ; e.w(" ") ; e.w(av) ; e.w(")\n")
 387  			} else if at == "ptr" {
 388  				ipt := e.intptrType()
 389  				e.declareRuntime("runtime.printptr", "void", ipt)
 390  				tmp := "%" | pfx | ".ptmp" | irItoa(ai)
 391  				e.w("  ") ; e.w(tmp) ; e.w(" = ptrtoint ptr ") ; e.w(av) ; e.w(" to ") ; e.w(ipt) ; e.w("\n")
 392  				e.w("  call void @runtime.printptr(") ; e.w(ipt) ; e.w(" ") ; e.w(tmp) ; e.w(")\n")
 393  			}
 394  		}
 395  		if name == "println" {
 396  			e.w("  call void @runtime.printnl()\n")
 397  		}
 398  		e.w("  call void @runtime.printunlock()\n")
 399  	} else if name == "delete" && len(args) == 2 {
 400  		e.declareRuntime("runtime.hashmapBinaryDelete", "void", "ptr, ptr, i32")
 401  		e.w("  ; defer delete - not fully implemented\n")
 402  	} else if name == "recover" {
 403  		e.w("  ; defer recover() is a no-op\n")
 404  	} else {
 405  		e.w("  ; defer builtin ") ; e.w(name) ; e.w(" - not implemented\n")
 406  	}
 407  }
 408  
 409  func (e *irEmitter) emitDeferDispatch(d *ssa.SSADefer, pfx string, idx int32) {
 410  	sty := e.deferStructType(d)
 411  	dp := "%" | pfx | ".cur"
 412  
 413  	fieldIdx := int32(2)
 414  	if bi, isBi := d.Call.Value.(*ssa.SSABuiltin); isBi {
 415  		e.emitDeferBuiltin(d, bi, pfx, idx, sty, dp)
 416  		return
 417  	}
 418  	if fn, isFn := d.Call.Value.(*ssa.SSAFunction); isFn {
 419  		var args []string
 420  		var argTypes []string
 421  		for i, arg := range d.Call.Args {
 422  			aGep := "%" | pfx | ".da" | irItoa(idx) | "f" | irItoa(i)
 423  			e.w("  ") ; e.w(aGep) ; e.w(" = getelementptr inbounds ") ; e.w(sty)
 424  			e.w(", ptr ") ; e.w(dp) ; e.w(", i32 0, i32 ") ; e.w(irItoa(int32(fieldIdx))) ; e.w("\n")
 425  			at := e.deferArgType(arg)
 426  			aVal := "%" | pfx | ".dv" | irItoa(idx) | "f" | irItoa(i)
 427  			e.w("  ") ; e.w(aVal) ; e.w(" = load ") ; e.w(at) ; e.w(", ptr ") ; e.w(aGep) ; e.w("\n")
 428  			args = append(args, aVal)
 429  			argTypes = append(argTypes, at)
 430  			fieldIdx++
 431  		}
 432  		if !e.isPkgFunc(fn) {
 433  			e.declareExternalFunc(fn)
 434  		}
 435  		rt := e.deferRetType(d)
 436  		e.w("  call ") ; e.w(rt) ; e.w(" ") ; e.w(e.funcSymbol(fn)) ; e.w("(")
 437  		for i, av := range args {
 438  			if i > 0 { e.w(", ") }
 439  			e.w(argTypes[i]) ; e.w(" ") ; e.w(av)
 440  		}
 441  		if !fn.IsExternC() {
 442  			if len(args) > 0 { e.w(", ") }
 443  			e.w("ptr null")
 444  		}
 445  		e.w(")\n")
 446  	} else {
 447  		fvGep := "%" | pfx | ".dfv" | irItoa(idx)
 448  		e.w("  ") ; e.w(fvGep) ; e.w(" = getelementptr inbounds ") ; e.w(sty)
 449  		e.w(", ptr ") ; e.w(dp) ; e.w(", i32 0, i32 2\n")
 450  		fvVal := "%" | pfx | ".fvv" | irItoa(idx)
 451  		e.w("  ") ; e.w(fvVal) ; e.w(" = load {ptr, ptr}, ptr ") ; e.w(fvGep) ; e.w("\n")
 452  		fpReg := "%" | pfx | ".fp" | irItoa(idx)
 453  		ctxReg := "%" | pfx | ".ctx" | irItoa(idx)
 454  		e.w("  ") ; e.w(fpReg) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(fvVal) ; e.w(", 1\n")
 455  		e.w("  ") ; e.w(ctxReg) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(fvVal) ; e.w(", 0\n")
 456  		fieldIdx = 3
 457  		var args []string
 458  		var argTypes []string
 459  		for i, arg := range d.Call.Args {
 460  			aGep := "%" | pfx | ".da" | irItoa(idx) | "f" | irItoa(i)
 461  			e.w("  ") ; e.w(aGep) ; e.w(" = getelementptr inbounds ") ; e.w(sty)
 462  			e.w(", ptr ") ; e.w(dp) ; e.w(", i32 0, i32 ") ; e.w(irItoa(int32(fieldIdx))) ; e.w("\n")
 463  			at := e.deferArgType(arg)
 464  			aVal := "%" | pfx | ".dv" | irItoa(idx) | "f" | irItoa(i)
 465  			e.w("  ") ; e.w(aVal) ; e.w(" = load ") ; e.w(at) ; e.w(", ptr ") ; e.w(aGep) ; e.w("\n")
 466  			args = append(args, aVal)
 467  			argTypes = append(argTypes, at)
 468  			fieldIdx++
 469  		}
 470  		rt := e.deferRetType(d)
 471  		e.w("  call ") ; e.w(rt) ; e.w(" ") ; e.w(fpReg) ; e.w("(")
 472  		for i, av := range args {
 473  			if i > 0 { e.w(", ") }
 474  			e.w(argTypes[i]) ; e.w(" ") ; e.w(av)
 475  		}
 476  		if len(args) > 0 { e.w(", ") }
 477  		e.w("ptr ") ; e.w(ctxReg)
 478  		e.w(")\n")
 479  	}
 480  }
 481  
 482  func irItoa(n int32) string {
 483  	if n == 0 {
 484  		return "0"
 485  	}
 486  	neg := n < 0
 487  	if neg {
 488  		n = -n
 489  	}
 490  	buf := []byte{:0:20}
 491  	for n > 0 {
 492  		buf = append(buf, byte('0'+n%10))
 493  		n /= 10
 494  	}
 495  	if neg {
 496  		buf = append(buf, '-')
 497  	}
 498  	for i, j := 0, len(buf)-1; i < j; i, j = i+1, j-1 {
 499  		buf[i], buf[j] = buf[j], buf[i]
 500  	}
 501  	return string(buf)
 502  }
 503  
 504  func parseIntFromTokenFloatLit(lit string) int64 {
 505  	neg := false
 506  	i := 0
 507  	if len(lit) > 0 && lit[0] == '-' {
 508  		neg = true
 509  		i = 1
 510  	} else if len(lit) > 0 && lit[0] == '+' {
 511  		i = 1
 512  	}
 513  	var n int64
 514  	for ; i < len(lit); i++ {
 515  		ch := lit[i]
 516  		if ch == '_' {
 517  			continue
 518  		}
 519  		if ch < '0' || ch > '9' {
 520  			break
 521  		}
 522  		n = n*10 + int64(ch-'0')
 523  	}
 524  	if neg {
 525  		return -n
 526  	}
 527  	return n
 528  }
 529  
 530  func floatLitForLLVM(lit string) string {
 531  	var buf []byte
 532  	hasDot := false
 533  	ePos := -1
 534  	for i := 0; i < len(lit); i++ {
 535  		ch := lit[i]
 536  		if ch == '_' {
 537  			continue
 538  		}
 539  		if ch == '.' {
 540  			hasDot = true
 541  			if len(buf) == 0 || (len(buf) == 1 && (buf[0] == '-' || buf[0] == '+')) {
 542  				buf = append(buf, '0')
 543  			}
 544  		}
 545  		if ch == 'e' || ch == 'E' {
 546  			ePos = len(buf)
 547  		}
 548  		buf = append(buf, ch)
 549  	}
 550  	if !hasDot {
 551  		if ePos >= 0 {
 552  			var out []byte
 553  			out = append(out, buf[:ePos]...)
 554  			out = append(out, '.', '0')
 555  			out = append(out, buf[ePos:]...)
 556  			return string(out)
 557  		}
 558  		buf = append(buf, '.', '0')
 559  	}
 560  	return string(buf)
 561  }
 562  
 563  func irHex64(v uint64) string {
 564  	digits := "0123456789ABCDEF"
 565  	buf := []byte{:16}
 566  	for i := 15; i >= 0; i-- {
 567  		buf[i] = digits[v&0xf]
 568  		v >>= 4
 569  	}
 570  	return string(buf)
 571  }
 572  
 573  func irItoa64(n int64) string {
 574  	if n == 0 {
 575  		return "0"
 576  	}
 577  	neg := n < 0
 578  	if neg {
 579  		n = -n
 580  	}
 581  	if n < 0 {
 582  		return "-9223372036854775808"
 583  	}
 584  	buf := []byte{:0:20}
 585  	for n > 0 {
 586  		buf = append(buf, byte('0'+n%10))
 587  		n /= 10
 588  	}
 589  	if neg {
 590  		buf = append(buf, '-')
 591  	}
 592  	for i, j := 0, len(buf)-1; i < j; i, j = i+1, j-1 {
 593  		buf[i], buf[j] = buf[j], buf[i]
 594  	}
 595  	return string(buf)
 596  }
 597  
 598  func irFtoa(f float64) string {
 599  	return "0.0"
 600  }
 601  
 602  func irParseInt64(s string) int64 {
 603  	var n int64
 604  	for i := 0; i < len(s); i++ {
 605  		c := s[i]
 606  		if c < '0' || c > '9' {
 607  			break
 608  		}
 609  		n = n*10 + int64(c-'0')
 610  	}
 611  	return n
 612  }
 613  
 614  func runeToUTF8(r rune) string {
 615  	if r < 0 || r > 0x10FFFF {
 616  		r = 0xFFFD
 617  	}
 618  	var out []byte
 619  	if r <= 0x7F {
 620  		out = append(out, byte(r))
 621  	} else if r <= 0x7FF {
 622  		out = append(out, byte(0xC0|(r>>6)), byte(0x80|(r&0x3F)))
 623  	} else if r <= 0xFFFF {
 624  		out = append(out, byte(0xE0|(r>>12)), byte(0x80|((r>>6)&0x3F)), byte(0x80|(r&0x3F)))
 625  	} else {
 626  		out = append(out, byte(0xF0|(r>>18)), byte(0x80|((r>>12)&0x3F)), byte(0x80|((r>>6)&0x3F)), byte(0x80|(r&0x3F)))
 627  	}
 628  	return string(out)
 629  }
 630