Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Miscellaneous fixes #294

Merged
merged 8 commits into from
Sep 12, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- uses: denoland/setup-deno@v1
with:
Expand All @@ -37,7 +37,7 @@ jobs:

- name: Install Turnt
# run: pip install turnt # Use instead if pip turnt version >= 1.7
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
repository: cucapra/turnt
path: './turnt'
Expand All @@ -53,7 +53,7 @@ jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- uses: denoland/setup-deno@v1
with:
Expand Down Expand Up @@ -81,7 +81,7 @@ jobs:
style:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: TrueBrain/actions-flake8@master
with:
path: bril-txt
2 changes: 1 addition & 1 deletion .github/workflows/docs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup mdBook
uses: peaceiris/actions-mdbook@v1
with:
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/rust.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
- "cd brilift && cargo build --release && make rt.o && make test TURNTARGS=-v"
- "cd brilift && cargo build --release && make rt.o && make benchmark TURNTARGS=-v"
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@v1
with:
toolchain: stable
Expand All @@ -60,7 +60,7 @@ jobs:

- name: Install Turnt
# run: pip install turnt # Use instead if pip turnt version >= 1.7
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
repository: cucapra/turnt
path: './turnt'
Expand All @@ -82,7 +82,7 @@ jobs:
matrix:
path: ["brilirs/Cargo.toml", "bril-rs/Cargo.toml", "bril-rs/bril2json/Cargo.toml", "bril-rs/brild/Cargo.toml", "brilift/Cargo.toml", "bril-rs/rs2bril/Cargo.toml", "bril-rs/brillvm/Cargo.toml"]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@v1
with:
toolchain: stable
Expand Down
2 changes: 0 additions & 2 deletions benchmarks/core/bitshift.bril
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
.then.0:
v4: int = id x;
ret v4;
jmp .endif.0;
.else.0:
v5: int = id x;
v6: int = id n;
Expand Down Expand Up @@ -37,7 +36,6 @@
.endif.12:
v22: int = id ans;
ret v22;
.endif.0:
}
@mod(a: int, b: int): int {
v0: int = id a;
Expand Down
2 changes: 0 additions & 2 deletions benchmarks/core/fact.bril
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
.then.0:
v4: int = const 1;
ret v4;
jmp .endif.0;
.else.0:
v5: int = id a;
v6: int = id a;
Expand All @@ -25,5 +24,4 @@
v9: int = call @fact v8;
v10: int = mul v5 v9;
ret v10;
.endif.0:
}
6 changes: 2 additions & 4 deletions benchmarks/core/mod_inv.bril
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# ARGS: 46, 10007
# ARGS: 46 10007
@main(n: int, p: int) {
v0: int = const 2;
two: int = id v0;
Expand Down Expand Up @@ -81,10 +81,8 @@
# }
# console.log(ans);
# }
#
#
# function mod(n: bigint, p: bigint): bigint {
# return n - n / p * p;
# }
#


9 changes: 7 additions & 2 deletions bril-rs/bril2json/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,17 +82,22 @@ impl Lines {
self.new_lines
.iter()
.enumerate()
//(i+1) because line numbers start at 1
.map(|(i, j)| (i + 1, j))
.fold(
ColRow {
col: index as u64,
// (index + 1) because column numbers start at 1
col: (index + 1) as u64,
// Hard code the first row to be 1
row: 1,
},
|current, (line_num, idx)| {
if *idx < index {
ColRow {
// (line_num + 1) because line numbers start at 1
row: (line_num + 1) as u64,
col: (index - idx) as u64,
// column values are kept relative to the previous index
col: ((index) - idx) as u64,
}
} else {
current
Expand Down
28 changes: 27 additions & 1 deletion bril-ts/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export class Builder {
return this.buildEffect("call", args, [func], undefined);
}
}

/**
* Build a constant instruction. As above, the destination name is optional.
*/
Expand Down Expand Up @@ -124,6 +124,32 @@ export class Builder {
this.curFunction.instrs.push(instr);
}

/**
* Checks whether the last emitted instruction in the current function is the specified op code.
* Useful for checking for terminating instructions.
*/
isLastEmittedEffectOp(op: bril.EffectOpCode): boolean {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like useful behavior! But the name is a little odd, in two ways:

  • Emitted: Maybe it would be a little more straightforward to just say it's the last op currently in the function? It seems less material that it's the last thing we emitted.
  • Effect: I think this would look for both effect and value ops, right?

Another alternative, FWIW, would be to just get the last (non-label) instruction. So the return type would be bril.Instruction?, and callers could get this behavior by doing stuff like lastInstr()?.op === "add".

Copy link
Contributor Author

@Pat-Lafon Pat-Lafon Sep 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, works for me.

I'll just note that I don't think the the ? sugar works on return types? microsoft/TypeScript#51332 Maybe I missed something obvious.

Instead I'm using bril.Instruction | undefined which the rest of the code base seems to do.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops; you're absolutely right. I forgot that T? was a special argument thing rather than an actual type.

if (!this.curFunction) {
return false
}

if (!this.curFunction.instrs) {
return false
}

if (this.curFunction.instrs.length === 0) {
return false
}

const last_instr : bril.Instruction | bril.Label = this.curFunction.instrs[this.curFunction.instrs.length - 1];

if ('label' in last_instr) {
return false
}

return last_instr.op === op
}

/**
* Generate an unused variable name.
*/
Expand Down
12 changes: 9 additions & 3 deletions brili.ts
Original file line number Diff line number Diff line change
Expand Up @@ -764,7 +764,7 @@ function evalInstr(instr: bril.Instruction, state: State): Action {
let i = getInt(instr, state.env, 0);
if (i > 1114111 || i < 0 || (55295 < i && i < 57344)) {
throw error(`value ${i} cannot be converted to char`);
}
}
let val = String.fromCodePoint(Number(i));
state.env.set(instr.dest, val);
return NEXT;
Expand Down Expand Up @@ -873,7 +873,12 @@ function parseBool(s: string): boolean {

function parseNumber(s: string): number {
let f = parseFloat(s);
if (!isNaN(f)) {
// parseFloat and Number have subtly different behaviors for parsing strings
// parseFloat ignores all random garbage after any valid number
// Number accepts empty/whitespace only strings and rejects numbers with seperators
// Use both and only accept the intersection of the results?
let f2 = Number(s);
if (!isNaN(f) && f === f2) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weird but true! It'll do.

return f;
} else {
throw error(`float argument to main must not be 'NaN'; got ${s}`);
Expand All @@ -891,7 +896,8 @@ function parseMainArguments(expected: bril.Argument[], args: string[]) : Env {
let type = expected[i].type;
switch (type) {
case "int":
let n: bigint = BigInt(parseInt(args[i]));
// https://dev.to/darkmavis1980/you-should-stop-using-parseint-nbf
let n: bigint = BigInt(Number(args[i]));
newEnv.set(expected[i].name, n as Value);
break;
case "float":
Expand Down
5 changes: 5 additions & 0 deletions brilirs/src/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,11 @@ fn type_check_instruction<'a>(
}

fn type_check_func(bbfunc: &BBFunction, bbprog: &BBProgram) -> Result<(), PositionalInterpError> {
if bbfunc.name == "main" && bbfunc.return_type.is_some() {
return Err(InterpError::NonEmptyRetForFunc(bbfunc.name.clone()))
.map_err(|e| e.add_pos(bbfunc.pos.clone()));
}

let mut env: FxHashMap<&str, &Type> =
FxHashMap::with_capacity_and_hasher(20, fxhash::FxBuildHasher::default());
bbfunc.args.iter().for_each(|a| {
Expand Down
5 changes: 0 additions & 5 deletions brilirs/src/interp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -796,11 +796,6 @@ pub fn execute_main<T: std::io::Write, U: std::io::Write>(
.map(|i| prog.get(i).unwrap())
.ok_or(InterpError::NoMainFunction)?;

if main_func.return_type.is_some() {
return Err(InterpError::NonEmptyRetForFunc(main_func.name.clone()))
.map_err(|e| e.add_pos(main_func.pos.clone()));
}

let mut env = Environment::new(main_func.num_of_vars);
let heap = Heap::default();

Expand Down
2 changes: 0 additions & 2 deletions test/ts/factorial.out
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@
.then.0:
v4: int = const 1;
ret v4;
jmp .endif.0;
.else.0:
.endif.0:
v5: int = id x;
v6: int = id x;
v7: int = const 1;
Expand Down
13 changes: 13 additions & 0 deletions test/ts/simplified.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
@main {
v0: int = const 1;
call @erronious v0;
v1: int = const 0;
}
@erronious(x: int): int {
v1: bool = const true;
br v1 .then.0 .else.0;
.then.0:
v2: int = id x;
ret v2;
.else.0:
}
8 changes: 8 additions & 0 deletions test/ts/simplified.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
erronious(1n);

// This snippet checks that the ts compiler doesn't try to create an unreachable else branch
function erronious(x: bigint): bigint {
if (true) {
return x;
}
}
24 changes: 15 additions & 9 deletions ts2bril.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,20 +145,20 @@ function emitBril(prog: ts.Node, checker: ts.TypeChecker): bril.Program {

// Check if effect statement, i.e., a call that is not a subexpression
if (call.parent.kind === ts.SyntaxKind.ExpressionStatement) {
builder.buildCall(callText,
builder.buildCall(callText,
values.map(v => v.dest));
return builder.buildInt(0); // Expressions must produce values
} else {
let decl = call.parent as ts.VariableDeclaration;
let type = brilType(decl, checker);
let name = (decl.name != undefined) ? decl.name.getText() : undefined;
return builder.buildCall(
callText,
values.map(v => v.dest),
type,
callText,
values.map(v => v.dest),
type,
name,
);
}
}
}
default:
throw `unsupported expression kind: ${expr.getText()}`;
Expand Down Expand Up @@ -215,12 +215,18 @@ function emitBril(prog: ts.Node, checker: ts.TypeChecker): bril.Program {
// Statement chunks.
builder.buildLabel(thenLab);
emit(if_.thenStatement);
builder.buildEffect("jmp", [], undefined, [endLab]);
const then_branch_terminated = builder.isLastEmittedEffectOp("ret");
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A little tricky, but makes sense!

if (!then_branch_terminated) {
builder.buildEffect("jmp", [], undefined, [endLab]);
}
builder.buildLabel(elseLab);
if (if_.elseStatement) {
emit(if_.elseStatement);
}
builder.buildLabel(endLab);
// The else branch otherwise just falls through without needing a target label
if (!then_branch_terminated) {
builder.buildLabel(endLab);
}

break;
}
Expand Down Expand Up @@ -258,7 +264,7 @@ function emitBril(prog: ts.Node, checker: ts.TypeChecker): bril.Program {
break;
}

case ts.SyntaxKind.FunctionDeclaration:
case ts.SyntaxKind.FunctionDeclaration:
let funcDef = node as ts.FunctionDeclaration;
if (funcDef.name === undefined) {
throw `no anonymous functions!`;
Expand Down Expand Up @@ -298,7 +304,7 @@ function emitBril(prog: ts.Node, checker: ts.TypeChecker): bril.Program {

case ts.SyntaxKind.ImportDeclaration:
break;

default:
throw `unhandled TypeScript AST node kind ${ts.SyntaxKind[node.kind]}`;
}
Expand Down