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

mod.rs 23.5 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;
21
22
23
/// CodeGenerator trait serves as an interface to the backend code
/// generator, which may generate assembly code or binary (not implemented
/// yet)
qinsoon's avatar
qinsoon committed
24
use compiler::backend::x86_64::codegen::CodeGenerator;
25

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

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

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

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

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

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

58
59
/// a macro to declare a set of general purpose registers that are aliased to
/// the first one
qinsoon's avatar
qinsoon committed
60
macro_rules! GPR_ALIAS {
qinsoon's avatar
qinsoon committed
61
62
    ($alias: ident: ($id64: expr, $r64: ident) ->
     $r32: ident, $r16: ident, $r8l: ident, $r8h: ident) => {
63
        lazy_static! {
64
65
66
67
68
69
70
71
72
73
            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);
74
75
76
77
78
79
80
            pub static ref $alias: [P<Value>; 5] = [
                $r64.clone(),
                $r32.clone(),
                $r16.clone(),
                $r8l.clone(),
                $r8h.clone()
            ];
qinsoon's avatar
qinsoon committed
81
82
83
        }
    };

qinsoon's avatar
qinsoon committed
84
    ($alias: ident: ($id64: expr, $r64: ident) -> $r32: ident, $r16: ident, $r8: ident) => {
85
        lazy_static! {
86
87
88
89
90
91
92
93
            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);
94
95
            pub static ref $alias: [P<Value>; 4] =
                [$r64.clone(), $r32.clone(), $r16.clone(), $r8.clone()];
qinsoon's avatar
qinsoon committed
96
97
98
99
        }
    };

    ($alias: ident: ($id64: expr, $r64: ident)) => {
100
        lazy_static! {
101
102
            pub static ref $r64: P<Value> =
                GPR!($id64, stringify!($r64), UINT64_TYPE);
103
104
            pub static ref $alias: [P<Value>; 4] =
                [$r64.clone(), $r64.clone(), $r64.clone(), $r64.clone()];
qinsoon's avatar
qinsoon committed
105
106
107
108
        }
    };
}

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

qinsoon's avatar
qinsoon committed
120
/// a macro to declare a floating point register
qinsoon's avatar
qinsoon committed
121
macro_rules! FPR {
122
123
124
125
    ($id:expr, $name: expr) => {{
        P(Value {
            hdr: MuEntityHeader::named($id, Arc::new($name.to_string())),
            ty: DOUBLE_TYPE.clone(),
126
            v: Value_::SSAVar($id)
127
128
        })
    }};
qinsoon's avatar
qinsoon committed
129
130
}

qinsoon's avatar
qinsoon committed
131
132
133
// declare all general purpose registers for x86_64
// non 64-bit registers are alias of its 64-bit one

134
135
GPR_ALIAS!(RAX_ALIAS: (0, RAX)  -> EAX, AX , AL, AH);
GPR_ALIAS!(RCX_ALIAS: (5, RCX)  -> ECX, CX , CL, CH);
136
GPR_ALIAS!(RDX_ALIAS: (10,RDX)  -> EDX, DX , DL, DH);
137
138
139
140
141
142
143
144
145
146
147
148
149
150
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
151

qinsoon's avatar
qinsoon committed
152
lazy_static! {
qinsoon's avatar
qinsoon committed
153
154
    /// a map from 64-bit register IDs to a vector of its aliased register (Values),
    /// including the 64-bit register
155
156
    pub static ref GPR_ALIAS_TABLE : LinkedHashMap<MuID, Vec<P<Value>>> = {
        let mut ret = LinkedHashMap::new();
qinsoon's avatar
qinsoon committed
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178

        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
179
    /// a map from any register to its 64-bit alias
qinsoon's avatar
qinsoon committed
180
181
182
183
184
185
186
187
188
189
190
191
    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
192
    };
qinsoon's avatar
qinsoon committed
193
194
}

qinsoon's avatar
qinsoon committed
195
196
/// 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
197
198
199
200
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,
201
            None => panic!("didnt find {} as GPR", id)
qinsoon's avatar
qinsoon committed
202
203
204
205
206
207
208
209
        };

        match length {
            64 => vec[0].clone(),
            32 => vec[1].clone(),
            16 => vec[2].clone(),
            8 => vec[3].clone(),
            1 => vec[3].clone(),
210
            _ => panic!("unexpected length {} for {}", length, vec[0])
qinsoon's avatar
qinsoon committed
211
212
        }
    } else {
qinsoon's avatar
qinsoon committed
213
        for r in ALL_FPRS.iter() {
qinsoon's avatar
qinsoon committed
214
215
216
217
218
219
220
221
            if r.id() == id {
                return r.clone();
            }
        }

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

223
224
/// are two registers aliased? (both must be machine register IDs, otherwise
/// this function panics)
225
pub fn is_aliased(id1: MuID, id2: MuID) -> bool {
qinsoon's avatar
qinsoon committed
226
    if get_color_for_precolored(id1) == get_color_for_precolored(id2) {
227
        // we need to specially check the case for AH/BH/CH/DH
228
229
        // because both AH and AL are aliased to RAX, but AH and AL are not
        // aliased
230
231
232
        macro_rules! is_match {
            ($a1: expr, $a2: expr; $b: expr) => {
                $a1 == $b.id() || $a2 == $b.id()
233
            };
234
235
236
237
238
239
240
241
242
243
244
245
246
        };

        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;
        }
247
    } else {
qinsoon's avatar
qinsoon committed
248
        false
249
250
251
    }
}

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

qinsoon's avatar
qinsoon committed
256
257
258
    if id < FPR_ID_START {
        match GPR_ALIAS_LOOKUP.get(&id) {
            Some(val) => val.id(),
259
            None => panic!("cannot find GPR {}", id)
qinsoon's avatar
qinsoon committed
260
261
262
263
        }
    } else {
        // we do not have alias for FPRs
        id
qinsoon's avatar
qinsoon committed
264
265
    }
}
qinsoon's avatar
qinsoon committed
266

qinsoon's avatar
mod.rs    
qinsoon committed
267
/// returns register length (in bits) for an integer operand
qinsoon's avatar
qinsoon committed
268
269
270
271
272
273
#[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
274
275
        Some(8) => 8,
        Some(1) => 8,
276
        _ => panic!("unsupported register length for x64: {}", op.ty)
qinsoon's avatar
qinsoon committed
277
278
279
    }
}

qinsoon's avatar
qinsoon committed
280
lazy_static! {
qinsoon's avatar
mod.rs    
qinsoon committed
281
282
    /// GPRs for returning values
    //  order matters
qinsoon's avatar
qinsoon committed
283
    pub static ref RETURN_GPRS : [P<Value>; 2] = [
qinsoon's avatar
qinsoon committed
284
285
286
        RAX.clone(),
        RDX.clone(),
    ];
287

qinsoon's avatar
mod.rs    
qinsoon committed
288
289
    /// GPRs for passing arguments
    //  order matters
qinsoon's avatar
qinsoon committed
290
    pub static ref ARGUMENT_GPRS : [P<Value>; 6] = [
qinsoon's avatar
qinsoon committed
291
292
293
294
295
296
297
        RDI.clone(),
        RSI.clone(),
        RDX.clone(),
        RCX.clone(),
        R8.clone(),
        R9.clone()
    ];
298

qinsoon's avatar
mod.rs    
qinsoon committed
299
    /// callee saved GPRs
qinsoon's avatar
qinsoon committed
300
    pub static ref CALLEE_SAVED_GPRS : [P<Value>; 6] = [
qinsoon's avatar
qinsoon committed
301
302
303
304
305
306
307
        RBX.clone(),
        RBP.clone(),
        R12.clone(),
        R13.clone(),
        R14.clone(),
        R15.clone()
    ];
qinsoon's avatar
qinsoon committed
308

qinsoon's avatar
mod.rs    
qinsoon committed
309
    /// caller saved GPRs
qinsoon's avatar
qinsoon committed
310
    pub static ref CALLER_SAVED_GPRS : [P<Value>; 9] = [
qinsoon's avatar
qinsoon committed
311
312
313
314
315
316
317
318
319
320
        RAX.clone(),
        RCX.clone(),
        RDX.clone(),
        RSI.clone(),
        RDI.clone(),
        R8.clone(),
        R9.clone(),
        R10.clone(),
        R11.clone()
    ];
321

qinsoon's avatar
mod.rs    
qinsoon committed
322
323
    /// all the genral purpose registers
    //  FIXME: why RBP is commented out?
qinsoon's avatar
qinsoon committed
324
    static ref ALL_GPRS : [P<Value>; 15] = [
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
        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
342
343
}

qinsoon's avatar
qinsoon committed
344
pub const FPR_ID_START: usize = 100;
qinsoon's avatar
qinsoon committed
345

346
lazy_static! {
qinsoon's avatar
mod.rs    
qinsoon committed
347
    // floating point registers, we use SSE registers
qinsoon's avatar
qinsoon committed
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
    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");
364

qinsoon's avatar
mod.rs    
qinsoon committed
365
366
    /// FPRs to return values
    //  order matters
qinsoon's avatar
qinsoon committed
367
    pub static ref RETURN_FPRS : [P<Value>; 2] = [
qinsoon's avatar
qinsoon committed
368
369
370
        XMM0.clone(),
        XMM1.clone()
    ];
371

qinsoon's avatar
mod.rs    
qinsoon committed
372
373
    /// FPRs to pass arguments
    //  order matters
qinsoon's avatar
qinsoon committed
374
    pub static ref ARGUMENT_FPRS : [P<Value>; 8] = [
qinsoon's avatar
qinsoon committed
375
376
        XMM0.clone(),
        XMM1.clone(),
qinsoon's avatar
qinsoon committed
377
378
379
380
381
382
383
        XMM2.clone(),
        XMM3.clone(),
        XMM4.clone(),
        XMM5.clone(),
        XMM6.clone(),
        XMM7.clone()
    ];
384

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

qinsoon's avatar
mod.rs    
qinsoon committed
388
    /// caller saved FPRs
qinsoon's avatar
qinsoon committed
389
    pub static ref CALLER_SAVED_FPRS : [P<Value>; 16] = [
qinsoon's avatar
qinsoon committed
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
        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(),
    ];
407

qinsoon's avatar
mod.rs    
qinsoon committed
408
    /// all the floating point registers
qinsoon's avatar
qinsoon committed
409
    static ref ALL_FPRS : [P<Value>; 16] = [
qinsoon's avatar
qinsoon committed
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
        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
427
428
}

qinsoon's avatar
qinsoon committed
429
lazy_static! {
qinsoon's avatar
mod.rs    
qinsoon committed
430
    /// a map for all the machine registers, from ID to P<Value>
qinsoon's avatar
qinsoon committed
431
    pub static ref ALL_MACHINE_REGS : LinkedHashMap<MuID, P<Value>> = {
432
        let mut map = LinkedHashMap::new();
qinsoon's avatar
qinsoon committed
433
434
435
436
437
438
439

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

440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
        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
    };
459

460
    /// all the usable general purpose registers for reg allocator to assign
qinsoon's avatar
mod.rs    
qinsoon committed
461
462
463
    //  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)
464
    pub static ref ALL_USABLE_GPRS : Vec<P<Value>> = vec![
qinsoon's avatar
mod.rs    
qinsoon committed
465
        // caller saved registers
466
467
468
469
470
471
472
473
474
        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
475
        // callee saved registers
476
477
478
479
480
        RBX.clone(),
        R12.clone(),
        R13.clone(),
        R14.clone(),
        R15.clone(),
481
482
483
484
485
486
487
    ];

    /// 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
488
        // floating point registers
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
        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()
    ];
506
507
508
509
510
511
512
513
514
515
516

    /// 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
    };
517
518
519
520
521
522
523
524
525
526
527
528

    /// 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
529
530
}

qinsoon's avatar
mod.rs    
qinsoon committed
531
/// creates context for each machine register in FunctionContext
qinsoon's avatar
qinsoon committed
532
pub fn init_machine_regs_for_func(func_context: &mut FunctionContext) {
qinsoon's avatar
qinsoon committed
533
    for reg in ALL_MACHINE_REGS.values() {
qinsoon's avatar
qinsoon committed
534
        let reg_id = reg.extract_ssa_id().unwrap();
qinsoon's avatar
qinsoon committed
535
        let entry = SSAVarEntry::new(reg.clone());
536

qinsoon's avatar
qinsoon committed
537
538
539
540
        func_context.values.insert(reg_id, entry);
    }
}

qinsoon's avatar
mod.rs    
qinsoon committed
541
/// gets the number of registers in a certain register group
542
pub fn number_of_usable_regs_in_group(group: RegGroup) -> usize {
qinsoon's avatar
qinsoon committed
543
    match group {
qinsoon's avatar
qinsoon committed
544
        RegGroup::GPR => ALL_USABLE_GPRS.len(),
545
        RegGroup::GPREX => ALL_USABLE_GPRS.len(),
546
        RegGroup::FPR => ALL_USABLE_FPRS.len()
qinsoon's avatar
qinsoon committed
547
548
549
    }
}

qinsoon's avatar
mod.rs    
qinsoon committed
550
/// returns the number of all registers on this platform
qinsoon's avatar
qinsoon committed
551
pub fn number_of_all_regs() -> usize {
qinsoon's avatar
qinsoon committed
552
    ALL_MACHINE_REGS.len()
qinsoon's avatar
qinsoon committed
553
554
}

qinsoon's avatar
mod.rs    
qinsoon committed
555
/// returns a reference to a map for all the registers
556
pub fn all_regs() -> &'static LinkedHashMap<MuID, P<Value>> {
qinsoon's avatar
qinsoon committed
557
    &ALL_MACHINE_REGS
qinsoon's avatar
qinsoon committed
558
559
}

qinsoon's avatar
mod.rs    
qinsoon committed
560
/// returns a reference to a vector of all usable registers
561
pub fn all_usable_regs() -> &'static Vec<P<Value>> {
qinsoon's avatar
qinsoon committed
562
    &ALL_USABLE_MACHINE_REGS
563
564
}

qinsoon's avatar
mod.rs    
qinsoon committed
565
566
/// returns RegGroup for a given machine register (by ID)
/// panics if the ID is not a machine register
567
pub fn pick_group_for_reg(reg_id: MuID) -> RegGroup {
568
    let reg = all_regs().get(&reg_id).unwrap();
569
    RegGroup::get_from_value(reg)
570
571
}

572
/// gets the previouse frame pointer with respect to the current
573
574
575
576
577
#[inline(always)]
pub fn get_previous_frame_pointer(frame_pointer: Address) -> Address {
    unsafe { frame_pointer.load::<Address>() }
}

578
/// gets the return address for the current frame pointer
579
580
#[inline(always)]
pub fn get_return_address(frame_pointer: Address) -> Address {
581
    unsafe { (frame_pointer + 8 as ByteSize).load::<Address>() }
582
583
}

584
/// gets the stack pointer before the current frame was created
585
#[inline(always)]
586
587
588
589
pub fn get_previous_stack_pointer(
    frame_pointer: Address,
    stack_arg_size: usize
) -> Address {
590
    frame_pointer + 16 as ByteSize + stack_arg_size
591
592
}

593
/// sets the stack point
594
595
596
597
598
#[inline(always)]
pub fn set_previous_frame_pointer(frame_pointer: Address, value: Address) {
    unsafe { frame_pointer.store::<Address>(value) }
}

599
/// gets the return address for the current frame pointer
600
601
#[inline(always)]
pub fn set_return_address(frame_pointer: Address, value: Address) {
602
    unsafe { (frame_pointer + 8 as ByteSize).store::<Address>(value) }
603
604
}

605
606
/// returns offset of callee saved register
/// Reg should be a 64-bit callee saved GPR or FPR
607
608
609
610
611
612
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
613
        (reg - R12.id()) / 4 + 1
614
    };
qinsoon's avatar
qinsoon committed
615
    (id as isize + 1) * (-8)
616
}
617

qinsoon's avatar
mod.rs    
qinsoon committed
618
619
/// is a machine register (by ID) callee saved?
/// returns false if the ID is not a machine register
620
pub fn is_callee_saved(reg_id: MuID) -> bool {
qinsoon's avatar
qinsoon committed
621
    for reg in CALLEE_SAVED_GPRS.iter() {
622
623
624
625
        if reg_id == reg.extract_ssa_id().unwrap() {
            return true;
        }
    }
626
627

    false
628
629
}

qinsoon's avatar
mod.rs    
qinsoon committed
630
/// is a constant a valid x86_64 immediate number (32 bits integer)?
631
pub fn is_valid_x86_imm(op: &P<Value>) -> bool {
632
633
    use std::i32;

634
635
636
    if let Some(int_width) = op.ty.get_int_length() {
        match int_width {
            1...32 => op.is_int_const(),
637
638
            64 => match op.v {
                Value_::Constant(Constant::Int(val)) => {
639
640
                    val as i64 >= i32::MIN as i64
                        && val as i64 <= i32::MAX as i64
641
                }
642
                _ => false
643
            },
644
            128 => false,
645
            _ => unimplemented!()
646
647
648
        }
    } else {
        false
649
    }
qinsoon's avatar
qinsoon committed
650
651
652
}

use ast::inst::*;
qinsoon's avatar
mod.rs    
qinsoon committed
653
654

/// estimate the number of machine instruction for each IR instruction
qinsoon's avatar
qinsoon committed
655
656
657
658
659
pub fn estimate_insts_for_ir(inst: &Instruction) -> usize {
    use ast::inst::Instruction_::*;

    match inst.v {
        // simple
qinsoon's avatar
qinsoon committed
660
        BinOp(_, _, _) => 1,
qinsoon's avatar
qinsoon committed
661
        BinOpWithStatus(_, _, _, _) => 2,
qinsoon's avatar
qinsoon committed
662
663
        CmpOp(_, _, _) => 1,
        ConvOp { .. } => 0,
qinsoon's avatar
qinsoon committed
664

665
666
667
668
669
670
671
672
673
674
        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
675

qinsoon's avatar
qinsoon committed
676
        // control flow
qinsoon's avatar
qinsoon committed
677
678
679
680
681
682
        Branch1(_) => 1,
        Branch2 { .. } => 1,
        Select { .. } => 2,
        Watchpoint { .. } => 1,
        WPBranch { .. } => 2,
        Switch { .. } => 3,
qinsoon's avatar
qinsoon committed
683
684

        // call
qinsoon's avatar
qinsoon committed
685
686
        ExprCall { .. } | ExprCCall { .. } | Call { .. } | CCall { .. } => 5,
        Return(_) => 1,
qinsoon's avatar
qinsoon committed
687
688
689
        TailCall(_) => 1,

        // memory access
qinsoon's avatar
qinsoon committed
690
691
692
693
694
        Load { .. } | Store { .. } => 1,
        CmpXchg { .. } => 1,
        AtomicRMW { .. } => 1,
        AllocA(_) => 1,
        AllocAHybrid(_, _) => 1,
695
        AllocAU(_) => 1,
696
        AllocAUHybrid(_, _) => 1,
qinsoon's avatar
qinsoon committed
697
        Fence(_) => 1,
qinsoon's avatar
qinsoon committed
698
699

        // memory addressing
700
701
702
703
704
        GetIRef(_)
        | GetFieldIRef { .. }
        | GetElementIRef { .. }
        | ShiftIRef { .. }
        | GetVarPartIRef { .. } => 0,
qinsoon's avatar
qinsoon committed
705

qinsoon's avatar
mod.rs    
qinsoon committed
706
        // runtime call
707
708
709
710
711
712
713
714
        New(_)
        | NewHybrid(_, _)
        | NewReg(_)
        | DeleteReg(_)
        | rAlloc(_, _)
        | rAllocHybrid(_, _, _)
        | eAlloc(_)
        | eAllocHybrid(_, _)
715
        | eDelete(_) => 10,
716
717
718
        NewStack(_)
        | NewThread { .. }
        | NewRTThread { .. }
719
        | NewFutex(_)
720
721
        | DeleteFutex(_)
        | LockFutex(_, _)
722
        | UnlockFutex(_,_)
723
        | NotifyThread(_)
724
725
        | ThreadSetPriority(_, _)
        | ThreadGetPriority(_)
726
727
        | GetTime
        | SetTime(_)
Javad Ebrahimian Amiri's avatar
Javad Ebrahimian Amiri committed
728
        | NewTimer
729
        | SetTimer { .. }
Javad Ebrahimian Amiri's avatar
Javad Ebrahimian Amiri committed
730
731
732
        | CancelTimer(_)
        | DeleteTimer(_)
        | Sleep(_)
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
        | NewAttr
        | DeleteAttr(_)
        | ThreadSetAttr(_, _)
        | ThreadGetAttr(_)
        | AttrClearCPU(_, _)
        | AttrIssetCPU(_, _)
        | AttrSetCPU(_, _)
        | AttrZeroCPU(_)
        | AttrSetPriority(_, _)
        | AttrGetPriority(_)
        | eAllocPA(_, _)
        | eAllocHybridPA(_, _, _)
        | BindObject(_)
        | UnbindObject(_)
        | NewRegionPA(_, _)
        | BindRegion(_)
        | UnbindRegion(_)
        | ThreadClearCPU(_, _)
        | ThreadSetCPU(_, _)
        | ThreadIssetCPU(_, _)
753
        | NewFrameCursor(_) => 10,
qinsoon's avatar
qinsoon committed
754
        ThreadExit => 10,
755
756
        CurrentStack => 10,
        KillStack(_) => 10,
qinsoon's avatar
qinsoon committed
757
        Throw(_) => 10,
qinsoon's avatar
qinsoon committed
758
        SwapStackExpr { .. } | SwapStackExc { .. } | SwapStackKill { .. } => 10,
qinsoon's avatar
qinsoon committed
759
        CommonInst_GetThreadLocal | CommonInst_SetThreadLocal(_) => 10,
qinsoon's avatar
qinsoon committed
760
        CommonInst_Pin(_) | CommonInst_Unpin(_) | CommonInst_GetAddr(_) => 10,
qinsoon's avatar
qinsoon committed
761
762
763

        // others
        Move(_) => 0,
764
        PrintHex(_) | PrintBool(_) | PrintTime(_) => 10,
765
        SetRetval(_) => 10,
766
767
        RandI(_, _) => 10,
        RandF(_, _) => 10,
qinsoon's avatar
qinsoon committed
768
        GetVMThreadLocal => 10,
769
        ExnInstruction { ref inner, .. } => estimate_insts_for_ir(&inner)
qinsoon's avatar
qinsoon committed
770
    }
771
}
772
773

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