C++: initial GVN for function calls

This commit is contained in:
Robert Marsh
2022-07-25 14:26:54 -04:00
parent 0b691dd46c
commit 76b292da6a
4 changed files with 123 additions and 23 deletions

View File

@@ -41,8 +41,75 @@ newtype TValueNumber =
) {
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
} or
TCallValueNumber(TCallPartialValueNumber vn) { callValueNumber(_, _, vn) } or
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
newtype TCallPartialValueNumber =
TNilArgument() or
TArgument(TCallPartialValueNumber head, TValueNumber arg) {
exists(CallInstruction call, int index |
callArgValueNumber(call, index, arg) and
callPartialValueNumber(call, index, head)
)
}
predicate callValueNumber(CallInstruction call, int index, TCallPartialValueNumber vn) {
index = max(int n | callArgRank(call, n, _) | n) and
exists(TCallPartialValueNumber head, TValueNumber arg |
callPartialValueNumber(call, index, head) and
callArgValueNumber(call, index, arg) and
vn = TArgument(head, arg)
)
or
not exists(int n | callArgRank(call, n, _)) and
index = -1 and
vn = TNilArgument()
}
predicate callPartialValueNumber(CallInstruction call, int index, TCallPartialValueNumber head) {
index = 1 and head = TNilArgument()
or
exists(TCallPartialValueNumber prev, TValueNumber prevVN |
callPartialValueNumber(call, index - 1, prev) and
callArgValueNumber(call, index - 1, prevVN) and
head = TArgument(prev, prevVN)
)
}
/**
*/
predicate callArgValueNumber(CallInstruction call, int index, TValueNumber arg) {
exists(Instruction instr |
callArgRank(call, index, instr) and
arg = tvalueNumber(instr)
)
}
/**
* Holds if `arg` is the `index`th element in `call`'s extended argument list, including the `this`
* argument and side-effect reads.
*/
predicate callArgRank(CallInstruction call, int index, Instruction arg) {
arg =
rank[index](int argIndex, boolean isEffect, Instruction instr |
instr = call.getThisArgument() and
argIndex = -1 and
isEffect = false
or
instr = call.getPositionalArgument(argIndex) and
isEffect = false
or
exists(ReadSideEffectInstruction read |
read.getPrimaryInstruction() = call and
read.getSideEffectOperand().getDef() = instr and
read.getIndex() = argIndex and
isEffect = true
)
|
instr order by argIndex, isEffect
)
}
/**
* A `CopyInstruction` whose source operand's value is congruent to the definition of that source
* operand.
@@ -93,6 +160,8 @@ private predicate numberableInstruction(Instruction instr) {
instr instanceof CongruentCopyInstruction
or
instr instanceof LoadTotalOverlapInstruction
or
instr instanceof CallInstruction
}
private predicate filteredNumberableInstruction(Instruction instr) {
@@ -309,6 +378,11 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
or
// The value number of a copy is just the value number of its source value.
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
or
exists(TCallPartialValueNumber pvn |
callValueNumber(instr, _, pvn) and
result = TCallValueNumber(pvn)
)
)
)
}

View File

@@ -12,6 +12,7 @@
| test.cpp:29:7:29:8 | GVN | 29:c7-c8 31:c7-c8 |
| test.cpp:29:7:29:13 | GVN | 29:c7-c13 31:c7-c13 |
| test.cpp:29:12:29:13 | GVN | 29:c12-c13 31:c12-c13 |
| test.cpp:30:3:30:17 | GVN | 30:c3-c17 77:c20-c28 80:c9-c17 |
| test.cpp:31:7:31:24 | GVN | 31:c7-c24 32:c7-c7 |
| test.cpp:43:3:43:3 | GVN | 43:c3-c3 45:c3-c3 |
| test.cpp:43:7:43:8 | GVN | 43:c7-c8 45:c7-c8 |
@@ -28,7 +29,7 @@
| test.cpp:56:13:56:16 | GVN | 56:c13-c16 56:c31-c34 59:c9-c12 |
| test.cpp:56:14:56:16 | GVN | 56:c14-c16 56:c32-c34 56:c47-c49 59:c10-c12 |
| test.cpp:62:5:62:10 | GVN | 62:c5-c10 65:c10-c15 |
| test.cpp:77:20:77:28 | GVN | 77:c20-c28 79:c7-c7 |
| test.cpp:77:20:77:28 | GVN | 77:c20-c28 79:c7-c7 80:c9-c17 |
| test.cpp:79:11:79:14 | GVN | 79:c11-c14 79:c24-c27 |
| test.cpp:92:11:92:16 | GVN | 92:c11-c16 92:c15-c16 93:c10-c10 |
| test.cpp:105:11:105:12 | GVN | 105:c11-c12 106:c33-c34 |
@@ -44,9 +45,12 @@
| test.cpp:144:15:144:15 | GVN | 144:c15-c15 149:c15-c15 |
| test.cpp:153:11:153:18 | GVN | 153:c11-c18 154:c11-c18 156:c3-c10 |
| test.cpp:153:21:153:21 | GVN | 153:c21-c21 154:c21-c21 |
| test.cpp:166:11:166:16 | GVN | 166:c11-c16 167:c11-c16 173:c11-c16 |
| test.cpp:166:18:166:20 | GVN | 166:c18-c20 167:c18-c20 171:c10-c12 173:c18-c20 |
| test.cpp:166:18:166:20 | GVN | 166:c18-c20 167:c18-c20 173:c18-c20 |
| test.cpp:168:11:168:16 | GVN | 168:c11-c16 169:c11-c16 174:c11-c16 |
| test.cpp:168:18:168:20 | GVN | 168:c18-c20 169:c18-c20 171:c15-c17 174:c18-c20 |
| test.cpp:168:18:168:20 | GVN | 168:c18-c20 169:c18-c20 171:c15-c17 174:c18-c20 |
| test.cpp:176:3:176:5 | GVN | 176:c3-c5 178:c3-c5 |
| test.cpp:176:7:176:7 | GVN | 176:c7-c7 178:c7-c7 |
| test.cpp:176:10:176:10 | GVN | 176:c10-c10 178:c10-c10 |

View File

@@ -10,7 +10,8 @@
| test.cpp:21:16:21:16 | 2 | test.cpp:178:10:178:10 | 2 | AST only |
| test.cpp:29:3:29:3 | x | test.cpp:31:3:31:3 | x | IR only |
| test.cpp:29:3:29:24 | ... = ... | test.cpp:29:3:29:24 | ... = ... | AST only |
| test.cpp:30:3:30:17 | call to change_global02 | test.cpp:30:3:30:17 | call to change_global02 | AST only |
| test.cpp:30:3:30:17 | call to change_global02 | test.cpp:77:20:77:28 | call to getAValue | IR only |
| test.cpp:30:3:30:17 | call to change_global02 | test.cpp:80:9:80:17 | call to getAValue | IR only |
| test.cpp:31:3:31:3 | x | test.cpp:29:3:29:3 | x | IR only |
| test.cpp:31:3:31:24 | ... = ... | test.cpp:31:3:31:24 | ... = ... | AST only |
| test.cpp:32:3:32:7 | ... = ... | test.cpp:32:3:32:7 | ... = ... | AST only |
@@ -77,15 +78,21 @@
| test.cpp:59:17:59:20 | (int)... | test.cpp:59:17:59:20 | (int)... | AST only |
| test.cpp:59:17:59:20 | (int)... | test.cpp:88:12:88:12 | 0 | AST only |
| test.cpp:62:5:62:12 | ... ++ | test.cpp:62:5:62:12 | ... ++ | AST only |
| test.cpp:77:20:77:28 | call to getAValue | test.cpp:30:3:30:17 | call to change_global02 | IR only |
| test.cpp:77:20:77:28 | call to getAValue | test.cpp:79:7:79:7 | v | IR only |
| test.cpp:77:20:77:28 | call to getAValue | test.cpp:80:9:80:17 | call to getAValue | IR only |
| test.cpp:77:20:77:30 | (signed short)... | test.cpp:77:20:77:30 | (signed short)... | AST only |
| test.cpp:77:20:77:30 | (signed short)... | test.cpp:79:7:79:7 | v | AST only |
| test.cpp:79:7:79:7 | (int)... | test.cpp:79:7:79:7 | (int)... | AST only |
| test.cpp:79:7:79:7 | v | test.cpp:77:20:77:28 | call to getAValue | IR only |
| test.cpp:79:7:79:7 | v | test.cpp:77:20:77:30 | (signed short)... | AST only |
| test.cpp:79:7:79:7 | v | test.cpp:80:9:80:17 | call to getAValue | IR only |
| test.cpp:79:11:79:20 | (int)... | test.cpp:79:11:79:20 | (int)... | AST only |
| test.cpp:79:24:79:33 | (int)... | test.cpp:79:24:79:33 | (int)... | AST only |
| test.cpp:80:5:80:19 | ... = ... | test.cpp:80:5:80:19 | ... = ... | AST only |
| test.cpp:80:9:80:17 | call to getAValue | test.cpp:30:3:30:17 | call to change_global02 | IR only |
| test.cpp:80:9:80:17 | call to getAValue | test.cpp:77:20:77:28 | call to getAValue | IR only |
| test.cpp:80:9:80:17 | call to getAValue | test.cpp:79:7:79:7 | v | IR only |
| test.cpp:80:9:80:19 | (signed short)... | test.cpp:80:9:80:19 | (signed short)... | AST only |
| test.cpp:88:3:88:20 | ... = ... | test.cpp:88:3:88:20 | ... = ... | AST only |
| test.cpp:88:12:88:12 | 0 | test.cpp:44:9:44:9 | 0 | AST only |
@@ -132,16 +139,24 @@
| test.cpp:147:7:147:7 | y | test.cpp:145:15:145:15 | y | AST only |
| test.cpp:149:15:149:15 | x | test.cpp:144:15:144:15 | x | IR only |
| test.cpp:156:3:156:17 | ... = ... | test.cpp:156:3:156:17 | ... = ... | AST only |
| test.cpp:166:11:166:16 | call to strlen | test.cpp:167:11:167:16 | call to strlen | IR only |
| test.cpp:166:11:166:16 | call to strlen | test.cpp:173:11:173:16 | call to strlen | IR only |
| test.cpp:166:18:166:20 | (const char *)... | test.cpp:166:18:166:20 | (const char *)... | AST only |
| test.cpp:166:18:166:20 | (const char *)... | test.cpp:167:18:167:20 | (const char *)... | AST only |
| test.cpp:166:18:166:20 | (const char *)... | test.cpp:173:18:173:20 | (const char *)... | AST only |
| test.cpp:167:11:167:16 | call to strlen | test.cpp:166:11:166:16 | call to strlen | IR only |
| test.cpp:167:11:167:16 | call to strlen | test.cpp:173:11:173:16 | call to strlen | IR only |
| test.cpp:167:18:167:20 | (const char *)... | test.cpp:166:18:166:20 | (const char *)... | AST only |
| test.cpp:167:18:167:20 | (const char *)... | test.cpp:167:18:167:20 | (const char *)... | AST only |
| test.cpp:167:18:167:20 | (const char *)... | test.cpp:173:18:173:20 | (const char *)... | AST only |
| test.cpp:168:11:168:16 | call to strlen | test.cpp:169:11:169:16 | call to strlen | IR only |
| test.cpp:168:11:168:16 | call to strlen | test.cpp:174:11:174:16 | call to strlen | IR only |
| test.cpp:168:18:168:20 | (const char *)... | test.cpp:168:18:168:20 | (const char *)... | AST only |
| test.cpp:168:18:168:20 | (const char *)... | test.cpp:169:18:169:20 | (const char *)... | AST only |
| test.cpp:168:18:168:20 | (const char *)... | test.cpp:171:15:171:17 | (const char *)... | AST only |
| test.cpp:168:18:168:20 | (const char *)... | test.cpp:174:18:174:20 | (const char *)... | AST only |
| test.cpp:169:11:169:16 | call to strlen | test.cpp:168:11:168:16 | call to strlen | IR only |
| test.cpp:169:11:169:16 | call to strlen | test.cpp:174:11:174:16 | call to strlen | IR only |
| test.cpp:169:18:169:20 | (const char *)... | test.cpp:168:18:168:20 | (const char *)... | AST only |
| test.cpp:169:18:169:20 | (const char *)... | test.cpp:169:18:169:20 | (const char *)... | AST only |
| test.cpp:169:18:169:20 | (const char *)... | test.cpp:171:15:171:17 | (const char *)... | AST only |
@@ -150,15 +165,21 @@
| test.cpp:171:15:171:17 | (const char *)... | test.cpp:169:18:169:20 | (const char *)... | AST only |
| test.cpp:171:15:171:17 | (const char *)... | test.cpp:171:15:171:17 | (const char *)... | AST only |
| test.cpp:171:15:171:17 | (const char *)... | test.cpp:174:18:174:20 | (const char *)... | AST only |
| test.cpp:173:11:173:16 | call to strlen | test.cpp:166:11:166:16 | call to strlen | IR only |
| test.cpp:173:11:173:16 | call to strlen | test.cpp:167:11:167:16 | call to strlen | IR only |
| test.cpp:173:18:173:20 | (const char *)... | test.cpp:166:18:166:20 | (const char *)... | AST only |
| test.cpp:173:18:173:20 | (const char *)... | test.cpp:167:18:167:20 | (const char *)... | AST only |
| test.cpp:173:18:173:20 | (const char *)... | test.cpp:173:18:173:20 | (const char *)... | AST only |
| test.cpp:174:11:174:16 | call to strlen | test.cpp:168:11:168:16 | call to strlen | IR only |
| test.cpp:174:11:174:16 | call to strlen | test.cpp:169:11:169:16 | call to strlen | IR only |
| test.cpp:174:18:174:20 | (const char *)... | test.cpp:168:18:168:20 | (const char *)... | AST only |
| test.cpp:174:18:174:20 | (const char *)... | test.cpp:169:18:169:20 | (const char *)... | AST only |
| test.cpp:174:18:174:20 | (const char *)... | test.cpp:171:15:171:17 | (const char *)... | AST only |
| test.cpp:174:18:174:20 | (const char *)... | test.cpp:174:18:174:20 | (const char *)... | AST only |
| test.cpp:176:3:176:5 | call to add | test.cpp:178:3:178:5 | call to add | IR only |
| test.cpp:176:7:176:7 | 1 | test.cpp:10:16:10:16 | 1 | AST only |
| test.cpp:176:10:176:10 | 2 | test.cpp:21:16:21:16 | 2 | AST only |
| test.cpp:177:7:177:7 | 3 | test.cpp:35:16:35:16 | 3 | AST only |
| test.cpp:178:3:178:5 | call to add | test.cpp:176:3:176:5 | call to add | IR only |
| test.cpp:178:7:178:7 | 1 | test.cpp:10:16:10:16 | 1 | AST only |
| test.cpp:178:10:178:10 | 2 | test.cpp:21:16:21:16 | 2 | AST only |

View File

@@ -237,6 +237,7 @@ test.cpp:
# 30| r30_1(glval<unknown>) = FunctionAddress[change_global02] :
# 30| valnum = unique
# 30| v30_2(void) = Call[change_global02] : func:r30_1
# 30| valnum = r77_3, r80_2, v30_2
# 30| m30_3(unknown) = ^CallSideEffect : ~m25_4
# 30| valnum = unique
# 30| m30_4(unknown) = Chi : total:m25_4, partial:m30_3
@@ -590,19 +591,19 @@ test.cpp:
# 77| r77_2(glval<unknown>) = FunctionAddress[getAValue] :
# 77| valnum = unique
# 77| r77_3(int) = Call[getAValue] : func:r77_2
# 77| valnum = unique
# 77| valnum = r77_3, r80_2, v30_2
# 77| m77_4(unknown) = ^CallSideEffect : ~m75_4
# 77| valnum = unique
# 77| m77_5(unknown) = Chi : total:m75_4, partial:m77_4
# 77| valnum = unique
# 77| r77_6(signed short) = Convert : r77_3
# 77| valnum = m77_7, r77_6, r79_2
# 77| valnum = m77_7, m80_7, r77_6, r79_2, r80_5
# 77| m77_7(signed short) = Store[v] : &:r77_1, r77_6
# 77| valnum = m77_7, r77_6, r79_2
# 77| valnum = m77_7, m80_7, r77_6, r79_2, r80_5
# 79| r79_1(glval<signed short>) = VariableAddress[v] :
# 79| valnum = r77_1, r79_1, r80_6
# 79| r79_2(signed short) = Load[v] : &:r79_1, m77_7
# 79| valnum = m77_7, r77_6, r79_2
# 79| valnum = m77_7, m80_7, r77_6, r79_2, r80_5
# 79| r79_3(int) = Convert : r79_2
# 79| valnum = unique
# 79| r79_4(glval<two_values *>) = VariableAddress[vals] :
@@ -637,17 +638,17 @@ test.cpp:
# 80| r80_1(glval<unknown>) = FunctionAddress[getAValue] :
# 80| valnum = unique
# 80| r80_2(int) = Call[getAValue] : func:r80_1
# 80| valnum = unique
# 80| valnum = r77_3, r80_2, v30_2
# 80| m80_3(unknown) = ^CallSideEffect : ~m77_5
# 80| valnum = unique
# 80| m80_4(unknown) = Chi : total:m77_5, partial:m80_3
# 80| valnum = unique
# 80| r80_5(signed short) = Convert : r80_2
# 80| valnum = m80_7, r80_5
# 80| valnum = m77_7, m80_7, r77_6, r79_2, r80_5
# 80| r80_6(glval<signed short>) = VariableAddress[v] :
# 80| valnum = r77_1, r79_1, r80_6
# 80| m80_7(signed short) = Store[v] : &:r80_6, r80_5
# 80| valnum = m80_7, r80_5
# 80| valnum = m77_7, m80_7, r77_6, r79_2, r80_5
#-----| Goto -> Block 2
# 82| Block 2
@@ -1182,10 +1183,10 @@ test.cpp:
# 166| r166_5(char *) = Convert : r166_4
# 166| valnum = r166_5, r167_5, r173_5
# 166| r166_6(int) = Call[strlen] : func:r166_2, 0:r166_5
# 166| valnum = m166_8, r166_6
# 166| valnum = m166_8, m167_8, m173_8, r166_6, r167_6, r173_6
# 166| v166_7(void) = ^BufferReadSideEffect[0] : &:r166_5, ~m165_8
# 166| m166_8(int) = Store[a] : &:r166_1, r166_6
# 166| valnum = m166_8, r166_6
# 166| valnum = m166_8, m167_8, m173_8, r166_6, r167_6, r173_6
# 167| r167_1(glval<int>) = VariableAddress[b] :
# 167| valnum = unique
# 167| r167_2(glval<unknown>) = FunctionAddress[strlen] :
@@ -1197,10 +1198,10 @@ test.cpp:
# 167| r167_5(char *) = Convert : r167_4
# 167| valnum = r166_5, r167_5, r173_5
# 167| r167_6(int) = Call[strlen] : func:r167_2, 0:r167_5
# 167| valnum = m167_8, r167_6
# 167| valnum = m166_8, m167_8, m173_8, r166_6, r167_6, r173_6
# 167| v167_7(void) = ^BufferReadSideEffect[0] : &:r167_5, ~m165_8
# 167| m167_8(int) = Store[b] : &:r167_1, r167_6
# 167| valnum = m167_8, r167_6
# 167| valnum = m166_8, m167_8, m173_8, r166_6, r167_6, r173_6
# 168| r168_1(glval<int>) = VariableAddress[c] :
# 168| valnum = unique
# 168| r168_2(glval<unknown>) = FunctionAddress[strlen] :
@@ -1212,10 +1213,10 @@ test.cpp:
# 168| r168_5(char *) = Convert : r168_4
# 168| valnum = r168_5, r169_5, r171_6, r174_5
# 168| r168_6(int) = Call[strlen] : func:r168_2, 0:r168_5
# 168| valnum = m168_8, r168_6
# 168| valnum = m168_8, m169_8, m174_8, r168_6, r169_6, r174_6
# 168| v168_7(void) = ^BufferReadSideEffect[0] : &:r168_5, ~m165_12
# 168| m168_8(int) = Store[c] : &:r168_1, r168_6
# 168| valnum = m168_8, r168_6
# 168| valnum = m168_8, m169_8, m174_8, r168_6, r169_6, r174_6
# 169| r169_1(glval<int>) = VariableAddress[d] :
# 169| valnum = unique
# 169| r169_2(glval<unknown>) = FunctionAddress[strlen] :
@@ -1227,10 +1228,10 @@ test.cpp:
# 169| r169_5(char *) = Convert : r169_4
# 169| valnum = r168_5, r169_5, r171_6, r174_5
# 169| r169_6(int) = Call[strlen] : func:r169_2, 0:r169_5
# 169| valnum = m169_8, r169_6
# 169| valnum = m168_8, m169_8, m174_8, r168_6, r169_6, r174_6
# 169| v169_7(void) = ^BufferReadSideEffect[0] : &:r169_5, ~m165_12
# 169| m169_8(int) = Store[d] : &:r169_1, r169_6
# 169| valnum = m169_8, r169_6
# 169| valnum = m168_8, m169_8, m174_8, r168_6, r169_6, r174_6
# 171| r171_1(glval<unknown>) = FunctionAddress[strcat] :
# 171| valnum = unique
# 171| r171_2(glval<char *>) = VariableAddress[dst] :
@@ -1262,10 +1263,10 @@ test.cpp:
# 173| r173_5(char *) = Convert : r173_4
# 173| valnum = r166_5, r167_5, r173_5
# 173| r173_6(int) = Call[strlen] : func:r173_2, 0:r173_5
# 173| valnum = m173_8, r173_6
# 173| valnum = m166_8, m167_8, m173_8, r166_6, r167_6, r173_6
# 173| v173_7(void) = ^BufferReadSideEffect[0] : &:r173_5, ~m171_11
# 173| m173_8(int) = Store[e] : &:r173_1, r173_6
# 173| valnum = m173_8, r173_6
# 173| valnum = m166_8, m167_8, m173_8, r166_6, r167_6, r173_6
# 174| r174_1(glval<int>) = VariableAddress[f] :
# 174| valnum = unique
# 174| r174_2(glval<unknown>) = FunctionAddress[strlen] :
@@ -1277,10 +1278,10 @@ test.cpp:
# 174| r174_5(char *) = Convert : r174_4
# 174| valnum = r168_5, r169_5, r171_6, r174_5
# 174| r174_6(int) = Call[strlen] : func:r174_2, 0:r174_5
# 174| valnum = m174_8, r174_6
# 174| valnum = m168_8, m169_8, m174_8, r168_6, r169_6, r174_6
# 174| v174_7(void) = ^BufferReadSideEffect[0] : &:r174_5, ~m165_12
# 174| m174_8(int) = Store[f] : &:r174_1, r174_6
# 174| valnum = m174_8, r174_6
# 174| valnum = m168_8, m169_8, m174_8, r168_6, r169_6, r174_6
# 176| r176_1(glval<unknown>) = FunctionAddress[add] :
# 176| valnum = unique
# 176| r176_2(int) = Constant[1] :
@@ -1288,7 +1289,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 = unique
# 176| valnum = r176_4, r178_4
# 176| m176_5(unknown) = ^CallSideEffect : ~m165_4
# 176| valnum = unique
# 176| m176_6(unknown) = Chi : total:m165_4, partial:m176_5
@@ -1312,7 +1313,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 = unique
# 178| valnum = r176_4, r178_4
# 178| m178_5(unknown) = ^CallSideEffect : ~m177_6
# 178| valnum = unique
# 178| m178_6(unknown) = Chi : total:m177_6, partial:m178_5