mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
Merge pull request #4825 from rdmarsh2/rdmarsh2/cpp/operand-reuse
C++: share `TOperand` across IR stages
This commit is contained in:
@@ -10,79 +10,32 @@ private import Imports::MemoryAccessKind
|
||||
private import Imports::IRType
|
||||
private import Imports::Overlap
|
||||
private import Imports::OperandTag
|
||||
|
||||
cached
|
||||
private newtype TOperand =
|
||||
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
|
||||
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
|
||||
not Construction::isInCycle(useInstr) and
|
||||
strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1
|
||||
} or
|
||||
TNonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) {
|
||||
useInstr.getOpcode().hasOperand(tag)
|
||||
} or
|
||||
TPhiOperand(
|
||||
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
|
||||
) {
|
||||
defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
|
||||
}
|
||||
private import Imports::TOperand
|
||||
private import internal.OperandInternal
|
||||
|
||||
/**
|
||||
* Base class for all register operands. This is a placeholder for the IPA union type that we will
|
||||
* eventually use for this purpose.
|
||||
* An operand of an `Instruction` in this stage of the IR. Implemented as a union of the branches
|
||||
* of `TOperand` that are used in this stage.
|
||||
*/
|
||||
private class RegisterOperandBase extends TRegisterOperand {
|
||||
/** Gets a textual representation of this element. */
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the register operand with the specified parameters.
|
||||
*/
|
||||
private RegisterOperandBase registerOperand(
|
||||
Instruction useInstr, RegisterOperandTag tag, Instruction defInstr
|
||||
) {
|
||||
result = TRegisterOperand(useInstr, tag, defInstr)
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for all non-Phi memory operands. This is a placeholder for the IPA union type that we
|
||||
* will eventually use for this purpose.
|
||||
*/
|
||||
private class NonPhiMemoryOperandBase extends TNonPhiMemoryOperand {
|
||||
/** Gets a textual representation of this element. */
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the non-Phi memory operand with the specified parameters.
|
||||
*/
|
||||
private NonPhiMemoryOperandBase nonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) {
|
||||
result = TNonPhiMemoryOperand(useInstr, tag)
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for all Phi operands. This is a placeholder for the IPA union type that we will
|
||||
* eventually use for this purpose.
|
||||
*/
|
||||
private class PhiOperandBase extends TPhiOperand {
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Phi operand with the specified parameters.
|
||||
*/
|
||||
private PhiOperandBase phiOperand(
|
||||
Instruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
|
||||
) {
|
||||
result = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap)
|
||||
}
|
||||
private class TStageOperand =
|
||||
TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand;
|
||||
|
||||
/**
|
||||
* An operand of an `Instruction`. The operand represents a use of the result of one instruction
|
||||
* (the defining instruction) in another instruction (the use instruction)
|
||||
*/
|
||||
class Operand extends TOperand {
|
||||
class Operand extends TStageOperand {
|
||||
cached
|
||||
Operand() {
|
||||
// Ensure that the operand does not refer to instructions from earlier stages that are unreachable here
|
||||
exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) or
|
||||
exists(Instruction use | this = nonSSAMemoryOperand(use, _)) or
|
||||
exists(Instruction use, Instruction def, IRBlock predecessorBlock |
|
||||
this = phiOperand(use, def, predecessorBlock, _)
|
||||
) or
|
||||
exists(Instruction use | this = chiOperand(use, _))
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = "Operand" }
|
||||
|
||||
@@ -238,9 +191,11 @@ class Operand extends TOperand {
|
||||
* An operand that consumes a memory result (e.g. the `LoadOperand` on a `Load` instruction).
|
||||
*/
|
||||
class MemoryOperand extends Operand {
|
||||
cached
|
||||
MemoryOperand() {
|
||||
this instanceof NonPhiMemoryOperandBase or
|
||||
this instanceof PhiOperandBase
|
||||
this instanceof TNonSSAMemoryOperand or
|
||||
this instanceof TPhiOperand or
|
||||
this instanceof TChiOperand
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -278,7 +233,8 @@ class NonPhiOperand extends Operand {
|
||||
|
||||
NonPhiOperand() {
|
||||
this = registerOperand(useInstr, tag, _) or
|
||||
this = nonPhiMemoryOperand(useInstr, tag)
|
||||
this = nonSSAMemoryOperand(useInstr, tag) or
|
||||
this = chiOperand(useInstr, tag)
|
||||
}
|
||||
|
||||
final override Instruction getUse() { result = useInstr }
|
||||
@@ -298,10 +254,11 @@ class NonPhiOperand extends Operand {
|
||||
/**
|
||||
* An operand that consumes a register (non-memory) result.
|
||||
*/
|
||||
class RegisterOperand extends NonPhiOperand, RegisterOperandBase {
|
||||
class RegisterOperand extends NonPhiOperand, TRegisterOperand {
|
||||
override RegisterOperandTag tag;
|
||||
Instruction defInstr;
|
||||
|
||||
cached
|
||||
RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) }
|
||||
|
||||
final override string toString() { result = tag.toString() }
|
||||
@@ -317,10 +274,15 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase {
|
||||
/**
|
||||
* A memory operand other than the operand of a `Phi` instruction.
|
||||
*/
|
||||
class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase {
|
||||
class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand {
|
||||
override MemoryOperandTag tag;
|
||||
|
||||
NonPhiMemoryOperand() { this = nonPhiMemoryOperand(useInstr, tag) }
|
||||
cached
|
||||
NonPhiMemoryOperand() {
|
||||
this = nonSSAMemoryOperand(useInstr, tag)
|
||||
or
|
||||
this = chiOperand(useInstr, tag)
|
||||
}
|
||||
|
||||
final override string toString() { result = tag.toString() }
|
||||
|
||||
@@ -462,12 +424,13 @@ class SideEffectOperand extends TypedOperand {
|
||||
/**
|
||||
* An operand of a `PhiInstruction`.
|
||||
*/
|
||||
class PhiInputOperand extends MemoryOperand, PhiOperandBase {
|
||||
class PhiInputOperand extends MemoryOperand, TPhiOperand {
|
||||
PhiInstruction useInstr;
|
||||
Instruction defInstr;
|
||||
IRBlock predecessorBlock;
|
||||
Overlap overlap;
|
||||
|
||||
cached
|
||||
PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) }
|
||||
|
||||
override string toString() { result = "Phi" }
|
||||
|
||||
@@ -2,3 +2,4 @@ import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind
|
||||
import semmle.code.cpp.ir.implementation.IRType as IRType
|
||||
import semmle.code.cpp.ir.internal.Overlap as Overlap
|
||||
import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag
|
||||
import semmle.code.cpp.ir.implementation.internal.TOperand as TOperand
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
private import semmle.code.cpp.ir.implementation.internal.TOperand
|
||||
import AliasedSSAOperands
|
||||
@@ -6,6 +6,7 @@ private import Imports::Overlap
|
||||
private import Imports::TInstruction
|
||||
private import Imports::RawIR as RawIR
|
||||
private import SSAInstructions
|
||||
private import SSAOperands
|
||||
private import NewIR
|
||||
|
||||
private class OldBlock = Reachability::ReachableBlock;
|
||||
|
||||
@@ -3,3 +3,4 @@ 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
|
||||
import semmle.code.cpp.ir.implementation.internal.TOperand as TOperand
|
||||
|
||||
@@ -5,3 +5,4 @@ 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
|
||||
import semmle.code.cpp.ir.implementation.internal.TOperand::AliasedSSAOperands as SSAOperands
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
private import TInstruction
|
||||
private import OperandTag
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as RawConstruction
|
||||
private import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedConstruction
|
||||
private import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSAConstruction as AliasedConstruction
|
||||
private import semmle.code.cpp.ir.implementation.raw.IR as Raw
|
||||
private import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as Unaliased
|
||||
private import semmle.code.cpp.ir.implementation.aliased_ssa.IR as Aliased
|
||||
private import semmle.code.cpp.ir.internal.Overlap
|
||||
|
||||
/**
|
||||
* Provides the newtype used to represent operands across all phases of the IR.
|
||||
*/
|
||||
private module Internal {
|
||||
/**
|
||||
* An IR operand. `TOperand` is shared across all phases of the IR. There are branches of this
|
||||
* type for operands created directly from the AST (`TRegisterOperand` and `TNonSSAMemoryOperand`),
|
||||
* for operands computed by each stage of SSA construction (`T*PhiOperand` and
|
||||
* `TAliasedChiOperand`), and a placehold branch for operands that do not exist in a given
|
||||
* stage of IR construction (`TNoOperand`).
|
||||
*/
|
||||
cached
|
||||
newtype TOperand =
|
||||
// RAW
|
||||
TRegisterOperand(TRawInstruction useInstr, RegisterOperandTag tag, TRawInstruction defInstr) {
|
||||
defInstr = RawConstruction::getRegisterOperandDefinition(useInstr, tag) and
|
||||
not RawConstruction::isInCycle(useInstr) and
|
||||
strictcount(RawConstruction::getRegisterOperandDefinition(useInstr, tag)) = 1
|
||||
} or
|
||||
// Placeholder for Phi and Chi operands in stages that don't have the corresponding instructions
|
||||
TNoOperand() { none() } or
|
||||
// Can be "removed" later when there's unreachable code
|
||||
// These operands can be reused across all three stages. They just get different defs.
|
||||
TNonSSAMemoryOperand(Raw::Instruction useInstr, MemoryOperandTag tag) {
|
||||
// Has no definition in raw but will get definitions later
|
||||
useInstr.getOpcode().hasOperand(tag)
|
||||
} or
|
||||
TUnaliasedPhiOperand(
|
||||
Unaliased::PhiInstruction useInstr, Unaliased::Instruction defInstr,
|
||||
Unaliased::IRBlock predecessorBlock, Overlap overlap
|
||||
) {
|
||||
defInstr = UnaliasedConstruction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
|
||||
} or
|
||||
//// ALIASED
|
||||
////
|
||||
// Until we share SSA, these will be all the phis there are. With SSA
|
||||
// sharing, these will add to the ones that are already there.
|
||||
// If we share SSA, be careful with the case where we remove all possible
|
||||
// indirect writes to a variable because they're dead code. In that case it's
|
||||
// important that we use the same definition of "is variable aliased" across
|
||||
// the phases.
|
||||
TAliasedPhiOperand(
|
||||
TAliasedSSAPhiInstruction useInstr, Aliased::Instruction defInstr,
|
||||
Aliased::IRBlock predecessorBlock, Overlap overlap
|
||||
) {
|
||||
defInstr = AliasedConstruction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
|
||||
} or
|
||||
TAliasedChiOperand(TAliasedSSAChiInstruction useInstr, ChiOperandTag tag) { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Reexports some branches from `TOperand` so they can be used in stage modules without importing
|
||||
* `TOperand` itself.
|
||||
*/
|
||||
private module Shared {
|
||||
class TRegisterOperand = Internal::TRegisterOperand;
|
||||
|
||||
/**
|
||||
* Returns the register operand with the specified parameters.
|
||||
*/
|
||||
TRegisterOperand registerOperand(
|
||||
TRawInstruction useInstr, RegisterOperandTag tag, TRawInstruction defInstr
|
||||
) {
|
||||
result = Internal::TRegisterOperand(useInstr, tag, defInstr)
|
||||
}
|
||||
|
||||
class TNonSSAMemoryOperand = Internal::TNonSSAMemoryOperand;
|
||||
|
||||
/**
|
||||
* Returns the non-Phi memory operand with the specified parameters.
|
||||
*/
|
||||
TNonSSAMemoryOperand nonSSAMemoryOperand(TRawInstruction useInstr, MemoryOperandTag tag) {
|
||||
result = Internal::TNonSSAMemoryOperand(useInstr, tag)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides wrappers for the constructors of each branch of `TOperand` that is used by the
|
||||
* raw IR stage.
|
||||
* These wrappers are not parameterized because it is not possible to invoke an IPA constructor via
|
||||
* a class alias.
|
||||
*/
|
||||
module RawOperands {
|
||||
import Shared
|
||||
|
||||
class TPhiOperand = Internal::TNoOperand;
|
||||
|
||||
class TChiOperand = Internal::TNoOperand;
|
||||
|
||||
class TNonPhiMemoryOperand = TNonSSAMemoryOperand or TChiOperand;
|
||||
|
||||
/**
|
||||
* Returns the Phi operand with the specified parameters.
|
||||
*/
|
||||
TPhiOperand phiOperand(
|
||||
Raw::PhiInstruction useInstr, Raw::Instruction defInstr, Raw::IRBlock predecessorBlock,
|
||||
Overlap overlap
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Chi operand with the specified parameters.
|
||||
*/
|
||||
TChiOperand chiOperand(Raw::Instruction useInstr, ChiOperandTag tag) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides wrappers for the constructors of each branch of `TOperand` 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 UnaliasedSSAOperands {
|
||||
import Shared
|
||||
|
||||
class TPhiOperand = Internal::TUnaliasedPhiOperand;
|
||||
|
||||
class TChiOperand = Internal::TNoOperand;
|
||||
|
||||
class TNonPhiMemoryOperand = TNonSSAMemoryOperand or TChiOperand;
|
||||
|
||||
/**
|
||||
* Returns the Phi operand with the specified parameters.
|
||||
*/
|
||||
TPhiOperand phiOperand(
|
||||
Unaliased::PhiInstruction useInstr, Unaliased::Instruction defInstr,
|
||||
Unaliased::IRBlock predecessorBlock, Overlap overlap
|
||||
) {
|
||||
result = Internal::TUnaliasedPhiOperand(useInstr, defInstr, predecessorBlock, overlap)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Chi operand with the specified parameters.
|
||||
*/
|
||||
TChiOperand chiOperand(Unaliased::Instruction useInstr, ChiOperandTag tag) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides wrappers for the constructors of each branch of `TOperand` that is used by the
|
||||
* asliased SSA stage.
|
||||
* These wrappers are not parameterized because it is not possible to invoke an IPA constructor via
|
||||
* a class alias.
|
||||
*/
|
||||
module AliasedSSAOperands {
|
||||
import Shared
|
||||
|
||||
class TPhiOperand = Internal::TAliasedPhiOperand;
|
||||
|
||||
class TChiOperand = Internal::TAliasedChiOperand;
|
||||
|
||||
class TNonPhiMemoryOperand = TNonSSAMemoryOperand or TChiOperand;
|
||||
|
||||
/**
|
||||
* Returns the Phi operand with the specified parameters.
|
||||
*/
|
||||
TPhiOperand phiOperand(
|
||||
TAliasedSSAPhiInstruction useInstr, Aliased::Instruction defInstr,
|
||||
Aliased::IRBlock predecessorBlock, Overlap overlap
|
||||
) {
|
||||
result = Internal::TAliasedPhiOperand(useInstr, defInstr, predecessorBlock, overlap)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Chi operand with the specified parameters.
|
||||
*/
|
||||
TChiOperand chiOperand(TAliasedSSAChiInstruction useInstr, ChiOperandTag tag) {
|
||||
result = Internal::TAliasedChiOperand(useInstr, tag)
|
||||
}
|
||||
}
|
||||
@@ -10,79 +10,32 @@ private import Imports::MemoryAccessKind
|
||||
private import Imports::IRType
|
||||
private import Imports::Overlap
|
||||
private import Imports::OperandTag
|
||||
|
||||
cached
|
||||
private newtype TOperand =
|
||||
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
|
||||
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
|
||||
not Construction::isInCycle(useInstr) and
|
||||
strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1
|
||||
} or
|
||||
TNonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) {
|
||||
useInstr.getOpcode().hasOperand(tag)
|
||||
} or
|
||||
TPhiOperand(
|
||||
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
|
||||
) {
|
||||
defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
|
||||
}
|
||||
private import Imports::TOperand
|
||||
private import internal.OperandInternal
|
||||
|
||||
/**
|
||||
* Base class for all register operands. This is a placeholder for the IPA union type that we will
|
||||
* eventually use for this purpose.
|
||||
* An operand of an `Instruction` in this stage of the IR. Implemented as a union of the branches
|
||||
* of `TOperand` that are used in this stage.
|
||||
*/
|
||||
private class RegisterOperandBase extends TRegisterOperand {
|
||||
/** Gets a textual representation of this element. */
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the register operand with the specified parameters.
|
||||
*/
|
||||
private RegisterOperandBase registerOperand(
|
||||
Instruction useInstr, RegisterOperandTag tag, Instruction defInstr
|
||||
) {
|
||||
result = TRegisterOperand(useInstr, tag, defInstr)
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for all non-Phi memory operands. This is a placeholder for the IPA union type that we
|
||||
* will eventually use for this purpose.
|
||||
*/
|
||||
private class NonPhiMemoryOperandBase extends TNonPhiMemoryOperand {
|
||||
/** Gets a textual representation of this element. */
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the non-Phi memory operand with the specified parameters.
|
||||
*/
|
||||
private NonPhiMemoryOperandBase nonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) {
|
||||
result = TNonPhiMemoryOperand(useInstr, tag)
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for all Phi operands. This is a placeholder for the IPA union type that we will
|
||||
* eventually use for this purpose.
|
||||
*/
|
||||
private class PhiOperandBase extends TPhiOperand {
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Phi operand with the specified parameters.
|
||||
*/
|
||||
private PhiOperandBase phiOperand(
|
||||
Instruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
|
||||
) {
|
||||
result = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap)
|
||||
}
|
||||
private class TStageOperand =
|
||||
TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand;
|
||||
|
||||
/**
|
||||
* An operand of an `Instruction`. The operand represents a use of the result of one instruction
|
||||
* (the defining instruction) in another instruction (the use instruction)
|
||||
*/
|
||||
class Operand extends TOperand {
|
||||
class Operand extends TStageOperand {
|
||||
cached
|
||||
Operand() {
|
||||
// Ensure that the operand does not refer to instructions from earlier stages that are unreachable here
|
||||
exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) or
|
||||
exists(Instruction use | this = nonSSAMemoryOperand(use, _)) or
|
||||
exists(Instruction use, Instruction def, IRBlock predecessorBlock |
|
||||
this = phiOperand(use, def, predecessorBlock, _)
|
||||
) or
|
||||
exists(Instruction use | this = chiOperand(use, _))
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = "Operand" }
|
||||
|
||||
@@ -238,9 +191,11 @@ class Operand extends TOperand {
|
||||
* An operand that consumes a memory result (e.g. the `LoadOperand` on a `Load` instruction).
|
||||
*/
|
||||
class MemoryOperand extends Operand {
|
||||
cached
|
||||
MemoryOperand() {
|
||||
this instanceof NonPhiMemoryOperandBase or
|
||||
this instanceof PhiOperandBase
|
||||
this instanceof TNonSSAMemoryOperand or
|
||||
this instanceof TPhiOperand or
|
||||
this instanceof TChiOperand
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -278,7 +233,8 @@ class NonPhiOperand extends Operand {
|
||||
|
||||
NonPhiOperand() {
|
||||
this = registerOperand(useInstr, tag, _) or
|
||||
this = nonPhiMemoryOperand(useInstr, tag)
|
||||
this = nonSSAMemoryOperand(useInstr, tag) or
|
||||
this = chiOperand(useInstr, tag)
|
||||
}
|
||||
|
||||
final override Instruction getUse() { result = useInstr }
|
||||
@@ -298,10 +254,11 @@ class NonPhiOperand extends Operand {
|
||||
/**
|
||||
* An operand that consumes a register (non-memory) result.
|
||||
*/
|
||||
class RegisterOperand extends NonPhiOperand, RegisterOperandBase {
|
||||
class RegisterOperand extends NonPhiOperand, TRegisterOperand {
|
||||
override RegisterOperandTag tag;
|
||||
Instruction defInstr;
|
||||
|
||||
cached
|
||||
RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) }
|
||||
|
||||
final override string toString() { result = tag.toString() }
|
||||
@@ -317,10 +274,15 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase {
|
||||
/**
|
||||
* A memory operand other than the operand of a `Phi` instruction.
|
||||
*/
|
||||
class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase {
|
||||
class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand {
|
||||
override MemoryOperandTag tag;
|
||||
|
||||
NonPhiMemoryOperand() { this = nonPhiMemoryOperand(useInstr, tag) }
|
||||
cached
|
||||
NonPhiMemoryOperand() {
|
||||
this = nonSSAMemoryOperand(useInstr, tag)
|
||||
or
|
||||
this = chiOperand(useInstr, tag)
|
||||
}
|
||||
|
||||
final override string toString() { result = tag.toString() }
|
||||
|
||||
@@ -462,12 +424,13 @@ class SideEffectOperand extends TypedOperand {
|
||||
/**
|
||||
* An operand of a `PhiInstruction`.
|
||||
*/
|
||||
class PhiInputOperand extends MemoryOperand, PhiOperandBase {
|
||||
class PhiInputOperand extends MemoryOperand, TPhiOperand {
|
||||
PhiInstruction useInstr;
|
||||
Instruction defInstr;
|
||||
IRBlock predecessorBlock;
|
||||
Overlap overlap;
|
||||
|
||||
cached
|
||||
PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) }
|
||||
|
||||
override string toString() { result = "Phi" }
|
||||
|
||||
@@ -2,3 +2,4 @@ import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind
|
||||
import semmle.code.cpp.ir.implementation.IRType as IRType
|
||||
import semmle.code.cpp.ir.internal.Overlap as Overlap
|
||||
import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag
|
||||
import semmle.code.cpp.ir.implementation.internal.TOperand as TOperand
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
private import semmle.code.cpp.ir.implementation.internal.TOperand
|
||||
import RawOperands
|
||||
@@ -10,79 +10,32 @@ private import Imports::MemoryAccessKind
|
||||
private import Imports::IRType
|
||||
private import Imports::Overlap
|
||||
private import Imports::OperandTag
|
||||
|
||||
cached
|
||||
private newtype TOperand =
|
||||
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
|
||||
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
|
||||
not Construction::isInCycle(useInstr) and
|
||||
strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1
|
||||
} or
|
||||
TNonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) {
|
||||
useInstr.getOpcode().hasOperand(tag)
|
||||
} or
|
||||
TPhiOperand(
|
||||
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
|
||||
) {
|
||||
defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
|
||||
}
|
||||
private import Imports::TOperand
|
||||
private import internal.OperandInternal
|
||||
|
||||
/**
|
||||
* Base class for all register operands. This is a placeholder for the IPA union type that we will
|
||||
* eventually use for this purpose.
|
||||
* An operand of an `Instruction` in this stage of the IR. Implemented as a union of the branches
|
||||
* of `TOperand` that are used in this stage.
|
||||
*/
|
||||
private class RegisterOperandBase extends TRegisterOperand {
|
||||
/** Gets a textual representation of this element. */
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the register operand with the specified parameters.
|
||||
*/
|
||||
private RegisterOperandBase registerOperand(
|
||||
Instruction useInstr, RegisterOperandTag tag, Instruction defInstr
|
||||
) {
|
||||
result = TRegisterOperand(useInstr, tag, defInstr)
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for all non-Phi memory operands. This is a placeholder for the IPA union type that we
|
||||
* will eventually use for this purpose.
|
||||
*/
|
||||
private class NonPhiMemoryOperandBase extends TNonPhiMemoryOperand {
|
||||
/** Gets a textual representation of this element. */
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the non-Phi memory operand with the specified parameters.
|
||||
*/
|
||||
private NonPhiMemoryOperandBase nonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) {
|
||||
result = TNonPhiMemoryOperand(useInstr, tag)
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for all Phi operands. This is a placeholder for the IPA union type that we will
|
||||
* eventually use for this purpose.
|
||||
*/
|
||||
private class PhiOperandBase extends TPhiOperand {
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Phi operand with the specified parameters.
|
||||
*/
|
||||
private PhiOperandBase phiOperand(
|
||||
Instruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
|
||||
) {
|
||||
result = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap)
|
||||
}
|
||||
private class TStageOperand =
|
||||
TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand;
|
||||
|
||||
/**
|
||||
* An operand of an `Instruction`. The operand represents a use of the result of one instruction
|
||||
* (the defining instruction) in another instruction (the use instruction)
|
||||
*/
|
||||
class Operand extends TOperand {
|
||||
class Operand extends TStageOperand {
|
||||
cached
|
||||
Operand() {
|
||||
// Ensure that the operand does not refer to instructions from earlier stages that are unreachable here
|
||||
exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) or
|
||||
exists(Instruction use | this = nonSSAMemoryOperand(use, _)) or
|
||||
exists(Instruction use, Instruction def, IRBlock predecessorBlock |
|
||||
this = phiOperand(use, def, predecessorBlock, _)
|
||||
) or
|
||||
exists(Instruction use | this = chiOperand(use, _))
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = "Operand" }
|
||||
|
||||
@@ -238,9 +191,11 @@ class Operand extends TOperand {
|
||||
* An operand that consumes a memory result (e.g. the `LoadOperand` on a `Load` instruction).
|
||||
*/
|
||||
class MemoryOperand extends Operand {
|
||||
cached
|
||||
MemoryOperand() {
|
||||
this instanceof NonPhiMemoryOperandBase or
|
||||
this instanceof PhiOperandBase
|
||||
this instanceof TNonSSAMemoryOperand or
|
||||
this instanceof TPhiOperand or
|
||||
this instanceof TChiOperand
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -278,7 +233,8 @@ class NonPhiOperand extends Operand {
|
||||
|
||||
NonPhiOperand() {
|
||||
this = registerOperand(useInstr, tag, _) or
|
||||
this = nonPhiMemoryOperand(useInstr, tag)
|
||||
this = nonSSAMemoryOperand(useInstr, tag) or
|
||||
this = chiOperand(useInstr, tag)
|
||||
}
|
||||
|
||||
final override Instruction getUse() { result = useInstr }
|
||||
@@ -298,10 +254,11 @@ class NonPhiOperand extends Operand {
|
||||
/**
|
||||
* An operand that consumes a register (non-memory) result.
|
||||
*/
|
||||
class RegisterOperand extends NonPhiOperand, RegisterOperandBase {
|
||||
class RegisterOperand extends NonPhiOperand, TRegisterOperand {
|
||||
override RegisterOperandTag tag;
|
||||
Instruction defInstr;
|
||||
|
||||
cached
|
||||
RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) }
|
||||
|
||||
final override string toString() { result = tag.toString() }
|
||||
@@ -317,10 +274,15 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase {
|
||||
/**
|
||||
* A memory operand other than the operand of a `Phi` instruction.
|
||||
*/
|
||||
class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase {
|
||||
class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand {
|
||||
override MemoryOperandTag tag;
|
||||
|
||||
NonPhiMemoryOperand() { this = nonPhiMemoryOperand(useInstr, tag) }
|
||||
cached
|
||||
NonPhiMemoryOperand() {
|
||||
this = nonSSAMemoryOperand(useInstr, tag)
|
||||
or
|
||||
this = chiOperand(useInstr, tag)
|
||||
}
|
||||
|
||||
final override string toString() { result = tag.toString() }
|
||||
|
||||
@@ -462,12 +424,13 @@ class SideEffectOperand extends TypedOperand {
|
||||
/**
|
||||
* An operand of a `PhiInstruction`.
|
||||
*/
|
||||
class PhiInputOperand extends MemoryOperand, PhiOperandBase {
|
||||
class PhiInputOperand extends MemoryOperand, TPhiOperand {
|
||||
PhiInstruction useInstr;
|
||||
Instruction defInstr;
|
||||
IRBlock predecessorBlock;
|
||||
Overlap overlap;
|
||||
|
||||
cached
|
||||
PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) }
|
||||
|
||||
override string toString() { result = "Phi" }
|
||||
|
||||
@@ -2,3 +2,4 @@ import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind
|
||||
import semmle.code.cpp.ir.implementation.IRType as IRType
|
||||
import semmle.code.cpp.ir.internal.Overlap as Overlap
|
||||
import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag
|
||||
import semmle.code.cpp.ir.implementation.internal.TOperand as TOperand
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
private import semmle.code.cpp.ir.implementation.internal.TOperand
|
||||
import UnaliasedSSAOperands
|
||||
@@ -6,6 +6,7 @@ private import Imports::Overlap
|
||||
private import Imports::TInstruction
|
||||
private import Imports::RawIR as RawIR
|
||||
private import SSAInstructions
|
||||
private import SSAOperands
|
||||
private import NewIR
|
||||
|
||||
private class OldBlock = Reachability::ReachableBlock;
|
||||
|
||||
@@ -3,3 +3,4 @@ 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
|
||||
import semmle.code.cpp.ir.implementation.internal.TOperand as TOperand
|
||||
|
||||
@@ -6,3 +6,4 @@ 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
|
||||
import semmle.code.cpp.ir.implementation.internal.TOperand::UnaliasedSSAOperands as SSAOperands
|
||||
|
||||
Reference in New Issue
Block a user