Skip to content

Commit

Permalink
Split init tests and implementation for if-then-else DCE.
Browse files Browse the repository at this point in the history
Tests for select statement DCE, but not implementation yet.
---
Signed-off-by: Brandon Neth <[email protected]>
  • Loading branch information
brandon-neth committed Dec 4, 2023
1 parent a205c90 commit 907dfc0
Show file tree
Hide file tree
Showing 4 changed files with 278 additions and 8 deletions.
8 changes: 8 additions & 0 deletions frontend/lib/resolution/VarScopeVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,12 @@ void VarScopeVisitor::exitScope(const AstNode* ast, RV& rv) {
thenFrame->returnsOrThrows && elseFrame->returnsOrThrows) {
parentFrame->returnsOrThrows = true;
}
if (thenFrame && thenFrame->returnsOrThrows && thenFrame->isParamTrue) {
parentFrame->returnsOrThrows = true;
}
if (elseFrame && elseFrame->returnsOrThrows && elseFrame->isParamTrue) {
parentFrame->returnsOrThrows = true;
}
}
} else if (auto t = ast->toTry()) {
handleTry(t, rv);
Expand Down Expand Up @@ -502,10 +508,12 @@ bool VarScopeVisitor::enter(const Conditional* cond, RV& rv) {
if (condRE.type().isParamTrue()) {
// Don't need to process the false branch.
cond->thenBlock()->traverse(rv);
currentThenFrame()->isParamTrue = true;
return false;
} else if (condRE.type().isParamFalse()) {
if (auto elseBlock = cond->elseBlock()) {
elseBlock->traverse(rv);
currentElseFrame()->isParamTrue = true;
}
return false;
}
Expand Down
1 change: 1 addition & 0 deletions frontend/lib/resolution/VarScopeVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ struct VarFrame {
// has the block already encountered a return or a throw?
bool returnsOrThrows = false;

bool isParamTrue = false;
// When processing a conditional or catch blocks,
// instead of popping the SplitInitFrame for the then/else/catch blocks,
// store them here, for use in handleExitScope(Conditional or Try).
Expand Down
16 changes: 9 additions & 7 deletions frontend/lib/resolution/split-init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,8 @@ void FindSplitInits::handleConditional(const Conditional* cond, RV& rv) {
if (elseFrame->eligibleVars.count(id) > 0) {
// variable declared in this scope, so save the result
allSplitInitedVars.insert(id);
} else if (thenFrame->mentionedVars.count(id) == 0) {
} else if (thenFrame == nullptr ||
thenFrame->mentionedVars.count(id) == 0) {
// variable inited in 'else' and not mentioned in 'then'
locInitedVars.insert(id);
}
Expand All @@ -276,22 +277,23 @@ void FindSplitInits::handleConditional(const Conditional* cond, RV& rv) {
// split init is OK if:
// both then & else blocks initialize it before mentioning it
// one initializes it and the other returns
// one initializes and its statically known to be the only path
for (const auto& id : locInitedVars) {

bool thenInits = false;
if (thenFrame) {
thenInits = thenFrame->initedVars.count(id) > 0;
}
thenInits = thenFrame && thenFrame->initedVars.count(id) > 0;
bool elseInits = false;
if (elseFrame) {
elseInits = elseFrame->initedVars.count(id) > 0;
}
elseInits = elseFrame && elseFrame->initedVars.count(id) > 0;

if (thenInits && elseInits) {
locSplitInitedVars.insert(id);
} else if ((thenInits && elseReturnsThrows) ||
(thenReturnsThrows && elseInits)) {
// one branch returns or throws and the other inits
locSplitInitedVars.insert(id);
} else if ((thenInits && thenFrame && thenFrame->isParamTrue) ||
(elseInits && elseFrame && elseFrame->isParamTrue)) {
locSplitInitedVars.insert(id);
} else {
frame->mentionedVars.insert(id);
}
Expand Down
261 changes: 260 additions & 1 deletion frontend/test/resolution/testSplitInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1335,7 +1335,256 @@ static void test53() {
{});
}

static void test54() {
testSplitInit("test54",
R""""(
module M {
// this would be in the standard library...
operator =(ref lhs: int, rhs: int) {
__primitive("=", lhs, rhs);
}
proc test() {
var x;
if true then
return;
x = 11;
}
}
)"""",
{});
}

static void test55() {
testSplitInit("test55",
R""""(
module M {
// this would be in the standard library...
operator =(ref lhs: int, rhs: int) {
__primitive("=", lhs, rhs);
}
proc test() {
var x;
if false then
return;
x = 11;
}
}
)"""",
{"x"});
}

static void test56() {
testSplitInit("test56",
R""""(
module M {
// this would be in the standard library...
operator =(ref lhs: int, rhs: int) {
__primitive("=", lhs, rhs);
}
proc test() {
type T = int;
var x;
if T == int then
return;
x = 11;
}
}
)"""",
{});
}

static void test57() {
testSplitInit("test57",
R""""(
module M {
// this would be in the standard library...
operator =(ref lhs: int, rhs: int) {
__primitive("=", lhs, rhs);
}
proc test() {
var x;
if false then
return;
x = 11;
}
}
)"""",
{"x"});
}


static void test58() {
testSplitInit("test58",
R""""(
module M {
// this would be in the standard library...
operator =(ref lhs: int, rhs: int) {
__primitive("=", lhs, rhs);
}
proc test() {
var x;
if true then
x = 2;
else
var y = 0;
x = 3;
return;
}
}
)"""",
{"x"});
}

static void test59() {
testSplitInit("test59",
R""""(
module M {
// this would be in the standard library...
operator =(ref lhs: int, rhs: int) {
__primitive("=", lhs, rhs);
}
proc test() {
var x;
if false then
x = 2;
else
var y = 0;
x = 3;
return;
}
}
)"""",
{"x"});
}

static void test60() {
testSplitInit("test60",
R""""(
module M {
// this would be in the standard library...
operator =(ref lhs: int, rhs: int) {
__primitive("=", lhs, rhs);
}
config const cond: bool = true;
proc test() {
var x;
if cond then
x = 2;
else
var y = 0;
x = 3;
return;
}
}
)"""",
{});
}

static void test61() {
testSplitInit("test61",
R""""(
module M {
// this would be in the standard library...
operator =(ref lhs: int, rhs: int) {
__primitive("=", lhs, rhs);
}
config const cond: bool = true;
proc test() {
var x;
if false then
var y = 0;
else
x=2;
x = 3;
return;
}
}
)"""",
{"x"});
}
static void test62() {
testSplitInit("test62",
R""""(
module M {
// this would be in the standard library...
operator =(ref lhs: int, rhs: int) {
__primitive("=", lhs, rhs);
}
proc test() {
type T = int;
var x;
select T {
when int {
x = 11;
}
when real {
return;
}
}
}
}
)"""",
{"x"});
}

static void test63() {
testSplitInit("test63",
R""""(
module M {
// this would be in the standard library...
operator =(ref lhs: int, rhs: int) {
__primitive("=", lhs, rhs);
}
proc test() {
type T = real;
var x;
select T {
when int {
x = 11;
}
when real {
return;
}
}
}
}
)"""",
{});
}
static void test64() {
testSplitInit("test64",
R""""(
module M {
// this would be in the standard library...
operator =(ref lhs: int, rhs: int) {
__primitive("=", lhs, rhs);
}
proc test() {
type T = real;
var x;
select T {
when int {
x = 11;
}
when real {
writeln("");
}
}
x = 12;
}
}
)"""",
{"x"});
}
int main() {
test1();
test2();
Expand Down Expand Up @@ -1392,6 +1641,16 @@ int main() {
test51();
test52();
test53();

test54();
test55();
test56();
test57();
test58();
test59();
test60();
test61();
test62();
test63();
test64();
return 0;
}

0 comments on commit 907dfc0

Please sign in to comment.