rose: fix CHECK_NOT_HANDLED placement bug

The CHECK_NOT_HANDLED instruction was being inserted into an already
partially-flattened program, which would result in jump offsets becoming
incorrect.

This change places it as part of the normal flow of program
construction, which avoids this issue.
This commit is contained in:
Justin Viiret 2016-05-27 10:40:06 +10:00 committed by Matthew Barr
parent 89bc2b4b39
commit 9826522e34

View File

@ -3019,6 +3019,25 @@ void makeRoleCheckBounds(const RoseBuildImpl &build, RoseVertex v,
program.insert(it, ri);
}
static
void makeRoleCheckNotHandled(build_context &bc, RoseVertex v,
vector<RoseInstruction> &program) {
auto ri = RoseInstruction(ROSE_INSTR_CHECK_NOT_HANDLED,
JumpTarget::NEXT_BLOCK);
u32 handled_key;
if (contains(bc.handledKeys, v)) {
handled_key = bc.handledKeys.at(v);
} else {
handled_key = verify_u32(bc.handledKeys.size());
bc.handledKeys.emplace(v, handled_key);
}
ri.u.checkNotHandled.key = handled_key;
program.push_back(move(ri));
}
static
vector<RoseInstruction> makeProgram(RoseBuildImpl &build, build_context &bc,
const RoseEdge &e) {
@ -3042,6 +3061,13 @@ vector<RoseInstruction> makeProgram(RoseBuildImpl &build, build_context &bc,
makeRoleCheckBounds(build, v, e, program);
}
// This program may be triggered by different predecessors, with different
// offset bounds. We must ensure we put this check/set operation after the
// bounds check to deal with this case.
if (hasGreaterInDegree(1, v, g)) {
makeRoleCheckNotHandled(bc, v, program);
}
makeRoleLookaround(build, bc, v, program);
makeRoleCheckLeftfix(build, bc, v, program);
@ -3228,48 +3254,6 @@ void buildLeftInfoTable(const RoseBuildImpl &tbi, build_context &bc,
*laggedRoseCount = lagIndex;
}
static
void makeRoleCheckNotHandled(build_context &bc, RoseVertex v,
vector<RoseInstruction> &program) {
auto ri = RoseInstruction(ROSE_INSTR_CHECK_NOT_HANDLED,
JumpTarget::NEXT_BLOCK);
u32 handled_key;
if (contains(bc.handledKeys, v)) {
handled_key = bc.handledKeys.at(v);
} else {
handled_key = verify_u32(bc.handledKeys.size());
bc.handledKeys.emplace(v, handled_key);
}
ri.u.checkNotHandled.key = handled_key;
// This program may be triggered by different predecessors, with different
// offset bounds. We must ensure we put this check/set operation after the
// bounds check to deal with this case.
auto it =
find_if(begin(program), end(program), [](const RoseInstruction &ri) {
return ri.code() > ROSE_INSTR_CHECK_BOUNDS;
});
program.insert(it, ri);
}
static
vector<RoseInstruction> makePredProgram(RoseBuildImpl &build, build_context &bc,
const RoseEdge &e) {
const RoseGraph &g = build.g;
const RoseVertex v = target(e, g);
auto program = makeProgram(build, bc, e);
if (hasGreaterInDegree(1, v, g)) {
// Only necessary when there is more than one pred.
makeRoleCheckNotHandled(bc, v, program);
}
return program;
}
static
u32 addPredBlocksSingle(
map<u32, vector<vector<RoseInstruction>>> &predProgramLists,
@ -3642,7 +3626,7 @@ u32 buildLiteralProgram(RoseBuildImpl &build, build_context &bc, u32 final_id,
g[target(e, g)].idx);
assert(contains(bc.roleStateIndices, u));
u32 pred_state = bc.roleStateIndices.at(u);
auto program = makePredProgram(build, bc, e);
auto program = makeProgram(build, bc, e);
predProgramLists[pred_state].push_back(program);
}