rv64: Support explicit native image placement

b7fbdab541ab75219d3d24f5c5c1e85e7fb1a7e6c47eef701ca65bc6e6512b2a
Assisted-by: Codex:gpt-6
Alexis Sellier committed ago 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 +
}