41 #define DEBUG_NAME "compiler2/LinearScanAllocator"
45 "Number of Hints followed (
i.
e. no move)",lsra_stat)
47 "Number of Hints not followed (
i.
e. move needed)",lsra_stat)
52 STAT_REGISTER_GROUP_VAR(std::
size_t,num_resolution_moves,0,"resolution moves","Number of move instructions for resolution",lsra_stat)
53 STAT_REGISTER_GROUP_VAR(std::
size_t,num_allocate_free,0,"allocate free","Number of free register allocated",lsra_stat)
54 STAT_REGISTER_GROUP_VAR(std::
size_t,num_allocate_blocked,0,"allocate blocked","Number of blocked register allocated (spill)",lsra_stat)
55 STAT_REGISTER_GROUP_VAR(std::
size_t,num_fixed_intervals,0,"fixed intervals","Number of fixed (preallocated) intervals",lsra_stat)
56 STAT_REGISTER_GROUP_VAR(std::
size_t,num_spill_blocked_fixed,0,"spilled blocked","Number blocked fixed intervals spilled",lsra_stat)
58 STAT_REGISTER_GROUP_VAR(std::
size_t,num_resolution_stacks,0,"resolution stacks","Number stackslots allocated for resolution (no free registers)",lsra_stat)
68 bool LinearScanAllocatorPass::StartComparator::operator()(
const LivetimeInterval &lhs,
69 const LivetimeInterval &rhs) {
70 if (rhs.front().start < lhs.front().start)
return true;
71 if (lhs.front().start < rhs.front().start)
return false;
73 return lhs.back().end < rhs.back().end;
80 struct FreeUntilCompare:
public std::binary_function<MachineOperand*,MachineOperand*,bool> {
81 bool operator()(MachineOperand *lhs, MachineOperand *rhs)
const {
82 bool r = lhs->aquivalence_less(*rhs);
88 typedef alloc::map<MachineOperand*,UseDef,FreeUntilCompare>::type FreeUntilMap;
93 struct InitFreeUntilMap:
public std::unary_function<MachineOperand*,void> {
94 FreeUntilMap &free_until_pos;
97 InitFreeUntilMap(FreeUntilMap &free_until_pos,
98 UseDef end) : free_until_pos(free_until_pos), end(end) {}
100 void operator()(MachineOperand *MO) {
101 free_until_pos.insert(std::make_pair(MO,end));
109 struct SetActive:
public std::unary_function<LivetimeInterval&,void> {
110 FreeUntilMap &free_until_pos;
113 SetActive(FreeUntilMap &free_until_pos,
114 UseDef start) : free_until_pos(free_until_pos), start(start) {}
116 void operator()(LivetimeInterval& lti) {
117 MachineOperand *MO = lti.get_operand();
119 FreeUntilMap::iterator
i = free_until_pos.find(MO);
120 if (i != free_until_pos.end()) {
122 LOG2(
"SetActive: " << lti <<
" operand: " << *MO <<
" to " << start <<
nl);
132 struct SetIntersection:
public std::unary_function<LivetimeInterval&,void> {
133 FreeUntilMap &free_until_pos;
138 SetIntersection(FreeUntilMap &free_until_pos,
139 LivetimeInterval &
current, UseDef
pos, UseDef end)
140 : free_until_pos(free_until_pos),
current(current),
pos(pos), end(end) {}
142 void operator()(LivetimeInterval& lti) {
143 MachineOperand *MO = lti.get_operand();
144 FreeUntilMap::iterator
i = free_until_pos.find(MO);
145 if (i != free_until_pos.end()) {
147 LOG2(
"SetIntersection: " << lti <<
" inter1: " << inter <<
nl);
150 if (inter < i->second) {
152 LOG2(
"SetIntersection: " << lti <<
" operand: " << *MO <<
" to " << i->second <<
nl);
163 struct FreeUntilMaxCompare
164 :
public std::binary_function<const FreeUntilMap::value_type&, const FreeUntilMap::value_type&,bool> {
165 bool operator()(
const FreeUntilMap::value_type &lhs,
const FreeUntilMap::value_type &rhs)
const {
166 return lhs.second < rhs.second;
173 struct SetUseDefOperand:
public std::unary_function<const UseDef&,void> {
176 SetUseDefOperand(MachineOperand*
op) :
op(op) {}
177 void operator()(
const UseDef &usedef) {
178 LOG2(
" set def operand " << usedef <<
" to " << op <<
nl);
179 usedef.get_operand()->op =
op;
184 MIIterator insert_move_before(MachineInstruction* move, UseDef usedef) {
185 MIIterator free_until_pos_reg = usedef.get_iterator();
186 assert(!(*free_until_pos_reg)->is_label());
196 FreeUntilMap free_until_pos;
198 backend->get_OperandFile(op_file,current.
get_operand());
200 std::for_each(op_file.begin(),op_file.end(),
201 InitFreeUntilMap(free_until_pos,
UseDef(UseDef::PseudoDef,MIS->mi_end())));
204 std::for_each(active.begin(), active.end(),
205 SetActive(free_until_pos,
UseDef(UseDef::PseudoUse,MIS->mi_begin())));
208 std::for_each(inactive.begin(), inactive.end(),
209 SetIntersection(free_until_pos, current,pos,
UseDef(UseDef::PseudoDef,MIS->mi_end())));
211 LOG2(
"free_until_pos:" <<
nl);
213 for (FreeUntilMap::iterator
i = free_until_pos.begin(),
e = free_until_pos.end();
i !=
e; ++
i) {
214 LOG2(
" " << (
i->first) <<
": " <<
i->second <<
nl);
219 UseDef free_until_pos_reg(UseDef::PseudoUse,MIS->mi_begin());
222 if (option::hints && hint) {
223 if (hint->is_virtual()) {
228 LOG2(
"hint current pos " << hint <<
nl);
229 FreeUntilMap::const_iterator
i = free_until_pos.find(hint);
230 if (i != free_until_pos.end()) {
231 free_until_pos_reg = i->second;
232 if ((free_until_pos_reg !=
UseDef(UseDef::PseudoUse,MIS->mi_begin())) &&
233 (current.
back().
end < free_until_pos_reg)) {
234 LOG2(
"hint available! " << hint <<
nl);
249 FreeUntilMap::value_type x = *std::max_element(free_until_pos.begin(), free_until_pos.end(), FreeUntilMaxCompare());
251 free_until_pos_reg = x.second;
254 LOG2(
"reg: " << reg <<
" pos: " << free_until_pos_reg <<
nl);
256 if (free_until_pos_reg ==
UseDef(UseDef::PseudoUse,MIS->mi_begin())) {
261 LOG2(
"assigned operand: " << *reg <<
nl);
262 if (current.
back().
end < free_until_pos_reg) {
268 if(!(*free_until_pos_reg.get_iterator())->is_label()) {
272 MIIterator split_pos = insert_move_before(move,free_until_pos_reg);
274 << free_until_pos_reg <<
" split: " << split_pos);
275 LOG2(
"splitting interval " << current <<
" at " << split_pos <<
" inserted move: " << move <<
nl);
280 LOG2(
"splitting interval " << current <<
" at " << free_until_pos_reg <<
" no move required, op" << tmp <<
nl);
291 struct SetNextUseActive:
public std::unary_function<LivetimeInterval&,void> {
292 FreeUntilMap &next_use_pos;
296 SetNextUseActive(FreeUntilMap &next_use_pos,
297 UseDef pos,
UseDef end) : next_use_pos(next_use_pos), pos(pos), end(end) {}
299 void operator()(LivetimeInterval& lti) {
302 FreeUntilMap::iterator
i = next_use_pos.find(MO);
303 if (i != next_use_pos.end()) {
305 i->second = lti.next_usedef_after(
pos,end);
306 LOG2(
"SetNextUseActive: " << lti <<
" operand: " << *MO <<
" to " << i->second <<
nl);
308 MachineInstruction *MI = *
pos.get_iterator();
309 MachineOperand *origMO = lti.get_init_operand();
310 LOG2(
"MI: " << MI <<
" orig: " << origMO <<
nl);
312 if (MI->find(origMO) != MI->end()) {
325 struct SetNextUseInactive:
public std::unary_function<LivetimeInterval&,void> {
326 FreeUntilMap &free_until_pos;
331 SetNextUseInactive(FreeUntilMap &free_until_pos,
332 LivetimeInterval &
current, UseDef
pos, UseDef end)
333 : free_until_pos(free_until_pos), current(current), pos(pos), end(end) {}
335 void operator()(LivetimeInterval& lti) {
336 MachineOperand *MO = lti.get_operand();
337 FreeUntilMap::iterator i = free_until_pos.find(MO);
339 i->second = lti.next_usedef_after(
pos,end);
340 LOG2(
"SetNextUseInactive: " << lti <<
" operand: " << *MO <<
" to " << i->second <<
nl);
345 inline MachineOperand* get_stackslot(Backend *backend, Type::TypeID type) {
346 return backend->get_JITData()->get_StackSlotManager()->create_ManagedStackSlot(type);
349 void split_active_position(LivetimeInterval lti, UseDef current_pos, UseDef next_use_pos, Backend *backend,
350 LinearScanAllocatorPass::UnhandledSetTy &
unhandled) {
351 MachineOperand *MO = lti.get_operand();
354 if (current_pos.is_pseudo()) {
357 if(lti.front().start == current_pos) {
360 stackslot = get_stackslot(backend,MO->get_type());
361 lti.set_operand(stackslot);
366 stackslot = get_stackslot(backend,MO->get_type());
367 lti = lti.split_phi_active(current_pos.get_iterator(),stackslot);
374 stackslot = get_stackslot(backend,MO->get_type());
375 MachineInstruction *move_to_stack = backend->create_Move(MO,stackslot);
376 MIIterator split_pos = insert_move_before(move_to_stack,current_pos);
378 lti = lti.split_active(split_pos,¤t_pos);
383 if (!next_use_pos.is_pseudo()) {
386 MachineOperand *vreg =
new VirtualRegister(MO->get_type());
387 MachineInstruction *move_from_stack = backend->create_Move(stackslot, vreg);
388 MIIterator split_pos = insert_move_before(move_from_stack,next_use_pos);
390 lti = lti.split_active(split_pos);
398 struct SplitActive:
public std::unary_function<LivetimeInterval&,void> {
403 LinearScanAllocatorPass::UnhandledSetTy &
unhandled;
405 SplitActive(MachineOperand *reg , UseDef
pos, UseDef next_use_pos, Backend *backend,
406 LinearScanAllocatorPass::UnhandledSetTy &unhandled)
407 : reg(reg), pos(pos), next_use_pos(next_use_pos), backend(backend), unhandled(unhandled) {}
409 void operator()(LivetimeInterval& lti) {
410 MachineOperand *MO = lti.get_operand();
411 if (reg->aquivalent(*MO)) {
412 split_active_position(lti,
pos,next_use_pos,backend, unhandled);
420 struct SplitInactive:
public std::unary_function<LivetimeInterval&,void> {
423 LinearScanAllocatorPass::UnhandledSetTy &
unhandled;
425 SplitInactive(MachineOperand *reg , UseDef
pos, LinearScanAllocatorPass::UnhandledSetTy &unhandled)
426 : reg(reg), pos(pos), unhandled(unhandled) {}
428 void operator()(LivetimeInterval& lti) {
429 MachineOperand *MO = lti.get_operand();
430 if (reg->aquivalent(*MO)) {
432 LivetimeInterval new_lti = lti.split_inactive(
pos,
new VirtualRegister(reg->get_type()));
434 assert(lti.front().start < new_lti.front().start);
435 unhandled.push(new_lti);
440 inline void split_current(LivetimeInterval &
current, Type::TypeID type, UseDef
pos, UseDef end,
441 LinearScanAllocatorPass::UnhandledSetTy &unhandled, Backend *backend) {
442 LOG2(
"Spill current (" << current <<
") at " << pos <<
nl);
444 MachineOperand *stackslot = get_stackslot(backend,type);
447 MachineOperand *vreg =
new VirtualRegister(type);
448 MachineInstruction *move_from_stack = backend->create_Move(stackslot,vreg);
450 MIIterator split_pos = insert_move_before(move_from_stack,pos);
452 LivetimeInterval new_lti = current.split_active(split_pos);
453 unhandled.push(new_lti);
456 current.set_operand(stackslot);
459 #if defined(ENABLE_LOGGING)
460 OStream& print_code(OStream &
OS, MIIterator pos, MIIterator
min, MIIterator
max,
461 MIIterator::difference_type before, MIIterator::difference_type after) {
464 before =
std::min(before,std::distance(min,pos));
465 after =
std::min(after,std::distance(pos,max));
466 std::advance(i,-before);
467 std::advance(e,after+1);
470 for ( ; i !=
e ; ++
i) {
476 return OS <<
"..." <<
nl;
484 FreeUntilMap next_use_pos;
486 backend->get_OperandFile(op_file,current.
get_operand());
488 std::for_each(op_file.begin(),op_file.end(),
489 InitFreeUntilMap(next_use_pos,
UseDef(UseDef::PseudoDef,MIS->mi_end())));
492 std::for_each(active.begin(), active.end(),
493 SetNextUseActive(next_use_pos, current.
front().
start,
UseDef(UseDef::PseudoDef,MIS->mi_end())));
496 std::for_each(inactive.begin(), inactive.end(),
497 SetNextUseInactive(next_use_pos, current, current.
front().
start,
UseDef(UseDef::PseudoDef,MIS->mi_end())));
499 LOG2(
"next_use_pos:" << nl);
500 for (FreeUntilMap::iterator i = next_use_pos.begin(), e = next_use_pos.end(); i !=
e; ++
i) {
501 LOG2(
" " << (i->first) <<
": " << i->second << nl);
505 FreeUntilMap::value_type x = *std::max_element(next_use_pos.begin(), next_use_pos.end(), FreeUntilMaxCompare());
507 UseDef next_use_pos_reg = x.second;
508 LOG2(
"reg: " << *reg <<
" pos: " << next_use_pos_reg << nl);
511 UseDef(UseDef::PseudoDef,MIS->mi_end()));
512 if (next_use_pos_reg < next_use_pos_current && !current.
front().
start.
is_def()) {
517 UseDef(UseDef::PseudoDef,MIS->mi_end()), unhandled, backend);
522 LOG2(
"Spill intervals blocking: " << *reg << nl);
526 std::for_each(active.begin(), active.end(),
530 std::for_each(inactive.begin(), inactive.end(),
533 LOG2(
"assigned operand: " << *reg << nl);
539 void LinearScanAllocatorPass::initialize() {
540 while (!unhandled.empty()) {
548 bool LinearScanAllocatorPass::allocate_unhandled() {
549 while(!unhandled.empty()) {
557 LOG2(
"check for intervals in active that are handled or inactive" << nl);
558 for (ActiveSetTy::iterator i = active.begin(), e = active.end();
562 case LivetimeInterval::Handled:
563 LOG2(
" LTI " << act <<
" moved from active to handled" << nl);
564 handled.push_back(act);
567 case LivetimeInterval::Inactive:
568 LOG2(
" LTI " << act <<
" moved from active to inactive" << nl);
569 inactive.push_back(act);
577 LOG2(
"check for intervals in inactive that are handled or active" << nl);
578 for (InactiveSetTy::iterator i = inactive.begin(), e = inactive.end();
582 case LivetimeInterval::Handled:
583 LOG2(
" LTI " << inact <<
" moved from inactive to handled" << nl);
584 handled.push_back(inact);
585 i = inactive.erase(i);
587 case LivetimeInterval::Active:
588 LOG2(
" LTI " << inact <<
" moved from inactive to active" << nl);
589 active.push_back(inact);
590 i = inactive.erase(i);
604 if (!try_allocate_free(current,pos)) {
605 if (!allocate_blocked(current)) {
607 "could not allocate register for " << current);
621 for (ActiveSetTy::iterator i = active.begin(), e = active.end(); i !=
e ; ++
i ) {
632 SplitActive::argument_type split_act = act;
635 std::for_each(inactive.begin(), inactive.end(),
643 active.push_back(current);
644 LOG2(
"LTI " << current <<
" moved from unhandled to handled" << nl);
648 for (ActiveSetTy::iterator i = active.begin(), e = active.end(); i !=
e ; ) {
649 handled.push_back(*i);
652 for (InactiveSetTy::iterator i = inactive.begin(), e = inactive.end(); i !=
e ; ) {
653 handled.push_back(*i);
654 i = inactive.erase(i);
659 bool LinearScanAllocatorPass::run(
JITData &JD) {
660 LA = get_Pass<LivetimeAnalysisPass>();
661 MIS = get_Pass<MachineInstructionSchedulingPass>();
668 unhandled.push(inter);
671 if (!allocate_unhandled())
return false;
673 if (!resolve())
return false;
676 for (HandledSetTy::const_iterator i = handled.begin(), e = handled.end(); i !=
e ; ++
i) {
685 typedef alloc::map<Type::TypeID, alloc::set<MachineOperand*,MachineOperandComp>::type >::type
FreeRegsMap;
691 template <
class BinaryOperation>
692 class CfgEdgeFunctor :
public std::unary_function<MachineBasicBlock*,void> {
697 CfgEdgeFunctor(BinaryOperation
op) :
op(op) {}
698 void operator()(MachineBasicBlock *predecessor) {
699 std::for_each(predecessor->back()->successor_begin(),
700 predecessor->back()->successor_end(), std::bind1st(op,predecessor));
704 template <
class BinaryOperation>
705 CfgEdgeFunctor<BinaryOperation> CfgEdge(BinaryOperation
op) {
706 return CfgEdgeFunctor<BinaryOperation>(
op);
709 class CalcBBtoLTIMap :
public std::unary_function<MachineBasicBlock*,void> {
711 LivetimeAnalysisPass* LA;
714 struct inner :
public std::unary_function<LivetimeAnalysisPass::LivetimeIntervalMapTy::value_type,void> {
715 MachineBasicBlock *MBB;
718 inner(MachineBasicBlock *MBB,
BBtoLTI_Map &bb2lti_map) : MBB(MBB), bb2lti_map(bb2lti_map) {}
720 void operator()(argument_type lti_pair) {
721 LivetimeInterval <i = lti_pair.second;
722 if (lti.get_State(UseDef(UseDef::PseudoUse,MBB->mi_first())) == LivetimeInterval::Active) {
723 bb2lti_map[MBB].push_back(lti);
727 LivetimeInterval lti_next = lti;
728 while (lti_next.has_next()) {
729 lti_next = lti_next.get_next();
730 if (lti_next.get_State(UseDef(UseDef::PseudoUse,MBB->mi_first())) == LivetimeInterval::Active) {
731 bb2lti_map[MBB].push_back(lti);
739 CalcBBtoLTIMap(LivetimeAnalysisPass* LA,
BBtoLTI_Map &bb2lti_map)
740 : LA(LA), bb2lti_map(bb2lti_map) {}
742 void operator()(MachineBasicBlock *MBB) {
743 std::for_each(LA->begin(),LA->end(),inner(MBB,bb2lti_map));
748 bool operator<(
const Move &lhs,
const Move &rhs) {
749 if (lhs.from < rhs.from)
751 if (rhs.from < lhs.from)
753 return lhs.to < rhs.to;
757 class ForEachLiveiterval :
public std::unary_function<LivetimeInterval&,void> {
759 MachineBasicBlock *predecessor;
760 MachineBasicBlock *successor;
761 LivetimeAnalysisPass *LA;
765 ForEachLiveiterval(MachineBasicBlock *predecessor, MachineBasicBlock *successor,
766 LivetimeAnalysisPass *LA,
MoveMapTy &move_map) :
767 predecessor(predecessor), successor(successor), LA(LA), move_map(move_map) {}
769 void operator()(LivetimeInterval& lti)
const {
770 LOG2(
"live: " << lti <<
" op: " << *lti.get_init_operand() <<
nl);
772 MachineOperand *move_from;
774 if (lti.front().start.get_iterator() == successor->mi_first()) {
777 LOG2(
"starts at successor begin: " << *phi << nl);
778 std::size_t
index = successor->get_predecessor_index(predecessor);
779 MachineOperand *op = phi->get(index).op;
780 if (op->is_Immediate()) {
781 ABORT_MSG(
"PHI with immediate operand",
"Can not yet handle phis with immediate operands");
784 move_from = LA->get(op).get_operand(predecessor->mi_last());
789 move_from = lti.get_operand(predecessor->mi_last());
791 MachineOperand *move_to = lti.get_operand(successor->mi_first());
792 LOG3(
" from: " << move_from <<
" to " << move_to << nl);
793 if (!move_from->aquivalent(*move_to)) {
794 move_map.push_back(Move(move_from,move_to));
799 #if defined(ENABLE_LOGGING)
801 for (FreeRegsMap::const_iterator i = free_regs.begin(), e = free_regs.end() ; i!=
e ; ++
i) {
802 Type::TypeID type = i->first;
803 const FreeRegsMap::mapped_type ®s = i->second;
804 OS <<
"type: " << type <<
" ";
811 Type::TypeID types[] = {
815 Type::ReferenceTypeID,
820 inline void free_regs_remove_op(
FreeRegsMap &free_regs, MachineOperand *op) {
821 for (Type::TypeID *p = types; *p != Type::VoidTypeID; ++p) {
822 Type::TypeID type = *p;
823 free_regs[type].erase(op);
827 inline MachineOperand* get_and_remove_free_regs(
FreeRegsMap &free_regs, Type::TypeID type) {
828 FreeRegsMap::mapped_type &
map = free_regs[type];
835 FreeRegsMap::mapped_type::iterator i = map.begin();
836 MachineOperand *op = *
i;
838 free_regs_remove_op(free_regs,op);
846 inline void calc_free_regs(
FreeRegsMap &free_regs,
BBtoLTI_Map &bb2lti_map, MachineBasicBlock* predecessor,
847 MachineBasicBlock *successor, Backend *backend, LivetimeAnalysisPass *LA) {
849 for (Type::TypeID *p = types; *p != Type::VoidTypeID; ++p) {
850 Type::TypeID type = *p;
852 VirtualRegister vreg(type);
853 backend->get_OperandFile(OF,&vreg);
854 free_regs[type].insert(OF.begin(),OF.end());
857 BBtoLTI_Map::mapped_type <is = bb2lti_map[successor];
858 LOG2(free_regs << nl);
859 for (BBtoLTI_Map::mapped_type::iterator i = ltis.begin(), e = ltis.end(); i !=
e; ++
i) {
860 LivetimeInterval lti = *
i;
861 MachineOperand *op_pred;
863 if (lti.front().start.get_iterator() == successor->mi_first()) {
866 std::size_t
index = successor->get_predecessor_index(predecessor);
867 MachineOperand *op = phi->get(index).op;
868 op_pred = LA->get(op).get_operand(predecessor->mi_last());
870 op_pred = lti.get_operand(predecessor->mi_last());
872 MachineOperand *op_succ = lti.get_operand(successor->mi_first());
876 LOG2(
"calc_free_regs: " << op_pred <<
" -> " << op_succ << nl);
877 free_regs_remove_op(free_regs,op_succ);
878 free_regs_remove_op(free_regs,op_pred);
882 #if defined(ENABLE_LOGGING)
883 inline OStream&
operator<<(OStream &OS,
const Move &move) {
884 return OS <<
"move from " << *move.from <<
" to " << *move.to;
888 inline bool is_stack2stack_move(Move* move) {
889 return (move->from->is_ManagedStackSlot() || move->from->is_StackSlot() ) &&
890 (move->to->is_ManagedStackSlot() || move->to->is_StackSlot());
893 bool compare_moves(Move *lhs, Move *rhs) {
901 class MoveScheduler {
903 alloc::list<MachineInstruction*>::type &
scheduled;
905 alloc::list<Move*>::type &queue;
907 alloc::list<Move*>::type &
stack;
912 alloc::list<Move*>::type &queue, Backend *backend, alloc::list<Move*>::type &
stack,
914 :
scheduled(scheduled), move_map(move_map), queue(queue), backend(backend),
stack(stack),
915 free_regs(free_regs) {}
918 Move* node = stack.back();
919 assert(!node->from->aquivalent(*node->to));
920 LOG2(
"schedule pre: " << *node << nl);
922 if (node->is_scheduled()) {
926 if (is_stack2stack_move(node)){
927 LOG2(
"Stack to stack move detected!" << nl);
928 MachineOperand *
tmp = get_and_remove_free_regs(free_regs,node->to->get_type());
931 Type::TypeID type = node->from->get_type();
933 MachineOperand *tmp_stack = backend->get_JITData()->
934 get_StackSlotManager()->create_ManagedStackSlot(type);
937 backend->get_OperandFile(OF,tmp_stack);
938 MachineOperand *tmp_reg = OF.front();
940 scheduled.push_back(backend->create_Move(tmp_reg,tmp_stack));
942 scheduled.push_back(backend->create_Move(node->from,tmp_reg));
943 scheduled.push_back(backend->create_Move(tmp_reg,node->to));
945 scheduled.push_back(backend->create_Move(tmp_stack,tmp_reg));
947 LOG2(
"schedule post: " << *node << nl);
949 node->scheduled =
true;
953 move_map.push_back(Move(tmp, node->to));
954 queue.push_back(&move_map.back());
959 else if (node->dep && !node->dep->is_scheduled()) {
960 alloc::list<Move*>::type::iterator i = std::find(stack.begin(),stack.end(),node->dep);
961 if (i != stack.end()) {
962 LOG2(
"cycle detected!" << nl);
964 MachineOperand *
tmp = get_and_remove_free_regs(free_regs,node->to->get_type());
967 assert(!node->from->is_StackSlot());
968 assert(!node->to->is_StackSlot());
969 tmp = get_stackslot(backend,node->to->get_type());
972 move_map.push_back(Move(tmp, node->to));
973 Move *tmp_move = &move_map.back();
975 queue.push_back(tmp_move);
979 stack.push_back(node->dep);
983 LOG2(
"schedule post: " << *node << nl);
985 scheduled.push_back(backend->create_Move(node->from,node->to));
986 node->scheduled =
true;
990 template <
class OutputIterator>
991 struct RefToPointerInserterImpl:
public std::unary_function<Move&,void> {
994 RefToPointerInserterImpl(OutputIterator i) :
i(i) {}
996 void operator()(Move& move) {
1001 template <
class OutputIterator>
1002 inline RefToPointerInserterImpl<OutputIterator> RefToPointerInserter(OutputIterator i) {
1003 return RefToPointerInserterImpl<OutputIterator>(
i);
1006 inline LivetimeInterval& find_or_insert(
1007 LivetimeAnalysisPass::LivetimeIntervalMapTy &
lti_map, MachineOperand* op) {
1008 LivetimeAnalysisPass::LivetimeIntervalMapTy::iterator i = lti_map.find(op);
1009 if (i == lti_map.end()) {
1010 LivetimeInterval lti(op);
1011 i = lti_map.insert(std::make_pair(op,lti)).first;
1018 class ProcessOutOperands :
public std::unary_function<MachineOperandDesc,void> {
1020 LivetimeAnalysisPass::LivetimeIntervalMapTy &
lti_map;
1025 ProcessOutOperands(LivetimeAnalysisPass::LivetimeIntervalMapTy <i_map,
1026 MIIterator i, MIIterator e)
1028 void operator()(MachineOperandDesc &op) {
1029 if (op.op->is_virtual()) {
1030 find_or_insert(lti_map,op.op).set_from(UseDef(UseDef::Def,i,&op), UseDef(UseDef::PseudoDef,e));
1037 class ProcessInOperands :
public std::unary_function<MachineOperandDesc,void> {
1039 LivetimeAnalysisPass::LivetimeIntervalMapTy &
lti_map;
1044 ProcessInOperands(LivetimeAnalysisPass::LivetimeIntervalMapTy <i_map,
1045 MIIterator first, MIIterator current) :
lti_map(lti_map), first(first),
1047 void operator()(MachineOperandDesc &op) {
1048 if (op.op->is_virtual()) {
1049 find_or_insert(lti_map,op.op).add_range(UseDef(UseDef::PseudoUse,first),
1050 UseDef(UseDef::Use,current,&op));
1055 class ForEachCfgEdge :
public std::binary_function<MachineBasicBlock*,MachineBasicBlock*,void> {
1059 LivetimeAnalysisPass *LA;
1064 : bb2lti_map(bb2lti_map), edge_move_map(edge_move_map), LA(LA) {}
1066 void operator()(MachineBasicBlock *predecessor, MachineBasicBlock *successor)
const {
1067 MoveMapTy &move_map = edge_move_map[
Edge(predecessor,successor)];
1068 LOG2(
Cyan <<
"edge " << *predecessor <<
" -> " << *successor << nl);
1069 BBtoLTI_Map::mapped_type <i_live_set = bb2lti_map[successor];
1071 std::for_each(lti_live_set.begin(), lti_live_set.end(),
1072 ForEachLiveiterval(predecessor,successor, LA, move_map));
1081 bool LinearScanAllocatorPass::order_and_insert_move(EdgeMoveMapTy::value_type &entry,
BBtoLTI_Map &bb2lti_map) {
1086 LOG2(
"order_and_insert_move: " << *predecessor <<
" -> " << *successor << nl);
1089 calc_free_regs(free_regs,bb2lti_map,predecessor,successor,backend, LA);
1090 LOG2(free_regs << nl);
1092 if (move_map.empty())
return true;
1097 for (MoveMapTy::iterator i = move_map.begin(), e = move_map.end(); i !=
e; ++
i) {
1098 LOG2(
"need move from " << i->from <<
" to " << i->to << nl);
1099 read_from[i->from] = &*
i;
1102 for (MoveMapTy::iterator i = move_map.begin(), e = move_map.end(); i !=
e; ++
i) {
1103 i->dep = read_from[i->to];
1109 std::for_each(move_map.begin(), move_map.end(), RefToPointerInserter(std::back_inserter(queue)));
1110 assert(move_map.size() == queue.size());
1112 MoveScheduler scheduler(scheduled, move_map, queue, backend, stack, free_regs);
1114 while (!queue.empty()) {
1116 queue.sort(compare_moves);
1117 stack.push_back(queue.front());
1121 assert(stack.empty());
1130 e = scheduled.end(); i !=
e ; ++
i) {
1133 #if defined(ENABLE_STATISTICS)
1150 assert(active.empty());
1151 assert(inactive.empty());
1152 assert(unhandled.empty());
1153 std::size_t handled_size = handled.size();
1155 for (HandledSetTy::iterator i = handled.begin(), e = handled.end();
1159 case LivetimeInterval::Active:
1160 active.push_back(lti);
1161 i = handled.erase(i);
1163 case LivetimeInterval::Inactive:
1164 inactive.push_back(lti);
1165 i = handled.erase(i);
1175 while (first != current) {
1178 ProcessOutOperands(lti_map, current, last)((*current)->get_result());
1180 std::for_each((*current)->begin(),(*current)->end(),
1181 ProcessInOperands(lti_map, current, last));
1183 for(LivetimeAnalysisPass::LivetimeIntervalMapTy::iterator i = lti_map.begin(),
1184 e = lti_map.end(); i !=
e; ++
i) {
1185 unhandled.push(i->second);
1187 handled_size += unhandled.size();
1188 allocate_unhandled();
1189 assert_msg(handled.size() == handled_size,
"handled.size(): " << handled.size() <<
" != handled_size: "
1194 bool LinearScanAllocatorPass::resolve() {
1198 std::for_each(MIS->begin(), MIS->end(), CalcBBtoLTIMap(LA,bb2lti_map));
1201 for (BBtoLTI_Map::const_iterator i = bb2lti_map.begin(), e = bb2lti_map.end(); i !=
e ; ++
i) {
1202 LOG2(
"live at: " << *i->first << nl);
1203 for (BBtoLTI_Map::mapped_type::const_iterator ii = i->second.begin(), ee = i->second.end(); ii != ee ; ++ii) {
1204 LOG2(
" " << *ii << nl);
1210 std::for_each(MIS->begin(), MIS->end(), CfgEdge(ForEachCfgEdge(bb2lti_map,edge_move_map,LA)));
1212 for (EdgeMoveMapTy::iterator i = edge_move_map.begin(), e = edge_move_map.end(); i !=
e ; ++
i) {
1213 if (!order_and_insert_move(*i,bb2lti_map)) {
1218 std::for_each(MIS->begin(), MIS->end(), std::mem_fun(&MachineBasicBlock::phi_clear));
1226 #if defined(LSRA_VERIFY)
1227 inline bool is_virtual(
const MachineOperandDesc &
op) {
1228 return op.op->is_virtual();
1233 bool LinearScanAllocatorPass::verify()
const {
1234 #if defined(LSRA_VERIFY)
1235 for(
MIIterator i = MIS->mi_begin(), e = MIS->mi_end(); i !=
e ; ++
i) {
1239 ERROR_MSG(
"Unallocated Operand!",
"Instruction " << *MI <<
" contains unallocated operands.");
1263 char LinearScanAllocatorPass::ID = 0;
const MachineOperandDesc & get(std::size_t i) const
#define STATISTICS(x)
Wrapper for statistics only code.
MIIterator get_iterator() const
Get instruction iterator.
alloc::map< Type::TypeID, alloc::set< MachineOperand *, MachineOperandComp >::type >::type FreeRegsMap
MIIterator get_edge_iterator(MachineBasicBlock *from, MachineBasicBlock *to, Backend *backend)
bool any_of(InputIt first, InputIt last, UnaryPredicate p)
LivetimeIntervalMapTy::iterator iterator
MachinePhiInst * get_phi_from_operand(MachineBasicBlock *MBB, MachineOperand *op)
alloc::map< Edge, MoveMapTy >::type EdgeMoveMapTy
A basic block of (scheduled) machine instructions.
OStream & print_container(OStream &OS, _ForwardIterator i, const _ForwardIterator &e)
MachineInstructionSchedulingPass TODO: more info.
bool operator<(const NativeMethod &first, const NativeMethod &second)
MIIterator insert_before(MIIterator pos, MachineInstruction *value)
Get an edge inserter.
State get_State(MIIterator pos) const
MachineOperandDesc & back()
LivetimeInterval split_active(MIIterator pos, UseDef *current=NULL)
Split interval at active pos.
#define ERROR_MSG(EXPR_SHORT, EXPR_LONG)
const_use_iterator use_begin() const
#define DEBUG_COND_N(VERBOSE)
alloc::map< MachineBasicBlock *, alloc::list< LivetimeInterval >::type >::type BBtoLTI_Map
alloc::map< MachineOperand *, LivetimeInterval, MachineOperandComp >::type LivetimeIntervalMapTy
MachineBasicBlock * current
std::list< T, Allocator< T > > type
virtual bool is_virtual() const
True if operand is virtual and must be assigned during register allocation.
UseDef next_usedef_after(UseDef pos, UseDef end) const
get next use def after pos (if not found return end)
Instruction::InstID tmp[]
LivetimeRange back() const
LivetimeInterval split_phi_active(MIIterator pos, MachineOperand *MO)
Split a phi input operand.
void set_operand(MachineOperand *op)
Set the current store of the interval.
LivetimeRange front() const
alloc::list< PassInfo::IDTy >::type & stack
alloc::list< Move >::type MoveMapTy
This file contains the statistics framework.
Stores the interdependencies of a pass.
#define STAT_REGISTER_GROUP_VAR(type, var, init, name, description, group)
Register an statistics variable and add it to a group.
#define STAT_REGISTER_GROUP(var, name, description)
Register a statistics group.
alloc::list< MachineOperand * >::type OperandFile
const_def_iterator def_begin() const
OStream & operator<<(OStream &OS, const std::string &t)
MachineOperandDesc * get_operand() const
Get operand descriptor.
bool aquivalent(const MachineOperand &MO) const
MachineOperand * get_init_operand() const
Get the initial operand.
#define LOG(STMT)
Analogous to DEBUG.
virtual bool is_move() const
Proxy to encode explicit and implicit successors.
UseDef next_intersection(const LivetimeInterval &a, const LivetimeInterval &b, UseDef pos, UseDef end)
STAT_REGISTER_GROUP_VAR_EXTERN(int, size_classinfo, 0,"size classinfo","classinfo", info_struct_stat) STAT_REGISTER_GROUP_VAR(int
Type::TypeID get_type() const
static PassRegistry< LinearScanAllocatorPass > X("LinearScanAllocatorPass")
LivetimeIntervalMapTy & lti_map
jmethodID jint const void jint const jvmtiAddrLocationMap * map
Operands that can be directly used by the machine (register, memory, stackslot)
void add_destroys()
PassName will be invalidated.
const_use_iterator use_end() const
alloc::deque< PassInfo::IDTy >::type & unhandled
const MachineOperandDesc & get_result() const
alloc::set< Instruction * >::type & scheduled
const_def_iterator def_end() const
MachineOperandDesc & front()
MachineOperand * get_operand() const
Get the current store of the interval.
bool is_ManagedStackSlot() const
#define assert_msg(COND, EXPR)
MachineOperand * get_hint() const
Get the hint for the interval.
OStream & print_ptr_container(OStream &OS, _ForwardIterator i, const _ForwardIterator &e)
bool is_def() const
Is a def position.
void add_modifies()
PassName will be modified.
#define ABORT_MSG(EXPR_SHORT, EXPR_LONG)
OStream & dbg()
The default destination for logging messages.
void add_requires()
PassName is required.