GitLab will be upgraded to the 12.10.14-ce.0 on 28 Sept 2020 at 2.00pm (AEDT) to 2.30pm (AEDT). During the update, GitLab and Mattermost services will not be available. If you have any concerns with this, please talk to us at N110 (b) CSIT building.

mod.rs 21.8 KB
Newer Older
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1
// Copyright 2017 The Australian National University
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
6
//
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
7
//     http://www.apache.org/licenses/LICENSE-2.0
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.

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

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

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) => {
qinsoon's avatar
qinsoon committed
61 62 63 64 65 66 67
        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);

qinsoon's avatar
qinsoon committed
68 69
            pub static ref $alias : [P<Value>; 5] = [$r64.clone(), $r32.clone(), $r16.clone(),
                                                     $r8l.clone(), $r8h.clone()];
qinsoon's avatar
qinsoon committed
70 71 72
        }
    };

qinsoon's avatar
qinsoon committed
73 74 75 76 77 78 79
    ($alias: ident: ($id64: expr, $r64: ident) -> $r32: ident, $r16: ident, $r8: ident) => {
        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 );

qinsoon's avatar
qinsoon committed
80 81
            pub static ref $alias : [P<Value>; 4] = [$r64.clone(), $r32.clone(),
                                                     $r16.clone(), $r8.clone()];
qinsoon's avatar
qinsoon committed
82 83 84 85 86
        }
    };

    ($alias: ident: ($id64: expr, $r64: ident)) => {
        lazy_static!{
qinsoon's avatar
qinsoon committed
87
            pub static ref $r64 : P<Value> = GPR!($id64, stringify!($r64), UINT64_TYPE);
qinsoon's avatar
qinsoon committed
88

qinsoon's avatar
qinsoon committed
89 90
            pub static ref $alias : [P<Value>; 4] = [$r64.clone(), $r64.clone(),
                                                     $r64.clone(), $r64.clone()];
qinsoon's avatar
qinsoon committed
91 92 93 94
        }
    };
}

qinsoon's avatar
qinsoon committed
95
/// a macro to declare a general purpose register
96
macro_rules! GPR {
qinsoon's avatar
qinsoon committed
97
    ($id:expr, $name: expr, $ty: ident) => {
qinsoon's avatar
qinsoon committed
98 99
        {
            P(Value {
100
                hdr: MuEntityHeader::named($id, Arc::new($name.to_string())),
qinsoon's avatar
qinsoon committed
101
                ty: $ty.clone(),
qinsoon's avatar
qinsoon committed
102
                v: Value_::SSAVar($id)
qinsoon's avatar
qinsoon committed
103 104
            })
        }
qinsoon's avatar
qinsoon committed
105 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 {
qinsoon's avatar
qinsoon committed
110
    ($id:expr, $name: expr) => {
qinsoon's avatar
qinsoon committed
111 112
        {
            P(Value {
113
                hdr: MuEntityHeader::named($id, Arc::new($name.to_string())),
qinsoon's avatar
qinsoon committed
114
                ty: DOUBLE_TYPE.clone(),
qinsoon's avatar
qinsoon committed
115
                v: Value_::SSAVar($id)
qinsoon's avatar
qinsoon committed
116 117
            })
        }
qinsoon's avatar
qinsoon committed
118 119 120
    };
}

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

124 125
GPR_ALIAS!(RAX_ALIAS: (0, RAX)  -> EAX, AX , AL, AH);
GPR_ALIAS!(RCX_ALIAS: (5, RCX)  -> ECX, CX , CL, CH);
126
GPR_ALIAS!(RDX_ALIAS: (10,RDX)  -> EDX, DX , DL, DH);
127 128 129 130 131 132 133 134 135 136 137 138 139 140
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
141

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

        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
169
    /// a map from any register to its 64-bit alias
qinsoon's avatar
qinsoon committed
170 171 172 173 174 175 176 177 178 179 180 181
    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
182
    };
qinsoon's avatar
qinsoon committed
183 184
}

qinsoon's avatar
qinsoon committed
185 186
/// returns P<Value> for a register ID of its alias of the given length
/// panics if the ID is not a machine register ID
qinsoon's avatar
qinsoon committed
187 188 189 190
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,
191
            None => panic!("didnt find {} as GPR", id)
qinsoon's avatar
qinsoon committed
192 193 194 195 196 197 198 199
        };

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

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

qinsoon's avatar
qinsoon committed
213
/// are two registers aliased? (both must be machine register IDs, otherwise this function panics)
214
pub fn is_aliased(id1: MuID, id2: MuID) -> bool {
qinsoon's avatar
qinsoon committed
215
    if get_color_for_precolored(id1) == get_color_for_precolored(id2) {
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
        // 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()
            }
        };

        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;
        }
235
    } else {
qinsoon's avatar
qinsoon committed
236
        false
237 238 239
    }
}

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

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

qinsoon's avatar
qinsoon committed
255
/// returns register length (in bits) for an integer operand
qinsoon's avatar
qinsoon committed
256 257 258 259 260 261
#[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
262 263
        Some(8) => 8,
        Some(1) => 8,
264
        _ => panic!("unsupported register length for x64: {}", op.ty)
qinsoon's avatar
qinsoon committed
265 266 267
    }
}

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

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

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

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

qinsoon's avatar
qinsoon committed
310 311
    /// all the genral purpose registers
    //  FIXME: why RBP is commented out?
qinsoon's avatar
qinsoon committed
312
    static ref ALL_GPRS : [P<Value>; 15] = [
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
        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
330 331
}

qinsoon's avatar
qinsoon committed
332
pub const FPR_ID_START: usize = 100;
qinsoon's avatar
qinsoon committed
333

qinsoon's avatar
qinsoon committed
334
lazy_static!{
qinsoon's avatar
qinsoon committed
335
    // floating point registers, we use SSE registers
qinsoon's avatar
qinsoon committed
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
    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");
352

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

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

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

qinsoon's avatar
qinsoon committed
376
    /// caller saved FPRs
qinsoon's avatar
qinsoon committed
377
    pub static ref CALLER_SAVED_FPRS : [P<Value>; 16] = [
qinsoon's avatar
qinsoon committed
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
        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(),
    ];
395

qinsoon's avatar
qinsoon committed
396
    /// all the floating point registers
qinsoon's avatar
qinsoon committed
397
    static ref ALL_FPRS : [P<Value>; 16] = [
qinsoon's avatar
qinsoon committed
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414
        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(),
    ];
415 416
}

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

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

428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
        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
    };
447

448
    /// all the usable general purpose registers for reg allocator to assign
qinsoon's avatar
qinsoon committed
449 450 451
    //  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)
452
    pub static ref ALL_USABLE_GPRS : Vec<P<Value>> = vec![
qinsoon's avatar
qinsoon committed
453
        // caller saved registers
454 455 456 457 458 459 460 461 462
        RAX.clone(),
        RCX.clone(),
        RDX.clone(),
        RSI.clone(),
        RDI.clone(),
        R8.clone(),
        R9.clone(),
        R10.clone(),
        R11.clone(),
qinsoon's avatar
qinsoon committed
463
        // callee saved registers
464 465 466 467 468
        RBX.clone(),
        R12.clone(),
        R13.clone(),
        R14.clone(),
        R15.clone(),
469 470 471 472 473 474 475
    ];

    /// 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
476
        // floating point registers
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
        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()
    ];
494 495 496 497 498 499 500 501 502 503 504

    /// 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
    };
505 506 507 508 509 510 511 512 513 514 515 516

    /// 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
517 518
}

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

qinsoon's avatar
qinsoon committed
525 526 527 528
        func_context.values.insert(reg_id, entry);
    }
}

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

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

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

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

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

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

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

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

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

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

590 591
/// returns offset of callee saved register
/// Reg should be a 64-bit callee saved GPR or FPR
592 593 594 595 596 597
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
598
        (reg - R12.id()) / 4 + 1
599
    };
qinsoon's avatar
qinsoon committed
600
    (id as isize + 1) * (-8)
601
}
602

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

    false
613 614
}

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

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

use ast::inst::*;
qinsoon's avatar
qinsoon committed
639 640

/// estimate the number of machine instruction for each IR instruction
641 642 643 644 645
pub fn estimate_insts_for_ir(inst: &Instruction) -> usize {
    use ast::inst::Instruction_::*;

    match inst.v {
        // simple
qinsoon's avatar
qinsoon committed
646
        BinOp(_, _, _) => 1,
qinsoon's avatar
qinsoon committed
647
        BinOpWithStatus(_, _, _, _) => 2,
qinsoon's avatar
qinsoon committed
648 649
        CmpOp(_, _, _) => 1,
        ConvOp { .. } => 0,
650 651

        // control flow
qinsoon's avatar
qinsoon committed
652 653 654 655 656 657
        Branch1(_) => 1,
        Branch2 { .. } => 1,
        Select { .. } => 2,
        Watchpoint { .. } => 1,
        WPBranch { .. } => 2,
        Switch { .. } => 3,
658 659

        // call
qinsoon's avatar
qinsoon committed
660 661
        ExprCall { .. } | ExprCCall { .. } | Call { .. } | CCall { .. } => 5,
        Return(_) => 1,
662 663 664
        TailCall(_) => 1,

        // memory access
qinsoon's avatar
qinsoon committed
665 666 667 668 669 670
        Load { .. } | Store { .. } => 1,
        CmpXchg { .. } => 1,
        AtomicRMW { .. } => 1,
        AllocA(_) => 1,
        AllocAHybrid(_, _) => 1,
        Fence(_) => 1,
671 672

        // memory addressing
qinsoon's avatar
qinsoon committed
673 674 675 676 677
        GetIRef(_) |
        GetFieldIRef { .. } |
        GetElementIRef { .. } |
        ShiftIRef { .. } |
        GetVarPartIRef { .. } => 0,
678

qinsoon's avatar
qinsoon committed
679
        // runtime call
680
        New(_) | NewHybrid(_, _) => 10,
681
        NewStack(_) | NewThread { .. } | NewFrameCursor(_) => 10,
qinsoon's avatar
qinsoon committed
682
        ThreadExit => 10,
683 684
        CurrentStack => 10,
        KillStack(_) => 10,
qinsoon's avatar
qinsoon committed
685
        Throw(_) => 10,
qinsoon's avatar
qinsoon committed
686
        SwapStackExpr { .. } | SwapStackExc { .. } | SwapStackKill { .. } => 10,
687
        CommonInst_GetThreadLocal | CommonInst_SetThreadLocal(_) => 10,
qinsoon's avatar
qinsoon committed
688
        CommonInst_Pin(_) | CommonInst_Unpin(_) => 10,
689 690 691

        // others
        Move(_) => 0,
qinsoon's avatar
qinsoon committed
692
        PrintHex(_) => 10,
693
        SetRetval(_) => 10,
qinsoon's avatar
qinsoon committed
694
        ExnInstruction { ref inner, .. } => estimate_insts_for_ir(&inner),
695
        _ => unimplemented!()
696
    }
697
}
698 699

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