Skip to content

Commit 46bc311

Browse files
committed
C++: Support constexpr if in the IR
1 parent 337db6b commit 46bc311

10 files changed

+423
-41
lines changed

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,8 @@ private predicate usedAsCondition(Expr expr) {
209209
or
210210
exists(IfStmt ifStmt | ifStmt.getCondition().getFullyConverted() = expr)
211211
or
212+
exists(ConstexprIfStmt ifStmt | ifStmt.getCondition().getFullyConverted() = expr)
213+
or
212214
exists(ConditionalExpr condExpr |
213215
// The two-operand form of `ConditionalExpr` treats its condition as a value, since it needs to
214216
// be reused as a value if the condition is true.

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,72 @@ class TranslatedIfStmt extends TranslatedStmt, ConditionContext {
774774
}
775775
}
776776

777+
class TranslatedConstExprIfStmt extends TranslatedStmt, ConditionContext {
778+
override ConstexprIfStmt stmt;
779+
780+
override Instruction getFirstInstruction(EdgeKind kind) {
781+
if this.hasInitialization()
782+
then result = this.getInitialization().getFirstInstruction(kind)
783+
else result = this.getFirstConditionInstruction(kind)
784+
}
785+
786+
override TranslatedElement getChild(int id) {
787+
id = 0 and result = this.getInitialization()
788+
or
789+
id = 1 and result = this.getCondition()
790+
or
791+
id = 2 and result = this.getThen()
792+
or
793+
id = 3 and result = this.getElse()
794+
}
795+
796+
private predicate hasInitialization() { exists(stmt.getInitialization()) }
797+
798+
private TranslatedStmt getInitialization() {
799+
result = getTranslatedStmt(stmt.getInitialization())
800+
}
801+
802+
private TranslatedCondition getCondition() {
803+
result = getTranslatedCondition(stmt.getCondition().getFullyConverted())
804+
}
805+
806+
private Instruction getFirstConditionInstruction(EdgeKind kind) {
807+
result = this.getCondition().getFirstInstruction(kind)
808+
}
809+
810+
private TranslatedStmt getThen() { result = getTranslatedStmt(stmt.getThen()) }
811+
812+
private TranslatedStmt getElse() { result = getTranslatedStmt(stmt.getElse()) }
813+
814+
private predicate hasElse() { exists(stmt.getElse()) }
815+
816+
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
817+
818+
override Instruction getChildTrueSuccessor(TranslatedCondition child, EdgeKind kind) {
819+
child = this.getCondition() and
820+
result = this.getThen().getFirstInstruction(kind)
821+
}
822+
823+
override Instruction getChildFalseSuccessor(TranslatedCondition child, EdgeKind kind) {
824+
child = this.getCondition() and
825+
if this.hasElse()
826+
then result = this.getElse().getFirstInstruction(kind)
827+
else result = this.getParent().getChildSuccessor(this, kind)
828+
}
829+
830+
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
831+
child = this.getInitialization() and
832+
result = this.getFirstConditionInstruction(kind)
833+
or
834+
(child = this.getThen() or child = this.getElse()) and
835+
result = this.getParent().getChildSuccessor(this, kind)
836+
}
837+
838+
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
839+
none()
840+
}
841+
}
842+
777843
abstract class TranslatedLoop extends TranslatedStmt, ConditionContext {
778844
override Loop stmt;
779845

cpp/ql/test/library-tests/ir/ir/aliased_ir.expected

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12614,6 +12614,7 @@ ir.cpp:
1261412614
# 2137| r2137_9(glval<bool>) = VariableAddress[b] :
1261512615
# 2137| r2137_10(bool) = Load[b] : &:r2137_9, m2136_6
1261612616
# 2137| v2137_11(void) = ConditionalBranch : r2137_10
12617+
#-----| False -> Block 2
1261712618
#-----| True -> Block 1
1261812619

1261912620
# 2138| Block 1
@@ -12626,6 +12627,170 @@ ir.cpp:
1262612627
# 2138| v2138_7(void) = ^IndirectReadSideEffect[-1] : &:r2138_1, m2137_8
1262712628
# 2138| m2138_8(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2138_1
1262812629
# 2138| m2138_9(ClassWithDestructor) = Chi : total:m2137_8, partial:m2138_8
12630+
#-----| Goto -> Block 2
12631+
12632+
# 2140| Block 2
12633+
# 2140| m2140_1(unknown) = Phi : from 0:~m2137_6, from 1:~m2138_6
12634+
# 2140| r2140_2(glval<ClassWithDestructor>) = VariableAddress[x] :
12635+
# 2140| m2140_3(ClassWithDestructor) = Uninitialized[x] : &:r2140_2
12636+
# 2140| r2140_4(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
12637+
# 2140| v2140_5(void) = Call[ClassWithDestructor] : func:r2140_4, this:r2140_2
12638+
# 2140| m2140_6(unknown) = ^CallSideEffect : ~m2140_1
12639+
# 2140| m2140_7(unknown) = Chi : total:m2140_1, partial:m2140_6
12640+
# 2140| m2140_8(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2140_2
12641+
# 2140| m2140_9(ClassWithDestructor) = Chi : total:m2140_3, partial:m2140_8
12642+
# 2140| r2140_10(bool) = Constant[1] :
12643+
# 2140| v2140_11(void) = ConditionalBranch : r2140_10
12644+
#-----| False -> Block 10
12645+
#-----| True -> Block 3
12646+
12647+
# 2141| Block 3
12648+
# 2141| r2141_1(glval<ClassWithDestructor>) = VariableAddress[x] :
12649+
# 2141| r2141_2(glval<unknown>) = FunctionAddress[set_x] :
12650+
# 2141| r2141_3(char) = Constant[97] :
12651+
# 2141| v2141_4(void) = Call[set_x] : func:r2141_2, this:r2141_1, 0:r2141_3
12652+
# 2141| m2141_5(unknown) = ^CallSideEffect : ~m2140_7
12653+
# 2141| m2141_6(unknown) = Chi : total:m2140_7, partial:m2141_5
12654+
# 2141| v2141_7(void) = ^IndirectReadSideEffect[-1] : &:r2141_1, m2140_9
12655+
# 2141| m2141_8(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2141_1
12656+
# 2141| m2141_9(ClassWithDestructor) = Chi : total:m2140_9, partial:m2141_8
12657+
# 2143| r2143_1(glval<ClassWithDestructor>) = VariableAddress[x] :
12658+
# 2143| m2143_2(ClassWithDestructor) = Uninitialized[x] : &:r2143_1
12659+
# 2143| r2143_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
12660+
# 2143| v2143_4(void) = Call[ClassWithDestructor] : func:r2143_3, this:r2143_1
12661+
# 2143| m2143_5(unknown) = ^CallSideEffect : ~m2141_6
12662+
# 2143| m2143_6(unknown) = Chi : total:m2141_6, partial:m2143_5
12663+
# 2143| m2143_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2143_1
12664+
# 2143| m2143_8(ClassWithDestructor) = Chi : total:m2143_2, partial:m2143_7
12665+
# 2143| r2143_9(glval<char>) = VariableAddress[c] :
12666+
# 2143| r2143_10(char) = Load[c] : &:r2143_9, m2136_8
12667+
# 2143| r2143_11(int) = Convert : r2143_10
12668+
# 2143| v2143_12(void) = Switch : r2143_11
12669+
#-----| Case[97] -> Block 4
12670+
#-----| Default -> Block 5
12671+
12672+
# 2144| Block 4
12673+
# 2144| v2144_1(void) = NoOp :
12674+
# 2145| r2145_1(glval<ClassWithDestructor>) = VariableAddress[x] :
12675+
# 2145| r2145_2(glval<unknown>) = FunctionAddress[set_x] :
12676+
# 2145| r2145_3(char) = Constant[97] :
12677+
# 2145| v2145_4(void) = Call[set_x] : func:r2145_2, this:r2145_1, 0:r2145_3
12678+
# 2145| m2145_5(unknown) = ^CallSideEffect : ~m2143_6
12679+
# 2145| m2145_6(unknown) = Chi : total:m2143_6, partial:m2145_5
12680+
# 2145| v2145_7(void) = ^IndirectReadSideEffect[-1] : &:r2145_1, m2143_8
12681+
# 2145| m2145_8(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2145_1
12682+
# 2145| m2145_9(ClassWithDestructor) = Chi : total:m2143_8, partial:m2145_8
12683+
# 2146| v2146_1(void) = NoOp :
12684+
#-----| Goto -> Block 6
12685+
12686+
# 2147| Block 5
12687+
# 2147| v2147_1(void) = NoOp :
12688+
# 2148| r2148_1(glval<ClassWithDestructor>) = VariableAddress[x] :
12689+
# 2148| r2148_2(glval<unknown>) = FunctionAddress[set_x] :
12690+
# 2148| r2148_3(char) = Constant[98] :
12691+
# 2148| v2148_4(void) = Call[set_x] : func:r2148_2, this:r2148_1, 0:r2148_3
12692+
# 2148| m2148_5(unknown) = ^CallSideEffect : ~m2143_6
12693+
# 2148| m2148_6(unknown) = Chi : total:m2143_6, partial:m2148_5
12694+
# 2148| v2148_7(void) = ^IndirectReadSideEffect[-1] : &:r2148_1, m2143_8
12695+
# 2148| m2148_8(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2148_1
12696+
# 2148| m2148_9(ClassWithDestructor) = Chi : total:m2143_8, partial:m2148_8
12697+
# 2149| v2149_1(void) = NoOp :
12698+
#-----| Goto -> Block 6
12699+
12700+
# 2150| Block 6
12701+
# 2150| m2150_1(unknown) = Phi : from 4:~m2145_6, from 5:~m2148_6
12702+
# 2150| v2150_2(void) = NoOp :
12703+
# 2152| r2152_1(glval<ClassWithDestructor>) = VariableAddress[x] :
12704+
# 2152| m2152_2(ClassWithDestructor) = Uninitialized[x] : &:r2152_1
12705+
# 2152| r2152_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
12706+
# 2152| v2152_4(void) = Call[ClassWithDestructor] : func:r2152_3, this:r2152_1
12707+
# 2152| m2152_5(unknown) = ^CallSideEffect : ~m2150_1
12708+
# 2152| m2152_6(unknown) = Chi : total:m2150_1, partial:m2152_5
12709+
# 2152| m2152_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2152_1
12710+
# 2152| m2152_8(ClassWithDestructor) = Chi : total:m2152_2, partial:m2152_7
12711+
# 2153| r2153_1(glval<vector<ClassWithDestructor> &>) = VariableAddress[(__range)] :
12712+
# 2153| r2153_2(glval<vector<ClassWithDestructor>>) = VariableAddress :
12713+
# 2153| r2153_3(vector<ClassWithDestructor> &) = CopyValue : r2153_2
12714+
# 2153| m2153_4(vector<ClassWithDestructor> &) = Store[(__range)] : &:r2153_1, r2153_3
12715+
# 2153| r2153_5(glval<iterator>) = VariableAddress[(__begin)] :
12716+
# 2153| r2153_6(glval<vector<ClassWithDestructor> &>) = VariableAddress[(__range)] :
12717+
# 2153| r2153_7(vector<ClassWithDestructor> &) = Load[(__range)] : &:r2153_6, m2153_4
12718+
#-----| r0_1(glval<vector<ClassWithDestructor>>) = CopyValue : r2153_7
12719+
#-----| r0_2(glval<vector<ClassWithDestructor>>) = Convert : r0_1
12720+
# 2153| r2153_8(glval<unknown>) = FunctionAddress[begin] :
12721+
# 2153| r2153_9(iterator) = Call[begin] : func:r2153_8, this:r0_2
12722+
# 2153| m2153_10(unknown) = ^CallSideEffect : ~m2152_6
12723+
# 2153| m2153_11(unknown) = Chi : total:m2152_6, partial:m2153_10
12724+
#-----| v0_3(void) = ^IndirectReadSideEffect[-1] : &:r0_2, ~m2153_11
12725+
# 2153| m2153_12(iterator) = Store[(__begin)] : &:r2153_5, r2153_9
12726+
# 2153| r2153_13(glval<iterator>) = VariableAddress[(__end)] :
12727+
# 2153| r2153_14(glval<vector<ClassWithDestructor> &>) = VariableAddress[(__range)] :
12728+
# 2153| r2153_15(vector<ClassWithDestructor> &) = Load[(__range)] : &:r2153_14, m2153_4
12729+
#-----| r0_4(glval<vector<ClassWithDestructor>>) = CopyValue : r2153_15
12730+
#-----| r0_5(glval<vector<ClassWithDestructor>>) = Convert : r0_4
12731+
# 2153| r2153_16(glval<unknown>) = FunctionAddress[end] :
12732+
# 2153| r2153_17(iterator) = Call[end] : func:r2153_16, this:r0_5
12733+
# 2153| m2153_18(unknown) = ^CallSideEffect : ~m2153_11
12734+
# 2153| m2153_19(unknown) = Chi : total:m2153_11, partial:m2153_18
12735+
#-----| v0_6(void) = ^IndirectReadSideEffect[-1] : &:r0_5, ~m2153_19
12736+
# 2153| m2153_20(iterator) = Store[(__end)] : &:r2153_13, r2153_17
12737+
#-----| Goto -> Block 7
12738+
12739+
# 2153| Block 7
12740+
# 2153| m2153_21(iterator) = Phi : from 6:m2153_12, from 8:m2153_46
12741+
# 2153| m2153_22(unknown) = Phi : from 6:~m2153_19, from 8:~m2153_43
12742+
# 2153| r2153_23(glval<iterator>) = VariableAddress[(__begin)] :
12743+
#-----| r0_7(glval<iterator>) = Convert : r2153_23
12744+
# 2153| r2153_24(glval<unknown>) = FunctionAddress[operator!=] :
12745+
# 2153| r2153_25(glval<iterator>) = VariableAddress[(__end)] :
12746+
# 2153| r2153_26(iterator) = Load[(__end)] : &:r2153_25, m2153_20
12747+
# 2153| r2153_27(bool) = Call[operator!=] : func:r2153_24, this:r0_7, 0:r2153_26
12748+
# 2153| m2153_28(unknown) = ^CallSideEffect : ~m2153_22
12749+
# 2153| m2153_29(unknown) = Chi : total:m2153_22, partial:m2153_28
12750+
#-----| v0_8(void) = ^IndirectReadSideEffect[-1] : &:r0_7, m2153_21
12751+
# 2153| v2153_30(void) = ConditionalBranch : r2153_27
12752+
#-----| False -> Block 9
12753+
#-----| True -> Block 8
12754+
12755+
# 2153| Block 8
12756+
# 2153| r2153_31(glval<ClassWithDestructor>) = VariableAddress[y] :
12757+
# 2153| r2153_32(glval<iterator>) = VariableAddress[(__begin)] :
12758+
#-----| r0_9(glval<iterator>) = Convert : r2153_32
12759+
# 2153| r2153_33(glval<unknown>) = FunctionAddress[operator*] :
12760+
# 2153| r2153_34(ClassWithDestructor &) = Call[operator*] : func:r2153_33, this:r0_9
12761+
# 2153| m2153_35(unknown) = ^CallSideEffect : ~m2153_29
12762+
# 2153| m2153_36(unknown) = Chi : total:m2153_29, partial:m2153_35
12763+
#-----| v0_10(void) = ^IndirectReadSideEffect[-1] : &:r0_9, m2153_21
12764+
# 2153| r2153_37(ClassWithDestructor) = Load[?] : &:r2153_34, ~m2153_36
12765+
# 2153| m2153_38(ClassWithDestructor) = Store[y] : &:r2153_31, r2153_37
12766+
# 2154| r2154_1(glval<ClassWithDestructor>) = VariableAddress[y] :
12767+
# 2154| r2154_2(glval<unknown>) = FunctionAddress[set_x] :
12768+
# 2154| r2154_3(char) = Constant[97] :
12769+
# 2154| v2154_4(void) = Call[set_x] : func:r2154_2, this:r2154_1, 0:r2154_3
12770+
# 2154| m2154_5(unknown) = ^CallSideEffect : ~m2153_36
12771+
# 2154| m2154_6(unknown) = Chi : total:m2153_36, partial:m2154_5
12772+
# 2154| v2154_7(void) = ^IndirectReadSideEffect[-1] : &:r2154_1, m2153_38
12773+
# 2154| m2154_8(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2154_1
12774+
# 2154| m2154_9(ClassWithDestructor) = Chi : total:m2153_38, partial:m2154_8
12775+
# 2153| r2153_39(glval<iterator>) = VariableAddress[(__begin)] :
12776+
# 2153| r2153_40(glval<unknown>) = FunctionAddress[operator++] :
12777+
# 2153| r2153_41(iterator &) = Call[operator++] : func:r2153_40, this:r2153_39
12778+
# 2153| m2153_42(unknown) = ^CallSideEffect : ~m2154_6
12779+
# 2153| m2153_43(unknown) = Chi : total:m2154_6, partial:m2153_42
12780+
# 2153| v2153_44(void) = ^IndirectReadSideEffect[-1] : &:r2153_39, m2153_21
12781+
# 2153| m2153_45(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r2153_39
12782+
# 2153| m2153_46(iterator) = Chi : total:m2153_21, partial:m2153_45
12783+
# 2153| r2153_47(glval<iterator>) = CopyValue : r2153_41
12784+
#-----| Goto (back edge) -> Block 7
12785+
12786+
# 2155| Block 9
12787+
# 2155| v2155_1(void) = NoOp :
12788+
# 2136| v2136_9(void) = ReturnVoid :
12789+
# 2136| v2136_10(void) = AliasedUse : ~m2153_29
12790+
# 2136| v2136_11(void) = ExitFunction :
12791+
12792+
# 2136| Block 10
12793+
# 2136| v2136_12(void) = Unreached :
1262912794

1263012795
perf-regression.cpp:
1263112796
# 6| void Big::Big()

cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ missingOperandType
66
duplicateChiOperand
77
sideEffectWithoutPrimary
88
instructionWithoutSuccessor
9-
| ir.cpp:2138:9:2138:9 | Chi: x | Instruction 'Chi: x' has no successors in function '$@'. | ir.cpp:2136:6:2136:35 | void initialization_with_destructor(bool, char) | void initialization_with_destructor(bool, char) |
109
ambiguousSuccessors
1110
unexplainedLoop
1211
unnecessaryPhiInstruction
@@ -29,4 +28,5 @@ nonUniqueEnclosingIRFunction
2928
fieldAddressOnNonPointer
3029
thisArgumentIsNonPointer
3130
nonUniqueIRVariable
31+
| ir.cpp:2153:68:2153:69 | VariableAddress: ys | Variable address instruction 'VariableAddress: ys' has no associated variable, in function '$@'. | ir.cpp:2136:6:2136:35 | void initialization_with_destructor(bool, char) | void initialization_with_destructor(bool, char) |
3232
missingCppType

cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ missingOperandType
66
duplicateChiOperand
77
sideEffectWithoutPrimary
88
instructionWithoutSuccessor
9-
| ir.cpp:2138:9:2138:9 | Chi: x | Instruction 'Chi: x' has no successors in function '$@'. | ir.cpp:2136:6:2136:35 | void initialization_with_destructor(bool, char) | void initialization_with_destructor(bool, char) |
109
ambiguousSuccessors
1110
unexplainedLoop
1211
unnecessaryPhiInstruction
@@ -29,4 +28,5 @@ nonUniqueEnclosingIRFunction
2928
fieldAddressOnNonPointer
3029
thisArgumentIsNonPointer
3130
nonUniqueIRVariable
31+
| ir.cpp:2153:68:2153:69 | VariableAddress: ys | Variable address instruction 'VariableAddress: ys' has no associated variable, in function '$@'. | ir.cpp:2136:6:2136:35 | void initialization_with_destructor(bool, char) | void initialization_with_destructor(bool, char) |
3232
missingCppType

0 commit comments

Comments
 (0)