Skip to content

Commit afe21ad

Browse files
committed
[CIR] Extend support for floating point attributes
This commit extends the support for floating point attributes parsing by using the new `AsmParser::parseFloat(fltSemnatics, APFloat&)` interface. As a drive-by, this commit also harmonizes the cir.fp print/parse namespace usage, and adds the constraint of supporting only "CIRFPType"s for cir.fp in tablegen instead of verifying it manually in the parsing logic.
1 parent 91caca0 commit afe21ad

File tree

7 files changed

+203
-41
lines changed

7 files changed

+203
-41
lines changed

clang/include/clang/CIR/Dialect/IR/CIRAttrs.td

+10-3
Original file line numberDiff line numberDiff line change
@@ -223,13 +223,20 @@ def FPAttr : CIR_Attr<"FP", "fp", [TypedAttrInterface]> {
223223
let summary = "An attribute containing a floating-point value";
224224
let description = [{
225225
An fp attribute is a literal attribute that represents a floating-point
226-
value of the specified floating-point type.
226+
value of the specified floating-point type. Supporting only CIR FP types.
227227
}];
228-
let parameters = (ins AttributeSelfTypeParameter<"">:$type, "APFloat":$value);
228+
let parameters = (ins
229+
AttributeSelfTypeParameter<"", "::mlir::cir::CIRFPTypeInterface">:$type,
230+
APFloatParameter<"">:$value
231+
);
229232
let builders = [
230233
AttrBuilderWithInferredContext<(ins "Type":$type,
231234
"const APFloat &":$value), [{
232-
return $_get(type.getContext(), type, value);
235+
return $_get(type.getContext(), type.cast<CIRFPTypeInterface>(), value);
236+
}]>,
237+
AttrBuilder<(ins "Type":$type,
238+
"const APFloat &":$value), [{
239+
return $_get($_ctxt, type.cast<CIRFPTypeInterface>(), value);
233240
}]>,
234241
];
235242
let extraClassDeclaration = [{

clang/lib/CIR/Dialect/IR/CIRAttrs.cpp

+16-35
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ static void printFloatLiteral(mlir::AsmPrinter &p, llvm::APFloat value,
4141
mlir::Type ty);
4242
static mlir::ParseResult
4343
parseFloatLiteral(mlir::AsmParser &parser,
44-
mlir::FailureOr<llvm::APFloat> &value, mlir::Type ty);
44+
mlir::FailureOr<llvm::APFloat> &value,
45+
mlir::cir::CIRFPTypeInterface fpType);
4546

4647
#define GET_ATTRDEF_CLASSES
4748
#include "clang/CIR/Dialect/IR/CIROpsAttributes.cpp.inc"
@@ -317,50 +318,30 @@ LogicalResult IntAttr::verify(function_ref<InFlightDiagnostic()> emitError,
317318
// FPAttr definitions
318319
//===----------------------------------------------------------------------===//
319320

320-
static void printFloatLiteral(mlir::AsmPrinter &p, llvm::APFloat value,
321-
mlir::Type ty) {
321+
static void printFloatLiteral(AsmPrinter &p, APFloat value, Type ty) {
322322
p << value;
323323
}
324324

325-
static mlir::ParseResult
326-
parseFloatLiteral(mlir::AsmParser &parser,
327-
mlir::FailureOr<llvm::APFloat> &value, mlir::Type ty) {
328-
double rawValue;
329-
if (parser.parseFloat(rawValue)) {
330-
return parser.emitError(parser.getCurrentLocation(),
331-
"expected floating-point value");
332-
}
333-
334-
auto losesInfo = false;
335-
value.emplace(rawValue);
325+
static ParseResult parseFloatLiteral(AsmParser &parser,
326+
FailureOr<APFloat> &value,
327+
CIRFPTypeInterface fpType) {
336328

337-
auto tyFpInterface = ty.dyn_cast<cir::CIRFPTypeInterface>();
338-
if (!tyFpInterface) {
339-
// Parsing of the current floating-point literal has succeeded, but the
340-
// given attribute type is invalid. This error will be reported later when
341-
// the attribute is being verified.
342-
return success();
343-
}
329+
APFloat parsedValue(0.0);
330+
if (parser.parseFloat(fpType.getFloatSemantics(), parsedValue))
331+
return failure();
344332

345-
value->convert(tyFpInterface.getFloatSemantics(),
346-
llvm::RoundingMode::TowardZero, &losesInfo);
333+
value.emplace(parsedValue);
347334
return success();
348335
}
349336

350-
cir::FPAttr cir::FPAttr::getZero(mlir::Type type) {
351-
return get(type,
352-
APFloat::getZero(
353-
type.cast<cir::CIRFPTypeInterface>().getFloatSemantics()));
337+
FPAttr FPAttr::getZero(Type type) {
338+
return get(type, APFloat::getZero(
339+
type.cast<CIRFPTypeInterface>().getFloatSemantics()));
354340
}
355341

356-
LogicalResult cir::FPAttr::verify(function_ref<InFlightDiagnostic()> emitError,
357-
Type type, APFloat value) {
358-
auto fltTypeInterface = type.dyn_cast<cir::CIRFPTypeInterface>();
359-
if (!fltTypeInterface) {
360-
emitError() << "expected floating-point type";
361-
return failure();
362-
}
363-
if (APFloat::SemanticsToEnum(fltTypeInterface.getFloatSemantics()) !=
342+
LogicalResult FPAttr::verify(function_ref<InFlightDiagnostic()> emitError,
343+
CIRFPTypeInterface fpType, APFloat value) {
344+
if (APFloat::SemanticsToEnum(fpType.getFloatSemantics()) !=
364345
APFloat::SemanticsToEnum(value.getSemantics())) {
365346
emitError() << "floating-point semantics mismatch";
366347
return failure();

clang/test/CIR/IR/attribute.cir

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: cir-opt %s -split-input-file -allow-unregistered-dialect -verify-diagnostics | FileCheck %s
2+
3+
cir.func @float_attrs_pass() {
4+
"test.float_attrs"() {
5+
// CHECK: float_attr = #cir.fp<2.000000e+00> : !cir.float
6+
float_attr = #cir.fp<2.> : !cir.float
7+
} : () -> ()
8+
"test.float_attrs"() {
9+
// CHECK: float_attr = #cir.fp<-2.000000e+00> : !cir.float
10+
float_attr = #cir.fp<-2.> : !cir.float
11+
} : () -> ()
12+
"test.float_attrs"() {
13+
// CHECK: float_attr = #cir.fp<2.000000e+00> : !cir.double
14+
float_attr = #cir.fp<2.> : !cir.double
15+
} : () -> ()
16+
"test.float_attrs"() {
17+
// CHECK: float_attr = #cir.fp<2.000000e+00> : !cir.long_double<!cir.f80>
18+
float_attr = #cir.fp<2.> : !cir.long_double<!cir.f80>
19+
} : () -> ()
20+
"test.float_attrs"() {
21+
// CHECK: float_attr = #cir.fp<2.000000e+00> : !cir.long_double<!cir.double>
22+
float_attr = #cir.fp<2.> : !cir.long_double<!cir.double>
23+
} : () -> ()
24+
cir.return
25+
}

clang/test/CIR/IR/float.cir

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// RUN: cir-opt %s | FileCheck %s
2+
3+
// Adapted from mlir/test/IR/parser.mlir
4+
5+
// CHECK-LABEL: @f32_special_values
6+
cir.func @f32_special_values() {
7+
// F32 signaling NaNs.
8+
// CHECK: cir.const(#cir.fp<0x7F800001> : !cir.float) : !cir.float
9+
%0 = cir.const(#cir.fp<0x7F800001> : !cir.float) : !cir.float
10+
// CHECK: cir.const(#cir.fp<0x7FBFFFFF> : !cir.float) : !cir.float
11+
%1 = cir.const(#cir.fp<0x7FBFFFFF> : !cir.float) : !cir.float
12+
13+
// F32 quiet NaNs.
14+
// CHECK: cir.const(#cir.fp<0x7FC00000> : !cir.float) : !cir.float
15+
%2 = cir.const(#cir.fp<0x7FC00000> : !cir.float) : !cir.float
16+
// CHECK: cir.const(#cir.fp<0xFFFFFFFF> : !cir.float) : !cir.float
17+
%3 = cir.const(#cir.fp<0xFFFFFFFF> : !cir.float) : !cir.float
18+
19+
// F32 positive infinity.
20+
// CHECK: cir.const(#cir.fp<0x7F800000> : !cir.float) : !cir.float
21+
%4 = cir.const(#cir.fp<0x7F800000> : !cir.float) : !cir.float
22+
// F32 negative infinity.
23+
// CHECK: cir.const(#cir.fp<0xFF800000> : !cir.float) : !cir.float
24+
%5 = cir.const(#cir.fp<0xFF800000> : !cir.float) : !cir.float
25+
26+
cir.return
27+
}
28+
29+
// CHECK-LABEL: @f64_special_values
30+
cir.func @f64_special_values() {
31+
// F64 signaling NaNs.
32+
// CHECK: cir.const(#cir.fp<0x7FF0000000000001> : !cir.double) : !cir.double
33+
%0 = cir.const(#cir.fp<0x7FF0000000000001> : !cir.double) : !cir.double
34+
// CHECK: cir.const(#cir.fp<0x7FF8000000000000> : !cir.double) : !cir.double
35+
%1 = cir.const(#cir.fp<0x7FF8000000000000> : !cir.double) : !cir.double
36+
37+
// F64 quiet NaNs.
38+
// CHECK: cir.const(#cir.fp<0x7FF0000001000000> : !cir.double) : !cir.double
39+
%2 = cir.const(#cir.fp<0x7FF0000001000000> : !cir.double) : !cir.double
40+
// CHECK: cir.const(#cir.fp<0xFFF0000001000000> : !cir.double) : !cir.double
41+
%3 = cir.const(#cir.fp<0xFFF0000001000000> : !cir.double) : !cir.double
42+
43+
// F64 positive infinity.
44+
// CHECK: cir.const(#cir.fp<0x7FF0000000000000> : !cir.double) : !cir.double
45+
%4 = cir.const(#cir.fp<0x7FF0000000000000> : !cir.double) : !cir.double
46+
// F64 negative infinity.
47+
// CHECK: cir.const(#cir.fp<0xFFF0000000000000> : !cir.double) : !cir.double
48+
%5 = cir.const(#cir.fp<0xFFF0000000000000> : !cir.double) : !cir.double
49+
50+
// Check that values that can't be represented with the default format, use
51+
// hex instead.
52+
// CHECK: cir.const(#cir.fp<0xC1CDC00000000000> : !cir.double) : !cir.double
53+
%6 = cir.const(#cir.fp<0xC1CDC00000000000> : !cir.double) : !cir.double
54+
55+
cir.return
56+
}
57+
58+
// CHECK-LABEL: @f80_special_values
59+
cir.func @f80_special_values() {
60+
// F80 signaling NaNs.
61+
// CHECK: cir.const(#cir.fp<0x7FFFE000000000000001> : !cir.long_double<!cir.f80>) : !cir.long_double<!cir.f80>
62+
%0 = cir.const(#cir.fp<0x7FFFE000000000000001> : !cir.long_double<!cir.f80>) : !cir.long_double<!cir.f80>
63+
// CHECK: cir.const(#cir.fp<0x7FFFB000000000000011> : !cir.long_double<!cir.f80>) : !cir.long_double<!cir.f80>
64+
%1 = cir.const(#cir.fp<0x7FFFB000000000000011> : !cir.long_double<!cir.f80>) : !cir.long_double<!cir.f80>
65+
66+
// F80 quiet NaNs.
67+
// CHECK: cir.const(#cir.fp<0x7FFFC000000000100000> : !cir.long_double<!cir.f80>) : !cir.long_double<!cir.f80>
68+
%2 = cir.const(#cir.fp<0x7FFFC000000000100000> : !cir.long_double<!cir.f80>) : !cir.long_double<!cir.f80>
69+
// CHECK: cir.const(#cir.fp<0x7FFFE000000001000000> : !cir.long_double<!cir.f80>) : !cir.long_double<!cir.f80>
70+
%3 = cir.const(#cir.fp<0x7FFFE000000001000000> : !cir.long_double<!cir.f80>) : !cir.long_double<!cir.f80>
71+
72+
// F80 positive infinity.
73+
// CHECK: cir.const(#cir.fp<0x7FFF8000000000000000> : !cir.long_double<!cir.f80>) : !cir.long_double<!cir.f80>
74+
%4 = cir.const(#cir.fp<0x7FFF8000000000000000> : !cir.long_double<!cir.f80>) : !cir.long_double<!cir.f80>
75+
// F80 negative infinity.
76+
// CHECK: cir.const(#cir.fp<0xFFFF8000000000000000> : !cir.long_double<!cir.f80>) : !cir.long_double<!cir.f80>
77+
%5 = cir.const(#cir.fp<0xFFFF8000000000000000> : !cir.long_double<!cir.f80>) : !cir.long_double<!cir.f80>
78+
79+
cir.return
80+
}
81+
82+
// We want to print floats in exponential notation with 6 significant digits,
83+
// but it may lead to precision loss when parsing back, in which case we print
84+
// the decimal form instead.
85+
// CHECK-LABEL: @f32_potential_precision_loss()
86+
cir.func @f32_potential_precision_loss() {
87+
// CHECK: cir.const(#cir.fp<1.23697901> : !cir.float) : !cir.float
88+
%0 = cir.const(#cir.fp<1.23697901> : !cir.float) : !cir.float
89+
cir.return
90+
}

clang/test/CIR/IR/invalid.cir

+60-1
Original file line numberDiff line numberDiff line change
@@ -1044,7 +1044,7 @@ cir.func @bad_fetch(%x: !cir.ptr<!cir.float>, %y: !cir.float) -> () {
10441044

10451045
cir.func @bad_operands_for_nowrap(%x: !cir.float, %y: !cir.float) {
10461046
// expected-error@+1 {{only operations on integer values may have nsw/nuw flags}}
1047-
%0 = cir.binop(add, %x, %y) nsw : !cir.float
1047+
%0 = cir.binop(add, %x, %y) nsw : !cir.float
10481048
}
10491049

10501050
// -----
@@ -1119,3 +1119,62 @@ module {
11191119
%0 = cir.dyn_cast(ptr, %arg0 : !cir.ptr<!Base>, #cir.dyn_cast_info<#cir.global_view<@_ZTI4Base> : !cir.ptr<!u8i>, #cir.global_view<@_ZTI7Derived> : !cir.ptr<!u32i>, @__dynamic_cast, @__cxa_bad_cast, #cir.int<0> : !s64i>) -> !cir.ptr<!Derived>
11201120
}
11211121
}
1122+
// -----
1123+
1124+
// Type of the attribute must be a CIR floating point type
1125+
1126+
// expected-error @below {{invalid kind of type specified}}
1127+
cir.global external @f = #cir.fp<0.5> : !cir.int<s, 32>
1128+
1129+
// -----
1130+
1131+
// Value must be a floating point literal or integer literal
1132+
1133+
// expected-error @below {{expected floating point literal}}
1134+
cir.global external @f = #cir.fp<"blabla"> : !cir.float
1135+
1136+
// -----
1137+
1138+
// Integer value must be in the width of the floating point type
1139+
1140+
// expected-error @below {{hexadecimal float constant out of range for type}}
1141+
cir.global external @f = #cir.fp<0x7FC000000> : !cir.float
1142+
1143+
// -----
1144+
1145+
// Integer value must be in the width of the floating point type
1146+
1147+
// expected-error @below {{hexadecimal float constant out of range for type}}
1148+
cir.global external @f = #cir.fp<0x7FC000007FC0000000> : !cir.double
1149+
1150+
// -----
1151+
1152+
// Integer value must be in the width of the floating point type
1153+
1154+
// expected-error @below {{hexadecimal float constant out of range for type}}
1155+
cir.global external @f = #cir.fp<0x7FC0000007FC0000007FC000000> : !cir.long_double<!cir.f80>
1156+
1157+
// -----
1158+
1159+
// Long double with `double` semnatics should have a value that fits in a double.
1160+
1161+
// CHECK: cir.global external @f = #cir.fp<0x7FC000007FC000000000> : !cir.long_double<!cir.f80>
1162+
cir.global external @f = #cir.fp<0x7FC000007FC000000000> : !cir.long_double<!cir.f80>
1163+
1164+
// expected-error @below {{hexadecimal float constant out of range for type}}
1165+
cir.global external @f = #cir.fp<0x7FC000007FC000000000> : !cir.long_double<!cir.double>
1166+
1167+
// -----
1168+
1169+
// Verify no need for type inside the attribute
1170+
1171+
// expected-error @below {{expected '>'}}
1172+
cir.global external @f = #cir.fp<0x7FC00000 : !cir.float> : !cir.float
1173+
1174+
// -----
1175+
1176+
// Verify no need for type inside the attribute
1177+
1178+
// expected-error @below {{unexpected decimal integer literal for a floating point value}}
1179+
// expected-note @below {{add a trailing dot to make the literal a float}}
1180+
cir.global external @f = #cir.fp<42> : !cir.float

clang/test/CIR/Lowering/class.cir

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ module {
4444
// CHECK: %0 = llvm.mlir.undef : !llvm.struct<"class.S1", (i32, f32, ptr)>
4545
// CHECK: %1 = llvm.mlir.constant(1 : i32) : i32
4646
// CHECK: %2 = llvm.insertvalue %1, %0[0] : !llvm.struct<"class.S1", (i32, f32, ptr)>
47-
// CHECK: %3 = llvm.mlir.constant(0.099999994 : f32) : f32
47+
// CHECK: %3 = llvm.mlir.constant(1.000000e-01 : f32) : f32
4848
// CHECK: %4 = llvm.insertvalue %3, %2[1] : !llvm.struct<"class.S1", (i32, f32, ptr)>
4949
// CHECK: %5 = llvm.mlir.zero : !llvm.ptr
5050
// CHECK: %6 = llvm.insertvalue %5, %4[2] : !llvm.struct<"class.S1", (i32, f32, ptr)>

clang/test/CIR/Lowering/struct.cir

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ module {
4444
// CHECK: %0 = llvm.mlir.undef : !llvm.struct<"struct.S1", (i32, f32, ptr)>
4545
// CHECK: %1 = llvm.mlir.constant(1 : i32) : i32
4646
// CHECK: %2 = llvm.insertvalue %1, %0[0] : !llvm.struct<"struct.S1", (i32, f32, ptr)>
47-
// CHECK: %3 = llvm.mlir.constant(0.099999994 : f32) : f32
47+
// CHECK: %3 = llvm.mlir.constant(1.000000e-01 : f32) : f32
4848
// CHECK: %4 = llvm.insertvalue %3, %2[1] : !llvm.struct<"struct.S1", (i32, f32, ptr)>
4949
// CHECK: %5 = llvm.mlir.zero : !llvm.ptr
5050
// CHECK: %6 = llvm.insertvalue %5, %4[2] : !llvm.struct<"struct.S1", (i32, f32, ptr)>

0 commit comments

Comments
 (0)