diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td @@ -527,9 +527,10 @@ The `call` instruction supports both direct and indirect calls. Direct calls start with a function name (`@`-prefixed) and indirect calls start with an SSA value (`%`-prefixed). The direct callee, if present, is stored as a - function attribute `callee`. The trailing type of the instruction is always - the MLIR function type, which may be different from the indirect callee that - has the wrapped LLVM IR function type. + function attribute `callee`. The trailing type list contains the optional + indirect callee type and the MLIR function type, which differs from the + LLVM function type that uses a explicit void type to model functions that do + not return a value. Examples: @@ -541,7 +542,7 @@ llvm.call @bar(%0) : (f32) -> () // Indirect call with an argument and without a result. - llvm.call %1(%0) : (f32) -> () + llvm.call %1(%0) : !llvm.ptr, (f32) -> () ``` }]; @@ -1652,13 +1653,18 @@ // FIXME: Need to add alignment and syncscope attribute to MLIR atomicrmw // operation. -def LLVM_AtomicRMWOp : LLVM_Op<"atomicrmw"> { +def LLVM_AtomicRMWOp : LLVM_Op<"atomicrmw", [ + TypesMatchWith<"result #0 and operand #1 have the same type", + "val", "res", "$_self">]> { let arguments = (ins AtomicBinOp:$bin_op, LLVM_PointerTo:$ptr, LLVM_AtomicRMWType:$val, AtomicOrdering:$ordering); let results = (outs LLVM_AtomicRMWType:$res); - let hasCustomAssemblyFormat = 1; let hasVerifier = 1; + let assemblyFormat = [{ + $bin_op $ptr `,` $val $ordering + attr-dict `:` qualified(type($ptr)) `,` type($val) + }]; string llvmInstName = "AtomicRMW"; string llvmBuilder = [{ $res = builder.CreateAtomicRMW(getLLVMAtomicBinOp($bin_op), $ptr, $val, @@ -1676,27 +1682,24 @@ } def LLVM_AtomicCmpXchgType : AnyTypeOf<[AnyInteger, LLVM_AnyPointer]>; -def LLVM_AtomicCmpXchgResultType : Type().getBody().size() == 2">, - SubstLeaves<"$_self", - "$_self.cast<::mlir::LLVM::LLVMStructType>().getBody()[0]", - LLVM_AtomicCmpXchgType.predicate>, - SubstLeaves<"$_self", - "$_self.cast<::mlir::LLVM::LLVMStructType>().getBody()[1]", - I1.predicate>]>, - "an LLVM struct type with any integer or pointer followed by a single-bit " - "integer">; // FIXME: Need to add alignment attribute to MLIR cmpxchg operation. -def LLVM_AtomicCmpXchgOp : LLVM_Op<"cmpxchg"> { +def LLVM_AtomicCmpXchgOp : LLVM_Op<"cmpxchg", [ + TypesMatchWith<"operand #1 and operand #2 have the same type", + "val", "cmp", "$_self">, + TypesMatchWith<"result #0 has an LLVM struct type that contains an " + "operand #2 and a bool element type", + "val", "res", "getValAndBoolStructType($_self)">]> { let arguments = (ins LLVM_PointerTo:$ptr, LLVM_AtomicCmpXchgType:$cmp, LLVM_AtomicCmpXchgType:$val, AtomicOrdering:$success_ordering, AtomicOrdering:$failure_ordering); - let results = (outs LLVM_AtomicCmpXchgResultType:$res); - let hasCustomAssemblyFormat = 1; + let results = (outs LLVM_AnyStruct:$res); let hasVerifier = 1; + let assemblyFormat = [{ + $ptr `,` $cmp `,` $val $success_ordering $failure_ordering + attr-dict `:` qualified(type($ptr)) `,` type($val) + }]; string llvmInstName = "AtomicCmpXchg"; string llvmBuilder = [{ $res = builder.CreateAtomicCmpXchg($ptr, $cmp, $val, llvm::MaybeAlign(), diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp @@ -891,6 +891,225 @@ return success(); } +//===----------------------------------------------------------------------===// +// CallOp +//===----------------------------------------------------------------------===// + +void CallOp::build(OpBuilder &builder, OperationState &state, TypeRange results, + StringRef callee, ValueRange args) { + build(builder, state, results, builder.getStringAttr(callee), args); +} + +void CallOp::build(OpBuilder &builder, OperationState &state, TypeRange results, + StringAttr callee, ValueRange args) { + build(builder, state, results, SymbolRefAttr::get(callee), args, nullptr, + nullptr); +} + +void CallOp::build(OpBuilder &builder, OperationState &state, TypeRange results, + FlatSymbolRefAttr callee, ValueRange args) { + build(builder, state, results, callee, args, nullptr, nullptr); +} + +void CallOp::build(OpBuilder &builder, OperationState &state, LLVMFuncOp func, + ValueRange args) { + SmallVector results; + Type resultType = func.getFunctionType().getReturnType(); + if (!resultType.isa()) + results.push_back(resultType); + build(builder, state, results, SymbolRefAttr::get(func), args, nullptr, + nullptr); +} + +CallInterfaceCallable CallOp::getCallableForCallee() { + // Direct call. + if (FlatSymbolRefAttr calleeAttr = getCalleeAttr()) + return calleeAttr; + // Indirect call, callee Value is the first operand. + return getOperand(0); +} + +Operation::operand_range CallOp::getArgOperands() { + return getOperands().drop_front(getCallee().has_value() ? 0 : 1); +} + +LogicalResult CallOp::verifySymbolUses(SymbolTableCollection &symbolTable) { + if (getNumResults() > 1) + return emitOpError("must have 0 or 1 result"); + + // Type for the callee, we'll get it differently depending if it is a direct + // or indirect call. + Type fnType; + + bool isIndirect = false; + + // If this is an indirect call, the callee attribute is missing. + FlatSymbolRefAttr calleeName = getCalleeAttr(); + if (!calleeName) { + isIndirect = true; + if (!getNumOperands()) + return emitOpError( + "must have either a `callee` attribute or at least an operand"); + auto ptrType = getOperand(0).getType().dyn_cast(); + if (!ptrType) + return emitOpError("indirect call expects a pointer as callee: ") + << getOperand(0).getType(); + + if (ptrType.isOpaque()) + return success(); + + fnType = ptrType.getElementType(); + } else { + Operation *callee = + symbolTable.lookupNearestSymbolFrom(*this, calleeName.getAttr()); + if (!callee) + return emitOpError() + << "'" << calleeName.getValue() + << "' does not reference a symbol in the current scope"; + auto fn = dyn_cast(callee); + if (!fn) + return emitOpError() << "'" << calleeName.getValue() + << "' does not reference a valid LLVM function"; + + fnType = fn.getFunctionType(); + } + + LLVMFunctionType funcType = fnType.dyn_cast(); + if (!funcType) + return emitOpError("callee does not have a functional type: ") << fnType; + + // Verify that the operand and result types match the callee. + + if (!funcType.isVarArg() && + funcType.getNumParams() != (getNumOperands() - isIndirect)) + return emitOpError() << "incorrect number of operands (" + << (getNumOperands() - isIndirect) + << ") for callee (expecting: " + << funcType.getNumParams() << ")"; + + if (funcType.getNumParams() > (getNumOperands() - isIndirect)) + return emitOpError() << "incorrect number of operands (" + << (getNumOperands() - isIndirect) + << ") for varargs callee (expecting at least: " + << funcType.getNumParams() << ")"; + + for (unsigned i = 0, e = funcType.getNumParams(); i != e; ++i) + if (getOperand(i + isIndirect).getType() != funcType.getParamType(i)) + return emitOpError() << "operand type mismatch for operand " << i << ": " + << getOperand(i + isIndirect).getType() + << " != " << funcType.getParamType(i); + + if (getNumResults() == 0 && + !funcType.getReturnType().isa()) + return emitOpError() << "expected function call to produce a value"; + + if (getNumResults() != 0 && + funcType.getReturnType().isa()) + return emitOpError() + << "calling function with void result must not produce values"; + + if (getNumResults() > 1) + return emitOpError() + << "expected LLVM function call to produce 0 or 1 result"; + + if (getNumResults() && getResult().getType() != funcType.getReturnType()) + return emitOpError() << "result type mismatch: " << getResult().getType() + << " != " << funcType.getReturnType(); + + return success(); +} + +void CallOp::print(OpAsmPrinter &p) { + auto callee = getCallee(); + bool isDirect = callee.has_value(); + + // Print the direct callee if present as a function attribute, or an indirect + // callee (first operand) otherwise. + p << ' '; + if (isDirect) + p.printSymbolName(callee.value()); + else + p << getOperand(0); + + auto args = getOperands().drop_front(isDirect ? 0 : 1); + p << '(' << args << ')'; + p.printOptionalAttrDict(processFMFAttr((*this)->getAttrs()), {"callee"}); + + p << " : "; + if (!isDirect) + p << getOperand(0).getType() << ", "; + + // Reconstruct the function MLIR function type from operand and result types. + p.printFunctionalType(args.getTypes(), getResultTypes()); +} + +/// Parses the type of a call operation and resolves the operands if the parsing +/// succeeds. Returns failure otherwise. +static ParseResult parseCallTypeAndResolveOperands( + OpAsmParser &parser, OperationState &result, bool isDirect, + ArrayRef operands) { + SMLoc trailingTypesLoc = parser.getCurrentLocation(); + SmallVector types; + if (parser.parseColonTypeList(types)) + return failure(); + + if (isDirect && types.size() != 1) + return parser.emitError(trailingTypesLoc, + "expected direct call to have 1 trailing type"); + if (!isDirect && types.size() != 2) + return parser.emitError(trailingTypesLoc, + "expected indirect call to have 2 trailing types"); + + auto funcType = types.pop_back_val().dyn_cast(); + if (!funcType) + return parser.emitError(trailingTypesLoc, + "expected trailing function type"); + if (funcType.getNumResults() > 1) + return parser.emitError(trailingTypesLoc, + "expected function with 0 or 1 result"); + + // The head element of the types list matches the callee type for indirect + // calls, while the types list is emtpy for direct calls. Append the function + // input types to resolve the call operation operands. + llvm::append_range(types, funcType.getInputs()); + if (parser.resolveOperands(operands, types, parser.getNameLoc(), + result.operands)) + return failure(); + if (funcType.getNumResults() != 0 && + !funcType.getResult(0).isa()) + result.addTypes(funcType.getResults()); + + return success(); +} + +// ::= `llvm.call` (function-id | ssa-use)`(` ssa-use-list `)` +// attribute-dict? `:` (type `,`)? function-type +ParseResult CallOp::parse(OpAsmParser &parser, OperationState &result) { + SymbolRefAttr funcAttr; + SmallVector operands; + + // Parse an operand list that will, in practice, contain 0 or 1 operand. In + // case of an indirect call, there will be 1 operand before `(`. In case of a + // direct call, there will be no operands and the parser will stop at the + // function identifier without complaining. + if (parser.parseOperandList(operands)) + return failure(); + bool isDirect = operands.empty(); + + // Optionally parse a function identifier. + if (isDirect) + if (parser.parseAttribute(funcAttr, "callee", result.attributes)) + return failure(); + + // Parse the function arguments. + if (parser.parseOperandList(operands, OpAsmParser::Delimiter::Paren) || + parser.parseOptionalAttrDict(result.attributes)) + return failure(); + + // Parse the trailing type list and resolve the operands. + return parseCallTypeAndResolveOperands(parser, result, isDirect, operands); +} + ///===---------------------------------------------------------------------===// /// LLVM::InvokeOp ///===---------------------------------------------------------------------===// @@ -949,20 +1168,22 @@ p.printOptionalAttrDict((*this)->getAttrs(), {InvokeOp::getOperandSegmentSizeAttr(), "callee"}); + p << " : "; + if (!isDirect) + p << getOperand(0).getType() << ", "; p.printFunctionalType(llvm::drop_begin(getOperandTypes(), isDirect ? 0 : 1), getResultTypes()); } -/// ::= `llvm.invoke` (function-id | ssa-use) `(` ssa-use-list `)` -/// `to` bb-id (`[` ssa-use-and-type-list `]`)? -/// `unwind` bb-id (`[` ssa-use-and-type-list `]`)? -/// attribute-dict? `:` function-type +// ::= `llvm.invoke` (function-id | ssa-use) +// `(` ssa-use-list `)` +// `to` bb-id (`[` ssa-use-and-type-list `]`)? +// `unwind` bb-id (`[` ssa-use-and-type-list `]`)? +// attribute-dict? `:` (type `,`)? function-type ParseResult InvokeOp::parse(OpAsmParser &parser, OperationState &result) { SmallVector operands; - FunctionType funcType; SymbolRefAttr funcAttr; - SMLoc trailingTypeLoc; Block *normalDest, *unwindDest; SmallVector normalOperands, unwindOperands; Builder &builder = parser.getBuilder(); @@ -979,63 +1200,19 @@ if (isDirect && parser.parseAttribute(funcAttr, "callee", result.attributes)) return failure(); + // Parse the function arguments. if (parser.parseOperandList(operands, OpAsmParser::Delimiter::Paren) || parser.parseKeyword("to") || parser.parseSuccessorAndUseList(normalDest, normalOperands) || parser.parseKeyword("unwind") || parser.parseSuccessorAndUseList(unwindDest, unwindOperands) || - parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() || - parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(funcType)) + parser.parseOptionalAttrDict(result.attributes)) return failure(); - if (isDirect) { - // Make sure types match. - if (parser.resolveOperands(operands, funcType.getInputs(), - parser.getNameLoc(), result.operands)) - return failure(); - result.addTypes(funcType.getResults()); - } else { - // Construct the LLVM IR Dialect function type that the first operand - // should match. - if (funcType.getNumResults() > 1) - return parser.emitError(trailingTypeLoc, - "expected function with 0 or 1 result"); - - Type llvmResultType; - if (funcType.getNumResults() == 0) { - llvmResultType = LLVM::LLVMVoidType::get(builder.getContext()); - } else { - llvmResultType = funcType.getResult(0); - if (!isCompatibleType(llvmResultType)) - return parser.emitError(trailingTypeLoc, - "expected result to have LLVM type"); - } - - SmallVector argTypes; - argTypes.reserve(funcType.getNumInputs()); - for (Type ty : funcType.getInputs()) { - if (isCompatibleType(ty)) - argTypes.push_back(ty); - else - return parser.emitError(trailingTypeLoc, - "expected LLVM types as inputs"); - } - - auto llvmFuncType = LLVM::LLVMFunctionType::get(llvmResultType, argTypes); - auto wrappedFuncType = LLVM::LLVMPointerType::get(llvmFuncType); - - auto funcArguments = llvm::ArrayRef(operands).drop_front(); - - // Make sure that the first operand (indirect callee) matches the wrapped - // LLVM IR function type, and that the types of the other call operands - // match the types of the function arguments. - if (parser.resolveOperand(operands[0], wrappedFuncType, result.operands) || - parser.resolveOperands(funcArguments, funcType.getInputs(), - parser.getNameLoc(), result.operands)) - return failure(); + // Parse the trailing type list and resolve the function operands. + if (parseCallTypeAndResolveOperands(parser, result, isDirect, operands)) + return failure(); - result.addTypes(llvmResultType); - } result.addSuccessors({normalDest, unwindDest}); result.addOperands(normalOperands); result.addOperands(unwindOperands); @@ -1108,8 +1285,8 @@ p << ": " << getType(); } -/// ::= `llvm.landingpad` `cleanup`? -/// ((`catch` | `filter`) operand-type ssa-use)* attribute-dict? +// ::= `llvm.landingpad` `cleanup`? +// ((`catch` | `filter`) operand-type ssa-use)* attribute-dict? ParseResult LandingpadOp::parse(OpAsmParser &parser, OperationState &result) { // Check for cleanup if (succeeded(parser.parseOptionalKeyword("cleanup"))) @@ -1136,237 +1313,6 @@ return success(); } -//===----------------------------------------------------------------------===// -// CallOp -//===----------------------------------------------------------------------===// - -void CallOp::build(OpBuilder &builder, OperationState &state, TypeRange results, - StringRef callee, ValueRange args) { - build(builder, state, results, builder.getStringAttr(callee), args); -} - -void CallOp::build(OpBuilder &builder, OperationState &state, TypeRange results, - StringAttr callee, ValueRange args) { - build(builder, state, results, SymbolRefAttr::get(callee), args, nullptr, - nullptr); -} - -void CallOp::build(OpBuilder &builder, OperationState &state, TypeRange results, - FlatSymbolRefAttr callee, ValueRange args) { - build(builder, state, results, callee, args, nullptr, nullptr); -} - -void CallOp::build(OpBuilder &builder, OperationState &state, LLVMFuncOp func, - ValueRange args) { - SmallVector results; - Type resultType = func.getFunctionType().getReturnType(); - if (!resultType.isa()) - results.push_back(resultType); - build(builder, state, results, SymbolRefAttr::get(func), args, nullptr, - nullptr); -} - -CallInterfaceCallable CallOp::getCallableForCallee() { - // Direct call. - if (FlatSymbolRefAttr calleeAttr = getCalleeAttr()) - return calleeAttr; - // Indirect call, callee Value is the first operand. - return getOperand(0); -} - -Operation::operand_range CallOp::getArgOperands() { - return getOperands().drop_front(getCallee().has_value() ? 0 : 1); -} - -LogicalResult CallOp::verifySymbolUses(SymbolTableCollection &symbolTable) { - if (getNumResults() > 1) - return emitOpError("must have 0 or 1 result"); - - // Type for the callee, we'll get it differently depending if it is a direct - // or indirect call. - Type fnType; - - bool isIndirect = false; - - // If this is an indirect call, the callee attribute is missing. - FlatSymbolRefAttr calleeName = getCalleeAttr(); - if (!calleeName) { - isIndirect = true; - if (!getNumOperands()) - return emitOpError( - "must have either a `callee` attribute or at least an operand"); - auto ptrType = getOperand(0).getType().dyn_cast(); - if (!ptrType) - return emitOpError("indirect call expects a pointer as callee: ") - << ptrType; - - if (ptrType.isOpaque()) - return success(); - - fnType = ptrType.getElementType(); - } else { - Operation *callee = - symbolTable.lookupNearestSymbolFrom(*this, calleeName.getAttr()); - if (!callee) - return emitOpError() - << "'" << calleeName.getValue() - << "' does not reference a symbol in the current scope"; - auto fn = dyn_cast(callee); - if (!fn) - return emitOpError() << "'" << calleeName.getValue() - << "' does not reference a valid LLVM function"; - - fnType = fn.getFunctionType(); - } - - LLVMFunctionType funcType = fnType.dyn_cast(); - if (!funcType) - return emitOpError("callee does not have a functional type: ") << fnType; - - // Verify that the operand and result types match the callee. - - if (!funcType.isVarArg() && - funcType.getNumParams() != (getNumOperands() - isIndirect)) - return emitOpError() << "incorrect number of operands (" - << (getNumOperands() - isIndirect) - << ") for callee (expecting: " - << funcType.getNumParams() << ")"; - - if (funcType.getNumParams() > (getNumOperands() - isIndirect)) - return emitOpError() << "incorrect number of operands (" - << (getNumOperands() - isIndirect) - << ") for varargs callee (expecting at least: " - << funcType.getNumParams() << ")"; - - for (unsigned i = 0, e = funcType.getNumParams(); i != e; ++i) - if (getOperand(i + isIndirect).getType() != funcType.getParamType(i)) - return emitOpError() << "operand type mismatch for operand " << i << ": " - << getOperand(i + isIndirect).getType() - << " != " << funcType.getParamType(i); - - if (getNumResults() == 0 && - !funcType.getReturnType().isa()) - return emitOpError() << "expected function call to produce a value"; - - if (getNumResults() != 0 && - funcType.getReturnType().isa()) - return emitOpError() - << "calling function with void result must not produce values"; - - if (getNumResults() > 1) - return emitOpError() - << "expected LLVM function call to produce 0 or 1 result"; - - if (getNumResults() && getResult().getType() != funcType.getReturnType()) - return emitOpError() << "result type mismatch: " << getResult().getType() - << " != " << funcType.getReturnType(); - - return success(); -} - -void CallOp::print(OpAsmPrinter &p) { - auto callee = getCallee(); - bool isDirect = callee.has_value(); - - // Print the direct callee if present as a function attribute, or an indirect - // callee (first operand) otherwise. - p << ' '; - if (isDirect) - p.printSymbolName(callee.value()); - else - p << getOperand(0); - - auto args = getOperands().drop_front(isDirect ? 0 : 1); - p << '(' << args << ')'; - p.printOptionalAttrDict(processFMFAttr((*this)->getAttrs()), {"callee"}); - - // Reconstruct the function MLIR function type from operand and result types. - p << " : "; - p.printFunctionalType(args.getTypes(), getResultTypes()); -} - -// ::= `llvm.call` (function-id | ssa-use) `(` ssa-use-list `)` -// attribute-dict? `:` function-type -ParseResult CallOp::parse(OpAsmParser &parser, OperationState &result) { - SmallVector operands; - Type type; - SymbolRefAttr funcAttr; - SMLoc trailingTypeLoc; - - // Parse an operand list that will, in practice, contain 0 or 1 operand. In - // case of an indirect call, there will be 1 operand before `(`. In case of a - // direct call, there will be no operands and the parser will stop at the - // function identifier without complaining. - if (parser.parseOperandList(operands)) - return failure(); - bool isDirect = operands.empty(); - - // Optionally parse a function identifier. - if (isDirect) - if (parser.parseAttribute(funcAttr, "callee", result.attributes)) - return failure(); - - if (parser.parseOperandList(operands, OpAsmParser::Delimiter::Paren) || - parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() || - parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(type)) - return failure(); - - auto funcType = type.dyn_cast(); - if (!funcType) - return parser.emitError(trailingTypeLoc, "expected function type"); - if (funcType.getNumResults() > 1) - return parser.emitError(trailingTypeLoc, - "expected function with 0 or 1 result"); - if (isDirect) { - // Make sure types match. - if (parser.resolveOperands(operands, funcType.getInputs(), - parser.getNameLoc(), result.operands)) - return failure(); - if (funcType.getNumResults() != 0 && - !funcType.getResult(0).isa()) - result.addTypes(funcType.getResults()); - } else { - Builder &builder = parser.getBuilder(); - Type llvmResultType; - if (funcType.getNumResults() == 0) { - llvmResultType = LLVM::LLVMVoidType::get(builder.getContext()); - } else { - llvmResultType = funcType.getResult(0); - if (!isCompatibleType(llvmResultType)) - return parser.emitError(trailingTypeLoc, - "expected result to have LLVM type"); - } - - SmallVector argTypes; - argTypes.reserve(funcType.getNumInputs()); - for (int i = 0, e = funcType.getNumInputs(); i < e; ++i) { - auto argType = funcType.getInput(i); - if (!isCompatibleType(argType)) - return parser.emitError(trailingTypeLoc, - "expected LLVM types as inputs"); - argTypes.push_back(argType); - } - auto llvmFuncType = LLVM::LLVMFunctionType::get(llvmResultType, argTypes); - auto wrappedFuncType = LLVM::LLVMPointerType::get(llvmFuncType); - - auto funcArguments = - ArrayRef(operands).drop_front(); - - // Make sure that the first operand (indirect callee) matches the wrapped - // LLVM IR function type, and that the types of the other call operands - // match the types of the function arguments. - if (parser.resolveOperand(operands[0], wrappedFuncType, result.operands) || - parser.resolveOperands(funcArguments, funcType.getInputs(), - parser.getNameLoc(), result.operands)) - return failure(); - - if (!llvmResultType.isa()) - result.addTypes(llvmResultType); - } - - return success(); -} - //===----------------------------------------------------------------------===// // ExtractValueOp //===----------------------------------------------------------------------===// @@ -2262,32 +2208,6 @@ // Utility functions for parsing atomic ops //===----------------------------------------------------------------------===// -// Helper function to parse a keyword into the specified attribute named by -// `attrName`. The keyword must match one of the string values defined by the -// AtomicBinOp enum. The resulting I64 attribute is added to the `result` -// state. -static ParseResult parseAtomicBinOp(OpAsmParser &parser, OperationState &result, - StringRef attrName) { - SMLoc loc; - StringRef keyword; - if (parser.getCurrentLocation(&loc) || parser.parseKeyword(&keyword)) - return failure(); - - // Replace the keyword `keyword` with an integer attribute. - auto kind = symbolizeAtomicBinOp(keyword); - if (!kind) { - return parser.emitError(loc) - << "'" << keyword << "' is an incorrect value of the '" << attrName - << "' attribute"; - } - - auto value = static_cast(*kind); - auto attr = parser.getBuilder().getI64IntegerAttr(value); - result.addAttribute(attrName, attr); - - return success(); -} - // Helper function to parse a keyword into the specified attribute named by // `attrName`. The keyword must match one of the string values defined by the // AtomicOrdering enum. The resulting I64 attribute is added to the `result` @@ -2316,45 +2236,15 @@ } //===----------------------------------------------------------------------===// -// Printer, parser and verifier for LLVM::AtomicRMWOp. +// Verifier for LLVM::AtomicRMWOp. //===----------------------------------------------------------------------===// -void AtomicRMWOp::print(OpAsmPrinter &p) { - p << ' ' << stringifyAtomicBinOp(getBinOp()) << ' ' << getPtr() << ", " - << getVal() << ' ' << stringifyAtomicOrdering(getOrdering()) << ' '; - p.printOptionalAttrDict((*this)->getAttrs(), {"bin_op", "ordering"}); - p << " : " << getRes().getType(); -} - -// ::= `llvm.atomicrmw` keyword ssa-use `,` ssa-use keyword -// attribute-dict? `:` type -ParseResult AtomicRMWOp::parse(OpAsmParser &parser, OperationState &result) { - Type type; - OpAsmParser::UnresolvedOperand ptr, val; - if (parseAtomicBinOp(parser, result, "bin_op") || parser.parseOperand(ptr) || - parser.parseComma() || parser.parseOperand(val) || - parseAtomicOrdering(parser, result, "ordering") || - parser.parseOptionalAttrDict(result.attributes) || - parser.parseColonType(type) || - parser.resolveOperand(ptr, LLVM::LLVMPointerType::get(type), - result.operands) || - parser.resolveOperand(val, type, result.operands)) - return failure(); - - result.addTypes(type); - return success(); -} - LogicalResult AtomicRMWOp::verify() { auto ptrType = getPtr().getType().cast(); auto valType = getVal().getType(); if (!ptrType.isOpaque() && valType != ptrType.getElementType()) return emitOpError("expected LLVM IR element type for operand #0 to " "match type for operand #1"); - auto resType = getRes().getType(); - if (resType != valType) - return emitOpError( - "expected LLVM IR result type to match type for operand #1"); if (getBinOp() == AtomicBinOp::fadd || getBinOp() == AtomicBinOp::fsub) { if (!mlir::LLVM::isCompatibleFloatingPointType(valType)) return emitOpError("expected LLVM IR floating point type"); @@ -2384,55 +2274,21 @@ } //===----------------------------------------------------------------------===// -// Printer, parser and verifier for LLVM::AtomicCmpXchgOp. +// Verifier for LLVM::AtomicCmpXchgOp. //===----------------------------------------------------------------------===// -void AtomicCmpXchgOp::print(OpAsmPrinter &p) { - p << ' ' << getPtr() << ", " << getCmp() << ", " << getVal() << ' ' - << stringifyAtomicOrdering(getSuccessOrdering()) << ' ' - << stringifyAtomicOrdering(getFailureOrdering()); - p.printOptionalAttrDict((*this)->getAttrs(), - {"success_ordering", "failure_ordering"}); - p << " : " << getVal().getType(); -} - -// ::= `llvm.cmpxchg` ssa-use `,` ssa-use `,` ssa-use -// keyword keyword attribute-dict? `:` type -ParseResult AtomicCmpXchgOp::parse(OpAsmParser &parser, - OperationState &result) { - auto &builder = parser.getBuilder(); - Type type; - OpAsmParser::UnresolvedOperand ptr, cmp, val; - if (parser.parseOperand(ptr) || parser.parseComma() || - parser.parseOperand(cmp) || parser.parseComma() || - parser.parseOperand(val) || - parseAtomicOrdering(parser, result, "success_ordering") || - parseAtomicOrdering(parser, result, "failure_ordering") || - parser.parseOptionalAttrDict(result.attributes) || - parser.parseColonType(type) || - parser.resolveOperand(ptr, LLVM::LLVMPointerType::get(type), - result.operands) || - parser.resolveOperand(cmp, type, result.operands) || - parser.resolveOperand(val, type, result.operands)) - return failure(); - - auto boolType = IntegerType::get(builder.getContext(), 1); - auto resultType = - LLVMStructType::getLiteral(builder.getContext(), {type, boolType}); - result.addTypes(resultType); - - return success(); +/// Returns an LLVM struct type that contains a value type and a boolean type. +static LLVMStructType getValAndBoolStructType(Type valType) { + auto boolType = IntegerType::get(valType.getContext(), 1); + return LLVMStructType::getLiteral(valType.getContext(), {valType, boolType}); } LogicalResult AtomicCmpXchgOp::verify() { auto ptrType = getPtr().getType().cast(); if (!ptrType) return emitOpError("expected LLVM IR pointer type for operand #0"); - auto cmpType = getCmp().getType(); auto valType = getVal().getType(); - if (cmpType != valType) - return emitOpError("expected both value operands to have the same type"); - if (!ptrType.isOpaque() && cmpType != ptrType.getElementType()) + if (!ptrType.isOpaque() && valType != ptrType.getElementType()) return emitOpError("expected LLVM IR element type for operand #0 to " "match type for all other operands"); auto intType = valType.dyn_cast(); diff --git a/mlir/test/Conversion/FuncToLLVM/convert-funcs.mlir b/mlir/test/Conversion/FuncToLLVM/convert-funcs.mlir --- a/mlir/test/Conversion/FuncToLLVM/convert-funcs.mlir +++ b/mlir/test/Conversion/FuncToLLVM/convert-funcs.mlir @@ -52,7 +52,7 @@ func.func @indirect_const_call(%arg0: i32) { // CHECK-NEXT: %[[ADDR:.*]] = llvm.mlir.addressof @body : !llvm.ptr> %0 = constant @body : (i32) -> () -// CHECK-NEXT: llvm.call %[[ADDR]](%[[ARG0:.*]]) : (i32) -> () +// CHECK-NEXT: llvm.call %[[ADDR]](%[[ARG0:.*]]) : !llvm.ptr>, (i32) -> () call_indirect %0(%arg0) : (i32) -> () // CHECK-NEXT: llvm.return return @@ -60,7 +60,7 @@ // CHECK-LABEL: llvm.func @indirect_call(%arg0: !llvm.ptr>, %arg1: f32) -> i32 { func.func @indirect_call(%arg0: (f32) -> i32, %arg1: f32) -> i32 { -// CHECK-NEXT: %0 = llvm.call %arg0(%arg1) : (f32) -> i32 +// CHECK-NEXT: %0 = llvm.call %arg0(%arg1) : !llvm.ptr>, (f32) -> i32 %0 = call_indirect %arg0(%arg1) : (f32) -> i32 // CHECK-NEXT: llvm.return %0 : i32 return %0 : i32 diff --git a/mlir/test/Conversion/MemRefToLLVM/memref-to-llvm.mlir b/mlir/test/Conversion/MemRefToLLVM/memref-to-llvm.mlir --- a/mlir/test/Conversion/MemRefToLLVM/memref-to-llvm.mlir +++ b/mlir/test/Conversion/MemRefToLLVM/memref-to-llvm.mlir @@ -370,7 +370,7 @@ // CHECK-NEXT: llvm.br ^bb1([[init]] : i32) // CHECK-NEXT: ^bb1([[loaded:%.*]]: i32): // CHECK-NEXT: [[pair:%.*]] = llvm.cmpxchg %{{.*}}, [[loaded]], [[loaded]] - // CHECK-SAME: acq_rel monotonic : i32 + // CHECK-SAME: acq_rel monotonic : !llvm.ptr, i32 // CHECK-NEXT: [[new:%.*]] = llvm.extractvalue [[pair]][0] // CHECK-NEXT: [[ok:%.*]] = llvm.extractvalue [[pair]][1] // CHECK-NEXT: llvm.cond_br [[ok]], ^bb2, ^bb1([[new]] : i32) diff --git a/mlir/test/Dialect/LLVMIR/invalid.mlir b/mlir/test/Dialect/LLVMIR/invalid.mlir --- a/mlir/test/Dialect/LLVMIR/invalid.mlir +++ b/mlir/test/Dialect/LLVMIR/invalid.mlir @@ -174,25 +174,43 @@ // ----- -func.func @call_non_function_type(%callee : !llvm.func, %arg : i8) { - // expected-error@+1 {{expected function type}} - llvm.call %callee(%arg) : !llvm.func +func.func @invalid_call() { + // expected-error@+1 {{'llvm.call' op must have either a `callee` attribute or at least an operand}} + "llvm.call"() : () -> () llvm.return } // ----- -func.func @invalid_call() { - // expected-error@+1 {{'llvm.call' op must have either a `callee` attribute or at least an operand}} - "llvm.call"() : () -> () +func.func @call_missing_ptr_type(%callee : !llvm.func, %arg : i8) { + // expected-error@+1 {{expected indirect call to have 2 trailing types}} + llvm.call %callee(%arg) : (i8) -> (i8) + llvm.return +} + +// ----- + +func.func private @standard_func_callee() + +func.func @call_missing_ptr_type(%arg : i8) { + // expected-error@+1 {{expected direct call to have 1 trailing type}} + llvm.call @standard_func_callee(%arg) : !llvm.ptr, (i8) -> (i8) + llvm.return +} + +// ----- + +func.func @call_non_pointer_type(%callee : !llvm.func, %arg : i8) { + // expected-error@+1 {{indirect call expects a pointer as callee: '!llvm.func'}} + llvm.call %callee(%arg) : !llvm.func, (i8) -> (i8) llvm.return } // ----- -func.func @call_non_function_type(%callee : !llvm.func, %arg : i8) { - // expected-error@+1 {{expected function type}} - llvm.call %callee(%arg) : !llvm.func +func.func @call_non_function_type(%callee : !llvm.ptr, %arg : i8) { + // expected-error@+1 {{expected trailing function type}} + llvm.call %callee(%arg) : !llvm.ptr, !llvm.func llvm.return } @@ -216,7 +234,7 @@ // ----- -func.func @call_non_llvm_indirect(%arg0 : tensor<*xi32>) { +func.func @call_non_llvm_arg(%arg0 : tensor<*xi32>) { // expected-error@+1 {{'llvm.call' op operand #0 must be LLVM dialect-compatible type}} "llvm.call"(%arg0) : (tensor<*xi32>) -> () llvm.return @@ -224,6 +242,14 @@ // ----- +func.func @call_non_llvm_res(%callee : !llvm.ptr) { + // expected-error@+1 {{'llvm.call' op result #0 must be LLVM dialect-compatible type}} + llvm.call %callee() : !llvm.ptr, () -> (tensor<*xi32>) + llvm.return +} + +// ----- + llvm.func @callee_func(i8) -> () func.func @callee_arg_mismatch(%arg0 : i32) { @@ -260,25 +286,9 @@ // ----- -func.func @call_too_many_results(%callee : () -> (i32,i32)) { +func.func @call_too_many_results(%callee : !llvm.ptr) { // expected-error@+1 {{expected function with 0 or 1 result}} - llvm.call %callee() : () -> (i32, i32) - llvm.return -} - -// ----- - -func.func @call_non_llvm_result(%callee : () -> (tensor<*xi32>)) { - // expected-error@+1 {{expected result to have LLVM type}} - llvm.call %callee() : () -> (tensor<*xi32>) - llvm.return -} - -// ----- - -func.func @call_non_llvm_input(%callee : (tensor<*xi32>) -> (), %arg : tensor<*xi32>) { - // expected-error@+1 {{expected LLVM types as inputs}} - llvm.call %callee(%arg) : (tensor<*xi32>) -> () + llvm.call %callee() : !llvm.ptr, () -> (i32, i32) llvm.return } @@ -577,14 +587,14 @@ func.func @atomicrmw_mismatched_operands(%f32_ptr : !llvm.ptr, %i32 : i32) { // expected-error@+1 {{expected LLVM IR element type for operand #0 to match type for operand #1}} - %0 = "llvm.atomicrmw"(%f32_ptr, %i32) {bin_op=11, ordering=1} : (!llvm.ptr, i32) -> f32 + %0 = "llvm.atomicrmw"(%f32_ptr, %i32) {bin_op=11, ordering=1} : (!llvm.ptr, i32) -> i32 llvm.return } // ----- func.func @atomicrmw_mismatched_operands(%f32_ptr : !llvm.ptr, %f32 : f32) { - // expected-error@+1 {{expected LLVM IR result type to match type for operand #1}} + // expected-error@+1 {{op failed to verify that result #0 and operand #1 have the same type}} %0 = "llvm.atomicrmw"(%f32_ptr, %f32) {bin_op=11, ordering=1} : (!llvm.ptr, f32) -> i32 llvm.return } @@ -593,7 +603,7 @@ func.func @atomicrmw_expected_float(%i32_ptr : !llvm.ptr, %i32 : i32) { // expected-error@+1 {{expected LLVM IR floating point type}} - %0 = llvm.atomicrmw fadd %i32_ptr, %i32 unordered : i32 + %0 = llvm.atomicrmw fadd %i32_ptr, %i32 unordered : !llvm.ptr, i32 llvm.return } @@ -601,7 +611,7 @@ func.func @atomicrmw_unexpected_xchg_type(%i1_ptr : !llvm.ptr, %i1 : i1) { // expected-error@+1 {{unexpected LLVM IR type for 'xchg' bin_op}} - %0 = llvm.atomicrmw xchg %i1_ptr, %i1 unordered : i1 + %0 = llvm.atomicrmw xchg %i1_ptr, %i1 unordered : !llvm.ptr, i1 llvm.return } @@ -609,7 +619,7 @@ func.func @atomicrmw_expected_int(%f32_ptr : !llvm.ptr, %f32 : f32) { // expected-error@+1 {{expected LLVM IR integer type}} - %0 = llvm.atomicrmw max %f32_ptr, %f32 unordered : f32 + %0 = llvm.atomicrmw max %f32_ptr, %f32 unordered : !llvm.ptr, f32 llvm.return } @@ -632,15 +642,24 @@ // ----- func.func @cmpxchg_mismatched_value_operands(%ptr : !llvm.ptr, %i32 : i32, %i64 : i64) { - // expected-error@+1 {{expected both value operands to have the same type}} + // expected-error@+1 {{op failed to verify that operand #1 and operand #2 have the same type}} %0 = "llvm.cmpxchg"(%ptr, %i32, %i64) {success_ordering=2,failure_ordering=2} : (!llvm.ptr, i32, i64) -> !llvm.struct<(i32, i1)> llvm.return } + +// ----- + +func.func @cmpxchg_mismatched_result(%ptr : !llvm.ptr, %i64 : i64) { + // expected-error@+1 {{op failed to verify that result #0 has an LLVM struct type that contains an operand #2 and a bool element type}} + %0 = "llvm.cmpxchg"(%ptr, %i64, %i64) {success_ordering=2,failure_ordering=2} : (!llvm.ptr, i64, i64) -> !llvm.struct<(i64, i64)> + llvm.return +} + // ----- func.func @cmpxchg_unexpected_type(%i1_ptr : !llvm.ptr, %i1 : i1) { // expected-error@+1 {{unexpected LLVM IR type}} - %0 = llvm.cmpxchg %i1_ptr, %i1, %i1 monotonic monotonic : i1 + %0 = llvm.cmpxchg %i1_ptr, %i1, %i1 monotonic monotonic : !llvm.ptr, i1 llvm.return } @@ -648,7 +667,7 @@ func.func @cmpxchg_at_least_monotonic_success(%i32_ptr : !llvm.ptr, %i32 : i32) { // expected-error@+1 {{ordering must be at least 'monotonic'}} - %0 = llvm.cmpxchg %i32_ptr, %i32, %i32 unordered monotonic : i32 + %0 = llvm.cmpxchg %i32_ptr, %i32, %i32 unordered monotonic : !llvm.ptr, i32 llvm.return } @@ -656,7 +675,7 @@ func.func @cmpxchg_at_least_monotonic_failure(%i32_ptr : !llvm.ptr, %i32 : i32) { // expected-error@+1 {{ordering must be at least 'monotonic'}} - %0 = llvm.cmpxchg %i32_ptr, %i32, %i32 monotonic unordered : i32 + %0 = llvm.cmpxchg %i32_ptr, %i32, %i32 monotonic unordered : !llvm.ptr, i32 llvm.return } @@ -664,7 +683,7 @@ func.func @cmpxchg_failure_release(%i32_ptr : !llvm.ptr, %i32 : i32) { // expected-error@+1 {{failure ordering cannot be 'release' or 'acq_rel'}} - %0 = llvm.cmpxchg %i32_ptr, %i32, %i32 acq_rel release : i32 + %0 = llvm.cmpxchg %i32_ptr, %i32, %i32 acq_rel release : !llvm.ptr, i32 llvm.return } @@ -672,7 +691,7 @@ func.func @cmpxchg_failure_acq_rel(%i32_ptr : !llvm.ptr, %i32 : i32) { // expected-error@+1 {{failure ordering cannot be 'release' or 'acq_rel'}} - %0 = llvm.cmpxchg %i32_ptr, %i32, %i32 acq_rel acq_rel : i32 + %0 = llvm.cmpxchg %i32_ptr, %i32, %i32 acq_rel acq_rel : !llvm.ptr, i32 llvm.return } diff --git a/mlir/test/Dialect/LLVMIR/roundtrip.mlir b/mlir/test/Dialect/LLVMIR/roundtrip.mlir --- a/mlir/test/Dialect/LLVMIR/roundtrip.mlir +++ b/mlir/test/Dialect/LLVMIR/roundtrip.mlir @@ -65,14 +65,13 @@ // CHECK: %[[STRUCT:.*]] = llvm.call @foo(%[[I32]]) : (i32) -> !llvm.struct<(i32, f64, i32)> // CHECK: %[[VALUE:.*]] = llvm.extractvalue %[[STRUCT]][0] : !llvm.struct<(i32, f64, i32)> // CHECK: %[[NEW_STRUCT:.*]] = llvm.insertvalue %[[VALUE]], %[[STRUCT]][2] : !llvm.struct<(i32, f64, i32)> -// CHECK: %[[FUNC:.*]] = llvm.mlir.addressof @foo : !llvm.ptr (i32)>> -// CHECK: %{{.*}} = llvm.call %[[FUNC]](%[[I32]]) : (i32) -> !llvm.struct<(i32, f64, i32)> +// CHECK: %[[FUNC:.*]] = llvm.mlir.addressof @foo : !llvm.ptr +// CHECK: %{{.*}} = llvm.call %[[FUNC]](%[[I32]]) : !llvm.ptr, (i32) -> !llvm.struct<(i32, f64, i32)> %17 = llvm.call @foo(%arg0) : (i32) -> !llvm.struct<(i32, f64, i32)> %18 = llvm.extractvalue %17[0] : !llvm.struct<(i32, f64, i32)> %19 = llvm.insertvalue %18, %17[2] : !llvm.struct<(i32, f64, i32)> - %20 = llvm.mlir.addressof @foo : !llvm.ptr (i32)>> - %21 = llvm.call %20(%arg0) : (i32) -> !llvm.struct<(i32, f64, i32)> - + %20 = llvm.mlir.addressof @foo : !llvm.ptr + %21 = llvm.call %20(%arg0) : !llvm.ptr, (i32) -> !llvm.struct<(i32, f64, i32)> // Terminator operations and their successors. // @@ -341,16 +340,16 @@ } // CHECK-LABEL: @atomicrmw -func.func @atomicrmw(%ptr : !llvm.ptr, %val : f32) { - // CHECK: llvm.atomicrmw fadd %{{.*}}, %{{.*}} monotonic : f32 - %0 = llvm.atomicrmw fadd %ptr, %val monotonic : f32 +func.func @atomicrmw(%ptr : !llvm.ptr, %val : f32) { + // CHECK: llvm.atomicrmw fadd %{{.*}}, %{{.*}} monotonic : !llvm.ptr, f32 + %0 = llvm.atomicrmw fadd %ptr, %val monotonic : !llvm.ptr, f32 llvm.return } // CHECK-LABEL: @cmpxchg -func.func @cmpxchg(%ptr : !llvm.ptr, %cmp : i32, %new : i32) { - // CHECK: llvm.cmpxchg %{{.*}}, %{{.*}}, %{{.*}} acq_rel monotonic : i32 - %0 = llvm.cmpxchg %ptr, %cmp, %new acq_rel monotonic : i32 +func.func @cmpxchg(%ptr : !llvm.ptr, %cmp : i32, %new : i32) { + // CHECK: llvm.cmpxchg %{{.*}}, %{{.*}}, %{{.*}} acq_rel monotonic : !llvm.ptr, i32 + %0 = llvm.cmpxchg %ptr, %cmp, %new acq_rel monotonic : !llvm.ptr, i32 llvm.return } @@ -401,8 +400,15 @@ llvm.invoke @bar(%8, %6, %4) to ^bb2 unwind ^bb1 : (!llvm.ptr, !llvm.ptr, !llvm.ptr) -> () // CHECK: ^[[BB4:.*]]: -// CHECK: llvm.return %[[a0]] : i32 +// CHECK: %[[FUNC:.*]] = llvm.mlir.addressof @foo : !llvm.ptr +// CHECK: %{{.*}} = llvm.invoke %[[FUNC]]{{.*}}: !llvm.ptr, ^bb4: + %12 = llvm.mlir.addressof @foo : !llvm.ptr + %13 = llvm.invoke %12(%7) to ^bb2 unwind ^bb1 : !llvm.ptr, (i32) -> !llvm.struct<(i32, f64, i32)> + +// CHECK: ^[[BB5:.*]]: +// CHECK: llvm.return %[[a0]] : i32 +^bb5: llvm.return %0 : i32 } diff --git a/mlir/test/Dialect/OpenMP/invalid.mlir b/mlir/test/Dialect/OpenMP/invalid.mlir --- a/mlir/test/Dialect/OpenMP/invalid.mlir +++ b/mlir/test/Dialect/OpenMP/invalid.mlir @@ -524,7 +524,7 @@ atomic { ^bb2(%arg2: !llvm.ptr, %arg3: !llvm.ptr): %2 = llvm.load %arg3 : !llvm.ptr - llvm.atomicrmw fadd %arg2, %2 monotonic : f32 + llvm.atomicrmw fadd %arg2, %2 monotonic : !llvm.ptr, f32 omp.yield } @@ -1288,7 +1288,7 @@ atomic { ^bb2(%arg2: !llvm.ptr, %arg3: !llvm.ptr): %2 = llvm.load %arg3 : !llvm.ptr - llvm.atomicrmw add %arg2, %2 monotonic : i32 + llvm.atomicrmw add %arg2, %2 monotonic : !llvm.ptr, i32 omp.yield } diff --git a/mlir/test/Dialect/OpenMP/ops.mlir b/mlir/test/Dialect/OpenMP/ops.mlir --- a/mlir/test/Dialect/OpenMP/ops.mlir +++ b/mlir/test/Dialect/OpenMP/ops.mlir @@ -556,7 +556,7 @@ atomic { ^bb2(%arg2: !llvm.ptr, %arg3: !llvm.ptr): %2 = llvm.load %arg3 : !llvm.ptr - llvm.atomicrmw fadd %arg2, %2 monotonic : f32 + llvm.atomicrmw fadd %arg2, %2 monotonic : !llvm.ptr, f32 omp.yield } diff --git a/mlir/test/Target/LLVMIR/Import/constant.ll b/mlir/test/Target/LLVMIR/Import/constant.ll --- a/mlir/test/Target/LLVMIR/Import/constant.ll +++ b/mlir/test/Target/LLVMIR/Import/constant.ll @@ -131,7 +131,7 @@ store ptr @callee, ptr %1 ; CHECK: %[[INDIR:.*]] = llvm.load %[[PTR]] : !llvm.ptr -> !llvm.ptr %2 = load ptr, ptr %1 - ; CHECK: llvm.call %[[INDIR]]() + ; CHECK: llvm.call %[[INDIR]]() : !llvm.ptr, () -> i32 %3 = call i32 %2() ret i32 %3 } @@ -149,7 +149,7 @@ store ptr @callee, ptr %1 ; CHECK: %[[INDIR:.*]] = llvm.load %[[PTR]] : !llvm.ptr -> !llvm.ptr %2 = load ptr, ptr %1 - ; CHECK: llvm.call %[[INDIR]]() + ; CHECK: llvm.call %[[INDIR]]() : !llvm.ptr, () -> i32 %3 = call i32 %2() ret i32 %3 } diff --git a/mlir/test/Target/LLVMIR/Import/instructions.ll b/mlir/test/Target/LLVMIR/Import/instructions.ll --- a/mlir/test/Target/LLVMIR/Import/instructions.ll +++ b/mlir/test/Target/LLVMIR/Import/instructions.ll @@ -367,31 +367,31 @@ ; CHECK-SAME: %[[PTR2:[a-zA-Z0-9]+]] ; CHECK-SAME: %[[VAL2:[a-zA-Z0-9]+]] define void @atomic_rmw(ptr %ptr1, i32 %val1, ptr %ptr2, float %val2) { - ; CHECK: llvm.atomicrmw xchg %[[PTR1]], %[[VAL1]] acquire : i32 + ; CHECK: llvm.atomicrmw xchg %[[PTR1]], %[[VAL1]] acquire %1 = atomicrmw xchg ptr %ptr1, i32 %val1 acquire - ; CHECK: llvm.atomicrmw add %[[PTR1]], %[[VAL1]] release : i32 + ; CHECK: llvm.atomicrmw add %[[PTR1]], %[[VAL1]] release %2 = atomicrmw add ptr %ptr1, i32 %val1 release - ; CHECK: llvm.atomicrmw sub %[[PTR1]], %[[VAL1]] acq_rel : i32 + ; CHECK: llvm.atomicrmw sub %[[PTR1]], %[[VAL1]] acq_rel %3 = atomicrmw sub ptr %ptr1, i32 %val1 acq_rel - ; CHECK: llvm.atomicrmw _and %[[PTR1]], %[[VAL1]] seq_cst : i32 + ; CHECK: llvm.atomicrmw _and %[[PTR1]], %[[VAL1]] seq_cst %4 = atomicrmw and ptr %ptr1, i32 %val1 seq_cst - ; CHECK: llvm.atomicrmw nand %[[PTR1]], %[[VAL1]] acquire : i32 + ; CHECK: llvm.atomicrmw nand %[[PTR1]], %[[VAL1]] acquire %5 = atomicrmw nand ptr %ptr1, i32 %val1 acquire - ; CHECK: llvm.atomicrmw _or %[[PTR1]], %[[VAL1]] acquire : i32 + ; CHECK: llvm.atomicrmw _or %[[PTR1]], %[[VAL1]] acquire %6 = atomicrmw or ptr %ptr1, i32 %val1 acquire - ; CHECK: llvm.atomicrmw _xor %[[PTR1]], %[[VAL1]] acquire : i32 + ; CHECK: llvm.atomicrmw _xor %[[PTR1]], %[[VAL1]] acquire %7 = atomicrmw xor ptr %ptr1, i32 %val1 acquire - ; CHECK: llvm.atomicrmw max %[[PTR1]], %[[VAL1]] acquire : i32 + ; CHECK: llvm.atomicrmw max %[[PTR1]], %[[VAL1]] acquire %8 = atomicrmw max ptr %ptr1, i32 %val1 acquire - ; CHECK: llvm.atomicrmw min %[[PTR1]], %[[VAL1]] acquire : i32 + ; CHECK: llvm.atomicrmw min %[[PTR1]], %[[VAL1]] acquire %9 = atomicrmw min ptr %ptr1, i32 %val1 acquire - ; CHECK: llvm.atomicrmw umax %[[PTR1]], %[[VAL1]] acquire : i32 + ; CHECK: llvm.atomicrmw umax %[[PTR1]], %[[VAL1]] acquire %10 = atomicrmw umax ptr %ptr1, i32 %val1 acquire - ; CHECK: llvm.atomicrmw umin %[[PTR1]], %[[VAL1]] acquire : i32 + ; CHECK: llvm.atomicrmw umin %[[PTR1]], %[[VAL1]] acquire %11 = atomicrmw umin ptr %ptr1, i32 %val1 acquire - ; CHECK: llvm.atomicrmw fadd %[[PTR2]], %[[VAL2]] acquire : f32 + ; CHECK: llvm.atomicrmw fadd %[[PTR2]], %[[VAL2]] acquire %12 = atomicrmw fadd ptr %ptr2, float %val2 acquire - ; CHECK: llvm.atomicrmw fsub %[[PTR2]], %[[VAL2]] acquire : f32 + ; CHECK: llvm.atomicrmw fsub %[[PTR2]], %[[VAL2]] acquire %13 = atomicrmw fsub ptr %ptr2, float %val2 acquire ret void } @@ -403,9 +403,9 @@ ; CHECK-SAME: %[[VAL1:[a-zA-Z0-9]+]] ; CHECK-SAME: %[[VAL2:[a-zA-Z0-9]+]] define void @atomic_cmpxchg(ptr %ptr1, i32 %val1, i32 %val2) { - ; CHECK: llvm.cmpxchg %[[PTR1]], %[[VAL1]], %[[VAL2]] seq_cst seq_cst : i32 + ; CHECK: llvm.cmpxchg %[[PTR1]], %[[VAL1]], %[[VAL2]] seq_cst seq_cst %1 = cmpxchg ptr %ptr1, i32 %val1, i32 %val2 seq_cst seq_cst - ; CHECK: llvm.cmpxchg %[[PTR1]], %[[VAL1]], %[[VAL2]] monotonic seq_cst : i32 + ; CHECK: llvm.cmpxchg %[[PTR1]], %[[VAL1]], %[[VAL2]] monotonic seq_cst %2 = cmpxchg ptr %ptr1, i32 %val1, i32 %val2 monotonic seq_cst ret void } @@ -429,7 +429,7 @@ ; CHECK-SAME: %[[PTR:[a-zA-Z0-9]+]] define void @call_fn_ptr(ptr %fn) { ; CHECK: %[[C0:[0-9]+]] = llvm.mlir.constant(0 : i16) : i16 - ; CHECK: llvm.call %[[PTR]](%[[C0]]) + ; CHECK: llvm.call %[[PTR]](%[[C0]]) : !llvm.ptr, (i16) -> () call void %fn(i16 0) ret void } diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir --- a/mlir/test/Target/LLVMIR/llvmir.mlir +++ b/mlir/test/Target/LLVMIR/llvmir.mlir @@ -1009,7 +1009,7 @@ llvm.func @indirect_const_call(%arg0: i64) { // CHECK-NEXT: call void @body(i64 %0) %0 = llvm.mlir.addressof @body : !llvm.ptr> - llvm.call %0(%arg0) : (i64) -> () + llvm.call %0(%arg0) : !llvm.ptr>, (i64) -> () // CHECK-NEXT: ret void llvm.return } @@ -1017,7 +1017,7 @@ // CHECK-LABEL: define i32 @indirect_call(ptr {{%.*}}, float {{%.*}}) llvm.func @indirect_call(%arg0: !llvm.ptr>, %arg1: f32) -> i32 { // CHECK-NEXT: %3 = call i32 %0(float %1) - %0 = llvm.call %arg0(%arg1) : (f32) -> i32 + %0 = llvm.call %arg0(%arg1) : !llvm.ptr>, (f32) -> i32 // CHECK-NEXT: ret i32 %3 llvm.return %0 : i32 } @@ -1347,38 +1347,38 @@ %f32_ptr : !llvm.ptr, %f32 : f32, %i32_ptr : !llvm.ptr, %i32 : i32) { // CHECK: atomicrmw fadd ptr %{{.*}}, float %{{.*}} monotonic - %0 = llvm.atomicrmw fadd %f32_ptr, %f32 monotonic : f32 + %0 = llvm.atomicrmw fadd %f32_ptr, %f32 monotonic : !llvm.ptr, f32 // CHECK: atomicrmw fsub ptr %{{.*}}, float %{{.*}} monotonic - %1 = llvm.atomicrmw fsub %f32_ptr, %f32 monotonic : f32 + %1 = llvm.atomicrmw fsub %f32_ptr, %f32 monotonic : !llvm.ptr, f32 // CHECK: atomicrmw xchg ptr %{{.*}}, float %{{.*}} monotonic - %2 = llvm.atomicrmw xchg %f32_ptr, %f32 monotonic : f32 + %2 = llvm.atomicrmw xchg %f32_ptr, %f32 monotonic : !llvm.ptr, f32 // CHECK: atomicrmw add ptr %{{.*}}, i32 %{{.*}} acquire - %3 = llvm.atomicrmw add %i32_ptr, %i32 acquire : i32 + %3 = llvm.atomicrmw add %i32_ptr, %i32 acquire : !llvm.ptr, i32 // CHECK: atomicrmw sub ptr %{{.*}}, i32 %{{.*}} release - %4 = llvm.atomicrmw sub %i32_ptr, %i32 release : i32 + %4 = llvm.atomicrmw sub %i32_ptr, %i32 release : !llvm.ptr, i32 // CHECK: atomicrmw and ptr %{{.*}}, i32 %{{.*}} acq_rel - %5 = llvm.atomicrmw _and %i32_ptr, %i32 acq_rel : i32 + %5 = llvm.atomicrmw _and %i32_ptr, %i32 acq_rel : !llvm.ptr, i32 // CHECK: atomicrmw nand ptr %{{.*}}, i32 %{{.*}} seq_cst - %6 = llvm.atomicrmw nand %i32_ptr, %i32 seq_cst : i32 + %6 = llvm.atomicrmw nand %i32_ptr, %i32 seq_cst : !llvm.ptr, i32 // CHECK: atomicrmw or ptr %{{.*}}, i32 %{{.*}} monotonic - %7 = llvm.atomicrmw _or %i32_ptr, %i32 monotonic : i32 + %7 = llvm.atomicrmw _or %i32_ptr, %i32 monotonic : !llvm.ptr, i32 // CHECK: atomicrmw xor ptr %{{.*}}, i32 %{{.*}} monotonic - %8 = llvm.atomicrmw _xor %i32_ptr, %i32 monotonic : i32 + %8 = llvm.atomicrmw _xor %i32_ptr, %i32 monotonic : !llvm.ptr, i32 // CHECK: atomicrmw max ptr %{{.*}}, i32 %{{.*}} monotonic - %9 = llvm.atomicrmw max %i32_ptr, %i32 monotonic : i32 + %9 = llvm.atomicrmw max %i32_ptr, %i32 monotonic : !llvm.ptr, i32 // CHECK: atomicrmw min ptr %{{.*}}, i32 %{{.*}} monotonic - %10 = llvm.atomicrmw min %i32_ptr, %i32 monotonic : i32 + %10 = llvm.atomicrmw min %i32_ptr, %i32 monotonic : !llvm.ptr, i32 // CHECK: atomicrmw umax ptr %{{.*}}, i32 %{{.*}} monotonic - %11 = llvm.atomicrmw umax %i32_ptr, %i32 monotonic : i32 + %11 = llvm.atomicrmw umax %i32_ptr, %i32 monotonic : !llvm.ptr, i32 // CHECK: atomicrmw umin ptr %{{.*}}, i32 %{{.*}} monotonic - %12 = llvm.atomicrmw umin %i32_ptr, %i32 monotonic : i32 + %12 = llvm.atomicrmw umin %i32_ptr, %i32 monotonic : !llvm.ptr, i32 llvm.return } // CHECK-LABEL: @cmpxchg llvm.func @cmpxchg(%ptr : !llvm.ptr, %cmp : i32, %val: i32) { // CHECK: cmpxchg ptr %{{.*}}, i32 %{{.*}}, i32 %{{.*}} acq_rel monotonic - %0 = llvm.cmpxchg %ptr, %cmp, %val acq_rel monotonic : i32 + %0 = llvm.cmpxchg %ptr, %cmp, %val acq_rel monotonic : !llvm.ptr, i32 // CHECK: %{{[0-9]+}} = extractvalue { i32, i1 } %{{[0-9]+}}, 0 %1 = llvm.extractvalue %0[0] : !llvm.struct<(i32, i1)> // CHECK: %{{[0-9]+}} = extractvalue { i32, i1 } %{{[0-9]+}}, 1 diff --git a/mlir/test/Target/LLVMIR/openmp-reduction.mlir b/mlir/test/Target/LLVMIR/openmp-reduction.mlir --- a/mlir/test/Target/LLVMIR/openmp-reduction.mlir +++ b/mlir/test/Target/LLVMIR/openmp-reduction.mlir @@ -17,7 +17,7 @@ atomic { ^bb2(%arg2: !llvm.ptr, %arg3: !llvm.ptr): %2 = llvm.load %arg3 : !llvm.ptr - llvm.atomicrmw fadd %arg2, %2 monotonic : f32 + llvm.atomicrmw fadd %arg2, %2 monotonic : !llvm.ptr, f32 omp.yield } @@ -90,7 +90,7 @@ atomic { ^bb2(%arg2: !llvm.ptr, %arg3: !llvm.ptr): %2 = llvm.load %arg3 : !llvm.ptr - llvm.atomicrmw fadd %arg2, %2 monotonic : f32 + llvm.atomicrmw fadd %arg2, %2 monotonic : !llvm.ptr, f32 omp.yield } @@ -178,7 +178,7 @@ atomic { ^bb2(%arg2: !llvm.ptr, %arg3: !llvm.ptr): %2 = llvm.load %arg3 : !llvm.ptr - llvm.atomicrmw fadd %arg2, %2 monotonic : f32 + llvm.atomicrmw fadd %arg2, %2 monotonic : !llvm.ptr, f32 omp.yield } @@ -261,7 +261,7 @@ atomic { ^bb2(%arg2: !llvm.ptr, %arg3: !llvm.ptr): %2 = llvm.load %arg3 : !llvm.ptr - llvm.atomicrmw fadd %arg2, %2 monotonic : f32 + llvm.atomicrmw fadd %arg2, %2 monotonic : !llvm.ptr, f32 omp.yield } @@ -340,7 +340,7 @@ atomic { ^bb2(%arg2: !llvm.ptr, %arg3: !llvm.ptr): %2 = llvm.load %arg3 : !llvm.ptr - llvm.atomicrmw fadd %arg2, %2 monotonic : f32 + llvm.atomicrmw fadd %arg2, %2 monotonic : !llvm.ptr, f32 omp.yield }