| // -*- mode:c++ -*- |
| |
| // Copyright (c) 2010-2011, 2015, 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. |
| |
| output header {{ |
| template <template <typename T> class Base> |
| StaticInstPtr |
| decodeNeonUThreeUReg(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 Unknown(machInst); |
| } |
| } |
| |
| template <class BaseS, class BaseD> |
| StaticInstPtr |
| decodeNeonSizeSingleDouble(unsigned size, |
| ExtMachInst machInst, IntRegIndex dest, |
| IntRegIndex op1, IntRegIndex op2) |
| { |
| switch (size) { |
| case 2: |
| return new BaseS(machInst, dest, op1, op2); |
| case 3: |
| return new BaseD(machInst, dest, op1, op2); |
| default: |
| return new Unknown(machInst); |
| } |
| } |
| |
| template <template <typename T> class Base> |
| StaticInstPtr |
| decodeNeonSThreeUReg(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 Unknown(machInst); |
| } |
| } |
| |
| template <template <typename T> class Base> |
| StaticInstPtr |
| decodeNeonUSThreeUReg(bool notSigned, unsigned size, |
| ExtMachInst machInst, IntRegIndex dest, |
| IntRegIndex op1, IntRegIndex op2) |
| { |
| if (notSigned) { |
| return decodeNeonUThreeUReg<Base>(size, machInst, dest, op1, op2); |
| } else { |
| return decodeNeonSThreeUReg<Base>(size, machInst, dest, op1, op2); |
| } |
| } |
| |
| template <template <typename T> class Base> |
| StaticInstPtr |
| decodeNeonUThreeUSReg(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); |
| default: |
| return new Unknown(machInst); |
| } |
| } |
| |
| template <template <typename T> class Base> |
| StaticInstPtr |
| decodeNeonSThreeUSReg(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); |
| default: |
| return new Unknown(machInst); |
| } |
| } |
| |
| template <template <typename T> class Base> |
| StaticInstPtr |
| decodeNeonSThreeHAndWReg(unsigned size, ExtMachInst machInst, |
| IntRegIndex dest, IntRegIndex op1, |
| IntRegIndex op2) |
| { |
| switch (size) { |
| case 1: |
| return new Base<int16_t>(machInst, dest, op1, op2); |
| case 2: |
| return new Base<int32_t>(machInst, dest, op1, op2); |
| default: |
| return new Unknown(machInst); |
| } |
| } |
| |
| template <template <typename T> class Base> |
| StaticInstPtr |
| decodeNeonSThreeImmHAndWReg(unsigned size, ExtMachInst machInst, |
| IntRegIndex dest, IntRegIndex op1, |
| IntRegIndex op2, uint64_t imm) |
| { |
| switch (size) { |
| case 1: |
| return new Base<int16_t>(machInst, dest, op1, op2, imm); |
| case 2: |
| return new Base<int32_t>(machInst, dest, op1, op2, imm); |
| default: |
| return new Unknown(machInst); |
| } |
| } |
| |
| template <template <typename T> class Base> |
| StaticInstPtr |
| decodeNeonUSThreeUSReg(bool notSigned, unsigned size, |
| ExtMachInst machInst, IntRegIndex dest, |
| IntRegIndex op1, IntRegIndex op2) |
| { |
| if (notSigned) { |
| return decodeNeonUThreeUSReg<Base>( |
| size, machInst, dest, op1, op2); |
| } else { |
| return decodeNeonSThreeUSReg<Base>( |
| size, machInst, dest, op1, op2); |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonUThreeSReg(bool q, unsigned size, |
| ExtMachInst machInst, IntRegIndex dest, |
| IntRegIndex op1, IntRegIndex op2) |
| { |
| if (q) { |
| return decodeNeonUThreeUSReg<BaseQ>( |
| size, machInst, dest, op1, op2); |
| } else { |
| return decodeNeonUThreeUSReg<BaseD>( |
| size, machInst, dest, op1, op2); |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonSThreeSReg(bool q, unsigned size, |
| ExtMachInst machInst, IntRegIndex dest, |
| IntRegIndex op1, IntRegIndex op2) |
| { |
| if (q) { |
| return decodeNeonSThreeUSReg<BaseQ>( |
| size, machInst, dest, op1, op2); |
| } else { |
| return decodeNeonSThreeUSReg<BaseD>( |
| size, machInst, dest, op1, op2); |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonSThreeXReg(bool q, unsigned size, |
| ExtMachInst machInst, IntRegIndex dest, |
| IntRegIndex op1, IntRegIndex op2) |
| { |
| if (q) { |
| return decodeNeonSThreeUReg<BaseQ>( |
| size, machInst, dest, op1, op2); |
| } else { |
| return decodeNeonSThreeUSReg<BaseD>( |
| size, machInst, dest, op1, op2); |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonUThreeXReg(bool q, unsigned size, |
| ExtMachInst machInst, IntRegIndex dest, |
| IntRegIndex op1, IntRegIndex op2) |
| { |
| if (q) { |
| return decodeNeonUThreeUReg<BaseQ>( |
| size, machInst, dest, op1, op2); |
| } else { |
| return decodeNeonUThreeUSReg<BaseD>( |
| size, machInst, dest, op1, op2); |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonUSThreeSReg(bool q, bool notSigned, unsigned size, |
| ExtMachInst machInst, IntRegIndex dest, |
| IntRegIndex op1, IntRegIndex op2) |
| { |
| if (notSigned) { |
| return decodeNeonUThreeSReg<BaseD, BaseQ>( |
| q, size, machInst, dest, op1, op2); |
| } else { |
| return decodeNeonSThreeSReg<BaseD, BaseQ>( |
| q, size, machInst, dest, op1, op2); |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonUThreeReg(bool q, unsigned size, |
| ExtMachInst machInst, IntRegIndex dest, |
| IntRegIndex op1, IntRegIndex op2) |
| { |
| if (q) { |
| return decodeNeonUThreeUReg<BaseQ>( |
| size, machInst, dest, op1, op2); |
| } else { |
| return decodeNeonUThreeUReg<BaseD>( |
| size, machInst, dest, op1, op2); |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonSThreeReg(bool q, unsigned size, |
| ExtMachInst machInst, IntRegIndex dest, |
| IntRegIndex op1, IntRegIndex op2) |
| { |
| if (q) { |
| return decodeNeonSThreeUReg<BaseQ>( |
| size, machInst, dest, op1, op2); |
| } else { |
| return decodeNeonSThreeUReg<BaseD>( |
| size, machInst, dest, op1, op2); |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonUSThreeReg(bool q, bool notSigned, unsigned size, |
| ExtMachInst machInst, IntRegIndex dest, |
| IntRegIndex op1, IntRegIndex op2) |
| { |
| if (notSigned) { |
| return decodeNeonUThreeReg<BaseD, BaseQ>( |
| q, size, machInst, dest, op1, op2); |
| } else { |
| return decodeNeonSThreeReg<BaseD, BaseQ>( |
| q, size, machInst, dest, op1, op2); |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonUThreeFpReg(bool q, unsigned size, ExtMachInst machInst, |
| IntRegIndex dest, IntRegIndex op1, IntRegIndex op2) |
| { |
| if (q) { |
| if (size) |
| return new BaseQ<uint64_t>(machInst, dest, op1, op2); |
| else |
| return new BaseQ<uint32_t>(machInst, dest, op1, op2); |
| } else { |
| if (size) |
| return new Unknown(machInst); |
| else |
| return new BaseD<uint32_t>(machInst, dest, op1, op2); |
| } |
| } |
| |
| template <template <typename T> class Base> |
| StaticInstPtr |
| decodeNeonUThreeScFpReg(bool size, ExtMachInst machInst, |
| IntRegIndex dest, IntRegIndex op1, IntRegIndex op2) |
| { |
| if (size) |
| return new Base<uint64_t>(machInst, dest, op1, op2); |
| else |
| return new Base<uint32_t>(machInst, dest, op1, op2); |
| } |
| |
| template <template <typename T> class Base> |
| StaticInstPtr |
| decodeNeonUThreeImmScFpReg(bool size, ExtMachInst machInst, |
| IntRegIndex dest, IntRegIndex op1, |
| IntRegIndex op2, uint64_t imm) |
| { |
| if (size) |
| return new Base<uint64_t>(machInst, dest, op1, op2, imm); |
| else |
| return new Base<uint32_t>(machInst, dest, op1, op2, imm); |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonUThreeImmHAndWReg(bool q, unsigned size, ExtMachInst machInst, |
| IntRegIndex dest, IntRegIndex op1, |
| IntRegIndex op2, uint64_t imm) |
| { |
| if (q) { |
| switch (size) { |
| case 1: |
| return new BaseQ<uint16_t>(machInst, dest, op1, op2, imm); |
| case 2: |
| return new BaseQ<uint32_t>(machInst, dest, op1, op2, imm); |
| default: |
| return new Unknown(machInst); |
| } |
| } else { |
| switch (size) { |
| case 1: |
| return new BaseD<uint16_t>(machInst, dest, op1, op2, imm); |
| case 2: |
| return new BaseD<uint32_t>(machInst, dest, op1, op2, imm); |
| default: |
| return new Unknown(machInst); |
| } |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonSThreeImmHAndWReg(bool q, unsigned size, ExtMachInst machInst, |
| IntRegIndex dest, IntRegIndex op1, |
| IntRegIndex op2, uint64_t imm) |
| { |
| if (q) { |
| switch (size) { |
| case 1: |
| return new BaseQ<int16_t>(machInst, dest, op1, op2, imm); |
| case 2: |
| return new BaseQ<int32_t>(machInst, dest, op1, op2, imm); |
| default: |
| return new Unknown(machInst); |
| } |
| } else { |
| switch (size) { |
| case 1: |
| return new BaseD<int16_t>(machInst, dest, op1, op2, imm); |
| case 2: |
| return new BaseD<int32_t>(machInst, dest, op1, op2, imm); |
| default: |
| return new Unknown(machInst); |
| } |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonUThreeImmFpReg(bool q, unsigned size, ExtMachInst machInst, |
| IntRegIndex dest, IntRegIndex op1, |
| IntRegIndex op2, uint64_t imm) |
| { |
| if (q) { |
| if (size) |
| return new BaseQ<uint64_t>(machInst, dest, op1, op2, imm); |
| else |
| return new BaseQ<uint32_t>(machInst, dest, op1, op2, imm); |
| } else { |
| if (size) |
| return new Unknown(machInst); |
| else |
| return new BaseD<uint32_t>(machInst, dest, op1, op2, imm); |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonUTwoShiftReg(bool q, unsigned size, |
| ExtMachInst machInst, IntRegIndex dest, |
| IntRegIndex op1, uint64_t imm) |
| { |
| if (q) { |
| switch (size) { |
| case 0: |
| return new BaseQ<uint8_t>(machInst, dest, op1, imm); |
| case 1: |
| return new BaseQ<uint16_t>(machInst, dest, op1, imm); |
| case 2: |
| return new BaseQ<uint32_t>(machInst, dest, op1, imm); |
| case 3: |
| return new BaseQ<uint64_t>(machInst, dest, op1, imm); |
| default: |
| return new Unknown(machInst); |
| } |
| } else { |
| switch (size) { |
| case 0: |
| return new BaseD<uint8_t>(machInst, dest, op1, imm); |
| case 1: |
| return new BaseD<uint16_t>(machInst, dest, op1, imm); |
| case 2: |
| return new BaseD<uint32_t>(machInst, dest, op1, imm); |
| case 3: |
| return new BaseD<uint64_t>(machInst, dest, op1, imm); |
| default: |
| return new Unknown(machInst); |
| } |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonSTwoShiftReg(bool q, unsigned size, |
| ExtMachInst machInst, IntRegIndex dest, |
| IntRegIndex op1, uint64_t imm) |
| { |
| if (q) { |
| switch (size) { |
| case 0: |
| return new BaseQ<int8_t>(machInst, dest, op1, imm); |
| case 1: |
| return new BaseQ<int16_t>(machInst, dest, op1, imm); |
| case 2: |
| return new BaseQ<int32_t>(machInst, dest, op1, imm); |
| case 3: |
| return new BaseQ<int64_t>(machInst, dest, op1, imm); |
| default: |
| return new Unknown(machInst); |
| } |
| } else { |
| switch (size) { |
| case 0: |
| return new BaseD<int8_t>(machInst, dest, op1, imm); |
| case 1: |
| return new BaseD<int16_t>(machInst, dest, op1, imm); |
| case 2: |
| return new BaseD<int32_t>(machInst, dest, op1, imm); |
| case 3: |
| return new BaseD<int64_t>(machInst, dest, op1, imm); |
| default: |
| return new Unknown(machInst); |
| } |
| } |
| } |
| |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonUSTwoShiftReg(bool q, bool notSigned, unsigned size, |
| ExtMachInst machInst, IntRegIndex dest, |
| IntRegIndex op1, uint64_t imm) |
| { |
| if (notSigned) { |
| return decodeNeonUTwoShiftReg<BaseD, BaseQ>( |
| q, size, machInst, dest, op1, imm); |
| } else { |
| return decodeNeonSTwoShiftReg<BaseD, BaseQ>( |
| q, size, machInst, dest, op1, imm); |
| } |
| } |
| |
| template <template <typename T> class Base> |
| StaticInstPtr |
| decodeNeonUTwoShiftUSReg(unsigned size, |
| ExtMachInst machInst, IntRegIndex dest, |
| IntRegIndex op1, uint64_t imm) |
| { |
| switch (size) { |
| case 0: |
| return new Base<uint8_t>(machInst, dest, op1, imm); |
| case 1: |
| return new Base<uint16_t>(machInst, dest, op1, imm); |
| case 2: |
| return new Base<uint32_t>(machInst, dest, op1, imm); |
| default: |
| return new Unknown(machInst); |
| } |
| } |
| |
| template <template <typename T> class Base> |
| StaticInstPtr |
| decodeNeonUTwoShiftUReg(unsigned size, |
| ExtMachInst machInst, IntRegIndex dest, |
| IntRegIndex op1, uint64_t imm) |
| { |
| switch (size) { |
| case 0: |
| return new Base<uint8_t>(machInst, dest, op1, imm); |
| case 1: |
| return new Base<uint16_t>(machInst, dest, op1, imm); |
| case 2: |
| return new Base<uint32_t>(machInst, dest, op1, imm); |
| case 3: |
| return new Base<uint64_t>(machInst, dest, op1, imm); |
| default: |
| return new Unknown(machInst); |
| } |
| } |
| |
| template <template <typename T> class Base> |
| StaticInstPtr |
| decodeNeonSTwoShiftUReg(unsigned size, |
| ExtMachInst machInst, IntRegIndex dest, |
| IntRegIndex op1, uint64_t imm) |
| { |
| switch (size) { |
| case 0: |
| return new Base<int8_t>(machInst, dest, op1, imm); |
| case 1: |
| return new Base<int16_t>(machInst, dest, op1, imm); |
| case 2: |
| return new Base<int32_t>(machInst, dest, op1, imm); |
| case 3: |
| return new Base<int64_t>(machInst, dest, op1, imm); |
| default: |
| return new Unknown(machInst); |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonUTwoShiftSReg(bool q, unsigned size, |
| ExtMachInst machInst, IntRegIndex dest, |
| IntRegIndex op1, uint64_t imm) |
| { |
| if (q) { |
| return decodeNeonUTwoShiftUSReg<BaseQ>( |
| size, machInst, dest, op1, imm); |
| } else { |
| return decodeNeonUTwoShiftUSReg<BaseD>( |
| size, machInst, dest, op1, imm); |
| } |
| } |
| |
| template <template <typename T> class Base> |
| StaticInstPtr |
| decodeNeonSTwoShiftUSReg(unsigned size, |
| ExtMachInst machInst, IntRegIndex dest, |
| IntRegIndex op1, uint64_t imm) |
| { |
| switch (size) { |
| case 0: |
| return new Base<int8_t>(machInst, dest, op1, imm); |
| case 1: |
| return new Base<int16_t>(machInst, dest, op1, imm); |
| case 2: |
| return new Base<int32_t>(machInst, dest, op1, imm); |
| default: |
| return new Unknown(machInst); |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonSTwoShiftSReg(bool q, unsigned size, |
| ExtMachInst machInst, IntRegIndex dest, |
| IntRegIndex op1, uint64_t imm) |
| { |
| if (q) { |
| return decodeNeonSTwoShiftUSReg<BaseQ>( |
| size, machInst, dest, op1, imm); |
| } else { |
| return decodeNeonSTwoShiftUSReg<BaseD>( |
| size, machInst, dest, op1, imm); |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonUSTwoShiftSReg(bool q, bool notSigned, unsigned size, |
| ExtMachInst machInst, IntRegIndex dest, |
| IntRegIndex op1, uint64_t imm) |
| { |
| if (notSigned) { |
| return decodeNeonUTwoShiftSReg<BaseD, BaseQ>( |
| q, size, machInst, dest, op1, imm); |
| } else { |
| return decodeNeonSTwoShiftSReg<BaseD, BaseQ>( |
| q, size, machInst, dest, op1, imm); |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonUTwoShiftXReg(bool q, unsigned size, ExtMachInst machInst, |
| IntRegIndex dest, IntRegIndex op1, uint64_t imm) |
| { |
| if (q) { |
| return decodeNeonUTwoShiftUReg<BaseQ>( |
| size, machInst, dest, op1, imm); |
| } else { |
| return decodeNeonUTwoShiftUSReg<BaseD>( |
| size, machInst, dest, op1, imm); |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonSTwoShiftXReg(bool q, unsigned size, ExtMachInst machInst, |
| IntRegIndex dest, IntRegIndex op1, uint64_t imm) |
| { |
| if (q) { |
| return decodeNeonSTwoShiftUReg<BaseQ>( |
| size, machInst, dest, op1, imm); |
| } else { |
| return decodeNeonSTwoShiftUSReg<BaseD>( |
| size, machInst, dest, op1, imm); |
| } |
| } |
| |
| template <template <typename T> class Base> |
| StaticInstPtr |
| decodeNeonUTwoShiftUFpReg(unsigned size, ExtMachInst machInst, |
| IntRegIndex dest, IntRegIndex op1, uint64_t imm) |
| { |
| if (size) |
| return new Base<uint64_t>(machInst, dest, op1, imm); |
| else |
| return new Base<uint32_t>(machInst, dest, op1, imm); |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonUTwoShiftFpReg(bool q, unsigned size, ExtMachInst machInst, |
| IntRegIndex dest, IntRegIndex op1, uint64_t imm) |
| { |
| if (q) { |
| if (size) |
| return new BaseQ<uint64_t>(machInst, dest, op1, imm); |
| else |
| return new BaseQ<uint32_t>(machInst, dest, op1, imm); |
| } else { |
| if (size) |
| return new Unknown(machInst); |
| else |
| return new BaseD<uint32_t>(machInst, dest, op1, imm); |
| } |
| } |
| |
| template <template <typename T> class Base> |
| StaticInstPtr |
| decodeNeonUTwoMiscUSReg(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); |
| default: |
| return new Unknown(machInst); |
| } |
| } |
| |
| template <template <typename T> class Base> |
| StaticInstPtr |
| decodeNeonSTwoMiscUSReg(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); |
| default: |
| return new Unknown(machInst); |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonUTwoMiscSReg(bool q, unsigned size, |
| ExtMachInst machInst, IntRegIndex dest, |
| IntRegIndex op1) |
| { |
| if (q) { |
| return decodeNeonUTwoMiscUSReg<BaseQ>(size, machInst, dest, op1); |
| } else { |
| return decodeNeonUTwoMiscUSReg<BaseD>(size, machInst, dest, op1); |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonSTwoMiscSReg(bool q, unsigned size, |
| ExtMachInst machInst, IntRegIndex dest, |
| IntRegIndex op1) |
| { |
| if (q) { |
| return decodeNeonSTwoMiscUSReg<BaseQ>(size, machInst, dest, op1); |
| } else { |
| return decodeNeonSTwoMiscUSReg<BaseD>(size, machInst, dest, op1); |
| } |
| } |
| |
| template <template <typename T> class Base> |
| StaticInstPtr |
| decodeNeonUTwoMiscUReg(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 Unknown(machInst); |
| } |
| } |
| |
| template <template <typename T> class Base> |
| StaticInstPtr |
| decodeNeonSTwoMiscUReg(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 Unknown(machInst); |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonSTwoMiscReg(bool q, unsigned size, |
| ExtMachInst machInst, IntRegIndex dest, |
| IntRegIndex op1) |
| { |
| if (q) { |
| return decodeNeonSTwoMiscUReg<BaseQ>(size, machInst, dest, op1); |
| } else { |
| return decodeNeonSTwoMiscUReg<BaseD>(size, machInst, dest, op1); |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonUTwoMiscReg(bool q, unsigned size, |
| ExtMachInst machInst, IntRegIndex dest, |
| IntRegIndex op1) |
| { |
| if (q) { |
| return decodeNeonUTwoMiscUReg<BaseQ>(size, machInst, dest, op1); |
| } else { |
| return decodeNeonUTwoMiscUReg<BaseD>(size, machInst, dest, op1); |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonUSTwoMiscSReg(bool q, bool notSigned, unsigned size, |
| ExtMachInst machInst, IntRegIndex dest, |
| IntRegIndex op1) |
| { |
| if (notSigned) { |
| return decodeNeonUTwoShiftSReg<BaseD, BaseQ>( |
| q, size, machInst, dest, op1); |
| } else { |
| return decodeNeonSTwoShiftSReg<BaseD, BaseQ>( |
| q, size, machInst, dest, op1); |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonUTwoMiscXReg(bool q, unsigned size, ExtMachInst machInst, |
| IntRegIndex dest, IntRegIndex op1) |
| { |
| if (q) { |
| return decodeNeonUTwoMiscUReg<BaseQ>(size, machInst, dest, op1); |
| } else { |
| return decodeNeonUTwoMiscUSReg<BaseD>(size, machInst, dest, op1); |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonSTwoMiscXReg(bool q, unsigned size, ExtMachInst machInst, |
| IntRegIndex dest, IntRegIndex op1) |
| { |
| if (q) { |
| return decodeNeonSTwoMiscUReg<BaseQ>(size, machInst, dest, op1); |
| } else { |
| return decodeNeonSTwoMiscUSReg<BaseD>(size, machInst, dest, op1); |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonUTwoMiscFpReg(bool q, unsigned size, ExtMachInst machInst, |
| IntRegIndex dest, IntRegIndex op1) |
| { |
| if (q) { |
| if (size) |
| return new BaseQ<uint64_t>(machInst, dest, op1); |
| else |
| return new BaseQ<uint32_t>(machInst, dest, op1); |
| } else { |
| if (size) |
| return new Unknown(machInst); |
| else |
| return new BaseD<uint32_t>(machInst, dest, op1); |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonUTwoMiscPwiseScFpReg(unsigned size, ExtMachInst machInst, |
| IntRegIndex dest, IntRegIndex op1) |
| { |
| if (size) |
| return new BaseQ<uint64_t>(machInst, dest, op1); |
| else |
| return new BaseD<uint32_t>(machInst, dest, op1); |
| } |
| |
| template <template <typename T> class Base> |
| StaticInstPtr |
| decodeNeonUTwoMiscScFpReg(unsigned size, ExtMachInst machInst, |
| IntRegIndex dest, IntRegIndex op1) |
| { |
| if (size) |
| return new Base<uint64_t>(machInst, dest, op1); |
| else |
| return new Base<uint32_t>(machInst, dest, op1); |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonUAcrossLanesReg(bool q, unsigned size, ExtMachInst machInst, |
| IntRegIndex dest, IntRegIndex op1) |
| { |
| if (q) { |
| switch (size) { |
| case 0x0: |
| return new BaseQ<uint8_t>(machInst, dest, op1); |
| case 0x1: |
| return new BaseQ<uint16_t>(machInst, dest, op1); |
| case 0x2: |
| return new BaseQ<uint32_t>(machInst, dest, op1); |
| default: |
| return new Unknown(machInst); |
| } |
| } else { |
| switch (size) { |
| case 0x0: |
| return new BaseD<uint8_t>(machInst, dest, op1); |
| case 0x1: |
| return new BaseD<uint16_t>(machInst, dest, op1); |
| default: |
| return new Unknown(machInst); |
| } |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ, |
| template <typename T> class BaseBQ> |
| StaticInstPtr |
| decodeNeonUAcrossLanesReg(bool q, unsigned size, ExtMachInst machInst, |
| IntRegIndex dest, IntRegIndex op1) |
| { |
| if (q) { |
| switch (size) { |
| case 0x0: |
| return new BaseQ<uint8_t>(machInst, dest, op1); |
| case 0x1: |
| return new BaseQ<uint16_t>(machInst, dest, op1); |
| case 0x2: |
| return new BaseBQ<uint32_t>(machInst, dest, op1); |
| default: |
| return new Unknown(machInst); |
| } |
| } else { |
| switch (size) { |
| case 0x0: |
| return new BaseD<uint8_t>(machInst, dest, op1); |
| case 0x1: |
| return new BaseD<uint16_t>(machInst, dest, op1); |
| default: |
| return new Unknown(machInst); |
| } |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ> |
| StaticInstPtr |
| decodeNeonSAcrossLanesReg(bool q, unsigned size, ExtMachInst machInst, |
| IntRegIndex dest, IntRegIndex op1) |
| { |
| if (q) { |
| switch (size) { |
| case 0x0: |
| return new BaseQ<int8_t>(machInst, dest, op1); |
| case 0x1: |
| return new BaseQ<int16_t>(machInst, dest, op1); |
| case 0x2: |
| return new BaseQ<int32_t>(machInst, dest, op1); |
| default: |
| return new Unknown(machInst); |
| } |
| } else { |
| switch (size) { |
| case 0x0: |
| return new BaseD<int8_t>(machInst, dest, op1); |
| case 0x1: |
| return new BaseD<int16_t>(machInst, dest, op1); |
| default: |
| return new Unknown(machInst); |
| } |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ, |
| template <typename T> class BaseBQ> |
| StaticInstPtr |
| decodeNeonUAcrossLanesLongReg(bool q, unsigned size, ExtMachInst machInst, |
| IntRegIndex dest, IntRegIndex op1) |
| { |
| if (q) { |
| switch (size) { |
| case 0x0: |
| return new BaseQ<uint8_t>(machInst, dest, op1); |
| case 0x1: |
| return new BaseQ<uint16_t>(machInst, dest, op1); |
| case 0x2: |
| return new BaseBQ<uint32_t>(machInst, dest, op1); |
| default: |
| return new Unknown(machInst); |
| } |
| } else { |
| switch (size) { |
| case 0x0: |
| return new BaseD<uint8_t>(machInst, dest, op1); |
| case 0x1: |
| return new BaseD<uint16_t>(machInst, dest, op1); |
| default: |
| return new Unknown(machInst); |
| } |
| } |
| } |
| |
| template <template <typename T> class BaseD, |
| template <typename T> class BaseQ, |
| template <typename T> class BaseBQ> |
| StaticInstPtr |
| decodeNeonSAcrossLanesLongReg(bool q, unsigned size, ExtMachInst machInst, |
| IntRegIndex dest, IntRegIndex op1) |
| { |
| if (q) { |
| switch (size) { |
| case 0x0: |
| return new BaseQ<int8_t>(machInst, dest, op1); |
| case 0x1: |
| return new BaseQ<int16_t>(machInst, dest, op1); |
| case 0x2: |
| return new BaseBQ<int32_t>(machInst, dest, op1); |
| default: |
| return new Unknown(machInst); |
| } |
| } else { |
| switch (size) { |
| case 0x0: |
| return new BaseD<int8_t>(machInst, dest, op1); |
| case 0x1: |
| return new BaseD<int16_t>(machInst, dest, op1); |
| default: |
| return new Unknown(machInst); |
| } |
| } |
| } |
| }}; |
| |
| let {{ |
| header_output = "" |
| exec_output = "" |
| |
| vcompares = ''' |
| static float |
| vcgtFunc(float op1, float op2) |
| { |
| if (std::isnan(op1) || std::isnan(op2)) |
| return 2.0; |
| return (op1 > op2) ? 0.0 : 1.0; |
| } |
| |
| static float |
| vcgeFunc(float op1, float op2) |
| { |
| if (std::isnan(op1) || std::isnan(op2)) |
| return 2.0; |
| return (op1 >= op2) ? 0.0 : 1.0; |
| } |
| |
| static float |
| vceqFunc(float op1, float op2) |
| { |
| if (isSnan(op1) || isSnan(op2)) |
| return 2.0; |
| return (op1 == op2) ? 0.0 : 1.0; |
| } |
| ''' |
| vcomparesL = ''' |
| static float |
| vcleFunc(float op1, float op2) |
| { |
| if (std::isnan(op1) || std::isnan(op2)) |
| return 2.0; |
| return (op1 <= op2) ? 0.0 : 1.0; |
| } |
| |
| static float |
| vcltFunc(float op1, float op2) |
| { |
| if (std::isnan(op1) || std::isnan(op2)) |
| return 2.0; |
| return (op1 < op2) ? 0.0 : 1.0; |
| } |
| ''' |
| vacomparesG = ''' |
| static float |
| vacgtFunc(float op1, float op2) |
| { |
| if (std::isnan(op1) || std::isnan(op2)) |
| return 2.0; |
| return (fabsf(op1) > fabsf(op2)) ? 0.0 : 1.0; |
| } |
| |
| static float |
| vacgeFunc(float op1, float op2) |
| { |
| if (std::isnan(op1) || std::isnan(op2)) |
| return 2.0; |
| return (fabsf(op1) >= fabsf(op2)) ? 0.0 : 1.0; |
| } |
| ''' |
| |
| exec_output += vcompares + vacomparesG |
| |
| smallUnsignedTypes = ("uint8_t", "uint16_t", "uint32_t") |
| unsignedTypes = smallUnsignedTypes + ("uint64_t",) |
| smallSignedTypes = ("int8_t", "int16_t", "int32_t") |
| signedTypes = smallSignedTypes + ("int64_t",) |
| smallTypes = smallUnsignedTypes + smallSignedTypes |
| allTypes = unsignedTypes + signedTypes |
| |
| def threeEqualRegInst(name, Name, opClass, types, rCount, op, |
| readDest=False, pairwise=False, byElem=False, |
| standardFpcsr=False, complex=False, extra=''): |
| global header_output, exec_output |
| eWalkCode = simdEnabledCheckCode + ''' |
| RegVect srcReg1, destReg; |
| ''' |
| if byElem: |
| # 2nd register operand has to be read fully |
| eWalkCode += ''' |
| FullRegVect srcReg2; |
| ''' |
| else: |
| eWalkCode += ''' |
| RegVect srcReg2; |
| ''' |
| for reg in range(rCount): |
| eWalkCode += ''' |
| srcReg1.regs[%(reg)d] = htole(FpOp1P%(reg)d_uw); |
| srcReg2.regs[%(reg)d] = htole(FpOp2P%(reg)d_uw); |
| ''' % { "reg" : reg } |
| if readDest: |
| eWalkCode += ''' |
| destReg.regs[%(reg)d] = htole(FpDestP%(reg)d_uw); |
| ''' % { "reg" : reg } |
| if byElem: |
| # 2nd operand has to be read fully |
| for reg in range(rCount, 4): |
| eWalkCode += ''' |
| srcReg2.regs[%(reg)d] = htole(FpOp2P%(reg)d_uw); |
| ''' % { "reg" : reg } |
| |
| readDestCode = '' |
| if standardFpcsr: |
| eWalkCode += ''' |
| FPSCR fpscr = fpStandardFPSCRValue((FPSCR)FpscrExc); |
| ''' |
| if readDest: |
| readDestCode = 'destElem = letoh(destReg.elements[i]);' |
| |
| if complex: |
| eWalkCode += op |
| elif pairwise: |
| eWalkCode += ''' |
| for (unsigned i = 0; i < eCount; i++) { |
| Element srcElem1 = letoh(2 * i < eCount ? |
| srcReg1.elements[2 * i] : |
| srcReg2.elements[2 * i - eCount]); |
| Element srcElem2 = letoh(2 * i < eCount ? |
| srcReg1.elements[2 * i + 1] : |
| srcReg2.elements[2 * i + 1 - eCount]); |
| Element destElem; |
| %(readDest)s |
| %(op)s |
| destReg.elements[i] = htole(destElem); |
| } |
| ''' % { "op" : op, "readDest" : readDestCode } |
| else: |
| eWalkCode += extra |
| eWalkCode += ''' |
| for (unsigned i = 0; i < eCount; i++) { |
| Element srcElem1 = letoh(srcReg1.elements[i]); |
| Element srcElem2 = letoh(srcReg2.elements[i]); |
| Element destElem; |
| %(readDest)s |
| %(op)s |
| destReg.elements[i] = htole(destElem); |
| } |
| ''' % { "op" : op, "readDest" : readDestCode } |
| if standardFpcsr: |
| eWalkCode += ''' |
| FpscrExc = fpscr; |
| ''' |
| for reg in range(rCount): |
| eWalkCode += ''' |
| FpDestP%(reg)d_uw = letoh(destReg.regs[%(reg)d]); |
| ''' % { "reg" : reg } |
| iop = ArmInstObjParams(name, Name, |
| "RegRegRegImmOp" if byElem else "RegRegRegOp", |
| { "code": eWalkCode, |
| "r_count": rCount, |
| "predicate_test": predicateTest, |
| "op_class": opClass }, []) |
| if byElem: |
| header_output += NeonRegRegRegImmOpDeclare.subst(iop) |
| else: |
| header_output += NeonRegRegRegOpDeclare.subst(iop) |
| exec_output += NeonEqualRegExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonExecDeclare.subst(substDict) |
| |
| def threeEqualRegInstFp(name, Name, opClass, types, rCount, op, |
| readDest=False, pairwise=False, toInt=False): |
| global header_output, exec_output |
| eWalkCode = simdEnabledCheckCode + ''' |
| typedef float FloatVect[rCount]; |
| FloatVect srcRegs1, srcRegs2; |
| ''' |
| if toInt: |
| eWalkCode += 'RegVect destRegs;\n' |
| else: |
| eWalkCode += 'FloatVect destRegs;\n' |
| for reg in range(rCount): |
| eWalkCode += ''' |
| srcRegs1[%(reg)d] = FpOp1P%(reg)d; |
| srcRegs2[%(reg)d] = FpOp2P%(reg)d; |
| ''' % { "reg" : reg } |
| if readDest: |
| if toInt: |
| eWalkCode += ''' |
| destRegs.regs[%(reg)d] = FpDestP%(reg)d.bits; |
| ''' % { "reg" : reg } |
| else: |
| eWalkCode += ''' |
| destRegs[%(reg)d] = FpDestP%(reg)d; |
| ''' % { "reg" : reg } |
| readDestCode = '' |
| if readDest: |
| readDestCode = 'destReg = destRegs[r];' |
| destType = 'float' |
| writeDest = 'destRegs[r] = destReg;' |
| if toInt: |
| destType = 'uint32_t' |
| writeDest = 'destRegs.regs[r] = destReg;' |
| if pairwise: |
| eWalkCode += ''' |
| for (unsigned r = 0; r < rCount; r++) { |
| float srcReg1 = (2 * r < rCount) ? |
| srcRegs1[2 * r] : srcRegs2[2 * r - rCount]; |
| float srcReg2 = (2 * r < rCount) ? |
| srcRegs1[2 * r + 1] : srcRegs2[2 * r + 1 - rCount]; |
| %(destType)s destReg; |
| %(readDest)s |
| %(op)s |
| %(writeDest)s |
| } |
| ''' % { "op" : op, |
| "readDest" : readDestCode, |
| "destType" : destType, |
| "writeDest" : writeDest } |
| else: |
| eWalkCode += ''' |
| for (unsigned r = 0; r < rCount; r++) { |
| float srcReg1 = srcRegs1[r]; |
| float srcReg2 = srcRegs2[r]; |
| %(destType)s destReg; |
| %(readDest)s |
| %(op)s |
| %(writeDest)s |
| } |
| ''' % { "op" : op, |
| "readDest" : readDestCode, |
| "destType" : destType, |
| "writeDest" : writeDest } |
| for reg in range(rCount): |
| if toInt: |
| eWalkCode += ''' |
| FpDestP%(reg)d_uw = destRegs.regs[%(reg)d]; |
| ''' % { "reg" : reg } |
| else: |
| eWalkCode += ''' |
| FpDestP%(reg)d = destRegs[%(reg)d]; |
| ''' % { "reg" : reg } |
| iop = ArmInstObjParams(name, Name, |
| "FpRegRegRegOp", |
| { "code": eWalkCode, |
| "r_count": rCount, |
| "predicate_test": predicateTest, |
| "op_class": opClass }, []) |
| header_output += NeonRegRegRegOpDeclare.subst(iop) |
| exec_output += NeonEqualRegExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonExecDeclare.subst(substDict) |
| |
| def threeUnequalRegInst(name, Name, opClass, types, op, |
| bigSrc1, bigSrc2, bigDest, readDest): |
| global header_output, exec_output |
| src1Cnt = src2Cnt = destCnt = 2 |
| src1Prefix = src2Prefix = destPrefix = '' |
| if bigSrc1: |
| src1Cnt = 4 |
| src1Prefix = 'Big' |
| if bigSrc2: |
| src2Cnt = 4 |
| src2Prefix = 'Big' |
| if bigDest: |
| destCnt = 4 |
| destPrefix = 'Big' |
| eWalkCode = simdEnabledCheckCode + ''' |
| %sRegVect srcReg1; |
| %sRegVect srcReg2; |
| %sRegVect destReg; |
| ''' % (src1Prefix, src2Prefix, destPrefix) |
| for reg in range(src1Cnt): |
| eWalkCode += ''' |
| srcReg1.regs[%(reg)d] = htole(FpOp1P%(reg)d_uw); |
| ''' % { "reg" : reg } |
| for reg in range(src2Cnt): |
| eWalkCode += ''' |
| srcReg2.regs[%(reg)d] = htole(FpOp2P%(reg)d_uw); |
| ''' % { "reg" : reg } |
| if readDest: |
| for reg in range(destCnt): |
| eWalkCode += ''' |
| destReg.regs[%(reg)d] = htole(FpDestP%(reg)d_uw); |
| ''' % { "reg" : reg } |
| readDestCode = '' |
| if readDest: |
| readDestCode = 'destElem = letoh(destReg.elements[i]);' |
| eWalkCode += ''' |
| for (unsigned i = 0; i < eCount; i++) { |
| %(src1Prefix)sElement srcElem1 = letoh(srcReg1.elements[i]); |
| %(src1Prefix)sElement srcElem2 = letoh(srcReg2.elements[i]); |
| %(destPrefix)sElement destElem; |
| %(readDest)s |
| %(op)s |
| destReg.elements[i] = htole(destElem); |
| } |
| ''' % { "op" : op, "readDest" : readDestCode, |
| "src1Prefix" : src1Prefix, "src2Prefix" : src2Prefix, |
| "destPrefix" : destPrefix } |
| for reg in range(destCnt): |
| eWalkCode += ''' |
| FpDestP%(reg)d_uw = letoh(destReg.regs[%(reg)d]); |
| ''' % { "reg" : reg } |
| iop = ArmInstObjParams(name, Name, |
| "RegRegRegOp", |
| { "code": eWalkCode, |
| "r_count": 2, |
| "predicate_test": predicateTest, |
| "op_class": opClass }, []) |
| header_output += NeonRegRegRegOpDeclare.subst(iop) |
| exec_output += NeonUnequalRegExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonExecDeclare.subst(substDict) |
| |
| def threeRegNarrowInst(name, Name, opClass, types, op, readDest=False): |
| threeUnequalRegInst(name, Name, opClass, types, op, |
| True, True, False, readDest) |
| |
| def threeRegLongInst(name, Name, opClass, types, op, readDest=False): |
| threeUnequalRegInst(name, Name, opClass, types, op, |
| False, False, True, readDest) |
| |
| def threeRegWideInst(name, Name, opClass, types, op, readDest=False): |
| threeUnequalRegInst(name, Name, opClass, types, op, |
| True, False, True, readDest) |
| |
| def twoEqualRegInst(name, Name, opClass, types, rCount, op, |
| readDest=False, extra=''): |
| global header_output, exec_output |
| eWalkCode = simdEnabledCheckCode + ''' |
| RegVect srcReg1, srcReg2, destReg; |
| ''' |
| for reg in range(rCount): |
| eWalkCode += ''' |
| srcReg1.regs[%(reg)d] = htole(FpOp1P%(reg)d_uw); |
| srcReg2.regs[%(reg)d] = htole(FpOp2P%(reg)d_uw); |
| ''' % { "reg" : reg } |
| if readDest: |
| eWalkCode += ''' |
| destReg.regs[%(reg)d] = htole(FpDestP%(reg)d_uw); |
| ''' % { "reg" : reg } |
| readDestCode = '' |
| if readDest: |
| readDestCode = 'destElem = letoh(destReg.elements[i]);' |
| eWalkCode += extra |
| eWalkCode += ''' |
| if (imm >= eCount) { |
| return std::make_shared<UndefinedInstruction>(machInst, false, |
| mnemonic); |
| } else { |
| for (unsigned i = 0; i < eCount; i++) { |
| Element srcElem1 = letoh(srcReg1.elements[i]); |
| Element srcElem2 = letoh(srcReg2.elements[imm]); |
| Element destElem; |
| %(readDest)s |
| %(op)s |
| destReg.elements[i] = htole(destElem); |
| } |
| } |
| ''' % { "op" : op, "readDest" : readDestCode } |
| for reg in range(rCount): |
| eWalkCode += ''' |
| FpDestP%(reg)d_uw = letoh(destReg.regs[%(reg)d]); |
| ''' % { "reg" : reg } |
| iop = ArmInstObjParams(name, Name, |
| "RegRegRegImmOp", |
| { "code": eWalkCode, |
| "r_count": rCount, |
| "predicate_test": predicateTest, |
| "op_class": opClass }, []) |
| header_output += NeonRegRegRegImmOpDeclare.subst(iop) |
| exec_output += NeonEqualRegExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonExecDeclare.subst(substDict) |
| |
| def twoRegLongInst(name, Name, opClass, types, op, readDest=False): |
| global header_output, exec_output |
| rCount = 2 |
| eWalkCode = simdEnabledCheckCode + ''' |
| RegVect srcReg1, srcReg2; |
| BigRegVect destReg = {}; |
| ''' |
| for reg in range(rCount): |
| eWalkCode += ''' |
| srcReg1.regs[%(reg)d] = htole(FpOp1P%(reg)d_uw); |
| srcReg2.regs[%(reg)d] = htole(FpOp2P%(reg)d_uw);; |
| ''' % { "reg" : reg } |
| if readDest: |
| for reg in range(2 * rCount): |
| eWalkCode += ''' |
| destReg.regs[%(reg)d] = htole(FpDestP%(reg)d_uw); |
| ''' % { "reg" : reg } |
| readDestCode = '' |
| if readDest: |
| readDestCode = 'destElem = letoh(destReg.elements[i]);' |
| eWalkCode += ''' |
| if (imm >= eCount) { |
| fault = std::make_shared<UndefinedInstruction>(machInst, false, |
| mnemonic); |
| } else { |
| for (unsigned i = 0; i < eCount; i++) { |
| Element srcElem1 = letoh(srcReg1.elements[i]); |
| Element srcElem2 = letoh(srcReg2.elements[imm]); |
| BigElement destElem; |
| %(readDest)s |
| %(op)s |
| destReg.elements[i] = htole(destElem); |
| } |
| } |
| ''' % { "op" : op, "readDest" : readDestCode } |
| for reg in range(2 * rCount): |
| eWalkCode += ''' |
| FpDestP%(reg)d_uw = letoh(destReg.regs[%(reg)d]); |
| ''' % { "reg" : reg } |
| iop = ArmInstObjParams(name, Name, |
| "RegRegRegImmOp", |
| { "code": eWalkCode, |
| "r_count": rCount, |
| "predicate_test": predicateTest, |
| "op_class": opClass }, []) |
| header_output += NeonRegRegRegImmOpDeclare.subst(iop) |
| exec_output += NeonUnequalRegExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonExecDeclare.subst(substDict) |
| |
| def twoEqualRegInstFp(name, Name, opClass, types, rCount, op, readDest=False): |
| global header_output, exec_output |
| eWalkCode = simdEnabledCheckCode + ''' |
| typedef float FloatVect[rCount]; |
| FloatVect srcRegs1, srcRegs2, destRegs; |
| ''' |
| for reg in range(rCount): |
| eWalkCode += ''' |
| srcRegs1[%(reg)d] = FpOp1P%(reg)d; |
| srcRegs2[%(reg)d] = FpOp2P%(reg)d; |
| ''' % { "reg" : reg } |
| if readDest: |
| eWalkCode += ''' |
| destRegs[%(reg)d] = FpDestP%(reg)d; |
| ''' % { "reg" : reg } |
| readDestCode = '' |
| if readDest: |
| readDestCode = 'destReg = destRegs[i];' |
| eWalkCode += ''' |
| if (imm >= eCount) { |
| return std::make_shared<UndefinedInstruction>(machInst, false, |
| mnemonic); |
| } else { |
| for (unsigned i = 0; i < rCount; i++) { |
| float srcReg1 = srcRegs1[i]; |
| float srcReg2 = srcRegs2[imm]; |
| float destReg; |
| %(readDest)s |
| %(op)s |
| destRegs[i] = destReg; |
| } |
| } |
| ''' % { "op" : op, "readDest" : readDestCode } |
| for reg in range(rCount): |
| eWalkCode += ''' |
| FpDestP%(reg)d = destRegs[%(reg)d]; |
| ''' % { "reg" : reg } |
| iop = ArmInstObjParams(name, Name, |
| "FpRegRegRegImmOp", |
| { "code": eWalkCode, |
| "r_count": rCount, |
| "predicate_test": predicateTest, |
| "op_class": opClass }, []) |
| header_output += NeonRegRegRegImmOpDeclare.subst(iop) |
| exec_output += NeonEqualRegExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonExecDeclare.subst(substDict) |
| |
| def twoRegShiftInst(name, Name, opClass, types, rCount, op, |
| readDest=False, toInt=False, fromInt=False): |
| global header_output, exec_output |
| eWalkCode = simdEnabledCheckCode + ''' |
| RegVect srcRegs1, destRegs; |
| ''' |
| for reg in range(rCount): |
| eWalkCode += ''' |
| srcRegs1.regs[%(reg)d] = htole(FpOp1P%(reg)d_uw); |
| ''' % { "reg" : reg } |
| if readDest: |
| eWalkCode += ''' |
| destRegs.regs[%(reg)d] = htole(FpDestP%(reg)d_uw); |
| ''' % { "reg" : reg } |
| readDestCode = '' |
| if readDest: |
| readDestCode = 'destElem = letoh(destRegs.elements[i]);' |
| if toInt: |
| readDestCode = 'destReg = letoh(destRegs.regs[i]);' |
| readOpCode = 'Element srcElem1 = letoh(srcRegs1.elements[i]);' |
| if fromInt: |
| readOpCode = 'uint32_t srcReg1 = letoh(srcRegs1.regs[i]);' |
| declDest = 'Element destElem;' |
| writeDestCode = 'destRegs.elements[i] = htole(destElem);' |
| if toInt: |
| declDest = 'uint32_t destReg;' |
| writeDestCode = 'destRegs.regs[i] = htole(destReg);' |
| eWalkCode += ''' |
| for (unsigned i = 0; i < eCount; i++) { |
| %(readOp)s |
| %(declDest)s |
| %(readDest)s |
| %(op)s |
| %(writeDest)s |
| } |
| ''' % { "readOp" : readOpCode, |
| "declDest" : declDest, |
| "readDest" : readDestCode, |
| "op" : op, |
| "writeDest" : writeDestCode } |
| for reg in range(rCount): |
| eWalkCode += ''' |
| FpDestP%(reg)d_uw = letoh(destRegs.regs[%(reg)d]); |
| ''' % { "reg" : reg } |
| iop = ArmInstObjParams(name, Name, |
| "RegRegImmOp", |
| { "code": eWalkCode, |
| "r_count": rCount, |
| "predicate_test": predicateTest, |
| "op_class": opClass }, []) |
| header_output += NeonRegRegImmOpDeclare.subst(iop) |
| exec_output += NeonEqualRegExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonExecDeclare.subst(substDict) |
| |
| def twoRegNarrowShiftInst(name, Name, opClass, types, op, readDest=False): |
| global header_output, exec_output |
| eWalkCode = simdEnabledCheckCode + ''' |
| BigRegVect srcReg1; |
| RegVect destReg; |
| ''' |
| for reg in range(4): |
| eWalkCode += ''' |
| srcReg1.regs[%(reg)d] = htole(FpOp1P%(reg)d_uw); |
| ''' % { "reg" : reg } |
| if readDest: |
| for reg in range(2): |
| eWalkCode += ''' |
| destReg.regs[%(reg)d] = htole(FpDestP%(reg)d_uw); |
| ''' % { "reg" : reg } |
| readDestCode = '' |
| if readDest: |
| readDestCode = 'destElem = letoh(destReg.elements[i]);' |
| eWalkCode += ''' |
| for (unsigned i = 0; i < eCount; i++) { |
| BigElement srcElem1 = letoh(srcReg1.elements[i]); |
| Element destElem; |
| %(readDest)s |
| %(op)s |
| destReg.elements[i] = htole(destElem); |
| } |
| ''' % { "op" : op, "readDest" : readDestCode } |
| for reg in range(2): |
| eWalkCode += ''' |
| FpDestP%(reg)d_uw = letoh(destReg.regs[%(reg)d]); |
| ''' % { "reg" : reg } |
| iop = ArmInstObjParams(name, Name, |
| "RegRegImmOp", |
| { "code": eWalkCode, |
| "r_count": 2, |
| "predicate_test": predicateTest, |
| "op_class": opClass }, []) |
| header_output += NeonRegRegImmOpDeclare.subst(iop) |
| exec_output += NeonUnequalRegExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonExecDeclare.subst(substDict) |
| |
| def twoRegLongShiftInst(name, Name, opClass, types, op, readDest=False): |
| global header_output, exec_output |
| eWalkCode = simdEnabledCheckCode + ''' |
| RegVect srcReg1; |
| BigRegVect destReg = {}; |
| ''' |
| for reg in range(2): |
| eWalkCode += ''' |
| srcReg1.regs[%(reg)d] = htole(FpOp1P%(reg)d_uw); |
| ''' % { "reg" : reg } |
| if readDest: |
| for reg in range(4): |
| eWalkCode += ''' |
| destReg.regs[%(reg)d] = htole(FpDestP%(reg)d_uw); |
| ''' % { "reg" : reg } |
| readDestCode = '' |
| if readDest: |
| readDestCode = 'destReg = letoh(destReg.elements[i]);' |
| eWalkCode += ''' |
| for (unsigned i = 0; i < eCount; i++) { |
| Element srcElem1 = letoh(srcReg1.elements[i]); |
| BigElement destElem; |
| %(readDest)s |
| %(op)s |
| destReg.elements[i] = htole(destElem); |
| } |
| ''' % { "op" : op, "readDest" : readDestCode } |
| for reg in range(4): |
| eWalkCode += ''' |
| FpDestP%(reg)d_uw = letoh(destReg.regs[%(reg)d]); |
| ''' % { "reg" : reg } |
| iop = ArmInstObjParams(name, Name, |
| "RegRegImmOp", |
| { "code": eWalkCode, |
| "r_count": 2, |
| "predicate_test": predicateTest, |
| "op_class": opClass }, []) |
| header_output += NeonRegRegImmOpDeclare.subst(iop) |
| exec_output += NeonUnequalRegExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonExecDeclare.subst(substDict) |
| |
| def twoRegMiscInst(name, Name, opClass, types, rCount, op, readDest=False): |
| global header_output, exec_output |
| eWalkCode = simdEnabledCheckCode + ''' |
| RegVect srcReg1, destReg; |
| ''' |
| for reg in range(rCount): |
| eWalkCode += ''' |
| srcReg1.regs[%(reg)d] = htole(FpOp1P%(reg)d_uw); |
| ''' % { "reg" : reg } |
| if readDest: |
| eWalkCode += ''' |
| destReg.regs[%(reg)d] = htole(FpDestP%(reg)d_uw); |
| ''' % { "reg" : reg } |
| readDestCode = '' |
| if readDest: |
| readDestCode = 'destElem = letoh(destReg.elements[i]);' |
| eWalkCode += ''' |
| for (unsigned i = 0; i < eCount; i++) { |
| unsigned j = i; |
| Element srcElem1 = letoh(srcReg1.elements[i]); |
| Element destElem; |
| %(readDest)s |
| %(op)s |
| destReg.elements[j] = htole(destElem); |
| } |
| ''' % { "op" : op, "readDest" : readDestCode } |
| for reg in range(rCount): |
| eWalkCode += ''' |
| FpDestP%(reg)d_uw = letoh(destReg.regs[%(reg)d]); |
| ''' % { "reg" : reg } |
| iop = ArmInstObjParams(name, Name, |
| "RegRegOp", |
| { "code": eWalkCode, |
| "r_count": rCount, |
| "predicate_test": predicateTest, |
| "op_class": opClass }, []) |
| header_output += NeonRegRegOpDeclare.subst(iop) |
| exec_output += NeonEqualRegExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonExecDeclare.subst(substDict) |
| |
| def twoRegMiscScInst(name, Name, opClass, types, rCount, op, readDest=False): |
| global header_output, exec_output |
| eWalkCode = simdEnabledCheckCode + ''' |
| RegVect srcReg1, destReg; |
| ''' |
| for reg in range(rCount): |
| eWalkCode += ''' |
| srcReg1.regs[%(reg)d] = htole(FpOp1P%(reg)d_uw); |
| ''' % { "reg" : reg } |
| if readDest: |
| eWalkCode += ''' |
| destReg.regs[%(reg)d] = htole(FpDestP%(reg)d_uw); |
| ''' % { "reg" : reg } |
| readDestCode = '' |
| if readDest: |
| readDestCode = 'destElem = letoh(destReg.elements[i]);' |
| eWalkCode += ''' |
| for (unsigned i = 0; i < eCount; i++) { |
| Element srcElem1 = letoh(srcReg1.elements[imm]); |
| Element destElem; |
| %(readDest)s |
| %(op)s |
| destReg.elements[i] = htole(destElem); |
| } |
| ''' % { "op" : op, "readDest" : readDestCode } |
| for reg in range(rCount): |
| eWalkCode += ''' |
| FpDestP%(reg)d_uw = letoh(destReg.regs[%(reg)d]); |
| ''' % { "reg" : reg } |
| iop = ArmInstObjParams(name, Name, |
| "RegRegImmOp", |
| { "code": eWalkCode, |
| "r_count": rCount, |
| "predicate_test": predicateTest, |
| "op_class": opClass }, []) |
| header_output += NeonRegRegImmOpDeclare.subst(iop) |
| exec_output += NeonEqualRegExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonExecDeclare.subst(substDict) |
| |
| def twoRegMiscScramble(name, Name, opClass, types, rCount, op, readDest=False): |
| global header_output, exec_output |
| eWalkCode = simdEnabledCheckCode + ''' |
| RegVect srcReg1, destReg; |
| ''' |
| for reg in range(rCount): |
| eWalkCode += ''' |
| srcReg1.regs[%(reg)d] = htole(FpOp1P%(reg)d_uw); |
| destReg.regs[%(reg)d] = htole(FpDestP%(reg)d_uw); |
| ''' % { "reg" : reg } |
| if readDest: |
| eWalkCode += ''' |
| ''' % { "reg" : reg } |
| readDestCode = '' |
| if readDest: |
| readDestCode = 'destElem = letoh(destReg.elements[i]);' |
| eWalkCode += op |
| for reg in range(rCount): |
| eWalkCode += ''' |
| FpDestP%(reg)d_uw = letoh(destReg.regs[%(reg)d]); |
| FpOp1P%(reg)d_uw = letoh(srcReg1.regs[%(reg)d]); |
| ''' % { "reg" : reg } |
| iop = ArmInstObjParams(name, Name, |
| "RegRegOp", |
| { "code": eWalkCode, |
| "r_count": rCount, |
| "predicate_test": predicateTest, |
| "op_class": opClass }, []) |
| header_output += NeonRegRegOpDeclare.subst(iop) |
| exec_output += NeonEqualRegExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonExecDeclare.subst(substDict) |
| |
| def twoRegMiscInstFp(name, Name, opClass, types, rCount, op, |
| readDest=False, toInt=False): |
| global header_output, exec_output |
| eWalkCode = simdEnabledCheckCode + ''' |
| typedef float FloatVect[rCount]; |
| FloatVect srcRegs1; |
| ''' |
| if toInt: |
| eWalkCode += 'RegVect destRegs;\n' |
| else: |
| eWalkCode += 'FloatVect destRegs;\n' |
| for reg in range(rCount): |
| eWalkCode += ''' |
| srcRegs1[%(reg)d] = FpOp1P%(reg)d; |
| ''' % { "reg" : reg } |
| if readDest: |
| if toInt: |
| eWalkCode += ''' |
| destRegs.regs[%(reg)d] = FpDestP%(reg)d.bits; |
| ''' % { "reg" : reg } |
| else: |
| eWalkCode += ''' |
| destRegs[%(reg)d] = FpDestP%(reg)d; |
| ''' % { "reg" : reg } |
| readDestCode = '' |
| if readDest: |
| readDestCode = 'destReg = destRegs[i];' |
| destType = 'float' |
| writeDest = 'destRegs[r] = destReg;' |
| if toInt: |
| destType = 'uint32_t' |
| writeDest = 'destRegs.regs[r] = destReg;' |
| eWalkCode += ''' |
| for (unsigned r = 0; r < rCount; r++) { |
| float srcReg1 = srcRegs1[r]; |
| %(destType)s destReg; |
| %(readDest)s |
| %(op)s |
| %(writeDest)s |
| } |
| ''' % { "op" : op, |
| "readDest" : readDestCode, |
| "destType" : destType, |
| "writeDest" : writeDest } |
| for reg in range(rCount): |
| if toInt: |
| eWalkCode += ''' |
| FpDestP%(reg)d_uw = destRegs.regs[%(reg)d]; |
| ''' % { "reg" : reg } |
| else: |
| eWalkCode += ''' |
| FpDestP%(reg)d = destRegs[%(reg)d]; |
| ''' % { "reg" : reg } |
| iop = ArmInstObjParams(name, Name, |
| "FpRegRegOp", |
| { "code": eWalkCode, |
| "r_count": rCount, |
| "predicate_test": predicateTest, |
| "op_class": opClass }, []) |
| header_output += NeonRegRegOpDeclare.subst(iop) |
| exec_output += NeonEqualRegExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonExecDeclare.subst(substDict) |
| |
| def twoRegCondenseInst(name, Name, opClass, types, rCount, op, readDest=False): |
| global header_output, exec_output |
| eWalkCode = simdEnabledCheckCode + ''' |
| RegVect srcRegs; |
| BigRegVect destReg = {}; |
| ''' |
| for reg in range(rCount): |
| eWalkCode += ''' |
| srcRegs.regs[%(reg)d] = htole(FpOp1P%(reg)d_uw); |
| ''' % { "reg" : reg } |
| if readDest: |
| eWalkCode += ''' |
| destReg.regs[%(reg)d] = htole(FpDestP%(reg)d_uw); |
| ''' % { "reg" : reg } |
| readDestCode = '' |
| if readDest: |
| readDestCode = 'destElem = letoh(destReg.elements[i]);' |
| eWalkCode += ''' |
| for (unsigned i = 0; i < eCount / 2; i++) { |
| Element srcElem1 = letoh(srcRegs.elements[2 * i]); |
| Element srcElem2 = letoh(srcRegs.elements[2 * i + 1]); |
| BigElement destElem; |
| %(readDest)s |
| %(op)s |
| destReg.elements[i] = htole(destElem); |
| } |
| ''' % { "op" : op, "readDest" : readDestCode } |
| for reg in range(rCount): |
| eWalkCode += ''' |
| FpDestP%(reg)d_uw = letoh(destReg.regs[%(reg)d]); |
| ''' % { "reg" : reg } |
| iop = ArmInstObjParams(name, Name, |
| "RegRegOp", |
| { "code": eWalkCode, |
| "r_count": rCount, |
| "predicate_test": predicateTest, |
| "op_class": opClass }, []) |
| header_output += NeonRegRegOpDeclare.subst(iop) |
| exec_output += NeonUnequalRegExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonExecDeclare.subst(substDict) |
| |
| def twoRegNarrowMiscInst(name, Name, opClass, types, op, readDest=False): |
| global header_output, exec_output |
| eWalkCode = simdEnabledCheckCode + ''' |
| BigRegVect srcReg1; |
| RegVect destReg; |
| ''' |
| for reg in range(4): |
| eWalkCode += ''' |
| srcReg1.regs[%(reg)d] = htole(FpOp1P%(reg)d_uw); |
| ''' % { "reg" : reg } |
| if readDest: |
| for reg in range(2): |
| eWalkCode += ''' |
| destReg.regs[%(reg)d] = htole(FpDestP%(reg)d_uw); |
| ''' % { "reg" : reg } |
| readDestCode = '' |
| if readDest: |
| readDestCode = 'destElem = letoh(destReg.elements[i]);' |
| eWalkCode += ''' |
| for (unsigned i = 0; i < eCount; i++) { |
| BigElement srcElem1 = letoh(srcReg1.elements[i]); |
| Element destElem; |
| %(readDest)s |
| %(op)s |
| destReg.elements[i] = htole(destElem); |
| } |
| ''' % { "op" : op, "readDest" : readDestCode } |
| for reg in range(2): |
| eWalkCode += ''' |
| FpDestP%(reg)d_uw = letoh(destReg.regs[%(reg)d]); |
| ''' % { "reg" : reg } |
| iop = ArmInstObjParams(name, Name, |
| "RegRegOp", |
| { "code": eWalkCode, |
| "r_count": 2, |
| "predicate_test": predicateTest, |
| "op_class": opClass }, []) |
| header_output += NeonRegRegOpDeclare.subst(iop) |
| exec_output += NeonUnequalRegExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonExecDeclare.subst(substDict) |
| |
| def oneRegImmInst(name, Name, opClass, types, rCount, op, readDest=False): |
| global header_output, exec_output |
| eWalkCode = simdEnabledCheckCode + ''' |
| RegVect destReg; |
| ''' |
| if readDest: |
| for reg in range(rCount): |
| eWalkCode += ''' |
| destReg.regs[%(reg)d] = htole(FpDestP%(reg)d_uw); |
| ''' % { "reg" : reg } |
| readDestCode = '' |
| if readDest: |
| readDestCode = 'destElem = letoh(destReg.elements[i]);' |
| eWalkCode += ''' |
| for (unsigned i = 0; i < eCount; i++) { |
| Element destElem; |
| %(readDest)s |
| %(op)s |
| destReg.elements[i] = htole(destElem); |
| } |
| ''' % { "op" : op, "readDest" : readDestCode } |
| for reg in range(rCount): |
| eWalkCode += ''' |
| FpDestP%(reg)d_uw = letoh(destReg.regs[%(reg)d]); |
| ''' % { "reg" : reg } |
| iop = ArmInstObjParams(name, Name, |
| "RegImmOp", |
| { "code": eWalkCode, |
| "r_count": rCount, |
| "predicate_test": predicateTest, |
| "op_class": opClass }, []) |
| header_output += NeonRegImmOpDeclare.subst(iop) |
| exec_output += NeonEqualRegExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonExecDeclare.subst(substDict) |
| |
| def twoRegLongMiscInst(name, Name, opClass, types, op, readDest=False): |
| global header_output, exec_output |
| eWalkCode = simdEnabledCheckCode + ''' |
| RegVect srcReg1; |
| BigRegVect destReg = {}; |
| ''' |
| for reg in range(2): |
| eWalkCode += ''' |
| srcReg1.regs[%(reg)d] = htole(FpOp1P%(reg)d_uw); |
| ''' % { "reg" : reg } |
| if readDest: |
| for reg in range(4): |
| eWalkCode += ''' |
| destReg.regs[%(reg)d] = htole(FpDestP%(reg)d_uw); |
| ''' % { "reg" : reg } |
| readDestCode = '' |
| if readDest: |
| readDestCode = 'destReg = letoh(destReg.elements[i]);' |
| eWalkCode += ''' |
| for (unsigned i = 0; i < eCount; i++) { |
| Element srcElem1 = letoh(srcReg1.elements[i]); |
| BigElement destElem; |
| %(readDest)s |
| %(op)s |
| destReg.elements[i] = htole(destElem); |
| } |
| ''' % { "op" : op, "readDest" : readDestCode } |
| for reg in range(4): |
| eWalkCode += ''' |
| FpDestP%(reg)d_uw = letoh(destReg.regs[%(reg)d]); |
| ''' % { "reg" : reg } |
| iop = ArmInstObjParams(name, Name, |
| "RegRegOp", |
| { "code": eWalkCode, |
| "r_count": 2, |
| "predicate_test": predicateTest, |
| "op_class": opClass }, []) |
| header_output += NeonRegRegOpDeclare.subst(iop) |
| exec_output += NeonUnequalRegExecute.subst(iop) |
| for type in types: |
| substDict = { "targs" : type, |
| "class_name" : Name } |
| exec_output += NeonExecDeclare.subst(substDict) |
| |
| vhaddCode = ''' |
| Element carryBit = |
| (((unsigned)srcElem1 & 0x1) + |
| ((unsigned)srcElem2 & 0x1)) >> 1; |
| // Use division instead of a shift to ensure the sign extension works |
| // right. The compiler will figure out if it can be a shift. Mask the |
| // inputs so they get truncated correctly. |
| destElem = (((srcElem1 & ~(Element)1) / 2) + |
| ((srcElem2 & ~(Element)1) / 2)) + carryBit; |
| ''' |
| threeEqualRegInst("vhadd", "VhaddD", "SimdAddOp", allTypes, 2, vhaddCode) |
| threeEqualRegInst("vhadd", "VhaddQ", "SimdAddOp", allTypes, 4, vhaddCode) |
| |
| vrhaddCode = ''' |
| Element carryBit = |
| (((unsigned)srcElem1 & 0x1) + |
| ((unsigned)srcElem2 & 0x1) + 1) >> 1; |
| // Use division instead of a shift to ensure the sign extension works |
| // right. The compiler will figure out if it can be a shift. Mask the |
| // inputs so they get truncated correctly. |
| destElem = (((srcElem1 & ~(Element)1) / 2) + |
| ((srcElem2 & ~(Element)1) / 2)) + carryBit; |
| ''' |
| threeEqualRegInst("vrhadd", "VrhaddD", "SimdAddOp", allTypes, 2, vrhaddCode) |
| threeEqualRegInst("vrhadd", "VrhaddQ", "SimdAddOp", allTypes, 4, vrhaddCode) |
| |
| vhsubCode = ''' |
| Element barrowBit = |
| (((srcElem1 & 0x1) - (srcElem2 & 0x1)) >> 1) & 0x1; |
| // Use division instead of a shift to ensure the sign extension works |
| // right. The compiler will figure out if it can be a shift. Mask the |
| // inputs so they get truncated correctly. |
| destElem = (((srcElem1 & ~(Element)1) / 2) - |
| ((srcElem2 & ~(Element)1) / 2)) - barrowBit; |
| ''' |
| threeEqualRegInst("vhsub", "VhsubD", "SimdAddOp", allTypes, 2, vhsubCode) |
| threeEqualRegInst("vhsub", "VhsubQ", "SimdAddOp", allTypes, 4, vhsubCode) |
| |
| vandCode = ''' |
| destElem = srcElem1 & srcElem2; |
| ''' |
| threeEqualRegInst("vand", "VandD", "SimdAluOp", unsignedTypes, 2, vandCode) |
| threeEqualRegInst("vand", "VandQ", "SimdAluOp", unsignedTypes, 4, vandCode) |
| |
| vbicCode = ''' |
| destElem = srcElem1 & ~srcElem2; |
| ''' |
| threeEqualRegInst("vbic", "VbicD", "SimdAluOp", unsignedTypes, 2, vbicCode) |
| threeEqualRegInst("vbic", "VbicQ", "SimdAluOp", unsignedTypes, 4, vbicCode) |
| |
| vorrCode = ''' |
| destElem = srcElem1 | srcElem2; |
| ''' |
| threeEqualRegInst("vorr", "VorrD", "SimdAluOp", unsignedTypes, 2, vorrCode) |
| threeEqualRegInst("vorr", "VorrQ", "SimdAluOp", unsignedTypes, 4, vorrCode) |
| |
| threeEqualRegInst("vmov", "VmovD", "SimdMiscOp", unsignedTypes, 2, vorrCode) |
| threeEqualRegInst("vmov", "VmovQ", "SimdMiscOp", unsignedTypes, 4, vorrCode) |
| |
| vornCode = ''' |
| destElem = srcElem1 | ~srcElem2; |
| ''' |
| threeEqualRegInst("vorn", "VornD", "SimdAluOp", unsignedTypes, 2, vornCode) |
| threeEqualRegInst("vorn", "VornQ", "SimdAluOp", unsignedTypes, 4, vornCode) |
| |
| veorCode = ''' |
| destElem = srcElem1 ^ srcElem2; |
| ''' |
| threeEqualRegInst("veor", "VeorD", "SimdAluOp", unsignedTypes, 2, veorCode) |
| threeEqualRegInst("veor", "VeorQ", "SimdAluOp", unsignedTypes, 4, veorCode) |
| |
| vbifCode = ''' |
| destElem = (destElem & srcElem2) | (srcElem1 & ~srcElem2); |
| ''' |
| threeEqualRegInst("vbif", "VbifD", "SimdAluOp", unsignedTypes, 2, vbifCode, True) |
| threeEqualRegInst("vbif", "VbifQ", "SimdAluOp", unsignedTypes, 4, vbifCode, True) |
| vbitCode = ''' |
| destElem = (srcElem1 & srcElem2) | (destElem & ~srcElem2); |
| ''' |
| threeEqualRegInst("vbit", "VbitD", "SimdAluOp", unsignedTypes, 2, vbitCode, True) |
| threeEqualRegInst("vbit", "VbitQ", "SimdAluOp", unsignedTypes, 4, vbitCode, True) |
| vbslCode = ''' |
| destElem = (srcElem1 & destElem) | (srcElem2 & ~destElem); |
| ''' |
| threeEqualRegInst("vbsl", "VbslD", "SimdAluOp", unsignedTypes, 2, vbslCode, True) |
| threeEqualRegInst("vbsl", "VbslQ", "SimdAluOp", unsignedTypes, 4, vbslCode, True) |
| |
| vmaxCode = ''' |
| destElem = (srcElem1 > srcElem2) ? srcElem1 : srcElem2; |
| ''' |
| threeEqualRegInst("vmax", "VmaxD", "SimdCmpOp", allTypes, 2, vmaxCode) |
| threeEqualRegInst("vmax", "VmaxQ", "SimdCmpOp", allTypes, 4, vmaxCode) |
| |
| vminCode = ''' |
| destElem = (srcElem1 < srcElem2) ? srcElem1 : srcElem2; |
| ''' |
| threeEqualRegInst("vmin", "VminD", "SimdCmpOp", allTypes, 2, vminCode) |
| threeEqualRegInst("vmin", "VminQ", "SimdCmpOp", allTypes, 4, vminCode) |
| |
| vaddCode = ''' |
| destElem = srcElem1 + srcElem2; |
| ''' |
| threeEqualRegInst("vadd", "NVaddD", "SimdAddOp", unsignedTypes, 2, vaddCode) |
| threeEqualRegInst("vadd", "NVaddQ", "SimdAddOp", unsignedTypes, 4, vaddCode) |
| |
| threeEqualRegInst("vpadd", "NVpaddD", "SimdAddOp", smallUnsignedTypes, |
| 2, vaddCode, pairwise=True) |
| vaddlwCode = ''' |
| destElem = (BigElement)srcElem1 + (BigElement)srcElem2; |
| ''' |
| threeRegLongInst("vaddl", "Vaddl", "SimdAddOp", smallTypes, vaddlwCode) |
| threeRegWideInst("vaddw", "Vaddw", "SimdAddOp", smallTypes, vaddlwCode) |
| vaddhnCode = ''' |
| destElem = ((BigElement)srcElem1 + (BigElement)srcElem2) >> |
| (sizeof(Element) * 8); |
| ''' |
| threeRegNarrowInst("vaddhn", "Vaddhn", "SimdAddOp", smallTypes, vaddhnCode) |
| vraddhnCode = ''' |
| destElem = ((BigElement)srcElem1 + (BigElement)srcElem2 + |
| ((BigElement)1 << (sizeof(Element) * 8 - 1))) >> |
| (sizeof(Element) * 8); |
| ''' |
| threeRegNarrowInst("vraddhn", "Vraddhn", "SimdAddOp", smallTypes, vraddhnCode) |
| |
| vsubCode = ''' |
| destElem = srcElem1 - srcElem2; |
| ''' |
| threeEqualRegInst("vsub", "NVsubD", "SimdAddOp", unsignedTypes, 2, vsubCode) |
| threeEqualRegInst("vsub", "NVsubQ", "SimdAddOp", unsignedTypes, 4, vsubCode) |
| vsublwCode = ''' |
| destElem = (BigElement)srcElem1 - (BigElement)srcElem2; |
| ''' |
| threeRegLongInst("vsubl", "Vsubl", "SimdAddOp", smallTypes, vsublwCode) |
| threeRegWideInst("vsubw", "Vsubw", "SimdAddOp", smallTypes, vsublwCode) |
| |
| vqaddUCode = ''' |
| destElem = srcElem1 + srcElem2; |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| if (destElem < srcElem1 || destElem < srcElem2) { |
| destElem = (Element)(-1); |
| fpscr.qc = 1; |
| } |
| FpscrQc = fpscr; |
| ''' |
| threeEqualRegInst("vqadd", "VqaddUD", "SimdAddOp", unsignedTypes, 2, vqaddUCode) |
| threeEqualRegInst("vqadd", "VqaddUQ", "SimdAddOp", unsignedTypes, 4, vqaddUCode) |
| vsubhnCode = ''' |
| destElem = ((BigElement)srcElem1 - (BigElement)srcElem2) >> |
| (sizeof(Element) * 8); |
| ''' |
| threeRegNarrowInst("vsubhn", "Vsubhn", "SimdAddOp", smallTypes, vsubhnCode) |
| vrsubhnCode = ''' |
| destElem = ((BigElement)srcElem1 - (BigElement)srcElem2 + |
| ((BigElement)1 << (sizeof(Element) * 8 - 1))) >> |
| (sizeof(Element) * 8); |
| ''' |
| threeRegNarrowInst("vrsubhn", "Vrsubhn", "SimdAddOp", smallTypes, vrsubhnCode) |
| |
| vcaddCode = ''' |
| bool rot = bits(machInst, 24); |
| Element el1; |
| Element el3; |
| |
| for (int i = 0; i < eCount/2; ++i) { |
| Element srcElem1_1 = letoh(srcReg1.elements[2*i]); |
| Element srcElem1_2 = letoh(srcReg1.elements[2*i+1]); |
| Element srcElem2_1 = letoh(srcReg2.elements[2*i]); |
| Element srcElem2_2 = letoh(srcReg2.elements[2*i+1]); |
| Element destElem_1; |
| Element destElem_2; |
| if (rot) { |
| el1 = srcElem2_2; |
| el3 = fplibNeg<Element>(srcElem2_1); |
| } else { |
| el1 = fplibNeg<Element>(srcElem2_2); |
| el3 = srcElem2_1; |
| } |
| |
| destElem_1 = fplibAdd<Element>(srcElem1_1, el1, fpscr); |
| destElem_2 = fplibAdd<Element>(srcElem1_2, el3, fpscr); |
| destReg.elements[2*i] = htole(destElem_1); |
| destReg.elements[2*i+1] = htole(destElem_2); |
| } |
| ''' |
| |
| # VCADD |
| threeEqualRegInst("vcadd", "VcaddD", "SimdFloatAddOp", |
| ("uint16_t", "uint32_t"), 2, vcaddCode, |
| standardFpcsr=True, complex=True) |
| threeEqualRegInst("vcadd", "VcaddQ", "SimdFloatAddOp", |
| ("uint16_t", "uint32_t"), 4, |
| vcaddCode, standardFpcsr=True, complex=True) |
| |
| vcmlaCode = ''' |
| uint8_t rot = bits(machInst, %(rot)s); |
| Element el1; |
| Element el2; |
| Element el3; |
| Element el4; |
| for (int i = 0; i < eCount/2; ++i) { |
| |
| Element srcElem1_1 = letoh(srcReg1.elements[2*i]); |
| Element srcElem1_2 = letoh(srcReg1.elements[2*i+1]); |
| Element srcElem2_1 = letoh(srcReg2.elements[2*%(index)s]); |
| Element srcElem2_2 = letoh(srcReg2.elements[2*%(index)s+1]); |
| Element destElem_1 = letoh(destReg.elements[2*i]); |
| Element destElem_2 = letoh(destReg.elements[2*i+1]); |
| |
| switch (rot) { |
| case 0x0: |
| { |
| el1 = srcElem2_1; |
| el2 = srcElem1_1; |
| el3 = srcElem2_2; |
| el4 = srcElem1_1; |
| break; |
| } |
| case 0x1: |
| { |
| el1 = fplibNeg<Element>(srcElem2_2); |
| el2 = srcElem1_2; |
| el3 = srcElem2_1; |
| el4 = srcElem1_2; |
| break; |
| } |
| case 0x2: |
| { |
| el1 = fplibNeg<Element>(srcElem2_1); |
| el2 = srcElem1_1; |
| el3 = fplibNeg<Element>(srcElem2_2); |
| el4 = srcElem1_1; |
| break; |
| } |
| case 0x3: |
| { |
| el1 = srcElem2_2; |
| el2 = srcElem1_2; |
| el3 = fplibNeg<Element>(srcElem2_1); |
| el4 = srcElem1_2; |
| break; |
| } |
| } |
| |
| destElem_1 = fplibMulAdd<Element>(destElem_1, el2, el1, fpscr); |
| destElem_2 = fplibMulAdd<Element>(destElem_2, el4, el3, fpscr); |
| |
| destReg.elements[2*i] = htole(destElem_1); |
| destReg.elements[2*i+1] = htole(destElem_2); |
| } |
| ''' |
| |
| # VCMLA (by element) |
| vcmla_imm = vcmlaCode % {'rot': '21, 20', 'index': 'imm'} |
| threeEqualRegInst("vcmla", "VcmlaElemD", "SimdFloatMultAccOp", |
| ("uint16_t", "uint32_t"), 2, vcmla_imm, |
| readDest=True, byElem=True, standardFpcsr=True, |
| complex=True) |
| threeEqualRegInst("vcmla", "VcmlaElemQ", "SimdFloatMultAccOp", |
| ("uint16_t", "uint32_t"), 4, vcmla_imm, |
| readDest=True, byElem=True, standardFpcsr=True, |
| complex=True) |
| |
| # FCMLA (vector) |
| vcmla_vec = vcmlaCode % {'rot': '24, 23', 'index': 'i'} |
| threeEqualRegInst("vcmla", "VcmlaD", "SimdFloatMultAccOp", |
| ("uint16_t", "uint32_t"), 2, vcmla_vec, |
| readDest=True, standardFpcsr=True, complex=True) |
| threeEqualRegInst("vcmla", "VcmlaQ", "SimdFloatMultAccOp", |
| ("uint16_t", "uint32_t"), 4, vcmla_vec, |
| readDest=True, standardFpcsr=True, complex=True) |
| |
| vqaddSCode = ''' |
| destElem = srcElem1 + srcElem2; |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| bool negDest = (destElem < 0); |
| bool negSrc1 = (srcElem1 < 0); |
| bool negSrc2 = (srcElem2 < 0); |
| if ((negDest != negSrc1) && (negSrc1 == negSrc2)) { |
| if (negDest) |
| /* If (>=0) plus (>=0) yields (<0), saturate to +. */ |
| destElem = std::numeric_limits<Element>::max(); |
| else |
| /* If (<0) plus (<0) yields (>=0), saturate to -. */ |
| destElem = std::numeric_limits<Element>::min(); |
| fpscr.qc = 1; |
| } |
| FpscrQc = fpscr; |
| ''' |
| threeEqualRegInst("vqadd", "VqaddSD", "SimdAddOp", signedTypes, 2, vqaddSCode) |
| threeEqualRegInst("vqadd", "VqaddSQ", "SimdAddOp", signedTypes, 4, vqaddSCode) |
| |
| vqsubUCode = ''' |
| destElem = srcElem1 - srcElem2; |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| if (destElem > srcElem1) { |
| destElem = 0; |
| fpscr.qc = 1; |
| } |
| FpscrQc = fpscr; |
| ''' |
| threeEqualRegInst("vqsub", "VqsubUD", "SimdAddOp", unsignedTypes, 2, vqsubUCode) |
| threeEqualRegInst("vqsub", "VqsubUQ", "SimdAddOp", unsignedTypes, 4, vqsubUCode) |
| |
| vqsubSCode = ''' |
| destElem = srcElem1 - srcElem2; |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| bool negDest = (destElem < 0); |
| bool negSrc1 = (srcElem1 < 0); |
| bool posSrc2 = (srcElem2 >= 0); |
| if ((negDest != negSrc1) && (negSrc1 == posSrc2)) { |
| if (negDest) |
| /* If (>=0) minus (<0) yields (<0), saturate to +. */ |
| destElem = std::numeric_limits<Element>::max(); |
| else |
| /* If (<0) minus (>=0) yields (>=0), saturate to -. */ |
| destElem = std::numeric_limits<Element>::min(); |
| fpscr.qc = 1; |
| } |
| FpscrQc = fpscr; |
| ''' |
| threeEqualRegInst("vqsub", "VqsubSD", "SimdAddOp", signedTypes, 2, vqsubSCode) |
| threeEqualRegInst("vqsub", "VqsubSQ", "SimdAddOp", signedTypes, 4, vqsubSCode) |
| |
| vcgtCode = ''' |
| destElem = (srcElem1 > srcElem2) ? (Element)(-1) : 0; |
| ''' |
| threeEqualRegInst("vcgt", "VcgtD", "SimdCmpOp", allTypes, 2, vcgtCode) |
| threeEqualRegInst("vcgt", "VcgtQ", "SimdCmpOp", allTypes, 4, vcgtCode) |
| |
| vcgeCode = ''' |
| destElem = (srcElem1 >= srcElem2) ? (Element)(-1) : 0; |
| ''' |
| threeEqualRegInst("vcge", "VcgeD", "SimdCmpOp", allTypes, 2, vcgeCode) |
| threeEqualRegInst("vcge", "VcgeQ", "SimdCmpOp", allTypes, 4, vcgeCode) |
| |
| vceqCode = ''' |
| destElem = (srcElem1 == srcElem2) ? (Element)(-1) : 0; |
| ''' |
| threeEqualRegInst("vceq", "VceqD", "SimdCmpOp", unsignedTypes, 2, vceqCode) |
| threeEqualRegInst("vceq", "VceqQ", "SimdCmpOp", unsignedTypes, 4, vceqCode) |
| |
| vshlCode = ''' |
| int16_t shiftAmt = (int8_t)srcElem2; |
| if (shiftAmt < 0) { |
| shiftAmt = -shiftAmt; |
| if (shiftAmt >= sizeof(Element) * 8) { |
| shiftAmt = sizeof(Element) * 8 - 1; |
| destElem = 0; |
| } else { |
| destElem = (srcElem1 >> shiftAmt); |
| } |
| // Make sure the right shift sign extended when it should. |
| if (ltz(srcElem1) && !ltz(destElem)) { |
| destElem |= -((Element)1 << (sizeof(Element) * 8 - |
| 1 - shiftAmt)); |
| } |
| } else { |
| if (shiftAmt >= sizeof(Element) * 8) { |
| destElem = 0; |
| } else { |
| destElem = srcElem1 << shiftAmt; |
| } |
| } |
| ''' |
| threeEqualRegInst("vshl", "VshlD", "SimdShiftOp", allTypes, 2, vshlCode) |
| threeEqualRegInst("vshl", "VshlQ", "SimdShiftOp", allTypes, 4, vshlCode) |
| |
| vrshlCode = ''' |
| int16_t shiftAmt = (int8_t)srcElem2; |
| if (shiftAmt < 0) { |
| shiftAmt = -shiftAmt; |
| Element rBit = 0; |
| if (shiftAmt <= sizeof(Element) * 8) |
| rBit = bits(srcElem1, shiftAmt - 1); |
| if (shiftAmt > sizeof(Element) * 8 && ltz(srcElem1)) |
| rBit = 1; |
| if (shiftAmt >= sizeof(Element) * 8) { |
| shiftAmt = sizeof(Element) * 8 - 1; |
| destElem = 0; |
| } else { |
| destElem = (srcElem1 >> shiftAmt); |
| } |
| // Make sure the right shift sign extended when it should. |
| if (ltz(srcElem1) && !ltz(destElem)) { |
| destElem |= -((Element)1 << (sizeof(Element) * 8 - |
| 1 - shiftAmt)); |
| } |
| destElem += rBit; |
| } else if (shiftAmt > 0) { |
| if (shiftAmt >= sizeof(Element) * 8) { |
| destElem = 0; |
| } else { |
| destElem = srcElem1 << shiftAmt; |
| } |
| } else { |
| destElem = srcElem1; |
| } |
| ''' |
| threeEqualRegInst("vrshl", "VrshlD", "SimdAluOp", allTypes, 2, vrshlCode) |
| threeEqualRegInst("vrshl", "VrshlQ", "SimdAluOp", allTypes, 4, vrshlCode) |
| |
| vqshlUCode = ''' |
| int16_t shiftAmt = (int8_t)srcElem2; |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| if (shiftAmt < 0) { |
| shiftAmt = -shiftAmt; |
| if (shiftAmt >= sizeof(Element) * 8) { |
| shiftAmt = sizeof(Element) * 8 - 1; |
| destElem = 0; |
| } else { |
| destElem = (srcElem1 >> shiftAmt); |
| } |
| } else if (shiftAmt > 0) { |
| if (shiftAmt >= sizeof(Element) * 8) { |
| if (srcElem1 != 0) { |
| destElem = mask(sizeof(Element) * 8); |
| fpscr.qc = 1; |
| } else { |
| destElem = 0; |
| } |
| } else { |
| if (bits(srcElem1, sizeof(Element) * 8 - 1, |
| sizeof(Element) * 8 - shiftAmt)) { |
| destElem = mask(sizeof(Element) * 8); |
| fpscr.qc = 1; |
| } else { |
| destElem = srcElem1 << shiftAmt; |
| } |
| } |
| } else { |
| destElem = srcElem1; |
| } |
| FpscrQc = fpscr; |
| ''' |
| threeEqualRegInst("vqshl", "VqshlUD", "SimdAluOp", unsignedTypes, 2, vqshlUCode) |
| threeEqualRegInst("vqshl", "VqshlUQ", "SimdAluOp", unsignedTypes, 4, vqshlUCode) |
| |
| vqshlSCode = ''' |
| int16_t shiftAmt = (int8_t)srcElem2; |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| if (shiftAmt < 0) { |
| shiftAmt = -shiftAmt; |
| if (shiftAmt >= sizeof(Element) * 8) { |
| shiftAmt = sizeof(Element) * 8 - 1; |
| destElem = 0; |
| } else { |
| destElem = (srcElem1 >> shiftAmt); |
| } |
| // Make sure the right shift sign extended when it should. |
| if (srcElem1 < 0 && destElem >= 0) { |
| destElem |= -((Element)1 << (sizeof(Element) * 8 - |
| 1 - shiftAmt)); |
| } |
| } else if (shiftAmt > 0) { |
| bool sat = false; |
| if (shiftAmt >= sizeof(Element) * 8) { |
| if (srcElem1 != 0) |
| sat = true; |
| else |
| destElem = 0; |
| } else { |
| if (bits(srcElem1, sizeof(Element) * 8 - 1, |
| sizeof(Element) * 8 - 1 - shiftAmt) != |
| ((srcElem1 < 0) ? mask(shiftAmt + 1) : 0)) { |
| sat = true; |
| } else { |
| destElem = srcElem1 << shiftAmt; |
| } |
| } |
| if (sat) { |
| fpscr.qc = 1; |
| destElem = mask(sizeof(Element) * 8 - 1); |
| if (srcElem1 < 0) |
| destElem = ~destElem; |
| } |
| } else { |
| destElem = srcElem1; |
| } |
| FpscrQc = fpscr; |
| ''' |
| threeEqualRegInst("vqshl", "VqshlSD", "SimdCmpOp", signedTypes, 2, vqshlSCode) |
| threeEqualRegInst("vqshl", "VqshlSQ", "SimdCmpOp", signedTypes, 4, vqshlSCode) |
| |
| vqrshlUCode = ''' |
| int16_t shiftAmt = (int8_t)srcElem2; |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| if (shiftAmt < 0) { |
| shiftAmt = -shiftAmt; |
| Element rBit = 0; |
| if (shiftAmt <= sizeof(Element) * 8) |
| rBit = bits(srcElem1, shiftAmt - 1); |
| if (shiftAmt >= sizeof(Element) * 8) { |
| shiftAmt = sizeof(Element) * 8 - 1; |
| destElem = 0; |
| } else { |
| destElem = (srcElem1 >> shiftAmt); |
| } |
| destElem += rBit; |
| } else { |
| if (shiftAmt >= sizeof(Element) * 8) { |
| if (srcElem1 != 0) { |
| destElem = mask(sizeof(Element) * 8); |
| fpscr.qc = 1; |
| } else { |
| destElem = 0; |
| } |
| } else { |
| if (bits(srcElem1, sizeof(Element) * 8 - 1, |
| sizeof(Element) * 8 - shiftAmt)) { |
| destElem = mask(sizeof(Element) * 8); |
| fpscr.qc = 1; |
| } else { |
| destElem = srcElem1 << shiftAmt; |
| } |
| } |
| } |
| FpscrQc = fpscr; |
| ''' |
| threeEqualRegInst("vqrshl", "VqrshlUD", "SimdCmpOp", unsignedTypes, 2, vqrshlUCode) |
| threeEqualRegInst("vqrshl", "VqrshlUQ", "SimdCmpOp", unsignedTypes, 4, vqrshlUCode) |
| |
| vqrshlSCode = ''' |
| int16_t shiftAmt = (int8_t)srcElem2; |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| if (shiftAmt < 0) { |
| shiftAmt = -shiftAmt; |
| Element rBit = 0; |
| if (shiftAmt <= sizeof(Element) * 8) |
| rBit = bits(srcElem1, shiftAmt - 1); |
| if (shiftAmt > sizeof(Element) * 8 && srcElem1 < 0) |
| rBit = 1; |
| if (shiftAmt >= sizeof(Element) * 8) { |
| shiftAmt = sizeof(Element) * 8 - 1; |
| destElem = 0; |
| } else { |
| destElem = (srcElem1 >> shiftAmt); |
| } |
| // Make sure the right shift sign extended when it should. |
| if (srcElem1 < 0 && destElem >= 0) { |
| destElem |= -((Element)1 << (sizeof(Element) * 8 - |
| 1 - shiftAmt)); |
| } |
| destElem += rBit; |
| } else if (shiftAmt > 0) { |
| bool sat = false; |
| if (shiftAmt >= sizeof(Element) * 8) { |
| if (srcElem1 != 0) |
| sat = true; |
| else |
| destElem = 0; |
| } else { |
| if (bits(srcElem1, sizeof(Element) * 8 - 1, |
| sizeof(Element) * 8 - 1 - shiftAmt) != |
| ((srcElem1 < 0) ? mask(shiftAmt + 1) : 0)) { |
| sat = true; |
| } else { |
| destElem = srcElem1 << shiftAmt; |
| } |
| } |
| if (sat) { |
| fpscr.qc = 1; |
| destElem = mask(sizeof(Element) * 8 - 1); |
| if (srcElem1 < 0) |
| destElem = ~destElem; |
| } |
| } else { |
| destElem = srcElem1; |
| } |
| FpscrQc = fpscr; |
| ''' |
| threeEqualRegInst("vqrshl", "VqrshlSD", "SimdCmpOp", signedTypes, 2, vqrshlSCode) |
| threeEqualRegInst("vqrshl", "VqrshlSQ", "SimdCmpOp", signedTypes, 4, vqrshlSCode) |
| |
| vabaCode = ''' |
| destElem += (srcElem1 > srcElem2) ? (srcElem1 - srcElem2) : |
| (srcElem2 - srcElem1); |
| ''' |
| threeEqualRegInst("vaba", "VabaD", "SimdAddAccOp", allTypes, 2, vabaCode, True) |
| threeEqualRegInst("vaba", "VabaQ", "SimdAddAccOp", allTypes, 4, vabaCode, True) |
| vabalCode = ''' |
| destElem += (srcElem1 > srcElem2) ? |
| ((BigElement)srcElem1 - (BigElement)srcElem2) : |
| ((BigElement)srcElem2 - (BigElement)srcElem1); |
| ''' |
| threeRegLongInst("vabal", "Vabal", "SimdAddAccOp", smallTypes, vabalCode, True) |
| |
| vabdCode = ''' |
| destElem = (srcElem1 > srcElem2) ? (srcElem1 - srcElem2) : |
| (srcElem2 - srcElem1); |
| ''' |
| threeEqualRegInst("vabd", "VabdD", "SimdAddOp", allTypes, 2, vabdCode) |
| threeEqualRegInst("vabd", "VabdQ", "SimdAddOp", allTypes, 4, vabdCode) |
| vabdlCode = ''' |
| destElem = (srcElem1 > srcElem2) ? |
| ((BigElement)srcElem1 - (BigElement)srcElem2) : |
| ((BigElement)srcElem2 - (BigElement)srcElem1); |
| ''' |
| threeRegLongInst("vabdl", "Vabdl", "SimdAddOp", smallTypes, vabdlCode) |
| |
| vtstCode = ''' |
| destElem = (srcElem1 & srcElem2) ? (Element)(-1) : 0; |
| ''' |
| threeEqualRegInst("vtst", "VtstD", "SimdAluOp", unsignedTypes, 2, vtstCode) |
| threeEqualRegInst("vtst", "VtstQ", "SimdAluOp", unsignedTypes, 4, vtstCode) |
| |
| vmulCode = ''' |
| destElem = srcElem1 * srcElem2; |
| ''' |
| threeEqualRegInst("vmul", "NVmulD", "SimdMultOp", allTypes, 2, vmulCode) |
| threeEqualRegInst("vmul", "NVmulQ", "SimdMultOp", allTypes, 4, vmulCode) |
| vmullCode = ''' |
| destElem = (BigElement)srcElem1 * (BigElement)srcElem2; |
| ''' |
| threeRegLongInst("vmull", "Vmull", "SimdMultOp", smallTypes, vmullCode) |
| |
| vmlaCode = ''' |
| destElem = destElem + srcElem1 * srcElem2; |
| ''' |
| threeEqualRegInst("vmla", "NVmlaD", "SimdMultAccOp", allTypes, 2, vmlaCode, True) |
| threeEqualRegInst("vmla", "NVmlaQ", "SimdMultAccOp", allTypes, 4, vmlaCode, True) |
| vmlalCode = ''' |
| destElem = destElem + (BigElement)srcElem1 * (BigElement)srcElem2; |
| ''' |
| threeRegLongInst("vmlal", "Vmlal", "SimdMultAccOp", smallTypes, vmlalCode, True) |
| |
| vqdmlalCode = ''' |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| BigElement midElem = (2 * (int64_t)srcElem1 * (int64_t)srcElem2); |
| Element maxNeg = std::numeric_limits<Element>::min(); |
| Element halfNeg = maxNeg / 2; |
| if ((srcElem1 == maxNeg && srcElem2 == maxNeg) || |
| (srcElem1 == halfNeg && srcElem2 == maxNeg) || |
| (srcElem1 == maxNeg && srcElem2 == halfNeg)) { |
| midElem = ~((BigElement)maxNeg << (sizeof(Element) * 8)); |
| fpscr.qc = 1; |
| } |
| bool negPreDest = ltz(destElem); |
| destElem += midElem; |
| bool negDest = ltz(destElem); |
| bool negMid = ltz(midElem); |
| if (negPreDest == negMid && negMid != negDest) { |
| destElem = mask(sizeof(BigElement) * 8 - 1); |
| if (negPreDest) |
| destElem = ~destElem; |
| fpscr.qc = 1; |
| } |
| FpscrQc = fpscr; |
| ''' |
| threeRegLongInst("vqdmlal", "Vqdmlal", "SimdMultAccOp", smallTypes, vqdmlalCode, True) |
| |
| vqdmlslCode = ''' |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| BigElement midElem = (2 * (int64_t)srcElem1 * (int64_t)srcElem2); |
| Element maxNeg = std::numeric_limits<Element>::min(); |
| Element halfNeg = maxNeg / 2; |
| if ((srcElem1 == maxNeg && srcElem2 == maxNeg) || |
| (srcElem1 == halfNeg && srcElem2 == maxNeg) || |
| (srcElem1 == maxNeg && srcElem2 == halfNeg)) { |
| midElem = ~((BigElement)maxNeg << (sizeof(Element) * 8)); |
| fpscr.qc = 1; |
| } |
| bool negPreDest = ltz(destElem); |
| destElem -= midElem; |
| bool negDest = ltz(destElem); |
| bool posMid = ltz((BigElement)-midElem); |
| if (negPreDest == posMid && posMid != negDest) { |
| destElem = mask(sizeof(BigElement) * 8 - 1); |
| if (negPreDest) |
| destElem = ~destElem; |
| fpscr.qc = 1; |
| } |
| FpscrQc = fpscr; |
| ''' |
| threeRegLongInst("vqdmlsl", "Vqdmlsl", "SimdMultAccOp", smallTypes, vqdmlslCode, True) |
| |
| vqdmullCode = ''' |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| destElem = (2 * (int64_t)srcElem1 * (int64_t)srcElem2); |
| if (srcElem1 == srcElem2 && |
| srcElem1 == (Element)(std::numeric_limits<Element>::min())) { |
| destElem = ~((BigElement)srcElem1 << (sizeof(Element) * 8)); |
| fpscr.qc = 1; |
| } |
| FpscrQc = fpscr; |
| ''' |
| threeRegLongInst("vqdmull", "Vqdmull", "SimdMultAccOp", smallTypes, vqdmullCode) |
| |
| vmlsCode = ''' |
| destElem = destElem - srcElem1 * srcElem2; |
| ''' |
| threeEqualRegInst("vmls", "NVmlsD", "SimdMultAccOp", allTypes, 2, vmlsCode, True) |
| threeEqualRegInst("vmls", "NVmlsQ", "SimdMultAccOp", allTypes, 4, vmlsCode, True) |
| vmlslCode = ''' |
| destElem = destElem - (BigElement)srcElem1 * (BigElement)srcElem2; |
| ''' |
| threeRegLongInst("vmlsl", "Vmlsl", "SimdMultAccOp", smallTypes, vmlslCode, True) |
| |
| vmulpCode = ''' |
| destElem = 0; |
| for (unsigned j = 0; j < sizeof(Element) * 8; j++) { |
| if (bits(srcElem2, j)) |
| destElem ^= srcElem1 << j; |
| } |
| ''' |
| threeEqualRegInst("vmul", "NVmulpD", "SimdMultOp", unsignedTypes, 2, vmulpCode) |
| threeEqualRegInst("vmul", "NVmulpQ", "SimdMultOp", unsignedTypes, 4, vmulpCode) |
| vmullpCode = ''' |
| destElem = 0; |
| for (unsigned j = 0; j < sizeof(Element) * 8; j++) { |
| if (bits(srcElem2, j)) |
| destElem ^= (BigElement)srcElem1 << j; |
| } |
| ''' |
| threeRegLongInst("vmull", "Vmullp", "SimdMultOp", smallUnsignedTypes, vmullpCode) |
| |
| threeEqualRegInst("vpmax", "VpmaxD", "SimdCmpOp", smallTypes, 2, vmaxCode, pairwise=True) |
| |
| threeEqualRegInst("vpmin", "VpminD", "SimdCmpOp", smallTypes, 2, vminCode, pairwise=True) |
| |
| vqdmulhCode = ''' |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| destElem = (2 * (int64_t)srcElem1 * (int64_t)srcElem2) >> |
| (sizeof(Element) * 8); |
| if (srcElem1 == srcElem2 && |
| srcElem1 == (Element)(std::numeric_limits<Element>::min())) { |
| destElem = ~srcElem1; |
| fpscr.qc = 1; |
| } |
| FpscrQc = fpscr; |
| ''' |
| threeEqualRegInst("vqdmulh", "VqdmulhD", "SimdMultOp", smallSignedTypes, 2, vqdmulhCode) |
| threeEqualRegInst("vqdmulh", "VqdmulhQ", "SimdMultOp", smallSignedTypes, 4, vqdmulhCode) |
| |
| |
| vqrdmCode = ''' |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| int nbits = sizeof(Element)*8; |
| |
| auto val_max = std::numeric_limits<Element>::max(); |
| auto val_min = std::numeric_limits<Element>::min(); |
| BigElement unsat_value = ((BigElement)destElem << nbits) %(code)s |
| ((BigElement)srcElem1 * (BigElement)srcElem2 * 2) + |
| ((BigElement)1 << (nbits - 1)); |
| unsat_value >>= nbits; |
| |
| if (unsat_value > val_max) { |
| fpscr.qc = 1; |
| destElem = val_max; |
| } else if (unsat_value < val_min) { |
| fpscr.qc = 1; |
| destElem = val_min; |
| } else { |
| destElem = unsat_value; |
| } |
| FpscrQc = fpscr; |
| ''' |
| code_add = "+" |
| vqrdmlahCode = vqrdmCode % {'code': code_add} |
| rdm_check = ''' |
| int sz = bits(machInst, 21, 20); |
| RegVal isar5 = xc->tcBase()->readMiscReg(MISCREG_ID_ISAR5); |
| if (!(bits(isar5, 27, 24) == 0x1) || sz == 3 || sz == 0) |
| return std::make_shared<UndefinedInstruction>(machInst, true); |
| typedef __int128_t BigElement; |
| ''' |
| threeEqualRegInst("vqrdmlah", "VqrdmlahD", |
| "SimdMultOp", smallSignedTypes, 2, vqrdmlahCode, readDest=True, |
| extra=rdm_check) |
| threeEqualRegInst("vqrdmlah", "VqrdmlahQ", |
| "SimdMultOp", smallSignedTypes, 4, vqrdmlahCode, readDest=True, |
| extra=rdm_check) |
| |
| code_sub = "-" |
| vqrdmlshCode = vqrdmCode % {'code': code_sub} |
| threeEqualRegInst("vqrdmlsh", "VqrdmlshD", |
| "SimdMultOp", smallSignedTypes, 2, vqrdmlshCode, readDest=True, |
| extra=rdm_check) |
| threeEqualRegInst("vqrdmlsh", "VqrdmlshQ", |
| "SimdMultOp", smallSignedTypes, 4, vqrdmlshCode, readDest=True, |
| extra=rdm_check) |
| |
| |
| vqrdmulhCode = ''' |
| FPSCR fpscr = (FPSCR) FpscrQc; |
| destElem = (2 * (int64_t)srcElem1 * (int64_t)srcElem2 + |
| ((int64_t)1 << (sizeof(Element) * 8 - 1))) >> |
| (sizeof(Element) * 8); |
| Element maxNeg = std::numeric_limits<Element>::min(); |
| Element halfNeg = maxNeg / 2; |
| if ((srcElem1 == maxNeg && srcElem2 == maxNeg) || |
| (srcElem1 == halfNeg && srcElem2 == maxNeg) || |
| (srcElem1 == maxNeg && srcElem2 == halfNeg)) { |
| if (destElem < 0) { |
| destElem = mask(sizeof(Element) * 8 - 1); |
| } else { |
| destElem = std::numeric_limits<Element>::min(); |
| } |
| fpscr.qc = 1; |
| } |
| FpscrQc = fpscr; |
| ''' |
| threeEqualRegInst("vqrdmulh", "VqrdmulhD", |
| "SimdMultOp", smallSignedTypes, 2, vqrdmulhCode) |
| threeEqualRegInst("vqrdmulh", "VqrdmulhQ", |
| "SimdMultOp", smallSignedTypes, 4, vqrdmulhCode) |
| |
| vMinMaxFpCode = ''' |
| destElem = fplib%s<Element>(srcElem1, srcElem2, fpscr); |
| ''' |
| vMinMaxInsts = [ |
| ("vmax", "VmaxDFp", 2, "Max", False, ), |
| ("vmax", "VmaxQFp", 4, "Max", False, ), |
| ("vmaxnm", "VmaxnmDFp", 2, "MaxNum", False, ), |
| ("vmaxnm", "VmaxnmQFp", 4, "MaxNum", False, ), |
| ("vpmax", "VpmaxDFp", 2, "Max", True, ), |
| ("vpmax", "VpmaxQFp", 4, "Max", True, ), |
| ("vmin", "VminDFp", 2, "Min", False, ), |
| ("vmin", "VminQFp", 4, "Min", False, ), |
| ("vminnm", "VminnmDFp", 2, "MinNum", False, ), |
| ("vminnm", "VminnmQFp", 4, "MinNum", False, ), |
| ("vpmin", "VpminDFp", 2, "Min", True, ), |
| ("vpmin", "VpminQFp", 4, "Min", True, ), |
| ] |
| for name, Name, rCount, op, pairwise in vMinMaxInsts: |
| threeEqualRegInst( |
| name, |
| Name, |
| "SimdFloatCmpOp", |
|