rv64: Support explicit native image placement
b7fbdab541ab75219d3d24f5c5c1e85e7fb1a7e6c47eef701ca65bc6e6512b2a
Assisted-by: Codex:gpt-6
1 parent
8e1da2cd
test/native/build.rad
added
+90 -0
| 1 | + | //! Build a native machine fixture with the reusable RV64 backend. |
|
| 2 | + | ||
| 3 | + | use std::sys; |
|
| 4 | + | use std::sys::unix; |
|
| 5 | + | use std::lang::il; |
|
| 6 | + | use std::lang::alloc; |
|
| 7 | + | use std::lang::gen::data; |
|
| 8 | + | use std::collections::dict; |
|
| 9 | + | use std::arch::rv64; |
|
| 10 | + | use std::arch::rv64::image; |
|
| 11 | + | ||
| 12 | + | /// Persistent code generation arena. |
|
| 13 | + | static MEMORY: [u8; 16777216] = [0; 16777216]; |
|
| 14 | + | /// Function lowering and allocation workspace. |
|
| 15 | + | static SCRATCH: [u8; 16777216] = [0; 16777216]; |
|
| 16 | + | /// Data symbol lookup workspace. |
|
| 17 | + | unsafe static ENTRIES: [dict::Entry; data::DATA_SYM_TABLE_SIZE] = undefined; |
|
| 18 | + | ||
| 19 | + | /// Compile data accesses and conditional finish writes into a native image. |
|
| 20 | + | @default unsafe fn main(env: *sys::Env) -> i32 { |
|
| 21 | + | assert env.args.len == 2; |
|
| 22 | + | let mut arena = alloc::new(&mut MEMORY[..]); |
|
| 23 | + | let mut scratch = alloc::new(&mut SCRATCH[..]); |
|
| 24 | + | let mut generator = rv64::beginProgram(rv64::ProgramOptions { |
|
| 25 | + | entryPatch: rv64::EntryPatch::None, debug: false, |
|
| 26 | + | placement: image::Placement::Physical { |
|
| 27 | + | code: 0x80010000, roData: 0x80018000, rwData: 0x80020000, entry: 0x80010000, |
|
| 28 | + | }, |
|
| 29 | + | }, &mut arena); |
|
| 30 | + | let mut args: [il::Val; 0] = []; |
|
| 31 | + | let mut entry = [ |
|
| 32 | + | il::Instr::Copy { dst: il::Reg { n: 0 }, val: il::Val::DataSym("fixture::value") }, |
|
| 33 | + | il::Instr::Load { typ: il::Type::W64, dst: il::Reg { n: 1 }, src: il::Reg { n: 0 }, offset: 0 }, |
|
| 34 | + | il::Instr::Br { |
|
| 35 | + | op: il::CmpOp::Eq, typ: il::Type::W64, a: il::Val::Reg(il::Reg { n: 1 }), b: il::Val::Imm(42), |
|
| 36 | + | thenTarget: 1, thenArgs: &mut args[..], elseTarget: 3, elseArgs: &mut args[..], |
|
| 37 | + | }, |
|
| 38 | + | ]; |
|
| 39 | + | let mut zero = [ |
|
| 40 | + | il::Instr::Copy { dst: il::Reg { n: 2 }, val: il::Val::DataSym("fixture::zero") }, |
|
| 41 | + | il::Instr::Load { typ: il::Type::W64, dst: il::Reg { n: 3 }, src: il::Reg { n: 2 }, offset: 0 }, |
|
| 42 | + | il::Instr::Br { |
|
| 43 | + | op: il::CmpOp::Eq, typ: il::Type::W64, a: il::Val::Reg(il::Reg { n: 3 }), b: il::Val::Imm(0), |
|
| 44 | + | thenTarget: 2, thenArgs: &mut args[..], elseTarget: 3, elseArgs: &mut args[..], |
|
| 45 | + | }, |
|
| 46 | + | ]; |
|
| 47 | + | let mut success = [ |
|
| 48 | + | il::Instr::Copy { dst: il::Reg { n: 4 }, val: il::Val::Imm(0x10001000) }, |
|
| 49 | + | il::Instr::Store { typ: il::Type::W32, src: il::Val::Imm(0x5555), dst: il::Reg { n: 4 }, offset: 0 }, |
|
| 50 | + | il::Instr::Unreachable, |
|
| 51 | + | ]; |
|
| 52 | + | let mut failure = [ |
|
| 53 | + | il::Instr::Copy { dst: il::Reg { n: 5 }, val: il::Val::Imm(0x10001000) }, |
|
| 54 | + | il::Instr::Store { typ: il::Type::W32, src: il::Val::Imm(0x13333), dst: il::Reg { n: 5 }, offset: 0 }, |
|
| 55 | + | il::Instr::Unreachable, |
|
| 56 | + | ]; |
|
| 57 | + | let func = il::Fn { |
|
| 58 | + | name: "fixture::entry", params: &[], returnType: il::Type::W64, isExtern: false, isLeaf: true, |
|
| 59 | + | blocks: &[ |
|
| 60 | + | il::Block { label: "entry", params: &[], instrs: &mut entry[..], locs: &[], preds: &[], loopDepth: 0 }, |
|
| 61 | + | il::Block { label: "zero", params: &[], instrs: &mut zero[..], locs: &[], preds: &[0], loopDepth: 0 }, |
|
| 62 | + | il::Block { label: "success", params: &[], instrs: &mut success[..], locs: &[], preds: &[1], loopDepth: 0 }, |
|
| 63 | + | il::Block { label: "failure", params: &[], instrs: &mut failure[..], locs: &[], preds: &[0, 1], loopDepth: 0 }, |
|
| 64 | + | ], |
|
| 65 | + | }; |
|
| 66 | + | rv64::generateFunction(&mut generator, &func, &mut scratch); |
|
| 67 | + | let globals = &[ |
|
| 68 | + | il::Data { |
|
| 69 | + | name: "fixture::value", size: 8, alignment: 8, readOnly: false, isZeroInit: false, |
|
| 70 | + | values: &[il::DataValue { item: il::DataItem::Val { typ: il::Type::W64, val: 42 }, count: 1 }], |
|
| 71 | + | }, |
|
| 72 | + | il::Data { |
|
| 73 | + | name: "fixture::zero", size: 4096, alignment: 8, readOnly: false, isZeroInit: true, values: &[], |
|
| 74 | + | }, |
|
| 75 | + | ]; |
|
| 76 | + | unsafe static symbols: [data::DataSym; 2] = undefined; |
|
| 77 | + | let mut ro: [u8; 8] = [0; 8]; |
|
| 78 | + | let mut rw: [u8; 8] = [0; 8]; |
|
| 79 | + | let result = try! rv64::finishProgram(&mut generator, globals, |
|
| 80 | + | rv64::Storage { dataSyms: &mut symbols[..], dataSymEntries: &mut ENTRIES[..] }, |
|
| 81 | + | &[], &mut ro[..], &mut rw[..]); |
|
| 82 | + | let header = try! image::header(result.layout); |
|
| 83 | + | let code = @sliceOf(result.code.ptr as *u8, result.code.len * 4); |
|
| 84 | + | let fd = unix::openOpts(env.args[1], unix::OpenFlags(*unix::O_WRONLY | *unix::O_CREAT | *unix::O_TRUNC), 420); |
|
| 85 | + | assert fd >= 0; |
|
| 86 | + | let written = unix::writeAll(fd, &header[..]) and unix::writeAll(fd, code) and unix::writeAll(fd, &ro[..result.roDataSize]) and unix::writeAll(fd, &rw[..result.rwDataSize]); |
|
| 87 | + | let closed = unix::close(fd) == 0; |
|
| 88 | + | assert written and closed; |
|
| 89 | + | return 0; |
|
| 90 | + | } |