Skip to content

Commit 7ac03e8

Browse files
authored
[mlir][EmitC] Add bitwise operators (#83387)
This adds operations for bitwise operators. Furthermore, an UnaryOp class and a helper to print unary operations are introduced.
1 parent 2d98d76 commit 7ac03e8

File tree

4 files changed

+207
-14
lines changed

4 files changed

+207
-14
lines changed

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

Lines changed: 117 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,14 @@ include "mlir/IR/RegionKindInterface.td"
3131
class EmitC_Op<string mnemonic, list<Trait> traits = []>
3232
: Op<EmitC_Dialect, mnemonic, traits>;
3333

34+
// Base class for unary operations.
35+
class EmitC_UnaryOp<string mnemonic, list<Trait> traits = []> :
36+
EmitC_Op<mnemonic, traits> {
37+
let arguments = (ins AnyType);
38+
let results = (outs AnyType);
39+
let assemblyFormat = "operands attr-dict `:` functional-type(operands, results)";
40+
}
41+
3442
// Base class for binary operations.
3543
class EmitC_BinaryOp<string mnemonic, list<Trait> traits = []> :
3644
EmitC_Op<mnemonic, traits> {
@@ -95,6 +103,114 @@ def EmitC_ApplyOp : EmitC_Op<"apply", []> {
95103
let hasVerifier = 1;
96104
}
97105

106+
def EmitC_BitwiseAndOp : EmitC_BinaryOp<"bitwise_and", []> {
107+
let summary = "Bitwise and operation";
108+
let description = [{
109+
With the `bitwise_and` operation the bitwise operator & (and) can
110+
be applied.
111+
112+
Example:
113+
114+
```mlir
115+
%0 = emitc.bitwise_and %arg0, %arg1 : (i32, i32) -> i32
116+
```
117+
```c++
118+
// Code emitted for the operation above.
119+
int32_t v3 = v1 & v2;
120+
```
121+
}];
122+
}
123+
124+
def EmitC_BitwiseLeftShiftOp : EmitC_BinaryOp<"bitwise_left_shift", []> {
125+
let summary = "Bitwise left shift operation";
126+
let description = [{
127+
With the `bitwise_left_shift` operation the bitwise operator <<
128+
(left shift) can be applied.
129+
130+
Example:
131+
132+
```mlir
133+
%0 = emitc.bitwise_left_shift %arg0, %arg1 : (i32, i32) -> i32
134+
```
135+
```c++
136+
// Code emitted for the operation above.
137+
int32_t v3 = v1 << v2;
138+
```
139+
}];
140+
}
141+
142+
def EmitC_BitwiseNotOp : EmitC_UnaryOp<"bitwise_not", []> {
143+
let summary = "Bitwise not operation";
144+
let description = [{
145+
With the `bitwise_not` operation the bitwise operator ~ (not) can
146+
be applied.
147+
148+
Example:
149+
150+
```mlir
151+
%0 = emitc.bitwise_not %arg0 : (i32) -> i32
152+
```
153+
```c++
154+
// Code emitted for the operation above.
155+
int32_t v2 = ~v1;
156+
```
157+
}];
158+
}
159+
160+
def EmitC_BitwiseOrOp : EmitC_BinaryOp<"bitwise_or", []> {
161+
let summary = "Bitwise or operation";
162+
let description = [{
163+
With the `bitwise_or` operation the bitwise operator | (or)
164+
can be applied.
165+
166+
Example:
167+
168+
```mlir
169+
%0 = emitc.bitwise_or %arg0, %arg1 : (i32, i32) -> i32
170+
```
171+
```c++
172+
// Code emitted for the operation above.
173+
int32_t v3 = v1 | v2;
174+
```
175+
}];
176+
}
177+
178+
def EmitC_BitwiseRightShiftOp : EmitC_BinaryOp<"bitwise_right_shift", []> {
179+
let summary = "Bitwise right shift operation";
180+
let description = [{
181+
With the `bitwise_right_shift` operation the bitwise operator >>
182+
(right shift) can be applied.
183+
184+
Example:
185+
186+
```mlir
187+
%0 = emitc.bitwise_right_shift %arg0, %arg1 : (i32, i32) -> i32
188+
```
189+
```c++
190+
// Code emitted for the operation above.
191+
int32_t v3 = v1 >> v2;
192+
```
193+
}];
194+
}
195+
196+
def EmitC_BitwiseXorOp : EmitC_BinaryOp<"bitwise_xor", []> {
197+
let summary = "Bitwise xor operation";
198+
let description = [{
199+
With the `bitwise_xor` operation the bitwise operator ^ (xor)
200+
can be applied.
201+
202+
Example:
203+
204+
```mlir
205+
%0 = emitc.bitwise_xor %arg0, %arg1 : (i32, i32) -> i32
206+
```
207+
```c++
208+
// Code emitted for the operation above.
209+
int32_t v3 = v1 ^ v2;
210+
```
211+
}];
212+
}
213+
98214
def EmitC_CallOpaqueOp : EmitC_Op<"call_opaque", []> {
99215
let summary = "Opaque call operation";
100216
let description = [{
@@ -679,7 +795,7 @@ def EmitC_LogicalAndOp : EmitC_BinaryOp<"logical_and", []> {
679795
let assemblyFormat = "operands attr-dict `:` type(operands)";
680796
}
681797

682-
def EmitC_LogicalNotOp : EmitC_Op<"logical_not", []> {
798+
def EmitC_LogicalNotOp : EmitC_UnaryOp<"logical_not", []> {
683799
let summary = "Logical not operation";
684800
let description = [{
685801
With the `logical_not` operation the logical operator ! (negation) can
@@ -696,7 +812,6 @@ def EmitC_LogicalNotOp : EmitC_Op<"logical_not", []> {
696812
```
697813
}];
698814

699-
let arguments = (ins AnyType);
700815
let results = (outs I1);
701816
let assemblyFormat = "operands attr-dict `:` type(operands)";
702817
}

mlir/lib/Target/Cpp/TranslateToCpp.cpp

Lines changed: 60 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,22 @@ static LogicalResult printBinaryOperation(CppEmitter &emitter,
361361
return success();
362362
}
363363

364+
static LogicalResult printUnaryOperation(CppEmitter &emitter,
365+
Operation *operation,
366+
StringRef unaryOperator) {
367+
raw_ostream &os = emitter.ostream();
368+
369+
if (failed(emitter.emitAssignPrefix(*operation)))
370+
return failure();
371+
372+
os << unaryOperator;
373+
374+
if (failed(emitter.emitOperand(operation->getOperand(0))))
375+
return failure();
376+
377+
return success();
378+
}
379+
364380
static LogicalResult printOperation(CppEmitter &emitter, emitc::AddOp addOp) {
365381
Operation *operation = addOp.getOperation();
366382

@@ -588,6 +604,44 @@ static LogicalResult printOperation(CppEmitter &emitter,
588604
return success();
589605
}
590606

607+
static LogicalResult printOperation(CppEmitter &emitter,
608+
emitc::BitwiseAndOp bitwiseAndOp) {
609+
Operation *operation = bitwiseAndOp.getOperation();
610+
return printBinaryOperation(emitter, operation, "&");
611+
}
612+
613+
static LogicalResult
614+
printOperation(CppEmitter &emitter,
615+
emitc::BitwiseLeftShiftOp bitwiseLeftShiftOp) {
616+
Operation *operation = bitwiseLeftShiftOp.getOperation();
617+
return printBinaryOperation(emitter, operation, "<<");
618+
}
619+
620+
static LogicalResult printOperation(CppEmitter &emitter,
621+
emitc::BitwiseNotOp bitwiseNotOp) {
622+
Operation *operation = bitwiseNotOp.getOperation();
623+
return printUnaryOperation(emitter, operation, "~");
624+
}
625+
626+
static LogicalResult printOperation(CppEmitter &emitter,
627+
emitc::BitwiseOrOp bitwiseOrOp) {
628+
Operation *operation = bitwiseOrOp.getOperation();
629+
return printBinaryOperation(emitter, operation, "|");
630+
}
631+
632+
static LogicalResult
633+
printOperation(CppEmitter &emitter,
634+
emitc::BitwiseRightShiftOp bitwiseRightShiftOp) {
635+
Operation *operation = bitwiseRightShiftOp.getOperation();
636+
return printBinaryOperation(emitter, operation, ">>");
637+
}
638+
639+
static LogicalResult printOperation(CppEmitter &emitter,
640+
emitc::BitwiseXorOp bitwiseXorOp) {
641+
Operation *operation = bitwiseXorOp.getOperation();
642+
return printBinaryOperation(emitter, operation, "^");
643+
}
644+
591645
static LogicalResult printOperation(CppEmitter &emitter, emitc::CastOp castOp) {
592646
raw_ostream &os = emitter.ostream();
593647
Operation &op = *castOp.getOperation();
@@ -635,17 +689,8 @@ static LogicalResult printOperation(CppEmitter &emitter,
635689

636690
static LogicalResult printOperation(CppEmitter &emitter,
637691
emitc::LogicalNotOp logicalNotOp) {
638-
raw_ostream &os = emitter.ostream();
639-
640-
if (failed(emitter.emitAssignPrefix(*logicalNotOp.getOperation())))
641-
return failure();
642-
643-
os << "!";
644-
645-
if (failed(emitter.emitOperand(logicalNotOp.getOperand())))
646-
return failure();
647-
648-
return success();
692+
Operation *operation = logicalNotOp.getOperation();
693+
return printUnaryOperation(emitter, operation, "!");
649694
}
650695

651696
static LogicalResult printOperation(CppEmitter &emitter,
@@ -1307,7 +1352,10 @@ LogicalResult CppEmitter::emitOperation(Operation &op, bool trailingSemicolon) {
13071352
.Case<cf::BranchOp, cf::CondBranchOp>(
13081353
[&](auto op) { return printOperation(*this, op); })
13091354
// EmitC ops.
1310-
.Case<emitc::AddOp, emitc::ApplyOp, emitc::AssignOp, emitc::CallOp,
1355+
.Case<emitc::AddOp, emitc::ApplyOp, emitc::AssignOp,
1356+
emitc::BitwiseAndOp, emitc::BitwiseLeftShiftOp,
1357+
emitc::BitwiseNotOp, emitc::BitwiseOrOp,
1358+
emitc::BitwiseRightShiftOp, emitc::BitwiseXorOp, emitc::CallOp,
13111359
emitc::CallOpaqueOp, emitc::CastOp, emitc::CmpOp,
13121360
emitc::ConstantOp, emitc::DeclareFuncOp, emitc::DivOp,
13131361
emitc::ExpressionOp, emitc::ForOp, emitc::FuncOp, emitc::IfOp,

mlir/test/Dialect/EmitC/ops.mlir

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,16 @@ func.func @add_pointer(%arg0: !emitc.ptr<f32>, %arg1: i32, %arg2: !emitc.opaque<
6161
return
6262
}
6363

64+
func.func @bitwise(%arg0: i32, %arg1: i32) -> () {
65+
%0 = emitc.bitwise_and %arg0, %arg1 : (i32, i32) -> i32
66+
%1 = emitc.bitwise_left_shift %arg0, %arg1 : (i32, i32) -> i32
67+
%2 = emitc.bitwise_not %arg0 : (i32) -> i32
68+
%3 = emitc.bitwise_or %arg0, %arg1 : (i32, i32) -> i32
69+
%4 = emitc.bitwise_right_shift %arg0, %arg1 : (i32, i32) -> i32
70+
%5 = emitc.bitwise_xor %arg0, %arg1 : (i32, i32) -> i32
71+
return
72+
}
73+
6474
func.func @div_int(%arg0: i32, %arg1: i32) {
6575
%1 = "emitc.div" (%arg0, %arg1) : (i32, i32) -> i32
6676
return
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: mlir-translate -mlir-to-cpp %s | FileCheck %s
2+
3+
func.func @bitwise(%arg0: i32, %arg1: i32) -> () {
4+
%0 = emitc.bitwise_and %arg0, %arg1 : (i32, i32) -> i32
5+
%1 = emitc.bitwise_left_shift %arg0, %arg1 : (i32, i32) -> i32
6+
%2 = emitc.bitwise_not %arg0 : (i32) -> i32
7+
%3 = emitc.bitwise_or %arg0, %arg1 : (i32, i32) -> i32
8+
%4 = emitc.bitwise_right_shift %arg0, %arg1 : (i32, i32) -> i32
9+
%5 = emitc.bitwise_xor %arg0, %arg1 : (i32, i32) -> i32
10+
11+
return
12+
}
13+
14+
// CHECK-LABEL: void bitwise
15+
// CHECK-NEXT: int32_t [[V2:[^ ]*]] = [[V0:[^ ]*]] & [[V1:[^ ]*]];
16+
// CHECK-NEXT: int32_t [[V3:[^ ]*]] = [[V0]] << [[V1]];
17+
// CHECK-NEXT: int32_t [[V4:[^ ]*]] = ~[[V0]];
18+
// CHECK-NEXT: int32_t [[V5:[^ ]*]] = [[V0]] | [[V1]];
19+
// CHECK-NEXT: int32_t [[V6:[^ ]*]] = [[V0]] >> [[V1]];
20+
// CHECK-NEXT: int32_t [[V7:[^ ]*]] = [[V0]] ^ [[V1]];

0 commit comments

Comments
 (0)