106f32e7eSjoerg //===-- ARMAddressingModes.h - ARM Addressing Modes -------------*- C++ -*-===// 206f32e7eSjoerg // 306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information. 506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 606f32e7eSjoerg // 706f32e7eSjoerg //===----------------------------------------------------------------------===// 806f32e7eSjoerg // 906f32e7eSjoerg // This file contains the ARM addressing mode implementation stuff. 1006f32e7eSjoerg // 1106f32e7eSjoerg //===----------------------------------------------------------------------===// 1206f32e7eSjoerg 1306f32e7eSjoerg #ifndef LLVM_LIB_TARGET_ARM_MCTARGETDESC_ARMADDRESSINGMODES_H 1406f32e7eSjoerg #define LLVM_LIB_TARGET_ARM_MCTARGETDESC_ARMADDRESSINGMODES_H 1506f32e7eSjoerg 1606f32e7eSjoerg #include "llvm/ADT/APFloat.h" 1706f32e7eSjoerg #include "llvm/ADT/APInt.h" 1806f32e7eSjoerg #include "llvm/ADT/bit.h" 1906f32e7eSjoerg #include "llvm/Support/ErrorHandling.h" 2006f32e7eSjoerg #include "llvm/Support/MathExtras.h" 2106f32e7eSjoerg #include <cassert> 2206f32e7eSjoerg 2306f32e7eSjoerg namespace llvm { 2406f32e7eSjoerg 2506f32e7eSjoerg /// ARM_AM - ARM Addressing Mode Stuff 2606f32e7eSjoerg namespace ARM_AM { 2706f32e7eSjoerg enum ShiftOpc { 2806f32e7eSjoerg no_shift = 0, 2906f32e7eSjoerg asr, 3006f32e7eSjoerg lsl, 3106f32e7eSjoerg lsr, 3206f32e7eSjoerg ror, 3306f32e7eSjoerg rrx, 3406f32e7eSjoerg uxtw 3506f32e7eSjoerg }; 3606f32e7eSjoerg 3706f32e7eSjoerg enum AddrOpc { 3806f32e7eSjoerg sub = 0, 3906f32e7eSjoerg add 4006f32e7eSjoerg }; 4106f32e7eSjoerg getAddrOpcStr(AddrOpc Op)4206f32e7eSjoerg inline const char *getAddrOpcStr(AddrOpc Op) { return Op == sub ? "-" : ""; } 4306f32e7eSjoerg getShiftOpcStr(ShiftOpc Op)4406f32e7eSjoerg inline const char *getShiftOpcStr(ShiftOpc Op) { 4506f32e7eSjoerg switch (Op) { 4606f32e7eSjoerg default: llvm_unreachable("Unknown shift opc!"); 4706f32e7eSjoerg case ARM_AM::asr: return "asr"; 4806f32e7eSjoerg case ARM_AM::lsl: return "lsl"; 4906f32e7eSjoerg case ARM_AM::lsr: return "lsr"; 5006f32e7eSjoerg case ARM_AM::ror: return "ror"; 5106f32e7eSjoerg case ARM_AM::rrx: return "rrx"; 5206f32e7eSjoerg case ARM_AM::uxtw: return "uxtw"; 5306f32e7eSjoerg } 5406f32e7eSjoerg } 5506f32e7eSjoerg getShiftOpcEncoding(ShiftOpc Op)5606f32e7eSjoerg inline unsigned getShiftOpcEncoding(ShiftOpc Op) { 5706f32e7eSjoerg switch (Op) { 5806f32e7eSjoerg default: llvm_unreachable("Unknown shift opc!"); 5906f32e7eSjoerg case ARM_AM::asr: return 2; 6006f32e7eSjoerg case ARM_AM::lsl: return 0; 6106f32e7eSjoerg case ARM_AM::lsr: return 1; 6206f32e7eSjoerg case ARM_AM::ror: return 3; 6306f32e7eSjoerg } 6406f32e7eSjoerg } 6506f32e7eSjoerg 6606f32e7eSjoerg enum AMSubMode { 6706f32e7eSjoerg bad_am_submode = 0, 6806f32e7eSjoerg ia, 6906f32e7eSjoerg ib, 7006f32e7eSjoerg da, 7106f32e7eSjoerg db 7206f32e7eSjoerg }; 7306f32e7eSjoerg getAMSubModeStr(AMSubMode Mode)7406f32e7eSjoerg inline const char *getAMSubModeStr(AMSubMode Mode) { 7506f32e7eSjoerg switch (Mode) { 7606f32e7eSjoerg default: llvm_unreachable("Unknown addressing sub-mode!"); 7706f32e7eSjoerg case ARM_AM::ia: return "ia"; 7806f32e7eSjoerg case ARM_AM::ib: return "ib"; 7906f32e7eSjoerg case ARM_AM::da: return "da"; 8006f32e7eSjoerg case ARM_AM::db: return "db"; 8106f32e7eSjoerg } 8206f32e7eSjoerg } 8306f32e7eSjoerg 8406f32e7eSjoerg /// rotr32 - Rotate a 32-bit unsigned value right by a specified # bits. 8506f32e7eSjoerg /// rotr32(unsigned Val,unsigned Amt)8606f32e7eSjoerg inline unsigned rotr32(unsigned Val, unsigned Amt) { 8706f32e7eSjoerg assert(Amt < 32 && "Invalid rotate amount"); 8806f32e7eSjoerg return (Val >> Amt) | (Val << ((32-Amt)&31)); 8906f32e7eSjoerg } 9006f32e7eSjoerg 9106f32e7eSjoerg /// rotl32 - Rotate a 32-bit unsigned value left by a specified # bits. 9206f32e7eSjoerg /// rotl32(unsigned Val,unsigned Amt)9306f32e7eSjoerg inline unsigned rotl32(unsigned Val, unsigned Amt) { 9406f32e7eSjoerg assert(Amt < 32 && "Invalid rotate amount"); 9506f32e7eSjoerg return (Val << Amt) | (Val >> ((32-Amt)&31)); 9606f32e7eSjoerg } 9706f32e7eSjoerg 9806f32e7eSjoerg //===--------------------------------------------------------------------===// 9906f32e7eSjoerg // Addressing Mode #1: shift_operand with registers 10006f32e7eSjoerg //===--------------------------------------------------------------------===// 10106f32e7eSjoerg // 10206f32e7eSjoerg // This 'addressing mode' is used for arithmetic instructions. It can 10306f32e7eSjoerg // represent things like: 10406f32e7eSjoerg // reg 10506f32e7eSjoerg // reg [asr|lsl|lsr|ror|rrx] reg 10606f32e7eSjoerg // reg [asr|lsl|lsr|ror|rrx] imm 10706f32e7eSjoerg // 10806f32e7eSjoerg // This is stored three operands [rega, regb, opc]. The first is the base 10906f32e7eSjoerg // reg, the second is the shift amount (or reg0 if not present or imm). The 11006f32e7eSjoerg // third operand encodes the shift opcode and the imm if a reg isn't present. 11106f32e7eSjoerg // getSORegOpc(ShiftOpc ShOp,unsigned Imm)11206f32e7eSjoerg inline unsigned getSORegOpc(ShiftOpc ShOp, unsigned Imm) { 11306f32e7eSjoerg return ShOp | (Imm << 3); 11406f32e7eSjoerg } getSORegOffset(unsigned Op)11506f32e7eSjoerg inline unsigned getSORegOffset(unsigned Op) { return Op >> 3; } getSORegShOp(unsigned Op)11606f32e7eSjoerg inline ShiftOpc getSORegShOp(unsigned Op) { return (ShiftOpc)(Op & 7); } 11706f32e7eSjoerg 11806f32e7eSjoerg /// getSOImmValImm - Given an encoded imm field for the reg/imm form, return 11906f32e7eSjoerg /// the 8-bit imm value. getSOImmValImm(unsigned Imm)12006f32e7eSjoerg inline unsigned getSOImmValImm(unsigned Imm) { return Imm & 0xFF; } 12106f32e7eSjoerg /// getSOImmValRot - Given an encoded imm field for the reg/imm form, return 12206f32e7eSjoerg /// the rotate amount. getSOImmValRot(unsigned Imm)12306f32e7eSjoerg inline unsigned getSOImmValRot(unsigned Imm) { return (Imm >> 8) * 2; } 12406f32e7eSjoerg 12506f32e7eSjoerg /// getSOImmValRotate - Try to handle Imm with an immediate shifter operand, 12606f32e7eSjoerg /// computing the rotate amount to use. If this immediate value cannot be 12706f32e7eSjoerg /// handled with a single shifter-op, determine a good rotate amount that will 12806f32e7eSjoerg /// take a maximal chunk of bits out of the immediate. getSOImmValRotate(unsigned Imm)12906f32e7eSjoerg inline unsigned getSOImmValRotate(unsigned Imm) { 13006f32e7eSjoerg // 8-bit (or less) immediates are trivially shifter_operands with a rotate 13106f32e7eSjoerg // of zero. 13206f32e7eSjoerg if ((Imm & ~255U) == 0) return 0; 13306f32e7eSjoerg 13406f32e7eSjoerg // Use CTZ to compute the rotate amount. 13506f32e7eSjoerg unsigned TZ = countTrailingZeros(Imm); 13606f32e7eSjoerg 13706f32e7eSjoerg // Rotate amount must be even. Something like 0x200 must be rotated 8 bits, 13806f32e7eSjoerg // not 9. 13906f32e7eSjoerg unsigned RotAmt = TZ & ~1; 14006f32e7eSjoerg 14106f32e7eSjoerg // If we can handle this spread, return it. 14206f32e7eSjoerg if ((rotr32(Imm, RotAmt) & ~255U) == 0) 14306f32e7eSjoerg return (32-RotAmt)&31; // HW rotates right, not left. 14406f32e7eSjoerg 14506f32e7eSjoerg // For values like 0xF000000F, we should ignore the low 6 bits, then 14606f32e7eSjoerg // retry the hunt. 14706f32e7eSjoerg if (Imm & 63U) { 14806f32e7eSjoerg unsigned TZ2 = countTrailingZeros(Imm & ~63U); 14906f32e7eSjoerg unsigned RotAmt2 = TZ2 & ~1; 15006f32e7eSjoerg if ((rotr32(Imm, RotAmt2) & ~255U) == 0) 15106f32e7eSjoerg return (32-RotAmt2)&31; // HW rotates right, not left. 15206f32e7eSjoerg } 15306f32e7eSjoerg 15406f32e7eSjoerg // Otherwise, we have no way to cover this span of bits with a single 15506f32e7eSjoerg // shifter_op immediate. Return a chunk of bits that will be useful to 15606f32e7eSjoerg // handle. 15706f32e7eSjoerg return (32-RotAmt)&31; // HW rotates right, not left. 15806f32e7eSjoerg } 15906f32e7eSjoerg 16006f32e7eSjoerg /// getSOImmVal - Given a 32-bit immediate, if it is something that can fit 16106f32e7eSjoerg /// into an shifter_operand immediate operand, return the 12-bit encoding for 16206f32e7eSjoerg /// it. If not, return -1. getSOImmVal(unsigned Arg)16306f32e7eSjoerg inline int getSOImmVal(unsigned Arg) { 16406f32e7eSjoerg // 8-bit (or less) immediates are trivially shifter_operands with a rotate 16506f32e7eSjoerg // of zero. 16606f32e7eSjoerg if ((Arg & ~255U) == 0) return Arg; 16706f32e7eSjoerg 16806f32e7eSjoerg unsigned RotAmt = getSOImmValRotate(Arg); 16906f32e7eSjoerg 17006f32e7eSjoerg // If this cannot be handled with a single shifter_op, bail out. 17106f32e7eSjoerg if (rotr32(~255U, RotAmt) & Arg) 17206f32e7eSjoerg return -1; 17306f32e7eSjoerg 17406f32e7eSjoerg // Encode this correctly. 17506f32e7eSjoerg return rotl32(Arg, RotAmt) | ((RotAmt>>1) << 8); 17606f32e7eSjoerg } 17706f32e7eSjoerg 17806f32e7eSjoerg /// isSOImmTwoPartVal - Return true if the specified value can be obtained by 17906f32e7eSjoerg /// or'ing together two SOImmVal's. isSOImmTwoPartVal(unsigned V)18006f32e7eSjoerg inline bool isSOImmTwoPartVal(unsigned V) { 18106f32e7eSjoerg // If this can be handled with a single shifter_op, bail out. 18206f32e7eSjoerg V = rotr32(~255U, getSOImmValRotate(V)) & V; 18306f32e7eSjoerg if (V == 0) 18406f32e7eSjoerg return false; 18506f32e7eSjoerg 18606f32e7eSjoerg // If this can be handled with two shifter_op's, accept. 18706f32e7eSjoerg V = rotr32(~255U, getSOImmValRotate(V)) & V; 18806f32e7eSjoerg return V == 0; 18906f32e7eSjoerg } 19006f32e7eSjoerg 19106f32e7eSjoerg /// getSOImmTwoPartFirst - If V is a value that satisfies isSOImmTwoPartVal, 19206f32e7eSjoerg /// return the first chunk of it. getSOImmTwoPartFirst(unsigned V)19306f32e7eSjoerg inline unsigned getSOImmTwoPartFirst(unsigned V) { 19406f32e7eSjoerg return rotr32(255U, getSOImmValRotate(V)) & V; 19506f32e7eSjoerg } 19606f32e7eSjoerg 19706f32e7eSjoerg /// getSOImmTwoPartSecond - If V is a value that satisfies isSOImmTwoPartVal, 19806f32e7eSjoerg /// return the second chunk of it. getSOImmTwoPartSecond(unsigned V)19906f32e7eSjoerg inline unsigned getSOImmTwoPartSecond(unsigned V) { 20006f32e7eSjoerg // Mask out the first hunk. 20106f32e7eSjoerg V = rotr32(~255U, getSOImmValRotate(V)) & V; 20206f32e7eSjoerg 20306f32e7eSjoerg // Take what's left. 20406f32e7eSjoerg assert(V == (rotr32(255U, getSOImmValRotate(V)) & V)); 20506f32e7eSjoerg return V; 20606f32e7eSjoerg } 20706f32e7eSjoerg 208*da58b97aSjoerg /// isSOImmTwoPartValNeg - Return true if the specified value can be obtained 209*da58b97aSjoerg /// by two SOImmVal, that -V = First + Second. 210*da58b97aSjoerg /// "R+V" can be optimized to (sub (sub R, First), Second). 211*da58b97aSjoerg /// "R=V" can be optimized to (sub (mvn R, ~(-First)), Second). isSOImmTwoPartValNeg(unsigned V)212*da58b97aSjoerg inline bool isSOImmTwoPartValNeg(unsigned V) { 213*da58b97aSjoerg unsigned First; 214*da58b97aSjoerg if (!isSOImmTwoPartVal(-V)) 215*da58b97aSjoerg return false; 216*da58b97aSjoerg // Return false if ~(-First) is not a SoImmval. 217*da58b97aSjoerg First = getSOImmTwoPartFirst(-V); 218*da58b97aSjoerg First = ~(-First); 219*da58b97aSjoerg return !(rotr32(~255U, getSOImmValRotate(First)) & First); 220*da58b97aSjoerg } 221*da58b97aSjoerg 22206f32e7eSjoerg /// getThumbImmValShift - Try to handle Imm with a 8-bit immediate followed 22306f32e7eSjoerg /// by a left shift. Returns the shift amount to use. getThumbImmValShift(unsigned Imm)22406f32e7eSjoerg inline unsigned getThumbImmValShift(unsigned Imm) { 22506f32e7eSjoerg // 8-bit (or less) immediates are trivially immediate operand with a shift 22606f32e7eSjoerg // of zero. 22706f32e7eSjoerg if ((Imm & ~255U) == 0) return 0; 22806f32e7eSjoerg 22906f32e7eSjoerg // Use CTZ to compute the shift amount. 23006f32e7eSjoerg return countTrailingZeros(Imm); 23106f32e7eSjoerg } 23206f32e7eSjoerg 23306f32e7eSjoerg /// isThumbImmShiftedVal - Return true if the specified value can be obtained 23406f32e7eSjoerg /// by left shifting a 8-bit immediate. isThumbImmShiftedVal(unsigned V)23506f32e7eSjoerg inline bool isThumbImmShiftedVal(unsigned V) { 23606f32e7eSjoerg // If this can be handled with 23706f32e7eSjoerg V = (~255U << getThumbImmValShift(V)) & V; 23806f32e7eSjoerg return V == 0; 23906f32e7eSjoerg } 24006f32e7eSjoerg 24106f32e7eSjoerg /// getThumbImm16ValShift - Try to handle Imm with a 16-bit immediate followed 24206f32e7eSjoerg /// by a left shift. Returns the shift amount to use. getThumbImm16ValShift(unsigned Imm)24306f32e7eSjoerg inline unsigned getThumbImm16ValShift(unsigned Imm) { 24406f32e7eSjoerg // 16-bit (or less) immediates are trivially immediate operand with a shift 24506f32e7eSjoerg // of zero. 24606f32e7eSjoerg if ((Imm & ~65535U) == 0) return 0; 24706f32e7eSjoerg 24806f32e7eSjoerg // Use CTZ to compute the shift amount. 24906f32e7eSjoerg return countTrailingZeros(Imm); 25006f32e7eSjoerg } 25106f32e7eSjoerg 25206f32e7eSjoerg /// isThumbImm16ShiftedVal - Return true if the specified value can be 25306f32e7eSjoerg /// obtained by left shifting a 16-bit immediate. isThumbImm16ShiftedVal(unsigned V)25406f32e7eSjoerg inline bool isThumbImm16ShiftedVal(unsigned V) { 25506f32e7eSjoerg // If this can be handled with 25606f32e7eSjoerg V = (~65535U << getThumbImm16ValShift(V)) & V; 25706f32e7eSjoerg return V == 0; 25806f32e7eSjoerg } 25906f32e7eSjoerg 26006f32e7eSjoerg /// getThumbImmNonShiftedVal - If V is a value that satisfies 26106f32e7eSjoerg /// isThumbImmShiftedVal, return the non-shiftd value. getThumbImmNonShiftedVal(unsigned V)26206f32e7eSjoerg inline unsigned getThumbImmNonShiftedVal(unsigned V) { 26306f32e7eSjoerg return V >> getThumbImmValShift(V); 26406f32e7eSjoerg } 26506f32e7eSjoerg 26606f32e7eSjoerg 26706f32e7eSjoerg /// getT2SOImmValSplat - Return the 12-bit encoded representation 26806f32e7eSjoerg /// if the specified value can be obtained by splatting the low 8 bits 26906f32e7eSjoerg /// into every other byte or every byte of a 32-bit value. i.e., 27006f32e7eSjoerg /// 00000000 00000000 00000000 abcdefgh control = 0 27106f32e7eSjoerg /// 00000000 abcdefgh 00000000 abcdefgh control = 1 27206f32e7eSjoerg /// abcdefgh 00000000 abcdefgh 00000000 control = 2 27306f32e7eSjoerg /// abcdefgh abcdefgh abcdefgh abcdefgh control = 3 27406f32e7eSjoerg /// Return -1 if none of the above apply. 27506f32e7eSjoerg /// See ARM Reference Manual A6.3.2. getT2SOImmValSplatVal(unsigned V)27606f32e7eSjoerg inline int getT2SOImmValSplatVal(unsigned V) { 27706f32e7eSjoerg unsigned u, Vs, Imm; 27806f32e7eSjoerg // control = 0 27906f32e7eSjoerg if ((V & 0xffffff00) == 0) 28006f32e7eSjoerg return V; 28106f32e7eSjoerg 28206f32e7eSjoerg // If the value is zeroes in the first byte, just shift those off 28306f32e7eSjoerg Vs = ((V & 0xff) == 0) ? V >> 8 : V; 28406f32e7eSjoerg // Any passing value only has 8 bits of payload, splatted across the word 28506f32e7eSjoerg Imm = Vs & 0xff; 28606f32e7eSjoerg // Likewise, any passing values have the payload splatted into the 3rd byte 28706f32e7eSjoerg u = Imm | (Imm << 16); 28806f32e7eSjoerg 28906f32e7eSjoerg // control = 1 or 2 29006f32e7eSjoerg if (Vs == u) 29106f32e7eSjoerg return (((Vs == V) ? 1 : 2) << 8) | Imm; 29206f32e7eSjoerg 29306f32e7eSjoerg // control = 3 29406f32e7eSjoerg if (Vs == (u | (u << 8))) 29506f32e7eSjoerg return (3 << 8) | Imm; 29606f32e7eSjoerg 29706f32e7eSjoerg return -1; 29806f32e7eSjoerg } 29906f32e7eSjoerg 30006f32e7eSjoerg /// getT2SOImmValRotateVal - Return the 12-bit encoded representation if the 30106f32e7eSjoerg /// specified value is a rotated 8-bit value. Return -1 if no rotation 30206f32e7eSjoerg /// encoding is possible. 30306f32e7eSjoerg /// See ARM Reference Manual A6.3.2. getT2SOImmValRotateVal(unsigned V)30406f32e7eSjoerg inline int getT2SOImmValRotateVal(unsigned V) { 30506f32e7eSjoerg unsigned RotAmt = countLeadingZeros(V); 30606f32e7eSjoerg if (RotAmt >= 24) 30706f32e7eSjoerg return -1; 30806f32e7eSjoerg 30906f32e7eSjoerg // If 'Arg' can be handled with a single shifter_op return the value. 31006f32e7eSjoerg if ((rotr32(0xff000000U, RotAmt) & V) == V) 31106f32e7eSjoerg return (rotr32(V, 24 - RotAmt) & 0x7f) | ((RotAmt + 8) << 7); 31206f32e7eSjoerg 31306f32e7eSjoerg return -1; 31406f32e7eSjoerg } 31506f32e7eSjoerg 31606f32e7eSjoerg /// getT2SOImmVal - Given a 32-bit immediate, if it is something that can fit 31706f32e7eSjoerg /// into a Thumb-2 shifter_operand immediate operand, return the 12-bit 31806f32e7eSjoerg /// encoding for it. If not, return -1. 31906f32e7eSjoerg /// See ARM Reference Manual A6.3.2. getT2SOImmVal(unsigned Arg)32006f32e7eSjoerg inline int getT2SOImmVal(unsigned Arg) { 32106f32e7eSjoerg // If 'Arg' is an 8-bit splat, then get the encoded value. 32206f32e7eSjoerg int Splat = getT2SOImmValSplatVal(Arg); 32306f32e7eSjoerg if (Splat != -1) 32406f32e7eSjoerg return Splat; 32506f32e7eSjoerg 32606f32e7eSjoerg // If 'Arg' can be handled with a single shifter_op return the value. 32706f32e7eSjoerg int Rot = getT2SOImmValRotateVal(Arg); 32806f32e7eSjoerg if (Rot != -1) 32906f32e7eSjoerg return Rot; 33006f32e7eSjoerg 33106f32e7eSjoerg return -1; 33206f32e7eSjoerg } 33306f32e7eSjoerg getT2SOImmValRotate(unsigned V)33406f32e7eSjoerg inline unsigned getT2SOImmValRotate(unsigned V) { 33506f32e7eSjoerg if ((V & ~255U) == 0) return 0; 33606f32e7eSjoerg // Use CTZ to compute the rotate amount. 33706f32e7eSjoerg unsigned RotAmt = countTrailingZeros(V); 33806f32e7eSjoerg return (32 - RotAmt) & 31; 33906f32e7eSjoerg } 34006f32e7eSjoerg isT2SOImmTwoPartVal(unsigned Imm)34106f32e7eSjoerg inline bool isT2SOImmTwoPartVal(unsigned Imm) { 34206f32e7eSjoerg unsigned V = Imm; 34306f32e7eSjoerg // Passing values can be any combination of splat values and shifter 34406f32e7eSjoerg // values. If this can be handled with a single shifter or splat, bail 34506f32e7eSjoerg // out. Those should be handled directly, not with a two-part val. 34606f32e7eSjoerg if (getT2SOImmValSplatVal(V) != -1) 34706f32e7eSjoerg return false; 34806f32e7eSjoerg V = rotr32 (~255U, getT2SOImmValRotate(V)) & V; 34906f32e7eSjoerg if (V == 0) 35006f32e7eSjoerg return false; 35106f32e7eSjoerg 35206f32e7eSjoerg // If this can be handled as an immediate, accept. 35306f32e7eSjoerg if (getT2SOImmVal(V) != -1) return true; 35406f32e7eSjoerg 35506f32e7eSjoerg // Likewise, try masking out a splat value first. 35606f32e7eSjoerg V = Imm; 35706f32e7eSjoerg if (getT2SOImmValSplatVal(V & 0xff00ff00U) != -1) 35806f32e7eSjoerg V &= ~0xff00ff00U; 35906f32e7eSjoerg else if (getT2SOImmValSplatVal(V & 0x00ff00ffU) != -1) 36006f32e7eSjoerg V &= ~0x00ff00ffU; 36106f32e7eSjoerg // If what's left can be handled as an immediate, accept. 36206f32e7eSjoerg if (getT2SOImmVal(V) != -1) return true; 36306f32e7eSjoerg 36406f32e7eSjoerg // Otherwise, do not accept. 36506f32e7eSjoerg return false; 36606f32e7eSjoerg } 36706f32e7eSjoerg getT2SOImmTwoPartFirst(unsigned Imm)36806f32e7eSjoerg inline unsigned getT2SOImmTwoPartFirst(unsigned Imm) { 36906f32e7eSjoerg assert (isT2SOImmTwoPartVal(Imm) && 37006f32e7eSjoerg "Immedate cannot be encoded as two part immediate!"); 37106f32e7eSjoerg // Try a shifter operand as one part 37206f32e7eSjoerg unsigned V = rotr32 (~255, getT2SOImmValRotate(Imm)) & Imm; 37306f32e7eSjoerg // If the rest is encodable as an immediate, then return it. 37406f32e7eSjoerg if (getT2SOImmVal(V) != -1) return V; 37506f32e7eSjoerg 37606f32e7eSjoerg // Try masking out a splat value first. 37706f32e7eSjoerg if (getT2SOImmValSplatVal(Imm & 0xff00ff00U) != -1) 37806f32e7eSjoerg return Imm & 0xff00ff00U; 37906f32e7eSjoerg 38006f32e7eSjoerg // The other splat is all that's left as an option. 38106f32e7eSjoerg assert (getT2SOImmValSplatVal(Imm & 0x00ff00ffU) != -1); 38206f32e7eSjoerg return Imm & 0x00ff00ffU; 38306f32e7eSjoerg } 38406f32e7eSjoerg getT2SOImmTwoPartSecond(unsigned Imm)38506f32e7eSjoerg inline unsigned getT2SOImmTwoPartSecond(unsigned Imm) { 38606f32e7eSjoerg // Mask out the first hunk 38706f32e7eSjoerg Imm ^= getT2SOImmTwoPartFirst(Imm); 38806f32e7eSjoerg // Return what's left 38906f32e7eSjoerg assert (getT2SOImmVal(Imm) != -1 && 39006f32e7eSjoerg "Unable to encode second part of T2 two part SO immediate"); 39106f32e7eSjoerg return Imm; 39206f32e7eSjoerg } 39306f32e7eSjoerg 39406f32e7eSjoerg 39506f32e7eSjoerg //===--------------------------------------------------------------------===// 39606f32e7eSjoerg // Addressing Mode #2 39706f32e7eSjoerg //===--------------------------------------------------------------------===// 39806f32e7eSjoerg // 39906f32e7eSjoerg // This is used for most simple load/store instructions. 40006f32e7eSjoerg // 40106f32e7eSjoerg // addrmode2 := reg +/- reg shop imm 40206f32e7eSjoerg // addrmode2 := reg +/- imm12 40306f32e7eSjoerg // 40406f32e7eSjoerg // The first operand is always a Reg. The second operand is a reg if in 40506f32e7eSjoerg // reg/reg form, otherwise it's reg#0. The third field encodes the operation 40606f32e7eSjoerg // in bit 12, the immediate in bits 0-11, and the shift op in 13-15. The 40706f32e7eSjoerg // fourth operand 16-17 encodes the index mode. 40806f32e7eSjoerg // 40906f32e7eSjoerg // If this addressing mode is a frame index (before prolog/epilog insertion 41006f32e7eSjoerg // and code rewriting), this operand will have the form: FI#, reg0, <offs> 41106f32e7eSjoerg // with no shift amount for the frame offset. 41206f32e7eSjoerg // 41306f32e7eSjoerg inline unsigned getAM2Opc(AddrOpc Opc, unsigned Imm12, ShiftOpc SO, 41406f32e7eSjoerg unsigned IdxMode = 0) { 41506f32e7eSjoerg assert(Imm12 < (1 << 12) && "Imm too large!"); 41606f32e7eSjoerg bool isSub = Opc == sub; 41706f32e7eSjoerg return Imm12 | ((int)isSub << 12) | (SO << 13) | (IdxMode << 16) ; 41806f32e7eSjoerg } getAM2Offset(unsigned AM2Opc)41906f32e7eSjoerg inline unsigned getAM2Offset(unsigned AM2Opc) { 42006f32e7eSjoerg return AM2Opc & ((1 << 12)-1); 42106f32e7eSjoerg } getAM2Op(unsigned AM2Opc)42206f32e7eSjoerg inline AddrOpc getAM2Op(unsigned AM2Opc) { 42306f32e7eSjoerg return ((AM2Opc >> 12) & 1) ? sub : add; 42406f32e7eSjoerg } getAM2ShiftOpc(unsigned AM2Opc)42506f32e7eSjoerg inline ShiftOpc getAM2ShiftOpc(unsigned AM2Opc) { 42606f32e7eSjoerg return (ShiftOpc)((AM2Opc >> 13) & 7); 42706f32e7eSjoerg } getAM2IdxMode(unsigned AM2Opc)42806f32e7eSjoerg inline unsigned getAM2IdxMode(unsigned AM2Opc) { return (AM2Opc >> 16); } 42906f32e7eSjoerg 43006f32e7eSjoerg //===--------------------------------------------------------------------===// 43106f32e7eSjoerg // Addressing Mode #3 43206f32e7eSjoerg //===--------------------------------------------------------------------===// 43306f32e7eSjoerg // 43406f32e7eSjoerg // This is used for sign-extending loads, and load/store-pair instructions. 43506f32e7eSjoerg // 43606f32e7eSjoerg // addrmode3 := reg +/- reg 43706f32e7eSjoerg // addrmode3 := reg +/- imm8 43806f32e7eSjoerg // 43906f32e7eSjoerg // The first operand is always a Reg. The second operand is a reg if in 44006f32e7eSjoerg // reg/reg form, otherwise it's reg#0. The third field encodes the operation 44106f32e7eSjoerg // in bit 8, the immediate in bits 0-7. The fourth operand 9-10 encodes the 44206f32e7eSjoerg // index mode. 44306f32e7eSjoerg 44406f32e7eSjoerg /// getAM3Opc - This function encodes the addrmode3 opc field. 44506f32e7eSjoerg inline unsigned getAM3Opc(AddrOpc Opc, unsigned char Offset, 44606f32e7eSjoerg unsigned IdxMode = 0) { 44706f32e7eSjoerg bool isSub = Opc == sub; 44806f32e7eSjoerg return ((int)isSub << 8) | Offset | (IdxMode << 9); 44906f32e7eSjoerg } getAM3Offset(unsigned AM3Opc)45006f32e7eSjoerg inline unsigned char getAM3Offset(unsigned AM3Opc) { return AM3Opc & 0xFF; } getAM3Op(unsigned AM3Opc)45106f32e7eSjoerg inline AddrOpc getAM3Op(unsigned AM3Opc) { 45206f32e7eSjoerg return ((AM3Opc >> 8) & 1) ? sub : add; 45306f32e7eSjoerg } getAM3IdxMode(unsigned AM3Opc)45406f32e7eSjoerg inline unsigned getAM3IdxMode(unsigned AM3Opc) { return (AM3Opc >> 9); } 45506f32e7eSjoerg 45606f32e7eSjoerg //===--------------------------------------------------------------------===// 45706f32e7eSjoerg // Addressing Mode #4 45806f32e7eSjoerg //===--------------------------------------------------------------------===// 45906f32e7eSjoerg // 46006f32e7eSjoerg // This is used for load / store multiple instructions. 46106f32e7eSjoerg // 46206f32e7eSjoerg // addrmode4 := reg, <mode> 46306f32e7eSjoerg // 46406f32e7eSjoerg // The four modes are: 46506f32e7eSjoerg // IA - Increment after 46606f32e7eSjoerg // IB - Increment before 46706f32e7eSjoerg // DA - Decrement after 46806f32e7eSjoerg // DB - Decrement before 46906f32e7eSjoerg // For VFP instructions, only the IA and DB modes are valid. 47006f32e7eSjoerg getAM4SubMode(unsigned Mode)47106f32e7eSjoerg inline AMSubMode getAM4SubMode(unsigned Mode) { 47206f32e7eSjoerg return (AMSubMode)(Mode & 0x7); 47306f32e7eSjoerg } 47406f32e7eSjoerg getAM4ModeImm(AMSubMode SubMode)47506f32e7eSjoerg inline unsigned getAM4ModeImm(AMSubMode SubMode) { return (int)SubMode; } 47606f32e7eSjoerg 47706f32e7eSjoerg //===--------------------------------------------------------------------===// 47806f32e7eSjoerg // Addressing Mode #5 47906f32e7eSjoerg //===--------------------------------------------------------------------===// 48006f32e7eSjoerg // 48106f32e7eSjoerg // This is used for coprocessor instructions, such as FP load/stores. 48206f32e7eSjoerg // 48306f32e7eSjoerg // addrmode5 := reg +/- imm8*4 48406f32e7eSjoerg // 48506f32e7eSjoerg // The first operand is always a Reg. The second operand encodes the 48606f32e7eSjoerg // operation (add or subtract) in bit 8 and the immediate in bits 0-7. 48706f32e7eSjoerg 48806f32e7eSjoerg /// getAM5Opc - This function encodes the addrmode5 opc field. getAM5Opc(AddrOpc Opc,unsigned char Offset)48906f32e7eSjoerg inline unsigned getAM5Opc(AddrOpc Opc, unsigned char Offset) { 49006f32e7eSjoerg bool isSub = Opc == sub; 49106f32e7eSjoerg return ((int)isSub << 8) | Offset; 49206f32e7eSjoerg } getAM5Offset(unsigned AM5Opc)49306f32e7eSjoerg inline unsigned char getAM5Offset(unsigned AM5Opc) { return AM5Opc & 0xFF; } getAM5Op(unsigned AM5Opc)49406f32e7eSjoerg inline AddrOpc getAM5Op(unsigned AM5Opc) { 49506f32e7eSjoerg return ((AM5Opc >> 8) & 1) ? sub : add; 49606f32e7eSjoerg } 49706f32e7eSjoerg 49806f32e7eSjoerg //===--------------------------------------------------------------------===// 49906f32e7eSjoerg // Addressing Mode #5 FP16 50006f32e7eSjoerg //===--------------------------------------------------------------------===// 50106f32e7eSjoerg // 50206f32e7eSjoerg // This is used for coprocessor instructions, such as 16-bit FP load/stores. 50306f32e7eSjoerg // 50406f32e7eSjoerg // addrmode5fp16 := reg +/- imm8*2 50506f32e7eSjoerg // 50606f32e7eSjoerg // The first operand is always a Reg. The second operand encodes the 50706f32e7eSjoerg // operation (add or subtract) in bit 8 and the immediate in bits 0-7. 50806f32e7eSjoerg 50906f32e7eSjoerg /// getAM5FP16Opc - This function encodes the addrmode5fp16 opc field. getAM5FP16Opc(AddrOpc Opc,unsigned char Offset)51006f32e7eSjoerg inline unsigned getAM5FP16Opc(AddrOpc Opc, unsigned char Offset) { 51106f32e7eSjoerg bool isSub = Opc == sub; 51206f32e7eSjoerg return ((int)isSub << 8) | Offset; 51306f32e7eSjoerg } getAM5FP16Offset(unsigned AM5Opc)51406f32e7eSjoerg inline unsigned char getAM5FP16Offset(unsigned AM5Opc) { 51506f32e7eSjoerg return AM5Opc & 0xFF; 51606f32e7eSjoerg } getAM5FP16Op(unsigned AM5Opc)51706f32e7eSjoerg inline AddrOpc getAM5FP16Op(unsigned AM5Opc) { 51806f32e7eSjoerg return ((AM5Opc >> 8) & 1) ? sub : add; 51906f32e7eSjoerg } 52006f32e7eSjoerg 52106f32e7eSjoerg //===--------------------------------------------------------------------===// 52206f32e7eSjoerg // Addressing Mode #6 52306f32e7eSjoerg //===--------------------------------------------------------------------===// 52406f32e7eSjoerg // 52506f32e7eSjoerg // This is used for NEON load / store instructions. 52606f32e7eSjoerg // 52706f32e7eSjoerg // addrmode6 := reg with optional alignment 52806f32e7eSjoerg // 52906f32e7eSjoerg // This is stored in two operands [regaddr, align]. The first is the 53006f32e7eSjoerg // address register. The second operand is the value of the alignment 53106f32e7eSjoerg // specifier in bytes or zero if no explicit alignment. 53206f32e7eSjoerg // Valid alignments depend on the specific instruction. 53306f32e7eSjoerg 53406f32e7eSjoerg //===--------------------------------------------------------------------===// 53506f32e7eSjoerg // NEON/MVE Modified Immediates 53606f32e7eSjoerg //===--------------------------------------------------------------------===// 53706f32e7eSjoerg // 53806f32e7eSjoerg // Several NEON and MVE instructions (e.g., VMOV) take a "modified immediate" 53906f32e7eSjoerg // vector operand, where a small immediate encoded in the instruction 54006f32e7eSjoerg // specifies a full NEON vector value. These modified immediates are 54106f32e7eSjoerg // represented here as encoded integers. The low 8 bits hold the immediate 54206f32e7eSjoerg // value; bit 12 holds the "Op" field of the instruction, and bits 11-8 hold 54306f32e7eSjoerg // the "Cmode" field of the instruction. The interfaces below treat the 54406f32e7eSjoerg // Op and Cmode values as a single 5-bit value. 54506f32e7eSjoerg createVMOVModImm(unsigned OpCmode,unsigned Val)54606f32e7eSjoerg inline unsigned createVMOVModImm(unsigned OpCmode, unsigned Val) { 54706f32e7eSjoerg return (OpCmode << 8) | Val; 54806f32e7eSjoerg } getVMOVModImmOpCmode(unsigned ModImm)54906f32e7eSjoerg inline unsigned getVMOVModImmOpCmode(unsigned ModImm) { 55006f32e7eSjoerg return (ModImm >> 8) & 0x1f; 55106f32e7eSjoerg } getVMOVModImmVal(unsigned ModImm)55206f32e7eSjoerg inline unsigned getVMOVModImmVal(unsigned ModImm) { return ModImm & 0xff; } 55306f32e7eSjoerg 55406f32e7eSjoerg /// decodeVMOVModImm - Decode a NEON/MVE modified immediate value into the 55506f32e7eSjoerg /// element value and the element size in bits. (If the element size is 55606f32e7eSjoerg /// smaller than the vector, it is splatted into all the elements.) decodeVMOVModImm(unsigned ModImm,unsigned & EltBits)55706f32e7eSjoerg inline uint64_t decodeVMOVModImm(unsigned ModImm, unsigned &EltBits) { 55806f32e7eSjoerg unsigned OpCmode = getVMOVModImmOpCmode(ModImm); 55906f32e7eSjoerg unsigned Imm8 = getVMOVModImmVal(ModImm); 56006f32e7eSjoerg uint64_t Val = 0; 56106f32e7eSjoerg 56206f32e7eSjoerg if (OpCmode == 0xe) { 56306f32e7eSjoerg // 8-bit vector elements 56406f32e7eSjoerg Val = Imm8; 56506f32e7eSjoerg EltBits = 8; 56606f32e7eSjoerg } else if ((OpCmode & 0xc) == 0x8) { 56706f32e7eSjoerg // 16-bit vector elements 56806f32e7eSjoerg unsigned ByteNum = (OpCmode & 0x6) >> 1; 56906f32e7eSjoerg Val = Imm8 << (8 * ByteNum); 57006f32e7eSjoerg EltBits = 16; 57106f32e7eSjoerg } else if ((OpCmode & 0x8) == 0) { 57206f32e7eSjoerg // 32-bit vector elements, zero with one byte set 57306f32e7eSjoerg unsigned ByteNum = (OpCmode & 0x6) >> 1; 57406f32e7eSjoerg Val = Imm8 << (8 * ByteNum); 57506f32e7eSjoerg EltBits = 32; 57606f32e7eSjoerg } else if ((OpCmode & 0xe) == 0xc) { 57706f32e7eSjoerg // 32-bit vector elements, one byte with low bits set 57806f32e7eSjoerg unsigned ByteNum = 1 + (OpCmode & 0x1); 57906f32e7eSjoerg Val = (Imm8 << (8 * ByteNum)) | (0xffff >> (8 * (2 - ByteNum))); 58006f32e7eSjoerg EltBits = 32; 58106f32e7eSjoerg } else if (OpCmode == 0x1e) { 58206f32e7eSjoerg // 64-bit vector elements 58306f32e7eSjoerg for (unsigned ByteNum = 0; ByteNum < 8; ++ByteNum) { 58406f32e7eSjoerg if ((ModImm >> ByteNum) & 1) 58506f32e7eSjoerg Val |= (uint64_t)0xff << (8 * ByteNum); 58606f32e7eSjoerg } 58706f32e7eSjoerg EltBits = 64; 58806f32e7eSjoerg } else { 58906f32e7eSjoerg llvm_unreachable("Unsupported VMOV immediate"); 59006f32e7eSjoerg } 59106f32e7eSjoerg return Val; 59206f32e7eSjoerg } 59306f32e7eSjoerg 59406f32e7eSjoerg // Generic validation for single-byte immediate (0X00, 00X0, etc). isNEONBytesplat(unsigned Value,unsigned Size)59506f32e7eSjoerg inline bool isNEONBytesplat(unsigned Value, unsigned Size) { 59606f32e7eSjoerg assert(Size >= 1 && Size <= 4 && "Invalid size"); 59706f32e7eSjoerg unsigned count = 0; 59806f32e7eSjoerg for (unsigned i = 0; i < Size; ++i) { 59906f32e7eSjoerg if (Value & 0xff) count++; 60006f32e7eSjoerg Value >>= 8; 60106f32e7eSjoerg } 60206f32e7eSjoerg return count == 1; 60306f32e7eSjoerg } 60406f32e7eSjoerg 60506f32e7eSjoerg /// Checks if Value is a correct immediate for instructions like VBIC/VORR. isNEONi16splat(unsigned Value)60606f32e7eSjoerg inline bool isNEONi16splat(unsigned Value) { 60706f32e7eSjoerg if (Value > 0xffff) 60806f32e7eSjoerg return false; 60906f32e7eSjoerg // i16 value with set bits only in one byte X0 or 0X. 61006f32e7eSjoerg return Value == 0 || isNEONBytesplat(Value, 2); 61106f32e7eSjoerg } 61206f32e7eSjoerg 61306f32e7eSjoerg // Encode NEON 16 bits Splat immediate for instructions like VBIC/VORR encodeNEONi16splat(unsigned Value)61406f32e7eSjoerg inline unsigned encodeNEONi16splat(unsigned Value) { 61506f32e7eSjoerg assert(isNEONi16splat(Value) && "Invalid NEON splat value"); 61606f32e7eSjoerg if (Value >= 0x100) 61706f32e7eSjoerg Value = (Value >> 8) | 0xa00; 61806f32e7eSjoerg else 61906f32e7eSjoerg Value |= 0x800; 62006f32e7eSjoerg return Value; 62106f32e7eSjoerg } 62206f32e7eSjoerg 62306f32e7eSjoerg /// Checks if Value is a correct immediate for instructions like VBIC/VORR. isNEONi32splat(unsigned Value)62406f32e7eSjoerg inline bool isNEONi32splat(unsigned Value) { 62506f32e7eSjoerg // i32 value with set bits only in one byte X000, 0X00, 00X0, or 000X. 62606f32e7eSjoerg return Value == 0 || isNEONBytesplat(Value, 4); 62706f32e7eSjoerg } 62806f32e7eSjoerg 62906f32e7eSjoerg /// Encode NEON 32 bits Splat immediate for instructions like VBIC/VORR. encodeNEONi32splat(unsigned Value)63006f32e7eSjoerg inline unsigned encodeNEONi32splat(unsigned Value) { 63106f32e7eSjoerg assert(isNEONi32splat(Value) && "Invalid NEON splat value"); 63206f32e7eSjoerg if (Value >= 0x100 && Value <= 0xff00) 63306f32e7eSjoerg Value = (Value >> 8) | 0x200; 63406f32e7eSjoerg else if (Value > 0xffff && Value <= 0xff0000) 63506f32e7eSjoerg Value = (Value >> 16) | 0x400; 63606f32e7eSjoerg else if (Value > 0xffffff) 63706f32e7eSjoerg Value = (Value >> 24) | 0x600; 63806f32e7eSjoerg return Value; 63906f32e7eSjoerg } 64006f32e7eSjoerg 64106f32e7eSjoerg //===--------------------------------------------------------------------===// 64206f32e7eSjoerg // Floating-point Immediates 64306f32e7eSjoerg // getFPImmFloat(unsigned Imm)64406f32e7eSjoerg inline float getFPImmFloat(unsigned Imm) { 64506f32e7eSjoerg // We expect an 8-bit binary encoding of a floating-point number here. 64606f32e7eSjoerg 64706f32e7eSjoerg uint8_t Sign = (Imm >> 7) & 0x1; 64806f32e7eSjoerg uint8_t Exp = (Imm >> 4) & 0x7; 64906f32e7eSjoerg uint8_t Mantissa = Imm & 0xf; 65006f32e7eSjoerg 65106f32e7eSjoerg // 8-bit FP IEEE Float Encoding 65206f32e7eSjoerg // abcd efgh aBbbbbbc defgh000 00000000 00000000 65306f32e7eSjoerg // 65406f32e7eSjoerg // where B = NOT(b); 65506f32e7eSjoerg uint32_t I = 0; 65606f32e7eSjoerg I |= Sign << 31; 65706f32e7eSjoerg I |= ((Exp & 0x4) != 0 ? 0 : 1) << 30; 65806f32e7eSjoerg I |= ((Exp & 0x4) != 0 ? 0x1f : 0) << 25; 65906f32e7eSjoerg I |= (Exp & 0x3) << 23; 66006f32e7eSjoerg I |= Mantissa << 19; 66106f32e7eSjoerg return bit_cast<float>(I); 66206f32e7eSjoerg } 66306f32e7eSjoerg 66406f32e7eSjoerg /// getFP16Imm - Return an 8-bit floating-point version of the 16-bit 66506f32e7eSjoerg /// floating-point value. If the value cannot be represented as an 8-bit 66606f32e7eSjoerg /// floating-point value, then return -1. getFP16Imm(const APInt & Imm)66706f32e7eSjoerg inline int getFP16Imm(const APInt &Imm) { 66806f32e7eSjoerg uint32_t Sign = Imm.lshr(15).getZExtValue() & 1; 66906f32e7eSjoerg int32_t Exp = (Imm.lshr(10).getSExtValue() & 0x1f) - 15; // -14 to 15 67006f32e7eSjoerg int64_t Mantissa = Imm.getZExtValue() & 0x3ff; // 10 bits 67106f32e7eSjoerg 67206f32e7eSjoerg // We can handle 4 bits of mantissa. 67306f32e7eSjoerg // mantissa = (16+UInt(e:f:g:h))/16. 67406f32e7eSjoerg if (Mantissa & 0x3f) 67506f32e7eSjoerg return -1; 67606f32e7eSjoerg Mantissa >>= 6; 67706f32e7eSjoerg 67806f32e7eSjoerg // We can handle 3 bits of exponent: exp == UInt(NOT(b):c:d)-3 67906f32e7eSjoerg if (Exp < -3 || Exp > 4) 68006f32e7eSjoerg return -1; 68106f32e7eSjoerg Exp = ((Exp+3) & 0x7) ^ 4; 68206f32e7eSjoerg 68306f32e7eSjoerg return ((int)Sign << 7) | (Exp << 4) | Mantissa; 68406f32e7eSjoerg } 68506f32e7eSjoerg getFP16Imm(const APFloat & FPImm)68606f32e7eSjoerg inline int getFP16Imm(const APFloat &FPImm) { 68706f32e7eSjoerg return getFP16Imm(FPImm.bitcastToAPInt()); 68806f32e7eSjoerg } 68906f32e7eSjoerg 690*da58b97aSjoerg /// If this is a FP16Imm encoded as a fp32 value, return the 8-bit encoding 691*da58b97aSjoerg /// for it. Otherwise return -1 like getFP16Imm. getFP32FP16Imm(const APInt & Imm)692*da58b97aSjoerg inline int getFP32FP16Imm(const APInt &Imm) { 693*da58b97aSjoerg if (Imm.getActiveBits() > 16) 694*da58b97aSjoerg return -1; 695*da58b97aSjoerg return ARM_AM::getFP16Imm(Imm.trunc(16)); 696*da58b97aSjoerg } 697*da58b97aSjoerg getFP32FP16Imm(const APFloat & FPImm)698*da58b97aSjoerg inline int getFP32FP16Imm(const APFloat &FPImm) { 699*da58b97aSjoerg return getFP32FP16Imm(FPImm.bitcastToAPInt()); 700*da58b97aSjoerg } 701*da58b97aSjoerg 70206f32e7eSjoerg /// getFP32Imm - Return an 8-bit floating-point version of the 32-bit 70306f32e7eSjoerg /// floating-point value. If the value cannot be represented as an 8-bit 70406f32e7eSjoerg /// floating-point value, then return -1. getFP32Imm(const APInt & Imm)70506f32e7eSjoerg inline int getFP32Imm(const APInt &Imm) { 70606f32e7eSjoerg uint32_t Sign = Imm.lshr(31).getZExtValue() & 1; 70706f32e7eSjoerg int32_t Exp = (Imm.lshr(23).getSExtValue() & 0xff) - 127; // -126 to 127 70806f32e7eSjoerg int64_t Mantissa = Imm.getZExtValue() & 0x7fffff; // 23 bits 70906f32e7eSjoerg 71006f32e7eSjoerg // We can handle 4 bits of mantissa. 71106f32e7eSjoerg // mantissa = (16+UInt(e:f:g:h))/16. 71206f32e7eSjoerg if (Mantissa & 0x7ffff) 71306f32e7eSjoerg return -1; 71406f32e7eSjoerg Mantissa >>= 19; 71506f32e7eSjoerg if ((Mantissa & 0xf) != Mantissa) 71606f32e7eSjoerg return -1; 71706f32e7eSjoerg 71806f32e7eSjoerg // We can handle 3 bits of exponent: exp == UInt(NOT(b):c:d)-3 71906f32e7eSjoerg if (Exp < -3 || Exp > 4) 72006f32e7eSjoerg return -1; 72106f32e7eSjoerg Exp = ((Exp+3) & 0x7) ^ 4; 72206f32e7eSjoerg 72306f32e7eSjoerg return ((int)Sign << 7) | (Exp << 4) | Mantissa; 72406f32e7eSjoerg } 72506f32e7eSjoerg getFP32Imm(const APFloat & FPImm)72606f32e7eSjoerg inline int getFP32Imm(const APFloat &FPImm) { 72706f32e7eSjoerg return getFP32Imm(FPImm.bitcastToAPInt()); 72806f32e7eSjoerg } 72906f32e7eSjoerg 73006f32e7eSjoerg /// getFP64Imm - Return an 8-bit floating-point version of the 64-bit 73106f32e7eSjoerg /// floating-point value. If the value cannot be represented as an 8-bit 73206f32e7eSjoerg /// floating-point value, then return -1. getFP64Imm(const APInt & Imm)73306f32e7eSjoerg inline int getFP64Imm(const APInt &Imm) { 73406f32e7eSjoerg uint64_t Sign = Imm.lshr(63).getZExtValue() & 1; 73506f32e7eSjoerg int64_t Exp = (Imm.lshr(52).getSExtValue() & 0x7ff) - 1023; // -1022 to 1023 73606f32e7eSjoerg uint64_t Mantissa = Imm.getZExtValue() & 0xfffffffffffffULL; 73706f32e7eSjoerg 73806f32e7eSjoerg // We can handle 4 bits of mantissa. 73906f32e7eSjoerg // mantissa = (16+UInt(e:f:g:h))/16. 74006f32e7eSjoerg if (Mantissa & 0xffffffffffffULL) 74106f32e7eSjoerg return -1; 74206f32e7eSjoerg Mantissa >>= 48; 74306f32e7eSjoerg if ((Mantissa & 0xf) != Mantissa) 74406f32e7eSjoerg return -1; 74506f32e7eSjoerg 74606f32e7eSjoerg // We can handle 3 bits of exponent: exp == UInt(NOT(b):c:d)-3 74706f32e7eSjoerg if (Exp < -3 || Exp > 4) 74806f32e7eSjoerg return -1; 74906f32e7eSjoerg Exp = ((Exp+3) & 0x7) ^ 4; 75006f32e7eSjoerg 75106f32e7eSjoerg return ((int)Sign << 7) | (Exp << 4) | Mantissa; 75206f32e7eSjoerg } 75306f32e7eSjoerg getFP64Imm(const APFloat & FPImm)75406f32e7eSjoerg inline int getFP64Imm(const APFloat &FPImm) { 75506f32e7eSjoerg return getFP64Imm(FPImm.bitcastToAPInt()); 75606f32e7eSjoerg } 75706f32e7eSjoerg 75806f32e7eSjoerg } // end namespace ARM_AM 75906f32e7eSjoerg } // end namespace llvm 76006f32e7eSjoerg 76106f32e7eSjoerg #endif 76206f32e7eSjoerg 763