Skip to content

Commit 9c2c7ef

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 3ef67c1 commit 9c2c7ef

File tree

7 files changed

+208
-46
lines changed

7 files changed

+208
-46
lines changed

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

+16-9
Original file line numberDiff line numberDiff line change
@@ -270,13 +270,20 @@ def FPAttr : CIR_Attr<"FP", "fp", [TypedAttrInterface]> {
270270
let summary = "An attribute containing a floating-point value";
271271
let description = [{
272272
An fp attribute is a literal attribute that represents a floating-point
273-
value of the specified floating-point type.
273+
value of the specified floating-point type. Supporting only CIR FP types.
274274
}];
275-
let parameters = (ins AttributeSelfTypeParameter<"">:$type, "APFloat":$value);
275+
let parameters = (ins
276+
AttributeSelfTypeParameter<"", "::mlir::cir::CIRFPTypeInterface">:$type,
277+
APFloatParameter<"">:$value
278+
);
276279
let builders = [
277280
AttrBuilderWithInferredContext<(ins "Type":$type,
278281
"const APFloat &":$value), [{
279-
return $_get(type.getContext(), type, value);
282+
return $_get(type.getContext(), mlir::cast<CIRFPTypeInterface>(type), value);
283+
}]>,
284+
AttrBuilder<(ins "Type":$type,
285+
"const APFloat &":$value), [{
286+
return $_get($_ctxt, mlir::cast<CIRFPTypeInterface>(type), value);
280287
}]>,
281288
];
282289
let extraClassDeclaration = [{
@@ -304,7 +311,7 @@ def ComplexAttr : CIR_Attr<"Complex", "complex", [TypedAttrInterface]> {
304311
contains values of the same CIR type.
305312
}];
306313

307-
let parameters = (ins
314+
let parameters = (ins
308315
AttributeSelfTypeParameter<"", "mlir::cir::ComplexType">:$type,
309316
"mlir::TypedAttr":$real, "mlir::TypedAttr":$imag);
310317

@@ -805,7 +812,7 @@ def AddressSpaceAttr : CIR_Attr<"AddressSpace", "addrspace"> {
805812
let extraClassDeclaration = [{
806813
static constexpr char kTargetKeyword[] = "}]#targetASCase.symbol#[{";
807814
static constexpr int32_t kFirstTargetASValue = }]#targetASCase.value#[{;
808-
815+
809816
bool isLang() const;
810817
bool isTarget() const;
811818
unsigned getTargetValue() const;
@@ -965,7 +972,7 @@ def ASTCallExprAttr : AST<"CallExpr", "call.expr",
965972
// VisibilityAttr
966973
//===----------------------------------------------------------------------===//
967974

968-
def VK_Default : I32EnumAttrCase<"Default", 1, "default">;
975+
def VK_Default : I32EnumAttrCase<"Default", 1, "default">;
969976
def VK_Hidden : I32EnumAttrCase<"Hidden", 2, "hidden">;
970977
def VK_Protected : I32EnumAttrCase<"Protected", 3, "protected">;
971978

@@ -998,7 +1005,7 @@ def VisibilityAttr : CIR_Attr<"Visibility", "visibility"> {
9981005
bool isDefault() const { return getValue() == VisibilityKind::Default; };
9991006
bool isHidden() const { return getValue() == VisibilityKind::Hidden; };
10001007
bool isProtected() const { return getValue() == VisibilityKind::Protected; };
1001-
}];
1008+
}];
10021009
}
10031010

10041011

@@ -1145,7 +1152,7 @@ def AnnotationAttr : CIR_Attr<"Annotation", "annotation"> {
11451152
let parameters = (ins "StringAttr":$name,
11461153
"ArrayAttr":$args);
11471154

1148-
let assemblyFormat = "`<` struct($name, $args) `>`";
1155+
let assemblyFormat = "`<` struct($name, $args) `>`";
11491156

11501157
let extraClassDeclaration = [{
11511158
bool isNoArgs() const { return getArgs().empty(); };
@@ -1172,7 +1179,7 @@ def GlobalAnnotationValuesAttr : CIR_Attr<"GlobalAnnotationValues",
11721179
void *c __attribute__((annotate("noargvar")));
11731180
void foo(int i) __attribute__((annotate("noargfunc"))) {}
11741181
```
1175-
After CIR lowering prepare pass, compiler generates a
1182+
After CIR lowering prepare pass, compiler generates a
11761183
`GlobalAnnotationValuesAttr` like the following:
11771184
```
11781185
#cir<global_annotations [

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

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

4748
static mlir::ParseResult parseConstPtr(mlir::AsmParser &parser,
4849
mlir::IntegerAttr &value);
@@ -311,50 +312,30 @@ LogicalResult IntAttr::verify(function_ref<InFlightDiagnostic()> emitError,
311312
// FPAttr definitions
312313
//===----------------------------------------------------------------------===//
313314

314-
static void printFloatLiteral(mlir::AsmPrinter &p, llvm::APFloat value,
315-
mlir::Type ty) {
315+
static void printFloatLiteral(AsmPrinter &p, APFloat value, Type ty) {
316316
p << value;
317317
}
318318

319-
static mlir::ParseResult
320-
parseFloatLiteral(mlir::AsmParser &parser,
321-
mlir::FailureOr<llvm::APFloat> &value, mlir::Type ty) {
322-
double rawValue;
323-
if (parser.parseFloat(rawValue)) {
324-
return parser.emitError(parser.getCurrentLocation(),
325-
"expected floating-point value");
326-
}
327-
328-
auto losesInfo = false;
329-
value.emplace(rawValue);
319+
static ParseResult parseFloatLiteral(AsmParser &parser,
320+
FailureOr<APFloat> &value,
321+
CIRFPTypeInterface fpType) {
330322

331-
auto tyFpInterface = dyn_cast<cir::CIRFPTypeInterface>(ty);
332-
if (!tyFpInterface) {
333-
// Parsing of the current floating-point literal has succeeded, but the
334-
// given attribute type is invalid. This error will be reported later when
335-
// the attribute is being verified.
336-
return success();
337-
}
323+
APFloat parsedValue(0.0);
324+
if (parser.parseFloat(fpType.getFloatSemantics(), parsedValue))
325+
return failure();
338326

339-
value->convert(tyFpInterface.getFloatSemantics(),
340-
llvm::RoundingMode::TowardZero, &losesInfo);
327+
value.emplace(parsedValue);
341328
return success();
342329
}
343330

344-
cir::FPAttr cir::FPAttr::getZero(mlir::Type type) {
345-
return get(
346-
type, APFloat::getZero(
347-
mlir::cast<cir::CIRFPTypeInterface>(type).getFloatSemantics()));
331+
FPAttr FPAttr::getZero(Type type) {
332+
return get(type, APFloat::getZero(
333+
mlir::cast<CIRFPTypeInterface>(type).getFloatSemantics()));
348334
}
349335

350-
LogicalResult cir::FPAttr::verify(function_ref<InFlightDiagnostic()> emitError,
351-
Type type, APFloat value) {
352-
auto fltTypeInterface = mlir::dyn_cast<cir::CIRFPTypeInterface>(type);
353-
if (!fltTypeInterface) {
354-
emitError() << "expected floating-point type";
355-
return failure();
356-
}
357-
if (APFloat::SemanticsToEnum(fltTypeInterface.getFloatSemantics()) !=
336+
LogicalResult FPAttr::verify(function_ref<InFlightDiagnostic()> emitError,
337+
CIRFPTypeInterface fpType, APFloat value) {
338+
if (APFloat::SemanticsToEnum(fpType.getFloatSemantics()) !=
358339
APFloat::SemanticsToEnum(value.getSemantics())) {
359340
emitError() << "floating-point semantics mismatch";
360341
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
9+
%0 = cir.const #cir.fp<0x7F800001> : !cir.float
10+
// CHECK: cir.const #cir.fp<0x7FBFFFFF> : !cir.float
11+
%1 = cir.const #cir.fp<0x7FBFFFFF> : !cir.float
12+
13+
// F32 quiet NaNs.
14+
// CHECK: cir.const #cir.fp<0x7FC00000> : !cir.float
15+
%2 = cir.const #cir.fp<0x7FC00000> : !cir.float
16+
// CHECK: cir.const #cir.fp<0xFFFFFFFF> : !cir.float
17+
%3 = cir.const #cir.fp<0xFFFFFFFF> : !cir.float
18+
19+
// F32 positive infinity.
20+
// CHECK: cir.const #cir.fp<0x7F800000> : !cir.float
21+
%4 = cir.const #cir.fp<0x7F800000> : !cir.float
22+
// F32 negative infinity.
23+
// CHECK: cir.const #cir.fp<0xFF800000> : !cir.float
24+
%5 = cir.const #cir.fp<0xFF800000> : !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
33+
%0 = cir.const #cir.fp<0x7FF0000000000001> : !cir.double
34+
// CHECK: cir.const #cir.fp<0x7FF8000000000000> : !cir.double
35+
%1 = cir.const #cir.fp<0x7FF8000000000000> : !cir.double
36+
37+
// F64 quiet NaNs.
38+
// CHECK: cir.const #cir.fp<0x7FF0000001000000> : !cir.double
39+
%2 = cir.const #cir.fp<0x7FF0000001000000> : !cir.double
40+
// CHECK: cir.const #cir.fp<0xFFF0000001000000> : !cir.double
41+
%3 = cir.const #cir.fp<0xFFF0000001000000> : !cir.double
42+
43+
// F64 positive infinity.
44+
// CHECK: cir.const #cir.fp<0x7FF0000000000000> : !cir.double
45+
%4 = cir.const #cir.fp<0x7FF0000000000000> : !cir.double
46+
// F64 negative infinity.
47+
// CHECK: cir.const #cir.fp<0xFFF0000000000000> : !cir.double
48+
%5 = cir.const #cir.fp<0xFFF0000000000000> : !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
53+
%6 = cir.const #cir.fp<0xC1CDC00000000000> : !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>
62+
%0 = cir.const #cir.fp<0x7FFFE000000000000001> : !cir.long_double<!cir.f80>
63+
// CHECK: cir.const #cir.fp<0x7FFFB000000000000011> : !cir.long_double<!cir.f80>
64+
%1 = cir.const #cir.fp<0x7FFFB000000000000011> : !cir.long_double<!cir.f80>
65+
66+
// F80 quiet NaNs.
67+
// CHECK: cir.const #cir.fp<0x7FFFC000000000100000> : !cir.long_double<!cir.f80>
68+
%2 = cir.const #cir.fp<0x7FFFC000000000100000> : !cir.long_double<!cir.f80>
69+
// CHECK: cir.const #cir.fp<0x7FFFE000000001000000> : !cir.long_double<!cir.f80>
70+
%3 = cir.const #cir.fp<0x7FFFE000000001000000> : !cir.long_double<!cir.f80>
71+
72+
// F80 positive infinity.
73+
// CHECK: cir.const #cir.fp<0x7FFF8000000000000000> : !cir.long_double<!cir.f80>
74+
%4 = cir.const #cir.fp<0x7FFF8000000000000000> : !cir.long_double<!cir.f80>
75+
// F80 negative infinity.
76+
// CHECK: cir.const #cir.fp<0xFFFF8000000000000000> : !cir.long_double<!cir.f80>
77+
%5 = cir.const #cir.fp<0xFFFF8000000000000000> : !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
88+
%0 = cir.const #cir.fp<1.23697901> : !cir.float
89+
cir.return
90+
}

clang/test/CIR/IR/invalid.cir

+59
Original file line numberDiff line numberDiff line change
@@ -1378,3 +1378,62 @@ module {
13781378
cir.return
13791379
}
13801380
}
1381+
// -----
1382+
1383+
// Type of the attribute must be a CIR floating point type
1384+
1385+
// expected-error @below {{invalid kind of type specified}}
1386+
cir.global external @f = #cir.fp<0.5> : !cir.int<s, 32>
1387+
1388+
// -----
1389+
1390+
// Value must be a floating point literal or integer literal
1391+
1392+
// expected-error @below {{expected floating point literal}}
1393+
cir.global external @f = #cir.fp<"blabla"> : !cir.float
1394+
1395+
// -----
1396+
1397+
// Integer value must be in the width of the floating point type
1398+
1399+
// expected-error @below {{hexadecimal float constant out of range for type}}
1400+
cir.global external @f = #cir.fp<0x7FC000000> : !cir.float
1401+
1402+
// -----
1403+
1404+
// Integer value must be in the width of the floating point type
1405+
1406+
// expected-error @below {{hexadecimal float constant out of range for type}}
1407+
cir.global external @f = #cir.fp<0x7FC000007FC0000000> : !cir.double
1408+
1409+
// -----
1410+
1411+
// Integer value must be in the width of the floating point type
1412+
1413+
// expected-error @below {{hexadecimal float constant out of range for type}}
1414+
cir.global external @f = #cir.fp<0x7FC0000007FC0000007FC000000> : !cir.long_double<!cir.f80>
1415+
1416+
// -----
1417+
1418+
// Long double with `double` semnatics should have a value that fits in a double.
1419+
1420+
// CHECK: cir.global external @f = #cir.fp<0x7FC000007FC000000000> : !cir.long_double<!cir.f80>
1421+
cir.global external @f = #cir.fp<0x7FC000007FC000000000> : !cir.long_double<!cir.f80>
1422+
1423+
// expected-error @below {{hexadecimal float constant out of range for type}}
1424+
cir.global external @f = #cir.fp<0x7FC000007FC000000000> : !cir.long_double<!cir.double>
1425+
1426+
// -----
1427+
1428+
// Verify no need for type inside the attribute
1429+
1430+
// expected-error @below {{expected '>'}}
1431+
cir.global external @f = #cir.fp<0x7FC00000 : !cir.float> : !cir.float
1432+
1433+
// -----
1434+
1435+
// Verify literal must be hex or float
1436+
1437+
// expected-error @below {{unexpected decimal integer literal for a floating point value}}
1438+
// expected-note @below {{add a trailing dot to make the literal a float}}
1439+
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)