}
PROGRAM_NEXT_INSTRUCTION
+ PROGRAM_CASE(FINAL_REPORT) {
+ updateSeqPoint(tctxt, end, from_mpv);
+ if (roseReport(t, scratch, end, ri->onmatch, ri->offset_adjust,
+ INVALID_EKEY) == HWLM_TERMINATE_MATCHING) {
+ return HWLM_TERMINATE_MATCHING;
+ }
+ /* One-shot specialisation: this instruction always terminates
+ * execution of the program. */
+ return HWLM_CONTINUE_MATCHING;
+ }
+ PROGRAM_NEXT_INSTRUCTION
+
PROGRAM_CASE(CHECK_EXHAUSTED) {
DEBUG_PRINTF("check ekey %u\n", ri->ekey);
assert(ri->ekey != INVALID_EKEY);
case ROSE_INSTR_REPORT_SOM: return &u.reportSom;
case ROSE_INSTR_REPORT_SOM_EXHAUST: return &u.reportSomExhaust;
case ROSE_INSTR_DEDUPE_AND_REPORT: return &u.dedupeAndReport;
+ case ROSE_INSTR_FINAL_REPORT: return &u.finalReport;
case ROSE_INSTR_CHECK_EXHAUSTED: return &u.checkExhausted;
case ROSE_INSTR_CHECK_MIN_LENGTH: return &u.checkMinLength;
case ROSE_INSTR_SET_STATE: return &u.setState;
case ROSE_INSTR_REPORT_SOM: return sizeof(u.reportSom);
case ROSE_INSTR_REPORT_SOM_EXHAUST: return sizeof(u.reportSomExhaust);
case ROSE_INSTR_DEDUPE_AND_REPORT: return sizeof(u.dedupeAndReport);
+ case ROSE_INSTR_FINAL_REPORT: return sizeof(u.finalReport);
case ROSE_INSTR_CHECK_EXHAUSTED: return sizeof(u.checkExhausted);
case ROSE_INSTR_CHECK_MIN_LENGTH: return sizeof(u.checkMinLength);
case ROSE_INSTR_SET_STATE: return sizeof(u.setState);
ROSE_STRUCT_REPORT_SOM reportSom;
ROSE_STRUCT_REPORT_SOM_EXHAUST reportSomExhaust;
ROSE_STRUCT_DEDUPE_AND_REPORT dedupeAndReport;
+ ROSE_STRUCT_FINAL_REPORT finalReport;
ROSE_STRUCT_CHECK_EXHAUSTED checkExhausted;
ROSE_STRUCT_CHECK_MIN_LENGTH checkMinLength;
ROSE_STRUCT_SET_STATE setState;
return out;
}
+static
+void applyFinalSpecialisation(vector<RoseInstruction> &program) {
+ assert(!program.empty());
+ assert(program.back().code() == ROSE_INSTR_END);
+ if (program.size() < 2) {
+ return;
+ }
+
+ /* Replace the second-to-last instruction (before END) with a one-shot
+ * specialisation if available. */
+ auto &ri = *(next(program.rbegin()));
+ switch (ri.code()) {
+ case ROSE_INSTR_REPORT: {
+ DEBUG_PRINTF("replacing REPORT with FINAL_REPORT\n");
+ auto ri2 = RoseInstruction(ROSE_INSTR_FINAL_REPORT);
+ ri2.u.finalReport.onmatch = ri.u.report.onmatch;
+ ri2.u.finalReport.offset_adjust = ri.u.report.offset_adjust;
+ ri = ri2;
+ break;
+ }
+ default:
+ break;
+ }
+}
+
static
void recordResources(RoseResources &resources,
const vector<RoseInstruction> &program) {
for (const auto &id : reports) {
makeReport(build, id, has_som, program);
}
- return writeProgram(bc, flattenProgram({program}));
+ program = flattenProgram({program});
+ applyFinalSpecialisation(program);
+ return writeProgram(bc, program);
}
static
program.insert(end(program), begin(root_program), end(root_program));
}
+ applyFinalSpecialisation(program);
return {writeProgram(bc, program), iter_offset};
}
makePushDelayedInstructions(build, final_id, program);
assert(!program.empty());
program = flattenProgram({program});
+ applyFinalSpecialisation(program);
return writeProgram(bc, program);
}
const bool has_som = false;
makeCatchupMpv(build, bc, id, program);
makeReport(build, id, has_som, program);
- programs[id] = writeProgram(bc, flattenProgram({program}));
+ program = flattenProgram({program});
+ applyFinalSpecialisation(program);
+ programs[id] = writeProgram(bc, program);
DEBUG_PRINTF("program for report %u @ %u (%zu instructions)\n", id,
programs.back(), program.size());
}
u32 iter_offset = addPredBlocks(bc, predProgramLists, program, true);
assert(program.size() > 1);
+ applyFinalSpecialisation(program);
return {writeProgram(bc, program), iter_offset};
}
/** \brief Super-instruction combining DEDUPE and REPORT. */
ROSE_INSTR_DEDUPE_AND_REPORT,
+ /**
+ * \brief Fire a report and stop program execution. This is a
+ * specialisation intended for short, frequently-executed programs.
+ */
+ ROSE_INSTR_FINAL_REPORT,
+
ROSE_INSTR_CHECK_EXHAUSTED, //!< Check if an ekey has already been set.
ROSE_INSTR_CHECK_MIN_LENGTH, //!< Check (EOM - SOM) against min length.
ROSE_INSTR_SET_STATE, //!< Switch a state index on.
u32 fail_jump; //!< Jump forward this many bytes on failure.
};
+struct ROSE_STRUCT_FINAL_REPORT {
+ u8 code; //!< From enum RoseInstructionCode.
+ ReportID onmatch; //!< Report ID to deliver to user.
+ s32 offset_adjust; //!< Offset adjustment to apply to end offset.
+};
+
struct ROSE_STRUCT_CHECK_EXHAUSTED {
u8 code; //!< From enum RoseInstructionCode.
u32 ekey; //!< Exhaustion key to check.