frame.rs 5.74 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
use ast::ir::*;
use ast::ptr::*;
use ast::types::*;
use runtime::ValueLocation;

use std::fmt;
use std::collections::HashMap;
use vm::VM;

// | previous frame ...
// |---------------
// | return address
// | old RBP        <- RBP
// | callee saved
// | spilled
// |---------------
// | alloca area
18

19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51

#[derive(RustcEncodable, RustcDecodable, Clone)]
pub struct Frame {
    func_ver_id: MuID,
    cur_offset: isize, // offset to frame base pointer
    pub argument_by_reg: HashMap<MuID, P<Value>>,
    pub argument_by_stack: HashMap<MuID, P<Value>>,
    
    pub allocated: HashMap<MuID, FrameSlot>,
    // (callsite, destination address)
    exception_callsites: Vec<(ValueLocation, ValueLocation)>
}

impl fmt::Display for Frame {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "\nFrame for FuncVer {} {{", self.func_ver_id).unwrap();
        writeln!(f, "  allocated slots:").unwrap();
        for slot in self.allocated.values() {
            writeln!(f, "    {}", slot).unwrap();
        }
        writeln!(f, "  exception callsites:").unwrap();
        for &(ref callsite, ref dest) in self.exception_callsites.iter() {
            writeln!(f, "    callsite: {} -> {}", callsite, dest).unwrap()
        }
        writeln!(f, "  cur offset: {}", self.cur_offset).unwrap();
        writeln!(f, "}}")
    }
}

impl Frame {
    pub fn new(func_ver_id: MuID) -> Frame {
        Frame {
            func_ver_id: func_ver_id,
52
            cur_offset: 0,
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 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
            argument_by_reg: HashMap::new(),
            argument_by_stack: HashMap::new(),

            allocated: HashMap::new(),
            exception_callsites: vec![]
        }
    }

    #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
    pub fn cur_size(&self) -> usize {
        // frame size is a multiple of 16 bytes
        let size = self.cur_offset.abs() as usize;

        // align size to a multiple of 16 bytes
        let size = (size + 16 - 1) & !(16 - 1);

        debug_assert!(size % 16 == 0);

        size
    }

    pub fn add_argument_by_reg(&mut self, temp: MuID, reg: P<Value>) {
        self.argument_by_reg.insert(temp, reg);
    }

    pub fn add_argument_by_stack(&mut self, temp: MuID, stack_slot: P<Value>) {
        self.argument_by_stack.insert(temp, stack_slot);
    }
    
    pub fn alloc_slot_for_callee_saved_reg(&mut self, reg: P<Value>, vm: &VM) -> P<Value> {
        let slot = self.alloc_slot(&reg, vm);

        slot.make_memory_op(reg.ty.clone(), vm)
    }

    pub fn remove_record_for_callee_saved_reg(&mut self, reg: MuID) {
        self.allocated.remove(&reg);
    }
    
    pub fn alloc_slot_for_spilling(&mut self, reg: P<Value>, vm: &VM) -> P<Value> {
        let slot = self.alloc_slot(&reg, vm);
        slot.make_memory_op(reg.ty.clone(), vm)
    }
    
    pub fn get_exception_callsites(&self) -> &Vec<(ValueLocation, ValueLocation)> {
        &self.exception_callsites
    }
    
    pub fn add_exception_callsite(&mut self, callsite: ValueLocation, dest: ValueLocation) {
        trace!("add exception callsite: {} to dest {}", callsite, dest);
        self.exception_callsites.push((callsite, dest));
    }
105

106
    #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
107
    pub fn alloc_slot(&mut self, val: &P<Value>, vm: &VM) -> &FrameSlot {
108
        // RBP/FP is 16 bytes aligned, we are offsetting from RBP/FP
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
        // every value should be properly aligned

        let backendty = vm.get_backend_type_info(val.ty.id());

        if backendty.alignment > 16 {
            unimplemented!()
        }

        self.cur_offset -= backendty.size as isize;

        {
            // if alignment doesnt satisfy, make adjustment
            let abs_offset = self.cur_offset.abs() as usize;
            if abs_offset % backendty.alignment != 0 {
                use utils::math;
                let abs_offset = math::align_up(abs_offset, backendty.alignment);

                self.cur_offset = -(abs_offset as isize);
            }
        }

130 131 132
        let id = val.id();
        let ret = FrameSlot {
            offset: self.cur_offset,
133
            value: val.clone(),
134
        };
135

136 137 138 139 140 141 142 143
        self.allocated.insert(id, ret);
        self.allocated.get(&id).unwrap()
    }
}

#[derive(RustcEncodable, RustcDecodable, Clone)]
pub struct FrameSlot {
    pub offset: isize,
144
    pub value: P<Value>,
145 146 147
}

impl fmt::Display for FrameSlot {
148
    #[cfg(target_arch = "x86_64")]
149 150 151
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}(RBP): {}", self.offset, self.value)
    }
152 153 154 155 156

    #[cfg(target_arch = "aarch64")]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "[FP, #{}]: {}", self.offset, self.value)
    }
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
}

impl FrameSlot {
    #[cfg(target_arch = "x86_64")]
    pub fn make_memory_op(&self, ty: P<MuType>, vm: &VM) -> P<Value> {
        use compiler::backend::x86_64;

        P(Value{
            hdr: MuEntityHeader::unnamed(vm.next_id()),
            ty: ty.clone(),
            v: Value_::Memory(
                MemoryLocation::Address{
                    base: x86_64::RBP.clone(),
                    offset: Some(Value::make_int_const(vm.next_id(), self.offset as u64)),
                    index: None,
                    scale: None
                }
            )
        })
    }
    #[cfg(target_arch = "aarch64")]
    pub fn make_memory_op(&self, ty: P<MuType>, vm: &VM) -> P<Value> {
        use compiler::backend::aarch64;

        P(Value{
            hdr: MuEntityHeader::unnamed(vm.next_id()),
            ty: ty.clone(),
            v: Value_::Memory(
185
                MemoryLocation::VirtualAddress{
186 187
                    base: aarch64::FP.clone(),
                    offset: Some(Value::make_int_const(vm.next_id(), self.offset as u64)),
188
                    scale: 1,
189
                    signed: true
190 191 192 193 194
                }
            )
        })
    }
}