mirror of
https://github.com/github/codeql.git
synced 2025-12-24 04:36:35 +01:00
C++: Share TInstruction across IR stages
Each stage of the IR reuses the majority of the instructions from previous stages. Previously, we've been wrapping each reused old instruction in a branch of the `TInstruction` type for the next stage. This causes use to create roughly three times as many `TInstruction` objects as we actually need. Now that IPA union types are supported in the compiler, we can share a single `TInstruction` IPA type across stages. We create a single `TInstruction` IPA type, with individual branches of this type for instructions created directly from the AST (`TRawInstruction`) and for instructions added by each stage of SSA construction (`T*PhiInstruction`, `T*ChiInstruction`, `T*UnreachedInstruction`). Each stage then defines a `TStageInstruction` type that is a union of 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. The interface that each stage exposes to the pyrameterized modules in the IR is now split into three pieces: - The `Raw` module, exposed only by the original IR construction stage. This module identifies which functions have IR, which `TRawInstruction`s exist, and which `IRVariable`s exist. - The `SSA` module, exposed only by the two SSA construction stages. This identifiers which `Phi`, `Chi`, and `Unreached` instructions exist. - The global module, exposed by all three stages. This module has all of the predicates whose implementation is different for each stage, like gathering definitions of `MemoryOperand`s. Similarly, there is now a single `TIRFunction` IPA type that is shared across all three stages. There is a single `IRFunctionBase` class that exposes the stage-indepdendent predicates; the `IRFunction` class for each stage extends `IRFunctionBase`. Most of the other changes are largely mechanical.
This commit is contained in:
@@ -177,6 +177,11 @@
|
|||||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll",
|
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll",
|
||||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRBlockImports.qll"
|
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRBlockImports.qll"
|
||||||
],
|
],
|
||||||
|
"C++ IR IRFunctionImports": [
|
||||||
|
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRFunctionImports.qll",
|
||||||
|
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll",
|
||||||
|
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRFunctionImports.qll"
|
||||||
|
],
|
||||||
"C++ IR IRVariableImports": [
|
"C++ IR IRVariableImports": [
|
||||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRVariableImports.qll",
|
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRVariableImports.qll",
|
||||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll",
|
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll",
|
||||||
|
|||||||
@@ -1,29 +1,12 @@
|
|||||||
private import internal.IRInternal
|
private import internal.IRInternal
|
||||||
|
private import internal.IRFunctionImports as Imports
|
||||||
|
import Imports::IRFunctionBase
|
||||||
import Instruction
|
import Instruction
|
||||||
|
|
||||||
private newtype TIRFunction =
|
|
||||||
MkIRFunction(Language::Function func) { Construction::functionHasIR(func) }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the IR for a function.
|
* The IR for a function.
|
||||||
*/
|
*/
|
||||||
class IRFunction extends TIRFunction {
|
class IRFunction extends IRFunctionBase {
|
||||||
Language::Function func;
|
|
||||||
|
|
||||||
IRFunction() { this = MkIRFunction(func) }
|
|
||||||
|
|
||||||
final string toString() { result = "IR: " + func.toString() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the function whose IR is represented.
|
|
||||||
*/
|
|
||||||
final Language::Function getFunction() { result = func }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the location of the function.
|
|
||||||
*/
|
|
||||||
final Language::Location getLocation() { result = func.getLocation() }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the entry point for this function.
|
* Gets the entry point for this function.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -29,7 +29,13 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil
|
|||||||
/**
|
/**
|
||||||
* Represents a single operation in the IR.
|
* Represents a single operation in the IR.
|
||||||
*/
|
*/
|
||||||
class Instruction extends Construction::TInstruction {
|
class Instruction extends Construction::TStageInstruction {
|
||||||
|
Instruction() {
|
||||||
|
// The base `TStageInstruction` type is a superset of the actual instructions appearing in this
|
||||||
|
// stage. This call lets the stage filter out the ones that are not reused from raw IR.
|
||||||
|
Construction::hasInstruction(this)
|
||||||
|
}
|
||||||
|
|
||||||
final string toString() { result = getOpcode().toString() + ": " + getAST().toString() }
|
final string toString() { result = getOpcode().toString() + ": " + getAST().toString() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -250,7 +256,7 @@ class Instruction extends Construction::TInstruction {
|
|||||||
* result of the `Load` instruction is a prvalue of type `int`, representing
|
* result of the `Load` instruction is a prvalue of type `int`, representing
|
||||||
* the integer value loaded from variable `x`.
|
* the integer value loaded from variable `x`.
|
||||||
*/
|
*/
|
||||||
final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) }
|
final predicate isGLValue() { getResultLanguageType().hasType(_, true) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the size of the result produced by this instruction, in bytes. If the
|
* Gets the size of the result produced by this instruction, in bytes. If the
|
||||||
@@ -259,7 +265,7 @@ class Instruction extends Construction::TInstruction {
|
|||||||
* If `this.isGLValue()` holds for this instruction, the value of
|
* If `this.isGLValue()` holds for this instruction, the value of
|
||||||
* `getResultSize()` will always be the size of a pointer.
|
* `getResultSize()` will always be the size of a pointer.
|
||||||
*/
|
*/
|
||||||
final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() }
|
final int getResultSize() { result = getResultLanguageType().getByteSize() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the opcode that specifies the operation performed by this instruction.
|
* Gets the opcode that specifies the operation performed by this instruction.
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
import semmle.code.cpp.ir.implementation.internal.IRFunctionBase as IRFunctionBase
|
||||||
@@ -1,5 +1,11 @@
|
|||||||
import SSAConstructionInternal
|
import SSAConstructionInternal
|
||||||
private import SSAConstructionImports
|
private import SSAConstructionImports as Imports
|
||||||
|
private import Imports::Opcode
|
||||||
|
private import Imports::OperandTag
|
||||||
|
private import Imports::Overlap
|
||||||
|
private import Imports::TInstruction
|
||||||
|
private import Imports::RawIR as RawIR
|
||||||
|
private import SSAInstructions
|
||||||
private import NewIR
|
private import NewIR
|
||||||
|
|
||||||
private class OldBlock = Reachability::ReachableBlock;
|
private class OldBlock = Reachability::ReachableBlock;
|
||||||
@@ -10,54 +16,35 @@ import Cached
|
|||||||
|
|
||||||
cached
|
cached
|
||||||
private module Cached {
|
private module Cached {
|
||||||
|
class TStageInstruction =
|
||||||
|
TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction;
|
||||||
|
|
||||||
|
private TRawInstruction rawInstruction(
|
||||||
|
IRFunctionBase irFunc, Opcode opcode, Language::AST ast, Language::LanguageType resultType
|
||||||
|
) {
|
||||||
|
result = TRawInstruction(irFunc, opcode, ast, resultType, _, _) and
|
||||||
|
result instanceof OldInstruction
|
||||||
|
}
|
||||||
|
|
||||||
|
cached
|
||||||
|
predicate hasInstruction(TStageInstruction instr) {
|
||||||
|
instr instanceof TRawInstruction and instr instanceof OldInstruction
|
||||||
|
or
|
||||||
|
not instr instanceof TRawInstruction
|
||||||
|
}
|
||||||
|
|
||||||
private IRBlock getNewBlock(OldBlock oldBlock) {
|
private IRBlock getNewBlock(OldBlock oldBlock) {
|
||||||
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
|
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
predicate functionHasIR(Language::Function func) {
|
OldInstruction getOldInstruction(Instruction instr) { instr = result }
|
||||||
exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func)
|
|
||||||
}
|
|
||||||
|
|
||||||
cached
|
|
||||||
OldInstruction getOldInstruction(Instruction instr) { instr = WrappedInstruction(result) }
|
|
||||||
|
|
||||||
private IRVariable getNewIRVariable(OldIR::IRVariable var) {
|
private IRVariable getNewIRVariable(OldIR::IRVariable var) {
|
||||||
// This is just a type cast. Both classes derive from the same newtype.
|
// This is just a type cast. Both classes derive from the same newtype.
|
||||||
result = var
|
result = var
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
|
||||||
newtype TInstruction =
|
|
||||||
WrappedInstruction(OldInstruction oldInstruction) {
|
|
||||||
not oldInstruction instanceof OldIR::PhiInstruction
|
|
||||||
} or
|
|
||||||
Phi(OldBlock block, Alias::MemoryLocation defLocation) {
|
|
||||||
definitionHasPhiNode(defLocation, block)
|
|
||||||
} or
|
|
||||||
Chi(OldInstruction oldInstruction) {
|
|
||||||
not oldInstruction instanceof OldIR::PhiInstruction and
|
|
||||||
hasChiNode(_, oldInstruction)
|
|
||||||
} or
|
|
||||||
Unreached(Language::Function function) {
|
|
||||||
exists(OldInstruction oldInstruction |
|
|
||||||
function = oldInstruction.getEnclosingFunction() and
|
|
||||||
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
cached
|
|
||||||
predicate hasTempVariable(
|
|
||||||
Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type
|
|
||||||
) {
|
|
||||||
exists(OldIR::IRTempVariable var |
|
|
||||||
var.getEnclosingFunction() = func and
|
|
||||||
var.getAST() = ast and
|
|
||||||
var.getTag() = tag and
|
|
||||||
var.getLanguageType() = type
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
cached
|
cached
|
||||||
predicate hasModeledMemoryResult(Instruction instruction) {
|
predicate hasModeledMemoryResult(Instruction instruction) {
|
||||||
exists(Alias::getResultMemoryLocation(getOldInstruction(instruction))) or
|
exists(Alias::getResultMemoryLocation(getOldInstruction(instruction))) or
|
||||||
@@ -73,7 +60,7 @@ private module Cached {
|
|||||||
or
|
or
|
||||||
// Chi instructions track virtual variables, and therefore a chi instruction is
|
// Chi instructions track virtual variables, and therefore a chi instruction is
|
||||||
// conflated if it's associated with the aliased virtual variable.
|
// conflated if it's associated with the aliased virtual variable.
|
||||||
exists(OldInstruction oldInstruction | instruction = Chi(oldInstruction) |
|
exists(OldInstruction oldInstruction | instruction = getChi(oldInstruction) |
|
||||||
Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof
|
Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof
|
||||||
Alias::AliasedVirtualVariable
|
Alias::AliasedVirtualVariable
|
||||||
)
|
)
|
||||||
@@ -81,7 +68,7 @@ private module Cached {
|
|||||||
// Phi instructions track locations, and therefore a phi instruction is
|
// Phi instructions track locations, and therefore a phi instruction is
|
||||||
// conflated if it's associated with a conflated location.
|
// conflated if it's associated with a conflated location.
|
||||||
exists(Alias::MemoryLocation location |
|
exists(Alias::MemoryLocation location |
|
||||||
instruction = Phi(_, location) and
|
instruction = getPhi(_, location) and
|
||||||
not exists(location.getAllocation())
|
not exists(location.getAllocation())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -128,7 +115,7 @@ private module Cached {
|
|||||||
hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result)
|
hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
instruction = Chi(getOldInstruction(result)) and
|
instruction = getChi(getOldInstruction(result)) and
|
||||||
tag instanceof ChiPartialOperandTag and
|
tag instanceof ChiPartialOperandTag and
|
||||||
overlap instanceof MustExactlyOverlap
|
overlap instanceof MustExactlyOverlap
|
||||||
or
|
or
|
||||||
@@ -172,13 +159,15 @@ private module Cached {
|
|||||||
|
|
||||||
pragma[noopt]
|
pragma[noopt]
|
||||||
cached
|
cached
|
||||||
Instruction getPhiOperandDefinition(Phi instr, IRBlock newPredecessorBlock, Overlap overlap) {
|
Instruction getPhiOperandDefinition(
|
||||||
|
PhiInstruction instr, IRBlock newPredecessorBlock, Overlap overlap
|
||||||
|
) {
|
||||||
exists(
|
exists(
|
||||||
Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock,
|
Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock,
|
||||||
OldBlock predBlock, OldBlock defBlock, int defOffset, Alias::MemoryLocation actualDefLocation
|
OldBlock predBlock, OldBlock defBlock, int defOffset, Alias::MemoryLocation actualDefLocation
|
||||||
|
|
|
|
||||||
hasPhiOperandDefinition(defLocation, useLocation, phiBlock, predBlock, defBlock, defOffset) and
|
hasPhiOperandDefinition(defLocation, useLocation, phiBlock, predBlock, defBlock, defOffset) and
|
||||||
instr = Phi(phiBlock, useLocation) and
|
instr = getPhi(phiBlock, useLocation) and
|
||||||
newPredecessorBlock = getNewBlock(predBlock) and
|
newPredecessorBlock = getNewBlock(predBlock) and
|
||||||
result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, actualDefLocation) and
|
result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, actualDefLocation) and
|
||||||
overlap = Alias::getOverlap(actualDefLocation, useLocation)
|
overlap = Alias::getOverlap(actualDefLocation, useLocation)
|
||||||
@@ -191,7 +180,7 @@ private module Cached {
|
|||||||
Alias::VirtualVariable vvar, OldInstruction oldInstr, Alias::MemoryLocation defLocation,
|
Alias::VirtualVariable vvar, OldInstruction oldInstr, Alias::MemoryLocation defLocation,
|
||||||
OldBlock defBlock, int defRank, int defOffset, OldBlock useBlock, int useRank
|
OldBlock defBlock, int defRank, int defOffset, OldBlock useBlock, int useRank
|
||||||
|
|
|
|
||||||
chiInstr = Chi(oldInstr) and
|
chiInstr = getChi(oldInstr) and
|
||||||
vvar = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() and
|
vvar = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() and
|
||||||
hasDefinitionAtRank(vvar, defLocation, defBlock, defRank, defOffset) and
|
hasDefinitionAtRank(vvar, defLocation, defBlock, defRank, defOffset) and
|
||||||
hasUseAtRank(vvar, useBlock, useRank, oldInstr) and
|
hasUseAtRank(vvar, useBlock, useRank, oldInstr) and
|
||||||
@@ -203,7 +192,7 @@ private module Cached {
|
|||||||
cached
|
cached
|
||||||
Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
|
Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
|
||||||
exists(OldBlock oldBlock |
|
exists(OldBlock oldBlock |
|
||||||
instr = Phi(oldBlock, _) and
|
instr = getPhi(oldBlock, _) and
|
||||||
result = getNewInstruction(oldBlock.getFirstInstruction())
|
result = getNewInstruction(oldBlock.getFirstInstruction())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -228,20 +217,20 @@ private module Cached {
|
|||||||
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||||
if hasChiNode(_, getOldInstruction(instruction))
|
if hasChiNode(_, getOldInstruction(instruction))
|
||||||
then
|
then
|
||||||
result = Chi(getOldInstruction(instruction)) and
|
result = getChi(getOldInstruction(instruction)) and
|
||||||
kind instanceof GotoEdge
|
kind instanceof GotoEdge
|
||||||
else (
|
else (
|
||||||
exists(OldInstruction oldInstruction |
|
exists(OldInstruction oldInstruction |
|
||||||
oldInstruction = getOldInstruction(instruction) and
|
oldInstruction = getOldInstruction(instruction) and
|
||||||
(
|
(
|
||||||
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
|
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
|
||||||
then result = Unreached(instruction.getEnclosingFunction())
|
then result = unreachedInstruction(instruction.getEnclosingIRFunction())
|
||||||
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(OldInstruction oldInstruction |
|
exists(OldInstruction oldInstruction |
|
||||||
instruction = Chi(oldInstruction) and
|
instruction = getChi(oldInstruction) and
|
||||||
result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -260,84 +249,61 @@ private module Cached {
|
|||||||
// `oldInstruction`, in which case the back edge should come out of the
|
// `oldInstruction`, in which case the back edge should come out of the
|
||||||
// chi node instead.
|
// chi node instead.
|
||||||
if hasChiNode(_, oldInstruction)
|
if hasChiNode(_, oldInstruction)
|
||||||
then instruction = Chi(oldInstruction)
|
then instruction = getChi(oldInstruction)
|
||||||
else instruction = getNewInstruction(oldInstruction)
|
else instruction = getNewInstruction(oldInstruction)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
Language::AST getInstructionAST(Instruction instruction) {
|
Language::AST getInstructionAST(TStageInstruction instr) {
|
||||||
exists(OldInstruction oldInstruction |
|
instr = rawInstruction(_, _, result, _)
|
||||||
instruction = WrappedInstruction(oldInstruction)
|
or
|
||||||
or
|
exists(RawIR::Instruction blockStartInstr |
|
||||||
instruction = Chi(oldInstruction)
|
instr = phiInstruction(_, _, blockStartInstr, _) and
|
||||||
|
|
result = blockStartInstr.getAST()
|
||||||
result = oldInstruction.getAST()
|
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(OldBlock block |
|
exists(RawIR::Instruction primaryInstr |
|
||||||
instruction = Phi(block, _) and
|
instr = chiInstruction(_, _, primaryInstr) and
|
||||||
result = block.getFirstInstruction().getAST()
|
result = primaryInstr.getAST()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
instruction = Unreached(result)
|
exists(IRFunctionBase irFunc |
|
||||||
|
instr = unreachedInstruction(irFunc) and result = irFunc.getFunction()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
Language::LanguageType getInstructionResultType(Instruction instruction) {
|
Language::LanguageType getInstructionResultType(TStageInstruction instr) {
|
||||||
exists(OldInstruction oldInstruction |
|
instr = rawInstruction(_, _, _, result)
|
||||||
instruction = WrappedInstruction(oldInstruction) and
|
|
||||||
result = oldInstruction.getResultLanguageType()
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar |
|
instr = phiInstruction(_, result, _, _)
|
||||||
instruction = Chi(oldInstruction) and
|
|
||||||
hasChiNode(vvar, oldInstruction) and
|
|
||||||
result = vvar.getType()
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
exists(Alias::MemoryLocation location |
|
instr = chiInstruction(_, result, _)
|
||||||
instruction = Phi(_, location) and
|
|
||||||
result = location.getType()
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
instruction = Unreached(_) and
|
instr = unreachedInstruction(_) and result = Language::getVoidType()
|
||||||
result = Language::getVoidType()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
Opcode getInstructionOpcode(Instruction instruction) {
|
Opcode getInstructionOpcode(TStageInstruction instr) {
|
||||||
exists(OldInstruction oldInstruction |
|
instr = rawInstruction(_, result, _, _)
|
||||||
instruction = WrappedInstruction(oldInstruction) and
|
|
||||||
result = oldInstruction.getOpcode()
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
instruction instanceof Chi and
|
instr = phiInstruction(_, _, _, _) and result instanceof Opcode::Phi
|
||||||
result instanceof Opcode::Chi
|
|
||||||
or
|
or
|
||||||
instruction instanceof Phi and
|
instr = chiInstruction(_, _, _) and result instanceof Opcode::Chi
|
||||||
result instanceof Opcode::Phi
|
|
||||||
or
|
or
|
||||||
instruction instanceof Unreached and
|
instr = unreachedInstruction(_) and result instanceof Opcode::Unreached
|
||||||
result instanceof Opcode::Unreached
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
IRFunction getInstructionEnclosingIRFunction(Instruction instruction) {
|
IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) {
|
||||||
exists(OldInstruction oldInstruction |
|
instr = rawInstruction(result, _, _, _)
|
||||||
instruction = WrappedInstruction(oldInstruction)
|
|
||||||
or
|
|
||||||
instruction = Chi(oldInstruction)
|
|
||||||
|
|
|
||||||
result.getFunction() = oldInstruction.getEnclosingFunction()
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
exists(OldBlock block |
|
instr = phiInstruction(result, _, _, _)
|
||||||
instruction = Phi(block, _) and
|
|
||||||
result.getFunction() = block.getEnclosingFunction()
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
instruction = Unreached(result.getFunction())
|
instr = chiInstruction(result, _, _)
|
||||||
|
or
|
||||||
|
instr = unreachedInstruction(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
@@ -401,7 +367,7 @@ private module Cached {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(OldIR::Instruction oldInstruction |
|
exists(OldIR::Instruction oldInstruction |
|
||||||
instruction = Chi(oldInstruction) and
|
instruction = getChi(oldInstruction) and
|
||||||
result = getNewInstruction(oldInstruction)
|
result = getNewInstruction(oldInstruction)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -409,6 +375,14 @@ private module Cached {
|
|||||||
|
|
||||||
private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr }
|
private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr }
|
||||||
|
|
||||||
|
private ChiInstruction getChi(OldInstruction primaryInstr) {
|
||||||
|
result = chiInstruction(_, _, primaryInstr)
|
||||||
|
}
|
||||||
|
|
||||||
|
private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) {
|
||||||
|
result = phiInstruction(_, _, defBlock.getFirstInstruction(), defLocation)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if instruction `def` needs to have a `Chi` instruction inserted after it, to account for a partial definition
|
* Holds if instruction `def` needs to have a `Chi` instruction inserted after it, to account for a partial definition
|
||||||
* of a virtual variable. The `Chi` instruction provides a definition of the entire virtual variable of which the
|
* of a virtual variable. The `Chi` instruction provides a definition of the entire virtual variable of which the
|
||||||
@@ -588,7 +562,7 @@ module DefUse {
|
|||||||
|
|
|
|
||||||
// An odd offset corresponds to the `Chi` instruction.
|
// An odd offset corresponds to the `Chi` instruction.
|
||||||
defOffset = oldOffset * 2 + 1 and
|
defOffset = oldOffset * 2 + 1 and
|
||||||
result = Chi(oldInstr) and
|
result = getChi(oldInstr) and
|
||||||
(
|
(
|
||||||
defLocation = Alias::getResultMemoryLocation(oldInstr) or
|
defLocation = Alias::getResultMemoryLocation(oldInstr) or
|
||||||
defLocation = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable()
|
defLocation = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable()
|
||||||
@@ -607,7 +581,7 @@ module DefUse {
|
|||||||
or
|
or
|
||||||
defOffset = -1 and
|
defOffset = -1 and
|
||||||
hasDefinition(_, defLocation, defBlock, defOffset) and
|
hasDefinition(_, defLocation, defBlock, defOffset) and
|
||||||
result = Phi(defBlock, defLocation) and
|
result = getPhi(defBlock, defLocation) and
|
||||||
actualDefLocation = defLocation
|
actualDefLocation = defLocation
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -891,7 +865,7 @@ private module CachedForDebugging {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(Alias::MemoryLocation location, OldBlock phiBlock, string specificity |
|
exists(Alias::MemoryLocation location, OldBlock phiBlock, string specificity |
|
||||||
instr = Phi(phiBlock, location) and
|
instr = getPhi(phiBlock, location) and
|
||||||
result =
|
result =
|
||||||
"Phi Block(" + phiBlock.getUniqueId() + ")[" + specificity + "]: " + location.getUniqueId() and
|
"Phi Block(" + phiBlock.getUniqueId() + ")[" + specificity + "]: " + location.getUniqueId() and
|
||||||
if location instanceof Alias::VirtualVariable
|
if location instanceof Alias::VirtualVariable
|
||||||
@@ -901,7 +875,7 @@ private module CachedForDebugging {
|
|||||||
else specificity = "s"
|
else specificity = "s"
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
instr = Unreached(_) and
|
instr = unreachedInstruction(_) and
|
||||||
result = "Unreached"
|
result = "Unreached"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -961,3 +935,44 @@ 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.
|
||||||
|
*/
|
||||||
|
cached
|
||||||
|
module SSA {
|
||||||
|
class MemoryLocation = Alias::MemoryLocation;
|
||||||
|
|
||||||
|
cached
|
||||||
|
predicate hasPhiInstruction(
|
||||||
|
IRFunction irFunc, Language::LanguageType resultType, OldInstruction blockStartInstr,
|
||||||
|
Alias::MemoryLocation defLocation
|
||||||
|
) {
|
||||||
|
exists(OldBlock oldBlock |
|
||||||
|
definitionHasPhiNode(defLocation, oldBlock) and
|
||||||
|
irFunc = oldBlock.getEnclosingIRFunction() and
|
||||||
|
blockStartInstr = oldBlock.getFirstInstruction() and
|
||||||
|
resultType = defLocation.getType()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
cached
|
||||||
|
predicate hasChiInstruction(
|
||||||
|
IRFunctionBase irFunc, Language::LanguageType resultType, OldInstruction primaryInstruction
|
||||||
|
) {
|
||||||
|
exists(Alias::VirtualVariable vvar |
|
||||||
|
hasChiNode(vvar, primaryInstruction) and
|
||||||
|
irFunc = primaryInstruction.getEnclosingIRFunction() and
|
||||||
|
resultType = vvar.getType()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
cached
|
||||||
|
predicate hasUnreachedInstruction(IRFunction irFunc) {
|
||||||
|
exists(OldInstruction oldInstruction |
|
||||||
|
irFunc = oldInstruction.getEnclosingIRFunction() and
|
||||||
|
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
import semmle.code.cpp.ir.implementation.Opcode
|
import semmle.code.cpp.ir.implementation.Opcode as Opcode
|
||||||
import semmle.code.cpp.ir.implementation.internal.OperandTag
|
import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag
|
||||||
import semmle.code.cpp.ir.internal.Overlap
|
import semmle.code.cpp.ir.internal.Overlap as Overlap
|
||||||
|
import semmle.code.cpp.ir.implementation.internal.TInstruction as TInstruction
|
||||||
|
import semmle.code.cpp.ir.implementation.raw.IR as RawIR
|
||||||
|
|||||||
@@ -2,5 +2,6 @@ import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as OldIR
|
|||||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.ReachableBlock as Reachability
|
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.ReachableBlock as Reachability
|
||||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.Dominance as Dominance
|
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.Dominance as Dominance
|
||||||
import semmle.code.cpp.ir.implementation.aliased_ssa.IR as NewIR
|
import semmle.code.cpp.ir.implementation.aliased_ssa.IR as NewIR
|
||||||
|
import semmle.code.cpp.ir.implementation.internal.TInstruction::AliasedSSAInstructions as SSAInstructions
|
||||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||||
import AliasedSSA as Alias
|
import AliasedSSA as Alias
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
private import IRFunctionBaseInternal
|
||||||
|
|
||||||
|
private newtype TIRFunction =
|
||||||
|
MkIRFunction(Language::Function func) { IRConstruction::Raw::functionHasIR(func) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The IR for a function. This base class contains only the predicates that are the same between all
|
||||||
|
* phases of the IR. Each instantiation of `IRFunction` extends this class.
|
||||||
|
*/
|
||||||
|
class IRFunctionBase extends TIRFunction {
|
||||||
|
Language::Function func;
|
||||||
|
|
||||||
|
IRFunctionBase() { this = MkIRFunction(func) }
|
||||||
|
|
||||||
|
/** Gets a textual representation of this element. */
|
||||||
|
final string toString() { result = "IR: " + func.toString() }
|
||||||
|
|
||||||
|
/** Gets the function whose IR is represented. */
|
||||||
|
final Language::Function getFunction() { result = func }
|
||||||
|
|
||||||
|
/** Gets the location of the function. */
|
||||||
|
final Language::Location getLocation() { result = func.getLocation() }
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||||
|
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||||
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as Construction
|
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction::Raw as Construction
|
||||||
private import semmle.code.cpp.ir.implementation.TempVariableTag as TempVariableTag_
|
private import semmle.code.cpp.ir.implementation.TempVariableTag as TempVariableTag_
|
||||||
|
|
||||||
module Imports {
|
module Imports {
|
||||||
|
|||||||
@@ -0,0 +1,111 @@
|
|||||||
|
private import TInstructionInternal
|
||||||
|
private import IRFunctionBase
|
||||||
|
private import TInstructionImports as Imports
|
||||||
|
private import Imports::IRType
|
||||||
|
private import Imports::Opcode
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An IR instruction. `TInstruction` is shared across all phases of the IR. There are individual
|
||||||
|
* branches of this type for instructions created directly from the AST (`TRawInstruction`) and for
|
||||||
|
* instructions added by each stage of SSA construction (`T*PhiInstruction`, `T*ChiInstruction`,
|
||||||
|
* `T*UnreachedInstruction`). Each stage then defines a `TStageInstruction` type that is a union of
|
||||||
|
* 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 =
|
||||||
|
TRawInstruction(
|
||||||
|
IRFunctionBase irFunc, Opcode opcode, Language::AST ast, Language::LanguageType resultType,
|
||||||
|
IRConstruction::Raw::InstructionTag1 tag1, IRConstruction::Raw::InstructionTag2 tag2
|
||||||
|
) {
|
||||||
|
IRConstruction::Raw::hasInstruction(irFunc.getFunction(), opcode, ast, resultType, tag1, tag2)
|
||||||
|
} or
|
||||||
|
TUnaliasedSSAPhiInstruction(
|
||||||
|
IRFunctionBase irFunc, Language::LanguageType resultType, TRawInstruction blockStartInstr,
|
||||||
|
UnaliasedSSA::SSA::MemoryLocation memoryLocation
|
||||||
|
) {
|
||||||
|
UnaliasedSSA::SSA::hasPhiInstruction(irFunc, resultType, blockStartInstr, memoryLocation)
|
||||||
|
} or
|
||||||
|
TUnaliasedSSAChiInstruction(
|
||||||
|
IRFunctionBase irFunc, Language::LanguageType resultType, TRawInstruction primaryInstruction
|
||||||
|
) {
|
||||||
|
none()
|
||||||
|
} or
|
||||||
|
TUnaliasedSSAUnreachedInstruction(IRFunctionBase irFunc) {
|
||||||
|
UnaliasedSSA::SSA::hasUnreachedInstruction(irFunc)
|
||||||
|
} or
|
||||||
|
TAliasedSSAPhiInstruction(
|
||||||
|
IRFunctionBase irFunc, Language::LanguageType resultType, TRawInstruction blockStartInstr,
|
||||||
|
AliasedSSA::SSA::MemoryLocation memoryLocation
|
||||||
|
) {
|
||||||
|
AliasedSSA::SSA::hasPhiInstruction(irFunc, resultType, blockStartInstr, memoryLocation)
|
||||||
|
} or
|
||||||
|
TAliasedSSAChiInstruction(
|
||||||
|
IRFunctionBase irFunc, Language::LanguageType resultType, TRawInstruction primaryInstruction
|
||||||
|
) {
|
||||||
|
AliasedSSA::SSA::hasChiInstruction(irFunc, resultType, primaryInstruction)
|
||||||
|
} or
|
||||||
|
TAliasedSSAUnreachedInstruction(IRFunctionBase irFunc) {
|
||||||
|
AliasedSSA::SSA::hasUnreachedInstruction(irFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides wrappers for the constructors of each branch of `TInstruction` that is used by the
|
||||||
|
* unaliased SSA stage.
|
||||||
|
* These wrappers are not parameterized because it is not possible to invoke an IPA constructor via
|
||||||
|
* a class alias.
|
||||||
|
*/
|
||||||
|
module UnaliasedSSAInstructions {
|
||||||
|
class TPhiInstruction = TUnaliasedSSAPhiInstruction;
|
||||||
|
|
||||||
|
TPhiInstruction phiInstruction(
|
||||||
|
IRFunctionBase irFunc, Language::LanguageType resultType, TRawInstruction blockStartInstr,
|
||||||
|
UnaliasedSSA::SSA::MemoryLocation memoryLocation
|
||||||
|
) {
|
||||||
|
result = TUnaliasedSSAPhiInstruction(irFunc, resultType, blockStartInstr, memoryLocation)
|
||||||
|
}
|
||||||
|
|
||||||
|
class TChiInstruction = TUnaliasedSSAChiInstruction;
|
||||||
|
|
||||||
|
TChiInstruction chiInstruction(
|
||||||
|
IRFunctionBase irFunc, Language::LanguageType resultType, TRawInstruction primaryInstruction
|
||||||
|
) {
|
||||||
|
result = TUnaliasedSSAChiInstruction(irFunc, resultType, primaryInstruction)
|
||||||
|
}
|
||||||
|
|
||||||
|
class TUnreachedInstruction = TUnaliasedSSAUnreachedInstruction;
|
||||||
|
|
||||||
|
TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) {
|
||||||
|
result = TUnaliasedSSAUnreachedInstruction(irFunc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides wrappers for the constructors of each branch of `TInstruction` that is used by the
|
||||||
|
* aliased SSA stage.
|
||||||
|
* These wrappers are not parameterized because it is not possible to invoke an IPA constructor via
|
||||||
|
* a class alias.
|
||||||
|
*/
|
||||||
|
module AliasedSSAInstructions {
|
||||||
|
class TPhiInstruction = TAliasedSSAPhiInstruction;
|
||||||
|
|
||||||
|
TPhiInstruction phiInstruction(
|
||||||
|
IRFunctionBase irFunc, Language::LanguageType resultType, TRawInstruction blockStartInstr,
|
||||||
|
AliasedSSA::SSA::MemoryLocation memoryLocation
|
||||||
|
) {
|
||||||
|
result = TAliasedSSAPhiInstruction(irFunc, resultType, blockStartInstr, memoryLocation)
|
||||||
|
}
|
||||||
|
|
||||||
|
class TChiInstruction = TAliasedSSAChiInstruction;
|
||||||
|
|
||||||
|
TChiInstruction chiInstruction(
|
||||||
|
IRFunctionBase irFunc, Language::LanguageType resultType, TRawInstruction primaryInstruction
|
||||||
|
) {
|
||||||
|
result = TAliasedSSAChiInstruction(irFunc, resultType, primaryInstruction)
|
||||||
|
}
|
||||||
|
|
||||||
|
class TUnreachedInstruction = TAliasedSSAUnreachedInstruction;
|
||||||
|
|
||||||
|
TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) {
|
||||||
|
result = TAliasedSSAUnreachedInstruction(irFunc)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
import semmle.code.cpp.ir.implementation.IRType as IRType
|
||||||
|
import semmle.code.cpp.ir.implementation.Opcode as Opcode
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||||
|
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
|
||||||
|
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedSSA
|
||||||
|
import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSAConstruction as AliasedSSA
|
||||||
@@ -1,29 +1,12 @@
|
|||||||
private import internal.IRInternal
|
private import internal.IRInternal
|
||||||
|
private import internal.IRFunctionImports as Imports
|
||||||
|
import Imports::IRFunctionBase
|
||||||
import Instruction
|
import Instruction
|
||||||
|
|
||||||
private newtype TIRFunction =
|
|
||||||
MkIRFunction(Language::Function func) { Construction::functionHasIR(func) }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the IR for a function.
|
* The IR for a function.
|
||||||
*/
|
*/
|
||||||
class IRFunction extends TIRFunction {
|
class IRFunction extends IRFunctionBase {
|
||||||
Language::Function func;
|
|
||||||
|
|
||||||
IRFunction() { this = MkIRFunction(func) }
|
|
||||||
|
|
||||||
final string toString() { result = "IR: " + func.toString() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the function whose IR is represented.
|
|
||||||
*/
|
|
||||||
final Language::Function getFunction() { result = func }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the location of the function.
|
|
||||||
*/
|
|
||||||
final Language::Location getLocation() { result = func.getLocation() }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the entry point for this function.
|
* Gets the entry point for this function.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -29,7 +29,13 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil
|
|||||||
/**
|
/**
|
||||||
* Represents a single operation in the IR.
|
* Represents a single operation in the IR.
|
||||||
*/
|
*/
|
||||||
class Instruction extends Construction::TInstruction {
|
class Instruction extends Construction::TStageInstruction {
|
||||||
|
Instruction() {
|
||||||
|
// The base `TStageInstruction` type is a superset of the actual instructions appearing in this
|
||||||
|
// stage. This call lets the stage filter out the ones that are not reused from raw IR.
|
||||||
|
Construction::hasInstruction(this)
|
||||||
|
}
|
||||||
|
|
||||||
final string toString() { result = getOpcode().toString() + ": " + getAST().toString() }
|
final string toString() { result = getOpcode().toString() + ": " + getAST().toString() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -250,7 +256,7 @@ class Instruction extends Construction::TInstruction {
|
|||||||
* result of the `Load` instruction is a prvalue of type `int`, representing
|
* result of the `Load` instruction is a prvalue of type `int`, representing
|
||||||
* the integer value loaded from variable `x`.
|
* the integer value loaded from variable `x`.
|
||||||
*/
|
*/
|
||||||
final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) }
|
final predicate isGLValue() { getResultLanguageType().hasType(_, true) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the size of the result produced by this instruction, in bytes. If the
|
* Gets the size of the result produced by this instruction, in bytes. If the
|
||||||
@@ -259,7 +265,7 @@ class Instruction extends Construction::TInstruction {
|
|||||||
* If `this.isGLValue()` holds for this instruction, the value of
|
* If `this.isGLValue()` holds for this instruction, the value of
|
||||||
* `getResultSize()` will always be the size of a pointer.
|
* `getResultSize()` will always be the size of a pointer.
|
||||||
*/
|
*/
|
||||||
final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() }
|
final int getResultSize() { result = getResultLanguageType().getByteSize() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the opcode that specifies the operation performed by this instruction.
|
* Gets the opcode that specifies the operation performed by this instruction.
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
private import cpp
|
private import cpp
|
||||||
import semmle.code.cpp.ir.implementation.raw.IR
|
import semmle.code.cpp.ir.implementation.raw.IR
|
||||||
private import semmle.code.cpp.ir.implementation.internal.OperandTag
|
private import semmle.code.cpp.ir.implementation.internal.OperandTag
|
||||||
|
private import semmle.code.cpp.ir.implementation.internal.IRFunctionBase
|
||||||
|
private import semmle.code.cpp.ir.implementation.internal.TInstruction
|
||||||
private import semmle.code.cpp.ir.internal.CppType
|
private import semmle.code.cpp.ir.internal.CppType
|
||||||
private import semmle.code.cpp.ir.internal.Overlap
|
private import semmle.code.cpp.ir.internal.Overlap
|
||||||
private import semmle.code.cpp.ir.internal.TempVariableTag
|
private import semmle.code.cpp.ir.internal.TempVariableTag
|
||||||
@@ -12,34 +14,41 @@ private import TranslatedStmt
|
|||||||
private import TranslatedFunction
|
private import TranslatedFunction
|
||||||
|
|
||||||
TranslatedElement getInstructionTranslatedElement(Instruction instruction) {
|
TranslatedElement getInstructionTranslatedElement(Instruction instruction) {
|
||||||
instruction = MkInstruction(result, _)
|
instruction = TRawInstruction(_, _, _, _, result, _)
|
||||||
}
|
}
|
||||||
|
|
||||||
InstructionTag getInstructionTag(Instruction instruction) { instruction = MkInstruction(_, result) }
|
InstructionTag getInstructionTag(Instruction instruction) {
|
||||||
|
instruction = TRawInstruction(_, _, _, _, _, result)
|
||||||
import Cached
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides the portion of the parameterized IR interface that is used to construct the initial
|
||||||
|
* "raw" stage of the IR. The other stages of the IR do not expose these predicates.
|
||||||
|
*/
|
||||||
cached
|
cached
|
||||||
private module Cached {
|
module Raw {
|
||||||
|
class InstructionTag1 = TranslatedElement;
|
||||||
|
|
||||||
|
class InstructionTag2 = InstructionTag;
|
||||||
|
|
||||||
cached
|
cached
|
||||||
predicate functionHasIR(Function func) { exists(getTranslatedFunction(func)) }
|
predicate functionHasIR(Function func) { exists(getTranslatedFunction(func)) }
|
||||||
|
|
||||||
cached
|
cached
|
||||||
newtype TInstruction =
|
predicate hasInstruction(
|
||||||
MkInstruction(TranslatedElement element, InstructionTag tag) {
|
Function func, Opcode opcode, Element ast, CppType resultType, TranslatedElement element,
|
||||||
element.hasInstruction(_, tag, _)
|
InstructionTag tag
|
||||||
}
|
) {
|
||||||
|
element.hasInstruction(opcode, tag, resultType) and
|
||||||
|
ast = element.getAST() and
|
||||||
|
func = element.getFunction()
|
||||||
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
predicate hasUserVariable(Function func, Variable var, CppType type) {
|
predicate hasUserVariable(Function func, Variable var, CppType type) {
|
||||||
getTranslatedFunction(func).hasUserVariable(var, type)
|
getTranslatedFunction(func).hasUserVariable(var, type)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
|
||||||
predicate hasThisVariable(Function func, CppType type) {
|
|
||||||
type = getTypeForGLValue(getTranslatedFunction(func).getThisType())
|
|
||||||
}
|
|
||||||
|
|
||||||
cached
|
cached
|
||||||
predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag, CppType type) {
|
predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag, CppType type) {
|
||||||
exists(TranslatedElement element |
|
exists(TranslatedElement element |
|
||||||
@@ -62,6 +71,16 @@ private module Cached {
|
|||||||
var.hasDynamicInitialization() and
|
var.hasDynamicInitialization() and
|
||||||
type = getBoolType()
|
type = getBoolType()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
import Cached
|
||||||
|
|
||||||
|
cached
|
||||||
|
private module Cached {
|
||||||
|
class TStageInstruction = TRawInstruction;
|
||||||
|
|
||||||
|
cached
|
||||||
|
predicate hasInstruction(TRawInstruction instr) { any() }
|
||||||
|
|
||||||
cached
|
cached
|
||||||
predicate hasModeledMemoryResult(Instruction instruction) { none() }
|
predicate hasModeledMemoryResult(Instruction instruction) { none() }
|
||||||
@@ -267,25 +286,23 @@ private module Cached {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
Locatable getInstructionAST(Instruction instruction) {
|
Locatable getInstructionAST(TStageInstruction instr) {
|
||||||
result = getInstructionTranslatedElement(instruction).getAST()
|
instr = TRawInstruction(_, _, result, _, _, _)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
CppType getInstructionResultType(Instruction instruction) {
|
CppType getInstructionResultType(TStageInstruction instr) {
|
||||||
getInstructionTranslatedElement(instruction)
|
instr = TRawInstruction(_, _, _, result, _, _)
|
||||||
.hasInstruction(_, getInstructionTag(instruction), result)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
Opcode getInstructionOpcode(Instruction instruction) {
|
Opcode getInstructionOpcode(TStageInstruction instr) {
|
||||||
getInstructionTranslatedElement(instruction)
|
instr = TRawInstruction(_, result, _, _, _, _)
|
||||||
.hasInstruction(result, getInstructionTag(instruction), _)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
IRFunction getInstructionEnclosingIRFunction(Instruction instruction) {
|
IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) {
|
||||||
result.getFunction() = getInstructionTranslatedElement(instruction).getFunction()
|
instr = TRawInstruction(result, _, _, _, _, _)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
import semmle.code.cpp.ir.implementation.internal.IRFunctionBase as IRFunctionBase
|
||||||
@@ -1,29 +1,12 @@
|
|||||||
private import internal.IRInternal
|
private import internal.IRInternal
|
||||||
|
private import internal.IRFunctionImports as Imports
|
||||||
|
import Imports::IRFunctionBase
|
||||||
import Instruction
|
import Instruction
|
||||||
|
|
||||||
private newtype TIRFunction =
|
|
||||||
MkIRFunction(Language::Function func) { Construction::functionHasIR(func) }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the IR for a function.
|
* The IR for a function.
|
||||||
*/
|
*/
|
||||||
class IRFunction extends TIRFunction {
|
class IRFunction extends IRFunctionBase {
|
||||||
Language::Function func;
|
|
||||||
|
|
||||||
IRFunction() { this = MkIRFunction(func) }
|
|
||||||
|
|
||||||
final string toString() { result = "IR: " + func.toString() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the function whose IR is represented.
|
|
||||||
*/
|
|
||||||
final Language::Function getFunction() { result = func }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the location of the function.
|
|
||||||
*/
|
|
||||||
final Language::Location getLocation() { result = func.getLocation() }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the entry point for this function.
|
* Gets the entry point for this function.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -29,7 +29,13 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil
|
|||||||
/**
|
/**
|
||||||
* Represents a single operation in the IR.
|
* Represents a single operation in the IR.
|
||||||
*/
|
*/
|
||||||
class Instruction extends Construction::TInstruction {
|
class Instruction extends Construction::TStageInstruction {
|
||||||
|
Instruction() {
|
||||||
|
// The base `TStageInstruction` type is a superset of the actual instructions appearing in this
|
||||||
|
// stage. This call lets the stage filter out the ones that are not reused from raw IR.
|
||||||
|
Construction::hasInstruction(this)
|
||||||
|
}
|
||||||
|
|
||||||
final string toString() { result = getOpcode().toString() + ": " + getAST().toString() }
|
final string toString() { result = getOpcode().toString() + ": " + getAST().toString() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -250,7 +256,7 @@ class Instruction extends Construction::TInstruction {
|
|||||||
* result of the `Load` instruction is a prvalue of type `int`, representing
|
* result of the `Load` instruction is a prvalue of type `int`, representing
|
||||||
* the integer value loaded from variable `x`.
|
* the integer value loaded from variable `x`.
|
||||||
*/
|
*/
|
||||||
final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) }
|
final predicate isGLValue() { getResultLanguageType().hasType(_, true) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the size of the result produced by this instruction, in bytes. If the
|
* Gets the size of the result produced by this instruction, in bytes. If the
|
||||||
@@ -259,7 +265,7 @@ class Instruction extends Construction::TInstruction {
|
|||||||
* If `this.isGLValue()` holds for this instruction, the value of
|
* If `this.isGLValue()` holds for this instruction, the value of
|
||||||
* `getResultSize()` will always be the size of a pointer.
|
* `getResultSize()` will always be the size of a pointer.
|
||||||
*/
|
*/
|
||||||
final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() }
|
final int getResultSize() { result = getResultLanguageType().getByteSize() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the opcode that specifies the operation performed by this instruction.
|
* Gets the opcode that specifies the operation performed by this instruction.
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
import semmle.code.cpp.ir.implementation.internal.IRFunctionBase as IRFunctionBase
|
||||||
@@ -1,5 +1,11 @@
|
|||||||
import SSAConstructionInternal
|
import SSAConstructionInternal
|
||||||
private import SSAConstructionImports
|
private import SSAConstructionImports as Imports
|
||||||
|
private import Imports::Opcode
|
||||||
|
private import Imports::OperandTag
|
||||||
|
private import Imports::Overlap
|
||||||
|
private import Imports::TInstruction
|
||||||
|
private import Imports::RawIR as RawIR
|
||||||
|
private import SSAInstructions
|
||||||
private import NewIR
|
private import NewIR
|
||||||
|
|
||||||
private class OldBlock = Reachability::ReachableBlock;
|
private class OldBlock = Reachability::ReachableBlock;
|
||||||
@@ -10,54 +16,35 @@ import Cached
|
|||||||
|
|
||||||
cached
|
cached
|
||||||
private module Cached {
|
private module Cached {
|
||||||
|
class TStageInstruction =
|
||||||
|
TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction;
|
||||||
|
|
||||||
|
private TRawInstruction rawInstruction(
|
||||||
|
IRFunctionBase irFunc, Opcode opcode, Language::AST ast, Language::LanguageType resultType
|
||||||
|
) {
|
||||||
|
result = TRawInstruction(irFunc, opcode, ast, resultType, _, _) and
|
||||||
|
result instanceof OldInstruction
|
||||||
|
}
|
||||||
|
|
||||||
|
cached
|
||||||
|
predicate hasInstruction(TStageInstruction instr) {
|
||||||
|
instr instanceof TRawInstruction and instr instanceof OldInstruction
|
||||||
|
or
|
||||||
|
not instr instanceof TRawInstruction
|
||||||
|
}
|
||||||
|
|
||||||
private IRBlock getNewBlock(OldBlock oldBlock) {
|
private IRBlock getNewBlock(OldBlock oldBlock) {
|
||||||
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
|
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
predicate functionHasIR(Language::Function func) {
|
OldInstruction getOldInstruction(Instruction instr) { instr = result }
|
||||||
exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func)
|
|
||||||
}
|
|
||||||
|
|
||||||
cached
|
|
||||||
OldInstruction getOldInstruction(Instruction instr) { instr = WrappedInstruction(result) }
|
|
||||||
|
|
||||||
private IRVariable getNewIRVariable(OldIR::IRVariable var) {
|
private IRVariable getNewIRVariable(OldIR::IRVariable var) {
|
||||||
// This is just a type cast. Both classes derive from the same newtype.
|
// This is just a type cast. Both classes derive from the same newtype.
|
||||||
result = var
|
result = var
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
|
||||||
newtype TInstruction =
|
|
||||||
WrappedInstruction(OldInstruction oldInstruction) {
|
|
||||||
not oldInstruction instanceof OldIR::PhiInstruction
|
|
||||||
} or
|
|
||||||
Phi(OldBlock block, Alias::MemoryLocation defLocation) {
|
|
||||||
definitionHasPhiNode(defLocation, block)
|
|
||||||
} or
|
|
||||||
Chi(OldInstruction oldInstruction) {
|
|
||||||
not oldInstruction instanceof OldIR::PhiInstruction and
|
|
||||||
hasChiNode(_, oldInstruction)
|
|
||||||
} or
|
|
||||||
Unreached(Language::Function function) {
|
|
||||||
exists(OldInstruction oldInstruction |
|
|
||||||
function = oldInstruction.getEnclosingFunction() and
|
|
||||||
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
cached
|
|
||||||
predicate hasTempVariable(
|
|
||||||
Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type
|
|
||||||
) {
|
|
||||||
exists(OldIR::IRTempVariable var |
|
|
||||||
var.getEnclosingFunction() = func and
|
|
||||||
var.getAST() = ast and
|
|
||||||
var.getTag() = tag and
|
|
||||||
var.getLanguageType() = type
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
cached
|
cached
|
||||||
predicate hasModeledMemoryResult(Instruction instruction) {
|
predicate hasModeledMemoryResult(Instruction instruction) {
|
||||||
exists(Alias::getResultMemoryLocation(getOldInstruction(instruction))) or
|
exists(Alias::getResultMemoryLocation(getOldInstruction(instruction))) or
|
||||||
@@ -73,7 +60,7 @@ private module Cached {
|
|||||||
or
|
or
|
||||||
// Chi instructions track virtual variables, and therefore a chi instruction is
|
// Chi instructions track virtual variables, and therefore a chi instruction is
|
||||||
// conflated if it's associated with the aliased virtual variable.
|
// conflated if it's associated with the aliased virtual variable.
|
||||||
exists(OldInstruction oldInstruction | instruction = Chi(oldInstruction) |
|
exists(OldInstruction oldInstruction | instruction = getChi(oldInstruction) |
|
||||||
Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof
|
Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof
|
||||||
Alias::AliasedVirtualVariable
|
Alias::AliasedVirtualVariable
|
||||||
)
|
)
|
||||||
@@ -81,7 +68,7 @@ private module Cached {
|
|||||||
// Phi instructions track locations, and therefore a phi instruction is
|
// Phi instructions track locations, and therefore a phi instruction is
|
||||||
// conflated if it's associated with a conflated location.
|
// conflated if it's associated with a conflated location.
|
||||||
exists(Alias::MemoryLocation location |
|
exists(Alias::MemoryLocation location |
|
||||||
instruction = Phi(_, location) and
|
instruction = getPhi(_, location) and
|
||||||
not exists(location.getAllocation())
|
not exists(location.getAllocation())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -128,7 +115,7 @@ private module Cached {
|
|||||||
hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result)
|
hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
instruction = Chi(getOldInstruction(result)) and
|
instruction = getChi(getOldInstruction(result)) and
|
||||||
tag instanceof ChiPartialOperandTag and
|
tag instanceof ChiPartialOperandTag and
|
||||||
overlap instanceof MustExactlyOverlap
|
overlap instanceof MustExactlyOverlap
|
||||||
or
|
or
|
||||||
@@ -172,13 +159,15 @@ private module Cached {
|
|||||||
|
|
||||||
pragma[noopt]
|
pragma[noopt]
|
||||||
cached
|
cached
|
||||||
Instruction getPhiOperandDefinition(Phi instr, IRBlock newPredecessorBlock, Overlap overlap) {
|
Instruction getPhiOperandDefinition(
|
||||||
|
PhiInstruction instr, IRBlock newPredecessorBlock, Overlap overlap
|
||||||
|
) {
|
||||||
exists(
|
exists(
|
||||||
Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock,
|
Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock,
|
||||||
OldBlock predBlock, OldBlock defBlock, int defOffset, Alias::MemoryLocation actualDefLocation
|
OldBlock predBlock, OldBlock defBlock, int defOffset, Alias::MemoryLocation actualDefLocation
|
||||||
|
|
|
|
||||||
hasPhiOperandDefinition(defLocation, useLocation, phiBlock, predBlock, defBlock, defOffset) and
|
hasPhiOperandDefinition(defLocation, useLocation, phiBlock, predBlock, defBlock, defOffset) and
|
||||||
instr = Phi(phiBlock, useLocation) and
|
instr = getPhi(phiBlock, useLocation) and
|
||||||
newPredecessorBlock = getNewBlock(predBlock) and
|
newPredecessorBlock = getNewBlock(predBlock) and
|
||||||
result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, actualDefLocation) and
|
result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, actualDefLocation) and
|
||||||
overlap = Alias::getOverlap(actualDefLocation, useLocation)
|
overlap = Alias::getOverlap(actualDefLocation, useLocation)
|
||||||
@@ -191,7 +180,7 @@ private module Cached {
|
|||||||
Alias::VirtualVariable vvar, OldInstruction oldInstr, Alias::MemoryLocation defLocation,
|
Alias::VirtualVariable vvar, OldInstruction oldInstr, Alias::MemoryLocation defLocation,
|
||||||
OldBlock defBlock, int defRank, int defOffset, OldBlock useBlock, int useRank
|
OldBlock defBlock, int defRank, int defOffset, OldBlock useBlock, int useRank
|
||||||
|
|
|
|
||||||
chiInstr = Chi(oldInstr) and
|
chiInstr = getChi(oldInstr) and
|
||||||
vvar = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() and
|
vvar = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() and
|
||||||
hasDefinitionAtRank(vvar, defLocation, defBlock, defRank, defOffset) and
|
hasDefinitionAtRank(vvar, defLocation, defBlock, defRank, defOffset) and
|
||||||
hasUseAtRank(vvar, useBlock, useRank, oldInstr) and
|
hasUseAtRank(vvar, useBlock, useRank, oldInstr) and
|
||||||
@@ -203,7 +192,7 @@ private module Cached {
|
|||||||
cached
|
cached
|
||||||
Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
|
Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
|
||||||
exists(OldBlock oldBlock |
|
exists(OldBlock oldBlock |
|
||||||
instr = Phi(oldBlock, _) and
|
instr = getPhi(oldBlock, _) and
|
||||||
result = getNewInstruction(oldBlock.getFirstInstruction())
|
result = getNewInstruction(oldBlock.getFirstInstruction())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -228,20 +217,20 @@ private module Cached {
|
|||||||
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||||
if hasChiNode(_, getOldInstruction(instruction))
|
if hasChiNode(_, getOldInstruction(instruction))
|
||||||
then
|
then
|
||||||
result = Chi(getOldInstruction(instruction)) and
|
result = getChi(getOldInstruction(instruction)) and
|
||||||
kind instanceof GotoEdge
|
kind instanceof GotoEdge
|
||||||
else (
|
else (
|
||||||
exists(OldInstruction oldInstruction |
|
exists(OldInstruction oldInstruction |
|
||||||
oldInstruction = getOldInstruction(instruction) and
|
oldInstruction = getOldInstruction(instruction) and
|
||||||
(
|
(
|
||||||
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
|
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
|
||||||
then result = Unreached(instruction.getEnclosingFunction())
|
then result = unreachedInstruction(instruction.getEnclosingIRFunction())
|
||||||
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(OldInstruction oldInstruction |
|
exists(OldInstruction oldInstruction |
|
||||||
instruction = Chi(oldInstruction) and
|
instruction = getChi(oldInstruction) and
|
||||||
result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -260,84 +249,61 @@ private module Cached {
|
|||||||
// `oldInstruction`, in which case the back edge should come out of the
|
// `oldInstruction`, in which case the back edge should come out of the
|
||||||
// chi node instead.
|
// chi node instead.
|
||||||
if hasChiNode(_, oldInstruction)
|
if hasChiNode(_, oldInstruction)
|
||||||
then instruction = Chi(oldInstruction)
|
then instruction = getChi(oldInstruction)
|
||||||
else instruction = getNewInstruction(oldInstruction)
|
else instruction = getNewInstruction(oldInstruction)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
Language::AST getInstructionAST(Instruction instruction) {
|
Language::AST getInstructionAST(TStageInstruction instr) {
|
||||||
exists(OldInstruction oldInstruction |
|
instr = rawInstruction(_, _, result, _)
|
||||||
instruction = WrappedInstruction(oldInstruction)
|
or
|
||||||
or
|
exists(RawIR::Instruction blockStartInstr |
|
||||||
instruction = Chi(oldInstruction)
|
instr = phiInstruction(_, _, blockStartInstr, _) and
|
||||||
|
|
result = blockStartInstr.getAST()
|
||||||
result = oldInstruction.getAST()
|
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(OldBlock block |
|
exists(RawIR::Instruction primaryInstr |
|
||||||
instruction = Phi(block, _) and
|
instr = chiInstruction(_, _, primaryInstr) and
|
||||||
result = block.getFirstInstruction().getAST()
|
result = primaryInstr.getAST()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
instruction = Unreached(result)
|
exists(IRFunctionBase irFunc |
|
||||||
|
instr = unreachedInstruction(irFunc) and result = irFunc.getFunction()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
Language::LanguageType getInstructionResultType(Instruction instruction) {
|
Language::LanguageType getInstructionResultType(TStageInstruction instr) {
|
||||||
exists(OldInstruction oldInstruction |
|
instr = rawInstruction(_, _, _, result)
|
||||||
instruction = WrappedInstruction(oldInstruction) and
|
|
||||||
result = oldInstruction.getResultLanguageType()
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar |
|
instr = phiInstruction(_, result, _, _)
|
||||||
instruction = Chi(oldInstruction) and
|
|
||||||
hasChiNode(vvar, oldInstruction) and
|
|
||||||
result = vvar.getType()
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
exists(Alias::MemoryLocation location |
|
instr = chiInstruction(_, result, _)
|
||||||
instruction = Phi(_, location) and
|
|
||||||
result = location.getType()
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
instruction = Unreached(_) and
|
instr = unreachedInstruction(_) and result = Language::getVoidType()
|
||||||
result = Language::getVoidType()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
Opcode getInstructionOpcode(Instruction instruction) {
|
Opcode getInstructionOpcode(TStageInstruction instr) {
|
||||||
exists(OldInstruction oldInstruction |
|
instr = rawInstruction(_, result, _, _)
|
||||||
instruction = WrappedInstruction(oldInstruction) and
|
|
||||||
result = oldInstruction.getOpcode()
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
instruction instanceof Chi and
|
instr = phiInstruction(_, _, _, _) and result instanceof Opcode::Phi
|
||||||
result instanceof Opcode::Chi
|
|
||||||
or
|
or
|
||||||
instruction instanceof Phi and
|
instr = chiInstruction(_, _, _) and result instanceof Opcode::Chi
|
||||||
result instanceof Opcode::Phi
|
|
||||||
or
|
or
|
||||||
instruction instanceof Unreached and
|
instr = unreachedInstruction(_) and result instanceof Opcode::Unreached
|
||||||
result instanceof Opcode::Unreached
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
IRFunction getInstructionEnclosingIRFunction(Instruction instruction) {
|
IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) {
|
||||||
exists(OldInstruction oldInstruction |
|
instr = rawInstruction(result, _, _, _)
|
||||||
instruction = WrappedInstruction(oldInstruction)
|
|
||||||
or
|
|
||||||
instruction = Chi(oldInstruction)
|
|
||||||
|
|
|
||||||
result.getFunction() = oldInstruction.getEnclosingFunction()
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
exists(OldBlock block |
|
instr = phiInstruction(result, _, _, _)
|
||||||
instruction = Phi(block, _) and
|
|
||||||
result.getFunction() = block.getEnclosingFunction()
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
instruction = Unreached(result.getFunction())
|
instr = chiInstruction(result, _, _)
|
||||||
|
or
|
||||||
|
instr = unreachedInstruction(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
@@ -401,7 +367,7 @@ private module Cached {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(OldIR::Instruction oldInstruction |
|
exists(OldIR::Instruction oldInstruction |
|
||||||
instruction = Chi(oldInstruction) and
|
instruction = getChi(oldInstruction) and
|
||||||
result = getNewInstruction(oldInstruction)
|
result = getNewInstruction(oldInstruction)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -409,6 +375,14 @@ private module Cached {
|
|||||||
|
|
||||||
private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr }
|
private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr }
|
||||||
|
|
||||||
|
private ChiInstruction getChi(OldInstruction primaryInstr) {
|
||||||
|
result = chiInstruction(_, _, primaryInstr)
|
||||||
|
}
|
||||||
|
|
||||||
|
private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) {
|
||||||
|
result = phiInstruction(_, _, defBlock.getFirstInstruction(), defLocation)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if instruction `def` needs to have a `Chi` instruction inserted after it, to account for a partial definition
|
* Holds if instruction `def` needs to have a `Chi` instruction inserted after it, to account for a partial definition
|
||||||
* of a virtual variable. The `Chi` instruction provides a definition of the entire virtual variable of which the
|
* of a virtual variable. The `Chi` instruction provides a definition of the entire virtual variable of which the
|
||||||
@@ -588,7 +562,7 @@ module DefUse {
|
|||||||
|
|
|
|
||||||
// An odd offset corresponds to the `Chi` instruction.
|
// An odd offset corresponds to the `Chi` instruction.
|
||||||
defOffset = oldOffset * 2 + 1 and
|
defOffset = oldOffset * 2 + 1 and
|
||||||
result = Chi(oldInstr) and
|
result = getChi(oldInstr) and
|
||||||
(
|
(
|
||||||
defLocation = Alias::getResultMemoryLocation(oldInstr) or
|
defLocation = Alias::getResultMemoryLocation(oldInstr) or
|
||||||
defLocation = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable()
|
defLocation = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable()
|
||||||
@@ -607,7 +581,7 @@ module DefUse {
|
|||||||
or
|
or
|
||||||
defOffset = -1 and
|
defOffset = -1 and
|
||||||
hasDefinition(_, defLocation, defBlock, defOffset) and
|
hasDefinition(_, defLocation, defBlock, defOffset) and
|
||||||
result = Phi(defBlock, defLocation) and
|
result = getPhi(defBlock, defLocation) and
|
||||||
actualDefLocation = defLocation
|
actualDefLocation = defLocation
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -891,7 +865,7 @@ private module CachedForDebugging {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(Alias::MemoryLocation location, OldBlock phiBlock, string specificity |
|
exists(Alias::MemoryLocation location, OldBlock phiBlock, string specificity |
|
||||||
instr = Phi(phiBlock, location) and
|
instr = getPhi(phiBlock, location) and
|
||||||
result =
|
result =
|
||||||
"Phi Block(" + phiBlock.getUniqueId() + ")[" + specificity + "]: " + location.getUniqueId() and
|
"Phi Block(" + phiBlock.getUniqueId() + ")[" + specificity + "]: " + location.getUniqueId() and
|
||||||
if location instanceof Alias::VirtualVariable
|
if location instanceof Alias::VirtualVariable
|
||||||
@@ -901,7 +875,7 @@ private module CachedForDebugging {
|
|||||||
else specificity = "s"
|
else specificity = "s"
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
instr = Unreached(_) and
|
instr = unreachedInstruction(_) and
|
||||||
result = "Unreached"
|
result = "Unreached"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -961,3 +935,44 @@ 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.
|
||||||
|
*/
|
||||||
|
cached
|
||||||
|
module SSA {
|
||||||
|
class MemoryLocation = Alias::MemoryLocation;
|
||||||
|
|
||||||
|
cached
|
||||||
|
predicate hasPhiInstruction(
|
||||||
|
IRFunction irFunc, Language::LanguageType resultType, OldInstruction blockStartInstr,
|
||||||
|
Alias::MemoryLocation defLocation
|
||||||
|
) {
|
||||||
|
exists(OldBlock oldBlock |
|
||||||
|
definitionHasPhiNode(defLocation, oldBlock) and
|
||||||
|
irFunc = oldBlock.getEnclosingIRFunction() and
|
||||||
|
blockStartInstr = oldBlock.getFirstInstruction() and
|
||||||
|
resultType = defLocation.getType()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
cached
|
||||||
|
predicate hasChiInstruction(
|
||||||
|
IRFunctionBase irFunc, Language::LanguageType resultType, OldInstruction primaryInstruction
|
||||||
|
) {
|
||||||
|
exists(Alias::VirtualVariable vvar |
|
||||||
|
hasChiNode(vvar, primaryInstruction) and
|
||||||
|
irFunc = primaryInstruction.getEnclosingIRFunction() and
|
||||||
|
resultType = vvar.getType()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
cached
|
||||||
|
predicate hasUnreachedInstruction(IRFunction irFunc) {
|
||||||
|
exists(OldInstruction oldInstruction |
|
||||||
|
irFunc = oldInstruction.getEnclosingIRFunction() and
|
||||||
|
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
import semmle.code.cpp.ir.implementation.Opcode
|
import semmle.code.cpp.ir.implementation.Opcode as Opcode
|
||||||
import semmle.code.cpp.ir.implementation.internal.OperandTag
|
import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag
|
||||||
import semmle.code.cpp.ir.internal.Overlap
|
import semmle.code.cpp.ir.internal.Overlap as Overlap
|
||||||
|
import semmle.code.cpp.ir.implementation.internal.TInstruction as TInstruction
|
||||||
|
import semmle.code.cpp.ir.implementation.raw.IR as RawIR
|
||||||
|
|||||||
@@ -2,5 +2,7 @@ import semmle.code.cpp.ir.implementation.raw.IR as OldIR
|
|||||||
import semmle.code.cpp.ir.implementation.raw.internal.reachability.ReachableBlock as Reachability
|
import semmle.code.cpp.ir.implementation.raw.internal.reachability.ReachableBlock as Reachability
|
||||||
import semmle.code.cpp.ir.implementation.raw.internal.reachability.Dominance as Dominance
|
import semmle.code.cpp.ir.implementation.raw.internal.reachability.Dominance as Dominance
|
||||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as NewIR
|
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as NewIR
|
||||||
|
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as RawStage
|
||||||
|
import semmle.code.cpp.ir.implementation.internal.TInstruction::UnaliasedSSAInstructions as SSAInstructions
|
||||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||||
import SimpleSSA as Alias
|
import SimpleSSA as Alias
|
||||||
|
|||||||
@@ -1,29 +1,12 @@
|
|||||||
private import internal.IRInternal
|
private import internal.IRInternal
|
||||||
|
private import internal.IRFunctionImports as Imports
|
||||||
|
import Imports::IRFunctionBase
|
||||||
import Instruction
|
import Instruction
|
||||||
|
|
||||||
private newtype TIRFunction =
|
|
||||||
MkIRFunction(Language::Function func) { Construction::functionHasIR(func) }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the IR for a function.
|
* The IR for a function.
|
||||||
*/
|
*/
|
||||||
class IRFunction extends TIRFunction {
|
class IRFunction extends IRFunctionBase {
|
||||||
Language::Function func;
|
|
||||||
|
|
||||||
IRFunction() { this = MkIRFunction(func) }
|
|
||||||
|
|
||||||
final string toString() { result = "IR: " + func.toString() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the function whose IR is represented.
|
|
||||||
*/
|
|
||||||
final Language::Function getFunction() { result = func }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the location of the function.
|
|
||||||
*/
|
|
||||||
final Language::Location getLocation() { result = func.getLocation() }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the entry point for this function.
|
* Gets the entry point for this function.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -29,7 +29,13 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil
|
|||||||
/**
|
/**
|
||||||
* Represents a single operation in the IR.
|
* Represents a single operation in the IR.
|
||||||
*/
|
*/
|
||||||
class Instruction extends Construction::TInstruction {
|
class Instruction extends Construction::TStageInstruction {
|
||||||
|
Instruction() {
|
||||||
|
// The base `TStageInstruction` type is a superset of the actual instructions appearing in this
|
||||||
|
// stage. This call lets the stage filter out the ones that are not reused from raw IR.
|
||||||
|
Construction::hasInstruction(this)
|
||||||
|
}
|
||||||
|
|
||||||
final string toString() { result = getOpcode().toString() + ": " + getAST().toString() }
|
final string toString() { result = getOpcode().toString() + ": " + getAST().toString() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -250,7 +256,7 @@ class Instruction extends Construction::TInstruction {
|
|||||||
* result of the `Load` instruction is a prvalue of type `int`, representing
|
* result of the `Load` instruction is a prvalue of type `int`, representing
|
||||||
* the integer value loaded from variable `x`.
|
* the integer value loaded from variable `x`.
|
||||||
*/
|
*/
|
||||||
final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) }
|
final predicate isGLValue() { getResultLanguageType().hasType(_, true) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the size of the result produced by this instruction, in bytes. If the
|
* Gets the size of the result produced by this instruction, in bytes. If the
|
||||||
@@ -259,7 +265,7 @@ class Instruction extends Construction::TInstruction {
|
|||||||
* If `this.isGLValue()` holds for this instruction, the value of
|
* If `this.isGLValue()` holds for this instruction, the value of
|
||||||
* `getResultSize()` will always be the size of a pointer.
|
* `getResultSize()` will always be the size of a pointer.
|
||||||
*/
|
*/
|
||||||
final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() }
|
final int getResultSize() { result = getResultLanguageType().getByteSize() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the opcode that specifies the operation performed by this instruction.
|
* Gets the opcode that specifies the operation performed by this instruction.
|
||||||
|
|||||||
@@ -1,29 +1,12 @@
|
|||||||
private import internal.IRInternal
|
private import internal.IRInternal
|
||||||
|
private import internal.IRFunctionImports as Imports
|
||||||
|
import Imports::IRFunctionBase
|
||||||
import Instruction
|
import Instruction
|
||||||
|
|
||||||
private newtype TIRFunction =
|
|
||||||
MkIRFunction(Language::Function func) { Construction::functionHasIR(func) }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the IR for a function.
|
* The IR for a function.
|
||||||
*/
|
*/
|
||||||
class IRFunction extends TIRFunction {
|
class IRFunction extends IRFunctionBase {
|
||||||
Language::Function func;
|
|
||||||
|
|
||||||
IRFunction() { this = MkIRFunction(func) }
|
|
||||||
|
|
||||||
final string toString() { result = "IR: " + func.toString() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the function whose IR is represented.
|
|
||||||
*/
|
|
||||||
final Language::Function getFunction() { result = func }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the location of the function.
|
|
||||||
*/
|
|
||||||
final Language::Location getLocation() { result = func.getLocation() }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the entry point for this function.
|
* Gets the entry point for this function.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -29,7 +29,13 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil
|
|||||||
/**
|
/**
|
||||||
* Represents a single operation in the IR.
|
* Represents a single operation in the IR.
|
||||||
*/
|
*/
|
||||||
class Instruction extends Construction::TInstruction {
|
class Instruction extends Construction::TStageInstruction {
|
||||||
|
Instruction() {
|
||||||
|
// The base `TStageInstruction` type is a superset of the actual instructions appearing in this
|
||||||
|
// stage. This call lets the stage filter out the ones that are not reused from raw IR.
|
||||||
|
Construction::hasInstruction(this)
|
||||||
|
}
|
||||||
|
|
||||||
final string toString() { result = getOpcode().toString() + ": " + getAST().toString() }
|
final string toString() { result = getOpcode().toString() + ": " + getAST().toString() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -250,7 +256,7 @@ class Instruction extends Construction::TInstruction {
|
|||||||
* result of the `Load` instruction is a prvalue of type `int`, representing
|
* result of the `Load` instruction is a prvalue of type `int`, representing
|
||||||
* the integer value loaded from variable `x`.
|
* the integer value loaded from variable `x`.
|
||||||
*/
|
*/
|
||||||
final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) }
|
final predicate isGLValue() { getResultLanguageType().hasType(_, true) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the size of the result produced by this instruction, in bytes. If the
|
* Gets the size of the result produced by this instruction, in bytes. If the
|
||||||
@@ -259,7 +265,7 @@ class Instruction extends Construction::TInstruction {
|
|||||||
* If `this.isGLValue()` holds for this instruction, the value of
|
* If `this.isGLValue()` holds for this instruction, the value of
|
||||||
* `getResultSize()` will always be the size of a pointer.
|
* `getResultSize()` will always be the size of a pointer.
|
||||||
*/
|
*/
|
||||||
final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() }
|
final int getResultSize() { result = getResultLanguageType().getByteSize() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the opcode that specifies the operation performed by this instruction.
|
* Gets the opcode that specifies the operation performed by this instruction.
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
import SSAConstructionInternal
|
import SSAConstructionInternal
|
||||||
private import SSAConstructionImports
|
private import SSAConstructionImports as Imports
|
||||||
|
private import Imports::Opcode
|
||||||
|
private import Imports::OperandTag
|
||||||
|
private import Imports::Overlap
|
||||||
|
private import Imports::TInstruction
|
||||||
|
private import Imports::RawIR as RawIR
|
||||||
|
private import SSAInstructions
|
||||||
private import NewIR
|
private import NewIR
|
||||||
|
|
||||||
private class OldBlock = Reachability::ReachableBlock;
|
private class OldBlock = Reachability::ReachableBlock;
|
||||||
@@ -10,54 +16,35 @@ import Cached
|
|||||||
|
|
||||||
cached
|
cached
|
||||||
private module Cached {
|
private module Cached {
|
||||||
|
class TStageInstruction =
|
||||||
|
TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction;
|
||||||
|
|
||||||
|
private TRawInstruction rawInstruction(
|
||||||
|
IRFunctionBase irFunc, Opcode opcode, Language::AST ast, Language::LanguageType resultType
|
||||||
|
) {
|
||||||
|
result = TRawInstruction(irFunc, opcode, ast, resultType, _, _) and
|
||||||
|
result instanceof OldInstruction
|
||||||
|
}
|
||||||
|
|
||||||
|
cached
|
||||||
|
predicate hasInstruction(TStageInstruction instr) {
|
||||||
|
instr instanceof TRawInstruction and instr instanceof OldInstruction
|
||||||
|
or
|
||||||
|
not instr instanceof TRawInstruction
|
||||||
|
}
|
||||||
|
|
||||||
private IRBlock getNewBlock(OldBlock oldBlock) {
|
private IRBlock getNewBlock(OldBlock oldBlock) {
|
||||||
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
|
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
predicate functionHasIR(Language::Function func) {
|
OldInstruction getOldInstruction(Instruction instr) { instr = result }
|
||||||
exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func)
|
|
||||||
}
|
|
||||||
|
|
||||||
cached
|
|
||||||
OldInstruction getOldInstruction(Instruction instr) { instr = WrappedInstruction(result) }
|
|
||||||
|
|
||||||
private IRVariable getNewIRVariable(OldIR::IRVariable var) {
|
private IRVariable getNewIRVariable(OldIR::IRVariable var) {
|
||||||
// This is just a type cast. Both classes derive from the same newtype.
|
// This is just a type cast. Both classes derive from the same newtype.
|
||||||
result = var
|
result = var
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
|
||||||
newtype TInstruction =
|
|
||||||
WrappedInstruction(OldInstruction oldInstruction) {
|
|
||||||
not oldInstruction instanceof OldIR::PhiInstruction
|
|
||||||
} or
|
|
||||||
Phi(OldBlock block, Alias::MemoryLocation defLocation) {
|
|
||||||
definitionHasPhiNode(defLocation, block)
|
|
||||||
} or
|
|
||||||
Chi(OldInstruction oldInstruction) {
|
|
||||||
not oldInstruction instanceof OldIR::PhiInstruction and
|
|
||||||
hasChiNode(_, oldInstruction)
|
|
||||||
} or
|
|
||||||
Unreached(Language::Function function) {
|
|
||||||
exists(OldInstruction oldInstruction |
|
|
||||||
function = oldInstruction.getEnclosingFunction() and
|
|
||||||
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
cached
|
|
||||||
predicate hasTempVariable(
|
|
||||||
Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type
|
|
||||||
) {
|
|
||||||
exists(OldIR::IRTempVariable var |
|
|
||||||
var.getEnclosingFunction() = func and
|
|
||||||
var.getAST() = ast and
|
|
||||||
var.getTag() = tag and
|
|
||||||
var.getLanguageType() = type
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
cached
|
cached
|
||||||
predicate hasModeledMemoryResult(Instruction instruction) {
|
predicate hasModeledMemoryResult(Instruction instruction) {
|
||||||
exists(Alias::getResultMemoryLocation(getOldInstruction(instruction))) or
|
exists(Alias::getResultMemoryLocation(getOldInstruction(instruction))) or
|
||||||
@@ -73,7 +60,7 @@ private module Cached {
|
|||||||
or
|
or
|
||||||
// Chi instructions track virtual variables, and therefore a chi instruction is
|
// Chi instructions track virtual variables, and therefore a chi instruction is
|
||||||
// conflated if it's associated with the aliased virtual variable.
|
// conflated if it's associated with the aliased virtual variable.
|
||||||
exists(OldInstruction oldInstruction | instruction = Chi(oldInstruction) |
|
exists(OldInstruction oldInstruction | instruction = getChi(oldInstruction) |
|
||||||
Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof
|
Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof
|
||||||
Alias::AliasedVirtualVariable
|
Alias::AliasedVirtualVariable
|
||||||
)
|
)
|
||||||
@@ -81,7 +68,7 @@ private module Cached {
|
|||||||
// Phi instructions track locations, and therefore a phi instruction is
|
// Phi instructions track locations, and therefore a phi instruction is
|
||||||
// conflated if it's associated with a conflated location.
|
// conflated if it's associated with a conflated location.
|
||||||
exists(Alias::MemoryLocation location |
|
exists(Alias::MemoryLocation location |
|
||||||
instruction = Phi(_, location) and
|
instruction = getPhi(_, location) and
|
||||||
not exists(location.getAllocation())
|
not exists(location.getAllocation())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -128,7 +115,7 @@ private module Cached {
|
|||||||
hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result)
|
hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
instruction = Chi(getOldInstruction(result)) and
|
instruction = getChi(getOldInstruction(result)) and
|
||||||
tag instanceof ChiPartialOperandTag and
|
tag instanceof ChiPartialOperandTag and
|
||||||
overlap instanceof MustExactlyOverlap
|
overlap instanceof MustExactlyOverlap
|
||||||
or
|
or
|
||||||
@@ -172,13 +159,15 @@ private module Cached {
|
|||||||
|
|
||||||
pragma[noopt]
|
pragma[noopt]
|
||||||
cached
|
cached
|
||||||
Instruction getPhiOperandDefinition(Phi instr, IRBlock newPredecessorBlock, Overlap overlap) {
|
Instruction getPhiOperandDefinition(
|
||||||
|
PhiInstruction instr, IRBlock newPredecessorBlock, Overlap overlap
|
||||||
|
) {
|
||||||
exists(
|
exists(
|
||||||
Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock,
|
Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock,
|
||||||
OldBlock predBlock, OldBlock defBlock, int defOffset, Alias::MemoryLocation actualDefLocation
|
OldBlock predBlock, OldBlock defBlock, int defOffset, Alias::MemoryLocation actualDefLocation
|
||||||
|
|
|
|
||||||
hasPhiOperandDefinition(defLocation, useLocation, phiBlock, predBlock, defBlock, defOffset) and
|
hasPhiOperandDefinition(defLocation, useLocation, phiBlock, predBlock, defBlock, defOffset) and
|
||||||
instr = Phi(phiBlock, useLocation) and
|
instr = getPhi(phiBlock, useLocation) and
|
||||||
newPredecessorBlock = getNewBlock(predBlock) and
|
newPredecessorBlock = getNewBlock(predBlock) and
|
||||||
result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, actualDefLocation) and
|
result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, actualDefLocation) and
|
||||||
overlap = Alias::getOverlap(actualDefLocation, useLocation)
|
overlap = Alias::getOverlap(actualDefLocation, useLocation)
|
||||||
@@ -191,7 +180,7 @@ private module Cached {
|
|||||||
Alias::VirtualVariable vvar, OldInstruction oldInstr, Alias::MemoryLocation defLocation,
|
Alias::VirtualVariable vvar, OldInstruction oldInstr, Alias::MemoryLocation defLocation,
|
||||||
OldBlock defBlock, int defRank, int defOffset, OldBlock useBlock, int useRank
|
OldBlock defBlock, int defRank, int defOffset, OldBlock useBlock, int useRank
|
||||||
|
|
|
|
||||||
chiInstr = Chi(oldInstr) and
|
chiInstr = getChi(oldInstr) and
|
||||||
vvar = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() and
|
vvar = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() and
|
||||||
hasDefinitionAtRank(vvar, defLocation, defBlock, defRank, defOffset) and
|
hasDefinitionAtRank(vvar, defLocation, defBlock, defRank, defOffset) and
|
||||||
hasUseAtRank(vvar, useBlock, useRank, oldInstr) and
|
hasUseAtRank(vvar, useBlock, useRank, oldInstr) and
|
||||||
@@ -203,7 +192,7 @@ private module Cached {
|
|||||||
cached
|
cached
|
||||||
Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
|
Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
|
||||||
exists(OldBlock oldBlock |
|
exists(OldBlock oldBlock |
|
||||||
instr = Phi(oldBlock, _) and
|
instr = getPhi(oldBlock, _) and
|
||||||
result = getNewInstruction(oldBlock.getFirstInstruction())
|
result = getNewInstruction(oldBlock.getFirstInstruction())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -228,20 +217,20 @@ private module Cached {
|
|||||||
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||||
if hasChiNode(_, getOldInstruction(instruction))
|
if hasChiNode(_, getOldInstruction(instruction))
|
||||||
then
|
then
|
||||||
result = Chi(getOldInstruction(instruction)) and
|
result = getChi(getOldInstruction(instruction)) and
|
||||||
kind instanceof GotoEdge
|
kind instanceof GotoEdge
|
||||||
else (
|
else (
|
||||||
exists(OldInstruction oldInstruction |
|
exists(OldInstruction oldInstruction |
|
||||||
oldInstruction = getOldInstruction(instruction) and
|
oldInstruction = getOldInstruction(instruction) and
|
||||||
(
|
(
|
||||||
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
|
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
|
||||||
then result = Unreached(instruction.getEnclosingFunction())
|
then result = unreachedInstruction(instruction.getEnclosingIRFunction())
|
||||||
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(OldInstruction oldInstruction |
|
exists(OldInstruction oldInstruction |
|
||||||
instruction = Chi(oldInstruction) and
|
instruction = getChi(oldInstruction) and
|
||||||
result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -260,84 +249,61 @@ private module Cached {
|
|||||||
// `oldInstruction`, in which case the back edge should come out of the
|
// `oldInstruction`, in which case the back edge should come out of the
|
||||||
// chi node instead.
|
// chi node instead.
|
||||||
if hasChiNode(_, oldInstruction)
|
if hasChiNode(_, oldInstruction)
|
||||||
then instruction = Chi(oldInstruction)
|
then instruction = getChi(oldInstruction)
|
||||||
else instruction = getNewInstruction(oldInstruction)
|
else instruction = getNewInstruction(oldInstruction)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
Language::AST getInstructionAST(Instruction instruction) {
|
Language::AST getInstructionAST(TStageInstruction instr) {
|
||||||
exists(OldInstruction oldInstruction |
|
instr = rawInstruction(_, _, result, _)
|
||||||
instruction = WrappedInstruction(oldInstruction)
|
or
|
||||||
or
|
exists(RawIR::Instruction blockStartInstr |
|
||||||
instruction = Chi(oldInstruction)
|
instr = phiInstruction(_, _, blockStartInstr, _) and
|
||||||
|
|
result = blockStartInstr.getAST()
|
||||||
result = oldInstruction.getAST()
|
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(OldBlock block |
|
exists(RawIR::Instruction primaryInstr |
|
||||||
instruction = Phi(block, _) and
|
instr = chiInstruction(_, _, primaryInstr) and
|
||||||
result = block.getFirstInstruction().getAST()
|
result = primaryInstr.getAST()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
instruction = Unreached(result)
|
exists(IRFunctionBase irFunc |
|
||||||
|
instr = unreachedInstruction(irFunc) and result = irFunc.getFunction()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
Language::LanguageType getInstructionResultType(Instruction instruction) {
|
Language::LanguageType getInstructionResultType(TStageInstruction instr) {
|
||||||
exists(OldInstruction oldInstruction |
|
instr = rawInstruction(_, _, _, result)
|
||||||
instruction = WrappedInstruction(oldInstruction) and
|
|
||||||
result = oldInstruction.getResultLanguageType()
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar |
|
instr = phiInstruction(_, result, _, _)
|
||||||
instruction = Chi(oldInstruction) and
|
|
||||||
hasChiNode(vvar, oldInstruction) and
|
|
||||||
result = vvar.getType()
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
exists(Alias::MemoryLocation location |
|
instr = chiInstruction(_, result, _)
|
||||||
instruction = Phi(_, location) and
|
|
||||||
result = location.getType()
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
instruction = Unreached(_) and
|
instr = unreachedInstruction(_) and result = Language::getVoidType()
|
||||||
result = Language::getVoidType()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
Opcode getInstructionOpcode(Instruction instruction) {
|
Opcode getInstructionOpcode(TStageInstruction instr) {
|
||||||
exists(OldInstruction oldInstruction |
|
instr = rawInstruction(_, result, _, _)
|
||||||
instruction = WrappedInstruction(oldInstruction) and
|
|
||||||
result = oldInstruction.getOpcode()
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
instruction instanceof Chi and
|
instr = phiInstruction(_, _, _, _) and result instanceof Opcode::Phi
|
||||||
result instanceof Opcode::Chi
|
|
||||||
or
|
or
|
||||||
instruction instanceof Phi and
|
instr = chiInstruction(_, _, _) and result instanceof Opcode::Chi
|
||||||
result instanceof Opcode::Phi
|
|
||||||
or
|
or
|
||||||
instruction instanceof Unreached and
|
instr = unreachedInstruction(_) and result instanceof Opcode::Unreached
|
||||||
result instanceof Opcode::Unreached
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
IRFunction getInstructionEnclosingIRFunction(Instruction instruction) {
|
IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) {
|
||||||
exists(OldInstruction oldInstruction |
|
instr = rawInstruction(result, _, _, _)
|
||||||
instruction = WrappedInstruction(oldInstruction)
|
|
||||||
or
|
|
||||||
instruction = Chi(oldInstruction)
|
|
||||||
|
|
|
||||||
result.getFunction() = oldInstruction.getEnclosingFunction()
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
exists(OldBlock block |
|
instr = phiInstruction(result, _, _, _)
|
||||||
instruction = Phi(block, _) and
|
|
||||||
result.getFunction() = block.getEnclosingFunction()
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
instruction = Unreached(result.getFunction())
|
instr = chiInstruction(result, _, _)
|
||||||
|
or
|
||||||
|
instr = unreachedInstruction(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
@@ -401,7 +367,7 @@ private module Cached {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(OldIR::Instruction oldInstruction |
|
exists(OldIR::Instruction oldInstruction |
|
||||||
instruction = Chi(oldInstruction) and
|
instruction = getChi(oldInstruction) and
|
||||||
result = getNewInstruction(oldInstruction)
|
result = getNewInstruction(oldInstruction)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -409,6 +375,14 @@ private module Cached {
|
|||||||
|
|
||||||
private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr }
|
private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr }
|
||||||
|
|
||||||
|
private ChiInstruction getChi(OldInstruction primaryInstr) {
|
||||||
|
result = chiInstruction(_, _, primaryInstr)
|
||||||
|
}
|
||||||
|
|
||||||
|
private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) {
|
||||||
|
result = phiInstruction(_, _, defBlock.getFirstInstruction(), defLocation)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if instruction `def` needs to have a `Chi` instruction inserted after it, to account for a partial definition
|
* Holds if instruction `def` needs to have a `Chi` instruction inserted after it, to account for a partial definition
|
||||||
* of a virtual variable. The `Chi` instruction provides a definition of the entire virtual variable of which the
|
* of a virtual variable. The `Chi` instruction provides a definition of the entire virtual variable of which the
|
||||||
@@ -588,7 +562,7 @@ module DefUse {
|
|||||||
|
|
|
|
||||||
// An odd offset corresponds to the `Chi` instruction.
|
// An odd offset corresponds to the `Chi` instruction.
|
||||||
defOffset = oldOffset * 2 + 1 and
|
defOffset = oldOffset * 2 + 1 and
|
||||||
result = Chi(oldInstr) and
|
result = getChi(oldInstr) and
|
||||||
(
|
(
|
||||||
defLocation = Alias::getResultMemoryLocation(oldInstr) or
|
defLocation = Alias::getResultMemoryLocation(oldInstr) or
|
||||||
defLocation = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable()
|
defLocation = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable()
|
||||||
@@ -607,7 +581,7 @@ module DefUse {
|
|||||||
or
|
or
|
||||||
defOffset = -1 and
|
defOffset = -1 and
|
||||||
hasDefinition(_, defLocation, defBlock, defOffset) and
|
hasDefinition(_, defLocation, defBlock, defOffset) and
|
||||||
result = Phi(defBlock, defLocation) and
|
result = getPhi(defBlock, defLocation) and
|
||||||
actualDefLocation = defLocation
|
actualDefLocation = defLocation
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -891,7 +865,7 @@ private module CachedForDebugging {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(Alias::MemoryLocation location, OldBlock phiBlock, string specificity |
|
exists(Alias::MemoryLocation location, OldBlock phiBlock, string specificity |
|
||||||
instr = Phi(phiBlock, location) and
|
instr = getPhi(phiBlock, location) and
|
||||||
result =
|
result =
|
||||||
"Phi Block(" + phiBlock.getUniqueId() + ")[" + specificity + "]: " + location.getUniqueId() and
|
"Phi Block(" + phiBlock.getUniqueId() + ")[" + specificity + "]: " + location.getUniqueId() and
|
||||||
if location instanceof Alias::VirtualVariable
|
if location instanceof Alias::VirtualVariable
|
||||||
@@ -901,7 +875,7 @@ private module CachedForDebugging {
|
|||||||
else specificity = "s"
|
else specificity = "s"
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
instr = Unreached(_) and
|
instr = unreachedInstruction(_) and
|
||||||
result = "Unreached"
|
result = "Unreached"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -961,3 +935,44 @@ 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.
|
||||||
|
*/
|
||||||
|
cached
|
||||||
|
module SSA {
|
||||||
|
class MemoryLocation = Alias::MemoryLocation;
|
||||||
|
|
||||||
|
cached
|
||||||
|
predicate hasPhiInstruction(
|
||||||
|
IRFunction irFunc, Language::LanguageType resultType, OldInstruction blockStartInstr,
|
||||||
|
Alias::MemoryLocation defLocation
|
||||||
|
) {
|
||||||
|
exists(OldBlock oldBlock |
|
||||||
|
definitionHasPhiNode(defLocation, oldBlock) and
|
||||||
|
irFunc = oldBlock.getEnclosingIRFunction() and
|
||||||
|
blockStartInstr = oldBlock.getFirstInstruction() and
|
||||||
|
resultType = defLocation.getType()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
cached
|
||||||
|
predicate hasChiInstruction(
|
||||||
|
IRFunctionBase irFunc, Language::LanguageType resultType, OldInstruction primaryInstruction
|
||||||
|
) {
|
||||||
|
exists(Alias::VirtualVariable vvar |
|
||||||
|
hasChiNode(vvar, primaryInstruction) and
|
||||||
|
irFunc = primaryInstruction.getEnclosingIRFunction() and
|
||||||
|
resultType = vvar.getType()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
cached
|
||||||
|
predicate hasUnreachedInstruction(IRFunction irFunc) {
|
||||||
|
exists(OldInstruction oldInstruction |
|
||||||
|
irFunc = oldInstruction.getEnclosingIRFunction() and
|
||||||
|
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user