[mlir][emitc] Add compound assignment ops (#210233)
This commit is contained in:
parent
8c556564a2
commit
8ae7803bed
6 changed files with 206 additions and 22 deletions
|
|
@ -88,6 +88,20 @@ class EmitC_IncDecOp<string mnemonic, string summaryStr>
|
|||
}];
|
||||
}
|
||||
|
||||
// Base class for compound assignment operations.
|
||||
class EmitC_CompoundAssignOp<string mnemonic, string summaryStr>
|
||||
: EmitC_Op<mnemonic, []> {
|
||||
let summary = summaryStr;
|
||||
let arguments = (ins
|
||||
Res<EmitC_LValueType, "",
|
||||
[MemRead<DefaultResource, 0, FullEffect>,
|
||||
MemWrite<DefaultResource, 0, FullEffect>]>:$var,
|
||||
EmitCType:$value);
|
||||
let results = (outs);
|
||||
let hasVerifier = 1;
|
||||
let assemblyFormat = "$value `:` type($value) `to` $var `:` type($var) attr-dict";
|
||||
}
|
||||
|
||||
// Types only used in binary arithmetic operations.
|
||||
def IntegerIndexOrOpaqueType : Type<CPred<"emitc::isIntegerIndexOrOpaqueType($_self)">,
|
||||
"integer, index or opaque type supported by EmitC">;
|
||||
|
|
@ -1591,6 +1605,76 @@ def EmitC_AssignOp : EmitC_Op<"assign", []> {
|
|||
let assemblyFormat = "$value `:` type($value) `to` $var `:` type($var) attr-dict";
|
||||
}
|
||||
|
||||
def EmitC_AddAssignOp
|
||||
: EmitC_CompoundAssignOp<"add_assign", "Addition assignment operation"> {
|
||||
let description = [{
|
||||
The `emitc.add_assign` operation applies the C/C++ `+=` operator to an
|
||||
lvalue.
|
||||
|
||||
Example:
|
||||
|
||||
```mlir
|
||||
emitc.add_assign %value : i32 to %var : !emitc.lvalue<i32>
|
||||
```
|
||||
}];
|
||||
}
|
||||
|
||||
def EmitC_SubAssignOp
|
||||
: EmitC_CompoundAssignOp<"sub_assign", "Subtraction assignment operation"> {
|
||||
let description = [{
|
||||
The `emitc.sub_assign` operation applies the C/C++ `-=` operator to an
|
||||
lvalue.
|
||||
|
||||
Example:
|
||||
|
||||
```mlir
|
||||
emitc.sub_assign %value : i32 to %var : !emitc.lvalue<i32>
|
||||
```
|
||||
}];
|
||||
}
|
||||
|
||||
def EmitC_MulAssignOp
|
||||
: EmitC_CompoundAssignOp<"mul_assign", "Multiplication assignment operation"> {
|
||||
let description = [{
|
||||
The `emitc.mul_assign` operation applies the C/C++ `*=` operator to an
|
||||
lvalue.
|
||||
|
||||
Example:
|
||||
|
||||
```mlir
|
||||
emitc.mul_assign %value : i32 to %var : !emitc.lvalue<i32>
|
||||
```
|
||||
}];
|
||||
}
|
||||
|
||||
def EmitC_DivAssignOp
|
||||
: EmitC_CompoundAssignOp<"div_assign", "Division assignment operation"> {
|
||||
let description = [{
|
||||
The `emitc.div_assign` operation applies the C/C++ `/=` operator to an
|
||||
lvalue.
|
||||
|
||||
Example:
|
||||
|
||||
```mlir
|
||||
emitc.div_assign %value : i32 to %var : !emitc.lvalue<i32>
|
||||
```
|
||||
}];
|
||||
}
|
||||
|
||||
def EmitC_RemAssignOp
|
||||
: EmitC_CompoundAssignOp<"rem_assign", "Remainder assignment operation"> {
|
||||
let description = [{
|
||||
The `emitc.rem_assign` operation applies the C/C++ `%=` operator to an
|
||||
lvalue.
|
||||
|
||||
Example:
|
||||
|
||||
```mlir
|
||||
emitc.rem_assign %value : i32 to %var : !emitc.lvalue<i32>
|
||||
```
|
||||
}];
|
||||
}
|
||||
|
||||
def EmitC_YieldOp : EmitC_Op<"yield",
|
||||
[Pure, Terminator, ParentOneOf<["DoOp", "ExpressionOp", "ForOp", "IfOp", "SwitchOp"]>]> {
|
||||
let summary = "Block termination operation";
|
||||
|
|
|
|||
|
|
@ -263,27 +263,38 @@ LogicalResult AddOp::verify() {
|
|||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// AssignOp
|
||||
// Assignment operations
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// The assign op requires that the assigned value's type matches the
|
||||
/// assigned-to variable type.
|
||||
LogicalResult emitc::AssignOp::verify() {
|
||||
TypedValue<emitc::LValueType> variable = getVar();
|
||||
template <typename AssignmentOp>
|
||||
static LogicalResult verifyAssignmentOp(AssignmentOp op) {
|
||||
TypedValue<emitc::LValueType> variable = op.getVar();
|
||||
|
||||
if (!variable.getDefiningOp())
|
||||
return emitOpError() << "cannot assign to block argument";
|
||||
return op.emitOpError() << "cannot assign to block argument";
|
||||
|
||||
Type valueType = getValue().getType();
|
||||
Type valueType = op.getValue().getType();
|
||||
Type variableType = variable.getType().getValueType();
|
||||
if (variableType != valueType)
|
||||
return emitOpError() << "requires value's type (" << valueType
|
||||
<< ") to match variable's type (" << variableType
|
||||
<< ")\n variable: " << variable
|
||||
<< "\n value: " << getValue() << "\n";
|
||||
return op.emitOpError() << "requires value's type (" << valueType
|
||||
<< ") to match variable's type (" << variableType
|
||||
<< ")\n variable: " << variable
|
||||
<< "\n value: " << op.getValue() << "\n";
|
||||
return success();
|
||||
}
|
||||
|
||||
LogicalResult emitc::AssignOp::verify() { return verifyAssignmentOp(*this); }
|
||||
|
||||
LogicalResult emitc::AddAssignOp::verify() { return verifyAssignmentOp(*this); }
|
||||
|
||||
LogicalResult emitc::SubAssignOp::verify() { return verifyAssignmentOp(*this); }
|
||||
|
||||
LogicalResult emitc::MulAssignOp::verify() { return verifyAssignmentOp(*this); }
|
||||
|
||||
LogicalResult emitc::DivAssignOp::verify() { return verifyAssignmentOp(*this); }
|
||||
|
||||
LogicalResult emitc::RemAssignOp::verify() { return verifyAssignmentOp(*this); }
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CastOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
|||
|
|
@ -608,6 +608,42 @@ static LogicalResult printOperation(CppEmitter &emitter,
|
|||
return emitter.emitOperand(assignOp.getValue());
|
||||
}
|
||||
|
||||
static LogicalResult
|
||||
printCompoundAssignmentOperation(CppEmitter &emitter, Operation *operation,
|
||||
StringRef compoundAssignmentOperator) {
|
||||
if (failed(emitter.emitOperand(operation->getOperand(0))))
|
||||
return failure();
|
||||
|
||||
emitter.ostream() << " " << compoundAssignmentOperator << " ";
|
||||
|
||||
return emitter.emitOperand(operation->getOperand(1));
|
||||
}
|
||||
|
||||
static LogicalResult printOperation(CppEmitter &emitter,
|
||||
emitc::AddAssignOp addAssignOp) {
|
||||
return printCompoundAssignmentOperation(emitter, addAssignOp, "+=");
|
||||
}
|
||||
|
||||
static LogicalResult printOperation(CppEmitter &emitter,
|
||||
emitc::SubAssignOp subAssignOp) {
|
||||
return printCompoundAssignmentOperation(emitter, subAssignOp, "-=");
|
||||
}
|
||||
|
||||
static LogicalResult printOperation(CppEmitter &emitter,
|
||||
emitc::MulAssignOp mulAssignOp) {
|
||||
return printCompoundAssignmentOperation(emitter, mulAssignOp, "*=");
|
||||
}
|
||||
|
||||
static LogicalResult printOperation(CppEmitter &emitter,
|
||||
emitc::DivAssignOp divAssignOp) {
|
||||
return printCompoundAssignmentOperation(emitter, divAssignOp, "/=");
|
||||
}
|
||||
|
||||
static LogicalResult printOperation(CppEmitter &emitter,
|
||||
emitc::RemAssignOp remAssignOp) {
|
||||
return printCompoundAssignmentOperation(emitter, remAssignOp, "%=");
|
||||
}
|
||||
|
||||
static LogicalResult printOperation(CppEmitter &emitter, emitc::LoadOp loadOp) {
|
||||
if (failed(emitter.emitAssignPrefix(*loadOp)))
|
||||
return failure();
|
||||
|
|
@ -1927,25 +1963,26 @@ LogicalResult CppEmitter::emitOperation(Operation &op, bool trailingSemicolon) {
|
|||
.Case<cf::BranchOp, cf::CondBranchOp>(
|
||||
[&](auto op) { return printOperation(*this, op); })
|
||||
// EmitC ops.
|
||||
.Case<emitc::AddressOfOp, emitc::AddOp, emitc::AssignOp,
|
||||
emitc::BitwiseAndOp, emitc::BitwiseLeftShiftOp,
|
||||
.Case<emitc::AddAssignOp, emitc::AddressOfOp, emitc::AddOp,
|
||||
emitc::AssignOp, emitc::BitwiseAndOp, emitc::BitwiseLeftShiftOp,
|
||||
emitc::BitwiseNotOp, emitc::BitwiseOrOp,
|
||||
emitc::BitwiseRightShiftOp, emitc::BitwiseXorOp, emitc::CallOp,
|
||||
emitc::CallOpaqueOp, emitc::CastOp, emitc::ClassOp,
|
||||
emitc::CmpOp, emitc::ConditionalOp, emitc::ConstantOp,
|
||||
emitc::DeclareFuncOp, emitc::DereferenceOp, emitc::DivOp,
|
||||
emitc::DoOp, emitc::ExpressionOp, emitc::FieldOp, emitc::FileOp,
|
||||
emitc::ForOp, emitc::FuncOp, emitc::GetFieldOp,
|
||||
emitc::DeclareFuncOp, emitc::DereferenceOp, emitc::DivAssignOp,
|
||||
emitc::DivOp, emitc::DoOp, emitc::ExpressionOp, emitc::FieldOp,
|
||||
emitc::FileOp, emitc::ForOp, emitc::FuncOp, emitc::GetFieldOp,
|
||||
emitc::GetGlobalOp, emitc::GlobalOp, emitc::IfOp,
|
||||
emitc::IncludeOp, emitc::LiteralOp, emitc::LoadOp,
|
||||
emitc::LogicalAndOp, emitc::LogicalNotOp, emitc::LogicalOrOp,
|
||||
emitc::MemberCallOpaqueOp, emitc::MemberOfPtrOp,
|
||||
emitc::MemberOp, emitc::MulOp, emitc::PostDecrementOp,
|
||||
emitc::PostIncrementOp, emitc::PreDecrementOp,
|
||||
emitc::PreIncrementOp, emitc::RemOp, emitc::ReturnOp,
|
||||
emitc::SubscriptOp, emitc::SubOp, emitc::SwitchOp,
|
||||
emitc::UnaryMinusOp, emitc::UnaryPlusOp, emitc::VariableOp,
|
||||
emitc::VerbatimOp>(
|
||||
emitc::MemberOp, emitc::MulAssignOp, emitc::MulOp,
|
||||
emitc::PostDecrementOp, emitc::PostIncrementOp,
|
||||
emitc::PreDecrementOp, emitc::PreIncrementOp,
|
||||
emitc::RemAssignOp, emitc::RemOp, emitc::ReturnOp,
|
||||
emitc::SubAssignOp, emitc::SubscriptOp, emitc::SubOp,
|
||||
emitc::SwitchOp, emitc::UnaryMinusOp, emitc::UnaryPlusOp,
|
||||
emitc::VariableOp, emitc::VerbatimOp>(
|
||||
|
||||
[&](auto op) { return printOperation(*this, op); })
|
||||
// Func ops.
|
||||
|
|
|
|||
|
|
@ -997,3 +997,20 @@ func.func @post_decrement_unmatch_type(%arg0: !emitc.lvalue<i32>) {
|
|||
%1 = "emitc.post_decrement"(%arg0) : (!emitc.lvalue<i32>) -> i8
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
func.func @add_assign_to_block_argument(%arg0: i32, %arg1: !emitc.lvalue<i32>) {
|
||||
// expected-error @+1 {{'emitc.add_assign' op cannot assign to block argument}}
|
||||
emitc.add_assign %arg0 : i32 to %arg1 : !emitc.lvalue<i32>
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
func.func @sub_assign_type_mismatch(%arg0: f32) {
|
||||
%v = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue<i32>
|
||||
// expected-error @+1 {{'emitc.sub_assign' op requires value's type ('f32') to match variable's type ('i32')}}
|
||||
emitc.sub_assign %arg0 : f32 to %v : !emitc.lvalue<i32>
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -187,6 +187,23 @@ func.func @test_assign(%arg1: f32) {
|
|||
return
|
||||
}
|
||||
|
||||
// CHECK-LABEL: func.func @compound_assign
|
||||
// CHECK: emitc.add_assign
|
||||
// CHECK: emitc.sub_assign
|
||||
// CHECK: emitc.mul_assign
|
||||
// CHECK: emitc.div_assign
|
||||
// CHECK: emitc.rem_assign
|
||||
func.func @compound_assign(%arg0: i32, %arg1: !emitc.opaque<"number">) {
|
||||
%v = "emitc.variable"() <{value = 0 : i32}> : () -> !emitc.lvalue<i32>
|
||||
%opaque = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue<!emitc.opaque<"number">>
|
||||
emitc.add_assign %arg0 : i32 to %v : !emitc.lvalue<i32>
|
||||
emitc.sub_assign %arg0 : i32 to %v : !emitc.lvalue<i32>
|
||||
emitc.mul_assign %arg0 : i32 to %v : !emitc.lvalue<i32>
|
||||
emitc.div_assign %arg0 : i32 to %v : !emitc.lvalue<i32>
|
||||
emitc.rem_assign %arg1 : !emitc.opaque<"number"> to %opaque : !emitc.lvalue<!emitc.opaque<"number">>
|
||||
return
|
||||
}
|
||||
|
||||
func.func @test_expression(%arg0: i32, %arg1: i32, %arg2: i32, %arg3: f32, %arg4: f32) -> i32 {
|
||||
%c7 = "emitc.constant"() {value = 7 : i32} : () -> i32
|
||||
%q = emitc.expression %arg1, %c7 : (i32, i32) -> i32 {
|
||||
|
|
|
|||
|
|
@ -122,6 +122,24 @@ func.func @inc_dec() {
|
|||
return
|
||||
}
|
||||
|
||||
// CHECK-LABEL: void compound_assign(
|
||||
// CHECK-SAME: int32_t [[ARG0:[^ ]*]]) {
|
||||
func.func @compound_assign(%arg0: i32) {
|
||||
// CHECK-NEXT: int32_t [[V1:[^ ]*]] = 0;
|
||||
%v = "emitc.variable"() <{value = 0 : i32}> : () -> !emitc.lvalue<i32>
|
||||
// CHECK-NEXT: [[V1]] += [[ARG0]];
|
||||
emitc.add_assign %arg0 : i32 to %v : !emitc.lvalue<i32>
|
||||
// CHECK-NEXT: [[V1]] -= [[ARG0]];
|
||||
emitc.sub_assign %arg0 : i32 to %v : !emitc.lvalue<i32>
|
||||
// CHECK-NEXT: [[V1]] *= [[ARG0]];
|
||||
emitc.mul_assign %arg0 : i32 to %v : !emitc.lvalue<i32>
|
||||
// CHECK-NEXT: [[V1]] /= [[ARG0]];
|
||||
emitc.div_assign %arg0 : i32 to %v : !emitc.lvalue<i32>
|
||||
// CHECK-NEXT: [[V1]] %= [[ARG0]];
|
||||
emitc.rem_assign %arg0 : i32 to %v : !emitc.lvalue<i32>
|
||||
return
|
||||
}
|
||||
|
||||
// CHECK-LABEL: int32_t inc_dec_expression() {
|
||||
func.func @inc_dec_expression() -> i32 {
|
||||
// CHECK-NEXT: int32_t [[V1:[^ ]*]] = 0;
|
||||
|
|
|
|||
Loading…
Reference in a new issue