1*5d7231d8SStephan Herhut //===- ModuleTranslation.cpp - MLIR to LLVM conversion ----------*- C++ -*-===// 2*5d7231d8SStephan Herhut // 3*5d7231d8SStephan Herhut // Copyright 2019 The MLIR Authors. 4*5d7231d8SStephan Herhut // 5*5d7231d8SStephan Herhut // Licensed under the Apache License, Version 2.0 (the "License"); 6*5d7231d8SStephan Herhut // you may not use this file except in compliance with the License. 7*5d7231d8SStephan Herhut // You may obtain a copy of the License at 8*5d7231d8SStephan Herhut // 9*5d7231d8SStephan Herhut // http://www.apache.org/licenses/LICENSE-2.0 10*5d7231d8SStephan Herhut // 11*5d7231d8SStephan Herhut // Unless required by applicable law or agreed to in writing, software 12*5d7231d8SStephan Herhut // distributed under the License is distributed on an "AS IS" BASIS, 13*5d7231d8SStephan Herhut // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*5d7231d8SStephan Herhut // See the License for the specific language governing permissions and 15*5d7231d8SStephan Herhut // limitations under the License. 16*5d7231d8SStephan Herhut // ============================================================================= 17*5d7231d8SStephan Herhut // 18*5d7231d8SStephan Herhut // This file implements the translation between an MLIR LLVM dialect module and 19*5d7231d8SStephan Herhut // the corresponding LLVMIR module. It only handles core LLVM IR operations. 20*5d7231d8SStephan Herhut // 21*5d7231d8SStephan Herhut //===----------------------------------------------------------------------===// 22*5d7231d8SStephan Herhut 23*5d7231d8SStephan Herhut #include "mlir/Target/LLVMIR/ModuleTranslation.h" 24*5d7231d8SStephan Herhut 25*5d7231d8SStephan Herhut #include "mlir/IR/Attributes.h" 26*5d7231d8SStephan Herhut #include "mlir/IR/Module.h" 27*5d7231d8SStephan Herhut #include "mlir/LLVMIR/LLVMDialect.h" 28*5d7231d8SStephan Herhut #include "mlir/StandardOps/Ops.h" 29*5d7231d8SStephan Herhut #include "mlir/Support/LLVM.h" 30*5d7231d8SStephan Herhut 31*5d7231d8SStephan Herhut #include "llvm/ADT/SetVector.h" 32*5d7231d8SStephan Herhut #include "llvm/IR/BasicBlock.h" 33*5d7231d8SStephan Herhut #include "llvm/IR/Constants.h" 34*5d7231d8SStephan Herhut #include "llvm/IR/DerivedTypes.h" 35*5d7231d8SStephan Herhut #include "llvm/IR/IRBuilder.h" 36*5d7231d8SStephan Herhut #include "llvm/IR/LLVMContext.h" 37*5d7231d8SStephan Herhut #include "llvm/IR/Module.h" 38*5d7231d8SStephan Herhut #include "llvm/Transforms/Utils/Cloning.h" 39*5d7231d8SStephan Herhut 40*5d7231d8SStephan Herhut namespace mlir { 41*5d7231d8SStephan Herhut namespace LLVM { 42*5d7231d8SStephan Herhut 43*5d7231d8SStephan Herhut // Convert an MLIR function type to LLVM IR. Arguments of the function must of 44*5d7231d8SStephan Herhut // MLIR LLVM IR dialect types. Use `loc` as a location when reporting errors. 45*5d7231d8SStephan Herhut // Return nullptr on errors. 46*5d7231d8SStephan Herhut static llvm::FunctionType *convertFunctionType(llvm::LLVMContext &llvmContext, 47*5d7231d8SStephan Herhut FunctionType type, Location loc, 48*5d7231d8SStephan Herhut bool isVarArgs) { 49*5d7231d8SStephan Herhut assert(type && "expected non-null type"); 50*5d7231d8SStephan Herhut 51*5d7231d8SStephan Herhut auto context = type.getContext(); 52*5d7231d8SStephan Herhut if (type.getNumResults() > 1) 53*5d7231d8SStephan Herhut return context->emitError(loc, 54*5d7231d8SStephan Herhut "LLVM functions can only have 0 or 1 result"), 55*5d7231d8SStephan Herhut nullptr; 56*5d7231d8SStephan Herhut 57*5d7231d8SStephan Herhut SmallVector<llvm::Type *, 8> argTypes; 58*5d7231d8SStephan Herhut argTypes.reserve(type.getNumInputs()); 59*5d7231d8SStephan Herhut for (auto t : type.getInputs()) { 60*5d7231d8SStephan Herhut auto wrappedLLVMType = t.dyn_cast<LLVM::LLVMType>(); 61*5d7231d8SStephan Herhut if (!wrappedLLVMType) 62*5d7231d8SStephan Herhut return context->emitError(loc, "non-LLVM function argument type"), 63*5d7231d8SStephan Herhut nullptr; 64*5d7231d8SStephan Herhut argTypes.push_back(wrappedLLVMType.getUnderlyingType()); 65*5d7231d8SStephan Herhut } 66*5d7231d8SStephan Herhut 67*5d7231d8SStephan Herhut if (type.getNumResults() == 0) 68*5d7231d8SStephan Herhut return llvm::FunctionType::get(llvm::Type::getVoidTy(llvmContext), argTypes, 69*5d7231d8SStephan Herhut isVarArgs); 70*5d7231d8SStephan Herhut 71*5d7231d8SStephan Herhut auto wrappedResultType = type.getResult(0).dyn_cast<LLVM::LLVMType>(); 72*5d7231d8SStephan Herhut if (!wrappedResultType) 73*5d7231d8SStephan Herhut return context->emitError(loc, "non-LLVM function result"), nullptr; 74*5d7231d8SStephan Herhut 75*5d7231d8SStephan Herhut return llvm::FunctionType::get(wrappedResultType.getUnderlyingType(), 76*5d7231d8SStephan Herhut argTypes, isVarArgs); 77*5d7231d8SStephan Herhut } 78*5d7231d8SStephan Herhut 79*5d7231d8SStephan Herhut // Create an LLVM IR constant of `llvmType` from the MLIR attribute `attr`. 80*5d7231d8SStephan Herhut // This currently supports integer, floating point, splat and dense element 81*5d7231d8SStephan Herhut // attributes and combinations thereof. In case of error, report it to `loc` 82*5d7231d8SStephan Herhut // and return nullptr. 83*5d7231d8SStephan Herhut llvm::Constant *ModuleTranslation::getLLVMConstant(llvm::Type *llvmType, 84*5d7231d8SStephan Herhut Attribute attr, 85*5d7231d8SStephan Herhut Location loc) { 86*5d7231d8SStephan Herhut if (auto intAttr = attr.dyn_cast<IntegerAttr>()) 87*5d7231d8SStephan Herhut return llvm::ConstantInt::get(llvmType, intAttr.getValue()); 88*5d7231d8SStephan Herhut if (auto floatAttr = attr.dyn_cast<FloatAttr>()) 89*5d7231d8SStephan Herhut return llvm::ConstantFP::get(llvmType, floatAttr.getValue()); 90*5d7231d8SStephan Herhut if (auto funcAttr = attr.dyn_cast<FunctionAttr>()) 91*5d7231d8SStephan Herhut return functionMapping.lookup(funcAttr.getValue()); 92*5d7231d8SStephan Herhut if (auto splatAttr = attr.dyn_cast<SplatElementsAttr>()) { 93*5d7231d8SStephan Herhut auto *vectorType = cast<llvm::VectorType>(llvmType); 94*5d7231d8SStephan Herhut auto *child = getLLVMConstant(vectorType->getElementType(), 95*5d7231d8SStephan Herhut splatAttr.getValue(), loc); 96*5d7231d8SStephan Herhut return llvm::ConstantVector::getSplat(vectorType->getNumElements(), child); 97*5d7231d8SStephan Herhut } 98*5d7231d8SStephan Herhut if (auto denseAttr = attr.dyn_cast<DenseElementsAttr>()) { 99*5d7231d8SStephan Herhut auto *vectorType = cast<llvm::VectorType>(llvmType); 100*5d7231d8SStephan Herhut SmallVector<llvm::Constant *, 8> constants; 101*5d7231d8SStephan Herhut uint64_t numElements = vectorType->getNumElements(); 102*5d7231d8SStephan Herhut constants.reserve(numElements); 103*5d7231d8SStephan Herhut SmallVector<Attribute, 8> nested; 104*5d7231d8SStephan Herhut denseAttr.getValues(nested); 105*5d7231d8SStephan Herhut for (auto n : nested) { 106*5d7231d8SStephan Herhut constants.push_back( 107*5d7231d8SStephan Herhut getLLVMConstant(vectorType->getElementType(), n, loc)); 108*5d7231d8SStephan Herhut if (!constants.back()) 109*5d7231d8SStephan Herhut return nullptr; 110*5d7231d8SStephan Herhut } 111*5d7231d8SStephan Herhut return llvm::ConstantVector::get(constants); 112*5d7231d8SStephan Herhut } 113*5d7231d8SStephan Herhut mlirModule.getContext()->emitError(loc, "unsupported constant value"); 114*5d7231d8SStephan Herhut return nullptr; 115*5d7231d8SStephan Herhut } 116*5d7231d8SStephan Herhut 117*5d7231d8SStephan Herhut // Convert MLIR integer comparison predicate to LLVM IR comparison predicate. 118*5d7231d8SStephan Herhut static llvm::CmpInst::Predicate getLLVMCmpPredicate(CmpIPredicate p) { 119*5d7231d8SStephan Herhut switch (p) { 120*5d7231d8SStephan Herhut case CmpIPredicate::EQ: 121*5d7231d8SStephan Herhut return llvm::CmpInst::Predicate::ICMP_EQ; 122*5d7231d8SStephan Herhut case CmpIPredicate::NE: 123*5d7231d8SStephan Herhut return llvm::CmpInst::Predicate::ICMP_NE; 124*5d7231d8SStephan Herhut case CmpIPredicate::SLT: 125*5d7231d8SStephan Herhut return llvm::CmpInst::Predicate::ICMP_SLT; 126*5d7231d8SStephan Herhut case CmpIPredicate::SLE: 127*5d7231d8SStephan Herhut return llvm::CmpInst::Predicate::ICMP_SLE; 128*5d7231d8SStephan Herhut case CmpIPredicate::SGT: 129*5d7231d8SStephan Herhut return llvm::CmpInst::Predicate::ICMP_SGT; 130*5d7231d8SStephan Herhut case CmpIPredicate::SGE: 131*5d7231d8SStephan Herhut return llvm::CmpInst::Predicate::ICMP_SGE; 132*5d7231d8SStephan Herhut case CmpIPredicate::ULT: 133*5d7231d8SStephan Herhut return llvm::CmpInst::Predicate::ICMP_ULT; 134*5d7231d8SStephan Herhut case CmpIPredicate::ULE: 135*5d7231d8SStephan Herhut return llvm::CmpInst::Predicate::ICMP_ULE; 136*5d7231d8SStephan Herhut case CmpIPredicate::UGT: 137*5d7231d8SStephan Herhut return llvm::CmpInst::Predicate::ICMP_UGT; 138*5d7231d8SStephan Herhut case CmpIPredicate::UGE: 139*5d7231d8SStephan Herhut return llvm::CmpInst::Predicate::ICMP_UGE; 140*5d7231d8SStephan Herhut default: 141*5d7231d8SStephan Herhut llvm_unreachable("incorrect comparison predicate"); 142*5d7231d8SStephan Herhut } 143*5d7231d8SStephan Herhut } 144*5d7231d8SStephan Herhut 145*5d7231d8SStephan Herhut // A helper to look up remapped operands in the value remapping table. 146*5d7231d8SStephan Herhut template <typename Range> 147*5d7231d8SStephan Herhut SmallVector<llvm::Value *, 8> ModuleTranslation::lookupValues(Range &&values) { 148*5d7231d8SStephan Herhut SmallVector<llvm::Value *, 8> remapped; 149*5d7231d8SStephan Herhut remapped.reserve(llvm::size(values)); 150*5d7231d8SStephan Herhut for (Value *v : values) { 151*5d7231d8SStephan Herhut remapped.push_back(valueMapping.lookup(v)); 152*5d7231d8SStephan Herhut } 153*5d7231d8SStephan Herhut return remapped; 154*5d7231d8SStephan Herhut } 155*5d7231d8SStephan Herhut 156*5d7231d8SStephan Herhut // Given a single MLIR operation, create the corresponding LLVM IR operation 157*5d7231d8SStephan Herhut // using the `builder`. LLVM IR Builder does not have a generic interface so 158*5d7231d8SStephan Herhut // this has to be a long chain of `if`s calling different functions with a 159*5d7231d8SStephan Herhut // different number of arguments. 160*5d7231d8SStephan Herhut bool ModuleTranslation::convertOperation(Operation &opInst, 161*5d7231d8SStephan Herhut llvm::IRBuilder<> &builder) { 162*5d7231d8SStephan Herhut auto extractPosition = [](ArrayAttr attr) { 163*5d7231d8SStephan Herhut SmallVector<unsigned, 4> position; 164*5d7231d8SStephan Herhut position.reserve(attr.size()); 165*5d7231d8SStephan Herhut for (Attribute v : attr) 166*5d7231d8SStephan Herhut position.push_back(v.cast<IntegerAttr>().getValue().getZExtValue()); 167*5d7231d8SStephan Herhut return position; 168*5d7231d8SStephan Herhut }; 169*5d7231d8SStephan Herhut 170*5d7231d8SStephan Herhut #include "mlir/LLVMIR/LLVMConversions.inc" 171*5d7231d8SStephan Herhut 172*5d7231d8SStephan Herhut // Emit function calls. If the "callee" attribute is present, this is a 173*5d7231d8SStephan Herhut // direct function call and we also need to look up the remapped function 174*5d7231d8SStephan Herhut // itself. Otherwise, this is an indirect call and the callee is the first 175*5d7231d8SStephan Herhut // operand, look it up as a normal value. Return the llvm::Value representing 176*5d7231d8SStephan Herhut // the function result, which may be of llvm::VoidTy type. 177*5d7231d8SStephan Herhut auto convertCall = [this, &builder](Operation &op) -> llvm::Value * { 178*5d7231d8SStephan Herhut auto operands = lookupValues(op.getOperands()); 179*5d7231d8SStephan Herhut ArrayRef<llvm::Value *> operandsRef(operands); 180*5d7231d8SStephan Herhut if (auto attr = op.getAttrOfType<FunctionAttr>("callee")) { 181*5d7231d8SStephan Herhut return builder.CreateCall(functionMapping.lookup(attr.getValue()), 182*5d7231d8SStephan Herhut operandsRef); 183*5d7231d8SStephan Herhut } else { 184*5d7231d8SStephan Herhut return builder.CreateCall(operandsRef.front(), operandsRef.drop_front()); 185*5d7231d8SStephan Herhut } 186*5d7231d8SStephan Herhut }; 187*5d7231d8SStephan Herhut 188*5d7231d8SStephan Herhut // Emit calls. If the called function has a result, remap the corresponding 189*5d7231d8SStephan Herhut // value. Note that LLVM IR dialect CallOp has either 0 or 1 result. 190*5d7231d8SStephan Herhut if (opInst.isa<LLVM::CallOp>()) { 191*5d7231d8SStephan Herhut llvm::Value *result = convertCall(opInst); 192*5d7231d8SStephan Herhut if (opInst.getNumResults() != 0) { 193*5d7231d8SStephan Herhut valueMapping[opInst.getResult(0)] = result; 194*5d7231d8SStephan Herhut return false; 195*5d7231d8SStephan Herhut } 196*5d7231d8SStephan Herhut // Check that LLVM call returns void for 0-result functions. 197*5d7231d8SStephan Herhut return !result->getType()->isVoidTy(); 198*5d7231d8SStephan Herhut } 199*5d7231d8SStephan Herhut 200*5d7231d8SStephan Herhut // Emit branches. We need to look up the remapped blocks and ignore the block 201*5d7231d8SStephan Herhut // arguments that were transformed into PHI nodes. 202*5d7231d8SStephan Herhut if (auto brOp = opInst.dyn_cast<LLVM::BrOp>()) { 203*5d7231d8SStephan Herhut builder.CreateBr(blockMapping[brOp.getSuccessor(0)]); 204*5d7231d8SStephan Herhut return false; 205*5d7231d8SStephan Herhut } 206*5d7231d8SStephan Herhut if (auto condbrOp = opInst.dyn_cast<LLVM::CondBrOp>()) { 207*5d7231d8SStephan Herhut builder.CreateCondBr(valueMapping.lookup(condbrOp.getOperand(0)), 208*5d7231d8SStephan Herhut blockMapping[condbrOp.getSuccessor(0)], 209*5d7231d8SStephan Herhut blockMapping[condbrOp.getSuccessor(1)]); 210*5d7231d8SStephan Herhut return false; 211*5d7231d8SStephan Herhut } 212*5d7231d8SStephan Herhut 213*5d7231d8SStephan Herhut opInst.emitError("unsupported or non-LLVM operation: " + 214*5d7231d8SStephan Herhut opInst.getName().getStringRef()); 215*5d7231d8SStephan Herhut return true; 216*5d7231d8SStephan Herhut } 217*5d7231d8SStephan Herhut 218*5d7231d8SStephan Herhut // Convert block to LLVM IR. Unless `ignoreArguments` is set, emit PHI nodes 219*5d7231d8SStephan Herhut // to define values corresponding to the MLIR block arguments. These nodes 220*5d7231d8SStephan Herhut // are not connected to the source basic blocks, which may not exist yet. 221*5d7231d8SStephan Herhut bool ModuleTranslation::convertBlock(Block &bb, bool ignoreArguments) { 222*5d7231d8SStephan Herhut llvm::IRBuilder<> builder(blockMapping[&bb]); 223*5d7231d8SStephan Herhut 224*5d7231d8SStephan Herhut // Before traversing operations, make block arguments available through 225*5d7231d8SStephan Herhut // value remapping and PHI nodes, but do not add incoming edges for the PHI 226*5d7231d8SStephan Herhut // nodes just yet: those values may be defined by this or following blocks. 227*5d7231d8SStephan Herhut // This step is omitted if "ignoreArguments" is set. The arguments of the 228*5d7231d8SStephan Herhut // first block have been already made available through the remapping of 229*5d7231d8SStephan Herhut // LLVM function arguments. 230*5d7231d8SStephan Herhut if (!ignoreArguments) { 231*5d7231d8SStephan Herhut auto predecessors = bb.getPredecessors(); 232*5d7231d8SStephan Herhut unsigned numPredecessors = 233*5d7231d8SStephan Herhut std::distance(predecessors.begin(), predecessors.end()); 234*5d7231d8SStephan Herhut for (auto *arg : bb.getArguments()) { 235*5d7231d8SStephan Herhut auto wrappedType = arg->getType().dyn_cast<LLVM::LLVMType>(); 236*5d7231d8SStephan Herhut if (!wrappedType) { 237*5d7231d8SStephan Herhut arg->getType().getContext()->emitError( 238*5d7231d8SStephan Herhut bb.front().getLoc(), "block argument does not have an LLVM type"); 239*5d7231d8SStephan Herhut return true; 240*5d7231d8SStephan Herhut } 241*5d7231d8SStephan Herhut llvm::Type *type = wrappedType.getUnderlyingType(); 242*5d7231d8SStephan Herhut llvm::PHINode *phi = builder.CreatePHI(type, numPredecessors); 243*5d7231d8SStephan Herhut valueMapping[arg] = phi; 244*5d7231d8SStephan Herhut } 245*5d7231d8SStephan Herhut } 246*5d7231d8SStephan Herhut 247*5d7231d8SStephan Herhut // Traverse operations. 248*5d7231d8SStephan Herhut for (auto &op : bb) { 249*5d7231d8SStephan Herhut if (convertOperation(op, builder)) 250*5d7231d8SStephan Herhut return true; 251*5d7231d8SStephan Herhut } 252*5d7231d8SStephan Herhut 253*5d7231d8SStephan Herhut return false; 254*5d7231d8SStephan Herhut } 255*5d7231d8SStephan Herhut 256*5d7231d8SStephan Herhut // Get the SSA value passed to the current block from the terminator operation 257*5d7231d8SStephan Herhut // of its predecessor. 258*5d7231d8SStephan Herhut static Value *getPHISourceValue(Block *current, Block *pred, 259*5d7231d8SStephan Herhut unsigned numArguments, unsigned index) { 260*5d7231d8SStephan Herhut auto &terminator = *pred->getTerminator(); 261*5d7231d8SStephan Herhut if (terminator.isa<LLVM::BrOp>()) { 262*5d7231d8SStephan Herhut return terminator.getOperand(index); 263*5d7231d8SStephan Herhut } 264*5d7231d8SStephan Herhut 265*5d7231d8SStephan Herhut // For conditional branches, we need to check if the current block is reached 266*5d7231d8SStephan Herhut // through the "true" or the "false" branch and take the relevant operands. 267*5d7231d8SStephan Herhut auto condBranchOp = terminator.dyn_cast<LLVM::CondBrOp>(); 268*5d7231d8SStephan Herhut assert(condBranchOp && 269*5d7231d8SStephan Herhut "only branch operations can be terminators of a block that " 270*5d7231d8SStephan Herhut "has successors"); 271*5d7231d8SStephan Herhut assert((condBranchOp.getSuccessor(0) != condBranchOp.getSuccessor(1)) && 272*5d7231d8SStephan Herhut "successors with arguments in LLVM conditional branches must be " 273*5d7231d8SStephan Herhut "different blocks"); 274*5d7231d8SStephan Herhut 275*5d7231d8SStephan Herhut return condBranchOp.getSuccessor(0) == current 276*5d7231d8SStephan Herhut ? terminator.getSuccessorOperand(0, index) 277*5d7231d8SStephan Herhut : terminator.getSuccessorOperand(1, index); 278*5d7231d8SStephan Herhut } 279*5d7231d8SStephan Herhut 280*5d7231d8SStephan Herhut void ModuleTranslation::connectPHINodes(Function &func) { 281*5d7231d8SStephan Herhut // Skip the first block, it cannot be branched to and its arguments correspond 282*5d7231d8SStephan Herhut // to the arguments of the LLVM function. 283*5d7231d8SStephan Herhut for (auto it = std::next(func.begin()), eit = func.end(); it != eit; ++it) { 284*5d7231d8SStephan Herhut Block *bb = &*it; 285*5d7231d8SStephan Herhut llvm::BasicBlock *llvmBB = blockMapping.lookup(bb); 286*5d7231d8SStephan Herhut auto phis = llvmBB->phis(); 287*5d7231d8SStephan Herhut auto numArguments = bb->getNumArguments(); 288*5d7231d8SStephan Herhut assert(numArguments == std::distance(phis.begin(), phis.end())); 289*5d7231d8SStephan Herhut for (auto &numberedPhiNode : llvm::enumerate(phis)) { 290*5d7231d8SStephan Herhut auto &phiNode = numberedPhiNode.value(); 291*5d7231d8SStephan Herhut unsigned index = numberedPhiNode.index(); 292*5d7231d8SStephan Herhut for (auto *pred : bb->getPredecessors()) { 293*5d7231d8SStephan Herhut phiNode.addIncoming(valueMapping.lookup(getPHISourceValue( 294*5d7231d8SStephan Herhut bb, pred, numArguments, index)), 295*5d7231d8SStephan Herhut blockMapping.lookup(pred)); 296*5d7231d8SStephan Herhut } 297*5d7231d8SStephan Herhut } 298*5d7231d8SStephan Herhut } 299*5d7231d8SStephan Herhut } 300*5d7231d8SStephan Herhut 301*5d7231d8SStephan Herhut // TODO(mlir-team): implement an iterative version 302*5d7231d8SStephan Herhut static void topologicalSortImpl(llvm::SetVector<Block *> &blocks, Block *b) { 303*5d7231d8SStephan Herhut blocks.insert(b); 304*5d7231d8SStephan Herhut for (Block *bb : b->getSuccessors()) { 305*5d7231d8SStephan Herhut if (blocks.count(bb) == 0) 306*5d7231d8SStephan Herhut topologicalSortImpl(blocks, bb); 307*5d7231d8SStephan Herhut } 308*5d7231d8SStephan Herhut } 309*5d7231d8SStephan Herhut 310*5d7231d8SStephan Herhut // Sort function blocks topologically. 311*5d7231d8SStephan Herhut static llvm::SetVector<Block *> topologicalSort(Function &f) { 312*5d7231d8SStephan Herhut // For each blocks that has not been visited yet (i.e. that has no 313*5d7231d8SStephan Herhut // predecessors), add it to the list and traverse its successors in DFS 314*5d7231d8SStephan Herhut // preorder. 315*5d7231d8SStephan Herhut llvm::SetVector<Block *> blocks; 316*5d7231d8SStephan Herhut for (Block &b : f.getBlocks()) { 317*5d7231d8SStephan Herhut if (blocks.count(&b) == 0) 318*5d7231d8SStephan Herhut topologicalSortImpl(blocks, &b); 319*5d7231d8SStephan Herhut } 320*5d7231d8SStephan Herhut assert(blocks.size() == f.getBlocks().size() && "some blocks are not sorted"); 321*5d7231d8SStephan Herhut 322*5d7231d8SStephan Herhut return blocks; 323*5d7231d8SStephan Herhut } 324*5d7231d8SStephan Herhut 325*5d7231d8SStephan Herhut bool ModuleTranslation::convertOneFunction(Function &func) { 326*5d7231d8SStephan Herhut // Clear the block and value mappings, they are only relevant within one 327*5d7231d8SStephan Herhut // function. 328*5d7231d8SStephan Herhut blockMapping.clear(); 329*5d7231d8SStephan Herhut valueMapping.clear(); 330*5d7231d8SStephan Herhut llvm::Function *llvmFunc = functionMapping.lookup(&func); 331*5d7231d8SStephan Herhut // Add function arguments to the value remapping table. 332*5d7231d8SStephan Herhut // If there was noalias info then we decorate each argument accordingly. 333*5d7231d8SStephan Herhut unsigned int argIdx = 0; 334*5d7231d8SStephan Herhut for (const auto &kvp : llvm::zip(func.getArguments(), llvmFunc->args())) { 335*5d7231d8SStephan Herhut llvm::Argument &llvmArg = std::get<1>(kvp); 336*5d7231d8SStephan Herhut BlockArgument *mlirArg = std::get<0>(kvp); 337*5d7231d8SStephan Herhut 338*5d7231d8SStephan Herhut if (auto attr = func.getArgAttrOfType<BoolAttr>(argIdx, "llvm.noalias")) { 339*5d7231d8SStephan Herhut // NB: Attribute already verified to be boolean, so check if we can indeed 340*5d7231d8SStephan Herhut // attach the attribute to this argument, based on its type. 341*5d7231d8SStephan Herhut auto argTy = mlirArg->getType().dyn_cast<LLVM::LLVMType>(); 342*5d7231d8SStephan Herhut if (!argTy.getUnderlyingType()->isPointerTy()) 343*5d7231d8SStephan Herhut return argTy.getContext()->emitError( 344*5d7231d8SStephan Herhut func.getLoc(), 345*5d7231d8SStephan Herhut "llvm.noalias attribute attached to LLVM non-pointer argument"); 346*5d7231d8SStephan Herhut if (attr.getValue()) 347*5d7231d8SStephan Herhut llvmArg.addAttr(llvm::Attribute::AttrKind::NoAlias); 348*5d7231d8SStephan Herhut } 349*5d7231d8SStephan Herhut valueMapping[mlirArg] = &llvmArg; 350*5d7231d8SStephan Herhut argIdx++; 351*5d7231d8SStephan Herhut } 352*5d7231d8SStephan Herhut 353*5d7231d8SStephan Herhut // First, create all blocks so we can jump to them. 354*5d7231d8SStephan Herhut llvm::LLVMContext &llvmContext = llvmFunc->getContext(); 355*5d7231d8SStephan Herhut for (auto &bb : func) { 356*5d7231d8SStephan Herhut auto *llvmBB = llvm::BasicBlock::Create(llvmContext); 357*5d7231d8SStephan Herhut llvmBB->insertInto(llvmFunc); 358*5d7231d8SStephan Herhut blockMapping[&bb] = llvmBB; 359*5d7231d8SStephan Herhut } 360*5d7231d8SStephan Herhut 361*5d7231d8SStephan Herhut // Then, convert blocks one by one in topological order to ensure defs are 362*5d7231d8SStephan Herhut // converted before uses. 363*5d7231d8SStephan Herhut auto blocks = topologicalSort(func); 364*5d7231d8SStephan Herhut for (auto indexedBB : llvm::enumerate(blocks)) { 365*5d7231d8SStephan Herhut auto *bb = indexedBB.value(); 366*5d7231d8SStephan Herhut if (convertBlock(*bb, /*ignoreArguments=*/indexedBB.index() == 0)) 367*5d7231d8SStephan Herhut return true; 368*5d7231d8SStephan Herhut } 369*5d7231d8SStephan Herhut 370*5d7231d8SStephan Herhut // Finally, after all blocks have been traversed and values mapped, connect 371*5d7231d8SStephan Herhut // the PHI nodes to the results of preceding blocks. 372*5d7231d8SStephan Herhut connectPHINodes(func); 373*5d7231d8SStephan Herhut return false; 374*5d7231d8SStephan Herhut } 375*5d7231d8SStephan Herhut 376*5d7231d8SStephan Herhut bool ModuleTranslation::convertFunctions() { 377*5d7231d8SStephan Herhut // Declare all functions first because there may be function calls that form a 378*5d7231d8SStephan Herhut // call graph with cycles. 379*5d7231d8SStephan Herhut for (Function &function : mlirModule) { 380*5d7231d8SStephan Herhut Function *functionPtr = &function; 381*5d7231d8SStephan Herhut mlir::BoolAttr isVarArgsAttr = 382*5d7231d8SStephan Herhut function.getAttrOfType<BoolAttr>("std.varargs"); 383*5d7231d8SStephan Herhut bool isVarArgs = isVarArgsAttr && isVarArgsAttr.getValue(); 384*5d7231d8SStephan Herhut llvm::FunctionType *functionType = 385*5d7231d8SStephan Herhut convertFunctionType(llvmModule->getContext(), function.getType(), 386*5d7231d8SStephan Herhut function.getLoc(), isVarArgs); 387*5d7231d8SStephan Herhut if (!functionType) 388*5d7231d8SStephan Herhut return true; 389*5d7231d8SStephan Herhut llvm::FunctionCallee llvmFuncCst = 390*5d7231d8SStephan Herhut llvmModule->getOrInsertFunction(function.getName(), functionType); 391*5d7231d8SStephan Herhut assert(isa<llvm::Function>(llvmFuncCst.getCallee())); 392*5d7231d8SStephan Herhut functionMapping[functionPtr] = 393*5d7231d8SStephan Herhut cast<llvm::Function>(llvmFuncCst.getCallee()); 394*5d7231d8SStephan Herhut } 395*5d7231d8SStephan Herhut 396*5d7231d8SStephan Herhut // Convert functions. 397*5d7231d8SStephan Herhut for (Function &function : mlirModule) { 398*5d7231d8SStephan Herhut // Ignore external functions. 399*5d7231d8SStephan Herhut if (function.isExternal()) 400*5d7231d8SStephan Herhut continue; 401*5d7231d8SStephan Herhut 402*5d7231d8SStephan Herhut if (convertOneFunction(function)) 403*5d7231d8SStephan Herhut return true; 404*5d7231d8SStephan Herhut } 405*5d7231d8SStephan Herhut 406*5d7231d8SStephan Herhut return false; 407*5d7231d8SStephan Herhut } 408*5d7231d8SStephan Herhut 409*5d7231d8SStephan Herhut std::unique_ptr<llvm::Module> ModuleTranslation::prepareLLVMModule(Module &m) { 410*5d7231d8SStephan Herhut Dialect *dialect = m.getContext()->getRegisteredDialect("llvm"); 411*5d7231d8SStephan Herhut assert(dialect && "LLVM dialect must be registered"); 412*5d7231d8SStephan Herhut auto *llvmDialect = static_cast<LLVM::LLVMDialect *>(dialect); 413*5d7231d8SStephan Herhut 414*5d7231d8SStephan Herhut auto llvmModule = llvm::CloneModule(llvmDialect->getLLVMModule()); 415*5d7231d8SStephan Herhut if (!llvmModule) 416*5d7231d8SStephan Herhut return nullptr; 417*5d7231d8SStephan Herhut 418*5d7231d8SStephan Herhut llvm::LLVMContext &llvmContext = llvmModule->getContext(); 419*5d7231d8SStephan Herhut llvm::IRBuilder<> builder(llvmContext); 420*5d7231d8SStephan Herhut 421*5d7231d8SStephan Herhut // Inject declarations for `malloc` and `free` functions that can be used in 422*5d7231d8SStephan Herhut // memref allocation/deallocation coming from standard ops lowering. 423*5d7231d8SStephan Herhut llvmModule->getOrInsertFunction("malloc", builder.getInt8PtrTy(), 424*5d7231d8SStephan Herhut builder.getInt64Ty()); 425*5d7231d8SStephan Herhut llvmModule->getOrInsertFunction("free", builder.getVoidTy(), 426*5d7231d8SStephan Herhut builder.getInt8PtrTy()); 427*5d7231d8SStephan Herhut 428*5d7231d8SStephan Herhut return llvmModule; 429*5d7231d8SStephan Herhut } 430*5d7231d8SStephan Herhut 431*5d7231d8SStephan Herhut } // namespace LLVM 432*5d7231d8SStephan Herhut } // namespace mlir 433