C++: IR translation for binary conditional operator

IR generation was not handling the special two-operand flavor of the `?:` operator that GCC supports as an extension. The extractor doesn't quite give us enough information to do this correctly (see github/codeql-c-extractor-team#67), but we can get pretty close.

About half of the code could be shared between the two-operand and three-operand flavors. The main differences for the two-operand flavor are:
1. The "then" operand isn't a child of the `ConditionalExpr`. Instead, we just reuse the original value of the "condition" operand, skipping any implicit cast to `bool` (see comment for rationale).
2. For the three-operand flavor, we generate the condition as control flow rather than the computation of a `bool` value, to avoid creating unnecessarily complicated branching. For the two-operand version, we just compute the value, since we have to reuse that value in the "then" branch anyway.

I've added IR tests for these new cases. I've also updated the expectations for `SignAnalysis.ql` based on the fix. @rdmarsh2, can you please double-check that these diffs look correct? I believe they do, but you're the range/sign analysis expert.
This commit is contained in:
Dave Bartolomeo
2020-04-21 02:05:21 -04:00
parent 875daae84b
commit 1428811f75
5 changed files with 656 additions and 37 deletions

View File

@@ -200,7 +200,11 @@ private predicate usedAsCondition(Expr expr) {
or
exists(IfStmt ifStmt | ifStmt.getCondition().getFullyConverted() = expr)
or
exists(ConditionalExpr condExpr | condExpr.getCondition().getFullyConverted() = expr)
exists(ConditionalExpr condExpr |
// The two-operand form of `ConditionalExpr` treats its condition as a value, since it needs to
// be reused as a value if the condition is true.
condExpr.getCondition().getFullyConverted() = expr and not condExpr.isTwoOperand()
)
or
exists(NotExpr notExpr |
notExpr.getOperand().getFullyConverted() = expr and

View File

@@ -1758,19 +1758,14 @@ class TranslatedDestructorFieldDestruction extends TranslatedNonConstantExpr, St
private TranslatedExpr getDestructorCall() { result = getTranslatedExpr(expr.getExpr()) }
}
class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionContext {
/**
* The IR translation of the `?:` operator. This class has the portions of the implementation that
* are shared between the standard three-operand form (`a ? b : c`) and the GCC-extension
* two-operand form (`a ?: c`).
*/
abstract class TranslatedConditionalExpr extends TranslatedNonConstantExpr {
override ConditionalExpr expr;
final override TranslatedElement getChild(int id) {
id = 0 and result = getCondition()
or
id = 1 and result = getThen()
or
id = 2 and result = getElse()
}
override Instruction getFirstInstruction() { result = getCondition().getFirstInstruction() }
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
not resultIsVoid() and
(
@@ -1866,13 +1861,13 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
)
}
override predicate hasTempVariable(TempVariableTag tag, CppType type) {
final override predicate hasTempVariable(TempVariableTag tag, CppType type) {
not resultIsVoid() and
tag = ConditionValueTempVar() and
type = getResultType()
}
override IRVariable getInstructionVariable(InstructionTag tag) {
final override IRVariable getInstructionVariable(InstructionTag tag) {
not resultIsVoid() and
(
tag = ConditionValueTrueTempAddressTag() or
@@ -1882,25 +1877,75 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
result = getTempVariable(ConditionValueTempVar())
}
override Instruction getResult() {
final override Instruction getResult() {
not resultIsVoid() and
result = getInstruction(ConditionValueResultLoadTag())
}
override Instruction getChildSuccessor(TranslatedElement child) {
child = getElse() and
if elseIsVoid()
then result = getParent().getChildSuccessor(this)
else result = getInstruction(ConditionValueFalseTempAddressTag())
}
/**
* Gets the `TranslatedExpr` for the "then" result. Note that nothing in the base implementation
* of this class assumes that `getThen()` is disjoint from `getCondition()`.
*/
abstract TranslatedExpr getThen();
/**
* Gets the `TranslatedExpr` for the "else" result.
*/
final TranslatedExpr getElse() { result = getTranslatedExpr(expr.getElse().getFullyConverted()) }
final predicate thenIsVoid() {
getThen().getResultType().getIRType() instanceof IRVoidType
or
// A `ThrowExpr.getType()` incorrectly returns the type of exception being
// thrown, rather than `void`. Handle that case here.
expr.getThen() instanceof ThrowExpr
}
private predicate elseIsVoid() {
getElse().getResultType().getIRType() instanceof IRVoidType
or
// A `ThrowExpr.getType()` incorrectly returns the type of exception being
// thrown, rather than `void`. Handle that case here.
expr.getElse() instanceof ThrowExpr
}
private predicate resultIsVoid() { getResultType().getIRType() instanceof IRVoidType }
}
/**
* The IR translation of the ternary conditional operator (`a ? b : c`).
* For this version, we expand the condition as a `TranslatedCondition`, rather than a
* `TranslatedExpr`, to simplify the control flow in the presence of short-ciruit logical operators.
*/
class TranslatedTernaryConditionalExpr extends TranslatedConditionalExpr, ConditionContext {
TranslatedTernaryConditionalExpr() { not expr.isTwoOperand() }
final override TranslatedElement getChild(int id) {
id = 0 and result = getCondition()
or
id = 1 and result = getThen()
or
id = 2 and result = getElse()
}
override Instruction getFirstInstruction() { result = getCondition().getFirstInstruction() }
override Instruction getChildSuccessor(TranslatedElement child) {
result = TranslatedConditionalExpr.super.getChildSuccessor(child)
or
(
child = getThen() and
if thenIsVoid()
then result = getParent().getChildSuccessor(this)
else result = getInstruction(ConditionValueTrueTempAddressTag())
)
or
(
child = getElse() and
if elseIsVoid()
then result = getParent().getChildSuccessor(this)
else result = getInstruction(ConditionValueFalseTempAddressTag())
)
}
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
@@ -1917,31 +1962,81 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
result = getTranslatedCondition(expr.getCondition().getFullyConverted())
}
private TranslatedExpr getThen() {
final override TranslatedExpr getThen() {
result = getTranslatedExpr(expr.getThen().getFullyConverted())
}
}
private TranslatedExpr getElse() {
result = getTranslatedExpr(expr.getElse().getFullyConverted())
}
/**
* The IR translation of a two-operand conditional operator (`a ?: b`). This is a GCC language
* extension.
* This version of the conditional expression returns its first operand (the condition) if that
* condition is non-zero. Since we'll be reusing the value of the condition, we'll compute that
* value directly before branching, even if that value was a short-circuit logical expression.
*/
class TranslatedBinaryConditionalExpr extends TranslatedConditionalExpr {
TranslatedBinaryConditionalExpr() { expr.isTwoOperand() }
private predicate thenIsVoid() {
getThen().getResultType().getIRType() instanceof IRVoidType
final override TranslatedElement getChild(int id) {
// We only truly have two children, because our "condition" and "then" are the same as far as
// the extractor is concerned.
id = 0 and result = getCondition()
or
// A `ThrowExpr.getType()` incorrectly returns the type of exception being
// thrown, rather than `void`. Handle that case here.
expr.getThen() instanceof ThrowExpr
id = 1 and result = getElse()
}
private predicate elseIsVoid() {
getElse().getResultType().getIRType() instanceof IRVoidType
override Instruction getFirstInstruction() { result = getCondition().getFirstInstruction() }
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
super.hasInstruction(opcode, tag, resultType)
or
// A `ThrowExpr.getType()` incorrectly returns the type of exception being
// thrown, rather than `void`. Handle that case here.
expr.getElse() instanceof ThrowExpr
// For the binary variant, we create our own conditional branch.
tag = ValueConditionConditionalBranchTag() and
opcode instanceof Opcode::ConditionalBranch and
resultType = getVoidType()
}
private predicate resultIsVoid() { getResultType().getIRType() instanceof IRVoidType }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
result = super.getInstructionSuccessor(tag, kind)
or
tag = ValueConditionConditionalBranchTag() and
(
kind instanceof TrueEdge and
result = getInstruction(ConditionValueTrueTempAddressTag())
or
kind instanceof FalseEdge and
result = getElse().getFirstInstruction()
)
}
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
result = super.getInstructionOperand(tag, operandTag)
or
tag = ValueConditionConditionalBranchTag() and
operandTag instanceof ConditionOperandTag and
result = getCondition().getResult()
}
override Instruction getChildSuccessor(TranslatedElement child) {
result = super.getChildSuccessor(child)
or
child = getCondition() and result = getInstruction(ValueConditionConditionalBranchTag())
}
private TranslatedExpr getCondition() {
result = getTranslatedExpr(expr.getCondition().getFullyConverted())
}
final override TranslatedExpr getThen() {
// The extractor returns the exact same expression for `ConditionalExpr::getCondition()` and
// `ConditionalExpr::getThen()`, even though the condition may have been converted to `bool`,
// and the "then" may have been converted to the result type. We'll strip the top-level implicit
// conversions from this, to skip any conversion to `bool`. We don't have enough information to
// know how to convert the result to the destination type, especially in the class pointer case,
// so we'll still sometimes wind up with one operand as the wrong type. This is better than
// always converting the "then" operand to `bool`, which is almost always the wrong type.
result = getTranslatedExpr(expr.getThen().getExplicitlyConverted())
}
}
/**

View File

@@ -10265,6 +10265,224 @@ ir.cpp:
# 1296| 1: [VariableAccess] y
# 1296| Type = [IntType] int
# 1296| ValueCategory = prvalue(load)
# 1299| [TopLevelFunction] void gccBinaryConditional(bool, int, long)
# 1299| params:
# 1299| 0: [Parameter] b
# 1299| Type = [BoolType] bool
# 1299| 1: [Parameter] x
# 1299| Type = [IntType] int
# 1299| 2: [Parameter] y
# 1299| Type = [LongType] long
# 1299| body: [Block] { ... }
# 1300| 0: [DeclStmt] declaration
# 1300| 0: [VariableDeclarationEntry] definition of z
# 1300| Type = [IntType] int
# 1300| init: [Initializer] initializer for z
# 1300| expr: [VariableAccess] x
# 1300| Type = [IntType] int
# 1300| ValueCategory = prvalue(load)
# 1301| 1: [ExprStmt] ExprStmt
# 1301| 0: [AssignExpr] ... = ...
# 1301| Type = [IntType] int
# 1301| ValueCategory = lvalue
# 1301| 0: [VariableAccess] z
# 1301| Type = [IntType] int
# 1301| ValueCategory = lvalue
# 1301| 1: [ConditionalExpr] ... ? ... : ...
# 1301| Type = [IntType] int
# 1301| ValueCategory = prvalue
# 1301| 0: [VariableAccess] b
# 1301| Type = [BoolType] bool
# 1301| ValueCategory = prvalue(load)
# 1301| 1: [VariableAccess] x
# 1301| Type = [IntType] int
# 1301| ValueCategory = prvalue(load)
# 1302| 2: [ExprStmt] ExprStmt
# 1302| 0: [AssignExpr] ... = ...
# 1302| Type = [IntType] int
# 1302| ValueCategory = lvalue
# 1302| 0: [VariableAccess] z
# 1302| Type = [IntType] int
# 1302| ValueCategory = lvalue
# 1302| 1: [CStyleCast] (int)...
# 1302| Conversion = [IntegralConversion] integral conversion
# 1302| Type = [IntType] int
# 1302| ValueCategory = prvalue
# 1302| expr: [ConditionalExpr] ... ? ... : ...
# 1302| Type = [LongType] long
# 1302| ValueCategory = prvalue
# 1302| 0: [VariableAccess] b
# 1302| Type = [BoolType] bool
# 1302| ValueCategory = prvalue(load)
# 1302| 1: [VariableAccess] y
# 1302| Type = [LongType] long
# 1302| ValueCategory = prvalue(load)
# 1303| 3: [ExprStmt] ExprStmt
# 1303| 0: [AssignExpr] ... = ...
# 1303| Type = [IntType] int
# 1303| ValueCategory = lvalue
# 1303| 0: [VariableAccess] z
# 1303| Type = [IntType] int
# 1303| ValueCategory = lvalue
# 1303| 1: [ConditionalExpr] ... ? ... : ...
# 1303| Type = [IntType] int
# 1303| ValueCategory = prvalue
# 1303| 0: [CStyleCast] (bool)...
# 1303| Conversion = [BoolConversion] conversion to bool
# 1303| Type = [BoolType] bool
# 1303| ValueCategory = prvalue
# 1303| expr: [VariableAccess] x
# 1303| Type = [IntType] int
# 1303| ValueCategory = prvalue(load)
# 1303| 1: [VariableAccess] x
# 1303| Type = [IntType] int
# 1303| ValueCategory = prvalue(load)
# 1304| 4: [ExprStmt] ExprStmt
# 1304| 0: [AssignExpr] ... = ...
# 1304| Type = [IntType] int
# 1304| ValueCategory = lvalue
# 1304| 0: [VariableAccess] z
# 1304| Type = [IntType] int
# 1304| ValueCategory = lvalue
# 1304| 1: [CStyleCast] (int)...
# 1304| Conversion = [IntegralConversion] integral conversion
# 1304| Type = [IntType] int
# 1304| ValueCategory = prvalue
# 1304| expr: [ConditionalExpr] ... ? ... : ...
# 1304| Type = [LongType] long
# 1304| ValueCategory = prvalue
# 1304| 0: [CStyleCast] (bool)...
# 1304| Conversion = [BoolConversion] conversion to bool
# 1304| Type = [BoolType] bool
# 1304| ValueCategory = prvalue
# 1304| expr: [VariableAccess] x
# 1304| Type = [IntType] int
# 1304| ValueCategory = prvalue(load)
# 1304| 1: [VariableAccess] y
# 1304| Type = [LongType] long
# 1304| ValueCategory = prvalue(load)
# 1305| 5: [ExprStmt] ExprStmt
# 1305| 0: [AssignExpr] ... = ...
# 1305| Type = [IntType] int
# 1305| ValueCategory = lvalue
# 1305| 0: [VariableAccess] z
# 1305| Type = [IntType] int
# 1305| ValueCategory = lvalue
# 1305| 1: [CStyleCast] (int)...
# 1305| Conversion = [IntegralConversion] integral conversion
# 1305| Type = [IntType] int
# 1305| ValueCategory = prvalue
# 1305| expr: [ConditionalExpr] ... ? ... : ...
# 1305| Type = [LongType] long
# 1305| ValueCategory = prvalue
# 1305| 0: [CStyleCast] (bool)...
# 1305| Conversion = [BoolConversion] conversion to bool
# 1305| Type = [BoolType] bool
# 1305| ValueCategory = prvalue
# 1305| expr: [VariableAccess] y
# 1305| Type = [LongType] long
# 1305| ValueCategory = prvalue(load)
# 1305| 1: [CStyleCast] (long)...
# 1305| Conversion = [IntegralConversion] integral conversion
# 1305| Type = [LongType] long
# 1305| ValueCategory = prvalue
# 1305| expr: [VariableAccess] x
# 1305| Type = [IntType] int
# 1305| ValueCategory = prvalue(load)
# 1306| 6: [ExprStmt] ExprStmt
# 1306| 0: [AssignExpr] ... = ...
# 1306| Type = [IntType] int
# 1306| ValueCategory = lvalue
# 1306| 0: [VariableAccess] z
# 1306| Type = [IntType] int
# 1306| ValueCategory = lvalue
# 1306| 1: [CStyleCast] (int)...
# 1306| Conversion = [IntegralConversion] integral conversion
# 1306| Type = [IntType] int
# 1306| ValueCategory = prvalue
# 1306| expr: [ConditionalExpr] ... ? ... : ...
# 1306| Type = [LongType] long
# 1306| ValueCategory = prvalue
# 1306| 0: [CStyleCast] (bool)...
# 1306| Conversion = [BoolConversion] conversion to bool
# 1306| Type = [BoolType] bool
# 1306| ValueCategory = prvalue
# 1306| expr: [VariableAccess] y
# 1306| Type = [LongType] long
# 1306| ValueCategory = prvalue(load)
# 1306| 1: [VariableAccess] y
# 1306| Type = [LongType] long
# 1306| ValueCategory = prvalue(load)
# 1308| 7: [ExprStmt] ExprStmt
# 1308| 0: [AssignExpr] ... = ...
# 1308| Type = [IntType] int
# 1308| ValueCategory = lvalue
# 1308| 0: [VariableAccess] z
# 1308| Type = [IntType] int
# 1308| ValueCategory = lvalue
# 1308| 1: [ConditionalExpr] ... ? ... : ...
# 1308| Type = [IntType] int
# 1308| ValueCategory = prvalue
# 1308| 0: [ParenthesisExpr] (...)
# 1308| Type = [BoolType] bool
# 1308| ValueCategory = prvalue
# 1308| expr: [LogicalOrExpr] ... || ...
# 1308| Type = [BoolType] bool
# 1308| ValueCategory = prvalue
# 1308| 0: [LogicalAndExpr] ... && ...
# 1308| Type = [BoolType] bool
# 1308| ValueCategory = prvalue
# 1308| 0: [CStyleCast] (bool)...
# 1308| Conversion = [BoolConversion] conversion to bool
# 1308| Type = [BoolType] bool
# 1308| ValueCategory = prvalue
# 1308| expr: [VariableAccess] x
# 1308| Type = [IntType] int
# 1308| ValueCategory = prvalue(load)
# 1308| 1: [VariableAccess] b
# 1308| Type = [BoolType] bool
# 1308| ValueCategory = prvalue(load)
# 1308| 1: [CStyleCast] (bool)...
# 1308| Conversion = [BoolConversion] conversion to bool
# 1308| Type = [BoolType] bool
# 1308| ValueCategory = prvalue
# 1308| expr: [VariableAccess] y
# 1308| Type = [LongType] long
# 1308| ValueCategory = prvalue(load)
# 1308| 1: [VariableAccess] x
# 1308| Type = [IntType] int
# 1308| ValueCategory = prvalue(load)
# 1309| 8: [ReturnStmt] return ...
# 1311| [TopLevelFunction] bool predicateA()
# 1311| params:
# 1312| [TopLevelFunction] bool predicateB()
# 1312| params:
# 1314| [TopLevelFunction] int shortCircuitConditional(int, int)
# 1314| params:
# 1314| 0: [Parameter] x
# 1314| Type = [IntType] int
# 1314| 1: [Parameter] y
# 1314| Type = [IntType] int
# 1314| body: [Block] { ... }
# 1315| 0: [ReturnStmt] return ...
# 1315| 0: [ConditionalExpr] ... ? ... : ...
# 1315| Type = [IntType] int
# 1315| ValueCategory = prvalue
# 1315| 0: [LogicalAndExpr] ... && ...
# 1315| Type = [BoolType] bool
# 1315| ValueCategory = prvalue
# 1315| 0: [FunctionCall] call to predicateA
# 1315| Type = [BoolType] bool
# 1315| ValueCategory = prvalue
# 1315| 1: [FunctionCall] call to predicateB
# 1315| Type = [BoolType] bool
# 1315| ValueCategory = prvalue
# 1315| 1: [VariableAccess] x
# 1315| Type = [IntType] int
# 1315| ValueCategory = prvalue(load)
# 1315| 2: [VariableAccess] y
# 1315| Type = [IntType] int
# 1315| ValueCategory = prvalue(load)
perf-regression.cpp:
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
# 4| params:

View File

@@ -1296,4 +1296,23 @@ void returnVoid(int x, int y) {
return IntegerOps(x, y);
}
void gccBinaryConditional(bool b, int x, long y) {
int z = x;
z = b ?: x;
z = b ?: y;
z = x ?: x;
z = x ?: y;
z = y ?: x;
z = y ?: y;
z = (x && b || y) ?: x;
}
bool predicateA();
bool predicateB();
int shortCircuitConditional(int x, int y) {
return predicateA() && predicateB() ? x : y;
}
// semmle-extractor-options: -std=c++17 --clang

View File

@@ -7258,6 +7258,289 @@ ir.cpp:
# 1295| v1295_11(void) = AliasedUse : ~mu1295_4
# 1295| v1295_12(void) = ExitFunction :
# 1299| void gccBinaryConditional(bool, int, long)
# 1299| Block 0
# 1299| v1299_1(void) = EnterFunction :
# 1299| mu1299_2(unknown) = AliasedDefinition :
# 1299| mu1299_3(unknown) = InitializeNonLocal :
# 1299| mu1299_4(unknown) = UnmodeledDefinition :
# 1299| r1299_5(glval<bool>) = VariableAddress[b] :
# 1299| mu1299_6(bool) = InitializeParameter[b] : &:r1299_5
# 1299| r1299_7(glval<int>) = VariableAddress[x] :
# 1299| mu1299_8(int) = InitializeParameter[x] : &:r1299_7
# 1299| r1299_9(glval<long>) = VariableAddress[y] :
# 1299| mu1299_10(long) = InitializeParameter[y] : &:r1299_9
# 1300| r1300_1(glval<int>) = VariableAddress[z] :
# 1300| r1300_2(glval<int>) = VariableAddress[x] :
# 1300| r1300_3(int) = Load : &:r1300_2, ~mu1299_4
# 1300| mu1300_4(int) = Store : &:r1300_1, r1300_3
# 1301| r1301_1(glval<bool>) = VariableAddress[b] :
# 1301| r1301_2(bool) = Load : &:r1301_1, ~mu1299_4
# 1301| v1301_3(void) = ConditionalBranch : r1301_2
#-----| False -> Block 3
#-----| True -> Block 2
# 1301| Block 1
# 1301| r1301_4(glval<int>) = VariableAddress[#temp1301:9] :
# 1301| r1301_5(int) = Load : &:r1301_4, ~mu1299_4
# 1301| r1301_6(glval<int>) = VariableAddress[z] :
# 1301| mu1301_7(int) = Store : &:r1301_6, r1301_5
# 1302| r1302_1(glval<bool>) = VariableAddress[b] :
# 1302| r1302_2(bool) = Load : &:r1302_1, ~mu1299_4
# 1302| v1302_3(void) = ConditionalBranch : r1302_2
#-----| False -> Block 6
#-----| True -> Block 5
# 1301| Block 2
# 1301| r1301_8(glval<int>) = VariableAddress[#temp1301:9] :
# 1301| mu1301_9(int) = Store : &:r1301_8, r1301_2
#-----| Goto -> Block 1
# 1301| Block 3
# 1301| r1301_10(glval<int>) = VariableAddress[x] :
# 1301| r1301_11(int) = Load : &:r1301_10, ~mu1299_4
# 1301| r1301_12(glval<int>) = VariableAddress[#temp1301:9] :
# 1301| mu1301_13(int) = Store : &:r1301_12, r1301_11
#-----| Goto -> Block 1
# 1302| Block 4
# 1302| r1302_4(glval<long>) = VariableAddress[#temp1302:9] :
# 1302| r1302_5(long) = Load : &:r1302_4, ~mu1299_4
# 1302| r1302_6(int) = Convert : r1302_5
# 1302| r1302_7(glval<int>) = VariableAddress[z] :
# 1302| mu1302_8(int) = Store : &:r1302_7, r1302_6
# 1303| r1303_1(glval<int>) = VariableAddress[x] :
# 1303| r1303_2(int) = Load : &:r1303_1, ~mu1299_4
# 1303| r1303_3(int) = Constant[0] :
# 1303| r1303_4(bool) = CompareNE : r1303_2, r1303_3
# 1303| v1303_5(void) = ConditionalBranch : r1303_4
#-----| False -> Block 9
#-----| True -> Block 8
# 1302| Block 5
# 1302| r1302_9(glval<long>) = VariableAddress[#temp1302:9] :
# 1302| mu1302_10(long) = Store : &:r1302_9, r1302_2
#-----| Goto -> Block 4
# 1302| Block 6
# 1302| r1302_11(glval<long>) = VariableAddress[y] :
# 1302| r1302_12(long) = Load : &:r1302_11, ~mu1299_4
# 1302| r1302_13(glval<long>) = VariableAddress[#temp1302:9] :
# 1302| mu1302_14(long) = Store : &:r1302_13, r1302_12
#-----| Goto -> Block 4
# 1303| Block 7
# 1303| r1303_6(glval<int>) = VariableAddress[#temp1303:9] :
# 1303| r1303_7(int) = Load : &:r1303_6, ~mu1299_4
# 1303| r1303_8(glval<int>) = VariableAddress[z] :
# 1303| mu1303_9(int) = Store : &:r1303_8, r1303_7
# 1304| r1304_1(glval<int>) = VariableAddress[x] :
# 1304| r1304_2(int) = Load : &:r1304_1, ~mu1299_4
# 1304| r1304_3(int) = Constant[0] :
# 1304| r1304_4(bool) = CompareNE : r1304_2, r1304_3
# 1304| v1304_5(void) = ConditionalBranch : r1304_4
#-----| False -> Block 12
#-----| True -> Block 11
# 1303| Block 8
# 1303| r1303_10(glval<int>) = VariableAddress[#temp1303:9] :
# 1303| mu1303_11(int) = Store : &:r1303_10, r1303_2
#-----| Goto -> Block 7
# 1303| Block 9
# 1303| r1303_12(glval<int>) = VariableAddress[x] :
# 1303| r1303_13(int) = Load : &:r1303_12, ~mu1299_4
# 1303| r1303_14(glval<int>) = VariableAddress[#temp1303:9] :
# 1303| mu1303_15(int) = Store : &:r1303_14, r1303_13
#-----| Goto -> Block 7
# 1304| Block 10
# 1304| r1304_6(glval<long>) = VariableAddress[#temp1304:9] :
# 1304| r1304_7(long) = Load : &:r1304_6, ~mu1299_4
# 1304| r1304_8(int) = Convert : r1304_7
# 1304| r1304_9(glval<int>) = VariableAddress[z] :
# 1304| mu1304_10(int) = Store : &:r1304_9, r1304_8
# 1305| r1305_1(glval<long>) = VariableAddress[y] :
# 1305| r1305_2(long) = Load : &:r1305_1, ~mu1299_4
# 1305| r1305_3(long) = Constant[0] :
# 1305| r1305_4(bool) = CompareNE : r1305_2, r1305_3
# 1305| v1305_5(void) = ConditionalBranch : r1305_4
#-----| False -> Block 15
#-----| True -> Block 14
# 1304| Block 11
# 1304| r1304_11(glval<long>) = VariableAddress[#temp1304:9] :
# 1304| mu1304_12(long) = Store : &:r1304_11, r1304_2
#-----| Goto -> Block 10
# 1304| Block 12
# 1304| r1304_13(glval<long>) = VariableAddress[y] :
# 1304| r1304_14(long) = Load : &:r1304_13, ~mu1299_4
# 1304| r1304_15(glval<long>) = VariableAddress[#temp1304:9] :
# 1304| mu1304_16(long) = Store : &:r1304_15, r1304_14
#-----| Goto -> Block 10
# 1305| Block 13
# 1305| r1305_6(glval<long>) = VariableAddress[#temp1305:9] :
# 1305| r1305_7(long) = Load : &:r1305_6, ~mu1299_4
# 1305| r1305_8(int) = Convert : r1305_7
# 1305| r1305_9(glval<int>) = VariableAddress[z] :
# 1305| mu1305_10(int) = Store : &:r1305_9, r1305_8
# 1306| r1306_1(glval<long>) = VariableAddress[y] :
# 1306| r1306_2(long) = Load : &:r1306_1, ~mu1299_4
# 1306| r1306_3(long) = Constant[0] :
# 1306| r1306_4(bool) = CompareNE : r1306_2, r1306_3
# 1306| v1306_5(void) = ConditionalBranch : r1306_4
#-----| False -> Block 18
#-----| True -> Block 17
# 1305| Block 14
# 1305| r1305_11(glval<long>) = VariableAddress[#temp1305:9] :
# 1305| mu1305_12(long) = Store : &:r1305_11, r1305_2
#-----| Goto -> Block 13
# 1305| Block 15
# 1305| r1305_13(glval<int>) = VariableAddress[x] :
# 1305| r1305_14(int) = Load : &:r1305_13, ~mu1299_4
# 1305| r1305_15(long) = Convert : r1305_14
# 1305| r1305_16(glval<long>) = VariableAddress[#temp1305:9] :
# 1305| mu1305_17(long) = Store : &:r1305_16, r1305_15
#-----| Goto -> Block 13
# 1306| Block 16
# 1306| r1306_6(glval<long>) = VariableAddress[#temp1306:9] :
# 1306| r1306_7(long) = Load : &:r1306_6, ~mu1299_4
# 1306| r1306_8(int) = Convert : r1306_7
# 1306| r1306_9(glval<int>) = VariableAddress[z] :
# 1306| mu1306_10(int) = Store : &:r1306_9, r1306_8
# 1308| r1308_1(glval<int>) = VariableAddress[x] :
# 1308| r1308_2(int) = Load : &:r1308_1, ~mu1299_4
# 1308| r1308_3(int) = Constant[0] :
# 1308| r1308_4(bool) = CompareNE : r1308_2, r1308_3
# 1308| v1308_5(void) = ConditionalBranch : r1308_4
#-----| False -> Block 25
#-----| True -> Block 24
# 1306| Block 17
# 1306| r1306_11(glval<long>) = VariableAddress[#temp1306:9] :
# 1306| mu1306_12(long) = Store : &:r1306_11, r1306_2
#-----| Goto -> Block 16
# 1306| Block 18
# 1306| r1306_13(glval<long>) = VariableAddress[y] :
# 1306| r1306_14(long) = Load : &:r1306_13, ~mu1299_4
# 1306| r1306_15(glval<long>) = VariableAddress[#temp1306:9] :
# 1306| mu1306_16(long) = Store : &:r1306_15, r1306_14
#-----| Goto -> Block 16
# 1308| Block 19
# 1308| r1308_6(glval<int>) = VariableAddress[#temp1308:9] :
# 1308| r1308_7(int) = Load : &:r1308_6, ~mu1299_4
# 1308| r1308_8(glval<int>) = VariableAddress[z] :
# 1308| mu1308_9(int) = Store : &:r1308_8, r1308_7
# 1309| v1309_1(void) = NoOp :
# 1299| v1299_11(void) = ReturnVoid :
# 1299| v1299_12(void) = UnmodeledUse : mu*
# 1299| v1299_13(void) = AliasedUse : ~mu1299_4
# 1299| v1299_14(void) = ExitFunction :
# 1308| Block 20
# 1308| r1308_10(glval<int>) = VariableAddress[#temp1308:9] :
# 1308| mu1308_11(int) = Store : &:r1308_10, r1308_16
#-----| Goto -> Block 19
# 1308| Block 21
# 1308| r1308_12(glval<bool>) = VariableAddress[#temp1308:10] :
# 1308| r1308_13(bool) = Constant[0] :
# 1308| mu1308_14(bool) = Store : &:r1308_12, r1308_13
#-----| Goto -> Block 22
# 1308| Block 22
# 1308| r1308_15(glval<bool>) = VariableAddress[#temp1308:10] :
# 1308| r1308_16(bool) = Load : &:r1308_15, ~mu1299_4
# 1308| v1308_17(void) = ConditionalBranch : r1308_16
#-----| False -> Block 26
#-----| True -> Block 20
# 1308| Block 23
# 1308| r1308_18(glval<bool>) = VariableAddress[#temp1308:10] :
# 1308| r1308_19(bool) = Constant[1] :
# 1308| mu1308_20(bool) = Store : &:r1308_18, r1308_19
#-----| Goto -> Block 22
# 1308| Block 24
# 1308| r1308_21(glval<bool>) = VariableAddress[b] :
# 1308| r1308_22(bool) = Load : &:r1308_21, ~mu1299_4
# 1308| v1308_23(void) = ConditionalBranch : r1308_22
#-----| False -> Block 25
#-----| True -> Block 23
# 1308| Block 25
# 1308| r1308_24(glval<long>) = VariableAddress[y] :
# 1308| r1308_25(long) = Load : &:r1308_24, ~mu1299_4
# 1308| r1308_26(long) = Constant[0] :
# 1308| r1308_27(bool) = CompareNE : r1308_25, r1308_26
# 1308| v1308_28(void) = ConditionalBranch : r1308_27
#-----| False -> Block 21
#-----| True -> Block 23
# 1308| Block 26
# 1308| r1308_29(glval<int>) = VariableAddress[x] :
# 1308| r1308_30(int) = Load : &:r1308_29, ~mu1299_4
# 1308| r1308_31(glval<int>) = VariableAddress[#temp1308:9] :
# 1308| mu1308_32(int) = Store : &:r1308_31, r1308_30
#-----| Goto -> Block 19
# 1314| int shortCircuitConditional(int, int)
# 1314| Block 0
# 1314| v1314_1(void) = EnterFunction :
# 1314| mu1314_2(unknown) = AliasedDefinition :
# 1314| mu1314_3(unknown) = InitializeNonLocal :
# 1314| mu1314_4(unknown) = UnmodeledDefinition :
# 1314| r1314_5(glval<int>) = VariableAddress[x] :
# 1314| mu1314_6(int) = InitializeParameter[x] : &:r1314_5
# 1314| r1314_7(glval<int>) = VariableAddress[y] :
# 1314| mu1314_8(int) = InitializeParameter[y] : &:r1314_7
# 1315| r1315_1(glval<int>) = VariableAddress[#return] :
# 1315| r1315_2(glval<unknown>) = FunctionAddress[predicateA] :
# 1315| r1315_3(bool) = Call : func:r1315_2
# 1315| mu1315_4(unknown) = ^CallSideEffect : ~mu1314_4
# 1315| v1315_5(void) = ConditionalBranch : r1315_3
#-----| False -> Block 3
#-----| True -> Block 1
# 1315| Block 1
# 1315| r1315_6(glval<unknown>) = FunctionAddress[predicateB] :
# 1315| r1315_7(bool) = Call : func:r1315_6
# 1315| mu1315_8(unknown) = ^CallSideEffect : ~mu1314_4
# 1315| v1315_9(void) = ConditionalBranch : r1315_7
#-----| False -> Block 3
#-----| True -> Block 2
# 1315| Block 2
# 1315| r1315_10(glval<int>) = VariableAddress[x] :
# 1315| r1315_11(int) = Load : &:r1315_10, ~mu1314_4
# 1315| r1315_12(glval<int>) = VariableAddress[#temp1315:12] :
# 1315| mu1315_13(int) = Store : &:r1315_12, r1315_11
#-----| Goto -> Block 4
# 1315| Block 3
# 1315| r1315_14(glval<int>) = VariableAddress[y] :
# 1315| r1315_15(int) = Load : &:r1315_14, ~mu1314_4
# 1315| r1315_16(glval<int>) = VariableAddress[#temp1315:12] :
# 1315| mu1315_17(int) = Store : &:r1315_16, r1315_15
#-----| Goto -> Block 4
# 1315| Block 4
# 1315| r1315_18(glval<int>) = VariableAddress[#temp1315:12] :
# 1315| r1315_19(int) = Load : &:r1315_18, ~mu1314_4
# 1315| mu1315_20(int) = Store : &:r1315_1, r1315_19
# 1314| r1314_9(glval<int>) = VariableAddress[#return] :
# 1314| v1314_10(void) = ReturnValue : &:r1314_9, ~mu1314_4
# 1314| v1314_11(void) = UnmodeledUse : mu*
# 1314| v1314_12(void) = AliasedUse : ~mu1314_4
# 1314| v1314_13(void) = ExitFunction :
perf-regression.cpp:
# 6| void Big::Big()
# 6| Block 0