[Vm-dev] Abstract & concrete registers

Eliot Miranda eliot.miranda at gmail.com
Thu Dec 10 16:14:46 UTC 2015


Hi Henrik,

On Mon, Dec 7, 2015 at 2:07 AM, Henrik Johansen <
henrik.s.johansen at veloxit.no> wrote:

>
> Will the permutations/call chains you end up having to change if
> explicitly splitting the cases
>
> someMethod
> someMethodUsingReg:
>
> genTrampoline:reg:reg
> genTrampoline:const:const:
>
> be too many?
> At least AFAICT, the cases where consts are actually used in trampoline
> generation is rather limited, and all have types determined by the caller
> directly, not somewhere far up the call chain...
>

oh the wheels of my brain turn so slowly and creakily.  One can always use
the same hack for constants.  If registers are in the range 0-N and
constants need to be in the range 0-M, then constants can be passed by
mapping 0-M onto -1 to -(M+1).  So it's a non-issue.  Doh!


> Cheers,
> Henry
>
> On 06 Dec 2015, at 9:02 , Eliot Miranda <eliot.miranda at gmail.com> wrote:
>
> Hi Clément,
>
>     you're thinking at the higher level of doing good register allocation,
> and I agree with you that that's all about basic block size.  In normal
> Malltalk code there are too many sends for us to be able to allocate lots
> of registers.  But in Sista code there will be much more opportunity.  But
> I m thinking about a much smaller issue that will make writing the better
> register allocation code for Sista easier.  What I'm suggesting is that we
> replace
>
> CogIA32Compiler class initialize
>     ...
>     EAX := 0.
>     ECX := 2.
>     EDX := 3.
>     EBX := 4.
>>
> CogRTLOpcodes class>>initialize
>     ...
>     TempReg := -1.
>     ClassReg := -2.
>     ReceiverResultReg := -3.
>
> with this:
>
> CogIA32Compiler class initialise
>     ...
>     TempReg := EAX := 0.
>     ClassReg := ECX := 2.
>     ReceiverResultReg := EDX := 3.
>     EBX := 4.
>>
> So now all the nonsense with converting between the abstract register
> vales and concrete register values disappears.  [Clément and just talked on
> Skype].  There are at least two issues.  One is that 0 = nil in C and so
> anywhere that uses nil to say "no register" won't work.  But the bigger
> issue is as you point out the code for generating calls from trampolines
> where non-negative values are interpreted as constants and negative values
> as abstract registers.  This will have to change and each parameter will
> have to become two, one the value and one a flag saying whether the value
> is a register or a constant.  e.g. this
>
> genTrampolineFor: aRoutine called: aString arg: regOrConst0 arg:
> regOrConst1
> "Generate a trampoline with two arguments.
> Hack: a negative value indicates an abstract register, a non-negative
> value indicates a constant."
> <var: #aRoutine type: #'void *'>
> <var: #aString type: #'char *'>
> ^self
> genTrampolineFor: aRoutine
> called: aString
> numArgs: 2
> arg: regOrConst0
> arg: regOrConst1
> arg: nil
> arg: nil
> saveRegs: false
> pushLinkReg: true
> resultReg: nil
> appendOpcodes: false
>
> needs to change to
>
> genTrampolineFor: aRoutine called: aString reg: reg0 reg: reg1
> "Generate a trampoline with two register arguments."
> <var: #aRoutine type: #'void *'>
> <var: #aString type: #'char *'>
> ^self
> genTrampolineFor: aRoutine
> called: aString
> numArgs: 2
> arg: reg0 isReg: true
> arg: reg1 isReg: true
> arg: nil isReg: nil
> arg: nil isReg: nil
> saveRegs: false
> pushLinkReg: true
> resultReg: nil
> appendOpcodes: false
>
>
> On Sun, Dec 6, 2015 at 11:26 AM, Clément Bera <bera.clement at gmail.com>
> wrote:
>
>> Hello Eliot,
>>
>> I was thinking a lot about the problem and it is not an easy one.
>>
>> I believe it's fine to let a fixed number of registers with a direct
>> mapping from abstract register to concrete register so they can be used for
>> calling convention (smalltalk sends & trampolines). The registers directly
>> mapped are Arg1Reg Arg0Reg ReceiverResultReg TempReg ClassReg
>> SendNumArgsReg FPReg SPReg, and maybe LinkReg and PCReg.
>>
>> I think the main issue is how to use efficiently the extra registers. For
>> that I started to build some fancier register allocation. Typically, you
>> can do:
>>
>> allocateRegNotConflictingWith: regMask
>> "This answers a free register not conflicting with the mask. If a free
>> reg is available, answers it, else scan the sim stack and find the cheapest
>> register to free, free it, answer it."
>>
>> allocateRegForStackEntryAt: index notConflictingWith: regMask
>> "Same think but allocates the register for a simStack entry, index 0 for
>> stack top, if sim stack entry is already in a reg answers the reg."
>>
>> The implementation uses this method that should be overriden in
>> subclasses of AbstractInstruction:
>> availableRegisterOrNilFor: liveRegsMask
>>
>> For example, in x64, assuming you have in ExtraRegs a list of registers
>> from R8 to R15, you could have:
>> availableRegisterOrNilFor: liveRegsMask
>>     1 to: NumExtraRegs do: [:i |
>>          (cogit register: (ExtraRegs at: i) isInMask: liveRegsMask)
>> ifFalse:
>> [^ExtraRegs at: i] ]
>>     ^ super availableRegisterOrNilFor: liveRegsMask
>>
>> so the register allocation would look up the extra registers before the
>> named ones when possible.
>>
>> The main problem then consists in using much more the register allocation
>> API instead of just picking named registers, as I tried to do with stores
>> (for example in genStorePop:RemoteTemp:At:). This is not possible currently
>> because of the calling convention (smalltalk sends and trampolines) which
>> require specific registers at specific places. I believe the smalltalk
>> sends convention should not be changed. However, trampolines that are
>> rarely called but frequent on machine code could be rewritten to pass
>> arguments on stack instead of by registers to be able to use much more
>> register allocation (mustBeBool, contextInstVar, remember,
>> scheduleScavenge, etc.). Another issue is to be able to save register state
>> register state across branches.
>>
>> I am just a bit confused by how to handle correctly VarBaseReg.
>>
>> Maybe we could talk on skype Eliot.
>>
>>
>>
>>
>> 2015-12-06 19:17 GMT+01:00 Eliot Miranda <eliot.miranda at gmail.com>:
>>
>>> Hi All,
>>>
>>>     when I started the Cogit I made the decision to have the notion of
>>> abstract registers (ReceiverResultReg, ClassReg, Arg0Reg et al) separate
>>> from concrete registers (EAX et al on x86, etc).  I used negative indices
>>> for abstract and non-negative indices for concrete.  But this means the
>>> back end has to map from one to the other and with much better register
>>> allocation being a priority for Clément and I to deliver in April next year
>>> I'm thinking that this was a mistake.  After all, the important things are
>>> the names, and the relevant back end can simply initialize the abstract
>>> registers with the concrete induces and then the napping could go away.
>>>
>>> The only issue I see is that in some circumstances nil is passed to a
>>> method expecting an optional abstract register, but nil maps to 0 in C and
>>> so would be confused for e.g. EAX, which has the value 0.  For this I guess
>>> we could use -1, named e.g. NoRegister.
>>>
>>> Before doing this I thought I'd ask y'all to think about the
>>> implications and see if we think it makes sense collectively.  So over the
>>> next few weeks, in working with the code, consider the issue, and I'll
>>> prompt you to state your conclusions then.
>>>
>>> _,,,^..^,,,_ (phone)
>>
>>
>>
>
>
> --
> _,,,^..^,,,_
> best, Eliot
>
>
>
>


-- 
_,,,^..^,,,_
best, Eliot
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/vm-dev/attachments/20151210/38665001/attachment.htm


More information about the Vm-dev mailing list