[讨论] 请教HotSpot C2寄存器分配中OptoReg的意义
LeafInWind
2014-08-13
看HotSpot C2寄存器分配,一直没有搞清楚OptoReg的意义,为什么不能直接使用VMReg,为什么OptoReg的0号对应R10,2号对应R11,...。ad文件中有一段描述,大致意思是要把优先分配的寄存器定义为小序号的OptoReg,又说NS的优先级高于SOC,SOC又高于SOE,...。这段完全没有搞懂,不知有谁能解答一下。谢谢!
|
|
RednaxelaFX
2014-08-14
LeafInWind 写道 呼唤R神
![]() 别急…最近有点事情,上网时间极其不固定 ![]() sparc.ad文件里有这么一段注释: // ---------------------------- // Specify the enum values for the registers. These enums are only used by the // OptoReg "class". We can convert these enum values at will to VMReg when needed // for visibility to the rest of the vm. The order of this enum influences the // register allocator so having the freedom to set this order and not be stuck // with the order that is natural for the rest of the vm is worth it. 我觉得这个已经足以解释为什么要在VMReg之外单独弄一个类型了。 HotSpot VM的runtime部分(包括具体的汇编器)能认识的表示寄存器的类型是VMReg。而OptoReg是C2专用的。两者之间可以相互转换。HotSpot VM有传统倾向于把JIT编译器和VM的其它部分尽可能分离开。所以编译器与VM之间的“接触面”很可能会有些看似重复的、或者是包装用的数据类型。几乎整个ci都是这个用途。OptoReg算是个例外,在ci之外但也是作为这种“隔离”用途的。这样编译器就有更大的自由去做各种不同的决定,最终要跟VM交互的时候再转换为VM能认识的类型。 LeafInWind 写道 又说NS的优先级高于SOC,SOC又高于SOE,...。这段完全没有搞懂
至于这段…楼主没搞懂的是那些缩写么? NS:no save SOC:save-on-call SOE:save-on-entry 其实换种更通用的说法就是: NS:scratch register SOC:caller-save register SOE:callee-save register 这样明白了? |
|
LeafInWind
2014-08-14
ad文件中定义的某些寄存器,例如
// General Registers // "reg_def" name ( register save type, C convention save type, // ideal register type, encoding ); reg_def RBX (SOC, SOE, Op_RegI, 3, rbx->as_VMReg()); 为什么register save type和C convention save type不一致,请问C2在分配RBX时到底是将它当做SOC还是SOE来使用的? 另外,Matcher类中部分变量,如_old_SP,_in_arg_limit,_new_SP,_out_arg_limit,都是OptoReg::Name类型,请问OptoReg的意义是否是为了能以某种方式一致的处理C2编译栈帧,就像VMReg使得物理寄存器和栈位置可以被统一处理一样。 最后,能否请R神解释一下下面这个函数的逻辑 int PhaseRegAlloc::reg2offset_unchecked( OptoReg::Name reg ) const { // Slots below _max_in_arg_stack_reg are offset by the entire frame. // Slots above _max_in_arg_stack_reg are frame_slots and are not offset. int slot = (reg < _matcher._new_SP) ? reg - OptoReg::stack0() + _framesize : reg - _matcher._new_SP; // Note: We use the direct formula (reg - SharedInfo::stack0) instead of // OptoReg::reg2stack(reg), in order to avoid asserts in the latter // function. This routine must remain unchecked, so that dump_frame() // can do its work undisturbed. // %%% not really clear why reg2stack would assert here return slot*VMRegImpl::stack_slot_size; } |
|
LeafInWind
2014-08-22
自己回答一下的,请大家指教!
在ad文件中,关于C2栈帧,有如下一段注释 代码清单1 //----------FRAME----------------------------------------------- // Definition of frame structure and management information. // // S T A C K L A Y O U T Allocators stack-slot number // | (to get allocators register number // G Owned by | | v add OptoReg::stack0()) // r CALLER | | // o | +--------+ pad to even-align allocators stack-slot // w V | pad0 | numbers; owned by CALLER // t -----------+--------+----> Matcher::_in_arg_limit, unaligned // h ^ | in | 5 // | | args | 4 Holes in incoming args owned by SELF // | | | | 3 // | | +--------+ // V | | old out| Empty on Intel, window on Sparc // | old |preserve| Must be even aligned. // | SP-+--------+----> Matcher::_old_SP, even aligned // | | in | 3 area for Intel ret address // Owned by |preserve| Empty on Sparc. // SELF +--------+ // | | pad2 | 2 pad to align old SP // | +--------+ 1 // | | locks | 0 // | +--------+----> OptoReg::stack0(), even aligned // | | pad1 | 11 pad to align new SP // | +--------+ // | | | 10 // | | spills | 9 spills // V | | 8 (pad0 slot for callee) // -----------+--------+----> Matcher::_out_arg_limit, unaligned // ^ | out | 7 // | | args | 6 Holes in outgoing args owned by CALLEE // Owned by +--------+ // CALLEE | new out| 6 Empty on Intel, window on Sparc // | new |preserve| Must be even-aligned. // | SP-+--------+----> Matcher::_new_SP, even aligned // | | | // 但这个栈帧并不是C2编译器在进行寄存器分配时看到的栈帧,在reg allocator眼中的基于OptoReg值的栈帧我认为如下代码清单2所示: 代码清单2 // | | // --- +--------+----> // ^ | pad1 | // | +--------+ // | | | // f | spills | // r | | // a +--------+----> Matcher::_out_arg_limit, unaligned // m | | // e | out | // | | // s | args | // z | | // | +--------+ // | | new out| // V |preserve| // ---+--------+----> Matcher::_new_SP, even aligned // | pad0 | // +--------+----> Matcher::_in_arg_limit, unaligned // | in | // | args | // | | // +--------+ // | old out| // |preserve| // +--------+----> Matcher::_old_SP, even aligned // | in | // |preserve| // +--------+ // | pad2 | // +--------+ // | locks | // +--------+----> OptoReg::stack0(), even aligned 其中_framesize在寄存器分配之初并没有实际值,只有到所有寄存器都已确定,才通过如下代码计算得到。 if( _max_reg <= _matcher._new_SP ) _framesize = C->out_preserve_stack_slots(); else _framesize = _max_reg -_matcher._new_SP; _framesize = round_to(_framesize, Matcher::stack_alignment_in_slots()); 其中_max_reg -_matcher._new_SP就是_new_SP之上的那段空间,实际代表的是当前方法需要的spill slots数目加上最大的out args slots数目。因此reg2offset_unchecked函数的逻辑如上一层楼,将一个OptoReg值转换为当前栈帧中相对SP的偏移。 至于reg allocator为什么要把栈帧看做代码清单2的样子,还没有想清楚!!?? |
|
LeafInWind
2014-08-22
关于NS,SOC和SOE的分配次序,我认为是因为NS不用保存,因此分配它没有任何代价,应该优先分配;而SOC通常用于分配给短命的值(见engineering a compiler P310),因此分配它的代价较小,故次优先分配;而SOE通常用于分配给长命的值,因此不到最后不使用它。
|