mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
C++: Handle casts to void in IR
Casts to `void` did not have a semantic conversion type in the AST, so they also weren't getting generated correctly in the IR. I've added a `VoidConversion` class to the AST, along with tests. I've also added IR translation for such conversions, using a new `ConvertToVoid` opcode. I'm not sure if it's really necessary to generate an instruction to represent this, but it may be useful for detecting values that are explicitly unused (e.g. return value from a call). I added two new sanity queries for the IR to detect the following: - IR blocks with no successors, which usually indicates bad IR translation - Phi instruction without an operand for one of the predecessor blocks. These sanity queries found another subtle IR translation bug. If an expression that is normally translated as a condition (e.g. `&&`, `||`, or parens in certain contexts) has a constant value, we were not creating a `TranslatedExpr` for the expression at all. I changed it to always treat a constant condition as a non-condition expression.
This commit is contained in:
@@ -292,6 +292,20 @@ class BoolConversion extends Cast {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A conversion to `void`.
|
||||
*/
|
||||
class VoidConversion extends Cast {
|
||||
VoidConversion() {
|
||||
conversionkinds(this, 0) and
|
||||
getType().getUnspecifiedType() instanceof VoidType
|
||||
}
|
||||
|
||||
override string getSemanticConversionString() {
|
||||
result = "conversion to void"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A conversion between two pointers or glvalues related by inheritance. The
|
||||
* base class will always be either a direct base class of the derived class,
|
||||
|
||||
@@ -67,6 +67,31 @@ module InstructionSanity {
|
||||
not tag instanceof UnmodeledUseOperand
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `Phi` instruction `instr` has fewer than two operands.
|
||||
*/
|
||||
query predicate missingPhiOperands(PhiInstruction instr, int predIndex, Location predLoc) {
|
||||
exists(IRBlock pred |
|
||||
pred = instr.getBlock().getAPredecessor() and
|
||||
predLoc = pred.getLocation() and
|
||||
predIndex = pred.getDisplayIndex() and
|
||||
not exists(PhiOperand operand |
|
||||
exists(instr.getOperand(operand)) and
|
||||
operand.getPredecessorBlock() = pred
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an instruction, other than `ExitFunction`, has no successors.
|
||||
*/
|
||||
query predicate instructionWithoutSuccessor(Instruction instr) {
|
||||
not exists(instr.getASuccessor()) and
|
||||
not instr instanceof ExitFunctionInstruction and
|
||||
// Phi instructions aren't linked into the instruction-level flow graph.
|
||||
not instr instanceof PhiInstruction
|
||||
}
|
||||
|
||||
query predicate operandAcrossFunctions(
|
||||
Instruction op, Instruction operand, OperandTag tag
|
||||
) {
|
||||
|
||||
@@ -33,6 +33,7 @@ private newtype TOpcode =
|
||||
TPointerSub() or
|
||||
TPointerDiff() or
|
||||
TConvert() or
|
||||
TConvertToVoid() or
|
||||
TConvertToBase() or
|
||||
TConvertToVirtualBase() or
|
||||
TConvertToDerived() or
|
||||
@@ -125,6 +126,7 @@ module Opcode {
|
||||
class PointerSub extends PointerOffsetOpcode, TPointerSub { override final string toString() { result = "PointerSub" } }
|
||||
class PointerDiff extends PointerArithmeticOpcode, TPointerDiff { override final string toString() { result = "PointerDiff" } }
|
||||
class Convert extends UnaryOpcode, TConvert { override final string toString() { result = "Convert" } }
|
||||
class ConvertToVoid extends UnaryOpcode, TConvertToVoid { override final string toString() { result = "ConvertToVoid" } }
|
||||
class ConvertToBase extends UnaryOpcode, TConvertToBase { override final string toString() { result = "ConvertToBase" } }
|
||||
class ConvertToVirtualBase extends UnaryOpcode, TConvertToVirtualBase { override final string toString() { result = "ConvertToVirtualBase" } }
|
||||
class ConvertToDerived extends UnaryOpcode, TConvertToDerived { override final string toString() { result = "ConvertToDerived" } }
|
||||
|
||||
@@ -89,7 +89,8 @@ private predicate ignoreElement(Element element) {
|
||||
* a value.
|
||||
*/
|
||||
private predicate isNativeCondition(Expr expr) {
|
||||
expr instanceof BinaryLogicalOperation
|
||||
expr instanceof BinaryLogicalOperation and
|
||||
not expr.isConstant()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,7 +102,8 @@ private predicate isFlexibleCondition(Expr expr) {
|
||||
expr instanceof ParenthesisExpr or
|
||||
expr instanceof NotExpr
|
||||
) and
|
||||
usedAsCondition(expr)
|
||||
usedAsCondition(expr) and
|
||||
not expr.isConstant()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1126,6 +1126,19 @@ abstract class TranslatedSingleInstructionConversion extends TranslatedConversio
|
||||
abstract Opcode getOpcode();
|
||||
}
|
||||
|
||||
/**
|
||||
* The translation of an explicit cast to `void`.
|
||||
*/
|
||||
class TranslatedVoidConversion extends TranslatedSingleInstructionConversion {
|
||||
TranslatedVoidConversion() {
|
||||
conv instanceof VoidConversion
|
||||
}
|
||||
|
||||
override Opcode getOpcode() {
|
||||
result instanceof Opcode::ConvertToVoid
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the translation of a conversion expression that generates a
|
||||
* `Convert` instruction.
|
||||
|
||||
@@ -67,6 +67,31 @@ module InstructionSanity {
|
||||
not tag instanceof UnmodeledUseOperand
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `Phi` instruction `instr` has fewer than two operands.
|
||||
*/
|
||||
query predicate missingPhiOperand(PhiInstruction instr, int predIndex, Location predLoc) {
|
||||
exists(IRBlock pred |
|
||||
pred = instr.getBlock().getAPredecessor() and
|
||||
predLoc = pred.getLocation() and
|
||||
predIndex = pred.getDisplayIndex() and
|
||||
not exists(PhiOperand operand |
|
||||
exists(instr.getOperand(operand)) and
|
||||
operand.getPredecessorBlock() = pred
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an instruction, other than `ExitFunction`, has no successors.
|
||||
*/
|
||||
query predicate instructionWithoutSuccessor(Instruction instr) {
|
||||
not exists(instr.getASuccessor()) and
|
||||
not instr instanceof ExitFunctionInstruction and
|
||||
// Phi instructions aren't linked into the instruction-level flow graph.
|
||||
not instr instanceof PhiInstruction
|
||||
}
|
||||
|
||||
query predicate operandAcrossFunctions(
|
||||
Instruction op, Instruction operand, OperandTag tag
|
||||
) {
|
||||
|
||||
@@ -67,6 +67,31 @@ module InstructionSanity {
|
||||
not tag instanceof UnmodeledUseOperand
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `Phi` instruction `instr` has fewer than two operands.
|
||||
*/
|
||||
query predicate missingPhiOperands(PhiInstruction instr, int predIndex, Location predLoc) {
|
||||
exists(IRBlock pred |
|
||||
pred = instr.getBlock().getAPredecessor() and
|
||||
predLoc = pred.getLocation() and
|
||||
predIndex = pred.getDisplayIndex() and
|
||||
not exists(PhiOperand operand |
|
||||
exists(instr.getOperand(operand)) and
|
||||
operand.getPredecessorBlock() = pred
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an instruction, other than `ExitFunction`, has no successors.
|
||||
*/
|
||||
query predicate instructionWithoutSuccessor(Instruction instr) {
|
||||
not exists(instr.getASuccessor()) and
|
||||
not instr instanceof ExitFunctionInstruction and
|
||||
// Phi instructions aren't linked into the instruction-level flow graph.
|
||||
not instr instanceof PhiInstruction
|
||||
}
|
||||
|
||||
query predicate operandAcrossFunctions(
|
||||
Instruction op, Instruction operand, OperandTag tag
|
||||
) {
|
||||
|
||||
@@ -235,3 +235,16 @@ void FuncPtrConversions(int(*pfn)(int), void* p) {
|
||||
p = (void*)pfn;
|
||||
pfn = (int(*)(int))p;
|
||||
}
|
||||
|
||||
int Func();
|
||||
|
||||
void ConversionsToVoid() {
|
||||
int x;
|
||||
(void)x;
|
||||
static_cast<void>(x);
|
||||
(void)Func();
|
||||
static_cast<void>(Func());
|
||||
(void)1;
|
||||
static_cast<void>(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -143,3 +143,9 @@
|
||||
| conversions.cpp:231:28:231:63 | dynamic_cast<PolymorphicDerived>... | dynamic_cast | lval | PolymorphicDerived | PolymorphicBase |
|
||||
| conversions.cpp:235:7:235:16 | (void *)... | pointer conversion | prval | void * | ..(*)(..) |
|
||||
| conversions.cpp:236:9:236:22 | (..(*)(..))... | pointer conversion | prval | ..(*)(..) | void * |
|
||||
| conversions.cpp:243:3:243:9 | (void)... | conversion to void | prval | void | int |
|
||||
| conversions.cpp:244:3:244:22 | static_cast<void>... | conversion to void | prval | void | int |
|
||||
| conversions.cpp:245:3:245:14 | (void)... | conversion to void | prval | void | int |
|
||||
| conversions.cpp:246:3:246:27 | static_cast<void>... | conversion to void | prval | void | int |
|
||||
| conversions.cpp:247:3:247:9 | (void)... | conversion to void | prval | void | int |
|
||||
| conversions.cpp:248:3:248:22 | static_cast<void>... | conversion to void | prval | void | int |
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
missingOperand
|
||||
unexpectedOperand
|
||||
duplicateOperand
|
||||
missingPhiOperand
|
||||
instructionWithoutSuccessor
|
||||
operandAcrossFunctions
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
missingOperand
|
||||
unexpectedOperand
|
||||
duplicateOperand
|
||||
missingPhiOperands
|
||||
instructionWithoutSuccessor
|
||||
operandAcrossFunctions
|
||||
|
||||
@@ -5900,3 +5900,60 @@ ir.cpp:
|
||||
# 897| Type = __va_list_tag[1]
|
||||
# 897| ValueCategory = lvalue
|
||||
# 898| 8: return ...
|
||||
# 900| CastToVoid(int) -> void
|
||||
# 900| params:
|
||||
# 900| 0: x
|
||||
# 900| Type = int
|
||||
# 900| body: { ... }
|
||||
# 901| 0: ExprStmt
|
||||
# 901| 0: (void)...
|
||||
# 901| Conversion = conversion to void
|
||||
# 901| Type = void
|
||||
# 901| ValueCategory = prvalue
|
||||
# 901| expr: x
|
||||
# 901| Type = int
|
||||
# 901| ValueCategory = lvalue
|
||||
# 902| 1: return ...
|
||||
# 904| ConstantConditions(int) -> void
|
||||
# 904| params:
|
||||
# 904| 0: x
|
||||
# 904| Type = int
|
||||
# 904| body: { ... }
|
||||
# 905| 0: declaration
|
||||
# 905| 0: definition of a
|
||||
# 905| Type = bool
|
||||
# 905| init: initializer for a
|
||||
# 905| expr: ... && ...
|
||||
# 905| Type = bool
|
||||
# 905| Value = 1
|
||||
# 905| ValueCategory = prvalue
|
||||
# 905| 0: 1
|
||||
# 905| Type = bool
|
||||
# 905| Value = 1
|
||||
# 905| ValueCategory = prvalue
|
||||
# 905| 1: 1
|
||||
# 905| Type = bool
|
||||
# 905| Value = 1
|
||||
# 905| ValueCategory = prvalue
|
||||
# 906| 1: declaration
|
||||
# 906| 0: definition of b
|
||||
# 906| Type = int
|
||||
# 906| init: initializer for b
|
||||
# 906| expr: ... ? ... : ...
|
||||
# 906| Type = int
|
||||
# 906| ValueCategory = prvalue
|
||||
# 906| 0: (...)
|
||||
# 906| Type = bool
|
||||
# 906| Value = 1
|
||||
# 906| ValueCategory = prvalue
|
||||
# 906| expr: 1
|
||||
# 906| Type = bool
|
||||
# 906| Value = 1
|
||||
# 906| ValueCategory = prvalue
|
||||
# 906| 1: x
|
||||
# 906| Type = int
|
||||
# 906| ValueCategory = prvalue(load)
|
||||
# 906| 2: x
|
||||
# 906| Type = int
|
||||
# 906| ValueCategory = prvalue(load)
|
||||
# 907| 2: return ...
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
missingOperand
|
||||
unexpectedOperand
|
||||
duplicateOperand
|
||||
missingPhiOperands
|
||||
instructionWithoutSuccessor
|
||||
operandAcrossFunctions
|
||||
|
||||
@@ -3846,3 +3846,57 @@ ir.cpp:
|
||||
# 888| v0_40(void) = ReturnVoid :
|
||||
# 888| v0_41(void) = UnmodeledUse : mu*
|
||||
# 888| v0_42(void) = ExitFunction :
|
||||
|
||||
# 900| CastToVoid(int) -> void
|
||||
# 900| Block 0
|
||||
# 900| v0_0(void) = EnterFunction :
|
||||
# 900| mu0_1(unknown) = UnmodeledDefinition :
|
||||
# 900| r0_2(int) = InitializeParameter[x] :
|
||||
# 900| r0_3(glval<int>) = VariableAddress[x] :
|
||||
# 900| mu0_4(int) = Store : r0_3, r0_2
|
||||
# 901| r0_5(glval<int>) = VariableAddress[x] :
|
||||
# 901| v0_6(void) = ConvertToVoid : r0_5
|
||||
# 902| v0_7(void) = NoOp :
|
||||
# 900| v0_8(void) = ReturnVoid :
|
||||
# 900| v0_9(void) = UnmodeledUse : mu*
|
||||
# 900| v0_10(void) = ExitFunction :
|
||||
|
||||
# 904| ConstantConditions(int) -> void
|
||||
# 904| Block 0
|
||||
# 904| v0_0(void) = EnterFunction :
|
||||
# 904| mu0_1(unknown) = UnmodeledDefinition :
|
||||
# 904| r0_2(int) = InitializeParameter[x] :
|
||||
# 904| r0_3(glval<int>) = VariableAddress[x] :
|
||||
# 904| m0_4(int) = Store : r0_3, r0_2
|
||||
# 905| r0_5(glval<bool>) = VariableAddress[a] :
|
||||
# 905| r0_6(bool) = Constant[1] :
|
||||
# 905| m0_7(bool) = Store : r0_5, r0_6
|
||||
# 906| r0_8(glval<int>) = VariableAddress[b] :
|
||||
# 906| r0_9(bool) = Constant[1] :
|
||||
# 906| v0_10(void) = ConditionalBranch : r0_9
|
||||
#-----| False -> Block 3
|
||||
#-----| True -> Block 2
|
||||
|
||||
# 906| Block 1
|
||||
# 906| m1_0(int) = Phi : from 2:m2_3, from 3:m3_3
|
||||
# 906| r1_1(glval<int>) = VariableAddress[#temp906:11] :
|
||||
# 906| r1_2(int) = Load : r1_1, m1_0
|
||||
# 906| m1_3(int) = Store : r0_8, r1_2
|
||||
# 907| v1_4(void) = NoOp :
|
||||
# 904| v1_5(void) = ReturnVoid :
|
||||
# 904| v1_6(void) = UnmodeledUse : mu*
|
||||
# 904| v1_7(void) = ExitFunction :
|
||||
|
||||
# 906| Block 2
|
||||
# 906| r2_0(glval<int>) = VariableAddress[x] :
|
||||
# 906| r2_1(int) = Load : r2_0, m0_4
|
||||
# 906| r2_2(glval<int>) = VariableAddress[#temp906:11] :
|
||||
# 906| m2_3(int) = Store : r2_2, r2_1
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 906| Block 3
|
||||
# 906| r3_0(glval<int>) = VariableAddress[x] :
|
||||
# 906| r3_1(int) = Load : r3_0, m0_4
|
||||
# 906| r3_2(glval<int>) = VariableAddress[#temp906:11] :
|
||||
# 906| m3_3(int) = Store : r3_2, r3_1
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
@@ -896,3 +896,12 @@ void VarArgUsage(int x, ...) {
|
||||
__builtin_va_end(args);
|
||||
__builtin_va_end(args2);
|
||||
}
|
||||
|
||||
void CastToVoid(int x) {
|
||||
(void)x;
|
||||
}
|
||||
|
||||
void ConstantConditions(int x) {
|
||||
bool a = true && true;
|
||||
int b = (true) ? x : x;
|
||||
}
|
||||
|
||||
@@ -3826,3 +3826,56 @@ ir.cpp:
|
||||
# 888| v0_40(void) = ReturnVoid :
|
||||
# 888| v0_41(void) = UnmodeledUse : mu*
|
||||
# 888| v0_42(void) = ExitFunction :
|
||||
|
||||
# 900| CastToVoid(int) -> void
|
||||
# 900| Block 0
|
||||
# 900| v0_0(void) = EnterFunction :
|
||||
# 900| mu0_1(unknown) = UnmodeledDefinition :
|
||||
# 900| r0_2(int) = InitializeParameter[x] :
|
||||
# 900| r0_3(glval<int>) = VariableAddress[x] :
|
||||
# 900| mu0_4(int) = Store : r0_3, r0_2
|
||||
# 901| r0_5(glval<int>) = VariableAddress[x] :
|
||||
# 901| v0_6(void) = ConvertToVoid : r0_5
|
||||
# 902| v0_7(void) = NoOp :
|
||||
# 900| v0_8(void) = ReturnVoid :
|
||||
# 900| v0_9(void) = UnmodeledUse : mu*
|
||||
# 900| v0_10(void) = ExitFunction :
|
||||
|
||||
# 904| ConstantConditions(int) -> void
|
||||
# 904| Block 0
|
||||
# 904| v0_0(void) = EnterFunction :
|
||||
# 904| mu0_1(unknown) = UnmodeledDefinition :
|
||||
# 904| r0_2(int) = InitializeParameter[x] :
|
||||
# 904| r0_3(glval<int>) = VariableAddress[x] :
|
||||
# 904| mu0_4(int) = Store : r0_3, r0_2
|
||||
# 905| r0_5(glval<bool>) = VariableAddress[a] :
|
||||
# 905| r0_6(bool) = Constant[1] :
|
||||
# 905| mu0_7(bool) = Store : r0_5, r0_6
|
||||
# 906| r0_8(glval<int>) = VariableAddress[b] :
|
||||
# 906| r0_9(bool) = Constant[1] :
|
||||
# 906| v0_10(void) = ConditionalBranch : r0_9
|
||||
#-----| False -> Block 3
|
||||
#-----| True -> Block 2
|
||||
|
||||
# 906| Block 1
|
||||
# 906| r1_0(glval<int>) = VariableAddress[#temp906:11] :
|
||||
# 906| r1_1(int) = Load : r1_0, mu0_1
|
||||
# 906| mu1_2(int) = Store : r0_8, r1_1
|
||||
# 907| v1_3(void) = NoOp :
|
||||
# 904| v1_4(void) = ReturnVoid :
|
||||
# 904| v1_5(void) = UnmodeledUse : mu*
|
||||
# 904| v1_6(void) = ExitFunction :
|
||||
|
||||
# 906| Block 2
|
||||
# 906| r2_0(glval<int>) = VariableAddress[x] :
|
||||
# 906| r2_1(int) = Load : r2_0, mu0_1
|
||||
# 906| r2_2(glval<int>) = VariableAddress[#temp906:11] :
|
||||
# 906| mu2_3(int) = Store : r2_2, r2_1
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 906| Block 3
|
||||
# 906| r3_0(glval<int>) = VariableAddress[x] :
|
||||
# 906| r3_1(int) = Load : r3_0, mu0_1
|
||||
# 906| r3_2(glval<int>) = VariableAddress[#temp906:11] :
|
||||
# 906| mu3_3(int) = Store : r3_2, r3_1
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
@@ -12,12 +12,14 @@
|
||||
| IR: CallMin | 1 |
|
||||
| IR: CallNestedTemplateFunc | 1 |
|
||||
| IR: CallViaFuncPtr | 1 |
|
||||
| IR: CastToVoid | 1 |
|
||||
| IR: Comma | 1 |
|
||||
| IR: CompoundAssignment | 1 |
|
||||
| IR: ConditionValues | 13 |
|
||||
| IR: Conditional | 4 |
|
||||
| IR: Conditional_LValue | 4 |
|
||||
| IR: Conditional_Void | 4 |
|
||||
| IR: ConstantConditions | 4 |
|
||||
| IR: Constants | 1 |
|
||||
| IR: Continue | 6 |
|
||||
| IR: DeclareObject | 1 |
|
||||
|
||||
@@ -3846,3 +3846,57 @@ ir.cpp:
|
||||
# 888| v0_40(void) = ReturnVoid :
|
||||
# 888| v0_41(void) = UnmodeledUse : mu*
|
||||
# 888| v0_42(void) = ExitFunction :
|
||||
|
||||
# 900| CastToVoid(int) -> void
|
||||
# 900| Block 0
|
||||
# 900| v0_0(void) = EnterFunction :
|
||||
# 900| mu0_1(unknown) = UnmodeledDefinition :
|
||||
# 900| r0_2(int) = InitializeParameter[x] :
|
||||
# 900| r0_3(glval<int>) = VariableAddress[x] :
|
||||
# 900| mu0_4(int) = Store : r0_3, r0_2
|
||||
# 901| r0_5(glval<int>) = VariableAddress[x] :
|
||||
# 901| v0_6(void) = ConvertToVoid : r0_5
|
||||
# 902| v0_7(void) = NoOp :
|
||||
# 900| v0_8(void) = ReturnVoid :
|
||||
# 900| v0_9(void) = UnmodeledUse : mu*
|
||||
# 900| v0_10(void) = ExitFunction :
|
||||
|
||||
# 904| ConstantConditions(int) -> void
|
||||
# 904| Block 0
|
||||
# 904| v0_0(void) = EnterFunction :
|
||||
# 904| mu0_1(unknown) = UnmodeledDefinition :
|
||||
# 904| r0_2(int) = InitializeParameter[x] :
|
||||
# 904| r0_3(glval<int>) = VariableAddress[x] :
|
||||
# 904| m0_4(int) = Store : r0_3, r0_2
|
||||
# 905| r0_5(glval<bool>) = VariableAddress[a] :
|
||||
# 905| r0_6(bool) = Constant[1] :
|
||||
# 905| m0_7(bool) = Store : r0_5, r0_6
|
||||
# 906| r0_8(glval<int>) = VariableAddress[b] :
|
||||
# 906| r0_9(bool) = Constant[1] :
|
||||
# 906| v0_10(void) = ConditionalBranch : r0_9
|
||||
#-----| False -> Block 3
|
||||
#-----| True -> Block 2
|
||||
|
||||
# 906| Block 1
|
||||
# 906| m1_0(int) = Phi : from 2:m2_3, from 3:m3_3
|
||||
# 906| r1_1(glval<int>) = VariableAddress[#temp906:11] :
|
||||
# 906| r1_2(int) = Load : r1_1, m1_0
|
||||
# 906| m1_3(int) = Store : r0_8, r1_2
|
||||
# 907| v1_4(void) = NoOp :
|
||||
# 904| v1_5(void) = ReturnVoid :
|
||||
# 904| v1_6(void) = UnmodeledUse : mu*
|
||||
# 904| v1_7(void) = ExitFunction :
|
||||
|
||||
# 906| Block 2
|
||||
# 906| r2_0(glval<int>) = VariableAddress[x] :
|
||||
# 906| r2_1(int) = Load : r2_0, m0_4
|
||||
# 906| r2_2(glval<int>) = VariableAddress[#temp906:11] :
|
||||
# 906| m2_3(int) = Store : r2_2, r2_1
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 906| Block 3
|
||||
# 906| r3_0(glval<int>) = VariableAddress[x] :
|
||||
# 906| r3_1(int) = Load : r3_0, m0_4
|
||||
# 906| r3_2(glval<int>) = VariableAddress[#temp906:11] :
|
||||
# 906| m3_3(int) = Store : r3_2, r3_1
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
Reference in New Issue
Block a user