[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.
This commit is contained in:
parent
22a7f7c331
commit
12fcca0afe
@ -40,6 +40,25 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/// Get the signed or unsigned type corresponding to \p ty.
|
||||
Type adaptIntegralTypeSignedness(Type ty, bool needsUnsigned) {
|
||||
if (isa<IntegerType>(ty)) {
|
||||
if (ty.isUnsignedInteger() != needsUnsigned) {
|
||||
auto signedness = needsUnsigned
|
||||
? IntegerType::SignednessSemantics::Unsigned
|
||||
: IntegerType::SignednessSemantics::Signed;
|
||||
return IntegerType::get(ty.getContext(), ty.getIntOrFloatBitWidth(),
|
||||
signedness);
|
||||
}
|
||||
}
|
||||
return ty;
|
||||
}
|
||||
|
||||
/// Insert a cast operation to type \p ty if \p val does not have this type.
|
||||
Value adaptValueType(Value val, ConversionPatternRewriter &rewriter, Type ty) {
|
||||
return rewriter.createOrFold<emitc::CastOp>(val.getLoc(), ty, val);
|
||||
}
|
||||
|
||||
class CmpIOpConversion : public OpConversionPattern<arith::CmpIOp> {
|
||||
public:
|
||||
using OpConversionPattern::OpConversionPattern;
|
||||
@ -265,6 +284,46 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ArithOp, typename EmitCOp>
|
||||
class BitwiseOpConversion : public OpConversionPattern<ArithOp> {
|
||||
public:
|
||||
using OpConversionPattern<ArithOp>::OpConversionPattern;
|
||||
|
||||
LogicalResult
|
||||
matchAndRewrite(ArithOp op, typename ArithOp::Adaptor adaptor,
|
||||
ConversionPatternRewriter &rewriter) const override {
|
||||
|
||||
Type type = this->getTypeConverter()->convertType(op.getType());
|
||||
if (!isa_and_nonnull<IntegerType>(type)) {
|
||||
return rewriter.notifyMatchFailure(
|
||||
op,
|
||||
"expected integer type, vector/tensor support not yet implemented");
|
||||
}
|
||||
|
||||
// Bitwise ops can be performed directly on booleans
|
||||
if (type.isInteger(1)) {
|
||||
rewriter.replaceOpWithNewOp<EmitCOp>(op, type, adaptor.getLhs(),
|
||||
adaptor.getRhs());
|
||||
return success();
|
||||
}
|
||||
|
||||
// Bitwise ops are defined by the C standard on unsigned operands.
|
||||
Type arithmeticType =
|
||||
adaptIntegralTypeSignedness(type, /*needsUnsigned=*/true);
|
||||
|
||||
Value lhs = adaptValueType(adaptor.getLhs(), rewriter, arithmeticType);
|
||||
Value rhs = adaptValueType(adaptor.getRhs(), rewriter, arithmeticType);
|
||||
|
||||
Value arithmeticResult = rewriter.template create<EmitCOp>(
|
||||
op.getLoc(), arithmeticType, lhs, rhs);
|
||||
|
||||
Value result = adaptValueType(arithmeticResult, rewriter, type);
|
||||
|
||||
rewriter.replaceOp(op, result);
|
||||
return success();
|
||||
}
|
||||
};
|
||||
|
||||
class SelectOpConversion : public OpConversionPattern<arith::SelectOp> {
|
||||
public:
|
||||
using OpConversionPattern<arith::SelectOp>::OpConversionPattern;
|
||||
@ -401,6 +460,9 @@ void mlir::populateArithToEmitCPatterns(TypeConverter &typeConverter,
|
||||
IntegerOpConversion<arith::AddIOp, emitc::AddOp>,
|
||||
IntegerOpConversion<arith::MulIOp, emitc::MulOp>,
|
||||
IntegerOpConversion<arith::SubIOp, emitc::SubOp>,
|
||||
BitwiseOpConversion<arith::AndIOp, emitc::BitwiseAndOp>,
|
||||
BitwiseOpConversion<arith::OrIOp, emitc::BitwiseOrOp>,
|
||||
BitwiseOpConversion<arith::XOrIOp, emitc::BitwiseXorOp>,
|
||||
CmpIOpConversion,
|
||||
SelectOpConversion,
|
||||
// Truncation is guaranteed for unsigned types.
|
||||
|
@ -88,6 +88,45 @@ func.func @arith_index(%arg0: index, %arg1: index) {
|
||||
|
||||
// -----
|
||||
|
||||
// CHECK-LABEL: arith_bitwise
|
||||
// CHECK-SAME: %[[ARG0:.*]]: i32, %[[ARG1:.*]]: i32
|
||||
func.func @arith_bitwise(%arg0: i32, %arg1: i32) {
|
||||
// CHECK: %[[C1:[^ ]*]] = emitc.cast %[[ARG0]] : i32 to ui32
|
||||
// CHECK: %[[C2:[^ ]*]] = emitc.cast %[[ARG1]] : i32 to ui32
|
||||
// CHECK: %[[AND:[^ ]*]] = emitc.bitwise_and %[[C1]], %[[C2]] : (ui32, ui32) -> ui32
|
||||
// CHECK: %[[C3:[^ ]*]] = emitc.cast %[[AND]] : ui32 to i32
|
||||
%0 = arith.andi %arg0, %arg1 : i32
|
||||
// CHECK: %[[C1:[^ ]*]] = emitc.cast %[[ARG0]] : i32 to ui32
|
||||
// CHECK: %[[C2:[^ ]*]] = emitc.cast %[[ARG1]] : i32 to ui32
|
||||
// CHECK: %[[OR:[^ ]*]] = emitc.bitwise_or %[[C1]], %[[C2]] : (ui32, ui32) -> ui32
|
||||
// CHECK: %[[C3:[^ ]*]] = emitc.cast %[[OR]] : ui32 to i32
|
||||
%1 = arith.ori %arg0, %arg1 : i32
|
||||
// CHECK: %[[C1:[^ ]*]] = emitc.cast %[[ARG0]] : i32 to ui32
|
||||
// CHECK: %[[C2:[^ ]*]] = emitc.cast %[[ARG1]] : i32 to ui32
|
||||
// CHECK: %[[XOR:[^ ]*]] = emitc.bitwise_xor %[[C1]], %[[C2]] : (ui32, ui32) -> ui32
|
||||
// CHECK: %[[C3:[^ ]*]] = emitc.cast %[[XOR]] : ui32 to i32
|
||||
%2 = arith.xori %arg0, %arg1 : i32
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// CHECK-LABEL: arith_bitwise_bool
|
||||
// CHECK-SAME: %[[ARG0:.*]]: i1, %[[ARG1:.*]]: i1
|
||||
func.func @arith_bitwise_bool(%arg0: i1, %arg1: i1) {
|
||||
// CHECK: %[[AND:[^ ]*]] = emitc.bitwise_and %[[ARG0]], %[[ARG1]] : (i1, i1) -> i1
|
||||
%0 = arith.andi %arg0, %arg1 : i1
|
||||
// CHECK: %[[OR:[^ ]*]] = emitc.bitwise_or %[[ARG0]], %[[ARG1]] : (i1, i1) -> i1
|
||||
%1 = arith.ori %arg0, %arg1 : i1
|
||||
// CHECK: %[[xor:[^ ]*]] = emitc.bitwise_xor %[[ARG0]], %[[ARG1]] : (i1, i1) -> i1
|
||||
%2 = arith.xori %arg0, %arg1 : i1
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// CHECK-LABEL: arith_signed_integer_div_rem
|
||||
func.func @arith_signed_integer_div_rem(%arg0: i32, %arg1: i32) {
|
||||
// CHECK: emitc.div %arg0, %arg1 : (i32, i32) -> i32
|
||||
|
Loading…
x
Reference in New Issue
Block a user