Skip to content

Commit c3a6ca0

Browse files
author
Dave Bartolomeo
committed
C++: Better support for complex numbers in IR and AST
This PR adds better support for differentiating complex and imaginary floating-point types from real floating-point types, in both the AST and in the IR type system. *AST Changes* - Introduces the new class `TypeDomain`, which can be either `RealDomain`, `ImaginaryDomain` or `ComplexDomain`. "type domain" is the term used for this concept in the C standard, and I couldn't think of a better one. - Introduces `FloatingPointType.getDomain()`, to get the type domain of the type. - Introduces `FloatingPointType.getBase()`, to get the numeric base of the type (either 2 or 10). - Introduces three new subtypes of `FloatingPointType`: `RealNumberType`, `ComplexNumberType`, and `ImaginaryNumberType`, which differentiate between the types based on their type domain. Note that the decimal types (e.g., `_Decimal32`) are included in `RealNumberType`. - Introduces two new subtypes of `FloatingPointType`: `BinaryFloatingPointType` and `DecimalFloatingPointType`, which differentiate between the types based on their numeric base, independent of type domain. *IR Changes* - `IRFloatingPointType` now has two additional parameters: the base and the type domain. - New test that ensures that C++ types get mapped to the correct IR types. - New IR test that verifies the IR for some basic usage of complex FP types.
1 parent 1baf5df commit c3a6ca0

File tree

14 files changed

+525
-43
lines changed

14 files changed

+525
-43
lines changed

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

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

724883
/**
@@ -727,7 +886,7 @@ class FloatingPointType extends ArithmeticType {
727886
* float f;
728887
* ```
729888
*/
730-
class FloatType extends FloatingPointType {
889+
class FloatType extends RealNumberType, BinaryFloatingPointType {
731890
FloatType() { builtintypes(underlyingElement(this), _, 24, _, _, _) }
732891

733892
override string getCanonicalQLClass() { result = "FloatType" }
@@ -739,7 +898,7 @@ class FloatType extends FloatingPointType {
739898
* double d;
740899
* ```
741900
*/
742-
class DoubleType extends FloatingPointType {
901+
class DoubleType extends RealNumberType, BinaryFloatingPointType {
743902
DoubleType() { builtintypes(underlyingElement(this), _, 25, _, _, _) }
744903

745904
override string getCanonicalQLClass() { result = "DoubleType" }
@@ -751,7 +910,7 @@ class DoubleType extends FloatingPointType {
751910
* long double ld;
752911
* ```
753912
*/
754-
class LongDoubleType extends FloatingPointType {
913+
class LongDoubleType extends RealNumberType, BinaryFloatingPointType {
755914
LongDoubleType() { builtintypes(underlyingElement(this), _, 26, _, _, _) }
756915

757916
override string getCanonicalQLClass() { result = "LongDoubleType" }
@@ -763,7 +922,7 @@ class LongDoubleType extends FloatingPointType {
763922
* __float128 f128;
764923
* ```
765924
*/
766-
class Float128Type extends FloatingPointType {
925+
class Float128Type extends RealNumberType, BinaryFloatingPointType {
767926
Float128Type() { builtintypes(underlyingElement(this), _, 38, _, _, _) }
768927

769928
override string getCanonicalQLClass() { result = "Float128Type" }
@@ -775,7 +934,7 @@ class Float128Type extends FloatingPointType {
775934
* _Decimal32 d32;
776935
* ```
777936
*/
778-
class Decimal32Type extends FloatingPointType {
937+
class Decimal32Type extends RealNumberType, DecimalFloatingPointType {
779938
Decimal32Type() { builtintypes(underlyingElement(this), _, 40, _, _, _) }
780939

781940
override string getCanonicalQLClass() { result = "Decimal32Type" }
@@ -787,7 +946,7 @@ class Decimal32Type extends FloatingPointType {
787946
* _Decimal64 d64;
788947
* ```
789948
*/
790-
class Decimal64Type extends FloatingPointType {
949+
class Decimal64Type extends RealNumberType, DecimalFloatingPointType {
791950
Decimal64Type() { builtintypes(underlyingElement(this), _, 41, _, _, _) }
792951

793952
override string getCanonicalQLClass() { result = "Decimal64Type" }
@@ -799,7 +958,7 @@ class Decimal64Type extends FloatingPointType {
799958
* _Decimal128 d128;
800959
* ```
801960
*/
802-
class Decimal128Type extends FloatingPointType {
961+
class Decimal128Type extends RealNumberType, DecimalFloatingPointType {
803962
Decimal128Type() { builtintypes(underlyingElement(this), _, 42, _, _, _) }
804963

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

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

Lines changed: 38 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,45 @@ 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+
private final int base;
177+
private final Language::TypeDomain domain;
178+
179+
IRFloatingPointType() {
180+
this = TIRFloatingPointType(_, base, domain)
181+
}
182+
183+
final override string toString() {
184+
result = getDomainPrefix() + getBaseString() + byteSize.toString()
185+
}
175186

176187
final override Language::LanguageType getCanonicalLanguageType() {
177-
result = Language::getCanonicalFloatingPointType(byteSize)
188+
result = Language::getCanonicalFloatingPointType(byteSize, base, domain)
178189
}
179190

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

184217
/**

0 commit comments

Comments
 (0)