To protect your data, the CISO officer has suggested users to enable GitLab 2FA as soon as possible.

frame.rs 8.13 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.

15
16
17
use ast::ir::*;
use ast::ptr::*;
use ast::types::*;
18
use compiler::backend::get_callee_saved_offset;
19
use utils::ByteOffset;
20

21
use std;
22
23
24
25
use std::fmt;
use std::collections::HashMap;
use vm::VM;

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/// Frame serves two purposes:
/// * it manages stack allocation that are known statically (such as callee saved,
///   spilled registers)
/// * it also stores exception table for a given function, used for exception handling at runtime

/// Mu frame layout is compatible with C ABI

/// on x64
/// | previous frame ...
/// |---------------
/// | return address
/// | old RBP        <- RBP
/// | callee saved
/// | spilled
/// |---------------
/// | alloca area (not implemented)
42
#[derive(Clone)]
43
pub struct Frame {
44
    /// function version for this frame
45
    func_ver_id: MuID,
46
47
48
    /// current offset to frame base pointer
    cur_offset: isize,
    /// arguments passed to this function by registers (used for validating register allocation)
49
    pub argument_by_reg: HashMap<MuID, P<Value>>,
50
    /// arguments passed to this function by stack (used for validating register allocation)
51
    pub argument_by_stack: HashMap<MuID, P<Value>>,
52
    /// allocated frame location for Mu Values
53
    pub allocated: HashMap<MuID, FrameSlot>,
54
55
    /// mapping from callee saved id (i.e. the position in the list of callee saved registers)
    /// and offset from the frame pointer
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
56
    pub callee_saved: HashMap<isize, ByteOffset>,
57
58
}

59
60
61
62
63
64
rodal_struct!(Frame {
    func_ver_id,
    cur_offset,
    argument_by_reg,
    argument_by_stack,
    allocated,
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
65
    callee_saved,
66
});
67

68
69
70
71
72
73
74
75
76
77
78
79
80
81
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();
        writeln!(f, "  cur offset: {}", self.cur_offset).unwrap();
        writeln!(f, "}}")
    }
}

impl Frame {
82
    /// creates a new Frame
83
84
85
    pub fn new(func_ver_id: MuID) -> Frame {
        Frame {
            func_ver_id: func_ver_id,
86
            cur_offset: 0,
87
88
            argument_by_reg: HashMap::new(),
            argument_by_stack: HashMap::new(),
89
            callee_saved: HashMap::new(),
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
90
            allocated: HashMap::new(),
91
92
93
        }
    }

94
95
    /// returns current size,
    /// which is always a multiple of 16 bytes for x64/aarch64 (alignment requirement)
96
97
98
99
100
101
102
103
104
105
106
107
108
    #[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
    }

109
    /// adds a record of a Mu value argument passed in a certain register
110
111
112
113
    pub fn add_argument_by_reg(&mut self, temp: MuID, reg: P<Value>) {
        self.argument_by_reg.insert(temp, reg);
    }

114
    /// adds a record of a Mu value argumetn passed on stack
115
116
117
    pub fn add_argument_by_stack(&mut self, temp: MuID, stack_slot: P<Value>) {
        self.argument_by_stack.insert(temp, stack_slot);
    }
118
119
120

    /// allocates next stack slot for a callee saved register, and returns
    /// a memory operand representing the stack slot
121
    pub fn alloc_slot_for_callee_saved_reg(&mut self, reg: P<Value>, vm: &VM) -> P<Value> {
122
123
124
125
126
127
128
        let (mem, off) = {
            let slot = self.alloc_slot(&reg, vm);
            (slot.make_memory_op(reg.ty.clone(), vm), slot.offset)
        };
        let o = get_callee_saved_offset(reg.id());
        self.callee_saved.insert(o, off);
        mem
129
130
    }

131
132
133
    /// removes the record for a callee saved register
    /// We allocate stack slots for all the callee saved regsiter, and later
    /// remove slots for those registers that are not actually used
134
135
    pub fn remove_record_for_callee_saved_reg(&mut self, reg: MuID) {
        self.allocated.remove(&reg);
136
137
        let id = get_callee_saved_offset(reg);
        self.callee_saved.remove(&id);
138
    }
139
140
141

    /// allocates next stack slot for a spilled register, and returns
    /// a memory operand representing the stack slot
142
143
144
145
    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)
    }
146

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
147
    #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
148
149
    fn alloc_slot(&mut self, val: &P<Value>, vm: &VM) -> &FrameSlot {
        // base pointer is 16 bytes aligned, we are offsetting from base pointer
150
151
152
        // every value should be properly aligned

        let backendty = vm.get_backend_type_info(val.ty.id());
153
154
        // asserting that the alignment is no larger than 16 bytes, otherwise
        // we need to adjust offset in a different way
155
        if backendty.alignment > 16 {
156
            if cfg!(target_arch = "aarch64") || cfg!(target_arch = "x86_64") {
157
158
159
160
                panic!("A type cannot have alignment greater than 16 on aarch64")
            } else {
                unimplemented!()
            }
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
        }

        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);
            }
        }

176
177
178
        let id = val.id();
        let ret = FrameSlot {
            offset: self.cur_offset,
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
179
            value: val.clone(),
180
        };
181

182
183
184
185
186
        self.allocated.insert(id, ret);
        self.allocated.get(&id).unwrap()
    }
}

187
/// FrameSlot presents a Value stored in a certain frame location
188
#[derive(Clone)]
189
pub struct FrameSlot {
190
    /// location offset from current base pointer
191
    pub offset: isize,
192
    /// Mu value that resides in this location
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
193
    pub value: P<Value>,
194
195
}

196
rodal_struct!(FrameSlot { offset, value });
197

198
impl fmt::Display for FrameSlot {
199
    #[cfg(target_arch = "x86_64")]
200
201
202
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}(RBP): {}", self.offset, self.value)
    }
203
204
205
206
207

    #[cfg(target_arch = "aarch64")]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "[FP, #{}]: {}", self.offset, self.value)
    }
208
209
210
}

impl FrameSlot {
211
    /// generates a memory operand for this frame slot
212
213
214
215
    #[cfg(target_arch = "x86_64")]
    pub fn make_memory_op(&self, ty: P<MuType>, vm: &VM) -> P<Value> {
        use compiler::backend::x86_64;

216
        P(Value {
217
218
            hdr: MuEntityHeader::unnamed(vm.next_id()),
            ty: ty.clone(),
219
220
221
222
            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,
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
223
224
                scale: None,
            }),
225
226
        })
    }
227
    /// generates a memory operand for this frame slot
228
229
230
231
    #[cfg(target_arch = "aarch64")]
    pub fn make_memory_op(&self, ty: P<MuType>, vm: &VM) -> P<Value> {
        use compiler::backend::aarch64;

232
        P(Value {
233
234
            hdr: MuEntityHeader::unnamed(vm.next_id()),
            ty: ty.clone(),
235
236
237
238
            v: Value_::Memory(MemoryLocation::VirtualAddress {
                base: aarch64::FP.clone(),
                offset: Some(Value::make_int_const(vm.next_id(), self.offset as u64)),
                scale: 1,
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
239
240
                signed: true,
            }),
241
242
243
        })
    }
}