Skip to content

Commit 875daae

Browse files
authored
Merge pull request github#3151 from dbartol/dbartol/floats
C++: Better support for complex numbers in IR and AST
2 parents e965e5c + 8041b74 commit 875daae

File tree

16 files changed

+2690
-60
lines changed

16 files changed

+2690
-60
lines changed

cpp/ql/src/semmle/code/cpp/Type.qll

Lines changed: 181 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -697,28 +697,188 @@ class Int128Type extends IntegralType {
697697
override string getCanonicalQLClass() { result = "Int128Type" }
698698
}
699699

700+
private newtype TTypeDomain =
701+
TRealDomain() or
702+
TComplexDomain() or
703+
TImaginaryDomain()
704+
700705
/**
701-
* The C/C++ floating point types. See 4.5. This includes `float`,
702-
* `double` and `long double` types.
703-
* ```
704-
* float f;
705-
* double d;
706-
* long double ld;
707-
* ```
706+
* The type ___domain of a floating-point type. One of `RealDomain`, `ComplexDomain`, or
707+
* `ImaginaryDomain`.
708+
*/
709+
class TypeDomain extends TTypeDomain {
710+
/** Gets a textual representation of this type ___domain. */
711+
string toString() { none() }
712+
}
713+
714+
/**
715+
* The type ___domain of a floating-point type that represents a real number.
716+
*/
717+
class RealDomain extends TypeDomain, TRealDomain {
718+
final override string toString() { result = "real" }
719+
}
720+
721+
/**
722+
* The type ___domain of a floating-point type that represents a complex number.
723+
*/
724+
class ComplexDomain extends TypeDomain, TComplexDomain {
725+
final override string toString() { result = "complex" }
726+
}
727+
728+
/**
729+
* The type ___domain of a floating-point type that represents an imaginary number.
730+
*/
731+
class ImaginaryDomain extends TypeDomain, TImaginaryDomain {
732+
final override string toString() { result = "imaginary" }
733+
}
734+
735+
/**
736+
* Data for floating-point types.
737+
*
738+
* kind: The original type kind. Can be any floating-point type kind.
739+
* base: The numeric base of the number's representation. Can be 2 (binary) or 10 (decimal).
740+
* ___domain: The type ___domain of the type. Can be `RealDomain`, `ComplexDomain`, or `ImaginaryDomain`.
741+
* realKind: The type kind of the corresponding real type. For example, the corresponding real type
742+
* of `_Complex double` is `double`.
743+
* extended: `true` if the number is an extended-precision floating-point number, such as
744+
* `_Float32x`.
745+
*/
746+
private predicate floatingPointTypeMapping(
747+
int kind, int base, TTypeDomain ___domain, int realKind, boolean extended
748+
) {
749+
// float
750+
kind = 24 and base = 2 and ___domain = TRealDomain() and realKind = 24 and extended = false
751+
or
752+
// double
753+
kind = 25 and base = 2 and ___domain = TRealDomain() and realKind = 25 and extended = false
754+
or
755+
// long double
756+
kind = 26 and base = 2 and ___domain = TRealDomain() and realKind = 26 and extended = false
757+
or
758+
// _Complex float
759+
kind = 27 and base = 2 and ___domain = TComplexDomain() and realKind = 24 and extended = false
760+
or
761+
// _Complex double
762+
kind = 28 and base = 2 and ___domain = TComplexDomain() and realKind = 25 and extended = false
763+
or
764+
// _Complex long double
765+
kind = 29 and base = 2 and ___domain = TComplexDomain() and realKind = 26 and extended = false
766+
or
767+
// _Imaginary float
768+
kind = 30 and base = 2 and ___domain = TImaginaryDomain() and realKind = 24 and extended = false
769+
or
770+
// _Imaginary double
771+
kind = 31 and base = 2 and ___domain = TImaginaryDomain() and realKind = 25 and extended = false
772+
or
773+
// _Imaginary long double
774+
kind = 32 and base = 2 and ___domain = TImaginaryDomain() and realKind = 26 and extended = false
775+
or
776+
// __float128
777+
kind = 38 and base = 2 and ___domain = TRealDomain() and realKind = 38 and extended = false
778+
or
779+
// _Complex __float128
780+
kind = 39 and base = 2 and ___domain = TComplexDomain() and realKind = 38 and extended = false
781+
or
782+
// _Decimal32
783+
kind = 40 and base = 10 and ___domain = TRealDomain() and realKind = 40 and extended = false
784+
or
785+
// _Decimal64
786+
kind = 41 and base = 10 and ___domain = TRealDomain() and realKind = 41 and extended = false
787+
or
788+
// _Decimal128
789+
kind = 42 and base = 10 and ___domain = TRealDomain() and realKind = 42 and extended = false
790+
or
791+
// _Float32
792+
kind = 45 and base = 2 and ___domain = TRealDomain() and realKind = 45 and extended = false
793+
or
794+
// _Float32x
795+
kind = 46 and base = 2 and ___domain = TRealDomain() and realKind = 46 and extended = true
796+
or
797+
// _Float64
798+
kind = 47 and base = 2 and ___domain = TRealDomain() and realKind = 47 and extended = false
799+
or
800+
// _Float64x
801+
kind = 48 and base = 2 and ___domain = TRealDomain() and realKind = 48 and extended = true
802+
or
803+
// _Float128
804+
kind = 49 and base = 2 and ___domain = TRealDomain() and realKind = 49 and extended = false
805+
or
806+
// _Float128x
807+
kind = 50 and base = 2 and ___domain = TRealDomain() and realKind = 50 and extended = true
808+
}
809+
810+
/**
811+
* The C/C++ floating point types. See 4.5. This includes `float`, `double` and `long double`, the
812+
* fixed-size floating-point types like `_Float32`, the extended-precision floating-point types like
813+
* `_Float64x`, and the decimal floating-point types like `_Decimal32`. It also includes the complex
814+
* and imaginary versions of all of these types.
708815
*/
709816
class FloatingPointType extends ArithmeticType {
817+
final int base;
818+
final TypeDomain ___domain;
819+
final int realKind;
820+
final boolean extended;
821+
710822
FloatingPointType() {
711823
exists(int kind |
712824
builtintypes(underlyingElement(this), _, kind, _, _, _) and
713-
(
714-
kind >= 24 and kind <= 32
715-
or
716-
kind >= 38 and kind <= 42
717-
or
718-
kind >= 45 and kind <= 50
719-
)
825+
floatingPointTypeMapping(kind, base, ___domain, realKind, extended)
720826
)
721827
}
828+
829+
/** Gets the numeric base of this type's representation: 2 (binary) or 10 (decimal). */
830+
final int getBase() { result = base }
831+
832+
/**
833+
* Gets the type ___domain of this type. Can be `RealDomain`, `ComplexDomain`, or `ImaginaryDomain`.
834+
*/
835+
final TypeDomain getDomain() { result = ___domain }
836+
837+
/**
838+
* Gets the corresponding real type of this type. For example, the corresponding real type of
839+
* `_Complex double` is `double`.
840+
*/
841+
final RealNumberType getRealType() {
842+
builtintypes(unresolveElement(result), _, realKind, _, _, _)
843+
}
844+
845+
/** Holds if this type is an extended precision floating-point type, such as `_Float32x`. */
846+
final predicate isExtendedPrecision() { extended = true }
847+
}
848+
849+
/**
850+
* A floating-point type representing a real number.
851+
*/
852+
class RealNumberType extends FloatingPointType {
853+
RealNumberType() { ___domain instanceof RealDomain }
854+
}
855+
856+
/**
857+
* A floating-point type representing a complex number.
858+
*/
859+
class ComplexNumberType extends FloatingPointType {
860+
ComplexNumberType() { ___domain instanceof ComplexDomain }
861+
}
862+
863+
/**
864+
* A floating-point type representing an imaginary number.
865+
*/
866+
class ImaginaryNumberType extends FloatingPointType {
867+
ImaginaryNumberType() { ___domain instanceof ImaginaryDomain }
868+
}
869+
870+
/**
871+
* A floating-point type whose representation is base 2.
872+
*/
873+
class BinaryFloatingPointType extends FloatingPointType {
874+
BinaryFloatingPointType() { base = 2 }
875+
}
876+
877+
/**
878+
* A floating-point type whose representation is base 10.
879+
*/
880+
class DecimalFloatingPointType extends FloatingPointType {
881+
DecimalFloatingPointType() { base = 10 }
722882
}
723883

724884
/**
@@ -727,7 +887,7 @@ class FloatingPointType extends ArithmeticType {
727887
* float f;
728888
* ```
729889
*/
730-
class FloatType extends FloatingPointType {
890+
class FloatType extends RealNumberType, BinaryFloatingPointType {
731891
FloatType() { builtintypes(underlyingElement(this), _, 24, _, _, _) }
732892

733893
override string getCanonicalQLClass() { result = "FloatType" }
@@ -739,7 +899,7 @@ class FloatType extends FloatingPointType {
739899
* double d;
740900
* ```
741901
*/
742-
class DoubleType extends FloatingPointType {
902+
class DoubleType extends RealNumberType, BinaryFloatingPointType {
743903
DoubleType() { builtintypes(underlyingElement(this), _, 25, _, _, _) }
744904

745905
override string getCanonicalQLClass() { result = "DoubleType" }
@@ -751,7 +911,7 @@ class DoubleType extends FloatingPointType {
751911
* long double ld;
752912
* ```
753913
*/
754-
class LongDoubleType extends FloatingPointType {
914+
class LongDoubleType extends RealNumberType, BinaryFloatingPointType {
755915
LongDoubleType() { builtintypes(underlyingElement(this), _, 26, _, _, _) }
756916

757917
override string getCanonicalQLClass() { result = "LongDoubleType" }
@@ -763,7 +923,7 @@ class LongDoubleType extends FloatingPointType {
763923
* __float128 f128;
764924
* ```
765925
*/
766-
class Float128Type extends FloatingPointType {
926+
class Float128Type extends RealNumberType, BinaryFloatingPointType {
767927
Float128Type() { builtintypes(underlyingElement(this), _, 38, _, _, _) }
768928

769929
override string getCanonicalQLClass() { result = "Float128Type" }
@@ -775,7 +935,7 @@ class Float128Type extends FloatingPointType {
775935
* _Decimal32 d32;
776936
* ```
777937
*/
778-
class Decimal32Type extends FloatingPointType {
938+
class Decimal32Type extends RealNumberType, DecimalFloatingPointType {
779939
Decimal32Type() { builtintypes(underlyingElement(this), _, 40, _, _, _) }
780940

781941
override string getCanonicalQLClass() { result = "Decimal32Type" }
@@ -787,7 +947,7 @@ class Decimal32Type extends FloatingPointType {
787947
* _Decimal64 d64;
788948
* ```
789949
*/
790-
class Decimal64Type extends FloatingPointType {
950+
class Decimal64Type extends RealNumberType, DecimalFloatingPointType {
791951
Decimal64Type() { builtintypes(underlyingElement(this), _, 41, _, _, _) }
792952

793953
override string getCanonicalQLClass() { result = "Decimal64Type" }
@@ -799,7 +959,7 @@ class Decimal64Type extends FloatingPointType {
799959
* _Decimal128 d128;
800960
* ```
801961
*/
802-
class Decimal128Type extends FloatingPointType {
962+
class Decimal128Type extends RealNumberType, DecimalFloatingPointType {
803963
Decimal128Type() { builtintypes(underlyingElement(this), _, 42, _, _, _) }
804964

805965
override string getCanonicalQLClass() { result = "Decimal128Type" }

cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ private newtype TIRType =
1212
TIRBooleanType(int byteSize) { Language::hasBooleanType(byteSize) } or
1313
TIRSignedIntegerType(int byteSize) { Language::hasSignedIntegerType(byteSize) } or
1414
TIRUnsignedIntegerType(int byteSize) { Language::hasUnsignedIntegerType(byteSize) } or
15-
TIRFloatingPointType(int byteSize) { Language::hasFloatingPointType(byteSize) } or
15+
TIRFloatingPointType(int byteSize, int base, Language::TypeDomain ___domain) {
16+
Language::hasFloatingPointType(byteSize, base, ___domain)
17+
} or
1618
TIRAddressType(int byteSize) { Language::hasAddressType(byteSize) } or
1719
TIRFunctionAddressType(int byteSize) { Language::hasFunctionAddressType(byteSize) } or
1820
TIROpaqueType(Language::OpaqueTypeTag tag, int byteSize) {
@@ -104,7 +106,7 @@ private class IRSizedType extends IRType {
104106
this = TIRBooleanType(byteSize) or
105107
this = TIRSignedIntegerType(byteSize) or
106108
this = TIRUnsignedIntegerType(byteSize) or
107-
this = TIRFloatingPointType(byteSize) or
109+
this = TIRFloatingPointType(byteSize, _, _) or
108110
this = TIRAddressType(byteSize) or
109111
this = TIRFunctionAddressType(byteSize) or
110112
this = TIROpaqueType(_, byteSize)
@@ -133,7 +135,7 @@ class IRNumericType extends IRSizedType {
133135
IRNumericType() {
134136
this = TIRSignedIntegerType(byteSize) or
135137
this = TIRUnsignedIntegerType(byteSize) or
136-
this = TIRFloatingPointType(byteSize)
138+
this = TIRFloatingPointType(byteSize, _, _)
137139
}
138140
}
139141

@@ -171,14 +173,43 @@ class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType {
171173
* A floating-point type.
172174
*/
173175
class IRFloatingPointType extends IRNumericType, TIRFloatingPointType {
174-
final override string toString() { result = "float" + byteSize.toString() }
176+
final private int base;
177+
final private Language::TypeDomain ___domain;
178+
179+
IRFloatingPointType() { this = TIRFloatingPointType(_, base, ___domain) }
180+
181+
final override string toString() {
182+
result = getDomainPrefix() + getBaseString() + byteSize.toString()
183+
}
175184

176185
final override Language::LanguageType getCanonicalLanguageType() {
177-
result = Language::getCanonicalFloatingPointType(byteSize)
186+
result = Language::getCanonicalFloatingPointType(byteSize, base, ___domain)
178187
}
179188

180189
pragma[noinline]
181190
final override int getByteSize() { result = byteSize }
191+
192+
/** Gets the numeric base of the type. Can be either 2 (binary) or 10 (decimal). */
193+
final int getBase() { result = base }
194+
195+
/**
196+
* Gets the type ___domain of the type. Can be `RealDomain`, `ComplexDomain`, or `ImaginaryDomain`.
197+
*/
198+
final Language::TypeDomain getDomain() { result = ___domain }
199+
200+
private string getBaseString() {
201+
base = 2 and result = "float"
202+
or
203+
base = 10 and result = "decimal"
204+
}
205+
206+
private string getDomainPrefix() {
207+
___domain instanceof Language::RealDomain and result = ""
208+
or
209+
___domain instanceof Language::ComplexDomain and result = "c"
210+
or
211+
___domain instanceof Language::ImaginaryDomain and result = "i"
212+
}
182213
}
183214

184215
/**

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

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,13 +1100,36 @@ private Opcode binaryBitwiseOpcode(BinaryBitwiseOperation expr) {
11001100
}
11011101

11021102
private Opcode binaryArithmeticOpcode(BinaryArithmeticOperation expr) {
1103-
expr instanceof AddExpr and result instanceof Opcode::Add
1103+
(
1104+
expr instanceof AddExpr
1105+
or
1106+
expr instanceof ImaginaryRealAddExpr
1107+
or
1108+
expr instanceof RealImaginaryAddExpr
1109+
) and
1110+
result instanceof Opcode::Add
11041111
or
1105-
expr instanceof SubExpr and result instanceof Opcode::Sub
1112+
(
1113+
expr instanceof SubExpr
1114+
or
1115+
expr instanceof ImaginaryRealSubExpr
1116+
or
1117+
expr instanceof RealImaginarySubExpr
1118+
) and
1119+
result instanceof Opcode::Sub
11061120
or
1107-
expr instanceof MulExpr and result instanceof Opcode::Mul
1121+
(
1122+
expr instanceof MulExpr
1123+
or
1124+
expr instanceof ImaginaryMulExpr
1125+
) and
1126+
result instanceof Opcode::Mul
11081127
or
1109-
expr instanceof DivExpr and result instanceof Opcode::Div
1128+
(
1129+
expr instanceof DivExpr or
1130+
expr instanceof ImaginaryDivExpr
1131+
) and
1132+
result instanceof Opcode::Div
11101133
or
11111134
expr instanceof RemExpr and result instanceof Opcode::Rem
11121135
or

0 commit comments

Comments
 (0)