| //===- subzero/src/IceConverter.cpp - Converts LLVM to Ice ---------------===// | |
| // | |
| // The Subzero Code Generator | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| /// | |
| /// \file | |
| /// \brief Implements the LLVM to ICE converter. | |
| /// | |
| //===----------------------------------------------------------------------===// | |
| #include "IceConverter.h" | |
| #include "IceCfg.h" | |
| #include "IceCfgNode.h" | |
| #include "IceClFlags.h" | |
| #include "IceDefs.h" | |
| #include "IceGlobalContext.h" | |
| #include "IceGlobalInits.h" | |
| #include "IceInst.h" | |
| #include "IceMangling.h" | |
| #include "IceOperand.h" | |
| #include "IceTargetLowering.h" | |
| #include "IceTypeConverter.h" | |
| #include "IceTypes.h" | |
| #ifdef __clang__ | |
| #pragma clang diagnostic push | |
| #pragma clang diagnostic ignored "-Wunused-parameter" | |
| #endif // __clang__ | |
| #include "llvm/IR/Constant.h" | |
| #include "llvm/IR/Constants.h" | |
| #include "llvm/IR/DataLayout.h" | |
| #include "llvm/IR/Instruction.h" | |
| #include "llvm/IR/Instructions.h" | |
| #include "llvm/IR/LLVMContext.h" | |
| #include "llvm/IR/Module.h" | |
| #ifdef __clang__ | |
| #pragma clang diagnostic pop | |
| #endif // __clang__ | |
| // TODO(kschimpf): Remove two namespaces being visible at once. | |
| using namespace llvm; | |
| namespace { | |
| // Debugging helper | |
| template <typename T> static std::string LLVMObjectAsString(const T *O) { | |
| std::string Dump; | |
| raw_string_ostream Stream(Dump); | |
| O->print(Stream); | |
| return Stream.str(); | |
| } | |
| // Base class for converting LLVM to ICE. | |
| // TODO(stichnot): Redesign Converter, LLVM2ICEConverter, | |
| // LLVM2ICEFunctionConverter, and LLVM2ICEGlobalsConverter with respect to | |
| // Translator. In particular, the unique_ptr ownership rules in | |
| // LLVM2ICEFunctionConverter. | |
| class LLVM2ICEConverter { | |
| LLVM2ICEConverter() = delete; | |
| LLVM2ICEConverter(const LLVM2ICEConverter &) = delete; | |
| LLVM2ICEConverter &operator=(const LLVM2ICEConverter &) = delete; | |
| public: | |
| explicit LLVM2ICEConverter(Ice::Converter &Converter) | |
| : Converter(Converter), Ctx(Converter.getContext()), | |
| TypeConverter(Converter.getModule()->getContext()) {} | |
| Ice::Converter &getConverter() const { return Converter; } | |
| protected: | |
| Ice::Converter &Converter; | |
| Ice::GlobalContext *Ctx; | |
| const Ice::TypeConverter TypeConverter; | |
| }; | |
| // Converter from LLVM functions to ICE. The entry point is the convertFunction | |
| // method. | |
| // | |
| // Note: this currently assumes that the given IR was verified to be valid | |
| // PNaCl bitcode. Otherwise, the behavior is undefined. | |
| class LLVM2ICEFunctionConverter : LLVM2ICEConverter { | |
| LLVM2ICEFunctionConverter() = delete; | |
| LLVM2ICEFunctionConverter(const LLVM2ICEFunctionConverter &) = delete; | |
| LLVM2ICEFunctionConverter & | |
| operator=(const LLVM2ICEFunctionConverter &) = delete; | |
| public: | |
| explicit LLVM2ICEFunctionConverter(Ice::Converter &Converter) | |
| : LLVM2ICEConverter(Converter), Func(nullptr) {} | |
| void convertFunction(const Function *F) { | |
| Func = Ice::Cfg::create(Ctx, Converter.getNextSequenceNumber()); | |
| { | |
| Ice::CfgLocalAllocatorScope _(Func.get()); | |
| VarMap.clear(); | |
| NodeMap.clear(); | |
| Func->setFunctionName( | |
| Ctx->getGlobalString(Ice::mangleName(F->getName()))); | |
| Func->setReturnType(convertToIceType(F->getReturnType())); | |
| Func->setInternal(F->hasInternalLinkage()); | |
| Ice::TimerMarker T(Ice::TimerStack::TT_llvmConvert, Func.get()); | |
| // The initial definition/use of each arg is the entry node. | |
| for (auto ArgI = F->arg_begin(), ArgE = F->arg_end(); ArgI != ArgE; | |
| ++ArgI) { | |
| Func->addArg(mapValueToIceVar(&*ArgI)); | |
| } | |
| // Make an initial pass through the block list just to resolve the blocks | |
| // in the original linearized order. Otherwise the ICE linearized order | |
| // will be affected by branch targets in terminator instructions. | |
| for (const BasicBlock &BBI : *F) | |
| mapBasicBlockToNode(&BBI); | |
| for (const BasicBlock &BBI : *F) | |
| convertBasicBlock(&BBI); | |
| Func->setEntryNode(mapBasicBlockToNode(&F->getEntryBlock())); | |
| Func->computeInOutEdges(); | |
| } | |
| Converter.translateFcn(std::move(Func)); | |
| } | |
| // convertConstant() does not use Func or require it to be a valid Ice::Cfg | |
| // pointer. As such, it's suitable for e.g. constructing global initializers. | |
| Ice::Constant *convertConstant(const Constant *Const) { | |
| if (const auto GV = dyn_cast<GlobalValue>(Const)) { | |
| Ice::GlobalDeclaration *Decl = getConverter().getGlobalDeclaration(GV); | |
| bool IsUndefined = false; | |
| if (const auto *Func = llvm::dyn_cast<Ice::FunctionDeclaration>(Decl)) | |
| IsUndefined = Func->isProto(); | |
| else if (const auto *Var = llvm::dyn_cast<Ice::VariableDeclaration>(Decl)) | |
| IsUndefined = !Var->hasInitializer(); | |
| else | |
| report_fatal_error("Unhandled GlobalDeclaration type"); | |
| if (IsUndefined) | |
| return Ctx->getConstantExternSym(Decl->getName()); | |
| else { | |
| const Ice::RelocOffsetT Offset = 0; | |
| return Ctx->getConstantSym( | |
| Offset, Ctx->getGlobalString(Decl->getName().toString())); | |
| } | |
| } else if (const auto CI = dyn_cast<ConstantInt>(Const)) { | |
| Ice::Type Ty = convertToIceType(CI->getType()); | |
| return Ctx->getConstantInt(Ty, CI->getSExtValue()); | |
| } else if (const auto CFP = dyn_cast<ConstantFP>(Const)) { | |
| Ice::Type Type = convertToIceType(CFP->getType()); | |
| if (Type == Ice::IceType_f32) | |
| return Ctx->getConstantFloat(CFP->getValueAPF().convertToFloat()); | |
| else if (Type == Ice::IceType_f64) | |
| return Ctx->getConstantDouble(CFP->getValueAPF().convertToDouble()); | |
| llvm_unreachable("Unexpected floating point type"); | |
| return nullptr; | |
| } else if (const auto CU = dyn_cast<UndefValue>(Const)) { | |
| return Ctx->getConstantUndef(convertToIceType(CU->getType())); | |
| } else { | |
| llvm_unreachable("Unhandled constant type"); | |
| return nullptr; | |
| } | |
| } | |
| private: | |
| // LLVM values (instructions, etc.) are mapped directly to ICE variables. | |
| // mapValueToIceVar has a version that forces an ICE type on the variable, | |
| // and a version that just uses convertToIceType on V. | |
| Ice::Variable *mapValueToIceVar(const Value *V, Ice::Type IceTy) { | |
| if (IceTy == Ice::IceType_void) | |
| return nullptr; | |
| if (VarMap.find(V) == VarMap.end()) { | |
| VarMap[V] = Func->makeVariable(IceTy); | |
| if (Ice::BuildDefs::dump()) | |
| VarMap[V]->setName(Func.get(), V->getName()); | |
| } | |
| return VarMap[V]; | |
| } | |
| Ice::Variable *mapValueToIceVar(const Value *V) { | |
| return mapValueToIceVar(V, convertToIceType(V->getType())); | |
| } | |
| Ice::CfgNode *mapBasicBlockToNode(const BasicBlock *BB) { | |
| if (NodeMap.find(BB) == NodeMap.end()) { | |
| NodeMap[BB] = Func->makeNode(); | |
| if (Ice::BuildDefs::dump()) | |
| NodeMap[BB]->setName(BB->getName()); | |
| } | |
| return NodeMap[BB]; | |
| } | |
| Ice::Type convertToIceType(Type *LLVMTy) const { | |
| Ice::Type IceTy = TypeConverter.convertToIceType(LLVMTy); | |
| if (IceTy == Ice::IceType_NUM) | |
| report_fatal_error(std::string("Invalid PNaCl type ") + | |
| LLVMObjectAsString(LLVMTy)); | |
| return IceTy; | |
| } | |
| // Given an LLVM instruction and an operand number, produce the Ice::Operand | |
| // this refers to. If there's no such operand, return nullptr. | |
| Ice::Operand *convertOperand(const Instruction *Instr, unsigned OpNum) { | |
| if (OpNum >= Instr->getNumOperands()) { | |
| return nullptr; | |
| } | |
| const Value *Op = Instr->getOperand(OpNum); | |
| return convertValue(Op); | |
| } | |
| Ice::Operand *convertValue(const Value *Op) { | |
| if (const auto Const = dyn_cast<Constant>(Op)) { | |
| return convertConstant(Const); | |
| } else { | |
| return mapValueToIceVar(Op); | |
| } | |
| } | |
| // Note: this currently assumes a 1x1 mapping between LLVM IR and Ice | |
| // instructions. | |
| Ice::Inst *convertInstruction(const Instruction *Instr) { | |
| switch (Instr->getOpcode()) { | |
| case Instruction::PHI: | |
| return convertPHINodeInstruction(cast<PHINode>(Instr)); | |
| case Instruction::Br: | |
| return convertBrInstruction(cast<BranchInst>(Instr)); | |
| case Instruction::Ret: | |
| return convertRetInstruction(cast<ReturnInst>(Instr)); | |
| case Instruction::IntToPtr: | |
| return convertIntToPtrInstruction(cast<IntToPtrInst>(Instr)); | |
| case Instruction::PtrToInt: | |
| return convertPtrToIntInstruction(cast<PtrToIntInst>(Instr)); | |
| case Instruction::ICmp: | |
| return convertICmpInstruction(cast<ICmpInst>(Instr)); | |
| case Instruction::FCmp: | |
| return convertFCmpInstruction(cast<FCmpInst>(Instr)); | |
| case Instruction::Select: | |
| return convertSelectInstruction(cast<SelectInst>(Instr)); | |
| case Instruction::Switch: | |
| return convertSwitchInstruction(cast<SwitchInst>(Instr)); | |
| case Instruction::Load: | |
| return convertLoadInstruction(cast<LoadInst>(Instr)); | |
| case Instruction::Store: | |
| return convertStoreInstruction(cast<StoreInst>(Instr)); | |
| case Instruction::ZExt: | |
| return convertCastInstruction(cast<ZExtInst>(Instr), Ice::InstCast::Zext); | |
| case Instruction::SExt: | |
| return convertCastInstruction(cast<SExtInst>(Instr), Ice::InstCast::Sext); | |
| case Instruction::Trunc: | |
| return convertCastInstruction(cast<TruncInst>(Instr), | |
| Ice::InstCast::Trunc); | |
| case Instruction::FPTrunc: | |
| return convertCastInstruction(cast<FPTruncInst>(Instr), | |
| Ice::InstCast::Fptrunc); | |
| case Instruction::FPExt: | |
| return convertCastInstruction(cast<FPExtInst>(Instr), | |
| Ice::InstCast::Fpext); | |
| case Instruction::FPToSI: | |
| return convertCastInstruction(cast<FPToSIInst>(Instr), | |
| Ice::InstCast::Fptosi); | |
| case Instruction::FPToUI: | |
| return convertCastInstruction(cast<FPToUIInst>(Instr), | |
| Ice::InstCast::Fptoui); | |
| case Instruction::SIToFP: | |
| return convertCastInstruction(cast<SIToFPInst>(Instr), | |
| Ice::InstCast::Sitofp); | |
| case Instruction::UIToFP: | |
| return convertCastInstruction(cast<UIToFPInst>(Instr), | |
| Ice::InstCast::Uitofp); | |
| case Instruction::BitCast: | |
| return convertCastInstruction(cast<BitCastInst>(Instr), | |
| Ice::InstCast::Bitcast); | |
| case Instruction::Add: | |
| return convertArithInstruction(Instr, Ice::InstArithmetic::Add); | |
| case Instruction::Sub: | |
| return convertArithInstruction(Instr, Ice::InstArithmetic::Sub); | |
| case Instruction::Mul: | |
| return convertArithInstruction(Instr, Ice::InstArithmetic::Mul); | |
| case Instruction::UDiv: | |
| return convertArithInstruction(Instr, Ice::InstArithmetic::Udiv); | |
| case Instruction::SDiv: | |
| return convertArithInstruction(Instr, Ice::InstArithmetic::Sdiv); | |
| case Instruction::URem: | |
| return convertArithInstruction(Instr, Ice::InstArithmetic::Urem); | |
| case Instruction::SRem: | |
| return convertArithInstruction(Instr, Ice::InstArithmetic::Srem); | |
| case Instruction::Shl: | |
| return convertArithInstruction(Instr, Ice::InstArithmetic::Shl); | |
| case Instruction::LShr: | |
| return convertArithInstruction(Instr, Ice::InstArithmetic::Lshr); | |
| case Instruction::AShr: | |
| return convertArithInstruction(Instr, Ice::InstArithmetic::Ashr); | |
| case Instruction::FAdd: | |
| return convertArithInstruction(Instr, Ice::InstArithmetic::Fadd); | |
| case Instruction::FSub: | |
| return convertArithInstruction(Instr, Ice::InstArithmetic::Fsub); | |
| case Instruction::FMul: | |
| return convertArithInstruction(Instr, Ice::InstArithmetic::Fmul); | |
| case Instruction::FDiv: | |
| return convertArithInstruction(Instr, Ice::InstArithmetic::Fdiv); | |
| case Instruction::FRem: | |
| return convertArithInstruction(Instr, Ice::InstArithmetic::Frem); | |
| case Instruction::And: | |
| return convertArithInstruction(Instr, Ice::InstArithmetic::And); | |
| case Instruction::Or: | |
| return convertArithInstruction(Instr, Ice::InstArithmetic::Or); | |
| case Instruction::Xor: | |
| return convertArithInstruction(Instr, Ice::InstArithmetic::Xor); | |
| case Instruction::ExtractElement: | |
| return convertExtractElementInstruction(cast<ExtractElementInst>(Instr)); | |
| case Instruction::InsertElement: | |
| return convertInsertElementInstruction(cast<InsertElementInst>(Instr)); | |
| case Instruction::Call: | |
| return convertCallInstruction(cast<CallInst>(Instr)); | |
| case Instruction::Alloca: | |
| return convertAllocaInstruction(cast<AllocaInst>(Instr)); | |
| case Instruction::Unreachable: | |
| return convertUnreachableInstruction(cast<UnreachableInst>(Instr)); | |
| default: | |
| report_fatal_error(std::string("Invalid PNaCl instruction: ") + | |
| LLVMObjectAsString(Instr)); | |
| } | |
| llvm_unreachable("convertInstruction"); | |
| return nullptr; | |
| } | |
| Ice::Inst *convertLoadInstruction(const LoadInst *Instr) { | |
| Ice::Operand *Src = convertOperand(Instr, 0); | |
| Ice::Variable *Dest = mapValueToIceVar(Instr); | |
| return Ice::InstLoad::create(Func.get(), Dest, Src); | |
| } | |
| Ice::Inst *convertStoreInstruction(const StoreInst *Instr) { | |
| Ice::Operand *Addr = convertOperand(Instr, 1); | |
| Ice::Operand *Val = convertOperand(Instr, 0); | |
| return Ice::InstStore::create(Func.get(), Val, Addr); | |
| } | |
| Ice::Inst *convertArithInstruction(const Instruction *Instr, | |
| Ice::InstArithmetic::OpKind Opcode) { | |
| const auto BinOp = cast<BinaryOperator>(Instr); | |
| Ice::Operand *Src0 = convertOperand(Instr, 0); | |
| Ice::Operand *Src1 = convertOperand(Instr, 1); | |
| Ice::Variable *Dest = mapValueToIceVar(BinOp); | |
| return Ice::InstArithmetic::create(Func.get(), Opcode, Dest, Src0, Src1); | |
| } | |
| Ice::Inst *convertPHINodeInstruction(const PHINode *Instr) { | |
| unsigned NumValues = Instr->getNumIncomingValues(); | |
| Ice::InstPhi *IcePhi = | |
| Ice::InstPhi::create(Func.get(), NumValues, mapValueToIceVar(Instr)); | |
| for (unsigned N = 0, E = NumValues; N != E; ++N) { | |
| IcePhi->addArgument(convertOperand(Instr, N), | |
| mapBasicBlockToNode(Instr->getIncomingBlock(N))); | |
| } | |
| return IcePhi; | |
| } | |
| Ice::Inst *convertBrInstruction(const BranchInst *Instr) { | |
| if (Instr->isConditional()) { | |
| Ice::Operand *Src = convertOperand(Instr, 0); | |
| BasicBlock *BBThen = Instr->getSuccessor(0); | |
| BasicBlock *BBElse = Instr->getSuccessor(1); | |
| Ice::CfgNode *NodeThen = mapBasicBlockToNode(BBThen); | |
| Ice::CfgNode *NodeElse = mapBasicBlockToNode(BBElse); | |
| return Ice::InstBr::create(Func.get(), Src, NodeThen, NodeElse); | |
| } else { | |
| BasicBlock *BBSucc = Instr->getSuccessor(0); | |
| return Ice::InstBr::create(Func.get(), mapBasicBlockToNode(BBSucc)); | |
| } | |
| } | |
| Ice::Inst *convertIntToPtrInstruction(const IntToPtrInst *Instr) { | |
| Ice::Operand *Src = convertOperand(Instr, 0); | |
| Ice::Variable *Dest = mapValueToIceVar(Instr, Ice::getPointerType()); | |
| return Ice::InstAssign::create(Func.get(), Dest, Src); | |
| } | |
| Ice::Inst *convertPtrToIntInstruction(const PtrToIntInst *Instr) { | |
| Ice::Operand *Src = convertOperand(Instr, 0); | |
| Ice::Variable *Dest = mapValueToIceVar(Instr); | |
| return Ice::InstAssign::create(Func.get(), Dest, Src); | |
| } | |
| Ice::Inst *convertRetInstruction(const ReturnInst *Instr) { | |
| Ice::Operand *RetOperand = convertOperand(Instr, 0); | |
| if (RetOperand) { | |
| return Ice::InstRet::create(Func.get(), RetOperand); | |
| } else { | |
| return Ice::InstRet::create(Func.get()); | |
| } | |
| } | |
| Ice::Inst *convertCastInstruction(const Instruction *Instr, | |
| Ice::InstCast::OpKind CastKind) { | |
| Ice::Operand *Src = convertOperand(Instr, 0); | |
| Ice::Variable *Dest = mapValueToIceVar(Instr); | |
| return Ice::InstCast::create(Func.get(), CastKind, Dest, Src); | |
| } | |
| Ice::Inst *convertICmpInstruction(const ICmpInst *Instr) { | |
| Ice::Operand *Src0 = convertOperand(Instr, 0); | |
| Ice::Operand *Src1 = convertOperand(Instr, 1); | |
| Ice::Variable *Dest = mapValueToIceVar(Instr); | |
| Ice::InstIcmp::ICond Cond; | |
| switch (Instr->getPredicate()) { | |
| default: | |
| llvm_unreachable("ICmpInst predicate"); | |
| case CmpInst::ICMP_EQ: | |
| Cond = Ice::InstIcmp::Eq; | |
| break; | |
| case CmpInst::ICMP_NE: | |
| Cond = Ice::InstIcmp::Ne; | |
| break; | |
| case CmpInst::ICMP_UGT: | |
| Cond = Ice::InstIcmp::Ugt; | |
| break; | |
| case CmpInst::ICMP_UGE: | |
| Cond = Ice::InstIcmp::Uge; | |
| break; | |
| case CmpInst::ICMP_ULT: | |
| Cond = Ice::InstIcmp::Ult; | |
| break; | |
| case CmpInst::ICMP_ULE: | |
| Cond = Ice::InstIcmp::Ule; | |
| break; | |
| case CmpInst::ICMP_SGT: | |
| Cond = Ice::InstIcmp::Sgt; | |
| break; | |
| case CmpInst::ICMP_SGE: | |
| Cond = Ice::InstIcmp::Sge; | |
| break; | |
| case CmpInst::ICMP_SLT: | |
| Cond = Ice::InstIcmp::Slt; | |
| break; | |
| case CmpInst::ICMP_SLE: | |
| Cond = Ice::InstIcmp::Sle; | |
| break; | |
| } | |
| return Ice::InstIcmp::create(Func.get(), Cond, Dest, Src0, Src1); | |
| } | |
| Ice::Inst *convertFCmpInstruction(const FCmpInst *Instr) { | |
| Ice::Operand *Src0 = convertOperand(Instr, 0); | |
| Ice::Operand *Src1 = convertOperand(Instr, 1); | |
| Ice::Variable *Dest = mapValueToIceVar(Instr); | |
| Ice::InstFcmp::FCond Cond; | |
| switch (Instr->getPredicate()) { | |
| default: | |
| llvm_unreachable("FCmpInst predicate"); | |
| case CmpInst::FCMP_FALSE: | |
| Cond = Ice::InstFcmp::False; | |
| break; | |
| case CmpInst::FCMP_OEQ: | |
| Cond = Ice::InstFcmp::Oeq; | |
| break; | |
| case CmpInst::FCMP_OGT: | |
| Cond = Ice::InstFcmp::Ogt; | |
| break; | |
| case CmpInst::FCMP_OGE: | |
| Cond = Ice::InstFcmp::Oge; | |
| break; | |
| case CmpInst::FCMP_OLT: | |
| Cond = Ice::InstFcmp::Olt; | |
| break; | |
| case CmpInst::FCMP_OLE: | |
| Cond = Ice::InstFcmp::Ole; | |
| break; | |
| case CmpInst::FCMP_ONE: | |
| Cond = Ice::InstFcmp::One; | |
| break; | |
| case CmpInst::FCMP_ORD: | |
| Cond = Ice::InstFcmp::Ord; | |
| break; | |
| case CmpInst::FCMP_UEQ: | |
| Cond = Ice::InstFcmp::Ueq; | |
| break; | |
| case CmpInst::FCMP_UGT: | |
| Cond = Ice::InstFcmp::Ugt; | |
| break; | |
| case CmpInst::FCMP_UGE: | |
| Cond = Ice::InstFcmp::Uge; | |
| break; | |
| case CmpInst::FCMP_ULT: | |
| Cond = Ice::InstFcmp::Ult; | |
| break; | |
| case CmpInst::FCMP_ULE: | |
| Cond = Ice::InstFcmp::Ule; | |
| break; | |
| case CmpInst::FCMP_UNE: | |
| Cond = Ice::InstFcmp::Une; | |
| break; | |
| case CmpInst::FCMP_UNO: | |
| Cond = Ice::InstFcmp::Uno; | |
| break; | |
| case CmpInst::FCMP_TRUE: | |
| Cond = Ice::InstFcmp::True; | |
| break; | |
| } | |
| return Ice::InstFcmp::create(Func.get(), Cond, Dest, Src0, Src1); | |
| } | |
| Ice::Inst *convertExtractElementInstruction(const ExtractElementInst *Instr) { | |
| Ice::Variable *Dest = mapValueToIceVar(Instr); | |
| Ice::Operand *Source1 = convertValue(Instr->getOperand(0)); | |
| Ice::Operand *Source2 = convertValue(Instr->getOperand(1)); | |
| return Ice::InstExtractElement::create(Func.get(), Dest, Source1, Source2); | |
| } | |
| Ice::Inst *convertInsertElementInstruction(const InsertElementInst *Instr) { | |
| Ice::Variable *Dest = mapValueToIceVar(Instr); | |
| Ice::Operand *Source1 = convertValue(Instr->getOperand(0)); | |
| Ice::Operand *Source2 = convertValue(Instr->getOperand(1)); | |
| Ice::Operand *Source3 = convertValue(Instr->getOperand(2)); | |
| return Ice::InstInsertElement::create(Func.get(), Dest, Source1, Source2, | |
| Source3); | |
| } | |
| Ice::Inst *convertSelectInstruction(const SelectInst *Instr) { | |
| Ice::Variable *Dest = mapValueToIceVar(Instr); | |
| Ice::Operand *Cond = convertValue(Instr->getCondition()); | |
| Ice::Operand *Source1 = convertValue(Instr->getTrueValue()); | |
| Ice::Operand *Source2 = convertValue(Instr->getFalseValue()); | |
| return Ice::InstSelect::create(Func.get(), Dest, Cond, Source1, Source2); | |
| } | |
| Ice::Inst *convertSwitchInstruction(const SwitchInst *Instr) { | |
| Ice::Operand *Source = convertValue(Instr->getCondition()); | |
| Ice::CfgNode *LabelDefault = mapBasicBlockToNode(Instr->getDefaultDest()); | |
| unsigned NumCases = Instr->getNumCases(); | |
| Ice::InstSwitch *Switch = | |
| Ice::InstSwitch::create(Func.get(), NumCases, Source, LabelDefault); | |
| unsigned CurrentCase = 0; | |
| for (SwitchInst::ConstCaseIt I = Instr->case_begin(), E = Instr->case_end(); | |
| I != E; ++I, ++CurrentCase) { | |
| uint64_t CaseValue = I.getCaseValue()->getSExtValue(); | |
| Ice::CfgNode *CaseSuccessor = mapBasicBlockToNode(I.getCaseSuccessor()); | |
| Switch->addBranch(CurrentCase, CaseValue, CaseSuccessor); | |
| } | |
| return Switch; | |
| } | |
| Ice::Inst *convertCallInstruction(const CallInst *Instr) { | |
| Ice::Variable *Dest = mapValueToIceVar(Instr); | |
| Ice::Operand *CallTarget = convertValue(Instr->getCalledValue()); | |
| unsigned NumArgs = Instr->getNumArgOperands(); | |
| if (const auto Target = dyn_cast<Ice::ConstantRelocatable>(CallTarget)) { | |
| // Check if this direct call is to an Intrinsic (starts with "llvm.") | |
| bool BadIntrinsic; | |
| const Ice::Intrinsics::FullIntrinsicInfo *Info = | |
| Ctx->getIntrinsicsInfo().find(Target->getName(), BadIntrinsic); | |
| if (BadIntrinsic) { | |
| report_fatal_error(std::string("Invalid PNaCl intrinsic call: ") + | |
| LLVMObjectAsString(Instr)); | |
| } | |
| if (Info) { | |
| Ice::InstIntrinsic *Intrinsic = Ice::InstIntrinsic::create( | |
| Func.get(), NumArgs, Dest, CallTarget, Info->Info); | |
| for (unsigned i = 0; i < NumArgs; ++i) { | |
| Intrinsic->addArg(convertOperand(Instr, i)); | |
| } | |
| validateIntrinsic(Intrinsic, Info); | |
| return Intrinsic; | |
| } | |
| } | |
| // Not an intrinsic. | |
| // Note: Subzero doesn't (yet) do anything special with the Tail flag in | |
| // the bitcode, i.e. CallInst::isTailCall(). | |
| Ice::InstCall *Call = Ice::InstCall::create( | |
| Func.get(), NumArgs, Dest, CallTarget, Instr->isTailCall()); | |
| for (unsigned i = 0; i < NumArgs; ++i) { | |
| Intrinsic->addArg(convertOperand(Instr, i)); | |
| } | |
| return Call; | |
| } | |
| Ice::Inst *convertAllocaInstruction(const AllocaInst *Instr) { | |
| // PNaCl bitcode only contains allocas of byte-granular objects. | |
| Ice::Operand *ByteCount = convertValue(Instr->getArraySize()); | |
| uint32_t Align = Instr->getAlignment(); | |
| Ice::Variable *Dest = mapValueToIceVar(Instr, Ice::getPointerType()); | |
| return Ice::InstAlloca::create(Func.get(), Dest, ByteCount, Align); | |
| } | |
| Ice::Inst *convertUnreachableInstruction(const UnreachableInst * /*Instr*/) { | |
| return Ice::InstUnreachable::create(Func.get()); | |
| } | |
| Ice::CfgNode *convertBasicBlock(const BasicBlock *BB) { | |
| Ice::CfgNode *Node = mapBasicBlockToNode(BB); | |
| for (const Instruction &II : *BB) { | |
| Ice::Inst *Instr = convertInstruction(&II); | |
| Node->appendInst(Instr); | |
| } | |
| return Node; | |
| } | |
| void validateIntrinsic(const Ice::InstIntrinsic *Intrinsic, | |
| const Ice::Intrinsics::FullIntrinsicInfo *I) { | |
| Ice::SizeT ArgIndex = 0; | |
| switch (I->validateCall(Intrinsic, ArgIndex)) { | |
| case Ice::Intrinsics::IsValidCall: | |
| break; | |
| case Ice::Intrinsics::BadReturnType: { | |
| std::string Buffer; | |
| raw_string_ostream StrBuf(Buffer); | |
| StrBuf << "Intrinsic call expects return type " << I->getReturnType() | |
| << ". Found: " << Intrinsic->getReturnType(); | |
| report_fatal_error(StrBuf.str()); | |
| break; | |
| } | |
| case Ice::Intrinsics::WrongNumOfArgs: { | |
| std::string Buffer; | |
| raw_string_ostream StrBuf(Buffer); | |
| StrBuf << "Intrinsic call expects " << I->getNumArgs() | |
| << ". Found: " << Intrinsic->getNumArgs(); | |
| report_fatal_error(StrBuf.str()); | |
| break; | |
| } | |
| case Ice::Intrinsics::WrongCallArgType: { | |
| std::string Buffer; | |
| raw_string_ostream StrBuf(Buffer); | |
| StrBuf << "Intrinsic call argument " << ArgIndex << " expects type " | |
| << I->getArgType(ArgIndex) | |
| << ". Found: " << Intrinsic->getArg(ArgIndex)->getType(); | |
| report_fatal_error(StrBuf.str()); | |
| break; | |
| } | |
| } | |
| } | |
| private: | |
| // Data | |
| std::unique_ptr<Ice::Cfg> Func; | |
| std::map<const Value *, Ice::Variable *> VarMap; | |
| std::map<const BasicBlock *, Ice::CfgNode *> NodeMap; | |
| }; | |
| // Converter from LLVM global variables to ICE. The entry point is the | |
| // convertGlobalsToIce method. | |
| // | |
| // Note: this currently assumes that the given IR was verified to be valid | |
| // PNaCl bitcode. Otherwise, the behavior is undefined. | |
| class LLVM2ICEGlobalsConverter : public LLVM2ICEConverter { | |
| LLVM2ICEGlobalsConverter() = delete; | |
| LLVM2ICEGlobalsConverter(const LLVM2ICEGlobalsConverter &) = delete; | |
| LLVM2ICEGlobalsConverter & | |
| operator=(const LLVM2ICEGlobalsConverter &) = delete; | |
| public: | |
| explicit LLVM2ICEGlobalsConverter(Ice::Converter &Converter, | |
| Ice::VariableDeclarationList *G) | |
| : LLVM2ICEConverter(Converter), GlobalPool(G) {} | |
| /// Converts global variables, and their initializers into ICE global variable | |
| /// declarations, for module Mod. Returns the set of converted declarations. | |
| void convertGlobalsToIce(Module *Mod); | |
| private: | |
| // Adds the Initializer to the list of initializers for the Global variable | |
| // declaration. | |
| void addGlobalInitializer(Ice::VariableDeclaration &Global, | |
| const Constant *Initializer) { | |
| constexpr bool HasOffset = false; | |
| constexpr Ice::RelocOffsetT Offset = 0; | |
| addGlobalInitializer(Global, Initializer, HasOffset, Offset); | |
| } | |
| // Adds Initializer to the list of initializers for Global variable | |
| // declaration. HasOffset is true only if Initializer is a relocation | |
| // initializer and Offset should be added to the relocation. | |
| void addGlobalInitializer(Ice::VariableDeclaration &Global, | |
| const Constant *Initializer, bool HasOffset, | |
| Ice::RelocOffsetT Offset); | |
| // Converts the given constant C to the corresponding integer literal it | |
| // contains. | |
| Ice::RelocOffsetT getIntegerLiteralConstant(const Value *C) { | |
| const auto CI = dyn_cast<ConstantInt>(C); | |
| if (CI && CI->getType()->isIntegerTy(32)) | |
| return CI->getSExtValue(); | |
| std::string Buffer; | |
| raw_string_ostream StrBuf(Buffer); | |
| StrBuf << "Constant not i32 literal: " << *C; | |
| report_fatal_error(StrBuf.str()); | |
| return 0; | |
| } | |
| Ice::VariableDeclarationList *GlobalPool; | |
| }; | |
| void LLVM2ICEGlobalsConverter::convertGlobalsToIce(Module *Mod) { | |
| for (Module::const_global_iterator I = Mod->global_begin(), | |
| E = Mod->global_end(); | |
| I != E; ++I) { | |
| const GlobalVariable *GV = &*I; | |
| Ice::GlobalDeclaration *Var = getConverter().getGlobalDeclaration(GV); | |
| auto *VarDecl = cast<Ice::VariableDeclaration>(Var); | |
| GlobalPool->push_back(VarDecl); | |
| if (!GV->hasInternalLinkage() && GV->hasInitializer()) { | |
| std::string Buffer; | |
| raw_string_ostream StrBuf(Buffer); | |
| StrBuf << "Can't define external global declaration: " << GV->getName(); | |
| report_fatal_error(StrBuf.str()); | |
| } | |
| if (!GV->hasInitializer()) { | |
| if (Ice::getFlags().getAllowUninitializedGlobals()) | |
| continue; | |
| else { | |
| std::string Buffer; | |
| raw_string_ostream StrBuf(Buffer); | |
| StrBuf << "Global declaration missing initializer: " << GV->getName(); | |
| report_fatal_error(StrBuf.str()); | |
| } | |
| } | |
| const Constant *Initializer = GV->getInitializer(); | |
| if (const auto CompoundInit = dyn_cast<ConstantStruct>(Initializer)) { | |
| for (ConstantStruct::const_op_iterator I = CompoundInit->op_begin(), | |
| E = CompoundInit->op_end(); | |
| I != E; ++I) { | |
| if (const auto Init = dyn_cast<Constant>(I)) { | |
| addGlobalInitializer(*VarDecl, Init); | |
| } | |
| } | |
| } else { | |
| addGlobalInitializer(*VarDecl, Initializer); | |
| } | |
| } | |
| } | |
| void LLVM2ICEGlobalsConverter::addGlobalInitializer( | |
| Ice::VariableDeclaration &Global, const Constant *Initializer, | |
| bool HasOffset, Ice::RelocOffsetT Offset) { | |
| (void)HasOffset; | |
| assert(HasOffset || Offset == 0); | |
| if (const auto CDA = dyn_cast<ConstantDataArray>(Initializer)) { | |
| assert(!HasOffset && isa<IntegerType>(CDA->getElementType()) && | |
| (cast<IntegerType>(CDA->getElementType())->getBitWidth() == 8)); | |
| Global.addInitializer(Ice::VariableDeclaration::DataInitializer::create( | |
| GlobalPool, CDA->getRawDataValues().data(), CDA->getNumElements())); | |
| return; | |
| } | |
| if (isa<ConstantAggregateZero>(Initializer)) { | |
| if (const auto AT = dyn_cast<ArrayType>(Initializer->getType())) { | |
| assert(!HasOffset && isa<IntegerType>(AT->getElementType()) && | |
| (cast<IntegerType>(AT->getElementType())->getBitWidth() == 8)); | |
| Global.addInitializer(Ice::VariableDeclaration::ZeroInitializer::create( | |
| GlobalPool, AT->getNumElements())); | |
| } else { | |
| llvm_unreachable("Unhandled constant aggregate zero type"); | |
| } | |
| return; | |
| } | |
| if (const auto Exp = dyn_cast<ConstantExpr>(Initializer)) { | |
| switch (Exp->getOpcode()) { | |
| case Instruction::Add: | |
| assert(!HasOffset); | |
| addGlobalInitializer(Global, Exp->getOperand(0), true, | |
| getIntegerLiteralConstant(Exp->getOperand(1))); | |
| return; | |
| case Instruction::PtrToInt: { | |
| assert(TypeConverter.convertToIceType(Exp->getType()) == | |
| Ice::getPointerType()); | |
| const auto GV = dyn_cast<GlobalValue>(Exp->getOperand(0)); | |
| assert(GV); | |
| const Ice::GlobalDeclaration *Addr = | |
| getConverter().getGlobalDeclaration(GV); | |
| Global.addInitializer(Ice::VariableDeclaration::RelocInitializer::create( | |
| GlobalPool, Addr, {Ice::RelocOffset::create(Ctx, Offset)})); | |
| return; | |
| } | |
| default: | |
| break; | |
| } | |
| } | |
| std::string Buffer; | |
| raw_string_ostream StrBuf(Buffer); | |
| StrBuf << "Unhandled global initializer: " << Initializer; | |
| report_fatal_error(StrBuf.str()); | |
| } | |
| } // end of anonymous namespace | |
| namespace Ice { | |
| void Converter::nameUnnamedGlobalVariables(Module *Mod) { | |
| const std::string GlobalPrefix = getFlags().getDefaultGlobalPrefix(); | |
| if (GlobalPrefix.empty()) | |
| return; | |
| uint32_t NameIndex = 0; | |
| for (auto V = Mod->global_begin(), E = Mod->global_end(); V != E; ++V) { | |
| if (!V->hasName()) { | |
| V->setName(createUnnamedName(GlobalPrefix, NameIndex)); | |
| ++NameIndex; | |
| } else { | |
| checkIfUnnamedNameSafe(V->getName(), "global", GlobalPrefix); | |
| } | |
| } | |
| } | |
| void Converter::nameUnnamedFunctions(Module *Mod) { | |
| const std::string FunctionPrefix = getFlags().getDefaultFunctionPrefix(); | |
| if (FunctionPrefix.empty()) | |
| return; | |
| uint32_t NameIndex = 0; | |
| for (Function &F : *Mod) { | |
| if (!F.hasName()) { | |
| F.setName(createUnnamedName(FunctionPrefix, NameIndex)); | |
| ++NameIndex; | |
| } else { | |
| checkIfUnnamedNameSafe(F.getName(), "function", FunctionPrefix); | |
| } | |
| } | |
| } | |
| void Converter::convertToIce() { | |
| TimerMarker T(TimerStack::TT_convertToIce, Ctx); | |
| nameUnnamedGlobalVariables(Mod); | |
| nameUnnamedFunctions(Mod); | |
| installGlobalDeclarations(Mod); | |
| convertGlobals(Mod); | |
| convertFunctions(); | |
| } | |
| GlobalDeclaration *Converter::getGlobalDeclaration(const GlobalValue *V) { | |
| GlobalDeclarationMapType::const_iterator Pos = GlobalDeclarationMap.find(V); | |
| if (Pos == GlobalDeclarationMap.end()) { | |
| std::string Buffer; | |
| raw_string_ostream StrBuf(Buffer); | |
| StrBuf << "Can't find global declaration for: " << V->getName(); | |
| report_fatal_error(StrBuf.str()); | |
| } | |
| return Pos->second; | |
| } | |
| void Converter::installGlobalDeclarations(Module *Mod) { | |
| const TypeConverter Converter(Mod->getContext()); | |
| // Install function declarations. | |
| for (const Function &Func : *Mod) { | |
| FuncSigType Signature; | |
| FunctionType *FuncType = Func.getFunctionType(); | |
| Signature.setReturnType( | |
| Converter.convertToIceType(FuncType->getReturnType())); | |
| for (size_t I = 0; I < FuncType->getNumParams(); ++I) { | |
| Signature.appendArgType( | |
| Converter.convertToIceType(FuncType->getParamType(I))); | |
| } | |
| auto *IceFunc = FunctionDeclaration::create( | |
| Ctx, Signature, Func.getCallingConv(), Func.getLinkage(), Func.empty()); | |
| IceFunc->setName(Ctx, Func.getName()); | |
| if (!IceFunc->verifyLinkageCorrect(Ctx)) { | |
| std::string Buffer; | |
| raw_string_ostream StrBuf(Buffer); | |
| StrBuf << "Function " << IceFunc->getName() | |
| << " has incorrect linkage: " << IceFunc->getLinkageName(); | |
| if (IceFunc->isExternal()) | |
| StrBuf << "\n Use flag -allow-externally-defined-symbols to override"; | |
| report_fatal_error(StrBuf.str()); | |
| } | |
| if (!IceFunc->validateTypeSignature(Ctx)) | |
| report_fatal_error(IceFunc->getTypeSignatureError(Ctx)); | |
| GlobalDeclarationMap[&Func] = IceFunc; | |
| } | |
| // Install global variable declarations. | |
| for (Module::const_global_iterator I = Mod->global_begin(), | |
| E = Mod->global_end(); | |
| I != E; ++I) { | |
| const GlobalVariable *GV = &*I; | |
| constexpr bool NoSuppressMangling = false; | |
| auto *Var = VariableDeclaration::create( | |
| GlobalDeclarationsPool.get(), NoSuppressMangling, GV->getLinkage()); | |
| Var->setAlignment(GV->getAlignment()); | |
| Var->setIsConstant(GV->isConstant()); | |
| Var->setName(Ctx, GV->getName()); | |
| if (!Var->verifyLinkageCorrect()) { | |
| std::string Buffer; | |
| raw_string_ostream StrBuf(Buffer); | |
| StrBuf << "Global " << Var->getName() | |
| << " has incorrect linkage: " << Var->getLinkageName(); | |
| if (Var->isExternal()) | |
| StrBuf << "\n Use flag -allow-externally-defined-symbols to override"; | |
| report_fatal_error(StrBuf.str()); | |
| } | |
| GlobalDeclarationMap[GV] = Var; | |
| } | |
| } | |
| void Converter::convertGlobals(Module *Mod) { | |
| LLVM2ICEGlobalsConverter(*this, GlobalDeclarationsPool.get()) | |
| .convertGlobalsToIce(Mod); | |
| lowerGlobals(std::move(GlobalDeclarationsPool)); | |
| } | |
| void Converter::convertFunctions() { | |
| for (const Function &I : *Mod) { | |
| if (I.empty()) | |
| continue; | |
| TimerMarker _(Ctx, I.getName()); | |
| LLVM2ICEFunctionConverter FunctionConverter(*this); | |
| FunctionConverter.convertFunction(&I); | |
| } | |
| } | |
| } // end of namespace Ice |