| // 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 = |