From 4560ca4b7fddc39cc43e122e8dab7bc6875c0610 Mon Sep 17 00:00:00 2001 From: Simon Camphausen Date: Tue, 4 Jun 2024 11:55:43 +0000 Subject: [PATCH 01/14] Add lvalue type --- mlir/include/mlir/Dialect/EmitC/IR/EmitC.td | 49 ++++++-- .../mlir/Dialect/EmitC/IR/EmitCTypes.td | 27 +++++ .../MemRefToEmitC/MemRefToEmitC.cpp | 7 +- mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp | 38 ++++++- mlir/lib/Dialect/EmitC/IR/EmitC.cpp | 107 +++++++++++++----- .../EmitC/Transforms/FormExpressions.cpp | 3 +- mlir/lib/Target/Cpp/TranslateToCpp.cpp | 18 ++- .../MemRefToEmitC/memref-to-emitc.mlir | 24 ++-- mlir/test/Conversion/SCFToEmitC/for.mlir | 46 ++++---- mlir/test/Conversion/SCFToEmitC/if.mlir | 22 ++-- mlir/test/Conversion/SCFToEmitC/switch.mlir | 34 +++--- mlir/test/Dialect/EmitC/invalid_ops.mlir | 92 +++++++-------- mlir/test/Dialect/EmitC/invalid_types.mlir | 66 ++++++++--- mlir/test/Dialect/EmitC/ops.mlir | 37 +++--- mlir/test/Dialect/EmitC/transforms.mlir | 48 ++------ mlir/test/Dialect/EmitC/types.mlir | 19 +++- mlir/test/Target/Cpp/common-cpp.mlir | 17 ++- mlir/test/Target/Cpp/expressions.mlir | 84 ++++++++------ mlir/test/Target/Cpp/for.mlir | 82 ++++++++++---- mlir/test/Target/Cpp/global.mlir | 32 ++++-- mlir/test/Target/Cpp/if.mlir | 12 +- mlir/test/Target/Cpp/invalid.mlir | 2 +- mlir/test/Target/Cpp/lvalue.mlir | 17 +++ mlir/test/Target/Cpp/member.mlir | 41 ++++--- mlir/test/Target/Cpp/subscript.mlir | 106 ++++++++++++----- mlir/test/Target/Cpp/switch.mlir | 56 ++++----- mlir/test/Target/Cpp/variable.mlir | 16 +-- 27 files changed, 714 insertions(+), 388 deletions(-) create mode 100644 mlir/test/Target/Cpp/lvalue.mlir diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td index 40903b4e288ca..0f876079d978b 100644 --- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td +++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td @@ -98,7 +98,7 @@ def EmitC_ApplyOp : EmitC_Op<"apply", [CExpression]> { }]; let arguments = (ins Arg:$applicableOperator, - EmitCType:$operand + AnyTypeOf<[EmitCType, EmitC_LValueType]>:$operand ); let results = (outs EmitCType:$result); let assemblyFormat = [{ @@ -836,6 +836,20 @@ def EmitC_LogicalOrOp : EmitC_BinaryOp<"logical_or", [CExpression]> { let assemblyFormat = "operands attr-dict `:` type(operands)"; } +def EmitC_LValueLoadOp : EmitC_Op<"lvalue_load", [ + TypesMatchWith<"result type matches value type of 'operand'", + "operand", "result", + "::llvm::cast($_self).getValue()"> +]> { + let summary = "load an lvalue by assigning it to a local variable"; + let description = [{}]; + + let arguments = (ins EmitC_LValueType:$operand); + let results = (outs AnyType:$result); + + let assemblyFormat = "$operand attr-dict `:` type($operand)"; +} + def EmitC_MulOp : EmitC_BinaryOp<"mul", [CExpression]> { let summary = "Multiplication operation"; let description = [{ @@ -924,9 +938,9 @@ def EmitC_MemberOp : EmitC_Op<"member"> { let arguments = (ins Arg:$member, - EmitC_OpaqueType:$operand + EmitC_LValueOf<[EmitC_OpaqueType]>:$operand ); - let results = (outs EmitCType); + let results = (outs EmitC_LValueOf<[EmitCType]>); } def EmitC_MemberOfPtrOp : EmitC_Op<"member_of_ptr"> { @@ -945,9 +959,9 @@ def EmitC_MemberOfPtrOp : EmitC_Op<"member_of_ptr"> { let arguments = (ins Arg:$member, - AnyTypeOf<[EmitC_OpaqueType,EmitC_PointerType]>:$operand + EmitC_LValueOf<[EmitC_OpaqueType,EmitC_PointerType]>:$operand ); - let results = (outs EmitCType); + let results = (outs EmitC_LValueOf<[EmitCType]>); } def EmitC_ConditionalOp : EmitC_Op<"conditional", @@ -1052,7 +1066,7 @@ def EmitC_VariableOp : EmitC_Op<"variable", []> { }]; let arguments = (ins EmitC_OpaqueOrTypedAttr:$value); - let results = (outs EmitCType); + let results = (outs AnyTypeOf<[EmitC_ArrayType, EmitC_LValueType]>); let hasVerifier = 1; } @@ -1122,7 +1136,7 @@ def EmitC_GetGlobalOp : EmitC_Op<"get_global", }]; let arguments = (ins FlatSymbolRefAttr:$name); - let results = (outs EmitCType:$result); + let results = (outs AnyTypeOf<[EmitC_ArrayType, EmitC_LValueType]>:$result); let assemblyFormat = "$name `:` type($result) attr-dict"; } @@ -1180,7 +1194,7 @@ def EmitC_AssignOp : EmitC_Op<"assign", []> { ``` }]; - let arguments = (ins EmitCType:$var, EmitCType:$value); + let arguments = (ins EmitC_LValueType:$var, EmitCType:$value); let results = (outs); let hasVerifier = 1; @@ -1286,15 +1300,26 @@ def EmitC_SubscriptOp : EmitC_Op<"subscript", []> { EmitC_PointerType]>, "the value to subscript">:$value, Variadic:$indices); - let results = (outs EmitCType:$result); + let results = (outs EmitC_LValueType:$result); let builders = [ OpBuilder<(ins "TypedValue":$array, "ValueRange":$indices), [{ - build($_builder, $_state, array.getType().getElementType(), array, indices); + build( + $_builder, + $_state, + emitc::LValueType::get(array.getType().getElementType()), + array, + indices + ); }]>, OpBuilder<(ins "TypedValue":$pointer, "Value":$index), [{ - build($_builder, $_state, pointer.getType().getPointee(), pointer, - ValueRange{index}); + build( + $_builder, + $_state, + emitc::LValueType::get(pointer.getType().getPointee()), + pointer, + ValueRange{index} + ); }]> ]; diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitCTypes.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitCTypes.td index 79f6d34fc91b1..b8169f43681b5 100644 --- a/mlir/include/mlir/Dialect/EmitC/IR/EmitCTypes.td +++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitCTypes.td @@ -84,6 +84,23 @@ def EmitC_ArrayType : EmitC_Type<"Array", "array", [ShapedTypeInterface]> { let hasCustomAssemblyFormat = 1; } +def EmitC_LValueType : EmitC_Type<"LValue", "lvalue"> { + let summary = "EmitC lvalue type"; + + let description = [{ + Values of this type can be assigned to and their address can be taken. + }]; + + let parameters = (ins "Type":$value); + let builders = [ + TypeBuilderWithInferredContext<(ins "Type":$value), [{ + return $_get(value.getContext(), value); + }]> + ]; + let assemblyFormat = "`<` qualified($value) `>`"; + let genVerifyDecl = 1; +} + def EmitC_OpaqueType : EmitC_Type<"Opaque", "opaque"> { let summary = "EmitC opaque type"; @@ -129,6 +146,7 @@ def EmitC_PointerType : EmitC_Type<"Pointer", "ptr"> { }]> ]; let assemblyFormat = "`<` qualified($pointee) `>`"; + let genVerifyDecl = 1; } def EmitC_SignedSizeT : EmitC_Type<"SignedSizeT", "ssize_t"> { @@ -158,4 +176,13 @@ def EmitC_SizeT : EmitC_Type<"SizeT", "size_t"> { }]; } +class EmitC_LValueOf allowedTypes> : + ContainerType< + AnyTypeOf, + CPred<"::llvm::isa<::mlir::emitc::LValueType>($_self)">, + "::llvm::cast<::mlir::emitc::LValueType>($_self).getValue()", + "emitc.lvalue", + "::mlir::emitc::LValueType" + >; + #endif // MLIR_DIALECT_EMITC_IR_EMITCTYPES diff --git a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp index e0c421741b305..2e8fbbad14d40 100644 --- a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp +++ b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp @@ -137,12 +137,7 @@ struct ConvertLoad final : public OpConversionPattern { auto subscript = rewriter.create( op.getLoc(), arrayValue, operands.getIndices()); - auto noInit = emitc::OpaqueAttr::get(getContext(), ""); - auto var = - rewriter.create(op.getLoc(), resultTy, noInit); - - rewriter.create(op.getLoc(), var, subscript); - rewriter.replaceOp(op, var); + rewriter.replaceOpWithNewOp(op, resultTy, subscript); return success(); } }; diff --git a/mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp b/mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp index ede811c6e1bb1..36f7f5b2f1eb9 100644 --- a/mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp +++ b/mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp @@ -63,9 +63,10 @@ static SmallVector createVariablesForResults(T op, for (OpResult result : op.getResults()) { Type resultType = result.getType(); + Type varType = emitc::LValueType::get(resultType); emitc::OpaqueAttr noInit = emitc::OpaqueAttr::get(context, ""); emitc::VariableOp var = - rewriter.create(loc, resultType, noInit); + rewriter.create(loc, varType, noInit); resultVariables.push_back(var); } @@ -80,6 +81,14 @@ static void assignValues(ValueRange values, SmallVector &variables, rewriter.create(loc, var, value); } +SmallVector loadValues(const SmallVector &variables, + PatternRewriter &rewriter, Location loc) { + return llvm::map_to_vector<>(variables, [&](Value var) { + Type type = cast(var.getType()).getValue(); + return rewriter.create(loc, type, var).getResult(); + }); +} + static void lowerYield(SmallVector &resultVariables, PatternRewriter &rewriter, scf::YieldOp yield) { Location loc = yield.getLoc(); @@ -126,15 +135,26 @@ LogicalResult ForLowering::matchAndRewrite(ForOp forOp, // Erase the auto-generated terminator for the lowered for op. rewriter.eraseOp(loweredBody->getTerminator()); + IRRewriter::InsertPoint ip = rewriter.saveInsertionPoint(); + rewriter.setInsertionPointToEnd(loweredBody); + + SmallVector iterArgsValues = + loadValues(resultVariables, rewriter, loc); + + rewriter.restoreInsertionPoint(ip); + SmallVector replacingValues; replacingValues.push_back(loweredFor.getInductionVar()); - replacingValues.append(resultVariables.begin(), resultVariables.end()); + replacingValues.append(iterArgsValues.begin(), iterArgsValues.end()); rewriter.mergeBlocks(forOp.getBody(), loweredBody, replacingValues); lowerYield(resultVariables, rewriter, cast(loweredBody->getTerminator())); - rewriter.replaceOp(forOp, resultVariables); + // Copy iterArgs into results after the for loop. + SmallVector resultValues = loadValues(resultVariables, rewriter, loc); + + rewriter.replaceOp(forOp, resultValues); return success(); } @@ -174,7 +194,10 @@ LogicalResult IfLowering::matchAndRewrite(IfOp ifOp, lowerRegion(resultVariables, rewriter, elseRegion, loweredElseRegion); } - rewriter.replaceOp(ifOp, resultVariables); + rewriter.setInsertionPointAfter(ifOp); + SmallVector results = loadValues(resultVariables, rewriter, loc); + + rewriter.replaceOp(ifOp, results); return success(); } @@ -212,7 +235,10 @@ IndexSwitchOpLowering::matchAndRewrite(IndexSwitchOp indexSwitchOp, lowerRegion(resultVariables, rewriter, indexSwitchOp.getDefaultRegion(), loweredSwitch.getDefaultRegion()); - rewriter.replaceOp(indexSwitchOp, resultVariables); + rewriter.setInsertionPointAfter(indexSwitchOp); + SmallVector results = loadValues(resultVariables, rewriter, loc); + + rewriter.replaceOp(indexSwitchOp, results); return success(); } @@ -233,4 +259,4 @@ void SCFToEmitCPass::runOnOperation() { if (failed( applyPartialConversion(getOperation(), target, std::move(patterns)))) signalPassFailure(); -} +} \ No newline at end of file diff --git a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp index d731a6756ff63..6b27c8c696a58 100644 --- a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp +++ b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp @@ -61,6 +61,9 @@ void mlir::emitc::buildTerminatedBody(OpBuilder &builder, Location loc) { bool mlir::emitc::isSupportedEmitCType(Type type) { if (llvm::isa(type)) return true; + if (auto lType = llvm::dyn_cast(type)) + // lvalue types are only allowed in a few places. + return false; if (auto ptrType = llvm::dyn_cast(type)) return isSupportedEmitCType(ptrType.getPointee()); if (auto arrayType = llvm::dyn_cast(type)) { @@ -145,6 +148,8 @@ static LogicalResult verifyInitializationAttribute(Operation *op, << "string attributes are not supported, use #emitc.opaque instead"; Type resultType = op->getResult(0).getType(); + if (auto lType = dyn_cast(resultType)) + resultType = lType.getValue(); Type attrType = cast(value).getType(); if (isPointerWideType(resultType) && attrType.isIndex()) @@ -196,9 +201,17 @@ LogicalResult ApplyOp::verify() { if (applicableOperatorStr != "&" && applicableOperatorStr != "*") return emitOpError("applicable operator is illegal"); - Operation *op = getOperand().getDefiningOp(); - if (op && dyn_cast(op)) - return emitOpError("cannot apply to constant"); + Type operandType = getOperand().getType(); + Type resultType = getResult().getType(); + if (applicableOperatorStr == "&") { + if (!llvm::isa(operandType)) + return emitOpError("operand type must be an lvalue when applying `&`"); + if (!llvm::isa(resultType)) + return emitOpError("result type must be a pointer when applying `&`"); + } else { + if (!llvm::isa(operandType)) + return emitOpError("operand type must be a pointer when applying `*`"); + } return success(); } @@ -210,22 +223,18 @@ LogicalResult ApplyOp::verify() { /// The assign op requires that the assigned value's type matches the /// assigned-to variable type. LogicalResult emitc::AssignOp::verify() { - Value variable = getVar(); - Operation *variableDef = variable.getDefiningOp(); - if (!variableDef || - !llvm::isa(variableDef)) - return emitOpError() << "requires first operand (" << variable - << ") to be a get_global, member, member of pointer, " - "subscript or variable"; - - Value value = getValue(); - if (variable.getType() != value.getType()) - return emitOpError() << "requires value's type (" << value.getType() - << ") to match variable's type (" << variable.getType() - << ")"; - if (isa(variable.getType())) - return emitOpError() << "cannot assign to array type"; + TypedValue variable = getVar(); + + if (!variable.getDefiningOp()) + return emitOpError() << "cannot assign to block argument"; + + Type valueType = getValue().getType(); + Type variableType = variable.getType().getValue(); + if (variableType != valueType) + return emitOpError() << "requires value's type (" << valueType + << ") to match variable's type (" << variableType + << ")\n variable: " << variable + << "\n value: " << getValue() << "\n"; return success(); } @@ -853,9 +862,10 @@ LogicalResult emitc::SubscriptOp::verify() { } // Check element type. Type elementType = arrayType.getElementType(); - if (elementType != getType()) { + Type resultType = getType().getValue(); + if (elementType != resultType) { return emitOpError() << "on array operand requires element type (" - << elementType << ") and result type (" << getType() + << elementType << ") and result type (" << resultType << ") to match"; } return success(); @@ -879,9 +889,10 @@ LogicalResult emitc::SubscriptOp::verify() { } // Check pointee type. Type pointeeType = pointerType.getPointee(); - if (pointeeType != getType()) { + Type resultType = getType().getValue(); + if (pointeeType != resultType) { return emitOpError() << "on pointer operand requires pointee type (" - << pointeeType << ") and result type (" << getType() + << pointeeType << ") and result type (" << resultType << ") to match"; } return success(); @@ -975,6 +986,25 @@ emitc::ArrayType::cloneWith(std::optional> shape, return emitc::ArrayType::get(*shape, elementType); } +//===----------------------------------------------------------------------===// +// LValueType +//===----------------------------------------------------------------------===// + +LogicalResult mlir::emitc::LValueType::verify( + llvm::function_ref emitError, + mlir::Type value) { + // Check that the wrapped type is valid. This especially forbids nested lvalue + // types. + if (!isSupportedEmitCType(value)) + return emitError() + << "!emitc.lvalue must wrap supported emitc type, but got " << value; + + if (llvm::isa(value)) + return emitError() << "!emitc.lvalue cannot wrap !emitc.array type"; + + return success(); +} + //===----------------------------------------------------------------------===// // OpaqueType //===----------------------------------------------------------------------===// @@ -992,6 +1022,18 @@ LogicalResult mlir::emitc::OpaqueType::verify( return success(); } +//===----------------------------------------------------------------------===// +// PointerType +//===----------------------------------------------------------------------===// + +LogicalResult mlir::emitc::PointerType::verify( + llvm::function_ref emitError, Type value) { + if (llvm::isa(value)) + return emitError() << "pointers to lvalues are not allowed"; + + return success(); +} + //===----------------------------------------------------------------------===// // GlobalOp //===----------------------------------------------------------------------===// @@ -1089,9 +1131,22 @@ GetGlobalOp::verifySymbolUses(SymbolTableCollection &symbolTable) { << getName() << "' does not reference a valid emitc.global"; Type resultType = getResult().getType(); - if (global.getType() != resultType) - return emitOpError("result type ") - << resultType << " does not match type " << global.getType() + Type globalType = global.getType(); + + // global has array type + if (llvm::isa(globalType)) { + if (globalType != resultType) + return emitOpError("on array type expects result type ") + << resultType << " to match type " << globalType + << " of the global @" << getName(); + return success(); + } + + // global has non-array type + auto lvalueType = dyn_cast(resultType); + if (!lvalueType || lvalueType.getValue() != globalType) + return emitOpError("on non-array type expects result inner type ") + << lvalueType.getValue() << " to match type " << globalType << " of the global @" << getName(); return success(); } diff --git a/mlir/lib/Dialect/EmitC/Transforms/FormExpressions.cpp b/mlir/lib/Dialect/EmitC/Transforms/FormExpressions.cpp index 82bd031430d36..758b8527c2fa5 100644 --- a/mlir/lib/Dialect/EmitC/Transforms/FormExpressions.cpp +++ b/mlir/lib/Dialect/EmitC/Transforms/FormExpressions.cpp @@ -38,7 +38,8 @@ struct FormExpressionsPass auto matchFun = [&](Operation *op) { if (op->hasTrait() && !op->getParentOfType() && - op->getNumResults() == 1) + op->getNumResults() == 1 && + isSupportedEmitCType(op->getResult(0).getType())) createExpression(op, builder); }; rootOp->walk(matchFun); diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp index 8e112e6f7dda6..7cd9032d82849 100644 --- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp +++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp @@ -384,6 +384,14 @@ static LogicalResult printOperation(CppEmitter &emitter, return emitter.emitOperand(assignOp.getValue()); } +static LogicalResult printOperation(CppEmitter &emitter, + emitc::LValueLoadOp lValueLoadOp) { + if (failed(emitter.emitAssignPrefix(*lValueLoadOp))) + return failure(); + + return emitter.emitOperand(lValueLoadOp.getOperand()); +} + static LogicalResult printBinaryOperation(CppEmitter &emitter, Operation *operation, StringRef binaryOperator) { @@ -1544,10 +1552,10 @@ LogicalResult CppEmitter::emitOperation(Operation &op, bool trailingSemicolon) { emitc::ConditionalOp, emitc::ConstantOp, emitc::DeclareFuncOp, emitc::DivOp, emitc::ExpressionOp, emitc::ForOp, emitc::FuncOp, emitc::GlobalOp, emitc::IfOp, emitc::IncludeOp, - emitc::LogicalAndOp, emitc::LogicalNotOp, emitc::LogicalOrOp, - emitc::MulOp, emitc::RemOp, emitc::ReturnOp, emitc::SubOp, - emitc::SwitchOp, emitc::UnaryMinusOp, emitc::UnaryPlusOp, - emitc::VariableOp, emitc::VerbatimOp>( + emitc::LValueLoadOp, emitc::LogicalAndOp, emitc::LogicalNotOp, + emitc::LogicalOrOp, emitc::MulOp, emitc::RemOp, emitc::ReturnOp, + emitc::SubOp, emitc::SwitchOp, emitc::UnaryMinusOp, + emitc::UnaryPlusOp, emitc::VariableOp, emitc::VerbatimOp>( [&](auto op) { return printOperation(*this, op); }) // Func ops. .Case( @@ -1675,6 +1683,8 @@ LogicalResult CppEmitter::emitType(Location loc, Type type) { os << "[" << dim << "]"; return success(); } + if (auto lType = dyn_cast(type)) + return emitType(loc, lType.getValue()); if (auto pType = dyn_cast(type)) { if (isa(pType.getPointee())) return emitError(loc, "cannot emit pointer to array type ") << type; diff --git a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir index bc40ef48268eb..15ffd815250d2 100644 --- a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir +++ b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir @@ -3,11 +3,11 @@ // CHECK-LABEL: memref_store // CHECK-SAME: %[[v:.*]]: f32, %[[i:.*]]: index, %[[j:.*]]: index func.func @memref_store(%v : f32, %i: index, %j: index) { - // CHECK: %[[ALLOCA:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.array<4x8xf32> + // CHECK-NEXT: %[[ALLOCA:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.array<4x8xf32> %0 = memref.alloca() : memref<4x8xf32> - // CHECK: %[[SUBSCRIPT:.*]] = emitc.subscript %[[ALLOCA]][%[[i]], %[[j]]] : (!emitc.array<4x8xf32>, index, index) -> f32 - // CHECK: emitc.assign %[[v]] : f32 to %[[SUBSCRIPT:.*]] : f32 + // CHECK-NEXT: %[[SUBSCRIPT:.*]] = emitc.subscript %[[ALLOCA]][%[[i]], %[[j]]] : (!emitc.array<4x8xf32>, index, index) -> !emitc.lvalue + // CHECK-NEXT: emitc.assign %[[v]] : f32 to %[[SUBSCRIPT]] : memref.store %v, %0[%i, %j] : memref<4x8xf32> return } @@ -17,14 +17,13 @@ func.func @memref_store(%v : f32, %i: index, %j: index) { // CHECK-LABEL: memref_load // CHECK-SAME: %[[i:.*]]: index, %[[j:.*]]: index func.func @memref_load(%i: index, %j: index) -> f32 { - // CHECK: %[[ALLOCA:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.array<4x8xf32> + // CHECK-NEXT: %[[ALLOCA:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.array<4x8xf32> %0 = memref.alloca() : memref<4x8xf32> - // CHECK: %[[LOAD:.*]] = emitc.subscript %[[ALLOCA]][%[[i]], %[[j]]] : (!emitc.array<4x8xf32>, index, index) -> f32 - // CHECK: %[[VAR:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> f32 - // CHECK: emitc.assign %[[LOAD]] : f32 to %[[VAR]] : f32 + // CHECK-NEXT: %[[SUBSCRIPT:.*]] = emitc.subscript %[[ALLOCA]][%[[i]], %[[j]]] : (!emitc.array<4x8xf32>, index, index) -> !emitc.lvalue + // CHECK-NEXT: %[[LOAD:.*]] = emitc.lvalue_load %[[SUBSCRIPT]] : %1 = memref.load %0[%i, %j] : memref<4x8xf32> - // CHECK: return %[[VAR]] : f32 + // CHECK-NEXT: return %[[LOAD]] : f32 return %1 : f32 } @@ -33,14 +32,15 @@ func.func @memref_load(%i: index, %j: index) -> f32 { // CHECK-LABEL: globals module @globals { memref.global "private" constant @internal_global : memref<3x7xf32> = dense<4.0> - // CHECK: emitc.global static const @internal_global : !emitc.array<3x7xf32> = dense<4.000000e+00> + // CHECK-NEXT: emitc.global static const @internal_global : !emitc.array<3x7xf32> = dense<4.000000e+00> memref.global @public_global : memref<3x7xf32> - // CHECK: emitc.global extern @public_global : !emitc.array<3x7xf32> + // CHECK-NEXT: emitc.global extern @public_global : !emitc.array<3x7xf32> memref.global @uninitialized_global : memref<3x7xf32> = uninitialized - // CHECK: emitc.global extern @uninitialized_global : !emitc.array<3x7xf32> + // CHECK-NEXT: emitc.global extern @uninitialized_global : !emitc.array<3x7xf32> + // CHECK-LABEL: use_global func.func @use_global() { - // CHECK: emitc.get_global @public_global : !emitc.array<3x7xf32> + // CHECK-NEXT: emitc.get_global @public_global : !emitc.array<3x7xf32> %0 = memref.get_global @public_global : memref<3x7xf32> return } diff --git a/mlir/test/Conversion/SCFToEmitC/for.mlir b/mlir/test/Conversion/SCFToEmitC/for.mlir index 7e59eac3d4095..32a9dfce7f4e6 100644 --- a/mlir/test/Conversion/SCFToEmitC/for.mlir +++ b/mlir/test/Conversion/SCFToEmitC/for.mlir @@ -47,16 +47,20 @@ func.func @for_yield(%arg0 : index, %arg1 : index, %arg2 : index) -> (f32, f32) // CHECK-SAME: %[[VAL_0:.*]]: index, %[[VAL_1:.*]]: index, %[[VAL_2:.*]]: index) -> (f32, f32) { // CHECK-NEXT: %[[VAL_3:.*]] = arith.constant 0.000000e+00 : f32 // CHECK-NEXT: %[[VAL_4:.*]] = arith.constant 1.000000e+00 : f32 -// CHECK-NEXT: %[[VAL_5:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> f32 -// CHECK-NEXT: %[[VAL_6:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> f32 -// CHECK-NEXT: emitc.assign %[[VAL_3]] : f32 to %[[VAL_5]] : f32 -// CHECK-NEXT: emitc.assign %[[VAL_4]] : f32 to %[[VAL_6]] : f32 -// CHECK-NEXT: emitc.for %[[VAL_9:.*]] = %[[VAL_0]] to %[[VAL_1]] step %[[VAL_2]] { -// CHECK-NEXT: %[[VAL_10:.*]] = arith.addf %[[VAL_5]], %[[VAL_6]] : f32 -// CHECK-NEXT: emitc.assign %[[VAL_10]] : f32 to %[[VAL_5]] : f32 -// CHECK-NEXT: emitc.assign %[[VAL_10]] : f32 to %[[VAL_6]] : f32 +// CHECK-NEXT: %[[VAL_5:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue +// CHECK-NEXT: %[[VAL_6:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue +// CHECK-NEXT: emitc.assign %[[VAL_3]] : f32 to %[[VAL_5]] : +// CHECK-NEXT: emitc.assign %[[VAL_4]] : f32 to %[[VAL_6]] : +// CHECK-NEXT: emitc.for %[[VAL_7:.*]] = %[[VAL_0]] to %[[VAL_1]] step %[[VAL_2]] { +// CHECK-NEXT: %[[VAL_8:.*]] = emitc.lvalue_load %[[VAL_5]] : +// CHECK-NEXT: %[[VAL_9:.*]] = emitc.lvalue_load %[[VAL_6]] : +// CHECK-NEXT: %[[VAL_10:.*]] = arith.addf %[[VAL_8]], %[[VAL_9]] : f32 +// CHECK-NEXT: emitc.assign %[[VAL_10]] : f32 to %[[VAL_5]] : +// CHECK-NEXT: emitc.assign %[[VAL_10]] : f32 to %[[VAL_6]] : // CHECK-NEXT: } -// CHECK-NEXT: return %[[VAL_5]], %[[VAL_6]] : f32, f32 +// CHECK-NEXT: %[[VAL_11:.*]] = emitc.lvalue_load %[[VAL_5]] : +// CHECK-NEXT: %[[VAL_12:.*]] = emitc.lvalue_load %[[VAL_6]] : +// CHECK-NEXT: return %[[VAL_11]], %[[VAL_12]] : f32, f32 // CHECK-NEXT: } func.func @nested_for_yield(%arg0 : index, %arg1 : index, %arg2 : index) -> f32 { @@ -73,16 +77,20 @@ func.func @nested_for_yield(%arg0 : index, %arg1 : index, %arg2 : index) -> f32 // CHECK-LABEL: func.func @nested_for_yield( // CHECK-SAME: %[[VAL_0:.*]]: index, %[[VAL_1:.*]]: index, %[[VAL_2:.*]]: index) -> f32 { // CHECK-NEXT: %[[VAL_3:.*]] = arith.constant 1.000000e+00 : f32 -// CHECK-NEXT: %[[VAL_4:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> f32 -// CHECK-NEXT: emitc.assign %[[VAL_3]] : f32 to %[[VAL_4]] : f32 -// CHECK-NEXT: emitc.for %[[VAL_6:.*]] = %[[VAL_0]] to %[[VAL_1]] step %[[VAL_2]] { -// CHECK-NEXT: %[[VAL_7:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> f32 -// CHECK-NEXT: emitc.assign %[[VAL_4]] : f32 to %[[VAL_7]] : f32 -// CHECK-NEXT: emitc.for %[[VAL_9:.*]] = %[[VAL_0]] to %[[VAL_1]] step %[[VAL_2]] { -// CHECK-NEXT: %[[VAL_10:.*]] = arith.addf %[[VAL_7]], %[[VAL_7]] : f32 -// CHECK-NEXT: emitc.assign %[[VAL_10]] : f32 to %[[VAL_7]] : f32 +// CHECK-NEXT: %[[VAL_4:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue +// CHECK-NEXT: emitc.assign %[[VAL_3]] : f32 to %[[VAL_4]] : +// CHECK-NEXT: emitc.for %[[VAL_5:.*]] = %[[VAL_0]] to %[[VAL_1]] step %[[VAL_2]] { +// CHECK-NEXT: %[[VAL_6:.*]] = emitc.lvalue_load %[[VAL_4]] : +// CHECK-NEXT: %[[VAL_7:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue +// CHECK-NEXT: emitc.assign %[[VAL_6]] : f32 to %[[VAL_7]] : +// CHECK-NEXT: emitc.for %[[VAL_8:.*]] = %[[VAL_0]] to %[[VAL_1]] step %[[VAL_2]] { +// CHECK-NEXT: %[[VAL_9:.*]] = emitc.lvalue_load %[[VAL_7]] : +// CHECK-NEXT: %[[VAL_10:.*]] = arith.addf %[[VAL_9]], %[[VAL_9]] : f32 +// CHECK-NEXT: emitc.assign %[[VAL_10]] : f32 to %[[VAL_7]] : // CHECK-NEXT: } -// CHECK-NEXT: emitc.assign %[[VAL_7]] : f32 to %[[VAL_4]] : f32 +// CHECK-NEXT: %[[VAL_11:.*]] = emitc.lvalue_load %[[VAL_7]] : +// CHECK-NEXT: emitc.assign %[[VAL_11]] : f32 to %[[VAL_4]] : // CHECK-NEXT: } -// CHECK-NEXT: return %[[VAL_4]] : f32 +// CHECK-NEXT: %[[VAL_12:.*]] = emitc.lvalue_load %[[VAL_4]] : +// CHECK-NEXT: return %[[VAL_12]] : f32 // CHECK-NEXT: } diff --git a/mlir/test/Conversion/SCFToEmitC/if.mlir b/mlir/test/Conversion/SCFToEmitC/if.mlir index afc9abc761eb4..463cf1d3d9645 100644 --- a/mlir/test/Conversion/SCFToEmitC/if.mlir +++ b/mlir/test/Conversion/SCFToEmitC/if.mlir @@ -36,7 +36,7 @@ func.func @test_if_else(%arg0: i1, %arg1: f32) { // CHECK-NEXT: } -func.func @test_if_yield(%arg0: i1, %arg1: f32) { +func.func @test_if_yield(%arg0: i1, %arg1: f32) -> (i32, f64) { %0 = arith.constant 0 : i8 %x, %y = scf.if %arg0 -> (i32, f64) { %1 = emitc.call_opaque "func_true_1"(%arg1) : (f32) -> i32 @@ -47,24 +47,26 @@ func.func @test_if_yield(%arg0: i1, %arg1: f32) { %2 = emitc.call_opaque "func_false_2"(%arg1) : (f32) -> f64 scf.yield %1, %2 : i32, f64 } - return + return %x, %y : i32, f64 } // CHECK-LABEL: func.func @test_if_yield( // CHECK-SAME: %[[VAL_0:.*]]: i1, -// CHECK-SAME: %[[VAL_1:.*]]: f32) { +// CHECK-SAME: %[[VAL_1:.*]]: f32) -> (i32, f64) { // CHECK-NEXT: %[[VAL_2:.*]] = arith.constant 0 : i8 -// CHECK-NEXT: %[[VAL_3:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> i32 -// CHECK-NEXT: %[[VAL_4:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> f64 +// CHECK-NEXT: %[[VAL_3:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue +// CHECK-NEXT: %[[VAL_4:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue // CHECK-NEXT: emitc.if %[[VAL_0]] { // CHECK-NEXT: %[[VAL_5:.*]] = emitc.call_opaque "func_true_1"(%[[VAL_1]]) : (f32) -> i32 // CHECK-NEXT: %[[VAL_6:.*]] = emitc.call_opaque "func_true_2"(%[[VAL_1]]) : (f32) -> f64 -// CHECK-NEXT: emitc.assign %[[VAL_5]] : i32 to %[[VAL_3]] : i32 -// CHECK-NEXT: emitc.assign %[[VAL_6]] : f64 to %[[VAL_4]] : f64 +// CHECK-NEXT: emitc.assign %[[VAL_5]] : i32 to %[[VAL_3]] : +// CHECK-NEXT: emitc.assign %[[VAL_6]] : f64 to %[[VAL_4]] : // CHECK-NEXT: } else { // CHECK-NEXT: %[[VAL_7:.*]] = emitc.call_opaque "func_false_1"(%[[VAL_1]]) : (f32) -> i32 // CHECK-NEXT: %[[VAL_8:.*]] = emitc.call_opaque "func_false_2"(%[[VAL_1]]) : (f32) -> f64 -// CHECK-NEXT: emitc.assign %[[VAL_7]] : i32 to %[[VAL_3]] : i32 -// CHECK-NEXT: emitc.assign %[[VAL_8]] : f64 to %[[VAL_4]] : f64 +// CHECK-NEXT: emitc.assign %[[VAL_7]] : i32 to %[[VAL_3]] : +// CHECK-NEXT: emitc.assign %[[VAL_8]] : f64 to %[[VAL_4]] : // CHECK-NEXT: } -// CHECK-NEXT: return +// CHECK-NEXT: %[[VAL_9:.*]] = emitc.lvalue_load %[[VAL_3]] : +// CHECK-NEXT: %[[VAL_10:.*]] = emitc.lvalue_load %[[VAL_4]] : +// CHECK-NEXT: return %[[VAL_9]], %[[VAL_10]] : i32, f64 // CHECK-NEXT: } diff --git a/mlir/test/Conversion/SCFToEmitC/switch.mlir b/mlir/test/Conversion/SCFToEmitC/switch.mlir index 659d9f43963ef..54d84738bcb9a 100644 --- a/mlir/test/Conversion/SCFToEmitC/switch.mlir +++ b/mlir/test/Conversion/SCFToEmitC/switch.mlir @@ -34,21 +34,21 @@ func.func @switch_no_result(%arg0 : index) { // CHECK-LABEL: func.func @switch_one_result( // CHECK-SAME: %[[VAL_0:.*]]: index) { -// CHECK: %[[VAL_1:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> i32 +// CHECK: %[[VAL_1:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue // CHECK: emitc.switch %[[VAL_0]] // CHECK: case 2 { // CHECK: %[[VAL_2:.*]] = arith.constant 10 : i32 -// CHECK: emitc.assign %[[VAL_2]] : i32 to %[[VAL_1]] : i32 +// CHECK: emitc.assign %[[VAL_2]] : i32 to %[[VAL_1]] : // CHECK: emitc.yield // CHECK: } // CHECK: case 5 { // CHECK: %[[VAL_3:.*]] = arith.constant 20 : i32 -// CHECK: emitc.assign %[[VAL_3]] : i32 to %[[VAL_1]] : i32 +// CHECK: emitc.assign %[[VAL_3]] : i32 to %[[VAL_1]] : // CHECK: emitc.yield // CHECK: } // CHECK: default { // CHECK: %[[VAL_4:.*]] = arith.constant 30 : i32 -// CHECK: emitc.assign %[[VAL_4]] : i32 to %[[VAL_1]] : i32 +// CHECK: emitc.assign %[[VAL_4]] : i32 to %[[VAL_1]] : // CHECK: } // CHECK: return // CHECK: } @@ -70,33 +70,35 @@ func.func @switch_one_result(%arg0 : index) { } // CHECK-LABEL: func.func @switch_two_results( -// CHECK-SAME: %[[VAL_0:.*]]: index) { -// CHECK: %[[VAL_1:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> i32 -// CHECK: %[[VAL_2:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> f32 +// CHECK-SAME: %[[VAL_0:.*]]: index) -> (i32, f32) { +// CHECK: %[[VAL_1:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue +// CHECK: %[[VAL_2:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue // CHECK: emitc.switch %[[VAL_0]] // CHECK: case 2 { // CHECK: %[[VAL_3:.*]] = arith.constant 10 : i32 // CHECK: %[[VAL_4:.*]] = arith.constant 1.200000e+00 : f32 -// CHECK: emitc.assign %[[VAL_3]] : i32 to %[[VAL_1]] : i32 -// CHECK: emitc.assign %[[VAL_4]] : f32 to %[[VAL_2]] : f32 +// CHECK: emitc.assign %[[VAL_3]] : i32 to %[[VAL_1]] : +// CHECK: emitc.assign %[[VAL_4]] : f32 to %[[VAL_2]] : // CHECK: emitc.yield // CHECK: } // CHECK: case 5 { // CHECK: %[[VAL_5:.*]] = arith.constant 20 : i32 // CHECK: %[[VAL_6:.*]] = arith.constant 2.400000e+00 : f32 -// CHECK: emitc.assign %[[VAL_5]] : i32 to %[[VAL_1]] : i32 -// CHECK: emitc.assign %[[VAL_6]] : f32 to %[[VAL_2]] : f32 +// CHECK: emitc.assign %[[VAL_5]] : i32 to %[[VAL_1]] : +// CHECK: emitc.assign %[[VAL_6]] : f32 to %[[VAL_2]] : // CHECK: emitc.yield // CHECK: } // CHECK: default { // CHECK: %[[VAL_7:.*]] = arith.constant 30 : i32 // CHECK: %[[VAL_8:.*]] = arith.constant 3.600000e+00 : f32 -// CHECK: emitc.assign %[[VAL_7]] : i32 to %[[VAL_1]] : i32 -// CHECK: emitc.assign %[[VAL_8]] : f32 to %[[VAL_2]] : f32 +// CHECK: emitc.assign %[[VAL_7]] : i32 to %[[VAL_1]] : +// CHECK: emitc.assign %[[VAL_8]] : f32 to %[[VAL_2]] : // CHECK: } -// CHECK: return +// CHECK: %[[RES_1:.*]] = emitc.lvalue_load %[[VAL_1]] : +// CHECK: %[[RES_2:.*]] = emitc.lvalue_load %[[VAL_2]] : +// CHECK: return %[[RES_1]], %[[RES_2]] : i32, f32 // CHECK: } -func.func @switch_two_results(%arg0 : index) { +func.func @switch_two_results(%arg0 : index) -> (i32, f32) { %0, %1 = scf.index_switch %arg0 -> i32, f32 case 2 { %2 = arith.constant 10 : i32 @@ -113,5 +115,5 @@ func.func @switch_two_results(%arg0 : index) { %7 = arith.constant 3.6 : f32 scf.yield %6, %7 : i32, f32 } - return + return %0, %1 : i32, f32 } diff --git a/mlir/test/Dialect/EmitC/invalid_ops.mlir b/mlir/test/Dialect/EmitC/invalid_ops.mlir index 4b5bcf46c1aab..d3f9c5c36ff8c 100644 --- a/mlir/test/Dialect/EmitC/invalid_ops.mlir +++ b/mlir/test/Dialect/EmitC/invalid_ops.mlir @@ -88,26 +88,17 @@ func.func @array_result() { // ----- -func.func @empty_operator(%arg : i32) { +func.func @empty_operator(%arg : !emitc.lvalue) { // expected-error @+1 {{'emitc.apply' op applicable operator must not be empty}} - %2 = emitc.apply ""(%arg) : (i32) -> !emitc.ptr + %2 = emitc.apply ""(%arg) : (!emitc.lvalue) -> !emitc.ptr return } // ----- -func.func @illegal_operator(%arg : i32) { +func.func @illegal_operator(%arg : !emitc.lvalue) { // expected-error @+1 {{'emitc.apply' op applicable operator is illegal}} - %2 = emitc.apply "+"(%arg) : (i32) -> !emitc.ptr - return -} - -// ----- - -func.func @illegal_operand() { - %1 = "emitc.constant"(){value = 42: i32} : () -> i32 - // expected-error @+1 {{'emitc.apply' op cannot apply to constant}} - %2 = emitc.apply "&"(%1) : (i32) -> !emitc.ptr + %2 = emitc.apply "+"(%arg) : (!emitc.lvalue) -> !emitc.ptr return } @@ -115,7 +106,7 @@ func.func @illegal_operand() { func.func @var_attribute_return_type_1() { // expected-error @+1 {{'emitc.variable' op requires attribute to either be an #emitc.opaque attribute or it's type ('i64') to match the op's result type ('i32')}} - %c0 = "emitc.variable"(){value = 42: i64} : () -> i32 + %c0 = "emitc.variable"(){value = 42: i64} : () -> !emitc.lvalue return } @@ -123,7 +114,7 @@ func.func @var_attribute_return_type_1() { func.func @var_attribute_return_type_2() { // expected-error @+1 {{'emitc.variable' op attribute 'value' failed to satisfy constraint: An opaque attribute or TypedAttr instance}} - %c0 = "emitc.variable"(){value = unit} : () -> i32 + %c0 = "emitc.variable"(){value = unit} : () -> !emitc.lvalue return } @@ -234,18 +225,18 @@ func.func @test_misplaced_yield() { // ----- -func.func @test_assign_to_non_variable(%arg1: f32, %arg2: f32) { - // expected-error @+1 {{'emitc.assign' op requires first operand ( of type 'f32' at index: 1) to be a get_global, member, member of pointer, subscript or variable}} - emitc.assign %arg1 : f32 to %arg2 : f32 +func.func @test_assign_to_non_variable(%arg1: f32, %arg2: !emitc.lvalue) { + // expected-error @+1 {{'emitc.assign' op cannot assign to block argument}} + emitc.assign %arg1 : f32 to %arg2 : !emitc.lvalue return } // ----- func.func @test_assign_type_mismatch(%arg1: f32) { - %v = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> i32 + %v = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue // expected-error @+1 {{'emitc.assign' op requires value's type ('f32') to match variable's type ('i32')}} - emitc.assign %arg1 : f32 to %v : i32 + emitc.assign %arg1 : f32 to %v : !emitc.lvalue return } @@ -253,7 +244,7 @@ func.func @test_assign_type_mismatch(%arg1: f32) { func.func @test_assign_to_array(%arg1: !emitc.array<4xi32>) { %v = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.array<4xi32> - // expected-error @+1 {{'emitc.assign' op cannot assign to array type}} + // expected-error @+1 {{invalid kind of Type specified}} emitc.assign %arg1 : !emitc.array<4xi32> to %v : !emitc.array<4xi32> return } @@ -273,8 +264,9 @@ func.func @test_expression_no_yield() -> i32 { func.func @test_expression_illegal_op(%arg0 : i1) -> i32 { // expected-error @+1 {{'emitc.expression' op contains an unsupported operation}} %r = emitc.expression : i32 { - %x = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> i32 - emitc.yield %x : i32 + %x = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue + %y = emitc.lvalue_load %x : + emitc.yield %y : i32 } return %r : i32 } @@ -392,7 +384,7 @@ func.func @logical_or_resulterror(%arg0: i32, %arg1: i32) { func.func @test_subscript_array_indices_mismatch(%arg0: !emitc.array<4x8xf32>, %arg1: index) { // expected-error @+1 {{'emitc.subscript' op on array operand requires number of indices (1) to match the rank of the array type (2)}} - %0 = emitc.subscript %arg0[%arg1] : (!emitc.array<4x8xf32>, index) -> f32 + %0 = emitc.subscript %arg0[%arg1] : (!emitc.array<4x8xf32>, index) -> !emitc.lvalue return } @@ -400,7 +392,7 @@ func.func @test_subscript_array_indices_mismatch(%arg0: !emitc.array<4x8xf32>, % func.func @test_subscript_array_index_type_mismatch(%arg0: !emitc.array<4x8xf32>, %arg1: index, %arg2: f32) { // expected-error @+1 {{'emitc.subscript' op on array operand requires index operand 1 to be integer-like, but got 'f32'}} - %0 = emitc.subscript %arg0[%arg1, %arg2] : (!emitc.array<4x8xf32>, index, f32) -> f32 + %0 = emitc.subscript %arg0[%arg1, %arg2] : (!emitc.array<4x8xf32>, index, f32) -> !emitc.lvalue return } @@ -408,7 +400,7 @@ func.func @test_subscript_array_index_type_mismatch(%arg0: !emitc.array<4x8xf32> func.func @test_subscript_array_type_mismatch(%arg0: !emitc.array<4x8xf32>, %arg1: index, %arg2: index) { // expected-error @+1 {{'emitc.subscript' op on array operand requires element type ('f32') and result type ('i32') to match}} - %0 = emitc.subscript %arg0[%arg1, %arg2] : (!emitc.array<4x8xf32>, index, index) -> i32 + %0 = emitc.subscript %arg0[%arg1, %arg2] : (!emitc.array<4x8xf32>, index, index) -> !emitc.lvalue return } @@ -416,7 +408,7 @@ func.func @test_subscript_array_type_mismatch(%arg0: !emitc.array<4x8xf32>, %arg func.func @test_subscript_ptr_indices_mismatch(%arg0: !emitc.ptr, %arg1: index) { // expected-error @+1 {{'emitc.subscript' op on pointer operand requires one index operand, but got 2}} - %0 = emitc.subscript %arg0[%arg1, %arg1] : (!emitc.ptr, index, index) -> f32 + %0 = emitc.subscript %arg0[%arg1, %arg1] : (!emitc.ptr, index, index) -> !emitc.lvalue return } @@ -424,7 +416,7 @@ func.func @test_subscript_ptr_indices_mismatch(%arg0: !emitc.ptr, %arg1: in func.func @test_subscript_ptr_index_type_mismatch(%arg0: !emitc.ptr, %arg1: f64) { // expected-error @+1 {{'emitc.subscript' op on pointer operand requires index operand to be integer-like, but got 'f64'}} - %0 = emitc.subscript %arg0[%arg1] : (!emitc.ptr, f64) -> f32 + %0 = emitc.subscript %arg0[%arg1] : (!emitc.ptr, f64) -> !emitc.lvalue return } @@ -432,7 +424,7 @@ func.func @test_subscript_ptr_index_type_mismatch(%arg0: !emitc.ptr, %arg1: func.func @test_subscript_ptr_type_mismatch(%arg0: !emitc.ptr, %arg1: index) { // expected-error @+1 {{'emitc.subscript' op on pointer operand requires pointee type ('f32') and result type ('f64') to match}} - %0 = emitc.subscript %arg0[%arg1] : (!emitc.ptr, index) -> f64 + %0 = emitc.subscript %arg0[%arg1] : (!emitc.ptr, index) -> !emitc.lvalue return } @@ -443,34 +435,44 @@ emitc.global extern static @uninit : i32 // ----- -emitc.global @myglobal : !emitc.array<2xf32> +emitc.global @myglobal_array : !emitc.array<2xf32> + +func.func @use_global() { + // expected-error @+1 {{'emitc.get_global' op on array type expects result type '!emitc.array<3xf32>' to match type '!emitc.array<2xf32>' of the global @myglobal_array}} + %0 = emitc.get_global @myglobal_array : !emitc.array<3xf32> + return +} + +// ----- + +emitc.global @myglobal_scalar : f32 func.func @use_global() { - // expected-error @+1 {{'emitc.get_global' op result type 'f32' does not match type '!emitc.array<2xf32>' of the global @myglobal}} - %0 = emitc.get_global @myglobal : f32 + // expected-error @+1 {{'emitc.get_global' op on non-array type expects result inner type 'i32' to match type 'f32' of the global @myglobal_scalar}} + %0 = emitc.get_global @myglobal_scalar : !emitc.lvalue return } // ----- -func.func @member(%arg0: i32) { - // expected-error @+1 {{'emitc.member' op operand #0 must be EmitC opaque type, but got 'i32'}} - %0 = "emitc.member" (%arg0) {member = "a"} : (i32) -> i32 +func.func @member(%arg0: !emitc.lvalue) { + // expected-error @+1 {{'emitc.member' op operand #0 must be emitc.lvalue of EmitC opaque type values, but got '!emitc.lvalue'}} + %0 = "emitc.member" (%arg0) {member = "a"} : (!emitc.lvalue) -> !emitc.lvalue return } // ----- -func.func @member_of_ptr(%arg0: i32) { - // expected-error @+1 {{'emitc.member_of_ptr' op operand #0 must be EmitC opaque type or EmitC pointer type, but got 'i32}} - %0 = "emitc.member_of_ptr" (%arg0) {member = "a"} : (i32) -> i32 +func.func @member_of_ptr(%arg0: !emitc.lvalue) { + // expected-error @+1 {{'emitc.member_of_ptr' op operand #0 must be emitc.lvalue of EmitC opaque type or EmitC pointer type values, but got '!emitc.lvalue'}} + %0 = "emitc.member_of_ptr" (%arg0) {member = "a"} : (!emitc.lvalue) -> !emitc.lvalue return } // ----- func.func @emitc_switch() { - %0 = "emitc.variable"(){value = 1 : i16} : () -> i16 + %0 = "emitc.constant"(){value = 1 : i16} : () -> i16 // expected-error@+1 {{'emitc.switch' op expected region to end with emitc.yield, but got emitc.call_opaque}} emitc.switch %0 : i16 @@ -482,7 +484,7 @@ func.func @emitc_switch() { emitc.yield } default { - %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32 + %3 = "emitc.constant"(){value = 42.0 : f32} : () -> f32 emitc.call_opaque "func2" (%3) : (f32) -> () emitc.yield } @@ -492,7 +494,7 @@ func.func @emitc_switch() { // ----- func.func @emitc_switch() { - %0 = "emitc.variable"(){value = 1 : i32} : () -> i32 + %0 = "emitc.constant"(){value = 1 : i32} : () -> i32 emitc.switch %0 : i32 case 2 { @@ -505,7 +507,7 @@ func.func @emitc_switch() { emitc.yield } default { - %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32 + %3 = "emitc.constant"(){value = 42.0 : f32} : () -> f32 emitc.call_opaque "func2" (%3) : (f32) -> () emitc.yield } @@ -515,7 +517,7 @@ func.func @emitc_switch() { // ----- func.func @emitc_switch() { - %0 = "emitc.variable"(){value = 1 : i8} : () -> i8 + %0 = "emitc.constant"(){value = 1 : i8} : () -> i8 emitc.switch %0 : i8 case 2 { @@ -533,7 +535,7 @@ func.func @emitc_switch() { // ----- func.func @emitc_switch() { - %0 = "emitc.variable"(){value = 1 : i64} : () -> i64 + %0 = "emitc.constant"(){value = 1 : i64} : () -> i64 // expected-error@+1 {{'emitc.switch' op has duplicate case value: 2}} emitc.switch %0 : i64 @@ -546,7 +548,7 @@ func.func @emitc_switch() { emitc.yield } default { - %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32 + %3 = "emitc.constant"(){value = 42.0 : f32} : () -> f32 emitc.call_opaque "func2" (%3) : (f32) -> () emitc.yield } diff --git a/mlir/test/Dialect/EmitC/invalid_types.mlir b/mlir/test/Dialect/EmitC/invalid_types.mlir index 9bf0c49e7199a..302a345c7c4f4 100644 --- a/mlir/test/Dialect/EmitC/invalid_types.mlir +++ b/mlir/test/Dialect/EmitC/invalid_types.mlir @@ -84,6 +84,14 @@ func.func @illegal_array_with_tensor_element_type( // ----- +func.func @illegal_array_with_lvalue_element_type( + // expected-error @+1 {{invalid array element type}} + %arg0: !emitc.array<4x!emitc.lvalue> +) { +} + +// ----- + func.func @illegal_integer_type(%arg0: i11, %arg1: i11) -> i11 { // expected-error @+1 {{'emitc.mul' op operand #0 must be floating-point type supported by EmitC or integer, index or opaque type supported by EmitC, but got 'i11'}} %mul = "emitc.mul" (%arg0, %arg1) : (i11, i11) -> i11 @@ -100,48 +108,80 @@ func.func @illegal_float_type(%arg0: f80, %arg1: f80) { // ----- -func.func @illegal_pointee_type() { - // expected-error @+1 {{'emitc.variable' op result #0 must be type supported by EmitC, but got '!emitc.ptr'}} - %v = "emitc.variable"(){value = #emitc.opaque<"">} : () -> !emitc.ptr +func.func @illegal_lvalue_type_1() { + // expected-error @+1 {{!emitc.lvalue cannot wrap !emitc.array type}} + %v = "emitc.variable"(){value = #emitc.opaque<"">} : () -> !emitc.lvalue> + return +} + +// ----- + +func.func @illegal_lvalue_type_2() { + // expected-error @+1 {{!emitc.lvalue must wrap supported emitc type, but got '!emitc.lvalue'}} + %v = "emitc.variable"(){value = #emitc.opaque<"">} : () -> !emitc.lvalue> + return +} + +// ----- + +func.func @illegal_lvalue_type_3() { + // expected-error @+1 {{!emitc.lvalue must wrap supported emitc type, but got 'i17'}} + %v = "emitc.variable"(){value = #emitc.opaque<"">} : () -> !emitc.lvalue + return +} + +// ----- + +func.func @illegal_pointee_type_1() { + // expected-error @+1 {{'emitc.constant' op result #0 must be type supported by EmitC, but got '!emitc.ptr'}} + %v = "emitc.constant"(){value = #emitc.opaque<"{}">} : () -> !emitc.ptr + return +} + +// ----- + +func.func @illegal_pointee_type_2() { + // expected-error @+1 {{pointers to lvalues are not allowed}} + %v = "emitc.constant"(){value = #emitc.opaque<"NULL">} : () -> !emitc.ptr> return } // ----- func.func @illegal_non_static_tensor_shape_type() { - // expected-error @+1 {{'emitc.variable' op result #0 must be type supported by EmitC, but got 'tensor'}} - %v = "emitc.variable"(){value = #emitc.opaque<"">} : () -> tensor + // expected-error @+1 {{'emitc.constant' op result #0 must be type supported by EmitC, but got 'tensor'}} + %v = "emitc.constant"(){value = #emitc.opaque<"{}">} : () -> tensor return } // ----- func.func @illegal_tensor_array_element_type() { - // expected-error @+1 {{'emitc.variable' op result #0 must be type supported by EmitC, but got 'tensor>'}} - %v = "emitc.variable"(){value = #emitc.opaque<"">} : () -> tensor> + // expected-error @+1 {{'emitc.constant' op result #0 must be type supported by EmitC, but got 'tensor>'}} + %v = "emitc.constant"(){value = #emitc.opaque<"{}">} : () -> tensor> return } // ----- func.func @illegal_tensor_integer_element_type() { - // expected-error @+1 {{'emitc.variable' op result #0 must be type supported by EmitC, but got 'tensor<9xi11>'}} - %v = "emitc.variable"(){value = #emitc.opaque<"">} : () -> tensor<9xi11> + // expected-error @+1 {{'emitc.constant' op result #0 must be type supported by EmitC, but got 'tensor<9xi11>'}} + %v = "emitc.constant"(){value = #emitc.opaque<"{}">} : () -> tensor<9xi11> return } // ----- func.func @illegal_tuple_array_element_type() { - // expected-error @+1 {{'emitc.variable' op result #0 must be type supported by EmitC, but got 'tuple, f32>'}} - %v = "emitc.variable"(){value = #emitc.opaque<"">} : () -> tuple, f32> + // expected-error @+1 {{'emitc.constant' op result #0 must be type supported by EmitC, but got 'tuple, f32>'}} + %v = "emitc.constant"(){value = #emitc.opaque<"{}">} : () -> tuple, f32> return } // ----- func.func @illegal_tuple_float_element_type() { - // expected-error @+1 {{'emitc.variable' op result #0 must be type supported by EmitC, but got 'tuple'}} - %v = "emitc.variable"(){value = #emitc.opaque<"">} : () -> tuple + // expected-error @+1 {{'emitc.constant' op result #0 must be type supported by EmitC, but got 'tuple'}} + %v = "emitc.constant"(){value = #emitc.opaque<"{}">} : () -> tuple return } diff --git a/mlir/test/Dialect/EmitC/ops.mlir b/mlir/test/Dialect/EmitC/ops.mlir index 64f22e8ad6b98..e72fc74a74002 100644 --- a/mlir/test/Dialect/EmitC/ops.mlir +++ b/mlir/test/Dialect/EmitC/ops.mlir @@ -47,9 +47,9 @@ func.func @c() { return } -func.func @a(%arg0: i32, %arg1: i32) { - %1 = "emitc.apply"(%arg0) {applicableOperator = "&"} : (i32) -> !emitc.ptr - %2 = emitc.apply "&"(%arg1) : (i32) -> !emitc.ptr +func.func @a(%arg0: !emitc.lvalue, %arg1: !emitc.lvalue) { + %1 = "emitc.apply"(%arg0) {applicableOperator = "&"} : (!emitc.lvalue) -> !emitc.ptr + %2 = emitc.apply "&"(%arg1) : (!emitc.lvalue) -> !emitc.ptr return } @@ -173,8 +173,8 @@ func.func @test_if_else(%arg0: i1, %arg1: f32) { } func.func @test_assign(%arg1: f32) { - %v = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> f32 - emitc.assign %arg1 : f32 to %v : f32 + %v = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue + emitc.assign %arg1 : f32 to %v : !emitc.lvalue return } @@ -218,9 +218,9 @@ func.func @test_for_not_index_induction(%arg0 : i16, %arg1 : i16, %arg2 : i16) { } func.func @test_subscript(%arg0 : !emitc.array<2x3xf32>, %arg1 : !emitc.ptr, %arg2 : !emitc.opaque<"std::map">, %idx0 : index, %idx1 : i32, %idx2 : !emitc.opaque<"char">) { - %0 = emitc.subscript %arg0[%idx0, %idx1] : (!emitc.array<2x3xf32>, index, i32) -> f32 - %1 = emitc.subscript %arg1[%idx0] : (!emitc.ptr, index) -> i32 - %2 = emitc.subscript %arg2[%idx2] : (!emitc.opaque<"std::map">, !emitc.opaque<"char">) -> !emitc.opaque<"int"> + %0 = emitc.subscript %arg0[%idx0, %idx1] : (!emitc.array<2x3xf32>, index, i32) -> !emitc.lvalue + %1 = emitc.subscript %arg1[%idx0] : (!emitc.ptr, index) -> !emitc.lvalue + %2 = emitc.subscript %arg2[%idx2] : (!emitc.opaque<"std::map">, !emitc.opaque<"char">) -> !emitc.lvalue> return } @@ -245,25 +245,26 @@ emitc.global const @myconstant : !emitc.array<2xi16> = dense<2> func.func @use_global(%i: index) -> f32 { %0 = emitc.get_global @myglobal : !emitc.array<2xf32> - %1 = emitc.subscript %0[%i] : (!emitc.array<2xf32>, index) -> f32 - return %1 : f32 + %1 = emitc.subscript %0[%i] : (!emitc.array<2xf32>, index) -> !emitc.lvalue + %2 = emitc.lvalue_load %1 : + return %2 : f32 } func.func @assign_global(%arg0 : i32) { - %0 = emitc.get_global @myglobal_int : i32 - emitc.assign %arg0 : i32 to %0 : i32 + %0 = emitc.get_global @myglobal_int : !emitc.lvalue + emitc.assign %arg0 : i32 to %0 : !emitc.lvalue return } -func.func @member_access(%arg0: !emitc.opaque<"mystruct">, %arg1: !emitc.opaque<"mystruct_ptr">, %arg2: !emitc.ptr>) { - %0 = "emitc.member" (%arg0) {member = "a"} : (!emitc.opaque<"mystruct">) -> i32 - %1 = "emitc.member_of_ptr" (%arg1) {member = "a"} : (!emitc.opaque<"mystruct_ptr">) -> i32 - %2 = "emitc.member_of_ptr" (%arg2) {member = "a"} : (!emitc.ptr>) -> i32 +func.func @member_access(%arg0: !emitc.lvalue>, %arg1: !emitc.lvalue>, %arg2: !emitc.lvalue>>) { + %0 = "emitc.member" (%arg0) {member = "a"} : (!emitc.lvalue>) -> !emitc.lvalue + %1 = "emitc.member_of_ptr" (%arg1) {member = "a"} : (!emitc.lvalue>) -> !emitc.lvalue + %2 = "emitc.member_of_ptr" (%arg2) {member = "a"} : (!emitc.lvalue>>) -> !emitc.lvalue return } func.func @switch() { - %0 = "emitc.variable"(){value = 1 : index} : () -> !emitc.ptrdiff_t + %0 = "emitc.constant"(){value = 1 : index} : () -> !emitc.ptrdiff_t emitc.switch %0 : !emitc.ptrdiff_t case 1 { @@ -275,7 +276,7 @@ func.func @switch() { emitc.yield } default { - %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32 + %3 = "emitc.constant"(){value = 42.0 : f32} : () -> f32 emitc.call_opaque "func2" (%3) : (f32) -> () } diff --git a/mlir/test/Dialect/EmitC/transforms.mlir b/mlir/test/Dialect/EmitC/transforms.mlir index a5c582be4aa7f..996fd327f7af7 100644 --- a/mlir/test/Dialect/EmitC/transforms.mlir +++ b/mlir/test/Dialect/EmitC/transforms.mlir @@ -64,50 +64,24 @@ func.func @expression_with_call(%arg0: i32, %arg1: i32, %arg2: i32, %arg3: i32) return %c : i1 } -// CHECK-LABEL: func.func @expression_with_dereference( -// CHECK-SAME: %[[VAL_0:.*]]: i32, %[[VAL_1:.*]]: i32, %[[VAL_2:.*]]: !emitc.ptr) -> i1 { -// CHECK: %[[VAL_3:.*]] = emitc.expression : i32 { -// CHECK: %[[VAL_4:.*]] = emitc.apply "*"(%[[VAL_2]]) : (!emitc.ptr) -> i32 -// CHECK: emitc.yield %[[VAL_4]] : i32 -// CHECK: } -// CHECK: %[[VAL_5:.*]] = emitc.expression : i1 { -// CHECK: %[[VAL_6:.*]] = emitc.mul %[[VAL_0]], %[[VAL_1]] : (i32, i32) -> i32 -// CHECK: %[[VAL_7:.*]] = emitc.cmp lt, %[[VAL_6]], %[[VAL_3]] : (i32, i32) -> i1 +// CHECK-LABEL: func.func @expression_with_address_taken( +// CHECK-SAME: %[[VAL_0:.*]]: i32, %[[VAL_1:.*]]: i32, %[[VAL_2:.*]]: !emitc.ptr, %[[VAL_3:.*]]: !emitc.lvalue) -> i1 { +// CHECK: %[[VAL_4:.*]] = emitc.expression : i1 { +// CHECK: %[[VAL_5:.*]] = emitc.apply "&"(%[[VAL_3]]) : (!emitc.lvalue) -> !emitc.ptr +// CHECK: %[[VAL_6:.*]] = emitc.add %[[VAL_5]], %[[VAL_1]] : (!emitc.ptr, i32) -> !emitc.ptr +// CHECK: %[[VAL_7:.*]] = emitc.cmp lt, %[[VAL_6]], %[[VAL_2]] : (!emitc.ptr, !emitc.ptr) -> i1 // CHECK: emitc.yield %[[VAL_7]] : i1 // CHECK: } -// CHECK: return %[[VAL_5]] : i1 +// CHECK: return %[[VAL_4]] : i1 // CHECK: } -func.func @expression_with_dereference(%arg0: i32, %arg1: i32, %arg2: !emitc.ptr) -> i1 { - %a = emitc.mul %arg0, %arg1 : (i32, i32) -> i32 - %b = emitc.apply "*"(%arg2) : (!emitc.ptr) -> (i32) - %c = emitc.cmp lt, %a, %b :(i32, i32) -> i1 +func.func @expression_with_address_taken(%arg0: i32, %arg1: i32, %arg2: !emitc.ptr, %arg3: !emitc.lvalue) -> i1 { + %a = emitc.apply "&"(%arg3) : (!emitc.lvalue) -> !emitc.ptr + %b = emitc.add %a, %arg1 : (!emitc.ptr, i32) -> !emitc.ptr + %c = emitc.cmp lt, %b, %arg2 :(!emitc.ptr, !emitc.ptr) -> i1 return %c : i1 } -// CHECK-LABEL: func.func @expression_with_address_taken( -// CHECK-SAME: %[[VAL_0:.*]]: i32, %[[VAL_1:.*]]: i32, %[[VAL_2:.*]]: !emitc.ptr) -> i1 { -// CHECK: %[[VAL_3:.*]] = emitc.expression : i32 { -// CHECK: %[[VAL_4:.*]] = emitc.rem %[[VAL_0]], %[[VAL_1]] : (i32, i32) -> i32 -// CHECK: emitc.yield %[[VAL_4]] : i32 -// CHECK: } -// CHECK: %[[VAL_5:.*]] = emitc.expression : i1 { -// CHECK: %[[VAL_6:.*]] = emitc.apply "&"(%[[VAL_3]]) : (i32) -> !emitc.ptr -// CHECK: %[[VAL_7:.*]] = emitc.add %[[VAL_6]], %[[VAL_1]] : (!emitc.ptr, i32) -> !emitc.ptr -// CHECK: %[[VAL_8:.*]] = emitc.cmp lt, %[[VAL_7]], %[[VAL_2]] : (!emitc.ptr, !emitc.ptr) -> i1 -// CHECK: emitc.yield %[[VAL_8]] : i1 -// CHECK: } -// CHECK: return %[[VAL_5]] : i1 -// CHECK: } - -func.func @expression_with_address_taken(%arg0: i32, %arg1: i32, %arg2: !emitc.ptr) -> i1 { - %a = emitc.rem %arg0, %arg1 : (i32, i32) -> (i32) - %b = emitc.apply "&"(%a) : (i32) -> !emitc.ptr - %c = emitc.add %b, %arg1 : (!emitc.ptr, i32) -> !emitc.ptr - %d = emitc.cmp lt, %c, %arg2 :(!emitc.ptr, !emitc.ptr) -> i1 - return %d : i1 -} - // CHECK-LABEL: func.func @no_nested_expression( // CHECK-SAME: %[[VAL_0:.*]]: i32, %[[VAL_1:.*]]: i32) -> i1 { // CHECK: %[[VAL_2:.*]] = emitc.expression : i1 { diff --git a/mlir/test/Dialect/EmitC/types.mlir b/mlir/test/Dialect/EmitC/types.mlir index 66947a97e1f9f..e3462bffc5b0d 100644 --- a/mlir/test/Dialect/EmitC/types.mlir +++ b/mlir/test/Dialect/EmitC/types.mlir @@ -1,6 +1,6 @@ -// RUN: mlir-opt -verify-diagnostics %s | FileCheck %s +// RUN: mlir-opt -verify-diagnostics -allow-unregistered-dialect %s | FileCheck %s // check parser -// RUN: mlir-opt -verify-diagnostics %s | mlir-opt -verify-diagnostics | FileCheck %s +// RUN: mlir-opt -verify-diagnostics -allow-unregistered-dialect %s | mlir-opt -verify-diagnostics --allow-unregistered-dialect | FileCheck %s // CHECK-LABEL: func @array_types( func.func @array_types( @@ -22,6 +22,21 @@ func.func @array_types( return } +// CHECK-LABEL: func @lvalue_types( +func.func @lvalue_types() { + // CHECK-NEXT: !emitc.lvalue + %0 = "typed.result"() : () -> (!emitc.lvalue) + // CHECK-NEXT: !emitc.lvalue + %2 = "typed.result"() : () -> (!emitc.lvalue) + // CHECK-NEXT: !emitc.lvalue + %3 = "typed.result"() : () -> (!emitc.lvalue) + // CHECK-NEXT: !emitc.lvalue> + %4 = "typed.result"() : () -> (!emitc.lvalue>) + // CHECK-NEXT: !emitc.lvalue> + %5 = "typed.result"() : () -> (!emitc.lvalue>) + return +} + // CHECK-LABEL: func @opaque_types() { func.func @opaque_types() { // CHECK-NEXT: !emitc.opaque<"int"> diff --git a/mlir/test/Target/Cpp/common-cpp.mlir b/mlir/test/Target/Cpp/common-cpp.mlir index 0e24bdd19993f..8af29531905ba 100644 --- a/mlir/test/Target/Cpp/common-cpp.mlir +++ b/mlir/test/Target/Cpp/common-cpp.mlir @@ -82,11 +82,18 @@ func.func @opaque_types(%arg0: !emitc.opaque<"bool">, %arg1: !emitc.opaque<"char return %2 : !emitc.opaque<"status_t"> } -func.func @apply(%arg0: i32) -> !emitc.ptr { - // CHECK: int32_t* [[V2]] = &[[V1]]; - %0 = emitc.apply "&"(%arg0) : (i32) -> !emitc.ptr - // CHECK: int32_t [[V3]] = *[[V2]]; - %1 = emitc.apply "*"(%0) : (!emitc.ptr) -> (i32) +// CHECK-LABEL: int32_t* apply( +// CHECK-SAME: int32_t [[V1:[^ ]*]]) { +func.func @apply(%arg0: !emitc.lvalue) -> !emitc.ptr { + // CHECK-NEXT: int32_t* [[V2:[^ ]*]] = &[[V1]]; + %0 = emitc.apply "&"(%arg0) : (!emitc.lvalue) -> !emitc.ptr + // CHECK-NEXT: int32_t [[V3:[^ ]*]]; + %2 = "emitc.variable"() {value = #emitc.opaque<"">} : () -> !emitc.lvalue + // CHECK-NEXT: int32_t [[V4:[^ ]*]] = *[[V2]]; + %1 = emitc.apply "*"(%0) : (!emitc.ptr) -> i32 + // CHECK-NEXT: [[V3]] = [[V4]]; + emitc.assign %1 : i32 to %2 : !emitc.lvalue + // CHECK-NEXT: return [[V2]]; return %0 : !emitc.ptr } diff --git a/mlir/test/Target/Cpp/expressions.mlir b/mlir/test/Target/Cpp/expressions.mlir index caa0a340d3e0a..d9455e8e98177 100644 --- a/mlir/test/Target/Cpp/expressions.mlir +++ b/mlir/test/Target/Cpp/expressions.mlir @@ -9,12 +9,14 @@ // CPP-DEFAULT-NEXT: } else { // CPP-DEFAULT-NEXT: [[VAL_6]] = [[VAL_1]]; // CPP-DEFAULT-NEXT: } -// CPP-DEFAULT-NEXT: return [[VAL_6]]; +// CPP-DEFAULT-NEXT: int32_t [[VAL_7:v[0-9]+]] = [[VAL_6]]; +// CPP-DEFAULT-NEXT: return [[VAL_7]]; // CPP-DEFAULT-NEXT: } // CPP-DECLTOP: int32_t single_use(int32_t [[VAL_1:v[0-9]+]], int32_t [[VAL_2:v[0-9]+]], int32_t [[VAL_3:v[0-9]+]], int32_t [[VAL_4:v[0-9]+]]) { // CPP-DECLTOP-NEXT: bool [[VAL_5:v[0-9]+]]; // CPP-DECLTOP-NEXT: int32_t [[VAL_6:v[0-9]+]]; +// CPP-DECLTOP-NEXT: int32_t [[VAL_7:v[0-9]+]]; // CPP-DECLTOP-NEXT: [[VAL_5]] = bar([[VAL_1]] * M_PI, [[VAL_3]]) - [[VAL_4]] < [[VAL_2]]; // CPP-DECLTOP-NEXT: ; // CPP-DECLTOP-NEXT: if ([[VAL_5]]) { @@ -22,7 +24,8 @@ // CPP-DECLTOP-NEXT: } else { // CPP-DECLTOP-NEXT: [[VAL_6]] = [[VAL_1]]; // CPP-DECLTOP-NEXT: } -// CPP-DECLTOP-NEXT: return [[VAL_6]]; +// CPP-DECLTOP-NEXT: [[VAL_7]] = [[VAL_6]]; +// CPP-DECLTOP-NEXT: return [[VAL_7]]; // CPP-DECLTOP-NEXT: } func.func @single_use(%arg0: i32, %arg1: i32, %arg2: i32, %arg3: i32) -> i32 { @@ -34,15 +37,16 @@ func.func @single_use(%arg0: i32, %arg1: i32, %arg2: i32, %arg3: i32) -> i32 { %d = emitc.cmp lt, %c, %arg1 :(i32, i32) -> i1 emitc.yield %d : i1 } - %v = "emitc.variable"(){value = #emitc.opaque<"">} : () -> i32 + %v = "emitc.variable"(){value = #emitc.opaque<"">} : () -> !emitc.lvalue emitc.if %e { - emitc.assign %arg0 : i32 to %v : i32 + emitc.assign %arg0 : i32 to %v : !emitc.lvalue emitc.yield } else { - emitc.assign %arg0 : i32 to %v : i32 + emitc.assign %arg0 : i32 to %v : !emitc.lvalue emitc.yield } - return %v : i32 + %v_load = emitc.lvalue_load %v : !emitc.lvalue + return %v_load : i32 } // CPP-DEFAULT: int32_t do_not_inline(int32_t [[VAL_1:v[0-9]+]], int32_t [[VAL_2:v[0-9]+]], int32_t [[VAL_3:v[0-9]+]]) { @@ -175,8 +179,8 @@ func.func @user_with_expression_trait(%arg0: i32, %arg1: i32, %arg2: i32) -> i32 %add = emitc.add %e1, %c0 : (i32, i32) -> i32 %call = emitc.call_opaque "bar" (%e2, %c0) : (i32, i32) -> (i32) %cond = emitc.conditional %cast, %e3, %c0 : i32 - %var = "emitc.variable"() {value = #emitc.opaque<"">} : () -> i32 - emitc.assign %e4 : i32 to %var : i32 + %var = "emitc.variable"() {value = #emitc.opaque<"">} : () -> !emitc.lvalue + emitc.assign %e4 : i32 to %var : !emitc.lvalue return %e5 : i32 } @@ -190,13 +194,15 @@ func.func @user_with_expression_trait(%arg0: i32, %arg1: i32, %arg2: i32) -> i32 // CPP-DEFAULT-NEXT: } // CPP-DEFAULT-NEXT: bool [[VAL_7:v[0-9]+]]; // CPP-DEFAULT-NEXT: [[VAL_7]] = [[VAL_5]]; -// CPP-DEFAULT-NEXT: return [[VAL_6]]; +// CPP-DEFAULT-NEXT: int32_t [[VAL_8:v[0-9]+]] = [[VAL_6]]; +// CPP-DEFAULT-NEXT: return [[VAL_8]]; // CPP-DEFAULT-NEXT: } // CPP-DECLTOP: int32_t multiple_uses(int32_t [[VAL_1:v[0-9]+]], int32_t [[VAL_2:v[0-9]+]], int32_t [[VAL_3:v[0-9]+]], int32_t [[VAL_4:v[0-9]+]]) { // CPP-DECLTOP-NEXT: bool [[VAL_5:v[0-9]+]]; // CPP-DECLTOP-NEXT: int32_t [[VAL_6:v[0-9]+]]; // CPP-DECLTOP-NEXT: bool [[VAL_7:v[0-9]+]]; +// CPP-DECLTOP-NEXT: int32_t [[VAL_8:v[0-9]+]]; // CPP-DECLTOP-NEXT: [[VAL_5]] = bar([[VAL_1]] * [[VAL_2]], [[VAL_3]]) - [[VAL_4]] < [[VAL_2]]; // CPP-DECLTOP-NEXT: ; // CPP-DECLTOP-NEXT: if ([[VAL_5]]) { @@ -206,7 +212,8 @@ func.func @user_with_expression_trait(%arg0: i32, %arg1: i32, %arg2: i32) -> i32 // CPP-DECLTOP-NEXT: } // CPP-DECLTOP-NEXT: ; // CPP-DECLTOP-NEXT: [[VAL_7]] = [[VAL_5]]; -// CPP-DECLTOP-NEXT: return [[VAL_6]]; +// CPP-DECLTOP-NEXT: [[VAL_8]] = [[VAL_6]]; +// CPP-DECLTOP-NEXT: return [[VAL_8]]; // CPP-DECLTOP-NEXT: } func.func @multiple_uses(%arg0: i32, %arg1: i32, %arg2: i32, %arg3: i32) -> i32 { @@ -217,17 +224,18 @@ func.func @multiple_uses(%arg0: i32, %arg1: i32, %arg2: i32, %arg3: i32) -> i32 %d = emitc.cmp lt, %c, %arg1 :(i32, i32) -> i1 emitc.yield %d : i1 } - %v = "emitc.variable"(){value = #emitc.opaque<"">} : () -> i32 + %v = "emitc.variable"(){value = #emitc.opaque<"">} : () -> !emitc.lvalue emitc.if %e { - emitc.assign %arg0 : i32 to %v : i32 + emitc.assign %arg0 : i32 to %v : !emitc.lvalue emitc.yield } else { - emitc.assign %arg0 : i32 to %v : i32 + emitc.assign %arg0 : i32 to %v : !emitc.lvalue emitc.yield } - %q = "emitc.variable"(){value = #emitc.opaque<"">} : () -> i1 - emitc.assign %e : i1 to %q : i1 - return %v : i32 + %q = "emitc.variable"(){value = #emitc.opaque<"">} : () -> !emitc.lvalue + emitc.assign %e : i1 to %q : !emitc.lvalue + %v_load = emitc.lvalue_load %v : !emitc.lvalue + return %v_load : i32 } // CPP-DEFAULT: int32_t different_expressions(int32_t [[VAL_1:v[0-9]+]], int32_t [[VAL_2:v[0-9]+]], int32_t [[VAL_3:v[0-9]+]], int32_t [[VAL_4:v[0-9]+]]) { @@ -239,13 +247,15 @@ func.func @multiple_uses(%arg0: i32, %arg1: i32, %arg2: i32, %arg3: i32) -> i32 // CPP-DEFAULT-NEXT: } else { // CPP-DEFAULT-NEXT: [[VAL_7]] = [[VAL_1]]; // CPP-DEFAULT-NEXT: } -// CPP-DEFAULT-NEXT: return [[VAL_7]]; +// CPP-DEFAULT-NEXT: int32_t [[VAL_8:v[0-9]+]] = [[VAL_7]]; +// CPP-DEFAULT-NEXT: return [[VAL_8]]; // CPP-DEFAULT-NEXT: } // CPP-DECLTOP: int32_t different_expressions(int32_t [[VAL_1:v[0-9]+]], int32_t [[VAL_2:v[0-9]+]], int32_t [[VAL_3:v[0-9]+]], int32_t [[VAL_4:v[0-9]+]]) { // CPP-DECLTOP-NEXT: int32_t [[VAL_5:v[0-9]+]]; // CPP-DECLTOP-NEXT: int32_t [[VAL_6:v[0-9]+]]; // CPP-DECLTOP-NEXT: int32_t [[VAL_7:v[0-9]+]]; +// CPP-DECLTOP-NEXT: int32_t [[VAL_8:v[0-9]+]]; // CPP-DECLTOP-NEXT: [[VAL_5]] = [[VAL_3]] % [[VAL_4]]; // CPP-DECLTOP-NEXT: [[VAL_6]] = bar([[VAL_5]], [[VAL_1]] * [[VAL_2]]); // CPP-DECLTOP-NEXT: ; @@ -254,7 +264,8 @@ func.func @multiple_uses(%arg0: i32, %arg1: i32, %arg2: i32, %arg3: i32) -> i32 // CPP-DECLTOP-NEXT: } else { // CPP-DECLTOP-NEXT: [[VAL_7]] = [[VAL_1]]; // CPP-DECLTOP-NEXT: } -// CPP-DECLTOP-NEXT: return [[VAL_7]]; +// CPP-DECLTOP-NEXT: [[VAL_8]] = [[VAL_7]]; +// CPP-DECLTOP-NEXT: return [[VAL_8]]; // CPP-DECLTOP-NEXT: } func.func @different_expressions(%arg0: i32, %arg1: i32, %arg2: i32, %arg3: i32) -> i32 { @@ -272,35 +283,33 @@ func.func @different_expressions(%arg0: i32, %arg1: i32, %arg2: i32, %arg3: i32) %d = emitc.cmp lt, %c, %arg1 :(i32, i32) -> i1 emitc.yield %d : i1 } - %v = "emitc.variable"(){value = #emitc.opaque<"">} : () -> i32 + %v = "emitc.variable"(){value = #emitc.opaque<"">} : () -> !emitc.lvalue emitc.if %e3 { - emitc.assign %arg0 : i32 to %v : i32 + emitc.assign %arg0 : i32 to %v : !emitc.lvalue emitc.yield } else { - emitc.assign %arg0 : i32 to %v : i32 + emitc.assign %arg0 : i32 to %v : !emitc.lvalue emitc.yield } - return %v : i32 + %v_load = emitc.lvalue_load %v : !emitc.lvalue + return %v_load : i32 } // CPP-DEFAULT: bool expression_with_address_taken(int32_t [[VAL_1:v[0-9]+]], int32_t [[VAL_2:v[0-9]+]], int32_t* [[VAL_3]]) { -// CPP-DEFAULT-NEXT: int32_t [[VAL_4:v[0-9]+]] = [[VAL_1]] % [[VAL_2]]; +// CPP-DEFAULT-NEXT: int32_t [[VAL_4:v[0-9]+]] = 42; // CPP-DEFAULT-NEXT: return &[[VAL_4]] - [[VAL_2]] < [[VAL_3]]; // CPP-DEFAULT-NEXT: } // CPP-DECLTOP: bool expression_with_address_taken(int32_t [[VAL_1:v[0-9]+]], int32_t [[VAL_2:v[0-9]+]], int32_t* [[VAL_3]]) { // CPP-DECLTOP-NEXT: int32_t [[VAL_4:v[0-9]+]]; -// CPP-DECLTOP-NEXT: [[VAL_4]] = [[VAL_1]] % [[VAL_2]]; +// CPP-DECLTOP-NEXT: [[VAL_4]] = 42; // CPP-DECLTOP-NEXT: return &[[VAL_4]] - [[VAL_2]] < [[VAL_3]]; // CPP-DECLTOP-NEXT: } func.func @expression_with_address_taken(%arg0: i32, %arg1: i32, %arg2: !emitc.ptr) -> i1 { - %a = emitc.expression : i32 { - %b = emitc.rem %arg0, %arg1 : (i32, i32) -> i32 - emitc.yield %b : i32 - } + %a = "emitc.variable"(){value = 42 : i32} : () -> !emitc.lvalue %c = emitc.expression : i1 { - %d = emitc.apply "&"(%a) : (i32) -> !emitc.ptr + %d = emitc.apply "&"(%a) : (!emitc.lvalue) -> !emitc.ptr %e = emitc.sub %d, %arg1 : (!emitc.ptr, i32) -> !emitc.ptr %f = emitc.cmp lt, %e, %arg2 : (!emitc.ptr, !emitc.ptr) -> i1 emitc.yield %f : i1 @@ -311,7 +320,17 @@ func.func @expression_with_address_taken(%arg0: i32, %arg1: i32, %arg2: !emitc.p // CPP-DEFAULT: int32_t expression_with_subscript_user(void* [[VAL_1:v.+]]) // CPP-DEFAULT-NEXT: int64_t [[VAL_2:v.+]] = 0; // CPP-DEFAULT-NEXT: int32_t* [[VAL_3:v.+]] = (int32_t*) [[VAL_1]]; -// CPP-DEFAULT-NEXT: return [[VAL_3]][[[VAL_2]]]; +// CPP-DEFAULT-NEXT: int32_t [[VAL_4:v.+]] = [[VAL_3]][[[VAL_2]]]; +// CPP-DEFAULT-NEXT: return [[VAL_4]]; + +// CPP-DECLTOP: int32_t expression_with_subscript_user(void* [[VAL_1:v.+]]) +// CPP-DECLTOP-NEXT: int64_t [[VAL_2:v.+]]; +// CPP-DECLTOP-NEXT: int32_t* [[VAL_3:v.+]]; +// CPP-DECLTOP-NEXT: int32_t [[VAL_4:v.+]]; +// CPP-DECLTOP-NEXT: [[VAL_2]] = 0; +// CPP-DECLTOP-NEXT: [[VAL_3]] = (int32_t*) [[VAL_1]]; +// CPP-DECLTOP-NEXT: [[VAL_4]] = [[VAL_3]][[[VAL_2]]]; +// CPP-DECLTOP-NEXT: return [[VAL_4]]; func.func @expression_with_subscript_user(%arg0: !emitc.ptr>) -> i32 { %c0 = "emitc.constant"() {value = 0 : i64} : () -> i64 @@ -319,6 +338,7 @@ func.func @expression_with_subscript_user(%arg0: !emitc.ptr> to !emitc.ptr emitc.yield %0 : !emitc.ptr } - %1 = emitc.subscript %0[%c0] : (!emitc.ptr, i64) -> i32 - return %1 : i32 + %res = emitc.subscript %0[%c0] : (!emitc.ptr, i64) -> !emitc.lvalue + %res_load = emitc.lvalue_load %res : !emitc.lvalue + return %res_load : i32 } diff --git a/mlir/test/Target/Cpp/for.mlir b/mlir/test/Target/Cpp/for.mlir index af1d829113f9d..14d3f05d6a08e 100644 --- a/mlir/test/Target/Cpp/for.mlir +++ b/mlir/test/Target/Cpp/for.mlir @@ -40,17 +40,25 @@ func.func @test_for_yield() { %s0 = "emitc.constant"() <{value = 0 : i32}> : () -> i32 %p0 = "emitc.constant"() <{value = 1.0 : f32}> : () -> f32 - %2 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> i32 - %3 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> f32 - emitc.assign %s0 : i32 to %2 : i32 - emitc.assign %p0 : f32 to %3 : f32 + %0 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue + %1 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue + %2 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue + %3 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue + emitc.assign %s0 : i32 to %2 : !emitc.lvalue + emitc.assign %p0 : f32 to %3 : !emitc.lvalue emitc.for %iter = %start to %stop step %step { - %sn = emitc.call_opaque "add"(%2, %iter) : (i32, index) -> i32 - %pn = emitc.call_opaque "mul"(%3, %iter) : (f32, index) -> f32 - emitc.assign %sn : i32 to %2 : i32 - emitc.assign %pn : f32 to %3 : f32 + %4 = emitc.lvalue_load %2 : !emitc.lvalue + %sn = emitc.call_opaque "add"(%4, %iter) : (i32, index) -> i32 + %5 = emitc.lvalue_load %3 : !emitc.lvalue + %pn = emitc.call_opaque "mul"(%5, %iter) : (f32, index) -> f32 + emitc.assign %sn : i32 to %2 : !emitc.lvalue + emitc.assign %pn : f32 to %3 : !emitc.lvalue emitc.yield } + %6 = emitc.lvalue_load %2 : !emitc.lvalue + emitc.assign %6 : i32 to %0 : !emitc.lvalue + %7 = emitc.lvalue_load %3 : !emitc.lvalue + emitc.assign %7 : f32 to %1 : !emitc.lvalue return } @@ -60,16 +68,24 @@ func.func @test_for_yield() { // CPP-DEFAULT-NEXT: size_t [[STEP:[^ ]*]] = 1; // CPP-DEFAULT-NEXT: int32_t [[S0:[^ ]*]] = 0; // CPP-DEFAULT-NEXT: float [[P0:[^ ]*]] = 1.000000000e+00f; +// CPP-DEFAULT-NEXT: int32_t [[SE:[^ ]*]]; +// CPP-DEFAULT-NEXT: float [[PE:[^ ]*]]; // CPP-DEFAULT-NEXT: int32_t [[SI:[^ ]*]]; // CPP-DEFAULT-NEXT: float [[PI:[^ ]*]]; // CPP-DEFAULT-NEXT: [[SI:[^ ]*]] = [[S0]]; // CPP-DEFAULT-NEXT: [[PI:[^ ]*]] = [[P0]]; // CPP-DEFAULT-NEXT: for (size_t [[ITER:[^ ]*]] = [[START]]; [[ITER]] < [[STOP]]; [[ITER]] += [[STEP]]) { -// CPP-DEFAULT-NEXT: int32_t [[SN:[^ ]*]] = add([[SI]], [[ITER]]); -// CPP-DEFAULT-NEXT: float [[PN:[^ ]*]] = mul([[PI]], [[ITER]]); +// CPP-DEFAULT-NEXT: int32_t [[SI_LOAD:[^ ]*]] = [[SI]]; +// CPP-DEFAULT-NEXT: int32_t [[SN:[^ ]*]] = add([[SI_LOAD]], [[ITER]]); +// CPP-DEFAULT-NEXT: float [[PI_LOAD:[^ ]*]] = [[PI]]; +// CPP-DEFAULT-NEXT: float [[PN:[^ ]*]] = mul([[PI_LOAD]], [[ITER]]); // CPP-DEFAULT-NEXT: [[SI]] = [[SN]]; // CPP-DEFAULT-NEXT: [[PI]] = [[PN]]; // CPP-DEFAULT-NEXT: } +// CPP-DEFAULT-NEXT: int32_t [[SI_LOAD2:[^ ]*]] = [[SI]]; +// CPP-DEFAULT-NEXT: [[SE]] = [[SI_LOAD2]]; +// CPP-DEFAULT-NEXT: float [[PI_LOAD2:[^ ]*]] = [[PI]]; +// CPP-DEFAULT-NEXT: [[PE]] = [[PI_LOAD2]]; // CPP-DEFAULT-NEXT: return; // CPP-DECLTOP: void test_for_yield() { @@ -78,10 +94,16 @@ func.func @test_for_yield() { // CPP-DECLTOP-NEXT: size_t [[STEP:[^ ]*]]; // CPP-DECLTOP-NEXT: int32_t [[S0:[^ ]*]]; // CPP-DECLTOP-NEXT: float [[P0:[^ ]*]]; +// CPP-DECLTOP-NEXT: int32_t [[SE:[^ ]*]]; +// CPP-DECLTOP-NEXT: float [[PE:[^ ]*]]; // CPP-DECLTOP-NEXT: int32_t [[SI:[^ ]*]]; // CPP-DECLTOP-NEXT: float [[PI:[^ ]*]]; +// CPP-DECLTOP-NEXT: int32_t [[SI_LOAD:[^ ]*]]; // CPP-DECLTOP-NEXT: int32_t [[SN:[^ ]*]]; +// CPP-DECLTOP-NEXT: float [[PI_LOAD:[^ ]*]]; // CPP-DECLTOP-NEXT: float [[PN:[^ ]*]]; +// CPP-DECLTOP-NEXT: int32_t [[SI_LOAD2:[^ ]*]]; +// CPP-DECLTOP-NEXT: float [[PI_LOAD2:[^ ]*]]; // CPP-DECLTOP-NEXT: [[START]] = 0; // CPP-DECLTOP-NEXT: [[STOP]] = 10; // CPP-DECLTOP-NEXT: [[STEP]] = 1; @@ -89,14 +111,22 @@ func.func @test_for_yield() { // CPP-DECLTOP-NEXT: [[P0]] = 1.000000000e+00f; // CPP-DECLTOP-NEXT: ; // CPP-DECLTOP-NEXT: ; -// CPP-DECLTOP-NEXT: [[SI:[^ ]*]] = [[S0]]; -// CPP-DECLTOP-NEXT: [[PI:[^ ]*]] = [[P0]]; +// CPP-DECLTOP-NEXT: ; +// CPP-DECLTOP-NEXT: ; +// CPP-DECLTOP-NEXT: [[SI]] = [[S0]]; +// CPP-DECLTOP-NEXT: [[PI]] = [[P0]]; // CPP-DECLTOP-NEXT: for (size_t [[ITER:[^ ]*]] = [[START]]; [[ITER]] < [[STOP]]; [[ITER]] += [[STEP]]) { -// CPP-DECLTOP-NEXT: [[SN]] = add([[SI]], [[ITER]]); -// CPP-DECLTOP-NEXT: [[PN]] = mul([[PI]], [[ITER]]); +// CPP-DECLTOP-NEXT: [[SI_LOAD]] = [[SI]]; +// CPP-DECLTOP-NEXT: [[SN]] = add([[SI_LOAD]], [[ITER]]); +// CPP-DECLTOP-NEXT: [[PI_LOAD]] = [[PI]]; +// CPP-DECLTOP-NEXT: [[PN]] = mul([[PI_LOAD]], [[ITER]]); // CPP-DECLTOP-NEXT: [[SI]] = [[SN]]; // CPP-DECLTOP-NEXT: [[PI]] = [[PN]]; // CPP-DECLTOP-NEXT: } +// CPP-DECLTOP-NEXT: [[SI_LOAD2]] = [[SI]]; +// CPP-DECLTOP-NEXT: [[SE]] = [[SI_LOAD2]]; +// CPP-DECLTOP-NEXT: [[PI_LOAD2]] = [[PI]]; +// CPP-DECLTOP-NEXT: [[PE]] = [[PI_LOAD2]]; // CPP-DECLTOP-NEXT: return; func.func @test_for_yield_2() { @@ -107,17 +137,25 @@ func.func @test_for_yield_2() { %s0 = emitc.literal "0" : i32 %p0 = emitc.literal "M_PI" : f32 - %2 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> i32 - %3 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> f32 - emitc.assign %s0 : i32 to %2 : i32 - emitc.assign %p0 : f32 to %3 : f32 + %0 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue + %1 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue + %2 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue + %3 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue + emitc.assign %s0 : i32 to %2 : !emitc.lvalue + emitc.assign %p0 : f32 to %3 : !emitc.lvalue emitc.for %iter = %start to %stop step %step { - %sn = emitc.call_opaque "add"(%2, %iter) : (i32, index) -> i32 - %pn = emitc.call_opaque "mul"(%3, %iter) : (f32, index) -> f32 - emitc.assign %sn : i32 to %2 : i32 - emitc.assign %pn : f32 to %3 : f32 + %4 = emitc.lvalue_load %2 : !emitc.lvalue + %sn = emitc.call_opaque "add"(%4, %iter) : (i32, index) -> i32 + %5 = emitc.lvalue_load %3 : !emitc.lvalue + %pn = emitc.call_opaque "mul"(%5, %iter) : (f32, index) -> f32 + emitc.assign %sn : i32 to %2 : !emitc.lvalue + emitc.assign %pn : f32 to %3 : !emitc.lvalue emitc.yield } + %6 = emitc.lvalue_load %2 : !emitc.lvalue + emitc.assign %6 : i32 to %0 : !emitc.lvalue + %7 = emitc.lvalue_load %3 : !emitc.lvalue + emitc.assign %7 : f32 to %1 : !emitc.lvalue return } diff --git a/mlir/test/Target/Cpp/global.mlir b/mlir/test/Target/Cpp/global.mlir index bddd94aea4219..b2d61681dbd60 100644 --- a/mlir/test/Target/Cpp/global.mlir +++ b/mlir/test/Target/Cpp/global.mlir @@ -38,18 +38,22 @@ emitc.global @opaque_init : !emitc.opaque<"char"> = #emitc.opaque<"CHAR_MIN"> // CPP-DECLTOP: char opaque_init = CHAR_MIN; func.func @use_global_scalar_read() -> i32 { - %0 = emitc.get_global @myglobal_int : i32 - return %0 : i32 + %0 = emitc.get_global @myglobal_int : !emitc.lvalue + %1 = emitc.lvalue_load %0 : !emitc.lvalue + return %1 : i32 } // CPP-DEFAULT-LABEL: int32_t use_global_scalar_read() -// CPP-DEFAULT-NEXT: return myglobal_int; +// CPP-DEFAULT-NEXT: int32_t [[V0:[^ ]*]] = myglobal_int; +// CPP-DEFAULT-NEXT: return [[V0]]; // CPP-DECLTOP-LABEL: int32_t use_global_scalar_read() -// CPP-DECLTOP-NEXT: return myglobal_int; +// CPP-DECLTOP-NEXT: int32_t [[V0:[^ ]*]]; +// CPP-DECLTOP-NEXT: [[V0]] = myglobal_int; +// CPP-DECLTOP-NEXT: return [[V0]]; func.func @use_global_scalar_write(%arg0 : i32) { - %0 = emitc.get_global @myglobal_int : i32 - emitc.assign %arg0 : i32 to %0 : i32 + %0 = emitc.get_global @myglobal_int : !emitc.lvalue + emitc.assign %arg0 : i32 to %0 : !emitc.lvalue return } // CPP-DEFAULT-LABEL: void use_global_scalar_write @@ -64,21 +68,25 @@ func.func @use_global_scalar_write(%arg0 : i32) { func.func @use_global_array_read(%i: index) -> f32 { %0 = emitc.get_global @myglobal : !emitc.array<2xf32> - %1 = emitc.subscript %0[%i] : (!emitc.array<2xf32>, index) -> f32 - return %1 : f32 + %1 = emitc.subscript %0[%i] : (!emitc.array<2xf32>, index) -> !emitc.lvalue + %2 = emitc.lvalue_load %1 : !emitc.lvalue + return %2 : f32 } // CPP-DEFAULT-LABEL: float use_global_array_read // CPP-DEFAULT-SAME: (size_t [[V1:.*]]) -// CPP-DEFAULT-NEXT: return myglobal[[[V1]]]; +// CPP-DEFAULT-NEXT: float [[V2:.*]] = myglobal[[[V1]]]; +// CPP-DEFAULT-NEXT: return [[V2]]; // CPP-DECLTOP-LABEL: float use_global_array_read // CPP-DECLTOP-SAME: (size_t [[V1:.*]]) -// CPP-DECLTOP-NEXT: return myglobal[[[V1]]]; +// CPP-DECLTOP-NEXT: float [[V2:.*]]; +// CPP-DECLTOP-NEXT: [[V2]] = myglobal[[[V1]]]; +// CPP-DECLTOP-NEXT: return [[V2]]; func.func @use_global_array_write(%i: index, %val : f32) { %0 = emitc.get_global @myglobal : !emitc.array<2xf32> - %1 = emitc.subscript %0[%i] : (!emitc.array<2xf32>, index) -> f32 - emitc.assign %val : f32 to %1 : f32 + %1 = emitc.subscript %0[%i] : (!emitc.array<2xf32>, index) -> !emitc.lvalue + emitc.assign %val : f32 to %1 : !emitc.lvalue return } // CPP-DEFAULT-LABEL: void use_global_array_write diff --git a/mlir/test/Target/Cpp/if.mlir b/mlir/test/Target/Cpp/if.mlir index 7b0e2da85d0eb..d3b792192c8b1 100644 --- a/mlir/test/Target/Cpp/if.mlir +++ b/mlir/test/Target/Cpp/if.mlir @@ -50,18 +50,18 @@ func.func @test_if_else(%arg0: i1, %arg1: f32) { func.func @test_if_yield(%arg0: i1, %arg1: f32) { %0 = "emitc.constant"() <{value = 0 : i8}> : () -> i8 - %x = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> i32 - %y = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> f64 + %x = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue + %y = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue emitc.if %arg0 { %1 = emitc.call_opaque "func_true_1"(%arg1) : (f32) -> i32 %2 = emitc.call_opaque "func_true_2"(%arg1) : (f32) -> f64 - emitc.assign %1 : i32 to %x : i32 - emitc.assign %2 : f64 to %y : f64 + emitc.assign %1 : i32 to %x : !emitc.lvalue + emitc.assign %2 : f64 to %y : !emitc.lvalue } else { %1 = emitc.call_opaque "func_false_1"(%arg1) : (f32) -> i32 %2 = emitc.call_opaque "func_false_2"(%arg1) : (f32) -> f64 - emitc.assign %1 : i32 to %x : i32 - emitc.assign %2 : f64 to %y : f64 + emitc.assign %1 : i32 to %x : !emitc.lvalue + emitc.assign %2 : f64 to %y : !emitc.lvalue } return } diff --git a/mlir/test/Target/Cpp/invalid.mlir b/mlir/test/Target/Cpp/invalid.mlir index 4e777239fba66..89f984f85347f 100644 --- a/mlir/test/Target/Cpp/invalid.mlir +++ b/mlir/test/Target/Cpp/invalid.mlir @@ -83,6 +83,6 @@ func.func @array_as_result(%arg: !emitc.array<4xi8>) -> (!emitc.array<4xi8>) { func.func @ptr_to_array() { // expected-error@+1 {{cannot emit pointer to array type '!emitc.ptr>'}} - %v = "emitc.variable"(){value = #emitc.opaque<"NULL">} : () -> !emitc.ptr> + %v = "emitc.variable"(){value = #emitc.opaque<"NULL">} : () -> !emitc.lvalue>> return } diff --git a/mlir/test/Target/Cpp/lvalue.mlir b/mlir/test/Target/Cpp/lvalue.mlir new file mode 100644 index 0000000000000..ce76dd7a7cfeb --- /dev/null +++ b/mlir/test/Target/Cpp/lvalue.mlir @@ -0,0 +1,17 @@ +// RUN: mlir-translate -mlir-to-cpp %s | FileCheck %s + +// CHECK: int32_t lvalue_variables( +emitc.func @lvalue_variables(%v1: i32, %v2: i32) -> i32 { + %val = emitc.mul %v1, %v2 : (i32, i32) -> i32 + %variable = "emitc.variable"() {value = #emitc.opaque<"">} : () -> !emitc.lvalue // alloc effect + emitc.assign %val : i32 to %variable : !emitc.lvalue // write effect + %addr = emitc.apply "&"(%variable) : (!emitc.lvalue) -> !emitc.ptr + emitc.call @zero (%addr) : (!emitc.ptr) -> () + %updated_val = emitc.lvalue_load %variable : !emitc.lvalue // read effect, (noop in emitter?) + %neg_one = "emitc.constant"() {value = -1 : i32} : () -> i32 + emitc.assign %neg_one : i32 to %variable : !emitc.lvalue // invalidates %updated_val + emitc.return %updated_val : i32 + // dealloc effect through automatic allocation scope +} + +emitc.func @zero(%arg0: !emitc.ptr) attributes {specifiers = ["extern"]} \ No newline at end of file diff --git a/mlir/test/Target/Cpp/member.mlir b/mlir/test/Target/Cpp/member.mlir index 1b4a3dcab879d..d1c453f07cda5 100644 --- a/mlir/test/Target/Cpp/member.mlir +++ b/mlir/test/Target/Cpp/member.mlir @@ -1,34 +1,39 @@ // RUN: mlir-translate -mlir-to-cpp %s | FileCheck %s -check-prefix=CPP-DEFAULT -func.func @member(%arg0: !emitc.opaque<"mystruct">, %arg1: i32) { - %0 = "emitc.member" (%arg0) {member = "a"} : (!emitc.opaque<"mystruct">) -> i32 - emitc.assign %arg1 : i32 to %0 : i32 +func.func @member(%arg0: !emitc.lvalue>, %arg1: i32) { + %0 = "emitc.member" (%arg0) {member = "a"} : (!emitc.lvalue>) -> !emitc.lvalue + emitc.assign %arg1 : i32 to %0 : !emitc.lvalue - %1 = "emitc.member" (%arg0) {member = "b"} : (!emitc.opaque<"mystruct">) -> i32 - %2 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> i32 - emitc.assign %1 : i32 to %2 : i32 + %1 = "emitc.member" (%arg0) {member = "b"} : (!emitc.lvalue>) -> !emitc.lvalue + %2 = emitc.lvalue_load %1 : !emitc.lvalue + %3 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue + emitc.assign %2 : i32 to %3 : !emitc.lvalue return } // CPP-DEFAULT: void member(mystruct [[V0:[^ ]*]], int32_t [[V1:[^ ]*]]) { -// CPP-DEFAULT-NEXT: [[V0:[^ ]*]].a = [[V1:[^ ]*]]; -// CPP-DEFAULT-NEXT: int32_t [[V2:[^ ]*]]; -// CPP-DEFAULT-NEXT: [[V2:[^ ]*]] = [[V0:[^ ]*]].b; +// CPP-DEFAULT-NEXT: [[V0]].a = [[V1]]; +// CPP-DEFAULT-NEXT: int32_t [[V2:[^ ]*]] = [[V0]].b; +// CPP-DEFAULT-NEXT: int32_t [[V3:[^ ]*]]; +// CPP-DEFAULT-NEXT: [[V3]] = [[V2]]; -func.func @member_of_pointer(%arg0: !emitc.ptr>, %arg1: i32) { - %0 = "emitc.member_of_ptr" (%arg0) {member = "a"} : (!emitc.ptr>) -> i32 - emitc.assign %arg1 : i32 to %0 : i32 +func.func @member_of_pointer(%arg0: !emitc.lvalue>>, %arg1: i32) { + %0 = "emitc.member_of_ptr" (%arg0) {member = "a"} : (!emitc.lvalue>>) -> !emitc.lvalue + emitc.assign %arg1 : i32 to %0 : !emitc.lvalue - %1 = "emitc.member_of_ptr" (%arg0) {member = "b"} : (!emitc.ptr>) -> i32 - %2 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> i32 - emitc.assign %1 : i32 to %2 : i32 + %1 = "emitc.member_of_ptr" (%arg0) {member = "b"} : (!emitc.lvalue>>) -> !emitc.lvalue + %2 = emitc.lvalue_load %1 : !emitc.lvalue + %3 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue + emitc.assign %2 : i32 to %3 : !emitc.lvalue return } // CPP-DEFAULT: void member_of_pointer(mystruct* [[V0:[^ ]*]], int32_t [[V1:[^ ]*]]) { -// CPP-DEFAULT-NEXT: [[V0:[^ ]*]]->a = [[V1:[^ ]*]]; -// CPP-DEFAULT-NEXT: int32_t [[V2:[^ ]*]]; -// CPP-DEFAULT-NEXT: [[V2:[^ ]*]] = [[V0:[^ ]*]]->b; +// CPP-DEFAULT-NEXT: [[V0]]->a = [[V1]]; +// CPP-DEFAULT-NEXT: int32_t [[V2:[^ ]*]] = [[V0]]->b; +// CPP-DEFAULT-NEXT: int32_t [[V3:[^ ]*]]; +// CPP-DEFAULT-NEXT: [[V3]] = [[V2]]; + diff --git a/mlir/test/Target/Cpp/subscript.mlir b/mlir/test/Target/Cpp/subscript.mlir index 0b388953c80d3..b5c94c146712e 100644 --- a/mlir/test/Target/Cpp/subscript.mlir +++ b/mlir/test/Target/Cpp/subscript.mlir @@ -1,35 +1,59 @@ -// RUN: mlir-translate -mlir-to-cpp %s | FileCheck %s -// RUN: mlir-translate -mlir-to-cpp -declare-variables-at-top %s | FileCheck %s +// RUN: mlir-translate -mlir-to-cpp %s | FileCheck %s -check-prefix=CPP-DEFAULT +// RUN: mlir-translate -mlir-to-cpp -declare-variables-at-top %s | FileCheck %s -check-prefix=CPP-DECLTOP func.func @load_store_array(%arg0: !emitc.array<4x8xf32>, %arg1: !emitc.array<3x5xf32>, %arg2: index, %arg3: index) { - %0 = emitc.subscript %arg0[%arg2, %arg3] : (!emitc.array<4x8xf32>, index, index) -> f32 - %1 = emitc.subscript %arg1[%arg2, %arg3] : (!emitc.array<3x5xf32>, index, index) -> f32 - emitc.assign %0 : f32 to %1 : f32 + %0 = emitc.subscript %arg0[%arg2, %arg3] : (!emitc.array<4x8xf32>, index, index) -> !emitc.lvalue + %1 = emitc.subscript %arg1[%arg2, %arg3] : (!emitc.array<3x5xf32>, index, index) -> !emitc.lvalue + %2 = emitc.lvalue_load %0 : + emitc.assign %2 : f32 to %1 : !emitc.lvalue return } -// CHECK: void load_store_array(float [[ARR1:[^ ]*]][4][8], float [[ARR2:[^ ]*]][3][5], -// CHECK-SAME: size_t [[I:[^ ]*]], size_t [[J:[^ ]*]]) -// CHECK-NEXT: [[ARR2]][[[I]]][[[J]]] = [[ARR1]][[[I]]][[[J]]]; +// CPP-DEFAULT: void load_store_array(float [[ARR1:[^ ]*]][4][8], float [[ARR2:[^ ]*]][3][5], +// CPP-DEFAULT-SAME: size_t [[I:[^ ]*]], size_t [[J:[^ ]*]]) +// CPP-DEFAULT-NEXT: float [[VAL:[^ ]*]] = [[ARR1]][[[I]]][[[J]]]; +// CPP-DEFAULT-NEXT: [[ARR2]][[[I]]][[[J]]] = [[VAL]]; + +// CPP-DECLTOP: void load_store_array(float [[ARR1:[^ ]*]][4][8], float [[ARR2:[^ ]*]][3][5], +// CPP-DECLTOP-SAME: size_t [[I:[^ ]*]], size_t [[J:[^ ]*]]) +// CPP-DECLTOP-NEXT: float [[VAL:[^ ]*]]; +// CPP-DECLTOP-NEXT: [[VAL]] = [[ARR1]][[[I]]][[[J]]]; +// CPP-DECLTOP-NEXT: [[ARR2]][[[I]]][[[J]]] = [[VAL]]; func.func @load_store_pointer(%arg0: !emitc.ptr, %arg1: !emitc.ptr, %arg2: index, %arg3: index) { - %0 = emitc.subscript %arg0[%arg2] : (!emitc.ptr, index) -> f32 - %1 = emitc.subscript %arg1[%arg3] : (!emitc.ptr, index) -> f32 - emitc.assign %0 : f32 to %1 : f32 + %0 = emitc.subscript %arg0[%arg2] : (!emitc.ptr, index) -> !emitc.lvalue + %1 = emitc.subscript %arg1[%arg3] : (!emitc.ptr, index) -> !emitc.lvalue + %2 = emitc.lvalue_load %0 : + emitc.assign %2 : f32 to %1 : return } -// CHECK: void load_store_pointer(float* [[PTR1:[^ ]*]], float* [[PTR2:[^ ]*]], -// CHECK-SAME: size_t [[I:[^ ]*]], size_t [[J:[^ ]*]]) -// CHECK-NEXT: [[PTR2]][[[J]]] = [[PTR1]][[[I]]]; +// CPP-DEFAULT: void load_store_pointer(float* [[PTR1:[^ ]*]], float* [[PTR2:[^ ]*]], +// CPP-DEFAULT-SAME: size_t [[I:[^ ]*]], size_t [[J:[^ ]*]]) +// CPP-DEFAULT-NEXT: float [[VAL:[^ ]*]] = [[PTR1]][[[I]]]; +// CPP-DEFAULT-NEXT: [[PTR2]][[[J]]] = [[VAL]]; + +// CPP-DECLTOP: void load_store_pointer(float* [[PTR1:[^ ]*]], float* [[PTR2:[^ ]*]], +// CPP-DECLTOP-SAME: size_t [[I:[^ ]*]], size_t [[J:[^ ]*]]) +// CPP-DECLTOP-NEXT: float [[VAL:[^ ]*]]; +// CPP-DECLTOP-NEXT: [[VAL]] = [[PTR1]][[[I]]]; +// CPP-DECLTOP-NEXT: [[PTR2]][[[J]]] = [[VAL]]; func.func @load_store_opaque(%arg0: !emitc.opaque<"std::map">, %arg1: !emitc.opaque<"std::map">, %arg2: !emitc.opaque<"char">, %arg3: !emitc.opaque<"char">) { - %0 = emitc.subscript %arg0[%arg2] : (!emitc.opaque<"std::map">, !emitc.opaque<"char">) -> !emitc.opaque<"int"> - %1 = emitc.subscript %arg1[%arg3] : (!emitc.opaque<"std::map">, !emitc.opaque<"char">) -> !emitc.opaque<"int"> - emitc.assign %0 : !emitc.opaque<"int"> to %1 : !emitc.opaque<"int"> + %0 = emitc.subscript %arg0[%arg2] : (!emitc.opaque<"std::map">, !emitc.opaque<"char">) -> !emitc.lvalue> + %1 = emitc.subscript %arg1[%arg3] : (!emitc.opaque<"std::map">, !emitc.opaque<"char">) -> !emitc.lvalue> + %2 = emitc.lvalue_load %0 : > + emitc.assign %2 : !emitc.opaque<"int"> to %1 : > return } -// CHECK: void load_store_opaque(std::map [[MAP1:[^ ]*]], std::map [[MAP2:[^ ]*]], -// CHECK-SAME: char [[I:[^ ]*]], char [[J:[^ ]*]]) -// CHECK-NEXT: [[MAP2]][[[J]]] = [[MAP1]][[[I]]]; +// CPP-DEFAULT: void load_store_opaque(std::map [[MAP1:[^ ]*]], std::map [[MAP2:[^ ]*]], +// CPP-DEFAULT-SAME: char [[I:[^ ]*]], char [[J:[^ ]*]]) +// CPP-DEFAULT-NEXT: int [[VAL:[^ ]*]] = [[MAP1]][[[I]]]; +// CPP-DEFAULT-NEXT: [[MAP2]][[[J]]] = [[VAL]]; + +// CPP-DECLTOP: void load_store_opaque(std::map [[MAP1:[^ ]*]], std::map [[MAP2:[^ ]*]], +// CPP-DECLTOP-SAME: char [[I:[^ ]*]], char [[J:[^ ]*]]) +// CPP-DECLTOP-NEXT: int [[VAL:[^ ]*]]; +// CPP-DECLTOP-NEXT: [[VAL]] = [[MAP1]][[[I]]]; +// CPP-DECLTOP-NEXT: [[MAP2]][[[J]]] = [[VAL]]; emitc.func @func1(%arg0 : f32) { emitc.return @@ -37,16 +61,38 @@ emitc.func @func1(%arg0 : f32) { emitc.func @call_arg(%arg0: !emitc.array<4x8xf32>, %i: i32, %j: i16, %k: i8) { - %0 = emitc.subscript %arg0[%i, %j] : (!emitc.array<4x8xf32>, i32, i16) -> f32 - %1 = emitc.subscript %arg0[%j, %k] : (!emitc.array<4x8xf32>, i16, i8) -> f32 + %0 = emitc.subscript %arg0[%i, %j] : (!emitc.array<4x8xf32>, i32, i16) -> !emitc.lvalue + %1 = emitc.subscript %arg0[%j, %k] : (!emitc.array<4x8xf32>, i16, i8) -> !emitc.lvalue - emitc.call @func1 (%0) : (f32) -> () - emitc.call_opaque "func2" (%1) : (f32) -> () - emitc.call_opaque "func3" (%0, %1) { args = [1 : index, 0 : index] } : (f32, f32) -> () + %2 = emitc.lvalue_load %0 : + emitc.call @func1 (%2) : (f32) -> () + %3 = emitc.lvalue_load %1 : + emitc.call_opaque "func2" (%3) : (f32) -> () + %4 = emitc.lvalue_load %0 : + %5 = emitc.lvalue_load %1 : + emitc.call_opaque "func3" (%4, %5) { args = [1 : index, 0 : index] } : (f32, f32) -> () emitc.return } -// CHECK: void call_arg(float [[ARR1:[^ ]*]][4][8], int32_t [[I:[^ ]*]], -// CHECK-SAME: int16_t [[J:[^ ]*]], int8_t [[K:[^ ]*]]) -// CHECK-NEXT: func1([[ARR1]][[[I]]][[[J]]]); -// CHECK-NEXT: func2([[ARR1]][[[J]]][[[K]]]); -// CHECK-NEXT: func3([[ARR1]][[[J]]][[[K]]], [[ARR1]][[[I]]][[[J]]]); +// CPP-DEFAULT: void call_arg(float [[ARR1:[^ ]*]][4][8], int32_t [[I:[^ ]*]], +// CPP-DEFAULT-SAME: int16_t [[J:[^ ]*]], int8_t [[K:[^ ]*]]) +// CPP-DEFAULT-NEXT: float [[VAL0:[^ ]*]] = [[ARR1]][[[I]]][[[J]]]; +// CPP-DEFAULT-NEXT: func1([[VAL0]]); +// CPP-DEFAULT-NEXT: float [[VAL1:[^ ]*]] = [[ARR1]][[[J]]][[[K]]]; +// CPP-DEFAULT-NEXT: func2([[VAL1]]); +// CPP-DEFAULT-NEXT: float [[VAL2:[^ ]*]] = [[ARR1]][[[I]]][[[J]]]; +// CPP-DEFAULT-NEXT: float [[VAL3:[^ ]*]] = [[ARR1]][[[J]]][[[K]]]; +// CPP-DEFAULT-NEXT: func3([[VAL3]], [[VAL2]]); + +// CPP-DECLTOP: void call_arg(float [[ARR1:[^ ]*]][4][8], int32_t [[I:[^ ]*]], +// CPP-DECLTOP-SAME: int16_t [[J:[^ ]*]], int8_t [[K:[^ ]*]]) +// CPP-DECLTOP-NEXT: float [[VAL0:[^ ]*]]; +// CPP-DECLTOP-NEXT: float [[VAL1:[^ ]*]]; +// CPP-DECLTOP-NEXT: float [[VAL2:[^ ]*]]; +// CPP-DECLTOP-NEXT: float [[VAL3:[^ ]*]]; +// CPP-DECLTOP-NEXT: [[VAL0]] = [[ARR1]][[[I]]][[[J]]]; +// CPP-DECLTOP-NEXT: func1([[VAL0]]); +// CPP-DECLTOP-NEXT: [[VAL1]] = [[ARR1]][[[J]]][[[K]]]; +// CPP-DECLTOP-NEXT: func2([[VAL1]]); +// CPP-DECLTOP-NEXT: [[VAL2]] = [[ARR1]][[[I]]][[[J]]]; +// CPP-DECLTOP-NEXT: [[VAL3]] = [[ARR1]][[[J]]][[[K]]]; +// CPP-DECLTOP-NEXT: func3([[VAL3]], [[VAL2]]); diff --git a/mlir/test/Target/Cpp/switch.mlir b/mlir/test/Target/Cpp/switch.mlir index 0f2e716a98f16..f9b8600606ec2 100644 --- a/mlir/test/Target/Cpp/switch.mlir +++ b/mlir/test/Target/Cpp/switch.mlir @@ -43,7 +43,7 @@ // CPP-DECLTOP: return; // CPP-DECLTOP: } func.func @emitc_switch_ptrdiff_t() { - %0 = "emitc.variable"(){value = 1 : index} : () -> !emitc.ptrdiff_t + %0 = "emitc.constant"(){value = 1 : index} : () -> !emitc.ptrdiff_t emitc.switch %0 : !emitc.ptrdiff_t case 2 { @@ -55,7 +55,7 @@ func.func @emitc_switch_ptrdiff_t() { emitc.yield } default { - %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32 + %3 = "emitc.constant"(){value = 42.0 : f32} : () -> f32 emitc.call_opaque "func2" (%3) : (f32) -> () } return @@ -103,7 +103,7 @@ func.func @emitc_switch_ptrdiff_t() { // CPP-DECLTOP: return; // CPP-DECLTOP: } func.func @emitc_switch_ssize_t() { - %0 = "emitc.variable"(){value = 1 : index} : () -> !emitc.ssize_t + %0 = "emitc.constant"(){value = 1 : index} : () -> !emitc.ssize_t emitc.switch %0 : !emitc.ssize_t case 2 { @@ -115,7 +115,7 @@ func.func @emitc_switch_ssize_t() { emitc.yield } default { - %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32 + %3 = "emitc.constant"(){value = 42.0 : f32} : () -> f32 emitc.call_opaque "func2" (%3) : (f32) -> () emitc.yield } @@ -164,7 +164,7 @@ func.func @emitc_switch_ssize_t() { // CPP-DECLTOP: return; // CPP-DECLTOP: } func.func @emitc_switch_size_t() { - %0 = "emitc.variable"(){value = 1 : index} : () -> !emitc.size_t + %0 = "emitc.constant"(){value = 1 : index} : () -> !emitc.size_t emitc.switch %0 : !emitc.size_t case 2 { @@ -176,7 +176,7 @@ func.func @emitc_switch_size_t() { emitc.yield } default { - %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32 + %3 = "emitc.constant"(){value = 42.0 : f32} : () -> f32 emitc.call_opaque "func2" (%3) : (f32) -> () emitc.yield } @@ -225,7 +225,7 @@ func.func @emitc_switch_size_t() { // CPP-DECLTOP: return; // CPP-DECLTOP: } func.func @emitc_switch_index() { - %0 = "emitc.variable"(){value = 1 : index} : () -> index + %0 = "emitc.constant"(){value = 1 : index} : () -> index emitc.switch %0 : index case 2 { @@ -237,7 +237,7 @@ func.func @emitc_switch_index() { emitc.yield } default { - %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32 + %3 = "emitc.constant"(){value = 42.0 : f32} : () -> f32 emitc.call_opaque "func2" (%3) : (f32) -> () emitc.yield } @@ -286,7 +286,7 @@ func.func @emitc_switch_index() { // CPP-DECLTOP: return; // CPP-DECLTOP: } func.func @emitc_switch_opaque() { - %0 = "emitc.variable"() {value = #emitc.opaque<"1">} + %0 = "emitc.constant"() {value = #emitc.opaque<"1">} : () -> !emitc.opaque<"size_t"> emitc.switch %0 : !emitc.opaque<"size_t"> @@ -299,7 +299,7 @@ func.func @emitc_switch_opaque() { emitc.yield } default { - %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32 + %3 = "emitc.constant"(){value = 42.0 : f32} : () -> f32 emitc.call_opaque "func2" (%3) : (f32) -> () emitc.yield } @@ -348,7 +348,7 @@ func.func @emitc_switch_opaque() { // CPP-DECLTOP: return; // CPP-DECLTOP: } func.func @emitc_switch_i1() { - %0 = "emitc.variable"(){value = 1 : i1} : () -> i1 + %0 = "emitc.constant"(){value = 1 : i1} : () -> i1 emitc.switch %0 : i1 case 2 { @@ -360,7 +360,7 @@ func.func @emitc_switch_i1() { emitc.yield } default { - %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32 + %3 = "emitc.constant"(){value = 42.0 : f32} : () -> f32 emitc.call_opaque "func2" (%3) : (f32) -> () emitc.yield } @@ -409,7 +409,7 @@ func.func @emitc_switch_i1() { // CPP-DECLTOP: return; // CPP-DECLTOP: } func.func @emitc_switch_i8() { - %0 = "emitc.variable"(){value = 1 : i8} : () -> i8 + %0 = "emitc.constant"(){value = 1 : i8} : () -> i8 emitc.switch %0 : i8 case 2 { @@ -421,7 +421,7 @@ func.func @emitc_switch_i8() { emitc.yield } default { - %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32 + %3 = "emitc.constant"(){value = 42.0 : f32} : () -> f32 emitc.call_opaque "func2" (%3) : (f32) -> () emitc.yield } @@ -470,7 +470,7 @@ func.func @emitc_switch_i8() { // CPP-DECLTOP: return; // CPP-DECLTOP: } func.func @emitc_switch_ui8() { - %0 = "emitc.variable"(){value = 1 : ui8} : () -> ui8 + %0 = "emitc.constant"(){value = 1 : ui8} : () -> ui8 emitc.switch %0 : ui8 case 2 { @@ -482,7 +482,7 @@ func.func @emitc_switch_ui8() { emitc.yield } default { - %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32 + %3 = "emitc.constant"(){value = 42.0 : f32} : () -> f32 emitc.call_opaque "func2" (%3) : (f32) -> () emitc.yield } @@ -531,7 +531,7 @@ func.func @emitc_switch_ui8() { // CPP-DECLTOP: return; // CPP-DECLTOP: } func.func @emitc_switch_i16() { - %0 = "emitc.variable"(){value = 1 : i16} : () -> i16 + %0 = "emitc.constant"(){value = 1 : i16} : () -> i16 emitc.switch %0 : i16 case 2 { @@ -543,7 +543,7 @@ func.func @emitc_switch_i16() { emitc.yield } default { - %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32 + %3 = "emitc.constant"(){value = 42.0 : f32} : () -> f32 emitc.call_opaque "func2" (%3) : (f32) -> () emitc.yield } @@ -592,7 +592,7 @@ func.func @emitc_switch_i16() { // CPP-DECLTOP: return; // CPP-DECLTOP: } func.func @emitc_switch_ui16() { - %0 = "emitc.variable"(){value = 1 : ui16} : () -> ui16 + %0 = "emitc.constant"(){value = 1 : ui16} : () -> ui16 emitc.switch %0 : ui16 case 2 { @@ -604,7 +604,7 @@ func.func @emitc_switch_ui16() { emitc.yield } default { - %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32 + %3 = "emitc.constant"(){value = 42.0 : f32} : () -> f32 emitc.call_opaque "func2" (%3) : (f32) -> () emitc.yield } @@ -653,7 +653,7 @@ func.func @emitc_switch_ui16() { // CPP-DECLTOP: return; // CPP-DECLTOP: } func.func @emitc_switch_i32() { - %0 = "emitc.variable"(){value = 1 : i32} : () -> i32 + %0 = "emitc.constant"(){value = 1 : i32} : () -> i32 emitc.switch %0 : i32 case 2 { @@ -665,7 +665,7 @@ func.func @emitc_switch_i32() { emitc.yield } default { - %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32 + %3 = "emitc.constant"(){value = 42.0 : f32} : () -> f32 emitc.call_opaque "func2" (%3) : (f32) -> () emitc.yield } @@ -714,7 +714,7 @@ func.func @emitc_switch_i32() { // CPP-DECLTOP: return; // CPP-DECLTOP: } func.func @emitc_switch_ui32() { - %0 = "emitc.variable"(){value = 1 : ui32} : () -> ui32 + %0 = "emitc.constant"(){value = 1 : ui32} : () -> ui32 emitc.switch %0 : ui32 case 2 { @@ -726,7 +726,7 @@ func.func @emitc_switch_ui32() { emitc.yield } default { - %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32 + %3 = "emitc.constant"(){value = 42.0 : f32} : () -> f32 emitc.call_opaque "func2" (%3) : (f32) -> () emitc.yield } @@ -775,7 +775,7 @@ func.func @emitc_switch_ui32() { // CPP-DECLTOP: return; // CPP-DECLTOP: } func.func @emitc_switch_i64() { - %0 = "emitc.variable"(){value = 1 : i64} : () -> i64 + %0 = "emitc.constant"(){value = 1 : i64} : () -> i64 emitc.switch %0 : i64 case 2 { @@ -787,7 +787,7 @@ func.func @emitc_switch_i64() { emitc.yield } default { - %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32 + %3 = "emitc.constant"(){value = 42.0 : f32} : () -> f32 emitc.call_opaque "func2" (%3) : (f32) -> () emitc.yield } @@ -836,7 +836,7 @@ func.func @emitc_switch_i64() { // CPP-DECLTOP: return; // CPP-DECLTOP: } func.func @emitc_switch_ui64() { - %0 = "emitc.variable"(){value = 1 : ui64} : () -> ui64 + %0 = "emitc.constant"(){value = 1 : ui64} : () -> ui64 emitc.switch %0 : ui64 case 2 { @@ -848,7 +848,7 @@ func.func @emitc_switch_ui64() { emitc.yield } default { - %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32 + %3 = "emitc.constant"(){value = 42.0 : f32} : () -> f32 emitc.call_opaque "func2" (%3) : (f32) -> () emitc.yield } diff --git a/mlir/test/Target/Cpp/variable.mlir b/mlir/test/Target/Cpp/variable.mlir index 126dd384b47a2..a26d724127cf2 100644 --- a/mlir/test/Target/Cpp/variable.mlir +++ b/mlir/test/Target/Cpp/variable.mlir @@ -2,13 +2,13 @@ // RUN: mlir-translate -mlir-to-cpp -declare-variables-at-top %s | FileCheck %s -check-prefix=CPP-DECLTOP func.func @emitc_variable() { - %c0 = "emitc.variable"(){value = #emitc.opaque<"">} : () -> i32 - %c1 = "emitc.variable"(){value = 42 : i32} : () -> i32 - %c2 = "emitc.variable"(){value = -1 : i32} : () -> i32 - %c3 = "emitc.variable"(){value = -1 : si8} : () -> si8 - %c4 = "emitc.variable"(){value = 255 : ui8} : () -> ui8 - %c5 = "emitc.variable"(){value = #emitc.opaque<"">} : () -> !emitc.ptr - %c6 = "emitc.variable"(){value = #emitc.opaque<"NULL">} : () -> !emitc.ptr + %c0 = "emitc.variable"(){value = #emitc.opaque<"">} : () -> !emitc.lvalue + %c1 = "emitc.variable"(){value = 42 : i32} : () -> !emitc.lvalue + %c2 = "emitc.variable"(){value = -1 : i32} : () -> !emitc.lvalue + %c3 = "emitc.variable"(){value = -1 : si8} : () -> !emitc.lvalue + %c4 = "emitc.variable"(){value = 255 : ui8} : () -> !emitc.lvalue + %c5 = "emitc.variable"(){value = #emitc.opaque<"">} : () -> !emitc.lvalue> + %c6 = "emitc.variable"(){value = #emitc.opaque<"NULL">} : () -> !emitc.lvalue> %c7 = "emitc.variable"(){value = #emitc.opaque<"">} : () -> !emitc.array<3x7xi32> %c8 = "emitc.variable"(){value = #emitc.opaque<"">} : () -> !emitc.array<5x!emitc.ptr> return @@ -41,3 +41,5 @@ func.func @emitc_variable() { // CPP-DECLTOP-NEXT: [[V4]] = 255; // CPP-DECLTOP-NEXT: ; // CPP-DECLTOP-NEXT: [[V6]] = NULL; +// CPP-DECLTOP-NEXT: ; +// CPP-DECLTOP-NEXT: ; From 5ec7fd548970eb2bb0b887583e35f1a7f582b866 Mon Sep 17 00:00:00 2001 From: Simon Camphausen Date: Tue, 11 Jun 2024 11:43:49 +0000 Subject: [PATCH 02/14] Add check lines --- mlir/test/Target/Cpp/lvalue.mlir | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/mlir/test/Target/Cpp/lvalue.mlir b/mlir/test/Target/Cpp/lvalue.mlir index ce76dd7a7cfeb..5ef7fb2763246 100644 --- a/mlir/test/Target/Cpp/lvalue.mlir +++ b/mlir/test/Target/Cpp/lvalue.mlir @@ -1,17 +1,28 @@ // RUN: mlir-translate -mlir-to-cpp %s | FileCheck %s -// CHECK: int32_t lvalue_variables( emitc.func @lvalue_variables(%v1: i32, %v2: i32) -> i32 { %val = emitc.mul %v1, %v2 : (i32, i32) -> i32 - %variable = "emitc.variable"() {value = #emitc.opaque<"">} : () -> !emitc.lvalue // alloc effect - emitc.assign %val : i32 to %variable : !emitc.lvalue // write effect + %variable = "emitc.variable"() {value = #emitc.opaque<"">} : () -> !emitc.lvalue + emitc.assign %val : i32 to %variable : !emitc.lvalue %addr = emitc.apply "&"(%variable) : (!emitc.lvalue) -> !emitc.ptr emitc.call @zero (%addr) : (!emitc.ptr) -> () - %updated_val = emitc.lvalue_load %variable : !emitc.lvalue // read effect, (noop in emitter?) + %updated_val = emitc.lvalue_load %variable : !emitc.lvalue %neg_one = "emitc.constant"() {value = -1 : i32} : () -> i32 - emitc.assign %neg_one : i32 to %variable : !emitc.lvalue // invalidates %updated_val + emitc.assign %neg_one : i32 to %variable : !emitc.lvalue emitc.return %updated_val : i32 - // dealloc effect through automatic allocation scope } +// CHECK-LABEL: int32_t lvalue_variables( +// CHECK-SAME: int32_t [[V1:[^ ]*]], int32_t [[V2:[^ ]*]]) +// CHECK-NEXT: int32_t [[VAL:[^ ]*]] = [[V1]] * [[V2]]; +// CHECK-NEXT: int32_t [[VAR:[^ ]*]]; +// CHECK-NEXT: [[VAR]] = [[VAL]]; +// CHECK-NEXT: int32_t* [[VAR_PTR:[^ ]*]] = &[[VAR]]; +// CHECK-NEXT: zero([[VAR_PTR]]); +// CHECK-NEXT: int32_t [[VAR_LOAD:[^ ]*]] = [[VAR]]; +// CHECK-NEXT: int32_t [[NEG_ONE:[^ ]*]] = -1; +// CHECK-NEXT: [[VAR]] = [[NEG_ONE]]; +// CHECK-NEXT: return [[VAR_LOAD]]; -emitc.func @zero(%arg0: !emitc.ptr) attributes {specifiers = ["extern"]} \ No newline at end of file + +emitc.func @zero(%arg0: !emitc.ptr) attributes {specifiers = ["extern"]} +// CHECK-LABEL: extern void zero(int32_t*); From 5fc4fb52e8de4be22ddc6fd80149989aafdeb985 Mon Sep 17 00:00:00 2001 From: Simon Camphausen Date: Tue, 11 Jun 2024 13:39:13 +0000 Subject: [PATCH 03/14] Add memory effects --- mlir/include/mlir/Dialect/EmitC/IR/EmitC.td | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td index 0f876079d978b..3c8cffa895401 100644 --- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td +++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td @@ -844,7 +844,8 @@ def EmitC_LValueLoadOp : EmitC_Op<"lvalue_load", [ let summary = "load an lvalue by assigning it to a local variable"; let description = [{}]; - let arguments = (ins EmitC_LValueType:$operand); + let arguments = (ins + Res]>:$operand); let results = (outs AnyType:$result); let assemblyFormat = "$operand attr-dict `:` type($operand)"; @@ -1066,7 +1067,8 @@ def EmitC_VariableOp : EmitC_Op<"variable", []> { }]; let arguments = (ins EmitC_OpaqueOrTypedAttr:$value); - let results = (outs AnyTypeOf<[EmitC_ArrayType, EmitC_LValueType]>); + let results = (outs Res, "", + [MemAlloc]>:$memref); let hasVerifier = 1; } @@ -1194,7 +1196,9 @@ def EmitC_AssignOp : EmitC_Op<"assign", []> { ``` }]; - let arguments = (ins EmitC_LValueType:$var, EmitCType:$value); + let arguments = (ins + Res]>:$var, + Res]>:$value); let results = (outs); let hasVerifier = 1; From a98d7844532da862cae425fb23fe3b760f4a0818 Mon Sep 17 00:00:00 2001 From: Simon Camphausen Date: Tue, 11 Jun 2024 13:50:55 +0000 Subject: [PATCH 04/14] Disallow lvalues as block arguments --- mlir/lib/Target/Cpp/TranslateToCpp.cpp | 4 ++-- .../Cpp/invalid_declare_variables_at_top.mlir | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp index 7cd9032d82849..9263026127bcf 100644 --- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp +++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp @@ -1019,9 +1019,9 @@ static LogicalResult printFunctionBody(CppEmitter &emitter, if (emitter.hasValueInScope(arg)) return functionOp->emitOpError(" block argument #") << arg.getArgNumber() << " is out of scope"; - if (isa(arg.getType())) + if (isa(arg.getType())) return functionOp->emitOpError("cannot emit block argument #") - << arg.getArgNumber() << " with array type"; + << arg.getArgNumber() << " with type " << arg.getType(); if (failed( emitter.emitType(block.getParentOp()->getLoc(), arg.getType()))) { return failure(); diff --git a/mlir/test/Target/Cpp/invalid_declare_variables_at_top.mlir b/mlir/test/Target/Cpp/invalid_declare_variables_at_top.mlir index 844fe03bad4ab..8b87113e6d960 100644 --- a/mlir/test/Target/Cpp/invalid_declare_variables_at_top.mlir +++ b/mlir/test/Target/Cpp/invalid_declare_variables_at_top.mlir @@ -1,9 +1,20 @@ // RUN: mlir-translate -split-input-file -declare-variables-at-top -mlir-to-cpp -verify-diagnostics %s -// expected-error@+1 {{'func.func' op cannot emit block argument #0 with array type}} +// expected-error@+1 {{'func.func' op cannot emit block argument #0 with type '!emitc.array<4xi8>'}} func.func @array_as_block_argument(!emitc.array<4xi8>) { ^bb0(%arg0 : !emitc.array<4xi8>): cf.br ^bb1(%arg0 : !emitc.array<4xi8>) ^bb1(%a : !emitc.array<4xi8>): - return + return +} + +// ----- + +// expected-error@+1 {{'emitc.func' op cannot emit block argument #0 with type '!emitc.lvalue'}} +emitc.func @lvalue_as_block_argument() { +^bb0: + %0 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue + cf.br ^bb1(%0 : !emitc.lvalue) +^bb1(%a : !emitc.lvalue): + emitc.return } From 39008854d810a875c57a770551ba0b5bb6ab038a Mon Sep 17 00:00:00 2001 From: Simon Camphausen Date: Tue, 11 Jun 2024 14:04:48 +0000 Subject: [PATCH 05/14] Fix line endings --- mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp b/mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp index 36f7f5b2f1eb9..dcb146071e7cf 100644 --- a/mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp +++ b/mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp @@ -259,4 +259,4 @@ void SCFToEmitCPass::runOnOperation() { if (failed( applyPartialConversion(getOperation(), target, std::move(patterns)))) signalPassFailure(); -} \ No newline at end of file +} From 0a5fbbb8ad38e1213efc6922477678e49e8d1090 Mon Sep 17 00:00:00 2001 From: Simon Camphausen Date: Tue, 11 Jun 2024 16:32:29 +0200 Subject: [PATCH 06/14] Apply suggestions from code review Co-authored-by: Matthias Gehre --- mlir/include/mlir/Dialect/EmitC/IR/EmitC.td | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td index 3c8cffa895401..ad314da8a10dd 100644 --- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td +++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td @@ -841,7 +841,7 @@ def EmitC_LValueLoadOp : EmitC_Op<"lvalue_load", [ "operand", "result", "::llvm::cast($_self).getValue()"> ]> { - let summary = "load an lvalue by assigning it to a local variable"; + let summary = "Load an lvalue into an SSA value."; let description = [{}]; let arguments = (ins From 9a75b898598af2d00e992ab4aa773d35f0d40d32 Mon Sep 17 00:00:00 2001 From: Simon Camphausen Date: Tue, 11 Jun 2024 14:46:17 +0000 Subject: [PATCH 07/14] Review comments --- mlir/include/mlir/Dialect/EmitC/IR/EmitC.td | 10 +++++++--- mlir/include/mlir/Dialect/EmitC/IR/EmitCTypes.td | 8 ++++---- mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp | 4 ++-- mlir/lib/Dialect/EmitC/IR/EmitC.cpp | 12 ++++++------ mlir/lib/Target/Cpp/TranslateToCpp.cpp | 2 +- 5 files changed, 20 insertions(+), 16 deletions(-) diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td index ad314da8a10dd..ff139f9094752 100644 --- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td +++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td @@ -839,10 +839,14 @@ def EmitC_LogicalOrOp : EmitC_BinaryOp<"logical_or", [CExpression]> { def EmitC_LValueLoadOp : EmitC_Op<"lvalue_load", [ TypesMatchWith<"result type matches value type of 'operand'", "operand", "result", - "::llvm::cast($_self).getValue()"> + "::llvm::cast($_self).getValueType()"> ]> { let summary = "Load an lvalue into an SSA value."; - let description = [{}]; + let description = [{ + This operation loads the content of a modifiable lvalue into an SSA value. + Modifications of the lvalue executed after the load are not observable on + the produced value. + }]; let arguments = (ins Res]>:$operand); @@ -1198,7 +1202,7 @@ def EmitC_AssignOp : EmitC_Op<"assign", []> { let arguments = (ins Res]>:$var, - Res]>:$value); + EmitCType:$value); let results = (outs); let hasVerifier = 1; diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitCTypes.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitCTypes.td index b8169f43681b5..e15185c888d2d 100644 --- a/mlir/include/mlir/Dialect/EmitC/IR/EmitCTypes.td +++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitCTypes.td @@ -91,13 +91,13 @@ def EmitC_LValueType : EmitC_Type<"LValue", "lvalue"> { Values of this type can be assigned to and their address can be taken. }]; - let parameters = (ins "Type":$value); + let parameters = (ins "Type":$valueType); let builders = [ - TypeBuilderWithInferredContext<(ins "Type":$value), [{ - return $_get(value.getContext(), value); + TypeBuilderWithInferredContext<(ins "Type":$valueType), [{ + return $_get(valueType.getContext(), valueType); }]> ]; - let assemblyFormat = "`<` qualified($value) `>`"; + let assemblyFormat = "`<` qualified($valueType) `>`"; let genVerifyDecl = 1; } diff --git a/mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp b/mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp index dcb146071e7cf..26d6a0af07c5c 100644 --- a/mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp +++ b/mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp @@ -84,7 +84,7 @@ static void assignValues(ValueRange values, SmallVector &variables, SmallVector loadValues(const SmallVector &variables, PatternRewriter &rewriter, Location loc) { return llvm::map_to_vector<>(variables, [&](Value var) { - Type type = cast(var.getType()).getValue(); + Type type = cast(var.getType()).getValueType(); return rewriter.create(loc, type, var).getResult(); }); } @@ -151,7 +151,7 @@ LogicalResult ForLowering::matchAndRewrite(ForOp forOp, lowerYield(resultVariables, rewriter, cast(loweredBody->getTerminator())); - // Copy iterArgs into results after the for loop. + // Load variables into SSA values after the for loop. SmallVector resultValues = loadValues(resultVariables, rewriter, loc); rewriter.replaceOp(forOp, resultValues); diff --git a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp index 6b27c8c696a58..a97b54db726dd 100644 --- a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp +++ b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp @@ -149,7 +149,7 @@ static LogicalResult verifyInitializationAttribute(Operation *op, Type resultType = op->getResult(0).getType(); if (auto lType = dyn_cast(resultType)) - resultType = lType.getValue(); + resultType = lType.getValueType(); Type attrType = cast(value).getType(); if (isPointerWideType(resultType) && attrType.isIndex()) @@ -229,7 +229,7 @@ LogicalResult emitc::AssignOp::verify() { return emitOpError() << "cannot assign to block argument"; Type valueType = getValue().getType(); - Type variableType = variable.getType().getValue(); + Type variableType = variable.getType().getValueType(); if (variableType != valueType) return emitOpError() << "requires value's type (" << valueType << ") to match variable's type (" << variableType @@ -862,7 +862,7 @@ LogicalResult emitc::SubscriptOp::verify() { } // Check element type. Type elementType = arrayType.getElementType(); - Type resultType = getType().getValue(); + Type resultType = getType().getValueType(); if (elementType != resultType) { return emitOpError() << "on array operand requires element type (" << elementType << ") and result type (" << resultType @@ -889,7 +889,7 @@ LogicalResult emitc::SubscriptOp::verify() { } // Check pointee type. Type pointeeType = pointerType.getPointee(); - Type resultType = getType().getValue(); + Type resultType = getType().getValueType(); if (pointeeType != resultType) { return emitOpError() << "on pointer operand requires pointee type (" << pointeeType << ") and result type (" << resultType @@ -1144,9 +1144,9 @@ GetGlobalOp::verifySymbolUses(SymbolTableCollection &symbolTable) { // global has non-array type auto lvalueType = dyn_cast(resultType); - if (!lvalueType || lvalueType.getValue() != globalType) + if (!lvalueType || lvalueType.getValueType() != globalType) return emitOpError("on non-array type expects result inner type ") - << lvalueType.getValue() << " to match type " << globalType + << lvalueType.getValueType() << " to match type " << globalType << " of the global @" << getName(); return success(); } diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp index 9263026127bcf..146f423b46995 100644 --- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp +++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp @@ -1684,7 +1684,7 @@ LogicalResult CppEmitter::emitType(Location loc, Type type) { return success(); } if (auto lType = dyn_cast(type)) - return emitType(loc, lType.getValue()); + return emitType(loc, lType.getValueType()); if (auto pType = dyn_cast(type)) { if (isa(pType.getPointee())) return emitError(loc, "cannot emit pointer to array type ") << type; From 6931515b1b8bf5cef0ee9f668de33b1bebfc1899 Mon Sep 17 00:00:00 2001 From: Simon Camphausen Date: Wed, 12 Jun 2024 08:12:56 +0000 Subject: [PATCH 08/14] Rename lvalue_load to load --- mlir/include/mlir/Dialect/EmitC/IR/EmitC.td | 2 +- .../include/mlir/Dialect/EmitC/IR/EmitCTypes.td | 2 +- .../Conversion/MemRefToEmitC/MemRefToEmitC.cpp | 2 +- mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp | 2 +- mlir/lib/Target/Cpp/TranslateToCpp.cpp | 17 ++++++++--------- .../MemRefToEmitC/memref-to-emitc.mlir | 2 +- mlir/test/Conversion/SCFToEmitC/for.mlir | 16 ++++++++-------- mlir/test/Conversion/SCFToEmitC/if.mlir | 4 ++-- mlir/test/Conversion/SCFToEmitC/switch.mlir | 4 ++-- mlir/test/Dialect/EmitC/invalid_ops.mlir | 2 +- mlir/test/Dialect/EmitC/ops.mlir | 2 +- mlir/test/Target/Cpp/expressions.mlir | 8 ++++---- mlir/test/Target/Cpp/for.mlir | 16 ++++++++-------- mlir/test/Target/Cpp/global.mlir | 4 ++-- mlir/test/Target/Cpp/lvalue.mlir | 2 +- mlir/test/Target/Cpp/member.mlir | 4 ++-- mlir/test/Target/Cpp/subscript.mlir | 14 +++++++------- 17 files changed, 51 insertions(+), 52 deletions(-) diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td index ff139f9094752..f4043763445a0 100644 --- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td +++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td @@ -836,7 +836,7 @@ def EmitC_LogicalOrOp : EmitC_BinaryOp<"logical_or", [CExpression]> { let assemblyFormat = "operands attr-dict `:` type(operands)"; } -def EmitC_LValueLoadOp : EmitC_Op<"lvalue_load", [ +def EmitC_LoadOp : EmitC_Op<"load", [ TypesMatchWith<"result type matches value type of 'operand'", "operand", "result", "::llvm::cast($_self).getValueType()"> diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitCTypes.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitCTypes.td index e15185c888d2d..134ef04f26dd4 100644 --- a/mlir/include/mlir/Dialect/EmitC/IR/EmitCTypes.td +++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitCTypes.td @@ -180,7 +180,7 @@ class EmitC_LValueOf allowedTypes> : ContainerType< AnyTypeOf, CPred<"::llvm::isa<::mlir::emitc::LValueType>($_self)">, - "::llvm::cast<::mlir::emitc::LValueType>($_self).getValue()", + "::llvm::cast<::mlir::emitc::LValueType>($_self).getValueType()", "emitc.lvalue", "::mlir::emitc::LValueType" >; diff --git a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp index 2e8fbbad14d40..1392bf924002e 100644 --- a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp +++ b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp @@ -137,7 +137,7 @@ struct ConvertLoad final : public OpConversionPattern { auto subscript = rewriter.create( op.getLoc(), arrayValue, operands.getIndices()); - rewriter.replaceOpWithNewOp(op, resultTy, subscript); + rewriter.replaceOpWithNewOp(op, resultTy, subscript); return success(); } }; diff --git a/mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp b/mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp index 26d6a0af07c5c..67a43c43d608b 100644 --- a/mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp +++ b/mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp @@ -85,7 +85,7 @@ SmallVector loadValues(const SmallVector &variables, PatternRewriter &rewriter, Location loc) { return llvm::map_to_vector<>(variables, [&](Value var) { Type type = cast(var.getType()).getValueType(); - return rewriter.create(loc, type, var).getResult(); + return rewriter.create(loc, type, var).getResult(); }); } diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp index 146f423b46995..a8a0efab84aed 100644 --- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp +++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp @@ -384,12 +384,11 @@ static LogicalResult printOperation(CppEmitter &emitter, return emitter.emitOperand(assignOp.getValue()); } -static LogicalResult printOperation(CppEmitter &emitter, - emitc::LValueLoadOp lValueLoadOp) { - if (failed(emitter.emitAssignPrefix(*lValueLoadOp))) +static LogicalResult printOperation(CppEmitter &emitter, emitc::LoadOp loadOp) { + if (failed(emitter.emitAssignPrefix(*loadOp))) return failure(); - return emitter.emitOperand(lValueLoadOp.getOperand()); + return emitter.emitOperand(loadOp.getOperand()); } static LogicalResult printBinaryOperation(CppEmitter &emitter, @@ -1551,11 +1550,11 @@ LogicalResult CppEmitter::emitOperation(Operation &op, bool trailingSemicolon) { emitc::CallOpaqueOp, emitc::CastOp, emitc::CmpOp, emitc::ConditionalOp, emitc::ConstantOp, emitc::DeclareFuncOp, emitc::DivOp, emitc::ExpressionOp, emitc::ForOp, emitc::FuncOp, - emitc::GlobalOp, emitc::IfOp, emitc::IncludeOp, - emitc::LValueLoadOp, emitc::LogicalAndOp, emitc::LogicalNotOp, - emitc::LogicalOrOp, emitc::MulOp, emitc::RemOp, emitc::ReturnOp, - emitc::SubOp, emitc::SwitchOp, emitc::UnaryMinusOp, - emitc::UnaryPlusOp, emitc::VariableOp, emitc::VerbatimOp>( + emitc::GlobalOp, emitc::IfOp, emitc::IncludeOp, emitc::LoadOp, + emitc::LogicalAndOp, emitc::LogicalNotOp, emitc::LogicalOrOp, + emitc::MulOp, emitc::RemOp, emitc::ReturnOp, emitc::SubOp, + emitc::SwitchOp, emitc::UnaryMinusOp, emitc::UnaryPlusOp, + emitc::VariableOp, emitc::VerbatimOp>( [&](auto op) { return printOperation(*this, op); }) // Func ops. .Case( diff --git a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir index 15ffd815250d2..f4722da08cc40 100644 --- a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir +++ b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir @@ -21,7 +21,7 @@ func.func @memref_load(%i: index, %j: index) -> f32 { %0 = memref.alloca() : memref<4x8xf32> // CHECK-NEXT: %[[SUBSCRIPT:.*]] = emitc.subscript %[[ALLOCA]][%[[i]], %[[j]]] : (!emitc.array<4x8xf32>, index, index) -> !emitc.lvalue - // CHECK-NEXT: %[[LOAD:.*]] = emitc.lvalue_load %[[SUBSCRIPT]] : + // CHECK-NEXT: %[[LOAD:.*]] = emitc.load %[[SUBSCRIPT]] : %1 = memref.load %0[%i, %j] : memref<4x8xf32> // CHECK-NEXT: return %[[LOAD]] : f32 return %1 : f32 diff --git a/mlir/test/Conversion/SCFToEmitC/for.mlir b/mlir/test/Conversion/SCFToEmitC/for.mlir index 32a9dfce7f4e6..83592187a9b68 100644 --- a/mlir/test/Conversion/SCFToEmitC/for.mlir +++ b/mlir/test/Conversion/SCFToEmitC/for.mlir @@ -52,14 +52,14 @@ func.func @for_yield(%arg0 : index, %arg1 : index, %arg2 : index) -> (f32, f32) // CHECK-NEXT: emitc.assign %[[VAL_3]] : f32 to %[[VAL_5]] : // CHECK-NEXT: emitc.assign %[[VAL_4]] : f32 to %[[VAL_6]] : // CHECK-NEXT: emitc.for %[[VAL_7:.*]] = %[[VAL_0]] to %[[VAL_1]] step %[[VAL_2]] { -// CHECK-NEXT: %[[VAL_8:.*]] = emitc.lvalue_load %[[VAL_5]] : -// CHECK-NEXT: %[[VAL_9:.*]] = emitc.lvalue_load %[[VAL_6]] : +// CHECK-NEXT: %[[VAL_8:.*]] = emitc.load %[[VAL_5]] : +// CHECK-NEXT: %[[VAL_9:.*]] = emitc.load %[[VAL_6]] : // CHECK-NEXT: %[[VAL_10:.*]] = arith.addf %[[VAL_8]], %[[VAL_9]] : f32 // CHECK-NEXT: emitc.assign %[[VAL_10]] : f32 to %[[VAL_5]] : // CHECK-NEXT: emitc.assign %[[VAL_10]] : f32 to %[[VAL_6]] : // CHECK-NEXT: } -// CHECK-NEXT: %[[VAL_11:.*]] = emitc.lvalue_load %[[VAL_5]] : -// CHECK-NEXT: %[[VAL_12:.*]] = emitc.lvalue_load %[[VAL_6]] : +// CHECK-NEXT: %[[VAL_11:.*]] = emitc.load %[[VAL_5]] : +// CHECK-NEXT: %[[VAL_12:.*]] = emitc.load %[[VAL_6]] : // CHECK-NEXT: return %[[VAL_11]], %[[VAL_12]] : f32, f32 // CHECK-NEXT: } @@ -80,17 +80,17 @@ func.func @nested_for_yield(%arg0 : index, %arg1 : index, %arg2 : index) -> f32 // CHECK-NEXT: %[[VAL_4:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue // CHECK-NEXT: emitc.assign %[[VAL_3]] : f32 to %[[VAL_4]] : // CHECK-NEXT: emitc.for %[[VAL_5:.*]] = %[[VAL_0]] to %[[VAL_1]] step %[[VAL_2]] { -// CHECK-NEXT: %[[VAL_6:.*]] = emitc.lvalue_load %[[VAL_4]] : +// CHECK-NEXT: %[[VAL_6:.*]] = emitc.load %[[VAL_4]] : // CHECK-NEXT: %[[VAL_7:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue // CHECK-NEXT: emitc.assign %[[VAL_6]] : f32 to %[[VAL_7]] : // CHECK-NEXT: emitc.for %[[VAL_8:.*]] = %[[VAL_0]] to %[[VAL_1]] step %[[VAL_2]] { -// CHECK-NEXT: %[[VAL_9:.*]] = emitc.lvalue_load %[[VAL_7]] : +// CHECK-NEXT: %[[VAL_9:.*]] = emitc.load %[[VAL_7]] : // CHECK-NEXT: %[[VAL_10:.*]] = arith.addf %[[VAL_9]], %[[VAL_9]] : f32 // CHECK-NEXT: emitc.assign %[[VAL_10]] : f32 to %[[VAL_7]] : // CHECK-NEXT: } -// CHECK-NEXT: %[[VAL_11:.*]] = emitc.lvalue_load %[[VAL_7]] : +// CHECK-NEXT: %[[VAL_11:.*]] = emitc.load %[[VAL_7]] : // CHECK-NEXT: emitc.assign %[[VAL_11]] : f32 to %[[VAL_4]] : // CHECK-NEXT: } -// CHECK-NEXT: %[[VAL_12:.*]] = emitc.lvalue_load %[[VAL_4]] : +// CHECK-NEXT: %[[VAL_12:.*]] = emitc.load %[[VAL_4]] : // CHECK-NEXT: return %[[VAL_12]] : f32 // CHECK-NEXT: } diff --git a/mlir/test/Conversion/SCFToEmitC/if.mlir b/mlir/test/Conversion/SCFToEmitC/if.mlir index 463cf1d3d9645..7d923785862d8 100644 --- a/mlir/test/Conversion/SCFToEmitC/if.mlir +++ b/mlir/test/Conversion/SCFToEmitC/if.mlir @@ -66,7 +66,7 @@ func.func @test_if_yield(%arg0: i1, %arg1: f32) -> (i32, f64) { // CHECK-NEXT: emitc.assign %[[VAL_7]] : i32 to %[[VAL_3]] : // CHECK-NEXT: emitc.assign %[[VAL_8]] : f64 to %[[VAL_4]] : // CHECK-NEXT: } -// CHECK-NEXT: %[[VAL_9:.*]] = emitc.lvalue_load %[[VAL_3]] : -// CHECK-NEXT: %[[VAL_10:.*]] = emitc.lvalue_load %[[VAL_4]] : +// CHECK-NEXT: %[[VAL_9:.*]] = emitc.load %[[VAL_3]] : +// CHECK-NEXT: %[[VAL_10:.*]] = emitc.load %[[VAL_4]] : // CHECK-NEXT: return %[[VAL_9]], %[[VAL_10]] : i32, f64 // CHECK-NEXT: } diff --git a/mlir/test/Conversion/SCFToEmitC/switch.mlir b/mlir/test/Conversion/SCFToEmitC/switch.mlir index 54d84738bcb9a..86d96ed21f1b5 100644 --- a/mlir/test/Conversion/SCFToEmitC/switch.mlir +++ b/mlir/test/Conversion/SCFToEmitC/switch.mlir @@ -94,8 +94,8 @@ func.func @switch_one_result(%arg0 : index) { // CHECK: emitc.assign %[[VAL_7]] : i32 to %[[VAL_1]] : // CHECK: emitc.assign %[[VAL_8]] : f32 to %[[VAL_2]] : // CHECK: } -// CHECK: %[[RES_1:.*]] = emitc.lvalue_load %[[VAL_1]] : -// CHECK: %[[RES_2:.*]] = emitc.lvalue_load %[[VAL_2]] : +// CHECK: %[[RES_1:.*]] = emitc.load %[[VAL_1]] : +// CHECK: %[[RES_2:.*]] = emitc.load %[[VAL_2]] : // CHECK: return %[[RES_1]], %[[RES_2]] : i32, f32 // CHECK: } func.func @switch_two_results(%arg0 : index) -> (i32, f32) { diff --git a/mlir/test/Dialect/EmitC/invalid_ops.mlir b/mlir/test/Dialect/EmitC/invalid_ops.mlir index d3f9c5c36ff8c..a80e49cc33fac 100644 --- a/mlir/test/Dialect/EmitC/invalid_ops.mlir +++ b/mlir/test/Dialect/EmitC/invalid_ops.mlir @@ -265,7 +265,7 @@ func.func @test_expression_illegal_op(%arg0 : i1) -> i32 { // expected-error @+1 {{'emitc.expression' op contains an unsupported operation}} %r = emitc.expression : i32 { %x = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue - %y = emitc.lvalue_load %x : + %y = emitc.load %x : emitc.yield %y : i32 } return %r : i32 diff --git a/mlir/test/Dialect/EmitC/ops.mlir b/mlir/test/Dialect/EmitC/ops.mlir index e72fc74a74002..bb38754ff469b 100644 --- a/mlir/test/Dialect/EmitC/ops.mlir +++ b/mlir/test/Dialect/EmitC/ops.mlir @@ -246,7 +246,7 @@ emitc.global const @myconstant : !emitc.array<2xi16> = dense<2> func.func @use_global(%i: index) -> f32 { %0 = emitc.get_global @myglobal : !emitc.array<2xf32> %1 = emitc.subscript %0[%i] : (!emitc.array<2xf32>, index) -> !emitc.lvalue - %2 = emitc.lvalue_load %1 : + %2 = emitc.load %1 : return %2 : f32 } diff --git a/mlir/test/Target/Cpp/expressions.mlir b/mlir/test/Target/Cpp/expressions.mlir index d9455e8e98177..6b67065f5d1a1 100644 --- a/mlir/test/Target/Cpp/expressions.mlir +++ b/mlir/test/Target/Cpp/expressions.mlir @@ -45,7 +45,7 @@ func.func @single_use(%arg0: i32, %arg1: i32, %arg2: i32, %arg3: i32) -> i32 { emitc.assign %arg0 : i32 to %v : !emitc.lvalue emitc.yield } - %v_load = emitc.lvalue_load %v : !emitc.lvalue + %v_load = emitc.load %v : !emitc.lvalue return %v_load : i32 } @@ -234,7 +234,7 @@ func.func @multiple_uses(%arg0: i32, %arg1: i32, %arg2: i32, %arg3: i32) -> i32 } %q = "emitc.variable"(){value = #emitc.opaque<"">} : () -> !emitc.lvalue emitc.assign %e : i1 to %q : !emitc.lvalue - %v_load = emitc.lvalue_load %v : !emitc.lvalue + %v_load = emitc.load %v : !emitc.lvalue return %v_load : i32 } @@ -291,7 +291,7 @@ func.func @different_expressions(%arg0: i32, %arg1: i32, %arg2: i32, %arg3: i32) emitc.assign %arg0 : i32 to %v : !emitc.lvalue emitc.yield } - %v_load = emitc.lvalue_load %v : !emitc.lvalue + %v_load = emitc.load %v : !emitc.lvalue return %v_load : i32 } @@ -339,6 +339,6 @@ func.func @expression_with_subscript_user(%arg0: !emitc.ptr } %res = emitc.subscript %0[%c0] : (!emitc.ptr, i64) -> !emitc.lvalue - %res_load = emitc.lvalue_load %res : !emitc.lvalue + %res_load = emitc.load %res : !emitc.lvalue return %res_load : i32 } diff --git a/mlir/test/Target/Cpp/for.mlir b/mlir/test/Target/Cpp/for.mlir index 14d3f05d6a08e..6a446eaf4add3 100644 --- a/mlir/test/Target/Cpp/for.mlir +++ b/mlir/test/Target/Cpp/for.mlir @@ -47,17 +47,17 @@ func.func @test_for_yield() { emitc.assign %s0 : i32 to %2 : !emitc.lvalue emitc.assign %p0 : f32 to %3 : !emitc.lvalue emitc.for %iter = %start to %stop step %step { - %4 = emitc.lvalue_load %2 : !emitc.lvalue + %4 = emitc.load %2 : !emitc.lvalue %sn = emitc.call_opaque "add"(%4, %iter) : (i32, index) -> i32 - %5 = emitc.lvalue_load %3 : !emitc.lvalue + %5 = emitc.load %3 : !emitc.lvalue %pn = emitc.call_opaque "mul"(%5, %iter) : (f32, index) -> f32 emitc.assign %sn : i32 to %2 : !emitc.lvalue emitc.assign %pn : f32 to %3 : !emitc.lvalue emitc.yield } - %6 = emitc.lvalue_load %2 : !emitc.lvalue + %6 = emitc.load %2 : !emitc.lvalue emitc.assign %6 : i32 to %0 : !emitc.lvalue - %7 = emitc.lvalue_load %3 : !emitc.lvalue + %7 = emitc.load %3 : !emitc.lvalue emitc.assign %7 : f32 to %1 : !emitc.lvalue return @@ -144,17 +144,17 @@ func.func @test_for_yield_2() { emitc.assign %s0 : i32 to %2 : !emitc.lvalue emitc.assign %p0 : f32 to %3 : !emitc.lvalue emitc.for %iter = %start to %stop step %step { - %4 = emitc.lvalue_load %2 : !emitc.lvalue + %4 = emitc.load %2 : !emitc.lvalue %sn = emitc.call_opaque "add"(%4, %iter) : (i32, index) -> i32 - %5 = emitc.lvalue_load %3 : !emitc.lvalue + %5 = emitc.load %3 : !emitc.lvalue %pn = emitc.call_opaque "mul"(%5, %iter) : (f32, index) -> f32 emitc.assign %sn : i32 to %2 : !emitc.lvalue emitc.assign %pn : f32 to %3 : !emitc.lvalue emitc.yield } - %6 = emitc.lvalue_load %2 : !emitc.lvalue + %6 = emitc.load %2 : !emitc.lvalue emitc.assign %6 : i32 to %0 : !emitc.lvalue - %7 = emitc.lvalue_load %3 : !emitc.lvalue + %7 = emitc.load %3 : !emitc.lvalue emitc.assign %7 : f32 to %1 : !emitc.lvalue return diff --git a/mlir/test/Target/Cpp/global.mlir b/mlir/test/Target/Cpp/global.mlir index b2d61681dbd60..c54338bc2faff 100644 --- a/mlir/test/Target/Cpp/global.mlir +++ b/mlir/test/Target/Cpp/global.mlir @@ -39,7 +39,7 @@ emitc.global @opaque_init : !emitc.opaque<"char"> = #emitc.opaque<"CHAR_MIN"> func.func @use_global_scalar_read() -> i32 { %0 = emitc.get_global @myglobal_int : !emitc.lvalue - %1 = emitc.lvalue_load %0 : !emitc.lvalue + %1 = emitc.load %0 : !emitc.lvalue return %1 : i32 } // CPP-DEFAULT-LABEL: int32_t use_global_scalar_read() @@ -69,7 +69,7 @@ func.func @use_global_scalar_write(%arg0 : i32) { func.func @use_global_array_read(%i: index) -> f32 { %0 = emitc.get_global @myglobal : !emitc.array<2xf32> %1 = emitc.subscript %0[%i] : (!emitc.array<2xf32>, index) -> !emitc.lvalue - %2 = emitc.lvalue_load %1 : !emitc.lvalue + %2 = emitc.load %1 : return %2 : f32 } // CPP-DEFAULT-LABEL: float use_global_array_read diff --git a/mlir/test/Target/Cpp/lvalue.mlir b/mlir/test/Target/Cpp/lvalue.mlir index 5ef7fb2763246..2aa438eb6371c 100644 --- a/mlir/test/Target/Cpp/lvalue.mlir +++ b/mlir/test/Target/Cpp/lvalue.mlir @@ -6,7 +6,7 @@ emitc.func @lvalue_variables(%v1: i32, %v2: i32) -> i32 { emitc.assign %val : i32 to %variable : !emitc.lvalue %addr = emitc.apply "&"(%variable) : (!emitc.lvalue) -> !emitc.ptr emitc.call @zero (%addr) : (!emitc.ptr) -> () - %updated_val = emitc.lvalue_load %variable : !emitc.lvalue + %updated_val = emitc.load %variable : !emitc.lvalue %neg_one = "emitc.constant"() {value = -1 : i32} : () -> i32 emitc.assign %neg_one : i32 to %variable : !emitc.lvalue emitc.return %updated_val : i32 diff --git a/mlir/test/Target/Cpp/member.mlir b/mlir/test/Target/Cpp/member.mlir index d1c453f07cda5..df3450c05dbf9 100644 --- a/mlir/test/Target/Cpp/member.mlir +++ b/mlir/test/Target/Cpp/member.mlir @@ -5,7 +5,7 @@ func.func @member(%arg0: !emitc.lvalue>, %arg1: i32) { emitc.assign %arg1 : i32 to %0 : !emitc.lvalue %1 = "emitc.member" (%arg0) {member = "b"} : (!emitc.lvalue>) -> !emitc.lvalue - %2 = emitc.lvalue_load %1 : !emitc.lvalue + %2 = emitc.load %1 : !emitc.lvalue %3 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue emitc.assign %2 : i32 to %3 : !emitc.lvalue @@ -24,7 +24,7 @@ func.func @member_of_pointer(%arg0: !emitc.lvalue %1 = "emitc.member_of_ptr" (%arg0) {member = "b"} : (!emitc.lvalue>>) -> !emitc.lvalue - %2 = emitc.lvalue_load %1 : !emitc.lvalue + %2 = emitc.load %1 : !emitc.lvalue %3 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue emitc.assign %2 : i32 to %3 : !emitc.lvalue diff --git a/mlir/test/Target/Cpp/subscript.mlir b/mlir/test/Target/Cpp/subscript.mlir index b5c94c146712e..7f015c210796e 100644 --- a/mlir/test/Target/Cpp/subscript.mlir +++ b/mlir/test/Target/Cpp/subscript.mlir @@ -4,7 +4,7 @@ func.func @load_store_array(%arg0: !emitc.array<4x8xf32>, %arg1: !emitc.array<3x5xf32>, %arg2: index, %arg3: index) { %0 = emitc.subscript %arg0[%arg2, %arg3] : (!emitc.array<4x8xf32>, index, index) -> !emitc.lvalue %1 = emitc.subscript %arg1[%arg2, %arg3] : (!emitc.array<3x5xf32>, index, index) -> !emitc.lvalue - %2 = emitc.lvalue_load %0 : + %2 = emitc.load %0 : emitc.assign %2 : f32 to %1 : !emitc.lvalue return } @@ -22,7 +22,7 @@ func.func @load_store_array(%arg0: !emitc.array<4x8xf32>, %arg1: !emitc.array<3x func.func @load_store_pointer(%arg0: !emitc.ptr, %arg1: !emitc.ptr, %arg2: index, %arg3: index) { %0 = emitc.subscript %arg0[%arg2] : (!emitc.ptr, index) -> !emitc.lvalue %1 = emitc.subscript %arg1[%arg3] : (!emitc.ptr, index) -> !emitc.lvalue - %2 = emitc.lvalue_load %0 : + %2 = emitc.load %0 : emitc.assign %2 : f32 to %1 : return } @@ -40,7 +40,7 @@ func.func @load_store_pointer(%arg0: !emitc.ptr, %arg1: !emitc.ptr, %a func.func @load_store_opaque(%arg0: !emitc.opaque<"std::map">, %arg1: !emitc.opaque<"std::map">, %arg2: !emitc.opaque<"char">, %arg3: !emitc.opaque<"char">) { %0 = emitc.subscript %arg0[%arg2] : (!emitc.opaque<"std::map">, !emitc.opaque<"char">) -> !emitc.lvalue> %1 = emitc.subscript %arg1[%arg3] : (!emitc.opaque<"std::map">, !emitc.opaque<"char">) -> !emitc.lvalue> - %2 = emitc.lvalue_load %0 : > + %2 = emitc.load %0 : > emitc.assign %2 : !emitc.opaque<"int"> to %1 : > return } @@ -64,12 +64,12 @@ emitc.func @call_arg(%arg0: !emitc.array<4x8xf32>, %i: i32, %j: i16, %0 = emitc.subscript %arg0[%i, %j] : (!emitc.array<4x8xf32>, i32, i16) -> !emitc.lvalue %1 = emitc.subscript %arg0[%j, %k] : (!emitc.array<4x8xf32>, i16, i8) -> !emitc.lvalue - %2 = emitc.lvalue_load %0 : + %2 = emitc.load %0 : emitc.call @func1 (%2) : (f32) -> () - %3 = emitc.lvalue_load %1 : + %3 = emitc.load %1 : emitc.call_opaque "func2" (%3) : (f32) -> () - %4 = emitc.lvalue_load %0 : - %5 = emitc.lvalue_load %1 : + %4 = emitc.load %0 : + %5 = emitc.load %1 : emitc.call_opaque "func3" (%4, %5) { args = [1 : index, 0 : index] } : (f32, f32) -> () emitc.return } From 0aab7aa710f5950148e82cd5f826dfb4d49c6a2f Mon Sep 17 00:00:00 2001 From: Simon Camphausen Date: Thu, 13 Jun 2024 08:03:40 +0000 Subject: [PATCH 09/14] Restore xpression_with_dereference test --- mlir/test/Dialect/EmitC/transforms.mlir | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/mlir/test/Dialect/EmitC/transforms.mlir b/mlir/test/Dialect/EmitC/transforms.mlir index 996fd327f7af7..bd0dd820609bf 100644 --- a/mlir/test/Dialect/EmitC/transforms.mlir +++ b/mlir/test/Dialect/EmitC/transforms.mlir @@ -64,6 +64,26 @@ func.func @expression_with_call(%arg0: i32, %arg1: i32, %arg2: i32, %arg3: i32) return %c : i1 } +// CHECK-LABEL: func.func @expression_with_dereference( +// CHECK-SAME: %[[VAL_0:.*]]: i32, %[[VAL_1:.*]]: i32, %[[VAL_2:.*]]: !emitc.ptr) -> i1 { +// CHECK: %[[VAL_3:.*]] = emitc.expression : i32 { +// CHECK: %[[VAL_4:.*]] = emitc.apply "*"(%[[VAL_2]]) : (!emitc.ptr) -> i32 +// CHECK: emitc.yield %[[VAL_4]] : i32 +// CHECK: } +// CHECK: %[[VAL_5:.*]] = emitc.expression : i1 { +// CHECK: %[[VAL_6:.*]] = emitc.mul %[[VAL_0]], %[[VAL_1]] : (i32, i32) -> i32 +// CHECK: %[[VAL_7:.*]] = emitc.cmp lt, %[[VAL_6]], %[[VAL_3]] : (i32, i32) -> i1 +// CHECK: return %[[VAL_5]] : i1 +// CHECK: } + +func.func @expression_with_dereference(%arg0: i32, %arg1: i32, %arg2: !emitc.ptr) -> i1 { + %a = emitc.mul %arg0, %arg1 : (i32, i32) -> i32 + %b = emitc.apply "*"(%arg2) : (!emitc.ptr) -> (i32) + %c = emitc.cmp lt, %a, %b :(i32, i32) -> i1 + return %c : i1 +} + + // CHECK-LABEL: func.func @expression_with_address_taken( // CHECK-SAME: %[[VAL_0:.*]]: i32, %[[VAL_1:.*]]: i32, %[[VAL_2:.*]]: !emitc.ptr, %[[VAL_3:.*]]: !emitc.lvalue) -> i1 { // CHECK: %[[VAL_4:.*]] = emitc.expression : i1 { From 3c34aa3f64a76bb2d7562eea630c947308e732ab Mon Sep 17 00:00:00 2001 From: Simon Camphausen Date: Thu, 13 Jun 2024 08:19:27 +0000 Subject: [PATCH 10/14] Drop unnecessary check --- mlir/lib/Dialect/EmitC/Transforms/FormExpressions.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mlir/lib/Dialect/EmitC/Transforms/FormExpressions.cpp b/mlir/lib/Dialect/EmitC/Transforms/FormExpressions.cpp index 758b8527c2fa5..82bd031430d36 100644 --- a/mlir/lib/Dialect/EmitC/Transforms/FormExpressions.cpp +++ b/mlir/lib/Dialect/EmitC/Transforms/FormExpressions.cpp @@ -38,8 +38,7 @@ struct FormExpressionsPass auto matchFun = [&](Operation *op) { if (op->hasTrait() && !op->getParentOfType() && - op->getNumResults() == 1 && - isSupportedEmitCType(op->getResult(0).getType())) + op->getNumResults() == 1) createExpression(op, builder); }; rootOp->walk(matchFun); From bbb4e9e0cb7ab626f5be17475a9a81ebf7e09edb Mon Sep 17 00:00:00 2001 From: Simon Camphausen Date: Thu, 13 Jun 2024 15:20:52 +0000 Subject: [PATCH 11/14] Remove result name --- mlir/include/mlir/Dialect/EmitC/IR/EmitC.td | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td index f4043763445a0..dbee2ff5ce7f0 100644 --- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td +++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td @@ -1072,7 +1072,7 @@ def EmitC_VariableOp : EmitC_Op<"variable", []> { let arguments = (ins EmitC_OpaqueOrTypedAttr:$value); let results = (outs Res, "", - [MemAlloc]>:$memref); + [MemAlloc]>); let hasVerifier = 1; } From a15dd75c3d9853dfeda33dd015fa3ea007cb9c15 Mon Sep 17 00:00:00 2001 From: Simon Camphausen Date: Thu, 13 Jun 2024 15:25:03 +0000 Subject: [PATCH 12/14] Review comment --- mlir/lib/Dialect/EmitC/IR/EmitC.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp index a97b54db726dd..86a227c2d8d1c 100644 --- a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp +++ b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp @@ -61,9 +61,6 @@ void mlir::emitc::buildTerminatedBody(OpBuilder &builder, Location loc) { bool mlir::emitc::isSupportedEmitCType(Type type) { if (llvm::isa(type)) return true; - if (auto lType = llvm::dyn_cast(type)) - // lvalue types are only allowed in a few places. - return false; if (auto ptrType = llvm::dyn_cast(type)) return isSupportedEmitCType(ptrType.getPointee()); if (auto arrayType = llvm::dyn_cast(type)) { From 5f41378613f9155bae5b2f28d03cec58ed4edce7 Mon Sep 17 00:00:00 2001 From: Simon Camphausen Date: Thu, 13 Jun 2024 16:09:11 +0000 Subject: [PATCH 13/14] Disallow lvalue as argument types --- mlir/lib/Dialect/EmitC/IR/EmitC.cpp | 4 +++ mlir/lib/Target/Cpp/TranslateToCpp.cpp | 5 +++ mlir/test/Dialect/EmitC/invalid_ops.mlir | 26 +++++++++++---- mlir/test/Dialect/EmitC/ops.mlir | 8 +++-- mlir/test/Dialect/EmitC/transforms.mlir | 8 +++-- mlir/test/Target/Cpp/common-cpp.mlir | 15 +++++---- mlir/test/Target/Cpp/invalid.mlir | 7 ++++ mlir/test/Target/Cpp/member.mlir | 42 +++++++++++++++--------- 8 files changed, 79 insertions(+), 36 deletions(-) diff --git a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp index 86a227c2d8d1c..a7f033fc1ea37 100644 --- a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp +++ b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp @@ -548,6 +548,10 @@ void FuncOp::print(OpAsmPrinter &p) { } LogicalResult FuncOp::verify() { + if (llvm::any_of(getArgumentTypes(), llvm::IsaPred)) { + return emitOpError("cannot have lvalue type as argument"); + } + if (getNumResults() > 1) return emitOpError("requires zero or exactly one result, but has ") << getNumResults(); diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp index a8a0efab84aed..c043582b7be9c 100644 --- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp +++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp @@ -1064,6 +1064,11 @@ static LogicalResult printOperation(CppEmitter &emitter, "with multiple blocks needs variables declared at top"); } + if (llvm::any_of(functionOp.getArgumentTypes(), llvm::IsaPred)) { + return functionOp.emitOpError() + << "cannot emit lvalue type as argument type"; + } + if (llvm::any_of(functionOp.getResultTypes(), llvm::IsaPred)) { return functionOp.emitOpError() << "cannot emit array type as result type"; } diff --git a/mlir/test/Dialect/EmitC/invalid_ops.mlir b/mlir/test/Dialect/EmitC/invalid_ops.mlir index a80e49cc33fac..fda2ffa5642d2 100644 --- a/mlir/test/Dialect/EmitC/invalid_ops.mlir +++ b/mlir/test/Dialect/EmitC/invalid_ops.mlir @@ -88,17 +88,19 @@ func.func @array_result() { // ----- -func.func @empty_operator(%arg : !emitc.lvalue) { +func.func @empty_operator() { + %0 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue // expected-error @+1 {{'emitc.apply' op applicable operator must not be empty}} - %2 = emitc.apply ""(%arg) : (!emitc.lvalue) -> !emitc.ptr + %1 = emitc.apply ""(%0) : (!emitc.lvalue) -> !emitc.ptr return } // ----- -func.func @illegal_operator(%arg : !emitc.lvalue) { +func.func @illegal_operator() { + %0 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue // expected-error @+1 {{'emitc.apply' op applicable operator is illegal}} - %2 = emitc.apply "+"(%arg) : (!emitc.lvalue) -> !emitc.ptr + %1 = emitc.apply "+"(%0) : (!emitc.lvalue) -> !emitc.ptr return } @@ -225,10 +227,13 @@ func.func @test_misplaced_yield() { // ----- -func.func @test_assign_to_non_variable(%arg1: f32, %arg2: !emitc.lvalue) { +func.func @test_assign_to_block_argument(%arg0: f32) { + %0 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue + cf.br ^bb1(%0 : !emitc.lvalue) +^bb1(%a : !emitc.lvalue): // expected-error @+1 {{'emitc.assign' op cannot assign to block argument}} - emitc.assign %arg1 : f32 to %arg2 : !emitc.lvalue - return + emitc.assign %arg0 : f32 to %a : !emitc.lvalue + func.return } // ----- @@ -330,6 +335,13 @@ emitc.func @return_type_mismatch() -> i32 { // ----- +// expected-error@+1 {{'emitc.func' op cannot have lvalue type as argument}} +emitc.func @argument_type_lvalue(%arg : !emitc.lvalue) { + emitc.return +} + +// ----- + // expected-error@+1 {{'emitc.func' op cannot return array type}} emitc.func @return_type_array(%arg : !emitc.array<4xi32>) -> !emitc.array<4xi32> { emitc.return %arg : !emitc.array<4xi32> diff --git a/mlir/test/Dialect/EmitC/ops.mlir b/mlir/test/Dialect/EmitC/ops.mlir index bb38754ff469b..b0a95b8940cc7 100644 --- a/mlir/test/Dialect/EmitC/ops.mlir +++ b/mlir/test/Dialect/EmitC/ops.mlir @@ -47,9 +47,11 @@ func.func @c() { return } -func.func @a(%arg0: !emitc.lvalue, %arg1: !emitc.lvalue) { - %1 = "emitc.apply"(%arg0) {applicableOperator = "&"} : (!emitc.lvalue) -> !emitc.ptr - %2 = emitc.apply "&"(%arg1) : (!emitc.lvalue) -> !emitc.ptr +func.func @a() { + %0 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue + %1 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue + %2 = "emitc.apply"(%0) {applicableOperator = "&"} : (!emitc.lvalue) -> !emitc.ptr + %3 = emitc.apply "&"(%1) : (!emitc.lvalue) -> !emitc.ptr return } diff --git a/mlir/test/Dialect/EmitC/transforms.mlir b/mlir/test/Dialect/EmitC/transforms.mlir index bd0dd820609bf..6cfac6462623c 100644 --- a/mlir/test/Dialect/EmitC/transforms.mlir +++ b/mlir/test/Dialect/EmitC/transforms.mlir @@ -85,7 +85,8 @@ func.func @expression_with_dereference(%arg0: i32, %arg1: i32, %arg2: !emitc.ptr // CHECK-LABEL: func.func @expression_with_address_taken( -// CHECK-SAME: %[[VAL_0:.*]]: i32, %[[VAL_1:.*]]: i32, %[[VAL_2:.*]]: !emitc.ptr, %[[VAL_3:.*]]: !emitc.lvalue) -> i1 { +// CHECK-SAME: %[[VAL_0:.*]]: i32, %[[VAL_1:.*]]: i32, %[[VAL_2:.*]]: !emitc.ptr) -> i1 { +// CHECK: %[[VAL_3:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue // CHECK: %[[VAL_4:.*]] = emitc.expression : i1 { // CHECK: %[[VAL_5:.*]] = emitc.apply "&"(%[[VAL_3]]) : (!emitc.lvalue) -> !emitc.ptr // CHECK: %[[VAL_6:.*]] = emitc.add %[[VAL_5]], %[[VAL_1]] : (!emitc.ptr, i32) -> !emitc.ptr @@ -95,8 +96,9 @@ func.func @expression_with_dereference(%arg0: i32, %arg1: i32, %arg2: !emitc.ptr // CHECK: return %[[VAL_4]] : i1 // CHECK: } -func.func @expression_with_address_taken(%arg0: i32, %arg1: i32, %arg2: !emitc.ptr, %arg3: !emitc.lvalue) -> i1 { - %a = emitc.apply "&"(%arg3) : (!emitc.lvalue) -> !emitc.ptr +func.func @expression_with_address_taken(%arg0: i32, %arg1: i32, %arg2: !emitc.ptr) -> i1 { + %0 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue + %a = emitc.apply "&"(%0) : (!emitc.lvalue) -> !emitc.ptr %b = emitc.add %a, %arg1 : (!emitc.ptr, i32) -> !emitc.ptr %c = emitc.cmp lt, %b, %arg2 :(!emitc.ptr, !emitc.ptr) -> i1 return %c : i1 diff --git a/mlir/test/Target/Cpp/common-cpp.mlir b/mlir/test/Target/Cpp/common-cpp.mlir index 8af29531905ba..2036a10e0cad1 100644 --- a/mlir/test/Target/Cpp/common-cpp.mlir +++ b/mlir/test/Target/Cpp/common-cpp.mlir @@ -82,19 +82,20 @@ func.func @opaque_types(%arg0: !emitc.opaque<"bool">, %arg1: !emitc.opaque<"char return %2 : !emitc.opaque<"status_t"> } -// CHECK-LABEL: int32_t* apply( -// CHECK-SAME: int32_t [[V1:[^ ]*]]) { -func.func @apply(%arg0: !emitc.lvalue) -> !emitc.ptr { +// CHECK-LABEL: int32_t* apply() { +func.func @apply() -> !emitc.ptr { + // CHECK-NEXT: int32_t [[V1:[^ ]*]]; + %0 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue // CHECK-NEXT: int32_t* [[V2:[^ ]*]] = &[[V1]]; - %0 = emitc.apply "&"(%arg0) : (!emitc.lvalue) -> !emitc.ptr + %1 = emitc.apply "&"(%0) : (!emitc.lvalue) -> !emitc.ptr // CHECK-NEXT: int32_t [[V3:[^ ]*]]; %2 = "emitc.variable"() {value = #emitc.opaque<"">} : () -> !emitc.lvalue // CHECK-NEXT: int32_t [[V4:[^ ]*]] = *[[V2]]; - %1 = emitc.apply "*"(%0) : (!emitc.ptr) -> i32 + %3 = emitc.apply "*"(%1) : (!emitc.ptr) -> i32 // CHECK-NEXT: [[V3]] = [[V4]]; - emitc.assign %1 : i32 to %2 : !emitc.lvalue + emitc.assign %3 : i32 to %2 : !emitc.lvalue // CHECK-NEXT: return [[V2]]; - return %0 : !emitc.ptr + return %1 : !emitc.ptr } // CHECK: void array_type(int32_t v1[3], float v2[10][20]) diff --git a/mlir/test/Target/Cpp/invalid.mlir b/mlir/test/Target/Cpp/invalid.mlir index 89f984f85347f..df4627a158319 100644 --- a/mlir/test/Target/Cpp/invalid.mlir +++ b/mlir/test/Target/Cpp/invalid.mlir @@ -74,6 +74,13 @@ func.func @pointer_to_array(%arg0 : !emitc.ptr>) { // ----- +// expected-error@+1 {{cannot emit lvalue type as argument type}} +func.func @lvalue_as_argument(%arg: !emitc.lvalue) { + return +} + +// ----- + // expected-error@+1 {{cannot emit array type as result type}} func.func @array_as_result(%arg: !emitc.array<4xi8>) -> (!emitc.array<4xi8>) { return %arg : !emitc.array<4xi8> diff --git a/mlir/test/Target/Cpp/member.mlir b/mlir/test/Target/Cpp/member.mlir index df3450c05dbf9..20589fe5b00b8 100644 --- a/mlir/test/Target/Cpp/member.mlir +++ b/mlir/test/Target/Cpp/member.mlir @@ -1,10 +1,13 @@ // RUN: mlir-translate -mlir-to-cpp %s | FileCheck %s -check-prefix=CPP-DEFAULT -func.func @member(%arg0: !emitc.lvalue>, %arg1: i32) { - %0 = "emitc.member" (%arg0) {member = "a"} : (!emitc.lvalue>) -> !emitc.lvalue +func.func @member(%arg0: !emitc.opaque<"mystruct">, %arg1: i32) { + %var0 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue> + emitc.assign %arg0 : !emitc.opaque<"mystruct"> to %var0 : !emitc.lvalue> + + %0 = "emitc.member" (%var0) {member = "a"} : (!emitc.lvalue>) -> !emitc.lvalue emitc.assign %arg1 : i32 to %0 : !emitc.lvalue - %1 = "emitc.member" (%arg0) {member = "b"} : (!emitc.lvalue>) -> !emitc.lvalue + %1 = "emitc.member" (%var0) {member = "b"} : (!emitc.lvalue>) -> !emitc.lvalue %2 = emitc.load %1 : !emitc.lvalue %3 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue emitc.assign %2 : i32 to %3 : !emitc.lvalue @@ -13,17 +16,22 @@ func.func @member(%arg0: !emitc.lvalue>, %arg1: i32) { } // CPP-DEFAULT: void member(mystruct [[V0:[^ ]*]], int32_t [[V1:[^ ]*]]) { -// CPP-DEFAULT-NEXT: [[V0]].a = [[V1]]; -// CPP-DEFAULT-NEXT: int32_t [[V2:[^ ]*]] = [[V0]].b; -// CPP-DEFAULT-NEXT: int32_t [[V3:[^ ]*]]; -// CPP-DEFAULT-NEXT: [[V3]] = [[V2]]; - - -func.func @member_of_pointer(%arg0: !emitc.lvalue>>, %arg1: i32) { - %0 = "emitc.member_of_ptr" (%arg0) {member = "a"} : (!emitc.lvalue>>) -> !emitc.lvalue +// CPP-DEFAULT-NEXT: mystruct [[V2:[^ ]*]]; +// CPP-DEFAULT-NEXT: [[V2]] = [[V0]]; +// CPP-DEFAULT-NEXT: [[V2]].a = [[V1]]; +// CPP-DEFAULT-NEXT: int32_t [[V3:[^ ]*]] = [[V2]].b; +// CPP-DEFAULT-NEXT: int32_t [[V4:[^ ]*]]; +// CPP-DEFAULT-NEXT: [[V4]] = [[V3]]; + + +func.func @member_of_pointer(%arg0: !emitc.ptr>, %arg1: i32) { + %var0 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue>> + emitc.assign %arg0 : !emitc.ptr> to %var0 : !emitc.lvalue>> + + %0 = "emitc.member_of_ptr" (%var0) {member = "a"} : (!emitc.lvalue>>) -> !emitc.lvalue emitc.assign %arg1 : i32 to %0 : !emitc.lvalue - %1 = "emitc.member_of_ptr" (%arg0) {member = "b"} : (!emitc.lvalue>>) -> !emitc.lvalue + %1 = "emitc.member_of_ptr" (%var0) {member = "b"} : (!emitc.lvalue>>) -> !emitc.lvalue %2 = emitc.load %1 : !emitc.lvalue %3 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue emitc.assign %2 : i32 to %3 : !emitc.lvalue @@ -32,8 +40,10 @@ func.func @member_of_pointer(%arg0: !emitc.lvaluea = [[V1]]; -// CPP-DEFAULT-NEXT: int32_t [[V2:[^ ]*]] = [[V0]]->b; -// CPP-DEFAULT-NEXT: int32_t [[V3:[^ ]*]]; -// CPP-DEFAULT-NEXT: [[V3]] = [[V2]]; +// CPP-DEFAULT-NEXT: mystruct* [[V2:[^ ]*]]; +// CPP-DEFAULT-NEXT: [[V2]] = [[V0]]; +// CPP-DEFAULT-NEXT: [[V2]]->a = [[V1]]; +// CPP-DEFAULT-NEXT: int32_t [[V3:[^ ]*]] = [[V2]]->b; +// CPP-DEFAULT-NEXT: int32_t [[V4:[^ ]*]]; +// CPP-DEFAULT-NEXT: [[V4]] = [[V3]]; From a600df4a00258339738b6c2125bd11a34a0e1bfe Mon Sep 17 00:00:00 2001 From: Simon Camphausen Date: Mon, 5 Aug 2024 12:40:17 +0000 Subject: [PATCH 14/14] Fix examples in op descriptions --- mlir/include/mlir/Dialect/EmitC/IR/EmitC.td | 44 ++++++++++++++------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td index dbee2ff5ce7f0..b8f9b7be37270 100644 --- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td +++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td @@ -88,11 +88,11 @@ def EmitC_ApplyOp : EmitC_Op<"apply", [CExpression]> { ```mlir // Custom form of applying the & operator. - %0 = emitc.apply "&"(%arg0) : (i32) -> !emitc.ptr + %0 = emitc.apply "&"(%arg0) : (!emitc.lvalue) -> !emitc.ptr // Generic form of the same operation. %0 = "emitc.apply"(%arg0) {applicableOperator = "&"} - : (i32) -> !emitc.ptr + : (!emitc.lvalue) -> !emitc.ptr ``` }]; @@ -846,6 +846,16 @@ def EmitC_LoadOp : EmitC_Op<"load", [ This operation loads the content of a modifiable lvalue into an SSA value. Modifications of the lvalue executed after the load are not observable on the produced value. + + Example: + + ```mlir + %1 = emitc.load %0 : !emitc.lvalue + ``` + ```c++ + // Code emitted for the operation above. + int32_t v2 = v1; + ``` }]; let arguments = (ins @@ -937,7 +947,7 @@ def EmitC_MemberOp : EmitC_Op<"member"> { ```mlir %0 = "emitc.member" (%arg0) {member = "a"} - : (!emitc.opaque<"mystruct">) -> i32 + : (!emitc.lvalue>) -> !emitc.lvalue ``` }]; @@ -958,7 +968,8 @@ def EmitC_MemberOfPtrOp : EmitC_Op<"member_of_ptr"> { ```mlir %0 = "emitc.member_of_ptr" (%arg0) {member = "a"} - : (!emitc.ptr>) -> i32 + : (!emitc.lvalue>>) + -> !emitc.lvalue ``` }]; @@ -1050,21 +1061,21 @@ def EmitC_VariableOp : EmitC_Op<"variable", []> { ```mlir // Integer variable - %0 = "emitc.variable"(){value = 42 : i32} : () -> i32 + %0 = "emitc.variable"(){value = 42 : i32} : () -> !emitc.lvalue // Variable emitted as `int32_t* = NULL;` %1 = "emitc.variable"() {value = #emitc.opaque<"NULL">} - : () -> !emitc.ptr> + : () -> !emitc.lvalue>> ``` Since folding is not supported, it can be used with pointers. As an example, it is valid to create pointers to `variable` operations by using `apply` operations and pass these to a `call` operation. ```mlir - %0 = "emitc.variable"() {value = 0 : i32} : () -> i32 - %1 = "emitc.variable"() {value = 0 : i32} : () -> i32 - %2 = emitc.apply "&"(%0) : (i32) -> !emitc.ptr - %3 = emitc.apply "&"(%1) : (i32) -> !emitc.ptr + %0 = "emitc.variable"() {value = 0 : i32} : () -> !emitc.lvalue + %1 = "emitc.variable"() {value = 0 : i32} : () -> !emitc.lvalue + %2 = emitc.apply "&"(%0) : (!emitc.lvalue) -> !emitc.ptr + %3 = emitc.apply "&"(%1) : (!emitc.lvalue) -> !emitc.ptr emitc.call_opaque "write"(%2, %3) : (!emitc.ptr, !emitc.ptr) -> () ``` @@ -1138,6 +1149,7 @@ def EmitC_GetGlobalOp : EmitC_Op<"get_global", ```mlir %x = emitc.get_global @foo : !emitc.array<2xf32> + %y = emitc.get_global @bar : !emitc.lvalue ``` }]; @@ -1192,11 +1204,11 @@ def EmitC_AssignOp : EmitC_Op<"assign", []> { ```mlir // Integer variable - %0 = "emitc.variable"(){value = 42 : i32} : () -> i32 + %0 = "emitc.variable"(){value = 42 : i32} : () -> !emitc.lvalue %1 = emitc.call_opaque "foo"() : () -> (i32) // Assign emitted as `... = ...;` - "emitc.assign"(%0, %1) : (i32, i32) -> () + "emitc.assign"(%0, %1) : (!emitc.lvalue, i32) -> () ``` }]; @@ -1298,8 +1310,10 @@ def EmitC_SubscriptOp : EmitC_Op<"subscript", []> { ```mlir %i = index.constant 1 %j = index.constant 7 - %0 = emitc.subscript %arg0[%i, %j] : !emitc.array<4x8xf32>, index, index - %1 = emitc.subscript %arg1[%i] : !emitc.ptr, index + %0 = emitc.subscript %arg0[%i, %j] : (!emitc.array<4x8xf32>, index, index) + -> !emitc.lvalue + %1 = emitc.subscript %arg1[%i] : (!emitc.ptr, index) + -> !emitc.lvalue ``` }]; let arguments = (ins Arg f32 + %3 = "emitc.constant"(){value = 42.0 : f32} : () -> f32 emitc.call_opaque "func2" (%3) : (f32) -> () } ```