mod.rs 22 KB
Newer Older
1
// Copyright 2017 The Australian National University
2
//
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
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
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.

qinsoon's avatar
qinsoon committed
15 16
#![allow(dead_code)]

qinsoon's avatar
qinsoon committed
17
/// Tree pattern matching instruction selection.
18 19 20
pub mod inst_sel;

mod codegen;
qinsoon's avatar
qinsoon committed
21 22 23
/// CodeGenerator trait serves as an interface to the backend code generator, which
/// may generate assembly code or binary (not implemented yet)
use compiler::backend::x86_64::codegen::CodeGenerator;
24

qinsoon's avatar
qinsoon committed
25 26 27 28
/// assembly backend as AOT compiler
mod asm_backend;
use compiler::backend::x86_64::asm_backend::ASMCodeGen;

29 30 31
/// call conventions
pub mod callconv;

qinsoon's avatar
qinsoon committed
32 33
// re-export a few functions for AOT compilation
#[cfg(feature = "aot")]
34
pub use compiler::backend::x86_64::asm_backend::emit_code;
qinsoon's avatar
qinsoon committed
35
#[cfg(feature = "aot")]
36
pub use compiler::backend::x86_64::asm_backend::emit_context;
qinsoon's avatar
qinsoon committed
37
#[cfg(feature = "aot")]
qinsoon's avatar
qinsoon committed
38
pub use compiler::backend::x86_64::asm_backend::emit_context_with_reloc;
39 40
#[cfg(feature = "aot")]
pub use compiler::backend::x86_64::asm_backend::spill_rewrite;
41 42

use ast::ir::*;
43
use ast::ptr::P;
qinsoon's avatar
qinsoon committed
44
use ast::types::*;
45
use compiler::backend::RegGroup;
46
use std::sync::Arc;
47 48 49
use utils::Address;
use utils::ByteSize;
use vm::VM;
qinsoon's avatar
qinsoon committed
50

51
use std::collections::HashMap;
52
use utils::LinkedHashMap;
53

54
// number of normal callee saved registers (excluding RSP and RBP)
qinsoon's avatar
qinsoon committed
55
pub const CALLEE_SAVED_COUNT: usize = 5;
56

qinsoon's avatar
qinsoon committed
57
/// a macro to declare a set of general purpose registers that are aliased to the first one
qinsoon's avatar
qinsoon committed
58
macro_rules! GPR_ALIAS {
qinsoon's avatar
qinsoon committed
59 60
    ($alias: ident: ($id64: expr, $r64: ident) ->
     $r32: ident, $r16: ident, $r8l: ident, $r8h: ident) => {
61 62 63 64 65 66 67 68 69 70 71 72 73
        lazy_static! {
            pub static ref $r64: P<Value> = GPR!($id64, stringify!($r64), UINT64_TYPE);
            pub static ref $r32: P<Value> = GPR!($id64 + 1, stringify!($r32), UINT32_TYPE);
            pub static ref $r16: P<Value> = GPR!($id64 + 2, stringify!($r16), UINT16_TYPE);
            pub static ref $r8l: P<Value> = GPR!($id64 + 3, stringify!($r8l), UINT8_TYPE);
            pub static ref $r8h: P<Value> = GPR!($id64 + 4, stringify!($r8h), UINT8_TYPE);
            pub static ref $alias: [P<Value>; 5] = [
                $r64.clone(),
                $r32.clone(),
                $r16.clone(),
                $r8l.clone(),
                $r8h.clone()
            ];
74 75 76
        }
    };

qinsoon's avatar
qinsoon committed
77
    ($alias: ident: ($id64: expr, $r64: ident) -> $r32: ident, $r16: ident, $r8: ident) => {
78 79 80 81 82 83 84
        lazy_static! {
            pub static ref $r64: P<Value> = GPR!($id64, stringify!($r64), UINT64_TYPE);
            pub static ref $r32: P<Value> = GPR!($id64 + 1, stringify!($r32), UINT32_TYPE);
            pub static ref $r16: P<Value> = GPR!($id64 + 2, stringify!($r16), UINT16_TYPE);
            pub static ref $r8: P<Value> = GPR!($id64 + 3, stringify!($r8), UINT8_TYPE);
            pub static ref $alias: [P<Value>; 4] =
                [$r64.clone(), $r32.clone(), $r16.clone(), $r8.clone()];
qinsoon's avatar
qinsoon committed
85 86 87 88
        }
    };

    ($alias: ident: ($id64: expr, $r64: ident)) => {
89 90 91 92
        lazy_static! {
            pub static ref $r64: P<Value> = GPR!($id64, stringify!($r64), UINT64_TYPE);
            pub static ref $alias: [P<Value>; 4] =
                [$r64.clone(), $r64.clone(), $r64.clone(), $r64.clone()];
qinsoon's avatar
qinsoon committed
93 94 95 96
        }
    };
}

qinsoon's avatar
qinsoon committed
97
/// a macro to declare a general purpose register
98
macro_rules! GPR {
99 100 101 102 103 104 105
    ($id:expr, $name: expr, $ty: ident) => {{
        P(Value {
            hdr: MuEntityHeader::named($id, Arc::new($name.to_string())),
            ty: $ty.clone(),
            v: Value_::SSAVar($id),
        })
    }};
qinsoon's avatar
qinsoon committed
106 107
}

qinsoon's avatar
qinsoon committed
108
/// a macro to declare a floating point register
qinsoon's avatar
qinsoon committed
109
macro_rules! FPR {
110 111 112 113 114 115 116
    ($id:expr, $name: expr) => {{
        P(Value {
            hdr: MuEntityHeader::named($id, Arc::new($name.to_string())),
            ty: DOUBLE_TYPE.clone(),
            v: Value_::SSAVar($id),
        })
    }};
qinsoon's avatar
qinsoon committed
117 118
}

qinsoon's avatar
qinsoon committed
119 120 121
// declare all general purpose registers for x86_64
// non 64-bit registers are alias of its 64-bit one

122 123
GPR_ALIAS!(RAX_ALIAS: (0, RAX)  -> EAX, AX , AL, AH);
GPR_ALIAS!(RCX_ALIAS: (5, RCX)  -> ECX, CX , CL, CH);
124
GPR_ALIAS!(RDX_ALIAS: (10,RDX)  -> EDX, DX , DL, DH);
125 126 127 128 129 130 131 132 133 134 135 136 137 138
GPR_ALIAS!(RBX_ALIAS: (15,RBX)  -> EBX, BX , BL, BH);
GPR_ALIAS!(RSP_ALIAS: (20,RSP)  -> ESP, SP , SPL);
GPR_ALIAS!(RBP_ALIAS: (24,RBP)  -> EBP, BP , BPL);
GPR_ALIAS!(RSI_ALIAS: (28,RSI)  -> ESI, SI , SIL);
GPR_ALIAS!(RDI_ALIAS: (32,RDI)  -> EDI, DI , DIL);
GPR_ALIAS!(R8_ALIAS : (36,R8 )  -> R8D, R8W, R8B);
GPR_ALIAS!(R9_ALIAS : (40,R9 )  -> R9D, R9W, R9B);
GPR_ALIAS!(R10_ALIAS: (44,R10) -> R10D,R10W,R10B);
GPR_ALIAS!(R11_ALIAS: (48,R11) -> R11D,R11W,R11B);
GPR_ALIAS!(R12_ALIAS: (52,R12) -> R12D,R12W,R12B);
GPR_ALIAS!(R13_ALIAS: (56,R13) -> R13D,R13W,R13B);
GPR_ALIAS!(R14_ALIAS: (60,R14) -> R14D,R14W,R14B);
GPR_ALIAS!(R15_ALIAS: (64,R15) -> R15D,R15W,R15B);
GPR_ALIAS!(RIP_ALIAS: (68,RIP));
qinsoon's avatar
qinsoon committed
139

140
lazy_static! {
qinsoon's avatar
qinsoon committed
141 142
    /// a map from 64-bit register IDs to a vector of its aliased register (Values),
    /// including the 64-bit register
143 144
    pub static ref GPR_ALIAS_TABLE : LinkedHashMap<MuID, Vec<P<Value>>> = {
        let mut ret = LinkedHashMap::new();
qinsoon's avatar
qinsoon committed
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166

        ret.insert(RAX.id(), RAX_ALIAS.to_vec());
        ret.insert(RCX.id(), RCX_ALIAS.to_vec());
        ret.insert(RDX.id(), RDX_ALIAS.to_vec());
        ret.insert(RBX.id(), RBX_ALIAS.to_vec());
        ret.insert(RSP.id(), RSP_ALIAS.to_vec());
        ret.insert(RBP.id(), RBP_ALIAS.to_vec());
        ret.insert(RSI.id(), RSI_ALIAS.to_vec());
        ret.insert(RDI.id(), RDI_ALIAS.to_vec());
        ret.insert(R8.id() , R8_ALIAS.to_vec() );
        ret.insert(R9.id() , R9_ALIAS.to_vec() );
        ret.insert(R10.id(), R10_ALIAS.to_vec());
        ret.insert(R11.id(), R11_ALIAS.to_vec());
        ret.insert(R12.id(), R12_ALIAS.to_vec());
        ret.insert(R13.id(), R13_ALIAS.to_vec());
        ret.insert(R14.id(), R14_ALIAS.to_vec());
        ret.insert(R15.id(), R15_ALIAS.to_vec());
        ret.insert(RIP.id(), RIP_ALIAS.to_vec());

        ret
    };

qinsoon's avatar
qinsoon committed
167
    /// a map from any register to its 64-bit alias
168 169 170 171 172 173 174 175 176 177 178 179
    pub static ref GPR_ALIAS_LOOKUP : HashMap<MuID, P<Value>> = {
        let mut ret = HashMap::new();

        for vec in GPR_ALIAS_TABLE.values() {
            let colorable = vec[0].clone();

            for gpr in vec {
                ret.insert(gpr.id(), colorable.clone());
            }
        }

        ret
qinsoon's avatar
qinsoon committed
180
    };
181 182
}

qinsoon's avatar
qinsoon committed
183 184
/// returns P<Value> for a register ID of its alias of the given length
/// panics if the ID is not a machine register ID
185 186 187 188
pub fn get_alias_for_length(id: MuID, length: usize) -> P<Value> {
    if id < FPR_ID_START {
        let vec = match GPR_ALIAS_TABLE.get(&id) {
            Some(vec) => vec,
189
            None => panic!("didnt find {} as GPR", id),
190 191 192 193 194 195 196 197
        };

        match length {
            64 => vec[0].clone(),
            32 => vec[1].clone(),
            16 => vec[2].clone(),
            8 => vec[3].clone(),
            1 => vec[3].clone(),
198
            _ => panic!("unexpected length {} for {}", length, vec[0]),
199 200
        }
    } else {
qinsoon's avatar
qinsoon committed
201
        for r in ALL_FPRS.iter() {
202 203 204 205 206 207 208 209
            if r.id() == id {
                return r.clone();
            }
        }

        panic!("didnt find {} as FPR", id)
    }
}
qinsoon's avatar
qinsoon committed
210

qinsoon's avatar
qinsoon committed
211
/// are two registers aliased? (both must be machine register IDs, otherwise this function panics)
212
pub fn is_aliased(id1: MuID, id2: MuID) -> bool {
qinsoon's avatar
qinsoon committed
213
    if get_color_for_precolored(id1) == get_color_for_precolored(id2) {
214 215 216 217 218
        // we need to specially check the case for AH/BH/CH/DH
        // because both AH and AL are aliased to RAX, but AH and AL are not aliased
        macro_rules! is_match {
            ($a1: expr, $a2: expr; $b: expr) => {
                $a1 == $b.id() || $a2 == $b.id()
219
            };
220 221 222 223 224 225 226 227 228 229 230 231 232
        };

        if is_match!(id1, id2; AH) {
            return false;
        } else if is_match!(id1, id2; BH) {
            return false;
        } else if is_match!(id1, id2; CH) {
            return false;
        } else if is_match!(id1, id2; DH) {
            return false;
        } else {
            return true;
        }
233
    } else {
234
        false
235 236 237
    }
}

qinsoon's avatar
qinsoon committed
238
/// gets the color for a machine register (returns 64-bit alias for it)
qinsoon's avatar
qinsoon committed
239 240 241
pub fn get_color_for_precolored(id: MuID) -> MuID {
    debug_assert!(id < MACHINE_ID_END);

242 243 244
    if id < FPR_ID_START {
        match GPR_ALIAS_LOOKUP.get(&id) {
            Some(val) => val.id(),
245
            None => panic!("cannot find GPR {}", id),
246 247 248 249
        }
    } else {
        // we do not have alias for FPRs
        id
qinsoon's avatar
qinsoon committed
250 251
    }
}
252

qinsoon's avatar
qinsoon committed
253
/// returns register length (in bits) for an integer operand
254 255 256 257 258 259
#[inline(always)]
pub fn check_op_len(op: &P<Value>) -> usize {
    match op.ty.get_int_length() {
        Some(64) => 64,
        Some(32) => 32,
        Some(16) => 16,
qinsoon's avatar
qinsoon committed
260 261
        Some(8) => 8,
        Some(1) => 8,
262
        _ => panic!("unsupported register length for x64: {}", op.ty),
263 264 265
    }
}

qinsoon's avatar
qinsoon committed
266
lazy_static! {
qinsoon's avatar
qinsoon committed
267 268
    /// GPRs for returning values
    //  order matters
qinsoon's avatar
qinsoon committed
269
    pub static ref RETURN_GPRS : [P<Value>; 2] = [
qinsoon's avatar
qinsoon committed
270 271 272
        RAX.clone(),
        RDX.clone(),
    ];
273

qinsoon's avatar
qinsoon committed
274 275
    /// GPRs for passing arguments
    //  order matters
qinsoon's avatar
qinsoon committed
276
    pub static ref ARGUMENT_GPRS : [P<Value>; 6] = [
qinsoon's avatar
qinsoon committed
277 278 279 280 281 282 283
        RDI.clone(),
        RSI.clone(),
        RDX.clone(),
        RCX.clone(),
        R8.clone(),
        R9.clone()
    ];
284

qinsoon's avatar
qinsoon committed
285
    /// callee saved GPRs
qinsoon's avatar
qinsoon committed
286
    pub static ref CALLEE_SAVED_GPRS : [P<Value>; 6] = [
qinsoon's avatar
qinsoon committed
287 288 289 290 291 292 293
        RBX.clone(),
        RBP.clone(),
        R12.clone(),
        R13.clone(),
        R14.clone(),
        R15.clone()
    ];
qinsoon's avatar
qinsoon committed
294

qinsoon's avatar
qinsoon committed
295
    /// caller saved GPRs
qinsoon's avatar
qinsoon committed
296
    pub static ref CALLER_SAVED_GPRS : [P<Value>; 9] = [
qinsoon's avatar
qinsoon committed
297 298 299 300 301 302 303 304 305 306
        RAX.clone(),
        RCX.clone(),
        RDX.clone(),
        RSI.clone(),
        RDI.clone(),
        R8.clone(),
        R9.clone(),
        R10.clone(),
        R11.clone()
    ];
307

qinsoon's avatar
qinsoon committed
308 309
    /// all the genral purpose registers
    //  FIXME: why RBP is commented out?
qinsoon's avatar
qinsoon committed
310
    static ref ALL_GPRS : [P<Value>; 15] = [
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
        RAX.clone(),
        RCX.clone(),
        RDX.clone(),
        RBX.clone(),
        RSP.clone(),
//        RBP.clone(),
        RSI.clone(),
        RDI.clone(),
        R8.clone(),
        R9.clone(),
        R10.clone(),
        R11.clone(),
        R12.clone(),
        R13.clone(),
        R14.clone(),
        R15.clone()
    ];
qinsoon's avatar
qinsoon committed
328 329
}

qinsoon's avatar
qinsoon committed
330
pub const FPR_ID_START: usize = 100;
331

332
lazy_static! {
qinsoon's avatar
qinsoon committed
333
    // floating point registers, we use SSE registers
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
    pub static ref XMM0  : P<Value> = FPR!(FPR_ID_START,    "xmm0");
    pub static ref XMM1  : P<Value> = FPR!(FPR_ID_START + 1,"xmm1");
    pub static ref XMM2  : P<Value> = FPR!(FPR_ID_START + 2,"xmm2");
    pub static ref XMM3  : P<Value> = FPR!(FPR_ID_START + 3,"xmm3");
    pub static ref XMM4  : P<Value> = FPR!(FPR_ID_START + 4,"xmm4");
    pub static ref XMM5  : P<Value> = FPR!(FPR_ID_START + 5,"xmm5");
    pub static ref XMM6  : P<Value> = FPR!(FPR_ID_START + 6,"xmm6");
    pub static ref XMM7  : P<Value> = FPR!(FPR_ID_START + 7,"xmm7");
    pub static ref XMM8  : P<Value> = FPR!(FPR_ID_START + 8,"xmm8");
    pub static ref XMM9  : P<Value> = FPR!(FPR_ID_START + 9,"xmm9");
    pub static ref XMM10 : P<Value> = FPR!(FPR_ID_START + 10,"xmm10");
    pub static ref XMM11 : P<Value> = FPR!(FPR_ID_START + 11,"xmm11");
    pub static ref XMM12 : P<Value> = FPR!(FPR_ID_START + 12,"xmm12");
    pub static ref XMM13 : P<Value> = FPR!(FPR_ID_START + 13,"xmm13");
    pub static ref XMM14 : P<Value> = FPR!(FPR_ID_START + 14,"xmm14");
    pub static ref XMM15 : P<Value> = FPR!(FPR_ID_START + 15,"xmm15");
350

qinsoon's avatar
qinsoon committed
351 352
    /// FPRs to return values
    //  order matters
qinsoon's avatar
qinsoon committed
353
    pub static ref RETURN_FPRS : [P<Value>; 2] = [
qinsoon's avatar
qinsoon committed
354 355 356
        XMM0.clone(),
        XMM1.clone()
    ];
357

qinsoon's avatar
qinsoon committed
358 359
    /// FPRs to pass arguments
    //  order matters
qinsoon's avatar
qinsoon committed
360
    pub static ref ARGUMENT_FPRS : [P<Value>; 8] = [
qinsoon's avatar
qinsoon committed
361 362
        XMM0.clone(),
        XMM1.clone(),
qinsoon's avatar
qinsoon committed
363 364 365 366 367 368 369
        XMM2.clone(),
        XMM3.clone(),
        XMM4.clone(),
        XMM5.clone(),
        XMM6.clone(),
        XMM7.clone()
    ];
370

qinsoon's avatar
qinsoon committed
371
    /// callee saved FPRs (none for x86_64)
qinsoon's avatar
qinsoon committed
372
    pub static ref CALLEE_SAVED_FPRS : [P<Value>; 0] = [];
qinsoon's avatar
qinsoon committed
373

qinsoon's avatar
qinsoon committed
374
    /// caller saved FPRs
qinsoon's avatar
qinsoon committed
375
    pub static ref CALLER_SAVED_FPRS : [P<Value>; 16] = [
qinsoon's avatar
qinsoon committed
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
        XMM0.clone(),
        XMM1.clone(),
        XMM2.clone(),
        XMM3.clone(),
        XMM4.clone(),
        XMM5.clone(),
        XMM6.clone(),
        XMM7.clone(),
        XMM8.clone(),
        XMM9.clone(),
        XMM10.clone(),
        XMM11.clone(),
        XMM12.clone(),
        XMM13.clone(),
        XMM14.clone(),
        XMM15.clone(),
    ];
393

qinsoon's avatar
qinsoon committed
394
    /// all the floating point registers
qinsoon's avatar
qinsoon committed
395
    static ref ALL_FPRS : [P<Value>; 16] = [
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
        XMM0.clone(),
        XMM1.clone(),
        XMM2.clone(),
        XMM3.clone(),
        XMM4.clone(),
        XMM5.clone(),
        XMM6.clone(),
        XMM7.clone(),
        XMM8.clone(),
        XMM9.clone(),
        XMM10.clone(),
        XMM11.clone(),
        XMM12.clone(),
        XMM13.clone(),
        XMM14.clone(),
        XMM15.clone(),
    ];
413 414
}

qinsoon's avatar
qinsoon committed
415
lazy_static! {
qinsoon's avatar
qinsoon committed
416
    /// a map for all the machine registers, from ID to P<Value>
qinsoon's avatar
qinsoon committed
417
    pub static ref ALL_MACHINE_REGS : LinkedHashMap<MuID, P<Value>> = {
418
        let mut map = LinkedHashMap::new();
419 420 421 422 423 424 425

        for vec in GPR_ALIAS_TABLE.values() {
            for reg in vec {
                map.insert(reg.id(), reg.clone());
            }
        }

426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
        map.insert(XMM0.id(), XMM0.clone());
        map.insert(XMM1.id(), XMM1.clone());
        map.insert(XMM2.id(), XMM2.clone());
        map.insert(XMM3.id(), XMM3.clone());
        map.insert(XMM4.id(), XMM4.clone());
        map.insert(XMM5.id(), XMM5.clone());
        map.insert(XMM6.id(), XMM6.clone());
        map.insert(XMM7.id(), XMM7.clone());
        map.insert(XMM8.id(), XMM8.clone());
        map.insert(XMM9.id(), XMM9.clone());
        map.insert(XMM10.id(), XMM10.clone());
        map.insert(XMM11.id(), XMM11.clone());
        map.insert(XMM12.id(), XMM12.clone());
        map.insert(XMM13.id(), XMM13.clone());
        map.insert(XMM14.id(), XMM14.clone());
        map.insert(XMM15.id(), XMM15.clone());

        map
    };
445

446
    /// all the usable general purpose registers for reg allocator to assign
qinsoon's avatar
qinsoon committed
447 448 449
    //  order matters here (since register allocator will prioritize assigning temporaries
    //  to a register that appears early)
    //  we put caller saved regs first (they imposes no overhead if there is no call instruction)
450
    pub static ref ALL_USABLE_GPRS : Vec<P<Value>> = vec![
qinsoon's avatar
qinsoon committed
451
        // caller saved registers
452 453 454 455 456 457 458 459 460
        RAX.clone(),
        RCX.clone(),
        RDX.clone(),
        RSI.clone(),
        RDI.clone(),
        R8.clone(),
        R9.clone(),
        R10.clone(),
        R11.clone(),
qinsoon's avatar
qinsoon committed
461
        // callee saved registers
462 463 464 465 466
        RBX.clone(),
        R12.clone(),
        R13.clone(),
        R14.clone(),
        R15.clone(),
467 468 469 470 471 472 473
    ];

    /// all the usable floating point registers for reg allocator to assign
    //  order matters here (since register allocator will prioritize assigning temporaries
    //  to a register that appears early)
    //  we put caller saved regs first (they imposes no overhead if there is no call instruction)
    pub static ref ALL_USABLE_FPRS : Vec<P<Value>> = vec![
qinsoon's avatar
qinsoon committed
474
        // floating point registers
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491
        XMM0.clone(),
        XMM1.clone(),
        XMM2.clone(),
        XMM3.clone(),
        XMM4.clone(),
        XMM5.clone(),
        XMM6.clone(),
        XMM7.clone(),
        XMM8.clone(),
        XMM9.clone(),
        XMM10.clone(),
        XMM11.clone(),
        XMM12.clone(),
        XMM13.clone(),
        XMM14.clone(),
        XMM15.clone()
    ];
492 493 494 495 496 497 498 499 500 501 502

    /// all the usable registers for register allocators to assign
    //  order matters here (since register allocator will prioritize assigning temporaries
    //  to a register that appears early)
    //  we put caller saved regs first (they imposes no overhead if there is no call instruction)
    pub static ref ALL_USABLE_MACHINE_REGS : Vec<P<Value>> = {
        let mut ret = vec![];
        ret.extend_from_slice(&ALL_USABLE_GPRS);
        ret.extend_from_slice(&ALL_USABLE_FPRS);
        ret
    };
503 504 505 506 507 508 509 510 511 512 513 514

    /// all the caller saved registers
    pub static ref ALL_CALLER_SAVED_REGS : Vec<P<Value>> = {
        let mut ret = vec![];
        for r in CALLER_SAVED_GPRS.iter() {
            ret.push(r.clone());
        }
        for r in CALLER_SAVED_FPRS.iter() {
            ret.push(r.clone());
        }
        ret
    };
qinsoon's avatar
qinsoon committed
515 516
}

qinsoon's avatar
qinsoon committed
517
/// creates context for each machine register in FunctionContext
qinsoon's avatar
qinsoon committed
518
pub fn init_machine_regs_for_func(func_context: &mut FunctionContext) {
qinsoon's avatar
qinsoon committed
519
    for reg in ALL_MACHINE_REGS.values() {
520
        let reg_id = reg.extract_ssa_id().unwrap();
qinsoon's avatar
qinsoon committed
521
        let entry = SSAVarEntry::new(reg.clone());
522

523 524 525 526
        func_context.values.insert(reg_id, entry);
    }
}

qinsoon's avatar
qinsoon committed
527
/// gets the number of registers in a certain register group
528
pub fn number_of_usable_regs_in_group(group: RegGroup) -> usize {
529
    match group {
qinsoon's avatar
qinsoon committed
530
        RegGroup::GPR => ALL_USABLE_GPRS.len(),
531
        RegGroup::GPREX => ALL_USABLE_GPRS.len(),
532
        RegGroup::FPR => ALL_USABLE_FPRS.len(),
qinsoon's avatar
qinsoon committed
533 534 535
    }
}

qinsoon's avatar
qinsoon committed
536
/// returns the number of all registers on this platform
537
pub fn number_of_all_regs() -> usize {
qinsoon's avatar
qinsoon committed
538
    ALL_MACHINE_REGS.len()
539 540
}

qinsoon's avatar
qinsoon committed
541
/// returns a reference to a map for all the registers
542
pub fn all_regs() -> &'static LinkedHashMap<MuID, P<Value>> {
qinsoon's avatar
qinsoon committed
543
    &ALL_MACHINE_REGS
544 545
}

qinsoon's avatar
qinsoon committed
546
/// returns a reference to a vector of all usable registers
547
pub fn all_usable_regs() -> &'static Vec<P<Value>> {
qinsoon's avatar
qinsoon committed
548
    &ALL_USABLE_MACHINE_REGS
549 550
}

qinsoon's avatar
qinsoon committed
551 552
/// returns RegGroup for a given machine register (by ID)
/// panics if the ID is not a machine register
553
pub fn pick_group_for_reg(reg_id: MuID) -> RegGroup {
554
    let reg = all_regs().get(&reg_id).unwrap();
555
    RegGroup::get_from_value(reg)
556 557
}

558
/// gets the previouse frame pointer with respect to the current
559 560 561 562 563
#[inline(always)]
pub fn get_previous_frame_pointer(frame_pointer: Address) -> Address {
    unsafe { frame_pointer.load::<Address>() }
}

564
/// gets the return address for the current frame pointer
565 566
#[inline(always)]
pub fn get_return_address(frame_pointer: Address) -> Address {
567
    unsafe { (frame_pointer + 8 as ByteSize).load::<Address>() }
568 569
}

570
/// gets the stack pointer before the current frame was created
571
#[inline(always)]
572
pub fn get_previous_stack_pointer(frame_pointer: Address, stack_arg_size: usize) -> Address {
573
    frame_pointer + 16 as ByteSize + stack_arg_size
574 575
}

576
/// sets the stack point
577 578 579 580 581
#[inline(always)]
pub fn set_previous_frame_pointer(frame_pointer: Address, value: Address) {
    unsafe { frame_pointer.store::<Address>(value) }
}

582
/// gets the return address for the current frame pointer
583 584
#[inline(always)]
pub fn set_return_address(frame_pointer: Address, value: Address) {
585
    unsafe { (frame_pointer + 8 as ByteSize).store::<Address>(value) }
586 587
}

588 589
/// returns offset of callee saved register
/// Reg should be a 64-bit callee saved GPR or FPR
590 591 592 593 594 595
pub fn get_callee_saved_offset(reg: MuID) -> isize {
    debug_assert!(is_callee_saved(reg) && reg != RBP.id());

    let id = if reg == RBX.id() {
        0
    } else {
qinsoon's avatar
qinsoon committed
596
        (reg - R12.id()) / 4 + 1
597
    };
qinsoon's avatar
qinsoon committed
598
    (id as isize + 1) * (-8)
599
}
600

qinsoon's avatar
qinsoon committed
601 602
/// is a machine register (by ID) callee saved?
/// returns false if the ID is not a machine register
603
pub fn is_callee_saved(reg_id: MuID) -> bool {
qinsoon's avatar
qinsoon committed
604
    for reg in CALLEE_SAVED_GPRS.iter() {
605 606 607 608
        if reg_id == reg.extract_ssa_id().unwrap() {
            return true;
        }
    }
609 610

    false
611 612
}

qinsoon's avatar
qinsoon committed
613
/// is a constant a valid x86_64 immediate number (32 bits integer)?
614
pub fn is_valid_x86_imm(op: &P<Value>) -> bool {
615 616
    use std::i32;

617 618 619
    if let Some(int_width) = op.ty.get_int_length() {
        match int_width {
            1...32 => op.is_int_const(),
620 621 622
            64 => match op.v {
                Value_::Constant(Constant::Int(val)) => {
                    val as i64 >= i32::MIN as i64 && val as i64 <= i32::MAX as i64
623
                }
624 625
                _ => false,
            },
626
            128 => false,
627
            _ => unimplemented!(),
628 629 630
        }
    } else {
        false
631
    }
632 633 634
}

use ast::inst::*;
qinsoon's avatar
qinsoon committed
635 636

/// estimate the number of machine instruction for each IR instruction
637 638 639 640 641
pub fn estimate_insts_for_ir(inst: &Instruction) -> usize {
    use ast::inst::Instruction_::*;

    match inst.v {
        // simple
qinsoon's avatar
qinsoon committed
642
        BinOp(_, _, _) => 1,
qinsoon's avatar
qinsoon committed
643
        BinOpWithStatus(_, _, _, _) => 2,
qinsoon's avatar
qinsoon committed
644 645
        CmpOp(_, _, _) => 1,
        ConvOp { .. } => 0,
646

647 648 649 650 651 652 653 654 655 656
        CommonInst_Tr64IsFp(_)
        | CommonInst_Tr64IsInt(_)
        | CommonInst_Tr64IsRef(_)
        | CommonInst_Tr64FromFp(_)
        | CommonInst_Tr64FromInt(_)
        | CommonInst_Tr64FromRef(_, _)
        | CommonInst_Tr64ToFp(_)
        | CommonInst_Tr64ToInt(_)
        | CommonInst_Tr64ToRef(_)
        | CommonInst_Tr64ToTag(_) => 3,
qinsoon's avatar
qinsoon committed
657

658
        // control flow
qinsoon's avatar
qinsoon committed
659 660 661 662 663 664
        Branch1(_) => 1,
        Branch2 { .. } => 1,
        Select { .. } => 2,
        Watchpoint { .. } => 1,
        WPBranch { .. } => 2,
        Switch { .. } => 3,
665 666

        // call
qinsoon's avatar
qinsoon committed
667 668
        ExprCall { .. } | ExprCCall { .. } | Call { .. } | CCall { .. } => 5,
        Return(_) => 1,
669 670 671
        TailCall(_) => 1,

        // memory access
qinsoon's avatar
qinsoon committed
672 673 674 675 676 677
        Load { .. } | Store { .. } => 1,
        CmpXchg { .. } => 1,
        AtomicRMW { .. } => 1,
        AllocA(_) => 1,
        AllocAHybrid(_, _) => 1,
        Fence(_) => 1,
678 679

        // memory addressing
680 681 682 683 684
        GetIRef(_)
        | GetFieldIRef { .. }
        | GetElementIRef { .. }
        | ShiftIRef { .. }
        | GetVarPartIRef { .. } => 0,
685

qinsoon's avatar
qinsoon committed
686
        // runtime call
687
        New(_) | NewHybrid(_, _) => 10,
688
        NewStack(_) | NewThread { .. } | NewFrameCursor(_) => 10,
qinsoon's avatar
qinsoon committed
689
        ThreadExit => 10,
690 691
        CurrentStack => 10,
        KillStack(_) => 10,
qinsoon's avatar
qinsoon committed
692
        Throw(_) => 10,
qinsoon's avatar
qinsoon committed
693
        SwapStackExpr { .. } | SwapStackExc { .. } | SwapStackKill { .. } => 10,
694
        CommonInst_GetThreadLocal | CommonInst_SetThreadLocal(_) => 10,
qinsoon's avatar
qinsoon committed
695
        CommonInst_Pin(_) | CommonInst_Unpin(_) | CommonInst_GetAddr(_) => 10,
696 697 698

        // others
        Move(_) => 0,
qinsoon's avatar
qinsoon committed
699
        PrintHex(_) => 10,
700
        SetRetval(_) => 10,
qinsoon's avatar
qinsoon committed
701
        GetVMThreadLocal => 10,
702
        ExnInstruction { ref inner, .. } => estimate_insts_for_ir(&inner),
703
    }
704
}
705 706

pub fn call_stack_size(sig: P<MuFuncSig>, vm: &VM) -> usize {
707 708 709
    use compiler::backend::x86_64::callconv::mu;
    let (size, _) = mu::compute_stack_args(&sig.arg_tys, vm);
    size
710
}