blob: efadb0f26bcebf485d4a39f9257bb3a6415e7f04 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// Copyright 2012 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_CRANKSHAFT_MIPS64_LITHIUM_CODEGEN_MIPS_H_
6#define V8_CRANKSHAFT_MIPS64_LITHIUM_CODEGEN_MIPS_H_
7
8#include "src/ast/scopes.h"
9#include "src/crankshaft/lithium-codegen.h"
10#include "src/crankshaft/mips64/lithium-gap-resolver-mips64.h"
11#include "src/crankshaft/mips64/lithium-mips64.h"
12#include "src/deoptimizer.h"
13#include "src/safepoint-table.h"
14#include "src/utils.h"
15
16namespace v8 {
17namespace internal {
18
19// Forward declarations.
20class LDeferredCode;
21class SafepointGenerator;
22
23class LCodeGen: public LCodeGenBase {
24 public:
25 LCodeGen(LChunk* chunk, MacroAssembler* assembler, CompilationInfo* info)
26 : LCodeGenBase(chunk, assembler, info),
27 jump_table_(4, info->zone()),
28 scope_(info->scope()),
29 deferred_(8, info->zone()),
30 frame_is_built_(false),
31 safepoints_(info->zone()),
32 resolver_(this),
33 expected_safepoint_kind_(Safepoint::kSimple) {
34 PopulateDeoptimizationLiteralsWithInlinedFunctions();
35 }
36
37
38 int LookupDestination(int block_id) const {
39 return chunk()->LookupDestination(block_id);
40 }
41
42 bool IsNextEmittedBlock(int block_id) const {
43 return LookupDestination(block_id) == GetNextEmittedBlock();
44 }
45
46 bool NeedsEagerFrame() const {
47 return GetStackSlotCount() > 0 ||
48 info()->is_non_deferred_calling() ||
49 !info()->IsStub() ||
50 info()->requires_frame();
51 }
52 bool NeedsDeferredFrame() const {
53 return !NeedsEagerFrame() && info()->is_deferred_calling();
54 }
55
56 RAStatus GetRAState() const {
57 return frame_is_built_ ? kRAHasBeenSaved : kRAHasNotBeenSaved;
58 }
59
60 // Support for converting LOperands to assembler types.
61 // LOperand must be a register.
62 Register ToRegister(LOperand* op) const;
63
64 // LOperand is loaded into scratch, unless already a register.
65 Register EmitLoadRegister(LOperand* op, Register scratch);
66
67 // LOperand must be a double register.
68 DoubleRegister ToDoubleRegister(LOperand* op) const;
69
70 // LOperand is loaded into dbl_scratch, unless already a double register.
71 DoubleRegister EmitLoadDoubleRegister(LOperand* op,
72 FloatRegister flt_scratch,
73 DoubleRegister dbl_scratch);
74 int64_t ToRepresentation_donotuse(LConstantOperand* op,
75 const Representation& r) const;
76 int32_t ToInteger32(LConstantOperand* op) const;
77 Smi* ToSmi(LConstantOperand* op) const;
78 double ToDouble(LConstantOperand* op) const;
79 Operand ToOperand(LOperand* op);
80 MemOperand ToMemOperand(LOperand* op) const;
81 // Returns a MemOperand pointing to the high word of a DoubleStackSlot.
82 MemOperand ToHighMemOperand(LOperand* op) const;
83
84 bool IsInteger32(LConstantOperand* op) const;
85 bool IsSmi(LConstantOperand* op) const;
86 Handle<Object> ToHandle(LConstantOperand* op) const;
87
88 // Try to generate code for the entire chunk, but it may fail if the
89 // chunk contains constructs we cannot handle. Returns true if the
90 // code generation attempt succeeded.
91 bool GenerateCode();
92
93 // Finish the code by setting stack height, safepoint, and bailout
94 // information on it.
95 void FinishCode(Handle<Code> code);
96
97 void DoDeferredNumberTagD(LNumberTagD* instr);
98
99 enum IntegerSignedness { SIGNED_INT32, UNSIGNED_INT32 };
100 void DoDeferredNumberTagIU(LInstruction* instr,
101 LOperand* value,
102 LOperand* temp1,
103 LOperand* temp2,
104 IntegerSignedness signedness);
105
106 void DoDeferredTaggedToI(LTaggedToI* instr);
107 void DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr);
108 void DoDeferredStackCheck(LStackCheck* instr);
109 void DoDeferredMaybeGrowElements(LMaybeGrowElements* instr);
110 void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
111 void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
112 void DoDeferredAllocate(LAllocate* instr);
113
114 void DoDeferredInstanceMigration(LCheckMaps* instr, Register object);
115 void DoDeferredLoadMutableDouble(LLoadFieldByIndex* instr,
116 Register result,
117 Register object,
118 Register index);
119
120 // Parallel move support.
121 void DoParallelMove(LParallelMove* move);
122 void DoGap(LGap* instr);
123
124 MemOperand PrepareKeyedOperand(Register key,
125 Register base,
126 bool key_is_constant,
127 int constant_key,
128 int element_size,
129 int shift_size,
130 int base_offset);
131
132 // Emit frame translation commands for an environment.
133 void WriteTranslation(LEnvironment* environment, Translation* translation);
134
135 // Declare methods that deal with the individual node types.
136#define DECLARE_DO(type) void Do##type(L##type* node);
137 LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
138#undef DECLARE_DO
139
140 private:
141 LanguageMode language_mode() const { return info()->language_mode(); }
142
143 Scope* scope() const { return scope_; }
144
145 Register scratch0() { return kLithiumScratchReg; }
146 Register scratch1() { return kLithiumScratchReg2; }
147 DoubleRegister double_scratch0() { return kLithiumScratchDouble; }
148
149 LInstruction* GetNextInstruction();
150
151 void EmitClassOfTest(Label* if_true,
152 Label* if_false,
153 Handle<String> class_name,
154 Register input,
155 Register temporary,
156 Register temporary2);
157
158 int GetStackSlotCount() const { return chunk()->spill_slot_count(); }
159
160 void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code, zone()); }
161
162 void SaveCallerDoubles();
163 void RestoreCallerDoubles();
164
165 // Code generation passes. Returns true if code generation should
166 // continue.
167 void GenerateBodyInstructionPre(LInstruction* instr) override;
168 bool GeneratePrologue();
169 bool GenerateDeferredCode();
170 bool GenerateJumpTable();
171 bool GenerateSafepointTable();
172
173 // Generates the custom OSR entrypoint and sets the osr_pc_offset.
174 void GenerateOsrPrologue();
175
176 enum SafepointMode {
177 RECORD_SIMPLE_SAFEPOINT,
178 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS
179 };
180
181 void CallCode(Handle<Code> code,
182 RelocInfo::Mode mode,
183 LInstruction* instr);
184
185 void CallCodeGeneric(Handle<Code> code,
186 RelocInfo::Mode mode,
187 LInstruction* instr,
188 SafepointMode safepoint_mode);
189
190 void CallRuntime(const Runtime::Function* function,
191 int num_arguments,
192 LInstruction* instr,
193 SaveFPRegsMode save_doubles = kDontSaveFPRegs);
194
195 void CallRuntime(Runtime::FunctionId id,
196 int num_arguments,
197 LInstruction* instr) {
198 const Runtime::Function* function = Runtime::FunctionForId(id);
199 CallRuntime(function, num_arguments, instr);
200 }
201
202 void CallRuntime(Runtime::FunctionId id, LInstruction* instr) {
203 const Runtime::Function* function = Runtime::FunctionForId(id);
204 CallRuntime(function, function->nargs, instr);
205 }
206
207 void LoadContextFromDeferred(LOperand* context);
208 void CallRuntimeFromDeferred(Runtime::FunctionId id,
209 int argc,
210 LInstruction* instr,
211 LOperand* context);
212
213 // Generate a direct call to a known function. Expects the function
214 // to be in a1.
215 void CallKnownFunction(Handle<JSFunction> function,
216 int formal_parameter_count, int arity,
217 LInstruction* instr);
218
219 void RecordSafepointWithLazyDeopt(LInstruction* instr,
220 SafepointMode safepoint_mode);
221
222 void RegisterEnvironmentForDeoptimization(LEnvironment* environment,
223 Safepoint::DeoptMode mode);
224 void DeoptimizeIf(Condition condition, LInstruction* instr,
225 Deoptimizer::DeoptReason deopt_reason,
226 Deoptimizer::BailoutType bailout_type,
227 Register src1 = zero_reg,
228 const Operand& src2 = Operand(zero_reg));
229 void DeoptimizeIf(
230 Condition condition, LInstruction* instr,
231 Deoptimizer::DeoptReason deopt_reason = Deoptimizer::kNoReason,
232 Register src1 = zero_reg, const Operand& src2 = Operand(zero_reg));
233
234 void AddToTranslation(LEnvironment* environment,
235 Translation* translation,
236 LOperand* op,
237 bool is_tagged,
238 bool is_uint32,
239 int* object_index_pointer,
240 int* dematerialized_index_pointer);
241
242 Register ToRegister(int index) const;
243 DoubleRegister ToDoubleRegister(int index) const;
244
245 MemOperand BuildSeqStringOperand(Register string,
246 LOperand* index,
247 String::Encoding encoding);
248
249 void EmitIntegerMathAbs(LMathAbs* instr);
250 void EmitSmiMathAbs(LMathAbs* instr);
251
252 // Support for recording safepoint and position information.
253 void RecordSafepoint(LPointerMap* pointers,
254 Safepoint::Kind kind,
255 int arguments,
256 Safepoint::DeoptMode mode);
257 void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode);
258 void RecordSafepoint(Safepoint::DeoptMode mode);
259 void RecordSafepointWithRegisters(LPointerMap* pointers,
260 int arguments,
261 Safepoint::DeoptMode mode);
262
263 void RecordAndWritePosition(int position) override;
264
265 static Condition TokenToCondition(Token::Value op, bool is_unsigned);
266 void EmitGoto(int block);
267
268 // EmitBranch expects to be the last instruction of a block.
269 template<class InstrType>
270 void EmitBranch(InstrType instr,
271 Condition condition,
272 Register src1,
273 const Operand& src2);
274 template<class InstrType>
275 void EmitBranchF(InstrType instr,
276 Condition condition,
277 FPURegister src1,
278 FPURegister src2);
279 template <class InstrType>
280 void EmitTrueBranch(InstrType instr, Condition condition, Register src1,
281 const Operand& src2);
282 template <class InstrType>
283 void EmitFalseBranch(InstrType instr, Condition condition, Register src1,
284 const Operand& src2);
285 template<class InstrType>
286 void EmitFalseBranchF(InstrType instr,
287 Condition condition,
288 FPURegister src1,
289 FPURegister src2);
290 void EmitCmpI(LOperand* left, LOperand* right);
291 void EmitNumberUntagD(LNumberUntagD* instr, Register input,
292 DoubleRegister result, NumberUntagDMode mode);
293
294 // Emits optimized code for typeof x == "y". Modifies input register.
295 // Returns the condition on which a final split to
296 // true and false label should be made, to optimize fallthrough.
297 // Returns two registers in cmp1 and cmp2 that can be used in the
298 // Branch instruction after EmitTypeofIs.
299 Condition EmitTypeofIs(Label* true_label,
300 Label* false_label,
301 Register input,
302 Handle<String> type_name,
303 Register* cmp1,
304 Operand* cmp2);
305
306 // Emits optimized code for %_IsString(x). Preserves input register.
307 // Returns the condition on which a final split to
308 // true and false label should be made, to optimize fallthrough.
309 Condition EmitIsString(Register input,
310 Register temp1,
311 Label* is_not_string,
312 SmiCheck check_needed);
313
314 // Emits optimized code to deep-copy the contents of statically known
315 // object graphs (e.g. object literal boilerplate).
316 void EmitDeepCopy(Handle<JSObject> object,
317 Register result,
318 Register source,
319 int* offset,
320 AllocationSiteMode mode);
321 // Emit optimized code for integer division.
322 // Inputs are signed.
323 // All registers are clobbered.
324 // If 'remainder' is no_reg, it is not computed.
325 void EmitSignedIntegerDivisionByConstant(Register result,
326 Register dividend,
327 int32_t divisor,
328 Register remainder,
329 Register scratch,
330 LEnvironment* environment);
331
332
333 void EnsureSpaceForLazyDeopt(int space_needed) override;
334 void DoLoadKeyedExternalArray(LLoadKeyed* instr);
335 void DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr);
336 void DoLoadKeyedFixedArray(LLoadKeyed* instr);
337 void DoStoreKeyedExternalArray(LStoreKeyed* instr);
338 void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr);
339 void DoStoreKeyedFixedArray(LStoreKeyed* instr);
340
341 template <class T>
342 void EmitVectorLoadICRegisters(T* instr);
343 template <class T>
344 void EmitVectorStoreICRegisters(T* instr);
345
346 ZoneList<Deoptimizer::JumpTableEntry*> jump_table_;
347 Scope* const scope_;
348 ZoneList<LDeferredCode*> deferred_;
349 bool frame_is_built_;
350
351 // Builder that keeps track of safepoints in the code. The table
352 // itself is emitted at the end of the generated code.
353 SafepointTableBuilder safepoints_;
354
355 // Compiler from a set of parallel moves to a sequential list of moves.
356 LGapResolver resolver_;
357
358 Safepoint::Kind expected_safepoint_kind_;
359
360 class PushSafepointRegistersScope final BASE_EMBEDDED {
361 public:
362 explicit PushSafepointRegistersScope(LCodeGen* codegen)
363 : codegen_(codegen) {
364 DCHECK(codegen_->info()->is_calling());
365 DCHECK(codegen_->expected_safepoint_kind_ == Safepoint::kSimple);
366 codegen_->expected_safepoint_kind_ = Safepoint::kWithRegisters;
367
368 StoreRegistersStateStub stub(codegen_->isolate());
369 codegen_->masm_->push(ra);
370 codegen_->masm_->CallStub(&stub);
371 }
372
373 ~PushSafepointRegistersScope() {
374 DCHECK(codegen_->expected_safepoint_kind_ == Safepoint::kWithRegisters);
375 RestoreRegistersStateStub stub(codegen_->isolate());
376 codegen_->masm_->push(ra);
377 codegen_->masm_->CallStub(&stub);
378 codegen_->expected_safepoint_kind_ = Safepoint::kSimple;
379 }
380
381 private:
382 LCodeGen* codegen_;
383 };
384
385 friend class LDeferredCode;
386 friend class LEnvironment;
387 friend class SafepointGenerator;
388 DISALLOW_COPY_AND_ASSIGN(LCodeGen);
389};
390
391
392class LDeferredCode : public ZoneObject {
393 public:
394 explicit LDeferredCode(LCodeGen* codegen)
395 : codegen_(codegen),
396 external_exit_(NULL),
397 instruction_index_(codegen->current_instruction_) {
398 codegen->AddDeferredCode(this);
399 }
400
401 virtual ~LDeferredCode() {}
402 virtual void Generate() = 0;
403 virtual LInstruction* instr() = 0;
404
405 void SetExit(Label* exit) { external_exit_ = exit; }
406 Label* entry() { return &entry_; }
407 Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; }
408 int instruction_index() const { return instruction_index_; }
409
410 protected:
411 LCodeGen* codegen() const { return codegen_; }
412 MacroAssembler* masm() const { return codegen_->masm(); }
413
414 private:
415 LCodeGen* codegen_;
416 Label entry_;
417 Label exit_;
418 Label* external_exit_;
419 int instruction_index_;
420};
421
422} // namespace internal
423} // namespace v8
424
425#endif // V8_CRANKSHAFT_MIPS64_LITHIUM_CODEGEN_MIPS_H_