Skip to content

Commit 12fcca0

Browse files
authored
[mlir][emitc] Lower arith.andi, arith.ori, arith.xori to EmitC
This commit lowers bitwise arith ops to EmitC and also brings in `adaptValueType` and `adaptIntegralTypeSignedness` that other ArithToEmitC functions can benefit from.
1 parent 22a7f7c commit 12fcca0

File tree

2 files changed

+101
-0
lines changed

2 files changed

+101
-0
lines changed

mlir/lib/Conversion/ArithToEmitC/ArithToEmitC.cpp

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,25 @@ class ArithConstantOpConversionPattern
4040
}
4141
};
4242

43+
/// Get the signed or unsigned type corresponding to \p ty.
44+
Type adaptIntegralTypeSignedness(Type ty, bool needsUnsigned) {
45+
if (isa<IntegerType>(ty)) {
46+
if (ty.isUnsignedInteger() != needsUnsigned) {
47+
auto signedness = needsUnsigned
48+
? IntegerType::SignednessSemantics::Unsigned
49+
: IntegerType::SignednessSemantics::Signed;
50+
return IntegerType::get(ty.getContext(), ty.getIntOrFloatBitWidth(),
51+
signedness);
52+
}
53+
}
54+
return ty;
55+
}
56+
57+
/// Insert a cast operation to type \p ty if \p val does not have this type.
58+
Value adaptValueType(Value val, ConversionPatternRewriter &rewriter, Type ty) {
59+
return rewriter.createOrFold<emitc::CastOp>(val.getLoc(), ty, val);
60+
}
61+
4362
class CmpIOpConversion : public OpConversionPattern<arith::CmpIOp> {
4463
public:
4564
using OpConversionPattern::OpConversionPattern;
@@ -265,6 +284,46 @@ class IntegerOpConversion final : public OpConversionPattern<ArithOp> {
265284
}
266285
};
267286

287+
template <typename ArithOp, typename EmitCOp>
288+
class BitwiseOpConversion : public OpConversionPattern<ArithOp> {
289+
public:
290+
using OpConversionPattern<ArithOp>::OpConversionPattern;
291+
292+
LogicalResult
293+
matchAndRewrite(ArithOp op, typename ArithOp::Adaptor adaptor,
294+
ConversionPatternRewriter &rewriter) const override {
295+
296+
Type type = this->getTypeConverter()->convertType(op.getType());
297+
if (!isa_and_nonnull<IntegerType>(type)) {
298+
return rewriter.notifyMatchFailure(
299+
op,
300+
"expected integer type, vector/tensor support not yet implemented");
301+
}
302+
303+
// Bitwise ops can be performed directly on booleans
304+
if (type.isInteger(1)) {
305+
rewriter.replaceOpWithNewOp<EmitCOp>(op, type, adaptor.getLhs(),
306+
adaptor.getRhs());
307+
return success();
308+
}
309+
310+
// Bitwise ops are defined by the C standard on unsigned operands.
311+
Type arithmeticType =
312+
adaptIntegralTypeSignedness(type, /*needsUnsigned=*/true);
313+
314+
Value lhs = adaptValueType(adaptor.getLhs(), rewriter, arithmeticType);
315+
Value rhs = adaptValueType(adaptor.getRhs(), rewriter, arithmeticType);
316+
317+
Value arithmeticResult = rewriter.template create<EmitCOp>(
318+
op.getLoc(), arithmeticType, lhs, rhs);
319+
320+
Value result = adaptValueType(arithmeticResult, rewriter, type);
321+
322+
rewriter.replaceOp(op, result);
323+
return success();
324+
}
325+
};
326+
268327
class SelectOpConversion : public OpConversionPattern<arith::SelectOp> {
269328
public:
270329
using OpConversionPattern<arith::SelectOp>::OpConversionPattern;
@@ -401,6 +460,9 @@ void mlir::populateArithToEmitCPatterns(TypeConverter &typeConverter,
401460
IntegerOpConversion<arith::AddIOp, emitc::AddOp>,
402461
IntegerOpConversion<arith::MulIOp, emitc::MulOp>,
403462
IntegerOpConversion<arith::SubIOp, emitc::SubOp>,
463+
BitwiseOpConversion<arith::AndIOp, emitc::BitwiseAndOp>,
464+
BitwiseOpConversion<arith::OrIOp, emitc::BitwiseOrOp>,
465+
BitwiseOpConversion<arith::XOrIOp, emitc::BitwiseXorOp>,
404466
CmpIOpConversion,
405467
SelectOpConversion,
406468
// Truncation is guaranteed for unsigned types.

mlir/test/Conversion/ArithToEmitC/arith-to-emitc.mlir

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,45 @@ func.func @arith_index(%arg0: index, %arg1: index) {
8888

8989
// -----
9090

91+
// CHECK-LABEL: arith_bitwise
92+
// CHECK-SAME: %[[ARG0:.*]]: i32, %[[ARG1:.*]]: i32
93+
func.func @arith_bitwise(%arg0: i32, %arg1: i32) {
94+
// CHECK: %[[C1:[^ ]*]] = emitc.cast %[[ARG0]] : i32 to ui32
95+
// CHECK: %[[C2:[^ ]*]] = emitc.cast %[[ARG1]] : i32 to ui32
96+
// CHECK: %[[AND:[^ ]*]] = emitc.bitwise_and %[[C1]], %[[C2]] : (ui32, ui32) -> ui32
97+
// CHECK: %[[C3:[^ ]*]] = emitc.cast %[[AND]] : ui32 to i32
98+
%0 = arith.andi %arg0, %arg1 : i32
99+
// CHECK: %[[C1:[^ ]*]] = emitc.cast %[[ARG0]] : i32 to ui32
100+
// CHECK: %[[C2:[^ ]*]] = emitc.cast %[[ARG1]] : i32 to ui32
101+
// CHECK: %[[OR:[^ ]*]] = emitc.bitwise_or %[[C1]], %[[C2]] : (ui32, ui32) -> ui32
102+
// CHECK: %[[C3:[^ ]*]] = emitc.cast %[[OR]] : ui32 to i32
103+
%1 = arith.ori %arg0, %arg1 : i32
104+
// CHECK: %[[C1:[^ ]*]] = emitc.cast %[[ARG0]] : i32 to ui32
105+
// CHECK: %[[C2:[^ ]*]] = emitc.cast %[[ARG1]] : i32 to ui32
106+
// CHECK: %[[XOR:[^ ]*]] = emitc.bitwise_xor %[[C1]], %[[C2]] : (ui32, ui32) -> ui32
107+
// CHECK: %[[C3:[^ ]*]] = emitc.cast %[[XOR]] : ui32 to i32
108+
%2 = arith.xori %arg0, %arg1 : i32
109+
110+
return
111+
}
112+
113+
// -----
114+
115+
// CHECK-LABEL: arith_bitwise_bool
116+
// CHECK-SAME: %[[ARG0:.*]]: i1, %[[ARG1:.*]]: i1
117+
func.func @arith_bitwise_bool(%arg0: i1, %arg1: i1) {
118+
// CHECK: %[[AND:[^ ]*]] = emitc.bitwise_and %[[ARG0]], %[[ARG1]] : (i1, i1) -> i1
119+
%0 = arith.andi %arg0, %arg1 : i1
120+
// CHECK: %[[OR:[^ ]*]] = emitc.bitwise_or %[[ARG0]], %[[ARG1]] : (i1, i1) -> i1
121+
%1 = arith.ori %arg0, %arg1 : i1
122+
// CHECK: %[[xor:[^ ]*]] = emitc.bitwise_xor %[[ARG0]], %[[ARG1]] : (i1, i1) -> i1
123+
%2 = arith.xori %arg0, %arg1 : i1
124+
125+
return
126+
}
127+
128+
// -----
129+
91130
// CHECK-LABEL: arith_signed_integer_div_rem
92131
func.func @arith_signed_integer_div_rem(%arg0: i32, %arg1: i32) {
93132
// CHECK: emitc.div %arg0, %arg1 : (i32, i32) -> i32

0 commit comments

Comments
 (0)