//===-- ARMAddressingModes.h - ARM Addressing Modes -------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file contains the ARM addressing mode implementation stuff. // //===----------------------------------------------------------------------===// #ifndef LLVM_LIB_TARGET_ARM_MCTARGETDESC_ARMADDRESSINGMODES_H #define LLVM_LIB_TARGET_ARM_MCTARGETDESC_ARMADDRESSINGMODES_H #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/bit.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include <cassert> namespace llvm { /// ARM_AM - ARM Addressing Mode Stuff namespace ARM_AM { enum ShiftOpc { … }; enum AddrOpc { … }; inline const char *getAddrOpcStr(AddrOpc Op) { … } inline const StringRef getShiftOpcStr(ShiftOpc Op) { … } inline unsigned getShiftOpcEncoding(ShiftOpc Op) { … } enum AMSubMode { … }; inline const char *getAMSubModeStr(AMSubMode Mode) { … } //===--------------------------------------------------------------------===// // Addressing Mode #1: shift_operand with registers //===--------------------------------------------------------------------===// // // This 'addressing mode' is used for arithmetic instructions. It can // represent things like: // reg // reg [asr|lsl|lsr|ror|rrx] reg // reg [asr|lsl|lsr|ror|rrx] imm // // This is stored three operands [rega, regb, opc]. The first is the base // reg, the second is the shift amount (or reg0 if not present or imm). The // third operand encodes the shift opcode and the imm if a reg isn't present. // inline unsigned getSORegOpc(ShiftOpc ShOp, unsigned Imm) { … } inline unsigned getSORegOffset(unsigned Op) { … } inline ShiftOpc getSORegShOp(unsigned Op) { … } /// getSOImmValImm - Given an encoded imm field for the reg/imm form, return /// the 8-bit imm value. inline unsigned getSOImmValImm(unsigned Imm) { … } /// getSOImmValRot - Given an encoded imm field for the reg/imm form, return /// the rotate amount. inline unsigned getSOImmValRot(unsigned Imm) { … } /// getSOImmValRotate - Try to handle Imm with an immediate shifter operand, /// computing the rotate amount to use. If this immediate value cannot be /// handled with a single shifter-op, determine a good rotate amount that will /// take a maximal chunk of bits out of the immediate. inline unsigned getSOImmValRotate(unsigned Imm) { … } /// getSOImmVal - Given a 32-bit immediate, if it is something that can fit /// into an shifter_operand immediate operand, return the 12-bit encoding for /// it. If not, return -1. inline int getSOImmVal(unsigned Arg) { … } /// isSOImmTwoPartVal - Return true if the specified value can be obtained by /// or'ing together two SOImmVal's. inline bool isSOImmTwoPartVal(unsigned V) { … } /// getSOImmTwoPartFirst - If V is a value that satisfies isSOImmTwoPartVal, /// return the first chunk of it. inline unsigned getSOImmTwoPartFirst(unsigned V) { … } /// getSOImmTwoPartSecond - If V is a value that satisfies isSOImmTwoPartVal, /// return the second chunk of it. inline unsigned getSOImmTwoPartSecond(unsigned V) { … } /// isSOImmTwoPartValNeg - Return true if the specified value can be obtained /// by two SOImmVal, that -V = First + Second. /// "R+V" can be optimized to (sub (sub R, First), Second). /// "R=V" can be optimized to (sub (mvn R, ~(-First)), Second). inline bool isSOImmTwoPartValNeg(unsigned V) { … } /// getThumbImmValShift - Try to handle Imm with a 8-bit immediate followed /// by a left shift. Returns the shift amount to use. inline unsigned getThumbImmValShift(unsigned Imm) { … } /// isThumbImmShiftedVal - Return true if the specified value can be obtained /// by left shifting a 8-bit immediate. inline bool isThumbImmShiftedVal(unsigned V) { … } /// getThumbImm16ValShift - Try to handle Imm with a 16-bit immediate followed /// by a left shift. Returns the shift amount to use. inline unsigned getThumbImm16ValShift(unsigned Imm) { … } /// isThumbImm16ShiftedVal - Return true if the specified value can be /// obtained by left shifting a 16-bit immediate. inline bool isThumbImm16ShiftedVal(unsigned V) { … } /// getThumbImmNonShiftedVal - If V is a value that satisfies /// isThumbImmShiftedVal, return the non-shiftd value. inline unsigned getThumbImmNonShiftedVal(unsigned V) { … } /// getT2SOImmValSplat - Return the 12-bit encoded representation /// if the specified value can be obtained by splatting the low 8 bits /// into every other byte or every byte of a 32-bit value. i.e., /// 00000000 00000000 00000000 abcdefgh control = 0 /// 00000000 abcdefgh 00000000 abcdefgh control = 1 /// abcdefgh 00000000 abcdefgh 00000000 control = 2 /// abcdefgh abcdefgh abcdefgh abcdefgh control = 3 /// Return -1 if none of the above apply. /// See ARM Reference Manual A6.3.2. inline int getT2SOImmValSplatVal(unsigned V) { … } /// getT2SOImmValRotateVal - Return the 12-bit encoded representation if the /// specified value is a rotated 8-bit value. Return -1 if no rotation /// encoding is possible. /// See ARM Reference Manual A6.3.2. inline int getT2SOImmValRotateVal(unsigned V) { … } /// getT2SOImmVal - Given a 32-bit immediate, if it is something that can fit /// into a Thumb-2 shifter_operand immediate operand, return the 12-bit /// encoding for it. If not, return -1. /// See ARM Reference Manual A6.3.2. inline int getT2SOImmVal(unsigned Arg) { … } inline unsigned getT2SOImmValRotate(unsigned V) { … } inline bool isT2SOImmTwoPartVal(unsigned Imm) { … } inline unsigned getT2SOImmTwoPartFirst(unsigned Imm) { … } inline unsigned getT2SOImmTwoPartSecond(unsigned Imm) { … } //===--------------------------------------------------------------------===// // Addressing Mode #2 //===--------------------------------------------------------------------===// // // This is used for most simple load/store instructions. // // addrmode2 := reg +/- reg shop imm // addrmode2 := reg +/- imm12 // // The first operand is always a Reg. The second operand is a reg if in // reg/reg form, otherwise it's reg#0. The third field encodes the operation // in bit 12, the immediate in bits 0-11, and the shift op in 13-15. The // fourth operand 16-17 encodes the index mode. // // If this addressing mode is a frame index (before prolog/epilog insertion // and code rewriting), this operand will have the form: FI#, reg0, <offs> // with no shift amount for the frame offset. // inline unsigned getAM2Opc(AddrOpc Opc, unsigned Imm12, ShiftOpc SO, unsigned IdxMode = 0) { … } inline unsigned getAM2Offset(unsigned AM2Opc) { … } inline AddrOpc getAM2Op(unsigned AM2Opc) { … } inline ShiftOpc getAM2ShiftOpc(unsigned AM2Opc) { … } inline unsigned getAM2IdxMode(unsigned AM2Opc) { … } //===--------------------------------------------------------------------===// // Addressing Mode #3 //===--------------------------------------------------------------------===// // // This is used for sign-extending loads, and load/store-pair instructions. // // addrmode3 := reg +/- reg // addrmode3 := reg +/- imm8 // // The first operand is always a Reg. The second operand is a reg if in // reg/reg form, otherwise it's reg#0. The third field encodes the operation // in bit 8, the immediate in bits 0-7. The fourth operand 9-10 encodes the // index mode. /// getAM3Opc - This function encodes the addrmode3 opc field. inline unsigned getAM3Opc(AddrOpc Opc, unsigned char Offset, unsigned IdxMode = 0) { … } inline unsigned char getAM3Offset(unsigned AM3Opc) { … } inline AddrOpc getAM3Op(unsigned AM3Opc) { … } inline unsigned getAM3IdxMode(unsigned AM3Opc) { … } //===--------------------------------------------------------------------===// // Addressing Mode #4 //===--------------------------------------------------------------------===// // // This is used for load / store multiple instructions. // // addrmode4 := reg, <mode> // // The four modes are: // IA - Increment after // IB - Increment before // DA - Decrement after // DB - Decrement before // For VFP instructions, only the IA and DB modes are valid. inline AMSubMode getAM4SubMode(unsigned Mode) { … } inline unsigned getAM4ModeImm(AMSubMode SubMode) { … } //===--------------------------------------------------------------------===// // Addressing Mode #5 //===--------------------------------------------------------------------===// // // This is used for coprocessor instructions, such as FP load/stores. // // addrmode5 := reg +/- imm8*4 // // The first operand is always a Reg. The second operand encodes the // operation (add or subtract) in bit 8 and the immediate in bits 0-7. /// getAM5Opc - This function encodes the addrmode5 opc field. inline unsigned getAM5Opc(AddrOpc Opc, unsigned char Offset) { … } inline unsigned char getAM5Offset(unsigned AM5Opc) { … } inline AddrOpc getAM5Op(unsigned AM5Opc) { … } //===--------------------------------------------------------------------===// // Addressing Mode #5 FP16 //===--------------------------------------------------------------------===// // // This is used for coprocessor instructions, such as 16-bit FP load/stores. // // addrmode5fp16 := reg +/- imm8*2 // // The first operand is always a Reg. The second operand encodes the // operation (add or subtract) in bit 8 and the immediate in bits 0-7. /// getAM5FP16Opc - This function encodes the addrmode5fp16 opc field. inline unsigned getAM5FP16Opc(AddrOpc Opc, unsigned char Offset) { … } inline unsigned char getAM5FP16Offset(unsigned AM5Opc) { … } inline AddrOpc getAM5FP16Op(unsigned AM5Opc) { … } //===--------------------------------------------------------------------===// // Addressing Mode #6 //===--------------------------------------------------------------------===// // // This is used for NEON load / store instructions. // // addrmode6 := reg with optional alignment // // This is stored in two operands [regaddr, align]. The first is the // address register. The second operand is the value of the alignment // specifier in bytes or zero if no explicit alignment. // Valid alignments depend on the specific instruction. //===--------------------------------------------------------------------===// // NEON/MVE Modified Immediates //===--------------------------------------------------------------------===// // // Several NEON and MVE instructions (e.g., VMOV) take a "modified immediate" // vector operand, where a small immediate encoded in the instruction // specifies a full NEON vector value. These modified immediates are // represented here as encoded integers. The low 8 bits hold the immediate // value; bit 12 holds the "Op" field of the instruction, and bits 11-8 hold // the "Cmode" field of the instruction. The interfaces below treat the // Op and Cmode values as a single 5-bit value. inline unsigned createVMOVModImm(unsigned OpCmode, unsigned Val) { … } inline unsigned getVMOVModImmOpCmode(unsigned ModImm) { … } inline unsigned getVMOVModImmVal(unsigned ModImm) { … } /// decodeVMOVModImm - Decode a NEON/MVE modified immediate value into the /// element value and the element size in bits. (If the element size is /// smaller than the vector, it is splatted into all the elements.) inline uint64_t decodeVMOVModImm(unsigned ModImm, unsigned &EltBits) { … } // Generic validation for single-byte immediate (0X00, 00X0, etc). inline bool isNEONBytesplat(unsigned Value, unsigned Size) { … } /// Checks if Value is a correct immediate for instructions like VBIC/VORR. inline bool isNEONi16splat(unsigned Value) { … } // Encode NEON 16 bits Splat immediate for instructions like VBIC/VORR inline unsigned encodeNEONi16splat(unsigned Value) { … } /// Checks if Value is a correct immediate for instructions like VBIC/VORR. inline bool isNEONi32splat(unsigned Value) { … } /// Encode NEON 32 bits Splat immediate for instructions like VBIC/VORR. inline unsigned encodeNEONi32splat(unsigned Value) { … } //===--------------------------------------------------------------------===// // Floating-point Immediates // inline float getFPImmFloat(unsigned Imm) { … } /// getFP16Imm - Return an 8-bit floating-point version of the 16-bit /// floating-point value. If the value cannot be represented as an 8-bit /// floating-point value, then return -1. inline int getFP16Imm(const APInt &Imm) { … } inline int getFP16Imm(const APFloat &FPImm) { … } /// If this is a FP16Imm encoded as a fp32 value, return the 8-bit encoding /// for it. Otherwise return -1 like getFP16Imm. inline int getFP32FP16Imm(const APInt &Imm) { … } inline int getFP32FP16Imm(const APFloat &FPImm) { … } /// getFP32Imm - Return an 8-bit floating-point version of the 32-bit /// floating-point value. If the value cannot be represented as an 8-bit /// floating-point value, then return -1. inline int getFP32Imm(const APInt &Imm) { … } inline int getFP32Imm(const APFloat &FPImm) { … } /// getFP64Imm - Return an 8-bit floating-point version of the 64-bit /// floating-point value. If the value cannot be represented as an 8-bit /// floating-point value, then return -1. inline int getFP64Imm(const APInt &Imm) { … } inline int getFP64Imm(const APFloat &FPImm) { … } } // end namespace ARM_AM } // end namespace llvm #endif