1 // Copyright 2014 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_PPC_LITHIUM_CODEGEN_PPC_H_ 6 #define V8_CRANKSHAFT_PPC_LITHIUM_CODEGEN_PPC_H_ 7 8 #include "src/ast/scopes.h" 9 #include "src/crankshaft/lithium-codegen.h" 10 #include "src/crankshaft/ppc/lithium-gap-resolver-ppc.h" 11 #include "src/crankshaft/ppc/lithium-ppc.h" 12 #include "src/deoptimizer.h" 13 #include "src/safepoint-table.h" 14 #include "src/utils.h" 15 16 namespace v8 { 17 namespace internal { 18 19 // Forward declarations. 20 class LDeferredCode; 21 class SafepointGenerator; 22 23 class LCodeGen : public LCodeGenBase { 24 public: LCodeGen(LChunk * chunk,MacroAssembler * assembler,CompilationInfo * info)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 LookupDestination(int block_id)38 int LookupDestination(int block_id) const { 39 return chunk()->LookupDestination(block_id); 40 } 41 IsNextEmittedBlock(int block_id)42 bool IsNextEmittedBlock(int block_id) const { 43 return LookupDestination(block_id) == GetNextEmittedBlock(); 44 } 45 NeedsEagerFrame()46 bool NeedsEagerFrame() const { 47 return HasAllocatedStackSlots() || info()->is_non_deferred_calling() || 48 !info()->IsStub() || info()->requires_frame(); 49 } NeedsDeferredFrame()50 bool NeedsDeferredFrame() const { 51 return !NeedsEagerFrame() && info()->is_deferred_calling(); 52 } 53 GetLinkRegisterState()54 LinkRegisterStatus GetLinkRegisterState() const { 55 return frame_is_built_ ? kLRHasBeenSaved : kLRHasNotBeenSaved; 56 } 57 58 // Support for converting LOperands to assembler types. 59 // LOperand must be a register. 60 Register ToRegister(LOperand* op) const; 61 62 // LOperand is loaded into scratch, unless already a register. 63 Register EmitLoadRegister(LOperand* op, Register scratch); 64 65 // LConstantOperand must be an Integer32 or Smi 66 void EmitLoadIntegerConstant(LConstantOperand* const_op, Register dst); 67 68 // LOperand must be a double register. 69 DoubleRegister ToDoubleRegister(LOperand* op) const; 70 71 intptr_t ToRepresentation(LConstantOperand* op, 72 const Representation& r) const; 73 int32_t ToInteger32(LConstantOperand* op) const; 74 Smi* ToSmi(LConstantOperand* op) const; 75 double ToDouble(LConstantOperand* op) const; 76 Operand ToOperand(LOperand* op); 77 MemOperand ToMemOperand(LOperand* op) const; 78 // Returns a MemOperand pointing to the high word of a DoubleStackSlot. 79 MemOperand ToHighMemOperand(LOperand* op) const; 80 81 bool IsInteger32(LConstantOperand* op) const; 82 bool IsSmi(LConstantOperand* op) const; 83 Handle<Object> ToHandle(LConstantOperand* op) const; 84 85 // Try to generate code for the entire chunk, but it may fail if the 86 // chunk contains constructs we cannot handle. Returns true if the 87 // code generation attempt succeeded. 88 bool GenerateCode(); 89 90 // Finish the code by setting stack height, safepoint, and bailout 91 // information on it. 92 void FinishCode(Handle<Code> code); 93 94 // Deferred code support. 95 void DoDeferredNumberTagD(LNumberTagD* instr); 96 97 enum IntegerSignedness { SIGNED_INT32, UNSIGNED_INT32 }; 98 void DoDeferredNumberTagIU(LInstruction* instr, LOperand* value, 99 LOperand* temp1, LOperand* temp2, 100 IntegerSignedness signedness); 101 102 void DoDeferredTaggedToI(LTaggedToI* instr); 103 void DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr); 104 void DoDeferredStackCheck(LStackCheck* instr); 105 void DoDeferredMaybeGrowElements(LMaybeGrowElements* instr); 106 void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr); 107 void DoDeferredStringCharFromCode(LStringCharFromCode* instr); 108 void DoDeferredAllocate(LAllocate* instr); 109 void DoDeferredInstanceMigration(LCheckMaps* instr, Register object); 110 void DoDeferredLoadMutableDouble(LLoadFieldByIndex* instr, Register result, 111 Register object, Register index); 112 113 // Parallel move support. 114 void DoParallelMove(LParallelMove* move); 115 void DoGap(LGap* instr); 116 117 MemOperand PrepareKeyedOperand(Register key, Register base, 118 bool key_is_constant, bool key_is_tagged, 119 int constant_key, int element_size_shift, 120 int base_offset); 121 122 // Emit frame translation commands for an environment. 123 void WriteTranslation(LEnvironment* environment, Translation* translation); 124 125 // Declare methods that deal with the individual node types. 126 #define DECLARE_DO(type) void Do##type(L##type* node); LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)127 LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO) 128 #undef DECLARE_DO 129 130 private: 131 Scope* scope() const { return scope_; } 132 scratch0()133 Register scratch0() { return kLithiumScratch; } double_scratch0()134 DoubleRegister double_scratch0() { return kScratchDoubleReg; } 135 136 LInstruction* GetNextInstruction(); 137 138 void EmitClassOfTest(Label* if_true, Label* if_false, 139 Handle<String> class_name, Register input, 140 Register temporary, Register temporary2); 141 HasAllocatedStackSlots()142 bool HasAllocatedStackSlots() const { 143 return chunk()->HasAllocatedStackSlots(); 144 } GetStackSlotCount()145 int GetStackSlotCount() const { return chunk()->GetSpillSlotCount(); } GetTotalFrameSlotCount()146 int GetTotalFrameSlotCount() const { 147 return chunk()->GetTotalFrameSlotCount(); 148 } 149 AddDeferredCode(LDeferredCode * code)150 void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code, zone()); } 151 152 void SaveCallerDoubles(); 153 void RestoreCallerDoubles(); 154 155 // Code generation passes. Returns true if code generation should 156 // continue. 157 void GenerateBodyInstructionPre(LInstruction* instr) override; 158 bool GeneratePrologue(); 159 bool GenerateDeferredCode(); 160 bool GenerateJumpTable(); 161 bool GenerateSafepointTable(); 162 163 // Generates the custom OSR entrypoint and sets the osr_pc_offset. 164 void GenerateOsrPrologue(); 165 166 enum SafepointMode { 167 RECORD_SIMPLE_SAFEPOINT, 168 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS 169 }; 170 171 void CallCode(Handle<Code> code, RelocInfo::Mode mode, LInstruction* instr); 172 173 void CallCodeGeneric(Handle<Code> code, RelocInfo::Mode mode, 174 LInstruction* instr, SafepointMode safepoint_mode); 175 176 void CallRuntime(const Runtime::Function* function, int num_arguments, 177 LInstruction* instr, 178 SaveFPRegsMode save_doubles = kDontSaveFPRegs); 179 CallRuntime(Runtime::FunctionId id,int num_arguments,LInstruction * instr)180 void CallRuntime(Runtime::FunctionId id, int num_arguments, 181 LInstruction* instr) { 182 const Runtime::Function* function = Runtime::FunctionForId(id); 183 CallRuntime(function, num_arguments, instr); 184 } 185 CallRuntime(Runtime::FunctionId id,LInstruction * instr)186 void CallRuntime(Runtime::FunctionId id, LInstruction* instr) { 187 const Runtime::Function* function = Runtime::FunctionForId(id); 188 CallRuntime(function, function->nargs, instr); 189 } 190 191 void LoadContextFromDeferred(LOperand* context); 192 void CallRuntimeFromDeferred(Runtime::FunctionId id, int argc, 193 LInstruction* instr, LOperand* context); 194 195 void PrepareForTailCall(const ParameterCount& actual, Register scratch1, 196 Register scratch2, Register scratch3); 197 198 // Generate a direct call to a known function. Expects the function 199 // to be in r4. 200 void CallKnownFunction(Handle<JSFunction> function, 201 int formal_parameter_count, int arity, 202 bool is_tail_call, LInstruction* instr); 203 204 void RecordSafepointWithLazyDeopt(LInstruction* instr, 205 SafepointMode safepoint_mode); 206 207 void RegisterEnvironmentForDeoptimization(LEnvironment* environment, 208 Safepoint::DeoptMode mode); 209 void DeoptimizeIf(Condition condition, LInstruction* instr, 210 Deoptimizer::DeoptReason deopt_reason, 211 Deoptimizer::BailoutType bailout_type, CRegister cr = cr7); 212 void DeoptimizeIf(Condition condition, LInstruction* instr, 213 Deoptimizer::DeoptReason deopt_reason, CRegister cr = cr7); 214 215 void AddToTranslation(LEnvironment* environment, Translation* translation, 216 LOperand* op, bool is_tagged, bool is_uint32, 217 int* object_index_pointer, 218 int* dematerialized_index_pointer); 219 220 Register ToRegister(int index) const; 221 DoubleRegister ToDoubleRegister(int index) const; 222 223 MemOperand BuildSeqStringOperand(Register string, LOperand* index, 224 String::Encoding encoding); 225 226 void EmitMathAbs(LMathAbs* instr); 227 #if V8_TARGET_ARCH_PPC64 228 void EmitInteger32MathAbs(LMathAbs* instr); 229 #endif 230 231 // Support for recording safepoint and position information. 232 void RecordSafepoint(LPointerMap* pointers, Safepoint::Kind kind, 233 int arguments, Safepoint::DeoptMode mode); 234 void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode); 235 void RecordSafepoint(Safepoint::DeoptMode mode); 236 void RecordSafepointWithRegisters(LPointerMap* pointers, int arguments, 237 Safepoint::DeoptMode mode); 238 239 void RecordAndWritePosition(int position) override; 240 241 static Condition TokenToCondition(Token::Value op); 242 void EmitGoto(int block); 243 244 // EmitBranch expects to be the last instruction of a block. 245 template <class InstrType> 246 void EmitBranch(InstrType instr, Condition condition, CRegister cr = cr7); 247 template <class InstrType> 248 void EmitTrueBranch(InstrType instr, Condition condition, CRegister cr = cr7); 249 template <class InstrType> 250 void EmitFalseBranch(InstrType instr, Condition condition, 251 CRegister cr = cr7); 252 void EmitNumberUntagD(LNumberUntagD* instr, Register input, 253 DoubleRegister result, NumberUntagDMode mode); 254 255 // Emits optimized code for typeof x == "y". Modifies input register. 256 // Returns the condition on which a final split to 257 // true and false label should be made, to optimize fallthrough. 258 Condition EmitTypeofIs(Label* true_label, Label* false_label, Register input, 259 Handle<String> type_name); 260 261 // Emits optimized code for %_IsString(x). Preserves input register. 262 // Returns the condition on which a final split to 263 // true and false label should be made, to optimize fallthrough. 264 Condition EmitIsString(Register input, Register temp1, Label* is_not_string, 265 SmiCheck check_needed); 266 267 // Emits optimized code to deep-copy the contents of statically known 268 // object graphs (e.g. object literal boilerplate). 269 void EmitDeepCopy(Handle<JSObject> object, Register result, Register source, 270 int* offset, AllocationSiteMode mode); 271 272 void EnsureSpaceForLazyDeopt(int space_needed) override; 273 void DoLoadKeyedExternalArray(LLoadKeyed* instr); 274 void DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr); 275 void DoLoadKeyedFixedArray(LLoadKeyed* instr); 276 void DoStoreKeyedExternalArray(LStoreKeyed* instr); 277 void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr); 278 void DoStoreKeyedFixedArray(LStoreKeyed* instr); 279 280 template <class T> 281 void EmitVectorLoadICRegisters(T* instr); 282 template <class T> 283 void EmitVectorStoreICRegisters(T* instr); 284 285 ZoneList<Deoptimizer::JumpTableEntry> jump_table_; 286 Scope* const scope_; 287 ZoneList<LDeferredCode*> deferred_; 288 bool frame_is_built_; 289 290 // Builder that keeps track of safepoints in the code. The table 291 // itself is emitted at the end of the generated code. 292 SafepointTableBuilder safepoints_; 293 294 // Compiler from a set of parallel moves to a sequential list of moves. 295 LGapResolver resolver_; 296 297 Safepoint::Kind expected_safepoint_kind_; 298 299 class PushSafepointRegistersScope final BASE_EMBEDDED { 300 public: PushSafepointRegistersScope(LCodeGen * codegen)301 explicit PushSafepointRegistersScope(LCodeGen* codegen) 302 : codegen_(codegen) { 303 DCHECK(codegen_->info()->is_calling()); 304 DCHECK(codegen_->expected_safepoint_kind_ == Safepoint::kSimple); 305 codegen_->expected_safepoint_kind_ = Safepoint::kWithRegisters; 306 StoreRegistersStateStub stub(codegen_->isolate()); 307 codegen_->masm_->CallStub(&stub); 308 } 309 ~PushSafepointRegistersScope()310 ~PushSafepointRegistersScope() { 311 DCHECK(codegen_->expected_safepoint_kind_ == Safepoint::kWithRegisters); 312 RestoreRegistersStateStub stub(codegen_->isolate()); 313 codegen_->masm_->CallStub(&stub); 314 codegen_->expected_safepoint_kind_ = Safepoint::kSimple; 315 } 316 317 private: 318 LCodeGen* codegen_; 319 }; 320 321 friend class LDeferredCode; 322 friend class LEnvironment; 323 friend class SafepointGenerator; 324 DISALLOW_COPY_AND_ASSIGN(LCodeGen); 325 }; 326 327 328 class LDeferredCode : public ZoneObject { 329 public: LDeferredCode(LCodeGen * codegen)330 explicit LDeferredCode(LCodeGen* codegen) 331 : codegen_(codegen), 332 external_exit_(NULL), 333 instruction_index_(codegen->current_instruction_) { 334 codegen->AddDeferredCode(this); 335 } 336 ~LDeferredCode()337 virtual ~LDeferredCode() {} 338 virtual void Generate() = 0; 339 virtual LInstruction* instr() = 0; 340 SetExit(Label * exit)341 void SetExit(Label* exit) { external_exit_ = exit; } entry()342 Label* entry() { return &entry_; } exit()343 Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; } instruction_index()344 int instruction_index() const { return instruction_index_; } 345 346 protected: codegen()347 LCodeGen* codegen() const { return codegen_; } masm()348 MacroAssembler* masm() const { return codegen_->masm(); } 349 350 private: 351 LCodeGen* codegen_; 352 Label entry_; 353 Label exit_; 354 Label* external_exit_; 355 int instruction_index_; 356 }; 357 } // namespace internal 358 } // namespace v8 359 360 #endif // V8_CRANKSHAFT_PPC_LITHIUM_CODEGEN_PPC_H_ 361