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 = 'Generic'):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());
Element srcElem1 = 0;
if (imm < eCount) {
srcElem1 = AA64FpOp1_x[imm];
}
for (int i = 0; i < eCount; ++i) {
AA64FpDest_x[i] = srcElem1;
}'''
iop = InstObjParams(name, 'Sve' + Name, 'SveBinImmIdxUnpredOp',
{'code': code, 'op_class': opClass}, [])
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)
# Generate definition for SVE reverse elements instructions
def sveReverseElementsInst(name, Name, opClass, types,
srcType = SrcRegType.Vector, decoder = 'Generic'):
assert srcType in (SrcRegType.Vector, SrcRegType.Predicate)
global header_output, exec_output, decoders
extraPrologCode = '''
auto& destPred = PDest;'''
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());'''
if srcType == SrcRegType.Predicate:
code += '''
TheISA::VecPredRegContainer tmpPredC;
auto auxPOp1 = tmpPredC.as<Element>();
for (unsigned i = 0; i < eCount; ++i) {
uint8_t v = POp1_x.get_raw(i);
auxPOp1.set_raw(i, v);
}
PDest_x[0] = 0;'''
else:
code += '''
TheISA::VecRegContainer tmpRegC;
auto auxOp1 = tmpRegC.as<Element>();
for (unsigned i = 0; i < eCount; ++i) {
auxOp1[i] = AA64FpOp1_x[i];
}'''
code += '''
for (int i = 0; i < eCount; ++i) {'''
if srcType == SrcRegType.Vector:
code += '''
AA64FpDest_x[i] = auxOp1[eCount - i - 1];'''
else:
code += '''
destPred.set_raw(i, auxPOp1.get_raw(eCount - i - 1));'''
code += '''
}'''
iop = InstObjParams(name, 'Sve' + Name, 'SveUnaryUnpredOp',
{'code': code, 'op_class': opClass}, [])
if srcType == SrcRegType.Predicate:
iop.snippets['code'] = extraPrologCode + iop.snippets['code']
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)
# Generate definition for shift & insert instructions
def sveShiftAndInsertInst(name, Name, opClass, types,
srcType = SrcRegType.Scalar, decoder = 'Generic'):
assert srcType in (SrcRegType.SimdFpScalar, SrcRegType.Scalar)
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());'''
if srcType == SrcRegType.Scalar:
code += '''
auto& srcElem1 = XOp1;'''
elif srcType == SrcRegType.SimdFpScalar:
code += '''
auto& srcElem1 = AA64FpOp1_x[0];'''
code += '''
for (int i = eCount - 1; i > 0; --i) {
AA64FpDest_x[i] = AA64FpDestMerge_x[i-1];
}
AA64FpDest_x[0] = srcElem1;'''
iop = InstObjParams(name, 'Sve' + Name, 'SveUnarySca2VecUnpredOp',
{'code': code, 'op_class': opClass,
'isSimdFp': 'true' if srcType == SrcRegType.SimdFpScalar
else 'false'}, [])
header_output += SveShiftAndInsertOpDeclare.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 DOT instructions
def sveDotInst(name, Name, opClass, types, isIndexed = True):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());
for (int i = 0; i < eCount; ++i) {'''
if isIndexed:
code += '''
int segbase = i - i % (16 / sizeof(Element));
int s = segbase + imm;'''
code += '''
DElement res = AA64FpDest_xd[i];
DElement srcElem1, srcElem2;
for (int j = 0; j <= 3; ++j) {
srcElem1 = static_cast<DElement>(AA64FpOp1_xs[4 * i + j]);'''
if isIndexed:
code += '''
srcElem2 = static_cast<DElement>(AA64FpOp2_xs[4 * s + j]);'''
else:
code += '''
srcElem2 = static_cast<DElement>(AA64FpOp2_xs[4 * i + j]);'''
code += '''
res += srcElem1 * srcElem2;
}
AA64FpDestMerge_xd[i] = res;
}'''
iop = InstObjParams(name, 'Sve' + Name,
'SveDotProdIdxOp' if isIndexed else
'SveDotProdOp',
{'code': code, 'op_class': opClass}, [])
if isIndexed:
header_output += SveWideningTerImmOpDeclare.subst(iop)
else:
header_output += SveWideningTerOpDeclare.subst(iop)
exec_output += SveWideningOpExecute.subst(iop)
for type in types:
substDict = {'targs': type, 'class_name': 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
# Generate definition for ordered reduction
def sveOrderedReduction(name, Name, opClass, types, op,
decoder = 'Generic'):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());'''
code += '''
Element destElem = AA64FpDestMerge_x[0];
for (int i = 0; i < eCount; ++i) {
if (GpOp_x[i]) {
Element srcElem1 = AA64FpOp1_x[i];
%(op)s
}
}
for (int i = 1; i < eCount; ++i) {
AA64FpDest_x[i] = 0;
}
AA64FpDest_x[0] = destElem;'''%{'op': op}
iop = InstObjParams(name, 'Sve' + Name, 'SveOrdReducOp',
{'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)
# Generate definitions for complex addition instructions
def sveComplexAddInst(name, Name, opClass, types,
decoder = 'Generic'):
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());'''
code += '''
bool sub_i = (rot == 1);
bool sub_r = (rot == 3);
for (int i = 0; i < eCount / 2; ++i) {
Element acc_r = AA64FpOp1_x[2 * i];
Element acc_i = AA64FpOp1_x[2 * i + 1];
Element elt2_r = AA64FpOp2_x[2 * i];
Element elt2_i = AA64FpOp2_x[2 * i + 1];
FPSCR fpscr;
if (GpOp_x[2 * i]) {
if (sub_i) {
elt2_i = fplibNeg<Element>(elt2_i);
}
fpscr = (FPSCR) FpscrExc;
acc_r = fplibAdd<Element>(acc_r, elt2_i, fpscr);
FpscrExc = fpscr;
}
if (GpOp_x[2 * i + 1]) {
if (sub_r) {
elt2_r = fplibNeg<Element>(elt2_r);
}
fpscr = (FPSCR) FpscrExc;
acc_i = fplibAdd<Element>(acc_i, elt2_r, fpscr);
FpscrExc = fpscr;
}
AA64FpDest_x[2 * i] = acc_r;
AA64FpDest_x[2 * i + 1] = acc_i;
}
'''
iop = InstObjParams(name, 'Sve' + Name, 'SveComplexOp',
{'code': code, 'op_class': opClass}, [])
header_output += SveComplexOpDeclare.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 complex multiply and accumulate instructions
def sveComplexMulAddInst(name, Name, opClass, types,
predType=PredType.NONE, decoder='Generic'):
assert predType in (PredType.NONE, PredType.MERGE)
global header_output, exec_output, decoders
code = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<Element>(
xc->tcBase());'''
code += '''
uint32_t sel_a = rot & 0x1;
uint32_t sel_b = sel_a ? 0 : 1;
bool neg_i = (rot & 0x2) == 1;
bool neg_r = (rot & 0x1) != (rot & 0x2);'''
if predType == PredType.NONE:
code += '''
uint32_t eltspersegment = 16 / (2 * sizeof(Element));'''
code += '''
for (int i = 0; i < eCount / 2; ++i) {'''
if predType == PredType.NONE:
code += '''
uint32_t segmentbase = i - (i % eltspersegment);
uint32_t s = segmentbase + imm;'''
else:
code += '''
uint32_t s = i;'''
code += '''
Element addend_r = AA64FpDestMerge_x[2 * i];
Element addend_i = AA64FpDestMerge_x[2 * i + 1];
Element elt1_a = AA64FpOp1_x[2 * i + sel_a];
Element elt2_a = AA64FpOp2_x[2 * s + sel_a];
Element elt2_b = AA64FpOp2_x[2 * s + sel_b];
FPSCR fpscr;
'''
if predType != PredType.NONE:
code += '''
if (GpOp_x[2 * i]) {'''
code += '''
if (neg_r) {
elt2_a = fplibNeg<Element>(elt2_a);
}
fpscr = (FPSCR) FpscrExc;
addend_r = fplibMulAdd<Element>(addend_r, elt1_a, elt2_a, fpscr);
FpscrExc = fpscr;'''
if predType != PredType.NONE:
code += '''
}'''
if predType != PredType.NONE:
code += '''
if (GpOp_x[2 * i + 1]) {'''
code += '''
if (neg_i) {
elt2_b = fplibNeg<Element>(elt2_b);
}
fpscr = (FPSCR) FpscrExc;
addend_i = fplibMulAdd<Element>(addend_i, elt1_a, elt2_b, fpscr);
FpscrExc = fpscr;'''
if predType != PredType.NONE:
code += '''
}'''
code += '''
AA64FpDest_x[2 * i] = addend_r;
AA64FpDest_x[2 * i + 1] = addend_i;
}'''
iop = InstObjParams(name, 'Sve' + Name,
'SveComplexIdxOp' if predType == PredType.NONE
else 'SveComplexOp',
{'code': code, 'op_class': opClass}, [])
if predType == PredType.NONE:
header_output += SveComplexIndexOpDeclare.subst(iop)
else:
header_output += SveComplexOpDeclare.subst(iop)
exec_output += SveOpExecute.subst(iop)
for type in types:
substDict = {'targs' : type,
'class_name' : 'Sve' + Name}
exec_output += SveOpExecDeclare.subst(substDict)
fpTypes = ('uint16_t', 'uint32_t', 'uint64_t')
signedTypes = ('int8_t', 'int16_t', 'int32_t', 'int64_t')
unsignedTypes = ('uint8_t', 'uint16_t', 'uint32_t', 'uint64_t')
smallSignedTypes = ('int8_t', 'int16_t', 'int32_t')
bigSignedTypes = ('int16_t', 'int32_t', 'int64_t')
smallUnsignedTypes = ('uint8_t', 'uint16_t', 'uint32_t')
bigUnsignedTypes = ('uint16_t', 'uint32_t', 'uint64_t')
unsignedWideSDTypes = (('uint8_t', 'uint16_t'),
('uint16_t', 'uint32_t'), ('uint32_t', 'uint64_t'))
signedWideSDTypes = (('int8_t', 'int16_t'),
('int16_t', 'int32_t'), ('int32_t', 'int64_t'))
# ABS
absCode = 'destElem = (Element) std::abs(srcElem1);'
sveUnaryInst('abs', 'Abs', 'SimdAluOp', signedTypes, absCode,
PredType.MERGE)
# ADD (immediate)
sveWideImmInst('add', 'AddImm', 'SimdAddOp', unsignedTypes, addCode, False)
# ADD (vectors, predicated)
addCode = 'destElem = srcElem1 + srcElem2;'
sveBinInst('add', 'AddPred', 'SimdAddOp', unsignedTypes, addCode,
PredType.MERGE, True)
# ADD (vectors, unpredicated)
addCode = 'destElem = srcElem1 + srcElem2;'
sveBinInst('add', 'AddUnpred', 'SimdAddOp', unsignedTypes, addCode)
# ADDPL
addvlCode = sveEnabledCheckCode + '''
unsigned eCount = ArmStaticInst::getCurSveVecLen<uint%d_t>(
xc->tcBase());
XDest = XOp1 + eCount * (int64_t) imm;
'''
buildXImmDataInst('addpl', addvlCode % 64, buildCc=False)
# ADDVL
buildXImmDataInst('addvl', addvlCode % 8, buildCc=False)
# ADR
adrCode = '''
if (offsetFormat == SveAdrOffsetUnpackedSigned) {
srcElem2 = sext<32>(srcElem2 & mask(32));
} else if (offsetFormat == SveAdrOffsetUnpackedUnsigned) {
srcElem2 = srcElem2 & mask(32);
}
destElem = srcElem1 + srcElem2 * mult;
'''
sveAdrInst('adr', 'Adr', 'SimdAddOp', ('uint32_t', 'uint64_t'), adrCode)
# AND (immediate)
andCode = 'destElem = srcElem1 & srcElem2;'
sveWideImmInst('and', 'AndImm', 'SimdAluOp', ('uint64_t',), andCode)
# AND (vectors, predicated)
sveBinInst('and', 'AndPred', 'SimdAluOp', unsignedTypes, andCode,
PredType.MERGE, True)
# AND (vectors, unpredicated)
andCode = 'destElem = srcElem1 & srcElem2;'
sveBinInst('and', 'AndUnpred', 'SimdAluOp', ('uint64_t',), andCode)
# AND, ANDS (predicates)
svePredLogicalInst('and', 'PredAnd', 'SimdPredAluOp', ('uint8_t',),
andCode)
svePredLogicalInst('ands', 'PredAnds', 'SimdPredAluOp', ('uint8_t',),
andCode, isFlagSetting=True)
# ANDV
andvCode = 'destElem &= srcElem1;'
sveAssocReducInst('andv', 'Andv', 'SimdReduceAluOp', unsignedTypes,
andvCode, 'std::numeric_limits<Element>::max()')
# ASR (immediate, predicated)
asrCode = '''
int sign_bit = bits(srcElem1, sizeof(Element) * 8 - 1);
if (srcElem2 == 0) {
destElem = srcElem1;
} else if (srcElem2 >= sizeof(Element) * 8) {
destElem = sign_bit ? std::numeric_limits<Element>::max() : 0;
} else {
destElem = srcElem1 >> srcElem2;
if (sign_bit) {
destElem |= ~mask(sizeof(Element) * 8 - srcElem2);
}
}
'''
sveBinImmInst('asr', 'AsrImmPred', 'SimdAluOp', unsignedTypes, asrCode,
PredType.MERGE)
# ASR (immediate, unpredicated)
sveBinImmInst('asr', 'AsrImmUnpred', 'SimdAluOp', unsignedTypes, asrCode)
# ASR (vectors)
sveBinInst('asr', 'AsrPred', 'SimdAluOp', unsignedTypes, asrCode,
PredType.MERGE, True)
# ASR (wide elements, predicated)
sveShiftByWideElemsInst('asr', 'AsrWidePred', 'SimdAluOp', unsignedTypes,
asrCode, PredType.MERGE)
# ASR (wide elements, unpredicated)
sveShiftByWideElemsInst('asr', 'AsrWideUnpred', 'SimdAluOp', unsignedTypes,
asrCode)
# ASRD
asrdCode = '''
Element element1 = srcElem1;
Element shift = srcElem2;
if (srcElem1 < 0) {
Element tmp = ((1L << shift) - 1L);
if (tmp == -1L) {
element1 = 0;
} else {
element1 = element1 + tmp;
}
}
destElem = (element1 >> shift);
'''
sveBinImmInst('asrd', 'Asrd', 'SimdAluOp', signedTypes, asrdCode,
PredType.MERGE)
# ASRR
asrrCode = '''
int sign_bit = bits(srcElem2, sizeof(Element) * 8 - 1);
if (srcElem1 == 0) {
destElem = srcElem2;
} else if (srcElem1 >= sizeof(Element) * 8) {
destElem = sign_bit ? std::numeric_limits<Element>::max() : 0;
} else {
destElem = srcElem2 >> srcElem1;
if (sign_bit) {
destElem |= ~mask(sizeof(Element) * 8 - srcElem1);
}
}
'''
sveBinInst('asrr', 'Asrr', 'SimdAluOp', unsignedTypes, asrrCode,
PredType.MERGE, True)
# BIC (vectors, predicated)
bicCode = 'destElem = srcElem1 & ~srcElem2;'
sveBinInst('bic', 'BicPred', 'SimdAluOp', unsignedTypes, bicCode,
PredType.MERGE, True)
# BIC (vectors, unpredicated)
sveBinInst('bic', 'BicUnpred', 'SimdAluOp', unsignedTypes, bicCode)
# BIC, BICS (predicates)
bicCode = 'destElem = srcElem1 && !srcElem2;'
svePredLogicalInst('bic', 'PredBic', 'SimdPredAluOp', ('uint8_t',),
bicCode)
svePredLogicalInst('bics', 'PredBics', 'SimdPredAluOp', ('uint8_t',),
bicCode, isFlagSetting=True)
# BRKA (merging)
svePartBrkInst('brka', 'Brkam', 'SimdPredAluOp', isFlagSetting = False,
predType = PredType.MERGE, whenBrk = Break.After)
# BRKA (zeroing)
svePartBrkInst('brka', 'Brkaz', 'SimdPredAluOp', isFlagSetting = False,
predType = PredType.ZERO, whenBrk = Break.After)
# BRKAS
svePartBrkInst('brkas', 'Brkas', 'SimdPredAluOp', isFlagSetting = True,
predType = PredType.ZERO, whenBrk = Break.After)
# BRKB (merging)
svePartBrkInst('brkb', 'Brkbm', 'SimdPredAluOp', isFlagSetting = False,
predType = PredType.MERGE, whenBrk = Break.Before)
# BRKB (zeroging)
svePartBrkInst('brkb', 'Brkbz', 'SimdPredAluOp', isFlagSetting = False,
predType = PredType.ZERO, whenBrk = Break.Before)
# BRKBS
svePartBrkInst('brkbs', 'Brkbs', 'SimdPredAluOp', isFlagSetting = True,
predType = PredType.ZERO, whenBrk = Break.Before)
# BRKN
svePartBrkPropNextInst('brkn', 'Brkn', 'SimdPredAluOp',
isFlagSetting = False)
# BRKNS
svePartBrkPropNextInst('brkns', 'Brkns', 'SimdPredAluOp',
isFlagSetting = True)
# BRKPA
svePartBrkPropPrevInst('brkpa', 'Brkpa', 'SimdPredAluOp',
isFlagSetting = False, whenBrk = Break.After)
# BRKPAS
svePartBrkPropPrevInst('brkpas', 'Brkpas', 'SimdPredAluOp',
isFlagSetting = True, whenBrk = Break.After)
# BRKPB
svePartBrkPropPrevInst('brkpb', 'Brkpb', 'SimdPredAluOp',
isFlagSetting = False, whenBrk = Break.Before)
# BRKPBS
svePartBrkPropPrevInst('brkpbs', 'Brkpbs', 'SimdPredAluOp',
isFlagSetting = True, whenBrk = Break.Before)
# CLASTA (scalar)
clastaCode = '''
last++;
if (last >= eCount)
last = 0;
destElem = AA64FpOp1_x[last];'''
sveSelectInst('clasta', 'Clasta', 'SimdAluOp', unsignedTypes, clastaCode,
isCond = True, destType = DstRegType.Scalar)
# CLASTA (SIMD&FP scalar)
sveSelectInst('clasta', 'Clastaf', 'SimdAluOp', unsignedTypes, clastaCode,
isCond = True, destType = DstRegType.SimdFpScalar)
# CLASTA (vector)
sveSelectInst('clasta', 'Clastav', 'SimdAluOp', unsignedTypes, clastaCode,
isCond = True, destType = DstRegType.Vector)
# CLASTB (scalar)
clastbCode = '''
destElem = AA64FpOp1_x[last];'''
sveSelectInst('clastb', 'Clastb', 'SimdAluOp', unsignedTypes, clastbCode,
isCond = True, destType = DstRegType.Scalar)
# CLASTB (SIMD&FP scalar)
sveSelectInst('clastb', 'Clastbf', 'SimdAluOp', unsignedTypes, clastbCode,
isCond = True, destType = DstRegType.SimdFpScalar)
# CLASTB (vectors)
sveSelectInst('clastb', 'Clastbv', 'SimdAluOp', unsignedTypes, clastbCode,
isCond = True, destType = DstRegType.Vector)
# CLS
clsCode = '''
destElem = 0;
Element val = srcElem1;
if (val < 0) {
val <<= 1;
while (val < 0) {
destElem++;
val <<= 1;
}
} else {
val <<= 1;
while (val >= 0 && destElem < sizeof(Element) * 8 - 1) {
destElem++;
val <<= 1;
}
}
'''
sveUnaryInst('cls', 'Cls', 'SimdAluOp', signedTypes, clsCode,
PredType.MERGE)
# CLZ
clzCode = '''
destElem = 0;
Element val = srcElem1;
while (val >= 0 && destElem < sizeof(Element) * 8) {
destElem++;
val <<= 1;
}
'''
sveUnaryInst('clz', 'Clz', 'SimdAluOp', signedTypes, clzCode,
PredType.MERGE)
# CMPEQ (immediate)
cmpeqCode = '''
destElem = (srcElem1 == srcElem2);
'''
sveIntCmpImmInst('cmpeq', 'Cmpeqi', 'SimdCmpOp', unsignedTypes, cmpeqCode)
# CMPEQ (vectors)
sveIntCmpInst('cmpeq', 'Cmpeq', 'SimdCmpOp', unsignedTypes, cmpeqCode)
# CMPEQ (wide elements)
sveIntCmpInst('cmpeq', 'Cmpeqw', 'SimdCmpOp', smallUnsignedTypes,
cmpeqCode, True)
# CMPGE (immediate)
cmpgeCode = '''
destElem = (srcElem1 >= srcElem2);
'''
sveIntCmpImmInst('cmpge', 'Cmpgei', 'SimdCmpOp', signedTypes, cmpgeCode)
# CMPGE (vectors)
sveIntCmpInst('cmpge', 'Cmpge', 'SimdCmpOp', signedTypes, cmpgeCode)
# CMPGE (wide elements)
sveIntCmpInst('cmpge', 'Cmpgew', 'SimdCmpOp', smallSignedTypes,
cmpgeCode, True)
# CMPGT (immediate)
cmpgtCode = '''
destElem = (srcElem1 > srcElem2);
'''
sveIntCmpImmInst('cmpge', 'Cmpgti', 'SimdCmpOp', signedTypes, cmpgtCode)
# CMPGT (vectors)
sveIntCmpInst('cmpge', 'Cmpgt', 'SimdCmpOp', signedTypes, cmpgtCode)
# CMPGT (wide elements)
sveIntCmpInst('cmpge', 'Cmpgtw', 'SimdCmpOp', smallSignedTypes,
cmpgtCode, True)
# CMPHI (immediate)
sveIntCmpImmInst('cmphi', 'Cmphii', 'SimdCmpOp', unsignedTypes, cmpgtCode)
# CMPHI (vectors)
sveIntCmpInst('cmphi', 'Cmphi', 'SimdCmpOp', unsignedTypes, cmpgtCode)
# CMPHI (wide elements)
sveIntCmpInst('cmphi', 'Cmphiw', 'SimdCmpOp', smallUnsignedTypes,
cmpgtCode, True)
# CMPHS (immediate)
sveIntCmpImmInst('cmphs', 'Cmphsi', 'SimdCmpOp', unsignedTypes, cmpgeCode)
# CMPHS (vectors)
sveIntCmpInst('cmphs', 'Cmphs', 'SimdCmpOp', unsignedTypes, cmpgeCode)
# CMPHS (wide elements)
sveIntCmpInst('cmphs', 'Cmphsw', 'SimdCmpOp', smallUnsignedTypes,
cmpgeCode, True)
# CMPLE (immediate)
cmpleCode = '''
destElem = (srcElem1 <= srcElem2);
'''
sveIntCmpImmInst('cmple', 'Cmplei', 'SimdCmpOp', signedTypes, cmpleCode)
# CMPLE (wide elements)
sveIntCmpInst('cmple', 'Cmplew', 'SimdCmpOp', smallSignedTypes,
cmpleCode, True)
# CMPLO (immediate)
cmpltCode = '''
destElem = (srcElem1 < srcElem2);
'''
sveIntCmpImmInst('cmplo', 'Cmploi', 'SimdCmpOp', unsignedTypes, cmpltCode)
# CMPLO (wide elements)
sveIntCmpInst('cmplo', 'Cmplow', 'SimdCmpOp', smallUnsignedTypes,
cmpltCode, True)
# CMPLS (immediate)
sveIntCmpImmInst('cmpls', 'Cmplsi', 'SimdCmpOp', unsignedTypes, cmpleCode)
# CMPLS (wide elements)
sveIntCmpInst('cmpls', 'Cmplsw', 'SimdCmpOp', smallUnsignedTypes,
cmpleCode, True)
# CMPLT (immediate)
sveIntCmpImmInst('cmplt', 'Cmplti', 'SimdCmpOp', signedTypes, cmpltCode)
# CMPLT (wide elements)
sveIntCmpInst('cmplt', 'Cmpltw', 'SimdCmpOp', smallSignedTypes,
cmpltCode, True)
# CMPNE (immediate)
cmpneCode = '''
destElem = (srcElem1 != srcElem2);
'''
sveIntCmpImmInst('cmpeq', 'Cmpnei', 'SimdCmpOp', unsignedTypes, cmpneCode)
# CMPNE (vectors)
sveIntCmpInst('cmpeq', 'Cmpne', 'SimdCmpOp', unsignedTypes, cmpneCode)
# CMPNE (wide elements)
sveIntCmpInst('cmpeq', 'Cmpnew', 'SimdCmpOp', smallUnsignedTypes,
cmpneCode, True)
# CNOT
cnotCode = '''
destElem = srcElem1?0:1;
'''
sveUnaryInst('cnot', 'Cnot', 'SimdAluOp', unsignedTypes, cnotCode,
PredType.MERGE)
# CNT
cntCode = '''
destElem = 0;
Element val = srcElem1;
while (val) {
destElem += val & 0x1;
val >>= 1;
}
'''
sveUnaryInst('cnt', 'Cnt', 'SimdAluOp', unsignedTypes, cntCode,
PredType.MERGE)
# CNTB, CNTD, CNTH, CNTW
cntxCode = '''
destElem = (count * imm);
'''
sveElemCountInst('cnt', 'Cntx', 'SimdAluOp', unsignedTypes, cntxCode,
destType = DestType.Scalar, dstIs32b = False, dstAcc = False)
# COMPACT
sveCompactInst('compact', 'Compact', 'SimdPredAluOp',
('uint32_t', 'uint64_t'))
# CPY (immediate)
dupCode = 'destElem = srcElem1;'
sveWideImmInst('cpy', 'CpyImmMerge', 'SimdAluOp', unsignedTypes, dupCode,
predType=PredType.MERGE, isUnary=True)
sveWideImmInst('cpy', 'CpyImmZero', 'SimdAluOp', unsignedTypes, dupCode,
predType=PredType.ZERO, isUnary=True)
# CPY (scalar)
sveUnaryInst('cpy', 'CpyScalar', 'SimdAluOp', unsignedTypes, dupCode,
PredType.MERGE, srcRegType=SrcRegType.Scalar)
# CPY (SIMD&FP scalar)
sveUnaryInst('cpy', 'CpySimdFpScalar', 'SimdAluOp', unsignedTypes, dupCode,
PredType.MERGE, srcRegType=SrcRegType.SimdFpScalar)
# CNTP
svePredCountPredInst('cntp', 'Cntp', 'SimdAluOp', unsignedTypes)
# CTERMEQ
cteqCode = '''
destElem = srcElem1 == srcElem2;
'''
sveCompTermInst('ctermeq', 'Ctermeq', 'IntAluOp',
['uint32_t', 'uint64_t'], cteqCode)
# CTERMNE
ctneCode = '''
destElem = srcElem1 != srcElem2;
'''
sveCompTermInst('ctermne', 'Ctermne', 'IntAluOp',
['uint32_t', 'uint64_t'], ctneCode)
# DECB, DECH, DECW, DECD (scalar)
decxCode = '''
destElem = srcElem1 - (count * imm);
'''
sveElemCountInst('dec', 'Dec', 'SimdAluOp', unsignedTypes, decxCode,
destType = DestType.Scalar, dstIs32b = False)
# DECH, DECW, DECD (vector)
sveElemCountInst('dec', 'Decv', 'SimdAluOp', bigUnsignedTypes, decxCode,
destType = DestType.Vector, dstIs32b = False)
# DECP (scalar)
decpCode = '''
XDest = XDest - count;
'''
svePredCountInst('decp', 'Decp', 'SimdAluOp', unsignedTypes, decpCode,
DestType.Scalar, SrcSize.Src64bit)
# DECP (vector)
decpvCode = '''
destElem = srcElem - count;
'''
svePredCountInst('decp', 'Decpv', 'SimdAluOp', unsignedTypes, decpvCode,
DestType.Vector)
# DUP (immediate)
sveWideImmInst('dup', 'DupImm', 'SimdAluOp', unsignedTypes, dupCode,
isUnary=True)
# DUP (indexed)
sveDupIndexInst('mov', 'DupIdx', 'SimdAluOp',
list(unsignedTypes) + ['__uint128_t'])
# DUP (scalar)
sveUnaryInst('dup', 'DupScalar', 'SimdAluOp', unsignedTypes, dupCode,
PredType.NONE, srcRegType=SrcRegType.Scalar)
# DUPM
sveWideImmInst('dupm', 'Dupm', 'SimdAluOp', unsignedTypes, dupCode,
isUnary=True)
# EOR (immediate)
eorCode = 'destElem = srcElem1 ^ srcElem2;'
sveWideImmInst('eor', 'EorImm', 'SimdAluOp', ('uint64_t',), eorCode)
# EOR (vectors, predicated)
sveBinInst('eor', 'EorPred', 'SimdAluOp', unsignedTypes, eorCode,
PredType.MERGE, True)
# EOR (vectors, unpredicated)
eorCode = 'destElem = srcElem1 ^ srcElem2;'
sveBinInst('eor', 'EorUnpred', 'SimdAluOp', ('uint64_t',), eorCode)
# EOR, EORS (predicates)
svePredLogicalInst('eor', 'PredEor', 'SimdPredAluOp', ('uint8_t',),
eorCode)
svePredLogicalInst('eors', 'PredEors', 'SimdPredAluOp', ('uint8_t',),
eorCode, isFlagSetting=True)
# EORV
eorvCode = 'destElem ^= srcElem1;'
sveAssocReducInst('eorv', 'Eorv', 'SimdReduceAluOp', unsignedTypes,
eorvCode, '0')
# EXT
sveExtInst('ext', 'Ext', 'SimdAluOp')
# FABD
fpOp = '''
FPSCR fpscr = (FPSCR) FpscrExc;
destElem = %s;
FpscrExc = fpscr;
'''
fabdCode = fpOp % 'fplibAbs<Element>(fplibSub(srcElem1, srcElem2, fpscr))'
sveBinInst('fabd', 'Fabd', 'SimdFloatAddOp', floatTypes, fabdCode,
PredType.MERGE, True)
# FABS
fabsCode = 'destElem = fplibAbs<Element>(srcElem1);'
sveUnaryInst('fabs', 'Fabs', 'SimdFloatAluOp', fpTypes, fabsCode,
PredType.MERGE)
# FACGE
fpCmpAbsOp = fpOp % ('fplibCompare%s<Element>(fplibAbs<Element>(srcElem1),'
' fplibAbs<Element>(srcElem2), fpscr)')
facgeCode = fpCmpAbsOp % 'GE'
sveCmpInst('facge', 'Facge', 'SimdFloatCmpOp', fpTypes, facgeCode)
# FACGT
facgtCode = fpCmpAbsOp % 'GT'
sveCmpInst('facgt', 'Facgt', 'SimdFloatCmpOp', fpTypes, facgtCode)
# FADD (immediate)
fpBinOp = fpOp % 'fplib%s<Element>(srcElem1, srcElem2, fpscr)'
faddCode = fpBinOp % 'Add'
sveBinImmInst('fadd', 'FaddImm', 'SimdFloatAddOp', floatTypes, faddCode,
PredType.MERGE)
# FADD (vectors, predicated)
sveBinInst('fadd', 'FaddPred', 'SimdFloatAddOp', floatTypes, faddCode,
PredType.MERGE, True)
# FADD (vectors, unpredicated)
sveBinInst('fadd', 'FaddUnpred', 'SimdFloatAddOp', floatTypes, faddCode)
# FADDA
fpAddaOp = '''
FPSCR fpscr = (FPSCR) FpscrExc;
destElem = fplibAdd<Element>(destElem, srcElem1, fpscr);
FpscrExc = FpscrExc | fpscr;
'''
sveOrderedReduction('fadda', 'Fadda', 'SimdFloatReduceAddOp', floatTypes,
fpAddaOp)
# FADDV
fpReduceOp = '''
FPSCR fpscr = (FPSCR) FpscrExc;
destElem = fplib%s<Element>(srcElem1, srcElem2, fpscr);
FpscrExc = FpscrExc | fpscr;
'''
faddvCode = fpReduceOp % 'Add'
sveNonAssocReducInst('faddv', 'Faddv', 'SimdFloatReduceAddOp', floatTypes,
faddvCode, '0')
# FCADD
sveComplexAddInst('fcadd','Fcadd', 'SimdFloatAddOp', fpTypes)
# FCMEQ (vectors)
fpCmpOp = fpOp % ('fplibCompare%s<Element>(srcElem1, srcElem2, fpscr)')
fcmeqCode = fpCmpOp % 'EQ'
sveCmpInst('fcmeq', 'Fcmeq', 'SimdFloatCmpOp', fpTypes, fcmeqCode)
# FCMEQ (zero)
fpCmpZeroOp = fpOp % 'fplibCompare%s<Element>(srcElem1, 0, fpscr)'
fcmeqZeroCode = fpCmpZeroOp % 'EQ'
sveCmpInst('fcmeq', 'FcmeqZero', 'SimdFloatCmpOp', fpTypes, fcmeqZeroCode,
True)
# FCMGE (vectors)
fcmgeCode = fpCmpOp % 'GE'
sveCmpInst('fcmge', 'Fcmge', 'SimdFloatCmpOp', fpTypes, fcmgeCode)
# FCMGE (zero)
fcmgeZeroCode = fpCmpZeroOp % 'GE'
sveCmpInst('fcmge', 'FcmgeZero', 'SimdFloatCmpOp', fpTypes, fcmgeZeroCode,
True)
# FCMGT (vectors)
fcmgtCode = fpCmpOp % 'GT'
sveCmpInst('fcmgt', 'Fcmgt', 'SimdFloatCmpOp', fpTypes, fcmgtCode)
# FCMGT (zero)
fcmgtZeroCode = fpCmpZeroOp % 'GT'
sveCmpInst('fcmgt', 'FcmgtZero', 'SimdFloatCmpOp', fpTypes, fcmgtZeroCode,
True)
# FCMLE (zero)
fpCmpRevZeroOp = fpOp % ('fplibCompare%s<Element>(0, srcElem1, fpscr)')
fcmleZeroCode = fpCmpRevZeroOp % 'GE'
sveCmpInst('fcmle', 'FcmleZero', 'SimdFloatCmpOp', fpTypes, fcmleZeroCode,
True)
# FCMLT (zero)
fcmltZeroCode = fpCmpRevZeroOp % 'GT'
sveCmpInst('fcmlt', 'FcmltZero', 'SimdFloatCmpOp', fpTypes, fcmltZeroCode,
True)
# FCMNE (vectors)
fcmneCode = fpOp % ('!fplibCompareEQ<Element>(srcElem1, srcElem2, fpscr)')
sveCmpInst('fcmne', 'Fcmne', 'SimdFloatCmpOp', fpTypes, fcmneCode)