ir_macros.rs 22.6 KB
Newer Older
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// Copyright 2017 The Australian National University
// 
// 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
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// 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)) => {
18 19
        let $name = $vm.declare_type(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))), MuType_::int($len));
        $vm.set_name($name.as_entity());
20
    };
qinsoon's avatar
qinsoon committed
21
    (($vm: expr) $name: ident = mu_double) => {
22 23
        let $name = $vm.declare_type(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))), MuType_::double());
        $vm.set_name($name.as_entity());
qinsoon's avatar
qinsoon committed
24
    };
25 26 27 28
    (($vm: expr) $name: ident = mu_float) => {
        let $name = $vm.declare_type(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))), MuType_::float());
        $vm.set_name($name.as_entity());
    };
qinsoon's avatar
qinsoon committed
29

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

qinsoon's avatar
qinsoon committed
44
    // struct
45
    (($vm: expr) $name: ident = mu_struct($($ty: ident), *)) => {
46 47
        let $name = $vm.declare_type(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))), MuType_::mustruct(Mu(stringify!($name)), vec![$($ty.clone()),*]));
        $vm.set_name($name.as_entity());
48
    };
qinsoon's avatar
qinsoon committed
49
    (($vm: expr) $name: ident = mu_struct()) => {
50 51
        let $name = $vm.declare_type(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))), MuType_::mustruct(Mu(stringify!($name)), vec![]));
        $vm.set_name($name.as_entity());
qinsoon's avatar
qinsoon committed
52
    };
qinsoon's avatar
qinsoon committed
53
    (($vm: expr) $name: ident = mu_struct_placeholder()) => {
54 55
        let $name = $vm.declare_type(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))), MuType_::mustruct_empty(Mu(stringify!($name))));
        $vm.set_name($name.as_entity());
qinsoon's avatar
qinsoon committed
56 57 58 59
    };
    (($vm: expr) mu_struct_put($name: ident, $($ty: ident), *)) => {
        MuType_::mustruct_put(&Mu(stringify!($name)), vec![$($ty.clone()), *])
    };
qinsoon's avatar
qinsoon committed
60

qinsoon's avatar
qinsoon committed
61
    // hybrid
62 63 64
    (($vm: expr) $name: ident = mu_hybrid($($ty: ident), *)($var_ty: ident)) => {
        let $name = $vm.declare_type(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))), MuType_::hybrid(Mu(stringify!($name)), vec![$($ty.clone()), *], $var_ty.clone()));
        $vm.set_name($name.as_entity());
qinsoon's avatar
qinsoon committed
65
    };
qinsoon's avatar
qinsoon committed
66

qinsoon's avatar
fix  
qinsoon committed
67
    // array
68
    (($vm: expr) $name: ident = mu_array($ty: ident, $len: expr)) => {
69 70
        let $name = $vm.declare_type(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))), MuType_::array($ty.clone(), $len));
        $vm.set_name($name.as_entity());
71
    };
qinsoon's avatar
fix  
qinsoon committed
72

qinsoon's avatar
qinsoon committed
73
    // funcref
qinsoon's avatar
qinsoon committed
74
    (($vm: expr) $name: ident = mu_funcref($sig: ident)) => {
75 76 77 78 79 80 81 82 83
        let $name = $vm.declare_type(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))), MuType_::funcref($sig.clone()));
        $vm.set_name($name.as_entity());
    };

    // ufuncptr
    (($vm: expr) $name: ident = mu_ufuncptr($sig: ident)) => {
        let $name = $vm.declare_type(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))), MuType_::ufuncptr($sig.clone()));
        $vm.set_name($name.as_entity());
    };
84 85 86 87
}

macro_rules! constdef {
    (($vm: expr) <$ty: ident> $name: ident = $val: expr) => {
88 89
        let $name = $vm.declare_const(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))), $ty.clone(), $val);
        $vm.set_name($name.as_entity());
90 91 92
    }
}

93 94
macro_rules! globaldef {
    (($vm: expr) <$ty: ident> $name: ident) => {
95 96
        let $name = $vm.declare_global(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))), $ty.clone());
        $vm.set_name($name.as_entity());
97 98 99
    }
}

100 101
macro_rules! funcsig {
    (($vm: expr) $name: ident = ($($arg_ty: ident),*) -> ($($ret_ty: ident),*)) => {
102 103
        let $name = $vm.declare_func_sig(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))), vec![$($ret_ty.clone()),*], vec![$($arg_ty.clone()),*]);
        $vm.set_name($name.as_entity());
104 105 106 107 108
    }
}

macro_rules! funcdecl {
    (($vm: expr) <$sig: ident> $name: ident) => {
109 110
        let func = MuFunction::new(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))), $sig.clone());
        $vm.set_name(func.as_entity());
111 112 113 114 115 116 117
        let $name = func.id();
        $vm.declare_func(func);
    }
}

macro_rules! funcdef {
    (($vm: expr) <$sig: ident> $func: ident VERSION $version: ident) => {
118 119
        let mut $version = MuFunctionVersion::new(MuEntityHeader::named($vm.next_id(), Mu(stringify!($version))), $func, $sig.clone());
        $vm.set_name($version.as_entity());
120 121 122 123 124
    }
}

macro_rules! define_func_ver {
    (($vm: expr) $fv: ident (entry: $entry: ident){$($blk: ident), *}) => {
125 126 127 128 129
        $fv.define(FunctionContent::new($entry.id(), {
            let mut ret = LinkedHashMap::new();
            $ (ret.insert($blk.id(), $blk); )*
            ret
        }));
130 131 132 133 134 135 136

        $vm.define_func_version($fv);
    }
}

macro_rules! block {
    (($vm: expr, $fv: ident) $name: ident) => {
137 138
        let mut $name = Block::new(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))));
        $vm.set_name($name.as_entity());
139 140 141 142 143 144 145 146 147 148 149
    }
}

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
        });
150 151 152 153 154 155 156 157 158
    };

    (($vm: expr, $fv: ident) $name: ident ($($arg: ident), *) [$exn_arg: ident] {$($inst: ident), *}) => {
        $name.content = Some(BlockContent{
            args: vec![$($arg.clone_value()), *],
            exn_arg: Some($exn_arg.clone_value()),
            body: vec![$($inst), *],
            keepalives: None
        });
159 160 161 162 163
    }
}

macro_rules! ssa {
    (($vm: expr, $fv: ident) <$ty: ident> $name: ident) => {
164 165
        let $name = $fv.new_ssa(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))), $ty.clone());
        $vm.set_name($name.as_entity());
166 167 168 169 170 171 172 173 174
    }
}

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

175 176 177 178 179 180
macro_rules! global {
    (($vm: expr, $fv: ident) $name: ident = $g: ident) => {
        let $name = $fv.new_global($g.clone());
    }
}

181 182 183 184 185 186
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()]),
187
            ops:    vec![],
188 189 190 191
            v:      Instruction_::New($ty.clone())
        });
    };

192 193 194 195 196
    // 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()]),
197
            ops:    vec![$len.clone()],
198 199 200 201
            v:      Instruction_::NewHybrid($ty.clone(), 0)
        });
    };

202 203 204 205 206
    // 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()]),
207
            ops:    vec![$op.clone()],
208 209 210 211 212 213 214 215 216
            v:      Instruction_::GetIRef(0)
        });
    };

    // GETFIELDIREF
    (($vm: expr, $fv: ident) $name: ident: $value: ident = GETFIELDIREF $op: ident (is_ptr: $is_ptr: expr, index: $index: expr)) => {
        let $name = $fv.new_inst(Instruction{
            hdr:    MuEntityHeader::unnamed($vm.next_id()),
            value:  Some(vec![$value.clone_value()]),
217
            ops:    vec![$op.clone()],
218 219 220 221 222 223 224 225
            v:      Instruction_::GetFieldIRef {
                        is_ptr: $is_ptr,
                        base: 0,
                        index: $index
            }
        });
    };

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

qinsoon's avatar
qinsoon committed
240 241 242 243 244
    // GETVARPARTIREF
    (($vm: expr, $fv: ident) $name: ident: $value: ident = GETVARPARTIREF $op: ident (is_ptr: $is_ptr: expr)) => {
        let $name = $fv.new_inst(Instruction{
            hdr:    MuEntityHeader::unnamed($vm.next_id()),
            value:  Some(vec![$value.clone_value()]),
245
            ops:    vec![$op.clone()],
qinsoon's avatar
qinsoon committed
246 247 248 249 250 251 252 253 254 255 256 257
            v:      Instruction_::GetVarPartIRef {
                        is_ptr: $is_ptr,
                        base: 0
            }
        });
    };

    // SHIFTIREF
    (($vm: expr, $fv: ident) $name: ident: $value: ident = SHIFTIREF $op: ident $offset: ident (is_ptr: $is_ptr: expr)) => {
        let $name = $fv.new_inst(Instruction{
            hdr:    MuEntityHeader::unnamed($vm.next_id()),
            value:  Some(vec![$value.clone_value()]),
258
            ops:    vec![$op.clone(), $offset.clone()],
qinsoon's avatar
qinsoon committed
259 260 261 262 263 264 265 266
            v:      Instruction_::ShiftIRef {
                        is_ptr: $is_ptr,
                        base: 0,
                        offset: 1
            }
        });
    };

267 268 269 270 271
    // STORE
    (($vm: expr, $fv: ident) $name: ident: STORE $loc: ident $val: ident (is_ptr: $is_ptr: expr, order: $order: expr)) => {
        let $name = $fv.new_inst(Instruction{
            hdr:    MuEntityHeader::unnamed($vm.next_id()),
            value:  None,
272
            ops:    vec![$loc.clone(), $val.clone()],
273 274 275 276 277 278 279 280 281 282 283 284 285 286
            v:      Instruction_::Store {
                        is_ptr: $is_ptr,
                        order: $order,
                        mem_loc: 0,
                        value: 1
            }
        });
    };

    // LOAD
    (($vm: expr, $fv: ident) $name: ident: $value: ident = LOAD $loc: ident (is_ptr: $is_ptr: expr, order: $order: expr)) => {
        let $name = $fv.new_inst(Instruction{
            hdr:    MuEntityHeader::unnamed($vm.next_id()),
            value:  Some(vec![$value.clone_value()]),
287
            ops:    vec![$loc.clone()],
288 289 290 291 292 293 294 295 296 297 298 299 300
            v:      Instruction_::Load {
                        is_ptr: $is_ptr,
                        order: $order,
                        mem_loc: 0
            }
        });
    };

    // BINOP
    (($vm: expr, $fv: ident) $name: ident: $value: ident = BINOP ($op: expr) $op1: ident $op2: ident) => {
        let $name = $fv.new_inst(Instruction{
            hdr:    MuEntityHeader::unnamed($vm.next_id()),
            value:  Some(vec![$value.clone_value()]),
301
            ops:    vec![$op1.clone(), $op2.clone()],
302 303 304 305
            v:      Instruction_::BinOp($op, 0, 1)
        });
    };

qinsoon's avatar
qinsoon committed
306 307 308 309 310
    // BINOP with status
    (($vm: expr, $fv: ident) $name: ident: $value: ident, $($flag: ident), * = BINOP_STATUS ($op: expr) ($flags: expr) $op1: ident $op2: ident) => {
        let $name = $fv.new_inst(Instruction{
            hdr:    MuEntityHeader::unnamed($vm.next_id()),
            value:  Some(vec![$value.clone_value(), $($flag.clone_value()), *]),
311
            ops:    vec![$op1.clone(), $op2.clone()],
qinsoon's avatar
qinsoon committed
312 313 314 315
            v:      Instruction_::BinOpWithStatus($op, $flags, 0, 1)
        });
    };

qinsoon's avatar
qinsoon committed
316 317 318 319 320
    // CMPOP
    (($vm: expr, $fv: ident) $name: ident: $value: ident = CMPOP ($op: expr) $op1: ident $op2: ident) => {
        let $name = $fv.new_inst(Instruction{
            hdr: MuEntityHeader::unnamed($vm.next_id()),
            value: Some(vec![$value.clone_value()]),
321
            ops: vec![$op1.clone(), $op2.clone()],
qinsoon's avatar
qinsoon committed
322 323 324 325
            v: Instruction_::CmpOp($op, 0, 1)
        });
    };

326 327 328 329 330
    // CONVOP
    (($vm: expr, $fv: ident) $name: ident: $value: ident = CONVOP ($operation: expr) <$ty1: ident $ty2: ident> $operand: ident) => {
        let $name = $fv.new_inst(Instruction{
            hdr: MuEntityHeader::unnamed($vm.next_id()),
            value: Some(vec![$value.clone_value()]),
331
            ops: vec![$operand.clone()],
332 333 334 335 336 337 338 339 340
            v: Instruction_::ConvOp{
                operation: $operation,
                from_ty: $ty1.clone(),
                to_ty: $ty2.clone(),
                operand: 0
            }
        });
    };

qinsoon's avatar
qinsoon committed
341 342 343 344 345
    // SELECT
    (($vm: expr, $fv: ident) $name: ident: $value: ident = SELECT $cond: ident $op_true: ident $op_false:ident) => {
        let $name = $fv.new_inst(Instruction{
            hdr: MuEntityHeader::unnamed($vm.next_id()),
            value: Some(vec![$value.clone_value()]),
346
            ops: vec![$cond.clone(), $op_true.clone(), $op_false.clone()],
qinsoon's avatar
qinsoon committed
347 348 349 350 351 352 353 354
            v: Instruction_::Select{
                cond: 0,
                true_val: 1,
                false_val: 2
            }
        });
    };

355 356 357 358 359
    // 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,
360
            ops:    vec![$($arg.clone()),*],
361 362 363 364
            v:      Instruction_::Branch1(Destination{
                        target: $dest.id(),
                        args: {
                            let mut i =0;
qinsoon's avatar
qinsoon committed
365
                            vec![$($arg.clone()),*].iter().map(|_| {let ret = DestArg::Normal(i); i+=1; ret}).collect()
366 367 368 369 370
                        }
            })
        });
    };

qinsoon's avatar
qinsoon committed
371 372 373 374 375 376 377 378 379 380 381 382 383
    // 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,
384
            ops:    vec![$($op.clone()),*],
qinsoon's avatar
qinsoon committed
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
            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
                }
            }
        });
    };

410
    // EXPRCALL
411
    (($vm: expr, $fv: ident) $name: ident: $res: ident = EXPRCALL ($cc: expr, is_abort: $is_abort: expr) $func: ident ($($val: ident), *)) => {
412
        let ops = vec![$func.clone(), $($val.clone()), *];
qinsoon's avatar
qinsoon committed
413 414 415 416
        let ops_len = ops.len();
        let $name = $fv.new_inst(Instruction{
            hdr:    MuEntityHeader::unnamed($vm.next_id()),
            value:  Some(vec![$res.clone_value()]),
417
            ops:    ops,
qinsoon's avatar
qinsoon committed
418 419 420 421 422 423 424 425 426 427
            v:      Instruction_::ExprCall {
                        data: CallData {
                            func: 0,
                            args: (1..ops_len).collect(),
                            convention: $cc
                        },
                        is_abort: $is_abort
                    }
        });
    };
428
    (($vm: expr, $fv: ident) $name: ident: EXPRCALL ($cc: expr, is_abort: $is_abort: expr) $func: ident ($($val: ident), *)) => {
qinsoon's avatar
[wip]  
qinsoon committed
429 430 431 432 433
        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![]),
434
            ops:    ops,
qinsoon's avatar
[wip]  
qinsoon committed
435 436 437 438 439 440 441 442 443 444
            v:      Instruction_::ExprCall {
                        data: CallData {
                            func: 0,
                            args: (1..ops_len).collect(),
                            convention: $cc
                        },
                        is_abort: $is_abort
                    }
        });
    };
445 446 447 448 449 450 451 452

    // EXPRCCALL
    (($vm: expr, $fv: ident) $name: ident: $res: ident = EXPRCCALL ($cc: expr, is_abort: $is_abort: expr) $func: ident ($($val: ident), *)) => {
        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()]),
453
            ops:    ops,
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
            v:      Instruction_::ExprCCall {
                        data: CallData {
                            func: 0,
                            args: (1..ops_len).collect(),
                            convention: $cc
                        },
                        is_abort: $is_abort
                    }
        });
    };
    (($vm: expr, $fv: ident) $name: ident: EXPRCCALL ($cc: expr, is_abort: $is_abort: expr) $func: ident ($($val: ident), *)) => {
        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![]),
470
            ops:    ops,
471 472 473 474 475 476 477 478 479 480 481
            v:      Instruction_::ExprCCall {
                        data: CallData {
                            func: 0,
                            args: (1..ops_len).collect(),
                            convention: $cc
                        },
                        is_abort: $is_abort
                    }
        });
    };

482
    // CALL (1 return result)
483 484 485 486 487 488 489
    (($vm: expr, $fv: ident) $name: ident:
        $res: 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: Some(vec![$res.clone_value()]),
490
            ops  : vec![$($op.clone()),*],
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509
            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
                    }
                }
            }
        });
    };
510 511 512 513 514 515 516 517
    // 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,
518
            ops  : vec![$($op.clone()),*],
519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538
            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
539

540
    // RET
541
    (($vm: expr, $fv: ident) $name: ident: RET ($($val: ident), +)) => {
542 543 544
        let $name = $fv.new_inst(Instruction{
            hdr:    MuEntityHeader::unnamed($vm.next_id()),
            value:  None,
545
            ops:    vec![$($val.clone()), *],
546 547
            v:      Instruction_::Return({
                        let mut i = 0;
qinsoon's avatar
qinsoon committed
548
                        vec![$($val.clone()), *].iter().map(|_| {let ret = i; i+= 1; ret}).collect()
549 550 551
                    })
        });
    };
552 553 554 555 556
    // RET (no value)
    (($vm: expr, $fv: ident) $name: ident: RET) => {
        let $name = $fv.new_inst(Instruction{
            hdr:    MuEntityHeader::unnamed($vm.next_id()),
            value:  None,
557
            ops:    vec![],
558 559 560
            v:      Instruction_::Return(vec![])
        });
    };
561 562 563 564 565 566

    // THREADEXIT
    (($vm: expr, $fv: ident) $name: ident: THREADEXIT) => {
        let $name = $fv.new_inst(Instruction{
            hdr: MuEntityHeader::unnamed($vm.next_id()),
            value: None,
567
            ops: vec![],
568 569 570 571
            v: Instruction_::ThreadExit
        });
    };

572 573 574 575 576
    // THROW
    (($vm: expr, $fv: ident) $name: ident: THROW $op: ident) => {
        let $name = $fv.new_inst(Instruction{
            hdr: MuEntityHeader::unnamed($vm.next_id()),
            value: None,
577
            ops: vec![$op.clone()],
578 579 580 581
            v: Instruction_::Throw(0)
        });
    };

582 583 584 585 586
    // PRINTHEX
    (($vm: expr, $fv: ident) $name: ident: PRINTHEX $val: ident) => {
        let $name = $fv.new_inst(Instruction{
            hdr: MuEntityHeader::unnamed($vm.next_id()),
            value: None,
587
            ops: vec![$val.clone()],
588 589
            v: Instruction_::PrintHex(0)
        });
590 591 592 593 594 595 596 597 598 599 600
    };

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