Merge pull request #3612 from dbartol/github/codeql-c-analysis-team/69_union

C++: Share `TInstruction` across IR stages
This commit is contained in:
Jonas Jensen
2020-06-19 16:03:11 +02:00
committed by GitHub
53 changed files with 1297 additions and 1158 deletions

View File

@@ -96,10 +96,18 @@
"cpp/ql/src/semmle/code/cpp/ir/implementation/UseSoundEscapeAnalysis.qll",
"csharp/ql/src/experimental/ir/implementation/UseSoundEscapeAnalysis.qll"
],
"IR IRFunctionBase": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBase.qll",
"csharp/ql/src/experimental/ir/implementation/internal/IRFunctionBase.qll"
],
"IR Operand Tag": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll",
"csharp/ql/src/experimental/ir/implementation/internal/OperandTag.qll"
],
"IR TInstruction":[
"cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll",
"csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll"
],
"IR TIRVariable":[
"cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TIRVariable.qll",
"csharp/ql/src/experimental/ir/implementation/internal/TIRVariable.qll"
@@ -177,6 +185,11 @@
"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"
],
"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": [
"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",
@@ -287,6 +300,10 @@
"csharp/ql/src/experimental/ir/implementation/raw/internal/IRBlockImports.qll",
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll"
],
"C# IR IRFunctionImports": [
"csharp/ql/src/experimental/ir/implementation/raw/internal/IRFunctionImports.qll",
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll"
],
"C# IR IRVariableImports": [
"csharp/ql/src/experimental/ir/implementation/raw/internal/IRVariableImports.qll",
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll"

View File

@@ -23,7 +23,7 @@ import semmle.code.cpp.ir.ValueNumbering
class NullInstruction extends ConstantValueInstruction {
NullInstruction() {
this.getValue() = "0" and
this.getResultType().getUnspecifiedType() instanceof PointerType
this.getResultIRType() instanceof IRAddressType
}
}
@@ -44,8 +44,8 @@ predicate explicitNullTestOfInstruction(Instruction checked, Instruction bool) {
bool =
any(ConvertInstruction convert |
checked = convert.getUnary() and
convert.getResultType() instanceof BoolType and
checked.getResultType() instanceof PointerType
convert.getResultIRType() instanceof IRBooleanType and
checked.getResultIRType() instanceof IRAddressType
)
}

View File

@@ -128,8 +128,13 @@ private class SideEffectOutNode extends OutNode {
* `kind`.
*/
OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) {
result.getCall() = call and
result.getReturnKind() = kind
// There should be only one `OutNode` for a given `(call, kind)` pair. Showing the optimizer that
// this is true helps it make better decisions downstream, especially in virtual dispatch.
result =
unique(OutNode outNode |
outNode.getCall() = call and
outNode.getReturnKind() = kind
)
}
/**

View File

@@ -111,6 +111,8 @@ private class IRSizedType extends IRType {
this = TIRFunctionAddressType(byteSize) or
this = TIROpaqueType(_, byteSize)
}
// Don't override `getByteSize()` here. The optimizer seems to generate better code when this is
// overridden only in the leaf classes.
}
/**
@@ -128,7 +130,7 @@ class IRBooleanType extends IRSizedType, TIRBooleanType {
}
/**
* A numberic type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and
* A numeric type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and
* `IRFloatingPointType`.
*/
class IRNumericType extends IRSizedType {
@@ -137,13 +139,27 @@ class IRNumericType extends IRSizedType {
this = TIRUnsignedIntegerType(byteSize) or
this = TIRFloatingPointType(byteSize, _, _)
}
// Don't override `getByteSize()` here. The optimizer seems to generate better code when this is
// overridden only in the leaf classes.
}
/**
* An integer type. This includes `IRSignedIntegerType` and `IRUnsignedIntegerType`.
*/
class IRIntegerType extends IRNumericType {
IRIntegerType() {
this = TIRSignedIntegerType(byteSize) or
this = TIRUnsignedIntegerType(byteSize)
}
// Don't override `getByteSize()` here. The optimizer seems to generate better code when this is
// overridden only in the leaf classes.
}
/**
* A signed two's-complement integer. Also used to represent enums whose underlying type is a signed
* integer, as well as character types whose representation is signed.
*/
class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType {
class IRSignedIntegerType extends IRIntegerType, TIRSignedIntegerType {
final override string toString() { result = "int" + byteSize.toString() }
final override Language::LanguageType getCanonicalLanguageType() {
@@ -158,7 +174,7 @@ class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType {
* An unsigned two's-complement integer. Also used to represent enums whose underlying type is an
* unsigned integer, as well as character types whose representation is unsigned.
*/
class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType {
class IRUnsignedIntegerType extends IRIntegerType, TIRUnsignedIntegerType {
final override string toString() { result = "uint" + byteSize.toString() }
final override Language::LanguageType getCanonicalLanguageType() {

View File

@@ -1,29 +1,12 @@
private import internal.IRInternal
private import internal.IRFunctionImports as Imports
import Imports::IRFunctionBase
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 {
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() }
class IRFunction extends IRFunctionBase {
/**
* Gets the entry point for this function.
*/

View File

@@ -29,7 +29,13 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil
/**
* 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() }
/**
@@ -194,14 +200,14 @@ class Instruction extends Construction::TInstruction {
* conversion.
*/
final Language::Expr getConvertedResultExpression() {
result = Construction::getInstructionConvertedResultExpression(this)
result = Raw::getInstructionConvertedResultExpression(this)
}
/**
* Gets the unconverted form of the `Expr` whose result is computed by this instruction, if any.
*/
final Language::Expr getUnconvertedResultExpression() {
result = Construction::getInstructionUnconvertedResultExpression(this)
result = Raw::getInstructionUnconvertedResultExpression(this)
}
final Language::LanguageType getResultLanguageType() {
@@ -212,6 +218,7 @@ class Instruction extends Construction::TInstruction {
* Gets the type of the result produced by this instruction. If the instruction does not produce
* a result, its result type will be `IRVoidType`.
*/
cached
final IRType getResultIRType() { result = getResultLanguageType().getIRType() }
/**
@@ -250,7 +257,7 @@ class Instruction extends Construction::TInstruction {
* result of the `Load` instruction is a prvalue of type `int`, representing
* 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
@@ -259,7 +266,7 @@ class Instruction extends Construction::TInstruction {
* If `this.isGLValue()` holds for this instruction, the value of
* `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.
@@ -395,7 +402,7 @@ class Instruction extends Construction::TInstruction {
class VariableInstruction extends Instruction {
IRVariable var;
VariableInstruction() { var = Construction::getInstructionVariable(this) }
VariableInstruction() { var = Raw::getInstructionVariable(this) }
override string getImmediateString() { result = var.toString() }
@@ -410,7 +417,7 @@ class VariableInstruction extends Instruction {
class FieldInstruction extends Instruction {
Language::Field field;
FieldInstruction() { field = Construction::getInstructionField(this) }
FieldInstruction() { field = Raw::getInstructionField(this) }
final override string getImmediateString() { result = field.toString() }
@@ -420,7 +427,7 @@ class FieldInstruction extends Instruction {
class FunctionInstruction extends Instruction {
Language::Function funcSymbol;
FunctionInstruction() { funcSymbol = Construction::getInstructionFunction(this) }
FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) }
final override string getImmediateString() { result = funcSymbol.toString() }
@@ -430,7 +437,7 @@ class FunctionInstruction extends Instruction {
class ConstantValueInstruction extends Instruction {
string value;
ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) }
ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) }
final override string getImmediateString() { result = value }
@@ -440,7 +447,7 @@ class ConstantValueInstruction extends Instruction {
class IndexedInstruction extends Instruction {
int index;
IndexedInstruction() { index = Construction::getInstructionIndex(this) }
IndexedInstruction() { index = Raw::getInstructionIndex(this) }
final override string getImmediateString() { result = index.toString() }
@@ -603,11 +610,16 @@ class ConstantInstruction extends ConstantValueInstruction {
}
class IntegerConstantInstruction extends ConstantInstruction {
IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType }
IntegerConstantInstruction() {
exists(IRType resultType |
resultType = getResultIRType() and
(resultType instanceof IRIntegerType or resultType instanceof IRBooleanType)
)
}
}
class FloatConstantInstruction extends ConstantInstruction {
FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType }
FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType }
}
class StringConstantInstruction extends VariableInstruction {
@@ -704,7 +716,7 @@ class PointerArithmeticInstruction extends BinaryInstruction {
PointerArithmeticInstruction() {
getOpcode() instanceof PointerArithmeticOpcode and
elementSize = Construction::getInstructionElementSize(this)
elementSize = Raw::getInstructionElementSize(this)
}
final override string getImmediateString() { result = elementSize.toString() }
@@ -753,7 +765,7 @@ class InheritanceConversionInstruction extends UnaryInstruction {
Language::Class derivedClass;
InheritanceConversionInstruction() {
Construction::getInstructionInheritance(this, baseClass, derivedClass)
Raw::getInstructionInheritance(this, baseClass, derivedClass)
}
final override string getImmediateString() {
@@ -1216,7 +1228,7 @@ class CatchByTypeInstruction extends CatchInstruction {
CatchByTypeInstruction() {
getOpcode() instanceof Opcode::CatchByType and
exceptionType = Construction::getInstructionExceptionType(this)
exceptionType = Raw::getInstructionExceptionType(this)
}
final override string getImmediateString() { result = exceptionType.toString() }
@@ -1362,7 +1374,7 @@ class BuiltInOperationInstruction extends Instruction {
BuiltInOperationInstruction() {
getOpcode() instanceof BuiltInOperationOpcode and
operation = Construction::getInstructionBuiltInOperation(this)
operation = Raw::getInstructionBuiltInOperation(this)
}
final Language::BuiltInOperation getBuiltInOperation() { result = operation }

View File

@@ -0,0 +1 @@
import semmle.code.cpp.ir.implementation.internal.IRFunctionBase as IRFunctionBase

View File

@@ -1,3 +1,4 @@
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import SSAConstruction as Construction
import semmle.code.cpp.ir.implementation.IRConfiguration as IRConfiguration
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction::Raw as Raw

View File

@@ -1,5 +1,11 @@
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 class OldBlock = Reachability::ReachableBlock;
@@ -10,54 +16,47 @@ import Cached
cached
private module Cached {
cached
predicate hasPhiInstructionCached(
OldInstruction blockStartInstr, Alias::MemoryLocation defLocation
) {
exists(OldBlock oldBlock |
definitionHasPhiNode(defLocation, oldBlock) and
blockStartInstr = oldBlock.getFirstInstruction()
)
}
cached
predicate hasChiInstructionCached(OldInstruction primaryInstruction) {
hasChiNode(_, primaryInstruction)
}
cached
predicate hasUnreachedInstructionCached(IRFunction irFunc) {
exists(OldInstruction oldInstruction |
irFunc = oldInstruction.getEnclosingIRFunction() and
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
)
}
class TStageInstruction =
TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction;
cached
predicate hasInstruction(TStageInstruction instr) {
instr instanceof TRawInstruction and instr instanceof OldInstruction
or
instr instanceof TPhiInstruction
or
instr instanceof TChiInstruction
or
instr instanceof TUnreachedInstruction
}
private IRBlock getNewBlock(OldBlock oldBlock) {
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
}
cached
predicate functionHasIR(Language::Function func) {
exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func)
}
cached
OldInstruction getOldInstruction(Instruction instr) { instr = WrappedInstruction(result) }
private IRVariable getNewIRVariable(OldIR::IRVariable var) {
// This is just a type cast. Both classes derive from the same newtype.
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
predicate hasModeledMemoryResult(Instruction instruction) {
exists(Alias::getResultMemoryLocation(getOldInstruction(instruction))) or
@@ -73,7 +72,7 @@ private module Cached {
or
// Chi instructions track virtual variables, and therefore a chi instruction is
// 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::AliasedVirtualVariable
)
@@ -81,7 +80,7 @@ private module Cached {
// Phi instructions track locations, and therefore a phi instruction is
// conflated if it's associated with a conflated location.
exists(Alias::MemoryLocation location |
instruction = Phi(_, location) and
instruction = getPhi(_, location) and
not exists(location.getAllocation())
)
}
@@ -128,7 +127,7 @@ private module Cached {
hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result)
)
or
instruction = Chi(getOldInstruction(result)) and
instruction = getChi(getOldInstruction(result)) and
tag instanceof ChiPartialOperandTag and
overlap instanceof MustExactlyOverlap
or
@@ -172,13 +171,15 @@ private module Cached {
pragma[noopt]
cached
Instruction getPhiOperandDefinition(Phi instr, IRBlock newPredecessorBlock, Overlap overlap) {
Instruction getPhiOperandDefinition(
PhiInstruction instr, IRBlock newPredecessorBlock, Overlap overlap
) {
exists(
Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock,
OldBlock predBlock, OldBlock defBlock, int defOffset, Alias::MemoryLocation actualDefLocation
|
hasPhiOperandDefinition(defLocation, useLocation, phiBlock, predBlock, defBlock, defOffset) and
instr = Phi(phiBlock, useLocation) and
instr = getPhi(phiBlock, useLocation) and
newPredecessorBlock = getNewBlock(predBlock) and
result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, actualDefLocation) and
overlap = Alias::getOverlap(actualDefLocation, useLocation)
@@ -191,7 +192,7 @@ private module Cached {
Alias::VirtualVariable vvar, OldInstruction oldInstr, Alias::MemoryLocation defLocation,
OldBlock defBlock, int defRank, int defOffset, OldBlock useBlock, int useRank
|
chiInstr = Chi(oldInstr) and
chiInstr = getChi(oldInstr) and
vvar = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() and
hasDefinitionAtRank(vvar, defLocation, defBlock, defRank, defOffset) and
hasUseAtRank(vvar, useBlock, useRank, oldInstr) and
@@ -203,21 +204,11 @@ private module Cached {
cached
Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
exists(OldBlock oldBlock |
instr = Phi(oldBlock, _) and
instr = getPhi(oldBlock, _) and
result = getNewInstruction(oldBlock.getFirstInstruction())
)
}
cached
Language::Expr getInstructionConvertedResultExpression(Instruction instruction) {
result = getOldInstruction(instruction).getConvertedResultExpression()
}
cached
Language::Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
result = getOldInstruction(instruction).getUnconvertedResultExpression()
}
/*
* This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node,
* that node is its successor in the new successor relation, and the Chi node's successors are
@@ -228,20 +219,20 @@ private module Cached {
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
if hasChiNode(_, getOldInstruction(instruction))
then
result = Chi(getOldInstruction(instruction)) and
result = getChi(getOldInstruction(instruction)) and
kind instanceof GotoEdge
else (
exists(OldInstruction oldInstruction |
oldInstruction = getOldInstruction(instruction) and
(
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
then result = Unreached(instruction.getEnclosingFunction())
then result = unreachedInstruction(instruction.getEnclosingIRFunction())
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
)
)
or
exists(OldInstruction oldInstruction |
instruction = Chi(oldInstruction) and
instruction = getChi(oldInstruction) and
result = getNewInstruction(oldInstruction.getSuccessor(kind))
)
)
@@ -260,137 +251,73 @@ private module Cached {
// `oldInstruction`, in which case the back edge should come out of the
// chi node instead.
if hasChiNode(_, oldInstruction)
then instruction = Chi(oldInstruction)
then instruction = getChi(oldInstruction)
else instruction = getNewInstruction(oldInstruction)
)
}
cached
Language::AST getInstructionAST(Instruction instruction) {
exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction)
or
instruction = Chi(oldInstruction)
|
result = oldInstruction.getAST()
Language::AST getInstructionAST(Instruction instr) {
result = getOldInstruction(instr).getAST()
or
exists(RawIR::Instruction blockStartInstr |
instr = phiInstruction(blockStartInstr, _) and
result = blockStartInstr.getAST()
)
or
exists(OldBlock block |
instruction = Phi(block, _) and
result = block.getFirstInstruction().getAST()
exists(RawIR::Instruction primaryInstr |
instr = chiInstruction(primaryInstr) and
result = primaryInstr.getAST()
)
or
instruction = Unreached(result)
exists(IRFunctionBase irFunc |
instr = unreachedInstruction(irFunc) and result = irFunc.getFunction()
)
}
cached
Language::LanguageType getInstructionResultType(Instruction instruction) {
exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction) and
result = oldInstruction.getResultLanguageType()
Language::LanguageType getInstructionResultType(Instruction instr) {
result = instr.(RawIR::Instruction).getResultLanguageType()
or
exists(Alias::MemoryLocation defLocation |
instr = phiInstruction(_, defLocation) and
result = defLocation.getType()
)
or
exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar |
instruction = Chi(oldInstruction) and
hasChiNode(vvar, oldInstruction) and
exists(Instruction primaryInstr, Alias::VirtualVariable vvar |
instr = chiInstruction(primaryInstr) and
hasChiNode(vvar, primaryInstr) and
result = vvar.getType()
)
or
exists(Alias::MemoryLocation location |
instruction = Phi(_, location) and
result = location.getType()
instr = unreachedInstruction(_) and result = Language::getVoidType()
}
cached
Opcode getInstructionOpcode(Instruction instr) {
result = getOldInstruction(instr).getOpcode()
or
instr = phiInstruction(_, _) and result instanceof Opcode::Phi
or
instr = chiInstruction(_) and result instanceof Opcode::Chi
or
instr = unreachedInstruction(_) and result instanceof Opcode::Unreached
}
cached
IRFunctionBase getInstructionEnclosingIRFunction(Instruction instr) {
result = getOldInstruction(instr).getEnclosingIRFunction()
or
exists(OldInstruction blockStartInstr |
instr = phiInstruction(blockStartInstr, _) and
result = blockStartInstr.getEnclosingIRFunction()
)
or
instruction = Unreached(_) and
result = Language::getVoidType()
}
cached
Opcode getInstructionOpcode(Instruction instruction) {
exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction) and
result = oldInstruction.getOpcode()
exists(OldInstruction primaryInstr |
instr = chiInstruction(primaryInstr) and result = primaryInstr.getEnclosingIRFunction()
)
or
instruction instanceof Chi and
result instanceof Opcode::Chi
or
instruction instanceof Phi and
result instanceof Opcode::Phi
or
instruction instanceof Unreached and
result instanceof Opcode::Unreached
}
cached
IRFunction getInstructionEnclosingIRFunction(Instruction instruction) {
exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction)
or
instruction = Chi(oldInstruction)
|
result.getFunction() = oldInstruction.getEnclosingFunction()
)
or
exists(OldBlock block |
instruction = Phi(block, _) and
result.getFunction() = block.getEnclosingFunction()
)
or
instruction = Unreached(result.getFunction())
}
cached
IRVariable getInstructionVariable(Instruction instruction) {
result =
getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getIRVariable())
}
cached
Language::Field getInstructionField(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField()
}
cached
int getInstructionIndex(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::IndexedInstruction).getIndex()
}
cached
Language::Function getInstructionFunction(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol()
}
cached
string getInstructionConstantValue(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue()
}
cached
Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) {
result =
getOldInstruction(instruction).(OldIR::BuiltInOperationInstruction).getBuiltInOperation()
}
cached
Language::LanguageType getInstructionExceptionType(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType()
}
cached
int getInstructionElementSize(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::PointerArithmeticInstruction).getElementSize()
}
cached
predicate getInstructionInheritance(
Instruction instruction, Language::Class baseClass, Language::Class derivedClass
) {
exists(OldIR::InheritanceConversionInstruction oldInstr |
oldInstr = getOldInstruction(instruction) and
baseClass = oldInstr.getBaseClass() and
derivedClass = oldInstr.getDerivedClass()
)
instr = unreachedInstruction(result)
}
cached
@@ -401,7 +328,7 @@ private module Cached {
)
or
exists(OldIR::Instruction oldInstruction |
instruction = Chi(oldInstruction) and
instruction = getChi(oldInstruction) and
result = getNewInstruction(oldInstruction)
)
}
@@ -409,6 +336,14 @@ private module Cached {
private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr }
private OldInstruction getOldInstruction(Instruction instr) { instr = result }
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
* of a virtual variable. The `Chi` instruction provides a definition of the entire virtual variable of which the
@@ -588,7 +523,7 @@ module DefUse {
|
// An odd offset corresponds to the `Chi` instruction.
defOffset = oldOffset * 2 + 1 and
result = Chi(oldInstr) and
result = getChi(oldInstr) and
(
defLocation = Alias::getResultMemoryLocation(oldInstr) or
defLocation = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable()
@@ -607,7 +542,7 @@ module DefUse {
or
defOffset = -1 and
hasDefinition(_, defLocation, defBlock, defOffset) and
result = Phi(defBlock, defLocation) and
result = getPhi(defBlock, defLocation) and
actualDefLocation = defLocation
}
@@ -891,7 +826,7 @@ private module CachedForDebugging {
)
or
exists(Alias::MemoryLocation location, OldBlock phiBlock, string specificity |
instr = Phi(phiBlock, location) and
instr = getPhi(phiBlock, location) and
result =
"Phi Block(" + phiBlock.getUniqueId() + ")[" + specificity + "]: " + location.getUniqueId() and
if location instanceof Alias::VirtualVariable
@@ -901,7 +836,7 @@ private module CachedForDebugging {
else specificity = "s"
)
or
instr = Unreached(_) and
instr = unreachedInstruction(_) and
result = "Unreached"
}
@@ -961,3 +896,19 @@ module SSAConsistency {
)
}
}
/**
* Provides the portion of the parameterized IR interface that is used to construct the SSA stages
* of the IR. The raw stage of the IR does not expose these predicates.
* These predicates are all just aliases for predicates defined in the `Cached` module. This ensures
* that all of SSA construction will be evaluated in the same stage.
*/
module SSA {
class MemoryLocation = Alias::MemoryLocation;
predicate hasPhiInstruction = Cached::hasPhiInstructionCached/2;
predicate hasChiInstruction = Cached::hasChiInstructionCached/1;
predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1;
}

View File

@@ -1,3 +1,5 @@
import semmle.code.cpp.ir.implementation.Opcode
import semmle.code.cpp.ir.implementation.internal.OperandTag
import semmle.code.cpp.ir.internal.Overlap
import semmle.code.cpp.ir.implementation.Opcode as Opcode
import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag
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

View File

@@ -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.Dominance as Dominance
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 AliasedSSA as Alias

View File

@@ -0,0 +1,27 @@
/**
* Provides a base class, `IRFunctionBase`, for the stage-independent portions of `IRFunction`.
*/
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() }
}

View File

@@ -0,0 +1,2 @@
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction

View File

@@ -1,5 +1,5 @@
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_
module Imports {

View File

@@ -0,0 +1,97 @@
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.
*/
cached
newtype TInstruction =
TRawInstruction(
IRConstruction::Raw::InstructionTag1 tag1, IRConstruction::Raw::InstructionTag2 tag2
) {
IRConstruction::Raw::hasInstruction(tag1, tag2)
} or
TUnaliasedSSAPhiInstruction(
TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation
) {
UnaliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation)
} or
TUnaliasedSSAChiInstruction(TRawInstruction primaryInstruction) { none() } or
TUnaliasedSSAUnreachedInstruction(IRFunctionBase irFunc) {
UnaliasedSSA::SSA::hasUnreachedInstruction(irFunc)
} or
TAliasedSSAPhiInstruction(
TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation
) {
AliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation)
} or
TAliasedSSAChiInstruction(TRawInstruction primaryInstruction) {
AliasedSSA::SSA::hasChiInstruction(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(
TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation
) {
result = TUnaliasedSSAPhiInstruction(blockStartInstr, memoryLocation)
}
class TChiInstruction = TUnaliasedSSAChiInstruction;
TChiInstruction chiInstruction(TRawInstruction primaryInstruction) {
result = TUnaliasedSSAChiInstruction(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(
TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation
) {
result = TAliasedSSAPhiInstruction(blockStartInstr, memoryLocation)
}
class TChiInstruction = TAliasedSSAChiInstruction;
TChiInstruction chiInstruction(TRawInstruction primaryInstruction) {
result = TAliasedSSAChiInstruction(primaryInstruction)
}
class TUnreachedInstruction = TAliasedSSAUnreachedInstruction;
TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) {
result = TAliasedSSAUnreachedInstruction(irFunc)
}
}

View File

@@ -0,0 +1,2 @@
import semmle.code.cpp.ir.implementation.IRType as IRType
import semmle.code.cpp.ir.implementation.Opcode as Opcode

View File

@@ -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

View File

@@ -1,29 +1,12 @@
private import internal.IRInternal
private import internal.IRFunctionImports as Imports
import Imports::IRFunctionBase
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 {
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() }
class IRFunction extends IRFunctionBase {
/**
* Gets the entry point for this function.
*/

View File

@@ -29,7 +29,13 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil
/**
* 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() }
/**
@@ -194,14 +200,14 @@ class Instruction extends Construction::TInstruction {
* conversion.
*/
final Language::Expr getConvertedResultExpression() {
result = Construction::getInstructionConvertedResultExpression(this)
result = Raw::getInstructionConvertedResultExpression(this)
}
/**
* Gets the unconverted form of the `Expr` whose result is computed by this instruction, if any.
*/
final Language::Expr getUnconvertedResultExpression() {
result = Construction::getInstructionUnconvertedResultExpression(this)
result = Raw::getInstructionUnconvertedResultExpression(this)
}
final Language::LanguageType getResultLanguageType() {
@@ -212,6 +218,7 @@ class Instruction extends Construction::TInstruction {
* Gets the type of the result produced by this instruction. If the instruction does not produce
* a result, its result type will be `IRVoidType`.
*/
cached
final IRType getResultIRType() { result = getResultLanguageType().getIRType() }
/**
@@ -250,7 +257,7 @@ class Instruction extends Construction::TInstruction {
* result of the `Load` instruction is a prvalue of type `int`, representing
* 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
@@ -259,7 +266,7 @@ class Instruction extends Construction::TInstruction {
* If `this.isGLValue()` holds for this instruction, the value of
* `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.
@@ -395,7 +402,7 @@ class Instruction extends Construction::TInstruction {
class VariableInstruction extends Instruction {
IRVariable var;
VariableInstruction() { var = Construction::getInstructionVariable(this) }
VariableInstruction() { var = Raw::getInstructionVariable(this) }
override string getImmediateString() { result = var.toString() }
@@ -410,7 +417,7 @@ class VariableInstruction extends Instruction {
class FieldInstruction extends Instruction {
Language::Field field;
FieldInstruction() { field = Construction::getInstructionField(this) }
FieldInstruction() { field = Raw::getInstructionField(this) }
final override string getImmediateString() { result = field.toString() }
@@ -420,7 +427,7 @@ class FieldInstruction extends Instruction {
class FunctionInstruction extends Instruction {
Language::Function funcSymbol;
FunctionInstruction() { funcSymbol = Construction::getInstructionFunction(this) }
FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) }
final override string getImmediateString() { result = funcSymbol.toString() }
@@ -430,7 +437,7 @@ class FunctionInstruction extends Instruction {
class ConstantValueInstruction extends Instruction {
string value;
ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) }
ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) }
final override string getImmediateString() { result = value }
@@ -440,7 +447,7 @@ class ConstantValueInstruction extends Instruction {
class IndexedInstruction extends Instruction {
int index;
IndexedInstruction() { index = Construction::getInstructionIndex(this) }
IndexedInstruction() { index = Raw::getInstructionIndex(this) }
final override string getImmediateString() { result = index.toString() }
@@ -603,11 +610,16 @@ class ConstantInstruction extends ConstantValueInstruction {
}
class IntegerConstantInstruction extends ConstantInstruction {
IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType }
IntegerConstantInstruction() {
exists(IRType resultType |
resultType = getResultIRType() and
(resultType instanceof IRIntegerType or resultType instanceof IRBooleanType)
)
}
}
class FloatConstantInstruction extends ConstantInstruction {
FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType }
FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType }
}
class StringConstantInstruction extends VariableInstruction {
@@ -704,7 +716,7 @@ class PointerArithmeticInstruction extends BinaryInstruction {
PointerArithmeticInstruction() {
getOpcode() instanceof PointerArithmeticOpcode and
elementSize = Construction::getInstructionElementSize(this)
elementSize = Raw::getInstructionElementSize(this)
}
final override string getImmediateString() { result = elementSize.toString() }
@@ -753,7 +765,7 @@ class InheritanceConversionInstruction extends UnaryInstruction {
Language::Class derivedClass;
InheritanceConversionInstruction() {
Construction::getInstructionInheritance(this, baseClass, derivedClass)
Raw::getInstructionInheritance(this, baseClass, derivedClass)
}
final override string getImmediateString() {
@@ -1216,7 +1228,7 @@ class CatchByTypeInstruction extends CatchInstruction {
CatchByTypeInstruction() {
getOpcode() instanceof Opcode::CatchByType and
exceptionType = Construction::getInstructionExceptionType(this)
exceptionType = Raw::getInstructionExceptionType(this)
}
final override string getImmediateString() { result = exceptionType.toString() }
@@ -1362,7 +1374,7 @@ class BuiltInOperationInstruction extends Instruction {
BuiltInOperationInstruction() {
getOpcode() instanceof BuiltInOperationOpcode and
operation = Construction::getInstructionBuiltInOperation(this)
operation = Raw::getInstructionBuiltInOperation(this)
}
final Language::BuiltInOperation getBuiltInOperation() { result = operation }

View File

@@ -1,6 +1,9 @@
private import cpp
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.IRFunctionBase
private import semmle.code.cpp.ir.implementation.internal.TInstruction
private import semmle.code.cpp.ir.implementation.internal.TIRVariable
private import semmle.code.cpp.ir.internal.CppType
private import semmle.code.cpp.ir.internal.Overlap
private import semmle.code.cpp.ir.internal.TempVariableTag
@@ -12,34 +15,36 @@ private import TranslatedStmt
private import TranslatedFunction
TranslatedElement getInstructionTranslatedElement(Instruction instruction) {
instruction = MkInstruction(result, _)
instruction = TRawInstruction(result, _)
}
InstructionTag getInstructionTag(Instruction instruction) { instruction = MkInstruction(_, result) }
import Cached
InstructionTag getInstructionTag(Instruction instruction) {
instruction = TRawInstruction(_, result)
}
/**
* 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
private module Cached {
module Raw {
class InstructionTag1 = TranslatedElement;
class InstructionTag2 = InstructionTag;
cached
predicate functionHasIR(Function func) { exists(getTranslatedFunction(func)) }
cached
newtype TInstruction =
MkInstruction(TranslatedElement element, InstructionTag tag) {
element.hasInstruction(_, tag, _)
}
predicate hasInstruction(TranslatedElement element, InstructionTag tag) {
element.hasInstruction(_, tag, _)
}
cached
predicate hasUserVariable(Function func, Variable var, CppType type) {
getTranslatedFunction(func).hasUserVariable(var, type)
}
cached
predicate hasThisVariable(Function func, CppType type) {
type = getTypeForGLValue(getTranslatedFunction(func).getThisType())
}
cached
predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag, CppType type) {
exists(TranslatedElement element |
@@ -64,232 +69,7 @@ private module Cached {
}
cached
predicate hasModeledMemoryResult(Instruction instruction) { none() }
cached
predicate hasConflatedMemoryResult(Instruction instruction) {
instruction instanceof AliasedDefinitionInstruction
or
instruction.getOpcode() instanceof Opcode::InitializeNonLocal
}
cached
Expr getInstructionConvertedResultExpression(Instruction instruction) {
exists(TranslatedExpr translatedExpr |
translatedExpr = getTranslatedExpr(result) and
instruction = translatedExpr.getResult() and
// Only associate `instruction` with this expression if the translated
// expression actually produced the instruction; not if it merely
// forwarded the result of another translated expression.
instruction = translatedExpr.getInstruction(_)
)
}
cached
Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
result = getInstructionConvertedResultExpression(instruction).getUnconverted()
}
cached
Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) {
result =
getInstructionTranslatedElement(instruction)
.getInstructionRegisterOperand(getInstructionTag(instruction), tag)
}
cached
Instruction getMemoryOperandDefinition(
Instruction instruction, MemoryOperandTag tag, Overlap overlap
) {
none()
}
/** Gets a non-phi instruction that defines an operand of `instr`. */
private Instruction getNonPhiOperandDef(Instruction instr) {
result = getRegisterOperandDefinition(instr, _)
or
result = getMemoryOperandDefinition(instr, _, _)
}
/**
* Gets a non-phi instruction that defines an operand of `instr` but only if
* both `instr` and the result have neighbor on the other side of the edge
* between them. This is a necessary condition for being in a cycle, and it
* removes about two thirds of the tuples that would otherwise be in this
* predicate.
*/
private Instruction getNonPhiOperandDefOfIntermediate(Instruction instr) {
result = getNonPhiOperandDef(instr) and
exists(getNonPhiOperandDef(result)) and
instr = getNonPhiOperandDef(_)
}
/**
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
* through a phi instruction and therefore should be impossible.
*
* If such cycles are present, either due to a programming error in the IR
* generation or due to a malformed database, it can cause infinite loops in
* analyses that assume a cycle-free graph of non-phi operands. Therefore it's
* better to remove these operands than to leave cycles in the operand graph.
*/
pragma[noopt]
cached
predicate isInCycle(Instruction instr) {
instr instanceof Instruction and
getNonPhiOperandDefOfIntermediate+(instr) = instr
}
cached
CppType getInstructionOperandType(Instruction instruction, TypedOperandTag tag) {
// For all `LoadInstruction`s, the operand type of the `LoadOperand` is the same as
// the result type of the load.
tag instanceof LoadOperandTag and
result = instruction.(LoadInstruction).getResultLanguageType()
or
not instruction instanceof LoadInstruction and
result =
getInstructionTranslatedElement(instruction)
.getInstructionMemoryOperandType(getInstructionTag(instruction), tag)
}
cached
Instruction getPhiOperandDefinition(
PhiInstruction instruction, IRBlock predecessorBlock, Overlap overlap
) {
none()
}
cached
Instruction getPhiInstructionBlockStart(PhiInstruction instr) { none() }
cached
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
result =
getInstructionTranslatedElement(instruction)
.getInstructionSuccessor(getInstructionTag(instruction), kind)
}
/**
* Holds if the CFG edge (`sourceElement`, `sourceTag`) ---`kind`-->
* `targetInstruction` is a back edge under the condition that
* `requiredAncestor` is an ancestor of `sourceElement`.
*/
private predicate backEdgeCandidate(
TranslatedElement sourceElement, InstructionTag sourceTag, TranslatedElement requiredAncestor,
Instruction targetInstruction, EdgeKind kind
) {
// While loop:
// Any edge from within the body of the loop to the condition of the loop
// is a back edge. This includes edges from `continue` and the fall-through
// edge(s) after the last instruction(s) in the body.
exists(TranslatedWhileStmt s |
targetInstruction = s.getFirstConditionInstruction() and
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
requiredAncestor = s.getBody()
)
or
// Do-while loop:
// The back edge should be the edge(s) from the condition to the
// body. This ensures that it's the back edge that will be pruned in a `do
// { ... } while (0)` statement. Note that all `continue` statements in a
// do-while loop produce forward edges.
exists(TranslatedDoStmt s |
targetInstruction = s.getBody().getFirstInstruction() and
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
requiredAncestor = s.getCondition()
)
or
// For loop:
// Any edge from within the body or update of the loop to the condition of
// the loop is a back edge. When there is no loop update expression, this
// includes edges from `continue` and the fall-through edge(s) after the
// last instruction(s) in the body. A for loop may not have a condition, in
// which case `getFirstConditionInstruction` returns the body instead.
exists(TranslatedForStmt s |
targetInstruction = s.getFirstConditionInstruction() and
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
(
requiredAncestor = s.getUpdate()
or
not exists(s.getUpdate()) and
requiredAncestor = s.getBody()
)
)
or
// Range-based for loop:
// Any edge from within the update of the loop to the condition of
// the loop is a back edge.
exists(TranslatedRangeBasedForStmt s |
targetInstruction = s.getCondition().getFirstInstruction() and
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
requiredAncestor = s.getUpdate()
)
}
private predicate jumpSourceHasAncestor(TranslatedElement jumpSource, TranslatedElement ancestor) {
backEdgeCandidate(jumpSource, _, _, _, _) and
ancestor = jumpSource
or
// For performance, we don't want a fastTC here
jumpSourceHasAncestor(jumpSource, ancestor.getAChild())
}
cached
Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) {
exists(
TranslatedElement sourceElement, InstructionTag sourceTag, TranslatedElement requiredAncestor
|
backEdgeCandidate(sourceElement, sourceTag, requiredAncestor, result, kind) and
jumpSourceHasAncestor(sourceElement, requiredAncestor) and
instruction = sourceElement.getInstruction(sourceTag)
)
or
// Goto statement:
// As a conservative approximation, any edge out of `goto` is a back edge
// unless it goes strictly forward in the program text. A `goto` whose
// source and target are both inside a macro will be seen as having the
// same location for source and target, so we conservatively assume that
// such a `goto` creates a back edge.
exists(TranslatedElement s, GotoStmt goto |
not isStrictlyForwardGoto(goto) and
goto = s.getAST() and
exists(InstructionTag tag |
result = s.getInstructionSuccessor(tag, kind) and
instruction = s.getInstruction(tag)
)
)
}
/** Holds if `goto` jumps strictly forward in the program text. */
private predicate isStrictlyForwardGoto(GotoStmt goto) {
goto.getLocation().isBefore(goto.getTarget().getLocation())
}
cached
Locatable getInstructionAST(Instruction instruction) {
result = getInstructionTranslatedElement(instruction).getAST()
}
cached
CppType getInstructionResultType(Instruction instruction) {
getInstructionTranslatedElement(instruction)
.hasInstruction(_, getInstructionTag(instruction), result)
}
cached
Opcode getInstructionOpcode(Instruction instruction) {
getInstructionTranslatedElement(instruction)
.hasInstruction(result, getInstructionTag(instruction), _)
}
cached
IRFunction getInstructionEnclosingIRFunction(Instruction instruction) {
result.getFunction() = getInstructionTranslatedElement(instruction).getFunction()
}
cached
IRVariable getInstructionVariable(Instruction instruction) {
TIRVariable getInstructionVariable(Instruction instruction) {
exists(TranslatedElement element, InstructionTag tag |
element = getInstructionTranslatedElement(instruction) and
tag = getInstructionTag(instruction) and
@@ -302,10 +82,9 @@ private module Cached {
cached
Field getInstructionField(Instruction instruction) {
exists(TranslatedElement element, InstructionTag tag |
instructionOrigin(instruction, element, tag) and
result = element.getInstructionField(tag)
)
result =
getInstructionTranslatedElement(instruction)
.getInstructionField(getInstructionTag(instruction))
}
cached
@@ -324,10 +103,9 @@ private module Cached {
cached
int getInstructionIndex(Instruction instruction) {
exists(TranslatedElement element, InstructionTag tag |
instructionOrigin(instruction, element, tag) and
result = element.getInstructionIndex(tag)
)
result =
getInstructionTranslatedElement(instruction)
.getInstructionIndex(getInstructionTag(instruction))
}
cached
@@ -350,20 +128,11 @@ private module Cached {
.getInstructionInheritance(getInstructionTag(instruction), baseClass, derivedClass)
}
pragma[noinline]
private predicate instructionOrigin(
Instruction instruction, TranslatedElement element, InstructionTag tag
) {
element = getInstructionTranslatedElement(instruction) and
tag = getInstructionTag(instruction)
}
cached
int getInstructionElementSize(Instruction instruction) {
exists(TranslatedElement element, InstructionTag tag |
instructionOrigin(instruction, element, tag) and
result = element.getInstructionElementSize(tag)
)
result =
getInstructionTranslatedElement(instruction)
.getInstructionElementSize(getInstructionTag(instruction))
}
cached
@@ -372,22 +141,225 @@ private module Cached {
}
cached
int getInstructionResultSize(Instruction instruction) {
exists(TranslatedElement element, InstructionTag tag |
instructionOrigin(instruction, element, tag) and
result = element.getInstructionResultSize(tag)
Expr getInstructionConvertedResultExpression(Instruction instruction) {
exists(TranslatedExpr translatedExpr |
translatedExpr = getTranslatedExpr(result) and
instruction = translatedExpr.getResult() and
// Only associate `instruction` with this expression if the translated
// expression actually produced the instruction; not if it merely
// forwarded the result of another translated expression.
instruction = translatedExpr.getInstruction(_)
)
}
cached
Instruction getPrimaryInstructionForSideEffect(Instruction instruction) {
exists(TranslatedElement element, InstructionTag tag |
instructionOrigin(instruction, element, tag) and
result = element.getPrimaryInstructionForSideEffect(tag)
)
Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
result = getInstructionConvertedResultExpression(instruction).getUnconverted()
}
}
class TStageInstruction = TRawInstruction;
predicate hasInstruction(TRawInstruction instr) { any() }
predicate hasModeledMemoryResult(Instruction instruction) { none() }
predicate hasConflatedMemoryResult(Instruction instruction) {
instruction instanceof AliasedDefinitionInstruction
or
instruction.getOpcode() instanceof Opcode::InitializeNonLocal
}
Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) {
result =
getInstructionTranslatedElement(instruction)
.getInstructionRegisterOperand(getInstructionTag(instruction), tag)
}
Instruction getMemoryOperandDefinition(
Instruction instruction, MemoryOperandTag tag, Overlap overlap
) {
none()
}
/** Gets a non-phi instruction that defines an operand of `instr`. */
private Instruction getNonPhiOperandDef(Instruction instr) {
result = getRegisterOperandDefinition(instr, _)
or
result = getMemoryOperandDefinition(instr, _, _)
}
/**
* Gets a non-phi instruction that defines an operand of `instr` but only if
* both `instr` and the result have neighbor on the other side of the edge
* between them. This is a necessary condition for being in a cycle, and it
* removes about two thirds of the tuples that would otherwise be in this
* predicate.
*/
private Instruction getNonPhiOperandDefOfIntermediate(Instruction instr) {
result = getNonPhiOperandDef(instr) and
exists(getNonPhiOperandDef(result)) and
instr = getNonPhiOperandDef(_)
}
/**
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
* through a phi instruction and therefore should be impossible.
*
* If such cycles are present, either due to a programming error in the IR
* generation or due to a malformed database, it can cause infinite loops in
* analyses that assume a cycle-free graph of non-phi operands. Therefore it's
* better to remove these operands than to leave cycles in the operand graph.
*/
pragma[noopt]
predicate isInCycle(Instruction instr) {
instr instanceof Instruction and
getNonPhiOperandDefOfIntermediate+(instr) = instr
}
CppType getInstructionOperandType(Instruction instruction, TypedOperandTag tag) {
// For all `LoadInstruction`s, the operand type of the `LoadOperand` is the same as
// the result type of the load.
tag instanceof LoadOperandTag and
result = instruction.(LoadInstruction).getResultLanguageType()
or
not instruction instanceof LoadInstruction and
result =
getInstructionTranslatedElement(instruction)
.getInstructionMemoryOperandType(getInstructionTag(instruction), tag)
}
Instruction getPhiOperandDefinition(
PhiInstruction instruction, IRBlock predecessorBlock, Overlap overlap
) {
none()
}
Instruction getPhiInstructionBlockStart(PhiInstruction instr) { none() }
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
result =
getInstructionTranslatedElement(instruction)
.getInstructionSuccessor(getInstructionTag(instruction), kind)
}
/**
* Holds if the CFG edge (`sourceElement`, `sourceTag`) ---`kind`-->
* `targetInstruction` is a back edge under the condition that
* `requiredAncestor` is an ancestor of `sourceElement`.
*/
private predicate backEdgeCandidate(
TranslatedElement sourceElement, InstructionTag sourceTag, TranslatedElement requiredAncestor,
Instruction targetInstruction, EdgeKind kind
) {
// While loop:
// Any edge from within the body of the loop to the condition of the loop
// is a back edge. This includes edges from `continue` and the fall-through
// edge(s) after the last instruction(s) in the body.
exists(TranslatedWhileStmt s |
targetInstruction = s.getFirstConditionInstruction() and
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
requiredAncestor = s.getBody()
)
or
// Do-while loop:
// The back edge should be the edge(s) from the condition to the
// body. This ensures that it's the back edge that will be pruned in a `do
// { ... } while (0)` statement. Note that all `continue` statements in a
// do-while loop produce forward edges.
exists(TranslatedDoStmt s |
targetInstruction = s.getBody().getFirstInstruction() and
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
requiredAncestor = s.getCondition()
)
or
// For loop:
// Any edge from within the body or update of the loop to the condition of
// the loop is a back edge. When there is no loop update expression, this
// includes edges from `continue` and the fall-through edge(s) after the
// last instruction(s) in the body. A for loop may not have a condition, in
// which case `getFirstConditionInstruction` returns the body instead.
exists(TranslatedForStmt s |
targetInstruction = s.getFirstConditionInstruction() and
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
(
requiredAncestor = s.getUpdate()
or
not exists(s.getUpdate()) and
requiredAncestor = s.getBody()
)
)
or
// Range-based for loop:
// Any edge from within the update of the loop to the condition of
// the loop is a back edge.
exists(TranslatedRangeBasedForStmt s |
targetInstruction = s.getCondition().getFirstInstruction() and
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
requiredAncestor = s.getUpdate()
)
}
private predicate jumpSourceHasAncestor(TranslatedElement jumpSource, TranslatedElement ancestor) {
backEdgeCandidate(jumpSource, _, _, _, _) and
ancestor = jumpSource
or
// For performance, we don't want a fastTC here
jumpSourceHasAncestor(jumpSource, ancestor.getAChild())
}
Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) {
exists(
TranslatedElement sourceElement, InstructionTag sourceTag, TranslatedElement requiredAncestor
|
backEdgeCandidate(sourceElement, sourceTag, requiredAncestor, result, kind) and
jumpSourceHasAncestor(sourceElement, requiredAncestor) and
instruction = sourceElement.getInstruction(sourceTag)
)
or
// Goto statement:
// As a conservative approximation, any edge out of `goto` is a back edge
// unless it goes strictly forward in the program text. A `goto` whose
// source and target are both inside a macro will be seen as having the
// same location for source and target, so we conservatively assume that
// such a `goto` creates a back edge.
exists(TranslatedElement s, GotoStmt goto |
not isStrictlyForwardGoto(goto) and
goto = s.getAST() and
exists(InstructionTag tag |
result = s.getInstructionSuccessor(tag, kind) and
instruction = s.getInstruction(tag)
)
)
}
/** Holds if `goto` jumps strictly forward in the program text. */
private predicate isStrictlyForwardGoto(GotoStmt goto) {
goto.getLocation().isBefore(goto.getTarget().getLocation())
}
Locatable getInstructionAST(TStageInstruction instr) {
result = getInstructionTranslatedElement(instr).getAST()
}
CppType getInstructionResultType(TStageInstruction instr) {
getInstructionTranslatedElement(instr).hasInstruction(_, getInstructionTag(instr), result)
}
Opcode getInstructionOpcode(TStageInstruction instr) {
getInstructionTranslatedElement(instr).hasInstruction(result, getInstructionTag(instr), _)
}
IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) {
result.getFunction() = getInstructionTranslatedElement(instr).getFunction()
}
Instruction getPrimaryInstructionForSideEffect(SideEffectInstruction instruction) {
result =
getInstructionTranslatedElement(instruction)
.getPrimaryInstructionForSideEffect(getInstructionTag(instruction))
}
import CachedForDebugging
cached

View File

@@ -0,0 +1 @@
import semmle.code.cpp.ir.implementation.internal.IRFunctionBase as IRFunctionBase

View File

@@ -1,3 +1,4 @@
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import IRConstruction as Construction
import semmle.code.cpp.ir.implementation.IRConfiguration as IRConfiguration
import IRConstruction::Raw as Raw

View File

@@ -705,12 +705,8 @@ abstract class TranslatedElement extends TTranslatedElement {
int getInstructionElementSize(InstructionTag tag) { none() }
/**
* If the instruction specified by `tag` has a result of type `UnknownType`,
* gets the size of the result in bytes. If the result does not have a knonwn
* constant size, this predicate does not hold.
* Holds if the generated IR refers to an opaque type with size `byteSize`.
*/
int getInstructionResultSize(InstructionTag tag) { none() }
predicate needsUnknownOpaqueType(int byteSize) { none() }
/**

View File

@@ -415,17 +415,6 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati
)
}
override int getInstructionResultSize(InstructionTag tag) {
exists(int elementCount |
zeroInitRange(_, elementCount) and
(
tag = ZeroPadStringConstantTag() or
tag = ZeroPadStringStoreTag()
) and
result = elementCount * getElementType().getSize()
)
}
private Type getElementType() {
result = getContext().getTargetType().getUnspecifiedType().(ArrayType).getBaseType()
}
@@ -772,15 +761,6 @@ class TranslatedElementValueInitialization extends TranslatedElementInitializati
result = getZeroValue(getElementType())
}
override int getInstructionResultSize(InstructionTag tag) {
elementCount > 1 and
(
tag = getElementDefaultValueTag() or
tag = getElementDefaultValueStoreTag()
) and
result = elementCount * getElementType().getSize()
}
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
result = TranslatedElementInitialization.super.getInstructionRegisterOperand(tag, operandTag)
or

View File

@@ -1,29 +1,12 @@
private import internal.IRInternal
private import internal.IRFunctionImports as Imports
import Imports::IRFunctionBase
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 {
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() }
class IRFunction extends IRFunctionBase {
/**
* Gets the entry point for this function.
*/

View File

@@ -29,7 +29,13 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil
/**
* 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() }
/**
@@ -194,14 +200,14 @@ class Instruction extends Construction::TInstruction {
* conversion.
*/
final Language::Expr getConvertedResultExpression() {
result = Construction::getInstructionConvertedResultExpression(this)
result = Raw::getInstructionConvertedResultExpression(this)
}
/**
* Gets the unconverted form of the `Expr` whose result is computed by this instruction, if any.
*/
final Language::Expr getUnconvertedResultExpression() {
result = Construction::getInstructionUnconvertedResultExpression(this)
result = Raw::getInstructionUnconvertedResultExpression(this)
}
final Language::LanguageType getResultLanguageType() {
@@ -212,6 +218,7 @@ class Instruction extends Construction::TInstruction {
* Gets the type of the result produced by this instruction. If the instruction does not produce
* a result, its result type will be `IRVoidType`.
*/
cached
final IRType getResultIRType() { result = getResultLanguageType().getIRType() }
/**
@@ -250,7 +257,7 @@ class Instruction extends Construction::TInstruction {
* result of the `Load` instruction is a prvalue of type `int`, representing
* 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
@@ -259,7 +266,7 @@ class Instruction extends Construction::TInstruction {
* If `this.isGLValue()` holds for this instruction, the value of
* `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.
@@ -395,7 +402,7 @@ class Instruction extends Construction::TInstruction {
class VariableInstruction extends Instruction {
IRVariable var;
VariableInstruction() { var = Construction::getInstructionVariable(this) }
VariableInstruction() { var = Raw::getInstructionVariable(this) }
override string getImmediateString() { result = var.toString() }
@@ -410,7 +417,7 @@ class VariableInstruction extends Instruction {
class FieldInstruction extends Instruction {
Language::Field field;
FieldInstruction() { field = Construction::getInstructionField(this) }
FieldInstruction() { field = Raw::getInstructionField(this) }
final override string getImmediateString() { result = field.toString() }
@@ -420,7 +427,7 @@ class FieldInstruction extends Instruction {
class FunctionInstruction extends Instruction {
Language::Function funcSymbol;
FunctionInstruction() { funcSymbol = Construction::getInstructionFunction(this) }
FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) }
final override string getImmediateString() { result = funcSymbol.toString() }
@@ -430,7 +437,7 @@ class FunctionInstruction extends Instruction {
class ConstantValueInstruction extends Instruction {
string value;
ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) }
ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) }
final override string getImmediateString() { result = value }
@@ -440,7 +447,7 @@ class ConstantValueInstruction extends Instruction {
class IndexedInstruction extends Instruction {
int index;
IndexedInstruction() { index = Construction::getInstructionIndex(this) }
IndexedInstruction() { index = Raw::getInstructionIndex(this) }
final override string getImmediateString() { result = index.toString() }
@@ -603,11 +610,16 @@ class ConstantInstruction extends ConstantValueInstruction {
}
class IntegerConstantInstruction extends ConstantInstruction {
IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType }
IntegerConstantInstruction() {
exists(IRType resultType |
resultType = getResultIRType() and
(resultType instanceof IRIntegerType or resultType instanceof IRBooleanType)
)
}
}
class FloatConstantInstruction extends ConstantInstruction {
FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType }
FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType }
}
class StringConstantInstruction extends VariableInstruction {
@@ -704,7 +716,7 @@ class PointerArithmeticInstruction extends BinaryInstruction {
PointerArithmeticInstruction() {
getOpcode() instanceof PointerArithmeticOpcode and
elementSize = Construction::getInstructionElementSize(this)
elementSize = Raw::getInstructionElementSize(this)
}
final override string getImmediateString() { result = elementSize.toString() }
@@ -753,7 +765,7 @@ class InheritanceConversionInstruction extends UnaryInstruction {
Language::Class derivedClass;
InheritanceConversionInstruction() {
Construction::getInstructionInheritance(this, baseClass, derivedClass)
Raw::getInstructionInheritance(this, baseClass, derivedClass)
}
final override string getImmediateString() {
@@ -1216,7 +1228,7 @@ class CatchByTypeInstruction extends CatchInstruction {
CatchByTypeInstruction() {
getOpcode() instanceof Opcode::CatchByType and
exceptionType = Construction::getInstructionExceptionType(this)
exceptionType = Raw::getInstructionExceptionType(this)
}
final override string getImmediateString() { result = exceptionType.toString() }
@@ -1362,7 +1374,7 @@ class BuiltInOperationInstruction extends Instruction {
BuiltInOperationInstruction() {
getOpcode() instanceof BuiltInOperationOpcode and
operation = Construction::getInstructionBuiltInOperation(this)
operation = Raw::getInstructionBuiltInOperation(this)
}
final Language::BuiltInOperation getBuiltInOperation() { result = operation }

View File

@@ -0,0 +1 @@
import semmle.code.cpp.ir.implementation.internal.IRFunctionBase as IRFunctionBase

View File

@@ -1,3 +1,4 @@
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import SSAConstruction as Construction
import semmle.code.cpp.ir.implementation.IRConfiguration as IRConfiguration
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction::Raw as Raw

View File

@@ -1,5 +1,11 @@
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 class OldBlock = Reachability::ReachableBlock;
@@ -10,54 +16,47 @@ import Cached
cached
private module Cached {
cached
predicate hasPhiInstructionCached(
OldInstruction blockStartInstr, Alias::MemoryLocation defLocation
) {
exists(OldBlock oldBlock |
definitionHasPhiNode(defLocation, oldBlock) and
blockStartInstr = oldBlock.getFirstInstruction()
)
}
cached
predicate hasChiInstructionCached(OldInstruction primaryInstruction) {
hasChiNode(_, primaryInstruction)
}
cached
predicate hasUnreachedInstructionCached(IRFunction irFunc) {
exists(OldInstruction oldInstruction |
irFunc = oldInstruction.getEnclosingIRFunction() and
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
)
}
class TStageInstruction =
TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction;
cached
predicate hasInstruction(TStageInstruction instr) {
instr instanceof TRawInstruction and instr instanceof OldInstruction
or
instr instanceof TPhiInstruction
or
instr instanceof TChiInstruction
or
instr instanceof TUnreachedInstruction
}
private IRBlock getNewBlock(OldBlock oldBlock) {
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
}
cached
predicate functionHasIR(Language::Function func) {
exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func)
}
cached
OldInstruction getOldInstruction(Instruction instr) { instr = WrappedInstruction(result) }
private IRVariable getNewIRVariable(OldIR::IRVariable var) {
// This is just a type cast. Both classes derive from the same newtype.
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
predicate hasModeledMemoryResult(Instruction instruction) {
exists(Alias::getResultMemoryLocation(getOldInstruction(instruction))) or
@@ -73,7 +72,7 @@ private module Cached {
or
// Chi instructions track virtual variables, and therefore a chi instruction is
// 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::AliasedVirtualVariable
)
@@ -81,7 +80,7 @@ private module Cached {
// Phi instructions track locations, and therefore a phi instruction is
// conflated if it's associated with a conflated location.
exists(Alias::MemoryLocation location |
instruction = Phi(_, location) and
instruction = getPhi(_, location) and
not exists(location.getAllocation())
)
}
@@ -128,7 +127,7 @@ private module Cached {
hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result)
)
or
instruction = Chi(getOldInstruction(result)) and
instruction = getChi(getOldInstruction(result)) and
tag instanceof ChiPartialOperandTag and
overlap instanceof MustExactlyOverlap
or
@@ -172,13 +171,15 @@ private module Cached {
pragma[noopt]
cached
Instruction getPhiOperandDefinition(Phi instr, IRBlock newPredecessorBlock, Overlap overlap) {
Instruction getPhiOperandDefinition(
PhiInstruction instr, IRBlock newPredecessorBlock, Overlap overlap
) {
exists(
Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock,
OldBlock predBlock, OldBlock defBlock, int defOffset, Alias::MemoryLocation actualDefLocation
|
hasPhiOperandDefinition(defLocation, useLocation, phiBlock, predBlock, defBlock, defOffset) and
instr = Phi(phiBlock, useLocation) and
instr = getPhi(phiBlock, useLocation) and
newPredecessorBlock = getNewBlock(predBlock) and
result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, actualDefLocation) and
overlap = Alias::getOverlap(actualDefLocation, useLocation)
@@ -191,7 +192,7 @@ private module Cached {
Alias::VirtualVariable vvar, OldInstruction oldInstr, Alias::MemoryLocation defLocation,
OldBlock defBlock, int defRank, int defOffset, OldBlock useBlock, int useRank
|
chiInstr = Chi(oldInstr) and
chiInstr = getChi(oldInstr) and
vvar = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() and
hasDefinitionAtRank(vvar, defLocation, defBlock, defRank, defOffset) and
hasUseAtRank(vvar, useBlock, useRank, oldInstr) and
@@ -203,21 +204,11 @@ private module Cached {
cached
Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
exists(OldBlock oldBlock |
instr = Phi(oldBlock, _) and
instr = getPhi(oldBlock, _) and
result = getNewInstruction(oldBlock.getFirstInstruction())
)
}
cached
Language::Expr getInstructionConvertedResultExpression(Instruction instruction) {
result = getOldInstruction(instruction).getConvertedResultExpression()
}
cached
Language::Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
result = getOldInstruction(instruction).getUnconvertedResultExpression()
}
/*
* This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node,
* that node is its successor in the new successor relation, and the Chi node's successors are
@@ -228,20 +219,20 @@ private module Cached {
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
if hasChiNode(_, getOldInstruction(instruction))
then
result = Chi(getOldInstruction(instruction)) and
result = getChi(getOldInstruction(instruction)) and
kind instanceof GotoEdge
else (
exists(OldInstruction oldInstruction |
oldInstruction = getOldInstruction(instruction) and
(
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
then result = Unreached(instruction.getEnclosingFunction())
then result = unreachedInstruction(instruction.getEnclosingIRFunction())
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
)
)
or
exists(OldInstruction oldInstruction |
instruction = Chi(oldInstruction) and
instruction = getChi(oldInstruction) and
result = getNewInstruction(oldInstruction.getSuccessor(kind))
)
)
@@ -260,137 +251,73 @@ private module Cached {
// `oldInstruction`, in which case the back edge should come out of the
// chi node instead.
if hasChiNode(_, oldInstruction)
then instruction = Chi(oldInstruction)
then instruction = getChi(oldInstruction)
else instruction = getNewInstruction(oldInstruction)
)
}
cached
Language::AST getInstructionAST(Instruction instruction) {
exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction)
or
instruction = Chi(oldInstruction)
|
result = oldInstruction.getAST()
Language::AST getInstructionAST(Instruction instr) {
result = getOldInstruction(instr).getAST()
or
exists(RawIR::Instruction blockStartInstr |
instr = phiInstruction(blockStartInstr, _) and
result = blockStartInstr.getAST()
)
or
exists(OldBlock block |
instruction = Phi(block, _) and
result = block.getFirstInstruction().getAST()
exists(RawIR::Instruction primaryInstr |
instr = chiInstruction(primaryInstr) and
result = primaryInstr.getAST()
)
or
instruction = Unreached(result)
exists(IRFunctionBase irFunc |
instr = unreachedInstruction(irFunc) and result = irFunc.getFunction()
)
}
cached
Language::LanguageType getInstructionResultType(Instruction instruction) {
exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction) and
result = oldInstruction.getResultLanguageType()
Language::LanguageType getInstructionResultType(Instruction instr) {
result = instr.(RawIR::Instruction).getResultLanguageType()
or
exists(Alias::MemoryLocation defLocation |
instr = phiInstruction(_, defLocation) and
result = defLocation.getType()
)
or
exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar |
instruction = Chi(oldInstruction) and
hasChiNode(vvar, oldInstruction) and
exists(Instruction primaryInstr, Alias::VirtualVariable vvar |
instr = chiInstruction(primaryInstr) and
hasChiNode(vvar, primaryInstr) and
result = vvar.getType()
)
or
exists(Alias::MemoryLocation location |
instruction = Phi(_, location) and
result = location.getType()
instr = unreachedInstruction(_) and result = Language::getVoidType()
}
cached
Opcode getInstructionOpcode(Instruction instr) {
result = getOldInstruction(instr).getOpcode()
or
instr = phiInstruction(_, _) and result instanceof Opcode::Phi
or
instr = chiInstruction(_) and result instanceof Opcode::Chi
or
instr = unreachedInstruction(_) and result instanceof Opcode::Unreached
}
cached
IRFunctionBase getInstructionEnclosingIRFunction(Instruction instr) {
result = getOldInstruction(instr).getEnclosingIRFunction()
or
exists(OldInstruction blockStartInstr |
instr = phiInstruction(blockStartInstr, _) and
result = blockStartInstr.getEnclosingIRFunction()
)
or
instruction = Unreached(_) and
result = Language::getVoidType()
}
cached
Opcode getInstructionOpcode(Instruction instruction) {
exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction) and
result = oldInstruction.getOpcode()
exists(OldInstruction primaryInstr |
instr = chiInstruction(primaryInstr) and result = primaryInstr.getEnclosingIRFunction()
)
or
instruction instanceof Chi and
result instanceof Opcode::Chi
or
instruction instanceof Phi and
result instanceof Opcode::Phi
or
instruction instanceof Unreached and
result instanceof Opcode::Unreached
}
cached
IRFunction getInstructionEnclosingIRFunction(Instruction instruction) {
exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction)
or
instruction = Chi(oldInstruction)
|
result.getFunction() = oldInstruction.getEnclosingFunction()
)
or
exists(OldBlock block |
instruction = Phi(block, _) and
result.getFunction() = block.getEnclosingFunction()
)
or
instruction = Unreached(result.getFunction())
}
cached
IRVariable getInstructionVariable(Instruction instruction) {
result =
getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getIRVariable())
}
cached
Language::Field getInstructionField(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField()
}
cached
int getInstructionIndex(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::IndexedInstruction).getIndex()
}
cached
Language::Function getInstructionFunction(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol()
}
cached
string getInstructionConstantValue(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue()
}
cached
Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) {
result =
getOldInstruction(instruction).(OldIR::BuiltInOperationInstruction).getBuiltInOperation()
}
cached
Language::LanguageType getInstructionExceptionType(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType()
}
cached
int getInstructionElementSize(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::PointerArithmeticInstruction).getElementSize()
}
cached
predicate getInstructionInheritance(
Instruction instruction, Language::Class baseClass, Language::Class derivedClass
) {
exists(OldIR::InheritanceConversionInstruction oldInstr |
oldInstr = getOldInstruction(instruction) and
baseClass = oldInstr.getBaseClass() and
derivedClass = oldInstr.getDerivedClass()
)
instr = unreachedInstruction(result)
}
cached
@@ -401,7 +328,7 @@ private module Cached {
)
or
exists(OldIR::Instruction oldInstruction |
instruction = Chi(oldInstruction) and
instruction = getChi(oldInstruction) and
result = getNewInstruction(oldInstruction)
)
}
@@ -409,6 +336,14 @@ private module Cached {
private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr }
private OldInstruction getOldInstruction(Instruction instr) { instr = result }
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
* of a virtual variable. The `Chi` instruction provides a definition of the entire virtual variable of which the
@@ -588,7 +523,7 @@ module DefUse {
|
// An odd offset corresponds to the `Chi` instruction.
defOffset = oldOffset * 2 + 1 and
result = Chi(oldInstr) and
result = getChi(oldInstr) and
(
defLocation = Alias::getResultMemoryLocation(oldInstr) or
defLocation = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable()
@@ -607,7 +542,7 @@ module DefUse {
or
defOffset = -1 and
hasDefinition(_, defLocation, defBlock, defOffset) and
result = Phi(defBlock, defLocation) and
result = getPhi(defBlock, defLocation) and
actualDefLocation = defLocation
}
@@ -891,7 +826,7 @@ private module CachedForDebugging {
)
or
exists(Alias::MemoryLocation location, OldBlock phiBlock, string specificity |
instr = Phi(phiBlock, location) and
instr = getPhi(phiBlock, location) and
result =
"Phi Block(" + phiBlock.getUniqueId() + ")[" + specificity + "]: " + location.getUniqueId() and
if location instanceof Alias::VirtualVariable
@@ -901,7 +836,7 @@ private module CachedForDebugging {
else specificity = "s"
)
or
instr = Unreached(_) and
instr = unreachedInstruction(_) and
result = "Unreached"
}
@@ -961,3 +896,19 @@ module SSAConsistency {
)
}
}
/**
* Provides the portion of the parameterized IR interface that is used to construct the SSA stages
* of the IR. The raw stage of the IR does not expose these predicates.
* These predicates are all just aliases for predicates defined in the `Cached` module. This ensures
* that all of SSA construction will be evaluated in the same stage.
*/
module SSA {
class MemoryLocation = Alias::MemoryLocation;
predicate hasPhiInstruction = Cached::hasPhiInstructionCached/2;
predicate hasChiInstruction = Cached::hasChiInstructionCached/1;
predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1;
}

View File

@@ -1,3 +1,5 @@
import semmle.code.cpp.ir.implementation.Opcode
import semmle.code.cpp.ir.implementation.internal.OperandTag
import semmle.code.cpp.ir.internal.Overlap
import semmle.code.cpp.ir.implementation.Opcode as Opcode
import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag
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

View File

@@ -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.Dominance as Dominance
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 SimpleSSA as Alias

View File

@@ -1,7 +1,7 @@
private import cpp
private import semmle.code.cpp.Print
private import semmle.code.cpp.ir.implementation.IRType
private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction::Raw as Raw
private int getPointerSize() { result = max(any(NullPointerType t).getSize()) }
@@ -143,7 +143,7 @@ private predicate isOpaqueType(Type type) {
predicate hasOpaqueType(Type tag, int byteSize) {
isOpaqueType(tag) and byteSize = getTypeSize(tag)
or
tag instanceof UnknownType and IRConstruction::needsUnknownOpaqueType(byteSize)
tag instanceof UnknownType and Raw::needsUnknownOpaqueType(byteSize)
}
/**
@@ -191,7 +191,7 @@ private newtype TCppType =
TPRValueType(Type type) { exists(getIRTypeForPRValue(type)) } or
TFunctionGLValueType() or
TGLValueAddressType(Type type) or
TUnknownOpaqueType(int byteSize) { IRConstruction::needsUnknownOpaqueType(byteSize) } or
TUnknownOpaqueType(int byteSize) { Raw::needsUnknownOpaqueType(byteSize) } or
TUnknownType()
/**

View File

@@ -111,6 +111,8 @@ private class IRSizedType extends IRType {
this = TIRFunctionAddressType(byteSize) or
this = TIROpaqueType(_, byteSize)
}
// Don't override `getByteSize()` here. The optimizer seems to generate better code when this is
// overridden only in the leaf classes.
}
/**
@@ -128,7 +130,7 @@ class IRBooleanType extends IRSizedType, TIRBooleanType {
}
/**
* A numberic type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and
* A numeric type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and
* `IRFloatingPointType`.
*/
class IRNumericType extends IRSizedType {
@@ -137,13 +139,27 @@ class IRNumericType extends IRSizedType {
this = TIRUnsignedIntegerType(byteSize) or
this = TIRFloatingPointType(byteSize, _, _)
}
// Don't override `getByteSize()` here. The optimizer seems to generate better code when this is
// overridden only in the leaf classes.
}
/**
* An integer type. This includes `IRSignedIntegerType` and `IRUnsignedIntegerType`.
*/
class IRIntegerType extends IRNumericType {
IRIntegerType() {
this = TIRSignedIntegerType(byteSize) or
this = TIRUnsignedIntegerType(byteSize)
}
// Don't override `getByteSize()` here. The optimizer seems to generate better code when this is
// overridden only in the leaf classes.
}
/**
* A signed two's-complement integer. Also used to represent enums whose underlying type is a signed
* integer, as well as character types whose representation is signed.
*/
class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType {
class IRSignedIntegerType extends IRIntegerType, TIRSignedIntegerType {
final override string toString() { result = "int" + byteSize.toString() }
final override Language::LanguageType getCanonicalLanguageType() {
@@ -158,7 +174,7 @@ class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType {
* An unsigned two's-complement integer. Also used to represent enums whose underlying type is an
* unsigned integer, as well as character types whose representation is unsigned.
*/
class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType {
class IRUnsignedIntegerType extends IRIntegerType, TIRUnsignedIntegerType {
final override string toString() { result = "uint" + byteSize.toString() }
final override Language::LanguageType getCanonicalLanguageType() {

View File

@@ -0,0 +1,19 @@
/**
* Provides a stub implementation of the required aliased SSA interface until we implement aliased
* SSA construction for C#.
*/
private import IRFunctionBase
private import TInstruction
module SSA {
class MemoryLocation = boolean;
predicate hasPhiInstruction(TRawInstruction blockStartInstr, MemoryLocation memoryLocation) {
none()
}
predicate hasChiInstruction(TRawInstruction primaryInstruction) { none() }
predicate hasUnreachedInstruction(IRFunctionBase irFunc) { none() }
}

View File

@@ -0,0 +1,27 @@
/**
* Provides a base class, `IRFunctionBase`, for the stage-independent portions of `IRFunction`.
*/
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() }
}

View File

@@ -0,0 +1,2 @@
import experimental.ir.internal.IRCSharpLanguage as Language
import experimental.ir.implementation.raw.internal.IRConstruction as IRConstruction

View File

@@ -1,5 +1,5 @@
import experimental.ir.internal.IRCSharpLanguage as Language
import experimental.ir.implementation.raw.internal.IRConstruction as Construction
import experimental.ir.implementation.raw.internal.IRConstruction::Raw as Construction
private import experimental.ir.implementation.TempVariableTag as TempVariableTag_
module Imports {

View File

@@ -0,0 +1,97 @@
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.
*/
cached
newtype TInstruction =
TRawInstruction(
IRConstruction::Raw::InstructionTag1 tag1, IRConstruction::Raw::InstructionTag2 tag2
) {
IRConstruction::Raw::hasInstruction(tag1, tag2)
} or
TUnaliasedSSAPhiInstruction(
TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation
) {
UnaliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation)
} or
TUnaliasedSSAChiInstruction(TRawInstruction primaryInstruction) { none() } or
TUnaliasedSSAUnreachedInstruction(IRFunctionBase irFunc) {
UnaliasedSSA::SSA::hasUnreachedInstruction(irFunc)
} or
TAliasedSSAPhiInstruction(
TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation
) {
AliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation)
} or
TAliasedSSAChiInstruction(TRawInstruction primaryInstruction) {
AliasedSSA::SSA::hasChiInstruction(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(
TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation
) {
result = TUnaliasedSSAPhiInstruction(blockStartInstr, memoryLocation)
}
class TChiInstruction = TUnaliasedSSAChiInstruction;
TChiInstruction chiInstruction(TRawInstruction primaryInstruction) {
result = TUnaliasedSSAChiInstruction(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(
TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation
) {
result = TAliasedSSAPhiInstruction(blockStartInstr, memoryLocation)
}
class TChiInstruction = TAliasedSSAChiInstruction;
TChiInstruction chiInstruction(TRawInstruction primaryInstruction) {
result = TAliasedSSAChiInstruction(primaryInstruction)
}
class TUnreachedInstruction = TAliasedSSAUnreachedInstruction;
TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) {
result = TAliasedSSAUnreachedInstruction(irFunc)
}
}

View File

@@ -0,0 +1,2 @@
import experimental.ir.implementation.IRType as IRType
import experimental.ir.implementation.Opcode as Opcode

View File

@@ -0,0 +1,4 @@
import experimental.ir.internal.IRCSharpLanguage as Language
import experimental.ir.implementation.raw.internal.IRConstruction as IRConstruction
import experimental.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedSSA
import AliasedSSAStub as AliasedSSA

View File

@@ -1,29 +1,12 @@
private import internal.IRInternal
private import internal.IRFunctionImports as Imports
import Imports::IRFunctionBase
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 {
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() }
class IRFunction extends IRFunctionBase {
/**
* Gets the entry point for this function.
*/

View File

@@ -29,7 +29,13 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil
/**
* 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() }
/**
@@ -194,14 +200,14 @@ class Instruction extends Construction::TInstruction {
* conversion.
*/
final Language::Expr getConvertedResultExpression() {
result = Construction::getInstructionConvertedResultExpression(this)
result = Raw::getInstructionConvertedResultExpression(this)
}
/**
* Gets the unconverted form of the `Expr` whose result is computed by this instruction, if any.
*/
final Language::Expr getUnconvertedResultExpression() {
result = Construction::getInstructionUnconvertedResultExpression(this)
result = Raw::getInstructionUnconvertedResultExpression(this)
}
final Language::LanguageType getResultLanguageType() {
@@ -212,6 +218,7 @@ class Instruction extends Construction::TInstruction {
* Gets the type of the result produced by this instruction. If the instruction does not produce
* a result, its result type will be `IRVoidType`.
*/
cached
final IRType getResultIRType() { result = getResultLanguageType().getIRType() }
/**
@@ -250,7 +257,7 @@ class Instruction extends Construction::TInstruction {
* result of the `Load` instruction is a prvalue of type `int`, representing
* 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
@@ -259,7 +266,7 @@ class Instruction extends Construction::TInstruction {
* If `this.isGLValue()` holds for this instruction, the value of
* `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.
@@ -395,7 +402,7 @@ class Instruction extends Construction::TInstruction {
class VariableInstruction extends Instruction {
IRVariable var;
VariableInstruction() { var = Construction::getInstructionVariable(this) }
VariableInstruction() { var = Raw::getInstructionVariable(this) }
override string getImmediateString() { result = var.toString() }
@@ -410,7 +417,7 @@ class VariableInstruction extends Instruction {
class FieldInstruction extends Instruction {
Language::Field field;
FieldInstruction() { field = Construction::getInstructionField(this) }
FieldInstruction() { field = Raw::getInstructionField(this) }
final override string getImmediateString() { result = field.toString() }
@@ -420,7 +427,7 @@ class FieldInstruction extends Instruction {
class FunctionInstruction extends Instruction {
Language::Function funcSymbol;
FunctionInstruction() { funcSymbol = Construction::getInstructionFunction(this) }
FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) }
final override string getImmediateString() { result = funcSymbol.toString() }
@@ -430,7 +437,7 @@ class FunctionInstruction extends Instruction {
class ConstantValueInstruction extends Instruction {
string value;
ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) }
ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) }
final override string getImmediateString() { result = value }
@@ -440,7 +447,7 @@ class ConstantValueInstruction extends Instruction {
class IndexedInstruction extends Instruction {
int index;
IndexedInstruction() { index = Construction::getInstructionIndex(this) }
IndexedInstruction() { index = Raw::getInstructionIndex(this) }
final override string getImmediateString() { result = index.toString() }
@@ -603,11 +610,16 @@ class ConstantInstruction extends ConstantValueInstruction {
}
class IntegerConstantInstruction extends ConstantInstruction {
IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType }
IntegerConstantInstruction() {
exists(IRType resultType |
resultType = getResultIRType() and
(resultType instanceof IRIntegerType or resultType instanceof IRBooleanType)
)
}
}
class FloatConstantInstruction extends ConstantInstruction {
FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType }
FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType }
}
class StringConstantInstruction extends VariableInstruction {
@@ -704,7 +716,7 @@ class PointerArithmeticInstruction extends BinaryInstruction {
PointerArithmeticInstruction() {
getOpcode() instanceof PointerArithmeticOpcode and
elementSize = Construction::getInstructionElementSize(this)
elementSize = Raw::getInstructionElementSize(this)
}
final override string getImmediateString() { result = elementSize.toString() }
@@ -753,7 +765,7 @@ class InheritanceConversionInstruction extends UnaryInstruction {
Language::Class derivedClass;
InheritanceConversionInstruction() {
Construction::getInstructionInheritance(this, baseClass, derivedClass)
Raw::getInstructionInheritance(this, baseClass, derivedClass)
}
final override string getImmediateString() {
@@ -1216,7 +1228,7 @@ class CatchByTypeInstruction extends CatchInstruction {
CatchByTypeInstruction() {
getOpcode() instanceof Opcode::CatchByType and
exceptionType = Construction::getInstructionExceptionType(this)
exceptionType = Raw::getInstructionExceptionType(this)
}
final override string getImmediateString() { result = exceptionType.toString() }
@@ -1362,7 +1374,7 @@ class BuiltInOperationInstruction extends Instruction {
BuiltInOperationInstruction() {
getOpcode() instanceof BuiltInOperationOpcode and
operation = Construction::getInstructionBuiltInOperation(this)
operation = Raw::getInstructionBuiltInOperation(this)
}
final Language::BuiltInOperation getBuiltInOperation() { result = operation }

View File

@@ -1,6 +1,8 @@
import csharp
import experimental.ir.implementation.raw.IR
private import experimental.ir.implementation.internal.OperandTag
private import experimental.ir.implementation.internal.IRFunctionBase
private import experimental.ir.implementation.internal.TInstruction
private import experimental.ir.internal.CSharpType
private import experimental.ir.internal.Overlap
private import experimental.ir.internal.TempVariableTag
@@ -15,23 +17,40 @@ private import experimental.ir.Util
private import experimental.ir.internal.IRCSharpLanguage as Language
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
pragma[noinline]
private predicate instructionOrigin(
Instruction instruction, TranslatedElement element, InstructionTag tag
) {
element = getInstructionTranslatedElement(instruction) and
tag = getInstructionTag(instruction)
}
class TStageInstruction = TRawInstruction;
/**
* 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
private module Cached {
module Raw {
class InstructionTag1 = TranslatedElement;
class InstructionTag2 = InstructionTag;
cached
predicate functionHasIR(Callable callable) { exists(getTranslatedFunction(callable)) }
cached
newtype TInstruction =
MkInstruction(TranslatedElement element, InstructionTag tag) {
element.hasInstruction(_, tag, _)
}
predicate hasInstruction(TranslatedElement element, InstructionTag tag) {
element.hasInstruction(_, tag, _)
}
cached
predicate hasUserVariable(Callable callable, Variable var, CSharpType type) {
@@ -63,16 +82,6 @@ private module Cached {
none()
}
cached
predicate hasModeledMemoryResult(Instruction instruction) { none() }
cached
predicate hasConflatedMemoryResult(Instruction instruction) {
instruction instanceof AliasedDefinitionInstruction
or
instruction.getOpcode() instanceof Opcode::InitializeNonLocal
}
cached
Expr getInstructionConvertedResultExpression(Instruction instruction) {
exists(TranslatedExpr translatedExpr |
@@ -89,6 +98,98 @@ private module Cached {
)
}
cached
IRVariable getInstructionVariable(Instruction instruction) {
exists(TranslatedElement element, InstructionTag tag |
element = getInstructionTranslatedElement(instruction) and
tag = getInstructionTag(instruction) and
(
result = element.getInstructionVariable(tag) or
result.(IRStringLiteral).getAST() = element.getInstructionStringLiteral(tag)
)
)
}
cached
Field getInstructionField(Instruction instruction) {
exists(TranslatedElement element, InstructionTag tag |
instructionOrigin(instruction, element, tag) and
result = element.getInstructionField(tag)
)
}
cached
int getInstructionIndex(Instruction instruction) { none() }
cached
Callable getInstructionFunction(Instruction instruction) {
result =
getInstructionTranslatedElement(instruction)
.getInstructionFunction(getInstructionTag(instruction))
}
cached
string getInstructionConstantValue(Instruction instruction) {
result =
getInstructionTranslatedElement(instruction)
.getInstructionConstantValue(getInstructionTag(instruction))
}
cached
CSharpType getInstructionExceptionType(Instruction instruction) {
result =
getInstructionTranslatedElement(instruction)
.getInstructionExceptionType(getInstructionTag(instruction))
}
cached
predicate getInstructionInheritance(Instruction instruction, Class baseClass, Class derivedClass) {
getInstructionTranslatedElement(instruction)
.getInstructionInheritance(getInstructionTag(instruction), baseClass, derivedClass)
}
cached
int getInstructionElementSize(Instruction instruction) {
exists(TranslatedElement element, InstructionTag tag |
instructionOrigin(instruction, element, tag) and
result = element.getInstructionElementSize(tag)
)
}
cached
Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instr) { none() }
}
import Cached
cached
private module Cached {
cached
Opcode getInstructionOpcode(TRawInstruction instr) {
exists(TranslatedElement element, InstructionTag tag |
instructionOrigin(instr, element, tag) and
element.hasInstruction(result, tag, _)
)
}
cached
IRFunctionBase getInstructionEnclosingIRFunction(TRawInstruction instr) {
result.getFunction() = getInstructionTranslatedElement(instr).getFunction()
}
cached
predicate hasInstruction(TRawInstruction instr) { any() }
cached
predicate hasModeledMemoryResult(Instruction instruction) { none() }
cached
predicate hasConflatedMemoryResult(Instruction instruction) {
instruction instanceof AliasedDefinitionInstruction
or
instruction.getOpcode() instanceof Opcode::InitializeNonLocal
}
cached
Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) {
result =
@@ -264,37 +365,6 @@ private module Cached {
.hasInstruction(_, getInstructionTag(instruction), result)
}
cached
Opcode getInstructionOpcode(Instruction instruction) {
getInstructionTranslatedElement(instruction)
.hasInstruction(result, getInstructionTag(instruction), _)
}
cached
IRFunction getInstructionEnclosingIRFunction(Instruction instruction) {
result.getFunction() = getInstructionTranslatedElement(instruction).getFunction()
}
cached
IRVariable getInstructionVariable(Instruction instruction) {
exists(TranslatedElement element, InstructionTag tag |
element = getInstructionTranslatedElement(instruction) and
tag = getInstructionTag(instruction) and
(
result = element.getInstructionVariable(tag) or
result.(IRStringLiteral).getAST() = element.getInstructionStringLiteral(tag)
)
)
}
cached
Field getInstructionField(Instruction instruction) {
exists(TranslatedElement element, InstructionTag tag |
instructionOrigin(instruction, element, tag) and
result = element.getInstructionField(tag)
)
}
cached
ArrayAccess getInstructionArrayAccess(Instruction instruction) {
result =
@@ -302,52 +372,6 @@ private module Cached {
.getInstructionArrayAccess(getInstructionTag(instruction))
}
cached
int getInstructionIndex(Instruction instruction) { none() }
cached
Callable getInstructionFunction(Instruction instruction) {
result =
getInstructionTranslatedElement(instruction)
.getInstructionFunction(getInstructionTag(instruction))
}
cached
string getInstructionConstantValue(Instruction instruction) {
result =
getInstructionTranslatedElement(instruction)
.getInstructionConstantValue(getInstructionTag(instruction))
}
cached
CSharpType getInstructionExceptionType(Instruction instruction) {
result =
getInstructionTranslatedElement(instruction)
.getInstructionExceptionType(getInstructionTag(instruction))
}
cached
predicate getInstructionInheritance(Instruction instruction, Class baseClass, Class derivedClass) {
getInstructionTranslatedElement(instruction)
.getInstructionInheritance(getInstructionTag(instruction), baseClass, derivedClass)
}
pragma[noinline]
private predicate instructionOrigin(
Instruction instruction, TranslatedElement element, InstructionTag tag
) {
element = getInstructionTranslatedElement(instruction) and
tag = getInstructionTag(instruction)
}
cached
int getInstructionElementSize(Instruction instruction) {
exists(TranslatedElement element, InstructionTag tag |
instructionOrigin(instruction, element, tag) and
result = element.getInstructionElementSize(tag)
)
}
cached
int getInstructionResultSize(Instruction instruction) {
exists(TranslatedElement element, InstructionTag tag |
@@ -363,9 +387,6 @@ private module Cached {
result = element.getPrimaryInstructionForSideEffect(tag)
)
}
cached
Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instr) { none() }
}
import CachedForDebugging

View File

@@ -0,0 +1 @@
import experimental.ir.implementation.internal.IRFunctionBase as IRFunctionBase

View File

@@ -1,3 +1,4 @@
import experimental.ir.internal.IRCSharpLanguage as Language
import IRConstruction as Construction
import experimental.ir.implementation.IRConfiguration as IRConfiguration
import IRConstruction::Raw as Raw

View File

@@ -1,29 +1,12 @@
private import internal.IRInternal
private import internal.IRFunctionImports as Imports
import Imports::IRFunctionBase
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 {
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() }
class IRFunction extends IRFunctionBase {
/**
* Gets the entry point for this function.
*/

View File

@@ -29,7 +29,13 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil
/**
* 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() }
/**
@@ -194,14 +200,14 @@ class Instruction extends Construction::TInstruction {
* conversion.
*/
final Language::Expr getConvertedResultExpression() {
result = Construction::getInstructionConvertedResultExpression(this)
result = Raw::getInstructionConvertedResultExpression(this)
}
/**
* Gets the unconverted form of the `Expr` whose result is computed by this instruction, if any.
*/
final Language::Expr getUnconvertedResultExpression() {
result = Construction::getInstructionUnconvertedResultExpression(this)
result = Raw::getInstructionUnconvertedResultExpression(this)
}
final Language::LanguageType getResultLanguageType() {
@@ -212,6 +218,7 @@ class Instruction extends Construction::TInstruction {
* Gets the type of the result produced by this instruction. If the instruction does not produce
* a result, its result type will be `IRVoidType`.
*/
cached
final IRType getResultIRType() { result = getResultLanguageType().getIRType() }
/**
@@ -250,7 +257,7 @@ class Instruction extends Construction::TInstruction {
* result of the `Load` instruction is a prvalue of type `int`, representing
* 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
@@ -259,7 +266,7 @@ class Instruction extends Construction::TInstruction {
* If `this.isGLValue()` holds for this instruction, the value of
* `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.
@@ -395,7 +402,7 @@ class Instruction extends Construction::TInstruction {
class VariableInstruction extends Instruction {
IRVariable var;
VariableInstruction() { var = Construction::getInstructionVariable(this) }
VariableInstruction() { var = Raw::getInstructionVariable(this) }
override string getImmediateString() { result = var.toString() }
@@ -410,7 +417,7 @@ class VariableInstruction extends Instruction {
class FieldInstruction extends Instruction {
Language::Field field;
FieldInstruction() { field = Construction::getInstructionField(this) }
FieldInstruction() { field = Raw::getInstructionField(this) }
final override string getImmediateString() { result = field.toString() }
@@ -420,7 +427,7 @@ class FieldInstruction extends Instruction {
class FunctionInstruction extends Instruction {
Language::Function funcSymbol;
FunctionInstruction() { funcSymbol = Construction::getInstructionFunction(this) }
FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) }
final override string getImmediateString() { result = funcSymbol.toString() }
@@ -430,7 +437,7 @@ class FunctionInstruction extends Instruction {
class ConstantValueInstruction extends Instruction {
string value;
ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) }
ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) }
final override string getImmediateString() { result = value }
@@ -440,7 +447,7 @@ class ConstantValueInstruction extends Instruction {
class IndexedInstruction extends Instruction {
int index;
IndexedInstruction() { index = Construction::getInstructionIndex(this) }
IndexedInstruction() { index = Raw::getInstructionIndex(this) }
final override string getImmediateString() { result = index.toString() }
@@ -603,11 +610,16 @@ class ConstantInstruction extends ConstantValueInstruction {
}
class IntegerConstantInstruction extends ConstantInstruction {
IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType }
IntegerConstantInstruction() {
exists(IRType resultType |
resultType = getResultIRType() and
(resultType instanceof IRIntegerType or resultType instanceof IRBooleanType)
)
}
}
class FloatConstantInstruction extends ConstantInstruction {
FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType }
FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType }
}
class StringConstantInstruction extends VariableInstruction {
@@ -704,7 +716,7 @@ class PointerArithmeticInstruction extends BinaryInstruction {
PointerArithmeticInstruction() {
getOpcode() instanceof PointerArithmeticOpcode and
elementSize = Construction::getInstructionElementSize(this)
elementSize = Raw::getInstructionElementSize(this)
}
final override string getImmediateString() { result = elementSize.toString() }
@@ -753,7 +765,7 @@ class InheritanceConversionInstruction extends UnaryInstruction {
Language::Class derivedClass;
InheritanceConversionInstruction() {
Construction::getInstructionInheritance(this, baseClass, derivedClass)
Raw::getInstructionInheritance(this, baseClass, derivedClass)
}
final override string getImmediateString() {
@@ -1216,7 +1228,7 @@ class CatchByTypeInstruction extends CatchInstruction {
CatchByTypeInstruction() {
getOpcode() instanceof Opcode::CatchByType and
exceptionType = Construction::getInstructionExceptionType(this)
exceptionType = Raw::getInstructionExceptionType(this)
}
final override string getImmediateString() { result = exceptionType.toString() }
@@ -1362,7 +1374,7 @@ class BuiltInOperationInstruction extends Instruction {
BuiltInOperationInstruction() {
getOpcode() instanceof BuiltInOperationOpcode and
operation = Construction::getInstructionBuiltInOperation(this)
operation = Raw::getInstructionBuiltInOperation(this)
}
final Language::BuiltInOperation getBuiltInOperation() { result = operation }

View File

@@ -0,0 +1 @@
import experimental.ir.implementation.internal.IRFunctionBase as IRFunctionBase

View File

@@ -1,3 +1,4 @@
import experimental.ir.internal.IRCSharpLanguage as Language
import SSAConstruction as Construction
import experimental.ir.implementation.IRConfiguration as IRConfiguration
import experimental.ir.implementation.raw.internal.IRConstruction::Raw as Raw

View File

@@ -1,5 +1,11 @@
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 class OldBlock = Reachability::ReachableBlock;
@@ -10,54 +16,47 @@ import Cached
cached
private module Cached {
cached
predicate hasPhiInstructionCached(
OldInstruction blockStartInstr, Alias::MemoryLocation defLocation
) {
exists(OldBlock oldBlock |
definitionHasPhiNode(defLocation, oldBlock) and
blockStartInstr = oldBlock.getFirstInstruction()
)
}
cached
predicate hasChiInstructionCached(OldInstruction primaryInstruction) {
hasChiNode(_, primaryInstruction)
}
cached
predicate hasUnreachedInstructionCached(IRFunction irFunc) {
exists(OldInstruction oldInstruction |
irFunc = oldInstruction.getEnclosingIRFunction() and
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
)
}
class TStageInstruction =
TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction;
cached
predicate hasInstruction(TStageInstruction instr) {
instr instanceof TRawInstruction and instr instanceof OldInstruction
or
instr instanceof TPhiInstruction
or
instr instanceof TChiInstruction
or
instr instanceof TUnreachedInstruction
}
private IRBlock getNewBlock(OldBlock oldBlock) {
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
}
cached
predicate functionHasIR(Language::Function func) {
exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func)
}
cached
OldInstruction getOldInstruction(Instruction instr) { instr = WrappedInstruction(result) }
private IRVariable getNewIRVariable(OldIR::IRVariable var) {
// This is just a type cast. Both classes derive from the same newtype.
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
predicate hasModeledMemoryResult(Instruction instruction) {
exists(Alias::getResultMemoryLocation(getOldInstruction(instruction))) or
@@ -73,7 +72,7 @@ private module Cached {
or
// Chi instructions track virtual variables, and therefore a chi instruction is
// 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::AliasedVirtualVariable
)
@@ -81,7 +80,7 @@ private module Cached {
// Phi instructions track locations, and therefore a phi instruction is
// conflated if it's associated with a conflated location.
exists(Alias::MemoryLocation location |
instruction = Phi(_, location) and
instruction = getPhi(_, location) and
not exists(location.getAllocation())
)
}
@@ -128,7 +127,7 @@ private module Cached {
hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result)
)
or
instruction = Chi(getOldInstruction(result)) and
instruction = getChi(getOldInstruction(result)) and
tag instanceof ChiPartialOperandTag and
overlap instanceof MustExactlyOverlap
or
@@ -172,13 +171,15 @@ private module Cached {
pragma[noopt]
cached
Instruction getPhiOperandDefinition(Phi instr, IRBlock newPredecessorBlock, Overlap overlap) {
Instruction getPhiOperandDefinition(
PhiInstruction instr, IRBlock newPredecessorBlock, Overlap overlap
) {
exists(
Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock,
OldBlock predBlock, OldBlock defBlock, int defOffset, Alias::MemoryLocation actualDefLocation
|
hasPhiOperandDefinition(defLocation, useLocation, phiBlock, predBlock, defBlock, defOffset) and
instr = Phi(phiBlock, useLocation) and
instr = getPhi(phiBlock, useLocation) and
newPredecessorBlock = getNewBlock(predBlock) and
result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, actualDefLocation) and
overlap = Alias::getOverlap(actualDefLocation, useLocation)
@@ -191,7 +192,7 @@ private module Cached {
Alias::VirtualVariable vvar, OldInstruction oldInstr, Alias::MemoryLocation defLocation,
OldBlock defBlock, int defRank, int defOffset, OldBlock useBlock, int useRank
|
chiInstr = Chi(oldInstr) and
chiInstr = getChi(oldInstr) and
vvar = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() and
hasDefinitionAtRank(vvar, defLocation, defBlock, defRank, defOffset) and
hasUseAtRank(vvar, useBlock, useRank, oldInstr) and
@@ -203,21 +204,11 @@ private module Cached {
cached
Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
exists(OldBlock oldBlock |
instr = Phi(oldBlock, _) and
instr = getPhi(oldBlock, _) and
result = getNewInstruction(oldBlock.getFirstInstruction())
)
}
cached
Language::Expr getInstructionConvertedResultExpression(Instruction instruction) {
result = getOldInstruction(instruction).getConvertedResultExpression()
}
cached
Language::Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
result = getOldInstruction(instruction).getUnconvertedResultExpression()
}
/*
* This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node,
* that node is its successor in the new successor relation, and the Chi node's successors are
@@ -228,20 +219,20 @@ private module Cached {
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
if hasChiNode(_, getOldInstruction(instruction))
then
result = Chi(getOldInstruction(instruction)) and
result = getChi(getOldInstruction(instruction)) and
kind instanceof GotoEdge
else (
exists(OldInstruction oldInstruction |
oldInstruction = getOldInstruction(instruction) and
(
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
then result = Unreached(instruction.getEnclosingFunction())
then result = unreachedInstruction(instruction.getEnclosingIRFunction())
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
)
)
or
exists(OldInstruction oldInstruction |
instruction = Chi(oldInstruction) and
instruction = getChi(oldInstruction) and
result = getNewInstruction(oldInstruction.getSuccessor(kind))
)
)
@@ -260,137 +251,73 @@ private module Cached {
// `oldInstruction`, in which case the back edge should come out of the
// chi node instead.
if hasChiNode(_, oldInstruction)
then instruction = Chi(oldInstruction)
then instruction = getChi(oldInstruction)
else instruction = getNewInstruction(oldInstruction)
)
}
cached
Language::AST getInstructionAST(Instruction instruction) {
exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction)
or
instruction = Chi(oldInstruction)
|
result = oldInstruction.getAST()
Language::AST getInstructionAST(Instruction instr) {
result = getOldInstruction(instr).getAST()
or
exists(RawIR::Instruction blockStartInstr |
instr = phiInstruction(blockStartInstr, _) and
result = blockStartInstr.getAST()
)
or
exists(OldBlock block |
instruction = Phi(block, _) and
result = block.getFirstInstruction().getAST()
exists(RawIR::Instruction primaryInstr |
instr = chiInstruction(primaryInstr) and
result = primaryInstr.getAST()
)
or
instruction = Unreached(result)
exists(IRFunctionBase irFunc |
instr = unreachedInstruction(irFunc) and result = irFunc.getFunction()
)
}
cached
Language::LanguageType getInstructionResultType(Instruction instruction) {
exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction) and
result = oldInstruction.getResultLanguageType()
Language::LanguageType getInstructionResultType(Instruction instr) {
result = instr.(RawIR::Instruction).getResultLanguageType()
or
exists(Alias::MemoryLocation defLocation |
instr = phiInstruction(_, defLocation) and
result = defLocation.getType()
)
or
exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar |
instruction = Chi(oldInstruction) and
hasChiNode(vvar, oldInstruction) and
exists(Instruction primaryInstr, Alias::VirtualVariable vvar |
instr = chiInstruction(primaryInstr) and
hasChiNode(vvar, primaryInstr) and
result = vvar.getType()
)
or
exists(Alias::MemoryLocation location |
instruction = Phi(_, location) and
result = location.getType()
instr = unreachedInstruction(_) and result = Language::getVoidType()
}
cached
Opcode getInstructionOpcode(Instruction instr) {
result = getOldInstruction(instr).getOpcode()
or
instr = phiInstruction(_, _) and result instanceof Opcode::Phi
or
instr = chiInstruction(_) and result instanceof Opcode::Chi
or
instr = unreachedInstruction(_) and result instanceof Opcode::Unreached
}
cached
IRFunctionBase getInstructionEnclosingIRFunction(Instruction instr) {
result = getOldInstruction(instr).getEnclosingIRFunction()
or
exists(OldInstruction blockStartInstr |
instr = phiInstruction(blockStartInstr, _) and
result = blockStartInstr.getEnclosingIRFunction()
)
or
instruction = Unreached(_) and
result = Language::getVoidType()
}
cached
Opcode getInstructionOpcode(Instruction instruction) {
exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction) and
result = oldInstruction.getOpcode()
exists(OldInstruction primaryInstr |
instr = chiInstruction(primaryInstr) and result = primaryInstr.getEnclosingIRFunction()
)
or
instruction instanceof Chi and
result instanceof Opcode::Chi
or
instruction instanceof Phi and
result instanceof Opcode::Phi
or
instruction instanceof Unreached and
result instanceof Opcode::Unreached
}
cached
IRFunction getInstructionEnclosingIRFunction(Instruction instruction) {
exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction)
or
instruction = Chi(oldInstruction)
|
result.getFunction() = oldInstruction.getEnclosingFunction()
)
or
exists(OldBlock block |
instruction = Phi(block, _) and
result.getFunction() = block.getEnclosingFunction()
)
or
instruction = Unreached(result.getFunction())
}
cached
IRVariable getInstructionVariable(Instruction instruction) {
result =
getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getIRVariable())
}
cached
Language::Field getInstructionField(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField()
}
cached
int getInstructionIndex(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::IndexedInstruction).getIndex()
}
cached
Language::Function getInstructionFunction(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol()
}
cached
string getInstructionConstantValue(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue()
}
cached
Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) {
result =
getOldInstruction(instruction).(OldIR::BuiltInOperationInstruction).getBuiltInOperation()
}
cached
Language::LanguageType getInstructionExceptionType(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType()
}
cached
int getInstructionElementSize(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::PointerArithmeticInstruction).getElementSize()
}
cached
predicate getInstructionInheritance(
Instruction instruction, Language::Class baseClass, Language::Class derivedClass
) {
exists(OldIR::InheritanceConversionInstruction oldInstr |
oldInstr = getOldInstruction(instruction) and
baseClass = oldInstr.getBaseClass() and
derivedClass = oldInstr.getDerivedClass()
)
instr = unreachedInstruction(result)
}
cached
@@ -401,7 +328,7 @@ private module Cached {
)
or
exists(OldIR::Instruction oldInstruction |
instruction = Chi(oldInstruction) and
instruction = getChi(oldInstruction) and
result = getNewInstruction(oldInstruction)
)
}
@@ -409,6 +336,14 @@ private module Cached {
private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr }
private OldInstruction getOldInstruction(Instruction instr) { instr = result }
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
* of a virtual variable. The `Chi` instruction provides a definition of the entire virtual variable of which the
@@ -588,7 +523,7 @@ module DefUse {
|
// An odd offset corresponds to the `Chi` instruction.
defOffset = oldOffset * 2 + 1 and
result = Chi(oldInstr) and
result = getChi(oldInstr) and
(
defLocation = Alias::getResultMemoryLocation(oldInstr) or
defLocation = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable()
@@ -607,7 +542,7 @@ module DefUse {
or
defOffset = -1 and
hasDefinition(_, defLocation, defBlock, defOffset) and
result = Phi(defBlock, defLocation) and
result = getPhi(defBlock, defLocation) and
actualDefLocation = defLocation
}
@@ -891,7 +826,7 @@ private module CachedForDebugging {
)
or
exists(Alias::MemoryLocation location, OldBlock phiBlock, string specificity |
instr = Phi(phiBlock, location) and
instr = getPhi(phiBlock, location) and
result =
"Phi Block(" + phiBlock.getUniqueId() + ")[" + specificity + "]: " + location.getUniqueId() and
if location instanceof Alias::VirtualVariable
@@ -901,7 +836,7 @@ private module CachedForDebugging {
else specificity = "s"
)
or
instr = Unreached(_) and
instr = unreachedInstruction(_) and
result = "Unreached"
}
@@ -961,3 +896,19 @@ module SSAConsistency {
)
}
}
/**
* Provides the portion of the parameterized IR interface that is used to construct the SSA stages
* of the IR. The raw stage of the IR does not expose these predicates.
* These predicates are all just aliases for predicates defined in the `Cached` module. This ensures
* that all of SSA construction will be evaluated in the same stage.
*/
module SSA {
class MemoryLocation = Alias::MemoryLocation;
predicate hasPhiInstruction = Cached::hasPhiInstructionCached/2;
predicate hasChiInstruction = Cached::hasChiInstructionCached/1;
predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1;
}

View File

@@ -1,3 +1,5 @@
import experimental.ir.implementation.Opcode
import experimental.ir.implementation.internal.OperandTag
import experimental.ir.internal.Overlap
import experimental.ir.implementation.Opcode as Opcode
import experimental.ir.implementation.internal.OperandTag as OperandTag
import experimental.ir.internal.Overlap as Overlap
import experimental.ir.implementation.internal.TInstruction as TInstruction
import experimental.ir.implementation.raw.IR as RawIR

View File

@@ -2,5 +2,7 @@ import experimental.ir.implementation.raw.IR as OldIR
import experimental.ir.implementation.raw.internal.reachability.ReachableBlock as Reachability
import experimental.ir.implementation.raw.internal.reachability.Dominance as Dominance
import experimental.ir.implementation.unaliased_ssa.IR as NewIR
import experimental.ir.implementation.raw.internal.IRConstruction as RawStage
import experimental.ir.implementation.internal.TInstruction::UnaliasedSSAInstructions as SSAInstructions
import experimental.ir.internal.IRCSharpLanguage as Language
import SimpleSSA as Alias

View File

@@ -1,16 +0,0 @@
private import csharp
private import experimental.ir.implementation.TempVariableTag
private import experimental.ir.implementation.raw.internal.IRConstruction as Construction
private import experimental.ir.Util
private import IRCSharpLanguage as Language
newtype TIRVariable =
TIRAutomaticUserVariable(LocalScopeVariable var, Callable callable) {
Construction::functionHasIR(callable) and
var.getCallable() = callable
} or
TIRTempVariable(
Callable callable, Language::AST ast, TempVariableTag tag, Language::LanguageType type
) {
Construction::hasTempVariable(callable, ast, tag, type)
}