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.7% of users enabled 2FA.

mod.rs 20.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
29
30
/// assembly backend as AOT compiler
mod asm_backend;
use compiler::backend::x86_64::asm_backend::ASMCodeGen;

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

39
40
use utils::Address;
use utils::ByteSize;
41
42
use ast::ptr::P;
use ast::ir::*;
qinsoon's avatar
qinsoon committed
43
use ast::types::*;
qinsoon's avatar
qinsoon committed
44
use compiler::backend::RegGroup;
qinsoon's avatar
qinsoon committed
45

46
use utils::LinkedHashMap;
47
48
use std::collections::HashMap;

49
// number of normal callee saved registers (excluding RSP and RBP)
50
pub const CALLEE_SAVED_COUNT: usize = 5;
51

qinsoon's avatar
qinsoon committed
52
/// a macro to declare a set of general purpose registers that are aliased to the first one
qinsoon's avatar
qinsoon committed
53
macro_rules! GPR_ALIAS {
qinsoon's avatar
qinsoon committed
54
55
56
57
58
59
60
61
62
63
64
65
    ($alias: ident: ($id64: expr, $r64: ident) -> $r32: ident, $r16: ident, $r8l: ident, $r8h: 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 $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()];
        }
    };

qinsoon's avatar
qinsoon committed
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
    ($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 );

            pub static ref $alias : [P<Value>; 4] = [$r64.clone(), $r32.clone(), $r16.clone(), $r8.clone()];
        }
    };

    ($alias: ident: ($id64: expr, $r64: ident)) => {
        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
86
/// a macro to declare a general purpose register
87
macro_rules! GPR {
qinsoon's avatar
qinsoon committed
88
    ($id:expr, $name: expr, $ty: ident) => {
qinsoon's avatar
qinsoon committed
89
90
        {
            P(Value {
qinsoon's avatar
qinsoon committed
91
                hdr: MuEntityHeader::named($id, $name.to_string()),
qinsoon's avatar
qinsoon committed
92
                ty: $ty.clone(),
qinsoon's avatar
qinsoon committed
93
                v: Value_::SSAVar($id)
qinsoon's avatar
qinsoon committed
94
95
            })
        }
qinsoon's avatar
qinsoon committed
96
97
98
    };
}

qinsoon's avatar
qinsoon committed
99
/// a macro to declare a floating point register
qinsoon's avatar
qinsoon committed
100
macro_rules! FPR {
qinsoon's avatar
qinsoon committed
101
    ($id:expr, $name: expr) => {
qinsoon's avatar
qinsoon committed
102
103
        {
            P(Value {
qinsoon's avatar
qinsoon committed
104
                hdr: MuEntityHeader::named($id, $name.to_string()),
qinsoon's avatar
qinsoon committed
105
                ty: DOUBLE_TYPE.clone(),
qinsoon's avatar
qinsoon committed
106
                v: Value_::SSAVar($id)
qinsoon's avatar
qinsoon committed
107
108
            })
        }
qinsoon's avatar
qinsoon committed
109
110
111
    };
}

qinsoon's avatar
qinsoon committed
112
113
114
// declare all general purpose registers for x86_64
// non 64-bit registers are alias of its 64-bit one

115
116
GPR_ALIAS!(RAX_ALIAS: (0, RAX)  -> EAX, AX , AL, AH);
GPR_ALIAS!(RCX_ALIAS: (5, RCX)  -> ECX, CX , CL, CH);
117
GPR_ALIAS!(RDX_ALIAS: (10,RDX)  -> EDX, DX , DL, DH);
118
119
120
121
122
123
124
125
126
127
128
129
130
131
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
132

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

        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
160
    /// a map from any register to its 64-bit alias
qinsoon's avatar
qinsoon committed
161
162
163
164
165
166
167
168
169
170
171
172
    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
173
    };
qinsoon's avatar
qinsoon committed
174
175
}

qinsoon's avatar
qinsoon committed
176
177
/// 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
178
179
180
181
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,
182
            None => panic!("didnt find {} as GPR", id)
qinsoon's avatar
qinsoon committed
183
184
185
186
187
188
189
190
        };

        match length {
            64 => vec[0].clone(),
            32 => vec[1].clone(),
            16 => vec[2].clone(),
            8 => vec[3].clone(),
            1 => vec[3].clone(),
191
            _ => panic!("unexpected length {} for {}", length, vec[0])
qinsoon's avatar
qinsoon committed
192
193
        }
    } else {
qinsoon's avatar
qinsoon committed
194
        for r in ALL_FPRS.iter() {
qinsoon's avatar
qinsoon committed
195
196
197
198
199
200
201
202
            if r.id() == id {
                return r.clone();
            }
        }

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

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

qinsoon's avatar
mod.rs    
qinsoon committed
231
/// gets the color for a machine register (returns 64-bit alias for it)
qinsoon's avatar
qinsoon committed
232
233
234
pub fn get_color_for_precolored(id: MuID) -> MuID {
    debug_assert!(id < MACHINE_ID_END);

qinsoon's avatar
qinsoon committed
235
236
237
    if id < FPR_ID_START {
        match GPR_ALIAS_LOOKUP.get(&id) {
            Some(val) => val.id(),
238
            None => panic!("cannot find GPR {}", id)
qinsoon's avatar
qinsoon committed
239
240
241
242
        }
    } else {
        // we do not have alias for FPRs
        id
qinsoon's avatar
qinsoon committed
243
244
    }
}
qinsoon's avatar
qinsoon committed
245

qinsoon's avatar
mod.rs    
qinsoon committed
246
/// returns register length (in bits) for an integer operand
qinsoon's avatar
qinsoon committed
247
248
249
250
251
252
#[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,
253
254
        Some(8) => 8,
        Some(1) => 8,
255
        _ => panic!("unsupported register length for x64: {}", op.ty)
qinsoon's avatar
qinsoon committed
256
257
258
    }
}

qinsoon's avatar
qinsoon committed
259
lazy_static! {
qinsoon's avatar
mod.rs    
qinsoon committed
260
261
    /// GPRs for returning values
    //  order matters
qinsoon's avatar
qinsoon committed
262
    pub static ref RETURN_GPRS : [P<Value>; 2] = [
qinsoon's avatar
qinsoon committed
263
264
265
        RAX.clone(),
        RDX.clone(),
    ];
266

qinsoon's avatar
mod.rs    
qinsoon committed
267
268
    /// GPRs for passing arguments
    //  order matters
qinsoon's avatar
qinsoon committed
269
    pub static ref ARGUMENT_GPRS : [P<Value>; 6] = [
qinsoon's avatar
qinsoon committed
270
271
272
273
274
275
276
        RDI.clone(),
        RSI.clone(),
        RDX.clone(),
        RCX.clone(),
        R8.clone(),
        R9.clone()
    ];
277

qinsoon's avatar
mod.rs    
qinsoon committed
278
    /// callee saved GPRs
qinsoon's avatar
qinsoon committed
279
    pub static ref CALLEE_SAVED_GPRS : [P<Value>; 6] = [
qinsoon's avatar
qinsoon committed
280
281
282
283
284
285
286
        RBX.clone(),
        RBP.clone(),
        R12.clone(),
        R13.clone(),
        R14.clone(),
        R15.clone()
    ];
qinsoon's avatar
qinsoon committed
287

qinsoon's avatar
mod.rs    
qinsoon committed
288
    /// caller saved GPRs
qinsoon's avatar
qinsoon committed
289
    pub static ref CALLER_SAVED_GPRS : [P<Value>; 9] = [
qinsoon's avatar
qinsoon committed
290
291
292
293
294
295
296
297
298
299
        RAX.clone(),
        RCX.clone(),
        RDX.clone(),
        RSI.clone(),
        RDI.clone(),
        R8.clone(),
        R9.clone(),
        R10.clone(),
        R11.clone()
    ];
300

qinsoon's avatar
mod.rs    
qinsoon committed
301
302
    /// all the genral purpose registers
    //  FIXME: why RBP is commented out?
qinsoon's avatar
qinsoon committed
303
    static ref ALL_GPRS : [P<Value>; 15] = [
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
        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
321
322
}

323
pub const FPR_ID_START: usize = 100;
qinsoon's avatar
qinsoon committed
324

qinsoon's avatar
qinsoon committed
325
lazy_static!{
qinsoon's avatar
mod.rs    
qinsoon committed
326
    // floating point registers, we use SSE registers
qinsoon's avatar
qinsoon committed
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
    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");
343

qinsoon's avatar
mod.rs    
qinsoon committed
344
345
    /// FPRs to return values
    //  order matters
qinsoon's avatar
qinsoon committed
346
    pub static ref RETURN_FPRS : [P<Value>; 2] = [
qinsoon's avatar
qinsoon committed
347
348
349
        XMM0.clone(),
        XMM1.clone()
    ];
350

qinsoon's avatar
mod.rs    
qinsoon committed
351
352
    /// FPRs to pass arguments
    //  order matters
qinsoon's avatar
qinsoon committed
353
    pub static ref ARGUMENT_FPRS : [P<Value>; 8] = [
qinsoon's avatar
qinsoon committed
354
355
        XMM0.clone(),
        XMM1.clone(),
qinsoon's avatar
qinsoon committed
356
357
358
359
360
361
362
        XMM2.clone(),
        XMM3.clone(),
        XMM4.clone(),
        XMM5.clone(),
        XMM6.clone(),
        XMM7.clone()
    ];
363

qinsoon's avatar
mod.rs    
qinsoon committed
364
    /// callee saved FPRs (none for x86_64)
qinsoon's avatar
qinsoon committed
365
    pub static ref CALLEE_SAVED_FPRS : [P<Value>; 0] = [];
qinsoon's avatar
qinsoon committed
366

qinsoon's avatar
mod.rs    
qinsoon committed
367
    /// caller saved FPRs
qinsoon's avatar
qinsoon committed
368
    pub static ref CALLER_SAVED_FPRS : [P<Value>; 16] = [
qinsoon's avatar
qinsoon committed
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
        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(),
    ];
386

qinsoon's avatar
mod.rs    
qinsoon committed
387
    /// all the floating point registers
qinsoon's avatar
qinsoon committed
388
    static ref ALL_FPRS : [P<Value>; 16] = [
qinsoon's avatar
qinsoon committed
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
        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(),
    ];
qinsoon's avatar
qinsoon committed
406
407
}

qinsoon's avatar
qinsoon committed
408
lazy_static! {
qinsoon's avatar
mod.rs    
qinsoon committed
409
    /// a map for all the machine registers, from ID to P<Value>
qinsoon's avatar
qinsoon committed
410
    pub static ref ALL_MACHINE_REGS : LinkedHashMap<MuID, P<Value>> = {
411
        let mut map = LinkedHashMap::new();
qinsoon's avatar
qinsoon committed
412
413
414
415
416
417
418

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

419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
        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
    };
438

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

    /// 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
mod.rs    
qinsoon committed
467
        // floating point registers
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
        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()
    ];
485
486
487
488
489
490
491
492
493
494
495

    /// 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
    };
qinsoon's avatar
qinsoon committed
496
497
}

qinsoon's avatar
mod.rs    
qinsoon committed
498
/// creates context for each machine register in FunctionContext
499
pub fn init_machine_regs_for_func(func_context: &mut FunctionContext) {
qinsoon's avatar
qinsoon committed
500
    for reg in ALL_MACHINE_REGS.values() {
qinsoon's avatar
qinsoon committed
501
        let reg_id = reg.extract_ssa_id().unwrap();
qinsoon's avatar
qinsoon committed
502
        let entry = SSAVarEntry::new(reg.clone());
503

qinsoon's avatar
qinsoon committed
504
505
506
507
        func_context.values.insert(reg_id, entry);
    }
}

qinsoon's avatar
mod.rs    
qinsoon committed
508
/// gets the number of registers in a certain register group
509
pub fn number_of_usable_regs_in_group(group: RegGroup) -> usize {
qinsoon's avatar
qinsoon committed
510
    match group {
511
        RegGroup::GPR => ALL_USABLE_GPRS.len(),
512
        RegGroup::GPREX => ALL_USABLE_GPRS.len(),
513
        RegGroup::FPR => ALL_USABLE_FPRS.len()
qinsoon's avatar
qinsoon committed
514
515
516
    }
}

qinsoon's avatar
mod.rs    
qinsoon committed
517
/// returns the number of all registers on this platform
qinsoon's avatar
qinsoon committed
518
pub fn number_of_all_regs() -> usize {
qinsoon's avatar
qinsoon committed
519
    ALL_MACHINE_REGS.len()
qinsoon's avatar
qinsoon committed
520
521
}

qinsoon's avatar
mod.rs    
qinsoon committed
522
/// returns a reference to a map for all the registers
523
pub fn all_regs() -> &'static LinkedHashMap<MuID, P<Value>> {
qinsoon's avatar
qinsoon committed
524
    &ALL_MACHINE_REGS
qinsoon's avatar
qinsoon committed
525
526
}

qinsoon's avatar
mod.rs    
qinsoon committed
527
/// returns a reference to a vector of all usable registers
528
pub fn all_usable_regs() -> &'static Vec<P<Value>> {
qinsoon's avatar
qinsoon committed
529
    &ALL_USABLE_MACHINE_REGS
530
531
}

qinsoon's avatar
mod.rs    
qinsoon committed
532
533
/// returns RegGroup for a given machine register (by ID)
/// panics if the ID is not a machine register
534
pub fn pick_group_for_reg(reg_id: MuID) -> RegGroup {
535
    let reg = all_regs().get(&reg_id).unwrap();
536
    RegGroup::get_from_value(reg)
537
538
}

539
/// gets the previouse frame pointer with respect to the current
540
541
542
543
544
#[inline(always)]
pub fn get_previous_frame_pointer(frame_pointer: Address) -> Address {
    unsafe { frame_pointer.load::<Address>() }
}

545
/// gets the return address for the current frame pointer
546
547
#[inline(always)]
pub fn get_return_address(frame_pointer: Address) -> Address {
548
    unsafe { (frame_pointer + 8 as ByteSize).load::<Address>() }
549
550
}

551
/// gets the stack pointer before the current frame was created
552
#[inline(always)]
553
pub fn get_previous_stack_pointer(frame_pointer: Address, stack_arg_size: usize) -> Address {
554
    frame_pointer + 16 as ByteSize + stack_arg_size
555
556
}

557
/// sets the stack point
558
559
560
561
562
#[inline(always)]
pub fn set_previous_frame_pointer(frame_pointer: Address, value: Address) {
    unsafe { frame_pointer.store::<Address>(value) }
}

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

569
570
/// returns offset of callee saved register
/// Reg should be a 64-bit callee saved GPR or FPR
571
572
573
574
575
576
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 {
577
        (reg - R12.id()) / 4 + 1
578
    };
579
    (id as isize + 1) * (-8)
580
}
581

qinsoon's avatar
mod.rs    
qinsoon committed
582
583
/// is a machine register (by ID) callee saved?
/// returns false if the ID is not a machine register
584
pub fn is_callee_saved(reg_id: MuID) -> bool {
qinsoon's avatar
qinsoon committed
585
    for reg in CALLEE_SAVED_GPRS.iter() {
586
587
588
589
        if reg_id == reg.extract_ssa_id().unwrap() {
            return true;
        }
    }
590
591

    false
592
593
}

qinsoon's avatar
mod.rs    
qinsoon committed
594
/// is a constant a valid x86_64 immediate number (32 bits integer)?
595
pub fn is_valid_x86_imm(op: &P<Value>) -> bool {
596
597
598
599
    use std::i32;

    if op.ty.get_int_length().is_some() && op.ty.get_int_length().unwrap() <= 32 {
        match op.v {
600
601
            Value_::Constant(Constant::Int(val))
                if val as i32 >= i32::MIN && val as i32 <= i32::MAX => true,
602
            _ => false
603
604
605
        }
    } else {
        false
606
    }
qinsoon's avatar
qinsoon committed
607
608
609
}

use ast::inst::*;
qinsoon's avatar
mod.rs    
qinsoon committed
610
611

/// estimate the number of machine instruction for each IR instruction
qinsoon's avatar
qinsoon committed
612
613
614
615
616
pub fn estimate_insts_for_ir(inst: &Instruction) -> usize {
    use ast::inst::Instruction_::*;

    match inst.v {
        // simple
617
        BinOp(_, _, _) => 1,
qinsoon's avatar
qinsoon committed
618
        BinOpWithStatus(_, _, _, _) => 2,
619
620
        CmpOp(_, _, _) => 1,
        ConvOp { .. } => 0,
qinsoon's avatar
qinsoon committed
621
622

        // control flow
623
624
625
626
627
628
        Branch1(_) => 1,
        Branch2 { .. } => 1,
        Select { .. } => 2,
        Watchpoint { .. } => 1,
        WPBranch { .. } => 2,
        Switch { .. } => 3,
qinsoon's avatar
qinsoon committed
629
630

        // call
631
632
        ExprCall { .. } | ExprCCall { .. } | Call { .. } | CCall { .. } => 5,
        Return(_) => 1,
qinsoon's avatar
qinsoon committed
633
634
635
        TailCall(_) => 1,

        // memory access
636
637
638
639
640
641
        Load { .. } | Store { .. } => 1,
        CmpXchg { .. } => 1,
        AtomicRMW { .. } => 1,
        AllocA(_) => 1,
        AllocAHybrid(_, _) => 1,
        Fence(_) => 1,
qinsoon's avatar
qinsoon committed
642
643

        // memory addressing
644
645
646
647
648
        GetIRef(_) |
        GetFieldIRef { .. } |
        GetElementIRef { .. } |
        ShiftIRef { .. } |
        GetVarPartIRef { .. } => 0,
qinsoon's avatar
qinsoon committed
649

qinsoon's avatar
mod.rs    
qinsoon committed
650
        // runtime call
qinsoon's avatar
qinsoon committed
651
652
        New(_) | NewHybrid(_, _) => 10,
        NewStack(_) | NewThread(_, _) | NewThreadExn(_, _) | NewFrameCursor(_) => 10,
653
654
655
        ThreadExit => 10,
        Throw(_) => 10,
        SwapStack { .. } => 10,
qinsoon's avatar
qinsoon committed
656
        CommonInst_GetThreadLocal | CommonInst_SetThreadLocal(_) => 10,
qinsoon's avatar
qinsoon committed
657
        CommonInst_Pin(_) | CommonInst_Unpin(_) => 10,
qinsoon's avatar
qinsoon committed
658
659
660

        // others
        Move(_) => 0,
661
        PrintHex(_) => 10,
662
        SetRetval(_) => 10,
663
        ExnInstruction { ref inner, .. } => estimate_insts_for_ir(&inner),
664
        _ => unimplemented!()
qinsoon's avatar
qinsoon committed
665
    }
666
}