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}
		}
	}
}
normalizeJumps normalizes conditional jumps to always use skipTrue:
Jumps that only use skipTrue (skipFalse == 0) are unchanged.
Jumps that use both skipTrue and skipFalse are unchanged.
Jumps that only use skipFalse (skipTrue == 0) are inverted to only use skipTrue.
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
}