| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 // Class for intrinsifying functions. | 4 // Class for intrinsifying functions. |
| 5 | 5 |
| 6 #include "vm/assembler.h" | 6 #include "vm/assembler.h" |
| 7 #include "vm/compiler.h" | 7 #include "vm/compiler.h" |
| 8 #include "vm/cpu.h" | 8 #include "vm/cpu.h" |
| 9 #include "vm/flags.h" | 9 #include "vm/flags.h" |
| 10 #include "vm/flow_graph.h" | 10 #include "vm/flow_graph.h" |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 75 } else { \ | 75 } else { \ |
| 76 str = String::New(#class_name); \ | 76 str = String::New(#class_name); \ |
| 77 cls = lib.LookupClassAllowPrivate(str); \ | 77 cls = lib.LookupClassAllowPrivate(str); \ |
| 78 ASSERT(!cls.IsNull()); \ | 78 ASSERT(!cls.IsNull()); \ |
| 79 error = cls.EnsureIsFinalized(thread); \ | 79 error = cls.EnsureIsFinalized(thread); \ |
| 80 if (!error.IsNull()) { \ | 80 if (!error.IsNull()) { \ |
| 81 OS::PrintErr("%s\n", error.ToErrorCString()); \ | 81 OS::PrintErr("%s\n", error.ToErrorCString()); \ |
| 82 } \ | 82 } \ |
| 83 ASSERT(error.IsNull()); \ | 83 ASSERT(error.IsNull()); \ |
| 84 if (#function_name[0] == '.') { \ | 84 if (#function_name[0] == '.') { \ |
| 85 str = String::New(#class_name#function_name); \ | 85 str = String::New(#class_name #function_name); \ |
| 86 } else { \ | 86 } else { \ |
| 87 str = String::New(#function_name); \ | 87 str = String::New(#function_name); \ |
| 88 } \ | 88 } \ |
| 89 func = cls.LookupFunctionAllowPrivate(str); \ | 89 func = cls.LookupFunctionAllowPrivate(str); \ |
| 90 } \ | 90 } \ |
| 91 ASSERT(!func.IsNull()); \ | 91 ASSERT(!func.IsNull()); \ |
| 92 func.set_is_intrinsic(true); | 92 func.set_is_intrinsic(true); |
| 93 | 93 |
| 94 // Set up all core lib functions that can be intrinsified. | 94 // Set up all core lib functions that can be intrinsified. |
| 95 lib = Library::CoreLibrary(); | 95 lib = Library::CoreLibrary(); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 115 ASSERT(!lib.IsNull()); | 115 ASSERT(!lib.IsNull()); |
| 116 DEVELOPER_LIB_INTRINSIC_LIST(SETUP_FUNCTION); | 116 DEVELOPER_LIB_INTRINSIC_LIST(SETUP_FUNCTION); |
| 117 | 117 |
| 118 #undef SETUP_FUNCTION | 118 #undef SETUP_FUNCTION |
| 119 } | 119 } |
| 120 #endif // defined(DART_NO_SNAPSHOT). | 120 #endif // defined(DART_NO_SNAPSHOT). |
| 121 | 121 |
| 122 | 122 |
| 123 // DBC does not use graph intrinsics. | 123 // DBC does not use graph intrinsics. |
| 124 #if !defined(TARGET_ARCH_DBC) | 124 #if !defined(TARGET_ARCH_DBC) |
| 125 static void EmitCodeFor(FlowGraphCompiler* compiler, | 125 static void EmitCodeFor(FlowGraphCompiler* compiler, FlowGraph* graph) { |
| 126 FlowGraph* graph) { | |
| 127 // The FlowGraph here is constructed by the intrinsics builder methods, and | 126 // The FlowGraph here is constructed by the intrinsics builder methods, and |
| 128 // is different from compiler->flow_graph(), the original method's flow graph. | 127 // is different from compiler->flow_graph(), the original method's flow graph. |
| 129 compiler->assembler()->Comment("Graph intrinsic begin"); | 128 compiler->assembler()->Comment("Graph intrinsic begin"); |
| 130 for (intptr_t i = 0; i < graph->reverse_postorder().length(); i++) { | 129 for (intptr_t i = 0; i < graph->reverse_postorder().length(); i++) { |
| 131 BlockEntryInstr* block = graph->reverse_postorder()[i]; | 130 BlockEntryInstr* block = graph->reverse_postorder()[i]; |
| 132 if (block->IsGraphEntry()) continue; // No code for graph entry needed. | 131 if (block->IsGraphEntry()) continue; // No code for graph entry needed. |
| 133 | 132 |
| 134 if (block->HasParallelMove()) { | 133 if (block->HasParallelMove()) { |
| 135 compiler->parallel_move_resolver()->EmitNativeCode( | 134 compiler->parallel_move_resolver()->EmitNativeCode( |
| 136 block->parallel_move()); | 135 block->parallel_move()); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 158 compiler->assembler()->Comment("Graph intrinsic end"); | 157 compiler->assembler()->Comment("Graph intrinsic end"); |
| 159 } | 158 } |
| 160 #endif | 159 #endif |
| 161 | 160 |
| 162 | 161 |
| 163 bool Intrinsifier::GraphIntrinsify(const ParsedFunction& parsed_function, | 162 bool Intrinsifier::GraphIntrinsify(const ParsedFunction& parsed_function, |
| 164 FlowGraphCompiler* compiler) { | 163 FlowGraphCompiler* compiler) { |
| 165 #if !defined(TARGET_ARCH_DBC) | 164 #if !defined(TARGET_ARCH_DBC) |
| 166 ZoneGrowableArray<const ICData*>* ic_data_array = | 165 ZoneGrowableArray<const ICData*>* ic_data_array = |
| 167 new ZoneGrowableArray<const ICData*>(); | 166 new ZoneGrowableArray<const ICData*>(); |
| 168 FlowGraphBuilder builder(parsed_function, | 167 FlowGraphBuilder builder(parsed_function, *ic_data_array, |
| 169 *ic_data_array, | |
| 170 NULL, // NULL = not inlining. | 168 NULL, // NULL = not inlining. |
| 171 Compiler::kNoOSRDeoptId); | 169 Compiler::kNoOSRDeoptId); |
| 172 | 170 |
| 173 intptr_t block_id = builder.AllocateBlockId(); | 171 intptr_t block_id = builder.AllocateBlockId(); |
| 174 TargetEntryInstr* normal_entry = | 172 TargetEntryInstr* normal_entry = |
| 175 new TargetEntryInstr(block_id, | 173 new TargetEntryInstr(block_id, CatchClauseNode::kInvalidTryIndex); |
| 176 CatchClauseNode::kInvalidTryIndex); | |
| 177 GraphEntryInstr* graph_entry = new GraphEntryInstr( | 174 GraphEntryInstr* graph_entry = new GraphEntryInstr( |
| 178 parsed_function, normal_entry, Compiler::kNoOSRDeoptId); | 175 parsed_function, normal_entry, Compiler::kNoOSRDeoptId); |
| 179 FlowGraph* graph = new FlowGraph(parsed_function, graph_entry, block_id); | 176 FlowGraph* graph = new FlowGraph(parsed_function, graph_entry, block_id); |
| 180 const Function& function = parsed_function.function(); | 177 const Function& function = parsed_function.function(); |
| 181 switch (function.recognized_kind()) { | 178 switch (function.recognized_kind()) { |
| 182 #define EMIT_CASE(class_name, function_name, enum_name, type, fp) \ | 179 #define EMIT_CASE(class_name, function_name, enum_name, type, fp) \ |
| 183 case MethodRecognizer::k##enum_name: \ | 180 case MethodRecognizer::k##enum_name: \ |
| 184 if (!Build_##enum_name(graph)) return false; \ | 181 if (!Build_##enum_name(graph)) return false; \ |
| 185 break; | 182 break; |
| 186 | 183 |
| 187 GRAPH_INTRINSICS_LIST(EMIT_CASE); | 184 GRAPH_INTRINSICS_LIST(EMIT_CASE); |
| 188 default: | 185 default: |
| 189 return false; | 186 return false; |
| 190 #undef EMIT_CASE | 187 #undef EMIT_CASE |
| 191 } | 188 } |
| 192 | 189 |
| 193 if (FLAG_support_il_printer && | 190 if (FLAG_support_il_printer && FLAG_print_flow_graph && |
| 194 FLAG_print_flow_graph && FlowGraphPrinter::ShouldPrint(function)) { | 191 FlowGraphPrinter::ShouldPrint(function)) { |
| 195 THR_Print("Intrinsic graph before\n"); | 192 THR_Print("Intrinsic graph before\n"); |
| 196 FlowGraphPrinter printer(*graph); | 193 FlowGraphPrinter printer(*graph); |
| 197 printer.PrintBlocks(); | 194 printer.PrintBlocks(); |
| 198 } | 195 } |
| 199 | 196 |
| 200 // Perform register allocation on the SSA graph. | 197 // Perform register allocation on the SSA graph. |
| 201 FlowGraphAllocator allocator(*graph, true); // Intrinsic mode. | 198 FlowGraphAllocator allocator(*graph, true); // Intrinsic mode. |
| 202 allocator.AllocateRegisters(); | 199 allocator.AllocateRegisters(); |
| 203 | 200 |
| 204 if (FLAG_support_il_printer && | 201 if (FLAG_support_il_printer && FLAG_print_flow_graph && |
| 205 FLAG_print_flow_graph && FlowGraphPrinter::ShouldPrint(function)) { | 202 FlowGraphPrinter::ShouldPrint(function)) { |
| 206 THR_Print("Intrinsic graph after\n"); | 203 THR_Print("Intrinsic graph after\n"); |
| 207 FlowGraphPrinter printer(*graph); | 204 FlowGraphPrinter printer(*graph); |
| 208 printer.PrintBlocks(); | 205 printer.PrintBlocks(); |
| 209 } | 206 } |
| 210 EmitCodeFor(compiler, graph); | 207 EmitCodeFor(compiler, graph); |
| 211 return true; | 208 return true; |
| 212 #else | 209 #else |
| 213 return false; | 210 return false; |
| 214 #endif // !defined(TARGET_ARCH_DBC) | 211 #endif // !defined(TARGET_ARCH_DBC) |
| 215 } | 212 } |
| 216 | 213 |
| 217 | 214 |
| 218 // Returns true if fall-through code can be omitted. | 215 // Returns true if fall-through code can be omitted. |
| 219 bool Intrinsifier::Intrinsify(const ParsedFunction& parsed_function, | 216 bool Intrinsifier::Intrinsify(const ParsedFunction& parsed_function, |
| 220 FlowGraphCompiler* compiler) { | 217 FlowGraphCompiler* compiler) { |
| 221 const Function& function = parsed_function.function(); | 218 const Function& function = parsed_function.function(); |
| 222 if (!CanIntrinsify(function)) { | 219 if (!CanIntrinsify(function)) { |
| 223 return false; | 220 return false; |
| 224 } | 221 } |
| 225 | 222 |
| 226 ASSERT(!compiler->flow_graph().IsCompiledForOsr()); | 223 ASSERT(!compiler->flow_graph().IsCompiledForOsr()); |
| 227 if (GraphIntrinsify(parsed_function, compiler)) { | 224 if (GraphIntrinsify(parsed_function, compiler)) { |
| 228 return compiler->intrinsic_slow_path_label()->IsUnused(); | 225 return compiler->intrinsic_slow_path_label()->IsUnused(); |
| 229 } | 226 } |
| 230 | 227 |
| 231 #define EMIT_CASE(class_name, function_name, enum_name, type, fp) \ | 228 #define EMIT_CASE(class_name, function_name, enum_name, type, fp) \ |
| 232 case MethodRecognizer::k##enum_name: \ | 229 case MethodRecognizer::k##enum_name: \ |
| 233 compiler->assembler()->Comment("Intrinsic"); \ | 230 compiler->assembler()->Comment("Intrinsic"); \ |
| 234 enum_name(compiler->assembler()); \ | 231 enum_name(compiler->assembler()); \ |
| 235 break; | 232 break; |
| 236 | 233 |
| 237 switch (function.recognized_kind()) { | 234 switch (function.recognized_kind()) { |
| 238 ALL_INTRINSICS_NO_INTEGER_LIB_LIST(EMIT_CASE); | 235 ALL_INTRINSICS_NO_INTEGER_LIB_LIST(EMIT_CASE); |
| 239 default: | 236 default: |
| 240 break; | 237 break; |
| 241 } | 238 } |
| 242 switch (function.recognized_kind()) { | 239 switch (function.recognized_kind()) { |
| 243 CORE_INTEGER_LIB_INTRINSIC_LIST(EMIT_CASE) | 240 CORE_INTEGER_LIB_INTRINSIC_LIST(EMIT_CASE) |
| 244 default: | 241 default: |
| 245 break; | 242 break; |
| 246 } | 243 } |
| 247 | 244 |
| 248 // On DBC all graph intrinsics are handled in the same way as non-graph | 245 // On DBC all graph intrinsics are handled in the same way as non-graph |
| 249 // intrinsics. | 246 // intrinsics. |
| 250 #if defined(TARGET_ARCH_DBC) | 247 #if defined(TARGET_ARCH_DBC) |
| 251 switch (function.recognized_kind()) { | 248 switch (function.recognized_kind()) { |
| 252 GRAPH_INTRINSICS_LIST(EMIT_CASE) | 249 GRAPH_INTRINSICS_LIST(EMIT_CASE) |
| 253 default: | 250 default: |
| 254 break; | 251 break; |
| 255 } | 252 } |
| 256 #endif | 253 #endif |
| 257 | 254 |
| 258 #undef EMIT_INTRINSIC | 255 #undef EMIT_INTRINSIC |
| 259 return false; | 256 return false; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 281 | 278 |
| 282 | 279 |
| 283 // Notes about the graph intrinsics: | 280 // Notes about the graph intrinsics: |
| 284 // | 281 // |
| 285 // IR instructions which would jump to a deoptimization sequence on failure | 282 // IR instructions which would jump to a deoptimization sequence on failure |
| 286 // instead branch to the intrinsic slow path. | 283 // instead branch to the intrinsic slow path. |
| 287 // | 284 // |
| 288 class BlockBuilder : public ValueObject { | 285 class BlockBuilder : public ValueObject { |
| 289 public: | 286 public: |
| 290 BlockBuilder(FlowGraph* flow_graph, TargetEntryInstr* entry) | 287 BlockBuilder(FlowGraph* flow_graph, TargetEntryInstr* entry) |
| 291 : flow_graph_(flow_graph), entry_(entry), current_(entry) { } | 288 : flow_graph_(flow_graph), entry_(entry), current_(entry) {} |
| 292 | 289 |
| 293 Definition* AddToInitialDefinitions(Definition* def) { | 290 Definition* AddToInitialDefinitions(Definition* def) { |
| 294 def->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); | 291 def->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); |
| 295 flow_graph_->AddToInitialDefinitions(def); | 292 flow_graph_->AddToInitialDefinitions(def); |
| 296 return def; | 293 return def; |
| 297 } | 294 } |
| 298 | 295 |
| 299 Definition* AddDefinition(Definition* def) { | 296 Definition* AddDefinition(Definition* def) { |
| 300 def->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); | 297 def->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); |
| 301 current_ = current_->AppendInstruction(def); | 298 current_ = current_->AppendInstruction(def); |
| 302 return def; | 299 return def; |
| 303 } | 300 } |
| 304 | 301 |
| 305 Instruction* AddInstruction(Instruction* instr) { | 302 Instruction* AddInstruction(Instruction* instr) { |
| 306 current_ = current_->AppendInstruction(instr); | 303 current_ = current_->AppendInstruction(instr); |
| 307 return instr; | 304 return instr; |
| 308 } | 305 } |
| 309 | 306 |
| 310 void AddIntrinsicReturn(Value* value) { | 307 void AddIntrinsicReturn(Value* value) { |
| 311 ReturnInstr* instr = new ReturnInstr(TokenPos(), value); | 308 ReturnInstr* instr = new ReturnInstr(TokenPos(), value); |
| 312 AddInstruction(instr); | 309 AddInstruction(instr); |
| 313 entry_->set_last_instruction(instr); | 310 entry_->set_last_instruction(instr); |
| 314 } | 311 } |
| 315 | 312 |
| 316 Definition* AddParameter(intptr_t index) { | 313 Definition* AddParameter(intptr_t index) { |
| 317 intptr_t adjustment = Intrinsifier::ParameterSlotFromSp(); | 314 intptr_t adjustment = Intrinsifier::ParameterSlotFromSp(); |
| 318 return AddToInitialDefinitions( | 315 return AddToInitialDefinitions(new ParameterInstr( |
| 319 new ParameterInstr(adjustment + index, | 316 adjustment + index, flow_graph_->graph_entry(), SPREG)); |
| 320 flow_graph_->graph_entry(), | |
| 321 SPREG)); | |
| 322 } | 317 } |
| 323 | 318 |
| 324 TokenPosition TokenPos() { | 319 TokenPosition TokenPos() { return flow_graph_->function().token_pos(); } |
| 325 return flow_graph_->function().token_pos(); | 320 |
| 321 Definition* AddNullDefinition() { |
| 322 return AddDefinition(new ConstantInstr(Object::ZoneHandle(Object::null()))); |
| 326 } | 323 } |
| 327 | 324 |
| 328 Definition* AddNullDefinition() { | 325 Definition* AddUnboxInstr(Representation rep, Value* value, bool is_checked) { |
| 329 return AddDefinition( | 326 Definition* unboxed_value = |
| 330 new ConstantInstr(Object::ZoneHandle(Object::null()))); | 327 AddDefinition(UnboxInstr::Create(rep, value, Thread::kNoDeoptId)); |
| 331 } | |
| 332 | |
| 333 Definition* AddUnboxInstr(Representation rep, | |
| 334 Value* value, | |
| 335 bool is_checked) { | |
| 336 Definition* unboxed_value = AddDefinition( | |
| 337 UnboxInstr::Create(rep, value, Thread::kNoDeoptId)); | |
| 338 if (is_checked) { | 328 if (is_checked) { |
| 339 // The type of |value| has already been checked and it is safe to | 329 // The type of |value| has already been checked and it is safe to |
| 340 // adjust reaching type. This is done manually because there is no type | 330 // adjust reaching type. This is done manually because there is no type |
| 341 // propagation when building intrinsics. | 331 // propagation when building intrinsics. |
| 342 unboxed_value->AsUnbox()->value()->SetReachingType(ZoneCompileType::Wrap( | 332 unboxed_value->AsUnbox()->value()->SetReachingType(ZoneCompileType::Wrap( |
| 343 CompileType::FromCid(CidForRepresentation(rep)))); | 333 CompileType::FromCid(CidForRepresentation(rep)))); |
| 344 } | 334 } |
| 345 return unboxed_value; | 335 return unboxed_value; |
| 346 } | 336 } |
| 347 | 337 |
| 348 Definition* AddUnboxInstr(Representation rep, | 338 Definition* AddUnboxInstr(Representation rep, |
| 349 Definition* boxed, | 339 Definition* boxed, |
| 350 bool is_checked) { | 340 bool is_checked) { |
| 351 return AddUnboxInstr(rep, new Value(boxed), is_checked); | 341 return AddUnboxInstr(rep, new Value(boxed), is_checked); |
| 352 } | 342 } |
| 353 | 343 |
| 354 Definition* InvokeMathCFunction(MethodRecognizer::Kind recognized_kind, | 344 Definition* InvokeMathCFunction(MethodRecognizer::Kind recognized_kind, |
| 355 ZoneGrowableArray<Value*>* args) { | 345 ZoneGrowableArray<Value*>* args) { |
| 356 return InvokeMathCFunctionHelper(recognized_kind, args); | 346 return InvokeMathCFunctionHelper(recognized_kind, args); |
| 357 } | 347 } |
| 358 | 348 |
| 359 private: | 349 private: |
| 360 Definition* InvokeMathCFunctionHelper(MethodRecognizer::Kind recognized_kind, | 350 Definition* InvokeMathCFunctionHelper(MethodRecognizer::Kind recognized_kind, |
| 361 ZoneGrowableArray<Value*>* args) { | 351 ZoneGrowableArray<Value*>* args) { |
| 362 InvokeMathCFunctionInstr* invoke_math_c_function = | 352 InvokeMathCFunctionInstr* invoke_math_c_function = |
| 363 new InvokeMathCFunctionInstr(args, | 353 new InvokeMathCFunctionInstr(args, Thread::kNoDeoptId, recognized_kind, |
| 364 Thread::kNoDeoptId, | |
| 365 recognized_kind, | |
| 366 TokenPos()); | 354 TokenPos()); |
| 367 AddDefinition(invoke_math_c_function); | 355 AddDefinition(invoke_math_c_function); |
| 368 return invoke_math_c_function; | 356 return invoke_math_c_function; |
| 369 } | 357 } |
| 370 | 358 |
| 371 | 359 |
| 372 FlowGraph* flow_graph_; | 360 FlowGraph* flow_graph_; |
| 373 BlockEntryInstr* entry_; | 361 BlockEntryInstr* entry_; |
| 374 Instruction* current_; | 362 Instruction* current_; |
| 375 }; | 363 }; |
| 376 | 364 |
| 377 | 365 |
| 378 static void PrepareIndexedOp(BlockBuilder* builder, | 366 static void PrepareIndexedOp(BlockBuilder* builder, |
| 379 Definition* array, | 367 Definition* array, |
| 380 Definition* index, | 368 Definition* index, |
| 381 intptr_t length_offset) { | 369 intptr_t length_offset) { |
| 382 Definition* length = builder->AddDefinition( | 370 Definition* length = builder->AddDefinition(new LoadFieldInstr( |
| 383 new LoadFieldInstr(new Value(array), | 371 new Value(array), length_offset, Type::ZoneHandle(Type::SmiType()), |
| 384 length_offset, | 372 TokenPosition::kNoSource)); |
| 385 Type::ZoneHandle(Type::SmiType()), | 373 builder->AddInstruction(new CheckArrayBoundInstr( |
| 386 TokenPosition::kNoSource)); | 374 new Value(length), new Value(index), Thread::kNoDeoptId)); |
| 387 builder->AddInstruction( | |
| 388 new CheckArrayBoundInstr(new Value(length), | |
| 389 new Value(index), | |
| 390 Thread::kNoDeoptId)); | |
| 391 } | 375 } |
| 392 | 376 |
| 393 static bool IntrinsifyArrayGetIndexed(FlowGraph* flow_graph, | 377 static bool IntrinsifyArrayGetIndexed(FlowGraph* flow_graph, |
| 394 intptr_t array_cid) { | 378 intptr_t array_cid) { |
| 395 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); | 379 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| 396 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); | 380 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| 397 BlockBuilder builder(flow_graph, normal_entry); | 381 BlockBuilder builder(flow_graph, normal_entry); |
| 398 | 382 |
| 399 Definition* index = builder.AddParameter(1); | 383 Definition* index = builder.AddParameter(1); |
| 400 Definition* array = builder.AddParameter(2); | 384 Definition* array = builder.AddParameter(2); |
| 401 | 385 |
| 402 intptr_t length_offset = Array::length_offset(); | 386 intptr_t length_offset = Array::length_offset(); |
| 403 if (RawObject::IsTypedDataClassId(array_cid)) { | 387 if (RawObject::IsTypedDataClassId(array_cid)) { |
| 404 length_offset = TypedData::length_offset(); | 388 length_offset = TypedData::length_offset(); |
| 405 } else if (RawObject::IsExternalTypedDataClassId(array_cid)) { | 389 } else if (RawObject::IsExternalTypedDataClassId(array_cid)) { |
| 406 length_offset = ExternalTypedData::length_offset(); | 390 length_offset = ExternalTypedData::length_offset(); |
| 407 } | 391 } |
| 408 | 392 |
| 409 PrepareIndexedOp(&builder, array, index, length_offset); | 393 PrepareIndexedOp(&builder, array, index, length_offset); |
| 410 | 394 |
| 411 if (RawObject::IsExternalTypedDataClassId(array_cid)) { | 395 if (RawObject::IsExternalTypedDataClassId(array_cid)) { |
| 412 array = builder.AddDefinition( | 396 array = builder.AddDefinition(new LoadUntaggedInstr( |
| 413 new LoadUntaggedInstr(new Value(array), | 397 new Value(array), ExternalTypedData::data_offset())); |
| 414 ExternalTypedData::data_offset())); | |
| 415 } | 398 } |
| 416 | 399 |
| 417 Definition* result = builder.AddDefinition( | 400 Definition* result = builder.AddDefinition(new LoadIndexedInstr( |
| 418 new LoadIndexedInstr(new Value(array), | 401 new Value(array), new Value(index), |
| 419 new Value(index), | 402 Instance::ElementSizeFor(array_cid), // index scale |
| 420 Instance::ElementSizeFor(array_cid), // index scale | 403 array_cid, kAlignedAccess, Thread::kNoDeoptId, builder.TokenPos())); |
| 421 array_cid, | |
| 422 kAlignedAccess, | |
| 423 Thread::kNoDeoptId, | |
| 424 builder.TokenPos())); | |
| 425 // Box and/or convert result if necessary. | 404 // Box and/or convert result if necessary. |
| 426 switch (array_cid) { | 405 switch (array_cid) { |
| 427 case kTypedDataInt32ArrayCid: | 406 case kTypedDataInt32ArrayCid: |
| 428 case kExternalTypedDataInt32ArrayCid: | 407 case kExternalTypedDataInt32ArrayCid: |
| 429 result = builder.AddDefinition( | 408 result = builder.AddDefinition( |
| 430 BoxInstr::Create(kUnboxedInt32, new Value(result))); | 409 BoxInstr::Create(kUnboxedInt32, new Value(result))); |
| 431 break; | 410 break; |
| 432 case kTypedDataUint32ArrayCid: | 411 case kTypedDataUint32ArrayCid: |
| 433 case kExternalTypedDataUint32ArrayCid: | 412 case kExternalTypedDataUint32ArrayCid: |
| 434 result = builder.AddDefinition( | 413 result = builder.AddDefinition( |
| 435 BoxInstr::Create(kUnboxedUint32, new Value(result))); | 414 BoxInstr::Create(kUnboxedUint32, new Value(result))); |
| 436 break; | 415 break; |
| 437 case kTypedDataFloat32ArrayCid: | 416 case kTypedDataFloat32ArrayCid: |
| 438 result = builder.AddDefinition( | 417 result = builder.AddDefinition( |
| 439 new FloatToDoubleInstr(new Value(result), Thread::kNoDeoptId)); | 418 new FloatToDoubleInstr(new Value(result), Thread::kNoDeoptId)); |
| 440 // Fall through. | 419 // Fall through. |
| 441 case kTypedDataFloat64ArrayCid: | 420 case kTypedDataFloat64ArrayCid: |
| 442 result = builder.AddDefinition( | 421 result = builder.AddDefinition( |
| 443 BoxInstr::Create(kUnboxedDouble, new Value(result))); | 422 BoxInstr::Create(kUnboxedDouble, new Value(result))); |
| 444 break; | 423 break; |
| 445 case kTypedDataFloat32x4ArrayCid: | 424 case kTypedDataFloat32x4ArrayCid: |
| 446 result = builder.AddDefinition( | 425 result = builder.AddDefinition( |
| 447 BoxInstr::Create(kUnboxedFloat32x4, new Value(result))); | 426 BoxInstr::Create(kUnboxedFloat32x4, new Value(result))); |
| 448 break; | 427 break; |
| 449 case kTypedDataInt32x4ArrayCid: | 428 case kTypedDataInt32x4ArrayCid: |
| 450 result = builder.AddDefinition( | 429 result = builder.AddDefinition( |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 495 | 474 |
| 496 // Value check/conversion. | 475 // Value check/conversion. |
| 497 switch (array_cid) { | 476 switch (array_cid) { |
| 498 case kTypedDataInt8ArrayCid: | 477 case kTypedDataInt8ArrayCid: |
| 499 case kTypedDataUint8ArrayCid: | 478 case kTypedDataUint8ArrayCid: |
| 500 case kExternalTypedDataUint8ArrayCid: | 479 case kExternalTypedDataUint8ArrayCid: |
| 501 case kTypedDataUint8ClampedArrayCid: | 480 case kTypedDataUint8ClampedArrayCid: |
| 502 case kExternalTypedDataUint8ClampedArrayCid: | 481 case kExternalTypedDataUint8ClampedArrayCid: |
| 503 case kTypedDataInt16ArrayCid: | 482 case kTypedDataInt16ArrayCid: |
| 504 case kTypedDataUint16ArrayCid: | 483 case kTypedDataUint16ArrayCid: |
| 505 builder.AddInstruction(new CheckSmiInstr(new Value(value), | 484 builder.AddInstruction(new CheckSmiInstr( |
| 506 Thread::kNoDeoptId, | 485 new Value(value), Thread::kNoDeoptId, builder.TokenPos())); |
| 507 builder.TokenPos())); | |
| 508 break; | 486 break; |
| 509 case kTypedDataInt32ArrayCid: | 487 case kTypedDataInt32ArrayCid: |
| 510 case kExternalTypedDataInt32ArrayCid: | 488 case kExternalTypedDataInt32ArrayCid: |
| 511 // Use same truncating unbox-instruction for int32 and uint32. | 489 // Use same truncating unbox-instruction for int32 and uint32. |
| 512 // Fall-through. | 490 // Fall-through. |
| 513 case kTypedDataUint32ArrayCid: | 491 case kTypedDataUint32ArrayCid: |
| 514 case kExternalTypedDataUint32ArrayCid: | 492 case kExternalTypedDataUint32ArrayCid: |
| 515 // Supports smi and mint, slow-case for bigints. | 493 // Supports smi and mint, slow-case for bigints. |
| 516 value = builder.AddUnboxInstr(kUnboxedUint32, | 494 value = builder.AddUnboxInstr(kUnboxedUint32, new Value(value), |
| 517 new Value(value), | |
| 518 /* is_checked = */ false); | 495 /* is_checked = */ false); |
| 519 break; | 496 break; |
| 520 case kTypedDataFloat32ArrayCid: | 497 case kTypedDataFloat32ArrayCid: |
| 521 case kTypedDataFloat64ArrayCid: | 498 case kTypedDataFloat64ArrayCid: |
| 522 case kTypedDataFloat32x4ArrayCid: | 499 case kTypedDataFloat32x4ArrayCid: |
| 523 case kTypedDataInt32x4ArrayCid: | 500 case kTypedDataInt32x4ArrayCid: |
| 524 case kTypedDataFloat64x2ArrayCid: { | 501 case kTypedDataFloat64x2ArrayCid: { |
| 525 intptr_t value_check_cid = kDoubleCid; | 502 intptr_t value_check_cid = kDoubleCid; |
| 526 Representation rep = kUnboxedDouble; | 503 Representation rep = kUnboxedDouble; |
| 527 switch (array_cid) { | 504 switch (array_cid) { |
| 528 case kTypedDataFloat32x4ArrayCid: | 505 case kTypedDataFloat32x4ArrayCid: |
| 529 value_check_cid = kFloat32x4Cid; | 506 value_check_cid = kFloat32x4Cid; |
| 530 rep = kUnboxedFloat32x4; | 507 rep = kUnboxedFloat32x4; |
| 531 break; | 508 break; |
| 532 case kTypedDataInt32x4ArrayCid: | 509 case kTypedDataInt32x4ArrayCid: |
| 533 value_check_cid = kInt32x4Cid; | 510 value_check_cid = kInt32x4Cid; |
| 534 rep = kUnboxedInt32x4; | 511 rep = kUnboxedInt32x4; |
| 535 break; | 512 break; |
| 536 case kTypedDataFloat64x2ArrayCid: | 513 case kTypedDataFloat64x2ArrayCid: |
| 537 value_check_cid = kFloat64x2Cid; | 514 value_check_cid = kFloat64x2Cid; |
| 538 rep = kUnboxedFloat64x2; | 515 rep = kUnboxedFloat64x2; |
| 539 break; | 516 break; |
| 540 default: | 517 default: |
| 541 // Float32/Float64 case already handled. | 518 // Float32/Float64 case already handled. |
| 542 break; | 519 break; |
| 543 } | 520 } |
| 544 const ICData& value_check = ICData::ZoneHandle(ICData::New( | 521 const ICData& value_check = ICData::ZoneHandle( |
| 545 flow_graph->function(), | 522 ICData::New(flow_graph->function(), |
| 546 Symbols::Empty(), // Dummy function name. | 523 Symbols::Empty(), // Dummy function name. |
| 547 Object::empty_array(), // Dummy args. descr. | 524 Object::empty_array(), // Dummy args. descr. |
| 548 Thread::kNoDeoptId, | 525 Thread::kNoDeoptId, 1, false)); |
| 549 1, | |
| 550 false)); | |
| 551 value_check.AddReceiverCheck(value_check_cid, flow_graph->function()); | 526 value_check.AddReceiverCheck(value_check_cid, flow_graph->function()); |
| 552 builder.AddInstruction( | 527 builder.AddInstruction( |
| 553 new CheckClassInstr(new Value(value), | 528 new CheckClassInstr(new Value(value), Thread::kNoDeoptId, value_check, |
| 554 Thread::kNoDeoptId, | |
| 555 value_check, | |
| 556 builder.TokenPos())); | 529 builder.TokenPos())); |
| 557 value = builder.AddUnboxInstr(rep, | 530 value = builder.AddUnboxInstr(rep, new Value(value), |
| 558 new Value(value), | |
| 559 /* is_checked = */ true); | 531 /* is_checked = */ true); |
| 560 if (array_cid == kTypedDataFloat32ArrayCid) { | 532 if (array_cid == kTypedDataFloat32ArrayCid) { |
| 561 value = builder.AddDefinition( | 533 value = builder.AddDefinition( |
| 562 new DoubleToFloatInstr(new Value(value), Thread::kNoDeoptId)); | 534 new DoubleToFloatInstr(new Value(value), Thread::kNoDeoptId)); |
| 563 } | 535 } |
| 564 break; | 536 break; |
| 565 } | 537 } |
| 566 default: | 538 default: |
| 567 UNREACHABLE(); | 539 UNREACHABLE(); |
| 568 } | 540 } |
| 569 | 541 |
| 570 if (RawObject::IsExternalTypedDataClassId(array_cid)) { | 542 if (RawObject::IsExternalTypedDataClassId(array_cid)) { |
| 571 array = builder.AddDefinition( | 543 array = builder.AddDefinition(new LoadUntaggedInstr( |
| 572 new LoadUntaggedInstr(new Value(array), | 544 new Value(array), ExternalTypedData::data_offset())); |
| 573 ExternalTypedData::data_offset())); | |
| 574 } | 545 } |
| 575 // No store barrier. | 546 // No store barrier. |
| 576 ASSERT(RawObject::IsExternalTypedDataClassId(array_cid) || | 547 ASSERT(RawObject::IsExternalTypedDataClassId(array_cid) || |
| 577 RawObject::IsTypedDataClassId(array_cid)); | 548 RawObject::IsTypedDataClassId(array_cid)); |
| 578 builder.AddInstruction( | 549 builder.AddInstruction(new StoreIndexedInstr( |
| 579 new StoreIndexedInstr(new Value(array), | 550 new Value(array), new Value(index), new Value(value), kNoStoreBarrier, |
| 580 new Value(index), | 551 Instance::ElementSizeFor(array_cid), // index scale |
| 581 new Value(value), | 552 array_cid, kAlignedAccess, Thread::kNoDeoptId, builder.TokenPos())); |
| 582 kNoStoreBarrier, | |
| 583 Instance::ElementSizeFor(array_cid), // index scale | |
| 584 array_cid, | |
| 585 kAlignedAccess, | |
| 586 Thread::kNoDeoptId, | |
| 587 builder.TokenPos())); | |
| 588 // Return null. | 553 // Return null. |
| 589 Definition* null_def = builder.AddNullDefinition(); | 554 Definition* null_def = builder.AddNullDefinition(); |
| 590 builder.AddIntrinsicReturn(new Value(null_def)); | 555 builder.AddIntrinsicReturn(new Value(null_def)); |
| 591 return true; | 556 return true; |
| 592 } | 557 } |
| 593 | 558 |
| 594 | 559 |
| 595 #define DEFINE_ARRAY_GETTER_INTRINSIC(enum_name) \ | 560 #define DEFINE_ARRAY_GETTER_INTRINSIC(enum_name) \ |
| 596 bool Intrinsifier::Build_##enum_name##GetIndexed(FlowGraph* flow_graph) { \ | 561 bool Intrinsifier::Build_##enum_name##GetIndexed(FlowGraph* flow_graph) { \ |
| 597 return IntrinsifyArrayGetIndexed( \ | 562 return IntrinsifyArrayGetIndexed( \ |
| 598 flow_graph, \ | 563 flow_graph, MethodRecognizer::MethodKindToReceiverCid( \ |
| 599 MethodRecognizer::MethodKindToReceiverCid( \ | 564 MethodRecognizer::k##enum_name##GetIndexed)); \ |
| 600 MethodRecognizer::k##enum_name##GetIndexed)); \ | 565 } |
| 601 } | |
| 602 | 566 |
| 603 | 567 |
| 604 #define DEFINE_ARRAY_SETTER_INTRINSIC(enum_name) \ | 568 #define DEFINE_ARRAY_SETTER_INTRINSIC(enum_name) \ |
| 605 bool Intrinsifier::Build_##enum_name##SetIndexed(FlowGraph* flow_graph) { \ | 569 bool Intrinsifier::Build_##enum_name##SetIndexed(FlowGraph* flow_graph) { \ |
| 606 return IntrinsifyArraySetIndexed( \ | 570 return IntrinsifyArraySetIndexed( \ |
| 607 flow_graph, \ | 571 flow_graph, MethodRecognizer::MethodKindToReceiverCid( \ |
| 608 MethodRecognizer::MethodKindToReceiverCid( \ | 572 MethodRecognizer::k##enum_name##SetIndexed)); \ |
| 609 MethodRecognizer::k##enum_name##SetIndexed)); \ | 573 } |
| 610 } | |
| 611 | 574 |
| 612 DEFINE_ARRAY_GETTER_INTRINSIC(ObjectArray) // Setter in intrinsifier_<arch>.cc. | 575 DEFINE_ARRAY_GETTER_INTRINSIC(ObjectArray) // Setter in intrinsifier_<arch>.cc. |
| 613 DEFINE_ARRAY_GETTER_INTRINSIC(ImmutableArray) | 576 DEFINE_ARRAY_GETTER_INTRINSIC(ImmutableArray) |
| 614 | 577 |
| 615 #define DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(enum_name) \ | 578 #define DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(enum_name) \ |
| 616 DEFINE_ARRAY_GETTER_INTRINSIC(enum_name) \ | 579 DEFINE_ARRAY_GETTER_INTRINSIC(enum_name) \ |
| 617 DEFINE_ARRAY_SETTER_INTRINSIC(enum_name) | 580 DEFINE_ARRAY_SETTER_INTRINSIC(enum_name) |
| 618 | 581 |
| 619 DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Int8Array) | 582 DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Int8Array) |
| 620 DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Uint8Array) | 583 DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Uint8Array) |
| 621 DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(ExternalUint8Array) | 584 DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(ExternalUint8Array) |
| 622 DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Uint8ClampedArray) | 585 DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Uint8ClampedArray) |
| 623 DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(ExternalUint8ClampedArray) | 586 DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(ExternalUint8ClampedArray) |
| 624 DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Int16Array) | 587 DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Int16Array) |
| 625 DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Uint16Array) | 588 DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Uint16Array) |
| 626 DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Int32Array) | 589 DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Int32Array) |
| 627 DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Uint32Array) | 590 DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Uint32Array) |
| 628 | 591 |
| 629 #undef DEFINE_ARRAY_GETTER_SETTER_INTRINSICS | 592 #undef DEFINE_ARRAY_GETTER_SETTER_INTRINSICS |
| 630 #undef DEFINE_ARRAY_GETTER_INTRINSIC | 593 #undef DEFINE_ARRAY_GETTER_INTRINSIC |
| 631 #undef DEFINE_ARRAY_SETTER_INTRINSIC | 594 #undef DEFINE_ARRAY_SETTER_INTRINSIC |
| 632 | 595 |
| 633 | 596 |
| 634 #define DEFINE_FLOAT_ARRAY_GETTER_INTRINSIC(enum_name) \ | 597 #define DEFINE_FLOAT_ARRAY_GETTER_INTRINSIC(enum_name) \ |
| 635 bool Intrinsifier::Build_##enum_name##GetIndexed(FlowGraph* flow_graph) { \ | 598 bool Intrinsifier::Build_##enum_name##GetIndexed(FlowGraph* flow_graph) { \ |
| 636 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) { \ | 599 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) { \ |
| 637 return false; \ | 600 return false; \ |
| 638 } \ | 601 } \ |
| 639 return IntrinsifyArrayGetIndexed( \ | 602 return IntrinsifyArrayGetIndexed( \ |
| 640 flow_graph, \ | 603 flow_graph, MethodRecognizer::MethodKindToReceiverCid( \ |
| 641 MethodRecognizer::MethodKindToReceiverCid( \ | 604 MethodRecognizer::k##enum_name##GetIndexed)); \ |
| 642 MethodRecognizer::k##enum_name##GetIndexed)); \ | 605 } |
| 643 } | |
| 644 | 606 |
| 645 | 607 |
| 646 #define DEFINE_FLOAT_ARRAY_SETTER_INTRINSIC(enum_name) \ | 608 #define DEFINE_FLOAT_ARRAY_SETTER_INTRINSIC(enum_name) \ |
| 647 bool Intrinsifier::Build_##enum_name##SetIndexed(FlowGraph* flow_graph) { \ | 609 bool Intrinsifier::Build_##enum_name##SetIndexed(FlowGraph* flow_graph) { \ |
| 648 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) { \ | 610 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) { \ |
| 649 return false; \ | 611 return false; \ |
| 650 } \ | 612 } \ |
| 651 return IntrinsifyArraySetIndexed( \ | 613 return IntrinsifyArraySetIndexed( \ |
| 652 flow_graph, \ | 614 flow_graph, MethodRecognizer::MethodKindToReceiverCid( \ |
| 653 MethodRecognizer::MethodKindToReceiverCid( \ | 615 MethodRecognizer::k##enum_name##SetIndexed)); \ |
| 654 MethodRecognizer::k##enum_name##SetIndexed)); \ | 616 } |
| 655 } | |
| 656 | 617 |
| 657 #define DEFINE_FLOAT_ARRAY_GETTER_SETTER_INTRINSICS(enum_name) \ | 618 #define DEFINE_FLOAT_ARRAY_GETTER_SETTER_INTRINSICS(enum_name) \ |
| 658 DEFINE_FLOAT_ARRAY_GETTER_INTRINSIC(enum_name) \ | 619 DEFINE_FLOAT_ARRAY_GETTER_INTRINSIC(enum_name) \ |
| 659 DEFINE_FLOAT_ARRAY_SETTER_INTRINSIC(enum_name) | 620 DEFINE_FLOAT_ARRAY_SETTER_INTRINSIC(enum_name) |
| 660 | 621 |
| 661 DEFINE_FLOAT_ARRAY_GETTER_SETTER_INTRINSICS(Float64Array) | 622 DEFINE_FLOAT_ARRAY_GETTER_SETTER_INTRINSICS(Float64Array) |
| 662 DEFINE_FLOAT_ARRAY_GETTER_SETTER_INTRINSICS(Float32Array) | 623 DEFINE_FLOAT_ARRAY_GETTER_SETTER_INTRINSICS(Float32Array) |
| 663 | 624 |
| 664 #undef DEFINE_FLOAT_ARRAY_GETTER_SETTER_INTRINSICS | 625 #undef DEFINE_FLOAT_ARRAY_GETTER_SETTER_INTRINSICS |
| 665 #undef DEFINE_FLOAT_ARRAY_GETTER_INTRINSIC | 626 #undef DEFINE_FLOAT_ARRAY_GETTER_INTRINSIC |
| 666 #undef DEFINE_FLOAT_ARRAY_SETTER_INTRINSIC | 627 #undef DEFINE_FLOAT_ARRAY_SETTER_INTRINSIC |
| 667 | 628 |
| 668 | 629 |
| 669 #define DEFINE_SIMD_ARRAY_GETTER_INTRINSIC(enum_name) \ | 630 #define DEFINE_SIMD_ARRAY_GETTER_INTRINSIC(enum_name) \ |
| 670 bool Intrinsifier::Build_##enum_name##GetIndexed(FlowGraph* flow_graph) { \ | 631 bool Intrinsifier::Build_##enum_name##GetIndexed(FlowGraph* flow_graph) { \ |
| 671 if (!FlowGraphCompiler::SupportsUnboxedSimd128()) { \ | 632 if (!FlowGraphCompiler::SupportsUnboxedSimd128()) { \ |
| 672 return false; \ | 633 return false; \ |
| 673 } \ | 634 } \ |
| 674 return IntrinsifyArrayGetIndexed( \ | 635 return IntrinsifyArrayGetIndexed( \ |
| 675 flow_graph, \ | 636 flow_graph, MethodRecognizer::MethodKindToReceiverCid( \ |
| 676 MethodRecognizer::MethodKindToReceiverCid( \ | 637 MethodRecognizer::k##enum_name##GetIndexed)); \ |
| 677 MethodRecognizer::k##enum_name##GetIndexed)); \ | 638 } |
| 678 } | |
| 679 | 639 |
| 680 | 640 |
| 681 #define DEFINE_SIMD_ARRAY_SETTER_INTRINSIC(enum_name) \ | 641 #define DEFINE_SIMD_ARRAY_SETTER_INTRINSIC(enum_name) \ |
| 682 bool Intrinsifier::Build_##enum_name##SetIndexed(FlowGraph* flow_graph) { \ | 642 bool Intrinsifier::Build_##enum_name##SetIndexed(FlowGraph* flow_graph) { \ |
| 683 if (!FlowGraphCompiler::SupportsUnboxedSimd128()) { \ | 643 if (!FlowGraphCompiler::SupportsUnboxedSimd128()) { \ |
| 684 return false; \ | 644 return false; \ |
| 685 } \ | 645 } \ |
| 686 return IntrinsifyArraySetIndexed( \ | 646 return IntrinsifyArraySetIndexed( \ |
| 687 flow_graph, \ | 647 flow_graph, MethodRecognizer::MethodKindToReceiverCid( \ |
| 688 MethodRecognizer::MethodKindToReceiverCid( \ | 648 MethodRecognizer::k##enum_name##SetIndexed)); \ |
| 689 MethodRecognizer::k##enum_name##SetIndexed)); \ | 649 } |
| 690 } | |
| 691 | 650 |
| 692 #define DEFINE_SIMD_ARRAY_GETTER_SETTER_INTRINSICS(enum_name) \ | 651 #define DEFINE_SIMD_ARRAY_GETTER_SETTER_INTRINSICS(enum_name) \ |
| 693 DEFINE_SIMD_ARRAY_GETTER_INTRINSIC(enum_name) \ | 652 DEFINE_SIMD_ARRAY_GETTER_INTRINSIC(enum_name) \ |
| 694 DEFINE_SIMD_ARRAY_SETTER_INTRINSIC(enum_name) | 653 DEFINE_SIMD_ARRAY_SETTER_INTRINSIC(enum_name) |
| 695 | 654 |
| 696 DEFINE_SIMD_ARRAY_GETTER_SETTER_INTRINSICS(Float32x4Array) | 655 DEFINE_SIMD_ARRAY_GETTER_SETTER_INTRINSICS(Float32x4Array) |
| 697 DEFINE_SIMD_ARRAY_GETTER_SETTER_INTRINSICS(Int32x4Array) | 656 DEFINE_SIMD_ARRAY_GETTER_SETTER_INTRINSICS(Int32x4Array) |
| 698 DEFINE_SIMD_ARRAY_GETTER_SETTER_INTRINSICS(Float64x2Array) | 657 DEFINE_SIMD_ARRAY_GETTER_SETTER_INTRINSICS(Float64x2Array) |
| 699 | 658 |
| 700 #undef DEFINE_SIMD_ARRAY_GETTER_SETTER_INTRINSICS | 659 #undef DEFINE_SIMD_ARRAY_GETTER_SETTER_INTRINSICS |
| 701 #undef DEFINE_SIMD_ARRAY_GETTER_INTRINSIC | 660 #undef DEFINE_SIMD_ARRAY_GETTER_INTRINSIC |
| 702 #undef DEFINE_SIMD_ARRAY_SETTER_INTRINSIC | 661 #undef DEFINE_SIMD_ARRAY_SETTER_INTRINSIC |
| 703 | 662 |
| 704 | 663 |
| 705 static bool BuildCodeUnitAt(FlowGraph* flow_graph, intptr_t cid) { | 664 static bool BuildCodeUnitAt(FlowGraph* flow_graph, intptr_t cid) { |
| 706 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); | 665 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| 707 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); | 666 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| 708 BlockBuilder builder(flow_graph, normal_entry); | 667 BlockBuilder builder(flow_graph, normal_entry); |
| 709 | 668 |
| 710 Definition* index = builder.AddParameter(1); | 669 Definition* index = builder.AddParameter(1); |
| 711 Definition* str = builder.AddParameter(2); | 670 Definition* str = builder.AddParameter(2); |
| 712 PrepareIndexedOp(&builder, str, index, String::length_offset()); | 671 PrepareIndexedOp(&builder, str, index, String::length_offset()); |
| 713 | 672 |
| 714 // For external strings: Load external data. | 673 // For external strings: Load external data. |
| 715 if (cid == kExternalOneByteStringCid) { | 674 if (cid == kExternalOneByteStringCid) { |
| 716 str = builder.AddDefinition( | 675 str = builder.AddDefinition(new LoadUntaggedInstr( |
| 717 new LoadUntaggedInstr(new Value(str), | 676 new Value(str), ExternalOneByteString::external_data_offset())); |
| 718 ExternalOneByteString::external_data_offset())); | 677 str = builder.AddDefinition(new LoadUntaggedInstr( |
| 719 str = builder.AddDefinition( | 678 new Value(str), RawExternalOneByteString::ExternalData::data_offset())); |
| 720 new LoadUntaggedInstr( | |
| 721 new Value(str), | |
| 722 RawExternalOneByteString::ExternalData::data_offset())); | |
| 723 } else if (cid == kExternalTwoByteStringCid) { | 679 } else if (cid == kExternalTwoByteStringCid) { |
| 724 str = builder.AddDefinition( | 680 str = builder.AddDefinition(new LoadUntaggedInstr( |
| 725 new LoadUntaggedInstr(new Value(str), | 681 new Value(str), ExternalTwoByteString::external_data_offset())); |
| 726 ExternalTwoByteString::external_data_offset())); | 682 str = builder.AddDefinition(new LoadUntaggedInstr( |
| 727 str = builder.AddDefinition( | 683 new Value(str), RawExternalTwoByteString::ExternalData::data_offset())); |
| 728 new LoadUntaggedInstr( | |
| 729 new Value(str), | |
| 730 RawExternalTwoByteString::ExternalData::data_offset())); | |
| 731 } | 684 } |
| 732 | 685 |
| 733 Definition* result = builder.AddDefinition( | 686 Definition* result = builder.AddDefinition(new LoadIndexedInstr( |
| 734 new LoadIndexedInstr(new Value(str), | 687 new Value(str), new Value(index), Instance::ElementSizeFor(cid), cid, |
| 735 new Value(index), | 688 kAlignedAccess, Thread::kNoDeoptId, builder.TokenPos())); |
| 736 Instance::ElementSizeFor(cid), | |
| 737 cid, | |
| 738 kAlignedAccess, | |
| 739 Thread::kNoDeoptId, | |
| 740 builder.TokenPos())); | |
| 741 builder.AddIntrinsicReturn(new Value(result)); | 689 builder.AddIntrinsicReturn(new Value(result)); |
| 742 return true; | 690 return true; |
| 743 } | 691 } |
| 744 | 692 |
| 745 | 693 |
| 746 bool Intrinsifier::Build_OneByteStringCodeUnitAt(FlowGraph* flow_graph) { | 694 bool Intrinsifier::Build_OneByteStringCodeUnitAt(FlowGraph* flow_graph) { |
| 747 return BuildCodeUnitAt(flow_graph, kOneByteStringCid); | 695 return BuildCodeUnitAt(flow_graph, kOneByteStringCid); |
| 748 } | 696 } |
| 749 | 697 |
| 750 | 698 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 769 if (!FlowGraphCompiler::SupportsUnboxedSimd128()) return false; | 717 if (!FlowGraphCompiler::SupportsUnboxedSimd128()) return false; |
| 770 | 718 |
| 771 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); | 719 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| 772 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); | 720 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| 773 BlockBuilder builder(flow_graph, normal_entry); | 721 BlockBuilder builder(flow_graph, normal_entry); |
| 774 | 722 |
| 775 Definition* right = builder.AddParameter(1); | 723 Definition* right = builder.AddParameter(1); |
| 776 Definition* left = builder.AddParameter(2); | 724 Definition* left = builder.AddParameter(2); |
| 777 | 725 |
| 778 const ICData& value_check = ICData::ZoneHandle(ICData::New( | 726 const ICData& value_check = ICData::ZoneHandle(ICData::New( |
| 779 flow_graph->function(), | 727 flow_graph->function(), String::Handle(flow_graph->function().name()), |
| 780 String::Handle(flow_graph->function().name()), | |
| 781 Object::empty_array(), // Dummy args. descr. | 728 Object::empty_array(), // Dummy args. descr. |
| 782 Thread::kNoDeoptId, | 729 Thread::kNoDeoptId, 1, false)); |
| 783 1, | |
| 784 false)); | |
| 785 value_check.AddReceiverCheck(kFloat32x4Cid, flow_graph->function()); | 730 value_check.AddReceiverCheck(kFloat32x4Cid, flow_graph->function()); |
| 786 // Check argument. Receiver (left) is known to be a Float32x4. | 731 // Check argument. Receiver (left) is known to be a Float32x4. |
| 787 builder.AddInstruction( | 732 builder.AddInstruction(new CheckClassInstr( |
| 788 new CheckClassInstr(new Value(right), | 733 new Value(right), Thread::kNoDeoptId, value_check, builder.TokenPos())); |
| 789 Thread::kNoDeoptId, | |
| 790 value_check, | |
| 791 builder.TokenPos())); | |
| 792 Definition* left_simd = | 734 Definition* left_simd = |
| 793 builder.AddUnboxInstr(kUnboxedFloat32x4, | 735 builder.AddUnboxInstr(kUnboxedFloat32x4, new Value(left), |
| 794 new Value(left), | |
| 795 /* is_checked = */ true); | 736 /* is_checked = */ true); |
| 796 | 737 |
| 797 Definition* right_simd = | 738 Definition* right_simd = |
| 798 builder.AddUnboxInstr(kUnboxedFloat32x4, | 739 builder.AddUnboxInstr(kUnboxedFloat32x4, new Value(right), |
| 799 new Value(right), | |
| 800 /* is_checked = */ true); | 740 /* is_checked = */ true); |
| 801 | 741 |
| 802 Definition* unboxed_result = builder.AddDefinition( | 742 Definition* unboxed_result = builder.AddDefinition(new BinaryFloat32x4OpInstr( |
| 803 new BinaryFloat32x4OpInstr(kind, | 743 kind, new Value(left_simd), new Value(right_simd), Thread::kNoDeoptId)); |
| 804 new Value(left_simd), | |
| 805 new Value(right_simd), | |
| 806 Thread::kNoDeoptId)); | |
| 807 Definition* result = builder.AddDefinition( | 744 Definition* result = builder.AddDefinition( |
| 808 BoxInstr::Create(kUnboxedFloat32x4, new Value(unboxed_result))); | 745 BoxInstr::Create(kUnboxedFloat32x4, new Value(unboxed_result))); |
| 809 builder.AddIntrinsicReturn(new Value(result)); | 746 builder.AddIntrinsicReturn(new Value(result)); |
| 810 return true; | 747 return true; |
| 811 } | 748 } |
| 812 | 749 |
| 813 | 750 |
| 814 bool Intrinsifier::Build_Float32x4Mul(FlowGraph* flow_graph) { | 751 bool Intrinsifier::Build_Float32x4Mul(FlowGraph* flow_graph) { |
| 815 return BuildBinaryFloat32x4Op(flow_graph, Token::kMUL); | 752 return BuildBinaryFloat32x4Op(flow_graph, Token::kMUL); |
| 816 } | 753 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 832 !FlowGraphCompiler::SupportsUnboxedSimd128()) { | 769 !FlowGraphCompiler::SupportsUnboxedSimd128()) { |
| 833 return false; | 770 return false; |
| 834 } | 771 } |
| 835 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); | 772 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| 836 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); | 773 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| 837 BlockBuilder builder(flow_graph, normal_entry); | 774 BlockBuilder builder(flow_graph, normal_entry); |
| 838 | 775 |
| 839 Definition* receiver = builder.AddParameter(1); | 776 Definition* receiver = builder.AddParameter(1); |
| 840 | 777 |
| 841 Definition* unboxed_receiver = | 778 Definition* unboxed_receiver = |
| 842 builder.AddUnboxInstr(kUnboxedFloat32x4, | 779 builder.AddUnboxInstr(kUnboxedFloat32x4, new Value(receiver), |
| 843 new Value(receiver), | |
| 844 /* is_checked = */ true); | 780 /* is_checked = */ true); |
| 845 | 781 |
| 846 Definition* unboxed_result = builder.AddDefinition( | 782 Definition* unboxed_result = builder.AddDefinition(new Simd32x4ShuffleInstr( |
| 847 new Simd32x4ShuffleInstr(kind, | 783 kind, new Value(unboxed_receiver), 0, Thread::kNoDeoptId)); |
| 848 new Value(unboxed_receiver), | |
| 849 0, | |
| 850 Thread::kNoDeoptId)); | |
| 851 | 784 |
| 852 Definition* result = builder.AddDefinition( | 785 Definition* result = builder.AddDefinition( |
| 853 BoxInstr::Create(kUnboxedDouble, new Value(unboxed_result))); | 786 BoxInstr::Create(kUnboxedDouble, new Value(unboxed_result))); |
| 854 builder.AddIntrinsicReturn(new Value(result)); | 787 builder.AddIntrinsicReturn(new Value(result)); |
| 855 return true; | 788 return true; |
| 856 } | 789 } |
| 857 | 790 |
| 858 | 791 |
| 859 bool Intrinsifier::Build_Float32x4ShuffleX(FlowGraph* flow_graph) { | 792 bool Intrinsifier::Build_Float32x4ShuffleX(FlowGraph* flow_graph) { |
| 860 return BuildFloat32x4Shuffle(flow_graph, | 793 return BuildFloat32x4Shuffle(flow_graph, |
| (...skipping 19 matching lines...) Expand all Loading... |
| 880 } | 813 } |
| 881 | 814 |
| 882 | 815 |
| 883 static bool BuildLoadField(FlowGraph* flow_graph, intptr_t offset) { | 816 static bool BuildLoadField(FlowGraph* flow_graph, intptr_t offset) { |
| 884 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); | 817 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| 885 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); | 818 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| 886 BlockBuilder builder(flow_graph, normal_entry); | 819 BlockBuilder builder(flow_graph, normal_entry); |
| 887 | 820 |
| 888 Definition* array = builder.AddParameter(1); | 821 Definition* array = builder.AddParameter(1); |
| 889 | 822 |
| 890 Definition* length = builder.AddDefinition( | 823 Definition* length = builder.AddDefinition(new LoadFieldInstr( |
| 891 new LoadFieldInstr(new Value(array), | 824 new Value(array), offset, Type::ZoneHandle(), builder.TokenPos())); |
| 892 offset, | |
| 893 Type::ZoneHandle(), | |
| 894 builder.TokenPos())); | |
| 895 builder.AddIntrinsicReturn(new Value(length)); | 825 builder.AddIntrinsicReturn(new Value(length)); |
| 896 return true; | 826 return true; |
| 897 } | 827 } |
| 898 | 828 |
| 899 | 829 |
| 900 bool Intrinsifier::Build_ObjectArrayLength(FlowGraph* flow_graph) { | 830 bool Intrinsifier::Build_ObjectArrayLength(FlowGraph* flow_graph) { |
| 901 return BuildLoadField(flow_graph, Array::length_offset()); | 831 return BuildLoadField(flow_graph, Array::length_offset()); |
| 902 } | 832 } |
| 903 | 833 |
| 904 | 834 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 923 | 853 |
| 924 | 854 |
| 925 bool Intrinsifier::Build_GrowableArrayCapacity(FlowGraph* flow_graph) { | 855 bool Intrinsifier::Build_GrowableArrayCapacity(FlowGraph* flow_graph) { |
| 926 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); | 856 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| 927 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); | 857 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| 928 BlockBuilder builder(flow_graph, normal_entry); | 858 BlockBuilder builder(flow_graph, normal_entry); |
| 929 | 859 |
| 930 Definition* array = builder.AddParameter(1); | 860 Definition* array = builder.AddParameter(1); |
| 931 | 861 |
| 932 Definition* backing_store = builder.AddDefinition( | 862 Definition* backing_store = builder.AddDefinition( |
| 933 new LoadFieldInstr(new Value(array), | 863 new LoadFieldInstr(new Value(array), GrowableObjectArray::data_offset(), |
| 934 GrowableObjectArray::data_offset(), | 864 Type::ZoneHandle(), builder.TokenPos())); |
| 935 Type::ZoneHandle(), | |
| 936 builder.TokenPos())); | |
| 937 Definition* capacity = builder.AddDefinition( | 865 Definition* capacity = builder.AddDefinition( |
| 938 new LoadFieldInstr(new Value(backing_store), | 866 new LoadFieldInstr(new Value(backing_store), Array::length_offset(), |
| 939 Array::length_offset(), | 867 Type::ZoneHandle(), builder.TokenPos())); |
| 940 Type::ZoneHandle(), | |
| 941 builder.TokenPos())); | |
| 942 builder.AddIntrinsicReturn(new Value(capacity)); | 868 builder.AddIntrinsicReturn(new Value(capacity)); |
| 943 return true; | 869 return true; |
| 944 } | 870 } |
| 945 | 871 |
| 946 | 872 |
| 947 bool Intrinsifier::Build_GrowableArrayGetIndexed(FlowGraph* flow_graph) { | 873 bool Intrinsifier::Build_GrowableArrayGetIndexed(FlowGraph* flow_graph) { |
| 948 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); | 874 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| 949 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); | 875 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| 950 BlockBuilder builder(flow_graph, normal_entry); | 876 BlockBuilder builder(flow_graph, normal_entry); |
| 951 | 877 |
| 952 Definition* index = builder.AddParameter(1); | 878 Definition* index = builder.AddParameter(1); |
| 953 Definition* growable_array = builder.AddParameter(2); | 879 Definition* growable_array = builder.AddParameter(2); |
| 954 | 880 |
| 955 PrepareIndexedOp( | 881 PrepareIndexedOp(&builder, growable_array, index, |
| 956 &builder, growable_array, index, GrowableObjectArray::length_offset()); | 882 GrowableObjectArray::length_offset()); |
| 957 | 883 |
| 958 Definition* backing_store = builder.AddDefinition( | 884 Definition* backing_store = builder.AddDefinition(new LoadFieldInstr( |
| 959 new LoadFieldInstr(new Value(growable_array), | 885 new Value(growable_array), GrowableObjectArray::data_offset(), |
| 960 GrowableObjectArray::data_offset(), | 886 Type::ZoneHandle(), builder.TokenPos())); |
| 961 Type::ZoneHandle(), | 887 Definition* result = builder.AddDefinition(new LoadIndexedInstr( |
| 962 builder.TokenPos())); | 888 new Value(backing_store), new Value(index), |
| 963 Definition* result = builder.AddDefinition( | 889 Instance::ElementSizeFor(kArrayCid), // index scale |
| 964 new LoadIndexedInstr(new Value(backing_store), | 890 kArrayCid, kAlignedAccess, Thread::kNoDeoptId, builder.TokenPos())); |
| 965 new Value(index), | |
| 966 Instance::ElementSizeFor(kArrayCid), // index scale | |
| 967 kArrayCid, | |
| 968 kAlignedAccess, | |
| 969 Thread::kNoDeoptId, | |
| 970 builder.TokenPos())); | |
| 971 builder.AddIntrinsicReturn(new Value(result)); | 891 builder.AddIntrinsicReturn(new Value(result)); |
| 972 return true; | 892 return true; |
| 973 } | 893 } |
| 974 | 894 |
| 975 | 895 |
| 976 bool Intrinsifier::Build_GrowableArraySetIndexed(FlowGraph* flow_graph) { | 896 bool Intrinsifier::Build_GrowableArraySetIndexed(FlowGraph* flow_graph) { |
| 977 if (Isolate::Current()->type_checks()) { | 897 if (Isolate::Current()->type_checks()) { |
| 978 return false; | 898 return false; |
| 979 } | 899 } |
| 980 | 900 |
| 981 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); | 901 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| 982 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); | 902 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| 983 BlockBuilder builder(flow_graph, normal_entry); | 903 BlockBuilder builder(flow_graph, normal_entry); |
| 984 | 904 |
| 985 Definition* value = builder.AddParameter(1); | 905 Definition* value = builder.AddParameter(1); |
| 986 Definition* index = builder.AddParameter(2); | 906 Definition* index = builder.AddParameter(2); |
| 987 Definition* array = builder.AddParameter(3); | 907 Definition* array = builder.AddParameter(3); |
| 988 | 908 |
| 989 PrepareIndexedOp( | 909 PrepareIndexedOp(&builder, array, index, |
| 990 &builder, array, index, GrowableObjectArray::length_offset()); | 910 GrowableObjectArray::length_offset()); |
| 991 | 911 |
| 992 Definition* backing_store = builder.AddDefinition( | 912 Definition* backing_store = builder.AddDefinition( |
| 993 new LoadFieldInstr(new Value(array), | 913 new LoadFieldInstr(new Value(array), GrowableObjectArray::data_offset(), |
| 994 GrowableObjectArray::data_offset(), | 914 Type::ZoneHandle(), builder.TokenPos())); |
| 995 Type::ZoneHandle(), | |
| 996 builder.TokenPos())); | |
| 997 | 915 |
| 998 builder.AddInstruction( | 916 builder.AddInstruction(new StoreIndexedInstr( |
| 999 new StoreIndexedInstr(new Value(backing_store), | 917 new Value(backing_store), new Value(index), new Value(value), |
| 1000 new Value(index), | 918 kEmitStoreBarrier, |
| 1001 new Value(value), | 919 Instance::ElementSizeFor(kArrayCid), // index scale |
| 1002 kEmitStoreBarrier, | 920 kArrayCid, kAlignedAccess, Thread::kNoDeoptId, builder.TokenPos())); |
| 1003 Instance::ElementSizeFor(kArrayCid), // index scale | |
| 1004 kArrayCid, | |
| 1005 kAlignedAccess, | |
| 1006 Thread::kNoDeoptId, | |
| 1007 builder.TokenPos())); | |
| 1008 // Return null. | 921 // Return null. |
| 1009 Definition* null_def = builder.AddNullDefinition(); | 922 Definition* null_def = builder.AddNullDefinition(); |
| 1010 builder.AddIntrinsicReturn(new Value(null_def)); | 923 builder.AddIntrinsicReturn(new Value(null_def)); |
| 1011 return true; | 924 return true; |
| 1012 } | 925 } |
| 1013 | 926 |
| 1014 | 927 |
| 1015 bool Intrinsifier::Build_GrowableArraySetData(FlowGraph* flow_graph) { | 928 bool Intrinsifier::Build_GrowableArraySetData(FlowGraph* flow_graph) { |
| 1016 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); | 929 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| 1017 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); | 930 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| 1018 BlockBuilder builder(flow_graph, normal_entry); | 931 BlockBuilder builder(flow_graph, normal_entry); |
| 1019 | 932 |
| 1020 Definition* data = builder.AddParameter(1); | 933 Definition* data = builder.AddParameter(1); |
| 1021 Definition* growable_array = builder.AddParameter(2); | 934 Definition* growable_array = builder.AddParameter(2); |
| 1022 | 935 |
| 1023 const ICData& value_check = ICData::ZoneHandle(ICData::New( | 936 const ICData& value_check = ICData::ZoneHandle(ICData::New( |
| 1024 flow_graph->function(), | 937 flow_graph->function(), String::Handle(flow_graph->function().name()), |
| 1025 String::Handle(flow_graph->function().name()), | |
| 1026 Object::empty_array(), // Dummy args. descr. | 938 Object::empty_array(), // Dummy args. descr. |
| 1027 Thread::kNoDeoptId, | 939 Thread::kNoDeoptId, 1, false)); |
| 1028 1, | |
| 1029 false)); | |
| 1030 value_check.AddReceiverCheck(kArrayCid, flow_graph->function()); | 940 value_check.AddReceiverCheck(kArrayCid, flow_graph->function()); |
| 1031 builder.AddInstruction( | 941 builder.AddInstruction(new CheckClassInstr( |
| 1032 new CheckClassInstr(new Value(data), | 942 new Value(data), Thread::kNoDeoptId, value_check, builder.TokenPos())); |
| 1033 Thread::kNoDeoptId, | |
| 1034 value_check, | |
| 1035 builder.TokenPos())); | |
| 1036 | 943 |
| 1037 builder.AddInstruction( | 944 builder.AddInstruction(new StoreInstanceFieldInstr( |
| 1038 new StoreInstanceFieldInstr(GrowableObjectArray::data_offset(), | 945 GrowableObjectArray::data_offset(), new Value(growable_array), |
| 1039 new Value(growable_array), | 946 new Value(data), kEmitStoreBarrier, builder.TokenPos())); |
| 1040 new Value(data), | |
| 1041 kEmitStoreBarrier, | |
| 1042 builder.TokenPos())); | |
| 1043 // Return null. | 947 // Return null. |
| 1044 Definition* null_def = builder.AddNullDefinition(); | 948 Definition* null_def = builder.AddNullDefinition(); |
| 1045 builder.AddIntrinsicReturn(new Value(null_def)); | 949 builder.AddIntrinsicReturn(new Value(null_def)); |
| 1046 return true; | 950 return true; |
| 1047 } | 951 } |
| 1048 | 952 |
| 1049 | 953 |
| 1050 bool Intrinsifier::Build_GrowableArraySetLength(FlowGraph* flow_graph) { | 954 bool Intrinsifier::Build_GrowableArraySetLength(FlowGraph* flow_graph) { |
| 1051 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); | 955 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| 1052 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); | 956 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| 1053 BlockBuilder builder(flow_graph, normal_entry); | 957 BlockBuilder builder(flow_graph, normal_entry); |
| 1054 | 958 |
| 1055 Definition* length = builder.AddParameter(1); | 959 Definition* length = builder.AddParameter(1); |
| 1056 Definition* growable_array = builder.AddParameter(2); | 960 Definition* growable_array = builder.AddParameter(2); |
| 1057 | 961 |
| 1058 builder.AddInstruction( | 962 builder.AddInstruction(new CheckSmiInstr( |
| 1059 new CheckSmiInstr(new Value(length), | 963 new Value(length), Thread::kNoDeoptId, builder.TokenPos())); |
| 1060 Thread::kNoDeoptId, | 964 builder.AddInstruction(new StoreInstanceFieldInstr( |
| 1061 builder.TokenPos())); | 965 GrowableObjectArray::length_offset(), new Value(growable_array), |
| 1062 builder.AddInstruction( | 966 new Value(length), kNoStoreBarrier, builder.TokenPos())); |
| 1063 new StoreInstanceFieldInstr(GrowableObjectArray::length_offset(), | |
| 1064 new Value(growable_array), | |
| 1065 new Value(length), | |
| 1066 kNoStoreBarrier, | |
| 1067 builder.TokenPos())); | |
| 1068 Definition* null_def = builder.AddNullDefinition(); | 967 Definition* null_def = builder.AddNullDefinition(); |
| 1069 builder.AddIntrinsicReturn(new Value(null_def)); | 968 builder.AddIntrinsicReturn(new Value(null_def)); |
| 1070 return true; | 969 return true; |
| 1071 } | 970 } |
| 1072 | 971 |
| 1073 | 972 |
| 1074 bool Intrinsifier::Build_DoubleFlipSignBit(FlowGraph* flow_graph) { | 973 bool Intrinsifier::Build_DoubleFlipSignBit(FlowGraph* flow_graph) { |
| 1075 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) { | 974 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) { |
| 1076 return false; | 975 return false; |
| 1077 } | 976 } |
| 1078 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); | 977 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| 1079 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); | 978 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| 1080 BlockBuilder builder(flow_graph, normal_entry); | 979 BlockBuilder builder(flow_graph, normal_entry); |
| 1081 | 980 |
| 1082 Definition* receiver = builder.AddParameter(1); | 981 Definition* receiver = builder.AddParameter(1); |
| 1083 Definition* unboxed_value = | 982 Definition* unboxed_value = |
| 1084 builder.AddUnboxInstr(kUnboxedDouble, | 983 builder.AddUnboxInstr(kUnboxedDouble, new Value(receiver), |
| 1085 new Value(receiver), | |
| 1086 /* is_checked = */ true); | 984 /* is_checked = */ true); |
| 1087 Definition* unboxed_result = builder.AddDefinition( | 985 Definition* unboxed_result = builder.AddDefinition(new UnaryDoubleOpInstr( |
| 1088 new UnaryDoubleOpInstr(Token::kNEGATE, | 986 Token::kNEGATE, new Value(unboxed_value), Thread::kNoDeoptId)); |
| 1089 new Value(unboxed_value), | |
| 1090 Thread::kNoDeoptId)); | |
| 1091 Definition* result = builder.AddDefinition( | 987 Definition* result = builder.AddDefinition( |
| 1092 BoxInstr::Create(kUnboxedDouble, new Value(unboxed_result))); | 988 BoxInstr::Create(kUnboxedDouble, new Value(unboxed_result))); |
| 1093 builder.AddIntrinsicReturn(new Value(result)); | 989 builder.AddIntrinsicReturn(new Value(result)); |
| 1094 return true; | 990 return true; |
| 1095 } | 991 } |
| 1096 | 992 |
| 1097 | 993 |
| 1098 static bool BuildInvokeMathCFunction(BlockBuilder* builder, | 994 static bool BuildInvokeMathCFunction(BlockBuilder* builder, |
| 1099 MethodRecognizer::Kind kind, | 995 MethodRecognizer::Kind kind, |
| 1100 intptr_t num_parameters = 1) { | 996 intptr_t num_parameters = 1) { |
| 1101 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) { | 997 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) { |
| 1102 return false; | 998 return false; |
| 1103 } | 999 } |
| 1104 ZoneGrowableArray<Value*>* args = | 1000 ZoneGrowableArray<Value*>* args = |
| 1105 new ZoneGrowableArray<Value*>(num_parameters); | 1001 new ZoneGrowableArray<Value*>(num_parameters); |
| 1106 | 1002 |
| 1107 for (intptr_t i = 0; i < num_parameters; i++) { | 1003 for (intptr_t i = 0; i < num_parameters; i++) { |
| 1108 const intptr_t parameter_index = (num_parameters - i); | 1004 const intptr_t parameter_index = (num_parameters - i); |
| 1109 Definition* value = builder->AddParameter(parameter_index); | 1005 Definition* value = builder->AddParameter(parameter_index); |
| 1110 Definition* unboxed_value = | 1006 Definition* unboxed_value = |
| 1111 builder->AddUnboxInstr(kUnboxedDouble, value, /* is_checked = */ false); | 1007 builder->AddUnboxInstr(kUnboxedDouble, value, /* is_checked = */ false); |
| 1112 args->Add(new Value(unboxed_value)); | 1008 args->Add(new Value(unboxed_value)); |
| 1113 } | 1009 } |
| 1114 | 1010 |
| 1115 Definition* unboxed_result = | 1011 Definition* unboxed_result = builder->InvokeMathCFunction(kind, args); |
| 1116 builder->InvokeMathCFunction(kind, args); | |
| 1117 | 1012 |
| 1118 Definition* result = builder->AddDefinition( | 1013 Definition* result = builder->AddDefinition( |
| 1119 BoxInstr::Create(kUnboxedDouble, new Value(unboxed_result))); | 1014 BoxInstr::Create(kUnboxedDouble, new Value(unboxed_result))); |
| 1120 | 1015 |
| 1121 builder->AddIntrinsicReturn(new Value(result)); | 1016 builder->AddIntrinsicReturn(new Value(result)); |
| 1122 | 1017 |
| 1123 return true; | 1018 return true; |
| 1124 } | 1019 } |
| 1125 | 1020 |
| 1126 | 1021 |
| 1127 bool Intrinsifier::Build_MathSin(FlowGraph* flow_graph) { | 1022 bool Intrinsifier::Build_MathSin(FlowGraph* flow_graph) { |
| 1128 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false; | 1023 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false; |
| 1129 | 1024 |
| 1130 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); | 1025 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| 1131 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); | 1026 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| 1132 BlockBuilder builder(flow_graph, normal_entry); | 1027 BlockBuilder builder(flow_graph, normal_entry); |
| 1133 | 1028 |
| 1134 return BuildInvokeMathCFunction(&builder, | 1029 return BuildInvokeMathCFunction(&builder, MethodRecognizer::kMathSin); |
| 1135 MethodRecognizer::kMathSin); | |
| 1136 } | 1030 } |
| 1137 | 1031 |
| 1138 | 1032 |
| 1139 bool Intrinsifier::Build_MathCos(FlowGraph* flow_graph) { | 1033 bool Intrinsifier::Build_MathCos(FlowGraph* flow_graph) { |
| 1140 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false; | 1034 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false; |
| 1141 | 1035 |
| 1142 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); | 1036 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| 1143 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); | 1037 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| 1144 BlockBuilder builder(flow_graph, normal_entry); | 1038 BlockBuilder builder(flow_graph, normal_entry); |
| 1145 | 1039 |
| 1146 return BuildInvokeMathCFunction(&builder, | 1040 return BuildInvokeMathCFunction(&builder, MethodRecognizer::kMathCos); |
| 1147 MethodRecognizer::kMathCos); | |
| 1148 } | 1041 } |
| 1149 | 1042 |
| 1150 | 1043 |
| 1151 bool Intrinsifier::Build_MathTan(FlowGraph* flow_graph) { | 1044 bool Intrinsifier::Build_MathTan(FlowGraph* flow_graph) { |
| 1152 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false; | 1045 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false; |
| 1153 | 1046 |
| 1154 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); | 1047 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| 1155 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); | 1048 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| 1156 BlockBuilder builder(flow_graph, normal_entry); | 1049 BlockBuilder builder(flow_graph, normal_entry); |
| 1157 | 1050 |
| 1158 return BuildInvokeMathCFunction(&builder, | 1051 return BuildInvokeMathCFunction(&builder, MethodRecognizer::kMathTan); |
| 1159 MethodRecognizer::kMathTan); | |
| 1160 } | 1052 } |
| 1161 | 1053 |
| 1162 | 1054 |
| 1163 bool Intrinsifier::Build_MathAsin(FlowGraph* flow_graph) { | 1055 bool Intrinsifier::Build_MathAsin(FlowGraph* flow_graph) { |
| 1164 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false; | 1056 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false; |
| 1165 | 1057 |
| 1166 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); | 1058 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| 1167 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); | 1059 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| 1168 BlockBuilder builder(flow_graph, normal_entry); | 1060 BlockBuilder builder(flow_graph, normal_entry); |
| 1169 | 1061 |
| 1170 return BuildInvokeMathCFunction(&builder, | 1062 return BuildInvokeMathCFunction(&builder, MethodRecognizer::kMathAsin); |
| 1171 MethodRecognizer::kMathAsin); | |
| 1172 } | 1063 } |
| 1173 | 1064 |
| 1174 | 1065 |
| 1175 bool Intrinsifier::Build_MathAcos(FlowGraph* flow_graph) { | 1066 bool Intrinsifier::Build_MathAcos(FlowGraph* flow_graph) { |
| 1176 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false; | 1067 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false; |
| 1177 | 1068 |
| 1178 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); | 1069 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| 1179 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); | 1070 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| 1180 BlockBuilder builder(flow_graph, normal_entry); | 1071 BlockBuilder builder(flow_graph, normal_entry); |
| 1181 | 1072 |
| 1182 return BuildInvokeMathCFunction(&builder, | 1073 return BuildInvokeMathCFunction(&builder, MethodRecognizer::kMathAcos); |
| 1183 MethodRecognizer::kMathAcos); | |
| 1184 } | 1074 } |
| 1185 | 1075 |
| 1186 | 1076 |
| 1187 bool Intrinsifier::Build_MathAtan(FlowGraph* flow_graph) { | 1077 bool Intrinsifier::Build_MathAtan(FlowGraph* flow_graph) { |
| 1188 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false; | 1078 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false; |
| 1189 | 1079 |
| 1190 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); | 1080 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| 1191 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); | 1081 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| 1192 BlockBuilder builder(flow_graph, normal_entry); | 1082 BlockBuilder builder(flow_graph, normal_entry); |
| 1193 | 1083 |
| 1194 return BuildInvokeMathCFunction(&builder, | 1084 return BuildInvokeMathCFunction(&builder, MethodRecognizer::kMathAtan); |
| 1195 MethodRecognizer::kMathAtan); | |
| 1196 } | 1085 } |
| 1197 | 1086 |
| 1198 | 1087 |
| 1199 bool Intrinsifier::Build_MathAtan2(FlowGraph* flow_graph) { | 1088 bool Intrinsifier::Build_MathAtan2(FlowGraph* flow_graph) { |
| 1200 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false; | 1089 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false; |
| 1201 | 1090 |
| 1202 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); | 1091 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| 1203 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); | 1092 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| 1204 BlockBuilder builder(flow_graph, normal_entry); | 1093 BlockBuilder builder(flow_graph, normal_entry); |
| 1205 | 1094 |
| 1206 return BuildInvokeMathCFunction(&builder, | 1095 return BuildInvokeMathCFunction(&builder, MethodRecognizer::kMathAtan2, |
| 1207 MethodRecognizer::kMathAtan2, | |
| 1208 /* num_parameters = */ 2); | 1096 /* num_parameters = */ 2); |
| 1209 } | 1097 } |
| 1210 | 1098 |
| 1211 | 1099 |
| 1212 bool Intrinsifier::Build_DoubleMod(FlowGraph* flow_graph) { | 1100 bool Intrinsifier::Build_DoubleMod(FlowGraph* flow_graph) { |
| 1213 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false; | 1101 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false; |
| 1214 | 1102 |
| 1215 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); | 1103 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| 1216 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); | 1104 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| 1217 BlockBuilder builder(flow_graph, normal_entry); | 1105 BlockBuilder builder(flow_graph, normal_entry); |
| 1218 | 1106 |
| 1219 return BuildInvokeMathCFunction(&builder, | 1107 return BuildInvokeMathCFunction(&builder, MethodRecognizer::kDoubleMod, |
| 1220 MethodRecognizer::kDoubleMod, | |
| 1221 /* num_parameters = */ 2); | 1108 /* num_parameters = */ 2); |
| 1222 } | 1109 } |
| 1223 | 1110 |
| 1224 | 1111 |
| 1225 bool Intrinsifier::Build_DoubleCeil(FlowGraph* flow_graph) { | 1112 bool Intrinsifier::Build_DoubleCeil(FlowGraph* flow_graph) { |
| 1226 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false; | 1113 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false; |
| 1227 // TODO(johnmccutchan): On X86 this intrinsic can be written in a different | 1114 // TODO(johnmccutchan): On X86 this intrinsic can be written in a different |
| 1228 // way. | 1115 // way. |
| 1229 if (TargetCPUFeatures::double_truncate_round_supported()) return false; | 1116 if (TargetCPUFeatures::double_truncate_round_supported()) return false; |
| 1230 | 1117 |
| 1231 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); | 1118 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| 1232 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); | 1119 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| 1233 BlockBuilder builder(flow_graph, normal_entry); | 1120 BlockBuilder builder(flow_graph, normal_entry); |
| 1234 | 1121 |
| 1235 return BuildInvokeMathCFunction(&builder, | 1122 return BuildInvokeMathCFunction(&builder, MethodRecognizer::kDoubleCeil); |
| 1236 MethodRecognizer::kDoubleCeil); | |
| 1237 } | 1123 } |
| 1238 | 1124 |
| 1239 | 1125 |
| 1240 bool Intrinsifier::Build_DoubleFloor(FlowGraph* flow_graph) { | 1126 bool Intrinsifier::Build_DoubleFloor(FlowGraph* flow_graph) { |
| 1241 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false; | 1127 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false; |
| 1242 // TODO(johnmccutchan): On X86 this intrinsic can be written in a different | 1128 // TODO(johnmccutchan): On X86 this intrinsic can be written in a different |
| 1243 // way. | 1129 // way. |
| 1244 if (TargetCPUFeatures::double_truncate_round_supported()) return false; | 1130 if (TargetCPUFeatures::double_truncate_round_supported()) return false; |
| 1245 | 1131 |
| 1246 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); | 1132 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| 1247 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); | 1133 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| 1248 BlockBuilder builder(flow_graph, normal_entry); | 1134 BlockBuilder builder(flow_graph, normal_entry); |
| 1249 | 1135 |
| 1250 return BuildInvokeMathCFunction(&builder, | 1136 return BuildInvokeMathCFunction(&builder, MethodRecognizer::kDoubleFloor); |
| 1251 MethodRecognizer::kDoubleFloor); | |
| 1252 } | 1137 } |
| 1253 | 1138 |
| 1254 | 1139 |
| 1255 bool Intrinsifier::Build_DoubleTruncate(FlowGraph* flow_graph) { | 1140 bool Intrinsifier::Build_DoubleTruncate(FlowGraph* flow_graph) { |
| 1256 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false; | 1141 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false; |
| 1257 // TODO(johnmccutchan): On X86 this intrinsic can be written in a different | 1142 // TODO(johnmccutchan): On X86 this intrinsic can be written in a different |
| 1258 // way. | 1143 // way. |
| 1259 if (TargetCPUFeatures::double_truncate_round_supported()) return false; | 1144 if (TargetCPUFeatures::double_truncate_round_supported()) return false; |
| 1260 | 1145 |
| 1261 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); | 1146 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| 1262 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); | 1147 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| 1263 BlockBuilder builder(flow_graph, normal_entry); | 1148 BlockBuilder builder(flow_graph, normal_entry); |
| 1264 | 1149 |
| 1265 return BuildInvokeMathCFunction(&builder, | 1150 return BuildInvokeMathCFunction(&builder, MethodRecognizer::kDoubleTruncate); |
| 1266 MethodRecognizer::kDoubleTruncate); | |
| 1267 } | 1151 } |
| 1268 | 1152 |
| 1269 | 1153 |
| 1270 bool Intrinsifier::Build_DoubleRound(FlowGraph* flow_graph) { | 1154 bool Intrinsifier::Build_DoubleRound(FlowGraph* flow_graph) { |
| 1271 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false; | 1155 if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false; |
| 1272 | 1156 |
| 1273 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); | 1157 GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| 1274 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); | 1158 TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| 1275 BlockBuilder builder(flow_graph, normal_entry); | 1159 BlockBuilder builder(flow_graph, normal_entry); |
| 1276 | 1160 |
| 1277 return BuildInvokeMathCFunction(&builder, | 1161 return BuildInvokeMathCFunction(&builder, MethodRecognizer::kDoubleRound); |
| 1278 MethodRecognizer::kDoubleRound); | |
| 1279 } | 1162 } |
| 1280 #endif // !defined(TARGET_ARCH_DBC) | 1163 #endif // !defined(TARGET_ARCH_DBC) |
| 1281 | 1164 |
| 1282 | 1165 |
| 1283 } // namespace dart | 1166 } // namespace dart |
| OLD | NEW |