blob: e5e9e245045e2f3e67bdced7209a6ca0269b3d9b [file] [log] [blame]
// Copyright (c) 2017-2019 ARM Limited
// All rights reserved
//
// The license below extends only to copyright in the software and shall
// not be construed as granting a license to any other intellectual
// property including but not limited to intellectual property relating
// to a hardware implementation of the functionality of the software
// licensed hereunder. You may use the software subject to the license
// terms below provided that you ensure that this notice is replicated
// unmodified and in its entirety in all distributions of the software,
// modified or unmodified, in source code or in binary form.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Authors: Giacomo Gabrielli
// @file Definition of SVE instructions.
output header {{
// Decodes unary, constructive, predicated (merging) SVE instructions,
// handling signed and unsigned variants.
template <template <typename T> class BaseS,
template <typename T> class BaseU>
StaticInstPtr
decodeSveUnaryPred(unsigned size, unsigned u, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1, IntRegIndex gp)
{
switch (size) {
case 0:
if (u) {
return new BaseU<uint8_t>(machInst, dest, op1, gp);
} else {
return new BaseS<int8_t>(machInst, dest, op1, gp);
}
case 1:
if (u) {
return new BaseU<uint16_t>(machInst, dest, op1, gp);
} else {
return new BaseS<int16_t>(machInst, dest, op1, gp);
}
case 2:
if (u) {
return new BaseU<uint32_t>(machInst, dest, op1, gp);
} else {
return new BaseS<int32_t>(machInst, dest, op1, gp);
}
case 3:
if (u) {
return new BaseU<uint64_t>(machInst, dest, op1, gp);
} else {
return new BaseS<int64_t>(machInst, dest, op1, gp);
}
default:
return new Unknown64(machInst);
}
}
// Decodes SVE widening reductions.
// handling signed and unsigned variants.
template <template <typename T1, typename T2> class BaseS,
template <typename T1, typename T2> class BaseU>
StaticInstPtr
decodeSveWideningReduc(unsigned size, unsigned u, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1, IntRegIndex gp)
{
switch (size) {
case 0:
if (u) {
return new BaseU<uint8_t, uint64_t>(machInst, dest, op1, gp);
} else {
return new BaseS<int8_t, int64_t>(machInst, dest, op1, gp);
}
case 1:
if (u) {
return new BaseU<uint16_t, uint64_t>(machInst, dest, op1, gp);
} else {
return new BaseS<int16_t, int64_t>(machInst, dest, op1, gp);
}
case 2:
if (u) {
return new BaseU<uint32_t, uint64_t>(machInst, dest, op1, gp);
} else {
return new BaseS<int32_t, int64_t>(machInst, dest, op1, gp);
}
case 3:
assert(u);
return new BaseU<uint64_t, uint64_t>(machInst, dest, op1, gp);
default:
return new Unknown64(machInst);
}
}
// Decodes unary, constructive, predicated (merging) SVE instructions,
// handling signed variants only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveUnaryPredS(unsigned size, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1, IntRegIndex gp)
{
switch (size) {
case 0:
return new Base<int8_t>(machInst, dest, op1, gp);
case 1:
return new Base<int16_t>(machInst, dest, op1, gp);
case 2:
return new Base<int32_t>(machInst, dest, op1, gp);
case 3:
return new Base<int64_t>(machInst, dest, op1, gp);
default:
return new Unknown64(machInst);
}
}
// Decodes unary, constructive, predicated (merging) SVE instructions,
// handling unsigned variants only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveUnaryPredU(unsigned size, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1, IntRegIndex gp)
{
switch (size) {
case 0:
return new Base<uint8_t>(machInst, dest, op1, gp);
case 1:
return new Base<uint16_t>(machInst, dest, op1, gp);
case 2:
return new Base<uint32_t>(machInst, dest, op1, gp);
case 3:
return new Base<uint64_t>(machInst, dest, op1, gp);
default:
return new Unknown64(machInst);
}
}
// Decodes unary, constructive, predicated (merging) SVE instructions,
// handling signed and unsigned variants, for small element sizes (8- to
// 32-bit).
template <template <typename T> class BaseS,
template <typename T> class BaseU>
StaticInstPtr
decodeSveUnaryPredSmall(unsigned size, unsigned u, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1, IntRegIndex gp)
{
switch (size) {
case 0:
if (u) {
return new BaseU<uint8_t>(machInst, dest, op1, gp);
} else {
return new BaseS<int8_t>(machInst, dest, op1, gp);
}
case 1:
if (u) {
return new BaseU<uint16_t>(machInst, dest, op1, gp);
} else {
return new BaseS<int16_t>(machInst, dest, op1, gp);
}
case 2:
if (u) {
return new BaseU<uint32_t>(machInst, dest, op1, gp);
} else {
return new BaseS<int32_t>(machInst, dest, op1, gp);
}
default:
return new Unknown64(machInst);
}
}
// Decodes unary, constructive, predicated (merging) SVE instructions,
// handling floating point variants only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveUnaryPredF(unsigned size, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1, IntRegIndex gp)
{
switch (size) {
case 1:
return new Base<uint16_t>(machInst, dest, op1, gp);
case 2:
return new Base<uint32_t>(machInst, dest, op1, gp);
case 3:
return new Base<uint64_t>(machInst, dest, op1, gp);
default:
return new Unknown64(machInst);
}
}
// Decodes unary, constructive, unpredicated SVE instructions, handling
// unsigned variants only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveUnaryUnpredU(unsigned size, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1)
{
switch (size) {
case 0:
return new Base<uint8_t>(machInst, dest, op1);
case 1:
return new Base<uint16_t>(machInst, dest, op1);
case 2:
return new Base<uint32_t>(machInst, dest, op1);
case 3:
return new Base<uint64_t>(machInst, dest, op1);
default:
return new Unknown64(machInst);
}
}
// Decodes unary, constructive, unpredicated SVE instructions, handling
// floating-point variants only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveUnaryUnpredF(unsigned size, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1)
{
switch (size) {
case 1:
return new Base<uint16_t>(machInst, dest, op1);
case 2:
return new Base<uint32_t>(machInst, dest, op1);
case 3:
return new Base<uint64_t>(machInst, dest, op1);
default:
return new Unknown64(machInst);
}
}
// Decodes binary, destructive, predicated (merging) SVE instructions,
// handling signed and unsigned variants.
template <template <typename T> class BaseS,
template <typename T> class BaseU>
StaticInstPtr
decodeSveBinDestrPred(unsigned size, unsigned u, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op2, IntRegIndex gp)
{
switch (size) {
case 0:
if (u) {
return new BaseU<uint8_t>(machInst, dest, op2, gp);
} else {
return new BaseS<int8_t>(machInst, dest, op2, gp);
}
case 1:
if (u) {
return new BaseU<uint16_t>(machInst, dest, op2, gp);
} else {
return new BaseS<int16_t>(machInst, dest, op2, gp);
}
case 2:
if (u) {
return new BaseU<uint32_t>(machInst, dest, op2, gp);
} else {
return new BaseS<int32_t>(machInst, dest, op2, gp);
}
case 3:
if (u) {
return new BaseU<uint64_t>(machInst, dest, op2, gp);
} else {
return new BaseS<int64_t>(machInst, dest, op2, gp);
}
default:
return new Unknown64(machInst);
}
}
// Decodes binary with immediate operand, constructive, unpredicated
// SVE instructions, handling signed variants only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveBinImmUnpredS(unsigned size, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1, unsigned immediate)
{
switch (size) {
case 0:
return new Base<int8_t>(machInst, dest, op1, immediate);
case 1:
return new Base<int16_t>(machInst, dest, op1, immediate);
case 2:
return new Base<int32_t>(machInst, dest, op1, immediate);
case 3:
return new Base<int64_t>(machInst, dest, op1, immediate);
default:
return new Unknown64(machInst);
}
}
// Decodes binary with immediate operand, constructive, unpredicated
// SVE instructions, handling unsigned variants only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveBinImmUnpredU(unsigned size, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1, unsigned immediate)
{
switch (size) {
case 0:
return new Base<uint8_t>(machInst, dest, op1, immediate);
case 1:
return new Base<uint16_t>(machInst, dest, op1, immediate);
case 2:
return new Base<uint32_t>(machInst, dest, op1, immediate);
case 3:
return new Base<uint64_t>(machInst, dest, op1, immediate);
default:
return new Unknown64(machInst);
}
}
// Decodes binary with immediate operand, destructive, predicated (merging)
// SVE instructions, handling unsigned variants only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveBinImmPredU(unsigned size, ExtMachInst machInst, IntRegIndex dest,
unsigned immediate, IntRegIndex gp)
{
switch (size) {
case 0:
return new Base<uint8_t>(machInst, dest, immediate, gp);
case 1:
return new Base<uint16_t>(machInst, dest, immediate, gp);
case 2:
return new Base<uint32_t>(machInst, dest, immediate, gp);
case 3:
return new Base<uint64_t>(machInst, dest, immediate, gp);
default:
return new Unknown64(machInst);
}
}
// Decodes binary with immediate operand, destructive, predicated (merging)
// SVE instructions, handling signed variants only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveBinImmPredS(unsigned size, ExtMachInst machInst, IntRegIndex dest,
unsigned immediate, IntRegIndex gp)
{
switch (size) {
case 0:
return new Base<int8_t>(machInst, dest, immediate, gp);
case 1:
return new Base<int16_t>(machInst, dest, immediate, gp);
case 2:
return new Base<int32_t>(machInst, dest, immediate, gp);
case 3:
return new Base<int64_t>(machInst, dest, immediate, gp);
default:
return new Unknown64(machInst);
}
}
// Decodes binary with immediate operand, destructive, predicated (merging)
// SVE instructions, handling floating-point variants only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveBinImmPredF(unsigned size, ExtMachInst machInst, IntRegIndex dest,
uint64_t immediate, IntRegIndex gp)
{
switch (size) {
case 1:
return new Base<uint16_t>(machInst, dest, immediate, gp);
case 2:
return new Base<uint32_t>(machInst, dest, immediate, gp);
case 3:
return new Base<uint64_t>(machInst, dest, immediate, gp);
default:
return new Unknown64(machInst);
}
}
// Decodes unary/binary with wide immediate operand, destructive,
// unpredicated SVE instructions, handling unsigned variants only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveWideImmUnpredU(unsigned size, ExtMachInst machInst,
IntRegIndex dest, uint64_t immediate)
{
switch (size) {
case 0:
return new Base<uint8_t>(machInst, dest, immediate);
case 1:
return new Base<uint16_t>(machInst, dest, immediate);
case 2:
return new Base<uint32_t>(machInst, dest, immediate);
case 3:
return new Base<uint64_t>(machInst, dest, immediate);
default:
return new Unknown64(machInst);
}
}
// Decodes unary/binary with wide immediate operand, destructive,
// unpredicated SVE instructions, handling signed variants only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveWideImmUnpredS(unsigned size, ExtMachInst machInst,
IntRegIndex dest, uint64_t immediate)
{
switch (size) {
case 0:
return new Base<int8_t>(machInst, dest, immediate);
case 1:
return new Base<int16_t>(machInst, dest, immediate);
case 2:
return new Base<int32_t>(machInst, dest, immediate);
case 3:
return new Base<int64_t>(machInst, dest, immediate);
default:
return new Unknown64(machInst);
}
}
// Decodes unary/binary with wide immediate operand, destructive,
// unpredicated SVE instructions, handling floating-point variants only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveWideImmUnpredF(unsigned size, ExtMachInst machInst,
IntRegIndex dest, uint64_t immediate)
{
switch (size) {
case 1:
return new Base<uint16_t>(machInst, dest, immediate);
case 2:
return new Base<uint32_t>(machInst, dest, immediate);
case 3:
return new Base<uint64_t>(machInst, dest, immediate);
default:
return new Unknown64(machInst);
}
}
// Decodes unary/binary with wide immediate operand, destructive,
// predicated SVE instructions, handling unsigned variants only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveWideImmPredU(unsigned size, ExtMachInst machInst,
IntRegIndex dest, uint64_t immediate, IntRegIndex gp,
bool isMerging = true)
{
switch (size) {
case 0:
return new Base<uint8_t>(machInst, dest, immediate, gp,
isMerging);
case 1:
return new Base<uint16_t>(machInst, dest, immediate, gp,
isMerging);
case 2:
return new Base<uint32_t>(machInst, dest, immediate, gp,
isMerging);
case 3:
return new Base<uint64_t>(machInst, dest, immediate, gp,
isMerging);
default:
return new Unknown64(machInst);
}
}
// Decodes unary/binary with wide immediate operand, destructive,
// predicated SVE instructions, handling floating-point variants only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveWideImmPredF(unsigned size, ExtMachInst machInst,
IntRegIndex dest, uint64_t immediate, IntRegIndex gp)
{
switch (size) {
case 1:
return new Base<uint16_t>(machInst, dest, immediate, gp);
case 2:
return new Base<uint32_t>(machInst, dest, immediate, gp);
case 3:
return new Base<uint64_t>(machInst, dest, immediate, gp);
default:
return new Unknown64(machInst);
}
}
// Decodes binary, destructive, predicated (merging) SVE instructions,
// handling unsigned variants only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveBinDestrPredU(unsigned size, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op2, IntRegIndex gp)
{
switch (size) {
case 0:
return new Base<uint8_t>(machInst, dest, op2, gp);
case 1:
return new Base<uint16_t>(machInst, dest, op2, gp);
case 2:
return new Base<uint32_t>(machInst, dest, op2, gp);
case 3:
return new Base<uint64_t>(machInst, dest, op2, gp);
default:
return new Unknown64(machInst);
}
}
// Decodes binary, destructive, predicated (merging) SVE instructions,
// handling signed variants only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveBinDestrPredS(unsigned size, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op2, IntRegIndex gp)
{
switch (size) {
case 0:
return new Base<int8_t>(machInst, dest, op2, gp);
case 1:
return new Base<int16_t>(machInst, dest, op2, gp);
case 2:
return new Base<int32_t>(machInst, dest, op2, gp);
case 3:
return new Base<int64_t>(machInst, dest, op2, gp);
default:
return new Unknown64(machInst);
}
}
// Decodes binary, destructive, predicated (merging) SVE instructions,
// handling floating-point variants only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveBinDestrPredF(unsigned size, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op2, IntRegIndex gp)
{
switch (size) {
case 1:
return new Base<uint16_t>(machInst, dest, op2, gp);
case 2:
return new Base<uint32_t>(machInst, dest, op2, gp);
case 3:
return new Base<uint64_t>(machInst, dest, op2, gp);
default:
return new Unknown64(machInst);
}
}
// Decodes binary, constructive, predicated SVE instructions, handling
// unsigned variants only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveBinConstrPredU(unsigned size, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1, IntRegIndex op2,
IntRegIndex gp, SvePredType predType)
{
switch (size) {
case 0:
return new Base<uint8_t>(machInst, dest, op1, op2, gp, predType);
case 1:
return new Base<uint16_t>(machInst, dest, op1, op2, gp, predType);
case 2:
return new Base<uint32_t>(machInst, dest, op1, op2, gp, predType);
case 3:
return new Base<uint64_t>(machInst, dest, op1, op2, gp, predType);
default:
return new Unknown64(machInst);
}
}
// Decodes binary, constructive, unpredicated SVE instructions.
template <template <typename T> class Base>
StaticInstPtr
decodeSveBinUnpred(unsigned size, unsigned u, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1, IntRegIndex op2)
{
switch (size) {
case 0:
if (u) {
return new Base<uint8_t>(machInst, dest, op1, op2);
} else {
return new Base<int8_t>(machInst, dest, op1, op2);
}
case 1:
if (u) {
return new Base<uint16_t>(machInst, dest, op1, op2);
} else {
return new Base<int16_t>(machInst, dest, op1, op2);
}
case 2:
if (u) {
return new Base<uint32_t>(machInst, dest, op1, op2);
} else {
return new Base<int32_t>(machInst, dest, op1, op2);
}
case 3:
if (u) {
return new Base<uint64_t>(machInst, dest, op1, op2);
} else {
return new Base<int64_t>(machInst, dest, op1, op2);
}
default:
return new Unknown64(machInst);
}
}
// Decodes binary, constructive, unpredicated SVE instructions.
// Unsigned instructions only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveBinUnpredU(unsigned size, ExtMachInst machInst, IntRegIndex dest,
IntRegIndex op1, IntRegIndex op2)
{
switch (size) {
case 0:
return new Base<uint8_t>(machInst, dest, op1, op2);
case 1:
return new Base<uint16_t>(machInst, dest, op1, op2);
case 2:
return new Base<uint32_t>(machInst, dest, op1, op2);
case 3:
return new Base<uint64_t>(machInst, dest, op1, op2);
default:
return new Unknown64(machInst);
}
}
// Decodes binary, constructive, unpredicated SVE instructions.
// Signed instructions only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveBinUnpredS(unsigned size, ExtMachInst machInst, IntRegIndex dest,
IntRegIndex op1, IntRegIndex op2)
{
switch (size) {
case 0:
return new Base<int8_t>(machInst, dest, op1, op2);
case 1:
return new Base<int16_t>(machInst, dest, op1, op2);
case 2:
return new Base<int32_t>(machInst, dest, op1, op2);
case 3:
return new Base<int64_t>(machInst, dest, op1, op2);
default:
return new Unknown64(machInst);
}
}
// Decodes binary, costructive, unpredicated SVE instructions, handling
// floating-point variants only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveBinUnpredF(unsigned size, ExtMachInst machInst, IntRegIndex dest,
IntRegIndex op1, IntRegIndex op2)
{
switch (size) {
case 1:
return new Base<uint16_t>(machInst, dest, op1, op2);
case 2:
return new Base<uint32_t>(machInst, dest, op1, op2);
case 3:
return new Base<uint64_t>(machInst, dest, op1, op2);
default:
return new Unknown64(machInst);
}
}
// Decodes SVE compare instructions - binary, predicated (zeroing),
// generating a predicate - handling floating-point variants only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveCmpF(unsigned size, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1, IntRegIndex op2,
IntRegIndex gp)
{
switch (size) {
case 1:
return new Base<uint16_t>(machInst, dest, op1, op2, gp);
case 2:
return new Base<uint32_t>(machInst, dest, op1, op2, gp);
case 3:
return new Base<uint64_t>(machInst, dest, op1, op2, gp);
default:
return new Unknown64(machInst);
}
}
// Decodes SVE compare-with-immediate instructions - binary, predicated
// (zeroing), generating a predicate - handling floating-point variants
// only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveCmpImmF(unsigned size, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1, uint64_t imm,
IntRegIndex gp)
{
switch (size) {
case 1:
return new Base<uint16_t>(machInst, dest, op1, imm, gp);
case 2:
return new Base<uint32_t>(machInst, dest, op1, imm, gp);
case 3:
return new Base<uint64_t>(machInst, dest, op1, imm, gp);
default:
return new Unknown64(machInst);
}
}
// Decodes ternary, destructive, predicated (merging) SVE instructions.
template <template <typename T> class Base>
StaticInstPtr
decodeSveTerPred(unsigned size, unsigned u, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1, IntRegIndex op2,
IntRegIndex gp)
{
switch (size) {
case 0:
if (u) {
return new Base<uint8_t>(machInst, dest, op1, op2, gp);
} else {
return new Base<int8_t>(machInst, dest, op1, op2, gp);
}
case 1:
if (u) {
return new Base<uint16_t>(machInst, dest, op1, op2, gp);
} else {
return new Base<int16_t>(machInst, dest, op1, op2, gp);
}
case 2:
if (u) {
return new Base<uint32_t>(machInst, dest, op1, op2, gp);
} else {
return new Base<int32_t>(machInst, dest, op1, op2, gp);
}
case 3:
if (u) {
return new Base<uint64_t>(machInst, dest, op1, op2, gp);
} else {
return new Base<int64_t>(machInst, dest, op1, op2, gp);
}
default:
return new Unknown64(machInst);
}
}
// Decodes ternary, destructive, predicated (merging) SVE instructions,
// handling wide signed variants only. XXX: zeroing for CMP instructions.
template <template <typename T> class Base>
StaticInstPtr
decodeSveTerPredWS(unsigned size, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1, IntRegIndex op2,
IntRegIndex gp)
{
switch (size) {
case 0:
return new Base<int8_t>(machInst, dest, op1, op2, gp);
case 1:
return new Base<int16_t>(machInst, dest, op1, op2, gp);
case 2:
return new Base<int32_t>(machInst, dest, op1, op2, gp);
default:
return new Unknown64(machInst);
}
}
// Decodes ternary, destructive, predicated (merging) SVE instructions,
// handling wide unsigned variants only. XXX: zeroing for CMP instructions.
template <template <typename T> class Base>
StaticInstPtr
decodeSveTerPredWU(unsigned size, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1, IntRegIndex op2,
IntRegIndex gp)
{
switch (size) {
case 0:
return new Base<uint8_t>(machInst, dest, op1, op2, gp);
case 1:
return new Base<uint16_t>(machInst, dest, op1, op2, gp);
case 2:
return new Base<uint32_t>(machInst, dest, op1, op2, gp);
default:
return new Unknown64(machInst);
}
}
// Decodes ternary, destructive, predicated (merging) SVE instructions,
// handling signed variants only. XXX: zeroing for CMP instructions.
template <template <typename T> class Base>
StaticInstPtr
decodeSveTerPredS(unsigned size, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1, IntRegIndex op2,
IntRegIndex gp)
{
switch (size) {
case 0:
return new Base<int8_t>(machInst, dest, op1, op2, gp);
case 1:
return new Base<int16_t>(machInst, dest, op1, op2, gp);
case 2:
return new Base<int32_t>(machInst, dest, op1, op2, gp);
case 3:
return new Base<int64_t>(machInst, dest, op1, op2, gp);
default:
return new Unknown64(machInst);
}
}
// Decodes ternary, destructive, predicated (merging) SVE instructions,
// handling unsigned variants only. XXX: zeroing for CMP instructions.
template <template <typename T> class Base>
StaticInstPtr
decodeSveTerPredU(unsigned size, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1, IntRegIndex op2,
IntRegIndex gp)
{
switch (size) {
case 0:
return new Base<uint8_t>(machInst, dest, op1, op2, gp);
case 1:
return new Base<uint16_t>(machInst, dest, op1, op2, gp);
case 2:
return new Base<uint32_t>(machInst, dest, op1, op2, gp);
case 3:
return new Base<uint64_t>(machInst, dest, op1, op2, gp);
default:
return new Unknown64(machInst);
}
}
// Decodes SVE signed unary extension instructions (8-bit source element
// size)
template <template <typename TS, typename TD> class Base>
StaticInstPtr
decodeSveUnaryExtendFromBPredS(unsigned dsize, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1,
IntRegIndex gp)
{
switch (dsize) {
case 1:
return new Base<int8_t, int16_t>(machInst, dest, op1, gp);
case 2:
return new Base<int8_t, int32_t>(machInst, dest, op1, gp);
case 3:
return new Base<int8_t, int64_t>(machInst, dest, op1, gp);
}
return new Unknown64(machInst);
}
// Decodes SVE unsigned unary extension instructions (8-bit source element
// size)
template <template <typename TS, typename TD> class Base>
StaticInstPtr
decodeSveUnaryExtendFromBPredU(unsigned dsize, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1,
IntRegIndex gp)
{
switch (dsize) {
case 1:
return new Base<uint8_t, uint16_t>(machInst, dest, op1, gp);
case 2:
return new Base<uint8_t, uint32_t>(machInst, dest, op1, gp);
case 3:
return new Base<uint8_t, uint64_t>(machInst, dest, op1, gp);
}
return new Unknown64(machInst);
}
// Decodes SVE signed unary extension instructions (16-bit source element
// size)
template <template <typename TS, typename TD> class Base>
StaticInstPtr
decodeSveUnaryExtendFromHPredS(unsigned dsize, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1,
IntRegIndex gp)
{
switch (dsize) {
case 2:
return new Base<int16_t, int32_t>(machInst, dest, op1, gp);
case 3:
return new Base<int16_t, int64_t>(machInst, dest, op1, gp);
}
return new Unknown64(machInst);
}
// Decodes SVE unsigned unary extension instructions (16-bit source element
// size)
template <template <typename TS, typename TD> class Base>
StaticInstPtr
decodeSveUnaryExtendFromHPredU(unsigned dsize, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1,
IntRegIndex gp)
{
switch (dsize) {
case 2:
return new Base<uint16_t, uint32_t>(machInst, dest, op1, gp);
case 3:
return new Base<uint16_t, uint64_t>(machInst, dest, op1, gp);
}
return new Unknown64(machInst);
}
// Decodes ternary, destructive, predicated (merging) SVE instructions,
// handling floating-point variants only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveTerPredF(unsigned size, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1, IntRegIndex op2,
IntRegIndex gp)
{
switch (size) {
case 1:
return new Base<uint16_t>(machInst, dest, op1, op2, gp);
case 2:
return new Base<uint32_t>(machInst, dest, op1, op2, gp);
case 3:
return new Base<uint64_t>(machInst, dest, op1, op2, gp);
default:
return new Unknown64(machInst);
}
}
// Decodes ternary with immediate operand, destructive, unpredicated SVE
// instructions handling floating-point variants only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveTerImmUnpredF(unsigned size, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op2, uint8_t imm)
{
switch (size) {
case 1:
return new Base<uint16_t>(machInst, dest, op2, imm);
case 2:
return new Base<uint32_t>(machInst, dest, op2, imm);
case 3:
return new Base<uint64_t>(machInst, dest, op2, imm);
default:
return new Unknown64(machInst);
}
}
// Decodes SVE PTRUE(S) instructions.
template <template <typename T> class Base>
StaticInstPtr
decodeSvePtrue(unsigned size, ExtMachInst machInst,
IntRegIndex dest, uint8_t imm)
{
switch (size) {
case 0:
return new Base<uint8_t>(machInst, dest, imm);
case 1:
return new Base<uint16_t>(machInst, dest, imm);
case 2:
return new Base<uint32_t>(machInst, dest, imm);
case 3:
return new Base<uint64_t>(machInst, dest, imm);
default:
return new Unknown64(machInst);
}
}
// Decodes SVE predicate count instructions, scalar signed variant only
template <template <typename T> class Base>
StaticInstPtr
decodeSvePredCountS(unsigned size, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1)
{
switch (size) {
case 0:
return new Base<int8_t>(machInst, dest, op1);
case 1:
return new Base<int16_t>(machInst, dest, op1);
case 2:
return new Base<int32_t>(machInst, dest, op1);
case 3:
return new Base<int64_t>(machInst, dest, op1);
default:
return new Unknown64(machInst);
}
}
// Decodes SVE predicate count instructions, scalar unsigned variant only
template <template <typename T> class Base>
StaticInstPtr
decodeSvePredCountU(unsigned size, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1)
{
switch (size) {
case 0:
return new Base<uint8_t>(machInst, dest, op1);
case 1:
return new Base<uint16_t>(machInst, dest, op1);
case 2:
return new Base<uint32_t>(machInst, dest, op1);
case 3:
return new Base<uint64_t>(machInst, dest, op1);
default:
return new Unknown64(machInst);
}
}
// Decodes SVE predicate count instructions, vector signed variant only
template <template <typename T> class Base>
StaticInstPtr
decodeSvePredCountVS(unsigned size, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1)
{
switch (size) {
case 1:
return new Base<int16_t>(machInst, dest, op1);
case 2:
return new Base<int32_t>(machInst, dest, op1);
case 3:
return new Base<int64_t>(machInst, dest, op1);
default:
return new Unknown64(machInst);
}
}
// Decodes SVE predicate count instructions, vector unsigned variant only
template <template <typename T> class Base>
StaticInstPtr
decodeSvePredCountVU(unsigned size, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1)
{
switch (size) {
case 1:
return new Base<uint16_t>(machInst, dest, op1);
case 2:
return new Base<uint32_t>(machInst, dest, op1);
case 3:
return new Base<uint64_t>(machInst, dest, op1);
default:
return new Unknown64(machInst);
}
}
// Decodes ternary with immediate operand, predicated SVE
// instructions handling unsigned variants only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveTerImmPredU(unsigned size, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1, int64_t imm, IntRegIndex gp)
{
switch (size) {
case 0:
return new Base<uint8_t>(machInst, dest, op1, imm, gp);
case 1:
return new Base<uint16_t>(machInst, dest, op1, imm, gp);
case 2:
return new Base<uint32_t>(machInst, dest, op1, imm, gp);
case 3:
return new Base<uint64_t>(machInst, dest, op1, imm, gp);
default:
return new Unknown64(machInst);
}
}
// Decodes ternary with immediate operand, predicated SVE
// instructions handling signed variants only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveTerImmPredS(unsigned size, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1, int64_t imm, IntRegIndex gp)
{
switch (size) {
case 0:
return new Base<int8_t>(machInst, dest, op1, imm, gp);
case 1:
return new Base<int16_t>(machInst, dest, op1, imm, gp);
case 2:
return new Base<int32_t>(machInst, dest, op1, imm, gp);
case 3:
return new Base<int64_t>(machInst, dest, op1, imm, gp);
default:
return new Unknown64(machInst);
}
}
// Decodes integer element count SVE instructions, handling
// signed variants only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveElemIntCountS(unsigned size, ExtMachInst machInst,
IntRegIndex dest, uint8_t pattern, uint8_t imm4)
{
switch (size) {
case 0:
return new Base<int8_t>(machInst, dest, pattern, imm4);
case 1:
return new Base<int16_t>(machInst, dest, pattern, imm4);
case 2:
return new Base<int32_t>(machInst, dest, pattern, imm4);
case 3:
return new Base<int64_t>(machInst, dest, pattern, imm4);
default:
return new Unknown64(machInst);
}
}
// Decodes integer element count SVE instructions, handling
// unsigned variants only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveElemIntCountU(unsigned size, ExtMachInst machInst,
IntRegIndex dest, uint8_t pattern, uint8_t imm4)
{
switch (size) {
case 0:
return new Base<uint8_t>(machInst, dest, pattern, imm4);
case 1:
return new Base<uint16_t>(machInst, dest, pattern, imm4);
case 2:
return new Base<uint32_t>(machInst, dest, pattern, imm4);
case 3:
return new Base<uint64_t>(machInst, dest, pattern, imm4);
default:
return new Unknown64(machInst);
}
}
// Decodes integer element count SVE instructions, handling
// signed variants from 16 to 64 bits only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveElemIntCountLS(unsigned size, ExtMachInst machInst,
IntRegIndex dest, uint8_t pattern, uint8_t imm4)
{
switch (size) {
case 1:
return new Base<int16_t>(machInst, dest, pattern, imm4);
case 2:
return new Base<int32_t>(machInst, dest, pattern, imm4);
case 3:
return new Base<int64_t>(machInst, dest, pattern, imm4);
default:
return new Unknown64(machInst);
}
}
// Decodes integer element count SVE instructions, handling
// unsigned variants from 16 to 64 bits only.
template <template <typename T> class Base>
StaticInstPtr
decodeSveElemIntCountLU(unsigned size, ExtMachInst machInst,
IntRegIndex dest, uint8_t pattern, uint8_t imm4)
{
switch (size) {
case 1:
return new Base<uint16_t>(machInst, dest, pattern, imm4);
case 2:
return new Base<uint32_t>(machInst, dest, pattern, imm4);
case 3:
return new Base<uint64_t>(machInst, dest, pattern, imm4);
default:
return new Unknown64(machInst);
}
}
// Decodes SVE unpack instructions. Handling signed variants.
template <template <typename T1, typename T2> class Base>
StaticInstPtr
decodeSveUnpackS(unsigned size, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1)
{
switch (size) {
case 1:
return new Base<int8_t, int16_t>(machInst, dest, op1);
case 2:
return new Base<int16_t, int32_t>(machInst, dest, op1);
case 3:
return new Base<int32_t, int64_t>(machInst, dest, op1);
default:
return new Unknown64(machInst);
}
}
// Decodes SVE unpack instructions. Handling unsigned variants.
template <template <typename T1, typename T2> class Base>
StaticInstPtr
decodeSveUnpackU(unsigned size, ExtMachInst machInst,
IntRegIndex dest, IntRegIndex op1)
{
switch (size) {
case 1:
return new Base<uint8_t, uint16_t>(machInst, dest, op1);
case 2:
return new Base<uint16_t, uint32_t>(machInst, dest, op1);
case 3:
return new Base<uint32_t, uint64_t>(machInst, dest, op1);
default:
return new Unknown64(machInst);
}
}
}};
let {{
header_output = ''
exec_output = ''
decoders = { 'Generic': {} }
class PredType:
NONE = 0
MERGE = 1
ZERO = 2
SELECT = 3
class CvtDir:
Narrow = 0
Widen = 1
class IndexFormat(object):
ImmImm = 'II'
ImmReg = 'IR'
RegImm = 'RI'
RegReg = 'RR'
class SrcRegType(object):
Vector = 0
Scalar = 1
SimdFpScalar = 2
Predicate = 3
class DstRegType(object):
Vector = 0
Scalar = 1
SimdFpScalar = 2
Predicate = 3
class DestType(object):
Scalar = 'false'
Vector = 'true'
class SrcSize(object):
Src32bit = 'true'
Src64bit = 'false'
class Break(object):
Before = 0
After = 1
class Unpack(object):
High = 0
Low = 1
# Generates definitions for SVE ADR instructions
def sveAdrInst(name, Name, opClass, types, op):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());
for (unsigned i = 0; i < eCount; i++) {
const Element& srcElem1 = AA64FpOp1_x[i];
Element srcElem2 = AA64FpOp2_x[i];
Element destElem = 0;
%(op)s
AA64FpDest_x[i] = destElem;
}''' % {'op': op}
iop = InstObjParams(name, 'Sve' + Name, 'SveAdrOp',
{'code': code, 'op_class': opClass}, [])
header_output += SveAdrOpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
for type in types:
substDict = {'targs' : type,
'class_name' : 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generates definition for SVE while predicate generation instructions
def sveWhileInst(name, Name, opClass, types, op,
srcSize = SrcSize.Src64bit):
global header_output, exec_output, decoders
extraPrologCode = '''
auto& destPred = PDest;'''
if 'int32_t' in types:
srcType = 'int64_t' if srcSize == SrcSize.Src64bit else 'int32_t'
else:
srcType = 'uint64_t' if srcSize == SrcSize.Src64bit else 'uint32_t'
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());
%(stype)s srcElem1 = static_cast<%(stype)s>(XOp1);
%(stype)s srcElem2 = static_cast<%(stype)s>(XOp2);
bool cond, first = false, none = true, last = true;
destPred.reset();
for (unsigned i = 0; i < eCount; i++) {
%(op)s;
last = last && cond;
none = none && !cond;
first = first || (i == 0 && cond);
PDest_x[i] = last;
srcElem1++;
}
CondCodesNZ = (first << 1) | none;
CondCodesC = !last;
CondCodesV = false;
'''%{'op': op, 'stype': srcType}
iop = InstObjParams(name, 'Sve' + Name, 'SveWhileOp',
{'code': code, 'op_class': opClass, 'srcIs32b': srcSize}, [])
iop.snippets['code'] = extraPrologCode + iop.snippets['code']
header_output += SveWhileOpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
for type in types:
substDict = {'targs' : type, 'class_name' : 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict);
# Generate definition for SVE compare & terminate instructions
def sveCompTermInst(name, Name, opClass, types, op):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
bool destElem;
Element srcElem1 = static_cast<Element>(XOp1);
Element srcElem2 = static_cast<Element>(XOp2);
%(op)s;
if (destElem) {
CondCodesNZ = CondCodesNZ | 0x2;
CondCodesV = 0;
} else {
CondCodesNZ = CondCodesNZ & ~0x2;
CondCodesV = !CondCodesC;
}
''' % {'op': op}
iop = InstObjParams(name, 'Sve' + Name, 'SveCompTermOp',
{'code': code, 'op_class': opClass}, [])
header_output += SveCompTermOpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
for type in types:
substDict = {'targs' : type, 'class_name': 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict);
# Generates definition for SVE predicate count instructions
def svePredCountInst(name, Name, opClass, types, op,
destType=DestType.Vector,
srcSize=SrcSize.Src64bit):
global header_output, exec_output, decoders
assert not (destType == DestType.Vector and
srcSize != SrcSize.Src64bit)
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());
int count = 0;
for (unsigned i = 0; i < eCount; i++) {
if (GpOp_x[i]) {
count++;
}
}'''
if destType == DestType.Vector:
code += '''
for (unsigned i = 0; i < eCount; i++) {
Element destElem = 0;
const Element& srcElem = AA64FpDestMerge_x[i];
%(op)s
AA64FpDest_x[i] = destElem;
}''' % {'op': op}
else:
code += '''
%(op)s''' % {'op': op}
iop = InstObjParams(name, 'Sve' + Name, 'SvePredCountOp',
{'code': code, 'op_class': opClass, 'srcIs32b': srcSize,
'destIsVec': destType}, [])
header_output += SvePredCountOpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
for type in types:
substDict = {'targs' : type, 'class_name' : 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict);
# Generates definition for SVE predicate count instructions (predicated)
def svePredCountPredInst(name, Name, opClass, types):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());
int count = 0;
for (unsigned i = 0; i < eCount; i++) {
if (POp1_x[i] && GpOp_x[i]) {
count++;
}
}
XDest = count;
'''
iop = InstObjParams(name, 'Sve' + Name, 'SvePredCountPredOp',
{'code': code, 'op_class': opClass}, [])
header_output += SvePredCountPredOpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
for type in types:
substDict = {'targs' : type, 'class_name' : 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generates definition for SVE Index generation instructions
def sveIndex(fmt):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());'''
if fmt == IndexFormat.ImmReg or fmt == IndexFormat.ImmImm:
code += '''
const Element& srcElem1 = imm1;'''
if fmt == IndexFormat.RegImm or fmt == IndexFormat.RegReg:
code += '''
const Element& srcElem1 = XOp1;'''
if fmt == IndexFormat.RegImm or fmt == IndexFormat.ImmImm:
code += '''
const Element& srcElem2 = imm2;'''
if fmt == IndexFormat.ImmReg or fmt == IndexFormat.RegReg:
code += '''
const Element& srcElem2 = XOp2;'''
code +='''
for (unsigned i = 0; i < eCount; i++) {
AA64FpDest_x[i] = srcElem1 + i * srcElem2;
}'''
iop = InstObjParams('index', 'SveIndex'+fmt, 'SveIndex'+fmt+'Op',
{'code': code, 'op_class': 'SimdAluOp'})
if fmt == IndexFormat.ImmImm:
header_output += SveIndexIIOpDeclare.subst(iop)
elif fmt == IndexFormat.ImmReg:
header_output += SveIndexIROpDeclare.subst(iop)
elif fmt == IndexFormat.RegImm:
header_output += SveIndexRIOpDeclare.subst(iop)
elif fmt == IndexFormat.RegReg:
header_output += SveIndexRROpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
for type in ['int8_t', 'int16_t', 'int32_t', 'int64_t']:
substDict = {'targs': type, 'class_name': 'SveIndex'+fmt}
exec_output += SveOpExecDeclare.subst(substDict)
# Generates definitions for widening unary SVE instructions
# (always constructive)
def sveWidenUnaryInst(name, Name, opClass, types, op,
predType=PredType.NONE, decoder='Generic'):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<DElement>(
xc->tcBase());
for (unsigned i = 0; i < eCount; i++) {
SElement srcElem1 = AA64FpOp1_xd[i];
DElement destElem = 0;'''
if predType != PredType.NONE:
code += '''
if (GpOp_xd[i]) {
%(op)s
} else {
destElem = %(dest_elem)s;
}''' % {'op': op,
'dest_elem': 'AA64FpDestMerge_xd[i]'
if predType == PredType.MERGE
else '0'}
else:
code += '''
%(op)s''' % {'op': op}
code += '''
AA64FpDest_xd[i] = destElem;
}'''
iop = InstObjParams(name, 'Sve' + Name,
'SveUnaryPredOp' if predType != PredType.NONE
else 'SveUnaryUnpredOp',
{'code': code, 'op_class': opClass}, [])
if predType != PredType.NONE:
header_output += SveWideningUnaryPredOpDeclare.subst(iop)
else:
header_output += SveWideningUnaryUnpredOpDeclare.subst(iop)
exec_output += SveWideningOpExecute.subst(iop)
for type in types:
substDict = {'targs' : type,
'class_name' : 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generates definitions for unary SVE instructions (always constructive)
def sveUnaryInst(name, Name, opClass, types, op, predType=PredType.NONE,
srcRegType=SrcRegType.Vector, decoder='Generic'):
global header_output, exec_output, decoders
op1 = ('AA64FpOp1_x[i]' if srcRegType == SrcRegType.Vector
else 'XOp1' if srcRegType == SrcRegType.Scalar
else 'AA64FpOp1_x[0]')
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());
for (unsigned i = 0; i < eCount; i++) {
Element srcElem1 = %s;
Element destElem = 0;''' % op1
if predType != PredType.NONE:
code += '''
if (GpOp_x[i]) {
%(op)s
} else {
destElem = %(dest_elem)s;
}''' % {'op': op,
'dest_elem': 'AA64FpDestMerge_x[i]'
if predType == PredType.MERGE
else '0'}
else:
code += '''
%(op)s''' % {'op': op}
code += '''
AA64FpDest_x[i] = destElem;
}'''
iop = InstObjParams(name, 'Sve' + Name,
'SveUnaryPredOp' if predType != PredType.NONE
else 'SveUnaryUnpredOp',
{'code': code, 'op_class': opClass}, [])
if predType != PredType.NONE:
header_output += SveUnaryPredOpDeclare.subst(iop)
else:
header_output += SveUnaryUnpredOpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
for type in types:
substDict = {'targs' : type,
'class_name' : 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generates definitions for SVE floating-point conversions (always
# unary, constructive, merging
def sveCvtInst(name, Name, opClass, types, op, direction=CvtDir.Narrow,
decoder='Generic'):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<%(bigElemType)s>(
xc->tcBase());
for (unsigned i = 0; i < eCount; i++) {
SElement srcElem1 = AA64FpOp1_x%(bigElemSuffix)s[i] &
mask(sizeof(SElement) * 8);
DElement destElem = 0;
if (GpOp_x%(bigElemSuffix)s[i]) {
%(op)s
AA64FpDest_x%(bigElemSuffix)s[i] = destElem;
} else {
AA64FpDest_x%(bigElemSuffix)s[i] =
AA64FpDestMerge_x%(bigElemSuffix)s[i];
}
}
''' % {'op': op,
'bigElemType': 'SElement' if direction == CvtDir.Narrow
else 'DElement',
'bigElemSuffix': 's' if direction == CvtDir.Narrow else 'd'}
iop = InstObjParams(name, 'Sve' + Name, 'SveUnaryPredOp',
{'code': code, 'op_class': opClass}, [])
header_output += SveWideningUnaryPredOpDeclare.subst(iop)
exec_output += SveWideningOpExecute.subst(iop)
for type in types:
substDict = {'targs' : type,
'class_name' : 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generates definitions for associative SVE reductions
def sveAssocReducInst(name, Name, opClass, types, op, identity,
decoder='Generic'):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());
TheISA::VecRegContainer tmpVecC;
auto auxOp1 = tmpVecC.as<Element>();
for (unsigned i = 0; i < eCount; ++i) {
auxOp1[i] = AA64FpOp1_x[i];
}
Element destElem = %(identity)s;
for (unsigned i = 0; i < eCount; i++) {
AA64FpDest_x[i] = 0; // zero upper part
if (GpOp_x[i]) {
const Element& srcElem1 = auxOp1[i];
%(op)s
}
}
AA64FpDest_x[0] = destElem;
''' % {'op': op, 'identity': identity}
iop = InstObjParams(name, 'Sve' + Name, 'SveReducOp',
{'code': code, 'op_class': opClass}, [])
header_output += SveReducOpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
for type in types:
substDict = {'targs' : type,
'class_name' : 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generates definitions for widening associative SVE reductions
def sveWideningAssocReducInst(name, Name, opClass, types, op, identity,
decoder='Generic'):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<SElement>(
xc->tcBase());
unsigned eWideCount = ArmStaticInst::getCurSveVecLen<DElement>(
xc->tcBase());
DElement destElem = %(identity)s;
for (unsigned i = 0; i < eCount; i++) {
if (GpOp_xs[i]) {
DElement srcElem1 = AA64FpOp1_xs[i];
%(op)s
}
}
AA64FpDest_xd[0] = destElem;
for (int i = 1; i < eWideCount; i++) {
AA64FpDest_xd[i] = 0;
}
''' % {'op': op, 'identity': identity}
iop = InstObjParams(name, 'Sve' + Name, 'SveReducOp',
{'code': code, 'op_class': opClass}, [])
header_output += SveWideningReducOpDeclare.subst(iop)
exec_output += SveWideningOpExecute.subst(iop)
for type in types:
substDict = {'targs' : type,
'class_name' : 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generates definitions for non-associative SVE reductions
def sveNonAssocReducInst(name, Name, opClass, types, op, identity,
decoder='Generic'):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());
TheISA::VecRegContainer tmpVecC;
auto tmpVec = tmpVecC.as<Element>();
int ePow2Count = 1;
while (ePow2Count < eCount) {
ePow2Count *= 2;
}
for (unsigned i = 0; i < ePow2Count; i++) {
if (i < eCount && GpOp_x[i]) {
tmpVec[i] = AA64FpOp1_x[i];
} else {
tmpVec[i] = %(identity)s;
}
}
unsigned n = ePow2Count;
while (n > 1) {
unsigned max = n;
n = 0;
for (unsigned i = 0; i < max; i += 2) {
Element srcElem1 = tmpVec[i];
Element srcElem2 = tmpVec[i + 1];
Element destElem = 0;
%(op)s
tmpVec[n] = destElem;
n++;
}
}
AA64FpDest_x[0] = tmpVec[0];
for (unsigned i = 1; i < eCount; i++) {
AA64FpDest_x[i] = 0; // zero upper part
}
''' % {'op': op, 'identity': identity}
iop = InstObjParams(name, 'Sve' + Name, 'SveReducOp',
{'code': code, 'op_class': opClass}, [])
header_output += SveReducOpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
for type in types:
substDict = {'targs' : type,
'class_name' : 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generates definitions for binary SVE instructions with immediate operand
def sveBinImmInst(name, Name, opClass, types, op, predType=PredType.NONE,
decoder='Generic'):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());
for (unsigned i = 0; i < eCount; i++) {'''
if predType != PredType.NONE:
code += '''
const Element& srcElem1 = %s;''' % (
'AA64FpDestMerge_x[i]' if predType == PredType.MERGE else '0')
else:
code += '''
const Element& srcElem1 = AA64FpOp1_x[i];'''
code += '''
Element srcElem2 = imm;
Element destElem = 0;'''
if predType != PredType.NONE:
code += '''
if (GpOp_x[i]) {
%(op)s
} else {
destElem = %(dest_elem)s;
}''' % {'op': op,
'dest_elem': 'AA64FpDestMerge_x[i]'
if predType == PredType.MERGE else '0'}
else:
code += '''
%(op)s''' % {'op': op}
code += '''
AA64FpDest_x[i] = destElem;
}'''
iop = InstObjParams(name, 'Sve' + Name,
'SveBinImmPredOp' if predType != PredType.NONE
else 'SveBinImmUnpredConstrOp',
{'code': code, 'op_class': opClass}, [])
if predType != PredType.NONE:
header_output += SveBinImmPredOpDeclare.subst(iop)
else:
header_output += SveBinImmUnpredOpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
for type in types:
substDict = {'targs' : type,
'class_name' : 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generates definitions for unary and binary SVE instructions with wide
# immediate operand
def sveWideImmInst(name, Name, opClass, types, op, predType=PredType.NONE,
isUnary=False, decoder='Generic'):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());
for (unsigned i = 0; i < eCount; i++) {'''
# TODO: handle unsigned-to-signed conversion properly...
if isUnary:
code += '''
Element srcElem1 = imm;'''
else:
code += '''
const Element& srcElem1 = AA64FpDestMerge_x[i];
Element srcElem2 = imm;'''
code += '''
Element destElem = 0;'''
if predType != PredType.NONE:
code += '''
if (GpOp_x[i]) {
%(op)s
} else {
destElem = %(dest_elem)s;
}''' % {'op': op,
'dest_elem': 'AA64FpDestMerge_x[i]'
if predType == PredType.MERGE else '0'}
else:
code += '''
%(op)s''' % {'op': op}
code += '''
AA64FpDest_x[i] = destElem;
}'''
iop = InstObjParams(name, 'Sve' + Name,
'Sve%sWideImm%sOp' % (
'Unary' if isUnary else 'Bin',
'Unpred' if predType == PredType.NONE else 'Pred'),
{'code': code, 'op_class': opClass}, [])
if predType == PredType.NONE:
header_output += SveWideImmUnpredOpDeclare.subst(iop)
else:
header_output += SveWideImmPredOpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
for type in types:
substDict = {'targs' : type,
'class_name' : 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generates definitions for shift SVE instructions with wide elements
def sveShiftByWideElemsInst(name, Name, opClass, types, op,
predType=PredType.NONE, decoder='Generic'):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());
TheISA::VecRegContainer tmpVecC;
auto auxOp2 = tmpVecC.as<Element>();
for (unsigned i = 0; i < eCount; i++) {
auxOp2[i] = AA64FpOp2_ud[i];
}
for (unsigned i = 0; i < eCount; i++) {'''
if predType != PredType.NONE:
code += '''
const Element& srcElem1 = AA64FpDestMerge_x[i];'''
else:
code += '''
const Element& srcElem1 = AA64FpOp1_x[i];'''
code += '''
const auto& srcElem2 = auxOp2[
(i * sizeof(Element) * 8) / 64];
Element destElem = 0;'''
if predType != PredType.NONE:
code += '''
if (GpOp_x[i]) {
%(op)s
} else {
destElem = %(dest_elem)s;
}''' % {'op': op,
'dest_elem': 'AA64FpDestMerge_x[i]'
if predType == PredType.MERGE else '0'}
else:
code += '''
%(op)s''' % {'op': op}
code += '''
AA64FpDest_x[i] = destElem;
}'''
iop = InstObjParams(name, 'Sve' + Name,
'SveBinDestrPredOp' if predType != PredType.NONE
else 'SveBinUnpredOp',
{'code': code, 'op_class': opClass}, [])
if predType != PredType.NONE:
header_output += SveBinDestrPredOpDeclare.subst(iop)
else:
header_output += SveBinUnpredOpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
for type in types:
substDict = {'targs' : type,
'class_name' : 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generates definitions for binary indexed SVE instructions
# (always unpredicated)
def sveBinIdxInst(name, Name, opClass, types, op, decoder='Generic'):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());
// Number of elements in a 128 bit segment
constexpr unsigned ePerSegment = 128 / sizeof(Element);
'''
code += '''
for (unsigned i = 0; i < eCount; i++) {
const auto segmentBase = i - i % ePerSegment;
const auto segmentIdx = segmentBase + index;
const Element& srcElem1 = AA64FpOp1_x[i];
const Element& srcElem2 = AA64FpOp2_x[segmentIdx];
Element destElem = 0;
'''
code += '''
%(op)s
AA64FpDest_x[i] = destElem;
}
''' % {'op': op}
baseClass = 'SveBinIdxUnpredOp'
iop = InstObjParams(name, 'Sve' + Name, baseClass,
{'code': code, 'op_class': opClass}, [])
header_output += SveBinIdxUnpredOpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
for type in types:
substDict = {'targs' : type,
'class_name' : 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generates definitions for binary SVE instructions
def sveBinInst(name, Name, opClass, types, op, predType=PredType.NONE,
isDestructive=False, customIterCode=None,
decoder='Generic'):
assert not (predType in (PredType.NONE, PredType.SELECT) and
isDestructive)
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());'''
if customIterCode is None:
code += '''
for (unsigned i = 0; i < eCount; i++) {'''
if predType == PredType.MERGE:
code += '''
const Element& srcElem1 = AA64FpDestMerge_x[i];'''
else:
code += '''
const Element& srcElem1 = AA64FpOp1_x[i];'''
code += '''
const Element& srcElem2 = AA64FpOp2_x[i];
Element destElem = 0;'''
if predType != PredType.NONE:
code += '''
if (GpOp_x[i]) {
%(op)s
} else {
destElem = %(dest_elem)s;
}''' % {'op': op,
'dest_elem':
'AA64FpDestMerge_x[i]' if predType == PredType.MERGE
else '0' if predType == PredType.ZERO
else 'srcElem2'}
else:
code += '''
%(op)s''' % {'op': op}
code += '''
AA64FpDest_x[i] = destElem;
}'''
else:
code += customIterCode
if predType == PredType.NONE:
baseClass = 'SveBinUnpredOp'
elif isDestructive:
baseClass = 'SveBinDestrPredOp'
else:
baseClass = 'SveBinConstrPredOp'
iop = InstObjParams(name, 'Sve' + Name, baseClass,
{'code': code, 'op_class': opClass}, [])
if predType == PredType.NONE:
header_output += SveBinUnpredOpDeclare.subst(iop)
elif isDestructive:
header_output += SveBinDestrPredOpDeclare.subst(iop)
else:
header_output += SveBinConstrPredOpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
for type in types:
substDict = {'targs' : type,
'class_name' : 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generates definitions for predicate logical instructions
def svePredLogicalInst(name, Name, opClass, types, op,
predType=PredType.ZERO, isFlagSetting=False,
decoder='Generic'):
global header_output, exec_output, decoders
assert predType in (PredType.ZERO, PredType.SELECT)
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());
TheISA::VecPredRegContainer tmpPredC;
auto auxGpOp = tmpPredC.as<Element>();
for (unsigned i = 0; i < eCount; i++) {
auxGpOp[i] = GpOp_x[i];
}
for (unsigned i = 0; i < eCount; i++) {
bool srcElem1 = POp1_x[i];
bool srcElem2 = POp2_x[i];
bool destElem = false;
if (auxGpOp[i]) {
%(op)s
} else {
destElem = %(dest_elem)s;
}
PDest_x[i] = destElem;
}''' % {'op': op,
'dest_elem': 'false' if predType == PredType.ZERO
else 'srcElem2'}
extraPrologCode = ''
if isFlagSetting:
code += '''
CondCodesNZ = (destPred.firstActive(auxGpOp, eCount) << 1) |
destPred.noneActive(auxGpOp, eCount);
CondCodesC = !destPred.lastActive(auxGpOp, eCount);
CondCodesV = 0;'''
extraPrologCode += '''
auto& destPred = PDest;'''
iop = InstObjParams(name, 'Sve' + Name, 'SvePredLogicalOp',
{'code': code, 'op_class': opClass}, [])
iop.snippets['code'] = extraPrologCode + iop.snippets['code']
header_output += SvePredLogicalOpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
for type in types:
substDict = {'targs' : type,
'class_name' : 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generates definitions for predicate permute instructions
def svePredBinPermInst(name, Name, opClass, types, iterCode,
decoder='Generic'):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());'''
code += iterCode
iop = InstObjParams(name, 'Sve' + Name, 'SvePredBinPermOp',
{'code': code, 'op_class': opClass}, [])
header_output += SveBinUnpredOpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
for type in types:
substDict = {'targs' : type,
'class_name' : 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generates definitions for SVE compare instructions
# NOTE: compares are all predicated zeroing
def sveCmpInst(name, Name, opClass, types, op, isImm=False,
decoder='Generic'):
global header_output, exec_output, decoders
extraPrologCode = '''
auto& destPred = PDest;'''
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());
TheISA::VecPredRegContainer tmpPredC;
auto tmpPred = tmpPredC.as<Element>();
for (unsigned i = 0; i < eCount; ++i)
tmpPred[i] = GpOp_x[i];
destPred.reset();
for (unsigned i = 0; i < eCount; i++) {
const Element& srcElem1 = AA64FpOp1_x[i];
%(src_elem_2_ty)s srcElem2 __attribute__((unused)) =
%(src_elem_2)s;
bool destElem = false;
if (tmpPred[i]) {
%(op)s
} else {
destElem = false;
}
PDest_x[i] = destElem;
}''' % {'op': op,
'src_elem_2_ty': 'Element' if isImm else 'const Element&',
'src_elem_2': 'imm' if isImm else 'AA64FpOp2_x[i]'}
iop = InstObjParams(name, 'Sve' + Name,
'SveCmpImmOp' if isImm else 'SveCmpOp',
{'code': code, 'op_class': opClass}, [])
iop.snippets['code'] = extraPrologCode + iop.snippets['code']
if isImm:
header_output += SveCmpImmOpDeclare.subst(iop)
else:
header_output += SveCmpOpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
for type in types:
substDict = {'targs' : type,
'class_name' : 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generates definitions for ternary SVE intructions (always predicated -
# merging)
def sveTerInst(name, Name, opClass, types, op, decoder='Generic'):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());
for (unsigned i = 0; i < eCount; i++) {
const Element& srcElem1 = AA64FpOp1_x[i];
const Element& srcElem2 = AA64FpOp2_x[i];
Element destElem = AA64FpDestMerge_x[i];
if (GpOp_x[i]) {
%(op)s
}
AA64FpDest_x[i] = destElem;
}''' % {'op': op}
iop = InstObjParams(name, 'Sve' + Name, 'SveTerPredOp',
{'code': code, 'op_class': opClass}, [])
header_output += SveTerPredOpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
for type in types:
substDict = {'targs' : type,
'class_name' : 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generates definitions for ternary SVE instructions with indexed operand
def sveTerIdxInst(name, Name, opClass, types, op, decoder='Generic'):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());
// Number of elements in a 128 bit segment
constexpr unsigned ePerSegment = 128 / sizeof(Element);
for (unsigned i = 0; i < eCount; i++) {
const auto segmentBase = i - i % ePerSegment;
const auto segmentIdx = segmentBase + index;
const Element& srcElem1 = AA64FpOp1_x[i];
const Element& srcElem2 = AA64FpOp2_x[segmentIdx];
Element destElem = AA64FpDestMerge_x[i];
'''
code += '''
%(op)s
AA64FpDest_x[i] = destElem;
}''' % {'op': op}
iop = InstObjParams(name, 'Sve' + Name, 'SveBinIdxUnpredOp',
{'code': code, 'op_class': opClass}, [])
header_output += SveBinIdxUnpredOpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
for type in types:
substDict = {'targs' : type,
'class_name' : 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generates definitions for ternary SVE intructions with immediate operand
# (always unpredicated)
def sveTerImmInst(name, Name, opClass, types, op, decoder='Generic'):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());
for (unsigned i = 0; i < eCount; i++) {
const Element& srcElem2 = AA64FpOp2_x[i];
Element srcElem3 = imm;
Element destElem = AA64FpDestMerge_x[i];
%(op)s
AA64FpDest_x[i] = destElem;
}''' % {'op': op}
iop = InstObjParams(name, 'Sve' + Name, 'SveTerImmUnpredOp',
{'code': code, 'op_class': opClass}, [])
header_output += SveTerImmUnpredOpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
for type in types:
substDict = {'targs' : type,
'class_name' : 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generates definitions for PTRUE and PTRUES instructions.
def svePtrueInst(name, Name, opClass, types, isFlagSetting=False,
decoder='Generic'):
global header_output, exec_output, decoders
extraPrologCode = '''
auto& destPred = PDest;'''
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());
unsigned predCount = sveDecodePredCount(imm, eCount);
destPred.reset();
for (unsigned i = 0; i < eCount; i++) {
PDest_x[i] = (i < predCount);
}'''
if isFlagSetting:
code += '''
CondCodesNZ = (destPred.firstActive(destPred, eCount) << 1) |
destPred.noneActive(destPred, eCount);
CondCodesC = !destPred.lastActive(destPred, eCount);
CondCodesV = 0;'''
iop = InstObjParams(name, 'Sve' + Name, 'SvePtrueOp',
{'code': code, 'op_class': opClass}, [])
iop.snippets['code'] = extraPrologCode + iop.snippets['code']
header_output += SvePtrueOpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
for type in types:
substDict = {'targs' : type,
'class_name' : 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generate definitions for integer CMP<cc> instructions
def sveIntCmpInst(name, Name, opClass, types, op, wideop = False,
decoder = 'Generic'):
global header_output, exec_output, decoders
signed = 'int8_t' in types
srcType = 'Element'
op2Suffix = 'x'
if wideop:
srcType = 'int64_t' if signed else 'uint64_t'
op2Suffix = 'sd' if signed else 'ud'
extraPrologCode = '''
auto& destPred = PDest;'''
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());
TheISA::VecPredRegContainer tmpPredC;
auto tmpPred = tmpPredC.as<Element>();
for (unsigned i = 0; i < eCount; ++i)
tmpPred[i] = GpOp_x[i];
destPred.reset();
for (unsigned i = 0; i < eCount; ++i) {
%(srcType)s srcElem1 = (%(srcType)s) AA64FpOp1_x[i];
%(srcType)s srcElem2 = AA64FpOp2_%(op2Suffix)s[%(op2Index)s];
bool destElem = false;
if (tmpPred[i]) {
%(op)s
}
PDest_x[i] = destElem;
}
CondCodesNZ = (destPred.firstActive(tmpPred, eCount) << 1) |
destPred.noneActive(tmpPred, eCount);
CondCodesC = !destPred.lastActive(tmpPred, eCount);
CondCodesV = 0;''' % {
'op': op,
'srcType': srcType,
'op2Suffix': op2Suffix,
'op2Index': '(i * sizeof(Element)) / 8' if wideop else 'i'
}
iop = InstObjParams(name, 'Sve' + Name, 'SveIntCmpOp',
{
'code': code,
'op_class': opClass,
'op2IsWide': 'true' if wideop else 'false',
}, [])
iop.snippets['code'] = extraPrologCode + iop.snippets['code']
header_output += SveIntCmpOpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
for type in types:
substDict = {'targs' : type,
'class_name' : 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generate definitions for integer CMP<cc> instructions (with immediate)
def sveIntCmpImmInst(name, Name, opClass, types, op, decoder = 'Generic'):
global header_output, exec_output, decoders
extraPrologCode = '''
auto& destPred = PDest;'''
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());
TheISA::VecPredRegContainer tmpPredC;
auto tmpPred = tmpPredC.as<Element>();
for (unsigned i = 0; i < eCount; ++i)
tmpPred[i] = GpOp_x[i];
destPred.reset();
for (unsigned i = 0; i < eCount; ++i) {
Element srcElem1 = AA64FpOp1_x[i];
Element srcElem2 = static_cast<Element>(imm);
bool destElem = false;
if (tmpPred[i]) {
%(op)s
}
PDest_x[i] = destElem;
}
CondCodesNZ = (destPred.firstActive(tmpPred, eCount) << 1) |
destPred.noneActive(tmpPred, eCount);
CondCodesC = !destPred.lastActive(tmpPred, eCount);
CondCodesV = 0;'''%{'op': op}
iop = InstObjParams(name, 'Sve' + Name, 'SveIntCmpImmOp',
{'code': code, 'op_class': opClass,}, [])
iop.snippets['code'] = extraPrologCode + iop.snippets['code']
header_output += SveIntCmpImmOpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
for type in types:
substDict = {'targs' : type,
'class_name' : 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generate definitions for SVE element count instructions
def sveElemCountInst(name, Name, opClass, types, op,
destType = DestType.Scalar, dstIs32b = False,
dstAcc = True, decoder = 'Generic'):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());
unsigned count = sveDecodePredCount(pattern, eCount);
'''
if destType == DestType.Vector:
code += '''
for (unsigned i = 0; i < eCount; ++i) {
Element srcElem1 = AA64FpDestMerge_x[i];
Element destElem = 0;
%(op)s
AA64FpDest_x[i] = destElem;
}'''%{'op': op}
else:
if 'uint16_t' in types:
if dstIs32b:
dstType = 'uint32_t'
else:
dstType = 'uint64_t'
else:
if dstIs32b:
dstType = 'int32_t'
else:
dstType = 'int64_t'
if dstAcc:
code += '''
%(dstType)s srcElem1 = XDest;
'''%{'dstType': dstType}
code += '''
%(dstType)s destElem = 0;
%(op)s;
XDest = destElem;
'''%{'op': op, 'dstType': dstType}
iop = InstObjParams(name, 'Sve' + Name, 'SveElemCountOp',
{'code': code, 'op_class': opClass, 'dstIsVec': destType,
'dstIs32b': 'true' if dstIs32b else 'false'}, [])
header_output += SveElemCountOpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
for type in types:
substDict = {'targs' : type,
'class_name' : 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict);
def svePartBrkInst(name, Name, opClass, isFlagSetting, predType, whenBrk,
decoder = 'Generic'):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<uint8_t>(
xc->tcBase());
bool dobreak = false;
TheISA::VecPredRegContainer tmpPredC;
auto auxGpOp = tmpPredC.as<uint8_t>();
for (unsigned i = 0; i < eCount; ++i) {
auxGpOp[i] = GpOp_ub[i];
}
for (unsigned i = 0; i < eCount; ++i) {
bool element = POp1_ub[i] == 1;
if (auxGpOp[i]) {'''
breakCode = '''
dobreak = dobreak || element;'''
if whenBrk == Break.Before:
code += breakCode
code += '''
PDest_ub[i] = !dobreak;'''
if whenBrk == Break.After:
code += breakCode
code += '''
}'''
if predType == PredType.ZERO:
code += ''' else {
PDest_ub[i] = 0;
}'''
elif predType == PredType.MERGE:
code += ''' else {
PDest_ub[i] = PDestMerge_ub[i];
}'''
code += '''
}'''
extraPrologCode = ''
if isFlagSetting:
code += '''
CondCodesNZ = (destPred.firstActive(auxGpOp, eCount) << 1) |
destPred.noneActive(auxGpOp, eCount);
CondCodesC = !destPred.lastActive(auxGpOp, eCount);
CondCodesV = 0;'''
extraPrologCode += '''
auto& destPred = PDest;'''
iop = InstObjParams(name, 'Sve' + Name, 'SvePartBrkOp',
{'code': code, 'op_class': opClass,
'isMerging': 'true' if predType == PredType.MERGE
else 'false'}, [])
iop.snippets['code'] = extraPrologCode + iop.snippets['code']
header_output += SvePartBrkOpDeclare.subst(iop)
exec_output += SveNonTemplatedOpExecute.subst(iop)
def svePartBrkPropPrevInst(name, Name, opClass, isFlagSetting, whenBrk,
decoder = 'Generic'):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<uint8_t>(
xc->tcBase());
bool last = POp1_ub.lastActive(GpOp_ub, eCount);
TheISA::VecPredRegContainer tmpPredC;
auto auxGpOp = tmpPredC.as<uint8_t>();
for (unsigned i = 0; i < eCount; ++i) {
auxGpOp[i] = GpOp_ub[i];
}
for (unsigned i = 0; i < eCount; ++i) {
if (auxGpOp[i]) {'''
breakCode = '''
last = last && (POp2_ub[i] == 0);'''
if whenBrk == Break.Before:
code += breakCode
code += '''
PDest_ub[i] = last;'''
if whenBrk == Break.After:
code += breakCode
code += '''
} else {
PDest_ub[i] = 0;
}
}'''
extraPrologCode = ''
if isFlagSetting:
code += '''
CondCodesNZ = (destPred.firstActive(auxGpOp, eCount) << 1) |
destPred.noneActive(auxGpOp, eCount);
CondCodesC = !destPred.lastActive(auxGpOp, eCount);
CondCodesV = 0;'''
extraPrologCode += '''
auto& destPred = PDest;'''
iop = InstObjParams(name, 'Sve' + Name, 'SvePartBrkPropOp',
{'code': code, 'op_class': opClass}, [])
iop.snippets['code'] = extraPrologCode + iop.snippets['code']
header_output += SvePartBrkPropOpDeclare.subst(iop)
exec_output += SveNonTemplatedOpExecute.subst(iop)
def svePartBrkPropNextInst(name, Name, opClass, isFlagSetting,
decoder = 'Generic'):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<uint8_t>(
xc->tcBase());
bool last = POp1_ub.lastActive(GpOp_ub, eCount);
for (unsigned i = 0; i < eCount; i++) {
if (!last) {
PDest_ub[i] = 0;
} else {
PDest_ub[i] = PDestMerge_ub[i];
}
}'''
extraPrologCode = ''
if isFlagSetting:
code += '''
VecPredRegT<uint8_t, MaxSveVecLenInBytes, false, false>::Container c;
VecPredRegT<uint8_t, MaxSveVecLenInBytes, false, false> predOnes(c);
for (unsigned i = 0; i < eCount; i++) {
predOnes[i] = 1;
}
CondCodesNZ = (destPred.firstActive(predOnes, eCount) << 1) |
destPred.noneActive(predOnes, eCount);
CondCodesC = !destPred.lastActive(predOnes, eCount);
CondCodesV = 0;'''
extraPrologCode += '''
auto& destPred = PDest;'''
iop = InstObjParams(name, 'Sve' + Name, 'SvePartBrkPropOp',
{'code': code, 'op_class': opClass}, [])
iop.snippets['code'] = extraPrologCode + iop.snippets['code']
header_output += SvePartBrkPropOpDeclare.subst(iop)
exec_output += SveNonTemplatedOpExecute.subst(iop)
# Generate definitions for scalar select instructions
def sveSelectInst(name, Name, opClass, types, op, isCond,
destType = DstRegType.Scalar, decoder = 'Generic'):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());
int last;
for (last = eCount - 1; last >= 0; --last) {
if (GpOp_x[last]) {
break;
}
}
'''
if isCond:
code += '''
if (last >= 0) {'''
code += '''
Element destElem;
%(op)s'''%{'op': op}
if destType == DstRegType.Vector:
code += '''
for (unsigned i = 0; i < eCount; ++i)
AA64FpDest_x[i] = destElem;'''
elif destType == DstRegType.Scalar:
code += '''
XDest = destElem;'''
elif destType == DstRegType.SimdFpScalar:
code += '''
AA64FpDest_x[0] = destElem;'''
if isCond:
code += '''
}'''
if destType == DstRegType.Scalar:
code += ''' else {
XDest = (Element) XDest;
}'''
elif destType == DstRegType.Vector:
code += ''' else {
for (unsigned i = 0; i < eCount; ++i)
AA64FpDest_x[i] = AA64FpDestMerge_x[i];
}'''
elif destType == DstRegType.SimdFpScalar:
code += ''' else {
AA64FpDest_x[0] = AA64FpDestMerge_x[0];
}'''
iop = InstObjParams(name, 'Sve' + Name, 'SveSelectOp',
{'code': code, 'op_class': opClass,
'isCond': 'true' if isCond else 'false',
'isScalar': 'true'
if destType == DstRegType.Scalar else 'false',
'isSimdFp': 'true'
if destType == DstRegType.SimdFpScalar
else 'false'},
[])
header_output += SveSelectOpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
for type in types:
substDict = {'targs' : type,
'class_name' : 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generate definitions for PNEXT (find next active predicate)
# instructions
def svePNextInst(name, Name, opClass, types, decoder = 'Generic'):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());
TheISA::VecPredRegContainer tmpPredC;
auto auxGpOp = tmpPredC.as<Element>();
for (unsigned i = 0; i < eCount; ++i) {
auxGpOp[i] = GpOp_x[i];
}
int last;
for (last = eCount - 1; last >= 0; --last) {
if (POp1_x[last]) {
break;
}
}
int next = last + 1;
while (next < eCount && GpOp_x[next] == 0) {
next++;
}
destPred.reset();
if (next < eCount) {
PDest_x[next] = 1;
}
CondCodesNZ = (destPred.firstActive(auxGpOp, eCount) << 1) |
destPred.noneActive(auxGpOp, eCount);
CondCodesC = !destPred.lastActive(auxGpOp, eCount);
CondCodesV = 0;'''
extraPrologCode = '''
auto& destPred = PDest;'''
iop = InstObjParams(name, 'Sve' + Name, 'SveUnaryPredPredOp',
{'code': code, 'op_class': opClass}, [])
iop.snippets['code'] = extraPrologCode + iop.snippets['code']
header_output += SveUnaryPredOpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
for type in types:
substDict = {'targs' : type,
'class_name' : 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generate definitions for PFIRST (set first active predicate)
# instructions
def svePFirstInst(name, Name, opClass, decoder = 'Generic'):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());
TheISA::VecPredRegContainer tmpPredC;
auto auxGpOp = tmpPredC.as<Element>();
for (unsigned i = 0; i < eCount; ++i)
auxGpOp[i] = GpOp_x[i];
int first = -1;
for (int i = 0; i < eCount; ++i) {
if (auxGpOp[i] && first == -1) {
first = i;
}
}
for (int i = 0; i < eCount; ++i) {
PDest_x[i] = PDestMerge_x[i];
}
if (first >= 0) {
PDest_x[first] = 1;
}
CondCodesNZ = (destPred.firstActive(auxGpOp, eCount) << 1) |
destPred.noneActive(auxGpOp, eCount);
CondCodesC = !destPred.lastActive(auxGpOp, eCount);
CondCodesV = 0;'''
extraPrologCode = '''
auto& destPred = PDest;'''
iop = InstObjParams(name, 'Sve' + Name, 'SveUnaryPredPredOp',
{'code': code, 'op_class': opClass}, [])
iop.snippets['code'] = extraPrologCode + iop.snippets['code']
header_output += SveUnaryPredOpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
substDict = {'targs' : 'uint8_t',
'class_name' : 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generate definitions for SVE TBL instructions
def sveTblInst(name, Name, opClass, decoder = 'Generic'):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());
for (int i = 0; i < eCount; ++i) {
Element idx = AA64FpOp2_x[i];
Element val;
if (idx < eCount) {
val = AA64FpOp1_x[idx];
} else {
val = 0;
}
AA64FpDest_x[i] = val;
}'''
iop = InstObjParams(name, 'Sve' + Name, 'SveTblOp',
{'code': code, 'op_class': opClass}, [])
header_output += SveBinUnpredOpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
for type in unsignedTypes:
substDict = {'targs' : type,
'class_name' : 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generate definitions for SVE Unpack instructions
def sveUnpackInst(name, Name, opClass, sdtypes, unpackHalf,
regType, decoder = 'Generic'):
global header_output, exec_output, decoders
extraPrologCode = '''
auto& destPred = PDest;'''
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<DElement>(
xc->tcBase());'''
if unpackHalf == Unpack.Low:
if regType == SrcRegType.Predicate:
code += '''
TheISA::VecPredRegContainer tmpPredC;
auto auxPOp1 = tmpPredC.as<SElement>();
for (int i = 0; i < eCount; ++i) {
auxPOp1[i] = POp1_xs[i];
}'''
else:
code += '''
TheISA::VecRegContainer tmpVecC;
auto auxOp1 = tmpVecC.as<SElement>();
for (int i = 0; i < eCount; ++i) {
auxOp1[i] = AA64FpOp1_xs[i];
}'''
code += '''
for (int i = 0; i < eCount; ++i) {'''
if regType == SrcRegType.Predicate:
if unpackHalf == Unpack.High:
code +='''
const SElement& srcElem1 = POp1_xs[i + eCount];'''
else:
code +='''
const SElement& srcElem1 = auxPOp1[i];'''
code += '''
destPred.set_raw(i, 0);
PDest_xd[i] = srcElem1;'''
else:
if unpackHalf == Unpack.High:
code +='''
const SElement& srcElem1 = AA64FpOp1_xs[i + eCount];'''
else:
code +='''
const SElement& srcElem1 = auxOp1[i];'''
code += '''
AA64FpDest_xd[i] = static_cast<DElement>(srcElem1);'''
code += '''
}
'''
iop = InstObjParams(name, 'Sve' + Name, 'SveUnpackOp',
{'code': code, 'op_class': opClass}, [])
if regType == SrcRegType.Predicate:
iop.snippets['code'] = extraPrologCode + iop.snippets['code']
header_output += SveUnpackOpDeclare.subst(iop)
exec_output += SveWideningOpExecute.subst(iop)
for srcType, dstType in sdtypes:
substDict = {'targs': srcType + ', ' + dstType,
'class_name': 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generate definition for SVE predicate test instructions
def svePredTestInst(name, Name, opClass, decoder = 'Generic'):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<uint8_t>(
xc->tcBase());
CondCodesNZ = (POp1_ub.firstActive(GpOp_ub, eCount) << 1) |
POp1_ub.noneActive(GpOp_ub, eCount);
CondCodesC = !POp1_ub.lastActive(GpOp_ub, eCount);
CondCodesV = 0;'''
iop = InstObjParams(name, 'Sve' + Name, 'SvePredTestOp',
{'code': code, 'op_class': opClass}, [])
header_output += SvePredicateTestOpDeclare.subst(iop)
exec_output += SveNonTemplatedOpExecute.subst(iop)
# Generate definition for SVE predicate compact operations
def sveCompactInst(name, Name, opClass, types, decoder = 'Generic'):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());
TheISA::VecRegContainer tmpVecC;
auto auxOp1 = tmpVecC.as<Element>();
for (unsigned i = 0; i < eCount; ++i) {
auxOp1[i] = AA64FpOp1_x[i];
}
unsigned x = 0;
for (unsigned i = 0; i < eCount; ++i) {
AA64FpDest_x[i] = 0;
if (GpOp_x[i]) {
AA64FpDest_x[x] = auxOp1[i];
x++;
}
}'''
iop = InstObjParams(name, 'Sve' + Name, 'SveUnaryPredOp',
{'code': code, 'op_class': opClass}, [])
header_output += SveUnaryPredOpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
for type in types:
substDict = {'targs': type, 'class_name': 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generate definition for unary SVE predicate instructions with implicit
# source operand (PFALSE, RDFFR(S))
def svePredUnaryWImplicitSrcInst(name, Name, opClass, op,
predType=PredType.NONE, isFlagSetting=False, decoder='Generic'):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + op
if isFlagSetting:
code += '''
CondCodesNZ = (destPred.firstActive(GpOp, eCount) << 1) |
destPred.noneActive(GpOp, eCount);
CondCodesC = !destPred.lastActive(GpOp, eCount);
CondCodesV = 0;'''
extraPrologCode = '''
auto& destPred M5_VAR_USED = PDest;'''
baseClass = ('SvePredUnaryWImplicitSrcOp' if predType == PredType.NONE
else 'SvePredUnaryWImplicitSrcPredOp')
iop = InstObjParams(name, 'Sve' + Name, baseClass,
{'code': code, 'op_class': opClass}, [])
iop.snippets['code'] = extraPrologCode + iop.snippets['code']
if predType == PredType.NONE:
header_output += SvePredUnaryOpWImplicitSrcDeclare.subst(iop)
else:
header_output += SvePredUnaryPredOpWImplicitSrcDeclare.subst(iop)
exec_output += SveNonTemplatedOpExecute.subst(iop)
# Generate definition for SVE instructions writing to the FFR (SETFFR,
# WRFFR)
def svePredWriteFfrInst(name, Name, opClass, op, isSetFfr,
decoder='Generic'):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + op
extraPrologCode = '''
auto& destPred M5_VAR_USED = Ffr;'''
baseClass = ('SveWImplicitSrcDstOp' if isSetFfr
else 'SvePredUnaryWImplicitDstOp')
iop = InstObjParams(name, 'Sve' + Name, baseClass,
{'code': code, 'op_class': opClass}, [])
iop.snippets['code'] = extraPrologCode + iop.snippets['code']
if isSetFfr:
header_output += SveOpWImplicitSrcDstDeclare.subst(iop)
else:
header_output += SvePredUnaryOpWImplicitDstDeclare.subst(iop)
exec_output += SveNonTemplatedOpExecute.subst(iop)
# Generate definition for SVE Ext instruction
def sveExtInst(name, Name, opClass, decoder = 'Generic'):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());
TheISA::VecRegContainer tmpVecC;
auto auxOp1 = tmpVecC.as<Element>();
for (unsigned i = 0; i < eCount; ++i) {
auxOp1[i] = AA64FpOp1_x[i];
}
uint64_t pos = imm;
if (pos >= eCount)
pos = 0;
for (int i = 0; i < eCount; ++i, ++pos)
{
if (pos < eCount)
AA64FpDest_x[i] = AA64FpDestMerge_x[pos];
else
AA64FpDest_x[i] = auxOp1[pos-eCount];
}
'''
iop = InstObjParams(name, 'Sve' + Name, 'SveBinImmUnpredDestrOp',
{'code': code, 'op_class': opClass}, [])
header_output += SveBinImmUnpredOpDeclare.subst(iop);
exec_output += SveOpExecute.subst(iop)
substDict = {'targs': 'uint8_t', 'class_name': 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generate definition for SVE Slice instruction
def sveSpliceInst(name, Name, opClass, types, decoder = 'Generic'):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());
TheISA::VecRegContainer tmpVecC;
auto auxDest = tmpVecC.as<Element>();
int firstelem = -1, lastelem = -2;
for (int i = 0; i < eCount; ++i) {
if (GpOp_x[i]) {
lastelem = i;
if (firstelem < 0)
firstelem = i;
}
}
int x = 0;
for (int i = firstelem; i <= lastelem; ++i, ++x) {
auxDest[x] = AA64FpDestMerge_x[i];
}
int remaining = eCount - x;
for (int i = 0; i < remaining; ++i, ++x) {
auxDest[x] = AA64FpOp2_x[i];
}
for (int i = 0; i < eCount; ++i) {
AA64FpDest_x[i] = auxDest[i];
}
'''
iop = InstObjParams(name, 'Sve' + Name, 'SveBinDestrPredOp',
{'code': code, 'op_class': opClass}, [])
header_output += SveBinDestrPredOpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
for type in types:
substDict = {'targs': type, 'class_name': 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generate definition for SVE DUP (index) instruction
def sveDupIndexInst(name, Name, opClass, types, decoder =