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 GetStackSlotCount() > 0 || 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 LanguageMode language_mode() const { return info()->language_mode(); } 132 scope()133 Scope* scope() const { return scope_; } 134 scratch0()135 Register scratch0() { return kLithiumScratch; } double_scratch0()136 DoubleRegister double_scratch0() { return kScratchDoubleReg; } 137 138 LInstruction* GetNextInstruction(); 139 140 void EmitClassOfTest(Label* if_true, Label* if_false, 141 Handle<String> class_name, Register input, 142 Register temporary, Register temporary2); 143 GetStackSlotCount()144 int GetStackSlotCount() const { return chunk()->spill_slot_count(); } 145 AddDeferredCode(LDeferredCode * code)146 void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code, zone()); } 147 148 void SaveCallerDoubles(); 149 void RestoreCallerDoubles(); 150 151 // Code generation passes. Returns true if code generation should 152 // continue. 153 void GenerateBodyInstructionPre(LInstruction* instr) override; 154 bool GeneratePrologue(); 155 bool GenerateDeferredCode(); 156 bool GenerateJumpTable(); 157 bool GenerateSafepointTable(); 158 159 // Generates the custom OSR entrypoint and sets the osr_pc_offset. 160 void GenerateOsrPrologue(); 161 162 enum SafepointMode { 163 RECORD_SIMPLE_SAFEPOINT, 164 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS 165 }; 166 167 void CallCode(Handle<Code> code, RelocInfo::Mode mode, LInstruction* instr); 168 169 void CallCodeGeneric(Handle<Code> code, RelocInfo::Mode mode, 170 LInstruction* instr, SafepointMode safepoint_mode); 171 172 void CallRuntime(const Runtime::Function* function, int num_arguments, 173 LInstruction* instr, 174 SaveFPRegsMode save_doubles = kDontSaveFPRegs); 175 CallRuntime(Runtime::FunctionId id,int num_arguments,LInstruction * instr)176 void CallRuntime(Runtime::FunctionId id, int num_arguments, 177 LInstruction* instr) { 178 const Runtime::Function* function = Runtime::FunctionForId(id); 179 CallRuntime(function, num_arguments, instr); 180 } 181 CallRuntime(Runtime::FunctionId id,LInstruction * instr)182 void CallRuntime(Runtime::FunctionId id, LInstruction* instr) { 183 const Runtime::Function* function = Runtime::FunctionForId(id); 184 CallRuntime(function, function->nargs, instr); 185 } 186 187 void LoadContextFromDeferred(LOperand* context); 188 void CallRuntimeFromDeferred(Runtime::FunctionId id, int argc, 189 LInstruction* instr, LOperand* context); 190 191 // Generate a direct call to a known function. Expects the function 192 // to be in r4. 193 void CallKnownFunction(Handle<JSFunction> function, 194 int formal_parameter_count, int arity, 195 LInstruction* instr); 196 197 void RecordSafepointWithLazyDeopt(LInstruction* instr, 198 SafepointMode safepoint_mode); 199 200 void RegisterEnvironmentForDeoptimization(LEnvironment* environment, 201 Safepoint::DeoptMode mode); 202 void DeoptimizeIf(Condition condition, LInstruction* instr, 203 Deoptimizer::DeoptReason deopt_reason, 204 Deoptimizer::BailoutType bailout_type, CRegister cr = cr7); 205 void DeoptimizeIf(Condition condition, LInstruction* instr, 206 Deoptimizer::DeoptReason deopt_reason, CRegister cr = cr7); 207 208 void AddToTranslation(LEnvironment* environment, Translation* translation, 209 LOperand* op, bool is_tagged, bool is_uint32, 210 int* object_index_pointer, 211 int* dematerialized_index_pointer); 212 213 Register ToRegister(int index) const; 214 DoubleRegister ToDoubleRegister(int index) const; 215 216 MemOperand BuildSeqStringOperand(Register string, LOperand* index, 217 String::Encoding encoding); 218 219 void EmitMathAbs(LMathAbs* instr); 220 #if V8_TARGET_ARCH_PPC64 221 void EmitInteger32MathAbs(LMathAbs* instr); 222 #endif 223 224 // Support for recording safepoint and position information. 225 void RecordSafepoint(LPointerMap* pointers, Safepoint::Kind kind, 226 int arguments, Safepoint::DeoptMode mode); 227 void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode); 228 void RecordSafepoint(Safepoint::DeoptMode mode); 229 void RecordSafepointWithRegisters(LPointerMap* pointers, int arguments, 230 Safepoint::DeoptMode mode); 231 232 void RecordAndWritePosition(int position) override; 233 234 static Condition TokenToCondition(Token::Value op); 235 void EmitGoto(int block); 236 237 // EmitBranch expects to be the last instruction of a block. 238 template <class InstrType> 239 void EmitBranch(InstrType instr, Condition condition, CRegister cr = cr7); 240 template <class InstrType> 241 void EmitTrueBranch(InstrType instr, Condition condition, CRegister cr = cr7); 242 template <class InstrType> 243 void EmitFalseBranch(InstrType instr, Condition condition, 244 CRegister cr = cr7); 245 void EmitNumberUntagD(LNumberUntagD* instr, Register input, 246 DoubleRegister result, NumberUntagDMode mode); 247 248 // Emits optimized code for typeof x == "y". Modifies input register. 249 // Returns the condition on which a final split to 250 // true and false label should be made, to optimize fallthrough. 251 Condition EmitTypeofIs(Label* true_label, Label* false_label, Register input, 252 Handle<String> type_name); 253 254 // Emits optimized code for %_IsString(x). Preserves input register. 255 // Returns the condition on which a final split to 256 // true and false label should be made, to optimize fallthrough. 257 Condition EmitIsString(Register input, Register temp1, Label* is_not_string, 258 SmiCheck check_needed); 259 260 // Emits optimized code to deep-copy the contents of statically known 261 // object graphs (e.g. object literal boilerplate). 262 void EmitDeepCopy(Handle<JSObject> object, Register result, Register source, 263 int* offset, AllocationSiteMode mode); 264 265 void EnsureSpaceForLazyDeopt(int space_needed) override; 266 void DoLoadKeyedExternalArray(LLoadKeyed* instr); 267 void DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr); 268 void DoLoadKeyedFixedArray(LLoadKeyed* instr); 269 void DoStoreKeyedExternalArray(LStoreKeyed* instr); 270 void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr); 271 void DoStoreKeyedFixedArray(LStoreKeyed* instr); 272 273 template <class T> 274 void EmitVectorLoadICRegisters(T* instr); 275 template <class T> 276 void EmitVectorStoreICRegisters(T* instr); 277 278 ZoneList<Deoptimizer::JumpTableEntry> jump_table_; 279 Scope* const scope_; 280 ZoneList<LDeferredCode*> deferred_; 281 bool frame_is_built_; 282 283 // Builder that keeps track of safepoints in the code. The table 284 // itself is emitted at the end of the generated code. 285 SafepointTableBuilder safepoints_; 286 287 // Compiler from a set of parallel moves to a sequential list of moves. 288 LGapResolver resolver_; 289 290 Safepoint::Kind expected_safepoint_kind_; 291 292 class PushSafepointRegistersScope final BASE_EMBEDDED { 293 public: PushSafepointRegistersScope(LCodeGen * codegen)294 explicit PushSafepointRegistersScope(LCodeGen* codegen) 295 : codegen_(codegen) { 296 DCHECK(codegen_->info()->is_calling()); 297 DCHECK(codegen_->expected_safepoint_kind_ == Safepoint::kSimple); 298 codegen_->expected_safepoint_kind_ = Safepoint::kWithRegisters; 299 StoreRegistersStateStub stub(codegen_->isolate()); 300 codegen_->masm_->CallStub(&stub); 301 } 302 ~PushSafepointRegistersScope()303 ~PushSafepointRegistersScope() { 304 DCHECK(codegen_->expected_safepoint_kind_ == Safepoint::kWithRegisters); 305 RestoreRegistersStateStub stub(codegen_->isolate()); 306 codegen_->masm_->CallStub(&stub); 307 codegen_->expected_safepoint_kind_ = Safepoint::kSimple; 308 } 309 310 private: 311 LCodeGen* codegen_; 312 }; 313 314 friend class LDeferredCode; 315 friend class LEnvironment; 316 friend class SafepointGenerator; 317 DISALLOW_COPY_AND_ASSIGN(LCodeGen); 318 }; 319 320 321 class LDeferredCode : public ZoneObject { 322 public: LDeferredCode(LCodeGen * codegen)323 explicit LDeferredCode(LCodeGen* codegen) 324 : codegen_(codegen), 325 external_exit_(NULL), 326 instruction_index_(codegen->current_instruction_) { 327 codegen->AddDeferredCode(this); 328 } 329 ~LDeferredCode()330 virtual ~LDeferredCode() {} 331 virtual void Generate() = 0; 332 virtual LInstruction* instr() = 0; 333 SetExit(Label * exit)334 void SetExit(Label* exit) { external_exit_ = exit; } entry()335 Label* entry() { return &entry_; } exit()336 Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; } instruction_index()337 int instruction_index() const { return instruction_index_; } 338 339 protected: codegen()340 LCodeGen* codegen() const { return codegen_; } masm()341 MacroAssembler* masm() const { return codegen_->masm(); } 342 343 private: 344 LCodeGen* codegen_; 345 Label entry_; 346 Label exit_; 347 Label* external_exit_; 348 int instruction_index_; 349 }; 350 } // namespace internal 351 } // namespace v8 352 353 #endif // V8_CRANKSHAFT_PPC_LITHIUM_CODEGEN_PPC_H_ 354