Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix store immutable receiver #87

Merged
merged 7 commits into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 26 additions & 13 deletions Druid-Tests/DRDeadCodeEliminationTest.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ Class {
#category : #'Druid-Tests-Optimizations'
}

{ #category : #test }
DRDeadCodeEliminationTest >> setUp [

super setUp.
optimisation := DRDeadCodeElimination new
]

{ #category : #tests }
DRDeadCodeEliminationTest >> testDCEOnConditionalJump [


| cfg copy1 copy2 copy3 copy4 copy5 copy6 jump add1 add2 phi|
optimisation := DRDeadCodeElimination new.

copy1 := DRCopy
operands: { (DRConstantValue value: 1) }
result: (DRTemporaryRegister id: 1).
Expand Down Expand Up @@ -58,10 +62,7 @@ DRDeadCodeEliminationTest >> testDCEOnConditionalJump [
{ #category : #tests }
DRDeadCodeEliminationTest >> testDCEOnDeadEndInstruction [

| cfg copy1 copy2 phi1|

optimisation := DRDeadCodeElimination new.

| cfg copy1 copy2 phi1|
cfg := self setUpCFG: 2.

cfg b1 addInstruction: (DRCopy operands: { DRConstantValue value: 1 } result: (DRTemporaryRegister id: 1)).
Expand All @@ -87,9 +88,6 @@ DRDeadCodeEliminationTest >> testDCEOnDeadEndInstruction [
DRDeadCodeEliminationTest >> testDCEOnSeveralBlocs [

| b1 b2 cfg copy1 |

optimisation := DRDeadCodeElimination new.

cfg := self setUpCFG: 2.

b1 := cfg b1.
Expand All @@ -107,13 +105,28 @@ DRDeadCodeEliminationTest >> testDCEOnSeveralBlocs [
self assert: cfg instructions size equals: 4.
]

{ #category : #test }
DRDeadCodeEliminationTest >> testNotRemoveUnusedMandatoryInstruction [

| cfg copy addition |
cfg := self setUpCFG: 2.

cfg b2 addInstruction: (copy := DRObjectReferenceCopy
operands:
{ (DRObjectReferenceValue expression: 'methodObj') }
result: (DRTemporaryRegister id: 1)).
addition := cfg b2 add: copy to: 1.

optimisation applyTo: cfg.

self denyCollection: cfg instructions includesAny: { addition }.
self assertCollection: cfg instructions includesAny: { copy }
]

{ #category : #test }
DRDeadCodeEliminationTest >> testRemoveUnusedNoop [

| cfg |

optimisation := DRDeadCodeElimination new.

cfg := self setUpCFG: 2.

cfg b2 addInstruction: (DRNoop new result: DRNoRegister new).
Expand Down
30 changes: 29 additions & 1 deletion Druid-Tests/DRLoopTest.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ DRLoopTest >> testCanRetrieveLoopGraphWithMultipleBodyBlocks [

loopSubgraph := loop loopGraph.

loopBlocksIds := { 6. 11. 12. 7 }.
loopBlocksIds := { 6. 12. 13 . 7 }.
self assertCollection: (loopSubgraph blocks collect: #id) hasSameElements: loopBlocksIds.
]

Expand Down Expand Up @@ -78,3 +78,31 @@ DRLoopTest >> testCanRetrieveLoopGraphWithSingleBodyBlock [
loopBlocksIds := { 6. 7 }.
self assertCollection: (loopSubgraph blocks collect: #id) hasSameElements: loopBlocksIds.
]

{ #category : #tests }
DRLoopTest >> testFixBackjumpsIgnoreInnerRecursivePhis [

| cfg innerPhi loopHeaderPhi loopBody addition1 addition2 |
cfg := self setUpCFGWithConditionalWithPhi.

loopHeaderPhi := cfg b1 phiWithVariables: { }.
addition1 := cfg b2 add: loopHeaderPhi to: 7.

innerPhi := cfg b4 phiFunctions unique.
innerPhi replaceOperandAtIndex: 1 by: addition1.

loopBody := cfg newBasicBlock. "5"
addition2 := loopBody add: innerPhi to: 8.
cfg b4 jumpIfTrueTo: loopBody ifFalseTo: cfg newBasicBlock.
loopBody backJumpTo: cfg b1.
loopHeaderPhi mergeOperands: { DRNullValue new. addition2 }.
cfg validate.

self assert: loopHeaderPhi hasRecursiveUse.
self assert: innerPhi hasRecursiveUse.
self assert: cfg allBackJumps unique equals: loopBody endInstruction.

cfg fixBackJumps.

self assert: cfg allBackJumps unique equals: loopBody endInstruction
]
23 changes: 23 additions & 0 deletions Druid-Tests/DRPathGenerationTest.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,29 @@ DRPathGenerationTest >> testConstraintsInferenceFromInnerBranches [
self assertConstraint: falseConstraint includes: (DRGreaterOrEqualsConstraint withValue: 20)
]

{ #category : #constraints }
DRPathGenerationTest >> testConstraintsInferenceFromJITExpressions [

| cfg jitExpression copy |
cfg := self setUpCFGWithConditional.

"Put the JIT expression in a register"
jitExpression := cfg b1 jitCompileTimeVariable: 'extB'.
copy := cfg b1 copy: jitExpression.

"Same comparison"
cfg b1 endInstruction replaceOperandAtIndex: 1 by: copy.
cfg b4
jumpIf: copy
to: cfg newBasicBlock
ifFalseTo: cfg newBasicBlock.

cfg generatePaths.

"Sand clock pattern have half of the paths dead"
self assert: cfg deadPaths size equals: cfg pathsSize / 2
]

{ #category : #constraints }
DRPathGenerationTest >> testConstraintsInferenceFromLoop [

Expand Down
101 changes: 95 additions & 6 deletions Druid-Tests/DRProductionBytecodeTest.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -1810,9 +1810,11 @@ DRProductionBytecodeTest >> testStoreAndPopReceiverVariableBytecode7 [
{ #category : #tests }
DRProductionBytecodeTest >> testStoreAndPopReceiverVariableBytecode: index [

| object storeCheckTrampoline |
storeCheckTrampoline := self compile: [ cogit RetN: 0 ].
cogit ceStoreCheckTrampoline: storeCheckTrampoline.
| object fakeTrampoline |
fakeTrampoline := self compile: [ cogit RetN: 0 ].
cogit ceStoreCheckTrampoline: fakeTrampoline.
cogit ceDeoptimiseFrameTrampoline: fakeTrampoline.
cogit bytecodePC: 87.

self
compileBytecode: 200 + index
Expand All @@ -1835,13 +1837,58 @@ DRProductionBytecodeTest >> testStoreAndPopReceiverVariableBytecode: index [
self assert: (memory fetchPointer: index ofObject: object) equals: memory trueObject
]

{ #category : #tests }
DRProductionBytecodeTest >> testStoreAndPopReceiverVariableBytecodeCallImmutableTrampoline [

| object value immutableTrampoline fakeTrampoline bytecodePC |

fakeTrampoline := self compile: [ cogit RetN: 0 ].
cogit ceStoreCheckTrampoline: fakeTrampoline.
immutableTrampoline := self compile: [ cogit RetN: 0 ].
cogit ceDeoptimiseFrameTrampoline: immutableTrampoline.
bytecodePC := 87.
cogit bytecodePC: bytecodePC.

self
compileBytecode: 200
selector: #storeAndPopReceiverVariableBytecode
thenDo: [ :generator |
cogit ssPushRegister: TempReg.

"Execute the druid's compiled code"
generator value.

"Then return without druid's compiled code"
cogit genUpArrowReturn ].

object := self newObjectWithSlots: 1.
memory setIsImmutableOf: object to: true.

value := self newObjectWithSlots: 0.

machineSimulator temporaryRegisterValue: value.

self
prepareStackForPrimitiveReceiver: object
arguments: #( )
method: 0.

"Should arrive to trampoline to put the object in the remembered set"
self runFrom: cogInitialAddress until: immutableTrampoline.

self assert: machineSimulator receiverRegisterValue equals: bytecodePC
]

{ #category : #tests }
DRProductionBytecodeTest >> testStoreAndPopReceiverVariableBytecodeCallRememberTrampoline [

| object value storeCheckTrampoline |
| object value storeCheckTrampoline fakeTrampoline |

storeCheckTrampoline := self compile: [ cogit RetN: 0 ].
cogit ceStoreCheckTrampoline: storeCheckTrampoline.
fakeTrampoline := self compile: [ cogit RetN: 0 ].
cogit ceDeoptimiseFrameTrampoline: fakeTrampoline.
cogit bytecodePC: 87.

self
compileBytecode: 200
Expand Down Expand Up @@ -1871,13 +1918,52 @@ DRProductionBytecodeTest >> testStoreAndPopReceiverVariableBytecodeCallRememberT
self assert: machineSimulator receiverRegisterValue equals: object
]

{ #category : #tests }
DRProductionBytecodeTest >> testStoreAndPopReceiverVariableBytecodeImmutable [

| object value storeCheckTrampoline fakeTrampoline |

storeCheckTrampoline := self compile: [ cogit RetN: 0 ].
cogit ceStoreCheckTrampoline: storeCheckTrampoline.
fakeTrampoline := self compile: [ cogit RetN: 0 ].
cogit ceDeoptimiseFrameTrampoline: fakeTrampoline.
cogit bytecodePC: 87.

self
compileBytecode: 200
selector: #storeAndPopReceiverVariableBytecode
thenDo: [ :generator |
cogit ssPushRegister: TempReg.

"Execute the druid's compiled code"
generator value.

"Then return without druid's compiled code"
cogit genUpArrowReturn ].

object := self newObjectWithSlots: 1.
memory setIsImmutableOf: object to: true.

value := self newObjectWithSlots: 0.

machineSimulator temporaryRegisterValue: value.

self executePrimitiveWithReceiver: object.

self assert: machineSimulator receiverRegisterValue equals: 87.
self assert: (memory fetchPointer: 0 ofObject: object) equals: memory nilObject
]

{ #category : #tests }
DRProductionBytecodeTest >> testStoreAndPopReceiverVariableBytecodeNotRemember [

| object value storeCheckTrampoline |
| object value storeCheckTrampoline fakeTrampoline |

storeCheckTrampoline := self compile: [ cogit RetN: 0 ].
cogit ceStoreCheckTrampoline: storeCheckTrampoline.
fakeTrampoline := self compile: [ cogit RetN: 0 ].
cogit ceDeoptimiseFrameTrampoline: fakeTrampoline.
cogit bytecodePC: 87.

self
compileBytecode: 200
Expand Down Expand Up @@ -1905,10 +1991,13 @@ DRProductionBytecodeTest >> testStoreAndPopReceiverVariableBytecodeNotRemember [
{ #category : #tests }
DRProductionBytecodeTest >> testStoreAndPopReceiverVariableBytecodeRemember [

| object value storeCheckTrampoline |
| object value storeCheckTrampoline fakeTrampoline |

storeCheckTrampoline := self compile: [ cogit RetN: 0 ].
cogit ceStoreCheckTrampoline: storeCheckTrampoline.
fakeTrampoline := self compile: [ cogit RetN: 0 ].
cogit ceDeoptimiseFrameTrampoline: fakeTrampoline.
cogit bytecodePC: 87.

self
compileBytecode: 200
Expand Down
24 changes: 24 additions & 0 deletions Druid-Tests/DRSCCPConstantFoldingTest.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,30 @@ DRSCCPConstantFoldingTest >> testFoldingLoadWithOperation [
self assert: cfg instructions nextToLast operand1 equals: load
]

{ #category : #tests }
DRSCCPConstantFoldingTest >> testFoldingObjectReferenceIntoJITExpression [

| cfg copy addition |
cfg := self setUpCFG: 1.

cfg b1 addInstruction: (copy := DRObjectReferenceCopy
operands:
{ (DRObjectReferenceValue expression: 'methodObj') }
result: (DRTemporaryRegister id: 999)).
addition := cfg b1 add: copy to: 1.
cfg b1 return: addition.

optimisation applyTo: cfg.

"Object references should keep to be annotated for GC"
self assert: cfg instructions first equals: copy.
"Anyway, users are folded"
self assert: cfg instructions second isCopy.
self assert: cfg instructions second operand1 expression equals: '(methodObj + 1)'.


]

{ #category : #tests }
DRSCCPConstantFoldingTest >> testNonConstantFoldingOf: aClass between: aDROperand1 and: aDROperand2 [
| cfg |
Expand Down
Loading
Loading