compiler: Check branch and loop emission

39a13d89431d59953844c9b5a94d8a7634bf7e87f77be58d1a0799d647e8a667
Alexis Sellier committed ago 1 parent f9a33a93
lib/std/lang/lower.rad +40 -32
2299 2299
    }
2300 2300
    block.instrs.append(*instr, allocator);
2301 2301
}
2302 2302
2303 2303
/// Emit an unconditional jump to `target`.
2304 -
unsafe fn emitJmp 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, target: BlockId) throws (LowerError) where 'arena: 'phase, 'phase: 'function {
2305 -
    emit(self, il::Instr::Jmp { target: *target, args: &mut [] });
2304 +
fn emitJmp 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, target: BlockId) throws (LowerError) where 'arena: 'phase, 'phase: 'function {
2305 +
    unsafe {
2306 +
        emit(self, il::Instr::Jmp { target: *target, args: &mut [] });
2307 +
    }
2306 2308
    addPredecessor(self, target, currentBlock(self));
2307 2309
}
2308 2310
2309 2311
/// Emit an unconditional jump to `target` with a single argument.
2310 -
unsafe fn emitJmpWithArg 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, target: BlockId, arg: il::Val) throws (LowerError) where 'arena: 'phase, 'phase: 'function {
2311 -
    let args = try allocVal(self, arg);
2312 -
    emit(self, il::Instr::Jmp { target: *target, args });
2312 +
fn emitJmpWithArg 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, target: BlockId, arg: il::Val) throws (LowerError) where 'arena: 'phase, 'phase: 'function {
2313 +
    unsafe {
2314 +
        let args = try allocVal(self, arg);
2315 +
        emit(self, il::Instr::Jmp { target: *target, args });
2316 +
    }
2313 2317
    addPredecessor(self, target, currentBlock(self));
2314 2318
}
2315 2319
2316 2320
/// Emit an unconditional jump to `target` and switch to it.
2317 -
unsafe fn switchAndJumpTo 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, target: BlockId) throws (LowerError) where 'arena: 'phase, 'phase: 'function {
2321 +
fn switchAndJumpTo 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, target: BlockId) throws (LowerError) where 'arena: 'phase, 'phase: 'function {
2318 2322
    try emitJmp(self, target);
2319 2323
    switchToBlock(self, target);
2320 2324
}
2321 2325
2322 2326
/// Emit a conditional branch based on `cond`.
2323 -
unsafe fn emitBr 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, cond: il::Reg, thenBlock: BlockId, elseBlock: BlockId) throws (LowerError) where 'arena: 'phase, 'phase: 'function {
2327 +
fn emitBr 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, cond: il::Reg, thenBlock: BlockId, elseBlock: BlockId) throws (LowerError) where 'arena: 'phase, 'phase: 'function {
2324 2328
    assert thenBlock <> elseBlock;
2325 -
    emit(self, il::Instr::Br {
2326 -
        op: il::CmpOp::Ne,
2327 -
        typ: il::Type::W32,
2328 -
        a: il::Val::Reg(cond),
2329 -
        b: il::Val::Imm(0),
2330 -
        thenTarget: *thenBlock,
2331 -
        thenArgs: &mut [],
2332 -
        elseTarget: *elseBlock,
2333 -
        elseArgs: &mut [],
2334 -
    });
2329 +
    unsafe {
2330 +
        emit(self, il::Instr::Br {
2331 +
            op: il::CmpOp::Ne,
2332 +
            typ: il::Type::W32,
2333 +
            a: il::Val::Reg(cond),
2334 +
            b: il::Val::Imm(0),
2335 +
            thenTarget: *thenBlock,
2336 +
            thenArgs: &mut [],
2337 +
            elseTarget: *elseBlock,
2338 +
            elseArgs: &mut [],
2339 +
        });
2340 +
    }
2335 2341
    addPredecessor(self, thenBlock, currentBlock(self));
2336 2342
    addPredecessor(self, elseBlock, currentBlock(self));
2337 2343
}
2338 2344
2339 2345
/// Emit a compare-and-branch instruction with the given comparison op.
2340 -
unsafe fn emitBrCmp 'arena 'phase 'function (
2346 +
fn emitBrCmp 'arena 'phase 'function (
2341 2347
    self: &mut FnLowerer 'arena 'phase 'function,
2342 2348
    op: il::CmpOp,
2343 2349
    typ: il::Type,
2344 2350
    a: il::Val,
2345 2351
    b: il::Val,
2346 2352
    thenBlock: BlockId,
2347 2353
    elseBlock: BlockId
2348 2354
) throws (LowerError) where 'arena: 'phase, 'phase: 'function {
2349 2355
    assert thenBlock <> elseBlock;
2350 -
    emit(self, il::Instr::Br {
2351 -
        op, typ, a, b,
2352 -
        thenTarget: *thenBlock, thenArgs: &mut [],
2353 -
        elseTarget: *elseBlock, elseArgs: &mut [],
2354 -
    });
2356 +
    unsafe {
2357 +
        emit(self, il::Instr::Br {
2358 +
            op, typ, a, b,
2359 +
            thenTarget: *thenBlock, thenArgs: &mut [],
2360 +
            elseTarget: *elseBlock, elseArgs: &mut [],
2361 +
        });
2362 +
    }
2355 2363
    addPredecessor(self, thenBlock, currentBlock(self));
2356 2364
    addPredecessor(self, elseBlock, currentBlock(self));
2357 2365
}
2358 2366
2359 2367
/// Emit a guard that traps with `ebreak` when a comparison is false.
2360 -
unsafe fn emitTrapUnlessCmp 'arena 'phase 'function (
2368 +
fn emitTrapUnlessCmp 'arena 'phase 'function (
2361 2369
    self: &mut FnLowerer 'arena 'phase 'function,
2362 2370
    op: il::CmpOp,
2363 2371
    typ: il::Type,
2364 2372
    a: il::Val,
2365 2373
    b: il::Val
2395 2403
    }
2396 2404
    return aa <= bb;
2397 2405
}
2398 2406
2399 2407
/// Emit an `ebreak` when `a < b` holds.
2400 -
unsafe fn emitTrapIfLt 'arena 'phase 'function (
2408 +
fn emitTrapIfLt 'arena 'phase 'function (
2401 2409
    self: &mut FnLowerer 'arena 'phase 'function,
2402 2410
    typ: il::Type,
2403 2411
    a: il::Val,
2404 2412
    b: il::Val
2405 2413
) throws (LowerError) where 'arena: 'phase, 'phase: 'function {
2704 2712
2705 2713
/// Emit a match binding pattern.
2706 2714
/// Binding patterns always match for regular values, but for optionals they
2707 2715
/// check for the presence of a value. Jumps to `valuePresent` on success,
2708 2716
/// `valueAbsent` on failure.
2709 -
unsafe fn emitBindingTest 'arena 'phase 'function (
2717 +
fn emitBindingTest 'arena 'phase 'function (
2710 2718
    self: &mut FnLowerer 'arena 'phase 'function,
2711 2719
    subject: &MatchSubject,
2712 2720
    valuePresent: BlockId,
2713 2721
    valueAbsent: BlockId
2714 2722
) throws (LowerError) where 'arena: 'phase, 'phase: 'function {
2723 2731
        }
2724 2732
    }
2725 2733
}
2726 2734
2727 2735
/// Emit a jump to target if the current block hasn't terminated, then seal the target block.
2728 -
unsafe fn emitJmpAndSeal 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, target: BlockId) throws (LowerError) where 'arena: 'phase, 'phase: 'function {
2736 +
fn emitJmpAndSeal 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, target: BlockId) throws (LowerError) where 'arena: 'phase, 'phase: 'function {
2729 2737
    if not blockHasTerminator(&self.blockData[*currentBlock(self)].instrs[..]) {
2730 2738
        try emitJmp(self, target);
2731 2739
    }
2732 2740
    try sealBlock(self, target);
2733 2741
}
2762 2770
///         return 0;   // @else diverges, no jump to merge.
2763 2771
///     }
2764 2772
///
2765 2773
/// In the above example, the merge block stays `nil`, and no code is generated
2766 2774
/// after the `if`. The merge block is created on first use.
2767 -
unsafe fn emitMergeIfUnterminated 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, mergeBlock: &mut ?BlockId) throws (LowerError) where 'arena: 'phase, 'phase: 'function {
2775 +
fn emitMergeIfUnterminated 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, mergeBlock: &mut ?BlockId) throws (LowerError) where 'arena: 'phase, 'phase: 'function {
2768 2776
    if not blockHasTerminator(&self.blockData[*currentBlock(self)].instrs[..]) {
2769 2777
        if *mergeBlock == nil {
2770 2778
            set *mergeBlock = try createBlock(self, "merge");
2771 2779
        }
2772 2780
        let target = *mergeBlock else { throw LowerError::MissingTarget; };
5849 5857
    try switchToAndSeal(self, endBlock);
5850 5858
    exitLoop(self);
5851 5859
}
5852 5860
5853 5861
/// Emit an increment of a variable by `1`.
5854 -
unsafe fn emitIncrement 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, v: Var, typ: il::Type) throws (LowerError) where 'arena: 'phase, 'phase: 'function {
5862 +
fn emitIncrement 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, v: Var, typ: il::Type) throws (LowerError) where 'arena: 'phase, 'phase: 'function {
5855 5863
    let cur = try useVar(self, v);
5856 5864
    let next = nextReg(self);
5857 5865
5858 5866
    emit(self, il::Instr::BinOp { op: il::BinOp::Add, typ, dst: next, a: cur, b: il::Val::Imm(1) });
5859 5867
    defVar(self, v, il::Val::Reg(next));
5994 6002
    }
5995 6003
    exitVarScope(&mut self.vars, savedVarsLen);
5996 6004
}
5997 6005
5998 6006
/// Lower a break statement.
5999 -
unsafe fn lowerBreak 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function) throws (LowerError) where 'arena: 'phase, 'phase: 'function {
6007 +
fn lowerBreak 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function) throws (LowerError) where 'arena: 'phase, 'phase: 'function {
6000 6008
    let ctx = currentLoop(self) else {
6001 6009
        throw LowerError::OutsideOfLoop;
6002 6010
    };
6003 6011
    try emitJmp(self, ctx.breakTarget);
6004 6012
}
6005 6013
6006 6014
/// Lower a continue statement.
6007 -
unsafe fn lowerContinue 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function) throws (LowerError) where 'arena: 'phase, 'phase: 'function {
6015 +
fn lowerContinue 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function) throws (LowerError) where 'arena: 'phase, 'phase: 'function {
6008 6016
    let block = try getOrCreateContinueBlock(self);
6009 6017
    try emitJmp(self, block);
6010 6018
}
6011 6019
6012 6020
/// Emit a return, blitting into the caller's return buffer if needed.
6768 6776
/// Emit a byte-copy loop: `for i in 0..size { dst[i] = src[i]; }`.
6769 6777
///
6770 6778
/// Used when `blit` cannot be used because the copy size is dynamic.
6771 6779
/// Terminates the current block and leaves the builder positioned
6772 6780
/// after the loop.
6773 -
unsafe fn emitByteCopyLoop 'arena 'phase 'function (
6781 +
fn emitByteCopyLoop 'arena 'phase 'function (
6774 6782
    self: &mut FnLowerer 'arena 'phase 'function,
6775 6783
    dst: il::Reg,
6776 6784
    src: il::Reg,
6777 6785
    size: il::Val,
6778 6786
    label: *[u8]