1f22ef01cSRoman Divacky //===-- llvm/CodeGen/MachineModuleInfo.cpp ----------------------*- C++ -*-===// 2f22ef01cSRoman Divacky // 3f22ef01cSRoman Divacky // The LLVM Compiler Infrastructure 4f22ef01cSRoman Divacky // 5f22ef01cSRoman Divacky // This file is distributed under the University of Illinois Open Source 6f22ef01cSRoman Divacky // License. See LICENSE.TXT for details. 7f22ef01cSRoman Divacky // 8f22ef01cSRoman Divacky //===----------------------------------------------------------------------===// 9f22ef01cSRoman Divacky 10db17bf38SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h" 11f9448bf3SDimitry Andric #include "llvm/ADT/ArrayRef.h" 12f9448bf3SDimitry Andric #include "llvm/ADT/DenseMap.h" 13d88c1a5aSDimitry Andric #include "llvm/ADT/PostOrderIterator.h" 14f9448bf3SDimitry Andric #include "llvm/ADT/StringRef.h" 157d523365SDimitry Andric #include "llvm/ADT/TinyPtrVector.h" 16f22ef01cSRoman Divacky #include "llvm/CodeGen/MachineFunction.h" 17f22ef01cSRoman Divacky #include "llvm/CodeGen/Passes.h" 18f9448bf3SDimitry Andric #include "llvm/IR/BasicBlock.h" 19139f7f9bSDimitry Andric #include "llvm/IR/DerivedTypes.h" 20d88c1a5aSDimitry Andric #include "llvm/IR/Instructions.h" 21139f7f9bSDimitry Andric #include "llvm/IR/Module.h" 22f9448bf3SDimitry Andric #include "llvm/IR/Value.h" 23f9448bf3SDimitry Andric #include "llvm/IR/ValueHandle.h" 24f9448bf3SDimitry Andric #include "llvm/MC/MCContext.h" 25f22ef01cSRoman Divacky #include "llvm/MC/MCSymbol.h" 26f9448bf3SDimitry Andric #include "llvm/Pass.h" 27f9448bf3SDimitry Andric #include "llvm/Support/Casting.h" 28f22ef01cSRoman Divacky #include "llvm/Support/ErrorHandling.h" 29d88c1a5aSDimitry Andric #include "llvm/Target/TargetLoweringObjectFile.h" 30d88c1a5aSDimitry Andric #include "llvm/Target/TargetMachine.h" 31f9448bf3SDimitry Andric #include <algorithm> 32f9448bf3SDimitry Andric #include <cassert> 33f9448bf3SDimitry Andric #include <memory> 34f9448bf3SDimitry Andric #include <utility> 35f9448bf3SDimitry Andric #include <vector> 36f9448bf3SDimitry Andric 37f22ef01cSRoman Divacky using namespace llvm; 38f22ef01cSRoman Divacky using namespace llvm::dwarf; 39f22ef01cSRoman Divacky 403861d79fSDimitry Andric // Handle the Pass registration stuff necessary to use DataLayout's. 41d8866befSDimitry Andric INITIALIZE_PASS(MachineModuleInfo, "machinemoduleinfo", 422754fe60SDimitry Andric "Machine Module Information", false, false) 43f22ef01cSRoman Divacky char MachineModuleInfo::ID = 0; 44f22ef01cSRoman Divacky 45f22ef01cSRoman Divacky // Out of line virtual method. 46f9448bf3SDimitry Andric MachineModuleInfoImpl::~MachineModuleInfoImpl() = default; 47f22ef01cSRoman Divacky 48f22ef01cSRoman Divacky namespace llvm { 49f9448bf3SDimitry Andric 507d523365SDimitry Andric class MMIAddrLabelMapCallbackPtr final : CallbackVH { 51f9448bf3SDimitry Andric MMIAddrLabelMap *Map = nullptr; 52f9448bf3SDimitry Andric 53f22ef01cSRoman Divacky public: 54f9448bf3SDimitry Andric MMIAddrLabelMapCallbackPtr() = default; 55f9448bf3SDimitry Andric MMIAddrLabelMapCallbackPtr(Value *V) : CallbackVH(V) {} 56f22ef01cSRoman Divacky 57f22ef01cSRoman Divacky void setPtr(BasicBlock *BB) { 58f22ef01cSRoman Divacky ValueHandleBase::operator=(BB); 59f22ef01cSRoman Divacky } 60f22ef01cSRoman Divacky 61f22ef01cSRoman Divacky void setMap(MMIAddrLabelMap *map) { Map = map; } 62f22ef01cSRoman Divacky 6391bc56edSDimitry Andric void deleted() override; 6491bc56edSDimitry Andric void allUsesReplacedWith(Value *V2) override; 65f22ef01cSRoman Divacky }; 66f22ef01cSRoman Divacky 67f22ef01cSRoman Divacky class MMIAddrLabelMap { 68f22ef01cSRoman Divacky MCContext &Context; 69f22ef01cSRoman Divacky struct AddrLabelSymEntry { 70d88c1a5aSDimitry Andric /// The symbols for the label. 713dac3a9bSDimitry Andric TinyPtrVector<MCSymbol *> Symbols; 72f22ef01cSRoman Divacky 73f22ef01cSRoman Divacky Function *Fn; // The containing function of the BasicBlock. 74f22ef01cSRoman Divacky unsigned Index; // The index in BBCallbacks for the BasicBlock. 75f22ef01cSRoman Divacky }; 76f22ef01cSRoman Divacky 77f22ef01cSRoman Divacky DenseMap<AssertingVH<BasicBlock>, AddrLabelSymEntry> AddrLabelSymbols; 78f22ef01cSRoman Divacky 79d88c1a5aSDimitry Andric /// Callbacks for the BasicBlock's that we have entries for. We use this so 80d88c1a5aSDimitry Andric /// we get notified if a block is deleted or RAUWd. 81f22ef01cSRoman Divacky std::vector<MMIAddrLabelMapCallbackPtr> BBCallbacks; 82f22ef01cSRoman Divacky 83d88c1a5aSDimitry Andric /// This is a per-function list of symbols whose corresponding BasicBlock got 84d88c1a5aSDimitry Andric /// deleted. These symbols need to be emitted at some point in the file, so 85d88c1a5aSDimitry Andric /// AsmPrinter emits them after the function body. 86f22ef01cSRoman Divacky DenseMap<AssertingVH<Function>, std::vector<MCSymbol*>> 87f22ef01cSRoman Divacky DeletedAddrLabelsNeedingEmission; 88f22ef01cSRoman Divacky 89f9448bf3SDimitry Andric public: 90f22ef01cSRoman Divacky MMIAddrLabelMap(MCContext &context) : Context(context) {} 91f9448bf3SDimitry Andric 92f22ef01cSRoman Divacky ~MMIAddrLabelMap() { 93f22ef01cSRoman Divacky assert(DeletedAddrLabelsNeedingEmission.empty() && 94f22ef01cSRoman Divacky "Some labels for deleted blocks never got emitted"); 95f22ef01cSRoman Divacky } 96f22ef01cSRoman Divacky 973dac3a9bSDimitry Andric ArrayRef<MCSymbol *> getAddrLabelSymbolToEmit(BasicBlock *BB); 98f22ef01cSRoman Divacky 99f22ef01cSRoman Divacky void takeDeletedSymbolsForFunction(Function *F, 100f22ef01cSRoman Divacky std::vector<MCSymbol*> &Result); 101f22ef01cSRoman Divacky 102f22ef01cSRoman Divacky void UpdateForDeletedBlock(BasicBlock *BB); 103f22ef01cSRoman Divacky void UpdateForRAUWBlock(BasicBlock *Old, BasicBlock *New); 104f22ef01cSRoman Divacky }; 105f9448bf3SDimitry Andric 106f9448bf3SDimitry Andric } // end namespace llvm 107f22ef01cSRoman Divacky 1083dac3a9bSDimitry Andric ArrayRef<MCSymbol *> MMIAddrLabelMap::getAddrLabelSymbolToEmit(BasicBlock *BB) { 109f22ef01cSRoman Divacky assert(BB->hasAddressTaken() && 110f22ef01cSRoman Divacky "Shouldn't get label for block without address taken"); 111f22ef01cSRoman Divacky AddrLabelSymEntry &Entry = AddrLabelSymbols[BB]; 112f22ef01cSRoman Divacky 113f22ef01cSRoman Divacky // If we already had an entry for this block, just return it. 1143dac3a9bSDimitry Andric if (!Entry.Symbols.empty()) { 115f22ef01cSRoman Divacky assert(BB->getParent() == Entry.Fn && "Parent changed"); 1163dac3a9bSDimitry Andric return Entry.Symbols; 117f22ef01cSRoman Divacky } 118f22ef01cSRoman Divacky 119f22ef01cSRoman Divacky // Otherwise, this is a new entry, create a new symbol for it and add an 120f22ef01cSRoman Divacky // entry to BBCallbacks so we can be notified if the BB is deleted or RAUWd. 12197bc6c73SDimitry Andric BBCallbacks.emplace_back(BB); 122f22ef01cSRoman Divacky BBCallbacks.back().setMap(this); 123f22ef01cSRoman Divacky Entry.Index = BBCallbacks.size() - 1; 124f22ef01cSRoman Divacky Entry.Fn = BB->getParent(); 1253dac3a9bSDimitry Andric Entry.Symbols.push_back(Context.createTempSymbol()); 1263dac3a9bSDimitry Andric return Entry.Symbols; 127f22ef01cSRoman Divacky } 128f22ef01cSRoman Divacky 129d88c1a5aSDimitry Andric /// If we have any deleted symbols for F, return them. 130f22ef01cSRoman Divacky void MMIAddrLabelMap:: 131f22ef01cSRoman Divacky takeDeletedSymbolsForFunction(Function *F, std::vector<MCSymbol*> &Result) { 132f22ef01cSRoman Divacky DenseMap<AssertingVH<Function>, std::vector<MCSymbol*>>::iterator I = 133f22ef01cSRoman Divacky DeletedAddrLabelsNeedingEmission.find(F); 134f22ef01cSRoman Divacky 135f22ef01cSRoman Divacky // If there are no entries for the function, just return. 136f22ef01cSRoman Divacky if (I == DeletedAddrLabelsNeedingEmission.end()) return; 137f22ef01cSRoman Divacky 138f22ef01cSRoman Divacky // Otherwise, take the list. 139f22ef01cSRoman Divacky std::swap(Result, I->second); 140f22ef01cSRoman Divacky DeletedAddrLabelsNeedingEmission.erase(I); 141f22ef01cSRoman Divacky } 142f22ef01cSRoman Divacky 143f22ef01cSRoman Divacky void MMIAddrLabelMap::UpdateForDeletedBlock(BasicBlock *BB) { 144f22ef01cSRoman Divacky // If the block got deleted, there is no need for the symbol. If the symbol 145f22ef01cSRoman Divacky // was already emitted, we can just forget about it, otherwise we need to 146f22ef01cSRoman Divacky // queue it up for later emission when the function is output. 1473dac3a9bSDimitry Andric AddrLabelSymEntry Entry = std::move(AddrLabelSymbols[BB]); 148f22ef01cSRoman Divacky AddrLabelSymbols.erase(BB); 1493dac3a9bSDimitry Andric assert(!Entry.Symbols.empty() && "Didn't have a symbol, why a callback?"); 15091bc56edSDimitry Andric BBCallbacks[Entry.Index] = nullptr; // Clear the callback. 151f22ef01cSRoman Divacky 15291bc56edSDimitry Andric assert((BB->getParent() == nullptr || BB->getParent() == Entry.Fn) && 153f22ef01cSRoman Divacky "Block/parent mismatch"); 154f22ef01cSRoman Divacky 1553dac3a9bSDimitry Andric for (MCSymbol *Sym : Entry.Symbols) { 156f22ef01cSRoman Divacky if (Sym->isDefined()) 157f22ef01cSRoman Divacky return; 158f22ef01cSRoman Divacky 159f22ef01cSRoman Divacky // If the block is not yet defined, we need to emit it at the end of the 160f22ef01cSRoman Divacky // function. Add the symbol to the DeletedAddrLabelsNeedingEmission list 161f22ef01cSRoman Divacky // for the containing Function. Since the block is being deleted, its 162f22ef01cSRoman Divacky // parent may already be removed, we have to get the function from 'Entry'. 163f22ef01cSRoman Divacky DeletedAddrLabelsNeedingEmission[Entry.Fn].push_back(Sym); 164f22ef01cSRoman Divacky } 165f22ef01cSRoman Divacky } 166f22ef01cSRoman Divacky 167f22ef01cSRoman Divacky void MMIAddrLabelMap::UpdateForRAUWBlock(BasicBlock *Old, BasicBlock *New) { 168f22ef01cSRoman Divacky // Get the entry for the RAUW'd block and remove it from our map. 1693dac3a9bSDimitry Andric AddrLabelSymEntry OldEntry = std::move(AddrLabelSymbols[Old]); 170f22ef01cSRoman Divacky AddrLabelSymbols.erase(Old); 1713dac3a9bSDimitry Andric assert(!OldEntry.Symbols.empty() && "Didn't have a symbol, why a callback?"); 172f22ef01cSRoman Divacky 173f22ef01cSRoman Divacky AddrLabelSymEntry &NewEntry = AddrLabelSymbols[New]; 174f22ef01cSRoman Divacky 175f22ef01cSRoman Divacky // If New is not address taken, just move our symbol over to it. 1763dac3a9bSDimitry Andric if (NewEntry.Symbols.empty()) { 177f22ef01cSRoman Divacky BBCallbacks[OldEntry.Index].setPtr(New); // Update the callback. 1783dac3a9bSDimitry Andric NewEntry = std::move(OldEntry); // Set New's entry. 179f22ef01cSRoman Divacky return; 180f22ef01cSRoman Divacky } 181f22ef01cSRoman Divacky 18291bc56edSDimitry Andric BBCallbacks[OldEntry.Index] = nullptr; // Update the callback. 183f22ef01cSRoman Divacky 1843dac3a9bSDimitry Andric // Otherwise, we need to add the old symbols to the new block's set. 1853dac3a9bSDimitry Andric NewEntry.Symbols.insert(NewEntry.Symbols.end(), OldEntry.Symbols.begin(), 1863dac3a9bSDimitry Andric OldEntry.Symbols.end()); 187f22ef01cSRoman Divacky } 188f22ef01cSRoman Divacky 189f22ef01cSRoman Divacky void MMIAddrLabelMapCallbackPtr::deleted() { 190f22ef01cSRoman Divacky Map->UpdateForDeletedBlock(cast<BasicBlock>(getValPtr())); 191f22ef01cSRoman Divacky } 192f22ef01cSRoman Divacky 193f22ef01cSRoman Divacky void MMIAddrLabelMapCallbackPtr::allUsesReplacedWith(Value *V2) { 194f22ef01cSRoman Divacky Map->UpdateForRAUWBlock(cast<BasicBlock>(getValPtr()), cast<BasicBlock>(V2)); 195f22ef01cSRoman Divacky } 196f22ef01cSRoman Divacky 197d88c1a5aSDimitry Andric MachineModuleInfo::MachineModuleInfo(const TargetMachine *TM) 198d88c1a5aSDimitry Andric : ImmutablePass(ID), TM(*TM), 199d88c1a5aSDimitry Andric Context(TM->getMCAsmInfo(), TM->getMCRegisterInfo(), 200d88c1a5aSDimitry Andric TM->getObjFileLowering(), nullptr, false) { 2012754fe60SDimitry Andric initializeMachineModuleInfoPass(*PassRegistry::getPassRegistry()); 202f22ef01cSRoman Divacky } 203f22ef01cSRoman Divacky 204f9448bf3SDimitry Andric MachineModuleInfo::~MachineModuleInfo() = default; 205f22ef01cSRoman Divacky 206139f7f9bSDimitry Andric bool MachineModuleInfo::doInitialization(Module &M) { 20791bc56edSDimitry Andric ObjFileMMI = nullptr; 208139f7f9bSDimitry Andric CurCallSite = 0; 20939d628a0SDimitry Andric DbgInfoAvailable = UsesVAFloatArgument = UsesMorestackAddr = false; 21091bc56edSDimitry Andric AddrLabelSymbols = nullptr; 211d88c1a5aSDimitry Andric TheModule = &M; 212139f7f9bSDimitry Andric 213f22ef01cSRoman Divacky return false; 214f22ef01cSRoman Divacky } 215f22ef01cSRoman Divacky 216139f7f9bSDimitry Andric bool MachineModuleInfo::doFinalization(Module &M) { 217139f7f9bSDimitry Andric Personalities.clear(); 218139f7f9bSDimitry Andric 219f22ef01cSRoman Divacky delete AddrLabelSymbols; 22091bc56edSDimitry Andric AddrLabelSymbols = nullptr; 221139f7f9bSDimitry Andric 222139f7f9bSDimitry Andric Context.reset(); 223139f7f9bSDimitry Andric 224139f7f9bSDimitry Andric delete ObjFileMMI; 22591bc56edSDimitry Andric ObjFileMMI = nullptr; 226139f7f9bSDimitry Andric 227f22ef01cSRoman Divacky return false; 228f22ef01cSRoman Divacky } 229f22ef01cSRoman Divacky 230f22ef01cSRoman Divacky //===- Address of Block Management ----------------------------------------===// 231f22ef01cSRoman Divacky 2323dac3a9bSDimitry Andric ArrayRef<MCSymbol *> 2333dac3a9bSDimitry Andric MachineModuleInfo::getAddrLabelSymbolToEmit(const BasicBlock *BB) { 234f22ef01cSRoman Divacky // Lazily create AddrLabelSymbols. 23591bc56edSDimitry Andric if (!AddrLabelSymbols) 236f22ef01cSRoman Divacky AddrLabelSymbols = new MMIAddrLabelMap(Context); 237f22ef01cSRoman Divacky return AddrLabelSymbols->getAddrLabelSymbolToEmit(const_cast<BasicBlock*>(BB)); 238f22ef01cSRoman Divacky } 239f22ef01cSRoman Divacky 240f22ef01cSRoman Divacky void MachineModuleInfo:: 241f22ef01cSRoman Divacky takeDeletedSymbolsForFunction(const Function *F, 242f22ef01cSRoman Divacky std::vector<MCSymbol*> &Result) { 243f22ef01cSRoman Divacky // If no blocks have had their addresses taken, we're done. 24491bc56edSDimitry Andric if (!AddrLabelSymbols) return; 245f22ef01cSRoman Divacky return AddrLabelSymbols-> 246f22ef01cSRoman Divacky takeDeletedSymbolsForFunction(const_cast<Function*>(F), Result); 247f22ef01cSRoman Divacky } 248f22ef01cSRoman Divacky 249d88c1a5aSDimitry Andric /// \name Exception Handling 250d88c1a5aSDimitry Andric /// \{ 251f22ef01cSRoman Divacky 252875ed548SDimitry Andric void MachineModuleInfo::addPersonality(const Function *Personality) { 253f22ef01cSRoman Divacky for (unsigned i = 0; i < Personalities.size(); ++i) 254f22ef01cSRoman Divacky if (Personalities[i] == Personality) 255f22ef01cSRoman Divacky return; 256f22ef01cSRoman Divacky Personalities.push_back(Personality); 257f22ef01cSRoman Divacky } 258f22ef01cSRoman Divacky 259d88c1a5aSDimitry Andric /// \} 260d88c1a5aSDimitry Andric 261db17bf38SDimitry Andric MachineFunction * 262db17bf38SDimitry Andric MachineModuleInfo::getMachineFunction(const Function &F) const { 263db17bf38SDimitry Andric auto I = MachineFunctions.find(&F); 264db17bf38SDimitry Andric return I != MachineFunctions.end() ? I->second.get() : nullptr; 265db17bf38SDimitry Andric } 266db17bf38SDimitry Andric 267db17bf38SDimitry Andric MachineFunction & 268db17bf38SDimitry Andric MachineModuleInfo::getOrCreateMachineFunction(const Function &F) { 269d88c1a5aSDimitry Andric // Shortcut for the common case where a sequence of MachineFunctionPasses 270d88c1a5aSDimitry Andric // all query for the same Function. 271d88c1a5aSDimitry Andric if (LastRequest == &F) 272d88c1a5aSDimitry Andric return *LastResult; 273d88c1a5aSDimitry Andric 274d88c1a5aSDimitry Andric auto I = MachineFunctions.insert( 275d88c1a5aSDimitry Andric std::make_pair(&F, std::unique_ptr<MachineFunction>())); 276d88c1a5aSDimitry Andric MachineFunction *MF; 277d88c1a5aSDimitry Andric if (I.second) { 278d88c1a5aSDimitry Andric // No pre-existing machine function, create a new one. 279d88c1a5aSDimitry Andric MF = new MachineFunction(&F, TM, NextFnNum++, *this); 280d88c1a5aSDimitry Andric // Update the set entry. 281d88c1a5aSDimitry Andric I.first->second.reset(MF); 282d88c1a5aSDimitry Andric } else { 283d88c1a5aSDimitry Andric MF = I.first->second.get(); 284f22ef01cSRoman Divacky } 285f22ef01cSRoman Divacky 286d88c1a5aSDimitry Andric LastRequest = &F; 287d88c1a5aSDimitry Andric LastResult = MF; 288d88c1a5aSDimitry Andric return *MF; 289f22ef01cSRoman Divacky } 290f22ef01cSRoman Divacky 291d88c1a5aSDimitry Andric void MachineModuleInfo::deleteMachineFunctionFor(Function &F) { 292d88c1a5aSDimitry Andric MachineFunctions.erase(&F); 293d88c1a5aSDimitry Andric LastRequest = nullptr; 294d88c1a5aSDimitry Andric LastResult = nullptr; 295f22ef01cSRoman Divacky } 296f22ef01cSRoman Divacky 297d88c1a5aSDimitry Andric namespace { 298f9448bf3SDimitry Andric 299d88c1a5aSDimitry Andric /// This pass frees the MachineFunction object associated with a Function. 300d88c1a5aSDimitry Andric class FreeMachineFunction : public FunctionPass { 301d88c1a5aSDimitry Andric public: 302d88c1a5aSDimitry Andric static char ID; 303f9448bf3SDimitry Andric 304d88c1a5aSDimitry Andric FreeMachineFunction() : FunctionPass(ID) {} 305d88c1a5aSDimitry Andric 306d88c1a5aSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 307d88c1a5aSDimitry Andric AU.addRequired<MachineModuleInfo>(); 308d88c1a5aSDimitry Andric AU.addPreserved<MachineModuleInfo>(); 309ff0cc061SDimitry Andric } 310ff0cc061SDimitry Andric 311d88c1a5aSDimitry Andric bool runOnFunction(Function &F) override { 312d88c1a5aSDimitry Andric MachineModuleInfo &MMI = getAnalysis<MachineModuleInfo>(); 313d88c1a5aSDimitry Andric MMI.deleteMachineFunctionFor(F); 314d88c1a5aSDimitry Andric return true; 315ff0cc061SDimitry Andric } 3167a7e6055SDimitry Andric 3177a7e6055SDimitry Andric StringRef getPassName() const override { 3187a7e6055SDimitry Andric return "Free MachineFunction"; 3197a7e6055SDimitry Andric } 320d88c1a5aSDimitry Andric }; 321f9448bf3SDimitry Andric 322d88c1a5aSDimitry Andric } // end anonymous namespace 323ff0cc061SDimitry Andric 324f9448bf3SDimitry Andric char FreeMachineFunction::ID; 325f9448bf3SDimitry Andric 326f9448bf3SDimitry Andric FunctionPass *llvm::createFreeMachineFunctionPass() { 327d88c1a5aSDimitry Andric return new FreeMachineFunction(); 328f22ef01cSRoman Divacky } 329f22ef01cSRoman Divacky 330d88c1a5aSDimitry Andric //===- MMI building helpers -----------------------------------------------===// 331f22ef01cSRoman Divacky 332d88c1a5aSDimitry Andric void llvm::computeUsesVAFloatArgument(const CallInst &I, 333d88c1a5aSDimitry Andric MachineModuleInfo &MMI) { 334d88c1a5aSDimitry Andric FunctionType *FT = 335d88c1a5aSDimitry Andric cast<FunctionType>(I.getCalledValue()->getType()->getContainedType(0)); 336d88c1a5aSDimitry Andric if (FT->isVarArg() && !MMI.usesVAFloatArgument()) { 337d88c1a5aSDimitry Andric for (unsigned i = 0, e = I.getNumArgOperands(); i != e; ++i) { 338d88c1a5aSDimitry Andric Type *T = I.getArgOperand(i)->getType(); 339d88c1a5aSDimitry Andric for (auto i : post_order(T)) { 340d88c1a5aSDimitry Andric if (i->isFloatingPointTy()) { 341d88c1a5aSDimitry Andric MMI.setUsesVAFloatArgument(true); 342d88c1a5aSDimitry Andric return; 343f22ef01cSRoman Divacky } 344f22ef01cSRoman Divacky } 3456122f3e6SDimitry Andric } 346f22ef01cSRoman Divacky } 347f22ef01cSRoman Divacky } 348