From e47b507562624bf291ab2515699d39c2669b6131 Mon Sep 17 00:00:00 2001 From: Simon Camphausen Date: Tue, 20 Aug 2024 11:52:16 +0200 Subject: [PATCH] [mlir][EmitC] Model lvalues as a type in EmitC (#91475) This adds an `emitc.lvalue` type which models assignable lvlaues in the type system. Operations modifying memory are restricted to this type accordingly. See also the discussion on [discourse](https://discourse.llvm.org/t/rfc-separate-variables-from-ssa-values-in-emitc/75224/9). The most notable changes are as follows. - `emitc.variable` and `emitc.global` ops are restricted to return `emitc.array` or `emitc.lvalue` types - Taking the address of a value is restricted to operands with lvalue type - Conversion from lvalues into SSA values is done with the new `emitc.load` op - The var operand of the `emitc.assign` op is restricted to lvalue type - The result of the `emitc.subscript` and `emitc.get_global` ops is a lvalue type - The operands and results of the `emitc.member` and `emitc.member_of_ptr` ops are restricted to lvalue types --------- Co-authored-by: Matthias Gehre --- mlir/include/mlir/Dialect/EmitC/IR/EmitC.td | 101 +++++++++++----- .../mlir/Dialect/EmitC/IR/EmitCTypes.td | 27 +++++ .../MemRefToEmitC/MemRefToEmitC.cpp | 7 +- mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp | 36 +++++- mlir/lib/Dialect/EmitC/IR/EmitC.cpp | 108 +++++++++++++----- mlir/lib/Target/Cpp/TranslateToCpp.cpp | 20 +++- .../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 | 106 +++++++++-------- mlir/test/Dialect/EmitC/invalid_types.mlir | 66 ++++++++--- mlir/test/Dialect/EmitC/ops.mlir | 39 ++++--- mlir/test/Dialect/EmitC/transforms.mlir | 30 +++-- mlir/test/Dialect/EmitC/types.mlir | 19 ++- mlir/test/Target/Cpp/common-cpp.mlir | 20 +++- 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 | 9 +- .../Cpp/invalid_declare_variables_at_top.mlir | 15 ++- mlir/test/Target/Cpp/lvalue.mlir | 28 +++++ mlir/test/Target/Cpp/member.mlir | 47 +++++--- mlir/test/Target/Cpp/subscript.mlir | 106 ++++++++++++----- mlir/test/Target/Cpp/switch.mlir | 56 ++++----- mlir/test/Target/Cpp/variable.mlir | 16 +-- 27 files changed, 810 insertions(+), 382 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 40903b4e288ca6..b8f9b7be372703 100644 --- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td +++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td @@ -88,17 +88,17 @@ 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 ``` }]; let arguments = (ins Arg:$applicableOperator, - EmitCType:$operand + AnyTypeOf<[EmitCType, EmitC_LValueType]>:$operand ); let results = (outs EmitCType:$result); let assemblyFormat = [{ @@ -836,6 +836,35 @@ def EmitC_LogicalOrOp : EmitC_BinaryOp<"logical_or", [CExpression]> { let assemblyFormat = "operands attr-dict `:` type(operands)"; } +def EmitC_LoadOp : EmitC_Op<"load", [ + TypesMatchWith<"result type matches value type of 'operand'", + "operand", "result", + "::llvm::cast($_self).getValueType()"> +]> { + let summary = "Load an lvalue into an SSA value."; + 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. + + Example: + + ```mlir + %1 = emitc.load %0 : !emitc.lvalue + ``` + ```c++ + // Code emitted for the operation above. + int32_t v2 = v1; + ``` + }]; + + let arguments = (ins + Res]>:$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 = [{ @@ -918,15 +947,15 @@ def EmitC_MemberOp : EmitC_Op<"member"> { ```mlir %0 = "emitc.member" (%arg0) {member = "a"} - : (!emitc.opaque<"mystruct">) -> i32 + : (!emitc.lvalue>) -> !emitc.lvalue ``` }]; 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"> { @@ -939,15 +968,16 @@ def EmitC_MemberOfPtrOp : EmitC_Op<"member_of_ptr"> { ```mlir %0 = "emitc.member_of_ptr" (%arg0) {member = "a"} - : (!emitc.ptr>) -> i32 + : (!emitc.lvalue>>) + -> !emitc.lvalue ``` }]; 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", @@ -1031,28 +1061,29 @@ 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) -> () ``` }]; let arguments = (ins EmitC_OpaqueOrTypedAttr:$value); - let results = (outs EmitCType); + let results = (outs Res, "", + [MemAlloc]>); let hasVerifier = 1; } @@ -1118,11 +1149,12 @@ def EmitC_GetGlobalOp : EmitC_Op<"get_global", ```mlir %x = emitc.get_global @foo : !emitc.array<2xf32> + %y = emitc.get_global @bar : !emitc.lvalue ``` }]; 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"; } @@ -1172,15 +1204,17 @@ 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) -> () ``` }]; - let arguments = (ins EmitCType:$var, EmitCType:$value); + let arguments = (ins + Res]>:$var, + EmitCType:$value); let results = (outs); let hasVerifier = 1; @@ -1276,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 { 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} + ); }]> ]; @@ -1338,7 +1385,7 @@ def EmitC_SwitchOp : EmitC_Op<"switch", [RecursiveMemoryEffects, 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/include/mlir/Dialect/EmitC/IR/EmitCTypes.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitCTypes.td index 79f6d34fc91b13..134ef04f26dd4b 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":$valueType); + let builders = [ + TypeBuilderWithInferredContext<(ins "Type":$valueType), [{ + return $_get(valueType.getContext(), valueType); + }]> + ]; + let assemblyFormat = "`<` qualified($valueType) `>`"; + 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).getValueType()", + "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 e0c421741b3055..1392bf924002ee 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 ede811c6e1bb1e..67a43c43d608b4 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()).getValueType(); + 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); + // Load variables into SSA values 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(); } diff --git a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp index d731a6756ff630..a7f033fc1ea37b 100644 --- a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp +++ b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp @@ -145,6 +145,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.getValueType(); Type attrType = cast(value).getType(); if (isPointerWideType(resultType) && attrType.isIndex()) @@ -196,9 +198,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 +220,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().getValueType(); + if (variableType != valueType) + return emitOpError() << "requires value's type (" << valueType + << ") to match variable's type (" << variableType + << ")\n variable: " << variable + << "\n value: " << getValue() << "\n"; return success(); } @@ -542,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(); @@ -853,9 +863,10 @@ LogicalResult emitc::SubscriptOp::verify() { } // Check element type. Type elementType = arrayType.getElementType(); - if (elementType != getType()) { + Type resultType = getType().getValueType(); + 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 +890,10 @@ LogicalResult emitc::SubscriptOp::verify() { } // Check pointee type. Type pointeeType = pointerType.getPointee(); - if (pointeeType != getType()) { + Type resultType = getType().getValueType(); + 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 +987,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 +1023,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 +1132,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.getValueType() != globalType) + return emitOpError("on non-array type expects result inner type ") + << 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 8e112e6f7dda65..c043582b7be9c6 100644 --- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp +++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp @@ -384,6 +384,13 @@ static LogicalResult printOperation(CppEmitter &emitter, return emitter.emitOperand(assignOp.getValue()); } +static LogicalResult printOperation(CppEmitter &emitter, emitc::LoadOp loadOp) { + if (failed(emitter.emitAssignPrefix(*loadOp))) + return failure(); + + return emitter.emitOperand(loadOp.getOperand()); +} + static LogicalResult printBinaryOperation(CppEmitter &emitter, Operation *operation, StringRef binaryOperator) { @@ -1011,9 +1018,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(); @@ -1057,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"; } @@ -1543,7 +1555,7 @@ 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::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, @@ -1675,6 +1687,8 @@ LogicalResult CppEmitter::emitType(Location loc, Type type) { os << "[" << dim << "]"; return success(); } + if (auto lType = dyn_cast(type)) + 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; diff --git a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir index bc40ef48268eb0..f4722da08cc40f 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.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 7e59eac3d40950..83592187a9b688 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.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: return %[[VAL_5]], %[[VAL_6]] : f32, f32 +// 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: } 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.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.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.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.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 afc9abc761eb4c..7d923785862d85 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.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 659d9f43963efa..86d96ed21f1b59 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.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) { +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 4b5bcf46c1aab9..fda2ffa5642d2d 100644 --- a/mlir/test/Dialect/EmitC/invalid_ops.mlir +++ b/mlir/test/Dialect/EmitC/invalid_ops.mlir @@ -88,26 +88,19 @@ func.func @array_result() { // ----- -func.func @empty_operator(%arg : i32) { +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) : (i32) -> !emitc.ptr + %1 = emitc.apply ""(%0) : (!emitc.lvalue) -> !emitc.ptr return } // ----- -func.func @illegal_operator(%arg : i32) { +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) : (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 + %1 = emitc.apply "+"(%0) : (!emitc.lvalue) -> !emitc.ptr return } @@ -115,7 +108,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 +116,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 +227,21 @@ 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 - return +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 %arg0 : f32 to %a : !emitc.lvalue + func.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 +249,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 +269,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.load %x : + emitc.yield %y : i32 } return %r : i32 } @@ -338,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> @@ -392,7 +396,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 +404,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 +412,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 +420,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 +428,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 +436,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 +447,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 +496,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 +506,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 +519,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 +529,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 +547,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 +560,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 9bf0c49e7199a9..302a345c7c4f42 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 64f22e8ad6b983..b0a95b8940cc7e 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: i32, %arg1: i32) { - %1 = "emitc.apply"(%arg0) {applicableOperator = "&"} : (i32) -> !emitc.ptr - %2 = emitc.apply "&"(%arg1) : (i32) -> !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 } @@ -173,8 +175,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 +220,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 +247,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.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 +278,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 a5c582be4aa7f6..6cfac6462623c9 100644 --- a/mlir/test/Dialect/EmitC/transforms.mlir +++ b/mlir/test/Dialect/EmitC/transforms.mlir @@ -73,8 +73,6 @@ func.func @expression_with_call(%arg0: i32, %arg1: i32, %arg2: i32, %arg3: i32) // 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: emitc.yield %[[VAL_7]] : i1 -// CHECK: } // CHECK: return %[[VAL_5]] : i1 // CHECK: } @@ -85,27 +83,25 @@ func.func @expression_with_dereference(%arg0: i32, %arg1: i32, %arg2: !emitc.ptr 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: %[[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 +// 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_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 + %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 } // CHECK-LABEL: func.func @no_nested_expression( diff --git a/mlir/test/Dialect/EmitC/types.mlir b/mlir/test/Dialect/EmitC/types.mlir index 66947a97e1f9fe..e3462bffc5b0de 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 0e24bdd19993f0..2036a10e0cad15 100644 --- a/mlir/test/Target/Cpp/common-cpp.mlir +++ b/mlir/test/Target/Cpp/common-cpp.mlir @@ -82,12 +82,20 @@ 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) - return %0 : !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]]; + %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]]; + %3 = emitc.apply "*"(%1) : (!emitc.ptr) -> i32 + // CHECK-NEXT: [[V3]] = [[V4]]; + emitc.assign %3 : i32 to %2 : !emitc.lvalue + // CHECK-NEXT: return [[V2]]; + return %1 : !emitc.ptr } // CHECK: void array_type(int32_t v1[3], float v2[10][20]) diff --git a/mlir/test/Target/Cpp/expressions.mlir b/mlir/test/Target/Cpp/expressions.mlir index caa0a340d3e0ad..6b67065f5d1a1c 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.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.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.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.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 af1d829113f9dd..6a446eaf4add3f 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.load %2 : !emitc.lvalue + %sn = emitc.call_opaque "add"(%4, %iter) : (i32, index) -> i32 + %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.load %2 : !emitc.lvalue + emitc.assign %6 : i32 to %0 : !emitc.lvalue + %7 = emitc.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.load %2 : !emitc.lvalue + %sn = emitc.call_opaque "add"(%4, %iter) : (i32, index) -> i32 + %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.load %2 : !emitc.lvalue + emitc.assign %6 : i32 to %0 : !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 bddd94aea4219c..c54338bc2faffd 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.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.load %1 : + 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 7b0e2da85d0eb2..d3b792192c8b10 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 4e777239fba662..df4627a158319b 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> @@ -83,6 +90,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/invalid_declare_variables_at_top.mlir b/mlir/test/Target/Cpp/invalid_declare_variables_at_top.mlir index 844fe03bad4aba..8b87113e6d960a 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 } diff --git a/mlir/test/Target/Cpp/lvalue.mlir b/mlir/test/Target/Cpp/lvalue.mlir new file mode 100644 index 00000000000000..2aa438eb6371c7 --- /dev/null +++ b/mlir/test/Target/Cpp/lvalue.mlir @@ -0,0 +1,28 @@ +// RUN: mlir-translate -mlir-to-cpp %s | FileCheck %s + +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 + 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.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 +} +// 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"]} +// CHECK-LABEL: extern void zero(int32_t*); diff --git a/mlir/test/Target/Cpp/member.mlir b/mlir/test/Target/Cpp/member.mlir index 1b4a3dcab879da..20589fe5b00b8f 100644 --- a/mlir/test/Target/Cpp/member.mlir +++ b/mlir/test/Target/Cpp/member.mlir @@ -1,34 +1,49 @@ // 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 + %var0 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue> + emitc.assign %arg0 : !emitc.opaque<"mystruct"> to %var0 : !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 + %0 = "emitc.member" (%var0) {member = "a"} : (!emitc.lvalue>) -> !emitc.lvalue + emitc.assign %arg1 : i32 to %0 : !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 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: 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) { - %0 = "emitc.member_of_ptr" (%arg0) {member = "a"} : (!emitc.ptr>) -> i32 - emitc.assign %arg1 : i32 to %0 : 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.ptr>) -> i32 - %2 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> i32 - emitc.assign %1 : i32 to %2 : i32 + %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 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: 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]]; + diff --git a/mlir/test/Target/Cpp/subscript.mlir b/mlir/test/Target/Cpp/subscript.mlir index 0b388953c80d37..7f015c210796e7 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.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.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.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.load %0 : + emitc.call @func1 (%2) : (f32) -> () + %3 = emitc.load %1 : + emitc.call_opaque "func2" (%3) : (f32) -> () + %4 = emitc.load %0 : + %5 = emitc.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 0f2e716a98f16b..f9b8600606ec2b 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 126dd384b47a2a..a26d724127cf25 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: ;