1d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org// Copyright 2013 the V8 project authors. All rights reserved.
2d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org// Use of this source code is governed by a BSD-style license that can be
3d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org// found in the LICENSE file.
4d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org
5d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org#ifndef V8_CRANKSHAFT_ARM64_DELAYED_MASM_ARM64_H_
6d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org#define V8_CRANKSHAFT_ARM64_DELAYED_MASM_ARM64_H_
7d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org
8d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org#include "src/crankshaft/lithium.h"
9d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org
10d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.orgnamespace v8 {
119c55f0f957534144d2b8a64154f0a479249b34behenrik.lundin@webrtc.orgnamespace internal {
129c55f0f957534144d2b8a64154f0a479249b34behenrik.lundin@webrtc.org
13d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.orgclass LCodeGen;
14d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org
1512dc1a38ca54a000e4fecfbc6d41138b895c9ca5pbos@webrtc.org// This class delays the generation of some instructions. This way, we have a
16d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org// chance to merge two instructions in one (with load/store pair).
1788fbb2d86b33a3886bba1af4d098efa2c19eb1e7henrike@webrtc.org// Each instruction must either:
189c55f0f957534144d2b8a64154f0a479249b34behenrik.lundin@webrtc.org//  - merge with the pending instruction and generate just one instruction.
19d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org//  - emit the pending instruction and then generate the instruction (or set the
20d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org//    pending instruction).
21d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.orgclass DelayedMasm BASE_EMBEDDED {
22d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org public:
23d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  DelayedMasm(LCodeGen* owner,
24d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org              MacroAssembler* masm,
25d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org              const Register& scratch_register)
26d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org    : cgen_(owner), masm_(masm), scratch_register_(scratch_register),
27d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org      scratch_register_used_(false), pending_(kNone), saved_value_(0) {
28d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org#ifdef DEBUG
29d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org    pending_register_ = no_reg;
30d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org    pending_value_ = 0;
31d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org    pending_pc_ = 0;
32d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org    scratch_register_acquired_ = false;
33d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org#endif
34d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  }
35d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  ~DelayedMasm() {
36d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org    DCHECK(!scratch_register_acquired_);
37d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org    DCHECK(!scratch_register_used_);
38d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org    DCHECK(!pending());
39d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  }
40d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  inline void EndDelayedUse();
41d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org
42dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting  const Register& ScratchRegister() {
43d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org    scratch_register_used_ = true;
44d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org    return scratch_register_;
45d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  }
46d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  bool IsScratchRegister(const CPURegister& reg) {
47d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org    return reg.Is(scratch_register_);
48d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  }
49d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  bool scratch_register_used() const { return scratch_register_used_; }
50d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  void reset_scratch_register_used() { scratch_register_used_ = false; }
51dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting  // Acquire/Release scratch register for use outside this class.
52d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  void AcquireScratchRegister() {
53d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org    EmitPending();
54d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org    ResetSavedValue();
55d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org#ifdef DEBUG
56d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org    DCHECK(!scratch_register_acquired_);
57d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org    scratch_register_acquired_ = true;
58d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org#endif
59d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  }
60d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  void ReleaseScratchRegister() {
61cf808d2366e58b33540931d182f36800d9a15b0dHenrik Lundin#ifdef DEBUG
62fd11bbfb56b42f82e18a744a414325db7a56013fhenrik.lundin@webrtc.org    DCHECK(scratch_register_acquired_);
63dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting    scratch_register_acquired_ = false;
64d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org#endif
65d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  }
66d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  bool pending() { return pending_ != kNone; }
67d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org
68d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  // Extra layer over the macro-assembler instructions (which emits the
69362a55e7b0852a7be95f0d627321503258152551turaj@webrtc.org  // potential pending instruction).
70d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  inline void Mov(const Register& rd,
71dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting                  const Operand& operand,
72d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org                  DiscardMoveMode discard_mode = kDontDiscardForSameWReg);
73d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  inline void Fmov(FPRegister fd, FPRegister fn);
74d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  inline void Fmov(FPRegister fd, double imm);
75d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  inline void LoadObject(Register result, Handle<Object> object);
76d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  // Instructions which try to merge which the pending instructions.
77cf808d2366e58b33540931d182f36800d9a15b0dHenrik Lundin  void StackSlotMove(LOperand* src, LOperand* dst);
78cf808d2366e58b33540931d182f36800d9a15b0dHenrik Lundin  // StoreConstant can only be used if the scratch register is not acquired.
79cf808d2366e58b33540931d182f36800d9a15b0dHenrik Lundin  void StoreConstant(uint64_t value, const MemOperand& operand);
80cf808d2366e58b33540931d182f36800d9a15b0dHenrik Lundin  void Load(const CPURegister& rd, const MemOperand& operand);
81cf808d2366e58b33540931d182f36800d9a15b0dHenrik Lundin  void Store(const CPURegister& rd, const MemOperand& operand);
82cf808d2366e58b33540931d182f36800d9a15b0dHenrik Lundin  // Emit the potential pending instruction.
83fd11bbfb56b42f82e18a744a414325db7a56013fhenrik.lundin@webrtc.org  void EmitPending();
84d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  // Reset the pending state.
85dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting  void ResetPending() {
86dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting    pending_ = kNone;
87dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting#ifdef DEBUG
88dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting    pending_register_ = no_reg;
89dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting    MemOperand tmp;
90d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org    pending_address_src_ = tmp;
91d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org    pending_address_dst_ = tmp;
92d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org    pending_value_ = 0;
93d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org    pending_pc_ = 0;
94dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting#endif
95d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  }
96d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  void InitializeRootRegister() {
97d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org    masm_->InitializeRootRegister();
98d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  }
99d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org
100d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org private:
101d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  // Set the saved value and load the ScratchRegister with it.
102d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  void SetSavedValue(uint64_t saved_value) {
103d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org    DCHECK(saved_value != 0);
104d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org    if (saved_value_ != saved_value) {
105d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org      masm_->Mov(ScratchRegister(), saved_value);
106d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org      saved_value_ = saved_value;
107d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org    }
108d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  }
109d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  // Reset the saved value (i.e. the value of ScratchRegister is no longer
110dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting  // known).
111d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  void ResetSavedValue() {
1123c089d751ede283e21e186885eaf705c3257ccd2henrikg    saved_value_ = 0;
113d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  }
114d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org
115d94659dc279b86376c1a6470dc326fd342caaa93henrik.lundin@webrtc.org  LCodeGen* cgen_;
1169c55f0f957534144d2b8a64154f0a479249b34behenrik.lundin@webrtc.org  MacroAssembler* masm_;
117
118  // Register used to store a constant.
119  Register scratch_register_;
120  bool scratch_register_used_;
121
122  // Sometimes we store or load two values in two contiguous stack slots.
123  // In this case, we try to use the ldp/stp instructions to reduce code size.
124  // To be able to do that, instead of generating directly the instructions,
125  // we register with the following fields that an instruction needs to be
126  // generated. Then with the next instruction, if the instruction is
127  // consistent with the pending one for stp/ldp we generate ldp/stp. Else,
128  // if they are not consistent, we generate the pending instruction and we
129  // register the new instruction (which becomes pending).
130
131  // Enumeration of instructions which can be pending.
132  enum Pending {
133    kNone,
134    kStoreConstant,
135    kLoad, kStore,
136    kStackSlotMove
137  };
138  // The pending instruction.
139  Pending pending_;
140  // For kLoad, kStore: register which must be loaded/stored.
141  CPURegister pending_register_;
142  // For kLoad, kStackSlotMove: address of the load.
143  MemOperand pending_address_src_;
144  // For kStoreConstant, kStore, kStackSlotMove: address of the store.
145  MemOperand pending_address_dst_;
146  // For kStoreConstant: value to be stored.
147  uint64_t pending_value_;
148  // Value held into the ScratchRegister if the saved_value_ is not 0.
149  // For 0, we use xzr.
150  uint64_t saved_value_;
151#ifdef DEBUG
152  // Address where the pending instruction must be generated. It's only used to
153  // check that nothing else has been generated since we set the pending
154  // instruction.
155  int pending_pc_;
156  // If true, the scratch register has been acquired outside this class. The
157  // scratch register can no longer be used for constants.
158  bool scratch_register_acquired_;
159#endif
160};
161
162}  // namespace internal
163}  // namespace v8
164
165#endif  // V8_CRANKSHAFT_ARM64_DELAYED_MASM_ARM64_H_
166