codegen.rs 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
use ast::ptr::P;
use ast::ir::*;
qinsoon's avatar
qinsoon committed
17
use runtime::ValueLocation;
18

qinsoon's avatar
qinsoon committed
19
use compiler::machine_code::MachineCode;
qinsoon's avatar
qinsoon committed
20
use compiler::backend::{Reg, Mem};
21

qinsoon's avatar
qinsoon committed
22 23 24 25 26
/// CodeGenerator provides an interface to emit x86_64 code for instruction selection.
/// This allows us to implement the other parts of the compiler (mostly instruction selection)
/// without assuming code generator. Currently there is only an assembly backend
/// that implements this interface for ahead-of-time compilation. We plan to add
/// a binary backend for just-in-time compilation.
27
pub trait CodeGenerator {
qinsoon's avatar
qinsoon committed
28
    /// starts code for a function
29
    fn start_code(&mut self, func_name: MuName, entry: MuName) -> ValueLocation;
qinsoon's avatar
qinsoon committed
30
    /// finishes code for a function
31 32
    fn finish_code(&mut self, func_name: MuName)
        -> (Box<MachineCode + Sync + Send>, ValueLocation);
33

qinsoon's avatar
qinsoon committed
34
    /// starts a sequence of linear code (no branch)
35
    fn start_code_sequence(&mut self);
qinsoon's avatar
qinsoon committed
36
    /// finishes code for a sequence
37
    fn finish_code_sequence(&mut self) -> Box<MachineCode + Sync + Send>;
qinsoon's avatar
qinsoon committed
38 39

    /// outputs current code (via debug! log)
40
    fn print_cur_code(&self);
qinsoon's avatar
qinsoon committed
41 42

    /// starts a block
qinsoon's avatar
qinsoon committed
43
    fn start_block(&mut self, block_name: MuName);
qinsoon's avatar
qinsoon committed
44
    /// starts an exceptional block, and returns its code address
qinsoon's avatar
qinsoon committed
45
    fn start_exception_block(&mut self, block_name: MuName) -> ValueLocation;
qinsoon's avatar
qinsoon committed
46 47
    /// finishes a block (must have called start_block() or start_excpetion_block() first)
    fn end_block(&mut self, block_name: MuName);
qinsoon's avatar
qinsoon committed
48

qinsoon's avatar
qinsoon committed
49
    // adds CFI info
qinsoon's avatar
qinsoon committed
50 51 52 53 54 55
    fn add_cfi_startproc(&mut self);
    fn add_cfi_endproc(&mut self);
    fn add_cfi_def_cfa_register(&mut self, reg: Reg);
    fn add_cfi_def_cfa_offset(&mut self, offset: i32);
    fn add_cfi_offset(&mut self, reg: Reg, offset: i32);

qinsoon's avatar
qinsoon committed
56
    // emit code to adjust frame size
qinsoon's avatar
qinsoon committed
57
    fn emit_frame_grow(&mut self);
58

59
    fn emit_nop(&mut self, bytes: usize);
60 61

    // comparison
62
    fn emit_cmp_r_r(&mut self, op1: Reg, op2: Reg);
qinsoon's avatar
qinsoon committed
63
    fn emit_cmp_imm_r(&mut self, op1: i32, op2: Reg);
64 65
    fn emit_cmp_mem_r(&mut self, op1: Mem, op2: Reg);
    fn emit_cmp_r_mem(&mut self, op1: Reg, op2: Mem);
66

67
    fn emit_test_r_r(&mut self, op1: Reg, op2: Reg);
qinsoon's avatar
qinsoon committed
68
    fn emit_test_imm_r(&mut self, op1: i32, op2: Reg);
qinsoon's avatar
qinsoon committed
69

70
    // gpr move
qinsoon's avatar
qinsoon committed
71 72

    // mov imm64 to r64
73
    fn emit_mov_r64_imm64(&mut self, dest: Reg, src: i64);
qinsoon's avatar
qinsoon committed
74
    // bitcast between int and floatpoint of same length
75
    fn emit_mov_fpr_r64(&mut self, dest: Reg, src: Reg);
qinsoon's avatar
qinsoon committed
76 77 78
    fn emit_mov_fpr_r32(&mut self, dest: Reg, src: Reg);
    fn emit_mov_r64_fpr(&mut self, dest: Reg, src: Reg);
    fn emit_mov_r32_fpr(&mut self, dest: Reg, src: Reg);
qinsoon's avatar
qinsoon committed
79

80 81 82 83
    fn emit_mov_r_imm(&mut self, dest: Reg, src: i32);
    fn emit_mov_r_mem(&mut self, dest: Reg, src: Mem); // load
    fn emit_mov_r_r(&mut self, dest: Reg, src: Reg);
    fn emit_mov_mem_r(&mut self, dest: Mem, src: Reg); // store
84 85 86
    // we can infer imm length from Reg, but cannot from Mem
    // because mem may only have type as ADDRESS_TYPE
    fn emit_mov_mem_imm(&mut self, dest: Mem, src: i32, oplen: usize); // store
qinsoon's avatar
qinsoon committed
87

88 89
    fn emit_mov_mem_r_callee_saved(&mut self, dest: Mem, src: Reg); // store callee saved register
    fn emit_mov_r_mem_callee_saved(&mut self, dest: Reg, src: Mem); // load callee saved register
90

qinsoon's avatar
qinsoon committed
91
    // zero/sign extend mov
92 93
    fn emit_movs_r_r(&mut self, dest: Reg, src: Reg);
    fn emit_movz_r_r(&mut self, dest: Reg, src: Reg);
94

qinsoon's avatar
qinsoon committed
95
    // set byte
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
    fn emit_sets_r8(&mut self, dest: Reg);
    fn emit_setz_r8(&mut self, dest: Reg);
    fn emit_seto_r8(&mut self, dest: Reg);
    fn emit_setb_r8(&mut self, dest: Reg);

    fn emit_seta_r(&mut self, dest: Reg);
    fn emit_setae_r(&mut self, dest: Reg);
    fn emit_setb_r(&mut self, dest: Reg);
    fn emit_setbe_r(&mut self, dest: Reg);
    fn emit_sete_r(&mut self, dest: Reg);
    fn emit_setg_r(&mut self, dest: Reg);
    fn emit_setge_r(&mut self, dest: Reg);
    fn emit_setl_r(&mut self, dest: Reg);
    fn emit_setle_r(&mut self, dest: Reg);
    fn emit_setne_r(&mut self, dest: Reg);
111

qinsoon's avatar
qinsoon committed
112 113
    // gpr conditional move

114
    fn emit_cmova_r_r(&mut self, dest: Reg, src: Reg);
qinsoon's avatar
qinsoon committed
115
    fn emit_cmova_r_mem(&mut self, dest: Reg, src: Mem); // load
qinsoon's avatar
qinsoon committed
116

117
    fn emit_cmovae_r_r(&mut self, dest: Reg, src: Reg);
qinsoon's avatar
qinsoon committed
118
    fn emit_cmovae_r_mem(&mut self, dest: Reg, src: Mem); // load
qinsoon's avatar
qinsoon committed
119

120
    fn emit_cmovb_r_r(&mut self, dest: Reg, src: Reg);
qinsoon's avatar
qinsoon committed
121
    fn emit_cmovb_r_mem(&mut self, dest: Reg, src: Mem); // load
qinsoon's avatar
qinsoon committed
122

123
    fn emit_cmovbe_r_r(&mut self, dest: Reg, src: Reg);
qinsoon's avatar
qinsoon committed
124
    fn emit_cmovbe_r_mem(&mut self, dest: Reg, src: Mem); // load
qinsoon's avatar
qinsoon committed
125

126
    fn emit_cmove_r_r(&mut self, dest: Reg, src: Reg);
qinsoon's avatar
qinsoon committed
127
    fn emit_cmove_r_mem(&mut self, dest: Reg, src: Mem); // load
qinsoon's avatar
qinsoon committed
128

129
    fn emit_cmovg_r_r(&mut self, dest: Reg, src: Reg);
qinsoon's avatar
qinsoon committed
130
    fn emit_cmovg_r_mem(&mut self, dest: Reg, src: Mem); // load
qinsoon's avatar
qinsoon committed
131

132
    fn emit_cmovge_r_r(&mut self, dest: Reg, src: Reg);
qinsoon's avatar
qinsoon committed
133
    fn emit_cmovge_r_mem(&mut self, dest: Reg, src: Mem); // load
qinsoon's avatar
qinsoon committed
134

135
    fn emit_cmovl_r_r(&mut self, dest: Reg, src: Reg);
qinsoon's avatar
qinsoon committed
136
    fn emit_cmovl_r_mem(&mut self, dest: Reg, src: Mem); // load
qinsoon's avatar
qinsoon committed
137

138
    fn emit_cmovle_r_r(&mut self, dest: Reg, src: Reg);
qinsoon's avatar
qinsoon committed
139
    fn emit_cmovle_r_mem(&mut self, dest: Reg, src: Mem); // load
qinsoon's avatar
qinsoon committed
140

141
    fn emit_cmovne_r_r(&mut self, dest: Reg, src: Reg);
qinsoon's avatar
qinsoon committed
142
    fn emit_cmovne_r_mem(&mut self, dest: Reg, src: Mem); // load
qinsoon's avatar
qinsoon committed
143

144
    // lea
qinsoon's avatar
qinsoon committed
145
    fn emit_lea_r64(&mut self, dest: Reg, src: Mem);
146 147

    // and
qinsoon's avatar
qinsoon committed
148
    fn emit_and_r_imm(&mut self, dest: Reg, src: i32);
149
    fn emit_and_r_r(&mut self, dest: Reg, src: Reg);
qinsoon's avatar
qinsoon committed
150
    fn emit_and_r_mem(&mut self, dest: Reg, src: Mem);
151

qinsoon's avatar
qinsoon committed
152
    // or
153
    fn emit_or_r_r(&mut self, dest: Reg, src: Reg);
qinsoon's avatar
qinsoon committed
154 155
    fn emit_or_r_imm(&mut self, dest: Reg, src: i32);
    fn emit_or_r_mem(&mut self, dest: Reg, src: Mem);
156

157
    // xor
158
    fn emit_xor_r_r(&mut self, dest: Reg, src: Reg);
qinsoon's avatar
qinsoon committed
159 160
    fn emit_xor_r_mem(&mut self, dest: Reg, src: Mem);
    fn emit_xor_r_imm(&mut self, dest: Reg, src: i32);
161

162
    // add
163
    fn emit_add_r_r(&mut self, dest: Reg, src: Reg);
qinsoon's avatar
qinsoon committed
164 165
    fn emit_add_r_mem(&mut self, dest: Reg, src: Mem);
    fn emit_add_r_imm(&mut self, dest: Reg, src: i32);
qinsoon's avatar
qinsoon committed
166 167

    // add with carry
168
    fn emit_adc_r_r(&mut self, dest: Reg, src: Reg);
qinsoon's avatar
qinsoon committed
169 170
    fn emit_adc_r_mem(&mut self, dest: Reg, src: Mem);
    fn emit_adc_r_imm(&mut self, dest: Reg, src: i32);
171

172
    // sub
173
    fn emit_sub_r_r(&mut self, dest: Reg, src: Reg);
qinsoon's avatar
qinsoon committed
174 175
    fn emit_sub_r_mem(&mut self, dest: Reg, src: Mem);
    fn emit_sub_r_imm(&mut self, dest: Reg, src: i32);
176

177
    // sub with borrow
178
    fn emit_sbb_r_r(&mut self, dest: Reg, src: Reg);
179 180 181
    fn emit_sbb_r_mem(&mut self, dest: Reg, src: Mem);
    fn emit_sbb_r_imm(&mut self, dest: Reg, src: i32);

qinsoon's avatar
qinsoon committed
182 183 184 185 186 187
    // inc and dec
    fn emit_inc_r(&mut self, dest: Reg);
    fn emit_inc_mem(&mut self, dest: Mem);
    fn emit_dec_r(&mut self, dest: Reg);
    fn emit_dec_mem(&mut self, dest: Mem);

188
    // multiply
189
    fn emit_mul_r(&mut self, src: Reg);
qinsoon's avatar
qinsoon committed
190
    fn emit_mul_mem(&mut self, src: Mem);
191

192 193 194
    // signed multiply
    fn emit_imul_r_r(&mut self, dest: Reg, src: Reg);

195
    // div
196 197
    fn emit_div_r(&mut self, src: Reg);
    fn emit_div_mem(&mut self, src: Mem);
198 199

    // idiv
200
    fn emit_idiv_r(&mut self, src: Reg);
qinsoon's avatar
qinsoon committed
201
    fn emit_idiv_mem(&mut self, src: Mem);
202 203

    // shl
204 205 206
    fn emit_shl_r_cl(&mut self, dest: Reg);
    fn emit_shl_r_imm8(&mut self, dest: Reg, src: i8);
    fn emit_shld_r_r_cl(&mut self, dest: Reg, src: Reg);
qinsoon's avatar
qinsoon committed
207

208 209 210
    fn emit_shr_r_cl(&mut self, dest: &P<Value>);
    fn emit_shr_r_imm8(&mut self, dest: &P<Value>, src: i8);
    fn emit_shrd_r_r_cl(&mut self, dest: Reg, src: Reg);
qinsoon's avatar
qinsoon committed
211

212 213
    fn emit_sar_r_cl(&mut self, dest: &P<Value>);
    fn emit_sar_r_imm8(&mut self, dest: &P<Value>, src: i8);
qinsoon's avatar
qinsoon committed
214

qinsoon's avatar
qinsoon committed
215 216 217
    fn emit_cqo(&mut self); // sign extend rax to rdx:rax
    fn emit_cdq(&mut self); // sign extend eax to edx:eax
    fn emit_cwd(&mut self); // sign extend ax  to dx:ax
qinsoon's avatar
qinsoon committed
218 219

    // jump, conditional jump
220
    fn emit_jmp(&mut self, dest: MuName);
221
    fn emit_je(&mut self, dest: MuName);
222
    fn emit_jne(&mut self, dest: MuName);
223
    fn emit_ja(&mut self, dest: MuName);
224
    fn emit_jae(&mut self, dest: MuName);
225
    fn emit_jb(&mut self, dest: MuName);
226
    fn emit_jbe(&mut self, dest: MuName);
227
    fn emit_jg(&mut self, dest: MuName);
228
    fn emit_jge(&mut self, dest: MuName);
229
    fn emit_jl(&mut self, dest: MuName);
230
    fn emit_jle(&mut self, dest: MuName);
qinsoon's avatar
qinsoon committed
231
    fn emit_js(&mut self, dest: MuName);
qinsoon's avatar
qinsoon committed
232 233

    // call
234 235
    fn emit_call_near_rel32(
        &mut self,
236
        callsite: MuName,
237 238
        func: MuName,
        pe: Option<MuName>,
239 240
        uses: Vec<P<Value>>,
        defs: Vec<P<Value>>,
241
        is_native: bool
242 243 244
    ) -> ValueLocation;
    fn emit_call_near_r64(
        &mut self,
245
        callsite: MuName,
246 247
        func: &P<Value>,
        pe: Option<MuName>,
248 249
        uses: Vec<P<Value>>,
        defs: Vec<P<Value>>
250 251 252
    ) -> ValueLocation;
    fn emit_call_near_mem64(
        &mut self,
253
        callsite: MuName,
254 255
        func: &P<Value>,
        pe: Option<MuName>,
256 257
        uses: Vec<P<Value>>,
        defs: Vec<P<Value>>
258 259
    ) -> ValueLocation;

260 261 262
    // sometimes we use jmp as a call (but without pushing return address)
    fn emit_call_jmp(
        &mut self,
263
        callsite: MuName,
264 265 266 267 268 269 270 271
        func: MuName,
        pe: Option<MuName>,
        uses: Vec<P<Value>>,
        defs: Vec<P<Value>>,
        is_native: bool
    ) -> ValueLocation;
    fn emit_call_jmp_indirect(
        &mut self,
272
        callsite: MuName,
273 274 275 276 277 278
        func: &P<Value>,
        pe: Option<MuName>,
        uses: Vec<P<Value>>,
        defs: Vec<P<Value>>
    ) -> ValueLocation;

qinsoon's avatar
qinsoon committed
279
    fn emit_ret(&mut self);
qinsoon's avatar
qinsoon committed
280

qinsoon's avatar
qinsoon committed
281
    // push/pop
282
    fn emit_push_r64(&mut self, src: &P<Value>);
283
    fn emit_push_imm32(&mut self, src: i32);
284
    fn emit_pop_r64(&mut self, dest: &P<Value>);
285 286

    // fpr move
287
    fn emit_movsd_f64_f64(&mut self, dest: &P<Value>, src: &P<Value>);
288 289
    fn emit_movsd_f64_mem64(&mut self, dest: &P<Value>, src: &P<Value>); // load
    fn emit_movsd_mem64_f64(&mut self, dest: &P<Value>, src: &P<Value>); // store
qinsoon's avatar
qinsoon committed
290

291
    fn emit_movss_f32_f32(&mut self, dest: &P<Value>, src: &P<Value>);
292 293 294
    fn emit_movss_f32_mem32(&mut self, dest: &P<Value>, src: &P<Value>); // load
    fn emit_movss_mem32_f32(&mut self, dest: &P<Value>, src: &P<Value>); // store

qinsoon's avatar
qinsoon committed
295
    // fp add
296
    fn emit_addsd_f64_f64(&mut self, dest: Reg, src: Reg);
qinsoon's avatar
qinsoon committed
297 298
    fn emit_addsd_f64_mem64(&mut self, dest: Reg, src: Mem);

299
    fn emit_addss_f32_f32(&mut self, dest: Reg, src: Reg);
300 301
    fn emit_addss_f32_mem32(&mut self, dest: Reg, src: Mem);

qinsoon's avatar
qinsoon committed
302
    // fp sub
303
    fn emit_subsd_f64_f64(&mut self, dest: Reg, src: Reg);
qinsoon's avatar
qinsoon committed
304 305
    fn emit_subsd_f64_mem64(&mut self, dest: Reg, src: Mem);

306
    fn emit_subss_f32_f32(&mut self, dest: Reg, src: Reg);
307 308
    fn emit_subss_f32_mem32(&mut self, dest: Reg, src: Mem);

qinsoon's avatar
qinsoon committed
309
    // fp div
310
    fn emit_divsd_f64_f64(&mut self, dest: Reg, src: Reg);
qinsoon's avatar
qinsoon committed
311 312
    fn emit_divsd_f64_mem64(&mut self, dest: Reg, src: Mem);

313
    fn emit_divss_f32_f32(&mut self, dest: Reg, src: Reg);
314 315
    fn emit_divss_f32_mem32(&mut self, dest: Reg, src: Mem);

qinsoon's avatar
qinsoon committed
316
    // fp mul
317
    fn emit_mulsd_f64_f64(&mut self, dest: Reg, src: Reg);
qinsoon's avatar
qinsoon committed
318 319
    fn emit_mulsd_f64_mem64(&mut self, dest: Reg, src: Mem);

320
    fn emit_mulss_f32_f32(&mut self, dest: Reg, src: Reg);
321 322
    fn emit_mulss_f32_mem32(&mut self, dest: Reg, src: Mem);

qinsoon's avatar
qinsoon committed
323
    // fp comparison
324 325
    fn emit_comisd_f64_f64(&mut self, op1: Reg, op2: Reg);
    fn emit_ucomisd_f64_f64(&mut self, op1: Reg, op2: Reg);
qinsoon's avatar
qinsoon committed
326

327 328
    fn emit_comiss_f32_f32(&mut self, op1: Reg, op2: Reg);
    fn emit_ucomiss_f32_f32(&mut self, op1: Reg, op2: Reg);
329

qinsoon's avatar
qinsoon committed
330 331 332 333
    // fp bitwise
    fn emit_xorps_f32_f32(&mut self, dest: Reg, src: Reg);
    fn emit_xorpd_f64_f64(&mut self, dest: Reg, src: Reg);

qinsoon's avatar
qinsoon committed
334
    // fp conversion
335 336
    fn emit_cvtsi2sd_f64_r(&mut self, dest: Reg, src: Reg);
    fn emit_cvtsd2si_r_f64(&mut self, dest: Reg, src: Reg);
337

338 339
    fn emit_cvtsi2ss_f32_r(&mut self, dest: Reg, src: Reg);
    fn emit_cvtss2si_r_f32(&mut self, dest: Reg, src: Reg);
340

qinsoon's avatar
qinsoon committed
341 342 343 344
    // fp trunc
    fn emit_cvtsd2ss_f32_f64(&mut self, dest: Reg, src: Reg);
    fn emit_cvtss2sd_f64_f32(&mut self, dest: Reg, src: Reg);

345
    // used for unsigned int to fp conversion
346 347
    fn emit_cvttsd2si_r_f64(&mut self, dest: Reg, src: Reg);
    fn emit_cvttss2si_r_f32(&mut self, dest: Reg, src: Reg);
348

349 350 351
    // unpack low data - interleave low byte
    fn emit_punpckldq_f64_mem128(&mut self, dest: Reg, src: Mem);
    // substract packed double-fp
352
    fn emit_subpd_f64_mem128(&mut self, dest: Reg, src: Mem);
353
    // packed double-fp horizontal add
354
    fn emit_haddpd_f64_f64(&mut self, dest: Reg, src: Reg);
355 356 357

    // move aligned packed double-precision fp values
    fn emit_movapd_f64_mem128(&mut self, dest: Reg, src: Mem);
358
    fn emit_movapd_f64_f64(&mut self, dest: Reg, src: Mem);
qinsoon's avatar
qinsoon committed
359

360
    fn emit_movaps_f32_f32(&mut self, dest: Reg, src: Reg);
361 362 363

    // memory fence
    fn emit_mfence(&mut self);
364
}