• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013, ARM Limited
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 //   * Redistributions of source code must retain the above copyright notice,
8 //     this list of conditions and the following disclaimer.
9 //   * Redistributions in binary form must reproduce the above copyright notice,
10 //     this list of conditions and the following disclaimer in the documentation
11 //     and/or other materials provided with the distribution.
12 //   * Neither the name of ARM Limited nor the names of its contributors may be
13 //     used to endorse or promote products derived from this software without
14 //     specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 
27 #ifndef VIXL_A64_INSTRUCTIONS_A64_H_
28 #define VIXL_A64_INSTRUCTIONS_A64_H_
29 
30 #include "globals-vixl.h"
31 #include "utils-vixl.h"
32 #include "a64/constants-a64.h"
33 
34 namespace vixl {
35 // ISA constants. --------------------------------------------------------------
36 
37 typedef uint32_t Instr;
38 const unsigned kInstructionSize = 4;
39 const unsigned kInstructionSizeLog2 = 2;
40 const unsigned kLiteralEntrySize = 4;
41 const unsigned kLiteralEntrySizeLog2 = 2;
42 const unsigned kMaxLoadLiteralRange = 1 * MBytes;
43 
44 const unsigned kWRegSize = 32;
45 const unsigned kWRegSizeLog2 = 5;
46 const unsigned kWRegSizeInBytes = kWRegSize / 8;
47 const unsigned kWRegSizeInBytesLog2 = kWRegSizeLog2 - 3;
48 const unsigned kXRegSize = 64;
49 const unsigned kXRegSizeLog2 = 6;
50 const unsigned kXRegSizeInBytes = kXRegSize / 8;
51 const unsigned kXRegSizeInBytesLog2 = kXRegSizeLog2 - 3;
52 const unsigned kSRegSize = 32;
53 const unsigned kSRegSizeLog2 = 5;
54 const unsigned kSRegSizeInBytes = kSRegSize / 8;
55 const unsigned kSRegSizeInBytesLog2 = kSRegSizeLog2 - 3;
56 const unsigned kDRegSize = 64;
57 const unsigned kDRegSizeLog2 = 6;
58 const unsigned kDRegSizeInBytes = kDRegSize / 8;
59 const unsigned kDRegSizeInBytesLog2 = kDRegSizeLog2 - 3;
60 const uint64_t kWRegMask = UINT64_C(0xffffffff);
61 const uint64_t kXRegMask = UINT64_C(0xffffffffffffffff);
62 const uint64_t kSRegMask = UINT64_C(0xffffffff);
63 const uint64_t kDRegMask = UINT64_C(0xffffffffffffffff);
64 const uint64_t kSSignMask = UINT64_C(0x80000000);
65 const uint64_t kDSignMask = UINT64_C(0x8000000000000000);
66 const uint64_t kWSignMask = UINT64_C(0x80000000);
67 const uint64_t kXSignMask = UINT64_C(0x8000000000000000);
68 const uint64_t kByteMask = UINT64_C(0xff);
69 const uint64_t kHalfWordMask = UINT64_C(0xffff);
70 const uint64_t kWordMask = UINT64_C(0xffffffff);
71 const uint64_t kXMaxUInt = UINT64_C(0xffffffffffffffff);
72 const uint64_t kWMaxUInt = UINT64_C(0xffffffff);
73 const int64_t kXMaxInt = INT64_C(0x7fffffffffffffff);
74 const int64_t kXMinInt = INT64_C(0x8000000000000000);
75 const int32_t kWMaxInt = INT32_C(0x7fffffff);
76 const int32_t kWMinInt = INT32_C(0x80000000);
77 const unsigned kLinkRegCode = 30;
78 const unsigned kZeroRegCode = 31;
79 const unsigned kSPRegInternalCode = 63;
80 const unsigned kRegCodeMask = 0x1f;
81 
82 // AArch64 floating-point specifics. These match IEEE-754.
83 const unsigned kDoubleMantissaBits = 52;
84 const unsigned kDoubleExponentBits = 11;
85 const unsigned kFloatMantissaBits = 23;
86 const unsigned kFloatExponentBits = 8;
87 
88 const float kFP32PositiveInfinity = rawbits_to_float(0x7f800000);
89 const float kFP32NegativeInfinity = rawbits_to_float(0xff800000);
90 const double kFP64PositiveInfinity =
91     rawbits_to_double(UINT64_C(0x7ff0000000000000));
92 const double kFP64NegativeInfinity =
93     rawbits_to_double(UINT64_C(0xfff0000000000000));
94 
95 // This value is a signalling NaN as both a double and as a float (taking the
96 // least-significant word).
97 static const double kFP64SignallingNaN =
98     rawbits_to_double(UINT64_C(0x7ff000007f800001));
99 static const float kFP32SignallingNaN = rawbits_to_float(0x7f800001);
100 
101 // A similar value, but as a quiet NaN.
102 static const double kFP64QuietNaN =
103     rawbits_to_double(UINT64_C(0x7ff800007fc00001));
104 static const float kFP32QuietNaN = rawbits_to_float(0x7fc00001);
105 
106 // The default NaN values (for FPCR.DN=1).
107 static const double kFP64DefaultNaN =
108     rawbits_to_double(UINT64_C(0x7ff8000000000000));
109 static const float kFP32DefaultNaN = rawbits_to_float(0x7fc00000);
110 
111 
112 enum LSDataSize {
113   LSByte        = 0,
114   LSHalfword    = 1,
115   LSWord        = 2,
116   LSDoubleWord  = 3
117 };
118 
119 LSDataSize CalcLSPairDataSize(LoadStorePairOp op);
120 
121 enum ImmBranchType {
122   UnknownBranchType = 0,
123   CondBranchType    = 1,
124   UncondBranchType  = 2,
125   CompareBranchType = 3,
126   TestBranchType    = 4
127 };
128 
129 enum AddrMode {
130   Offset,
131   PreIndex,
132   PostIndex
133 };
134 
135 enum FPRounding {
136   // The first four values are encodable directly by FPCR<RMode>.
137   FPTieEven = 0x0,
138   FPPositiveInfinity = 0x1,
139   FPNegativeInfinity = 0x2,
140   FPZero = 0x3,
141 
142   // The final rounding mode is only available when explicitly specified by the
143   // instruction (such as with fcvta). It cannot be set in FPCR.
144   FPTieAway
145 };
146 
147 enum Reg31Mode {
148   Reg31IsStackPointer,
149   Reg31IsZeroRegister
150 };
151 
152 // Instructions. ---------------------------------------------------------------
153 
154 class Instruction {
155  public:
InstructionBits()156   inline Instr InstructionBits() const {
157     return *(reinterpret_cast<const Instr*>(this));
158   }
159 
SetInstructionBits(Instr new_instr)160   inline void SetInstructionBits(Instr new_instr) {
161     *(reinterpret_cast<Instr*>(this)) = new_instr;
162   }
163 
Bit(int pos)164   inline int Bit(int pos) const {
165     return (InstructionBits() >> pos) & 1;
166   }
167 
Bits(int msb,int lsb)168   inline uint32_t Bits(int msb, int lsb) const {
169     return unsigned_bitextract_32(msb, lsb, InstructionBits());
170   }
171 
SignedBits(int msb,int lsb)172   inline int32_t SignedBits(int msb, int lsb) const {
173     int32_t bits = *(reinterpret_cast<const int32_t*>(this));
174     return signed_bitextract_32(msb, lsb, bits);
175   }
176 
Mask(uint32_t mask)177   inline Instr Mask(uint32_t mask) const {
178     return InstructionBits() & mask;
179   }
180 
181   #define DEFINE_GETTER(Name, HighBit, LowBit, Func)             \
182   inline int64_t Name() const { return Func(HighBit, LowBit); }
INSTRUCTION_FIELDS_LIST(DEFINE_GETTER)183   INSTRUCTION_FIELDS_LIST(DEFINE_GETTER)
184   #undef DEFINE_GETTER
185 
186   // ImmPCRel is a compound field (not present in INSTRUCTION_FIELDS_LIST),
187   // formed from ImmPCRelLo and ImmPCRelHi.
188   int ImmPCRel() const {
189     int const offset = ((ImmPCRelHi() << ImmPCRelLo_width) | ImmPCRelLo());
190     int const width = ImmPCRelLo_width + ImmPCRelHi_width;
191     return signed_bitextract_32(width-1, 0, offset);
192   }
193 
194   uint64_t ImmLogical();
195   float ImmFP32();
196   double ImmFP64();
197 
SizeLSPair()198   inline LSDataSize SizeLSPair() const {
199     return CalcLSPairDataSize(
200              static_cast<LoadStorePairOp>(Mask(LoadStorePairMask)));
201   }
202 
203   // Helpers.
IsCondBranchImm()204   inline bool IsCondBranchImm() const {
205     return Mask(ConditionalBranchFMask) == ConditionalBranchFixed;
206   }
207 
IsUncondBranchImm()208   inline bool IsUncondBranchImm() const {
209     return Mask(UnconditionalBranchFMask) == UnconditionalBranchFixed;
210   }
211 
IsCompareBranch()212   inline bool IsCompareBranch() const {
213     return Mask(CompareBranchFMask) == CompareBranchFixed;
214   }
215 
IsTestBranch()216   inline bool IsTestBranch() const {
217     return Mask(TestBranchFMask) == TestBranchFixed;
218   }
219 
IsPCRelAddressing()220   inline bool IsPCRelAddressing() const {
221     return Mask(PCRelAddressingFMask) == PCRelAddressingFixed;
222   }
223 
IsLogicalImmediate()224   inline bool IsLogicalImmediate() const {
225     return Mask(LogicalImmediateFMask) == LogicalImmediateFixed;
226   }
227 
IsAddSubImmediate()228   inline bool IsAddSubImmediate() const {
229     return Mask(AddSubImmediateFMask) == AddSubImmediateFixed;
230   }
231 
IsAddSubExtended()232   inline bool IsAddSubExtended() const {
233     return Mask(AddSubExtendedFMask) == AddSubExtendedFixed;
234   }
235 
IsLoadOrStore()236   inline bool IsLoadOrStore() const {
237     return Mask(LoadStoreAnyFMask) == LoadStoreAnyFixed;
238   }
239 
IsMovn()240   inline bool IsMovn() const {
241     return (Mask(MoveWideImmediateMask) == MOVN_x) ||
242            (Mask(MoveWideImmediateMask) == MOVN_w);
243   }
244 
245   // Indicate whether Rd can be the stack pointer or the zero register. This
246   // does not check that the instruction actually has an Rd field.
RdMode()247   inline Reg31Mode RdMode() const {
248     // The following instructions use sp or wsp as Rd:
249     //  Add/sub (immediate) when not setting the flags.
250     //  Add/sub (extended) when not setting the flags.
251     //  Logical (immediate) when not setting the flags.
252     // Otherwise, r31 is the zero register.
253     if (IsAddSubImmediate() || IsAddSubExtended()) {
254       if (Mask(AddSubSetFlagsBit)) {
255         return Reg31IsZeroRegister;
256       } else {
257         return Reg31IsStackPointer;
258       }
259     }
260     if (IsLogicalImmediate()) {
261       // Of the logical (immediate) instructions, only ANDS (and its aliases)
262       // can set the flags. The others can all write into sp.
263       // Note that some logical operations are not available to
264       // immediate-operand instructions, so we have to combine two masks here.
265       if (Mask(LogicalImmediateMask & LogicalOpMask) == ANDS) {
266         return Reg31IsZeroRegister;
267       } else {
268         return Reg31IsStackPointer;
269       }
270     }
271     return Reg31IsZeroRegister;
272   }
273 
274   // Indicate whether Rn can be the stack pointer or the zero register. This
275   // does not check that the instruction actually has an Rn field.
RnMode()276   inline Reg31Mode RnMode() const {
277     // The following instructions use sp or wsp as Rn:
278     //  All loads and stores.
279     //  Add/sub (immediate).
280     //  Add/sub (extended).
281     // Otherwise, r31 is the zero register.
282     if (IsLoadOrStore() || IsAddSubImmediate() || IsAddSubExtended()) {
283       return Reg31IsStackPointer;
284     }
285     return Reg31IsZeroRegister;
286   }
287 
BranchType()288   inline ImmBranchType BranchType() const {
289     if (IsCondBranchImm()) {
290       return CondBranchType;
291     } else if (IsUncondBranchImm()) {
292       return UncondBranchType;
293     } else if (IsCompareBranch()) {
294       return CompareBranchType;
295     } else if (IsTestBranch()) {
296       return TestBranchType;
297     } else {
298       return UnknownBranchType;
299     }
300   }
301 
302   // Find the target of this instruction. 'this' may be a branch or a
303   // PC-relative addressing instruction.
304   Instruction* ImmPCOffsetTarget();
305 
306   // Patch a PC-relative offset to refer to 'target'. 'this' may be a branch or
307   // a PC-relative addressing instruction.
308   void SetImmPCOffsetTarget(Instruction* target);
309   // Patch a literal load instruction to load from 'source'.
310   void SetImmLLiteral(Instruction* source);
311 
LiteralAddress()312   inline uint8_t* LiteralAddress() {
313     int offset = ImmLLiteral() << kLiteralEntrySizeLog2;
314     return reinterpret_cast<uint8_t*>(this) + offset;
315   }
316 
Literal32()317   inline uint32_t Literal32() {
318     uint32_t literal;
319     memcpy(&literal, LiteralAddress(), sizeof(literal));
320 
321     return literal;
322   }
323 
Literal64()324   inline uint64_t Literal64() {
325     uint64_t literal;
326     memcpy(&literal, LiteralAddress(), sizeof(literal));
327 
328     return literal;
329   }
330 
LiteralFP32()331   inline float LiteralFP32() {
332     return rawbits_to_float(Literal32());
333   }
334 
LiteralFP64()335   inline double LiteralFP64() {
336     return rawbits_to_double(Literal64());
337   }
338 
NextInstruction()339   inline Instruction* NextInstruction() {
340     return this + kInstructionSize;
341   }
342 
InstructionAtOffset(int64_t offset)343   inline Instruction* InstructionAtOffset(int64_t offset) {
344     VIXL_ASSERT(IsWordAligned(this + offset));
345     return this + offset;
346   }
347 
Cast(T src)348   template<typename T> static inline Instruction* Cast(T src) {
349     return reinterpret_cast<Instruction*>(src);
350   }
351 
352  private:
353   inline int ImmBranch() const;
354 
355   void SetPCRelImmTarget(Instruction* target);
356   void SetBranchImmTarget(Instruction* target);
357 };
358 }  // namespace vixl
359 
360 #endif  // VIXL_A64_INSTRUCTIONS_A64_H_
361