WARNING! Access to this system is limited to authorised users only.
Unauthorised users may be subject to prosecution.
Unauthorised access to this system is a criminal offence under Australian law (Federal Crimes Act 1914 Part VIA)
It is a criminal offence to:
(1) Obtain access to data without authority. -Penalty 2 years imprisonment.
(2) Damage, delete, alter or insert data without authority. -Penalty 10 years imprisonment.
User activity is monitored and recorded. Anyone using this system expressly consents to such monitoring and recording.

To protect your data, the CISO officer has suggested users to enable 2FA as soon as possible.
Currently 2.6% of users enabled 2FA.

codegen.rs 23.5 KB
Newer Older
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1
// Copyright 2017 The Australian National University
qinsoon's avatar
qinsoon committed
2
//
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
3 4 5
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
qinsoon's avatar
qinsoon committed
6
//
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
7
//     http://www.apache.org/licenses/LICENSE-2.0
qinsoon's avatar
qinsoon committed
8
//
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
9 10 11 12 13 14
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

15
use ast::ir::*;
16
use ast::ptr::P;
17 18
use runtime::ValueLocation;

19
use compiler::backend::{Mem, Reg};
20 21 22
use compiler::machine_code::MachineCode;

pub trait CodeGenerator {
23 24 25 26 27 28
    fn start_code(&mut self, func_name: MuName, entry: MuName)
        -> ValueLocation;
    fn finish_code(
        &mut self,
        func_name: MuName
    ) -> (Box<MachineCode + Sync + Send>, ValueLocation);
29 30 31 32 33 34 35 36

    // generate unnamed sequence of linear code (no branch)
    fn start_code_sequence(&mut self);
    fn finish_code_sequence(&mut self) -> Box<MachineCode + Sync + Send>;

    fn print_cur_code(&self);

    fn start_block(&mut self, block_name: MuName);
37
    fn block_exists(&self, block_name: MuName) -> bool;
38 39 40 41
    fn start_exception_block(&mut self, block_name: MuName) -> ValueLocation;
    fn end_block(&mut self, block_name: MuName);

    // add CFI info
42
    fn add_cfi_sections(&mut self, arg: &str);
43 44
    fn add_cfi_startproc(&mut self);
    fn add_cfi_endproc(&mut self);
45
    fn add_cfi_def_cfa(&mut self, reg: Reg, offset: i32);
46 47 48 49
    fn add_cfi_def_cfa_register(&mut self, reg: Reg);
    fn add_cfi_def_cfa_offset(&mut self, offset: i32);
    fn add_cfi_offset(&mut self, reg: Reg, offset: i32);

qinsoon's avatar
qinsoon committed
50
    //===========================================================================================
51 52 53 54 55 56 57 58

    // emit code to adjust frame
    fn emit_frame_grow(&mut self); // Emits a SUB

    // stack minimpulation
    fn emit_push_pair(&mut self, src1: Reg, src2: Reg, stack: Reg); // Emits a STP
    fn emit_pop_pair(&mut self, dest1: Reg, dest2: Reg, stack: Reg); // Emits a LDP

59 60
    // For callee saved loads and stores (flags them so that only they are
    // removed)
61 62 63
    fn emit_ldr_callee_saved(&mut self, dest: Reg, src: Mem);
    fn emit_str_callee_saved(&mut self, dest: Mem, src: Reg);

qinsoon's avatar
qinsoon committed
64
    //===========================================================================================
65

66 67 68
    /* Bellow ar all ARMv8-A Aarch64 instruction menmonics (with all operand modes) except:
        PRFM, PRFUM, CRC32*
        All advanced SIMD instructions (except MOVI)
69 70

    NOTE:
qinsoon's avatar
qinsoon committed
71 72 73 74
        with loads and stores the menmonic indicated may be given a suffix indicating the size
        and signenedness of the access also b_cond's menmononic is 'B.cond' (where cond is the
        value of the 'cond' parameter) all other instructions have the menmonic being the first
        word of the function name after emit_
75
            (subsequent words are used to disambiguate different overloads)
76
    NOTE unless otherwise indicated:
qinsoon's avatar
qinsoon committed
77 78 79 80
        An instruction that dosn't start with an F operates on GPRS, those that start with
        an F operate on FPRs. All instructions operate on 32-bit and 64-bit registers (but all
        register arguments must be the same size) Also all arguments that may take the SP can't
        take the ZR (and vice versa)
81 82 83
    */

    // loads
qinsoon's avatar
qinsoon committed
84
    // supports the full full range of addressing modes
85 86 87 88 89 90
    fn emit_ldr(
        &mut self,
        dest: Reg, /* GPR or FPR */
        src: Mem,
        signed: bool
    );
91
    fn emit_ldtr(&mut self, dest: Reg, src: Mem, signed: bool); // [base, #simm9]
92 93 94 95 96 97 98
    fn emit_ldur(
        &mut self,
        dest: Reg, /* GPR or FPR */
        src: Mem,
        signed: bool
    );
    // [base, #simm9]
qinsoon's avatar
qinsoon committed
99 100 101
    fn emit_ldxr(&mut self, dest: Reg, src: Mem); // [base]
    fn emit_ldaxr(&mut self, dest: Reg, src: Mem); // [base]
    fn emit_ldar(&mut self, dest: Reg, src: Mem); // [base]
102

qinsoon's avatar
qinsoon committed
103
    // [base, #simm7], [base], #simm7, [base, #simm7]!
104 105 106 107 108 109
    fn emit_ldp(
        &mut self,
        dest1: Reg,
        dest2: Reg, /* GPR or FPR */
        src: Mem
    );
110 111
    fn emit_ldxp(&mut self, dest1: Reg, dest2: Reg, src: Mem); // [base]
    fn emit_ldaxp(&mut self, dest1: Reg, dest2: Reg, src: Mem); // [base]
qinsoon's avatar
qinsoon committed
112 113
    fn emit_ldnp(
        &mut self,
114 115 116
        dest1: Reg, /* GPR or FPR */
        dest2: Reg, /* GPR or FPR */
        src: Mem
qinsoon's avatar
qinsoon committed
117
    ); // [base, #simm7]
118

119
    // Stores
qinsoon's avatar
qinsoon committed
120
    // supports the full full range of addressing modes
121
    fn emit_str(&mut self, dest: Mem, src: Reg /* GPR or FPR */);
122
    fn emit_sttr(&mut self, dest: Mem, src: Reg); // [base, #simm9]
123
    fn emit_stur(&mut self, dest: Mem, src: Reg /* GPR or FPR */); // [base, #simm9]
124 125 126 127
    fn emit_stlr(&mut self, dest: Mem, src: Reg); // [base]
    fn emit_stxr(&mut self, dest: Mem, status: Reg, src: Reg); // [base]
    fn emit_stlxr(&mut self, dest: Mem, status: Reg, src: Reg); // [base]

qinsoon's avatar
qinsoon committed
128 129
    // [base, #simm7], [base], #simm7, [base, #simm7]!
    fn emit_stp(&mut self, dest: Mem, src1: Reg, src2: Reg);
130 131
    fn emit_stxp(&mut self, dest: Mem, status: Reg, src1: Reg, src2: Reg); // [base]
    fn emit_stlxp(&mut self, dest: Mem, status: Reg, src1: Reg, src2: Reg); // [base]
qinsoon's avatar
qinsoon committed
132 133 134
    fn emit_stnp(
        &mut self,
        dest: Mem,
135 136
        src1: Reg, /* GPR or FPR */
        src2: Reg  /* GPR or FPR */
qinsoon's avatar
qinsoon committed
137
    ); // [base, #simm7]
138

139
    // Calls
qinsoon's avatar
qinsoon committed
140 141
    fn emit_bl(
        &mut self,
142
        callsite: Option<MuName>,
qinsoon's avatar
qinsoon committed
143 144 145
        func: MuName,
        pe: Option<MuName>,
        args: Vec<P<Value>>,
146
        ret: Vec<P<Value>>,
147
        is_native: bool
148
    ) -> Option<ValueLocation>;
qinsoon's avatar
qinsoon committed
149 150
    fn emit_blr(
        &mut self,
151
        callsite: Option<MuName>,
qinsoon's avatar
qinsoon committed
152 153
        func: Reg,
        pe: Option<MuName>,
154
        args: Vec<P<Value>>,
155
        ret: Vec<P<Value>>
156
    ) -> Option<ValueLocation>;
157
    // Branches
158 159 160
    fn emit_b(&mut self, dest_name: MuName);
    fn emit_b_cond(&mut self, cond: &str, dest_name: MuName);
    fn emit_br(&mut self, dest_address: Reg);
161 162
    fn emit_b_call(
        &mut self,
163
        callsite: Option<MuName>,
164 165 166 167 168
        func: MuName,
        pe: Option<MuName>,
        args: Vec<P<Value>>,
        ret: Vec<P<Value>>,
        is_native: bool,
169
        may_return: bool
170 171 172
    ) -> Option<ValueLocation>;
    fn emit_br_call(
        &mut self,
173
        callsite: Option<MuName>,
174 175 176 177
        func: Reg,
        pe: Option<MuName>,
        args: Vec<P<Value>>,
        ret: Vec<P<Value>>,
178
        may_return: bool
179 180
    ) -> Option<ValueLocation>;

181 182 183 184 185 186 187 188 189 190 191
    fn emit_ret(&mut self, src: Reg);
    fn emit_cbnz(&mut self, src: Reg, dest_name: MuName);
    fn emit_cbz(&mut self, src: Reg, dest_name: MuName);
    fn emit_tbnz(&mut self, src1: Reg, src2: u8, dest_name: MuName);
    fn emit_tbz(&mut self, src1: Reg, src2: u8, dest_name: MuName);

    // Read and write flags
    fn emit_msr(&mut self, dest: &str, src: Reg);
    fn emit_mrs(&mut self, dest: Reg, src: &str);

    // Address calculation
192 193
    fn emit_adr(&mut self, dest: Reg, src: Mem);
    fn emit_adrp(&mut self, dest: Reg, src: Mem);
194 195

    // Unary ops
qinsoon's avatar
qinsoon committed
196
    // The SP and ZR cannot both be used
197 198 199 200 201
    fn emit_mov(
        &mut self,
        dest: Reg, /* GPR or SP or ZR */
        src: Reg   /* GPR or SP or ZR */
    );
202 203 204 205 206
    fn emit_mvn(&mut self, dest: Reg, src: Reg);
    fn emit_neg(&mut self, dest: Reg, src: Reg);
    fn emit_negs(&mut self, dest: Reg, src: Reg);
    fn emit_ngc(&mut self, dest: Reg, src: Reg);
    fn emit_ngcs(&mut self, dest: Reg, src: Reg);
207 208 209 210 211
    fn emit_sxtb(&mut self, dest: Reg /* 32 */, src: Reg /* 32 */);
    fn emit_sxth(&mut self, dest: Reg /* 32 */, src: Reg /* 32 */);
    fn emit_sxtw(&mut self, dest: Reg /* 64 */, src: Reg /* 32 */);
    fn emit_uxtb(&mut self, dest: Reg /* 32 */, src: Reg /* 32 */);
    fn emit_uxth(&mut self, dest: Reg /* 32 */, src: Reg /* 32 */);
212 213 214 215 216
    fn emit_cls(&mut self, dest: Reg, src: Reg);
    fn emit_clz(&mut self, dest: Reg, src: Reg);
    fn emit_rbit(&mut self, dest: Reg, src: Reg);
    fn emit_rev(&mut self, dest: Reg, src: Reg);
    fn emit_rev16(&mut self, dest: Reg, src: Reg);
217 218
    fn emit_rev32(&mut self, dest: Reg /* 64 */, src: Reg);
    fn emit_rev64(&mut self, dest: Reg /* 64 */, src: Reg); // alias of REV
219
    fn emit_fabs(&mut self, dest: Reg, src: Reg);
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
    fn emit_fcvt(
        &mut self,
        dest: Reg,
        src: Reg /* Must have different size */
    );
    fn emit_fcvtas(
        &mut self,
        dest: Reg, /* GPR, may have different size */
        src: Reg
    );
    fn emit_fcvtau(
        &mut self,
        dest: Reg, /* GPR, may have different size */
        src: Reg
    );
    fn emit_fcvtms(
        &mut self,
        dest: Reg, /* GPR, may have different size */
        src: Reg
    );
    fn emit_fcvtmu(
        &mut self,
        dest: Reg, /* GPR, may have different size */
        src: Reg
    );
    fn emit_fcvtns(
        &mut self,
        dest: Reg, /* GPR, may have different size */
        src: Reg
    );
    fn emit_fcvtnu(
        &mut self,
        dest: Reg, /* GPR, may have different size */
        src: Reg
    );
    fn emit_fcvtps(
        &mut self,
        dest: Reg, /* GPR, may have different size */
        src: Reg
    );
    fn emit_fcvtpu(
        &mut self,
        dest: Reg, /* GPR, may have different size */
        src: Reg
    );
    fn emit_fcvtzs(
        &mut self,
        dest: Reg, /* GPR, may have different size */
        src: Reg
    );
    fn emit_fcvtzu(
        &mut self,
        dest: Reg, /* GPR, may have different size */
        src: Reg
    );
qinsoon's avatar
qinsoon committed
275 276
    // One register must be an FPR, the other may be a GPR or an FPR
    fn emit_fmov(&mut self, dest: Reg, src: Reg);
277 278 279 280 281 282 283 284 285
    fn emit_fneg(&mut self, dest: Reg, src: Reg);
    fn emit_frinta(&mut self, dest: Reg, src: Reg);
    fn emit_frinti(&mut self, dest: Reg, src: Reg);
    fn emit_frintm(&mut self, dest: Reg, src: Reg);
    fn emit_frintn(&mut self, dest: Reg, src: Reg);
    fn emit_frintp(&mut self, dest: Reg, src: Reg);
    fn emit_frintx(&mut self, dest: Reg, src: Reg);
    fn emit_frintz(&mut self, dest: Reg, src: Reg);
    fn emit_fsqrt(&mut self, dest: Reg, src: Reg);
286 287 288 289 290 291 292 293 294 295
    fn emit_scvtf(
        &mut self,
        dest: Reg, /* FPR, may have different size */
        src: Reg
    );
    fn emit_ucvtf(
        &mut self,
        dest: Reg, /* FPR, may have different size */
        src: Reg
    );
296 297 298 299 300

    // Unary operations with shift
    fn emit_mov_shift(&mut self, dest: Reg, src: Reg, shift: &str, ammount: u8);
    fn emit_mvn_shift(&mut self, dest: Reg, src: Reg, shift: &str, ammount: u8);
    fn emit_neg_shift(&mut self, dest: Reg, src: Reg, shift: &str, ammount: u8);
301 302 303 304 305 306 307
    fn emit_negs_shift(
        &mut self,
        dest: Reg,
        src: Reg,
        shift: &str,
        ammount: u8
    );
308 309 310 311 312 313

    // Unary operations with immediates
    fn emit_mov_imm(&mut self, dest: Reg, src: u64);
    fn emit_movz(&mut self, dest: Reg, src: u16, shift: u8);
    fn emit_movk(&mut self, dest: Reg, src: u16, shift: u8);
    fn emit_movn(&mut self, dest: Reg, src: u16, shift: u8);
314
    fn emit_movi(&mut self, dest: Reg /* FPR */, src: u64);
315 316 317
    fn emit_fmov_imm(&mut self, dest: Reg, src: f32);

    // Extended binary ops
qinsoon's avatar
qinsoon committed
318 319
    fn emit_add_ext(
        &mut self,
320 321
        dest: Reg, /* GPR or SP */
        src1: Reg, /* GPR or SP */
qinsoon's avatar
qinsoon committed
322 323
        src2: Reg,
        signed: bool,
324
        shift: u8
qinsoon's avatar
qinsoon committed
325 326 327 328
    );
    fn emit_adds_ext(
        &mut self,
        dest: Reg,
329
        src1: Reg, /* GPR or SP */
qinsoon's avatar
qinsoon committed
330 331
        src2: Reg,
        signed: bool,
332
        shift: u8
qinsoon's avatar
qinsoon committed
333 334 335
    );
    fn emit_sub_ext(
        &mut self,
336 337
        dest: Reg, /* GPR or SP */
        src1: Reg, /* GPR or SP */
qinsoon's avatar
qinsoon committed
338 339
        src2: Reg,
        signed: bool,
340
        shift: u8
qinsoon's avatar
qinsoon committed
341 342 343 344
    );
    fn emit_subs_ext(
        &mut self,
        dest: Reg,
345
        src1: Reg, /* GPR or SP */
qinsoon's avatar
qinsoon committed
346 347
        src2: Reg,
        signed: bool,
348
        shift: u8
qinsoon's avatar
qinsoon committed
349
    );
350 351 352 353

    // Multiplication
    fn emit_mul(&mut self, dest: Reg, src1: Reg, src2: Reg);
    fn emit_mneg(&mut self, dest: Reg, src1: Reg, src2: Reg);
354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389
    fn emit_smulh(
        &mut self,
        dest: Reg, /* 64 */
        src1: Reg, /* 64 */
        src2: Reg  /* 64 */
    );
    fn emit_umulh(
        &mut self,
        dest: Reg, /* 64 */
        src1: Reg, /* 64 */
        src2: Reg  /* 64 */
    );
    fn emit_smnegl(
        &mut self,
        dest: Reg, /* 64 */
        src1: Reg, /* 32 */
        src2: Reg  /* 32 */
    );
    fn emit_smull(
        &mut self,
        dest: Reg, /* 64 */
        src1: Reg, /* 32 */
        src2: Reg  /* 32 */
    );
    fn emit_umnegl(
        &mut self,
        dest: Reg, /* 64 */
        src1: Reg, /* 32 */
        src2: Reg  /* 32 */
    );
    fn emit_umull(
        &mut self,
        dest: Reg, /* 64 */
        src1: Reg, /* 32 */
        src2: Reg  /* 32 */
    );
390 391 392 393

    // Other binaries
    fn emit_adc(&mut self, dest: Reg, src1: Reg, src2: Reg);
    fn emit_adcs(&mut self, dest: Reg, src1: Reg, src2: Reg);
394 395
    fn emit_add(&mut self, dest: Reg, src1: Reg /* GPR or SP */, src2: Reg);
    fn emit_adds(&mut self, dest: Reg, src1: Reg /* GPR or SP */, src2: Reg);
396 397 398 399 400 401 402
    fn emit_sbc(&mut self, dest: Reg, src1: Reg, src2: Reg);
    fn emit_sbcs(&mut self, dest: Reg, src1: Reg, src2: Reg);
    fn emit_sub(&mut self, dest: Reg, src1: Reg, src2: Reg);
    fn emit_subs(&mut self, dest: Reg, src1: Reg, src2: Reg);
    fn emit_sdiv(&mut self, dest: Reg, src1: Reg, src2: Reg);
    fn emit_udiv(&mut self, dest: Reg, src1: Reg, src2: Reg);
    fn emit_asr(&mut self, dest: Reg, src1: Reg, src2: Reg);
403
    fn emit_asrv(&mut self, dest: Reg, src1: Reg, src2: Reg); // Alias of ASR
404
    fn emit_lsl(&mut self, dest: Reg, src1: Reg, src2: Reg);
405
    fn emit_lslv(&mut self, dest: Reg, src1: Reg, src2: Reg); // Alias of LSL
406
    fn emit_lsr(&mut self, dest: Reg, src1: Reg, src2: Reg);
407
    fn emit_lsrv(&mut self, dest: Reg, src1: Reg, src2: Reg); // Alias of LSR
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427
    fn emit_ror(&mut self, dest: Reg, src1: Reg, src2: Reg);
    fn emit_bic(&mut self, dest: Reg, src1: Reg, src2: Reg);
    fn emit_bics(&mut self, dest: Reg, src1: Reg, src2: Reg);
    fn emit_and(&mut self, dest: Reg, src1: Reg, src2: Reg);
    fn emit_ands(&mut self, dest: Reg, src1: Reg, src2: Reg);
    fn emit_eon(&mut self, dest: Reg, src1: Reg, src2: Reg);
    fn emit_eor(&mut self, dest: Reg, src1: Reg, src2: Reg);
    fn emit_orn(&mut self, dest: Reg, src1: Reg, src2: Reg);
    fn emit_orr(&mut self, dest: Reg, src1: Reg, src2: Reg);
    fn emit_fadd(&mut self, dest: Reg, src1: Reg, src2: Reg);
    fn emit_fdiv(&mut self, dest: Reg, src1: Reg, src2: Reg);
    fn emit_fmax(&mut self, dest: Reg, src1: Reg, src2: Reg);
    fn emit_fmaxnm(&mut self, dest: Reg, src1: Reg, src2: Reg);
    fn emit_fmin(&mut self, dest: Reg, src1: Reg, src2: Reg);
    fn emit_fminm(&mut self, dest: Reg, src1: Reg, src2: Reg);
    fn emit_fmul(&mut self, dest: Reg, src1: Reg, src2: Reg);
    fn emit_fnmul(&mut self, dest: Reg, src1: Reg, src2: Reg);
    fn emit_fsub(&mut self, dest: Reg, src1: Reg, src2: Reg);

    // Binary operations with shift
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
    fn emit_add_shift(
        &mut self,
        dest: Reg,
        src1: Reg,
        src2: Reg,
        shift: &str,
        amount: u8
    );
    fn emit_adds_shift(
        &mut self,
        dest: Reg,
        src1: Reg,
        src2: Reg,
        shift: &str,
        amount: u8
    );
    fn emit_sub_shift(
        &mut self,
        dest: Reg,
        src1: Reg,
        src2: Reg,
        shift: &str,
        amount: u8
    );
    fn emit_subs_shift(
        &mut self,
        dest: Reg,
        src1: Reg,
        src2: Reg,
        shift: &str,
        amount: u8
    );
    fn emit_bic_shift(
        &mut self,
        dest: Reg,
        src1: Reg,
        src2: Reg,
        shift: &str,
        amount: u8
    );
    fn emit_bics_shift(
        &mut self,
        dest: Reg,
        src1: Reg,
        src2: Reg,
        shift: &str,
        amount: u8
    );
    fn emit_and_shift(
        &mut self,
        dest: Reg,
        src1: Reg,
        src2: Reg,
        shift: &str,
        amount: u8
    );
    fn emit_ands_shift(
        &mut self,
        dest: Reg,
        src1: Reg,
        src2: Reg,
        shift: &str,
        amount: u8
    );
    fn emit_eon_shift(
        &mut self,
        dest: Reg,
        src1: Reg,
        src2: Reg,
        shift: &str,
        amount: u8
    );
    fn emit_eor_shift(
        &mut self,
        dest: Reg,
        src1: Reg,
        src2: Reg,
        shift: &str,
        amount: u8
    );
    fn emit_orn_shift(
        &mut self,
        dest: Reg,
        src1: Reg,
        src2: Reg,
        shift: &str,
        amount: u8
    );
    fn emit_orr_shift(
        &mut self,
        dest: Reg,
        src1: Reg,
        src2: Reg,
        shift: &str,
        amount: u8
    );
524 525

    // binary ops with immediates
qinsoon's avatar
qinsoon committed
526 527
    fn emit_add_imm(
        &mut self,
528 529 530 531 532 533 534 535 536
        dest: Reg, /* GPR or SP */
        src1: Reg, /* GPR or SP */
        src2: u16,
        shift: bool
    );
    fn emit_adds_imm(
        &mut self,
        dest: Reg,
        src1: Reg, /* GPR or SP */
qinsoon's avatar
qinsoon committed
537
        src2: u16,
538
        shift: bool
qinsoon's avatar
qinsoon committed
539 540 541
    );
    fn emit_sub_imm(
        &mut self,
542 543
        dest: Reg, /* GPR or SP */
        src1: Reg, /* GPR or SP */
qinsoon's avatar
qinsoon committed
544
        src2: u16,
545 546 547 548 549 550 551 552
        shift: bool
    );
    fn emit_subs_imm(
        &mut self,
        dest: Reg,
        src1: Reg, /* GPR or SP */
        src2: u16,
        shift: bool
qinsoon's avatar
qinsoon committed
553 554
    );

555 556 557 558 559 560
    fn emit_and_imm(
        &mut self,
        dest: Reg, /* GPR or SP */
        src1: Reg,
        src2: u64
    );
561
    fn emit_ands_imm(&mut self, dest: Reg, src1: Reg, src2: u64);
562 563 564 565 566 567 568 569 570 571 572 573
    fn emit_eor_imm(
        &mut self,
        dest: Reg, /* GPR or SP */
        src1: Reg,
        src2: u64
    );
    fn emit_orr_imm(
        &mut self,
        dest: Reg, /* GPR or SP */
        src1: Reg,
        src2: u64
    );
574 575 576 577 578 579 580 581 582 583

    fn emit_asr_imm(&mut self, dest: Reg, src1: Reg, src2: u8);
    fn emit_lsr_imm(&mut self, dest: Reg, src1: Reg, src2: u8);
    fn emit_lsl_imm(&mut self, dest: Reg, src1: Reg, src2: u8);
    fn emit_ror_imm(&mut self, dest: Reg, src1: Reg, src2: u8);

    // ternary ops

    fn emit_madd(&mut self, dest: Reg, src1: Reg, src2: Reg, src3: Reg);
    fn emit_msub(&mut self, dest: Reg, src1: Reg, src2: Reg, src3: Reg);
qinsoon's avatar
qinsoon committed
584 585
    fn emit_smaddl(
        &mut self,
586 587 588 589
        dest: Reg, /* 64 */
        src1: Reg, /* 32 */
        src2: Reg, /* 32 */
        src3: Reg  /* 64 */
qinsoon's avatar
qinsoon committed
590 591 592
    );
    fn emit_smsubl(
        &mut self,
593 594 595 596
        dest: Reg, /* 64 */
        src1: Reg, /* 32 */
        src2: Reg, /* 32 */
        src3: Reg  /* 64 */
qinsoon's avatar
qinsoon committed
597 598 599
    );
    fn emit_umaddl(
        &mut self,
600 601 602 603
        dest: Reg, /* 64 */
        src1: Reg, /* 32 */
        src2: Reg, /* 32 */
        src3: Reg  /* 64 */
qinsoon's avatar
qinsoon committed
604 605 606
    );
    fn emit_umsubl(
        &mut self,
607 608 609 610
        dest: Reg, /* 64 */
        src1: Reg, /* 32 */
        src2: Reg, /* 32 */
        src3: Reg  /* 64 */
qinsoon's avatar
qinsoon committed
611
    );
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635
    fn emit_fmadd(&mut self, dest: Reg, src1: Reg, src2: Reg, src3: Reg);
    fn emit_fmsub(&mut self, dest: Reg, src1: Reg, src2: Reg, src3: Reg);
    fn emit_fnmadd(&mut self, dest: Reg, src1: Reg, src2: Reg, src3: Reg);
    fn emit_fnmsub(&mut self, dest: Reg, src1: Reg, src2: Reg, src3: Reg);

    // Ternary ops with immediates
    fn emit_bfm(&mut self, dest: Reg, src1: Reg, src2: u8, src3: u8);
    fn emit_bfi(&mut self, dest: Reg, src1: Reg, src2: u8, src3: u8);
    fn emit_bfxil(&mut self, dest: Reg, src1: Reg, src2: u8, src3: u8);
    fn emit_ubfm(&mut self, dest: Reg, src1: Reg, src2: u8, src3: u8);
    fn emit_ubfx(&mut self, dest: Reg, src1: Reg, src2: u8, src3: u8);
    fn emit_ubfiz(&mut self, dest: Reg, src1: Reg, src2: u8, src3: u8);
    fn emit_sbfm(&mut self, dest: Reg, src1: Reg, src2: u8, src3: u8);
    fn emit_sbfx(&mut self, dest: Reg, src1: Reg, src2: u8, src3: u8);
    fn emit_sbfiz(&mut self, dest: Reg, src1: Reg, src2: u8, src3: u8);

    // Comparison (dosn't store a result, only updates flags)
    fn emit_tst(&mut self, src1: Reg, src2: Reg);
    fn emit_cmn(&mut self, src1: Reg, src2: Reg);
    fn emit_cmp(&mut self, src1: Reg, src2: Reg);
    fn emit_fcmp(&mut self, src1: Reg, src2: Reg);
    fn emit_fcmpe(&mut self, src1: Reg, src2: Reg);

    // Comparisons with extension
636 637 638 639 640 641 642 643 644 645 646 647 648 649
    fn emit_cmn_ext(
        &mut self,
        src1: Reg, /* GPR or SP */
        src2: Reg,
        signed: bool,
        shift: u8
    );
    fn emit_cmp_ext(
        &mut self,
        src1: Reg, /* GPR or SP */
        src2: Reg,
        signed: bool,
        shift: u8
    );
650 651

    // Comparisons with shift
652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672
    fn emit_tst_shift(
        &mut self,
        src1: Reg,
        src2: Reg,
        shift: &str,
        ammount: u8
    );
    fn emit_cmn_shift(
        &mut self,
        src1: Reg,
        src2: Reg,
        shift: &str,
        ammount: u8
    );
    fn emit_cmp_shift(
        &mut self,
        src1: Reg,
        src2: Reg,
        shift: &str,
        ammount: u8
    );
673 674 675

    // Immediat Comparisons
    fn emit_tst_imm(&mut self, src1: Reg, src2: u64);
676 677 678 679 680 681 682 683 684 685 686 687
    fn emit_cmn_imm(
        &mut self,
        src1: Reg, /* GPR or SP */
        src2: u16,
        shift: bool
    );
    fn emit_cmp_imm(
        &mut self,
        src1: Reg, /* GPR or SP */
        src2: u16,
        shift: bool
    );
688

689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758
    // Comparison against 0
    fn emit_fcmp_0(&mut self, src: Reg);
    fn emit_fcmpe_0(&mut self, src: Reg);

    // Conditional ops
    fn emit_cset(&mut self, dest: Reg, cond: &str);
    fn emit_csetm(&mut self, dest: Reg, cond: &str);

    // Conditional unary ops
    fn emit_cinc(&mut self, dest: Reg, src: Reg, cond: &str);
    fn emit_cneg(&mut self, dest: Reg, src: Reg, cond: &str);
    fn emit_cinv(&mut self, dest: Reg, src: Reg, cond: &str);

    // Conditional binary ops
    fn emit_csel(&mut self, dest: Reg, src1: Reg, src2: Reg, cond: &str);
    fn emit_csinc(&mut self, dest: Reg, src1: Reg, src2: Reg, cond: &str);
    fn emit_csinv(&mut self, dest: Reg, src1: Reg, src2: Reg, cond: &str);
    fn emit_csneg(&mut self, dest: Reg, src1: Reg, src2: Reg, cond: &str);
    fn emit_fcsel(&mut self, dest: Reg, src1: Reg, src2: Reg, cond: &str);

    // Conditional comparisons
    fn emit_ccmn(&mut self, src1: Reg, src2: Reg, flags: u8, cond: &str);
    fn emit_ccmp(&mut self, src1: Reg, src2: Reg, flags: u8, cond: &str);
    fn emit_fccmp(&mut self, src1: Reg, src2: Reg, flags: u8, cond: &str);
    fn emit_fccmpe(&mut self, src1: Reg, src2: Reg, flags: u8, cond: &str);

    // Conditional comparisons (with immediate)
    fn emit_ccmn_imm(&mut self, src1: Reg, src2: u8, flags: u8, cond: &str);
    fn emit_ccmp_imm(&mut self, src1: Reg, src2: u8, flags: u8, cond: &str);

    fn emit_bfc(&mut self, dest: Reg, src1: u8, src2: u8);
    fn emit_extr(&mut self, dest: Reg, src1: Reg, src2: Reg, src3: u8);

    // Synchronisation
    fn emit_dsb(&mut self, option: &str);
    fn emit_dmb(&mut self, option: &str);
    fn emit_isb(&mut self, option: &str);
    fn emit_clrex(&mut self);

    // Hint instructions
    fn emit_sevl(&mut self);
    fn emit_sev(&mut self);
    fn emit_wfe(&mut self);
    fn emit_wfi(&mut self);
    fn emit_yield(&mut self);
    fn emit_nop(&mut self);
    fn emit_hint(&mut self, val: u8);

    // Debug instructions
    fn emit_drps(&mut self);
    fn emit_dcps1(&mut self, val: u16);
    fn emit_dcps2(&mut self, val: u16);
    fn emit_dcps3(&mut self, val: u16);

    // System instruction
    fn emit_dc(&mut self, option: &str, src: Reg);
    fn emit_at(&mut self, option: &str, src: Reg);
    fn emit_ic(&mut self, option: &str, src: Reg);
    fn emit_tlbi(&mut self, option: &str, src: Reg);

    fn emit_sys(&mut self, imm1: u8, cn: u8, cm: u8, imm2: u8, src: Reg);
    fn emit_sysl(&mut self, dest: Reg, imm1: u8, cn: u8, cm: u8, imm2: u8);

    // Exceptiuon instructions (NOTE: these will alter the PC)
    fn emit_brk(&mut self, val: u16);
    fn emit_hlt(&mut self, val: u16);
    fn emit_hvc(&mut self, val: u16);
    fn emit_smc(&mut self, val: u16);
    fn emit_svc(&mut self, val: u16);
    fn emit_eret(&mut self);
759
}