diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index 058e335928aa..749f44aa907f 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -270,13 +270,20 @@ def FPAttr : CIR_Attr<"FP", "fp", [TypedAttrInterface]> { let summary = "An attribute containing a floating-point value"; let description = [{ An fp attribute is a literal attribute that represents a floating-point - value of the specified floating-point type. + value of the specified floating-point type. Supporting only CIR FP types. }]; - let parameters = (ins AttributeSelfTypeParameter<"">:$type, "APFloat":$value); + let parameters = (ins + AttributeSelfTypeParameter<"", "::mlir::cir::CIRFPTypeInterface">:$type, + APFloatParameter<"">:$value + ); let builders = [ AttrBuilderWithInferredContext<(ins "Type":$type, "const APFloat &":$value), [{ - return $_get(type.getContext(), type, value); + return $_get(type.getContext(), type.cast(), value); + }]>, + AttrBuilder<(ins "Type":$type, + "const APFloat &":$value), [{ + return $_get($_ctxt, type.cast(), value); }]>, ]; let extraClassDeclaration = [{ diff --git a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp index 79577e10fca9..8afb7ff56ea0 100644 --- a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp @@ -42,7 +42,8 @@ static void printFloatLiteral(mlir::AsmPrinter &p, llvm::APFloat value, mlir::Type ty); static mlir::ParseResult parseFloatLiteral(mlir::AsmParser &parser, - mlir::FailureOr &value, mlir::Type ty); + mlir::FailureOr &value, + mlir::cir::CIRFPTypeInterface fpType); static mlir::ParseResult parseConstPtr(mlir::AsmParser &parser, mlir::IntegerAttr &value); @@ -311,50 +312,30 @@ LogicalResult IntAttr::verify(function_ref emitError, // FPAttr definitions //===----------------------------------------------------------------------===// -static void printFloatLiteral(mlir::AsmPrinter &p, llvm::APFloat value, - mlir::Type ty) { +static void printFloatLiteral(AsmPrinter &p, APFloat value, Type ty) { p << value; } -static mlir::ParseResult -parseFloatLiteral(mlir::AsmParser &parser, - mlir::FailureOr &value, mlir::Type ty) { - double rawValue; - if (parser.parseFloat(rawValue)) { - return parser.emitError(parser.getCurrentLocation(), - "expected floating-point value"); - } - - auto losesInfo = false; - value.emplace(rawValue); +static ParseResult parseFloatLiteral(AsmParser &parser, + FailureOr &value, + CIRFPTypeInterface fpType) { - auto tyFpInterface = dyn_cast(ty); - if (!tyFpInterface) { - // Parsing of the current floating-point literal has succeeded, but the - // given attribute type is invalid. This error will be reported later when - // the attribute is being verified. - return success(); - } + APFloat parsedValue(0.0); + if (parser.parseFloat(fpType.getFloatSemantics(), parsedValue)) + return failure(); - value->convert(tyFpInterface.getFloatSemantics(), - llvm::RoundingMode::TowardZero, &losesInfo); + value.emplace(parsedValue); return success(); } -cir::FPAttr cir::FPAttr::getZero(mlir::Type type) { - return get( - type, APFloat::getZero( - mlir::cast(type).getFloatSemantics())); +FPAttr FPAttr::getZero(Type type) { + return get(type, APFloat::getZero( + type.cast().getFloatSemantics())); } -LogicalResult cir::FPAttr::verify(function_ref emitError, - Type type, APFloat value) { - auto fltTypeInterface = mlir::dyn_cast(type); - if (!fltTypeInterface) { - emitError() << "expected floating-point type"; - return failure(); - } - if (APFloat::SemanticsToEnum(fltTypeInterface.getFloatSemantics()) != +LogicalResult FPAttr::verify(function_ref emitError, + CIRFPTypeInterface fpType, APFloat value) { + if (APFloat::SemanticsToEnum(fpType.getFloatSemantics()) != APFloat::SemanticsToEnum(value.getSemantics())) { emitError() << "floating-point semantics mismatch"; return failure(); diff --git a/clang/test/CIR/IR/attribute.cir b/clang/test/CIR/IR/attribute.cir new file mode 100644 index 000000000000..4c9d4083ad4a --- /dev/null +++ b/clang/test/CIR/IR/attribute.cir @@ -0,0 +1,25 @@ +// RUN: cir-opt %s -split-input-file -allow-unregistered-dialect -verify-diagnostics | FileCheck %s + +cir.func @float_attrs_pass() { + "test.float_attrs"() { + // CHECK: float_attr = #cir.fp<2.000000e+00> : !cir.float + float_attr = #cir.fp<2.> : !cir.float + } : () -> () + "test.float_attrs"() { + // CHECK: float_attr = #cir.fp<-2.000000e+00> : !cir.float + float_attr = #cir.fp<-2.> : !cir.float + } : () -> () + "test.float_attrs"() { + // CHECK: float_attr = #cir.fp<2.000000e+00> : !cir.double + float_attr = #cir.fp<2.> : !cir.double + } : () -> () + "test.float_attrs"() { + // CHECK: float_attr = #cir.fp<2.000000e+00> : !cir.long_double + float_attr = #cir.fp<2.> : !cir.long_double + } : () -> () + "test.float_attrs"() { + // CHECK: float_attr = #cir.fp<2.000000e+00> : !cir.long_double + float_attr = #cir.fp<2.> : !cir.long_double + } : () -> () + cir.return +} \ No newline at end of file diff --git a/clang/test/CIR/IR/float.cir b/clang/test/CIR/IR/float.cir new file mode 100644 index 000000000000..13aeb2d97261 --- /dev/null +++ b/clang/test/CIR/IR/float.cir @@ -0,0 +1,90 @@ +// RUN: cir-opt %s | FileCheck %s + +// Adapted from mlir/test/IR/parser.mlir + +// CHECK-LABEL: @f32_special_values +cir.func @f32_special_values() { + // F32 signaling NaNs. + // CHECK: cir.const(#cir.fp<0x7F800001> : !cir.float) : !cir.float + %0 = cir.const(#cir.fp<0x7F800001> : !cir.float) : !cir.float + // CHECK: cir.const(#cir.fp<0x7FBFFFFF> : !cir.float) : !cir.float + %1 = cir.const(#cir.fp<0x7FBFFFFF> : !cir.float) : !cir.float + + // F32 quiet NaNs. + // CHECK: cir.const(#cir.fp<0x7FC00000> : !cir.float) : !cir.float + %2 = cir.const(#cir.fp<0x7FC00000> : !cir.float) : !cir.float + // CHECK: cir.const(#cir.fp<0xFFFFFFFF> : !cir.float) : !cir.float + %3 = cir.const(#cir.fp<0xFFFFFFFF> : !cir.float) : !cir.float + + // F32 positive infinity. + // CHECK: cir.const(#cir.fp<0x7F800000> : !cir.float) : !cir.float + %4 = cir.const(#cir.fp<0x7F800000> : !cir.float) : !cir.float + // F32 negative infinity. + // CHECK: cir.const(#cir.fp<0xFF800000> : !cir.float) : !cir.float + %5 = cir.const(#cir.fp<0xFF800000> : !cir.float) : !cir.float + + cir.return +} + +// CHECK-LABEL: @f64_special_values +cir.func @f64_special_values() { + // F64 signaling NaNs. + // CHECK: cir.const(#cir.fp<0x7FF0000000000001> : !cir.double) : !cir.double + %0 = cir.const(#cir.fp<0x7FF0000000000001> : !cir.double) : !cir.double + // CHECK: cir.const(#cir.fp<0x7FF8000000000000> : !cir.double) : !cir.double + %1 = cir.const(#cir.fp<0x7FF8000000000000> : !cir.double) : !cir.double + + // F64 quiet NaNs. + // CHECK: cir.const(#cir.fp<0x7FF0000001000000> : !cir.double) : !cir.double + %2 = cir.const(#cir.fp<0x7FF0000001000000> : !cir.double) : !cir.double + // CHECK: cir.const(#cir.fp<0xFFF0000001000000> : !cir.double) : !cir.double + %3 = cir.const(#cir.fp<0xFFF0000001000000> : !cir.double) : !cir.double + + // F64 positive infinity. + // CHECK: cir.const(#cir.fp<0x7FF0000000000000> : !cir.double) : !cir.double + %4 = cir.const(#cir.fp<0x7FF0000000000000> : !cir.double) : !cir.double + // F64 negative infinity. + // CHECK: cir.const(#cir.fp<0xFFF0000000000000> : !cir.double) : !cir.double + %5 = cir.const(#cir.fp<0xFFF0000000000000> : !cir.double) : !cir.double + + // Check that values that can't be represented with the default format, use + // hex instead. + // CHECK: cir.const(#cir.fp<0xC1CDC00000000000> : !cir.double) : !cir.double + %6 = cir.const(#cir.fp<0xC1CDC00000000000> : !cir.double) : !cir.double + + cir.return +} + +// CHECK-LABEL: @f80_special_values +cir.func @f80_special_values() { + // F80 signaling NaNs. + // CHECK: cir.const(#cir.fp<0x7FFFE000000000000001> : !cir.long_double) : !cir.long_double + %0 = cir.const(#cir.fp<0x7FFFE000000000000001> : !cir.long_double) : !cir.long_double + // CHECK: cir.const(#cir.fp<0x7FFFB000000000000011> : !cir.long_double) : !cir.long_double + %1 = cir.const(#cir.fp<0x7FFFB000000000000011> : !cir.long_double) : !cir.long_double + + // F80 quiet NaNs. + // CHECK: cir.const(#cir.fp<0x7FFFC000000000100000> : !cir.long_double) : !cir.long_double + %2 = cir.const(#cir.fp<0x7FFFC000000000100000> : !cir.long_double) : !cir.long_double + // CHECK: cir.const(#cir.fp<0x7FFFE000000001000000> : !cir.long_double) : !cir.long_double + %3 = cir.const(#cir.fp<0x7FFFE000000001000000> : !cir.long_double) : !cir.long_double + + // F80 positive infinity. + // CHECK: cir.const(#cir.fp<0x7FFF8000000000000000> : !cir.long_double) : !cir.long_double + %4 = cir.const(#cir.fp<0x7FFF8000000000000000> : !cir.long_double) : !cir.long_double + // F80 negative infinity. + // CHECK: cir.const(#cir.fp<0xFFFF8000000000000000> : !cir.long_double) : !cir.long_double + %5 = cir.const(#cir.fp<0xFFFF8000000000000000> : !cir.long_double) : !cir.long_double + + cir.return +} + +// We want to print floats in exponential notation with 6 significant digits, +// but it may lead to precision loss when parsing back, in which case we print +// the decimal form instead. +// CHECK-LABEL: @f32_potential_precision_loss() +cir.func @f32_potential_precision_loss() { + // CHECK: cir.const(#cir.fp<1.23697901> : !cir.float) : !cir.float + %0 = cir.const(#cir.fp<1.23697901> : !cir.float) : !cir.float + cir.return +} diff --git a/clang/test/CIR/IR/invalid.cir b/clang/test/CIR/IR/invalid.cir index 9df6e0c858fb..316ac3080797 100644 --- a/clang/test/CIR/IR/invalid.cir +++ b/clang/test/CIR/IR/invalid.cir @@ -1378,3 +1378,62 @@ module { cir.return } } +// ----- + +// Type of the attribute must be a CIR floating point type + +// expected-error @below {{invalid kind of type specified}} +cir.global external @f = #cir.fp<0.5> : !cir.int + +// ----- + +// Value must be a floating point literal or integer literal + +// expected-error @below {{expected floating point literal}} +cir.global external @f = #cir.fp<"blabla"> : !cir.float + +// ----- + +// Integer value must be in the width of the floating point type + +// expected-error @below {{hexadecimal float constant out of range for type}} +cir.global external @f = #cir.fp<0x7FC000000> : !cir.float + +// ----- + +// Integer value must be in the width of the floating point type + +// expected-error @below {{hexadecimal float constant out of range for type}} +cir.global external @f = #cir.fp<0x7FC000007FC0000000> : !cir.double + +// ----- + +// Integer value must be in the width of the floating point type + +// expected-error @below {{hexadecimal float constant out of range for type}} +cir.global external @f = #cir.fp<0x7FC0000007FC0000007FC000000> : !cir.long_double + +// ----- + +// Long double with `double` semnatics should have a value that fits in a double. + +// CHECK: cir.global external @f = #cir.fp<0x7FC000007FC000000000> : !cir.long_double +cir.global external @f = #cir.fp<0x7FC000007FC000000000> : !cir.long_double + +// expected-error @below {{hexadecimal float constant out of range for type}} +cir.global external @f = #cir.fp<0x7FC000007FC000000000> : !cir.long_double + +// ----- + +// Verify no need for type inside the attribute + +// expected-error @below {{expected '>'}} +cir.global external @f = #cir.fp<0x7FC00000 : !cir.float> : !cir.float + +// ----- + +// Verify literal must be hex or float + +// expected-error @below {{unexpected decimal integer literal for a floating point value}} +// expected-note @below {{add a trailing dot to make the literal a float}} +cir.global external @f = #cir.fp<42> : !cir.float diff --git a/clang/test/CIR/Lowering/class.cir b/clang/test/CIR/Lowering/class.cir index dd028f4c3b7d..4f0c25151179 100644 --- a/clang/test/CIR/Lowering/class.cir +++ b/clang/test/CIR/Lowering/class.cir @@ -44,7 +44,7 @@ module { // CHECK: %0 = llvm.mlir.undef : !llvm.struct<"class.S1", (i32, f32, ptr)> // CHECK: %1 = llvm.mlir.constant(1 : i32) : i32 // CHECK: %2 = llvm.insertvalue %1, %0[0] : !llvm.struct<"class.S1", (i32, f32, ptr)> - // CHECK: %3 = llvm.mlir.constant(0.099999994 : f32) : f32 + // CHECK: %3 = llvm.mlir.constant(1.000000e-01 : f32) : f32 // CHECK: %4 = llvm.insertvalue %3, %2[1] : !llvm.struct<"class.S1", (i32, f32, ptr)> // CHECK: %5 = llvm.mlir.zero : !llvm.ptr // CHECK: %6 = llvm.insertvalue %5, %4[2] : !llvm.struct<"class.S1", (i32, f32, ptr)> diff --git a/clang/test/CIR/Lowering/struct.cir b/clang/test/CIR/Lowering/struct.cir index a1a3d352c8a1..c89a58a9772e 100644 --- a/clang/test/CIR/Lowering/struct.cir +++ b/clang/test/CIR/Lowering/struct.cir @@ -44,7 +44,7 @@ module { // CHECK: %0 = llvm.mlir.undef : !llvm.struct<"struct.S1", (i32, f32, ptr)> // CHECK: %1 = llvm.mlir.constant(1 : i32) : i32 // CHECK: %2 = llvm.insertvalue %1, %0[0] : !llvm.struct<"struct.S1", (i32, f32, ptr)> - // CHECK: %3 = llvm.mlir.constant(0.099999994 : f32) : f32 + // CHECK: %3 = llvm.mlir.constant(1.000000e-01 : f32) : f32 // CHECK: %4 = llvm.insertvalue %3, %2[1] : !llvm.struct<"struct.S1", (i32, f32, ptr)> // CHECK: %5 = llvm.mlir.zero : !llvm.ptr // CHECK: %6 = llvm.insertvalue %5, %4[2] : !llvm.struct<"struct.S1", (i32, f32, ptr)>