//===- 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 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(Const)) { Ice::GlobalDeclaration *Decl = getConverter().getGlobalDeclaration(GV); bool IsUndefined = false; if (const auto *Func = llvm::dyn_cast(Decl)) IsUndefined = Func->isProto(); else if (const auto *Var = llvm::dyn_cast(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(Const)) { Ice::Type Ty = convertToIceType(CI->getType()); return Ctx->getConstantInt(Ty, CI->getSExtValue()); } else if (const auto CFP = dyn_cast(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(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(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(Instr)); case Instruction::Br: return convertBrInstruction(cast(Instr)); case Instruction::Ret: return convertRetInstruction(cast(Instr)); case Instruction::IntToPtr: return convertIntToPtrInstruction(cast(Instr)); case Instruction::PtrToInt: return convertPtrToIntInstruction(cast(Instr)); case Instruction::ICmp: return convertICmpInstruction(cast(Instr)); case Instruction::FCmp: return convertFCmpInstruction(cast(Instr)); case Instruction::Select: return convertSelectInstruction(cast(Instr)); case Instruction::Switch: return convertSwitchInstruction(cast(Instr)); case Instruction::Load: return convertLoadInstruction(cast(Instr)); case Instruction::Store: return convertStoreInstruction(cast(Instr)); case Instruction::ZExt: return convertCastInstruction(cast(Instr), Ice::InstCast::Zext); case Instruction::SExt: return convertCastInstruction(cast(Instr), Ice::InstCast::Sext); case Instruction::Trunc: return convertCastInstruction(cast(Instr), Ice::InstCast::Trunc); case Instruction::FPTrunc: return convertCastInstruction(cast(Instr), Ice::InstCast::Fptrunc); case Instruction::FPExt: return convertCastInstruction(cast(Instr), Ice::InstCast::Fpext); case Instruction::FPToSI: return convertCastInstruction(cast(Instr), Ice::InstCast::Fptosi); case Instruction::FPToUI: return convertCastInstruction(cast(Instr), Ice::InstCast::Fptoui); case Instruction::SIToFP: return convertCastInstruction(cast(Instr), Ice::InstCast::Sitofp); case Instruction::UIToFP: return convertCastInstruction(cast(Instr), Ice::InstCast::Uitofp); case Instruction::BitCast: return convertCastInstruction(cast(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(Instr)); case Instruction::InsertElement: return convertInsertElementInstruction(cast(Instr)); case Instruction::Call: return convertCallInstruction(cast(Instr)); case Instruction::Alloca: return convertAllocaInstruction(cast(Instr)); case Instruction::Unreachable: return convertUnreachableInstruction(cast(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(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(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 Func; std::map VarMap; std::map 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(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(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(Initializer)) { for (ConstantStruct::const_op_iterator I = CompoundInit->op_begin(), E = CompoundInit->op_end(); I != E; ++I) { if (const auto Init = dyn_cast(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(Initializer)) { assert(!HasOffset && isa(CDA->getElementType()) && (cast(CDA->getElementType())->getBitWidth() == 8)); Global.addInitializer(Ice::VariableDeclaration::DataInitializer::create( GlobalPool, CDA->getRawDataValues().data(), CDA->getNumElements())); return; } if (isa(Initializer)) { if (const auto AT = dyn_cast(Initializer->getType())) { assert(!HasOffset && isa(AT->getElementType()) && (cast(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(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(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