Skip to content

Commit bd3d808

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 bd3d808

File tree

10 files changed

+158
-78
lines changed

10 files changed

+158
-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: 63 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
@@ -308,11 +325,12 @@ def EmitC_CallOpaqueOp : EmitC_Op<"call_opaque", [CExpression]> {
308325
let assemblyFormat = [{
309326
$callee `(` $operands `)` attr-dict `:` functional-type($operands, results)
310327
}];
328+
311329
let hasVerifier = 1;
312330
}
313331

314332
def EmitC_CastOp : EmitC_Op<"cast",
315-
[CExpression,
333+
[CExpressionInterface,
316334
DeclareOpInterfaceMethods<CastOpInterface>]> {
317335
let summary = "Cast operation";
318336
let description = [{
@@ -335,9 +353,15 @@ def EmitC_CastOp : EmitC_Op<"cast",
335353
let arguments = (ins EmitCType:$source);
336354
let results = (outs EmitCType:$dest);
337355
let assemblyFormat = "$source attr-dict `:` type($source) `to` type($dest)";
356+
357+
let extraClassDeclaration = [{
358+
bool hasSideEffects() {
359+
return false;
360+
}
361+
}];
338362
}
339363

340-
def EmitC_CmpOp : EmitC_BinaryOp<"cmp", [CExpression]> {
364+
def EmitC_CmpOp : EmitC_BinaryOp<"cmp", [CExpressionInterface]> {
341365
let summary = "Comparison operation";
342366
let description = [{
343367
With the `emitc.cmp` operation the comparison operators ==, !=, <, <=, >, >=, <=>
@@ -407,7 +431,7 @@ def EmitC_ConstantOp : EmitC_Op<"constant", [ConstantLike]> {
407431
let hasVerifier = 1;
408432
}
409433

410-
def EmitC_DivOp : EmitC_BinaryOp<"div", [CExpression]> {
434+
def EmitC_DivOp : EmitC_BinaryOp<"div", [CExpressionInterface]> {
411435
let summary = "Division operation";
412436
let description = [{
413437
With the `emitc.div` operation the arithmetic operator / (division) can
@@ -462,7 +486,7 @@ def EmitC_ExpressionOp : EmitC_Op<"expression",
462486
```
463487

464488
The operations allowed within expression body are EmitC operations with the
465-
CExpression trait.
489+
CExpressionInterface interface.
466490

467491
When specified, the optional `do_not_inline` indicates that the expression is
468492
to be emitted as seen above, i.e. as the rhs of an EmitC SSA value
@@ -480,18 +504,8 @@ def EmitC_ExpressionOp : EmitC_Op<"expression",
480504
let extraClassDeclaration = [{
481505
bool hasSideEffects() {
482506
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);
507+
assert(isa<emitc::CExpressionInterface>(op) && "Expected a C expression");
508+
return cast<emitc::CExpressionInterface>(op).hasSideEffects();
495509
};
496510
return llvm::any_of(getRegion().front().without_terminator(), predicate);
497511
};
@@ -579,7 +593,7 @@ def EmitC_ForOp : EmitC_Op<"for",
579593
}
580594

581595
def EmitC_CallOp : EmitC_Op<"call",
582-
[CallOpInterface, CExpression,
596+
[CallOpInterface, CExpressionInterface,
583597
DeclareOpInterfaceMethods<SymbolUserOpInterface>]> {
584598
let summary = "Call operation";
585599
let description = [{
@@ -649,6 +663,10 @@ def EmitC_CallOp : EmitC_Op<"call",
649663
void setCalleeFromCallable(CallInterfaceCallable callee) {
650664
(*this)->setAttr("callee", cast<SymbolRefAttr>(callee));
651665
}
666+
667+
bool hasSideEffects() {
668+
return false;
669+
}
652670
}];
653671

654672
let assemblyFormat = [{
@@ -861,7 +879,7 @@ def EmitC_LiteralOp : EmitC_Op<"literal", [Pure]> {
861879
let assemblyFormat = "$value attr-dict `:` type($result)";
862880
}
863881

864-
def EmitC_LogicalAndOp : EmitC_BinaryOp<"logical_and", [CExpression]> {
882+
def EmitC_LogicalAndOp : EmitC_BinaryOp<"logical_and", [CExpressionInterface]> {
865883
let summary = "Logical and operation";
866884
let description = [{
867885
With the `emitc.logical_and` operation the logical operator && (and) can
@@ -882,7 +900,7 @@ def EmitC_LogicalAndOp : EmitC_BinaryOp<"logical_and", [CExpression]> {
882900
let assemblyFormat = "operands attr-dict `:` type(operands)";
883901
}
884902

885-
def EmitC_LogicalNotOp : EmitC_UnaryOp<"logical_not", [CExpression]> {
903+
def EmitC_LogicalNotOp : EmitC_UnaryOp<"logical_not", [CExpressionInterface]> {
886904
let summary = "Logical not operation";
887905
let description = [{
888906
With the `emitc.logical_not` operation the logical operator ! (negation) can
@@ -903,7 +921,7 @@ def EmitC_LogicalNotOp : EmitC_UnaryOp<"logical_not", [CExpression]> {
903921
let assemblyFormat = "operands attr-dict `:` type(operands)";
904922
}
905923

906-
def EmitC_LogicalOrOp : EmitC_BinaryOp<"logical_or", [CExpression]> {
924+
def EmitC_LogicalOrOp : EmitC_BinaryOp<"logical_or", [CExpressionInterface]> {
907925
let summary = "Logical or operation";
908926
let description = [{
909927
With the `emitc.logical_or` operation the logical operator || (inclusive or)
@@ -924,7 +942,7 @@ def EmitC_LogicalOrOp : EmitC_BinaryOp<"logical_or", [CExpression]> {
924942
let assemblyFormat = "operands attr-dict `:` type(operands)";
925943
}
926944

927-
def EmitC_LoadOp : EmitC_Op<"load", [CExpression,
945+
def EmitC_LoadOp : EmitC_Op<"load", [CExpressionInterface,
928946
TypesMatchWith<"result type matches value type of 'operand'",
929947
"operand", "result",
930948
"::llvm::cast<LValueType>($_self).getValueType()">
@@ -953,7 +971,7 @@ def EmitC_LoadOp : EmitC_Op<"load", [CExpression,
953971
let assemblyFormat = "$operand attr-dict `:` type($operand)";
954972
}
955973

956-
def EmitC_MulOp : EmitC_BinaryOp<"mul", [CExpression]> {
974+
def EmitC_MulOp : EmitC_BinaryOp<"mul", [CExpressionInterface]> {
957975
let summary = "Multiplication operation";
958976
let description = [{
959977
With the `emitc.mul` operation the arithmetic operator * (multiplication) can
@@ -977,7 +995,7 @@ def EmitC_MulOp : EmitC_BinaryOp<"mul", [CExpression]> {
977995
let results = (outs FloatIntegerIndexOrOpaqueType);
978996
}
979997

980-
def EmitC_RemOp : EmitC_BinaryOp<"rem", [CExpression]> {
998+
def EmitC_RemOp : EmitC_BinaryOp<"rem", [CExpressionInterface]> {
981999
let summary = "Remainder operation";
9821000
let description = [{
9831001
With the `emitc.rem` operation the arithmetic operator % (remainder) can
@@ -999,7 +1017,7 @@ def EmitC_RemOp : EmitC_BinaryOp<"rem", [CExpression]> {
9991017
let results = (outs IntegerIndexOrOpaqueType);
10001018
}
10011019

1002-
def EmitC_SubOp : EmitC_BinaryOp<"sub", [CExpression]> {
1020+
def EmitC_SubOp : EmitC_BinaryOp<"sub", [CExpressionInterface]> {
10031021
let summary = "Subtraction operation";
10041022
let description = [{
10051023
With the `emitc.sub` operation the arithmetic operator - (subtraction) can
@@ -1069,7 +1087,7 @@ def EmitC_MemberOfPtrOp : EmitC_Op<"member_of_ptr"> {
10691087
}
10701088

10711089
def EmitC_ConditionalOp : EmitC_Op<"conditional",
1072-
[AllTypesMatch<["true_value", "false_value", "result"]>, CExpression]> {
1090+
[AllTypesMatch<["true_value", "false_value", "result"]>, CExpressionInterface]> {
10731091
let summary = "Conditional (ternary) operation";
10741092
let description = [{
10751093
With the `emitc.conditional` operation the ternary conditional operator can
@@ -1096,9 +1114,15 @@ def EmitC_ConditionalOp : EmitC_Op<"conditional",
10961114
let arguments = (ins I1:$condition, EmitCType:$true_value, EmitCType:$false_value);
10971115
let results = (outs EmitCType:$result);
10981116
let assemblyFormat = "operands attr-dict `:` type($result)";
1117+
1118+
let extraClassDeclaration = [{
1119+
bool hasSideEffects() {
1120+
return false;
1121+
}
1122+
}];
10991123
}
11001124

1101-
def EmitC_UnaryMinusOp : EmitC_UnaryOp<"unary_minus", [CExpression]> {
1125+
def EmitC_UnaryMinusOp : EmitC_UnaryOp<"unary_minus", [CExpressionInterface]> {
11021126
let summary = "Unary minus operation";
11031127
let description = [{
11041128
With the `emitc.unary_minus` operation the unary operator - (minus) can be
@@ -1116,7 +1140,7 @@ def EmitC_UnaryMinusOp : EmitC_UnaryOp<"unary_minus", [CExpression]> {
11161140
}];
11171141
}
11181142

1119-
def EmitC_UnaryPlusOp : EmitC_UnaryOp<"unary_plus", [CExpression]> {
1143+
def EmitC_UnaryPlusOp : EmitC_UnaryOp<"unary_plus", [CExpressionInterface]> {
11201144
let summary = "Unary plus operation";
11211145
let description = [{
11221146
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)