-
Notifications
You must be signed in to change notification settings - Fork 6
ABCD dead branch elimination (upper bounds checks) #191
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
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
3cda1e8
ABCD (upper bounds checks)
m-demare e59e72a
Save unreachable blocks instead of dead edges
m-demare 24bbdbe
Small changes and improvements to merge this PR now (and implement th…
m-demare 370eb73
Add AIGraphAlgorithms dependency
m-demare c3addfc
Merge branch 'main' into pi-nodes/abcd
m-demare File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
Class { | ||
#name : 'DRPiABCDDeadBranchEliminationTest', | ||
#superclass : 'DRPiNodesTest', | ||
#category : 'Druid-Tests-Optimizations', | ||
#package : 'Druid-Tests', | ||
#tag : 'Optimizations' | ||
} | ||
|
||
{ #category : 'tests' } | ||
DRPiABCDDeadBranchEliminationTest >> testABCDGraph [ | ||
| cfg b_i b_end limit0 limit1 st0 st1 b_while b_for j1 b_if1 st3 limit3 j0 b_if2 t0 b_if2_after_check2 b_if2_after_check1 j4 cmp_for dummyOperand1 jmp_for b_check_failed | | ||
|
||
"This is the running example in the ABCD paper, reproduced it just to have something to validate our results agains | ||
The code is kinda ugly, I don't know if there's a nicer way to build this self-referencial/cyclic IRs" | ||
|
||
" /->------------------------------------------------------------------------------------->-\ | ||
/ V--<-------------------<-\ /->---------------------/->--\ | ||
|b_i| -> |b_while| -> |b_if1| -> |b_for| -> |b_if2| -> |b_if2_after_check1| -> |b_if2_after_check2| -> |b_end| | ||
\-<------------------------------------------------------<-/ | ||
" | ||
|
||
"Check Figure 3 in ABCD: Eliminating Array Bounds Checks on Demand for it to make *a bit* more sense" | ||
|
||
cfg := DRControlFlowGraph new. | ||
|
||
b_end := cfg newBasicBlockWith: [ :block | block storeSInt64: 2 at: 888 ]. | ||
b_check_failed := cfg newBasicBlockWith: [ :block | block storeSInt64: 2 at: 777 ]. | ||
|
||
b_i := cfg newBasicBlockWith: [ :block | | ||
dummyOperand1 := block copy: 1234. | ||
limit0 := block loadFramePointer. | ||
st0 := block copy: -1. | ||
]. | ||
cfg initialBasicBlock jumpTo: b_i. | ||
|
||
b_if2_after_check2 := cfg newBasicBlockWith: [ :block | | ||
j4 := block add: 1 to: dummyOperand1 "j1". | ||
]. | ||
|
||
b_if2_after_check1 := cfg newBasicBlockWith: [ :block | |check| | ||
t0 := block add: 1 to: dummyOperand1 "j1". | ||
check := block less: t0 than: limit0. | ||
block jumpIf: check to: b_if2_after_check2 ifFalseTo: b_check_failed. | ||
]. | ||
b_if2 := cfg newBasicBlockWith: [ :block | |check| | ||
check := block less: dummyOperand1 "j1" than: limit0. | ||
block jumpIf: check to: b_if2_after_check1 ifFalseTo: b_check_failed. | ||
]. | ||
|
||
b_for := cfg newBasicBlock. | ||
|
||
b_if2_after_check2 jumpTo: b_for. | ||
|
||
b_if1 := cfg newBasicBlockWith: [ :block | | ||
st3 := block add: 1 to: dummyOperand1 "st1". | ||
limit3 := block subtract: 1 from: dummyOperand1 "limit1". | ||
j0 := block copy: st3. | ||
block jumpTo: b_for. | ||
]. | ||
|
||
cmp_for := b_for less: dummyOperand1 than: limit3. | ||
jmp_for := b_for jumpIf: cmp_for to: b_if2 ifFalseTo: b_i. | ||
|
||
j1 := b_for phiWithVariables: {1234 asDRValue . 4567 asDRValue }. | ||
cmp_for replaceOperand: dummyOperand1 by: j1. | ||
|
||
b_if2_after_check2 instructions first replaceOperand: dummyOperand1 by: j1. | ||
b_if2_after_check1 instructions first replaceOperand: dummyOperand1 by: j1. | ||
b_if2 instructions first replaceOperand: dummyOperand1 by: j1. | ||
|
||
j1 replaceOperand: j1 operands first by: j0. | ||
j1 replaceOperand: j1 operands second by: j4. | ||
|
||
b_while := cfg newBasicBlockWith: [ :block | |cmp| | ||
limit1 := block phiWithVariables: {}. | ||
st1 := block phiWithVariables: {}. | ||
cmp := block less: st1 than: limit1. | ||
block jumpIf: cmp to: b_if1 ifFalseTo: b_end | ||
]. | ||
|
||
b_if1 instructions first replaceOperand: dummyOperand1 by: st1. | ||
b_if1 instructions second replaceOperand: dummyOperand1 by: limit1. | ||
|
||
b_i jumpTo: b_while. | ||
|
||
jmp_for falseBranch removePredecessor: jmp_for basicBlock. | ||
jmp_for newFalseBranch: b_while. | ||
jmp_for basicBlock predecessors add: jmp_for basicBlock predecessors removeFirst. | ||
|
||
limit1 operands: {limit0. limit3}. | ||
st1 operands: {st0. st3}. | ||
|
||
cfg validate. | ||
|
||
|
||
self optimize: cfg with: { DRPiABCDDeadBranchElimination }. | ||
|
||
|
||
self assert: b_if2 successors size equals: 1. | ||
self assert: b_if2 successors unique ~= b_check_failed. | ||
|
||
self assert: b_if2_after_check1 successors size equals: 1. | ||
self assert: b_if2 successors unique ~= b_check_failed. | ||
|
||
self assert: (cfg blocks includes: b_check_failed) not. | ||
|
||
] | ||
|
||
{ #category : 'tests' } | ||
DRPiABCDDeadBranchEliminationTest >> testABCDWithAdditionOverSameVariable [ | ||
|
||
" | ||
/->-|b_end0| (unreachable) | ||
|b_i| -> |b_if1| -> |b_end1| | ||
" | ||
|
||
| cfg b_end0 b_end1 b_i x y b_if1 | | ||
cfg := DRControlFlowGraph new. | ||
|
||
b_end0 := cfg newBasicBlockWith: [ :block | block storeSInt64: 2 at: 777 ]. | ||
b_end1 := cfg newBasicBlockWith: [ :block | block storeSInt64: 2 at: 888 ]. | ||
|
||
b_i := cfg newBasicBlockWith: [ :block | | ||
x := block loadSInt64: 111. | ||
y := block add: 1 to: x. | ||
]. | ||
|
||
b_if1 := cfg newBasicBlockWith: [ :block | |cmp| | ||
cmp := block less: y than: x. | ||
block jumpIf: cmp to: b_end0 ifFalseTo: b_end1 | ||
]. | ||
|
||
cfg initialBasicBlock jumpTo: b_i. | ||
b_i jumpTo: b_if1. | ||
|
||
|
||
self optimize: cfg with: { DRPiABCDDeadBranchElimination }. | ||
|
||
self skip. "Pretty sure this needs lower bounds check algorithm to work" | ||
self deny: (cfg blocks includes: b_end0). | ||
self assert: (cfg blocks includes: b_end1). | ||
|
||
self assert: b_if1 endInstruction isJump. | ||
self assert: b_if1 endInstruction isConditionalBranch not. | ||
self assert: b_if1 endInstruction target equals: b_end1. | ||
|
||
] | ||
|
||
{ #category : 'tests' } | ||
DRPiABCDDeadBranchEliminationTest >> testABCDWithSubstractionOverSameVariable [ | ||
|
||
" | ||
/->-|b_end0| | ||
|b_i| -> |b_if1| -> |b_end1| (unreachable) | ||
" | ||
|
||
| cfg b_end0 b_end1 b_i x y b_if1 | | ||
cfg := DRControlFlowGraph new. | ||
|
||
b_end0 := cfg newBasicBlockWith: [ :block | block storeSInt64: 2 at: 777 ]. | ||
b_end1 := cfg newBasicBlockWith: [ :block | block storeSInt64: 2 at: 888 ]. | ||
|
||
b_i := cfg newBasicBlockWith: [ :block | | ||
x := block loadSInt64: 111. | ||
y := block subtract: 1 from: x. | ||
]. | ||
|
||
b_if1 := cfg newBasicBlockWith: [ :block | |cmp| | ||
cmp := block less: y than: x. | ||
block jumpIf: cmp to: b_end0 ifFalseTo: b_end1 | ||
]. | ||
|
||
cfg initialBasicBlock jumpTo: b_i. | ||
b_i jumpTo: b_if1. | ||
|
||
|
||
self optimize: cfg with: { DRPiABCDDeadBranchElimination }. | ||
|
||
|
||
self assert: (cfg blocks includes: b_end0). | ||
self deny: (cfg blocks includes: b_end1). | ||
|
||
self assert: b_if1 endInstruction isJump. | ||
self assert: b_if1 endInstruction isConditionalBranch not. | ||
self assert: b_if1 endInstruction target equals: b_end0. | ||
|
||
] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👏