compiler: Check binary function and block encoding

81eb8a8d3de0eb33027a238fc87f57d38d9007037de920d5f164eb92e5f0efa7
Alexis Sellier committed ago 1 parent 9e618540
lib/std/lang/il/binary/decodeTests.rad +19 -0
49 49
    };
50 50
    try testing::expectBytesEq(decoded.name, package.name);
51 51
    try testing::expect(decoded.dependencies.len == package.dependencies.len);
52 52
    try testing::expect(decoded.exports.len == package.exports.len);
53 53
    try testing::expect(decoded.program.fns.len == package.program.fns.len);
54 +
    for original, i in package.program.fns {
55 +
        let restored = decoded.program.fns[i];
56 +
        assert restored.blocks.len == original.blocks.len;
57 +
        for block, j in original.blocks {
58 +
            let rebuilt = &restored.blocks[j];
59 +
            try testing::expectBytesEq(rebuilt.label, block.label);
60 +
            assert rebuilt.loopDepth == block.loopDepth;
61 +
            assert rebuilt.params.len == block.params.len;
62 +
            for param, k in block.params {
63 +
                assert rebuilt.params[k].value.n == param.value.n;
64 +
                assert rebuilt.params[k].type == param.type;
65 +
            }
66 +
            assert rebuilt.preds.len == block.preds.len;
67 +
            for pred, k in block.preds { assert rebuilt.preds[k] == pred; }
68 +
        }
69 +
    }
54 70
    let mut encoded: [u8; 2048] = [0; 2048];
55 71
    let repeated = try program::encode(&mut encoded[..], &decoded) catch {
56 72
        throw testing::TestError::Failed;
57 73
    };
58 74
    try testing::expectBytesEq(&buffer[..length], &encoded[..repeated]);
135 151
    ];
136 152
    let func = il::Fn {
137 153
        name: "p::main", params, returnType: il::Type::W64, isExtern: false, isLeaf: false,
138 154
        blocks: &[il::Block {
139 155
            label: "entry", params: &[], instrs: &mut instrs[..], locs: &[], preds: &[0], loopDepth: 2,
156 +
        }, il::Block {
157 +
            label: "empty", params: &[il::Param { value: il::Reg { n: 3 }, type: il::Type::W32 }],
158 +
            instrs: &mut [], locs: &[], preds: &[0, 1], loopDepth: 0,
140 159
        }],
141 160
    };
142 161
    let external = il::Fn {
143 162
        name: "dep::fn", params, returnType: il::Type::W64, isExtern: true, isLeaf: true, blocks: &[],
144 163
    };
lib/std/lang/il/binary/program.rad +57 -21
75 75
export unsafe fn encode(bytes: &mut [u8], package: &binary::Package) -> u32 throws (binary::Error) {
76 76
    let output: 'output = &mut bytes[..], symbols = &package.symbols[..] in {
77 77
        let mut out = writer::new(output, symbols);
78 78
        try writeHeader(&mut out, symbols, package.name, package.dependencies, package.exports, package.entry);
79 79
        try writeData(&mut out, &package.program.data[..]);
80 -
        try writer::integer(&mut out, package.program.fns.len as u64, 4);
81 -
        for func in package.program.fns {
82 -
            try writer::symbol(&mut out, func.name);
83 -
            try writer::typ(&mut out, func.returnType);
84 -
            try writer::integer(&mut out, 1 if func.isExtern else 0, 1);
85 -
            try writeParams(&mut out, func.params);
86 -
            try writer::integer(&mut out, func.blocks.len as u64, 4);
87 -
            for block in func.blocks {
88 -
                try writer::bytes(&mut out, block.label);
89 -
                try writeParams(&mut out, block.params);
90 -
                try writer::integer(&mut out, block.loopDepth as u64, 4);
91 -
                try writer::integer(&mut out, block.preds.len as u64, 4);
92 -
                for pred in block.preds {
93 -
                    try writer::integer(&mut out, pred as u64, 4);
94 -
                }
95 -
                try writer::integer(&mut out, block.instrs.len as u64, 4);
96 -
                for instr in block.instrs {
97 -
                    try writer::instr(&mut out, instr);
98 -
                }
99 -
            }
100 -
        }
80 +
        try writeFunctions(&mut out, package.program.fns);
101 81
        return out.offset;
102 82
    }
103 83
}
104 84
85 +
/// Write a counted function-pointer table in wire order.
86 +
fn writeFunctions 'buffer (out: &mut writer::Writer 'buffer, functions: &[*unsafe il::Fn]) throws (binary::Error) {
87 +
    try writer::integer(out, functions.len as u64, 4);
88 +
    for i in 0..functions.len {
89 +
        unsafe {
90 +
            try writeFunction(out, functions[i]);
91 +
        }
92 +
    }
93 +
}
94 +
95 +
/// Write function metadata before its parameter and block tables.
96 +
fn writeFunction 'buffer (out: &mut writer::Writer 'buffer, func: &il::Fn) throws (binary::Error) {
97 +
    try writer::symbol(out, func.name);
98 +
    try writer::typ(out, func.returnType);
99 +
    try writer::integer(out, 1 if func.isExtern else 0, 1);
100 +
    unsafe {
101 +
        try writeParams(out, func.params);
102 +
        try writeBlocks(out, func.blocks);
103 +
    }
104 +
}
105 +
106 +
/// Write a counted block table in function order.
107 +
fn writeBlocks 'buffer (out: &mut writer::Writer 'buffer, blocks: &[il::Block]) throws (binary::Error) {
108 +
    try writer::integer(out, blocks.len as u64, 4);
109 +
    for i in 0..blocks.len {
110 +
        let block = &blocks[i];
111 +
        unsafe {
112 +
            try writeBlock(out, block.label, block.params, block.loopDepth, block.preds, block.instrs);
113 +
        }
114 +
    }
115 +
}
116 +
117 +
/// Write block metadata and counted predecessor and instruction tables.
118 +
fn writeBlock 'buffer (
119 +
    out: &mut writer::Writer 'buffer,
120 +
    label: *[u8],
121 +
    params: &[il::Param],
122 +
    loopDepth: u32,
123 +
    preds: &[u32],
124 +
    instructions: &[il::Instr],
125 +
) throws (binary::Error) {
126 +
    try writer::bytes(out, label);
127 +
    try writeParams(out, params);
128 +
    try writer::integer(out, loopDepth as u64, 4);
129 +
    try writer::integer(out, preds.len as u64, 4);
130 +
    for pred in preds {
131 +
        try writer::integer(out, pred as u64, 4);
132 +
    }
133 +
    try writer::integer(out, instructions.len as u64, 4);
134 +
    for instr in instructions {
135 +
        unsafe {
136 +
            try writer::instr(out, instr);
137 +
        }
138 +
    }
139 +
}
140 +
105 141
/// Read typed SSA parameters with checked register indices.
106 142
unsafe fn readParams 'input (input: &mut reader::Reader 'input) -> *unsafe [il::Param] throws (binary::Error) {
107 143
    let n = try reader::count(input, 5);
108 144
    let params = try reader::storage(input, @sizeOf(il::Param), @alignOf(il::Param), n)
109 145
        as *mut [il::Param];