[Vm-dev] VM Maker: VMMaker.oscog-eem.2018.mcz
commits at source.squeak.org
commits at source.squeak.org
Thu Dec 1 18:48:21 UTC 2016
Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-eem.2018.mcz
==================== Summary ====================
Name: VMMaker.oscog-eem.2018
Author: eem
Time: 1 December 2016, 10:47:33.781504 am
UUID: 2ca1b9f3-8f95-4dc0-9111-acfd6f7fe95f
Ancestors: VMMaker.oscog-EstebanLorenzano.2017
RegisterAllocatingCogit:
Reimplement mergeCurrentSimStackWith: to use a better algorithm. Implement all but the register sort/swap code.
Esteban, amen!
=============== Diff against VMMaker.oscog-EstebanLorenzano.2017 ===============
Item was added:
+ ----- Method: RegisterAllocatingCogit>>assignToTempRegConflictingRegisterIn: (in category 'bytecode generator support') -----
+ assignToTempRegConflictingRegisterIn: conflictingRegisterMask
+ "Find the stackEntry in simStack whose liveRegister matches conflictingRegisterMask
+ and assign it to TempReg."
+ self assert: (self isAPowerOfTwo: conflictingRegisterMask).
+ 0 to: simStackPtr do:
+ [:i|
+ (self simStackAt: i) registerMaskOrNone = conflictingRegisterMask ifTrue:
+ [(self simStackAt: i)
+ storeToReg: TempReg;
+ liveRegister: TempReg.
+ ^self]].
+ self error: 'conflict entry not found'!
Item was added:
+ ----- Method: RegisterAllocatingCogit>>conflcitsResolvedBetweenSimStackAnd: (in category 'bytecode generator support') -----
+ conflcitsResolvedBetweenSimStackAnd: mergeSimStack
+ "There are no register conflicts between simStack and mergeSimStack if
+ traversing both stacks from hot end (simStackPtr) to cold end (0) no register
+ exists in simStack that has previously existed in mergeSimStack. This is because
+ the resolution assigns values from simStack to registers in mergeSimStack and so
+ must not assign to a register yet to be read."
+ | regsWrittenToMask |
+ regsWrittenToMask := 0.
+ simStackPtr to: 0 by: -1 do:
+ [:i| | mergeMask currentMask |
+ mergeMask := (self simStack: mergeSimStack at: i) registerMaskOrNone.
+ currentMask := (self simStack: simStack at: i) registerMaskOrNone.
+ mergeMask ~= currentMask ifTrue:
+ [(currentMask anyMask: regsWrittenToMask) ifTrue:
+ [^false]].
+ regsWrittenToMask := regsWrittenToMask bitOr: mergeMask].
+ ^true!
Item was added:
+ ----- Method: RegisterAllocatingCogit>>isAPowerOfTwo: (in category 'bytecode generator support') -----
+ isAPowerOfTwo: anInteger
+ <inline: true>
+ ^(anInteger bitAnd: anInteger - 1) = 0!
Item was removed:
- ----- Method: RegisterAllocatingCogit>>liveRegistersExceptingTopNItems: (in category 'simulation stack') -----
- liveRegistersExceptingTopNItems: n
- | regsSet |
- regsSet := 0.
- 0 to: simStackPtr - n do:
- [:i|
- regsSet := regsSet bitOr: (self simStackAt: i) registerMask].
- LowcodeVM ifTrue:
- [(simNativeSpillBase max: 0) to: simNativeStackPtr - n do:
- [:i|
- regsSet := regsSet bitOr: (self simNativeStackAt: i) nativeRegisterMask]].
- ^regsSet!
Item was added:
+ ----- Method: RegisterAllocatingCogit>>liveRegistersExceptingTopNItems:in: (in category 'simulation stack') -----
+ liveRegistersExceptingTopNItems: n in: aSimStack
+ <var: 'aSimStack' type: #'SimStackEntry *'>
+ | regsSet |
+ regsSet := 0.
+ 0 to: simStackPtr - n do:
+ [:i|
+ regsSet := regsSet bitOr: (self simStack: aSimStack at: i) registerMask].
+ LowcodeVM ifTrue:
+ [self shouldBeImplemented.
+ (simNativeSpillBase max: 0) to: simNativeStackPtr - n do:
+ [:i|
+ regsSet := regsSet bitOr: (self simNativeStackAt: i) nativeRegisterMask]].
+ ^regsSet!
Item was changed:
----- Method: RegisterAllocatingCogit>>mergeCurrentSimStackWith: (in category 'bytecode generator support') -----
mergeCurrentSimStackWith: mergeSimStack
<var: #mergeSimStack type: #'SimStackEntry *'>
+ "At a merge point the cogit expects the stack to be in the same state as mergeSimStack.
+ mergeSimStack is the state as of some jump forward to this point. So make simStack agree
+ with mergeSimStack (it is, um, problematic to plant code at the jump).
+ Values may have to be assigned to registers. Registers may have to be swapped.
+ The state of optStatus must agree."
+ | currentRegsMask mergeRegsMask potentialConflictRegMask conflictingRegsMask
+ currentRegMask mergeRegMask currentEntry targetEntry |
+ <var: #currentEntry type: #'SimStackEntry *'>
+ <var: #targetEntry type: #'SimStackEntry *'>
+ mergeSimStack ifNil: [^self].
+ currentRegsMask := mergeRegsMask := potentialConflictRegMask := 0.
+ 0 to: simStackPtr do:
- <var: #currentSSEntry type: #'SimStackEntry *'>
- <var: #expectedSSEntry type: #'SimStackEntry *'>
- "At merge point the cogit expects the stack to be in the same state as mergeSimStack.
- The logic is very naive, we align the existing state from the current stack to the merge stack
- from simStackPtr to methodOrBlockNumTemps, and if a conflict happen, we flush what remains
- to be merged."
- self flag: #TODO. "we could have a better algorithm with the current set of live registers to avoid flushing"
- simStackPtr to: methodOrBlockNumTemps by: -1 do:
[:i|
+ currentRegMask := (currentEntry := self simStack: simStack at: i) registerMaskOrNone.
+ mergeRegMask := (targetEntry := self simStack: mergeSimStack at: i) registerMaskOrNone.
+ currentRegMask = mergeRegMask
+ ifTrue:
+ [self assert: (currentEntry isSameEntryAs: targetEntry)]
+ ifFalse: "This checks for a potential conflict..."
+ [(currentRegMask ~= 0 or: [mergeRegMask ~= 0]) ifTrue:
+ [potentialConflictRegMask := potentialConflictRegMask bitOr: (currentRegMask bitOr: mergeRegMask)]].
+ currentRegsMask := currentRegsMask bitOr: currentRegMask.
+ mergeRegsMask := mergeRegsMask bitOr: mergeRegMask].
+ conflictingRegsMask := potentialConflictRegMask bitAnd: (currentRegsMask bitAnd: mergeRegsMask).
+ "One simple algorithm is to spill everything if there are any conflicts and then pop back.
+ But this is terrible :-( Can we do better? Yes... Consider the following two simStacks
+ target: 0: | rA | __ | rB | rC | rD | <- sp
+ current: 0: | __ | __ | rD | rA | rC | <- sp
+ If we were to assign in a naive order, 0 through sp rA would be overwritten before its value in current[3] is written to rC,
+ and rC would be overwritten before its value in current[4] is written to rD. But if we swap the registers in current so that
+ they respect the reverse ordering in target we can assign directly:
+ swap current[3] & current[4]
+ 0: | __ | __ | rD | rC | rA | <- sp
+ now do the assignment in the order target[0] := current[0], target[1] := current[1], ... target[4] := current[4],
+ i.e. rA := current[0]; rB := rD; (rC := rC); (rD := rD)."
+ conflictingRegsMask ~= 0 ifTrue:
+ [(self isAPowerOfTwo: conflictingRegsMask) "Multiple conflicts mean we have to sort"
+ ifFalse: [self swapCurrentRegistersInMask: currentRegsMask accordingToRegisterOrderIn: mergeSimStack]
+ ifTrue: [self assignToTempRegConflictingRegisterIn: conflictingRegsMask]].
+ self assert: (self conflcitsResolvedBetweenSimStackAnd: mergeSimStack).
+ simStackPtr to: 0 by: -1 do:
+ [:i|
+ currentRegMask := (currentEntry := self simStack: simStack at: i) registerMaskOrNone.
+ mergeRegMask := (targetEntry := self simStack: mergeSimStack at: i) registerMaskOrNone.
+ mergeRegMask ~= 0
+ ifTrue:
+ [currentRegMask ~= mergeRegMask
+ ifTrue:
+ [currentEntry reconcilePoppingWith: targetEntry.
+ simStack
+ at: i
+ put: (self
+ cCode: [mergeSimStack at: i]
+ inSmalltalk: [(mergeSimStack at: i) copy])]
+ ifFalse:
+ [self assert: (currentEntry isSameEntryAs: targetEntry)]]
+ ifFalse:
+ [self assert: (currentRegMask = 0 or: [currentEntry spilled]).
+ self assert: (currentEntry isSameEntryAs: targetEntry) "really? here to check"]]!
- | currentSSEntry expectedSSEntry |
- currentSSEntry := self simStackAt: i.
- expectedSSEntry := self simStack: mergeSimStack at: i.
- expectedSSEntry type
- caseOf: {
- [SSBaseOffset] -> [ self assert: (expectedSSEntry register = ReceiverResultReg or: [ expectedSSEntry register = FPReg ]).
- (expectedSSEntry register = ReceiverResultReg and: [needsFrame]) ifTrue:
- [optStatus isReceiverResultRegLive ifFalse:
- [self ssFlushFrom: i - 1 upThroughRegister: ReceiverResultReg.
- self putSelfInReceiverResultReg ].
- optStatus isReceiverResultRegLive: true]. ].
- [SSSpill] -> [currentSSEntry ensureSpilledAt: (self frameOffsetOfTemporary: i) from: FPReg].
- [SSConstant] -> [self assert: expectedSSEntry liveRegister notNil.
- currentSSEntry storeToReg: expectedSSEntry liveRegister ].
- [SSRegister] -> [(currentSSEntry type = SSRegister and: [currentSSEntry register = expectedSSEntry register])
- ifFalse:
- [ self ssFlushFrom: i - 1 upThroughRegister: expectedSSEntry register.
- currentSSEntry storeToReg: expectedSSEntry register ] ]}.
- ]!
Item was changed:
----- Method: RegisterAllocatingCogit>>ssStorePop:toPreferredReg: (in category 'simulation stack') -----
ssStorePop: popBoolean toPreferredReg: preferredReg
"Store or pop the top simulated stack entry to a register.
Use preferredReg if the entry is not itself a register.
Answer the actual register the result ends up in."
| actualReg liveRegisters |
actualReg := preferredReg.
self ssTop type = SSRegister ifTrue:
[self assert: (self ssTop liveRegister = NoReg
or: [self ssTop liveRegister = self ssTop register]).
self assert: self ssTop spilled not.
actualReg := self ssTop register].
self ssTop liveRegister ~= NoReg ifTrue:
[actualReg := self ssTop liveRegister].
+ liveRegisters := self liveRegistersExceptingTopNItems: 1 in: simStack.
- liveRegisters := self liveRegistersExceptingTopNItems: 1.
(self register: actualReg isInMask: liveRegisters) ifTrue:
[actualReg := self allocateRegNotConflictingWith: (self registerMaskFor: preferredReg).
actualReg = NoReg ifTrue:
[actualReg := preferredReg]].
self deny: (self register: actualReg isInMask: liveRegisters).
self ssStorePop: popBoolean toReg: actualReg. "generates nothing if ssTop is already in actualReg"
^actualReg!
Item was added:
+ ----- Method: StackToRegisterMappingCogit>>printSimStack: (in category 'simulation only') -----
+ printSimStack: aSimStack
+ <doNotGenerate>
+ self printSimStack: aSimStack toDepth: simStackPtr spillBase: simSpillBase on: coInterpreter transcript!
More information about the Vm-dev
mailing list