зеркало из https://github.com/github/codeql.git
C# IR: Add support for multiple decls and updates
Added support for multiple declarations and updates in a for stmt. Added test cases and updated the expected output.
This commit is contained in:
Родитель
ad4715fd52
Коммит
d9f3c14c9c
|
@ -179,7 +179,7 @@ private module Cached {
|
||||||
exists(TranslatedElement bodyOrUpdate |
|
exists(TranslatedElement bodyOrUpdate |
|
||||||
bodyOrUpdate = s.getBody()
|
bodyOrUpdate = s.getBody()
|
||||||
or
|
or
|
||||||
bodyOrUpdate = s.getUpdate()
|
bodyOrUpdate = s.getUpdate(_)
|
||||||
|
|
|
|
||||||
inLoop = bodyOrUpdate.getAChild*()
|
inLoop = bodyOrUpdate.getAChild*()
|
||||||
) and
|
) and
|
||||||
|
|
|
@ -10,7 +10,7 @@ private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The IR translation of a call to a function. The function can be a normal function
|
* The IR translation of a call to a function. The function can be a normal function
|
||||||
* (ie. `MethodCall`) or a constructor call (ie. `ObjectCreation`). Notice that the
|
* (eg. `MethodCall`) or a constructor call (eg. `ObjectCreation`). Notice that the
|
||||||
* AST generated translated calls are tied to an expression (unlike compiler generated ones,
|
* AST generated translated calls are tied to an expression (unlike compiler generated ones,
|
||||||
* which can be attached to either a statement or an expression).
|
* which can be attached to either a statement or an expression).
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -651,43 +651,70 @@ class TranslatedForStmt extends TranslatedLoop {
|
||||||
override ForStmt stmt;
|
override ForStmt stmt;
|
||||||
|
|
||||||
override TranslatedElement getChild(int id) {
|
override TranslatedElement getChild(int id) {
|
||||||
id = 0 and result = this.getDeclAndInit()
|
initializerIndices(id) and result = this.getDeclAndInit(id)
|
||||||
or
|
or
|
||||||
id = 1 and result = this.getCondition()
|
updateIndices(id) and result = this.getUpdate(id - initializersNo())
|
||||||
or
|
or
|
||||||
id = 2 and result = this.getUpdate()
|
id = initializersNo() + updatesNo() and result = this.getCondition()
|
||||||
or
|
or
|
||||||
id = 3 and result = this.getBody()
|
id = initializersNo() + updatesNo() + 1 and result = this.getBody()
|
||||||
}
|
}
|
||||||
|
|
||||||
private TranslatedLocalDeclaration getDeclAndInit() {
|
private TranslatedLocalDeclaration getDeclAndInit(int index) {
|
||||||
result = getTranslatedLocalDeclaration(stmt.getAnInitializer())
|
result = getTranslatedLocalDeclaration(stmt.getInitializer(index))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate hasInitialization() { exists(stmt.getAnInitializer()) }
|
private predicate hasInitialization() { exists(stmt.getAnInitializer()) }
|
||||||
|
|
||||||
TranslatedExpr getUpdate() { result = getTranslatedExpr(stmt.getAnUpdate()) }
|
TranslatedExpr getUpdate(int index) { result = getTranslatedExpr(stmt.getUpdate(index)) }
|
||||||
|
|
||||||
private predicate hasUpdate() { exists(stmt.getAnUpdate()) }
|
private predicate hasUpdate() { exists(stmt.getAnUpdate()) }
|
||||||
|
|
||||||
|
private int initializersNo() { result = count(stmt.getAnInitializer()) }
|
||||||
|
|
||||||
|
private int updatesNo() { result = count(stmt.getAnUpdate()) }
|
||||||
|
|
||||||
|
private predicate initializerIndices(int index) { index in [0 .. initializersNo() - 1] }
|
||||||
|
|
||||||
|
private predicate updateIndices(int index) {
|
||||||
|
index in [initializersNo() .. initializersNo() + updatesNo() - 1]
|
||||||
|
}
|
||||||
|
|
||||||
override Instruction getFirstInstruction() {
|
override Instruction getFirstInstruction() {
|
||||||
if this.hasInitialization()
|
if this.hasInitialization()
|
||||||
then result = this.getDeclAndInit().getFirstInstruction()
|
then result = this.getDeclAndInit(0).getFirstInstruction()
|
||||||
else result = this.getFirstConditionInstruction()
|
else result = this.getFirstConditionInstruction()
|
||||||
}
|
}
|
||||||
|
|
||||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||||
child = this.getDeclAndInit() and
|
exists(int index |
|
||||||
|
this.hasInitialization() and
|
||||||
|
child = this.getDeclAndInit(index) and
|
||||||
|
index < initializersNo() - 1 and
|
||||||
|
result = this.getDeclAndInit(index + 1).getFirstInstruction()
|
||||||
|
)
|
||||||
|
or
|
||||||
|
this.hasInitialization() and
|
||||||
|
child = this.getDeclAndInit(initializersNo() - 1) and
|
||||||
result = this.getFirstConditionInstruction()
|
result = this.getFirstConditionInstruction()
|
||||||
or
|
or
|
||||||
(
|
(
|
||||||
child = this.getBody() and
|
child = this.getBody() and
|
||||||
if this.hasUpdate()
|
if this.hasUpdate()
|
||||||
then result = this.getUpdate().getFirstInstruction()
|
then result = this.getUpdate(0).getFirstInstruction()
|
||||||
else result = this.getFirstConditionInstruction()
|
else result = this.getFirstConditionInstruction()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
child = this.getUpdate() and result = this.getFirstConditionInstruction()
|
exists(int index |
|
||||||
|
this.hasUpdate() and
|
||||||
|
child = this.getUpdate(index) and
|
||||||
|
index < updatesNo() - 1 and
|
||||||
|
result = this.getUpdate(index + 1).getFirstInstruction()
|
||||||
|
)
|
||||||
|
or
|
||||||
|
this.hasUpdate() and
|
||||||
|
child = this.getUpdate(updatesNo() - 1) and
|
||||||
|
result = this.getFirstConditionInstruction()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
* (both AST generated and compiler generated).
|
* (both AST generated and compiler generated).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
import csharp
|
import csharp
|
||||||
private import semmle.code.csharp.ir.implementation.Opcode
|
private import semmle.code.csharp.ir.implementation.Opcode
|
||||||
private import semmle.code.csharp.ir.implementation.internal.OperandTag
|
private import semmle.code.csharp.ir.implementation.internal.OperandTag
|
||||||
|
@ -22,125 +21,108 @@ abstract class TranslatedCallBase extends TranslatedElement {
|
||||||
// though the `this` argument exists and is the result of the instruction
|
// though the `this` argument exists and is the result of the instruction
|
||||||
// that allocated the new object. For those calls, `getQualifier()` should
|
// that allocated the new object. For those calls, `getQualifier()` should
|
||||||
// be void.
|
// be void.
|
||||||
id = -1 and result = getQualifier() or
|
id = -1 and result = getQualifier()
|
||||||
|
or
|
||||||
result = getArgument(id)
|
result = getArgument(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
override final Instruction getFirstInstruction() {
|
final override Instruction getFirstInstruction() {
|
||||||
if exists(getQualifier()) then
|
if exists(getQualifier())
|
||||||
result = getQualifier().getFirstInstruction()
|
then result = getQualifier().getFirstInstruction()
|
||||||
else
|
else result = getInstruction(CallTargetTag())
|
||||||
result = getInstruction(CallTargetTag())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
override predicate hasInstruction(
|
||||||
Type resultType, boolean isLValue) {
|
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
|
||||||
|
) {
|
||||||
|
tag = CallTag() and
|
||||||
|
opcode instanceof Opcode::Call and
|
||||||
|
resultType = getCallResultType() and
|
||||||
|
isLValue = false
|
||||||
|
or
|
||||||
|
hasSideEffect() and
|
||||||
|
tag = CallSideEffectTag() and
|
||||||
(
|
(
|
||||||
tag = CallTag() and
|
if hasWriteSideEffect()
|
||||||
opcode instanceof Opcode::Call and
|
then (
|
||||||
resultType = getCallResultType() and
|
opcode instanceof Opcode::CallSideEffect and
|
||||||
isLValue = false
|
resultType instanceof Language::UnknownType
|
||||||
) or
|
) else (
|
||||||
(
|
opcode instanceof Opcode::CallReadSideEffect and
|
||||||
hasSideEffect() and
|
resultType instanceof Language::UnknownType
|
||||||
tag = CallSideEffectTag() and
|
)
|
||||||
(
|
) and
|
||||||
if hasWriteSideEffect() then (
|
isLValue = false
|
||||||
opcode instanceof Opcode::CallSideEffect and
|
or
|
||||||
resultType instanceof Language::UnknownType
|
tag = CallTargetTag() and
|
||||||
)
|
opcode instanceof Opcode::FunctionAddress and
|
||||||
else (
|
// Since the DB does not have a function type,
|
||||||
opcode instanceof Opcode::CallReadSideEffect and
|
// we just use the UnknownType
|
||||||
resultType instanceof Language::UnknownType
|
resultType instanceof Language::UnknownType and
|
||||||
)
|
isLValue = true
|
||||||
) and
|
|
||||||
isLValue = false
|
|
||||||
) or
|
|
||||||
(
|
|
||||||
tag = CallTargetTag() and
|
|
||||||
opcode instanceof Opcode::FunctionAddress and
|
|
||||||
// Since the DB does not have a function type,
|
|
||||||
// we just use the UnknownType
|
|
||||||
resultType instanceof Language::UnknownType and
|
|
||||||
isLValue = true
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||||
(
|
child = getQualifier() and
|
||||||
child = getQualifier() and
|
result = getInstruction(CallTargetTag())
|
||||||
result = getInstruction(CallTargetTag())
|
or
|
||||||
) or
|
|
||||||
exists(int argIndex |
|
exists(int argIndex |
|
||||||
child = getArgument(argIndex) and
|
child = getArgument(argIndex) and
|
||||||
if exists(getArgument(argIndex + 1)) then
|
if exists(getArgument(argIndex + 1))
|
||||||
result = getArgument(argIndex + 1).getFirstInstruction()
|
then result = getArgument(argIndex + 1).getFirstInstruction()
|
||||||
else
|
else result = getInstruction(CallTag())
|
||||||
result = getInstruction(CallTag())
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||||
EdgeKind kind) {
|
|
||||||
kind instanceof GotoEdge and
|
kind instanceof GotoEdge and
|
||||||
(
|
(
|
||||||
(
|
(
|
||||||
tag = CallTag() and
|
tag = CallTag() and
|
||||||
if hasSideEffect() then
|
if hasSideEffect()
|
||||||
result = getInstruction(CallSideEffectTag())
|
then result = getInstruction(CallSideEffectTag())
|
||||||
else
|
else result = getParent().getChildSuccessor(this)
|
||||||
result = getParent().getChildSuccessor(this)
|
|
||||||
) or
|
|
||||||
(
|
|
||||||
hasSideEffect() and
|
|
||||||
tag = CallSideEffectTag() and
|
|
||||||
result = getParent().getChildSuccessor(this)
|
|
||||||
) or
|
|
||||||
(
|
|
||||||
tag = CallTargetTag() and
|
|
||||||
kind instanceof GotoEdge and
|
|
||||||
result = getFirstArgumentOrCallInstruction()
|
|
||||||
)
|
)
|
||||||
)
|
or
|
||||||
}
|
|
||||||
|
|
||||||
override Instruction getInstructionOperand(InstructionTag tag,
|
|
||||||
OperandTag operandTag) {
|
|
||||||
(
|
|
||||||
tag = CallTag() and
|
|
||||||
(
|
|
||||||
(
|
|
||||||
operandTag instanceof CallTargetOperandTag and
|
|
||||||
result = getInstruction(CallTargetTag())
|
|
||||||
) or
|
|
||||||
(
|
|
||||||
operandTag instanceof ThisArgumentOperandTag and
|
|
||||||
result = getQualifierResult()
|
|
||||||
) or
|
|
||||||
exists(PositionalArgumentOperandTag argTag |
|
|
||||||
argTag = operandTag and
|
|
||||||
result = getArgument(argTag.getArgIndex()).getResult()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
) or
|
|
||||||
(
|
|
||||||
tag = CallSideEffectTag() and
|
|
||||||
hasSideEffect() and
|
hasSideEffect() and
|
||||||
operandTag instanceof SideEffectOperandTag and
|
tag = CallSideEffectTag() and
|
||||||
result = getUnmodeledDefinitionInstruction()
|
result = getParent().getChildSuccessor(this)
|
||||||
|
or
|
||||||
|
tag = CallTargetTag() and
|
||||||
|
kind instanceof GotoEdge and
|
||||||
|
result = getFirstArgumentOrCallInstruction()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override final Type getInstructionOperandType(InstructionTag tag,
|
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||||
TypedOperandTag operandTag) {
|
tag = CallTag() and
|
||||||
|
(
|
||||||
|
operandTag instanceof CallTargetOperandTag and
|
||||||
|
result = getInstruction(CallTargetTag())
|
||||||
|
or
|
||||||
|
operandTag instanceof ThisArgumentOperandTag and
|
||||||
|
result = getQualifierResult()
|
||||||
|
or
|
||||||
|
exists(PositionalArgumentOperandTag argTag |
|
||||||
|
argTag = operandTag and
|
||||||
|
result = getArgument(argTag.getArgIndex()).getResult()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
tag = CallSideEffectTag() and
|
||||||
|
hasSideEffect() and
|
||||||
|
operandTag instanceof SideEffectOperandTag and
|
||||||
|
result = getUnmodeledDefinitionInstruction()
|
||||||
|
}
|
||||||
|
|
||||||
|
final override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) {
|
||||||
tag = CallSideEffectTag() and
|
tag = CallSideEffectTag() and
|
||||||
hasSideEffect() and
|
hasSideEffect() and
|
||||||
operandTag instanceof SideEffectOperandTag and
|
operandTag instanceof SideEffectOperandTag and
|
||||||
result instanceof Language::UnknownType
|
result instanceof Language::UnknownType
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction getResult() {
|
Instruction getResult() { result = getInstruction(CallTag()) }
|
||||||
result = getInstruction(CallTag())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the result type of the call.
|
* Gets the result type of the call.
|
||||||
|
@ -156,9 +138,7 @@ abstract class TranslatedCallBase extends TranslatedElement {
|
||||||
/**
|
/**
|
||||||
* Holds if the call has a `this` argument.
|
* Holds if the call has a `this` argument.
|
||||||
*/
|
*/
|
||||||
predicate hasQualifier() {
|
predicate hasQualifier() { exists(getQualifier()) }
|
||||||
exists(getQualifier())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the expr for the qualifier of the call.
|
* Gets the expr for the qualifier of the call.
|
||||||
|
@ -186,10 +166,9 @@ abstract class TranslatedCallBase extends TranslatedElement {
|
||||||
* argument. Otherwise, returns the call instruction.
|
* argument. Otherwise, returns the call instruction.
|
||||||
*/
|
*/
|
||||||
final Instruction getFirstArgumentOrCallInstruction() {
|
final Instruction getFirstArgumentOrCallInstruction() {
|
||||||
if hasArguments() then
|
if hasArguments()
|
||||||
result = getArgument(0).getFirstInstruction()
|
then result = getArgument(0).getFirstInstruction()
|
||||||
else
|
else result = getInstruction(CallTag())
|
||||||
result = getInstruction(CallTag())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -199,21 +178,15 @@ abstract class TranslatedCallBase extends TranslatedElement {
|
||||||
exists(getArgument(0))
|
exists(getArgument(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate hasReadSideEffect() {
|
predicate hasReadSideEffect() { any() }
|
||||||
any()
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate hasWriteSideEffect() {
|
predicate hasWriteSideEffect() { any() }
|
||||||
any()
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate hasSideEffect() {
|
private predicate hasSideEffect() { hasReadSideEffect() or hasWriteSideEffect() }
|
||||||
hasReadSideEffect() or hasWriteSideEffect()
|
|
||||||
}
|
|
||||||
|
|
||||||
override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) {
|
override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) {
|
||||||
hasSideEffect() and
|
hasSideEffect() and
|
||||||
tag = CallSideEffectTag() and
|
tag = CallSideEffectTag() and
|
||||||
result = getResult()
|
result = getResult()
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,7 +11,6 @@ private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr
|
||||||
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedCondition
|
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedCondition
|
||||||
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
|
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the context of the condition, ie. provides
|
* Represents the context of the condition, ie. provides
|
||||||
* information about the instruction that follows a conditional branch.
|
* information about the instruction that follows a conditional branch.
|
||||||
|
@ -27,9 +26,7 @@ abstract class ConditionContext extends TranslatedElement {
|
||||||
* and the compiler generated ones (captures the common patterns).
|
* and the compiler generated ones (captures the common patterns).
|
||||||
*/
|
*/
|
||||||
abstract class ConditionBase extends TranslatedElement {
|
abstract class ConditionBase extends TranslatedElement {
|
||||||
final ConditionContext getConditionContext() {
|
final ConditionContext getConditionContext() { result = getParent() }
|
||||||
result = getParent()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,16 +34,13 @@ abstract class ConditionBase extends TranslatedElement {
|
||||||
* and the compiler generated ones (captures the common patterns).
|
* and the compiler generated ones (captures the common patterns).
|
||||||
*/
|
*/
|
||||||
abstract class ValueConditionBase extends ConditionBase {
|
abstract class ValueConditionBase extends ConditionBase {
|
||||||
override TranslatedElement getChild(int id) {
|
override TranslatedElement getChild(int id) { id = 0 and result = getValueExpr() }
|
||||||
id = 0 and result = getValueExpr()
|
|
||||||
}
|
|
||||||
|
|
||||||
override Instruction getFirstInstruction() {
|
override Instruction getFirstInstruction() { result = getValueExpr().getFirstInstruction() }
|
||||||
result = getValueExpr().getFirstInstruction()
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
override predicate hasInstruction(
|
||||||
Type resultType, boolean isLValue) {
|
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
|
||||||
|
) {
|
||||||
tag = ValueConditionConditionalBranchTag() and
|
tag = ValueConditionConditionalBranchTag() and
|
||||||
opcode instanceof Opcode::ConditionalBranch and
|
opcode instanceof Opcode::ConditionalBranch and
|
||||||
resultType instanceof VoidType and
|
resultType instanceof VoidType and
|
||||||
|
@ -58,23 +52,18 @@ abstract class ValueConditionBase extends ConditionBase {
|
||||||
result = getInstruction(ValueConditionConditionalBranchTag())
|
result = getInstruction(ValueConditionConditionalBranchTag())
|
||||||
}
|
}
|
||||||
|
|
||||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||||
EdgeKind kind) {
|
|
||||||
tag = ValueConditionConditionalBranchTag() and
|
tag = ValueConditionConditionalBranchTag() and
|
||||||
(
|
(
|
||||||
(
|
kind instanceof TrueEdge and
|
||||||
kind instanceof TrueEdge and
|
result = getConditionContext().getChildTrueSuccessor(this)
|
||||||
result = getConditionContext().getChildTrueSuccessor(this)
|
or
|
||||||
) or
|
kind instanceof FalseEdge and
|
||||||
(
|
result = getConditionContext().getChildFalseSuccessor(this)
|
||||||
kind instanceof FalseEdge and
|
|
||||||
result = getConditionContext().getChildFalseSuccessor(this)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override Instruction getInstructionOperand(InstructionTag tag,
|
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||||
OperandTag operandTag) {
|
|
||||||
tag = ValueConditionConditionalBranchTag() and
|
tag = ValueConditionConditionalBranchTag() and
|
||||||
operandTag instanceof ConditionOperandTag and
|
operandTag instanceof ConditionOperandTag and
|
||||||
result = valueExprResult()
|
result = valueExprResult()
|
||||||
|
|
|
@ -13,55 +13,47 @@ private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr
|
||||||
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedInitialization
|
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedInitialization
|
||||||
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
|
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
|
||||||
|
|
||||||
|
|
||||||
abstract class LocalVariableDeclarationBase extends TranslatedElement {
|
abstract class LocalVariableDeclarationBase extends TranslatedElement {
|
||||||
override TranslatedElement getChild(int id) {
|
override TranslatedElement getChild(int id) { id = 0 and result = getInitialization() }
|
||||||
id = 0 and result = getInitialization()
|
|
||||||
|
override Instruction getFirstInstruction() { result = getVarAddress() }
|
||||||
|
|
||||||
|
override predicate hasInstruction(
|
||||||
|
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
|
||||||
|
) {
|
||||||
|
tag = InitializerVariableAddressTag() and
|
||||||
|
opcode instanceof Opcode::VariableAddress and
|
||||||
|
resultType = getVarType() and
|
||||||
|
isLValue = true
|
||||||
|
or
|
||||||
|
hasUninitializedInstruction() and
|
||||||
|
tag = InitializerStoreTag() and
|
||||||
|
opcode instanceof Opcode::Uninitialized and
|
||||||
|
resultType = getVarType() and
|
||||||
|
isLValue = false
|
||||||
}
|
}
|
||||||
|
|
||||||
override Instruction getFirstInstruction() {
|
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||||
result = getVarAddress()
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
|
||||||
Type resultType, boolean isLValue) {
|
|
||||||
(
|
|
||||||
tag = InitializerVariableAddressTag() and
|
|
||||||
opcode instanceof Opcode::VariableAddress and
|
|
||||||
resultType = getVarType() and
|
|
||||||
isLValue = true
|
|
||||||
) or
|
|
||||||
(
|
|
||||||
hasUninitializedInstruction() and
|
|
||||||
tag = InitializerStoreTag() and
|
|
||||||
opcode instanceof Opcode::Uninitialized and
|
|
||||||
resultType = getVarType() and
|
|
||||||
isLValue = false
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
|
||||||
EdgeKind kind) {
|
|
||||||
(
|
(
|
||||||
tag = InitializerVariableAddressTag() and
|
tag = InitializerVariableAddressTag() and
|
||||||
kind instanceof GotoEdge and
|
kind instanceof GotoEdge and
|
||||||
if hasUninitializedInstruction() then
|
if hasUninitializedInstruction()
|
||||||
result = getInstruction(InitializerStoreTag())
|
then result = getInstruction(InitializerStoreTag())
|
||||||
else
|
else
|
||||||
if isInitializedByElement() then
|
if isInitializedByElement()
|
||||||
|
then
|
||||||
// initialization is done by an element
|
// initialization is done by an element
|
||||||
result = getParent().getChildSuccessor(this)
|
result = getParent().getChildSuccessor(this)
|
||||||
else
|
else result = getInitialization().getFirstInstruction()
|
||||||
result = getInitialization().getFirstInstruction()
|
)
|
||||||
) or
|
or
|
||||||
|
hasUninitializedInstruction() and
|
||||||
|
kind instanceof GotoEdge and
|
||||||
|
tag = InitializerStoreTag() and
|
||||||
(
|
(
|
||||||
hasUninitializedInstruction() and
|
result = getInitialization().getFirstInstruction()
|
||||||
kind instanceof GotoEdge and
|
or
|
||||||
tag = InitializerStoreTag() and
|
not exists(getInitialization()) and result = getParent().getChildSuccessor(this)
|
||||||
(
|
|
||||||
result = getInitialization().getFirstInstruction() or
|
|
||||||
not exists(getInitialization()) and result = getParent().getChildSuccessor(this)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,9 +82,7 @@ abstract class LocalVariableDeclarationBase extends TranslatedElement {
|
||||||
not isInitializedByElement()
|
not isInitializedByElement()
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction getVarAddress() {
|
Instruction getVarAddress() { result = getInstruction(InitializerVariableAddressTag()) }
|
||||||
result = getInstruction(InitializerVariableAddressTag())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the declared variable. For compiler generated elements, this
|
* Gets the declared variable. For compiler generated elements, this
|
||||||
|
|
|
@ -0,0 +1,251 @@
|
||||||
|
import csharp
|
||||||
|
|
||||||
|
private int getMaxCallArgIndex() {
|
||||||
|
result = max(int argIndex |
|
||||||
|
exists(Call call | exists(call.getArgument(argIndex)))
|
||||||
|
or
|
||||||
|
// Quick fix so that generated calls (`Invoke` etc) will have the
|
||||||
|
// correct number of parameters; it is an overestimation,
|
||||||
|
// since we don't care about all the callables, so it
|
||||||
|
// should be restricted more
|
||||||
|
exists(Callable callable | callable.getNumberOfParameters() = argIndex)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private newtype TOperandTag =
|
||||||
|
TAddressOperand() or
|
||||||
|
TBufferSizeOperand() or
|
||||||
|
TSideEffectOperand() or
|
||||||
|
TLoadOperand() or
|
||||||
|
TStoreValueOperand() or
|
||||||
|
TUnaryOperand() or
|
||||||
|
TLeftOperand() or
|
||||||
|
TRightOperand() or
|
||||||
|
TConditionOperand() or
|
||||||
|
TUnmodeledUseOperand() or
|
||||||
|
TCallTargetOperand() or
|
||||||
|
TThisArgumentOperand() or
|
||||||
|
TPositionalArgumentOperand(int argIndex) { argIndex in [0 .. getMaxCallArgIndex()] } or
|
||||||
|
TChiTotalOperand() or
|
||||||
|
TChiPartialOperand()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifies the kind of operand on an instruction. Each `Instruction` has at
|
||||||
|
* most one operand of any single `OperandTag`. The set of `OperandTag`s used by
|
||||||
|
* an `Instruction` is determined by the instruction's opcode.
|
||||||
|
*/
|
||||||
|
abstract class OperandTag extends TOperandTag {
|
||||||
|
abstract string toString();
|
||||||
|
|
||||||
|
abstract int getSortOrder();
|
||||||
|
|
||||||
|
string getLabel() { result = "" }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An operand that consumes a memory result (e.g. the `LoadOperand` on a `Load` instruction).
|
||||||
|
*/
|
||||||
|
abstract class MemoryOperandTag extends OperandTag { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An operand that consumes a register (non-memory) result.
|
||||||
|
*/
|
||||||
|
abstract class RegisterOperandTag extends OperandTag { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A memory operand whose type may be different from the result type of its definition instruction.
|
||||||
|
*/
|
||||||
|
abstract class TypedOperandTag extends MemoryOperandTag { }
|
||||||
|
|
||||||
|
// Note: individual subtypes are listed in the order that the operands should
|
||||||
|
// appear in the operand list of the instruction when printing.
|
||||||
|
/**
|
||||||
|
* The address operand of an instruction that loads or stores a value from
|
||||||
|
* memory (e.g. `Load`, `Store`, `InitializeParameter`, `IndirectReadSideEffect`).
|
||||||
|
*/
|
||||||
|
class AddressOperandTag extends RegisterOperandTag, TAddressOperand {
|
||||||
|
final override string toString() { result = "Address" }
|
||||||
|
|
||||||
|
final override int getSortOrder() { result = 0 }
|
||||||
|
|
||||||
|
final override string getLabel() { result = "&:" }
|
||||||
|
}
|
||||||
|
|
||||||
|
AddressOperandTag addressOperand() { result = TAddressOperand() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The buffer size operand of an instruction that represents a read or write of
|
||||||
|
* a buffer.
|
||||||
|
*/
|
||||||
|
class BufferSizeOperand extends RegisterOperandTag, TBufferSizeOperand {
|
||||||
|
final override string toString() { result = "BufferSize" }
|
||||||
|
|
||||||
|
final override int getSortOrder() { result = 1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The operand representing the read side effect of a `SideEffectInstruction`.
|
||||||
|
*/
|
||||||
|
class SideEffectOperandTag extends TypedOperandTag, TSideEffectOperand {
|
||||||
|
final override string toString() { result = "SideEffect" }
|
||||||
|
|
||||||
|
final override int getSortOrder() { result = 2 }
|
||||||
|
}
|
||||||
|
|
||||||
|
SideEffectOperandTag sideEffectOperand() { result = TSideEffectOperand() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The source value operand of an instruction that loads a value from memory (e.g. `Load`,
|
||||||
|
* `ReturnValue`, `ThrowValue`).
|
||||||
|
*/
|
||||||
|
class LoadOperandTag extends TypedOperandTag, TLoadOperand {
|
||||||
|
final override string toString() { result = "Load" }
|
||||||
|
|
||||||
|
final override int getSortOrder() { result = 3 }
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadOperandTag loadOperand() { result = TLoadOperand() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The source value operand of a `Store` instruction.
|
||||||
|
*/
|
||||||
|
class StoreValueOperandTag extends RegisterOperandTag, TStoreValueOperand {
|
||||||
|
final override string toString() { result = "StoreValue" }
|
||||||
|
|
||||||
|
final override int getSortOrder() { result = 4 }
|
||||||
|
}
|
||||||
|
|
||||||
|
StoreValueOperandTag storeValueOperand() { result = TStoreValueOperand() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`, `Copy`).
|
||||||
|
*/
|
||||||
|
class UnaryOperandTag extends RegisterOperandTag, TUnaryOperand {
|
||||||
|
final override string toString() { result = "Unary" }
|
||||||
|
|
||||||
|
final override int getSortOrder() { result = 5 }
|
||||||
|
}
|
||||||
|
|
||||||
|
UnaryOperandTag unaryOperand() { result = TUnaryOperand() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||||
|
*/
|
||||||
|
class LeftOperandTag extends RegisterOperandTag, TLeftOperand {
|
||||||
|
final override string toString() { result = "Left" }
|
||||||
|
|
||||||
|
final override int getSortOrder() { result = 6 }
|
||||||
|
}
|
||||||
|
|
||||||
|
LeftOperandTag leftOperand() { result = TLeftOperand() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||||
|
*/
|
||||||
|
class RightOperandTag extends RegisterOperandTag, TRightOperand {
|
||||||
|
final override string toString() { result = "Right" }
|
||||||
|
|
||||||
|
final override int getSortOrder() { result = 7 }
|
||||||
|
}
|
||||||
|
|
||||||
|
RightOperandTag rightOperand() { result = TRightOperand() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
|
||||||
|
*/
|
||||||
|
class ConditionOperandTag extends RegisterOperandTag, TConditionOperand {
|
||||||
|
final override string toString() { result = "Condition" }
|
||||||
|
|
||||||
|
final override int getSortOrder() { result = 8 }
|
||||||
|
}
|
||||||
|
|
||||||
|
ConditionOperandTag conditionOperand() { result = TConditionOperand() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An operand of the special `UnmodeledUse` instruction, representing a value
|
||||||
|
* whose set of uses is unknown.
|
||||||
|
*/
|
||||||
|
class UnmodeledUseOperandTag extends MemoryOperandTag, TUnmodeledUseOperand {
|
||||||
|
final override string toString() { result = "UnmodeledUse" }
|
||||||
|
|
||||||
|
final override int getSortOrder() { result = 9 }
|
||||||
|
}
|
||||||
|
|
||||||
|
UnmodeledUseOperandTag unmodeledUseOperand() { result = TUnmodeledUseOperand() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The operand representing the target function of an `Call` instruction.
|
||||||
|
*/
|
||||||
|
class CallTargetOperandTag extends RegisterOperandTag, TCallTargetOperand {
|
||||||
|
final override string toString() { result = "CallTarget" }
|
||||||
|
|
||||||
|
final override int getSortOrder() { result = 10 }
|
||||||
|
|
||||||
|
final override string getLabel() { result = "func:" }
|
||||||
|
}
|
||||||
|
|
||||||
|
CallTargetOperandTag callTargetOperand() { result = TCallTargetOperand() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An operand representing an argument to a function call. This includes both
|
||||||
|
* positional arguments (represented by `PositionalArgumentOperand`) and the
|
||||||
|
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
|
||||||
|
*/
|
||||||
|
abstract class ArgumentOperandTag extends RegisterOperandTag { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An operand representing the implicit 'this' argument to a member function
|
||||||
|
* call.
|
||||||
|
*/
|
||||||
|
class ThisArgumentOperandTag extends ArgumentOperandTag, TThisArgumentOperand {
|
||||||
|
ThisArgumentOperandTag() { this = TThisArgumentOperand() }
|
||||||
|
|
||||||
|
final override string toString() { result = "Arg(this)" }
|
||||||
|
|
||||||
|
final override int getSortOrder() { result = 11 }
|
||||||
|
|
||||||
|
final override string getLabel() { result = "this:" }
|
||||||
|
}
|
||||||
|
|
||||||
|
ThisArgumentOperandTag thisArgumentOperand() { result = TThisArgumentOperand() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An operand representing an argument to a function call.
|
||||||
|
*/
|
||||||
|
class PositionalArgumentOperandTag extends ArgumentOperandTag, TPositionalArgumentOperand {
|
||||||
|
int argIndex;
|
||||||
|
|
||||||
|
PositionalArgumentOperandTag() { this = TPositionalArgumentOperand(argIndex) }
|
||||||
|
|
||||||
|
final override string toString() { result = "Arg(" + argIndex + ")" }
|
||||||
|
|
||||||
|
final override int getSortOrder() { result = 12 + argIndex }
|
||||||
|
|
||||||
|
final override string getLabel() { result = argIndex.toString() + ":" }
|
||||||
|
|
||||||
|
final int getArgIndex() { result = argIndex }
|
||||||
|
}
|
||||||
|
|
||||||
|
PositionalArgumentOperandTag positionalArgumentOperand(int argIndex) {
|
||||||
|
result = TPositionalArgumentOperand(argIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChiTotalOperandTag extends MemoryOperandTag, TChiTotalOperand {
|
||||||
|
final override string toString() { result = "ChiTotal" }
|
||||||
|
|
||||||
|
final override int getSortOrder() { result = 13 }
|
||||||
|
|
||||||
|
final override string getLabel() { result = "total:" }
|
||||||
|
}
|
||||||
|
|
||||||
|
ChiTotalOperandTag chiTotalOperand() { result = TChiTotalOperand() }
|
||||||
|
|
||||||
|
class ChiPartialOperandTag extends MemoryOperandTag, TChiPartialOperand {
|
||||||
|
final override string toString() { result = "ChiPartial" }
|
||||||
|
|
||||||
|
final override int getSortOrder() { result = 14 }
|
||||||
|
|
||||||
|
final override string getLabel() { result = "partial:" }
|
||||||
|
}
|
||||||
|
|
||||||
|
ChiPartialOperandTag chiPartialOperand() { result = TChiPartialOperand() }
|
|
@ -1048,6 +1048,9 @@ stmts.cs:
|
||||||
# 71| r0_6(glval<Int32>) = VariableAddress[i] :
|
# 71| r0_6(glval<Int32>) = VariableAddress[i] :
|
||||||
# 71| r0_7(Int32) = Constant[0] :
|
# 71| r0_7(Int32) = Constant[0] :
|
||||||
# 71| mu0_8(Int32) = Store : &:r0_6, r0_7
|
# 71| mu0_8(Int32) = Store : &:r0_6, r0_7
|
||||||
|
# 71| r0_9(glval<Int32>) = VariableAddress[j] :
|
||||||
|
# 71| r0_10(Int32) = Constant[10] :
|
||||||
|
# 71| mu0_11(Int32) = Store : &:r0_9, r0_10
|
||||||
#-----| Goto -> Block 2
|
#-----| Goto -> Block 2
|
||||||
|
|
||||||
# 68| Block 1
|
# 68| Block 1
|
||||||
|
@ -1058,53 +1061,86 @@ stmts.cs:
|
||||||
# 71| Block 2
|
# 71| Block 2
|
||||||
# 71| r2_0(glval<Int32>) = VariableAddress[i] :
|
# 71| r2_0(glval<Int32>) = VariableAddress[i] :
|
||||||
# 71| r2_1(Int32) = Load : &:r2_0, ~mu0_2
|
# 71| r2_1(Int32) = Load : &:r2_0, ~mu0_2
|
||||||
# 71| r2_2(Int32) = Constant[10] :
|
# 71| r2_2(glval<Int32>) = VariableAddress[j] :
|
||||||
# 71| r2_3(Boolean) = CompareLE : r2_1, r2_2
|
# 71| r2_3(Int32) = Load : &:r2_2, ~mu0_2
|
||||||
# 71| v2_4(Void) = ConditionalBranch : r2_3
|
# 71| r2_4(Boolean) = CompareLT : r2_1, r2_3
|
||||||
#-----| False -> Block 1
|
# 71| v2_5(Void) = ConditionalBranch : r2_4
|
||||||
|
#-----| False -> Block 4
|
||||||
#-----| True -> Block 3
|
#-----| True -> Block 3
|
||||||
|
|
||||||
# 73| Block 3
|
# 73| Block 3
|
||||||
# 73| r3_0(glval<Int32>) = VariableAddress[x] :
|
# 73| r3_0(glval<Int32>) = VariableAddress[x] :
|
||||||
# 73| r3_1(Int32) = Load : &:r3_0, ~mu0_2
|
# 73| r3_1(Int32) = Load : &:r3_0, ~mu0_2
|
||||||
# 73| r3_2(Int32) = Constant[1] :
|
# 73| r3_2(Int32) = Constant[1] :
|
||||||
# 73| r3_3(Int32) = Sub : r3_1, r3_2
|
# 73| r3_3(Int32) = Sub : r3_1, r3_2
|
||||||
# 73| r3_4(glval<Int32>) = VariableAddress[x] :
|
# 73| r3_4(glval<Int32>) = VariableAddress[x] :
|
||||||
# 73| mu3_5(Int32) = Store : &:r3_4, r3_3
|
# 73| mu3_5(Int32) = Store : &:r3_4, r3_3
|
||||||
# 71| r3_6(glval<Int32>) = VariableAddress[i] :
|
# 71| r3_6(glval<Int32>) = VariableAddress[i] :
|
||||||
# 71| r3_7(Int32) = Load : &:r3_6, ~mu0_2
|
# 71| r3_7(Int32) = Load : &:r3_6, ~mu0_2
|
||||||
# 71| r3_8(Int32) = Constant[1] :
|
# 71| r3_8(Int32) = Constant[1] :
|
||||||
# 71| r3_9(Int32) = Add : r3_7, r3_8
|
# 71| r3_9(Int32) = Add : r3_7, r3_8
|
||||||
# 71| mu3_10(Int32) = Store : &:r3_6, r3_9
|
# 71| mu3_10(Int32) = Store : &:r3_6, r3_9
|
||||||
|
# 71| r3_11(glval<Int32>) = VariableAddress[j] :
|
||||||
|
# 71| r3_12(Int32) = Load : &:r3_11, ~mu0_2
|
||||||
|
# 71| r3_13(Int32) = Constant[1] :
|
||||||
|
# 71| r3_14(Int32) = Sub : r3_12, r3_13
|
||||||
|
# 71| mu3_15(Int32) = Store : &:r3_11, r3_14
|
||||||
#-----| Goto (back edge) -> Block 2
|
#-----| Goto (back edge) -> Block 2
|
||||||
|
|
||||||
# 77| System.Void test_stmts.doWhile()
|
# 76| Block 4
|
||||||
# 77| Block 0
|
# 76| r4_0(glval<Int32>) = VariableAddress[a] :
|
||||||
# 77| v0_0(Void) = EnterFunction :
|
# 76| r4_1(Int32) = Constant[0] :
|
||||||
# 77| mu0_1(null) = AliasedDefinition :
|
# 76| mu4_2(Int32) = Store : &:r4_0, r4_1
|
||||||
# 77| mu0_2(null) = UnmodeledDefinition :
|
# 76| r4_3(glval<Int32>) = VariableAddress[b] :
|
||||||
# 79| r0_3(glval<Int32>) = VariableAddress[x] :
|
# 76| r4_4(Int32) = Constant[10] :
|
||||||
# 79| r0_4(Int32) = Constant[0] :
|
# 76| mu4_5(Int32) = Store : &:r4_3, r4_4
|
||||||
# 79| mu0_5(Int32) = Store : &:r0_3, r0_4
|
#-----| Goto -> Block 5
|
||||||
|
|
||||||
|
# 77| Block 5
|
||||||
|
# 77| r5_0(glval<Int32>) = VariableAddress[a] :
|
||||||
|
# 77| r5_1(Int32) = Load : &:r5_0, ~mu0_2
|
||||||
|
# 77| r5_2(glval<Int32>) = VariableAddress[b] :
|
||||||
|
# 77| r5_3(Int32) = Load : &:r5_2, ~mu0_2
|
||||||
|
# 77| r5_4(Boolean) = CompareLT : r5_1, r5_3
|
||||||
|
# 77| v5_5(Void) = ConditionalBranch : r5_4
|
||||||
|
#-----| False -> Block 1
|
||||||
|
#-----| True -> Block 6
|
||||||
|
|
||||||
|
# 79| Block 6
|
||||||
|
# 79| r6_0(glval<Int32>) = VariableAddress[a] :
|
||||||
|
# 79| r6_1(Int32) = Load : &:r6_0, ~mu0_2
|
||||||
|
# 79| r6_2(Int32) = Constant[1] :
|
||||||
|
# 79| r6_3(Int32) = Add : r6_1, r6_2
|
||||||
|
# 79| mu6_4(Int32) = Store : &:r6_0, r6_3
|
||||||
|
#-----| Goto (back edge) -> Block 5
|
||||||
|
|
||||||
|
# 83| System.Void test_stmts.doWhile()
|
||||||
|
# 83| Block 0
|
||||||
|
# 83| v0_0(Void) = EnterFunction :
|
||||||
|
# 83| mu0_1(null) = AliasedDefinition :
|
||||||
|
# 83| mu0_2(null) = UnmodeledDefinition :
|
||||||
|
# 85| r0_3(glval<Int32>) = VariableAddress[x] :
|
||||||
|
# 85| r0_4(Int32) = Constant[0] :
|
||||||
|
# 85| mu0_5(Int32) = Store : &:r0_3, r0_4
|
||||||
#-----| Goto -> Block 2
|
#-----| Goto -> Block 2
|
||||||
|
|
||||||
# 77| Block 1
|
# 83| Block 1
|
||||||
# 77| v1_0(Void) = ReturnVoid :
|
# 83| v1_0(Void) = ReturnVoid :
|
||||||
# 77| v1_1(Void) = UnmodeledUse : mu*
|
# 83| v1_1(Void) = UnmodeledUse : mu*
|
||||||
# 77| v1_2(Void) = ExitFunction :
|
# 83| v1_2(Void) = ExitFunction :
|
||||||
|
|
||||||
# 82| Block 2
|
# 88| Block 2
|
||||||
# 82| r2_0(glval<Int32>) = VariableAddress[x] :
|
# 88| r2_0(glval<Int32>) = VariableAddress[x] :
|
||||||
# 82| r2_1(Int32) = Load : &:r2_0, ~mu0_2
|
# 88| r2_1(Int32) = Load : &:r2_0, ~mu0_2
|
||||||
# 82| r2_2(Int32) = Constant[1] :
|
# 88| r2_2(Int32) = Constant[1] :
|
||||||
# 82| r2_3(Int32) = Add : r2_1, r2_2
|
# 88| r2_3(Int32) = Add : r2_1, r2_2
|
||||||
# 82| r2_4(glval<Int32>) = VariableAddress[x] :
|
# 88| r2_4(glval<Int32>) = VariableAddress[x] :
|
||||||
# 82| mu2_5(Int32) = Store : &:r2_4, r2_3
|
# 88| mu2_5(Int32) = Store : &:r2_4, r2_3
|
||||||
# 84| r2_6(glval<Int32>) = VariableAddress[x] :
|
# 90| r2_6(glval<Int32>) = VariableAddress[x] :
|
||||||
# 84| r2_7(Int32) = Load : &:r2_6, ~mu0_2
|
# 90| r2_7(Int32) = Load : &:r2_6, ~mu0_2
|
||||||
# 84| r2_8(Int32) = Constant[10] :
|
# 90| r2_8(Int32) = Constant[10] :
|
||||||
# 84| r2_9(Boolean) = CompareLT : r2_7, r2_8
|
# 90| r2_9(Boolean) = CompareLT : r2_7, r2_8
|
||||||
# 84| v2_10(Void) = ConditionalBranch : r2_9
|
# 90| v2_10(Void) = ConditionalBranch : r2_9
|
||||||
#-----| False -> Block 1
|
#-----| False -> Block 1
|
||||||
#-----| True (back edge) -> Block 2
|
#-----| True (back edge) -> Block 2
|
||||||
|
|
||||||
|
|
|
@ -68,10 +68,16 @@ public class test_stmts
|
||||||
public static void forStmt()
|
public static void forStmt()
|
||||||
{
|
{
|
||||||
int x = 0;
|
int x = 0;
|
||||||
for (int i = 0; i <= 10; i++)
|
for (int i = 0, j = 10; i < j; i++, j--)
|
||||||
{
|
{
|
||||||
x = x - 1;
|
x = x - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int a = 0, b = 10;
|
||||||
|
for (; a < b; )
|
||||||
|
{
|
||||||
|
a++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void doWhile()
|
public static void doWhile()
|
||||||
|
|
Загрузка…
Ссылка в новой задаче