mod.rs 14.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// Copyright 2017 The Australian National University
// 
// 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
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

15
pub mod inst_sel;
16
pub mod reg_alloc;
17
pub mod peephole_opt;
18
pub mod code_emission;
19

qinsoon's avatar
qinsoon committed
20
use utils::ByteSize;
21
use utils::math::align_up;
22
use runtime::mm;
qinsoon's avatar
qinsoon committed
23
use runtime::mm::common::gctype::{GCType, GCTYPE_INIT_ID, RefPattern};
qinsoon's avatar
qinsoon committed
24

25 26 27
pub type Word = usize;
pub const WORD_SIZE : ByteSize = 8;

28 29
pub const AOT_EMIT_CONTEXT_FILE : &'static str = "context.s";

qinsoon's avatar
qinsoon committed
30 31 32 33
// this is not full name, but pro/epilogue name is generated from this
pub const PROLOGUE_BLOCK_NAME: &'static str = "prologue";
pub const EPILOGUE_BLOCK_NAME: &'static str = "epilogue";

34 35 36
pub type Reg<'a> = &'a P<Value>;
pub type Mem<'a> = &'a P<Value>;

qinsoon's avatar
qinsoon committed
37
// X86_64
38

39
#[cfg(target_arch = "x86_64")]
40
#[path = "arch/x86_64/mod.rs"]
41
pub mod x86_64;
42

43 44
#[cfg(target_arch = "x86_64")]
pub use compiler::backend::x86_64::estimate_insts_for_ir;
qinsoon's avatar
qinsoon committed
45
#[cfg(target_arch = "x86_64")]
46
pub use compiler::backend::x86_64::init_machine_regs_for_func;
47 48
#[cfg(target_arch = "x86_64")]
pub use compiler::backend::x86_64::is_aliased;
49
#[cfg(target_arch = "x86_64")]
qinsoon's avatar
qinsoon committed
50
pub use compiler::backend::x86_64::get_color_for_precolored;
qinsoon's avatar
qinsoon committed
51
#[cfg(target_arch = "x86_64")]
52
pub use compiler::backend::x86_64::number_of_regs_in_group;
qinsoon's avatar
qinsoon committed
53
#[cfg(target_arch = "x86_64")]
54 55 56
pub use compiler::backend::x86_64::number_of_all_regs;
#[cfg(target_arch = "x86_64")]
pub use compiler::backend::x86_64::all_regs;
57
#[cfg(target_arch = "x86_64")]
58 59
pub use compiler::backend::x86_64::all_usable_regs;
#[cfg(target_arch = "x86_64")]
60
pub use compiler::backend::x86_64::pick_group_for_reg;
61 62
#[cfg(target_arch = "x86_64")]
pub use compiler::backend::x86_64::is_callee_saved;
63 64 65 66
#[cfg(target_arch = "x86_64")]
pub use compiler::backend::x86_64::emit_code;
#[cfg(target_arch = "x86_64")]
pub use compiler::backend::x86_64::emit_context;
67
#[cfg(target_arch = "x86_64")]
qinsoon's avatar
qinsoon committed
68 69
pub use compiler::backend::x86_64::emit_context_with_reloc;
#[cfg(target_arch = "x86_64")]
70
pub use compiler::backend::x86_64::spill_rewrite;
71

72
// aarch64
qinsoon's avatar
qinsoon committed
73

74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
#[cfg(target_arch = "aarch64")]
#[path = "arch/aarch64/mod.rs"]
pub mod aarch64;

#[cfg(target_arch = "aarch64")]
pub use compiler::backend::aarch64::estimate_insts_for_ir;
#[cfg(target_arch = "aarch64")]
pub use compiler::backend::aarch64::init_machine_regs_for_func;
#[cfg(target_arch = "aarch64")]
pub use compiler::backend::aarch64::is_aliased;
#[cfg(target_arch = "aarch64")]
pub use compiler::backend::aarch64::get_color_for_precolored;
#[cfg(target_arch = "aarch64")]
pub use compiler::backend::aarch64::number_of_regs_in_group;
#[cfg(target_arch = "aarch64")]
pub use compiler::backend::aarch64::number_of_all_regs;
#[cfg(target_arch = "aarch64")]
pub use compiler::backend::aarch64::all_regs;
#[cfg(target_arch = "aarch64")]
pub use compiler::backend::aarch64::all_usable_regs;
#[cfg(target_arch = "aarch64")]
pub use compiler::backend::aarch64::pick_group_for_reg;
#[cfg(target_arch = "aarch64")]
pub use compiler::backend::aarch64::is_callee_saved;
#[cfg(target_arch = "aarch64")]
pub use compiler::backend::aarch64::emit_code;
#[cfg(target_arch = "aarch64")]
pub use compiler::backend::aarch64::emit_context;
#[cfg(target_arch = "aarch64")]
pub use compiler::backend::aarch64::emit_context_with_reloc;
#[cfg(target_arch = "aarch64")]
pub use compiler::backend::aarch64::spill_rewrite;
qinsoon's avatar
qinsoon committed
106 107 108

// common data structure with target specific info

qinsoon's avatar
qinsoon committed
109
use vm::VM;
qinsoon's avatar
qinsoon committed
110 111
use ast::types::*;
use ast::ptr::*;
112
use ast::ir::*;
qinsoon's avatar
qinsoon committed
113
pub fn resolve_backend_type_info (ty: &MuType, vm: &VM) -> BackendTypeInfo {
qinsoon's avatar
qinsoon committed
114
    match ty.v {
115
        // integer
qinsoon's avatar
qinsoon committed
116
        MuType_::Int(size_in_bit) => {
qinsoon's avatar
qinsoon committed
117
            match size_in_bit {
118
                1  => BackendTypeInfo{
119
                    size: 1, alignment: 1, struct_layout: None, elem_padded_size: None,
qinsoon's avatar
qinsoon committed
120
                    gc_type: mm::add_gc_type(GCType::new_noreftype(1, 1))
121 122
                },
                8  => BackendTypeInfo{
123
                    size: 1, alignment: 1, struct_layout: None, elem_padded_size: None,
qinsoon's avatar
qinsoon committed
124
                    gc_type: mm::add_gc_type(GCType::new_noreftype(1, 1))
125 126
                },
                16 => BackendTypeInfo{
127
                    size: 2, alignment: 2, struct_layout: None, elem_padded_size: None,
qinsoon's avatar
qinsoon committed
128
                    gc_type: mm::add_gc_type(GCType::new_noreftype(2, 2))
129 130
                },
                32 => BackendTypeInfo{
131
                    size: 4, alignment: 4, struct_layout: None, elem_padded_size: None,
qinsoon's avatar
qinsoon committed
132
                    gc_type: mm::add_gc_type(GCType::new_noreftype(4, 4))
133 134
                },
                64 => BackendTypeInfo{
135
                    size: 8, alignment: 8, struct_layout: None, elem_padded_size: None,
qinsoon's avatar
qinsoon committed
136
                    gc_type: mm::add_gc_type(GCType::new_noreftype(8, 8))
137
                },
qinsoon's avatar
qinsoon committed
138 139 140 141
                128 => BackendTypeInfo {
                    size: 16, alignment: 16, struct_layout: None, elem_padded_size: None,
                    gc_type: mm::add_gc_type(GCType::new_noreftype(16, 16))
                },
qinsoon's avatar
qinsoon committed
142 143 144
                _ => unimplemented!()
            }
        },
145
        // reference of any type
qinsoon's avatar
qinsoon committed
146 147
        MuType_::Ref(_)
        | MuType_::IRef(_)
148
        | MuType_::WeakRef(_) => BackendTypeInfo{
149
            size: 8, alignment: 8, struct_layout: None, elem_padded_size: None,
150 151 152 153
            gc_type: mm::add_gc_type(GCType::new_reftype())
        },
        // pointer
        MuType_::UPtr(_)
qinsoon's avatar
qinsoon committed
154
        | MuType_::UFuncPtr(_)
155
        | MuType_::FuncRef(_)
qinsoon's avatar
qinsoon committed
156
        | MuType_::ThreadRef
157
        | MuType_::StackRef => BackendTypeInfo{
158
            size: 8, alignment: 8, struct_layout: None, elem_padded_size: None,
qinsoon's avatar
qinsoon committed
159
            gc_type: mm::add_gc_type(GCType::new_noreftype(8, 8))
160 161 162
        },
        // tagref
        MuType_::Tagref64 => unimplemented!(),
qinsoon's avatar
qinsoon committed
163
        // floating point
164
        MuType_::Float => BackendTypeInfo{
165
            size: 4, alignment: 4, struct_layout: None, elem_padded_size: None,
qinsoon's avatar
qinsoon committed
166
            gc_type: mm::add_gc_type(GCType::new_noreftype(4, 4))
167 168
        },
        MuType_::Double => BackendTypeInfo {
169
            size: 8, alignment: 8, struct_layout: None, elem_padded_size: None,
qinsoon's avatar
qinsoon committed
170
            gc_type: mm::add_gc_type(GCType::new_noreftype(8, 8))
171
        },
qinsoon's avatar
qinsoon committed
172
        // array
qinsoon's avatar
qinsoon committed
173
        MuType_::Array(ref ty, len) => {
174
            let ele_ty = vm.get_backend_type_info(ty.id());
175
            let ele_padded_size = align_up(ele_ty.size, ele_ty.alignment);
qinsoon's avatar
qinsoon committed
176
            
177
            BackendTypeInfo{
178
                size         : ele_padded_size * len,
179 180
                alignment    : ele_ty.alignment,
                struct_layout: None,
181
                elem_padded_size : Some(ele_padded_size),
qinsoon's avatar
qinsoon committed
182
                gc_type      : mm::add_gc_type(GCType::new_fix(GCTYPE_INIT_ID,
183
                                                           ele_padded_size * len,
184
                                                           ele_ty.alignment,
qinsoon's avatar
qinsoon committed
185 186
                                                           Some(RefPattern::Repeat{
                                                                pattern: Box::new(RefPattern::NestedType(vec![ele_ty.gc_type])),
187 188 189
                                                                count  : len
                                                            })
                ))
190
            }
qinsoon's avatar
qinsoon committed
191 192
        }
        // struct
193
        MuType_::Struct(ref name) => {
qinsoon's avatar
qinsoon committed
194 195 196 197 198 199 200 201 202 203 204
            let read_lock = STRUCT_TAG_MAP.read().unwrap();
            let struc = read_lock.get(name).unwrap();
            let tys = struc.get_tys();            
            
            trace!("layout struct: {}", struc);
            layout_struct(tys, vm)
        }
        // hybrid 
        // - align is the most strict aligned element (from all fix tys and var ty)
        // - size is fixed tys size
        // - layout is fixed tys layout
205 206 207 208 209 210 211
        MuType_::Hybrid(ref name) => {
            let read_lock = HYBRID_TAG_MAP.read().unwrap();
            let hybrid = read_lock.get(name).unwrap();

            let fix_tys = hybrid.get_fix_tys();
            let var_ty  = hybrid.get_var_ty();

qinsoon's avatar
qinsoon committed
212 213 214 215
            // treat fix_tys as struct
            let mut ret = layout_struct(fix_tys, vm);
            
            // treat var_ty as array (getting its alignment)
216 217
            let var_ele_ty = vm.get_backend_type_info(var_ty.id());
            let var_align = var_ele_ty.alignment;
218 219
            let var_padded_size = align_up(var_ele_ty.size, var_ele_ty.alignment);
            ret.elem_padded_size = Some(var_padded_size);
220 221 222

            // fix type info as hybrid
            // 1. check alignment
qinsoon's avatar
qinsoon committed
223 224 225
            if ret.alignment < var_align {
                ret.alignment = var_align;
            }
226 227
            // 2. fix gc type
            let mut gctype = ret.gc_type.as_ref().clone();
qinsoon's avatar
qinsoon committed
228
            gctype.var_refs = Some(RefPattern::NestedType(vec![var_ele_ty.gc_type.clone()]));
229
            gctype.var_size = Some(var_padded_size);
230
            ret.gc_type = mm::add_gc_type(gctype);
qinsoon's avatar
qinsoon committed
231 232 233 234
            
            ret
        }
        // void
235
        MuType_::Void => BackendTypeInfo{
236
            size: 0, alignment: 8, struct_layout: None, elem_padded_size: None,
qinsoon's avatar
qinsoon committed
237
            gc_type: mm::add_gc_type(GCType::new_noreftype(0, 8))
238
        },
qinsoon's avatar
qinsoon committed
239
        // vector
qinsoon's avatar
qinsoon committed
240
        MuType_::Vector(_, _) => unimplemented!()
qinsoon's avatar
qinsoon committed
241 242 243
    }
}

qinsoon's avatar
qinsoon committed
244
fn layout_struct(tys: &Vec<P<MuType>>, vm: &VM) -> BackendTypeInfo {
qinsoon's avatar
qinsoon committed
245 246
    let mut offsets : Vec<ByteSize> = vec![];
    let mut cur : ByteSize = 0;
qinsoon's avatar
qinsoon committed
247
    let mut struct_align : ByteSize = 1;
248 249 250 251 252

    // for gc type
    let mut use_ref_offsets = true;
    let mut ref_offsets = vec![];
    let mut gc_types    = vec![];
qinsoon's avatar
qinsoon committed
253 254
    
    for ty in tys.iter() {
255
        let ty_info = vm.get_backend_type_info(ty.id());
qinsoon's avatar
qinsoon committed
256 257 258 259 260 261 262 263 264 265 266 267 268 269
        trace!("examining field: {}, {:?}", ty, ty_info);
        
        let align = ty_info.alignment;
        if struct_align < align {
            struct_align = align;
        }
        
        if cur % align != 0 {
            // move cursor to next aligned offset
            cur = (cur / align + 1) * align;
        }
        
        offsets.push(cur);
        trace!("aligned to {}", cur);
270 271 272

        // for convenience, if the struct contains other struct/array
        // we do not use reference map
273
        if ty.is_aggregate() {
274 275 276 277 278
            use_ref_offsets = false;
        }

        // if this type is reference type, we store its offsets
        // we may not use this ref map though
279
        if ty.is_reference() {
280 281 282 283
            ref_offsets.push(cur);
        }
        // always store its gc type (we may not use it as well)
        gc_types.push(ty_info.gc_type.clone());
qinsoon's avatar
qinsoon committed
284 285 286 287 288
        
        cur += ty_info.size;
    }
    
    // if we need padding at the end
289 290 291 292 293
    let size = if cur % struct_align != 0 {
        (cur / struct_align + 1) * struct_align
    } else {
        cur
    };
qinsoon's avatar
qinsoon committed
294 295
    
    BackendTypeInfo {
296 297 298
        size         : size,
        alignment    : struct_align,
        struct_layout: Some(offsets),
299
        elem_padded_size: None,
qinsoon's avatar
qinsoon committed
300
        gc_type      : mm::add_gc_type(GCType::new_fix(GCTYPE_INIT_ID,
301 302 303 304 305 306 307 308 309
                                                   size,
                                                   struct_align,
                                                   Some(if use_ref_offsets {
                                                       RefPattern::Map {
                                                           offsets: ref_offsets,
                                                           size: size
                                                       }
                                                   } else {
                                                       RefPattern::NestedType(gc_types)
qinsoon's avatar
qinsoon committed
310
                                                   })))
qinsoon's avatar
qinsoon committed
311 312 313
    }
}

314 315 316 317
pub fn sequetial_layout(tys: &Vec<P<MuType>>, vm: &VM) -> (ByteSize, ByteSize, Vec<ByteSize>) {
    let ret = layout_struct(tys, vm);
    
    (ret.size, ret.alignment, ret.struct_layout.unwrap())
qinsoon's avatar
qinsoon committed
318
}
319

qinsoon's avatar
qinsoon committed
320
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
qinsoon's avatar
qinsoon committed
321
pub struct BackendTypeInfo {
qinsoon's avatar
qinsoon committed
322 323
    pub size: ByteSize,
    pub alignment: ByteSize,
324

325
    pub struct_layout: Option<Vec<ByteSize>>,
326 327 328
    // for hybrid/array, every element needs to be properly aligned
    // thus it may take more space than it actually needs
    pub elem_padded_size: Option<ByteSize>,
329 330

    pub gc_type: P<GCType>
qinsoon's avatar
qinsoon committed
331 332
}

qinsoon's avatar
qinsoon committed
333
impl BackendTypeInfo {
qinsoon's avatar
qinsoon committed
334 335 336 337
    pub fn is_hybrid(&self) -> bool {
        self.gc_type.is_hybrid()
    }

qinsoon's avatar
qinsoon committed
338 339 340 341 342 343 344 345 346 347
    pub fn get_field_offset(&self, index: usize) -> ByteSize {
        if self.struct_layout.is_some() {
            let layout = self.struct_layout.as_ref().unwrap();
            layout[index]
        } else {
            panic!("trying to get field offset on a non-struct type")
        }
    }
}

qinsoon's avatar
qinsoon committed
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
use std::fmt;
impl fmt::Display for BackendTypeInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} bytes ({} bytes aligned), ", self.size, self.alignment).unwrap();
        if self.struct_layout.is_some() {
            use utils::vec_utils;

            let layout = self.struct_layout.as_ref().unwrap();
            write!(f, "field offsets: ({})", vec_utils::as_str(layout)).unwrap();
        }

        Ok(())
    }
}

qinsoon's avatar
qinsoon committed
363
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
364
pub enum RegGroup {GPR, GPREX, FPR}
365 366

impl RegGroup {
367
    pub fn get_from_ty(ty: &P<MuType>) -> RegGroup {
368
        match ty.v {
qinsoon's avatar
qinsoon committed
369
            // for now, only use 64bits registers
370
            MuType_::Int(len) if len == 1  => RegGroup::GPR,
371 372 373 374
            MuType_::Int(len) if len == 8  => RegGroup::GPR,
            MuType_::Int(len) if len == 16 => RegGroup::GPR,
            MuType_::Int(len) if len == 32 => RegGroup::GPR,
            MuType_::Int(len) if len == 64 => RegGroup::GPR,
375
            MuType_::Int(len) if len == 128=> RegGroup::GPREX,
376 377 378 379 380 381 382 383 384

            MuType_::Ref(_)
            | MuType_::IRef(_)
            | MuType_::WeakRef(_)
            | MuType_::UPtr(_)
            | MuType_::ThreadRef
            | MuType_::StackRef
            | MuType_::Tagref64
            | MuType_::FuncRef(_)
385
            | MuType_::UFuncPtr(_)         => RegGroup::GPR,
386

387 388
            MuType_::Float                 => RegGroup::FPR,
            MuType_::Double                => RegGroup::FPR,
389 390 391 392

            _ => unimplemented!()
        }
    }
393 394 395 396

    pub fn get_from_value(val: &P<Value>) -> RegGroup {
        RegGroup::get_from_ty(&val.ty)
    }
397
}