C++: Only GVN side-effect-free functions. This improves the performance dramatically.

This commit is contained in:
Mathias Vorreiter Pedersen
2022-08-25 15:45:50 +01:00
parent fac28ccbe0
commit dc105b404b
7 changed files with 86 additions and 86 deletions

View File

@@ -1,3 +1,4 @@
import semmle.code.cpp.ir.implementation.aliased_ssa.IR
import semmle.code.cpp.ir.internal.Overlap
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import semmle.code.cpp.models.interfaces.SideEffect as SideEffect

View File

@@ -44,16 +44,30 @@ newtype TValueNumber =
TCallValueNumber(TCallPartialValueNumber vn) { callValueNumber(_, _, vn) } or
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
private class NumberableCallInstruction extends CallInstruction {
NumberableCallInstruction() {
not this.getResultIRType() instanceof IRVoidType and
exists(SideEffect::SideEffectFunction sideEffectFunc |
sideEffectFunc = this.getStaticCallTarget()
|
sideEffectFunc.hasOnlySpecificReadSideEffects() and
sideEffectFunc.hasOnlySpecificWriteSideEffects()
)
}
}
private newtype TCallPartialValueNumber =
TNilArgument() or
TArgument(TCallPartialValueNumber head, TValueNumber arg) {
exists(CallInstruction call, int index |
exists(NumberableCallInstruction call, int index |
callArgValueNumber(call, index, arg) and
callPartialValueNumber(call, index, head)
)
}
private predicate callValueNumber(CallInstruction call, int index, TCallPartialValueNumber vn) {
private predicate callValueNumber(
NumberableCallInstruction call, int index, TCallPartialValueNumber vn
) {
index = max(int n | callArgRank(call, n, _) | n) and
exists(TCallPartialValueNumber head, TValueNumber arg |
callPartialValueNumber(call, index, pragma[only_bind_out](head)) and
@@ -61,14 +75,15 @@ private predicate callValueNumber(CallInstruction call, int index, TCallPartialV
vn = TArgument(head, arg)
)
or
not call.getResultIRType() instanceof IRVoidType and
not exists(int n | callArgRank(call, n, _)) and
index = -1 and
vn = TNilArgument()
}
private predicate callPartialValueNumber(CallInstruction call, int index, TCallPartialValueNumber head) {
index = 1 and head = TNilArgument() and not call.getResultIRType() instanceof IRVoidType
private predicate callPartialValueNumber(
NumberableCallInstruction call, int index, TCallPartialValueNumber head
) {
index = 1 and head = TNilArgument()
or
exists(TCallPartialValueNumber prev, TValueNumber prevVN |
callPartialValueNumber(call, index - 1, pragma[only_bind_out](prev)) and
@@ -79,8 +94,7 @@ private predicate callPartialValueNumber(CallInstruction call, int index, TCallP
/**
*/
private predicate callArgValueNumber(CallInstruction call, int index, TValueNumber arg) {
not call.getResultIRType() instanceof IRVoidType and
private predicate callArgValueNumber(NumberableCallInstruction call, int index, TValueNumber arg) {
exists(Instruction instr |
callArgRank(call, index, instr) and
arg = tvalueNumber(instr)
@@ -91,28 +105,13 @@ private predicate callArgValueNumber(CallInstruction call, int index, TValueNumb
* Holds if `arg` is the `index`th element in `call`'s extended argument list, including the `this`
* argument and side-effect reads.
*/
private predicate callArgRank(CallInstruction call, int index, Instruction arg) {
private predicate callArgRank(NumberableCallInstruction call, int index, Instruction arg) {
arg =
rank[index](int argIndex, boolean isEffect, Instruction instr |
exists(CallSideEffectInstruction cse |
cse.getPrimaryInstruction() = call and
cse.getSideEffectOperand().getAnyDef() = instr and
argIndex = -2 and
isEffect = true
)
or
exists(CallReadSideEffectInstruction cse |
cse.getPrimaryInstruction() = call and
cse.getSideEffectOperand().getAnyDef() = instr and
argIndex = -2 and
isEffect = true
)
or
instr = call.getThisArgument() and
argIndex = -1 and
isEffect = false
or
instr = call.getPositionalArgument(argIndex) and
// There is no need to include the call's read and write side effects on
// all-aliased-memory as `NumberableCallInstruction`s do not read or write
// to all-aliased-memory.
instr = call.getArgument(argIndex) and
isEffect = false
or
exists(ReadSideEffectInstruction read |
@@ -177,7 +176,7 @@ private predicate numberableInstruction(Instruction instr) {
or
instr instanceof LoadTotalOverlapInstruction
or
instr instanceof CallInstruction
instr instanceof NumberableCallInstruction
}
private predicate filteredNumberableInstruction(Instruction instr) {

View File

@@ -1,3 +1,4 @@
import semmle.code.cpp.ir.implementation.aliased_ssa.IR
import semmle.code.cpp.ir.internal.Overlap
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import semmle.code.cpp.models.interfaces.SideEffect as SideEffect

View File

@@ -44,16 +44,30 @@ newtype TValueNumber =
TCallValueNumber(TCallPartialValueNumber vn) { callValueNumber(_, _, vn) } or
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
private class NumberableCallInstruction extends CallInstruction {
NumberableCallInstruction() {
not this.getResultIRType() instanceof IRVoidType and
exists(SideEffect::SideEffectFunction sideEffectFunc |
sideEffectFunc = this.getStaticCallTarget()
|
sideEffectFunc.hasOnlySpecificReadSideEffects() and
sideEffectFunc.hasOnlySpecificWriteSideEffects()
)
}
}
private newtype TCallPartialValueNumber =
TNilArgument() or
TArgument(TCallPartialValueNumber head, TValueNumber arg) {
exists(CallInstruction call, int index |
exists(NumberableCallInstruction call, int index |
callArgValueNumber(call, index, arg) and
callPartialValueNumber(call, index, head)
)
}
private predicate callValueNumber(CallInstruction call, int index, TCallPartialValueNumber vn) {
private predicate callValueNumber(
NumberableCallInstruction call, int index, TCallPartialValueNumber vn
) {
index = max(int n | callArgRank(call, n, _) | n) and
exists(TCallPartialValueNumber head, TValueNumber arg |
callPartialValueNumber(call, index, pragma[only_bind_out](head)) and
@@ -61,14 +75,15 @@ private predicate callValueNumber(CallInstruction call, int index, TCallPartialV
vn = TArgument(head, arg)
)
or
not call.getResultIRType() instanceof IRVoidType and
not exists(int n | callArgRank(call, n, _)) and
index = -1 and
vn = TNilArgument()
}
private predicate callPartialValueNumber(CallInstruction call, int index, TCallPartialValueNumber head) {
index = 1 and head = TNilArgument() and not call.getResultIRType() instanceof IRVoidType
private predicate callPartialValueNumber(
NumberableCallInstruction call, int index, TCallPartialValueNumber head
) {
index = 1 and head = TNilArgument()
or
exists(TCallPartialValueNumber prev, TValueNumber prevVN |
callPartialValueNumber(call, index - 1, pragma[only_bind_out](prev)) and
@@ -79,8 +94,7 @@ private predicate callPartialValueNumber(CallInstruction call, int index, TCallP
/**
*/
private predicate callArgValueNumber(CallInstruction call, int index, TValueNumber arg) {
not call.getResultIRType() instanceof IRVoidType and
private predicate callArgValueNumber(NumberableCallInstruction call, int index, TValueNumber arg) {
exists(Instruction instr |
callArgRank(call, index, instr) and
arg = tvalueNumber(instr)
@@ -91,28 +105,13 @@ private predicate callArgValueNumber(CallInstruction call, int index, TValueNumb
* Holds if `arg` is the `index`th element in `call`'s extended argument list, including the `this`
* argument and side-effect reads.
*/
private predicate callArgRank(CallInstruction call, int index, Instruction arg) {
private predicate callArgRank(NumberableCallInstruction call, int index, Instruction arg) {
arg =
rank[index](int argIndex, boolean isEffect, Instruction instr |
exists(CallSideEffectInstruction cse |
cse.getPrimaryInstruction() = call and
cse.getSideEffectOperand().getAnyDef() = instr and
argIndex = -2 and
isEffect = true
)
or
exists(CallReadSideEffectInstruction cse |
cse.getPrimaryInstruction() = call and
cse.getSideEffectOperand().getAnyDef() = instr and
argIndex = -2 and
isEffect = true
)
or
instr = call.getThisArgument() and
argIndex = -1 and
isEffect = false
or
instr = call.getPositionalArgument(argIndex) and
// There is no need to include the call's read and write side effects on
// all-aliased-memory as `NumberableCallInstruction`s do not read or write
// to all-aliased-memory.
instr = call.getArgument(argIndex) and
isEffect = false
or
exists(ReadSideEffectInstruction read |
@@ -177,7 +176,7 @@ private predicate numberableInstruction(Instruction instr) {
or
instr instanceof LoadTotalOverlapInstruction
or
instr instanceof CallInstruction
instr instanceof NumberableCallInstruction
}
private predicate filteredNumberableInstruction(Instruction instr) {

View File

@@ -1,3 +1,4 @@
import semmle.code.cpp.ir.implementation.aliased_ssa.IR
import semmle.code.cpp.ir.internal.Overlap
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import semmle.code.cpp.models.interfaces.SideEffect as SideEffect

View File

@@ -44,16 +44,30 @@ newtype TValueNumber =
TCallValueNumber(TCallPartialValueNumber vn) { callValueNumber(_, _, vn) } or
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
private class NumberableCallInstruction extends CallInstruction {
NumberableCallInstruction() {
not this.getResultIRType() instanceof IRVoidType and
exists(SideEffect::SideEffectFunction sideEffectFunc |
sideEffectFunc = this.getStaticCallTarget()
|
sideEffectFunc.hasOnlySpecificReadSideEffects() and
sideEffectFunc.hasOnlySpecificWriteSideEffects()
)
}
}
private newtype TCallPartialValueNumber =
TNilArgument() or
TArgument(TCallPartialValueNumber head, TValueNumber arg) {
exists(CallInstruction call, int index |
exists(NumberableCallInstruction call, int index |
callArgValueNumber(call, index, arg) and
callPartialValueNumber(call, index, head)
)
}
private predicate callValueNumber(CallInstruction call, int index, TCallPartialValueNumber vn) {
private predicate callValueNumber(
NumberableCallInstruction call, int index, TCallPartialValueNumber vn
) {
index = max(int n | callArgRank(call, n, _) | n) and
exists(TCallPartialValueNumber head, TValueNumber arg |
callPartialValueNumber(call, index, pragma[only_bind_out](head)) and
@@ -61,14 +75,15 @@ private predicate callValueNumber(CallInstruction call, int index, TCallPartialV
vn = TArgument(head, arg)
)
or
not call.getResultIRType() instanceof IRVoidType and
not exists(int n | callArgRank(call, n, _)) and
index = -1 and
vn = TNilArgument()
}
private predicate callPartialValueNumber(CallInstruction call, int index, TCallPartialValueNumber head) {
index = 1 and head = TNilArgument() and not call.getResultIRType() instanceof IRVoidType
private predicate callPartialValueNumber(
NumberableCallInstruction call, int index, TCallPartialValueNumber head
) {
index = 1 and head = TNilArgument()
or
exists(TCallPartialValueNumber prev, TValueNumber prevVN |
callPartialValueNumber(call, index - 1, pragma[only_bind_out](prev)) and
@@ -79,8 +94,7 @@ private predicate callPartialValueNumber(CallInstruction call, int index, TCallP
/**
*/
private predicate callArgValueNumber(CallInstruction call, int index, TValueNumber arg) {
not call.getResultIRType() instanceof IRVoidType and
private predicate callArgValueNumber(NumberableCallInstruction call, int index, TValueNumber arg) {
exists(Instruction instr |
callArgRank(call, index, instr) and
arg = tvalueNumber(instr)
@@ -91,28 +105,13 @@ private predicate callArgValueNumber(CallInstruction call, int index, TValueNumb
* Holds if `arg` is the `index`th element in `call`'s extended argument list, including the `this`
* argument and side-effect reads.
*/
private predicate callArgRank(CallInstruction call, int index, Instruction arg) {
private predicate callArgRank(NumberableCallInstruction call, int index, Instruction arg) {
arg =
rank[index](int argIndex, boolean isEffect, Instruction instr |
exists(CallSideEffectInstruction cse |
cse.getPrimaryInstruction() = call and
cse.getSideEffectOperand().getAnyDef() = instr and
argIndex = -2 and
isEffect = true
)
or
exists(CallReadSideEffectInstruction cse |
cse.getPrimaryInstruction() = call and
cse.getSideEffectOperand().getAnyDef() = instr and
argIndex = -2 and
isEffect = true
)
or
instr = call.getThisArgument() and
argIndex = -1 and
isEffect = false
or
instr = call.getPositionalArgument(argIndex) and
// There is no need to include the call's read and write side effects on
// all-aliased-memory as `NumberableCallInstruction`s do not read or write
// to all-aliased-memory.
instr = call.getArgument(argIndex) and
isEffect = false
or
exists(ReadSideEffectInstruction read |
@@ -177,7 +176,7 @@ private predicate numberableInstruction(Instruction instr) {
or
instr instanceof LoadTotalOverlapInstruction
or
instr instanceof CallInstruction
instr instanceof NumberableCallInstruction
}
private predicate filteredNumberableInstruction(Instruction instr) {

View File

@@ -1325,7 +1325,7 @@ test.cpp:
# 176| r176_3(int) = Constant[2] :
# 176| valnum = r176_3, r178_3
# 176| r176_4(int) = Call[add] : func:r176_1, 0:r176_2, 1:r176_3
# 176| valnum = r176_4, r178_4
# 176| valnum = unique
# 177| r177_1(glval<unknown>) = FunctionAddress[add] :
# 177| valnum = unique
# 177| r177_2(int) = Constant[3] :
@@ -1341,7 +1341,7 @@ test.cpp:
# 178| r178_3(int) = Constant[2] :
# 178| valnum = r176_3, r178_3
# 178| r178_4(int) = Call[add] : func:r178_1, 0:r178_2, 1:r178_3
# 178| valnum = r176_4, r178_4
# 178| valnum = unique
# 179| v179_1(void) = NoOp :
# 165| v165_13(void) = ReturnIndirection[dst] : &:r165_7, m171_11
# 165| v165_14(void) = ReturnIndirection[src] : &:r165_11, m165_12