ir_macros.rs 24 KB
Newer Older
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1
// Copyright 2017 The Australian National University
qinsoon's avatar
qinsoon committed
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
qinsoon's avatar
qinsoon committed
6
//
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
7
//     http://www.apache.org/licenses/LICENSE-2.0
qinsoon's avatar
qinsoon committed
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
macro_rules! typedef {
qinsoon's avatar
qinsoon committed
16
    // int, floating point
17
    (($vm: expr) $name: ident = mu_int($len: expr)) => {
qinsoon's avatar
qinsoon committed
18 19
        let $name = $vm.declare_type(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))),
                                     MuType_::int($len));
20
        $vm.set_name($name.as_entity());
21
    };
qinsoon's avatar
qinsoon committed
22
    (($vm: expr) $name: ident = mu_double) => {
qinsoon's avatar
qinsoon committed
23 24
        let $name = $vm.declare_type(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))),
                                     MuType_::double());
25
        $vm.set_name($name.as_entity());
qinsoon's avatar
qinsoon committed
26
    };
27
    (($vm: expr) $name: ident = mu_float) => {
qinsoon's avatar
qinsoon committed
28 29
        let $name = $vm.declare_type(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))),
                                     MuType_::float());
30 31
        $vm.set_name($name.as_entity());
    };
qinsoon's avatar
qinsoon committed
32

qinsoon's avatar
qinsoon committed
33
    // ref, iref, ptr
34
    (($vm: expr) $name: ident = mu_ref($ty: ident)) => {
qinsoon's avatar
qinsoon committed
35 36
        let $name = $vm.declare_type(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))),
                                     MuType_::muref($ty.clone()));
37
        $vm.set_name($name.as_entity());
38 39
    };
    (($vm: expr) $name: ident = mu_iref($ty: ident)) => {
qinsoon's avatar
qinsoon committed
40 41
        let $name = $vm.declare_type(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))),
                                     MuType_::iref($ty.clone()));
42
        $vm.set_name($name.as_entity());
43
    };
qinsoon's avatar
qinsoon committed
44
    (($vm: expr) $name: ident = mu_uptr($ty: ident)) => {
qinsoon's avatar
qinsoon committed
45 46
        let $name = $vm.declare_type(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))),
                                     MuType_::uptr($ty.clone()));
47
        $vm.set_name($name.as_entity());
qinsoon's avatar
qinsoon committed
48 49
    };

qinsoon's avatar
qinsoon committed
50
    // struct
51
    (($vm: expr) $name: ident = mu_struct($($ty: ident), *)) => {
qinsoon's avatar
qinsoon committed
52 53 54
        let $name = $vm.declare_type(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))),
                                     MuType_::mustruct(Mu(stringify!($name)),
                                                       vec![$($ty.clone()),*]));
55
        $vm.set_name($name.as_entity());
56
    };
qinsoon's avatar
qinsoon committed
57
    (($vm: expr) $name: ident = mu_struct()) => {
qinsoon's avatar
qinsoon committed
58 59
        let $name = $vm.declare_type(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))),
                                     MuType_::mustruct(Mu(stringify!($name)), vec![]));
60
        $vm.set_name($name.as_entity());
qinsoon's avatar
qinsoon committed
61
    };
qinsoon's avatar
qinsoon committed
62
    (($vm: expr) $name: ident = mu_struct_placeholder()) => {
qinsoon's avatar
qinsoon committed
63 64
        let $name = $vm.declare_type(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))),
                                     MuType_::mustruct_empty(Mu(stringify!($name))));
65
        $vm.set_name($name.as_entity());
qinsoon's avatar
qinsoon committed
66 67 68 69
    };
    (($vm: expr) mu_struct_put($name: ident, $($ty: ident), *)) => {
        MuType_::mustruct_put(&Mu(stringify!($name)), vec![$($ty.clone()), *])
    };
qinsoon's avatar
qinsoon committed
70

qinsoon's avatar
qinsoon committed
71
    // hybrid
72
    (($vm: expr) $name: ident = mu_hybrid($($ty: ident), *)($var_ty: ident)) => {
qinsoon's avatar
qinsoon committed
73 74 75
        let $name = $vm.declare_type(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))),
                                     MuType_::hybrid(Mu(stringify!($name)),
                                                     vec![$($ty.clone()), *], $var_ty.clone()));
76
        $vm.set_name($name.as_entity());
qinsoon's avatar
qinsoon committed
77
    };
qinsoon's avatar
qinsoon committed
78

qinsoon's avatar
fix  
qinsoon committed
79
    // array
80
    (($vm: expr) $name: ident = mu_array($ty: ident, $len: expr)) => {
qinsoon's avatar
qinsoon committed
81 82
        let $name = $vm.declare_type(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))),
                                     MuType_::array($ty.clone(), $len));
83
        $vm.set_name($name.as_entity());
84
    };
qinsoon's avatar
fix  
qinsoon committed
85

qinsoon's avatar
qinsoon committed
86
    // funcref
qinsoon's avatar
qinsoon committed
87
    (($vm: expr) $name: ident = mu_funcref($sig: ident)) => {
qinsoon's avatar
qinsoon committed
88 89
        let $name = $vm.declare_type(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))),
                                     MuType_::funcref($sig.clone()));
90 91 92 93 94
        $vm.set_name($name.as_entity());
    };

    // ufuncptr
    (($vm: expr) $name: ident = mu_ufuncptr($sig: ident)) => {
qinsoon's avatar
qinsoon committed
95 96
        let $name = $vm.declare_type(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))),
                                     MuType_::ufuncptr($sig.clone()));
97 98
        $vm.set_name($name.as_entity());
    };
99 100 101 102
}

macro_rules! constdef {
    (($vm: expr) <$ty: ident> $name: ident = $val: expr) => {
qinsoon's avatar
qinsoon committed
103 104
        let $name = $vm.declare_const(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))),
                                      $ty.clone(), $val);
105
        $vm.set_name($name.as_entity());
106 107 108
    }
}

109 110
macro_rules! globaldef {
    (($vm: expr) <$ty: ident> $name: ident) => {
qinsoon's avatar
qinsoon committed
111 112
        let $name = $vm.declare_global(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))),
                                       $ty.clone());
113
        $vm.set_name($name.as_entity());
114 115 116
    }
}

117 118
macro_rules! funcsig {
    (($vm: expr) $name: ident = ($($arg_ty: ident),*) -> ($($ret_ty: ident),*)) => {
qinsoon's avatar
qinsoon committed
119 120 121
        let $name = $vm.declare_func_sig(MuEntityHeader::named($vm.next_id(),
                                                               Mu(stringify!($name))),
                                         vec![$($ret_ty.clone()),*], vec![$($arg_ty.clone()),*]);
122
        $vm.set_name($name.as_entity());
123 124 125 126 127
    }
}

macro_rules! funcdecl {
    (($vm: expr) <$sig: ident> $name: ident) => {
qinsoon's avatar
qinsoon committed
128 129
        let func = MuFunction::new(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))),
                                   $sig.clone());
130
        $vm.set_name(func.as_entity());
131 132 133 134 135 136 137
        let $name = func.id();
        $vm.declare_func(func);
    }
}

macro_rules! funcdef {
    (($vm: expr) <$sig: ident> $func: ident VERSION $version: ident) => {
qinsoon's avatar
qinsoon committed
138 139 140
        let mut $version = MuFunctionVersion::new(MuEntityHeader::named($vm.next_id(),
                                                                        Mu(stringify!($version))),
                                                  $func, $sig.clone());
141
        $vm.set_name($version.as_entity());
142 143 144 145 146
    }
}

macro_rules! define_func_ver {
    (($vm: expr) $fv: ident (entry: $entry: ident){$($blk: ident), *}) => {
147 148 149 150 151
        $fv.define(FunctionContent::new($entry.id(), {
            let mut ret = LinkedHashMap::new();
            $ (ret.insert($blk.id(), $blk); )*
            ret
        }));
152 153 154 155 156 157 158

        $vm.define_func_version($fv);
    }
}

macro_rules! block {
    (($vm: expr, $fv: ident) $name: ident) => {
159 160
        let mut $name = Block::new(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))));
        $vm.set_name($name.as_entity());
161 162 163 164 165 166 167 168 169 170 171
    }
}

macro_rules! define_block {
    (($vm: expr, $fv: ident) $name: ident ($($arg: ident), *) {$($inst: ident), *}) => {
        $name.content = Some(BlockContent{
            args: vec![$($arg.clone_value()), *],
            exn_arg: None,
            body: vec![$($inst), *],
            keepalives: None
        });
172 173
    };

qinsoon's avatar
qinsoon committed
174 175
    (($vm: expr, $fv: ident) $name: ident ($($arg: ident), *)
     [$exn_arg: ident] {$($inst: ident), *}) => {
176 177 178 179 180 181
        $name.content = Some(BlockContent{
            args: vec![$($arg.clone_value()), *],
            exn_arg: Some($exn_arg.clone_value()),
            body: vec![$($inst), *],
            keepalives: None
        });
182 183 184 185 186
    }
}

macro_rules! ssa {
    (($vm: expr, $fv: ident) <$ty: ident> $name: ident) => {
qinsoon's avatar
qinsoon committed
187 188
        let $name = $fv.new_ssa(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))),
                                                      $ty.clone());
189
        $vm.set_name($name.as_entity());
190 191 192 193 194 195 196 197 198
    }
}

macro_rules! consta {
    (($vm: expr, $fv: ident) $name: ident = $c: ident) => {
        let $name = $fv.new_constant($c.clone());
    }
}

199 200 201 202 203 204
macro_rules! global {
    (($vm: expr, $fv: ident) $name: ident = $g: ident) => {
        let $name = $fv.new_global($g.clone());
    }
}

205 206 207 208 209 210
macro_rules! inst {
    // NEW
    (($vm: expr, $fv: ident) $name: ident: $value: ident = NEW <$ty: ident>) => {
        let $name = $fv.new_inst(Instruction{
            hdr:    MuEntityHeader::unnamed($vm.next_id()),
            value:  Some(vec![$value.clone_value()]),
211
            ops:    vec![],
212 213 214 215
            v:      Instruction_::New($ty.clone())
        });
    };

216 217 218 219 220
    // NEWHYBRID
    (($vm: expr, $fv: ident) $name: ident: $value: ident = NEWHYBRID <$ty: ident> $len: ident) => {
        let $name = $fv.new_inst(Instruction{
            hdr:    MuEntityHeader::unnamed($vm.next_id()),
            value:  Some(vec![$value.clone_value()]),
221
            ops:    vec![$len.clone()],
222 223 224 225
            v:      Instruction_::NewHybrid($ty.clone(), 0)
        });
    };

226 227 228 229 230
    // GETIREF
    (($vm: expr, $fv: ident) $name: ident: $value: ident = GETIREF $op: ident) => {
        let $name = $fv.new_inst(Instruction{
            hdr:    MuEntityHeader::unnamed($vm.next_id()),
            value:  Some(vec![$value.clone_value()]),
231
            ops:    vec![$op.clone()],
232 233 234 235 236
            v:      Instruction_::GetIRef(0)
        });
    };

    // GETFIELDIREF
qinsoon's avatar
qinsoon committed
237 238
    (($vm: expr, $fv: ident) $name: ident: $value: ident = GETFIELDIREF $op: ident
     (is_ptr: $is_ptr: expr, index: $index: expr)) => {
239 240 241
        let $name = $fv.new_inst(Instruction{
            hdr:    MuEntityHeader::unnamed($vm.next_id()),
            value:  Some(vec![$value.clone_value()]),
242
            ops:    vec![$op.clone()],
243 244 245 246 247 248 249 250
            v:      Instruction_::GetFieldIRef {
                        is_ptr: $is_ptr,
                        base: 0,
                        index: $index
            }
        });
    };

251
    // GETELEMIREF
qinsoon's avatar
qinsoon committed
252 253
    (($vm: expr, $fv: ident) $name: ident: $value: ident = GETELEMIREF $op: ident $index: ident
     (is_ptr: $is_ptr: expr)) => {
254 255 256
        let $name = $fv.new_inst(Instruction{
            hdr:    MuEntityHeader::unnamed($vm.next_id()),
            value:  Some(vec![$value.clone_value()]),
257
            ops:    vec![$op.clone(), $index.clone()],
258 259 260 261 262 263 264 265
            v:      Instruction_::GetElementIRef {
                        is_ptr: $is_ptr,
                        base: 0,
                        index: 1
            }
        });
    };

qinsoon's avatar
qinsoon committed
266
    // GETVARPARTIREF
qinsoon's avatar
qinsoon committed
267 268
    (($vm: expr, $fv: ident) $name: ident: $value: ident = GETVARPARTIREF $op: ident
     (is_ptr: $is_ptr: expr)) => {
qinsoon's avatar
qinsoon committed
269 270 271
        let $name = $fv.new_inst(Instruction{
            hdr:    MuEntityHeader::unnamed($vm.next_id()),
            value:  Some(vec![$value.clone_value()]),
272
            ops:    vec![$op.clone()],
qinsoon's avatar
qinsoon committed
273 274 275 276 277 278 279 280
            v:      Instruction_::GetVarPartIRef {
                        is_ptr: $is_ptr,
                        base: 0
            }
        });
    };

    // SHIFTIREF
qinsoon's avatar
qinsoon committed
281 282
    (($vm: expr, $fv: ident) $name: ident: $value: ident = SHIFTIREF $op: ident $offset: ident
     (is_ptr: $is_ptr: expr)) => {
qinsoon's avatar
qinsoon committed
283 284 285
        let $name = $fv.new_inst(Instruction{
            hdr:    MuEntityHeader::unnamed($vm.next_id()),
            value:  Some(vec![$value.clone_value()]),
286
            ops:    vec![$op.clone(), $offset.clone()],
qinsoon's avatar
qinsoon committed
287 288 289 290 291 292 293 294
            v:      Instruction_::ShiftIRef {
                        is_ptr: $is_ptr,
                        base: 0,
                        offset: 1
            }
        });
    };

295
    // STORE
qinsoon's avatar
qinsoon committed
296 297
    (($vm: expr, $fv: ident) $name: ident: STORE $loc: ident $val: ident
     (is_ptr: $is_ptr: expr, order: $order: expr)) => {
298 299 300
        let $name = $fv.new_inst(Instruction{
            hdr:    MuEntityHeader::unnamed($vm.next_id()),
            value:  None,
301
            ops:    vec![$loc.clone(), $val.clone()],
302 303 304 305 306 307 308 309 310 311
            v:      Instruction_::Store {
                        is_ptr: $is_ptr,
                        order: $order,
                        mem_loc: 0,
                        value: 1
            }
        });
    };

    // LOAD
qinsoon's avatar
qinsoon committed
312 313
    (($vm: expr, $fv: ident) $name: ident: $value: ident = LOAD $loc: ident
     (is_ptr: $is_ptr: expr, order: $order: expr)) => {
314 315 316
        let $name = $fv.new_inst(Instruction{
            hdr:    MuEntityHeader::unnamed($vm.next_id()),
            value:  Some(vec![$value.clone_value()]),
317
            ops:    vec![$loc.clone()],
318 319 320 321 322 323 324 325 326
            v:      Instruction_::Load {
                        is_ptr: $is_ptr,
                        order: $order,
                        mem_loc: 0
            }
        });
    };

    // BINOP
qinsoon's avatar
qinsoon committed
327 328
    (($vm: expr, $fv: ident) $name: ident: $value: ident =
     BINOP ($op: expr) $op1: ident $op2: ident) => {
329 330 331
        let $name = $fv.new_inst(Instruction{
            hdr:    MuEntityHeader::unnamed($vm.next_id()),
            value:  Some(vec![$value.clone_value()]),
332
            ops:    vec![$op1.clone(), $op2.clone()],
333 334 335 336
            v:      Instruction_::BinOp($op, 0, 1)
        });
    };

qinsoon's avatar
qinsoon committed
337
    // BINOP with status
qinsoon's avatar
qinsoon committed
338 339
    (($vm: expr, $fv: ident) $name: ident: $value: ident, $($flag: ident), * =
     BINOP_STATUS ($op: expr) ($flags: expr) $op1: ident $op2: ident) => {
qinsoon's avatar
qinsoon committed
340 341 342
        let $name = $fv.new_inst(Instruction{
            hdr:    MuEntityHeader::unnamed($vm.next_id()),
            value:  Some(vec![$value.clone_value(), $($flag.clone_value()), *]),
343
            ops:    vec![$op1.clone(), $op2.clone()],
qinsoon's avatar
qinsoon committed
344 345 346 347
            v:      Instruction_::BinOpWithStatus($op, $flags, 0, 1)
        });
    };

qinsoon's avatar
qinsoon committed
348
    // CMPOP
qinsoon's avatar
qinsoon committed
349 350
    (($vm: expr, $fv: ident) $name: ident: $value: ident =
     CMPOP ($op: expr) $op1: ident $op2: ident) => {
qinsoon's avatar
qinsoon committed
351 352 353
        let $name = $fv.new_inst(Instruction{
            hdr: MuEntityHeader::unnamed($vm.next_id()),
            value: Some(vec![$value.clone_value()]),
354
            ops: vec![$op1.clone(), $op2.clone()],
qinsoon's avatar
qinsoon committed
355 356 357 358
            v: Instruction_::CmpOp($op, 0, 1)
        });
    };

359
    // CONVOP
qinsoon's avatar
qinsoon committed
360 361
    (($vm: expr, $fv: ident) $name: ident: $value: ident =
     CONVOP ($operation: expr) <$ty1: ident $ty2: ident> $operand: ident) => {
362 363 364
        let $name = $fv.new_inst(Instruction{
            hdr: MuEntityHeader::unnamed($vm.next_id()),
            value: Some(vec![$value.clone_value()]),
365
            ops: vec![$operand.clone()],
366 367 368 369 370 371 372 373 374
            v: Instruction_::ConvOp{
                operation: $operation,
                from_ty: $ty1.clone(),
                to_ty: $ty2.clone(),
                operand: 0
            }
        });
    };

qinsoon's avatar
qinsoon committed
375
    // SELECT
qinsoon's avatar
qinsoon committed
376 377
    (($vm: expr, $fv: ident) $name: ident: $value: ident =
     SELECT $cond: ident $op_true: ident $op_false:ident) => {
qinsoon's avatar
qinsoon committed
378 379 380
        let $name = $fv.new_inst(Instruction{
            hdr: MuEntityHeader::unnamed($vm.next_id()),
            value: Some(vec![$value.clone_value()]),
381
            ops: vec![$cond.clone(), $op_true.clone(), $op_false.clone()],
qinsoon's avatar
qinsoon committed
382 383 384 385 386 387 388 389
            v: Instruction_::Select{
                cond: 0,
                true_val: 1,
                false_val: 2
            }
        });
    };

390 391 392 393 394
    // BRANCH
    (($vm: expr, $fv: ident) $name: ident: BRANCH $dest: ident ($($arg: ident), *)) => {
        let $name = $fv.new_inst(Instruction{
            hdr:    MuEntityHeader::unnamed($vm.next_id()),
            value:  None,
395
            ops:    vec![$($arg.clone()),*],
396 397 398 399
            v:      Instruction_::Branch1(Destination{
                        target: $dest.id(),
                        args: {
                            let mut i =0;
qinsoon's avatar
qinsoon committed
400 401 402
                            vec![$($arg.clone()),*].iter().map(|_| {
                                let ret = DestArg::Normal(i); i+=1; ret
                             }).collect()
403 404 405 406 407
                        }
            })
        });
    };

qinsoon's avatar
qinsoon committed
408 409 410 411 412 413 414 415 416 417 418 419 420
    // BRANCH2
    // list all operands first
    // then use vector expr to list operands for each destination
    // (we cannot have two repetition list of different lengths in a macro)
    (($vm: expr, $fv: ident) $name: ident:
        BRANCH2 ($($op: ident), *)
            IF (OP $cond: expr)
            THEN $true_dest : ident ($true_args: expr) WITH $prob: expr,
            ELSE $false_dest: ident ($false_args: expr)
    ) => {
        let $name = $fv.new_inst(Instruction{
            hdr:    MuEntityHeader::unnamed($vm.next_id()),
            value:  None,
421
            ops:    vec![$($op.clone()),*],
qinsoon's avatar
qinsoon committed
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
            v:      {
                let true_args = {
                    $true_args.iter().map(|x| DestArg::Normal(*x)).collect()
                };

                let false_args = {
                    $false_args.iter().map(|x| DestArg::Normal(*x)).collect()
                };

                Instruction_::Branch2{
                    cond: $cond,
                    true_dest: Destination {
                        target: $true_dest.id(),
                        args: true_args
                    },
                    false_dest: Destination {
                        target: $false_dest.id(),
                        args: false_args
                    },
                    true_prob: $prob
                }
            }
        });
    };

447
    // EXPRCALL
qinsoon's avatar
qinsoon committed
448 449
    (($vm: expr, $fv: ident) $name: ident: $res: ident =
     EXPRCALL ($cc: expr, is_abort: $is_abort: expr) $func: ident ($($val: ident), *)) => {
450
        let ops = vec![$func.clone(), $($val.clone()), *];
qinsoon's avatar
qinsoon committed
451 452 453 454
        let ops_len = ops.len();
        let $name = $fv.new_inst(Instruction{
            hdr:    MuEntityHeader::unnamed($vm.next_id()),
            value:  Some(vec![$res.clone_value()]),
455
            ops:    ops,
qinsoon's avatar
qinsoon committed
456 457 458 459 460 461 462 463 464 465
            v:      Instruction_::ExprCall {
                        data: CallData {
                            func: 0,
                            args: (1..ops_len).collect(),
                            convention: $cc
                        },
                        is_abort: $is_abort
                    }
        });
    };
qinsoon's avatar
qinsoon committed
466 467
    (($vm: expr, $fv: ident) $name: ident:
     EXPRCALL ($cc: expr, is_abort: $is_abort: expr) $func: ident ($($val: ident), *)) => {
qinsoon's avatar
[wip]  
qinsoon committed
468 469 470 471 472
        let ops = vec![$func.clone(), $($val.clone()), *];
        let ops_len = ops.len();
        let $name = $fv.new_inst(Instruction{
            hdr:    MuEntityHeader::unnamed($vm.next_id()),
            value:  Some(vec![]),
473
            ops:    ops,
qinsoon's avatar
[wip]  
qinsoon committed
474 475 476 477 478 479 480 481 482 483
            v:      Instruction_::ExprCall {
                        data: CallData {
                            func: 0,
                            args: (1..ops_len).collect(),
                            convention: $cc
                        },
                        is_abort: $is_abort
                    }
        });
    };
484 485

    // EXPRCCALL
qinsoon's avatar
qinsoon committed
486 487
    (($vm: expr, $fv: ident) $name: ident: $res: ident =
     EXPRCCALL ($cc: expr, is_abort: $is_abort: expr) $func: ident ($($val: ident), *)) => {
488 489 490 491 492
        let ops = vec![$func.clone(), $($val.clone()), *];
        let ops_len = ops.len();
        let $name = $fv.new_inst(Instruction{
            hdr:    MuEntityHeader::unnamed($vm.next_id()),
            value:  Some(vec![$res.clone_value()]),
493
            ops:    ops,
494 495 496 497 498 499 500 501 502 503
            v:      Instruction_::ExprCCall {
                        data: CallData {
                            func: 0,
                            args: (1..ops_len).collect(),
                            convention: $cc
                        },
                        is_abort: $is_abort
                    }
        });
    };
qinsoon's avatar
qinsoon committed
504 505
    (($vm: expr, $fv: ident) $name: ident:
    EXPRCCALL ($cc: expr, is_abort: $is_abort: expr) $func: ident ($($val: ident), *)) => {
506 507 508 509 510
        let ops = vec![$func.clone(), $($val.clone()), *];
        let ops_len = ops.len();
        let $name = $fv.new_inst(Instruction{
            hdr:    MuEntityHeader::unnamed($vm.next_id()),
            value:  Some(vec![]),
511
            ops:    ops,
512 513 514 515 516 517 518 519 520 521 522
            v:      Instruction_::ExprCCall {
                        data: CallData {
                            func: 0,
                            args: (1..ops_len).collect(),
                            convention: $cc
                        },
                        is_abort: $is_abort
                    }
        });
    };

523
    // CALL (1 return result)
qinsoon's avatar
qinsoon committed
524 525
    (($vm: expr, $fv: ident) $name: ident: $res: ident =
     CALL ($($op: ident), *) FUNC($func: expr) ($args: expr) $cc: expr,
526 527 528 529 530
                      normal: $norm_dest: ident ($norm_args: expr),
                      exc: $exc_dest: ident ($exc_args: expr)) => {
        let $name = $fv.new_inst(Instruction {
            hdr  : MuEntityHeader::unnamed($vm.next_id()),
            value: Some(vec![$res.clone_value()]),
531
            ops  : vec![$($op.clone()),*],
532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
            v    : Instruction_::Call {
                data: CallData {
                    func: $func,
                    args: $args,
                    convention: $cc
                },
                resume: ResumptionData {
                    normal_dest: Destination {
                        target: $norm_dest.id(),
                        args  : $norm_args
                    },
                    exn_dest: Destination {
                        target: $exc_dest.id(),
                        args  : $exc_args
                    }
                }
            }
        });
    };
551 552 553 554 555 556 557 558
    // CALL (no return value)
    (($vm: expr, $fv: ident) $name: ident:
        CALL ($($op: ident), *) FUNC($func: expr) ($args: expr) $cc: expr,
                      normal: $norm_dest: ident ($norm_args: expr),
                      exc: $exc_dest: ident ($exc_args: expr)) => {
        let $name = $fv.new_inst(Instruction {
            hdr  : MuEntityHeader::unnamed($vm.next_id()),
            value: None,
559
            ops  : vec![$($op.clone()),*],
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
            v    : Instruction_::Call {
                data: CallData {
                    func: $func,
                    args: $args,
                    convention: $cc
                },
                resume: ResumptionData {
                    normal_dest: Destination {
                        target: $norm_dest.id(),
                        args  : $norm_args
                    },
                    exn_dest: Destination {
                        target: $exc_dest.id(),
                        args  : $exc_args
                    }
                }
            }
        });
    };

qinsoon's avatar
qinsoon committed
580

581
    // RET
582
    (($vm: expr, $fv: ident) $name: ident: RET ($($val: ident), +)) => {
583 584 585
        let $name = $fv.new_inst(Instruction{
            hdr:    MuEntityHeader::unnamed($vm.next_id()),
            value:  None,
586
            ops:    vec![$($val.clone()), *],
587 588
            v:      Instruction_::Return({
                        let mut i = 0;
qinsoon's avatar
qinsoon committed
589
                        vec![$($val.clone()), *].iter().map(|_| {let ret = i; i+= 1; ret}).collect()
590 591 592
                    })
        });
    };
593 594 595 596 597
    // RET (no value)
    (($vm: expr, $fv: ident) $name: ident: RET) => {
        let $name = $fv.new_inst(Instruction{
            hdr:    MuEntityHeader::unnamed($vm.next_id()),
            value:  None,
598
            ops:    vec![],
599 600 601
            v:      Instruction_::Return(vec![])
        });
    };
602 603 604 605 606 607

    // THREADEXIT
    (($vm: expr, $fv: ident) $name: ident: THREADEXIT) => {
        let $name = $fv.new_inst(Instruction{
            hdr: MuEntityHeader::unnamed($vm.next_id()),
            value: None,
608
            ops: vec![],
609 610 611 612
            v: Instruction_::ThreadExit
        });
    };

613 614 615 616 617
    // THROW
    (($vm: expr, $fv: ident) $name: ident: THROW $op: ident) => {
        let $name = $fv.new_inst(Instruction{
            hdr: MuEntityHeader::unnamed($vm.next_id()),
            value: None,
618
            ops: vec![$op.clone()],
619 620 621 622
            v: Instruction_::Throw(0)
        });
    };

623 624 625 626 627
    // PRINTHEX
    (($vm: expr, $fv: ident) $name: ident: PRINTHEX $val: ident) => {
        let $name = $fv.new_inst(Instruction{
            hdr: MuEntityHeader::unnamed($vm.next_id()),
            value: None,
628
            ops: vec![$val.clone()],
629 630
            v: Instruction_::PrintHex(0)
        });
631 632 633 634 635 636 637 638 639 640 641
    };

    // SET_RETVAL
    (($vm: expr, $fv: ident) $name: ident: SET_RETVAL $val: ident) => {
        let $name = $fv.new_inst(Instruction{
            hdr: MuEntityHeader::unnamed($vm.next_id()),
            value: None,
            ops: vec![$val.clone()],
            v: Instruction_::SetRetval(0)
        });
    };
642 643 644 645 646 647 648 649 650 651

    // MOVE
    (($vm: expr, $fv: ident) $name: ident: MOVE $src: ident -> $dst: ident) => {
        let $name = $fv.new_inst(Instruction {
            hdr: MuEntityHeader::unnamed($vm.next_id()),
            value: Some(vec![$dst.clone_value()]),
            ops: vec![$src],
            v: Instruction_::Move(0)
        });
    };
652
}