You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: zjit/src/hir.rs
+91-75Lines changed: 91 additions & 75 deletions
Original file line number
Diff line number
Diff line change
@@ -5287,81 +5287,97 @@ impl Function {
5287
5287
}
5288
5288
}
5289
5289
5290
-
/// Convert maximal SSA (constructed from YARV with `add_iseq_to_hir`) to minimal SSA
5291
-
/// We implement the SSA construction described by Braun et al.
5292
-
/// SSA Paper reference: <https://c9x.me/compile/bib/braun13cc.pdf>
5293
-
fn minify_ssa(&mut self) {
5294
-
// This PR is _very_ much an early draft. I've spent some time reading the paper, and isolating some of the concepts.
5295
-
// There will be lots of lengthy comments that get removed and reworked. There are concepts in ZJIT that are identical but named different things.
5296
-
// We need to map these to each other. It probably makes sense to keep some reference comments performing this mapping for the future too.
5297
-
//
5298
-
// Important difference: Braun et al construct SSA from scratch. We already have a maximal SSA representation. We may be able to get away with only the pruning parts of the paper
5299
-
// Alternatively, we may just need to overhaul our entire SSA construction. I'm not sure what makes sense yet.
5300
-
//
5301
-
// TODO: Make tests for single blocks and multiple block constructions of minimal SSA
5302
-
// It would be great to faithfully recreate examples from the paper but with ZJIT specifics. If there's a way to construct ruby code that maps to this HIR, that would be awesome but jury is still out
5303
-
//
5304
-
// First Test Idea for LVN (page 3):
5305
-
// This first version isn't entirely implementable because `d` and `v?` are intentionally unspecified but it's a good starting point
5306
-
// source (make into ruby) SSA (make into ZJIT)
5307
-
// a <- 42 v1: 42
5308
-
// b <- a
5309
-
// c <- a + b v2: v1 + v1
5310
-
// v3: 23
5311
-
// a <- c + 23 v4: v2 + v3
5312
-
// c <- a + d v5: v4 + v?
5313
-
5314
-
// ------------ SINGLE BLOCK ----------------
5315
-
// This section contains all the tech we need for single blocks. For implementation, let's pass tests for this part first before adding in the rest
5316
-
// These two functions handle local value numbering. I don't know if this is something that Max landed in a PR, nor what can / should be repurposed vs written from scratch
5317
-
fn read_variable() {
5318
-
// TODO: Specify and define arguments
5319
-
// TODO: Figure out if this already exists in ZJIT. Likely this uses find or chase_insn?
5320
-
}
5321
-
5322
-
fn write_variable() {
5323
-
// TODO: Specify and define arguments
5324
-
// TODO: Figure out if this already exists in ZJIT. Likely this uses find or chase_insn?
5325
-
}
5326
-
//
5327
-
// ------------ MULTIPLE BLOCKS ----------------
5328
-
// When we get to multiple blocks, we need to deal with phi nodes. It seems that in ZJIT, these are referred to as block arguments or block params
5329
-
// It would be really nice to check my knowledge on this, and potentially rename them if so
5330
-
fn read_variable_recursive() {
5331
-
// TODO: fill out
5332
-
// This function is the global value numbering version of the single block variant
5333
-
}
5334
-
5335
-
fn add_phi_operands() {
5336
-
// See comments in try_remove_triival_phi
5337
-
}
5290
+
fn try_remove_trivial_phi(BlockId: block_id) {
5338
5291
5339
-
fn try_remove_trivial_phi() {
5340
-
// TODO: fill out
5341
-
// This function cleans up the opportunistic phis that get added in Braun's algorithm.
5342
-
// If we didn't add such phis, we run into all sorts of recursion issues. This is a key idea in the algorithm we are implementing
5343
-
}
5344
-
5345
-
// ---------- INCOMPLETE CFGS --------------
5346
-
// While technically part of the multiple blocks section, the next functions are even more complicated so they get their own section
5347
-
fn seal_block() {
5348
-
// We call a block "sealed" when we know there will not be predecessors added to the block.
5349
-
// This function adds all necessary phis to incomplete blocks and adds this block to the sealed list
5350
-
}
5351
-
5352
-
// I don't yet know which optimizations we want to include during construction. Pages 8 and 9 of the paper show why this is non-trivial and important for us to figure out
5353
-
// However, the following tools are definitely necessary
5354
-
fn remove_redundant_phis() {
5355
-
// In the paper, they innovate by considering irreducible control flow from the perspective of the strongly connected component that _must_ exist if there are redundant phis
5356
-
// By computing this strongly connected component, we can figure out what to remove (with the following function)
5357
-
}
5358
-
5359
-
fn process_strongly_connected_component() {
5360
-
// Do some fancy logic to iterate across all the phis in the SCC, tracking "inner" and "outer" operations
5361
-
}
5292
+
}
5362
5293
5363
-
// TODO: Close reading of page 11 after implementing everything else to see if there are further optimizations to be made
5364
-
// Key issue: we construct a lot of phis and then remove a lot of phis. Can we construct fewer in the first place?
5294
+
fn remove_trivial_phis(&mut self) {
5295
+
let mut fixpoint = False;
5296
+
while not fixpoint {
5297
+
for block in self.reverse_post_order() {
5298
+
// TODO: Figure out where the predecessors come from
5299
+
predecessors = vec![];
5300
+
try_remove_trivial_phi(block);
5301
+
}
5302
+
}
5303
+
}
5304
+
5305
+
// TODO: Probably throw this next big comment away
5306
+
// /// Convert maximal SSA (constructed from YARV with `add_iseq_to_hir`) to minimal SSA
5307
+
// /// We implement the SSA construction described by Braun et al.
5308
+
// /// SSA Paper reference: <https://c9x.me/compile/bib/braun13cc.pdf>
5309
+
// fn minify_ssa(&mut self) {
5310
+
// // This PR is _very_ much an early draft. I've spent some time reading the paper, and isolating some of the concepts.
5311
+
// // There will be lots of lengthy comments that get removed and reworked. There are concepts in ZJIT that are identical but named different things.
5312
+
// // We need to map these to each other. It probably makes sense to keep some reference comments performing this mapping for the future too.
5313
+
// //
5314
+
// // Important difference: Braun et al construct SSA from scratch. We already have a maximal SSA representation. We may be able to get away with only the pruning parts of the paper
5315
+
// // Alternatively, we may just need to overhaul our entire SSA construction. I'm not sure what makes sense yet.
5316
+
// //
5317
+
// // TODO: Make tests for single blocks and multiple block constructions of minimal SSA
5318
+
// // It would be great to faithfully recreate examples from the paper but with ZJIT specifics. If there's a way to construct ruby code that maps to this HIR, that would be awesome but jury is still out
5319
+
// //
5320
+
// // First Test Idea for LVN (page 3):
5321
+
// // This first version isn't entirely implementable because `d` and `v?` are intentionally unspecified but it's a good starting point
5322
+
// // source (make into ruby) SSA (make into ZJIT)
5323
+
// // a <- 42 v1: 42
5324
+
// // b <- a
5325
+
// // c <- a + b v2: v1 + v1
5326
+
// // v3: 23
5327
+
// // a <- c + 23 v4: v2 + v3
5328
+
// // c <- a + d v5: v4 + v?
5329
+
5330
+
// // ------------ SINGLE BLOCK ----------------
5331
+
// // This section contains all the tech we need for single blocks. For implementation, let's pass tests for this part first before adding in the rest
5332
+
// // These two functions handle local value numbering. I don't know if this is something that Max landed in a PR, nor what can / should be repurposed vs written from scratch
5333
+
// fn read_variable() {
5334
+
// // TODO: Specify and define arguments
5335
+
// // TODO: Figure out if this already exists in ZJIT. Likely this uses find or chase_insn?
5336
+
// }
5337
+
5338
+
// fn write_variable() {
5339
+
// // TODO: Specify and define arguments
5340
+
// // TODO: Figure out if this already exists in ZJIT. Likely this uses find or chase_insn?
// // When we get to multiple blocks, we need to deal with phi nodes. It seems that in ZJIT, these are referred to as block arguments or block params
5345
+
// // It would be really nice to check my knowledge on this, and potentially rename them if so
5346
+
// fn read_variable_recursive() {
5347
+
// // TODO: fill out
5348
+
// // This function is the global value numbering version of the single block variant
5349
+
// }
5350
+
5351
+
// fn add_phi_operands() {
5352
+
// // See comments in try_remove_triival_phi
5353
+
// }
5354
+
5355
+
// fn try_remove_trivial_phi() {
5356
+
// // TODO: fill out
5357
+
// // This function cleans up the opportunistic phis that get added in Braun's algorithm.
5358
+
// // If we didn't add such phis, we run into all sorts of recursion issues. This is a key idea in the algorithm we are implementing
5359
+
// }
5360
+
5361
+
// // ---------- INCOMPLETE CFGS --------------
5362
+
// // While technically part of the multiple blocks section, the next functions are even more complicated so they get their own section
5363
+
// fn seal_block() {
5364
+
// // We call a block "sealed" when we know there will not be predecessors added to the block.
5365
+
// // This function adds all necessary phis to incomplete blocks and adds this block to the sealed list
5366
+
// }
5367
+
5368
+
// // I don't yet know which optimizations we want to include during construction. Pages 8 and 9 of the paper show why this is non-trivial and important for us to figure out
5369
+
// // However, the following tools are definitely necessary
5370
+
// fn remove_redundant_phis() {
5371
+
// // In the paper, they innovate by considering irreducible control flow from the perspective of the strongly connected component that _must_ exist if there are redundant phis
5372
+
// // By computing this strongly connected component, we can figure out what to remove (with the following function)
5373
+
// }
5374
+
5375
+
// fn process_strongly_connected_component() {
5376
+
// // Do some fancy logic to iterate across all the phis in the SCC, tracking "inner" and "outer" operations
5377
+
// }
5378
+
5379
+
// // TODO: Close reading of page 11 after implementing everything else to see if there are further optimizations to be made
5380
+
// // Key issue: we construct a lot of phis and then remove a lot of phis. Can we construct fewer in the first place?
0 commit comments