github.com/goplus/llgo@v0.8.3/ssa/expr.go (about)

     1  /*
     2   * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package ssa
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"go/constant"
    23  	"go/token"
    24  	"go/types"
    25  	"log"
    26  
    27  	"github.com/goplus/llgo/internal/abi"
    28  	"github.com/goplus/llvm"
    29  )
    30  
    31  // -----------------------------------------------------------------------------
    32  
    33  type Expr struct {
    34  	impl llvm.Value
    35  	Type
    36  }
    37  
    38  var Nil Expr // Zero value is a nil Expr
    39  
    40  // IsNil checks if the expression is nil or not.
    41  func (v Expr) IsNil() bool {
    42  	return v.Type == nil
    43  }
    44  
    45  // Do evaluates the delay expression and returns the result.
    46  func (v Expr) Do(b Builder) Expr {
    47  	switch vt := v.Type; vt.kind {
    48  	case vkPhisExpr:
    49  		e := vt.raw.Type.(*phisExprTy)
    50  		return b.aggregateValue(e.Type, e.phis...)
    51  	}
    52  	return v
    53  }
    54  
    55  // -----------------------------------------------------------------------------
    56  
    57  type pyVarTy struct {
    58  	mod  Expr
    59  	name string
    60  }
    61  
    62  func (p pyVarTy) Underlying() types.Type {
    63  	panic("don't call")
    64  }
    65  
    66  func (p pyVarTy) String() string {
    67  	return "pyVar"
    68  }
    69  
    70  func pyVarExpr(mod Expr, name string) Expr {
    71  	tvar := &aType{raw: rawType{&pyVarTy{mod, name}}, kind: vkPyVarRef}
    72  	return Expr{Type: tvar}
    73  }
    74  
    75  // -----------------------------------------------------------------------------
    76  
    77  type phisExprTy struct {
    78  	phis []llvm.Value
    79  	Type
    80  }
    81  
    82  func (p phisExprTy) Underlying() types.Type {
    83  	panic("don't call")
    84  }
    85  
    86  func (p phisExprTy) String() string {
    87  	return "phisExpr"
    88  }
    89  
    90  func phisExpr(t Type, phis []llvm.Value) Expr {
    91  	tphi := &aType{raw: rawType{&phisExprTy{phis, t}}, kind: vkPhisExpr}
    92  	return Expr{Type: tphi}
    93  }
    94  
    95  // -----------------------------------------------------------------------------
    96  
    97  // Null returns a null constant expression.
    98  func (p Program) Null(t Type) Expr {
    99  	return Expr{llvm.ConstNull(t.ll), t}
   100  }
   101  
   102  // PyNull returns a null *PyObject constant expression.
   103  func (p Program) PyNull() Expr {
   104  	return p.Null(p.PyObjectPtr())
   105  }
   106  
   107  // BoolVal returns a boolean constant expression.
   108  func (p Program) BoolVal(v bool) Expr {
   109  	t := p.Bool()
   110  	var bv uint64
   111  	if v {
   112  		bv = 1
   113  	}
   114  	ret := llvm.ConstInt(t.ll, bv, v)
   115  	return Expr{ret, t}
   116  }
   117  
   118  // IntVal returns an integer constant expression.
   119  func (p Program) IntVal(v uint64, t Type) Expr {
   120  	ret := llvm.ConstInt(t.ll, v, false)
   121  	return Expr{ret, t}
   122  }
   123  
   124  func (p Program) FloatVal(v float64, t Type) Expr {
   125  	ret := llvm.ConstFloat(t.ll, v)
   126  	return Expr{ret, t}
   127  }
   128  
   129  // Val returns a constant expression.
   130  func (p Program) Val(v interface{}) Expr {
   131  	switch v := v.(type) {
   132  	case int:
   133  		return p.IntVal(uint64(v), p.Int())
   134  	case uintptr:
   135  		return p.IntVal(uint64(v), p.Uintptr())
   136  	case bool:
   137  		return p.BoolVal(v)
   138  	case float64:
   139  		t := p.Float64()
   140  		ret := llvm.ConstFloat(t.ll, v)
   141  		return Expr{ret, t}
   142  	}
   143  	panic("todo")
   144  }
   145  
   146  // Const returns a constant expression.
   147  func (b Builder) Const(v constant.Value, typ Type) Expr {
   148  	prog := b.Prog
   149  	if v == nil {
   150  		return prog.Null(typ)
   151  	}
   152  	raw := typ.raw.Type
   153  	switch t := raw.(type) {
   154  	case *types.Basic:
   155  		kind := t.Kind()
   156  		switch {
   157  		case kind == types.Bool:
   158  			return prog.BoolVal(constant.BoolVal(v))
   159  		case kind >= types.Int && kind <= types.Int64:
   160  			if v, exact := constant.Int64Val(v); exact {
   161  				return prog.IntVal(uint64(v), typ)
   162  			}
   163  		case kind >= types.Uint && kind <= types.Uintptr:
   164  			if v, exact := constant.Uint64Val(v); exact {
   165  				return prog.IntVal(v, typ)
   166  			}
   167  		case kind == types.Float32 || kind == types.Float64:
   168  			if v, exact := constant.Float64Val(v); exact {
   169  				return prog.FloatVal(v, typ)
   170  			}
   171  		case kind == types.String:
   172  			return b.Str(constant.StringVal(v))
   173  		}
   174  	}
   175  	panic(fmt.Sprintf("unsupported Const: %v, %v", v, raw))
   176  }
   177  
   178  // SizeOf returns the size of a type.
   179  func (b Builder) SizeOf(t Type, n ...int64) Expr {
   180  	prog := b.Prog
   181  	size := prog.SizeOf(t, n...)
   182  	return prog.IntVal(size, prog.Uintptr())
   183  }
   184  
   185  // CStr returns a c-style string constant expression.
   186  func (b Builder) CStr(v string) Expr {
   187  	return Expr{llvm.CreateGlobalStringPtr(b.impl, v), b.Prog.CStr()}
   188  }
   189  
   190  // Str returns a Go string constant expression.
   191  func (b Builder) Str(v string) (ret Expr) {
   192  	prog := b.Prog
   193  	cstr := b.CStr(v)
   194  	ret = b.InlineCall(b.Func.Pkg.rtFunc("NewString"), cstr, prog.Val(len(v)))
   195  	ret.Type = prog.String()
   196  	return
   197  }
   198  
   199  // -----------------------------------------------------------------------------
   200  
   201  const (
   202  	mathOpBase = token.ADD
   203  	mathOpLast = token.REM
   204  )
   205  
   206  var mathOpToLLVM = []llvm.Opcode{
   207  	int(token.ADD-mathOpBase)<<2 | vkSigned:   llvm.Add,
   208  	int(token.ADD-mathOpBase)<<2 | vkUnsigned: llvm.Add,
   209  	int(token.ADD-mathOpBase)<<2 | vkFloat:    llvm.FAdd,
   210  
   211  	int(token.SUB-mathOpBase)<<2 | vkSigned:   llvm.Sub,
   212  	int(token.SUB-mathOpBase)<<2 | vkUnsigned: llvm.Sub,
   213  	int(token.SUB-mathOpBase)<<2 | vkFloat:    llvm.FSub,
   214  
   215  	int(token.MUL-mathOpBase)<<2 | vkSigned:   llvm.Mul,
   216  	int(token.MUL-mathOpBase)<<2 | vkUnsigned: llvm.Mul,
   217  	int(token.MUL-mathOpBase)<<2 | vkFloat:    llvm.FMul,
   218  
   219  	int(token.QUO-mathOpBase)<<2 | vkSigned:   llvm.SDiv,
   220  	int(token.QUO-mathOpBase)<<2 | vkUnsigned: llvm.UDiv,
   221  	int(token.QUO-mathOpBase)<<2 | vkFloat:    llvm.FDiv,
   222  
   223  	int(token.REM-mathOpBase)<<2 | vkSigned:   llvm.SRem,
   224  	int(token.REM-mathOpBase)<<2 | vkUnsigned: llvm.URem,
   225  	int(token.REM-mathOpBase)<<2 | vkFloat:    llvm.FRem,
   226  }
   227  
   228  func mathOpIdx(op token.Token, x valueKind) int {
   229  	return int(op-mathOpBase)<<2 | x
   230  }
   231  
   232  // ADD SUB MUL QUO REM          + - * / %
   233  func isMathOp(op token.Token) bool {
   234  	return op >= mathOpBase && op <= mathOpLast
   235  }
   236  
   237  const (
   238  	logicOpBase = token.AND
   239  	logicOpLast = token.AND_NOT
   240  )
   241  
   242  var logicOpToLLVM = []llvm.Opcode{
   243  	token.AND - logicOpBase: llvm.And,
   244  	token.OR - logicOpBase:  llvm.Or,
   245  	token.XOR - logicOpBase: llvm.Xor,
   246  	token.SHL - logicOpBase: llvm.Shl,
   247  	token.SHR - logicOpBase: llvm.AShr, // Arithmetic Shift Right
   248  }
   249  
   250  // AND OR XOR SHL SHR AND_NOT   & | ^ << >> &^
   251  func isLogicOp(op token.Token) bool {
   252  	return op >= logicOpBase && op <= logicOpLast
   253  }
   254  
   255  const (
   256  	predOpBase = token.EQL
   257  	predOpLast = token.GEQ
   258  )
   259  
   260  var intPredOpToLLVM = []llvm.IntPredicate{
   261  	token.EQL - predOpBase: llvm.IntEQ,
   262  	token.NEQ - predOpBase: llvm.IntNE,
   263  	token.LSS - predOpBase: llvm.IntSLT,
   264  	token.LEQ - predOpBase: llvm.IntSLE,
   265  	token.GTR - predOpBase: llvm.IntSGT,
   266  	token.GEQ - predOpBase: llvm.IntSGE,
   267  }
   268  
   269  var uintPredOpToLLVM = []llvm.IntPredicate{
   270  	token.EQL - predOpBase: llvm.IntEQ,
   271  	token.NEQ - predOpBase: llvm.IntNE,
   272  	token.LSS - predOpBase: llvm.IntULT,
   273  	token.LEQ - predOpBase: llvm.IntULE,
   274  	token.GTR - predOpBase: llvm.IntUGT,
   275  	token.GEQ - predOpBase: llvm.IntUGE,
   276  }
   277  
   278  var floatPredOpToLLVM = []llvm.FloatPredicate{
   279  	token.EQL - predOpBase: llvm.FloatOEQ,
   280  	token.NEQ - predOpBase: llvm.FloatONE,
   281  	token.LSS - predOpBase: llvm.FloatOLT,
   282  	token.LEQ - predOpBase: llvm.FloatOLE,
   283  	token.GTR - predOpBase: llvm.FloatOGT,
   284  	token.GEQ - predOpBase: llvm.FloatOGE,
   285  }
   286  
   287  var boolPredOpToLLVM = []llvm.IntPredicate{
   288  	token.EQL - predOpBase: llvm.IntEQ,
   289  	token.NEQ - predOpBase: llvm.IntNE,
   290  }
   291  
   292  // EQL NEQ LSS LEQ GTR GEQ      == != < <= < >=
   293  func isPredOp(op token.Token) bool {
   294  	return op >= predOpBase && op <= predOpLast
   295  }
   296  
   297  // The BinOp instruction yields the result of binary operation (x op y).
   298  // op can be:
   299  // ADD SUB MUL QUO REM          + - * / %
   300  // AND OR XOR SHL SHR AND_NOT   & | ^ << >> &^
   301  // EQL NEQ LSS LEQ GTR GEQ      == != < <= < >=
   302  func (b Builder) BinOp(op token.Token, x, y Expr) Expr {
   303  	if debugInstr {
   304  		log.Printf("BinOp %d, %v, %v\n", op, x.impl, y.impl)
   305  	}
   306  	switch {
   307  	case isMathOp(op): // op: + - * / %
   308  		kind := x.kind
   309  		switch kind {
   310  		case vkString:
   311  			if op == token.ADD {
   312  				pkg := b.Func.Pkg
   313  				return Expr{b.InlineCall(pkg.rtFunc("StringCat"), x, y).impl, x.Type}
   314  			}
   315  		case vkComplex:
   316  		default:
   317  			idx := mathOpIdx(op, kind)
   318  			if llop := mathOpToLLVM[idx]; llop != 0 {
   319  				return Expr{llvm.CreateBinOp(b.impl, llop, x.impl, y.impl), x.Type}
   320  			}
   321  		}
   322  	case isLogicOp(op): // op: & | ^ << >> &^
   323  		switch op {
   324  		case token.AND_NOT:
   325  			return Expr{b.impl.CreateAnd(x.impl, b.impl.CreateNot(y.impl, ""), ""), x.Type}
   326  		case token.SHL, token.SHR:
   327  			if needsNegativeCheck(y) {
   328  				check := Expr{b.impl.CreateICmp(llvm.IntSLT, y.impl, llvm.ConstInt(y.ll, 0, false), ""), b.Prog.Bool()}
   329  				b.InlineCall(b.Func.Pkg.rtFunc("AssertNegativeShift"), check)
   330  			}
   331  			xsize, ysize := b.Prog.SizeOf(x.Type), b.Prog.SizeOf(y.Type)
   332  			if xsize != ysize {
   333  				y = b.Convert(x.Type, y)
   334  			}
   335  			overflows := b.impl.CreateICmp(llvm.IntUGE, y.impl, llvm.ConstInt(y.ll, xsize*8, false), "")
   336  			xzero := llvm.ConstInt(x.ll, 0, false)
   337  			if op == token.SHL {
   338  				rhs := b.impl.CreateShl(x.impl, y.impl, "")
   339  				return Expr{b.impl.CreateSelect(overflows, xzero, rhs, ""), x.Type}
   340  			} else {
   341  				if x.kind == vkSigned {
   342  					rhs := b.impl.CreateSelect(overflows, llvm.ConstInt(y.ll, 8*xsize-1, false), y.impl, "")
   343  					return Expr{b.impl.CreateAShr(x.impl, rhs, ""), x.Type}
   344  				} else {
   345  					rsh := b.impl.CreateLShr(x.impl, y.impl, "")
   346  					return Expr{b.impl.CreateSelect(overflows, xzero, rsh, ""), x.Type}
   347  				}
   348  			}
   349  		default:
   350  			llop := logicOpToLLVM[op-logicOpBase]
   351  			return Expr{llvm.CreateBinOp(b.impl, llop, x.impl, y.impl), x.Type}
   352  		}
   353  	case isPredOp(op): // op: == != < <= < >=
   354  		tret := b.Prog.Bool()
   355  		kind := x.kind
   356  		switch kind {
   357  		case vkSigned:
   358  			pred := intPredOpToLLVM[op-predOpBase]
   359  			return Expr{llvm.CreateICmp(b.impl, pred, x.impl, y.impl), tret}
   360  		case vkUnsigned, vkPtr:
   361  			pred := uintPredOpToLLVM[op-predOpBase]
   362  			return Expr{llvm.CreateICmp(b.impl, pred, x.impl, y.impl), tret}
   363  		case vkFloat:
   364  			pred := floatPredOpToLLVM[op-predOpBase]
   365  			return Expr{llvm.CreateFCmp(b.impl, pred, x.impl, y.impl), tret}
   366  		case vkBool:
   367  			pred := boolPredOpToLLVM[op-predOpBase]
   368  			return Expr{llvm.CreateICmp(b.impl, pred, x.impl, y.impl), tret}
   369  		case vkString, vkComplex:
   370  			panic("todo")
   371  		}
   372  	}
   373  	panic("todo")
   374  }
   375  
   376  // The UnOp instruction yields the result of (op x).
   377  // ARROW is channel receive.
   378  // MUL is pointer indirection (load).
   379  // XOR is bitwise complement.
   380  // SUB is negation.
   381  // NOT is logical negation.
   382  func (b Builder) UnOp(op token.Token, x Expr) (ret Expr) {
   383  	if debugInstr {
   384  		log.Printf("UnOp %v, %v\n", op, x.impl)
   385  	}
   386  	switch op {
   387  	case token.MUL:
   388  		return b.Load(x)
   389  	case token.SUB:
   390  		switch t := x.Type.raw.Underlying().(type) {
   391  		case *types.Basic:
   392  			ret.Type = x.Type
   393  			if t.Info()&types.IsInteger != 0 {
   394  				ret.impl = b.impl.CreateNeg(x.impl, "")
   395  			} else if t.Info()&types.IsFloat != 0 {
   396  				ret.impl = b.impl.CreateFNeg(x.impl, "")
   397  			} else {
   398  				panic("todo")
   399  			}
   400  		default:
   401  			panic("unreachable")
   402  		}
   403  	case token.NOT:
   404  		ret.Type = x.Type
   405  		ret.impl = b.impl.CreateNot(x.impl, "")
   406  	case token.XOR:
   407  		ret.Type = x.Type
   408  		ret.impl = b.impl.CreateXor(x.impl, llvm.ConstInt(x.Type.ll, ^uint64(0), false), "")
   409  	case token.ARROW:
   410  		panic("todo")
   411  	}
   412  	return
   413  }
   414  
   415  // -----------------------------------------------------------------------------
   416  
   417  func checkExpr(v Expr, t types.Type, b Builder) Expr {
   418  	if t, ok := t.(*types.Struct); ok && isClosure(t) {
   419  		if v.kind != vkClosure {
   420  			return b.Func.Pkg.closureStub(b, t, v)
   421  		}
   422  	}
   423  	return v
   424  }
   425  
   426  func llvmParamsEx(data Expr, vals []Expr, params *types.Tuple, b Builder) (ret []llvm.Value) {
   427  	if data.IsNil() {
   428  		return llvmParams(0, vals, params, b)
   429  	}
   430  	ret = llvmParams(1, vals, params, b)
   431  	ret[0] = data.impl
   432  	return
   433  }
   434  
   435  func llvmParams(base int, vals []Expr, params *types.Tuple, b Builder) (ret []llvm.Value) {
   436  	n := params.Len()
   437  	if n > 0 {
   438  		ret = make([]llvm.Value, len(vals)+base)
   439  		for idx, v := range vals {
   440  			i := base + idx
   441  			if i < n {
   442  				v = checkExpr(v, params.At(i).Type(), b)
   443  			}
   444  			ret[i] = v.impl
   445  		}
   446  	}
   447  	return
   448  }
   449  
   450  func llvmFields(vals []Expr, t *types.Struct, b Builder) (ret []llvm.Value) {
   451  	n := t.NumFields()
   452  	if n > 0 {
   453  		ret = make([]llvm.Value, len(vals))
   454  		for i, v := range vals {
   455  			if i < n {
   456  				v = checkExpr(v, t.Field(i).Type(), b)
   457  			}
   458  			ret[i] = v.impl
   459  		}
   460  	}
   461  	return
   462  }
   463  
   464  func llvmDelayValues(f func(i int) Expr, n int) []llvm.Value {
   465  	ret := make([]llvm.Value, n)
   466  	for i := 0; i < n; i++ {
   467  		ret[i] = f(i).impl
   468  	}
   469  	return ret
   470  }
   471  
   472  func llvmBlocks(bblks []BasicBlock) []llvm.BasicBlock {
   473  	ret := make([]llvm.BasicBlock, len(bblks))
   474  	for i, v := range bblks {
   475  		ret[i] = v.impl
   476  	}
   477  	return ret
   478  }
   479  
   480  // Phi represents a phi node.
   481  type Phi struct {
   482  	Expr
   483  }
   484  
   485  // AddIncoming adds incoming values to a phi node.
   486  func (p Phi) AddIncoming(b Builder, bblks []BasicBlock, f func(i int) Expr) {
   487  	bs := llvmBlocks(bblks)
   488  	if p.kind != vkPhisExpr { // normal phi node
   489  		vs := llvmDelayValues(f, len(bblks))
   490  		p.impl.AddIncoming(vs, bs)
   491  		return
   492  	}
   493  	e := p.raw.Type.(*phisExprTy)
   494  	phis := e.phis
   495  	vals := make([][]llvm.Value, len(phis))
   496  	for iblk, blk := range bblks {
   497  		last := blk.impl.LastInstruction()
   498  		b.impl.SetInsertPointBefore(last)
   499  		impl := b.impl
   500  		val := f(iblk).impl
   501  		for i := range phis {
   502  			if iblk == 0 {
   503  				vals[i] = make([]llvm.Value, len(bblks))
   504  			}
   505  			vals[i][iblk] = llvm.CreateExtractValue(impl, val, i)
   506  		}
   507  	}
   508  	for i, phi := range phis {
   509  		phi.AddIncoming(vals[i], bs)
   510  	}
   511  }
   512  
   513  // Phi returns a phi node.
   514  func (b Builder) Phi(t Type) Phi {
   515  	impl := b.impl
   516  	switch tund := t.raw.Type.Underlying().(type) {
   517  	case *types.Basic:
   518  		kind := tund.Kind()
   519  		switch kind {
   520  		case types.String:
   521  			prog := b.Prog
   522  			phis := make([]llvm.Value, 2)
   523  			phis[0] = llvm.CreatePHI(impl, prog.tyVoidPtr())
   524  			phis[1] = llvm.CreatePHI(impl, prog.tyInt())
   525  			return Phi{phisExpr(t, phis)}
   526  		}
   527  	case *types.Struct:
   528  		panic("todo")
   529  	}
   530  	phi := llvm.CreatePHI(impl, t.ll)
   531  	return Phi{Expr{phi, t}}
   532  }
   533  
   534  // -----------------------------------------------------------------------------
   535  
   536  // Advance returns the pointer ptr advanced by offset.
   537  func (b Builder) Advance(ptr Expr, offset Expr) Expr {
   538  	if debugInstr {
   539  		log.Printf("Advance %v, %v\n", ptr.impl, offset.impl)
   540  	}
   541  	var elem llvm.Type
   542  	var prog = b.Prog
   543  	switch t := ptr.raw.Type.(type) {
   544  	case *types.Basic: // void
   545  		elem = prog.tyInt8()
   546  	default:
   547  		elem = prog.rawType(t.(*types.Pointer).Elem()).ll
   548  	}
   549  	ret := llvm.CreateGEP(b.impl, elem, ptr.impl, []llvm.Value{offset.impl})
   550  	return Expr{ret, ptr.Type}
   551  }
   552  
   553  // Load returns the value at the pointer ptr.
   554  func (b Builder) Load(ptr Expr) Expr {
   555  	if debugInstr {
   556  		log.Printf("Load %v\n", ptr.impl)
   557  	}
   558  	if ptr.kind == vkPyVarRef {
   559  		return b.pyLoad(ptr)
   560  	}
   561  	telem := b.Prog.Elem(ptr.Type)
   562  	return Expr{llvm.CreateLoad(b.impl, telem.ll, ptr.impl), telem}
   563  }
   564  
   565  // Store stores val at the pointer ptr.
   566  func (b Builder) Store(ptr, val Expr) Builder {
   567  	raw := ptr.raw.Type
   568  	if debugInstr {
   569  		log.Printf("Store %v, %v, %v\n", raw, ptr.impl, val.impl)
   570  	}
   571  	val = checkExpr(val, raw.(*types.Pointer).Elem(), b)
   572  	b.impl.CreateStore(val.impl, ptr.impl)
   573  	return b
   574  }
   575  
   576  func (b Builder) aggregateAlloc(t Type, flds ...llvm.Value) llvm.Value {
   577  	prog := b.Prog
   578  	pkg := b.Func.Pkg
   579  	size := prog.SizeOf(t)
   580  	ptr := b.InlineCall(pkg.rtFunc("AllocU"), prog.IntVal(size, prog.Uintptr())).impl
   581  	tll := t.ll
   582  	impl := b.impl
   583  	for i, fld := range flds {
   584  		impl.CreateStore(fld, llvm.CreateStructGEP(impl, tll, ptr, i))
   585  	}
   586  	return ptr
   587  }
   588  
   589  // aggregateValue yields the value of the aggregate X with the fields
   590  func (b Builder) aggregateValue(t Type, flds ...llvm.Value) Expr {
   591  	tll := t.ll
   592  	impl := b.impl
   593  	ptr := llvm.CreateAlloca(impl, tll)
   594  	for i, fld := range flds {
   595  		impl.CreateStore(fld, llvm.CreateStructGEP(impl, tll, ptr, i))
   596  	}
   597  	return Expr{llvm.CreateLoad(b.impl, tll, ptr), t}
   598  }
   599  
   600  // The MakeClosure instruction yields a closure value whose code is
   601  // Fn and whose free variables' values are supplied by Bindings.
   602  //
   603  // Type() returns a (possibly named) *types.Signature.
   604  //
   605  // Example printed form:
   606  //
   607  //	t0 = make closure anon@1.2 [x y z]
   608  //	t1 = make closure bound$(main.I).add [i]
   609  func (b Builder) MakeClosure(fn Expr, bindings []Expr) Expr {
   610  	if debugInstr {
   611  		log.Printf("MakeClosure %v, %v\n", fn, bindings)
   612  	}
   613  	prog := b.Prog
   614  	tfn := fn.Type
   615  	sig := tfn.raw.Type.(*types.Signature)
   616  	tctx := sig.Params().At(0).Type().Underlying().(*types.Pointer).Elem().(*types.Struct)
   617  	flds := llvmFields(bindings, tctx, b)
   618  	data := b.aggregateAlloc(prog.rawType(tctx), flds...)
   619  	return b.aggregateValue(prog.Closure(tfn), fn.impl, data)
   620  }
   621  
   622  // The FieldAddr instruction yields the address of Field of *struct X.
   623  //
   624  // The field is identified by its index within the field list of the
   625  // struct type of X.
   626  //
   627  // Dynamically, this instruction panics if X evaluates to a nil
   628  // pointer.
   629  //
   630  // Type() returns a (possibly named) *types.Pointer.
   631  //
   632  // Example printed form:
   633  //
   634  //	t1 = &t0.name [#1]
   635  func (b Builder) FieldAddr(x Expr, idx int) Expr {
   636  	if debugInstr {
   637  		log.Printf("FieldAddr %v, %d\n", x.impl, idx)
   638  	}
   639  	prog := b.Prog
   640  	tstruc := prog.Elem(x.Type)
   641  	telem := prog.Field(tstruc, idx)
   642  	pt := prog.Pointer(telem)
   643  	return Expr{llvm.CreateStructGEP(b.impl, tstruc.ll, x.impl, idx), pt}
   644  }
   645  
   646  // The Field instruction yields the value of Field of struct X.
   647  func (b Builder) Field(x Expr, idx int) Expr {
   648  	if debugInstr {
   649  		log.Printf("Field %v, %d\n", x.impl, idx)
   650  	}
   651  	return b.getField(x, idx)
   652  }
   653  
   654  func (b Builder) getField(x Expr, idx int) Expr {
   655  	tfld := b.Prog.Field(x.Type, idx)
   656  	fld := llvm.CreateExtractValue(b.impl, x.impl, idx)
   657  	return Expr{fld, tfld}
   658  }
   659  
   660  // StringData returns the data pointer of a string.
   661  func (b Builder) StringData(x Expr) Expr {
   662  	if debugInstr {
   663  		log.Printf("StringData %v\n", x.impl)
   664  	}
   665  	prog := b.Prog
   666  	ptr := llvm.CreateExtractValue(b.impl, x.impl, 0)
   667  	return Expr{ptr, prog.CStr()}
   668  }
   669  
   670  // StringLen returns the length of a string.
   671  func (b Builder) StringLen(x Expr) Expr {
   672  	if debugInstr {
   673  		log.Printf("StringLen %v\n", x.impl)
   674  	}
   675  	prog := b.Prog
   676  	ptr := llvm.CreateExtractValue(b.impl, x.impl, 1)
   677  	return Expr{ptr, prog.Int()}
   678  }
   679  
   680  // SliceData returns the data pointer of a slice.
   681  func (b Builder) SliceData(x Expr) Expr {
   682  	if debugInstr {
   683  		log.Printf("SliceData %v\n", x.impl)
   684  	}
   685  	prog := b.Prog
   686  	ptr := llvm.CreateExtractValue(b.impl, x.impl, 0)
   687  	return Expr{ptr, prog.CStr()}
   688  }
   689  
   690  // SliceLen returns the length of a slice.
   691  func (b Builder) SliceLen(x Expr) Expr {
   692  	if debugInstr {
   693  		log.Printf("SliceLen %v\n", x.impl)
   694  	}
   695  	prog := b.Prog
   696  	ptr := llvm.CreateExtractValue(b.impl, x.impl, 1)
   697  	return Expr{ptr, prog.Int()}
   698  }
   699  
   700  // SliceCap returns the length of a slice cap.
   701  func (b Builder) SliceCap(x Expr) Expr {
   702  	if debugInstr {
   703  		log.Printf("SliceCap %v\n", x.impl)
   704  	}
   705  	prog := b.Prog
   706  	ptr := llvm.CreateExtractValue(b.impl, x.impl, 2)
   707  	return Expr{ptr, prog.Int()}
   708  }
   709  
   710  // The IndexAddr instruction yields the address of the element at
   711  // index `idx` of collection `x`.  `idx` is an integer expression.
   712  //
   713  // The elements of maps and strings are not addressable; use Lookup (map),
   714  // Index (string), or MapUpdate instead.
   715  //
   716  // Dynamically, this instruction panics if `x` evaluates to a nil *array
   717  // pointer.
   718  //
   719  // Example printed form:
   720  //
   721  //	t2 = &t0[t1]
   722  func (b Builder) IndexAddr(x, idx Expr) Expr {
   723  	if debugInstr {
   724  		log.Printf("IndexAddr %v, %v\n", x.impl, idx.impl)
   725  	}
   726  	idx = b.checkIndex(idx)
   727  	prog := b.Prog
   728  	telem := prog.Index(x.Type)
   729  	pt := prog.Pointer(telem)
   730  	switch x.raw.Type.Underlying().(type) {
   731  	case *types.Slice:
   732  		ptr := b.SliceData(x)
   733  		indices := []llvm.Value{idx.impl}
   734  		return Expr{llvm.CreateInBoundsGEP(b.impl, telem.ll, ptr.impl, indices), pt}
   735  	}
   736  	// case *types.Pointer:
   737  	indices := []llvm.Value{idx.impl}
   738  	return Expr{llvm.CreateInBoundsGEP(b.impl, telem.ll, x.impl, indices), pt}
   739  }
   740  
   741  func needsNegativeCheck(x Expr) bool {
   742  	if x.kind == vkSigned {
   743  		if rv := x.impl.IsAConstantInt(); !rv.IsNil() && rv.SExtValue() >= 0 {
   744  			return false
   745  		}
   746  		return true
   747  	}
   748  	return false
   749  }
   750  
   751  // check index >= 0 and size to uint
   752  func (b Builder) checkIndex(idx Expr) Expr {
   753  	if needsNegativeCheck(idx) {
   754  		check := Expr{b.impl.CreateICmp(llvm.IntSLT, idx.impl, llvm.ConstInt(idx.ll, 0, false), ""), b.Prog.Bool()}
   755  		b.InlineCall(b.Func.Pkg.rtFunc("AssertIndexRange"), check)
   756  	}
   757  	typ := b.Prog.Uint()
   758  	if b.Prog.SizeOf(idx.Type) < b.Prog.SizeOf(typ) {
   759  		idx.Type = typ
   760  		idx.impl = castUintptr(b, idx.impl, typ)
   761  	}
   762  	return idx
   763  }
   764  
   765  // The Index instruction yields element Index of collection X, an array,
   766  // string or type parameter containing an array, a string, a pointer to an,
   767  // array or a slice.
   768  //
   769  // Example printed form:
   770  //
   771  //	t2 = t0[t1]
   772  func (b Builder) Index(x, idx Expr, addr func(Expr) Expr) Expr {
   773  	if debugInstr {
   774  		log.Printf("Index %v, %v\n", x.impl, idx.impl)
   775  	}
   776  	prog := b.Prog
   777  	var telem Type
   778  	var ptr Expr
   779  	switch t := x.raw.Type.Underlying().(type) {
   780  	case *types.Basic:
   781  		if t.Kind() != types.String {
   782  			panic(fmt.Errorf("invalid operation: cannot index %v", t))
   783  		}
   784  		telem = prog.rawType(types.Typ[types.Byte])
   785  		ptr = b.StringData(x)
   786  	case *types.Array:
   787  		telem = prog.Index(x.Type)
   788  		if addr != nil {
   789  			ptr = addr(x)
   790  		} else {
   791  			size := b.SizeOf(telem, t.Len())
   792  			ptr = b.Alloca(size)
   793  			b.Store(ptr, x)
   794  		}
   795  	}
   796  	idx = b.checkIndex(idx)
   797  	pt := prog.Pointer(telem)
   798  	indices := []llvm.Value{idx.impl}
   799  	buf := Expr{llvm.CreateInBoundsGEP(b.impl, telem.ll, ptr.impl, indices), pt}
   800  	return b.Load(buf)
   801  }
   802  
   803  // The Lookup instruction yields element Index of collection map X.
   804  // Index is the appropriate key type.
   805  //
   806  // If CommaOk, the result is a 2-tuple of the value above and a
   807  // boolean indicating the result of a map membership test for the key.
   808  // The components of the tuple are accessed using Extract.
   809  //
   810  // Example printed form:
   811  //
   812  //	t2 = t0[t1]
   813  //	t5 = t3[t4],ok
   814  func (b Builder) Lookup(x, key Expr, commaOk bool) (ret Expr) {
   815  	if debugInstr {
   816  		log.Printf("Lookup %v, %v, %v\n", x.impl, key.impl, commaOk)
   817  	}
   818  	// TODO(xsw)
   819  	// panic("todo")
   820  	return
   821  }
   822  
   823  // The Slice instruction yields a slice of an existing string, slice
   824  // or *array X between optional integer bounds Low and High.
   825  //
   826  // Dynamically, this instruction panics if X evaluates to a nil *array
   827  // pointer.
   828  //
   829  // Type() returns string if the type of X was string, otherwise a
   830  // *types.Slice with the same element type as X.
   831  //
   832  // Example printed form:
   833  //
   834  //	t1 = slice t0[1:]
   835  func (b Builder) Slice(x, low, high, max Expr) (ret Expr) {
   836  	if debugInstr {
   837  		log.Printf("Slice %v, %v, %v\n", x.impl, low.impl, high.impl)
   838  	}
   839  	prog := b.Prog
   840  	pkg := b.Func.Pkg
   841  	var nCap Expr
   842  	var nEltSize Expr
   843  	var base Expr
   844  	if low.IsNil() {
   845  		low = prog.IntVal(0, prog.Int())
   846  	}
   847  	switch t := x.raw.Type.Underlying().(type) {
   848  	case *types.Basic:
   849  		if t.Kind() != types.String {
   850  			panic(fmt.Errorf("invalid operation: cannot slice %v", t))
   851  		}
   852  		if high.IsNil() {
   853  			high = b.StringLen(x)
   854  		}
   855  		ret.Type = x.Type
   856  		ret.impl = b.InlineCall(pkg.rtFunc("NewStringSlice"), x, low, high).impl
   857  		return
   858  	case *types.Slice:
   859  		nEltSize = b.SizeOf(prog.Index(x.Type))
   860  		nCap = b.SliceCap(x)
   861  		if high.IsNil() {
   862  			high = b.SliceCap(x)
   863  		}
   864  		ret.Type = x.Type
   865  		base = b.SliceData(x)
   866  	case *types.Pointer:
   867  		telem := t.Elem()
   868  		switch te := telem.Underlying().(type) {
   869  		case *types.Array:
   870  			elem := prog.rawType(te.Elem())
   871  			ret.Type = prog.Slice(elem)
   872  			nEltSize = b.SizeOf(elem)
   873  			nCap = prog.IntVal(uint64(te.Len()), prog.Int())
   874  			if high.IsNil() {
   875  				high = nCap
   876  			}
   877  			base = x
   878  		}
   879  	}
   880  	if max.IsNil() {
   881  		max = nCap
   882  	}
   883  	ret.impl = b.InlineCall(pkg.rtFunc("NewSlice3"), base, nEltSize, nCap, low, high, max).impl
   884  	return
   885  }
   886  
   887  // -----------------------------------------------------------------------------
   888  
   889  // The MakeMap instruction creates a new hash-table-based map object
   890  // and yields a value of kind map.
   891  //
   892  // t is a (possibly named) *types.Map.
   893  //
   894  // Example printed form:
   895  //
   896  //	t1 = make map[string]int t0
   897  //	t1 = make StringIntMap t0
   898  func (b Builder) MakeMap(t Type, nReserve Expr) (ret Expr) {
   899  	if debugInstr {
   900  		log.Printf("MakeMap %v, %v\n", t.RawType(), nReserve.impl)
   901  	}
   902  	pkg := b.Func.Pkg
   903  	ret.Type = t
   904  	ret.impl = b.InlineCall(pkg.rtFunc("MakeSmallMap")).impl
   905  	// TODO(xsw): nReserve
   906  	return
   907  }
   908  
   909  // The MakeSlice instruction yields a slice of length Len backed by a
   910  // newly allocated array of length Cap.
   911  //
   912  // Both Len and Cap must be non-nil Values of integer type.
   913  //
   914  // (Alloc(types.Array) followed by Slice will not suffice because
   915  // Alloc can only create arrays of constant length.)
   916  //
   917  // Type() returns a (possibly named) *types.Slice.
   918  //
   919  // Example printed form:
   920  //
   921  //	t1 = make []string 1:int t0
   922  //	t1 = make StringSlice 1:int t0
   923  func (b Builder) MakeSlice(t Type, len, cap Expr) (ret Expr) {
   924  	if debugInstr {
   925  		log.Printf("MakeSlice %v, %v, %v\n", t.RawType(), len.impl, cap.impl)
   926  	}
   927  	pkg := b.Func.Pkg
   928  	if cap.IsNil() {
   929  		cap = len
   930  	}
   931  	elemSize := b.SizeOf(b.Prog.Index(t))
   932  	size := b.BinOp(token.MUL, cap, elemSize)
   933  	ptr := b.InlineCall(pkg.rtFunc("AllocZ"), size)
   934  	ret.impl = b.InlineCall(pkg.rtFunc("NewSlice"), ptr, len, cap).impl
   935  	ret.Type = t
   936  	return
   937  }
   938  
   939  // -----------------------------------------------------------------------------
   940  
   941  // The Alloc instruction reserves space for a variable of the given type,
   942  // zero-initializes it, and yields its address.
   943  //
   944  // If heap is false, Alloc zero-initializes the same local variable in
   945  // the call frame and returns its address; in this case the Alloc must
   946  // be present in Function.Locals. We call this a "local" alloc.
   947  //
   948  // If heap is true, Alloc allocates a new zero-initialized variable
   949  // each time the instruction is executed. We call this a "new" alloc.
   950  //
   951  // When Alloc is applied to a channel, map or slice type, it returns
   952  // the address of an uninitialized (nil) reference of that kind; store
   953  // the result of MakeSlice, MakeMap or MakeChan in that location to
   954  // instantiate these types.
   955  //
   956  // Example printed form:
   957  //
   958  //	t0 = local int
   959  //	t1 = new int
   960  func (b Builder) Alloc(elem Type, heap bool) (ret Expr) {
   961  	if debugInstr {
   962  		log.Printf("Alloc %v, %v\n", elem.RawType(), heap)
   963  	}
   964  	prog := b.Prog
   965  	pkg := b.Func.Pkg
   966  	size := b.SizeOf(elem)
   967  	if heap {
   968  		ret = b.InlineCall(pkg.rtFunc("AllocZ"), size)
   969  	} else {
   970  		ret = Expr{llvm.CreateAlloca(b.impl, elem.ll), prog.VoidPtr()}
   971  		ret.impl = b.InlineCall(pkg.rtFunc("Zeroinit"), ret, size).impl
   972  	}
   973  	ret.Type = prog.Pointer(elem)
   974  	return
   975  }
   976  
   977  // Alloca allocates space for n bytes.
   978  func (b Builder) Alloca(n Expr) (ret Expr) {
   979  	if debugInstr {
   980  		log.Printf("Alloca %v\n", n.impl)
   981  	}
   982  	prog := b.Prog
   983  	telem := prog.tyInt8()
   984  	ret.impl = llvm.CreateArrayAlloca(b.impl, telem, n.impl)
   985  	ret.Type = prog.VoidPtr()
   986  	return
   987  }
   988  
   989  /*
   990  // ArrayAlloca reserves space for an array of n elements of type telem.
   991  func (b Builder) ArrayAlloca(telem Type, n Expr) (ret Expr) {
   992  	if debugInstr {
   993  		log.Printf("ArrayAlloca %v, %v\n", telem.t, n.impl)
   994  	}
   995  	ret.impl = llvm.CreateArrayAlloca(b.impl, telem.ll, n.impl)
   996  	ret.Type = b.Prog.Pointer(telem)
   997  	return
   998  }
   999  */
  1000  
  1001  // AllocaCStr allocates space for copy it from a Go string.
  1002  func (b Builder) AllocaCStr(gostr Expr) (ret Expr) {
  1003  	if debugInstr {
  1004  		log.Printf("AllocaCStr %v\n", gostr.impl)
  1005  	}
  1006  	pkg := b.Func.Pkg
  1007  	n := b.StringLen(gostr)
  1008  	n1 := b.BinOp(token.ADD, n, b.Prog.Val(1))
  1009  	cstr := b.Alloca(n1)
  1010  	return b.InlineCall(pkg.rtFunc("CStrCopy"), cstr, gostr)
  1011  }
  1012  
  1013  // -----------------------------------------------------------------------------
  1014  
  1015  // The ChangeType instruction applies to X a value-preserving type
  1016  // change to Type().
  1017  //
  1018  // Type changes are permitted:
  1019  //   - between a named type and its underlying type.
  1020  //   - between two named types of the same underlying type.
  1021  //   - between (possibly named) pointers to identical base types.
  1022  //   - from a bidirectional channel to a read- or write-channel,
  1023  //     optionally adding/removing a name.
  1024  //   - between a type (t) and an instance of the type (tσ), i.e.
  1025  //     Type() == σ(X.Type()) (or X.Type()== σ(Type())) where
  1026  //     σ is the type substitution of Parent().TypeParams by
  1027  //     Parent().TypeArgs.
  1028  //
  1029  // This operation cannot fail dynamically.
  1030  //
  1031  // Type changes may to be to or from a type parameter (or both). All
  1032  // types in the type set of X.Type() have a value-preserving type
  1033  // change to all types in the type set of Type().
  1034  //
  1035  // Example printed form:
  1036  //
  1037  //	t1 = changetype *int <- IntPtr (t0)
  1038  func (b Builder) ChangeType(t Type, x Expr) (ret Expr) {
  1039  	if debugInstr {
  1040  		log.Printf("ChangeType %v, %v\n", t.RawType(), x.impl)
  1041  	}
  1042  	typ := t.raw.Type
  1043  	switch typ.(type) {
  1044  	default:
  1045  		// TODO(xsw): remove instr name
  1046  		ret.impl = b.impl.CreateBitCast(x.impl, t.ll, "bitCast")
  1047  		ret.Type = b.Prog.rawType(typ)
  1048  		return
  1049  	}
  1050  }
  1051  
  1052  // The Convert instruction yields the conversion of value X to type
  1053  // Type().  One or both of those types is basic (but possibly named).
  1054  //
  1055  // A conversion may change the value and representation of its operand.
  1056  // Conversions are permitted:
  1057  //   - between real numeric types.
  1058  //   - between complex numeric types.
  1059  //   - between string and []byte or []rune.
  1060  //   - between pointers and unsafe.Pointer.
  1061  //   - between unsafe.Pointer and uintptr.
  1062  //   - from (Unicode) integer to (UTF-8) string.
  1063  //
  1064  // A conversion may imply a type name change also.
  1065  //
  1066  // Conversions may to be to or from a type parameter. All types in
  1067  // the type set of X.Type() can be converted to all types in the type
  1068  // set of Type().
  1069  //
  1070  // This operation cannot fail dynamically.
  1071  //
  1072  // Conversions of untyped string/number/bool constants to a specific
  1073  // representation are eliminated during SSA construction.
  1074  //
  1075  // Example printed form:
  1076  //
  1077  //	t1 = convert []byte <- string (t0)
  1078  func (b Builder) Convert(t Type, x Expr) (ret Expr) {
  1079  	if debugInstr {
  1080  		log.Printf("Convert %v <- %v\n", t.RawType(), x.RawType())
  1081  	}
  1082  	typ := t.raw.Type
  1083  	ret.Type = b.Prog.rawType(typ)
  1084  	switch typ := typ.Underlying().(type) {
  1085  	case *types.Basic:
  1086  		switch typ.Kind() {
  1087  		case types.Uintptr:
  1088  			ret.impl = castUintptr(b, x.impl, t)
  1089  			return
  1090  		case types.UnsafePointer:
  1091  			ret.impl = castPtr(b.impl, x.impl, t.ll)
  1092  			return
  1093  		}
  1094  		switch xtyp := x.RawType().Underlying().(type) {
  1095  		case *types.Basic:
  1096  			if typ.Info()&types.IsInteger != 0 {
  1097  				// int <- int/float
  1098  				if xtyp.Info()&types.IsInteger != 0 {
  1099  					ret.impl = castInt(b, x.impl, t)
  1100  					return
  1101  				} else if xtyp.Info()&types.IsFloat != 0 {
  1102  					if typ.Info()&types.IsUnsigned != 0 {
  1103  						ret.impl = b.impl.CreateFPToUI(x.impl, t.ll, "")
  1104  					} else {
  1105  						ret.impl = b.impl.CreateFPToSI(x.impl, t.ll, "")
  1106  					}
  1107  					return
  1108  				}
  1109  			} else if typ.Info()&types.IsFloat != 0 {
  1110  				// float <- int/float
  1111  				if xtyp.Info()&types.IsInteger != 0 {
  1112  					if xtyp.Info()&types.IsUnsigned != 0 {
  1113  						ret.impl = b.impl.CreateUIToFP(x.impl, t.ll, "")
  1114  					} else {
  1115  						ret.impl = b.impl.CreateSIToFP(x.impl, t.ll, "")
  1116  					}
  1117  					return
  1118  				} else if xtyp.Info()&types.IsFloat != 0 {
  1119  					ret.impl = castFloat(b, x.impl, t)
  1120  					return
  1121  				}
  1122  			}
  1123  		}
  1124  	case *types.Pointer:
  1125  		ret.impl = castPtr(b.impl, x.impl, t.ll)
  1126  		return
  1127  	}
  1128  	panic("todo")
  1129  }
  1130  
  1131  func castUintptr(b Builder, x llvm.Value, typ Type) llvm.Value {
  1132  	if x.Type().TypeKind() == llvm.PointerTypeKind {
  1133  		return llvm.CreatePtrToInt(b.impl, x, typ.ll)
  1134  	}
  1135  	return castInt(b, x, typ)
  1136  }
  1137  
  1138  func castInt(b Builder, x llvm.Value, typ Type) llvm.Value {
  1139  	xsize := b.Prog.td.TypeAllocSize(x.Type())
  1140  	size := b.Prog.td.TypeAllocSize(typ.ll)
  1141  	if xsize > size {
  1142  		return b.impl.CreateTrunc(x, typ.ll, "")
  1143  	} else if typ.kind == vkUnsigned {
  1144  		return b.impl.CreateZExt(x, typ.ll, "")
  1145  	} else {
  1146  		return b.impl.CreateSExt(x, typ.ll, "")
  1147  	}
  1148  }
  1149  
  1150  func castFloat(b Builder, x llvm.Value, typ Type) llvm.Value {
  1151  	xsize := b.Prog.td.TypeAllocSize(x.Type())
  1152  	size := b.Prog.td.TypeAllocSize(typ.ll)
  1153  	if xsize > size {
  1154  		return b.impl.CreateFPTrunc(x, typ.ll, "")
  1155  	} else {
  1156  		return b.impl.CreateFPExt(x, typ.ll, "")
  1157  	}
  1158  }
  1159  
  1160  func castPtr(b llvm.Builder, x llvm.Value, t llvm.Type) llvm.Value {
  1161  	if x.Type().TypeKind() == llvm.PointerTypeKind {
  1162  		return llvm.CreatePointerCast(b, x, t)
  1163  	}
  1164  	return llvm.CreateIntToPtr(b, x, t)
  1165  }
  1166  
  1167  // MakeInterface constructs an instance of an interface type from a
  1168  // value of a concrete type.
  1169  //
  1170  // Use Program.MethodSets.MethodSet(X.Type()) to find the method-set
  1171  // of X, and Program.MethodValue(m) to find the implementation of a method.
  1172  //
  1173  // To construct the zero value of an interface type T, use:
  1174  //
  1175  //	NewConst(constant.MakeNil(), T, pos)
  1176  //
  1177  // Example printed form:
  1178  //
  1179  //	t1 = make interface{} <- int (42:int)
  1180  //	t2 = make Stringer <- t0
  1181  func (b Builder) MakeInterface(tinter Type, x Expr) (ret Expr) {
  1182  	raw := tinter.raw.Type
  1183  	if debugInstr {
  1184  		log.Printf("MakeInterface %v, %v\n", raw, x.impl)
  1185  	}
  1186  	prog := b.Prog
  1187  	pkg := b.Func.Pkg
  1188  	switch tx := x.raw.Type.Underlying().(type) {
  1189  	case *types.Basic:
  1190  		kind := tx.Kind()
  1191  		switch {
  1192  		case kind >= types.Bool && kind <= types.Uintptr:
  1193  			t := b.InlineCall(pkg.rtFunc("Basic"), prog.Val(int(kind)))
  1194  			tptr := prog.Uintptr()
  1195  			vptr := Expr{llvm.CreateIntCast(b.impl, x.impl, tptr.ll), tptr}
  1196  			return Expr{b.InlineCall(pkg.rtFunc("MakeAnyInt"), t, vptr).impl, tinter}
  1197  		case kind == types.Float32:
  1198  			t := b.InlineCall(pkg.rtFunc("Basic"), prog.Val(int(kind)))
  1199  			tptr := prog.Uintptr()
  1200  			i32 := b.impl.CreateBitCast(x.impl, prog.tyInt32(), "")
  1201  			vptr := Expr{llvm.CreateIntCast(b.impl, i32, tptr.ll), tptr}
  1202  			return Expr{b.InlineCall(pkg.rtFunc("MakeAnyInt"), t, vptr).impl, tinter}
  1203  		case kind == types.Float64:
  1204  			t := b.InlineCall(pkg.rtFunc("Basic"), prog.Val(int(kind)))
  1205  			tptr := prog.Uintptr()
  1206  			vptr := Expr{b.impl.CreateBitCast(x.impl, tptr.ll, ""), tptr}
  1207  			return Expr{b.InlineCall(pkg.rtFunc("MakeAnyInt"), t, vptr).impl, tinter}
  1208  		case kind == types.String:
  1209  			return Expr{b.InlineCall(pkg.rtFunc("MakeAnyString"), x).impl, tinter}
  1210  		}
  1211  	}
  1212  	panic("todo")
  1213  }
  1214  
  1215  // The TypeAssert instruction tests whether interface value X has type
  1216  // AssertedType.
  1217  //
  1218  // If !CommaOk, on success it returns v, the result of the conversion
  1219  // (defined below); on failure it panics.
  1220  //
  1221  // If CommaOk: on success it returns a pair (v, true) where v is the
  1222  // result of the conversion; on failure it returns (z, false) where z
  1223  // is AssertedType's zero value.  The components of the pair must be
  1224  // accessed using the Extract instruction.
  1225  //
  1226  // If Underlying: tests whether interface value X has the underlying
  1227  // type AssertedType.
  1228  //
  1229  // If AssertedType is a concrete type, TypeAssert checks whether the
  1230  // dynamic type in interface X is equal to it, and if so, the result
  1231  // of the conversion is a copy of the value in the interface.
  1232  //
  1233  // If AssertedType is an interface, TypeAssert checks whether the
  1234  // dynamic type of the interface is assignable to it, and if so, the
  1235  // result of the conversion is a copy of the interface value X.
  1236  // If AssertedType is a superinterface of X.Type(), the operation will
  1237  // fail iff the operand is nil.  (Contrast with ChangeInterface, which
  1238  // performs no nil-check.)
  1239  //
  1240  // Type() reflects the actual type of the result, possibly a
  1241  // 2-types.Tuple; AssertedType is the asserted type.
  1242  //
  1243  // Depending on the TypeAssert's purpose, Pos may return:
  1244  //   - the ast.CallExpr.Lparen of an explicit T(e) conversion;
  1245  //   - the ast.TypeAssertExpr.Lparen of an explicit e.(T) operation;
  1246  //   - the ast.CaseClause.Case of a case of a type-switch statement;
  1247  //   - the Ident(m).NamePos of an interface method value i.m
  1248  //     (for which TypeAssert may be used to effect the nil check).
  1249  //
  1250  // Example printed form:
  1251  //
  1252  //	t1 = typeassert t0.(int)
  1253  //	t3 = typeassert,ok t2.(T)
  1254  func (b Builder) TypeAssert(x Expr, assertedTyp Type, commaOk bool) (ret Expr) {
  1255  	if debugInstr {
  1256  		log.Printf("TypeAssert %v, %v, %v\n", x.impl, assertedTyp.raw.Type, commaOk)
  1257  	}
  1258  	switch assertedTyp.kind {
  1259  	case vkSigned, vkUnsigned, vkFloat, vkBool:
  1260  		pkg := b.Func.Pkg
  1261  		fnName := "I2Int"
  1262  		if commaOk {
  1263  			fnName = "CheckI2Int"
  1264  		}
  1265  		fn := pkg.rtFunc(fnName)
  1266  		var kind types.BasicKind
  1267  		switch t := assertedTyp.raw.Type.(type) {
  1268  		case *types.Basic:
  1269  			kind = t.Kind()
  1270  		default:
  1271  			panic("todo")
  1272  		}
  1273  		typ := b.InlineCall(pkg.rtFunc("Basic"), b.Prog.Val(int(kind)))
  1274  		ret = b.InlineCall(fn, x, typ)
  1275  		if kind != types.Uintptr {
  1276  			conv := func(v llvm.Value) llvm.Value {
  1277  				switch kind {
  1278  				case types.Float32:
  1279  					v = castInt(b, v, b.Prog.Int32())
  1280  					v = b.impl.CreateBitCast(v, assertedTyp.ll, "")
  1281  				case types.Float64:
  1282  					v = b.impl.CreateBitCast(v, assertedTyp.ll, "")
  1283  				default:
  1284  					v = castInt(b, v, assertedTyp)
  1285  				}
  1286  				return v
  1287  			}
  1288  			if !commaOk {
  1289  				ret.Type = assertedTyp
  1290  				ret.impl = conv(ret.impl)
  1291  			} else {
  1292  				ret.Type = b.Prog.toTuple(
  1293  					types.NewTuple(
  1294  						types.NewVar(token.NoPos, nil, "", assertedTyp.RawType()),
  1295  						ret.Type.RawType().(*types.Tuple).At(1),
  1296  					),
  1297  				)
  1298  				val0 := conv(b.impl.CreateExtractValue(ret.impl, 0, ""))
  1299  				val1 := b.impl.CreateExtractValue(ret.impl, 1, "")
  1300  				ret.impl = llvm.ConstStruct([]llvm.Value{val0, val1}, false)
  1301  			}
  1302  		}
  1303  		return
  1304  	case vkString:
  1305  		pkg := b.Func.Pkg
  1306  		fnName := "I2String"
  1307  		if commaOk {
  1308  			fnName = "CheckI2String"
  1309  		}
  1310  		fn := pkg.rtFunc(fnName)
  1311  		typ := b.InlineCall(pkg.rtFunc("Basic"), b.Prog.Val(int(abi.String)))
  1312  		return b.InlineCall(fn, x, typ)
  1313  	}
  1314  	panic("todo")
  1315  }
  1316  
  1317  // -----------------------------------------------------------------------------
  1318  
  1319  // TODO(xsw): make inline call
  1320  func (b Builder) InlineCall(fn Expr, args ...Expr) (ret Expr) {
  1321  	return b.Call(fn, args...)
  1322  }
  1323  
  1324  // The Call instruction represents a function or method call.
  1325  //
  1326  // The Call instruction yields the function result if there is exactly
  1327  // one.  Otherwise it returns a tuple, the components of which are
  1328  // accessed via Extract.
  1329  //
  1330  // Example printed form:
  1331  //
  1332  //	t2 = println(t0, t1)
  1333  //	t4 = t3()
  1334  //	t7 = invoke t5.Println(...t6)
  1335  func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) {
  1336  	if debugInstr {
  1337  		var b bytes.Buffer
  1338  		name := fn.impl.Name()
  1339  		if name == "" {
  1340  			name = "closure"
  1341  		}
  1342  		fmt.Fprint(&b, "Call ", fn.kind, " ", fn.raw.Type, " ", name)
  1343  		sep := ": "
  1344  		for _, arg := range args {
  1345  			fmt.Fprint(&b, sep, arg.impl)
  1346  			sep = ", "
  1347  		}
  1348  		log.Println(b.String())
  1349  	}
  1350  	var kind = fn.kind
  1351  	if kind == vkPyFuncRef {
  1352  		return b.pyCall(fn, args)
  1353  	}
  1354  	var ll llvm.Type
  1355  	var data Expr
  1356  	var sig *types.Signature
  1357  	var prog = b.Prog
  1358  	var raw = fn.raw.Type
  1359  	switch kind {
  1360  	case vkClosure:
  1361  		data = b.Field(fn, 1)
  1362  		fn = b.Field(fn, 0)
  1363  		raw = fn.raw.Type
  1364  		fallthrough
  1365  	case vkFuncPtr:
  1366  		sig = raw.(*types.Signature)
  1367  		ll = prog.FuncDecl(sig, InC).ll
  1368  	case vkFuncDecl:
  1369  		sig = raw.(*types.Signature)
  1370  		ll = fn.ll
  1371  	default:
  1372  		panic("unreachable")
  1373  	}
  1374  	ret.Type = prog.retType(sig)
  1375  	ret.impl = llvm.CreateCall(b.impl, ll, fn.impl, llvmParamsEx(data, args, sig.Params(), b))
  1376  	return
  1377  }
  1378  
  1379  // The Extract instruction yields component Index of Tuple.
  1380  //
  1381  // This is used to access the results of instructions with multiple
  1382  // return values, such as Call, TypeAssert, Next, UnOp(ARROW) and
  1383  // IndexExpr(Map).
  1384  //
  1385  // Example printed form:
  1386  //
  1387  //	t1 = extract t0 #1
  1388  func (b Builder) Extract(x Expr, index int) (ret Expr) {
  1389  	ret.Type = b.Prog.toType(x.Type.raw.Type.(*types.Tuple).At(index).Type())
  1390  	ret.impl = b.impl.CreateExtractValue(x.impl, index, "")
  1391  	return
  1392  }
  1393  
  1394  // A Builtin represents a specific use of a built-in function, e.g. len.
  1395  //
  1396  // Builtins are immutable values.  Builtins do not have addresses.
  1397  //
  1398  // `fn` indicates the function: one of the built-in functions from the
  1399  // Go spec (excluding "make" and "new").
  1400  func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) {
  1401  	switch fn {
  1402  	case "len":
  1403  		if len(args) == 1 {
  1404  			arg := args[0]
  1405  			switch arg.kind {
  1406  			case vkSlice:
  1407  				return b.SliceLen(arg)
  1408  			case vkString:
  1409  				return b.StringLen(arg)
  1410  			}
  1411  		}
  1412  	case "cap":
  1413  		if len(args) == 1 {
  1414  			arg := args[0]
  1415  			switch arg.kind {
  1416  			case vkSlice:
  1417  				return b.SliceCap(arg)
  1418  			}
  1419  		}
  1420  	case "append":
  1421  		if len(args) == 2 {
  1422  			src := args[0]
  1423  			if src.kind == vkSlice {
  1424  				elem := args[1]
  1425  				switch elem.kind {
  1426  				case vkSlice:
  1427  					etSize := b.Prog.SizeOf(b.Prog.Elem(elem.Type))
  1428  					ret.Type = src.Type
  1429  					ret.impl = b.InlineCall(b.Func.Pkg.rtFunc("SliceAppend"),
  1430  						src, b.SliceData(elem), b.SliceLen(elem), b.Prog.Val(int(etSize))).impl
  1431  					return
  1432  				case vkString:
  1433  					etSize := b.Prog.SizeOf(b.Prog.Byte())
  1434  					ret.Type = src.Type
  1435  					ret.impl = b.InlineCall(b.Func.Pkg.rtFunc("SliceAppend"),
  1436  						src, b.StringData(elem), b.StringLen(elem), b.Prog.Val(int(etSize))).impl
  1437  					return
  1438  				}
  1439  			}
  1440  		}
  1441  	case "print", "println":
  1442  		ln := fn == "println"
  1443  		ret.Type = b.Prog.Void()
  1444  		for i, arg := range args {
  1445  			if ln && i > 0 {
  1446  				b.InlineCall(b.Func.Pkg.rtFunc("PrintString"), b.Str(" "))
  1447  			}
  1448  			var fn string
  1449  			var typ Type
  1450  			switch arg.kind {
  1451  			case vkBool:
  1452  				fn = "PrintBool"
  1453  			case vkSigned:
  1454  				fn = "PrintInt"
  1455  				typ = b.Prog.Int64()
  1456  			case vkUnsigned:
  1457  				fn = "PrintUint"
  1458  				typ = b.Prog.Uint64()
  1459  			case vkFloat:
  1460  				fn = "PrintFloat"
  1461  				typ = b.Prog.Float64()
  1462  			case vkSlice:
  1463  				fn = "PrintSlice"
  1464  			case vkPtr, vkFuncPtr, vkFuncDecl, vkClosure, vkPyVarRef, vkPyFuncRef:
  1465  				fn = "PrintPointer"
  1466  				typ = b.Prog.VoidPtr()
  1467  			case vkString:
  1468  				fn = "PrintString"
  1469  			case vkInterface:
  1470  				fn = "PrintIface"
  1471  			// case vkComplex:
  1472  			// 	fn = "PrintComplex"
  1473  			default:
  1474  				panic(fmt.Errorf("illegal types for operand: print %v", arg.RawType()))
  1475  			}
  1476  			if typ != nil && typ != arg.Type {
  1477  				arg = b.Convert(typ, arg)
  1478  			}
  1479  			b.InlineCall(b.Func.Pkg.rtFunc(fn), arg)
  1480  		}
  1481  		if ln {
  1482  			b.InlineCall(b.Func.Pkg.rtFunc("PrintString"), b.Str("\n"))
  1483  		}
  1484  		return
  1485  	}
  1486  	panic("todo")
  1487  }
  1488  
  1489  // -----------------------------------------------------------------------------