ir: new pass iteration strategy

Before:
 * IR basic blocks are in arbitrary order
 * when doing an IR pass, when a block is encountered, code
   must look at all the instructions in the old basic block,
   determine what blocks are referenced, and queue up those
   old basic blocks first.
 * This had a bug (See #667)

Now:
 * IR basic blocks are required to be in an order that guarantees
   they will be referenced by a branch, before any instructions
   within are referenced.
   ir pass1 is updated to meet this constraint.
 * When doing an IR pass, we iterate over old basic blocks
   in the order they appear. Blocks which have not been
   referenced are discarded.
 * After the pass is complete, we must iterate again to look
   for old basic blocks which now point to incomplete new
   basic blocks, due to comptime code generation.
 * This last part can probably be optimized - most of the time
   we don't need to iterate over the basic block again.

closes #667
This commit is contained in:
Andrew Kelley 2018-01-02 20:52:24 -05:00
parent aafb832288
commit 0ea50b3157
5 changed files with 252 additions and 1207 deletions

1428
src/ir.cpp

File diff suppressed because it is too large Load Diff

View File

@ -39,7 +39,6 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)->%void,
switch (state) {
State.Start => switch (c) {
'{' => {
// TODO if you make this an if statement with `and` then it breaks
if (start_index < i) {
%return output(context, fmt[start_index..i]);
}

View File

@ -39,7 +39,7 @@ fn acos32(x: f32) -> f32 {
if (hx >> 31 != 0) {
return 2.0 * pio2_hi + 0x1.0p-120;
} else {
return 0;
return 0.0;
}
} else {
return math.nan(f32);

View File

@ -230,20 +230,21 @@ fn foo(args: ...) {
test "peer type resolution: error and [N]T" {
assert(mem.eql(u8, %%testPeerErrorAndArray(0), "OK"));
comptime assert(mem.eql(u8, %%testPeerErrorAndArray(0), "OK"));
// TODO: implicit %T to %U where T can implicitly cast to U
//assert(mem.eql(u8, %%testPeerErrorAndArray(0), "OK"));
//comptime assert(mem.eql(u8, %%testPeerErrorAndArray(0), "OK"));
assert(mem.eql(u8, %%testPeerErrorAndArray2(1), "OKK"));
comptime assert(mem.eql(u8, %%testPeerErrorAndArray2(1), "OKK"));
}
error BadValue;
fn testPeerErrorAndArray(x: u8) -> %[]const u8 {
return switch (x) {
0x00 => "OK",
else => error.BadValue,
};
}
//fn testPeerErrorAndArray(x: u8) -> %[]const u8 {
// return switch (x) {
// 0x00 => "OK",
// else => error.BadValue,
// };
//}
fn testPeerErrorAndArray2(x: u8) -> %[]const u8 {
return switch (x) {
0x00 => "OK",

View File

@ -560,3 +560,14 @@ fn hereIsAnOpaqueType(ptr: &OpaqueA) -> &OpaqueA {
var a = ptr;
return a;
}
test "comptime if inside runtime while which unconditionally breaks" {
testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true);
comptime testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true);
}
fn testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(cond: bool) {
while (cond) {
if (false) { }
break;
}
}