diff --git a/mlir/docs/OpDefinitions.md b/mlir/docs/OpDefinitions.md --- a/mlir/docs/OpDefinitions.md +++ b/mlir/docs/OpDefinitions.md @@ -273,6 +273,9 @@ like `"0.5f"`, and an integer array default value should be specified as like `"{1, 2, 3}"`. +The generated operation printing function will not print default-valued +attributes when the attribute value is equal to the default. + #### Confining attributes `ConfinedAttr` is provided as a general mechanism to help modelling further diff --git a/mlir/test/Dialect/AMDGPU/ops.mlir b/mlir/test/Dialect/AMDGPU/ops.mlir --- a/mlir/test/Dialect/AMDGPU/ops.mlir +++ b/mlir/test/Dialect/AMDGPU/ops.mlir @@ -6,56 +6,56 @@ // CHECK-LABEL: func @raw_buffer_load_f32_from_rank_1 func.func @raw_buffer_load_f32_from_rank_1(%src : memref<128xf32>, %offset : i32, %idx0 : i32) -> f32 { - // CHECK: amdgpu.raw_buffer_load {boundsCheck = true, indexOffset = 1 : i32} %{{.*}}[{{.*}}] sgprOffset %{{.*}} : memref<128xf32>, i32 -> f32 + // CHECK: amdgpu.raw_buffer_load {indexOffset = 1 : i32} %{{.*}}[{{.*}}] sgprOffset %{{.*}} : memref<128xf32>, i32 -> f32 %0 = amdgpu.raw_buffer_load {boundsCheck = true, indexOffset = 1 : i32} %src[%idx0] sgprOffset %offset : memref<128xf32>, i32 -> f32 func.return %0 : f32 } // CHECK-LABEL: func @raw_buffer_load_f32_from_rank_4 func.func @raw_buffer_load_f32_from_rank_4(%src : memref<128x64x32x16xf32>, %offset : i32, %idx0 : i32, %idx1 : i32, %idx2 : i32, %idx3 : i32) -> f32 { - // CHECK: amdgpu.raw_buffer_load {boundsCheck = true, indexOffset = 1 : i32} %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] sgprOffset %{{.*}} : memref<128x64x32x16xf32>, i32, i32, i32, i32 -> f32 + // CHECK: amdgpu.raw_buffer_load {indexOffset = 1 : i32} %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] sgprOffset %{{.*}} : memref<128x64x32x16xf32>, i32, i32, i32, i32 -> f32 %0 = amdgpu.raw_buffer_load {boundsCheck = true, indexOffset = 1 : i32} %src[%idx0, %idx1, %idx2, %idx3] sgprOffset %offset : memref<128x64x32x16xf32>, i32, i32, i32, i32 -> f32 func.return %0 : f32 } // CHECK-LABEL: func @raw_buffer_load_4xf32_from_rank_4 func.func @raw_buffer_load_4xf32_from_rank_4(%src : memref<128x64x32x16xf32>, %offset : i32, %idx0 : i32, %idx1 : i32, %idx2 : i32, %idx3 : i32) -> vector<4xf32> { - // CHECK: amdgpu.raw_buffer_load {boundsCheck = true, indexOffset = 1 : i32} %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] sgprOffset %{{.*}} : memref<128x64x32x16xf32>, i32, i32, i32, i32 -> vector<4xf32> + // CHECK: amdgpu.raw_buffer_load {indexOffset = 1 : i32} %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] sgprOffset %{{.*}} : memref<128x64x32x16xf32>, i32, i32, i32, i32 -> vector<4xf32> %0 = amdgpu.raw_buffer_load {boundsCheck = true, indexOffset = 1 : i32} %src[%idx0, %idx1, %idx2, %idx3] sgprOffset %offset : memref<128x64x32x16xf32>, i32, i32, i32, i32 -> vector<4xf32> func.return %0 : vector<4xf32> } // CHECK-LABEL: func @raw_buffer_store_f32_to_rank_1 func.func @raw_buffer_store_f32_to_rank_1(%value : f32, %dst : memref<128xf32>, %offset : i32, %idx0 : i32) { - // CHECK: amdgpu.raw_buffer_store {boundsCheck = true, indexOffset = 1 : i32} %{{.*}} -> %{{.*}}[{{.*}}] sgprOffset %{{.*}} : f32 -> memref<128xf32>, i32 + // CHECK: amdgpu.raw_buffer_store {indexOffset = 1 : i32} %{{.*}} -> %{{.*}}[{{.*}}] sgprOffset %{{.*}} : f32 -> memref<128xf32>, i32 amdgpu.raw_buffer_store {boundsCheck = true, indexOffset = 1 : i32} %value -> %dst[%idx0] sgprOffset %offset : f32 -> memref<128xf32>, i32 func.return } // CHECK-LABEL: func @raw_buffer_store_f32_to_rank_4 func.func @raw_buffer_store_f32_to_rank_4(%value : f32, %dst : memref<128x64x32x16xf32>, %offset : i32, %idx0 : i32, %idx1 : i32, %idx2 : i32, %idx3 : i32) { - // CHECK: amdgpu.raw_buffer_store {boundsCheck = true, indexOffset = 1 : i32} %{{.*}} -> %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] sgprOffset %{{.*}} : f32 -> memref<128x64x32x16xf32>, i32, i32, i32, i32 + // CHECK: amdgpu.raw_buffer_store {indexOffset = 1 : i32} %{{.*}} -> %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] sgprOffset %{{.*}} : f32 -> memref<128x64x32x16xf32>, i32, i32, i32, i32 amdgpu.raw_buffer_store {boundsCheck = true, indexOffset = 1 : i32} %value -> %dst[%idx0, %idx1, %idx2, %idx3] sgprOffset %offset : f32 -> memref<128x64x32x16xf32>, i32, i32, i32, i32 func.return } // CHECK-LABEL: func @raw_buffer_store_4xf32_to_rank_4 func.func @raw_buffer_store_4xf32_to_rank_4(%value : vector<4xf32>, %dst : memref<128x64x32x16xf32>, %offset : i32, %idx0 : i32, %idx1 : i32, %idx2 : i32, %idx3 : i32) { - // CHECK: amdgpu.raw_buffer_store {boundsCheck = true, indexOffset = 1 : i32} %{{.*}} -> %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] sgprOffset %{{.*}} : vector<4xf32> -> memref<128x64x32x16xf32>, i32, i32, i32, i32 + // CHECK: amdgpu.raw_buffer_store {indexOffset = 1 : i32} %{{.*}} -> %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] sgprOffset %{{.*}} : vector<4xf32> -> memref<128x64x32x16xf32>, i32, i32, i32, i32 amdgpu.raw_buffer_store {boundsCheck = true, indexOffset = 1 : i32} %value -> %dst[%idx0, %idx1, %idx2, %idx3] sgprOffset %offset : vector<4xf32> -> memref<128x64x32x16xf32>, i32, i32, i32, i32 func.return } // CHECK-LABEL: func @raw_buffer_atomic_fadd_f32_to_rank_1 func.func @raw_buffer_atomic_fadd_f32_to_rank_1(%value : f32, %dst : memref<128xf32>, %offset : i32, %idx0 : i32) { - // CHECK: amdgpu.raw_buffer_atomic_fadd {boundsCheck = true, indexOffset = 1 : i32} %{{.*}} -> %{{.*}}[{{.*}}] sgprOffset %{{.*}} : f32 -> memref<128xf32>, i32 + // CHECK: amdgpu.raw_buffer_atomic_fadd {indexOffset = 1 : i32} %{{.*}} -> %{{.*}}[{{.*}}] sgprOffset %{{.*}} : f32 -> memref<128xf32>, i32 amdgpu.raw_buffer_atomic_fadd {boundsCheck = true, indexOffset = 1 : i32} %value -> %dst[%idx0] sgprOffset %offset : f32 -> memref<128xf32>, i32 func.return } // CHECK-LABEL: func @raw_buffer_atomic_fadd_f32_to_rank_4 func.func @raw_buffer_atomic_fadd_f32_to_rank_4(%value : f32, %dst : memref<128x64x32x16xf32>, %offset : i32, %idx0 : i32, %idx1 : i32, %idx2 : i32, %idx3 : i32) { - // CHECK: amdgpu.raw_buffer_atomic_fadd {boundsCheck = true, indexOffset = 1 : i32} %{{.*}} -> %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] sgprOffset %{{.*}} : f32 -> memref<128x64x32x16xf32>, i32, i32, i32, i32 + // CHECK: amdgpu.raw_buffer_atomic_fadd {indexOffset = 1 : i32} %{{.*}} -> %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] sgprOffset %{{.*}} : f32 -> memref<128x64x32x16xf32>, i32, i32, i32, i32 amdgpu.raw_buffer_atomic_fadd {boundsCheck = true, indexOffset = 1 : i32} %value -> %dst[%idx0, %idx1, %idx2, %idx3] sgprOffset %offset : f32 -> memref<128x64x32x16xf32>, i32, i32, i32, i32 func.return } diff --git a/mlir/test/IR/attribute.mlir b/mlir/test/IR/attribute.mlir --- a/mlir/test/IR/attribute.mlir +++ b/mlir/test/IR/attribute.mlir @@ -786,3 +786,20 @@ } : () -> () return } + +// ----- + +//===----------------------------------------------------------------------===// +// Test DefaultValuedAttr Printing +//===----------------------------------------------------------------------===// + +// CHECK-LABEL: @default_value_printing +func.func @default_value_printing(%arg0 : i32) { + // The attribute SHOULD NOT be printed because it is equal to the default + // CHECK: test.default_value_print %arg0 + "test.default_value_print"(%arg0) {"value_with_default" = 0 : i32} : (i32) -> () + // The attribute SHOULD be printed because it is not equal to the default + // CHECK: test.default_value_print {value_with_default = 1 : i32} %arg0 + "test.default_value_print"(%arg0) {"value_with_default" = 1 : i32} : (i32) -> () + return +} diff --git a/mlir/test/lib/Dialect/Test/TestOps.td b/mlir/test/lib/Dialect/Test/TestOps.td --- a/mlir/test/lib/Dialect/Test/TestOps.td +++ b/mlir/test/lib/Dialect/Test/TestOps.td @@ -2919,6 +2919,16 @@ def : Pat<(TestDefaultStrAttrNoValueOp $value), (TestDefaultStrAttrHasValueOp ConstantStrAttr)>; +//===----------------------------------------------------------------------===// +// Test Ops with Default-Valued Attributes and Differing Print Settings +//===----------------------------------------------------------------------===// + +def TestDefaultAttrPrintOp : TEST_Op<"default_value_print"> { + let arguments = (ins DefaultValuedAttr:$value_with_default, + I32:$operand); + let assemblyFormat = "attr-dict $operand"; +} + //===----------------------------------------------------------------------===// // Test Ops with effects //===----------------------------------------------------------------------===// diff --git a/mlir/test/python/dialects/transform_loop_ext.py b/mlir/test/python/dialects/transform_loop_ext.py --- a/mlir/test/python/dialects/transform_loop_ext.py +++ b/mlir/test/python/dialects/transform_loop_ext.py @@ -61,7 +61,7 @@ # CHECK-LABEL: TEST: loopPipeline # CHECK: = transform.loop.pipeline % # CHECK-DAG: iteration_interval = 3 - # CHECK-DAG: read_latency = 10 + # (read_latency has default value and is not printed) @run diff --git a/mlir/test/python/dialects/transform_structured_ext.py b/mlir/test/python/dialects/transform_structured_ext.py --- a/mlir/test/python/dialects/transform_structured_ext.py +++ b/mlir/test/python/dialects/transform_structured_ext.py @@ -84,9 +84,7 @@ # CHECK-DAG: padding_values = [4.200000e+01 : f32] # CHECK-DAG: padding_dimensions = [1] # CHECK-DAG: transpose_paddings = {{\[}}[1, 0]] - # CHECK-DAG: hoist_paddings = [] - # CHECK-DAG: pack_paddings = [] - + # (hoist_paddings and pack_paddings have default values) @run def testScalarize(): diff --git a/mlir/tools/mlir-tblgen/OpFormatGen.cpp b/mlir/tools/mlir-tblgen/OpFormatGen.cpp --- a/mlir/tools/mlir-tblgen/OpFormatGen.cpp +++ b/mlir/tools/mlir-tblgen/OpFormatGen.cpp @@ -1644,24 +1644,39 @@ /// Generate the printer for the 'attr-dict' directive. static void genAttrDictPrinter(OperationFormat &fmt, Operator &op, MethodBody &body, bool withKeyword) { - body << " _odsPrinter.printOptionalAttrDict" - << (withKeyword ? "WithKeyword" : "") - << "((*this)->getAttrs(), /*elidedAttrs=*/{"; + body << " ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;\n"; // Elide the variadic segment size attributes if necessary. if (!fmt.allOperands && op.getTrait("::mlir::OpTrait::AttrSizedOperandSegments")) - body << "\"operand_segment_sizes\", "; + body << " elidedAttrs.push_back(\"operand_segment_sizes\");\n"; if (!fmt.allResultTypes && op.getTrait("::mlir::OpTrait::AttrSizedResultSegments")) - body << "\"result_segment_sizes\", "; - if (!fmt.inferredAttributes.empty()) { - for (const auto &attr : fmt.inferredAttributes) - body << "\"" << attr.getKey() << "\", "; - } - llvm::interleaveComma( - fmt.usedAttributes, body, - [&](const NamedAttribute *attr) { body << "\"" << attr->name << "\""; }); - body << "});\n"; + body << " elidedAttrs.push_back(\"result_segment_sizes\");\n"; + for (const StringRef key : fmt.inferredAttributes.keys()) + body << " elidedAttrs.push_back(\"" << key << "\");\n"; + for (const NamedAttribute *attr : fmt.usedAttributes) + body << " elidedAttrs.push_back(\"" << attr->name << "\");\n"; + // Add code to check attributes for equality with the default value + // for attributes with the elidePrintingDefaultValue bit set. + for (const NamedAttribute &namedAttr : op.getAttributes()) { + const Attribute &attr = namedAttr.attr; + if (!attr.isDerivedAttr() && attr.hasDefaultValue()) { + const StringRef &name = namedAttr.name; + FmtContext fctx; + fctx.withBuilder("odsBuilder"); + std::string defaultValue = std::string( + tgfmt(attr.getConstBuilderTemplate(), &fctx, attr.getDefaultValue())); + body << " {\n"; + body << " ::mlir::Builder odsBuilder(getContext());\n"; + body << " Attribute attr = " << op.getGetterName(name) << "Attr();\n"; + body << " if(attr && (attr == " << defaultValue << "))\n"; + body << " elidedAttrs.push_back(\"" << name << "\");\n"; + body << " }\n"; + } + } + body << " _odsPrinter.printOptionalAttrDict" + << (withKeyword ? "WithKeyword" : "") + << "((*this)->getAttrs(), elidedAttrs);\n"; } /// Generate the printer for a literal value. `shouldEmitSpace` is true if a