[Vm-dev] VM Maker: VMMaker.oscog-eem.2099.mcz
commits at source.squeak.org
commits at source.squeak.org
Tue Jan 17 18:04:21 UTC 2017
Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-eem.2099.mcz
==================== Summary ====================
Name: VMMaker.oscog-eem.2099
Author: eem
Time: 17 January 2017, 10:03:25.012123 am
UUID: 08323ffb-7df4-498c-a5b0-8a4e6d295352
Ancestors: VMMaker.oscog-eem.2098
StackToRegisterMappingCogits:
Clean-up after the branch following changes:
Make extractMaybeBranchDescriptorInto: fulfil its contract when it doesn't find a following branch (directly or indirectly).
Simplify the various gen*InlinedIdenticalOrNotIf: to eliminate the duplication using #== to compare orNot with the branch.
=============== Diff against VMMaker.oscog-eem.2098 ===============
Item was changed:
----- Method: RegisterAllocatingCogit>>genForwardersInlinedIdenticalOrNotIf: (in category 'bytecode generators') -----
genForwardersInlinedIdenticalOrNotIf: orNot
| nextPC branchDescriptor unforwardRcvr argReg targetBytecodePC
unforwardArg rcvrReg postBranchPC label fixup |
<var: #branchDescriptor type: #'BytecodeDescriptor *'>
<var: #label type: #'AbstractInstruction *'>
self extractMaybeBranchDescriptorInto: [ :descr :next :postBranch :target |
branchDescriptor := descr. nextPC := next. postBranchPC := postBranch. targetBytecodePC := target ].
"If an operand is an annotable constant, it may be forwarded, so we need to store it into a
register so the forwarder check can jump back to the comparison after unforwarding the constant.
However, if one of the operand is an unnanotable constant, does not allocate a register for it
(machine code will use operations on constants) and does not generate forwarder checks."
unforwardRcvr := (objectRepresentation isUnannotatableConstant: (self ssValue: 1)) not.
unforwardArg := (objectRepresentation isUnannotatableConstant: self ssTop) not.
self
allocateEqualsEqualsRegistersArgNeedsReg: unforwardArg
rcvrNeedsReg: unforwardRcvr
into: [ :rcvr :arg | rcvrReg:= rcvr. argReg := arg ].
"If not followed by a branch, resolve to true or false."
(branchDescriptor isBranchTrue or: [branchDescriptor isBranchFalse]) ifFalse:
[^ self
genIdenticalNoBranchArgIsConstant: unforwardArg not
rcvrIsConstant: unforwardRcvr not
argReg: argReg
rcvrReg: rcvrReg
orNotIf: orNot].
label := self Label.
self genCmpArgIsConstant: unforwardArg not rcvrIsConstant: unforwardRcvr not argReg: argReg rcvrReg: rcvrReg.
self ssPop: 2.
"Further since there is a following conditional jump bytecode, define
non-merge fixups and leave the cond bytecode to set the mergeness."
(self fixupAt: nextPC - initialPC) notAFixup
ifTrue: "The next instruction is dead. we can skip it."
[deadCode := true.
self ensureFixupAt: targetBytecodePC - initialPC.
self ensureFixupAt: postBranchPC - initialPC]
ifFalse:
[self deny: deadCode]. "push dummy value below"
self assert: (unforwardArg or: [unforwardRcvr]).
+ orNot == branchDescriptor isBranchTrue "orNot is true for ~~"
+ ifFalse: "branchDescriptor is branchFalse"
+ [ fixup := (self ensureNonMergeFixupAt: postBranchPC - initialPC) asUnsignedInteger.
+ self JumpZero: (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger ]
+ ifTrue:
+ [ fixup := (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger.
+ self JumpZero: (self ensureNonMergeFixupAt: postBranchPC - initialPC) asUnsignedInteger ].
- "We could use (branchDescriptor isBranchTrue xor: orNot) to simplify this."
- orNot
- ifFalse: [branchDescriptor isBranchTrue
- ifTrue:
- [ fixup := (self ensureNonMergeFixupAt: postBranchPC - initialPC) asUnsignedInteger.
- self JumpZero: (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger ]
- ifFalse: "branchDescriptor is branchFalse"
- [ fixup := (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger.
- self JumpZero: (self ensureNonMergeFixupAt: postBranchPC - initialPC) asUnsignedInteger ]]
- ifTrue: [branchDescriptor isBranchTrue
- ifFalse: "branchDescriptor is branchFalse"
- [ fixup := (self ensureNonMergeFixupAt: postBranchPC - initialPC) asUnsignedInteger.
- self JumpZero: (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger ]
- ifTrue:
- [ fixup := (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger.
- self JumpZero: (self ensureNonMergeFixupAt: postBranchPC - initialPC) asUnsignedInteger ]].
deadCode ifFalse:
[self ssPushConstant: objectMemory trueObject]. "dummy value"
"The forwarders checks need to jump back to the comparison (label) if a forwarder is found, else
jump forward either to the next forwarder check or to the postBranch or branch target (fixup)."
unforwardArg ifTrue:
[ unforwardRcvr
ifTrue: [ objectRepresentation genEnsureOopInRegNotForwarded: argReg scratchReg: TempReg jumpBackTo: label ]
ifFalse: [ objectRepresentation
genEnsureOopInRegNotForwarded: argReg
scratchReg: TempReg
ifForwarder: label
ifNotForwarder: fixup ] ].
unforwardRcvr ifTrue:
[ objectRepresentation
genEnsureOopInRegNotForwarded: rcvrReg
scratchReg: TempReg
ifForwarder: label
ifNotForwarder: fixup ].
"Not reached, execution flow have jumped to fixup"
^0!
Item was changed:
----- Method: RegisterAllocatingCogit>>genVanillaInlinedIdenticalOrNotIf: (in category 'bytecode generators') -----
genVanillaInlinedIdenticalOrNotIf: orNot
| nextPC postBranchPC targetBytecodePC branchDescriptor
rcvrReg argReg argIsConstant rcvrIsConstant |
<var: #branchDescriptor type: #'BytecodeDescriptor *'>
self extractMaybeBranchDescriptorInto: [ :descr :next :postBranch :target |
branchDescriptor := descr. nextPC := next. postBranchPC := postBranch. targetBytecodePC := target ].
argIsConstant := self ssTop type = SSConstant.
"They can't be both constants to use correct machine opcodes.
However annotable constants can't be resolved statically, hence we need to careful."
rcvrIsConstant := argIsConstant not and: [(self ssValue: 1) type = SSConstant].
self
allocateEqualsEqualsRegistersArgNeedsReg: argIsConstant not
rcvrNeedsReg: rcvrIsConstant not
into: [ :rcvr :arg | rcvrReg:= rcvr. argReg := arg ].
"If not followed by a branch, resolve to true or false."
(branchDescriptor isBranchTrue or: [branchDescriptor isBranchFalse]) ifFalse:
[^ self
genIdenticalNoBranchArgIsConstant: argIsConstant
rcvrIsConstant: rcvrIsConstant
argReg: argReg
rcvrReg: rcvrReg
orNotIf: orNot].
self genCmpArgIsConstant: argIsConstant rcvrIsConstant: rcvrIsConstant argReg: argReg rcvrReg: rcvrReg.
self ssPop: 2.
"Further since there is a following conditional jump bytecode, define
non-merge fixups and leave the cond bytecode to set the mergeness."
(self fixupAt: nextPC - initialPC) notAFixup
ifTrue: "The next instruction is dead. we can skip it."
[deadCode := true.
self ensureFixupAt: targetBytecodePC - initialPC.
self ensureFixupAt: postBranchPC - initialPC]
ifFalse:
[self deny: deadCode]. "push dummy value below"
+ self genConditionalBranch: (orNot == branchDescriptor isBranchTrue ifTrue: [JumpNonZero] ifFalse: [JumpZero])
- "We could simplify this with a xor:"
- self genConditionalBranch: (orNot
- ifFalse: [branchDescriptor isBranchTrue ifTrue: [JumpZero] ifFalse: [JumpNonZero]]
- ifTrue: [branchDescriptor isBranchTrue ifTrue: [JumpNonZero] ifFalse: [JumpZero]])
operand: (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger.
"If the branch is dead, then we can just fall through postBranchPC (only a nop in-between), else
we need to jump over the code of the branch"
deadCode ifFalse:
[self Jump: (self ensureNonMergeFixupAt: postBranchPC - initialPC).
self ssPushConstant: objectMemory trueObject]. "dummy value"
^0!
Item was changed:
----- Method: SistaCogit>>genForwardersInlinedIdenticalOrNotIf: (in category 'bytecode generators') -----
genForwardersInlinedIdenticalOrNotIf: orNot
"Override to count inlined branches if followed by a conditional branch.
We borrow the following conditional branch's counter and when about to
inline the comparison we decrement the counter (without writing it back)
and if it trips simply abort the inlining, falling back to the normal send which
will then continue to the conditional branch which will trip and enter the abort."
| nextPC postBranchPC targetBytecodePC branchDescriptor counterReg fixup jumpEqual jumpNotEqual
counterAddress countTripped unforwardArg unforwardRcvr argReg rcvrReg regMask |
<var: #fixup type: #'BytecodeFixup *'>
<var: #countTripped type: #'AbstractInstruction *'>
<var: #label type: #'AbstractInstruction *'>
<var: #branchDescriptor type: #'BytecodeDescriptor *'>
<var: #jumpEqual type: #'AbstractInstruction *'>
<var: #jumpNotEqual type: #'AbstractInstruction *'>
((coInterpreter isOptimizedMethod: methodObj) or: [needsFrame not]) ifTrue:
[^super genForwardersInlinedIdenticalOrNotIf: orNot].
regMask := 0.
self extractMaybeBranchDescriptorInto: [ :descr :next :postBranch :target |
branchDescriptor := descr. nextPC := next. postBranchPC := postBranch. targetBytecodePC := target ].
unforwardRcvr := (objectRepresentation isUnannotatableConstant: (self ssValue: 1)) not.
unforwardArg := (objectRepresentation isUnannotatableConstant: self ssTop) not.
"If an operand is an annotable constant, it may be forwarded, so we need to store it into a
register so the forwarder check can jump back to the comparison after unforwarding the constant.
However, if one of the operand is an unnanotable constant, does not allocate a register for it
(machine code will use operations on constants)."
rcvrReg:= argReg := NoReg.
self
allocateEqualsEqualsRegistersArgNeedsReg: unforwardArg
rcvrNeedsReg: unforwardRcvr
into: [ :rcvr :arg | rcvrReg:= rcvr. argReg := arg ].
argReg ~= NoReg ifTrue: [ regMask := self registerMaskFor: argReg ].
rcvrReg ~= NoReg ifTrue: [ regMask := regMask bitOr: (self registerMaskFor: rcvrReg) ].
"Only interested in inlining if followed by a conditional branch."
(branchDescriptor isBranchTrue or: [branchDescriptor isBranchFalse]) ifFalse:
[^ self
genIdenticalNoBranchArgIsConstant: unforwardArg not
rcvrIsConstant: unforwardRcvr not
argReg: argReg
rcvrReg: rcvrReg
orNotIf: orNot].
"If branching the stack must be flushed for the merge"
self ssFlushTo: simStackPtr - 2.
unforwardArg ifTrue: [ objectRepresentation genEnsureOopInRegNotForwarded: argReg scratchReg: TempReg ].
unforwardRcvr ifTrue: [ objectRepresentation genEnsureOopInRegNotForwarded: rcvrReg scratchReg: TempReg ].
counterReg := self allocateRegNotConflictingWith: regMask.
self
genExecutionCountLogicInto: [ :cAddress :countTripBranch |
counterAddress := cAddress.
countTripped := countTripBranch ]
counterReg: counterReg.
self assert: (unforwardArg or: [ unforwardRcvr ]).
self genCmpArgIsConstant: unforwardArg not rcvrIsConstant: unforwardRcvr not argReg: argReg rcvrReg: rcvrReg.
self ssPop: 2.
+ orNot == branchDescriptor isBranchTrue "orNot is true for ~~"
+ ifFalse:
+ [ fixup := (self ensureNonMergeFixupAt: postBranchPC - initialPC) asUnsignedInteger.
+ self JumpZero: (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger ]
+ ifTrue:
+ [ fixup := (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger.
+ self JumpZero: (self ensureNonMergeFixupAt: postBranchPC - initialPC) asUnsignedInteger ].
- "We could use (branchDescriptor isBranchTrue xor: orNot) to simplify this."
- orNot
- ifFalse: [branchDescriptor isBranchTrue
- ifTrue:
- [ fixup := (self ensureNonMergeFixupAt: postBranchPC - initialPC) asUnsignedInteger.
- self JumpZero: (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger ]
- ifFalse: "branchDescriptor is branchFalse"
- [ fixup := (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger.
- self JumpZero: (self ensureNonMergeFixupAt: postBranchPC - initialPC) asUnsignedInteger ]]
- ifTrue: [branchDescriptor isBranchTrue
- ifFalse: "branchDescriptor is branchFalse"
- [ fixup := (self ensureNonMergeFixupAt: postBranchPC - initialPC) asUnsignedInteger.
- self JumpZero: (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger ]
- ifTrue:
- [ fixup := (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger.
- self JumpZero: (self ensureNonMergeFixupAt: postBranchPC - initialPC) asUnsignedInteger ]].
self genFallsThroughCountLogicCounterReg: counterReg counterAddress: counterAddress.
self Jump: fixup.
countTripped jmpTarget: self Label.
"inlined version of #== ignoring the branchDescriptor if the counter trips to have normal state for the optimizer"
self ssPop: -2.
self genCmpArgIsConstant: unforwardArg not rcvrIsConstant: unforwardRcvr not argReg: argReg rcvrReg: rcvrReg.
self ssPop: 2.
"This code necessarily directly falls through the jumpIf: code which pops the top of the stack into TempReg.
We therefore directly assign the result to TempReg to save one move instruction"
jumpEqual := orNot ifFalse: [self JumpZero: 0] ifTrue: [self JumpNonZero: 0].
self genMoveFalseR: TempReg.
jumpNotEqual := self Jump: 0.
jumpEqual jmpTarget: (self genMoveTrueR: TempReg).
jumpNotEqual jmpTarget: self Label.
self ssPushRegister: TempReg.
(self fixupAt: nextPC - initialPC) notAFixup ifTrue: [ branchReachedOnlyForCounterTrip := true ].
^ 0!
Item was changed:
----- Method: SistaRegisterAllocatingCogit>>genForwardersInlinedIdenticalOrNotIf: (in category 'bytecode generators') -----
genForwardersInlinedIdenticalOrNotIf: orNot
"Override to count inlined branches if followed by a conditional branch.
We borrow the following conditional branch's counter and when about to
inline the comparison we decrement the counter (without writing it back)
and if it trips simply abort the inlining, falling back to the normal send which
will then continue to the conditional branch which will trip and enter the abort."
| nextPC postBranchPC targetBytecodePC branchDescriptor counterReg fixup jumpEqual jumpNotEqual
counterAddress countTripped unforwardArg unforwardRcvr argReg rcvrReg regMask |
<var: #fixup type: #'BytecodeFixup *'>
<var: #countTripped type: #'AbstractInstruction *'>
<var: #label type: #'AbstractInstruction *'>
<var: #branchDescriptor type: #'BytecodeDescriptor *'>
<var: #jumpEqual type: #'AbstractInstruction *'>
<var: #jumpNotEqual type: #'AbstractInstruction *'>
((coInterpreter isOptimizedMethod: methodObj) or: [needsFrame not]) ifTrue:
[^super genForwardersInlinedIdenticalOrNotIf: orNot].
regMask := 0.
self extractMaybeBranchDescriptorInto: [ :descr :next :postBranch :target |
branchDescriptor := descr. nextPC := next. postBranchPC := postBranch. targetBytecodePC := target ].
unforwardRcvr := (objectRepresentation isUnannotatableConstant: (self ssValue: 1)) not.
unforwardArg := (objectRepresentation isUnannotatableConstant: self ssTop) not.
"If an operand is an annotable constant, it may be forwarded, so we need to store it into a
register so the forwarder check can jump back to the comparison after unforwarding the constant.
However, if one of the operand is an unnanotable constant, does not allocate a register for it
(machine code will use operations on constants)."
rcvrReg:= argReg := NoReg.
self
allocateEqualsEqualsRegistersArgNeedsReg: unforwardArg
rcvrNeedsReg: unforwardRcvr
into: [ :rcvr :arg | rcvrReg:= rcvr. argReg := arg ].
argReg ~= NoReg ifTrue: [ regMask := self registerMaskFor: argReg ].
rcvrReg ~= NoReg ifTrue: [ regMask := regMask bitOr: (self registerMaskFor: rcvrReg) ].
"Only interested in inlining if followed by a conditional branch."
(branchDescriptor isBranchTrue or: [branchDescriptor isBranchFalse]) ifFalse:
[^ self
genIdenticalNoBranchArgIsConstant: unforwardArg not
rcvrIsConstant: unforwardRcvr not
argReg: argReg
rcvrReg: rcvrReg
orNotIf: orNot].
unforwardArg ifTrue: [ objectRepresentation genEnsureOopInRegNotForwarded: argReg scratchReg: TempReg ].
unforwardRcvr ifTrue: [ objectRepresentation genEnsureOopInRegNotForwarded: rcvrReg scratchReg: TempReg ].
counterReg := self allocateRegNotConflictingWith: regMask.
self
genExecutionCountLogicInto: [ :cAddress :countTripBranch |
counterAddress := cAddress.
countTripped := countTripBranch ]
counterReg: counterReg.
self assert: (unforwardArg or: [ unforwardRcvr ]).
self genCmpArgIsConstant: unforwardArg not rcvrIsConstant: unforwardRcvr not argReg: argReg rcvrReg: rcvrReg.
self ssPop: 2.
+ orNot == branchDescriptor isBranchTrue "orNot is true for ~~"
+ ifFalse:
+ [ fixup := (self ensureNonMergeFixupAt: postBranchPC - initialPC) asUnsignedInteger.
+ self JumpZero: (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger ]
+ ifTrue:
+ [ fixup := (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger.
+ self JumpZero: (self ensureNonMergeFixupAt: postBranchPC - initialPC) asUnsignedInteger ].
- "We could use (branchDescriptor isBranchTrue xor: orNot) to simplify this."
- orNot
- ifFalse: [branchDescriptor isBranchTrue
- ifTrue:
- [ fixup := (self ensureNonMergeFixupAt: postBranchPC - initialPC) asUnsignedInteger.
- self JumpZero: (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger ]
- ifFalse: "branchDescriptor is branchFalse"
- [ fixup := (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger.
- self JumpZero: (self ensureNonMergeFixupAt: postBranchPC - initialPC) asUnsignedInteger ]]
- ifTrue: [branchDescriptor isBranchTrue
- ifFalse: "branchDescriptor is branchFalse"
- [ fixup := (self ensureNonMergeFixupAt: postBranchPC - initialPC) asUnsignedInteger.
- self JumpZero: (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger ]
- ifTrue:
- [ fixup := (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger.
- self JumpZero: (self ensureNonMergeFixupAt: postBranchPC - initialPC) asUnsignedInteger ]].
self genFallsThroughCountLogicCounterReg: counterReg counterAddress: counterAddress.
self Jump: fixup.
countTripped jmpTarget: self Label.
"inlined version of #== ignoring the branchDescriptor if the counter trips to have normal state for the optimizer"
self ssPop: -2.
self genCmpArgIsConstant: unforwardArg not rcvrIsConstant: unforwardRcvr not argReg: argReg rcvrReg: rcvrReg.
self ssPop: 2.
"This code necessarily directly falls through the jumpIf: code which pops the top of the stack into TempReg.
We therefore directly assign the result to TempReg to save one move instruction"
jumpEqual := orNot ifFalse: [self JumpZero: 0] ifTrue: [self JumpNonZero: 0].
self genMoveFalseR: TempReg.
jumpNotEqual := self Jump: 0.
jumpEqual jmpTarget: (self genMoveTrueR: TempReg).
jumpNotEqual jmpTarget: self Label.
self ssPushRegister: TempReg.
(self fixupAt: nextPC - initialPC) notAFixup ifTrue: [ branchReachedOnlyForCounterTrip := true ].
^ 0!
Item was changed:
----- Method: StackToRegisterMappingCogit>>extractMaybeBranchDescriptorInto: (in category 'bytecode generator support') -----
extractMaybeBranchDescriptorInto: fourArgBlock
"Looks one instruction ahead of the current bytecodePC and answers its bytecode descriptor and its pc.
+ If the instruction found is a branch, also answers the pc after the branch and the pc targeted by the branch.
+ For convenience, avoiding duplication in the senders, it follows those two pcs to their eventual targets."
- If the instruction found is a branch, also answers the pc after the branch and the pc targeted by the branch."
| primDescriptor nextPC nExts branchDescriptor targetBytecodePC postBranchPC |
<inline: true>
<var: #primDescriptor type: #'BytecodeDescriptor *'>
<var: #branchDescriptor type: #'BytecodeDescriptor *'>
primDescriptor := self generatorAt: byte0.
nextPC := bytecodePC + primDescriptor numBytes.
nExts := 0.
[[branchDescriptor := self generatorAt: (objectMemory fetchByte: nextPC ofObject: methodObj) + bytecodeSetOffset.
branchDescriptor isExtension] whileTrue:
[nExts := nExts + 1.
nextPC := nextPC + branchDescriptor numBytes].
branchDescriptor isUnconditionalBranch]
whileTrue:
[nextPC := self eventualTargetOf: nextPC
+ branchDescriptor numBytes
+ (self spanFor: branchDescriptor at: nextPC exts: nExts in: methodObj)].
targetBytecodePC := postBranchPC := 0.
(branchDescriptor isBranchTrue or: [branchDescriptor isBranchFalse])
ifTrue:
[targetBytecodePC := self eventualTargetOf: nextPC
+ branchDescriptor numBytes
+ (self spanFor: branchDescriptor at: nextPC exts: nExts in: methodObj).
postBranchPC := self eventualTargetOf: nextPC + branchDescriptor numBytes]
ifFalse:
+ [nextPC := bytecodePC + primDescriptor numBytes].
- [branchDescriptor isReturn ifFalse:
- [postBranchPC := self eventualTargetOf: nextPC + branchDescriptor numBytes.
- nextPC := self eventualTargetOf: bytecodePC + primDescriptor numBytes]].
fourArgBlock value: branchDescriptor value: nextPC value: postBranchPC value: targetBytecodePC!
Item was changed:
----- Method: StackToRegisterMappingCogit>>genForwardersInlinedIdenticalOrNotIf: (in category 'bytecode generators') -----
genForwardersInlinedIdenticalOrNotIf: orNot
| nextPC branchDescriptor unforwardRcvr argReg targetBytecodePC
unforwardArg rcvrReg postBranchPC label fixup |
<var: #branchDescriptor type: #'BytecodeDescriptor *'>
<var: #label type: #'AbstractInstruction *'>
self extractMaybeBranchDescriptorInto: [ :descr :next :postBranch :target |
branchDescriptor := descr. nextPC := next. postBranchPC := postBranch. targetBytecodePC := target ].
"If an operand is an annotable constant, it may be forwarded, so we need to store it into a
register so the forwarder check can jump back to the comparison after unforwarding the constant.
However, if one of the operand is an unnanotable constant, does not allocate a register for it
(machine code will use operations on constants) and does not generate forwarder checks."
unforwardRcvr := (objectRepresentation isUnannotatableConstant: (self ssValue: 1)) not.
unforwardArg := (objectRepresentation isUnannotatableConstant: self ssTop) not.
self
allocateEqualsEqualsRegistersArgNeedsReg: unforwardArg
rcvrNeedsReg: unforwardRcvr
into: [ :rcvr :arg | rcvrReg:= rcvr. argReg := arg ].
"If not followed by a branch, resolve to true or false."
(branchDescriptor isBranchTrue or: [branchDescriptor isBranchFalse]) ifFalse:
[^ self
genIdenticalNoBranchArgIsConstant: unforwardArg not
rcvrIsConstant: unforwardRcvr not
argReg: argReg
rcvrReg: rcvrReg
orNotIf: orNot].
"If branching the stack must be flushed for the merge"
self ssFlushTo: simStackPtr - 2.
label := self Label.
self genCmpArgIsConstant: unforwardArg not rcvrIsConstant: unforwardRcvr not argReg: argReg rcvrReg: rcvrReg.
self ssPop: 2.
"Further since there is a following conditional jump bytecode, define
non-merge fixups and leave the cond bytecode to set the mergeness."
(self fixupAt: nextPC - initialPC) notAFixup
ifTrue: "The next instruction is dead. we can skip it."
[deadCode := true.
self ensureFixupAt: targetBytecodePC - initialPC.
self ensureFixupAt: postBranchPC - initialPC]
ifFalse:
[self deny: deadCode]. "push dummy value below"
self assert: (unforwardArg or: [unforwardRcvr]).
+ orNot == branchDescriptor isBranchTrue "orNot is true for ~~"
+ ifFalse:
+ [ fixup := (self ensureNonMergeFixupAt: postBranchPC - initialPC) asUnsignedInteger.
+ self JumpZero: (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger ]
+ ifTrue:
+ [ fixup := (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger.
+ self JumpZero: (self ensureNonMergeFixupAt: postBranchPC - initialPC) asUnsignedInteger ].
- "We could use (branchDescriptor isBranchTrue xor: orNot) to simplify this."
- orNot
- ifFalse: [branchDescriptor isBranchTrue
- ifTrue:
- [ fixup := (self ensureNonMergeFixupAt: postBranchPC - initialPC) asUnsignedInteger.
- self JumpZero: (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger ]
- ifFalse: "branchDescriptor is branchFalse"
- [ fixup := (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger.
- self JumpZero: (self ensureNonMergeFixupAt: postBranchPC - initialPC) asUnsignedInteger ]]
- ifTrue: [branchDescriptor isBranchTrue
- ifFalse: "branchDescriptor is branchFalse"
- [ fixup := (self ensureNonMergeFixupAt: postBranchPC - initialPC) asUnsignedInteger.
- self JumpZero: (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger ]
- ifTrue:
- [ fixup := (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger.
- self JumpZero: (self ensureNonMergeFixupAt: postBranchPC - initialPC) asUnsignedInteger ]].
deadCode ifFalse:
[self ssPushConstant: objectMemory trueObject]. "dummy value"
"The forwarders checks need to jump back to the comparison (label) if a forwarder is found, else
jump forward either to the next forwarder check or to the postBranch or branch target (fixup)."
unforwardArg ifTrue:
[ unforwardRcvr
ifTrue: [ objectRepresentation genEnsureOopInRegNotForwarded: argReg scratchReg: TempReg jumpBackTo: label ]
ifFalse: [ objectRepresentation
genEnsureOopInRegNotForwarded: argReg
scratchReg: TempReg
ifForwarder: label
ifNotForwarder: fixup ] ].
unforwardRcvr ifTrue:
[ objectRepresentation
genEnsureOopInRegNotForwarded: rcvrReg
scratchReg: TempReg
ifForwarder: label
ifNotForwarder: fixup ].
"Not reached, execution flow have jumped to fixup"
^0!
Item was changed:
----- Method: StackToRegisterMappingCogit>>genVanillaInlinedIdenticalOrNotIf: (in category 'bytecode generators') -----
genVanillaInlinedIdenticalOrNotIf: orNot
| nextPC postBranchPC targetBytecodePC branchDescriptor
rcvrReg argReg argIsConstant rcvrIsConstant |
<var: #branchDescriptor type: #'BytecodeDescriptor *'>
self extractMaybeBranchDescriptorInto: [ :descr :next :postBranch :target |
branchDescriptor := descr. nextPC := next. postBranchPC := postBranch. targetBytecodePC := target ].
argIsConstant := self ssTop type = SSConstant.
"They can't be both constants to use correct machine opcodes.
However annotable constants can't be resolved statically, hence we need to careful."
rcvrIsConstant := argIsConstant not and: [(self ssValue: 1) type = SSConstant].
self
allocateEqualsEqualsRegistersArgNeedsReg: argIsConstant not
rcvrNeedsReg: rcvrIsConstant not
into: [ :rcvr :arg | rcvrReg:= rcvr. argReg := arg ].
"If not followed by a branch, resolve to true or false."
(branchDescriptor isBranchTrue or: [branchDescriptor isBranchFalse]) ifFalse:
[^ self
genIdenticalNoBranchArgIsConstant: argIsConstant
rcvrIsConstant: rcvrIsConstant
argReg: argReg
rcvrReg: rcvrReg
orNotIf: orNot].
"If branching the stack must be flushed for the merge"
self ssFlushTo: simStackPtr - 2.
self genCmpArgIsConstant: argIsConstant rcvrIsConstant: rcvrIsConstant argReg: argReg rcvrReg: rcvrReg.
self ssPop: 2.
"Further since there is a following conditional jump bytecode, define
non-merge fixups and leave the cond bytecode to set the mergeness."
(self fixupAt: nextPC - initialPC) notAFixup
ifTrue: "The next instruction is dead. we can skip it."
[deadCode := true.
self ensureFixupAt: targetBytecodePC - initialPC.
self ensureFixupAt: postBranchPC - initialPC]
ifFalse:
[self deny: deadCode]. "push dummy value below"
+ self genConditionalBranch: (orNot == branchDescriptor isBranchTrue ifTrue: [JumpNonZero] ifFalse: [JumpZero])
- "We could simplify this with a xor:"
- self genConditionalBranch: (orNot
- ifFalse: [branchDescriptor isBranchTrue ifTrue: [JumpZero] ifFalse: [JumpNonZero]]
- ifTrue: [branchDescriptor isBranchTrue ifTrue: [JumpNonZero] ifFalse: [JumpZero]])
operand: (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger.
"If the branch is dead, then we can just fall through postBranchPC (only a nop in-between), else
we need to jump over the code of the branch"
deadCode ifFalse:
[self Jump: (self ensureNonMergeFixupAt: postBranchPC - initialPC).
self ssPushConstant: objectMemory trueObject]. "dummy value"
^0!
More information about the Vm-dev
mailing list