if_decompiler/glulx/
opcodes.rs1use super::*;
13
14pub const OP_NOP: u32 = 0x00;
15pub const OP_ADD: u32 = 0x10;
16pub const OP_SUB: u32 = 0x11;
17pub const OP_MUL: u32 = 0x12;
18pub const OP_DIV: u32 = 0x13;
19pub const OP_MOD: u32 = 0x14;
20pub const OP_NEG: u32 = 0x15;
21pub const OP_BITAND: u32 = 0x18;
22pub const OP_BITOR: u32 = 0x19;
23pub const OP_BITXOR: u32 = 0x1A;
24pub const OP_BITNOT: u32 = 0x1B;
25pub const OP_SHIFTL: u32 = 0x1C;
26pub const OP_SSHIFTR: u32 = 0x1D;
27pub const OP_USHIFTR: u32 = 0x1E;
28pub const OP_JUMP: u32 = 0x20;
29pub const OP_JZ: u32 = 0x22;
30pub const OP_JNZ: u32 = 0x23;
31pub const OP_JEQ: u32 = 0x24;
32pub const OP_JNE: u32 = 0x25;
33pub const OP_JLT: u32 = 0x26;
34pub const OP_JGE: u32 = 0x27;
35pub const OP_JGT: u32 = 0x28;
36pub const OP_JLE: u32 = 0x29;
37pub const OP_JLTU: u32 = 0x2A;
38pub const OP_JGEU: u32 = 0x2B;
39pub const OP_JGTU: u32 = 0x2C;
40pub const OP_JLEU: u32 = 0x2D;
41pub const OP_CALL: u32 = 0x30;
42pub const OP_RETURN: u32 = 0x31;
43pub const OP_CATCH: u32 = 0x32;
44pub const OP_THROW: u32 = 0x33;
45pub const OP_TAILCALL: u32 = 0x34;
46pub const OP_COPY: u32 = 0x40;
47pub const OP_COPYS: u32 = 0x41;
48pub const OP_COPYB: u32 = 0x42;
49pub const OP_SEXS: u32 = 0x44;
50pub const OP_SEXB: u32 = 0x45;
51pub const OP_ALOAD: u32 = 0x48;
52pub const OP_ALOADS: u32 = 0x49;
53pub const OP_ALOADB: u32 = 0x4A;
54pub const OP_ALOADBIT: u32 = 0x4B;
55pub const OP_ASTORE: u32 = 0x4C;
56pub const OP_ASTORES: u32 = 0x4D;
57pub const OP_ASTOREB: u32 = 0x4E;
58pub const OP_ASTOREBIT: u32 = 0x4F;
59pub const OP_STKCOUNT: u32 = 0x50;
60pub const OP_STKPEEK: u32 = 0x51;
61pub const OP_STKSWAP: u32 = 0x52;
62pub const OP_STKROLL: u32 = 0x53;
63pub const OP_STKCOPY: u32 = 0x54;
64pub const OP_STREAMCHAR: u32 = 0x70;
65pub const OP_STREAMNUM: u32 = 0x71;
66pub const OP_STREAMSTR: u32 = 0x72;
67pub const OP_STREAMUNICHAR: u32 = 0x73;
68pub const OP_GESTALT: u32 = 0x100;
69pub const OP_DEBUGTRAP: u32 = 0x101;
70pub const OP_GETMEMSIZE: u32 = 0x102;
71pub const OP_SETMEMSIZE: u32 = 0x103;
72pub const OP_JUMPABS: u32 = 0x104;
73pub const OP_RANDOM: u32 = 0x110;
74pub const OP_SETRANDOM: u32 = 0x111;
75pub const OP_QUIT: u32 = 0x120;
76pub const OP_VERIFY: u32 = 0x121;
77pub const OP_RESTART: u32 = 0x122;
78pub const OP_SAVE: u32 = 0x123;
79pub const OP_RESTORE: u32 = 0x124;
80pub const OP_SAVEUNDO: u32 = 0x125;
81pub const OP_RESTOREUNDO: u32 = 0x126;
82pub const OP_PROTECT: u32 = 0x127;
83pub const OP_GLK: u32 = 0x130;
84pub const OP_GETSTRINGTBL: u32 = 0x140;
85pub const OP_SETSTRINGTBL: u32 = 0x141;
86pub const OP_GETIOSYS: u32 = 0x148;
87pub const OP_SETIOSYS: u32 = 0x149;
88pub const OP_LINEARSEARCH: u32 = 0x150;
89pub const OP_BINARYSEARCH: u32 = 0x151;
90pub const OP_LINKEDSEARCH: u32 = 0x152;
91pub const OP_CALLF: u32 = 0x160;
92pub const OP_CALLFI: u32 = 0x161;
93pub const OP_CALLFII: u32 = 0x162;
94pub const OP_CALLFIII: u32 = 0x163;
95pub const OP_MZERO: u32 = 0x170;
96pub const OP_MCOPY: u32 = 0x171;
97pub const OP_MALLOC: u32 = 0x178;
98pub const OP_MFREE: u32 = 0x179;
99pub const OP_ACCELFUNC: u32 = 0x180;
100pub const OP_ACCELPARAM: u32 = 0x181;
101pub const OP_NUMTOF: u32 = 0x190;
102pub const OP_FTONUMZ: u32 = 0x191;
103pub const OP_FTONUMN: u32 = 0x192;
104pub const OP_CEIL: u32 = 0x198;
105pub const OP_FLOOR: u32 = 0x199;
106pub const OP_FADD: u32 = 0x1A0;
107pub const OP_FSUB: u32 = 0x1A1;
108pub const OP_FMUL: u32 = 0x1A2;
109pub const OP_FDIV: u32 = 0x1A3;
110pub const OP_FMOD: u32 = 0x1A4;
111pub const OP_SQRT: u32 = 0x1A8;
112pub const OP_EXP: u32 = 0x1A9;
113pub const OP_LOG: u32 = 0x1AA;
114pub const OP_POW: u32 = 0x1AB;
115pub const OP_SIN: u32 = 0x1B0;
116pub const OP_COS: u32 = 0x1B1;
117pub const OP_TAN: u32 = 0x1B2;
118pub const OP_ASIN: u32 = 0x1B3;
119pub const OP_ACOS: u32 = 0x1B4;
120pub const OP_ATAN: u32 = 0x1B5;
121pub const OP_ATAN2: u32 = 0x1B6;
122pub const OP_JFEQ: u32 = 0x1C0;
123pub const OP_JFNE: u32 = 0x1C1;
124pub const OP_JFLT: u32 = 0x1C2;
125pub const OP_JFLE: u32 = 0x1C3;
126pub const OP_JFGT: u32 = 0x1C4;
127pub const OP_JFGE: u32 = 0x1C5;
128pub const OP_JISNAN: u32 = 0x1C8;
129pub const OP_JISINF: u32 = 0x1C9;
130
131pub fn operands_count(opcode: u32) -> Option<u8> {
134 match opcode {
135 OP_NOP | OP_STKSWAP | OP_QUIT | OP_RESTART => Some(0),
136 OP_JUMP | OP_RETURN | OP_STKCOUNT | OP_STKCOPY
137 | OP_STREAMCHAR ..= OP_STREAMUNICHAR | OP_DEBUGTRAP | OP_GETMEMSIZE
138 | OP_JUMPABS | OP_SETRANDOM | OP_VERIFY | OP_SAVEUNDO | OP_RESTOREUNDO
139 | OP_GETSTRINGTBL | OP_SETSTRINGTBL | OP_MFREE => Some(1),
140 OP_NEG | OP_BITNOT | OP_JZ | OP_JNZ | OP_CATCH ..= OP_TAILCALL
141 | OP_COPY ..= OP_SEXB | OP_STKPEEK | OP_STKROLL | OP_CALLF
142 | OP_SETMEMSIZE | OP_RANDOM | OP_SAVE | OP_RESTORE | OP_PROTECT
143 | OP_GETIOSYS | OP_SETIOSYS | OP_MZERO | OP_MALLOC | OP_ACCELFUNC
144 | OP_ACCELPARAM | OP_NUMTOF ..= OP_FLOOR | OP_SQRT ..= OP_LOG
145 | OP_SIN ..= OP_ATAN | OP_JISNAN | OP_JISINF => Some(2),
146 OP_ADD ..= OP_MOD | OP_BITAND ..= OP_BITXOR | OP_SHIFTL ..= OP_USHIFTR
147 | OP_JEQ ..= OP_CALL | OP_ALOAD ..= OP_ASTOREBIT | OP_GESTALT
148 | OP_GLK | OP_CALLFI | OP_MCOPY | OP_FADD ..= OP_FDIV | OP_POW
149 | OP_ATAN2 | OP_JFLT ..= OP_JFGE => Some(3),
150 OP_CALLFII | OP_FMOD | OP_JFEQ | OP_JFNE => Some(4),
151 OP_CALLFIII => Some(5),
152 OP_LINKEDSEARCH => Some(7),
153 OP_LINEARSEARCH | OP_BINARYSEARCH => Some(8),
154 _ => None,
155 }
156}
157
158pub fn instruction_branches(opcode: u32) -> bool {
160 match opcode {
161 OP_JUMP ..= OP_JLEU | OP_CATCH | OP_JUMPABS | OP_JFEQ ..= OP_JISINF => true,
162 _ => false,
163 }
164}
165
166pub fn instruction_calls(opcode: u32) -> bool {
168 match opcode {
169 OP_CALL | OP_TAILCALL | OP_CALLF ..= OP_CALLFIII => true,
170 _ => false,
171 }
172}
173
174pub fn instruction_halts(opcode: u32) -> bool {
176 match opcode {
177 OP_JUMP | OP_RETURN | OP_THROW | OP_TAILCALL | OP_JUMPABS | OP_QUIT
178 | OP_RESTART => true,
179 _ => false,
180 }
181}
182
183pub fn instruction_resumes(opcode: u32) -> bool {
185 match opcode {
186 OP_CALL | OP_STREAMCHAR ..= OP_STREAMUNICHAR | OP_SAVE | OP_SAVEUNDO
187 | OP_CALLF ..= OP_CALLFIII => true,
188 _ => false,
189 }
190}
191
192#[derive(Copy, Clone, PartialEq)]
193pub enum StoreMode {
194 DoesNotStore,
195 LastOperand,
196 LastTwoOperands,
197}
198
199pub fn instruction_stores(opcode: u32) -> StoreMode {
201 use StoreMode::*;
202 match opcode {
203 OP_ADD ..= OP_USHIFTR | OP_CALL | OP_COPY
204 | OP_SEXS ..= OP_ALOADBIT | OP_STKCOUNT ..= OP_STKPEEK
206 | OP_GESTALT | OP_GETMEMSIZE | OP_SETMEMSIZE | OP_RANDOM | OP_VERIFY
207 | OP_SAVE ..= OP_RESTOREUNDO | OP_GLK | OP_GETSTRINGTBL
208 | OP_LINEARSEARCH ..= OP_CALLFIII | OP_MALLOC | OP_NUMTOF ..= OP_FDIV
209 | OP_SQRT ..= OP_ATAN2 => LastOperand,
210 OP_GETIOSYS | OP_FMOD => LastTwoOperands,
211 _ => DoesNotStore,
212 }
213}
214
215pub fn function_safety(instructions: &Vec<Instruction>) -> FunctionSafety {
217 use FunctionSafety::*;
218 let mut result = SafetyTBD;
219 for instruction in instructions {
220 match instruction.opcode {
221 OP_THROW | OP_QUIT | OP_RESTART ..= OP_RESTOREUNDO => result = Unsafe,
222
223 OP_CALL | OP_TAILCALL | OP_CALLF ..= OP_CALLFIII => match instruction.operands[0] {
225 Operand::Constant(_) => continue,
226 _ => result = Unsafe,
227 }
228
229 OP_JUMP ..= OP_JLEU | OP_JUMPABS | OP_JFEQ ..= OP_JISINF => match instruction.operands.last().unwrap() {
231 Operand::Constant(_) => continue,
232 _ => return UnsafeDynamicBranches,
233 }
234
235 OP_CATCH => match instruction.operands.last().unwrap() {
237 Operand::Constant(_) => result = Unsafe,
238 _ => return UnsafeDynamicBranches,
239 }
240
241 _ => continue,
242 };
243 }
244 result
245}