]>
Witch of Git - ivy/blob - src/trans/x64.rs
2 use crate::trans
::{Code
, FnName
, Func
, Program
, SsaName
, Var
};
10 #[cfg(target_os = "macos")]
11 macro_rules
! extern_label
{
13 Label
::Extern(concat
!("_", $l
))
16 #[cfg(not(target_os = "macos"))]
17 macro_rules
! extern_label
{
23 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
28 Builtin(&'
static str),
31 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
37 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
58 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
74 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
75 pub struct Definition
{
77 body
: Cow
<'
static, [Inst
]>,
86 builtins
: &HashMap
<String
, ast
::Name
>,
90 let (entry
, globals
, defns
) = compile(&prog
);
96 let builtins
= builtins
99 let number
= id
.global_number().unwrap
();
100 let (params
, name
, code
) = builtin(&name
);
104 name
: Label
::Builtin(name
),
105 body
: Cow
::Borrowed(code
),
110 .collect
::<Vec
<_
>>();
111 writeln
!(out
, ".data")?
;
112 for global
in globals
{
113 writeln
!(out
, "{}", global
)?
;
125 for builtin
in &builtins
{
133 mov [rip + {}], rax"#,
136 extern_label
!("ivy_make_lam"),
137 Label
::Global(builtin
.number
),
149 extern_label
!("ivy_exit"),
151 for builtin
in &builtins
{
152 writeln
!(out
, "{}", builtin
.defn
)?
;
156 writeln
!(out
, "{}", defn
)?
;
162 pub fn compile(prog
: &Program
) -> (Label
, Vec
<Global
>, Vec
<Definition
>) {
166 .map(|&global
| Global
{
167 name
: Label
::Global(global
),
174 .map(|func
| compile_func(func
))
176 (Label
::Function(prog
.top
), globals
, defns
)
179 fn even_up(x
: usize) -> usize {
183 fn compile_func(func
: &Func
) -> Definition
{
184 fn stack(x
: &SsaName
) -> Addr
{
185 Addr
::Off(Reg
::Rsp
, x
.0 as i32 * 8)
188 const HEADER_SIZE
: i32 = 0x18;
190 fn param(x
: u16) -> Addr
{
191 Addr
::Off(Reg
::Rbx
, HEADER_SIZE
+ x
as i32 * 8)
194 let upvar
= move |x
: u16| {
195 let params
= func
.params
as i32 * 8;
196 Addr
::Off(Reg
::Rbx
, HEADER_SIZE
+ params
+ x
as i32 * 8)
199 let mut body
= Vec
::new();
200 let stack_slots
= even_up(func
.order
.len());
201 body
.push(Inst
::Push(Reg
::Rbx
));
202 body
.push(Inst
::Mov(Reg
::Rbx
, Reg
::Rdi
));
203 body
.push(Inst
::Sub(Reg
::Rsp
, stack_slots
as u32 * 8));
204 for ssa
in &func
.order
{
205 match &func
.block
[ssa
] {
206 Code
::Load(Var
::Global(x
)) => {
207 body
.push(Inst
::Load(Reg
::Rax
, Addr
::Rip(Label
::Global(*x
))));
208 body
.push(Inst
::Store(stack(ssa
), Reg
::Rax
));
210 Code
::Load(Var
::Param(x
)) => {
211 body
.push(Inst
::Load(Reg
::Rax
, param(*x
)));
212 body
.push(Inst
::Store(stack(ssa
), Reg
::Rax
));
214 Code
::Load(Var
::Upvar(x
)) => {
215 body
.push(Inst
::Load(Reg
::Rax
, upvar(*x
)));
216 body
.push(Inst
::Store(stack(ssa
), Reg
::Rax
));
218 Code
::Load(Var
::Ssa(ssa2
)) => {
219 body
.push(Inst
::Load(Reg
::Rax
, stack(ssa2
)));
220 body
.push(Inst
::Store(stack(ssa
), Reg
::Rax
));
222 Code
::StoreGlobal(x
, s
) => {
223 body
.push(Inst
::Load(Reg
::Rax
, stack(s
)));
224 body
.push(Inst
::Store(Addr
::Rip(Label
::Global(*x
)), Reg
::Rax
));
231 body
.push(Inst
::Lea(Reg
::Rdi
, Addr
::Rip(Label
::Function(*name
))));
232 body
.push(Inst
::Imm(Reg
::Rsi
, *params
as i64));
233 body
.push(Inst
::Imm(Reg
::Rdx
, upvars
.len() as i64));
234 body
.push(Inst
::Call(extern_label
!("ivy_make_lam")));
235 // @TODO: Implement copying in closure captures
236 assert
!(upvars
.is
_empty
());
237 body
.push(Inst
::Store(stack(ssa
), Reg
::Rax
));
239 Code
::App(terms
) => {
240 let mut terms
= terms
.iter
();
241 body
.push(Inst
::Load(
243 stack(terms
.next().expect("a function to apply")),
246 Some(s
) => body
.push(Inst
::Load(Reg
::Rsi
, stack(s
))),
247 None
=> body
.push(Inst
::Imm(Reg
::Rsi
, 0)),
249 body
.push(Inst
::Call(extern_label
!("ivy_app")));
250 while let Some(term
) = terms
.next() {
251 body
.push(Inst
::Mov(Reg
::Rdi
, Reg
::Rax
));
252 body
.push(Inst
::Load(Reg
::Rsi
, stack(term
)));
253 body
.push(Inst
::Call(extern_label
!("ivy_app_mut")));
255 body
.push(Inst
::Store(stack(ssa
), Reg
::Rax
));
258 body
.push(Inst
::Imm(Reg
::Rax
, (n
<< 1) | 1i64));
259 body
.push(Inst
::Store(stack(ssa
), Reg
::Rax
));
263 body
.push(Inst
::Add(Reg
::Rsp
, stack_slots
as u32 * 8));
264 body
.push(Inst
::Pop(Reg
::Rbx
));
265 body
.push(Inst
::Ret
);
267 name
: Label
::Function(func
.name
),
268 body
: Cow
::Owned(body
),
272 impl fmt
::Display
for Definition
{
273 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
274 match self.body
.len() {
275 0 => write
!(fmt
, "{}:", self.name
),
276 1 => write
!(fmt
, "{}: {}", self.name
, self.body
[0]),
278 writeln
!(fmt
, "{}:", self.name
)?
;
279 for inst
in &self.body
[..len
- 1] {
280 writeln
!(fmt
, " {}", inst
)?
;
282 write
!(fmt
, " {}", self.body
.last().unwrap
())
288 impl fmt
::Display
for Global
{
289 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
290 write
!(fmt
, "{}: .quad {}", self.name
, self.value
)
294 impl fmt
::Display
for Label
{
295 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
297 Label
::Global(g
) => write
!(fmt
, "IVY_GLOBAL${}", g
),
298 Label
::Function(f
) => write
!(fmt
, "ivy_fn${}", f
.0),
299 Label
::Extern(l
) => write
!(fmt
, "{}", l
),
300 Label
::Builtin(l
) => write
!(fmt
, "ivy_builtin${}", l
),
305 impl fmt
::Display
for Reg
{
306 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
308 Reg
::Rax
=> write
!(fmt
, "rax"),
309 Reg
::Rbx
=> write
!(fmt
, "rbx"),
310 Reg
::Rcx
=> write
!(fmt
, "rcx"),
311 Reg
::Rdx
=> write
!(fmt
, "rdx"),
312 Reg
::Rsi
=> write
!(fmt
, "rsi"),
313 Reg
::Rdi
=> write
!(fmt
, "rdi"),
314 Reg
::Rbp
=> write
!(fmt
, "rbp"),
315 Reg
::Rsp
=> write
!(fmt
, "rsp"),
316 Reg
::R8
=> write
!(fmt
, "r8"),
317 Reg
::R9
=> write
!(fmt
, "r9"),
318 Reg
::R10
=> write
!(fmt
, "r10"),
319 Reg
::R11
=> write
!(fmt
, "r11"),
320 Reg
::R12
=> write
!(fmt
, "r12"),
321 Reg
::R13
=> write
!(fmt
, "r13"),
322 Reg
::R14
=> write
!(fmt
, "r14"),
323 Reg
::R15
=> write
!(fmt
, "r15"),
328 impl fmt
::Display
for Addr
{
329 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
331 Addr
::Rip(l
) => write
!(fmt
, "[rip + {}]", l
),
332 Addr
::Off(r
, o
) => write
!(fmt
, "[{} + {}]", r
, o
),
337 impl fmt
::Display
for Inst
{
338 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
340 Inst
::Push(r
) => write
!(fmt
, "push {}", r
),
341 Inst
::Pop(r
) => write
!(fmt
, "pop {}", r
),
342 Inst
::Mov(d
, s
) => write
!(fmt
, "mov {}, {}", d
, s
),
343 Inst
::Load(r
, a
) => write
!(fmt
, "mov {}, {}", r
, a
),
344 Inst
::Store(a
, r
) => write
!(fmt
, "mov {}, {}", a
, r
),
345 Inst
::Imm(r
, i
) => write
!(fmt
, "mov {}, {}", r
, i
),
346 Inst
::Lea(r
, a
) => write
!(fmt
, "lea {}, {}", r
, a
),
347 Inst
::Call(l
) => write
!(fmt
, "call {}", l
),
348 Inst
::Jmp(l
) => write
!(fmt
, "jmp {}", l
),
349 Inst
::Add(r
, x
) => write
!(fmt
, "add {}, {}", r
, x
),
350 Inst
::Sub(r
, x
) => write
!(fmt
, "sub {}, {}", r
, x
),
351 Inst
::Ret
=> write
!(fmt
, "ret"),
356 fn builtin(name
: &str) -> (u16, &'
static str, &'
static [Inst
]) {
362 Inst
::Load(Reg
::Rdi
, Addr
::Off(Reg
::Rdi
, 0x18)),
363 Inst
::Jmp(extern_label
!("ivy_debug")),
366 name
=> panic
!("Unsupported builtin '{}' for x64", name
),