C++/C#: Use cached to ensure that IR is evaluated in a single stage

Before this change, evaluation of the IR was spread out across about 5 stages. This resulted in a lot of redundant evaluation, especially tuple numbering of large IPA types like `TInstruction`. This change makes two small changes that, when combined, ensure that the IR is evaluated all in one stage:

First, we mark `TInstruction` as `cached`. This collapses all of the work to create instructions, across all three IR phases, into a single phase.

Second, we make the `SSA` module in `SSAConstruction.qll` just contain aliases to `cached` predicates defined in the `Cached` module. This ensures that all of the `Operand`-related SSA computation happens in the same stage as all of the `Instruction`-related SSA computation.
This commit is contained in:
Dave Bartolomeo
2020-06-05 14:05:25 -04:00
parent cb2370cc7d
commit 11818489f5
5 changed files with 92 additions and 71 deletions

View File

@@ -16,6 +16,31 @@ import Cached
cached
private module Cached {
cached
predicate hasPhiInstructionCached(
IRFunction irFunc, OldInstruction blockStartInstr, Alias::MemoryLocation defLocation
) {
exists(OldBlock oldBlock |
definitionHasPhiNode(defLocation, oldBlock) and
irFunc = oldBlock.getEnclosingIRFunction() and
blockStartInstr = oldBlock.getFirstInstruction()
)
}
cached
predicate hasChiInstructionCached(IRFunctionBase irFunc, OldInstruction primaryInstruction) {
hasChiNode(_, primaryInstruction) and
irFunc = primaryInstruction.getEnclosingIRFunction()
}
cached
predicate hasUnreachedInstructionCached(IRFunction irFunc) {
exists(OldInstruction oldInstruction |
irFunc = oldInstruction.getEnclosingIRFunction() and
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
)
}
class TStageInstruction =
TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction;
@@ -876,33 +901,15 @@ module SSAConsistency {
/**
* Provides the portion of the parameterized IR interface that is used to construct the SSA stages
* of the IR. The raw stage of the IR does not expose these predicates.
* These predicates are all just aliases for predicates defined in the `Cached` module. This ensures
* that all of SSA construction will be evaluated in the same stage.
*/
cached
module SSA {
class MemoryLocation = Alias::MemoryLocation;
cached
predicate hasPhiInstruction(
IRFunction irFunc, OldInstruction blockStartInstr, Alias::MemoryLocation defLocation
) {
exists(OldBlock oldBlock |
definitionHasPhiNode(defLocation, oldBlock) and
irFunc = oldBlock.getEnclosingIRFunction() and
blockStartInstr = oldBlock.getFirstInstruction()
)
}
predicate hasPhiInstruction = Cached::hasPhiInstructionCached/3;
cached
predicate hasChiInstruction(IRFunctionBase irFunc, OldInstruction primaryInstruction) {
hasChiNode(_, primaryInstruction) and
irFunc = primaryInstruction.getEnclosingIRFunction()
}
predicate hasChiInstruction = Cached::hasChiInstructionCached/2;
cached
predicate hasUnreachedInstruction(IRFunction irFunc) {
exists(OldInstruction oldInstruction |
irFunc = oldInstruction.getEnclosingIRFunction() and
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
)
}
predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1;
}

View File

@@ -12,7 +12,7 @@ private import Imports::Opcode
* all of the branches that can appear in that particular stage. The public `Instruction` class for
* each phase extends the `TStageInstruction` type for that stage.
*/
newtype TInstruction =
cached newtype TInstruction =
TRawInstruction(
IRFunctionBase irFunc, Opcode opcode, Language::AST ast,
IRConstruction::Raw::InstructionTag1 tag1, IRConstruction::Raw::InstructionTag2 tag2

View File

@@ -16,6 +16,31 @@ import Cached
cached
private module Cached {
cached
predicate hasPhiInstructionCached(
IRFunction irFunc, OldInstruction blockStartInstr, Alias::MemoryLocation defLocation
) {
exists(OldBlock oldBlock |
definitionHasPhiNode(defLocation, oldBlock) and
irFunc = oldBlock.getEnclosingIRFunction() and
blockStartInstr = oldBlock.getFirstInstruction()
)
}
cached
predicate hasChiInstructionCached(IRFunctionBase irFunc, OldInstruction primaryInstruction) {
hasChiNode(_, primaryInstruction) and
irFunc = primaryInstruction.getEnclosingIRFunction()
}
cached
predicate hasUnreachedInstructionCached(IRFunction irFunc) {
exists(OldInstruction oldInstruction |
irFunc = oldInstruction.getEnclosingIRFunction() and
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
)
}
class TStageInstruction =
TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction;
@@ -876,33 +901,15 @@ module SSAConsistency {
/**
* Provides the portion of the parameterized IR interface that is used to construct the SSA stages
* of the IR. The raw stage of the IR does not expose these predicates.
* These predicates are all just aliases for predicates defined in the `Cached` module. This ensures
* that all of SSA construction will be evaluated in the same stage.
*/
cached
module SSA {
class MemoryLocation = Alias::MemoryLocation;
cached
predicate hasPhiInstruction(
IRFunction irFunc, OldInstruction blockStartInstr, Alias::MemoryLocation defLocation
) {
exists(OldBlock oldBlock |
definitionHasPhiNode(defLocation, oldBlock) and
irFunc = oldBlock.getEnclosingIRFunction() and
blockStartInstr = oldBlock.getFirstInstruction()
)
}
predicate hasPhiInstruction = Cached::hasPhiInstructionCached/3;
cached
predicate hasChiInstruction(IRFunctionBase irFunc, OldInstruction primaryInstruction) {
hasChiNode(_, primaryInstruction) and
irFunc = primaryInstruction.getEnclosingIRFunction()
}
predicate hasChiInstruction = Cached::hasChiInstructionCached/2;
cached
predicate hasUnreachedInstruction(IRFunction irFunc) {
exists(OldInstruction oldInstruction |
irFunc = oldInstruction.getEnclosingIRFunction() and
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
)
}
predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1;
}