blob: ddc49fab932feed4ad17759c94e32f06453fd04e [file] [log] [blame]
// Copyright (C) 2015 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package opcode
import (
"fmt"
"android.googlesource.com/platform/tools/gpu/binary"
"android.googlesource.com/platform/tools/gpu/replay/protocol"
)
func bit(bits, idx uint32) bool {
if bits&(1<<idx) != 0 {
return true
} else {
return false
}
}
func setBit(bits, idx uint32, v bool) uint32 {
if v {
return bits | (1 << idx)
} else {
return bits & ^(1 << idx)
}
}
// ┏━━┯━━┯━━┯━━┯━━┯━━┳━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┓
// ┃c │c │c │c │c │c ┃0 │0 │0 │0 │0 │0 │0 │0 │0 │0 │0 │0 │0 │0 │0 │0 │0 │0 │0 │0 │0 │0 │0 │0 │0 │0 ┃
// ┃ ₅│ ₄│ ₃│ ₂│ ₁│ ₀┃₂₅│₂₄│₂₃│₂₂│₂₁│₂₀│₁₉│₁₈│₁₇│₁₆│₁₅│₁₄│₁₃│₁₂│₁₁│₁₀│ ₉│ ₈│ ₇│ ₆│ ₅│ ₄│ ₃│ ₂│ ₁│ ₀┃
// ┡━━┿━━┿━━┿━━┿━━┿━━╇━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┩
// │₃₁│₃₀│₂₉│₂₈│₂₇│₂₆│₂₅│₂₄│₂₃│₂₂│₂₁│₂₀│₁₉│₁₈│₁₇│₁₆│₁₅│₁₄│₁₃│₁₂│₁₁│₁₀│ ₉│ ₈│ ₇│ ₆│ ₅│ ₄│ ₃│ ₂│ ₁│ ₀│
// └──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘
func packC(c uint32) uint32 {
if c >= 0x3f {
panic(fmt.Errorf("c exceeds 6 bits (0x%x)", c))
}
return c << 26
}
// ┏━━┯━━┯━━┯━━┯━━┯━━┳━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┓
// ┃c │c │c │c │c │c ┃x │x │x │x │x │x │x │x │x │x │x │x │x │x │x │x │x │x │x │x │x │x │x │x │x │x ┃
// ┃ ₅│ ₄│ ₃│ ₂│ ₁│ ₀┃₂₅│₂₄│₂₃│₂₂│₂₁│₂₀│₁₉│₁₈│₁₇│₁₆│₁₅│₁₄│₁₃│₁₂│₁₁│₁₀│ ₉│ ₈│ ₇│ ₆│ ₅│ ₄│ ₃│ ₂│ ₁│ ₀┃
// ┡━━┿━━┿━━┿━━┿━━┿━━╇━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┩
// │₃₁│₃₀│₂₉│₂₈│₂₇│₂₆│₂₅│₂₄│₂₃│₂₂│₂₁│₂₀│₁₉│₁₈│₁₇│₁₆│₁₅│₁₄│₁₃│₁₂│₁₁│₁₀│ ₉│ ₈│ ₇│ ₆│ ₅│ ₄│ ₃│ ₂│ ₁│ ₀│
// └──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘
func packCX(c uint32, x uint32) uint32 {
if x > 0x3ffffff {
panic(fmt.Errorf("x exceeds 26 bits (0x%x)", x))
}
return packC(c) | x
}
// ┏━━┯━━┯━━┯━━┯━━┯━━┳━━┯━━┯━━┯━━┯━━┯━━┳━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┯━━┓
// ┃c │c │c │c │c │c ┃y │y │y │y │y │y ┃z │z │z │z │z │z │z │z │z │z │z │z │z │z │z │z │z │z │z │z ┃
// ┃ ₅│ ₄│ ₃│ ₂│ ₁│ ₀┃ ₅│ ₄│ ₃│ ₂│ ₁│ ₀┃₁₉│₁₈│₁₇│₁₆│₁₅│₁₄│₁₃│₁₂│₁₁│₁₀│ ₉│ ₈│ ₇│ ₆│ ₅│ ₄│ ₃│ ₂│ ₁│ ₀┃
// ┡━━┿━━┿━━┿━━┿━━┿━━╇━━┿━━┿━━┿━━┿━━┿━━╇━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┿━━┩
// │₃₁│₃₀│₂₉│₂₈│₂₇│₂₆│₂₅│₂₄│₂₃│₂₂│₂₁│₂₀│₁₉│₁₈│₁₇│₁₆│₁₅│₁₄│₁₃│₁₂│₁₁│₁₀│ ₉│ ₈│ ₇│ ₆│ ₅│ ₄│ ₃│ ₂│ ₁│ ₀│
// └──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘
func packCYZ(c uint32, y uint32, z uint32) uint32 {
if y > 0x3f {
panic(fmt.Errorf("y exceeds 6 bits (0x%x)", y))
}
if z > 0xfffff {
panic(fmt.Errorf("z exceeds 20 bits (0x%x)", z))
}
return packC(c) | (y << 20) | z
}
func unpackC(i uint32) uint32 { return i >> 26 }
func unpackX(i uint32) uint32 { return i & 0x3ffffff }
func unpackY(i uint32) uint32 { return (i >> 20) & 0x3f }
func unpackZ(i uint32) uint32 { return i & 0xfffff }
// Call represents the CALL virtual machine opcode.
type Call struct {
PushReturn bool // Should the return value be pushed onto the stack?
FunctionID uint16 // The function identifier to call.
}
func (c Call) Encode(e binary.Encoder) error {
return e.Uint32(packCX(protocol.OpCall, setBit(uint32(c.FunctionID), 24, c.PushReturn)))
}
// PushI represents the PUSH_I virtual machine opcode.
type PushI struct {
DataType protocol.Type // The value type to push.
Value uint32 // The value to push packed into the low 20 bits.
}
func (c PushI) Encode(e binary.Encoder) error {
return e.Uint32(packCYZ(protocol.OpPushI, uint32(c.DataType), c.Value))
}
// LoadC represents the LOAD_C virtual machine opcode.
type LoadC struct {
DataType protocol.Type // The value type to load.
Address uint32 // The pointer to the value in constant address-space.
}
func (c LoadC) Encode(e binary.Encoder) error {
return e.Uint32(packCYZ(protocol.OpLoadC, uint32(c.DataType), c.Address))
}
// LoadV represents the LOAD_V virtual machine opcode.
type LoadV struct {
DataType protocol.Type // The value type to load.
Address uint32 // The pointer to the value in volatile address-space.
}
func (c LoadV) Encode(e binary.Encoder) error {
return e.Uint32(packCYZ(protocol.OpLoadV, uint32(c.DataType), c.Address))
}
// Load represents the LOAD virtual machine opcode.
type Load struct {
DataType protocol.Type // The value types to load.
}
func (c Load) Encode(e binary.Encoder) error {
return e.Uint32(packCYZ(protocol.OpLoad, uint32(c.DataType), 0))
}
// Pop represents the POP virtual machine opcode.
type Pop struct {
Count uint32 // Number of elements to pop from the top of the stack.
}
func (c Pop) Encode(e binary.Encoder) error {
return e.Uint32(packCX(protocol.OpPop, c.Count))
}
// StoreV represents the STORE_V virtual machine opcode.
type StoreV struct {
Address uint32 // Pointer in volatile address-space.
}
func (c StoreV) Encode(e binary.Encoder) error {
return e.Uint32(packCX(protocol.OpStoreV, c.Address))
}
// Store represents the STORE virtual machine opcode.
type Store struct{}
func (c Store) Encode(e binary.Encoder) error {
return e.Uint32(packC(protocol.OpStore))
}
// Resource represents the RESOURCE virtual machine opcode.
type Resource struct {
ID uint32 // The index of the resource identifier.
}
func (c Resource) Encode(e binary.Encoder) error {
return e.Uint32(packCX(protocol.OpResource, c.ID))
}
// Post represents the POST virtual machine opcode.
type Post struct{}
func (c Post) Encode(e binary.Encoder) error {
return e.Uint32(packC(protocol.OpPost))
}
// Copy represents the COPY virtual machine opcode.
type Copy struct {
Count uint32 // Number of bytes to copy.
}
func (c Copy) Encode(e binary.Encoder) error {
return e.Uint32(packCX(protocol.OpCopy, c.Count))
}
// Clone represents the CLONE virtual machine opcode.
type Clone struct {
Index uint32 // Index of element from top of stack to clone.
}
func (c Clone) Encode(e binary.Encoder) error {
return e.Uint32(packCX(protocol.OpClone, c.Index))
}
// Strcpy represents the STRCPY virtual machine opcode.
type Strcpy struct {
MaxSize uint32 // Maximum size in bytes to copy.
}
func (c Strcpy) Encode(e binary.Encoder) error {
return e.Uint32(packCX(protocol.OpStrcpy, c.MaxSize))
}
// Extend represents the EXTEND virtual machine opcode.
type Extend struct {
Value uint32 // 26 bit value to extend the top of the stack by.
}
func (c Extend) Encode(e binary.Encoder) error {
return e.Uint32(packCX(protocol.OpExtend, c.Value))
}
// Extend represents the LABEL virtual machine opcode.
type Label struct {
Value uint32 // 26 bit label name.
}
func (c Label) Encode(e binary.Encoder) error {
return e.Uint32(packCX(protocol.OpLabel, c.Value))
}
// Decode returns the opcode decoded from decoder d.
func Decode(d binary.Decoder) (interface{}, error) {
i, err := d.Uint32()
if err != nil {
return nil, err
}
code := unpackC(i)
switch code {
case protocol.OpCall:
return Call{PushReturn: bit(i, 24), FunctionID: uint16(unpackX(i))}, nil
case protocol.OpPushI:
return PushI{DataType: protocol.Type(unpackY(i)), Value: unpackZ(i)}, nil
case protocol.OpLoadC:
return LoadC{DataType: protocol.Type(unpackY(i)), Address: unpackZ(i)}, nil
case protocol.OpLoadV:
return LoadV{DataType: protocol.Type(unpackY(i)), Address: unpackZ(i)}, nil
case protocol.OpLoad:
return Load{DataType: protocol.Type(unpackY(i))}, nil
case protocol.OpPop:
return Pop{Count: unpackX(i)}, nil
case protocol.OpStoreV:
return StoreV{Address: unpackX(i)}, nil
case protocol.OpStore:
return Store{}, nil
case protocol.OpResource:
return Resource{ID: unpackX(i)}, nil
case protocol.OpPost:
return Post{}, nil
case protocol.OpCopy:
return Copy{Count: unpackX(i)}, nil
case protocol.OpClone:
return Clone{Index: unpackX(i)}, nil
case protocol.OpStrcpy:
return Strcpy{MaxSize: unpackX(i)}, nil
case protocol.OpExtend:
return Extend{Value: unpackX(i)}, nil
case protocol.OpLabel:
return Label{Value: unpackX(i)}, nil
default:
return nil, fmt.Errorf("Unknown opcode with code %v", code)
}
}