[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