Skip to content

Commit eabe651

Browse files
authored
Merge pull request #20069 from jketema/spaceship-ir
C++: Support the spaceship operator in the IR
2 parents 9b8302f + 29a6af4 commit eabe651

File tree

12 files changed

+110
-62
lines changed

12 files changed

+110
-62
lines changed

cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ private newtype TOpcode =
4242
TCompareGT() or
4343
TCompareLE() or
4444
TCompareGE() or
45+
TSpaceship() or
4546
TPointerAdd() or
4647
TPointerSub() or
4748
TPointerDiff() or
@@ -765,6 +766,15 @@ module Opcode {
765766
final override string toString() { result = "CompareGE" }
766767
}
767768

769+
/**
770+
* The `Opcode` for a `SpaceshipInstruction`.
771+
*
772+
* See the `SpaceshipInstruction` documentation for more details.
773+
*/
774+
class Spaceship extends BinaryOpcode, TSpaceship {
775+
final override string toString() { result = "Spaceship" }
776+
}
777+
768778
/**
769779
* The `Opcode` for a `PointerAddInstruction`.
770780
*

cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1604,6 +1604,13 @@ class CompareGEInstruction extends RelationalInstruction {
16041604
override predicate isStrict() { none() }
16051605
}
16061606

1607+
/**
1608+
* An instruction that represents a three-way comparison operator.
1609+
*/
1610+
class SpaceshipInstruction extends BinaryInstruction {
1611+
SpaceshipInstruction() { this.getOpcode() instanceof Opcode::Spaceship }
1612+
}
1613+
16071614
/**
16081615
* An instruction that branches to one of multiple successor instructions based on the value of an
16091616
* integer operand.

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1604,6 +1604,13 @@ class CompareGEInstruction extends RelationalInstruction {
16041604
override predicate isStrict() { none() }
16051605
}
16061606

1607+
/**
1608+
* An instruction that represents a three-way comparison operator.
1609+
*/
1610+
class SpaceshipInstruction extends BinaryInstruction {
1611+
SpaceshipInstruction() { this.getOpcode() instanceof Opcode::Spaceship }
1612+
}
1613+
16071614
/**
16081615
* An instruction that branches to one of multiple successor instructions based on the value of an
16091616
* integer operand.

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1808,6 +1808,11 @@ private Opcode comparisonOpcode(ComparisonOperation expr) {
18081808
expr instanceof GEExpr and result instanceof Opcode::CompareGE
18091809
}
18101810

1811+
private Opcode spaceShipOpcode(SpaceshipExpr expr) {
1812+
exists(expr) and
1813+
result instanceof Opcode::Spaceship
1814+
}
1815+
18111816
/**
18121817
* IR translation of a simple binary operation.
18131818
*/
@@ -1867,7 +1872,8 @@ class TranslatedBinaryOperation extends TranslatedSingleInstructionExpr {
18671872
override Opcode getOpcode() {
18681873
result = binaryArithmeticOpcode(expr) or
18691874
result = binaryBitwiseOpcode(expr) or
1870-
result = comparisonOpcode(expr)
1875+
result = comparisonOpcode(expr) or
1876+
result = spaceShipOpcode(expr)
18711877
}
18721878

18731879
override Type getExprType() {

cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1604,6 +1604,13 @@ class CompareGEInstruction extends RelationalInstruction {
16041604
override predicate isStrict() { none() }
16051605
}
16061606

1607+
/**
1608+
* An instruction that represents a three-way comparison operator.
1609+
*/
1610+
class SpaceshipInstruction extends BinaryInstruction {
1611+
SpaceshipInstruction() { this.getOpcode() instanceof Opcode::Spaceship }
1612+
}
1613+
16071614
/**
16081615
* An instruction that branches to one of multiple successor instructions based on the value of an
16091616
* integer operand.

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

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20336,26 +20336,55 @@ ir.cpp:
2033620336
# 2766| r2766_20(glval<ThreeWay>) = CopyValue : r2766_19
2033720337
# 2766| r2766_21(glval<int>) = FieldAddress[x] : r2766_20
2033820338
# 2766| r2766_22(int) = Load[?] : &:r2766_21, ~m2766_12
20339+
# 2766| r2766_23(strong_ordering) = Spaceship : r2766_17, r2766_22
20340+
# 2766| m2766_24(strong_ordering) = Store[#return] : &:r2766_13, r2766_23
20341+
# 2766| v2766_25(void) = ReturnIndirection[#this] : &:r2766_7, m2766_8
20342+
# 2766| v2766_26(void) = ReturnIndirection[y] : &:r2766_11, m2766_12
20343+
# 2766| r2766_27(glval<strong_ordering>) = VariableAddress[#return] :
20344+
# 2766| v2766_28(void) = ReturnValue : &:r2766_27, m2766_24
20345+
# 2766| v2766_29(void) = AliasedUse : m2766_3
20346+
# 2766| v2766_30(void) = ExitFunction :
2033920347

2034020348
# 2769| void test_three_way(int, int, ThreeWay, ThreeWay)
2034120349
# 2769| Block 0
20342-
# 2769| v2769_1(void) = EnterFunction :
20343-
# 2769| m2769_2(unknown) = AliasedDefinition :
20344-
# 2769| m2769_3(unknown) = InitializeNonLocal :
20345-
# 2769| m2769_4(unknown) = Chi : total:m2769_2, partial:m2769_3
20346-
# 2769| r2769_5(glval<int>) = VariableAddress[a] :
20347-
# 2769| m2769_6(int) = InitializeParameter[a] : &:r2769_5
20348-
# 2769| r2769_7(glval<int>) = VariableAddress[b] :
20349-
# 2769| m2769_8(int) = InitializeParameter[b] : &:r2769_7
20350-
# 2769| r2769_9(glval<ThreeWay>) = VariableAddress[c] :
20351-
# 2769| m2769_10(ThreeWay) = InitializeParameter[c] : &:r2769_9
20352-
# 2769| r2769_11(glval<ThreeWay>) = VariableAddress[d] :
20353-
# 2769| m2769_12(ThreeWay) = InitializeParameter[d] : &:r2769_11
20354-
# 2770| r2770_1(glval<strong_ordering>) = VariableAddress[x] :
20355-
# 2770| r2770_2(glval<int>) = VariableAddress[a] :
20356-
# 2770| r2770_3(int) = Load[a] : &:r2770_2, m2769_6
20357-
# 2770| r2770_4(glval<int>) = VariableAddress[b] :
20358-
# 2770| r2770_5(int) = Load[b] : &:r2770_4, m2769_8
20350+
# 2769| v2769_1(void) = EnterFunction :
20351+
# 2769| m2769_2(unknown) = AliasedDefinition :
20352+
# 2769| m2769_3(unknown) = InitializeNonLocal :
20353+
# 2769| m2769_4(unknown) = Chi : total:m2769_2, partial:m2769_3
20354+
# 2769| r2769_5(glval<int>) = VariableAddress[a] :
20355+
# 2769| m2769_6(int) = InitializeParameter[a] : &:r2769_5
20356+
# 2769| r2769_7(glval<int>) = VariableAddress[b] :
20357+
# 2769| m2769_8(int) = InitializeParameter[b] : &:r2769_7
20358+
# 2769| r2769_9(glval<ThreeWay>) = VariableAddress[c] :
20359+
# 2769| m2769_10(ThreeWay) = InitializeParameter[c] : &:r2769_9
20360+
# 2769| r2769_11(glval<ThreeWay>) = VariableAddress[d] :
20361+
# 2769| m2769_12(ThreeWay) = InitializeParameter[d] : &:r2769_11
20362+
# 2770| r2770_1(glval<strong_ordering>) = VariableAddress[x] :
20363+
# 2770| r2770_2(glval<int>) = VariableAddress[a] :
20364+
# 2770| r2770_3(int) = Load[a] : &:r2770_2, m2769_6
20365+
# 2770| r2770_4(glval<int>) = VariableAddress[b] :
20366+
# 2770| r2770_5(int) = Load[b] : &:r2770_4, m2769_8
20367+
# 2770| r2770_6(strong_ordering) = Spaceship : r2770_3, r2770_5
20368+
# 2770| m2770_7(strong_ordering) = Store[x] : &:r2770_1, r2770_6
20369+
# 2771| r2771_1(glval<strong_ordering>) = VariableAddress[y] :
20370+
# 2771| r2771_2(glval<ThreeWay>) = VariableAddress[c] :
20371+
# 2771| r2771_3(glval<unknown>) = FunctionAddress[operator<=>] :
20372+
# 2771| r2771_4(glval<ThreeWay>) = VariableAddress[d] :
20373+
# 2771| r2771_5(ThreeWay &) = CopyValue : r2771_4
20374+
# 2771| r2771_6(strong_ordering) = Call[operator<=>] : func:r2771_3, this:r2771_2, 0:r2771_5
20375+
# 2771| m2771_7(unknown) = ^CallSideEffect : ~m2769_4
20376+
# 2771| m2771_8(unknown) = Chi : total:m2769_4, partial:m2771_7
20377+
# 2771| v2771_9(void) = ^IndirectReadSideEffect[-1] : &:r2771_2, m2769_10
20378+
# 2771| v2771_10(void) = ^BufferReadSideEffect[0] : &:r2771_5, ~m2769_12
20379+
# 2771| m2771_11(ThreeWay) = ^IndirectMayWriteSideEffect[-1] : &:r2771_2
20380+
# 2771| m2771_12(ThreeWay) = Chi : total:m2769_10, partial:m2771_11
20381+
# 2771| m2771_13(unknown) = ^BufferMayWriteSideEffect[0] : &:r2771_5
20382+
# 2771| m2771_14(ThreeWay) = Chi : total:m2769_12, partial:m2771_13
20383+
# 2771| m2771_15(strong_ordering) = Store[y] : &:r2771_1, r2771_6
20384+
# 2772| v2772_1(void) = NoOp :
20385+
# 2769| v2769_13(void) = ReturnVoid :
20386+
# 2769| v2769_14(void) = AliasedUse : ~m2771_8
20387+
# 2769| v2769_15(void) = ExitFunction :
2035920388

2036020389
ir23.cpp:
2036120390
# 1| bool consteval_1()

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ missingOperandType
66
duplicateChiOperand
77
sideEffectWithoutPrimary
88
instructionWithoutSuccessor
9-
| ir.cpp:2766:72:2766:72 | Load: x | Instruction 'Load: x' has no successors in function '$@'. | ir.cpp:2766:24:2766:34 | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) |
10-
| ir.cpp:2770:18:2770:18 | Load: b | Instruction 'Load: b' has no successors in function '$@'. | ir.cpp:2769:6:2769:19 | void test_three_way(int, int, ThreeWay, ThreeWay) | void test_three_way(int, int, ThreeWay, ThreeWay) |
119
ambiguousSuccessors
1210
unexplainedLoop
1311
unnecessaryPhiInstruction

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ missingOperandType
66
duplicateChiOperand
77
sideEffectWithoutPrimary
88
instructionWithoutSuccessor
9-
| ir.cpp:2766:72:2766:72 | Load: x | Instruction 'Load: x' has no successors in function '$@'. | ir.cpp:2766:24:2766:34 | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) |
10-
| ir.cpp:2770:18:2770:18 | Load: b | Instruction 'Load: b' has no successors in function '$@'. | ir.cpp:2769:6:2769:19 | void test_three_way(int, int, ThreeWay, ThreeWay) | void test_three_way(int, int, ThreeWay, ThreeWay) |
119
ambiguousSuccessors
1210
unexplainedLoop
1311
unnecessaryPhiInstruction

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

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
11
missingOperand
2-
| ir.cpp:2766:58:2766:72 | Store: ... <=> ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:2766:24:2766:34 | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) |
3-
| ir.cpp:2770:12:2770:18 | Store: ... <=> ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:2769:6:2769:19 | void test_three_way(int, int, ThreeWay, ThreeWay) | void test_three_way(int, int, ThreeWay, ThreeWay) |
42
unexpectedOperand
53
duplicateOperand
64
missingPhiOperand
75
missingOperandType
86
duplicateChiOperand
97
sideEffectWithoutPrimary
108
instructionWithoutSuccessor
11-
| ir.cpp:2766:72:2766:72 | Load: x | Instruction 'Load: x' has no successors in function '$@'. | ir.cpp:2766:24:2766:34 | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) |
12-
| ir.cpp:2770:18:2770:18 | Load: b | Instruction 'Load: b' has no successors in function '$@'. | ir.cpp:2769:6:2769:19 | void test_three_way(int, int, ThreeWay, ThreeWay) | void test_three_way(int, int, ThreeWay, ThreeWay) |
139
ambiguousSuccessors
1410
unexplainedLoop
1511
unnecessaryPhiInstruction
@@ -25,10 +21,6 @@ lostReachability
2521
backEdgeCountMismatch
2622
useNotDominatedByDefinition
2723
| ir.cpp:1535:8:1535:8 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1535:8:1535:8 | void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct() | void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct() |
28-
| ir.cpp:2766:24:2766:34 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2766:24:2766:34 | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) |
29-
| ir.cpp:2766:46:2766:46 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2766:24:2766:34 | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) |
30-
| ir.cpp:2766:51:2766:73 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2766:24:2766:34 | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) |
31-
| ir.cpp:2770:8:2770:8 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2769:6:2769:19 | void test_three_way(int, int, ThreeWay, ThreeWay) | void test_three_way(int, int, ThreeWay, ThreeWay) |
3224
switchInstructionWithoutDefaultEdge
3325
notMarkedAsConflated
3426
wronglyMarkedAsConflated

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

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18492,37 +18492,35 @@ ir.cpp:
1849218492
# 2766| r2766_19(glval<ThreeWay>) = CopyValue : r2766_18
1849318493
# 2766| r2766_20(glval<int>) = FieldAddress[x] : r2766_19
1849418494
# 2766| r2766_21(int) = Load[?] : &:r2766_20, ~m?
18495-
18496-
# 2766| Block 1
18497-
# 2766| mu2766_22(strong_ordering) = Store[#return] : &:r2766_12
18498-
# 2766| v2766_23(void) = ReturnIndirection[#this] : &:r2766_6, ~m?
18499-
# 2766| v2766_24(void) = ReturnIndirection[y] : &:r2766_10, ~m?
18500-
# 2766| r2766_25(glval<strong_ordering>) = VariableAddress[#return] :
18501-
# 2766| v2766_26(void) = ReturnValue : &:r2766_25, ~m?
18502-
# 2766| v2766_27(void) = AliasedUse : ~m?
18503-
# 2766| v2766_28(void) = ExitFunction :
18495+
# 2766| r2766_22(strong_ordering) = Spaceship : r2766_16, r2766_21
18496+
# 2766| mu2766_23(strong_ordering) = Store[#return] : &:r2766_12, r2766_22
18497+
# 2766| v2766_24(void) = ReturnIndirection[#this] : &:r2766_6, ~m?
18498+
# 2766| v2766_25(void) = ReturnIndirection[y] : &:r2766_10, ~m?
18499+
# 2766| r2766_26(glval<strong_ordering>) = VariableAddress[#return] :
18500+
# 2766| v2766_27(void) = ReturnValue : &:r2766_26, ~m?
18501+
# 2766| v2766_28(void) = AliasedUse : ~m?
18502+
# 2766| v2766_29(void) = ExitFunction :
1850418503

1850518504
# 2769| void test_three_way(int, int, ThreeWay, ThreeWay)
1850618505
# 2769| Block 0
18507-
# 2769| v2769_1(void) = EnterFunction :
18508-
# 2769| mu2769_2(unknown) = AliasedDefinition :
18509-
# 2769| mu2769_3(unknown) = InitializeNonLocal :
18510-
# 2769| r2769_4(glval<int>) = VariableAddress[a] :
18511-
# 2769| mu2769_5(int) = InitializeParameter[a] : &:r2769_4
18512-
# 2769| r2769_6(glval<int>) = VariableAddress[b] :
18513-
# 2769| mu2769_7(int) = InitializeParameter[b] : &:r2769_6
18514-
# 2769| r2769_8(glval<ThreeWay>) = VariableAddress[c] :
18515-
# 2769| mu2769_9(ThreeWay) = InitializeParameter[c] : &:r2769_8
18516-
# 2769| r2769_10(glval<ThreeWay>) = VariableAddress[d] :
18517-
# 2769| mu2769_11(ThreeWay) = InitializeParameter[d] : &:r2769_10
18518-
# 2770| r2770_1(glval<strong_ordering>) = VariableAddress[x] :
18519-
# 2770| r2770_2(glval<int>) = VariableAddress[a] :
18520-
# 2770| r2770_3(int) = Load[a] : &:r2770_2, ~m?
18521-
# 2770| r2770_4(glval<int>) = VariableAddress[b] :
18522-
# 2770| r2770_5(int) = Load[b] : &:r2770_4, ~m?
18523-
18524-
# 2770| Block 1
18525-
# 2770| mu2770_6(strong_ordering) = Store[x] : &:r2770_1
18506+
# 2769| v2769_1(void) = EnterFunction :
18507+
# 2769| mu2769_2(unknown) = AliasedDefinition :
18508+
# 2769| mu2769_3(unknown) = InitializeNonLocal :
18509+
# 2769| r2769_4(glval<int>) = VariableAddress[a] :
18510+
# 2769| mu2769_5(int) = InitializeParameter[a] : &:r2769_4
18511+
# 2769| r2769_6(glval<int>) = VariableAddress[b] :
18512+
# 2769| mu2769_7(int) = InitializeParameter[b] : &:r2769_6
18513+
# 2769| r2769_8(glval<ThreeWay>) = VariableAddress[c] :
18514+
# 2769| mu2769_9(ThreeWay) = InitializeParameter[c] : &:r2769_8
18515+
# 2769| r2769_10(glval<ThreeWay>) = VariableAddress[d] :
18516+
# 2769| mu2769_11(ThreeWay) = InitializeParameter[d] : &:r2769_10
18517+
# 2770| r2770_1(glval<strong_ordering>) = VariableAddress[x] :
18518+
# 2770| r2770_2(glval<int>) = VariableAddress[a] :
18519+
# 2770| r2770_3(int) = Load[a] : &:r2770_2, ~m?
18520+
# 2770| r2770_4(glval<int>) = VariableAddress[b] :
18521+
# 2770| r2770_5(int) = Load[b] : &:r2770_4, ~m?
18522+
# 2770| r2770_6(strong_ordering) = Spaceship : r2770_3, r2770_5
18523+
# 2770| mu2770_7(strong_ordering) = Store[x] : &:r2770_1, r2770_6
1852618524
# 2771| r2771_1(glval<strong_ordering>) = VariableAddress[y] :
1852718525
# 2771| r2771_2(glval<ThreeWay>) = VariableAddress[c] :
1852818526
# 2771| r2771_3(glval<unknown>) = FunctionAddress[operator<=>] :

0 commit comments

Comments
 (0)