1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
use crate::cursor::{Cursor, FuncCursor};
use crate::flowgraph::ControlFlowGraph;
use crate::ir::condcodes::IntCC;
use crate::ir::immediates::Offset32;
use crate::ir::{self, InstBuilder};
use crate::isa::TargetIsa;
pub fn expand_table_addr(
inst: ir::Inst,
func: &mut ir::Function,
_cfg: &mut ControlFlowGraph,
_isa: &dyn TargetIsa,
) {
let (table, index, element_offset) = match func.dfg[inst] {
ir::InstructionData::TableAddr {
opcode,
table,
arg,
offset,
} => {
debug_assert_eq!(opcode, ir::Opcode::TableAddr);
(table, arg, offset)
}
_ => panic!("Wanted table_addr: {}", func.dfg.display_inst(inst, None)),
};
dynamic_addr(inst, table, index, element_offset, func);
}
fn dynamic_addr(
inst: ir::Inst,
table: ir::Table,
index: ir::Value,
element_offset: Offset32,
func: &mut ir::Function,
) {
let bound_gv = func.tables[table].bound_gv;
let index_ty = func.dfg.value_type(index);
let addr_ty = func.dfg.value_type(func.dfg.first_result(inst));
let mut pos = FuncCursor::new(func).at_inst(inst);
pos.use_srcloc(inst);
let bound = pos.ins().global_value(index_ty, bound_gv);
let oob = pos
.ins()
.icmp(IntCC::UnsignedGreaterThanOrEqual, index, bound);
pos.ins().trapnz(oob, ir::TrapCode::TableOutOfBounds);
compute_addr(
inst,
table,
addr_ty,
index,
index_ty,
element_offset,
pos.func,
);
}
fn compute_addr(
inst: ir::Inst,
table: ir::Table,
addr_ty: ir::Type,
mut index: ir::Value,
index_ty: ir::Type,
element_offset: Offset32,
func: &mut ir::Function,
) {
let mut pos = FuncCursor::new(func).at_inst(inst);
pos.use_srcloc(inst);
if index_ty != addr_ty {
index = pos.ins().uextend(addr_ty, index);
}
let base_gv = pos.func.tables[table].base_gv;
let base = pos.ins().global_value(addr_ty, base_gv);
let element_size = pos.func.tables[table].element_size;
let mut offset;
let element_size: u64 = element_size.into();
if element_size == 1 {
offset = index;
} else if element_size.is_power_of_two() {
offset = pos
.ins()
.ishl_imm(index, i64::from(element_size.trailing_zeros()));
} else {
offset = pos.ins().imul_imm(index, element_size as i64);
}
if element_offset == Offset32::new(0) {
pos.func.dfg.replace(inst).iadd(base, offset);
} else {
let imm: i64 = element_offset.into();
offset = pos.ins().iadd(base, offset);
pos.func.dfg.replace(inst).iadd_imm(offset, imm);
}
}