compiler/
lib/
examples/
std/
arch/
char/
collections/
graph/
lang/
alloc/
ast/
gen/
il/
binary/
binary.rad
5.9 KiB
printer.rad
16.0 KiB
published.rad
13.4 KiB
publishedTests.rad
8.7 KiB
tests.rad
14.7 KiB
module/
parser/
resolver/
scanner/
alloc.rad
7.1 KiB
ast.rad
26.9 KiB
gen.rad
513 B
il.rad
20.4 KiB
lower.rad
321.7 KiB
module.rad
17.3 KiB
package.rad
1.3 KiB
parser.rad
92.2 KiB
resolver.rad
511.1 KiB
scanner.rad
17.9 KiB
sexpr.rad
6.7 KiB
strings.rad
2.2 KiB
types.rad
1.6 KiB
sys/
arch.rad
68 B
char.rad
855 B
collections.rad
39 B
fmt.rad
8.3 KiB
graph.rad
4.3 KiB
intrinsics.rad
467 B
io.rad
1.7 KiB
lang.rad
276 B
mem.rad
2.3 KiB
sys.rad
179 B
testing.rad
2.4 KiB
tests.rad
15.7 KiB
vec.rad
3.2 KiB
std.rad
299 B
scripts/
seed/
sublime/
test/
vim/
.gitignore
336 B
.gitsigners
112 B
CELL_PERMISSIONS
6.8 KiB
CONTRIBUTING
2.1 KiB
LICENSE
1.1 KiB
Makefile
5.4 KiB
README
2.5 KiB
STYLE
2.5 KiB
std.lib
1.5 KiB
std.lib.test
808 B
lib/std/lang/il/publishedTests.rad
raw
| 1 | //! Checked traversal of published IL operand tables. |
| 2 | |
| 3 | use std::testing; |
| 4 | use std::lang::alloc; |
| 5 | use std::lang::il; |
| 6 | use std::lang::il::published; |
| 7 | |
| 8 | /// Checked instruction construction preserves argument order and repeated uses. |
| 9 | @test fn testCheckedInstruction() throws (testing::TestError) { |
| 10 | static DATA: [u8; 4096] = [0; 4096]; |
| 11 | let mut arena = alloc::new(&mut DATA[..]); |
| 12 | use arena as storage in { |
| 13 | let instruction = try! buildCall(&storage); |
| 14 | assert published::identity(&instruction) == nil; |
| 15 | assert published::isCall(&instruction); |
| 16 | let destination = published::destination(&instruction) else panic; |
| 17 | assert destination.n == 9; |
| 18 | let regs = published::registers(&instruction); |
| 19 | assert regs.len == 3 and regs[0].n == 2 and regs[1].n == 7 and regs[2].n == 7; |
| 20 | assert published::successors(&instruction).len == 0; |
| 21 | } |
| 22 | } |
| 23 | |
| 24 | /// Construct a call whose argument source ends with this stack frame. |
| 25 | fn buildCall 'view (storage: &Session 'view) |
| 26 | -> published::Instruction 'view throws (alloc::AllocError) |
| 27 | { |
| 28 | let values = [il::Val::Imm(4), il::Val::Reg(il::Reg { n: 7 }), |
| 29 | il::Val::Reg(il::Reg { n: 7 })]; |
| 30 | let args = try storage.copy(&values[..]); |
| 31 | let code = try storage.new(published::Code 'view::Call { retTy: il::Type::W64, |
| 32 | dst: il::Reg { n: 9 }, func: il::Val::Reg(il::Reg { n: 2 }), args }); |
| 33 | return try published::buildInstruction(code, nil, storage); |
| 34 | } |
| 35 | |
| 36 | /// Publish operands from source tables that end with this stack frame. |
| 37 | unsafe fn transientInput 'view (storage: &Session 'view) -> published::Function 'view |
| 38 | throws (alloc::AllocError) |
| 39 | { |
| 40 | let params = [il::Param { value: il::Reg { n: 5 }, type: il::Type::W64 }]; |
| 41 | let blockParams = [il::Param { value: il::Reg { n: 6 }, type: il::Type::W64 }]; |
| 42 | let mut instructions = [ |
| 43 | il::Instr::BinOp { op: il::BinOp::Add, typ: il::Type::W64, dst: il::Reg { n: 9 }, |
| 44 | a: il::Val::Reg(il::Reg { n: 5 }), b: il::Val::Reg(il::Reg { n: 6 }) }, |
| 45 | il::Instr::Ret { val: il::Val::Reg(il::Reg { n: 9 }) }, |
| 46 | ]; |
| 47 | let blocks = [il::Block { label: "entry", params: &blockParams[..], instrs: &mut instructions[..], |
| 48 | locs: &[], preds: &[], loopDepth: 2 }]; |
| 49 | let function = il::Fn { name: "transient", params: ¶ms[..], returnType: il::Type::W64, |
| 50 | isExtern: false, isLeaf: true, blocks: &blocks[..] }; |
| 51 | return try published::publish(&function, storage); |
| 52 | } |
| 53 | |
| 54 | /// Analysis tables remain valid after their source stack frame returns. |
| 55 | @test unsafe fn testTransientPublishedInput() throws (testing::TestError) { |
| 56 | static DATA: [u8; 4096] = [0; 4096]; |
| 57 | let mut arena = alloc::new(&mut DATA[..]); |
| 58 | use arena as storage in { |
| 59 | let view = try! transientInput(&storage); |
| 60 | assert view.params.len == 1 and view.params[0].value.n == 5; |
| 61 | let block = &view.blocks[0]; |
| 62 | assert block.params.len == 1 and block.params[0].value.n == 6; |
| 63 | assert block.loopDepth == 2; |
| 64 | let registers = published::registers(&block.instructions[0]); |
| 65 | assert registers.len == 2 and registers[0].n == 5 and registers[1].n == 6; |
| 66 | let destination = published::destination(&block.instructions[0]) else panic; |
| 67 | assert destination.n == 9; |
| 68 | assert not published::isCall(&block.instructions[0]); |
| 69 | let returned = published::registers(&block.instructions[1]); |
| 70 | assert returned.len == 1 and returned[0].n == 9; |
| 71 | assert published::destination(&block.instructions[1]) == nil; |
| 72 | assert published::successors(&block.instructions[1]).len == 0; |
| 73 | let case published::Code::Fixed(fixed) = published::code(&block.instructions[1]) |
| 74 | else panic; |
| 75 | let case il::Instr::Ret { val } = fixed else panic; |
| 76 | let value = val else panic; |
| 77 | let case il::Val::Reg(reg) = value else panic; |
| 78 | assert reg.n == 9; |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | /// Empty functions require no analysis storage. |
| 83 | @test unsafe fn testEmptyPublication() throws (testing::TestError) { |
| 84 | let function = il::Fn { name: "empty", params: &[], returnType: il::Type::W64, |
| 85 | isExtern: true, isLeaf: true, blocks: &[] }; |
| 86 | static DATA: [u8; 1] = [0; 1]; |
| 87 | let mut arena = alloc::new(&mut DATA[..0]); |
| 88 | use arena as storage in { |
| 89 | let view = try! published::publish(&function, &storage); |
| 90 | assert view.params.len == 0 and view.blocks.len == 0; |
| 91 | } |
| 92 | assert alloc::used(&arena) == 0; |
| 93 | } |
| 94 | |
| 95 | /// Publication retains source identities and scans nested argument groups. |
| 96 | @test unsafe fn testPublishedOperands() throws (testing::TestError) { |
| 97 | let value = il::Val::Reg(il::Reg { n: 7 }); |
| 98 | let mut arguments = [il::Val::Imm(3), value, value]; |
| 99 | let mut cases = [il::SwitchCase { value: 1, target: 0, args: &mut arguments[..] }]; |
| 100 | let mut instructions = [il::Instr::Switch { val: value, defaultTarget: 0, |
| 101 | defaultArgs: &mut [], cases: &mut cases[..] }]; |
| 102 | let blocks = [il::Block { label: "entry", params: &[], instrs: &mut instructions[..], |
| 103 | locs: &[], preds: &[], loopDepth: 0 }]; |
| 104 | let function = il::Fn { name: "published", params: &[], returnType: il::Type::W64, |
| 105 | isExtern: false, isLeaf: true, blocks: &blocks[..] }; |
| 106 | static DATA: [u8; 4096] = [0; 4096]; |
| 107 | let mut arena = alloc::new(&mut DATA[..]); |
| 108 | let input: 'input = &function in { |
| 109 | use arena as storage in { |
| 110 | let view = try! published::publish(input, &storage); |
| 111 | assert view.blocks.len == 1; |
| 112 | let blockIdentity = view.blocks[0].identity else panic; |
| 113 | assert blockIdentity == &blocks[0]; |
| 114 | let instruction = &view.blocks[0].instructions[0]; |
| 115 | let identity = published::identity(instruction) else panic; |
| 116 | assert identity == &instructions[0]; |
| 117 | set arguments[1] = il::Val::Reg(il::Reg { n: 99 }); |
| 118 | set cases[0].target = 42; |
| 119 | set instructions[0] = il::Instr::Ret { val: nil }; |
| 120 | let registers = published::registers(instruction); |
| 121 | assert registers.len == 3; |
| 122 | for reg in registers { |
| 123 | assert reg.n == 7; |
| 124 | } |
| 125 | let targets = published::successors(instruction); |
| 126 | assert targets.len == 2 and targets[0] == 0 and targets[1] == 0; |
| 127 | let case published::Code::Switch { cases, defaultArgs, .. } = published::code(instruction) |
| 128 | else panic; |
| 129 | assert defaultArgs.len == 0 and cases.len == 1; |
| 130 | assert cases[0].value == 1 and cases[0].target == 0; |
| 131 | assert cases[0].args.len == 3; |
| 132 | let case il::Val::Reg(reg) = cases[0].args[1] else panic; |
| 133 | assert reg.n == 7; |
| 134 | } |
| 135 | } |
| 136 | } |
| 137 | |
| 138 | /// Allocation failures leave no borrowed source storage in published results. |
| 139 | @test unsafe fn testPublicationAllocationFailure() throws (testing::TestError) { |
| 140 | let mut args = [il::Val::Reg(il::Reg { n: 4 })]; |
| 141 | let locations = [il::SrcLoc { moduleId: 5, offset: 17 }, il::SrcLoc { moduleId: 5, offset: 18 }]; |
| 142 | let mut cases = [il::SwitchCase { value: 1, target: 0, args: &mut args[..] }, |
| 143 | il::SwitchCase { value: 2, target: 0, args: &mut args[..] }]; |
| 144 | let mut instructions = [il::Instr::Call { retTy: il::Type::W64, dst: nil, |
| 145 | func: il::Val::FnAddr("callee"), args: &args[..] }, |
| 146 | il::Instr::Switch { val: il::Val::Imm(1), defaultTarget: 0, |
| 147 | defaultArgs: &mut args[..], cases: &mut cases[..] }]; |
| 148 | let blocks = [il::Block { label: "entry", params: &[], instrs: &mut instructions[..], |
| 149 | locs: &locations[..], preds: &[], loopDepth: 0 }]; |
| 150 | let function = il::Fn { name: "allocation", params: &[], returnType: il::Type::W64, |
| 151 | isExtern: false, isLeaf: false, blocks: &blocks[..] }; |
| 152 | let mut succeeded = false; |
| 153 | for capacity in 0..2049 { |
| 154 | static DATA: [u8; 2048] = [0; 2048]; |
| 155 | let mut arena = alloc::new(&mut DATA[..capacity]); |
| 156 | let input: 'input = &function in { |
| 157 | use arena as storage in { |
| 158 | if let view = try? published::publish(input, &storage) { |
| 159 | let registers = published::registers(&view.blocks[0].instructions[0]); |
| 160 | assert registers.len == 1 and registers[0].n == 4; |
| 161 | assert view.blocks[0].locations.len == 2; |
| 162 | assert view.blocks[0].locations[0].offset == 17; |
| 163 | let case published::Code::Switch { cases, defaultArgs, .. } = |
| 164 | *published::code(&view.blocks[0].instructions[1]) else panic; |
| 165 | assert cases.len == 2 and cases[1].value == 2; |
| 166 | assert cases[1].args.len == 1 and defaultArgs.len == 1; |
| 167 | set succeeded = true; |
| 168 | } else { |
| 169 | assert not succeeded; |
| 170 | } |
| 171 | } |
| 172 | } |
| 173 | alloc::reset(&mut arena); |
| 174 | assert alloc::used(&arena) == 0; |
| 175 | } |
| 176 | assert succeeded; |
| 177 | } |