diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td @@ -376,7 +376,7 @@ Operation *op = $_builder.create<$_qualCppClassName>( $_location, resultTypes, - processValues(llvmOperands)); + convertValues(llvmOperands)); }] # !if(!gt(numResults, 0), "$res = op->getResult(0);", "(void)op;"); } 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 @@ -810,7 +810,7 @@ builder.CreateRetVoid(); }]; string mlirBuilder = [{ - $_builder.create($_location, processValues(llvmOperands)); + $_builder.create($_location, convertValues(llvmOperands)); }]; } diff --git a/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp b/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp --- a/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp +++ b/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp @@ -25,6 +25,7 @@ #include "mlir/Tools/mlir-translate/Translation.h" #include "llvm/ADT/PostOrderIterator.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/StringSet.h" #include "llvm/ADT/TypeSwitch.h" #include "llvm/IR/Attributes.h" @@ -347,6 +348,9 @@ return mlir; } + /// Returns the MLIR value mapped to the given LLVM value. + Value lookupValue(llvm::Value *value) { return valueMapping.lookup(value); } + /// Stores the mapping between an LLVM block and its MLIR counterpart. void mapBlock(llvm::BasicBlock *llvm, Block *mlir) { auto result = blockMapping.try_emplace(llvm, mlir); @@ -359,14 +363,13 @@ return blockMapping.lookup(block); } - /// Returns the remapped version of `value` or a placeholder that will be - /// remapped later if the defining instruction has not yet been visited. - Value processValue(llvm::Value *value); + /// Converts an LLVM value either to the mapped MLIR value or to a constant + /// using the `convertConstant` method. + Value convertValue(llvm::Value *value); - /// Calls `processValue` for a range of `values` and returns their remapped - /// values or placeholders if the defining instructions have not yet been - /// visited. - SmallVector processValues(ArrayRef values); + /// Converts a range of LLVM values to a range of MLIR values using the + /// `convertValue` method. + SmallVector convertValues(ArrayRef values); /// Converts `value` to an integer attribute. Asserts if the conversion fails. IntegerAttr matchIntegerAttr(Value value); @@ -401,6 +404,17 @@ GlobalOp processGlobal(llvm::GlobalVariable *gv); private: + /// Clears the block and value mapping before processing a new region. + void clearBlockAndValueMapping() { + valueMapping.clear(); + blockMapping.clear(); + } + /// Sets the constant insertion point to the start of the given block. + void setConstantInsertionPointToStart(Block *block) { + constantInsertionBlock = block; + constantInsertionOp = nullptr; + } + /// Returns personality of `func` as a FlatSymbolRefAttr. FlatSymbolRefAttr getPersonalityAsAttr(llvm::Function *func); /// Imports `bb` into `block`, which must be initially empty. @@ -408,10 +422,11 @@ /// Imports `inst` and populates valueMapping[inst] with the result of the /// imported operation. LogicalResult processInstruction(llvm::Instruction *inst); - /// `br` branches to `target`. Append the block arguments to attach to the - /// generated branch op to `blockArguments`. These should be in the same order - /// as the PHIs in `target`. - LogicalResult processBranchArgs(llvm::Instruction *br, + /// Converts the `branch` arguments in the order of the phi's found in + /// `target` and appends them to the `blockArguments` to attach to the + /// generated branch operation. The `blockArguments` thus have the same order + /// as the phi's in `target`. + LogicalResult convertBranchArgs(llvm::Instruction *branch, llvm::BasicBlock *target, SmallVectorImpl &blockArguments); /// Returns the builtin type equivalent to be used in attributes for the given @@ -419,20 +434,18 @@ Type getStdTypeForAttr(Type type); /// Returns `value` as an attribute to attach to a GlobalOp. Attribute getConstantAsAttr(llvm::Constant *value); - /// Converts the LLVM constant to an MLIR value produced by a ConstantOp, - /// AddressOfOp, NullOp, or to an expanded sequence of operations (for - /// ConstantExprs or ConstantGEPs). - Value convertConstantInPlace(llvm::Constant *constant); - /// Converts the LLVM constant to an MLIR value using the - /// `convertConstantInPlace` method and inserts the constant at the start of - /// the function entry block. + /// Returns the topologically sorted set of transitive dependencies needed to + /// convert the given constant. + SetVector getConstantsToConvert(llvm::Constant *constant); + /// Converts an LLVM constant to an MLIR value produced by a ConstantOp, + /// AddressOfOp, NullOp, or a side-effect free operation (for ConstantExprs or + /// ConstantGEPs). Value convertConstant(llvm::Constant *constant); - - /// Set the constant insertion point to the start of the given block. - void setConstantInsertionPointToStart(Block *block) { - constantInsertionBlock = block; - constantInsertionOp = nullptr; - } + /// Converts an LLVM constant and its transitive dependencies to MLIR + /// operations by converting them in topological order using the + /// `convertConstant` method. All operations are inserted at the + /// start of the current function entry block. + Value convertConstantExpr(llvm::Constant *constant); /// Builder pointing at where the next instruction should be generated. OpBuilder builder; @@ -633,9 +646,8 @@ } GlobalOp Importer::processGlobal(llvm::GlobalVariable *gv) { - auto it = globals.find(gv); - if (it != globals.end()) - return it->second; + if (globals.count(gv)) + return globals[gv]; // Insert the global after the last one or at the start of the module. OpBuilder::InsertionGuard guard(builder); @@ -661,14 +673,16 @@ UnknownLoc::get(context), type, gv->isConstant(), convertLinkageFromLLVM(gv->getLinkage()), gv->getName(), valueAttr, alignment, /*addr_space=*/gv->getAddressSpace(), - /*dso_local=*/gv->isDSOLocal(), /*thread_local=*/gv->isThreadLocal()); + /*dso_local=*/gv->isDSOLocal(), + /*thread_local=*/gv->isThreadLocal()); globalInsertionOp = op; if (gv->hasInitializer() && !valueAttr) { + clearBlockAndValueMapping(); Block *block = builder.createBlock(&op.getInitializerRegion()); setConstantInsertionPointToStart(block); - Value value = convertConstant(gv->getInitializer()); - builder.create(op.getLoc(), ArrayRef({value})); + Value value = convertConstantExpr(gv->getInitializer()); + builder.create(op.getLoc(), value); } if (gv->hasAtLeastLocalUnnamedAddr()) op.setUnnamedAddr(convertUnnamedAddrFromLLVM(gv->getUnnamedAddr())); @@ -678,89 +692,126 @@ return globals[gv] = op; } -Value Importer::convertConstantInPlace(llvm::Constant *constant) { +SetVector +Importer::getConstantsToConvert(llvm::Constant *constant) { + // Traverse the constant dependencies in post order. + SmallVector workList; + SmallVector orderedList; + workList.push_back(constant); + while (!workList.empty()) { + llvm::Constant *current = workList.pop_back_val(); + // Skip constants that have been converted before and store all other ones. + if (valueMapping.count(constant)) + continue; + orderedList.push_back(current); + // Add the current constant's dependencies to the work list. + for (llvm::Value *operand : current->operands()) { + assert(isa(operand) && + "expected constants to have constant operands only"); + workList.push_back(cast(operand)); + } + // Use the `getElementValue` method to add the dependencies of zero + // initialized aggregate constants since they do not take any operands. + if (auto *constAgg = dyn_cast(current)) { + unsigned numElements = constAgg->getElementCount().getFixedValue(); + for (unsigned i = 0, e = numElements; i != e; ++i) + workList.push_back(constAgg->getElementValue(i)); + } + } + + // Add the constants in reverse post order to the result set to ensure all + // dependencies are satisfied. Avoid storing duplicates since LLVM constants + // are uniqued and only one `valueMapping` entry per constant is possible. + SetVector orderedSet; + for (llvm::Constant *orderedConst : llvm::reverse(orderedList)) + orderedSet.insert(orderedConst); + return orderedSet; +} + +Value Importer::convertConstant(llvm::Constant *constant) { + // Constants have no location attached. + Location loc = UnknownLoc::get(context); + + // Convert constants that can be represented as attributes. if (Attribute attr = getConstantAsAttr(constant)) { - // These constants can be represented as attributes. Type type = convertType(constant->getType()); if (auto symbolRef = attr.dyn_cast()) - return builder.create(UnknownLoc::get(context), type, - symbolRef.getValue()); - return builder.create(UnknownLoc::get(context), type, attr); + return builder.create(loc, type, symbolRef.getValue()); + return builder.create(loc, type, attr); } - if (auto *cn = dyn_cast(constant)) { - Type type = convertType(cn->getType()); - return builder.create(UnknownLoc::get(context), type); + + // Convert null pointer constants. + if (auto *nullPtr = dyn_cast(constant)) { + Type type = convertType(nullPtr->getType()); + return builder.create(loc, type); } - if (auto *gv = dyn_cast(constant)) - return builder.create(UnknownLoc::get(context), - processGlobal(gv)); - if (auto *ce = dyn_cast(constant)) { - llvm::Instruction *i = ce->getAsInstruction(); - if (failed(processInstruction(i))) - return nullptr; - assert(valueMapping.count(i)); - - // If we don't remove entry of `i` here, it's totally possible that the - // next time llvm::ConstantExpr::getAsInstruction is called again, which - // always allocates a new Instruction, memory address of the newly - // created Instruction might be the same as `i`. Making processInstruction - // falsely believe that the new Instruction has been processed before - // and raised an assertion error. - Value value = valueMapping[i]; - valueMapping.erase(i); - // Remove this zombie LLVM instruction now, leaving us only with the MLIR - // op. - i->deleteValue(); - return value; + // Convert undef. + if (auto *undefVal = dyn_cast(constant)) { + Type type = convertType(undefVal->getType()); + return builder.create(loc, type); } - if (auto *ue = dyn_cast(constant)) { - Type type = convertType(ue->getType()); - return builder.create(UnknownLoc::get(context), type); + + // Convert global variable accesses. + if (auto *globalVar = dyn_cast(constant)) + return builder.create(loc, processGlobal(globalVar)); + + // Convert constant expressions. + if (auto *constExpr = dyn_cast(constant)) { + // Convert the constant expression to a temporary LLVM instruction and + // translate it using the `processInstruction` method. Delete the + // instruction after the translation and remove it from `valueMapping`, + // since later calls to `getAsInstruction` may return the same address + // resulting in a conflicting `valueMapping` entry. + llvm::Instruction *inst = constExpr->getAsInstruction(); + auto guard = llvm::make_scope_exit([&]() { + valueMapping.erase(inst); + inst->deleteValue(); + }); + // Note: `processInstruction` does not call `convertConstant` recursively + // since all constant dependencies have been converted before. + assert(llvm::all_of(inst->operands(), [&](llvm::Value *value) { + return valueMapping.count(value); + })); + if (failed(processInstruction(inst))) + return nullptr; + return lookupValue(inst); } + // Convert aggregate constants. if (isa(constant) || isa(constant)) { - unsigned numElements = constant->getNumOperands(); - std::function getElement = - [&](unsigned index) -> llvm::Constant * { - return constant->getAggregateElement(index); - }; - // llvm::ConstantAggregateZero doesn't take any operand - // so its getNumOperands is always zero. - if (auto *caz = dyn_cast(constant)) { - numElements = caz->getElementCount().getFixedValue(); - // We want to capture the pointer rather than reference - // to the pointer since the latter will become dangling upon - // exiting the scope. - getElement = [=](unsigned index) -> llvm::Constant * { - return caz->getElementValue(index); - }; + // Lookup the aggregate elements that have been converted before. + SmallVector elementValues; + if (auto *constAgg = dyn_cast(constant)) { + elementValues.reserve(constAgg->getNumOperands()); + for (llvm::Value *operand : constAgg->operands()) + elementValues.push_back(lookupValue(operand)); + } + if (auto *constAgg = dyn_cast(constant)) { + unsigned numElements = constAgg->getElementCount().getFixedValue(); + elementValues.reserve(numElements); + for (unsigned i = 0, e = numElements; i != e; ++i) + elementValues.push_back(lookupValue(constAgg->getElementValue(i))); } + assert(llvm::count(elementValues, nullptr) == 0 && + "expected all elements have been converted before"); - // Generate a llvm.undef as the root value first. + // Generate an UndefOp as root value and insert the aggregate elements. Type rootType = convertType(constant->getType()); - bool useInsertValue = rootType.isa(); - assert((useInsertValue || LLVM::isCompatibleVectorType(rootType)) && + bool isArrayOrStruct = rootType.isa(); + assert((isArrayOrStruct || LLVM::isCompatibleVectorType(rootType)) && "unrecognized aggregate type"); - Value root = builder.create(UnknownLoc::get(context), rootType); - for (unsigned i = 0; i < numElements; ++i) { - llvm::Constant *element = getElement(i); - Value elementValue = convertConstantInPlace(element); - if (!elementValue) - return nullptr; - if (useInsertValue) { - root = builder.create(UnknownLoc::get(context), root, - elementValue, i); + Value root = builder.create(loc, rootType); + for (const auto &it : llvm::enumerate(elementValues)) { + if (isArrayOrStruct) { + root = builder.create(loc, root, it.value(), it.index()); } else { - Attribute indexAttr = - builder.getI32IntegerAttr(static_cast(i)); - Value indexValue = builder.create( - UnknownLoc::get(context), builder.getI32Type(), indexAttr); - if (!indexValue) - return nullptr; - root = builder.create( - UnknownLoc::get(context), rootType, root, elementValue, indexValue); + Attribute indexAttr = builder.getI32IntegerAttr(it.index()); + Value indexValue = + builder.create(loc, builder.getI32Type(), indexAttr); + root = builder.create(loc, rootType, root, it.value(), + indexValue); } } return root; @@ -769,7 +820,7 @@ return nullptr; } -Value Importer::convertConstant(llvm::Constant *constant) { +Value Importer::convertConstantExpr(llvm::Constant *constant) { assert(constantInsertionBlock && "expected the constant insertion block to be non-null"); @@ -781,34 +832,43 @@ builder.setInsertionPointAfter(constantInsertionOp); } - // Convert the constant in-place and update the insertion point if successful. - if (Value result = convertConstantInPlace(constant)) { - constantInsertionOp = result.getDefiningOp(); - return result; + // Convert all constants of the expression and add them to `valueMapping`. + SetVector constantsToConvert = + getConstantsToConvert(constant); + for (llvm::Constant *constantToConvert : constantsToConvert) { + if (Value value = convertConstant(constantToConvert)) { + mapValue(constantToConvert, value); + continue; + } + + llvm::errs() << diag(*constantToConvert) << "\n"; + llvm_unreachable("unhandled constant"); } - llvm::errs() << diag(*constant) << "\n"; - llvm_unreachable("unhandled constant"); + // Update the constant insertion point and return the converted constant. + Value result = lookupValue(constant); + constantInsertionOp = result.getDefiningOp(); + return result; } -Value Importer::processValue(llvm::Value *value) { - auto it = valueMapping.find(value); - if (it != valueMapping.end()) - return it->second; +Value Importer::convertValue(llvm::Value *value) { + // Return the mapped value if it has been converted before. + if (valueMapping.count(value)) + return lookupValue(value); - // Convert constants such as immediate arguments that have no mapping. - if (auto *c = dyn_cast(value)) - return convertConstant(c); + // Convert constants such as immediate values that have no mapping yet. + if (auto *constant = dyn_cast(value)) + return convertConstantExpr(constant); llvm::errs() << diag(*value) << "\n"; llvm_unreachable("unhandled value"); } -SmallVector Importer::processValues(ArrayRef values) { +SmallVector Importer::convertValues(ArrayRef values) { SmallVector remapped; remapped.reserve(values.size()); for (llvm::Value *value : values) - remapped.push_back(processValue(value)); + remapped.push_back(convertValue(value)); return remapped; } @@ -820,15 +880,13 @@ return integerAttr; } -// `br` branches to `target`. Return the branch arguments to `br`, in the -// same order of the PHIs in `target`. LogicalResult -Importer::processBranchArgs(llvm::Instruction *br, llvm::BasicBlock *target, +Importer::convertBranchArgs(llvm::Instruction *branch, llvm::BasicBlock *target, SmallVectorImpl &blockArguments) { for (auto inst = target->begin(); isa(inst); ++inst) { - auto *pn = cast(&*inst); - Value value = processValue(pn->getIncomingValueForBlock(br->getParent())); - blockArguments.push_back(value); + auto *phi = cast(&*inst); + llvm::Value *value = phi->getIncomingValueForBlock(branch->getParent()); + blockArguments.push_back(convertValue(value)); } return success(); } @@ -856,7 +914,7 @@ OperationState state(loc, brInst->isConditional() ? "llvm.cond_br" : "llvm.br"); if (brInst->isConditional()) { - Value condition = processValue(brInst->getCondition()); + Value condition = convertValue(brInst->getCondition()); state.addOperands(condition); } @@ -864,7 +922,7 @@ for (int i : llvm::seq(0, brInst->getNumSuccessors())) { llvm::BasicBlock *succ = brInst->getSuccessor(i); SmallVector blockArguments; - if (failed(processBranchArgs(brInst, succ, blockArguments))) + if (failed(convertBranchArgs(brInst, succ, blockArguments))) return failure(); state.addSuccessors(lookupBlock(succ)); state.addOperands(blockArguments); @@ -882,11 +940,11 @@ if (inst->getOpcode() == llvm::Instruction::Switch) { auto *swInst = cast(inst); // Process the condition value. - Value condition = processValue(swInst->getCondition()); + Value condition = convertValue(swInst->getCondition()); SmallVector defaultBlockArgs; // Process the default case. llvm::BasicBlock *defaultBB = swInst->getDefaultDest(); - if (failed(processBranchArgs(swInst, defaultBB, defaultBlockArgs))) + if (failed(convertBranchArgs(swInst, defaultBB, defaultBlockArgs))) return failure(); // Process the cases. @@ -898,7 +956,7 @@ for (const auto &it : llvm::enumerate(swInst->cases())) { const llvm::SwitchInst::CaseHandle &caseHandle = it.value(); llvm::BasicBlock *succBB = caseHandle.getCaseSuccessor(); - if (failed(processBranchArgs(swInst, succBB, caseOperands[it.index()]))) + if (failed(convertBranchArgs(swInst, succBB, caseOperands[it.index()]))) return failure(); caseOperandRefs[it.index()] = caseOperands[it.index()]; caseValues[it.index()] = caseHandle.getCaseValue()->getSExtValue(); @@ -919,7 +977,7 @@ if (inst->getOpcode() == llvm::Instruction::Call) { llvm::CallInst *ci = cast(inst); SmallVector args(ci->args()); - SmallVector ops = processValues(args); + SmallVector ops = convertValues(args); SmallVector tys; if (!ci->getType()->isVoidTy()) { Type type = convertType(inst->getType()); @@ -931,7 +989,7 @@ loc, tys, SymbolRefAttr::get(builder.getContext(), callee->getName()), ops); } else { - Value calledValue = processValue(ci->getCalledOperand()); + Value calledValue = convertValue(ci->getCalledOperand()); ops.insert(ops.begin(), calledValue); op = builder.create(loc, tys, ops); } @@ -944,7 +1002,7 @@ SmallVector ops; for (unsigned i = 0, ie = lpi->getNumClauses(); i < ie; i++) - ops.push_back(convertConstant(lpi->getClause(i))); + ops.push_back(convertConstantExpr(lpi->getClause(i))); Type ty = convertType(lpi->getType()); Value res = builder.create(loc, ty, lpi->isCleanup(), ops); @@ -959,11 +1017,11 @@ tys.push_back(convertType(inst->getType())); SmallVector args(ii->args()); - SmallVector ops = processValues(args); + SmallVector ops = convertValues(args); SmallVector normalArgs, unwindArgs; - (void)processBranchArgs(ii, ii->getNormalDest(), normalArgs); - (void)processBranchArgs(ii, ii->getUnwindDest(), unwindArgs); + (void)convertBranchArgs(ii, ii->getNormalDest(), normalArgs); + (void)convertBranchArgs(ii, ii->getUnwindDest(), unwindArgs); Operation *op; if (llvm::Function *callee = ii->getCalledFunction()) { @@ -972,7 +1030,7 @@ ops, lookupBlock(ii->getNormalDest()), normalArgs, lookupBlock(ii->getUnwindDest()), unwindArgs); } else { - ops.insert(ops.begin(), processValue(ii->getCalledOperand())); + ops.insert(ops.begin(), convertValue(ii->getCalledOperand())); op = builder.create( loc, tys, ops, lookupBlock(ii->getNormalDest()), normalArgs, lookupBlock(ii->getUnwindDest()), unwindArgs); @@ -985,7 +1043,7 @@ if (inst->getOpcode() == llvm::Instruction::GetElementPtr) { // FIXME: Support inbounds GEPs. llvm::GetElementPtrInst *gep = cast(inst); - Value basePtr = processValue(gep->getOperand(0)); + Value basePtr = convertValue(gep->getOperand(0)); Type sourceElementType = convertType(gep->getSourceElementType()); // Treat every indices as dynamic since GEPOp::build will refine those @@ -994,7 +1052,7 @@ // at first place. SmallVector indices; for (llvm::Value *operand : llvm::drop_begin(gep->operand_values())) { - Value val = processValue(operand); + Value val = convertValue(operand); indices.push_back(val); } @@ -1040,8 +1098,7 @@ } LogicalResult Importer::processFunction(llvm::Function *func) { - blockMapping.clear(); - valueMapping.clear(); + clearBlockAndValueMapping(); auto functionType = convertType(func->getFunctionType()).dyn_cast(); 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 @@ -81,6 +81,57 @@ ; // ----- +@global = external global i32, align 8 + +; CHECK-LABEL: @const_expr_with_duplicate +define i64 @const_expr_with_duplicate() { + ; CHECK: %[[ADDR:[0-9]+]] = llvm.mlir.addressof @global : !llvm.ptr + ; CHECK: %[[IDX:[0-9]+]] = llvm.mlir.constant(7 : i32) : i32 + ; CHECK: %[[GEP:[0-9]+]] = llvm.getelementptr %[[ADDR]][%[[IDX]]] : (!llvm.ptr, i32) -> !llvm.ptr + ; CHECK: %[[DUP:[0-9]+]] = llvm.ptrtoint %[[GEP]] : !llvm.ptr to i64 + + ; Verify the duplicate sub expression is converted only once. + ; CHECK: %[[SUM:[0-9]+]] = llvm.add %[[DUP]], %[[DUP]] : i64 + ; CHECK: llvm.return %[[SUM]] : i64 + ret i64 add (i64 ptrtoint (i32* getelementptr (i32, i32* @global, i32 7) to i64), + i64 ptrtoint (i32* getelementptr (i32, i32* @global, i32 7) to i64)) +} + +; // ----- + +@global = external global i32, align 8 + +; CHECK-LABEL: @const_expr_with_aggregate() +define i64 @const_expr_with_aggregate() { + ; Compute the vector elements. + ; CHECK: %[[VAL1:[0-9]+]] = llvm.mlir.constant(33 : i64) : i64 + ; CHECK: %[[ADDR:[0-9]+]] = llvm.mlir.addressof @global : !llvm.ptr + ; CHECK: %[[IDX1:[0-9]+]] = llvm.mlir.constant(7 : i32) : i32 + ; CHECK: %[[GEP1:[0-9]+]] = llvm.getelementptr %[[ADDR]][%[[IDX1]]] : (!llvm.ptr, i32) -> !llvm.ptr + ; CHECK: %[[VAL2:[0-9]+]] = llvm.ptrtoint %[[GEP1]] : !llvm.ptr to i64 + + ; Fill the vector. + ; CHECK: %[[VEC1:[0-9]+]] = llvm.mlir.undef : vector<2xi64> + ; CHECK: %[[IDX2:[0-9]+]] = llvm.mlir.constant(0 : i32) : i32 + ; CHECK: %[[VEC2:[0-9]+]] = llvm.insertelement %[[VAL1]], %[[VEC1]][%[[IDX2]] : i32] : vector<2xi64> + ; CHECK: %[[IDX3:[0-9]+]] = llvm.mlir.constant(1 : i32) : i32 + ; CHECK: %[[VEC3:[0-9]+]] = llvm.insertelement %[[VAL2]], %[[VEC2]][%[[IDX3]] : i32] : vector<2xi64> + ; CHECK: %[[IDX4:[0-9]+]] = llvm.mlir.constant(42 : i32) : i32 + + ; Compute the extract index. + ; CHECK: %[[GEP2:[0-9]+]] = llvm.getelementptr %[[ADDR]][%[[IDX4]]] : (!llvm.ptr, i32) -> !llvm.ptr + ; CHECK: %[[IDX5:[0-9]+]] = llvm.ptrtoint %[[GEP2]] : !llvm.ptr to i64 + + ; Extract the vector element. + ; CHECK: %[[ELEM:[0-9]+]] = llvm.extractelement %[[VEC3]][%[[IDX5]] : i64] : vector<2xi64> + ; CHECK: llvm.return %[[ELEM]] : i64 + ret i64 extractelement ( + <2 x i64> , + i64 ptrtoint (i32* getelementptr (i32, i32* @global, i32 42) to i64)) +} + +; // ----- + ; Verify the function constant import. ; Calling a function that has not been defined yet. @@ -119,42 +170,41 @@ ; Verify the aggregate constant import. -; CHECK: %[[ROOT:.+]] = llvm.mlir.undef : !llvm.struct<"simple_agg_type", (i32, i8, i16, i32)> ; CHECK: %[[C0:.+]] = llvm.mlir.constant(9 : i32) : i32 -; CHECK: %[[CHAIN0:.+]] = llvm.insertvalue %[[C0]], %[[ROOT]][0] ; CHECK: %[[C1:.+]] = llvm.mlir.constant(4 : i8) : i8 -; CHECK: %[[CHAIN1:.+]] = llvm.insertvalue %[[C1]], %[[CHAIN0]][1] ; CHECK: %[[C2:.+]] = llvm.mlir.constant(8 : i16) : i16 -; CHECK: %[[CHAIN2:.+]] = llvm.insertvalue %[[C2]], %[[CHAIN1]][2] ; CHECK: %[[C3:.+]] = llvm.mlir.constant(7 : i32) : i32 +; CHECK: %[[ROOT:.+]] = llvm.mlir.undef : !llvm.struct<"simple_agg_type", (i32, i8, i16, i32)> +; CHECK: %[[CHAIN0:.+]] = llvm.insertvalue %[[C0]], %[[ROOT]][0] +; CHECK: %[[CHAIN1:.+]] = llvm.insertvalue %[[C1]], %[[CHAIN0]][1] +; CHECK: %[[CHAIN2:.+]] = llvm.insertvalue %[[C2]], %[[CHAIN1]][2] ; CHECK: %[[CHAIN3:.+]] = llvm.insertvalue %[[C3]], %[[CHAIN2]][3] ; CHECK: llvm.return %[[CHAIN3]] %simple_agg_type = type {i32, i8, i16, i32} @simple_agg = global %simple_agg_type {i32 9, i8 4, i16 8, i32 7} -; CHECK: %[[ROOT:.+]] = llvm.mlir.undef : !llvm.struct<"nested_agg_type", (struct<"simple_agg_type", (i32, i8, i16, i32)>, ptr>)> -; CHECK: %[[NESTED:.+]] = llvm.mlir.undef : !llvm.struct<"simple_agg_type", (i32, i8, i16, i32)> ; CHECK: %[[C1:.+]] = llvm.mlir.constant(1 : i32) : i32 -; CHECK: %[[CHAIN0:.+]] = llvm.insertvalue %[[C1]], %[[NESTED]][0] ; CHECK: %[[C2:.+]] = llvm.mlir.constant(2 : i8) : i8 -; CHECK: %[[CHAIN1:.+]] = llvm.insertvalue %[[C2]], %[[CHAIN0]][1] ; CHECK: %[[C3:.+]] = llvm.mlir.constant(3 : i16) : i16 -; CHECK: %[[CHAIN2:.+]] = llvm.insertvalue %[[C3]], %[[CHAIN1]][2] ; CHECK: %[[C4:.+]] = llvm.mlir.constant(4 : i32) : i32 +; CHECK: %[[NESTED:.+]] = llvm.mlir.undef : !llvm.struct<"simple_agg_type", (i32, i8, i16, i32)> +; CHECK: %[[CHAIN0:.+]] = llvm.insertvalue %[[C1]], %[[NESTED]][0] +; CHECK: %[[CHAIN1:.+]] = llvm.insertvalue %[[C2]], %[[CHAIN0]][1] +; CHECK: %[[CHAIN2:.+]] = llvm.insertvalue %[[C3]], %[[CHAIN1]][2] ; CHECK: %[[CHAIN3:.+]] = llvm.insertvalue %[[C4]], %[[CHAIN2]][3] +; CHECK: %[[NULL:.+]] = llvm.mlir.null : !llvm.ptr> +; CHECK: %[[ROOT:.+]] = llvm.mlir.undef : !llvm.struct<"nested_agg_type", (struct<"simple_agg_type", (i32, i8, i16, i32)>, ptr>)> ; CHECK: %[[CHAIN4:.+]] = llvm.insertvalue %[[CHAIN3]], %[[ROOT]][0] -; CHECK: %[[NP:.+]] = llvm.mlir.null : !llvm.ptr> -; CHECK: %[[CHAIN5:.+]] = llvm.insertvalue %[[NP]], %[[CHAIN4]][1] +; CHECK: %[[CHAIN5:.+]] = llvm.insertvalue %[[NULL]], %[[CHAIN4]][1] ; CHECK: llvm.return %[[CHAIN5]] %nested_agg_type = type {%simple_agg_type, %simple_agg_type*} @nested_agg = global %nested_agg_type { %simple_agg_type{i32 1, i8 2, i16 3, i32 4}, %simple_agg_type* null } +; CHECK: %[[NULL:.+]] = llvm.mlir.null : !llvm.ptr> ; CHECK: %[[ROOT:.+]] = llvm.mlir.undef : !llvm.vec<2 x ptr>> -; CHECK: %[[C0:.+]] = llvm.mlir.null : !llvm.ptr> ; CHECK: %[[P0:.+]] = llvm.mlir.constant(0 : i32) : i32 -; CHECK: %[[CHAIN0:.+]] = llvm.insertelement %[[C0]], %[[ROOT]][%[[P0]] : i32] : !llvm.vec<2 x ptr>> -; CHECK: %[[C1:.+]] = llvm.mlir.null : !llvm.ptr> +; CHECK: %[[CHAIN0:.+]] = llvm.insertelement %[[NULL]], %[[ROOT]][%[[P0]] : i32] : !llvm.vec<2 x ptr>> ; CHECK: %[[P1:.+]] = llvm.mlir.constant(1 : i32) : i32 -; CHECK: %[[CHAIN1:.+]] = llvm.insertelement %[[C1]], %[[CHAIN0]][%[[P1]] : i32] : !llvm.vec<2 x ptr>> +; CHECK: %[[CHAIN1:.+]] = llvm.insertelement %[[NULL]], %[[CHAIN0]][%[[P1]] : i32] : !llvm.vec<2 x ptr>> ; CHECK: llvm.return %[[CHAIN1]] : !llvm.vec<2 x ptr>> @vector_agg = global <2 x %simple_agg_type*> <%simple_agg_type* null, %simple_agg_type* null> diff --git a/mlir/test/Target/LLVMIR/Import/incorrect-constant-caching.ll b/mlir/test/Target/LLVMIR/Import/incorrect-constant-caching.ll --- a/mlir/test/Target/LLVMIR/Import/incorrect-constant-caching.ll +++ b/mlir/test/Target/LLVMIR/Import/incorrect-constant-caching.ll @@ -8,19 +8,20 @@ ; only wrote minimum level of checks. %my_struct = type {i32, i8*} -; CHECK: llvm.mlir.addressof @str0 : !llvm.ptr> -; CHECK: llvm.mlir.addressof @str1 : !llvm.ptr> -; CHECK: llvm.mlir.undef : !llvm.array<2 x struct<"my_struct", (i32, ptr)>> -; CHECK: llvm.mlir.undef : !llvm.struct<"my_struct", (i32, ptr)> ; CHECK: llvm.mlir.constant(8 : i32) : i32 -; CHECK: llvm.insertvalue +; CHECK: llvm.mlir.addressof @str0 : !llvm.ptr> +; CHECK: llvm.mlir.constant(0 : i32) : i32 ; CHECK: llvm.getelementptr +; CHECK: llvm.mlir.undef : !llvm.struct<"my_struct", (i32, ptr)> ; CHECK: llvm.insertvalue ; CHECK: llvm.insertvalue -; CHECK: llvm.mlir.undef : !llvm.struct<"my_struct", (i32, ptr)> ; CHECK: llvm.mlir.constant(7 : i32) : i32 -; CHECK: llvm.insertvalue +; CHECK: llvm.mlir.addressof @str1 : !llvm.ptr> ; CHECK: llvm.getelementptr +; CHECK: llvm.mlir.undef : !llvm.struct<"my_struct", (i32, ptr)> +; CHECK: llvm.insertvalue +; CHECK: llvm.insertvalue +; CHECK: llvm.mlir.undef : !llvm.array<2 x struct<"my_struct", (i32, ptr)>> ; CHECK: llvm.insertvalue ; CHECK: llvm.insertvalue ; CHECK: llvm.return diff --git a/mlir/test/Target/LLVMIR/Import/incorrect-constexpr-inst-caching.ll b/mlir/test/Target/LLVMIR/Import/incorrect-constexpr-inst-caching.ll --- a/mlir/test/Target/LLVMIR/Import/incorrect-constexpr-inst-caching.ll +++ b/mlir/test/Target/LLVMIR/Import/incorrect-constexpr-inst-caching.ll @@ -5,23 +5,23 @@ ; Thus, we only wrote minimum level of checks. %my_struct = type {i32, i8*} +; CHECK: llvm.mlir.constant(8 : i32) : i32 ; CHECK: llvm.mlir.addressof @str0 : !llvm.ptr> ; CHECK: llvm.mlir.constant(0 : i32) : i32 ; CHECK: llvm.mlir.constant(1 : i32) : i32 +; CHECK: llvm.getelementptr +; CHECK: llvm.mlir.undef : !llvm.struct<"my_struct", (i32, ptr)> +; CHECK: llvm.insertvalue +; CHECK: llvm.insertvalue +; CHECK: llvm.mlir.constant(7 : i32) : i32 ; CHECK: llvm.mlir.addressof @str1 : !llvm.ptr> ; CHECK: llvm.mlir.constant(2 : i32) : i32 ; CHECK: llvm.mlir.constant(3 : i32) : i32 -; CHECK: llvm.mlir.undef : !llvm.array<2 x struct<"my_struct", (i32, ptr)>> -; CHECK: llvm.mlir.undef : !llvm.struct<"my_struct", (i32, ptr)> -; CHECK: llvm.mlir.constant(8 : i32) : i32 -; CHECK: llvm.insertvalue ; CHECK: llvm.getelementptr -; CHECK: llvm.insertvalue -; CHECK: llvm.insertvalue ; CHECK: llvm.mlir.undef : !llvm.struct<"my_struct", (i32, ptr)> -; CHECK: llvm.mlir.constant(7 : i32) : i32 ; CHECK: llvm.insertvalue -; CHECK: llvm.getelementptr +; CHECK: llvm.insertvalue +; CHECK: llvm.mlir.undef : !llvm.array<2 x struct<"my_struct", (i32, ptr)>> ; CHECK: llvm.insertvalue ; CHECK: llvm.insertvalue ; CHECK: llvm.return diff --git a/mlir/test/Target/LLVMIR/Import/intrinsic.ll b/mlir/test/Target/LLVMIR/Import/intrinsic.ll --- a/mlir/test/Target/LLVMIR/Import/intrinsic.ll +++ b/mlir/test/Target/LLVMIR/Import/intrinsic.ll @@ -127,21 +127,19 @@ } ; CHECK-LABEL: llvm.func @ctlz_test define void @ctlz_test(i32 %0, <8 x i32> %1) { - ; CHECK: %[[falseval1:.+]] = llvm.mlir.constant(false) : i1 - ; CHECK: %[[falseval2:.+]] = llvm.mlir.constant(false) : i1 - ; CHECK: "llvm.intr.ctlz"(%{{.*}}, %[[falseval1]]) : (i32, i1) -> i32 + ; CHECK: %[[FALSE:.+]] = llvm.mlir.constant(false) : i1 + ; CHECK: "llvm.intr.ctlz"(%{{.*}}, %[[FALSE]]) : (i32, i1) -> i32 %3 = call i32 @llvm.ctlz.i32(i32 %0, i1 false) - ; CHECK: "llvm.intr.ctlz"(%{{.*}}, %[[falseval2]]) : (vector<8xi32>, i1) -> vector<8xi32> + ; CHECK: "llvm.intr.ctlz"(%{{.*}}, %[[FALSE]]) : (vector<8xi32>, i1) -> vector<8xi32> %4 = call <8 x i32> @llvm.ctlz.v8i32(<8 x i32> %1, i1 false) ret void } ; CHECK-LABEL: llvm.func @cttz_test define void @cttz_test(i32 %0, <8 x i32> %1) { - ; CHECK: %[[falseval1:.+]] = llvm.mlir.constant(false) : i1 - ; CHECK: %[[falseval2:.+]] = llvm.mlir.constant(false) : i1 - ; CHECK: "llvm.intr.cttz"(%{{.*}}, %[[falseval1]]) : (i32, i1) -> i32 + ; CHECK: %[[FALSE:.+]] = llvm.mlir.constant(false) : i1 + ; CHECK: "llvm.intr.cttz"(%{{.*}}, %[[FALSE]]) : (i32, i1) -> i32 %3 = call i32 @llvm.cttz.i32(i32 %0, i1 false) - ; CHECK: "llvm.intr.cttz"(%{{.*}}, %[[falseval2]]) : (vector<8xi32>, i1) -> vector<8xi32> + ; CHECK: "llvm.intr.cttz"(%{{.*}}, %[[FALSE]]) : (vector<8xi32>, i1) -> vector<8xi32> %4 = call <8 x i32> @llvm.cttz.v8i32(<8 x i32> %1, i1 false) ret void } @@ -333,12 +331,11 @@ ; CHECK-LABEL: llvm.func @memcpy_test define void @memcpy_test(i32 %0, i8* %1, i8* %2) { - ; CHECK: %[[falseval1:.+]] = llvm.mlir.constant(false) : i1 - ; CHECK: %[[constant:.+]] = llvm.mlir.constant(10 : i64) : i64 - ; CHECK: %[[falseval2:.+]] = llvm.mlir.constant(false) : i1 - ; CHECK: "llvm.intr.memcpy"(%{{.*}}, %{{.*}}, %{{.*}}, %[[falseval1]]) : (!llvm.ptr, !llvm.ptr, i32, i1) -> () + ; CHECK: %[[FALSE:.+]] = llvm.mlir.constant(false) : i1 + ; CHECK: %[[CST:.+]] = llvm.mlir.constant(10 : i64) : i64 + ; CHECK: "llvm.intr.memcpy"(%{{.*}}, %{{.*}}, %{{.*}}, %[[FALSE]]) : (!llvm.ptr, !llvm.ptr, i32, i1) -> () call void @llvm.memcpy.p0i8.p0i8.i32(i8* %1, i8* %2, i32 %0, i1 false) - ; CHECK: "llvm.intr.memcpy.inline"(%{{.*}}, %{{.*}}, %[[constant]], %[[falseval2]]) : (!llvm.ptr, !llvm.ptr, i64, i1) -> () + ; CHECK: "llvm.intr.memcpy.inline"(%{{.*}}, %{{.*}}, %[[CST]], %[[FALSE]]) : (!llvm.ptr, !llvm.ptr, i64, i1) -> () call void @llvm.memcpy.inline.p0i8.p0i8.i64(i8* %1, i8* %2, i64 10, i1 false) ret void } diff --git a/mlir/test/Target/LLVMIR/Import/zeroinitializer.ll b/mlir/test/Target/LLVMIR/Import/zeroinitializer.ll --- a/mlir/test/Target/LLVMIR/Import/zeroinitializer.ll +++ b/mlir/test/Target/LLVMIR/Import/zeroinitializer.ll @@ -4,10 +4,10 @@ ; CHECK: llvm.mlir.global external @D() ; CHECK-SAME: !llvm.struct<"Domain", (ptr>>, ptr>)> -; CHECK: %[[ROOT:.+]] = llvm.mlir.undef : !llvm.struct<"Domain", (ptr>>, ptr>)> ; CHECK: %[[E0:.+]] = llvm.mlir.null : !llvm.ptr>>, ptr>)>>> -; CHECK: %[[CHAIN:.+]] = llvm.insertvalue %[[E0]], %[[ROOT]][0] ; CHECK: %[[E1:.+]] = llvm.mlir.null : !llvm.ptr>>, ptr>)>> +; CHECK: %[[ROOT:.+]] = llvm.mlir.undef : !llvm.struct<"Domain", (ptr>>, ptr>)> +; CHECK: %[[CHAIN:.+]] = llvm.insertvalue %[[E0]], %[[ROOT]][0] ; CHECK: %[[RES:.+]] = llvm.insertvalue %[[E1]], %[[CHAIN]][1] ; CHECK: llvm.return %[[RES]] @D = global %Domain zeroinitializer diff --git a/mlir/tools/mlir-tblgen/LLVMIRConversionGen.cpp b/mlir/tools/mlir-tblgen/LLVMIRConversionGen.cpp --- a/mlir/tools/mlir-tblgen/LLVMIRConversionGen.cpp +++ b/mlir/tools/mlir-tblgen/LLVMIRConversionGen.cpp @@ -240,8 +240,8 @@ bool isVariadicOperand = isVariadicOperandName(op, name); auto result = isVariadicOperand - ? formatv("processValues(llvmOperands.drop_front({0}))", idx) - : formatv("processValue(llvmOperands[{0}])", idx); + ? formatv("convertValues(llvmOperands.drop_front({0}))", idx) + : formatv("convertValue(llvmOperands[{0}])", idx); bs << result; } else if (isResultName(op, name)) { if (op.getNumResults() != 1)