Skip to content

Commit d8affab

Browse files
committed
[mlir][emitc] make CExpression trait into interface
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 detection logic. It also allows checking for side effects of each operation individually.
1 parent 7efc861 commit d8affab

File tree

10 files changed

+157
-78
lines changed

10 files changed

+157
-78
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: 62 additions & 39 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"
@@ -39,6 +40,12 @@ class EmitC_UnaryOp<string mnemonic, list<Trait> traits = []> :
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.
@@ -47,10 +54,13 @@ class EmitC_BinaryOp<string mnemonic, list<Trait> traits = []> :
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", [CExpressionInterface]> {
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", [CExpressionInterface]> {
159176
let summary = "Bitwise and operation";
160177
let description = [{
161178
With the `emitc.bitwise_and` operation the bitwise operator & (and) can
@@ -174,7 +191,7 @@ def EmitC_BitwiseAndOp : EmitC_BinaryOp<"bitwise_and", [CExpression]> {
174191
}
175192

176193
def EmitC_BitwiseLeftShiftOp : EmitC_BinaryOp<"bitwise_left_shift",
177-
[CExpression]> {
194+
[CExpressionInterface]> {
178195
let summary = "Bitwise left shift operation";
179196
let description = [{
180197
With the `emitc.bitwise_left_shift` operation the bitwise operator <<
@@ -192,7 +209,7 @@ def EmitC_BitwiseLeftShiftOp : EmitC_BinaryOp<"bitwise_left_shift",
192209
}];
193210
}
194211

195-
def EmitC_BitwiseNotOp : EmitC_UnaryOp<"bitwise_not", [CExpression]> {
212+
def EmitC_BitwiseNotOp : EmitC_UnaryOp<"bitwise_not", [CExpressionInterface]> {
196213
let summary = "Bitwise not operation";
197214
let description = [{
198215
With the `emitc.bitwise_not` operation the bitwise operator ~ (not) can
@@ -210,7 +227,7 @@ def EmitC_BitwiseNotOp : EmitC_UnaryOp<"bitwise_not", [CExpression]> {
210227
}];
211228
}
212229

213-
def EmitC_BitwiseOrOp : EmitC_BinaryOp<"bitwise_or", [CExpression]> {
230+
def EmitC_BitwiseOrOp : EmitC_BinaryOp<"bitwise_or", [CExpressionInterface]> {
214231
let summary = "Bitwise or operation";
215232
let description = [{
216233
With the `emitc.bitwise_or` operation the bitwise operator | (or)
@@ -229,7 +246,7 @@ def EmitC_BitwiseOrOp : EmitC_BinaryOp<"bitwise_or", [CExpression]> {
229246
}
230247

231248
def EmitC_BitwiseRightShiftOp : EmitC_BinaryOp<"bitwise_right_shift",
232-
[CExpression]> {
249+
[CExpressionInterface]> {
233250
let summary = "Bitwise right shift operation";
234251
let description = [{
235252
With the `emitc.bitwise_right_shift` operation the bitwise operator >>
@@ -247,7 +264,7 @@ def EmitC_BitwiseRightShiftOp : EmitC_BinaryOp<"bitwise_right_shift",
247264
}];
248265
}
249266

250-
def EmitC_BitwiseXorOp : EmitC_BinaryOp<"bitwise_xor", [CExpression]> {
267+
def EmitC_BitwiseXorOp : EmitC_BinaryOp<"bitwise_xor", [CExpressionInterface]> {
251268
let summary = "Bitwise xor operation";
252269
let description = [{
253270
With the `emitc.bitwise_xor` operation the bitwise operator ^ (xor)
@@ -265,7 +282,7 @@ def EmitC_BitwiseXorOp : EmitC_BinaryOp<"bitwise_xor", [CExpression]> {
265282
}];
266283
}
267284

268-
def EmitC_CallOpaqueOp : EmitC_Op<"call_opaque", [CExpression]> {
285+
def EmitC_CallOpaqueOp : EmitC_Op<"call_opaque", [CExpressionInterface]> {
269286
let summary = "Opaque call operation";
270287
let description = [{
271288
The `emitc.call_opaque` operation represents a C++ function call. The callee
@@ -312,7 +329,7 @@ def EmitC_CallOpaqueOp : EmitC_Op<"call_opaque", [CExpression]> {
312329
}
313330

314331
def EmitC_CastOp : EmitC_Op<"cast",
315-
[CExpression,
332+
[CExpressionInterface,
316333
DeclareOpInterfaceMethods<CastOpInterface>]> {
317334
let summary = "Cast operation";
318335
let description = [{
@@ -335,9 +352,15 @@ def EmitC_CastOp : EmitC_Op<"cast",
335352
let arguments = (ins EmitCType:$source);
336353
let results = (outs EmitCType:$dest);
337354
let assemblyFormat = "$source attr-dict `:` type($source) `to` type($dest)";
355+
356+
let extraClassDeclaration = [{
357+
bool hasSideEffects() {
358+
return false;
359+
}
360+
}];
338361
}
339362

340-
def EmitC_CmpOp : EmitC_BinaryOp<"cmp", [CExpression]> {
363+
def EmitC_CmpOp : EmitC_BinaryOp<"cmp", [CExpressionInterface]> {
341364
let summary = "Comparison operation";
342365
let description = [{
343366
With the `emitc.cmp` operation the comparison operators ==, !=, <, <=, >, >=, <=>
@@ -407,7 +430,7 @@ def EmitC_ConstantOp : EmitC_Op<"constant", [ConstantLike]> {
407430
let hasVerifier = 1;
408431
}
409432

410-
def EmitC_DivOp : EmitC_BinaryOp<"div", [CExpression]> {
433+
def EmitC_DivOp : EmitC_BinaryOp<"div", [CExpressionInterface]> {
411434
let summary = "Division operation";
412435
let description = [{
413436
With the `emitc.div` operation the arithmetic operator / (division) can
@@ -462,7 +485,7 @@ def EmitC_ExpressionOp : EmitC_Op<"expression",
462485
```
463486

464487
The operations allowed within expression body are EmitC operations with the
465-
CExpression trait.
488+
CExpressionInterface interface.
466489

467490
When specified, the optional `do_not_inline` indicates that the expression is
468491
to be emitted as seen above, i.e. as the rhs of an EmitC SSA value
@@ -480,18 +503,8 @@ def EmitC_ExpressionOp : EmitC_Op<"expression",
480503
let extraClassDeclaration = [{
481504
bool hasSideEffects() {
482505
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);
506+
assert(isa<emitc::CExpressionInterface>(op) && "Expected a C expression");
507+
return cast<emitc::CExpressionInterface>(op).hasSideEffects();
495508
};
496509
return llvm::any_of(getRegion().front().without_terminator(), predicate);
497510
};
@@ -579,7 +592,7 @@ def EmitC_ForOp : EmitC_Op<"for",
579592
}
580593

581594
def EmitC_CallOp : EmitC_Op<"call",
582-
[CallOpInterface, CExpression,
595+
[CallOpInterface, CExpressionInterface,
583596
DeclareOpInterfaceMethods<SymbolUserOpInterface>]> {
584597
let summary = "Call operation";
585598
let description = [{
@@ -649,6 +662,10 @@ def EmitC_CallOp : EmitC_Op<"call",
649662
void setCalleeFromCallable(CallInterfaceCallable callee) {
650663
(*this)->setAttr("callee", cast<SymbolRefAttr>(callee));
651664
}
665+
666+
bool hasSideEffects() {
667+
return false;
668+
}
652669
}];
653670

654671
let assemblyFormat = [{
@@ -861,7 +878,7 @@ def EmitC_LiteralOp : EmitC_Op<"literal", [Pure]> {
861878
let assemblyFormat = "$value attr-dict `:` type($result)";
862879
}
863880

864-
def EmitC_LogicalAndOp : EmitC_BinaryOp<"logical_and", [CExpression]> {
881+
def EmitC_LogicalAndOp : EmitC_BinaryOp<"logical_and", [CExpressionInterface]> {
865882
let summary = "Logical and operation";
866883
let description = [{
867884
With the `emitc.logical_and` operation the logical operator && (and) can
@@ -882,7 +899,7 @@ def EmitC_LogicalAndOp : EmitC_BinaryOp<"logical_and", [CExpression]> {
882899
let assemblyFormat = "operands attr-dict `:` type(operands)";
883900
}
884901

885-
def EmitC_LogicalNotOp : EmitC_UnaryOp<"logical_not", [CExpression]> {
902+
def EmitC_LogicalNotOp : EmitC_UnaryOp<"logical_not", [CExpressionInterface]> {
886903
let summary = "Logical not operation";
887904
let description = [{
888905
With the `emitc.logical_not` operation the logical operator ! (negation) can
@@ -903,7 +920,7 @@ def EmitC_LogicalNotOp : EmitC_UnaryOp<"logical_not", [CExpression]> {
903920
let assemblyFormat = "operands attr-dict `:` type(operands)";
904921
}
905922

906-
def EmitC_LogicalOrOp : EmitC_BinaryOp<"logical_or", [CExpression]> {
923+
def EmitC_LogicalOrOp : EmitC_BinaryOp<"logical_or", [CExpressionInterface]> {
907924
let summary = "Logical or operation";
908925
let description = [{
909926
With the `emitc.logical_or` operation the logical operator || (inclusive or)
@@ -924,7 +941,7 @@ def EmitC_LogicalOrOp : EmitC_BinaryOp<"logical_or", [CExpression]> {
924941
let assemblyFormat = "operands attr-dict `:` type(operands)";
925942
}
926943

927-
def EmitC_LoadOp : EmitC_Op<"load", [CExpression,
944+
def EmitC_LoadOp : EmitC_Op<"load", [CExpressionInterface,
928945
TypesMatchWith<"result type matches value type of 'operand'",
929946
"operand", "result",
930947
"::llvm::cast<LValueType>($_self).getValueType()">
@@ -953,7 +970,7 @@ def EmitC_LoadOp : EmitC_Op<"load", [CExpression,
953970
let assemblyFormat = "$operand attr-dict `:` type($operand)";
954971
}
955972

956-
def EmitC_MulOp : EmitC_BinaryOp<"mul", [CExpression]> {
973+
def EmitC_MulOp : EmitC_BinaryOp<"mul", [CExpressionInterface]> {
957974
let summary = "Multiplication operation";
958975
let description = [{
959976
With the `emitc.mul` operation the arithmetic operator * (multiplication) can
@@ -977,7 +994,7 @@ def EmitC_MulOp : EmitC_BinaryOp<"mul", [CExpression]> {
977994
let results = (outs FloatIntegerIndexOrOpaqueType);
978995
}
979996

980-
def EmitC_RemOp : EmitC_BinaryOp<"rem", [CExpression]> {
997+
def EmitC_RemOp : EmitC_BinaryOp<"rem", [CExpressionInterface]> {
981998
let summary = "Remainder operation";
982999
let description = [{
9831000
With the `emitc.rem` operation the arithmetic operator % (remainder) can
@@ -999,7 +1016,7 @@ def EmitC_RemOp : EmitC_BinaryOp<"rem", [CExpression]> {
9991016
let results = (outs IntegerIndexOrOpaqueType);
10001017
}
10011018

1002-
def EmitC_SubOp : EmitC_BinaryOp<"sub", [CExpression]> {
1019+
def EmitC_SubOp : EmitC_BinaryOp<"sub", [CExpressionInterface]> {
10031020
let summary = "Subtraction operation";
10041021
let description = [{
10051022
With the `emitc.sub` operation the arithmetic operator - (subtraction) can
@@ -1069,7 +1086,7 @@ def EmitC_MemberOfPtrOp : EmitC_Op<"member_of_ptr"> {
10691086
}
10701087

10711088
def EmitC_ConditionalOp : EmitC_Op<"conditional",
1072-
[AllTypesMatch<["true_value", "false_value", "result"]>, CExpression]> {
1089+
[AllTypesMatch<["true_value", "false_value", "result"]>, CExpressionInterface]> {
10731090
let summary = "Conditional (ternary) operation";
10741091
let description = [{
10751092
With the `emitc.conditional` operation the ternary conditional operator can
@@ -1096,9 +1113,15 @@ def EmitC_ConditionalOp : EmitC_Op<"conditional",
10961113
let arguments = (ins I1:$condition, EmitCType:$true_value, EmitCType:$false_value);
10971114
let results = (outs EmitCType:$result);
10981115
let assemblyFormat = "operands attr-dict `:` type($result)";
1116+
1117+
let extraClassDeclaration = [{
1118+
bool hasSideEffects() {
1119+
return false;
1120+
}
1121+
}];
10991122
}
11001123

1101-
def EmitC_UnaryMinusOp : EmitC_UnaryOp<"unary_minus", [CExpression]> {
1124+
def EmitC_UnaryMinusOp : EmitC_UnaryOp<"unary_minus", [CExpressionInterface]> {
11021125
let summary = "Unary minus operation";
11031126
let description = [{
11041127
With the `emitc.unary_minus` operation the unary operator - (minus) can be
@@ -1116,7 +1139,7 @@ def EmitC_UnaryMinusOp : EmitC_UnaryOp<"unary_minus", [CExpression]> {
11161139
}];
11171140
}
11181141

1119-
def EmitC_UnaryPlusOp : EmitC_UnaryOp<"unary_plus", [CExpression]> {
1142+
def EmitC_UnaryPlusOp : EmitC_UnaryOp<"unary_plus", [CExpressionInterface]> {
11201143
let summary = "Unary plus operation";
11211144
let description = [{
11221145
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)