Skip to content

Commit 7468718

Browse files
authored
[mlir][emitc] Make CExpression trait into interface (#142771)
By defining `CExpressionInterface`, we move the side effect detection logic from `emitc.expression` into the individual operations implementing the interface allowing operations to gradually tune the side effect. It also allows checking for side effects each operation individually.
1 parent ad9e591 commit 7468718

File tree

10 files changed

+159
-82
lines changed

10 files changed

+159
-82
lines changed

mlir/include/mlir/Dialect/EmitC/IR/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
add_mlir_dialect(EmitC emitc)
22
add_mlir_doc(EmitC EmitC Dialects/ -gen-dialect-doc -dialect emitc)
33

4+
set(LLVM_TARGET_DEFINITIONS EmitCInterfaces.td)
5+
mlir_tablegen(EmitCInterfaces.h.inc -gen-op-interface-decls)
6+
mlir_tablegen(EmitCInterfaces.cpp.inc -gen-op-interface-defs)
7+
add_public_tablegen_target(MLIREmitCInterfacesIncGen)
8+
add_dependencies(mlir-generic-headers MLIREmitCInterfacesIncGen)
9+
410
set(LLVM_TARGET_DEFINITIONS EmitCAttributes.td)
511
mlir_tablegen(EmitCEnums.h.inc -gen-enum-decls)
612
mlir_tablegen(EmitCEnums.cpp.inc -gen-enum-defs)

mlir/include/mlir/Dialect/EmitC/IR/EmitC.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
#define MLIR_DIALECT_EMITC_IR_EMITC_H
1515

1616
#include "mlir/Bytecode/BytecodeOpInterface.h"
17-
#include "mlir/Dialect/EmitC/IR/EmitCTraits.h"
17+
#include "mlir/Dialect/EmitC/IR/EmitCInterfaces.h"
1818
#include "mlir/IR/Builders.h"
1919
#include "mlir/IR/BuiltinOps.h"
2020
#include "mlir/IR/BuiltinTypes.h"

mlir/include/mlir/Dialect/EmitC/IR/EmitC.td

Lines changed: 64 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#define MLIR_DIALECT_EMITC_IR_EMITC
1515

1616
include "mlir/Dialect/EmitC/IR/EmitCAttributes.td"
17+
include "mlir/Dialect/EmitC/IR/EmitCInterfaces.td"
1718
include "mlir/Dialect/EmitC/IR/EmitCTypes.td"
1819

1920
include "mlir/Interfaces/CallInterfaces.td"
@@ -35,22 +36,31 @@ class EmitC_Op<string mnemonic, list<Trait> traits = []>
3536

3637
// Base class for unary operations.
3738
class EmitC_UnaryOp<string mnemonic, list<Trait> traits = []> :
38-
EmitC_Op<mnemonic, traits> {
39+
EmitC_Op<mnemonic, !listconcat(traits, [CExpressionInterface])> {
3940
let arguments = (ins EmitCType);
4041
let results = (outs EmitCType);
4142
let assemblyFormat = "operands attr-dict `:` functional-type(operands, results)";
43+
44+
let extraClassDeclaration = [{
45+
bool hasSideEffects() {
46+
return false;
47+
}
48+
}];
4249
}
4350

4451
// Base class for binary operations.
4552
class EmitC_BinaryOp<string mnemonic, list<Trait> traits = []> :
46-
EmitC_Op<mnemonic, traits> {
53+
EmitC_Op<mnemonic, !listconcat(traits, [CExpressionInterface])> {
4754
let arguments = (ins EmitCType:$lhs, EmitCType:$rhs);
4855
let results = (outs EmitCType);
4956
let assemblyFormat = "operands attr-dict `:` functional-type(operands, results)";
50-
}
5157

52-
// EmitC OpTrait
53-
def CExpression : NativeOpTrait<"emitc::CExpression">;
58+
let extraClassDeclaration = [{
59+
bool hasSideEffects() {
60+
return false;
61+
}
62+
}];
63+
}
5464

5565
// Types only used in binary arithmetic operations.
5666
def IntegerIndexOrOpaqueType : Type<CPred<"emitc::isIntegerIndexOrOpaqueType($_self)">,
@@ -103,7 +113,7 @@ def EmitC_FileOp
103113
let skipDefaultBuilders = 1;
104114
}
105115

106-
def EmitC_AddOp : EmitC_BinaryOp<"add", [CExpression]> {
116+
def EmitC_AddOp : EmitC_BinaryOp<"add", []> {
107117
let summary = "Addition operation";
108118
let description = [{
109119
With the `emitc.add` operation the arithmetic operator + (addition) can
@@ -126,7 +136,7 @@ def EmitC_AddOp : EmitC_BinaryOp<"add", [CExpression]> {
126136
let hasVerifier = 1;
127137
}
128138

129-
def EmitC_ApplyOp : EmitC_Op<"apply", [CExpression]> {
139+
def EmitC_ApplyOp : EmitC_Op<"apply", [CExpressionInterface]> {
130140
let summary = "Apply operation";
131141
let description = [{
132142
With the `emitc.apply` operation the operators & (address of) and * (contents of)
@@ -152,10 +162,17 @@ def EmitC_ApplyOp : EmitC_Op<"apply", [CExpression]> {
152162
let assemblyFormat = [{
153163
$applicableOperator `(` $operand `)` attr-dict `:` functional-type($operand, results)
154164
}];
165+
166+
let extraClassDeclaration = [{
167+
bool hasSideEffects() {
168+
return getApplicableOperator() == "*";
169+
}
170+
}];
171+
155172
let hasVerifier = 1;
156173
}
157174

158-
def EmitC_BitwiseAndOp : EmitC_BinaryOp<"bitwise_and", [CExpression]> {
175+
def EmitC_BitwiseAndOp : EmitC_BinaryOp<"bitwise_and", []> {
159176
let summary = "Bitwise and operation";
160177
let description = [{
161178
With the `emitc.bitwise_and` operation the bitwise operator & (and) can
@@ -173,8 +190,7 @@ def EmitC_BitwiseAndOp : EmitC_BinaryOp<"bitwise_and", [CExpression]> {
173190
}];
174191
}
175192

176-
def EmitC_BitwiseLeftShiftOp : EmitC_BinaryOp<"bitwise_left_shift",
177-
[CExpression]> {
193+
def EmitC_BitwiseLeftShiftOp : EmitC_BinaryOp<"bitwise_left_shift", []> {
178194
let summary = "Bitwise left shift operation";
179195
let description = [{
180196
With the `emitc.bitwise_left_shift` operation the bitwise operator <<
@@ -192,7 +208,7 @@ def EmitC_BitwiseLeftShiftOp : EmitC_BinaryOp<"bitwise_left_shift",
192208
}];
193209
}
194210

195-
def EmitC_BitwiseNotOp : EmitC_UnaryOp<"bitwise_not", [CExpression]> {
211+
def EmitC_BitwiseNotOp : EmitC_UnaryOp<"bitwise_not", []> {
196212
let summary = "Bitwise not operation";
197213
let description = [{
198214
With the `emitc.bitwise_not` operation the bitwise operator ~ (not) can
@@ -210,7 +226,7 @@ def EmitC_BitwiseNotOp : EmitC_UnaryOp<"bitwise_not", [CExpression]> {
210226
}];
211227
}
212228

213-
def EmitC_BitwiseOrOp : EmitC_BinaryOp<"bitwise_or", [CExpression]> {
229+
def EmitC_BitwiseOrOp : EmitC_BinaryOp<"bitwise_or", []> {
214230
let summary = "Bitwise or operation";
215231
let description = [{
216232
With the `emitc.bitwise_or` operation the bitwise operator | (or)
@@ -228,8 +244,7 @@ def EmitC_BitwiseOrOp : EmitC_BinaryOp<"bitwise_or", [CExpression]> {
228244
}];
229245
}
230246

231-
def EmitC_BitwiseRightShiftOp : EmitC_BinaryOp<"bitwise_right_shift",
232-
[CExpression]> {
247+
def EmitC_BitwiseRightShiftOp : EmitC_BinaryOp<"bitwise_right_shift", []> {
233248
let summary = "Bitwise right shift operation";
234249
let description = [{
235250
With the `emitc.bitwise_right_shift` operation the bitwise operator >>
@@ -247,7 +262,7 @@ def EmitC_BitwiseRightShiftOp : EmitC_BinaryOp<"bitwise_right_shift",
247262
}];
248263
}
249264

250-
def EmitC_BitwiseXorOp : EmitC_BinaryOp<"bitwise_xor", [CExpression]> {
265+
def EmitC_BitwiseXorOp : EmitC_BinaryOp<"bitwise_xor", []> {
251266
let summary = "Bitwise xor operation";
252267
let description = [{
253268
With the `emitc.bitwise_xor` operation the bitwise operator ^ (xor)
@@ -265,7 +280,7 @@ def EmitC_BitwiseXorOp : EmitC_BinaryOp<"bitwise_xor", [CExpression]> {
265280
}];
266281
}
267282

268-
def EmitC_CallOpaqueOp : EmitC_Op<"call_opaque", [CExpression]> {
283+
def EmitC_CallOpaqueOp : EmitC_Op<"call_opaque", [CExpressionInterface]> {
269284
let summary = "Opaque call operation";
270285
let description = [{
271286
The `emitc.call_opaque` operation represents a C++ function call. The callee
@@ -312,7 +327,7 @@ def EmitC_CallOpaqueOp : EmitC_Op<"call_opaque", [CExpression]> {
312327
}
313328

314329
def EmitC_CastOp : EmitC_Op<"cast",
315-
[CExpression,
330+
[CExpressionInterface,
316331
DeclareOpInterfaceMethods<CastOpInterface>]> {
317332
let summary = "Cast operation";
318333
let description = [{
@@ -335,9 +350,15 @@ def EmitC_CastOp : EmitC_Op<"cast",
335350
let arguments = (ins EmitCType:$source);
336351
let results = (outs EmitCType:$dest);
337352
let assemblyFormat = "$source attr-dict `:` type($source) `to` type($dest)";
353+
354+
let extraClassDeclaration = [{
355+
bool hasSideEffects() {
356+
return false;
357+
}
358+
}];
338359
}
339360

340-
def EmitC_CmpOp : EmitC_BinaryOp<"cmp", [CExpression]> {
361+
def EmitC_CmpOp : EmitC_BinaryOp<"cmp", []> {
341362
let summary = "Comparison operation";
342363
let description = [{
343364
With the `emitc.cmp` operation the comparison operators ==, !=, <, <=, >, >=, <=>
@@ -407,7 +428,7 @@ def EmitC_ConstantOp : EmitC_Op<"constant", [ConstantLike]> {
407428
let hasVerifier = 1;
408429
}
409430

410-
def EmitC_DivOp : EmitC_BinaryOp<"div", [CExpression]> {
431+
def EmitC_DivOp : EmitC_BinaryOp<"div", []> {
411432
let summary = "Division operation";
412433
let description = [{
413434
With the `emitc.div` operation the arithmetic operator / (division) can
@@ -462,7 +483,7 @@ def EmitC_ExpressionOp : EmitC_Op<"expression",
462483
```
463484

464485
The operations allowed within expression body are EmitC operations with the
465-
CExpression trait.
486+
CExpressionInterface interface.
466487

467488
When specified, the optional `do_not_inline` indicates that the expression is
468489
to be emitted as seen above, i.e. as the rhs of an EmitC SSA value
@@ -480,18 +501,8 @@ def EmitC_ExpressionOp : EmitC_Op<"expression",
480501
let extraClassDeclaration = [{
481502
bool hasSideEffects() {
482503
auto predicate = [](Operation &op) {
483-
assert(op.hasTrait<OpTrait::emitc::CExpression>() && "Expected a C expression");
484-
// Conservatively assume calls to read and write memory.
485-
if (isa<emitc::CallOpaqueOp>(op))
486-
return true;
487-
// De-referencing reads modifiable memory, address-taking has no
488-
// side-effect.
489-
auto applyOp = dyn_cast<emitc::ApplyOp>(op);
490-
if (applyOp)
491-
return applyOp.getApplicableOperator() == "*";
492-
// Any load operation is assumed to read from memory and thus perform
493-
// a side effect.
494-
return isa<emitc::LoadOp>(op);
504+
assert(isa<emitc::CExpressionInterface>(op) && "Expected a C expression");
505+
return cast<emitc::CExpressionInterface>(op).hasSideEffects();
495506
};
496507
return llvm::any_of(getRegion().front().without_terminator(), predicate);
497508
};
@@ -579,7 +590,7 @@ def EmitC_ForOp : EmitC_Op<"for",
579590
}
580591

581592
def EmitC_CallOp : EmitC_Op<"call",
582-
[CallOpInterface, CExpression,
593+
[CallOpInterface, CExpressionInterface,
583594
DeclareOpInterfaceMethods<SymbolUserOpInterface>]> {
584595
let summary = "Call operation";
585596
let description = [{
@@ -649,6 +660,10 @@ def EmitC_CallOp : EmitC_Op<"call",
649660
void setCalleeFromCallable(CallInterfaceCallable callee) {
650661
(*this)->setAttr("callee", cast<SymbolRefAttr>(callee));
651662
}
663+
664+
bool hasSideEffects() {
665+
return false;
666+
}
652667
}];
653668

654669
let assemblyFormat = [{
@@ -861,7 +876,7 @@ def EmitC_LiteralOp : EmitC_Op<"literal", [Pure]> {
861876
let assemblyFormat = "$value attr-dict `:` type($result)";
862877
}
863878

864-
def EmitC_LogicalAndOp : EmitC_BinaryOp<"logical_and", [CExpression]> {
879+
def EmitC_LogicalAndOp : EmitC_BinaryOp<"logical_and", []> {
865880
let summary = "Logical and operation";
866881
let description = [{
867882
With the `emitc.logical_and` operation the logical operator && (and) can
@@ -882,7 +897,7 @@ def EmitC_LogicalAndOp : EmitC_BinaryOp<"logical_and", [CExpression]> {
882897
let assemblyFormat = "operands attr-dict `:` type(operands)";
883898
}
884899

885-
def EmitC_LogicalNotOp : EmitC_UnaryOp<"logical_not", [CExpression]> {
900+
def EmitC_LogicalNotOp : EmitC_UnaryOp<"logical_not", []> {
886901
let summary = "Logical not operation";
887902
let description = [{
888903
With the `emitc.logical_not` operation the logical operator ! (negation) can
@@ -903,7 +918,7 @@ def EmitC_LogicalNotOp : EmitC_UnaryOp<"logical_not", [CExpression]> {
903918
let assemblyFormat = "operands attr-dict `:` type(operands)";
904919
}
905920

906-
def EmitC_LogicalOrOp : EmitC_BinaryOp<"logical_or", [CExpression]> {
921+
def EmitC_LogicalOrOp : EmitC_BinaryOp<"logical_or", []> {
907922
let summary = "Logical or operation";
908923
let description = [{
909924
With the `emitc.logical_or` operation the logical operator || (inclusive or)
@@ -924,7 +939,7 @@ def EmitC_LogicalOrOp : EmitC_BinaryOp<"logical_or", [CExpression]> {
924939
let assemblyFormat = "operands attr-dict `:` type(operands)";
925940
}
926941

927-
def EmitC_LoadOp : EmitC_Op<"load", [CExpression,
942+
def EmitC_LoadOp : EmitC_Op<"load", [CExpressionInterface,
928943
TypesMatchWith<"result type matches value type of 'operand'",
929944
"operand", "result",
930945
"::llvm::cast<LValueType>($_self).getValueType()">
@@ -953,7 +968,7 @@ def EmitC_LoadOp : EmitC_Op<"load", [CExpression,
953968
let assemblyFormat = "$operand attr-dict `:` type($operand)";
954969
}
955970

956-
def EmitC_MulOp : EmitC_BinaryOp<"mul", [CExpression]> {
971+
def EmitC_MulOp : EmitC_BinaryOp<"mul", []> {
957972
let summary = "Multiplication operation";
958973
let description = [{
959974
With the `emitc.mul` operation the arithmetic operator * (multiplication) can
@@ -977,7 +992,7 @@ def EmitC_MulOp : EmitC_BinaryOp<"mul", [CExpression]> {
977992
let results = (outs FloatIntegerIndexOrOpaqueType);
978993
}
979994

980-
def EmitC_RemOp : EmitC_BinaryOp<"rem", [CExpression]> {
995+
def EmitC_RemOp : EmitC_BinaryOp<"rem", []> {
981996
let summary = "Remainder operation";
982997
let description = [{
983998
With the `emitc.rem` operation the arithmetic operator % (remainder) can
@@ -999,7 +1014,7 @@ def EmitC_RemOp : EmitC_BinaryOp<"rem", [CExpression]> {
9991014
let results = (outs IntegerIndexOrOpaqueType);
10001015
}
10011016

1002-
def EmitC_SubOp : EmitC_BinaryOp<"sub", [CExpression]> {
1017+
def EmitC_SubOp : EmitC_BinaryOp<"sub", []> {
10031018
let summary = "Subtraction operation";
10041019
let description = [{
10051020
With the `emitc.sub` operation the arithmetic operator - (subtraction) can
@@ -1069,7 +1084,7 @@ def EmitC_MemberOfPtrOp : EmitC_Op<"member_of_ptr"> {
10691084
}
10701085

10711086
def EmitC_ConditionalOp : EmitC_Op<"conditional",
1072-
[AllTypesMatch<["true_value", "false_value", "result"]>, CExpression]> {
1087+
[AllTypesMatch<["true_value", "false_value", "result"]>, CExpressionInterface]> {
10731088
let summary = "Conditional (ternary) operation";
10741089
let description = [{
10751090
With the `emitc.conditional` operation the ternary conditional operator can
@@ -1096,9 +1111,15 @@ def EmitC_ConditionalOp : EmitC_Op<"conditional",
10961111
let arguments = (ins I1:$condition, EmitCType:$true_value, EmitCType:$false_value);
10971112
let results = (outs EmitCType:$result);
10981113
let assemblyFormat = "operands attr-dict `:` type($result)";
1114+
1115+
let extraClassDeclaration = [{
1116+
bool hasSideEffects() {
1117+
return false;
1118+
}
1119+
}];
10991120
}
11001121

1101-
def EmitC_UnaryMinusOp : EmitC_UnaryOp<"unary_minus", [CExpression]> {
1122+
def EmitC_UnaryMinusOp : EmitC_UnaryOp<"unary_minus", []> {
11021123
let summary = "Unary minus operation";
11031124
let description = [{
11041125
With the `emitc.unary_minus` operation the unary operator - (minus) can be
@@ -1116,7 +1137,7 @@ def EmitC_UnaryMinusOp : EmitC_UnaryOp<"unary_minus", [CExpression]> {
11161137
}];
11171138
}
11181139

1119-
def EmitC_UnaryPlusOp : EmitC_UnaryOp<"unary_plus", [CExpression]> {
1140+
def EmitC_UnaryPlusOp : EmitC_UnaryOp<"unary_plus", []> {
11201141
let summary = "Unary plus operation";
11211142
let description = [{
11221143
With the `emitc.unary_plus` operation the unary operator + (plus) can be
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//===- EmitCInterfaces.h - EmitC interfaces definitions ---------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file declares C++ classes for some of the interfaces used in the EmitC
10+
// dialect.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef MLIR_DIALECT_EMITC_IR_EMITCINTERFACES_H
15+
#define MLIR_DIALECT_EMITC_IR_EMITCINTERFACES_H
16+
17+
#include "mlir/IR/OpDefinition.h"
18+
19+
namespace mlir {
20+
namespace emitc {
21+
//
22+
} // namespace emitc
23+
} // namespace mlir
24+
25+
//===----------------------------------------------------------------------===//
26+
// EmitC Dialect Interfaces
27+
//===----------------------------------------------------------------------===//
28+
29+
#include "mlir/Dialect/EmitC/IR/EmitCInterfaces.h.inc"
30+
31+
#endif // MLIR_DIALECT_EMITC_IR_EMITCINTERFACES_H

0 commit comments

Comments
 (0)