tjs2dec\decompile/
hlir.rs1use anyhow::Result;
2
3use super::ssa::{SsaBlock, SsaInsn, SsaProgram, Var, VarId};
4
5#[derive(Debug, Clone)]
16pub enum HExpr {
17 Var(VarId),
18 Opaque { op: &'static str, args: Vec<VarId> },
19}
20
21#[derive(Debug, Clone)]
22pub enum HStmt {
23 Phi {
24 result: VarId,
25 args: Vec<(usize, VarId)>,
26 },
27 Let {
28 defs: Vec<VarId>,
29 expr: HExpr,
30 },
31 Opaque {
32 defs: Vec<VarId>,
33 op: &'static str,
34 uses: Vec<VarId>,
35 },
36}
37
38#[derive(Debug, Clone)]
39pub struct HlirBlock {
40 pub id: usize,
41 pub start_pc: usize,
42 pub pred: Vec<usize>,
43 pub succ: Vec<usize>,
44 pub stmts: Vec<HStmt>,
45}
46
47#[derive(Debug, Clone)]
48pub struct HlirProgram {
49 pub obj_index: usize,
50 pub blocks: Vec<HlirBlock>,
51 pub entry_block: usize,
52}
53
54impl HlirProgram {
55 pub fn from_ssa(ssa: &SsaProgram) -> Result<Self> {
56 let mut blocks = Vec::new();
57 for b in &ssa.blocks {
58 blocks.push(lower_block(b));
59 }
60 Ok(Self {
61 obj_index: ssa.obj_index,
62 blocks,
63 entry_block: ssa.entry_block,
64 })
65 }
66
67 pub fn dump(&self) -> String {
68 let mut out = String::new();
69 for b in &self.blocks {
70 out.push_str(&format!(
71 "-- bb{} @{} (pred={:?}, succ={:?})\n",
72 b.id, b.start_pc, b.pred, b.succ
73 ));
74 for st in &b.stmts {
75 match st {
76 HStmt::Phi { result, args } => {
77 out.push_str(&format!(" {} = phi [", fmt_vid(*result)));
78 for (i, (pred, v)) in args.iter().enumerate() {
79 if i != 0 {
80 out.push_str(", ");
81 }
82 out.push_str(&format!("bb{}: {}", pred, fmt_vid(*v)));
83 }
84 out.push_str("]\n");
85 }
86 HStmt::Let { defs, expr } => {
87 if !defs.is_empty() {
88 out.push_str(" ");
89 for (i, d) in defs.iter().enumerate() {
90 if i != 0 {
91 out.push_str(", ");
92 }
93 out.push_str(&fmt_vid(*d));
94 }
95 out.push_str(" = ");
96 } else {
97 out.push_str(" ");
98 }
99 match expr {
100 HExpr::Var(v) => out.push_str(&fmt_vid(*v)),
101 HExpr::Opaque { op, args } => {
102 out.push_str(op);
103 if !args.is_empty() {
104 out.push('(');
105 for (i, a) in args.iter().enumerate() {
106 if i != 0 {
107 out.push_str(", ");
108 }
109 out.push_str(&fmt_vid(*a));
110 }
111 out.push(')');
112 }
113 }
114 }
115 out.push('\n');
116 }
117 HStmt::Opaque { defs, op, uses } => {
118 out.push_str(" ");
119 if !defs.is_empty() {
120 for (i, d) in defs.iter().enumerate() {
121 if i != 0 {
122 out.push_str(", ");
123 }
124 out.push_str(&fmt_vid(*d));
125 }
126 out.push_str(" = ");
127 }
128 out.push_str(op);
129 if !uses.is_empty() {
130 out.push('(');
131 for (i, u) in uses.iter().enumerate() {
132 if i != 0 {
133 out.push_str(", ");
134 }
135 out.push_str(&fmt_vid(*u));
136 }
137 out.push(')');
138 }
139 out.push('\n');
140 }
141 }
142 }
143 }
144 out
145 }
146}
147
148fn lower_block(b: &SsaBlock) -> HlirBlock {
149 let mut stmts = Vec::new();
150 for p in &b.phi {
151 stmts.push(HStmt::Phi {
152 result: p.result,
153 args: p.args.clone(),
154 });
155 }
156 for insn in &b.insns {
157 stmts.push(lower_insn(insn));
158 }
159 HlirBlock {
160 id: b.id,
161 start_pc: b.start_pc,
162 pred: b.pred.clone(),
163 succ: b.succ.clone(),
164 stmts,
165 }
166}
167
168fn lower_insn(insn: &SsaInsn) -> HStmt {
169 if insn.op == -1 {
172 return HStmt::Opaque {
173 defs: insn.defs.clone(),
174 op: insn.mnemonic,
175 uses: insn.uses.clone(),
176 };
177 }
178
179 if insn.mnemonic == "VM_CP" && insn.defs.len() == 1 && insn.uses.len() == 1 {
180 return HStmt::Let {
181 defs: insn.defs.clone(),
182 expr: HExpr::Var(insn.uses[0]),
183 };
184 }
185
186 HStmt::Opaque {
187 defs: insn.defs.clone(),
188 op: insn.mnemonic,
189 uses: insn.uses.clone(),
190 }
191}
192
193fn fmt_vid(v: VarId) -> String {
194 match v.var {
195 Var::Reg(r) => format!("r{}#{}", r, v.ver),
196 Var::Flag => format!("flag#{}", v.ver),
197 Var::Exception => format!("exc#{}", v.ver),
198 }
199}