func sortTargets(targets map[pos][]*block) []pos {
	keys := make([]pos, len(targets))
	i := 0
	for k := range targets {
		keys[i] = k
		i++
	}
	sort.Slice(keys, func(i, j int) bool {
		return keys[i] < keys[j]
	})
	return keys
}
sortTargets sorts the target positions (keys), lowest first
package cbpfc
import (
	"fmt"
	"sort"
	"github.com/pkg/errors"
	"golang.org/x/net/bpf"
)
var condToInverse = map[bpf.JumpTest]bpf.JumpTest{
	bpf.JumpEqual:          bpf.JumpNotEqual,
	bpf.JumpNotEqual:       bpf.JumpEqual,
	bpf.JumpGreaterThan:    bpf.JumpLessOrEqual,
	bpf.JumpLessThan:       bpf.JumpGreaterOrEqual,
	bpf.JumpGreaterOrEqual: bpf.JumpLessThan,
	bpf.JumpLessOrEqual:    bpf.JumpGreaterThan,
	bpf.JumpBitsSet:        bpf.JumpBitsNotSet,
	bpf.JumpBitsNotSet:     bpf.JumpBitsSet,
}
type pos uint
type skip uint
type instruction struct {
	bpf.Instruction
	id pos
}
func (i instruction) String() string {
	return fmt.Sprintf("%d: %v", i.id, i.Instruction)
}
type block struct {
	insns []instruction
	jumps map[pos]*block
	id pos
}
func newBlock(insns []instruction) *block {
	return &block{
		insns: insns,
		jumps: make(map[pos]*block),
		id:    insns[0].id,
	}
}
func (b *block) Label() string {
	return fmt.Sprintf("block_%d", b.id)
}
func (b *block) skipToPos(s skip) pos {
	return b.last().id + 1 + pos(s)
}
func (b *block) skipToBlock(s skip) *block {
	return b.jumps[b.skipToPos(s)]
}
func (b *block) last() instruction {
	return b.insns[len(b.insns)-1]
}
type packetGuard uint32
type packetGuardAbsolute struct {
	guard packetGuard
}
func (p packetGuardAbsolute) Assemble() (bpf.RawInstruction, error) {
	return bpf.RawInstruction{}, errors.Errorf("unsupported")
}
type packetGuardIndirect struct {
	guard packetGuard
}
func (p packetGuardIndirect) Assemble() (bpf.RawInstruction, error) {
	return bpf.RawInstruction{}, errors.Errorf("unsupported")
}
type checkXNotZero struct {
}
func (c checkXNotZero) Assemble() (bpf.RawInstruction, error) {
	return bpf.RawInstruction{}, errors.Errorf("unsupported")
}
func compile(insns []bpf.Instruction) ([]*block, error) {
	err := validateInstructions(insns)
	if err != nil {
		return nil, err
	}
	instructions := toInstructions(insns)
	normalizeJumps(instructions)
	blocks, err := splitBlocks(instructions)
	if err != nil {
		return nil, errors.Wrapf(err, "unable to compute blocks")
	}
	err = initializeMemory(blocks)
	if err != nil {
		return nil, err
	}
	err = addDivideByZeroGuards(blocks)
	if err != nil {
		return nil, err
	}
	addAbsolutePacketGuards(blocks)
	addIndirectPacketGuards(blocks)
	return blocks, nil
}
func validateInstructions(insns []bpf.Instruction) error {
	if len(insns) == 0 {
		return errors.New("can't compile 0 instructions")
	}
	for pc, insn := range insns {
		_, err := insn.Assemble()
		if err != nil {
			return errors.Errorf("can't assemble instruction %d: %v", pc, insn)
		}
		switch i := insn.(type) {
		case bpf.RawInstruction:
			return errors.Errorf("unsupported instruction %d: %v", pc, insn)
		case bpf.LoadExtension:
			switch i.Num {
			case bpf.ExtLen:
				break
			default:
				return errors.Errorf("unsupported BPF extension %d: %v", pc, insn)
			}
		}
	}
	return nil
}
func toInstructions(insns []bpf.Instruction) []instruction {
	instructions := make([]instruction, len(insns))
	for pc, insn := range insns {
		instructions[pc] = instruction{
			Instruction: insn,
			id:          pos(pc),
		}
	}
	return instructions
}
func normalizeJumps(insns []instruction) {
	for pc := range insns {
		switch i := insns[pc].Instruction.(type) {
		case bpf.JumpIf:
			if !shouldInvert(i.SkipTrue, i.SkipFalse) {
				continue
			}
			insns[pc].Instruction = bpf.JumpIf{Cond: condToInverse[i.Cond], Val: i.Val, SkipTrue: i.SkipFalse, SkipFalse: i.SkipTrue}
		case bpf.JumpIfX:
			if !shouldInvert(i.SkipTrue, i.SkipFalse) {
				continue
			}
			insns[pc].Instruction = bpf.JumpIfX{Cond: condToInverse[i.Cond], SkipTrue: i.SkipFalse, SkipFalse: i.SkipTrue}
		}
	}
}
func shouldInvert(skipTrue, skipFalse uint8) bool {
	return skipTrue == 0 && skipFalse != 0
}
func visitBlock(insns []instruction, target pos) (*block, []skip) {
	for pc, insn := range insns {
		var skips []skip
		switch i := insn.Instruction.(type) {
		case bpf.Jump:
			skips = []skip{skip(i.Skip)}
		case bpf.JumpIf:
			skips = []skip{skip(i.SkipTrue), skip(i.SkipFalse)}
		case bpf.JumpIfX:
			skips = []skip{skip(i.SkipTrue), skip(i.SkipFalse)}
		case bpf.RetA, bpf.RetConstant:
		default:
			continue
		}
		return newBlock(insns[:pc+1]), skips
	}
	return newBlock(insns), []skip{0}
}
func splitBlocks(instructions []instruction) ([]*block, error) {
	blocks := []*block{}
	targets := map[pos][]*block{
		0: nil,
	}
	for len(targets) > 0 {
		sortedTargets := sortTargets(targets)
		target := sortedTargets[0]
		end := len(instructions)
		if len(sortedTargets) > 1 {
			end = int(sortedTargets[1])
		}
		next, nextSkips := visitBlock(instructions[target:end], target)
		for _, s := range nextSkips {
			t := next.skipToPos(s)
			if t >= pos(len(instructions)) {
				return nil, errors.Errorf("instruction %v flows past last instruction", next.last())
			}
			targets[t] = append(targets[t], next)
		}
		jmpBlocks := targets[target]
		for _, jmpBlock := range jmpBlocks {
			jmpBlock.jumps[target] = next
		}
		blocks = append(blocks, next)
		delete(targets, target)
	}
	return blocks, nil
}