// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package bpf

import (
	
	
)

func aluOpConstant( ALUOpConstant,  uint32) uint32 {
	return aluOpCommon(.Op, , .Val)
}

func aluOpX( ALUOpX,  uint32,  uint32) (uint32, bool) {
	// Guard against division or modulus by zero by terminating
	// the program, as the OS BPF VM does
	if  == 0 {
		switch .Op {
		case ALUOpDiv, ALUOpMod:
			return 0, false
		}
	}

	return aluOpCommon(.Op, , ), true
}

func aluOpCommon( ALUOp,  uint32,  uint32) uint32 {
	switch  {
	case ALUOpAdd:
		return  + 
	case ALUOpSub:
		return  - 
	case ALUOpMul:
		return  * 
	case ALUOpDiv:
		// Division by zero not permitted by NewVM and aluOpX checks
		return  / 
	case ALUOpOr:
		return  | 
	case ALUOpAnd:
		return  & 
	case ALUOpShiftLeft:
		return  << 
	case ALUOpShiftRight:
		return  >> 
	case ALUOpMod:
		// Modulus by zero not permitted by NewVM and aluOpX checks
		return  % 
	case ALUOpXor:
		return  ^ 
	default:
		return 
	}
}

func jumpIf( JumpIf,  uint32) int {
	return jumpIfCommon(.Cond, .SkipTrue, .SkipFalse, , .Val)
}

func jumpIfX( JumpIfX,  uint32,  uint32) int {
	return jumpIfCommon(.Cond, .SkipTrue, .SkipFalse, , )
}

func jumpIfCommon( JumpTest, ,  uint8,  uint32,  uint32) int {
	var  bool

	switch  {
	case JumpEqual:
		 =  == 
	case JumpNotEqual:
		 =  != 
	case JumpGreaterThan:
		 =  > 
	case JumpLessThan:
		 =  < 
	case JumpGreaterOrEqual:
		 =  >= 
	case JumpLessOrEqual:
		 =  <= 
	case JumpBitsSet:
		 = ( & ) != 0
	case JumpBitsNotSet:
		 = ( & ) == 0
	}

	if  {
		return int()
	}

	return int()
}

func loadAbsolute( LoadAbsolute,  []byte) (uint32, bool) {
	 := int(.Off)
	 := .Size

	return loadCommon(, , )
}

func loadConstant( LoadConstant,  uint32,  uint32) (uint32, uint32) {
	switch .Dst {
	case RegA:
		 = .Val
	case RegX:
		 = .Val
	}

	return , 
}

func loadExtension( LoadExtension,  []byte) uint32 {
	switch .Num {
	case ExtLen:
		return uint32(len())
	default:
		panic(fmt.Sprintf("unimplemented extension: %d", .Num))
	}
}

func loadIndirect( LoadIndirect,  []byte,  uint32) (uint32, bool) {
	 := int(.Off) + int()
	 := .Size

	return loadCommon(, , )
}

func loadMemShift( LoadMemShift,  []byte) (uint32, bool) {
	 := int(.Off)

	// Size of LoadMemShift is always 1 byte
	if !inBounds(len(), , 1) {
		return 0, false
	}

	// Mask off high 4 bits and multiply low 4 bits by 4
	return uint32([]&0x0f) * 4, true
}

func inBounds( int,  int,  int) bool {
	return + <= 
}

func loadCommon( []byte,  int,  int) (uint32, bool) {
	if !inBounds(len(), , ) {
		return 0, false
	}

	switch  {
	case 1:
		return uint32([]), true
	case 2:
		return uint32(binary.BigEndian.Uint16([ : +])), true
	case 4:
		return uint32(binary.BigEndian.Uint32([ : +])), true
	default:
		panic(fmt.Sprintf("invalid load size: %d", ))
	}
}

func loadScratch( LoadScratch,  [16]uint32,  uint32,  uint32) (uint32, uint32) {
	switch .Dst {
	case RegA:
		 = [.N]
	case RegX:
		 = [.N]
	}

	return , 
}

func storeScratch( StoreScratch,  [16]uint32,  uint32,  uint32) [16]uint32 {
	switch .Src {
	case RegA:
		[.N] = 
	case RegX:
		[.N] = 
	}

	return 
}