]>
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
), 
 
This page took 0.077748 seconds  and 5 git commands  to generate.