Fix some bugs with fb_setprofile in ARM mode
[hiphop-php.git] / hphp / vixl / a64 / simulator-a64.h
blob82d17b2e142896a8ad4d83a052c192dc981d0fda
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.
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.
27 #ifndef VIXL_A64_SIMULATOR_A64_H_
28 #define VIXL_A64_SIMULATOR_A64_H_
30 #include "hphp/vixl/globals.h"
31 #include "hphp/vixl/utils.h"
32 #include "hphp/vixl/a64/instructions-a64.h"
33 #include "hphp/vixl/a64/assembler-a64.h"
34 #include "hphp/vixl/a64/disasm-a64.h"
35 #include "hphp/vixl/a64/instrument-a64.h"
37 namespace vixl {
39 enum ReverseByteMode {
40 Reverse16 = 0,
41 Reverse32 = 1,
42 Reverse64 = 2
45 // Printf. See debugger-a64.h for more information on pseudo instructions.
46 // - type: CPURegister::RegisterType stored as a uint32_t.
48 // Simulate a call to printf.
50 // Floating-point and integer arguments are passed in separate sets of
51 // registers in AAPCS64 (even for varargs functions), so it is not possible to
52 // determine the type of location of each argument without some information
53 // about the values that were passed in. This information could be retrieved
54 // from the printf format string, but the format string is not trivial to
55 // parse so we encode the relevant information with the HLT instruction under
56 // the type argument. Therefore the interface is:
57 // x0: The format string
58 // x1-x7: Optional arguments, if type == CPURegister::kRegister
59 // d0-d7: Optional arguments, if type == CPURegister::kFPRegister
60 const Instr kPrintfOpcode = 0xdeb1;
61 const unsigned kPrintfTypeOffset = 1 * kInstructionSize;
62 const unsigned kPrintfLength = 2 * kInstructionSize;
64 const Instr kHostCallOpcode = 0xdeb4;
65 const unsigned kHostCallCountOffset = 1 * kInstructionSize;
67 // The proper way to initialize a simulated system register (such as NZCV) is as
68 // follows:
69 // SimSystemRegister nzcv = SimSystemRegister::DefaultValueFor(NZCV);
70 class SimSystemRegister {
71 public:
72 // The default constructor represents a register which has no writable bits.
73 // It is not possible to set its value to anything other than 0.
74 SimSystemRegister() : value_(0), write_ignore_mask_(0xffffffff) { }
76 inline uint32_t RawValue() const {
77 return value_;
80 inline void SetRawValue(uint32_t new_value) {
81 value_ = (value_ & write_ignore_mask_) | (new_value & ~write_ignore_mask_);
84 inline uint32_t Bits(int msb, int lsb) const {
85 return unsigned_bitextract_32(msb, lsb, value_);
88 inline int32_t SignedBits(int msb, int lsb) const {
89 return signed_bitextract_32(msb, lsb, value_);
92 void SetBits(int msb, int lsb, uint32_t bits);
94 // Default system register values.
95 static SimSystemRegister DefaultValueFor(SystemRegister id);
97 #define DEFINE_GETTER(Name, HighBit, LowBit, Func) \
98 inline uint32_t Name() const { return Func(HighBit, LowBit); } \
99 inline void Set##Name(uint32_t bits) { SetBits(HighBit, LowBit, bits); }
100 #define DEFINE_WRITE_IGNORE_MASK(Name, Mask) \
101 static const uint32_t Name##WriteIgnoreMask = ~static_cast<uint32_t>(Mask);
103 SYSTEM_REGISTER_FIELDS_LIST(DEFINE_GETTER, DEFINE_WRITE_IGNORE_MASK)
105 #undef DEFINE_ZERO_BITS
106 #undef DEFINE_GETTER
108 protected:
109 // Most system registers only implement a few of the bits in the word. Other
110 // bits are "read-as-zero, write-ignored". The write_ignore_mask argument
111 // describes the bits which are not modifiable.
112 SimSystemRegister(uint32_t value, uint32_t write_ignore_mask)
113 : value_(value), write_ignore_mask_(write_ignore_mask) { }
115 uint32_t value_;
116 uint32_t write_ignore_mask_;
119 class Simulator : public DecoderVisitor {
120 public:
121 explicit Simulator(Decoder* decoder, std::ostream& stream = std::cout);
122 ~Simulator();
124 void ResetState();
126 // TODO: We assume little endianness, and the way in which the members of this
127 // union overlay. Add tests to ensure this, or fix accessors to no longer
128 // require this assumption.
129 union SimRegister {
130 int64_t x;
131 int32_t w;
134 union SimFPRegister {
135 double d;
136 float s;
139 // When an exception is thrown through simulated code, call this hook.
140 typedef void(*ExceptionHook)(Simulator*);
141 void set_exception_hook(ExceptionHook hook) {
142 exception_hook_ = hook;
145 // Run the simulator.
146 virtual void Run();
147 void RunFrom(Instruction* first);
149 // Simulation helpers.
150 inline Instruction* pc() const { return pc_; }
151 inline void set_pc(Instruction* new_pc) {
152 pc_ = new_pc;
153 pc_modified_ = true;
156 inline void increment_pc() {
157 if (!pc_modified_) {
158 pc_ = pc_->NextInstruction();
161 pc_modified_ = false;
164 inline void ExecuteInstruction() {
165 // The program counter should always be aligned.
166 assert(IsWordAligned(pc_));
167 decoder_->Decode(pc_);
168 increment_pc();
171 // Declare all Visitor functions.
172 #define DECLARE(A) void Visit##A(Instruction* instr);
173 VISITOR_LIST(DECLARE)
174 #undef DECLARE
176 // Register accessors.
177 inline int32_t wreg(unsigned code,
178 Reg31Mode r31mode = Reg31IsZeroRegister) const {
179 assert(code < kNumberOfRegisters);
180 if ((code == 31) && (r31mode == Reg31IsZeroRegister)) {
181 return 0;
183 return registers_[code].w;
186 inline int64_t xreg(unsigned code,
187 Reg31Mode r31mode = Reg31IsZeroRegister) const {
188 assert(code < kNumberOfRegisters);
189 if ((code == 31) && (r31mode == Reg31IsZeroRegister)) {
190 return 0;
192 return registers_[code].x;
195 inline int64_t reg(unsigned size,
196 unsigned code,
197 Reg31Mode r31mode = Reg31IsZeroRegister) const {
198 switch (size) {
199 case kWRegSize: return wreg(code, r31mode) & kWRegMask;
200 case kXRegSize: return xreg(code, r31mode);
201 default:
202 not_reached();
203 return 0;
207 inline void set_wreg(unsigned code, int32_t value,
208 Reg31Mode r31mode = Reg31IsZeroRegister) {
209 assert(code < kNumberOfRegisters);
210 if ((code == kZeroRegCode) && (r31mode == Reg31IsZeroRegister)) {
211 return;
213 registers_[code].x = 0; // First clear the register top bits.
214 registers_[code].w = value;
217 template<typename T>
218 inline void set_xreg(unsigned code, T* value,
219 Reg31Mode r31mode = Reg31IsZeroRegister) {
220 set_xreg(code, reinterpret_cast<int64_t>(value), r31mode);
223 inline void set_xreg(unsigned code, int64_t value,
224 Reg31Mode r31mode = Reg31IsZeroRegister) {
225 assert(code < kNumberOfRegisters);
226 if ((code == kZeroRegCode) && (r31mode == Reg31IsZeroRegister)) {
227 return;
229 registers_[code].x = value;
232 inline void set_reg(unsigned size, unsigned code, int64_t value,
233 Reg31Mode r31mode = Reg31IsZeroRegister) {
234 switch (size) {
235 case kWRegSize:
236 return set_wreg(code, static_cast<int32_t>(value & 0xffffffff),
237 r31mode);
238 case kXRegSize:
239 return set_xreg(code, value, r31mode);
240 default:
241 not_reached();
242 break;
246 #define REG_ACCESSORS(N) \
247 inline int32_t w##N() { return wreg(N); } \
248 inline int64_t x##N() { return xreg(N); } \
249 inline void set_w##N(int32_t val) { set_wreg(N, val); } \
250 inline void set_x##N(int64_t val) { set_xreg(N, val); }
251 REGISTER_CODE_LIST(REG_ACCESSORS)
252 #undef REG_ACCESSORS
254 // Aliases.
255 #define REG_ALIAS_ACCESSORS(N, wname, xname) \
256 inline int32_t wname() { return wreg(N); } \
257 inline int64_t xname() { return xreg(N); } \
258 inline void set_##wname(int32_t val) { set_wreg(N, val); } \
259 inline void set_##xname(int64_t val) { set_xreg(N, val); }
260 REG_ALIAS_ACCESSORS(30, wlr, lr);
261 #undef REG_ALIAS_ACCESSORS
263 // The stack is a special case in aarch64.
264 inline int32_t wsp() { return wreg(31, Reg31IsStackPointer); }
265 inline int64_t sp() { return xreg(31, Reg31IsStackPointer); }
266 inline void set_wsp(int32_t val) {
267 set_wreg(31, val, Reg31IsStackPointer);
269 inline void set_sp(int64_t val) {
270 set_xreg(31, val, Reg31IsStackPointer);
273 // FPRegister accessors.
274 inline float sreg(unsigned code) const {
275 assert(code < kNumberOfFPRegisters);
276 return fpregisters_[code].s;
279 inline uint32_t sreg_bits(unsigned code) const {
280 return float_to_rawbits(sreg(code));
283 inline double dreg(unsigned code) const {
284 assert(code < kNumberOfFPRegisters);
285 return fpregisters_[code].d;
288 inline uint64_t dreg_bits(unsigned code) const {
289 return double_to_rawbits(dreg(code));
292 inline double fpreg(unsigned size, unsigned code) const {
293 switch (size) {
294 case kSRegSize: return sreg(code);
295 case kDRegSize: return dreg(code);
296 default: {
297 not_reached();
298 return 0.0;
303 inline void set_sreg(unsigned code, float val) {
304 assert(code < kNumberOfFPRegisters);
305 // Ensure that the upper word is set to 0.
306 set_dreg_bits(code, 0);
308 fpregisters_[code].s = val;
311 inline void set_sreg_bits(unsigned code, uint32_t rawbits) {
312 assert(code < kNumberOfFPRegisters);
313 // Ensure that the upper word is set to 0.
314 set_dreg_bits(code, 0);
316 set_sreg(code, rawbits_to_float(rawbits));
319 inline void set_dreg(unsigned code, double val) {
320 assert(code < kNumberOfFPRegisters);
321 fpregisters_[code].d = val;
324 inline void set_dreg_bits(unsigned code, uint64_t rawbits) {
325 assert(code < kNumberOfFPRegisters);
326 set_dreg(code, rawbits_to_double(rawbits));
329 inline void set_fpreg(unsigned size, unsigned code, double value) {
330 switch (size) {
331 case kSRegSize:
332 return set_sreg(code, value);
333 case kDRegSize:
334 return set_dreg(code, value);
335 default:
336 not_reached();
337 break;
341 #define FPREG_ACCESSORS(N) \
342 inline float s##N() { return sreg(N); } \
343 inline double d##N() { return dreg(N); } \
344 inline void set_s##N(float val) { set_sreg(N, val); } \
345 inline void set_d##N(double val) { set_dreg(N, val); }
346 REGISTER_CODE_LIST(FPREG_ACCESSORS)
347 #undef FPREG_ACCESSORS
349 bool N() { return nzcv_.N() != 0; }
350 bool Z() { return nzcv_.Z() != 0; }
351 bool C() { return nzcv_.C() != 0; }
352 bool V() { return nzcv_.V() != 0; }
353 SimSystemRegister& nzcv() { return nzcv_; }
355 // TODO(jbramley): Find a way to make the fpcr_ members return the proper
356 // types, so this accessor is not necessary.
357 FPRounding RMode() { return static_cast<FPRounding>(fpcr_.RMode()); }
358 SimSystemRegister& fpcr() { return fpcr_; }
360 // Debug helpers
361 void PrintSystemRegisters(bool print_all = false);
362 void PrintRegisters(bool print_all_regs = false);
363 void PrintFPRegisters(bool print_all_regs = false);
364 void PrintProcessorState();
366 static const char* WRegNameForCode(unsigned code,
367 Reg31Mode mode = Reg31IsZeroRegister);
368 static const char* XRegNameForCode(unsigned code,
369 Reg31Mode mode = Reg31IsZeroRegister);
370 static const char* SRegNameForCode(unsigned code);
371 static const char* DRegNameForCode(unsigned code);
372 static const char* VRegNameForCode(unsigned code);
374 inline bool coloured_trace() { return coloured_trace_; }
375 inline void set_coloured_trace(bool value) { coloured_trace_ = value; }
377 inline bool disasm_trace() { return disasm_trace_; }
378 inline void set_disasm_trace(bool value) {
379 if (value != disasm_trace_) {
380 if (value) {
381 decoder_->InsertVisitorBefore(print_disasm_, this);
382 } else {
383 decoder_->RemoveVisitor(print_disasm_);
385 disasm_trace_ = value;
388 inline void set_instruction_stats(bool value) {
389 if (value != instruction_stats_) {
390 if (value) {
391 decoder_->AppendVisitor(instrumentation_);
392 } else {
393 decoder_->RemoveVisitor(instrumentation_);
395 instruction_stats_ = value;
399 protected:
400 // Simulation helpers ------------------------------------
401 bool ConditionPassed(Condition cond) {
402 switch (cond) {
403 case eq:
404 return Z();
405 case ne:
406 return !Z();
407 case hs:
408 return C();
409 case lo:
410 return !C();
411 case mi:
412 return N();
413 case pl:
414 return !N();
415 case vs:
416 return V();
417 case vc:
418 return !V();
419 case hi:
420 return C() && !Z();
421 case ls:
422 return !(C() && !Z());
423 case ge:
424 return N() == V();
425 case lt:
426 return N() != V();
427 case gt:
428 return !Z() && (N() == V());
429 case le:
430 return !(!Z() && (N() == V()));
431 case nv: // Fall through.
432 case al:
433 return true;
434 default:
435 not_reached();
436 return false;
440 bool ConditionFailed(Condition cond) {
441 return !ConditionPassed(cond);
444 void AddSubHelper(Instruction* instr, int64_t op2);
445 int64_t AddWithCarry(unsigned reg_size,
446 bool set_flags,
447 int64_t src1,
448 int64_t src2,
449 int64_t carry_in = 0);
450 void LogicalHelper(Instruction* instr, int64_t op2);
451 void ConditionalCompareHelper(Instruction* instr, int64_t op2);
452 void LoadStoreHelper(Instruction* instr,
453 int64_t offset,
454 AddrMode addrmode);
455 void LoadStorePairHelper(Instruction* instr, AddrMode addrmode);
456 uint8_t* AddressModeHelper(unsigned addr_reg,
457 int64_t offset,
458 AddrMode addrmode);
460 uint64_t MemoryRead(const uint8_t* address, unsigned num_bytes);
461 uint8_t MemoryRead8(uint8_t* address);
462 uint16_t MemoryRead16(uint8_t* address);
463 uint32_t MemoryRead32(uint8_t* address);
464 float MemoryReadFP32(uint8_t* address);
465 uint64_t MemoryRead64(uint8_t* address);
466 double MemoryReadFP64(uint8_t* address);
468 void MemoryWrite(uint8_t* address, uint64_t value, unsigned num_bytes);
469 void MemoryWrite32(uint8_t* address, uint32_t value);
470 void MemoryWriteFP32(uint8_t* address, float value);
471 void MemoryWrite64(uint8_t* address, uint64_t value);
472 void MemoryWriteFP64(uint8_t* address, double value);
474 int64_t ShiftOperand(unsigned reg_size,
475 int64_t value,
476 Shift shift_type,
477 unsigned amount);
478 int64_t Rotate(unsigned reg_width,
479 int64_t value,
480 Shift shift_type,
481 unsigned amount);
482 int64_t ExtendValue(unsigned reg_width,
483 int64_t value,
484 Extend extend_type,
485 unsigned left_shift = 0);
487 uint64_t ReverseBits(uint64_t value, unsigned num_bits);
488 uint64_t ReverseBytes(uint64_t value, ReverseByteMode mode);
490 void FPCompare(double val0, double val1);
491 double FPRoundInt(double value, FPRounding round_mode);
492 double FPToDouble(float value);
493 float FPToFloat(double value, FPRounding round_mode);
494 double FixedToDouble(int64_t src, int fbits, FPRounding round_mode);
495 double UFixedToDouble(uint64_t src, int fbits, FPRounding round_mode);
496 float FixedToFloat(int64_t src, int fbits, FPRounding round_mode);
497 float UFixedToFloat(uint64_t src, int fbits, FPRounding round_mode);
498 int32_t FPToInt32(double value, FPRounding rmode);
499 int64_t FPToInt64(double value, FPRounding rmode);
500 uint32_t FPToUInt32(double value, FPRounding rmode);
501 uint64_t FPToUInt64(double value, FPRounding rmode);
502 double FPMax(double a, double b);
503 double FPMin(double a, double b);
505 // Pseudo Printf instruction
506 void DoPrintf(Instruction* instr);
507 // Pseudo HostCall instruction
508 void DoHostCall(Instruction* instr);
510 // Processor state ---------------------------------------
512 // Output stream.
513 std::ostream& stream_;
514 PrintDisassembler* print_disasm_;
516 // Instruction statistics instrumentation.
517 Instrument* instrumentation_;
519 // Hook to handle exceptions being thrown through simulated code.
520 ExceptionHook exception_hook_ = nullptr;
522 // General purpose registers. Register 31 is the stack pointer.
523 SimRegister registers_[kNumberOfRegisters];
525 // Floating point registers
526 SimFPRegister fpregisters_[kNumberOfFPRegisters];
528 // Program Status Register.
529 // bits[31, 27]: Condition flags N, Z, C, and V.
530 // (Negative, Zero, Carry, Overflow)
531 SimSystemRegister nzcv_;
533 // Floating-Point Control Register
534 SimSystemRegister fpcr_;
536 // Only a subset of FPCR features are supported by the simulator. This helper
537 // checks that the FPCR settings are supported.
539 // This is checked when floating-point instructions are executed, not when
540 // FPCR is set. This allows generated code to modify FPCR for external
541 // functions, or to save and restore it when entering and leaving generated
542 // code.
543 void AssertSupportedFPCR() {
544 assert(fpcr().DN() == 0); // No default-NaN support.
545 assert(fpcr().FZ() == 0); // No flush-to-zero support.
546 assert(fpcr().RMode() == FPTieEven); // Ties-to-even rounding only.
548 // The simulator does not support half-precision operations so fpcr().AHP()
549 // is irrelevant, and is not checked here.
552 static inline int CalcNFlag(uint64_t result, unsigned reg_size) {
553 return (result >> (reg_size - 1)) & 1;
556 static inline int CalcZFlag(uint64_t result) {
557 return result == 0;
560 static const uint32_t kConditionFlagsMask = 0xf0000000;
562 // Stack
563 byte* stack_;
564 static const int stack_protection_size_ = 256;
565 // 2 KB stack.
566 static const int stack_size_ = 2 * 1024 + 2 * stack_protection_size_;
567 byte* stack_limit_;
569 Decoder* decoder_;
570 // Indicates if the pc has been modified by the instruction and should not be
571 // automatically incremented.
572 bool pc_modified_;
573 Instruction* pc_;
575 static const char* xreg_names[];
576 static const char* wreg_names[];
577 static const char* sreg_names[];
578 static const char* dreg_names[];
579 static const char* vreg_names[];
581 static const Instruction* kEndOfSimAddress;
583 private:
584 bool coloured_trace_;
586 // Indicates whether the disassembly trace is active.
587 bool disasm_trace_;
589 // Indicates whether the instruction instrumentation is active.
590 bool instruction_stats_;
592 } // namespace vixl
594 #endif // VIXL_A64_SIMULATOR_A64_H_