compiler: Scan stack reservations through checked instruction slices
f28b07519331e1ca6603e85eda11d3eb6165183277d052eb3d8d42ffb6e9b389
1 parent
80edc705
lib/std/arch/rv64/isel.rad
+28 -28
| 270 | 270 | size: i32, |
|
| 271 | 271 | /// Whether any dynamic-sized reserves exist. |
|
| 272 | 272 | isDynamic: bool, |
|
| 273 | 273 | } |
|
| 274 | 274 | ||
| 275 | - | /// Pre-scan all blocks for constant-sized reserve instructions. |
|
| 275 | + | /// Add a block's reserve instructions to the accumulated frame requirements. |
|
| 276 | 276 | /// Returns the total size needed for all static reserves, respecting alignment. |
|
| 277 | - | unsafe fn computeReserveInfo(func: &il::Fn) -> ?ReserveInfo { |
|
| 278 | - | let mut offset: i32 = 0; |
|
| 279 | - | let mut isDynamic = false; |
|
| 280 | - | ||
| 281 | - | for b in 0..func.blocks.len { |
|
| 282 | - | let block = &func.blocks[b]; |
|
| 283 | - | for instr in block.instrs { |
|
| 284 | - | match instr { |
|
| 285 | - | case il::Instr::Reserve { size, alignment, .. } => { |
|
| 286 | - | if let case il::Val::Imm(sz) = size { |
|
| 287 | - | if alignment == 0 or (alignment & (alignment - 1)) <> 0 or sz < 0 { |
|
| 288 | - | return nil; |
|
| 289 | - | } |
|
| 290 | - | let aligned = (offset as u64 + alignment as u64 - 1) & ~(alignment as u64 - 1); |
|
| 291 | - | if aligned > 0x7fff0000 or sz as u64 > 0x7fff0000 - aligned { |
|
| 292 | - | return nil; |
|
| 293 | - | } |
|
| 294 | - | set offset = (aligned + sz as u64) as i32; |
|
| 295 | - | } else { |
|
| 296 | - | set isDynamic = true; |
|
| 277 | + | fn computeReserveInfo(instrs: &[il::Instr], previous: ReserveInfo) -> ?ReserveInfo { |
|
| 278 | + | let mut offset = previous.size; |
|
| 279 | + | let mut isDynamic = previous.isDynamic; |
|
| 280 | + | for instr in instrs { |
|
| 281 | + | match instr { |
|
| 282 | + | case il::Instr::Reserve { size, alignment, .. } => { |
|
| 283 | + | if let case il::Val::Imm(sz) = size { |
|
| 284 | + | if alignment == 0 or (alignment & (alignment - 1)) <> 0 or sz < 0 { |
|
| 285 | + | return nil; |
|
| 297 | 286 | } |
|
| 298 | - | }, |
|
| 299 | - | else => {}, |
|
| 300 | - | } |
|
| 287 | + | let aligned = (offset as u64 + alignment as u64 - 1) & ~(alignment as u64 - 1); |
|
| 288 | + | if aligned > 0x7fff0000 or sz as u64 > 0x7fff0000 - aligned { |
|
| 289 | + | return nil; |
|
| 290 | + | } |
|
| 291 | + | set offset = (aligned + sz as u64) as i32; |
|
| 292 | + | } else { |
|
| 293 | + | set isDynamic = true; |
|
| 294 | + | } |
|
| 295 | + | }, |
|
| 296 | + | else => {}, |
|
| 301 | 297 | } |
|
| 302 | 298 | } |
|
| 303 | 299 | return ReserveInfo { size: offset, isDynamic }; |
|
| 304 | 300 | } |
|
| 305 | 301 |
| 313 | 309 | return; |
|
| 314 | 310 | } |
|
| 315 | 311 | // Reset block offsets for this function. |
|
| 316 | 312 | labels::resetBlocks(&mut e.labels); |
|
| 317 | 313 | // Pre-scan for constant-sized reserves to promote to fixed frame slots. |
|
| 318 | - | let reserveInfo = computeReserveInfo(func) else { |
|
| 319 | - | set e.error = super::Error::Capacity; |
|
| 320 | - | return; |
|
| 321 | - | }; |
|
| 314 | + | let mut reserveInfo = ReserveInfo { size: 0, isDynamic: false }; |
|
| 315 | + | for block in func.blocks { |
|
| 316 | + | let next = computeReserveInfo(&block.instrs[..], reserveInfo) else { |
|
| 317 | + | set e.error = super::Error::Capacity; |
|
| 318 | + | return; |
|
| 319 | + | }; |
|
| 320 | + | set reserveInfo = next; |
|
| 321 | + | } |
|
| 322 | 322 | if reserveInfo.size as u64 + ralloc.spill.frameSize as u64 > 0x7fffff00 { |
|
| 323 | 323 | set e.error = super::Error::Capacity; return; |
|
| 324 | 324 | } |
|
| 325 | 325 | let isLeaf = func.isLeaf; |
|
| 326 | 326 | // Compute frame layout from spill slots, reserve slots, and used callee-saved registers. |