compiler: Check binary instruction and switch encoding
9b1ca970d96ade65f0b940b1e2890059f8d1fe20451dd525ba5a686232406547
1 parent
81eb8a8d
lib/std/lang/il/binary/tests.rad
+14 -0
| 315 | 315 | }, &[ |
|
| 316 | 316 | 14, 4, 1, 0, 0, 0, 1, 0, 0, 0, 4, 1, |
|
| 317 | 317 | 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 2, |
|
| 318 | 318 | 0, 0, 0, 1, 0, 0, 0, 4, |
|
| 319 | 319 | ]); |
|
| 320 | + | try instruction(il::Instr::Switch { |
|
| 321 | + | val: il::Val::Undef, defaultTarget: 1, defaultArgs: &mut [], cases: &mut [], |
|
| 322 | + | }, &[14, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); |
|
| 323 | + | let mut mixedCases = [ |
|
| 324 | + | il::SwitchCase { value: -9223372036854775808, target: 0, args: &mut [] }, |
|
| 325 | + | il::SwitchCase { value: 9223372036854775807, target: 2, args: &mut args[..] }, |
|
| 326 | + | ]; |
|
| 327 | + | try instruction(il::Instr::Switch { |
|
| 328 | + | val: il::Val::Undef, defaultTarget: 1, defaultArgs: &mut [], cases: &mut mixedCases[..], |
|
| 329 | + | }, &[ |
|
| 330 | + | 14, 4, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, |
|
| 331 | + | 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, |
|
| 332 | + | 255, 255, 255, 255, 255, 255, 255, 127, 2, 0, 0, 0, 1, 0, 0, 0, 4, |
|
| 333 | + | ]); |
|
| 320 | 334 | try instruction(il::Instr::Unreachable, &[15]); |
|
| 321 | 335 | try instruction(il::Instr::Ecall { |
|
| 322 | 336 | dst: il::Reg { n: 1 }, num: il::Val::Undef, a0: il::Val::Undef, a1: il::Val::Undef, |
|
| 323 | 337 | a2: il::Val::Undef, a3: il::Val::Undef, |
|
| 324 | 338 | }, &[16, 1, 0, 0, 0, 4, 4, 4, 4, 4]); |
lib/std/lang/il/binary/writer.rad
+35 -12
| 251 | 251 | } |
|
| 252 | 252 | ||
| 253 | 253 | /// Write one instruction. Fields follow the IL record declaration order. |
|
| 254 | 254 | /// All raw instruction operand tables must remain valid during encoding. |
|
| 255 | 255 | export unsafe fn instr 'buffer (out: &mut Writer 'buffer, item: il::Instr) throws (binary::Error) { |
|
| 256 | - | match item { |
|
| 256 | + | try writeInstr(out, &item); |
|
| 257 | + | } |
|
| 258 | + | ||
| 259 | + | /// Write instruction fields and acquire nested operand views at their wire position. |
|
| 260 | + | fn writeInstr 'buffer (out: &mut Writer 'buffer, item: &il::Instr) throws (binary::Error) { |
|
| 261 | + | match *item { |
|
| 257 | 262 | case il::Instr::Call { retTy: vretTy, dst: vdst, func: vfunc, args: vargs } => { |
|
| 258 | 263 | try integer(out, super::INSTR_CALL as u64, 1); |
|
| 259 | 264 | try typ(out, vretTy); |
|
| 260 | 265 | if let present = vdst { |
|
| 261 | 266 | try integer(out, 1, 1); |
|
| 262 | 267 | try integer(out, present.n as u64, 4); |
|
| 263 | 268 | } else { |
|
| 264 | 269 | try integer(out, 0, 1); |
|
| 265 | 270 | } |
|
| 266 | 271 | try val(out, vfunc); |
|
| 267 | - | try values(out, vargs); |
|
| 272 | + | unsafe { |
|
| 273 | + | try values(out, vargs); |
|
| 274 | + | } |
|
| 268 | 275 | }, |
|
| 269 | 276 | case il::Instr::Jmp { target: vtarget, args: vargs } => { |
|
| 270 | 277 | try integer(out, super::INSTR_JMP as u64, 1); |
|
| 271 | 278 | try integer(out, vtarget as u64, 4); |
|
| 272 | - | try values(out, vargs); |
|
| 279 | + | unsafe { |
|
| 280 | + | try values(out, vargs); |
|
| 281 | + | } |
|
| 273 | 282 | }, |
|
| 274 | 283 | case il::Instr::Br { op: vop, typ: vtyp, a: va, b: vb, thenTarget: vthenTarget, thenArgs: vthenArgs, elseTarget: velseTarget, elseArgs: velseArgs } => { |
|
| 275 | 284 | try integer(out, super::INSTR_BR as u64, 1); |
|
| 276 | 285 | try cmpOp(out, vop); |
|
| 277 | 286 | try typ(out, vtyp); |
|
| 278 | 287 | try val(out, va); |
|
| 279 | 288 | try val(out, vb); |
|
| 280 | 289 | try integer(out, vthenTarget as u64, 4); |
|
| 281 | - | try values(out, vthenArgs); |
|
| 290 | + | unsafe { |
|
| 291 | + | try values(out, vthenArgs); |
|
| 292 | + | } |
|
| 282 | 293 | try integer(out, velseTarget as u64, 4); |
|
| 283 | - | try values(out, velseArgs); |
|
| 294 | + | unsafe { |
|
| 295 | + | try values(out, velseArgs); |
|
| 296 | + | } |
|
| 284 | 297 | }, |
|
| 285 | 298 | case il::Instr::Switch { val: vval, defaultTarget: vdefaultTarget, defaultArgs: vdefaultArgs, cases: vcases } => { |
|
| 286 | 299 | try integer(out, super::INSTR_SWITCH as u64, 1); |
|
| 287 | 300 | try val(out, vval); |
|
| 288 | 301 | try integer(out, vdefaultTarget as u64, 4); |
|
| 289 | - | try values(out, vdefaultArgs); |
|
| 290 | - | try integer(out, vcases.len as u64, 4); |
|
| 291 | - | for branch in vcases { |
|
| 292 | - | try integer(out, branch.value as u64, 8); |
|
| 293 | - | try integer(out, branch.target as u64, 4); |
|
| 294 | - | try values(out, branch.args); |
|
| 302 | + | unsafe { |
|
| 303 | + | try values(out, vdefaultArgs); |
|
| 304 | + | try writeCases(out, vcases); |
|
| 295 | 305 | } |
|
| 296 | 306 | }, |
|
| 297 | - | else => try fixedInstr(out, item), |
|
| 307 | + | else => try fixedInstr(out, *item), |
|
| 308 | + | } |
|
| 309 | + | } |
|
| 310 | + | ||
| 311 | + | /// Write a counted switch-case table with signed values and argument groups. |
|
| 312 | + | fn writeCases 'buffer (out: &mut Writer 'buffer, cases: &[il::SwitchCase]) throws (binary::Error) { |
|
| 313 | + | try integer(out, cases.len as u64, 4); |
|
| 314 | + | for i in 0..cases.len { |
|
| 315 | + | let branch = &cases[i]; |
|
| 316 | + | try integer(out, branch.value as u64, 8); |
|
| 317 | + | try integer(out, branch.target as u64, 4); |
|
| 318 | + | unsafe { |
|
| 319 | + | try values(out, branch.args); |
|
| 320 | + | } |
|
| 298 | 321 | } |
|
| 299 | 322 | } |
|
| 300 | 323 | ||
| 301 | 324 | /// Write one data initializer and its repetition count. |
|
| 302 | 325 | export fn dataValue 'buffer (out: &mut Writer 'buffer, value: il::DataValue) throws (binary::Error) { |