func (ic instrCompiler) ProcessCallInstr(c ir.Call) {
	call := code.Call
	if c.Tail {
		call = code.TailCall
	}
	opcode := call(ic.codeReg(c.Cont))
	ic.Emit(opcode)
}
ProcessCallInstr compiles a Call instruction.
package ircomp
import (
	"fmt"
	"math"
	"github.com/arnodel/golua/code"
	"github.com/arnodel/golua/ir"
	"github.com/arnodel/golua/ops"
)
type instrCompiler struct {
	*ConstantCompiler
	*regAllocator
	line int
}
var _ ir.InstrProcessor = instrCompiler{}
func (ic instrCompiler) Emit(opcode code.Opcode) {
	ic.builder.Emit(opcode, ic.line)
}
func (ic instrCompiler) EmitJump(opcode code.Opcode, lbl code.Label) {
	ic.builder.EmitJump(opcode, lbl, ic.line)
}
func (ic instrCompiler) ProcessCombineInstr(c ir.Combine) {
	codeOp, ok := codeBinOp[c.Op]
	if !ok {
		panic(fmt.Sprintf("Cannot compile %v: invalid op", c))
	}
	opcode := code.Combine(codeOp, ic.codeReg(c.Dst), ic.codeReg(c.Lsrc), ic.codeReg(c.Rsrc))
	ic.Emit(opcode)
}
var codeBinOp = map[ops.Op]code.BinOp{
	ops.OpLt:       code.OpLt,
	ops.OpLeq:      code.OpLeq,
	ops.OpEq:       code.OpEq,
	ops.OpBitOr:    code.OpBitOr,
	ops.OpBitXor:   code.OpBitXor,
	ops.OpBitAnd:   code.OpBitAnd,
	ops.OpShiftL:   code.OpShiftL,
	ops.OpShiftR:   code.OpShiftR,
	ops.OpConcat:   code.OpConcat,
	ops.OpAdd:      code.OpAdd,
	ops.OpSub:      code.OpSub,
	ops.OpMul:      code.OpMul,
	ops.OpDiv:      code.OpDiv,
	ops.OpFloorDiv: code.OpFloorDiv,
	ops.OpMod:      code.OpMod,
	ops.OpPow:      code.OpPow,
}
func (ic instrCompiler) ProcessTransformInstr(t ir.Transform) {
	codeOp, ok := codeUnOp[t.Op]
	if !ok {
		panic(fmt.Sprintf("Cannot compile %v: invalid op", t))
	}
	opcode := code.Transform(codeOp, ic.codeReg(t.Dst), ic.codeReg(t.Src))
	ic.Emit(opcode)
}
var codeUnOp = map[ops.Op]code.UnOp{
	ops.OpNeg:      code.OpNeg,
	ops.OpNot:      code.OpNot,
	ops.OpLen:      code.OpLen,
	ops.OpBitNot:   code.OpBitNot,
	ops.OpId:       code.OpId,
	ops.OpToNumber: code.OpToNumber,
}
func (ic instrCompiler) ProcessLoadConstInstr(l ir.LoadConst) {
	k := ic.GetConstant(l.Kidx)
	dst := ic.codeReg(l.Dst)
	var opcode code.Opcode
	var inlined bool
	switch kk := k.(type) {
	case ir.Int:
		opcode, inlined = code.LoadSmallInt(dst, int(kk))
	case ir.String:
		opcode, inlined = code.LoadShortString(dst, []byte(kk))
	case ir.Bool:
		opcode, inlined = code.LoadBool(dst, bool(kk)), true
	case ir.NilType:
		opcode, inlined = code.LoadNil(dst), true
	}
	if !inlined {
		ckidx := ic.QueueConstant(l.Kidx)
		opcode = code.LoadConst(dst, code.KIndexFromInt(ckidx))
	}
	ic.Emit(opcode)
}
func (ic instrCompiler) ProcessPushInstr(p ir.Push) {
	var opcode code.Opcode
	if p.Etc {
		opcode = code.PushEtc(ic.codeReg(p.Cont), ic.codeReg(p.Item))
	} else {
		opcode = code.Push(ic.codeReg(p.Cont), ic.codeReg(p.Item))
	}
	ic.Emit(opcode)
}
func (ic instrCompiler) ProcessJumpInstr(j ir.Jump) {
	opcode := code.Jump(0)
	ic.EmitJump(opcode, code.Label(j.Label))
}
func (ic instrCompiler) ProcessJumpIfInstr(j ir.JumpIf) {
	var opcode code.Opcode
	if j.Not {
		opcode = code.JumpIfNot(0, ic.codeReg(j.Cond))
	} else {
		opcode = code.JumpIf(0, ic.codeReg(j.Cond))
	}
	ic.EmitJump(opcode, code.Label(j.Label))
}