il: Print numbers without arena allocations
e0c7ad6ca2ca3c55bf1d73401de7ad9d8c944d48e19725b65cb87d9ee146daa9
Numeric output is consumed synchronously. Format into local buffers to avoid temporary arena allocations and copies, and remove the printer arena parameters from callers. Keep each register token in one output write. Assisted-by: Codex:gpt-6-astra
1 parent
d3a86b21
compiler/radiance.rad
+1 -1
| 1041 | 1041 | let mut out = sexpr::Output::Stdout; |
|
| 1042 | 1042 | ||
| 1043 | 1043 | if ctx.dump == Dump::Il { |
|
| 1044 | 1044 | // Lower all packages into a single unified IL program for dumping. |
|
| 1045 | 1045 | let program = try lowerAllPackages(ctx, res); |
|
| 1046 | - | il::printer::printProgram(&mut out, &mut res.arena, &program); |
|
| 1046 | + | il::printer::printProgram(&mut out, &program); |
|
| 1047 | 1047 | io::print("\n"); |
|
| 1048 | 1048 | return; |
|
| 1049 | 1049 | } |
|
| 1050 | 1050 | if ctx.dump == Dump::Asm { |
|
| 1051 | 1051 | let result = try lowerAndGenerateAllPackages(ctx, res, fnArena, CodegenOptions { |
lib/std/lang/il/printer.rad
+89 -113
| 1 | 1 | //! IL pretty printer. |
|
| 2 | 2 | ||
| 3 | 3 | use std::fmt; |
|
| 4 | - | use std::mem; |
|
| 5 | 4 | use std::lang::sexpr; |
|
| 6 | - | use std::lang::alloc; |
|
| 7 | 5 | ||
| 8 | 6 | /////////////////////// |
|
| 9 | 7 | // String formatting // |
|
| 10 | 8 | /////////////////////// |
|
| 11 | 9 | ||
| 12 | - | /// Copy a byte slice into arena-allocated storage. |
|
| 13 | - | fn copyToArena(a: *mut alloc::Arena, text: *[u8]) -> *[u8] { |
|
| 14 | - | let slice = try! alloc::allocSlice(a, 1, 1, text.len) as *mut [u8]; |
|
| 15 | - | try! mem::copy(slice, text); |
|
| 16 | - | return slice; |
|
| 17 | - | } |
|
| 18 | - | ||
| 19 | - | /// Format a `u32` into a string in the arena. |
|
| 20 | - | fn formatU32(a: *mut alloc::Arena, val: u32) -> *[u8] { |
|
| 10 | + | /// Write a `u32` before its stack buffer leaves scope. |
|
| 11 | + | fn writeU32(out: *mut sexpr::Output, val: u32) { |
|
| 21 | 12 | let mut digits: [u8; 10] = undefined; |
|
| 22 | - | return copyToArena(a, fmt::formatU32(val, &mut digits[..])); |
|
| 13 | + | write(out, fmt::formatU32(val, &mut digits[..])); |
|
| 23 | 14 | } |
|
| 24 | 15 | ||
| 25 | - | /// Format an `i32` into a string in the arena. |
|
| 26 | - | fn formatI32(a: *mut alloc::Arena, val: i32) -> *[u8] { |
|
| 16 | + | /// Write an `i32` before its stack buffer leaves scope. |
|
| 17 | + | fn writeI32(out: *mut sexpr::Output, val: i32) { |
|
| 27 | 18 | let mut digits: [u8; 12] = undefined; |
|
| 28 | - | return copyToArena(a, fmt::formatI32(val, &mut digits[..])); |
|
| 19 | + | write(out, fmt::formatI32(val, &mut digits[..])); |
|
| 29 | 20 | } |
|
| 30 | 21 | ||
| 31 | - | /// Format an `i64` into a string in the arena. |
|
| 32 | - | fn formatI64(a: *mut alloc::Arena, val: i64) -> *[u8] { |
|
| 22 | + | /// Write an `i64` before its stack buffer leaves scope. |
|
| 23 | + | fn writeI64(out: *mut sexpr::Output, val: i64) { |
|
| 33 | 24 | let mut digits: [u8; 20] = undefined; |
|
| 34 | - | return copyToArena(a, fmt::formatI64(val, &mut digits[..])); |
|
| 35 | - | } |
|
| 36 | - | ||
| 37 | - | /// Concatenate prefix and string in the arena. |
|
| 38 | - | fn prefixStr(a: *mut alloc::Arena, prefix: u8, str: *[u8]) -> *[u8] { |
|
| 39 | - | let len = str.len + 1; |
|
| 40 | - | let ptr = try! alloc::allocSlice(a, 1, 1, len); |
|
| 41 | - | let slice = ptr as *mut [u8]; |
|
| 42 | - | set slice[0] = prefix; |
|
| 43 | - | try! mem::copy(&mut slice[1..], str); |
|
| 44 | - | ||
| 45 | - | return slice; |
|
| 46 | - | } |
|
| 47 | - | ||
| 48 | - | /// Format a register reference (`%n`). |
|
| 49 | - | fn regStr(a: *mut alloc::Arena, reg: super::Reg) -> *[u8] { |
|
| 50 | - | return prefixStr(a, '%', formatU32(a, reg.n)); |
|
| 25 | + | write(out, fmt::formatI64(val, &mut digits[..])); |
|
| 51 | 26 | } |
|
| 52 | 27 | ||
| 53 | 28 | ///////////////////// |
|
| 54 | 29 | // Output helpers // |
|
| 55 | 30 | ///////////////////// |
| 147 | 122 | //////////////////// |
|
| 148 | 123 | // Value printing // |
|
| 149 | 124 | //////////////////// |
|
| 150 | 125 | ||
| 151 | 126 | /// Write a value (register, immediate, symbol, or undefined). |
|
| 152 | - | fn writeVal(out: *mut sexpr::Output, a: *mut alloc::Arena, val: super::Val) { |
|
| 127 | + | fn writeVal(out: *mut sexpr::Output, val: super::Val) { |
|
| 153 | 128 | match val { |
|
| 154 | - | case super::Val::Reg(reg) => write(out, regStr(a, reg)), |
|
| 155 | - | case super::Val::Imm(v) => write(out, formatI64(a, v)), |
|
| 129 | + | case super::Val::Reg(reg) => writeReg(out, reg), |
|
| 130 | + | case super::Val::Imm(v) => writeI64(out, v), |
|
| 156 | 131 | case super::Val::DataSym(name) => writeSymbol(out, name), |
|
| 157 | 132 | case super::Val::FnAddr(name) => writeSymbol(out, name), |
|
| 158 | 133 | case super::Val::Undef => write(out, "undefined"), |
|
| 159 | 134 | } |
|
| 160 | 135 | } |
|
| 161 | 136 | ||
| 162 | - | /// Write a register. |
|
| 163 | - | fn writeReg(out: *mut sexpr::Output, a: *mut alloc::Arena, reg: super::Reg) { |
|
| 164 | - | write(out, regStr(a, reg)); |
|
| 137 | + | /// Write a register in one operation before its stack buffer leaves scope. |
|
| 138 | + | fn writeReg(out: *mut sexpr::Output, reg: super::Reg) { |
|
| 139 | + | let mut buffer: [u8; 11] = undefined; |
|
| 140 | + | let digits = fmt::formatU32(reg.n, &mut buffer[1..]); |
|
| 141 | + | let start = buffer.len - digits.len - 1; |
|
| 142 | + | set buffer[start] = '%'; |
|
| 143 | + | write(out, &buffer[start..]); |
|
| 165 | 144 | } |
|
| 166 | 145 | ||
| 167 | 146 | /// Write a comma-separated argument list in parentheses. |
|
| 168 | - | fn writeArgs(out: *mut sexpr::Output, a: *mut alloc::Arena, args: *[super::Val]) { |
|
| 147 | + | fn writeArgs(out: *mut sexpr::Output, args: *[super::Val]) { |
|
| 169 | 148 | write(out, "("); |
|
| 170 | 149 | for arg, i in args { |
|
| 171 | 150 | if i > 0 { |
|
| 172 | 151 | write(out, ", "); |
|
| 173 | 152 | } |
|
| 174 | - | writeVal(out, a, arg); |
|
| 153 | + | writeVal(out, arg); |
|
| 175 | 154 | } |
|
| 176 | 155 | write(out, ")"); |
|
| 177 | 156 | } |
|
| 178 | 157 | ||
| 179 | 158 | /// Write a typed parameter (e.g., `w32 %0`). |
|
| 180 | - | fn writeParam(out: *mut sexpr::Output, a: *mut alloc::Arena, param: super::Param) { |
|
| 159 | + | fn writeParam(out: *mut sexpr::Output, param: super::Param) { |
|
| 181 | 160 | writeType(out, param.type); |
|
| 182 | 161 | write(out, " "); |
|
| 183 | - | writeReg(out, a, param.value); |
|
| 162 | + | writeReg(out, param.value); |
|
| 184 | 163 | } |
|
| 185 | 164 | ||
| 186 | 165 | /// Write a comma-separated parameter list. |
|
| 187 | - | fn writeParams(out: *mut sexpr::Output, a: *mut alloc::Arena, params: *[super::Param]) { |
|
| 166 | + | fn writeParams(out: *mut sexpr::Output, params: *[super::Param]) { |
|
| 188 | 167 | for param, i in params { |
|
| 189 | 168 | if i > 0 { |
|
| 190 | 169 | write(out, ", "); |
|
| 191 | 170 | } |
|
| 192 | - | writeParam(out, a, param); |
|
| 171 | + | writeParam(out, param); |
|
| 193 | 172 | } |
|
| 194 | 173 | } |
|
| 195 | 174 | ||
| 196 | 175 | ////////////////////////// |
|
| 197 | 176 | // Instruction printing // |
|
| 198 | 177 | ////////////////////////// |
|
| 199 | 178 | ||
| 200 | 179 | /// Write an instruction. |
|
| 201 | - | fn writeInstr(out: *mut sexpr::Output, a: *mut alloc::Arena, blocks: *[super::Block], inst: super::Instr) { |
|
| 180 | + | fn writeInstr(out: *mut sexpr::Output, blocks: *[super::Block], inst: super::Instr) { |
|
| 202 | 181 | match inst { |
|
| 203 | 182 | // Memory operations. |
|
| 204 | 183 | case super::Instr::Reserve { dst, size, alignment } => { |
|
| 205 | 184 | write(out, "reserve "); |
|
| 206 | - | writeReg(out, a, dst); |
|
| 185 | + | writeReg(out, dst); |
|
| 207 | 186 | write(out, " "); |
|
| 208 | - | writeVal(out, a, size); |
|
| 187 | + | writeVal(out, size); |
|
| 209 | 188 | write(out, " "); |
|
| 210 | - | write(out, formatU32(a, alignment)); |
|
| 189 | + | writeU32(out, alignment); |
|
| 211 | 190 | } |
|
| 212 | 191 | case super::Instr::Load { dst, typ, src, offset } => { |
|
| 213 | 192 | write(out, "load "); |
|
| 214 | 193 | writeType(out, typ); |
|
| 215 | 194 | write(out, " "); |
|
| 216 | - | writeReg(out, a, dst); |
|
| 195 | + | writeReg(out, dst); |
|
| 217 | 196 | write(out, " "); |
|
| 218 | - | writeReg(out, a, src); |
|
| 197 | + | writeReg(out, src); |
|
| 219 | 198 | write(out, " "); |
|
| 220 | - | write(out, formatI32(a, offset)); |
|
| 199 | + | writeI32(out, offset); |
|
| 221 | 200 | } |
|
| 222 | 201 | case super::Instr::Sload { dst, typ, src, offset } => { |
|
| 223 | 202 | write(out, "sload "); |
|
| 224 | 203 | writeType(out, typ); |
|
| 225 | 204 | write(out, " "); |
|
| 226 | - | writeReg(out, a, dst); |
|
| 205 | + | writeReg(out, dst); |
|
| 227 | 206 | write(out, " "); |
|
| 228 | - | writeReg(out, a, src); |
|
| 207 | + | writeReg(out, src); |
|
| 229 | 208 | write(out, " "); |
|
| 230 | - | write(out, formatI32(a, offset)); |
|
| 209 | + | writeI32(out, offset); |
|
| 231 | 210 | } |
|
| 232 | 211 | case super::Instr::Store { typ, src, dst, offset } => { |
|
| 233 | 212 | write(out, "store "); |
|
| 234 | 213 | writeType(out, typ); |
|
| 235 | 214 | write(out, " "); |
|
| 236 | - | writeVal(out, a, src); |
|
| 215 | + | writeVal(out, src); |
|
| 237 | 216 | write(out, " "); |
|
| 238 | - | writeReg(out, a, dst); |
|
| 217 | + | writeReg(out, dst); |
|
| 239 | 218 | write(out, " "); |
|
| 240 | - | write(out, formatI32(a, offset)); |
|
| 219 | + | writeI32(out, offset); |
|
| 241 | 220 | } |
|
| 242 | 221 | case super::Instr::Blit { dst, src, size } => { |
|
| 243 | 222 | write(out, "blit "); |
|
| 244 | - | writeReg(out, a, dst); |
|
| 223 | + | writeReg(out, dst); |
|
| 245 | 224 | write(out, " "); |
|
| 246 | - | writeReg(out, a, src); |
|
| 225 | + | writeReg(out, src); |
|
| 247 | 226 | write(out, " "); |
|
| 248 | - | writeVal(out, a, size); |
|
| 227 | + | writeVal(out, size); |
|
| 249 | 228 | } |
|
| 250 | 229 | case super::Instr::Copy { dst, val } => { |
|
| 251 | 230 | write(out, "copy "); |
|
| 252 | - | writeReg(out, a, dst); |
|
| 231 | + | writeReg(out, dst); |
|
| 253 | 232 | write(out, " "); |
|
| 254 | - | writeVal(out, a, val); |
|
| 233 | + | writeVal(out, val); |
|
| 255 | 234 | } |
|
| 256 | 235 | ||
| 257 | 236 | // ALU operations. |
|
| 258 | 237 | case super::Instr::BinOp { op, dst, typ, a: va, b } => |
|
| 259 | - | writeTypedBinOp(out, a, binOpStr(op), typ, dst, va, b), |
|
| 238 | + | writeTypedBinOp(out, binOpStr(op), typ, dst, va, b), |
|
| 260 | 239 | case super::Instr::UnOp { op, dst, typ, a: va } => |
|
| 261 | - | writeTypedUnaryOp(out, a, unOpStr(op), typ, dst, va), |
|
| 240 | + | writeTypedUnaryOp(out, unOpStr(op), typ, dst, va), |
|
| 262 | 241 | ||
| 263 | 242 | // Conversion operations. |
|
| 264 | 243 | case super::Instr::Zext { dst, typ, val } => |
|
| 265 | - | writeTypedUnaryOp(out, a, "zext", typ, dst, val), |
|
| 244 | + | writeTypedUnaryOp(out, "zext", typ, dst, val), |
|
| 266 | 245 | case super::Instr::Sext { dst, typ, val } => |
|
| 267 | - | writeTypedUnaryOp(out, a, "sext", typ, dst, val), |
|
| 246 | + | writeTypedUnaryOp(out, "sext", typ, dst, val), |
|
| 268 | 247 | ||
| 269 | 248 | // Call. |
|
| 270 | 249 | case super::Instr::Call { dst, retTy, func, args } => { |
|
| 271 | 250 | write(out, "call "); |
|
| 272 | 251 | writeType(out, retTy); |
|
| 273 | 252 | write(out, " "); |
|
| 274 | 253 | if let d = dst { |
|
| 275 | - | writeReg(out, a, d); |
|
| 254 | + | writeReg(out, d); |
|
| 276 | 255 | write(out, " "); |
|
| 277 | 256 | } |
|
| 278 | - | writeVal(out, a, func); |
|
| 279 | - | writeArgs(out, a, args); |
|
| 257 | + | writeVal(out, func); |
|
| 258 | + | writeArgs(out, args); |
|
| 280 | 259 | } |
|
| 281 | 260 | ||
| 282 | 261 | // Terminators. |
|
| 283 | 262 | case super::Instr::Ret { val } => { |
|
| 284 | 263 | write(out, "ret"); |
|
| 285 | 264 | if let v = val { |
|
| 286 | 265 | write(out, " "); |
|
| 287 | - | writeVal(out, a, v); |
|
| 266 | + | writeVal(out, v); |
|
| 288 | 267 | } |
|
| 289 | 268 | } |
|
| 290 | 269 | case super::Instr::Jmp { target, args } => { |
|
| 291 | 270 | write(out, "jmp @"); |
|
| 292 | 271 | write(out, blocks[target].label); |
|
| 293 | 272 | if args.len > 0 { |
|
| 294 | - | writeArgs(out, a, args); |
|
| 273 | + | writeArgs(out, args); |
|
| 295 | 274 | } |
|
| 296 | 275 | } |
|
| 297 | 276 | case super::Instr::Br { op, typ, a: va, b: vb, thenTarget, thenArgs, elseTarget, elseArgs } => { |
|
| 298 | 277 | write(out, "br."); |
|
| 299 | 278 | match op { |
| 303 | 282 | case super::CmpOp::Ult => write(out, "ult"), |
|
| 304 | 283 | } |
|
| 305 | 284 | write(out, " "); |
|
| 306 | 285 | writeType(out, typ); |
|
| 307 | 286 | write(out, " "); |
|
| 308 | - | writeVal(out, a, va); |
|
| 287 | + | writeVal(out, va); |
|
| 309 | 288 | write(out, " "); |
|
| 310 | - | writeVal(out, a, vb); |
|
| 289 | + | writeVal(out, vb); |
|
| 311 | 290 | write(out, " @"); |
|
| 312 | 291 | write(out, blocks[thenTarget].label); |
|
| 313 | 292 | if thenArgs.len > 0 { |
|
| 314 | - | writeArgs(out, a, thenArgs); |
|
| 293 | + | writeArgs(out, thenArgs); |
|
| 315 | 294 | } |
|
| 316 | 295 | write(out, " @"); |
|
| 317 | 296 | write(out, blocks[elseTarget].label); |
|
| 318 | 297 | if elseArgs.len > 0 { |
|
| 319 | - | writeArgs(out, a, elseArgs); |
|
| 298 | + | writeArgs(out, elseArgs); |
|
| 320 | 299 | } |
|
| 321 | 300 | } |
|
| 322 | 301 | case super::Instr::Switch { val, defaultTarget, defaultArgs, cases } => { |
|
| 323 | 302 | write(out, "switch "); |
|
| 324 | - | writeVal(out, a, val); |
|
| 303 | + | writeVal(out, val); |
|
| 325 | 304 | for c in cases { |
|
| 326 | 305 | write(out, " ("); |
|
| 327 | - | write(out, formatI64(a, c.value)); |
|
| 306 | + | writeI64(out, c.value); |
|
| 328 | 307 | write(out, " @"); |
|
| 329 | 308 | write(out, blocks[c.target].label); |
|
| 330 | 309 | if c.args.len > 0 { |
|
| 331 | - | writeArgs(out, a, c.args); |
|
| 310 | + | writeArgs(out, c.args); |
|
| 332 | 311 | } |
|
| 333 | 312 | write(out, ")"); |
|
| 334 | 313 | } |
|
| 335 | 314 | write(out, " @"); |
|
| 336 | 315 | write(out, blocks[defaultTarget].label); |
|
| 337 | 316 | if defaultArgs.len > 0 { |
|
| 338 | - | writeArgs(out, a, defaultArgs); |
|
| 317 | + | writeArgs(out, defaultArgs); |
|
| 339 | 318 | } |
|
| 340 | 319 | } |
|
| 341 | 320 | case super::Instr::Unreachable => { |
|
| 342 | 321 | write(out, "unreachable"); |
|
| 343 | 322 | } |
|
| 344 | 323 | ||
| 345 | 324 | // Intrinsics. |
|
| 346 | 325 | case super::Instr::Ecall { dst, num, a0, a1, a2, a3 } => { |
|
| 347 | 326 | write(out, "ecall "); |
|
| 348 | - | writeReg(out, a, dst); |
|
| 327 | + | writeReg(out, dst); |
|
| 349 | 328 | write(out, " "); |
|
| 350 | - | writeVal(out, a, num); |
|
| 329 | + | writeVal(out, num); |
|
| 351 | 330 | write(out, " "); |
|
| 352 | - | writeVal(out, a, a0); |
|
| 331 | + | writeVal(out, a0); |
|
| 353 | 332 | write(out, " "); |
|
| 354 | - | writeVal(out, a, a1); |
|
| 333 | + | writeVal(out, a1); |
|
| 355 | 334 | write(out, " "); |
|
| 356 | - | writeVal(out, a, a2); |
|
| 335 | + | writeVal(out, a2); |
|
| 357 | 336 | write(out, " "); |
|
| 358 | - | writeVal(out, a, a3); |
|
| 337 | + | writeVal(out, a3); |
|
| 359 | 338 | } |
|
| 360 | 339 | case super::Instr::Ebreak => { |
|
| 361 | 340 | write(out, "ebreak"); |
|
| 362 | 341 | } |
|
| 363 | 342 | case super::Instr::MemoryFence => { |
| 367 | 346 | } |
|
| 368 | 347 | ||
| 369 | 348 | /// Write a typed binary operation: `op type %dst %a %b`. |
|
| 370 | 349 | fn writeTypedBinOp( |
|
| 371 | 350 | out: *mut sexpr::Output, |
|
| 372 | - | a: *mut alloc::Arena, |
|
| 373 | 351 | name: *[u8], |
|
| 374 | 352 | typ: super::Type, |
|
| 375 | 353 | dst: super::Reg, |
|
| 376 | 354 | va: super::Val, |
|
| 377 | 355 | vb: super::Val |
|
| 378 | 356 | ) { |
|
| 379 | 357 | write(out, name); |
|
| 380 | 358 | write(out, " "); |
|
| 381 | 359 | writeType(out, typ); |
|
| 382 | 360 | write(out, " "); |
|
| 383 | - | writeReg(out, a, dst); |
|
| 361 | + | writeReg(out, dst); |
|
| 384 | 362 | write(out, " "); |
|
| 385 | - | writeVal(out, a, va); |
|
| 363 | + | writeVal(out, va); |
|
| 386 | 364 | write(out, " "); |
|
| 387 | - | writeVal(out, a, vb); |
|
| 365 | + | writeVal(out, vb); |
|
| 388 | 366 | } |
|
| 389 | 367 | ||
| 390 | 368 | /// Write a typed unary operation: `op type %dst %val`. |
|
| 391 | 369 | fn writeTypedUnaryOp( |
|
| 392 | 370 | out: *mut sexpr::Output, |
|
| 393 | - | a: *mut alloc::Arena, |
|
| 394 | 371 | name: *[u8], |
|
| 395 | 372 | typ: super::Type, |
|
| 396 | 373 | dst: super::Reg, |
|
| 397 | 374 | val: super::Val |
|
| 398 | 375 | ) { |
|
| 399 | 376 | write(out, name); |
|
| 400 | 377 | write(out, " "); |
|
| 401 | 378 | writeType(out, typ); |
|
| 402 | 379 | write(out, " "); |
|
| 403 | - | writeReg(out, a, dst); |
|
| 380 | + | writeReg(out, dst); |
|
| 404 | 381 | write(out, " "); |
|
| 405 | - | writeVal(out, a, val); |
|
| 382 | + | writeVal(out, val); |
|
| 406 | 383 | } |
|
| 407 | 384 | ||
| 408 | 385 | //////////////////// |
|
| 409 | 386 | // Block printing // |
|
| 410 | 387 | //////////////////// |
|
| 411 | 388 | ||
| 412 | 389 | /// Write a basic block. |
|
| 413 | - | fn writeBlock(out: *mut sexpr::Output, a: *mut alloc::Arena, blocks: *[super::Block], block: *super::Block) { |
|
| 390 | + | fn writeBlock(out: *mut sexpr::Output, blocks: *[super::Block], block: *super::Block) { |
|
| 414 | 391 | // Block label. |
|
| 415 | 392 | write(out, " @"); |
|
| 416 | 393 | write(out, block.label); |
|
| 417 | 394 | ||
| 418 | 395 | // Block parameters. |
|
| 419 | 396 | if block.params.len > 0 { |
|
| 420 | 397 | write(out, "("); |
|
| 421 | - | writeParams(out, a, block.params); |
|
| 398 | + | writeParams(out, block.params); |
|
| 422 | 399 | write(out, ")"); |
|
| 423 | 400 | } |
|
| 424 | 401 | write(out, "\n"); |
|
| 425 | 402 | ||
| 426 | 403 | // Instructions. |
|
| 427 | 404 | for instr in block.instrs { |
|
| 428 | 405 | indent(out, 1); |
|
| 429 | - | writeInstr(out, a, blocks, instr); |
|
| 406 | + | writeInstr(out, blocks, instr); |
|
| 430 | 407 | write(out, ";\n"); |
|
| 431 | 408 | } |
|
| 432 | 409 | } |
|
| 433 | 410 | ||
| 434 | 411 | /////////////////////// |
|
| 435 | 412 | // Function printing // |
|
| 436 | 413 | /////////////////////// |
|
| 437 | 414 | ||
| 438 | 415 | /// Write a function. |
|
| 439 | - | fn writeFn(out: *mut sexpr::Output, a: *mut alloc::Arena, f: *super::Fn) { |
|
| 416 | + | fn writeFn(out: *mut sexpr::Output, f: *super::Fn) { |
|
| 440 | 417 | // Function signature. |
|
| 441 | 418 | if f.isExtern { |
|
| 442 | 419 | write(out, "extern "); |
|
| 443 | 420 | } |
|
| 444 | 421 | write(out, "fn "); |
|
| 445 | 422 | writeType(out, f.returnType); |
|
| 446 | 423 | write(out, " "); |
|
| 447 | 424 | writeSymbol(out, f.name); |
|
| 448 | 425 | write(out, "("); |
|
| 449 | - | writeParams(out, a, f.params); |
|
| 426 | + | writeParams(out, f.params); |
|
| 450 | 427 | write(out, ")"); |
|
| 451 | 428 | ||
| 452 | 429 | // Extern functions have no body. |
|
| 453 | 430 | if f.isExtern { |
|
| 454 | 431 | write(out, ";\n"); |
| 457 | 434 | write(out, " {\n"); |
|
| 458 | 435 | ||
| 459 | 436 | // Blocks. |
|
| 460 | 437 | for i in 0..f.blocks.len { |
|
| 461 | 438 | if f.blocks[i].instrs.len > 0 { |
|
| 462 | - | writeBlock(out, a, f.blocks, &f.blocks[i]); |
|
| 439 | + | writeBlock(out, f.blocks, &f.blocks[i]); |
|
| 463 | 440 | } |
|
| 464 | 441 | } |
|
| 465 | 442 | write(out, "}\n"); |
|
| 466 | 443 | } |
|
| 467 | 444 | ||
| 468 | 445 | /////////////////// |
|
| 469 | 446 | // Data printing // |
|
| 470 | 447 | /////////////////// |
|
| 471 | 448 | ||
| 472 | 449 | /// Write a data item. |
|
| 473 | - | fn writeDataItem(out: *mut sexpr::Output, a: *mut alloc::Arena, item: super::DataItem) { |
|
| 450 | + | fn writeDataItem(out: *mut sexpr::Output, item: super::DataItem) { |
|
| 474 | 451 | match item { |
|
| 475 | 452 | case super::DataItem::Val { typ, val } => { |
|
| 476 | 453 | writeType(out, typ); |
|
| 477 | 454 | write(out, " "); |
|
| 478 | - | write(out, formatI64(a, val)); |
|
| 455 | + | writeI64(out, val); |
|
| 479 | 456 | } |
|
| 480 | 457 | case super::DataItem::Sym(name) => { |
|
| 481 | 458 | write(out, "sym "); |
|
| 482 | 459 | writeSymbol(out, name); |
|
| 483 | 460 | } |
| 494 | 471 | } |
|
| 495 | 472 | } |
|
| 496 | 473 | } |
|
| 497 | 474 | ||
| 498 | 475 | /// Write a data value (item with optional repeat count). |
|
| 499 | - | fn writeDataValue(out: *mut sexpr::Output, a: *mut alloc::Arena, value: super::DataValue) { |
|
| 500 | - | writeDataItem(out, a, value.item); |
|
| 476 | + | fn writeDataValue(out: *mut sexpr::Output, value: super::DataValue) { |
|
| 477 | + | writeDataItem(out, value.item); |
|
| 501 | 478 | if value.count > 1 { |
|
| 502 | 479 | write(out, " * "); |
|
| 503 | - | write(out, formatU32(a, value.count)); |
|
| 480 | + | writeU32(out, value.count); |
|
| 504 | 481 | } |
|
| 505 | 482 | } |
|
| 506 | 483 | ||
| 507 | 484 | /// Write global data. |
|
| 508 | - | fn writeData(out: *mut sexpr::Output, a: *mut alloc::Arena, d: super::Data) { |
|
| 485 | + | fn writeData(out: *mut sexpr::Output, d: super::Data) { |
|
| 509 | 486 | write(out, "data "); |
|
| 510 | 487 | if not d.readOnly { |
|
| 511 | 488 | write(out, "mut "); |
|
| 512 | 489 | } |
|
| 513 | 490 | writeSymbol(out, d.name); |
|
| 514 | 491 | write(out, " align "); |
|
| 515 | - | write(out, formatU32(a, d.alignment)); |
|
| 492 | + | writeU32(out, d.alignment); |
|
| 516 | 493 | write(out, " {\n"); |
|
| 517 | 494 | ||
| 518 | 495 | for v in d.values { |
|
| 519 | 496 | indent(out, 1); |
|
| 520 | - | writeDataValue(out, a, v); |
|
| 497 | + | writeDataValue(out, v); |
|
| 521 | 498 | write(out, ";\n"); |
|
| 522 | 499 | } |
|
| 523 | 500 | write(out, "}\n"); |
|
| 524 | 501 | } |
|
| 525 | 502 | ||
| 526 | 503 | ////////////////////// |
|
| 527 | 504 | // Program printing // |
|
| 528 | 505 | ////////////////////// |
|
| 529 | 506 | ||
| 530 | 507 | /// Print a program. |
|
| 531 | - | export fn printProgram(out: *mut sexpr::Output, a: *mut alloc::Arena, program: *super::Program) { |
|
| 508 | + | export fn printProgram(out: *mut sexpr::Output, program: *super::Program) { |
|
| 532 | 509 | // Data declarations. |
|
| 533 | 510 | for data, i in program.data { |
|
| 534 | - | writeData(out, a, data); |
|
| 511 | + | writeData(out, data); |
|
| 535 | 512 | if i < program.data.len - 1 or program.fns.len > 0 { |
|
| 536 | 513 | write(out, "\n"); |
|
| 537 | 514 | } |
|
| 538 | 515 | } |
|
| 539 | 516 | // Functions. |
|
| 540 | 517 | for func, i in program.fns { |
|
| 541 | - | writeFn(out, a, func); |
|
| 518 | + | writeFn(out, func); |
|
| 542 | 519 | if i < program.fns.len - 1 { |
|
| 543 | 520 | write(out, "\n"); |
|
| 544 | 521 | } |
|
| 545 | 522 | } |
|
| 546 | 523 | } |
|
| 547 | 524 | ||
| 548 | 525 | /// Print a program to a buffer, returning the written slice. |
|
| 549 | 526 | export fn printProgramToBuffer( |
|
| 550 | 527 | program: *super::Program, |
|
| 551 | - | arena: *mut alloc::Arena, |
|
| 552 | 528 | buf: *mut [u8] |
|
| 553 | 529 | ) -> *[u8] { |
|
| 554 | 530 | let mut pos: u32 = 0; |
|
| 555 | 531 | let mut out = sexpr::Output::Buffer { buf, pos: &mut pos }; |
|
| 556 | - | printProgram(&mut out, arena, program); |
|
| 532 | + | printProgram(&mut out, program); |
|
| 557 | 533 | ||
| 558 | 534 | return &buf[..pos]; |
|
| 559 | 535 | } |
test/runner.rad
+1 -3
| 51 | 51 | static SOURCE_BUF: [u8; SOURCE_BUF_SIZE] = undefined; |
|
| 52 | 52 | static EXPECTED_BUF: [u8; EXPECTED_BUF_SIZE] = undefined; |
|
| 53 | 53 | static OUTPUT_BUF: [u8; OUTPUT_BUF_SIZE] = undefined; |
|
| 54 | 54 | static AST_ARENA_STORAGE: [u8; ARENA_SIZE] = undefined; |
|
| 55 | 55 | static IL_ARENA_STORAGE: [u8; ARENA_SIZE] = undefined; |
|
| 56 | - | static PRINT_ARENA_STORAGE: [u8; ARENA_SIZE] = undefined; |
|
| 57 | 56 | static RESOLVER_ARENA_STORAGE: [u8; ARENA_SIZE] = undefined; |
|
| 58 | 57 | static NODE_DATA_STORAGE: [resolver::NodeData; MAX_NODE_DATA] = undefined; |
|
| 59 | 58 | static ERROR_STORAGE: [resolver::Error; MAX_ERRORS] = undefined; |
|
| 60 | 59 | static ASM_TEXT_STORAGE: [u32; ASM_TEXT_CAPACITY] = undefined; |
|
| 61 | 60 | static ASM_DATA_STORAGE: [u8; ASM_DATA_CAPACITY] = undefined; |
| 274 | 273 | io::printLn(""); |
|
| 275 | 274 | return false; |
|
| 276 | 275 | }; |
|
| 277 | 276 | ||
| 278 | 277 | // Print IL to buffer. |
|
| 279 | - | let mut printArena = alloc::new(&mut PRINT_ARENA_STORAGE[..]); |
|
| 280 | - | let actual = printer::printProgramToBuffer(&program, &mut printArena, &mut OUTPUT_BUF[..]); |
|
| 278 | + | let actual = printer::printProgramToBuffer(&program, &mut OUTPUT_BUF[..]); |
|
| 281 | 279 | ||
| 282 | 280 | // Compare ignoring comments. |
|
| 283 | 281 | if not stringsEqual(actual, expected) { |
|
| 284 | 282 | io::printLn("FAILED"); |
|
| 285 | 283 | printDiff(expected, actual); |