Chromium Code Reviews| 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 | 4 |
| 5 #ifndef VM_FLOW_GRAPH_COMPILER_H_ | 5 #ifndef VM_FLOW_GRAPH_COMPILER_H_ |
| 6 #define VM_FLOW_GRAPH_COMPILER_H_ | 6 #define VM_FLOW_GRAPH_COMPILER_H_ |
| 7 | 7 |
| 8 #include "vm/allocation.h" | |
| 9 #include "vm/assembler.h" | |
| 10 #include "vm/assembler_macros.h" | |
| 11 #include "vm/code_descriptors.h" | |
| 12 #include "vm/code_generator.h" | |
| 13 #include "vm/intermediate_language.h" | |
| 14 | |
| 15 namespace dart { | |
| 16 | |
| 17 // Forward declarations. | |
| 18 class FlowGraphCompiler; | |
| 19 class DeoptimizationStub; | |
| 20 | |
| 21 | |
| 22 // FrameRegisterAllocator is a simple local register allocator that tries to | |
| 23 // keep values in registers by delaying pushing them to the stack after they | |
| 24 // were produced by Bind instruction. FrameRegisterAllocator relies on the | |
| 25 // fact that IR is stack based and a value produced by a bind instruction | |
| 26 // will be used only once. For the register allocator every Bind is a push and | |
| 27 // every UseVal of a bind is a pop. | |
| 28 // It can also operate in a non-optimizing mode when every value is pushed | |
| 29 // to the stack immediately after it is produced. | |
| 30 // TODO(vegorov): replace with a linear scan register allocator once SSA is | |
| 31 // available. | |
| 32 class FrameRegisterAllocator : public ValueObject { | |
| 33 public: | |
| 34 explicit FrameRegisterAllocator(FlowGraphCompiler* compiler, | |
| 35 bool keep_values_in_registers) | |
|
srdjan
2012/06/18 16:33:20
remove explicit
Vyacheslav Egorov (Google)
2012/06/18 17:51:16
Done.
| |
| 36 : compiler_(compiler), | |
| 37 stack_(kNumberOfCpuRegisters), | |
| 38 registers_(), | |
| 39 keep_values_in_registers_(keep_values_in_registers) { | |
| 40 for (int i = 0; i < kNumberOfCpuRegisters; i++) { | |
| 41 registers_[i] = NULL; | |
| 42 } | |
| 43 } | |
| 44 | |
| 45 // Notify register allocator that given instruction produced a value | |
| 46 // in the given register. | |
| 47 void Push(Register reg, Instruction* val); | |
| 48 | |
| 49 // Perform a greedy local register allocation. Consider all register free. | |
| 50 void AllocateRegisters(Instruction* instr); | |
| 51 | |
| 52 // Spill all live registers to the stack in order from oldest to newest. | |
| 53 void Spill(); | |
| 54 | |
| 55 // Returns true if all live values are stored on the stack. | |
| 56 // Code generator expects no live values in registers at call sites and | |
| 57 // branches. | |
| 58 bool IsSpilled() const { return stack_.length() == 0; } | |
| 59 | |
| 60 // Popuplate deoptimization stub with live registers to ensure | |
| 61 // that they will be pushed to the stack when deoptimization happens. | |
| 62 void SpillInDeoptStub(DeoptimizationStub* stub); | |
| 63 | |
| 64 private: | |
| 65 // Pop a value from the place where it is currently stored (either register | |
| 66 // or top of the stack) into a given register. If value is in the register | |
| 67 // verify that passed use corresponds to the instruction that produced the | |
| 68 // value. | |
| 69 void Pop(Register reg, Value* use); | |
| 70 | |
| 71 // Allocate a register that is not explicitly blocked. | |
| 72 // Spills a value if all non-blocked registers contain values. | |
| 73 Register AllocateFreeRegister(bool* blocked_registers); | |
| 74 | |
| 75 // Ensure that given register is free for allocation. | |
| 76 void SpillRegister(Register reg); | |
| 77 | |
| 78 // Spill the oldest live value from register to the stack. | |
| 79 Register SpillFirst(); | |
| 80 | |
| 81 FlowGraphCompiler* compiler() { return compiler_; } | |
| 82 | |
| 83 FlowGraphCompiler* compiler_; | |
| 84 | |
| 85 // List of registers with live values in order from oldest to newest. | |
| 86 GrowableArray<Register> stack_; | |
| 87 | |
| 88 // Mapping between live registers and instructions that produced values | |
| 89 // in them. Contains NULL for registers do not have corresponding live value. | |
| 90 Instruction* registers_[kNumberOfCpuRegisters]; | |
|
srdjan
2012/06/18 16:33:20
Consider renaming registers_to_instructions_, or j
Florian Schneider
2012/06/18 16:50:55
Can it even be BindInstr*?
Vyacheslav Egorov (Google)
2012/06/18 17:51:16
Done.
Vyacheslav Egorov (Google)
2012/06/18 17:51:16
I am not sure instructions_ reflects the purpose:
| |
| 91 | |
| 92 bool keep_values_in_registers_; | |
|
srdjan
2012/06/18 16:33:20
const?
Vyacheslav Egorov (Google)
2012/06/18 17:51:16
Done.
Vyacheslav Egorov (Google)
2012/06/18 17:51:16
Done.
| |
| 93 | |
| 94 DISALLOW_COPY_AND_ASSIGN(FrameRegisterAllocator); | |
| 95 }; | |
| 96 | |
| 97 } // namespace dart | |
| 98 | |
| 8 #if defined(TARGET_ARCH_IA32) | 99 #if defined(TARGET_ARCH_IA32) |
| 9 #include "vm/flow_graph_compiler_ia32.h" | 100 #include "vm/flow_graph_compiler_ia32.h" |
| 10 #elif defined(TARGET_ARCH_X64) | 101 #elif defined(TARGET_ARCH_X64) |
| 11 #include "vm/flow_graph_compiler_x64.h" | 102 #include "vm/flow_graph_compiler_x64.h" |
| 12 #elif defined(TARGET_ARCH_ARM) | 103 #elif defined(TARGET_ARCH_ARM) |
| 13 #include "vm/flow_graph_compiler_arm.h" | 104 #include "vm/flow_graph_compiler_arm.h" |
| 14 #else | 105 #else |
| 15 #error Unknown architecture. | 106 #error Unknown architecture. |
| 16 #endif | 107 #endif |
| 17 | 108 |
| 18 #endif // VM_FLOW_GRAPH_COMPILER_H_ | 109 #endif // VM_FLOW_GRAPH_COMPILER_H_ |
| OLD | NEW |