10b57cec5SDimitry Andric //===-- ARMAddressingModes.h - ARM Addressing Modes -------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file contains the ARM addressing mode implementation stuff. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #ifndef LLVM_LIB_TARGET_ARM_MCTARGETDESC_ARMADDRESSINGMODES_H 140b57cec5SDimitry Andric #define LLVM_LIB_TARGET_ARM_MCTARGETDESC_ARMADDRESSINGMODES_H 150b57cec5SDimitry Andric 160b57cec5SDimitry Andric #include "llvm/ADT/APFloat.h" 170b57cec5SDimitry Andric #include "llvm/ADT/APInt.h" 180b57cec5SDimitry Andric #include "llvm/ADT/bit.h" 190b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 200b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h" 210b57cec5SDimitry Andric #include <cassert> 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric namespace llvm { 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric /// ARM_AM - ARM Addressing Mode Stuff 260b57cec5SDimitry Andric namespace ARM_AM { 270b57cec5SDimitry Andric enum ShiftOpc { 280b57cec5SDimitry Andric no_shift = 0, 290b57cec5SDimitry Andric asr, 300b57cec5SDimitry Andric lsl, 310b57cec5SDimitry Andric lsr, 320b57cec5SDimitry Andric ror, 330b57cec5SDimitry Andric rrx, 340b57cec5SDimitry Andric uxtw 350b57cec5SDimitry Andric }; 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric enum AddrOpc { 380b57cec5SDimitry Andric sub = 0, 390b57cec5SDimitry Andric add 400b57cec5SDimitry Andric }; 410b57cec5SDimitry Andric getAddrOpcStr(AddrOpc Op)420b57cec5SDimitry Andric inline const char *getAddrOpcStr(AddrOpc Op) { return Op == sub ? "-" : ""; } 430b57cec5SDimitry Andric getShiftOpcStr(ShiftOpc Op)44*0fca6ea1SDimitry Andric inline const StringRef getShiftOpcStr(ShiftOpc Op) { 450b57cec5SDimitry Andric switch (Op) { 460b57cec5SDimitry Andric default: llvm_unreachable("Unknown shift opc!"); 470b57cec5SDimitry Andric case ARM_AM::asr: return "asr"; 480b57cec5SDimitry Andric case ARM_AM::lsl: return "lsl"; 490b57cec5SDimitry Andric case ARM_AM::lsr: return "lsr"; 500b57cec5SDimitry Andric case ARM_AM::ror: return "ror"; 510b57cec5SDimitry Andric case ARM_AM::rrx: return "rrx"; 520b57cec5SDimitry Andric case ARM_AM::uxtw: return "uxtw"; 530b57cec5SDimitry Andric } 540b57cec5SDimitry Andric } 550b57cec5SDimitry Andric getShiftOpcEncoding(ShiftOpc Op)560b57cec5SDimitry Andric inline unsigned getShiftOpcEncoding(ShiftOpc Op) { 570b57cec5SDimitry Andric switch (Op) { 580b57cec5SDimitry Andric default: llvm_unreachable("Unknown shift opc!"); 590b57cec5SDimitry Andric case ARM_AM::asr: return 2; 600b57cec5SDimitry Andric case ARM_AM::lsl: return 0; 610b57cec5SDimitry Andric case ARM_AM::lsr: return 1; 620b57cec5SDimitry Andric case ARM_AM::ror: return 3; 630b57cec5SDimitry Andric } 640b57cec5SDimitry Andric } 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric enum AMSubMode { 670b57cec5SDimitry Andric bad_am_submode = 0, 680b57cec5SDimitry Andric ia, 690b57cec5SDimitry Andric ib, 700b57cec5SDimitry Andric da, 710b57cec5SDimitry Andric db 720b57cec5SDimitry Andric }; 730b57cec5SDimitry Andric getAMSubModeStr(AMSubMode Mode)740b57cec5SDimitry Andric inline const char *getAMSubModeStr(AMSubMode Mode) { 750b57cec5SDimitry Andric switch (Mode) { 760b57cec5SDimitry Andric default: llvm_unreachable("Unknown addressing sub-mode!"); 770b57cec5SDimitry Andric case ARM_AM::ia: return "ia"; 780b57cec5SDimitry Andric case ARM_AM::ib: return "ib"; 790b57cec5SDimitry Andric case ARM_AM::da: return "da"; 800b57cec5SDimitry Andric case ARM_AM::db: return "db"; 810b57cec5SDimitry Andric } 820b57cec5SDimitry Andric } 830b57cec5SDimitry Andric 840b57cec5SDimitry Andric //===--------------------------------------------------------------------===// 850b57cec5SDimitry Andric // Addressing Mode #1: shift_operand with registers 860b57cec5SDimitry Andric //===--------------------------------------------------------------------===// 870b57cec5SDimitry Andric // 880b57cec5SDimitry Andric // This 'addressing mode' is used for arithmetic instructions. It can 890b57cec5SDimitry Andric // represent things like: 900b57cec5SDimitry Andric // reg 910b57cec5SDimitry Andric // reg [asr|lsl|lsr|ror|rrx] reg 920b57cec5SDimitry Andric // reg [asr|lsl|lsr|ror|rrx] imm 930b57cec5SDimitry Andric // 940b57cec5SDimitry Andric // This is stored three operands [rega, regb, opc]. The first is the base 950b57cec5SDimitry Andric // reg, the second is the shift amount (or reg0 if not present or imm). The 960b57cec5SDimitry Andric // third operand encodes the shift opcode and the imm if a reg isn't present. 970b57cec5SDimitry Andric // getSORegOpc(ShiftOpc ShOp,unsigned Imm)980b57cec5SDimitry Andric inline unsigned getSORegOpc(ShiftOpc ShOp, unsigned Imm) { 990b57cec5SDimitry Andric return ShOp | (Imm << 3); 1000b57cec5SDimitry Andric } getSORegOffset(unsigned Op)1010b57cec5SDimitry Andric inline unsigned getSORegOffset(unsigned Op) { return Op >> 3; } getSORegShOp(unsigned Op)1020b57cec5SDimitry Andric inline ShiftOpc getSORegShOp(unsigned Op) { return (ShiftOpc)(Op & 7); } 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric /// getSOImmValImm - Given an encoded imm field for the reg/imm form, return 1050b57cec5SDimitry Andric /// the 8-bit imm value. getSOImmValImm(unsigned Imm)1060b57cec5SDimitry Andric inline unsigned getSOImmValImm(unsigned Imm) { return Imm & 0xFF; } 1070b57cec5SDimitry Andric /// getSOImmValRot - Given an encoded imm field for the reg/imm form, return 1080b57cec5SDimitry Andric /// the rotate amount. getSOImmValRot(unsigned Imm)1090b57cec5SDimitry Andric inline unsigned getSOImmValRot(unsigned Imm) { return (Imm >> 8) * 2; } 1100b57cec5SDimitry Andric 1110b57cec5SDimitry Andric /// getSOImmValRotate - Try to handle Imm with an immediate shifter operand, 1120b57cec5SDimitry Andric /// computing the rotate amount to use. If this immediate value cannot be 1130b57cec5SDimitry Andric /// handled with a single shifter-op, determine a good rotate amount that will 1140b57cec5SDimitry Andric /// take a maximal chunk of bits out of the immediate. getSOImmValRotate(unsigned Imm)1150b57cec5SDimitry Andric inline unsigned getSOImmValRotate(unsigned Imm) { 1160b57cec5SDimitry Andric // 8-bit (or less) immediates are trivially shifter_operands with a rotate 1170b57cec5SDimitry Andric // of zero. 1180b57cec5SDimitry Andric if ((Imm & ~255U) == 0) return 0; 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric // Use CTZ to compute the rotate amount. 12106c3fb27SDimitry Andric unsigned TZ = llvm::countr_zero(Imm); 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric // Rotate amount must be even. Something like 0x200 must be rotated 8 bits, 1240b57cec5SDimitry Andric // not 9. 1250b57cec5SDimitry Andric unsigned RotAmt = TZ & ~1; 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric // If we can handle this spread, return it. 12806c3fb27SDimitry Andric if ((llvm::rotr<uint32_t>(Imm, RotAmt) & ~255U) == 0) 1290b57cec5SDimitry Andric return (32-RotAmt)&31; // HW rotates right, not left. 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric // For values like 0xF000000F, we should ignore the low 6 bits, then 1320b57cec5SDimitry Andric // retry the hunt. 1330b57cec5SDimitry Andric if (Imm & 63U) { 13406c3fb27SDimitry Andric unsigned TZ2 = llvm::countr_zero(Imm & ~63U); 1350b57cec5SDimitry Andric unsigned RotAmt2 = TZ2 & ~1; 13606c3fb27SDimitry Andric if ((llvm::rotr<uint32_t>(Imm, RotAmt2) & ~255U) == 0) 1370b57cec5SDimitry Andric return (32-RotAmt2)&31; // HW rotates right, not left. 1380b57cec5SDimitry Andric } 1390b57cec5SDimitry Andric 1400b57cec5SDimitry Andric // Otherwise, we have no way to cover this span of bits with a single 1410b57cec5SDimitry Andric // shifter_op immediate. Return a chunk of bits that will be useful to 1420b57cec5SDimitry Andric // handle. 1430b57cec5SDimitry Andric return (32-RotAmt)&31; // HW rotates right, not left. 1440b57cec5SDimitry Andric } 1450b57cec5SDimitry Andric 1460b57cec5SDimitry Andric /// getSOImmVal - Given a 32-bit immediate, if it is something that can fit 1470b57cec5SDimitry Andric /// into an shifter_operand immediate operand, return the 12-bit encoding for 1480b57cec5SDimitry Andric /// it. If not, return -1. getSOImmVal(unsigned Arg)1490b57cec5SDimitry Andric inline int getSOImmVal(unsigned Arg) { 1500b57cec5SDimitry Andric // 8-bit (or less) immediates are trivially shifter_operands with a rotate 1510b57cec5SDimitry Andric // of zero. 1520b57cec5SDimitry Andric if ((Arg & ~255U) == 0) return Arg; 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric unsigned RotAmt = getSOImmValRotate(Arg); 1550b57cec5SDimitry Andric 1560b57cec5SDimitry Andric // If this cannot be handled with a single shifter_op, bail out. 15706c3fb27SDimitry Andric if (llvm::rotr<uint32_t>(~255U, RotAmt) & Arg) 1580b57cec5SDimitry Andric return -1; 1590b57cec5SDimitry Andric 1600b57cec5SDimitry Andric // Encode this correctly. 16106c3fb27SDimitry Andric return llvm::rotl<uint32_t>(Arg, RotAmt) | ((RotAmt >> 1) << 8); 1620b57cec5SDimitry Andric } 1630b57cec5SDimitry Andric 1640b57cec5SDimitry Andric /// isSOImmTwoPartVal - Return true if the specified value can be obtained by 1650b57cec5SDimitry Andric /// or'ing together two SOImmVal's. isSOImmTwoPartVal(unsigned V)1660b57cec5SDimitry Andric inline bool isSOImmTwoPartVal(unsigned V) { 1670b57cec5SDimitry Andric // If this can be handled with a single shifter_op, bail out. 16806c3fb27SDimitry Andric V = llvm::rotr<uint32_t>(~255U, getSOImmValRotate(V)) & V; 1690b57cec5SDimitry Andric if (V == 0) 1700b57cec5SDimitry Andric return false; 1710b57cec5SDimitry Andric 1720b57cec5SDimitry Andric // If this can be handled with two shifter_op's, accept. 17306c3fb27SDimitry Andric V = llvm::rotr<uint32_t>(~255U, getSOImmValRotate(V)) & V; 1740b57cec5SDimitry Andric return V == 0; 1750b57cec5SDimitry Andric } 1760b57cec5SDimitry Andric 1770b57cec5SDimitry Andric /// getSOImmTwoPartFirst - If V is a value that satisfies isSOImmTwoPartVal, 1780b57cec5SDimitry Andric /// return the first chunk of it. getSOImmTwoPartFirst(unsigned V)1790b57cec5SDimitry Andric inline unsigned getSOImmTwoPartFirst(unsigned V) { 18006c3fb27SDimitry Andric return llvm::rotr<uint32_t>(255U, getSOImmValRotate(V)) & V; 1810b57cec5SDimitry Andric } 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric /// getSOImmTwoPartSecond - If V is a value that satisfies isSOImmTwoPartVal, 1840b57cec5SDimitry Andric /// return the second chunk of it. getSOImmTwoPartSecond(unsigned V)1850b57cec5SDimitry Andric inline unsigned getSOImmTwoPartSecond(unsigned V) { 1860b57cec5SDimitry Andric // Mask out the first hunk. 18706c3fb27SDimitry Andric V = llvm::rotr<uint32_t>(~255U, getSOImmValRotate(V)) & V; 1880b57cec5SDimitry Andric 1890b57cec5SDimitry Andric // Take what's left. 19006c3fb27SDimitry Andric assert(V == (llvm::rotr<uint32_t>(255U, getSOImmValRotate(V)) & V)); 1910b57cec5SDimitry Andric return V; 1920b57cec5SDimitry Andric } 1930b57cec5SDimitry Andric 194e8d8bef9SDimitry Andric /// isSOImmTwoPartValNeg - Return true if the specified value can be obtained 195e8d8bef9SDimitry Andric /// by two SOImmVal, that -V = First + Second. 196e8d8bef9SDimitry Andric /// "R+V" can be optimized to (sub (sub R, First), Second). 197e8d8bef9SDimitry Andric /// "R=V" can be optimized to (sub (mvn R, ~(-First)), Second). isSOImmTwoPartValNeg(unsigned V)198e8d8bef9SDimitry Andric inline bool isSOImmTwoPartValNeg(unsigned V) { 199e8d8bef9SDimitry Andric unsigned First; 200e8d8bef9SDimitry Andric if (!isSOImmTwoPartVal(-V)) 201e8d8bef9SDimitry Andric return false; 202e8d8bef9SDimitry Andric // Return false if ~(-First) is not a SoImmval. 203e8d8bef9SDimitry Andric First = getSOImmTwoPartFirst(-V); 204e8d8bef9SDimitry Andric First = ~(-First); 20506c3fb27SDimitry Andric return !(llvm::rotr<uint32_t>(~255U, getSOImmValRotate(First)) & First); 206e8d8bef9SDimitry Andric } 207e8d8bef9SDimitry Andric 2080b57cec5SDimitry Andric /// getThumbImmValShift - Try to handle Imm with a 8-bit immediate followed 2090b57cec5SDimitry Andric /// by a left shift. Returns the shift amount to use. getThumbImmValShift(unsigned Imm)2100b57cec5SDimitry Andric inline unsigned getThumbImmValShift(unsigned Imm) { 2110b57cec5SDimitry Andric // 8-bit (or less) immediates are trivially immediate operand with a shift 2120b57cec5SDimitry Andric // of zero. 2130b57cec5SDimitry Andric if ((Imm & ~255U) == 0) return 0; 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric // Use CTZ to compute the shift amount. 21606c3fb27SDimitry Andric return llvm::countr_zero(Imm); 2170b57cec5SDimitry Andric } 2180b57cec5SDimitry Andric 2190b57cec5SDimitry Andric /// isThumbImmShiftedVal - Return true if the specified value can be obtained 2200b57cec5SDimitry Andric /// by left shifting a 8-bit immediate. isThumbImmShiftedVal(unsigned V)2210b57cec5SDimitry Andric inline bool isThumbImmShiftedVal(unsigned V) { 2220b57cec5SDimitry Andric // If this can be handled with 2230b57cec5SDimitry Andric V = (~255U << getThumbImmValShift(V)) & V; 2240b57cec5SDimitry Andric return V == 0; 2250b57cec5SDimitry Andric } 2260b57cec5SDimitry Andric 2270b57cec5SDimitry Andric /// getThumbImm16ValShift - Try to handle Imm with a 16-bit immediate followed 2280b57cec5SDimitry Andric /// by a left shift. Returns the shift amount to use. getThumbImm16ValShift(unsigned Imm)2290b57cec5SDimitry Andric inline unsigned getThumbImm16ValShift(unsigned Imm) { 2300b57cec5SDimitry Andric // 16-bit (or less) immediates are trivially immediate operand with a shift 2310b57cec5SDimitry Andric // of zero. 2320b57cec5SDimitry Andric if ((Imm & ~65535U) == 0) return 0; 2330b57cec5SDimitry Andric 2340b57cec5SDimitry Andric // Use CTZ to compute the shift amount. 23506c3fb27SDimitry Andric return llvm::countr_zero(Imm); 2360b57cec5SDimitry Andric } 2370b57cec5SDimitry Andric 2380b57cec5SDimitry Andric /// isThumbImm16ShiftedVal - Return true if the specified value can be 2390b57cec5SDimitry Andric /// obtained by left shifting a 16-bit immediate. isThumbImm16ShiftedVal(unsigned V)2400b57cec5SDimitry Andric inline bool isThumbImm16ShiftedVal(unsigned V) { 2410b57cec5SDimitry Andric // If this can be handled with 2420b57cec5SDimitry Andric V = (~65535U << getThumbImm16ValShift(V)) & V; 2430b57cec5SDimitry Andric return V == 0; 2440b57cec5SDimitry Andric } 2450b57cec5SDimitry Andric 2460b57cec5SDimitry Andric /// getThumbImmNonShiftedVal - If V is a value that satisfies 2470b57cec5SDimitry Andric /// isThumbImmShiftedVal, return the non-shiftd value. getThumbImmNonShiftedVal(unsigned V)2480b57cec5SDimitry Andric inline unsigned getThumbImmNonShiftedVal(unsigned V) { 2490b57cec5SDimitry Andric return V >> getThumbImmValShift(V); 2500b57cec5SDimitry Andric } 2510b57cec5SDimitry Andric 2520b57cec5SDimitry Andric 2530b57cec5SDimitry Andric /// getT2SOImmValSplat - Return the 12-bit encoded representation 2540b57cec5SDimitry Andric /// if the specified value can be obtained by splatting the low 8 bits 2550b57cec5SDimitry Andric /// into every other byte or every byte of a 32-bit value. i.e., 2560b57cec5SDimitry Andric /// 00000000 00000000 00000000 abcdefgh control = 0 2570b57cec5SDimitry Andric /// 00000000 abcdefgh 00000000 abcdefgh control = 1 2580b57cec5SDimitry Andric /// abcdefgh 00000000 abcdefgh 00000000 control = 2 2590b57cec5SDimitry Andric /// abcdefgh abcdefgh abcdefgh abcdefgh control = 3 2600b57cec5SDimitry Andric /// Return -1 if none of the above apply. 2610b57cec5SDimitry Andric /// See ARM Reference Manual A6.3.2. getT2SOImmValSplatVal(unsigned V)2620b57cec5SDimitry Andric inline int getT2SOImmValSplatVal(unsigned V) { 2630b57cec5SDimitry Andric unsigned u, Vs, Imm; 2640b57cec5SDimitry Andric // control = 0 2650b57cec5SDimitry Andric if ((V & 0xffffff00) == 0) 2660b57cec5SDimitry Andric return V; 2670b57cec5SDimitry Andric 2680b57cec5SDimitry Andric // If the value is zeroes in the first byte, just shift those off 2690b57cec5SDimitry Andric Vs = ((V & 0xff) == 0) ? V >> 8 : V; 2700b57cec5SDimitry Andric // Any passing value only has 8 bits of payload, splatted across the word 2710b57cec5SDimitry Andric Imm = Vs & 0xff; 2720b57cec5SDimitry Andric // Likewise, any passing values have the payload splatted into the 3rd byte 2730b57cec5SDimitry Andric u = Imm | (Imm << 16); 2740b57cec5SDimitry Andric 2750b57cec5SDimitry Andric // control = 1 or 2 2760b57cec5SDimitry Andric if (Vs == u) 2770b57cec5SDimitry Andric return (((Vs == V) ? 1 : 2) << 8) | Imm; 2780b57cec5SDimitry Andric 2790b57cec5SDimitry Andric // control = 3 2800b57cec5SDimitry Andric if (Vs == (u | (u << 8))) 2810b57cec5SDimitry Andric return (3 << 8) | Imm; 2820b57cec5SDimitry Andric 2830b57cec5SDimitry Andric return -1; 2840b57cec5SDimitry Andric } 2850b57cec5SDimitry Andric 2860b57cec5SDimitry Andric /// getT2SOImmValRotateVal - Return the 12-bit encoded representation if the 2870b57cec5SDimitry Andric /// specified value is a rotated 8-bit value. Return -1 if no rotation 2880b57cec5SDimitry Andric /// encoding is possible. 2890b57cec5SDimitry Andric /// See ARM Reference Manual A6.3.2. getT2SOImmValRotateVal(unsigned V)2900b57cec5SDimitry Andric inline int getT2SOImmValRotateVal(unsigned V) { 29106c3fb27SDimitry Andric unsigned RotAmt = llvm::countl_zero(V); 2920b57cec5SDimitry Andric if (RotAmt >= 24) 2930b57cec5SDimitry Andric return -1; 2940b57cec5SDimitry Andric 2950b57cec5SDimitry Andric // If 'Arg' can be handled with a single shifter_op return the value. 29606c3fb27SDimitry Andric if ((llvm::rotr<uint32_t>(0xff000000U, RotAmt) & V) == V) 29706c3fb27SDimitry Andric return (llvm::rotr<uint32_t>(V, 24 - RotAmt) & 0x7f) | 29806c3fb27SDimitry Andric ((RotAmt + 8) << 7); 2990b57cec5SDimitry Andric 3000b57cec5SDimitry Andric return -1; 3010b57cec5SDimitry Andric } 3020b57cec5SDimitry Andric 3030b57cec5SDimitry Andric /// getT2SOImmVal - Given a 32-bit immediate, if it is something that can fit 3040b57cec5SDimitry Andric /// into a Thumb-2 shifter_operand immediate operand, return the 12-bit 3050b57cec5SDimitry Andric /// encoding for it. If not, return -1. 3060b57cec5SDimitry Andric /// See ARM Reference Manual A6.3.2. getT2SOImmVal(unsigned Arg)3070b57cec5SDimitry Andric inline int getT2SOImmVal(unsigned Arg) { 3080b57cec5SDimitry Andric // If 'Arg' is an 8-bit splat, then get the encoded value. 3090b57cec5SDimitry Andric int Splat = getT2SOImmValSplatVal(Arg); 3100b57cec5SDimitry Andric if (Splat != -1) 3110b57cec5SDimitry Andric return Splat; 3120b57cec5SDimitry Andric 3130b57cec5SDimitry Andric // If 'Arg' can be handled with a single shifter_op return the value. 3140b57cec5SDimitry Andric int Rot = getT2SOImmValRotateVal(Arg); 3150b57cec5SDimitry Andric if (Rot != -1) 3160b57cec5SDimitry Andric return Rot; 3170b57cec5SDimitry Andric 3180b57cec5SDimitry Andric return -1; 3190b57cec5SDimitry Andric } 3200b57cec5SDimitry Andric getT2SOImmValRotate(unsigned V)3210b57cec5SDimitry Andric inline unsigned getT2SOImmValRotate(unsigned V) { 3220b57cec5SDimitry Andric if ((V & ~255U) == 0) return 0; 3230b57cec5SDimitry Andric // Use CTZ to compute the rotate amount. 32406c3fb27SDimitry Andric unsigned RotAmt = llvm::countr_zero(V); 3250b57cec5SDimitry Andric return (32 - RotAmt) & 31; 3260b57cec5SDimitry Andric } 3270b57cec5SDimitry Andric isT2SOImmTwoPartVal(unsigned Imm)3280b57cec5SDimitry Andric inline bool isT2SOImmTwoPartVal(unsigned Imm) { 3290b57cec5SDimitry Andric unsigned V = Imm; 3300b57cec5SDimitry Andric // Passing values can be any combination of splat values and shifter 3310b57cec5SDimitry Andric // values. If this can be handled with a single shifter or splat, bail 3320b57cec5SDimitry Andric // out. Those should be handled directly, not with a two-part val. 3330b57cec5SDimitry Andric if (getT2SOImmValSplatVal(V) != -1) 3340b57cec5SDimitry Andric return false; 33506c3fb27SDimitry Andric V = llvm::rotr<uint32_t>(~255U, getT2SOImmValRotate(V)) & V; 3360b57cec5SDimitry Andric if (V == 0) 3370b57cec5SDimitry Andric return false; 3380b57cec5SDimitry Andric 3390b57cec5SDimitry Andric // If this can be handled as an immediate, accept. 3400b57cec5SDimitry Andric if (getT2SOImmVal(V) != -1) return true; 3410b57cec5SDimitry Andric 3420b57cec5SDimitry Andric // Likewise, try masking out a splat value first. 3430b57cec5SDimitry Andric V = Imm; 3440b57cec5SDimitry Andric if (getT2SOImmValSplatVal(V & 0xff00ff00U) != -1) 3450b57cec5SDimitry Andric V &= ~0xff00ff00U; 3460b57cec5SDimitry Andric else if (getT2SOImmValSplatVal(V & 0x00ff00ffU) != -1) 3470b57cec5SDimitry Andric V &= ~0x00ff00ffU; 3480b57cec5SDimitry Andric // If what's left can be handled as an immediate, accept. 3490b57cec5SDimitry Andric if (getT2SOImmVal(V) != -1) return true; 3500b57cec5SDimitry Andric 3510b57cec5SDimitry Andric // Otherwise, do not accept. 3520b57cec5SDimitry Andric return false; 3530b57cec5SDimitry Andric } 3540b57cec5SDimitry Andric getT2SOImmTwoPartFirst(unsigned Imm)3550b57cec5SDimitry Andric inline unsigned getT2SOImmTwoPartFirst(unsigned Imm) { 3560b57cec5SDimitry Andric assert (isT2SOImmTwoPartVal(Imm) && 3570b57cec5SDimitry Andric "Immedate cannot be encoded as two part immediate!"); 3580b57cec5SDimitry Andric // Try a shifter operand as one part 35906c3fb27SDimitry Andric unsigned V = llvm::rotr<uint32_t>(~255, getT2SOImmValRotate(Imm)) & Imm; 3600b57cec5SDimitry Andric // If the rest is encodable as an immediate, then return it. 3610b57cec5SDimitry Andric if (getT2SOImmVal(V) != -1) return V; 3620b57cec5SDimitry Andric 3630b57cec5SDimitry Andric // Try masking out a splat value first. 3640b57cec5SDimitry Andric if (getT2SOImmValSplatVal(Imm & 0xff00ff00U) != -1) 3650b57cec5SDimitry Andric return Imm & 0xff00ff00U; 3660b57cec5SDimitry Andric 3670b57cec5SDimitry Andric // The other splat is all that's left as an option. 3680b57cec5SDimitry Andric assert (getT2SOImmValSplatVal(Imm & 0x00ff00ffU) != -1); 3690b57cec5SDimitry Andric return Imm & 0x00ff00ffU; 3700b57cec5SDimitry Andric } 3710b57cec5SDimitry Andric getT2SOImmTwoPartSecond(unsigned Imm)3720b57cec5SDimitry Andric inline unsigned getT2SOImmTwoPartSecond(unsigned Imm) { 3730b57cec5SDimitry Andric // Mask out the first hunk 3740b57cec5SDimitry Andric Imm ^= getT2SOImmTwoPartFirst(Imm); 3750b57cec5SDimitry Andric // Return what's left 3760b57cec5SDimitry Andric assert (getT2SOImmVal(Imm) != -1 && 3770b57cec5SDimitry Andric "Unable to encode second part of T2 two part SO immediate"); 3780b57cec5SDimitry Andric return Imm; 3790b57cec5SDimitry Andric } 3800b57cec5SDimitry Andric 3810b57cec5SDimitry Andric 3820b57cec5SDimitry Andric //===--------------------------------------------------------------------===// 3830b57cec5SDimitry Andric // Addressing Mode #2 3840b57cec5SDimitry Andric //===--------------------------------------------------------------------===// 3850b57cec5SDimitry Andric // 3860b57cec5SDimitry Andric // This is used for most simple load/store instructions. 3870b57cec5SDimitry Andric // 3880b57cec5SDimitry Andric // addrmode2 := reg +/- reg shop imm 3890b57cec5SDimitry Andric // addrmode2 := reg +/- imm12 3900b57cec5SDimitry Andric // 3910b57cec5SDimitry Andric // The first operand is always a Reg. The second operand is a reg if in 3920b57cec5SDimitry Andric // reg/reg form, otherwise it's reg#0. The third field encodes the operation 3930b57cec5SDimitry Andric // in bit 12, the immediate in bits 0-11, and the shift op in 13-15. The 3940b57cec5SDimitry Andric // fourth operand 16-17 encodes the index mode. 3950b57cec5SDimitry Andric // 3960b57cec5SDimitry Andric // If this addressing mode is a frame index (before prolog/epilog insertion 3970b57cec5SDimitry Andric // and code rewriting), this operand will have the form: FI#, reg0, <offs> 3980b57cec5SDimitry Andric // with no shift amount for the frame offset. 3990b57cec5SDimitry Andric // 4000b57cec5SDimitry Andric inline unsigned getAM2Opc(AddrOpc Opc, unsigned Imm12, ShiftOpc SO, 4010b57cec5SDimitry Andric unsigned IdxMode = 0) { 4020b57cec5SDimitry Andric assert(Imm12 < (1 << 12) && "Imm too large!"); 4030b57cec5SDimitry Andric bool isSub = Opc == sub; 4040b57cec5SDimitry Andric return Imm12 | ((int)isSub << 12) | (SO << 13) | (IdxMode << 16) ; 4050b57cec5SDimitry Andric } getAM2Offset(unsigned AM2Opc)4060b57cec5SDimitry Andric inline unsigned getAM2Offset(unsigned AM2Opc) { 4070b57cec5SDimitry Andric return AM2Opc & ((1 << 12)-1); 4080b57cec5SDimitry Andric } getAM2Op(unsigned AM2Opc)4090b57cec5SDimitry Andric inline AddrOpc getAM2Op(unsigned AM2Opc) { 4100b57cec5SDimitry Andric return ((AM2Opc >> 12) & 1) ? sub : add; 4110b57cec5SDimitry Andric } getAM2ShiftOpc(unsigned AM2Opc)4120b57cec5SDimitry Andric inline ShiftOpc getAM2ShiftOpc(unsigned AM2Opc) { 4130b57cec5SDimitry Andric return (ShiftOpc)((AM2Opc >> 13) & 7); 4140b57cec5SDimitry Andric } getAM2IdxMode(unsigned AM2Opc)4150b57cec5SDimitry Andric inline unsigned getAM2IdxMode(unsigned AM2Opc) { return (AM2Opc >> 16); } 4160b57cec5SDimitry Andric 4170b57cec5SDimitry Andric //===--------------------------------------------------------------------===// 4180b57cec5SDimitry Andric // Addressing Mode #3 4190b57cec5SDimitry Andric //===--------------------------------------------------------------------===// 4200b57cec5SDimitry Andric // 4210b57cec5SDimitry Andric // This is used for sign-extending loads, and load/store-pair instructions. 4220b57cec5SDimitry Andric // 4230b57cec5SDimitry Andric // addrmode3 := reg +/- reg 4240b57cec5SDimitry Andric // addrmode3 := reg +/- imm8 4250b57cec5SDimitry Andric // 4260b57cec5SDimitry Andric // The first operand is always a Reg. The second operand is a reg if in 4270b57cec5SDimitry Andric // reg/reg form, otherwise it's reg#0. The third field encodes the operation 4280b57cec5SDimitry Andric // in bit 8, the immediate in bits 0-7. The fourth operand 9-10 encodes the 4290b57cec5SDimitry Andric // index mode. 4300b57cec5SDimitry Andric 4310b57cec5SDimitry Andric /// getAM3Opc - This function encodes the addrmode3 opc field. 4320b57cec5SDimitry Andric inline unsigned getAM3Opc(AddrOpc Opc, unsigned char Offset, 4330b57cec5SDimitry Andric unsigned IdxMode = 0) { 4340b57cec5SDimitry Andric bool isSub = Opc == sub; 4350b57cec5SDimitry Andric return ((int)isSub << 8) | Offset | (IdxMode << 9); 4360b57cec5SDimitry Andric } getAM3Offset(unsigned AM3Opc)4370b57cec5SDimitry Andric inline unsigned char getAM3Offset(unsigned AM3Opc) { return AM3Opc & 0xFF; } getAM3Op(unsigned AM3Opc)4380b57cec5SDimitry Andric inline AddrOpc getAM3Op(unsigned AM3Opc) { 4390b57cec5SDimitry Andric return ((AM3Opc >> 8) & 1) ? sub : add; 4400b57cec5SDimitry Andric } getAM3IdxMode(unsigned AM3Opc)4410b57cec5SDimitry Andric inline unsigned getAM3IdxMode(unsigned AM3Opc) { return (AM3Opc >> 9); } 4420b57cec5SDimitry Andric 4430b57cec5SDimitry Andric //===--------------------------------------------------------------------===// 4440b57cec5SDimitry Andric // Addressing Mode #4 4450b57cec5SDimitry Andric //===--------------------------------------------------------------------===// 4460b57cec5SDimitry Andric // 4470b57cec5SDimitry Andric // This is used for load / store multiple instructions. 4480b57cec5SDimitry Andric // 4490b57cec5SDimitry Andric // addrmode4 := reg, <mode> 4500b57cec5SDimitry Andric // 4510b57cec5SDimitry Andric // The four modes are: 4520b57cec5SDimitry Andric // IA - Increment after 4530b57cec5SDimitry Andric // IB - Increment before 4540b57cec5SDimitry Andric // DA - Decrement after 4550b57cec5SDimitry Andric // DB - Decrement before 4560b57cec5SDimitry Andric // For VFP instructions, only the IA and DB modes are valid. 4570b57cec5SDimitry Andric getAM4SubMode(unsigned Mode)4580b57cec5SDimitry Andric inline AMSubMode getAM4SubMode(unsigned Mode) { 4590b57cec5SDimitry Andric return (AMSubMode)(Mode & 0x7); 4600b57cec5SDimitry Andric } 4610b57cec5SDimitry Andric getAM4ModeImm(AMSubMode SubMode)4620b57cec5SDimitry Andric inline unsigned getAM4ModeImm(AMSubMode SubMode) { return (int)SubMode; } 4630b57cec5SDimitry Andric 4640b57cec5SDimitry Andric //===--------------------------------------------------------------------===// 4650b57cec5SDimitry Andric // Addressing Mode #5 4660b57cec5SDimitry Andric //===--------------------------------------------------------------------===// 4670b57cec5SDimitry Andric // 4680b57cec5SDimitry Andric // This is used for coprocessor instructions, such as FP load/stores. 4690b57cec5SDimitry Andric // 4700b57cec5SDimitry Andric // addrmode5 := reg +/- imm8*4 4710b57cec5SDimitry Andric // 4720b57cec5SDimitry Andric // The first operand is always a Reg. The second operand encodes the 4730b57cec5SDimitry Andric // operation (add or subtract) in bit 8 and the immediate in bits 0-7. 4740b57cec5SDimitry Andric 4750b57cec5SDimitry Andric /// getAM5Opc - This function encodes the addrmode5 opc field. getAM5Opc(AddrOpc Opc,unsigned char Offset)4760b57cec5SDimitry Andric inline unsigned getAM5Opc(AddrOpc Opc, unsigned char Offset) { 4770b57cec5SDimitry Andric bool isSub = Opc == sub; 4780b57cec5SDimitry Andric return ((int)isSub << 8) | Offset; 4790b57cec5SDimitry Andric } getAM5Offset(unsigned AM5Opc)4800b57cec5SDimitry Andric inline unsigned char getAM5Offset(unsigned AM5Opc) { return AM5Opc & 0xFF; } getAM5Op(unsigned AM5Opc)4810b57cec5SDimitry Andric inline AddrOpc getAM5Op(unsigned AM5Opc) { 4820b57cec5SDimitry Andric return ((AM5Opc >> 8) & 1) ? sub : add; 4830b57cec5SDimitry Andric } 4840b57cec5SDimitry Andric 4850b57cec5SDimitry Andric //===--------------------------------------------------------------------===// 4860b57cec5SDimitry Andric // Addressing Mode #5 FP16 4870b57cec5SDimitry Andric //===--------------------------------------------------------------------===// 4880b57cec5SDimitry Andric // 4890b57cec5SDimitry Andric // This is used for coprocessor instructions, such as 16-bit FP load/stores. 4900b57cec5SDimitry Andric // 4910b57cec5SDimitry Andric // addrmode5fp16 := reg +/- imm8*2 4920b57cec5SDimitry Andric // 4930b57cec5SDimitry Andric // The first operand is always a Reg. The second operand encodes the 4940b57cec5SDimitry Andric // operation (add or subtract) in bit 8 and the immediate in bits 0-7. 4950b57cec5SDimitry Andric 4960b57cec5SDimitry Andric /// getAM5FP16Opc - This function encodes the addrmode5fp16 opc field. getAM5FP16Opc(AddrOpc Opc,unsigned char Offset)4970b57cec5SDimitry Andric inline unsigned getAM5FP16Opc(AddrOpc Opc, unsigned char Offset) { 4980b57cec5SDimitry Andric bool isSub = Opc == sub; 4990b57cec5SDimitry Andric return ((int)isSub << 8) | Offset; 5000b57cec5SDimitry Andric } getAM5FP16Offset(unsigned AM5Opc)5010b57cec5SDimitry Andric inline unsigned char getAM5FP16Offset(unsigned AM5Opc) { 5020b57cec5SDimitry Andric return AM5Opc & 0xFF; 5030b57cec5SDimitry Andric } getAM5FP16Op(unsigned AM5Opc)5040b57cec5SDimitry Andric inline AddrOpc getAM5FP16Op(unsigned AM5Opc) { 5050b57cec5SDimitry Andric return ((AM5Opc >> 8) & 1) ? sub : add; 5060b57cec5SDimitry Andric } 5070b57cec5SDimitry Andric 5080b57cec5SDimitry Andric //===--------------------------------------------------------------------===// 5090b57cec5SDimitry Andric // Addressing Mode #6 5100b57cec5SDimitry Andric //===--------------------------------------------------------------------===// 5110b57cec5SDimitry Andric // 5120b57cec5SDimitry Andric // This is used for NEON load / store instructions. 5130b57cec5SDimitry Andric // 5140b57cec5SDimitry Andric // addrmode6 := reg with optional alignment 5150b57cec5SDimitry Andric // 5160b57cec5SDimitry Andric // This is stored in two operands [regaddr, align]. The first is the 5170b57cec5SDimitry Andric // address register. The second operand is the value of the alignment 5180b57cec5SDimitry Andric // specifier in bytes or zero if no explicit alignment. 5190b57cec5SDimitry Andric // Valid alignments depend on the specific instruction. 5200b57cec5SDimitry Andric 5210b57cec5SDimitry Andric //===--------------------------------------------------------------------===// 5228bcb0991SDimitry Andric // NEON/MVE Modified Immediates 5230b57cec5SDimitry Andric //===--------------------------------------------------------------------===// 5240b57cec5SDimitry Andric // 5258bcb0991SDimitry Andric // Several NEON and MVE instructions (e.g., VMOV) take a "modified immediate" 5260b57cec5SDimitry Andric // vector operand, where a small immediate encoded in the instruction 5270b57cec5SDimitry Andric // specifies a full NEON vector value. These modified immediates are 5280b57cec5SDimitry Andric // represented here as encoded integers. The low 8 bits hold the immediate 5290b57cec5SDimitry Andric // value; bit 12 holds the "Op" field of the instruction, and bits 11-8 hold 5300b57cec5SDimitry Andric // the "Cmode" field of the instruction. The interfaces below treat the 5310b57cec5SDimitry Andric // Op and Cmode values as a single 5-bit value. 5320b57cec5SDimitry Andric createVMOVModImm(unsigned OpCmode,unsigned Val)5338bcb0991SDimitry Andric inline unsigned createVMOVModImm(unsigned OpCmode, unsigned Val) { 5340b57cec5SDimitry Andric return (OpCmode << 8) | Val; 5350b57cec5SDimitry Andric } getVMOVModImmOpCmode(unsigned ModImm)5368bcb0991SDimitry Andric inline unsigned getVMOVModImmOpCmode(unsigned ModImm) { 5370b57cec5SDimitry Andric return (ModImm >> 8) & 0x1f; 5380b57cec5SDimitry Andric } getVMOVModImmVal(unsigned ModImm)5398bcb0991SDimitry Andric inline unsigned getVMOVModImmVal(unsigned ModImm) { return ModImm & 0xff; } 5400b57cec5SDimitry Andric 5418bcb0991SDimitry Andric /// decodeVMOVModImm - Decode a NEON/MVE modified immediate value into the 5420b57cec5SDimitry Andric /// element value and the element size in bits. (If the element size is 5430b57cec5SDimitry Andric /// smaller than the vector, it is splatted into all the elements.) decodeVMOVModImm(unsigned ModImm,unsigned & EltBits)5448bcb0991SDimitry Andric inline uint64_t decodeVMOVModImm(unsigned ModImm, unsigned &EltBits) { 5458bcb0991SDimitry Andric unsigned OpCmode = getVMOVModImmOpCmode(ModImm); 5468bcb0991SDimitry Andric unsigned Imm8 = getVMOVModImmVal(ModImm); 5470b57cec5SDimitry Andric uint64_t Val = 0; 5480b57cec5SDimitry Andric 5490b57cec5SDimitry Andric if (OpCmode == 0xe) { 5500b57cec5SDimitry Andric // 8-bit vector elements 5510b57cec5SDimitry Andric Val = Imm8; 5520b57cec5SDimitry Andric EltBits = 8; 5530b57cec5SDimitry Andric } else if ((OpCmode & 0xc) == 0x8) { 5540b57cec5SDimitry Andric // 16-bit vector elements 5550b57cec5SDimitry Andric unsigned ByteNum = (OpCmode & 0x6) >> 1; 5560b57cec5SDimitry Andric Val = Imm8 << (8 * ByteNum); 5570b57cec5SDimitry Andric EltBits = 16; 5580b57cec5SDimitry Andric } else if ((OpCmode & 0x8) == 0) { 5590b57cec5SDimitry Andric // 32-bit vector elements, zero with one byte set 5600b57cec5SDimitry Andric unsigned ByteNum = (OpCmode & 0x6) >> 1; 5610b57cec5SDimitry Andric Val = Imm8 << (8 * ByteNum); 5620b57cec5SDimitry Andric EltBits = 32; 5630b57cec5SDimitry Andric } else if ((OpCmode & 0xe) == 0xc) { 5640b57cec5SDimitry Andric // 32-bit vector elements, one byte with low bits set 5650b57cec5SDimitry Andric unsigned ByteNum = 1 + (OpCmode & 0x1); 5660b57cec5SDimitry Andric Val = (Imm8 << (8 * ByteNum)) | (0xffff >> (8 * (2 - ByteNum))); 5670b57cec5SDimitry Andric EltBits = 32; 5680b57cec5SDimitry Andric } else if (OpCmode == 0x1e) { 5690b57cec5SDimitry Andric // 64-bit vector elements 5700b57cec5SDimitry Andric for (unsigned ByteNum = 0; ByteNum < 8; ++ByteNum) { 5710b57cec5SDimitry Andric if ((ModImm >> ByteNum) & 1) 5720b57cec5SDimitry Andric Val |= (uint64_t)0xff << (8 * ByteNum); 5730b57cec5SDimitry Andric } 5740b57cec5SDimitry Andric EltBits = 64; 5750b57cec5SDimitry Andric } else { 5768bcb0991SDimitry Andric llvm_unreachable("Unsupported VMOV immediate"); 5770b57cec5SDimitry Andric } 5780b57cec5SDimitry Andric return Val; 5790b57cec5SDimitry Andric } 5800b57cec5SDimitry Andric 5810b57cec5SDimitry Andric // Generic validation for single-byte immediate (0X00, 00X0, etc). isNEONBytesplat(unsigned Value,unsigned Size)5820b57cec5SDimitry Andric inline bool isNEONBytesplat(unsigned Value, unsigned Size) { 5830b57cec5SDimitry Andric assert(Size >= 1 && Size <= 4 && "Invalid size"); 5840b57cec5SDimitry Andric unsigned count = 0; 5850b57cec5SDimitry Andric for (unsigned i = 0; i < Size; ++i) { 5860b57cec5SDimitry Andric if (Value & 0xff) count++; 5870b57cec5SDimitry Andric Value >>= 8; 5880b57cec5SDimitry Andric } 5890b57cec5SDimitry Andric return count == 1; 5900b57cec5SDimitry Andric } 5910b57cec5SDimitry Andric 5920b57cec5SDimitry Andric /// Checks if Value is a correct immediate for instructions like VBIC/VORR. isNEONi16splat(unsigned Value)5930b57cec5SDimitry Andric inline bool isNEONi16splat(unsigned Value) { 5940b57cec5SDimitry Andric if (Value > 0xffff) 5950b57cec5SDimitry Andric return false; 5960b57cec5SDimitry Andric // i16 value with set bits only in one byte X0 or 0X. 5970b57cec5SDimitry Andric return Value == 0 || isNEONBytesplat(Value, 2); 5980b57cec5SDimitry Andric } 5990b57cec5SDimitry Andric 6000b57cec5SDimitry Andric // Encode NEON 16 bits Splat immediate for instructions like VBIC/VORR encodeNEONi16splat(unsigned Value)6010b57cec5SDimitry Andric inline unsigned encodeNEONi16splat(unsigned Value) { 6020b57cec5SDimitry Andric assert(isNEONi16splat(Value) && "Invalid NEON splat value"); 6030b57cec5SDimitry Andric if (Value >= 0x100) 6040b57cec5SDimitry Andric Value = (Value >> 8) | 0xa00; 6050b57cec5SDimitry Andric else 6060b57cec5SDimitry Andric Value |= 0x800; 6070b57cec5SDimitry Andric return Value; 6080b57cec5SDimitry Andric } 6090b57cec5SDimitry Andric 6100b57cec5SDimitry Andric /// Checks if Value is a correct immediate for instructions like VBIC/VORR. isNEONi32splat(unsigned Value)6110b57cec5SDimitry Andric inline bool isNEONi32splat(unsigned Value) { 6120b57cec5SDimitry Andric // i32 value with set bits only in one byte X000, 0X00, 00X0, or 000X. 6130b57cec5SDimitry Andric return Value == 0 || isNEONBytesplat(Value, 4); 6140b57cec5SDimitry Andric } 6150b57cec5SDimitry Andric 6160b57cec5SDimitry Andric /// Encode NEON 32 bits Splat immediate for instructions like VBIC/VORR. encodeNEONi32splat(unsigned Value)6170b57cec5SDimitry Andric inline unsigned encodeNEONi32splat(unsigned Value) { 6180b57cec5SDimitry Andric assert(isNEONi32splat(Value) && "Invalid NEON splat value"); 6190b57cec5SDimitry Andric if (Value >= 0x100 && Value <= 0xff00) 6200b57cec5SDimitry Andric Value = (Value >> 8) | 0x200; 6210b57cec5SDimitry Andric else if (Value > 0xffff && Value <= 0xff0000) 6220b57cec5SDimitry Andric Value = (Value >> 16) | 0x400; 6230b57cec5SDimitry Andric else if (Value > 0xffffff) 6240b57cec5SDimitry Andric Value = (Value >> 24) | 0x600; 6250b57cec5SDimitry Andric return Value; 6260b57cec5SDimitry Andric } 6270b57cec5SDimitry Andric 6280b57cec5SDimitry Andric //===--------------------------------------------------------------------===// 6290b57cec5SDimitry Andric // Floating-point Immediates 6300b57cec5SDimitry Andric // getFPImmFloat(unsigned Imm)6310b57cec5SDimitry Andric inline float getFPImmFloat(unsigned Imm) { 6320b57cec5SDimitry Andric // We expect an 8-bit binary encoding of a floating-point number here. 6330b57cec5SDimitry Andric 6340b57cec5SDimitry Andric uint8_t Sign = (Imm >> 7) & 0x1; 6350b57cec5SDimitry Andric uint8_t Exp = (Imm >> 4) & 0x7; 6360b57cec5SDimitry Andric uint8_t Mantissa = Imm & 0xf; 6370b57cec5SDimitry Andric 6380b57cec5SDimitry Andric // 8-bit FP IEEE Float Encoding 6390b57cec5SDimitry Andric // abcd efgh aBbbbbbc defgh000 00000000 00000000 6400b57cec5SDimitry Andric // 6410b57cec5SDimitry Andric // where B = NOT(b); 6420b57cec5SDimitry Andric uint32_t I = 0; 6430b57cec5SDimitry Andric I |= Sign << 31; 6440b57cec5SDimitry Andric I |= ((Exp & 0x4) != 0 ? 0 : 1) << 30; 6450b57cec5SDimitry Andric I |= ((Exp & 0x4) != 0 ? 0x1f : 0) << 25; 6460b57cec5SDimitry Andric I |= (Exp & 0x3) << 23; 6470b57cec5SDimitry Andric I |= Mantissa << 19; 6480b57cec5SDimitry Andric return bit_cast<float>(I); 6490b57cec5SDimitry Andric } 6500b57cec5SDimitry Andric 6510b57cec5SDimitry Andric /// getFP16Imm - Return an 8-bit floating-point version of the 16-bit 6520b57cec5SDimitry Andric /// floating-point value. If the value cannot be represented as an 8-bit 6530b57cec5SDimitry Andric /// floating-point value, then return -1. getFP16Imm(const APInt & Imm)6540b57cec5SDimitry Andric inline int getFP16Imm(const APInt &Imm) { 6550b57cec5SDimitry Andric uint32_t Sign = Imm.lshr(15).getZExtValue() & 1; 6560b57cec5SDimitry Andric int32_t Exp = (Imm.lshr(10).getSExtValue() & 0x1f) - 15; // -14 to 15 6570b57cec5SDimitry Andric int64_t Mantissa = Imm.getZExtValue() & 0x3ff; // 10 bits 6580b57cec5SDimitry Andric 6590b57cec5SDimitry Andric // We can handle 4 bits of mantissa. 6600b57cec5SDimitry Andric // mantissa = (16+UInt(e:f:g:h))/16. 6610b57cec5SDimitry Andric if (Mantissa & 0x3f) 6620b57cec5SDimitry Andric return -1; 6630b57cec5SDimitry Andric Mantissa >>= 6; 6640b57cec5SDimitry Andric 6650b57cec5SDimitry Andric // We can handle 3 bits of exponent: exp == UInt(NOT(b):c:d)-3 6660b57cec5SDimitry Andric if (Exp < -3 || Exp > 4) 6670b57cec5SDimitry Andric return -1; 6680b57cec5SDimitry Andric Exp = ((Exp+3) & 0x7) ^ 4; 6690b57cec5SDimitry Andric 6700b57cec5SDimitry Andric return ((int)Sign << 7) | (Exp << 4) | Mantissa; 6710b57cec5SDimitry Andric } 6720b57cec5SDimitry Andric getFP16Imm(const APFloat & FPImm)6730b57cec5SDimitry Andric inline int getFP16Imm(const APFloat &FPImm) { 6740b57cec5SDimitry Andric return getFP16Imm(FPImm.bitcastToAPInt()); 6750b57cec5SDimitry Andric } 6760b57cec5SDimitry Andric 677e8d8bef9SDimitry Andric /// If this is a FP16Imm encoded as a fp32 value, return the 8-bit encoding 678e8d8bef9SDimitry Andric /// for it. Otherwise return -1 like getFP16Imm. getFP32FP16Imm(const APInt & Imm)679e8d8bef9SDimitry Andric inline int getFP32FP16Imm(const APInt &Imm) { 680e8d8bef9SDimitry Andric if (Imm.getActiveBits() > 16) 681e8d8bef9SDimitry Andric return -1; 682e8d8bef9SDimitry Andric return ARM_AM::getFP16Imm(Imm.trunc(16)); 683e8d8bef9SDimitry Andric } 684e8d8bef9SDimitry Andric getFP32FP16Imm(const APFloat & FPImm)685e8d8bef9SDimitry Andric inline int getFP32FP16Imm(const APFloat &FPImm) { 686e8d8bef9SDimitry Andric return getFP32FP16Imm(FPImm.bitcastToAPInt()); 687e8d8bef9SDimitry Andric } 688e8d8bef9SDimitry Andric 6890b57cec5SDimitry Andric /// getFP32Imm - Return an 8-bit floating-point version of the 32-bit 6900b57cec5SDimitry Andric /// floating-point value. If the value cannot be represented as an 8-bit 6910b57cec5SDimitry Andric /// floating-point value, then return -1. getFP32Imm(const APInt & Imm)6920b57cec5SDimitry Andric inline int getFP32Imm(const APInt &Imm) { 6930b57cec5SDimitry Andric uint32_t Sign = Imm.lshr(31).getZExtValue() & 1; 6940b57cec5SDimitry Andric int32_t Exp = (Imm.lshr(23).getSExtValue() & 0xff) - 127; // -126 to 127 6950b57cec5SDimitry Andric int64_t Mantissa = Imm.getZExtValue() & 0x7fffff; // 23 bits 6960b57cec5SDimitry Andric 6970b57cec5SDimitry Andric // We can handle 4 bits of mantissa. 6980b57cec5SDimitry Andric // mantissa = (16+UInt(e:f:g:h))/16. 6990b57cec5SDimitry Andric if (Mantissa & 0x7ffff) 7000b57cec5SDimitry Andric return -1; 7010b57cec5SDimitry Andric Mantissa >>= 19; 7020b57cec5SDimitry Andric if ((Mantissa & 0xf) != Mantissa) 7030b57cec5SDimitry Andric return -1; 7040b57cec5SDimitry Andric 7050b57cec5SDimitry Andric // We can handle 3 bits of exponent: exp == UInt(NOT(b):c:d)-3 7060b57cec5SDimitry Andric if (Exp < -3 || Exp > 4) 7070b57cec5SDimitry Andric return -1; 7080b57cec5SDimitry Andric Exp = ((Exp+3) & 0x7) ^ 4; 7090b57cec5SDimitry Andric 7100b57cec5SDimitry Andric return ((int)Sign << 7) | (Exp << 4) | Mantissa; 7110b57cec5SDimitry Andric } 7120b57cec5SDimitry Andric getFP32Imm(const APFloat & FPImm)7130b57cec5SDimitry Andric inline int getFP32Imm(const APFloat &FPImm) { 7140b57cec5SDimitry Andric return getFP32Imm(FPImm.bitcastToAPInt()); 7150b57cec5SDimitry Andric } 7160b57cec5SDimitry Andric 7170b57cec5SDimitry Andric /// getFP64Imm - Return an 8-bit floating-point version of the 64-bit 7180b57cec5SDimitry Andric /// floating-point value. If the value cannot be represented as an 8-bit 7190b57cec5SDimitry Andric /// floating-point value, then return -1. getFP64Imm(const APInt & Imm)7200b57cec5SDimitry Andric inline int getFP64Imm(const APInt &Imm) { 7210b57cec5SDimitry Andric uint64_t Sign = Imm.lshr(63).getZExtValue() & 1; 7220b57cec5SDimitry Andric int64_t Exp = (Imm.lshr(52).getSExtValue() & 0x7ff) - 1023; // -1022 to 1023 7230b57cec5SDimitry Andric uint64_t Mantissa = Imm.getZExtValue() & 0xfffffffffffffULL; 7240b57cec5SDimitry Andric 7250b57cec5SDimitry Andric // We can handle 4 bits of mantissa. 7260b57cec5SDimitry Andric // mantissa = (16+UInt(e:f:g:h))/16. 7270b57cec5SDimitry Andric if (Mantissa & 0xffffffffffffULL) 7280b57cec5SDimitry Andric return -1; 7290b57cec5SDimitry Andric Mantissa >>= 48; 7300b57cec5SDimitry Andric if ((Mantissa & 0xf) != Mantissa) 7310b57cec5SDimitry Andric return -1; 7320b57cec5SDimitry Andric 7330b57cec5SDimitry Andric // We can handle 3 bits of exponent: exp == UInt(NOT(b):c:d)-3 7340b57cec5SDimitry Andric if (Exp < -3 || Exp > 4) 7350b57cec5SDimitry Andric return -1; 7360b57cec5SDimitry Andric Exp = ((Exp+3) & 0x7) ^ 4; 7370b57cec5SDimitry Andric 7380b57cec5SDimitry Andric return ((int)Sign << 7) | (Exp << 4) | Mantissa; 7390b57cec5SDimitry Andric } 7400b57cec5SDimitry Andric getFP64Imm(const APFloat & FPImm)7410b57cec5SDimitry Andric inline int getFP64Imm(const APFloat &FPImm) { 7420b57cec5SDimitry Andric return getFP64Imm(FPImm.bitcastToAPInt()); 7430b57cec5SDimitry Andric } 7440b57cec5SDimitry Andric 7450b57cec5SDimitry Andric } // end namespace ARM_AM 7460b57cec5SDimitry Andric } // end namespace llvm 7470b57cec5SDimitry Andric 7480b57cec5SDimitry Andric #endif 749