Index: head/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp =================================================================== --- head/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp (revision 228378) +++ head/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp (revision 228379) @@ -1,1411 +1,1413 @@ //===-- llvm/CodeGen/DwarfCompileUnit.cpp - Dwarf Compile Unit ------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file contains support for writing dwarf compile unit. // //===----------------------------------------------------------------------===// #define DEBUG_TYPE "dwarfdebug" #include "DwarfCompileUnit.h" #include "DwarfDebug.h" #include "llvm/Constants.h" #include "llvm/GlobalVariable.h" #include "llvm/Instructions.h" #include "llvm/Analysis/DIBuilder.h" #include "llvm/Target/Mangler.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetFrameLowering.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/ADT/APFloat.h" #include "llvm/Support/ErrorHandling.h" using namespace llvm; /// CompileUnit - Compile unit constructor. CompileUnit::CompileUnit(unsigned I, DIE *D, AsmPrinter *A, DwarfDebug *DW) : ID(I), CUDie(D), Asm(A), DD(DW), IndexTyDie(0) { DIEIntegerOne = new (DIEValueAllocator) DIEInteger(1); } /// ~CompileUnit - Destructor for compile unit. CompileUnit::~CompileUnit() { for (unsigned j = 0, M = DIEBlocks.size(); j < M; ++j) DIEBlocks[j]->~DIEBlock(); } /// createDIEEntry - Creates a new DIEEntry to be a proxy for a debug /// information entry. DIEEntry *CompileUnit::createDIEEntry(DIE *Entry) { DIEEntry *Value = new (DIEValueAllocator) DIEEntry(Entry); return Value; } /// addUInt - Add an unsigned integer attribute data and value. /// void CompileUnit::addUInt(DIE *Die, unsigned Attribute, unsigned Form, uint64_t Integer) { if (!Form) Form = DIEInteger::BestForm(false, Integer); DIEValue *Value = Integer == 1 ? DIEIntegerOne : new (DIEValueAllocator) DIEInteger(Integer); Die->addValue(Attribute, Form, Value); } /// addSInt - Add an signed integer attribute data and value. /// void CompileUnit::addSInt(DIE *Die, unsigned Attribute, unsigned Form, int64_t Integer) { if (!Form) Form = DIEInteger::BestForm(true, Integer); DIEValue *Value = new (DIEValueAllocator) DIEInteger(Integer); Die->addValue(Attribute, Form, Value); } /// addString - Add a string attribute data and value. DIEString only /// keeps string reference. void CompileUnit::addString(DIE *Die, unsigned Attribute, unsigned Form, StringRef String) { DIEValue *Value = new (DIEValueAllocator) DIEString(String); Die->addValue(Attribute, Form, Value); } /// addLabel - Add a Dwarf label attribute data and value. /// void CompileUnit::addLabel(DIE *Die, unsigned Attribute, unsigned Form, const MCSymbol *Label) { DIEValue *Value = new (DIEValueAllocator) DIELabel(Label); Die->addValue(Attribute, Form, Value); } /// addDelta - Add a label delta attribute data and value. /// void CompileUnit::addDelta(DIE *Die, unsigned Attribute, unsigned Form, const MCSymbol *Hi, const MCSymbol *Lo) { DIEValue *Value = new (DIEValueAllocator) DIEDelta(Hi, Lo); Die->addValue(Attribute, Form, Value); } /// addDIEEntry - Add a DIE attribute data and value. /// void CompileUnit::addDIEEntry(DIE *Die, unsigned Attribute, unsigned Form, DIE *Entry) { Die->addValue(Attribute, Form, createDIEEntry(Entry)); } /// addBlock - Add block data. /// void CompileUnit::addBlock(DIE *Die, unsigned Attribute, unsigned Form, DIEBlock *Block) { Block->ComputeSize(Asm); DIEBlocks.push_back(Block); // Memoize so we can call the destructor later on. Die->addValue(Attribute, Block->BestForm(), Block); } /// addSourceLine - Add location information to specified debug information /// entry. void CompileUnit::addSourceLine(DIE *Die, DIVariable V) { // Verify variable. if (!V.Verify()) return; unsigned Line = V.getLineNumber(); if (Line == 0) return; unsigned FileID = DD->GetOrCreateSourceID(V.getContext().getFilename(), V.getContext().getDirectory()); assert(FileID && "Invalid file id"); addUInt(Die, dwarf::DW_AT_decl_file, 0, FileID); addUInt(Die, dwarf::DW_AT_decl_line, 0, Line); } /// addSourceLine - Add location information to specified debug information /// entry. void CompileUnit::addSourceLine(DIE *Die, DIGlobalVariable G) { // Verify global variable. if (!G.Verify()) return; unsigned Line = G.getLineNumber(); if (Line == 0) return; unsigned FileID = DD->GetOrCreateSourceID(G.getFilename(), G.getDirectory()); assert(FileID && "Invalid file id"); addUInt(Die, dwarf::DW_AT_decl_file, 0, FileID); addUInt(Die, dwarf::DW_AT_decl_line, 0, Line); } /// addSourceLine - Add location information to specified debug information /// entry. void CompileUnit::addSourceLine(DIE *Die, DISubprogram SP) { // Verify subprogram. if (!SP.Verify()) return; // If the line number is 0, don't add it. if (SP.getLineNumber() == 0) return; unsigned Line = SP.getLineNumber(); if (!SP.getContext().Verify()) return; unsigned FileID = DD->GetOrCreateSourceID(SP.getFilename(), SP.getDirectory()); assert(FileID && "Invalid file id"); addUInt(Die, dwarf::DW_AT_decl_file, 0, FileID); addUInt(Die, dwarf::DW_AT_decl_line, 0, Line); } /// addSourceLine - Add location information to specified debug information /// entry. void CompileUnit::addSourceLine(DIE *Die, DIType Ty) { // Verify type. if (!Ty.Verify()) return; unsigned Line = Ty.getLineNumber(); if (Line == 0 || !Ty.getContext().Verify()) return; unsigned FileID = DD->GetOrCreateSourceID(Ty.getFilename(), Ty.getDirectory()); assert(FileID && "Invalid file id"); addUInt(Die, dwarf::DW_AT_decl_file, 0, FileID); addUInt(Die, dwarf::DW_AT_decl_line, 0, Line); } /// addSourceLine - Add location information to specified debug information /// entry. void CompileUnit::addSourceLine(DIE *Die, DINameSpace NS) { // Verify namespace. if (!NS.Verify()) return; unsigned Line = NS.getLineNumber(); if (Line == 0) return; StringRef FN = NS.getFilename(); unsigned FileID = DD->GetOrCreateSourceID(FN, NS.getDirectory()); assert(FileID && "Invalid file id"); addUInt(Die, dwarf::DW_AT_decl_file, 0, FileID); addUInt(Die, dwarf::DW_AT_decl_line, 0, Line); } /// addVariableAddress - Add DW_AT_location attribute for a /// DbgVariable based on provided MachineLocation. void CompileUnit::addVariableAddress(DbgVariable *&DV, DIE *Die, MachineLocation Location) { if (DV->variableHasComplexAddress()) addComplexAddress(DV, Die, dwarf::DW_AT_location, Location); else if (DV->isBlockByrefVariable()) addBlockByrefAddress(DV, Die, dwarf::DW_AT_location, Location); else addAddress(Die, dwarf::DW_AT_location, Location); } /// addRegisterOp - Add register operand. void CompileUnit::addRegisterOp(DIE *TheDie, unsigned Reg) { const TargetRegisterInfo *RI = Asm->TM.getRegisterInfo(); unsigned DWReg = RI->getDwarfRegNum(Reg, false); if (DWReg < 32) addUInt(TheDie, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_reg0 + DWReg); else { addUInt(TheDie, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_regx); addUInt(TheDie, 0, dwarf::DW_FORM_udata, DWReg); } } /// addRegisterOffset - Add register offset. void CompileUnit::addRegisterOffset(DIE *TheDie, unsigned Reg, int64_t Offset) { const TargetRegisterInfo *RI = Asm->TM.getRegisterInfo(); unsigned DWReg = RI->getDwarfRegNum(Reg, false); const TargetRegisterInfo *TRI = Asm->TM.getRegisterInfo(); if (Reg == TRI->getFrameRegister(*Asm->MF)) // If variable offset is based in frame register then use fbreg. addUInt(TheDie, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_fbreg); else if (DWReg < 32) addUInt(TheDie, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_breg0 + DWReg); else { addUInt(TheDie, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_bregx); addUInt(TheDie, 0, dwarf::DW_FORM_udata, DWReg); } addSInt(TheDie, 0, dwarf::DW_FORM_sdata, Offset); } /// addAddress - Add an address attribute to a die based on the location /// provided. void CompileUnit::addAddress(DIE *Die, unsigned Attribute, const MachineLocation &Location) { DIEBlock *Block = new (DIEValueAllocator) DIEBlock(); if (Location.isReg()) addRegisterOp(Block, Location.getReg()); else addRegisterOffset(Block, Location.getReg(), Location.getOffset()); // Now attach the location information to the DIE. addBlock(Die, Attribute, 0, Block); } /// addComplexAddress - Start with the address based on the location provided, /// and generate the DWARF information necessary to find the actual variable /// given the extra address information encoded in the DIVariable, starting from /// the starting location. Add the DWARF information to the die. /// void CompileUnit::addComplexAddress(DbgVariable *&DV, DIE *Die, unsigned Attribute, const MachineLocation &Location) { DIEBlock *Block = new (DIEValueAllocator) DIEBlock(); unsigned N = DV->getNumAddrElements(); unsigned i = 0; if (Location.isReg()) { if (N >= 2 && DV->getAddrElement(0) == DIBuilder::OpPlus) { // If first address element is OpPlus then emit // DW_OP_breg + Offset instead of DW_OP_reg + Offset. addRegisterOffset(Block, Location.getReg(), DV->getAddrElement(1)); i = 2; } else addRegisterOp(Block, Location.getReg()); } else addRegisterOffset(Block, Location.getReg(), Location.getOffset()); for (;i < N; ++i) { uint64_t Element = DV->getAddrElement(i); if (Element == DIBuilder::OpPlus) { addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst); addUInt(Block, 0, dwarf::DW_FORM_udata, DV->getAddrElement(++i)); } else if (Element == DIBuilder::OpDeref) { addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_deref); } else llvm_unreachable("unknown DIBuilder Opcode"); } // Now attach the location information to the DIE. addBlock(Die, Attribute, 0, Block); } /* Byref variables, in Blocks, are declared by the programmer as "SomeType VarName;", but the compiler creates a __Block_byref_x_VarName struct, and gives the variable VarName either the struct, or a pointer to the struct, as its type. This is necessary for various behind-the-scenes things the compiler needs to do with by-reference variables in Blocks. However, as far as the original *programmer* is concerned, the variable should still have type 'SomeType', as originally declared. The function getBlockByrefType dives into the __Block_byref_x_VarName struct to find the original type of the variable, which is then assigned to the variable's Debug Information Entry as its real type. So far, so good. However now the debugger will expect the variable VarName to have the type SomeType. So we need the location attribute for the variable to be an expression that explains to the debugger how to navigate through the pointers and struct to find the actual variable of type SomeType. The following function does just that. We start by getting the "normal" location for the variable. This will be the location of either the struct __Block_byref_x_VarName or the pointer to the struct __Block_byref_x_VarName. The struct will look something like: struct __Block_byref_x_VarName { ... struct __Block_byref_x_VarName *forwarding; ... SomeType VarName; ... }; If we are given the struct directly (as our starting point) we need to tell the debugger to: 1). Add the offset of the forwarding field. 2). Follow that pointer to get the real __Block_byref_x_VarName struct to use (the real one may have been copied onto the heap). 3). Add the offset for the field VarName, to find the actual variable. If we started with a pointer to the struct, then we need to dereference that pointer first, before the other steps. Translating this into DWARF ops, we will need to append the following to the current location description for the variable: DW_OP_deref -- optional, if we start with a pointer DW_OP_plus_uconst DW_OP_deref DW_OP_plus_uconst That is what this function does. */ /// addBlockByrefAddress - Start with the address based on the location /// provided, and generate the DWARF information necessary to find the /// actual Block variable (navigating the Block struct) based on the /// starting location. Add the DWARF information to the die. For /// more information, read large comment just above here. /// void CompileUnit::addBlockByrefAddress(DbgVariable *&DV, DIE *Die, unsigned Attribute, const MachineLocation &Location) { DIType Ty = DV->getType(); DIType TmpTy = Ty; unsigned Tag = Ty.getTag(); bool isPointer = false; StringRef varName = DV->getName(); if (Tag == dwarf::DW_TAG_pointer_type) { DIDerivedType DTy = DIDerivedType(Ty); TmpTy = DTy.getTypeDerivedFrom(); isPointer = true; } DICompositeType blockStruct = DICompositeType(TmpTy); // Find the __forwarding field and the variable field in the __Block_byref // struct. DIArray Fields = blockStruct.getTypeArray(); DIDescriptor varField = DIDescriptor(); DIDescriptor forwardingField = DIDescriptor(); for (unsigned i = 0, N = Fields.getNumElements(); i < N; ++i) { DIDescriptor Element = Fields.getElement(i); DIDerivedType DT = DIDerivedType(Element); StringRef fieldName = DT.getName(); if (fieldName == "__forwarding") forwardingField = Element; else if (fieldName == varName) varField = Element; } // Get the offsets for the forwarding field and the variable field. unsigned forwardingFieldOffset = DIDerivedType(forwardingField).getOffsetInBits() >> 3; unsigned varFieldOffset = DIDerivedType(varField).getOffsetInBits() >> 3; // Decode the original location, and use that as the start of the byref // variable's location. const TargetRegisterInfo *RI = Asm->TM.getRegisterInfo(); unsigned Reg = RI->getDwarfRegNum(Location.getReg(), false); DIEBlock *Block = new (DIEValueAllocator) DIEBlock(); if (Location.isReg()) { if (Reg < 32) addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_reg0 + Reg); else { addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_regx); addUInt(Block, 0, dwarf::DW_FORM_udata, Reg); } } else { if (Reg < 32) addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_breg0 + Reg); else { addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_bregx); addUInt(Block, 0, dwarf::DW_FORM_udata, Reg); } addUInt(Block, 0, dwarf::DW_FORM_sdata, Location.getOffset()); } // If we started with a pointer to the __Block_byref... struct, then // the first thing we need to do is dereference the pointer (DW_OP_deref). if (isPointer) addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_deref); // Next add the offset for the '__forwarding' field: // DW_OP_plus_uconst ForwardingFieldOffset. Note there's no point in // adding the offset if it's 0. if (forwardingFieldOffset > 0) { addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst); addUInt(Block, 0, dwarf::DW_FORM_udata, forwardingFieldOffset); } // Now dereference the __forwarding field to get to the real __Block_byref // struct: DW_OP_deref. addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_deref); // Now that we've got the real __Block_byref... struct, add the offset // for the variable's field to get to the location of the actual variable: // DW_OP_plus_uconst varFieldOffset. Again, don't add if it's 0. if (varFieldOffset > 0) { addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst); addUInt(Block, 0, dwarf::DW_FORM_udata, varFieldOffset); } // Now attach the location information to the DIE. addBlock(Die, Attribute, 0, Block); } /// isTypeSigned - Return true if the type is signed. static bool isTypeSigned(DIType Ty, int *SizeInBits) { if (Ty.isDerivedType()) return isTypeSigned(DIDerivedType(Ty).getTypeDerivedFrom(), SizeInBits); if (Ty.isBasicType()) if (DIBasicType(Ty).getEncoding() == dwarf::DW_ATE_signed || DIBasicType(Ty).getEncoding() == dwarf::DW_ATE_signed_char) { *SizeInBits = Ty.getSizeInBits(); return true; } return false; } /// addConstantValue - Add constant value entry in variable DIE. bool CompileUnit::addConstantValue(DIE *Die, const MachineOperand &MO, DIType Ty) { assert (MO.isImm() && "Invalid machine operand!"); DIEBlock *Block = new (DIEValueAllocator) DIEBlock(); int SizeInBits = -1; bool SignedConstant = isTypeSigned(Ty, &SizeInBits); unsigned Form = SignedConstant ? dwarf::DW_FORM_sdata : dwarf::DW_FORM_udata; switch (SizeInBits) { case 8: Form = dwarf::DW_FORM_data1; break; case 16: Form = dwarf::DW_FORM_data2; break; case 32: Form = dwarf::DW_FORM_data4; break; case 64: Form = dwarf::DW_FORM_data8; break; default: break; } SignedConstant ? addSInt(Block, 0, Form, MO.getImm()) : addUInt(Block, 0, Form, MO.getImm()); addBlock(Die, dwarf::DW_AT_const_value, 0, Block); return true; } /// addConstantFPValue - Add constant value entry in variable DIE. bool CompileUnit::addConstantFPValue(DIE *Die, const MachineOperand &MO) { assert (MO.isFPImm() && "Invalid machine operand!"); DIEBlock *Block = new (DIEValueAllocator) DIEBlock(); APFloat FPImm = MO.getFPImm()->getValueAPF(); // Get the raw data form of the floating point. const APInt FltVal = FPImm.bitcastToAPInt(); const char *FltPtr = (const char*)FltVal.getRawData(); int NumBytes = FltVal.getBitWidth() / 8; // 8 bits per byte. bool LittleEndian = Asm->getTargetData().isLittleEndian(); int Incr = (LittleEndian ? 1 : -1); int Start = (LittleEndian ? 0 : NumBytes - 1); int Stop = (LittleEndian ? NumBytes : -1); // Output the constant to DWARF one byte at a time. for (; Start != Stop; Start += Incr) addUInt(Block, 0, dwarf::DW_FORM_data1, (unsigned char)0xFF & FltPtr[Start]); addBlock(Die, dwarf::DW_AT_const_value, 0, Block); return true; } /// addConstantValue - Add constant value entry in variable DIE. bool CompileUnit::addConstantValue(DIE *Die, const ConstantInt *CI, bool Unsigned) { unsigned CIBitWidth = CI->getBitWidth(); if (CIBitWidth <= 64) { unsigned form = 0; switch (CIBitWidth) { case 8: form = dwarf::DW_FORM_data1; break; case 16: form = dwarf::DW_FORM_data2; break; case 32: form = dwarf::DW_FORM_data4; break; case 64: form = dwarf::DW_FORM_data8; break; default: form = Unsigned ? dwarf::DW_FORM_udata : dwarf::DW_FORM_sdata; } if (Unsigned) addUInt(Die, dwarf::DW_AT_const_value, form, CI->getZExtValue()); else addSInt(Die, dwarf::DW_AT_const_value, form, CI->getSExtValue()); return true; } DIEBlock *Block = new (DIEValueAllocator) DIEBlock(); // Get the raw data form of the large APInt. const APInt Val = CI->getValue(); - const char *Ptr = (const char*)Val.getRawData(); + const uint64_t *Ptr64 = Val.getRawData(); int NumBytes = Val.getBitWidth() / 8; // 8 bits per byte. bool LittleEndian = Asm->getTargetData().isLittleEndian(); - int Incr = (LittleEndian ? 1 : -1); - int Start = (LittleEndian ? 0 : NumBytes - 1); - int Stop = (LittleEndian ? NumBytes : -1); // Output the constant to DWARF one byte at a time. - for (; Start != Stop; Start += Incr) - addUInt(Block, 0, dwarf::DW_FORM_data1, - (unsigned char)0xFF & Ptr[Start]); + for (int i = 0; i < NumBytes; i++) { + uint8_t c; + if (LittleEndian) + c = Ptr64[i / 8] >> (8 * (i & 7)); + else + c = Ptr64[(NumBytes - 1 - i) / 8] >> (8 * ((NumBytes - 1 - i) & 7)); + addUInt(Block, 0, dwarf::DW_FORM_data1, c); + } addBlock(Die, dwarf::DW_AT_const_value, 0, Block); return true; } /// addTemplateParams - Add template parameters in buffer. void CompileUnit::addTemplateParams(DIE &Buffer, DIArray TParams) { // Add template parameters. for (unsigned i = 0, e = TParams.getNumElements(); i != e; ++i) { DIDescriptor Element = TParams.getElement(i); if (Element.isTemplateTypeParameter()) Buffer.addChild(getOrCreateTemplateTypeParameterDIE( DITemplateTypeParameter(Element))); else if (Element.isTemplateValueParameter()) Buffer.addChild(getOrCreateTemplateValueParameterDIE( DITemplateValueParameter(Element))); } } /// addToContextOwner - Add Die into the list of its context owner's children. void CompileUnit::addToContextOwner(DIE *Die, DIDescriptor Context) { if (Context.isType()) { DIE *ContextDIE = getOrCreateTypeDIE(DIType(Context)); ContextDIE->addChild(Die); } else if (Context.isNameSpace()) { DIE *ContextDIE = getOrCreateNameSpace(DINameSpace(Context)); ContextDIE->addChild(Die); } else if (Context.isSubprogram()) { DIE *ContextDIE = getOrCreateSubprogramDIE(DISubprogram(Context)); ContextDIE->addChild(Die); } else if (DIE *ContextDIE = getDIE(Context)) ContextDIE->addChild(Die); else addDie(Die); } /// getOrCreateTypeDIE - Find existing DIE or create new DIE for the /// given DIType. DIE *CompileUnit::getOrCreateTypeDIE(const MDNode *TyNode) { DIType Ty(TyNode); if (!Ty.Verify()) return NULL; DIE *TyDIE = getDIE(Ty); if (TyDIE) return TyDIE; // Create new type. TyDIE = new DIE(dwarf::DW_TAG_base_type); insertDIE(Ty, TyDIE); if (Ty.isBasicType()) constructTypeDIE(*TyDIE, DIBasicType(Ty)); else if (Ty.isCompositeType()) constructTypeDIE(*TyDIE, DICompositeType(Ty)); else { assert(Ty.isDerivedType() && "Unknown kind of DIType"); constructTypeDIE(*TyDIE, DIDerivedType(Ty)); } addToContextOwner(TyDIE, Ty.getContext()); return TyDIE; } /// addType - Add a new type attribute to the specified entity. void CompileUnit::addType(DIE *Entity, DIType Ty) { if (!Ty.Verify()) return; // Check for pre-existence. DIEEntry *Entry = getDIEEntry(Ty); // If it exists then use the existing value. if (Entry) { Entity->addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, Entry); return; } // Construct type. DIE *Buffer = getOrCreateTypeDIE(Ty); // Set up proxy. Entry = createDIEEntry(Buffer); insertDIEEntry(Ty, Entry); Entity->addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, Entry); // If this is a complete composite type then include it in the // list of global types. addGlobalType(Ty); } /// addGlobalType - Add a new global type to the compile unit. /// void CompileUnit::addGlobalType(DIType Ty) { DIDescriptor Context = Ty.getContext(); if (Ty.isCompositeType() && !Ty.getName().empty() && !Ty.isForwardDecl() && (!Context || Context.isCompileUnit() || Context.isFile() || Context.isNameSpace())) if (DIEEntry *Entry = getDIEEntry(Ty)) GlobalTypes[Ty.getName()] = Entry->getEntry(); } /// addPubTypes - Add type for pubtypes section. void CompileUnit::addPubTypes(DISubprogram SP) { DICompositeType SPTy = SP.getType(); unsigned SPTag = SPTy.getTag(); if (SPTag != dwarf::DW_TAG_subroutine_type) return; DIArray Args = SPTy.getTypeArray(); for (unsigned i = 0, e = Args.getNumElements(); i != e; ++i) { DIType ATy(Args.getElement(i)); if (!ATy.Verify()) continue; addGlobalType(ATy); } } /// constructTypeDIE - Construct basic type die from DIBasicType. void CompileUnit::constructTypeDIE(DIE &Buffer, DIBasicType BTy) { // Get core information. StringRef Name = BTy.getName(); // Add name if not anonymous or intermediate type. if (!Name.empty()) addString(&Buffer, dwarf::DW_AT_name, dwarf::DW_FORM_string, Name); if (BTy.getTag() == dwarf::DW_TAG_unspecified_type) { Buffer.setTag(dwarf::DW_TAG_unspecified_type); // Unspecified types has only name, nothing else. return; } Buffer.setTag(dwarf::DW_TAG_base_type); addUInt(&Buffer, dwarf::DW_AT_encoding, dwarf::DW_FORM_data1, BTy.getEncoding()); uint64_t Size = BTy.getSizeInBits() >> 3; addUInt(&Buffer, dwarf::DW_AT_byte_size, 0, Size); } /// constructTypeDIE - Construct derived type die from DIDerivedType. void CompileUnit::constructTypeDIE(DIE &Buffer, DIDerivedType DTy) { // Get core information. StringRef Name = DTy.getName(); uint64_t Size = DTy.getSizeInBits() >> 3; unsigned Tag = DTy.getTag(); // FIXME - Workaround for templates. if (Tag == dwarf::DW_TAG_inheritance) Tag = dwarf::DW_TAG_reference_type; Buffer.setTag(Tag); // Map to main type, void will not have a type. DIType FromTy = DTy.getTypeDerivedFrom(); addType(&Buffer, FromTy); // Add name if not anonymous or intermediate type. if (!Name.empty()) addString(&Buffer, dwarf::DW_AT_name, dwarf::DW_FORM_string, Name); // Add size if non-zero (derived types might be zero-sized.) if (Size) addUInt(&Buffer, dwarf::DW_AT_byte_size, 0, Size); // Add source line info if available and TyDesc is not a forward declaration. if (!DTy.isForwardDecl()) addSourceLine(&Buffer, DTy); } /// constructTypeDIE - Construct type DIE from DICompositeType. void CompileUnit::constructTypeDIE(DIE &Buffer, DICompositeType CTy) { // Get core information. StringRef Name = CTy.getName(); uint64_t Size = CTy.getSizeInBits() >> 3; unsigned Tag = CTy.getTag(); Buffer.setTag(Tag); switch (Tag) { case dwarf::DW_TAG_vector_type: case dwarf::DW_TAG_array_type: constructArrayTypeDIE(Buffer, &CTy); break; case dwarf::DW_TAG_enumeration_type: { DIArray Elements = CTy.getTypeArray(); // Add enumerators to enumeration type. for (unsigned i = 0, N = Elements.getNumElements(); i < N; ++i) { DIE *ElemDie = NULL; DIDescriptor Enum(Elements.getElement(i)); if (Enum.isEnumerator()) { ElemDie = constructEnumTypeDIE(DIEnumerator(Enum)); Buffer.addChild(ElemDie); } } } break; case dwarf::DW_TAG_subroutine_type: { // Add return type. DIArray Elements = CTy.getTypeArray(); DIDescriptor RTy = Elements.getElement(0); addType(&Buffer, DIType(RTy)); bool isPrototyped = true; // Add arguments. for (unsigned i = 1, N = Elements.getNumElements(); i < N; ++i) { DIDescriptor Ty = Elements.getElement(i); if (Ty.isUnspecifiedParameter()) { DIE *Arg = new DIE(dwarf::DW_TAG_unspecified_parameters); Buffer.addChild(Arg); isPrototyped = false; } else { DIE *Arg = new DIE(dwarf::DW_TAG_formal_parameter); addType(Arg, DIType(Ty)); Buffer.addChild(Arg); } } // Add prototype flag. if (isPrototyped) addUInt(&Buffer, dwarf::DW_AT_prototyped, dwarf::DW_FORM_flag, 1); } break; case dwarf::DW_TAG_structure_type: case dwarf::DW_TAG_union_type: case dwarf::DW_TAG_class_type: { // Add elements to structure type. DIArray Elements = CTy.getTypeArray(); // A forward struct declared type may not have elements available. unsigned N = Elements.getNumElements(); if (N == 0) break; // Add elements to structure type. for (unsigned i = 0; i < N; ++i) { DIDescriptor Element = Elements.getElement(i); DIE *ElemDie = NULL; if (Element.isSubprogram()) { DISubprogram SP(Element); ElemDie = getOrCreateSubprogramDIE(DISubprogram(Element)); if (SP.isProtected()) addUInt(ElemDie, dwarf::DW_AT_accessibility, dwarf::DW_FORM_flag, dwarf::DW_ACCESS_protected); else if (SP.isPrivate()) addUInt(ElemDie, dwarf::DW_AT_accessibility, dwarf::DW_FORM_flag, dwarf::DW_ACCESS_private); else addUInt(ElemDie, dwarf::DW_AT_accessibility, dwarf::DW_FORM_flag, dwarf::DW_ACCESS_public); if (SP.isExplicit()) addUInt(ElemDie, dwarf::DW_AT_explicit, dwarf::DW_FORM_flag, 1); } else if (Element.isVariable()) { DIVariable DV(Element); ElemDie = new DIE(dwarf::DW_TAG_variable); addString(ElemDie, dwarf::DW_AT_name, dwarf::DW_FORM_string, DV.getName()); addType(ElemDie, DV.getType()); addUInt(ElemDie, dwarf::DW_AT_declaration, dwarf::DW_FORM_flag, 1); addUInt(ElemDie, dwarf::DW_AT_external, dwarf::DW_FORM_flag, 1); addSourceLine(ElemDie, DV); } else if (Element.isDerivedType()) ElemDie = createMemberDIE(DIDerivedType(Element)); else continue; Buffer.addChild(ElemDie); } if (CTy.isAppleBlockExtension()) addUInt(&Buffer, dwarf::DW_AT_APPLE_block, dwarf::DW_FORM_flag, 1); unsigned RLang = CTy.getRunTimeLang(); if (RLang) addUInt(&Buffer, dwarf::DW_AT_APPLE_runtime_class, dwarf::DW_FORM_data1, RLang); DICompositeType ContainingType = CTy.getContainingType(); if (DIDescriptor(ContainingType).isCompositeType()) addDIEEntry(&Buffer, dwarf::DW_AT_containing_type, dwarf::DW_FORM_ref4, getOrCreateTypeDIE(DIType(ContainingType))); else { DIDescriptor Context = CTy.getContext(); addToContextOwner(&Buffer, Context); } if (CTy.isObjcClassComplete()) addUInt(&Buffer, dwarf::DW_AT_APPLE_objc_complete_type, dwarf::DW_FORM_flag, 1); if (Tag == dwarf::DW_TAG_class_type) addTemplateParams(Buffer, CTy.getTemplateParams()); break; } default: break; } // Add name if not anonymous or intermediate type. if (!Name.empty()) addString(&Buffer, dwarf::DW_AT_name, dwarf::DW_FORM_string, Name); if (Tag == dwarf::DW_TAG_enumeration_type || Tag == dwarf::DW_TAG_class_type || Tag == dwarf::DW_TAG_structure_type || Tag == dwarf::DW_TAG_union_type) { // Add size if non-zero (derived types might be zero-sized.) if (Size) addUInt(&Buffer, dwarf::DW_AT_byte_size, 0, Size); else { // Add zero size if it is not a forward declaration. if (CTy.isForwardDecl()) addUInt(&Buffer, dwarf::DW_AT_declaration, dwarf::DW_FORM_flag, 1); else addUInt(&Buffer, dwarf::DW_AT_byte_size, 0, 0); } // Add source line info if available. if (!CTy.isForwardDecl()) addSourceLine(&Buffer, CTy); } } /// getOrCreateTemplateTypeParameterDIE - Find existing DIE or create new DIE /// for the given DITemplateTypeParameter. DIE * CompileUnit::getOrCreateTemplateTypeParameterDIE(DITemplateTypeParameter TP) { DIE *ParamDIE = getDIE(TP); if (ParamDIE) return ParamDIE; ParamDIE = new DIE(dwarf::DW_TAG_template_type_parameter); addType(ParamDIE, TP.getType()); addString(ParamDIE, dwarf::DW_AT_name, dwarf::DW_FORM_string, TP.getName()); return ParamDIE; } /// getOrCreateTemplateValueParameterDIE - Find existing DIE or create new DIE /// for the given DITemplateValueParameter. DIE * CompileUnit::getOrCreateTemplateValueParameterDIE(DITemplateValueParameter TPV) { DIE *ParamDIE = getDIE(TPV); if (ParamDIE) return ParamDIE; ParamDIE = new DIE(dwarf::DW_TAG_template_value_parameter); addType(ParamDIE, TPV.getType()); if (!TPV.getName().empty()) addString(ParamDIE, dwarf::DW_AT_name, dwarf::DW_FORM_string, TPV.getName()); addUInt(ParamDIE, dwarf::DW_AT_const_value, dwarf::DW_FORM_udata, TPV.getValue()); return ParamDIE; } /// getOrCreateNameSpace - Create a DIE for DINameSpace. DIE *CompileUnit::getOrCreateNameSpace(DINameSpace NS) { DIE *NDie = getDIE(NS); if (NDie) return NDie; NDie = new DIE(dwarf::DW_TAG_namespace); insertDIE(NS, NDie); if (!NS.getName().empty()) addString(NDie, dwarf::DW_AT_name, dwarf::DW_FORM_string, NS.getName()); addSourceLine(NDie, NS); addToContextOwner(NDie, NS.getContext()); return NDie; } /// getRealLinkageName - If special LLVM prefix that is used to inform the asm /// printer to not emit usual symbol prefix before the symbol name is used then /// return linkage name after skipping this special LLVM prefix. static StringRef getRealLinkageName(StringRef LinkageName) { char One = '\1'; if (LinkageName.startswith(StringRef(&One, 1))) return LinkageName.substr(1); return LinkageName; } /// getOrCreateSubprogramDIE - Create new DIE using SP. DIE *CompileUnit::getOrCreateSubprogramDIE(DISubprogram SP) { DIE *SPDie = getDIE(SP); if (SPDie) return SPDie; SPDie = new DIE(dwarf::DW_TAG_subprogram); // DW_TAG_inlined_subroutine may refer to this DIE. insertDIE(SP, SPDie); // Add to context owner. addToContextOwner(SPDie, SP.getContext()); // Add function template parameters. addTemplateParams(*SPDie, SP.getTemplateParams()); StringRef LinkageName = SP.getLinkageName(); if (!LinkageName.empty()) addString(SPDie, dwarf::DW_AT_MIPS_linkage_name, dwarf::DW_FORM_string, getRealLinkageName(LinkageName)); // If this DIE is going to refer declaration info using AT_specification // then there is no need to add other attributes. if (SP.getFunctionDeclaration().isSubprogram()) return SPDie; // Constructors and operators for anonymous aggregates do not have names. if (!SP.getName().empty()) addString(SPDie, dwarf::DW_AT_name, dwarf::DW_FORM_string, SP.getName()); addSourceLine(SPDie, SP); if (SP.isPrototyped()) addUInt(SPDie, dwarf::DW_AT_prototyped, dwarf::DW_FORM_flag, 1); // Add Return Type. DICompositeType SPTy = SP.getType(); DIArray Args = SPTy.getTypeArray(); unsigned SPTag = SPTy.getTag(); if (Args.getNumElements() == 0 || SPTag != dwarf::DW_TAG_subroutine_type) addType(SPDie, SPTy); else addType(SPDie, DIType(Args.getElement(0))); unsigned VK = SP.getVirtuality(); if (VK) { addUInt(SPDie, dwarf::DW_AT_virtuality, dwarf::DW_FORM_flag, VK); DIEBlock *Block = getDIEBlock(); addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_constu); addUInt(Block, 0, dwarf::DW_FORM_udata, SP.getVirtualIndex()); addBlock(SPDie, dwarf::DW_AT_vtable_elem_location, 0, Block); ContainingTypeMap.insert(std::make_pair(SPDie, SP.getContainingType())); } if (!SP.isDefinition()) { addUInt(SPDie, dwarf::DW_AT_declaration, dwarf::DW_FORM_flag, 1); // Add arguments. Do not add arguments for subprogram definition. They will // be handled while processing variables. DICompositeType SPTy = SP.getType(); DIArray Args = SPTy.getTypeArray(); unsigned SPTag = SPTy.getTag(); if (SPTag == dwarf::DW_TAG_subroutine_type) for (unsigned i = 1, N = Args.getNumElements(); i < N; ++i) { DIE *Arg = new DIE(dwarf::DW_TAG_formal_parameter); DIType ATy = DIType(DIType(Args.getElement(i))); addType(Arg, ATy); if (ATy.isArtificial()) addUInt(Arg, dwarf::DW_AT_artificial, dwarf::DW_FORM_flag, 1); SPDie->addChild(Arg); } } if (SP.isArtificial()) addUInt(SPDie, dwarf::DW_AT_artificial, dwarf::DW_FORM_flag, 1); if (!SP.isLocalToUnit()) addUInt(SPDie, dwarf::DW_AT_external, dwarf::DW_FORM_flag, 1); if (SP.isOptimized()) addUInt(SPDie, dwarf::DW_AT_APPLE_optimized, dwarf::DW_FORM_flag, 1); if (unsigned isa = Asm->getISAEncoding()) { addUInt(SPDie, dwarf::DW_AT_APPLE_isa, dwarf::DW_FORM_flag, isa); } return SPDie; } // Return const expression if value is a GEP to access merged global // constant. e.g. // i8* getelementptr ({ i8, i8, i8, i8 }* @_MergedGlobals, i32 0, i32 0) static const ConstantExpr *getMergedGlobalExpr(const Value *V) { const ConstantExpr *CE = dyn_cast_or_null(V); if (!CE || CE->getNumOperands() != 3 || CE->getOpcode() != Instruction::GetElementPtr) return NULL; // First operand points to a global struct. Value *Ptr = CE->getOperand(0); if (!isa(Ptr) || !isa(cast(Ptr->getType())->getElementType())) return NULL; // Second operand is zero. const ConstantInt *CI = dyn_cast_or_null(CE->getOperand(1)); if (!CI || !CI->isZero()) return NULL; // Third operand is offset. if (!isa(CE->getOperand(2))) return NULL; return CE; } /// createGlobalVariableDIE - create global variable DIE. void CompileUnit::createGlobalVariableDIE(const MDNode *N) { // Check for pre-existence. if (getDIE(N)) return; DIGlobalVariable GV(N); if (!GV.Verify()) return; DIE *VariableDIE = new DIE(GV.getTag()); // Add to map. insertDIE(N, VariableDIE); // Add name. addString(VariableDIE, dwarf::DW_AT_name, dwarf::DW_FORM_string, GV.getDisplayName()); StringRef LinkageName = GV.getLinkageName(); bool isGlobalVariable = GV.getGlobal() != NULL; if (!LinkageName.empty() && isGlobalVariable) addString(VariableDIE, dwarf::DW_AT_MIPS_linkage_name, dwarf::DW_FORM_string, getRealLinkageName(LinkageName)); // Add type. DIType GTy = GV.getType(); addType(VariableDIE, GTy); // Add scoping info. if (!GV.isLocalToUnit()) { addUInt(VariableDIE, dwarf::DW_AT_external, dwarf::DW_FORM_flag, 1); // Expose as global. addGlobal(GV.getName(), VariableDIE); } // Add line number info. addSourceLine(VariableDIE, GV); // Add to context owner. DIDescriptor GVContext = GV.getContext(); addToContextOwner(VariableDIE, GVContext); // Add location. if (isGlobalVariable) { DIEBlock *Block = new (DIEValueAllocator) DIEBlock(); addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_addr); addLabel(Block, 0, dwarf::DW_FORM_udata, Asm->Mang->getSymbol(GV.getGlobal())); // Do not create specification DIE if context is either compile unit // or a subprogram. if (GVContext && GV.isDefinition() && !GVContext.isCompileUnit() && !GVContext.isFile() && !isSubprogramContext(GVContext)) { // Create specification DIE. DIE *VariableSpecDIE = new DIE(dwarf::DW_TAG_variable); addDIEEntry(VariableSpecDIE, dwarf::DW_AT_specification, dwarf::DW_FORM_ref4, VariableDIE); addBlock(VariableSpecDIE, dwarf::DW_AT_location, 0, Block); addUInt(VariableDIE, dwarf::DW_AT_declaration, dwarf::DW_FORM_flag, 1); addDie(VariableSpecDIE); } else { addBlock(VariableDIE, dwarf::DW_AT_location, 0, Block); } } else if (const ConstantInt *CI = dyn_cast_or_null(GV.getConstant())) addConstantValue(VariableDIE, CI, GTy.isUnsignedDIType()); else if (const ConstantExpr *CE = getMergedGlobalExpr(N->getOperand(11))) { // GV is a merged global. DIEBlock *Block = new (DIEValueAllocator) DIEBlock(); Value *Ptr = CE->getOperand(0); addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_addr); addLabel(Block, 0, dwarf::DW_FORM_udata, Asm->Mang->getSymbol(cast(Ptr))); addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_constu); SmallVector Idx(CE->op_begin()+1, CE->op_end()); addUInt(Block, 0, dwarf::DW_FORM_udata, Asm->getTargetData().getIndexedOffset(Ptr->getType(), Idx)); addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_plus); addBlock(VariableDIE, dwarf::DW_AT_location, 0, Block); } return; } /// constructSubrangeDIE - Construct subrange DIE from DISubrange. void CompileUnit::constructSubrangeDIE(DIE &Buffer, DISubrange SR, DIE *IndexTy){ DIE *DW_Subrange = new DIE(dwarf::DW_TAG_subrange_type); addDIEEntry(DW_Subrange, dwarf::DW_AT_type, dwarf::DW_FORM_ref4, IndexTy); int64_t L = SR.getLo(); int64_t H = SR.getHi(); // The L value defines the lower bounds which is typically zero for C/C++. The // H value is the upper bounds. Values are 64 bit. H - L + 1 is the size // of the array. If L > H then do not emit DW_AT_lower_bound and // DW_AT_upper_bound attributes. If L is zero and H is also zero then the // array has one element and in such case do not emit lower bound. if (L > H) { Buffer.addChild(DW_Subrange); return; } if (L) addSInt(DW_Subrange, dwarf::DW_AT_lower_bound, 0, L); addSInt(DW_Subrange, dwarf::DW_AT_upper_bound, 0, H); Buffer.addChild(DW_Subrange); } /// constructArrayTypeDIE - Construct array type DIE from DICompositeType. void CompileUnit::constructArrayTypeDIE(DIE &Buffer, DICompositeType *CTy) { Buffer.setTag(dwarf::DW_TAG_array_type); if (CTy->getTag() == dwarf::DW_TAG_vector_type) addUInt(&Buffer, dwarf::DW_AT_GNU_vector, dwarf::DW_FORM_flag, 1); // Emit derived type. addType(&Buffer, CTy->getTypeDerivedFrom()); DIArray Elements = CTy->getTypeArray(); // Get an anonymous type for index type. DIE *IdxTy = getIndexTyDie(); if (!IdxTy) { // Construct an anonymous type for index type. IdxTy = new DIE(dwarf::DW_TAG_base_type); addUInt(IdxTy, dwarf::DW_AT_byte_size, 0, sizeof(int32_t)); addUInt(IdxTy, dwarf::DW_AT_encoding, dwarf::DW_FORM_data1, dwarf::DW_ATE_signed); addDie(IdxTy); setIndexTyDie(IdxTy); } // Add subranges to array type. for (unsigned i = 0, N = Elements.getNumElements(); i < N; ++i) { DIDescriptor Element = Elements.getElement(i); if (Element.getTag() == dwarf::DW_TAG_subrange_type) constructSubrangeDIE(Buffer, DISubrange(Element), IdxTy); } } /// constructEnumTypeDIE - Construct enum type DIE from DIEnumerator. DIE *CompileUnit::constructEnumTypeDIE(DIEnumerator ETy) { DIE *Enumerator = new DIE(dwarf::DW_TAG_enumerator); StringRef Name = ETy.getName(); addString(Enumerator, dwarf::DW_AT_name, dwarf::DW_FORM_string, Name); int64_t Value = ETy.getEnumValue(); addSInt(Enumerator, dwarf::DW_AT_const_value, dwarf::DW_FORM_sdata, Value); return Enumerator; } /// constructContainingTypeDIEs - Construct DIEs for types that contain /// vtables. void CompileUnit::constructContainingTypeDIEs() { for (DenseMap::iterator CI = ContainingTypeMap.begin(), CE = ContainingTypeMap.end(); CI != CE; ++CI) { DIE *SPDie = CI->first; const MDNode *N = CI->second; if (!N) continue; DIE *NDie = getDIE(N); if (!NDie) continue; addDIEEntry(SPDie, dwarf::DW_AT_containing_type, dwarf::DW_FORM_ref4, NDie); } } /// constructVariableDIE - Construct a DIE for the given DbgVariable. DIE *CompileUnit::constructVariableDIE(DbgVariable *DV, bool isScopeAbstract) { StringRef Name = DV->getName(); if (Name.empty()) return NULL; // Translate tag to proper Dwarf tag. unsigned Tag = DV->getTag(); // Define variable debug information entry. DIE *VariableDie = new DIE(Tag); DbgVariable *AbsVar = DV->getAbstractVariable(); DIE *AbsDIE = AbsVar ? AbsVar->getDIE() : NULL; if (AbsDIE) addDIEEntry(VariableDie, dwarf::DW_AT_abstract_origin, dwarf::DW_FORM_ref4, AbsDIE); else { addString(VariableDie, dwarf::DW_AT_name, dwarf::DW_FORM_string, Name); addSourceLine(VariableDie, DV->getVariable()); addType(VariableDie, DV->getType()); } if (DV->isArtificial()) addUInt(VariableDie, dwarf::DW_AT_artificial, dwarf::DW_FORM_flag, 1); if (isScopeAbstract) { DV->setDIE(VariableDie); return VariableDie; } // Add variable address. unsigned Offset = DV->getDotDebugLocOffset(); if (Offset != ~0U) { addLabel(VariableDie, dwarf::DW_AT_location, dwarf::DW_FORM_data4, Asm->GetTempSymbol("debug_loc", Offset)); DV->setDIE(VariableDie); return VariableDie; } // Check if variable is described by a DBG_VALUE instruction. if (const MachineInstr *DVInsn = DV->getMInsn()) { bool updated = false; if (DVInsn->getNumOperands() == 3) { if (DVInsn->getOperand(0).isReg()) { const MachineOperand RegOp = DVInsn->getOperand(0); const TargetRegisterInfo *TRI = Asm->TM.getRegisterInfo(); if (DVInsn->getOperand(1).isImm() && TRI->getFrameRegister(*Asm->MF) == RegOp.getReg()) { unsigned FrameReg = 0; const TargetFrameLowering *TFI = Asm->TM.getFrameLowering(); int Offset = TFI->getFrameIndexReference(*Asm->MF, DVInsn->getOperand(1).getImm(), FrameReg); MachineLocation Location(FrameReg, Offset); addVariableAddress(DV, VariableDie, Location); } else if (RegOp.getReg()) addVariableAddress(DV, VariableDie, MachineLocation(RegOp.getReg())); updated = true; } else if (DVInsn->getOperand(0).isImm()) updated = addConstantValue(VariableDie, DVInsn->getOperand(0), DV->getType()); else if (DVInsn->getOperand(0).isFPImm()) updated = addConstantFPValue(VariableDie, DVInsn->getOperand(0)); else if (DVInsn->getOperand(0).isCImm()) updated = addConstantValue(VariableDie, DVInsn->getOperand(0).getCImm(), DV->getType().isUnsignedDIType()); } else { addVariableAddress(DV, VariableDie, Asm->getDebugValueLocation(DVInsn)); updated = true; } if (!updated) { // If variableDie is not updated then DBG_VALUE instruction does not // have valid variable info. delete VariableDie; return NULL; } DV->setDIE(VariableDie); return VariableDie; } else { // .. else use frame index. int FI = DV->getFrameIndex(); if (FI != ~0) { unsigned FrameReg = 0; const TargetFrameLowering *TFI = Asm->TM.getFrameLowering(); int Offset = TFI->getFrameIndexReference(*Asm->MF, FI, FrameReg); MachineLocation Location(FrameReg, Offset); addVariableAddress(DV, VariableDie, Location); } } DV->setDIE(VariableDie); return VariableDie; } /// createMemberDIE - Create new member DIE. DIE *CompileUnit::createMemberDIE(DIDerivedType DT) { DIE *MemberDie = new DIE(DT.getTag()); StringRef Name = DT.getName(); if (!Name.empty()) addString(MemberDie, dwarf::DW_AT_name, dwarf::DW_FORM_string, Name); addType(MemberDie, DT.getTypeDerivedFrom()); addSourceLine(MemberDie, DT); DIEBlock *MemLocationDie = new (DIEValueAllocator) DIEBlock(); addUInt(MemLocationDie, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst); uint64_t Size = DT.getSizeInBits(); uint64_t FieldSize = DT.getOriginalTypeSize(); if (Size != FieldSize) { // Handle bitfield. addUInt(MemberDie, dwarf::DW_AT_byte_size, 0, DT.getOriginalTypeSize()>>3); addUInt(MemberDie, dwarf::DW_AT_bit_size, 0, DT.getSizeInBits()); uint64_t Offset = DT.getOffsetInBits(); uint64_t AlignMask = ~(DT.getAlignInBits() - 1); uint64_t HiMark = (Offset + FieldSize) & AlignMask; uint64_t FieldOffset = (HiMark - FieldSize); Offset -= FieldOffset; // Maybe we need to work from the other end. if (Asm->getTargetData().isLittleEndian()) Offset = FieldSize - (Offset + Size); addUInt(MemberDie, dwarf::DW_AT_bit_offset, 0, Offset); // Here WD_AT_data_member_location points to the anonymous // field that includes this bit field. addUInt(MemLocationDie, 0, dwarf::DW_FORM_udata, FieldOffset >> 3); } else // This is not a bitfield. addUInt(MemLocationDie, 0, dwarf::DW_FORM_udata, DT.getOffsetInBits() >> 3); if (DT.getTag() == dwarf::DW_TAG_inheritance && DT.isVirtual()) { // For C++, virtual base classes are not at fixed offset. Use following // expression to extract appropriate offset from vtable. // BaseAddr = ObAddr + *((*ObAddr) - Offset) DIEBlock *VBaseLocationDie = new (DIEValueAllocator) DIEBlock(); addUInt(VBaseLocationDie, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_dup); addUInt(VBaseLocationDie, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_deref); addUInt(VBaseLocationDie, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_constu); addUInt(VBaseLocationDie, 0, dwarf::DW_FORM_udata, DT.getOffsetInBits()); addUInt(VBaseLocationDie, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_minus); addUInt(VBaseLocationDie, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_deref); addUInt(VBaseLocationDie, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_plus); addBlock(MemberDie, dwarf::DW_AT_data_member_location, 0, VBaseLocationDie); } else addBlock(MemberDie, dwarf::DW_AT_data_member_location, 0, MemLocationDie); if (DT.isProtected()) addUInt(MemberDie, dwarf::DW_AT_accessibility, dwarf::DW_FORM_flag, dwarf::DW_ACCESS_protected); else if (DT.isPrivate()) addUInt(MemberDie, dwarf::DW_AT_accessibility, dwarf::DW_FORM_flag, dwarf::DW_ACCESS_private); // Otherwise C++ member and base classes are considered public. else addUInt(MemberDie, dwarf::DW_AT_accessibility, dwarf::DW_FORM_flag, dwarf::DW_ACCESS_public); if (DT.isVirtual()) addUInt(MemberDie, dwarf::DW_AT_virtuality, dwarf::DW_FORM_flag, dwarf::DW_VIRTUALITY_virtual); // Objective-C properties. StringRef PropertyName = DT.getObjCPropertyName(); if (!PropertyName.empty()) { addString(MemberDie, dwarf::DW_AT_APPLE_property_name, dwarf::DW_FORM_string, PropertyName); StringRef GetterName = DT.getObjCPropertyGetterName(); if (!GetterName.empty()) addString(MemberDie, dwarf::DW_AT_APPLE_property_getter, dwarf::DW_FORM_string, GetterName); StringRef SetterName = DT.getObjCPropertySetterName(); if (!SetterName.empty()) addString(MemberDie, dwarf::DW_AT_APPLE_property_setter, dwarf::DW_FORM_string, SetterName); unsigned PropertyAttributes = 0; if (DT.isReadOnlyObjCProperty()) PropertyAttributes |= dwarf::DW_APPLE_PROPERTY_readonly; if (DT.isReadWriteObjCProperty()) PropertyAttributes |= dwarf::DW_APPLE_PROPERTY_readwrite; if (DT.isAssignObjCProperty()) PropertyAttributes |= dwarf::DW_APPLE_PROPERTY_assign; if (DT.isRetainObjCProperty()) PropertyAttributes |= dwarf::DW_APPLE_PROPERTY_retain; if (DT.isCopyObjCProperty()) PropertyAttributes |= dwarf::DW_APPLE_PROPERTY_copy; if (DT.isNonAtomicObjCProperty()) PropertyAttributes |= dwarf::DW_APPLE_PROPERTY_nonatomic; if (PropertyAttributes) addUInt(MemberDie, dwarf::DW_AT_APPLE_property_attribute, 0, PropertyAttributes); } return MemberDie; } Index: head/contrib/llvm/lib/CodeGen/LLVMTargetMachine.cpp =================================================================== --- head/contrib/llvm/lib/CodeGen/LLVMTargetMachine.cpp (revision 228378) +++ head/contrib/llvm/lib/CodeGen/LLVMTargetMachine.cpp (revision 228379) @@ -1,496 +1,497 @@ //===-- LLVMTargetMachine.cpp - Implement the LLVMTargetMachine class -----===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the LLVMTargetMachine class. // //===----------------------------------------------------------------------===// #include "llvm/Target/TargetMachine.h" #include "llvm/PassManager.h" #include "llvm/Analysis/Passes.h" #include "llvm/Analysis/Verifier.h" #include "llvm/Assembly/PrintModulePass.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/MachineFunctionAnalysis.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/GCStrategy.h" #include "llvm/CodeGen/Passes.h" #include "llvm/Target/TargetLowering.h" #include "llvm/Target/TargetOptions.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetLowering.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Target/TargetSubtargetInfo.h" #include "llvm/Transforms/Scalar.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/TargetRegistry.h" using namespace llvm; namespace llvm { bool EnableFastISel; } static cl::opt DisablePostRA("disable-post-ra", cl::Hidden, cl::desc("Disable Post Regalloc")); static cl::opt DisableBranchFold("disable-branch-fold", cl::Hidden, cl::desc("Disable branch folding")); static cl::opt DisableTailDuplicate("disable-tail-duplicate", cl::Hidden, cl::desc("Disable tail duplication")); static cl::opt DisableEarlyTailDup("disable-early-taildup", cl::Hidden, cl::desc("Disable pre-register allocation tail duplication")); static cl::opt DisableCodePlace("disable-code-place", cl::Hidden, cl::desc("Disable code placement")); static cl::opt DisableSSC("disable-ssc", cl::Hidden, cl::desc("Disable Stack Slot Coloring")); static cl::opt DisableMachineDCE("disable-machine-dce", cl::Hidden, cl::desc("Disable Machine Dead Code Elimination")); static cl::opt DisableMachineLICM("disable-machine-licm", cl::Hidden, cl::desc("Disable Machine LICM")); static cl::opt DisableMachineCSE("disable-machine-cse", cl::Hidden, cl::desc("Disable Machine Common Subexpression Elimination")); static cl::opt DisablePostRAMachineLICM("disable-postra-machine-licm", cl::Hidden, cl::desc("Disable Machine LICM")); static cl::opt DisableMachineSink("disable-machine-sink", cl::Hidden, cl::desc("Disable Machine Sinking")); static cl::opt DisableLSR("disable-lsr", cl::Hidden, cl::desc("Disable Loop Strength Reduction Pass")); static cl::opt DisableCGP("disable-cgp", cl::Hidden, cl::desc("Disable Codegen Prepare")); static cl::opt PrintLSR("print-lsr-output", cl::Hidden, cl::desc("Print LLVM IR produced by the loop-reduce pass")); static cl::opt PrintISelInput("print-isel-input", cl::Hidden, cl::desc("Print LLVM IR input to isel pass")); static cl::opt PrintGCInfo("print-gc", cl::Hidden, cl::desc("Dump garbage collector data")); static cl::opt ShowMCEncoding("show-mc-encoding", cl::Hidden, cl::desc("Show encoding in .s output")); static cl::opt ShowMCInst("show-mc-inst", cl::Hidden, cl::desc("Show instruction structure in .s output")); static cl::opt EnableMCLogging("enable-mc-api-logging", cl::Hidden, cl::desc("Enable MC API logging")); static cl::opt VerifyMachineCode("verify-machineinstrs", cl::Hidden, cl::desc("Verify generated machine code"), cl::init(getenv("LLVM_VERIFY_MACHINEINSTRS")!=NULL)); static cl::opt AsmVerbose("asm-verbose", cl::desc("Add comments to directives."), cl::init(cl::BOU_UNSET)); static bool getVerboseAsm() { switch (AsmVerbose) { default: case cl::BOU_UNSET: return TargetMachine::getAsmVerbosityDefault(); case cl::BOU_TRUE: return true; case cl::BOU_FALSE: return false; } } // Enable or disable FastISel. Both options are needed, because // FastISel is enabled by default with -fast, and we wish to be // able to enable or disable fast-isel independently from -O0. static cl::opt EnableFastISelOption("fast-isel", cl::Hidden, cl::desc("Enable the \"fast\" instruction selector")); LLVMTargetMachine::LLVMTargetMachine(const Target &T, StringRef Triple, StringRef CPU, StringRef FS, Reloc::Model RM, CodeModel::Model CM) : TargetMachine(T, Triple, CPU, FS) { CodeGenInfo = T.createMCCodeGenInfo(Triple, RM, CM); AsmInfo = T.createMCAsmInfo(Triple); // TargetSelect.h moved to a different directory between LLVM 2.9 and 3.0, // and if the old one gets included then MCAsmInfo will be NULL and // we'll crash later. // Provide the user with a useful error message about what's wrong. assert(AsmInfo && "MCAsmInfo not initialized." - "Make sure you include the correct TargetSelect.h!"); + "Make sure you include the correct TargetSelect.h" + "and that InitializeAllTargetMCs() is being invoked!"); } bool LLVMTargetMachine::addPassesToEmitFile(PassManagerBase &PM, formatted_raw_ostream &Out, CodeGenFileType FileType, CodeGenOpt::Level OptLevel, bool DisableVerify) { // Add common CodeGen passes. MCContext *Context = 0; if (addCommonCodeGenPasses(PM, OptLevel, DisableVerify, Context)) return true; assert(Context != 0 && "Failed to get MCContext"); if (hasMCSaveTempLabels()) Context->setAllowTemporaryLabels(false); const MCAsmInfo &MAI = *getMCAsmInfo(); const MCSubtargetInfo &STI = getSubtarget(); OwningPtr AsmStreamer; switch (FileType) { default: return true; case CGFT_AssemblyFile: { MCInstPrinter *InstPrinter = getTarget().createMCInstPrinter(MAI.getAssemblerDialect(), MAI, STI); // Create a code emitter if asked to show the encoding. MCCodeEmitter *MCE = 0; MCAsmBackend *MAB = 0; if (ShowMCEncoding) { const MCSubtargetInfo &STI = getSubtarget(); MCE = getTarget().createMCCodeEmitter(*getInstrInfo(), STI, *Context); MAB = getTarget().createMCAsmBackend(getTargetTriple()); } MCStreamer *S = getTarget().createAsmStreamer(*Context, Out, getVerboseAsm(), hasMCUseLoc(), hasMCUseCFI(), InstPrinter, MCE, MAB, ShowMCInst); AsmStreamer.reset(S); break; } case CGFT_ObjectFile: { // Create the code emitter for the target if it exists. If not, .o file // emission fails. MCCodeEmitter *MCE = getTarget().createMCCodeEmitter(*getInstrInfo(), STI, *Context); MCAsmBackend *MAB = getTarget().createMCAsmBackend(getTargetTriple()); if (MCE == 0 || MAB == 0) return true; AsmStreamer.reset(getTarget().createMCObjectStreamer(getTargetTriple(), *Context, *MAB, Out, MCE, hasMCRelaxAll(), hasMCNoExecStack())); AsmStreamer.get()->InitSections(); break; } case CGFT_Null: // The Null output is intended for use for performance analysis and testing, // not real users. AsmStreamer.reset(createNullStreamer(*Context)); break; } if (EnableMCLogging) AsmStreamer.reset(createLoggingStreamer(AsmStreamer.take(), errs())); // Create the AsmPrinter, which takes ownership of AsmStreamer if successful. FunctionPass *Printer = getTarget().createAsmPrinter(*this, *AsmStreamer); if (Printer == 0) return true; // If successful, createAsmPrinter took ownership of AsmStreamer. AsmStreamer.take(); PM.add(Printer); PM.add(createGCInfoDeleter()); return false; } /// addPassesToEmitMachineCode - Add passes to the specified pass manager to /// get machine code emitted. This uses a JITCodeEmitter object to handle /// actually outputting the machine code and resolving things like the address /// of functions. This method should returns true if machine code emission is /// not supported. /// bool LLVMTargetMachine::addPassesToEmitMachineCode(PassManagerBase &PM, JITCodeEmitter &JCE, CodeGenOpt::Level OptLevel, bool DisableVerify) { // Add common CodeGen passes. MCContext *Ctx = 0; if (addCommonCodeGenPasses(PM, OptLevel, DisableVerify, Ctx)) return true; addCodeEmitter(PM, OptLevel, JCE); PM.add(createGCInfoDeleter()); return false; // success! } /// addPassesToEmitMC - Add passes to the specified pass manager to get /// machine code emitted with the MCJIT. This method returns true if machine /// code is not supported. It fills the MCContext Ctx pointer which can be /// used to build custom MCStreamer. /// bool LLVMTargetMachine::addPassesToEmitMC(PassManagerBase &PM, MCContext *&Ctx, raw_ostream &Out, CodeGenOpt::Level OptLevel, bool DisableVerify) { // Add common CodeGen passes. if (addCommonCodeGenPasses(PM, OptLevel, DisableVerify, Ctx)) return true; if (hasMCSaveTempLabels()) Ctx->setAllowTemporaryLabels(false); // Create the code emitter for the target if it exists. If not, .o file // emission fails. const MCSubtargetInfo &STI = getSubtarget(); MCCodeEmitter *MCE = getTarget().createMCCodeEmitter(*getInstrInfo(),STI, *Ctx); MCAsmBackend *MAB = getTarget().createMCAsmBackend(getTargetTriple()); if (MCE == 0 || MAB == 0) return true; OwningPtr AsmStreamer; AsmStreamer.reset(getTarget().createMCObjectStreamer(getTargetTriple(), *Ctx, *MAB, Out, MCE, hasMCRelaxAll(), hasMCNoExecStack())); AsmStreamer.get()->InitSections(); // Create the AsmPrinter, which takes ownership of AsmStreamer if successful. FunctionPass *Printer = getTarget().createAsmPrinter(*this, *AsmStreamer); if (Printer == 0) return true; // If successful, createAsmPrinter took ownership of AsmStreamer. AsmStreamer.take(); PM.add(Printer); return false; // success! } static void printNoVerify(PassManagerBase &PM, const char *Banner) { if (PrintMachineCode) PM.add(createMachineFunctionPrinterPass(dbgs(), Banner)); } static void printAndVerify(PassManagerBase &PM, const char *Banner) { if (PrintMachineCode) PM.add(createMachineFunctionPrinterPass(dbgs(), Banner)); if (VerifyMachineCode) PM.add(createMachineVerifierPass(Banner)); } /// addCommonCodeGenPasses - Add standard LLVM codegen passes used for both /// emitting to assembly files or machine code output. /// bool LLVMTargetMachine::addCommonCodeGenPasses(PassManagerBase &PM, CodeGenOpt::Level OptLevel, bool DisableVerify, MCContext *&OutContext) { // Standard LLVM-Level Passes. // Basic AliasAnalysis support. // Add TypeBasedAliasAnalysis before BasicAliasAnalysis so that // BasicAliasAnalysis wins if they disagree. This is intended to help // support "obvious" type-punning idioms. PM.add(createTypeBasedAliasAnalysisPass()); PM.add(createBasicAliasAnalysisPass()); // Before running any passes, run the verifier to determine if the input // coming from the front-end and/or optimizer is valid. if (!DisableVerify) PM.add(createVerifierPass()); // Run loop strength reduction before anything else. if (OptLevel != CodeGenOpt::None && !DisableLSR) { PM.add(createLoopStrengthReducePass(getTargetLowering())); if (PrintLSR) PM.add(createPrintFunctionPass("\n\n*** Code after LSR ***\n", &dbgs())); } PM.add(createGCLoweringPass()); // Make sure that no unreachable blocks are instruction selected. PM.add(createUnreachableBlockEliminationPass()); // Turn exception handling constructs into something the code generators can // handle. switch (getMCAsmInfo()->getExceptionHandlingType()) { case ExceptionHandling::SjLj: // SjLj piggy-backs on dwarf for this bit. The cleanups done apply to both // Dwarf EH prepare needs to be run after SjLj prepare. Otherwise, // catch info can get misplaced when a selector ends up more than one block // removed from the parent invoke(s). This could happen when a landing // pad is shared by multiple invokes and is also a target of a normal // edge from elsewhere. PM.add(createSjLjEHPass(getTargetLowering())); // FALLTHROUGH case ExceptionHandling::DwarfCFI: case ExceptionHandling::ARM: case ExceptionHandling::Win64: PM.add(createDwarfEHPass(this)); break; case ExceptionHandling::None: PM.add(createLowerInvokePass(getTargetLowering())); // The lower invoke pass may create unreachable code. Remove it. PM.add(createUnreachableBlockEliminationPass()); break; } if (OptLevel != CodeGenOpt::None && !DisableCGP) PM.add(createCodeGenPreparePass(getTargetLowering())); PM.add(createStackProtectorPass(getTargetLowering())); addPreISel(PM, OptLevel); if (PrintISelInput) PM.add(createPrintFunctionPass("\n\n" "*** Final LLVM Code input to ISel ***\n", &dbgs())); // All passes which modify the LLVM IR are now complete; run the verifier // to ensure that the IR is valid. if (!DisableVerify) PM.add(createVerifierPass()); // Standard Lower-Level Passes. // Install a MachineModuleInfo class, which is an immutable pass that holds // all the per-module stuff we're generating, including MCContext. MachineModuleInfo *MMI = new MachineModuleInfo(*getMCAsmInfo(), *getRegisterInfo(), &getTargetLowering()->getObjFileLowering()); PM.add(MMI); OutContext = &MMI->getContext(); // Return the MCContext specifically by-ref. // Set up a MachineFunction for the rest of CodeGen to work on. PM.add(new MachineFunctionAnalysis(*this, OptLevel)); // Enable FastISel with -fast, but allow that to be overridden. if (EnableFastISelOption == cl::BOU_TRUE || (OptLevel == CodeGenOpt::None && EnableFastISelOption != cl::BOU_FALSE)) EnableFastISel = true; // Ask the target for an isel. if (addInstSelector(PM, OptLevel)) return true; // Print the instruction selected machine code... printAndVerify(PM, "After Instruction Selection"); // Expand pseudo-instructions emitted by ISel. PM.add(createExpandISelPseudosPass()); // Pre-ra tail duplication. if (OptLevel != CodeGenOpt::None && !DisableEarlyTailDup) { PM.add(createTailDuplicatePass(true)); printAndVerify(PM, "After Pre-RegAlloc TailDuplicate"); } // Optimize PHIs before DCE: removing dead PHI cycles may make more // instructions dead. if (OptLevel != CodeGenOpt::None) PM.add(createOptimizePHIsPass()); // If the target requests it, assign local variables to stack slots relative // to one another and simplify frame index references where possible. PM.add(createLocalStackSlotAllocationPass()); if (OptLevel != CodeGenOpt::None) { // With optimization, dead code should already be eliminated. However // there is one known exception: lowered code for arguments that are only // used by tail calls, where the tail calls reuse the incoming stack // arguments directly (see t11 in test/CodeGen/X86/sibcall.ll). if (!DisableMachineDCE) PM.add(createDeadMachineInstructionElimPass()); printAndVerify(PM, "After codegen DCE pass"); if (!DisableMachineLICM) PM.add(createMachineLICMPass()); if (!DisableMachineCSE) PM.add(createMachineCSEPass()); if (!DisableMachineSink) PM.add(createMachineSinkingPass()); printAndVerify(PM, "After Machine LICM, CSE and Sinking passes"); PM.add(createPeepholeOptimizerPass()); printAndVerify(PM, "After codegen peephole optimization pass"); } // Run pre-ra passes. if (addPreRegAlloc(PM, OptLevel)) printAndVerify(PM, "After PreRegAlloc passes"); // Perform register allocation. PM.add(createRegisterAllocator(OptLevel)); printAndVerify(PM, "After Register Allocation"); // Perform stack slot coloring and post-ra machine LICM. if (OptLevel != CodeGenOpt::None) { // FIXME: Re-enable coloring with register when it's capable of adding // kill markers. if (!DisableSSC) PM.add(createStackSlotColoringPass(false)); // Run post-ra machine LICM to hoist reloads / remats. if (!DisablePostRAMachineLICM) PM.add(createMachineLICMPass(false)); printAndVerify(PM, "After StackSlotColoring and postra Machine LICM"); } // Run post-ra passes. if (addPostRegAlloc(PM, OptLevel)) printAndVerify(PM, "After PostRegAlloc passes"); PM.add(createExpandPostRAPseudosPass()); printAndVerify(PM, "After ExpandPostRAPseudos"); // Insert prolog/epilog code. Eliminate abstract frame index references... PM.add(createPrologEpilogCodeInserter()); printAndVerify(PM, "After PrologEpilogCodeInserter"); // Run pre-sched2 passes. if (addPreSched2(PM, OptLevel)) printAndVerify(PM, "After PreSched2 passes"); // Second pass scheduler. if (OptLevel != CodeGenOpt::None && !DisablePostRA) { PM.add(createPostRAScheduler(OptLevel)); printAndVerify(PM, "After PostRAScheduler"); } // Branch folding must be run after regalloc and prolog/epilog insertion. if (OptLevel != CodeGenOpt::None && !DisableBranchFold) { PM.add(createBranchFoldingPass(getEnableTailMergeDefault())); printNoVerify(PM, "After BranchFolding"); } // Tail duplication. if (OptLevel != CodeGenOpt::None && !DisableTailDuplicate) { PM.add(createTailDuplicatePass(false)); printNoVerify(PM, "After TailDuplicate"); } PM.add(createGCMachineCodeAnalysisPass()); if (PrintGCInfo) PM.add(createGCInfoPrinter(dbgs())); if (OptLevel != CodeGenOpt::None && !DisableCodePlace) { PM.add(createCodePlacementOptPass()); printNoVerify(PM, "After CodePlacementOpt"); } if (addPreEmitPass(PM, OptLevel)) printNoVerify(PM, "After PreEmit passes"); return false; } Index: head/contrib/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- head/contrib/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp (revision 228378) +++ head/contrib/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp (revision 228379) @@ -1,6818 +1,6821 @@ //===-- SelectionDAGBuilder.cpp - Selection-DAG building ------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This implements routines for translating from LLVM IR into SelectionDAG IR. // //===----------------------------------------------------------------------===// #define DEBUG_TYPE "isel" #include "SDNodeDbgValue.h" #include "SelectionDAGBuilder.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/PostOrderIterator.h" #include "llvm/ADT/SmallSet.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/ConstantFolding.h" #include "llvm/Constants.h" #include "llvm/CallingConv.h" #include "llvm/DerivedTypes.h" #include "llvm/Function.h" #include "llvm/GlobalVariable.h" #include "llvm/InlineAsm.h" #include "llvm/Instructions.h" #include "llvm/Intrinsics.h" #include "llvm/IntrinsicInst.h" #include "llvm/LLVMContext.h" #include "llvm/Module.h" #include "llvm/CodeGen/Analysis.h" #include "llvm/CodeGen/FastISel.h" #include "llvm/CodeGen/FunctionLoweringInfo.h" #include "llvm/CodeGen/GCStrategy.h" #include "llvm/CodeGen/GCMetadata.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/PseudoSourceValue.h" #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/Analysis/DebugInfo.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetFrameLowering.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetIntrinsicInfo.h" #include "llvm/Target/TargetLowering.h" #include "llvm/Target/TargetOptions.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include using namespace llvm; /// LimitFloatPrecision - Generate low-precision inline sequences for /// some float libcalls (6, 8 or 12 bits). static unsigned LimitFloatPrecision; static cl::opt LimitFPPrecision("limit-float-precision", cl::desc("Generate low-precision inline sequences " "for some float libcalls"), cl::location(LimitFloatPrecision), cl::init(0)); // Limit the width of DAG chains. This is important in general to prevent // prevent DAG-based analysis from blowing up. For example, alias analysis and // load clustering may not complete in reasonable time. It is difficult to // recognize and avoid this situation within each individual analysis, and // future analyses are likely to have the same behavior. Limiting DAG width is // the safe approach, and will be especially important with global DAGs. // // MaxParallelChains default is arbitrarily high to avoid affecting // optimization, but could be lowered to improve compile time. Any ld-ld-st-st // sequence over this should have been converted to llvm.memcpy by the // frontend. It easy to induce this behavior with .ll code such as: // %buffer = alloca [4096 x i8] // %data = load [4096 x i8]* %argPtr // store [4096 x i8] %data, [4096 x i8]* %buffer static const unsigned MaxParallelChains = 64; static SDValue getCopyFromPartsVector(SelectionDAG &DAG, DebugLoc DL, const SDValue *Parts, unsigned NumParts, EVT PartVT, EVT ValueVT); /// getCopyFromParts - Create a value that contains the specified legal parts /// combined into the value they represent. If the parts combine to a type /// larger then ValueVT then AssertOp can be used to specify whether the extra /// bits are known to be zero (ISD::AssertZext) or sign extended from ValueVT /// (ISD::AssertSext). static SDValue getCopyFromParts(SelectionDAG &DAG, DebugLoc DL, const SDValue *Parts, unsigned NumParts, EVT PartVT, EVT ValueVT, ISD::NodeType AssertOp = ISD::DELETED_NODE) { if (ValueVT.isVector()) return getCopyFromPartsVector(DAG, DL, Parts, NumParts, PartVT, ValueVT); assert(NumParts > 0 && "No parts to assemble!"); const TargetLowering &TLI = DAG.getTargetLoweringInfo(); SDValue Val = Parts[0]; if (NumParts > 1) { // Assemble the value from multiple parts. if (ValueVT.isInteger()) { unsigned PartBits = PartVT.getSizeInBits(); unsigned ValueBits = ValueVT.getSizeInBits(); // Assemble the power of 2 part. unsigned RoundParts = NumParts & (NumParts - 1) ? 1 << Log2_32(NumParts) : NumParts; unsigned RoundBits = PartBits * RoundParts; EVT RoundVT = RoundBits == ValueBits ? ValueVT : EVT::getIntegerVT(*DAG.getContext(), RoundBits); SDValue Lo, Hi; EVT HalfVT = EVT::getIntegerVT(*DAG.getContext(), RoundBits/2); if (RoundParts > 2) { Lo = getCopyFromParts(DAG, DL, Parts, RoundParts / 2, PartVT, HalfVT); Hi = getCopyFromParts(DAG, DL, Parts + RoundParts / 2, RoundParts / 2, PartVT, HalfVT); } else { Lo = DAG.getNode(ISD::BITCAST, DL, HalfVT, Parts[0]); Hi = DAG.getNode(ISD::BITCAST, DL, HalfVT, Parts[1]); } if (TLI.isBigEndian()) std::swap(Lo, Hi); Val = DAG.getNode(ISD::BUILD_PAIR, DL, RoundVT, Lo, Hi); if (RoundParts < NumParts) { // Assemble the trailing non-power-of-2 part. unsigned OddParts = NumParts - RoundParts; EVT OddVT = EVT::getIntegerVT(*DAG.getContext(), OddParts * PartBits); Hi = getCopyFromParts(DAG, DL, Parts + RoundParts, OddParts, PartVT, OddVT); // Combine the round and odd parts. Lo = Val; if (TLI.isBigEndian()) std::swap(Lo, Hi); EVT TotalVT = EVT::getIntegerVT(*DAG.getContext(), NumParts * PartBits); Hi = DAG.getNode(ISD::ANY_EXTEND, DL, TotalVT, Hi); Hi = DAG.getNode(ISD::SHL, DL, TotalVT, Hi, DAG.getConstant(Lo.getValueType().getSizeInBits(), TLI.getPointerTy())); Lo = DAG.getNode(ISD::ZERO_EXTEND, DL, TotalVT, Lo); Val = DAG.getNode(ISD::OR, DL, TotalVT, Lo, Hi); } } else if (PartVT.isFloatingPoint()) { // FP split into multiple FP parts (for ppcf128) assert(ValueVT == EVT(MVT::ppcf128) && PartVT == EVT(MVT::f64) && "Unexpected split"); SDValue Lo, Hi; Lo = DAG.getNode(ISD::BITCAST, DL, EVT(MVT::f64), Parts[0]); Hi = DAG.getNode(ISD::BITCAST, DL, EVT(MVT::f64), Parts[1]); if (TLI.isBigEndian()) std::swap(Lo, Hi); Val = DAG.getNode(ISD::BUILD_PAIR, DL, ValueVT, Lo, Hi); } else { // FP split into integer parts (soft fp) assert(ValueVT.isFloatingPoint() && PartVT.isInteger() && !PartVT.isVector() && "Unexpected split"); EVT IntVT = EVT::getIntegerVT(*DAG.getContext(), ValueVT.getSizeInBits()); Val = getCopyFromParts(DAG, DL, Parts, NumParts, PartVT, IntVT); } } // There is now one part, held in Val. Correct it to match ValueVT. PartVT = Val.getValueType(); if (PartVT == ValueVT) return Val; if (PartVT.isInteger() && ValueVT.isInteger()) { if (ValueVT.bitsLT(PartVT)) { // For a truncate, see if we have any information to // indicate whether the truncated bits will always be // zero or sign-extension. if (AssertOp != ISD::DELETED_NODE) Val = DAG.getNode(AssertOp, DL, PartVT, Val, DAG.getValueType(ValueVT)); return DAG.getNode(ISD::TRUNCATE, DL, ValueVT, Val); } return DAG.getNode(ISD::ANY_EXTEND, DL, ValueVT, Val); } if (PartVT.isFloatingPoint() && ValueVT.isFloatingPoint()) { // FP_ROUND's are always exact here. if (ValueVT.bitsLT(Val.getValueType())) return DAG.getNode(ISD::FP_ROUND, DL, ValueVT, Val, DAG.getIntPtrConstant(1)); return DAG.getNode(ISD::FP_EXTEND, DL, ValueVT, Val); } if (PartVT.getSizeInBits() == ValueVT.getSizeInBits()) return DAG.getNode(ISD::BITCAST, DL, ValueVT, Val); llvm_unreachable("Unknown mismatch!"); return SDValue(); } /// getCopyFromParts - Create a value that contains the specified legal parts /// combined into the value they represent. If the parts combine to a type /// larger then ValueVT then AssertOp can be used to specify whether the extra /// bits are known to be zero (ISD::AssertZext) or sign extended from ValueVT /// (ISD::AssertSext). static SDValue getCopyFromPartsVector(SelectionDAG &DAG, DebugLoc DL, const SDValue *Parts, unsigned NumParts, EVT PartVT, EVT ValueVT) { assert(ValueVT.isVector() && "Not a vector value"); assert(NumParts > 0 && "No parts to assemble!"); const TargetLowering &TLI = DAG.getTargetLoweringInfo(); SDValue Val = Parts[0]; // Handle a multi-element vector. if (NumParts > 1) { EVT IntermediateVT, RegisterVT; unsigned NumIntermediates; unsigned NumRegs = TLI.getVectorTypeBreakdown(*DAG.getContext(), ValueVT, IntermediateVT, NumIntermediates, RegisterVT); assert(NumRegs == NumParts && "Part count doesn't match vector breakdown!"); NumParts = NumRegs; // Silence a compiler warning. assert(RegisterVT == PartVT && "Part type doesn't match vector breakdown!"); assert(RegisterVT == Parts[0].getValueType() && "Part type doesn't match part!"); // Assemble the parts into intermediate operands. SmallVector Ops(NumIntermediates); if (NumIntermediates == NumParts) { // If the register was not expanded, truncate or copy the value, // as appropriate. for (unsigned i = 0; i != NumParts; ++i) Ops[i] = getCopyFromParts(DAG, DL, &Parts[i], 1, PartVT, IntermediateVT); } else if (NumParts > 0) { // If the intermediate type was expanded, build the intermediate // operands from the parts. assert(NumParts % NumIntermediates == 0 && "Must expand into a divisible number of parts!"); unsigned Factor = NumParts / NumIntermediates; for (unsigned i = 0; i != NumIntermediates; ++i) Ops[i] = getCopyFromParts(DAG, DL, &Parts[i * Factor], Factor, PartVT, IntermediateVT); } // Build a vector with BUILD_VECTOR or CONCAT_VECTORS from the // intermediate operands. Val = DAG.getNode(IntermediateVT.isVector() ? ISD::CONCAT_VECTORS : ISD::BUILD_VECTOR, DL, ValueVT, &Ops[0], NumIntermediates); } // There is now one part, held in Val. Correct it to match ValueVT. PartVT = Val.getValueType(); if (PartVT == ValueVT) return Val; if (PartVT.isVector()) { // If the element type of the source/dest vectors are the same, but the // parts vector has more elements than the value vector, then we have a // vector widening case (e.g. <2 x float> -> <4 x float>). Extract the // elements we want. if (PartVT.getVectorElementType() == ValueVT.getVectorElementType()) { assert(PartVT.getVectorNumElements() > ValueVT.getVectorNumElements() && "Cannot narrow, it would be a lossy transformation"); return DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, ValueVT, Val, DAG.getIntPtrConstant(0)); } // Vector/Vector bitcast. if (ValueVT.getSizeInBits() == PartVT.getSizeInBits()) return DAG.getNode(ISD::BITCAST, DL, ValueVT, Val); assert(PartVT.getVectorNumElements() == ValueVT.getVectorNumElements() && "Cannot handle this kind of promotion"); // Promoted vector extract bool Smaller = ValueVT.bitsLE(PartVT); return DAG.getNode((Smaller ? ISD::TRUNCATE : ISD::ANY_EXTEND), DL, ValueVT, Val); } // Trivial bitcast if the types are the same size and the destination // vector type is legal. if (PartVT.getSizeInBits() == ValueVT.getSizeInBits() && TLI.isTypeLegal(ValueVT)) return DAG.getNode(ISD::BITCAST, DL, ValueVT, Val); // Handle cases such as i8 -> <1 x i1> assert(ValueVT.getVectorNumElements() == 1 && "Only trivial scalar-to-vector conversions should get here!"); if (ValueVT.getVectorNumElements() == 1 && ValueVT.getVectorElementType() != PartVT) { bool Smaller = ValueVT.bitsLE(PartVT); Val = DAG.getNode((Smaller ? ISD::TRUNCATE : ISD::ANY_EXTEND), DL, ValueVT.getScalarType(), Val); } return DAG.getNode(ISD::BUILD_VECTOR, DL, ValueVT, Val); } static void getCopyToPartsVector(SelectionDAG &DAG, DebugLoc dl, SDValue Val, SDValue *Parts, unsigned NumParts, EVT PartVT); /// getCopyToParts - Create a series of nodes that contain the specified value /// split into legal parts. If the parts contain more bits than Val, then, for /// integers, ExtendKind can be used to specify how to generate the extra bits. static void getCopyToParts(SelectionDAG &DAG, DebugLoc DL, SDValue Val, SDValue *Parts, unsigned NumParts, EVT PartVT, ISD::NodeType ExtendKind = ISD::ANY_EXTEND) { EVT ValueVT = Val.getValueType(); // Handle the vector case separately. if (ValueVT.isVector()) return getCopyToPartsVector(DAG, DL, Val, Parts, NumParts, PartVT); const TargetLowering &TLI = DAG.getTargetLoweringInfo(); unsigned PartBits = PartVT.getSizeInBits(); unsigned OrigNumParts = NumParts; assert(TLI.isTypeLegal(PartVT) && "Copying to an illegal type!"); if (NumParts == 0) return; assert(!ValueVT.isVector() && "Vector case handled elsewhere"); if (PartVT == ValueVT) { assert(NumParts == 1 && "No-op copy with multiple parts!"); Parts[0] = Val; return; } if (NumParts * PartBits > ValueVT.getSizeInBits()) { // If the parts cover more bits than the value has, promote the value. if (PartVT.isFloatingPoint() && ValueVT.isFloatingPoint()) { assert(NumParts == 1 && "Do not know what to promote to!"); Val = DAG.getNode(ISD::FP_EXTEND, DL, PartVT, Val); } else { assert(PartVT.isInteger() && ValueVT.isInteger() && "Unknown mismatch!"); ValueVT = EVT::getIntegerVT(*DAG.getContext(), NumParts * PartBits); Val = DAG.getNode(ExtendKind, DL, ValueVT, Val); } } else if (PartBits == ValueVT.getSizeInBits()) { // Different types of the same size. assert(NumParts == 1 && PartVT != ValueVT); Val = DAG.getNode(ISD::BITCAST, DL, PartVT, Val); } else if (NumParts * PartBits < ValueVT.getSizeInBits()) { // If the parts cover less bits than value has, truncate the value. assert(PartVT.isInteger() && ValueVT.isInteger() && "Unknown mismatch!"); ValueVT = EVT::getIntegerVT(*DAG.getContext(), NumParts * PartBits); Val = DAG.getNode(ISD::TRUNCATE, DL, ValueVT, Val); } // The value may have changed - recompute ValueVT. ValueVT = Val.getValueType(); assert(NumParts * PartBits == ValueVT.getSizeInBits() && "Failed to tile the value with PartVT!"); if (NumParts == 1) { assert(PartVT == ValueVT && "Type conversion failed!"); Parts[0] = Val; return; } // Expand the value into multiple parts. if (NumParts & (NumParts - 1)) { // The number of parts is not a power of 2. Split off and copy the tail. assert(PartVT.isInteger() && ValueVT.isInteger() && "Do not know what to expand to!"); unsigned RoundParts = 1 << Log2_32(NumParts); unsigned RoundBits = RoundParts * PartBits; unsigned OddParts = NumParts - RoundParts; SDValue OddVal = DAG.getNode(ISD::SRL, DL, ValueVT, Val, DAG.getIntPtrConstant(RoundBits)); getCopyToParts(DAG, DL, OddVal, Parts + RoundParts, OddParts, PartVT); if (TLI.isBigEndian()) // The odd parts were reversed by getCopyToParts - unreverse them. std::reverse(Parts + RoundParts, Parts + NumParts); NumParts = RoundParts; ValueVT = EVT::getIntegerVT(*DAG.getContext(), NumParts * PartBits); Val = DAG.getNode(ISD::TRUNCATE, DL, ValueVT, Val); } // The number of parts is a power of 2. Repeatedly bisect the value using // EXTRACT_ELEMENT. Parts[0] = DAG.getNode(ISD::BITCAST, DL, EVT::getIntegerVT(*DAG.getContext(), ValueVT.getSizeInBits()), Val); for (unsigned StepSize = NumParts; StepSize > 1; StepSize /= 2) { for (unsigned i = 0; i < NumParts; i += StepSize) { unsigned ThisBits = StepSize * PartBits / 2; EVT ThisVT = EVT::getIntegerVT(*DAG.getContext(), ThisBits); SDValue &Part0 = Parts[i]; SDValue &Part1 = Parts[i+StepSize/2]; Part1 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, ThisVT, Part0, DAG.getIntPtrConstant(1)); Part0 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, ThisVT, Part0, DAG.getIntPtrConstant(0)); if (ThisBits == PartBits && ThisVT != PartVT) { Part0 = DAG.getNode(ISD::BITCAST, DL, PartVT, Part0); Part1 = DAG.getNode(ISD::BITCAST, DL, PartVT, Part1); } } } if (TLI.isBigEndian()) std::reverse(Parts, Parts + OrigNumParts); } /// getCopyToPartsVector - Create a series of nodes that contain the specified /// value split into legal parts. static void getCopyToPartsVector(SelectionDAG &DAG, DebugLoc DL, SDValue Val, SDValue *Parts, unsigned NumParts, EVT PartVT) { EVT ValueVT = Val.getValueType(); assert(ValueVT.isVector() && "Not a vector"); const TargetLowering &TLI = DAG.getTargetLoweringInfo(); if (NumParts == 1) { if (PartVT == ValueVT) { // Nothing to do. } else if (PartVT.getSizeInBits() == ValueVT.getSizeInBits()) { // Bitconvert vector->vector case. Val = DAG.getNode(ISD::BITCAST, DL, PartVT, Val); } else if (PartVT.isVector() && PartVT.getVectorElementType() == ValueVT.getVectorElementType() && PartVT.getVectorNumElements() > ValueVT.getVectorNumElements()) { EVT ElementVT = PartVT.getVectorElementType(); // Vector widening case, e.g. <2 x float> -> <4 x float>. Shuffle in // undef elements. SmallVector Ops; for (unsigned i = 0, e = ValueVT.getVectorNumElements(); i != e; ++i) Ops.push_back(DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, ElementVT, Val, DAG.getIntPtrConstant(i))); for (unsigned i = ValueVT.getVectorNumElements(), e = PartVT.getVectorNumElements(); i != e; ++i) Ops.push_back(DAG.getUNDEF(ElementVT)); Val = DAG.getNode(ISD::BUILD_VECTOR, DL, PartVT, &Ops[0], Ops.size()); // FIXME: Use CONCAT for 2x -> 4x. //SDValue UndefElts = DAG.getUNDEF(VectorTy); //Val = DAG.getNode(ISD::CONCAT_VECTORS, DL, PartVT, Val, UndefElts); } else if (PartVT.isVector() && PartVT.getVectorElementType().bitsGE( ValueVT.getVectorElementType()) && PartVT.getVectorNumElements() == ValueVT.getVectorNumElements()) { // Promoted vector extract bool Smaller = PartVT.bitsLE(ValueVT); Val = DAG.getNode((Smaller ? ISD::TRUNCATE : ISD::ANY_EXTEND), DL, PartVT, Val); } else{ // Vector -> scalar conversion. assert(ValueVT.getVectorNumElements() == 1 && "Only trivial vector-to-scalar conversions should get here!"); Val = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, PartVT, Val, DAG.getIntPtrConstant(0)); bool Smaller = ValueVT.bitsLE(PartVT); Val = DAG.getNode((Smaller ? ISD::TRUNCATE : ISD::ANY_EXTEND), DL, PartVT, Val); } Parts[0] = Val; return; } // Handle a multi-element vector. EVT IntermediateVT, RegisterVT; unsigned NumIntermediates; unsigned NumRegs = TLI.getVectorTypeBreakdown(*DAG.getContext(), ValueVT, IntermediateVT, NumIntermediates, RegisterVT); unsigned NumElements = ValueVT.getVectorNumElements(); assert(NumRegs == NumParts && "Part count doesn't match vector breakdown!"); NumParts = NumRegs; // Silence a compiler warning. assert(RegisterVT == PartVT && "Part type doesn't match vector breakdown!"); // Split the vector into intermediate operands. SmallVector Ops(NumIntermediates); for (unsigned i = 0; i != NumIntermediates; ++i) { if (IntermediateVT.isVector()) Ops[i] = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, IntermediateVT, Val, DAG.getIntPtrConstant(i * (NumElements / NumIntermediates))); else Ops[i] = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, IntermediateVT, Val, DAG.getIntPtrConstant(i)); } // Split the intermediate operands into legal parts. if (NumParts == NumIntermediates) { // If the register was not expanded, promote or copy the value, // as appropriate. for (unsigned i = 0; i != NumParts; ++i) getCopyToParts(DAG, DL, Ops[i], &Parts[i], 1, PartVT); } else if (NumParts > 0) { // If the intermediate type was expanded, split each the value into // legal parts. assert(NumParts % NumIntermediates == 0 && "Must expand into a divisible number of parts!"); unsigned Factor = NumParts / NumIntermediates; for (unsigned i = 0; i != NumIntermediates; ++i) getCopyToParts(DAG, DL, Ops[i], &Parts[i*Factor], Factor, PartVT); } } namespace { /// RegsForValue - This struct represents the registers (physical or virtual) /// that a particular set of values is assigned, and the type information /// about the value. The most common situation is to represent one value at a /// time, but struct or array values are handled element-wise as multiple /// values. The splitting of aggregates is performed recursively, so that we /// never have aggregate-typed registers. The values at this point do not /// necessarily have legal types, so each value may require one or more /// registers of some legal type. /// struct RegsForValue { /// ValueVTs - The value types of the values, which may not be legal, and /// may need be promoted or synthesized from one or more registers. /// SmallVector ValueVTs; /// RegVTs - The value types of the registers. This is the same size as /// ValueVTs and it records, for each value, what the type of the assigned /// register or registers are. (Individual values are never synthesized /// from more than one type of register.) /// /// With virtual registers, the contents of RegVTs is redundant with TLI's /// getRegisterType member function, however when with physical registers /// it is necessary to have a separate record of the types. /// SmallVector RegVTs; /// Regs - This list holds the registers assigned to the values. /// Each legal or promoted value requires one register, and each /// expanded value requires multiple registers. /// SmallVector Regs; RegsForValue() {} RegsForValue(const SmallVector ®s, EVT regvt, EVT valuevt) : ValueVTs(1, valuevt), RegVTs(1, regvt), Regs(regs) {} RegsForValue(LLVMContext &Context, const TargetLowering &tli, unsigned Reg, Type *Ty) { ComputeValueVTs(tli, Ty, ValueVTs); for (unsigned Value = 0, e = ValueVTs.size(); Value != e; ++Value) { EVT ValueVT = ValueVTs[Value]; unsigned NumRegs = tli.getNumRegisters(Context, ValueVT); EVT RegisterVT = tli.getRegisterType(Context, ValueVT); for (unsigned i = 0; i != NumRegs; ++i) Regs.push_back(Reg + i); RegVTs.push_back(RegisterVT); Reg += NumRegs; } } /// areValueTypesLegal - Return true if types of all the values are legal. bool areValueTypesLegal(const TargetLowering &TLI) { for (unsigned Value = 0, e = ValueVTs.size(); Value != e; ++Value) { EVT RegisterVT = RegVTs[Value]; if (!TLI.isTypeLegal(RegisterVT)) return false; } return true; } /// append - Add the specified values to this one. void append(const RegsForValue &RHS) { ValueVTs.append(RHS.ValueVTs.begin(), RHS.ValueVTs.end()); RegVTs.append(RHS.RegVTs.begin(), RHS.RegVTs.end()); Regs.append(RHS.Regs.begin(), RHS.Regs.end()); } /// getCopyFromRegs - Emit a series of CopyFromReg nodes that copies from /// this value and returns the result as a ValueVTs value. This uses /// Chain/Flag as the input and updates them for the output Chain/Flag. /// If the Flag pointer is NULL, no flag is used. SDValue getCopyFromRegs(SelectionDAG &DAG, FunctionLoweringInfo &FuncInfo, DebugLoc dl, SDValue &Chain, SDValue *Flag) const; /// getCopyToRegs - Emit a series of CopyToReg nodes that copies the /// specified value into the registers specified by this object. This uses /// Chain/Flag as the input and updates them for the output Chain/Flag. /// If the Flag pointer is NULL, no flag is used. void getCopyToRegs(SDValue Val, SelectionDAG &DAG, DebugLoc dl, SDValue &Chain, SDValue *Flag) const; /// AddInlineAsmOperands - Add this value to the specified inlineasm node /// operand list. This adds the code marker, matching input operand index /// (if applicable), and includes the number of values added into it. void AddInlineAsmOperands(unsigned Kind, bool HasMatching, unsigned MatchingIdx, SelectionDAG &DAG, std::vector &Ops) const; }; } /// getCopyFromRegs - Emit a series of CopyFromReg nodes that copies from /// this value and returns the result as a ValueVT value. This uses /// Chain/Flag as the input and updates them for the output Chain/Flag. /// If the Flag pointer is NULL, no flag is used. SDValue RegsForValue::getCopyFromRegs(SelectionDAG &DAG, FunctionLoweringInfo &FuncInfo, DebugLoc dl, SDValue &Chain, SDValue *Flag) const { // A Value with type {} or [0 x %t] needs no registers. if (ValueVTs.empty()) return SDValue(); const TargetLowering &TLI = DAG.getTargetLoweringInfo(); // Assemble the legal parts into the final values. SmallVector Values(ValueVTs.size()); SmallVector Parts; for (unsigned Value = 0, Part = 0, e = ValueVTs.size(); Value != e; ++Value) { // Copy the legal parts from the registers. EVT ValueVT = ValueVTs[Value]; unsigned NumRegs = TLI.getNumRegisters(*DAG.getContext(), ValueVT); EVT RegisterVT = RegVTs[Value]; Parts.resize(NumRegs); for (unsigned i = 0; i != NumRegs; ++i) { SDValue P; if (Flag == 0) { P = DAG.getCopyFromReg(Chain, dl, Regs[Part+i], RegisterVT); } else { P = DAG.getCopyFromReg(Chain, dl, Regs[Part+i], RegisterVT, *Flag); *Flag = P.getValue(2); } Chain = P.getValue(1); Parts[i] = P; // If the source register was virtual and if we know something about it, // add an assert node. if (!TargetRegisterInfo::isVirtualRegister(Regs[Part+i]) || !RegisterVT.isInteger() || RegisterVT.isVector()) continue; const FunctionLoweringInfo::LiveOutInfo *LOI = FuncInfo.GetLiveOutRegInfo(Regs[Part+i]); if (!LOI) continue; unsigned RegSize = RegisterVT.getSizeInBits(); unsigned NumSignBits = LOI->NumSignBits; unsigned NumZeroBits = LOI->KnownZero.countLeadingOnes(); // FIXME: We capture more information than the dag can represent. For // now, just use the tightest assertzext/assertsext possible. bool isSExt = true; EVT FromVT(MVT::Other); if (NumSignBits == RegSize) isSExt = true, FromVT = MVT::i1; // ASSERT SEXT 1 else if (NumZeroBits >= RegSize-1) isSExt = false, FromVT = MVT::i1; // ASSERT ZEXT 1 else if (NumSignBits > RegSize-8) isSExt = true, FromVT = MVT::i8; // ASSERT SEXT 8 else if (NumZeroBits >= RegSize-8) isSExt = false, FromVT = MVT::i8; // ASSERT ZEXT 8 else if (NumSignBits > RegSize-16) isSExt = true, FromVT = MVT::i16; // ASSERT SEXT 16 else if (NumZeroBits >= RegSize-16) isSExt = false, FromVT = MVT::i16; // ASSERT ZEXT 16 else if (NumSignBits > RegSize-32) isSExt = true, FromVT = MVT::i32; // ASSERT SEXT 32 else if (NumZeroBits >= RegSize-32) isSExt = false, FromVT = MVT::i32; // ASSERT ZEXT 32 else continue; // Add an assertion node. assert(FromVT != MVT::Other); Parts[i] = DAG.getNode(isSExt ? ISD::AssertSext : ISD::AssertZext, dl, RegisterVT, P, DAG.getValueType(FromVT)); } Values[Value] = getCopyFromParts(DAG, dl, Parts.begin(), NumRegs, RegisterVT, ValueVT); Part += NumRegs; Parts.clear(); } return DAG.getNode(ISD::MERGE_VALUES, dl, DAG.getVTList(&ValueVTs[0], ValueVTs.size()), &Values[0], ValueVTs.size()); } /// getCopyToRegs - Emit a series of CopyToReg nodes that copies the /// specified value into the registers specified by this object. This uses /// Chain/Flag as the input and updates them for the output Chain/Flag. /// If the Flag pointer is NULL, no flag is used. void RegsForValue::getCopyToRegs(SDValue Val, SelectionDAG &DAG, DebugLoc dl, SDValue &Chain, SDValue *Flag) const { const TargetLowering &TLI = DAG.getTargetLoweringInfo(); // Get the list of the values's legal parts. unsigned NumRegs = Regs.size(); SmallVector Parts(NumRegs); for (unsigned Value = 0, Part = 0, e = ValueVTs.size(); Value != e; ++Value) { EVT ValueVT = ValueVTs[Value]; unsigned NumParts = TLI.getNumRegisters(*DAG.getContext(), ValueVT); EVT RegisterVT = RegVTs[Value]; getCopyToParts(DAG, dl, Val.getValue(Val.getResNo() + Value), &Parts[Part], NumParts, RegisterVT); Part += NumParts; } // Copy the parts into the registers. SmallVector Chains(NumRegs); for (unsigned i = 0; i != NumRegs; ++i) { SDValue Part; if (Flag == 0) { Part = DAG.getCopyToReg(Chain, dl, Regs[i], Parts[i]); } else { Part = DAG.getCopyToReg(Chain, dl, Regs[i], Parts[i], *Flag); *Flag = Part.getValue(1); } Chains[i] = Part.getValue(0); } if (NumRegs == 1 || Flag) // If NumRegs > 1 && Flag is used then the use of the last CopyToReg is // flagged to it. That is the CopyToReg nodes and the user are considered // a single scheduling unit. If we create a TokenFactor and return it as // chain, then the TokenFactor is both a predecessor (operand) of the // user as well as a successor (the TF operands are flagged to the user). // c1, f1 = CopyToReg // c2, f2 = CopyToReg // c3 = TokenFactor c1, c2 // ... // = op c3, ..., f2 Chain = Chains[NumRegs-1]; else Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &Chains[0], NumRegs); } /// AddInlineAsmOperands - Add this value to the specified inlineasm node /// operand list. This adds the code marker and includes the number of /// values added into it. void RegsForValue::AddInlineAsmOperands(unsigned Code, bool HasMatching, unsigned MatchingIdx, SelectionDAG &DAG, std::vector &Ops) const { const TargetLowering &TLI = DAG.getTargetLoweringInfo(); unsigned Flag = InlineAsm::getFlagWord(Code, Regs.size()); if (HasMatching) Flag = InlineAsm::getFlagWordForMatchingOp(Flag, MatchingIdx); else if (!Regs.empty() && TargetRegisterInfo::isVirtualRegister(Regs.front())) { // Put the register class of the virtual registers in the flag word. That // way, later passes can recompute register class constraints for inline // assembly as well as normal instructions. // Don't do this for tied operands that can use the regclass information // from the def. const MachineRegisterInfo &MRI = DAG.getMachineFunction().getRegInfo(); const TargetRegisterClass *RC = MRI.getRegClass(Regs.front()); Flag = InlineAsm::getFlagWordForRegClass(Flag, RC->getID()); } SDValue Res = DAG.getTargetConstant(Flag, MVT::i32); Ops.push_back(Res); for (unsigned Value = 0, Reg = 0, e = ValueVTs.size(); Value != e; ++Value) { unsigned NumRegs = TLI.getNumRegisters(*DAG.getContext(), ValueVTs[Value]); EVT RegisterVT = RegVTs[Value]; for (unsigned i = 0; i != NumRegs; ++i) { assert(Reg < Regs.size() && "Mismatch in # registers expected"); Ops.push_back(DAG.getRegister(Regs[Reg++], RegisterVT)); } } } void SelectionDAGBuilder::init(GCFunctionInfo *gfi, AliasAnalysis &aa) { AA = &aa; GFI = gfi; TD = DAG.getTarget().getTargetData(); LPadToCallSiteMap.clear(); } /// clear - Clear out the current SelectionDAG and the associated /// state and prepare this SelectionDAGBuilder object to be used /// for a new block. This doesn't clear out information about /// additional blocks that are needed to complete switch lowering /// or PHI node updating; that information is cleared out as it is /// consumed. void SelectionDAGBuilder::clear() { NodeMap.clear(); UnusedArgNodeMap.clear(); PendingLoads.clear(); PendingExports.clear(); CurDebugLoc = DebugLoc(); HasTailCall = false; } /// clearDanglingDebugInfo - Clear the dangling debug information /// map. This function is seperated from the clear so that debug /// information that is dangling in a basic block can be properly /// resolved in a different basic block. This allows the /// SelectionDAG to resolve dangling debug information attached /// to PHI nodes. void SelectionDAGBuilder::clearDanglingDebugInfo() { DanglingDebugInfoMap.clear(); } /// getRoot - Return the current virtual root of the Selection DAG, /// flushing any PendingLoad items. This must be done before emitting /// a store or any other node that may need to be ordered after any /// prior load instructions. /// SDValue SelectionDAGBuilder::getRoot() { if (PendingLoads.empty()) return DAG.getRoot(); if (PendingLoads.size() == 1) { SDValue Root = PendingLoads[0]; DAG.setRoot(Root); PendingLoads.clear(); return Root; } // Otherwise, we have to make a token factor node. SDValue Root = DAG.getNode(ISD::TokenFactor, getCurDebugLoc(), MVT::Other, &PendingLoads[0], PendingLoads.size()); PendingLoads.clear(); DAG.setRoot(Root); return Root; } /// getControlRoot - Similar to getRoot, but instead of flushing all the /// PendingLoad items, flush all the PendingExports items. It is necessary /// to do this before emitting a terminator instruction. /// SDValue SelectionDAGBuilder::getControlRoot() { SDValue Root = DAG.getRoot(); if (PendingExports.empty()) return Root; // Turn all of the CopyToReg chains into one factored node. if (Root.getOpcode() != ISD::EntryToken) { unsigned i = 0, e = PendingExports.size(); for (; i != e; ++i) { assert(PendingExports[i].getNode()->getNumOperands() > 1); if (PendingExports[i].getNode()->getOperand(0) == Root) break; // Don't add the root if we already indirectly depend on it. } if (i == e) PendingExports.push_back(Root); } Root = DAG.getNode(ISD::TokenFactor, getCurDebugLoc(), MVT::Other, &PendingExports[0], PendingExports.size()); PendingExports.clear(); DAG.setRoot(Root); return Root; } void SelectionDAGBuilder::AssignOrderingToNode(const SDNode *Node) { if (DAG.GetOrdering(Node) != 0) return; // Already has ordering. DAG.AssignOrdering(Node, SDNodeOrder); for (unsigned I = 0, E = Node->getNumOperands(); I != E; ++I) AssignOrderingToNode(Node->getOperand(I).getNode()); } void SelectionDAGBuilder::visit(const Instruction &I) { // Set up outgoing PHI node register values before emitting the terminator. if (isa(&I)) HandlePHINodesInSuccessorBlocks(I.getParent()); CurDebugLoc = I.getDebugLoc(); visit(I.getOpcode(), I); if (!isa(&I) && !HasTailCall) CopyToExportRegsIfNeeded(&I); CurDebugLoc = DebugLoc(); } void SelectionDAGBuilder::visitPHI(const PHINode &) { llvm_unreachable("SelectionDAGBuilder shouldn't visit PHI nodes!"); } void SelectionDAGBuilder::visit(unsigned Opcode, const User &I) { // Note: this doesn't use InstVisitor, because it has to work with // ConstantExpr's in addition to instructions. switch (Opcode) { default: llvm_unreachable("Unknown instruction type encountered!"); // Build the switch statement using the Instruction.def file. #define HANDLE_INST(NUM, OPCODE, CLASS) \ case Instruction::OPCODE: visit##OPCODE((CLASS&)I); break; #include "llvm/Instruction.def" } // Assign the ordering to the freshly created DAG nodes. if (NodeMap.count(&I)) { ++SDNodeOrder; AssignOrderingToNode(getValue(&I).getNode()); } } // resolveDanglingDebugInfo - if we saw an earlier dbg_value referring to V, // generate the debug data structures now that we've seen its definition. void SelectionDAGBuilder::resolveDanglingDebugInfo(const Value *V, SDValue Val) { DanglingDebugInfo &DDI = DanglingDebugInfoMap[V]; if (DDI.getDI()) { const DbgValueInst *DI = DDI.getDI(); DebugLoc dl = DDI.getdl(); unsigned DbgSDNodeOrder = DDI.getSDNodeOrder(); MDNode *Variable = DI->getVariable(); uint64_t Offset = DI->getOffset(); SDDbgValue *SDV; if (Val.getNode()) { if (!EmitFuncArgumentDbgValue(V, Variable, Offset, Val)) { SDV = DAG.getDbgValue(Variable, Val.getNode(), Val.getResNo(), Offset, dl, DbgSDNodeOrder); DAG.AddDbgValue(SDV, Val.getNode(), false); } } else DEBUG(dbgs() << "Dropping debug info for " << DI); DanglingDebugInfoMap[V] = DanglingDebugInfo(); } } /// getValue - Return an SDValue for the given Value. SDValue SelectionDAGBuilder::getValue(const Value *V) { // If we already have an SDValue for this value, use it. It's important // to do this first, so that we don't create a CopyFromReg if we already // have a regular SDValue. SDValue &N = NodeMap[V]; if (N.getNode()) return N; // If there's a virtual register allocated and initialized for this // value, use it. DenseMap::iterator It = FuncInfo.ValueMap.find(V); if (It != FuncInfo.ValueMap.end()) { unsigned InReg = It->second; RegsForValue RFV(*DAG.getContext(), TLI, InReg, V->getType()); SDValue Chain = DAG.getEntryNode(); N = RFV.getCopyFromRegs(DAG, FuncInfo, getCurDebugLoc(), Chain, NULL); resolveDanglingDebugInfo(V, N); return N; } // Otherwise create a new SDValue and remember it. SDValue Val = getValueImpl(V); NodeMap[V] = Val; resolveDanglingDebugInfo(V, Val); return Val; } /// getNonRegisterValue - Return an SDValue for the given Value, but /// don't look in FuncInfo.ValueMap for a virtual register. SDValue SelectionDAGBuilder::getNonRegisterValue(const Value *V) { // If we already have an SDValue for this value, use it. SDValue &N = NodeMap[V]; if (N.getNode()) return N; // Otherwise create a new SDValue and remember it. SDValue Val = getValueImpl(V); NodeMap[V] = Val; resolveDanglingDebugInfo(V, Val); return Val; } /// getValueImpl - Helper function for getValue and getNonRegisterValue. /// Create an SDValue for the given value. SDValue SelectionDAGBuilder::getValueImpl(const Value *V) { if (const Constant *C = dyn_cast(V)) { EVT VT = TLI.getValueType(V->getType(), true); if (const ConstantInt *CI = dyn_cast(C)) return DAG.getConstant(*CI, VT); if (const GlobalValue *GV = dyn_cast(C)) return DAG.getGlobalAddress(GV, getCurDebugLoc(), VT); if (isa(C)) return DAG.getConstant(0, TLI.getPointerTy()); if (const ConstantFP *CFP = dyn_cast(C)) return DAG.getConstantFP(*CFP, VT); if (isa(C) && !V->getType()->isAggregateType()) return DAG.getUNDEF(VT); if (const ConstantExpr *CE = dyn_cast(C)) { visit(CE->getOpcode(), *CE); SDValue N1 = NodeMap[V]; assert(N1.getNode() && "visit didn't populate the NodeMap!"); return N1; } if (isa(C) || isa(C)) { SmallVector Constants; for (User::const_op_iterator OI = C->op_begin(), OE = C->op_end(); OI != OE; ++OI) { SDNode *Val = getValue(*OI).getNode(); // If the operand is an empty aggregate, there are no values. if (!Val) continue; // Add each leaf value from the operand to the Constants list // to form a flattened list of all the values. for (unsigned i = 0, e = Val->getNumValues(); i != e; ++i) Constants.push_back(SDValue(Val, i)); } return DAG.getMergeValues(&Constants[0], Constants.size(), getCurDebugLoc()); } if (C->getType()->isStructTy() || C->getType()->isArrayTy()) { assert((isa(C) || isa(C)) && "Unknown struct or array constant!"); SmallVector ValueVTs; ComputeValueVTs(TLI, C->getType(), ValueVTs); unsigned NumElts = ValueVTs.size(); if (NumElts == 0) return SDValue(); // empty struct SmallVector Constants(NumElts); for (unsigned i = 0; i != NumElts; ++i) { EVT EltVT = ValueVTs[i]; if (isa(C)) Constants[i] = DAG.getUNDEF(EltVT); else if (EltVT.isFloatingPoint()) Constants[i] = DAG.getConstantFP(0, EltVT); else Constants[i] = DAG.getConstant(0, EltVT); } return DAG.getMergeValues(&Constants[0], NumElts, getCurDebugLoc()); } if (const BlockAddress *BA = dyn_cast(C)) return DAG.getBlockAddress(BA, VT); VectorType *VecTy = cast(V->getType()); unsigned NumElements = VecTy->getNumElements(); // Now that we know the number and type of the elements, get that number of // elements into the Ops array based on what kind of constant it is. SmallVector Ops; if (const ConstantVector *CP = dyn_cast(C)) { for (unsigned i = 0; i != NumElements; ++i) Ops.push_back(getValue(CP->getOperand(i))); } else { assert(isa(C) && "Unknown vector constant!"); EVT EltVT = TLI.getValueType(VecTy->getElementType()); SDValue Op; if (EltVT.isFloatingPoint()) Op = DAG.getConstantFP(0, EltVT); else Op = DAG.getConstant(0, EltVT); Ops.assign(NumElements, Op); } // Create a BUILD_VECTOR node. return NodeMap[V] = DAG.getNode(ISD::BUILD_VECTOR, getCurDebugLoc(), VT, &Ops[0], Ops.size()); } // If this is a static alloca, generate it as the frameindex instead of // computation. if (const AllocaInst *AI = dyn_cast(V)) { DenseMap::iterator SI = FuncInfo.StaticAllocaMap.find(AI); if (SI != FuncInfo.StaticAllocaMap.end()) return DAG.getFrameIndex(SI->second, TLI.getPointerTy()); } // If this is an instruction which fast-isel has deferred, select it now. if (const Instruction *Inst = dyn_cast(V)) { unsigned InReg = FuncInfo.InitializeRegForValue(Inst); RegsForValue RFV(*DAG.getContext(), TLI, InReg, Inst->getType()); SDValue Chain = DAG.getEntryNode(); return RFV.getCopyFromRegs(DAG, FuncInfo, getCurDebugLoc(), Chain, NULL); } llvm_unreachable("Can't get register for value!"); return SDValue(); } void SelectionDAGBuilder::visitRet(const ReturnInst &I) { SDValue Chain = getControlRoot(); SmallVector Outs; SmallVector OutVals; if (!FuncInfo.CanLowerReturn) { unsigned DemoteReg = FuncInfo.DemoteRegister; const Function *F = I.getParent()->getParent(); // Emit a store of the return value through the virtual register. // Leave Outs empty so that LowerReturn won't try to load return // registers the usual way. SmallVector PtrValueVTs; ComputeValueVTs(TLI, PointerType::getUnqual(F->getReturnType()), PtrValueVTs); SDValue RetPtr = DAG.getRegister(DemoteReg, PtrValueVTs[0]); SDValue RetOp = getValue(I.getOperand(0)); SmallVector ValueVTs; SmallVector Offsets; ComputeValueVTs(TLI, I.getOperand(0)->getType(), ValueVTs, &Offsets); unsigned NumValues = ValueVTs.size(); SmallVector Chains(NumValues); for (unsigned i = 0; i != NumValues; ++i) { SDValue Add = DAG.getNode(ISD::ADD, getCurDebugLoc(), RetPtr.getValueType(), RetPtr, DAG.getIntPtrConstant(Offsets[i])); Chains[i] = DAG.getStore(Chain, getCurDebugLoc(), SDValue(RetOp.getNode(), RetOp.getResNo() + i), // FIXME: better loc info would be nice. Add, MachinePointerInfo(), false, false, 0); } Chain = DAG.getNode(ISD::TokenFactor, getCurDebugLoc(), MVT::Other, &Chains[0], NumValues); } else if (I.getNumOperands() != 0) { SmallVector ValueVTs; ComputeValueVTs(TLI, I.getOperand(0)->getType(), ValueVTs); unsigned NumValues = ValueVTs.size(); if (NumValues) { SDValue RetOp = getValue(I.getOperand(0)); for (unsigned j = 0, f = NumValues; j != f; ++j) { EVT VT = ValueVTs[j]; ISD::NodeType ExtendKind = ISD::ANY_EXTEND; const Function *F = I.getParent()->getParent(); if (F->paramHasAttr(0, Attribute::SExt)) ExtendKind = ISD::SIGN_EXTEND; else if (F->paramHasAttr(0, Attribute::ZExt)) ExtendKind = ISD::ZERO_EXTEND; if (ExtendKind != ISD::ANY_EXTEND && VT.isInteger()) VT = TLI.getTypeForExtArgOrReturn(*DAG.getContext(), VT, ExtendKind); unsigned NumParts = TLI.getNumRegisters(*DAG.getContext(), VT); EVT PartVT = TLI.getRegisterType(*DAG.getContext(), VT); SmallVector Parts(NumParts); getCopyToParts(DAG, getCurDebugLoc(), SDValue(RetOp.getNode(), RetOp.getResNo() + j), &Parts[0], NumParts, PartVT, ExtendKind); // 'inreg' on function refers to return value ISD::ArgFlagsTy Flags = ISD::ArgFlagsTy(); if (F->paramHasAttr(0, Attribute::InReg)) Flags.setInReg(); // Propagate extension type if any if (ExtendKind == ISD::SIGN_EXTEND) Flags.setSExt(); else if (ExtendKind == ISD::ZERO_EXTEND) Flags.setZExt(); for (unsigned i = 0; i < NumParts; ++i) { Outs.push_back(ISD::OutputArg(Flags, Parts[i].getValueType(), /*isfixed=*/true)); OutVals.push_back(Parts[i]); } } } } bool isVarArg = DAG.getMachineFunction().getFunction()->isVarArg(); CallingConv::ID CallConv = DAG.getMachineFunction().getFunction()->getCallingConv(); Chain = TLI.LowerReturn(Chain, CallConv, isVarArg, Outs, OutVals, getCurDebugLoc(), DAG); // Verify that the target's LowerReturn behaved as expected. assert(Chain.getNode() && Chain.getValueType() == MVT::Other && "LowerReturn didn't return a valid chain!"); // Update the DAG with the new chain value resulting from return lowering. DAG.setRoot(Chain); } /// CopyToExportRegsIfNeeded - If the given value has virtual registers /// created for it, emit nodes to copy the value into the virtual /// registers. void SelectionDAGBuilder::CopyToExportRegsIfNeeded(const Value *V) { // Skip empty types if (V->getType()->isEmptyTy()) return; DenseMap::iterator VMI = FuncInfo.ValueMap.find(V); if (VMI != FuncInfo.ValueMap.end()) { assert(!V->use_empty() && "Unused value assigned virtual registers!"); CopyValueToVirtualRegister(V, VMI->second); } } /// ExportFromCurrentBlock - If this condition isn't known to be exported from /// the current basic block, add it to ValueMap now so that we'll get a /// CopyTo/FromReg. void SelectionDAGBuilder::ExportFromCurrentBlock(const Value *V) { // No need to export constants. if (!isa(V) && !isa(V)) return; // Already exported? if (FuncInfo.isExportedInst(V)) return; unsigned Reg = FuncInfo.InitializeRegForValue(V); CopyValueToVirtualRegister(V, Reg); } bool SelectionDAGBuilder::isExportableFromCurrentBlock(const Value *V, const BasicBlock *FromBB) { // The operands of the setcc have to be in this block. We don't know // how to export them from some other block. if (const Instruction *VI = dyn_cast(V)) { // Can export from current BB. if (VI->getParent() == FromBB) return true; // Is already exported, noop. return FuncInfo.isExportedInst(V); } // If this is an argument, we can export it if the BB is the entry block or // if it is already exported. if (isa(V)) { if (FromBB == &FromBB->getParent()->getEntryBlock()) return true; // Otherwise, can only export this if it is already exported. return FuncInfo.isExportedInst(V); } // Otherwise, constants can always be exported. return true; } /// Return branch probability calculated by BranchProbabilityInfo for IR blocks. uint32_t SelectionDAGBuilder::getEdgeWeight(MachineBasicBlock *Src, MachineBasicBlock *Dst) { BranchProbabilityInfo *BPI = FuncInfo.BPI; if (!BPI) return 0; const BasicBlock *SrcBB = Src->getBasicBlock(); const BasicBlock *DstBB = Dst->getBasicBlock(); return BPI->getEdgeWeight(SrcBB, DstBB); } void SelectionDAGBuilder:: addSuccessorWithWeight(MachineBasicBlock *Src, MachineBasicBlock *Dst, uint32_t Weight /* = 0 */) { if (!Weight) Weight = getEdgeWeight(Src, Dst); Src->addSuccessor(Dst, Weight); } static bool InBlock(const Value *V, const BasicBlock *BB) { if (const Instruction *I = dyn_cast(V)) return I->getParent() == BB; return true; } /// EmitBranchForMergedCondition - Helper method for FindMergedConditions. /// This function emits a branch and is used at the leaves of an OR or an /// AND operator tree. /// void SelectionDAGBuilder::EmitBranchForMergedCondition(const Value *Cond, MachineBasicBlock *TBB, MachineBasicBlock *FBB, MachineBasicBlock *CurBB, MachineBasicBlock *SwitchBB) { const BasicBlock *BB = CurBB->getBasicBlock(); // If the leaf of the tree is a comparison, merge the condition into // the caseblock. if (const CmpInst *BOp = dyn_cast(Cond)) { // The operands of the cmp have to be in this block. We don't know // how to export them from some other block. If this is the first block // of the sequence, no exporting is needed. if (CurBB == SwitchBB || (isExportableFromCurrentBlock(BOp->getOperand(0), BB) && isExportableFromCurrentBlock(BOp->getOperand(1), BB))) { ISD::CondCode Condition; if (const ICmpInst *IC = dyn_cast(Cond)) { Condition = getICmpCondCode(IC->getPredicate()); } else if (const FCmpInst *FC = dyn_cast(Cond)) { Condition = getFCmpCondCode(FC->getPredicate()); } else { Condition = ISD::SETEQ; // silence warning. llvm_unreachable("Unknown compare instruction"); } CaseBlock CB(Condition, BOp->getOperand(0), BOp->getOperand(1), NULL, TBB, FBB, CurBB); SwitchCases.push_back(CB); return; } } // Create a CaseBlock record representing this branch. CaseBlock CB(ISD::SETEQ, Cond, ConstantInt::getTrue(*DAG.getContext()), NULL, TBB, FBB, CurBB); SwitchCases.push_back(CB); } /// FindMergedConditions - If Cond is an expression like void SelectionDAGBuilder::FindMergedConditions(const Value *Cond, MachineBasicBlock *TBB, MachineBasicBlock *FBB, MachineBasicBlock *CurBB, MachineBasicBlock *SwitchBB, unsigned Opc) { // If this node is not part of the or/and tree, emit it as a branch. const Instruction *BOp = dyn_cast(Cond); if (!BOp || !(isa(BOp) || isa(BOp)) || (unsigned)BOp->getOpcode() != Opc || !BOp->hasOneUse() || BOp->getParent() != CurBB->getBasicBlock() || !InBlock(BOp->getOperand(0), CurBB->getBasicBlock()) || !InBlock(BOp->getOperand(1), CurBB->getBasicBlock())) { EmitBranchForMergedCondition(Cond, TBB, FBB, CurBB, SwitchBB); return; } // Create TmpBB after CurBB. MachineFunction::iterator BBI = CurBB; MachineFunction &MF = DAG.getMachineFunction(); MachineBasicBlock *TmpBB = MF.CreateMachineBasicBlock(CurBB->getBasicBlock()); CurBB->getParent()->insert(++BBI, TmpBB); if (Opc == Instruction::Or) { // Codegen X | Y as: // jmp_if_X TBB // jmp TmpBB // TmpBB: // jmp_if_Y TBB // jmp FBB // // Emit the LHS condition. FindMergedConditions(BOp->getOperand(0), TBB, TmpBB, CurBB, SwitchBB, Opc); // Emit the RHS condition into TmpBB. FindMergedConditions(BOp->getOperand(1), TBB, FBB, TmpBB, SwitchBB, Opc); } else { assert(Opc == Instruction::And && "Unknown merge op!"); // Codegen X & Y as: // jmp_if_X TmpBB // jmp FBB // TmpBB: // jmp_if_Y TBB // jmp FBB // // This requires creation of TmpBB after CurBB. // Emit the LHS condition. FindMergedConditions(BOp->getOperand(0), TmpBB, FBB, CurBB, SwitchBB, Opc); // Emit the RHS condition into TmpBB. FindMergedConditions(BOp->getOperand(1), TBB, FBB, TmpBB, SwitchBB, Opc); } } /// If the set of cases should be emitted as a series of branches, return true. /// If we should emit this as a bunch of and/or'd together conditions, return /// false. bool SelectionDAGBuilder::ShouldEmitAsBranches(const std::vector &Cases){ if (Cases.size() != 2) return true; // If this is two comparisons of the same values or'd or and'd together, they // will get folded into a single comparison, so don't emit two blocks. if ((Cases[0].CmpLHS == Cases[1].CmpLHS && Cases[0].CmpRHS == Cases[1].CmpRHS) || (Cases[0].CmpRHS == Cases[1].CmpLHS && Cases[0].CmpLHS == Cases[1].CmpRHS)) { return false; } // Handle: (X != null) | (Y != null) --> (X|Y) != 0 // Handle: (X == null) & (Y == null) --> (X|Y) == 0 if (Cases[0].CmpRHS == Cases[1].CmpRHS && Cases[0].CC == Cases[1].CC && isa(Cases[0].CmpRHS) && cast(Cases[0].CmpRHS)->isNullValue()) { if (Cases[0].CC == ISD::SETEQ && Cases[0].TrueBB == Cases[1].ThisBB) return false; if (Cases[0].CC == ISD::SETNE && Cases[0].FalseBB == Cases[1].ThisBB) return false; } return true; } void SelectionDAGBuilder::visitBr(const BranchInst &I) { MachineBasicBlock *BrMBB = FuncInfo.MBB; // Update machine-CFG edges. MachineBasicBlock *Succ0MBB = FuncInfo.MBBMap[I.getSuccessor(0)]; // Figure out which block is immediately after the current one. MachineBasicBlock *NextBlock = 0; MachineFunction::iterator BBI = BrMBB; if (++BBI != FuncInfo.MF->end()) NextBlock = BBI; if (I.isUnconditional()) { // Update machine-CFG edges. BrMBB->addSuccessor(Succ0MBB); // If this is not a fall-through branch, emit the branch. if (Succ0MBB != NextBlock) DAG.setRoot(DAG.getNode(ISD::BR, getCurDebugLoc(), MVT::Other, getControlRoot(), DAG.getBasicBlock(Succ0MBB))); return; } // If this condition is one of the special cases we handle, do special stuff // now. const Value *CondVal = I.getCondition(); MachineBasicBlock *Succ1MBB = FuncInfo.MBBMap[I.getSuccessor(1)]; // If this is a series of conditions that are or'd or and'd together, emit // this as a sequence of branches instead of setcc's with and/or operations. // As long as jumps are not expensive, this should improve performance. // For example, instead of something like: // cmp A, B // C = seteq // cmp D, E // F = setle // or C, F // jnz foo // Emit: // cmp A, B // je foo // cmp D, E // jle foo // if (const BinaryOperator *BOp = dyn_cast(CondVal)) { if (!TLI.isJumpExpensive() && BOp->hasOneUse() && (BOp->getOpcode() == Instruction::And || BOp->getOpcode() == Instruction::Or)) { FindMergedConditions(BOp, Succ0MBB, Succ1MBB, BrMBB, BrMBB, BOp->getOpcode()); // If the compares in later blocks need to use values not currently // exported from this block, export them now. This block should always // be the first entry. assert(SwitchCases[0].ThisBB == BrMBB && "Unexpected lowering!"); // Allow some cases to be rejected. if (ShouldEmitAsBranches(SwitchCases)) { for (unsigned i = 1, e = SwitchCases.size(); i != e; ++i) { ExportFromCurrentBlock(SwitchCases[i].CmpLHS); ExportFromCurrentBlock(SwitchCases[i].CmpRHS); } // Emit the branch for this block. visitSwitchCase(SwitchCases[0], BrMBB); SwitchCases.erase(SwitchCases.begin()); return; } // Okay, we decided not to do this, remove any inserted MBB's and clear // SwitchCases. for (unsigned i = 1, e = SwitchCases.size(); i != e; ++i) FuncInfo.MF->erase(SwitchCases[i].ThisBB); SwitchCases.clear(); } } // Create a CaseBlock record representing this branch. CaseBlock CB(ISD::SETEQ, CondVal, ConstantInt::getTrue(*DAG.getContext()), NULL, Succ0MBB, Succ1MBB, BrMBB); // Use visitSwitchCase to actually insert the fast branch sequence for this // cond branch. visitSwitchCase(CB, BrMBB); } /// visitSwitchCase - Emits the necessary code to represent a single node in /// the binary search tree resulting from lowering a switch instruction. void SelectionDAGBuilder::visitSwitchCase(CaseBlock &CB, MachineBasicBlock *SwitchBB) { SDValue Cond; SDValue CondLHS = getValue(CB.CmpLHS); DebugLoc dl = getCurDebugLoc(); // Build the setcc now. if (CB.CmpMHS == NULL) { // Fold "(X == true)" to X and "(X == false)" to !X to // handle common cases produced by branch lowering. if (CB.CmpRHS == ConstantInt::getTrue(*DAG.getContext()) && CB.CC == ISD::SETEQ) Cond = CondLHS; else if (CB.CmpRHS == ConstantInt::getFalse(*DAG.getContext()) && CB.CC == ISD::SETEQ) { SDValue True = DAG.getConstant(1, CondLHS.getValueType()); Cond = DAG.getNode(ISD::XOR, dl, CondLHS.getValueType(), CondLHS, True); } else Cond = DAG.getSetCC(dl, MVT::i1, CondLHS, getValue(CB.CmpRHS), CB.CC); } else { assert(CB.CC == ISD::SETLE && "Can handle only LE ranges now"); const APInt& Low = cast(CB.CmpLHS)->getValue(); const APInt& High = cast(CB.CmpRHS)->getValue(); SDValue CmpOp = getValue(CB.CmpMHS); EVT VT = CmpOp.getValueType(); if (cast(CB.CmpLHS)->isMinValue(true)) { Cond = DAG.getSetCC(dl, MVT::i1, CmpOp, DAG.getConstant(High, VT), ISD::SETLE); } else { SDValue SUB = DAG.getNode(ISD::SUB, dl, VT, CmpOp, DAG.getConstant(Low, VT)); Cond = DAG.getSetCC(dl, MVT::i1, SUB, DAG.getConstant(High-Low, VT), ISD::SETULE); } } // Update successor info addSuccessorWithWeight(SwitchBB, CB.TrueBB, CB.TrueWeight); addSuccessorWithWeight(SwitchBB, CB.FalseBB, CB.FalseWeight); // Set NextBlock to be the MBB immediately after the current one, if any. // This is used to avoid emitting unnecessary branches to the next block. MachineBasicBlock *NextBlock = 0; MachineFunction::iterator BBI = SwitchBB; if (++BBI != FuncInfo.MF->end()) NextBlock = BBI; // If the lhs block is the next block, invert the condition so that we can // fall through to the lhs instead of the rhs block. if (CB.TrueBB == NextBlock) { std::swap(CB.TrueBB, CB.FalseBB); SDValue True = DAG.getConstant(1, Cond.getValueType()); Cond = DAG.getNode(ISD::XOR, dl, Cond.getValueType(), Cond, True); } SDValue BrCond = DAG.getNode(ISD::BRCOND, dl, MVT::Other, getControlRoot(), Cond, DAG.getBasicBlock(CB.TrueBB)); // Insert the false branch. Do this even if it's a fall through branch, // this makes it easier to do DAG optimizations which require inverting // the branch condition. BrCond = DAG.getNode(ISD::BR, dl, MVT::Other, BrCond, DAG.getBasicBlock(CB.FalseBB)); DAG.setRoot(BrCond); } /// visitJumpTable - Emit JumpTable node in the current MBB void SelectionDAGBuilder::visitJumpTable(JumpTable &JT) { // Emit the code for the jump table assert(JT.Reg != -1U && "Should lower JT Header first!"); EVT PTy = TLI.getPointerTy(); SDValue Index = DAG.getCopyFromReg(getControlRoot(), getCurDebugLoc(), JT.Reg, PTy); SDValue Table = DAG.getJumpTable(JT.JTI, PTy); SDValue BrJumpTable = DAG.getNode(ISD::BR_JT, getCurDebugLoc(), MVT::Other, Index.getValue(1), Table, Index); DAG.setRoot(BrJumpTable); } /// visitJumpTableHeader - This function emits necessary code to produce index /// in the JumpTable from switch case. void SelectionDAGBuilder::visitJumpTableHeader(JumpTable &JT, JumpTableHeader &JTH, MachineBasicBlock *SwitchBB) { // Subtract the lowest switch case value from the value being switched on and // conditional branch to default mbb if the result is greater than the // difference between smallest and largest cases. SDValue SwitchOp = getValue(JTH.SValue); EVT VT = SwitchOp.getValueType(); SDValue Sub = DAG.getNode(ISD::SUB, getCurDebugLoc(), VT, SwitchOp, DAG.getConstant(JTH.First, VT)); // The SDNode we just created, which holds the value being switched on minus // the smallest case value, needs to be copied to a virtual register so it // can be used as an index into the jump table in a subsequent basic block. // This value may be smaller or larger than the target's pointer type, and // therefore require extension or truncating. SwitchOp = DAG.getZExtOrTrunc(Sub, getCurDebugLoc(), TLI.getPointerTy()); unsigned JumpTableReg = FuncInfo.CreateReg(TLI.getPointerTy()); SDValue CopyTo = DAG.getCopyToReg(getControlRoot(), getCurDebugLoc(), JumpTableReg, SwitchOp); JT.Reg = JumpTableReg; // Emit the range check for the jump table, and branch to the default block // for the switch statement if the value being switched on exceeds the largest // case in the switch. SDValue CMP = DAG.getSetCC(getCurDebugLoc(), TLI.getSetCCResultType(Sub.getValueType()), Sub, DAG.getConstant(JTH.Last-JTH.First,VT), ISD::SETUGT); // Set NextBlock to be the MBB immediately after the current one, if any. // This is used to avoid emitting unnecessary branches to the next block. MachineBasicBlock *NextBlock = 0; MachineFunction::iterator BBI = SwitchBB; if (++BBI != FuncInfo.MF->end()) NextBlock = BBI; SDValue BrCond = DAG.getNode(ISD::BRCOND, getCurDebugLoc(), MVT::Other, CopyTo, CMP, DAG.getBasicBlock(JT.Default)); if (JT.MBB != NextBlock) BrCond = DAG.getNode(ISD::BR, getCurDebugLoc(), MVT::Other, BrCond, DAG.getBasicBlock(JT.MBB)); DAG.setRoot(BrCond); } /// visitBitTestHeader - This function emits necessary code to produce value /// suitable for "bit tests" void SelectionDAGBuilder::visitBitTestHeader(BitTestBlock &B, MachineBasicBlock *SwitchBB) { // Subtract the minimum value SDValue SwitchOp = getValue(B.SValue); EVT VT = SwitchOp.getValueType(); SDValue Sub = DAG.getNode(ISD::SUB, getCurDebugLoc(), VT, SwitchOp, DAG.getConstant(B.First, VT)); // Check range SDValue RangeCmp = DAG.getSetCC(getCurDebugLoc(), TLI.getSetCCResultType(Sub.getValueType()), Sub, DAG.getConstant(B.Range, VT), ISD::SETUGT); // Determine the type of the test operands. bool UsePtrType = false; if (!TLI.isTypeLegal(VT)) UsePtrType = true; else { for (unsigned i = 0, e = B.Cases.size(); i != e; ++i) if (!isUIntN(VT.getSizeInBits(), B.Cases[i].Mask)) { // Switch table case range are encoded into series of masks. // Just use pointer type, it's guaranteed to fit. UsePtrType = true; break; } } if (UsePtrType) { VT = TLI.getPointerTy(); Sub = DAG.getZExtOrTrunc(Sub, getCurDebugLoc(), VT); } B.RegVT = VT; B.Reg = FuncInfo.CreateReg(VT); SDValue CopyTo = DAG.getCopyToReg(getControlRoot(), getCurDebugLoc(), B.Reg, Sub); // Set NextBlock to be the MBB immediately after the current one, if any. // This is used to avoid emitting unnecessary branches to the next block. MachineBasicBlock *NextBlock = 0; MachineFunction::iterator BBI = SwitchBB; if (++BBI != FuncInfo.MF->end()) NextBlock = BBI; MachineBasicBlock* MBB = B.Cases[0].ThisBB; addSuccessorWithWeight(SwitchBB, B.Default); addSuccessorWithWeight(SwitchBB, MBB); SDValue BrRange = DAG.getNode(ISD::BRCOND, getCurDebugLoc(), MVT::Other, CopyTo, RangeCmp, DAG.getBasicBlock(B.Default)); if (MBB != NextBlock) BrRange = DAG.getNode(ISD::BR, getCurDebugLoc(), MVT::Other, CopyTo, DAG.getBasicBlock(MBB)); DAG.setRoot(BrRange); } /// visitBitTestCase - this function produces one "bit test" void SelectionDAGBuilder::visitBitTestCase(BitTestBlock &BB, MachineBasicBlock* NextMBB, unsigned Reg, BitTestCase &B, MachineBasicBlock *SwitchBB) { EVT VT = BB.RegVT; SDValue ShiftOp = DAG.getCopyFromReg(getControlRoot(), getCurDebugLoc(), Reg, VT); SDValue Cmp; unsigned PopCount = CountPopulation_64(B.Mask); if (PopCount == 1) { // Testing for a single bit; just compare the shift count with what it // would need to be to shift a 1 bit in that position. Cmp = DAG.getSetCC(getCurDebugLoc(), TLI.getSetCCResultType(VT), ShiftOp, DAG.getConstant(CountTrailingZeros_64(B.Mask), VT), ISD::SETEQ); } else if (PopCount == BB.Range) { // There is only one zero bit in the range, test for it directly. Cmp = DAG.getSetCC(getCurDebugLoc(), TLI.getSetCCResultType(VT), ShiftOp, DAG.getConstant(CountTrailingOnes_64(B.Mask), VT), ISD::SETNE); } else { // Make desired shift SDValue SwitchVal = DAG.getNode(ISD::SHL, getCurDebugLoc(), VT, DAG.getConstant(1, VT), ShiftOp); // Emit bit tests and jumps SDValue AndOp = DAG.getNode(ISD::AND, getCurDebugLoc(), VT, SwitchVal, DAG.getConstant(B.Mask, VT)); Cmp = DAG.getSetCC(getCurDebugLoc(), TLI.getSetCCResultType(VT), AndOp, DAG.getConstant(0, VT), ISD::SETNE); } addSuccessorWithWeight(SwitchBB, B.TargetBB); addSuccessorWithWeight(SwitchBB, NextMBB); SDValue BrAnd = DAG.getNode(ISD::BRCOND, getCurDebugLoc(), MVT::Other, getControlRoot(), Cmp, DAG.getBasicBlock(B.TargetBB)); // Set NextBlock to be the MBB immediately after the current one, if any. // This is used to avoid emitting unnecessary branches to the next block. MachineBasicBlock *NextBlock = 0; MachineFunction::iterator BBI = SwitchBB; if (++BBI != FuncInfo.MF->end()) NextBlock = BBI; if (NextMBB != NextBlock) BrAnd = DAG.getNode(ISD::BR, getCurDebugLoc(), MVT::Other, BrAnd, DAG.getBasicBlock(NextMBB)); DAG.setRoot(BrAnd); } void SelectionDAGBuilder::visitInvoke(const InvokeInst &I) { MachineBasicBlock *InvokeMBB = FuncInfo.MBB; // Retrieve successors. MachineBasicBlock *Return = FuncInfo.MBBMap[I.getSuccessor(0)]; MachineBasicBlock *LandingPad = FuncInfo.MBBMap[I.getSuccessor(1)]; const Value *Callee(I.getCalledValue()); if (isa(Callee)) visitInlineAsm(&I); else LowerCallTo(&I, getValue(Callee), false, LandingPad); // If the value of the invoke is used outside of its defining block, make it // available as a virtual register. CopyToExportRegsIfNeeded(&I); // Update successor info InvokeMBB->addSuccessor(Return); InvokeMBB->addSuccessor(LandingPad); // Drop into normal successor. DAG.setRoot(DAG.getNode(ISD::BR, getCurDebugLoc(), MVT::Other, getControlRoot(), DAG.getBasicBlock(Return))); } void SelectionDAGBuilder::visitUnwind(const UnwindInst &I) { } void SelectionDAGBuilder::visitResume(const ResumeInst &RI) { llvm_unreachable("SelectionDAGBuilder shouldn't visit resume instructions!"); } void SelectionDAGBuilder::visitLandingPad(const LandingPadInst &LP) { assert(FuncInfo.MBB->isLandingPad() && "Call to landingpad not in landing pad!"); MachineBasicBlock *MBB = FuncInfo.MBB; MachineModuleInfo &MMI = DAG.getMachineFunction().getMMI(); AddLandingPadInfo(LP, MMI, MBB); SmallVector ValueVTs; ComputeValueVTs(TLI, LP.getType(), ValueVTs); // Insert the EXCEPTIONADDR instruction. assert(FuncInfo.MBB->isLandingPad() && "Call to eh.exception not in landing pad!"); SDVTList VTs = DAG.getVTList(TLI.getPointerTy(), MVT::Other); SDValue Ops[2]; Ops[0] = DAG.getRoot(); SDValue Op1 = DAG.getNode(ISD::EXCEPTIONADDR, getCurDebugLoc(), VTs, Ops, 1); SDValue Chain = Op1.getValue(1); // Insert the EHSELECTION instruction. VTs = DAG.getVTList(TLI.getPointerTy(), MVT::Other); Ops[0] = Op1; Ops[1] = Chain; SDValue Op2 = DAG.getNode(ISD::EHSELECTION, getCurDebugLoc(), VTs, Ops, 2); Chain = Op2.getValue(1); Op2 = DAG.getSExtOrTrunc(Op2, getCurDebugLoc(), MVT::i32); Ops[0] = Op1; Ops[1] = Op2; SDValue Res = DAG.getNode(ISD::MERGE_VALUES, getCurDebugLoc(), DAG.getVTList(&ValueVTs[0], ValueVTs.size()), &Ops[0], 2); std::pair RetPair = std::make_pair(Res, Chain); setValue(&LP, RetPair.first); DAG.setRoot(RetPair.second); } /// handleSmallSwitchCaseRange - Emit a series of specific tests (suitable for /// small case ranges). bool SelectionDAGBuilder::handleSmallSwitchRange(CaseRec& CR, CaseRecVector& WorkList, const Value* SV, MachineBasicBlock *Default, MachineBasicBlock *SwitchBB) { Case& BackCase = *(CR.Range.second-1); // Size is the number of Cases represented by this range. size_t Size = CR.Range.second - CR.Range.first; if (Size > 3) return false; // Get the MachineFunction which holds the current MBB. This is used when // inserting any additional MBBs necessary to represent the switch. MachineFunction *CurMF = FuncInfo.MF; // Figure out which block is immediately after the current one. MachineBasicBlock *NextBlock = 0; MachineFunction::iterator BBI = CR.CaseBB; if (++BBI != FuncInfo.MF->end()) NextBlock = BBI; // If any two of the cases has the same destination, and if one value // is the same as the other, but has one bit unset that the other has set, // use bit manipulation to do two compares at once. For example: // "if (X == 6 || X == 4)" -> "if ((X|2) == 6)" // TODO: This could be extended to merge any 2 cases in switches with 3 cases. // TODO: Handle cases where CR.CaseBB != SwitchBB. if (Size == 2 && CR.CaseBB == SwitchBB) { Case &Small = *CR.Range.first; Case &Big = *(CR.Range.second-1); if (Small.Low == Small.High && Big.Low == Big.High && Small.BB == Big.BB) { const APInt& SmallValue = cast(Small.Low)->getValue(); const APInt& BigValue = cast(Big.Low)->getValue(); // Check that there is only one bit different. if (BigValue.countPopulation() == SmallValue.countPopulation() + 1 && (SmallValue | BigValue) == BigValue) { // Isolate the common bit. APInt CommonBit = BigValue & ~SmallValue; assert((SmallValue | CommonBit) == BigValue && CommonBit.countPopulation() == 1 && "Not a common bit?"); SDValue CondLHS = getValue(SV); EVT VT = CondLHS.getValueType(); DebugLoc DL = getCurDebugLoc(); SDValue Or = DAG.getNode(ISD::OR, DL, VT, CondLHS, DAG.getConstant(CommonBit, VT)); SDValue Cond = DAG.getSetCC(DL, MVT::i1, Or, DAG.getConstant(BigValue, VT), ISD::SETEQ); // Update successor info. addSuccessorWithWeight(SwitchBB, Small.BB); addSuccessorWithWeight(SwitchBB, Default); // Insert the true branch. SDValue BrCond = DAG.getNode(ISD::BRCOND, DL, MVT::Other, getControlRoot(), Cond, DAG.getBasicBlock(Small.BB)); // Insert the false branch. BrCond = DAG.getNode(ISD::BR, DL, MVT::Other, BrCond, DAG.getBasicBlock(Default)); DAG.setRoot(BrCond); return true; } } } // Rearrange the case blocks so that the last one falls through if possible. if (NextBlock && Default != NextBlock && BackCase.BB != NextBlock) { // The last case block won't fall through into 'NextBlock' if we emit the // branches in this order. See if rearranging a case value would help. for (CaseItr I = CR.Range.first, E = CR.Range.second-1; I != E; ++I) { if (I->BB == NextBlock) { std::swap(*I, BackCase); break; } } } // Create a CaseBlock record representing a conditional branch to // the Case's target mbb if the value being switched on SV is equal // to C. MachineBasicBlock *CurBlock = CR.CaseBB; for (CaseItr I = CR.Range.first, E = CR.Range.second; I != E; ++I) { MachineBasicBlock *FallThrough; if (I != E-1) { FallThrough = CurMF->CreateMachineBasicBlock(CurBlock->getBasicBlock()); CurMF->insert(BBI, FallThrough); // Put SV in a virtual register to make it available from the new blocks. ExportFromCurrentBlock(SV); } else { // If the last case doesn't match, go to the default block. FallThrough = Default; } const Value *RHS, *LHS, *MHS; ISD::CondCode CC; if (I->High == I->Low) { // This is just small small case range :) containing exactly 1 case CC = ISD::SETEQ; LHS = SV; RHS = I->High; MHS = NULL; } else { CC = ISD::SETLE; LHS = I->Low; MHS = SV; RHS = I->High; } uint32_t ExtraWeight = I->ExtraWeight; CaseBlock CB(CC, LHS, RHS, MHS, /* truebb */ I->BB, /* falsebb */ FallThrough, /* me */ CurBlock, /* trueweight */ ExtraWeight / 2, /* falseweight */ ExtraWeight / 2); // If emitting the first comparison, just call visitSwitchCase to emit the // code into the current block. Otherwise, push the CaseBlock onto the // vector to be later processed by SDISel, and insert the node's MBB // before the next MBB. if (CurBlock == SwitchBB) visitSwitchCase(CB, SwitchBB); else SwitchCases.push_back(CB); CurBlock = FallThrough; } return true; } static inline bool areJTsAllowed(const TargetLowering &TLI) { return !DisableJumpTables && (TLI.isOperationLegalOrCustom(ISD::BR_JT, MVT::Other) || TLI.isOperationLegalOrCustom(ISD::BRIND, MVT::Other)); } static APInt ComputeRange(const APInt &First, const APInt &Last) { uint32_t BitWidth = std::max(Last.getBitWidth(), First.getBitWidth()) + 1; APInt LastExt = Last.sext(BitWidth), FirstExt = First.sext(BitWidth); return (LastExt - FirstExt + 1ULL); } /// handleJTSwitchCase - Emit jumptable for current switch case range bool SelectionDAGBuilder::handleJTSwitchCase(CaseRec &CR, CaseRecVector &WorkList, const Value *SV, MachineBasicBlock *Default, MachineBasicBlock *SwitchBB) { Case& FrontCase = *CR.Range.first; Case& BackCase = *(CR.Range.second-1); const APInt &First = cast(FrontCase.Low)->getValue(); const APInt &Last = cast(BackCase.High)->getValue(); APInt TSize(First.getBitWidth(), 0); for (CaseItr I = CR.Range.first, E = CR.Range.second; I != E; ++I) TSize += I->size(); if (!areJTsAllowed(TLI) || TSize.ult(4)) return false; APInt Range = ComputeRange(First, Last); - double Density = TSize.roundToDouble() / Range.roundToDouble(); - if (Density < 0.4) + // The density is TSize / Range. Require at least 40%. + // It should not be possible for IntTSize to saturate for sane code, but make + // sure we handle Range saturation correctly. + uint64_t IntRange = Range.getLimitedValue(UINT64_MAX/10); + uint64_t IntTSize = TSize.getLimitedValue(UINT64_MAX/10); + if (IntTSize * 10 < IntRange * 4) return false; DEBUG(dbgs() << "Lowering jump table\n" << "First entry: " << First << ". Last entry: " << Last << '\n' - << "Range: " << Range - << ". Size: " << TSize << ". Density: " << Density << "\n\n"); + << "Range: " << Range << ". Size: " << TSize << ".\n\n"); // Get the MachineFunction which holds the current MBB. This is used when // inserting any additional MBBs necessary to represent the switch. MachineFunction *CurMF = FuncInfo.MF; // Figure out which block is immediately after the current one. MachineFunction::iterator BBI = CR.CaseBB; ++BBI; const BasicBlock *LLVMBB = CR.CaseBB->getBasicBlock(); // Create a new basic block to hold the code for loading the address // of the jump table, and jumping to it. Update successor information; // we will either branch to the default case for the switch, or the jump // table. MachineBasicBlock *JumpTableBB = CurMF->CreateMachineBasicBlock(LLVMBB); CurMF->insert(BBI, JumpTableBB); addSuccessorWithWeight(CR.CaseBB, Default); addSuccessorWithWeight(CR.CaseBB, JumpTableBB); // Build a vector of destination BBs, corresponding to each target // of the jump table. If the value of the jump table slot corresponds to // a case statement, push the case's BB onto the vector, otherwise, push // the default BB. std::vector DestBBs; APInt TEI = First; for (CaseItr I = CR.Range.first, E = CR.Range.second; I != E; ++TEI) { const APInt &Low = cast(I->Low)->getValue(); const APInt &High = cast(I->High)->getValue(); if (Low.sle(TEI) && TEI.sle(High)) { DestBBs.push_back(I->BB); if (TEI==High) ++I; } else { DestBBs.push_back(Default); } } // Update successor info. Add one edge to each unique successor. BitVector SuccsHandled(CR.CaseBB->getParent()->getNumBlockIDs()); for (std::vector::iterator I = DestBBs.begin(), E = DestBBs.end(); I != E; ++I) { if (!SuccsHandled[(*I)->getNumber()]) { SuccsHandled[(*I)->getNumber()] = true; addSuccessorWithWeight(JumpTableBB, *I); } } // Create a jump table index for this jump table. unsigned JTEncoding = TLI.getJumpTableEncoding(); unsigned JTI = CurMF->getOrCreateJumpTableInfo(JTEncoding) ->createJumpTableIndex(DestBBs); // Set the jump table information so that we can codegen it as a second // MachineBasicBlock JumpTable JT(-1U, JTI, JumpTableBB, Default); JumpTableHeader JTH(First, Last, SV, CR.CaseBB, (CR.CaseBB == SwitchBB)); if (CR.CaseBB == SwitchBB) visitJumpTableHeader(JT, JTH, SwitchBB); JTCases.push_back(JumpTableBlock(JTH, JT)); return true; } /// handleBTSplitSwitchCase - emit comparison and split binary search tree into /// 2 subtrees. bool SelectionDAGBuilder::handleBTSplitSwitchCase(CaseRec& CR, CaseRecVector& WorkList, const Value* SV, MachineBasicBlock *Default, MachineBasicBlock *SwitchBB) { // Get the MachineFunction which holds the current MBB. This is used when // inserting any additional MBBs necessary to represent the switch. MachineFunction *CurMF = FuncInfo.MF; // Figure out which block is immediately after the current one. MachineFunction::iterator BBI = CR.CaseBB; ++BBI; Case& FrontCase = *CR.Range.first; Case& BackCase = *(CR.Range.second-1); const BasicBlock *LLVMBB = CR.CaseBB->getBasicBlock(); // Size is the number of Cases represented by this range. unsigned Size = CR.Range.second - CR.Range.first; const APInt &First = cast(FrontCase.Low)->getValue(); const APInt &Last = cast(BackCase.High)->getValue(); double FMetric = 0; CaseItr Pivot = CR.Range.first + Size/2; // Select optimal pivot, maximizing sum density of LHS and RHS. This will // (heuristically) allow us to emit JumpTable's later. APInt TSize(First.getBitWidth(), 0); for (CaseItr I = CR.Range.first, E = CR.Range.second; I!=E; ++I) TSize += I->size(); APInt LSize = FrontCase.size(); APInt RSize = TSize-LSize; DEBUG(dbgs() << "Selecting best pivot: \n" << "First: " << First << ", Last: " << Last <<'\n' << "LSize: " << LSize << ", RSize: " << RSize << '\n'); for (CaseItr I = CR.Range.first, J=I+1, E = CR.Range.second; J!=E; ++I, ++J) { const APInt &LEnd = cast(I->High)->getValue(); const APInt &RBegin = cast(J->Low)->getValue(); APInt Range = ComputeRange(LEnd, RBegin); assert((Range - 2ULL).isNonNegative() && "Invalid case distance"); // Use volatile double here to avoid excess precision issues on some hosts, // e.g. that use 80-bit X87 registers. volatile double LDensity = (double)LSize.roundToDouble() / (LEnd - First + 1ULL).roundToDouble(); volatile double RDensity = (double)RSize.roundToDouble() / (Last - RBegin + 1ULL).roundToDouble(); double Metric = Range.logBase2()*(LDensity+RDensity); // Should always split in some non-trivial place DEBUG(dbgs() <<"=>Step\n" << "LEnd: " << LEnd << ", RBegin: " << RBegin << '\n' << "LDensity: " << LDensity << ", RDensity: " << RDensity << '\n' << "Metric: " << Metric << '\n'); if (FMetric < Metric) { Pivot = J; FMetric = Metric; DEBUG(dbgs() << "Current metric set to: " << FMetric << '\n'); } LSize += J->size(); RSize -= J->size(); } if (areJTsAllowed(TLI)) { // If our case is dense we *really* should handle it earlier! assert((FMetric > 0) && "Should handle dense range earlier!"); } else { Pivot = CR.Range.first + Size/2; } CaseRange LHSR(CR.Range.first, Pivot); CaseRange RHSR(Pivot, CR.Range.second); Constant *C = Pivot->Low; MachineBasicBlock *FalseBB = 0, *TrueBB = 0; // We know that we branch to the LHS if the Value being switched on is // less than the Pivot value, C. We use this to optimize our binary // tree a bit, by recognizing that if SV is greater than or equal to the // LHS's Case Value, and that Case Value is exactly one less than the // Pivot's Value, then we can branch directly to the LHS's Target, // rather than creating a leaf node for it. if ((LHSR.second - LHSR.first) == 1 && LHSR.first->High == CR.GE && cast(C)->getValue() == (cast(CR.GE)->getValue() + 1LL)) { TrueBB = LHSR.first->BB; } else { TrueBB = CurMF->CreateMachineBasicBlock(LLVMBB); CurMF->insert(BBI, TrueBB); WorkList.push_back(CaseRec(TrueBB, C, CR.GE, LHSR)); // Put SV in a virtual register to make it available from the new blocks. ExportFromCurrentBlock(SV); } // Similar to the optimization above, if the Value being switched on is // known to be less than the Constant CR.LT, and the current Case Value // is CR.LT - 1, then we can branch directly to the target block for // the current Case Value, rather than emitting a RHS leaf node for it. if ((RHSR.second - RHSR.first) == 1 && CR.LT && cast(RHSR.first->Low)->getValue() == (cast(CR.LT)->getValue() - 1LL)) { FalseBB = RHSR.first->BB; } else { FalseBB = CurMF->CreateMachineBasicBlock(LLVMBB); CurMF->insert(BBI, FalseBB); WorkList.push_back(CaseRec(FalseBB,CR.LT,C,RHSR)); // Put SV in a virtual register to make it available from the new blocks. ExportFromCurrentBlock(SV); } // Create a CaseBlock record representing a conditional branch to // the LHS node if the value being switched on SV is less than C. // Otherwise, branch to LHS. CaseBlock CB(ISD::SETLT, SV, C, NULL, TrueBB, FalseBB, CR.CaseBB); if (CR.CaseBB == SwitchBB) visitSwitchCase(CB, SwitchBB); else SwitchCases.push_back(CB); return true; } /// handleBitTestsSwitchCase - if current case range has few destination and /// range span less, than machine word bitwidth, encode case range into series /// of masks and emit bit tests with these masks. bool SelectionDAGBuilder::handleBitTestsSwitchCase(CaseRec& CR, CaseRecVector& WorkList, const Value* SV, MachineBasicBlock* Default, MachineBasicBlock *SwitchBB){ EVT PTy = TLI.getPointerTy(); unsigned IntPtrBits = PTy.getSizeInBits(); Case& FrontCase = *CR.Range.first; Case& BackCase = *(CR.Range.second-1); // Get the MachineFunction which holds the current MBB. This is used when // inserting any additional MBBs necessary to represent the switch. MachineFunction *CurMF = FuncInfo.MF; // If target does not have legal shift left, do not emit bit tests at all. if (!TLI.isOperationLegal(ISD::SHL, TLI.getPointerTy())) return false; size_t numCmps = 0; for (CaseItr I = CR.Range.first, E = CR.Range.second; I!=E; ++I) { // Single case counts one, case range - two. numCmps += (I->Low == I->High ? 1 : 2); } // Count unique destinations SmallSet Dests; for (CaseItr I = CR.Range.first, E = CR.Range.second; I!=E; ++I) { Dests.insert(I->BB); if (Dests.size() > 3) // Don't bother the code below, if there are too much unique destinations return false; } DEBUG(dbgs() << "Total number of unique destinations: " << Dests.size() << '\n' << "Total number of comparisons: " << numCmps << '\n'); // Compute span of values. const APInt& minValue = cast(FrontCase.Low)->getValue(); const APInt& maxValue = cast(BackCase.High)->getValue(); APInt cmpRange = maxValue - minValue; DEBUG(dbgs() << "Compare range: " << cmpRange << '\n' << "Low bound: " << minValue << '\n' << "High bound: " << maxValue << '\n'); if (cmpRange.uge(IntPtrBits) || (!(Dests.size() == 1 && numCmps >= 3) && !(Dests.size() == 2 && numCmps >= 5) && !(Dests.size() >= 3 && numCmps >= 6))) return false; DEBUG(dbgs() << "Emitting bit tests\n"); APInt lowBound = APInt::getNullValue(cmpRange.getBitWidth()); // Optimize the case where all the case values fit in a // word without having to subtract minValue. In this case, // we can optimize away the subtraction. if (minValue.isNonNegative() && maxValue.slt(IntPtrBits)) { cmpRange = maxValue; } else { lowBound = minValue; } CaseBitsVector CasesBits; unsigned i, count = 0; for (CaseItr I = CR.Range.first, E = CR.Range.second; I!=E; ++I) { MachineBasicBlock* Dest = I->BB; for (i = 0; i < count; ++i) if (Dest == CasesBits[i].BB) break; if (i == count) { assert((count < 3) && "Too much destinations to test!"); CasesBits.push_back(CaseBits(0, Dest, 0)); count++; } const APInt& lowValue = cast(I->Low)->getValue(); const APInt& highValue = cast(I->High)->getValue(); uint64_t lo = (lowValue - lowBound).getZExtValue(); uint64_t hi = (highValue - lowBound).getZExtValue(); for (uint64_t j = lo; j <= hi; j++) { CasesBits[i].Mask |= 1ULL << j; CasesBits[i].Bits++; } } std::sort(CasesBits.begin(), CasesBits.end(), CaseBitsCmp()); BitTestInfo BTC; // Figure out which block is immediately after the current one. MachineFunction::iterator BBI = CR.CaseBB; ++BBI; const BasicBlock *LLVMBB = CR.CaseBB->getBasicBlock(); DEBUG(dbgs() << "Cases:\n"); for (unsigned i = 0, e = CasesBits.size(); i!=e; ++i) { DEBUG(dbgs() << "Mask: " << CasesBits[i].Mask << ", Bits: " << CasesBits[i].Bits << ", BB: " << CasesBits[i].BB << '\n'); MachineBasicBlock *CaseBB = CurMF->CreateMachineBasicBlock(LLVMBB); CurMF->insert(BBI, CaseBB); BTC.push_back(BitTestCase(CasesBits[i].Mask, CaseBB, CasesBits[i].BB)); // Put SV in a virtual register to make it available from the new blocks. ExportFromCurrentBlock(SV); } BitTestBlock BTB(lowBound, cmpRange, SV, -1U, MVT::Other, (CR.CaseBB == SwitchBB), CR.CaseBB, Default, BTC); if (CR.CaseBB == SwitchBB) visitBitTestHeader(BTB, SwitchBB); BitTestCases.push_back(BTB); return true; } /// Clusterify - Transform simple list of Cases into list of CaseRange's size_t SelectionDAGBuilder::Clusterify(CaseVector& Cases, const SwitchInst& SI) { size_t numCmps = 0; BranchProbabilityInfo *BPI = FuncInfo.BPI; // Start with "simple" cases for (size_t i = 1; i < SI.getNumSuccessors(); ++i) { BasicBlock *SuccBB = SI.getSuccessor(i); MachineBasicBlock *SMBB = FuncInfo.MBBMap[SuccBB]; uint32_t ExtraWeight = BPI ? BPI->getEdgeWeight(SI.getParent(), SuccBB) : 0; Cases.push_back(Case(SI.getSuccessorValue(i), SI.getSuccessorValue(i), SMBB, ExtraWeight)); } std::sort(Cases.begin(), Cases.end(), CaseCmp()); // Merge case into clusters if (Cases.size() >= 2) // Must recompute end() each iteration because it may be // invalidated by erase if we hold on to it for (CaseItr I = Cases.begin(), J = llvm::next(Cases.begin()); J != Cases.end(); ) { const APInt& nextValue = cast(J->Low)->getValue(); const APInt& currentValue = cast(I->High)->getValue(); MachineBasicBlock* nextBB = J->BB; MachineBasicBlock* currentBB = I->BB; // If the two neighboring cases go to the same destination, merge them // into a single case. if ((nextValue - currentValue == 1) && (currentBB == nextBB)) { I->High = J->High; J = Cases.erase(J); if (BranchProbabilityInfo *BPI = FuncInfo.BPI) { uint32_t CurWeight = currentBB->getBasicBlock() ? BPI->getEdgeWeight(SI.getParent(), currentBB->getBasicBlock()) : 16; uint32_t NextWeight = nextBB->getBasicBlock() ? BPI->getEdgeWeight(SI.getParent(), nextBB->getBasicBlock()) : 16; BPI->setEdgeWeight(SI.getParent(), currentBB->getBasicBlock(), CurWeight + NextWeight); } } else { I = J++; } } for (CaseItr I=Cases.begin(), E=Cases.end(); I!=E; ++I, ++numCmps) { if (I->Low != I->High) // A range counts double, since it requires two compares. ++numCmps; } return numCmps; } void SelectionDAGBuilder::UpdateSplitBlock(MachineBasicBlock *First, MachineBasicBlock *Last) { // Update JTCases. for (unsigned i = 0, e = JTCases.size(); i != e; ++i) if (JTCases[i].first.HeaderBB == First) JTCases[i].first.HeaderBB = Last; // Update BitTestCases. for (unsigned i = 0, e = BitTestCases.size(); i != e; ++i) if (BitTestCases[i].Parent == First) BitTestCases[i].Parent = Last; } void SelectionDAGBuilder::visitSwitch(const SwitchInst &SI) { MachineBasicBlock *SwitchMBB = FuncInfo.MBB; // Figure out which block is immediately after the current one. MachineBasicBlock *NextBlock = 0; MachineBasicBlock *Default = FuncInfo.MBBMap[SI.getDefaultDest()]; // If there is only the default destination, branch to it if it is not the // next basic block. Otherwise, just fall through. if (SI.getNumCases() == 1) { // Update machine-CFG edges. // If this is not a fall-through branch, emit the branch. SwitchMBB->addSuccessor(Default); if (Default != NextBlock) DAG.setRoot(DAG.getNode(ISD::BR, getCurDebugLoc(), MVT::Other, getControlRoot(), DAG.getBasicBlock(Default))); return; } // If there are any non-default case statements, create a vector of Cases // representing each one, and sort the vector so that we can efficiently // create a binary search tree from them. CaseVector Cases; size_t numCmps = Clusterify(Cases, SI); DEBUG(dbgs() << "Clusterify finished. Total clusters: " << Cases.size() << ". Total compares: " << numCmps << '\n'); (void)numCmps; // Get the Value to be switched on and default basic blocks, which will be // inserted into CaseBlock records, representing basic blocks in the binary // search tree. const Value *SV = SI.getCondition(); // Push the initial CaseRec onto the worklist CaseRecVector WorkList; WorkList.push_back(CaseRec(SwitchMBB,0,0, CaseRange(Cases.begin(),Cases.end()))); while (!WorkList.empty()) { // Grab a record representing a case range to process off the worklist CaseRec CR = WorkList.back(); WorkList.pop_back(); if (handleBitTestsSwitchCase(CR, WorkList, SV, Default, SwitchMBB)) continue; // If the range has few cases (two or less) emit a series of specific // tests. if (handleSmallSwitchRange(CR, WorkList, SV, Default, SwitchMBB)) continue; // If the switch has more than 5 blocks, and at least 40% dense, and the // target supports indirect branches, then emit a jump table rather than // lowering the switch to a binary tree of conditional branches. if (handleJTSwitchCase(CR, WorkList, SV, Default, SwitchMBB)) continue; // Emit binary tree. We need to pick a pivot, and push left and right ranges // onto the worklist. Leafs are handled via handleSmallSwitchRange() call. handleBTSplitSwitchCase(CR, WorkList, SV, Default, SwitchMBB); } } void SelectionDAGBuilder::visitIndirectBr(const IndirectBrInst &I) { MachineBasicBlock *IndirectBrMBB = FuncInfo.MBB; // Update machine-CFG edges with unique successors. SmallVector succs; succs.reserve(I.getNumSuccessors()); for (unsigned i = 0, e = I.getNumSuccessors(); i != e; ++i) succs.push_back(I.getSuccessor(i)); array_pod_sort(succs.begin(), succs.end()); succs.erase(std::unique(succs.begin(), succs.end()), succs.end()); for (unsigned i = 0, e = succs.size(); i != e; ++i) { MachineBasicBlock *Succ = FuncInfo.MBBMap[succs[i]]; addSuccessorWithWeight(IndirectBrMBB, Succ); } DAG.setRoot(DAG.getNode(ISD::BRIND, getCurDebugLoc(), MVT::Other, getControlRoot(), getValue(I.getAddress()))); } void SelectionDAGBuilder::visitFSub(const User &I) { // -0.0 - X --> fneg Type *Ty = I.getType(); if (isa(I.getOperand(0)) && I.getOperand(0) == ConstantFP::getZeroValueForNegation(Ty)) { SDValue Op2 = getValue(I.getOperand(1)); setValue(&I, DAG.getNode(ISD::FNEG, getCurDebugLoc(), Op2.getValueType(), Op2)); return; } visitBinary(I, ISD::FSUB); } void SelectionDAGBuilder::visitBinary(const User &I, unsigned OpCode) { SDValue Op1 = getValue(I.getOperand(0)); SDValue Op2 = getValue(I.getOperand(1)); setValue(&I, DAG.getNode(OpCode, getCurDebugLoc(), Op1.getValueType(), Op1, Op2)); } void SelectionDAGBuilder::visitShift(const User &I, unsigned Opcode) { SDValue Op1 = getValue(I.getOperand(0)); SDValue Op2 = getValue(I.getOperand(1)); MVT ShiftTy = TLI.getShiftAmountTy(Op2.getValueType()); // Coerce the shift amount to the right type if we can. if (!I.getType()->isVectorTy() && Op2.getValueType() != ShiftTy) { unsigned ShiftSize = ShiftTy.getSizeInBits(); unsigned Op2Size = Op2.getValueType().getSizeInBits(); DebugLoc DL = getCurDebugLoc(); // If the operand is smaller than the shift count type, promote it. if (ShiftSize > Op2Size) Op2 = DAG.getNode(ISD::ZERO_EXTEND, DL, ShiftTy, Op2); // If the operand is larger than the shift count type but the shift // count type has enough bits to represent any shift value, truncate // it now. This is a common case and it exposes the truncate to // optimization early. else if (ShiftSize >= Log2_32_Ceil(Op2.getValueType().getSizeInBits())) Op2 = DAG.getNode(ISD::TRUNCATE, DL, ShiftTy, Op2); // Otherwise we'll need to temporarily settle for some other convenient // type. Type legalization will make adjustments once the shiftee is split. else Op2 = DAG.getZExtOrTrunc(Op2, DL, MVT::i32); } setValue(&I, DAG.getNode(Opcode, getCurDebugLoc(), Op1.getValueType(), Op1, Op2)); } void SelectionDAGBuilder::visitSDiv(const User &I) { SDValue Op1 = getValue(I.getOperand(0)); SDValue Op2 = getValue(I.getOperand(1)); // Turn exact SDivs into multiplications. // FIXME: This should be in DAGCombiner, but it doesn't have access to the // exact bit. if (isa(&I) && cast(&I)->isExact() && !isa(Op1) && isa(Op2) && !cast(Op2)->isNullValue()) setValue(&I, TLI.BuildExactSDIV(Op1, Op2, getCurDebugLoc(), DAG)); else setValue(&I, DAG.getNode(ISD::SDIV, getCurDebugLoc(), Op1.getValueType(), Op1, Op2)); } void SelectionDAGBuilder::visitICmp(const User &I) { ICmpInst::Predicate predicate = ICmpInst::BAD_ICMP_PREDICATE; if (const ICmpInst *IC = dyn_cast(&I)) predicate = IC->getPredicate(); else if (const ConstantExpr *IC = dyn_cast(&I)) predicate = ICmpInst::Predicate(IC->getPredicate()); SDValue Op1 = getValue(I.getOperand(0)); SDValue Op2 = getValue(I.getOperand(1)); ISD::CondCode Opcode = getICmpCondCode(predicate); EVT DestVT = TLI.getValueType(I.getType()); setValue(&I, DAG.getSetCC(getCurDebugLoc(), DestVT, Op1, Op2, Opcode)); } void SelectionDAGBuilder::visitFCmp(const User &I) { FCmpInst::Predicate predicate = FCmpInst::BAD_FCMP_PREDICATE; if (const FCmpInst *FC = dyn_cast(&I)) predicate = FC->getPredicate(); else if (const ConstantExpr *FC = dyn_cast(&I)) predicate = FCmpInst::Predicate(FC->getPredicate()); SDValue Op1 = getValue(I.getOperand(0)); SDValue Op2 = getValue(I.getOperand(1)); ISD::CondCode Condition = getFCmpCondCode(predicate); EVT DestVT = TLI.getValueType(I.getType()); setValue(&I, DAG.getSetCC(getCurDebugLoc(), DestVT, Op1, Op2, Condition)); } void SelectionDAGBuilder::visitSelect(const User &I) { SmallVector ValueVTs; ComputeValueVTs(TLI, I.getType(), ValueVTs); unsigned NumValues = ValueVTs.size(); if (NumValues == 0) return; SmallVector Values(NumValues); SDValue Cond = getValue(I.getOperand(0)); SDValue TrueVal = getValue(I.getOperand(1)); SDValue FalseVal = getValue(I.getOperand(2)); ISD::NodeType OpCode = Cond.getValueType().isVector() ? ISD::VSELECT : ISD::SELECT; for (unsigned i = 0; i != NumValues; ++i) Values[i] = DAG.getNode(OpCode, getCurDebugLoc(), TrueVal.getNode()->getValueType(TrueVal.getResNo()+i), Cond, SDValue(TrueVal.getNode(), TrueVal.getResNo() + i), SDValue(FalseVal.getNode(), FalseVal.getResNo() + i)); setValue(&I, DAG.getNode(ISD::MERGE_VALUES, getCurDebugLoc(), DAG.getVTList(&ValueVTs[0], NumValues), &Values[0], NumValues)); } void SelectionDAGBuilder::visitTrunc(const User &I) { // TruncInst cannot be a no-op cast because sizeof(src) > sizeof(dest). SDValue N = getValue(I.getOperand(0)); EVT DestVT = TLI.getValueType(I.getType()); setValue(&I, DAG.getNode(ISD::TRUNCATE, getCurDebugLoc(), DestVT, N)); } void SelectionDAGBuilder::visitZExt(const User &I) { // ZExt cannot be a no-op cast because sizeof(src) < sizeof(dest). // ZExt also can't be a cast to bool for same reason. So, nothing much to do SDValue N = getValue(I.getOperand(0)); EVT DestVT = TLI.getValueType(I.getType()); setValue(&I, DAG.getNode(ISD::ZERO_EXTEND, getCurDebugLoc(), DestVT, N)); } void SelectionDAGBuilder::visitSExt(const User &I) { // SExt cannot be a no-op cast because sizeof(src) < sizeof(dest). // SExt also can't be a cast to bool for same reason. So, nothing much to do SDValue N = getValue(I.getOperand(0)); EVT DestVT = TLI.getValueType(I.getType()); setValue(&I, DAG.getNode(ISD::SIGN_EXTEND, getCurDebugLoc(), DestVT, N)); } void SelectionDAGBuilder::visitFPTrunc(const User &I) { // FPTrunc is never a no-op cast, no need to check SDValue N = getValue(I.getOperand(0)); EVT DestVT = TLI.getValueType(I.getType()); setValue(&I, DAG.getNode(ISD::FP_ROUND, getCurDebugLoc(), DestVT, N, DAG.getIntPtrConstant(0))); } void SelectionDAGBuilder::visitFPExt(const User &I){ // FPTrunc is never a no-op cast, no need to check SDValue N = getValue(I.getOperand(0)); EVT DestVT = TLI.getValueType(I.getType()); setValue(&I, DAG.getNode(ISD::FP_EXTEND, getCurDebugLoc(), DestVT, N)); } void SelectionDAGBuilder::visitFPToUI(const User &I) { // FPToUI is never a no-op cast, no need to check SDValue N = getValue(I.getOperand(0)); EVT DestVT = TLI.getValueType(I.getType()); setValue(&I, DAG.getNode(ISD::FP_TO_UINT, getCurDebugLoc(), DestVT, N)); } void SelectionDAGBuilder::visitFPToSI(const User &I) { // FPToSI is never a no-op cast, no need to check SDValue N = getValue(I.getOperand(0)); EVT DestVT = TLI.getValueType(I.getType()); setValue(&I, DAG.getNode(ISD::FP_TO_SINT, getCurDebugLoc(), DestVT, N)); } void SelectionDAGBuilder::visitUIToFP(const User &I) { // UIToFP is never a no-op cast, no need to check SDValue N = getValue(I.getOperand(0)); EVT DestVT = TLI.getValueType(I.getType()); setValue(&I, DAG.getNode(ISD::UINT_TO_FP, getCurDebugLoc(), DestVT, N)); } void SelectionDAGBuilder::visitSIToFP(const User &I){ // SIToFP is never a no-op cast, no need to check SDValue N = getValue(I.getOperand(0)); EVT DestVT = TLI.getValueType(I.getType()); setValue(&I, DAG.getNode(ISD::SINT_TO_FP, getCurDebugLoc(), DestVT, N)); } void SelectionDAGBuilder::visitPtrToInt(const User &I) { // What to do depends on the size of the integer and the size of the pointer. // We can either truncate, zero extend, or no-op, accordingly. SDValue N = getValue(I.getOperand(0)); EVT DestVT = TLI.getValueType(I.getType()); setValue(&I, DAG.getZExtOrTrunc(N, getCurDebugLoc(), DestVT)); } void SelectionDAGBuilder::visitIntToPtr(const User &I) { // What to do depends on the size of the integer and the size of the pointer. // We can either truncate, zero extend, or no-op, accordingly. SDValue N = getValue(I.getOperand(0)); EVT DestVT = TLI.getValueType(I.getType()); setValue(&I, DAG.getZExtOrTrunc(N, getCurDebugLoc(), DestVT)); } void SelectionDAGBuilder::visitBitCast(const User &I) { SDValue N = getValue(I.getOperand(0)); EVT DestVT = TLI.getValueType(I.getType()); // BitCast assures us that source and destination are the same size so this is // either a BITCAST or a no-op. if (DestVT != N.getValueType()) setValue(&I, DAG.getNode(ISD::BITCAST, getCurDebugLoc(), DestVT, N)); // convert types. else setValue(&I, N); // noop cast. } void SelectionDAGBuilder::visitInsertElement(const User &I) { SDValue InVec = getValue(I.getOperand(0)); SDValue InVal = getValue(I.getOperand(1)); SDValue InIdx = DAG.getNode(ISD::ZERO_EXTEND, getCurDebugLoc(), TLI.getPointerTy(), getValue(I.getOperand(2))); setValue(&I, DAG.getNode(ISD::INSERT_VECTOR_ELT, getCurDebugLoc(), TLI.getValueType(I.getType()), InVec, InVal, InIdx)); } void SelectionDAGBuilder::visitExtractElement(const User &I) { SDValue InVec = getValue(I.getOperand(0)); SDValue InIdx = DAG.getNode(ISD::ZERO_EXTEND, getCurDebugLoc(), TLI.getPointerTy(), getValue(I.getOperand(1))); setValue(&I, DAG.getNode(ISD::EXTRACT_VECTOR_ELT, getCurDebugLoc(), TLI.getValueType(I.getType()), InVec, InIdx)); } // Utility for visitShuffleVector - Returns true if the mask is mask starting // from SIndx and increasing to the element length (undefs are allowed). static bool SequentialMask(SmallVectorImpl &Mask, unsigned SIndx) { unsigned MaskNumElts = Mask.size(); for (unsigned i = 0; i != MaskNumElts; ++i) if ((Mask[i] >= 0) && (Mask[i] != (int)(i + SIndx))) return false; return true; } void SelectionDAGBuilder::visitShuffleVector(const User &I) { SmallVector Mask; SDValue Src1 = getValue(I.getOperand(0)); SDValue Src2 = getValue(I.getOperand(1)); // Convert the ConstantVector mask operand into an array of ints, with -1 // representing undef values. SmallVector MaskElts; cast(I.getOperand(2))->getVectorElements(MaskElts); unsigned MaskNumElts = MaskElts.size(); for (unsigned i = 0; i != MaskNumElts; ++i) { if (isa(MaskElts[i])) Mask.push_back(-1); else Mask.push_back(cast(MaskElts[i])->getSExtValue()); } EVT VT = TLI.getValueType(I.getType()); EVT SrcVT = Src1.getValueType(); unsigned SrcNumElts = SrcVT.getVectorNumElements(); if (SrcNumElts == MaskNumElts) { setValue(&I, DAG.getVectorShuffle(VT, getCurDebugLoc(), Src1, Src2, &Mask[0])); return; } // Normalize the shuffle vector since mask and vector length don't match. if (SrcNumElts < MaskNumElts && MaskNumElts % SrcNumElts == 0) { // Mask is longer than the source vectors and is a multiple of the source // vectors. We can use concatenate vector to make the mask and vectors // lengths match. if (SrcNumElts*2 == MaskNumElts && SequentialMask(Mask, 0)) { // The shuffle is concatenating two vectors together. setValue(&I, DAG.getNode(ISD::CONCAT_VECTORS, getCurDebugLoc(), VT, Src1, Src2)); return; } // Pad both vectors with undefs to make them the same length as the mask. unsigned NumConcat = MaskNumElts / SrcNumElts; bool Src1U = Src1.getOpcode() == ISD::UNDEF; bool Src2U = Src2.getOpcode() == ISD::UNDEF; SDValue UndefVal = DAG.getUNDEF(SrcVT); SmallVector MOps1(NumConcat, UndefVal); SmallVector MOps2(NumConcat, UndefVal); MOps1[0] = Src1; MOps2[0] = Src2; Src1 = Src1U ? DAG.getUNDEF(VT) : DAG.getNode(ISD::CONCAT_VECTORS, getCurDebugLoc(), VT, &MOps1[0], NumConcat); Src2 = Src2U ? DAG.getUNDEF(VT) : DAG.getNode(ISD::CONCAT_VECTORS, getCurDebugLoc(), VT, &MOps2[0], NumConcat); // Readjust mask for new input vector length. SmallVector MappedOps; for (unsigned i = 0; i != MaskNumElts; ++i) { int Idx = Mask[i]; if (Idx < (int)SrcNumElts) MappedOps.push_back(Idx); else MappedOps.push_back(Idx + MaskNumElts - SrcNumElts); } setValue(&I, DAG.getVectorShuffle(VT, getCurDebugLoc(), Src1, Src2, &MappedOps[0])); return; } if (SrcNumElts > MaskNumElts) { // Analyze the access pattern of the vector to see if we can extract // two subvectors and do the shuffle. The analysis is done by calculating // the range of elements the mask access on both vectors. int MinRange[2] = { static_cast(SrcNumElts+1), static_cast(SrcNumElts+1)}; int MaxRange[2] = {-1, -1}; for (unsigned i = 0; i != MaskNumElts; ++i) { int Idx = Mask[i]; int Input = 0; if (Idx < 0) continue; if (Idx >= (int)SrcNumElts) { Input = 1; Idx -= SrcNumElts; } if (Idx > MaxRange[Input]) MaxRange[Input] = Idx; if (Idx < MinRange[Input]) MinRange[Input] = Idx; } // Check if the access is smaller than the vector size and can we find // a reasonable extract index. int RangeUse[2] = { 2, 2 }; // 0 = Unused, 1 = Extract, 2 = Can not // Extract. int StartIdx[2]; // StartIdx to extract from for (int Input=0; Input < 2; ++Input) { if (MinRange[Input] == (int)(SrcNumElts+1) && MaxRange[Input] == -1) { RangeUse[Input] = 0; // Unused StartIdx[Input] = 0; } else if (MaxRange[Input] - MinRange[Input] < (int)MaskNumElts) { // Fits within range but we should see if we can find a good // start index that is a multiple of the mask length. if (MaxRange[Input] < (int)MaskNumElts) { RangeUse[Input] = 1; // Extract from beginning of the vector StartIdx[Input] = 0; } else { StartIdx[Input] = (MinRange[Input]/MaskNumElts)*MaskNumElts; if (MaxRange[Input] - StartIdx[Input] < (int)MaskNumElts && StartIdx[Input] + MaskNumElts <= SrcNumElts) RangeUse[Input] = 1; // Extract from a multiple of the mask length. } } } if (RangeUse[0] == 0 && RangeUse[1] == 0) { setValue(&I, DAG.getUNDEF(VT)); // Vectors are not used. return; } else if (RangeUse[0] < 2 && RangeUse[1] < 2) { // Extract appropriate subvector and generate a vector shuffle for (int Input=0; Input < 2; ++Input) { SDValue &Src = Input == 0 ? Src1 : Src2; if (RangeUse[Input] == 0) Src = DAG.getUNDEF(VT); else Src = DAG.getNode(ISD::EXTRACT_SUBVECTOR, getCurDebugLoc(), VT, Src, DAG.getIntPtrConstant(StartIdx[Input])); } // Calculate new mask. SmallVector MappedOps; for (unsigned i = 0; i != MaskNumElts; ++i) { int Idx = Mask[i]; if (Idx < 0) MappedOps.push_back(Idx); else if (Idx < (int)SrcNumElts) MappedOps.push_back(Idx - StartIdx[0]); else MappedOps.push_back(Idx - SrcNumElts - StartIdx[1] + MaskNumElts); } setValue(&I, DAG.getVectorShuffle(VT, getCurDebugLoc(), Src1, Src2, &MappedOps[0])); return; } } // We can't use either concat vectors or extract subvectors so fall back to // replacing the shuffle with extract and build vector. // to insert and build vector. EVT EltVT = VT.getVectorElementType(); EVT PtrVT = TLI.getPointerTy(); SmallVector Ops; for (unsigned i = 0; i != MaskNumElts; ++i) { if (Mask[i] < 0) { Ops.push_back(DAG.getUNDEF(EltVT)); } else { int Idx = Mask[i]; SDValue Res; if (Idx < (int)SrcNumElts) Res = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, getCurDebugLoc(), EltVT, Src1, DAG.getConstant(Idx, PtrVT)); else Res = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, getCurDebugLoc(), EltVT, Src2, DAG.getConstant(Idx - SrcNumElts, PtrVT)); Ops.push_back(Res); } } setValue(&I, DAG.getNode(ISD::BUILD_VECTOR, getCurDebugLoc(), VT, &Ops[0], Ops.size())); } void SelectionDAGBuilder::visitInsertValue(const InsertValueInst &I) { const Value *Op0 = I.getOperand(0); const Value *Op1 = I.getOperand(1); Type *AggTy = I.getType(); Type *ValTy = Op1->getType(); bool IntoUndef = isa(Op0); bool FromUndef = isa(Op1); unsigned LinearIndex = ComputeLinearIndex(AggTy, I.getIndices()); SmallVector AggValueVTs; ComputeValueVTs(TLI, AggTy, AggValueVTs); SmallVector ValValueVTs; ComputeValueVTs(TLI, ValTy, ValValueVTs); unsigned NumAggValues = AggValueVTs.size(); unsigned NumValValues = ValValueVTs.size(); SmallVector Values(NumAggValues); SDValue Agg = getValue(Op0); unsigned i = 0; // Copy the beginning value(s) from the original aggregate. for (; i != LinearIndex; ++i) Values[i] = IntoUndef ? DAG.getUNDEF(AggValueVTs[i]) : SDValue(Agg.getNode(), Agg.getResNo() + i); // Copy values from the inserted value(s). if (NumValValues) { SDValue Val = getValue(Op1); for (; i != LinearIndex + NumValValues; ++i) Values[i] = FromUndef ? DAG.getUNDEF(AggValueVTs[i]) : SDValue(Val.getNode(), Val.getResNo() + i - LinearIndex); } // Copy remaining value(s) from the original aggregate. for (; i != NumAggValues; ++i) Values[i] = IntoUndef ? DAG.getUNDEF(AggValueVTs[i]) : SDValue(Agg.getNode(), Agg.getResNo() + i); setValue(&I, DAG.getNode(ISD::MERGE_VALUES, getCurDebugLoc(), DAG.getVTList(&AggValueVTs[0], NumAggValues), &Values[0], NumAggValues)); } void SelectionDAGBuilder::visitExtractValue(const ExtractValueInst &I) { const Value *Op0 = I.getOperand(0); Type *AggTy = Op0->getType(); Type *ValTy = I.getType(); bool OutOfUndef = isa(Op0); unsigned LinearIndex = ComputeLinearIndex(AggTy, I.getIndices()); SmallVector ValValueVTs; ComputeValueVTs(TLI, ValTy, ValValueVTs); unsigned NumValValues = ValValueVTs.size(); // Ignore a extractvalue that produces an empty object if (!NumValValues) { setValue(&I, DAG.getUNDEF(MVT(MVT::Other))); return; } SmallVector Values(NumValValues); SDValue Agg = getValue(Op0); // Copy out the selected value(s). for (unsigned i = LinearIndex; i != LinearIndex + NumValValues; ++i) Values[i - LinearIndex] = OutOfUndef ? DAG.getUNDEF(Agg.getNode()->getValueType(Agg.getResNo() + i)) : SDValue(Agg.getNode(), Agg.getResNo() + i); setValue(&I, DAG.getNode(ISD::MERGE_VALUES, getCurDebugLoc(), DAG.getVTList(&ValValueVTs[0], NumValValues), &Values[0], NumValValues)); } void SelectionDAGBuilder::visitGetElementPtr(const User &I) { SDValue N = getValue(I.getOperand(0)); Type *Ty = I.getOperand(0)->getType(); for (GetElementPtrInst::const_op_iterator OI = I.op_begin()+1, E = I.op_end(); OI != E; ++OI) { const Value *Idx = *OI; if (StructType *StTy = dyn_cast(Ty)) { unsigned Field = cast(Idx)->getZExtValue(); if (Field) { // N = N + Offset uint64_t Offset = TD->getStructLayout(StTy)->getElementOffset(Field); N = DAG.getNode(ISD::ADD, getCurDebugLoc(), N.getValueType(), N, DAG.getIntPtrConstant(Offset)); } Ty = StTy->getElementType(Field); } else { Ty = cast(Ty)->getElementType(); // If this is a constant subscript, handle it quickly. if (const ConstantInt *CI = dyn_cast(Idx)) { if (CI->isZero()) continue; uint64_t Offs = TD->getTypeAllocSize(Ty)*cast(CI)->getSExtValue(); SDValue OffsVal; EVT PTy = TLI.getPointerTy(); unsigned PtrBits = PTy.getSizeInBits(); if (PtrBits < 64) OffsVal = DAG.getNode(ISD::TRUNCATE, getCurDebugLoc(), TLI.getPointerTy(), DAG.getConstant(Offs, MVT::i64)); else OffsVal = DAG.getIntPtrConstant(Offs); N = DAG.getNode(ISD::ADD, getCurDebugLoc(), N.getValueType(), N, OffsVal); continue; } // N = N + Idx * ElementSize; APInt ElementSize = APInt(TLI.getPointerTy().getSizeInBits(), TD->getTypeAllocSize(Ty)); SDValue IdxN = getValue(Idx); // If the index is smaller or larger than intptr_t, truncate or extend // it. IdxN = DAG.getSExtOrTrunc(IdxN, getCurDebugLoc(), N.getValueType()); // If this is a multiply by a power of two, turn it into a shl // immediately. This is a very common case. if (ElementSize != 1) { if (ElementSize.isPowerOf2()) { unsigned Amt = ElementSize.logBase2(); IdxN = DAG.getNode(ISD::SHL, getCurDebugLoc(), N.getValueType(), IdxN, DAG.getConstant(Amt, TLI.getPointerTy())); } else { SDValue Scale = DAG.getConstant(ElementSize, TLI.getPointerTy()); IdxN = DAG.getNode(ISD::MUL, getCurDebugLoc(), N.getValueType(), IdxN, Scale); } } N = DAG.getNode(ISD::ADD, getCurDebugLoc(), N.getValueType(), N, IdxN); } } setValue(&I, N); } void SelectionDAGBuilder::visitAlloca(const AllocaInst &I) { // If this is a fixed sized alloca in the entry block of the function, // allocate it statically on the stack. if (FuncInfo.StaticAllocaMap.count(&I)) return; // getValue will auto-populate this. Type *Ty = I.getAllocatedType(); uint64_t TySize = TLI.getTargetData()->getTypeAllocSize(Ty); unsigned Align = std::max((unsigned)TLI.getTargetData()->getPrefTypeAlignment(Ty), I.getAlignment()); SDValue AllocSize = getValue(I.getArraySize()); EVT IntPtr = TLI.getPointerTy(); if (AllocSize.getValueType() != IntPtr) AllocSize = DAG.getZExtOrTrunc(AllocSize, getCurDebugLoc(), IntPtr); AllocSize = DAG.getNode(ISD::MUL, getCurDebugLoc(), IntPtr, AllocSize, DAG.getConstant(TySize, IntPtr)); // Handle alignment. If the requested alignment is less than or equal to // the stack alignment, ignore it. If the size is greater than or equal to // the stack alignment, we note this in the DYNAMIC_STACKALLOC node. unsigned StackAlign = TM.getFrameLowering()->getStackAlignment(); if (Align <= StackAlign) Align = 0; // Round the size of the allocation up to the stack alignment size // by add SA-1 to the size. AllocSize = DAG.getNode(ISD::ADD, getCurDebugLoc(), AllocSize.getValueType(), AllocSize, DAG.getIntPtrConstant(StackAlign-1)); // Mask out the low bits for alignment purposes. AllocSize = DAG.getNode(ISD::AND, getCurDebugLoc(), AllocSize.getValueType(), AllocSize, DAG.getIntPtrConstant(~(uint64_t)(StackAlign-1))); SDValue Ops[] = { getRoot(), AllocSize, DAG.getIntPtrConstant(Align) }; SDVTList VTs = DAG.getVTList(AllocSize.getValueType(), MVT::Other); SDValue DSA = DAG.getNode(ISD::DYNAMIC_STACKALLOC, getCurDebugLoc(), VTs, Ops, 3); setValue(&I, DSA); DAG.setRoot(DSA.getValue(1)); // Inform the Frame Information that we have just allocated a variable-sized // object. FuncInfo.MF->getFrameInfo()->CreateVariableSizedObject(Align ? Align : 1); } void SelectionDAGBuilder::visitLoad(const LoadInst &I) { if (I.isAtomic()) return visitAtomicLoad(I); const Value *SV = I.getOperand(0); SDValue Ptr = getValue(SV); Type *Ty = I.getType(); bool isVolatile = I.isVolatile(); bool isNonTemporal = I.getMetadata("nontemporal") != 0; unsigned Alignment = I.getAlignment(); const MDNode *TBAAInfo = I.getMetadata(LLVMContext::MD_tbaa); SmallVector ValueVTs; SmallVector Offsets; ComputeValueVTs(TLI, Ty, ValueVTs, &Offsets); unsigned NumValues = ValueVTs.size(); if (NumValues == 0) return; SDValue Root; bool ConstantMemory = false; if (I.isVolatile() || NumValues > MaxParallelChains) // Serialize volatile loads with other side effects. Root = getRoot(); else if (AA->pointsToConstantMemory( AliasAnalysis::Location(SV, AA->getTypeStoreSize(Ty), TBAAInfo))) { // Do not serialize (non-volatile) loads of constant memory with anything. Root = DAG.getEntryNode(); ConstantMemory = true; } else { // Do not serialize non-volatile loads against each other. Root = DAG.getRoot(); } SmallVector Values(NumValues); SmallVector Chains(std::min(unsigned(MaxParallelChains), NumValues)); EVT PtrVT = Ptr.getValueType(); unsigned ChainI = 0; for (unsigned i = 0; i != NumValues; ++i, ++ChainI) { // Serializing loads here may result in excessive register pressure, and // TokenFactor places arbitrary choke points on the scheduler. SD scheduling // could recover a bit by hoisting nodes upward in the chain by recognizing // they are side-effect free or do not alias. The optimizer should really // avoid this case by converting large object/array copies to llvm.memcpy // (MaxParallelChains should always remain as failsafe). if (ChainI == MaxParallelChains) { assert(PendingLoads.empty() && "PendingLoads must be serialized first"); SDValue Chain = DAG.getNode(ISD::TokenFactor, getCurDebugLoc(), MVT::Other, &Chains[0], ChainI); Root = Chain; ChainI = 0; } SDValue A = DAG.getNode(ISD::ADD, getCurDebugLoc(), PtrVT, Ptr, DAG.getConstant(Offsets[i], PtrVT)); SDValue L = DAG.getLoad(ValueVTs[i], getCurDebugLoc(), Root, A, MachinePointerInfo(SV, Offsets[i]), isVolatile, isNonTemporal, Alignment, TBAAInfo); Values[i] = L; Chains[ChainI] = L.getValue(1); } if (!ConstantMemory) { SDValue Chain = DAG.getNode(ISD::TokenFactor, getCurDebugLoc(), MVT::Other, &Chains[0], ChainI); if (isVolatile) DAG.setRoot(Chain); else PendingLoads.push_back(Chain); } setValue(&I, DAG.getNode(ISD::MERGE_VALUES, getCurDebugLoc(), DAG.getVTList(&ValueVTs[0], NumValues), &Values[0], NumValues)); } void SelectionDAGBuilder::visitStore(const StoreInst &I) { if (I.isAtomic()) return visitAtomicStore(I); const Value *SrcV = I.getOperand(0); const Value *PtrV = I.getOperand(1); SmallVector ValueVTs; SmallVector Offsets; ComputeValueVTs(TLI, SrcV->getType(), ValueVTs, &Offsets); unsigned NumValues = ValueVTs.size(); if (NumValues == 0) return; // Get the lowered operands. Note that we do this after // checking if NumResults is zero, because with zero results // the operands won't have values in the map. SDValue Src = getValue(SrcV); SDValue Ptr = getValue(PtrV); SDValue Root = getRoot(); SmallVector Chains(std::min(unsigned(MaxParallelChains), NumValues)); EVT PtrVT = Ptr.getValueType(); bool isVolatile = I.isVolatile(); bool isNonTemporal = I.getMetadata("nontemporal") != 0; unsigned Alignment = I.getAlignment(); const MDNode *TBAAInfo = I.getMetadata(LLVMContext::MD_tbaa); unsigned ChainI = 0; for (unsigned i = 0; i != NumValues; ++i, ++ChainI) { // See visitLoad comments. if (ChainI == MaxParallelChains) { SDValue Chain = DAG.getNode(ISD::TokenFactor, getCurDebugLoc(), MVT::Other, &Chains[0], ChainI); Root = Chain; ChainI = 0; } SDValue Add = DAG.getNode(ISD::ADD, getCurDebugLoc(), PtrVT, Ptr, DAG.getConstant(Offsets[i], PtrVT)); SDValue St = DAG.getStore(Root, getCurDebugLoc(), SDValue(Src.getNode(), Src.getResNo() + i), Add, MachinePointerInfo(PtrV, Offsets[i]), isVolatile, isNonTemporal, Alignment, TBAAInfo); Chains[ChainI] = St; } SDValue StoreNode = DAG.getNode(ISD::TokenFactor, getCurDebugLoc(), MVT::Other, &Chains[0], ChainI); ++SDNodeOrder; AssignOrderingToNode(StoreNode.getNode()); DAG.setRoot(StoreNode); } static SDValue InsertFenceForAtomic(SDValue Chain, AtomicOrdering Order, SynchronizationScope Scope, bool Before, DebugLoc dl, SelectionDAG &DAG, const TargetLowering &TLI) { // Fence, if necessary if (Before) { if (Order == AcquireRelease || Order == SequentiallyConsistent) Order = Release; else if (Order == Acquire || Order == Monotonic) return Chain; } else { if (Order == AcquireRelease) Order = Acquire; else if (Order == Release || Order == Monotonic) return Chain; } SDValue Ops[3]; Ops[0] = Chain; Ops[1] = DAG.getConstant(Order, TLI.getPointerTy()); Ops[2] = DAG.getConstant(Scope, TLI.getPointerTy()); return DAG.getNode(ISD::ATOMIC_FENCE, dl, MVT::Other, Ops, 3); } void SelectionDAGBuilder::visitAtomicCmpXchg(const AtomicCmpXchgInst &I) { DebugLoc dl = getCurDebugLoc(); AtomicOrdering Order = I.getOrdering(); SynchronizationScope Scope = I.getSynchScope(); SDValue InChain = getRoot(); if (TLI.getInsertFencesForAtomic()) InChain = InsertFenceForAtomic(InChain, Order, Scope, true, dl, DAG, TLI); SDValue L = DAG.getAtomic(ISD::ATOMIC_CMP_SWAP, dl, getValue(I.getCompareOperand()).getValueType().getSimpleVT(), InChain, getValue(I.getPointerOperand()), getValue(I.getCompareOperand()), getValue(I.getNewValOperand()), MachinePointerInfo(I.getPointerOperand()), 0 /* Alignment */, TLI.getInsertFencesForAtomic() ? Monotonic : Order, Scope); SDValue OutChain = L.getValue(1); if (TLI.getInsertFencesForAtomic()) OutChain = InsertFenceForAtomic(OutChain, Order, Scope, false, dl, DAG, TLI); setValue(&I, L); DAG.setRoot(OutChain); } void SelectionDAGBuilder::visitAtomicRMW(const AtomicRMWInst &I) { DebugLoc dl = getCurDebugLoc(); ISD::NodeType NT; switch (I.getOperation()) { default: llvm_unreachable("Unknown atomicrmw operation"); return; case AtomicRMWInst::Xchg: NT = ISD::ATOMIC_SWAP; break; case AtomicRMWInst::Add: NT = ISD::ATOMIC_LOAD_ADD; break; case AtomicRMWInst::Sub: NT = ISD::ATOMIC_LOAD_SUB; break; case AtomicRMWInst::And: NT = ISD::ATOMIC_LOAD_AND; break; case AtomicRMWInst::Nand: NT = ISD::ATOMIC_LOAD_NAND; break; case AtomicRMWInst::Or: NT = ISD::ATOMIC_LOAD_OR; break; case AtomicRMWInst::Xor: NT = ISD::ATOMIC_LOAD_XOR; break; case AtomicRMWInst::Max: NT = ISD::ATOMIC_LOAD_MAX; break; case AtomicRMWInst::Min: NT = ISD::ATOMIC_LOAD_MIN; break; case AtomicRMWInst::UMax: NT = ISD::ATOMIC_LOAD_UMAX; break; case AtomicRMWInst::UMin: NT = ISD::ATOMIC_LOAD_UMIN; break; } AtomicOrdering Order = I.getOrdering(); SynchronizationScope Scope = I.getSynchScope(); SDValue InChain = getRoot(); if (TLI.getInsertFencesForAtomic()) InChain = InsertFenceForAtomic(InChain, Order, Scope, true, dl, DAG, TLI); SDValue L = DAG.getAtomic(NT, dl, getValue(I.getValOperand()).getValueType().getSimpleVT(), InChain, getValue(I.getPointerOperand()), getValue(I.getValOperand()), I.getPointerOperand(), 0 /* Alignment */, TLI.getInsertFencesForAtomic() ? Monotonic : Order, Scope); SDValue OutChain = L.getValue(1); if (TLI.getInsertFencesForAtomic()) OutChain = InsertFenceForAtomic(OutChain, Order, Scope, false, dl, DAG, TLI); setValue(&I, L); DAG.setRoot(OutChain); } void SelectionDAGBuilder::visitFence(const FenceInst &I) { DebugLoc dl = getCurDebugLoc(); SDValue Ops[3]; Ops[0] = getRoot(); Ops[1] = DAG.getConstant(I.getOrdering(), TLI.getPointerTy()); Ops[2] = DAG.getConstant(I.getSynchScope(), TLI.getPointerTy()); DAG.setRoot(DAG.getNode(ISD::ATOMIC_FENCE, dl, MVT::Other, Ops, 3)); } void SelectionDAGBuilder::visitAtomicLoad(const LoadInst &I) { DebugLoc dl = getCurDebugLoc(); AtomicOrdering Order = I.getOrdering(); SynchronizationScope Scope = I.getSynchScope(); SDValue InChain = getRoot(); EVT VT = EVT::getEVT(I.getType()); if (I.getAlignment() * 8 < VT.getSizeInBits()) report_fatal_error("Cannot generate unaligned atomic load"); SDValue L = DAG.getAtomic(ISD::ATOMIC_LOAD, dl, VT, VT, InChain, getValue(I.getPointerOperand()), I.getPointerOperand(), I.getAlignment(), TLI.getInsertFencesForAtomic() ? Monotonic : Order, Scope); SDValue OutChain = L.getValue(1); if (TLI.getInsertFencesForAtomic()) OutChain = InsertFenceForAtomic(OutChain, Order, Scope, false, dl, DAG, TLI); setValue(&I, L); DAG.setRoot(OutChain); } void SelectionDAGBuilder::visitAtomicStore(const StoreInst &I) { DebugLoc dl = getCurDebugLoc(); AtomicOrdering Order = I.getOrdering(); SynchronizationScope Scope = I.getSynchScope(); SDValue InChain = getRoot(); EVT VT = EVT::getEVT(I.getValueOperand()->getType()); if (I.getAlignment() * 8 < VT.getSizeInBits()) report_fatal_error("Cannot generate unaligned atomic store"); if (TLI.getInsertFencesForAtomic()) InChain = InsertFenceForAtomic(InChain, Order, Scope, true, dl, DAG, TLI); SDValue OutChain = DAG.getAtomic(ISD::ATOMIC_STORE, dl, VT, InChain, getValue(I.getPointerOperand()), getValue(I.getValueOperand()), I.getPointerOperand(), I.getAlignment(), TLI.getInsertFencesForAtomic() ? Monotonic : Order, Scope); if (TLI.getInsertFencesForAtomic()) OutChain = InsertFenceForAtomic(OutChain, Order, Scope, false, dl, DAG, TLI); DAG.setRoot(OutChain); } /// visitTargetIntrinsic - Lower a call of a target intrinsic to an INTRINSIC /// node. void SelectionDAGBuilder::visitTargetIntrinsic(const CallInst &I, unsigned Intrinsic) { bool HasChain = !I.doesNotAccessMemory(); bool OnlyLoad = HasChain && I.onlyReadsMemory(); // Build the operand list. SmallVector Ops; if (HasChain) { // If this intrinsic has side-effects, chainify it. if (OnlyLoad) { // We don't need to serialize loads against other loads. Ops.push_back(DAG.getRoot()); } else { Ops.push_back(getRoot()); } } // Info is set by getTgtMemInstrinsic TargetLowering::IntrinsicInfo Info; bool IsTgtIntrinsic = TLI.getTgtMemIntrinsic(Info, I, Intrinsic); // Add the intrinsic ID as an integer operand if it's not a target intrinsic. if (!IsTgtIntrinsic || Info.opc == ISD::INTRINSIC_VOID || Info.opc == ISD::INTRINSIC_W_CHAIN) Ops.push_back(DAG.getConstant(Intrinsic, TLI.getPointerTy())); // Add all operands of the call to the operand list. for (unsigned i = 0, e = I.getNumArgOperands(); i != e; ++i) { SDValue Op = getValue(I.getArgOperand(i)); assert(TLI.isTypeLegal(Op.getValueType()) && "Intrinsic uses a non-legal type?"); Ops.push_back(Op); } SmallVector ValueVTs; ComputeValueVTs(TLI, I.getType(), ValueVTs); #ifndef NDEBUG for (unsigned Val = 0, E = ValueVTs.size(); Val != E; ++Val) { assert(TLI.isTypeLegal(ValueVTs[Val]) && "Intrinsic uses a non-legal type?"); } #endif // NDEBUG if (HasChain) ValueVTs.push_back(MVT::Other); SDVTList VTs = DAG.getVTList(ValueVTs.data(), ValueVTs.size()); // Create the node. SDValue Result; if (IsTgtIntrinsic) { // This is target intrinsic that touches memory Result = DAG.getMemIntrinsicNode(Info.opc, getCurDebugLoc(), VTs, &Ops[0], Ops.size(), Info.memVT, MachinePointerInfo(Info.ptrVal, Info.offset), Info.align, Info.vol, Info.readMem, Info.writeMem); } else if (!HasChain) { Result = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, getCurDebugLoc(), VTs, &Ops[0], Ops.size()); } else if (!I.getType()->isVoidTy()) { Result = DAG.getNode(ISD::INTRINSIC_W_CHAIN, getCurDebugLoc(), VTs, &Ops[0], Ops.size()); } else { Result = DAG.getNode(ISD::INTRINSIC_VOID, getCurDebugLoc(), VTs, &Ops[0], Ops.size()); } if (HasChain) { SDValue Chain = Result.getValue(Result.getNode()->getNumValues()-1); if (OnlyLoad) PendingLoads.push_back(Chain); else DAG.setRoot(Chain); } if (!I.getType()->isVoidTy()) { if (VectorType *PTy = dyn_cast(I.getType())) { EVT VT = TLI.getValueType(PTy); Result = DAG.getNode(ISD::BITCAST, getCurDebugLoc(), VT, Result); } setValue(&I, Result); } } /// GetSignificand - Get the significand and build it into a floating-point /// number with exponent of 1: /// /// Op = (Op & 0x007fffff) | 0x3f800000; /// /// where Op is the hexidecimal representation of floating point value. static SDValue GetSignificand(SelectionDAG &DAG, SDValue Op, DebugLoc dl) { SDValue t1 = DAG.getNode(ISD::AND, dl, MVT::i32, Op, DAG.getConstant(0x007fffff, MVT::i32)); SDValue t2 = DAG.getNode(ISD::OR, dl, MVT::i32, t1, DAG.getConstant(0x3f800000, MVT::i32)); return DAG.getNode(ISD::BITCAST, dl, MVT::f32, t2); } /// GetExponent - Get the exponent: /// /// (float)(int)(((Op & 0x7f800000) >> 23) - 127); /// /// where Op is the hexidecimal representation of floating point value. static SDValue GetExponent(SelectionDAG &DAG, SDValue Op, const TargetLowering &TLI, DebugLoc dl) { SDValue t0 = DAG.getNode(ISD::AND, dl, MVT::i32, Op, DAG.getConstant(0x7f800000, MVT::i32)); SDValue t1 = DAG.getNode(ISD::SRL, dl, MVT::i32, t0, DAG.getConstant(23, TLI.getPointerTy())); SDValue t2 = DAG.getNode(ISD::SUB, dl, MVT::i32, t1, DAG.getConstant(127, MVT::i32)); return DAG.getNode(ISD::SINT_TO_FP, dl, MVT::f32, t2); } /// getF32Constant - Get 32-bit floating point constant. static SDValue getF32Constant(SelectionDAG &DAG, unsigned Flt) { return DAG.getConstantFP(APFloat(APInt(32, Flt)), MVT::f32); } // implVisitAluOverflow - Lower arithmetic overflow instrinsics. const char * SelectionDAGBuilder::implVisitAluOverflow(const CallInst &I, ISD::NodeType Op) { SDValue Op1 = getValue(I.getArgOperand(0)); SDValue Op2 = getValue(I.getArgOperand(1)); SDVTList VTs = DAG.getVTList(Op1.getValueType(), MVT::i1); setValue(&I, DAG.getNode(Op, getCurDebugLoc(), VTs, Op1, Op2)); return 0; } /// visitExp - Lower an exp intrinsic. Handles the special sequences for /// limited-precision mode. void SelectionDAGBuilder::visitExp(const CallInst &I) { SDValue result; DebugLoc dl = getCurDebugLoc(); if (getValue(I.getArgOperand(0)).getValueType() == MVT::f32 && LimitFloatPrecision > 0 && LimitFloatPrecision <= 18) { SDValue Op = getValue(I.getArgOperand(0)); // Put the exponent in the right bit position for later addition to the // final result: // // #define LOG2OFe 1.4426950f // IntegerPartOfX = ((int32_t)(X * LOG2OFe)); SDValue t0 = DAG.getNode(ISD::FMUL, dl, MVT::f32, Op, getF32Constant(DAG, 0x3fb8aa3b)); SDValue IntegerPartOfX = DAG.getNode(ISD::FP_TO_SINT, dl, MVT::i32, t0); // FractionalPartOfX = (X * LOG2OFe) - (float)IntegerPartOfX; SDValue t1 = DAG.getNode(ISD::SINT_TO_FP, dl, MVT::f32, IntegerPartOfX); SDValue X = DAG.getNode(ISD::FSUB, dl, MVT::f32, t0, t1); // IntegerPartOfX <<= 23; IntegerPartOfX = DAG.getNode(ISD::SHL, dl, MVT::i32, IntegerPartOfX, DAG.getConstant(23, TLI.getPointerTy())); if (LimitFloatPrecision <= 6) { // For floating-point precision of 6: // // TwoToFractionalPartOfX = // 0.997535578f + // (0.735607626f + 0.252464424f * x) * x; // // error 0.0144103317, which is 6 bits SDValue t2 = DAG.getNode(ISD::FMUL, dl, MVT::f32, X, getF32Constant(DAG, 0x3e814304)); SDValue t3 = DAG.getNode(ISD::FADD, dl, MVT::f32, t2, getF32Constant(DAG, 0x3f3c50c8)); SDValue t4 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t3, X); SDValue t5 = DAG.getNode(ISD::FADD, dl, MVT::f32, t4, getF32Constant(DAG, 0x3f7f5e7e)); SDValue TwoToFracPartOfX = DAG.getNode(ISD::BITCAST, dl,MVT::i32, t5); // Add the exponent into the result in integer domain. SDValue t6 = DAG.getNode(ISD::ADD, dl, MVT::i32, TwoToFracPartOfX, IntegerPartOfX); result = DAG.getNode(ISD::BITCAST, dl, MVT::f32, t6); } else if (LimitFloatPrecision > 6 && LimitFloatPrecision <= 12) { // For floating-point precision of 12: // // TwoToFractionalPartOfX = // 0.999892986f + // (0.696457318f + // (0.224338339f + 0.792043434e-1f * x) * x) * x; // // 0.000107046256 error, which is 13 to 14 bits SDValue t2 = DAG.getNode(ISD::FMUL, dl, MVT::f32, X, getF32Constant(DAG, 0x3da235e3)); SDValue t3 = DAG.getNode(ISD::FADD, dl, MVT::f32, t2, getF32Constant(DAG, 0x3e65b8f3)); SDValue t4 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t3, X); SDValue t5 = DAG.getNode(ISD::FADD, dl, MVT::f32, t4, getF32Constant(DAG, 0x3f324b07)); SDValue t6 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t5, X); SDValue t7 = DAG.getNode(ISD::FADD, dl, MVT::f32, t6, getF32Constant(DAG, 0x3f7ff8fd)); SDValue TwoToFracPartOfX = DAG.getNode(ISD::BITCAST, dl,MVT::i32, t7); // Add the exponent into the result in integer domain. SDValue t8 = DAG.getNode(ISD::ADD, dl, MVT::i32, TwoToFracPartOfX, IntegerPartOfX); result = DAG.getNode(ISD::BITCAST, dl, MVT::f32, t8); } else { // LimitFloatPrecision > 12 && LimitFloatPrecision <= 18 // For floating-point precision of 18: // // TwoToFractionalPartOfX = // 0.999999982f + // (0.693148872f + // (0.240227044f + // (0.554906021e-1f + // (0.961591928e-2f + // (0.136028312e-2f + 0.157059148e-3f *x)*x)*x)*x)*x)*x; // // error 2.47208000*10^(-7), which is better than 18 bits SDValue t2 = DAG.getNode(ISD::FMUL, dl, MVT::f32, X, getF32Constant(DAG, 0x3924b03e)); SDValue t3 = DAG.getNode(ISD::FADD, dl, MVT::f32, t2, getF32Constant(DAG, 0x3ab24b87)); SDValue t4 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t3, X); SDValue t5 = DAG.getNode(ISD::FADD, dl, MVT::f32, t4, getF32Constant(DAG, 0x3c1d8c17)); SDValue t6 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t5, X); SDValue t7 = DAG.getNode(ISD::FADD, dl, MVT::f32, t6, getF32Constant(DAG, 0x3d634a1d)); SDValue t8 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t7, X); SDValue t9 = DAG.getNode(ISD::FADD, dl, MVT::f32, t8, getF32Constant(DAG, 0x3e75fe14)); SDValue t10 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t9, X); SDValue t11 = DAG.getNode(ISD::FADD, dl, MVT::f32, t10, getF32Constant(DAG, 0x3f317234)); SDValue t12 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t11, X); SDValue t13 = DAG.getNode(ISD::FADD, dl, MVT::f32, t12, getF32Constant(DAG, 0x3f800000)); SDValue TwoToFracPartOfX = DAG.getNode(ISD::BITCAST, dl, MVT::i32, t13); // Add the exponent into the result in integer domain. SDValue t14 = DAG.getNode(ISD::ADD, dl, MVT::i32, TwoToFracPartOfX, IntegerPartOfX); result = DAG.getNode(ISD::BITCAST, dl, MVT::f32, t14); } } else { // No special expansion. result = DAG.getNode(ISD::FEXP, dl, getValue(I.getArgOperand(0)).getValueType(), getValue(I.getArgOperand(0))); } setValue(&I, result); } /// visitLog - Lower a log intrinsic. Handles the special sequences for /// limited-precision mode. void SelectionDAGBuilder::visitLog(const CallInst &I) { SDValue result; DebugLoc dl = getCurDebugLoc(); if (getValue(I.getArgOperand(0)).getValueType() == MVT::f32 && LimitFloatPrecision > 0 && LimitFloatPrecision <= 18) { SDValue Op = getValue(I.getArgOperand(0)); SDValue Op1 = DAG.getNode(ISD::BITCAST, dl, MVT::i32, Op); // Scale the exponent by log(2) [0.69314718f]. SDValue Exp = GetExponent(DAG, Op1, TLI, dl); SDValue LogOfExponent = DAG.getNode(ISD::FMUL, dl, MVT::f32, Exp, getF32Constant(DAG, 0x3f317218)); // Get the significand and build it into a floating-point number with // exponent of 1. SDValue X = GetSignificand(DAG, Op1, dl); if (LimitFloatPrecision <= 6) { // For floating-point precision of 6: // // LogofMantissa = // -1.1609546f + // (1.4034025f - 0.23903021f * x) * x; // // error 0.0034276066, which is better than 8 bits SDValue t0 = DAG.getNode(ISD::FMUL, dl, MVT::f32, X, getF32Constant(DAG, 0xbe74c456)); SDValue t1 = DAG.getNode(ISD::FADD, dl, MVT::f32, t0, getF32Constant(DAG, 0x3fb3a2b1)); SDValue t2 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t1, X); SDValue LogOfMantissa = DAG.getNode(ISD::FSUB, dl, MVT::f32, t2, getF32Constant(DAG, 0x3f949a29)); result = DAG.getNode(ISD::FADD, dl, MVT::f32, LogOfExponent, LogOfMantissa); } else if (LimitFloatPrecision > 6 && LimitFloatPrecision <= 12) { // For floating-point precision of 12: // // LogOfMantissa = // -1.7417939f + // (2.8212026f + // (-1.4699568f + // (0.44717955f - 0.56570851e-1f * x) * x) * x) * x; // // error 0.000061011436, which is 14 bits SDValue t0 = DAG.getNode(ISD::FMUL, dl, MVT::f32, X, getF32Constant(DAG, 0xbd67b6d6)); SDValue t1 = DAG.getNode(ISD::FADD, dl, MVT::f32, t0, getF32Constant(DAG, 0x3ee4f4b8)); SDValue t2 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t1, X); SDValue t3 = DAG.getNode(ISD::FSUB, dl, MVT::f32, t2, getF32Constant(DAG, 0x3fbc278b)); SDValue t4 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t3, X); SDValue t5 = DAG.getNode(ISD::FADD, dl, MVT::f32, t4, getF32Constant(DAG, 0x40348e95)); SDValue t6 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t5, X); SDValue LogOfMantissa = DAG.getNode(ISD::FSUB, dl, MVT::f32, t6, getF32Constant(DAG, 0x3fdef31a)); result = DAG.getNode(ISD::FADD, dl, MVT::f32, LogOfExponent, LogOfMantissa); } else { // LimitFloatPrecision > 12 && LimitFloatPrecision <= 18 // For floating-point precision of 18: // // LogOfMantissa = // -2.1072184f + // (4.2372794f + // (-3.7029485f + // (2.2781945f + // (-0.87823314f + // (0.19073739f - 0.17809712e-1f * x) * x) * x) * x) * x)*x; // // error 0.0000023660568, which is better than 18 bits SDValue t0 = DAG.getNode(ISD::FMUL, dl, MVT::f32, X, getF32Constant(DAG, 0xbc91e5ac)); SDValue t1 = DAG.getNode(ISD::FADD, dl, MVT::f32, t0, getF32Constant(DAG, 0x3e4350aa)); SDValue t2 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t1, X); SDValue t3 = DAG.getNode(ISD::FSUB, dl, MVT::f32, t2, getF32Constant(DAG, 0x3f60d3e3)); SDValue t4 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t3, X); SDValue t5 = DAG.getNode(ISD::FADD, dl, MVT::f32, t4, getF32Constant(DAG, 0x4011cdf0)); SDValue t6 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t5, X); SDValue t7 = DAG.getNode(ISD::FSUB, dl, MVT::f32, t6, getF32Constant(DAG, 0x406cfd1c)); SDValue t8 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t7, X); SDValue t9 = DAG.getNode(ISD::FADD, dl, MVT::f32, t8, getF32Constant(DAG, 0x408797cb)); SDValue t10 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t9, X); SDValue LogOfMantissa = DAG.getNode(ISD::FSUB, dl, MVT::f32, t10, getF32Constant(DAG, 0x4006dcab)); result = DAG.getNode(ISD::FADD, dl, MVT::f32, LogOfExponent, LogOfMantissa); } } else { // No special expansion. result = DAG.getNode(ISD::FLOG, dl, getValue(I.getArgOperand(0)).getValueType(), getValue(I.getArgOperand(0))); } setValue(&I, result); } /// visitLog2 - Lower a log2 intrinsic. Handles the special sequences for /// limited-precision mode. void SelectionDAGBuilder::visitLog2(const CallInst &I) { SDValue result; DebugLoc dl = getCurDebugLoc(); if (getValue(I.getArgOperand(0)).getValueType() == MVT::f32 && LimitFloatPrecision > 0 && LimitFloatPrecision <= 18) { SDValue Op = getValue(I.getArgOperand(0)); SDValue Op1 = DAG.getNode(ISD::BITCAST, dl, MVT::i32, Op); // Get the exponent. SDValue LogOfExponent = GetExponent(DAG, Op1, TLI, dl); // Get the significand and build it into a floating-point number with // exponent of 1. SDValue X = GetSignificand(DAG, Op1, dl); // Different possible minimax approximations of significand in // floating-point for various degrees of accuracy over [1,2]. if (LimitFloatPrecision <= 6) { // For floating-point precision of 6: // // Log2ofMantissa = -1.6749035f + (2.0246817f - .34484768f * x) * x; // // error 0.0049451742, which is more than 7 bits SDValue t0 = DAG.getNode(ISD::FMUL, dl, MVT::f32, X, getF32Constant(DAG, 0xbeb08fe0)); SDValue t1 = DAG.getNode(ISD::FADD, dl, MVT::f32, t0, getF32Constant(DAG, 0x40019463)); SDValue t2 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t1, X); SDValue Log2ofMantissa = DAG.getNode(ISD::FSUB, dl, MVT::f32, t2, getF32Constant(DAG, 0x3fd6633d)); result = DAG.getNode(ISD::FADD, dl, MVT::f32, LogOfExponent, Log2ofMantissa); } else if (LimitFloatPrecision > 6 && LimitFloatPrecision <= 12) { // For floating-point precision of 12: // // Log2ofMantissa = // -2.51285454f + // (4.07009056f + // (-2.12067489f + // (.645142248f - 0.816157886e-1f * x) * x) * x) * x; // // error 0.0000876136000, which is better than 13 bits SDValue t0 = DAG.getNode(ISD::FMUL, dl, MVT::f32, X, getF32Constant(DAG, 0xbda7262e)); SDValue t1 = DAG.getNode(ISD::FADD, dl, MVT::f32, t0, getF32Constant(DAG, 0x3f25280b)); SDValue t2 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t1, X); SDValue t3 = DAG.getNode(ISD::FSUB, dl, MVT::f32, t2, getF32Constant(DAG, 0x4007b923)); SDValue t4 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t3, X); SDValue t5 = DAG.getNode(ISD::FADD, dl, MVT::f32, t4, getF32Constant(DAG, 0x40823e2f)); SDValue t6 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t5, X); SDValue Log2ofMantissa = DAG.getNode(ISD::FSUB, dl, MVT::f32, t6, getF32Constant(DAG, 0x4020d29c)); result = DAG.getNode(ISD::FADD, dl, MVT::f32, LogOfExponent, Log2ofMantissa); } else { // LimitFloatPrecision > 12 && LimitFloatPrecision <= 18 // For floating-point precision of 18: // // Log2ofMantissa = // -3.0400495f + // (6.1129976f + // (-5.3420409f + // (3.2865683f + // (-1.2669343f + // (0.27515199f - // 0.25691327e-1f * x) * x) * x) * x) * x) * x; // // error 0.0000018516, which is better than 18 bits SDValue t0 = DAG.getNode(ISD::FMUL, dl, MVT::f32, X, getF32Constant(DAG, 0xbcd2769e)); SDValue t1 = DAG.getNode(ISD::FADD, dl, MVT::f32, t0, getF32Constant(DAG, 0x3e8ce0b9)); SDValue t2 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t1, X); SDValue t3 = DAG.getNode(ISD::FSUB, dl, MVT::f32, t2, getF32Constant(DAG, 0x3fa22ae7)); SDValue t4 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t3, X); SDValue t5 = DAG.getNode(ISD::FADD, dl, MVT::f32, t4, getF32Constant(DAG, 0x40525723)); SDValue t6 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t5, X); SDValue t7 = DAG.getNode(ISD::FSUB, dl, MVT::f32, t6, getF32Constant(DAG, 0x40aaf200)); SDValue t8 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t7, X); SDValue t9 = DAG.getNode(ISD::FADD, dl, MVT::f32, t8, getF32Constant(DAG, 0x40c39dad)); SDValue t10 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t9, X); SDValue Log2ofMantissa = DAG.getNode(ISD::FSUB, dl, MVT::f32, t10, getF32Constant(DAG, 0x4042902c)); result = DAG.getNode(ISD::FADD, dl, MVT::f32, LogOfExponent, Log2ofMantissa); } } else { // No special expansion. result = DAG.getNode(ISD::FLOG2, dl, getValue(I.getArgOperand(0)).getValueType(), getValue(I.getArgOperand(0))); } setValue(&I, result); } /// visitLog10 - Lower a log10 intrinsic. Handles the special sequences for /// limited-precision mode. void SelectionDAGBuilder::visitLog10(const CallInst &I) { SDValue result; DebugLoc dl = getCurDebugLoc(); if (getValue(I.getArgOperand(0)).getValueType() == MVT::f32 && LimitFloatPrecision > 0 && LimitFloatPrecision <= 18) { SDValue Op = getValue(I.getArgOperand(0)); SDValue Op1 = DAG.getNode(ISD::BITCAST, dl, MVT::i32, Op); // Scale the exponent by log10(2) [0.30102999f]. SDValue Exp = GetExponent(DAG, Op1, TLI, dl); SDValue LogOfExponent = DAG.getNode(ISD::FMUL, dl, MVT::f32, Exp, getF32Constant(DAG, 0x3e9a209a)); // Get the significand and build it into a floating-point number with // exponent of 1. SDValue X = GetSignificand(DAG, Op1, dl); if (LimitFloatPrecision <= 6) { // For floating-point precision of 6: // // Log10ofMantissa = // -0.50419619f + // (0.60948995f - 0.10380950f * x) * x; // // error 0.0014886165, which is 6 bits SDValue t0 = DAG.getNode(ISD::FMUL, dl, MVT::f32, X, getF32Constant(DAG, 0xbdd49a13)); SDValue t1 = DAG.getNode(ISD::FADD, dl, MVT::f32, t0, getF32Constant(DAG, 0x3f1c0789)); SDValue t2 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t1, X); SDValue Log10ofMantissa = DAG.getNode(ISD::FSUB, dl, MVT::f32, t2, getF32Constant(DAG, 0x3f011300)); result = DAG.getNode(ISD::FADD, dl, MVT::f32, LogOfExponent, Log10ofMantissa); } else if (LimitFloatPrecision > 6 && LimitFloatPrecision <= 12) { // For floating-point precision of 12: // // Log10ofMantissa = // -0.64831180f + // (0.91751397f + // (-0.31664806f + 0.47637168e-1f * x) * x) * x; // // error 0.00019228036, which is better than 12 bits SDValue t0 = DAG.getNode(ISD::FMUL, dl, MVT::f32, X, getF32Constant(DAG, 0x3d431f31)); SDValue t1 = DAG.getNode(ISD::FSUB, dl, MVT::f32, t0, getF32Constant(DAG, 0x3ea21fb2)); SDValue t2 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t1, X); SDValue t3 = DAG.getNode(ISD::FADD, dl, MVT::f32, t2, getF32Constant(DAG, 0x3f6ae232)); SDValue t4 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t3, X); SDValue Log10ofMantissa = DAG.getNode(ISD::FSUB, dl, MVT::f32, t4, getF32Constant(DAG, 0x3f25f7c3)); result = DAG.getNode(ISD::FADD, dl, MVT::f32, LogOfExponent, Log10ofMantissa); } else { // LimitFloatPrecision > 12 && LimitFloatPrecision <= 18 // For floating-point precision of 18: // // Log10ofMantissa = // -0.84299375f + // (1.5327582f + // (-1.0688956f + // (0.49102474f + // (-0.12539807f + 0.13508273e-1f * x) * x) * x) * x) * x; // // error 0.0000037995730, which is better than 18 bits SDValue t0 = DAG.getNode(ISD::FMUL, dl, MVT::f32, X, getF32Constant(DAG, 0x3c5d51ce)); SDValue t1 = DAG.getNode(ISD::FSUB, dl, MVT::f32, t0, getF32Constant(DAG, 0x3e00685a)); SDValue t2 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t1, X); SDValue t3 = DAG.getNode(ISD::FADD, dl, MVT::f32, t2, getF32Constant(DAG, 0x3efb6798)); SDValue t4 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t3, X); SDValue t5 = DAG.getNode(ISD::FSUB, dl, MVT::f32, t4, getF32Constant(DAG, 0x3f88d192)); SDValue t6 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t5, X); SDValue t7 = DAG.getNode(ISD::FADD, dl, MVT::f32, t6, getF32Constant(DAG, 0x3fc4316c)); SDValue t8 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t7, X); SDValue Log10ofMantissa = DAG.getNode(ISD::FSUB, dl, MVT::f32, t8, getF32Constant(DAG, 0x3f57ce70)); result = DAG.getNode(ISD::FADD, dl, MVT::f32, LogOfExponent, Log10ofMantissa); } } else { // No special expansion. result = DAG.getNode(ISD::FLOG10, dl, getValue(I.getArgOperand(0)).getValueType(), getValue(I.getArgOperand(0))); } setValue(&I, result); } /// visitExp2 - Lower an exp2 intrinsic. Handles the special sequences for /// limited-precision mode. void SelectionDAGBuilder::visitExp2(const CallInst &I) { SDValue result; DebugLoc dl = getCurDebugLoc(); if (getValue(I.getArgOperand(0)).getValueType() == MVT::f32 && LimitFloatPrecision > 0 && LimitFloatPrecision <= 18) { SDValue Op = getValue(I.getArgOperand(0)); SDValue IntegerPartOfX = DAG.getNode(ISD::FP_TO_SINT, dl, MVT::i32, Op); // FractionalPartOfX = x - (float)IntegerPartOfX; SDValue t1 = DAG.getNode(ISD::SINT_TO_FP, dl, MVT::f32, IntegerPartOfX); SDValue X = DAG.getNode(ISD::FSUB, dl, MVT::f32, Op, t1); // IntegerPartOfX <<= 23; IntegerPartOfX = DAG.getNode(ISD::SHL, dl, MVT::i32, IntegerPartOfX, DAG.getConstant(23, TLI.getPointerTy())); if (LimitFloatPrecision <= 6) { // For floating-point precision of 6: // // TwoToFractionalPartOfX = // 0.997535578f + // (0.735607626f + 0.252464424f * x) * x; // // error 0.0144103317, which is 6 bits SDValue t2 = DAG.getNode(ISD::FMUL, dl, MVT::f32, X, getF32Constant(DAG, 0x3e814304)); SDValue t3 = DAG.getNode(ISD::FADD, dl, MVT::f32, t2, getF32Constant(DAG, 0x3f3c50c8)); SDValue t4 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t3, X); SDValue t5 = DAG.getNode(ISD::FADD, dl, MVT::f32, t4, getF32Constant(DAG, 0x3f7f5e7e)); SDValue t6 = DAG.getNode(ISD::BITCAST, dl, MVT::i32, t5); SDValue TwoToFractionalPartOfX = DAG.getNode(ISD::ADD, dl, MVT::i32, t6, IntegerPartOfX); result = DAG.getNode(ISD::BITCAST, dl, MVT::f32, TwoToFractionalPartOfX); } else if (LimitFloatPrecision > 6 && LimitFloatPrecision <= 12) { // For floating-point precision of 12: // // TwoToFractionalPartOfX = // 0.999892986f + // (0.696457318f + // (0.224338339f + 0.792043434e-1f * x) * x) * x; // // error 0.000107046256, which is 13 to 14 bits SDValue t2 = DAG.getNode(ISD::FMUL, dl, MVT::f32, X, getF32Constant(DAG, 0x3da235e3)); SDValue t3 = DAG.getNode(ISD::FADD, dl, MVT::f32, t2, getF32Constant(DAG, 0x3e65b8f3)); SDValue t4 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t3, X); SDValue t5 = DAG.getNode(ISD::FADD, dl, MVT::f32, t4, getF32Constant(DAG, 0x3f324b07)); SDValue t6 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t5, X); SDValue t7 = DAG.getNode(ISD::FADD, dl, MVT::f32, t6, getF32Constant(DAG, 0x3f7ff8fd)); SDValue t8 = DAG.getNode(ISD::BITCAST, dl, MVT::i32, t7); SDValue TwoToFractionalPartOfX = DAG.getNode(ISD::ADD, dl, MVT::i32, t8, IntegerPartOfX); result = DAG.getNode(ISD::BITCAST, dl, MVT::f32, TwoToFractionalPartOfX); } else { // LimitFloatPrecision > 12 && LimitFloatPrecision <= 18 // For floating-point precision of 18: // // TwoToFractionalPartOfX = // 0.999999982f + // (0.693148872f + // (0.240227044f + // (0.554906021e-1f + // (0.961591928e-2f + // (0.136028312e-2f + 0.157059148e-3f *x)*x)*x)*x)*x)*x; // error 2.47208000*10^(-7), which is better than 18 bits SDValue t2 = DAG.getNode(ISD::FMUL, dl, MVT::f32, X, getF32Constant(DAG, 0x3924b03e)); SDValue t3 = DAG.getNode(ISD::FADD, dl, MVT::f32, t2, getF32Constant(DAG, 0x3ab24b87)); SDValue t4 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t3, X); SDValue t5 = DAG.getNode(ISD::FADD, dl, MVT::f32, t4, getF32Constant(DAG, 0x3c1d8c17)); SDValue t6 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t5, X); SDValue t7 = DAG.getNode(ISD::FADD, dl, MVT::f32, t6, getF32Constant(DAG, 0x3d634a1d)); SDValue t8 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t7, X); SDValue t9 = DAG.getNode(ISD::FADD, dl, MVT::f32, t8, getF32Constant(DAG, 0x3e75fe14)); SDValue t10 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t9, X); SDValue t11 = DAG.getNode(ISD::FADD, dl, MVT::f32, t10, getF32Constant(DAG, 0x3f317234)); SDValue t12 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t11, X); SDValue t13 = DAG.getNode(ISD::FADD, dl, MVT::f32, t12, getF32Constant(DAG, 0x3f800000)); SDValue t14 = DAG.getNode(ISD::BITCAST, dl, MVT::i32, t13); SDValue TwoToFractionalPartOfX = DAG.getNode(ISD::ADD, dl, MVT::i32, t14, IntegerPartOfX); result = DAG.getNode(ISD::BITCAST, dl, MVT::f32, TwoToFractionalPartOfX); } } else { // No special expansion. result = DAG.getNode(ISD::FEXP2, dl, getValue(I.getArgOperand(0)).getValueType(), getValue(I.getArgOperand(0))); } setValue(&I, result); } /// visitPow - Lower a pow intrinsic. Handles the special sequences for /// limited-precision mode with x == 10.0f. void SelectionDAGBuilder::visitPow(const CallInst &I) { SDValue result; const Value *Val = I.getArgOperand(0); DebugLoc dl = getCurDebugLoc(); bool IsExp10 = false; if (getValue(Val).getValueType() == MVT::f32 && getValue(I.getArgOperand(1)).getValueType() == MVT::f32 && LimitFloatPrecision > 0 && LimitFloatPrecision <= 18) { if (Constant *C = const_cast(dyn_cast(Val))) { if (ConstantFP *CFP = dyn_cast(C)) { APFloat Ten(10.0f); IsExp10 = CFP->getValueAPF().bitwiseIsEqual(Ten); } } } if (IsExp10 && LimitFloatPrecision > 0 && LimitFloatPrecision <= 18) { SDValue Op = getValue(I.getArgOperand(1)); // Put the exponent in the right bit position for later addition to the // final result: // // #define LOG2OF10 3.3219281f // IntegerPartOfX = (int32_t)(x * LOG2OF10); SDValue t0 = DAG.getNode(ISD::FMUL, dl, MVT::f32, Op, getF32Constant(DAG, 0x40549a78)); SDValue IntegerPartOfX = DAG.getNode(ISD::FP_TO_SINT, dl, MVT::i32, t0); // FractionalPartOfX = x - (float)IntegerPartOfX; SDValue t1 = DAG.getNode(ISD::SINT_TO_FP, dl, MVT::f32, IntegerPartOfX); SDValue X = DAG.getNode(ISD::FSUB, dl, MVT::f32, t0, t1); // IntegerPartOfX <<= 23; IntegerPartOfX = DAG.getNode(ISD::SHL, dl, MVT::i32, IntegerPartOfX, DAG.getConstant(23, TLI.getPointerTy())); if (LimitFloatPrecision <= 6) { // For floating-point precision of 6: // // twoToFractionalPartOfX = // 0.997535578f + // (0.735607626f + 0.252464424f * x) * x; // // error 0.0144103317, which is 6 bits SDValue t2 = DAG.getNode(ISD::FMUL, dl, MVT::f32, X, getF32Constant(DAG, 0x3e814304)); SDValue t3 = DAG.getNode(ISD::FADD, dl, MVT::f32, t2, getF32Constant(DAG, 0x3f3c50c8)); SDValue t4 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t3, X); SDValue t5 = DAG.getNode(ISD::FADD, dl, MVT::f32, t4, getF32Constant(DAG, 0x3f7f5e7e)); SDValue t6 = DAG.getNode(ISD::BITCAST, dl, MVT::i32, t5); SDValue TwoToFractionalPartOfX = DAG.getNode(ISD::ADD, dl, MVT::i32, t6, IntegerPartOfX); result = DAG.getNode(ISD::BITCAST, dl, MVT::f32, TwoToFractionalPartOfX); } else if (LimitFloatPrecision > 6 && LimitFloatPrecision <= 12) { // For floating-point precision of 12: // // TwoToFractionalPartOfX = // 0.999892986f + // (0.696457318f + // (0.224338339f + 0.792043434e-1f * x) * x) * x; // // error 0.000107046256, which is 13 to 14 bits SDValue t2 = DAG.getNode(ISD::FMUL, dl, MVT::f32, X, getF32Constant(DAG, 0x3da235e3)); SDValue t3 = DAG.getNode(ISD::FADD, dl, MVT::f32, t2, getF32Constant(DAG, 0x3e65b8f3)); SDValue t4 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t3, X); SDValue t5 = DAG.getNode(ISD::FADD, dl, MVT::f32, t4, getF32Constant(DAG, 0x3f324b07)); SDValue t6 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t5, X); SDValue t7 = DAG.getNode(ISD::FADD, dl, MVT::f32, t6, getF32Constant(DAG, 0x3f7ff8fd)); SDValue t8 = DAG.getNode(ISD::BITCAST, dl, MVT::i32, t7); SDValue TwoToFractionalPartOfX = DAG.getNode(ISD::ADD, dl, MVT::i32, t8, IntegerPartOfX); result = DAG.getNode(ISD::BITCAST, dl, MVT::f32, TwoToFractionalPartOfX); } else { // LimitFloatPrecision > 12 && LimitFloatPrecision <= 18 // For floating-point precision of 18: // // TwoToFractionalPartOfX = // 0.999999982f + // (0.693148872f + // (0.240227044f + // (0.554906021e-1f + // (0.961591928e-2f + // (0.136028312e-2f + 0.157059148e-3f *x)*x)*x)*x)*x)*x; // error 2.47208000*10^(-7), which is better than 18 bits SDValue t2 = DAG.getNode(ISD::FMUL, dl, MVT::f32, X, getF32Constant(DAG, 0x3924b03e)); SDValue t3 = DAG.getNode(ISD::FADD, dl, MVT::f32, t2, getF32Constant(DAG, 0x3ab24b87)); SDValue t4 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t3, X); SDValue t5 = DAG.getNode(ISD::FADD, dl, MVT::f32, t4, getF32Constant(DAG, 0x3c1d8c17)); SDValue t6 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t5, X); SDValue t7 = DAG.getNode(ISD::FADD, dl, MVT::f32, t6, getF32Constant(DAG, 0x3d634a1d)); SDValue t8 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t7, X); SDValue t9 = DAG.getNode(ISD::FADD, dl, MVT::f32, t8, getF32Constant(DAG, 0x3e75fe14)); SDValue t10 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t9, X); SDValue t11 = DAG.getNode(ISD::FADD, dl, MVT::f32, t10, getF32Constant(DAG, 0x3f317234)); SDValue t12 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t11, X); SDValue t13 = DAG.getNode(ISD::FADD, dl, MVT::f32, t12, getF32Constant(DAG, 0x3f800000)); SDValue t14 = DAG.getNode(ISD::BITCAST, dl, MVT::i32, t13); SDValue TwoToFractionalPartOfX = DAG.getNode(ISD::ADD, dl, MVT::i32, t14, IntegerPartOfX); result = DAG.getNode(ISD::BITCAST, dl, MVT::f32, TwoToFractionalPartOfX); } } else { // No special expansion. result = DAG.getNode(ISD::FPOW, dl, getValue(I.getArgOperand(0)).getValueType(), getValue(I.getArgOperand(0)), getValue(I.getArgOperand(1))); } setValue(&I, result); } /// ExpandPowI - Expand a llvm.powi intrinsic. static SDValue ExpandPowI(DebugLoc DL, SDValue LHS, SDValue RHS, SelectionDAG &DAG) { // If RHS is a constant, we can expand this out to a multiplication tree, // otherwise we end up lowering to a call to __powidf2 (for example). When // optimizing for size, we only want to do this if the expansion would produce // a small number of multiplies, otherwise we do the full expansion. if (ConstantSDNode *RHSC = dyn_cast(RHS)) { // Get the exponent as a positive value. unsigned Val = RHSC->getSExtValue(); if ((int)Val < 0) Val = -Val; // powi(x, 0) -> 1.0 if (Val == 0) return DAG.getConstantFP(1.0, LHS.getValueType()); const Function *F = DAG.getMachineFunction().getFunction(); if (!F->hasFnAttr(Attribute::OptimizeForSize) || // If optimizing for size, don't insert too many multiplies. This // inserts up to 5 multiplies. CountPopulation_32(Val)+Log2_32(Val) < 7) { // We use the simple binary decomposition method to generate the multiply // sequence. There are more optimal ways to do this (for example, // powi(x,15) generates one more multiply than it should), but this has // the benefit of being both really simple and much better than a libcall. SDValue Res; // Logically starts equal to 1.0 SDValue CurSquare = LHS; while (Val) { if (Val & 1) { if (Res.getNode()) Res = DAG.getNode(ISD::FMUL, DL,Res.getValueType(), Res, CurSquare); else Res = CurSquare; // 1.0*CurSquare. } CurSquare = DAG.getNode(ISD::FMUL, DL, CurSquare.getValueType(), CurSquare, CurSquare); Val >>= 1; } // If the original was negative, invert the result, producing 1/(x*x*x). if (RHSC->getSExtValue() < 0) Res = DAG.getNode(ISD::FDIV, DL, LHS.getValueType(), DAG.getConstantFP(1.0, LHS.getValueType()), Res); return Res; } } // Otherwise, expand to a libcall. return DAG.getNode(ISD::FPOWI, DL, LHS.getValueType(), LHS, RHS); } // getTruncatedArgReg - Find underlying register used for an truncated // argument. static unsigned getTruncatedArgReg(const SDValue &N) { if (N.getOpcode() != ISD::TRUNCATE) return 0; const SDValue &Ext = N.getOperand(0); if (Ext.getOpcode() == ISD::AssertZext || Ext.getOpcode() == ISD::AssertSext){ const SDValue &CFR = Ext.getOperand(0); if (CFR.getOpcode() == ISD::CopyFromReg) return cast(CFR.getOperand(1))->getReg(); else if (CFR.getOpcode() == ISD::TRUNCATE) return getTruncatedArgReg(CFR); } return 0; } /// EmitFuncArgumentDbgValue - If the DbgValueInst is a dbg_value of a function /// argument, create the corresponding DBG_VALUE machine instruction for it now. /// At the end of instruction selection, they will be inserted to the entry BB. bool SelectionDAGBuilder::EmitFuncArgumentDbgValue(const Value *V, MDNode *Variable, int64_t Offset, const SDValue &N) { const Argument *Arg = dyn_cast(V); if (!Arg) return false; MachineFunction &MF = DAG.getMachineFunction(); const TargetInstrInfo *TII = DAG.getTarget().getInstrInfo(); const TargetRegisterInfo *TRI = DAG.getTarget().getRegisterInfo(); // Ignore inlined function arguments here. DIVariable DV(Variable); if (DV.isInlinedFnArgument(MF.getFunction())) return false; unsigned Reg = 0; // Some arguments' frame index is recorded during argument lowering. Offset = FuncInfo.getArgumentFrameIndex(Arg); if (Offset) Reg = TRI->getFrameRegister(MF); if (!Reg && N.getNode()) { if (N.getOpcode() == ISD::CopyFromReg) Reg = cast(N.getOperand(1))->getReg(); else Reg = getTruncatedArgReg(N); if (Reg && TargetRegisterInfo::isVirtualRegister(Reg)) { MachineRegisterInfo &RegInfo = MF.getRegInfo(); unsigned PR = RegInfo.getLiveInPhysReg(Reg); if (PR) Reg = PR; } } if (!Reg) { // Check if ValueMap has reg number. DenseMap::iterator VMI = FuncInfo.ValueMap.find(V); if (VMI != FuncInfo.ValueMap.end()) Reg = VMI->second; } if (!Reg && N.getNode()) { // Check if frame index is available. if (LoadSDNode *LNode = dyn_cast(N.getNode())) if (FrameIndexSDNode *FINode = dyn_cast(LNode->getBasePtr().getNode())) { Reg = TRI->getFrameRegister(MF); Offset = FINode->getIndex(); } } if (!Reg) return false; MachineInstrBuilder MIB = BuildMI(MF, getCurDebugLoc(), TII->get(TargetOpcode::DBG_VALUE)) .addReg(Reg, RegState::Debug).addImm(Offset).addMetadata(Variable); FuncInfo.ArgDbgValues.push_back(&*MIB); return true; } // VisualStudio defines setjmp as _setjmp #if defined(_MSC_VER) && defined(setjmp) && \ !defined(setjmp_undefined_for_msvc) # pragma push_macro("setjmp") # undef setjmp # define setjmp_undefined_for_msvc #endif /// visitIntrinsicCall - Lower the call to the specified intrinsic function. If /// we want to emit this as a call to a named external function, return the name /// otherwise lower it and return null. const char * SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { DebugLoc dl = getCurDebugLoc(); SDValue Res; switch (Intrinsic) { default: // By default, turn this into a target intrinsic node. visitTargetIntrinsic(I, Intrinsic); return 0; case Intrinsic::vastart: visitVAStart(I); return 0; case Intrinsic::vaend: visitVAEnd(I); return 0; case Intrinsic::vacopy: visitVACopy(I); return 0; case Intrinsic::returnaddress: setValue(&I, DAG.getNode(ISD::RETURNADDR, dl, TLI.getPointerTy(), getValue(I.getArgOperand(0)))); return 0; case Intrinsic::frameaddress: setValue(&I, DAG.getNode(ISD::FRAMEADDR, dl, TLI.getPointerTy(), getValue(I.getArgOperand(0)))); return 0; case Intrinsic::setjmp: return "_setjmp"+!TLI.usesUnderscoreSetJmp(); case Intrinsic::longjmp: return "_longjmp"+!TLI.usesUnderscoreLongJmp(); case Intrinsic::memcpy: { // Assert for address < 256 since we support only user defined address // spaces. assert(cast(I.getArgOperand(0)->getType())->getAddressSpace() < 256 && cast(I.getArgOperand(1)->getType())->getAddressSpace() < 256 && "Unknown address space"); SDValue Op1 = getValue(I.getArgOperand(0)); SDValue Op2 = getValue(I.getArgOperand(1)); SDValue Op3 = getValue(I.getArgOperand(2)); unsigned Align = cast(I.getArgOperand(3))->getZExtValue(); bool isVol = cast(I.getArgOperand(4))->getZExtValue(); DAG.setRoot(DAG.getMemcpy(getRoot(), dl, Op1, Op2, Op3, Align, isVol, false, MachinePointerInfo(I.getArgOperand(0)), MachinePointerInfo(I.getArgOperand(1)))); return 0; } case Intrinsic::memset: { // Assert for address < 256 since we support only user defined address // spaces. assert(cast(I.getArgOperand(0)->getType())->getAddressSpace() < 256 && "Unknown address space"); SDValue Op1 = getValue(I.getArgOperand(0)); SDValue Op2 = getValue(I.getArgOperand(1)); SDValue Op3 = getValue(I.getArgOperand(2)); unsigned Align = cast(I.getArgOperand(3))->getZExtValue(); bool isVol = cast(I.getArgOperand(4))->getZExtValue(); DAG.setRoot(DAG.getMemset(getRoot(), dl, Op1, Op2, Op3, Align, isVol, MachinePointerInfo(I.getArgOperand(0)))); return 0; } case Intrinsic::memmove: { // Assert for address < 256 since we support only user defined address // spaces. assert(cast(I.getArgOperand(0)->getType())->getAddressSpace() < 256 && cast(I.getArgOperand(1)->getType())->getAddressSpace() < 256 && "Unknown address space"); SDValue Op1 = getValue(I.getArgOperand(0)); SDValue Op2 = getValue(I.getArgOperand(1)); SDValue Op3 = getValue(I.getArgOperand(2)); unsigned Align = cast(I.getArgOperand(3))->getZExtValue(); bool isVol = cast(I.getArgOperand(4))->getZExtValue(); DAG.setRoot(DAG.getMemmove(getRoot(), dl, Op1, Op2, Op3, Align, isVol, MachinePointerInfo(I.getArgOperand(0)), MachinePointerInfo(I.getArgOperand(1)))); return 0; } case Intrinsic::dbg_declare: { const DbgDeclareInst &DI = cast(I); MDNode *Variable = DI.getVariable(); const Value *Address = DI.getAddress(); if (!Address || !DIVariable(Variable).Verify()) return 0; // Build an entry in DbgOrdering. Debug info input nodes get an SDNodeOrder // but do not always have a corresponding SDNode built. The SDNodeOrder // absolute, but not relative, values are different depending on whether // debug info exists. ++SDNodeOrder; // Check if address has undef value. if (isa(Address) || (Address->use_empty() && !isa(Address))) { DEBUG(dbgs() << "Dropping debug info for " << DI); return 0; } SDValue &N = NodeMap[Address]; if (!N.getNode() && isa(Address)) // Check unused arguments map. N = UnusedArgNodeMap[Address]; SDDbgValue *SDV; if (N.getNode()) { // Parameters are handled specially. bool isParameter = DIVariable(Variable).getTag() == dwarf::DW_TAG_arg_variable; if (const BitCastInst *BCI = dyn_cast(Address)) Address = BCI->getOperand(0); const AllocaInst *AI = dyn_cast(Address); if (isParameter && !AI) { FrameIndexSDNode *FINode = dyn_cast(N.getNode()); if (FINode) // Byval parameter. We have a frame index at this point. SDV = DAG.getDbgValue(Variable, FINode->getIndex(), 0, dl, SDNodeOrder); else { // Address is an argument, so try to emit its dbg value using // virtual register info from the FuncInfo.ValueMap. EmitFuncArgumentDbgValue(Address, Variable, 0, N); return 0; } } else if (AI) SDV = DAG.getDbgValue(Variable, N.getNode(), N.getResNo(), 0, dl, SDNodeOrder); else { // Can't do anything with other non-AI cases yet. DEBUG(dbgs() << "Dropping debug info for " << DI); return 0; } DAG.AddDbgValue(SDV, N.getNode(), isParameter); } else { // If Address is an argument then try to emit its dbg value using // virtual register info from the FuncInfo.ValueMap. if (!EmitFuncArgumentDbgValue(Address, Variable, 0, N)) { // If variable is pinned by a alloca in dominating bb then // use StaticAllocaMap. if (const AllocaInst *AI = dyn_cast(Address)) { if (AI->getParent() != DI.getParent()) { DenseMap::iterator SI = FuncInfo.StaticAllocaMap.find(AI); if (SI != FuncInfo.StaticAllocaMap.end()) { SDV = DAG.getDbgValue(Variable, SI->second, 0, dl, SDNodeOrder); DAG.AddDbgValue(SDV, 0, false); return 0; } } } DEBUG(dbgs() << "Dropping debug info for " << DI); } } return 0; } case Intrinsic::dbg_value: { const DbgValueInst &DI = cast(I); if (!DIVariable(DI.getVariable()).Verify()) return 0; MDNode *Variable = DI.getVariable(); uint64_t Offset = DI.getOffset(); const Value *V = DI.getValue(); if (!V) return 0; // Build an entry in DbgOrdering. Debug info input nodes get an SDNodeOrder // but do not always have a corresponding SDNode built. The SDNodeOrder // absolute, but not relative, values are different depending on whether // debug info exists. ++SDNodeOrder; SDDbgValue *SDV; if (isa(V) || isa(V) || isa(V)) { SDV = DAG.getDbgValue(Variable, V, Offset, dl, SDNodeOrder); DAG.AddDbgValue(SDV, 0, false); } else { // Do not use getValue() in here; we don't want to generate code at // this point if it hasn't been done yet. SDValue N = NodeMap[V]; if (!N.getNode() && isa(V)) // Check unused arguments map. N = UnusedArgNodeMap[V]; if (N.getNode()) { if (!EmitFuncArgumentDbgValue(V, Variable, Offset, N)) { SDV = DAG.getDbgValue(Variable, N.getNode(), N.getResNo(), Offset, dl, SDNodeOrder); DAG.AddDbgValue(SDV, N.getNode(), false); } } else if (!V->use_empty() ) { // Do not call getValue(V) yet, as we don't want to generate code. // Remember it for later. DanglingDebugInfo DDI(&DI, dl, SDNodeOrder); DanglingDebugInfoMap[V] = DDI; } else { // We may expand this to cover more cases. One case where we have no // data available is an unreferenced parameter. DEBUG(dbgs() << "Dropping debug info for " << DI); } } // Build a debug info table entry. if (const BitCastInst *BCI = dyn_cast(V)) V = BCI->getOperand(0); const AllocaInst *AI = dyn_cast(V); // Don't handle byval struct arguments or VLAs, for example. if (!AI) return 0; DenseMap::iterator SI = FuncInfo.StaticAllocaMap.find(AI); if (SI == FuncInfo.StaticAllocaMap.end()) return 0; // VLAs. int FI = SI->second; MachineModuleInfo &MMI = DAG.getMachineFunction().getMMI(); if (!DI.getDebugLoc().isUnknown() && MMI.hasDebugInfo()) MMI.setVariableDbgInfo(Variable, FI, DI.getDebugLoc()); return 0; } case Intrinsic::eh_exception: { // Insert the EXCEPTIONADDR instruction. assert(FuncInfo.MBB->isLandingPad() && "Call to eh.exception not in landing pad!"); SDVTList VTs = DAG.getVTList(TLI.getPointerTy(), MVT::Other); SDValue Ops[1]; Ops[0] = DAG.getRoot(); SDValue Op = DAG.getNode(ISD::EXCEPTIONADDR, dl, VTs, Ops, 1); setValue(&I, Op); DAG.setRoot(Op.getValue(1)); return 0; } case Intrinsic::eh_selector: { MachineBasicBlock *CallMBB = FuncInfo.MBB; MachineModuleInfo &MMI = DAG.getMachineFunction().getMMI(); if (CallMBB->isLandingPad()) AddCatchInfo(I, &MMI, CallMBB); else { #ifndef NDEBUG FuncInfo.CatchInfoLost.insert(&I); #endif // FIXME: Mark exception selector register as live in. Hack for PR1508. unsigned Reg = TLI.getExceptionSelectorRegister(); if (Reg) FuncInfo.MBB->addLiveIn(Reg); } // Insert the EHSELECTION instruction. SDVTList VTs = DAG.getVTList(TLI.getPointerTy(), MVT::Other); SDValue Ops[2]; Ops[0] = getValue(I.getArgOperand(0)); Ops[1] = getRoot(); SDValue Op = DAG.getNode(ISD::EHSELECTION, dl, VTs, Ops, 2); DAG.setRoot(Op.getValue(1)); setValue(&I, DAG.getSExtOrTrunc(Op, dl, MVT::i32)); return 0; } case Intrinsic::eh_typeid_for: { // Find the type id for the given typeinfo. GlobalVariable *GV = ExtractTypeInfo(I.getArgOperand(0)); unsigned TypeID = DAG.getMachineFunction().getMMI().getTypeIDFor(GV); Res = DAG.getConstant(TypeID, MVT::i32); setValue(&I, Res); return 0; } case Intrinsic::eh_return_i32: case Intrinsic::eh_return_i64: DAG.getMachineFunction().getMMI().setCallsEHReturn(true); DAG.setRoot(DAG.getNode(ISD::EH_RETURN, dl, MVT::Other, getControlRoot(), getValue(I.getArgOperand(0)), getValue(I.getArgOperand(1)))); return 0; case Intrinsic::eh_unwind_init: DAG.getMachineFunction().getMMI().setCallsUnwindInit(true); return 0; case Intrinsic::eh_dwarf_cfa: { SDValue CfaArg = DAG.getSExtOrTrunc(getValue(I.getArgOperand(0)), dl, TLI.getPointerTy()); SDValue Offset = DAG.getNode(ISD::ADD, dl, TLI.getPointerTy(), DAG.getNode(ISD::FRAME_TO_ARGS_OFFSET, dl, TLI.getPointerTy()), CfaArg); SDValue FA = DAG.getNode(ISD::FRAMEADDR, dl, TLI.getPointerTy(), DAG.getConstant(0, TLI.getPointerTy())); setValue(&I, DAG.getNode(ISD::ADD, dl, TLI.getPointerTy(), FA, Offset)); return 0; } case Intrinsic::eh_sjlj_callsite: { MachineModuleInfo &MMI = DAG.getMachineFunction().getMMI(); ConstantInt *CI = dyn_cast(I.getArgOperand(0)); assert(CI && "Non-constant call site value in eh.sjlj.callsite!"); assert(MMI.getCurrentCallSite() == 0 && "Overlapping call sites!"); MMI.setCurrentCallSite(CI->getZExtValue()); return 0; } case Intrinsic::eh_sjlj_functioncontext: { // Get and store the index of the function context. MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); AllocaInst *FnCtx = cast(I.getArgOperand(0)->stripPointerCasts()); int FI = FuncInfo.StaticAllocaMap[FnCtx]; MFI->setFunctionContextIndex(FI); return 0; } case Intrinsic::eh_sjlj_setjmp: { SDValue Ops[2]; Ops[0] = getRoot(); Ops[1] = getValue(I.getArgOperand(0)); SDValue Op = DAG.getNode(ISD::EH_SJLJ_SETJMP, dl, DAG.getVTList(MVT::i32, MVT::Other), Ops, 2); setValue(&I, Op.getValue(0)); DAG.setRoot(Op.getValue(1)); return 0; } case Intrinsic::eh_sjlj_longjmp: { DAG.setRoot(DAG.getNode(ISD::EH_SJLJ_LONGJMP, dl, MVT::Other, getRoot(), getValue(I.getArgOperand(0)))); return 0; } case Intrinsic::eh_sjlj_dispatch_setup: { DAG.setRoot(DAG.getNode(ISD::EH_SJLJ_DISPATCHSETUP, dl, MVT::Other, getRoot(), getValue(I.getArgOperand(0)))); return 0; } case Intrinsic::x86_mmx_pslli_w: case Intrinsic::x86_mmx_pslli_d: case Intrinsic::x86_mmx_pslli_q: case Intrinsic::x86_mmx_psrli_w: case Intrinsic::x86_mmx_psrli_d: case Intrinsic::x86_mmx_psrli_q: case Intrinsic::x86_mmx_psrai_w: case Intrinsic::x86_mmx_psrai_d: { SDValue ShAmt = getValue(I.getArgOperand(1)); if (isa(ShAmt)) { visitTargetIntrinsic(I, Intrinsic); return 0; } unsigned NewIntrinsic = 0; EVT ShAmtVT = MVT::v2i32; switch (Intrinsic) { case Intrinsic::x86_mmx_pslli_w: NewIntrinsic = Intrinsic::x86_mmx_psll_w; break; case Intrinsic::x86_mmx_pslli_d: NewIntrinsic = Intrinsic::x86_mmx_psll_d; break; case Intrinsic::x86_mmx_pslli_q: NewIntrinsic = Intrinsic::x86_mmx_psll_q; break; case Intrinsic::x86_mmx_psrli_w: NewIntrinsic = Intrinsic::x86_mmx_psrl_w; break; case Intrinsic::x86_mmx_psrli_d: NewIntrinsic = Intrinsic::x86_mmx_psrl_d; break; case Intrinsic::x86_mmx_psrli_q: NewIntrinsic = Intrinsic::x86_mmx_psrl_q; break; case Intrinsic::x86_mmx_psrai_w: NewIntrinsic = Intrinsic::x86_mmx_psra_w; break; case Intrinsic::x86_mmx_psrai_d: NewIntrinsic = Intrinsic::x86_mmx_psra_d; break; default: llvm_unreachable("Impossible intrinsic"); // Can't reach here. } // The vector shift intrinsics with scalars uses 32b shift amounts but // the sse2/mmx shift instructions reads 64 bits. Set the upper 32 bits // to be zero. // We must do this early because v2i32 is not a legal type. DebugLoc dl = getCurDebugLoc(); SDValue ShOps[2]; ShOps[0] = ShAmt; ShOps[1] = DAG.getConstant(0, MVT::i32); ShAmt = DAG.getNode(ISD::BUILD_VECTOR, dl, ShAmtVT, &ShOps[0], 2); EVT DestVT = TLI.getValueType(I.getType()); ShAmt = DAG.getNode(ISD::BITCAST, dl, DestVT, ShAmt); Res = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, DestVT, DAG.getConstant(NewIntrinsic, MVT::i32), getValue(I.getArgOperand(0)), ShAmt); setValue(&I, Res); return 0; } case Intrinsic::convertff: case Intrinsic::convertfsi: case Intrinsic::convertfui: case Intrinsic::convertsif: case Intrinsic::convertuif: case Intrinsic::convertss: case Intrinsic::convertsu: case Intrinsic::convertus: case Intrinsic::convertuu: { ISD::CvtCode Code = ISD::CVT_INVALID; switch (Intrinsic) { case Intrinsic::convertff: Code = ISD::CVT_FF; break; case Intrinsic::convertfsi: Code = ISD::CVT_FS; break; case Intrinsic::convertfui: Code = ISD::CVT_FU; break; case Intrinsic::convertsif: Code = ISD::CVT_SF; break; case Intrinsic::convertuif: Code = ISD::CVT_UF; break; case Intrinsic::convertss: Code = ISD::CVT_SS; break; case Intrinsic::convertsu: Code = ISD::CVT_SU; break; case Intrinsic::convertus: Code = ISD::CVT_US; break; case Intrinsic::convertuu: Code = ISD::CVT_UU; break; } EVT DestVT = TLI.getValueType(I.getType()); const Value *Op1 = I.getArgOperand(0); Res = DAG.getConvertRndSat(DestVT, getCurDebugLoc(), getValue(Op1), DAG.getValueType(DestVT), DAG.getValueType(getValue(Op1).getValueType()), getValue(I.getArgOperand(1)), getValue(I.getArgOperand(2)), Code); setValue(&I, Res); return 0; } case Intrinsic::sqrt: setValue(&I, DAG.getNode(ISD::FSQRT, dl, getValue(I.getArgOperand(0)).getValueType(), getValue(I.getArgOperand(0)))); return 0; case Intrinsic::powi: setValue(&I, ExpandPowI(dl, getValue(I.getArgOperand(0)), getValue(I.getArgOperand(1)), DAG)); return 0; case Intrinsic::sin: setValue(&I, DAG.getNode(ISD::FSIN, dl, getValue(I.getArgOperand(0)).getValueType(), getValue(I.getArgOperand(0)))); return 0; case Intrinsic::cos: setValue(&I, DAG.getNode(ISD::FCOS, dl, getValue(I.getArgOperand(0)).getValueType(), getValue(I.getArgOperand(0)))); return 0; case Intrinsic::log: visitLog(I); return 0; case Intrinsic::log2: visitLog2(I); return 0; case Intrinsic::log10: visitLog10(I); return 0; case Intrinsic::exp: visitExp(I); return 0; case Intrinsic::exp2: visitExp2(I); return 0; case Intrinsic::pow: visitPow(I); return 0; case Intrinsic::fma: setValue(&I, DAG.getNode(ISD::FMA, dl, getValue(I.getArgOperand(0)).getValueType(), getValue(I.getArgOperand(0)), getValue(I.getArgOperand(1)), getValue(I.getArgOperand(2)))); return 0; case Intrinsic::convert_to_fp16: setValue(&I, DAG.getNode(ISD::FP32_TO_FP16, dl, MVT::i16, getValue(I.getArgOperand(0)))); return 0; case Intrinsic::convert_from_fp16: setValue(&I, DAG.getNode(ISD::FP16_TO_FP32, dl, MVT::f32, getValue(I.getArgOperand(0)))); return 0; case Intrinsic::pcmarker: { SDValue Tmp = getValue(I.getArgOperand(0)); DAG.setRoot(DAG.getNode(ISD::PCMARKER, dl, MVT::Other, getRoot(), Tmp)); return 0; } case Intrinsic::readcyclecounter: { SDValue Op = getRoot(); Res = DAG.getNode(ISD::READCYCLECOUNTER, dl, DAG.getVTList(MVT::i64, MVT::Other), &Op, 1); setValue(&I, Res); DAG.setRoot(Res.getValue(1)); return 0; } case Intrinsic::bswap: setValue(&I, DAG.getNode(ISD::BSWAP, dl, getValue(I.getArgOperand(0)).getValueType(), getValue(I.getArgOperand(0)))); return 0; case Intrinsic::cttz: { SDValue Arg = getValue(I.getArgOperand(0)); EVT Ty = Arg.getValueType(); setValue(&I, DAG.getNode(ISD::CTTZ, dl, Ty, Arg)); return 0; } case Intrinsic::ctlz: { SDValue Arg = getValue(I.getArgOperand(0)); EVT Ty = Arg.getValueType(); setValue(&I, DAG.getNode(ISD::CTLZ, dl, Ty, Arg)); return 0; } case Intrinsic::ctpop: { SDValue Arg = getValue(I.getArgOperand(0)); EVT Ty = Arg.getValueType(); setValue(&I, DAG.getNode(ISD::CTPOP, dl, Ty, Arg)); return 0; } case Intrinsic::stacksave: { SDValue Op = getRoot(); Res = DAG.getNode(ISD::STACKSAVE, dl, DAG.getVTList(TLI.getPointerTy(), MVT::Other), &Op, 1); setValue(&I, Res); DAG.setRoot(Res.getValue(1)); return 0; } case Intrinsic::stackrestore: { Res = getValue(I.getArgOperand(0)); DAG.setRoot(DAG.getNode(ISD::STACKRESTORE, dl, MVT::Other, getRoot(), Res)); return 0; } case Intrinsic::stackprotector: { // Emit code into the DAG to store the stack guard onto the stack. MachineFunction &MF = DAG.getMachineFunction(); MachineFrameInfo *MFI = MF.getFrameInfo(); EVT PtrTy = TLI.getPointerTy(); SDValue Src = getValue(I.getArgOperand(0)); // The guard's value. AllocaInst *Slot = cast(I.getArgOperand(1)); int FI = FuncInfo.StaticAllocaMap[Slot]; MFI->setStackProtectorIndex(FI); SDValue FIN = DAG.getFrameIndex(FI, PtrTy); // Store the stack protector onto the stack. Res = DAG.getStore(getRoot(), getCurDebugLoc(), Src, FIN, MachinePointerInfo::getFixedStack(FI), true, false, 0); setValue(&I, Res); DAG.setRoot(Res); return 0; } case Intrinsic::objectsize: { // If we don't know by now, we're never going to know. ConstantInt *CI = dyn_cast(I.getArgOperand(1)); assert(CI && "Non-constant type in __builtin_object_size?"); SDValue Arg = getValue(I.getCalledValue()); EVT Ty = Arg.getValueType(); if (CI->isZero()) Res = DAG.getConstant(-1ULL, Ty); else Res = DAG.getConstant(0, Ty); setValue(&I, Res); return 0; } case Intrinsic::var_annotation: // Discard annotate attributes return 0; case Intrinsic::init_trampoline: { const Function *F = cast(I.getArgOperand(1)->stripPointerCasts()); SDValue Ops[6]; Ops[0] = getRoot(); Ops[1] = getValue(I.getArgOperand(0)); Ops[2] = getValue(I.getArgOperand(1)); Ops[3] = getValue(I.getArgOperand(2)); Ops[4] = DAG.getSrcValue(I.getArgOperand(0)); Ops[5] = DAG.getSrcValue(F); Res = DAG.getNode(ISD::INIT_TRAMPOLINE, dl, MVT::Other, Ops, 6); DAG.setRoot(Res); return 0; } case Intrinsic::adjust_trampoline: { setValue(&I, DAG.getNode(ISD::ADJUST_TRAMPOLINE, dl, TLI.getPointerTy(), getValue(I.getArgOperand(0)))); return 0; } case Intrinsic::gcroot: if (GFI) { const Value *Alloca = I.getArgOperand(0); const Constant *TypeMap = cast(I.getArgOperand(1)); FrameIndexSDNode *FI = cast(getValue(Alloca).getNode()); GFI->addStackRoot(FI->getIndex(), TypeMap); } return 0; case Intrinsic::gcread: case Intrinsic::gcwrite: llvm_unreachable("GC failed to lower gcread/gcwrite intrinsics!"); return 0; case Intrinsic::flt_rounds: setValue(&I, DAG.getNode(ISD::FLT_ROUNDS_, dl, MVT::i32)); return 0; case Intrinsic::expect: { // Just replace __builtin_expect(exp, c) with EXP. setValue(&I, getValue(I.getArgOperand(0))); return 0; } case Intrinsic::trap: { StringRef TrapFuncName = getTrapFunctionName(); if (TrapFuncName.empty()) { DAG.setRoot(DAG.getNode(ISD::TRAP, dl,MVT::Other, getRoot())); return 0; } TargetLowering::ArgListTy Args; std::pair Result = TLI.LowerCallTo(getRoot(), I.getType(), false, false, false, false, 0, CallingConv::C, /*isTailCall=*/false, /*isReturnValueUsed=*/true, DAG.getExternalSymbol(TrapFuncName.data(), TLI.getPointerTy()), Args, DAG, getCurDebugLoc()); DAG.setRoot(Result.second); return 0; } case Intrinsic::uadd_with_overflow: return implVisitAluOverflow(I, ISD::UADDO); case Intrinsic::sadd_with_overflow: return implVisitAluOverflow(I, ISD::SADDO); case Intrinsic::usub_with_overflow: return implVisitAluOverflow(I, ISD::USUBO); case Intrinsic::ssub_with_overflow: return implVisitAluOverflow(I, ISD::SSUBO); case Intrinsic::umul_with_overflow: return implVisitAluOverflow(I, ISD::UMULO); case Intrinsic::smul_with_overflow: return implVisitAluOverflow(I, ISD::SMULO); case Intrinsic::prefetch: { SDValue Ops[5]; unsigned rw = cast(I.getArgOperand(1))->getZExtValue(); Ops[0] = getRoot(); Ops[1] = getValue(I.getArgOperand(0)); Ops[2] = getValue(I.getArgOperand(1)); Ops[3] = getValue(I.getArgOperand(2)); Ops[4] = getValue(I.getArgOperand(3)); DAG.setRoot(DAG.getMemIntrinsicNode(ISD::PREFETCH, dl, DAG.getVTList(MVT::Other), &Ops[0], 5, EVT::getIntegerVT(*Context, 8), MachinePointerInfo(I.getArgOperand(0)), 0, /* align */ false, /* volatile */ rw==0, /* read */ rw==1)); /* write */ return 0; } case Intrinsic::invariant_start: case Intrinsic::lifetime_start: // Discard region information. setValue(&I, DAG.getUNDEF(TLI.getPointerTy())); return 0; case Intrinsic::invariant_end: case Intrinsic::lifetime_end: // Discard region information. return 0; } } void SelectionDAGBuilder::LowerCallTo(ImmutableCallSite CS, SDValue Callee, bool isTailCall, MachineBasicBlock *LandingPad) { PointerType *PT = cast(CS.getCalledValue()->getType()); FunctionType *FTy = cast(PT->getElementType()); Type *RetTy = FTy->getReturnType(); MachineModuleInfo &MMI = DAG.getMachineFunction().getMMI(); MCSymbol *BeginLabel = 0; TargetLowering::ArgListTy Args; TargetLowering::ArgListEntry Entry; Args.reserve(CS.arg_size()); // Check whether the function can return without sret-demotion. SmallVector Outs; SmallVector Offsets; GetReturnInfo(RetTy, CS.getAttributes().getRetAttributes(), Outs, TLI, &Offsets); bool CanLowerReturn = TLI.CanLowerReturn(CS.getCallingConv(), DAG.getMachineFunction(), FTy->isVarArg(), Outs, FTy->getContext()); SDValue DemoteStackSlot; int DemoteStackIdx = -100; if (!CanLowerReturn) { uint64_t TySize = TLI.getTargetData()->getTypeAllocSize( FTy->getReturnType()); unsigned Align = TLI.getTargetData()->getPrefTypeAlignment( FTy->getReturnType()); MachineFunction &MF = DAG.getMachineFunction(); DemoteStackIdx = MF.getFrameInfo()->CreateStackObject(TySize, Align, false); Type *StackSlotPtrType = PointerType::getUnqual(FTy->getReturnType()); DemoteStackSlot = DAG.getFrameIndex(DemoteStackIdx, TLI.getPointerTy()); Entry.Node = DemoteStackSlot; Entry.Ty = StackSlotPtrType; Entry.isSExt = false; Entry.isZExt = false; Entry.isInReg = false; Entry.isSRet = true; Entry.isNest = false; Entry.isByVal = false; Entry.Alignment = Align; Args.push_back(Entry); RetTy = Type::getVoidTy(FTy->getContext()); } for (ImmutableCallSite::arg_iterator i = CS.arg_begin(), e = CS.arg_end(); i != e; ++i) { const Value *V = *i; // Skip empty types if (V->getType()->isEmptyTy()) continue; SDValue ArgNode = getValue(V); Entry.Node = ArgNode; Entry.Ty = V->getType(); unsigned attrInd = i - CS.arg_begin() + 1; Entry.isSExt = CS.paramHasAttr(attrInd, Attribute::SExt); Entry.isZExt = CS.paramHasAttr(attrInd, Attribute::ZExt); Entry.isInReg = CS.paramHasAttr(attrInd, Attribute::InReg); Entry.isSRet = CS.paramHasAttr(attrInd, Attribute::StructRet); Entry.isNest = CS.paramHasAttr(attrInd, Attribute::Nest); Entry.isByVal = CS.paramHasAttr(attrInd, Attribute::ByVal); Entry.Alignment = CS.getParamAlignment(attrInd); Args.push_back(Entry); } if (LandingPad) { // Insert a label before the invoke call to mark the try range. This can be // used to detect deletion of the invoke via the MachineModuleInfo. BeginLabel = MMI.getContext().CreateTempSymbol(); // For SjLj, keep track of which landing pads go with which invokes // so as to maintain the ordering of pads in the LSDA. unsigned CallSiteIndex = MMI.getCurrentCallSite(); if (CallSiteIndex) { MMI.setCallSiteBeginLabel(BeginLabel, CallSiteIndex); LPadToCallSiteMap[LandingPad].push_back(CallSiteIndex); // Now that the call site is handled, stop tracking it. MMI.setCurrentCallSite(0); } // Both PendingLoads and PendingExports must be flushed here; // this call might not return. (void)getRoot(); DAG.setRoot(DAG.getEHLabel(getCurDebugLoc(), getControlRoot(), BeginLabel)); } // Check if target-independent constraints permit a tail call here. // Target-dependent constraints are checked within TLI.LowerCallTo. if (isTailCall && !isInTailCallPosition(CS, CS.getAttributes().getRetAttributes(), TLI)) isTailCall = false; // If there's a possibility that fast-isel has already selected some amount // of the current basic block, don't emit a tail call. if (isTailCall && EnableFastISel) isTailCall = false; std::pair Result = TLI.LowerCallTo(getRoot(), RetTy, CS.paramHasAttr(0, Attribute::SExt), CS.paramHasAttr(0, Attribute::ZExt), FTy->isVarArg(), CS.paramHasAttr(0, Attribute::InReg), FTy->getNumParams(), CS.getCallingConv(), isTailCall, !CS.getInstruction()->use_empty(), Callee, Args, DAG, getCurDebugLoc()); assert((isTailCall || Result.second.getNode()) && "Non-null chain expected with non-tail call!"); assert((Result.second.getNode() || !Result.first.getNode()) && "Null value expected with tail call!"); if (Result.first.getNode()) { setValue(CS.getInstruction(), Result.first); } else if (!CanLowerReturn && Result.second.getNode()) { // The instruction result is the result of loading from the // hidden sret parameter. SmallVector PVTs; Type *PtrRetTy = PointerType::getUnqual(FTy->getReturnType()); ComputeValueVTs(TLI, PtrRetTy, PVTs); assert(PVTs.size() == 1 && "Pointers should fit in one register"); EVT PtrVT = PVTs[0]; unsigned NumValues = Outs.size(); SmallVector Values(NumValues); SmallVector Chains(NumValues); for (unsigned i = 0; i < NumValues; ++i) { SDValue Add = DAG.getNode(ISD::ADD, getCurDebugLoc(), PtrVT, DemoteStackSlot, DAG.getConstant(Offsets[i], PtrVT)); SDValue L = DAG.getLoad(Outs[i].VT, getCurDebugLoc(), Result.second, Add, MachinePointerInfo::getFixedStack(DemoteStackIdx, Offsets[i]), false, false, 1); Values[i] = L; Chains[i] = L.getValue(1); } SDValue Chain = DAG.getNode(ISD::TokenFactor, getCurDebugLoc(), MVT::Other, &Chains[0], NumValues); PendingLoads.push_back(Chain); // Collect the legal value parts into potentially illegal values // that correspond to the original function's return values. SmallVector RetTys; RetTy = FTy->getReturnType(); ComputeValueVTs(TLI, RetTy, RetTys); ISD::NodeType AssertOp = ISD::DELETED_NODE; SmallVector ReturnValues; unsigned CurReg = 0; for (unsigned I = 0, E = RetTys.size(); I != E; ++I) { EVT VT = RetTys[I]; EVT RegisterVT = TLI.getRegisterType(RetTy->getContext(), VT); unsigned NumRegs = TLI.getNumRegisters(RetTy->getContext(), VT); SDValue ReturnValue = getCopyFromParts(DAG, getCurDebugLoc(), &Values[CurReg], NumRegs, RegisterVT, VT, AssertOp); ReturnValues.push_back(ReturnValue); CurReg += NumRegs; } setValue(CS.getInstruction(), DAG.getNode(ISD::MERGE_VALUES, getCurDebugLoc(), DAG.getVTList(&RetTys[0], RetTys.size()), &ReturnValues[0], ReturnValues.size())); } // Assign order to nodes here. If the call does not produce a result, it won't // be mapped to a SDNode and visit() will not assign it an order number. if (!Result.second.getNode()) { // As a special case, a null chain means that a tail call has been emitted and // the DAG root is already updated. HasTailCall = true; ++SDNodeOrder; AssignOrderingToNode(DAG.getRoot().getNode()); } else { DAG.setRoot(Result.second); ++SDNodeOrder; AssignOrderingToNode(Result.second.getNode()); } if (LandingPad) { // Insert a label at the end of the invoke call to mark the try range. This // can be used to detect deletion of the invoke via the MachineModuleInfo. MCSymbol *EndLabel = MMI.getContext().CreateTempSymbol(); DAG.setRoot(DAG.getEHLabel(getCurDebugLoc(), getRoot(), EndLabel)); // Inform MachineModuleInfo of range. MMI.addInvoke(LandingPad, BeginLabel, EndLabel); } } /// IsOnlyUsedInZeroEqualityComparison - Return true if it only matters that the /// value is equal or not-equal to zero. static bool IsOnlyUsedInZeroEqualityComparison(const Value *V) { for (Value::const_use_iterator UI = V->use_begin(), E = V->use_end(); UI != E; ++UI) { if (const ICmpInst *IC = dyn_cast(*UI)) if (IC->isEquality()) if (const Constant *C = dyn_cast(IC->getOperand(1))) if (C->isNullValue()) continue; // Unknown instruction. return false; } return true; } static SDValue getMemCmpLoad(const Value *PtrVal, MVT LoadVT, Type *LoadTy, SelectionDAGBuilder &Builder) { // Check to see if this load can be trivially constant folded, e.g. if the // input is from a string literal. if (const Constant *LoadInput = dyn_cast(PtrVal)) { // Cast pointer to the type we really want to load. LoadInput = ConstantExpr::getBitCast(const_cast(LoadInput), PointerType::getUnqual(LoadTy)); if (const Constant *LoadCst = ConstantFoldLoadFromConstPtr(const_cast(LoadInput), Builder.TD)) return Builder.getValue(LoadCst); } // Otherwise, we have to emit the load. If the pointer is to unfoldable but // still constant memory, the input chain can be the entry node. SDValue Root; bool ConstantMemory = false; // Do not serialize (non-volatile) loads of constant memory with anything. if (Builder.AA->pointsToConstantMemory(PtrVal)) { Root = Builder.DAG.getEntryNode(); ConstantMemory = true; } else { // Do not serialize non-volatile loads against each other. Root = Builder.DAG.getRoot(); } SDValue Ptr = Builder.getValue(PtrVal); SDValue LoadVal = Builder.DAG.getLoad(LoadVT, Builder.getCurDebugLoc(), Root, Ptr, MachinePointerInfo(PtrVal), false /*volatile*/, false /*nontemporal*/, 1 /* align=1 */); if (!ConstantMemory) Builder.PendingLoads.push_back(LoadVal.getValue(1)); return LoadVal; } /// visitMemCmpCall - See if we can lower a call to memcmp in an optimized form. /// If so, return true and lower it, otherwise return false and it will be /// lowered like a normal call. bool SelectionDAGBuilder::visitMemCmpCall(const CallInst &I) { // Verify that the prototype makes sense. int memcmp(void*,void*,size_t) if (I.getNumArgOperands() != 3) return false; const Value *LHS = I.getArgOperand(0), *RHS = I.getArgOperand(1); if (!LHS->getType()->isPointerTy() || !RHS->getType()->isPointerTy() || !I.getArgOperand(2)->getType()->isIntegerTy() || !I.getType()->isIntegerTy()) return false; const ConstantInt *Size = dyn_cast(I.getArgOperand(2)); // memcmp(S1,S2,2) != 0 -> (*(short*)LHS != *(short*)RHS) != 0 // memcmp(S1,S2,4) != 0 -> (*(int*)LHS != *(int*)RHS) != 0 if (Size && IsOnlyUsedInZeroEqualityComparison(&I)) { bool ActuallyDoIt = true; MVT LoadVT; Type *LoadTy; switch (Size->getZExtValue()) { default: LoadVT = MVT::Other; LoadTy = 0; ActuallyDoIt = false; break; case 2: LoadVT = MVT::i16; LoadTy = Type::getInt16Ty(Size->getContext()); break; case 4: LoadVT = MVT::i32; LoadTy = Type::getInt32Ty(Size->getContext()); break; case 8: LoadVT = MVT::i64; LoadTy = Type::getInt64Ty(Size->getContext()); break; /* case 16: LoadVT = MVT::v4i32; LoadTy = Type::getInt32Ty(Size->getContext()); LoadTy = VectorType::get(LoadTy, 4); break; */ } // This turns into unaligned loads. We only do this if the target natively // supports the MVT we'll be loading or if it is small enough (<= 4) that // we'll only produce a small number of byte loads. // Require that we can find a legal MVT, and only do this if the target // supports unaligned loads of that type. Expanding into byte loads would // bloat the code. if (ActuallyDoIt && Size->getZExtValue() > 4) { // TODO: Handle 5 byte compare as 4-byte + 1 byte. // TODO: Handle 8 byte compare on x86-32 as two 32-bit loads. if (!TLI.isTypeLegal(LoadVT) ||!TLI.allowsUnalignedMemoryAccesses(LoadVT)) ActuallyDoIt = false; } if (ActuallyDoIt) { SDValue LHSVal = getMemCmpLoad(LHS, LoadVT, LoadTy, *this); SDValue RHSVal = getMemCmpLoad(RHS, LoadVT, LoadTy, *this); SDValue Res = DAG.getSetCC(getCurDebugLoc(), MVT::i1, LHSVal, RHSVal, ISD::SETNE); EVT CallVT = TLI.getValueType(I.getType(), true); setValue(&I, DAG.getZExtOrTrunc(Res, getCurDebugLoc(), CallVT)); return true; } } return false; } void SelectionDAGBuilder::visitCall(const CallInst &I) { // Handle inline assembly differently. if (isa(I.getCalledValue())) { visitInlineAsm(&I); return; } // See if any floating point values are being passed to this function. This is // used to emit an undefined reference to fltused on Windows. FunctionType *FT = cast(I.getCalledValue()->getType()->getContainedType(0)); MachineModuleInfo &MMI = DAG.getMachineFunction().getMMI(); if (FT->isVarArg() && !MMI.callsExternalVAFunctionWithFloatingPointArguments()) { for (unsigned i = 0, e = I.getNumArgOperands(); i != e; ++i) { Type* T = I.getArgOperand(i)->getType(); for (po_iterator i = po_begin(T), e = po_end(T); i != e; ++i) { if (!i->isFloatingPointTy()) continue; MMI.setCallsExternalVAFunctionWithFloatingPointArguments(true); break; } } } const char *RenameFn = 0; if (Function *F = I.getCalledFunction()) { if (F->isDeclaration()) { if (const TargetIntrinsicInfo *II = TM.getIntrinsicInfo()) { if (unsigned IID = II->getIntrinsicID(F)) { RenameFn = visitIntrinsicCall(I, IID); if (!RenameFn) return; } } if (unsigned IID = F->getIntrinsicID()) { RenameFn = visitIntrinsicCall(I, IID); if (!RenameFn) return; } } // Check for well-known libc/libm calls. If the function is internal, it // can't be a library call. if (!F->hasLocalLinkage() && F->hasName()) { StringRef Name = F->getName(); if (Name == "copysign" || Name == "copysignf" || Name == "copysignl") { if (I.getNumArgOperands() == 2 && // Basic sanity checks. I.getArgOperand(0)->getType()->isFloatingPointTy() && I.getType() == I.getArgOperand(0)->getType() && I.getType() == I.getArgOperand(1)->getType()) { SDValue LHS = getValue(I.getArgOperand(0)); SDValue RHS = getValue(I.getArgOperand(1)); setValue(&I, DAG.getNode(ISD::FCOPYSIGN, getCurDebugLoc(), LHS.getValueType(), LHS, RHS)); return; } } else if (Name == "fabs" || Name == "fabsf" || Name == "fabsl") { if (I.getNumArgOperands() == 1 && // Basic sanity checks. I.getArgOperand(0)->getType()->isFloatingPointTy() && I.getType() == I.getArgOperand(0)->getType()) { SDValue Tmp = getValue(I.getArgOperand(0)); setValue(&I, DAG.getNode(ISD::FABS, getCurDebugLoc(), Tmp.getValueType(), Tmp)); return; } } else if (Name == "sin" || Name == "sinf" || Name == "sinl") { if (I.getNumArgOperands() == 1 && // Basic sanity checks. I.getArgOperand(0)->getType()->isFloatingPointTy() && I.getType() == I.getArgOperand(0)->getType() && I.onlyReadsMemory()) { SDValue Tmp = getValue(I.getArgOperand(0)); setValue(&I, DAG.getNode(ISD::FSIN, getCurDebugLoc(), Tmp.getValueType(), Tmp)); return; } } else if (Name == "cos" || Name == "cosf" || Name == "cosl") { if (I.getNumArgOperands() == 1 && // Basic sanity checks. I.getArgOperand(0)->getType()->isFloatingPointTy() && I.getType() == I.getArgOperand(0)->getType() && I.onlyReadsMemory()) { SDValue Tmp = getValue(I.getArgOperand(0)); setValue(&I, DAG.getNode(ISD::FCOS, getCurDebugLoc(), Tmp.getValueType(), Tmp)); return; } } else if (Name == "sqrt" || Name == "sqrtf" || Name == "sqrtl") { if (I.getNumArgOperands() == 1 && // Basic sanity checks. I.getArgOperand(0)->getType()->isFloatingPointTy() && I.getType() == I.getArgOperand(0)->getType() && I.onlyReadsMemory()) { SDValue Tmp = getValue(I.getArgOperand(0)); setValue(&I, DAG.getNode(ISD::FSQRT, getCurDebugLoc(), Tmp.getValueType(), Tmp)); return; } } else if (Name == "memcmp") { if (visitMemCmpCall(I)) return; } } } SDValue Callee; if (!RenameFn) Callee = getValue(I.getCalledValue()); else Callee = DAG.getExternalSymbol(RenameFn, TLI.getPointerTy()); // Check if we can potentially perform a tail call. More detailed checking is // be done within LowerCallTo, after more information about the call is known. LowerCallTo(&I, Callee, I.isTailCall()); } namespace { /// AsmOperandInfo - This contains information for each constraint that we are /// lowering. class SDISelAsmOperandInfo : public TargetLowering::AsmOperandInfo { public: /// CallOperand - If this is the result output operand or a clobber /// this is null, otherwise it is the incoming operand to the CallInst. /// This gets modified as the asm is processed. SDValue CallOperand; /// AssignedRegs - If this is a register or register class operand, this /// contains the set of register corresponding to the operand. RegsForValue AssignedRegs; explicit SDISelAsmOperandInfo(const TargetLowering::AsmOperandInfo &info) : TargetLowering::AsmOperandInfo(info), CallOperand(0,0) { } /// MarkAllocatedRegs - Once AssignedRegs is set, mark the assigned registers /// busy in OutputRegs/InputRegs. void MarkAllocatedRegs(bool isOutReg, bool isInReg, std::set &OutputRegs, std::set &InputRegs, const TargetRegisterInfo &TRI) const { if (isOutReg) { for (unsigned i = 0, e = AssignedRegs.Regs.size(); i != e; ++i) MarkRegAndAliases(AssignedRegs.Regs[i], OutputRegs, TRI); } if (isInReg) { for (unsigned i = 0, e = AssignedRegs.Regs.size(); i != e; ++i) MarkRegAndAliases(AssignedRegs.Regs[i], InputRegs, TRI); } } /// getCallOperandValEVT - Return the EVT of the Value* that this operand /// corresponds to. If there is no Value* for this operand, it returns /// MVT::Other. EVT getCallOperandValEVT(LLVMContext &Context, const TargetLowering &TLI, const TargetData *TD) const { if (CallOperandVal == 0) return MVT::Other; if (isa(CallOperandVal)) return TLI.getPointerTy(); llvm::Type *OpTy = CallOperandVal->getType(); // FIXME: code duplicated from TargetLowering::ParseConstraints(). // If this is an indirect operand, the operand is a pointer to the // accessed type. if (isIndirect) { llvm::PointerType *PtrTy = dyn_cast(OpTy); if (!PtrTy) report_fatal_error("Indirect operand for inline asm not a pointer!"); OpTy = PtrTy->getElementType(); } // Look for vector wrapped in a struct. e.g. { <16 x i8> }. if (StructType *STy = dyn_cast(OpTy)) if (STy->getNumElements() == 1) OpTy = STy->getElementType(0); // If OpTy is not a single value, it may be a struct/union that we // can tile with integers. if (!OpTy->isSingleValueType() && OpTy->isSized()) { unsigned BitSize = TD->getTypeSizeInBits(OpTy); switch (BitSize) { default: break; case 1: case 8: case 16: case 32: case 64: case 128: OpTy = IntegerType::get(Context, BitSize); break; } } return TLI.getValueType(OpTy, true); } private: /// MarkRegAndAliases - Mark the specified register and all aliases in the /// specified set. static void MarkRegAndAliases(unsigned Reg, std::set &Regs, const TargetRegisterInfo &TRI) { assert(TargetRegisterInfo::isPhysicalRegister(Reg) && "Isn't a physreg"); Regs.insert(Reg); if (const unsigned *Aliases = TRI.getAliasSet(Reg)) for (; *Aliases; ++Aliases) Regs.insert(*Aliases); } }; typedef SmallVector SDISelAsmOperandInfoVector; } // end anonymous namespace /// GetRegistersForValue - Assign registers (virtual or physical) for the /// specified operand. We prefer to assign virtual registers, to allow the /// register allocator to handle the assignment process. However, if the asm /// uses features that we can't model on machineinstrs, we have SDISel do the /// allocation. This produces generally horrible, but correct, code. /// /// OpInfo describes the operand. /// Input and OutputRegs are the set of already allocated physical registers. /// static void GetRegistersForValue(SelectionDAG &DAG, const TargetLowering &TLI, DebugLoc DL, SDISelAsmOperandInfo &OpInfo, std::set &OutputRegs, std::set &InputRegs) { LLVMContext &Context = *DAG.getContext(); // Compute whether this value requires an input register, an output register, // or both. bool isOutReg = false; bool isInReg = false; switch (OpInfo.Type) { case InlineAsm::isOutput: isOutReg = true; // If there is an input constraint that matches this, we need to reserve // the input register so no other inputs allocate to it. isInReg = OpInfo.hasMatchingInput(); break; case InlineAsm::isInput: isInReg = true; isOutReg = false; break; case InlineAsm::isClobber: isOutReg = true; isInReg = true; break; } MachineFunction &MF = DAG.getMachineFunction(); SmallVector Regs; // If this is a constraint for a single physreg, or a constraint for a // register class, find it. std::pair PhysReg = TLI.getRegForInlineAsmConstraint(OpInfo.ConstraintCode, OpInfo.ConstraintVT); unsigned NumRegs = 1; if (OpInfo.ConstraintVT != MVT::Other) { // If this is a FP input in an integer register (or visa versa) insert a bit // cast of the input value. More generally, handle any case where the input // value disagrees with the register class we plan to stick this in. if (OpInfo.Type == InlineAsm::isInput && PhysReg.second && !PhysReg.second->hasType(OpInfo.ConstraintVT)) { // Try to convert to the first EVT that the reg class contains. If the // types are identical size, use a bitcast to convert (e.g. two differing // vector types). EVT RegVT = *PhysReg.second->vt_begin(); if (RegVT.getSizeInBits() == OpInfo.ConstraintVT.getSizeInBits()) { OpInfo.CallOperand = DAG.getNode(ISD::BITCAST, DL, RegVT, OpInfo.CallOperand); OpInfo.ConstraintVT = RegVT; } else if (RegVT.isInteger() && OpInfo.ConstraintVT.isFloatingPoint()) { // If the input is a FP value and we want it in FP registers, do a // bitcast to the corresponding integer type. This turns an f64 value // into i64, which can be passed with two i32 values on a 32-bit // machine. RegVT = EVT::getIntegerVT(Context, OpInfo.ConstraintVT.getSizeInBits()); OpInfo.CallOperand = DAG.getNode(ISD::BITCAST, DL, RegVT, OpInfo.CallOperand); OpInfo.ConstraintVT = RegVT; } } NumRegs = TLI.getNumRegisters(Context, OpInfo.ConstraintVT); } EVT RegVT; EVT ValueVT = OpInfo.ConstraintVT; // If this is a constraint for a specific physical register, like {r17}, // assign it now. if (unsigned AssignedReg = PhysReg.first) { const TargetRegisterClass *RC = PhysReg.second; if (OpInfo.ConstraintVT == MVT::Other) ValueVT = *RC->vt_begin(); // Get the actual register value type. This is important, because the user // may have asked for (e.g.) the AX register in i32 type. We need to // remember that AX is actually i16 to get the right extension. RegVT = *RC->vt_begin(); // This is a explicit reference to a physical register. Regs.push_back(AssignedReg); // If this is an expanded reference, add the rest of the regs to Regs. if (NumRegs != 1) { TargetRegisterClass::iterator I = RC->begin(); for (; *I != AssignedReg; ++I) assert(I != RC->end() && "Didn't find reg!"); // Already added the first reg. --NumRegs; ++I; for (; NumRegs; --NumRegs, ++I) { assert(I != RC->end() && "Ran out of registers to allocate!"); Regs.push_back(*I); } } OpInfo.AssignedRegs = RegsForValue(Regs, RegVT, ValueVT); const TargetRegisterInfo *TRI = DAG.getTarget().getRegisterInfo(); OpInfo.MarkAllocatedRegs(isOutReg, isInReg, OutputRegs, InputRegs, *TRI); return; } // Otherwise, if this was a reference to an LLVM register class, create vregs // for this reference. if (const TargetRegisterClass *RC = PhysReg.second) { RegVT = *RC->vt_begin(); if (OpInfo.ConstraintVT == MVT::Other) ValueVT = RegVT; // Create the appropriate number of virtual registers. MachineRegisterInfo &RegInfo = MF.getRegInfo(); for (; NumRegs; --NumRegs) Regs.push_back(RegInfo.createVirtualRegister(RC)); OpInfo.AssignedRegs = RegsForValue(Regs, RegVT, ValueVT); return; } // Otherwise, we couldn't allocate enough registers for this. } /// visitInlineAsm - Handle a call to an InlineAsm object. /// void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { const InlineAsm *IA = cast(CS.getCalledValue()); /// ConstraintOperands - Information about all of the constraints. SDISelAsmOperandInfoVector ConstraintOperands; std::set OutputRegs, InputRegs; TargetLowering::AsmOperandInfoVector TargetConstraints = TLI.ParseConstraints(CS); bool hasMemory = false; unsigned ArgNo = 0; // ArgNo - The argument of the CallInst. unsigned ResNo = 0; // ResNo - The result number of the next output. for (unsigned i = 0, e = TargetConstraints.size(); i != e; ++i) { ConstraintOperands.push_back(SDISelAsmOperandInfo(TargetConstraints[i])); SDISelAsmOperandInfo &OpInfo = ConstraintOperands.back(); EVT OpVT = MVT::Other; // Compute the value type for each operand. switch (OpInfo.Type) { case InlineAsm::isOutput: // Indirect outputs just consume an argument. if (OpInfo.isIndirect) { OpInfo.CallOperandVal = const_cast(CS.getArgument(ArgNo++)); break; } // The return value of the call is this value. As such, there is no // corresponding argument. assert(!CS.getType()->isVoidTy() && "Bad inline asm!"); if (StructType *STy = dyn_cast(CS.getType())) { OpVT = TLI.getValueType(STy->getElementType(ResNo)); } else { assert(ResNo == 0 && "Asm only has one result!"); OpVT = TLI.getValueType(CS.getType()); } ++ResNo; break; case InlineAsm::isInput: OpInfo.CallOperandVal = const_cast(CS.getArgument(ArgNo++)); break; case InlineAsm::isClobber: // Nothing to do. break; } // If this is an input or an indirect output, process the call argument. // BasicBlocks are labels, currently appearing only in asm's. if (OpInfo.CallOperandVal) { if (const BasicBlock *BB = dyn_cast(OpInfo.CallOperandVal)) { OpInfo.CallOperand = DAG.getBasicBlock(FuncInfo.MBBMap[BB]); } else { OpInfo.CallOperand = getValue(OpInfo.CallOperandVal); } OpVT = OpInfo.getCallOperandValEVT(*DAG.getContext(), TLI, TD); } OpInfo.ConstraintVT = OpVT; // Indirect operand accesses access memory. if (OpInfo.isIndirect) hasMemory = true; else { for (unsigned j = 0, ee = OpInfo.Codes.size(); j != ee; ++j) { TargetLowering::ConstraintType CType = TLI.getConstraintType(OpInfo.Codes[j]); if (CType == TargetLowering::C_Memory) { hasMemory = true; break; } } } } SDValue Chain, Flag; // We won't need to flush pending loads if this asm doesn't touch // memory and is nonvolatile. if (hasMemory || IA->hasSideEffects()) Chain = getRoot(); else Chain = DAG.getRoot(); // Second pass over the constraints: compute which constraint option to use // and assign registers to constraints that want a specific physreg. for (unsigned i = 0, e = ConstraintOperands.size(); i != e; ++i) { SDISelAsmOperandInfo &OpInfo = ConstraintOperands[i]; // If this is an output operand with a matching input operand, look up the // matching input. If their types mismatch, e.g. one is an integer, the // other is floating point, or their sizes are different, flag it as an // error. if (OpInfo.hasMatchingInput()) { SDISelAsmOperandInfo &Input = ConstraintOperands[OpInfo.MatchingInput]; if (OpInfo.ConstraintVT != Input.ConstraintVT) { std::pair MatchRC = TLI.getRegForInlineAsmConstraint(OpInfo.ConstraintCode, OpInfo.ConstraintVT); std::pair InputRC = TLI.getRegForInlineAsmConstraint(Input.ConstraintCode, Input.ConstraintVT); if ((OpInfo.ConstraintVT.isInteger() != Input.ConstraintVT.isInteger()) || (MatchRC.second != InputRC.second)) { report_fatal_error("Unsupported asm: input constraint" " with a matching output constraint of" " incompatible type!"); } Input.ConstraintVT = OpInfo.ConstraintVT; } } // Compute the constraint code and ConstraintType to use. TLI.ComputeConstraintToUse(OpInfo, OpInfo.CallOperand, &DAG); // If this is a memory input, and if the operand is not indirect, do what we // need to to provide an address for the memory input. if (OpInfo.ConstraintType == TargetLowering::C_Memory && !OpInfo.isIndirect) { assert((OpInfo.isMultipleAlternative || (OpInfo.Type == InlineAsm::isInput)) && "Can only indirectify direct input operands!"); // Memory operands really want the address of the value. If we don't have // an indirect input, put it in the constpool if we can, otherwise spill // it to a stack slot. // TODO: This isn't quite right. We need to handle these according to // the addressing mode that the constraint wants. Also, this may take // an additional register for the computation and we don't want that // either. // If the operand is a float, integer, or vector constant, spill to a // constant pool entry to get its address. const Value *OpVal = OpInfo.CallOperandVal; if (isa(OpVal) || isa(OpVal) || isa(OpVal)) { OpInfo.CallOperand = DAG.getConstantPool(cast(OpVal), TLI.getPointerTy()); } else { // Otherwise, create a stack slot and emit a store to it before the // asm. Type *Ty = OpVal->getType(); uint64_t TySize = TLI.getTargetData()->getTypeAllocSize(Ty); unsigned Align = TLI.getTargetData()->getPrefTypeAlignment(Ty); MachineFunction &MF = DAG.getMachineFunction(); int SSFI = MF.getFrameInfo()->CreateStackObject(TySize, Align, false); SDValue StackSlot = DAG.getFrameIndex(SSFI, TLI.getPointerTy()); Chain = DAG.getStore(Chain, getCurDebugLoc(), OpInfo.CallOperand, StackSlot, MachinePointerInfo::getFixedStack(SSFI), false, false, 0); OpInfo.CallOperand = StackSlot; } // There is no longer a Value* corresponding to this operand. OpInfo.CallOperandVal = 0; // It is now an indirect operand. OpInfo.isIndirect = true; } // If this constraint is for a specific register, allocate it before // anything else. if (OpInfo.ConstraintType == TargetLowering::C_Register) GetRegistersForValue(DAG, TLI, getCurDebugLoc(), OpInfo, OutputRegs, InputRegs); } // Second pass - Loop over all of the operands, assigning virtual or physregs // to register class operands. for (unsigned i = 0, e = ConstraintOperands.size(); i != e; ++i) { SDISelAsmOperandInfo &OpInfo = ConstraintOperands[i]; // C_Register operands have already been allocated, Other/Memory don't need // to be. if (OpInfo.ConstraintType == TargetLowering::C_RegisterClass) GetRegistersForValue(DAG, TLI, getCurDebugLoc(), OpInfo, OutputRegs, InputRegs); } // AsmNodeOperands - The operands for the ISD::INLINEASM node. std::vector AsmNodeOperands; AsmNodeOperands.push_back(SDValue()); // reserve space for input chain AsmNodeOperands.push_back( DAG.getTargetExternalSymbol(IA->getAsmString().c_str(), TLI.getPointerTy())); // If we have a !srcloc metadata node associated with it, we want to attach // this to the ultimately generated inline asm machineinstr. To do this, we // pass in the third operand as this (potentially null) inline asm MDNode. const MDNode *SrcLoc = CS.getInstruction()->getMetadata("srcloc"); AsmNodeOperands.push_back(DAG.getMDNode(SrcLoc)); // Remember the HasSideEffect and AlignStack bits as operand 3. unsigned ExtraInfo = 0; if (IA->hasSideEffects()) ExtraInfo |= InlineAsm::Extra_HasSideEffects; if (IA->isAlignStack()) ExtraInfo |= InlineAsm::Extra_IsAlignStack; AsmNodeOperands.push_back(DAG.getTargetConstant(ExtraInfo, TLI.getPointerTy())); // Loop over all of the inputs, copying the operand values into the // appropriate registers and processing the output regs. RegsForValue RetValRegs; // IndirectStoresToEmit - The set of stores to emit after the inline asm node. std::vector > IndirectStoresToEmit; for (unsigned i = 0, e = ConstraintOperands.size(); i != e; ++i) { SDISelAsmOperandInfo &OpInfo = ConstraintOperands[i]; switch (OpInfo.Type) { case InlineAsm::isOutput: { if (OpInfo.ConstraintType != TargetLowering::C_RegisterClass && OpInfo.ConstraintType != TargetLowering::C_Register) { // Memory output, or 'other' output (e.g. 'X' constraint). assert(OpInfo.isIndirect && "Memory output must be indirect operand"); // Add information to the INLINEASM node to know about this output. unsigned OpFlags = InlineAsm::getFlagWord(InlineAsm::Kind_Mem, 1); AsmNodeOperands.push_back(DAG.getTargetConstant(OpFlags, TLI.getPointerTy())); AsmNodeOperands.push_back(OpInfo.CallOperand); break; } // Otherwise, this is a register or register class output. // Copy the output from the appropriate register. Find a register that // we can use. if (OpInfo.AssignedRegs.Regs.empty()) report_fatal_error("Couldn't allocate output reg for constraint '" + Twine(OpInfo.ConstraintCode) + "'!"); // If this is an indirect operand, store through the pointer after the // asm. if (OpInfo.isIndirect) { IndirectStoresToEmit.push_back(std::make_pair(OpInfo.AssignedRegs, OpInfo.CallOperandVal)); } else { // This is the result value of the call. assert(!CS.getType()->isVoidTy() && "Bad inline asm!"); // Concatenate this output onto the outputs list. RetValRegs.append(OpInfo.AssignedRegs); } // Add information to the INLINEASM node to know that this register is // set. OpInfo.AssignedRegs.AddInlineAsmOperands(OpInfo.isEarlyClobber ? InlineAsm::Kind_RegDefEarlyClobber : InlineAsm::Kind_RegDef, false, 0, DAG, AsmNodeOperands); break; } case InlineAsm::isInput: { SDValue InOperandVal = OpInfo.CallOperand; if (OpInfo.isMatchingInputConstraint()) { // Matching constraint? // If this is required to match an output register we have already set, // just use its register. unsigned OperandNo = OpInfo.getMatchedOperand(); // Scan until we find the definition we already emitted of this operand. // When we find it, create a RegsForValue operand. unsigned CurOp = InlineAsm::Op_FirstOperand; for (; OperandNo; --OperandNo) { // Advance to the next operand. unsigned OpFlag = cast(AsmNodeOperands[CurOp])->getZExtValue(); assert((InlineAsm::isRegDefKind(OpFlag) || InlineAsm::isRegDefEarlyClobberKind(OpFlag) || InlineAsm::isMemKind(OpFlag)) && "Skipped past definitions?"); CurOp += InlineAsm::getNumOperandRegisters(OpFlag)+1; } unsigned OpFlag = cast(AsmNodeOperands[CurOp])->getZExtValue(); if (InlineAsm::isRegDefKind(OpFlag) || InlineAsm::isRegDefEarlyClobberKind(OpFlag)) { // Add (OpFlag&0xffff)>>3 registers to MatchedRegs. if (OpInfo.isIndirect) { // This happens on gcc/testsuite/gcc.dg/pr8788-1.c LLVMContext &Ctx = *DAG.getContext(); Ctx.emitError(CS.getInstruction(), "inline asm not supported yet:" " don't know how to handle tied " "indirect register inputs"); } RegsForValue MatchedRegs; MatchedRegs.ValueVTs.push_back(InOperandVal.getValueType()); EVT RegVT = AsmNodeOperands[CurOp+1].getValueType(); MatchedRegs.RegVTs.push_back(RegVT); MachineRegisterInfo &RegInfo = DAG.getMachineFunction().getRegInfo(); for (unsigned i = 0, e = InlineAsm::getNumOperandRegisters(OpFlag); i != e; ++i) MatchedRegs.Regs.push_back (RegInfo.createVirtualRegister(TLI.getRegClassFor(RegVT))); // Use the produced MatchedRegs object to MatchedRegs.getCopyToRegs(InOperandVal, DAG, getCurDebugLoc(), Chain, &Flag); MatchedRegs.AddInlineAsmOperands(InlineAsm::Kind_RegUse, true, OpInfo.getMatchedOperand(), DAG, AsmNodeOperands); break; } assert(InlineAsm::isMemKind(OpFlag) && "Unknown matching constraint!"); assert(InlineAsm::getNumOperandRegisters(OpFlag) == 1 && "Unexpected number of operands"); // Add information to the INLINEASM node to know about this input. // See InlineAsm.h isUseOperandTiedToDef. OpFlag = InlineAsm::getFlagWordForMatchingOp(OpFlag, OpInfo.getMatchedOperand()); AsmNodeOperands.push_back(DAG.getTargetConstant(OpFlag, TLI.getPointerTy())); AsmNodeOperands.push_back(AsmNodeOperands[CurOp+1]); break; } // Treat indirect 'X' constraint as memory. if (OpInfo.ConstraintType == TargetLowering::C_Other && OpInfo.isIndirect) OpInfo.ConstraintType = TargetLowering::C_Memory; if (OpInfo.ConstraintType == TargetLowering::C_Other) { std::vector Ops; TLI.LowerAsmOperandForConstraint(InOperandVal, OpInfo.ConstraintCode, Ops, DAG); if (Ops.empty()) report_fatal_error("Invalid operand for inline asm constraint '" + Twine(OpInfo.ConstraintCode) + "'!"); // Add information to the INLINEASM node to know about this input. unsigned ResOpType = InlineAsm::getFlagWord(InlineAsm::Kind_Imm, Ops.size()); AsmNodeOperands.push_back(DAG.getTargetConstant(ResOpType, TLI.getPointerTy())); AsmNodeOperands.insert(AsmNodeOperands.end(), Ops.begin(), Ops.end()); break; } if (OpInfo.ConstraintType == TargetLowering::C_Memory) { assert(OpInfo.isIndirect && "Operand must be indirect to be a mem!"); assert(InOperandVal.getValueType() == TLI.getPointerTy() && "Memory operands expect pointer values"); // Add information to the INLINEASM node to know about this input. unsigned ResOpType = InlineAsm::getFlagWord(InlineAsm::Kind_Mem, 1); AsmNodeOperands.push_back(DAG.getTargetConstant(ResOpType, TLI.getPointerTy())); AsmNodeOperands.push_back(InOperandVal); break; } assert((OpInfo.ConstraintType == TargetLowering::C_RegisterClass || OpInfo.ConstraintType == TargetLowering::C_Register) && "Unknown constraint type!"); assert(!OpInfo.isIndirect && "Don't know how to handle indirect register inputs yet!"); // Copy the input into the appropriate registers. if (OpInfo.AssignedRegs.Regs.empty()) report_fatal_error("Couldn't allocate input reg for constraint '" + Twine(OpInfo.ConstraintCode) + "'!"); OpInfo.AssignedRegs.getCopyToRegs(InOperandVal, DAG, getCurDebugLoc(), Chain, &Flag); OpInfo.AssignedRegs.AddInlineAsmOperands(InlineAsm::Kind_RegUse, false, 0, DAG, AsmNodeOperands); break; } case InlineAsm::isClobber: { // Add the clobbered value to the operand list, so that the register // allocator is aware that the physreg got clobbered. if (!OpInfo.AssignedRegs.Regs.empty()) OpInfo.AssignedRegs.AddInlineAsmOperands(InlineAsm::Kind_Clobber, false, 0, DAG, AsmNodeOperands); break; } } } // Finish up input operands. Set the input chain and add the flag last. AsmNodeOperands[InlineAsm::Op_InputChain] = Chain; if (Flag.getNode()) AsmNodeOperands.push_back(Flag); Chain = DAG.getNode(ISD::INLINEASM, getCurDebugLoc(), DAG.getVTList(MVT::Other, MVT::Glue), &AsmNodeOperands[0], AsmNodeOperands.size()); Flag = Chain.getValue(1); // If this asm returns a register value, copy the result from that register // and set it as the value of the call. if (!RetValRegs.Regs.empty()) { SDValue Val = RetValRegs.getCopyFromRegs(DAG, FuncInfo, getCurDebugLoc(), Chain, &Flag); // FIXME: Why don't we do this for inline asms with MRVs? if (CS.getType()->isSingleValueType() && CS.getType()->isSized()) { EVT ResultType = TLI.getValueType(CS.getType()); // If any of the results of the inline asm is a vector, it may have the // wrong width/num elts. This can happen for register classes that can // contain multiple different value types. The preg or vreg allocated may // not have the same VT as was expected. Convert it to the right type // with bit_convert. if (ResultType != Val.getValueType() && Val.getValueType().isVector()) { Val = DAG.getNode(ISD::BITCAST, getCurDebugLoc(), ResultType, Val); } else if (ResultType != Val.getValueType() && ResultType.isInteger() && Val.getValueType().isInteger()) { // If a result value was tied to an input value, the computed result may // have a wider width than the expected result. Extract the relevant // portion. Val = DAG.getNode(ISD::TRUNCATE, getCurDebugLoc(), ResultType, Val); } assert(ResultType == Val.getValueType() && "Asm result value mismatch!"); } setValue(CS.getInstruction(), Val); // Don't need to use this as a chain in this case. if (!IA->hasSideEffects() && !hasMemory && IndirectStoresToEmit.empty()) return; } std::vector > StoresToEmit; // Process indirect outputs, first output all of the flagged copies out of // physregs. for (unsigned i = 0, e = IndirectStoresToEmit.size(); i != e; ++i) { RegsForValue &OutRegs = IndirectStoresToEmit[i].first; const Value *Ptr = IndirectStoresToEmit[i].second; SDValue OutVal = OutRegs.getCopyFromRegs(DAG, FuncInfo, getCurDebugLoc(), Chain, &Flag); StoresToEmit.push_back(std::make_pair(OutVal, Ptr)); } // Emit the non-flagged stores from the physregs. SmallVector OutChains; for (unsigned i = 0, e = StoresToEmit.size(); i != e; ++i) { SDValue Val = DAG.getStore(Chain, getCurDebugLoc(), StoresToEmit[i].first, getValue(StoresToEmit[i].second), MachinePointerInfo(StoresToEmit[i].second), false, false, 0); OutChains.push_back(Val); } if (!OutChains.empty()) Chain = DAG.getNode(ISD::TokenFactor, getCurDebugLoc(), MVT::Other, &OutChains[0], OutChains.size()); DAG.setRoot(Chain); } void SelectionDAGBuilder::visitVAStart(const CallInst &I) { DAG.setRoot(DAG.getNode(ISD::VASTART, getCurDebugLoc(), MVT::Other, getRoot(), getValue(I.getArgOperand(0)), DAG.getSrcValue(I.getArgOperand(0)))); } void SelectionDAGBuilder::visitVAArg(const VAArgInst &I) { const TargetData &TD = *TLI.getTargetData(); SDValue V = DAG.getVAArg(TLI.getValueType(I.getType()), getCurDebugLoc(), getRoot(), getValue(I.getOperand(0)), DAG.getSrcValue(I.getOperand(0)), TD.getABITypeAlignment(I.getType())); setValue(&I, V); DAG.setRoot(V.getValue(1)); } void SelectionDAGBuilder::visitVAEnd(const CallInst &I) { DAG.setRoot(DAG.getNode(ISD::VAEND, getCurDebugLoc(), MVT::Other, getRoot(), getValue(I.getArgOperand(0)), DAG.getSrcValue(I.getArgOperand(0)))); } void SelectionDAGBuilder::visitVACopy(const CallInst &I) { DAG.setRoot(DAG.getNode(ISD::VACOPY, getCurDebugLoc(), MVT::Other, getRoot(), getValue(I.getArgOperand(0)), getValue(I.getArgOperand(1)), DAG.getSrcValue(I.getArgOperand(0)), DAG.getSrcValue(I.getArgOperand(1)))); } /// TargetLowering::LowerCallTo - This is the default LowerCallTo /// implementation, which just calls LowerCall. /// FIXME: When all targets are /// migrated to using LowerCall, this hook should be integrated into SDISel. std::pair TargetLowering::LowerCallTo(SDValue Chain, Type *RetTy, bool RetSExt, bool RetZExt, bool isVarArg, bool isInreg, unsigned NumFixedArgs, CallingConv::ID CallConv, bool isTailCall, bool isReturnValueUsed, SDValue Callee, ArgListTy &Args, SelectionDAG &DAG, DebugLoc dl) const { // Handle all of the outgoing arguments. SmallVector Outs; SmallVector OutVals; for (unsigned i = 0, e = Args.size(); i != e; ++i) { SmallVector ValueVTs; ComputeValueVTs(*this, Args[i].Ty, ValueVTs); for (unsigned Value = 0, NumValues = ValueVTs.size(); Value != NumValues; ++Value) { EVT VT = ValueVTs[Value]; Type *ArgTy = VT.getTypeForEVT(RetTy->getContext()); SDValue Op = SDValue(Args[i].Node.getNode(), Args[i].Node.getResNo() + Value); ISD::ArgFlagsTy Flags; unsigned OriginalAlignment = getTargetData()->getABITypeAlignment(ArgTy); if (Args[i].isZExt) Flags.setZExt(); if (Args[i].isSExt) Flags.setSExt(); if (Args[i].isInReg) Flags.setInReg(); if (Args[i].isSRet) Flags.setSRet(); if (Args[i].isByVal) { Flags.setByVal(); PointerType *Ty = cast(Args[i].Ty); Type *ElementTy = Ty->getElementType(); Flags.setByValSize(getTargetData()->getTypeAllocSize(ElementTy)); // For ByVal, alignment should come from FE. BE will guess if this // info is not there but there are cases it cannot get right. unsigned FrameAlign; if (Args[i].Alignment) FrameAlign = Args[i].Alignment; else FrameAlign = getByValTypeAlignment(ElementTy); Flags.setByValAlign(FrameAlign); } if (Args[i].isNest) Flags.setNest(); Flags.setOrigAlign(OriginalAlignment); EVT PartVT = getRegisterType(RetTy->getContext(), VT); unsigned NumParts = getNumRegisters(RetTy->getContext(), VT); SmallVector Parts(NumParts); ISD::NodeType ExtendKind = ISD::ANY_EXTEND; if (Args[i].isSExt) ExtendKind = ISD::SIGN_EXTEND; else if (Args[i].isZExt) ExtendKind = ISD::ZERO_EXTEND; getCopyToParts(DAG, dl, Op, &Parts[0], NumParts, PartVT, ExtendKind); for (unsigned j = 0; j != NumParts; ++j) { // if it isn't first piece, alignment must be 1 ISD::OutputArg MyFlags(Flags, Parts[j].getValueType(), i < NumFixedArgs); if (NumParts > 1 && j == 0) MyFlags.Flags.setSplit(); else if (j != 0) MyFlags.Flags.setOrigAlign(1); Outs.push_back(MyFlags); OutVals.push_back(Parts[j]); } } } // Handle the incoming return values from the call. SmallVector Ins; SmallVector RetTys; ComputeValueVTs(*this, RetTy, RetTys); for (unsigned I = 0, E = RetTys.size(); I != E; ++I) { EVT VT = RetTys[I]; EVT RegisterVT = getRegisterType(RetTy->getContext(), VT); unsigned NumRegs = getNumRegisters(RetTy->getContext(), VT); for (unsigned i = 0; i != NumRegs; ++i) { ISD::InputArg MyFlags; MyFlags.VT = RegisterVT.getSimpleVT(); MyFlags.Used = isReturnValueUsed; if (RetSExt) MyFlags.Flags.setSExt(); if (RetZExt) MyFlags.Flags.setZExt(); if (isInreg) MyFlags.Flags.setInReg(); Ins.push_back(MyFlags); } } SmallVector InVals; Chain = LowerCall(Chain, Callee, CallConv, isVarArg, isTailCall, Outs, OutVals, Ins, dl, DAG, InVals); // Verify that the target's LowerCall behaved as expected. assert(Chain.getNode() && Chain.getValueType() == MVT::Other && "LowerCall didn't return a valid chain!"); assert((!isTailCall || InVals.empty()) && "LowerCall emitted a return value for a tail call!"); assert((isTailCall || InVals.size() == Ins.size()) && "LowerCall didn't emit the correct number of values!"); // For a tail call, the return value is merely live-out and there aren't // any nodes in the DAG representing it. Return a special value to // indicate that a tail call has been emitted and no more Instructions // should be processed in the current block. if (isTailCall) { DAG.setRoot(Chain); return std::make_pair(SDValue(), SDValue()); } DEBUG(for (unsigned i = 0, e = Ins.size(); i != e; ++i) { assert(InVals[i].getNode() && "LowerCall emitted a null value!"); assert(EVT(Ins[i].VT) == InVals[i].getValueType() && "LowerCall emitted a value with the wrong type!"); }); // Collect the legal value parts into potentially illegal values // that correspond to the original function's return values. ISD::NodeType AssertOp = ISD::DELETED_NODE; if (RetSExt) AssertOp = ISD::AssertSext; else if (RetZExt) AssertOp = ISD::AssertZext; SmallVector ReturnValues; unsigned CurReg = 0; for (unsigned I = 0, E = RetTys.size(); I != E; ++I) { EVT VT = RetTys[I]; EVT RegisterVT = getRegisterType(RetTy->getContext(), VT); unsigned NumRegs = getNumRegisters(RetTy->getContext(), VT); ReturnValues.push_back(getCopyFromParts(DAG, dl, &InVals[CurReg], NumRegs, RegisterVT, VT, AssertOp)); CurReg += NumRegs; } // For a function returning void, there is no return value. We can't create // such a node, so we just return a null return value in that case. In // that case, nothing will actually look at the value. if (ReturnValues.empty()) return std::make_pair(SDValue(), Chain); SDValue Res = DAG.getNode(ISD::MERGE_VALUES, dl, DAG.getVTList(&RetTys[0], RetTys.size()), &ReturnValues[0], ReturnValues.size()); return std::make_pair(Res, Chain); } void TargetLowering::LowerOperationWrapper(SDNode *N, SmallVectorImpl &Results, SelectionDAG &DAG) const { SDValue Res = LowerOperation(SDValue(N, 0), DAG); if (Res.getNode()) Results.push_back(Res); } SDValue TargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { llvm_unreachable("LowerOperation not implemented for this target!"); return SDValue(); } void SelectionDAGBuilder::CopyValueToVirtualRegister(const Value *V, unsigned Reg) { SDValue Op = getNonRegisterValue(V); assert((Op.getOpcode() != ISD::CopyFromReg || cast(Op.getOperand(1))->getReg() != Reg) && "Copy from a reg to the same reg!"); assert(!TargetRegisterInfo::isPhysicalRegister(Reg) && "Is a physreg"); RegsForValue RFV(V->getContext(), TLI, Reg, V->getType()); SDValue Chain = DAG.getEntryNode(); RFV.getCopyToRegs(Op, DAG, getCurDebugLoc(), Chain, 0); PendingExports.push_back(Chain); } #include "llvm/CodeGen/SelectionDAGISel.h" /// isOnlyUsedInEntryBlock - If the specified argument is only used in the /// entry block, return true. This includes arguments used by switches, since /// the switch may expand into multiple basic blocks. static bool isOnlyUsedInEntryBlock(const Argument *A) { // With FastISel active, we may be splitting blocks, so force creation // of virtual registers for all non-dead arguments. if (EnableFastISel) return A->use_empty(); const BasicBlock *Entry = A->getParent()->begin(); for (Value::const_use_iterator UI = A->use_begin(), E = A->use_end(); UI != E; ++UI) { const User *U = *UI; if (cast(U)->getParent() != Entry || isa(U)) return false; // Use not in entry block. } return true; } void SelectionDAGISel::LowerArguments(const BasicBlock *LLVMBB) { // If this is the entry block, emit arguments. const Function &F = *LLVMBB->getParent(); SelectionDAG &DAG = SDB->DAG; DebugLoc dl = SDB->getCurDebugLoc(); const TargetData *TD = TLI.getTargetData(); SmallVector Ins; // Check whether the function can return without sret-demotion. SmallVector Outs; GetReturnInfo(F.getReturnType(), F.getAttributes().getRetAttributes(), Outs, TLI); if (!FuncInfo->CanLowerReturn) { // Put in an sret pointer parameter before all the other parameters. SmallVector ValueVTs; ComputeValueVTs(TLI, PointerType::getUnqual(F.getReturnType()), ValueVTs); // NOTE: Assuming that a pointer will never break down to more than one VT // or one register. ISD::ArgFlagsTy Flags; Flags.setSRet(); EVT RegisterVT = TLI.getRegisterType(*DAG.getContext(), ValueVTs[0]); ISD::InputArg RetArg(Flags, RegisterVT, true); Ins.push_back(RetArg); } // Set up the incoming argument description vector. unsigned Idx = 1; for (Function::const_arg_iterator I = F.arg_begin(), E = F.arg_end(); I != E; ++I, ++Idx) { SmallVector ValueVTs; ComputeValueVTs(TLI, I->getType(), ValueVTs); bool isArgValueUsed = !I->use_empty(); for (unsigned Value = 0, NumValues = ValueVTs.size(); Value != NumValues; ++Value) { EVT VT = ValueVTs[Value]; Type *ArgTy = VT.getTypeForEVT(*DAG.getContext()); ISD::ArgFlagsTy Flags; unsigned OriginalAlignment = TD->getABITypeAlignment(ArgTy); if (F.paramHasAttr(Idx, Attribute::ZExt)) Flags.setZExt(); if (F.paramHasAttr(Idx, Attribute::SExt)) Flags.setSExt(); if (F.paramHasAttr(Idx, Attribute::InReg)) Flags.setInReg(); if (F.paramHasAttr(Idx, Attribute::StructRet)) Flags.setSRet(); if (F.paramHasAttr(Idx, Attribute::ByVal)) { Flags.setByVal(); PointerType *Ty = cast(I->getType()); Type *ElementTy = Ty->getElementType(); Flags.setByValSize(TD->getTypeAllocSize(ElementTy)); // For ByVal, alignment should be passed from FE. BE will guess if // this info is not there but there are cases it cannot get right. unsigned FrameAlign; if (F.getParamAlignment(Idx)) FrameAlign = F.getParamAlignment(Idx); else FrameAlign = TLI.getByValTypeAlignment(ElementTy); Flags.setByValAlign(FrameAlign); } if (F.paramHasAttr(Idx, Attribute::Nest)) Flags.setNest(); Flags.setOrigAlign(OriginalAlignment); EVT RegisterVT = TLI.getRegisterType(*CurDAG->getContext(), VT); unsigned NumRegs = TLI.getNumRegisters(*CurDAG->getContext(), VT); for (unsigned i = 0; i != NumRegs; ++i) { ISD::InputArg MyFlags(Flags, RegisterVT, isArgValueUsed); if (NumRegs > 1 && i == 0) MyFlags.Flags.setSplit(); // if it isn't first piece, alignment must be 1 else if (i > 0) MyFlags.Flags.setOrigAlign(1); Ins.push_back(MyFlags); } } } // Call the target to set up the argument values. SmallVector InVals; SDValue NewRoot = TLI.LowerFormalArguments(DAG.getRoot(), F.getCallingConv(), F.isVarArg(), Ins, dl, DAG, InVals); // Verify that the target's LowerFormalArguments behaved as expected. assert(NewRoot.getNode() && NewRoot.getValueType() == MVT::Other && "LowerFormalArguments didn't return a valid chain!"); assert(InVals.size() == Ins.size() && "LowerFormalArguments didn't emit the correct number of values!"); DEBUG({ for (unsigned i = 0, e = Ins.size(); i != e; ++i) { assert(InVals[i].getNode() && "LowerFormalArguments emitted a null value!"); assert(EVT(Ins[i].VT) == InVals[i].getValueType() && "LowerFormalArguments emitted a value with the wrong type!"); } }); // Update the DAG with the new chain value resulting from argument lowering. DAG.setRoot(NewRoot); // Set up the argument values. unsigned i = 0; Idx = 1; if (!FuncInfo->CanLowerReturn) { // Create a virtual register for the sret pointer, and put in a copy // from the sret argument into it. SmallVector ValueVTs; ComputeValueVTs(TLI, PointerType::getUnqual(F.getReturnType()), ValueVTs); EVT VT = ValueVTs[0]; EVT RegVT = TLI.getRegisterType(*CurDAG->getContext(), VT); ISD::NodeType AssertOp = ISD::DELETED_NODE; SDValue ArgValue = getCopyFromParts(DAG, dl, &InVals[0], 1, RegVT, VT, AssertOp); MachineFunction& MF = SDB->DAG.getMachineFunction(); MachineRegisterInfo& RegInfo = MF.getRegInfo(); unsigned SRetReg = RegInfo.createVirtualRegister(TLI.getRegClassFor(RegVT)); FuncInfo->DemoteRegister = SRetReg; NewRoot = SDB->DAG.getCopyToReg(NewRoot, SDB->getCurDebugLoc(), SRetReg, ArgValue); DAG.setRoot(NewRoot); // i indexes lowered arguments. Bump it past the hidden sret argument. // Idx indexes LLVM arguments. Don't touch it. ++i; } for (Function::const_arg_iterator I = F.arg_begin(), E = F.arg_end(); I != E; ++I, ++Idx) { SmallVector ArgValues; SmallVector ValueVTs; ComputeValueVTs(TLI, I->getType(), ValueVTs); unsigned NumValues = ValueVTs.size(); // If this argument is unused then remember its value. It is used to generate // debugging information. if (I->use_empty() && NumValues) SDB->setUnusedArgValue(I, InVals[i]); for (unsigned Val = 0; Val != NumValues; ++Val) { EVT VT = ValueVTs[Val]; EVT PartVT = TLI.getRegisterType(*CurDAG->getContext(), VT); unsigned NumParts = TLI.getNumRegisters(*CurDAG->getContext(), VT); if (!I->use_empty()) { ISD::NodeType AssertOp = ISD::DELETED_NODE; if (F.paramHasAttr(Idx, Attribute::SExt)) AssertOp = ISD::AssertSext; else if (F.paramHasAttr(Idx, Attribute::ZExt)) AssertOp = ISD::AssertZext; ArgValues.push_back(getCopyFromParts(DAG, dl, &InVals[i], NumParts, PartVT, VT, AssertOp)); } i += NumParts; } // We don't need to do anything else for unused arguments. if (ArgValues.empty()) continue; // Note down frame index. if (FrameIndexSDNode *FI = dyn_cast(ArgValues[0].getNode())) FuncInfo->setArgumentFrameIndex(I, FI->getIndex()); SDValue Res = DAG.getMergeValues(&ArgValues[0], NumValues, SDB->getCurDebugLoc()); SDB->setValue(I, Res); if (!EnableFastISel && Res.getOpcode() == ISD::BUILD_PAIR) { if (LoadSDNode *LNode = dyn_cast(Res.getOperand(0).getNode())) if (FrameIndexSDNode *FI = dyn_cast(LNode->getBasePtr().getNode())) FuncInfo->setArgumentFrameIndex(I, FI->getIndex()); } // If this argument is live outside of the entry block, insert a copy from // wherever we got it to the vreg that other BB's will reference it as. if (!EnableFastISel && Res.getOpcode() == ISD::CopyFromReg) { // If we can, though, try to skip creating an unnecessary vreg. // FIXME: This isn't very clean... it would be nice to make this more // general. It's also subtly incompatible with the hacks FastISel // uses with vregs. unsigned Reg = cast(Res.getOperand(1))->getReg(); if (TargetRegisterInfo::isVirtualRegister(Reg)) { FuncInfo->ValueMap[I] = Reg; continue; } } if (!isOnlyUsedInEntryBlock(I)) { FuncInfo->InitializeRegForValue(I); SDB->CopyToExportRegsIfNeeded(I); } } assert(i == InVals.size() && "Argument register count mismatch!"); // Finally, if the target has anything special to do, allow it to do so. // FIXME: this should insert code into the DAG! EmitFunctionEntryCode(); } /// Handle PHI nodes in successor blocks. Emit code into the SelectionDAG to /// ensure constants are generated when needed. Remember the virtual registers /// that need to be added to the Machine PHI nodes as input. We cannot just /// directly add them, because expansion might result in multiple MBB's for one /// BB. As such, the start of the BB might correspond to a different MBB than /// the end. /// void SelectionDAGBuilder::HandlePHINodesInSuccessorBlocks(const BasicBlock *LLVMBB) { const TerminatorInst *TI = LLVMBB->getTerminator(); SmallPtrSet SuccsHandled; // Check successor nodes' PHI nodes that expect a constant to be available // from this block. for (unsigned succ = 0, e = TI->getNumSuccessors(); succ != e; ++succ) { const BasicBlock *SuccBB = TI->getSuccessor(succ); if (!isa(SuccBB->begin())) continue; MachineBasicBlock *SuccMBB = FuncInfo.MBBMap[SuccBB]; // If this terminator has multiple identical successors (common for // switches), only handle each succ once. if (!SuccsHandled.insert(SuccMBB)) continue; MachineBasicBlock::iterator MBBI = SuccMBB->begin(); // At this point we know that there is a 1-1 correspondence between LLVM PHI // nodes and Machine PHI nodes, but the incoming operands have not been // emitted yet. for (BasicBlock::const_iterator I = SuccBB->begin(); const PHINode *PN = dyn_cast(I); ++I) { // Ignore dead phi's. if (PN->use_empty()) continue; // Skip empty types if (PN->getType()->isEmptyTy()) continue; unsigned Reg; const Value *PHIOp = PN->getIncomingValueForBlock(LLVMBB); if (const Constant *C = dyn_cast(PHIOp)) { unsigned &RegOut = ConstantsOut[C]; if (RegOut == 0) { RegOut = FuncInfo.CreateRegs(C->getType()); CopyValueToVirtualRegister(C, RegOut); } Reg = RegOut; } else { DenseMap::iterator I = FuncInfo.ValueMap.find(PHIOp); if (I != FuncInfo.ValueMap.end()) Reg = I->second; else { assert(isa(PHIOp) && FuncInfo.StaticAllocaMap.count(cast(PHIOp)) && "Didn't codegen value into a register!??"); Reg = FuncInfo.CreateRegs(PHIOp->getType()); CopyValueToVirtualRegister(PHIOp, Reg); } } // Remember that this register needs to added to the machine PHI node as // the input for this MBB. SmallVector ValueVTs; ComputeValueVTs(TLI, PN->getType(), ValueVTs); for (unsigned vti = 0, vte = ValueVTs.size(); vti != vte; ++vti) { EVT VT = ValueVTs[vti]; unsigned NumRegisters = TLI.getNumRegisters(*DAG.getContext(), VT); for (unsigned i = 0, e = NumRegisters; i != e; ++i) FuncInfo.PHINodesToUpdate.push_back(std::make_pair(MBBI++, Reg+i)); Reg += NumRegisters; } } } ConstantsOut.clear(); } Index: head/contrib/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp =================================================================== --- head/contrib/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp (revision 228378) +++ head/contrib/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp (revision 228379) @@ -1,625 +1,629 @@ //===-- llvm/CodeGen/TargetLoweringObjectFileImpl.cpp - Object File Info --===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements classes used to handle lowerings specific to common // object file formats. // //===----------------------------------------------------------------------===// #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" #include "llvm/Function.h" #include "llvm/GlobalVariable.h" #include "llvm/CodeGen/MachineModuleInfoImpls.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSectionCOFF.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Target/Mangler.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/ELF.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" using namespace llvm; using namespace dwarf; //===----------------------------------------------------------------------===// // ELF //===----------------------------------------------------------------------===// MCSymbol * TargetLoweringObjectFileELF::getCFIPersonalitySymbol(const GlobalValue *GV, Mangler *Mang, MachineModuleInfo *MMI) const { unsigned Encoding = getPersonalityEncoding(); switch (Encoding & 0x70) { default: report_fatal_error("We do not support this DWARF encoding yet!"); case dwarf::DW_EH_PE_absptr: return Mang->getSymbol(GV); break; case dwarf::DW_EH_PE_pcrel: { return getContext().GetOrCreateSymbol(StringRef("DW.ref.") + Mang->getSymbol(GV)->getName()); break; } } } void TargetLoweringObjectFileELF::emitPersonalityValue(MCStreamer &Streamer, const TargetMachine &TM, const MCSymbol *Sym) const { SmallString<64> NameData("DW.ref."); NameData += Sym->getName(); MCSymbol *Label = getContext().GetOrCreateSymbol(NameData); Streamer.EmitSymbolAttribute(Label, MCSA_Hidden); Streamer.EmitSymbolAttribute(Label, MCSA_Weak); StringRef Prefix = ".data."; NameData.insert(NameData.begin(), Prefix.begin(), Prefix.end()); unsigned Flags = ELF::SHF_ALLOC | ELF::SHF_WRITE | ELF::SHF_GROUP; const MCSection *Sec = getContext().getELFSection(NameData, ELF::SHT_PROGBITS, Flags, SectionKind::getDataRel(), 0, Label->getName()); Streamer.SwitchSection(Sec); Streamer.EmitValueToAlignment(8); Streamer.EmitSymbolAttribute(Label, MCSA_ELF_TypeObject); const MCExpr *E = MCConstantExpr::Create(8, getContext()); Streamer.EmitELFSize(Label, E); Streamer.EmitLabel(Label); unsigned Size = TM.getTargetData()->getPointerSize(); Streamer.EmitSymbolValue(Sym, Size); } static SectionKind getELFKindForNamedSection(StringRef Name, SectionKind K) { // N.B.: The defaults used in here are no the same ones used in MC. // We follow gcc, MC follows gas. For example, given ".section .eh_frame", // both gas and MC will produce a section with no flags. Given // section(".eh_frame") gcc will produce // .section .eh_frame,"a",@progbits if (Name.empty() || Name[0] != '.') return K; // Some lame default implementation based on some magic section names. if (Name == ".bss" || Name.startswith(".bss.") || Name.startswith(".gnu.linkonce.b.") || Name.startswith(".llvm.linkonce.b.") || Name == ".sbss" || Name.startswith(".sbss.") || Name.startswith(".gnu.linkonce.sb.") || Name.startswith(".llvm.linkonce.sb.")) return SectionKind::getBSS(); if (Name == ".tdata" || Name.startswith(".tdata.") || Name.startswith(".gnu.linkonce.td.") || Name.startswith(".llvm.linkonce.td.")) return SectionKind::getThreadData(); if (Name == ".tbss" || Name.startswith(".tbss.") || Name.startswith(".gnu.linkonce.tb.") || Name.startswith(".llvm.linkonce.tb.")) return SectionKind::getThreadBSS(); return K; } static unsigned getELFSectionType(StringRef Name, SectionKind K) { if (Name == ".init_array") return ELF::SHT_INIT_ARRAY; if (Name == ".fini_array") return ELF::SHT_FINI_ARRAY; if (Name == ".preinit_array") return ELF::SHT_PREINIT_ARRAY; if (K.isBSS() || K.isThreadBSS()) return ELF::SHT_NOBITS; return ELF::SHT_PROGBITS; } static unsigned getELFSectionFlags(SectionKind K) { unsigned Flags = 0; if (!K.isMetadata()) Flags |= ELF::SHF_ALLOC; if (K.isText()) Flags |= ELF::SHF_EXECINSTR; if (K.isWriteable()) Flags |= ELF::SHF_WRITE; if (K.isThreadLocal()) Flags |= ELF::SHF_TLS; // K.isMergeableConst() is left out to honour PR4650 if (K.isMergeableCString() || K.isMergeableConst4() || K.isMergeableConst8() || K.isMergeableConst16()) Flags |= ELF::SHF_MERGE; if (K.isMergeableCString()) Flags |= ELF::SHF_STRINGS; return Flags; } const MCSection *TargetLoweringObjectFileELF:: getExplicitSectionGlobal(const GlobalValue *GV, SectionKind Kind, Mangler *Mang, const TargetMachine &TM) const { StringRef SectionName = GV->getSection(); // Infer section flags from the section name if we can. Kind = getELFKindForNamedSection(SectionName, Kind); return getContext().getELFSection(SectionName, getELFSectionType(SectionName, Kind), getELFSectionFlags(Kind), Kind); } /// getSectionPrefixForGlobal - Return the section prefix name used by options /// FunctionsSections and DataSections. static const char *getSectionPrefixForGlobal(SectionKind Kind) { if (Kind.isText()) return ".text."; if (Kind.isReadOnly()) return ".rodata."; if (Kind.isThreadData()) return ".tdata."; if (Kind.isThreadBSS()) return ".tbss."; if (Kind.isDataNoRel()) return ".data."; if (Kind.isDataRelLocal()) return ".data.rel.local."; if (Kind.isDataRel()) return ".data.rel."; if (Kind.isReadOnlyWithRelLocal()) return ".data.rel.ro.local."; assert(Kind.isReadOnlyWithRel() && "Unknown section kind"); return ".data.rel.ro."; } const MCSection *TargetLoweringObjectFileELF:: SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, Mangler *Mang, const TargetMachine &TM) const { // If we have -ffunction-section or -fdata-section then we should emit the // global value to a uniqued section specifically for it. bool EmitUniquedSection; if (Kind.isText()) EmitUniquedSection = TM.getFunctionSections(); else EmitUniquedSection = TM.getDataSections(); // If this global is linkonce/weak and the target handles this by emitting it // into a 'uniqued' section name, create and return the section now. if ((GV->isWeakForLinker() || EmitUniquedSection) && !Kind.isCommon() && !Kind.isBSS()) { const char *Prefix; Prefix = getSectionPrefixForGlobal(Kind); SmallString<128> Name(Prefix, Prefix+strlen(Prefix)); MCSymbol *Sym = Mang->getSymbol(GV); Name.append(Sym->getName().begin(), Sym->getName().end()); StringRef Group = ""; unsigned Flags = getELFSectionFlags(Kind); if (GV->isWeakForLinker()) { Group = Sym->getName(); Flags |= ELF::SHF_GROUP; } return getContext().getELFSection(Name.str(), getELFSectionType(Name.str(), Kind), Flags, Kind, 0, Group); } if (Kind.isText()) return TextSection; if (Kind.isMergeable1ByteCString() || Kind.isMergeable2ByteCString() || Kind.isMergeable4ByteCString()) { // We also need alignment here. // FIXME: this is getting the alignment of the character, not the // alignment of the global! unsigned Align = TM.getTargetData()->getPreferredAlignment(cast(GV)); const char *SizeSpec = ".rodata.str1."; if (Kind.isMergeable2ByteCString()) SizeSpec = ".rodata.str2."; else if (Kind.isMergeable4ByteCString()) SizeSpec = ".rodata.str4."; else assert(Kind.isMergeable1ByteCString() && "unknown string width"); std::string Name = SizeSpec + utostr(Align); return getContext().getELFSection(Name, ELF::SHT_PROGBITS, ELF::SHF_ALLOC | ELF::SHF_MERGE | ELF::SHF_STRINGS, Kind); } if (Kind.isMergeableConst()) { if (Kind.isMergeableConst4() && MergeableConst4Section) return MergeableConst4Section; if (Kind.isMergeableConst8() && MergeableConst8Section) return MergeableConst8Section; if (Kind.isMergeableConst16() && MergeableConst16Section) return MergeableConst16Section; return ReadOnlySection; // .const } if (Kind.isReadOnly()) return ReadOnlySection; if (Kind.isThreadData()) return TLSDataSection; if (Kind.isThreadBSS()) return TLSBSSSection; // Note: we claim that common symbols are put in BSSSection, but they are // really emitted with the magic .comm directive, which creates a symbol table // entry but not a section. if (Kind.isBSS() || Kind.isCommon()) return BSSSection; if (Kind.isDataNoRel()) return DataSection; if (Kind.isDataRelLocal()) return DataRelLocalSection; if (Kind.isDataRel()) return DataRelSection; if (Kind.isReadOnlyWithRelLocal()) return DataRelROLocalSection; assert(Kind.isReadOnlyWithRel() && "Unknown section kind"); return DataRelROSection; } /// getSectionForConstant - Given a mergeable constant with the /// specified size and relocation information, return a section that it /// should be placed in. const MCSection *TargetLoweringObjectFileELF:: getSectionForConstant(SectionKind Kind) const { if (Kind.isMergeableConst4() && MergeableConst4Section) return MergeableConst4Section; if (Kind.isMergeableConst8() && MergeableConst8Section) return MergeableConst8Section; if (Kind.isMergeableConst16() && MergeableConst16Section) return MergeableConst16Section; if (Kind.isReadOnly()) return ReadOnlySection; if (Kind.isReadOnlyWithRelLocal()) return DataRelROLocalSection; assert(Kind.isReadOnlyWithRel() && "Unknown section kind"); return DataRelROSection; } const MCExpr *TargetLoweringObjectFileELF:: getExprForDwarfGlobalReference(const GlobalValue *GV, Mangler *Mang, MachineModuleInfo *MMI, unsigned Encoding, MCStreamer &Streamer) const { if (Encoding & dwarf::DW_EH_PE_indirect) { MachineModuleInfoELF &ELFMMI = MMI->getObjFileInfo(); SmallString<128> Name; Mang->getNameWithPrefix(Name, GV, true); Name += ".DW.stub"; // Add information about the stub reference to ELFMMI so that the stub // gets emitted by the asmprinter. MCSymbol *SSym = getContext().GetOrCreateSymbol(Name.str()); MachineModuleInfoImpl::StubValueTy &StubSym = ELFMMI.getGVStubEntry(SSym); if (StubSym.getPointer() == 0) { MCSymbol *Sym = Mang->getSymbol(GV); StubSym = MachineModuleInfoImpl::StubValueTy(Sym, !GV->hasLocalLinkage()); } return TargetLoweringObjectFile:: getExprForDwarfReference(SSym, Encoding & ~dwarf::DW_EH_PE_indirect, Streamer); } return TargetLoweringObjectFile:: getExprForDwarfGlobalReference(GV, Mang, MMI, Encoding, Streamer); } //===----------------------------------------------------------------------===// // MachO //===----------------------------------------------------------------------===// const MCSection *TargetLoweringObjectFileMachO:: getExplicitSectionGlobal(const GlobalValue *GV, SectionKind Kind, Mangler *Mang, const TargetMachine &TM) const { // Parse the section specifier and create it if valid. StringRef Segment, Section; unsigned TAA = 0, StubSize = 0; bool TAAParsed; std::string ErrorCode = MCSectionMachO::ParseSectionSpecifier(GV->getSection(), Segment, Section, TAA, TAAParsed, StubSize); if (!ErrorCode.empty()) { // If invalid, report the error with report_fatal_error. report_fatal_error("Global variable '" + GV->getNameStr() + "' has an invalid section specifier '" + GV->getSection()+ "': " + ErrorCode + "."); // Fall back to dropping it into the data section. return DataSection; } // Get the section. const MCSectionMachO *S = getContext().getMachOSection(Segment, Section, TAA, StubSize, Kind); // If TAA wasn't set by ParseSectionSpecifier() above, // use the value returned by getMachOSection() as a default. if (!TAAParsed) TAA = S->getTypeAndAttributes(); // Okay, now that we got the section, verify that the TAA & StubSize agree. // If the user declared multiple globals with different section flags, we need // to reject it here. if (S->getTypeAndAttributes() != TAA || S->getStubSize() != StubSize) { // If invalid, report the error with report_fatal_error. report_fatal_error("Global variable '" + GV->getNameStr() + "' section type or attributes does not match previous" " section specifier"); } return S; } const MCSection *TargetLoweringObjectFileMachO:: SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, Mangler *Mang, const TargetMachine &TM) const { // Handle thread local data. if (Kind.isThreadBSS()) return TLSBSSSection; if (Kind.isThreadData()) return TLSDataSection; if (Kind.isText()) return GV->isWeakForLinker() ? TextCoalSection : TextSection; // If this is weak/linkonce, put this in a coalescable section, either in text // or data depending on if it is writable. if (GV->isWeakForLinker()) { if (Kind.isReadOnly()) return ConstTextCoalSection; return DataCoalSection; } // FIXME: Alignment check should be handled by section classifier. if (Kind.isMergeable1ByteCString() && TM.getTargetData()->getPreferredAlignment(cast(GV)) < 32) return CStringSection; // Do not put 16-bit arrays in the UString section if they have an // externally visible label, this runs into issues with certain linker // versions. if (Kind.isMergeable2ByteCString() && !GV->hasExternalLinkage() && TM.getTargetData()->getPreferredAlignment(cast(GV)) < 32) return UStringSection; if (Kind.isMergeableConst()) { if (Kind.isMergeableConst4()) return FourByteConstantSection; if (Kind.isMergeableConst8()) return EightByteConstantSection; if (Kind.isMergeableConst16() && SixteenByteConstantSection) return SixteenByteConstantSection; } // Otherwise, if it is readonly, but not something we can specially optimize, // just drop it in .const. if (Kind.isReadOnly()) return ReadOnlySection; // If this is marked const, put it into a const section. But if the dynamic // linker needs to write to it, put it in the data segment. if (Kind.isReadOnlyWithRel()) return ConstDataSection; // Put zero initialized globals with strong external linkage in the // DATA, __common section with the .zerofill directive. if (Kind.isBSSExtern()) return DataCommonSection; // Put zero initialized globals with local linkage in __DATA,__bss directive // with the .zerofill directive (aka .lcomm). if (Kind.isBSSLocal()) return DataBSSSection; // Otherwise, just drop the variable in the normal data section. return DataSection; } const MCSection * TargetLoweringObjectFileMachO::getSectionForConstant(SectionKind Kind) const { // If this constant requires a relocation, we have to put it in the data // segment, not in the text segment. if (Kind.isDataRel() || Kind.isReadOnlyWithRel()) return ConstDataSection; if (Kind.isMergeableConst4()) return FourByteConstantSection; if (Kind.isMergeableConst8()) return EightByteConstantSection; if (Kind.isMergeableConst16() && SixteenByteConstantSection) return SixteenByteConstantSection; return ReadOnlySection; // .const } /// shouldEmitUsedDirectiveFor - This hook allows targets to selectively decide /// not to emit the UsedDirective for some symbols in llvm.used. // FIXME: REMOVE this (rdar://7071300) bool TargetLoweringObjectFileMachO:: shouldEmitUsedDirectiveFor(const GlobalValue *GV, Mangler *Mang) const { /// On Darwin, internally linked data beginning with "L" or "l" does not have /// the directive emitted (this occurs in ObjC metadata). if (!GV) return false; // Check whether the mangled name has the "Private" or "LinkerPrivate" prefix. if (GV->hasLocalLinkage() && !isa(GV)) { // FIXME: ObjC metadata is currently emitted as internal symbols that have // \1L and \0l prefixes on them. Fix them to be Private/LinkerPrivate and // this horrible hack can go away. MCSymbol *Sym = Mang->getSymbol(GV); if (Sym->getName()[0] == 'L' || Sym->getName()[0] == 'l') return false; } return true; } const MCExpr *TargetLoweringObjectFileMachO:: getExprForDwarfGlobalReference(const GlobalValue *GV, Mangler *Mang, MachineModuleInfo *MMI, unsigned Encoding, MCStreamer &Streamer) const { // The mach-o version of this method defaults to returning a stub reference. if (Encoding & DW_EH_PE_indirect) { MachineModuleInfoMachO &MachOMMI = MMI->getObjFileInfo(); SmallString<128> Name; Mang->getNameWithPrefix(Name, GV, true); Name += "$non_lazy_ptr"; // Add information about the stub reference to MachOMMI so that the stub // gets emitted by the asmprinter. MCSymbol *SSym = getContext().GetOrCreateSymbol(Name.str()); - MachineModuleInfoImpl::StubValueTy &StubSym = MachOMMI.getGVStubEntry(SSym); + MachineModuleInfoImpl::StubValueTy &StubSym = + GV->hasHiddenVisibility() ? MachOMMI.getHiddenGVStubEntry(SSym) : + MachOMMI.getGVStubEntry(SSym); if (StubSym.getPointer() == 0) { MCSymbol *Sym = Mang->getSymbol(GV); StubSym = MachineModuleInfoImpl::StubValueTy(Sym, !GV->hasLocalLinkage()); } return TargetLoweringObjectFile:: getExprForDwarfReference(SSym, Encoding & ~dwarf::DW_EH_PE_indirect, Streamer); } return TargetLoweringObjectFile:: getExprForDwarfGlobalReference(GV, Mang, MMI, Encoding, Streamer); } MCSymbol *TargetLoweringObjectFileMachO:: getCFIPersonalitySymbol(const GlobalValue *GV, Mangler *Mang, MachineModuleInfo *MMI) const { // The mach-o version of this method defaults to returning a stub reference. MachineModuleInfoMachO &MachOMMI = MMI->getObjFileInfo(); SmallString<128> Name; Mang->getNameWithPrefix(Name, GV, true); Name += "$non_lazy_ptr"; // Add information about the stub reference to MachOMMI so that the stub // gets emitted by the asmprinter. MCSymbol *SSym = getContext().GetOrCreateSymbol(Name.str()); - MachineModuleInfoImpl::StubValueTy &StubSym = MachOMMI.getGVStubEntry(SSym); + MachineModuleInfoImpl::StubValueTy &StubSym = + GV->hasHiddenVisibility() ? MachOMMI.getHiddenGVStubEntry(SSym) : + MachOMMI.getGVStubEntry(SSym); if (StubSym.getPointer() == 0) { MCSymbol *Sym = Mang->getSymbol(GV); StubSym = MachineModuleInfoImpl::StubValueTy(Sym, !GV->hasLocalLinkage()); } return SSym; } //===----------------------------------------------------------------------===// // COFF //===----------------------------------------------------------------------===// static unsigned getCOFFSectionFlags(SectionKind K) { unsigned Flags = 0; if (K.isMetadata()) Flags |= COFF::IMAGE_SCN_MEM_DISCARDABLE; else if (K.isText()) Flags |= COFF::IMAGE_SCN_MEM_EXECUTE | COFF::IMAGE_SCN_MEM_READ | COFF::IMAGE_SCN_CNT_CODE; else if (K.isBSS ()) Flags |= COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ | COFF::IMAGE_SCN_MEM_WRITE; else if (K.isReadOnly()) Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ; else if (K.isWriteable()) Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ | COFF::IMAGE_SCN_MEM_WRITE; return Flags; } const MCSection *TargetLoweringObjectFileCOFF:: getExplicitSectionGlobal(const GlobalValue *GV, SectionKind Kind, Mangler *Mang, const TargetMachine &TM) const { return getContext().getCOFFSection(GV->getSection(), getCOFFSectionFlags(Kind), Kind); } static const char *getCOFFSectionPrefixForUniqueGlobal(SectionKind Kind) { if (Kind.isText()) return ".text$"; if (Kind.isBSS ()) return ".bss$"; if (Kind.isWriteable()) return ".data$"; return ".rdata$"; } const MCSection *TargetLoweringObjectFileCOFF:: SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, Mangler *Mang, const TargetMachine &TM) const { assert(!Kind.isThreadLocal() && "Doesn't support TLS"); // If this global is linkonce/weak and the target handles this by emitting it // into a 'uniqued' section name, create and return the section now. if (GV->isWeakForLinker()) { const char *Prefix = getCOFFSectionPrefixForUniqueGlobal(Kind); SmallString<128> Name(Prefix, Prefix+strlen(Prefix)); MCSymbol *Sym = Mang->getSymbol(GV); Name.append(Sym->getName().begin() + 1, Sym->getName().end()); unsigned Characteristics = getCOFFSectionFlags(Kind); Characteristics |= COFF::IMAGE_SCN_LNK_COMDAT; return getContext().getCOFFSection(Name.str(), Characteristics, COFF::IMAGE_COMDAT_SELECT_ANY, Kind); } if (Kind.isText()) return getTextSection(); return getDataSection(); } Index: head/contrib/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp =================================================================== --- head/contrib/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp (revision 228378) +++ head/contrib/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp (revision 228379) @@ -1,1208 +1,1221 @@ //===- ARMBaseRegisterInfo.cpp - ARM Register Information -------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file contains the base ARM implementation of TargetRegisterInfo class. // //===----------------------------------------------------------------------===// #include "ARM.h" #include "ARMBaseInstrInfo.h" #include "ARMBaseRegisterInfo.h" #include "ARMFrameLowering.h" #include "ARMInstrInfo.h" #include "ARMMachineFunctionInfo.h" #include "ARMSubtarget.h" #include "MCTargetDesc/ARMAddressingModes.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" #include "llvm/Function.h" #include "llvm/LLVMContext.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/RegisterScavenging.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetFrameLowering.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/CommandLine.h" #define GET_REGINFO_TARGET_DESC #include "ARMGenRegisterInfo.inc" using namespace llvm; static cl::opt ForceAllBaseRegAlloc("arm-force-base-reg-alloc", cl::Hidden, cl::init(false), cl::desc("Force use of virtual base registers for stack load/store")); static cl::opt EnableLocalStackAlloc("enable-local-stack-alloc", cl::init(true), cl::Hidden, cl::desc("Enable pre-regalloc stack frame index allocation")); static cl::opt EnableBasePointer("arm-use-base-pointer", cl::Hidden, cl::init(true), cl::desc("Enable use of a base pointer for complex stack frames")); ARMBaseRegisterInfo::ARMBaseRegisterInfo(const ARMBaseInstrInfo &tii, const ARMSubtarget &sti) : ARMGenRegisterInfo(ARM::LR), TII(tii), STI(sti), FramePtr((STI.isTargetDarwin() || STI.isThumb()) ? ARM::R7 : ARM::R11), BasePtr(ARM::R6) { } const unsigned* ARMBaseRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { + bool ghcCall = false; + + if (MF) { + const Function *F = MF->getFunction(); + ghcCall = (F ? F->getCallingConv() == CallingConv::GHC : false); + } + static const unsigned CalleeSavedRegs[] = { ARM::LR, ARM::R11, ARM::R10, ARM::R9, ARM::R8, ARM::R7, ARM::R6, ARM::R5, ARM::R4, ARM::D15, ARM::D14, ARM::D13, ARM::D12, ARM::D11, ARM::D10, ARM::D9, ARM::D8, 0 }; static const unsigned DarwinCalleeSavedRegs[] = { // Darwin ABI deviates from ARM standard ABI. R9 is not a callee-saved // register. ARM::LR, ARM::R7, ARM::R6, ARM::R5, ARM::R4, ARM::R11, ARM::R10, ARM::R8, ARM::D15, ARM::D14, ARM::D13, ARM::D12, ARM::D11, ARM::D10, ARM::D9, ARM::D8, 0 }; - return STI.isTargetDarwin() ? DarwinCalleeSavedRegs : CalleeSavedRegs; + + static const unsigned GhcCalleeSavedRegs[] = { + 0 + }; + + return ghcCall ? GhcCalleeSavedRegs : + STI.isTargetDarwin() ? DarwinCalleeSavedRegs : CalleeSavedRegs; } BitVector ARMBaseRegisterInfo:: getReservedRegs(const MachineFunction &MF) const { const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); // FIXME: avoid re-calculating this every time. BitVector Reserved(getNumRegs()); Reserved.set(ARM::SP); Reserved.set(ARM::PC); Reserved.set(ARM::FPSCR); if (TFI->hasFP(MF)) Reserved.set(FramePtr); if (hasBasePointer(MF)) Reserved.set(BasePtr); // Some targets reserve R9. if (STI.isR9Reserved()) Reserved.set(ARM::R9); // Reserve D16-D31 if the subtarget doesn't support them. if (!STI.hasVFP3() || STI.hasD16()) { assert(ARM::D31 == ARM::D16 + 15); for (unsigned i = 0; i != 16; ++i) Reserved.set(ARM::D16 + i); } return Reserved; } bool ARMBaseRegisterInfo::isReservedReg(const MachineFunction &MF, unsigned Reg) const { const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); switch (Reg) { default: break; case ARM::SP: case ARM::PC: return true; case ARM::R6: if (hasBasePointer(MF)) return true; break; case ARM::R7: case ARM::R11: if (FramePtr == Reg && TFI->hasFP(MF)) return true; break; case ARM::R9: return STI.isR9Reserved(); } return false; } const TargetRegisterClass * ARMBaseRegisterInfo::getMatchingSuperRegClass(const TargetRegisterClass *A, const TargetRegisterClass *B, unsigned SubIdx) const { switch (SubIdx) { default: return 0; case ARM::ssub_0: case ARM::ssub_1: case ARM::ssub_2: case ARM::ssub_3: { // S sub-registers. if (A->getSize() == 8) { if (B == &ARM::SPR_8RegClass) return &ARM::DPR_8RegClass; assert(B == &ARM::SPRRegClass && "Expecting SPR register class!"); if (A == &ARM::DPR_8RegClass) return A; return &ARM::DPR_VFP2RegClass; } if (A->getSize() == 16) { if (B == &ARM::SPR_8RegClass) return &ARM::QPR_8RegClass; return &ARM::QPR_VFP2RegClass; } if (A->getSize() == 32) { if (B == &ARM::SPR_8RegClass) return 0; // Do not allow coalescing! return &ARM::QQPR_VFP2RegClass; } assert(A->getSize() == 64 && "Expecting a QQQQ register class!"); return 0; // Do not allow coalescing! } case ARM::dsub_0: case ARM::dsub_1: case ARM::dsub_2: case ARM::dsub_3: { // D sub-registers. if (A->getSize() == 16) { if (B == &ARM::DPR_VFP2RegClass) return &ARM::QPR_VFP2RegClass; if (B == &ARM::DPR_8RegClass) return 0; // Do not allow coalescing! return A; } if (A->getSize() == 32) { if (B == &ARM::DPR_VFP2RegClass) return &ARM::QQPR_VFP2RegClass; if (B == &ARM::DPR_8RegClass) return 0; // Do not allow coalescing! return A; } assert(A->getSize() == 64 && "Expecting a QQQQ register class!"); if (B != &ARM::DPRRegClass) return 0; // Do not allow coalescing! return A; } case ARM::dsub_4: case ARM::dsub_5: case ARM::dsub_6: case ARM::dsub_7: { // D sub-registers of QQQQ registers. if (A->getSize() == 64 && B == &ARM::DPRRegClass) return A; return 0; // Do not allow coalescing! } case ARM::qsub_0: case ARM::qsub_1: { // Q sub-registers. if (A->getSize() == 32) { if (B == &ARM::QPR_VFP2RegClass) return &ARM::QQPR_VFP2RegClass; if (B == &ARM::QPR_8RegClass) return 0; // Do not allow coalescing! return A; } assert(A->getSize() == 64 && "Expecting a QQQQ register class!"); if (B == &ARM::QPRRegClass) return A; return 0; // Do not allow coalescing! } case ARM::qsub_2: case ARM::qsub_3: { // Q sub-registers of QQQQ registers. if (A->getSize() == 64 && B == &ARM::QPRRegClass) return A; return 0; // Do not allow coalescing! } } return 0; } bool ARMBaseRegisterInfo::canCombineSubRegIndices(const TargetRegisterClass *RC, SmallVectorImpl &SubIndices, unsigned &NewSubIdx) const { unsigned Size = RC->getSize() * 8; if (Size < 6) return 0; NewSubIdx = 0; // Whole register. unsigned NumRegs = SubIndices.size(); if (NumRegs == 8) { // 8 D registers -> 1 QQQQ register. return (Size == 512 && SubIndices[0] == ARM::dsub_0 && SubIndices[1] == ARM::dsub_1 && SubIndices[2] == ARM::dsub_2 && SubIndices[3] == ARM::dsub_3 && SubIndices[4] == ARM::dsub_4 && SubIndices[5] == ARM::dsub_5 && SubIndices[6] == ARM::dsub_6 && SubIndices[7] == ARM::dsub_7); } else if (NumRegs == 4) { if (SubIndices[0] == ARM::qsub_0) { // 4 Q registers -> 1 QQQQ register. return (Size == 512 && SubIndices[1] == ARM::qsub_1 && SubIndices[2] == ARM::qsub_2 && SubIndices[3] == ARM::qsub_3); } else if (SubIndices[0] == ARM::dsub_0) { // 4 D registers -> 1 QQ register. if (Size >= 256 && SubIndices[1] == ARM::dsub_1 && SubIndices[2] == ARM::dsub_2 && SubIndices[3] == ARM::dsub_3) { if (Size == 512) NewSubIdx = ARM::qqsub_0; return true; } } else if (SubIndices[0] == ARM::dsub_4) { // 4 D registers -> 1 QQ register (2nd). if (Size == 512 && SubIndices[1] == ARM::dsub_5 && SubIndices[2] == ARM::dsub_6 && SubIndices[3] == ARM::dsub_7) { NewSubIdx = ARM::qqsub_1; return true; } } else if (SubIndices[0] == ARM::ssub_0) { // 4 S registers -> 1 Q register. if (Size >= 128 && SubIndices[1] == ARM::ssub_1 && SubIndices[2] == ARM::ssub_2 && SubIndices[3] == ARM::ssub_3) { if (Size >= 256) NewSubIdx = ARM::qsub_0; return true; } } } else if (NumRegs == 2) { if (SubIndices[0] == ARM::qsub_0) { // 2 Q registers -> 1 QQ register. if (Size >= 256 && SubIndices[1] == ARM::qsub_1) { if (Size == 512) NewSubIdx = ARM::qqsub_0; return true; } } else if (SubIndices[0] == ARM::qsub_2) { // 2 Q registers -> 1 QQ register (2nd). if (Size == 512 && SubIndices[1] == ARM::qsub_3) { NewSubIdx = ARM::qqsub_1; return true; } } else if (SubIndices[0] == ARM::dsub_0) { // 2 D registers -> 1 Q register. if (Size >= 128 && SubIndices[1] == ARM::dsub_1) { if (Size >= 256) NewSubIdx = ARM::qsub_0; return true; } } else if (SubIndices[0] == ARM::dsub_2) { // 2 D registers -> 1 Q register (2nd). if (Size >= 256 && SubIndices[1] == ARM::dsub_3) { NewSubIdx = ARM::qsub_1; return true; } } else if (SubIndices[0] == ARM::dsub_4) { // 2 D registers -> 1 Q register (3rd). if (Size == 512 && SubIndices[1] == ARM::dsub_5) { NewSubIdx = ARM::qsub_2; return true; } } else if (SubIndices[0] == ARM::dsub_6) { // 2 D registers -> 1 Q register (3rd). if (Size == 512 && SubIndices[1] == ARM::dsub_7) { NewSubIdx = ARM::qsub_3; return true; } } else if (SubIndices[0] == ARM::ssub_0) { // 2 S registers -> 1 D register. if (SubIndices[1] == ARM::ssub_1) { if (Size >= 128) NewSubIdx = ARM::dsub_0; return true; } } else if (SubIndices[0] == ARM::ssub_2) { // 2 S registers -> 1 D register (2nd). if (Size >= 128 && SubIndices[1] == ARM::ssub_3) { NewSubIdx = ARM::dsub_1; return true; } } } return false; } const TargetRegisterClass* ARMBaseRegisterInfo::getLargestLegalSuperClass(const TargetRegisterClass *RC) const { const TargetRegisterClass *Super = RC; TargetRegisterClass::sc_iterator I = RC->getSuperClasses(); do { switch (Super->getID()) { case ARM::GPRRegClassID: case ARM::SPRRegClassID: case ARM::DPRRegClassID: case ARM::QPRRegClassID: case ARM::QQPRRegClassID: case ARM::QQQQPRRegClassID: return Super; } Super = *I++; } while (Super); return RC; } const TargetRegisterClass * ARMBaseRegisterInfo::getPointerRegClass(unsigned Kind) const { return ARM::GPRRegisterClass; } const TargetRegisterClass * ARMBaseRegisterInfo::getCrossCopyRegClass(const TargetRegisterClass *RC) const { if (RC == &ARM::CCRRegClass) return 0; // Can't copy CCR registers. return RC; } unsigned ARMBaseRegisterInfo::getRegPressureLimit(const TargetRegisterClass *RC, MachineFunction &MF) const { const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); switch (RC->getID()) { default: return 0; case ARM::tGPRRegClassID: return TFI->hasFP(MF) ? 4 : 5; case ARM::GPRRegClassID: { unsigned FP = TFI->hasFP(MF) ? 1 : 0; return 10 - FP - (STI.isR9Reserved() ? 1 : 0); } case ARM::SPRRegClassID: // Currently not used as 'rep' register class. case ARM::DPRRegClassID: return 32 - 10; } } /// getRawAllocationOrder - Returns the register allocation order for a /// specified register class with a target-dependent hint. ArrayRef ARMBaseRegisterInfo::getRawAllocationOrder(const TargetRegisterClass *RC, unsigned HintType, unsigned HintReg, const MachineFunction &MF) const { const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); // Alternative register allocation orders when favoring even / odd registers // of register pairs. // No FP, R9 is available. static const unsigned GPREven1[] = { ARM::R0, ARM::R2, ARM::R4, ARM::R6, ARM::R8, ARM::R10, ARM::R1, ARM::R3, ARM::R12,ARM::LR, ARM::R5, ARM::R7, ARM::R9, ARM::R11 }; static const unsigned GPROdd1[] = { ARM::R1, ARM::R3, ARM::R5, ARM::R7, ARM::R9, ARM::R11, ARM::R0, ARM::R2, ARM::R12,ARM::LR, ARM::R4, ARM::R6, ARM::R8, ARM::R10 }; // FP is R7, R9 is available. static const unsigned GPREven2[] = { ARM::R0, ARM::R2, ARM::R4, ARM::R8, ARM::R10, ARM::R1, ARM::R3, ARM::R12,ARM::LR, ARM::R5, ARM::R6, ARM::R9, ARM::R11 }; static const unsigned GPROdd2[] = { ARM::R1, ARM::R3, ARM::R5, ARM::R9, ARM::R11, ARM::R0, ARM::R2, ARM::R12,ARM::LR, ARM::R4, ARM::R6, ARM::R8, ARM::R10 }; // FP is R11, R9 is available. static const unsigned GPREven3[] = { ARM::R0, ARM::R2, ARM::R4, ARM::R6, ARM::R8, ARM::R1, ARM::R3, ARM::R10,ARM::R12,ARM::LR, ARM::R5, ARM::R7, ARM::R9 }; static const unsigned GPROdd3[] = { ARM::R1, ARM::R3, ARM::R5, ARM::R6, ARM::R9, ARM::R0, ARM::R2, ARM::R10,ARM::R12,ARM::LR, ARM::R4, ARM::R7, ARM::R8 }; // No FP, R9 is not available. static const unsigned GPREven4[] = { ARM::R0, ARM::R2, ARM::R4, ARM::R6, ARM::R10, ARM::R1, ARM::R3, ARM::R12,ARM::LR, ARM::R5, ARM::R7, ARM::R8, ARM::R11 }; static const unsigned GPROdd4[] = { ARM::R1, ARM::R3, ARM::R5, ARM::R7, ARM::R11, ARM::R0, ARM::R2, ARM::R12,ARM::LR, ARM::R4, ARM::R6, ARM::R8, ARM::R10 }; // FP is R7, R9 is not available. static const unsigned GPREven5[] = { ARM::R0, ARM::R2, ARM::R4, ARM::R10, ARM::R1, ARM::R3, ARM::R12,ARM::LR, ARM::R5, ARM::R6, ARM::R8, ARM::R11 }; static const unsigned GPROdd5[] = { ARM::R1, ARM::R3, ARM::R5, ARM::R11, ARM::R0, ARM::R2, ARM::R12,ARM::LR, ARM::R4, ARM::R6, ARM::R8, ARM::R10 }; // FP is R11, R9 is not available. static const unsigned GPREven6[] = { ARM::R0, ARM::R2, ARM::R4, ARM::R6, ARM::R1, ARM::R3, ARM::R10,ARM::R12,ARM::LR, ARM::R5, ARM::R7, ARM::R8 }; static const unsigned GPROdd6[] = { ARM::R1, ARM::R3, ARM::R5, ARM::R7, ARM::R0, ARM::R2, ARM::R10,ARM::R12,ARM::LR, ARM::R4, ARM::R6, ARM::R8 }; // We only support even/odd hints for GPR and rGPR. if (RC != ARM::GPRRegisterClass && RC != ARM::rGPRRegisterClass) return RC->getRawAllocationOrder(MF); if (HintType == ARMRI::RegPairEven) { if (isPhysicalRegister(HintReg) && getRegisterPairEven(HintReg, MF) == 0) // It's no longer possible to fulfill this hint. Return the default // allocation order. return RC->getRawAllocationOrder(MF); if (!TFI->hasFP(MF)) { if (!STI.isR9Reserved()) return makeArrayRef(GPREven1); else return makeArrayRef(GPREven4); } else if (FramePtr == ARM::R7) { if (!STI.isR9Reserved()) return makeArrayRef(GPREven2); else return makeArrayRef(GPREven5); } else { // FramePtr == ARM::R11 if (!STI.isR9Reserved()) return makeArrayRef(GPREven3); else return makeArrayRef(GPREven6); } } else if (HintType == ARMRI::RegPairOdd) { if (isPhysicalRegister(HintReg) && getRegisterPairOdd(HintReg, MF) == 0) // It's no longer possible to fulfill this hint. Return the default // allocation order. return RC->getRawAllocationOrder(MF); if (!TFI->hasFP(MF)) { if (!STI.isR9Reserved()) return makeArrayRef(GPROdd1); else return makeArrayRef(GPROdd4); } else if (FramePtr == ARM::R7) { if (!STI.isR9Reserved()) return makeArrayRef(GPROdd2); else return makeArrayRef(GPROdd5); } else { // FramePtr == ARM::R11 if (!STI.isR9Reserved()) return makeArrayRef(GPROdd3); else return makeArrayRef(GPROdd6); } } return RC->getRawAllocationOrder(MF); } /// ResolveRegAllocHint - Resolves the specified register allocation hint /// to a physical register. Returns the physical register if it is successful. unsigned ARMBaseRegisterInfo::ResolveRegAllocHint(unsigned Type, unsigned Reg, const MachineFunction &MF) const { if (Reg == 0 || !isPhysicalRegister(Reg)) return 0; if (Type == 0) return Reg; else if (Type == (unsigned)ARMRI::RegPairOdd) // Odd register. return getRegisterPairOdd(Reg, MF); else if (Type == (unsigned)ARMRI::RegPairEven) // Even register. return getRegisterPairEven(Reg, MF); return 0; } void ARMBaseRegisterInfo::UpdateRegAllocHint(unsigned Reg, unsigned NewReg, MachineFunction &MF) const { MachineRegisterInfo *MRI = &MF.getRegInfo(); std::pair Hint = MRI->getRegAllocationHint(Reg); if ((Hint.first == (unsigned)ARMRI::RegPairOdd || Hint.first == (unsigned)ARMRI::RegPairEven) && TargetRegisterInfo::isVirtualRegister(Hint.second)) { // If 'Reg' is one of the even / odd register pair and it's now changed // (e.g. coalesced) into a different register. The other register of the // pair allocation hint must be updated to reflect the relationship // change. unsigned OtherReg = Hint.second; Hint = MRI->getRegAllocationHint(OtherReg); if (Hint.second == Reg) // Make sure the pair has not already divorced. MRI->setRegAllocationHint(OtherReg, Hint.first, NewReg); } } bool ARMBaseRegisterInfo::avoidWriteAfterWrite(const TargetRegisterClass *RC) const { // CortexA9 has a Write-after-write hazard for NEON registers. if (!STI.isCortexA9()) return false; switch (RC->getID()) { case ARM::DPRRegClassID: case ARM::DPR_8RegClassID: case ARM::DPR_VFP2RegClassID: case ARM::QPRRegClassID: case ARM::QPR_8RegClassID: case ARM::QPR_VFP2RegClassID: case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: // Avoid reusing S, D, and Q registers. // Don't increase register pressure for QQ and QQQQ. return true; default: return false; } } bool ARMBaseRegisterInfo::hasBasePointer(const MachineFunction &MF) const { const MachineFrameInfo *MFI = MF.getFrameInfo(); const ARMFunctionInfo *AFI = MF.getInfo(); if (!EnableBasePointer) return false; if (needsStackRealignment(MF) && MFI->hasVarSizedObjects()) return true; // Thumb has trouble with negative offsets from the FP. Thumb2 has a limited // negative range for ldr/str (255), and thumb1 is positive offsets only. // It's going to be better to use the SP or Base Pointer instead. When there // are variable sized objects, we can't reference off of the SP, so we // reserve a Base Pointer. if (AFI->isThumbFunction() && MFI->hasVarSizedObjects()) { // Conservatively estimate whether the negative offset from the frame // pointer will be sufficient to reach. If a function has a smallish // frame, it's less likely to have lots of spills and callee saved // space, so it's all more likely to be within range of the frame pointer. // If it's wrong, the scavenger will still enable access to work, it just // won't be optimal. if (AFI->isThumb2Function() && MFI->getLocalFrameSize() < 128) return false; return true; } return false; } bool ARMBaseRegisterInfo::canRealignStack(const MachineFunction &MF) const { const MachineFrameInfo *MFI = MF.getFrameInfo(); const ARMFunctionInfo *AFI = MF.getInfo(); // We can't realign the stack if: // 1. Dynamic stack realignment is explicitly disabled, // 2. This is a Thumb1 function (it's not useful, so we don't bother), or // 3. There are VLAs in the function and the base pointer is disabled. return (RealignStack && !AFI->isThumb1OnlyFunction() && (!MFI->hasVarSizedObjects() || EnableBasePointer)); } bool ARMBaseRegisterInfo:: needsStackRealignment(const MachineFunction &MF) const { const MachineFrameInfo *MFI = MF.getFrameInfo(); const Function *F = MF.getFunction(); unsigned StackAlign = MF.getTarget().getFrameLowering()->getStackAlignment(); bool requiresRealignment = ((MFI->getLocalFrameMaxAlign() > StackAlign) || F->hasFnAttr(Attribute::StackAlignment)); return requiresRealignment && canRealignStack(MF); } bool ARMBaseRegisterInfo:: cannotEliminateFrame(const MachineFunction &MF) const { const MachineFrameInfo *MFI = MF.getFrameInfo(); if (DisableFramePointerElim(MF) && MFI->adjustsStack()) return true; return MFI->hasVarSizedObjects() || MFI->isFrameAddressTaken() || needsStackRealignment(MF); } unsigned ARMBaseRegisterInfo::getFrameRegister(const MachineFunction &MF) const { const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); if (TFI->hasFP(MF)) return FramePtr; return ARM::SP; } unsigned ARMBaseRegisterInfo::getEHExceptionRegister() const { llvm_unreachable("What is the exception register"); return 0; } unsigned ARMBaseRegisterInfo::getEHHandlerRegister() const { llvm_unreachable("What is the exception handler register"); return 0; } unsigned ARMBaseRegisterInfo::getRegisterPairEven(unsigned Reg, const MachineFunction &MF) const { switch (Reg) { default: break; // Return 0 if either register of the pair is a special register. // So no R12, etc. case ARM::R1: return ARM::R0; case ARM::R3: return ARM::R2; case ARM::R5: return ARM::R4; case ARM::R7: return (isReservedReg(MF, ARM::R7) || isReservedReg(MF, ARM::R6)) ? 0 : ARM::R6; case ARM::R9: return isReservedReg(MF, ARM::R9) ? 0 :ARM::R8; case ARM::R11: return isReservedReg(MF, ARM::R11) ? 0 : ARM::R10; case ARM::S1: return ARM::S0; case ARM::S3: return ARM::S2; case ARM::S5: return ARM::S4; case ARM::S7: return ARM::S6; case ARM::S9: return ARM::S8; case ARM::S11: return ARM::S10; case ARM::S13: return ARM::S12; case ARM::S15: return ARM::S14; case ARM::S17: return ARM::S16; case ARM::S19: return ARM::S18; case ARM::S21: return ARM::S20; case ARM::S23: return ARM::S22; case ARM::S25: return ARM::S24; case ARM::S27: return ARM::S26; case ARM::S29: return ARM::S28; case ARM::S31: return ARM::S30; case ARM::D1: return ARM::D0; case ARM::D3: return ARM::D2; case ARM::D5: return ARM::D4; case ARM::D7: return ARM::D6; case ARM::D9: return ARM::D8; case ARM::D11: return ARM::D10; case ARM::D13: return ARM::D12; case ARM::D15: return ARM::D14; case ARM::D17: return ARM::D16; case ARM::D19: return ARM::D18; case ARM::D21: return ARM::D20; case ARM::D23: return ARM::D22; case ARM::D25: return ARM::D24; case ARM::D27: return ARM::D26; case ARM::D29: return ARM::D28; case ARM::D31: return ARM::D30; } return 0; } unsigned ARMBaseRegisterInfo::getRegisterPairOdd(unsigned Reg, const MachineFunction &MF) const { switch (Reg) { default: break; // Return 0 if either register of the pair is a special register. // So no R12, etc. case ARM::R0: return ARM::R1; case ARM::R2: return ARM::R3; case ARM::R4: return ARM::R5; case ARM::R6: return (isReservedReg(MF, ARM::R7) || isReservedReg(MF, ARM::R6)) ? 0 : ARM::R7; case ARM::R8: return isReservedReg(MF, ARM::R9) ? 0 :ARM::R9; case ARM::R10: return isReservedReg(MF, ARM::R11) ? 0 : ARM::R11; case ARM::S0: return ARM::S1; case ARM::S2: return ARM::S3; case ARM::S4: return ARM::S5; case ARM::S6: return ARM::S7; case ARM::S8: return ARM::S9; case ARM::S10: return ARM::S11; case ARM::S12: return ARM::S13; case ARM::S14: return ARM::S15; case ARM::S16: return ARM::S17; case ARM::S18: return ARM::S19; case ARM::S20: return ARM::S21; case ARM::S22: return ARM::S23; case ARM::S24: return ARM::S25; case ARM::S26: return ARM::S27; case ARM::S28: return ARM::S29; case ARM::S30: return ARM::S31; case ARM::D0: return ARM::D1; case ARM::D2: return ARM::D3; case ARM::D4: return ARM::D5; case ARM::D6: return ARM::D7; case ARM::D8: return ARM::D9; case ARM::D10: return ARM::D11; case ARM::D12: return ARM::D13; case ARM::D14: return ARM::D15; case ARM::D16: return ARM::D17; case ARM::D18: return ARM::D19; case ARM::D20: return ARM::D21; case ARM::D22: return ARM::D23; case ARM::D24: return ARM::D25; case ARM::D26: return ARM::D27; case ARM::D28: return ARM::D29; case ARM::D30: return ARM::D31; } return 0; } /// emitLoadConstPool - Emits a load from constpool to materialize the /// specified immediate. void ARMBaseRegisterInfo:: emitLoadConstPool(MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI, DebugLoc dl, unsigned DestReg, unsigned SubIdx, int Val, ARMCC::CondCodes Pred, unsigned PredReg, unsigned MIFlags) const { MachineFunction &MF = *MBB.getParent(); MachineConstantPool *ConstantPool = MF.getConstantPool(); const Constant *C = ConstantInt::get(Type::getInt32Ty(MF.getFunction()->getContext()), Val); unsigned Idx = ConstantPool->getConstantPoolIndex(C, 4); BuildMI(MBB, MBBI, dl, TII.get(ARM::LDRcp)) .addReg(DestReg, getDefRegState(true), SubIdx) .addConstantPoolIndex(Idx) .addImm(0).addImm(Pred).addReg(PredReg) .setMIFlags(MIFlags); } bool ARMBaseRegisterInfo:: requiresRegisterScavenging(const MachineFunction &MF) const { return true; } bool ARMBaseRegisterInfo:: requiresFrameIndexScavenging(const MachineFunction &MF) const { return true; } bool ARMBaseRegisterInfo:: requiresVirtualBaseRegisters(const MachineFunction &MF) const { return EnableLocalStackAlloc; } static void emitSPUpdate(bool isARM, MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI, DebugLoc dl, const ARMBaseInstrInfo &TII, int NumBytes, ARMCC::CondCodes Pred = ARMCC::AL, unsigned PredReg = 0) { if (isARM) emitARMRegPlusImmediate(MBB, MBBI, dl, ARM::SP, ARM::SP, NumBytes, Pred, PredReg, TII); else emitT2RegPlusImmediate(MBB, MBBI, dl, ARM::SP, ARM::SP, NumBytes, Pred, PredReg, TII); } void ARMBaseRegisterInfo:: eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const { const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); if (!TFI->hasReservedCallFrame(MF)) { // If we have alloca, convert as follows: // ADJCALLSTACKDOWN -> sub, sp, sp, amount // ADJCALLSTACKUP -> add, sp, sp, amount MachineInstr *Old = I; DebugLoc dl = Old->getDebugLoc(); unsigned Amount = Old->getOperand(0).getImm(); if (Amount != 0) { // We need to keep the stack aligned properly. To do this, we round the // amount of space needed for the outgoing arguments up to the next // alignment boundary. unsigned Align = TFI->getStackAlignment(); Amount = (Amount+Align-1)/Align*Align; ARMFunctionInfo *AFI = MF.getInfo(); assert(!AFI->isThumb1OnlyFunction() && "This eliminateCallFramePseudoInstr does not support Thumb1!"); bool isARM = !AFI->isThumbFunction(); // Replace the pseudo instruction with a new instruction... unsigned Opc = Old->getOpcode(); int PIdx = Old->findFirstPredOperandIdx(); ARMCC::CondCodes Pred = (PIdx == -1) ? ARMCC::AL : (ARMCC::CondCodes)Old->getOperand(PIdx).getImm(); if (Opc == ARM::ADJCALLSTACKDOWN || Opc == ARM::tADJCALLSTACKDOWN) { // Note: PredReg is operand 2 for ADJCALLSTACKDOWN. unsigned PredReg = Old->getOperand(2).getReg(); emitSPUpdate(isARM, MBB, I, dl, TII, -Amount, Pred, PredReg); } else { // Note: PredReg is operand 3 for ADJCALLSTACKUP. unsigned PredReg = Old->getOperand(3).getReg(); assert(Opc == ARM::ADJCALLSTACKUP || Opc == ARM::tADJCALLSTACKUP); emitSPUpdate(isARM, MBB, I, dl, TII, Amount, Pred, PredReg); } } } MBB.erase(I); } int64_t ARMBaseRegisterInfo:: getFrameIndexInstrOffset(const MachineInstr *MI, int Idx) const { const MCInstrDesc &Desc = MI->getDesc(); unsigned AddrMode = (Desc.TSFlags & ARMII::AddrModeMask); int64_t InstrOffs = 0;; int Scale = 1; unsigned ImmIdx = 0; switch (AddrMode) { case ARMII::AddrModeT2_i8: case ARMII::AddrModeT2_i12: case ARMII::AddrMode_i12: InstrOffs = MI->getOperand(Idx+1).getImm(); Scale = 1; break; case ARMII::AddrMode5: { // VFP address mode. const MachineOperand &OffOp = MI->getOperand(Idx+1); InstrOffs = ARM_AM::getAM5Offset(OffOp.getImm()); if (ARM_AM::getAM5Op(OffOp.getImm()) == ARM_AM::sub) InstrOffs = -InstrOffs; Scale = 4; break; } case ARMII::AddrMode2: { ImmIdx = Idx+2; InstrOffs = ARM_AM::getAM2Offset(MI->getOperand(ImmIdx).getImm()); if (ARM_AM::getAM2Op(MI->getOperand(ImmIdx).getImm()) == ARM_AM::sub) InstrOffs = -InstrOffs; break; } case ARMII::AddrMode3: { ImmIdx = Idx+2; InstrOffs = ARM_AM::getAM3Offset(MI->getOperand(ImmIdx).getImm()); if (ARM_AM::getAM3Op(MI->getOperand(ImmIdx).getImm()) == ARM_AM::sub) InstrOffs = -InstrOffs; break; } case ARMII::AddrModeT1_s: { ImmIdx = Idx+1; InstrOffs = MI->getOperand(ImmIdx).getImm(); Scale = 4; break; } default: llvm_unreachable("Unsupported addressing mode!"); break; } return InstrOffs * Scale; } /// needsFrameBaseReg - Returns true if the instruction's frame index /// reference would be better served by a base register other than FP /// or SP. Used by LocalStackFrameAllocation to determine which frame index /// references it should create new base registers for. bool ARMBaseRegisterInfo:: needsFrameBaseReg(MachineInstr *MI, int64_t Offset) const { for (unsigned i = 0; !MI->getOperand(i).isFI(); ++i) { assert(i < MI->getNumOperands() &&"Instr doesn't have FrameIndex operand!"); } // It's the load/store FI references that cause issues, as it can be difficult // to materialize the offset if it won't fit in the literal field. Estimate // based on the size of the local frame and some conservative assumptions // about the rest of the stack frame (note, this is pre-regalloc, so // we don't know everything for certain yet) whether this offset is likely // to be out of range of the immediate. Return true if so. // We only generate virtual base registers for loads and stores, so // return false for everything else. unsigned Opc = MI->getOpcode(); switch (Opc) { case ARM::LDRi12: case ARM::LDRH: case ARM::LDRBi12: case ARM::STRi12: case ARM::STRH: case ARM::STRBi12: case ARM::t2LDRi12: case ARM::t2LDRi8: case ARM::t2STRi12: case ARM::t2STRi8: case ARM::VLDRS: case ARM::VLDRD: case ARM::VSTRS: case ARM::VSTRD: case ARM::tSTRspi: case ARM::tLDRspi: if (ForceAllBaseRegAlloc) return true; break; default: return false; } // Without a virtual base register, if the function has variable sized // objects, all fixed-size local references will be via the frame pointer, // Approximate the offset and see if it's legal for the instruction. // Note that the incoming offset is based on the SP value at function entry, // so it'll be negative. MachineFunction &MF = *MI->getParent()->getParent(); const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); MachineFrameInfo *MFI = MF.getFrameInfo(); ARMFunctionInfo *AFI = MF.getInfo(); // Estimate an offset from the frame pointer. // Conservatively assume all callee-saved registers get pushed. R4-R6 // will be earlier than the FP, so we ignore those. // R7, LR int64_t FPOffset = Offset - 8; // ARM and Thumb2 functions also need to consider R8-R11 and D8-D15 if (!AFI->isThumbFunction() || !AFI->isThumb1OnlyFunction()) FPOffset -= 80; // Estimate an offset from the stack pointer. // The incoming offset is relating to the SP at the start of the function, // but when we access the local it'll be relative to the SP after local // allocation, so adjust our SP-relative offset by that allocation size. Offset = -Offset; Offset += MFI->getLocalFrameSize(); // Assume that we'll have at least some spill slots allocated. // FIXME: This is a total SWAG number. We should run some statistics // and pick a real one. Offset += 128; // 128 bytes of spill slots // If there is a frame pointer, try using it. // The FP is only available if there is no dynamic realignment. We // don't know for sure yet whether we'll need that, so we guess based // on whether there are any local variables that would trigger it. unsigned StackAlign = TFI->getStackAlignment(); if (TFI->hasFP(MF) && !((MFI->getLocalFrameMaxAlign() > StackAlign) && canRealignStack(MF))) { if (isFrameOffsetLegal(MI, FPOffset)) return false; } // If we can reference via the stack pointer, try that. // FIXME: This (and the code that resolves the references) can be improved // to only disallow SP relative references in the live range of // the VLA(s). In practice, it's unclear how much difference that // would make, but it may be worth doing. if (!MFI->hasVarSizedObjects() && isFrameOffsetLegal(MI, Offset)) return false; // The offset likely isn't legal, we want to allocate a virtual base register. return true; } /// materializeFrameBaseRegister - Insert defining instruction(s) for BaseReg to /// be a pointer to FrameIdx at the beginning of the basic block. void ARMBaseRegisterInfo:: materializeFrameBaseRegister(MachineBasicBlock *MBB, unsigned BaseReg, int FrameIdx, int64_t Offset) const { ARMFunctionInfo *AFI = MBB->getParent()->getInfo(); unsigned ADDriOpc = !AFI->isThumbFunction() ? ARM::ADDri : (AFI->isThumb1OnlyFunction() ? ARM::tADDrSPi : ARM::t2ADDri); MachineBasicBlock::iterator Ins = MBB->begin(); DebugLoc DL; // Defaults to "unknown" if (Ins != MBB->end()) DL = Ins->getDebugLoc(); const MCInstrDesc &MCID = TII.get(ADDriOpc); MachineRegisterInfo &MRI = MBB->getParent()->getRegInfo(); MRI.constrainRegClass(BaseReg, TII.getRegClass(MCID, 0, this)); MachineInstrBuilder MIB = AddDefaultPred(BuildMI(*MBB, Ins, DL, MCID, BaseReg) .addFrameIndex(FrameIdx).addImm(Offset)); if (!AFI->isThumb1OnlyFunction()) AddDefaultCC(MIB); } void ARMBaseRegisterInfo::resolveFrameIndex(MachineBasicBlock::iterator I, unsigned BaseReg, int64_t Offset) const { MachineInstr &MI = *I; MachineBasicBlock &MBB = *MI.getParent(); MachineFunction &MF = *MBB.getParent(); ARMFunctionInfo *AFI = MF.getInfo(); int Off = Offset; // ARM doesn't need the general 64-bit offsets unsigned i = 0; assert(!AFI->isThumb1OnlyFunction() && "This resolveFrameIndex does not support Thumb1!"); while (!MI.getOperand(i).isFI()) { ++i; assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!"); } bool Done = false; if (!AFI->isThumbFunction()) Done = rewriteARMFrameIndex(MI, i, BaseReg, Off, TII); else { assert(AFI->isThumb2Function()); Done = rewriteT2FrameIndex(MI, i, BaseReg, Off, TII); } assert (Done && "Unable to resolve frame index!"); (void)Done; } bool ARMBaseRegisterInfo::isFrameOffsetLegal(const MachineInstr *MI, int64_t Offset) const { const MCInstrDesc &Desc = MI->getDesc(); unsigned AddrMode = (Desc.TSFlags & ARMII::AddrModeMask); unsigned i = 0; while (!MI->getOperand(i).isFI()) { ++i; assert(i < MI->getNumOperands() &&"Instr doesn't have FrameIndex operand!"); } // AddrMode4 and AddrMode6 cannot handle any offset. if (AddrMode == ARMII::AddrMode4 || AddrMode == ARMII::AddrMode6) return Offset == 0; unsigned NumBits = 0; unsigned Scale = 1; bool isSigned = true; switch (AddrMode) { case ARMII::AddrModeT2_i8: case ARMII::AddrModeT2_i12: // i8 supports only negative, and i12 supports only positive, so // based on Offset sign, consider the appropriate instruction Scale = 1; if (Offset < 0) { NumBits = 8; Offset = -Offset; } else { NumBits = 12; } break; case ARMII::AddrMode5: // VFP address mode. NumBits = 8; Scale = 4; break; case ARMII::AddrMode_i12: case ARMII::AddrMode2: NumBits = 12; break; case ARMII::AddrMode3: NumBits = 8; break; case ARMII::AddrModeT1_s: NumBits = 5; Scale = 4; isSigned = false; break; default: llvm_unreachable("Unsupported addressing mode!"); break; } Offset += getFrameIndexInstrOffset(MI, i); // Make sure the offset is encodable for instructions that scale the // immediate. if ((Offset & (Scale-1)) != 0) return false; if (isSigned && Offset < 0) Offset = -Offset; unsigned Mask = (1 << NumBits) - 1; if ((unsigned)Offset <= Mask * Scale) return true; return false; } void ARMBaseRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, RegScavenger *RS) const { unsigned i = 0; MachineInstr &MI = *II; MachineBasicBlock &MBB = *MI.getParent(); MachineFunction &MF = *MBB.getParent(); const ARMFrameLowering *TFI = static_cast(MF.getTarget().getFrameLowering()); ARMFunctionInfo *AFI = MF.getInfo(); assert(!AFI->isThumb1OnlyFunction() && "This eliminateFrameIndex does not support Thumb1!"); while (!MI.getOperand(i).isFI()) { ++i; assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!"); } int FrameIndex = MI.getOperand(i).getIndex(); unsigned FrameReg; int Offset = TFI->ResolveFrameIndexReference(MF, FrameIndex, FrameReg, SPAdj); // Special handling of dbg_value instructions. if (MI.isDebugValue()) { MI.getOperand(i). ChangeToRegister(FrameReg, false /*isDef*/); MI.getOperand(i+1).ChangeToImmediate(Offset); return; } // Modify MI as necessary to handle as much of 'Offset' as possible bool Done = false; if (!AFI->isThumbFunction()) Done = rewriteARMFrameIndex(MI, i, FrameReg, Offset, TII); else { assert(AFI->isThumb2Function()); Done = rewriteT2FrameIndex(MI, i, FrameReg, Offset, TII); } if (Done) return; // If we get here, the immediate doesn't fit into the instruction. We folded // as much as possible above, handle the rest, providing a register that is // SP+LargeImm. assert((Offset || (MI.getDesc().TSFlags & ARMII::AddrModeMask) == ARMII::AddrMode4 || (MI.getDesc().TSFlags & ARMII::AddrModeMask) == ARMII::AddrMode6) && "This code isn't needed if offset already handled!"); unsigned ScratchReg = 0; int PIdx = MI.findFirstPredOperandIdx(); ARMCC::CondCodes Pred = (PIdx == -1) ? ARMCC::AL : (ARMCC::CondCodes)MI.getOperand(PIdx).getImm(); unsigned PredReg = (PIdx == -1) ? 0 : MI.getOperand(PIdx+1).getReg(); if (Offset == 0) // Must be addrmode4/6. MI.getOperand(i).ChangeToRegister(FrameReg, false, false, false); else { ScratchReg = MF.getRegInfo().createVirtualRegister(ARM::GPRRegisterClass); if (!AFI->isThumbFunction()) emitARMRegPlusImmediate(MBB, II, MI.getDebugLoc(), ScratchReg, FrameReg, Offset, Pred, PredReg, TII); else { assert(AFI->isThumb2Function()); emitT2RegPlusImmediate(MBB, II, MI.getDebugLoc(), ScratchReg, FrameReg, Offset, Pred, PredReg, TII); } // Update the original instruction to use the scratch register. MI.getOperand(i).ChangeToRegister(ScratchReg, false, false, true); } } Index: head/contrib/llvm/lib/Target/ARM/ARMCallingConv.td =================================================================== --- head/contrib/llvm/lib/Target/ARM/ARMCallingConv.td (revision 228378) +++ head/contrib/llvm/lib/Target/ARM/ARMCallingConv.td (revision 228379) @@ -1,164 +1,183 @@ //===- ARMCallingConv.td - Calling Conventions for ARM -----*- tablegen -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // This describes the calling conventions for ARM architecture. //===----------------------------------------------------------------------===// /// CCIfSubtarget - Match if the current subtarget has a feature F. class CCIfSubtarget: CCIf().", F), A>; /// CCIfAlign - Match of the original alignment of the arg class CCIfAlign: CCIf; //===----------------------------------------------------------------------===// // ARM APCS Calling Convention //===----------------------------------------------------------------------===// def CC_ARM_APCS : CallingConv<[ // Handles byval parameters. CCIfByVal>, CCIfType<[i8, i16], CCPromoteToType>, // Handle all vector types as either f64 or v2f64. CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType>, CCIfType<[v2i64, v4i32, v8i16, v16i8, v4f32], CCBitConvertToType>, // f64 and v2f64 are passed in adjacent GPRs, possibly split onto the stack CCIfType<[f64, v2f64], CCCustom<"CC_ARM_APCS_Custom_f64">>, CCIfType<[f32], CCBitConvertToType>, CCIfType<[i32], CCAssignToReg<[R0, R1, R2, R3]>>, CCIfType<[i32], CCAssignToStack<4, 4>>, CCIfType<[f64], CCAssignToStack<8, 4>>, CCIfType<[v2f64], CCAssignToStack<16, 4>> ]>; def RetCC_ARM_APCS : CallingConv<[ CCIfType<[f32], CCBitConvertToType>, // Handle all vector types as either f64 or v2f64. CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType>, CCIfType<[v2i64, v4i32, v8i16, v16i8, v4f32], CCBitConvertToType>, CCIfType<[f64, v2f64], CCCustom<"RetCC_ARM_APCS_Custom_f64">>, CCIfType<[i32], CCAssignToReg<[R0, R1, R2, R3]>>, CCIfType<[i64], CCAssignToRegWithShadow<[R0, R2], [R1, R3]>> ]>; //===----------------------------------------------------------------------===// // ARM APCS Calling Convention for FastCC (when VFP2 or later is available) //===----------------------------------------------------------------------===// def FastCC_ARM_APCS : CallingConv<[ // Handle all vector types as either f64 or v2f64. CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType>, CCIfType<[v2i64, v4i32, v8i16, v16i8, v4f32], CCBitConvertToType>, CCIfType<[v2f64], CCAssignToReg<[Q0, Q1, Q2, Q3]>>, CCIfType<[f64], CCAssignToReg<[D0, D1, D2, D3, D4, D5, D6, D7]>>, CCIfType<[f32], CCAssignToReg<[S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13, S14, S15]>>, CCDelegateTo ]>; def RetFastCC_ARM_APCS : CallingConv<[ // Handle all vector types as either f64 or v2f64. CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType>, CCIfType<[v2i64, v4i32, v8i16, v16i8, v4f32], CCBitConvertToType>, CCIfType<[v2f64], CCAssignToReg<[Q0, Q1, Q2, Q3]>>, CCIfType<[f64], CCAssignToReg<[D0, D1, D2, D3, D4, D5, D6, D7]>>, CCIfType<[f32], CCAssignToReg<[S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13, S14, S15]>>, CCDelegateTo ]>; +//===----------------------------------------------------------------------===// +// ARM APCS Calling Convention for GHC +//===----------------------------------------------------------------------===// + +def CC_ARM_APCS_GHC : CallingConv<[ + // Handle all vector types as either f64 or v2f64. + CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType>, + CCIfType<[v2i64, v4i32, v8i16, v16i8, v4f32], CCBitConvertToType>, + + CCIfType<[v2f64], CCAssignToReg<[Q4, Q5]>>, + CCIfType<[f64], CCAssignToReg<[D8, D9, D10, D11]>>, + CCIfType<[f32], CCAssignToReg<[S16, S17, S18, S19, S20, S21, S22, S23]>>, + + // Promote i8/i16 arguments to i32. + CCIfType<[i8, i16], CCPromoteToType>, + + // Pass in STG registers: Base, Sp, Hp, R1, R2, R3, R4, SpLim + CCIfType<[i32], CCAssignToReg<[R4, R5, R6, R7, R8, R9, R10, R11]>> +]>; //===----------------------------------------------------------------------===// // ARM AAPCS (EABI) Calling Convention, common parts //===----------------------------------------------------------------------===// def CC_ARM_AAPCS_Common : CallingConv<[ CCIfType<[i8, i16], CCPromoteToType>, // i64/f64 is passed in even pairs of GPRs // i64 is 8-aligned i32 here, so we may need to eat R1 as a pad register // (and the same is true for f64 if VFP is not enabled) CCIfType<[i32], CCIfAlign<"8", CCAssignToRegWithShadow<[R0, R2], [R0, R1]>>>, CCIfType<[i32], CCIf<"State.getNextStackOffset() == 0 &&" "ArgFlags.getOrigAlign() != 8", CCAssignToReg<[R0, R1, R2, R3]>>>, CCIfType<[i32], CCIfAlign<"8", CCAssignToStackWithShadow<4, 8, R3>>>, CCIfType<[i32, f32], CCAssignToStack<4, 4>>, CCIfType<[f64], CCAssignToStack<8, 8>>, CCIfType<[v2f64], CCAssignToStack<16, 8>> ]>; def RetCC_ARM_AAPCS_Common : CallingConv<[ CCIfType<[i32], CCAssignToReg<[R0, R1, R2, R3]>>, CCIfType<[i64], CCAssignToRegWithShadow<[R0, R2], [R1, R3]>> ]>; //===----------------------------------------------------------------------===// // ARM AAPCS (EABI) Calling Convention //===----------------------------------------------------------------------===// def CC_ARM_AAPCS : CallingConv<[ // Handle all vector types as either f64 or v2f64. CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType>, CCIfType<[v2i64, v4i32, v8i16, v16i8, v4f32], CCBitConvertToType>, CCIfType<[f64, v2f64], CCCustom<"CC_ARM_AAPCS_Custom_f64">>, CCIfType<[f32], CCBitConvertToType>, CCDelegateTo ]>; def RetCC_ARM_AAPCS : CallingConv<[ // Handle all vector types as either f64 or v2f64. CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType>, CCIfType<[v2i64, v4i32, v8i16, v16i8, v4f32], CCBitConvertToType>, CCIfType<[f64, v2f64], CCCustom<"RetCC_ARM_AAPCS_Custom_f64">>, CCIfType<[f32], CCBitConvertToType>, CCDelegateTo ]>; //===----------------------------------------------------------------------===// // ARM AAPCS-VFP (EABI) Calling Convention // Also used for FastCC (when VFP2 or later is available) //===----------------------------------------------------------------------===// def CC_ARM_AAPCS_VFP : CallingConv<[ // Handle all vector types as either f64 or v2f64. CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType>, CCIfType<[v2i64, v4i32, v8i16, v16i8, v4f32], CCBitConvertToType>, CCIfType<[v2f64], CCAssignToReg<[Q0, Q1, Q2, Q3]>>, CCIfType<[f64], CCAssignToReg<[D0, D1, D2, D3, D4, D5, D6, D7]>>, CCIfType<[f32], CCAssignToReg<[S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13, S14, S15]>>, CCDelegateTo ]>; def RetCC_ARM_AAPCS_VFP : CallingConv<[ // Handle all vector types as either f64 or v2f64. CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType>, CCIfType<[v2i64, v4i32, v8i16, v16i8, v4f32], CCBitConvertToType>, CCIfType<[v2f64], CCAssignToReg<[Q0, Q1, Q2, Q3]>>, CCIfType<[f64], CCAssignToReg<[D0, D1, D2, D3, D4, D5, D6, D7]>>, CCIfType<[f32], CCAssignToReg<[S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13, S14, S15]>>, CCDelegateTo ]>; Index: head/contrib/llvm/lib/Target/ARM/ARMFastISel.cpp =================================================================== --- head/contrib/llvm/lib/Target/ARM/ARMFastISel.cpp (revision 228378) +++ head/contrib/llvm/lib/Target/ARM/ARMFastISel.cpp (revision 228379) @@ -1,2120 +1,2125 @@ //===-- ARMFastISel.cpp - ARM FastISel implementation ---------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines the ARM-specific support for the FastISel class. Some // of the target-specific code is generated by tablegen in the file // ARMGenFastISel.inc, which is #included here. // //===----------------------------------------------------------------------===// #include "ARM.h" #include "ARMBaseInstrInfo.h" #include "ARMCallingConv.h" #include "ARMRegisterInfo.h" #include "ARMTargetMachine.h" #include "ARMSubtarget.h" #include "ARMConstantPoolValue.h" #include "MCTargetDesc/ARMAddressingModes.h" #include "llvm/CallingConv.h" #include "llvm/DerivedTypes.h" #include "llvm/GlobalVariable.h" #include "llvm/Instructions.h" #include "llvm/IntrinsicInst.h" #include "llvm/Module.h" #include "llvm/Operator.h" #include "llvm/CodeGen/Analysis.h" #include "llvm/CodeGen/FastISel.h" #include "llvm/CodeGen/FunctionLoweringInfo.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineMemOperand.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/PseudoSourceValue.h" #include "llvm/Support/CallSite.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/GetElementPtrTypeIterator.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetLowering.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" using namespace llvm; static cl::opt DisableARMFastISel("disable-arm-fast-isel", cl::desc("Turn off experimental ARM fast-isel support"), cl::init(false), cl::Hidden); extern cl::opt EnableARMLongCalls; namespace { // All possible address modes, plus some. typedef struct Address { enum { RegBase, FrameIndexBase } BaseType; union { unsigned Reg; int FI; } Base; int Offset; // Innocuous defaults for our address. Address() : BaseType(RegBase), Offset(0) { Base.Reg = 0; } } Address; class ARMFastISel : public FastISel { /// Subtarget - Keep a pointer to the ARMSubtarget around so that we can /// make the right decision when generating code for different targets. const ARMSubtarget *Subtarget; const TargetMachine &TM; const TargetInstrInfo &TII; const TargetLowering &TLI; ARMFunctionInfo *AFI; // Convenience variables to avoid some queries. bool isThumb; LLVMContext *Context; public: explicit ARMFastISel(FunctionLoweringInfo &funcInfo) : FastISel(funcInfo), TM(funcInfo.MF->getTarget()), TII(*TM.getInstrInfo()), TLI(*TM.getTargetLowering()) { Subtarget = &TM.getSubtarget(); AFI = funcInfo.MF->getInfo(); isThumb = AFI->isThumbFunction(); Context = &funcInfo.Fn->getContext(); } // Code from FastISel.cpp. virtual unsigned FastEmitInst_(unsigned MachineInstOpcode, const TargetRegisterClass *RC); virtual unsigned FastEmitInst_r(unsigned MachineInstOpcode, const TargetRegisterClass *RC, unsigned Op0, bool Op0IsKill); virtual unsigned FastEmitInst_rr(unsigned MachineInstOpcode, const TargetRegisterClass *RC, unsigned Op0, bool Op0IsKill, unsigned Op1, bool Op1IsKill); virtual unsigned FastEmitInst_rrr(unsigned MachineInstOpcode, const TargetRegisterClass *RC, unsigned Op0, bool Op0IsKill, unsigned Op1, bool Op1IsKill, unsigned Op2, bool Op2IsKill); virtual unsigned FastEmitInst_ri(unsigned MachineInstOpcode, const TargetRegisterClass *RC, unsigned Op0, bool Op0IsKill, uint64_t Imm); virtual unsigned FastEmitInst_rf(unsigned MachineInstOpcode, const TargetRegisterClass *RC, unsigned Op0, bool Op0IsKill, const ConstantFP *FPImm); virtual unsigned FastEmitInst_rri(unsigned MachineInstOpcode, const TargetRegisterClass *RC, unsigned Op0, bool Op0IsKill, unsigned Op1, bool Op1IsKill, uint64_t Imm); virtual unsigned FastEmitInst_i(unsigned MachineInstOpcode, const TargetRegisterClass *RC, uint64_t Imm); virtual unsigned FastEmitInst_ii(unsigned MachineInstOpcode, const TargetRegisterClass *RC, uint64_t Imm1, uint64_t Imm2); virtual unsigned FastEmitInst_extractsubreg(MVT RetVT, unsigned Op0, bool Op0IsKill, uint32_t Idx); // Backend specific FastISel code. virtual bool TargetSelectInstruction(const Instruction *I); virtual unsigned TargetMaterializeConstant(const Constant *C); virtual unsigned TargetMaterializeAlloca(const AllocaInst *AI); #include "ARMGenFastISel.inc" // Instruction selection routines. private: bool SelectLoad(const Instruction *I); bool SelectStore(const Instruction *I); bool SelectBranch(const Instruction *I); bool SelectCmp(const Instruction *I); bool SelectFPExt(const Instruction *I); bool SelectFPTrunc(const Instruction *I); bool SelectBinaryOp(const Instruction *I, unsigned ISDOpcode); bool SelectSIToFP(const Instruction *I); bool SelectFPToSI(const Instruction *I); bool SelectSDiv(const Instruction *I); bool SelectSRem(const Instruction *I); bool SelectCall(const Instruction *I); bool SelectSelect(const Instruction *I); bool SelectRet(const Instruction *I); bool SelectIntCast(const Instruction *I); // Utility routines. private: bool isTypeLegal(Type *Ty, MVT &VT); bool isLoadTypeLegal(Type *Ty, MVT &VT); bool ARMEmitLoad(EVT VT, unsigned &ResultReg, Address &Addr); bool ARMEmitStore(EVT VT, unsigned SrcReg, Address &Addr); bool ARMComputeAddress(const Value *Obj, Address &Addr); void ARMSimplifyAddress(Address &Addr, EVT VT); unsigned ARMMaterializeFP(const ConstantFP *CFP, EVT VT); unsigned ARMMaterializeInt(const Constant *C, EVT VT); unsigned ARMMaterializeGV(const GlobalValue *GV, EVT VT); unsigned ARMMoveToFPReg(EVT VT, unsigned SrcReg); unsigned ARMMoveToIntReg(EVT VT, unsigned SrcReg); unsigned ARMSelectCallOp(const GlobalValue *GV); // Call handling routines. private: bool FastEmitExtend(ISD::NodeType Opc, EVT DstVT, unsigned Src, EVT SrcVT, unsigned &ResultReg); CCAssignFn *CCAssignFnForCall(CallingConv::ID CC, bool Return); bool ProcessCallArgs(SmallVectorImpl &Args, SmallVectorImpl &ArgRegs, SmallVectorImpl &ArgVTs, SmallVectorImpl &ArgFlags, SmallVectorImpl &RegArgs, CallingConv::ID CC, unsigned &NumBytes); bool FinishCall(MVT RetVT, SmallVectorImpl &UsedRegs, const Instruction *I, CallingConv::ID CC, unsigned &NumBytes); bool ARMEmitLibcall(const Instruction *I, RTLIB::Libcall Call); // OptionalDef handling routines. private: bool isARMNEONPred(const MachineInstr *MI); bool DefinesOptionalPredicate(MachineInstr *MI, bool *CPSR); const MachineInstrBuilder &AddOptionalDefs(const MachineInstrBuilder &MIB); void AddLoadStoreOperands(EVT VT, Address &Addr, const MachineInstrBuilder &MIB, unsigned Flags); }; } // end anonymous namespace #include "ARMGenCallingConv.inc" // DefinesOptionalPredicate - This is different from DefinesPredicate in that // we don't care about implicit defs here, just places we'll need to add a // default CCReg argument. Sets CPSR if we're setting CPSR instead of CCR. bool ARMFastISel::DefinesOptionalPredicate(MachineInstr *MI, bool *CPSR) { const MCInstrDesc &MCID = MI->getDesc(); if (!MCID.hasOptionalDef()) return false; // Look to see if our OptionalDef is defining CPSR or CCR. for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { const MachineOperand &MO = MI->getOperand(i); if (!MO.isReg() || !MO.isDef()) continue; if (MO.getReg() == ARM::CPSR) *CPSR = true; } return true; } bool ARMFastISel::isARMNEONPred(const MachineInstr *MI) { const MCInstrDesc &MCID = MI->getDesc(); // If we're a thumb2 or not NEON function we were handled via isPredicable. if ((MCID.TSFlags & ARMII::DomainMask) != ARMII::DomainNEON || AFI->isThumb2Function()) return false; for (unsigned i = 0, e = MCID.getNumOperands(); i != e; ++i) if (MCID.OpInfo[i].isPredicate()) return true; return false; } // If the machine is predicable go ahead and add the predicate operands, if // it needs default CC operands add those. // TODO: If we want to support thumb1 then we'll need to deal with optional // CPSR defs that need to be added before the remaining operands. See s_cc_out // for descriptions why. const MachineInstrBuilder & ARMFastISel::AddOptionalDefs(const MachineInstrBuilder &MIB) { MachineInstr *MI = &*MIB; // Do we use a predicate? or... // Are we NEON in ARM mode and have a predicate operand? If so, I know // we're not predicable but add it anyways. if (TII.isPredicable(MI) || isARMNEONPred(MI)) AddDefaultPred(MIB); // Do we optionally set a predicate? Preds is size > 0 iff the predicate // defines CPSR. All other OptionalDefines in ARM are the CCR register. bool CPSR = false; if (DefinesOptionalPredicate(MI, &CPSR)) { if (CPSR) AddDefaultT1CC(MIB); else AddDefaultCC(MIB); } return MIB; } unsigned ARMFastISel::FastEmitInst_(unsigned MachineInstOpcode, const TargetRegisterClass* RC) { unsigned ResultReg = createResultReg(RC); const MCInstrDesc &II = TII.get(MachineInstOpcode); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II, ResultReg)); return ResultReg; } unsigned ARMFastISel::FastEmitInst_r(unsigned MachineInstOpcode, const TargetRegisterClass *RC, unsigned Op0, bool Op0IsKill) { unsigned ResultReg = createResultReg(RC); const MCInstrDesc &II = TII.get(MachineInstOpcode); if (II.getNumDefs() >= 1) AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II, ResultReg) .addReg(Op0, Op0IsKill * RegState::Kill)); else { AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II) .addReg(Op0, Op0IsKill * RegState::Kill)); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(TargetOpcode::COPY), ResultReg) .addReg(II.ImplicitDefs[0])); } return ResultReg; } unsigned ARMFastISel::FastEmitInst_rr(unsigned MachineInstOpcode, const TargetRegisterClass *RC, unsigned Op0, bool Op0IsKill, unsigned Op1, bool Op1IsKill) { unsigned ResultReg = createResultReg(RC); const MCInstrDesc &II = TII.get(MachineInstOpcode); if (II.getNumDefs() >= 1) AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II, ResultReg) .addReg(Op0, Op0IsKill * RegState::Kill) .addReg(Op1, Op1IsKill * RegState::Kill)); else { AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II) .addReg(Op0, Op0IsKill * RegState::Kill) .addReg(Op1, Op1IsKill * RegState::Kill)); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(TargetOpcode::COPY), ResultReg) .addReg(II.ImplicitDefs[0])); } return ResultReg; } unsigned ARMFastISel::FastEmitInst_rrr(unsigned MachineInstOpcode, const TargetRegisterClass *RC, unsigned Op0, bool Op0IsKill, unsigned Op1, bool Op1IsKill, unsigned Op2, bool Op2IsKill) { unsigned ResultReg = createResultReg(RC); const MCInstrDesc &II = TII.get(MachineInstOpcode); if (II.getNumDefs() >= 1) AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II, ResultReg) .addReg(Op0, Op0IsKill * RegState::Kill) .addReg(Op1, Op1IsKill * RegState::Kill) .addReg(Op2, Op2IsKill * RegState::Kill)); else { AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II) .addReg(Op0, Op0IsKill * RegState::Kill) .addReg(Op1, Op1IsKill * RegState::Kill) .addReg(Op2, Op2IsKill * RegState::Kill)); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(TargetOpcode::COPY), ResultReg) .addReg(II.ImplicitDefs[0])); } return ResultReg; } unsigned ARMFastISel::FastEmitInst_ri(unsigned MachineInstOpcode, const TargetRegisterClass *RC, unsigned Op0, bool Op0IsKill, uint64_t Imm) { unsigned ResultReg = createResultReg(RC); const MCInstrDesc &II = TII.get(MachineInstOpcode); if (II.getNumDefs() >= 1) AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II, ResultReg) .addReg(Op0, Op0IsKill * RegState::Kill) .addImm(Imm)); else { AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II) .addReg(Op0, Op0IsKill * RegState::Kill) .addImm(Imm)); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(TargetOpcode::COPY), ResultReg) .addReg(II.ImplicitDefs[0])); } return ResultReg; } unsigned ARMFastISel::FastEmitInst_rf(unsigned MachineInstOpcode, const TargetRegisterClass *RC, unsigned Op0, bool Op0IsKill, const ConstantFP *FPImm) { unsigned ResultReg = createResultReg(RC); const MCInstrDesc &II = TII.get(MachineInstOpcode); if (II.getNumDefs() >= 1) AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II, ResultReg) .addReg(Op0, Op0IsKill * RegState::Kill) .addFPImm(FPImm)); else { AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II) .addReg(Op0, Op0IsKill * RegState::Kill) .addFPImm(FPImm)); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(TargetOpcode::COPY), ResultReg) .addReg(II.ImplicitDefs[0])); } return ResultReg; } unsigned ARMFastISel::FastEmitInst_rri(unsigned MachineInstOpcode, const TargetRegisterClass *RC, unsigned Op0, bool Op0IsKill, unsigned Op1, bool Op1IsKill, uint64_t Imm) { unsigned ResultReg = createResultReg(RC); const MCInstrDesc &II = TII.get(MachineInstOpcode); if (II.getNumDefs() >= 1) AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II, ResultReg) .addReg(Op0, Op0IsKill * RegState::Kill) .addReg(Op1, Op1IsKill * RegState::Kill) .addImm(Imm)); else { AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II) .addReg(Op0, Op0IsKill * RegState::Kill) .addReg(Op1, Op1IsKill * RegState::Kill) .addImm(Imm)); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(TargetOpcode::COPY), ResultReg) .addReg(II.ImplicitDefs[0])); } return ResultReg; } unsigned ARMFastISel::FastEmitInst_i(unsigned MachineInstOpcode, const TargetRegisterClass *RC, uint64_t Imm) { unsigned ResultReg = createResultReg(RC); const MCInstrDesc &II = TII.get(MachineInstOpcode); if (II.getNumDefs() >= 1) AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II, ResultReg) .addImm(Imm)); else { AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II) .addImm(Imm)); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(TargetOpcode::COPY), ResultReg) .addReg(II.ImplicitDefs[0])); } return ResultReg; } unsigned ARMFastISel::FastEmitInst_ii(unsigned MachineInstOpcode, const TargetRegisterClass *RC, uint64_t Imm1, uint64_t Imm2) { unsigned ResultReg = createResultReg(RC); const MCInstrDesc &II = TII.get(MachineInstOpcode); if (II.getNumDefs() >= 1) AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II, ResultReg) .addImm(Imm1).addImm(Imm2)); else { AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II) .addImm(Imm1).addImm(Imm2)); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(TargetOpcode::COPY), ResultReg) .addReg(II.ImplicitDefs[0])); } return ResultReg; } unsigned ARMFastISel::FastEmitInst_extractsubreg(MVT RetVT, unsigned Op0, bool Op0IsKill, uint32_t Idx) { unsigned ResultReg = createResultReg(TLI.getRegClassFor(RetVT)); assert(TargetRegisterInfo::isVirtualRegister(Op0) && "Cannot yet extract from physregs"); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(TargetOpcode::COPY), ResultReg) .addReg(Op0, getKillRegState(Op0IsKill), Idx)); return ResultReg; } // TODO: Don't worry about 64-bit now, but when this is fixed remove the // checks from the various callers. unsigned ARMFastISel::ARMMoveToFPReg(EVT VT, unsigned SrcReg) { if (VT == MVT::f64) return 0; unsigned MoveReg = createResultReg(TLI.getRegClassFor(VT)); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(ARM::VMOVRS), MoveReg) .addReg(SrcReg)); return MoveReg; } unsigned ARMFastISel::ARMMoveToIntReg(EVT VT, unsigned SrcReg) { if (VT == MVT::i64) return 0; unsigned MoveReg = createResultReg(TLI.getRegClassFor(VT)); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(ARM::VMOVSR), MoveReg) .addReg(SrcReg)); return MoveReg; } // For double width floating point we need to materialize two constants // (the high and the low) into integer registers then use a move to get // the combined constant into an FP reg. unsigned ARMFastISel::ARMMaterializeFP(const ConstantFP *CFP, EVT VT) { const APFloat Val = CFP->getValueAPF(); bool is64bit = VT == MVT::f64; // This checks to see if we can use VFP3 instructions to materialize // a constant, otherwise we have to go through the constant pool. if (TLI.isFPImmLegal(Val, VT)) { int Imm; unsigned Opc; if (is64bit) { Imm = ARM_AM::getFP64Imm(Val); Opc = ARM::FCONSTD; } else { Imm = ARM_AM::getFP32Imm(Val); Opc = ARM::FCONSTS; } unsigned DestReg = createResultReg(TLI.getRegClassFor(VT)); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(Opc), DestReg) .addImm(Imm)); return DestReg; } // Require VFP2 for loading fp constants. if (!Subtarget->hasVFP2()) return false; // MachineConstantPool wants an explicit alignment. unsigned Align = TD.getPrefTypeAlignment(CFP->getType()); if (Align == 0) { // TODO: Figure out if this is correct. Align = TD.getTypeAllocSize(CFP->getType()); } unsigned Idx = MCP.getConstantPoolIndex(cast(CFP), Align); unsigned DestReg = createResultReg(TLI.getRegClassFor(VT)); unsigned Opc = is64bit ? ARM::VLDRD : ARM::VLDRS; // The extra reg is for addrmode5. AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(Opc), DestReg) .addConstantPoolIndex(Idx) .addReg(0)); return DestReg; } unsigned ARMFastISel::ARMMaterializeInt(const Constant *C, EVT VT) { // For now 32-bit only. if (VT != MVT::i32) return false; unsigned DestReg = createResultReg(TLI.getRegClassFor(VT)); // If we can do this in a single instruction without a constant pool entry // do so now. const ConstantInt *CI = cast(C); if (Subtarget->hasV6T2Ops() && isUInt<16>(CI->getSExtValue())) { unsigned Opc = isThumb ? ARM::t2MOVi16 : ARM::MOVi16; AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(Opc), DestReg) .addImm(CI->getSExtValue())); return DestReg; } // MachineConstantPool wants an explicit alignment. unsigned Align = TD.getPrefTypeAlignment(C->getType()); if (Align == 0) { // TODO: Figure out if this is correct. Align = TD.getTypeAllocSize(C->getType()); } unsigned Idx = MCP.getConstantPoolIndex(C, Align); if (isThumb) AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(ARM::t2LDRpci), DestReg) .addConstantPoolIndex(Idx)); else // The extra immediate is for addrmode2. AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(ARM::LDRcp), DestReg) .addConstantPoolIndex(Idx) .addImm(0)); return DestReg; } unsigned ARMFastISel::ARMMaterializeGV(const GlobalValue *GV, EVT VT) { // For now 32-bit only. if (VT != MVT::i32) return 0; Reloc::Model RelocM = TM.getRelocationModel(); // TODO: Need more magic for ARM PIC. if (!isThumb && (RelocM == Reloc::PIC_)) return 0; // MachineConstantPool wants an explicit alignment. unsigned Align = TD.getPrefTypeAlignment(GV->getType()); if (Align == 0) { // TODO: Figure out if this is correct. Align = TD.getTypeAllocSize(GV->getType()); } // Grab index. unsigned PCAdj = (RelocM != Reloc::PIC_) ? 0 : (Subtarget->isThumb() ? 4 : 8); unsigned Id = AFI->createPICLabelUId(); ARMConstantPoolValue *CPV = ARMConstantPoolConstant::Create(GV, Id, ARMCP::CPValue, PCAdj); unsigned Idx = MCP.getConstantPoolIndex(CPV, Align); // Load value. MachineInstrBuilder MIB; unsigned DestReg = createResultReg(TLI.getRegClassFor(VT)); if (isThumb) { unsigned Opc = (RelocM != Reloc::PIC_) ? ARM::t2LDRpci : ARM::t2LDRpci_pic; MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(Opc), DestReg) .addConstantPoolIndex(Idx); if (RelocM == Reloc::PIC_) MIB.addImm(Id); } else { // The extra immediate is for addrmode2. MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(ARM::LDRcp), DestReg) .addConstantPoolIndex(Idx) .addImm(0); } AddOptionalDefs(MIB); if (Subtarget->GVIsIndirectSymbol(GV, RelocM)) { unsigned NewDestReg = createResultReg(TLI.getRegClassFor(VT)); if (isThumb) MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(ARM::t2LDRi12), NewDestReg) .addReg(DestReg) .addImm(0); else MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(ARM::LDRi12), NewDestReg) .addReg(DestReg) .addImm(0); DestReg = NewDestReg; AddOptionalDefs(MIB); } return DestReg; } unsigned ARMFastISel::TargetMaterializeConstant(const Constant *C) { EVT VT = TLI.getValueType(C->getType(), true); // Only handle simple types. if (!VT.isSimple()) return 0; if (const ConstantFP *CFP = dyn_cast(C)) return ARMMaterializeFP(CFP, VT); else if (const GlobalValue *GV = dyn_cast(C)) return ARMMaterializeGV(GV, VT); else if (isa(C)) return ARMMaterializeInt(C, VT); return 0; } unsigned ARMFastISel::TargetMaterializeAlloca(const AllocaInst *AI) { // Don't handle dynamic allocas. if (!FuncInfo.StaticAllocaMap.count(AI)) return 0; MVT VT; if (!isLoadTypeLegal(AI->getType(), VT)) return false; DenseMap::iterator SI = FuncInfo.StaticAllocaMap.find(AI); // This will get lowered later into the correct offsets and registers // via rewriteXFrameIndex. if (SI != FuncInfo.StaticAllocaMap.end()) { TargetRegisterClass* RC = TLI.getRegClassFor(VT); unsigned ResultReg = createResultReg(RC); unsigned Opc = isThumb ? ARM::t2ADDri : ARM::ADDri; AddOptionalDefs(BuildMI(*FuncInfo.MBB, *FuncInfo.InsertPt, DL, TII.get(Opc), ResultReg) .addFrameIndex(SI->second) .addImm(0)); return ResultReg; } return 0; } bool ARMFastISel::isTypeLegal(Type *Ty, MVT &VT) { EVT evt = TLI.getValueType(Ty, true); // Only handle simple types. if (evt == MVT::Other || !evt.isSimple()) return false; VT = evt.getSimpleVT(); // Handle all legal types, i.e. a register that will directly hold this // value. return TLI.isTypeLegal(VT); } bool ARMFastISel::isLoadTypeLegal(Type *Ty, MVT &VT) { if (isTypeLegal(Ty, VT)) return true; // If this is a type than can be sign or zero-extended to a basic operation // go ahead and accept it now. if (VT == MVT::i8 || VT == MVT::i16) return true; return false; } // Computes the address to get to an object. bool ARMFastISel::ARMComputeAddress(const Value *Obj, Address &Addr) { // Some boilerplate from the X86 FastISel. const User *U = NULL; unsigned Opcode = Instruction::UserOp1; if (const Instruction *I = dyn_cast(Obj)) { // Don't walk into other basic blocks unless the object is an alloca from // another block, otherwise it may not have a virtual register assigned. if (FuncInfo.StaticAllocaMap.count(static_cast(Obj)) || FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) { Opcode = I->getOpcode(); U = I; } } else if (const ConstantExpr *C = dyn_cast(Obj)) { Opcode = C->getOpcode(); U = C; } if (PointerType *Ty = dyn_cast(Obj->getType())) if (Ty->getAddressSpace() > 255) // Fast instruction selection doesn't support the special // address spaces. return false; switch (Opcode) { default: break; case Instruction::BitCast: { // Look through bitcasts. return ARMComputeAddress(U->getOperand(0), Addr); } case Instruction::IntToPtr: { // Look past no-op inttoptrs. if (TLI.getValueType(U->getOperand(0)->getType()) == TLI.getPointerTy()) return ARMComputeAddress(U->getOperand(0), Addr); break; } case Instruction::PtrToInt: { // Look past no-op ptrtoints. if (TLI.getValueType(U->getType()) == TLI.getPointerTy()) return ARMComputeAddress(U->getOperand(0), Addr); break; } case Instruction::GetElementPtr: { Address SavedAddr = Addr; int TmpOffset = Addr.Offset; // Iterate through the GEP folding the constants into offsets where // we can. gep_type_iterator GTI = gep_type_begin(U); for (User::const_op_iterator i = U->op_begin() + 1, e = U->op_end(); i != e; ++i, ++GTI) { const Value *Op = *i; if (StructType *STy = dyn_cast(*GTI)) { const StructLayout *SL = TD.getStructLayout(STy); unsigned Idx = cast(Op)->getZExtValue(); TmpOffset += SL->getElementOffset(Idx); } else { uint64_t S = TD.getTypeAllocSize(GTI.getIndexedType()); for (;;) { if (const ConstantInt *CI = dyn_cast(Op)) { // Constant-offset addressing. TmpOffset += CI->getSExtValue() * S; break; } if (isa(Op) && (!isa(Op) || FuncInfo.MBBMap[cast(Op)->getParent()] == FuncInfo.MBB) && isa(cast(Op)->getOperand(1))) { // An add (in the same block) with a constant operand. Fold the // constant. ConstantInt *CI = cast(cast(Op)->getOperand(1)); TmpOffset += CI->getSExtValue() * S; // Iterate on the other operand. Op = cast(Op)->getOperand(0); continue; } // Unsupported goto unsupported_gep; } } } // Try to grab the base operand now. Addr.Offset = TmpOffset; if (ARMComputeAddress(U->getOperand(0), Addr)) return true; // We failed, restore everything and try the other options. Addr = SavedAddr; unsupported_gep: break; } case Instruction::Alloca: { const AllocaInst *AI = cast(Obj); DenseMap::iterator SI = FuncInfo.StaticAllocaMap.find(AI); if (SI != FuncInfo.StaticAllocaMap.end()) { Addr.BaseType = Address::FrameIndexBase; Addr.Base.FI = SI->second; return true; } break; } } // Materialize the global variable's address into a reg which can // then be used later to load the variable. if (const GlobalValue *GV = dyn_cast(Obj)) { unsigned Tmp = ARMMaterializeGV(GV, TLI.getValueType(Obj->getType())); if (Tmp == 0) return false; Addr.Base.Reg = Tmp; return true; } // Try to get this in a register if nothing else has worked. if (Addr.Base.Reg == 0) Addr.Base.Reg = getRegForValue(Obj); return Addr.Base.Reg != 0; } void ARMFastISel::ARMSimplifyAddress(Address &Addr, EVT VT) { assert(VT.isSimple() && "Non-simple types are invalid here!"); bool needsLowering = false; switch (VT.getSimpleVT().SimpleTy) { default: assert(false && "Unhandled load/store type!"); case MVT::i1: case MVT::i8: case MVT::i16: case MVT::i32: // Integer loads/stores handle 12-bit offsets. needsLowering = ((Addr.Offset & 0xfff) != Addr.Offset); break; case MVT::f32: case MVT::f64: // Floating point operands handle 8-bit offsets. needsLowering = ((Addr.Offset & 0xff) != Addr.Offset); break; } // If this is a stack pointer and the offset needs to be simplified then // put the alloca address into a register, set the base type back to // register and continue. This should almost never happen. if (needsLowering && Addr.BaseType == Address::FrameIndexBase) { TargetRegisterClass *RC = isThumb ? ARM::tGPRRegisterClass : ARM::GPRRegisterClass; unsigned ResultReg = createResultReg(RC); unsigned Opc = isThumb ? ARM::t2ADDri : ARM::ADDri; AddOptionalDefs(BuildMI(*FuncInfo.MBB, *FuncInfo.InsertPt, DL, TII.get(Opc), ResultReg) .addFrameIndex(Addr.Base.FI) .addImm(0)); Addr.Base.Reg = ResultReg; Addr.BaseType = Address::RegBase; } // Since the offset is too large for the load/store instruction // get the reg+offset into a register. if (needsLowering) { Addr.Base.Reg = FastEmit_ri_(MVT::i32, ISD::ADD, Addr.Base.Reg, /*Op0IsKill*/false, Addr.Offset, MVT::i32); Addr.Offset = 0; } } void ARMFastISel::AddLoadStoreOperands(EVT VT, Address &Addr, const MachineInstrBuilder &MIB, unsigned Flags) { // addrmode5 output depends on the selection dag addressing dividing the // offset by 4 that it then later multiplies. Do this here as well. if (VT.getSimpleVT().SimpleTy == MVT::f32 || VT.getSimpleVT().SimpleTy == MVT::f64) Addr.Offset /= 4; // Frame base works a bit differently. Handle it separately. if (Addr.BaseType == Address::FrameIndexBase) { int FI = Addr.Base.FI; int Offset = Addr.Offset; MachineMemOperand *MMO = FuncInfo.MF->getMachineMemOperand( MachinePointerInfo::getFixedStack(FI, Offset), Flags, MFI.getObjectSize(FI), MFI.getObjectAlignment(FI)); // Now add the rest of the operands. MIB.addFrameIndex(FI); // ARM halfword load/stores need an additional operand. if (!isThumb && VT.getSimpleVT().SimpleTy == MVT::i16) MIB.addReg(0); MIB.addImm(Addr.Offset); MIB.addMemOperand(MMO); } else { // Now add the rest of the operands. MIB.addReg(Addr.Base.Reg); // ARM halfword load/stores need an additional operand. if (!isThumb && VT.getSimpleVT().SimpleTy == MVT::i16) MIB.addReg(0); MIB.addImm(Addr.Offset); } AddOptionalDefs(MIB); } bool ARMFastISel::ARMEmitLoad(EVT VT, unsigned &ResultReg, Address &Addr) { assert(VT.isSimple() && "Non-simple types are invalid here!"); unsigned Opc; TargetRegisterClass *RC; switch (VT.getSimpleVT().SimpleTy) { // This is mostly going to be Neon/vector support. default: return false; case MVT::i16: Opc = isThumb ? ARM::t2LDRHi12 : ARM::LDRH; RC = ARM::GPRRegisterClass; break; case MVT::i8: Opc = isThumb ? ARM::t2LDRBi12 : ARM::LDRBi12; RC = ARM::GPRRegisterClass; break; case MVT::i32: Opc = isThumb ? ARM::t2LDRi12 : ARM::LDRi12; RC = ARM::GPRRegisterClass; break; case MVT::f32: Opc = ARM::VLDRS; RC = TLI.getRegClassFor(VT); break; case MVT::f64: Opc = ARM::VLDRD; RC = TLI.getRegClassFor(VT); break; } // Simplify this down to something we can handle. ARMSimplifyAddress(Addr, VT); // Create the base instruction, then add the operands. ResultReg = createResultReg(RC); MachineInstrBuilder MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(Opc), ResultReg); AddLoadStoreOperands(VT, Addr, MIB, MachineMemOperand::MOLoad); return true; } bool ARMFastISel::SelectLoad(const Instruction *I) { // Atomic loads need special handling. if (cast(I)->isAtomic()) return false; // Verify we have a legal type before going any further. MVT VT; if (!isLoadTypeLegal(I->getType(), VT)) return false; // See if we can handle this address. Address Addr; if (!ARMComputeAddress(I->getOperand(0), Addr)) return false; unsigned ResultReg; if (!ARMEmitLoad(VT, ResultReg, Addr)) return false; UpdateValueMap(I, ResultReg); return true; } bool ARMFastISel::ARMEmitStore(EVT VT, unsigned SrcReg, Address &Addr) { unsigned StrOpc; switch (VT.getSimpleVT().SimpleTy) { // This is mostly going to be Neon/vector support. default: return false; case MVT::i1: { unsigned Res = createResultReg(isThumb ? ARM::tGPRRegisterClass : ARM::GPRRegisterClass); unsigned Opc = isThumb ? ARM::t2ANDri : ARM::ANDri; AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(Opc), Res) .addReg(SrcReg).addImm(1)); SrcReg = Res; } // Fallthrough here. case MVT::i8: StrOpc = isThumb ? ARM::t2STRBi12 : ARM::STRBi12; break; case MVT::i16: StrOpc = isThumb ? ARM::t2STRHi12 : ARM::STRH; break; case MVT::i32: StrOpc = isThumb ? ARM::t2STRi12 : ARM::STRi12; break; case MVT::f32: if (!Subtarget->hasVFP2()) return false; StrOpc = ARM::VSTRS; break; case MVT::f64: if (!Subtarget->hasVFP2()) return false; StrOpc = ARM::VSTRD; break; } // Simplify this down to something we can handle. ARMSimplifyAddress(Addr, VT); // Create the base instruction, then add the operands. MachineInstrBuilder MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(StrOpc)) .addReg(SrcReg, getKillRegState(true)); AddLoadStoreOperands(VT, Addr, MIB, MachineMemOperand::MOStore); return true; } bool ARMFastISel::SelectStore(const Instruction *I) { Value *Op0 = I->getOperand(0); unsigned SrcReg = 0; // Atomic stores need special handling. if (cast(I)->isAtomic()) return false; // Verify we have a legal type before going any further. MVT VT; if (!isLoadTypeLegal(I->getOperand(0)->getType(), VT)) return false; // Get the value to be stored into a register. SrcReg = getRegForValue(Op0); if (SrcReg == 0) return false; // See if we can handle this address. Address Addr; if (!ARMComputeAddress(I->getOperand(1), Addr)) return false; if (!ARMEmitStore(VT, SrcReg, Addr)) return false; return true; } static ARMCC::CondCodes getComparePred(CmpInst::Predicate Pred) { switch (Pred) { // Needs two compares... case CmpInst::FCMP_ONE: case CmpInst::FCMP_UEQ: default: // AL is our "false" for now. The other two need more compares. return ARMCC::AL; case CmpInst::ICMP_EQ: case CmpInst::FCMP_OEQ: return ARMCC::EQ; case CmpInst::ICMP_SGT: case CmpInst::FCMP_OGT: return ARMCC::GT; case CmpInst::ICMP_SGE: case CmpInst::FCMP_OGE: return ARMCC::GE; case CmpInst::ICMP_UGT: case CmpInst::FCMP_UGT: return ARMCC::HI; case CmpInst::FCMP_OLT: return ARMCC::MI; case CmpInst::ICMP_ULE: case CmpInst::FCMP_OLE: return ARMCC::LS; case CmpInst::FCMP_ORD: return ARMCC::VC; case CmpInst::FCMP_UNO: return ARMCC::VS; case CmpInst::FCMP_UGE: return ARMCC::PL; case CmpInst::ICMP_SLT: case CmpInst::FCMP_ULT: return ARMCC::LT; case CmpInst::ICMP_SLE: case CmpInst::FCMP_ULE: return ARMCC::LE; case CmpInst::FCMP_UNE: case CmpInst::ICMP_NE: return ARMCC::NE; case CmpInst::ICMP_UGE: return ARMCC::HS; case CmpInst::ICMP_ULT: return ARMCC::LO; } } bool ARMFastISel::SelectBranch(const Instruction *I) { const BranchInst *BI = cast(I); MachineBasicBlock *TBB = FuncInfo.MBBMap[BI->getSuccessor(0)]; MachineBasicBlock *FBB = FuncInfo.MBBMap[BI->getSuccessor(1)]; // Simple branch support. // If we can, avoid recomputing the compare - redoing it could lead to wonky // behavior. // TODO: Factor this out. if (const CmpInst *CI = dyn_cast(BI->getCondition())) { MVT SourceVT; Type *Ty = CI->getOperand(0)->getType(); if (CI->hasOneUse() && (CI->getParent() == I->getParent()) && isTypeLegal(Ty, SourceVT)) { bool isFloat = (Ty->isDoubleTy() || Ty->isFloatTy()); if (isFloat && !Subtarget->hasVFP2()) return false; unsigned CmpOpc; switch (SourceVT.SimpleTy) { default: return false; // TODO: Verify compares. case MVT::f32: CmpOpc = ARM::VCMPES; break; case MVT::f64: CmpOpc = ARM::VCMPED; break; case MVT::i32: CmpOpc = isThumb ? ARM::t2CMPrr : ARM::CMPrr; break; } // Get the compare predicate. // Try to take advantage of fallthrough opportunities. CmpInst::Predicate Predicate = CI->getPredicate(); if (FuncInfo.MBB->isLayoutSuccessor(TBB)) { std::swap(TBB, FBB); Predicate = CmpInst::getInversePredicate(Predicate); } ARMCC::CondCodes ARMPred = getComparePred(Predicate); // We may not handle every CC for now. if (ARMPred == ARMCC::AL) return false; unsigned Arg1 = getRegForValue(CI->getOperand(0)); if (Arg1 == 0) return false; unsigned Arg2 = getRegForValue(CI->getOperand(1)); if (Arg2 == 0) return false; AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(CmpOpc)) .addReg(Arg1).addReg(Arg2)); // For floating point we need to move the result to a comparison register // that we can then use for branches. if (isFloat) AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(ARM::FMSTAT))); unsigned BrOpc = isThumb ? ARM::t2Bcc : ARM::Bcc; BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(BrOpc)) .addMBB(TBB).addImm(ARMPred).addReg(ARM::CPSR); FastEmitBranch(FBB, DL); FuncInfo.MBB->addSuccessor(TBB); return true; } } else if (TruncInst *TI = dyn_cast(BI->getCondition())) { MVT SourceVT; if (TI->hasOneUse() && TI->getParent() == I->getParent() && (isLoadTypeLegal(TI->getOperand(0)->getType(), SourceVT))) { unsigned TstOpc = isThumb ? ARM::t2TSTri : ARM::TSTri; unsigned OpReg = getRegForValue(TI->getOperand(0)); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(TstOpc)) .addReg(OpReg).addImm(1)); unsigned CCMode = ARMCC::NE; if (FuncInfo.MBB->isLayoutSuccessor(TBB)) { std::swap(TBB, FBB); CCMode = ARMCC::EQ; } unsigned BrOpc = isThumb ? ARM::t2Bcc : ARM::Bcc; BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(BrOpc)) .addMBB(TBB).addImm(CCMode).addReg(ARM::CPSR); FastEmitBranch(FBB, DL); FuncInfo.MBB->addSuccessor(TBB); return true; } } unsigned CmpReg = getRegForValue(BI->getCondition()); if (CmpReg == 0) return false; // We've been divorced from our compare! Our block was split, and // now our compare lives in a predecessor block. We musn't // re-compare here, as the children of the compare aren't guaranteed // live across the block boundary (we *could* check for this). // Regardless, the compare has been done in the predecessor block, // and it left a value for us in a virtual register. Ergo, we test // the one-bit value left in the virtual register. unsigned TstOpc = isThumb ? ARM::t2TSTri : ARM::TSTri; AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(TstOpc)) .addReg(CmpReg).addImm(1)); unsigned CCMode = ARMCC::NE; if (FuncInfo.MBB->isLayoutSuccessor(TBB)) { std::swap(TBB, FBB); CCMode = ARMCC::EQ; } unsigned BrOpc = isThumb ? ARM::t2Bcc : ARM::Bcc; BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(BrOpc)) .addMBB(TBB).addImm(CCMode).addReg(ARM::CPSR); FastEmitBranch(FBB, DL); FuncInfo.MBB->addSuccessor(TBB); return true; } bool ARMFastISel::SelectCmp(const Instruction *I) { const CmpInst *CI = cast(I); MVT VT; Type *Ty = CI->getOperand(0)->getType(); if (!isTypeLegal(Ty, VT)) return false; bool isFloat = (Ty->isDoubleTy() || Ty->isFloatTy()); if (isFloat && !Subtarget->hasVFP2()) return false; unsigned CmpOpc; unsigned CondReg; switch (VT.SimpleTy) { default: return false; // TODO: Verify compares. case MVT::f32: CmpOpc = ARM::VCMPES; CondReg = ARM::FPSCR; break; case MVT::f64: CmpOpc = ARM::VCMPED; CondReg = ARM::FPSCR; break; case MVT::i32: CmpOpc = isThumb ? ARM::t2CMPrr : ARM::CMPrr; CondReg = ARM::CPSR; break; } // Get the compare predicate. ARMCC::CondCodes ARMPred = getComparePred(CI->getPredicate()); // We may not handle every CC for now. if (ARMPred == ARMCC::AL) return false; unsigned Arg1 = getRegForValue(CI->getOperand(0)); if (Arg1 == 0) return false; unsigned Arg2 = getRegForValue(CI->getOperand(1)); if (Arg2 == 0) return false; AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(CmpOpc)) .addReg(Arg1).addReg(Arg2)); // For floating point we need to move the result to a comparison register // that we can then use for branches. if (isFloat) AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(ARM::FMSTAT))); // Now set a register based on the comparison. Explicitly set the predicates // here. unsigned MovCCOpc = isThumb ? ARM::t2MOVCCi : ARM::MOVCCi; TargetRegisterClass *RC = isThumb ? ARM::rGPRRegisterClass : ARM::GPRRegisterClass; unsigned DestReg = createResultReg(RC); Constant *Zero = ConstantInt::get(Type::getInt32Ty(*Context), 0); unsigned ZeroReg = TargetMaterializeConstant(Zero); BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(MovCCOpc), DestReg) .addReg(ZeroReg).addImm(1) .addImm(ARMPred).addReg(CondReg); UpdateValueMap(I, DestReg); return true; } bool ARMFastISel::SelectFPExt(const Instruction *I) { // Make sure we have VFP and that we're extending float to double. if (!Subtarget->hasVFP2()) return false; Value *V = I->getOperand(0); if (!I->getType()->isDoubleTy() || !V->getType()->isFloatTy()) return false; unsigned Op = getRegForValue(V); if (Op == 0) return false; unsigned Result = createResultReg(ARM::DPRRegisterClass); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(ARM::VCVTDS), Result) .addReg(Op)); UpdateValueMap(I, Result); return true; } bool ARMFastISel::SelectFPTrunc(const Instruction *I) { // Make sure we have VFP and that we're truncating double to float. if (!Subtarget->hasVFP2()) return false; Value *V = I->getOperand(0); if (!(I->getType()->isFloatTy() && V->getType()->isDoubleTy())) return false; unsigned Op = getRegForValue(V); if (Op == 0) return false; unsigned Result = createResultReg(ARM::SPRRegisterClass); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(ARM::VCVTSD), Result) .addReg(Op)); UpdateValueMap(I, Result); return true; } bool ARMFastISel::SelectSIToFP(const Instruction *I) { // Make sure we have VFP. if (!Subtarget->hasVFP2()) return false; MVT DstVT; Type *Ty = I->getType(); if (!isTypeLegal(Ty, DstVT)) return false; // FIXME: Handle sign-extension where necessary. if (!I->getOperand(0)->getType()->isIntegerTy(32)) return false; unsigned Op = getRegForValue(I->getOperand(0)); if (Op == 0) return false; // The conversion routine works on fp-reg to fp-reg and the operand above // was an integer, move it to the fp registers if possible. unsigned FP = ARMMoveToFPReg(MVT::f32, Op); if (FP == 0) return false; unsigned Opc; if (Ty->isFloatTy()) Opc = ARM::VSITOS; else if (Ty->isDoubleTy()) Opc = ARM::VSITOD; else return false; unsigned ResultReg = createResultReg(TLI.getRegClassFor(DstVT)); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(Opc), ResultReg) .addReg(FP)); UpdateValueMap(I, ResultReg); return true; } bool ARMFastISel::SelectFPToSI(const Instruction *I) { // Make sure we have VFP. if (!Subtarget->hasVFP2()) return false; MVT DstVT; Type *RetTy = I->getType(); if (!isTypeLegal(RetTy, DstVT)) return false; unsigned Op = getRegForValue(I->getOperand(0)); if (Op == 0) return false; unsigned Opc; Type *OpTy = I->getOperand(0)->getType(); if (OpTy->isFloatTy()) Opc = ARM::VTOSIZS; else if (OpTy->isDoubleTy()) Opc = ARM::VTOSIZD; else return false; // f64->s32 or f32->s32 both need an intermediate f32 reg. unsigned ResultReg = createResultReg(TLI.getRegClassFor(MVT::f32)); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(Opc), ResultReg) .addReg(Op)); // This result needs to be in an integer register, but the conversion only // takes place in fp-regs. unsigned IntReg = ARMMoveToIntReg(DstVT, ResultReg); if (IntReg == 0) return false; UpdateValueMap(I, IntReg); return true; } bool ARMFastISel::SelectSelect(const Instruction *I) { MVT VT; if (!isTypeLegal(I->getType(), VT)) return false; // Things need to be register sized for register moves. if (VT != MVT::i32) return false; const TargetRegisterClass *RC = TLI.getRegClassFor(VT); unsigned CondReg = getRegForValue(I->getOperand(0)); if (CondReg == 0) return false; unsigned Op1Reg = getRegForValue(I->getOperand(1)); if (Op1Reg == 0) return false; unsigned Op2Reg = getRegForValue(I->getOperand(2)); if (Op2Reg == 0) return false; unsigned CmpOpc = isThumb ? ARM::t2TSTri : ARM::TSTri; AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(CmpOpc)) .addReg(CondReg).addImm(1)); unsigned ResultReg = createResultReg(RC); unsigned MovCCOpc = isThumb ? ARM::t2MOVCCr : ARM::MOVCCr; BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(MovCCOpc), ResultReg) .addReg(Op1Reg).addReg(Op2Reg) .addImm(ARMCC::EQ).addReg(ARM::CPSR); UpdateValueMap(I, ResultReg); return true; } bool ARMFastISel::SelectSDiv(const Instruction *I) { MVT VT; Type *Ty = I->getType(); if (!isTypeLegal(Ty, VT)) return false; // If we have integer div support we should have selected this automagically. // In case we have a real miss go ahead and return false and we'll pick // it up later. if (Subtarget->hasDivide()) return false; // Otherwise emit a libcall. RTLIB::Libcall LC = RTLIB::UNKNOWN_LIBCALL; if (VT == MVT::i8) LC = RTLIB::SDIV_I8; else if (VT == MVT::i16) LC = RTLIB::SDIV_I16; else if (VT == MVT::i32) LC = RTLIB::SDIV_I32; else if (VT == MVT::i64) LC = RTLIB::SDIV_I64; else if (VT == MVT::i128) LC = RTLIB::SDIV_I128; assert(LC != RTLIB::UNKNOWN_LIBCALL && "Unsupported SDIV!"); return ARMEmitLibcall(I, LC); } bool ARMFastISel::SelectSRem(const Instruction *I) { MVT VT; Type *Ty = I->getType(); if (!isTypeLegal(Ty, VT)) return false; RTLIB::Libcall LC = RTLIB::UNKNOWN_LIBCALL; if (VT == MVT::i8) LC = RTLIB::SREM_I8; else if (VT == MVT::i16) LC = RTLIB::SREM_I16; else if (VT == MVT::i32) LC = RTLIB::SREM_I32; else if (VT == MVT::i64) LC = RTLIB::SREM_I64; else if (VT == MVT::i128) LC = RTLIB::SREM_I128; assert(LC != RTLIB::UNKNOWN_LIBCALL && "Unsupported SREM!"); return ARMEmitLibcall(I, LC); } bool ARMFastISel::SelectBinaryOp(const Instruction *I, unsigned ISDOpcode) { EVT VT = TLI.getValueType(I->getType(), true); // We can get here in the case when we want to use NEON for our fp // operations, but can't figure out how to. Just use the vfp instructions // if we have them. // FIXME: It'd be nice to use NEON instructions. Type *Ty = I->getType(); bool isFloat = (Ty->isDoubleTy() || Ty->isFloatTy()); if (isFloat && !Subtarget->hasVFP2()) return false; unsigned Op1 = getRegForValue(I->getOperand(0)); if (Op1 == 0) return false; unsigned Op2 = getRegForValue(I->getOperand(1)); if (Op2 == 0) return false; unsigned Opc; bool is64bit = VT == MVT::f64 || VT == MVT::i64; switch (ISDOpcode) { default: return false; case ISD::FADD: Opc = is64bit ? ARM::VADDD : ARM::VADDS; break; case ISD::FSUB: Opc = is64bit ? ARM::VSUBD : ARM::VSUBS; break; case ISD::FMUL: Opc = is64bit ? ARM::VMULD : ARM::VMULS; break; } unsigned ResultReg = createResultReg(TLI.getRegClassFor(VT)); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(Opc), ResultReg) .addReg(Op1).addReg(Op2)); UpdateValueMap(I, ResultReg); return true; } // Call Handling Code bool ARMFastISel::FastEmitExtend(ISD::NodeType Opc, EVT DstVT, unsigned Src, EVT SrcVT, unsigned &ResultReg) { unsigned RR = FastEmit_r(SrcVT.getSimpleVT(), DstVT.getSimpleVT(), Opc, Src, /*TODO: Kill=*/false); if (RR != 0) { ResultReg = RR; return true; } else return false; } // This is largely taken directly from CCAssignFnForNode - we don't support // varargs in FastISel so that part has been removed. // TODO: We may not support all of this. CCAssignFn *ARMFastISel::CCAssignFnForCall(CallingConv::ID CC, bool Return) { switch (CC) { default: llvm_unreachable("Unsupported calling convention"); case CallingConv::Fast: // Ignore fastcc. Silence compiler warnings. (void)RetFastCC_ARM_APCS; (void)FastCC_ARM_APCS; // Fallthrough case CallingConv::C: // Use target triple & subtarget features to do actual dispatch. if (Subtarget->isAAPCS_ABI()) { if (Subtarget->hasVFP2() && FloatABIType == FloatABI::Hard) return (Return ? RetCC_ARM_AAPCS_VFP: CC_ARM_AAPCS_VFP); else return (Return ? RetCC_ARM_AAPCS: CC_ARM_AAPCS); } else return (Return ? RetCC_ARM_APCS: CC_ARM_APCS); case CallingConv::ARM_AAPCS_VFP: return (Return ? RetCC_ARM_AAPCS_VFP: CC_ARM_AAPCS_VFP); case CallingConv::ARM_AAPCS: return (Return ? RetCC_ARM_AAPCS: CC_ARM_AAPCS); case CallingConv::ARM_APCS: return (Return ? RetCC_ARM_APCS: CC_ARM_APCS); + case CallingConv::GHC: + if (Return) + llvm_unreachable("Can't return in GHC call convention"); + else + return CC_ARM_APCS_GHC; } } bool ARMFastISel::ProcessCallArgs(SmallVectorImpl &Args, SmallVectorImpl &ArgRegs, SmallVectorImpl &ArgVTs, SmallVectorImpl &ArgFlags, SmallVectorImpl &RegArgs, CallingConv::ID CC, unsigned &NumBytes) { SmallVector ArgLocs; CCState CCInfo(CC, false, *FuncInfo.MF, TM, ArgLocs, *Context); CCInfo.AnalyzeCallOperands(ArgVTs, ArgFlags, CCAssignFnForCall(CC, false)); // Get a count of how many bytes are to be pushed on the stack. NumBytes = CCInfo.getNextStackOffset(); // Issue CALLSEQ_START unsigned AdjStackDown = TII.getCallFrameSetupOpcode(); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(AdjStackDown)) .addImm(NumBytes)); // Process the args. for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { CCValAssign &VA = ArgLocs[i]; unsigned Arg = ArgRegs[VA.getValNo()]; MVT ArgVT = ArgVTs[VA.getValNo()]; // We don't handle NEON/vector parameters yet. if (ArgVT.isVector() || ArgVT.getSizeInBits() > 64) return false; // Handle arg promotion, etc. switch (VA.getLocInfo()) { case CCValAssign::Full: break; case CCValAssign::SExt: { bool Emitted = FastEmitExtend(ISD::SIGN_EXTEND, VA.getLocVT(), Arg, ArgVT, Arg); assert(Emitted && "Failed to emit a sext!"); (void)Emitted; Emitted = true; ArgVT = VA.getLocVT(); break; } case CCValAssign::ZExt: { bool Emitted = FastEmitExtend(ISD::ZERO_EXTEND, VA.getLocVT(), Arg, ArgVT, Arg); assert(Emitted && "Failed to emit a zext!"); (void)Emitted; Emitted = true; ArgVT = VA.getLocVT(); break; } case CCValAssign::AExt: { bool Emitted = FastEmitExtend(ISD::ANY_EXTEND, VA.getLocVT(), Arg, ArgVT, Arg); if (!Emitted) Emitted = FastEmitExtend(ISD::ZERO_EXTEND, VA.getLocVT(), Arg, ArgVT, Arg); if (!Emitted) Emitted = FastEmitExtend(ISD::SIGN_EXTEND, VA.getLocVT(), Arg, ArgVT, Arg); assert(Emitted && "Failed to emit a aext!"); (void)Emitted; ArgVT = VA.getLocVT(); break; } case CCValAssign::BCvt: { unsigned BC = FastEmit_r(ArgVT, VA.getLocVT(), ISD::BITCAST, Arg, /*TODO: Kill=*/false); assert(BC != 0 && "Failed to emit a bitcast!"); Arg = BC; ArgVT = VA.getLocVT(); break; } default: llvm_unreachable("Unknown arg promotion!"); } // Now copy/store arg to correct locations. if (VA.isRegLoc() && !VA.needsCustom()) { BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(TargetOpcode::COPY), VA.getLocReg()) .addReg(Arg); RegArgs.push_back(VA.getLocReg()); } else if (VA.needsCustom()) { // TODO: We need custom lowering for vector (v2f64) args. if (VA.getLocVT() != MVT::f64) return false; CCValAssign &NextVA = ArgLocs[++i]; // TODO: Only handle register args for now. if(!(VA.isRegLoc() && NextVA.isRegLoc())) return false; AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(ARM::VMOVRRD), VA.getLocReg()) .addReg(NextVA.getLocReg(), RegState::Define) .addReg(Arg)); RegArgs.push_back(VA.getLocReg()); RegArgs.push_back(NextVA.getLocReg()); } else { assert(VA.isMemLoc()); // Need to store on the stack. Address Addr; Addr.BaseType = Address::RegBase; Addr.Base.Reg = ARM::SP; Addr.Offset = VA.getLocMemOffset(); if (!ARMEmitStore(ArgVT, Arg, Addr)) return false; } } return true; } bool ARMFastISel::FinishCall(MVT RetVT, SmallVectorImpl &UsedRegs, const Instruction *I, CallingConv::ID CC, unsigned &NumBytes) { // Issue CALLSEQ_END unsigned AdjStackUp = TII.getCallFrameDestroyOpcode(); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(AdjStackUp)) .addImm(NumBytes).addImm(0)); // Now the return value. if (RetVT != MVT::isVoid) { SmallVector RVLocs; CCState CCInfo(CC, false, *FuncInfo.MF, TM, RVLocs, *Context); CCInfo.AnalyzeCallResult(RetVT, CCAssignFnForCall(CC, true)); // Copy all of the result registers out of their specified physreg. if (RVLocs.size() == 2 && RetVT == MVT::f64) { // For this move we copy into two registers and then move into the // double fp reg we want. EVT DestVT = RVLocs[0].getValVT(); TargetRegisterClass* DstRC = TLI.getRegClassFor(DestVT); unsigned ResultReg = createResultReg(DstRC); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(ARM::VMOVDRR), ResultReg) .addReg(RVLocs[0].getLocReg()) .addReg(RVLocs[1].getLocReg())); UsedRegs.push_back(RVLocs[0].getLocReg()); UsedRegs.push_back(RVLocs[1].getLocReg()); // Finally update the result. UpdateValueMap(I, ResultReg); } else { assert(RVLocs.size() == 1 &&"Can't handle non-double multi-reg retvals!"); EVT CopyVT = RVLocs[0].getValVT(); TargetRegisterClass* DstRC = TLI.getRegClassFor(CopyVT); unsigned ResultReg = createResultReg(DstRC); BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(TargetOpcode::COPY), ResultReg).addReg(RVLocs[0].getLocReg()); UsedRegs.push_back(RVLocs[0].getLocReg()); // Finally update the result. UpdateValueMap(I, ResultReg); } } return true; } bool ARMFastISel::SelectRet(const Instruction *I) { const ReturnInst *Ret = cast(I); const Function &F = *I->getParent()->getParent(); if (!FuncInfo.CanLowerReturn) return false; if (F.isVarArg()) return false; CallingConv::ID CC = F.getCallingConv(); if (Ret->getNumOperands() > 0) { SmallVector Outs; GetReturnInfo(F.getReturnType(), F.getAttributes().getRetAttributes(), Outs, TLI); // Analyze operands of the call, assigning locations to each operand. SmallVector ValLocs; CCState CCInfo(CC, F.isVarArg(), *FuncInfo.MF, TM, ValLocs,I->getContext()); CCInfo.AnalyzeReturn(Outs, CCAssignFnForCall(CC, true /* is Ret */)); const Value *RV = Ret->getOperand(0); unsigned Reg = getRegForValue(RV); if (Reg == 0) return false; // Only handle a single return value for now. if (ValLocs.size() != 1) return false; CCValAssign &VA = ValLocs[0]; // Don't bother handling odd stuff for now. if (VA.getLocInfo() != CCValAssign::Full) return false; // Only handle register returns for now. if (!VA.isRegLoc()) return false; // TODO: For now, don't try to handle cases where getLocInfo() // says Full but the types don't match. if (TLI.getValueType(RV->getType()) != VA.getValVT()) return false; // Make the copy. unsigned SrcReg = Reg + VA.getValNo(); unsigned DstReg = VA.getLocReg(); const TargetRegisterClass* SrcRC = MRI.getRegClass(SrcReg); // Avoid a cross-class copy. This is very unlikely. if (!SrcRC->contains(DstReg)) return false; BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(TargetOpcode::COPY), DstReg).addReg(SrcReg); // Mark the register as live out of the function. MRI.addLiveOut(VA.getLocReg()); } unsigned RetOpc = isThumb ? ARM::tBX_RET : ARM::BX_RET; AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(RetOpc))); return true; } unsigned ARMFastISel::ARMSelectCallOp(const GlobalValue *GV) { // Darwin needs the r9 versions of the opcodes. bool isDarwin = Subtarget->isTargetDarwin(); if (isThumb) { return isDarwin ? ARM::tBLr9 : ARM::tBL; } else { return isDarwin ? ARM::BLr9 : ARM::BL; } } // A quick function that will emit a call for a named libcall in F with the // vector of passed arguments for the Instruction in I. We can assume that we // can emit a call for any libcall we can produce. This is an abridged version // of the full call infrastructure since we won't need to worry about things // like computed function pointers or strange arguments at call sites. // TODO: Try to unify this and the normal call bits for ARM, then try to unify // with X86. bool ARMFastISel::ARMEmitLibcall(const Instruction *I, RTLIB::Libcall Call) { CallingConv::ID CC = TLI.getLibcallCallingConv(Call); // Handle *simple* calls for now. Type *RetTy = I->getType(); MVT RetVT; if (RetTy->isVoidTy()) RetVT = MVT::isVoid; else if (!isTypeLegal(RetTy, RetVT)) return false; // TODO: For now if we have long calls specified we don't handle the call. if (EnableARMLongCalls) return false; // Set up the argument vectors. SmallVector Args; SmallVector ArgRegs; SmallVector ArgVTs; SmallVector ArgFlags; Args.reserve(I->getNumOperands()); ArgRegs.reserve(I->getNumOperands()); ArgVTs.reserve(I->getNumOperands()); ArgFlags.reserve(I->getNumOperands()); for (unsigned i = 0; i < I->getNumOperands(); ++i) { Value *Op = I->getOperand(i); unsigned Arg = getRegForValue(Op); if (Arg == 0) return false; Type *ArgTy = Op->getType(); MVT ArgVT; if (!isTypeLegal(ArgTy, ArgVT)) return false; ISD::ArgFlagsTy Flags; unsigned OriginalAlignment = TD.getABITypeAlignment(ArgTy); Flags.setOrigAlign(OriginalAlignment); Args.push_back(Op); ArgRegs.push_back(Arg); ArgVTs.push_back(ArgVT); ArgFlags.push_back(Flags); } // Handle the arguments now that we've gotten them. SmallVector RegArgs; unsigned NumBytes; if (!ProcessCallArgs(Args, ArgRegs, ArgVTs, ArgFlags, RegArgs, CC, NumBytes)) return false; // Issue the call, BLr9 for darwin, BL otherwise. // TODO: Turn this into the table of arm call ops. MachineInstrBuilder MIB; unsigned CallOpc = ARMSelectCallOp(NULL); if(isThumb) // Explicitly adding the predicate here. MIB = AddDefaultPred(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(CallOpc))) .addExternalSymbol(TLI.getLibcallName(Call)); else // Explicitly adding the predicate here. MIB = AddDefaultPred(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(CallOpc)) .addExternalSymbol(TLI.getLibcallName(Call))); // Add implicit physical register uses to the call. for (unsigned i = 0, e = RegArgs.size(); i != e; ++i) MIB.addReg(RegArgs[i]); // Finish off the call including any return values. SmallVector UsedRegs; if (!FinishCall(RetVT, UsedRegs, I, CC, NumBytes)) return false; // Set all unused physreg defs as dead. static_cast(MIB)->setPhysRegsDeadExcept(UsedRegs, TRI); return true; } bool ARMFastISel::SelectCall(const Instruction *I) { const CallInst *CI = cast(I); const Value *Callee = CI->getCalledValue(); // Can't handle inline asm or worry about intrinsics yet. if (isa(Callee) || isa(CI)) return false; // Only handle global variable Callees. const GlobalValue *GV = dyn_cast(Callee); if (!GV) return false; // Check the calling convention. ImmutableCallSite CS(CI); CallingConv::ID CC = CS.getCallingConv(); // TODO: Avoid some calling conventions? // Let SDISel handle vararg functions. PointerType *PT = cast(CS.getCalledValue()->getType()); FunctionType *FTy = cast(PT->getElementType()); if (FTy->isVarArg()) return false; // Handle *simple* calls for now. Type *RetTy = I->getType(); MVT RetVT; if (RetTy->isVoidTy()) RetVT = MVT::isVoid; else if (!isTypeLegal(RetTy, RetVT)) return false; // TODO: For now if we have long calls specified we don't handle the call. if (EnableARMLongCalls) return false; // Set up the argument vectors. SmallVector Args; SmallVector ArgRegs; SmallVector ArgVTs; SmallVector ArgFlags; Args.reserve(CS.arg_size()); ArgRegs.reserve(CS.arg_size()); ArgVTs.reserve(CS.arg_size()); ArgFlags.reserve(CS.arg_size()); for (ImmutableCallSite::arg_iterator i = CS.arg_begin(), e = CS.arg_end(); i != e; ++i) { unsigned Arg = getRegForValue(*i); if (Arg == 0) return false; ISD::ArgFlagsTy Flags; unsigned AttrInd = i - CS.arg_begin() + 1; if (CS.paramHasAttr(AttrInd, Attribute::SExt)) Flags.setSExt(); if (CS.paramHasAttr(AttrInd, Attribute::ZExt)) Flags.setZExt(); // FIXME: Only handle *easy* calls for now. if (CS.paramHasAttr(AttrInd, Attribute::InReg) || CS.paramHasAttr(AttrInd, Attribute::StructRet) || CS.paramHasAttr(AttrInd, Attribute::Nest) || CS.paramHasAttr(AttrInd, Attribute::ByVal)) return false; Type *ArgTy = (*i)->getType(); MVT ArgVT; if (!isTypeLegal(ArgTy, ArgVT)) return false; unsigned OriginalAlignment = TD.getABITypeAlignment(ArgTy); Flags.setOrigAlign(OriginalAlignment); Args.push_back(*i); ArgRegs.push_back(Arg); ArgVTs.push_back(ArgVT); ArgFlags.push_back(Flags); } // Handle the arguments now that we've gotten them. SmallVector RegArgs; unsigned NumBytes; if (!ProcessCallArgs(Args, ArgRegs, ArgVTs, ArgFlags, RegArgs, CC, NumBytes)) return false; // Issue the call, BLr9 for darwin, BL otherwise. // TODO: Turn this into the table of arm call ops. MachineInstrBuilder MIB; unsigned CallOpc = ARMSelectCallOp(GV); // Explicitly adding the predicate here. if(isThumb) // Explicitly adding the predicate here. MIB = AddDefaultPred(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(CallOpc))) .addGlobalAddress(GV, 0, 0); else // Explicitly adding the predicate here. MIB = AddDefaultPred(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(CallOpc)) .addGlobalAddress(GV, 0, 0)); // Add implicit physical register uses to the call. for (unsigned i = 0, e = RegArgs.size(); i != e; ++i) MIB.addReg(RegArgs[i]); // Finish off the call including any return values. SmallVector UsedRegs; if (!FinishCall(RetVT, UsedRegs, I, CC, NumBytes)) return false; // Set all unused physreg defs as dead. static_cast(MIB)->setPhysRegsDeadExcept(UsedRegs, TRI); return true; } bool ARMFastISel::SelectIntCast(const Instruction *I) { // On ARM, in general, integer casts don't involve legal types; this code // handles promotable integers. The high bits for a type smaller than // the register size are assumed to be undefined. Type *DestTy = I->getType(); Value *Op = I->getOperand(0); Type *SrcTy = Op->getType(); EVT SrcVT, DestVT; SrcVT = TLI.getValueType(SrcTy, true); DestVT = TLI.getValueType(DestTy, true); if (isa(I)) { if (SrcVT != MVT::i32 && SrcVT != MVT::i16 && SrcVT != MVT::i8) return false; if (DestVT != MVT::i16 && DestVT != MVT::i8 && DestVT != MVT::i1) return false; unsigned SrcReg = getRegForValue(Op); if (!SrcReg) return false; // Because the high bits are undefined, a truncate doesn't generate // any code. UpdateValueMap(I, SrcReg); return true; } if (DestVT != MVT::i32 && DestVT != MVT::i16 && DestVT != MVT::i8) return false; unsigned Opc; bool isZext = isa(I); bool isBoolZext = false; if (!SrcVT.isSimple()) return false; switch (SrcVT.getSimpleVT().SimpleTy) { default: return false; case MVT::i16: if (!Subtarget->hasV6Ops()) return false; if (isZext) Opc = isThumb ? ARM::t2UXTH : ARM::UXTH; else Opc = isThumb ? ARM::t2SXTH : ARM::SXTH; break; case MVT::i8: if (!Subtarget->hasV6Ops()) return false; if (isZext) Opc = isThumb ? ARM::t2UXTB : ARM::UXTB; else Opc = isThumb ? ARM::t2SXTB : ARM::SXTB; break; case MVT::i1: if (isZext) { Opc = isThumb ? ARM::t2ANDri : ARM::ANDri; isBoolZext = true; break; } return false; } // FIXME: We could save an instruction in many cases by special-casing // load instructions. unsigned SrcReg = getRegForValue(Op); if (!SrcReg) return false; unsigned DestReg = createResultReg(TLI.getRegClassFor(MVT::i32)); MachineInstrBuilder MIB; MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(Opc), DestReg) .addReg(SrcReg); if (isBoolZext) MIB.addImm(1); else MIB.addImm(0); AddOptionalDefs(MIB); UpdateValueMap(I, DestReg); return true; } // TODO: SoftFP support. bool ARMFastISel::TargetSelectInstruction(const Instruction *I) { switch (I->getOpcode()) { case Instruction::Load: return SelectLoad(I); case Instruction::Store: return SelectStore(I); case Instruction::Br: return SelectBranch(I); case Instruction::ICmp: case Instruction::FCmp: return SelectCmp(I); case Instruction::FPExt: return SelectFPExt(I); case Instruction::FPTrunc: return SelectFPTrunc(I); case Instruction::SIToFP: return SelectSIToFP(I); case Instruction::FPToSI: return SelectFPToSI(I); case Instruction::FAdd: return SelectBinaryOp(I, ISD::FADD); case Instruction::FSub: return SelectBinaryOp(I, ISD::FSUB); case Instruction::FMul: return SelectBinaryOp(I, ISD::FMUL); case Instruction::SDiv: return SelectSDiv(I); case Instruction::SRem: return SelectSRem(I); case Instruction::Call: return SelectCall(I); case Instruction::Select: return SelectSelect(I); case Instruction::Ret: return SelectRet(I); case Instruction::Trunc: case Instruction::ZExt: case Instruction::SExt: return SelectIntCast(I); default: break; } return false; } namespace llvm { llvm::FastISel *ARM::createFastISel(FunctionLoweringInfo &funcInfo) { // Completely untested on non-darwin. const TargetMachine &TM = funcInfo.MF->getTarget(); // Darwin and thumb1 only for now. const ARMSubtarget *Subtarget = &TM.getSubtarget(); if (Subtarget->isTargetDarwin() && !Subtarget->isThumb1Only() && !DisableARMFastISel) return new ARMFastISel(funcInfo); return 0; } } Index: head/contrib/llvm/lib/Target/ARM/ARMFrameLowering.cpp =================================================================== --- head/contrib/llvm/lib/Target/ARM/ARMFrameLowering.cpp (revision 228378) +++ head/contrib/llvm/lib/Target/ARM/ARMFrameLowering.cpp (revision 228379) @@ -1,1087 +1,1097 @@ //=======- ARMFrameLowering.cpp - ARM Frame Information --------*- C++ -*-====// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file contains the ARM implementation of TargetFrameLowering class. // //===----------------------------------------------------------------------===// #include "ARMFrameLowering.h" #include "ARMBaseInstrInfo.h" #include "ARMBaseRegisterInfo.h" #include "ARMMachineFunctionInfo.h" +#include "llvm/CallingConv.h" +#include "llvm/Function.h" #include "MCTargetDesc/ARMAddressingModes.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/RegisterScavenging.h" #include "llvm/Target/TargetOptions.h" using namespace llvm; /// hasFP - Return true if the specified function should have a dedicated frame /// pointer register. This is true if the function has variable sized allocas /// or if frame pointer elimination is disabled. bool ARMFrameLowering::hasFP(const MachineFunction &MF) const { const TargetRegisterInfo *RegInfo = MF.getTarget().getRegisterInfo(); // Mac OS X requires FP not to be clobbered for backtracing purpose. if (STI.isTargetDarwin()) return true; const MachineFrameInfo *MFI = MF.getFrameInfo(); // Always eliminate non-leaf frame pointers. return ((DisableFramePointerElim(MF) && MFI->hasCalls()) || RegInfo->needsStackRealignment(MF) || MFI->hasVarSizedObjects() || MFI->isFrameAddressTaken()); } /// hasReservedCallFrame - Under normal circumstances, when a frame pointer is /// not required, we reserve argument space for call sites in the function /// immediately on entry to the current function. This eliminates the need for /// add/sub sp brackets around call sites. Returns true if the call frame is /// included as part of the stack frame. bool ARMFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const { const MachineFrameInfo *FFI = MF.getFrameInfo(); unsigned CFSize = FFI->getMaxCallFrameSize(); // It's not always a good idea to include the call frame as part of the // stack frame. ARM (especially Thumb) has small immediate offset to // address the stack frame. So a large call frame can cause poor codegen // and may even makes it impossible to scavenge a register. if (CFSize >= ((1 << 12) - 1) / 2) // Half of imm12 return false; return !MF.getFrameInfo()->hasVarSizedObjects(); } /// canSimplifyCallFramePseudos - If there is a reserved call frame, the /// call frame pseudos can be simplified. Unlike most targets, having a FP /// is not sufficient here since we still may reference some objects via SP /// even when FP is available in Thumb2 mode. bool ARMFrameLowering::canSimplifyCallFramePseudos(const MachineFunction &MF) const { return hasReservedCallFrame(MF) || MF.getFrameInfo()->hasVarSizedObjects(); } static bool isCalleeSavedRegister(unsigned Reg, const unsigned *CSRegs) { for (unsigned i = 0; CSRegs[i]; ++i) if (Reg == CSRegs[i]) return true; return false; } static bool isCSRestore(MachineInstr *MI, const ARMBaseInstrInfo &TII, const unsigned *CSRegs) { // Integer spill area is handled with "pop". if (MI->getOpcode() == ARM::LDMIA_RET || MI->getOpcode() == ARM::t2LDMIA_RET || MI->getOpcode() == ARM::LDMIA_UPD || MI->getOpcode() == ARM::t2LDMIA_UPD || MI->getOpcode() == ARM::VLDMDIA_UPD) { // The first two operands are predicates. The last two are // imp-def and imp-use of SP. Check everything in between. for (int i = 5, e = MI->getNumOperands(); i != e; ++i) if (!isCalleeSavedRegister(MI->getOperand(i).getReg(), CSRegs)) return false; return true; } if ((MI->getOpcode() == ARM::LDR_POST_IMM || MI->getOpcode() == ARM::LDR_POST_REG || MI->getOpcode() == ARM::t2LDR_POST) && isCalleeSavedRegister(MI->getOperand(0).getReg(), CSRegs) && MI->getOperand(1).getReg() == ARM::SP) return true; return false; } static void emitSPUpdate(bool isARM, MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI, DebugLoc dl, const ARMBaseInstrInfo &TII, int NumBytes, unsigned MIFlags = MachineInstr::NoFlags) { if (isARM) emitARMRegPlusImmediate(MBB, MBBI, dl, ARM::SP, ARM::SP, NumBytes, ARMCC::AL, 0, TII, MIFlags); else emitT2RegPlusImmediate(MBB, MBBI, dl, ARM::SP, ARM::SP, NumBytes, ARMCC::AL, 0, TII, MIFlags); } void ARMFrameLowering::emitPrologue(MachineFunction &MF) const { MachineBasicBlock &MBB = MF.front(); MachineBasicBlock::iterator MBBI = MBB.begin(); MachineFrameInfo *MFI = MF.getFrameInfo(); ARMFunctionInfo *AFI = MF.getInfo(); const ARMBaseRegisterInfo *RegInfo = static_cast(MF.getTarget().getRegisterInfo()); const ARMBaseInstrInfo &TII = *static_cast(MF.getTarget().getInstrInfo()); assert(!AFI->isThumb1OnlyFunction() && "This emitPrologue does not support Thumb1!"); bool isARM = !AFI->isThumbFunction(); unsigned VARegSaveSize = AFI->getVarArgsRegSaveSize(); unsigned NumBytes = MFI->getStackSize(); const std::vector &CSI = MFI->getCalleeSavedInfo(); DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); unsigned FramePtr = RegInfo->getFrameRegister(MF); // Determine the sizes of each callee-save spill areas and record which frame // belongs to which callee-save spill areas. unsigned GPRCS1Size = 0, GPRCS2Size = 0, DPRCSSize = 0; int FramePtrSpillFI = 0; + // All calls are tail calls in GHC calling conv, and functions have no prologue/epilogue. + if (MF.getFunction()->getCallingConv() == CallingConv::GHC) + return; + // Allocate the vararg register save area. This is not counted in NumBytes. if (VARegSaveSize) emitSPUpdate(isARM, MBB, MBBI, dl, TII, -VARegSaveSize, MachineInstr::FrameSetup); if (!AFI->hasStackFrame()) { if (NumBytes != 0) emitSPUpdate(isARM, MBB, MBBI, dl, TII, -NumBytes, MachineInstr::FrameSetup); return; } for (unsigned i = 0, e = CSI.size(); i != e; ++i) { unsigned Reg = CSI[i].getReg(); int FI = CSI[i].getFrameIdx(); switch (Reg) { case ARM::R4: case ARM::R5: case ARM::R6: case ARM::R7: case ARM::LR: if (Reg == FramePtr) FramePtrSpillFI = FI; AFI->addGPRCalleeSavedArea1Frame(FI); GPRCS1Size += 4; break; case ARM::R8: case ARM::R9: case ARM::R10: case ARM::R11: if (Reg == FramePtr) FramePtrSpillFI = FI; if (STI.isTargetDarwin()) { AFI->addGPRCalleeSavedArea2Frame(FI); GPRCS2Size += 4; } else { AFI->addGPRCalleeSavedArea1Frame(FI); GPRCS1Size += 4; } break; default: AFI->addDPRCalleeSavedAreaFrame(FI); DPRCSSize += 8; } } // Move past area 1. if (GPRCS1Size > 0) MBBI++; // Set FP to point to the stack slot that contains the previous FP. // For Darwin, FP is R7, which has now been stored in spill area 1. // Otherwise, if this is not Darwin, all the callee-saved registers go // into spill area 1, including the FP in R11. In either case, it is // now safe to emit this assignment. bool HasFP = hasFP(MF); if (HasFP) { unsigned ADDriOpc = !AFI->isThumbFunction() ? ARM::ADDri : ARM::t2ADDri; MachineInstrBuilder MIB = BuildMI(MBB, MBBI, dl, TII.get(ADDriOpc), FramePtr) .addFrameIndex(FramePtrSpillFI).addImm(0) .setMIFlag(MachineInstr::FrameSetup); AddDefaultCC(AddDefaultPred(MIB)); } // Move past area 2. if (GPRCS2Size > 0) MBBI++; // Determine starting offsets of spill areas. unsigned DPRCSOffset = NumBytes - (GPRCS1Size + GPRCS2Size + DPRCSSize); unsigned GPRCS2Offset = DPRCSOffset + DPRCSSize; unsigned GPRCS1Offset = GPRCS2Offset + GPRCS2Size; if (HasFP) AFI->setFramePtrSpillOffset(MFI->getObjectOffset(FramePtrSpillFI) + NumBytes); AFI->setGPRCalleeSavedArea1Offset(GPRCS1Offset); AFI->setGPRCalleeSavedArea2Offset(GPRCS2Offset); AFI->setDPRCalleeSavedAreaOffset(DPRCSOffset); // Move past area 3. if (DPRCSSize > 0) { MBBI++; // Since vpush register list cannot have gaps, there may be multiple vpush // instructions in the prologue. while (MBBI->getOpcode() == ARM::VSTMDDB_UPD) MBBI++; } NumBytes = DPRCSOffset; if (NumBytes) { // Adjust SP after all the callee-save spills. emitSPUpdate(isARM, MBB, MBBI, dl, TII, -NumBytes, MachineInstr::FrameSetup); if (HasFP && isARM) // Restore from fp only in ARM mode: e.g. sub sp, r7, #24 // Note it's not safe to do this in Thumb2 mode because it would have // taken two instructions: // mov sp, r7 // sub sp, #24 // If an interrupt is taken between the two instructions, then sp is in // an inconsistent state (pointing to the middle of callee-saved area). // The interrupt handler can end up clobbering the registers. AFI->setShouldRestoreSPFromFP(true); } if (STI.isTargetELF() && hasFP(MF)) MFI->setOffsetAdjustment(MFI->getOffsetAdjustment() - AFI->getFramePtrSpillOffset()); AFI->setGPRCalleeSavedArea1Size(GPRCS1Size); AFI->setGPRCalleeSavedArea2Size(GPRCS2Size); AFI->setDPRCalleeSavedAreaSize(DPRCSSize); // If we need dynamic stack realignment, do it here. Be paranoid and make // sure if we also have VLAs, we have a base pointer for frame access. if (RegInfo->needsStackRealignment(MF)) { unsigned MaxAlign = MFI->getMaxAlignment(); assert (!AFI->isThumb1OnlyFunction()); if (!AFI->isThumbFunction()) { // Emit bic sp, sp, MaxAlign AddDefaultCC(AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::BICri), ARM::SP) .addReg(ARM::SP, RegState::Kill) .addImm(MaxAlign-1))); } else { // We cannot use sp as source/dest register here, thus we're emitting the // following sequence: // mov r4, sp // bic r4, r4, MaxAlign // mov sp, r4 // FIXME: It will be better just to find spare register here. AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVr), ARM::R4) .addReg(ARM::SP, RegState::Kill)); AddDefaultCC(AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::t2BICri), ARM::R4) .addReg(ARM::R4, RegState::Kill) .addImm(MaxAlign-1))); AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVr), ARM::SP) .addReg(ARM::R4, RegState::Kill)); } AFI->setShouldRestoreSPFromFP(true); } // If we need a base pointer, set it up here. It's whatever the value // of the stack pointer is at this point. Any variable size objects // will be allocated after this, so we can still use the base pointer // to reference locals. // FIXME: Clarify FrameSetup flags here. if (RegInfo->hasBasePointer(MF)) { if (isARM) BuildMI(MBB, MBBI, dl, TII.get(ARM::MOVr), RegInfo->getBaseRegister()) .addReg(ARM::SP) .addImm((unsigned)ARMCC::AL).addReg(0).addReg(0); else AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVr), RegInfo->getBaseRegister()) .addReg(ARM::SP)); } // If the frame has variable sized objects then the epilogue must restore // the sp from fp. We can assume there's an FP here since hasFP already // checks for hasVarSizedObjects. if (MFI->hasVarSizedObjects()) AFI->setShouldRestoreSPFromFP(true); } void ARMFrameLowering::emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const { MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); assert(MBBI->getDesc().isReturn() && "Can only insert epilog into returning blocks"); unsigned RetOpcode = MBBI->getOpcode(); DebugLoc dl = MBBI->getDebugLoc(); MachineFrameInfo *MFI = MF.getFrameInfo(); ARMFunctionInfo *AFI = MF.getInfo(); const TargetRegisterInfo *RegInfo = MF.getTarget().getRegisterInfo(); const ARMBaseInstrInfo &TII = *static_cast(MF.getTarget().getInstrInfo()); assert(!AFI->isThumb1OnlyFunction() && "This emitEpilogue does not support Thumb1!"); bool isARM = !AFI->isThumbFunction(); unsigned VARegSaveSize = AFI->getVarArgsRegSaveSize(); int NumBytes = (int)MFI->getStackSize(); unsigned FramePtr = RegInfo->getFrameRegister(MF); + + // All calls are tail calls in GHC calling conv, and functions have no prologue/epilogue. + if (MF.getFunction()->getCallingConv() == CallingConv::GHC) + return; if (!AFI->hasStackFrame()) { if (NumBytes != 0) emitSPUpdate(isARM, MBB, MBBI, dl, TII, NumBytes); } else { // Unwind MBBI to point to first LDR / VLDRD. const unsigned *CSRegs = RegInfo->getCalleeSavedRegs(); if (MBBI != MBB.begin()) { do --MBBI; while (MBBI != MBB.begin() && isCSRestore(MBBI, TII, CSRegs)); if (!isCSRestore(MBBI, TII, CSRegs)) ++MBBI; } // Move SP to start of FP callee save spill area. NumBytes -= (AFI->getGPRCalleeSavedArea1Size() + AFI->getGPRCalleeSavedArea2Size() + AFI->getDPRCalleeSavedAreaSize()); // Reset SP based on frame pointer only if the stack frame extends beyond // frame pointer stack slot or target is ELF and the function has FP. if (AFI->shouldRestoreSPFromFP()) { NumBytes = AFI->getFramePtrSpillOffset() - NumBytes; if (NumBytes) { if (isARM) emitARMRegPlusImmediate(MBB, MBBI, dl, ARM::SP, FramePtr, -NumBytes, ARMCC::AL, 0, TII); else { // It's not possible to restore SP from FP in a single instruction. // For Darwin, this looks like: // mov sp, r7 // sub sp, #24 // This is bad, if an interrupt is taken after the mov, sp is in an // inconsistent state. // Use the first callee-saved register as a scratch register. assert(MF.getRegInfo().isPhysRegUsed(ARM::R4) && "No scratch register to restore SP from FP!"); emitT2RegPlusImmediate(MBB, MBBI, dl, ARM::R4, FramePtr, -NumBytes, ARMCC::AL, 0, TII); AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVr), ARM::SP) .addReg(ARM::R4)); } } else { // Thumb2 or ARM. if (isARM) BuildMI(MBB, MBBI, dl, TII.get(ARM::MOVr), ARM::SP) .addReg(FramePtr).addImm((unsigned)ARMCC::AL).addReg(0).addReg(0); else AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVr), ARM::SP) .addReg(FramePtr)); } } else if (NumBytes) emitSPUpdate(isARM, MBB, MBBI, dl, TII, NumBytes); // Increment past our save areas. if (AFI->getDPRCalleeSavedAreaSize()) { MBBI++; // Since vpop register list cannot have gaps, there may be multiple vpop // instructions in the epilogue. while (MBBI->getOpcode() == ARM::VLDMDIA_UPD) MBBI++; } if (AFI->getGPRCalleeSavedArea2Size()) MBBI++; if (AFI->getGPRCalleeSavedArea1Size()) MBBI++; } if (RetOpcode == ARM::TCRETURNdi || RetOpcode == ARM::TCRETURNdiND || RetOpcode == ARM::TCRETURNri || RetOpcode == ARM::TCRETURNriND) { // Tail call return: adjust the stack pointer and jump to callee. MBBI = MBB.getLastNonDebugInstr(); MachineOperand &JumpTarget = MBBI->getOperand(0); // Jump to label or value in register. if (RetOpcode == ARM::TCRETURNdi || RetOpcode == ARM::TCRETURNdiND) { unsigned TCOpcode = (RetOpcode == ARM::TCRETURNdi) ? (STI.isThumb() ? ARM::tTAILJMPd : ARM::TAILJMPd) : (STI.isThumb() ? ARM::tTAILJMPdND : ARM::TAILJMPdND); MachineInstrBuilder MIB = BuildMI(MBB, MBBI, dl, TII.get(TCOpcode)); if (JumpTarget.isGlobal()) MIB.addGlobalAddress(JumpTarget.getGlobal(), JumpTarget.getOffset(), JumpTarget.getTargetFlags()); else { assert(JumpTarget.isSymbol()); MIB.addExternalSymbol(JumpTarget.getSymbolName(), JumpTarget.getTargetFlags()); } // Add the default predicate in Thumb mode. if (STI.isThumb()) MIB.addImm(ARMCC::AL).addReg(0); } else if (RetOpcode == ARM::TCRETURNri) { BuildMI(MBB, MBBI, dl, TII.get(STI.isThumb() ? ARM::tTAILJMPr : ARM::TAILJMPr)). addReg(JumpTarget.getReg(), RegState::Kill); } else if (RetOpcode == ARM::TCRETURNriND) { BuildMI(MBB, MBBI, dl, TII.get(STI.isThumb() ? ARM::tTAILJMPrND : ARM::TAILJMPrND)). addReg(JumpTarget.getReg(), RegState::Kill); } MachineInstr *NewMI = prior(MBBI); for (unsigned i = 1, e = MBBI->getNumOperands(); i != e; ++i) NewMI->addOperand(MBBI->getOperand(i)); // Delete the pseudo instruction TCRETURN. MBB.erase(MBBI); MBBI = NewMI; } if (VARegSaveSize) emitSPUpdate(isARM, MBB, MBBI, dl, TII, VARegSaveSize); } /// getFrameIndexReference - Provide a base+offset reference to an FI slot for /// debug info. It's the same as what we use for resolving the code-gen /// references for now. FIXME: This can go wrong when references are /// SP-relative and simple call frames aren't used. int ARMFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI, unsigned &FrameReg) const { return ResolveFrameIndexReference(MF, FI, FrameReg, 0); } int ARMFrameLowering::ResolveFrameIndexReference(const MachineFunction &MF, int FI, unsigned &FrameReg, int SPAdj) const { const MachineFrameInfo *MFI = MF.getFrameInfo(); const ARMBaseRegisterInfo *RegInfo = static_cast(MF.getTarget().getRegisterInfo()); const ARMFunctionInfo *AFI = MF.getInfo(); int Offset = MFI->getObjectOffset(FI) + MFI->getStackSize(); int FPOffset = Offset - AFI->getFramePtrSpillOffset(); bool isFixed = MFI->isFixedObjectIndex(FI); FrameReg = ARM::SP; Offset += SPAdj; if (AFI->isGPRCalleeSavedArea1Frame(FI)) return Offset - AFI->getGPRCalleeSavedArea1Offset(); else if (AFI->isGPRCalleeSavedArea2Frame(FI)) return Offset - AFI->getGPRCalleeSavedArea2Offset(); else if (AFI->isDPRCalleeSavedAreaFrame(FI)) return Offset - AFI->getDPRCalleeSavedAreaOffset(); // When dynamically realigning the stack, use the frame pointer for // parameters, and the stack/base pointer for locals. if (RegInfo->needsStackRealignment(MF)) { assert (hasFP(MF) && "dynamic stack realignment without a FP!"); if (isFixed) { FrameReg = RegInfo->getFrameRegister(MF); Offset = FPOffset; } else if (MFI->hasVarSizedObjects()) { assert(RegInfo->hasBasePointer(MF) && "VLAs and dynamic stack alignment, but missing base pointer!"); FrameReg = RegInfo->getBaseRegister(); } return Offset; } // If there is a frame pointer, use it when we can. if (hasFP(MF) && AFI->hasStackFrame()) { // Use frame pointer to reference fixed objects. Use it for locals if // there are VLAs (and thus the SP isn't reliable as a base). if (isFixed || (MFI->hasVarSizedObjects() && !RegInfo->hasBasePointer(MF))) { FrameReg = RegInfo->getFrameRegister(MF); return FPOffset; } else if (MFI->hasVarSizedObjects()) { assert(RegInfo->hasBasePointer(MF) && "missing base pointer!"); if (AFI->isThumb2Function()) { // Try to use the frame pointer if we can, else use the base pointer // since it's available. This is handy for the emergency spill slot, in // particular. if (FPOffset >= -255 && FPOffset < 0) { FrameReg = RegInfo->getFrameRegister(MF); return FPOffset; } } } else if (AFI->isThumb2Function()) { // Use add , sp, # // ldr , [sp, #] // if at all possible to save space. if (Offset >= 0 && (Offset & 3) == 0 && Offset <= 1020) return Offset; // In Thumb2 mode, the negative offset is very limited. Try to avoid // out of range references. ldr ,[, #-] if (FPOffset >= -255 && FPOffset < 0) { FrameReg = RegInfo->getFrameRegister(MF); return FPOffset; } } else if (Offset > (FPOffset < 0 ? -FPOffset : FPOffset)) { // Otherwise, use SP or FP, whichever is closer to the stack slot. FrameReg = RegInfo->getFrameRegister(MF); return FPOffset; } } // Use the base pointer if we have one. if (RegInfo->hasBasePointer(MF)) FrameReg = RegInfo->getBaseRegister(); return Offset; } int ARMFrameLowering::getFrameIndexOffset(const MachineFunction &MF, int FI) const { unsigned FrameReg; return getFrameIndexReference(MF, FI, FrameReg); } void ARMFrameLowering::emitPushInst(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, const std::vector &CSI, unsigned StmOpc, unsigned StrOpc, bool NoGap, bool(*Func)(unsigned, bool), unsigned MIFlags) const { MachineFunction &MF = *MBB.getParent(); const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo(); DebugLoc DL; if (MI != MBB.end()) DL = MI->getDebugLoc(); SmallVector, 4> Regs; unsigned i = CSI.size(); while (i != 0) { unsigned LastReg = 0; for (; i != 0; --i) { unsigned Reg = CSI[i-1].getReg(); if (!(Func)(Reg, STI.isTargetDarwin())) continue; // Add the callee-saved register as live-in unless it's LR and // @llvm.returnaddress is called. If LR is returned for // @llvm.returnaddress then it's already added to the function and // entry block live-in sets. bool isKill = true; if (Reg == ARM::LR) { if (MF.getFrameInfo()->isReturnAddressTaken() && MF.getRegInfo().isLiveIn(Reg)) isKill = false; } if (isKill) MBB.addLiveIn(Reg); // If NoGap is true, push consecutive registers and then leave the rest // for other instructions. e.g. // vpush {d8, d10, d11} -> vpush {d8}, vpush {d10, d11} if (NoGap && LastReg && LastReg != Reg-1) break; LastReg = Reg; Regs.push_back(std::make_pair(Reg, isKill)); } if (Regs.empty()) continue; if (Regs.size() > 1 || StrOpc== 0) { MachineInstrBuilder MIB = AddDefaultPred(BuildMI(MBB, MI, DL, TII.get(StmOpc), ARM::SP) .addReg(ARM::SP).setMIFlags(MIFlags)); for (unsigned i = 0, e = Regs.size(); i < e; ++i) MIB.addReg(Regs[i].first, getKillRegState(Regs[i].second)); } else if (Regs.size() == 1) { MachineInstrBuilder MIB = BuildMI(MBB, MI, DL, TII.get(StrOpc), ARM::SP) .addReg(Regs[0].first, getKillRegState(Regs[0].second)) .addReg(ARM::SP).setMIFlags(MIFlags) .addImm(-4); AddDefaultPred(MIB); } Regs.clear(); } } void ARMFrameLowering::emitPopInst(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, const std::vector &CSI, unsigned LdmOpc, unsigned LdrOpc, bool isVarArg, bool NoGap, bool(*Func)(unsigned, bool)) const { MachineFunction &MF = *MBB.getParent(); const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo(); ARMFunctionInfo *AFI = MF.getInfo(); DebugLoc DL = MI->getDebugLoc(); unsigned RetOpcode = MI->getOpcode(); bool isTailCall = (RetOpcode == ARM::TCRETURNdi || RetOpcode == ARM::TCRETURNdiND || RetOpcode == ARM::TCRETURNri || RetOpcode == ARM::TCRETURNriND); SmallVector Regs; unsigned i = CSI.size(); while (i != 0) { unsigned LastReg = 0; bool DeleteRet = false; for (; i != 0; --i) { unsigned Reg = CSI[i-1].getReg(); if (!(Func)(Reg, STI.isTargetDarwin())) continue; if (Reg == ARM::LR && !isTailCall && !isVarArg && STI.hasV5TOps()) { Reg = ARM::PC; LdmOpc = AFI->isThumbFunction() ? ARM::t2LDMIA_RET : ARM::LDMIA_RET; // Fold the return instruction into the LDM. DeleteRet = true; } // If NoGap is true, pop consecutive registers and then leave the rest // for other instructions. e.g. // vpop {d8, d10, d11} -> vpop {d8}, vpop {d10, d11} if (NoGap && LastReg && LastReg != Reg-1) break; LastReg = Reg; Regs.push_back(Reg); } if (Regs.empty()) continue; if (Regs.size() > 1 || LdrOpc == 0) { MachineInstrBuilder MIB = AddDefaultPred(BuildMI(MBB, MI, DL, TII.get(LdmOpc), ARM::SP) .addReg(ARM::SP)); for (unsigned i = 0, e = Regs.size(); i < e; ++i) MIB.addReg(Regs[i], getDefRegState(true)); if (DeleteRet) { MIB->copyImplicitOps(&*MI); MI->eraseFromParent(); } MI = MIB; } else if (Regs.size() == 1) { // If we adjusted the reg to PC from LR above, switch it back here. We // only do that for LDM. if (Regs[0] == ARM::PC) Regs[0] = ARM::LR; MachineInstrBuilder MIB = BuildMI(MBB, MI, DL, TII.get(LdrOpc), Regs[0]) .addReg(ARM::SP, RegState::Define) .addReg(ARM::SP); // ARM mode needs an extra reg0 here due to addrmode2. Will go away once // that refactoring is complete (eventually). if (LdrOpc == ARM::LDR_POST_REG || LdrOpc == ARM::LDR_POST_IMM) { MIB.addReg(0); MIB.addImm(ARM_AM::getAM2Opc(ARM_AM::add, 4, ARM_AM::no_shift)); } else MIB.addImm(4); AddDefaultPred(MIB); } Regs.clear(); } } bool ARMFrameLowering::spillCalleeSavedRegisters(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, const std::vector &CSI, const TargetRegisterInfo *TRI) const { if (CSI.empty()) return false; MachineFunction &MF = *MBB.getParent(); ARMFunctionInfo *AFI = MF.getInfo(); unsigned PushOpc = AFI->isThumbFunction() ? ARM::t2STMDB_UPD : ARM::STMDB_UPD; unsigned PushOneOpc = AFI->isThumbFunction() ? ARM::t2STR_PRE : ARM::STR_PRE_IMM; unsigned FltOpc = ARM::VSTMDDB_UPD; emitPushInst(MBB, MI, CSI, PushOpc, PushOneOpc, false, &isARMArea1Register, MachineInstr::FrameSetup); emitPushInst(MBB, MI, CSI, PushOpc, PushOneOpc, false, &isARMArea2Register, MachineInstr::FrameSetup); emitPushInst(MBB, MI, CSI, FltOpc, 0, true, &isARMArea3Register, MachineInstr::FrameSetup); return true; } bool ARMFrameLowering::restoreCalleeSavedRegisters(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, const std::vector &CSI, const TargetRegisterInfo *TRI) const { if (CSI.empty()) return false; MachineFunction &MF = *MBB.getParent(); ARMFunctionInfo *AFI = MF.getInfo(); bool isVarArg = AFI->getVarArgsRegSaveSize() > 0; unsigned PopOpc = AFI->isThumbFunction() ? ARM::t2LDMIA_UPD : ARM::LDMIA_UPD; unsigned LdrOpc = AFI->isThumbFunction() ? ARM::t2LDR_POST :ARM::LDR_POST_IMM; unsigned FltOpc = ARM::VLDMDIA_UPD; emitPopInst(MBB, MI, CSI, FltOpc, 0, isVarArg, true, &isARMArea3Register); emitPopInst(MBB, MI, CSI, PopOpc, LdrOpc, isVarArg, false, &isARMArea2Register); emitPopInst(MBB, MI, CSI, PopOpc, LdrOpc, isVarArg, false, &isARMArea1Register); return true; } // FIXME: Make generic? static unsigned GetFunctionSizeInBytes(const MachineFunction &MF, const ARMBaseInstrInfo &TII) { unsigned FnSize = 0; for (MachineFunction::const_iterator MBBI = MF.begin(), E = MF.end(); MBBI != E; ++MBBI) { const MachineBasicBlock &MBB = *MBBI; for (MachineBasicBlock::const_iterator I = MBB.begin(),E = MBB.end(); I != E; ++I) FnSize += TII.GetInstSizeInBytes(I); } return FnSize; } /// estimateStackSize - Estimate and return the size of the frame. /// FIXME: Make generic? static unsigned estimateStackSize(MachineFunction &MF) { const MachineFrameInfo *MFI = MF.getFrameInfo(); const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); const TargetRegisterInfo *RegInfo = MF.getTarget().getRegisterInfo(); unsigned MaxAlign = MFI->getMaxAlignment(); int Offset = 0; // This code is very, very similar to PEI::calculateFrameObjectOffsets(). // It really should be refactored to share code. Until then, changes // should keep in mind that there's tight coupling between the two. for (int i = MFI->getObjectIndexBegin(); i != 0; ++i) { int FixedOff = -MFI->getObjectOffset(i); if (FixedOff > Offset) Offset = FixedOff; } for (unsigned i = 0, e = MFI->getObjectIndexEnd(); i != e; ++i) { if (MFI->isDeadObjectIndex(i)) continue; Offset += MFI->getObjectSize(i); unsigned Align = MFI->getObjectAlignment(i); // Adjust to alignment boundary Offset = (Offset+Align-1)/Align*Align; MaxAlign = std::max(Align, MaxAlign); } if (MFI->adjustsStack() && TFI->hasReservedCallFrame(MF)) Offset += MFI->getMaxCallFrameSize(); // Round up the size to a multiple of the alignment. If the function has // any calls or alloca's, align to the target's StackAlignment value to // ensure that the callee's frame or the alloca data is suitably aligned; // otherwise, for leaf functions, align to the TransientStackAlignment // value. unsigned StackAlign; if (MFI->adjustsStack() || MFI->hasVarSizedObjects() || (RegInfo->needsStackRealignment(MF) && MFI->getObjectIndexEnd() != 0)) StackAlign = TFI->getStackAlignment(); else StackAlign = TFI->getTransientStackAlignment(); // If the frame pointer is eliminated, all frame offsets will be relative to // SP not FP. Align to MaxAlign so this works. StackAlign = std::max(StackAlign, MaxAlign); unsigned AlignMask = StackAlign - 1; Offset = (Offset + AlignMask) & ~uint64_t(AlignMask); return (unsigned)Offset; } /// estimateRSStackSizeLimit - Look at each instruction that references stack /// frames and return the stack size limit beyond which some of these /// instructions will require a scratch register during their expansion later. // FIXME: Move to TII? static unsigned estimateRSStackSizeLimit(MachineFunction &MF, const TargetFrameLowering *TFI) { const ARMFunctionInfo *AFI = MF.getInfo(); unsigned Limit = (1 << 12) - 1; for (MachineFunction::iterator BB = MF.begin(),E = MF.end(); BB != E; ++BB) { for (MachineBasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) { for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) { if (!I->getOperand(i).isFI()) continue; // When using ADDri to get the address of a stack object, 255 is the // largest offset guaranteed to fit in the immediate offset. if (I->getOpcode() == ARM::ADDri) { Limit = std::min(Limit, (1U << 8) - 1); break; } // Otherwise check the addressing mode. switch (I->getDesc().TSFlags & ARMII::AddrModeMask) { case ARMII::AddrMode3: case ARMII::AddrModeT2_i8: Limit = std::min(Limit, (1U << 8) - 1); break; case ARMII::AddrMode5: case ARMII::AddrModeT2_i8s4: Limit = std::min(Limit, ((1U << 8) - 1) * 4); break; case ARMII::AddrModeT2_i12: // i12 supports only positive offset so these will be converted to // i8 opcodes. See llvm::rewriteT2FrameIndex. if (TFI->hasFP(MF) && AFI->hasStackFrame()) Limit = std::min(Limit, (1U << 8) - 1); break; case ARMII::AddrMode4: case ARMII::AddrMode6: // Addressing modes 4 & 6 (load/store) instructions can't encode an // immediate offset for stack references. return 0; default: break; } break; // At most one FI per instruction } } } return Limit; } void ARMFrameLowering::processFunctionBeforeCalleeSavedScan(MachineFunction &MF, RegScavenger *RS) const { // This tells PEI to spill the FP as if it is any other callee-save register // to take advantage the eliminateFrameIndex machinery. This also ensures it // is spilled in the order specified by getCalleeSavedRegs() to make it easier // to combine multiple loads / stores. bool CanEliminateFrame = true; bool CS1Spilled = false; bool LRSpilled = false; unsigned NumGPRSpills = 0; SmallVector UnspilledCS1GPRs; SmallVector UnspilledCS2GPRs; const ARMBaseRegisterInfo *RegInfo = static_cast(MF.getTarget().getRegisterInfo()); const ARMBaseInstrInfo &TII = *static_cast(MF.getTarget().getInstrInfo()); ARMFunctionInfo *AFI = MF.getInfo(); MachineFrameInfo *MFI = MF.getFrameInfo(); unsigned FramePtr = RegInfo->getFrameRegister(MF); // Spill R4 if Thumb2 function requires stack realignment - it will be used as // scratch register. Also spill R4 if Thumb2 function has varsized objects, // since it's not always possible to restore sp from fp in a single // instruction. // FIXME: It will be better just to find spare register here. if (AFI->isThumb2Function() && (MFI->hasVarSizedObjects() || RegInfo->needsStackRealignment(MF))) MF.getRegInfo().setPhysRegUsed(ARM::R4); if (AFI->isThumb1OnlyFunction()) { // Spill LR if Thumb1 function uses variable length argument lists. if (AFI->getVarArgsRegSaveSize() > 0) MF.getRegInfo().setPhysRegUsed(ARM::LR); // Spill R4 if Thumb1 epilogue has to restore SP from FP. We don't know // for sure what the stack size will be, but for this, an estimate is good // enough. If there anything changes it, it'll be a spill, which implies // we've used all the registers and so R4 is already used, so not marking // it here will be OK. // FIXME: It will be better just to find spare register here. unsigned StackSize = estimateStackSize(MF); if (MFI->hasVarSizedObjects() || StackSize > 508) MF.getRegInfo().setPhysRegUsed(ARM::R4); } // Spill the BasePtr if it's used. if (RegInfo->hasBasePointer(MF)) MF.getRegInfo().setPhysRegUsed(RegInfo->getBaseRegister()); // Don't spill FP if the frame can be eliminated. This is determined // by scanning the callee-save registers to see if any is used. const unsigned *CSRegs = RegInfo->getCalleeSavedRegs(); for (unsigned i = 0; CSRegs[i]; ++i) { unsigned Reg = CSRegs[i]; bool Spilled = false; if (MF.getRegInfo().isPhysRegUsed(Reg)) { Spilled = true; CanEliminateFrame = false; } else { // Check alias registers too. for (const unsigned *Aliases = RegInfo->getAliasSet(Reg); *Aliases; ++Aliases) { if (MF.getRegInfo().isPhysRegUsed(*Aliases)) { Spilled = true; CanEliminateFrame = false; } } } if (!ARM::GPRRegisterClass->contains(Reg)) continue; if (Spilled) { NumGPRSpills++; if (!STI.isTargetDarwin()) { if (Reg == ARM::LR) LRSpilled = true; CS1Spilled = true; continue; } // Keep track if LR and any of R4, R5, R6, and R7 is spilled. switch (Reg) { case ARM::LR: LRSpilled = true; // Fallthrough case ARM::R4: case ARM::R5: case ARM::R6: case ARM::R7: CS1Spilled = true; break; default: break; } } else { if (!STI.isTargetDarwin()) { UnspilledCS1GPRs.push_back(Reg); continue; } switch (Reg) { case ARM::R4: case ARM::R5: case ARM::R6: case ARM::R7: case ARM::LR: UnspilledCS1GPRs.push_back(Reg); break; default: UnspilledCS2GPRs.push_back(Reg); break; } } } bool ForceLRSpill = false; if (!LRSpilled && AFI->isThumb1OnlyFunction()) { unsigned FnSize = GetFunctionSizeInBytes(MF, TII); // Force LR to be spilled if the Thumb function size is > 2048. This enables // use of BL to implement far jump. If it turns out that it's not needed // then the branch fix up path will undo it. if (FnSize >= (1 << 11)) { CanEliminateFrame = false; ForceLRSpill = true; } } // If any of the stack slot references may be out of range of an immediate // offset, make sure a register (or a spill slot) is available for the // register scavenger. Note that if we're indexing off the frame pointer, the // effective stack size is 4 bytes larger since the FP points to the stack // slot of the previous FP. Also, if we have variable sized objects in the // function, stack slot references will often be negative, and some of // our instructions are positive-offset only, so conservatively consider // that case to want a spill slot (or register) as well. Similarly, if // the function adjusts the stack pointer during execution and the // adjustments aren't already part of our stack size estimate, our offset // calculations may be off, so be conservative. // FIXME: We could add logic to be more precise about negative offsets // and which instructions will need a scratch register for them. Is it // worth the effort and added fragility? bool BigStack = (RS && (estimateStackSize(MF) + ((hasFP(MF) && AFI->hasStackFrame()) ? 4:0) >= estimateRSStackSizeLimit(MF, this))) || MFI->hasVarSizedObjects() || (MFI->adjustsStack() && !canSimplifyCallFramePseudos(MF)); bool ExtraCSSpill = false; if (BigStack || !CanEliminateFrame || RegInfo->cannotEliminateFrame(MF)) { AFI->setHasStackFrame(true); // If LR is not spilled, but at least one of R4, R5, R6, and R7 is spilled. // Spill LR as well so we can fold BX_RET to the registers restore (LDM). if (!LRSpilled && CS1Spilled) { MF.getRegInfo().setPhysRegUsed(ARM::LR); NumGPRSpills++; UnspilledCS1GPRs.erase(std::find(UnspilledCS1GPRs.begin(), UnspilledCS1GPRs.end(), (unsigned)ARM::LR)); ForceLRSpill = false; ExtraCSSpill = true; } if (hasFP(MF)) { MF.getRegInfo().setPhysRegUsed(FramePtr); NumGPRSpills++; } // If stack and double are 8-byte aligned and we are spilling an odd number // of GPRs, spill one extra callee save GPR so we won't have to pad between // the integer and double callee save areas. unsigned TargetAlign = getStackAlignment(); if (TargetAlign == 8 && (NumGPRSpills & 1)) { if (CS1Spilled && !UnspilledCS1GPRs.empty()) { for (unsigned i = 0, e = UnspilledCS1GPRs.size(); i != e; ++i) { unsigned Reg = UnspilledCS1GPRs[i]; // Don't spill high register if the function is thumb1 if (!AFI->isThumb1OnlyFunction() || isARMLowRegister(Reg) || Reg == ARM::LR) { MF.getRegInfo().setPhysRegUsed(Reg); if (!RegInfo->isReservedReg(MF, Reg)) ExtraCSSpill = true; break; } } } else if (!UnspilledCS2GPRs.empty() && !AFI->isThumb1OnlyFunction()) { unsigned Reg = UnspilledCS2GPRs.front(); MF.getRegInfo().setPhysRegUsed(Reg); if (!RegInfo->isReservedReg(MF, Reg)) ExtraCSSpill = true; } } // Estimate if we might need to scavenge a register at some point in order // to materialize a stack offset. If so, either spill one additional // callee-saved register or reserve a special spill slot to facilitate // register scavenging. Thumb1 needs a spill slot for stack pointer // adjustments also, even when the frame itself is small. if (BigStack && !ExtraCSSpill) { // If any non-reserved CS register isn't spilled, just spill one or two // extra. That should take care of it! unsigned NumExtras = TargetAlign / 4; SmallVector Extras; while (NumExtras && !UnspilledCS1GPRs.empty()) { unsigned Reg = UnspilledCS1GPRs.back(); UnspilledCS1GPRs.pop_back(); if (!RegInfo->isReservedReg(MF, Reg) && (!AFI->isThumb1OnlyFunction() || isARMLowRegister(Reg) || Reg == ARM::LR)) { Extras.push_back(Reg); NumExtras--; } } // For non-Thumb1 functions, also check for hi-reg CS registers if (!AFI->isThumb1OnlyFunction()) { while (NumExtras && !UnspilledCS2GPRs.empty()) { unsigned Reg = UnspilledCS2GPRs.back(); UnspilledCS2GPRs.pop_back(); if (!RegInfo->isReservedReg(MF, Reg)) { Extras.push_back(Reg); NumExtras--; } } } if (Extras.size() && NumExtras == 0) { for (unsigned i = 0, e = Extras.size(); i != e; ++i) { MF.getRegInfo().setPhysRegUsed(Extras[i]); } } else if (!AFI->isThumb1OnlyFunction()) { // note: Thumb1 functions spill to R12, not the stack. Reserve a slot // closest to SP or frame pointer. const TargetRegisterClass *RC = ARM::GPRRegisterClass; RS->setScavengingFrameIndex(MFI->CreateStackObject(RC->getSize(), RC->getAlignment(), false)); } } } if (ForceLRSpill) { MF.getRegInfo().setPhysRegUsed(ARM::LR); AFI->setLRIsSpilledForFarJump(true); } } Index: head/contrib/llvm/lib/Target/ARM/ARMISelLowering.cpp =================================================================== --- head/contrib/llvm/lib/Target/ARM/ARMISelLowering.cpp (revision 228378) +++ head/contrib/llvm/lib/Target/ARM/ARMISelLowering.cpp (revision 228379) @@ -1,8835 +1,8837 @@ //===-- ARMISelLowering.cpp - ARM DAG Lowering Implementation -------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines the interfaces that ARM uses to lower LLVM code into a // selection DAG. // //===----------------------------------------------------------------------===// #define DEBUG_TYPE "arm-isel" #include "ARM.h" #include "ARMCallingConv.h" #include "ARMConstantPoolValue.h" #include "ARMISelLowering.h" #include "ARMMachineFunctionInfo.h" #include "ARMPerfectShuffle.h" #include "ARMRegisterInfo.h" #include "ARMSubtarget.h" #include "ARMTargetMachine.h" #include "ARMTargetObjectFile.h" #include "MCTargetDesc/ARMAddressingModes.h" #include "llvm/CallingConv.h" #include "llvm/Constants.h" #include "llvm/Function.h" #include "llvm/GlobalValue.h" #include "llvm/Instruction.h" #include "llvm/Instructions.h" #include "llvm/Intrinsics.h" #include "llvm/Type.h" #include "llvm/CodeGen/CallingConvLower.h" #include "llvm/CodeGen/IntrinsicLowering.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/PseudoSourceValue.h" #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/Target/TargetOptions.h" #include "llvm/ADT/VectorExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include using namespace llvm; STATISTIC(NumTailCalls, "Number of tail calls"); STATISTIC(NumMovwMovt, "Number of GAs materialized with movw + movt"); // This option should go away when tail calls fully work. static cl::opt EnableARMTailCalls("arm-tail-calls", cl::Hidden, cl::desc("Generate tail calls (TEMPORARY OPTION)."), cl::init(false)); cl::opt EnableARMLongCalls("arm-long-calls", cl::Hidden, cl::desc("Generate calls via indirect call instructions"), cl::init(false)); static cl::opt ARMInterworking("arm-interworking", cl::Hidden, cl::desc("Enable / disable ARM interworking (for debugging only)"), cl::init(true)); namespace llvm { class ARMCCState : public CCState { public: ARMCCState(CallingConv::ID CC, bool isVarArg, MachineFunction &MF, const TargetMachine &TM, SmallVector &locs, LLVMContext &C, ParmContext PC) : CCState(CC, isVarArg, MF, TM, locs, C) { assert(((PC == Call) || (PC == Prologue)) && "ARMCCState users must specify whether their context is call" "or prologue generation."); CallOrPrologue = PC; } }; } // The APCS parameter registers. static const unsigned GPRArgRegs[] = { ARM::R0, ARM::R1, ARM::R2, ARM::R3 }; void ARMTargetLowering::addTypeForNEON(EVT VT, EVT PromotedLdStVT, EVT PromotedBitwiseVT) { if (VT != PromotedLdStVT) { setOperationAction(ISD::LOAD, VT.getSimpleVT(), Promote); AddPromotedToType (ISD::LOAD, VT.getSimpleVT(), PromotedLdStVT.getSimpleVT()); setOperationAction(ISD::STORE, VT.getSimpleVT(), Promote); AddPromotedToType (ISD::STORE, VT.getSimpleVT(), PromotedLdStVT.getSimpleVT()); } EVT ElemTy = VT.getVectorElementType(); if (ElemTy != MVT::i64 && ElemTy != MVT::f64) setOperationAction(ISD::SETCC, VT.getSimpleVT(), Custom); setOperationAction(ISD::EXTRACT_VECTOR_ELT, VT.getSimpleVT(), Custom); if (ElemTy != MVT::i32) { setOperationAction(ISD::SINT_TO_FP, VT.getSimpleVT(), Expand); setOperationAction(ISD::UINT_TO_FP, VT.getSimpleVT(), Expand); setOperationAction(ISD::FP_TO_SINT, VT.getSimpleVT(), Expand); setOperationAction(ISD::FP_TO_UINT, VT.getSimpleVT(), Expand); } setOperationAction(ISD::BUILD_VECTOR, VT.getSimpleVT(), Custom); setOperationAction(ISD::VECTOR_SHUFFLE, VT.getSimpleVT(), Custom); setOperationAction(ISD::CONCAT_VECTORS, VT.getSimpleVT(), Legal); setOperationAction(ISD::EXTRACT_SUBVECTOR, VT.getSimpleVT(), Legal); setOperationAction(ISD::SELECT, VT.getSimpleVT(), Expand); setOperationAction(ISD::SELECT_CC, VT.getSimpleVT(), Expand); if (VT.isInteger()) { setOperationAction(ISD::SHL, VT.getSimpleVT(), Custom); setOperationAction(ISD::SRA, VT.getSimpleVT(), Custom); setOperationAction(ISD::SRL, VT.getSimpleVT(), Custom); setLoadExtAction(ISD::SEXTLOAD, VT.getSimpleVT(), Expand); setLoadExtAction(ISD::ZEXTLOAD, VT.getSimpleVT(), Expand); for (unsigned InnerVT = (unsigned)MVT::FIRST_VECTOR_VALUETYPE; InnerVT <= (unsigned)MVT::LAST_VECTOR_VALUETYPE; ++InnerVT) setTruncStoreAction(VT.getSimpleVT(), (MVT::SimpleValueType)InnerVT, Expand); } setLoadExtAction(ISD::EXTLOAD, VT.getSimpleVT(), Expand); // Promote all bit-wise operations. if (VT.isInteger() && VT != PromotedBitwiseVT) { setOperationAction(ISD::AND, VT.getSimpleVT(), Promote); AddPromotedToType (ISD::AND, VT.getSimpleVT(), PromotedBitwiseVT.getSimpleVT()); setOperationAction(ISD::OR, VT.getSimpleVT(), Promote); AddPromotedToType (ISD::OR, VT.getSimpleVT(), PromotedBitwiseVT.getSimpleVT()); setOperationAction(ISD::XOR, VT.getSimpleVT(), Promote); AddPromotedToType (ISD::XOR, VT.getSimpleVT(), PromotedBitwiseVT.getSimpleVT()); } // Neon does not support vector divide/remainder operations. setOperationAction(ISD::SDIV, VT.getSimpleVT(), Expand); setOperationAction(ISD::UDIV, VT.getSimpleVT(), Expand); setOperationAction(ISD::FDIV, VT.getSimpleVT(), Expand); setOperationAction(ISD::SREM, VT.getSimpleVT(), Expand); setOperationAction(ISD::UREM, VT.getSimpleVT(), Expand); setOperationAction(ISD::FREM, VT.getSimpleVT(), Expand); } void ARMTargetLowering::addDRTypeForNEON(EVT VT) { addRegisterClass(VT, ARM::DPRRegisterClass); addTypeForNEON(VT, MVT::f64, MVT::v2i32); } void ARMTargetLowering::addQRTypeForNEON(EVT VT) { addRegisterClass(VT, ARM::QPRRegisterClass); addTypeForNEON(VT, MVT::v2f64, MVT::v4i32); } static TargetLoweringObjectFile *createTLOF(TargetMachine &TM) { if (TM.getSubtarget().isTargetDarwin()) return new TargetLoweringObjectFileMachO(); return new ARMElfTargetObjectFile(); } ARMTargetLowering::ARMTargetLowering(TargetMachine &TM) : TargetLowering(TM, createTLOF(TM)) { Subtarget = &TM.getSubtarget(); RegInfo = TM.getRegisterInfo(); Itins = TM.getInstrItineraryData(); setBooleanVectorContents(ZeroOrNegativeOneBooleanContent); if (Subtarget->isTargetDarwin()) { // Uses VFP for Thumb libfuncs if available. if (Subtarget->isThumb() && Subtarget->hasVFP2()) { // Single-precision floating-point arithmetic. setLibcallName(RTLIB::ADD_F32, "__addsf3vfp"); setLibcallName(RTLIB::SUB_F32, "__subsf3vfp"); setLibcallName(RTLIB::MUL_F32, "__mulsf3vfp"); setLibcallName(RTLIB::DIV_F32, "__divsf3vfp"); // Double-precision floating-point arithmetic. setLibcallName(RTLIB::ADD_F64, "__adddf3vfp"); setLibcallName(RTLIB::SUB_F64, "__subdf3vfp"); setLibcallName(RTLIB::MUL_F64, "__muldf3vfp"); setLibcallName(RTLIB::DIV_F64, "__divdf3vfp"); // Single-precision comparisons. setLibcallName(RTLIB::OEQ_F32, "__eqsf2vfp"); setLibcallName(RTLIB::UNE_F32, "__nesf2vfp"); setLibcallName(RTLIB::OLT_F32, "__ltsf2vfp"); setLibcallName(RTLIB::OLE_F32, "__lesf2vfp"); setLibcallName(RTLIB::OGE_F32, "__gesf2vfp"); setLibcallName(RTLIB::OGT_F32, "__gtsf2vfp"); setLibcallName(RTLIB::UO_F32, "__unordsf2vfp"); setLibcallName(RTLIB::O_F32, "__unordsf2vfp"); setCmpLibcallCC(RTLIB::OEQ_F32, ISD::SETNE); setCmpLibcallCC(RTLIB::UNE_F32, ISD::SETNE); setCmpLibcallCC(RTLIB::OLT_F32, ISD::SETNE); setCmpLibcallCC(RTLIB::OLE_F32, ISD::SETNE); setCmpLibcallCC(RTLIB::OGE_F32, ISD::SETNE); setCmpLibcallCC(RTLIB::OGT_F32, ISD::SETNE); setCmpLibcallCC(RTLIB::UO_F32, ISD::SETNE); setCmpLibcallCC(RTLIB::O_F32, ISD::SETEQ); // Double-precision comparisons. setLibcallName(RTLIB::OEQ_F64, "__eqdf2vfp"); setLibcallName(RTLIB::UNE_F64, "__nedf2vfp"); setLibcallName(RTLIB::OLT_F64, "__ltdf2vfp"); setLibcallName(RTLIB::OLE_F64, "__ledf2vfp"); setLibcallName(RTLIB::OGE_F64, "__gedf2vfp"); setLibcallName(RTLIB::OGT_F64, "__gtdf2vfp"); setLibcallName(RTLIB::UO_F64, "__unorddf2vfp"); setLibcallName(RTLIB::O_F64, "__unorddf2vfp"); setCmpLibcallCC(RTLIB::OEQ_F64, ISD::SETNE); setCmpLibcallCC(RTLIB::UNE_F64, ISD::SETNE); setCmpLibcallCC(RTLIB::OLT_F64, ISD::SETNE); setCmpLibcallCC(RTLIB::OLE_F64, ISD::SETNE); setCmpLibcallCC(RTLIB::OGE_F64, ISD::SETNE); setCmpLibcallCC(RTLIB::OGT_F64, ISD::SETNE); setCmpLibcallCC(RTLIB::UO_F64, ISD::SETNE); setCmpLibcallCC(RTLIB::O_F64, ISD::SETEQ); // Floating-point to integer conversions. // i64 conversions are done via library routines even when generating VFP // instructions, so use the same ones. setLibcallName(RTLIB::FPTOSINT_F64_I32, "__fixdfsivfp"); setLibcallName(RTLIB::FPTOUINT_F64_I32, "__fixunsdfsivfp"); setLibcallName(RTLIB::FPTOSINT_F32_I32, "__fixsfsivfp"); setLibcallName(RTLIB::FPTOUINT_F32_I32, "__fixunssfsivfp"); // Conversions between floating types. setLibcallName(RTLIB::FPROUND_F64_F32, "__truncdfsf2vfp"); setLibcallName(RTLIB::FPEXT_F32_F64, "__extendsfdf2vfp"); // Integer to floating-point conversions. // i64 conversions are done via library routines even when generating VFP // instructions, so use the same ones. // FIXME: There appears to be some naming inconsistency in ARM libgcc: // e.g., __floatunsidf vs. __floatunssidfvfp. setLibcallName(RTLIB::SINTTOFP_I32_F64, "__floatsidfvfp"); setLibcallName(RTLIB::UINTTOFP_I32_F64, "__floatunssidfvfp"); setLibcallName(RTLIB::SINTTOFP_I32_F32, "__floatsisfvfp"); setLibcallName(RTLIB::UINTTOFP_I32_F32, "__floatunssisfvfp"); } } // These libcalls are not available in 32-bit. setLibcallName(RTLIB::SHL_I128, 0); setLibcallName(RTLIB::SRL_I128, 0); setLibcallName(RTLIB::SRA_I128, 0); if (Subtarget->isAAPCS_ABI()) { // Double-precision floating-point arithmetic helper functions // RTABI chapter 4.1.2, Table 2 setLibcallName(RTLIB::ADD_F64, "__aeabi_dadd"); setLibcallName(RTLIB::DIV_F64, "__aeabi_ddiv"); setLibcallName(RTLIB::MUL_F64, "__aeabi_dmul"); setLibcallName(RTLIB::SUB_F64, "__aeabi_dsub"); setLibcallCallingConv(RTLIB::ADD_F64, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::DIV_F64, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::MUL_F64, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::SUB_F64, CallingConv::ARM_AAPCS); // Double-precision floating-point comparison helper functions // RTABI chapter 4.1.2, Table 3 setLibcallName(RTLIB::OEQ_F64, "__aeabi_dcmpeq"); setCmpLibcallCC(RTLIB::OEQ_F64, ISD::SETNE); setLibcallName(RTLIB::UNE_F64, "__aeabi_dcmpeq"); setCmpLibcallCC(RTLIB::UNE_F64, ISD::SETEQ); setLibcallName(RTLIB::OLT_F64, "__aeabi_dcmplt"); setCmpLibcallCC(RTLIB::OLT_F64, ISD::SETNE); setLibcallName(RTLIB::OLE_F64, "__aeabi_dcmple"); setCmpLibcallCC(RTLIB::OLE_F64, ISD::SETNE); setLibcallName(RTLIB::OGE_F64, "__aeabi_dcmpge"); setCmpLibcallCC(RTLIB::OGE_F64, ISD::SETNE); setLibcallName(RTLIB::OGT_F64, "__aeabi_dcmpgt"); setCmpLibcallCC(RTLIB::OGT_F64, ISD::SETNE); setLibcallName(RTLIB::UO_F64, "__aeabi_dcmpun"); setCmpLibcallCC(RTLIB::UO_F64, ISD::SETNE); setLibcallName(RTLIB::O_F64, "__aeabi_dcmpun"); setCmpLibcallCC(RTLIB::O_F64, ISD::SETEQ); setLibcallCallingConv(RTLIB::OEQ_F64, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::UNE_F64, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::OLT_F64, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::OLE_F64, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::OGE_F64, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::OGT_F64, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::UO_F64, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::O_F64, CallingConv::ARM_AAPCS); // Single-precision floating-point arithmetic helper functions // RTABI chapter 4.1.2, Table 4 setLibcallName(RTLIB::ADD_F32, "__aeabi_fadd"); setLibcallName(RTLIB::DIV_F32, "__aeabi_fdiv"); setLibcallName(RTLIB::MUL_F32, "__aeabi_fmul"); setLibcallName(RTLIB::SUB_F32, "__aeabi_fsub"); setLibcallCallingConv(RTLIB::ADD_F32, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::DIV_F32, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::MUL_F32, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::SUB_F32, CallingConv::ARM_AAPCS); // Single-precision floating-point comparison helper functions // RTABI chapter 4.1.2, Table 5 setLibcallName(RTLIB::OEQ_F32, "__aeabi_fcmpeq"); setCmpLibcallCC(RTLIB::OEQ_F32, ISD::SETNE); setLibcallName(RTLIB::UNE_F32, "__aeabi_fcmpeq"); setCmpLibcallCC(RTLIB::UNE_F32, ISD::SETEQ); setLibcallName(RTLIB::OLT_F32, "__aeabi_fcmplt"); setCmpLibcallCC(RTLIB::OLT_F32, ISD::SETNE); setLibcallName(RTLIB::OLE_F32, "__aeabi_fcmple"); setCmpLibcallCC(RTLIB::OLE_F32, ISD::SETNE); setLibcallName(RTLIB::OGE_F32, "__aeabi_fcmpge"); setCmpLibcallCC(RTLIB::OGE_F32, ISD::SETNE); setLibcallName(RTLIB::OGT_F32, "__aeabi_fcmpgt"); setCmpLibcallCC(RTLIB::OGT_F32, ISD::SETNE); setLibcallName(RTLIB::UO_F32, "__aeabi_fcmpun"); setCmpLibcallCC(RTLIB::UO_F32, ISD::SETNE); setLibcallName(RTLIB::O_F32, "__aeabi_fcmpun"); setCmpLibcallCC(RTLIB::O_F32, ISD::SETEQ); setLibcallCallingConv(RTLIB::OEQ_F32, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::UNE_F32, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::OLT_F32, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::OLE_F32, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::OGE_F32, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::OGT_F32, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::UO_F32, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::O_F32, CallingConv::ARM_AAPCS); // Floating-point to integer conversions. // RTABI chapter 4.1.2, Table 6 setLibcallName(RTLIB::FPTOSINT_F64_I32, "__aeabi_d2iz"); setLibcallName(RTLIB::FPTOUINT_F64_I32, "__aeabi_d2uiz"); setLibcallName(RTLIB::FPTOSINT_F64_I64, "__aeabi_d2lz"); setLibcallName(RTLIB::FPTOUINT_F64_I64, "__aeabi_d2ulz"); setLibcallName(RTLIB::FPTOSINT_F32_I32, "__aeabi_f2iz"); setLibcallName(RTLIB::FPTOUINT_F32_I32, "__aeabi_f2uiz"); setLibcallName(RTLIB::FPTOSINT_F32_I64, "__aeabi_f2lz"); setLibcallName(RTLIB::FPTOUINT_F32_I64, "__aeabi_f2ulz"); setLibcallCallingConv(RTLIB::FPTOSINT_F64_I32, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::FPTOUINT_F64_I32, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::FPTOSINT_F64_I64, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::FPTOUINT_F64_I64, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::FPTOSINT_F32_I32, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::FPTOUINT_F32_I32, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::FPTOSINT_F32_I64, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::FPTOUINT_F32_I64, CallingConv::ARM_AAPCS); // Conversions between floating types. // RTABI chapter 4.1.2, Table 7 setLibcallName(RTLIB::FPROUND_F64_F32, "__aeabi_d2f"); setLibcallName(RTLIB::FPEXT_F32_F64, "__aeabi_f2d"); setLibcallCallingConv(RTLIB::FPROUND_F64_F32, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::FPEXT_F32_F64, CallingConv::ARM_AAPCS); // Integer to floating-point conversions. // RTABI chapter 4.1.2, Table 8 setLibcallName(RTLIB::SINTTOFP_I32_F64, "__aeabi_i2d"); setLibcallName(RTLIB::UINTTOFP_I32_F64, "__aeabi_ui2d"); setLibcallName(RTLIB::SINTTOFP_I64_F64, "__aeabi_l2d"); setLibcallName(RTLIB::UINTTOFP_I64_F64, "__aeabi_ul2d"); setLibcallName(RTLIB::SINTTOFP_I32_F32, "__aeabi_i2f"); setLibcallName(RTLIB::UINTTOFP_I32_F32, "__aeabi_ui2f"); setLibcallName(RTLIB::SINTTOFP_I64_F32, "__aeabi_l2f"); setLibcallName(RTLIB::UINTTOFP_I64_F32, "__aeabi_ul2f"); setLibcallCallingConv(RTLIB::SINTTOFP_I32_F64, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::UINTTOFP_I32_F64, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::SINTTOFP_I64_F64, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::UINTTOFP_I64_F64, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::SINTTOFP_I32_F32, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::UINTTOFP_I32_F32, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::SINTTOFP_I64_F32, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::UINTTOFP_I64_F32, CallingConv::ARM_AAPCS); // Long long helper functions // RTABI chapter 4.2, Table 9 setLibcallName(RTLIB::MUL_I64, "__aeabi_lmul"); setLibcallName(RTLIB::SDIV_I64, "__aeabi_ldivmod"); setLibcallName(RTLIB::UDIV_I64, "__aeabi_uldivmod"); setLibcallName(RTLIB::SHL_I64, "__aeabi_llsl"); setLibcallName(RTLIB::SRL_I64, "__aeabi_llsr"); setLibcallName(RTLIB::SRA_I64, "__aeabi_lasr"); setLibcallCallingConv(RTLIB::MUL_I64, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::SDIV_I64, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::UDIV_I64, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::SHL_I64, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::SRL_I64, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::SRA_I64, CallingConv::ARM_AAPCS); // Integer division functions // RTABI chapter 4.3.1 setLibcallName(RTLIB::SDIV_I8, "__aeabi_idiv"); setLibcallName(RTLIB::SDIV_I16, "__aeabi_idiv"); setLibcallName(RTLIB::SDIV_I32, "__aeabi_idiv"); setLibcallName(RTLIB::UDIV_I8, "__aeabi_uidiv"); setLibcallName(RTLIB::UDIV_I16, "__aeabi_uidiv"); setLibcallName(RTLIB::UDIV_I32, "__aeabi_uidiv"); setLibcallCallingConv(RTLIB::SDIV_I8, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::SDIV_I16, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::SDIV_I32, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::UDIV_I8, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::UDIV_I16, CallingConv::ARM_AAPCS); setLibcallCallingConv(RTLIB::UDIV_I32, CallingConv::ARM_AAPCS); // Memory operations // RTABI chapter 4.3.4 setLibcallName(RTLIB::MEMCPY, "__aeabi_memcpy"); setLibcallName(RTLIB::MEMMOVE, "__aeabi_memmove"); setLibcallName(RTLIB::MEMSET, "__aeabi_memset"); } // Use divmod compiler-rt calls for iOS 5.0 and later. if (Subtarget->getTargetTriple().getOS() == Triple::IOS && !Subtarget->getTargetTriple().isOSVersionLT(5, 0)) { setLibcallName(RTLIB::SDIVREM_I32, "__divmodsi4"); setLibcallName(RTLIB::UDIVREM_I32, "__udivmodsi4"); } if (Subtarget->isThumb1Only()) addRegisterClass(MVT::i32, ARM::tGPRRegisterClass); else addRegisterClass(MVT::i32, ARM::GPRRegisterClass); if (!UseSoftFloat && Subtarget->hasVFP2() && !Subtarget->isThumb1Only()) { addRegisterClass(MVT::f32, ARM::SPRRegisterClass); if (!Subtarget->isFPOnlySP()) addRegisterClass(MVT::f64, ARM::DPRRegisterClass); setTruncStoreAction(MVT::f64, MVT::f32, Expand); } if (Subtarget->hasNEON()) { addDRTypeForNEON(MVT::v2f32); addDRTypeForNEON(MVT::v8i8); addDRTypeForNEON(MVT::v4i16); addDRTypeForNEON(MVT::v2i32); addDRTypeForNEON(MVT::v1i64); addQRTypeForNEON(MVT::v4f32); addQRTypeForNEON(MVT::v2f64); addQRTypeForNEON(MVT::v16i8); addQRTypeForNEON(MVT::v8i16); addQRTypeForNEON(MVT::v4i32); addQRTypeForNEON(MVT::v2i64); // v2f64 is legal so that QR subregs can be extracted as f64 elements, but // neither Neon nor VFP support any arithmetic operations on it. setOperationAction(ISD::FADD, MVT::v2f64, Expand); setOperationAction(ISD::FSUB, MVT::v2f64, Expand); setOperationAction(ISD::FMUL, MVT::v2f64, Expand); setOperationAction(ISD::FDIV, MVT::v2f64, Expand); setOperationAction(ISD::FREM, MVT::v2f64, Expand); setOperationAction(ISD::FCOPYSIGN, MVT::v2f64, Expand); setOperationAction(ISD::SETCC, MVT::v2f64, Expand); setOperationAction(ISD::FNEG, MVT::v2f64, Expand); setOperationAction(ISD::FABS, MVT::v2f64, Expand); setOperationAction(ISD::FSQRT, MVT::v2f64, Expand); setOperationAction(ISD::FSIN, MVT::v2f64, Expand); setOperationAction(ISD::FCOS, MVT::v2f64, Expand); setOperationAction(ISD::FPOWI, MVT::v2f64, Expand); setOperationAction(ISD::FPOW, MVT::v2f64, Expand); setOperationAction(ISD::FLOG, MVT::v2f64, Expand); setOperationAction(ISD::FLOG2, MVT::v2f64, Expand); setOperationAction(ISD::FLOG10, MVT::v2f64, Expand); setOperationAction(ISD::FEXP, MVT::v2f64, Expand); setOperationAction(ISD::FEXP2, MVT::v2f64, Expand); setOperationAction(ISD::FCEIL, MVT::v2f64, Expand); setOperationAction(ISD::FTRUNC, MVT::v2f64, Expand); setOperationAction(ISD::FRINT, MVT::v2f64, Expand); setOperationAction(ISD::FNEARBYINT, MVT::v2f64, Expand); setOperationAction(ISD::FFLOOR, MVT::v2f64, Expand); setTruncStoreAction(MVT::v2f64, MVT::v2f32, Expand); // Neon does not support some operations on v1i64 and v2i64 types. setOperationAction(ISD::MUL, MVT::v1i64, Expand); // Custom handling for some quad-vector types to detect VMULL. setOperationAction(ISD::MUL, MVT::v8i16, Custom); setOperationAction(ISD::MUL, MVT::v4i32, Custom); setOperationAction(ISD::MUL, MVT::v2i64, Custom); // Custom handling for some vector types to avoid expensive expansions setOperationAction(ISD::SDIV, MVT::v4i16, Custom); setOperationAction(ISD::SDIV, MVT::v8i8, Custom); setOperationAction(ISD::UDIV, MVT::v4i16, Custom); setOperationAction(ISD::UDIV, MVT::v8i8, Custom); setOperationAction(ISD::SETCC, MVT::v1i64, Expand); setOperationAction(ISD::SETCC, MVT::v2i64, Expand); // Neon does not have single instruction SINT_TO_FP and UINT_TO_FP with // a destination type that is wider than the source. setOperationAction(ISD::SINT_TO_FP, MVT::v4i16, Custom); setOperationAction(ISD::UINT_TO_FP, MVT::v4i16, Custom); setTargetDAGCombine(ISD::INTRINSIC_VOID); setTargetDAGCombine(ISD::INTRINSIC_W_CHAIN); setTargetDAGCombine(ISD::INTRINSIC_WO_CHAIN); setTargetDAGCombine(ISD::SHL); setTargetDAGCombine(ISD::SRL); setTargetDAGCombine(ISD::SRA); setTargetDAGCombine(ISD::SIGN_EXTEND); setTargetDAGCombine(ISD::ZERO_EXTEND); setTargetDAGCombine(ISD::ANY_EXTEND); setTargetDAGCombine(ISD::SELECT_CC); setTargetDAGCombine(ISD::BUILD_VECTOR); setTargetDAGCombine(ISD::VECTOR_SHUFFLE); setTargetDAGCombine(ISD::INSERT_VECTOR_ELT); setTargetDAGCombine(ISD::STORE); setTargetDAGCombine(ISD::FP_TO_SINT); setTargetDAGCombine(ISD::FP_TO_UINT); setTargetDAGCombine(ISD::FDIV); } computeRegisterProperties(); // ARM does not have f32 extending load. setLoadExtAction(ISD::EXTLOAD, MVT::f32, Expand); // ARM does not have i1 sign extending load. setLoadExtAction(ISD::SEXTLOAD, MVT::i1, Promote); // ARM supports all 4 flavors of integer indexed load / store. if (!Subtarget->isThumb1Only()) { for (unsigned im = (unsigned)ISD::PRE_INC; im != (unsigned)ISD::LAST_INDEXED_MODE; ++im) { setIndexedLoadAction(im, MVT::i1, Legal); setIndexedLoadAction(im, MVT::i8, Legal); setIndexedLoadAction(im, MVT::i16, Legal); setIndexedLoadAction(im, MVT::i32, Legal); setIndexedStoreAction(im, MVT::i1, Legal); setIndexedStoreAction(im, MVT::i8, Legal); setIndexedStoreAction(im, MVT::i16, Legal); setIndexedStoreAction(im, MVT::i32, Legal); } } // i64 operation support. setOperationAction(ISD::MUL, MVT::i64, Expand); setOperationAction(ISD::MULHU, MVT::i32, Expand); if (Subtarget->isThumb1Only()) { setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand); setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand); } if (Subtarget->isThumb1Only() || !Subtarget->hasV6Ops() || (Subtarget->isThumb2() && !Subtarget->hasThumb2DSP())) setOperationAction(ISD::MULHS, MVT::i32, Expand); setOperationAction(ISD::SHL_PARTS, MVT::i32, Custom); setOperationAction(ISD::SRA_PARTS, MVT::i32, Custom); setOperationAction(ISD::SRL_PARTS, MVT::i32, Custom); setOperationAction(ISD::SRL, MVT::i64, Custom); setOperationAction(ISD::SRA, MVT::i64, Custom); if (!Subtarget->isThumb1Only()) { // FIXME: We should do this for Thumb1 as well. setOperationAction(ISD::ADDC, MVT::i32, Custom); setOperationAction(ISD::ADDE, MVT::i32, Custom); setOperationAction(ISD::SUBC, MVT::i32, Custom); setOperationAction(ISD::SUBE, MVT::i32, Custom); } // ARM does not have ROTL. setOperationAction(ISD::ROTL, MVT::i32, Expand); setOperationAction(ISD::CTTZ, MVT::i32, Custom); setOperationAction(ISD::CTPOP, MVT::i32, Expand); if (!Subtarget->hasV5TOps() || Subtarget->isThumb1Only()) setOperationAction(ISD::CTLZ, MVT::i32, Expand); // Only ARMv6 has BSWAP. if (!Subtarget->hasV6Ops()) setOperationAction(ISD::BSWAP, MVT::i32, Expand); // These are expanded into libcalls. if (!Subtarget->hasDivide() || !Subtarget->isThumb2()) { // v7M has a hardware divider setOperationAction(ISD::SDIV, MVT::i32, Expand); setOperationAction(ISD::UDIV, MVT::i32, Expand); } setOperationAction(ISD::SREM, MVT::i32, Expand); setOperationAction(ISD::UREM, MVT::i32, Expand); setOperationAction(ISD::SDIVREM, MVT::i32, Expand); setOperationAction(ISD::UDIVREM, MVT::i32, Expand); setOperationAction(ISD::GlobalAddress, MVT::i32, Custom); setOperationAction(ISD::ConstantPool, MVT::i32, Custom); setOperationAction(ISD::GLOBAL_OFFSET_TABLE, MVT::i32, Custom); setOperationAction(ISD::GlobalTLSAddress, MVT::i32, Custom); setOperationAction(ISD::BlockAddress, MVT::i32, Custom); setOperationAction(ISD::TRAP, MVT::Other, Legal); // Use the default implementation. setOperationAction(ISD::VASTART, MVT::Other, Custom); setOperationAction(ISD::VAARG, MVT::Other, Expand); setOperationAction(ISD::VACOPY, MVT::Other, Expand); setOperationAction(ISD::VAEND, MVT::Other, Expand); setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); setOperationAction(ISD::EHSELECTION, MVT::i32, Expand); setOperationAction(ISD::EXCEPTIONADDR, MVT::i32, Expand); setExceptionPointerRegister(ARM::R0); setExceptionSelectorRegister(ARM::R1); setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Expand); // ARMv6 Thumb1 (except for CPUs that support dmb / dsb) and earlier use // the default expansion. // FIXME: This should be checking for v6k, not just v6. if (Subtarget->hasDataBarrier() || (Subtarget->hasV6Ops() && !Subtarget->isThumb())) { // membarrier needs custom lowering; the rest are legal and handled // normally. setOperationAction(ISD::MEMBARRIER, MVT::Other, Custom); setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Custom); // Custom lowering for 64-bit ops setOperationAction(ISD::ATOMIC_LOAD_ADD, MVT::i64, Custom); setOperationAction(ISD::ATOMIC_LOAD_SUB, MVT::i64, Custom); setOperationAction(ISD::ATOMIC_LOAD_AND, MVT::i64, Custom); setOperationAction(ISD::ATOMIC_LOAD_OR, MVT::i64, Custom); setOperationAction(ISD::ATOMIC_LOAD_XOR, MVT::i64, Custom); setOperationAction(ISD::ATOMIC_SWAP, MVT::i64, Custom); setOperationAction(ISD::ATOMIC_CMP_SWAP, MVT::i64, Custom); // Automatically insert fences (dmb ist) around ATOMIC_SWAP etc. setInsertFencesForAtomic(true); } else { // Set them all for expansion, which will force libcalls. setOperationAction(ISD::MEMBARRIER, MVT::Other, Expand); setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Expand); setOperationAction(ISD::ATOMIC_CMP_SWAP, MVT::i32, Expand); setOperationAction(ISD::ATOMIC_SWAP, MVT::i32, Expand); setOperationAction(ISD::ATOMIC_LOAD_ADD, MVT::i32, Expand); setOperationAction(ISD::ATOMIC_LOAD_SUB, MVT::i32, Expand); setOperationAction(ISD::ATOMIC_LOAD_AND, MVT::i32, Expand); setOperationAction(ISD::ATOMIC_LOAD_OR, MVT::i32, Expand); setOperationAction(ISD::ATOMIC_LOAD_XOR, MVT::i32, Expand); setOperationAction(ISD::ATOMIC_LOAD_NAND, MVT::i32, Expand); setOperationAction(ISD::ATOMIC_LOAD_MIN, MVT::i32, Expand); setOperationAction(ISD::ATOMIC_LOAD_MAX, MVT::i32, Expand); setOperationAction(ISD::ATOMIC_LOAD_UMIN, MVT::i32, Expand); setOperationAction(ISD::ATOMIC_LOAD_UMAX, MVT::i32, Expand); // Mark ATOMIC_LOAD and ATOMIC_STORE custom so we can handle the // Unordered/Monotonic case. setOperationAction(ISD::ATOMIC_LOAD, MVT::i32, Custom); setOperationAction(ISD::ATOMIC_STORE, MVT::i32, Custom); // Since the libcalls include locking, fold in the fences setShouldFoldAtomicFences(true); } setOperationAction(ISD::PREFETCH, MVT::Other, Custom); // Requires SXTB/SXTH, available on v6 and up in both ARM and Thumb modes. if (!Subtarget->hasV6Ops()) { setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand); setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8, Expand); } setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); if (!UseSoftFloat && Subtarget->hasVFP2() && !Subtarget->isThumb1Only()) { // Turn f64->i64 into VMOVRRD, i64 -> f64 to VMOVDRR // iff target supports vfp2. setOperationAction(ISD::BITCAST, MVT::i64, Custom); setOperationAction(ISD::FLT_ROUNDS_, MVT::i32, Custom); } // We want to custom lower some of our intrinsics. setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom); if (Subtarget->isTargetDarwin()) { setOperationAction(ISD::EH_SJLJ_SETJMP, MVT::i32, Custom); setOperationAction(ISD::EH_SJLJ_LONGJMP, MVT::Other, Custom); setOperationAction(ISD::EH_SJLJ_DISPATCHSETUP, MVT::Other, Custom); setLibcallName(RTLIB::UNWIND_RESUME, "_Unwind_SjLj_Resume"); } setOperationAction(ISD::SETCC, MVT::i32, Expand); setOperationAction(ISD::SETCC, MVT::f32, Expand); setOperationAction(ISD::SETCC, MVT::f64, Expand); setOperationAction(ISD::SELECT, MVT::i32, Custom); setOperationAction(ISD::SELECT, MVT::f32, Custom); setOperationAction(ISD::SELECT, MVT::f64, Custom); setOperationAction(ISD::SELECT_CC, MVT::i32, Custom); setOperationAction(ISD::SELECT_CC, MVT::f32, Custom); setOperationAction(ISD::SELECT_CC, MVT::f64, Custom); setOperationAction(ISD::BRCOND, MVT::Other, Expand); setOperationAction(ISD::BR_CC, MVT::i32, Custom); setOperationAction(ISD::BR_CC, MVT::f32, Custom); setOperationAction(ISD::BR_CC, MVT::f64, Custom); setOperationAction(ISD::BR_JT, MVT::Other, Custom); // We don't support sin/cos/fmod/copysign/pow setOperationAction(ISD::FSIN, MVT::f64, Expand); setOperationAction(ISD::FSIN, MVT::f32, Expand); setOperationAction(ISD::FCOS, MVT::f32, Expand); setOperationAction(ISD::FCOS, MVT::f64, Expand); setOperationAction(ISD::FREM, MVT::f64, Expand); setOperationAction(ISD::FREM, MVT::f32, Expand); if (!UseSoftFloat && Subtarget->hasVFP2() && !Subtarget->isThumb1Only()) { setOperationAction(ISD::FCOPYSIGN, MVT::f64, Custom); setOperationAction(ISD::FCOPYSIGN, MVT::f32, Custom); } setOperationAction(ISD::FPOW, MVT::f64, Expand); setOperationAction(ISD::FPOW, MVT::f32, Expand); setOperationAction(ISD::FMA, MVT::f64, Expand); setOperationAction(ISD::FMA, MVT::f32, Expand); // Various VFP goodness if (!UseSoftFloat && !Subtarget->isThumb1Only()) { // int <-> fp are custom expanded into bit_convert + ARMISD ops. if (Subtarget->hasVFP2()) { setOperationAction(ISD::SINT_TO_FP, MVT::i32, Custom); setOperationAction(ISD::UINT_TO_FP, MVT::i32, Custom); setOperationAction(ISD::FP_TO_UINT, MVT::i32, Custom); setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom); } // Special handling for half-precision FP. if (!Subtarget->hasFP16()) { setOperationAction(ISD::FP16_TO_FP32, MVT::f32, Expand); setOperationAction(ISD::FP32_TO_FP16, MVT::i32, Expand); } } // We have target-specific dag combine patterns for the following nodes: // ARMISD::VMOVRRD - No need to call setTargetDAGCombine setTargetDAGCombine(ISD::ADD); setTargetDAGCombine(ISD::SUB); setTargetDAGCombine(ISD::MUL); if (Subtarget->hasV6T2Ops() || Subtarget->hasNEON()) setTargetDAGCombine(ISD::OR); if (Subtarget->hasNEON()) setTargetDAGCombine(ISD::AND); setStackPointerRegisterToSaveRestore(ARM::SP); if (UseSoftFloat || Subtarget->isThumb1Only() || !Subtarget->hasVFP2()) setSchedulingPreference(Sched::RegPressure); else setSchedulingPreference(Sched::Hybrid); //// temporary - rewrite interface to use type maxStoresPerMemcpy = maxStoresPerMemcpyOptSize = 1; // On ARM arguments smaller than 4 bytes are extended, so all arguments // are at least 4 bytes aligned. setMinStackArgumentAlignment(4); benefitFromCodePlacementOpt = true; setMinFunctionAlignment(Subtarget->isThumb() ? 1 : 2); } // FIXME: It might make sense to define the representative register class as the // nearest super-register that has a non-null superset. For example, DPR_VFP2 is // a super-register of SPR, and DPR is a superset if DPR_VFP2. Consequently, // SPR's representative would be DPR_VFP2. This should work well if register // pressure tracking were modified such that a register use would increment the // pressure of the register class's representative and all of it's super // classes' representatives transitively. We have not implemented this because // of the difficulty prior to coalescing of modeling operand register classes // due to the common occurrence of cross class copies and subregister insertions // and extractions. std::pair ARMTargetLowering::findRepresentativeClass(EVT VT) const{ const TargetRegisterClass *RRC = 0; uint8_t Cost = 1; switch (VT.getSimpleVT().SimpleTy) { default: return TargetLowering::findRepresentativeClass(VT); // Use DPR as representative register class for all floating point // and vector types. Since there are 32 SPR registers and 32 DPR registers so // the cost is 1 for both f32 and f64. case MVT::f32: case MVT::f64: case MVT::v8i8: case MVT::v4i16: case MVT::v2i32: case MVT::v1i64: case MVT::v2f32: RRC = ARM::DPRRegisterClass; // When NEON is used for SP, only half of the register file is available // because operations that define both SP and DP results will be constrained // to the VFP2 class (D0-D15). We currently model this constraint prior to // coalescing by double-counting the SP regs. See the FIXME above. if (Subtarget->useNEONForSinglePrecisionFP()) Cost = 2; break; case MVT::v16i8: case MVT::v8i16: case MVT::v4i32: case MVT::v2i64: case MVT::v4f32: case MVT::v2f64: RRC = ARM::DPRRegisterClass; Cost = 2; break; case MVT::v4i64: RRC = ARM::DPRRegisterClass; Cost = 4; break; case MVT::v8i64: RRC = ARM::DPRRegisterClass; Cost = 8; break; } return std::make_pair(RRC, Cost); } const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const { switch (Opcode) { default: return 0; case ARMISD::Wrapper: return "ARMISD::Wrapper"; case ARMISD::WrapperDYN: return "ARMISD::WrapperDYN"; case ARMISD::WrapperPIC: return "ARMISD::WrapperPIC"; case ARMISD::WrapperJT: return "ARMISD::WrapperJT"; case ARMISD::CALL: return "ARMISD::CALL"; case ARMISD::CALL_PRED: return "ARMISD::CALL_PRED"; case ARMISD::CALL_NOLINK: return "ARMISD::CALL_NOLINK"; case ARMISD::tCALL: return "ARMISD::tCALL"; case ARMISD::BRCOND: return "ARMISD::BRCOND"; case ARMISD::BR_JT: return "ARMISD::BR_JT"; case ARMISD::BR2_JT: return "ARMISD::BR2_JT"; case ARMISD::RET_FLAG: return "ARMISD::RET_FLAG"; case ARMISD::PIC_ADD: return "ARMISD::PIC_ADD"; case ARMISD::CMP: return "ARMISD::CMP"; case ARMISD::CMPZ: return "ARMISD::CMPZ"; case ARMISD::CMPFP: return "ARMISD::CMPFP"; case ARMISD::CMPFPw0: return "ARMISD::CMPFPw0"; case ARMISD::BCC_i64: return "ARMISD::BCC_i64"; case ARMISD::FMSTAT: return "ARMISD::FMSTAT"; case ARMISD::CMOV: return "ARMISD::CMOV"; case ARMISD::RBIT: return "ARMISD::RBIT"; case ARMISD::FTOSI: return "ARMISD::FTOSI"; case ARMISD::FTOUI: return "ARMISD::FTOUI"; case ARMISD::SITOF: return "ARMISD::SITOF"; case ARMISD::UITOF: return "ARMISD::UITOF"; case ARMISD::SRL_FLAG: return "ARMISD::SRL_FLAG"; case ARMISD::SRA_FLAG: return "ARMISD::SRA_FLAG"; case ARMISD::RRX: return "ARMISD::RRX"; case ARMISD::ADDC: return "ARMISD::ADDC"; case ARMISD::ADDE: return "ARMISD::ADDE"; case ARMISD::SUBC: return "ARMISD::SUBC"; case ARMISD::SUBE: return "ARMISD::SUBE"; case ARMISD::VMOVRRD: return "ARMISD::VMOVRRD"; case ARMISD::VMOVDRR: return "ARMISD::VMOVDRR"; case ARMISD::EH_SJLJ_SETJMP: return "ARMISD::EH_SJLJ_SETJMP"; case ARMISD::EH_SJLJ_LONGJMP:return "ARMISD::EH_SJLJ_LONGJMP"; case ARMISD::EH_SJLJ_DISPATCHSETUP:return "ARMISD::EH_SJLJ_DISPATCHSETUP"; case ARMISD::TC_RETURN: return "ARMISD::TC_RETURN"; case ARMISD::THREAD_POINTER:return "ARMISD::THREAD_POINTER"; case ARMISD::DYN_ALLOC: return "ARMISD::DYN_ALLOC"; case ARMISD::MEMBARRIER: return "ARMISD::MEMBARRIER"; case ARMISD::MEMBARRIER_MCR: return "ARMISD::MEMBARRIER_MCR"; case ARMISD::PRELOAD: return "ARMISD::PRELOAD"; case ARMISD::VCEQ: return "ARMISD::VCEQ"; case ARMISD::VCEQZ: return "ARMISD::VCEQZ"; case ARMISD::VCGE: return "ARMISD::VCGE"; case ARMISD::VCGEZ: return "ARMISD::VCGEZ"; case ARMISD::VCLEZ: return "ARMISD::VCLEZ"; case ARMISD::VCGEU: return "ARMISD::VCGEU"; case ARMISD::VCGT: return "ARMISD::VCGT"; case ARMISD::VCGTZ: return "ARMISD::VCGTZ"; case ARMISD::VCLTZ: return "ARMISD::VCLTZ"; case ARMISD::VCGTU: return "ARMISD::VCGTU"; case ARMISD::VTST: return "ARMISD::VTST"; case ARMISD::VSHL: return "ARMISD::VSHL"; case ARMISD::VSHRs: return "ARMISD::VSHRs"; case ARMISD::VSHRu: return "ARMISD::VSHRu"; case ARMISD::VSHLLs: return "ARMISD::VSHLLs"; case ARMISD::VSHLLu: return "ARMISD::VSHLLu"; case ARMISD::VSHLLi: return "ARMISD::VSHLLi"; case ARMISD::VSHRN: return "ARMISD::VSHRN"; case ARMISD::VRSHRs: return "ARMISD::VRSHRs"; case ARMISD::VRSHRu: return "ARMISD::VRSHRu"; case ARMISD::VRSHRN: return "ARMISD::VRSHRN"; case ARMISD::VQSHLs: return "ARMISD::VQSHLs"; case ARMISD::VQSHLu: return "ARMISD::VQSHLu"; case ARMISD::VQSHLsu: return "ARMISD::VQSHLsu"; case ARMISD::VQSHRNs: return "ARMISD::VQSHRNs"; case ARMISD::VQSHRNu: return "ARMISD::VQSHRNu"; case ARMISD::VQSHRNsu: return "ARMISD::VQSHRNsu"; case ARMISD::VQRSHRNs: return "ARMISD::VQRSHRNs"; case ARMISD::VQRSHRNu: return "ARMISD::VQRSHRNu"; case ARMISD::VQRSHRNsu: return "ARMISD::VQRSHRNsu"; case ARMISD::VGETLANEu: return "ARMISD::VGETLANEu"; case ARMISD::VGETLANEs: return "ARMISD::VGETLANEs"; case ARMISD::VMOVIMM: return "ARMISD::VMOVIMM"; case ARMISD::VMVNIMM: return "ARMISD::VMVNIMM"; case ARMISD::VDUP: return "ARMISD::VDUP"; case ARMISD::VDUPLANE: return "ARMISD::VDUPLANE"; case ARMISD::VEXT: return "ARMISD::VEXT"; case ARMISD::VREV64: return "ARMISD::VREV64"; case ARMISD::VREV32: return "ARMISD::VREV32"; case ARMISD::VREV16: return "ARMISD::VREV16"; case ARMISD::VZIP: return "ARMISD::VZIP"; case ARMISD::VUZP: return "ARMISD::VUZP"; case ARMISD::VTRN: return "ARMISD::VTRN"; case ARMISD::VTBL1: return "ARMISD::VTBL1"; case ARMISD::VTBL2: return "ARMISD::VTBL2"; case ARMISD::VMULLs: return "ARMISD::VMULLs"; case ARMISD::VMULLu: return "ARMISD::VMULLu"; case ARMISD::BUILD_VECTOR: return "ARMISD::BUILD_VECTOR"; case ARMISD::FMAX: return "ARMISD::FMAX"; case ARMISD::FMIN: return "ARMISD::FMIN"; case ARMISD::BFI: return "ARMISD::BFI"; case ARMISD::VORRIMM: return "ARMISD::VORRIMM"; case ARMISD::VBICIMM: return "ARMISD::VBICIMM"; case ARMISD::VBSL: return "ARMISD::VBSL"; case ARMISD::VLD2DUP: return "ARMISD::VLD2DUP"; case ARMISD::VLD3DUP: return "ARMISD::VLD3DUP"; case ARMISD::VLD4DUP: return "ARMISD::VLD4DUP"; case ARMISD::VLD1_UPD: return "ARMISD::VLD1_UPD"; case ARMISD::VLD2_UPD: return "ARMISD::VLD2_UPD"; case ARMISD::VLD3_UPD: return "ARMISD::VLD3_UPD"; case ARMISD::VLD4_UPD: return "ARMISD::VLD4_UPD"; case ARMISD::VLD2LN_UPD: return "ARMISD::VLD2LN_UPD"; case ARMISD::VLD3LN_UPD: return "ARMISD::VLD3LN_UPD"; case ARMISD::VLD4LN_UPD: return "ARMISD::VLD4LN_UPD"; case ARMISD::VLD2DUP_UPD: return "ARMISD::VLD2DUP_UPD"; case ARMISD::VLD3DUP_UPD: return "ARMISD::VLD3DUP_UPD"; case ARMISD::VLD4DUP_UPD: return "ARMISD::VLD4DUP_UPD"; case ARMISD::VST1_UPD: return "ARMISD::VST1_UPD"; case ARMISD::VST2_UPD: return "ARMISD::VST2_UPD"; case ARMISD::VST3_UPD: return "ARMISD::VST3_UPD"; case ARMISD::VST4_UPD: return "ARMISD::VST4_UPD"; case ARMISD::VST2LN_UPD: return "ARMISD::VST2LN_UPD"; case ARMISD::VST3LN_UPD: return "ARMISD::VST3LN_UPD"; case ARMISD::VST4LN_UPD: return "ARMISD::VST4LN_UPD"; } } EVT ARMTargetLowering::getSetCCResultType(EVT VT) const { if (!VT.isVector()) return getPointerTy(); return VT.changeVectorElementTypeToInteger(); } /// getRegClassFor - Return the register class that should be used for the /// specified value type. TargetRegisterClass *ARMTargetLowering::getRegClassFor(EVT VT) const { // Map v4i64 to QQ registers but do not make the type legal. Similarly map // v8i64 to QQQQ registers. v4i64 and v8i64 are only used for REG_SEQUENCE to // load / store 4 to 8 consecutive D registers. if (Subtarget->hasNEON()) { if (VT == MVT::v4i64) return ARM::QQPRRegisterClass; else if (VT == MVT::v8i64) return ARM::QQQQPRRegisterClass; } return TargetLowering::getRegClassFor(VT); } // Create a fast isel object. FastISel * ARMTargetLowering::createFastISel(FunctionLoweringInfo &funcInfo) const { return ARM::createFastISel(funcInfo); } /// getMaximalGlobalOffset - Returns the maximal possible offset which can /// be used for loads / stores from the global. unsigned ARMTargetLowering::getMaximalGlobalOffset() const { return (Subtarget->isThumb1Only() ? 127 : 4095); } Sched::Preference ARMTargetLowering::getSchedulingPreference(SDNode *N) const { unsigned NumVals = N->getNumValues(); if (!NumVals) return Sched::RegPressure; for (unsigned i = 0; i != NumVals; ++i) { EVT VT = N->getValueType(i); if (VT == MVT::Glue || VT == MVT::Other) continue; if (VT.isFloatingPoint() || VT.isVector()) return Sched::Latency; } if (!N->isMachineOpcode()) return Sched::RegPressure; // Load are scheduled for latency even if there instruction itinerary // is not available. const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); const MCInstrDesc &MCID = TII->get(N->getMachineOpcode()); if (MCID.getNumDefs() == 0) return Sched::RegPressure; if (!Itins->isEmpty() && Itins->getOperandCycle(MCID.getSchedClass(), 0) > 2) return Sched::Latency; return Sched::RegPressure; } //===----------------------------------------------------------------------===// // Lowering Code //===----------------------------------------------------------------------===// /// IntCCToARMCC - Convert a DAG integer condition code to an ARM CC static ARMCC::CondCodes IntCCToARMCC(ISD::CondCode CC) { switch (CC) { default: llvm_unreachable("Unknown condition code!"); case ISD::SETNE: return ARMCC::NE; case ISD::SETEQ: return ARMCC::EQ; case ISD::SETGT: return ARMCC::GT; case ISD::SETGE: return ARMCC::GE; case ISD::SETLT: return ARMCC::LT; case ISD::SETLE: return ARMCC::LE; case ISD::SETUGT: return ARMCC::HI; case ISD::SETUGE: return ARMCC::HS; case ISD::SETULT: return ARMCC::LO; case ISD::SETULE: return ARMCC::LS; } } /// FPCCToARMCC - Convert a DAG fp condition code to an ARM CC. static void FPCCToARMCC(ISD::CondCode CC, ARMCC::CondCodes &CondCode, ARMCC::CondCodes &CondCode2) { CondCode2 = ARMCC::AL; switch (CC) { default: llvm_unreachable("Unknown FP condition!"); case ISD::SETEQ: case ISD::SETOEQ: CondCode = ARMCC::EQ; break; case ISD::SETGT: case ISD::SETOGT: CondCode = ARMCC::GT; break; case ISD::SETGE: case ISD::SETOGE: CondCode = ARMCC::GE; break; case ISD::SETOLT: CondCode = ARMCC::MI; break; case ISD::SETOLE: CondCode = ARMCC::LS; break; case ISD::SETONE: CondCode = ARMCC::MI; CondCode2 = ARMCC::GT; break; case ISD::SETO: CondCode = ARMCC::VC; break; case ISD::SETUO: CondCode = ARMCC::VS; break; case ISD::SETUEQ: CondCode = ARMCC::EQ; CondCode2 = ARMCC::VS; break; case ISD::SETUGT: CondCode = ARMCC::HI; break; case ISD::SETUGE: CondCode = ARMCC::PL; break; case ISD::SETLT: case ISD::SETULT: CondCode = ARMCC::LT; break; case ISD::SETLE: case ISD::SETULE: CondCode = ARMCC::LE; break; case ISD::SETNE: case ISD::SETUNE: CondCode = ARMCC::NE; break; } } //===----------------------------------------------------------------------===// // Calling Convention Implementation //===----------------------------------------------------------------------===// #include "ARMGenCallingConv.inc" /// CCAssignFnForNode - Selects the correct CCAssignFn for a the /// given CallingConvention value. CCAssignFn *ARMTargetLowering::CCAssignFnForNode(CallingConv::ID CC, bool Return, bool isVarArg) const { switch (CC) { default: llvm_unreachable("Unsupported calling convention"); case CallingConv::Fast: if (Subtarget->hasVFP2() && !isVarArg) { if (!Subtarget->isAAPCS_ABI()) return (Return ? RetFastCC_ARM_APCS : FastCC_ARM_APCS); // For AAPCS ABI targets, just use VFP variant of the calling convention. return (Return ? RetCC_ARM_AAPCS_VFP : CC_ARM_AAPCS_VFP); } // Fallthrough case CallingConv::C: { // Use target triple & subtarget features to do actual dispatch. if (!Subtarget->isAAPCS_ABI()) return (Return ? RetCC_ARM_APCS : CC_ARM_APCS); else if (Subtarget->hasVFP2() && FloatABIType == FloatABI::Hard && !isVarArg) return (Return ? RetCC_ARM_AAPCS_VFP : CC_ARM_AAPCS_VFP); return (Return ? RetCC_ARM_AAPCS : CC_ARM_AAPCS); } case CallingConv::ARM_AAPCS_VFP: return (Return ? RetCC_ARM_AAPCS_VFP : CC_ARM_AAPCS_VFP); case CallingConv::ARM_AAPCS: return (Return ? RetCC_ARM_AAPCS : CC_ARM_AAPCS); case CallingConv::ARM_APCS: return (Return ? RetCC_ARM_APCS : CC_ARM_APCS); + case CallingConv::GHC: + return (Return ? RetCC_ARM_APCS : CC_ARM_APCS_GHC); } } /// LowerCallResult - Lower the result values of a call into the /// appropriate copies out of appropriate physical registers. SDValue ARMTargetLowering::LowerCallResult(SDValue Chain, SDValue InFlag, CallingConv::ID CallConv, bool isVarArg, const SmallVectorImpl &Ins, DebugLoc dl, SelectionDAG &DAG, SmallVectorImpl &InVals) const { // Assign locations to each value returned by this call. SmallVector RVLocs; ARMCCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), getTargetMachine(), RVLocs, *DAG.getContext(), Call); CCInfo.AnalyzeCallResult(Ins, CCAssignFnForNode(CallConv, /* Return*/ true, isVarArg)); // Copy all of the result registers out of their specified physreg. for (unsigned i = 0; i != RVLocs.size(); ++i) { CCValAssign VA = RVLocs[i]; SDValue Val; if (VA.needsCustom()) { // Handle f64 or half of a v2f64. SDValue Lo = DAG.getCopyFromReg(Chain, dl, VA.getLocReg(), MVT::i32, InFlag); Chain = Lo.getValue(1); InFlag = Lo.getValue(2); VA = RVLocs[++i]; // skip ahead to next loc SDValue Hi = DAG.getCopyFromReg(Chain, dl, VA.getLocReg(), MVT::i32, InFlag); Chain = Hi.getValue(1); InFlag = Hi.getValue(2); Val = DAG.getNode(ARMISD::VMOVDRR, dl, MVT::f64, Lo, Hi); if (VA.getLocVT() == MVT::v2f64) { SDValue Vec = DAG.getNode(ISD::UNDEF, dl, MVT::v2f64); Vec = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, MVT::v2f64, Vec, Val, DAG.getConstant(0, MVT::i32)); VA = RVLocs[++i]; // skip ahead to next loc Lo = DAG.getCopyFromReg(Chain, dl, VA.getLocReg(), MVT::i32, InFlag); Chain = Lo.getValue(1); InFlag = Lo.getValue(2); VA = RVLocs[++i]; // skip ahead to next loc Hi = DAG.getCopyFromReg(Chain, dl, VA.getLocReg(), MVT::i32, InFlag); Chain = Hi.getValue(1); InFlag = Hi.getValue(2); Val = DAG.getNode(ARMISD::VMOVDRR, dl, MVT::f64, Lo, Hi); Val = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, MVT::v2f64, Vec, Val, DAG.getConstant(1, MVT::i32)); } } else { Val = DAG.getCopyFromReg(Chain, dl, VA.getLocReg(), VA.getLocVT(), InFlag); Chain = Val.getValue(1); InFlag = Val.getValue(2); } switch (VA.getLocInfo()) { default: llvm_unreachable("Unknown loc info!"); case CCValAssign::Full: break; case CCValAssign::BCvt: Val = DAG.getNode(ISD::BITCAST, dl, VA.getValVT(), Val); break; } InVals.push_back(Val); } return Chain; } /// LowerMemOpCallTo - Store the argument to the stack. SDValue ARMTargetLowering::LowerMemOpCallTo(SDValue Chain, SDValue StackPtr, SDValue Arg, DebugLoc dl, SelectionDAG &DAG, const CCValAssign &VA, ISD::ArgFlagsTy Flags) const { unsigned LocMemOffset = VA.getLocMemOffset(); SDValue PtrOff = DAG.getIntPtrConstant(LocMemOffset); PtrOff = DAG.getNode(ISD::ADD, dl, getPointerTy(), StackPtr, PtrOff); return DAG.getStore(Chain, dl, Arg, PtrOff, MachinePointerInfo::getStack(LocMemOffset), false, false, 0); } void ARMTargetLowering::PassF64ArgInRegs(DebugLoc dl, SelectionDAG &DAG, SDValue Chain, SDValue &Arg, RegsToPassVector &RegsToPass, CCValAssign &VA, CCValAssign &NextVA, SDValue &StackPtr, SmallVector &MemOpChains, ISD::ArgFlagsTy Flags) const { SDValue fmrrd = DAG.getNode(ARMISD::VMOVRRD, dl, DAG.getVTList(MVT::i32, MVT::i32), Arg); RegsToPass.push_back(std::make_pair(VA.getLocReg(), fmrrd)); if (NextVA.isRegLoc()) RegsToPass.push_back(std::make_pair(NextVA.getLocReg(), fmrrd.getValue(1))); else { assert(NextVA.isMemLoc()); if (StackPtr.getNode() == 0) StackPtr = DAG.getCopyFromReg(Chain, dl, ARM::SP, getPointerTy()); MemOpChains.push_back(LowerMemOpCallTo(Chain, StackPtr, fmrrd.getValue(1), dl, DAG, NextVA, Flags)); } } /// LowerCall - Lowering a call into a callseq_start <- /// ARMISD:CALL <- callseq_end chain. Also add input and output parameter /// nodes. SDValue ARMTargetLowering::LowerCall(SDValue Chain, SDValue Callee, CallingConv::ID CallConv, bool isVarArg, bool &isTailCall, const SmallVectorImpl &Outs, const SmallVectorImpl &OutVals, const SmallVectorImpl &Ins, DebugLoc dl, SelectionDAG &DAG, SmallVectorImpl &InVals) const { MachineFunction &MF = DAG.getMachineFunction(); bool IsStructRet = (Outs.empty()) ? false : Outs[0].Flags.isSRet(); bool IsSibCall = false; // Disable tail calls if they're not supported. if (!EnableARMTailCalls && !Subtarget->supportsTailCall()) isTailCall = false; if (isTailCall) { // Check if it's really possible to do a tail call. isTailCall = IsEligibleForTailCallOptimization(Callee, CallConv, isVarArg, IsStructRet, MF.getFunction()->hasStructRetAttr(), Outs, OutVals, Ins, DAG); // We don't support GuaranteedTailCallOpt for ARM, only automatically // detected sibcalls. if (isTailCall) { ++NumTailCalls; IsSibCall = true; } } // Analyze operands of the call, assigning locations to each operand. SmallVector ArgLocs; ARMCCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), getTargetMachine(), ArgLocs, *DAG.getContext(), Call); CCInfo.AnalyzeCallOperands(Outs, CCAssignFnForNode(CallConv, /* Return*/ false, isVarArg)); // Get a count of how many bytes are to be pushed on the stack. unsigned NumBytes = CCInfo.getNextStackOffset(); // For tail calls, memory operands are available in our caller's stack. if (IsSibCall) NumBytes = 0; // Adjust the stack pointer for the new arguments... // These operations are automatically eliminated by the prolog/epilog pass if (!IsSibCall) Chain = DAG.getCALLSEQ_START(Chain, DAG.getIntPtrConstant(NumBytes, true)); SDValue StackPtr = DAG.getCopyFromReg(Chain, dl, ARM::SP, getPointerTy()); RegsToPassVector RegsToPass; SmallVector MemOpChains; // Walk the register/memloc assignments, inserting copies/loads. In the case // of tail call optimization, arguments are handled later. for (unsigned i = 0, realArgIdx = 0, e = ArgLocs.size(); i != e; ++i, ++realArgIdx) { CCValAssign &VA = ArgLocs[i]; SDValue Arg = OutVals[realArgIdx]; ISD::ArgFlagsTy Flags = Outs[realArgIdx].Flags; bool isByVal = Flags.isByVal(); // Promote the value if needed. switch (VA.getLocInfo()) { default: llvm_unreachable("Unknown loc info!"); case CCValAssign::Full: break; case CCValAssign::SExt: Arg = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Arg); break; case CCValAssign::ZExt: Arg = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), Arg); break; case CCValAssign::AExt: Arg = DAG.getNode(ISD::ANY_EXTEND, dl, VA.getLocVT(), Arg); break; case CCValAssign::BCvt: Arg = DAG.getNode(ISD::BITCAST, dl, VA.getLocVT(), Arg); break; } // f64 and v2f64 might be passed in i32 pairs and must be split into pieces if (VA.needsCustom()) { if (VA.getLocVT() == MVT::v2f64) { SDValue Op0 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, MVT::f64, Arg, DAG.getConstant(0, MVT::i32)); SDValue Op1 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, MVT::f64, Arg, DAG.getConstant(1, MVT::i32)); PassF64ArgInRegs(dl, DAG, Chain, Op0, RegsToPass, VA, ArgLocs[++i], StackPtr, MemOpChains, Flags); VA = ArgLocs[++i]; // skip ahead to next loc if (VA.isRegLoc()) { PassF64ArgInRegs(dl, DAG, Chain, Op1, RegsToPass, VA, ArgLocs[++i], StackPtr, MemOpChains, Flags); } else { assert(VA.isMemLoc()); MemOpChains.push_back(LowerMemOpCallTo(Chain, StackPtr, Op1, dl, DAG, VA, Flags)); } } else { PassF64ArgInRegs(dl, DAG, Chain, Arg, RegsToPass, VA, ArgLocs[++i], StackPtr, MemOpChains, Flags); } } else if (VA.isRegLoc()) { RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg)); } else if (isByVal) { assert(VA.isMemLoc()); unsigned offset = 0; // True if this byval aggregate will be split between registers // and memory. if (CCInfo.isFirstByValRegValid()) { EVT PtrVT = DAG.getTargetLoweringInfo().getPointerTy(); unsigned int i, j; for (i = 0, j = CCInfo.getFirstByValReg(); j < ARM::R4; i++, j++) { SDValue Const = DAG.getConstant(4*i, MVT::i32); SDValue AddArg = DAG.getNode(ISD::ADD, dl, PtrVT, Arg, Const); SDValue Load = DAG.getLoad(PtrVT, dl, Chain, AddArg, MachinePointerInfo(), false, false, 0); MemOpChains.push_back(Load.getValue(1)); RegsToPass.push_back(std::make_pair(j, Load)); } offset = ARM::R4 - CCInfo.getFirstByValReg(); CCInfo.clearFirstByValReg(); } unsigned LocMemOffset = VA.getLocMemOffset(); SDValue StkPtrOff = DAG.getIntPtrConstant(LocMemOffset); SDValue Dst = DAG.getNode(ISD::ADD, dl, getPointerTy(), StackPtr, StkPtrOff); SDValue SrcOffset = DAG.getIntPtrConstant(4*offset); SDValue Src = DAG.getNode(ISD::ADD, dl, getPointerTy(), Arg, SrcOffset); SDValue SizeNode = DAG.getConstant(Flags.getByValSize() - 4*offset, MVT::i32); // TODO: Disable AlwaysInline when it becomes possible // to emit a nested call sequence. MemOpChains.push_back(DAG.getMemcpy(Chain, dl, Dst, Src, SizeNode, Flags.getByValAlign(), /*isVolatile=*/false, /*AlwaysInline=*/true, MachinePointerInfo(0), MachinePointerInfo(0))); } else if (!IsSibCall) { assert(VA.isMemLoc()); MemOpChains.push_back(LowerMemOpCallTo(Chain, StackPtr, Arg, dl, DAG, VA, Flags)); } } if (!MemOpChains.empty()) Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &MemOpChains[0], MemOpChains.size()); // Build a sequence of copy-to-reg nodes chained together with token chain // and flag operands which copy the outgoing args into the appropriate regs. SDValue InFlag; // Tail call byval lowering might overwrite argument registers so in case of // tail call optimization the copies to registers are lowered later. if (!isTailCall) for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) { Chain = DAG.getCopyToReg(Chain, dl, RegsToPass[i].first, RegsToPass[i].second, InFlag); InFlag = Chain.getValue(1); } // For tail calls lower the arguments to the 'real' stack slot. if (isTailCall) { // Force all the incoming stack arguments to be loaded from the stack // before any new outgoing arguments are stored to the stack, because the // outgoing stack slots may alias the incoming argument stack slots, and // the alias isn't otherwise explicit. This is slightly more conservative // than necessary, because it means that each store effectively depends // on every argument instead of just those arguments it would clobber. // Do not flag preceding copytoreg stuff together with the following stuff. InFlag = SDValue(); for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) { Chain = DAG.getCopyToReg(Chain, dl, RegsToPass[i].first, RegsToPass[i].second, InFlag); InFlag = Chain.getValue(1); } InFlag =SDValue(); } // If the callee is a GlobalAddress/ExternalSymbol node (quite common, every // direct call is) turn it into a TargetGlobalAddress/TargetExternalSymbol // node so that legalize doesn't hack it. bool isDirect = false; bool isARMFunc = false; bool isLocalARMFunc = false; ARMFunctionInfo *AFI = MF.getInfo(); if (EnableARMLongCalls) { assert (getTargetMachine().getRelocationModel() == Reloc::Static && "long-calls with non-static relocation model!"); // Handle a global address or an external symbol. If it's not one of // those, the target's already in a register, so we don't need to do // anything extra. if (GlobalAddressSDNode *G = dyn_cast(Callee)) { const GlobalValue *GV = G->getGlobal(); // Create a constant pool entry for the callee address unsigned ARMPCLabelIndex = AFI->createPICLabelUId(); ARMConstantPoolValue *CPV = ARMConstantPoolConstant::Create(GV, ARMPCLabelIndex, ARMCP::CPValue, 0); // Get the address of the callee into a register SDValue CPAddr = DAG.getTargetConstantPool(CPV, getPointerTy(), 4); CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); Callee = DAG.getLoad(getPointerTy(), dl, DAG.getEntryNode(), CPAddr, MachinePointerInfo::getConstantPool(), false, false, 0); } else if (ExternalSymbolSDNode *S=dyn_cast(Callee)) { const char *Sym = S->getSymbol(); // Create a constant pool entry for the callee address unsigned ARMPCLabelIndex = AFI->createPICLabelUId(); ARMConstantPoolValue *CPV = ARMConstantPoolSymbol::Create(*DAG.getContext(), Sym, ARMPCLabelIndex, 0); // Get the address of the callee into a register SDValue CPAddr = DAG.getTargetConstantPool(CPV, getPointerTy(), 4); CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); Callee = DAG.getLoad(getPointerTy(), dl, DAG.getEntryNode(), CPAddr, MachinePointerInfo::getConstantPool(), false, false, 0); } } else if (GlobalAddressSDNode *G = dyn_cast(Callee)) { const GlobalValue *GV = G->getGlobal(); isDirect = true; bool isExt = GV->isDeclaration() || GV->isWeakForLinker(); bool isStub = (isExt && Subtarget->isTargetDarwin()) && getTargetMachine().getRelocationModel() != Reloc::Static; isARMFunc = !Subtarget->isThumb() || isStub; // ARM call to a local ARM function is predicable. isLocalARMFunc = !Subtarget->isThumb() && (!isExt || !ARMInterworking); // tBX takes a register source operand. if (isARMFunc && Subtarget->isThumb1Only() && !Subtarget->hasV5TOps()) { unsigned ARMPCLabelIndex = AFI->createPICLabelUId(); ARMConstantPoolValue *CPV = ARMConstantPoolConstant::Create(GV, ARMPCLabelIndex, ARMCP::CPValue, 4); SDValue CPAddr = DAG.getTargetConstantPool(CPV, getPointerTy(), 4); CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); Callee = DAG.getLoad(getPointerTy(), dl, DAG.getEntryNode(), CPAddr, MachinePointerInfo::getConstantPool(), false, false, 0); SDValue PICLabel = DAG.getConstant(ARMPCLabelIndex, MVT::i32); Callee = DAG.getNode(ARMISD::PIC_ADD, dl, getPointerTy(), Callee, PICLabel); } else { // On ELF targets for PIC code, direct calls should go through the PLT unsigned OpFlags = 0; if (Subtarget->isTargetELF() && getTargetMachine().getRelocationModel() == Reloc::PIC_) OpFlags = ARMII::MO_PLT; Callee = DAG.getTargetGlobalAddress(GV, dl, getPointerTy(), 0, OpFlags); } } else if (ExternalSymbolSDNode *S = dyn_cast(Callee)) { isDirect = true; bool isStub = Subtarget->isTargetDarwin() && getTargetMachine().getRelocationModel() != Reloc::Static; isARMFunc = !Subtarget->isThumb() || isStub; // tBX takes a register source operand. const char *Sym = S->getSymbol(); if (isARMFunc && Subtarget->isThumb1Only() && !Subtarget->hasV5TOps()) { unsigned ARMPCLabelIndex = AFI->createPICLabelUId(); ARMConstantPoolValue *CPV = ARMConstantPoolSymbol::Create(*DAG.getContext(), Sym, ARMPCLabelIndex, 4); SDValue CPAddr = DAG.getTargetConstantPool(CPV, getPointerTy(), 4); CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); Callee = DAG.getLoad(getPointerTy(), dl, DAG.getEntryNode(), CPAddr, MachinePointerInfo::getConstantPool(), false, false, 0); SDValue PICLabel = DAG.getConstant(ARMPCLabelIndex, MVT::i32); Callee = DAG.getNode(ARMISD::PIC_ADD, dl, getPointerTy(), Callee, PICLabel); } else { unsigned OpFlags = 0; // On ELF targets for PIC code, direct calls should go through the PLT if (Subtarget->isTargetELF() && getTargetMachine().getRelocationModel() == Reloc::PIC_) OpFlags = ARMII::MO_PLT; Callee = DAG.getTargetExternalSymbol(Sym, getPointerTy(), OpFlags); } } // FIXME: handle tail calls differently. unsigned CallOpc; if (Subtarget->isThumb()) { if ((!isDirect || isARMFunc) && !Subtarget->hasV5TOps()) CallOpc = ARMISD::CALL_NOLINK; else CallOpc = isARMFunc ? ARMISD::CALL : ARMISD::tCALL; } else { CallOpc = (isDirect || Subtarget->hasV5TOps()) ? (isLocalARMFunc ? ARMISD::CALL_PRED : ARMISD::CALL) : ARMISD::CALL_NOLINK; } std::vector Ops; Ops.push_back(Chain); Ops.push_back(Callee); // Add argument registers to the end of the list so that they are known live // into the call. for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) Ops.push_back(DAG.getRegister(RegsToPass[i].first, RegsToPass[i].second.getValueType())); if (InFlag.getNode()) Ops.push_back(InFlag); SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); if (isTailCall) return DAG.getNode(ARMISD::TC_RETURN, dl, NodeTys, &Ops[0], Ops.size()); // Returns a chain and a flag for retval copy to use. Chain = DAG.getNode(CallOpc, dl, NodeTys, &Ops[0], Ops.size()); InFlag = Chain.getValue(1); Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(NumBytes, true), DAG.getIntPtrConstant(0, true), InFlag); if (!Ins.empty()) InFlag = Chain.getValue(1); // Handle result values, copying them out of physregs into vregs that we // return. return LowerCallResult(Chain, InFlag, CallConv, isVarArg, Ins, dl, DAG, InVals); } /// HandleByVal - Every parameter *after* a byval parameter is passed /// on the stack. Remember the next parameter register to allocate, /// and then confiscate the rest of the parameter registers to insure /// this. void llvm::ARMTargetLowering::HandleByVal(CCState *State, unsigned &size) const { unsigned reg = State->AllocateReg(GPRArgRegs, 4); assert((State->getCallOrPrologue() == Prologue || State->getCallOrPrologue() == Call) && "unhandled ParmContext"); if ((!State->isFirstByValRegValid()) && (ARM::R0 <= reg) && (reg <= ARM::R3)) { State->setFirstByValReg(reg); // At a call site, a byval parameter that is split between // registers and memory needs its size truncated here. In a // function prologue, such byval parameters are reassembled in // memory, and are not truncated. if (State->getCallOrPrologue() == Call) { unsigned excess = 4 * (ARM::R4 - reg); assert(size >= excess && "expected larger existing stack allocation"); size -= excess; } } // Confiscate any remaining parameter registers to preclude their // assignment to subsequent parameters. while (State->AllocateReg(GPRArgRegs, 4)) ; } /// MatchingStackOffset - Return true if the given stack call argument is /// already available in the same position (relatively) of the caller's /// incoming argument stack. static bool MatchingStackOffset(SDValue Arg, unsigned Offset, ISD::ArgFlagsTy Flags, MachineFrameInfo *MFI, const MachineRegisterInfo *MRI, const ARMInstrInfo *TII) { unsigned Bytes = Arg.getValueType().getSizeInBits() / 8; int FI = INT_MAX; if (Arg.getOpcode() == ISD::CopyFromReg) { unsigned VR = cast(Arg.getOperand(1))->getReg(); if (!TargetRegisterInfo::isVirtualRegister(VR)) return false; MachineInstr *Def = MRI->getVRegDef(VR); if (!Def) return false; if (!Flags.isByVal()) { if (!TII->isLoadFromStackSlot(Def, FI)) return false; } else { return false; } } else if (LoadSDNode *Ld = dyn_cast(Arg)) { if (Flags.isByVal()) // ByVal argument is passed in as a pointer but it's now being // dereferenced. e.g. // define @foo(%struct.X* %A) { // tail call @bar(%struct.X* byval %A) // } return false; SDValue Ptr = Ld->getBasePtr(); FrameIndexSDNode *FINode = dyn_cast(Ptr); if (!FINode) return false; FI = FINode->getIndex(); } else return false; assert(FI != INT_MAX); if (!MFI->isFixedObjectIndex(FI)) return false; return Offset == MFI->getObjectOffset(FI) && Bytes == MFI->getObjectSize(FI); } /// IsEligibleForTailCallOptimization - Check whether the call is eligible /// for tail call optimization. Targets which want to do tail call /// optimization should implement this function. bool ARMTargetLowering::IsEligibleForTailCallOptimization(SDValue Callee, CallingConv::ID CalleeCC, bool isVarArg, bool isCalleeStructRet, bool isCallerStructRet, const SmallVectorImpl &Outs, const SmallVectorImpl &OutVals, const SmallVectorImpl &Ins, SelectionDAG& DAG) const { const Function *CallerF = DAG.getMachineFunction().getFunction(); CallingConv::ID CallerCC = CallerF->getCallingConv(); bool CCMatch = CallerCC == CalleeCC; // Look for obvious safe cases to perform tail call optimization that do not // require ABI changes. This is what gcc calls sibcall. // Do not sibcall optimize vararg calls unless the call site is not passing // any arguments. if (isVarArg && !Outs.empty()) return false; // Also avoid sibcall optimization if either caller or callee uses struct // return semantics. if (isCalleeStructRet || isCallerStructRet) return false; // FIXME: Completely disable sibcall for Thumb1 since Thumb1RegisterInfo:: // emitEpilogue is not ready for them. Thumb tail calls also use t2B, as // the Thumb1 16-bit unconditional branch doesn't have sufficient relocation // support in the assembler and linker to be used. This would need to be // fixed to fully support tail calls in Thumb1. // // Doing this is tricky, since the LDM/POP instruction on Thumb doesn't take // LR. This means if we need to reload LR, it takes an extra instructions, // which outweighs the value of the tail call; but here we don't know yet // whether LR is going to be used. Probably the right approach is to // generate the tail call here and turn it back into CALL/RET in // emitEpilogue if LR is used. // Thumb1 PIC calls to external symbols use BX, so they can be tail calls, // but we need to make sure there are enough registers; the only valid // registers are the 4 used for parameters. We don't currently do this // case. if (Subtarget->isThumb1Only()) return false; // If the calling conventions do not match, then we'd better make sure the // results are returned in the same way as what the caller expects. if (!CCMatch) { SmallVector RVLocs1; ARMCCState CCInfo1(CalleeCC, false, DAG.getMachineFunction(), getTargetMachine(), RVLocs1, *DAG.getContext(), Call); CCInfo1.AnalyzeCallResult(Ins, CCAssignFnForNode(CalleeCC, true, isVarArg)); SmallVector RVLocs2; ARMCCState CCInfo2(CallerCC, false, DAG.getMachineFunction(), getTargetMachine(), RVLocs2, *DAG.getContext(), Call); CCInfo2.AnalyzeCallResult(Ins, CCAssignFnForNode(CallerCC, true, isVarArg)); if (RVLocs1.size() != RVLocs2.size()) return false; for (unsigned i = 0, e = RVLocs1.size(); i != e; ++i) { if (RVLocs1[i].isRegLoc() != RVLocs2[i].isRegLoc()) return false; if (RVLocs1[i].getLocInfo() != RVLocs2[i].getLocInfo()) return false; if (RVLocs1[i].isRegLoc()) { if (RVLocs1[i].getLocReg() != RVLocs2[i].getLocReg()) return false; } else { if (RVLocs1[i].getLocMemOffset() != RVLocs2[i].getLocMemOffset()) return false; } } } // If the callee takes no arguments then go on to check the results of the // call. if (!Outs.empty()) { // Check if stack adjustment is needed. For now, do not do this if any // argument is passed on the stack. SmallVector ArgLocs; ARMCCState CCInfo(CalleeCC, isVarArg, DAG.getMachineFunction(), getTargetMachine(), ArgLocs, *DAG.getContext(), Call); CCInfo.AnalyzeCallOperands(Outs, CCAssignFnForNode(CalleeCC, false, isVarArg)); if (CCInfo.getNextStackOffset()) { MachineFunction &MF = DAG.getMachineFunction(); // Check if the arguments are already laid out in the right way as // the caller's fixed stack objects. MachineFrameInfo *MFI = MF.getFrameInfo(); const MachineRegisterInfo *MRI = &MF.getRegInfo(); const ARMInstrInfo *TII = ((ARMTargetMachine&)getTargetMachine()).getInstrInfo(); for (unsigned i = 0, realArgIdx = 0, e = ArgLocs.size(); i != e; ++i, ++realArgIdx) { CCValAssign &VA = ArgLocs[i]; EVT RegVT = VA.getLocVT(); SDValue Arg = OutVals[realArgIdx]; ISD::ArgFlagsTy Flags = Outs[realArgIdx].Flags; if (VA.getLocInfo() == CCValAssign::Indirect) return false; if (VA.needsCustom()) { // f64 and vector types are split into multiple registers or // register/stack-slot combinations. The types will not match // the registers; give up on memory f64 refs until we figure // out what to do about this. if (!VA.isRegLoc()) return false; if (!ArgLocs[++i].isRegLoc()) return false; if (RegVT == MVT::v2f64) { if (!ArgLocs[++i].isRegLoc()) return false; if (!ArgLocs[++i].isRegLoc()) return false; } } else if (!VA.isRegLoc()) { if (!MatchingStackOffset(Arg, VA.getLocMemOffset(), Flags, MFI, MRI, TII)) return false; } } } } return true; } SDValue ARMTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, const SmallVectorImpl &Outs, const SmallVectorImpl &OutVals, DebugLoc dl, SelectionDAG &DAG) const { // CCValAssign - represent the assignment of the return value to a location. SmallVector RVLocs; // CCState - Info about the registers and stack slots. ARMCCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), getTargetMachine(), RVLocs, *DAG.getContext(), Call); // Analyze outgoing return values. CCInfo.AnalyzeReturn(Outs, CCAssignFnForNode(CallConv, /* Return */ true, isVarArg)); // If this is the first return lowered for this function, add // the regs to the liveout set for the function. if (DAG.getMachineFunction().getRegInfo().liveout_empty()) { for (unsigned i = 0; i != RVLocs.size(); ++i) if (RVLocs[i].isRegLoc()) DAG.getMachineFunction().getRegInfo().addLiveOut(RVLocs[i].getLocReg()); } SDValue Flag; // Copy the result values into the output registers. for (unsigned i = 0, realRVLocIdx = 0; i != RVLocs.size(); ++i, ++realRVLocIdx) { CCValAssign &VA = RVLocs[i]; assert(VA.isRegLoc() && "Can only return in registers!"); SDValue Arg = OutVals[realRVLocIdx]; switch (VA.getLocInfo()) { default: llvm_unreachable("Unknown loc info!"); case CCValAssign::Full: break; case CCValAssign::BCvt: Arg = DAG.getNode(ISD::BITCAST, dl, VA.getLocVT(), Arg); break; } if (VA.needsCustom()) { if (VA.getLocVT() == MVT::v2f64) { // Extract the first half and return it in two registers. SDValue Half = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, MVT::f64, Arg, DAG.getConstant(0, MVT::i32)); SDValue HalfGPRs = DAG.getNode(ARMISD::VMOVRRD, dl, DAG.getVTList(MVT::i32, MVT::i32), Half); Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), HalfGPRs, Flag); Flag = Chain.getValue(1); VA = RVLocs[++i]; // skip ahead to next loc Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), HalfGPRs.getValue(1), Flag); Flag = Chain.getValue(1); VA = RVLocs[++i]; // skip ahead to next loc // Extract the 2nd half and fall through to handle it as an f64 value. Arg = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, MVT::f64, Arg, DAG.getConstant(1, MVT::i32)); } // Legalize ret f64 -> ret 2 x i32. We always have fmrrd if f64 is // available. SDValue fmrrd = DAG.getNode(ARMISD::VMOVRRD, dl, DAG.getVTList(MVT::i32, MVT::i32), &Arg, 1); Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), fmrrd, Flag); Flag = Chain.getValue(1); VA = RVLocs[++i]; // skip ahead to next loc Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), fmrrd.getValue(1), Flag); } else Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), Arg, Flag); // Guarantee that all emitted copies are // stuck together, avoiding something bad. Flag = Chain.getValue(1); } SDValue result; if (Flag.getNode()) result = DAG.getNode(ARMISD::RET_FLAG, dl, MVT::Other, Chain, Flag); else // Return Void result = DAG.getNode(ARMISD::RET_FLAG, dl, MVT::Other, Chain); return result; } bool ARMTargetLowering::isUsedByReturnOnly(SDNode *N) const { if (N->getNumValues() != 1) return false; if (!N->hasNUsesOfValue(1, 0)) return false; unsigned NumCopies = 0; SDNode* Copies[2]; SDNode *Use = *N->use_begin(); if (Use->getOpcode() == ISD::CopyToReg) { Copies[NumCopies++] = Use; } else if (Use->getOpcode() == ARMISD::VMOVRRD) { // f64 returned in a pair of GPRs. for (SDNode::use_iterator UI = Use->use_begin(), UE = Use->use_end(); UI != UE; ++UI) { if (UI->getOpcode() != ISD::CopyToReg) return false; Copies[UI.getUse().getResNo()] = *UI; ++NumCopies; } } else if (Use->getOpcode() == ISD::BITCAST) { // f32 returned in a single GPR. if (!Use->hasNUsesOfValue(1, 0)) return false; Use = *Use->use_begin(); if (Use->getOpcode() != ISD::CopyToReg || !Use->hasNUsesOfValue(1, 0)) return false; Copies[NumCopies++] = Use; } else { return false; } if (NumCopies != 1 && NumCopies != 2) return false; bool HasRet = false; for (unsigned i = 0; i < NumCopies; ++i) { SDNode *Copy = Copies[i]; for (SDNode::use_iterator UI = Copy->use_begin(), UE = Copy->use_end(); UI != UE; ++UI) { if (UI->getOpcode() == ISD::CopyToReg) { SDNode *Use = *UI; if (Use == Copies[0] || Use == Copies[1]) continue; return false; } if (UI->getOpcode() != ARMISD::RET_FLAG) return false; HasRet = true; } } return HasRet; } bool ARMTargetLowering::mayBeEmittedAsTailCall(CallInst *CI) const { if (!EnableARMTailCalls) return false; if (!CI->isTailCall()) return false; return !Subtarget->isThumb1Only(); } // ConstantPool, JumpTable, GlobalAddress, and ExternalSymbol are lowered as // their target counterpart wrapped in the ARMISD::Wrapper node. Suppose N is // one of the above mentioned nodes. It has to be wrapped because otherwise // Select(N) returns N. So the raw TargetGlobalAddress nodes, etc. can only // be used to form addressing mode. These wrapped nodes will be selected // into MOVi. static SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG) { EVT PtrVT = Op.getValueType(); // FIXME there is no actual debug info here DebugLoc dl = Op.getDebugLoc(); ConstantPoolSDNode *CP = cast(Op); SDValue Res; if (CP->isMachineConstantPoolEntry()) Res = DAG.getTargetConstantPool(CP->getMachineCPVal(), PtrVT, CP->getAlignment()); else Res = DAG.getTargetConstantPool(CP->getConstVal(), PtrVT, CP->getAlignment()); return DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, Res); } unsigned ARMTargetLowering::getJumpTableEncoding() const { return MachineJumpTableInfo::EK_Inline; } SDValue ARMTargetLowering::LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const { MachineFunction &MF = DAG.getMachineFunction(); ARMFunctionInfo *AFI = MF.getInfo(); unsigned ARMPCLabelIndex = 0; DebugLoc DL = Op.getDebugLoc(); EVT PtrVT = getPointerTy(); const BlockAddress *BA = cast(Op)->getBlockAddress(); Reloc::Model RelocM = getTargetMachine().getRelocationModel(); SDValue CPAddr; if (RelocM == Reloc::Static) { CPAddr = DAG.getTargetConstantPool(BA, PtrVT, 4); } else { unsigned PCAdj = Subtarget->isThumb() ? 4 : 8; ARMPCLabelIndex = AFI->createPICLabelUId(); ARMConstantPoolValue *CPV = ARMConstantPoolConstant::Create(BA, ARMPCLabelIndex, ARMCP::CPBlockAddress, PCAdj); CPAddr = DAG.getTargetConstantPool(CPV, PtrVT, 4); } CPAddr = DAG.getNode(ARMISD::Wrapper, DL, PtrVT, CPAddr); SDValue Result = DAG.getLoad(PtrVT, DL, DAG.getEntryNode(), CPAddr, MachinePointerInfo::getConstantPool(), false, false, 0); if (RelocM == Reloc::Static) return Result; SDValue PICLabel = DAG.getConstant(ARMPCLabelIndex, MVT::i32); return DAG.getNode(ARMISD::PIC_ADD, DL, PtrVT, Result, PICLabel); } // Lower ISD::GlobalTLSAddress using the "general dynamic" model SDValue ARMTargetLowering::LowerToTLSGeneralDynamicModel(GlobalAddressSDNode *GA, SelectionDAG &DAG) const { DebugLoc dl = GA->getDebugLoc(); EVT PtrVT = getPointerTy(); unsigned char PCAdj = Subtarget->isThumb() ? 4 : 8; MachineFunction &MF = DAG.getMachineFunction(); ARMFunctionInfo *AFI = MF.getInfo(); unsigned ARMPCLabelIndex = AFI->createPICLabelUId(); ARMConstantPoolValue *CPV = ARMConstantPoolConstant::Create(GA->getGlobal(), ARMPCLabelIndex, ARMCP::CPValue, PCAdj, ARMCP::TLSGD, true); SDValue Argument = DAG.getTargetConstantPool(CPV, PtrVT, 4); Argument = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, Argument); Argument = DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), Argument, MachinePointerInfo::getConstantPool(), false, false, 0); SDValue Chain = Argument.getValue(1); SDValue PICLabel = DAG.getConstant(ARMPCLabelIndex, MVT::i32); Argument = DAG.getNode(ARMISD::PIC_ADD, dl, PtrVT, Argument, PICLabel); // call __tls_get_addr. ArgListTy Args; ArgListEntry Entry; Entry.Node = Argument; Entry.Ty = (Type *) Type::getInt32Ty(*DAG.getContext()); Args.push_back(Entry); // FIXME: is there useful debug info available here? std::pair CallResult = LowerCallTo(Chain, (Type *) Type::getInt32Ty(*DAG.getContext()), false, false, false, false, 0, CallingConv::C, false, /*isReturnValueUsed=*/true, DAG.getExternalSymbol("__tls_get_addr", PtrVT), Args, DAG, dl); return CallResult.first; } // Lower ISD::GlobalTLSAddress using the "initial exec" or // "local exec" model. SDValue ARMTargetLowering::LowerToTLSExecModels(GlobalAddressSDNode *GA, SelectionDAG &DAG) const { const GlobalValue *GV = GA->getGlobal(); DebugLoc dl = GA->getDebugLoc(); SDValue Offset; SDValue Chain = DAG.getEntryNode(); EVT PtrVT = getPointerTy(); // Get the Thread Pointer SDValue ThreadPointer = DAG.getNode(ARMISD::THREAD_POINTER, dl, PtrVT); if (GV->isDeclaration()) { MachineFunction &MF = DAG.getMachineFunction(); ARMFunctionInfo *AFI = MF.getInfo(); unsigned ARMPCLabelIndex = AFI->createPICLabelUId(); // Initial exec model. unsigned char PCAdj = Subtarget->isThumb() ? 4 : 8; ARMConstantPoolValue *CPV = ARMConstantPoolConstant::Create(GA->getGlobal(), ARMPCLabelIndex, ARMCP::CPValue, PCAdj, ARMCP::GOTTPOFF, true); Offset = DAG.getTargetConstantPool(CPV, PtrVT, 4); Offset = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, Offset); Offset = DAG.getLoad(PtrVT, dl, Chain, Offset, MachinePointerInfo::getConstantPool(), false, false, 0); Chain = Offset.getValue(1); SDValue PICLabel = DAG.getConstant(ARMPCLabelIndex, MVT::i32); Offset = DAG.getNode(ARMISD::PIC_ADD, dl, PtrVT, Offset, PICLabel); Offset = DAG.getLoad(PtrVT, dl, Chain, Offset, MachinePointerInfo::getConstantPool(), false, false, 0); } else { // local exec model ARMConstantPoolValue *CPV = ARMConstantPoolConstant::Create(GV, ARMCP::TPOFF); Offset = DAG.getTargetConstantPool(CPV, PtrVT, 4); Offset = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, Offset); Offset = DAG.getLoad(PtrVT, dl, Chain, Offset, MachinePointerInfo::getConstantPool(), false, false, 0); } // The address of the thread local variable is the add of the thread // pointer with the offset of the variable. return DAG.getNode(ISD::ADD, dl, PtrVT, ThreadPointer, Offset); } SDValue ARMTargetLowering::LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const { // TODO: implement the "local dynamic" model assert(Subtarget->isTargetELF() && "TLS not implemented for non-ELF targets"); GlobalAddressSDNode *GA = cast(Op); // If the relocation model is PIC, use the "General Dynamic" TLS Model, // otherwise use the "Local Exec" TLS Model if (getTargetMachine().getRelocationModel() == Reloc::PIC_) return LowerToTLSGeneralDynamicModel(GA, DAG); else return LowerToTLSExecModels(GA, DAG); } SDValue ARMTargetLowering::LowerGlobalAddressELF(SDValue Op, SelectionDAG &DAG) const { EVT PtrVT = getPointerTy(); DebugLoc dl = Op.getDebugLoc(); const GlobalValue *GV = cast(Op)->getGlobal(); Reloc::Model RelocM = getTargetMachine().getRelocationModel(); if (RelocM == Reloc::PIC_) { bool UseGOTOFF = GV->hasLocalLinkage() || GV->hasHiddenVisibility(); ARMConstantPoolValue *CPV = ARMConstantPoolConstant::Create(GV, UseGOTOFF ? ARMCP::GOTOFF : ARMCP::GOT); SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVT, 4); CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); SDValue Result = DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), CPAddr, MachinePointerInfo::getConstantPool(), false, false, 0); SDValue Chain = Result.getValue(1); SDValue GOT = DAG.getGLOBAL_OFFSET_TABLE(PtrVT); Result = DAG.getNode(ISD::ADD, dl, PtrVT, Result, GOT); if (!UseGOTOFF) Result = DAG.getLoad(PtrVT, dl, Chain, Result, MachinePointerInfo::getGOT(), false, false, 0); return Result; } // If we have T2 ops, we can materialize the address directly via movt/movw // pair. This is always cheaper. if (Subtarget->useMovt()) { ++NumMovwMovt; // FIXME: Once remat is capable of dealing with instructions with register // operands, expand this into two nodes. return DAG.getNode(ARMISD::Wrapper, dl, PtrVT, DAG.getTargetGlobalAddress(GV, dl, PtrVT)); } else { SDValue CPAddr = DAG.getTargetConstantPool(GV, PtrVT, 4); CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); return DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), CPAddr, MachinePointerInfo::getConstantPool(), false, false, 0); } } SDValue ARMTargetLowering::LowerGlobalAddressDarwin(SDValue Op, SelectionDAG &DAG) const { EVT PtrVT = getPointerTy(); DebugLoc dl = Op.getDebugLoc(); const GlobalValue *GV = cast(Op)->getGlobal(); Reloc::Model RelocM = getTargetMachine().getRelocationModel(); MachineFunction &MF = DAG.getMachineFunction(); ARMFunctionInfo *AFI = MF.getInfo(); // FIXME: Enable this for static codegen when tool issues are fixed. if (Subtarget->useMovt() && RelocM != Reloc::Static) { ++NumMovwMovt; // FIXME: Once remat is capable of dealing with instructions with register // operands, expand this into two nodes. if (RelocM == Reloc::Static) return DAG.getNode(ARMISD::Wrapper, dl, PtrVT, DAG.getTargetGlobalAddress(GV, dl, PtrVT)); unsigned Wrapper = (RelocM == Reloc::PIC_) ? ARMISD::WrapperPIC : ARMISD::WrapperDYN; SDValue Result = DAG.getNode(Wrapper, dl, PtrVT, DAG.getTargetGlobalAddress(GV, dl, PtrVT)); if (Subtarget->GVIsIndirectSymbol(GV, RelocM)) Result = DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), Result, MachinePointerInfo::getGOT(), false, false, 0); return Result; } unsigned ARMPCLabelIndex = 0; SDValue CPAddr; if (RelocM == Reloc::Static) { CPAddr = DAG.getTargetConstantPool(GV, PtrVT, 4); } else { ARMPCLabelIndex = AFI->createPICLabelUId(); unsigned PCAdj = (RelocM != Reloc::PIC_) ? 0 : (Subtarget->isThumb()?4:8); ARMConstantPoolValue *CPV = ARMConstantPoolConstant::Create(GV, ARMPCLabelIndex, ARMCP::CPValue, PCAdj); CPAddr = DAG.getTargetConstantPool(CPV, PtrVT, 4); } CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); SDValue Result = DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), CPAddr, MachinePointerInfo::getConstantPool(), false, false, 0); SDValue Chain = Result.getValue(1); if (RelocM == Reloc::PIC_) { SDValue PICLabel = DAG.getConstant(ARMPCLabelIndex, MVT::i32); Result = DAG.getNode(ARMISD::PIC_ADD, dl, PtrVT, Result, PICLabel); } if (Subtarget->GVIsIndirectSymbol(GV, RelocM)) Result = DAG.getLoad(PtrVT, dl, Chain, Result, MachinePointerInfo::getGOT(), false, false, 0); return Result; } SDValue ARMTargetLowering::LowerGLOBAL_OFFSET_TABLE(SDValue Op, SelectionDAG &DAG) const { assert(Subtarget->isTargetELF() && "GLOBAL OFFSET TABLE not implemented for non-ELF targets"); MachineFunction &MF = DAG.getMachineFunction(); ARMFunctionInfo *AFI = MF.getInfo(); unsigned ARMPCLabelIndex = AFI->createPICLabelUId(); EVT PtrVT = getPointerTy(); DebugLoc dl = Op.getDebugLoc(); unsigned PCAdj = Subtarget->isThumb() ? 4 : 8; ARMConstantPoolValue *CPV = ARMConstantPoolSymbol::Create(*DAG.getContext(), "_GLOBAL_OFFSET_TABLE_", ARMPCLabelIndex, PCAdj); SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVT, 4); CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); SDValue Result = DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), CPAddr, MachinePointerInfo::getConstantPool(), false, false, 0); SDValue PICLabel = DAG.getConstant(ARMPCLabelIndex, MVT::i32); return DAG.getNode(ARMISD::PIC_ADD, dl, PtrVT, Result, PICLabel); } SDValue ARMTargetLowering::LowerEH_SJLJ_DISPATCHSETUP(SDValue Op, SelectionDAG &DAG) const { DebugLoc dl = Op.getDebugLoc(); return DAG.getNode(ARMISD::EH_SJLJ_DISPATCHSETUP, dl, MVT::Other, Op.getOperand(0), Op.getOperand(1)); } SDValue ARMTargetLowering::LowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG) const { DebugLoc dl = Op.getDebugLoc(); SDValue Val = DAG.getConstant(0, MVT::i32); return DAG.getNode(ARMISD::EH_SJLJ_SETJMP, dl, DAG.getVTList(MVT::i32, MVT::Other), Op.getOperand(0), Op.getOperand(1), Val); } SDValue ARMTargetLowering::LowerEH_SJLJ_LONGJMP(SDValue Op, SelectionDAG &DAG) const { DebugLoc dl = Op.getDebugLoc(); return DAG.getNode(ARMISD::EH_SJLJ_LONGJMP, dl, MVT::Other, Op.getOperand(0), Op.getOperand(1), DAG.getConstant(0, MVT::i32)); } SDValue ARMTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG, const ARMSubtarget *Subtarget) const { unsigned IntNo = cast(Op.getOperand(0))->getZExtValue(); DebugLoc dl = Op.getDebugLoc(); switch (IntNo) { default: return SDValue(); // Don't custom lower most intrinsics. case Intrinsic::arm_thread_pointer: { EVT PtrVT = DAG.getTargetLoweringInfo().getPointerTy(); return DAG.getNode(ARMISD::THREAD_POINTER, dl, PtrVT); } case Intrinsic::eh_sjlj_lsda: { MachineFunction &MF = DAG.getMachineFunction(); ARMFunctionInfo *AFI = MF.getInfo(); unsigned ARMPCLabelIndex = AFI->createPICLabelUId(); EVT PtrVT = getPointerTy(); DebugLoc dl = Op.getDebugLoc(); Reloc::Model RelocM = getTargetMachine().getRelocationModel(); SDValue CPAddr; unsigned PCAdj = (RelocM != Reloc::PIC_) ? 0 : (Subtarget->isThumb() ? 4 : 8); ARMConstantPoolValue *CPV = ARMConstantPoolConstant::Create(MF.getFunction(), ARMPCLabelIndex, ARMCP::CPLSDA, PCAdj); CPAddr = DAG.getTargetConstantPool(CPV, PtrVT, 4); CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); SDValue Result = DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), CPAddr, MachinePointerInfo::getConstantPool(), false, false, 0); if (RelocM == Reloc::PIC_) { SDValue PICLabel = DAG.getConstant(ARMPCLabelIndex, MVT::i32); Result = DAG.getNode(ARMISD::PIC_ADD, dl, PtrVT, Result, PICLabel); } return Result; } case Intrinsic::arm_neon_vmulls: case Intrinsic::arm_neon_vmullu: { unsigned NewOpc = (IntNo == Intrinsic::arm_neon_vmulls) ? ARMISD::VMULLs : ARMISD::VMULLu; return DAG.getNode(NewOpc, Op.getDebugLoc(), Op.getValueType(), Op.getOperand(1), Op.getOperand(2)); } } } static SDValue LowerMEMBARRIER(SDValue Op, SelectionDAG &DAG, const ARMSubtarget *Subtarget) { DebugLoc dl = Op.getDebugLoc(); if (!Subtarget->hasDataBarrier()) { // Some ARMv6 cpus can support data barriers with an mcr instruction. // Thumb1 and pre-v6 ARM mode use a libcall instead and should never get // here. assert(Subtarget->hasV6Ops() && !Subtarget->isThumb() && "Unexpected ISD::MEMBARRIER encountered. Should be libcall!"); return DAG.getNode(ARMISD::MEMBARRIER_MCR, dl, MVT::Other, Op.getOperand(0), DAG.getConstant(0, MVT::i32)); } SDValue Op5 = Op.getOperand(5); bool isDeviceBarrier = cast(Op5)->getZExtValue() != 0; unsigned isLL = cast(Op.getOperand(1))->getZExtValue(); unsigned isLS = cast(Op.getOperand(2))->getZExtValue(); bool isOnlyStoreBarrier = (isLL == 0 && isLS == 0); ARM_MB::MemBOpt DMBOpt; if (isDeviceBarrier) DMBOpt = isOnlyStoreBarrier ? ARM_MB::ST : ARM_MB::SY; else DMBOpt = isOnlyStoreBarrier ? ARM_MB::ISHST : ARM_MB::ISH; return DAG.getNode(ARMISD::MEMBARRIER, dl, MVT::Other, Op.getOperand(0), DAG.getConstant(DMBOpt, MVT::i32)); } static SDValue LowerATOMIC_FENCE(SDValue Op, SelectionDAG &DAG, const ARMSubtarget *Subtarget) { // FIXME: handle "fence singlethread" more efficiently. DebugLoc dl = Op.getDebugLoc(); if (!Subtarget->hasDataBarrier()) { // Some ARMv6 cpus can support data barriers with an mcr instruction. // Thumb1 and pre-v6 ARM mode use a libcall instead and should never get // here. assert(Subtarget->hasV6Ops() && !Subtarget->isThumb() && "Unexpected ISD::MEMBARRIER encountered. Should be libcall!"); return DAG.getNode(ARMISD::MEMBARRIER_MCR, dl, MVT::Other, Op.getOperand(0), DAG.getConstant(0, MVT::i32)); } return DAG.getNode(ARMISD::MEMBARRIER, dl, MVT::Other, Op.getOperand(0), DAG.getConstant(ARM_MB::ISH, MVT::i32)); } static SDValue LowerPREFETCH(SDValue Op, SelectionDAG &DAG, const ARMSubtarget *Subtarget) { // ARM pre v5TE and Thumb1 does not have preload instructions. if (!(Subtarget->isThumb2() || (!Subtarget->isThumb1Only() && Subtarget->hasV5TEOps()))) // Just preserve the chain. return Op.getOperand(0); DebugLoc dl = Op.getDebugLoc(); unsigned isRead = ~cast(Op.getOperand(2))->getZExtValue() & 1; if (!isRead && (!Subtarget->hasV7Ops() || !Subtarget->hasMPExtension())) // ARMv7 with MP extension has PLDW. return Op.getOperand(0); unsigned isData = cast(Op.getOperand(4))->getZExtValue(); if (Subtarget->isThumb()) { // Invert the bits. isRead = ~isRead & 1; isData = ~isData & 1; } return DAG.getNode(ARMISD::PRELOAD, dl, MVT::Other, Op.getOperand(0), Op.getOperand(1), DAG.getConstant(isRead, MVT::i32), DAG.getConstant(isData, MVT::i32)); } static SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) { MachineFunction &MF = DAG.getMachineFunction(); ARMFunctionInfo *FuncInfo = MF.getInfo(); // vastart just stores the address of the VarArgsFrameIndex slot into the // memory location argument. DebugLoc dl = Op.getDebugLoc(); EVT PtrVT = DAG.getTargetLoweringInfo().getPointerTy(); SDValue FR = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(), PtrVT); const Value *SV = cast(Op.getOperand(2))->getValue(); return DAG.getStore(Op.getOperand(0), dl, FR, Op.getOperand(1), MachinePointerInfo(SV), false, false, 0); } SDValue ARMTargetLowering::GetF64FormalArgument(CCValAssign &VA, CCValAssign &NextVA, SDValue &Root, SelectionDAG &DAG, DebugLoc dl) const { MachineFunction &MF = DAG.getMachineFunction(); ARMFunctionInfo *AFI = MF.getInfo(); TargetRegisterClass *RC; if (AFI->isThumb1OnlyFunction()) RC = ARM::tGPRRegisterClass; else RC = ARM::GPRRegisterClass; // Transform the arguments stored in physical registers into virtual ones. unsigned Reg = MF.addLiveIn(VA.getLocReg(), RC); SDValue ArgValue = DAG.getCopyFromReg(Root, dl, Reg, MVT::i32); SDValue ArgValue2; if (NextVA.isMemLoc()) { MachineFrameInfo *MFI = MF.getFrameInfo(); int FI = MFI->CreateFixedObject(4, NextVA.getLocMemOffset(), true); // Create load node to retrieve arguments from the stack. SDValue FIN = DAG.getFrameIndex(FI, getPointerTy()); ArgValue2 = DAG.getLoad(MVT::i32, dl, Root, FIN, MachinePointerInfo::getFixedStack(FI), false, false, 0); } else { Reg = MF.addLiveIn(NextVA.getLocReg(), RC); ArgValue2 = DAG.getCopyFromReg(Root, dl, Reg, MVT::i32); } return DAG.getNode(ARMISD::VMOVDRR, dl, MVT::f64, ArgValue, ArgValue2); } void ARMTargetLowering::computeRegArea(CCState &CCInfo, MachineFunction &MF, unsigned &VARegSize, unsigned &VARegSaveSize) const { unsigned NumGPRs; if (CCInfo.isFirstByValRegValid()) NumGPRs = ARM::R4 - CCInfo.getFirstByValReg(); else { unsigned int firstUnalloced; firstUnalloced = CCInfo.getFirstUnallocated(GPRArgRegs, sizeof(GPRArgRegs) / sizeof(GPRArgRegs[0])); NumGPRs = (firstUnalloced <= 3) ? (4 - firstUnalloced) : 0; } unsigned Align = MF.getTarget().getFrameLowering()->getStackAlignment(); VARegSize = NumGPRs * 4; VARegSaveSize = (VARegSize + Align - 1) & ~(Align - 1); } // The remaining GPRs hold either the beginning of variable-argument // data, or the beginning of an aggregate passed by value (usuall // byval). Either way, we allocate stack slots adjacent to the data // provided by our caller, and store the unallocated registers there. // If this is a variadic function, the va_list pointer will begin with // these values; otherwise, this reassembles a (byval) structure that // was split between registers and memory. void ARMTargetLowering::VarArgStyleRegisters(CCState &CCInfo, SelectionDAG &DAG, DebugLoc dl, SDValue &Chain, unsigned ArgOffset) const { MachineFunction &MF = DAG.getMachineFunction(); MachineFrameInfo *MFI = MF.getFrameInfo(); ARMFunctionInfo *AFI = MF.getInfo(); unsigned firstRegToSaveIndex; if (CCInfo.isFirstByValRegValid()) firstRegToSaveIndex = CCInfo.getFirstByValReg() - ARM::R0; else { firstRegToSaveIndex = CCInfo.getFirstUnallocated (GPRArgRegs, sizeof(GPRArgRegs) / sizeof(GPRArgRegs[0])); } unsigned VARegSize, VARegSaveSize; computeRegArea(CCInfo, MF, VARegSize, VARegSaveSize); if (VARegSaveSize) { // If this function is vararg, store any remaining integer argument regs // to their spots on the stack so that they may be loaded by deferencing // the result of va_next. AFI->setVarArgsRegSaveSize(VARegSaveSize); AFI->setVarArgsFrameIndex(MFI->CreateFixedObject(VARegSaveSize, ArgOffset + VARegSaveSize - VARegSize, false)); SDValue FIN = DAG.getFrameIndex(AFI->getVarArgsFrameIndex(), getPointerTy()); SmallVector MemOps; for (; firstRegToSaveIndex < 4; ++firstRegToSaveIndex) { TargetRegisterClass *RC; if (AFI->isThumb1OnlyFunction()) RC = ARM::tGPRRegisterClass; else RC = ARM::GPRRegisterClass; unsigned VReg = MF.addLiveIn(GPRArgRegs[firstRegToSaveIndex], RC); SDValue Val = DAG.getCopyFromReg(Chain, dl, VReg, MVT::i32); SDValue Store = DAG.getStore(Val.getValue(1), dl, Val, FIN, MachinePointerInfo::getFixedStack(AFI->getVarArgsFrameIndex()), false, false, 0); MemOps.push_back(Store); FIN = DAG.getNode(ISD::ADD, dl, getPointerTy(), FIN, DAG.getConstant(4, getPointerTy())); } if (!MemOps.empty()) Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &MemOps[0], MemOps.size()); } else // This will point to the next argument passed via stack. AFI->setVarArgsFrameIndex(MFI->CreateFixedObject(4, ArgOffset, true)); } SDValue ARMTargetLowering::LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, const SmallVectorImpl &Ins, DebugLoc dl, SelectionDAG &DAG, SmallVectorImpl &InVals) const { MachineFunction &MF = DAG.getMachineFunction(); MachineFrameInfo *MFI = MF.getFrameInfo(); ARMFunctionInfo *AFI = MF.getInfo(); // Assign locations to all of the incoming arguments. SmallVector ArgLocs; ARMCCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), getTargetMachine(), ArgLocs, *DAG.getContext(), Prologue); CCInfo.AnalyzeFormalArguments(Ins, CCAssignFnForNode(CallConv, /* Return*/ false, isVarArg)); SmallVector ArgValues; int lastInsIndex = -1; SDValue ArgValue; for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { CCValAssign &VA = ArgLocs[i]; // Arguments stored in registers. if (VA.isRegLoc()) { EVT RegVT = VA.getLocVT(); if (VA.needsCustom()) { // f64 and vector types are split up into multiple registers or // combinations of registers and stack slots. if (VA.getLocVT() == MVT::v2f64) { SDValue ArgValue1 = GetF64FormalArgument(VA, ArgLocs[++i], Chain, DAG, dl); VA = ArgLocs[++i]; // skip ahead to next loc SDValue ArgValue2; if (VA.isMemLoc()) { int FI = MFI->CreateFixedObject(8, VA.getLocMemOffset(), true); SDValue FIN = DAG.getFrameIndex(FI, getPointerTy()); ArgValue2 = DAG.getLoad(MVT::f64, dl, Chain, FIN, MachinePointerInfo::getFixedStack(FI), false, false, 0); } else { ArgValue2 = GetF64FormalArgument(VA, ArgLocs[++i], Chain, DAG, dl); } ArgValue = DAG.getNode(ISD::UNDEF, dl, MVT::v2f64); ArgValue = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, MVT::v2f64, ArgValue, ArgValue1, DAG.getIntPtrConstant(0)); ArgValue = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, MVT::v2f64, ArgValue, ArgValue2, DAG.getIntPtrConstant(1)); } else ArgValue = GetF64FormalArgument(VA, ArgLocs[++i], Chain, DAG, dl); } else { TargetRegisterClass *RC; if (RegVT == MVT::f32) RC = ARM::SPRRegisterClass; else if (RegVT == MVT::f64) RC = ARM::DPRRegisterClass; else if (RegVT == MVT::v2f64) RC = ARM::QPRRegisterClass; else if (RegVT == MVT::i32) RC = (AFI->isThumb1OnlyFunction() ? ARM::tGPRRegisterClass : ARM::GPRRegisterClass); else llvm_unreachable("RegVT not supported by FORMAL_ARGUMENTS Lowering"); // Transform the arguments in physical registers into virtual ones. unsigned Reg = MF.addLiveIn(VA.getLocReg(), RC); ArgValue = DAG.getCopyFromReg(Chain, dl, Reg, RegVT); } // If this is an 8 or 16-bit value, it is really passed promoted // to 32 bits. Insert an assert[sz]ext to capture this, then // truncate to the right size. switch (VA.getLocInfo()) { default: llvm_unreachable("Unknown loc info!"); case CCValAssign::Full: break; case CCValAssign::BCvt: ArgValue = DAG.getNode(ISD::BITCAST, dl, VA.getValVT(), ArgValue); break; case CCValAssign::SExt: ArgValue = DAG.getNode(ISD::AssertSext, dl, RegVT, ArgValue, DAG.getValueType(VA.getValVT())); ArgValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), ArgValue); break; case CCValAssign::ZExt: ArgValue = DAG.getNode(ISD::AssertZext, dl, RegVT, ArgValue, DAG.getValueType(VA.getValVT())); ArgValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), ArgValue); break; } InVals.push_back(ArgValue); } else { // VA.isRegLoc() // sanity check assert(VA.isMemLoc()); assert(VA.getValVT() != MVT::i64 && "i64 should already be lowered"); int index = ArgLocs[i].getValNo(); // Some Ins[] entries become multiple ArgLoc[] entries. // Process them only once. if (index != lastInsIndex) { ISD::ArgFlagsTy Flags = Ins[index].Flags; // FIXME: For now, all byval parameter objects are marked mutable. // This can be changed with more analysis. // In case of tail call optimization mark all arguments mutable. // Since they could be overwritten by lowering of arguments in case of // a tail call. if (Flags.isByVal()) { unsigned VARegSize, VARegSaveSize; computeRegArea(CCInfo, MF, VARegSize, VARegSaveSize); VarArgStyleRegisters(CCInfo, DAG, dl, Chain, 0); unsigned Bytes = Flags.getByValSize() - VARegSize; if (Bytes == 0) Bytes = 1; // Don't create zero-sized stack objects. int FI = MFI->CreateFixedObject(Bytes, VA.getLocMemOffset(), false); InVals.push_back(DAG.getFrameIndex(FI, getPointerTy())); } else { int FI = MFI->CreateFixedObject(VA.getLocVT().getSizeInBits()/8, VA.getLocMemOffset(), true); // Create load nodes to retrieve arguments from the stack. SDValue FIN = DAG.getFrameIndex(FI, getPointerTy()); InVals.push_back(DAG.getLoad(VA.getValVT(), dl, Chain, FIN, MachinePointerInfo::getFixedStack(FI), false, false, 0)); } lastInsIndex = index; } } } // varargs if (isVarArg) VarArgStyleRegisters(CCInfo, DAG, dl, Chain, CCInfo.getNextStackOffset()); return Chain; } /// isFloatingPointZero - Return true if this is +0.0. static bool isFloatingPointZero(SDValue Op) { if (ConstantFPSDNode *CFP = dyn_cast(Op)) return CFP->getValueAPF().isPosZero(); else if (ISD::isEXTLoad(Op.getNode()) || ISD::isNON_EXTLoad(Op.getNode())) { // Maybe this has already been legalized into the constant pool? if (Op.getOperand(1).getOpcode() == ARMISD::Wrapper) { SDValue WrapperOp = Op.getOperand(1).getOperand(0); if (ConstantPoolSDNode *CP = dyn_cast(WrapperOp)) if (const ConstantFP *CFP = dyn_cast(CP->getConstVal())) return CFP->getValueAPF().isPosZero(); } } return false; } /// Returns appropriate ARM CMP (cmp) and corresponding condition code for /// the given operands. SDValue ARMTargetLowering::getARMCmp(SDValue LHS, SDValue RHS, ISD::CondCode CC, SDValue &ARMcc, SelectionDAG &DAG, DebugLoc dl) const { if (ConstantSDNode *RHSC = dyn_cast(RHS.getNode())) { unsigned C = RHSC->getZExtValue(); if (!isLegalICmpImmediate(C)) { // Constant does not fit, try adjusting it by one? switch (CC) { default: break; case ISD::SETLT: case ISD::SETGE: if (C != 0x80000000 && isLegalICmpImmediate(C-1)) { CC = (CC == ISD::SETLT) ? ISD::SETLE : ISD::SETGT; RHS = DAG.getConstant(C-1, MVT::i32); } break; case ISD::SETULT: case ISD::SETUGE: if (C != 0 && isLegalICmpImmediate(C-1)) { CC = (CC == ISD::SETULT) ? ISD::SETULE : ISD::SETUGT; RHS = DAG.getConstant(C-1, MVT::i32); } break; case ISD::SETLE: case ISD::SETGT: if (C != 0x7fffffff && isLegalICmpImmediate(C+1)) { CC = (CC == ISD::SETLE) ? ISD::SETLT : ISD::SETGE; RHS = DAG.getConstant(C+1, MVT::i32); } break; case ISD::SETULE: case ISD::SETUGT: if (C != 0xffffffff && isLegalICmpImmediate(C+1)) { CC = (CC == ISD::SETULE) ? ISD::SETULT : ISD::SETUGE; RHS = DAG.getConstant(C+1, MVT::i32); } break; } } } ARMCC::CondCodes CondCode = IntCCToARMCC(CC); ARMISD::NodeType CompareType; switch (CondCode) { default: CompareType = ARMISD::CMP; break; case ARMCC::EQ: case ARMCC::NE: // Uses only Z Flag CompareType = ARMISD::CMPZ; break; } ARMcc = DAG.getConstant(CondCode, MVT::i32); return DAG.getNode(CompareType, dl, MVT::Glue, LHS, RHS); } /// Returns a appropriate VFP CMP (fcmp{s|d}+fmstat) for the given operands. SDValue ARMTargetLowering::getVFPCmp(SDValue LHS, SDValue RHS, SelectionDAG &DAG, DebugLoc dl) const { SDValue Cmp; if (!isFloatingPointZero(RHS)) Cmp = DAG.getNode(ARMISD::CMPFP, dl, MVT::Glue, LHS, RHS); else Cmp = DAG.getNode(ARMISD::CMPFPw0, dl, MVT::Glue, LHS); return DAG.getNode(ARMISD::FMSTAT, dl, MVT::Glue, Cmp); } /// duplicateCmp - Glue values can have only one use, so this function /// duplicates a comparison node. SDValue ARMTargetLowering::duplicateCmp(SDValue Cmp, SelectionDAG &DAG) const { unsigned Opc = Cmp.getOpcode(); DebugLoc DL = Cmp.getDebugLoc(); if (Opc == ARMISD::CMP || Opc == ARMISD::CMPZ) return DAG.getNode(Opc, DL, MVT::Glue, Cmp.getOperand(0),Cmp.getOperand(1)); assert(Opc == ARMISD::FMSTAT && "unexpected comparison operation"); Cmp = Cmp.getOperand(0); Opc = Cmp.getOpcode(); if (Opc == ARMISD::CMPFP) Cmp = DAG.getNode(Opc, DL, MVT::Glue, Cmp.getOperand(0),Cmp.getOperand(1)); else { assert(Opc == ARMISD::CMPFPw0 && "unexpected operand of FMSTAT"); Cmp = DAG.getNode(Opc, DL, MVT::Glue, Cmp.getOperand(0)); } return DAG.getNode(ARMISD::FMSTAT, DL, MVT::Glue, Cmp); } SDValue ARMTargetLowering::LowerSELECT(SDValue Op, SelectionDAG &DAG) const { SDValue Cond = Op.getOperand(0); SDValue SelectTrue = Op.getOperand(1); SDValue SelectFalse = Op.getOperand(2); DebugLoc dl = Op.getDebugLoc(); // Convert: // // (select (cmov 1, 0, cond), t, f) -> (cmov t, f, cond) // (select (cmov 0, 1, cond), t, f) -> (cmov f, t, cond) // if (Cond.getOpcode() == ARMISD::CMOV && Cond.hasOneUse()) { const ConstantSDNode *CMOVTrue = dyn_cast(Cond.getOperand(0)); const ConstantSDNode *CMOVFalse = dyn_cast(Cond.getOperand(1)); if (CMOVTrue && CMOVFalse) { unsigned CMOVTrueVal = CMOVTrue->getZExtValue(); unsigned CMOVFalseVal = CMOVFalse->getZExtValue(); SDValue True; SDValue False; if (CMOVTrueVal == 1 && CMOVFalseVal == 0) { True = SelectTrue; False = SelectFalse; } else if (CMOVTrueVal == 0 && CMOVFalseVal == 1) { True = SelectFalse; False = SelectTrue; } if (True.getNode() && False.getNode()) { EVT VT = Op.getValueType(); SDValue ARMcc = Cond.getOperand(2); SDValue CCR = Cond.getOperand(3); SDValue Cmp = duplicateCmp(Cond.getOperand(4), DAG); assert(True.getValueType() == VT); return DAG.getNode(ARMISD::CMOV, dl, VT, True, False, ARMcc, CCR, Cmp); } } } return DAG.getSelectCC(dl, Cond, DAG.getConstant(0, Cond.getValueType()), SelectTrue, SelectFalse, ISD::SETNE); } SDValue ARMTargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const { EVT VT = Op.getValueType(); SDValue LHS = Op.getOperand(0); SDValue RHS = Op.getOperand(1); ISD::CondCode CC = cast(Op.getOperand(4))->get(); SDValue TrueVal = Op.getOperand(2); SDValue FalseVal = Op.getOperand(3); DebugLoc dl = Op.getDebugLoc(); if (LHS.getValueType() == MVT::i32) { SDValue ARMcc; SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32); SDValue Cmp = getARMCmp(LHS, RHS, CC, ARMcc, DAG, dl); return DAG.getNode(ARMISD::CMOV, dl, VT, FalseVal, TrueVal, ARMcc, CCR,Cmp); } ARMCC::CondCodes CondCode, CondCode2; FPCCToARMCC(CC, CondCode, CondCode2); SDValue ARMcc = DAG.getConstant(CondCode, MVT::i32); SDValue Cmp = getVFPCmp(LHS, RHS, DAG, dl); SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32); SDValue Result = DAG.getNode(ARMISD::CMOV, dl, VT, FalseVal, TrueVal, ARMcc, CCR, Cmp); if (CondCode2 != ARMCC::AL) { SDValue ARMcc2 = DAG.getConstant(CondCode2, MVT::i32); // FIXME: Needs another CMP because flag can have but one use. SDValue Cmp2 = getVFPCmp(LHS, RHS, DAG, dl); Result = DAG.getNode(ARMISD::CMOV, dl, VT, Result, TrueVal, ARMcc2, CCR, Cmp2); } return Result; } /// canChangeToInt - Given the fp compare operand, return true if it is suitable /// to morph to an integer compare sequence. static bool canChangeToInt(SDValue Op, bool &SeenZero, const ARMSubtarget *Subtarget) { SDNode *N = Op.getNode(); if (!N->hasOneUse()) // Otherwise it requires moving the value from fp to integer registers. return false; if (!N->getNumValues()) return false; EVT VT = Op.getValueType(); if (VT != MVT::f32 && !Subtarget->isFPBrccSlow()) // f32 case is generally profitable. f64 case only makes sense when vcmpe + // vmrs are very slow, e.g. cortex-a8. return false; if (isFloatingPointZero(Op)) { SeenZero = true; return true; } return ISD::isNormalLoad(N); } static SDValue bitcastf32Toi32(SDValue Op, SelectionDAG &DAG) { if (isFloatingPointZero(Op)) return DAG.getConstant(0, MVT::i32); if (LoadSDNode *Ld = dyn_cast(Op)) return DAG.getLoad(MVT::i32, Op.getDebugLoc(), Ld->getChain(), Ld->getBasePtr(), Ld->getPointerInfo(), Ld->isVolatile(), Ld->isNonTemporal(), Ld->getAlignment()); llvm_unreachable("Unknown VFP cmp argument!"); } static void expandf64Toi32(SDValue Op, SelectionDAG &DAG, SDValue &RetVal1, SDValue &RetVal2) { if (isFloatingPointZero(Op)) { RetVal1 = DAG.getConstant(0, MVT::i32); RetVal2 = DAG.getConstant(0, MVT::i32); return; } if (LoadSDNode *Ld = dyn_cast(Op)) { SDValue Ptr = Ld->getBasePtr(); RetVal1 = DAG.getLoad(MVT::i32, Op.getDebugLoc(), Ld->getChain(), Ptr, Ld->getPointerInfo(), Ld->isVolatile(), Ld->isNonTemporal(), Ld->getAlignment()); EVT PtrType = Ptr.getValueType(); unsigned NewAlign = MinAlign(Ld->getAlignment(), 4); SDValue NewPtr = DAG.getNode(ISD::ADD, Op.getDebugLoc(), PtrType, Ptr, DAG.getConstant(4, PtrType)); RetVal2 = DAG.getLoad(MVT::i32, Op.getDebugLoc(), Ld->getChain(), NewPtr, Ld->getPointerInfo().getWithOffset(4), Ld->isVolatile(), Ld->isNonTemporal(), NewAlign); return; } llvm_unreachable("Unknown VFP cmp argument!"); } /// OptimizeVFPBrcond - With -enable-unsafe-fp-math, it's legal to optimize some /// f32 and even f64 comparisons to integer ones. SDValue ARMTargetLowering::OptimizeVFPBrcond(SDValue Op, SelectionDAG &DAG) const { SDValue Chain = Op.getOperand(0); ISD::CondCode CC = cast(Op.getOperand(1))->get(); SDValue LHS = Op.getOperand(2); SDValue RHS = Op.getOperand(3); SDValue Dest = Op.getOperand(4); DebugLoc dl = Op.getDebugLoc(); bool SeenZero = false; if (canChangeToInt(LHS, SeenZero, Subtarget) && canChangeToInt(RHS, SeenZero, Subtarget) && // If one of the operand is zero, it's safe to ignore the NaN case since // we only care about equality comparisons. (SeenZero || (DAG.isKnownNeverNaN(LHS) && DAG.isKnownNeverNaN(RHS)))) { // If unsafe fp math optimization is enabled and there are no other uses of // the CMP operands, and the condition code is EQ or NE, we can optimize it // to an integer comparison. if (CC == ISD::SETOEQ) CC = ISD::SETEQ; else if (CC == ISD::SETUNE) CC = ISD::SETNE; SDValue ARMcc; if (LHS.getValueType() == MVT::f32) { LHS = bitcastf32Toi32(LHS, DAG); RHS = bitcastf32Toi32(RHS, DAG); SDValue Cmp = getARMCmp(LHS, RHS, CC, ARMcc, DAG, dl); SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32); return DAG.getNode(ARMISD::BRCOND, dl, MVT::Other, Chain, Dest, ARMcc, CCR, Cmp); } SDValue LHS1, LHS2; SDValue RHS1, RHS2; expandf64Toi32(LHS, DAG, LHS1, LHS2); expandf64Toi32(RHS, DAG, RHS1, RHS2); ARMCC::CondCodes CondCode = IntCCToARMCC(CC); ARMcc = DAG.getConstant(CondCode, MVT::i32); SDVTList VTList = DAG.getVTList(MVT::Other, MVT::Glue); SDValue Ops[] = { Chain, ARMcc, LHS1, LHS2, RHS1, RHS2, Dest }; return DAG.getNode(ARMISD::BCC_i64, dl, VTList, Ops, 7); } return SDValue(); } SDValue ARMTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const { SDValue Chain = Op.getOperand(0); ISD::CondCode CC = cast(Op.getOperand(1))->get(); SDValue LHS = Op.getOperand(2); SDValue RHS = Op.getOperand(3); SDValue Dest = Op.getOperand(4); DebugLoc dl = Op.getDebugLoc(); if (LHS.getValueType() == MVT::i32) { SDValue ARMcc; SDValue Cmp = getARMCmp(LHS, RHS, CC, ARMcc, DAG, dl); SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32); return DAG.getNode(ARMISD::BRCOND, dl, MVT::Other, Chain, Dest, ARMcc, CCR, Cmp); } assert(LHS.getValueType() == MVT::f32 || LHS.getValueType() == MVT::f64); if (UnsafeFPMath && (CC == ISD::SETEQ || CC == ISD::SETOEQ || CC == ISD::SETNE || CC == ISD::SETUNE)) { SDValue Result = OptimizeVFPBrcond(Op, DAG); if (Result.getNode()) return Result; } ARMCC::CondCodes CondCode, CondCode2; FPCCToARMCC(CC, CondCode, CondCode2); SDValue ARMcc = DAG.getConstant(CondCode, MVT::i32); SDValue Cmp = getVFPCmp(LHS, RHS, DAG, dl); SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32); SDVTList VTList = DAG.getVTList(MVT::Other, MVT::Glue); SDValue Ops[] = { Chain, Dest, ARMcc, CCR, Cmp }; SDValue Res = DAG.getNode(ARMISD::BRCOND, dl, VTList, Ops, 5); if (CondCode2 != ARMCC::AL) { ARMcc = DAG.getConstant(CondCode2, MVT::i32); SDValue Ops[] = { Res, Dest, ARMcc, CCR, Res.getValue(1) }; Res = DAG.getNode(ARMISD::BRCOND, dl, VTList, Ops, 5); } return Res; } SDValue ARMTargetLowering::LowerBR_JT(SDValue Op, SelectionDAG &DAG) const { SDValue Chain = Op.getOperand(0); SDValue Table = Op.getOperand(1); SDValue Index = Op.getOperand(2); DebugLoc dl = Op.getDebugLoc(); EVT PTy = getPointerTy(); JumpTableSDNode *JT = cast(Table); ARMFunctionInfo *AFI = DAG.getMachineFunction().getInfo(); SDValue UId = DAG.getConstant(AFI->createJumpTableUId(), PTy); SDValue JTI = DAG.getTargetJumpTable(JT->getIndex(), PTy); Table = DAG.getNode(ARMISD::WrapperJT, dl, MVT::i32, JTI, UId); Index = DAG.getNode(ISD::MUL, dl, PTy, Index, DAG.getConstant(4, PTy)); SDValue Addr = DAG.getNode(ISD::ADD, dl, PTy, Index, Table); if (Subtarget->isThumb2()) { // Thumb2 uses a two-level jump. That is, it jumps into the jump table // which does another jump to the destination. This also makes it easier // to translate it to TBB / TBH later. // FIXME: This might not work if the function is extremely large. return DAG.getNode(ARMISD::BR2_JT, dl, MVT::Other, Chain, Addr, Op.getOperand(2), JTI, UId); } if (getTargetMachine().getRelocationModel() == Reloc::PIC_) { Addr = DAG.getLoad((EVT)MVT::i32, dl, Chain, Addr, MachinePointerInfo::getJumpTable(), false, false, 0); Chain = Addr.getValue(1); Addr = DAG.getNode(ISD::ADD, dl, PTy, Addr, Table); return DAG.getNode(ARMISD::BR_JT, dl, MVT::Other, Chain, Addr, JTI, UId); } else { Addr = DAG.getLoad(PTy, dl, Chain, Addr, MachinePointerInfo::getJumpTable(), false, false, 0); Chain = Addr.getValue(1); return DAG.getNode(ARMISD::BR_JT, dl, MVT::Other, Chain, Addr, JTI, UId); } } static SDValue LowerFP_TO_INT(SDValue Op, SelectionDAG &DAG) { DebugLoc dl = Op.getDebugLoc(); unsigned Opc; switch (Op.getOpcode()) { default: assert(0 && "Invalid opcode!"); case ISD::FP_TO_SINT: Opc = ARMISD::FTOSI; break; case ISD::FP_TO_UINT: Opc = ARMISD::FTOUI; break; } Op = DAG.getNode(Opc, dl, MVT::f32, Op.getOperand(0)); return DAG.getNode(ISD::BITCAST, dl, MVT::i32, Op); } static SDValue LowerVectorINT_TO_FP(SDValue Op, SelectionDAG &DAG) { EVT VT = Op.getValueType(); DebugLoc dl = Op.getDebugLoc(); assert(Op.getOperand(0).getValueType() == MVT::v4i16 && "Invalid type for custom lowering!"); if (VT != MVT::v4f32) return DAG.UnrollVectorOp(Op.getNode()); unsigned CastOpc; unsigned Opc; switch (Op.getOpcode()) { default: assert(0 && "Invalid opcode!"); case ISD::SINT_TO_FP: CastOpc = ISD::SIGN_EXTEND; Opc = ISD::SINT_TO_FP; break; case ISD::UINT_TO_FP: CastOpc = ISD::ZERO_EXTEND; Opc = ISD::UINT_TO_FP; break; } Op = DAG.getNode(CastOpc, dl, MVT::v4i32, Op.getOperand(0)); return DAG.getNode(Opc, dl, VT, Op); } static SDValue LowerINT_TO_FP(SDValue Op, SelectionDAG &DAG) { EVT VT = Op.getValueType(); if (VT.isVector()) return LowerVectorINT_TO_FP(Op, DAG); DebugLoc dl = Op.getDebugLoc(); unsigned Opc; switch (Op.getOpcode()) { default: assert(0 && "Invalid opcode!"); case ISD::SINT_TO_FP: Opc = ARMISD::SITOF; break; case ISD::UINT_TO_FP: Opc = ARMISD::UITOF; break; } Op = DAG.getNode(ISD::BITCAST, dl, MVT::f32, Op.getOperand(0)); return DAG.getNode(Opc, dl, VT, Op); } SDValue ARMTargetLowering::LowerFCOPYSIGN(SDValue Op, SelectionDAG &DAG) const { // Implement fcopysign with a fabs and a conditional fneg. SDValue Tmp0 = Op.getOperand(0); SDValue Tmp1 = Op.getOperand(1); DebugLoc dl = Op.getDebugLoc(); EVT VT = Op.getValueType(); EVT SrcVT = Tmp1.getValueType(); bool InGPR = Tmp0.getOpcode() == ISD::BITCAST || Tmp0.getOpcode() == ARMISD::VMOVDRR; bool UseNEON = !InGPR && Subtarget->hasNEON(); if (UseNEON) { // Use VBSL to copy the sign bit. unsigned EncodedVal = ARM_AM::createNEONModImm(0x6, 0x80); SDValue Mask = DAG.getNode(ARMISD::VMOVIMM, dl, MVT::v2i32, DAG.getTargetConstant(EncodedVal, MVT::i32)); EVT OpVT = (VT == MVT::f32) ? MVT::v2i32 : MVT::v1i64; if (VT == MVT::f64) Mask = DAG.getNode(ARMISD::VSHL, dl, OpVT, DAG.getNode(ISD::BITCAST, dl, OpVT, Mask), DAG.getConstant(32, MVT::i32)); else /*if (VT == MVT::f32)*/ Tmp0 = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, MVT::v2f32, Tmp0); if (SrcVT == MVT::f32) { Tmp1 = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, MVT::v2f32, Tmp1); if (VT == MVT::f64) Tmp1 = DAG.getNode(ARMISD::VSHL, dl, OpVT, DAG.getNode(ISD::BITCAST, dl, OpVT, Tmp1), DAG.getConstant(32, MVT::i32)); } else if (VT == MVT::f32) Tmp1 = DAG.getNode(ARMISD::VSHRu, dl, MVT::v1i64, DAG.getNode(ISD::BITCAST, dl, MVT::v1i64, Tmp1), DAG.getConstant(32, MVT::i32)); Tmp0 = DAG.getNode(ISD::BITCAST, dl, OpVT, Tmp0); Tmp1 = DAG.getNode(ISD::BITCAST, dl, OpVT, Tmp1); SDValue AllOnes = DAG.getTargetConstant(ARM_AM::createNEONModImm(0xe, 0xff), MVT::i32); AllOnes = DAG.getNode(ARMISD::VMOVIMM, dl, MVT::v8i8, AllOnes); SDValue MaskNot = DAG.getNode(ISD::XOR, dl, OpVT, Mask, DAG.getNode(ISD::BITCAST, dl, OpVT, AllOnes)); SDValue Res = DAG.getNode(ISD::OR, dl, OpVT, DAG.getNode(ISD::AND, dl, OpVT, Tmp1, Mask), DAG.getNode(ISD::AND, dl, OpVT, Tmp0, MaskNot)); if (VT == MVT::f32) { Res = DAG.getNode(ISD::BITCAST, dl, MVT::v2f32, Res); Res = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, MVT::f32, Res, DAG.getConstant(0, MVT::i32)); } else { Res = DAG.getNode(ISD::BITCAST, dl, MVT::f64, Res); } return Res; } // Bitcast operand 1 to i32. if (SrcVT == MVT::f64) Tmp1 = DAG.getNode(ARMISD::VMOVRRD, dl, DAG.getVTList(MVT::i32, MVT::i32), &Tmp1, 1).getValue(1); Tmp1 = DAG.getNode(ISD::BITCAST, dl, MVT::i32, Tmp1); // Or in the signbit with integer operations. SDValue Mask1 = DAG.getConstant(0x80000000, MVT::i32); SDValue Mask2 = DAG.getConstant(0x7fffffff, MVT::i32); Tmp1 = DAG.getNode(ISD::AND, dl, MVT::i32, Tmp1, Mask1); if (VT == MVT::f32) { Tmp0 = DAG.getNode(ISD::AND, dl, MVT::i32, DAG.getNode(ISD::BITCAST, dl, MVT::i32, Tmp0), Mask2); return DAG.getNode(ISD::BITCAST, dl, MVT::f32, DAG.getNode(ISD::OR, dl, MVT::i32, Tmp0, Tmp1)); } // f64: Or the high part with signbit and then combine two parts. Tmp0 = DAG.getNode(ARMISD::VMOVRRD, dl, DAG.getVTList(MVT::i32, MVT::i32), &Tmp0, 1); SDValue Lo = Tmp0.getValue(0); SDValue Hi = DAG.getNode(ISD::AND, dl, MVT::i32, Tmp0.getValue(1), Mask2); Hi = DAG.getNode(ISD::OR, dl, MVT::i32, Hi, Tmp1); return DAG.getNode(ARMISD::VMOVDRR, dl, MVT::f64, Lo, Hi); } SDValue ARMTargetLowering::LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const{ MachineFunction &MF = DAG.getMachineFunction(); MachineFrameInfo *MFI = MF.getFrameInfo(); MFI->setReturnAddressIsTaken(true); EVT VT = Op.getValueType(); DebugLoc dl = Op.getDebugLoc(); unsigned Depth = cast(Op.getOperand(0))->getZExtValue(); if (Depth) { SDValue FrameAddr = LowerFRAMEADDR(Op, DAG); SDValue Offset = DAG.getConstant(4, MVT::i32); return DAG.getLoad(VT, dl, DAG.getEntryNode(), DAG.getNode(ISD::ADD, dl, VT, FrameAddr, Offset), MachinePointerInfo(), false, false, 0); } // Return LR, which contains the return address. Mark it an implicit live-in. unsigned Reg = MF.addLiveIn(ARM::LR, getRegClassFor(MVT::i32)); return DAG.getCopyFromReg(DAG.getEntryNode(), dl, Reg, VT); } SDValue ARMTargetLowering::LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const { MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); MFI->setFrameAddressIsTaken(true); EVT VT = Op.getValueType(); DebugLoc dl = Op.getDebugLoc(); // FIXME probably not meaningful unsigned Depth = cast(Op.getOperand(0))->getZExtValue(); unsigned FrameReg = (Subtarget->isThumb() || Subtarget->isTargetDarwin()) ? ARM::R7 : ARM::R11; SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl, FrameReg, VT); while (Depth--) FrameAddr = DAG.getLoad(VT, dl, DAG.getEntryNode(), FrameAddr, MachinePointerInfo(), false, false, 0); return FrameAddr; } /// ExpandBITCAST - If the target supports VFP, this function is called to /// expand a bit convert where either the source or destination type is i64 to /// use a VMOVDRR or VMOVRRD node. This should not be done when the non-i64 /// operand type is illegal (e.g., v2f32 for a target that doesn't support /// vectors), since the legalizer won't know what to do with that. static SDValue ExpandBITCAST(SDNode *N, SelectionDAG &DAG) { const TargetLowering &TLI = DAG.getTargetLoweringInfo(); DebugLoc dl = N->getDebugLoc(); SDValue Op = N->getOperand(0); // This function is only supposed to be called for i64 types, either as the // source or destination of the bit convert. EVT SrcVT = Op.getValueType(); EVT DstVT = N->getValueType(0); assert((SrcVT == MVT::i64 || DstVT == MVT::i64) && "ExpandBITCAST called for non-i64 type"); // Turn i64->f64 into VMOVDRR. if (SrcVT == MVT::i64 && TLI.isTypeLegal(DstVT)) { SDValue Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, Op, DAG.getConstant(0, MVT::i32)); SDValue Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, Op, DAG.getConstant(1, MVT::i32)); return DAG.getNode(ISD::BITCAST, dl, DstVT, DAG.getNode(ARMISD::VMOVDRR, dl, MVT::f64, Lo, Hi)); } // Turn f64->i64 into VMOVRRD. if (DstVT == MVT::i64 && TLI.isTypeLegal(SrcVT)) { SDValue Cvt = DAG.getNode(ARMISD::VMOVRRD, dl, DAG.getVTList(MVT::i32, MVT::i32), &Op, 1); // Merge the pieces into a single i64 value. return DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, Cvt, Cvt.getValue(1)); } return SDValue(); } /// getZeroVector - Returns a vector of specified type with all zero elements. /// Zero vectors are used to represent vector negation and in those cases /// will be implemented with the NEON VNEG instruction. However, VNEG does /// not support i64 elements, so sometimes the zero vectors will need to be /// explicitly constructed. Regardless, use a canonical VMOV to create the /// zero vector. static SDValue getZeroVector(EVT VT, SelectionDAG &DAG, DebugLoc dl) { assert(VT.isVector() && "Expected a vector type"); // The canonical modified immediate encoding of a zero vector is....0! SDValue EncodedVal = DAG.getTargetConstant(0, MVT::i32); EVT VmovVT = VT.is128BitVector() ? MVT::v4i32 : MVT::v2i32; SDValue Vmov = DAG.getNode(ARMISD::VMOVIMM, dl, VmovVT, EncodedVal); return DAG.getNode(ISD::BITCAST, dl, VT, Vmov); } /// LowerShiftRightParts - Lower SRA_PARTS, which returns two /// i32 values and take a 2 x i32 value to shift plus a shift amount. SDValue ARMTargetLowering::LowerShiftRightParts(SDValue Op, SelectionDAG &DAG) const { assert(Op.getNumOperands() == 3 && "Not a double-shift!"); EVT VT = Op.getValueType(); unsigned VTBits = VT.getSizeInBits(); DebugLoc dl = Op.getDebugLoc(); SDValue ShOpLo = Op.getOperand(0); SDValue ShOpHi = Op.getOperand(1); SDValue ShAmt = Op.getOperand(2); SDValue ARMcc; unsigned Opc = (Op.getOpcode() == ISD::SRA_PARTS) ? ISD::SRA : ISD::SRL; assert(Op.getOpcode() == ISD::SRA_PARTS || Op.getOpcode() == ISD::SRL_PARTS); SDValue RevShAmt = DAG.getNode(ISD::SUB, dl, MVT::i32, DAG.getConstant(VTBits, MVT::i32), ShAmt); SDValue Tmp1 = DAG.getNode(ISD::SRL, dl, VT, ShOpLo, ShAmt); SDValue ExtraShAmt = DAG.getNode(ISD::SUB, dl, MVT::i32, ShAmt, DAG.getConstant(VTBits, MVT::i32)); SDValue Tmp2 = DAG.getNode(ISD::SHL, dl, VT, ShOpHi, RevShAmt); SDValue FalseVal = DAG.getNode(ISD::OR, dl, VT, Tmp1, Tmp2); SDValue TrueVal = DAG.getNode(Opc, dl, VT, ShOpHi, ExtraShAmt); SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32); SDValue Cmp = getARMCmp(ExtraShAmt, DAG.getConstant(0, MVT::i32), ISD::SETGE, ARMcc, DAG, dl); SDValue Hi = DAG.getNode(Opc, dl, VT, ShOpHi, ShAmt); SDValue Lo = DAG.getNode(ARMISD::CMOV, dl, VT, FalseVal, TrueVal, ARMcc, CCR, Cmp); SDValue Ops[2] = { Lo, Hi }; return DAG.getMergeValues(Ops, 2, dl); } /// LowerShiftLeftParts - Lower SHL_PARTS, which returns two /// i32 values and take a 2 x i32 value to shift plus a shift amount. SDValue ARMTargetLowering::LowerShiftLeftParts(SDValue Op, SelectionDAG &DAG) const { assert(Op.getNumOperands() == 3 && "Not a double-shift!"); EVT VT = Op.getValueType(); unsigned VTBits = VT.getSizeInBits(); DebugLoc dl = Op.getDebugLoc(); SDValue ShOpLo = Op.getOperand(0); SDValue ShOpHi = Op.getOperand(1); SDValue ShAmt = Op.getOperand(2); SDValue ARMcc; assert(Op.getOpcode() == ISD::SHL_PARTS); SDValue RevShAmt = DAG.getNode(ISD::SUB, dl, MVT::i32, DAG.getConstant(VTBits, MVT::i32), ShAmt); SDValue Tmp1 = DAG.getNode(ISD::SRL, dl, VT, ShOpLo, RevShAmt); SDValue ExtraShAmt = DAG.getNode(ISD::SUB, dl, MVT::i32, ShAmt, DAG.getConstant(VTBits, MVT::i32)); SDValue Tmp2 = DAG.getNode(ISD::SHL, dl, VT, ShOpHi, ShAmt); SDValue Tmp3 = DAG.getNode(ISD::SHL, dl, VT, ShOpLo, ExtraShAmt); SDValue FalseVal = DAG.getNode(ISD::OR, dl, VT, Tmp1, Tmp2); SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32); SDValue Cmp = getARMCmp(ExtraShAmt, DAG.getConstant(0, MVT::i32), ISD::SETGE, ARMcc, DAG, dl); SDValue Lo = DAG.getNode(ISD::SHL, dl, VT, ShOpLo, ShAmt); SDValue Hi = DAG.getNode(ARMISD::CMOV, dl, VT, FalseVal, Tmp3, ARMcc, CCR, Cmp); SDValue Ops[2] = { Lo, Hi }; return DAG.getMergeValues(Ops, 2, dl); } SDValue ARMTargetLowering::LowerFLT_ROUNDS_(SDValue Op, SelectionDAG &DAG) const { // The rounding mode is in bits 23:22 of the FPSCR. // The ARM rounding mode value to FLT_ROUNDS mapping is 0->1, 1->2, 2->3, 3->0 // The formula we use to implement this is (((FPSCR + 1 << 22) >> 22) & 3) // so that the shift + and get folded into a bitfield extract. DebugLoc dl = Op.getDebugLoc(); SDValue FPSCR = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, MVT::i32, DAG.getConstant(Intrinsic::arm_get_fpscr, MVT::i32)); SDValue FltRounds = DAG.getNode(ISD::ADD, dl, MVT::i32, FPSCR, DAG.getConstant(1U << 22, MVT::i32)); SDValue RMODE = DAG.getNode(ISD::SRL, dl, MVT::i32, FltRounds, DAG.getConstant(22, MVT::i32)); return DAG.getNode(ISD::AND, dl, MVT::i32, RMODE, DAG.getConstant(3, MVT::i32)); } static SDValue LowerCTTZ(SDNode *N, SelectionDAG &DAG, const ARMSubtarget *ST) { EVT VT = N->getValueType(0); DebugLoc dl = N->getDebugLoc(); if (!ST->hasV6T2Ops()) return SDValue(); SDValue rbit = DAG.getNode(ARMISD::RBIT, dl, VT, N->getOperand(0)); return DAG.getNode(ISD::CTLZ, dl, VT, rbit); } static SDValue LowerShift(SDNode *N, SelectionDAG &DAG, const ARMSubtarget *ST) { EVT VT = N->getValueType(0); DebugLoc dl = N->getDebugLoc(); if (!VT.isVector()) return SDValue(); // Lower vector shifts on NEON to use VSHL. assert(ST->hasNEON() && "unexpected vector shift"); // Left shifts translate directly to the vshiftu intrinsic. if (N->getOpcode() == ISD::SHL) return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, VT, DAG.getConstant(Intrinsic::arm_neon_vshiftu, MVT::i32), N->getOperand(0), N->getOperand(1)); assert((N->getOpcode() == ISD::SRA || N->getOpcode() == ISD::SRL) && "unexpected vector shift opcode"); // NEON uses the same intrinsics for both left and right shifts. For // right shifts, the shift amounts are negative, so negate the vector of // shift amounts. EVT ShiftVT = N->getOperand(1).getValueType(); SDValue NegatedCount = DAG.getNode(ISD::SUB, dl, ShiftVT, getZeroVector(ShiftVT, DAG, dl), N->getOperand(1)); Intrinsic::ID vshiftInt = (N->getOpcode() == ISD::SRA ? Intrinsic::arm_neon_vshifts : Intrinsic::arm_neon_vshiftu); return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, VT, DAG.getConstant(vshiftInt, MVT::i32), N->getOperand(0), NegatedCount); } static SDValue Expand64BitShift(SDNode *N, SelectionDAG &DAG, const ARMSubtarget *ST) { EVT VT = N->getValueType(0); DebugLoc dl = N->getDebugLoc(); // We can get here for a node like i32 = ISD::SHL i32, i64 if (VT != MVT::i64) return SDValue(); assert((N->getOpcode() == ISD::SRL || N->getOpcode() == ISD::SRA) && "Unknown shift to lower!"); // We only lower SRA, SRL of 1 here, all others use generic lowering. if (!isa(N->getOperand(1)) || cast(N->getOperand(1))->getZExtValue() != 1) return SDValue(); // If we are in thumb mode, we don't have RRX. if (ST->isThumb1Only()) return SDValue(); // Okay, we have a 64-bit SRA or SRL of 1. Lower this to an RRX expr. SDValue Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, N->getOperand(0), DAG.getConstant(0, MVT::i32)); SDValue Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, N->getOperand(0), DAG.getConstant(1, MVT::i32)); // First, build a SRA_FLAG/SRL_FLAG op, which shifts the top part by one and // captures the result into a carry flag. unsigned Opc = N->getOpcode() == ISD::SRL ? ARMISD::SRL_FLAG:ARMISD::SRA_FLAG; Hi = DAG.getNode(Opc, dl, DAG.getVTList(MVT::i32, MVT::Glue), &Hi, 1); // The low part is an ARMISD::RRX operand, which shifts the carry in. Lo = DAG.getNode(ARMISD::RRX, dl, MVT::i32, Lo, Hi.getValue(1)); // Merge the pieces into a single i64 value. return DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, Lo, Hi); } static SDValue LowerVSETCC(SDValue Op, SelectionDAG &DAG) { SDValue TmpOp0, TmpOp1; bool Invert = false; bool Swap = false; unsigned Opc = 0; SDValue Op0 = Op.getOperand(0); SDValue Op1 = Op.getOperand(1); SDValue CC = Op.getOperand(2); EVT VT = Op.getValueType(); ISD::CondCode SetCCOpcode = cast(CC)->get(); DebugLoc dl = Op.getDebugLoc(); if (Op.getOperand(1).getValueType().isFloatingPoint()) { switch (SetCCOpcode) { default: llvm_unreachable("Illegal FP comparison"); break; case ISD::SETUNE: case ISD::SETNE: Invert = true; // Fallthrough case ISD::SETOEQ: case ISD::SETEQ: Opc = ARMISD::VCEQ; break; case ISD::SETOLT: case ISD::SETLT: Swap = true; // Fallthrough case ISD::SETOGT: case ISD::SETGT: Opc = ARMISD::VCGT; break; case ISD::SETOLE: case ISD::SETLE: Swap = true; // Fallthrough case ISD::SETOGE: case ISD::SETGE: Opc = ARMISD::VCGE; break; case ISD::SETUGE: Swap = true; // Fallthrough case ISD::SETULE: Invert = true; Opc = ARMISD::VCGT; break; case ISD::SETUGT: Swap = true; // Fallthrough case ISD::SETULT: Invert = true; Opc = ARMISD::VCGE; break; case ISD::SETUEQ: Invert = true; // Fallthrough case ISD::SETONE: // Expand this to (OLT | OGT). TmpOp0 = Op0; TmpOp1 = Op1; Opc = ISD::OR; Op0 = DAG.getNode(ARMISD::VCGT, dl, VT, TmpOp1, TmpOp0); Op1 = DAG.getNode(ARMISD::VCGT, dl, VT, TmpOp0, TmpOp1); break; case ISD::SETUO: Invert = true; // Fallthrough case ISD::SETO: // Expand this to (OLT | OGE). TmpOp0 = Op0; TmpOp1 = Op1; Opc = ISD::OR; Op0 = DAG.getNode(ARMISD::VCGT, dl, VT, TmpOp1, TmpOp0); Op1 = DAG.getNode(ARMISD::VCGE, dl, VT, TmpOp0, TmpOp1); break; } } else { // Integer comparisons. switch (SetCCOpcode) { default: llvm_unreachable("Illegal integer comparison"); break; case ISD::SETNE: Invert = true; case ISD::SETEQ: Opc = ARMISD::VCEQ; break; case ISD::SETLT: Swap = true; case ISD::SETGT: Opc = ARMISD::VCGT; break; case ISD::SETLE: Swap = true; case ISD::SETGE: Opc = ARMISD::VCGE; break; case ISD::SETULT: Swap = true; case ISD::SETUGT: Opc = ARMISD::VCGTU; break; case ISD::SETULE: Swap = true; case ISD::SETUGE: Opc = ARMISD::VCGEU; break; } // Detect VTST (Vector Test Bits) = icmp ne (and (op0, op1), zero). if (Opc == ARMISD::VCEQ) { SDValue AndOp; if (ISD::isBuildVectorAllZeros(Op1.getNode())) AndOp = Op0; else if (ISD::isBuildVectorAllZeros(Op0.getNode())) AndOp = Op1; // Ignore bitconvert. if (AndOp.getNode() && AndOp.getOpcode() == ISD::BITCAST) AndOp = AndOp.getOperand(0); if (AndOp.getNode() && AndOp.getOpcode() == ISD::AND) { Opc = ARMISD::VTST; Op0 = DAG.getNode(ISD::BITCAST, dl, VT, AndOp.getOperand(0)); Op1 = DAG.getNode(ISD::BITCAST, dl, VT, AndOp.getOperand(1)); Invert = !Invert; } } } if (Swap) std::swap(Op0, Op1); // If one of the operands is a constant vector zero, attempt to fold the // comparison to a specialized compare-against-zero form. SDValue SingleOp; if (ISD::isBuildVectorAllZeros(Op1.getNode())) SingleOp = Op0; else if (ISD::isBuildVectorAllZeros(Op0.getNode())) { if (Opc == ARMISD::VCGE) Opc = ARMISD::VCLEZ; else if (Opc == ARMISD::VCGT) Opc = ARMISD::VCLTZ; SingleOp = Op1; } SDValue Result; if (SingleOp.getNode()) { switch (Opc) { case ARMISD::VCEQ: Result = DAG.getNode(ARMISD::VCEQZ, dl, VT, SingleOp); break; case ARMISD::VCGE: Result = DAG.getNode(ARMISD::VCGEZ, dl, VT, SingleOp); break; case ARMISD::VCLEZ: Result = DAG.getNode(ARMISD::VCLEZ, dl, VT, SingleOp); break; case ARMISD::VCGT: Result = DAG.getNode(ARMISD::VCGTZ, dl, VT, SingleOp); break; case ARMISD::VCLTZ: Result = DAG.getNode(ARMISD::VCLTZ, dl, VT, SingleOp); break; default: Result = DAG.getNode(Opc, dl, VT, Op0, Op1); } } else { Result = DAG.getNode(Opc, dl, VT, Op0, Op1); } if (Invert) Result = DAG.getNOT(dl, Result, VT); return Result; } /// isNEONModifiedImm - Check if the specified splat value corresponds to a /// valid vector constant for a NEON instruction with a "modified immediate" /// operand (e.g., VMOV). If so, return the encoded value. static SDValue isNEONModifiedImm(uint64_t SplatBits, uint64_t SplatUndef, unsigned SplatBitSize, SelectionDAG &DAG, EVT &VT, bool is128Bits, NEONModImmType type) { unsigned OpCmode, Imm; // SplatBitSize is set to the smallest size that splats the vector, so a // zero vector will always have SplatBitSize == 8. However, NEON modified // immediate instructions others than VMOV do not support the 8-bit encoding // of a zero vector, and the default encoding of zero is supposed to be the // 32-bit version. if (SplatBits == 0) SplatBitSize = 32; switch (SplatBitSize) { case 8: if (type != VMOVModImm) return SDValue(); // Any 1-byte value is OK. Op=0, Cmode=1110. assert((SplatBits & ~0xff) == 0 && "one byte splat value is too big"); OpCmode = 0xe; Imm = SplatBits; VT = is128Bits ? MVT::v16i8 : MVT::v8i8; break; case 16: // NEON's 16-bit VMOV supports splat values where only one byte is nonzero. VT = is128Bits ? MVT::v8i16 : MVT::v4i16; if ((SplatBits & ~0xff) == 0) { // Value = 0x00nn: Op=x, Cmode=100x. OpCmode = 0x8; Imm = SplatBits; break; } if ((SplatBits & ~0xff00) == 0) { // Value = 0xnn00: Op=x, Cmode=101x. OpCmode = 0xa; Imm = SplatBits >> 8; break; } return SDValue(); case 32: // NEON's 32-bit VMOV supports splat values where: // * only one byte is nonzero, or // * the least significant byte is 0xff and the second byte is nonzero, or // * the least significant 2 bytes are 0xff and the third is nonzero. VT = is128Bits ? MVT::v4i32 : MVT::v2i32; if ((SplatBits & ~0xff) == 0) { // Value = 0x000000nn: Op=x, Cmode=000x. OpCmode = 0; Imm = SplatBits; break; } if ((SplatBits & ~0xff00) == 0) { // Value = 0x0000nn00: Op=x, Cmode=001x. OpCmode = 0x2; Imm = SplatBits >> 8; break; } if ((SplatBits & ~0xff0000) == 0) { // Value = 0x00nn0000: Op=x, Cmode=010x. OpCmode = 0x4; Imm = SplatBits >> 16; break; } if ((SplatBits & ~0xff000000) == 0) { // Value = 0xnn000000: Op=x, Cmode=011x. OpCmode = 0x6; Imm = SplatBits >> 24; break; } // cmode == 0b1100 and cmode == 0b1101 are not supported for VORR or VBIC if (type == OtherModImm) return SDValue(); if ((SplatBits & ~0xffff) == 0 && ((SplatBits | SplatUndef) & 0xff) == 0xff) { // Value = 0x0000nnff: Op=x, Cmode=1100. OpCmode = 0xc; Imm = SplatBits >> 8; SplatBits |= 0xff; break; } if ((SplatBits & ~0xffffff) == 0 && ((SplatBits | SplatUndef) & 0xffff) == 0xffff) { // Value = 0x00nnffff: Op=x, Cmode=1101. OpCmode = 0xd; Imm = SplatBits >> 16; SplatBits |= 0xffff; break; } // Note: there are a few 32-bit splat values (specifically: 00ffff00, // ff000000, ff0000ff, and ffff00ff) that are valid for VMOV.I64 but not // VMOV.I32. A (very) minor optimization would be to replicate the value // and fall through here to test for a valid 64-bit splat. But, then the // caller would also need to check and handle the change in size. return SDValue(); case 64: { if (type != VMOVModImm) return SDValue(); // NEON has a 64-bit VMOV splat where each byte is either 0 or 0xff. uint64_t BitMask = 0xff; uint64_t Val = 0; unsigned ImmMask = 1; Imm = 0; for (int ByteNum = 0; ByteNum < 8; ++ByteNum) { if (((SplatBits | SplatUndef) & BitMask) == BitMask) { Val |= BitMask; Imm |= ImmMask; } else if ((SplatBits & BitMask) != 0) { return SDValue(); } BitMask <<= 8; ImmMask <<= 1; } // Op=1, Cmode=1110. OpCmode = 0x1e; SplatBits = Val; VT = is128Bits ? MVT::v2i64 : MVT::v1i64; break; } default: llvm_unreachable("unexpected size for isNEONModifiedImm"); return SDValue(); } unsigned EncodedVal = ARM_AM::createNEONModImm(OpCmode, Imm); return DAG.getTargetConstant(EncodedVal, MVT::i32); } static bool isVEXTMask(const SmallVectorImpl &M, EVT VT, bool &ReverseVEXT, unsigned &Imm) { unsigned NumElts = VT.getVectorNumElements(); ReverseVEXT = false; // Assume that the first shuffle index is not UNDEF. Fail if it is. if (M[0] < 0) return false; Imm = M[0]; // If this is a VEXT shuffle, the immediate value is the index of the first // element. The other shuffle indices must be the successive elements after // the first one. unsigned ExpectedElt = Imm; for (unsigned i = 1; i < NumElts; ++i) { // Increment the expected index. If it wraps around, it may still be // a VEXT but the source vectors must be swapped. ExpectedElt += 1; if (ExpectedElt == NumElts * 2) { ExpectedElt = 0; ReverseVEXT = true; } if (M[i] < 0) continue; // ignore UNDEF indices if (ExpectedElt != static_cast(M[i])) return false; } // Adjust the index value if the source operands will be swapped. if (ReverseVEXT) Imm -= NumElts; return true; } /// isVREVMask - Check if a vector shuffle corresponds to a VREV /// instruction with the specified blocksize. (The order of the elements /// within each block of the vector is reversed.) static bool isVREVMask(const SmallVectorImpl &M, EVT VT, unsigned BlockSize) { assert((BlockSize==16 || BlockSize==32 || BlockSize==64) && "Only possible block sizes for VREV are: 16, 32, 64"); unsigned EltSz = VT.getVectorElementType().getSizeInBits(); if (EltSz == 64) return false; unsigned NumElts = VT.getVectorNumElements(); unsigned BlockElts = M[0] + 1; // If the first shuffle index is UNDEF, be optimistic. if (M[0] < 0) BlockElts = BlockSize / EltSz; if (BlockSize <= EltSz || BlockSize != BlockElts * EltSz) return false; for (unsigned i = 0; i < NumElts; ++i) { if (M[i] < 0) continue; // ignore UNDEF indices if ((unsigned) M[i] != (i - i%BlockElts) + (BlockElts - 1 - i%BlockElts)) return false; } return true; } static bool isVTBLMask(const SmallVectorImpl &M, EVT VT) { // We can handle <8 x i8> vector shuffles. If the index in the mask is out of // range, then 0 is placed into the resulting vector. So pretty much any mask // of 8 elements can work here. return VT == MVT::v8i8 && M.size() == 8; } static bool isVTRNMask(const SmallVectorImpl &M, EVT VT, unsigned &WhichResult) { unsigned EltSz = VT.getVectorElementType().getSizeInBits(); if (EltSz == 64) return false; unsigned NumElts = VT.getVectorNumElements(); WhichResult = (M[0] == 0 ? 0 : 1); for (unsigned i = 0; i < NumElts; i += 2) { if ((M[i] >= 0 && (unsigned) M[i] != i + WhichResult) || (M[i+1] >= 0 && (unsigned) M[i+1] != i + NumElts + WhichResult)) return false; } return true; } /// isVTRN_v_undef_Mask - Special case of isVTRNMask for canonical form of /// "vector_shuffle v, v", i.e., "vector_shuffle v, undef". /// Mask is e.g., <0, 0, 2, 2> instead of <0, 4, 2, 6>. static bool isVTRN_v_undef_Mask(const SmallVectorImpl &M, EVT VT, unsigned &WhichResult) { unsigned EltSz = VT.getVectorElementType().getSizeInBits(); if (EltSz == 64) return false; unsigned NumElts = VT.getVectorNumElements(); WhichResult = (M[0] == 0 ? 0 : 1); for (unsigned i = 0; i < NumElts; i += 2) { if ((M[i] >= 0 && (unsigned) M[i] != i + WhichResult) || (M[i+1] >= 0 && (unsigned) M[i+1] != i + WhichResult)) return false; } return true; } static bool isVUZPMask(const SmallVectorImpl &M, EVT VT, unsigned &WhichResult) { unsigned EltSz = VT.getVectorElementType().getSizeInBits(); if (EltSz == 64) return false; unsigned NumElts = VT.getVectorNumElements(); WhichResult = (M[0] == 0 ? 0 : 1); for (unsigned i = 0; i != NumElts; ++i) { if (M[i] < 0) continue; // ignore UNDEF indices if ((unsigned) M[i] != 2 * i + WhichResult) return false; } // VUZP.32 for 64-bit vectors is a pseudo-instruction alias for VTRN.32. if (VT.is64BitVector() && EltSz == 32) return false; return true; } /// isVUZP_v_undef_Mask - Special case of isVUZPMask for canonical form of /// "vector_shuffle v, v", i.e., "vector_shuffle v, undef". /// Mask is e.g., <0, 2, 0, 2> instead of <0, 2, 4, 6>, static bool isVUZP_v_undef_Mask(const SmallVectorImpl &M, EVT VT, unsigned &WhichResult) { unsigned EltSz = VT.getVectorElementType().getSizeInBits(); if (EltSz == 64) return false; unsigned Half = VT.getVectorNumElements() / 2; WhichResult = (M[0] == 0 ? 0 : 1); for (unsigned j = 0; j != 2; ++j) { unsigned Idx = WhichResult; for (unsigned i = 0; i != Half; ++i) { int MIdx = M[i + j * Half]; if (MIdx >= 0 && (unsigned) MIdx != Idx) return false; Idx += 2; } } // VUZP.32 for 64-bit vectors is a pseudo-instruction alias for VTRN.32. if (VT.is64BitVector() && EltSz == 32) return false; return true; } static bool isVZIPMask(const SmallVectorImpl &M, EVT VT, unsigned &WhichResult) { unsigned EltSz = VT.getVectorElementType().getSizeInBits(); if (EltSz == 64) return false; unsigned NumElts = VT.getVectorNumElements(); WhichResult = (M[0] == 0 ? 0 : 1); unsigned Idx = WhichResult * NumElts / 2; for (unsigned i = 0; i != NumElts; i += 2) { if ((M[i] >= 0 && (unsigned) M[i] != Idx) || (M[i+1] >= 0 && (unsigned) M[i+1] != Idx + NumElts)) return false; Idx += 1; } // VZIP.32 for 64-bit vectors is a pseudo-instruction alias for VTRN.32. if (VT.is64BitVector() && EltSz == 32) return false; return true; } /// isVZIP_v_undef_Mask - Special case of isVZIPMask for canonical form of /// "vector_shuffle v, v", i.e., "vector_shuffle v, undef". /// Mask is e.g., <0, 0, 1, 1> instead of <0, 4, 1, 5>. static bool isVZIP_v_undef_Mask(const SmallVectorImpl &M, EVT VT, unsigned &WhichResult) { unsigned EltSz = VT.getVectorElementType().getSizeInBits(); if (EltSz == 64) return false; unsigned NumElts = VT.getVectorNumElements(); WhichResult = (M[0] == 0 ? 0 : 1); unsigned Idx = WhichResult * NumElts / 2; for (unsigned i = 0; i != NumElts; i += 2) { if ((M[i] >= 0 && (unsigned) M[i] != Idx) || (M[i+1] >= 0 && (unsigned) M[i+1] != Idx)) return false; Idx += 1; } // VZIP.32 for 64-bit vectors is a pseudo-instruction alias for VTRN.32. if (VT.is64BitVector() && EltSz == 32) return false; return true; } // If N is an integer constant that can be moved into a register in one // instruction, return an SDValue of such a constant (will become a MOV // instruction). Otherwise return null. static SDValue IsSingleInstrConstant(SDValue N, SelectionDAG &DAG, const ARMSubtarget *ST, DebugLoc dl) { uint64_t Val; if (!isa(N)) return SDValue(); Val = cast(N)->getZExtValue(); if (ST->isThumb1Only()) { if (Val <= 255 || ~Val <= 255) return DAG.getConstant(Val, MVT::i32); } else { if (ARM_AM::getSOImmVal(Val) != -1 || ARM_AM::getSOImmVal(~Val) != -1) return DAG.getConstant(Val, MVT::i32); } return SDValue(); } // If this is a case we can't handle, return null and let the default // expansion code take care of it. SDValue ARMTargetLowering::LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG, const ARMSubtarget *ST) const { BuildVectorSDNode *BVN = cast(Op.getNode()); DebugLoc dl = Op.getDebugLoc(); EVT VT = Op.getValueType(); APInt SplatBits, SplatUndef; unsigned SplatBitSize; bool HasAnyUndefs; if (BVN->isConstantSplat(SplatBits, SplatUndef, SplatBitSize, HasAnyUndefs)) { if (SplatBitSize <= 64) { // Check if an immediate VMOV works. EVT VmovVT; SDValue Val = isNEONModifiedImm(SplatBits.getZExtValue(), SplatUndef.getZExtValue(), SplatBitSize, DAG, VmovVT, VT.is128BitVector(), VMOVModImm); if (Val.getNode()) { SDValue Vmov = DAG.getNode(ARMISD::VMOVIMM, dl, VmovVT, Val); return DAG.getNode(ISD::BITCAST, dl, VT, Vmov); } // Try an immediate VMVN. uint64_t NegatedImm = (~SplatBits).getZExtValue(); Val = isNEONModifiedImm(NegatedImm, SplatUndef.getZExtValue(), SplatBitSize, DAG, VmovVT, VT.is128BitVector(), VMVNModImm); if (Val.getNode()) { SDValue Vmov = DAG.getNode(ARMISD::VMVNIMM, dl, VmovVT, Val); return DAG.getNode(ISD::BITCAST, dl, VT, Vmov); } } } // Scan through the operands to see if only one value is used. unsigned NumElts = VT.getVectorNumElements(); bool isOnlyLowElement = true; bool usesOnlyOneValue = true; bool isConstant = true; SDValue Value; for (unsigned i = 0; i < NumElts; ++i) { SDValue V = Op.getOperand(i); if (V.getOpcode() == ISD::UNDEF) continue; if (i > 0) isOnlyLowElement = false; if (!isa(V) && !isa(V)) isConstant = false; if (!Value.getNode()) Value = V; else if (V != Value) usesOnlyOneValue = false; } if (!Value.getNode()) return DAG.getUNDEF(VT); if (isOnlyLowElement) return DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, VT, Value); unsigned EltSize = VT.getVectorElementType().getSizeInBits(); // Use VDUP for non-constant splats. For f32 constant splats, reduce to // i32 and try again. if (usesOnlyOneValue && EltSize <= 32) { if (!isConstant) return DAG.getNode(ARMISD::VDUP, dl, VT, Value); if (VT.getVectorElementType().isFloatingPoint()) { SmallVector Ops; for (unsigned i = 0; i < NumElts; ++i) Ops.push_back(DAG.getNode(ISD::BITCAST, dl, MVT::i32, Op.getOperand(i))); EVT VecVT = EVT::getVectorVT(*DAG.getContext(), MVT::i32, NumElts); SDValue Val = DAG.getNode(ISD::BUILD_VECTOR, dl, VecVT, &Ops[0], NumElts); Val = LowerBUILD_VECTOR(Val, DAG, ST); if (Val.getNode()) return DAG.getNode(ISD::BITCAST, dl, VT, Val); } SDValue Val = IsSingleInstrConstant(Value, DAG, ST, dl); if (Val.getNode()) return DAG.getNode(ARMISD::VDUP, dl, VT, Val); } // If all elements are constants and the case above didn't get hit, fall back // to the default expansion, which will generate a load from the constant // pool. if (isConstant) return SDValue(); // Empirical tests suggest this is rarely worth it for vectors of length <= 2. if (NumElts >= 4) { SDValue shuffle = ReconstructShuffle(Op, DAG); if (shuffle != SDValue()) return shuffle; } // Vectors with 32- or 64-bit elements can be built by directly assigning // the subregisters. Lower it to an ARMISD::BUILD_VECTOR so the operands // will be legalized. if (EltSize >= 32) { // Do the expansion with floating-point types, since that is what the VFP // registers are defined to use, and since i64 is not legal. EVT EltVT = EVT::getFloatingPointVT(EltSize); EVT VecVT = EVT::getVectorVT(*DAG.getContext(), EltVT, NumElts); SmallVector Ops; for (unsigned i = 0; i < NumElts; ++i) Ops.push_back(DAG.getNode(ISD::BITCAST, dl, EltVT, Op.getOperand(i))); SDValue Val = DAG.getNode(ARMISD::BUILD_VECTOR, dl, VecVT, &Ops[0],NumElts); return DAG.getNode(ISD::BITCAST, dl, VT, Val); } return SDValue(); } // Gather data to see if the operation can be modelled as a // shuffle in combination with VEXTs. SDValue ARMTargetLowering::ReconstructShuffle(SDValue Op, SelectionDAG &DAG) const { DebugLoc dl = Op.getDebugLoc(); EVT VT = Op.getValueType(); unsigned NumElts = VT.getVectorNumElements(); SmallVector SourceVecs; SmallVector MinElts; SmallVector MaxElts; for (unsigned i = 0; i < NumElts; ++i) { SDValue V = Op.getOperand(i); if (V.getOpcode() == ISD::UNDEF) continue; else if (V.getOpcode() != ISD::EXTRACT_VECTOR_ELT) { // A shuffle can only come from building a vector from various // elements of other vectors. return SDValue(); } else if (V.getOperand(0).getValueType().getVectorElementType() != VT.getVectorElementType()) { // This code doesn't know how to handle shuffles where the vector // element types do not match (this happens because type legalization // promotes the return type of EXTRACT_VECTOR_ELT). // FIXME: It might be appropriate to extend this code to handle // mismatched types. return SDValue(); } // Record this extraction against the appropriate vector if possible... SDValue SourceVec = V.getOperand(0); unsigned EltNo = cast(V.getOperand(1))->getZExtValue(); bool FoundSource = false; for (unsigned j = 0; j < SourceVecs.size(); ++j) { if (SourceVecs[j] == SourceVec) { if (MinElts[j] > EltNo) MinElts[j] = EltNo; if (MaxElts[j] < EltNo) MaxElts[j] = EltNo; FoundSource = true; break; } } // Or record a new source if not... if (!FoundSource) { SourceVecs.push_back(SourceVec); MinElts.push_back(EltNo); MaxElts.push_back(EltNo); } } // Currently only do something sane when at most two source vectors // involved. if (SourceVecs.size() > 2) return SDValue(); SDValue ShuffleSrcs[2] = {DAG.getUNDEF(VT), DAG.getUNDEF(VT) }; int VEXTOffsets[2] = {0, 0}; // This loop extracts the usage patterns of the source vectors // and prepares appropriate SDValues for a shuffle if possible. for (unsigned i = 0; i < SourceVecs.size(); ++i) { if (SourceVecs[i].getValueType() == VT) { // No VEXT necessary ShuffleSrcs[i] = SourceVecs[i]; VEXTOffsets[i] = 0; continue; } else if (SourceVecs[i].getValueType().getVectorNumElements() < NumElts) { // It probably isn't worth padding out a smaller vector just to // break it down again in a shuffle. return SDValue(); } // Since only 64-bit and 128-bit vectors are legal on ARM and // we've eliminated the other cases... assert(SourceVecs[i].getValueType().getVectorNumElements() == 2*NumElts && "unexpected vector sizes in ReconstructShuffle"); if (MaxElts[i] - MinElts[i] >= NumElts) { // Span too large for a VEXT to cope return SDValue(); } if (MinElts[i] >= NumElts) { // The extraction can just take the second half VEXTOffsets[i] = NumElts; ShuffleSrcs[i] = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, VT, SourceVecs[i], DAG.getIntPtrConstant(NumElts)); } else if (MaxElts[i] < NumElts) { // The extraction can just take the first half VEXTOffsets[i] = 0; ShuffleSrcs[i] = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, VT, SourceVecs[i], DAG.getIntPtrConstant(0)); } else { // An actual VEXT is needed VEXTOffsets[i] = MinElts[i]; SDValue VEXTSrc1 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, VT, SourceVecs[i], DAG.getIntPtrConstant(0)); SDValue VEXTSrc2 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, VT, SourceVecs[i], DAG.getIntPtrConstant(NumElts)); ShuffleSrcs[i] = DAG.getNode(ARMISD::VEXT, dl, VT, VEXTSrc1, VEXTSrc2, DAG.getConstant(VEXTOffsets[i], MVT::i32)); } } SmallVector Mask; for (unsigned i = 0; i < NumElts; ++i) { SDValue Entry = Op.getOperand(i); if (Entry.getOpcode() == ISD::UNDEF) { Mask.push_back(-1); continue; } SDValue ExtractVec = Entry.getOperand(0); int ExtractElt = cast(Op.getOperand(i) .getOperand(1))->getSExtValue(); if (ExtractVec == SourceVecs[0]) { Mask.push_back(ExtractElt - VEXTOffsets[0]); } else { Mask.push_back(ExtractElt + NumElts - VEXTOffsets[1]); } } // Final check before we try to produce nonsense... if (isShuffleMaskLegal(Mask, VT)) return DAG.getVectorShuffle(VT, dl, ShuffleSrcs[0], ShuffleSrcs[1], &Mask[0]); return SDValue(); } /// isShuffleMaskLegal - Targets can use this to indicate that they only /// support *some* VECTOR_SHUFFLE operations, those with specific masks. /// By default, if a target supports the VECTOR_SHUFFLE node, all mask values /// are assumed to be legal. bool ARMTargetLowering::isShuffleMaskLegal(const SmallVectorImpl &M, EVT VT) const { if (VT.getVectorNumElements() == 4 && (VT.is128BitVector() || VT.is64BitVector())) { unsigned PFIndexes[4]; for (unsigned i = 0; i != 4; ++i) { if (M[i] < 0) PFIndexes[i] = 8; else PFIndexes[i] = M[i]; } // Compute the index in the perfect shuffle table. unsigned PFTableIndex = PFIndexes[0]*9*9*9+PFIndexes[1]*9*9+PFIndexes[2]*9+PFIndexes[3]; unsigned PFEntry = PerfectShuffleTable[PFTableIndex]; unsigned Cost = (PFEntry >> 30); if (Cost <= 4) return true; } bool ReverseVEXT; unsigned Imm, WhichResult; unsigned EltSize = VT.getVectorElementType().getSizeInBits(); return (EltSize >= 32 || ShuffleVectorSDNode::isSplatMask(&M[0], VT) || isVREVMask(M, VT, 64) || isVREVMask(M, VT, 32) || isVREVMask(M, VT, 16) || isVEXTMask(M, VT, ReverseVEXT, Imm) || isVTBLMask(M, VT) || isVTRNMask(M, VT, WhichResult) || isVUZPMask(M, VT, WhichResult) || isVZIPMask(M, VT, WhichResult) || isVTRN_v_undef_Mask(M, VT, WhichResult) || isVUZP_v_undef_Mask(M, VT, WhichResult) || isVZIP_v_undef_Mask(M, VT, WhichResult)); } /// GeneratePerfectShuffle - Given an entry in the perfect-shuffle table, emit /// the specified operations to build the shuffle. static SDValue GeneratePerfectShuffle(unsigned PFEntry, SDValue LHS, SDValue RHS, SelectionDAG &DAG, DebugLoc dl) { unsigned OpNum = (PFEntry >> 26) & 0x0F; unsigned LHSID = (PFEntry >> 13) & ((1 << 13)-1); unsigned RHSID = (PFEntry >> 0) & ((1 << 13)-1); enum { OP_COPY = 0, // Copy, used for things like to say it is <0,1,2,3> OP_VREV, OP_VDUP0, OP_VDUP1, OP_VDUP2, OP_VDUP3, OP_VEXT1, OP_VEXT2, OP_VEXT3, OP_VUZPL, // VUZP, left result OP_VUZPR, // VUZP, right result OP_VZIPL, // VZIP, left result OP_VZIPR, // VZIP, right result OP_VTRNL, // VTRN, left result OP_VTRNR // VTRN, right result }; if (OpNum == OP_COPY) { if (LHSID == (1*9+2)*9+3) return LHS; assert(LHSID == ((4*9+5)*9+6)*9+7 && "Illegal OP_COPY!"); return RHS; } SDValue OpLHS, OpRHS; OpLHS = GeneratePerfectShuffle(PerfectShuffleTable[LHSID], LHS, RHS, DAG, dl); OpRHS = GeneratePerfectShuffle(PerfectShuffleTable[RHSID], LHS, RHS, DAG, dl); EVT VT = OpLHS.getValueType(); switch (OpNum) { default: llvm_unreachable("Unknown shuffle opcode!"); case OP_VREV: // VREV divides the vector in half and swaps within the half. if (VT.getVectorElementType() == MVT::i32 || VT.getVectorElementType() == MVT::f32) return DAG.getNode(ARMISD::VREV64, dl, VT, OpLHS); // vrev <4 x i16> -> VREV32 if (VT.getVectorElementType() == MVT::i16) return DAG.getNode(ARMISD::VREV32, dl, VT, OpLHS); // vrev <4 x i8> -> VREV16 assert(VT.getVectorElementType() == MVT::i8); return DAG.getNode(ARMISD::VREV16, dl, VT, OpLHS); case OP_VDUP0: case OP_VDUP1: case OP_VDUP2: case OP_VDUP3: return DAG.getNode(ARMISD::VDUPLANE, dl, VT, OpLHS, DAG.getConstant(OpNum-OP_VDUP0, MVT::i32)); case OP_VEXT1: case OP_VEXT2: case OP_VEXT3: return DAG.getNode(ARMISD::VEXT, dl, VT, OpLHS, OpRHS, DAG.getConstant(OpNum-OP_VEXT1+1, MVT::i32)); case OP_VUZPL: case OP_VUZPR: return DAG.getNode(ARMISD::VUZP, dl, DAG.getVTList(VT, VT), OpLHS, OpRHS).getValue(OpNum-OP_VUZPL); case OP_VZIPL: case OP_VZIPR: return DAG.getNode(ARMISD::VZIP, dl, DAG.getVTList(VT, VT), OpLHS, OpRHS).getValue(OpNum-OP_VZIPL); case OP_VTRNL: case OP_VTRNR: return DAG.getNode(ARMISD::VTRN, dl, DAG.getVTList(VT, VT), OpLHS, OpRHS).getValue(OpNum-OP_VTRNL); } } static SDValue LowerVECTOR_SHUFFLEv8i8(SDValue Op, SmallVectorImpl &ShuffleMask, SelectionDAG &DAG) { // Check to see if we can use the VTBL instruction. SDValue V1 = Op.getOperand(0); SDValue V2 = Op.getOperand(1); DebugLoc DL = Op.getDebugLoc(); SmallVector VTBLMask; for (SmallVectorImpl::iterator I = ShuffleMask.begin(), E = ShuffleMask.end(); I != E; ++I) VTBLMask.push_back(DAG.getConstant(*I, MVT::i32)); if (V2.getNode()->getOpcode() == ISD::UNDEF) return DAG.getNode(ARMISD::VTBL1, DL, MVT::v8i8, V1, DAG.getNode(ISD::BUILD_VECTOR, DL, MVT::v8i8, &VTBLMask[0], 8)); return DAG.getNode(ARMISD::VTBL2, DL, MVT::v8i8, V1, V2, DAG.getNode(ISD::BUILD_VECTOR, DL, MVT::v8i8, &VTBLMask[0], 8)); } static SDValue LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) { SDValue V1 = Op.getOperand(0); SDValue V2 = Op.getOperand(1); DebugLoc dl = Op.getDebugLoc(); EVT VT = Op.getValueType(); ShuffleVectorSDNode *SVN = cast(Op.getNode()); SmallVector ShuffleMask; // Convert shuffles that are directly supported on NEON to target-specific // DAG nodes, instead of keeping them as shuffles and matching them again // during code selection. This is more efficient and avoids the possibility // of inconsistencies between legalization and selection. // FIXME: floating-point vectors should be canonicalized to integer vectors // of the same time so that they get CSEd properly. SVN->getMask(ShuffleMask); unsigned EltSize = VT.getVectorElementType().getSizeInBits(); if (EltSize <= 32) { if (ShuffleVectorSDNode::isSplatMask(&ShuffleMask[0], VT)) { int Lane = SVN->getSplatIndex(); // If this is undef splat, generate it via "just" vdup, if possible. if (Lane == -1) Lane = 0; if (Lane == 0 && V1.getOpcode() == ISD::SCALAR_TO_VECTOR) { return DAG.getNode(ARMISD::VDUP, dl, VT, V1.getOperand(0)); } return DAG.getNode(ARMISD::VDUPLANE, dl, VT, V1, DAG.getConstant(Lane, MVT::i32)); } bool ReverseVEXT; unsigned Imm; if (isVEXTMask(ShuffleMask, VT, ReverseVEXT, Imm)) { if (ReverseVEXT) std::swap(V1, V2); return DAG.getNode(ARMISD::VEXT, dl, VT, V1, V2, DAG.getConstant(Imm, MVT::i32)); } if (isVREVMask(ShuffleMask, VT, 64)) return DAG.getNode(ARMISD::VREV64, dl, VT, V1); if (isVREVMask(ShuffleMask, VT, 32)) return DAG.getNode(ARMISD::VREV32, dl, VT, V1); if (isVREVMask(ShuffleMask, VT, 16)) return DAG.getNode(ARMISD::VREV16, dl, VT, V1); // Check for Neon shuffles that modify both input vectors in place. // If both results are used, i.e., if there are two shuffles with the same // source operands and with masks corresponding to both results of one of // these operations, DAG memoization will ensure that a single node is // used for both shuffles. unsigned WhichResult; if (isVTRNMask(ShuffleMask, VT, WhichResult)) return DAG.getNode(ARMISD::VTRN, dl, DAG.getVTList(VT, VT), V1, V2).getValue(WhichResult); if (isVUZPMask(ShuffleMask, VT, WhichResult)) return DAG.getNode(ARMISD::VUZP, dl, DAG.getVTList(VT, VT), V1, V2).getValue(WhichResult); if (isVZIPMask(ShuffleMask, VT, WhichResult)) return DAG.getNode(ARMISD::VZIP, dl, DAG.getVTList(VT, VT), V1, V2).getValue(WhichResult); if (isVTRN_v_undef_Mask(ShuffleMask, VT, WhichResult)) return DAG.getNode(ARMISD::VTRN, dl, DAG.getVTList(VT, VT), V1, V1).getValue(WhichResult); if (isVUZP_v_undef_Mask(ShuffleMask, VT, WhichResult)) return DAG.getNode(ARMISD::VUZP, dl, DAG.getVTList(VT, VT), V1, V1).getValue(WhichResult); if (isVZIP_v_undef_Mask(ShuffleMask, VT, WhichResult)) return DAG.getNode(ARMISD::VZIP, dl, DAG.getVTList(VT, VT), V1, V1).getValue(WhichResult); } // If the shuffle is not directly supported and it has 4 elements, use // the PerfectShuffle-generated table to synthesize it from other shuffles. unsigned NumElts = VT.getVectorNumElements(); if (NumElts == 4) { unsigned PFIndexes[4]; for (unsigned i = 0; i != 4; ++i) { if (ShuffleMask[i] < 0) PFIndexes[i] = 8; else PFIndexes[i] = ShuffleMask[i]; } // Compute the index in the perfect shuffle table. unsigned PFTableIndex = PFIndexes[0]*9*9*9+PFIndexes[1]*9*9+PFIndexes[2]*9+PFIndexes[3]; unsigned PFEntry = PerfectShuffleTable[PFTableIndex]; unsigned Cost = (PFEntry >> 30); if (Cost <= 4) return GeneratePerfectShuffle(PFEntry, V1, V2, DAG, dl); } // Implement shuffles with 32- or 64-bit elements as ARMISD::BUILD_VECTORs. if (EltSize >= 32) { // Do the expansion with floating-point types, since that is what the VFP // registers are defined to use, and since i64 is not legal. EVT EltVT = EVT::getFloatingPointVT(EltSize); EVT VecVT = EVT::getVectorVT(*DAG.getContext(), EltVT, NumElts); V1 = DAG.getNode(ISD::BITCAST, dl, VecVT, V1); V2 = DAG.getNode(ISD::BITCAST, dl, VecVT, V2); SmallVector Ops; for (unsigned i = 0; i < NumElts; ++i) { if (ShuffleMask[i] < 0) Ops.push_back(DAG.getUNDEF(EltVT)); else Ops.push_back(DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, EltVT, ShuffleMask[i] < (int)NumElts ? V1 : V2, DAG.getConstant(ShuffleMask[i] & (NumElts-1), MVT::i32))); } SDValue Val = DAG.getNode(ARMISD::BUILD_VECTOR, dl, VecVT, &Ops[0],NumElts); return DAG.getNode(ISD::BITCAST, dl, VT, Val); } if (VT == MVT::v8i8) { SDValue NewOp = LowerVECTOR_SHUFFLEv8i8(Op, ShuffleMask, DAG); if (NewOp.getNode()) return NewOp; } return SDValue(); } static SDValue LowerEXTRACT_VECTOR_ELT(SDValue Op, SelectionDAG &DAG) { // EXTRACT_VECTOR_ELT is legal only for immediate indexes. SDValue Lane = Op.getOperand(1); if (!isa(Lane)) return SDValue(); SDValue Vec = Op.getOperand(0); if (Op.getValueType() == MVT::i32 && Vec.getValueType().getVectorElementType().getSizeInBits() < 32) { DebugLoc dl = Op.getDebugLoc(); return DAG.getNode(ARMISD::VGETLANEu, dl, MVT::i32, Vec, Lane); } return Op; } static SDValue LowerCONCAT_VECTORS(SDValue Op, SelectionDAG &DAG) { // The only time a CONCAT_VECTORS operation can have legal types is when // two 64-bit vectors are concatenated to a 128-bit vector. assert(Op.getValueType().is128BitVector() && Op.getNumOperands() == 2 && "unexpected CONCAT_VECTORS"); DebugLoc dl = Op.getDebugLoc(); SDValue Val = DAG.getUNDEF(MVT::v2f64); SDValue Op0 = Op.getOperand(0); SDValue Op1 = Op.getOperand(1); if (Op0.getOpcode() != ISD::UNDEF) Val = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, MVT::v2f64, Val, DAG.getNode(ISD::BITCAST, dl, MVT::f64, Op0), DAG.getIntPtrConstant(0)); if (Op1.getOpcode() != ISD::UNDEF) Val = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, MVT::v2f64, Val, DAG.getNode(ISD::BITCAST, dl, MVT::f64, Op1), DAG.getIntPtrConstant(1)); return DAG.getNode(ISD::BITCAST, dl, Op.getValueType(), Val); } /// isExtendedBUILD_VECTOR - Check if N is a constant BUILD_VECTOR where each /// element has been zero/sign-extended, depending on the isSigned parameter, /// from an integer type half its size. static bool isExtendedBUILD_VECTOR(SDNode *N, SelectionDAG &DAG, bool isSigned) { // A v2i64 BUILD_VECTOR will have been legalized to a BITCAST from v4i32. EVT VT = N->getValueType(0); if (VT == MVT::v2i64 && N->getOpcode() == ISD::BITCAST) { SDNode *BVN = N->getOperand(0).getNode(); if (BVN->getValueType(0) != MVT::v4i32 || BVN->getOpcode() != ISD::BUILD_VECTOR) return false; unsigned LoElt = DAG.getTargetLoweringInfo().isBigEndian() ? 1 : 0; unsigned HiElt = 1 - LoElt; ConstantSDNode *Lo0 = dyn_cast(BVN->getOperand(LoElt)); ConstantSDNode *Hi0 = dyn_cast(BVN->getOperand(HiElt)); ConstantSDNode *Lo1 = dyn_cast(BVN->getOperand(LoElt+2)); ConstantSDNode *Hi1 = dyn_cast(BVN->getOperand(HiElt+2)); if (!Lo0 || !Hi0 || !Lo1 || !Hi1) return false; if (isSigned) { if (Hi0->getSExtValue() == Lo0->getSExtValue() >> 32 && Hi1->getSExtValue() == Lo1->getSExtValue() >> 32) return true; } else { if (Hi0->isNullValue() && Hi1->isNullValue()) return true; } return false; } if (N->getOpcode() != ISD::BUILD_VECTOR) return false; for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) { SDNode *Elt = N->getOperand(i).getNode(); if (ConstantSDNode *C = dyn_cast(Elt)) { unsigned EltSize = VT.getVectorElementType().getSizeInBits(); unsigned HalfSize = EltSize / 2; if (isSigned) { int64_t SExtVal = C->getSExtValue(); if ((SExtVal >> HalfSize) != (SExtVal >> EltSize)) return false; } else { if ((C->getZExtValue() >> HalfSize) != 0) return false; } continue; } return false; } return true; } /// isSignExtended - Check if a node is a vector value that is sign-extended /// or a constant BUILD_VECTOR with sign-extended elements. static bool isSignExtended(SDNode *N, SelectionDAG &DAG) { if (N->getOpcode() == ISD::SIGN_EXTEND || ISD::isSEXTLoad(N)) return true; if (isExtendedBUILD_VECTOR(N, DAG, true)) return true; return false; } /// isZeroExtended - Check if a node is a vector value that is zero-extended /// or a constant BUILD_VECTOR with zero-extended elements. static bool isZeroExtended(SDNode *N, SelectionDAG &DAG) { if (N->getOpcode() == ISD::ZERO_EXTEND || ISD::isZEXTLoad(N)) return true; if (isExtendedBUILD_VECTOR(N, DAG, false)) return true; return false; } /// SkipExtension - For a node that is a SIGN_EXTEND, ZERO_EXTEND, extending /// load, or BUILD_VECTOR with extended elements, return the unextended value. static SDValue SkipExtension(SDNode *N, SelectionDAG &DAG) { if (N->getOpcode() == ISD::SIGN_EXTEND || N->getOpcode() == ISD::ZERO_EXTEND) return N->getOperand(0); if (LoadSDNode *LD = dyn_cast(N)) return DAG.getLoad(LD->getMemoryVT(), N->getDebugLoc(), LD->getChain(), LD->getBasePtr(), LD->getPointerInfo(), LD->isVolatile(), LD->isNonTemporal(), LD->getAlignment()); // Otherwise, the value must be a BUILD_VECTOR. For v2i64, it will // have been legalized as a BITCAST from v4i32. if (N->getOpcode() == ISD::BITCAST) { SDNode *BVN = N->getOperand(0).getNode(); assert(BVN->getOpcode() == ISD::BUILD_VECTOR && BVN->getValueType(0) == MVT::v4i32 && "expected v4i32 BUILD_VECTOR"); unsigned LowElt = DAG.getTargetLoweringInfo().isBigEndian() ? 1 : 0; return DAG.getNode(ISD::BUILD_VECTOR, N->getDebugLoc(), MVT::v2i32, BVN->getOperand(LowElt), BVN->getOperand(LowElt+2)); } // Construct a new BUILD_VECTOR with elements truncated to half the size. assert(N->getOpcode() == ISD::BUILD_VECTOR && "expected BUILD_VECTOR"); EVT VT = N->getValueType(0); unsigned EltSize = VT.getVectorElementType().getSizeInBits() / 2; unsigned NumElts = VT.getVectorNumElements(); MVT TruncVT = MVT::getIntegerVT(EltSize); SmallVector Ops; for (unsigned i = 0; i != NumElts; ++i) { ConstantSDNode *C = cast(N->getOperand(i)); const APInt &CInt = C->getAPIntValue(); Ops.push_back(DAG.getConstant(CInt.trunc(EltSize), TruncVT)); } return DAG.getNode(ISD::BUILD_VECTOR, N->getDebugLoc(), MVT::getVectorVT(TruncVT, NumElts), Ops.data(), NumElts); } static bool isAddSubSExt(SDNode *N, SelectionDAG &DAG) { unsigned Opcode = N->getOpcode(); if (Opcode == ISD::ADD || Opcode == ISD::SUB) { SDNode *N0 = N->getOperand(0).getNode(); SDNode *N1 = N->getOperand(1).getNode(); return N0->hasOneUse() && N1->hasOneUse() && isSignExtended(N0, DAG) && isSignExtended(N1, DAG); } return false; } static bool isAddSubZExt(SDNode *N, SelectionDAG &DAG) { unsigned Opcode = N->getOpcode(); if (Opcode == ISD::ADD || Opcode == ISD::SUB) { SDNode *N0 = N->getOperand(0).getNode(); SDNode *N1 = N->getOperand(1).getNode(); return N0->hasOneUse() && N1->hasOneUse() && isZeroExtended(N0, DAG) && isZeroExtended(N1, DAG); } return false; } static SDValue LowerMUL(SDValue Op, SelectionDAG &DAG) { // Multiplications are only custom-lowered for 128-bit vectors so that // VMULL can be detected. Otherwise v2i64 multiplications are not legal. EVT VT = Op.getValueType(); assert(VT.is128BitVector() && "unexpected type for custom-lowering ISD::MUL"); SDNode *N0 = Op.getOperand(0).getNode(); SDNode *N1 = Op.getOperand(1).getNode(); unsigned NewOpc = 0; bool isMLA = false; bool isN0SExt = isSignExtended(N0, DAG); bool isN1SExt = isSignExtended(N1, DAG); if (isN0SExt && isN1SExt) NewOpc = ARMISD::VMULLs; else { bool isN0ZExt = isZeroExtended(N0, DAG); bool isN1ZExt = isZeroExtended(N1, DAG); if (isN0ZExt && isN1ZExt) NewOpc = ARMISD::VMULLu; else if (isN1SExt || isN1ZExt) { // Look for (s/zext A + s/zext B) * (s/zext C). We want to turn these // into (s/zext A * s/zext C) + (s/zext B * s/zext C) if (isN1SExt && isAddSubSExt(N0, DAG)) { NewOpc = ARMISD::VMULLs; isMLA = true; } else if (isN1ZExt && isAddSubZExt(N0, DAG)) { NewOpc = ARMISD::VMULLu; isMLA = true; } else if (isN0ZExt && isAddSubZExt(N1, DAG)) { std::swap(N0, N1); NewOpc = ARMISD::VMULLu; isMLA = true; } } if (!NewOpc) { if (VT == MVT::v2i64) // Fall through to expand this. It is not legal. return SDValue(); else // Other vector multiplications are legal. return Op; } } // Legalize to a VMULL instruction. DebugLoc DL = Op.getDebugLoc(); SDValue Op0; SDValue Op1 = SkipExtension(N1, DAG); if (!isMLA) { Op0 = SkipExtension(N0, DAG); assert(Op0.getValueType().is64BitVector() && Op1.getValueType().is64BitVector() && "unexpected types for extended operands to VMULL"); return DAG.getNode(NewOpc, DL, VT, Op0, Op1); } // Optimizing (zext A + zext B) * C, to (VMULL A, C) + (VMULL B, C) during // isel lowering to take advantage of no-stall back to back vmul + vmla. // vmull q0, d4, d6 // vmlal q0, d5, d6 // is faster than // vaddl q0, d4, d5 // vmovl q1, d6 // vmul q0, q0, q1 SDValue N00 = SkipExtension(N0->getOperand(0).getNode(), DAG); SDValue N01 = SkipExtension(N0->getOperand(1).getNode(), DAG); EVT Op1VT = Op1.getValueType(); return DAG.getNode(N0->getOpcode(), DL, VT, DAG.getNode(NewOpc, DL, VT, DAG.getNode(ISD::BITCAST, DL, Op1VT, N00), Op1), DAG.getNode(NewOpc, DL, VT, DAG.getNode(ISD::BITCAST, DL, Op1VT, N01), Op1)); } static SDValue LowerSDIV_v4i8(SDValue X, SDValue Y, DebugLoc dl, SelectionDAG &DAG) { // Convert to float // float4 xf = vcvt_f32_s32(vmovl_s16(a.lo)); // float4 yf = vcvt_f32_s32(vmovl_s16(b.lo)); X = DAG.getNode(ISD::SIGN_EXTEND, dl, MVT::v4i32, X); Y = DAG.getNode(ISD::SIGN_EXTEND, dl, MVT::v4i32, Y); X = DAG.getNode(ISD::SINT_TO_FP, dl, MVT::v4f32, X); Y = DAG.getNode(ISD::SINT_TO_FP, dl, MVT::v4f32, Y); // Get reciprocal estimate. // float4 recip = vrecpeq_f32(yf); Y = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, MVT::v4f32, DAG.getConstant(Intrinsic::arm_neon_vrecpe, MVT::i32), Y); // Because char has a smaller range than uchar, we can actually get away // without any newton steps. This requires that we use a weird bias // of 0xb000, however (again, this has been exhaustively tested). // float4 result = as_float4(as_int4(xf*recip) + 0xb000); X = DAG.getNode(ISD::FMUL, dl, MVT::v4f32, X, Y); X = DAG.getNode(ISD::BITCAST, dl, MVT::v4i32, X); Y = DAG.getConstant(0xb000, MVT::i32); Y = DAG.getNode(ISD::BUILD_VECTOR, dl, MVT::v4i32, Y, Y, Y, Y); X = DAG.getNode(ISD::ADD, dl, MVT::v4i32, X, Y); X = DAG.getNode(ISD::BITCAST, dl, MVT::v4f32, X); // Convert back to short. X = DAG.getNode(ISD::FP_TO_SINT, dl, MVT::v4i32, X); X = DAG.getNode(ISD::TRUNCATE, dl, MVT::v4i16, X); return X; } static SDValue LowerSDIV_v4i16(SDValue N0, SDValue N1, DebugLoc dl, SelectionDAG &DAG) { SDValue N2; // Convert to float. // float4 yf = vcvt_f32_s32(vmovl_s16(y)); // float4 xf = vcvt_f32_s32(vmovl_s16(x)); N0 = DAG.getNode(ISD::SIGN_EXTEND, dl, MVT::v4i32, N0); N1 = DAG.getNode(ISD::SIGN_EXTEND, dl, MVT::v4i32, N1); N0 = DAG.getNode(ISD::SINT_TO_FP, dl, MVT::v4f32, N0); N1 = DAG.getNode(ISD::SINT_TO_FP, dl, MVT::v4f32, N1); // Use reciprocal estimate and one refinement step. // float4 recip = vrecpeq_f32(yf); // recip *= vrecpsq_f32(yf, recip); N2 = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, MVT::v4f32, DAG.getConstant(Intrinsic::arm_neon_vrecpe, MVT::i32), N1); N1 = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, MVT::v4f32, DAG.getConstant(Intrinsic::arm_neon_vrecps, MVT::i32), N1, N2); N2 = DAG.getNode(ISD::FMUL, dl, MVT::v4f32, N1, N2); // Because short has a smaller range than ushort, we can actually get away // with only a single newton step. This requires that we use a weird bias // of 89, however (again, this has been exhaustively tested). // float4 result = as_float4(as_int4(xf*recip) + 0x89); N0 = DAG.getNode(ISD::FMUL, dl, MVT::v4f32, N0, N2); N0 = DAG.getNode(ISD::BITCAST, dl, MVT::v4i32, N0); N1 = DAG.getConstant(0x89, MVT::i32); N1 = DAG.getNode(ISD::BUILD_VECTOR, dl, MVT::v4i32, N1, N1, N1, N1); N0 = DAG.getNode(ISD::ADD, dl, MVT::v4i32, N0, N1); N0 = DAG.getNode(ISD::BITCAST, dl, MVT::v4f32, N0); // Convert back to integer and return. // return vmovn_s32(vcvt_s32_f32(result)); N0 = DAG.getNode(ISD::FP_TO_SINT, dl, MVT::v4i32, N0); N0 = DAG.getNode(ISD::TRUNCATE, dl, MVT::v4i16, N0); return N0; } static SDValue LowerSDIV(SDValue Op, SelectionDAG &DAG) { EVT VT = Op.getValueType(); assert((VT == MVT::v4i16 || VT == MVT::v8i8) && "unexpected type for custom-lowering ISD::SDIV"); DebugLoc dl = Op.getDebugLoc(); SDValue N0 = Op.getOperand(0); SDValue N1 = Op.getOperand(1); SDValue N2, N3; if (VT == MVT::v8i8) { N0 = DAG.getNode(ISD::SIGN_EXTEND, dl, MVT::v8i16, N0); N1 = DAG.getNode(ISD::SIGN_EXTEND, dl, MVT::v8i16, N1); N2 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, MVT::v4i16, N0, DAG.getIntPtrConstant(4)); N3 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, MVT::v4i16, N1, DAG.getIntPtrConstant(4)); N0 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, MVT::v4i16, N0, DAG.getIntPtrConstant(0)); N1 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, MVT::v4i16, N1, DAG.getIntPtrConstant(0)); N0 = LowerSDIV_v4i8(N0, N1, dl, DAG); // v4i16 N2 = LowerSDIV_v4i8(N2, N3, dl, DAG); // v4i16 N0 = DAG.getNode(ISD::CONCAT_VECTORS, dl, MVT::v8i16, N0, N2); N0 = LowerCONCAT_VECTORS(N0, DAG); N0 = DAG.getNode(ISD::TRUNCATE, dl, MVT::v8i8, N0); return N0; } return LowerSDIV_v4i16(N0, N1, dl, DAG); } static SDValue LowerUDIV(SDValue Op, SelectionDAG &DAG) { EVT VT = Op.getValueType(); assert((VT == MVT::v4i16 || VT == MVT::v8i8) && "unexpected type for custom-lowering ISD::UDIV"); DebugLoc dl = Op.getDebugLoc(); SDValue N0 = Op.getOperand(0); SDValue N1 = Op.getOperand(1); SDValue N2, N3; if (VT == MVT::v8i8) { N0 = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::v8i16, N0); N1 = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::v8i16, N1); N2 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, MVT::v4i16, N0, DAG.getIntPtrConstant(4)); N3 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, MVT::v4i16, N1, DAG.getIntPtrConstant(4)); N0 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, MVT::v4i16, N0, DAG.getIntPtrConstant(0)); N1 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, MVT::v4i16, N1, DAG.getIntPtrConstant(0)); N0 = LowerSDIV_v4i16(N0, N1, dl, DAG); // v4i16 N2 = LowerSDIV_v4i16(N2, N3, dl, DAG); // v4i16 N0 = DAG.getNode(ISD::CONCAT_VECTORS, dl, MVT::v8i16, N0, N2); N0 = LowerCONCAT_VECTORS(N0, DAG); N0 = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, MVT::v8i8, DAG.getConstant(Intrinsic::arm_neon_vqmovnsu, MVT::i32), N0); return N0; } // v4i16 sdiv ... Convert to float. // float4 yf = vcvt_f32_s32(vmovl_u16(y)); // float4 xf = vcvt_f32_s32(vmovl_u16(x)); N0 = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::v4i32, N0); N1 = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::v4i32, N1); N0 = DAG.getNode(ISD::SINT_TO_FP, dl, MVT::v4f32, N0); SDValue BN1 = DAG.getNode(ISD::SINT_TO_FP, dl, MVT::v4f32, N1); // Use reciprocal estimate and two refinement steps. // float4 recip = vrecpeq_f32(yf); // recip *= vrecpsq_f32(yf, recip); // recip *= vrecpsq_f32(yf, recip); N2 = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, MVT::v4f32, DAG.getConstant(Intrinsic::arm_neon_vrecpe, MVT::i32), BN1); N1 = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, MVT::v4f32, DAG.getConstant(Intrinsic::arm_neon_vrecps, MVT::i32), BN1, N2); N2 = DAG.getNode(ISD::FMUL, dl, MVT::v4f32, N1, N2); N1 = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, MVT::v4f32, DAG.getConstant(Intrinsic::arm_neon_vrecps, MVT::i32), BN1, N2); N2 = DAG.getNode(ISD::FMUL, dl, MVT::v4f32, N1, N2); // Simply multiplying by the reciprocal estimate can leave us a few ulps // too low, so we add 2 ulps (exhaustive testing shows that this is enough, // and that it will never cause us to return an answer too large). // float4 result = as_float4(as_int4(xf*recip) + 2); N0 = DAG.getNode(ISD::FMUL, dl, MVT::v4f32, N0, N2); N0 = DAG.getNode(ISD::BITCAST, dl, MVT::v4i32, N0); N1 = DAG.getConstant(2, MVT::i32); N1 = DAG.getNode(ISD::BUILD_VECTOR, dl, MVT::v4i32, N1, N1, N1, N1); N0 = DAG.getNode(ISD::ADD, dl, MVT::v4i32, N0, N1); N0 = DAG.getNode(ISD::BITCAST, dl, MVT::v4f32, N0); // Convert back to integer and return. // return vmovn_u32(vcvt_s32_f32(result)); N0 = DAG.getNode(ISD::FP_TO_SINT, dl, MVT::v4i32, N0); N0 = DAG.getNode(ISD::TRUNCATE, dl, MVT::v4i16, N0); return N0; } static SDValue LowerADDC_ADDE_SUBC_SUBE(SDValue Op, SelectionDAG &DAG) { EVT VT = Op.getNode()->getValueType(0); SDVTList VTs = DAG.getVTList(VT, MVT::i32); unsigned Opc; bool ExtraOp = false; switch (Op.getOpcode()) { default: assert(0 && "Invalid code"); case ISD::ADDC: Opc = ARMISD::ADDC; break; case ISD::ADDE: Opc = ARMISD::ADDE; ExtraOp = true; break; case ISD::SUBC: Opc = ARMISD::SUBC; break; case ISD::SUBE: Opc = ARMISD::SUBE; ExtraOp = true; break; } if (!ExtraOp) return DAG.getNode(Opc, Op->getDebugLoc(), VTs, Op.getOperand(0), Op.getOperand(1)); return DAG.getNode(Opc, Op->getDebugLoc(), VTs, Op.getOperand(0), Op.getOperand(1), Op.getOperand(2)); } static SDValue LowerAtomicLoadStore(SDValue Op, SelectionDAG &DAG) { // Monotonic load/store is legal for all targets if (cast(Op)->getOrdering() <= Monotonic) return Op; // Aquire/Release load/store is not legal for targets without a // dmb or equivalent available. return SDValue(); } static void ReplaceATOMIC_OP_64(SDNode *Node, SmallVectorImpl& Results, SelectionDAG &DAG, unsigned NewOp) { DebugLoc dl = Node->getDebugLoc(); assert (Node->getValueType(0) == MVT::i64 && "Only know how to expand i64 atomics"); SmallVector Ops; Ops.push_back(Node->getOperand(0)); // Chain Ops.push_back(Node->getOperand(1)); // Ptr // Low part of Val1 Ops.push_back(DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, Node->getOperand(2), DAG.getIntPtrConstant(0))); // High part of Val1 Ops.push_back(DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, Node->getOperand(2), DAG.getIntPtrConstant(1))); if (NewOp == ARMISD::ATOMCMPXCHG64_DAG) { // High part of Val1 Ops.push_back(DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, Node->getOperand(3), DAG.getIntPtrConstant(0))); // High part of Val2 Ops.push_back(DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, Node->getOperand(3), DAG.getIntPtrConstant(1))); } SDVTList Tys = DAG.getVTList(MVT::i32, MVT::i32, MVT::Other); SDValue Result = DAG.getMemIntrinsicNode(NewOp, dl, Tys, Ops.data(), Ops.size(), MVT::i64, cast(Node)->getMemOperand()); SDValue OpsF[] = { Result.getValue(0), Result.getValue(1) }; Results.push_back(DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, OpsF, 2)); Results.push_back(Result.getValue(2)); } SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { switch (Op.getOpcode()) { default: llvm_unreachable("Don't know how to custom lower this!"); case ISD::ConstantPool: return LowerConstantPool(Op, DAG); case ISD::BlockAddress: return LowerBlockAddress(Op, DAG); case ISD::GlobalAddress: return Subtarget->isTargetDarwin() ? LowerGlobalAddressDarwin(Op, DAG) : LowerGlobalAddressELF(Op, DAG); case ISD::GlobalTLSAddress: return LowerGlobalTLSAddress(Op, DAG); case ISD::SELECT: return LowerSELECT(Op, DAG); case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG); case ISD::BR_CC: return LowerBR_CC(Op, DAG); case ISD::BR_JT: return LowerBR_JT(Op, DAG); case ISD::VASTART: return LowerVASTART(Op, DAG); case ISD::MEMBARRIER: return LowerMEMBARRIER(Op, DAG, Subtarget); case ISD::ATOMIC_FENCE: return LowerATOMIC_FENCE(Op, DAG, Subtarget); case ISD::PREFETCH: return LowerPREFETCH(Op, DAG, Subtarget); case ISD::SINT_TO_FP: case ISD::UINT_TO_FP: return LowerINT_TO_FP(Op, DAG); case ISD::FP_TO_SINT: case ISD::FP_TO_UINT: return LowerFP_TO_INT(Op, DAG); case ISD::FCOPYSIGN: return LowerFCOPYSIGN(Op, DAG); case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG); case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG); case ISD::GLOBAL_OFFSET_TABLE: return LowerGLOBAL_OFFSET_TABLE(Op, DAG); case ISD::EH_SJLJ_SETJMP: return LowerEH_SJLJ_SETJMP(Op, DAG); case ISD::EH_SJLJ_LONGJMP: return LowerEH_SJLJ_LONGJMP(Op, DAG); case ISD::EH_SJLJ_DISPATCHSETUP: return LowerEH_SJLJ_DISPATCHSETUP(Op, DAG); case ISD::INTRINSIC_WO_CHAIN: return LowerINTRINSIC_WO_CHAIN(Op, DAG, Subtarget); case ISD::BITCAST: return ExpandBITCAST(Op.getNode(), DAG); case ISD::SHL: case ISD::SRL: case ISD::SRA: return LowerShift(Op.getNode(), DAG, Subtarget); case ISD::SHL_PARTS: return LowerShiftLeftParts(Op, DAG); case ISD::SRL_PARTS: case ISD::SRA_PARTS: return LowerShiftRightParts(Op, DAG); case ISD::CTTZ: return LowerCTTZ(Op.getNode(), DAG, Subtarget); case ISD::SETCC: return LowerVSETCC(Op, DAG); case ISD::BUILD_VECTOR: return LowerBUILD_VECTOR(Op, DAG, Subtarget); case ISD::VECTOR_SHUFFLE: return LowerVECTOR_SHUFFLE(Op, DAG); case ISD::EXTRACT_VECTOR_ELT: return LowerEXTRACT_VECTOR_ELT(Op, DAG); case ISD::CONCAT_VECTORS: return LowerCONCAT_VECTORS(Op, DAG); case ISD::FLT_ROUNDS_: return LowerFLT_ROUNDS_(Op, DAG); case ISD::MUL: return LowerMUL(Op, DAG); case ISD::SDIV: return LowerSDIV(Op, DAG); case ISD::UDIV: return LowerUDIV(Op, DAG); case ISD::ADDC: case ISD::ADDE: case ISD::SUBC: case ISD::SUBE: return LowerADDC_ADDE_SUBC_SUBE(Op, DAG); case ISD::ATOMIC_LOAD: case ISD::ATOMIC_STORE: return LowerAtomicLoadStore(Op, DAG); } return SDValue(); } /// ReplaceNodeResults - Replace the results of node with an illegal result /// type with new values built out of custom code. void ARMTargetLowering::ReplaceNodeResults(SDNode *N, SmallVectorImpl&Results, SelectionDAG &DAG) const { SDValue Res; switch (N->getOpcode()) { default: llvm_unreachable("Don't know how to custom expand this!"); break; case ISD::BITCAST: Res = ExpandBITCAST(N, DAG); break; case ISD::SRL: case ISD::SRA: Res = Expand64BitShift(N, DAG, Subtarget); break; case ISD::ATOMIC_LOAD_ADD: ReplaceATOMIC_OP_64(N, Results, DAG, ARMISD::ATOMADD64_DAG); return; case ISD::ATOMIC_LOAD_AND: ReplaceATOMIC_OP_64(N, Results, DAG, ARMISD::ATOMAND64_DAG); return; case ISD::ATOMIC_LOAD_NAND: ReplaceATOMIC_OP_64(N, Results, DAG, ARMISD::ATOMNAND64_DAG); return; case ISD::ATOMIC_LOAD_OR: ReplaceATOMIC_OP_64(N, Results, DAG, ARMISD::ATOMOR64_DAG); return; case ISD::ATOMIC_LOAD_SUB: ReplaceATOMIC_OP_64(N, Results, DAG, ARMISD::ATOMSUB64_DAG); return; case ISD::ATOMIC_LOAD_XOR: ReplaceATOMIC_OP_64(N, Results, DAG, ARMISD::ATOMXOR64_DAG); return; case ISD::ATOMIC_SWAP: ReplaceATOMIC_OP_64(N, Results, DAG, ARMISD::ATOMSWAP64_DAG); return; case ISD::ATOMIC_CMP_SWAP: ReplaceATOMIC_OP_64(N, Results, DAG, ARMISD::ATOMCMPXCHG64_DAG); return; } if (Res.getNode()) Results.push_back(Res); } //===----------------------------------------------------------------------===// // ARM Scheduler Hooks //===----------------------------------------------------------------------===// MachineBasicBlock * ARMTargetLowering::EmitAtomicCmpSwap(MachineInstr *MI, MachineBasicBlock *BB, unsigned Size) const { unsigned dest = MI->getOperand(0).getReg(); unsigned ptr = MI->getOperand(1).getReg(); unsigned oldval = MI->getOperand(2).getReg(); unsigned newval = MI->getOperand(3).getReg(); const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); DebugLoc dl = MI->getDebugLoc(); bool isThumb2 = Subtarget->isThumb2(); MachineRegisterInfo &MRI = BB->getParent()->getRegInfo(); unsigned scratch = MRI.createVirtualRegister(isThumb2 ? ARM::rGPRRegisterClass : ARM::GPRRegisterClass); if (isThumb2) { MRI.constrainRegClass(dest, ARM::rGPRRegisterClass); MRI.constrainRegClass(oldval, ARM::rGPRRegisterClass); MRI.constrainRegClass(newval, ARM::rGPRRegisterClass); } unsigned ldrOpc, strOpc; switch (Size) { default: llvm_unreachable("unsupported size for AtomicCmpSwap!"); case 1: ldrOpc = isThumb2 ? ARM::t2LDREXB : ARM::LDREXB; strOpc = isThumb2 ? ARM::t2STREXB : ARM::STREXB; break; case 2: ldrOpc = isThumb2 ? ARM::t2LDREXH : ARM::LDREXH; strOpc = isThumb2 ? ARM::t2STREXH : ARM::STREXH; break; case 4: ldrOpc = isThumb2 ? ARM::t2LDREX : ARM::LDREX; strOpc = isThumb2 ? ARM::t2STREX : ARM::STREX; break; } MachineFunction *MF = BB->getParent(); const BasicBlock *LLVM_BB = BB->getBasicBlock(); MachineFunction::iterator It = BB; ++It; // insert the new blocks after the current block MachineBasicBlock *loop1MBB = MF->CreateMachineBasicBlock(LLVM_BB); MachineBasicBlock *loop2MBB = MF->CreateMachineBasicBlock(LLVM_BB); MachineBasicBlock *exitMBB = MF->CreateMachineBasicBlock(LLVM_BB); MF->insert(It, loop1MBB); MF->insert(It, loop2MBB); MF->insert(It, exitMBB); // Transfer the remainder of BB and its successor edges to exitMBB. exitMBB->splice(exitMBB->begin(), BB, llvm::next(MachineBasicBlock::iterator(MI)), BB->end()); exitMBB->transferSuccessorsAndUpdatePHIs(BB); // thisMBB: // ... // fallthrough --> loop1MBB BB->addSuccessor(loop1MBB); // loop1MBB: // ldrex dest, [ptr] // cmp dest, oldval // bne exitMBB BB = loop1MBB; MachineInstrBuilder MIB = BuildMI(BB, dl, TII->get(ldrOpc), dest).addReg(ptr); if (ldrOpc == ARM::t2LDREX) MIB.addImm(0); AddDefaultPred(MIB); AddDefaultPred(BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2CMPrr : ARM::CMPrr)) .addReg(dest).addReg(oldval)); BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2Bcc : ARM::Bcc)) .addMBB(exitMBB).addImm(ARMCC::NE).addReg(ARM::CPSR); BB->addSuccessor(loop2MBB); BB->addSuccessor(exitMBB); // loop2MBB: // strex scratch, newval, [ptr] // cmp scratch, #0 // bne loop1MBB BB = loop2MBB; MIB = BuildMI(BB, dl, TII->get(strOpc), scratch).addReg(newval).addReg(ptr); if (strOpc == ARM::t2STREX) MIB.addImm(0); AddDefaultPred(MIB); AddDefaultPred(BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2CMPri : ARM::CMPri)) .addReg(scratch).addImm(0)); BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2Bcc : ARM::Bcc)) .addMBB(loop1MBB).addImm(ARMCC::NE).addReg(ARM::CPSR); BB->addSuccessor(loop1MBB); BB->addSuccessor(exitMBB); // exitMBB: // ... BB = exitMBB; MI->eraseFromParent(); // The instruction is gone now. return BB; } MachineBasicBlock * ARMTargetLowering::EmitAtomicBinary(MachineInstr *MI, MachineBasicBlock *BB, unsigned Size, unsigned BinOpcode) const { // This also handles ATOMIC_SWAP, indicated by BinOpcode==0. const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); const BasicBlock *LLVM_BB = BB->getBasicBlock(); MachineFunction *MF = BB->getParent(); MachineFunction::iterator It = BB; ++It; unsigned dest = MI->getOperand(0).getReg(); unsigned ptr = MI->getOperand(1).getReg(); unsigned incr = MI->getOperand(2).getReg(); DebugLoc dl = MI->getDebugLoc(); bool isThumb2 = Subtarget->isThumb2(); MachineRegisterInfo &MRI = BB->getParent()->getRegInfo(); if (isThumb2) { MRI.constrainRegClass(dest, ARM::rGPRRegisterClass); MRI.constrainRegClass(ptr, ARM::rGPRRegisterClass); } unsigned ldrOpc, strOpc; switch (Size) { default: llvm_unreachable("unsupported size for AtomicCmpSwap!"); case 1: ldrOpc = isThumb2 ? ARM::t2LDREXB : ARM::LDREXB; strOpc = isThumb2 ? ARM::t2STREXB : ARM::STREXB; break; case 2: ldrOpc = isThumb2 ? ARM::t2LDREXH : ARM::LDREXH; strOpc = isThumb2 ? ARM::t2STREXH : ARM::STREXH; break; case 4: ldrOpc = isThumb2 ? ARM::t2LDREX : ARM::LDREX; strOpc = isThumb2 ? ARM::t2STREX : ARM::STREX; break; } MachineBasicBlock *loopMBB = MF->CreateMachineBasicBlock(LLVM_BB); MachineBasicBlock *exitMBB = MF->CreateMachineBasicBlock(LLVM_BB); MF->insert(It, loopMBB); MF->insert(It, exitMBB); // Transfer the remainder of BB and its successor edges to exitMBB. exitMBB->splice(exitMBB->begin(), BB, llvm::next(MachineBasicBlock::iterator(MI)), BB->end()); exitMBB->transferSuccessorsAndUpdatePHIs(BB); TargetRegisterClass *TRC = isThumb2 ? ARM::tGPRRegisterClass : ARM::GPRRegisterClass; unsigned scratch = MRI.createVirtualRegister(TRC); unsigned scratch2 = (!BinOpcode) ? incr : MRI.createVirtualRegister(TRC); // thisMBB: // ... // fallthrough --> loopMBB BB->addSuccessor(loopMBB); // loopMBB: // ldrex dest, ptr // scratch2, dest, incr // strex scratch, scratch2, ptr // cmp scratch, #0 // bne- loopMBB // fallthrough --> exitMBB BB = loopMBB; MachineInstrBuilder MIB = BuildMI(BB, dl, TII->get(ldrOpc), dest).addReg(ptr); if (ldrOpc == ARM::t2LDREX) MIB.addImm(0); AddDefaultPred(MIB); if (BinOpcode) { // operand order needs to go the other way for NAND if (BinOpcode == ARM::BICrr || BinOpcode == ARM::t2BICrr) AddDefaultPred(BuildMI(BB, dl, TII->get(BinOpcode), scratch2). addReg(incr).addReg(dest)).addReg(0); else AddDefaultPred(BuildMI(BB, dl, TII->get(BinOpcode), scratch2). addReg(dest).addReg(incr)).addReg(0); } MIB = BuildMI(BB, dl, TII->get(strOpc), scratch).addReg(scratch2).addReg(ptr); if (strOpc == ARM::t2STREX) MIB.addImm(0); AddDefaultPred(MIB); AddDefaultPred(BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2CMPri : ARM::CMPri)) .addReg(scratch).addImm(0)); BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2Bcc : ARM::Bcc)) .addMBB(loopMBB).addImm(ARMCC::NE).addReg(ARM::CPSR); BB->addSuccessor(loopMBB); BB->addSuccessor(exitMBB); // exitMBB: // ... BB = exitMBB; MI->eraseFromParent(); // The instruction is gone now. return BB; } MachineBasicBlock * ARMTargetLowering::EmitAtomicBinaryMinMax(MachineInstr *MI, MachineBasicBlock *BB, unsigned Size, bool signExtend, ARMCC::CondCodes Cond) const { const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); const BasicBlock *LLVM_BB = BB->getBasicBlock(); MachineFunction *MF = BB->getParent(); MachineFunction::iterator It = BB; ++It; unsigned dest = MI->getOperand(0).getReg(); unsigned ptr = MI->getOperand(1).getReg(); unsigned incr = MI->getOperand(2).getReg(); unsigned oldval = dest; DebugLoc dl = MI->getDebugLoc(); bool isThumb2 = Subtarget->isThumb2(); MachineRegisterInfo &MRI = BB->getParent()->getRegInfo(); if (isThumb2) { MRI.constrainRegClass(dest, ARM::rGPRRegisterClass); MRI.constrainRegClass(ptr, ARM::rGPRRegisterClass); } unsigned ldrOpc, strOpc, extendOpc; switch (Size) { default: llvm_unreachable("unsupported size for AtomicCmpSwap!"); case 1: ldrOpc = isThumb2 ? ARM::t2LDREXB : ARM::LDREXB; strOpc = isThumb2 ? ARM::t2STREXB : ARM::STREXB; extendOpc = isThumb2 ? ARM::t2SXTB : ARM::SXTB; break; case 2: ldrOpc = isThumb2 ? ARM::t2LDREXH : ARM::LDREXH; strOpc = isThumb2 ? ARM::t2STREXH : ARM::STREXH; extendOpc = isThumb2 ? ARM::t2SXTH : ARM::SXTH; break; case 4: ldrOpc = isThumb2 ? ARM::t2LDREX : ARM::LDREX; strOpc = isThumb2 ? ARM::t2STREX : ARM::STREX; extendOpc = 0; break; } MachineBasicBlock *loopMBB = MF->CreateMachineBasicBlock(LLVM_BB); MachineBasicBlock *exitMBB = MF->CreateMachineBasicBlock(LLVM_BB); MF->insert(It, loopMBB); MF->insert(It, exitMBB); // Transfer the remainder of BB and its successor edges to exitMBB. exitMBB->splice(exitMBB->begin(), BB, llvm::next(MachineBasicBlock::iterator(MI)), BB->end()); exitMBB->transferSuccessorsAndUpdatePHIs(BB); TargetRegisterClass *TRC = isThumb2 ? ARM::tGPRRegisterClass : ARM::GPRRegisterClass; unsigned scratch = MRI.createVirtualRegister(TRC); unsigned scratch2 = MRI.createVirtualRegister(TRC); // thisMBB: // ... // fallthrough --> loopMBB BB->addSuccessor(loopMBB); // loopMBB: // ldrex dest, ptr // (sign extend dest, if required) // cmp dest, incr // cmov.cond scratch2, dest, incr // strex scratch, scratch2, ptr // cmp scratch, #0 // bne- loopMBB // fallthrough --> exitMBB BB = loopMBB; MachineInstrBuilder MIB = BuildMI(BB, dl, TII->get(ldrOpc), dest).addReg(ptr); if (ldrOpc == ARM::t2LDREX) MIB.addImm(0); AddDefaultPred(MIB); // Sign extend the value, if necessary. if (signExtend && extendOpc) { oldval = MRI.createVirtualRegister(ARM::GPRRegisterClass); AddDefaultPred(BuildMI(BB, dl, TII->get(extendOpc), oldval) .addReg(dest) .addImm(0)); } // Build compare and cmov instructions. AddDefaultPred(BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2CMPrr : ARM::CMPrr)) .addReg(oldval).addReg(incr)); BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2MOVCCr : ARM::MOVCCr), scratch2) .addReg(oldval).addReg(incr).addImm(Cond).addReg(ARM::CPSR); MIB = BuildMI(BB, dl, TII->get(strOpc), scratch).addReg(scratch2).addReg(ptr); if (strOpc == ARM::t2STREX) MIB.addImm(0); AddDefaultPred(MIB); AddDefaultPred(BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2CMPri : ARM::CMPri)) .addReg(scratch).addImm(0)); BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2Bcc : ARM::Bcc)) .addMBB(loopMBB).addImm(ARMCC::NE).addReg(ARM::CPSR); BB->addSuccessor(loopMBB); BB->addSuccessor(exitMBB); // exitMBB: // ... BB = exitMBB; MI->eraseFromParent(); // The instruction is gone now. return BB; } MachineBasicBlock * ARMTargetLowering::EmitAtomicBinary64(MachineInstr *MI, MachineBasicBlock *BB, unsigned Op1, unsigned Op2, bool NeedsCarry, bool IsCmpxchg) const { // This also handles ATOMIC_SWAP, indicated by Op1==0. const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); const BasicBlock *LLVM_BB = BB->getBasicBlock(); MachineFunction *MF = BB->getParent(); MachineFunction::iterator It = BB; ++It; unsigned destlo = MI->getOperand(0).getReg(); unsigned desthi = MI->getOperand(1).getReg(); unsigned ptr = MI->getOperand(2).getReg(); unsigned vallo = MI->getOperand(3).getReg(); unsigned valhi = MI->getOperand(4).getReg(); DebugLoc dl = MI->getDebugLoc(); bool isThumb2 = Subtarget->isThumb2(); MachineRegisterInfo &MRI = BB->getParent()->getRegInfo(); if (isThumb2) { MRI.constrainRegClass(destlo, ARM::rGPRRegisterClass); MRI.constrainRegClass(desthi, ARM::rGPRRegisterClass); MRI.constrainRegClass(ptr, ARM::rGPRRegisterClass); } unsigned ldrOpc = isThumb2 ? ARM::t2LDREXD : ARM::LDREXD; unsigned strOpc = isThumb2 ? ARM::t2STREXD : ARM::STREXD; MachineBasicBlock *loopMBB = MF->CreateMachineBasicBlock(LLVM_BB); MachineBasicBlock *contBB = 0, *cont2BB = 0; if (IsCmpxchg) { contBB = MF->CreateMachineBasicBlock(LLVM_BB); cont2BB = MF->CreateMachineBasicBlock(LLVM_BB); } MachineBasicBlock *exitMBB = MF->CreateMachineBasicBlock(LLVM_BB); MF->insert(It, loopMBB); if (IsCmpxchg) { MF->insert(It, contBB); MF->insert(It, cont2BB); } MF->insert(It, exitMBB); // Transfer the remainder of BB and its successor edges to exitMBB. exitMBB->splice(exitMBB->begin(), BB, llvm::next(MachineBasicBlock::iterator(MI)), BB->end()); exitMBB->transferSuccessorsAndUpdatePHIs(BB); TargetRegisterClass *TRC = isThumb2 ? ARM::tGPRRegisterClass : ARM::GPRRegisterClass; unsigned storesuccess = MRI.createVirtualRegister(TRC); // thisMBB: // ... // fallthrough --> loopMBB BB->addSuccessor(loopMBB); // loopMBB: // ldrexd r2, r3, ptr // r0, r2, incr // r1, r3, incr // strexd storesuccess, r0, r1, ptr // cmp storesuccess, #0 // bne- loopMBB // fallthrough --> exitMBB // // Note that the registers are explicitly specified because there is not any // way to force the register allocator to allocate a register pair. // // FIXME: The hardcoded registers are not necessary for Thumb2, but we // need to properly enforce the restriction that the two output registers // for ldrexd must be different. BB = loopMBB; // Load AddDefaultPred(BuildMI(BB, dl, TII->get(ldrOpc)) .addReg(ARM::R2, RegState::Define) .addReg(ARM::R3, RegState::Define).addReg(ptr)); // Copy r2/r3 into dest. (This copy will normally be coalesced.) BuildMI(BB, dl, TII->get(TargetOpcode::COPY), destlo).addReg(ARM::R2); BuildMI(BB, dl, TII->get(TargetOpcode::COPY), desthi).addReg(ARM::R3); if (IsCmpxchg) { // Add early exit for (unsigned i = 0; i < 2; i++) { AddDefaultPred(BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2CMPrr : ARM::CMPrr)) .addReg(i == 0 ? destlo : desthi) .addReg(i == 0 ? vallo : valhi)); BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2Bcc : ARM::Bcc)) .addMBB(exitMBB).addImm(ARMCC::NE).addReg(ARM::CPSR); BB->addSuccessor(exitMBB); BB->addSuccessor(i == 0 ? contBB : cont2BB); BB = (i == 0 ? contBB : cont2BB); } // Copy to physregs for strexd unsigned setlo = MI->getOperand(5).getReg(); unsigned sethi = MI->getOperand(6).getReg(); BuildMI(BB, dl, TII->get(TargetOpcode::COPY), ARM::R0).addReg(setlo); BuildMI(BB, dl, TII->get(TargetOpcode::COPY), ARM::R1).addReg(sethi); } else if (Op1) { // Perform binary operation AddDefaultPred(BuildMI(BB, dl, TII->get(Op1), ARM::R0) .addReg(destlo).addReg(vallo)) .addReg(NeedsCarry ? ARM::CPSR : 0, getDefRegState(NeedsCarry)); AddDefaultPred(BuildMI(BB, dl, TII->get(Op2), ARM::R1) .addReg(desthi).addReg(valhi)).addReg(0); } else { // Copy to physregs for strexd BuildMI(BB, dl, TII->get(TargetOpcode::COPY), ARM::R0).addReg(vallo); BuildMI(BB, dl, TII->get(TargetOpcode::COPY), ARM::R1).addReg(valhi); } // Store AddDefaultPred(BuildMI(BB, dl, TII->get(strOpc), storesuccess) .addReg(ARM::R0).addReg(ARM::R1).addReg(ptr)); // Cmp+jump AddDefaultPred(BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2CMPri : ARM::CMPri)) .addReg(storesuccess).addImm(0)); BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2Bcc : ARM::Bcc)) .addMBB(loopMBB).addImm(ARMCC::NE).addReg(ARM::CPSR); BB->addSuccessor(loopMBB); BB->addSuccessor(exitMBB); // exitMBB: // ... BB = exitMBB; MI->eraseFromParent(); // The instruction is gone now. return BB; } /// EmitBasePointerRecalculation - For functions using a base pointer, we /// rematerialize it (via the frame pointer). void ARMTargetLowering:: EmitBasePointerRecalculation(MachineInstr *MI, MachineBasicBlock *MBB, MachineBasicBlock *DispatchBB) const { const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); const ARMBaseInstrInfo *AII = static_cast(TII); MachineFunction &MF = *MI->getParent()->getParent(); ARMFunctionInfo *AFI = MF.getInfo(); const ARMBaseRegisterInfo &RI = AII->getRegisterInfo(); if (!RI.hasBasePointer(MF)) return; MachineBasicBlock::iterator MBBI = MI; int32_t NumBytes = AFI->getFramePtrSpillOffset(); unsigned FramePtr = RI.getFrameRegister(MF); assert(MF.getTarget().getFrameLowering()->hasFP(MF) && "Base pointer without frame pointer?"); if (AFI->isThumb2Function()) llvm::emitT2RegPlusImmediate(*MBB, MBBI, MI->getDebugLoc(), ARM::R6, FramePtr, -NumBytes, ARMCC::AL, 0, *AII); else if (AFI->isThumbFunction()) llvm::emitThumbRegPlusImmediate(*MBB, MBBI, MI->getDebugLoc(), ARM::R6, FramePtr, -NumBytes, *AII, RI); else llvm::emitARMRegPlusImmediate(*MBB, MBBI, MI->getDebugLoc(), ARM::R6, FramePtr, -NumBytes, ARMCC::AL, 0, *AII); if (!RI.needsStackRealignment(MF)) return; // If there's dynamic realignment, adjust for it. MachineFrameInfo *MFI = MF.getFrameInfo(); unsigned MaxAlign = MFI->getMaxAlignment(); assert(!AFI->isThumb1OnlyFunction()); // Emit bic r6, r6, MaxAlign unsigned bicOpc = AFI->isThumbFunction() ? ARM::t2BICri : ARM::BICri; AddDefaultCC( AddDefaultPred( BuildMI(*MBB, MBBI, MI->getDebugLoc(), TII->get(bicOpc), ARM::R6) .addReg(ARM::R6, RegState::Kill) .addImm(MaxAlign - 1))); } /// SetupEntryBlockForSjLj - Insert code into the entry block that creates and /// registers the function context. void ARMTargetLowering:: SetupEntryBlockForSjLj(MachineInstr *MI, MachineBasicBlock *MBB, MachineBasicBlock *DispatchBB, int FI) const { const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); DebugLoc dl = MI->getDebugLoc(); MachineFunction *MF = MBB->getParent(); MachineRegisterInfo *MRI = &MF->getRegInfo(); MachineConstantPool *MCP = MF->getConstantPool(); ARMFunctionInfo *AFI = MF->getInfo(); const Function *F = MF->getFunction(); bool isThumb = Subtarget->isThumb(); bool isThumb2 = Subtarget->isThumb2(); unsigned PCLabelId = AFI->createPICLabelUId(); unsigned PCAdj = (isThumb || isThumb2) ? 4 : 8; ARMConstantPoolValue *CPV = ARMConstantPoolMBB::Create(F->getContext(), DispatchBB, PCLabelId, PCAdj); unsigned CPI = MCP->getConstantPoolIndex(CPV, 4); const TargetRegisterClass *TRC = isThumb ? ARM::tGPRRegisterClass : ARM::GPRRegisterClass; // Grab constant pool and fixed stack memory operands. MachineMemOperand *CPMMO = MF->getMachineMemOperand(MachinePointerInfo::getConstantPool(), MachineMemOperand::MOLoad, 4, 4); MachineMemOperand *FIMMOSt = MF->getMachineMemOperand(MachinePointerInfo::getFixedStack(FI), MachineMemOperand::MOStore, 4, 4); EmitBasePointerRecalculation(MI, MBB, DispatchBB); // Load the address of the dispatch MBB into the jump buffer. if (isThumb2) { // Incoming value: jbuf // ldr.n r5, LCPI1_1 // orr r5, r5, #1 // add r5, pc // str r5, [$jbuf, #+4] ; &jbuf[1] unsigned NewVReg1 = MRI->createVirtualRegister(TRC); AddDefaultPred(BuildMI(*MBB, MI, dl, TII->get(ARM::t2LDRpci), NewVReg1) .addConstantPoolIndex(CPI) .addMemOperand(CPMMO)); // Set the low bit because of thumb mode. unsigned NewVReg2 = MRI->createVirtualRegister(TRC); AddDefaultCC( AddDefaultPred(BuildMI(*MBB, MI, dl, TII->get(ARM::t2ORRri), NewVReg2) .addReg(NewVReg1, RegState::Kill) .addImm(0x01))); unsigned NewVReg3 = MRI->createVirtualRegister(TRC); BuildMI(*MBB, MI, dl, TII->get(ARM::tPICADD), NewVReg3) .addReg(NewVReg2, RegState::Kill) .addImm(PCLabelId); AddDefaultPred(BuildMI(*MBB, MI, dl, TII->get(ARM::t2STRi12)) .addReg(NewVReg3, RegState::Kill) .addFrameIndex(FI) .addImm(36) // &jbuf[1] :: pc .addMemOperand(FIMMOSt)); } else if (isThumb) { // Incoming value: jbuf // ldr.n r1, LCPI1_4 // add r1, pc // mov r2, #1 // orrs r1, r2 // add r2, $jbuf, #+4 ; &jbuf[1] // str r1, [r2] unsigned NewVReg1 = MRI->createVirtualRegister(TRC); AddDefaultPred(BuildMI(*MBB, MI, dl, TII->get(ARM::tLDRpci), NewVReg1) .addConstantPoolIndex(CPI) .addMemOperand(CPMMO)); unsigned NewVReg2 = MRI->createVirtualRegister(TRC); BuildMI(*MBB, MI, dl, TII->get(ARM::tPICADD), NewVReg2) .addReg(NewVReg1, RegState::Kill) .addImm(PCLabelId); // Set the low bit because of thumb mode. unsigned NewVReg3 = MRI->createVirtualRegister(TRC); AddDefaultPred(BuildMI(*MBB, MI, dl, TII->get(ARM::tMOVi8), NewVReg3) .addReg(ARM::CPSR, RegState::Define) .addImm(1)); unsigned NewVReg4 = MRI->createVirtualRegister(TRC); AddDefaultPred(BuildMI(*MBB, MI, dl, TII->get(ARM::tORR), NewVReg4) .addReg(ARM::CPSR, RegState::Define) .addReg(NewVReg2, RegState::Kill) .addReg(NewVReg3, RegState::Kill)); unsigned NewVReg5 = MRI->createVirtualRegister(TRC); AddDefaultPred(BuildMI(*MBB, MI, dl, TII->get(ARM::tADDrSPi), NewVReg5) .addFrameIndex(FI) .addImm(36)); // &jbuf[1] :: pc AddDefaultPred(BuildMI(*MBB, MI, dl, TII->get(ARM::tSTRi)) .addReg(NewVReg4, RegState::Kill) .addReg(NewVReg5, RegState::Kill) .addImm(0) .addMemOperand(FIMMOSt)); } else { // Incoming value: jbuf // ldr r1, LCPI1_1 // add r1, pc, r1 // str r1, [$jbuf, #+4] ; &jbuf[1] unsigned NewVReg1 = MRI->createVirtualRegister(TRC); AddDefaultPred(BuildMI(*MBB, MI, dl, TII->get(ARM::LDRi12), NewVReg1) .addConstantPoolIndex(CPI) .addImm(0) .addMemOperand(CPMMO)); unsigned NewVReg2 = MRI->createVirtualRegister(TRC); AddDefaultPred(BuildMI(*MBB, MI, dl, TII->get(ARM::PICADD), NewVReg2) .addReg(NewVReg1, RegState::Kill) .addImm(PCLabelId)); AddDefaultPred(BuildMI(*MBB, MI, dl, TII->get(ARM::STRi12)) .addReg(NewVReg2, RegState::Kill) .addFrameIndex(FI) .addImm(36) // &jbuf[1] :: pc .addMemOperand(FIMMOSt)); } } MachineBasicBlock *ARMTargetLowering:: EmitSjLjDispatchBlock(MachineInstr *MI, MachineBasicBlock *MBB) const { const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); DebugLoc dl = MI->getDebugLoc(); MachineFunction *MF = MBB->getParent(); MachineRegisterInfo *MRI = &MF->getRegInfo(); ARMFunctionInfo *AFI = MF->getInfo(); MachineFrameInfo *MFI = MF->getFrameInfo(); int FI = MFI->getFunctionContextIndex(); const TargetRegisterClass *TRC = Subtarget->isThumb() ? ARM::tGPRRegisterClass : ARM::GPRRegisterClass; // Get a mapping of the call site numbers to all of the landing pads they're // associated with. DenseMap > CallSiteNumToLPad; unsigned MaxCSNum = 0; MachineModuleInfo &MMI = MF->getMMI(); for (MachineFunction::iterator BB = MF->begin(), E = MF->end(); BB != E; ++BB) { if (!BB->isLandingPad()) continue; // FIXME: We should assert that the EH_LABEL is the first MI in the landing // pad. for (MachineBasicBlock::iterator II = BB->begin(), IE = BB->end(); II != IE; ++II) { if (!II->isEHLabel()) continue; MCSymbol *Sym = II->getOperand(0).getMCSymbol(); if (!MMI.hasCallSiteLandingPad(Sym)) continue; SmallVectorImpl &CallSiteIdxs = MMI.getCallSiteLandingPad(Sym); for (SmallVectorImpl::iterator CSI = CallSiteIdxs.begin(), CSE = CallSiteIdxs.end(); CSI != CSE; ++CSI) { CallSiteNumToLPad[*CSI].push_back(BB); MaxCSNum = std::max(MaxCSNum, *CSI); } break; } } // Get an ordered list of the machine basic blocks for the jump table. std::vector LPadList; SmallPtrSet InvokeBBs; LPadList.reserve(CallSiteNumToLPad.size()); for (unsigned I = 1; I <= MaxCSNum; ++I) { SmallVectorImpl &MBBList = CallSiteNumToLPad[I]; for (SmallVectorImpl::iterator II = MBBList.begin(), IE = MBBList.end(); II != IE; ++II) { LPadList.push_back(*II); InvokeBBs.insert((*II)->pred_begin(), (*II)->pred_end()); } } assert(!LPadList.empty() && "No landing pad destinations for the dispatch jump table!"); // Create the jump table and associated information. MachineJumpTableInfo *JTI = MF->getOrCreateJumpTableInfo(MachineJumpTableInfo::EK_Inline); unsigned MJTI = JTI->createJumpTableIndex(LPadList); unsigned UId = AFI->createJumpTableUId(); // Create the MBBs for the dispatch code. // Shove the dispatch's address into the return slot in the function context. MachineBasicBlock *DispatchBB = MF->CreateMachineBasicBlock(); DispatchBB->setIsLandingPad(); MachineBasicBlock *TrapBB = MF->CreateMachineBasicBlock(); BuildMI(TrapBB, dl, TII->get(Subtarget->isThumb() ? ARM::tTRAP : ARM::TRAP)); DispatchBB->addSuccessor(TrapBB); MachineBasicBlock *DispContBB = MF->CreateMachineBasicBlock(); DispatchBB->addSuccessor(DispContBB); // Insert and renumber MBBs. MachineBasicBlock *Last = &MF->back(); MF->insert(MF->end(), DispatchBB); MF->insert(MF->end(), DispContBB); MF->insert(MF->end(), TrapBB); MF->RenumberBlocks(Last); // Insert code into the entry block that creates and registers the function // context. SetupEntryBlockForSjLj(MI, MBB, DispatchBB, FI); MachineMemOperand *FIMMOLd = MF->getMachineMemOperand(MachinePointerInfo::getFixedStack(FI), MachineMemOperand::MOLoad | MachineMemOperand::MOVolatile, 4, 4); if (Subtarget->isThumb2()) { unsigned NewVReg1 = MRI->createVirtualRegister(TRC); AddDefaultPred(BuildMI(DispatchBB, dl, TII->get(ARM::t2LDRi12), NewVReg1) .addFrameIndex(FI) .addImm(4) .addMemOperand(FIMMOLd)); AddDefaultPred(BuildMI(DispatchBB, dl, TII->get(ARM::t2CMPri)) .addReg(NewVReg1) .addImm(LPadList.size())); BuildMI(DispatchBB, dl, TII->get(ARM::t2Bcc)) .addMBB(TrapBB) .addImm(ARMCC::HI) .addReg(ARM::CPSR); unsigned NewVReg2 = MRI->createVirtualRegister(TRC); AddDefaultPred(BuildMI(DispContBB, dl, TII->get(ARM::t2LEApcrelJT),NewVReg2) .addJumpTableIndex(MJTI) .addImm(UId)); unsigned NewVReg3 = MRI->createVirtualRegister(TRC); AddDefaultCC( AddDefaultPred( BuildMI(DispContBB, dl, TII->get(ARM::t2ADDrs), NewVReg3) .addReg(NewVReg2, RegState::Kill) .addReg(NewVReg1) .addImm(ARM_AM::getSORegOpc(ARM_AM::lsl, 2)))); BuildMI(DispContBB, dl, TII->get(ARM::t2BR_JT)) .addReg(NewVReg3, RegState::Kill) .addReg(NewVReg1) .addJumpTableIndex(MJTI) .addImm(UId); } else if (Subtarget->isThumb()) { unsigned NewVReg1 = MRI->createVirtualRegister(TRC); AddDefaultPred(BuildMI(DispatchBB, dl, TII->get(ARM::tLDRspi), NewVReg1) .addFrameIndex(FI) .addImm(1) .addMemOperand(FIMMOLd)); AddDefaultPred(BuildMI(DispatchBB, dl, TII->get(ARM::tCMPi8)) .addReg(NewVReg1) .addImm(LPadList.size())); BuildMI(DispatchBB, dl, TII->get(ARM::tBcc)) .addMBB(TrapBB) .addImm(ARMCC::HI) .addReg(ARM::CPSR); unsigned NewVReg2 = MRI->createVirtualRegister(TRC); AddDefaultPred(BuildMI(DispContBB, dl, TII->get(ARM::tLSLri), NewVReg2) .addReg(ARM::CPSR, RegState::Define) .addReg(NewVReg1) .addImm(2)); unsigned NewVReg3 = MRI->createVirtualRegister(TRC); AddDefaultPred(BuildMI(DispContBB, dl, TII->get(ARM::tLEApcrelJT), NewVReg3) .addJumpTableIndex(MJTI) .addImm(UId)); unsigned NewVReg4 = MRI->createVirtualRegister(TRC); AddDefaultPred(BuildMI(DispContBB, dl, TII->get(ARM::tADDrr), NewVReg4) .addReg(ARM::CPSR, RegState::Define) .addReg(NewVReg2, RegState::Kill) .addReg(NewVReg3)); MachineMemOperand *JTMMOLd = MF->getMachineMemOperand(MachinePointerInfo::getJumpTable(), MachineMemOperand::MOLoad, 4, 4); unsigned NewVReg5 = MRI->createVirtualRegister(TRC); AddDefaultPred(BuildMI(DispContBB, dl, TII->get(ARM::tLDRi), NewVReg5) .addReg(NewVReg4, RegState::Kill) .addImm(0) .addMemOperand(JTMMOLd)); unsigned NewVReg6 = MRI->createVirtualRegister(TRC); AddDefaultPred(BuildMI(DispContBB, dl, TII->get(ARM::tADDrr), NewVReg6) .addReg(ARM::CPSR, RegState::Define) .addReg(NewVReg5, RegState::Kill) .addReg(NewVReg3)); BuildMI(DispContBB, dl, TII->get(ARM::tBR_JTr)) .addReg(NewVReg6, RegState::Kill) .addJumpTableIndex(MJTI) .addImm(UId); } else { unsigned NewVReg1 = MRI->createVirtualRegister(TRC); AddDefaultPred(BuildMI(DispatchBB, dl, TII->get(ARM::LDRi12), NewVReg1) .addFrameIndex(FI) .addImm(4) .addMemOperand(FIMMOLd)); AddDefaultPred(BuildMI(DispatchBB, dl, TII->get(ARM::CMPri)) .addReg(NewVReg1) .addImm(LPadList.size())); BuildMI(DispatchBB, dl, TII->get(ARM::Bcc)) .addMBB(TrapBB) .addImm(ARMCC::HI) .addReg(ARM::CPSR); unsigned NewVReg2 = MRI->createVirtualRegister(TRC); AddDefaultCC( AddDefaultPred(BuildMI(DispContBB, dl, TII->get(ARM::MOVsi), NewVReg2) .addReg(NewVReg1) .addImm(ARM_AM::getSORegOpc(ARM_AM::lsl, 2)))); unsigned NewVReg3 = MRI->createVirtualRegister(TRC); AddDefaultPred(BuildMI(DispContBB, dl, TII->get(ARM::LEApcrelJT), NewVReg3) .addJumpTableIndex(MJTI) .addImm(UId)); MachineMemOperand *JTMMOLd = MF->getMachineMemOperand(MachinePointerInfo::getJumpTable(), MachineMemOperand::MOLoad, 4, 4); unsigned NewVReg4 = MRI->createVirtualRegister(TRC); AddDefaultPred( BuildMI(DispContBB, dl, TII->get(ARM::LDRrs), NewVReg4) .addReg(NewVReg2, RegState::Kill) .addReg(NewVReg3) .addImm(0) .addMemOperand(JTMMOLd)); BuildMI(DispContBB, dl, TII->get(ARM::BR_JTadd)) .addReg(NewVReg4, RegState::Kill) .addReg(NewVReg3) .addJumpTableIndex(MJTI) .addImm(UId); } // Add the jump table entries as successors to the MBB. MachineBasicBlock *PrevMBB = 0; for (std::vector::iterator I = LPadList.begin(), E = LPadList.end(); I != E; ++I) { MachineBasicBlock *CurMBB = *I; if (PrevMBB != CurMBB) DispContBB->addSuccessor(CurMBB); PrevMBB = CurMBB; } const ARMBaseInstrInfo *AII = static_cast(TII); const ARMBaseRegisterInfo &RI = AII->getRegisterInfo(); const unsigned *SavedRegs = RI.getCalleeSavedRegs(MF); for (SmallPtrSet::iterator I = InvokeBBs.begin(), E = InvokeBBs.end(); I != E; ++I) { MachineBasicBlock *BB = *I; // Remove the landing pad successor from the invoke block and replace it // with the new dispatch block. for (MachineBasicBlock::succ_iterator SI = BB->succ_begin(), SE = BB->succ_end(); SI != SE; ++SI) { MachineBasicBlock *SMBB = *SI; if (SMBB->isLandingPad()) { BB->removeSuccessor(SMBB); SMBB->setIsLandingPad(false); } } BB->addSuccessor(DispatchBB); // Find the invoke call and mark all of the callee-saved registers as // 'implicit defined' so that they're spilled. This prevents code from // moving instructions to before the EH block, where they will never be // executed. for (MachineBasicBlock::reverse_iterator II = BB->rbegin(), IE = BB->rend(); II != IE; ++II) { if (!II->getDesc().isCall()) continue; DenseMap DefRegs; for (MachineInstr::mop_iterator OI = II->operands_begin(), OE = II->operands_end(); OI != OE; ++OI) { if (!OI->isReg()) continue; DefRegs[OI->getReg()] = true; } MachineInstrBuilder MIB(&*II); for (unsigned i = 0; SavedRegs[i] != 0; ++i) { if (!TRC->contains(SavedRegs[i])) continue; if (!DefRegs[SavedRegs[i]]) MIB.addReg(SavedRegs[i], RegState::ImplicitDefine | RegState::Dead); } break; } } // The instruction is gone now. MI->eraseFromParent(); return MBB; } static MachineBasicBlock *OtherSucc(MachineBasicBlock *MBB, MachineBasicBlock *Succ) { for (MachineBasicBlock::succ_iterator I = MBB->succ_begin(), E = MBB->succ_end(); I != E; ++I) if (*I != Succ) return *I; llvm_unreachable("Expecting a BB with two successors!"); } MachineBasicBlock * ARMTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, MachineBasicBlock *BB) const { const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); DebugLoc dl = MI->getDebugLoc(); bool isThumb2 = Subtarget->isThumb2(); switch (MI->getOpcode()) { default: { MI->dump(); llvm_unreachable("Unexpected instr type to insert"); } // The Thumb2 pre-indexed stores have the same MI operands, they just // define them differently in the .td files from the isel patterns, so // they need pseudos. case ARM::t2STR_preidx: MI->setDesc(TII->get(ARM::t2STR_PRE)); return BB; case ARM::t2STRB_preidx: MI->setDesc(TII->get(ARM::t2STRB_PRE)); return BB; case ARM::t2STRH_preidx: MI->setDesc(TII->get(ARM::t2STRH_PRE)); return BB; case ARM::STRi_preidx: case ARM::STRBi_preidx: { unsigned NewOpc = MI->getOpcode() == ARM::STRi_preidx ? ARM::STR_PRE_IMM : ARM::STRB_PRE_IMM; // Decode the offset. unsigned Offset = MI->getOperand(4).getImm(); bool isSub = ARM_AM::getAM2Op(Offset) == ARM_AM::sub; Offset = ARM_AM::getAM2Offset(Offset); if (isSub) Offset = -Offset; MachineMemOperand *MMO = *MI->memoperands_begin(); BuildMI(*BB, MI, dl, TII->get(NewOpc)) .addOperand(MI->getOperand(0)) // Rn_wb .addOperand(MI->getOperand(1)) // Rt .addOperand(MI->getOperand(2)) // Rn .addImm(Offset) // offset (skip GPR==zero_reg) .addOperand(MI->getOperand(5)) // pred .addOperand(MI->getOperand(6)) .addMemOperand(MMO); MI->eraseFromParent(); return BB; } case ARM::STRr_preidx: case ARM::STRBr_preidx: case ARM::STRH_preidx: { unsigned NewOpc; switch (MI->getOpcode()) { default: llvm_unreachable("unexpected opcode!"); case ARM::STRr_preidx: NewOpc = ARM::STR_PRE_REG; break; case ARM::STRBr_preidx: NewOpc = ARM::STRB_PRE_REG; break; case ARM::STRH_preidx: NewOpc = ARM::STRH_PRE; break; } MachineInstrBuilder MIB = BuildMI(*BB, MI, dl, TII->get(NewOpc)); for (unsigned i = 0; i < MI->getNumOperands(); ++i) MIB.addOperand(MI->getOperand(i)); MI->eraseFromParent(); return BB; } case ARM::ATOMIC_LOAD_ADD_I8: return EmitAtomicBinary(MI, BB, 1, isThumb2 ? ARM::t2ADDrr : ARM::ADDrr); case ARM::ATOMIC_LOAD_ADD_I16: return EmitAtomicBinary(MI, BB, 2, isThumb2 ? ARM::t2ADDrr : ARM::ADDrr); case ARM::ATOMIC_LOAD_ADD_I32: return EmitAtomicBinary(MI, BB, 4, isThumb2 ? ARM::t2ADDrr : ARM::ADDrr); case ARM::ATOMIC_LOAD_AND_I8: return EmitAtomicBinary(MI, BB, 1, isThumb2 ? ARM::t2ANDrr : ARM::ANDrr); case ARM::ATOMIC_LOAD_AND_I16: return EmitAtomicBinary(MI, BB, 2, isThumb2 ? ARM::t2ANDrr : ARM::ANDrr); case ARM::ATOMIC_LOAD_AND_I32: return EmitAtomicBinary(MI, BB, 4, isThumb2 ? ARM::t2ANDrr : ARM::ANDrr); case ARM::ATOMIC_LOAD_OR_I8: return EmitAtomicBinary(MI, BB, 1, isThumb2 ? ARM::t2ORRrr : ARM::ORRrr); case ARM::ATOMIC_LOAD_OR_I16: return EmitAtomicBinary(MI, BB, 2, isThumb2 ? ARM::t2ORRrr : ARM::ORRrr); case ARM::ATOMIC_LOAD_OR_I32: return EmitAtomicBinary(MI, BB, 4, isThumb2 ? ARM::t2ORRrr : ARM::ORRrr); case ARM::ATOMIC_LOAD_XOR_I8: return EmitAtomicBinary(MI, BB, 1, isThumb2 ? ARM::t2EORrr : ARM::EORrr); case ARM::ATOMIC_LOAD_XOR_I16: return EmitAtomicBinary(MI, BB, 2, isThumb2 ? ARM::t2EORrr : ARM::EORrr); case ARM::ATOMIC_LOAD_XOR_I32: return EmitAtomicBinary(MI, BB, 4, isThumb2 ? ARM::t2EORrr : ARM::EORrr); case ARM::ATOMIC_LOAD_NAND_I8: return EmitAtomicBinary(MI, BB, 1, isThumb2 ? ARM::t2BICrr : ARM::BICrr); case ARM::ATOMIC_LOAD_NAND_I16: return EmitAtomicBinary(MI, BB, 2, isThumb2 ? ARM::t2BICrr : ARM::BICrr); case ARM::ATOMIC_LOAD_NAND_I32: return EmitAtomicBinary(MI, BB, 4, isThumb2 ? ARM::t2BICrr : ARM::BICrr); case ARM::ATOMIC_LOAD_SUB_I8: return EmitAtomicBinary(MI, BB, 1, isThumb2 ? ARM::t2SUBrr : ARM::SUBrr); case ARM::ATOMIC_LOAD_SUB_I16: return EmitAtomicBinary(MI, BB, 2, isThumb2 ? ARM::t2SUBrr : ARM::SUBrr); case ARM::ATOMIC_LOAD_SUB_I32: return EmitAtomicBinary(MI, BB, 4, isThumb2 ? ARM::t2SUBrr : ARM::SUBrr); case ARM::ATOMIC_LOAD_MIN_I8: return EmitAtomicBinaryMinMax(MI, BB, 1, true, ARMCC::LT); case ARM::ATOMIC_LOAD_MIN_I16: return EmitAtomicBinaryMinMax(MI, BB, 2, true, ARMCC::LT); case ARM::ATOMIC_LOAD_MIN_I32: return EmitAtomicBinaryMinMax(MI, BB, 4, true, ARMCC::LT); case ARM::ATOMIC_LOAD_MAX_I8: return EmitAtomicBinaryMinMax(MI, BB, 1, true, ARMCC::GT); case ARM::ATOMIC_LOAD_MAX_I16: return EmitAtomicBinaryMinMax(MI, BB, 2, true, ARMCC::GT); case ARM::ATOMIC_LOAD_MAX_I32: return EmitAtomicBinaryMinMax(MI, BB, 4, true, ARMCC::GT); case ARM::ATOMIC_LOAD_UMIN_I8: return EmitAtomicBinaryMinMax(MI, BB, 1, false, ARMCC::LO); case ARM::ATOMIC_LOAD_UMIN_I16: return EmitAtomicBinaryMinMax(MI, BB, 2, false, ARMCC::LO); case ARM::ATOMIC_LOAD_UMIN_I32: return EmitAtomicBinaryMinMax(MI, BB, 4, false, ARMCC::LO); case ARM::ATOMIC_LOAD_UMAX_I8: return EmitAtomicBinaryMinMax(MI, BB, 1, false, ARMCC::HI); case ARM::ATOMIC_LOAD_UMAX_I16: return EmitAtomicBinaryMinMax(MI, BB, 2, false, ARMCC::HI); case ARM::ATOMIC_LOAD_UMAX_I32: return EmitAtomicBinaryMinMax(MI, BB, 4, false, ARMCC::HI); case ARM::ATOMIC_SWAP_I8: return EmitAtomicBinary(MI, BB, 1, 0); case ARM::ATOMIC_SWAP_I16: return EmitAtomicBinary(MI, BB, 2, 0); case ARM::ATOMIC_SWAP_I32: return EmitAtomicBinary(MI, BB, 4, 0); case ARM::ATOMIC_CMP_SWAP_I8: return EmitAtomicCmpSwap(MI, BB, 1); case ARM::ATOMIC_CMP_SWAP_I16: return EmitAtomicCmpSwap(MI, BB, 2); case ARM::ATOMIC_CMP_SWAP_I32: return EmitAtomicCmpSwap(MI, BB, 4); case ARM::ATOMADD6432: return EmitAtomicBinary64(MI, BB, isThumb2 ? ARM::t2ADDrr : ARM::ADDrr, isThumb2 ? ARM::t2ADCrr : ARM::ADCrr, /*NeedsCarry*/ true); case ARM::ATOMSUB6432: return EmitAtomicBinary64(MI, BB, isThumb2 ? ARM::t2SUBrr : ARM::SUBrr, isThumb2 ? ARM::t2SBCrr : ARM::SBCrr, /*NeedsCarry*/ true); case ARM::ATOMOR6432: return EmitAtomicBinary64(MI, BB, isThumb2 ? ARM::t2ORRrr : ARM::ORRrr, isThumb2 ? ARM::t2ORRrr : ARM::ORRrr); case ARM::ATOMXOR6432: return EmitAtomicBinary64(MI, BB, isThumb2 ? ARM::t2EORrr : ARM::EORrr, isThumb2 ? ARM::t2EORrr : ARM::EORrr); case ARM::ATOMAND6432: return EmitAtomicBinary64(MI, BB, isThumb2 ? ARM::t2ANDrr : ARM::ANDrr, isThumb2 ? ARM::t2ANDrr : ARM::ANDrr); case ARM::ATOMSWAP6432: return EmitAtomicBinary64(MI, BB, 0, 0, false); case ARM::ATOMCMPXCHG6432: return EmitAtomicBinary64(MI, BB, isThumb2 ? ARM::t2SUBrr : ARM::SUBrr, isThumb2 ? ARM::t2SBCrr : ARM::SBCrr, /*NeedsCarry*/ false, /*IsCmpxchg*/true); case ARM::tMOVCCr_pseudo: { // To "insert" a SELECT_CC instruction, we actually have to insert the // diamond control-flow pattern. The incoming instruction knows the // destination vreg to set, the condition code register to branch on, the // true/false values to select between, and a branch opcode to use. const BasicBlock *LLVM_BB = BB->getBasicBlock(); MachineFunction::iterator It = BB; ++It; // thisMBB: // ... // TrueVal = ... // cmpTY ccX, r1, r2 // bCC copy1MBB // fallthrough --> copy0MBB MachineBasicBlock *thisMBB = BB; MachineFunction *F = BB->getParent(); MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB); MachineBasicBlock *sinkMBB = F->CreateMachineBasicBlock(LLVM_BB); F->insert(It, copy0MBB); F->insert(It, sinkMBB); // Transfer the remainder of BB and its successor edges to sinkMBB. sinkMBB->splice(sinkMBB->begin(), BB, llvm::next(MachineBasicBlock::iterator(MI)), BB->end()); sinkMBB->transferSuccessorsAndUpdatePHIs(BB); BB->addSuccessor(copy0MBB); BB->addSuccessor(sinkMBB); BuildMI(BB, dl, TII->get(ARM::tBcc)).addMBB(sinkMBB) .addImm(MI->getOperand(3).getImm()).addReg(MI->getOperand(4).getReg()); // copy0MBB: // %FalseValue = ... // # fallthrough to sinkMBB BB = copy0MBB; // Update machine-CFG edges BB->addSuccessor(sinkMBB); // sinkMBB: // %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ] // ... BB = sinkMBB; BuildMI(*BB, BB->begin(), dl, TII->get(ARM::PHI), MI->getOperand(0).getReg()) .addReg(MI->getOperand(1).getReg()).addMBB(copy0MBB) .addReg(MI->getOperand(2).getReg()).addMBB(thisMBB); MI->eraseFromParent(); // The pseudo instruction is gone now. return BB; } case ARM::BCCi64: case ARM::BCCZi64: { // If there is an unconditional branch to the other successor, remove it. BB->erase(llvm::next(MachineBasicBlock::iterator(MI)), BB->end()); // Compare both parts that make up the double comparison separately for // equality. bool RHSisZero = MI->getOpcode() == ARM::BCCZi64; unsigned LHS1 = MI->getOperand(1).getReg(); unsigned LHS2 = MI->getOperand(2).getReg(); if (RHSisZero) { AddDefaultPred(BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2CMPri : ARM::CMPri)) .addReg(LHS1).addImm(0)); BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2CMPri : ARM::CMPri)) .addReg(LHS2).addImm(0) .addImm(ARMCC::EQ).addReg(ARM::CPSR); } else { unsigned RHS1 = MI->getOperand(3).getReg(); unsigned RHS2 = MI->getOperand(4).getReg(); AddDefaultPred(BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2CMPrr : ARM::CMPrr)) .addReg(LHS1).addReg(RHS1)); BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2CMPrr : ARM::CMPrr)) .addReg(LHS2).addReg(RHS2) .addImm(ARMCC::EQ).addReg(ARM::CPSR); } MachineBasicBlock *destMBB = MI->getOperand(RHSisZero ? 3 : 5).getMBB(); MachineBasicBlock *exitMBB = OtherSucc(BB, destMBB); if (MI->getOperand(0).getImm() == ARMCC::NE) std::swap(destMBB, exitMBB); BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2Bcc : ARM::Bcc)) .addMBB(destMBB).addImm(ARMCC::EQ).addReg(ARM::CPSR); if (isThumb2) AddDefaultPred(BuildMI(BB, dl, TII->get(ARM::t2B)).addMBB(exitMBB)); else BuildMI(BB, dl, TII->get(ARM::B)) .addMBB(exitMBB); MI->eraseFromParent(); // The pseudo instruction is gone now. return BB; } case ARM::ABS: case ARM::t2ABS: { // To insert an ABS instruction, we have to insert the // diamond control-flow pattern. The incoming instruction knows the // source vreg to test against 0, the destination vreg to set, // the condition code register to branch on, the // true/false values to select between, and a branch opcode to use. // It transforms // V1 = ABS V0 // into // V2 = MOVS V0 // BCC (branch to SinkBB if V0 >= 0) // RSBBB: V3 = RSBri V2, 0 (compute ABS if V2 < 0) // SinkBB: V1 = PHI(V2, V3) const BasicBlock *LLVM_BB = BB->getBasicBlock(); MachineFunction::iterator BBI = BB; ++BBI; MachineFunction *Fn = BB->getParent(); MachineBasicBlock *RSBBB = Fn->CreateMachineBasicBlock(LLVM_BB); MachineBasicBlock *SinkBB = Fn->CreateMachineBasicBlock(LLVM_BB); Fn->insert(BBI, RSBBB); Fn->insert(BBI, SinkBB); unsigned int ABSSrcReg = MI->getOperand(1).getReg(); unsigned int ABSDstReg = MI->getOperand(0).getReg(); bool isThumb2 = Subtarget->isThumb2(); MachineRegisterInfo &MRI = Fn->getRegInfo(); // In Thumb mode S must not be specified if source register is the SP or // PC and if destination register is the SP, so restrict register class unsigned NewMovDstReg = MRI.createVirtualRegister( isThumb2 ? ARM::rGPRRegisterClass : ARM::GPRRegisterClass); unsigned NewRsbDstReg = MRI.createVirtualRegister( isThumb2 ? ARM::rGPRRegisterClass : ARM::GPRRegisterClass); // Transfer the remainder of BB and its successor edges to sinkMBB. SinkBB->splice(SinkBB->begin(), BB, llvm::next(MachineBasicBlock::iterator(MI)), BB->end()); SinkBB->transferSuccessorsAndUpdatePHIs(BB); BB->addSuccessor(RSBBB); BB->addSuccessor(SinkBB); // fall through to SinkMBB RSBBB->addSuccessor(SinkBB); // insert a movs at the end of BB BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2MOVr : ARM::MOVr), NewMovDstReg) .addReg(ABSSrcReg, RegState::Kill) .addImm((unsigned)ARMCC::AL).addReg(0) .addReg(ARM::CPSR, RegState::Define); // insert a bcc with opposite CC to ARMCC::MI at the end of BB BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2Bcc : ARM::Bcc)).addMBB(SinkBB) .addImm(ARMCC::getOppositeCondition(ARMCC::MI)).addReg(ARM::CPSR); // insert rsbri in RSBBB // Note: BCC and rsbri will be converted into predicated rsbmi // by if-conversion pass BuildMI(*RSBBB, RSBBB->begin(), dl, TII->get(isThumb2 ? ARM::t2RSBri : ARM::RSBri), NewRsbDstReg) .addReg(NewMovDstReg, RegState::Kill) .addImm(0).addImm((unsigned)ARMCC::AL).addReg(0).addReg(0); // insert PHI in SinkBB, // reuse ABSDstReg to not change uses of ABS instruction BuildMI(*SinkBB, SinkBB->begin(), dl, TII->get(ARM::PHI), ABSDstReg) .addReg(NewRsbDstReg).addMBB(RSBBB) .addReg(NewMovDstReg).addMBB(BB); // remove ABS instruction MI->eraseFromParent(); // return last added BB return SinkBB; } } } void ARMTargetLowering::AdjustInstrPostInstrSelection(MachineInstr *MI, SDNode *Node) const { const MCInstrDesc &MCID = MI->getDesc(); if (!MCID.hasPostISelHook()) { assert(!convertAddSubFlagsOpcode(MI->getOpcode()) && "Pseudo flag-setting opcodes must be marked with 'hasPostISelHook'"); return; } // Adjust potentially 's' setting instructions after isel, i.e. ADC, SBC, RSB, // RSC. Coming out of isel, they have an implicit CPSR def, but the optional // operand is still set to noreg. If needed, set the optional operand's // register to CPSR, and remove the redundant implicit def. // // e.g. ADCS (...opt:%noreg, CPSR) -> ADC (... opt:CPSR). // Rename pseudo opcodes. unsigned NewOpc = convertAddSubFlagsOpcode(MI->getOpcode()); if (NewOpc) { const ARMBaseInstrInfo *TII = static_cast(getTargetMachine().getInstrInfo()); MI->setDesc(TII->get(NewOpc)); } unsigned ccOutIdx = MCID.getNumOperands() - 1; // Any ARM instruction that sets the 's' bit should specify an optional // "cc_out" operand in the last operand position. if (!MCID.hasOptionalDef() || !MCID.OpInfo[ccOutIdx].isOptionalDef()) { assert(!NewOpc && "Optional cc_out operand required"); return; } // Look for an implicit def of CPSR added by MachineInstr ctor. Remove it // since we already have an optional CPSR def. bool definesCPSR = false; bool deadCPSR = false; for (unsigned i = MCID.getNumOperands(), e = MI->getNumOperands(); i != e; ++i) { const MachineOperand &MO = MI->getOperand(i); if (MO.isReg() && MO.isDef() && MO.getReg() == ARM::CPSR) { definesCPSR = true; if (MO.isDead()) deadCPSR = true; MI->RemoveOperand(i); break; } } if (!definesCPSR) { assert(!NewOpc && "Optional cc_out operand required"); return; } assert(deadCPSR == !Node->hasAnyUseOfValue(1) && "inconsistent dead flag"); if (deadCPSR) { assert(!MI->getOperand(ccOutIdx).getReg() && "expect uninitialized optional cc_out operand"); return; } // If this instruction was defined with an optional CPSR def and its dag node // had a live implicit CPSR def, then activate the optional CPSR def. MachineOperand &MO = MI->getOperand(ccOutIdx); MO.setReg(ARM::CPSR); MO.setIsDef(true); } //===----------------------------------------------------------------------===// // ARM Optimization Hooks //===----------------------------------------------------------------------===// static SDValue combineSelectAndUse(SDNode *N, SDValue Slct, SDValue OtherOp, TargetLowering::DAGCombinerInfo &DCI) { SelectionDAG &DAG = DCI.DAG; const TargetLowering &TLI = DAG.getTargetLoweringInfo(); EVT VT = N->getValueType(0); unsigned Opc = N->getOpcode(); bool isSlctCC = Slct.getOpcode() == ISD::SELECT_CC; SDValue LHS = isSlctCC ? Slct.getOperand(2) : Slct.getOperand(1); SDValue RHS = isSlctCC ? Slct.getOperand(3) : Slct.getOperand(2); ISD::CondCode CC = ISD::SETCC_INVALID; if (isSlctCC) { CC = cast(Slct.getOperand(4))->get(); } else { SDValue CCOp = Slct.getOperand(0); if (CCOp.getOpcode() == ISD::SETCC) CC = cast(CCOp.getOperand(2))->get(); } bool DoXform = false; bool InvCC = false; assert ((Opc == ISD::ADD || (Opc == ISD::SUB && Slct == N->getOperand(1))) && "Bad input!"); if (LHS.getOpcode() == ISD::Constant && cast(LHS)->isNullValue()) { DoXform = true; } else if (CC != ISD::SETCC_INVALID && RHS.getOpcode() == ISD::Constant && cast(RHS)->isNullValue()) { std::swap(LHS, RHS); SDValue Op0 = Slct.getOperand(0); EVT OpVT = isSlctCC ? Op0.getValueType() : Op0.getOperand(0).getValueType(); bool isInt = OpVT.isInteger(); CC = ISD::getSetCCInverse(CC, isInt); if (!TLI.isCondCodeLegal(CC, OpVT)) return SDValue(); // Inverse operator isn't legal. DoXform = true; InvCC = true; } if (DoXform) { SDValue Result = DAG.getNode(Opc, RHS.getDebugLoc(), VT, OtherOp, RHS); if (isSlctCC) return DAG.getSelectCC(N->getDebugLoc(), OtherOp, Result, Slct.getOperand(0), Slct.getOperand(1), CC); SDValue CCOp = Slct.getOperand(0); if (InvCC) CCOp = DAG.getSetCC(Slct.getDebugLoc(), CCOp.getValueType(), CCOp.getOperand(0), CCOp.getOperand(1), CC); return DAG.getNode(ISD::SELECT, N->getDebugLoc(), VT, CCOp, OtherOp, Result); } return SDValue(); } // AddCombineToVPADDL- For pair-wise add on neon, use the vpaddl instruction // (only after legalization). static SDValue AddCombineToVPADDL(SDNode *N, SDValue N0, SDValue N1, TargetLowering::DAGCombinerInfo &DCI, const ARMSubtarget *Subtarget) { // Only perform optimization if after legalize, and if NEON is available. We // also expected both operands to be BUILD_VECTORs. if (DCI.isBeforeLegalize() || !Subtarget->hasNEON() || N0.getOpcode() != ISD::BUILD_VECTOR || N1.getOpcode() != ISD::BUILD_VECTOR) return SDValue(); // Check output type since VPADDL operand elements can only be 8, 16, or 32. EVT VT = N->getValueType(0); if (!VT.isInteger() || VT.getVectorElementType() == MVT::i64) return SDValue(); // Check that the vector operands are of the right form. // N0 and N1 are BUILD_VECTOR nodes with N number of EXTRACT_VECTOR // operands, where N is the size of the formed vector. // Each EXTRACT_VECTOR should have the same input vector and odd or even // index such that we have a pair wise add pattern. // Grab the vector that all EXTRACT_VECTOR nodes should be referencing. if (N0->getOperand(0)->getOpcode() != ISD::EXTRACT_VECTOR_ELT) return SDValue(); SDValue Vec = N0->getOperand(0)->getOperand(0); SDNode *V = Vec.getNode(); unsigned nextIndex = 0; // For each operands to the ADD which are BUILD_VECTORs, // check to see if each of their operands are an EXTRACT_VECTOR with // the same vector and appropriate index. for (unsigned i = 0, e = N0->getNumOperands(); i != e; ++i) { if (N0->getOperand(i)->getOpcode() == ISD::EXTRACT_VECTOR_ELT && N1->getOperand(i)->getOpcode() == ISD::EXTRACT_VECTOR_ELT) { SDValue ExtVec0 = N0->getOperand(i); SDValue ExtVec1 = N1->getOperand(i); // First operand is the vector, verify its the same. if (V != ExtVec0->getOperand(0).getNode() || V != ExtVec1->getOperand(0).getNode()) return SDValue(); // Second is the constant, verify its correct. ConstantSDNode *C0 = dyn_cast(ExtVec0->getOperand(1)); ConstantSDNode *C1 = dyn_cast(ExtVec1->getOperand(1)); // For the constant, we want to see all the even or all the odd. if (!C0 || !C1 || C0->getZExtValue() != nextIndex || C1->getZExtValue() != nextIndex+1) return SDValue(); // Increment index. nextIndex+=2; } else return SDValue(); } // Create VPADDL node. SelectionDAG &DAG = DCI.DAG; const TargetLowering &TLI = DAG.getTargetLoweringInfo(); // Build operand list. SmallVector Ops; Ops.push_back(DAG.getConstant(Intrinsic::arm_neon_vpaddls, TLI.getPointerTy())); // Input is the vector. Ops.push_back(Vec); // Get widened type and narrowed type. MVT widenType; unsigned numElem = VT.getVectorNumElements(); switch (VT.getVectorElementType().getSimpleVT().SimpleTy) { case MVT::i8: widenType = MVT::getVectorVT(MVT::i16, numElem); break; case MVT::i16: widenType = MVT::getVectorVT(MVT::i32, numElem); break; case MVT::i32: widenType = MVT::getVectorVT(MVT::i64, numElem); break; default: assert(0 && "Invalid vector element type for padd optimization."); } SDValue tmp = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, N->getDebugLoc(), widenType, &Ops[0], Ops.size()); return DAG.getNode(ISD::TRUNCATE, N->getDebugLoc(), VT, tmp); } /// PerformADDCombineWithOperands - Try DAG combinations for an ADD with /// operands N0 and N1. This is a helper for PerformADDCombine that is /// called with the default operands, and if that fails, with commuted /// operands. static SDValue PerformADDCombineWithOperands(SDNode *N, SDValue N0, SDValue N1, TargetLowering::DAGCombinerInfo &DCI, const ARMSubtarget *Subtarget){ // Attempt to create vpaddl for this add. SDValue Result = AddCombineToVPADDL(N, N0, N1, DCI, Subtarget); if (Result.getNode()) return Result; // fold (add (select cc, 0, c), x) -> (select cc, x, (add, x, c)) if (N0.getOpcode() == ISD::SELECT && N0.getNode()->hasOneUse()) { SDValue Result = combineSelectAndUse(N, N0, N1, DCI); if (Result.getNode()) return Result; } return SDValue(); } /// PerformADDCombine - Target-specific dag combine xforms for ISD::ADD. /// static SDValue PerformADDCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, const ARMSubtarget *Subtarget) { SDValue N0 = N->getOperand(0); SDValue N1 = N->getOperand(1); // First try with the default operand order. SDValue Result = PerformADDCombineWithOperands(N, N0, N1, DCI, Subtarget); if (Result.getNode()) return Result; // If that didn't work, try again with the operands commuted. return PerformADDCombineWithOperands(N, N1, N0, DCI, Subtarget); } /// PerformSUBCombine - Target-specific dag combine xforms for ISD::SUB. /// static SDValue PerformSUBCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { SDValue N0 = N->getOperand(0); SDValue N1 = N->getOperand(1); // fold (sub x, (select cc, 0, c)) -> (select cc, x, (sub, x, c)) if (N1.getOpcode() == ISD::SELECT && N1.getNode()->hasOneUse()) { SDValue Result = combineSelectAndUse(N, N1, N0, DCI); if (Result.getNode()) return Result; } return SDValue(); } /// PerformVMULCombine /// Distribute (A + B) * C to (A * C) + (B * C) to take advantage of the /// special multiplier accumulator forwarding. /// vmul d3, d0, d2 /// vmla d3, d1, d2 /// is faster than /// vadd d3, d0, d1 /// vmul d3, d3, d2 static SDValue PerformVMULCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, const ARMSubtarget *Subtarget) { if (!Subtarget->hasVMLxForwarding()) return SDValue(); SelectionDAG &DAG = DCI.DAG; SDValue N0 = N->getOperand(0); SDValue N1 = N->getOperand(1); unsigned Opcode = N0.getOpcode(); if (Opcode != ISD::ADD && Opcode != ISD::SUB && Opcode != ISD::FADD && Opcode != ISD::FSUB) { Opcode = N1.getOpcode(); if (Opcode != ISD::ADD && Opcode != ISD::SUB && Opcode != ISD::FADD && Opcode != ISD::FSUB) return SDValue(); std::swap(N0, N1); } EVT VT = N->getValueType(0); DebugLoc DL = N->getDebugLoc(); SDValue N00 = N0->getOperand(0); SDValue N01 = N0->getOperand(1); return DAG.getNode(Opcode, DL, VT, DAG.getNode(ISD::MUL, DL, VT, N00, N1), DAG.getNode(ISD::MUL, DL, VT, N01, N1)); } static SDValue PerformMULCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, const ARMSubtarget *Subtarget) { SelectionDAG &DAG = DCI.DAG; if (Subtarget->isThumb1Only()) return SDValue(); if (DCI.isBeforeLegalize() || DCI.isCalledByLegalizer()) return SDValue(); EVT VT = N->getValueType(0); if (VT.is64BitVector() || VT.is128BitVector()) return PerformVMULCombine(N, DCI, Subtarget); if (VT != MVT::i32) return SDValue(); ConstantSDNode *C = dyn_cast(N->getOperand(1)); if (!C) return SDValue(); uint64_t MulAmt = C->getZExtValue(); unsigned ShiftAmt = CountTrailingZeros_64(MulAmt); ShiftAmt = ShiftAmt & (32 - 1); SDValue V = N->getOperand(0); DebugLoc DL = N->getDebugLoc(); SDValue Res; MulAmt >>= ShiftAmt; if (isPowerOf2_32(MulAmt - 1)) { // (mul x, 2^N + 1) => (add (shl x, N), x) Res = DAG.getNode(ISD::ADD, DL, VT, V, DAG.getNode(ISD::SHL, DL, VT, V, DAG.getConstant(Log2_32(MulAmt-1), MVT::i32))); } else if (isPowerOf2_32(MulAmt + 1)) { // (mul x, 2^N - 1) => (sub (shl x, N), x) Res = DAG.getNode(ISD::SUB, DL, VT, DAG.getNode(ISD::SHL, DL, VT, V, DAG.getConstant(Log2_32(MulAmt+1), MVT::i32)), V); } else return SDValue(); if (ShiftAmt != 0) Res = DAG.getNode(ISD::SHL, DL, VT, Res, DAG.getConstant(ShiftAmt, MVT::i32)); // Do not add new nodes to DAG combiner worklist. DCI.CombineTo(N, Res, false); return SDValue(); } static SDValue PerformANDCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { // Attempt to use immediate-form VBIC BuildVectorSDNode *BVN = dyn_cast(N->getOperand(1)); DebugLoc dl = N->getDebugLoc(); EVT VT = N->getValueType(0); SelectionDAG &DAG = DCI.DAG; if(!DAG.getTargetLoweringInfo().isTypeLegal(VT)) return SDValue(); APInt SplatBits, SplatUndef; unsigned SplatBitSize; bool HasAnyUndefs; if (BVN && BVN->isConstantSplat(SplatBits, SplatUndef, SplatBitSize, HasAnyUndefs)) { if (SplatBitSize <= 64) { EVT VbicVT; SDValue Val = isNEONModifiedImm((~SplatBits).getZExtValue(), SplatUndef.getZExtValue(), SplatBitSize, DAG, VbicVT, VT.is128BitVector(), OtherModImm); if (Val.getNode()) { SDValue Input = DAG.getNode(ISD::BITCAST, dl, VbicVT, N->getOperand(0)); SDValue Vbic = DAG.getNode(ARMISD::VBICIMM, dl, VbicVT, Input, Val); return DAG.getNode(ISD::BITCAST, dl, VT, Vbic); } } } return SDValue(); } /// PerformORCombine - Target-specific dag combine xforms for ISD::OR static SDValue PerformORCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, const ARMSubtarget *Subtarget) { // Attempt to use immediate-form VORR BuildVectorSDNode *BVN = dyn_cast(N->getOperand(1)); DebugLoc dl = N->getDebugLoc(); EVT VT = N->getValueType(0); SelectionDAG &DAG = DCI.DAG; if(!DAG.getTargetLoweringInfo().isTypeLegal(VT)) return SDValue(); APInt SplatBits, SplatUndef; unsigned SplatBitSize; bool HasAnyUndefs; if (BVN && Subtarget->hasNEON() && BVN->isConstantSplat(SplatBits, SplatUndef, SplatBitSize, HasAnyUndefs)) { if (SplatBitSize <= 64) { EVT VorrVT; SDValue Val = isNEONModifiedImm(SplatBits.getZExtValue(), SplatUndef.getZExtValue(), SplatBitSize, DAG, VorrVT, VT.is128BitVector(), OtherModImm); if (Val.getNode()) { SDValue Input = DAG.getNode(ISD::BITCAST, dl, VorrVT, N->getOperand(0)); SDValue Vorr = DAG.getNode(ARMISD::VORRIMM, dl, VorrVT, Input, Val); return DAG.getNode(ISD::BITCAST, dl, VT, Vorr); } } } SDValue N0 = N->getOperand(0); if (N0.getOpcode() != ISD::AND) return SDValue(); SDValue N1 = N->getOperand(1); // (or (and B, A), (and C, ~A)) => (VBSL A, B, C) when A is a constant. if (Subtarget->hasNEON() && N1.getOpcode() == ISD::AND && VT.isVector() && DAG.getTargetLoweringInfo().isTypeLegal(VT)) { APInt SplatUndef; unsigned SplatBitSize; bool HasAnyUndefs; BuildVectorSDNode *BVN0 = dyn_cast(N0->getOperand(1)); APInt SplatBits0; if (BVN0 && BVN0->isConstantSplat(SplatBits0, SplatUndef, SplatBitSize, HasAnyUndefs) && !HasAnyUndefs) { BuildVectorSDNode *BVN1 = dyn_cast(N1->getOperand(1)); APInt SplatBits1; if (BVN1 && BVN1->isConstantSplat(SplatBits1, SplatUndef, SplatBitSize, HasAnyUndefs) && !HasAnyUndefs && SplatBits0 == ~SplatBits1) { // Canonicalize the vector type to make instruction selection simpler. EVT CanonicalVT = VT.is128BitVector() ? MVT::v4i32 : MVT::v2i32; SDValue Result = DAG.getNode(ARMISD::VBSL, dl, CanonicalVT, N0->getOperand(1), N0->getOperand(0), N1->getOperand(0)); return DAG.getNode(ISD::BITCAST, dl, VT, Result); } } } // Try to use the ARM/Thumb2 BFI (bitfield insert) instruction when // reasonable. // BFI is only available on V6T2+ if (Subtarget->isThumb1Only() || !Subtarget->hasV6T2Ops()) return SDValue(); DebugLoc DL = N->getDebugLoc(); // 1) or (and A, mask), val => ARMbfi A, val, mask // iff (val & mask) == val // // 2) or (and A, mask), (and B, mask2) => ARMbfi A, (lsr B, amt), mask // 2a) iff isBitFieldInvertedMask(mask) && isBitFieldInvertedMask(~mask2) // && mask == ~mask2 // 2b) iff isBitFieldInvertedMask(~mask) && isBitFieldInvertedMask(mask2) // && ~mask == mask2 // (i.e., copy a bitfield value into another bitfield of the same width) if (VT != MVT::i32) return SDValue(); SDValue N00 = N0.getOperand(0); // The value and the mask need to be constants so we can verify this is // actually a bitfield set. If the mask is 0xffff, we can do better // via a movt instruction, so don't use BFI in that case. SDValue MaskOp = N0.getOperand(1); ConstantSDNode *MaskC = dyn_cast(MaskOp); if (!MaskC) return SDValue(); unsigned Mask = MaskC->getZExtValue(); if (Mask == 0xffff) return SDValue(); SDValue Res; // Case (1): or (and A, mask), val => ARMbfi A, val, mask ConstantSDNode *N1C = dyn_cast(N1); if (N1C) { unsigned Val = N1C->getZExtValue(); if ((Val & ~Mask) != Val) return SDValue(); if (ARM::isBitFieldInvertedMask(Mask)) { Val >>= CountTrailingZeros_32(~Mask); Res = DAG.getNode(ARMISD::BFI, DL, VT, N00, DAG.getConstant(Val, MVT::i32), DAG.getConstant(Mask, MVT::i32)); // Do not add new nodes to DAG combiner worklist. DCI.CombineTo(N, Res, false); return SDValue(); } } else if (N1.getOpcode() == ISD::AND) { // case (2) or (and A, mask), (and B, mask2) => ARMbfi A, (lsr B, amt), mask ConstantSDNode *N11C = dyn_cast(N1.getOperand(1)); if (!N11C) return SDValue(); unsigned Mask2 = N11C->getZExtValue(); // Mask and ~Mask2 (or reverse) must be equivalent for the BFI pattern // as is to match. if (ARM::isBitFieldInvertedMask(Mask) && (Mask == ~Mask2)) { // The pack halfword instruction works better for masks that fit it, // so use that when it's available. if (Subtarget->hasT2ExtractPack() && (Mask == 0xffff || Mask == 0xffff0000)) return SDValue(); // 2a unsigned amt = CountTrailingZeros_32(Mask2); Res = DAG.getNode(ISD::SRL, DL, VT, N1.getOperand(0), DAG.getConstant(amt, MVT::i32)); Res = DAG.getNode(ARMISD::BFI, DL, VT, N00, Res, DAG.getConstant(Mask, MVT::i32)); // Do not add new nodes to DAG combiner worklist. DCI.CombineTo(N, Res, false); return SDValue(); } else if (ARM::isBitFieldInvertedMask(~Mask) && (~Mask == Mask2)) { // The pack halfword instruction works better for masks that fit it, // so use that when it's available. if (Subtarget->hasT2ExtractPack() && (Mask2 == 0xffff || Mask2 == 0xffff0000)) return SDValue(); // 2b unsigned lsb = CountTrailingZeros_32(Mask); Res = DAG.getNode(ISD::SRL, DL, VT, N00, DAG.getConstant(lsb, MVT::i32)); Res = DAG.getNode(ARMISD::BFI, DL, VT, N1.getOperand(0), Res, DAG.getConstant(Mask2, MVT::i32)); // Do not add new nodes to DAG combiner worklist. DCI.CombineTo(N, Res, false); return SDValue(); } } if (DAG.MaskedValueIsZero(N1, MaskC->getAPIntValue()) && N00.getOpcode() == ISD::SHL && isa(N00.getOperand(1)) && ARM::isBitFieldInvertedMask(~Mask)) { // Case (3): or (and (shl A, #shamt), mask), B => ARMbfi B, A, ~mask // where lsb(mask) == #shamt and masked bits of B are known zero. SDValue ShAmt = N00.getOperand(1); unsigned ShAmtC = cast(ShAmt)->getZExtValue(); unsigned LSB = CountTrailingZeros_32(Mask); if (ShAmtC != LSB) return SDValue(); Res = DAG.getNode(ARMISD::BFI, DL, VT, N1, N00.getOperand(0), DAG.getConstant(~Mask, MVT::i32)); // Do not add new nodes to DAG combiner worklist. DCI.CombineTo(N, Res, false); } return SDValue(); } /// PerformBFICombine - (bfi A, (and B, Mask1), Mask2) -> (bfi A, B, Mask2) iff /// the bits being cleared by the AND are not demanded by the BFI. static SDValue PerformBFICombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { SDValue N1 = N->getOperand(1); if (N1.getOpcode() == ISD::AND) { ConstantSDNode *N11C = dyn_cast(N1.getOperand(1)); if (!N11C) return SDValue(); unsigned InvMask = cast(N->getOperand(2))->getZExtValue(); unsigned LSB = CountTrailingZeros_32(~InvMask); unsigned Width = (32 - CountLeadingZeros_32(~InvMask)) - LSB; unsigned Mask = (1 << Width)-1; unsigned Mask2 = N11C->getZExtValue(); if ((Mask & (~Mask2)) == 0) return DCI.DAG.getNode(ARMISD::BFI, N->getDebugLoc(), N->getValueType(0), N->getOperand(0), N1.getOperand(0), N->getOperand(2)); } return SDValue(); } /// PerformVMOVRRDCombine - Target-specific dag combine xforms for /// ARMISD::VMOVRRD. static SDValue PerformVMOVRRDCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { // vmovrrd(vmovdrr x, y) -> x,y SDValue InDouble = N->getOperand(0); if (InDouble.getOpcode() == ARMISD::VMOVDRR) return DCI.CombineTo(N, InDouble.getOperand(0), InDouble.getOperand(1)); // vmovrrd(load f64) -> (load i32), (load i32) SDNode *InNode = InDouble.getNode(); if (ISD::isNormalLoad(InNode) && InNode->hasOneUse() && InNode->getValueType(0) == MVT::f64 && InNode->getOperand(1).getOpcode() == ISD::FrameIndex && !cast(InNode)->isVolatile()) { // TODO: Should this be done for non-FrameIndex operands? LoadSDNode *LD = cast(InNode); SelectionDAG &DAG = DCI.DAG; DebugLoc DL = LD->getDebugLoc(); SDValue BasePtr = LD->getBasePtr(); SDValue NewLD1 = DAG.getLoad(MVT::i32, DL, LD->getChain(), BasePtr, LD->getPointerInfo(), LD->isVolatile(), LD->isNonTemporal(), LD->getAlignment()); SDValue OffsetPtr = DAG.getNode(ISD::ADD, DL, MVT::i32, BasePtr, DAG.getConstant(4, MVT::i32)); SDValue NewLD2 = DAG.getLoad(MVT::i32, DL, NewLD1.getValue(1), OffsetPtr, LD->getPointerInfo(), LD->isVolatile(), LD->isNonTemporal(), std::min(4U, LD->getAlignment() / 2)); DAG.ReplaceAllUsesOfValueWith(SDValue(LD, 1), NewLD2.getValue(1)); SDValue Result = DCI.CombineTo(N, NewLD1, NewLD2); DCI.RemoveFromWorklist(LD); DAG.DeleteNode(LD); return Result; } return SDValue(); } /// PerformVMOVDRRCombine - Target-specific dag combine xforms for /// ARMISD::VMOVDRR. This is also used for BUILD_VECTORs with 2 operands. static SDValue PerformVMOVDRRCombine(SDNode *N, SelectionDAG &DAG) { // N=vmovrrd(X); vmovdrr(N:0, N:1) -> bit_convert(X) SDValue Op0 = N->getOperand(0); SDValue Op1 = N->getOperand(1); if (Op0.getOpcode() == ISD::BITCAST) Op0 = Op0.getOperand(0); if (Op1.getOpcode() == ISD::BITCAST) Op1 = Op1.getOperand(0); if (Op0.getOpcode() == ARMISD::VMOVRRD && Op0.getNode() == Op1.getNode() && Op0.getResNo() == 0 && Op1.getResNo() == 1) return DAG.getNode(ISD::BITCAST, N->getDebugLoc(), N->getValueType(0), Op0.getOperand(0)); return SDValue(); } /// PerformSTORECombine - Target-specific dag combine xforms for /// ISD::STORE. static SDValue PerformSTORECombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { // Bitcast an i64 store extracted from a vector to f64. // Otherwise, the i64 value will be legalized to a pair of i32 values. StoreSDNode *St = cast(N); SDValue StVal = St->getValue(); if (!ISD::isNormalStore(St) || St->isVolatile()) return SDValue(); if (StVal.getNode()->getOpcode() == ARMISD::VMOVDRR && StVal.getNode()->hasOneUse() && !St->isVolatile()) { SelectionDAG &DAG = DCI.DAG; DebugLoc DL = St->getDebugLoc(); SDValue BasePtr = St->getBasePtr(); SDValue NewST1 = DAG.getStore(St->getChain(), DL, StVal.getNode()->getOperand(0), BasePtr, St->getPointerInfo(), St->isVolatile(), St->isNonTemporal(), St->getAlignment()); SDValue OffsetPtr = DAG.getNode(ISD::ADD, DL, MVT::i32, BasePtr, DAG.getConstant(4, MVT::i32)); return DAG.getStore(NewST1.getValue(0), DL, StVal.getNode()->getOperand(1), OffsetPtr, St->getPointerInfo(), St->isVolatile(), St->isNonTemporal(), std::min(4U, St->getAlignment() / 2)); } if (StVal.getValueType() != MVT::i64 || StVal.getNode()->getOpcode() != ISD::EXTRACT_VECTOR_ELT) return SDValue(); SelectionDAG &DAG = DCI.DAG; DebugLoc dl = StVal.getDebugLoc(); SDValue IntVec = StVal.getOperand(0); EVT FloatVT = EVT::getVectorVT(*DAG.getContext(), MVT::f64, IntVec.getValueType().getVectorNumElements()); SDValue Vec = DAG.getNode(ISD::BITCAST, dl, FloatVT, IntVec); SDValue ExtElt = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, MVT::f64, Vec, StVal.getOperand(1)); dl = N->getDebugLoc(); SDValue V = DAG.getNode(ISD::BITCAST, dl, MVT::i64, ExtElt); // Make the DAGCombiner fold the bitcasts. DCI.AddToWorklist(Vec.getNode()); DCI.AddToWorklist(ExtElt.getNode()); DCI.AddToWorklist(V.getNode()); return DAG.getStore(St->getChain(), dl, V, St->getBasePtr(), St->getPointerInfo(), St->isVolatile(), St->isNonTemporal(), St->getAlignment(), St->getTBAAInfo()); } /// hasNormalLoadOperand - Check if any of the operands of a BUILD_VECTOR node /// are normal, non-volatile loads. If so, it is profitable to bitcast an /// i64 vector to have f64 elements, since the value can then be loaded /// directly into a VFP register. static bool hasNormalLoadOperand(SDNode *N) { unsigned NumElts = N->getValueType(0).getVectorNumElements(); for (unsigned i = 0; i < NumElts; ++i) { SDNode *Elt = N->getOperand(i).getNode(); if (ISD::isNormalLoad(Elt) && !cast(Elt)->isVolatile()) return true; } return false; } /// PerformBUILD_VECTORCombine - Target-specific dag combine xforms for /// ISD::BUILD_VECTOR. static SDValue PerformBUILD_VECTORCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI){ // build_vector(N=ARMISD::VMOVRRD(X), N:1) -> bit_convert(X): // VMOVRRD is introduced when legalizing i64 types. It forces the i64 value // into a pair of GPRs, which is fine when the value is used as a scalar, // but if the i64 value is converted to a vector, we need to undo the VMOVRRD. SelectionDAG &DAG = DCI.DAG; if (N->getNumOperands() == 2) { SDValue RV = PerformVMOVDRRCombine(N, DAG); if (RV.getNode()) return RV; } // Load i64 elements as f64 values so that type legalization does not split // them up into i32 values. EVT VT = N->getValueType(0); if (VT.getVectorElementType() != MVT::i64 || !hasNormalLoadOperand(N)) return SDValue(); DebugLoc dl = N->getDebugLoc(); SmallVector Ops; unsigned NumElts = VT.getVectorNumElements(); for (unsigned i = 0; i < NumElts; ++i) { SDValue V = DAG.getNode(ISD::BITCAST, dl, MVT::f64, N->getOperand(i)); Ops.push_back(V); // Make the DAGCombiner fold the bitcast. DCI.AddToWorklist(V.getNode()); } EVT FloatVT = EVT::getVectorVT(*DAG.getContext(), MVT::f64, NumElts); SDValue BV = DAG.getNode(ISD::BUILD_VECTOR, dl, FloatVT, Ops.data(), NumElts); return DAG.getNode(ISD::BITCAST, dl, VT, BV); } /// PerformInsertEltCombine - Target-specific dag combine xforms for /// ISD::INSERT_VECTOR_ELT. static SDValue PerformInsertEltCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { // Bitcast an i64 load inserted into a vector to f64. // Otherwise, the i64 value will be legalized to a pair of i32 values. EVT VT = N->getValueType(0); SDNode *Elt = N->getOperand(1).getNode(); if (VT.getVectorElementType() != MVT::i64 || !ISD::isNormalLoad(Elt) || cast(Elt)->isVolatile()) return SDValue(); SelectionDAG &DAG = DCI.DAG; DebugLoc dl = N->getDebugLoc(); EVT FloatVT = EVT::getVectorVT(*DAG.getContext(), MVT::f64, VT.getVectorNumElements()); SDValue Vec = DAG.getNode(ISD::BITCAST, dl, FloatVT, N->getOperand(0)); SDValue V = DAG.getNode(ISD::BITCAST, dl, MVT::f64, N->getOperand(1)); // Make the DAGCombiner fold the bitcasts. DCI.AddToWorklist(Vec.getNode()); DCI.AddToWorklist(V.getNode()); SDValue InsElt = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, FloatVT, Vec, V, N->getOperand(2)); return DAG.getNode(ISD::BITCAST, dl, VT, InsElt); } /// PerformVECTOR_SHUFFLECombine - Target-specific dag combine xforms for /// ISD::VECTOR_SHUFFLE. static SDValue PerformVECTOR_SHUFFLECombine(SDNode *N, SelectionDAG &DAG) { // The LLVM shufflevector instruction does not require the shuffle mask // length to match the operand vector length, but ISD::VECTOR_SHUFFLE does // have that requirement. When translating to ISD::VECTOR_SHUFFLE, if the // operands do not match the mask length, they are extended by concatenating // them with undef vectors. That is probably the right thing for other // targets, but for NEON it is better to concatenate two double-register // size vector operands into a single quad-register size vector. Do that // transformation here: // shuffle(concat(v1, undef), concat(v2, undef)) -> // shuffle(concat(v1, v2), undef) SDValue Op0 = N->getOperand(0); SDValue Op1 = N->getOperand(1); if (Op0.getOpcode() != ISD::CONCAT_VECTORS || Op1.getOpcode() != ISD::CONCAT_VECTORS || Op0.getNumOperands() != 2 || Op1.getNumOperands() != 2) return SDValue(); SDValue Concat0Op1 = Op0.getOperand(1); SDValue Concat1Op1 = Op1.getOperand(1); if (Concat0Op1.getOpcode() != ISD::UNDEF || Concat1Op1.getOpcode() != ISD::UNDEF) return SDValue(); // Skip the transformation if any of the types are illegal. const TargetLowering &TLI = DAG.getTargetLoweringInfo(); EVT VT = N->getValueType(0); if (!TLI.isTypeLegal(VT) || !TLI.isTypeLegal(Concat0Op1.getValueType()) || !TLI.isTypeLegal(Concat1Op1.getValueType())) return SDValue(); SDValue NewConcat = DAG.getNode(ISD::CONCAT_VECTORS, N->getDebugLoc(), VT, Op0.getOperand(0), Op1.getOperand(0)); // Translate the shuffle mask. SmallVector NewMask; unsigned NumElts = VT.getVectorNumElements(); unsigned HalfElts = NumElts/2; ShuffleVectorSDNode *SVN = cast(N); for (unsigned n = 0; n < NumElts; ++n) { int MaskElt = SVN->getMaskElt(n); int NewElt = -1; if (MaskElt < (int)HalfElts) NewElt = MaskElt; else if (MaskElt >= (int)NumElts && MaskElt < (int)(NumElts + HalfElts)) NewElt = HalfElts + MaskElt - NumElts; NewMask.push_back(NewElt); } return DAG.getVectorShuffle(VT, N->getDebugLoc(), NewConcat, DAG.getUNDEF(VT), NewMask.data()); } /// CombineBaseUpdate - Target-specific DAG combine function for VLDDUP and /// NEON load/store intrinsics to merge base address updates. static SDValue CombineBaseUpdate(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { if (DCI.isBeforeLegalize() || DCI.isCalledByLegalizer()) return SDValue(); SelectionDAG &DAG = DCI.DAG; bool isIntrinsic = (N->getOpcode() == ISD::INTRINSIC_VOID || N->getOpcode() == ISD::INTRINSIC_W_CHAIN); unsigned AddrOpIdx = (isIntrinsic ? 2 : 1); SDValue Addr = N->getOperand(AddrOpIdx); // Search for a use of the address operand that is an increment. for (SDNode::use_iterator UI = Addr.getNode()->use_begin(), UE = Addr.getNode()->use_end(); UI != UE; ++UI) { SDNode *User = *UI; if (User->getOpcode() != ISD::ADD || UI.getUse().getResNo() != Addr.getResNo()) continue; // Check that the add is independent of the load/store. Otherwise, folding // it would create a cycle. if (User->isPredecessorOf(N) || N->isPredecessorOf(User)) continue; // Find the new opcode for the updating load/store. bool isLoad = true; bool isLaneOp = false; unsigned NewOpc = 0; unsigned NumVecs = 0; if (isIntrinsic) { unsigned IntNo = cast(N->getOperand(1))->getZExtValue(); switch (IntNo) { default: assert(0 && "unexpected intrinsic for Neon base update"); case Intrinsic::arm_neon_vld1: NewOpc = ARMISD::VLD1_UPD; NumVecs = 1; break; case Intrinsic::arm_neon_vld2: NewOpc = ARMISD::VLD2_UPD; NumVecs = 2; break; case Intrinsic::arm_neon_vld3: NewOpc = ARMISD::VLD3_UPD; NumVecs = 3; break; case Intrinsic::arm_neon_vld4: NewOpc = ARMISD::VLD4_UPD; NumVecs = 4; break; case Intrinsic::arm_neon_vld2lane: NewOpc = ARMISD::VLD2LN_UPD; NumVecs = 2; isLaneOp = true; break; case Intrinsic::arm_neon_vld3lane: NewOpc = ARMISD::VLD3LN_UPD; NumVecs = 3; isLaneOp = true; break; case Intrinsic::arm_neon_vld4lane: NewOpc = ARMISD::VLD4LN_UPD; NumVecs = 4; isLaneOp = true; break; case Intrinsic::arm_neon_vst1: NewOpc = ARMISD::VST1_UPD; NumVecs = 1; isLoad = false; break; case Intrinsic::arm_neon_vst2: NewOpc = ARMISD::VST2_UPD; NumVecs = 2; isLoad = false; break; case Intrinsic::arm_neon_vst3: NewOpc = ARMISD::VST3_UPD; NumVecs = 3; isLoad = false; break; case Intrinsic::arm_neon_vst4: NewOpc = ARMISD::VST4_UPD; NumVecs = 4; isLoad = false; break; case Intrinsic::arm_neon_vst2lane: NewOpc = ARMISD::VST2LN_UPD; NumVecs = 2; isLoad = false; isLaneOp = true; break; case Intrinsic::arm_neon_vst3lane: NewOpc = ARMISD::VST3LN_UPD; NumVecs = 3; isLoad = false; isLaneOp = true; break; case Intrinsic::arm_neon_vst4lane: NewOpc = ARMISD::VST4LN_UPD; NumVecs = 4; isLoad = false; isLaneOp = true; break; } } else { isLaneOp = true; switch (N->getOpcode()) { default: assert(0 && "unexpected opcode for Neon base update"); case ARMISD::VLD2DUP: NewOpc = ARMISD::VLD2DUP_UPD; NumVecs = 2; break; case ARMISD::VLD3DUP: NewOpc = ARMISD::VLD3DUP_UPD; NumVecs = 3; break; case ARMISD::VLD4DUP: NewOpc = ARMISD::VLD4DUP_UPD; NumVecs = 4; break; } } // Find the size of memory referenced by the load/store. EVT VecTy; if (isLoad) VecTy = N->getValueType(0); else VecTy = N->getOperand(AddrOpIdx+1).getValueType(); unsigned NumBytes = NumVecs * VecTy.getSizeInBits() / 8; if (isLaneOp) NumBytes /= VecTy.getVectorNumElements(); // If the increment is a constant, it must match the memory ref size. SDValue Inc = User->getOperand(User->getOperand(0) == Addr ? 1 : 0); if (ConstantSDNode *CInc = dyn_cast(Inc.getNode())) { uint64_t IncVal = CInc->getZExtValue(); if (IncVal != NumBytes) continue; } else if (NumBytes >= 3 * 16) { // VLD3/4 and VST3/4 for 128-bit vectors are implemented with two // separate instructions that make it harder to use a non-constant update. continue; } // Create the new updating load/store node. EVT Tys[6]; unsigned NumResultVecs = (isLoad ? NumVecs : 0); unsigned n; for (n = 0; n < NumResultVecs; ++n) Tys[n] = VecTy; Tys[n++] = MVT::i32; Tys[n] = MVT::Other; SDVTList SDTys = DAG.getVTList(Tys, NumResultVecs+2); SmallVector Ops; Ops.push_back(N->getOperand(0)); // incoming chain Ops.push_back(N->getOperand(AddrOpIdx)); Ops.push_back(Inc); for (unsigned i = AddrOpIdx + 1; i < N->getNumOperands(); ++i) { Ops.push_back(N->getOperand(i)); } MemIntrinsicSDNode *MemInt = cast(N); SDValue UpdN = DAG.getMemIntrinsicNode(NewOpc, N->getDebugLoc(), SDTys, Ops.data(), Ops.size(), MemInt->getMemoryVT(), MemInt->getMemOperand()); // Update the uses. std::vector NewResults; for (unsigned i = 0; i < NumResultVecs; ++i) { NewResults.push_back(SDValue(UpdN.getNode(), i)); } NewResults.push_back(SDValue(UpdN.getNode(), NumResultVecs+1)); // chain DCI.CombineTo(N, NewResults); DCI.CombineTo(User, SDValue(UpdN.getNode(), NumResultVecs)); break; } return SDValue(); } /// CombineVLDDUP - For a VDUPLANE node N, check if its source operand is a /// vldN-lane (N > 1) intrinsic, and if all the other uses of that intrinsic /// are also VDUPLANEs. If so, combine them to a vldN-dup operation and /// return true. static bool CombineVLDDUP(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { SelectionDAG &DAG = DCI.DAG; EVT VT = N->getValueType(0); // vldN-dup instructions only support 64-bit vectors for N > 1. if (!VT.is64BitVector()) return false; // Check if the VDUPLANE operand is a vldN-dup intrinsic. SDNode *VLD = N->getOperand(0).getNode(); if (VLD->getOpcode() != ISD::INTRINSIC_W_CHAIN) return false; unsigned NumVecs = 0; unsigned NewOpc = 0; unsigned IntNo = cast(VLD->getOperand(1))->getZExtValue(); if (IntNo == Intrinsic::arm_neon_vld2lane) { NumVecs = 2; NewOpc = ARMISD::VLD2DUP; } else if (IntNo == Intrinsic::arm_neon_vld3lane) { NumVecs = 3; NewOpc = ARMISD::VLD3DUP; } else if (IntNo == Intrinsic::arm_neon_vld4lane) { NumVecs = 4; NewOpc = ARMISD::VLD4DUP; } else { return false; } // First check that all the vldN-lane uses are VDUPLANEs and that the lane // numbers match the load. unsigned VLDLaneNo = cast(VLD->getOperand(NumVecs+3))->getZExtValue(); for (SDNode::use_iterator UI = VLD->use_begin(), UE = VLD->use_end(); UI != UE; ++UI) { // Ignore uses of the chain result. if (UI.getUse().getResNo() == NumVecs) continue; SDNode *User = *UI; if (User->getOpcode() != ARMISD::VDUPLANE || VLDLaneNo != cast(User->getOperand(1))->getZExtValue()) return false; } // Create the vldN-dup node. EVT Tys[5]; unsigned n; for (n = 0; n < NumVecs; ++n) Tys[n] = VT; Tys[n] = MVT::Other; SDVTList SDTys = DAG.getVTList(Tys, NumVecs+1); SDValue Ops[] = { VLD->getOperand(0), VLD->getOperand(2) }; MemIntrinsicSDNode *VLDMemInt = cast(VLD); SDValue VLDDup = DAG.getMemIntrinsicNode(NewOpc, VLD->getDebugLoc(), SDTys, Ops, 2, VLDMemInt->getMemoryVT(), VLDMemInt->getMemOperand()); // Update the uses. for (SDNode::use_iterator UI = VLD->use_begin(), UE = VLD->use_end(); UI != UE; ++UI) { unsigned ResNo = UI.getUse().getResNo(); // Ignore uses of the chain result. if (ResNo == NumVecs) continue; SDNode *User = *UI; DCI.CombineTo(User, SDValue(VLDDup.getNode(), ResNo)); } // Now the vldN-lane intrinsic is dead except for its chain result. // Update uses of the chain. std::vector VLDDupResults; for (unsigned n = 0; n < NumVecs; ++n) VLDDupResults.push_back(SDValue(VLDDup.getNode(), n)); VLDDupResults.push_back(SDValue(VLDDup.getNode(), NumVecs)); DCI.CombineTo(VLD, VLDDupResults); return true; } /// PerformVDUPLANECombine - Target-specific dag combine xforms for /// ARMISD::VDUPLANE. static SDValue PerformVDUPLANECombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { SDValue Op = N->getOperand(0); // If the source is a vldN-lane (N > 1) intrinsic, and all the other uses // of that intrinsic are also VDUPLANEs, combine them to a vldN-dup operation. if (CombineVLDDUP(N, DCI)) return SDValue(N, 0); // If the source is already a VMOVIMM or VMVNIMM splat, the VDUPLANE is // redundant. Ignore bit_converts for now; element sizes are checked below. while (Op.getOpcode() == ISD::BITCAST) Op = Op.getOperand(0); if (Op.getOpcode() != ARMISD::VMOVIMM && Op.getOpcode() != ARMISD::VMVNIMM) return SDValue(); // Make sure the VMOV element size is not bigger than the VDUPLANE elements. unsigned EltSize = Op.getValueType().getVectorElementType().getSizeInBits(); // The canonical VMOV for a zero vector uses a 32-bit element size. unsigned Imm = cast(Op.getOperand(0))->getZExtValue(); unsigned EltBits; if (ARM_AM::decodeNEONModImm(Imm, EltBits) == 0) EltSize = 8; EVT VT = N->getValueType(0); if (EltSize > VT.getVectorElementType().getSizeInBits()) return SDValue(); return DCI.DAG.getNode(ISD::BITCAST, N->getDebugLoc(), VT, Op); } // isConstVecPow2 - Return true if each vector element is a power of 2, all // elements are the same constant, C, and Log2(C) ranges from 1 to 32. static bool isConstVecPow2(SDValue ConstVec, bool isSigned, uint64_t &C) { integerPart cN; integerPart c0 = 0; for (unsigned I = 0, E = ConstVec.getValueType().getVectorNumElements(); I != E; I++) { ConstantFPSDNode *C = dyn_cast(ConstVec.getOperand(I)); if (!C) return false; bool isExact; APFloat APF = C->getValueAPF(); if (APF.convertToInteger(&cN, 64, isSigned, APFloat::rmTowardZero, &isExact) != APFloat::opOK || !isExact) return false; c0 = (I == 0) ? cN : c0; if (!isPowerOf2_64(cN) || c0 != cN || Log2_64(c0) < 1 || Log2_64(c0) > 32) return false; } C = c0; return true; } /// PerformVCVTCombine - VCVT (floating-point to fixed-point, Advanced SIMD) /// can replace combinations of VMUL and VCVT (floating-point to integer) /// when the VMUL has a constant operand that is a power of 2. /// /// Example (assume d17 = ): /// vmul.f32 d16, d17, d16 /// vcvt.s32.f32 d16, d16 /// becomes: /// vcvt.s32.f32 d16, d16, #3 static SDValue PerformVCVTCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, const ARMSubtarget *Subtarget) { SelectionDAG &DAG = DCI.DAG; SDValue Op = N->getOperand(0); if (!Subtarget->hasNEON() || !Op.getValueType().isVector() || Op.getOpcode() != ISD::FMUL) return SDValue(); uint64_t C; SDValue N0 = Op->getOperand(0); SDValue ConstVec = Op->getOperand(1); bool isSigned = N->getOpcode() == ISD::FP_TO_SINT; if (ConstVec.getOpcode() != ISD::BUILD_VECTOR || !isConstVecPow2(ConstVec, isSigned, C)) return SDValue(); unsigned IntrinsicOpcode = isSigned ? Intrinsic::arm_neon_vcvtfp2fxs : Intrinsic::arm_neon_vcvtfp2fxu; return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, N->getDebugLoc(), N->getValueType(0), DAG.getConstant(IntrinsicOpcode, MVT::i32), N0, DAG.getConstant(Log2_64(C), MVT::i32)); } /// PerformVDIVCombine - VCVT (fixed-point to floating-point, Advanced SIMD) /// can replace combinations of VCVT (integer to floating-point) and VDIV /// when the VDIV has a constant operand that is a power of 2. /// /// Example (assume d17 = ): /// vcvt.f32.s32 d16, d16 /// vdiv.f32 d16, d17, d16 /// becomes: /// vcvt.f32.s32 d16, d16, #3 static SDValue PerformVDIVCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, const ARMSubtarget *Subtarget) { SelectionDAG &DAG = DCI.DAG; SDValue Op = N->getOperand(0); unsigned OpOpcode = Op.getNode()->getOpcode(); if (!Subtarget->hasNEON() || !N->getValueType(0).isVector() || (OpOpcode != ISD::SINT_TO_FP && OpOpcode != ISD::UINT_TO_FP)) return SDValue(); uint64_t C; SDValue ConstVec = N->getOperand(1); bool isSigned = OpOpcode == ISD::SINT_TO_FP; if (ConstVec.getOpcode() != ISD::BUILD_VECTOR || !isConstVecPow2(ConstVec, isSigned, C)) return SDValue(); unsigned IntrinsicOpcode = isSigned ? Intrinsic::arm_neon_vcvtfxs2fp : Intrinsic::arm_neon_vcvtfxu2fp; return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, N->getDebugLoc(), Op.getValueType(), DAG.getConstant(IntrinsicOpcode, MVT::i32), Op.getOperand(0), DAG.getConstant(Log2_64(C), MVT::i32)); } /// Getvshiftimm - Check if this is a valid build_vector for the immediate /// operand of a vector shift operation, where all the elements of the /// build_vector must have the same constant integer value. static bool getVShiftImm(SDValue Op, unsigned ElementBits, int64_t &Cnt) { // Ignore bit_converts. while (Op.getOpcode() == ISD::BITCAST) Op = Op.getOperand(0); BuildVectorSDNode *BVN = dyn_cast(Op.getNode()); APInt SplatBits, SplatUndef; unsigned SplatBitSize; bool HasAnyUndefs; if (! BVN || ! BVN->isConstantSplat(SplatBits, SplatUndef, SplatBitSize, HasAnyUndefs, ElementBits) || SplatBitSize > ElementBits) return false; Cnt = SplatBits.getSExtValue(); return true; } /// isVShiftLImm - Check if this is a valid build_vector for the immediate /// operand of a vector shift left operation. That value must be in the range: /// 0 <= Value < ElementBits for a left shift; or /// 0 <= Value <= ElementBits for a long left shift. static bool isVShiftLImm(SDValue Op, EVT VT, bool isLong, int64_t &Cnt) { assert(VT.isVector() && "vector shift count is not a vector type"); unsigned ElementBits = VT.getVectorElementType().getSizeInBits(); if (! getVShiftImm(Op, ElementBits, Cnt)) return false; return (Cnt >= 0 && (isLong ? Cnt-1 : Cnt) < ElementBits); } /// isVShiftRImm - Check if this is a valid build_vector for the immediate /// operand of a vector shift right operation. For a shift opcode, the value /// is positive, but for an intrinsic the value count must be negative. The /// absolute value must be in the range: /// 1 <= |Value| <= ElementBits for a right shift; or /// 1 <= |Value| <= ElementBits/2 for a narrow right shift. static bool isVShiftRImm(SDValue Op, EVT VT, bool isNarrow, bool isIntrinsic, int64_t &Cnt) { assert(VT.isVector() && "vector shift count is not a vector type"); unsigned ElementBits = VT.getVectorElementType().getSizeInBits(); if (! getVShiftImm(Op, ElementBits, Cnt)) return false; if (isIntrinsic) Cnt = -Cnt; return (Cnt >= 1 && Cnt <= (isNarrow ? ElementBits/2 : ElementBits)); } /// PerformIntrinsicCombine - ARM-specific DAG combining for intrinsics. static SDValue PerformIntrinsicCombine(SDNode *N, SelectionDAG &DAG) { unsigned IntNo = cast(N->getOperand(0))->getZExtValue(); switch (IntNo) { default: // Don't do anything for most intrinsics. break; // Vector shifts: check for immediate versions and lower them. // Note: This is done during DAG combining instead of DAG legalizing because // the build_vectors for 64-bit vector element shift counts are generally // not legal, and it is hard to see their values after they get legalized to // loads from a constant pool. case Intrinsic::arm_neon_vshifts: case Intrinsic::arm_neon_vshiftu: case Intrinsic::arm_neon_vshiftls: case Intrinsic::arm_neon_vshiftlu: case Intrinsic::arm_neon_vshiftn: case Intrinsic::arm_neon_vrshifts: case Intrinsic::arm_neon_vrshiftu: case Intrinsic::arm_neon_vrshiftn: case Intrinsic::arm_neon_vqshifts: case Intrinsic::arm_neon_vqshiftu: case Intrinsic::arm_neon_vqshiftsu: case Intrinsic::arm_neon_vqshiftns: case Intrinsic::arm_neon_vqshiftnu: case Intrinsic::arm_neon_vqshiftnsu: case Intrinsic::arm_neon_vqrshiftns: case Intrinsic::arm_neon_vqrshiftnu: case Intrinsic::arm_neon_vqrshiftnsu: { EVT VT = N->getOperand(1).getValueType(); int64_t Cnt; unsigned VShiftOpc = 0; switch (IntNo) { case Intrinsic::arm_neon_vshifts: case Intrinsic::arm_neon_vshiftu: if (isVShiftLImm(N->getOperand(2), VT, false, Cnt)) { VShiftOpc = ARMISD::VSHL; break; } if (isVShiftRImm(N->getOperand(2), VT, false, true, Cnt)) { VShiftOpc = (IntNo == Intrinsic::arm_neon_vshifts ? ARMISD::VSHRs : ARMISD::VSHRu); break; } return SDValue(); case Intrinsic::arm_neon_vshiftls: case Intrinsic::arm_neon_vshiftlu: if (isVShiftLImm(N->getOperand(2), VT, true, Cnt)) break; llvm_unreachable("invalid shift count for vshll intrinsic"); case Intrinsic::arm_neon_vrshifts: case Intrinsic::arm_neon_vrshiftu: if (isVShiftRImm(N->getOperand(2), VT, false, true, Cnt)) break; return SDValue(); case Intrinsic::arm_neon_vqshifts: case Intrinsic::arm_neon_vqshiftu: if (isVShiftLImm(N->getOperand(2), VT, false, Cnt)) break; return SDValue(); case Intrinsic::arm_neon_vqshiftsu: if (isVShiftLImm(N->getOperand(2), VT, false, Cnt)) break; llvm_unreachable("invalid shift count for vqshlu intrinsic"); case Intrinsic::arm_neon_vshiftn: case Intrinsic::arm_neon_vrshiftn: case Intrinsic::arm_neon_vqshiftns: case Intrinsic::arm_neon_vqshiftnu: case Intrinsic::arm_neon_vqshiftnsu: case Intrinsic::arm_neon_vqrshiftns: case Intrinsic::arm_neon_vqrshiftnu: case Intrinsic::arm_neon_vqrshiftnsu: // Narrowing shifts require an immediate right shift. if (isVShiftRImm(N->getOperand(2), VT, true, true, Cnt)) break; llvm_unreachable("invalid shift count for narrowing vector shift " "intrinsic"); default: llvm_unreachable("unhandled vector shift"); } switch (IntNo) { case Intrinsic::arm_neon_vshifts: case Intrinsic::arm_neon_vshiftu: // Opcode already set above. break; case Intrinsic::arm_neon_vshiftls: case Intrinsic::arm_neon_vshiftlu: if (Cnt == VT.getVectorElementType().getSizeInBits()) VShiftOpc = ARMISD::VSHLLi; else VShiftOpc = (IntNo == Intrinsic::arm_neon_vshiftls ? ARMISD::VSHLLs : ARMISD::VSHLLu); break; case Intrinsic::arm_neon_vshiftn: VShiftOpc = ARMISD::VSHRN; break; case Intrinsic::arm_neon_vrshifts: VShiftOpc = ARMISD::VRSHRs; break; case Intrinsic::arm_neon_vrshiftu: VShiftOpc = ARMISD::VRSHRu; break; case Intrinsic::arm_neon_vrshiftn: VShiftOpc = ARMISD::VRSHRN; break; case Intrinsic::arm_neon_vqshifts: VShiftOpc = ARMISD::VQSHLs; break; case Intrinsic::arm_neon_vqshiftu: VShiftOpc = ARMISD::VQSHLu; break; case Intrinsic::arm_neon_vqshiftsu: VShiftOpc = ARMISD::VQSHLsu; break; case Intrinsic::arm_neon_vqshiftns: VShiftOpc = ARMISD::VQSHRNs; break; case Intrinsic::arm_neon_vqshiftnu: VShiftOpc = ARMISD::VQSHRNu; break; case Intrinsic::arm_neon_vqshiftnsu: VShiftOpc = ARMISD::VQSHRNsu; break; case Intrinsic::arm_neon_vqrshiftns: VShiftOpc = ARMISD::VQRSHRNs; break; case Intrinsic::arm_neon_vqrshiftnu: VShiftOpc = ARMISD::VQRSHRNu; break; case Intrinsic::arm_neon_vqrshiftnsu: VShiftOpc = ARMISD::VQRSHRNsu; break; } return DAG.getNode(VShiftOpc, N->getDebugLoc(), N->getValueType(0), N->getOperand(1), DAG.getConstant(Cnt, MVT::i32)); } case Intrinsic::arm_neon_vshiftins: { EVT VT = N->getOperand(1).getValueType(); int64_t Cnt; unsigned VShiftOpc = 0; if (isVShiftLImm(N->getOperand(3), VT, false, Cnt)) VShiftOpc = ARMISD::VSLI; else if (isVShiftRImm(N->getOperand(3), VT, false, true, Cnt)) VShiftOpc = ARMISD::VSRI; else { llvm_unreachable("invalid shift count for vsli/vsri intrinsic"); } return DAG.getNode(VShiftOpc, N->getDebugLoc(), N->getValueType(0), N->getOperand(1), N->getOperand(2), DAG.getConstant(Cnt, MVT::i32)); } case Intrinsic::arm_neon_vqrshifts: case Intrinsic::arm_neon_vqrshiftu: // No immediate versions of these to check for. break; } return SDValue(); } /// PerformShiftCombine - Checks for immediate versions of vector shifts and /// lowers them. As with the vector shift intrinsics, this is done during DAG /// combining instead of DAG legalizing because the build_vectors for 64-bit /// vector element shift counts are generally not legal, and it is hard to see /// their values after they get legalized to loads from a constant pool. static SDValue PerformShiftCombine(SDNode *N, SelectionDAG &DAG, const ARMSubtarget *ST) { EVT VT = N->getValueType(0); // Nothing to be done for scalar shifts. const TargetLowering &TLI = DAG.getTargetLoweringInfo(); if (!VT.isVector() || !TLI.isTypeLegal(VT)) return SDValue(); assert(ST->hasNEON() && "unexpected vector shift"); int64_t Cnt; switch (N->getOpcode()) { default: llvm_unreachable("unexpected shift opcode"); case ISD::SHL: if (isVShiftLImm(N->getOperand(1), VT, false, Cnt)) return DAG.getNode(ARMISD::VSHL, N->getDebugLoc(), VT, N->getOperand(0), DAG.getConstant(Cnt, MVT::i32)); break; case ISD::SRA: case ISD::SRL: if (isVShiftRImm(N->getOperand(1), VT, false, false, Cnt)) { unsigned VShiftOpc = (N->getOpcode() == ISD::SRA ? ARMISD::VSHRs : ARMISD::VSHRu); return DAG.getNode(VShiftOpc, N->getDebugLoc(), VT, N->getOperand(0), DAG.getConstant(Cnt, MVT::i32)); } } return SDValue(); } /// PerformExtendCombine - Target-specific DAG combining for ISD::SIGN_EXTEND, /// ISD::ZERO_EXTEND, and ISD::ANY_EXTEND. static SDValue PerformExtendCombine(SDNode *N, SelectionDAG &DAG, const ARMSubtarget *ST) { SDValue N0 = N->getOperand(0); // Check for sign- and zero-extensions of vector extract operations of 8- // and 16-bit vector elements. NEON supports these directly. They are // handled during DAG combining because type legalization will promote them // to 32-bit types and it is messy to recognize the operations after that. if (ST->hasNEON() && N0.getOpcode() == ISD::EXTRACT_VECTOR_ELT) { SDValue Vec = N0.getOperand(0); SDValue Lane = N0.getOperand(1); EVT VT = N->getValueType(0); EVT EltVT = N0.getValueType(); const TargetLowering &TLI = DAG.getTargetLoweringInfo(); if (VT == MVT::i32 && (EltVT == MVT::i8 || EltVT == MVT::i16) && TLI.isTypeLegal(Vec.getValueType()) && isa(Lane)) { unsigned Opc = 0; switch (N->getOpcode()) { default: llvm_unreachable("unexpected opcode"); case ISD::SIGN_EXTEND: Opc = ARMISD::VGETLANEs; break; case ISD::ZERO_EXTEND: case ISD::ANY_EXTEND: Opc = ARMISD::VGETLANEu; break; } return DAG.getNode(Opc, N->getDebugLoc(), VT, Vec, Lane); } } return SDValue(); } /// PerformSELECT_CCCombine - Target-specific DAG combining for ISD::SELECT_CC /// to match f32 max/min patterns to use NEON vmax/vmin instructions. static SDValue PerformSELECT_CCCombine(SDNode *N, SelectionDAG &DAG, const ARMSubtarget *ST) { // If the target supports NEON, try to use vmax/vmin instructions for f32 // selects like "x < y ? x : y". Unless the NoNaNsFPMath option is set, // be careful about NaNs: NEON's vmax/vmin return NaN if either operand is // a NaN; only do the transformation when it matches that behavior. // For now only do this when using NEON for FP operations; if using VFP, it // is not obvious that the benefit outweighs the cost of switching to the // NEON pipeline. if (!ST->hasNEON() || !ST->useNEONForSinglePrecisionFP() || N->getValueType(0) != MVT::f32) return SDValue(); SDValue CondLHS = N->getOperand(0); SDValue CondRHS = N->getOperand(1); SDValue LHS = N->getOperand(2); SDValue RHS = N->getOperand(3); ISD::CondCode CC = cast(N->getOperand(4))->get(); unsigned Opcode = 0; bool IsReversed; if (DAG.isEqualTo(LHS, CondLHS) && DAG.isEqualTo(RHS, CondRHS)) { IsReversed = false; // x CC y ? x : y } else if (DAG.isEqualTo(LHS, CondRHS) && DAG.isEqualTo(RHS, CondLHS)) { IsReversed = true ; // x CC y ? y : x } else { return SDValue(); } bool IsUnordered; switch (CC) { default: break; case ISD::SETOLT: case ISD::SETOLE: case ISD::SETLT: case ISD::SETLE: case ISD::SETULT: case ISD::SETULE: // If LHS is NaN, an ordered comparison will be false and the result will // be the RHS, but vmin(NaN, RHS) = NaN. Avoid this by checking that LHS // != NaN. Likewise, for unordered comparisons, check for RHS != NaN. IsUnordered = (CC == ISD::SETULT || CC == ISD::SETULE); if (!DAG.isKnownNeverNaN(IsUnordered ? RHS : LHS)) break; // For less-than-or-equal comparisons, "+0 <= -0" will be true but vmin // will return -0, so vmin can only be used for unsafe math or if one of // the operands is known to be nonzero. if ((CC == ISD::SETLE || CC == ISD::SETOLE || CC == ISD::SETULE) && !UnsafeFPMath && !(DAG.isKnownNeverZero(LHS) || DAG.isKnownNeverZero(RHS))) break; Opcode = IsReversed ? ARMISD::FMAX : ARMISD::FMIN; break; case ISD::SETOGT: case ISD::SETOGE: case ISD::SETGT: case ISD::SETGE: case ISD::SETUGT: case ISD::SETUGE: // If LHS is NaN, an ordered comparison will be false and the result will // be the RHS, but vmax(NaN, RHS) = NaN. Avoid this by checking that LHS // != NaN. Likewise, for unordered comparisons, check for RHS != NaN. IsUnordered = (CC == ISD::SETUGT || CC == ISD::SETUGE); if (!DAG.isKnownNeverNaN(IsUnordered ? RHS : LHS)) break; // For greater-than-or-equal comparisons, "-0 >= +0" will be true but vmax // will return +0, so vmax can only be used for unsafe math or if one of // the operands is known to be nonzero. if ((CC == ISD::SETGE || CC == ISD::SETOGE || CC == ISD::SETUGE) && !UnsafeFPMath && !(DAG.isKnownNeverZero(LHS) || DAG.isKnownNeverZero(RHS))) break; Opcode = IsReversed ? ARMISD::FMIN : ARMISD::FMAX; break; } if (!Opcode) return SDValue(); return DAG.getNode(Opcode, N->getDebugLoc(), N->getValueType(0), LHS, RHS); } /// PerformCMOVCombine - Target-specific DAG combining for ARMISD::CMOV. SDValue ARMTargetLowering::PerformCMOVCombine(SDNode *N, SelectionDAG &DAG) const { SDValue Cmp = N->getOperand(4); if (Cmp.getOpcode() != ARMISD::CMPZ) // Only looking at EQ and NE cases. return SDValue(); EVT VT = N->getValueType(0); DebugLoc dl = N->getDebugLoc(); SDValue LHS = Cmp.getOperand(0); SDValue RHS = Cmp.getOperand(1); SDValue FalseVal = N->getOperand(0); SDValue TrueVal = N->getOperand(1); SDValue ARMcc = N->getOperand(2); ARMCC::CondCodes CC = (ARMCC::CondCodes)cast(ARMcc)->getZExtValue(); // Simplify // mov r1, r0 // cmp r1, x // mov r0, y // moveq r0, x // to // cmp r0, x // movne r0, y // // mov r1, r0 // cmp r1, x // mov r0, x // movne r0, y // to // cmp r0, x // movne r0, y /// FIXME: Turn this into a target neutral optimization? SDValue Res; if (CC == ARMCC::NE && FalseVal == RHS && FalseVal != LHS) { Res = DAG.getNode(ARMISD::CMOV, dl, VT, LHS, TrueVal, ARMcc, N->getOperand(3), Cmp); } else if (CC == ARMCC::EQ && TrueVal == RHS) { SDValue ARMcc; SDValue NewCmp = getARMCmp(LHS, RHS, ISD::SETNE, ARMcc, DAG, dl); Res = DAG.getNode(ARMISD::CMOV, dl, VT, LHS, FalseVal, ARMcc, N->getOperand(3), NewCmp); } if (Res.getNode()) { APInt KnownZero, KnownOne; APInt Mask = APInt::getAllOnesValue(VT.getScalarType().getSizeInBits()); DAG.ComputeMaskedBits(SDValue(N,0), Mask, KnownZero, KnownOne); // Capture demanded bits information that would be otherwise lost. if (KnownZero == 0xfffffffe) Res = DAG.getNode(ISD::AssertZext, dl, MVT::i32, Res, DAG.getValueType(MVT::i1)); else if (KnownZero == 0xffffff00) Res = DAG.getNode(ISD::AssertZext, dl, MVT::i32, Res, DAG.getValueType(MVT::i8)); else if (KnownZero == 0xffff0000) Res = DAG.getNode(ISD::AssertZext, dl, MVT::i32, Res, DAG.getValueType(MVT::i16)); } return Res; } SDValue ARMTargetLowering::PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const { switch (N->getOpcode()) { default: break; case ISD::ADD: return PerformADDCombine(N, DCI, Subtarget); case ISD::SUB: return PerformSUBCombine(N, DCI); case ISD::MUL: return PerformMULCombine(N, DCI, Subtarget); case ISD::OR: return PerformORCombine(N, DCI, Subtarget); case ISD::AND: return PerformANDCombine(N, DCI); case ARMISD::BFI: return PerformBFICombine(N, DCI); case ARMISD::VMOVRRD: return PerformVMOVRRDCombine(N, DCI); case ARMISD::VMOVDRR: return PerformVMOVDRRCombine(N, DCI.DAG); case ISD::STORE: return PerformSTORECombine(N, DCI); case ISD::BUILD_VECTOR: return PerformBUILD_VECTORCombine(N, DCI); case ISD::INSERT_VECTOR_ELT: return PerformInsertEltCombine(N, DCI); case ISD::VECTOR_SHUFFLE: return PerformVECTOR_SHUFFLECombine(N, DCI.DAG); case ARMISD::VDUPLANE: return PerformVDUPLANECombine(N, DCI); case ISD::FP_TO_SINT: case ISD::FP_TO_UINT: return PerformVCVTCombine(N, DCI, Subtarget); case ISD::FDIV: return PerformVDIVCombine(N, DCI, Subtarget); case ISD::INTRINSIC_WO_CHAIN: return PerformIntrinsicCombine(N, DCI.DAG); case ISD::SHL: case ISD::SRA: case ISD::SRL: return PerformShiftCombine(N, DCI.DAG, Subtarget); case ISD::SIGN_EXTEND: case ISD::ZERO_EXTEND: case ISD::ANY_EXTEND: return PerformExtendCombine(N, DCI.DAG, Subtarget); case ISD::SELECT_CC: return PerformSELECT_CCCombine(N, DCI.DAG, Subtarget); case ARMISD::CMOV: return PerformCMOVCombine(N, DCI.DAG); case ARMISD::VLD2DUP: case ARMISD::VLD3DUP: case ARMISD::VLD4DUP: return CombineBaseUpdate(N, DCI); case ISD::INTRINSIC_VOID: case ISD::INTRINSIC_W_CHAIN: switch (cast(N->getOperand(1))->getZExtValue()) { case Intrinsic::arm_neon_vld1: case Intrinsic::arm_neon_vld2: case Intrinsic::arm_neon_vld3: case Intrinsic::arm_neon_vld4: case Intrinsic::arm_neon_vld2lane: case Intrinsic::arm_neon_vld3lane: case Intrinsic::arm_neon_vld4lane: case Intrinsic::arm_neon_vst1: case Intrinsic::arm_neon_vst2: case Intrinsic::arm_neon_vst3: case Intrinsic::arm_neon_vst4: case Intrinsic::arm_neon_vst2lane: case Intrinsic::arm_neon_vst3lane: case Intrinsic::arm_neon_vst4lane: return CombineBaseUpdate(N, DCI); default: break; } break; } return SDValue(); } bool ARMTargetLowering::isDesirableToTransformToIntegerOp(unsigned Opc, EVT VT) const { return (VT == MVT::f32) && (Opc == ISD::LOAD || Opc == ISD::STORE); } bool ARMTargetLowering::allowsUnalignedMemoryAccesses(EVT VT) const { if (!Subtarget->allowsUnalignedMem()) return false; switch (VT.getSimpleVT().SimpleTy) { default: return false; case MVT::i8: case MVT::i16: case MVT::i32: return true; // FIXME: VLD1 etc with standard alignment is legal. } } static bool isLegalT1AddressImmediate(int64_t V, EVT VT) { if (V < 0) return false; unsigned Scale = 1; switch (VT.getSimpleVT().SimpleTy) { default: return false; case MVT::i1: case MVT::i8: // Scale == 1; break; case MVT::i16: // Scale == 2; Scale = 2; break; case MVT::i32: // Scale == 4; Scale = 4; break; } if ((V & (Scale - 1)) != 0) return false; V /= Scale; return V == (V & ((1LL << 5) - 1)); } static bool isLegalT2AddressImmediate(int64_t V, EVT VT, const ARMSubtarget *Subtarget) { bool isNeg = false; if (V < 0) { isNeg = true; V = - V; } switch (VT.getSimpleVT().SimpleTy) { default: return false; case MVT::i1: case MVT::i8: case MVT::i16: case MVT::i32: // + imm12 or - imm8 if (isNeg) return V == (V & ((1LL << 8) - 1)); return V == (V & ((1LL << 12) - 1)); case MVT::f32: case MVT::f64: // Same as ARM mode. FIXME: NEON? if (!Subtarget->hasVFP2()) return false; if ((V & 3) != 0) return false; V >>= 2; return V == (V & ((1LL << 8) - 1)); } } /// isLegalAddressImmediate - Return true if the integer value can be used /// as the offset of the target addressing mode for load / store of the /// given type. static bool isLegalAddressImmediate(int64_t V, EVT VT, const ARMSubtarget *Subtarget) { if (V == 0) return true; if (!VT.isSimple()) return false; if (Subtarget->isThumb1Only()) return isLegalT1AddressImmediate(V, VT); else if (Subtarget->isThumb2()) return isLegalT2AddressImmediate(V, VT, Subtarget); // ARM mode. if (V < 0) V = - V; switch (VT.getSimpleVT().SimpleTy) { default: return false; case MVT::i1: case MVT::i8: case MVT::i32: // +- imm12 return V == (V & ((1LL << 12) - 1)); case MVT::i16: // +- imm8 return V == (V & ((1LL << 8) - 1)); case MVT::f32: case MVT::f64: if (!Subtarget->hasVFP2()) // FIXME: NEON? return false; if ((V & 3) != 0) return false; V >>= 2; return V == (V & ((1LL << 8) - 1)); } } bool ARMTargetLowering::isLegalT2ScaledAddressingMode(const AddrMode &AM, EVT VT) const { int Scale = AM.Scale; if (Scale < 0) return false; switch (VT.getSimpleVT().SimpleTy) { default: return false; case MVT::i1: case MVT::i8: case MVT::i16: case MVT::i32: if (Scale == 1) return true; // r + r << imm Scale = Scale & ~1; return Scale == 2 || Scale == 4 || Scale == 8; case MVT::i64: // r + r if (((unsigned)AM.HasBaseReg + Scale) <= 2) return true; return false; case MVT::isVoid: // Note, we allow "void" uses (basically, uses that aren't loads or // stores), because arm allows folding a scale into many arithmetic // operations. This should be made more precise and revisited later. // Allow r << imm, but the imm has to be a multiple of two. if (Scale & 1) return false; return isPowerOf2_32(Scale); } } /// isLegalAddressingMode - Return true if the addressing mode represented /// by AM is legal for this target, for a load/store of the specified type. bool ARMTargetLowering::isLegalAddressingMode(const AddrMode &AM, Type *Ty) const { EVT VT = getValueType(Ty, true); if (!isLegalAddressImmediate(AM.BaseOffs, VT, Subtarget)) return false; // Can never fold addr of global into load/store. if (AM.BaseGV) return false; switch (AM.Scale) { case 0: // no scale reg, must be "r+i" or "r", or "i". break; case 1: if (Subtarget->isThumb1Only()) return false; // FALL THROUGH. default: // ARM doesn't support any R+R*scale+imm addr modes. if (AM.BaseOffs) return false; if (!VT.isSimple()) return false; if (Subtarget->isThumb2()) return isLegalT2ScaledAddressingMode(AM, VT); int Scale = AM.Scale; switch (VT.getSimpleVT().SimpleTy) { default: return false; case MVT::i1: case MVT::i8: case MVT::i32: if (Scale < 0) Scale = -Scale; if (Scale == 1) return true; // r + r << imm return isPowerOf2_32(Scale & ~1); case MVT::i16: case MVT::i64: // r + r if (((unsigned)AM.HasBaseReg + Scale) <= 2) return true; return false; case MVT::isVoid: // Note, we allow "void" uses (basically, uses that aren't loads or // stores), because arm allows folding a scale into many arithmetic // operations. This should be made more precise and revisited later. // Allow r << imm, but the imm has to be a multiple of two. if (Scale & 1) return false; return isPowerOf2_32(Scale); } break; } return true; } /// isLegalICmpImmediate - Return true if the specified immediate is legal /// icmp immediate, that is the target has icmp instructions which can compare /// a register against the immediate without having to materialize the /// immediate into a register. bool ARMTargetLowering::isLegalICmpImmediate(int64_t Imm) const { if (!Subtarget->isThumb()) return ARM_AM::getSOImmVal(Imm) != -1; if (Subtarget->isThumb2()) return ARM_AM::getT2SOImmVal(Imm) != -1; return Imm >= 0 && Imm <= 255; } /// isLegalAddImmediate - Return true if the specified immediate is legal /// add immediate, that is the target has add instructions which can add /// a register with the immediate without having to materialize the /// immediate into a register. bool ARMTargetLowering::isLegalAddImmediate(int64_t Imm) const { return ARM_AM::getSOImmVal(Imm) != -1; } static bool getARMIndexedAddressParts(SDNode *Ptr, EVT VT, bool isSEXTLoad, SDValue &Base, SDValue &Offset, bool &isInc, SelectionDAG &DAG) { if (Ptr->getOpcode() != ISD::ADD && Ptr->getOpcode() != ISD::SUB) return false; if (VT == MVT::i16 || ((VT == MVT::i8 || VT == MVT::i1) && isSEXTLoad)) { // AddressingMode 3 Base = Ptr->getOperand(0); if (ConstantSDNode *RHS = dyn_cast(Ptr->getOperand(1))) { int RHSC = (int)RHS->getZExtValue(); if (RHSC < 0 && RHSC > -256) { assert(Ptr->getOpcode() == ISD::ADD); isInc = false; Offset = DAG.getConstant(-RHSC, RHS->getValueType(0)); return true; } } isInc = (Ptr->getOpcode() == ISD::ADD); Offset = Ptr->getOperand(1); return true; } else if (VT == MVT::i32 || VT == MVT::i8 || VT == MVT::i1) { // AddressingMode 2 if (ConstantSDNode *RHS = dyn_cast(Ptr->getOperand(1))) { int RHSC = (int)RHS->getZExtValue(); if (RHSC < 0 && RHSC > -0x1000) { assert(Ptr->getOpcode() == ISD::ADD); isInc = false; Offset = DAG.getConstant(-RHSC, RHS->getValueType(0)); Base = Ptr->getOperand(0); return true; } } if (Ptr->getOpcode() == ISD::ADD) { isInc = true; ARM_AM::ShiftOpc ShOpcVal= ARM_AM::getShiftOpcForNode(Ptr->getOperand(0).getOpcode()); if (ShOpcVal != ARM_AM::no_shift) { Base = Ptr->getOperand(1); Offset = Ptr->getOperand(0); } else { Base = Ptr->getOperand(0); Offset = Ptr->getOperand(1); } return true; } isInc = (Ptr->getOpcode() == ISD::ADD); Base = Ptr->getOperand(0); Offset = Ptr->getOperand(1); return true; } // FIXME: Use VLDM / VSTM to emulate indexed FP load / store. return false; } static bool getT2IndexedAddressParts(SDNode *Ptr, EVT VT, bool isSEXTLoad, SDValue &Base, SDValue &Offset, bool &isInc, SelectionDAG &DAG) { if (Ptr->getOpcode() != ISD::ADD && Ptr->getOpcode() != ISD::SUB) return false; Base = Ptr->getOperand(0); if (ConstantSDNode *RHS = dyn_cast(Ptr->getOperand(1))) { int RHSC = (int)RHS->getZExtValue(); if (RHSC < 0 && RHSC > -0x100) { // 8 bits. assert(Ptr->getOpcode() == ISD::ADD); isInc = false; Offset = DAG.getConstant(-RHSC, RHS->getValueType(0)); return true; } else if (RHSC > 0 && RHSC < 0x100) { // 8 bit, no zero. isInc = Ptr->getOpcode() == ISD::ADD; Offset = DAG.getConstant(RHSC, RHS->getValueType(0)); return true; } } return false; } /// getPreIndexedAddressParts - returns true by value, base pointer and /// offset pointer and addressing mode by reference if the node's address /// can be legally represented as pre-indexed load / store address. bool ARMTargetLowering::getPreIndexedAddressParts(SDNode *N, SDValue &Base, SDValue &Offset, ISD::MemIndexedMode &AM, SelectionDAG &DAG) const { if (Subtarget->isThumb1Only()) return false; EVT VT; SDValue Ptr; bool isSEXTLoad = false; if (LoadSDNode *LD = dyn_cast(N)) { Ptr = LD->getBasePtr(); VT = LD->getMemoryVT(); isSEXTLoad = LD->getExtensionType() == ISD::SEXTLOAD; } else if (StoreSDNode *ST = dyn_cast(N)) { Ptr = ST->getBasePtr(); VT = ST->getMemoryVT(); } else return false; bool isInc; bool isLegal = false; if (Subtarget->isThumb2()) isLegal = getT2IndexedAddressParts(Ptr.getNode(), VT, isSEXTLoad, Base, Offset, isInc, DAG); else isLegal = getARMIndexedAddressParts(Ptr.getNode(), VT, isSEXTLoad, Base, Offset, isInc, DAG); if (!isLegal) return false; AM = isInc ? ISD::PRE_INC : ISD::PRE_DEC; return true; } /// getPostIndexedAddressParts - returns true by value, base pointer and /// offset pointer and addressing mode by reference if this node can be /// combined with a load / store to form a post-indexed load / store. bool ARMTargetLowering::getPostIndexedAddressParts(SDNode *N, SDNode *Op, SDValue &Base, SDValue &Offset, ISD::MemIndexedMode &AM, SelectionDAG &DAG) const { if (Subtarget->isThumb1Only()) return false; EVT VT; SDValue Ptr; bool isSEXTLoad = false; if (LoadSDNode *LD = dyn_cast(N)) { VT = LD->getMemoryVT(); Ptr = LD->getBasePtr(); isSEXTLoad = LD->getExtensionType() == ISD::SEXTLOAD; } else if (StoreSDNode *ST = dyn_cast(N)) { VT = ST->getMemoryVT(); Ptr = ST->getBasePtr(); } else return false; bool isInc; bool isLegal = false; if (Subtarget->isThumb2()) isLegal = getT2IndexedAddressParts(Op, VT, isSEXTLoad, Base, Offset, isInc, DAG); else isLegal = getARMIndexedAddressParts(Op, VT, isSEXTLoad, Base, Offset, isInc, DAG); if (!isLegal) return false; if (Ptr != Base) { // Swap base ptr and offset to catch more post-index load / store when // it's legal. In Thumb2 mode, offset must be an immediate. if (Ptr == Offset && Op->getOpcode() == ISD::ADD && !Subtarget->isThumb2()) std::swap(Base, Offset); // Post-indexed load / store update the base pointer. if (Ptr != Base) return false; } AM = isInc ? ISD::POST_INC : ISD::POST_DEC; return true; } void ARMTargetLowering::computeMaskedBitsForTargetNode(const SDValue Op, const APInt &Mask, APInt &KnownZero, APInt &KnownOne, const SelectionDAG &DAG, unsigned Depth) const { KnownZero = KnownOne = APInt(Mask.getBitWidth(), 0); switch (Op.getOpcode()) { default: break; case ARMISD::CMOV: { // Bits are known zero/one if known on the LHS and RHS. DAG.ComputeMaskedBits(Op.getOperand(0), Mask, KnownZero, KnownOne, Depth+1); if (KnownZero == 0 && KnownOne == 0) return; APInt KnownZeroRHS, KnownOneRHS; DAG.ComputeMaskedBits(Op.getOperand(1), Mask, KnownZeroRHS, KnownOneRHS, Depth+1); KnownZero &= KnownZeroRHS; KnownOne &= KnownOneRHS; return; } } } //===----------------------------------------------------------------------===// // ARM Inline Assembly Support //===----------------------------------------------------------------------===// bool ARMTargetLowering::ExpandInlineAsm(CallInst *CI) const { // Looking for "rev" which is V6+. if (!Subtarget->hasV6Ops()) return false; InlineAsm *IA = cast(CI->getCalledValue()); std::string AsmStr = IA->getAsmString(); SmallVector AsmPieces; SplitString(AsmStr, AsmPieces, ";\n"); switch (AsmPieces.size()) { default: return false; case 1: AsmStr = AsmPieces[0]; AsmPieces.clear(); SplitString(AsmStr, AsmPieces, " \t,"); // rev $0, $1 if (AsmPieces.size() == 3 && AsmPieces[0] == "rev" && AsmPieces[1] == "$0" && AsmPieces[2] == "$1" && IA->getConstraintString().compare(0, 4, "=l,l") == 0) { IntegerType *Ty = dyn_cast(CI->getType()); if (Ty && Ty->getBitWidth() == 32) return IntrinsicLowering::LowerToByteSwap(CI); } break; } return false; } /// getConstraintType - Given a constraint letter, return the type of /// constraint it is for this target. ARMTargetLowering::ConstraintType ARMTargetLowering::getConstraintType(const std::string &Constraint) const { if (Constraint.size() == 1) { switch (Constraint[0]) { default: break; case 'l': return C_RegisterClass; case 'w': return C_RegisterClass; case 'h': return C_RegisterClass; case 'x': return C_RegisterClass; case 't': return C_RegisterClass; case 'j': return C_Other; // Constant for movw. // An address with a single base register. Due to the way we // currently handle addresses it is the same as an 'r' memory constraint. case 'Q': return C_Memory; } } else if (Constraint.size() == 2) { switch (Constraint[0]) { default: break; // All 'U+' constraints are addresses. case 'U': return C_Memory; } } return TargetLowering::getConstraintType(Constraint); } /// Examine constraint type and operand type and determine a weight value. /// This object must already have been set up with the operand type /// and the current alternative constraint selected. TargetLowering::ConstraintWeight ARMTargetLowering::getSingleConstraintMatchWeight( AsmOperandInfo &info, const char *constraint) const { ConstraintWeight weight = CW_Invalid; Value *CallOperandVal = info.CallOperandVal; // If we don't have a value, we can't do a match, // but allow it at the lowest weight. if (CallOperandVal == NULL) return CW_Default; Type *type = CallOperandVal->getType(); // Look at the constraint type. switch (*constraint) { default: weight = TargetLowering::getSingleConstraintMatchWeight(info, constraint); break; case 'l': if (type->isIntegerTy()) { if (Subtarget->isThumb()) weight = CW_SpecificReg; else weight = CW_Register; } break; case 'w': if (type->isFloatingPointTy()) weight = CW_Register; break; } return weight; } typedef std::pair RCPair; RCPair ARMTargetLowering::getRegForInlineAsmConstraint(const std::string &Constraint, EVT VT) const { if (Constraint.size() == 1) { // GCC ARM Constraint Letters switch (Constraint[0]) { case 'l': // Low regs or general regs. if (Subtarget->isThumb()) return RCPair(0U, ARM::tGPRRegisterClass); else return RCPair(0U, ARM::GPRRegisterClass); case 'h': // High regs or no regs. if (Subtarget->isThumb()) return RCPair(0U, ARM::hGPRRegisterClass); break; case 'r': return RCPair(0U, ARM::GPRRegisterClass); case 'w': if (VT == MVT::f32) return RCPair(0U, ARM::SPRRegisterClass); if (VT.getSizeInBits() == 64) return RCPair(0U, ARM::DPRRegisterClass); if (VT.getSizeInBits() == 128) return RCPair(0U, ARM::QPRRegisterClass); break; case 'x': if (VT == MVT::f32) return RCPair(0U, ARM::SPR_8RegisterClass); if (VT.getSizeInBits() == 64) return RCPair(0U, ARM::DPR_8RegisterClass); if (VT.getSizeInBits() == 128) return RCPair(0U, ARM::QPR_8RegisterClass); break; case 't': if (VT == MVT::f32) return RCPair(0U, ARM::SPRRegisterClass); break; } } if (StringRef("{cc}").equals_lower(Constraint)) return std::make_pair(unsigned(ARM::CPSR), ARM::CCRRegisterClass); return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT); } /// LowerAsmOperandForConstraint - Lower the specified operand into the Ops /// vector. If it is invalid, don't add anything to Ops. void ARMTargetLowering::LowerAsmOperandForConstraint(SDValue Op, std::string &Constraint, std::vector&Ops, SelectionDAG &DAG) const { SDValue Result(0, 0); // Currently only support length 1 constraints. if (Constraint.length() != 1) return; char ConstraintLetter = Constraint[0]; switch (ConstraintLetter) { default: break; case 'j': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': ConstantSDNode *C = dyn_cast(Op); if (!C) return; int64_t CVal64 = C->getSExtValue(); int CVal = (int) CVal64; // None of these constraints allow values larger than 32 bits. Check // that the value fits in an int. if (CVal != CVal64) return; switch (ConstraintLetter) { case 'j': // Constant suitable for movw, must be between 0 and // 65535. if (Subtarget->hasV6T2Ops()) if (CVal >= 0 && CVal <= 65535) break; return; case 'I': if (Subtarget->isThumb1Only()) { // This must be a constant between 0 and 255, for ADD // immediates. if (CVal >= 0 && CVal <= 255) break; } else if (Subtarget->isThumb2()) { // A constant that can be used as an immediate value in a // data-processing instruction. if (ARM_AM::getT2SOImmVal(CVal) != -1) break; } else { // A constant that can be used as an immediate value in a // data-processing instruction. if (ARM_AM::getSOImmVal(CVal) != -1) break; } return; case 'J': if (Subtarget->isThumb()) { // FIXME thumb2 // This must be a constant between -255 and -1, for negated ADD // immediates. This can be used in GCC with an "n" modifier that // prints the negated value, for use with SUB instructions. It is // not useful otherwise but is implemented for compatibility. if (CVal >= -255 && CVal <= -1) break; } else { // This must be a constant between -4095 and 4095. It is not clear // what this constraint is intended for. Implemented for // compatibility with GCC. if (CVal >= -4095 && CVal <= 4095) break; } return; case 'K': if (Subtarget->isThumb1Only()) { // A 32-bit value where only one byte has a nonzero value. Exclude // zero to match GCC. This constraint is used by GCC internally for // constants that can be loaded with a move/shift combination. // It is not useful otherwise but is implemented for compatibility. if (CVal != 0 && ARM_AM::isThumbImmShiftedVal(CVal)) break; } else if (Subtarget->isThumb2()) { // A constant whose bitwise inverse can be used as an immediate // value in a data-processing instruction. This can be used in GCC // with a "B" modifier that prints the inverted value, for use with // BIC and MVN instructions. It is not useful otherwise but is // implemented for compatibility. if (ARM_AM::getT2SOImmVal(~CVal) != -1) break; } else { // A constant whose bitwise inverse can be used as an immediate // value in a data-processing instruction. This can be used in GCC // with a "B" modifier that prints the inverted value, for use with // BIC and MVN instructions. It is not useful otherwise but is // implemented for compatibility. if (ARM_AM::getSOImmVal(~CVal) != -1) break; } return; case 'L': if (Subtarget->isThumb1Only()) { // This must be a constant between -7 and 7, // for 3-operand ADD/SUB immediate instructions. if (CVal >= -7 && CVal < 7) break; } else if (Subtarget->isThumb2()) { // A constant whose negation can be used as an immediate value in a // data-processing instruction. This can be used in GCC with an "n" // modifier that prints the negated value, for use with SUB // instructions. It is not useful otherwise but is implemented for // compatibility. if (ARM_AM::getT2SOImmVal(-CVal) != -1) break; } else { // A constant whose negation can be used as an immediate value in a // data-processing instruction. This can be used in GCC with an "n" // modifier that prints the negated value, for use with SUB // instructions. It is not useful otherwise but is implemented for // compatibility. if (ARM_AM::getSOImmVal(-CVal) != -1) break; } return; case 'M': if (Subtarget->isThumb()) { // FIXME thumb2 // This must be a multiple of 4 between 0 and 1020, for // ADD sp + immediate. if ((CVal >= 0 && CVal <= 1020) && ((CVal & 3) == 0)) break; } else { // A power of two or a constant between 0 and 32. This is used in // GCC for the shift amount on shifted register operands, but it is // useful in general for any shift amounts. if ((CVal >= 0 && CVal <= 32) || ((CVal & (CVal - 1)) == 0)) break; } return; case 'N': if (Subtarget->isThumb()) { // FIXME thumb2 // This must be a constant between 0 and 31, for shift amounts. if (CVal >= 0 && CVal <= 31) break; } return; case 'O': if (Subtarget->isThumb()) { // FIXME thumb2 // This must be a multiple of 4 between -508 and 508, for // ADD/SUB sp = sp + immediate. if ((CVal >= -508 && CVal <= 508) && ((CVal & 3) == 0)) break; } return; } Result = DAG.getTargetConstant(CVal, Op.getValueType()); break; } if (Result.getNode()) { Ops.push_back(Result); return; } return TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG); } bool ARMTargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const { // The ARM target isn't yet aware of offsets. return false; } bool ARM::isBitFieldInvertedMask(unsigned v) { if (v == 0xffffffff) return 0; // there can be 1's on either or both "outsides", all the "inside" // bits must be 0's unsigned int lsb = 0, msb = 31; while (v & (1 << msb)) --msb; while (v & (1 << lsb)) ++lsb; for (unsigned int i = lsb; i <= msb; ++i) { if (v & (1 << i)) return 0; } return 1; } /// isFPImmLegal - Returns true if the target can instruction select the /// specified FP immediate natively. If false, the legalizer will /// materialize the FP immediate as a load from a constant pool. bool ARMTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT) const { if (!Subtarget->hasVFP3()) return false; if (VT == MVT::f32) return ARM_AM::getFP32Imm(Imm) != -1; if (VT == MVT::f64) return ARM_AM::getFP64Imm(Imm) != -1; return false; } /// getTgtMemIntrinsic - Represent NEON load and store intrinsics as /// MemIntrinsicNodes. The associated MachineMemOperands record the alignment /// specified in the intrinsic calls. bool ARMTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info, const CallInst &I, unsigned Intrinsic) const { switch (Intrinsic) { case Intrinsic::arm_neon_vld1: case Intrinsic::arm_neon_vld2: case Intrinsic::arm_neon_vld3: case Intrinsic::arm_neon_vld4: case Intrinsic::arm_neon_vld2lane: case Intrinsic::arm_neon_vld3lane: case Intrinsic::arm_neon_vld4lane: { Info.opc = ISD::INTRINSIC_W_CHAIN; // Conservatively set memVT to the entire set of vectors loaded. uint64_t NumElts = getTargetData()->getTypeAllocSize(I.getType()) / 8; Info.memVT = EVT::getVectorVT(I.getType()->getContext(), MVT::i64, NumElts); Info.ptrVal = I.getArgOperand(0); Info.offset = 0; Value *AlignArg = I.getArgOperand(I.getNumArgOperands() - 1); Info.align = cast(AlignArg)->getZExtValue(); Info.vol = false; // volatile loads with NEON intrinsics not supported Info.readMem = true; Info.writeMem = false; return true; } case Intrinsic::arm_neon_vst1: case Intrinsic::arm_neon_vst2: case Intrinsic::arm_neon_vst3: case Intrinsic::arm_neon_vst4: case Intrinsic::arm_neon_vst2lane: case Intrinsic::arm_neon_vst3lane: case Intrinsic::arm_neon_vst4lane: { Info.opc = ISD::INTRINSIC_VOID; // Conservatively set memVT to the entire set of vectors stored. unsigned NumElts = 0; for (unsigned ArgI = 1, ArgE = I.getNumArgOperands(); ArgI < ArgE; ++ArgI) { Type *ArgTy = I.getArgOperand(ArgI)->getType(); if (!ArgTy->isVectorTy()) break; NumElts += getTargetData()->getTypeAllocSize(ArgTy) / 8; } Info.memVT = EVT::getVectorVT(I.getType()->getContext(), MVT::i64, NumElts); Info.ptrVal = I.getArgOperand(0); Info.offset = 0; Value *AlignArg = I.getArgOperand(I.getNumArgOperands() - 1); Info.align = cast(AlignArg)->getZExtValue(); Info.vol = false; // volatile stores with NEON intrinsics not supported Info.readMem = false; Info.writeMem = true; return true; } case Intrinsic::arm_strexd: { Info.opc = ISD::INTRINSIC_W_CHAIN; Info.memVT = MVT::i64; Info.ptrVal = I.getArgOperand(2); Info.offset = 0; Info.align = 8; Info.vol = true; Info.readMem = false; Info.writeMem = true; return true; } case Intrinsic::arm_ldrexd: { Info.opc = ISD::INTRINSIC_W_CHAIN; Info.memVT = MVT::i64; Info.ptrVal = I.getArgOperand(0); Info.offset = 0; Info.align = 8; Info.vol = true; Info.readMem = true; Info.writeMem = false; return true; } default: break; } return false; } Index: head/contrib/llvm/lib/Target/ARM/ARMInstrThumb2.td =================================================================== --- head/contrib/llvm/lib/Target/ARM/ARMInstrThumb2.td (revision 228378) +++ head/contrib/llvm/lib/Target/ARM/ARMInstrThumb2.td (revision 228379) @@ -1,4022 +1,4018 @@ //===- ARMInstrThumb2.td - Thumb2 support for ARM -------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file describes the Thumb2 instruction set. // //===----------------------------------------------------------------------===// // IT block predicate field def it_pred_asmoperand : AsmOperandClass { let Name = "ITCondCode"; let ParserMethod = "parseITCondCode"; } def it_pred : Operand { let PrintMethod = "printMandatoryPredicateOperand"; let ParserMatchClass = it_pred_asmoperand; } // IT block condition mask def it_mask_asmoperand : AsmOperandClass { let Name = "ITMask"; } def it_mask : Operand { let PrintMethod = "printThumbITMask"; let ParserMatchClass = it_mask_asmoperand; } // t2_shift_imm: An integer that encodes a shift amount and the type of shift // (asr or lsl). The 6-bit immediate encodes as: // {5} 0 ==> lsl // 1 asr // {4-0} imm5 shift amount. // asr #32 not allowed def t2_shift_imm : Operand { let PrintMethod = "printShiftImmOperand"; let ParserMatchClass = ShifterImmAsmOperand; let DecoderMethod = "DecodeT2ShifterImmOperand"; } // Shifted operands. No register controlled shifts for Thumb2. // Note: We do not support rrx shifted operands yet. def t2_so_reg : Operand, // reg imm ComplexPattern { let EncoderMethod = "getT2SORegOpValue"; let PrintMethod = "printT2SOOperand"; let DecoderMethod = "DecodeSORegImmOperand"; let ParserMatchClass = ShiftedImmAsmOperand; let MIOperandInfo = (ops rGPR, i32imm); } // t2_so_imm_not_XFORM - Return the complement of a t2_so_imm value def t2_so_imm_not_XFORM : SDNodeXFormgetTargetConstant(~((uint32_t)N->getZExtValue()), MVT::i32); }]>; // t2_so_imm_neg_XFORM - Return the negation of a t2_so_imm value def t2_so_imm_neg_XFORM : SDNodeXFormgetTargetConstant(-((int)N->getZExtValue()), MVT::i32); }]>; // t2_so_imm - Match a 32-bit immediate operand, which is an // 8-bit immediate rotated by an arbitrary number of bits, or an 8-bit // immediate splatted into multiple bytes of the word. def t2_so_imm_asmoperand : AsmOperandClass { let Name = "T2SOImm"; } def t2_so_imm : Operand, ImmLeaf { let ParserMatchClass = t2_so_imm_asmoperand; let EncoderMethod = "getT2SOImmOpValue"; let DecoderMethod = "DecodeT2SOImm"; } // t2_so_imm_not - Match an immediate that is a complement // of a t2_so_imm. def t2_so_imm_not : Operand, PatLeaf<(imm), [{ return ARM_AM::getT2SOImmVal(~((uint32_t)N->getZExtValue())) != -1; }], t2_so_imm_not_XFORM>; // t2_so_imm_neg - Match an immediate that is a negation of a t2_so_imm. def t2_so_imm_neg : Operand, PatLeaf<(imm), [{ return ARM_AM::getT2SOImmVal(-((uint32_t)N->getZExtValue())) != -1; }], t2_so_imm_neg_XFORM>; /// imm0_4095 predicate - True if the 32-bit immediate is in the range [0.4095]. def imm0_4095 : Operand, ImmLeaf= 0 && Imm < 4096; }]>; def imm0_4095_neg : PatLeaf<(i32 imm), [{ return (uint32_t)(-N->getZExtValue()) < 4096; }], imm_neg_XFORM>; def imm0_255_neg : PatLeaf<(i32 imm), [{ return (uint32_t)(-N->getZExtValue()) < 255; }], imm_neg_XFORM>; def imm0_255_not : PatLeaf<(i32 imm), [{ return (uint32_t)(~N->getZExtValue()) < 255; }], imm_comp_XFORM>; def lo5AllOne : PatLeaf<(i32 imm), [{ // Returns true if all low 5-bits are 1. return (((uint32_t)N->getZExtValue()) & 0x1FUL) == 0x1FUL; }]>; // Define Thumb2 specific addressing modes. // t2addrmode_imm12 := reg + imm12 def t2addrmode_imm12_asmoperand : AsmOperandClass {let Name="MemUImm12Offset";} def t2addrmode_imm12 : Operand, ComplexPattern { let PrintMethod = "printAddrModeImm12Operand"; let EncoderMethod = "getAddrModeImm12OpValue"; let DecoderMethod = "DecodeT2AddrModeImm12"; let ParserMatchClass = t2addrmode_imm12_asmoperand; let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm); } // t2ldrlabel := imm12 def t2ldrlabel : Operand { let EncoderMethod = "getAddrModeImm12OpValue"; let PrintMethod = "printT2LdrLabelOperand"; } // ADR instruction labels. def t2adrlabel : Operand { let EncoderMethod = "getT2AdrLabelOpValue"; } // t2addrmode_posimm8 := reg + imm8 def MemPosImm8OffsetAsmOperand : AsmOperandClass {let Name="MemPosImm8Offset";} def t2addrmode_posimm8 : Operand { let PrintMethod = "printT2AddrModeImm8Operand"; let EncoderMethod = "getT2AddrModeImm8OpValue"; let DecoderMethod = "DecodeT2AddrModeImm8"; let ParserMatchClass = MemPosImm8OffsetAsmOperand; let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm); } // t2addrmode_negimm8 := reg - imm8 def MemNegImm8OffsetAsmOperand : AsmOperandClass {let Name="MemNegImm8Offset";} def t2addrmode_negimm8 : Operand, ComplexPattern { let PrintMethod = "printT2AddrModeImm8Operand"; let EncoderMethod = "getT2AddrModeImm8OpValue"; let DecoderMethod = "DecodeT2AddrModeImm8"; let ParserMatchClass = MemNegImm8OffsetAsmOperand; let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm); } // t2addrmode_imm8 := reg +/- imm8 def MemImm8OffsetAsmOperand : AsmOperandClass { let Name = "MemImm8Offset"; } def t2addrmode_imm8 : Operand, ComplexPattern { let PrintMethod = "printT2AddrModeImm8Operand"; let EncoderMethod = "getT2AddrModeImm8OpValue"; let DecoderMethod = "DecodeT2AddrModeImm8"; let ParserMatchClass = MemImm8OffsetAsmOperand; let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm); } def t2am_imm8_offset : Operand, ComplexPattern { let PrintMethod = "printT2AddrModeImm8OffsetOperand"; let EncoderMethod = "getT2AddrModeImm8OffsetOpValue"; let DecoderMethod = "DecodeT2Imm8"; } // t2addrmode_imm8s4 := reg +/- (imm8 << 2) def MemImm8s4OffsetAsmOperand : AsmOperandClass {let Name = "MemImm8s4Offset";} def t2addrmode_imm8s4 : Operand { let PrintMethod = "printT2AddrModeImm8s4Operand"; let EncoderMethod = "getT2AddrModeImm8s4OpValue"; let DecoderMethod = "DecodeT2AddrModeImm8s4"; let ParserMatchClass = MemImm8s4OffsetAsmOperand; let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm); } def t2am_imm8s4_offset_asmoperand : AsmOperandClass { let Name = "Imm8s4"; } def t2am_imm8s4_offset : Operand { let PrintMethod = "printT2AddrModeImm8s4OffsetOperand"; let EncoderMethod = "getT2Imm8s4OpValue"; let DecoderMethod = "DecodeT2Imm8S4"; } // t2addrmode_imm0_1020s4 := reg + (imm8 << 2) def MemImm0_1020s4OffsetAsmOperand : AsmOperandClass { let Name = "MemImm0_1020s4Offset"; } def t2addrmode_imm0_1020s4 : Operand { let PrintMethod = "printT2AddrModeImm0_1020s4Operand"; let EncoderMethod = "getT2AddrModeImm0_1020s4OpValue"; let DecoderMethod = "DecodeT2AddrModeImm0_1020s4"; let ParserMatchClass = MemImm0_1020s4OffsetAsmOperand; let MIOperandInfo = (ops GPRnopc:$base, i32imm:$offsimm); } // t2addrmode_so_reg := reg + (reg << imm2) def t2addrmode_so_reg_asmoperand : AsmOperandClass {let Name="T2MemRegOffset";} def t2addrmode_so_reg : Operand, ComplexPattern { let PrintMethod = "printT2AddrModeSoRegOperand"; let EncoderMethod = "getT2AddrModeSORegOpValue"; let DecoderMethod = "DecodeT2AddrModeSOReg"; let ParserMatchClass = t2addrmode_so_reg_asmoperand; let MIOperandInfo = (ops GPR:$base, rGPR:$offsreg, i32imm:$offsimm); } // Addresses for the TBB/TBH instructions. def addrmode_tbb_asmoperand : AsmOperandClass { let Name = "MemTBB"; } def addrmode_tbb : Operand { let PrintMethod = "printAddrModeTBB"; let ParserMatchClass = addrmode_tbb_asmoperand; let MIOperandInfo = (ops GPR:$Rn, rGPR:$Rm); } def addrmode_tbh_asmoperand : AsmOperandClass { let Name = "MemTBH"; } def addrmode_tbh : Operand { let PrintMethod = "printAddrModeTBH"; let ParserMatchClass = addrmode_tbh_asmoperand; let MIOperandInfo = (ops GPR:$Rn, rGPR:$Rm); } //===----------------------------------------------------------------------===// // Multiclass helpers... // class T2OneRegImm pattern> : T2I { bits<4> Rd; bits<12> imm; let Inst{11-8} = Rd; let Inst{26} = imm{11}; let Inst{14-12} = imm{10-8}; let Inst{7-0} = imm{7-0}; } class T2sOneRegImm pattern> : T2sI { bits<4> Rd; bits<4> Rn; bits<12> imm; let Inst{11-8} = Rd; let Inst{26} = imm{11}; let Inst{14-12} = imm{10-8}; let Inst{7-0} = imm{7-0}; } class T2OneRegCmpImm pattern> : T2I { bits<4> Rn; bits<12> imm; let Inst{19-16} = Rn; let Inst{26} = imm{11}; let Inst{14-12} = imm{10-8}; let Inst{7-0} = imm{7-0}; } class T2OneRegShiftedReg pattern> : T2I { bits<4> Rd; bits<12> ShiftedRm; let Inst{11-8} = Rd; let Inst{3-0} = ShiftedRm{3-0}; let Inst{5-4} = ShiftedRm{6-5}; let Inst{14-12} = ShiftedRm{11-9}; let Inst{7-6} = ShiftedRm{8-7}; } class T2sOneRegShiftedReg pattern> : T2sI { bits<4> Rd; bits<12> ShiftedRm; let Inst{11-8} = Rd; let Inst{3-0} = ShiftedRm{3-0}; let Inst{5-4} = ShiftedRm{6-5}; let Inst{14-12} = ShiftedRm{11-9}; let Inst{7-6} = ShiftedRm{8-7}; } class T2OneRegCmpShiftedReg pattern> : T2I { bits<4> Rn; bits<12> ShiftedRm; let Inst{19-16} = Rn; let Inst{3-0} = ShiftedRm{3-0}; let Inst{5-4} = ShiftedRm{6-5}; let Inst{14-12} = ShiftedRm{11-9}; let Inst{7-6} = ShiftedRm{8-7}; } class T2TwoReg pattern> : T2I { bits<4> Rd; bits<4> Rm; let Inst{11-8} = Rd; let Inst{3-0} = Rm; } class T2sTwoReg pattern> : T2sI { bits<4> Rd; bits<4> Rm; let Inst{11-8} = Rd; let Inst{3-0} = Rm; } class T2TwoRegCmp pattern> : T2I { bits<4> Rn; bits<4> Rm; let Inst{19-16} = Rn; let Inst{3-0} = Rm; } class T2TwoRegImm pattern> : T2I { bits<4> Rd; bits<4> Rn; bits<12> imm; let Inst{11-8} = Rd; let Inst{19-16} = Rn; let Inst{26} = imm{11}; let Inst{14-12} = imm{10-8}; let Inst{7-0} = imm{7-0}; } class T2sTwoRegImm pattern> : T2sI { bits<4> Rd; bits<4> Rn; bits<12> imm; let Inst{11-8} = Rd; let Inst{19-16} = Rn; let Inst{26} = imm{11}; let Inst{14-12} = imm{10-8}; let Inst{7-0} = imm{7-0}; } class T2TwoRegShiftImm pattern> : T2I { bits<4> Rd; bits<4> Rm; bits<5> imm; let Inst{11-8} = Rd; let Inst{3-0} = Rm; let Inst{14-12} = imm{4-2}; let Inst{7-6} = imm{1-0}; } class T2sTwoRegShiftImm pattern> : T2sI { bits<4> Rd; bits<4> Rm; bits<5> imm; let Inst{11-8} = Rd; let Inst{3-0} = Rm; let Inst{14-12} = imm{4-2}; let Inst{7-6} = imm{1-0}; } class T2ThreeReg pattern> : T2I { bits<4> Rd; bits<4> Rn; bits<4> Rm; let Inst{11-8} = Rd; let Inst{19-16} = Rn; let Inst{3-0} = Rm; } class T2sThreeReg pattern> : T2sI { bits<4> Rd; bits<4> Rn; bits<4> Rm; let Inst{11-8} = Rd; let Inst{19-16} = Rn; let Inst{3-0} = Rm; } class T2TwoRegShiftedReg pattern> : T2I { bits<4> Rd; bits<4> Rn; bits<12> ShiftedRm; let Inst{11-8} = Rd; let Inst{19-16} = Rn; let Inst{3-0} = ShiftedRm{3-0}; let Inst{5-4} = ShiftedRm{6-5}; let Inst{14-12} = ShiftedRm{11-9}; let Inst{7-6} = ShiftedRm{8-7}; } class T2sTwoRegShiftedReg pattern> : T2sI { bits<4> Rd; bits<4> Rn; bits<12> ShiftedRm; let Inst{11-8} = Rd; let Inst{19-16} = Rn; let Inst{3-0} = ShiftedRm{3-0}; let Inst{5-4} = ShiftedRm{6-5}; let Inst{14-12} = ShiftedRm{11-9}; let Inst{7-6} = ShiftedRm{8-7}; } class T2FourReg pattern> : T2I { bits<4> Rd; bits<4> Rn; bits<4> Rm; bits<4> Ra; let Inst{19-16} = Rn; let Inst{15-12} = Ra; let Inst{11-8} = Rd; let Inst{3-0} = Rm; } class T2MulLong opc22_20, bits<4> opc7_4, dag oops, dag iops, InstrItinClass itin, string opc, string asm, list pattern> : T2I { bits<4> RdLo; bits<4> RdHi; bits<4> Rn; bits<4> Rm; let Inst{31-23} = 0b111110111; let Inst{22-20} = opc22_20; let Inst{19-16} = Rn; let Inst{15-12} = RdLo; let Inst{11-8} = RdHi; let Inst{7-4} = opc7_4; let Inst{3-0} = Rm; } /// T2I_bin_irs - Defines a set of (op reg, {so_imm|r|so_reg}) patterns for a /// binary operation that produces a value. These are predicable and can be /// changed to modify CPSR. multiclass T2I_bin_irs opcod, string opc, InstrItinClass iii, InstrItinClass iir, InstrItinClass iis, PatFrag opnode, string baseOpc, bit Commutable = 0, string wide = ""> { // shifted imm def ri : T2sTwoRegImm< (outs rGPR:$Rd), (ins rGPR:$Rn, t2_so_imm:$imm), iii, opc, "\t$Rd, $Rn, $imm", [(set rGPR:$Rd, (opnode rGPR:$Rn, t2_so_imm:$imm))]> { let Inst{31-27} = 0b11110; let Inst{25} = 0; let Inst{24-21} = opcod; let Inst{15} = 0; } // register def rr : T2sThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), iir, opc, !strconcat(wide, "\t$Rd, $Rn, $Rm"), [(set rGPR:$Rd, (opnode rGPR:$Rn, rGPR:$Rm))]> { let isCommutable = Commutable; let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = opcod; let Inst{14-12} = 0b000; // imm3 let Inst{7-6} = 0b00; // imm2 let Inst{5-4} = 0b00; // type } // shifted register def rs : T2sTwoRegShiftedReg< (outs rGPR:$Rd), (ins rGPR:$Rn, t2_so_reg:$ShiftedRm), iis, opc, !strconcat(wide, "\t$Rd, $Rn, $ShiftedRm"), [(set rGPR:$Rd, (opnode rGPR:$Rn, t2_so_reg:$ShiftedRm))]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = opcod; } // Assembly aliases for optional destination operand when it's the same // as the source operand. def : t2InstAlias(!strconcat(baseOpc, "ri")) rGPR:$Rdn, rGPR:$Rdn, t2_so_imm:$imm, pred:$p, cc_out:$s)>; def : t2InstAlias(!strconcat(baseOpc, "rr")) rGPR:$Rdn, rGPR:$Rdn, rGPR:$Rm, pred:$p, cc_out:$s)>; def : t2InstAlias(!strconcat(baseOpc, "rs")) rGPR:$Rdn, rGPR:$Rdn, t2_so_reg:$shift, pred:$p, cc_out:$s)>; } /// T2I_bin_w_irs - Same as T2I_bin_irs except these operations need // the ".w" suffix to indicate that they are wide. multiclass T2I_bin_w_irs opcod, string opc, InstrItinClass iii, InstrItinClass iir, InstrItinClass iis, PatFrag opnode, string baseOpc, bit Commutable = 0> : T2I_bin_irs { // Assembler aliases w/o the ".w" suffix. def : t2InstAlias(!strconcat(baseOpc, "rr")) rGPR:$Rd, rGPR:$Rn, rGPR:$Rm, pred:$p, cc_out:$s)>; def : t2InstAlias(!strconcat(baseOpc, "rs")) rGPR:$Rd, rGPR:$Rn, t2_so_reg:$shift, pred:$p, cc_out:$s)>; // and with the optional destination operand, too. def : t2InstAlias(!strconcat(baseOpc, "rr")) rGPR:$Rdn, rGPR:$Rdn, rGPR:$Rm, pred:$p, cc_out:$s)>; def : t2InstAlias(!strconcat(baseOpc, "rs")) rGPR:$Rdn, rGPR:$Rdn, t2_so_reg:$shift, pred:$p, cc_out:$s)>; } /// T2I_rbin_is - Same as T2I_bin_irs except the order of operands are /// reversed. The 'rr' form is only defined for the disassembler; for codegen /// it is equivalent to the T2I_bin_irs counterpart. multiclass T2I_rbin_irs opcod, string opc, PatFrag opnode> { // shifted imm def ri : T2sTwoRegImm< (outs rGPR:$Rd), (ins rGPR:$Rn, t2_so_imm:$imm), IIC_iALUi, opc, ".w\t$Rd, $Rn, $imm", [(set rGPR:$Rd, (opnode t2_so_imm:$imm, rGPR:$Rn))]> { let Inst{31-27} = 0b11110; let Inst{25} = 0; let Inst{24-21} = opcod; let Inst{15} = 0; } // register def rr : T2sThreeReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iALUr, opc, "\t$Rd, $Rn, $Rm", [/* For disassembly only; pattern left blank */]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = opcod; let Inst{14-12} = 0b000; // imm3 let Inst{7-6} = 0b00; // imm2 let Inst{5-4} = 0b00; // type } // shifted register def rs : T2sTwoRegShiftedReg< (outs rGPR:$Rd), (ins rGPR:$Rn, t2_so_reg:$ShiftedRm), IIC_iALUsir, opc, "\t$Rd, $Rn, $ShiftedRm", [(set rGPR:$Rd, (opnode t2_so_reg:$ShiftedRm, rGPR:$Rn))]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = opcod; } } /// T2I_bin_s_irs - Similar to T2I_bin_irs except it sets the 's' bit so the /// instruction modifies the CPSR register. /// /// These opcodes will be converted to the real non-S opcodes by /// AdjustInstrPostInstrSelection after giving then an optional CPSR operand. let hasPostISelHook = 1, isCodeGenOnly = 1, isPseudo = 1, Defs = [CPSR] in { multiclass T2I_bin_s_irs opcod, string opc, InstrItinClass iii, InstrItinClass iir, InstrItinClass iis, PatFrag opnode, bit Commutable = 0> { // shifted imm def ri : T2sTwoRegImm< (outs rGPR:$Rd), (ins GPR:$Rn, t2_so_imm:$imm), iii, opc, ".w\t$Rd, $Rn, $imm", [(set rGPR:$Rd, CPSR, (opnode GPR:$Rn, t2_so_imm:$imm))]>; // register def rr : T2sThreeReg< (outs rGPR:$Rd), (ins GPR:$Rn, rGPR:$Rm), iir, opc, ".w\t$Rd, $Rn, $Rm", [(set rGPR:$Rd, CPSR, (opnode GPR:$Rn, rGPR:$Rm))]>; // shifted register def rs : T2sTwoRegShiftedReg< (outs rGPR:$Rd), (ins GPR:$Rn, t2_so_reg:$ShiftedRm), iis, opc, ".w\t$Rd, $Rn, $ShiftedRm", [(set rGPR:$Rd, CPSR, (opnode GPR:$Rn, t2_so_reg:$ShiftedRm))]>; } } /// T2I_bin_ii12rs - Defines a set of (op reg, {so_imm|imm0_4095|r|so_reg}) /// patterns for a binary operation that produces a value. multiclass T2I_bin_ii12rs op23_21, string opc, PatFrag opnode, bit Commutable = 0> { // shifted imm // The register-immediate version is re-materializable. This is useful // in particular for taking the address of a local. let isReMaterializable = 1 in { def ri : T2sTwoRegImm< (outs GPRnopc:$Rd), (ins GPRnopc:$Rn, t2_so_imm:$imm), IIC_iALUi, opc, ".w\t$Rd, $Rn, $imm", [(set GPRnopc:$Rd, (opnode GPRnopc:$Rn, t2_so_imm:$imm))]> { let Inst{31-27} = 0b11110; let Inst{25} = 0; let Inst{24} = 1; let Inst{23-21} = op23_21; let Inst{15} = 0; } } // 12-bit imm def ri12 : T2I< (outs GPRnopc:$Rd), (ins GPR:$Rn, imm0_4095:$imm), IIC_iALUi, !strconcat(opc, "w"), "\t$Rd, $Rn, $imm", [(set GPRnopc:$Rd, (opnode GPR:$Rn, imm0_4095:$imm))]> { bits<4> Rd; bits<4> Rn; bits<12> imm; let Inst{31-27} = 0b11110; let Inst{26} = imm{11}; let Inst{25-24} = 0b10; let Inst{23-21} = op23_21; let Inst{20} = 0; // The S bit. let Inst{19-16} = Rn; let Inst{15} = 0; let Inst{14-12} = imm{10-8}; let Inst{11-8} = Rd; let Inst{7-0} = imm{7-0}; } // register def rr : T2sThreeReg<(outs GPRnopc:$Rd), (ins GPRnopc:$Rn, rGPR:$Rm), IIC_iALUr, opc, ".w\t$Rd, $Rn, $Rm", [(set GPRnopc:$Rd, (opnode GPRnopc:$Rn, rGPR:$Rm))]> { let isCommutable = Commutable; let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24} = 1; let Inst{23-21} = op23_21; let Inst{14-12} = 0b000; // imm3 let Inst{7-6} = 0b00; // imm2 let Inst{5-4} = 0b00; // type } // shifted register def rs : T2sTwoRegShiftedReg< (outs GPRnopc:$Rd), (ins GPRnopc:$Rn, t2_so_reg:$ShiftedRm), IIC_iALUsi, opc, ".w\t$Rd, $Rn, $ShiftedRm", [(set GPRnopc:$Rd, (opnode GPRnopc:$Rn, t2_so_reg:$ShiftedRm))]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24} = 1; let Inst{23-21} = op23_21; } } /// T2I_adde_sube_irs - Defines a set of (op reg, {so_imm|r|so_reg}) patterns /// for a binary operation that produces a value and use the carry /// bit. It's not predicable. let Defs = [CPSR], Uses = [CPSR] in { multiclass T2I_adde_sube_irs opcod, string opc, PatFrag opnode, bit Commutable = 0> { // shifted imm def ri : T2sTwoRegImm<(outs rGPR:$Rd), (ins rGPR:$Rn, t2_so_imm:$imm), IIC_iALUi, opc, "\t$Rd, $Rn, $imm", [(set rGPR:$Rd, CPSR, (opnode rGPR:$Rn, t2_so_imm:$imm, CPSR))]>, Requires<[IsThumb2]> { let Inst{31-27} = 0b11110; let Inst{25} = 0; let Inst{24-21} = opcod; let Inst{15} = 0; } // register def rr : T2sThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iALUr, opc, ".w\t$Rd, $Rn, $Rm", [(set rGPR:$Rd, CPSR, (opnode rGPR:$Rn, rGPR:$Rm, CPSR))]>, Requires<[IsThumb2]> { let isCommutable = Commutable; let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = opcod; let Inst{14-12} = 0b000; // imm3 let Inst{7-6} = 0b00; // imm2 let Inst{5-4} = 0b00; // type } // shifted register def rs : T2sTwoRegShiftedReg< (outs rGPR:$Rd), (ins rGPR:$Rn, t2_so_reg:$ShiftedRm), IIC_iALUsi, opc, ".w\t$Rd, $Rn, $ShiftedRm", [(set rGPR:$Rd, CPSR, (opnode rGPR:$Rn, t2_so_reg:$ShiftedRm, CPSR))]>, Requires<[IsThumb2]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = opcod; } } } /// T2I_rbin_s_is - Same as T2I_rbin_irs except sets 's' bit and the register /// version is not needed since this is only for codegen. /// /// These opcodes will be converted to the real non-S opcodes by /// AdjustInstrPostInstrSelection after giving then an optional CPSR operand. let hasPostISelHook = 1, isCodeGenOnly = 1, isPseudo = 1, Defs = [CPSR] in { multiclass T2I_rbin_s_is opcod, string opc, PatFrag opnode> { // shifted imm def ri : T2sTwoRegImm< (outs rGPR:$Rd), (ins rGPR:$Rn, t2_so_imm:$imm), IIC_iALUi, opc, ".w\t$Rd, $Rn, $imm", [(set rGPR:$Rd, CPSR, (opnode t2_so_imm:$imm, rGPR:$Rn))]>; // shifted register def rs : T2sTwoRegShiftedReg< (outs rGPR:$Rd), (ins rGPR:$Rn, t2_so_reg:$ShiftedRm), IIC_iALUsi, opc, "\t$Rd, $Rn, $ShiftedRm", [(set rGPR:$Rd, CPSR, (opnode t2_so_reg:$ShiftedRm, rGPR:$Rn))]>; } } /// T2I_sh_ir - Defines a set of (op reg, {so_imm|r}) patterns for a shift / // rotate operation that produces a value. multiclass T2I_sh_ir opcod, string opc, Operand ty, PatFrag opnode, string baseOpc> { // 5-bit imm def ri : T2sTwoRegShiftImm< (outs rGPR:$Rd), (ins rGPR:$Rm, ty:$imm), IIC_iMOVsi, opc, ".w\t$Rd, $Rm, $imm", [(set rGPR:$Rd, (opnode rGPR:$Rm, (i32 ty:$imm)))]> { let Inst{31-27} = 0b11101; let Inst{26-21} = 0b010010; let Inst{19-16} = 0b1111; // Rn let Inst{5-4} = opcod; } // register def rr : T2sThreeReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMOVsr, opc, ".w\t$Rd, $Rn, $Rm", [(set rGPR:$Rd, (opnode rGPR:$Rn, rGPR:$Rm))]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0100; let Inst{22-21} = opcod; let Inst{15-12} = 0b1111; let Inst{7-4} = 0b0000; } // Optional destination register def : t2InstAlias(!strconcat(baseOpc, "ri")) rGPR:$Rdn, rGPR:$Rdn, ty:$imm, pred:$p, cc_out:$s)>; def : t2InstAlias(!strconcat(baseOpc, "rr")) rGPR:$Rdn, rGPR:$Rdn, rGPR:$Rm, pred:$p, cc_out:$s)>; // Assembler aliases w/o the ".w" suffix. def : t2InstAlias(!strconcat(baseOpc, "ri")) rGPR:$Rd, rGPR:$Rn, ty:$imm, pred:$p, cc_out:$s)>; def : t2InstAlias(!strconcat(baseOpc, "rr")) rGPR:$Rd, rGPR:$Rn, rGPR:$Rm, pred:$p, cc_out:$s)>; // and with the optional destination operand, too. def : t2InstAlias(!strconcat(baseOpc, "ri")) rGPR:$Rdn, rGPR:$Rdn, ty:$imm, pred:$p, cc_out:$s)>; def : t2InstAlias(!strconcat(baseOpc, "rr")) rGPR:$Rdn, rGPR:$Rdn, rGPR:$Rm, pred:$p, cc_out:$s)>; } /// T2I_cmp_irs - Defines a set of (op r, {so_imm|r|so_reg}) cmp / test /// patterns. Similar to T2I_bin_irs except the instruction does not produce /// a explicit result, only implicitly set CPSR. multiclass T2I_cmp_irs opcod, string opc, InstrItinClass iii, InstrItinClass iir, InstrItinClass iis, PatFrag opnode, string baseOpc> { let isCompare = 1, Defs = [CPSR] in { // shifted imm def ri : T2OneRegCmpImm< (outs), (ins GPRnopc:$Rn, t2_so_imm:$imm), iii, opc, ".w\t$Rn, $imm", [(opnode GPRnopc:$Rn, t2_so_imm:$imm)]> { let Inst{31-27} = 0b11110; let Inst{25} = 0; let Inst{24-21} = opcod; let Inst{20} = 1; // The S bit. let Inst{15} = 0; let Inst{11-8} = 0b1111; // Rd } // register def rr : T2TwoRegCmp< (outs), (ins GPRnopc:$Rn, rGPR:$Rm), iir, opc, ".w\t$Rn, $Rm", [(opnode GPRnopc:$Rn, rGPR:$Rm)]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = opcod; let Inst{20} = 1; // The S bit. let Inst{14-12} = 0b000; // imm3 let Inst{11-8} = 0b1111; // Rd let Inst{7-6} = 0b00; // imm2 let Inst{5-4} = 0b00; // type } // shifted register def rs : T2OneRegCmpShiftedReg< (outs), (ins GPRnopc:$Rn, t2_so_reg:$ShiftedRm), iis, opc, ".w\t$Rn, $ShiftedRm", [(opnode GPRnopc:$Rn, t2_so_reg:$ShiftedRm)]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = opcod; let Inst{20} = 1; // The S bit. let Inst{11-8} = 0b1111; // Rd } } // Assembler aliases w/o the ".w" suffix. // No alias here for 'rr' version as not all instantiations of this // multiclass want one (CMP in particular, does not). def : t2InstAlias(!strconcat(baseOpc, "ri")) GPRnopc:$Rn, t2_so_imm:$imm, pred:$p)>; def : t2InstAlias(!strconcat(baseOpc, "rs")) GPRnopc:$Rn, t2_so_reg:$shift, pred:$p)>; } /// T2I_ld - Defines a set of (op r, {imm12|imm8|so_reg}) load patterns. multiclass T2I_ld opcod, string opc, InstrItinClass iii, InstrItinClass iis, RegisterClass target, PatFrag opnode> { def i12 : T2Ii12<(outs target:$Rt), (ins t2addrmode_imm12:$addr), iii, opc, ".w\t$Rt, $addr", [(set target:$Rt, (opnode t2addrmode_imm12:$addr))]> { bits<4> Rt; bits<17> addr; let Inst{31-25} = 0b1111100; let Inst{24} = signed; let Inst{23} = 1; let Inst{22-21} = opcod; let Inst{20} = 1; // load let Inst{19-16} = addr{16-13}; // Rn let Inst{15-12} = Rt; let Inst{11-0} = addr{11-0}; // imm } def i8 : T2Ii8 <(outs target:$Rt), (ins t2addrmode_negimm8:$addr), iii, opc, "\t$Rt, $addr", [(set target:$Rt, (opnode t2addrmode_negimm8:$addr))]> { bits<4> Rt; bits<13> addr; let Inst{31-27} = 0b11111; let Inst{26-25} = 0b00; let Inst{24} = signed; let Inst{23} = 0; let Inst{22-21} = opcod; let Inst{20} = 1; // load let Inst{19-16} = addr{12-9}; // Rn let Inst{15-12} = Rt; let Inst{11} = 1; // Offset: index==TRUE, wback==FALSE let Inst{10} = 1; // The P bit. let Inst{9} = addr{8}; // U let Inst{8} = 0; // The W bit. let Inst{7-0} = addr{7-0}; // imm } def s : T2Iso <(outs target:$Rt), (ins t2addrmode_so_reg:$addr), iis, opc, ".w\t$Rt, $addr", [(set target:$Rt, (opnode t2addrmode_so_reg:$addr))]> { let Inst{31-27} = 0b11111; let Inst{26-25} = 0b00; let Inst{24} = signed; let Inst{23} = 0; let Inst{22-21} = opcod; let Inst{20} = 1; // load let Inst{11-6} = 0b000000; bits<4> Rt; let Inst{15-12} = Rt; bits<10> addr; let Inst{19-16} = addr{9-6}; // Rn let Inst{3-0} = addr{5-2}; // Rm let Inst{5-4} = addr{1-0}; // imm let DecoderMethod = "DecodeT2LoadShift"; } // FIXME: Is the pci variant actually needed? def pci : T2Ipc <(outs target:$Rt), (ins t2ldrlabel:$addr), iii, opc, ".w\t$Rt, $addr", [(set target:$Rt, (opnode (ARMWrapper tconstpool:$addr)))]> { let isReMaterializable = 1; let Inst{31-27} = 0b11111; let Inst{26-25} = 0b00; let Inst{24} = signed; let Inst{23} = ?; // add = (U == '1') let Inst{22-21} = opcod; let Inst{20} = 1; // load let Inst{19-16} = 0b1111; // Rn bits<4> Rt; bits<12> addr; let Inst{15-12} = Rt{3-0}; let Inst{11-0} = addr{11-0}; } } /// T2I_st - Defines a set of (op r, {imm12|imm8|so_reg}) store patterns. multiclass T2I_st opcod, string opc, InstrItinClass iii, InstrItinClass iis, RegisterClass target, PatFrag opnode> { def i12 : T2Ii12<(outs), (ins target:$Rt, t2addrmode_imm12:$addr), iii, opc, ".w\t$Rt, $addr", [(opnode target:$Rt, t2addrmode_imm12:$addr)]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0001; let Inst{22-21} = opcod; let Inst{20} = 0; // !load bits<4> Rt; let Inst{15-12} = Rt; bits<17> addr; let addr{12} = 1; // add = TRUE let Inst{19-16} = addr{16-13}; // Rn let Inst{23} = addr{12}; // U let Inst{11-0} = addr{11-0}; // imm } def i8 : T2Ii8 <(outs), (ins target:$Rt, t2addrmode_negimm8:$addr), iii, opc, "\t$Rt, $addr", [(opnode target:$Rt, t2addrmode_negimm8:$addr)]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0000; let Inst{22-21} = opcod; let Inst{20} = 0; // !load let Inst{11} = 1; // Offset: index==TRUE, wback==FALSE let Inst{10} = 1; // The P bit. let Inst{8} = 0; // The W bit. bits<4> Rt; let Inst{15-12} = Rt; bits<13> addr; let Inst{19-16} = addr{12-9}; // Rn let Inst{9} = addr{8}; // U let Inst{7-0} = addr{7-0}; // imm } def s : T2Iso <(outs), (ins target:$Rt, t2addrmode_so_reg:$addr), iis, opc, ".w\t$Rt, $addr", [(opnode target:$Rt, t2addrmode_so_reg:$addr)]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0000; let Inst{22-21} = opcod; let Inst{20} = 0; // !load let Inst{11-6} = 0b000000; bits<4> Rt; let Inst{15-12} = Rt; bits<10> addr; let Inst{19-16} = addr{9-6}; // Rn let Inst{3-0} = addr{5-2}; // Rm let Inst{5-4} = addr{1-0}; // imm } } /// T2I_ext_rrot - A unary operation with two forms: one whose operand is a /// register and one whose operand is a register rotated by 8/16/24. class T2I_ext_rrot opcod, string opc, PatFrag opnode> : T2TwoReg<(outs rGPR:$Rd), (ins rGPR:$Rm, rot_imm:$rot), IIC_iEXTr, opc, ".w\t$Rd, $Rm$rot", [(set rGPR:$Rd, (opnode (rotr rGPR:$Rm, rot_imm:$rot)))]>, Requires<[IsThumb2]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0100; let Inst{22-20} = opcod; let Inst{19-16} = 0b1111; // Rn let Inst{15-12} = 0b1111; let Inst{7} = 1; bits<2> rot; let Inst{5-4} = rot{1-0}; // rotate } // UXTB16 - Requres T2ExtractPack, does not need the .w qualifier. class T2I_ext_rrot_uxtb16 opcod, string opc, PatFrag opnode> : T2TwoReg<(outs rGPR:$Rd), (ins rGPR:$Rm, rot_imm:$rot), IIC_iEXTr, opc, "\t$Rd, $Rm$rot", [(set rGPR:$Rd, (opnode (rotr rGPR:$Rm, rot_imm:$rot)))]>, Requires<[HasT2ExtractPack, IsThumb2]> { bits<2> rot; let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0100; let Inst{22-20} = opcod; let Inst{19-16} = 0b1111; // Rn let Inst{15-12} = 0b1111; let Inst{7} = 1; let Inst{5-4} = rot; } // SXTB16 - Requres T2ExtractPack, does not need the .w qualifier, no pattern // supported yet. class T2I_ext_rrot_sxtb16 opcod, string opc> : T2TwoReg<(outs rGPR:$Rd), (ins rGPR:$Rm, rot_imm:$rot), IIC_iEXTr, opc, "\t$Rd, $Rm$rot", []>, Requires<[IsThumb2, HasT2ExtractPack]> { bits<2> rot; let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0100; let Inst{22-20} = opcod; let Inst{19-16} = 0b1111; // Rn let Inst{15-12} = 0b1111; let Inst{7} = 1; let Inst{5-4} = rot; } /// T2I_exta_rrot - A binary operation with two forms: one whose operand is a /// register and one whose operand is a register rotated by 8/16/24. class T2I_exta_rrot opcod, string opc, PatFrag opnode> : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rot_imm:$rot), IIC_iEXTAsr, opc, "\t$Rd, $Rn, $Rm$rot", [(set rGPR:$Rd, (opnode rGPR:$Rn, (rotr rGPR:$Rm,rot_imm:$rot)))]>, Requires<[HasT2ExtractPack, IsThumb2]> { bits<2> rot; let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0100; let Inst{22-20} = opcod; let Inst{15-12} = 0b1111; let Inst{7} = 1; let Inst{5-4} = rot; } class T2I_exta_rrot_np opcod, string opc> : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm,rot_imm:$rot), IIC_iEXTAsr, opc, "\t$Rd, $Rn, $Rm$rot", []> { bits<2> rot; let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0100; let Inst{22-20} = opcod; let Inst{15-12} = 0b1111; let Inst{7} = 1; let Inst{5-4} = rot; } //===----------------------------------------------------------------------===// // Instructions //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// // Miscellaneous Instructions. // class T2PCOneRegImm pattern> : T2XI { bits<4> Rd; bits<12> label; let Inst{11-8} = Rd; let Inst{26} = label{11}; let Inst{14-12} = label{10-8}; let Inst{7-0} = label{7-0}; } // LEApcrel - Load a pc-relative address into a register without offending the // assembler. def t2ADR : T2PCOneRegImm<(outs rGPR:$Rd), (ins t2adrlabel:$addr, pred:$p), IIC_iALUi, "adr{$p}.w\t$Rd, $addr", []> { let Inst{31-27} = 0b11110; let Inst{25-24} = 0b10; // Inst{23:21} = '11' (add = FALSE) or '00' (add = TRUE) let Inst{22} = 0; let Inst{20} = 0; let Inst{19-16} = 0b1111; // Rn let Inst{15} = 0; bits<4> Rd; bits<13> addr; let Inst{11-8} = Rd; let Inst{23} = addr{12}; let Inst{21} = addr{12}; let Inst{26} = addr{11}; let Inst{14-12} = addr{10-8}; let Inst{7-0} = addr{7-0}; let DecoderMethod = "DecodeT2Adr"; } let neverHasSideEffects = 1, isReMaterializable = 1 in def t2LEApcrel : t2PseudoInst<(outs rGPR:$Rd), (ins i32imm:$label, pred:$p), 4, IIC_iALUi, []>; def t2LEApcrelJT : t2PseudoInst<(outs rGPR:$Rd), (ins i32imm:$label, nohash_imm:$id, pred:$p), 4, IIC_iALUi, []>; //===----------------------------------------------------------------------===// // Load / store Instructions. // // Load let canFoldAsLoad = 1, isReMaterializable = 1 in defm t2LDR : T2I_ld<0, 0b10, "ldr", IIC_iLoad_i, IIC_iLoad_si, GPR, UnOpFrag<(load node:$Src)>>; // Loads with zero extension defm t2LDRH : T2I_ld<0, 0b01, "ldrh", IIC_iLoad_bh_i, IIC_iLoad_bh_si, rGPR, UnOpFrag<(zextloadi16 node:$Src)>>; defm t2LDRB : T2I_ld<0, 0b00, "ldrb", IIC_iLoad_bh_i, IIC_iLoad_bh_si, rGPR, UnOpFrag<(zextloadi8 node:$Src)>>; // Loads with sign extension defm t2LDRSH : T2I_ld<1, 0b01, "ldrsh", IIC_iLoad_bh_i, IIC_iLoad_bh_si, rGPR, UnOpFrag<(sextloadi16 node:$Src)>>; defm t2LDRSB : T2I_ld<1, 0b00, "ldrsb", IIC_iLoad_bh_i, IIC_iLoad_bh_si, rGPR, UnOpFrag<(sextloadi8 node:$Src)>>; let mayLoad = 1, neverHasSideEffects = 1, hasExtraDefRegAllocReq = 1 in { // Load doubleword def t2LDRDi8 : T2Ii8s4<1, 0, 1, (outs rGPR:$Rt, rGPR:$Rt2), (ins t2addrmode_imm8s4:$addr), IIC_iLoad_d_i, "ldrd", "\t$Rt, $Rt2, $addr", "", []>; } // mayLoad = 1, neverHasSideEffects = 1, hasExtraDefRegAllocReq = 1 // zextload i1 -> zextload i8 def : T2Pat<(zextloadi1 t2addrmode_imm12:$addr), (t2LDRBi12 t2addrmode_imm12:$addr)>; def : T2Pat<(zextloadi1 t2addrmode_negimm8:$addr), (t2LDRBi8 t2addrmode_negimm8:$addr)>; def : T2Pat<(zextloadi1 t2addrmode_so_reg:$addr), (t2LDRBs t2addrmode_so_reg:$addr)>; def : T2Pat<(zextloadi1 (ARMWrapper tconstpool:$addr)), (t2LDRBpci tconstpool:$addr)>; // extload -> zextload // FIXME: Reduce the number of patterns by legalizing extload to zextload // earlier? def : T2Pat<(extloadi1 t2addrmode_imm12:$addr), (t2LDRBi12 t2addrmode_imm12:$addr)>; def : T2Pat<(extloadi1 t2addrmode_negimm8:$addr), (t2LDRBi8 t2addrmode_negimm8:$addr)>; def : T2Pat<(extloadi1 t2addrmode_so_reg:$addr), (t2LDRBs t2addrmode_so_reg:$addr)>; def : T2Pat<(extloadi1 (ARMWrapper tconstpool:$addr)), (t2LDRBpci tconstpool:$addr)>; def : T2Pat<(extloadi8 t2addrmode_imm12:$addr), (t2LDRBi12 t2addrmode_imm12:$addr)>; def : T2Pat<(extloadi8 t2addrmode_negimm8:$addr), (t2LDRBi8 t2addrmode_negimm8:$addr)>; def : T2Pat<(extloadi8 t2addrmode_so_reg:$addr), (t2LDRBs t2addrmode_so_reg:$addr)>; def : T2Pat<(extloadi8 (ARMWrapper tconstpool:$addr)), (t2LDRBpci tconstpool:$addr)>; def : T2Pat<(extloadi16 t2addrmode_imm12:$addr), (t2LDRHi12 t2addrmode_imm12:$addr)>; def : T2Pat<(extloadi16 t2addrmode_negimm8:$addr), (t2LDRHi8 t2addrmode_negimm8:$addr)>; def : T2Pat<(extloadi16 t2addrmode_so_reg:$addr), (t2LDRHs t2addrmode_so_reg:$addr)>; def : T2Pat<(extloadi16 (ARMWrapper tconstpool:$addr)), (t2LDRHpci tconstpool:$addr)>; // FIXME: The destination register of the loads and stores can't be PC, but // can be SP. We need another regclass (similar to rGPR) to represent // that. Not a pressing issue since these are selected manually, // not via pattern. // Indexed loads let mayLoad = 1, neverHasSideEffects = 1 in { def t2LDR_PRE : T2Ipreldst<0, 0b10, 1, 1, (outs GPR:$Rt, GPR:$Rn_wb), (ins t2addrmode_imm8:$addr), AddrModeT2_i8, IndexModePre, IIC_iLoad_iu, "ldr", "\t$Rt, $addr!", "$addr.base = $Rn_wb", []> { let AsmMatchConverter = "cvtLdWriteBackRegT2AddrModeImm8"; } def t2LDR_POST : T2Ipostldst<0, 0b10, 1, 0, (outs GPR:$Rt, GPR:$Rn_wb), (ins addr_offset_none:$Rn, t2am_imm8_offset:$offset), AddrModeT2_i8, IndexModePost, IIC_iLoad_iu, "ldr", "\t$Rt, $Rn$offset", "$Rn = $Rn_wb", []>; def t2LDRB_PRE : T2Ipreldst<0, 0b00, 1, 1, (outs GPR:$Rt, GPR:$Rn_wb), (ins t2addrmode_imm8:$addr), AddrModeT2_i8, IndexModePre, IIC_iLoad_bh_iu, "ldrb", "\t$Rt, $addr!", "$addr.base = $Rn_wb", []> { let AsmMatchConverter = "cvtLdWriteBackRegT2AddrModeImm8"; } def t2LDRB_POST : T2Ipostldst<0, 0b00, 1, 0, (outs GPR:$Rt, GPR:$Rn_wb), (ins addr_offset_none:$Rn, t2am_imm8_offset:$offset), AddrModeT2_i8, IndexModePost, IIC_iLoad_bh_iu, "ldrb", "\t$Rt, $Rn$offset", "$Rn = $Rn_wb", []>; def t2LDRH_PRE : T2Ipreldst<0, 0b01, 1, 1, (outs GPR:$Rt, GPR:$Rn_wb), (ins t2addrmode_imm8:$addr), AddrModeT2_i8, IndexModePre, IIC_iLoad_bh_iu, "ldrh", "\t$Rt, $addr!", "$addr.base = $Rn_wb", []> { let AsmMatchConverter = "cvtLdWriteBackRegT2AddrModeImm8"; } def t2LDRH_POST : T2Ipostldst<0, 0b01, 1, 0, (outs GPR:$Rt, GPR:$Rn_wb), (ins addr_offset_none:$Rn, t2am_imm8_offset:$offset), AddrModeT2_i8, IndexModePost, IIC_iLoad_bh_iu, "ldrh", "\t$Rt, $Rn$offset", "$Rn = $Rn_wb", []>; def t2LDRSB_PRE : T2Ipreldst<1, 0b00, 1, 1, (outs GPR:$Rt, GPR:$Rn_wb), (ins t2addrmode_imm8:$addr), AddrModeT2_i8, IndexModePre, IIC_iLoad_bh_iu, "ldrsb", "\t$Rt, $addr!", "$addr.base = $Rn_wb", []> { let AsmMatchConverter = "cvtLdWriteBackRegT2AddrModeImm8"; } def t2LDRSB_POST : T2Ipostldst<1, 0b00, 1, 0, (outs GPR:$Rt, GPR:$Rn_wb), (ins addr_offset_none:$Rn, t2am_imm8_offset:$offset), AddrModeT2_i8, IndexModePost, IIC_iLoad_bh_iu, "ldrsb", "\t$Rt, $Rn$offset", "$Rn = $Rn_wb", []>; def t2LDRSH_PRE : T2Ipreldst<1, 0b01, 1, 1, (outs GPR:$Rt, GPR:$Rn_wb), (ins t2addrmode_imm8:$addr), AddrModeT2_i8, IndexModePre, IIC_iLoad_bh_iu, "ldrsh", "\t$Rt, $addr!", "$addr.base = $Rn_wb", []> { let AsmMatchConverter = "cvtLdWriteBackRegT2AddrModeImm8"; } def t2LDRSH_POST : T2Ipostldst<1, 0b01, 1, 0, (outs GPR:$Rt, GPR:$Rn_wb), (ins addr_offset_none:$Rn, t2am_imm8_offset:$offset), AddrModeT2_i8, IndexModePost, IIC_iLoad_bh_iu, "ldrsh", "\t$Rt, $Rn$offset", "$Rn = $Rn_wb", []>; } // mayLoad = 1, neverHasSideEffects = 1 // LDRT, LDRBT, LDRHT, LDRSBT, LDRSHT all have offset mode (PUW=0b110). // Ref: A8.6.57 LDR (immediate, Thumb) Encoding T4 class T2IldT type, string opc, InstrItinClass ii> : T2Ii8<(outs rGPR:$Rt), (ins t2addrmode_posimm8:$addr), ii, opc, "\t$Rt, $addr", []> { bits<4> Rt; bits<13> addr; let Inst{31-27} = 0b11111; let Inst{26-25} = 0b00; let Inst{24} = signed; let Inst{23} = 0; let Inst{22-21} = type; let Inst{20} = 1; // load let Inst{19-16} = addr{12-9}; let Inst{15-12} = Rt; let Inst{11} = 1; let Inst{10-8} = 0b110; // PUW. let Inst{7-0} = addr{7-0}; } def t2LDRT : T2IldT<0, 0b10, "ldrt", IIC_iLoad_i>; def t2LDRBT : T2IldT<0, 0b00, "ldrbt", IIC_iLoad_bh_i>; def t2LDRHT : T2IldT<0, 0b01, "ldrht", IIC_iLoad_bh_i>; def t2LDRSBT : T2IldT<1, 0b00, "ldrsbt", IIC_iLoad_bh_i>; def t2LDRSHT : T2IldT<1, 0b01, "ldrsht", IIC_iLoad_bh_i>; // Store defm t2STR :T2I_st<0b10,"str", IIC_iStore_i, IIC_iStore_si, GPR, BinOpFrag<(store node:$LHS, node:$RHS)>>; defm t2STRB:T2I_st<0b00,"strb", IIC_iStore_bh_i, IIC_iStore_bh_si, rGPR, BinOpFrag<(truncstorei8 node:$LHS, node:$RHS)>>; defm t2STRH:T2I_st<0b01,"strh", IIC_iStore_bh_i, IIC_iStore_bh_si, rGPR, BinOpFrag<(truncstorei16 node:$LHS, node:$RHS)>>; // Store doubleword let mayLoad = 1, neverHasSideEffects = 1, hasExtraSrcRegAllocReq = 1 in def t2STRDi8 : T2Ii8s4<1, 0, 0, (outs), (ins GPR:$Rt, GPR:$Rt2, t2addrmode_imm8s4:$addr), IIC_iStore_d_r, "strd", "\t$Rt, $Rt2, $addr", "", []>; // Indexed stores def t2STR_PRE : T2Ipreldst<0, 0b10, 0, 1, (outs GPRnopc:$Rn_wb), (ins rGPR:$Rt, t2addrmode_imm8:$addr), AddrModeT2_i8, IndexModePre, IIC_iStore_iu, "str", "\t$Rt, $addr!", "$addr.base = $Rn_wb,@earlyclobber $Rn_wb", []> { let AsmMatchConverter = "cvtStWriteBackRegT2AddrModeImm8"; } def t2STRH_PRE : T2Ipreldst<0, 0b01, 0, 1, (outs GPRnopc:$Rn_wb), (ins rGPR:$Rt, t2addrmode_imm8:$addr), AddrModeT2_i8, IndexModePre, IIC_iStore_iu, "strh", "\t$Rt, $addr!", "$addr.base = $Rn_wb,@earlyclobber $Rn_wb", []> { let AsmMatchConverter = "cvtStWriteBackRegT2AddrModeImm8"; } def t2STRB_PRE : T2Ipreldst<0, 0b00, 0, 1, (outs GPRnopc:$Rn_wb), (ins rGPR:$Rt, t2addrmode_imm8:$addr), AddrModeT2_i8, IndexModePre, IIC_iStore_bh_iu, "strb", "\t$Rt, $addr!", "$addr.base = $Rn_wb,@earlyclobber $Rn_wb", []> { let AsmMatchConverter = "cvtStWriteBackRegT2AddrModeImm8"; } def t2STR_POST : T2Ipostldst<0, 0b10, 0, 0, (outs GPRnopc:$Rn_wb), (ins rGPR:$Rt, addr_offset_none:$Rn, t2am_imm8_offset:$offset), AddrModeT2_i8, IndexModePost, IIC_iStore_iu, "str", "\t$Rt, $Rn$offset", "$Rn = $Rn_wb,@earlyclobber $Rn_wb", [(set GPRnopc:$Rn_wb, (post_store rGPR:$Rt, addr_offset_none:$Rn, t2am_imm8_offset:$offset))]>; def t2STRH_POST : T2Ipostldst<0, 0b01, 0, 0, (outs GPRnopc:$Rn_wb), (ins rGPR:$Rt, addr_offset_none:$Rn, t2am_imm8_offset:$offset), AddrModeT2_i8, IndexModePost, IIC_iStore_bh_iu, "strh", "\t$Rt, $Rn$offset", "$Rn = $Rn_wb,@earlyclobber $Rn_wb", [(set GPRnopc:$Rn_wb, (post_truncsti16 rGPR:$Rt, addr_offset_none:$Rn, t2am_imm8_offset:$offset))]>; def t2STRB_POST : T2Ipostldst<0, 0b00, 0, 0, (outs GPRnopc:$Rn_wb), (ins rGPR:$Rt, addr_offset_none:$Rn, t2am_imm8_offset:$offset), AddrModeT2_i8, IndexModePost, IIC_iStore_bh_iu, "strb", "\t$Rt, $Rn$offset", "$Rn = $Rn_wb,@earlyclobber $Rn_wb", [(set GPRnopc:$Rn_wb, (post_truncsti8 rGPR:$Rt, addr_offset_none:$Rn, t2am_imm8_offset:$offset))]>; // Pseudo-instructions for pattern matching the pre-indexed stores. We can't // put the patterns on the instruction definitions directly as ISel wants // the address base and offset to be separate operands, not a single // complex operand like we represent the instructions themselves. The // pseudos map between the two. let usesCustomInserter = 1, Constraints = "$Rn = $Rn_wb,@earlyclobber $Rn_wb" in { def t2STR_preidx: t2PseudoInst<(outs GPRnopc:$Rn_wb), (ins rGPR:$Rt, GPRnopc:$Rn, t2am_imm8_offset:$offset, pred:$p), 4, IIC_iStore_ru, [(set GPRnopc:$Rn_wb, (pre_store rGPR:$Rt, GPRnopc:$Rn, t2am_imm8_offset:$offset))]>; def t2STRB_preidx: t2PseudoInst<(outs GPRnopc:$Rn_wb), (ins rGPR:$Rt, GPRnopc:$Rn, t2am_imm8_offset:$offset, pred:$p), 4, IIC_iStore_ru, [(set GPRnopc:$Rn_wb, (pre_truncsti8 rGPR:$Rt, GPRnopc:$Rn, t2am_imm8_offset:$offset))]>; def t2STRH_preidx: t2PseudoInst<(outs GPRnopc:$Rn_wb), (ins rGPR:$Rt, GPRnopc:$Rn, t2am_imm8_offset:$offset, pred:$p), 4, IIC_iStore_ru, [(set GPRnopc:$Rn_wb, (pre_truncsti16 rGPR:$Rt, GPRnopc:$Rn, t2am_imm8_offset:$offset))]>; } // STRT, STRBT, STRHT all have offset mode (PUW=0b110) and are for disassembly // only. // Ref: A8.6.193 STR (immediate, Thumb) Encoding T4 class T2IstT type, string opc, InstrItinClass ii> : T2Ii8<(outs rGPR:$Rt), (ins t2addrmode_imm8:$addr), ii, opc, "\t$Rt, $addr", []> { let Inst{31-27} = 0b11111; let Inst{26-25} = 0b00; let Inst{24} = 0; // not signed let Inst{23} = 0; let Inst{22-21} = type; let Inst{20} = 0; // store let Inst{11} = 1; let Inst{10-8} = 0b110; // PUW bits<4> Rt; bits<13> addr; let Inst{15-12} = Rt; let Inst{19-16} = addr{12-9}; let Inst{7-0} = addr{7-0}; } def t2STRT : T2IstT<0b10, "strt", IIC_iStore_i>; def t2STRBT : T2IstT<0b00, "strbt", IIC_iStore_bh_i>; def t2STRHT : T2IstT<0b01, "strht", IIC_iStore_bh_i>; // ldrd / strd pre / post variants // For disassembly only. def t2LDRD_PRE : T2Ii8s4<1, 1, 1, (outs rGPR:$Rt, rGPR:$Rt2, GPR:$wb), (ins t2addrmode_imm8s4:$addr), IIC_iLoad_d_ru, "ldrd", "\t$Rt, $Rt2, $addr!", "$addr.base = $wb", []> { let AsmMatchConverter = "cvtT2LdrdPre"; let DecoderMethod = "DecodeT2LDRDPreInstruction"; } def t2LDRD_POST : T2Ii8s4post<0, 1, 1, (outs rGPR:$Rt, rGPR:$Rt2, GPR:$wb), (ins addr_offset_none:$addr, t2am_imm8s4_offset:$imm), IIC_iLoad_d_ru, "ldrd", "\t$Rt, $Rt2, $addr$imm", "$addr.base = $wb", []>; def t2STRD_PRE : T2Ii8s4<1, 1, 0, (outs GPR:$wb), (ins rGPR:$Rt, rGPR:$Rt2, t2addrmode_imm8s4:$addr), IIC_iStore_d_ru, "strd", "\t$Rt, $Rt2, $addr!", "$addr.base = $wb", []> { let AsmMatchConverter = "cvtT2StrdPre"; let DecoderMethod = "DecodeT2STRDPreInstruction"; } def t2STRD_POST : T2Ii8s4post<0, 1, 0, (outs GPR:$wb), (ins rGPR:$Rt, rGPR:$Rt2, addr_offset_none:$addr, t2am_imm8s4_offset:$imm), IIC_iStore_d_ru, "strd", "\t$Rt, $Rt2, $addr$imm", "$addr.base = $wb", []>; // T2Ipl (Preload Data/Instruction) signals the memory system of possible future // data/instruction access. These are for disassembly only. // instr_write is inverted for Thumb mode: (prefetch 3) -> (preload 0), // (prefetch 1) -> (preload 2), (prefetch 2) -> (preload 1). multiclass T2Ipl write, bits<1> instr, string opc> { def i12 : T2Ii12<(outs), (ins t2addrmode_imm12:$addr), IIC_Preload, opc, "\t$addr", [(ARMPreload t2addrmode_imm12:$addr, (i32 write), (i32 instr))]> { let Inst{31-25} = 0b1111100; let Inst{24} = instr; let Inst{22} = 0; let Inst{21} = write; let Inst{20} = 1; let Inst{15-12} = 0b1111; bits<17> addr; let addr{12} = 1; // add = TRUE let Inst{19-16} = addr{16-13}; // Rn let Inst{23} = addr{12}; // U let Inst{11-0} = addr{11-0}; // imm12 } def i8 : T2Ii8<(outs), (ins t2addrmode_negimm8:$addr), IIC_Preload, opc, "\t$addr", [(ARMPreload t2addrmode_negimm8:$addr, (i32 write), (i32 instr))]> { let Inst{31-25} = 0b1111100; let Inst{24} = instr; let Inst{23} = 0; // U = 0 let Inst{22} = 0; let Inst{21} = write; let Inst{20} = 1; let Inst{15-12} = 0b1111; let Inst{11-8} = 0b1100; bits<13> addr; let Inst{19-16} = addr{12-9}; // Rn let Inst{7-0} = addr{7-0}; // imm8 } def s : T2Iso<(outs), (ins t2addrmode_so_reg:$addr), IIC_Preload, opc, "\t$addr", [(ARMPreload t2addrmode_so_reg:$addr, (i32 write), (i32 instr))]> { let Inst{31-25} = 0b1111100; let Inst{24} = instr; let Inst{23} = 0; // add = TRUE for T1 let Inst{22} = 0; let Inst{21} = write; let Inst{20} = 1; let Inst{15-12} = 0b1111; let Inst{11-6} = 0000000; bits<10> addr; let Inst{19-16} = addr{9-6}; // Rn let Inst{3-0} = addr{5-2}; // Rm let Inst{5-4} = addr{1-0}; // imm2 let DecoderMethod = "DecodeT2LoadShift"; } } defm t2PLD : T2Ipl<0, 0, "pld">, Requires<[IsThumb2]>; defm t2PLDW : T2Ipl<1, 0, "pldw">, Requires<[IsThumb2,HasV7,HasMP]>; defm t2PLI : T2Ipl<0, 1, "pli">, Requires<[IsThumb2,HasV7]>; //===----------------------------------------------------------------------===// // Load / store multiple Instructions. // multiclass thumb2_ld_mult { def IA : T2XI<(outs), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops), itin, !strconcat(asm, "${p}.w\t$Rn, $regs"), []> { bits<4> Rn; bits<16> regs; let Inst{31-27} = 0b11101; let Inst{26-25} = 0b00; let Inst{24-23} = 0b01; // Increment After let Inst{22} = 0; let Inst{21} = 0; // No writeback let Inst{20} = L_bit; let Inst{19-16} = Rn; - let Inst{15} = 0; - let Inst{14-0} = regs{14-0}; + let Inst{15-0} = regs; } def IA_UPD : T2XIt<(outs GPR:$wb), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops), itin_upd, !strconcat(asm, "${p}.w\t$Rn!, $regs"), "$Rn = $wb", []> { bits<4> Rn; bits<16> regs; let Inst{31-27} = 0b11101; let Inst{26-25} = 0b00; let Inst{24-23} = 0b01; // Increment After let Inst{22} = 0; let Inst{21} = 1; // Writeback let Inst{20} = L_bit; let Inst{19-16} = Rn; - let Inst{15} = 0; - let Inst{14-0} = regs{14-0}; + let Inst{15-0} = regs; } def DB : T2XI<(outs), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops), itin, !strconcat(asm, "db${p}\t$Rn, $regs"), []> { bits<4> Rn; bits<16> regs; let Inst{31-27} = 0b11101; let Inst{26-25} = 0b00; let Inst{24-23} = 0b10; // Decrement Before let Inst{22} = 0; let Inst{21} = 0; // No writeback let Inst{20} = L_bit; let Inst{19-16} = Rn; - let Inst{15} = 0; - let Inst{14-0} = regs{14-0}; + let Inst{15-0} = regs; } def DB_UPD : T2XIt<(outs GPR:$wb), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops), itin_upd, !strconcat(asm, "db${p}\t$Rn!, $regs"), "$Rn = $wb", []> { bits<4> Rn; bits<16> regs; let Inst{31-27} = 0b11101; let Inst{26-25} = 0b00; let Inst{24-23} = 0b10; // Decrement Before let Inst{22} = 0; let Inst{21} = 1; // Writeback let Inst{20} = L_bit; let Inst{19-16} = Rn; - let Inst{15} = 0; - let Inst{14-0} = regs{14-0}; + let Inst{15-0} = regs; } } let neverHasSideEffects = 1 in { let mayLoad = 1, hasExtraDefRegAllocReq = 1 in defm t2LDM : thumb2_ld_mult<"ldm", IIC_iLoad_m, IIC_iLoad_mu, 1>; multiclass thumb2_st_mult { def IA : T2XI<(outs), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops), itin, !strconcat(asm, "${p}.w\t$Rn, $regs"), []> { bits<4> Rn; bits<16> regs; let Inst{31-27} = 0b11101; let Inst{26-25} = 0b00; let Inst{24-23} = 0b01; // Increment After let Inst{22} = 0; let Inst{21} = 0; // No writeback let Inst{20} = L_bit; let Inst{19-16} = Rn; let Inst{15} = 0; let Inst{14} = regs{14}; let Inst{13} = 0; let Inst{12-0} = regs{12-0}; } def IA_UPD : T2XIt<(outs GPR:$wb), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops), itin_upd, !strconcat(asm, "${p}.w\t$Rn!, $regs"), "$Rn = $wb", []> { bits<4> Rn; bits<16> regs; let Inst{31-27} = 0b11101; let Inst{26-25} = 0b00; let Inst{24-23} = 0b01; // Increment After let Inst{22} = 0; let Inst{21} = 1; // Writeback let Inst{20} = L_bit; let Inst{19-16} = Rn; let Inst{15} = 0; let Inst{14} = regs{14}; let Inst{13} = 0; let Inst{12-0} = regs{12-0}; } def DB : T2XI<(outs), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops), itin, !strconcat(asm, "db${p}\t$Rn, $regs"), []> { bits<4> Rn; bits<16> regs; let Inst{31-27} = 0b11101; let Inst{26-25} = 0b00; let Inst{24-23} = 0b10; // Decrement Before let Inst{22} = 0; let Inst{21} = 0; // No writeback let Inst{20} = L_bit; let Inst{19-16} = Rn; let Inst{15} = 0; let Inst{14} = regs{14}; let Inst{13} = 0; let Inst{12-0} = regs{12-0}; } def DB_UPD : T2XIt<(outs GPR:$wb), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops), itin_upd, !strconcat(asm, "db${p}\t$Rn!, $regs"), "$Rn = $wb", []> { bits<4> Rn; bits<16> regs; let Inst{31-27} = 0b11101; let Inst{26-25} = 0b00; let Inst{24-23} = 0b10; // Decrement Before let Inst{22} = 0; let Inst{21} = 1; // Writeback let Inst{20} = L_bit; let Inst{19-16} = Rn; let Inst{15} = 0; let Inst{14} = regs{14}; let Inst{13} = 0; let Inst{12-0} = regs{12-0}; } } let mayStore = 1, hasExtraSrcRegAllocReq = 1 in defm t2STM : thumb2_st_mult<"stm", IIC_iStore_m, IIC_iStore_mu, 0>; } // neverHasSideEffects //===----------------------------------------------------------------------===// // Move Instructions. // let neverHasSideEffects = 1 in def t2MOVr : T2sTwoReg<(outs GPRnopc:$Rd), (ins GPR:$Rm), IIC_iMOVr, "mov", ".w\t$Rd, $Rm", []> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = 0b0010; let Inst{19-16} = 0b1111; // Rn let Inst{14-12} = 0b000; let Inst{7-4} = 0b0000; } def : t2InstAlias<"movs${p}.w $Rd, $Rm", (t2MOVr GPRnopc:$Rd, GPR:$Rm, pred:$p, CPSR)>; def : t2InstAlias<"movs${p} $Rd, $Rm", (t2MOVr GPRnopc:$Rd, GPR:$Rm, pred:$p, CPSR)>; // AddedComplexity to ensure isel tries t2MOVi before t2MOVi16. let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveImm = 1, AddedComplexity = 1 in def t2MOVi : T2sOneRegImm<(outs rGPR:$Rd), (ins t2_so_imm:$imm), IIC_iMOVi, "mov", ".w\t$Rd, $imm", [(set rGPR:$Rd, t2_so_imm:$imm)]> { let Inst{31-27} = 0b11110; let Inst{25} = 0; let Inst{24-21} = 0b0010; let Inst{19-16} = 0b1111; // Rn let Inst{15} = 0; } // cc_out is handled as part of the explicit mnemonic in the parser for 'mov'. // Use aliases to get that to play nice here. def : t2InstAlias<"movs${p}.w $Rd, $imm", (t2MOVi rGPR:$Rd, t2_so_imm:$imm, pred:$p, CPSR)>; def : t2InstAlias<"movs${p} $Rd, $imm", (t2MOVi rGPR:$Rd, t2_so_imm:$imm, pred:$p, CPSR)>; def : t2InstAlias<"mov${p}.w $Rd, $imm", (t2MOVi rGPR:$Rd, t2_so_imm:$imm, pred:$p, zero_reg)>; def : t2InstAlias<"mov${p} $Rd, $imm", (t2MOVi rGPR:$Rd, t2_so_imm:$imm, pred:$p, zero_reg)>; let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveImm = 1 in def t2MOVi16 : T2I<(outs rGPR:$Rd), (ins imm0_65535_expr:$imm), IIC_iMOVi, "movw", "\t$Rd, $imm", [(set rGPR:$Rd, imm0_65535:$imm)]> { let Inst{31-27} = 0b11110; let Inst{25} = 1; let Inst{24-21} = 0b0010; let Inst{20} = 0; // The S bit. let Inst{15} = 0; bits<4> Rd; bits<16> imm; let Inst{11-8} = Rd; let Inst{19-16} = imm{15-12}; let Inst{26} = imm{11}; let Inst{14-12} = imm{10-8}; let Inst{7-0} = imm{7-0}; let DecoderMethod = "DecodeT2MOVTWInstruction"; } def t2MOVi16_ga_pcrel : PseudoInst<(outs rGPR:$Rd), (ins i32imm:$addr, pclabel:$id), IIC_iMOVi, []>; let Constraints = "$src = $Rd" in { def t2MOVTi16 : T2I<(outs rGPR:$Rd), (ins rGPR:$src, imm0_65535_expr:$imm), IIC_iMOVi, "movt", "\t$Rd, $imm", [(set rGPR:$Rd, (or (and rGPR:$src, 0xffff), lo16AllZero:$imm))]> { let Inst{31-27} = 0b11110; let Inst{25} = 1; let Inst{24-21} = 0b0110; let Inst{20} = 0; // The S bit. let Inst{15} = 0; bits<4> Rd; bits<16> imm; let Inst{11-8} = Rd; let Inst{19-16} = imm{15-12}; let Inst{26} = imm{11}; let Inst{14-12} = imm{10-8}; let Inst{7-0} = imm{7-0}; let DecoderMethod = "DecodeT2MOVTWInstruction"; } def t2MOVTi16_ga_pcrel : PseudoInst<(outs rGPR:$Rd), (ins rGPR:$src, i32imm:$addr, pclabel:$id), IIC_iMOVi, []>; } // Constraints def : T2Pat<(or rGPR:$src, 0xffff0000), (t2MOVTi16 rGPR:$src, 0xffff)>; //===----------------------------------------------------------------------===// // Extend Instructions. // // Sign extenders def t2SXTB : T2I_ext_rrot<0b100, "sxtb", UnOpFrag<(sext_inreg node:$Src, i8)>>; def t2SXTH : T2I_ext_rrot<0b000, "sxth", UnOpFrag<(sext_inreg node:$Src, i16)>>; def t2SXTB16 : T2I_ext_rrot_sxtb16<0b010, "sxtb16">; def t2SXTAB : T2I_exta_rrot<0b100, "sxtab", BinOpFrag<(add node:$LHS, (sext_inreg node:$RHS, i8))>>; def t2SXTAH : T2I_exta_rrot<0b000, "sxtah", BinOpFrag<(add node:$LHS, (sext_inreg node:$RHS,i16))>>; def t2SXTAB16 : T2I_exta_rrot_np<0b010, "sxtab16">; // Zero extenders let AddedComplexity = 16 in { def t2UXTB : T2I_ext_rrot<0b101, "uxtb", UnOpFrag<(and node:$Src, 0x000000FF)>>; def t2UXTH : T2I_ext_rrot<0b001, "uxth", UnOpFrag<(and node:$Src, 0x0000FFFF)>>; def t2UXTB16 : T2I_ext_rrot_uxtb16<0b011, "uxtb16", UnOpFrag<(and node:$Src, 0x00FF00FF)>>; // FIXME: This pattern incorrectly assumes the shl operator is a rotate. // The transformation should probably be done as a combiner action // instead so we can include a check for masking back in the upper // eight bits of the source into the lower eight bits of the result. //def : T2Pat<(and (shl rGPR:$Src, (i32 8)), 0xFF00FF), // (t2UXTB16 rGPR:$Src, 3)>, // Requires<[HasT2ExtractPack, IsThumb2]>; def : T2Pat<(and (srl rGPR:$Src, (i32 8)), 0xFF00FF), (t2UXTB16 rGPR:$Src, 1)>, Requires<[HasT2ExtractPack, IsThumb2]>; def t2UXTAB : T2I_exta_rrot<0b101, "uxtab", BinOpFrag<(add node:$LHS, (and node:$RHS, 0x00FF))>>; def t2UXTAH : T2I_exta_rrot<0b001, "uxtah", BinOpFrag<(add node:$LHS, (and node:$RHS, 0xFFFF))>>; def t2UXTAB16 : T2I_exta_rrot_np<0b011, "uxtab16">; } //===----------------------------------------------------------------------===// // Arithmetic Instructions. // defm t2ADD : T2I_bin_ii12rs<0b000, "add", BinOpFrag<(add node:$LHS, node:$RHS)>, 1>; defm t2SUB : T2I_bin_ii12rs<0b101, "sub", BinOpFrag<(sub node:$LHS, node:$RHS)>>; // ADD and SUB with 's' bit set. No 12-bit immediate (T4) variants. // // Currently, t2ADDS/t2SUBS are pseudo opcodes that exist only in the // selection DAG. They are "lowered" to real t2ADD/t2SUB opcodes by // AdjustInstrPostInstrSelection where we determine whether or not to // set the "s" bit based on CPSR liveness. // // FIXME: Eliminate t2ADDS/t2SUBS pseudo opcodes after adding tablegen // support for an optional CPSR definition that corresponds to the DAG // node's second value. We can then eliminate the implicit def of CPSR. defm t2ADDS : T2I_bin_s_irs <0b1000, "add", IIC_iALUi, IIC_iALUr, IIC_iALUsi, BinOpFrag<(ARMaddc node:$LHS, node:$RHS)>, 1>; defm t2SUBS : T2I_bin_s_irs <0b1101, "sub", IIC_iALUi, IIC_iALUr, IIC_iALUsi, BinOpFrag<(ARMsubc node:$LHS, node:$RHS)>>; let hasPostISelHook = 1 in { defm t2ADC : T2I_adde_sube_irs<0b1010, "adc", BinOpWithFlagFrag<(ARMadde node:$LHS, node:$RHS, node:$FLAG)>, 1>; defm t2SBC : T2I_adde_sube_irs<0b1011, "sbc", BinOpWithFlagFrag<(ARMsube node:$LHS, node:$RHS, node:$FLAG)>>; } // RSB defm t2RSB : T2I_rbin_irs <0b1110, "rsb", BinOpFrag<(sub node:$LHS, node:$RHS)>>; // FIXME: Eliminate them if we can write def : Pat patterns which defines // CPSR and the implicit def of CPSR is not needed. defm t2RSBS : T2I_rbin_s_is <0b1110, "rsb", BinOpFrag<(ARMsubc node:$LHS, node:$RHS)>>; // (sub X, imm) gets canonicalized to (add X, -imm). Match this form. // The assume-no-carry-in form uses the negation of the input since add/sub // assume opposite meanings of the carry flag (i.e., carry == !borrow). // See the definition of AddWithCarry() in the ARM ARM A2.2.1 for the gory // details. // The AddedComplexity preferences the first variant over the others since // it can be shrunk to a 16-bit wide encoding, while the others cannot. let AddedComplexity = 1 in def : T2Pat<(add GPR:$src, imm0_255_neg:$imm), (t2SUBri GPR:$src, imm0_255_neg:$imm)>; def : T2Pat<(add GPR:$src, t2_so_imm_neg:$imm), (t2SUBri GPR:$src, t2_so_imm_neg:$imm)>; def : T2Pat<(add GPR:$src, imm0_4095_neg:$imm), (t2SUBri12 GPR:$src, imm0_4095_neg:$imm)>; let AddedComplexity = 1 in def : T2Pat<(ARMaddc rGPR:$src, imm0_255_neg:$imm), (t2SUBSri rGPR:$src, imm0_255_neg:$imm)>; def : T2Pat<(ARMaddc rGPR:$src, t2_so_imm_neg:$imm), (t2SUBSri rGPR:$src, t2_so_imm_neg:$imm)>; // The with-carry-in form matches bitwise not instead of the negation. // Effectively, the inverse interpretation of the carry flag already accounts // for part of the negation. let AddedComplexity = 1 in def : T2Pat<(ARMadde rGPR:$src, imm0_255_not:$imm, CPSR), (t2SBCri rGPR:$src, imm0_255_not:$imm)>; def : T2Pat<(ARMadde rGPR:$src, t2_so_imm_not:$imm, CPSR), (t2SBCri rGPR:$src, t2_so_imm_not:$imm)>; // Select Bytes -- for disassembly only def t2SEL : T2ThreeReg<(outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), NoItinerary, "sel", "\t$Rd, $Rn, $Rm", []>, Requires<[IsThumb2, HasThumb2DSP]> { let Inst{31-27} = 0b11111; let Inst{26-24} = 0b010; let Inst{23} = 0b1; let Inst{22-20} = 0b010; let Inst{15-12} = 0b1111; let Inst{7} = 0b1; let Inst{6-4} = 0b000; } // A6.3.13, A6.3.14, A6.3.15 Parallel addition and subtraction (signed/unsigned) // And Miscellaneous operations -- for disassembly only class T2I_pam op22_20, bits<4> op7_4, string opc, list pat = [/* For disassembly only; pattern left blank */], dag iops = (ins rGPR:$Rn, rGPR:$Rm), string asm = "\t$Rd, $Rn, $Rm"> : T2I<(outs rGPR:$Rd), iops, NoItinerary, opc, asm, pat>, Requires<[IsThumb2, HasThumb2DSP]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0101; let Inst{22-20} = op22_20; let Inst{15-12} = 0b1111; let Inst{7-4} = op7_4; bits<4> Rd; bits<4> Rn; bits<4> Rm; let Inst{11-8} = Rd; let Inst{19-16} = Rn; let Inst{3-0} = Rm; } // Saturating add/subtract -- for disassembly only def t2QADD : T2I_pam<0b000, 0b1000, "qadd", [(set rGPR:$Rd, (int_arm_qadd rGPR:$Rn, rGPR:$Rm))], (ins rGPR:$Rm, rGPR:$Rn), "\t$Rd, $Rm, $Rn">; def t2QADD16 : T2I_pam<0b001, 0b0001, "qadd16">; def t2QADD8 : T2I_pam<0b000, 0b0001, "qadd8">; def t2QASX : T2I_pam<0b010, 0b0001, "qasx">; def t2QDADD : T2I_pam<0b000, 0b1001, "qdadd", [], (ins rGPR:$Rm, rGPR:$Rn), "\t$Rd, $Rm, $Rn">; def t2QDSUB : T2I_pam<0b000, 0b1011, "qdsub", [], (ins rGPR:$Rm, rGPR:$Rn), "\t$Rd, $Rm, $Rn">; def t2QSAX : T2I_pam<0b110, 0b0001, "qsax">; def t2QSUB : T2I_pam<0b000, 0b1010, "qsub", [(set rGPR:$Rd, (int_arm_qsub rGPR:$Rn, rGPR:$Rm))], (ins rGPR:$Rm, rGPR:$Rn), "\t$Rd, $Rm, $Rn">; def t2QSUB16 : T2I_pam<0b101, 0b0001, "qsub16">; def t2QSUB8 : T2I_pam<0b100, 0b0001, "qsub8">; def t2UQADD16 : T2I_pam<0b001, 0b0101, "uqadd16">; def t2UQADD8 : T2I_pam<0b000, 0b0101, "uqadd8">; def t2UQASX : T2I_pam<0b010, 0b0101, "uqasx">; def t2UQSAX : T2I_pam<0b110, 0b0101, "uqsax">; def t2UQSUB16 : T2I_pam<0b101, 0b0101, "uqsub16">; def t2UQSUB8 : T2I_pam<0b100, 0b0101, "uqsub8">; // Signed/Unsigned add/subtract -- for disassembly only def t2SASX : T2I_pam<0b010, 0b0000, "sasx">; def t2SADD16 : T2I_pam<0b001, 0b0000, "sadd16">; def t2SADD8 : T2I_pam<0b000, 0b0000, "sadd8">; def t2SSAX : T2I_pam<0b110, 0b0000, "ssax">; def t2SSUB16 : T2I_pam<0b101, 0b0000, "ssub16">; def t2SSUB8 : T2I_pam<0b100, 0b0000, "ssub8">; def t2UASX : T2I_pam<0b010, 0b0100, "uasx">; def t2UADD16 : T2I_pam<0b001, 0b0100, "uadd16">; def t2UADD8 : T2I_pam<0b000, 0b0100, "uadd8">; def t2USAX : T2I_pam<0b110, 0b0100, "usax">; def t2USUB16 : T2I_pam<0b101, 0b0100, "usub16">; def t2USUB8 : T2I_pam<0b100, 0b0100, "usub8">; // Signed/Unsigned halving add/subtract -- for disassembly only def t2SHASX : T2I_pam<0b010, 0b0010, "shasx">; def t2SHADD16 : T2I_pam<0b001, 0b0010, "shadd16">; def t2SHADD8 : T2I_pam<0b000, 0b0010, "shadd8">; def t2SHSAX : T2I_pam<0b110, 0b0010, "shsax">; def t2SHSUB16 : T2I_pam<0b101, 0b0010, "shsub16">; def t2SHSUB8 : T2I_pam<0b100, 0b0010, "shsub8">; def t2UHASX : T2I_pam<0b010, 0b0110, "uhasx">; def t2UHADD16 : T2I_pam<0b001, 0b0110, "uhadd16">; def t2UHADD8 : T2I_pam<0b000, 0b0110, "uhadd8">; def t2UHSAX : T2I_pam<0b110, 0b0110, "uhsax">; def t2UHSUB16 : T2I_pam<0b101, 0b0110, "uhsub16">; def t2UHSUB8 : T2I_pam<0b100, 0b0110, "uhsub8">; // Helper class for disassembly only // A6.3.16 & A6.3.17 // T2Imac - Thumb2 multiply [accumulate, and absolute difference] instructions. class T2ThreeReg_mac op22_20, bits<4> op7_4, dag oops, dag iops, InstrItinClass itin, string opc, string asm, list pattern> : T2ThreeReg { let Inst{31-27} = 0b11111; let Inst{26-24} = 0b011; let Inst{23} = long; let Inst{22-20} = op22_20; let Inst{7-4} = op7_4; } class T2FourReg_mac op22_20, bits<4> op7_4, dag oops, dag iops, InstrItinClass itin, string opc, string asm, list pattern> : T2FourReg { let Inst{31-27} = 0b11111; let Inst{26-24} = 0b011; let Inst{23} = long; let Inst{22-20} = op22_20; let Inst{7-4} = op7_4; } // Unsigned Sum of Absolute Differences [and Accumulate]. def t2USAD8 : T2ThreeReg_mac<0, 0b111, 0b0000, (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), NoItinerary, "usad8", "\t$Rd, $Rn, $Rm", []>, Requires<[IsThumb2, HasThumb2DSP]> { let Inst{15-12} = 0b1111; } def t2USADA8 : T2FourReg_mac<0, 0b111, 0b0000, (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), NoItinerary, "usada8", "\t$Rd, $Rn, $Rm, $Ra", []>, Requires<[IsThumb2, HasThumb2DSP]>; // Signed/Unsigned saturate. class T2SatI pattern> : T2I { bits<4> Rd; bits<4> Rn; bits<5> sat_imm; bits<7> sh; let Inst{11-8} = Rd; let Inst{19-16} = Rn; let Inst{4-0} = sat_imm; let Inst{21} = sh{5}; let Inst{14-12} = sh{4-2}; let Inst{7-6} = sh{1-0}; } def t2SSAT: T2SatI< (outs rGPR:$Rd), (ins imm1_32:$sat_imm, rGPR:$Rn, t2_shift_imm:$sh), NoItinerary, "ssat", "\t$Rd, $sat_imm, $Rn$sh", []> { let Inst{31-27} = 0b11110; let Inst{25-22} = 0b1100; let Inst{20} = 0; let Inst{15} = 0; let Inst{5} = 0; } def t2SSAT16: T2SatI< (outs rGPR:$Rd), (ins imm1_16:$sat_imm, rGPR:$Rn), NoItinerary, "ssat16", "\t$Rd, $sat_imm, $Rn", []>, Requires<[IsThumb2, HasThumb2DSP]> { let Inst{31-27} = 0b11110; let Inst{25-22} = 0b1100; let Inst{20} = 0; let Inst{15} = 0; let Inst{21} = 1; // sh = '1' let Inst{14-12} = 0b000; // imm3 = '000' let Inst{7-6} = 0b00; // imm2 = '00' let Inst{5-4} = 0b00; } def t2USAT: T2SatI< (outs rGPR:$Rd), (ins imm0_31:$sat_imm, rGPR:$Rn, t2_shift_imm:$sh), NoItinerary, "usat", "\t$Rd, $sat_imm, $Rn$sh", []> { let Inst{31-27} = 0b11110; let Inst{25-22} = 0b1110; let Inst{20} = 0; let Inst{15} = 0; } def t2USAT16: T2SatI<(outs rGPR:$Rd), (ins imm0_15:$sat_imm, rGPR:$Rn), NoItinerary, "usat16", "\t$Rd, $sat_imm, $Rn", []>, Requires<[IsThumb2, HasThumb2DSP]> { let Inst{31-22} = 0b1111001110; let Inst{20} = 0; let Inst{15} = 0; let Inst{21} = 1; // sh = '1' let Inst{14-12} = 0b000; // imm3 = '000' let Inst{7-6} = 0b00; // imm2 = '00' let Inst{5-4} = 0b00; } def : T2Pat<(int_arm_ssat GPR:$a, imm:$pos), (t2SSAT imm:$pos, GPR:$a, 0)>; def : T2Pat<(int_arm_usat GPR:$a, imm:$pos), (t2USAT imm:$pos, GPR:$a, 0)>; //===----------------------------------------------------------------------===// // Shift and rotate Instructions. // defm t2LSL : T2I_sh_ir<0b00, "lsl", imm0_31, BinOpFrag<(shl node:$LHS, node:$RHS)>, "t2LSL">; defm t2LSR : T2I_sh_ir<0b01, "lsr", imm_sr, BinOpFrag<(srl node:$LHS, node:$RHS)>, "t2LSR">; defm t2ASR : T2I_sh_ir<0b10, "asr", imm_sr, BinOpFrag<(sra node:$LHS, node:$RHS)>, "t2ASR">; defm t2ROR : T2I_sh_ir<0b11, "ror", imm0_31, BinOpFrag<(rotr node:$LHS, node:$RHS)>, "t2ROR">; // (rotr x, (and y, 0x...1f)) ==> (ROR x, y) def : Pat<(rotr rGPR:$lhs, (and rGPR:$rhs, lo5AllOne)), (t2RORrr rGPR:$lhs, rGPR:$rhs)>; let Uses = [CPSR] in { def t2RRX : T2sTwoReg<(outs rGPR:$Rd), (ins rGPR:$Rm), IIC_iMOVsi, "rrx", "\t$Rd, $Rm", [(set rGPR:$Rd, (ARMrrx rGPR:$Rm))]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = 0b0010; let Inst{19-16} = 0b1111; // Rn let Inst{14-12} = 0b000; let Inst{7-4} = 0b0011; } } let isCodeGenOnly = 1, Defs = [CPSR] in { def t2MOVsrl_flag : T2TwoRegShiftImm< (outs rGPR:$Rd), (ins rGPR:$Rm), IIC_iMOVsi, "lsrs", ".w\t$Rd, $Rm, #1", [(set rGPR:$Rd, (ARMsrl_flag rGPR:$Rm))]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = 0b0010; let Inst{20} = 1; // The S bit. let Inst{19-16} = 0b1111; // Rn let Inst{5-4} = 0b01; // Shift type. // Shift amount = Inst{14-12:7-6} = 1. let Inst{14-12} = 0b000; let Inst{7-6} = 0b01; } def t2MOVsra_flag : T2TwoRegShiftImm< (outs rGPR:$Rd), (ins rGPR:$Rm), IIC_iMOVsi, "asrs", ".w\t$Rd, $Rm, #1", [(set rGPR:$Rd, (ARMsra_flag rGPR:$Rm))]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = 0b0010; let Inst{20} = 1; // The S bit. let Inst{19-16} = 0b1111; // Rn let Inst{5-4} = 0b10; // Shift type. // Shift amount = Inst{14-12:7-6} = 1. let Inst{14-12} = 0b000; let Inst{7-6} = 0b01; } } //===----------------------------------------------------------------------===// // Bitwise Instructions. // defm t2AND : T2I_bin_w_irs<0b0000, "and", IIC_iBITi, IIC_iBITr, IIC_iBITsi, BinOpFrag<(and node:$LHS, node:$RHS)>, "t2AND", 1>; defm t2ORR : T2I_bin_w_irs<0b0010, "orr", IIC_iBITi, IIC_iBITr, IIC_iBITsi, BinOpFrag<(or node:$LHS, node:$RHS)>, "t2ORR", 1>; defm t2EOR : T2I_bin_w_irs<0b0100, "eor", IIC_iBITi, IIC_iBITr, IIC_iBITsi, BinOpFrag<(xor node:$LHS, node:$RHS)>, "t2EOR", 1>; defm t2BIC : T2I_bin_w_irs<0b0001, "bic", IIC_iBITi, IIC_iBITr, IIC_iBITsi, BinOpFrag<(and node:$LHS, (not node:$RHS))>, "t2BIC">; class T2BitFI pattern> : T2I { bits<4> Rd; bits<5> msb; bits<5> lsb; let Inst{11-8} = Rd; let Inst{4-0} = msb{4-0}; let Inst{14-12} = lsb{4-2}; let Inst{7-6} = lsb{1-0}; } class T2TwoRegBitFI pattern> : T2BitFI { bits<4> Rn; let Inst{19-16} = Rn; } let Constraints = "$src = $Rd" in def t2BFC : T2BitFI<(outs rGPR:$Rd), (ins rGPR:$src, bf_inv_mask_imm:$imm), IIC_iUNAsi, "bfc", "\t$Rd, $imm", [(set rGPR:$Rd, (and rGPR:$src, bf_inv_mask_imm:$imm))]> { let Inst{31-27} = 0b11110; let Inst{26} = 0; // should be 0. let Inst{25} = 1; let Inst{24-20} = 0b10110; let Inst{19-16} = 0b1111; // Rn let Inst{15} = 0; let Inst{5} = 0; // should be 0. bits<10> imm; let msb{4-0} = imm{9-5}; let lsb{4-0} = imm{4-0}; } def t2SBFX: T2TwoRegBitFI< (outs rGPR:$Rd), (ins rGPR:$Rn, imm0_31:$lsb, imm1_32:$msb), IIC_iUNAsi, "sbfx", "\t$Rd, $Rn, $lsb, $msb", []> { let Inst{31-27} = 0b11110; let Inst{25} = 1; let Inst{24-20} = 0b10100; let Inst{15} = 0; } def t2UBFX: T2TwoRegBitFI< (outs rGPR:$Rd), (ins rGPR:$Rn, imm0_31:$lsb, imm1_32:$msb), IIC_iUNAsi, "ubfx", "\t$Rd, $Rn, $lsb, $msb", []> { let Inst{31-27} = 0b11110; let Inst{25} = 1; let Inst{24-20} = 0b11100; let Inst{15} = 0; } // A8.6.18 BFI - Bitfield insert (Encoding T1) let Constraints = "$src = $Rd" in { def t2BFI : T2TwoRegBitFI<(outs rGPR:$Rd), (ins rGPR:$src, rGPR:$Rn, bf_inv_mask_imm:$imm), IIC_iBITi, "bfi", "\t$Rd, $Rn, $imm", [(set rGPR:$Rd, (ARMbfi rGPR:$src, rGPR:$Rn, bf_inv_mask_imm:$imm))]> { let Inst{31-27} = 0b11110; let Inst{26} = 0; // should be 0. let Inst{25} = 1; let Inst{24-20} = 0b10110; let Inst{15} = 0; let Inst{5} = 0; // should be 0. bits<10> imm; let msb{4-0} = imm{9-5}; let lsb{4-0} = imm{4-0}; } } defm t2ORN : T2I_bin_irs<0b0011, "orn", IIC_iBITi, IIC_iBITr, IIC_iBITsi, BinOpFrag<(or node:$LHS, (not node:$RHS))>, "t2ORN", 0, "">; /// T2I_un_irs - Defines a set of (op reg, {so_imm|r|so_reg}) patterns for a /// unary operation that produces a value. These are predicable and can be /// changed to modify CPSR. multiclass T2I_un_irs opcod, string opc, InstrItinClass iii, InstrItinClass iir, InstrItinClass iis, PatFrag opnode, bit Cheap = 0, bit ReMat = 0> { // shifted imm def i : T2sOneRegImm<(outs rGPR:$Rd), (ins t2_so_imm:$imm), iii, opc, "\t$Rd, $imm", [(set rGPR:$Rd, (opnode t2_so_imm:$imm))]> { let isAsCheapAsAMove = Cheap; let isReMaterializable = ReMat; let Inst{31-27} = 0b11110; let Inst{25} = 0; let Inst{24-21} = opcod; let Inst{19-16} = 0b1111; // Rn let Inst{15} = 0; } // register def r : T2sTwoReg<(outs rGPR:$Rd), (ins rGPR:$Rm), iir, opc, ".w\t$Rd, $Rm", [(set rGPR:$Rd, (opnode rGPR:$Rm))]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = opcod; let Inst{19-16} = 0b1111; // Rn let Inst{14-12} = 0b000; // imm3 let Inst{7-6} = 0b00; // imm2 let Inst{5-4} = 0b00; // type } // shifted register def s : T2sOneRegShiftedReg<(outs rGPR:$Rd), (ins t2_so_reg:$ShiftedRm), iis, opc, ".w\t$Rd, $ShiftedRm", [(set rGPR:$Rd, (opnode t2_so_reg:$ShiftedRm))]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = opcod; let Inst{19-16} = 0b1111; // Rn } } // Prefer over of t2EORri ra, rb, -1 because mvn has 16-bit version let AddedComplexity = 1 in defm t2MVN : T2I_un_irs <0b0011, "mvn", IIC_iMVNi, IIC_iMVNr, IIC_iMVNsi, UnOpFrag<(not node:$Src)>, 1, 1>; let AddedComplexity = 1 in def : T2Pat<(and rGPR:$src, t2_so_imm_not:$imm), (t2BICri rGPR:$src, t2_so_imm_not:$imm)>; // FIXME: Disable this pattern on Darwin to workaround an assembler bug. def : T2Pat<(or rGPR:$src, t2_so_imm_not:$imm), (t2ORNri rGPR:$src, t2_so_imm_not:$imm)>, Requires<[IsThumb2]>; def : T2Pat<(t2_so_imm_not:$src), (t2MVNi t2_so_imm_not:$src)>; //===----------------------------------------------------------------------===// // Multiply Instructions. // let isCommutable = 1 in def t2MUL: T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL32, "mul", "\t$Rd, $Rn, $Rm", [(set rGPR:$Rd, (mul rGPR:$Rn, rGPR:$Rm))]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b000; let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate) let Inst{7-4} = 0b0000; // Multiply } def t2MLA: T2FourReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32, "mla", "\t$Rd, $Rn, $Rm, $Ra", [(set rGPR:$Rd, (add (mul rGPR:$Rn, rGPR:$Rm), rGPR:$Ra))]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b000; let Inst{7-4} = 0b0000; // Multiply } def t2MLS: T2FourReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32, "mls", "\t$Rd, $Rn, $Rm, $Ra", [(set rGPR:$Rd, (sub rGPR:$Ra, (mul rGPR:$Rn, rGPR:$Rm)))]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b000; let Inst{7-4} = 0b0001; // Multiply and Subtract } // Extra precision multiplies with low / high results let neverHasSideEffects = 1 in { let isCommutable = 1 in { def t2SMULL : T2MulLong<0b000, 0b0000, (outs rGPR:$RdLo, rGPR:$RdHi), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL64, "smull", "\t$RdLo, $RdHi, $Rn, $Rm", []>; def t2UMULL : T2MulLong<0b010, 0b0000, (outs rGPR:$RdLo, rGPR:$RdHi), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL64, "umull", "\t$RdLo, $RdHi, $Rn, $Rm", []>; } // isCommutable // Multiply + accumulate def t2SMLAL : T2MulLong<0b100, 0b0000, (outs rGPR:$RdLo, rGPR:$RdHi), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMAC64, "smlal", "\t$RdLo, $RdHi, $Rn, $Rm", []>; def t2UMLAL : T2MulLong<0b110, 0b0000, (outs rGPR:$RdLo, rGPR:$RdHi), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMAC64, "umlal", "\t$RdLo, $RdHi, $Rn, $Rm", []>; def t2UMAAL : T2MulLong<0b110, 0b0110, (outs rGPR:$RdLo, rGPR:$RdHi), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMAC64, "umaal", "\t$RdLo, $RdHi, $Rn, $Rm", []>, Requires<[IsThumb2, HasThumb2DSP]>; } // neverHasSideEffects // Rounding variants of the below included for disassembly only // Most significant word multiply def t2SMMUL : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL32, "smmul", "\t$Rd, $Rn, $Rm", [(set rGPR:$Rd, (mulhs rGPR:$Rn, rGPR:$Rm))]>, Requires<[IsThumb2, HasThumb2DSP]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b101; let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate) let Inst{7-4} = 0b0000; // No Rounding (Inst{4} = 0) } def t2SMMULR : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL32, "smmulr", "\t$Rd, $Rn, $Rm", []>, Requires<[IsThumb2, HasThumb2DSP]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b101; let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate) let Inst{7-4} = 0b0001; // Rounding (Inst{4} = 1) } def t2SMMLA : T2FourReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32, "smmla", "\t$Rd, $Rn, $Rm, $Ra", [(set rGPR:$Rd, (add (mulhs rGPR:$Rm, rGPR:$Rn), rGPR:$Ra))]>, Requires<[IsThumb2, HasThumb2DSP]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b101; let Inst{7-4} = 0b0000; // No Rounding (Inst{4} = 0) } def t2SMMLAR: T2FourReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32, "smmlar", "\t$Rd, $Rn, $Rm, $Ra", []>, Requires<[IsThumb2, HasThumb2DSP]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b101; let Inst{7-4} = 0b0001; // Rounding (Inst{4} = 1) } def t2SMMLS: T2FourReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32, "smmls", "\t$Rd, $Rn, $Rm, $Ra", [(set rGPR:$Rd, (sub rGPR:$Ra, (mulhs rGPR:$Rn, rGPR:$Rm)))]>, Requires<[IsThumb2, HasThumb2DSP]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b110; let Inst{7-4} = 0b0000; // No Rounding (Inst{4} = 0) } def t2SMMLSR:T2FourReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32, "smmlsr", "\t$Rd, $Rn, $Rm, $Ra", []>, Requires<[IsThumb2, HasThumb2DSP]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b110; let Inst{7-4} = 0b0001; // Rounding (Inst{4} = 1) } multiclass T2I_smul { def BB : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL16, !strconcat(opc, "bb"), "\t$Rd, $Rn, $Rm", [(set rGPR:$Rd, (opnode (sext_inreg rGPR:$Rn, i16), (sext_inreg rGPR:$Rm, i16)))]>, Requires<[IsThumb2, HasThumb2DSP]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b001; let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate) let Inst{7-6} = 0b00; let Inst{5-4} = 0b00; } def BT : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL16, !strconcat(opc, "bt"), "\t$Rd, $Rn, $Rm", [(set rGPR:$Rd, (opnode (sext_inreg rGPR:$Rn, i16), (sra rGPR:$Rm, (i32 16))))]>, Requires<[IsThumb2, HasThumb2DSP]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b001; let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate) let Inst{7-6} = 0b00; let Inst{5-4} = 0b01; } def TB : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL16, !strconcat(opc, "tb"), "\t$Rd, $Rn, $Rm", [(set rGPR:$Rd, (opnode (sra rGPR:$Rn, (i32 16)), (sext_inreg rGPR:$Rm, i16)))]>, Requires<[IsThumb2, HasThumb2DSP]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b001; let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate) let Inst{7-6} = 0b00; let Inst{5-4} = 0b10; } def TT : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL16, !strconcat(opc, "tt"), "\t$Rd, $Rn, $Rm", [(set rGPR:$Rd, (opnode (sra rGPR:$Rn, (i32 16)), (sra rGPR:$Rm, (i32 16))))]>, Requires<[IsThumb2, HasThumb2DSP]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b001; let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate) let Inst{7-6} = 0b00; let Inst{5-4} = 0b11; } def WB : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL16, !strconcat(opc, "wb"), "\t$Rd, $Rn, $Rm", [(set rGPR:$Rd, (sra (opnode rGPR:$Rn, (sext_inreg rGPR:$Rm, i16)), (i32 16)))]>, Requires<[IsThumb2, HasThumb2DSP]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b011; let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate) let Inst{7-6} = 0b00; let Inst{5-4} = 0b00; } def WT : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL16, !strconcat(opc, "wt"), "\t$Rd, $Rn, $Rm", [(set rGPR:$Rd, (sra (opnode rGPR:$Rn, (sra rGPR:$Rm, (i32 16))), (i32 16)))]>, Requires<[IsThumb2, HasThumb2DSP]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b011; let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate) let Inst{7-6} = 0b00; let Inst{5-4} = 0b01; } } multiclass T2I_smla { def BB : T2FourReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC16, !strconcat(opc, "bb"), "\t$Rd, $Rn, $Rm, $Ra", [(set rGPR:$Rd, (add rGPR:$Ra, (opnode (sext_inreg rGPR:$Rn, i16), (sext_inreg rGPR:$Rm, i16))))]>, Requires<[IsThumb2, HasThumb2DSP]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b001; let Inst{7-6} = 0b00; let Inst{5-4} = 0b00; } def BT : T2FourReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC16, !strconcat(opc, "bt"), "\t$Rd, $Rn, $Rm, $Ra", [(set rGPR:$Rd, (add rGPR:$Ra, (opnode (sext_inreg rGPR:$Rn, i16), (sra rGPR:$Rm, (i32 16)))))]>, Requires<[IsThumb2, HasThumb2DSP]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b001; let Inst{7-6} = 0b00; let Inst{5-4} = 0b01; } def TB : T2FourReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC16, !strconcat(opc, "tb"), "\t$Rd, $Rn, $Rm, $Ra", [(set rGPR:$Rd, (add rGPR:$Ra, (opnode (sra rGPR:$Rn, (i32 16)), (sext_inreg rGPR:$Rm, i16))))]>, Requires<[IsThumb2, HasThumb2DSP]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b001; let Inst{7-6} = 0b00; let Inst{5-4} = 0b10; } def TT : T2FourReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC16, !strconcat(opc, "tt"), "\t$Rd, $Rn, $Rm, $Ra", [(set rGPR:$Rd, (add rGPR:$Ra, (opnode (sra rGPR:$Rn, (i32 16)), (sra rGPR:$Rm, (i32 16)))))]>, Requires<[IsThumb2, HasThumb2DSP]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b001; let Inst{7-6} = 0b00; let Inst{5-4} = 0b11; } def WB : T2FourReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC16, !strconcat(opc, "wb"), "\t$Rd, $Rn, $Rm, $Ra", [(set rGPR:$Rd, (add rGPR:$Ra, (sra (opnode rGPR:$Rn, (sext_inreg rGPR:$Rm, i16)), (i32 16))))]>, Requires<[IsThumb2, HasThumb2DSP]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b011; let Inst{7-6} = 0b00; let Inst{5-4} = 0b00; } def WT : T2FourReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC16, !strconcat(opc, "wt"), "\t$Rd, $Rn, $Rm, $Ra", [(set rGPR:$Rd, (add rGPR:$Ra, (sra (opnode rGPR:$Rn, (sra rGPR:$Rm, (i32 16))), (i32 16))))]>, Requires<[IsThumb2, HasThumb2DSP]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b011; let Inst{7-6} = 0b00; let Inst{5-4} = 0b01; } } defm t2SMUL : T2I_smul<"smul", BinOpFrag<(mul node:$LHS, node:$RHS)>>; defm t2SMLA : T2I_smla<"smla", BinOpFrag<(mul node:$LHS, node:$RHS)>>; // Halfword multiple accumulate long: SMLAL def t2SMLALBB : T2FourReg_mac<1, 0b100, 0b1000, (outs rGPR:$Ra,rGPR:$Rd), (ins rGPR:$Rn,rGPR:$Rm), IIC_iMAC64, "smlalbb", "\t$Ra, $Rd, $Rn, $Rm", [/* For disassembly only; pattern left blank */]>, Requires<[IsThumb2, HasThumb2DSP]>; def t2SMLALBT : T2FourReg_mac<1, 0b100, 0b1001, (outs rGPR:$Ra,rGPR:$Rd), (ins rGPR:$Rn,rGPR:$Rm), IIC_iMAC64, "smlalbt", "\t$Ra, $Rd, $Rn, $Rm", [/* For disassembly only; pattern left blank */]>, Requires<[IsThumb2, HasThumb2DSP]>; def t2SMLALTB : T2FourReg_mac<1, 0b100, 0b1010, (outs rGPR:$Ra,rGPR:$Rd), (ins rGPR:$Rn,rGPR:$Rm), IIC_iMAC64, "smlaltb", "\t$Ra, $Rd, $Rn, $Rm", [/* For disassembly only; pattern left blank */]>, Requires<[IsThumb2, HasThumb2DSP]>; def t2SMLALTT : T2FourReg_mac<1, 0b100, 0b1011, (outs rGPR:$Ra,rGPR:$Rd), (ins rGPR:$Rn,rGPR:$Rm), IIC_iMAC64, "smlaltt", "\t$Ra, $Rd, $Rn, $Rm", [/* For disassembly only; pattern left blank */]>, Requires<[IsThumb2, HasThumb2DSP]>; // Dual halfword multiple: SMUAD, SMUSD, SMLAD, SMLSD, SMLALD, SMLSLD def t2SMUAD: T2ThreeReg_mac< 0, 0b010, 0b0000, (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMAC32, "smuad", "\t$Rd, $Rn, $Rm", []>, Requires<[IsThumb2, HasThumb2DSP]> { let Inst{15-12} = 0b1111; } def t2SMUADX:T2ThreeReg_mac< 0, 0b010, 0b0001, (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMAC32, "smuadx", "\t$Rd, $Rn, $Rm", []>, Requires<[IsThumb2, HasThumb2DSP]> { let Inst{15-12} = 0b1111; } def t2SMUSD: T2ThreeReg_mac< 0, 0b100, 0b0000, (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMAC32, "smusd", "\t$Rd, $Rn, $Rm", []>, Requires<[IsThumb2, HasThumb2DSP]> { let Inst{15-12} = 0b1111; } def t2SMUSDX:T2ThreeReg_mac< 0, 0b100, 0b0001, (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMAC32, "smusdx", "\t$Rd, $Rn, $Rm", []>, Requires<[IsThumb2, HasThumb2DSP]> { let Inst{15-12} = 0b1111; } def t2SMLAD : T2FourReg_mac< 0, 0b010, 0b0000, (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32, "smlad", "\t$Rd, $Rn, $Rm, $Ra", []>, Requires<[IsThumb2, HasThumb2DSP]>; def t2SMLADX : T2FourReg_mac< 0, 0b010, 0b0001, (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32, "smladx", "\t$Rd, $Rn, $Rm, $Ra", []>, Requires<[IsThumb2, HasThumb2DSP]>; def t2SMLSD : T2FourReg_mac<0, 0b100, 0b0000, (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32, "smlsd", "\t$Rd, $Rn, $Rm, $Ra", []>, Requires<[IsThumb2, HasThumb2DSP]>; def t2SMLSDX : T2FourReg_mac<0, 0b100, 0b0001, (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32, "smlsdx", "\t$Rd, $Rn, $Rm, $Ra", []>, Requires<[IsThumb2, HasThumb2DSP]>; def t2SMLALD : T2FourReg_mac<1, 0b100, 0b1100, (outs rGPR:$Ra,rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMAC64, "smlald", "\t$Ra, $Rd, $Rn, $Rm", []>, Requires<[IsThumb2, HasThumb2DSP]>; def t2SMLALDX : T2FourReg_mac<1, 0b100, 0b1101, (outs rGPR:$Ra,rGPR:$Rd), (ins rGPR:$Rn,rGPR:$Rm), IIC_iMAC64, "smlaldx", "\t$Ra, $Rd, $Rn, $Rm", []>, Requires<[IsThumb2, HasThumb2DSP]>; def t2SMLSLD : T2FourReg_mac<1, 0b101, 0b1100, (outs rGPR:$Ra,rGPR:$Rd), (ins rGPR:$Rn,rGPR:$Rm), IIC_iMAC64, "smlsld", "\t$Ra, $Rd, $Rn, $Rm", []>, Requires<[IsThumb2, HasThumb2DSP]>; def t2SMLSLDX : T2FourReg_mac<1, 0b101, 0b1101, (outs rGPR:$Ra,rGPR:$Rd), (ins rGPR:$Rm,rGPR:$Rn), IIC_iMAC64, "smlsldx", "\t$Ra, $Rd, $Rn, $Rm", []>, Requires<[IsThumb2, HasThumb2DSP]>; //===----------------------------------------------------------------------===// // Division Instructions. // Signed and unsigned division on v7-M // def t2SDIV : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iALUi, "sdiv", "\t$Rd, $Rn, $Rm", [(set rGPR:$Rd, (sdiv rGPR:$Rn, rGPR:$Rm))]>, Requires<[HasDivide, IsThumb2]> { let Inst{31-27} = 0b11111; let Inst{26-21} = 0b011100; let Inst{20} = 0b1; let Inst{15-12} = 0b1111; let Inst{7-4} = 0b1111; } def t2UDIV : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iALUi, "udiv", "\t$Rd, $Rn, $Rm", [(set rGPR:$Rd, (udiv rGPR:$Rn, rGPR:$Rm))]>, Requires<[HasDivide, IsThumb2]> { let Inst{31-27} = 0b11111; let Inst{26-21} = 0b011101; let Inst{20} = 0b1; let Inst{15-12} = 0b1111; let Inst{7-4} = 0b1111; } //===----------------------------------------------------------------------===// // Misc. Arithmetic Instructions. // class T2I_misc op1, bits<2> op2, dag oops, dag iops, InstrItinClass itin, string opc, string asm, list pattern> : T2ThreeReg { let Inst{31-27} = 0b11111; let Inst{26-22} = 0b01010; let Inst{21-20} = op1; let Inst{15-12} = 0b1111; let Inst{7-6} = 0b10; let Inst{5-4} = op2; let Rn{3-0} = Rm; } def t2CLZ : T2I_misc<0b11, 0b00, (outs rGPR:$Rd), (ins rGPR:$Rm), IIC_iUNAr, "clz", "\t$Rd, $Rm", [(set rGPR:$Rd, (ctlz rGPR:$Rm))]>; def t2RBIT : T2I_misc<0b01, 0b10, (outs rGPR:$Rd), (ins rGPR:$Rm), IIC_iUNAr, "rbit", "\t$Rd, $Rm", [(set rGPR:$Rd, (ARMrbit rGPR:$Rm))]>; def t2REV : T2I_misc<0b01, 0b00, (outs rGPR:$Rd), (ins rGPR:$Rm), IIC_iUNAr, "rev", ".w\t$Rd, $Rm", [(set rGPR:$Rd, (bswap rGPR:$Rm))]>; def t2REV16 : T2I_misc<0b01, 0b01, (outs rGPR:$Rd), (ins rGPR:$Rm), IIC_iUNAr, "rev16", ".w\t$Rd, $Rm", [(set rGPR:$Rd, (rotr (bswap rGPR:$Rm), (i32 16)))]>; def t2REVSH : T2I_misc<0b01, 0b11, (outs rGPR:$Rd), (ins rGPR:$Rm), IIC_iUNAr, "revsh", ".w\t$Rd, $Rm", [(set rGPR:$Rd, (sra (bswap rGPR:$Rm), (i32 16)))]>; def : T2Pat<(or (sra (shl rGPR:$Rm, (i32 24)), (i32 16)), (and (srl rGPR:$Rm, (i32 8)), 0xFF)), (t2REVSH rGPR:$Rm)>; def t2PKHBT : T2ThreeReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, pkh_lsl_amt:$sh), IIC_iBITsi, "pkhbt", "\t$Rd, $Rn, $Rm$sh", [(set rGPR:$Rd, (or (and rGPR:$Rn, 0xFFFF), (and (shl rGPR:$Rm, pkh_lsl_amt:$sh), 0xFFFF0000)))]>, Requires<[HasT2ExtractPack, IsThumb2]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-20} = 0b01100; let Inst{5} = 0; // BT form let Inst{4} = 0; bits<5> sh; let Inst{14-12} = sh{4-2}; let Inst{7-6} = sh{1-0}; } // Alternate cases for PKHBT where identities eliminate some nodes. def : T2Pat<(or (and rGPR:$src1, 0xFFFF), (and rGPR:$src2, 0xFFFF0000)), (t2PKHBT rGPR:$src1, rGPR:$src2, 0)>, Requires<[HasT2ExtractPack, IsThumb2]>; def : T2Pat<(or (and rGPR:$src1, 0xFFFF), (shl rGPR:$src2, imm16_31:$sh)), (t2PKHBT rGPR:$src1, rGPR:$src2, imm16_31:$sh)>, Requires<[HasT2ExtractPack, IsThumb2]>; // Note: Shifts of 1-15 bits will be transformed to srl instead of sra and // will match the pattern below. def t2PKHTB : T2ThreeReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, pkh_asr_amt:$sh), IIC_iBITsi, "pkhtb", "\t$Rd, $Rn, $Rm$sh", [(set rGPR:$Rd, (or (and rGPR:$Rn, 0xFFFF0000), (and (sra rGPR:$Rm, pkh_asr_amt:$sh), 0xFFFF)))]>, Requires<[HasT2ExtractPack, IsThumb2]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-20} = 0b01100; let Inst{5} = 1; // TB form let Inst{4} = 0; bits<5> sh; let Inst{14-12} = sh{4-2}; let Inst{7-6} = sh{1-0}; } // Alternate cases for PKHTB where identities eliminate some nodes. Note that // a shift amount of 0 is *not legal* here, it is PKHBT instead. def : T2Pat<(or (and rGPR:$src1, 0xFFFF0000), (srl rGPR:$src2, imm16_31:$sh)), (t2PKHTB rGPR:$src1, rGPR:$src2, imm16_31:$sh)>, Requires<[HasT2ExtractPack, IsThumb2]>; def : T2Pat<(or (and rGPR:$src1, 0xFFFF0000), (and (srl rGPR:$src2, imm1_15:$sh), 0xFFFF)), (t2PKHTB rGPR:$src1, rGPR:$src2, imm1_15:$sh)>, Requires<[HasT2ExtractPack, IsThumb2]>; //===----------------------------------------------------------------------===// // Comparison Instructions... // defm t2CMP : T2I_cmp_irs<0b1101, "cmp", IIC_iCMPi, IIC_iCMPr, IIC_iCMPsi, BinOpFrag<(ARMcmp node:$LHS, node:$RHS)>, "t2CMP">; def : T2Pat<(ARMcmpZ GPRnopc:$lhs, t2_so_imm:$imm), (t2CMPri GPRnopc:$lhs, t2_so_imm:$imm)>; def : T2Pat<(ARMcmpZ GPRnopc:$lhs, rGPR:$rhs), (t2CMPrr GPRnopc:$lhs, rGPR:$rhs)>; def : T2Pat<(ARMcmpZ GPRnopc:$lhs, t2_so_reg:$rhs), (t2CMPrs GPRnopc:$lhs, t2_so_reg:$rhs)>; //FIXME: Disable CMN, as CCodes are backwards from compare expectations // Compare-to-zero still works out, just not the relationals //defm t2CMN : T2I_cmp_irs<0b1000, "cmn", // BinOpFrag<(ARMcmp node:$LHS,(ineg node:$RHS))>>; defm t2CMNz : T2I_cmp_irs<0b1000, "cmn", IIC_iCMPi, IIC_iCMPr, IIC_iCMPsi, BinOpFrag<(ARMcmpZ node:$LHS,(ineg node:$RHS))>, "t2CMNz">; //def : T2Pat<(ARMcmp GPR:$src, t2_so_imm_neg:$imm), // (t2CMNri GPR:$src, t2_so_imm_neg:$imm)>; def : T2Pat<(ARMcmpZ GPRnopc:$src, t2_so_imm_neg:$imm), (t2CMNzri GPRnopc:$src, t2_so_imm_neg:$imm)>; defm t2TST : T2I_cmp_irs<0b0000, "tst", IIC_iTSTi, IIC_iTSTr, IIC_iTSTsi, BinOpFrag<(ARMcmpZ (and_su node:$LHS, node:$RHS), 0)>, "t2TST">; defm t2TEQ : T2I_cmp_irs<0b0100, "teq", IIC_iTSTi, IIC_iTSTr, IIC_iTSTsi, BinOpFrag<(ARMcmpZ (xor_su node:$LHS, node:$RHS), 0)>, "t2TEQ">; // Conditional moves // FIXME: should be able to write a pattern for ARMcmov, but can't use // a two-value operand where a dag node expects two operands. :( let neverHasSideEffects = 1 in { def t2MOVCCr : t2PseudoInst<(outs rGPR:$Rd), (ins rGPR:$false, rGPR:$Rm, pred:$p), 4, IIC_iCMOVr, [/*(set rGPR:$Rd, (ARMcmov rGPR:$false, rGPR:$Rm, imm:$cc, CCR:$ccr))*/]>, RegConstraint<"$false = $Rd">; let isMoveImm = 1 in def t2MOVCCi : t2PseudoInst<(outs rGPR:$Rd), (ins rGPR:$false, t2_so_imm:$imm, pred:$p), 4, IIC_iCMOVi, [/*(set rGPR:$Rd,(ARMcmov rGPR:$false,t2_so_imm:$imm, imm:$cc, CCR:$ccr))*/]>, RegConstraint<"$false = $Rd">; // FIXME: Pseudo-ize these. For now, just mark codegen only. let isCodeGenOnly = 1 in { let isMoveImm = 1 in def t2MOVCCi16 : T2I<(outs rGPR:$Rd), (ins rGPR:$false, imm0_65535_expr:$imm), IIC_iCMOVi, "movw", "\t$Rd, $imm", []>, RegConstraint<"$false = $Rd"> { let Inst{31-27} = 0b11110; let Inst{25} = 1; let Inst{24-21} = 0b0010; let Inst{20} = 0; // The S bit. let Inst{15} = 0; bits<4> Rd; bits<16> imm; let Inst{11-8} = Rd; let Inst{19-16} = imm{15-12}; let Inst{26} = imm{11}; let Inst{14-12} = imm{10-8}; let Inst{7-0} = imm{7-0}; } let isMoveImm = 1 in def t2MOVCCi32imm : PseudoInst<(outs rGPR:$dst), (ins rGPR:$false, i32imm:$src, pred:$p), IIC_iCMOVix2, []>, RegConstraint<"$false = $dst">; let isMoveImm = 1 in def t2MVNCCi : T2OneRegImm<(outs rGPR:$Rd), (ins rGPR:$false, t2_so_imm:$imm), IIC_iCMOVi, "mvn", ".w\t$Rd, $imm", [/*(set rGPR:$Rd,(ARMcmov rGPR:$false,t2_so_imm_not:$imm, imm:$cc, CCR:$ccr))*/]>, RegConstraint<"$false = $Rd"> { let Inst{31-27} = 0b11110; let Inst{25} = 0; let Inst{24-21} = 0b0011; let Inst{20} = 0; // The S bit. let Inst{19-16} = 0b1111; // Rn let Inst{15} = 0; } class T2I_movcc_sh opcod, dag oops, dag iops, InstrItinClass itin, string opc, string asm, list pattern> : T2TwoRegShiftImm { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = 0b0010; let Inst{20} = 0; // The S bit. let Inst{19-16} = 0b1111; // Rn let Inst{5-4} = opcod; // Shift type. } def t2MOVCClsl : T2I_movcc_sh<0b00, (outs rGPR:$Rd), (ins rGPR:$false, rGPR:$Rm, i32imm:$imm), IIC_iCMOVsi, "lsl", ".w\t$Rd, $Rm, $imm", []>, RegConstraint<"$false = $Rd">; def t2MOVCClsr : T2I_movcc_sh<0b01, (outs rGPR:$Rd), (ins rGPR:$false, rGPR:$Rm, i32imm:$imm), IIC_iCMOVsi, "lsr", ".w\t$Rd, $Rm, $imm", []>, RegConstraint<"$false = $Rd">; def t2MOVCCasr : T2I_movcc_sh<0b10, (outs rGPR:$Rd), (ins rGPR:$false, rGPR:$Rm, i32imm:$imm), IIC_iCMOVsi, "asr", ".w\t$Rd, $Rm, $imm", []>, RegConstraint<"$false = $Rd">; def t2MOVCCror : T2I_movcc_sh<0b11, (outs rGPR:$Rd), (ins rGPR:$false, rGPR:$Rm, i32imm:$imm), IIC_iCMOVsi, "ror", ".w\t$Rd, $Rm, $imm", []>, RegConstraint<"$false = $Rd">; } // isCodeGenOnly = 1 } // neverHasSideEffects //===----------------------------------------------------------------------===// // Atomic operations intrinsics // // memory barriers protect the atomic sequences let hasSideEffects = 1 in { def t2DMB : AInoP<(outs), (ins memb_opt:$opt), ThumbFrm, NoItinerary, "dmb", "\t$opt", [(ARMMemBarrier (i32 imm:$opt))]>, Requires<[IsThumb, HasDB]> { bits<4> opt; let Inst{31-4} = 0xf3bf8f5; let Inst{3-0} = opt; } } def t2DSB : AInoP<(outs), (ins memb_opt:$opt), ThumbFrm, NoItinerary, "dsb", "\t$opt", []>, Requires<[IsThumb, HasDB]> { bits<4> opt; let Inst{31-4} = 0xf3bf8f4; let Inst{3-0} = opt; } def t2ISB : AInoP<(outs), (ins memb_opt:$opt), ThumbFrm, NoItinerary, "isb", "\t$opt", []>, Requires<[IsThumb2, HasDB]> { bits<4> opt; let Inst{31-4} = 0xf3bf8f6; let Inst{3-0} = opt; } class T2I_ldrex opcod, dag oops, dag iops, AddrMode am, int sz, InstrItinClass itin, string opc, string asm, string cstr, list pattern, bits<4> rt2 = 0b1111> : Thumb2I { let Inst{31-27} = 0b11101; let Inst{26-20} = 0b0001101; let Inst{11-8} = rt2; let Inst{7-6} = 0b01; let Inst{5-4} = opcod; let Inst{3-0} = 0b1111; bits<4> addr; bits<4> Rt; let Inst{19-16} = addr; let Inst{15-12} = Rt; } class T2I_strex opcod, dag oops, dag iops, AddrMode am, int sz, InstrItinClass itin, string opc, string asm, string cstr, list pattern, bits<4> rt2 = 0b1111> : Thumb2I { let Inst{31-27} = 0b11101; let Inst{26-20} = 0b0001100; let Inst{11-8} = rt2; let Inst{7-6} = 0b01; let Inst{5-4} = opcod; bits<4> Rd; bits<4> addr; bits<4> Rt; let Inst{3-0} = Rd; let Inst{19-16} = addr; let Inst{15-12} = Rt; } let mayLoad = 1 in { def t2LDREXB : T2I_ldrex<0b00, (outs rGPR:$Rt), (ins addr_offset_none:$addr), AddrModeNone, 4, NoItinerary, "ldrexb", "\t$Rt, $addr", "", []>; def t2LDREXH : T2I_ldrex<0b01, (outs rGPR:$Rt), (ins addr_offset_none:$addr), AddrModeNone, 4, NoItinerary, "ldrexh", "\t$Rt, $addr", "", []>; def t2LDREX : Thumb2I<(outs rGPR:$Rt), (ins t2addrmode_imm0_1020s4:$addr), AddrModeNone, 4, NoItinerary, "ldrex", "\t$Rt, $addr", "", []> { bits<4> Rt; bits<12> addr; let Inst{31-27} = 0b11101; let Inst{26-20} = 0b0000101; let Inst{19-16} = addr{11-8}; let Inst{15-12} = Rt; let Inst{11-8} = 0b1111; let Inst{7-0} = addr{7-0}; } let hasExtraDefRegAllocReq = 1 in def t2LDREXD : T2I_ldrex<0b11, (outs rGPR:$Rt, rGPR:$Rt2), (ins addr_offset_none:$addr), AddrModeNone, 4, NoItinerary, "ldrexd", "\t$Rt, $Rt2, $addr", "", [], {?, ?, ?, ?}> { bits<4> Rt2; let Inst{11-8} = Rt2; } } let mayStore = 1, Constraints = "@earlyclobber $Rd" in { def t2STREXB : T2I_strex<0b00, (outs rGPR:$Rd), (ins rGPR:$Rt, addr_offset_none:$addr), AddrModeNone, 4, NoItinerary, "strexb", "\t$Rd, $Rt, $addr", "", []>; def t2STREXH : T2I_strex<0b01, (outs rGPR:$Rd), (ins rGPR:$Rt, addr_offset_none:$addr), AddrModeNone, 4, NoItinerary, "strexh", "\t$Rd, $Rt, $addr", "", []>; def t2STREX : Thumb2I<(outs rGPR:$Rd), (ins rGPR:$Rt, t2addrmode_imm0_1020s4:$addr), AddrModeNone, 4, NoItinerary, "strex", "\t$Rd, $Rt, $addr", "", []> { bits<4> Rd; bits<4> Rt; bits<12> addr; let Inst{31-27} = 0b11101; let Inst{26-20} = 0b0000100; let Inst{19-16} = addr{11-8}; let Inst{15-12} = Rt; let Inst{11-8} = Rd; let Inst{7-0} = addr{7-0}; } } let hasExtraSrcRegAllocReq = 1, Constraints = "@earlyclobber $Rd" in def t2STREXD : T2I_strex<0b11, (outs rGPR:$Rd), (ins rGPR:$Rt, rGPR:$Rt2, addr_offset_none:$addr), AddrModeNone, 4, NoItinerary, "strexd", "\t$Rd, $Rt, $Rt2, $addr", "", [], {?, ?, ?, ?}> { bits<4> Rt2; let Inst{11-8} = Rt2; } def t2CLREX : T2I<(outs), (ins), NoItinerary, "clrex", "", []>, Requires<[IsThumb2, HasV7]> { let Inst{31-16} = 0xf3bf; let Inst{15-14} = 0b10; let Inst{13} = 0; let Inst{12} = 0; let Inst{11-8} = 0b1111; let Inst{7-4} = 0b0010; let Inst{3-0} = 0b1111; } //===----------------------------------------------------------------------===// // SJLJ Exception handling intrinsics // eh_sjlj_setjmp() is an instruction sequence to store the return // address and save #0 in R0 for the non-longjmp case. // Since by its nature we may be coming from some other function to get // here, and we're using the stack frame for the containing function to // save/restore registers, we can't keep anything live in regs across // the eh_sjlj_setjmp(), else it will almost certainly have been tromped upon // when we get here from a longjmp(). We force everything out of registers // except for our own input by listing the relevant registers in Defs. By // doing so, we also cause the prologue/epilogue code to actively preserve // all of the callee-saved resgisters, which is exactly what we want. // $val is a scratch register for our use. let Defs = [ R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR, CPSR, QQQQ0, QQQQ1, QQQQ2, QQQQ3 ], hasSideEffects = 1, isBarrier = 1, isCodeGenOnly = 1 in { def t2Int_eh_sjlj_setjmp : Thumb2XI<(outs), (ins tGPR:$src, tGPR:$val), AddrModeNone, 0, NoItinerary, "", "", [(set R0, (ARMeh_sjlj_setjmp tGPR:$src, tGPR:$val))]>, Requires<[IsThumb2, HasVFP2]>; } let Defs = [ R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR, CPSR ], hasSideEffects = 1, isBarrier = 1, isCodeGenOnly = 1 in { def t2Int_eh_sjlj_setjmp_nofp : Thumb2XI<(outs), (ins tGPR:$src, tGPR:$val), AddrModeNone, 0, NoItinerary, "", "", [(set R0, (ARMeh_sjlj_setjmp tGPR:$src, tGPR:$val))]>, Requires<[IsThumb2, NoVFP]>; } //===----------------------------------------------------------------------===// // Control-Flow Instructions // // FIXME: remove when we have a way to marking a MI with these properties. // FIXME: Should pc be an implicit operand like PICADD, etc? let isReturn = 1, isTerminator = 1, isBarrier = 1, mayLoad = 1, hasExtraDefRegAllocReq = 1, isCodeGenOnly = 1 in def t2LDMIA_RET: t2PseudoExpand<(outs GPR:$wb), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops), 4, IIC_iLoad_mBr, [], (t2LDMIA_UPD GPR:$wb, GPR:$Rn, pred:$p, reglist:$regs)>, RegConstraint<"$Rn = $wb">; let isBranch = 1, isTerminator = 1, isBarrier = 1 in { let isPredicable = 1 in def t2B : T2I<(outs), (ins uncondbrtarget:$target), IIC_Br, "b", ".w\t$target", [(br bb:$target)]> { let Inst{31-27} = 0b11110; let Inst{15-14} = 0b10; let Inst{12} = 1; bits<20> target; let Inst{26} = target{19}; let Inst{11} = target{18}; let Inst{13} = target{17}; let Inst{21-16} = target{16-11}; let Inst{10-0} = target{10-0}; } let isNotDuplicable = 1, isIndirectBranch = 1 in { def t2BR_JT : t2PseudoInst<(outs), (ins GPR:$target, GPR:$index, i32imm:$jt, i32imm:$id), 0, IIC_Br, [(ARMbr2jt GPR:$target, GPR:$index, tjumptable:$jt, imm:$id)]>; // FIXME: Add a non-pc based case that can be predicated. def t2TBB_JT : t2PseudoInst<(outs), (ins GPR:$index, i32imm:$jt, i32imm:$id), 0, IIC_Br, []>; def t2TBH_JT : t2PseudoInst<(outs), (ins GPR:$index, i32imm:$jt, i32imm:$id), 0, IIC_Br, []>; def t2TBB : T2I<(outs), (ins addrmode_tbb:$addr), IIC_Br, "tbb", "\t$addr", []> { bits<4> Rn; bits<4> Rm; let Inst{31-20} = 0b111010001101; let Inst{19-16} = Rn; let Inst{15-5} = 0b11110000000; let Inst{4} = 0; // B form let Inst{3-0} = Rm; let DecoderMethod = "DecodeThumbTableBranch"; } def t2TBH : T2I<(outs), (ins addrmode_tbh:$addr), IIC_Br, "tbh", "\t$addr", []> { bits<4> Rn; bits<4> Rm; let Inst{31-20} = 0b111010001101; let Inst{19-16} = Rn; let Inst{15-5} = 0b11110000000; let Inst{4} = 1; // H form let Inst{3-0} = Rm; let DecoderMethod = "DecodeThumbTableBranch"; } } // isNotDuplicable, isIndirectBranch } // isBranch, isTerminator, isBarrier // FIXME: should be able to write a pattern for ARMBrcond, but can't use // a two-value operand where a dag node expects ", "two operands. :( let isBranch = 1, isTerminator = 1 in def t2Bcc : T2I<(outs), (ins brtarget:$target), IIC_Br, "b", ".w\t$target", [/*(ARMbrcond bb:$target, imm:$cc)*/]> { let Inst{31-27} = 0b11110; let Inst{15-14} = 0b10; let Inst{12} = 0; bits<4> p; let Inst{25-22} = p; bits<21> target; let Inst{26} = target{20}; let Inst{11} = target{19}; let Inst{13} = target{18}; let Inst{21-16} = target{17-12}; let Inst{10-0} = target{11-1}; let DecoderMethod = "DecodeThumb2BCCInstruction"; } // Tail calls. The Darwin version of thumb tail calls uses a t2 branch, so // it goes here. let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1 in { // Darwin version. let Defs = [R0, R1, R2, R3, R9, R12, QQQQ0, QQQQ2, QQQQ3, PC], Uses = [SP] in def tTAILJMPd: tPseudoExpand<(outs), (ins uncondbrtarget:$dst, pred:$p, variable_ops), 4, IIC_Br, [], (t2B uncondbrtarget:$dst, pred:$p)>, Requires<[IsThumb2, IsDarwin]>; } // IT block let Defs = [ITSTATE] in def t2IT : Thumb2XI<(outs), (ins it_pred:$cc, it_mask:$mask), AddrModeNone, 2, IIC_iALUx, "it$mask\t$cc", "", []> { // 16-bit instruction. let Inst{31-16} = 0x0000; let Inst{15-8} = 0b10111111; bits<4> cc; bits<4> mask; let Inst{7-4} = cc; let Inst{3-0} = mask; let DecoderMethod = "DecodeIT"; } // Branch and Exchange Jazelle -- for disassembly only // Rm = Inst{19-16} def t2BXJ : T2I<(outs), (ins rGPR:$func), NoItinerary, "bxj", "\t$func", []> { bits<4> func; let Inst{31-27} = 0b11110; let Inst{26} = 0; let Inst{25-20} = 0b111100; let Inst{19-16} = func; let Inst{15-0} = 0b1000111100000000; } // Compare and branch on zero / non-zero let isBranch = 1, isTerminator = 1 in { def tCBZ : T1I<(outs), (ins tGPR:$Rn, t_cbtarget:$target), IIC_Br, "cbz\t$Rn, $target", []>, T1Misc<{0,0,?,1,?,?,?}>, Requires<[IsThumb2]> { // A8.6.27 bits<6> target; bits<3> Rn; let Inst{9} = target{5}; let Inst{7-3} = target{4-0}; let Inst{2-0} = Rn; } def tCBNZ : T1I<(outs), (ins tGPR:$Rn, t_cbtarget:$target), IIC_Br, "cbnz\t$Rn, $target", []>, T1Misc<{1,0,?,1,?,?,?}>, Requires<[IsThumb2]> { // A8.6.27 bits<6> target; bits<3> Rn; let Inst{9} = target{5}; let Inst{7-3} = target{4-0}; let Inst{2-0} = Rn; } } // Change Processor State is a system instruction. // FIXME: Since the asm parser has currently no clean way to handle optional // operands, create 3 versions of the same instruction. Once there's a clean // framework to represent optional operands, change this behavior. class t2CPS : T2XI<(outs), iops, NoItinerary, !strconcat("cps", asm_op), []> { bits<2> imod; bits<3> iflags; bits<5> mode; bit M; let Inst{31-27} = 0b11110; let Inst{26} = 0; let Inst{25-20} = 0b111010; let Inst{19-16} = 0b1111; let Inst{15-14} = 0b10; let Inst{12} = 0; let Inst{10-9} = imod; let Inst{8} = M; let Inst{7-5} = iflags; let Inst{4-0} = mode; let DecoderMethod = "DecodeT2CPSInstruction"; } let M = 1 in def t2CPS3p : t2CPS<(ins imod_op:$imod, iflags_op:$iflags, i32imm:$mode), "$imod.w\t$iflags, $mode">; let mode = 0, M = 0 in def t2CPS2p : t2CPS<(ins imod_op:$imod, iflags_op:$iflags), "$imod.w\t$iflags">; let imod = 0, iflags = 0, M = 1 in def t2CPS1p : t2CPS<(ins imm0_31:$mode), "\t$mode">; // A6.3.4 Branches and miscellaneous control // Table A6-14 Change Processor State, and hint instructions class T2I_hint op7_0, string opc, string asm> : T2I<(outs), (ins), NoItinerary, opc, asm, []> { let Inst{31-20} = 0xf3a; let Inst{19-16} = 0b1111; let Inst{15-14} = 0b10; let Inst{12} = 0; let Inst{10-8} = 0b000; let Inst{7-0} = op7_0; } def t2NOP : T2I_hint<0b00000000, "nop", ".w">; def t2YIELD : T2I_hint<0b00000001, "yield", ".w">; def t2WFE : T2I_hint<0b00000010, "wfe", ".w">; def t2WFI : T2I_hint<0b00000011, "wfi", ".w">; def t2SEV : T2I_hint<0b00000100, "sev", ".w">; def t2DBG : T2I<(outs), (ins imm0_15:$opt), NoItinerary, "dbg", "\t$opt", []> { bits<4> opt; let Inst{31-20} = 0b111100111010; let Inst{19-16} = 0b1111; let Inst{15-8} = 0b10000000; let Inst{7-4} = 0b1111; let Inst{3-0} = opt; } // Secure Monitor Call is a system instruction. // Option = Inst{19-16} def t2SMC : T2I<(outs), (ins imm0_15:$opt), NoItinerary, "smc", "\t$opt", []> { let Inst{31-27} = 0b11110; let Inst{26-20} = 0b1111111; let Inst{15-12} = 0b1000; bits<4> opt; let Inst{19-16} = opt; } class T2SRS Op, bit W, dag oops, dag iops, InstrItinClass itin, string opc, string asm, list pattern> : T2I { bits<5> mode; let Inst{31-25} = 0b1110100; let Inst{24-23} = Op; let Inst{22} = 0; let Inst{21} = W; let Inst{20-16} = 0b01101; let Inst{15-5} = 0b11000000000; let Inst{4-0} = mode{4-0}; } // Store Return State is a system instruction. def t2SRSDB_UPD : T2SRS<0b00, 1, (outs), (ins imm0_31:$mode), NoItinerary, "srsdb", "\tsp!, $mode", []>; def t2SRSDB : T2SRS<0b00, 0, (outs), (ins imm0_31:$mode), NoItinerary, "srsdb","\tsp, $mode", []>; def t2SRSIA_UPD : T2SRS<0b11, 1, (outs), (ins imm0_31:$mode), NoItinerary, "srsia","\tsp!, $mode", []>; def t2SRSIA : T2SRS<0b11, 0, (outs), (ins imm0_31:$mode), NoItinerary, "srsia","\tsp, $mode", []>; // Return From Exception is a system instruction. class T2RFE op31_20, dag oops, dag iops, InstrItinClass itin, string opc, string asm, list pattern> : T2I { let Inst{31-20} = op31_20{11-0}; bits<4> Rn; let Inst{19-16} = Rn; let Inst{15-0} = 0xc000; } def t2RFEDBW : T2RFE<0b111010000011, (outs), (ins GPR:$Rn), NoItinerary, "rfedb", "\t$Rn!", [/* For disassembly only; pattern left blank */]>; def t2RFEDB : T2RFE<0b111010000001, (outs), (ins GPR:$Rn), NoItinerary, "rfedb", "\t$Rn", [/* For disassembly only; pattern left blank */]>; def t2RFEIAW : T2RFE<0b111010011011, (outs), (ins GPR:$Rn), NoItinerary, "rfeia", "\t$Rn!", [/* For disassembly only; pattern left blank */]>; def t2RFEIA : T2RFE<0b111010011001, (outs), (ins GPR:$Rn), NoItinerary, "rfeia", "\t$Rn", [/* For disassembly only; pattern left blank */]>; //===----------------------------------------------------------------------===// // Non-Instruction Patterns // // 32-bit immediate using movw + movt. // This is a single pseudo instruction to make it re-materializable. // FIXME: Remove this when we can do generalized remat. let isReMaterializable = 1, isMoveImm = 1 in def t2MOVi32imm : PseudoInst<(outs rGPR:$dst), (ins i32imm:$src), IIC_iMOVix2, [(set rGPR:$dst, (i32 imm:$src))]>, Requires<[IsThumb, HasV6T2]>; // Pseudo instruction that combines movw + movt + add pc (if pic). // It also makes it possible to rematerialize the instructions. // FIXME: Remove this when we can do generalized remat and when machine licm // can properly the instructions. let isReMaterializable = 1 in { def t2MOV_ga_pcrel : PseudoInst<(outs rGPR:$dst), (ins i32imm:$addr), IIC_iMOVix2addpc, [(set rGPR:$dst, (ARMWrapperPIC tglobaladdr:$addr))]>, Requires<[IsThumb2, UseMovt]>; def t2MOV_ga_dyn : PseudoInst<(outs rGPR:$dst), (ins i32imm:$addr), IIC_iMOVix2, [(set rGPR:$dst, (ARMWrapperDYN tglobaladdr:$addr))]>, Requires<[IsThumb2, UseMovt]>; } // ConstantPool, GlobalAddress, and JumpTable def : T2Pat<(ARMWrapper tglobaladdr :$dst), (t2LEApcrel tglobaladdr :$dst)>, Requires<[IsThumb2, DontUseMovt]>; def : T2Pat<(ARMWrapper tconstpool :$dst), (t2LEApcrel tconstpool :$dst)>; def : T2Pat<(ARMWrapper tglobaladdr :$dst), (t2MOVi32imm tglobaladdr :$dst)>, Requires<[IsThumb2, UseMovt]>; def : T2Pat<(ARMWrapperJT tjumptable:$dst, imm:$id), (t2LEApcrelJT tjumptable:$dst, imm:$id)>; // Pseudo instruction that combines ldr from constpool and add pc. This should // be expanded into two instructions late to allow if-conversion and // scheduling. let canFoldAsLoad = 1, isReMaterializable = 1 in def t2LDRpci_pic : PseudoInst<(outs rGPR:$dst), (ins i32imm:$addr, pclabel:$cp), IIC_iLoadiALU, [(set rGPR:$dst, (ARMpic_add (load (ARMWrapper tconstpool:$addr)), imm:$cp))]>, Requires<[IsThumb2]>; // Pseudo isntruction that combines movs + predicated rsbmi // to implement integer ABS let usesCustomInserter = 1, Defs = [CPSR] in { def t2ABS : PseudoInst<(outs rGPR:$dst), (ins rGPR:$src), NoItinerary, []>, Requires<[IsThumb2]>; } //===----------------------------------------------------------------------===// // Coprocessor load/store -- for disassembly only // class T2CI op31_28, dag oops, dag iops, string opc, string asm> : T2I { let Inst{31-28} = op31_28; let Inst{27-25} = 0b110; } multiclass t2LdStCop op31_28, bit load, bit Dbit, string asm> { def _OFFSET : T2CI { bits<13> addr; bits<4> cop; bits<4> CRd; let Inst{24} = 1; // P = 1 let Inst{23} = addr{8}; let Inst{22} = Dbit; let Inst{21} = 0; // W = 0 let Inst{20} = load; let Inst{19-16} = addr{12-9}; let Inst{15-12} = CRd; let Inst{11-8} = cop; let Inst{7-0} = addr{7-0}; let DecoderMethod = "DecodeCopMemInstruction"; } def _PRE : T2CI { bits<13> addr; bits<4> cop; bits<4> CRd; let Inst{24} = 1; // P = 1 let Inst{23} = addr{8}; let Inst{22} = Dbit; let Inst{21} = 1; // W = 1 let Inst{20} = load; let Inst{19-16} = addr{12-9}; let Inst{15-12} = CRd; let Inst{11-8} = cop; let Inst{7-0} = addr{7-0}; let DecoderMethod = "DecodeCopMemInstruction"; } def _POST: T2CI { bits<9> offset; bits<4> addr; bits<4> cop; bits<4> CRd; let Inst{24} = 0; // P = 0 let Inst{23} = offset{8}; let Inst{22} = Dbit; let Inst{21} = 1; // W = 1 let Inst{20} = load; let Inst{19-16} = addr; let Inst{15-12} = CRd; let Inst{11-8} = cop; let Inst{7-0} = offset{7-0}; let DecoderMethod = "DecodeCopMemInstruction"; } def _OPTION : T2CI { bits<8> option; bits<4> addr; bits<4> cop; bits<4> CRd; let Inst{24} = 0; // P = 0 let Inst{23} = 1; // U = 1 let Inst{22} = Dbit; let Inst{21} = 0; // W = 0 let Inst{20} = load; let Inst{19-16} = addr; let Inst{15-12} = CRd; let Inst{11-8} = cop; let Inst{7-0} = option; let DecoderMethod = "DecodeCopMemInstruction"; } } defm t2LDC : t2LdStCop<0b1110, 1, 0, "ldc">; defm t2LDCL : t2LdStCop<0b1110, 1, 1, "ldcl">; defm t2STC : t2LdStCop<0b1110, 0, 0, "stc">; defm t2STCL : t2LdStCop<0b1110, 0, 1, "stcl">; defm t2LDC2 : t2LdStCop<0b1111, 1, 0, "ldc2">; defm t2LDC2L : t2LdStCop<0b1111, 1, 1, "ldc2l">; defm t2STC2 : t2LdStCop<0b1111, 0, 0, "stc2">; defm t2STC2L : t2LdStCop<0b1111, 0, 1, "stc2l">; //===----------------------------------------------------------------------===// // Move between special register and ARM core register -- for disassembly only // // Move to ARM core register from Special Register // A/R class MRS. // // A/R class can only move from CPSR or SPSR. def t2MRS_AR : T2I<(outs GPR:$Rd), (ins), NoItinerary, "mrs", "\t$Rd, apsr", []>, Requires<[IsThumb2,IsARClass]> { bits<4> Rd; let Inst{31-12} = 0b11110011111011111000; let Inst{11-8} = Rd; let Inst{7-0} = 0b0000; } def : t2InstAlias<"mrs${p} $Rd, cpsr", (t2MRS_AR GPR:$Rd, pred:$p)>; def t2MRSsys_AR: T2I<(outs GPR:$Rd), (ins), NoItinerary, "mrs", "\t$Rd, spsr", []>, Requires<[IsThumb2,IsARClass]> { bits<4> Rd; let Inst{31-12} = 0b11110011111111111000; let Inst{11-8} = Rd; let Inst{7-0} = 0b0000; } // M class MRS. // // This MRS has a mask field in bits 7-0 and can take more values than // the A/R class (a full msr_mask). def t2MRS_M : T2I<(outs rGPR:$Rd), (ins msr_mask:$mask), NoItinerary, "mrs", "\t$Rd, $mask", []>, Requires<[IsThumb2,IsMClass]> { bits<4> Rd; bits<8> mask; let Inst{31-12} = 0b11110011111011111000; let Inst{11-8} = Rd; let Inst{19-16} = 0b1111; let Inst{7-0} = mask; } // Move from ARM core register to Special Register // // A/R class MSR. // // No need to have both system and application versions, the encodings are the // same and the assembly parser has no way to distinguish between them. The mask // operand contains the special register (R Bit) in bit 4 and bits 3-0 contains // the mask with the fields to be accessed in the special register. def t2MSR_AR : T2I<(outs), (ins msr_mask:$mask, rGPR:$Rn), NoItinerary, "msr", "\t$mask, $Rn", []>, Requires<[IsThumb2,IsARClass]> { bits<5> mask; bits<4> Rn; let Inst{31-21} = 0b11110011100; let Inst{20} = mask{4}; // R Bit let Inst{19-16} = Rn; let Inst{15-12} = 0b1000; let Inst{11-8} = mask{3-0}; let Inst{7-0} = 0; } // M class MSR. // // Move from ARM core register to Special Register def t2MSR_M : T2I<(outs), (ins msr_mask:$SYSm, rGPR:$Rn), NoItinerary, "msr", "\t$SYSm, $Rn", []>, Requires<[IsThumb2,IsMClass]> { bits<8> SYSm; bits<4> Rn; let Inst{31-21} = 0b11110011100; let Inst{20} = 0b0; let Inst{19-16} = Rn; let Inst{15-12} = 0b1000; let Inst{7-0} = SYSm; } //===----------------------------------------------------------------------===// // Move between coprocessor and ARM core register // class t2MovRCopro Op, string opc, bit direction, dag oops, dag iops, list pattern> : T2Cop { let Inst{27-24} = 0b1110; let Inst{20} = direction; let Inst{4} = 1; bits<4> Rt; bits<4> cop; bits<3> opc1; bits<3> opc2; bits<4> CRm; bits<4> CRn; let Inst{15-12} = Rt; let Inst{11-8} = cop; let Inst{23-21} = opc1; let Inst{7-5} = opc2; let Inst{3-0} = CRm; let Inst{19-16} = CRn; } class t2MovRRCopro Op, string opc, bit direction, list pattern = []> : T2Cop { let Inst{27-24} = 0b1100; let Inst{23-21} = 0b010; let Inst{20} = direction; bits<4> Rt; bits<4> Rt2; bits<4> cop; bits<4> opc1; bits<4> CRm; let Inst{15-12} = Rt; let Inst{19-16} = Rt2; let Inst{11-8} = cop; let Inst{7-4} = opc1; let Inst{3-0} = CRm; } /* from ARM core register to coprocessor */ def t2MCR : t2MovRCopro<0b1110, "mcr", 0, (outs), (ins p_imm:$cop, imm0_7:$opc1, GPR:$Rt, c_imm:$CRn, c_imm:$CRm, imm0_7:$opc2), [(int_arm_mcr imm:$cop, imm:$opc1, GPR:$Rt, imm:$CRn, imm:$CRm, imm:$opc2)]>; def t2MCR2 : t2MovRCopro<0b1111, "mcr2", 0, (outs), (ins p_imm:$cop, imm0_7:$opc1, GPR:$Rt, c_imm:$CRn, c_imm:$CRm, imm0_7:$opc2), [(int_arm_mcr2 imm:$cop, imm:$opc1, GPR:$Rt, imm:$CRn, imm:$CRm, imm:$opc2)]>; /* from coprocessor to ARM core register */ def t2MRC : t2MovRCopro<0b1110, "mrc", 1, (outs GPR:$Rt), (ins p_imm:$cop, imm0_7:$opc1, c_imm:$CRn, c_imm:$CRm, imm0_7:$opc2), []>; def t2MRC2 : t2MovRCopro<0b1111, "mrc2", 1, (outs GPR:$Rt), (ins p_imm:$cop, imm0_7:$opc1, c_imm:$CRn, c_imm:$CRm, imm0_7:$opc2), []>; def : T2v6Pat<(int_arm_mrc imm:$cop, imm:$opc1, imm:$CRn, imm:$CRm, imm:$opc2), (t2MRC imm:$cop, imm:$opc1, imm:$CRn, imm:$CRm, imm:$opc2)>; def : T2v6Pat<(int_arm_mrc2 imm:$cop, imm:$opc1, imm:$CRn, imm:$CRm, imm:$opc2), (t2MRC2 imm:$cop, imm:$opc1, imm:$CRn, imm:$CRm, imm:$opc2)>; /* from ARM core register to coprocessor */ def t2MCRR : t2MovRRCopro<0b1110, "mcrr", 0, [(int_arm_mcrr imm:$cop, imm:$opc1, GPR:$Rt, GPR:$Rt2, imm:$CRm)]>; def t2MCRR2 : t2MovRRCopro<0b1111, "mcrr2", 0, [(int_arm_mcrr2 imm:$cop, imm:$opc1, GPR:$Rt, GPR:$Rt2, imm:$CRm)]>; /* from coprocessor to ARM core register */ def t2MRRC : t2MovRRCopro<0b1110, "mrrc", 1>; def t2MRRC2 : t2MovRRCopro<0b1111, "mrrc2", 1>; //===----------------------------------------------------------------------===// // Other Coprocessor Instructions. // def tCDP : T2Cop<0b1110, (outs), (ins p_imm:$cop, imm0_15:$opc1, c_imm:$CRd, c_imm:$CRn, c_imm:$CRm, imm0_7:$opc2), "cdp\t$cop, $opc1, $CRd, $CRn, $CRm, $opc2", [(int_arm_cdp imm:$cop, imm:$opc1, imm:$CRd, imm:$CRn, imm:$CRm, imm:$opc2)]> { let Inst{27-24} = 0b1110; bits<4> opc1; bits<4> CRn; bits<4> CRd; bits<4> cop; bits<3> opc2; bits<4> CRm; let Inst{3-0} = CRm; let Inst{4} = 0; let Inst{7-5} = opc2; let Inst{11-8} = cop; let Inst{15-12} = CRd; let Inst{19-16} = CRn; let Inst{23-20} = opc1; } def t2CDP2 : T2Cop<0b1111, (outs), (ins p_imm:$cop, imm0_15:$opc1, c_imm:$CRd, c_imm:$CRn, c_imm:$CRm, imm0_7:$opc2), "cdp2\t$cop, $opc1, $CRd, $CRn, $CRm, $opc2", [(int_arm_cdp2 imm:$cop, imm:$opc1, imm:$CRd, imm:$CRn, imm:$CRm, imm:$opc2)]> { let Inst{27-24} = 0b1110; bits<4> opc1; bits<4> CRn; bits<4> CRd; bits<4> cop; bits<3> opc2; bits<4> CRm; let Inst{3-0} = CRm; let Inst{4} = 0; let Inst{7-5} = opc2; let Inst{11-8} = cop; let Inst{15-12} = CRd; let Inst{19-16} = CRn; let Inst{23-20} = opc1; } //===----------------------------------------------------------------------===// // Non-Instruction Patterns // // SXT/UXT with no rotate let AddedComplexity = 16 in { def : T2Pat<(and rGPR:$Rm, 0x000000FF), (t2UXTB rGPR:$Rm, 0)>, Requires<[IsThumb2]>; def : T2Pat<(and rGPR:$Rm, 0x0000FFFF), (t2UXTH rGPR:$Rm, 0)>, Requires<[IsThumb2]>; def : T2Pat<(and rGPR:$Rm, 0x00FF00FF), (t2UXTB16 rGPR:$Rm, 0)>, Requires<[HasT2ExtractPack, IsThumb2]>; def : T2Pat<(add rGPR:$Rn, (and rGPR:$Rm, 0x00FF)), (t2UXTAB rGPR:$Rn, rGPR:$Rm, 0)>, Requires<[HasT2ExtractPack, IsThumb2]>; def : T2Pat<(add rGPR:$Rn, (and rGPR:$Rm, 0xFFFF)), (t2UXTAH rGPR:$Rn, rGPR:$Rm, 0)>, Requires<[HasT2ExtractPack, IsThumb2]>; } def : T2Pat<(sext_inreg rGPR:$Src, i8), (t2SXTB rGPR:$Src, 0)>, Requires<[IsThumb2]>; def : T2Pat<(sext_inreg rGPR:$Src, i16), (t2SXTH rGPR:$Src, 0)>, Requires<[IsThumb2]>; def : T2Pat<(add rGPR:$Rn, (sext_inreg rGPR:$Rm, i8)), (t2SXTAB rGPR:$Rn, rGPR:$Rm, 0)>, Requires<[HasT2ExtractPack, IsThumb2]>; def : T2Pat<(add rGPR:$Rn, (sext_inreg rGPR:$Rm, i16)), (t2SXTAH rGPR:$Rn, rGPR:$Rm, 0)>, Requires<[HasT2ExtractPack, IsThumb2]>; // Atomic load/store patterns def : T2Pat<(atomic_load_8 t2addrmode_imm12:$addr), (t2LDRBi12 t2addrmode_imm12:$addr)>; def : T2Pat<(atomic_load_8 t2addrmode_negimm8:$addr), (t2LDRBi8 t2addrmode_negimm8:$addr)>; def : T2Pat<(atomic_load_8 t2addrmode_so_reg:$addr), (t2LDRBs t2addrmode_so_reg:$addr)>; def : T2Pat<(atomic_load_16 t2addrmode_imm12:$addr), (t2LDRHi12 t2addrmode_imm12:$addr)>; def : T2Pat<(atomic_load_16 t2addrmode_negimm8:$addr), (t2LDRHi8 t2addrmode_negimm8:$addr)>; def : T2Pat<(atomic_load_16 t2addrmode_so_reg:$addr), (t2LDRHs t2addrmode_so_reg:$addr)>; def : T2Pat<(atomic_load_32 t2addrmode_imm12:$addr), (t2LDRi12 t2addrmode_imm12:$addr)>; def : T2Pat<(atomic_load_32 t2addrmode_negimm8:$addr), (t2LDRi8 t2addrmode_negimm8:$addr)>; def : T2Pat<(atomic_load_32 t2addrmode_so_reg:$addr), (t2LDRs t2addrmode_so_reg:$addr)>; def : T2Pat<(atomic_store_8 t2addrmode_imm12:$addr, GPR:$val), (t2STRBi12 GPR:$val, t2addrmode_imm12:$addr)>; def : T2Pat<(atomic_store_8 t2addrmode_negimm8:$addr, GPR:$val), (t2STRBi8 GPR:$val, t2addrmode_negimm8:$addr)>; def : T2Pat<(atomic_store_8 t2addrmode_so_reg:$addr, GPR:$val), (t2STRBs GPR:$val, t2addrmode_so_reg:$addr)>; def : T2Pat<(atomic_store_16 t2addrmode_imm12:$addr, GPR:$val), (t2STRHi12 GPR:$val, t2addrmode_imm12:$addr)>; def : T2Pat<(atomic_store_16 t2addrmode_negimm8:$addr, GPR:$val), (t2STRHi8 GPR:$val, t2addrmode_negimm8:$addr)>; def : T2Pat<(atomic_store_16 t2addrmode_so_reg:$addr, GPR:$val), (t2STRHs GPR:$val, t2addrmode_so_reg:$addr)>; def : T2Pat<(atomic_store_32 t2addrmode_imm12:$addr, GPR:$val), (t2STRi12 GPR:$val, t2addrmode_imm12:$addr)>; def : T2Pat<(atomic_store_32 t2addrmode_negimm8:$addr, GPR:$val), (t2STRi8 GPR:$val, t2addrmode_negimm8:$addr)>; def : T2Pat<(atomic_store_32 t2addrmode_so_reg:$addr, GPR:$val), (t2STRs GPR:$val, t2addrmode_so_reg:$addr)>; //===----------------------------------------------------------------------===// // Assembler aliases // // Aliases for ADC without the ".w" optional width specifier. def : t2InstAlias<"adc${s}${p} $Rd, $Rn, $Rm", (t2ADCrr rGPR:$Rd, rGPR:$Rn, rGPR:$Rm, pred:$p, cc_out:$s)>; def : t2InstAlias<"adc${s}${p} $Rd, $Rn, $ShiftedRm", (t2ADCrs rGPR:$Rd, rGPR:$Rn, t2_so_reg:$ShiftedRm, pred:$p, cc_out:$s)>; // Aliases for SBC without the ".w" optional width specifier. def : t2InstAlias<"sbc${s}${p} $Rd, $Rn, $Rm", (t2SBCrr rGPR:$Rd, rGPR:$Rn, rGPR:$Rm, pred:$p, cc_out:$s)>; def : t2InstAlias<"sbc${s}${p} $Rd, $Rn, $ShiftedRm", (t2SBCrs rGPR:$Rd, rGPR:$Rn, t2_so_reg:$ShiftedRm, pred:$p, cc_out:$s)>; // Aliases for ADD without the ".w" optional width specifier. def : t2InstAlias<"add${s}${p} $Rd, $Rn, $imm", (t2ADDri GPRnopc:$Rd, GPRnopc:$Rn, t2_so_imm:$imm, pred:$p, cc_out:$s)>; def : t2InstAlias<"add${p} $Rd, $Rn, $imm", (t2ADDri12 GPRnopc:$Rd, GPR:$Rn, imm0_4095:$imm, pred:$p)>; def : t2InstAlias<"add${s}${p} $Rd, $Rn, $Rm", (t2ADDrr GPRnopc:$Rd, GPRnopc:$Rn, rGPR:$Rm, pred:$p, cc_out:$s)>; def : t2InstAlias<"add${s}${p} $Rd, $Rn, $ShiftedRm", (t2ADDrs GPRnopc:$Rd, GPRnopc:$Rn, t2_so_reg:$ShiftedRm, pred:$p, cc_out:$s)>; // Aliases for SUB without the ".w" optional width specifier. def : t2InstAlias<"sub${s}${p} $Rd, $Rn, $imm", (t2SUBri GPRnopc:$Rd, GPRnopc:$Rn, t2_so_imm:$imm, pred:$p, cc_out:$s)>; def : t2InstAlias<"sub${p} $Rd, $Rn, $imm", (t2SUBri12 GPRnopc:$Rd, GPR:$Rn, imm0_4095:$imm, pred:$p)>; def : t2InstAlias<"sub${s}${p} $Rd, $Rn, $Rm", (t2SUBrr GPRnopc:$Rd, GPRnopc:$Rn, rGPR:$Rm, pred:$p, cc_out:$s)>; def : t2InstAlias<"sub${s}${p} $Rd, $Rn, $ShiftedRm", (t2SUBrs GPRnopc:$Rd, GPRnopc:$Rn, t2_so_reg:$ShiftedRm, pred:$p, cc_out:$s)>; // Alias for compares without the ".w" optional width specifier. def : t2InstAlias<"cmn${p} $Rn, $Rm", (t2CMNzrr GPRnopc:$Rn, rGPR:$Rm, pred:$p)>; def : t2InstAlias<"teq${p} $Rn, $Rm", (t2TEQrr GPRnopc:$Rn, rGPR:$Rm, pred:$p)>; def : t2InstAlias<"tst${p} $Rn, $Rm", (t2TSTrr GPRnopc:$Rn, rGPR:$Rm, pred:$p)>; // Memory barriers def : InstAlias<"dmb", (t2DMB 0xf)>, Requires<[IsThumb2, HasDB]>; def : InstAlias<"dsb", (t2DSB 0xf)>, Requires<[IsThumb2, HasDB]>; def : InstAlias<"isb", (t2ISB 0xf)>, Requires<[IsThumb2, HasDB]>; // Alias for LDR, LDRB, LDRH, LDRSB, and LDRSH without the ".w" optional // width specifier. def : t2InstAlias<"ldr${p} $Rt, $addr", (t2LDRi12 GPR:$Rt, t2addrmode_imm12:$addr, pred:$p)>; def : t2InstAlias<"ldrb${p} $Rt, $addr", (t2LDRBi12 rGPR:$Rt, t2addrmode_imm12:$addr, pred:$p)>; def : t2InstAlias<"ldrh${p} $Rt, $addr", (t2LDRHi12 rGPR:$Rt, t2addrmode_imm12:$addr, pred:$p)>; def : t2InstAlias<"ldrsb${p} $Rt, $addr", (t2LDRSBi12 rGPR:$Rt, t2addrmode_imm12:$addr, pred:$p)>; def : t2InstAlias<"ldrsh${p} $Rt, $addr", (t2LDRSHi12 rGPR:$Rt, t2addrmode_imm12:$addr, pred:$p)>; def : t2InstAlias<"ldr${p} $Rt, $addr", (t2LDRs GPR:$Rt, t2addrmode_so_reg:$addr, pred:$p)>; def : t2InstAlias<"ldrb${p} $Rt, $addr", (t2LDRBs rGPR:$Rt, t2addrmode_so_reg:$addr, pred:$p)>; def : t2InstAlias<"ldrh${p} $Rt, $addr", (t2LDRHs rGPR:$Rt, t2addrmode_so_reg:$addr, pred:$p)>; def : t2InstAlias<"ldrsb${p} $Rt, $addr", (t2LDRSBs rGPR:$Rt, t2addrmode_so_reg:$addr, pred:$p)>; def : t2InstAlias<"ldrsh${p} $Rt, $addr", (t2LDRSHs rGPR:$Rt, t2addrmode_so_reg:$addr, pred:$p)>; // Alias for MVN without the ".w" optional width specifier. def : t2InstAlias<"mvn${s}${p} $Rd, $Rm", (t2MVNr rGPR:$Rd, rGPR:$Rm, pred:$p, cc_out:$s)>; def : t2InstAlias<"mvn${s}${p} $Rd, $ShiftedRm", (t2MVNs rGPR:$Rd, t2_so_reg:$ShiftedRm, pred:$p, cc_out:$s)>; // PKHBT/PKHTB with default shift amount. PKHTB is equivalent to PKHBT when the // shift amount is zero (i.e., unspecified). def : InstAlias<"pkhbt${p} $Rd, $Rn, $Rm", (t2PKHBT rGPR:$Rd, rGPR:$Rn, rGPR:$Rm, 0, pred:$p)>, Requires<[HasT2ExtractPack, IsThumb2]>; def : InstAlias<"pkhtb${p} $Rd, $Rn, $Rm", (t2PKHBT rGPR:$Rd, rGPR:$Rn, rGPR:$Rm, 0, pred:$p)>, Requires<[HasT2ExtractPack, IsThumb2]>; // PUSH/POP aliases for STM/LDM def : t2InstAlias<"push${p}.w $regs", (t2STMDB_UPD SP, pred:$p, reglist:$regs)>; def : t2InstAlias<"push${p} $regs", (t2STMDB_UPD SP, pred:$p, reglist:$regs)>; def : t2InstAlias<"pop${p}.w $regs", (t2LDMIA_UPD SP, pred:$p, reglist:$regs)>; def : t2InstAlias<"pop${p} $regs", (t2LDMIA_UPD SP, pred:$p, reglist:$regs)>; // Alias for REV/REV16/REVSH without the ".w" optional width specifier. def : t2InstAlias<"rev${p} $Rd, $Rm", (t2REV rGPR:$Rd, rGPR:$Rm, pred:$p)>; def : t2InstAlias<"rev16${p} $Rd, $Rm", (t2REV16 rGPR:$Rd, rGPR:$Rm, pred:$p)>; def : t2InstAlias<"revsh${p} $Rd, $Rm", (t2REVSH rGPR:$Rd, rGPR:$Rm, pred:$p)>; // Alias for RSB without the ".w" optional width specifier, and with optional // implied destination register. def : t2InstAlias<"rsb${s}${p} $Rd, $Rn, $imm", (t2RSBri rGPR:$Rd, rGPR:$Rn, t2_so_imm:$imm, pred:$p, cc_out:$s)>; def : t2InstAlias<"rsb${s}${p} $Rdn, $imm", (t2RSBri rGPR:$Rdn, rGPR:$Rdn, t2_so_imm:$imm, pred:$p, cc_out:$s)>; def : t2InstAlias<"rsb${s}${p} $Rdn, $Rm", (t2RSBrr rGPR:$Rdn, rGPR:$Rdn, rGPR:$Rm, pred:$p, cc_out:$s)>; def : t2InstAlias<"rsb${s}${p} $Rdn, $ShiftedRm", (t2RSBrs rGPR:$Rdn, rGPR:$Rdn, t2_so_reg:$ShiftedRm, pred:$p, cc_out:$s)>; // SSAT/USAT optional shift operand. def : t2InstAlias<"ssat${p} $Rd, $sat_imm, $Rn", (t2SSAT rGPR:$Rd, imm1_32:$sat_imm, rGPR:$Rn, 0, pred:$p)>; def : t2InstAlias<"usat${p} $Rd, $sat_imm, $Rn", (t2USAT rGPR:$Rd, imm0_31:$sat_imm, rGPR:$Rn, 0, pred:$p)>; // STM w/o the .w suffix. def : t2InstAlias<"stm${p} $Rn, $regs", (t2STMIA GPR:$Rn, pred:$p, reglist:$regs)>; // Alias for STR, STRB, and STRH without the ".w" optional // width specifier. def : t2InstAlias<"str${p} $Rt, $addr", (t2STRi12 GPR:$Rt, t2addrmode_imm12:$addr, pred:$p)>; def : t2InstAlias<"strb${p} $Rt, $addr", (t2STRBi12 rGPR:$Rt, t2addrmode_imm12:$addr, pred:$p)>; def : t2InstAlias<"strh${p} $Rt, $addr", (t2STRHi12 rGPR:$Rt, t2addrmode_imm12:$addr, pred:$p)>; def : t2InstAlias<"str${p} $Rt, $addr", (t2STRs GPR:$Rt, t2addrmode_so_reg:$addr, pred:$p)>; def : t2InstAlias<"strb${p} $Rt, $addr", (t2STRBs rGPR:$Rt, t2addrmode_so_reg:$addr, pred:$p)>; def : t2InstAlias<"strh${p} $Rt, $addr", (t2STRHs rGPR:$Rt, t2addrmode_so_reg:$addr, pred:$p)>; // Extend instruction optional rotate operand. def : t2InstAlias<"sxtab${p} $Rd, $Rn, $Rm", (t2SXTAB rGPR:$Rd, rGPR:$Rn, rGPR:$Rm, 0, pred:$p)>; def : t2InstAlias<"sxtah${p} $Rd, $Rn, $Rm", (t2SXTAH rGPR:$Rd, rGPR:$Rn, rGPR:$Rm, 0, pred:$p)>; def : t2InstAlias<"sxtab16${p} $Rd, $Rn, $Rm", (t2SXTAB16 rGPR:$Rd, rGPR:$Rn, rGPR:$Rm, 0, pred:$p)>; def : t2InstAlias<"sxtb${p} $Rd, $Rm", (t2SXTB rGPR:$Rd, rGPR:$Rm, 0, pred:$p)>; def : t2InstAlias<"sxtb16${p} $Rd, $Rm", (t2SXTB16 rGPR:$Rd, rGPR:$Rm, 0, pred:$p)>; def : t2InstAlias<"sxth${p} $Rd, $Rm", (t2SXTH rGPR:$Rd, rGPR:$Rm, 0, pred:$p)>; def : t2InstAlias<"sxtb${p}.w $Rd, $Rm", (t2SXTB rGPR:$Rd, rGPR:$Rm, 0, pred:$p)>; def : t2InstAlias<"sxth${p}.w $Rd, $Rm", (t2SXTH rGPR:$Rd, rGPR:$Rm, 0, pred:$p)>; def : t2InstAlias<"uxtab${p} $Rd, $Rn, $Rm", (t2UXTAB rGPR:$Rd, rGPR:$Rn, rGPR:$Rm, 0, pred:$p)>; def : t2InstAlias<"uxtah${p} $Rd, $Rn, $Rm", (t2UXTAH rGPR:$Rd, rGPR:$Rn, rGPR:$Rm, 0, pred:$p)>; def : t2InstAlias<"uxtab16${p} $Rd, $Rn, $Rm", (t2UXTAB16 rGPR:$Rd, rGPR:$Rn, rGPR:$Rm, 0, pred:$p)>; def : t2InstAlias<"uxtb${p} $Rd, $Rm", (t2UXTB rGPR:$Rd, rGPR:$Rm, 0, pred:$p)>; def : t2InstAlias<"uxtb16${p} $Rd, $Rm", (t2UXTB16 rGPR:$Rd, rGPR:$Rm, 0, pred:$p)>; def : t2InstAlias<"uxth${p} $Rd, $Rm", (t2UXTH rGPR:$Rd, rGPR:$Rm, 0, pred:$p)>; def : t2InstAlias<"uxtb${p}.w $Rd, $Rm", (t2UXTB rGPR:$Rd, rGPR:$Rm, 0, pred:$p)>; def : t2InstAlias<"uxth${p}.w $Rd, $Rm", (t2UXTH rGPR:$Rd, rGPR:$Rm, 0, pred:$p)>; // Extend instruction w/o the ".w" optional width specifier. def : t2InstAlias<"uxtb${p} $Rd, $Rm$rot", (t2UXTB rGPR:$Rd, rGPR:$Rm, rot_imm:$rot, pred:$p)>; def : t2InstAlias<"uxtb16${p} $Rd, $Rm$rot", (t2UXTB16 rGPR:$Rd, rGPR:$Rm, rot_imm:$rot, pred:$p)>; def : t2InstAlias<"uxth${p} $Rd, $Rm$rot", (t2UXTH rGPR:$Rd, rGPR:$Rm, rot_imm:$rot, pred:$p)>; def : t2InstAlias<"sxtb${p} $Rd, $Rm$rot", (t2SXTB rGPR:$Rd, rGPR:$Rm, rot_imm:$rot, pred:$p)>; def : t2InstAlias<"sxtb16${p} $Rd, $Rm$rot", (t2SXTB16 rGPR:$Rd, rGPR:$Rm, rot_imm:$rot, pred:$p)>; def : t2InstAlias<"sxth${p} $Rd, $Rm$rot", (t2SXTH rGPR:$Rd, rGPR:$Rm, rot_imm:$rot, pred:$p)>; Index: head/contrib/llvm/lib/Target/CppBackend/CPPBackend.cpp =================================================================== --- head/contrib/llvm/lib/Target/CppBackend/CPPBackend.cpp (revision 228378) +++ head/contrib/llvm/lib/Target/CppBackend/CPPBackend.cpp (revision 228379) @@ -1,1978 +1,2073 @@ //===-- CPPBackend.cpp - Library for converting LLVM code to C++ code -----===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the writing of the LLVM IR as a set of C++ calls to the // LLVM IR interface. The input module is assumed to be verified. // //===----------------------------------------------------------------------===// #include "CPPTargetMachine.h" #include "llvm/CallingConv.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" #include "llvm/InlineAsm.h" #include "llvm/Instruction.h" #include "llvm/Instructions.h" #include "llvm/Module.h" #include "llvm/Pass.h" #include "llvm/PassManager.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Config/config.h" #include #include #include using namespace llvm; static cl::opt FuncName("cppfname", cl::desc("Specify the name of the generated function"), cl::value_desc("function name")); enum WhatToGenerate { GenProgram, GenModule, GenContents, GenFunction, GenFunctions, GenInline, GenVariable, GenType }; static cl::opt GenerationType("cppgen", cl::Optional, cl::desc("Choose what kind of output to generate"), cl::init(GenProgram), cl::values( clEnumValN(GenProgram, "program", "Generate a complete program"), clEnumValN(GenModule, "module", "Generate a module definition"), clEnumValN(GenContents, "contents", "Generate contents of a module"), clEnumValN(GenFunction, "function", "Generate a function definition"), clEnumValN(GenFunctions,"functions", "Generate all function definitions"), clEnumValN(GenInline, "inline", "Generate an inline function"), clEnumValN(GenVariable, "variable", "Generate a variable definition"), clEnumValN(GenType, "type", "Generate a type definition"), clEnumValEnd ) ); static cl::opt NameToGenerate("cppfor", cl::Optional, cl::desc("Specify the name of the thing to generate"), cl::init("!bad!")); extern "C" void LLVMInitializeCppBackendTarget() { // Register the target. RegisterTargetMachine X(TheCppBackendTarget); } namespace { typedef std::vector TypeList; typedef std::map TypeMap; typedef std::map ValueMap; typedef std::set NameSet; typedef std::set TypeSet; typedef std::set ValueSet; typedef std::map ForwardRefMap; /// CppWriter - This class is the main chunk of code that converts an LLVM /// module to a C++ translation unit. class CppWriter : public ModulePass { formatted_raw_ostream &Out; const Module *TheModule; uint64_t uniqueNum; TypeMap TypeNames; ValueMap ValueNames; NameSet UsedNames; TypeSet DefinedTypes; ValueSet DefinedValues; ForwardRefMap ForwardRefs; bool is_inline; unsigned indent_level; public: static char ID; explicit CppWriter(formatted_raw_ostream &o) : ModulePass(ID), Out(o), uniqueNum(0), is_inline(false), indent_level(0){} virtual const char *getPassName() const { return "C++ backend"; } bool runOnModule(Module &M); void printProgram(const std::string& fname, const std::string& modName ); void printModule(const std::string& fname, const std::string& modName ); void printContents(const std::string& fname, const std::string& modName ); void printFunction(const std::string& fname, const std::string& funcName ); void printFunctions(); void printInline(const std::string& fname, const std::string& funcName ); void printVariable(const std::string& fname, const std::string& varName ); void printType(const std::string& fname, const std::string& typeName ); void error(const std::string& msg); formatted_raw_ostream& nl(formatted_raw_ostream &Out, int delta = 0); inline void in() { indent_level++; } inline void out() { if (indent_level >0) indent_level--; } private: void printLinkageType(GlobalValue::LinkageTypes LT); void printVisibilityType(GlobalValue::VisibilityTypes VisTypes); void printCallingConv(CallingConv::ID cc); void printEscapedString(const std::string& str); void printCFP(const ConstantFP* CFP); std::string getCppName(Type* val); inline void printCppName(Type* val); std::string getCppName(const Value* val); inline void printCppName(const Value* val); void printAttributes(const AttrListPtr &PAL, const std::string &name); void printType(Type* Ty); void printTypes(const Module* M); void printConstant(const Constant *CPV); void printConstants(const Module* M); void printVariableUses(const GlobalVariable *GV); void printVariableHead(const GlobalVariable *GV); void printVariableBody(const GlobalVariable *GV); void printFunctionUses(const Function *F); void printFunctionHead(const Function *F); void printFunctionBody(const Function *F); void printInstruction(const Instruction *I, const std::string& bbname); std::string getOpName(const Value*); void printModuleBody(); }; } // end anonymous namespace. formatted_raw_ostream &CppWriter::nl(formatted_raw_ostream &Out, int delta) { Out << '\n'; if (delta >= 0 || indent_level >= unsigned(-delta)) indent_level += delta; Out.indent(indent_level); return Out; } static inline void sanitize(std::string &str) { for (size_t i = 0; i < str.length(); ++i) if (!isalnum(str[i]) && str[i] != '_') str[i] = '_'; } static std::string getTypePrefix(Type *Ty) { switch (Ty->getTypeID()) { case Type::VoidTyID: return "void_"; case Type::IntegerTyID: return "int" + utostr(cast(Ty)->getBitWidth()) + "_"; case Type::FloatTyID: return "float_"; case Type::DoubleTyID: return "double_"; case Type::LabelTyID: return "label_"; case Type::FunctionTyID: return "func_"; case Type::StructTyID: return "struct_"; case Type::ArrayTyID: return "array_"; case Type::PointerTyID: return "ptr_"; case Type::VectorTyID: return "packed_"; default: return "other_"; } return "unknown_"; } void CppWriter::error(const std::string& msg) { report_fatal_error(msg); } // printCFP - Print a floating point constant .. very carefully :) // This makes sure that conversion to/from floating yields the same binary // result so that we don't lose precision. void CppWriter::printCFP(const ConstantFP *CFP) { bool ignored; APFloat APF = APFloat(CFP->getValueAPF()); // copy if (CFP->getType() == Type::getFloatTy(CFP->getContext())) APF.convert(APFloat::IEEEdouble, APFloat::rmNearestTiesToEven, &ignored); Out << "ConstantFP::get(mod->getContext(), "; Out << "APFloat("; #if HAVE_PRINTF_A char Buffer[100]; sprintf(Buffer, "%A", APF.convertToDouble()); if ((!strncmp(Buffer, "0x", 2) || !strncmp(Buffer, "-0x", 3) || !strncmp(Buffer, "+0x", 3)) && APF.bitwiseIsEqual(APFloat(atof(Buffer)))) { if (CFP->getType() == Type::getDoubleTy(CFP->getContext())) Out << "BitsToDouble(" << Buffer << ")"; else Out << "BitsToFloat((float)" << Buffer << ")"; Out << ")"; } else { #endif std::string StrVal = ftostr(CFP->getValueAPF()); while (StrVal[0] == ' ') StrVal.erase(StrVal.begin()); // Check to make sure that the stringized number is not some string like // "Inf" or NaN. Check that the string matches the "[-+]?[0-9]" regex. if (((StrVal[0] >= '0' && StrVal[0] <= '9') || ((StrVal[0] == '-' || StrVal[0] == '+') && (StrVal[1] >= '0' && StrVal[1] <= '9'))) && (CFP->isExactlyValue(atof(StrVal.c_str())))) { if (CFP->getType() == Type::getDoubleTy(CFP->getContext())) Out << StrVal; else Out << StrVal << "f"; } else if (CFP->getType() == Type::getDoubleTy(CFP->getContext())) Out << "BitsToDouble(0x" << utohexstr(CFP->getValueAPF().bitcastToAPInt().getZExtValue()) << "ULL) /* " << StrVal << " */"; else Out << "BitsToFloat(0x" << utohexstr((uint32_t)CFP->getValueAPF(). bitcastToAPInt().getZExtValue()) << "U) /* " << StrVal << " */"; Out << ")"; #if HAVE_PRINTF_A } #endif Out << ")"; } void CppWriter::printCallingConv(CallingConv::ID cc){ // Print the calling convention. switch (cc) { case CallingConv::C: Out << "CallingConv::C"; break; case CallingConv::Fast: Out << "CallingConv::Fast"; break; case CallingConv::Cold: Out << "CallingConv::Cold"; break; case CallingConv::FirstTargetCC: Out << "CallingConv::FirstTargetCC"; break; default: Out << cc; break; } } void CppWriter::printLinkageType(GlobalValue::LinkageTypes LT) { switch (LT) { case GlobalValue::InternalLinkage: Out << "GlobalValue::InternalLinkage"; break; case GlobalValue::PrivateLinkage: Out << "GlobalValue::PrivateLinkage"; break; case GlobalValue::LinkerPrivateLinkage: Out << "GlobalValue::LinkerPrivateLinkage"; break; case GlobalValue::LinkerPrivateWeakLinkage: Out << "GlobalValue::LinkerPrivateWeakLinkage"; break; case GlobalValue::LinkerPrivateWeakDefAutoLinkage: Out << "GlobalValue::LinkerPrivateWeakDefAutoLinkage"; break; case GlobalValue::AvailableExternallyLinkage: Out << "GlobalValue::AvailableExternallyLinkage "; break; case GlobalValue::LinkOnceAnyLinkage: Out << "GlobalValue::LinkOnceAnyLinkage "; break; case GlobalValue::LinkOnceODRLinkage: Out << "GlobalValue::LinkOnceODRLinkage "; break; case GlobalValue::WeakAnyLinkage: Out << "GlobalValue::WeakAnyLinkage"; break; case GlobalValue::WeakODRLinkage: Out << "GlobalValue::WeakODRLinkage"; break; case GlobalValue::AppendingLinkage: Out << "GlobalValue::AppendingLinkage"; break; case GlobalValue::ExternalLinkage: Out << "GlobalValue::ExternalLinkage"; break; case GlobalValue::DLLImportLinkage: Out << "GlobalValue::DLLImportLinkage"; break; case GlobalValue::DLLExportLinkage: Out << "GlobalValue::DLLExportLinkage"; break; case GlobalValue::ExternalWeakLinkage: Out << "GlobalValue::ExternalWeakLinkage"; break; case GlobalValue::CommonLinkage: Out << "GlobalValue::CommonLinkage"; break; } } void CppWriter::printVisibilityType(GlobalValue::VisibilityTypes VisType) { switch (VisType) { default: llvm_unreachable("Unknown GVar visibility"); case GlobalValue::DefaultVisibility: Out << "GlobalValue::DefaultVisibility"; break; case GlobalValue::HiddenVisibility: Out << "GlobalValue::HiddenVisibility"; break; case GlobalValue::ProtectedVisibility: Out << "GlobalValue::ProtectedVisibility"; break; } } // printEscapedString - Print each character of the specified string, escaping // it if it is not printable or if it is an escape char. void CppWriter::printEscapedString(const std::string &Str) { for (unsigned i = 0, e = Str.size(); i != e; ++i) { unsigned char C = Str[i]; if (isprint(C) && C != '"' && C != '\\') { Out << C; } else { Out << "\\x" << (char) ((C/16 < 10) ? ( C/16 +'0') : ( C/16 -10+'A')) << (char)(((C&15) < 10) ? ((C&15)+'0') : ((C&15)-10+'A')); } } } std::string CppWriter::getCppName(Type* Ty) { // First, handle the primitive types .. easy if (Ty->isPrimitiveType() || Ty->isIntegerTy()) { switch (Ty->getTypeID()) { case Type::VoidTyID: return "Type::getVoidTy(mod->getContext())"; case Type::IntegerTyID: { unsigned BitWidth = cast(Ty)->getBitWidth(); return "IntegerType::get(mod->getContext(), " + utostr(BitWidth) + ")"; } case Type::X86_FP80TyID: return "Type::getX86_FP80Ty(mod->getContext())"; case Type::FloatTyID: return "Type::getFloatTy(mod->getContext())"; case Type::DoubleTyID: return "Type::getDoubleTy(mod->getContext())"; case Type::LabelTyID: return "Type::getLabelTy(mod->getContext())"; case Type::X86_MMXTyID: return "Type::getX86_MMXTy(mod->getContext())"; default: error("Invalid primitive type"); break; } // shouldn't be returned, but make it sensible return "Type::getVoidTy(mod->getContext())"; } // Now, see if we've seen the type before and return that TypeMap::iterator I = TypeNames.find(Ty); if (I != TypeNames.end()) return I->second; // Okay, let's build a new name for this type. Start with a prefix const char* prefix = 0; switch (Ty->getTypeID()) { case Type::FunctionTyID: prefix = "FuncTy_"; break; case Type::StructTyID: prefix = "StructTy_"; break; case Type::ArrayTyID: prefix = "ArrayTy_"; break; case Type::PointerTyID: prefix = "PointerTy_"; break; case Type::VectorTyID: prefix = "VectorTy_"; break; default: prefix = "OtherTy_"; break; // prevent breakage } // See if the type has a name in the symboltable and build accordingly std::string name; if (StructType *STy = dyn_cast(Ty)) if (STy->hasName()) name = STy->getName(); if (name.empty()) name = utostr(uniqueNum++); name = std::string(prefix) + name; sanitize(name); // Save the name return TypeNames[Ty] = name; } void CppWriter::printCppName(Type* Ty) { printEscapedString(getCppName(Ty)); } std::string CppWriter::getCppName(const Value* val) { std::string name; ValueMap::iterator I = ValueNames.find(val); if (I != ValueNames.end() && I->first == val) return I->second; if (const GlobalVariable* GV = dyn_cast(val)) { name = std::string("gvar_") + getTypePrefix(GV->getType()->getElementType()); } else if (isa(val)) { name = std::string("func_"); } else if (const Constant* C = dyn_cast(val)) { name = std::string("const_") + getTypePrefix(C->getType()); } else if (const Argument* Arg = dyn_cast(val)) { if (is_inline) { unsigned argNum = std::distance(Arg->getParent()->arg_begin(), Function::const_arg_iterator(Arg)) + 1; name = std::string("arg_") + utostr(argNum); NameSet::iterator NI = UsedNames.find(name); if (NI != UsedNames.end()) name += std::string("_") + utostr(uniqueNum++); UsedNames.insert(name); return ValueNames[val] = name; } else { name = getTypePrefix(val->getType()); } } else { name = getTypePrefix(val->getType()); } if (val->hasName()) name += val->getName(); else name += utostr(uniqueNum++); sanitize(name); NameSet::iterator NI = UsedNames.find(name); if (NI != UsedNames.end()) name += std::string("_") + utostr(uniqueNum++); UsedNames.insert(name); return ValueNames[val] = name; } void CppWriter::printCppName(const Value* val) { printEscapedString(getCppName(val)); } void CppWriter::printAttributes(const AttrListPtr &PAL, const std::string &name) { Out << "AttrListPtr " << name << "_PAL;"; nl(Out); if (!PAL.isEmpty()) { Out << '{'; in(); nl(Out); Out << "SmallVector Attrs;"; nl(Out); Out << "AttributeWithIndex PAWI;"; nl(Out); for (unsigned i = 0; i < PAL.getNumSlots(); ++i) { unsigned index = PAL.getSlot(i).Index; Attributes attrs = PAL.getSlot(i).Attrs; Out << "PAWI.Index = " << index << "U; PAWI.Attrs = 0 "; #define HANDLE_ATTR(X) \ if (attrs & Attribute::X) \ Out << " | Attribute::" #X; \ attrs &= ~Attribute::X; HANDLE_ATTR(SExt); HANDLE_ATTR(ZExt); HANDLE_ATTR(NoReturn); HANDLE_ATTR(InReg); HANDLE_ATTR(StructRet); HANDLE_ATTR(NoUnwind); HANDLE_ATTR(NoAlias); HANDLE_ATTR(ByVal); HANDLE_ATTR(Nest); HANDLE_ATTR(ReadNone); HANDLE_ATTR(ReadOnly); HANDLE_ATTR(NoInline); HANDLE_ATTR(AlwaysInline); HANDLE_ATTR(OptimizeForSize); HANDLE_ATTR(StackProtect); HANDLE_ATTR(StackProtectReq); HANDLE_ATTR(NoCapture); HANDLE_ATTR(NoRedZone); HANDLE_ATTR(NoImplicitFloat); HANDLE_ATTR(Naked); HANDLE_ATTR(InlineHint); HANDLE_ATTR(ReturnsTwice); HANDLE_ATTR(UWTable); HANDLE_ATTR(NonLazyBind); #undef HANDLE_ATTR if (attrs & Attribute::StackAlignment) Out << " | Attribute::constructStackAlignmentFromInt(" << Attribute::getStackAlignmentFromAttrs(attrs) << ")"; attrs &= ~Attribute::StackAlignment; assert(attrs == 0 && "Unhandled attribute!"); Out << ";"; nl(Out); Out << "Attrs.push_back(PAWI);"; nl(Out); } Out << name << "_PAL = AttrListPtr::get(Attrs.begin(), Attrs.end());"; nl(Out); out(); nl(Out); Out << '}'; nl(Out); } } void CppWriter::printType(Type* Ty) { // We don't print definitions for primitive types if (Ty->isPrimitiveType() || Ty->isIntegerTy()) return; // If we already defined this type, we don't need to define it again. if (DefinedTypes.find(Ty) != DefinedTypes.end()) return; // Everything below needs the name for the type so get it now. std::string typeName(getCppName(Ty)); // Print the type definition switch (Ty->getTypeID()) { case Type::FunctionTyID: { FunctionType* FT = cast(Ty); Out << "std::vector" << typeName << "_args;"; nl(Out); FunctionType::param_iterator PI = FT->param_begin(); FunctionType::param_iterator PE = FT->param_end(); for (; PI != PE; ++PI) { Type* argTy = static_cast(*PI); printType(argTy); std::string argName(getCppName(argTy)); Out << typeName << "_args.push_back(" << argName; Out << ");"; nl(Out); } printType(FT->getReturnType()); std::string retTypeName(getCppName(FT->getReturnType())); Out << "FunctionType* " << typeName << " = FunctionType::get("; in(); nl(Out) << "/*Result=*/" << retTypeName; Out << ","; nl(Out) << "/*Params=*/" << typeName << "_args,"; nl(Out) << "/*isVarArg=*/" << (FT->isVarArg() ? "true" : "false") << ");"; out(); nl(Out); break; } case Type::StructTyID: { StructType* ST = cast(Ty); if (!ST->isLiteral()) { Out << "StructType *" << typeName << " = mod->getTypeByName(\""; printEscapedString(ST->getName()); Out << "\");"; nl(Out); Out << "if (!" << typeName << ") {"; nl(Out); Out << typeName << " = "; Out << "StructType::create(mod->getContext(), \""; printEscapedString(ST->getName()); Out << "\");"; nl(Out); Out << "}"; nl(Out); // Indicate that this type is now defined. DefinedTypes.insert(Ty); } Out << "std::vector" << typeName << "_fields;"; nl(Out); StructType::element_iterator EI = ST->element_begin(); StructType::element_iterator EE = ST->element_end(); for (; EI != EE; ++EI) { Type* fieldTy = static_cast(*EI); printType(fieldTy); std::string fieldName(getCppName(fieldTy)); Out << typeName << "_fields.push_back(" << fieldName; Out << ");"; nl(Out); } if (ST->isLiteral()) { Out << "StructType *" << typeName << " = "; Out << "StructType::get(" << "mod->getContext(), "; } else { Out << "if (" << typeName << "->isOpaque()) {"; nl(Out); Out << typeName << "->setBody("; } Out << typeName << "_fields, /*isPacked=*/" << (ST->isPacked() ? "true" : "false") << ");"; nl(Out); if (!ST->isLiteral()) { Out << "}"; nl(Out); } break; } case Type::ArrayTyID: { ArrayType* AT = cast(Ty); Type* ET = AT->getElementType(); printType(ET); if (DefinedTypes.find(Ty) == DefinedTypes.end()) { std::string elemName(getCppName(ET)); Out << "ArrayType* " << typeName << " = ArrayType::get(" << elemName << ", " << utostr(AT->getNumElements()) << ");"; nl(Out); } break; } case Type::PointerTyID: { PointerType* PT = cast(Ty); Type* ET = PT->getElementType(); printType(ET); if (DefinedTypes.find(Ty) == DefinedTypes.end()) { std::string elemName(getCppName(ET)); Out << "PointerType* " << typeName << " = PointerType::get(" << elemName << ", " << utostr(PT->getAddressSpace()) << ");"; nl(Out); } break; } case Type::VectorTyID: { VectorType* PT = cast(Ty); Type* ET = PT->getElementType(); printType(ET); if (DefinedTypes.find(Ty) == DefinedTypes.end()) { std::string elemName(getCppName(ET)); Out << "VectorType* " << typeName << " = VectorType::get(" << elemName << ", " << utostr(PT->getNumElements()) << ");"; nl(Out); } break; } default: error("Invalid TypeID"); } // Indicate that this type is now defined. DefinedTypes.insert(Ty); // Finally, separate the type definition from other with a newline. nl(Out); } void CppWriter::printTypes(const Module* M) { // Add all of the global variables to the value table. for (Module::const_global_iterator I = TheModule->global_begin(), E = TheModule->global_end(); I != E; ++I) { if (I->hasInitializer()) printType(I->getInitializer()->getType()); printType(I->getType()); } // Add all the functions to the table for (Module::const_iterator FI = TheModule->begin(), FE = TheModule->end(); FI != FE; ++FI) { printType(FI->getReturnType()); printType(FI->getFunctionType()); // Add all the function arguments for (Function::const_arg_iterator AI = FI->arg_begin(), AE = FI->arg_end(); AI != AE; ++AI) { printType(AI->getType()); } // Add all of the basic blocks and instructions for (Function::const_iterator BB = FI->begin(), E = FI->end(); BB != E; ++BB) { printType(BB->getType()); for (BasicBlock::const_iterator I = BB->begin(), E = BB->end(); I!=E; ++I) { printType(I->getType()); for (unsigned i = 0; i < I->getNumOperands(); ++i) printType(I->getOperand(i)->getType()); } } } } // printConstant - Print out a constant pool entry... void CppWriter::printConstant(const Constant *CV) { // First, if the constant is actually a GlobalValue (variable or function) // or its already in the constant list then we've printed it already and we // can just return. if (isa(CV) || ValueNames.find(CV) != ValueNames.end()) return; std::string constName(getCppName(CV)); std::string typeName(getCppName(CV->getType())); if (isa(CV)) { // Skip variables and functions, we emit them elsewhere return; } if (const ConstantInt *CI = dyn_cast(CV)) { std::string constValue = CI->getValue().toString(10, true); Out << "ConstantInt* " << constName << " = ConstantInt::get(mod->getContext(), APInt(" << cast(CI->getType())->getBitWidth() << ", StringRef(\"" << constValue << "\"), 10));"; } else if (isa(CV)) { Out << "ConstantAggregateZero* " << constName << " = ConstantAggregateZero::get(" << typeName << ");"; } else if (isa(CV)) { Out << "ConstantPointerNull* " << constName << " = ConstantPointerNull::get(" << typeName << ");"; } else if (const ConstantFP *CFP = dyn_cast(CV)) { Out << "ConstantFP* " << constName << " = "; printCFP(CFP); Out << ";"; } else if (const ConstantArray *CA = dyn_cast(CV)) { if (CA->isString() && CA->getType()->getElementType() == Type::getInt8Ty(CA->getContext())) { Out << "Constant* " << constName << " = ConstantArray::get(mod->getContext(), \""; std::string tmp = CA->getAsString(); bool nullTerminate = false; if (tmp[tmp.length()-1] == 0) { tmp.erase(tmp.length()-1); nullTerminate = true; } printEscapedString(tmp); // Determine if we want null termination or not. if (nullTerminate) Out << "\", true"; // Indicate that the null terminator should be // added. else Out << "\", false";// No null terminator Out << ");"; } else { Out << "std::vector " << constName << "_elems;"; nl(Out); unsigned N = CA->getNumOperands(); for (unsigned i = 0; i < N; ++i) { printConstant(CA->getOperand(i)); // recurse to print operands Out << constName << "_elems.push_back(" << getCppName(CA->getOperand(i)) << ");"; nl(Out); } Out << "Constant* " << constName << " = ConstantArray::get(" << typeName << ", " << constName << "_elems);"; } } else if (const ConstantStruct *CS = dyn_cast(CV)) { Out << "std::vector " << constName << "_fields;"; nl(Out); unsigned N = CS->getNumOperands(); for (unsigned i = 0; i < N; i++) { printConstant(CS->getOperand(i)); Out << constName << "_fields.push_back(" << getCppName(CS->getOperand(i)) << ");"; nl(Out); } Out << "Constant* " << constName << " = ConstantStruct::get(" << typeName << ", " << constName << "_fields);"; } else if (const ConstantVector *CP = dyn_cast(CV)) { Out << "std::vector " << constName << "_elems;"; nl(Out); unsigned N = CP->getNumOperands(); for (unsigned i = 0; i < N; ++i) { printConstant(CP->getOperand(i)); Out << constName << "_elems.push_back(" << getCppName(CP->getOperand(i)) << ");"; nl(Out); } Out << "Constant* " << constName << " = ConstantVector::get(" << typeName << ", " << constName << "_elems);"; } else if (isa(CV)) { Out << "UndefValue* " << constName << " = UndefValue::get(" << typeName << ");"; } else if (const ConstantExpr *CE = dyn_cast(CV)) { if (CE->getOpcode() == Instruction::GetElementPtr) { Out << "std::vector " << constName << "_indices;"; nl(Out); printConstant(CE->getOperand(0)); for (unsigned i = 1; i < CE->getNumOperands(); ++i ) { printConstant(CE->getOperand(i)); Out << constName << "_indices.push_back(" << getCppName(CE->getOperand(i)) << ");"; nl(Out); } Out << "Constant* " << constName << " = ConstantExpr::getGetElementPtr(" << getCppName(CE->getOperand(0)) << ", " << constName << "_indices);"; } else if (CE->isCast()) { printConstant(CE->getOperand(0)); Out << "Constant* " << constName << " = ConstantExpr::getCast("; switch (CE->getOpcode()) { default: llvm_unreachable("Invalid cast opcode"); case Instruction::Trunc: Out << "Instruction::Trunc"; break; case Instruction::ZExt: Out << "Instruction::ZExt"; break; case Instruction::SExt: Out << "Instruction::SExt"; break; case Instruction::FPTrunc: Out << "Instruction::FPTrunc"; break; case Instruction::FPExt: Out << "Instruction::FPExt"; break; case Instruction::FPToUI: Out << "Instruction::FPToUI"; break; case Instruction::FPToSI: Out << "Instruction::FPToSI"; break; case Instruction::UIToFP: Out << "Instruction::UIToFP"; break; case Instruction::SIToFP: Out << "Instruction::SIToFP"; break; case Instruction::PtrToInt: Out << "Instruction::PtrToInt"; break; case Instruction::IntToPtr: Out << "Instruction::IntToPtr"; break; case Instruction::BitCast: Out << "Instruction::BitCast"; break; } Out << ", " << getCppName(CE->getOperand(0)) << ", " << getCppName(CE->getType()) << ");"; } else { unsigned N = CE->getNumOperands(); for (unsigned i = 0; i < N; ++i ) { printConstant(CE->getOperand(i)); } Out << "Constant* " << constName << " = ConstantExpr::"; switch (CE->getOpcode()) { case Instruction::Add: Out << "getAdd("; break; case Instruction::FAdd: Out << "getFAdd("; break; case Instruction::Sub: Out << "getSub("; break; case Instruction::FSub: Out << "getFSub("; break; case Instruction::Mul: Out << "getMul("; break; case Instruction::FMul: Out << "getFMul("; break; case Instruction::UDiv: Out << "getUDiv("; break; case Instruction::SDiv: Out << "getSDiv("; break; case Instruction::FDiv: Out << "getFDiv("; break; case Instruction::URem: Out << "getURem("; break; case Instruction::SRem: Out << "getSRem("; break; case Instruction::FRem: Out << "getFRem("; break; case Instruction::And: Out << "getAnd("; break; case Instruction::Or: Out << "getOr("; break; case Instruction::Xor: Out << "getXor("; break; case Instruction::ICmp: Out << "getICmp(ICmpInst::ICMP_"; switch (CE->getPredicate()) { case ICmpInst::ICMP_EQ: Out << "EQ"; break; case ICmpInst::ICMP_NE: Out << "NE"; break; case ICmpInst::ICMP_SLT: Out << "SLT"; break; case ICmpInst::ICMP_ULT: Out << "ULT"; break; case ICmpInst::ICMP_SGT: Out << "SGT"; break; case ICmpInst::ICMP_UGT: Out << "UGT"; break; case ICmpInst::ICMP_SLE: Out << "SLE"; break; case ICmpInst::ICMP_ULE: Out << "ULE"; break; case ICmpInst::ICMP_SGE: Out << "SGE"; break; case ICmpInst::ICMP_UGE: Out << "UGE"; break; default: error("Invalid ICmp Predicate"); } break; case Instruction::FCmp: Out << "getFCmp(FCmpInst::FCMP_"; switch (CE->getPredicate()) { case FCmpInst::FCMP_FALSE: Out << "FALSE"; break; case FCmpInst::FCMP_ORD: Out << "ORD"; break; case FCmpInst::FCMP_UNO: Out << "UNO"; break; case FCmpInst::FCMP_OEQ: Out << "OEQ"; break; case FCmpInst::FCMP_UEQ: Out << "UEQ"; break; case FCmpInst::FCMP_ONE: Out << "ONE"; break; case FCmpInst::FCMP_UNE: Out << "UNE"; break; case FCmpInst::FCMP_OLT: Out << "OLT"; break; case FCmpInst::FCMP_ULT: Out << "ULT"; break; case FCmpInst::FCMP_OGT: Out << "OGT"; break; case FCmpInst::FCMP_UGT: Out << "UGT"; break; case FCmpInst::FCMP_OLE: Out << "OLE"; break; case FCmpInst::FCMP_ULE: Out << "ULE"; break; case FCmpInst::FCMP_OGE: Out << "OGE"; break; case FCmpInst::FCMP_UGE: Out << "UGE"; break; case FCmpInst::FCMP_TRUE: Out << "TRUE"; break; default: error("Invalid FCmp Predicate"); } break; case Instruction::Shl: Out << "getShl("; break; case Instruction::LShr: Out << "getLShr("; break; case Instruction::AShr: Out << "getAShr("; break; case Instruction::Select: Out << "getSelect("; break; case Instruction::ExtractElement: Out << "getExtractElement("; break; case Instruction::InsertElement: Out << "getInsertElement("; break; case Instruction::ShuffleVector: Out << "getShuffleVector("; break; default: error("Invalid constant expression"); break; } Out << getCppName(CE->getOperand(0)); for (unsigned i = 1; i < CE->getNumOperands(); ++i) Out << ", " << getCppName(CE->getOperand(i)); Out << ");"; } } else if (const BlockAddress *BA = dyn_cast(CV)) { Out << "Constant* " << constName << " = "; Out << "BlockAddress::get(" << getOpName(BA->getBasicBlock()) << ");"; } else { error("Bad Constant"); Out << "Constant* " << constName << " = 0; "; } nl(Out); } void CppWriter::printConstants(const Module* M) { // Traverse all the global variables looking for constant initializers for (Module::const_global_iterator I = TheModule->global_begin(), E = TheModule->global_end(); I != E; ++I) if (I->hasInitializer()) printConstant(I->getInitializer()); // Traverse the LLVM functions looking for constants for (Module::const_iterator FI = TheModule->begin(), FE = TheModule->end(); FI != FE; ++FI) { // Add all of the basic blocks and instructions for (Function::const_iterator BB = FI->begin(), E = FI->end(); BB != E; ++BB) { for (BasicBlock::const_iterator I = BB->begin(), E = BB->end(); I!=E; ++I) { for (unsigned i = 0; i < I->getNumOperands(); ++i) { if (Constant* C = dyn_cast(I->getOperand(i))) { printConstant(C); } } } } } } void CppWriter::printVariableUses(const GlobalVariable *GV) { nl(Out) << "// Type Definitions"; nl(Out); printType(GV->getType()); if (GV->hasInitializer()) { const Constant *Init = GV->getInitializer(); printType(Init->getType()); if (const Function *F = dyn_cast(Init)) { nl(Out)<< "/ Function Declarations"; nl(Out); printFunctionHead(F); } else if (const GlobalVariable* gv = dyn_cast(Init)) { nl(Out) << "// Global Variable Declarations"; nl(Out); printVariableHead(gv); nl(Out) << "// Global Variable Definitions"; nl(Out); printVariableBody(gv); } else { nl(Out) << "// Constant Definitions"; nl(Out); printConstant(Init); } } } void CppWriter::printVariableHead(const GlobalVariable *GV) { nl(Out) << "GlobalVariable* " << getCppName(GV); if (is_inline) { Out << " = mod->getGlobalVariable(mod->getContext(), "; printEscapedString(GV->getName()); Out << ", " << getCppName(GV->getType()->getElementType()) << ",true)"; nl(Out) << "if (!" << getCppName(GV) << ") {"; in(); nl(Out) << getCppName(GV); } Out << " = new GlobalVariable(/*Module=*/*mod, "; nl(Out) << "/*Type=*/"; printCppName(GV->getType()->getElementType()); Out << ","; nl(Out) << "/*isConstant=*/" << (GV->isConstant()?"true":"false"); Out << ","; nl(Out) << "/*Linkage=*/"; printLinkageType(GV->getLinkage()); Out << ","; nl(Out) << "/*Initializer=*/0, "; if (GV->hasInitializer()) { Out << "// has initializer, specified below"; } nl(Out) << "/*Name=*/\""; printEscapedString(GV->getName()); Out << "\");"; nl(Out); if (GV->hasSection()) { printCppName(GV); Out << "->setSection(\""; printEscapedString(GV->getSection()); Out << "\");"; nl(Out); } if (GV->getAlignment()) { printCppName(GV); Out << "->setAlignment(" << utostr(GV->getAlignment()) << ");"; nl(Out); } if (GV->getVisibility() != GlobalValue::DefaultVisibility) { printCppName(GV); Out << "->setVisibility("; printVisibilityType(GV->getVisibility()); Out << ");"; nl(Out); } if (GV->isThreadLocal()) { printCppName(GV); Out << "->setThreadLocal(true);"; nl(Out); } if (is_inline) { out(); Out << "}"; nl(Out); } } void CppWriter::printVariableBody(const GlobalVariable *GV) { if (GV->hasInitializer()) { printCppName(GV); Out << "->setInitializer("; Out << getCppName(GV->getInitializer()) << ");"; nl(Out); } } std::string CppWriter::getOpName(const Value* V) { if (!isa(V) || DefinedValues.find(V) != DefinedValues.end()) return getCppName(V); // See if its alread in the map of forward references, if so just return the // name we already set up for it ForwardRefMap::const_iterator I = ForwardRefs.find(V); if (I != ForwardRefs.end()) return I->second; // This is a new forward reference. Generate a unique name for it std::string result(std::string("fwdref_") + utostr(uniqueNum++)); // Yes, this is a hack. An Argument is the smallest instantiable value that // we can make as a placeholder for the real value. We'll replace these // Argument instances later. Out << "Argument* " << result << " = new Argument(" << getCppName(V->getType()) << ");"; nl(Out); ForwardRefs[V] = result; return result; } +static StringRef ConvertAtomicOrdering(AtomicOrdering Ordering) { + switch (Ordering) { + case NotAtomic: return "NotAtomic"; + case Unordered: return "Unordered"; + case Monotonic: return "Monotonic"; + case Acquire: return "Acquire"; + case Release: return "Release"; + case AcquireRelease: return "AcquireRelease"; + case SequentiallyConsistent: return "SequentiallyConsistent"; + } + llvm_unreachable("Unknown ordering"); +} + +static StringRef ConvertAtomicSynchScope(SynchronizationScope SynchScope) { + switch (SynchScope) { + case SingleThread: return "SingleThread"; + case CrossThread: return "CrossThread"; + } + llvm_unreachable("Unknown synch scope"); +} + // printInstruction - This member is called for each Instruction in a function. void CppWriter::printInstruction(const Instruction *I, const std::string& bbname) { std::string iName(getCppName(I)); // Before we emit this instruction, we need to take care of generating any // forward references. So, we get the names of all the operands in advance const unsigned Ops(I->getNumOperands()); std::string* opNames = new std::string[Ops]; for (unsigned i = 0; i < Ops; i++) opNames[i] = getOpName(I->getOperand(i)); switch (I->getOpcode()) { default: error("Invalid instruction"); break; case Instruction::Ret: { const ReturnInst* ret = cast(I); Out << "ReturnInst::Create(mod->getContext(), " << (ret->getReturnValue() ? opNames[0] + ", " : "") << bbname << ");"; break; } case Instruction::Br: { const BranchInst* br = cast(I); Out << "BranchInst::Create(" ; if (br->getNumOperands() == 3) { Out << opNames[2] << ", " << opNames[1] << ", " << opNames[0] << ", "; } else if (br->getNumOperands() == 1) { Out << opNames[0] << ", "; } else { error("Branch with 2 operands?"); } Out << bbname << ");"; break; } case Instruction::Switch: { const SwitchInst *SI = cast(I); Out << "SwitchInst* " << iName << " = SwitchInst::Create(" << getOpName(SI->getCondition()) << ", " << getOpName(SI->getDefaultDest()) << ", " << SI->getNumCases() << ", " << bbname << ");"; nl(Out); unsigned NumCases = SI->getNumCases(); for (unsigned i = 1; i < NumCases; ++i) { const ConstantInt* CaseVal = SI->getCaseValue(i); const BasicBlock* BB = SI->getSuccessor(i); Out << iName << "->addCase(" << getOpName(CaseVal) << ", " << getOpName(BB) << ");"; nl(Out); } break; } case Instruction::IndirectBr: { const IndirectBrInst *IBI = cast(I); Out << "IndirectBrInst *" << iName << " = IndirectBrInst::Create(" << opNames[0] << ", " << IBI->getNumDestinations() << ");"; nl(Out); for (unsigned i = 1; i != IBI->getNumOperands(); ++i) { Out << iName << "->addDestination(" << opNames[i] << ");"; nl(Out); } break; } case Instruction::Resume: { Out << "ResumeInst::Create(mod->getContext(), " << opNames[0] << ", " << bbname << ");"; break; } case Instruction::Invoke: { const InvokeInst* inv = cast(I); Out << "std::vector " << iName << "_params;"; nl(Out); for (unsigned i = 0; i < inv->getNumArgOperands(); ++i) { Out << iName << "_params.push_back(" << getOpName(inv->getArgOperand(i)) << ");"; nl(Out); } // FIXME: This shouldn't use magic numbers -3, -2, and -1. Out << "InvokeInst *" << iName << " = InvokeInst::Create(" << getOpName(inv->getCalledFunction()) << ", " << getOpName(inv->getNormalDest()) << ", " << getOpName(inv->getUnwindDest()) << ", " << iName << "_params, \""; printEscapedString(inv->getName()); Out << "\", " << bbname << ");"; nl(Out) << iName << "->setCallingConv("; printCallingConv(inv->getCallingConv()); Out << ");"; printAttributes(inv->getAttributes(), iName); Out << iName << "->setAttributes(" << iName << "_PAL);"; nl(Out); break; } case Instruction::Unwind: { Out << "new UnwindInst(" << bbname << ");"; break; } case Instruction::Unreachable: { Out << "new UnreachableInst(" << "mod->getContext(), " << bbname << ");"; break; } case Instruction::Add: case Instruction::FAdd: case Instruction::Sub: case Instruction::FSub: case Instruction::Mul: case Instruction::FMul: case Instruction::UDiv: case Instruction::SDiv: case Instruction::FDiv: case Instruction::URem: case Instruction::SRem: case Instruction::FRem: case Instruction::And: case Instruction::Or: case Instruction::Xor: case Instruction::Shl: case Instruction::LShr: case Instruction::AShr:{ Out << "BinaryOperator* " << iName << " = BinaryOperator::Create("; switch (I->getOpcode()) { case Instruction::Add: Out << "Instruction::Add"; break; case Instruction::FAdd: Out << "Instruction::FAdd"; break; case Instruction::Sub: Out << "Instruction::Sub"; break; case Instruction::FSub: Out << "Instruction::FSub"; break; case Instruction::Mul: Out << "Instruction::Mul"; break; case Instruction::FMul: Out << "Instruction::FMul"; break; case Instruction::UDiv:Out << "Instruction::UDiv"; break; case Instruction::SDiv:Out << "Instruction::SDiv"; break; case Instruction::FDiv:Out << "Instruction::FDiv"; break; case Instruction::URem:Out << "Instruction::URem"; break; case Instruction::SRem:Out << "Instruction::SRem"; break; case Instruction::FRem:Out << "Instruction::FRem"; break; case Instruction::And: Out << "Instruction::And"; break; case Instruction::Or: Out << "Instruction::Or"; break; case Instruction::Xor: Out << "Instruction::Xor"; break; case Instruction::Shl: Out << "Instruction::Shl"; break; case Instruction::LShr:Out << "Instruction::LShr"; break; case Instruction::AShr:Out << "Instruction::AShr"; break; default: Out << "Instruction::BadOpCode"; break; } Out << ", " << opNames[0] << ", " << opNames[1] << ", \""; printEscapedString(I->getName()); Out << "\", " << bbname << ");"; break; } case Instruction::FCmp: { Out << "FCmpInst* " << iName << " = new FCmpInst(*" << bbname << ", "; switch (cast(I)->getPredicate()) { case FCmpInst::FCMP_FALSE: Out << "FCmpInst::FCMP_FALSE"; break; case FCmpInst::FCMP_OEQ : Out << "FCmpInst::FCMP_OEQ"; break; case FCmpInst::FCMP_OGT : Out << "FCmpInst::FCMP_OGT"; break; case FCmpInst::FCMP_OGE : Out << "FCmpInst::FCMP_OGE"; break; case FCmpInst::FCMP_OLT : Out << "FCmpInst::FCMP_OLT"; break; case FCmpInst::FCMP_OLE : Out << "FCmpInst::FCMP_OLE"; break; case FCmpInst::FCMP_ONE : Out << "FCmpInst::FCMP_ONE"; break; case FCmpInst::FCMP_ORD : Out << "FCmpInst::FCMP_ORD"; break; case FCmpInst::FCMP_UNO : Out << "FCmpInst::FCMP_UNO"; break; case FCmpInst::FCMP_UEQ : Out << "FCmpInst::FCMP_UEQ"; break; case FCmpInst::FCMP_UGT : Out << "FCmpInst::FCMP_UGT"; break; case FCmpInst::FCMP_UGE : Out << "FCmpInst::FCMP_UGE"; break; case FCmpInst::FCMP_ULT : Out << "FCmpInst::FCMP_ULT"; break; case FCmpInst::FCMP_ULE : Out << "FCmpInst::FCMP_ULE"; break; case FCmpInst::FCMP_UNE : Out << "FCmpInst::FCMP_UNE"; break; case FCmpInst::FCMP_TRUE : Out << "FCmpInst::FCMP_TRUE"; break; default: Out << "FCmpInst::BAD_ICMP_PREDICATE"; break; } Out << ", " << opNames[0] << ", " << opNames[1] << ", \""; printEscapedString(I->getName()); Out << "\");"; break; } case Instruction::ICmp: { Out << "ICmpInst* " << iName << " = new ICmpInst(*" << bbname << ", "; switch (cast(I)->getPredicate()) { case ICmpInst::ICMP_EQ: Out << "ICmpInst::ICMP_EQ"; break; case ICmpInst::ICMP_NE: Out << "ICmpInst::ICMP_NE"; break; case ICmpInst::ICMP_ULE: Out << "ICmpInst::ICMP_ULE"; break; case ICmpInst::ICMP_SLE: Out << "ICmpInst::ICMP_SLE"; break; case ICmpInst::ICMP_UGE: Out << "ICmpInst::ICMP_UGE"; break; case ICmpInst::ICMP_SGE: Out << "ICmpInst::ICMP_SGE"; break; case ICmpInst::ICMP_ULT: Out << "ICmpInst::ICMP_ULT"; break; case ICmpInst::ICMP_SLT: Out << "ICmpInst::ICMP_SLT"; break; case ICmpInst::ICMP_UGT: Out << "ICmpInst::ICMP_UGT"; break; case ICmpInst::ICMP_SGT: Out << "ICmpInst::ICMP_SGT"; break; default: Out << "ICmpInst::BAD_ICMP_PREDICATE"; break; } Out << ", " << opNames[0] << ", " << opNames[1] << ", \""; printEscapedString(I->getName()); Out << "\");"; break; } case Instruction::Alloca: { const AllocaInst* allocaI = cast(I); Out << "AllocaInst* " << iName << " = new AllocaInst(" << getCppName(allocaI->getAllocatedType()) << ", "; if (allocaI->isArrayAllocation()) Out << opNames[0] << ", "; Out << "\""; printEscapedString(allocaI->getName()); Out << "\", " << bbname << ");"; if (allocaI->getAlignment()) nl(Out) << iName << "->setAlignment(" << allocaI->getAlignment() << ");"; break; } case Instruction::Load: { const LoadInst* load = cast(I); Out << "LoadInst* " << iName << " = new LoadInst(" << opNames[0] << ", \""; printEscapedString(load->getName()); Out << "\", " << (load->isVolatile() ? "true" : "false" ) << ", " << bbname << ");"; + if (load->getAlignment()) + nl(Out) << iName << "->setAlignment(" + << load->getAlignment() << ");"; + if (load->isAtomic()) { + StringRef Ordering = ConvertAtomicOrdering(load->getOrdering()); + StringRef CrossThread = ConvertAtomicSynchScope(load->getSynchScope()); + nl(Out) << iName << "->setAtomic(" + << Ordering << ", " << CrossThread << ");"; + } break; } case Instruction::Store: { const StoreInst* store = cast(I); - Out << " new StoreInst(" + Out << "StoreInst* " << iName << " = new StoreInst(" << opNames[0] << ", " << opNames[1] << ", " << (store->isVolatile() ? "true" : "false") << ", " << bbname << ");"; + if (store->getAlignment()) + nl(Out) << iName << "->setAlignment(" + << store->getAlignment() << ");"; + if (store->isAtomic()) { + StringRef Ordering = ConvertAtomicOrdering(store->getOrdering()); + StringRef CrossThread = ConvertAtomicSynchScope(store->getSynchScope()); + nl(Out) << iName << "->setAtomic(" + << Ordering << ", " << CrossThread << ");"; + } break; } case Instruction::GetElementPtr: { const GetElementPtrInst* gep = cast(I); if (gep->getNumOperands() <= 2) { Out << "GetElementPtrInst* " << iName << " = GetElementPtrInst::Create(" << opNames[0]; if (gep->getNumOperands() == 2) Out << ", " << opNames[1]; } else { Out << "std::vector " << iName << "_indices;"; nl(Out); for (unsigned i = 1; i < gep->getNumOperands(); ++i ) { Out << iName << "_indices.push_back(" << opNames[i] << ");"; nl(Out); } Out << "Instruction* " << iName << " = GetElementPtrInst::Create(" << opNames[0] << ", " << iName << "_indices"; } Out << ", \""; printEscapedString(gep->getName()); Out << "\", " << bbname << ");"; break; } case Instruction::PHI: { const PHINode* phi = cast(I); Out << "PHINode* " << iName << " = PHINode::Create(" << getCppName(phi->getType()) << ", " << phi->getNumIncomingValues() << ", \""; printEscapedString(phi->getName()); Out << "\", " << bbname << ");"; nl(Out); for (unsigned i = 0; i < phi->getNumIncomingValues(); ++i) { Out << iName << "->addIncoming(" << opNames[PHINode::getOperandNumForIncomingValue(i)] << ", " << getOpName(phi->getIncomingBlock(i)) << ");"; nl(Out); } break; } case Instruction::Trunc: case Instruction::ZExt: case Instruction::SExt: case Instruction::FPTrunc: case Instruction::FPExt: case Instruction::FPToUI: case Instruction::FPToSI: case Instruction::UIToFP: case Instruction::SIToFP: case Instruction::PtrToInt: case Instruction::IntToPtr: case Instruction::BitCast: { const CastInst* cst = cast(I); Out << "CastInst* " << iName << " = new "; switch (I->getOpcode()) { case Instruction::Trunc: Out << "TruncInst"; break; case Instruction::ZExt: Out << "ZExtInst"; break; case Instruction::SExt: Out << "SExtInst"; break; case Instruction::FPTrunc: Out << "FPTruncInst"; break; case Instruction::FPExt: Out << "FPExtInst"; break; case Instruction::FPToUI: Out << "FPToUIInst"; break; case Instruction::FPToSI: Out << "FPToSIInst"; break; case Instruction::UIToFP: Out << "UIToFPInst"; break; case Instruction::SIToFP: Out << "SIToFPInst"; break; case Instruction::PtrToInt: Out << "PtrToIntInst"; break; case Instruction::IntToPtr: Out << "IntToPtrInst"; break; case Instruction::BitCast: Out << "BitCastInst"; break; default: assert(0 && "Unreachable"); break; } Out << "(" << opNames[0] << ", " << getCppName(cst->getType()) << ", \""; printEscapedString(cst->getName()); Out << "\", " << bbname << ");"; break; } case Instruction::Call: { const CallInst* call = cast(I); if (const InlineAsm* ila = dyn_cast(call->getCalledValue())) { Out << "InlineAsm* " << getCppName(ila) << " = InlineAsm::get(" << getCppName(ila->getFunctionType()) << ", \"" << ila->getAsmString() << "\", \"" << ila->getConstraintString() << "\"," << (ila->hasSideEffects() ? "true" : "false") << ");"; nl(Out); } if (call->getNumArgOperands() > 1) { Out << "std::vector " << iName << "_params;"; nl(Out); for (unsigned i = 0; i < call->getNumArgOperands(); ++i) { Out << iName << "_params.push_back(" << opNames[i] << ");"; nl(Out); } Out << "CallInst* " << iName << " = CallInst::Create(" << opNames[call->getNumArgOperands()] << ", " << iName << "_params, \""; } else if (call->getNumArgOperands() == 1) { Out << "CallInst* " << iName << " = CallInst::Create(" << opNames[call->getNumArgOperands()] << ", " << opNames[0] << ", \""; } else { Out << "CallInst* " << iName << " = CallInst::Create(" << opNames[call->getNumArgOperands()] << ", \""; } printEscapedString(call->getName()); Out << "\", " << bbname << ");"; nl(Out) << iName << "->setCallingConv("; printCallingConv(call->getCallingConv()); Out << ");"; nl(Out) << iName << "->setTailCall(" << (call->isTailCall() ? "true" : "false"); Out << ");"; nl(Out); printAttributes(call->getAttributes(), iName); Out << iName << "->setAttributes(" << iName << "_PAL);"; nl(Out); break; } case Instruction::Select: { const SelectInst* sel = cast(I); Out << "SelectInst* " << getCppName(sel) << " = SelectInst::Create("; Out << opNames[0] << ", " << opNames[1] << ", " << opNames[2] << ", \""; printEscapedString(sel->getName()); Out << "\", " << bbname << ");"; break; } case Instruction::UserOp1: /// FALL THROUGH case Instruction::UserOp2: { /// FIXME: What should be done here? break; } case Instruction::VAArg: { const VAArgInst* va = cast(I); Out << "VAArgInst* " << getCppName(va) << " = new VAArgInst(" << opNames[0] << ", " << getCppName(va->getType()) << ", \""; printEscapedString(va->getName()); Out << "\", " << bbname << ");"; break; } case Instruction::ExtractElement: { const ExtractElementInst* eei = cast(I); Out << "ExtractElementInst* " << getCppName(eei) << " = new ExtractElementInst(" << opNames[0] << ", " << opNames[1] << ", \""; printEscapedString(eei->getName()); Out << "\", " << bbname << ");"; break; } case Instruction::InsertElement: { const InsertElementInst* iei = cast(I); Out << "InsertElementInst* " << getCppName(iei) << " = InsertElementInst::Create(" << opNames[0] << ", " << opNames[1] << ", " << opNames[2] << ", \""; printEscapedString(iei->getName()); Out << "\", " << bbname << ");"; break; } case Instruction::ShuffleVector: { const ShuffleVectorInst* svi = cast(I); Out << "ShuffleVectorInst* " << getCppName(svi) << " = new ShuffleVectorInst(" << opNames[0] << ", " << opNames[1] << ", " << opNames[2] << ", \""; printEscapedString(svi->getName()); Out << "\", " << bbname << ");"; break; } case Instruction::ExtractValue: { const ExtractValueInst *evi = cast(I); Out << "std::vector " << iName << "_indices;"; nl(Out); for (unsigned i = 0; i < evi->getNumIndices(); ++i) { Out << iName << "_indices.push_back(" << evi->idx_begin()[i] << ");"; nl(Out); } Out << "ExtractValueInst* " << getCppName(evi) << " = ExtractValueInst::Create(" << opNames[0] << ", " << iName << "_indices, \""; printEscapedString(evi->getName()); Out << "\", " << bbname << ");"; break; } case Instruction::InsertValue: { const InsertValueInst *ivi = cast(I); Out << "std::vector " << iName << "_indices;"; nl(Out); for (unsigned i = 0; i < ivi->getNumIndices(); ++i) { Out << iName << "_indices.push_back(" << ivi->idx_begin()[i] << ");"; nl(Out); } Out << "InsertValueInst* " << getCppName(ivi) << " = InsertValueInst::Create(" << opNames[0] << ", " << opNames[1] << ", " << iName << "_indices, \""; printEscapedString(ivi->getName()); Out << "\", " << bbname << ");"; break; } + case Instruction::Fence: { + const FenceInst *fi = cast(I); + StringRef Ordering = ConvertAtomicOrdering(fi->getOrdering()); + StringRef CrossThread = ConvertAtomicSynchScope(fi->getSynchScope()); + Out << "FenceInst* " << iName + << " = new FenceInst(mod->getContext(), " + << Ordering << ", " << CrossThread << ", " << bbname + << ");"; + break; } + case Instruction::AtomicCmpXchg: { + const AtomicCmpXchgInst *cxi = cast(I); + StringRef Ordering = ConvertAtomicOrdering(cxi->getOrdering()); + StringRef CrossThread = ConvertAtomicSynchScope(cxi->getSynchScope()); + Out << "AtomicCmpXchgInst* " << iName + << " = new AtomicCmpXchgInst(" + << opNames[0] << ", " << opNames[1] << ", " << opNames[2] << ", " + << Ordering << ", " << CrossThread << ", " << bbname + << ");"; + nl(Out) << iName << "->setName(\""; + printEscapedString(cxi->getName()); + Out << "\");"; + break; + } + case Instruction::AtomicRMW: { + const AtomicRMWInst *rmwi = cast(I); + StringRef Ordering = ConvertAtomicOrdering(rmwi->getOrdering()); + StringRef CrossThread = ConvertAtomicSynchScope(rmwi->getSynchScope()); + StringRef Operation; + switch (rmwi->getOperation()) { + case AtomicRMWInst::Xchg: Operation = "AtomicRMWInst::Xchg"; break; + case AtomicRMWInst::Add: Operation = "AtomicRMWInst::Add"; break; + case AtomicRMWInst::Sub: Operation = "AtomicRMWInst::Sub"; break; + case AtomicRMWInst::And: Operation = "AtomicRMWInst::And"; break; + case AtomicRMWInst::Nand: Operation = "AtomicRMWInst::Nand"; break; + case AtomicRMWInst::Or: Operation = "AtomicRMWInst::Or"; break; + case AtomicRMWInst::Xor: Operation = "AtomicRMWInst::Xor"; break; + case AtomicRMWInst::Max: Operation = "AtomicRMWInst::Max"; break; + case AtomicRMWInst::Min: Operation = "AtomicRMWInst::Min"; break; + case AtomicRMWInst::UMax: Operation = "AtomicRMWInst::UMax"; break; + case AtomicRMWInst::UMin: Operation = "AtomicRMWInst::UMin"; break; + case AtomicRMWInst::BAD_BINOP: llvm_unreachable("Bad atomic operation"); + } + Out << "AtomicRMWInst* " << iName + << " = new AtomicRMWInst(" + << Operation << ", " + << opNames[0] << ", " << opNames[1] << ", " + << Ordering << ", " << CrossThread << ", " << bbname + << ");"; + nl(Out) << iName << "->setName(\""; + printEscapedString(rmwi->getName()); + Out << "\");"; + break; + } + } DefinedValues.insert(I); nl(Out); delete [] opNames; } // Print out the types, constants and declarations needed by one function void CppWriter::printFunctionUses(const Function* F) { nl(Out) << "// Type Definitions"; nl(Out); if (!is_inline) { // Print the function's return type printType(F->getReturnType()); // Print the function's function type printType(F->getFunctionType()); // Print the types of each of the function's arguments for (Function::const_arg_iterator AI = F->arg_begin(), AE = F->arg_end(); AI != AE; ++AI) { printType(AI->getType()); } } // Print type definitions for every type referenced by an instruction and // make a note of any global values or constants that are referenced SmallPtrSet gvs; SmallPtrSet consts; for (Function::const_iterator BB = F->begin(), BE = F->end(); BB != BE; ++BB){ for (BasicBlock::const_iterator I = BB->begin(), E = BB->end(); I != E; ++I) { // Print the type of the instruction itself printType(I->getType()); // Print the type of each of the instruction's operands for (unsigned i = 0; i < I->getNumOperands(); ++i) { Value* operand = I->getOperand(i); printType(operand->getType()); // If the operand references a GVal or Constant, make a note of it if (GlobalValue* GV = dyn_cast(operand)) { gvs.insert(GV); if (GenerationType != GenFunction) if (GlobalVariable *GVar = dyn_cast(GV)) if (GVar->hasInitializer()) consts.insert(GVar->getInitializer()); } else if (Constant* C = dyn_cast(operand)) { consts.insert(C); for (unsigned j = 0; j < C->getNumOperands(); ++j) { // If the operand references a GVal or Constant, make a note of it Value* operand = C->getOperand(j); printType(operand->getType()); if (GlobalValue* GV = dyn_cast(operand)) { gvs.insert(GV); if (GenerationType != GenFunction) if (GlobalVariable *GVar = dyn_cast(GV)) if (GVar->hasInitializer()) consts.insert(GVar->getInitializer()); } } } } } } // Print the function declarations for any functions encountered nl(Out) << "// Function Declarations"; nl(Out); for (SmallPtrSet::iterator I = gvs.begin(), E = gvs.end(); I != E; ++I) { if (Function* Fun = dyn_cast(*I)) { if (!is_inline || Fun != F) printFunctionHead(Fun); } } // Print the global variable declarations for any variables encountered nl(Out) << "// Global Variable Declarations"; nl(Out); for (SmallPtrSet::iterator I = gvs.begin(), E = gvs.end(); I != E; ++I) { if (GlobalVariable* F = dyn_cast(*I)) printVariableHead(F); } // Print the constants found nl(Out) << "// Constant Definitions"; nl(Out); for (SmallPtrSet::iterator I = consts.begin(), E = consts.end(); I != E; ++I) { printConstant(*I); } // Process the global variables definitions now that all the constants have // been emitted. These definitions just couple the gvars with their constant // initializers. if (GenerationType != GenFunction) { nl(Out) << "// Global Variable Definitions"; nl(Out); for (SmallPtrSet::iterator I = gvs.begin(), E = gvs.end(); I != E; ++I) { if (GlobalVariable* GV = dyn_cast(*I)) printVariableBody(GV); } } } void CppWriter::printFunctionHead(const Function* F) { nl(Out) << "Function* " << getCppName(F); Out << " = mod->getFunction(\""; printEscapedString(F->getName()); Out << "\");"; nl(Out) << "if (!" << getCppName(F) << ") {"; nl(Out) << getCppName(F); Out<< " = Function::Create("; nl(Out,1) << "/*Type=*/" << getCppName(F->getFunctionType()) << ","; nl(Out) << "/*Linkage=*/"; printLinkageType(F->getLinkage()); Out << ","; nl(Out) << "/*Name=*/\""; printEscapedString(F->getName()); Out << "\", mod); " << (F->isDeclaration()? "// (external, no body)" : ""); nl(Out,-1); printCppName(F); Out << "->setCallingConv("; printCallingConv(F->getCallingConv()); Out << ");"; nl(Out); if (F->hasSection()) { printCppName(F); Out << "->setSection(\"" << F->getSection() << "\");"; nl(Out); } if (F->getAlignment()) { printCppName(F); Out << "->setAlignment(" << F->getAlignment() << ");"; nl(Out); } if (F->getVisibility() != GlobalValue::DefaultVisibility) { printCppName(F); Out << "->setVisibility("; printVisibilityType(F->getVisibility()); Out << ");"; nl(Out); } if (F->hasGC()) { printCppName(F); Out << "->setGC(\"" << F->getGC() << "\");"; nl(Out); } Out << "}"; nl(Out); printAttributes(F->getAttributes(), getCppName(F)); printCppName(F); Out << "->setAttributes(" << getCppName(F) << "_PAL);"; nl(Out); } void CppWriter::printFunctionBody(const Function *F) { if (F->isDeclaration()) return; // external functions have no bodies. // Clear the DefinedValues and ForwardRefs maps because we can't have // cross-function forward refs ForwardRefs.clear(); DefinedValues.clear(); // Create all the argument values if (!is_inline) { if (!F->arg_empty()) { Out << "Function::arg_iterator args = " << getCppName(F) << "->arg_begin();"; nl(Out); } for (Function::const_arg_iterator AI = F->arg_begin(), AE = F->arg_end(); AI != AE; ++AI) { Out << "Value* " << getCppName(AI) << " = args++;"; nl(Out); if (AI->hasName()) { - Out << getCppName(AI) << "->setName(\"" << AI->getName() << "\");"; + Out << getCppName(AI) << "->setName(\""; + printEscapedString(AI->getName()); + Out << "\");"; nl(Out); } } } // Create all the basic blocks nl(Out); for (Function::const_iterator BI = F->begin(), BE = F->end(); BI != BE; ++BI) { std::string bbname(getCppName(BI)); Out << "BasicBlock* " << bbname << " = BasicBlock::Create(mod->getContext(), \""; if (BI->hasName()) printEscapedString(BI->getName()); Out << "\"," << getCppName(BI->getParent()) << ",0);"; nl(Out); } // Output all of its basic blocks... for the function for (Function::const_iterator BI = F->begin(), BE = F->end(); BI != BE; ++BI) { std::string bbname(getCppName(BI)); nl(Out) << "// Block " << BI->getName() << " (" << bbname << ")"; nl(Out); // Output all of the instructions in the basic block... for (BasicBlock::const_iterator I = BI->begin(), E = BI->end(); I != E; ++I) { printInstruction(I,bbname); } } // Loop over the ForwardRefs and resolve them now that all instructions // are generated. if (!ForwardRefs.empty()) { nl(Out) << "// Resolve Forward References"; nl(Out); } while (!ForwardRefs.empty()) { ForwardRefMap::iterator I = ForwardRefs.begin(); Out << I->second << "->replaceAllUsesWith(" << getCppName(I->first) << "); delete " << I->second << ";"; nl(Out); ForwardRefs.erase(I); } } void CppWriter::printInline(const std::string& fname, const std::string& func) { const Function* F = TheModule->getFunction(func); if (!F) { error(std::string("Function '") + func + "' not found in input module"); return; } if (F->isDeclaration()) { error(std::string("Function '") + func + "' is external!"); return; } nl(Out) << "BasicBlock* " << fname << "(Module* mod, Function *" << getCppName(F); unsigned arg_count = 1; for (Function::const_arg_iterator AI = F->arg_begin(), AE = F->arg_end(); AI != AE; ++AI) { Out << ", Value* arg_" << arg_count; } Out << ") {"; nl(Out); is_inline = true; printFunctionUses(F); printFunctionBody(F); is_inline = false; Out << "return " << getCppName(F->begin()) << ";"; nl(Out) << "}"; nl(Out); } void CppWriter::printModuleBody() { // Print out all the type definitions nl(Out) << "// Type Definitions"; nl(Out); printTypes(TheModule); // Functions can call each other and global variables can reference them so // define all the functions first before emitting their function bodies. nl(Out) << "// Function Declarations"; nl(Out); for (Module::const_iterator I = TheModule->begin(), E = TheModule->end(); I != E; ++I) printFunctionHead(I); // Process the global variables declarations. We can't initialze them until // after the constants are printed so just print a header for each global nl(Out) << "// Global Variable Declarations\n"; nl(Out); for (Module::const_global_iterator I = TheModule->global_begin(), E = TheModule->global_end(); I != E; ++I) { printVariableHead(I); } // Print out all the constants definitions. Constants don't recurse except // through GlobalValues. All GlobalValues have been declared at this point // so we can proceed to generate the constants. nl(Out) << "// Constant Definitions"; nl(Out); printConstants(TheModule); // Process the global variables definitions now that all the constants have // been emitted. These definitions just couple the gvars with their constant // initializers. nl(Out) << "// Global Variable Definitions"; nl(Out); for (Module::const_global_iterator I = TheModule->global_begin(), E = TheModule->global_end(); I != E; ++I) { printVariableBody(I); } // Finally, we can safely put out all of the function bodies. nl(Out) << "// Function Definitions"; nl(Out); for (Module::const_iterator I = TheModule->begin(), E = TheModule->end(); I != E; ++I) { if (!I->isDeclaration()) { nl(Out) << "// Function: " << I->getName() << " (" << getCppName(I) << ")"; nl(Out) << "{"; nl(Out,1); printFunctionBody(I); nl(Out,-1) << "}"; nl(Out); } } } void CppWriter::printProgram(const std::string& fname, const std::string& mName) { Out << "#include \n"; Out << "#include \n"; Out << "#include \n"; Out << "#include \n"; Out << "#include \n"; Out << "#include \n"; Out << "#include \n"; Out << "#include \n"; Out << "#include \n"; Out << "#include \n"; Out << "#include \n"; Out << "#include \n"; Out << "#include \n"; Out << "#include \n"; Out << "#include \n"; Out << "#include \n"; Out << "#include \n"; Out << "#include \n"; Out << "using namespace llvm;\n\n"; Out << "Module* " << fname << "();\n\n"; Out << "int main(int argc, char**argv) {\n"; Out << " Module* Mod = " << fname << "();\n"; Out << " verifyModule(*Mod, PrintMessageAction);\n"; Out << " PassManager PM;\n"; Out << " PM.add(createPrintModulePass(&outs()));\n"; Out << " PM.run(*Mod);\n"; Out << " return 0;\n"; Out << "}\n\n"; printModule(fname,mName); } void CppWriter::printModule(const std::string& fname, const std::string& mName) { nl(Out) << "Module* " << fname << "() {"; nl(Out,1) << "// Module Construction"; nl(Out) << "Module* mod = new Module(\""; printEscapedString(mName); Out << "\", getGlobalContext());"; if (!TheModule->getTargetTriple().empty()) { nl(Out) << "mod->setDataLayout(\"" << TheModule->getDataLayout() << "\");"; } if (!TheModule->getTargetTriple().empty()) { nl(Out) << "mod->setTargetTriple(\"" << TheModule->getTargetTriple() << "\");"; } if (!TheModule->getModuleInlineAsm().empty()) { nl(Out) << "mod->setModuleInlineAsm(\""; printEscapedString(TheModule->getModuleInlineAsm()); Out << "\");"; } nl(Out); // Loop over the dependent libraries and emit them. Module::lib_iterator LI = TheModule->lib_begin(); Module::lib_iterator LE = TheModule->lib_end(); while (LI != LE) { Out << "mod->addLibrary(\"" << *LI << "\");"; nl(Out); ++LI; } printModuleBody(); nl(Out) << "return mod;"; nl(Out,-1) << "}"; nl(Out); } void CppWriter::printContents(const std::string& fname, const std::string& mName) { Out << "\nModule* " << fname << "(Module *mod) {\n"; Out << "\nmod->setModuleIdentifier(\""; printEscapedString(mName); Out << "\");\n"; printModuleBody(); Out << "\nreturn mod;\n"; Out << "\n}\n"; } void CppWriter::printFunction(const std::string& fname, const std::string& funcName) { const Function* F = TheModule->getFunction(funcName); if (!F) { error(std::string("Function '") + funcName + "' not found in input module"); return; } Out << "\nFunction* " << fname << "(Module *mod) {\n"; printFunctionUses(F); printFunctionHead(F); printFunctionBody(F); Out << "return " << getCppName(F) << ";\n"; Out << "}\n"; } void CppWriter::printFunctions() { const Module::FunctionListType &funcs = TheModule->getFunctionList(); Module::const_iterator I = funcs.begin(); Module::const_iterator IE = funcs.end(); for (; I != IE; ++I) { const Function &func = *I; if (!func.isDeclaration()) { std::string name("define_"); name += func.getName(); printFunction(name, func.getName()); } } } void CppWriter::printVariable(const std::string& fname, const std::string& varName) { const GlobalVariable* GV = TheModule->getNamedGlobal(varName); if (!GV) { error(std::string("Variable '") + varName + "' not found in input module"); return; } Out << "\nGlobalVariable* " << fname << "(Module *mod) {\n"; printVariableUses(GV); printVariableHead(GV); printVariableBody(GV); Out << "return " << getCppName(GV) << ";\n"; Out << "}\n"; } void CppWriter::printType(const std::string &fname, const std::string &typeName) { Type* Ty = TheModule->getTypeByName(typeName); if (!Ty) { error(std::string("Type '") + typeName + "' not found in input module"); return; } Out << "\nType* " << fname << "(Module *mod) {\n"; printType(Ty); Out << "return " << getCppName(Ty) << ";\n"; Out << "}\n"; } bool CppWriter::runOnModule(Module &M) { TheModule = &M; // Emit a header Out << "// Generated by llvm2cpp - DO NOT MODIFY!\n\n"; // Get the name of the function we're supposed to generate std::string fname = FuncName.getValue(); // Get the name of the thing we are to generate std::string tgtname = NameToGenerate.getValue(); if (GenerationType == GenModule || GenerationType == GenContents || GenerationType == GenProgram || GenerationType == GenFunctions) { if (tgtname == "!bad!") { if (M.getModuleIdentifier() == "-") tgtname = ""; else tgtname = M.getModuleIdentifier(); } } else if (tgtname == "!bad!") error("You must use the -for option with -gen-{function,variable,type}"); switch (WhatToGenerate(GenerationType)) { case GenProgram: if (fname.empty()) fname = "makeLLVMModule"; printProgram(fname,tgtname); break; case GenModule: if (fname.empty()) fname = "makeLLVMModule"; printModule(fname,tgtname); break; case GenContents: if (fname.empty()) fname = "makeLLVMModuleContents"; printContents(fname,tgtname); break; case GenFunction: if (fname.empty()) fname = "makeLLVMFunction"; printFunction(fname,tgtname); break; case GenFunctions: printFunctions(); break; case GenInline: if (fname.empty()) fname = "makeLLVMInline"; printInline(fname,tgtname); break; case GenVariable: if (fname.empty()) fname = "makeLLVMVariable"; printVariable(fname,tgtname); break; case GenType: if (fname.empty()) fname = "makeLLVMType"; printType(fname,tgtname); break; default: error("Invalid generation option"); } return false; } char CppWriter::ID = 0; //===----------------------------------------------------------------------===// // External Interface declaration //===----------------------------------------------------------------------===// bool CPPTargetMachine::addPassesToEmitFile(PassManagerBase &PM, formatted_raw_ostream &o, CodeGenFileType FileType, CodeGenOpt::Level OptLevel, bool DisableVerify) { if (FileType != TargetMachine::CGFT_AssemblyFile) return true; PM.add(new CppWriter(o)); return false; } Index: head/contrib/llvm/lib/Target/Mips/Mips64InstrInfo.td =================================================================== --- head/contrib/llvm/lib/Target/Mips/Mips64InstrInfo.td (revision 228378) +++ head/contrib/llvm/lib/Target/Mips/Mips64InstrInfo.td (revision 228379) @@ -1,214 +1,214 @@ //===- Mips64InstrInfo.td - Mips64 Instruction Information -*- tablegen -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file describes Mips64 instructions. // //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// // Mips Operand, Complex Patterns and Transformations Definitions. //===----------------------------------------------------------------------===// // Instruction operand types def shamt_64 : Operand; // Unsigned Operand def uimm16_64 : Operand { let PrintMethod = "printUnsignedImm"; } // Transformation Function - get Imm - 32. def Subtract32 : SDNodeXFormgetZExtValue() - 32); }]>; // imm32_63 predicate - True if imm is in range [32, 63]. def imm32_63 : ImmLeaf= 32 && (int32_t)Imm < 64;}], Subtract32>; //===----------------------------------------------------------------------===// // Instructions specific format //===----------------------------------------------------------------------===// // Shifts class LogicR_shift_rotate_imm64 func, bits<5> _rs, string instr_asm, SDNode OpNode, PatFrag PF>: - FR<0x00, func, (outs CPU64Regs:$dst), (ins CPU64Regs:$b, shamt_64:$c), - !strconcat(instr_asm, "\t$dst, $b, $c"), - [(set CPU64Regs:$dst, (OpNode CPU64Regs:$b, (i64 PF:$c)))], + FR<0x00, func, (outs CPU64Regs:$rd), (ins CPU64Regs:$rt, shamt_64:$shamt), + !strconcat(instr_asm, "\t$rd, $rt, $shamt"), + [(set CPU64Regs:$rd, (OpNode CPU64Regs:$rt, (i64 PF:$shamt)))], IIAlu> { let rs = _rs; } class LogicR_shift_rotate_reg64 func, bits<5> _shamt, string instr_asm, SDNode OpNode>: - FR<0x00, func, (outs CPU64Regs:$dst), (ins CPU64Regs:$c, CPU64Regs:$b), - !strconcat(instr_asm, "\t$dst, $b, $c"), - [(set CPU64Regs:$dst, (OpNode CPU64Regs:$b, CPU64Regs:$c))], IIAlu> { + FR<0x00, func, (outs CPU64Regs:$rd), (ins CPU64Regs:$rs, CPU64Regs:$rt), + !strconcat(instr_asm, "\t$rd, $rt, $rs"), + [(set CPU64Regs:$rd, (OpNode CPU64Regs:$rt, CPU64Regs:$rs))], IIAlu> { let shamt = _shamt; } // Mul, Div -let Defs = [HI64, LO64] in { +let rd = 0, shamt = 0, Defs = [HI64, LO64] in { let isCommutable = 1 in class Mul64 func, string instr_asm, InstrItinClass itin>: - FR<0x00, func, (outs), (ins CPU64Regs:$a, CPU64Regs:$b), - !strconcat(instr_asm, "\t$a, $b"), [], itin>; + FR<0x00, func, (outs), (ins CPU64Regs:$rs, CPU64Regs:$rt), + !strconcat(instr_asm, "\t$rs, $rt"), [], itin>; class Div64 func, string instr_asm, InstrItinClass itin>: - FR<0x00, func, (outs), (ins CPU64Regs:$a, CPU64Regs:$b), - !strconcat(instr_asm, "\t$$zero, $a, $b"), - [(op CPU64Regs:$a, CPU64Regs:$b)], itin>; + FR<0x00, func, (outs), (ins CPU64Regs:$rs, CPU64Regs:$rt), + !strconcat(instr_asm, "\t$$zero, $rs, $rt"), + [(op CPU64Regs:$rs, CPU64Regs:$rt)], itin>; } // Move from Hi/Lo let shamt = 0 in { let rs = 0, rt = 0 in class MoveFromLOHI64 func, string instr_asm>: - FR<0x00, func, (outs CPU64Regs:$dst), (ins), - !strconcat(instr_asm, "\t$dst"), [], IIHiLo>; + FR<0x00, func, (outs CPU64Regs:$rd), (ins), + !strconcat(instr_asm, "\t$rd"), [], IIHiLo>; let rt = 0, rd = 0 in class MoveToLOHI64 func, string instr_asm>: - FR<0x00, func, (outs), (ins CPU64Regs:$src), - !strconcat(instr_asm, "\t$src"), [], IIHiLo>; + FR<0x00, func, (outs), (ins CPU64Regs:$rs), + !strconcat(instr_asm, "\t$rs"), [], IIHiLo>; } // Count Leading Ones/Zeros in Word class CountLeading64 func, string instr_asm, list pattern>: - FR<0x1c, func, (outs CPU64Regs:$dst), (ins CPU64Regs:$src), - !strconcat(instr_asm, "\t$dst, $src"), pattern, IIAlu>, + FR<0x1c, func, (outs CPU64Regs:$rd), (ins CPU64Regs:$rs), + !strconcat(instr_asm, "\t$rd, $rs"), pattern, IIAlu>, Requires<[HasBitCount]> { let shamt = 0; let rt = rd; } //===----------------------------------------------------------------------===// // Instruction definition //===----------------------------------------------------------------------===// /// Arithmetic Instructions (ALU Immediate) def DADDiu : ArithLogicI<0x19, "daddiu", add, simm16_64, immSExt16, CPU64Regs>; def DANDi : ArithLogicI<0x0c, "andi", and, uimm16_64, immZExt16, CPU64Regs>; def SLTi64 : SetCC_I<0x0a, "slti", setlt, simm16_64, immSExt16, CPU64Regs>; def SLTiu64 : SetCC_I<0x0b, "sltiu", setult, simm16_64, immSExt16, CPU64Regs>; def ORi64 : ArithLogicI<0x0d, "ori", or, uimm16_64, immZExt16, CPU64Regs>; def XORi64 : ArithLogicI<0x0e, "xori", xor, uimm16_64, immZExt16, CPU64Regs>; /// Arithmetic Instructions (3-Operand, R-Type) def DADDu : ArithLogicR<0x00, 0x2d, "daddu", add, IIAlu, CPU64Regs, 1>; def DSUBu : ArithLogicR<0x00, 0x2f, "dsubu", sub, IIAlu, CPU64Regs>; def SLT64 : SetCC_R<0x00, 0x2a, "slt", setlt, CPU64Regs>; def SLTu64 : SetCC_R<0x00, 0x2b, "sltu", setult, CPU64Regs>; def AND64 : ArithLogicR<0x00, 0x24, "and", and, IIAlu, CPU64Regs, 1>; def OR64 : ArithLogicR<0x00, 0x25, "or", or, IIAlu, CPU64Regs, 1>; def XOR64 : ArithLogicR<0x00, 0x26, "xor", xor, IIAlu, CPU64Regs, 1>; def NOR64 : LogicNOR<0x00, 0x27, "nor", CPU64Regs>; /// Shift Instructions def DSLL : LogicR_shift_rotate_imm64<0x38, 0x00, "dsll", shl, immZExt5>; def DSRL : LogicR_shift_rotate_imm64<0x3a, 0x00, "dsrl", srl, immZExt5>; def DSRA : LogicR_shift_rotate_imm64<0x3b, 0x00, "dsra", sra, immZExt5>; def DSLL32 : LogicR_shift_rotate_imm64<0x3c, 0x00, "dsll32", shl, imm32_63>; def DSRL32 : LogicR_shift_rotate_imm64<0x3e, 0x00, "dsrl32", srl, imm32_63>; def DSRA32 : LogicR_shift_rotate_imm64<0x3f, 0x00, "dsra32", sra, imm32_63>; def DSLLV : LogicR_shift_rotate_reg64<0x24, 0x00, "dsllv", shl>; def DSRLV : LogicR_shift_rotate_reg64<0x26, 0x00, "dsrlv", srl>; def DSRAV : LogicR_shift_rotate_reg64<0x27, 0x00, "dsrav", sra>; // Rotate Instructions let Predicates = [HasMips64r2] in { def DROTR : LogicR_shift_rotate_imm64<0x3a, 0x01, "drotr", rotr, immZExt5>; def DROTR32 : LogicR_shift_rotate_imm64<0x3e, 0x01, "drotr32", rotr, imm32_63>; def DROTRV : LogicR_shift_rotate_reg64<0x16, 0x01, "drotrv", rotr>; } /// Load and Store Instructions /// aligned defm LB64 : LoadM64<0x20, "lb", sextloadi8>; defm LBu64 : LoadM64<0x24, "lbu", zextloadi8>; defm LH64 : LoadM64<0x21, "lh", sextloadi16_a>; defm LHu64 : LoadM64<0x25, "lhu", zextloadi16_a>; defm LW64 : LoadM64<0x23, "lw", sextloadi32_a>; defm LWu64 : LoadM64<0x27, "lwu", zextloadi32_a>; defm SB64 : StoreM64<0x28, "sb", truncstorei8>; defm SH64 : StoreM64<0x29, "sh", truncstorei16_a>; defm SW64 : StoreM64<0x2b, "sw", truncstorei32_a>; defm LD : LoadM64<0x37, "ld", load_a>; defm SD : StoreM64<0x3f, "sd", store_a>; /// unaligned defm ULH64 : LoadM64<0x21, "ulh", sextloadi16_u, 1>; defm ULHu64 : LoadM64<0x25, "ulhu", zextloadi16_u, 1>; defm ULW64 : LoadM64<0x23, "ulw", sextloadi32_u, 1>; defm USH64 : StoreM64<0x29, "ush", truncstorei16_u, 1>; defm USW64 : StoreM64<0x2b, "usw", truncstorei32_u, 1>; defm ULD : LoadM64<0x37, "uld", load_u, 1>; defm USD : StoreM64<0x3f, "usd", store_u, 1>; /// Jump and Branch Instructions def BEQ64 : CBranch<0x04, "beq", seteq, CPU64Regs>; def BNE64 : CBranch<0x05, "bne", setne, CPU64Regs>; def BGEZ64 : CBranchZero<0x01, 1, "bgez", setge, CPU64Regs>; def BGTZ64 : CBranchZero<0x07, 0, "bgtz", setgt, CPU64Regs>; def BLEZ64 : CBranchZero<0x07, 0, "blez", setle, CPU64Regs>; def BLTZ64 : CBranchZero<0x01, 0, "bltz", setlt, CPU64Regs>; /// Multiply and Divide Instructions. def DMULT : Mul64<0x1c, "dmult", IIImul>; def DMULTu : Mul64<0x1d, "dmultu", IIImul>; def DSDIV : Div64; def DUDIV : Div64; let Defs = [HI64] in def MTHI64 : MoveToLOHI64<0x11, "mthi">; let Defs = [LO64] in def MTLO64 : MoveToLOHI64<0x13, "mtlo">; let Uses = [HI64] in def MFHI64 : MoveFromLOHI64<0x10, "mfhi">; let Uses = [LO64] in def MFLO64 : MoveFromLOHI64<0x12, "mflo">; /// Count Leading def DCLZ : CountLeading64<0x24, "dclz", - [(set CPU64Regs:$dst, (ctlz CPU64Regs:$src))]>; + [(set CPU64Regs:$rd, (ctlz CPU64Regs:$rs))]>; def DCLO : CountLeading64<0x25, "dclo", - [(set CPU64Regs:$dst, (ctlz (not CPU64Regs:$src)))]>; + [(set CPU64Regs:$rd, (ctlz (not CPU64Regs:$rs)))]>; //===----------------------------------------------------------------------===// // Arbitrary patterns that map to one or more instructions //===----------------------------------------------------------------------===// // Small immediates def : Pat<(i64 immSExt16:$in), (DADDiu ZERO_64, imm:$in)>; def : Pat<(i64 immZExt16:$in), (ORi64 ZERO_64, imm:$in)>; // zextloadi32_u def : Pat<(zextloadi32_u addr:$a), (DSRL (DSLL (ULW64_P8 addr:$a), 32), 32)>, Requires<[IsN64]>; def : Pat<(zextloadi32_u addr:$a), (DSRL (DSLL (ULW64 addr:$a), 32), 32)>, Requires<[NotN64]>; // hi/lo relocs def : Pat<(i64 (MipsLo tglobaladdr:$in)), (DADDiu ZERO_64, tglobaladdr:$in)>; defm : BrcondPats; // setcc patterns defm : SeteqPats; defm : SetlePats; defm : SetgtPats; defm : SetgePats; defm : SetgeImmPats; Index: head/contrib/llvm/lib/Target/Mips/MipsCodeEmitter.cpp =================================================================== --- head/contrib/llvm/lib/Target/Mips/MipsCodeEmitter.cpp (revision 228378) +++ head/contrib/llvm/lib/Target/Mips/MipsCodeEmitter.cpp (revision 228379) @@ -1,245 +1,266 @@ //===-- Mips/MipsCodeEmitter.cpp - Convert Mips code to machine code -----===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===---------------------------------------------------------------------===// // // This file contains the pass that transforms the Mips machine instructions // into relocatable machine code. // //===---------------------------------------------------------------------===// #define DEBUG_TYPE "jit" #include "Mips.h" #include "MipsInstrInfo.h" #include "MipsRelocations.h" #include "MipsSubtarget.h" #include "MipsTargetMachine.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" #include "llvm/Function.h" #include "llvm/PassManager.h" #include "llvm/CodeGen/JITCodeEmitter.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/Passes.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #ifndef NDEBUG #include #endif #include "llvm/CodeGen/MachineOperand.h" using namespace llvm; STATISTIC(NumEmitted, "Number of machine instructions emitted"); namespace { class MipsCodeEmitter : public MachineFunctionPass { MipsJITInfo *JTI; const MipsInstrInfo *II; const TargetData *TD; const MipsSubtarget *Subtarget; TargetMachine &TM; JITCodeEmitter &MCE; const std::vector *MCPEs; const std::vector *MJTEs; bool IsPIC; void getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired (); MachineFunctionPass::getAnalysisUsage(AU); } static char ID; public: MipsCodeEmitter(TargetMachine &tm, JITCodeEmitter &mce) : MachineFunctionPass(ID), JTI(0), II((const MipsInstrInfo *) tm.getInstrInfo()), TD(tm.getTargetData()), TM(tm), MCE(mce), MCPEs(0), MJTEs(0), IsPIC(TM.getRelocationModel() == Reloc::PIC_) { } bool runOnMachineFunction(MachineFunction &MF); virtual const char *getPassName() const { return "Mips Machine Code Emitter"; } /// getBinaryCodeForInstr - This function, generated by the /// CodeEmitterGenerator using TableGen, produces the binary encoding for /// machine instructions. unsigned getBinaryCodeForInstr(const MachineInstr &MI) const; void emitInstruction(const MachineInstr &MI); private: void emitWordLE(unsigned Word); /// Routines that handle operands which add machine relocations which are /// fixed up by the relocation stage. void emitGlobalAddress(const GlobalValue *GV, unsigned Reloc, bool MayNeedFarStub) const; void emitExternalSymbolAddress(const char *ES, unsigned Reloc) const; void emitConstPoolAddress(unsigned CPI, unsigned Reloc) const; void emitJumpTableAddress(unsigned JTIndex, unsigned Reloc) const; void emitMachineBasicBlock(MachineBasicBlock *BB, unsigned Reloc) const; /// getMachineOpValue - Return binary encoding of operand. If the machine /// operand requires relocation, record the relocation and return zero. unsigned getMachineOpValue(const MachineInstr &MI, const MachineOperand &MO) const; unsigned getRelocation(const MachineInstr &MI, const MachineOperand &MO) const; + unsigned getMemEncoding(const MachineInstr &MI, unsigned OpNo) const; + unsigned getSizeExtEncoding(const MachineInstr &MI, unsigned OpNo) const; + unsigned getSizeInsEncoding(const MachineInstr &MI, unsigned OpNo) const; }; } char MipsCodeEmitter::ID = 0; bool MipsCodeEmitter::runOnMachineFunction(MachineFunction &MF) { JTI = ((MipsTargetMachine&) MF.getTarget()).getJITInfo(); II = ((const MipsTargetMachine&) MF.getTarget()).getInstrInfo(); TD = ((const MipsTargetMachine&) MF.getTarget()).getTargetData(); Subtarget = &TM.getSubtarget (); MCPEs = &MF.getConstantPool()->getConstants(); MJTEs = 0; if (MF.getJumpTableInfo()) MJTEs = &MF.getJumpTableInfo()->getJumpTables(); JTI->Initialize(MF, IsPIC); MCE.setModuleInfo(&getAnalysis ()); do { DEBUG(errs() << "JITTing function '" << MF.getFunction()->getName() << "'\n"); MCE.startFunction(MF); for (MachineFunction::iterator MBB = MF.begin(), E = MF.end(); MBB != E; ++MBB){ MCE.StartMachineBasicBlock(MBB); for (MachineBasicBlock::const_iterator I = MBB->begin(), E = MBB->end(); I != E; ++I) emitInstruction(*I); } } while (MCE.finishFunction(MF)); return false; } unsigned MipsCodeEmitter::getRelocation(const MachineInstr &MI, const MachineOperand &MO) const { // NOTE: This relocations are for static. uint64_t TSFlags = MI.getDesc().TSFlags; uint64_t Form = TSFlags & MipsII::FormMask; if (Form == MipsII::FrmJ) return Mips::reloc_mips_26; if ((Form == MipsII::FrmI || Form == MipsII::FrmFI) && MI.getDesc().isBranch()) return Mips::reloc_mips_branch; if (Form == MipsII::FrmI && MI.getOpcode() == Mips::LUi) return Mips::reloc_mips_hi; return Mips::reloc_mips_lo; } +unsigned MipsCodeEmitter::getMemEncoding(const MachineInstr &MI, + unsigned OpNo) const { + // Base register is encoded in bits 20-16, offset is encoded in bits 15-0. + assert(MI.getOperand(OpNo).isReg()); + unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo)) << 16; + return + (getMachineOpValue(MI, MI.getOperand(OpNo+1)) & 0xFFFF) | RegBits; +} + +unsigned MipsCodeEmitter::getSizeExtEncoding(const MachineInstr &MI, + unsigned OpNo) const { + // size is encoded as size-1. + return getMachineOpValue(MI, MI.getOperand(OpNo)) - 1; +} + +unsigned MipsCodeEmitter::getSizeInsEncoding(const MachineInstr &MI, + unsigned OpNo) const { + // size is encoded as pos+size-1. + return getMachineOpValue(MI, MI.getOperand(OpNo-1)) + + getMachineOpValue(MI, MI.getOperand(OpNo)) - 1; +} + /// getMachineOpValue - Return binary encoding of operand. If the machine /// operand requires relocation, record the relocation and return zero. unsigned MipsCodeEmitter::getMachineOpValue(const MachineInstr &MI, const MachineOperand &MO) const { if (MO.isReg()) return MipsRegisterInfo::getRegisterNumbering(MO.getReg()); else if (MO.isImm()) return static_cast(MO.getImm()); else if (MO.isGlobal()) emitGlobalAddress(MO.getGlobal(), getRelocation(MI, MO), true); else if (MO.isSymbol()) emitExternalSymbolAddress(MO.getSymbolName(), getRelocation(MI, MO)); else if (MO.isCPI()) emitConstPoolAddress(MO.getIndex(), getRelocation(MI, MO)); else if (MO.isJTI()) emitJumpTableAddress(MO.getIndex(), getRelocation(MI, MO)); else if (MO.isMBB()) emitMachineBasicBlock(MO.getMBB(), getRelocation(MI, MO)); else llvm_unreachable("Unable to encode MachineOperand!"); return 0; } void MipsCodeEmitter::emitGlobalAddress(const GlobalValue *GV, unsigned Reloc, bool MayNeedFarStub) const { MCE.addRelocation(MachineRelocation::getGV(MCE.getCurrentPCOffset(), Reloc, const_cast(GV), 0, MayNeedFarStub)); } void MipsCodeEmitter:: emitExternalSymbolAddress(const char *ES, unsigned Reloc) const { MCE.addRelocation(MachineRelocation::getExtSym(MCE.getCurrentPCOffset(), Reloc, ES, 0, 0, false)); } void MipsCodeEmitter::emitConstPoolAddress(unsigned CPI, unsigned Reloc) const { MCE.addRelocation(MachineRelocation::getConstPool(MCE.getCurrentPCOffset(), Reloc, CPI, 0, false)); } void MipsCodeEmitter:: emitJumpTableAddress(unsigned JTIndex, unsigned Reloc) const { MCE.addRelocation(MachineRelocation::getJumpTable(MCE.getCurrentPCOffset(), Reloc, JTIndex, 0, false)); } void MipsCodeEmitter::emitMachineBasicBlock(MachineBasicBlock *BB, unsigned Reloc) const { MCE.addRelocation(MachineRelocation::getBB(MCE.getCurrentPCOffset(), Reloc, BB)); } void MipsCodeEmitter::emitInstruction(const MachineInstr &MI) { DEBUG(errs() << "JIT: " << (void*)MCE.getCurrentPCValue() << ":\t" << MI); MCE.processDebugLoc(MI.getDebugLoc(), true); // Skip pseudo instructions. if ((MI.getDesc().TSFlags & MipsII::FormMask) == MipsII::Pseudo) return; ++NumEmitted; // Keep track of the # of mi's emitted switch (MI.getOpcode()) { default: emitWordLE(getBinaryCodeForInstr(MI)); break; } MCE.processDebugLoc(MI.getDebugLoc(), false); } void MipsCodeEmitter::emitWordLE(unsigned Word) { DEBUG(errs() << " 0x"; errs().write_hex(Word) << "\n"); MCE.emitWordLE(Word); } /// createMipsJITCodeEmitterPass - Return a pass that emits the collected Mips /// code to the specified MCE object. FunctionPass *llvm::createMipsJITCodeEmitterPass(MipsTargetMachine &TM, JITCodeEmitter &JCE) { return new MipsCodeEmitter(TM, JCE); } -unsigned MipsCodeEmitter::getBinaryCodeForInstr(const MachineInstr &MI) const { - // this function will be automatically generated by the CodeEmitterGenerator - // using TableGen - return 0; -} +#include "MipsGenCodeEmitter.inc" Index: head/contrib/llvm/lib/Target/Mips/MipsInstrFPU.td =================================================================== --- head/contrib/llvm/lib/Target/Mips/MipsInstrFPU.td (revision 228378) +++ head/contrib/llvm/lib/Target/Mips/MipsInstrFPU.td (revision 228379) @@ -1,362 +1,376 @@ //===- MipsInstrFPU.td - Mips FPU Instruction Information --*- tablegen -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file describes the Mips FPU instruction set. // //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// // Floating Point Instructions // ------------------------ // * 64bit fp: // - 32 64-bit registers (default mode) // - 16 even 32-bit registers (32-bit compatible mode) for // single and double access. // * 32bit fp: // - 16 even 32-bit registers - single and double (aliased) // - 32 32-bit registers (within single-only mode) //===----------------------------------------------------------------------===// // Floating Point Compare and Branch def SDT_MipsFPBrcond : SDTypeProfile<0, 2, [SDTCisInt<0>, SDTCisVT<1, OtherVT>]>; def SDT_MipsFPCmp : SDTypeProfile<0, 3, [SDTCisSameAs<0, 1>, SDTCisFP<1>, SDTCisVT<2, i32>]>; def SDT_MipsCMovFP : SDTypeProfile<1, 2, [SDTCisSameAs<0, 1>, SDTCisSameAs<1, 2>]>; def SDT_MipsBuildPairF64 : SDTypeProfile<1, 2, [SDTCisVT<0, f64>, SDTCisVT<1, i32>, SDTCisSameAs<1, 2>]>; def SDT_MipsExtractElementF64 : SDTypeProfile<1, 2, [SDTCisVT<0, i32>, SDTCisVT<1, f64>, SDTCisVT<2, i32>]>; def MipsFPCmp : SDNode<"MipsISD::FPCmp", SDT_MipsFPCmp, [SDNPOutGlue]>; def MipsCMovFP_T : SDNode<"MipsISD::CMovFP_T", SDT_MipsCMovFP, [SDNPInGlue]>; def MipsCMovFP_F : SDNode<"MipsISD::CMovFP_F", SDT_MipsCMovFP, [SDNPInGlue]>; def MipsFPBrcond : SDNode<"MipsISD::FPBrcond", SDT_MipsFPBrcond, [SDNPHasChain, SDNPOptInGlue]>; def MipsBuildPairF64 : SDNode<"MipsISD::BuildPairF64", SDT_MipsBuildPairF64>; def MipsExtractElementF64 : SDNode<"MipsISD::ExtractElementF64", SDT_MipsExtractElementF64>; // Operand for printing out a condition code. let PrintMethod = "printFCCOperand" in def condcode : Operand; //===----------------------------------------------------------------------===// // Feature predicates. //===----------------------------------------------------------------------===// def IsFP64bit : Predicate<"Subtarget.isFP64bit()">; def NotFP64bit : Predicate<"!Subtarget.isFP64bit()">; def IsSingleFloat : Predicate<"Subtarget.isSingleFloat()">; def IsNotSingleFloat : Predicate<"!Subtarget.isSingleFloat()">; //===----------------------------------------------------------------------===// // Instruction Class Templates // // A set of multiclasses is used to address the register usage. // // S32 - single precision in 16 32bit even fp registers // single precision in 32 32bit fp registers in SingleOnly mode // S64 - single precision in 32 64bit fp registers (In64BitMode) // D32 - double precision in 16 32bit even fp registers // D64 - double precision in 32 64bit fp registers (In64BitMode) // // Only S32 and D32 are supported right now. //===----------------------------------------------------------------------===// // FP load. class FPLoad op, string opstr, PatFrag FOp, RegisterClass RC, Operand MemOpnd>: - FFI; + FMem; // FP store. class FPStore op, string opstr, PatFrag FOp, RegisterClass RC, Operand MemOpnd>: - FFI; + FMem; // Instructions that convert an FP value to 32-bit fixed point. multiclass FFR1_W_M funct, string opstr> { def _S : FFR1; def _D32 : FFR1, Requires<[NotFP64bit]>; def _D64 : FFR1, Requires<[IsFP64bit]>; } // Instructions that convert an FP value to 64-bit fixed point. let Predicates = [IsFP64bit] in multiclass FFR1_L_M funct, string opstr> { def _S : FFR1; def _D64 : FFR1; } // FP-to-FP conversion instructions. multiclass FFR1P_M funct, string opstr, SDNode OpNode> { def _S : FFR1P; def _D32 : FFR1P, Requires<[NotFP64bit]>; def _D64 : FFR1P, Requires<[IsFP64bit]>; } multiclass FFR2P_M funct, string opstr, SDNode OpNode, bit isComm = 0> { let isCommutable = isComm in { def _S : FFR2P; def _D32 : FFR2P, Requires<[NotFP64bit]>; def _D64 : FFR2P, Requires<[IsFP64bit]>; } } //===----------------------------------------------------------------------===// // Floating Point Instructions //===----------------------------------------------------------------------===// defm ROUND_W : FFR1_W_M<0xc, "round">; defm ROUND_L : FFR1_L_M<0x8, "round">; defm TRUNC_W : FFR1_W_M<0xd, "trunc">; defm TRUNC_L : FFR1_L_M<0x9, "trunc">; defm CEIL_W : FFR1_W_M<0xe, "ceil">; defm CEIL_L : FFR1_L_M<0xa, "ceil">; defm FLOOR_W : FFR1_W_M<0xf, "floor">; defm FLOOR_L : FFR1_L_M<0xb, "floor">; defm CVT_W : FFR1_W_M<0x24, "cvt">; defm CVT_L : FFR1_L_M<0x25, "cvt">; def CVT_S_W : FFR1<0x20, 20, "cvt", "s.w", FGR32, FGR32>; let Predicates = [NotFP64bit] in { def CVT_S_D32 : FFR1<0x20, 17, "cvt", "s.d", FGR32, AFGR64>; def CVT_D32_W : FFR1<0x21, 20, "cvt", "d.w", AFGR64, FGR32>; def CVT_D32_S : FFR1<0x21, 16, "cvt", "d.s", AFGR64, FGR32>; } let Predicates = [IsFP64bit] in { def CVT_S_D64 : FFR1<0x20, 17, "cvt", "s.d", FGR32, FGR64>; def CVT_S_L : FFR1<0x20, 21, "cvt", "s.l", FGR32, FGR64>; def CVT_D64_W : FFR1<0x21, 20, "cvt", "d.w", FGR64, FGR32>; def CVT_D64_S : FFR1<0x21, 16, "cvt", "d.s", FGR64, FGR32>; def CVT_D64_L : FFR1<0x21, 21, "cvt", "d.l", FGR64, FGR64>; } defm FABS : FFR1P_M<0x5, "abs", fabs>; defm FNEG : FFR1P_M<0x7, "neg", fneg>; defm FSQRT : FFR1P_M<0x4, "sqrt", fsqrt>; // The odd-numbered registers are only referenced when doing loads, // stores, and moves between floating-point and integer registers. // When defining instructions, we reference all 32-bit registers, // regardless of register aliasing. -let fd = 0 in { - /// Move Control Registers From/To CPU Registers - def CFC1 : FFR<0x11, 0x0, 0x2, (outs CPURegs:$rt), (ins CCR:$fs), + +class FFRGPR _fmt, dag outs, dag ins, string asmstr, list pattern>: + FFR<0x11, 0x0, _fmt, outs, ins, asmstr, pattern> { + bits<5> rt; + let ft = rt; + let fd = 0; +} + +/// Move Control Registers From/To CPU Registers +def CFC1 : FFRGPR<0x2, (outs CPURegs:$rt), (ins CCR:$fs), "cfc1\t$rt, $fs", []>; - def CTC1 : FFR<0x11, 0x0, 0x6, (outs CCR:$rt), (ins CPURegs:$fs), - "ctc1\t$fs, $rt", []>; +def CTC1 : FFRGPR<0x6, (outs CCR:$fs), (ins CPURegs:$rt), + "ctc1\t$rt, $fs", []>; - def MFC1 : FFR<0x11, 0x00, 0x00, (outs CPURegs:$rt), (ins FGR32:$fs), +def MFC1 : FFRGPR<0x00, (outs CPURegs:$rt), (ins FGR32:$fs), "mfc1\t$rt, $fs", [(set CPURegs:$rt, (bitconvert FGR32:$fs))]>; - def MTC1 : FFR<0x11, 0x00, 0x04, (outs FGR32:$fs), (ins CPURegs:$rt), +def MTC1 : FFRGPR<0x04, (outs FGR32:$fs), (ins CPURegs:$rt), "mtc1\t$rt, $fs", [(set FGR32:$fs, (bitconvert CPURegs:$rt))]>; -} def FMOV_S : FFR1<0x6, 16, "mov", "s", FGR32, FGR32>; def FMOV_D32 : FFR1<0x6, 17, "mov", "d", AFGR64, AFGR64>, Requires<[NotFP64bit]>; def FMOV_D64 : FFR1<0x6, 17, "mov", "d", FGR64, FGR64>, Requires<[IsFP64bit]>; /// Floating Point Memory Instructions let Predicates = [IsN64] in { def LWC1_P8 : FPLoad<0x31, "lwc1", load, FGR32, mem64>; def SWC1_P8 : FPStore<0x39, "swc1", store, FGR32, mem64>; def LDC164_P8 : FPLoad<0x35, "ldc1", load, FGR64, mem64>; def SDC164_P8 : FPStore<0x3d, "sdc1", store, FGR64, mem64>; } let Predicates = [NotN64] in { def LWC1 : FPLoad<0x31, "lwc1", load, FGR32, mem>; def SWC1 : FPStore<0x39, "swc1", store, FGR32, mem>; let Predicates = [HasMips64] in { def LDC164 : FPLoad<0x35, "ldc1", load, FGR64, mem>; def SDC164 : FPStore<0x3d, "sdc1", store, FGR64, mem>; } let Predicates = [NotMips64] in { def LDC1 : FPLoad<0x35, "ldc1", load, AFGR64, mem>; def SDC1 : FPStore<0x3d, "sdc1", store, AFGR64, mem>; } } /// Floating-point Aritmetic -defm FADD : FFR2P_M<0x10, "add", fadd, 1>; +defm FADD : FFR2P_M<0x00, "add", fadd, 1>; defm FDIV : FFR2P_M<0x03, "div", fdiv>; defm FMUL : FFR2P_M<0x02, "mul", fmul, 1>; defm FSUB : FFR2P_M<0x01, "sub", fsub>; //===----------------------------------------------------------------------===// // Floating Point Branch Codes //===----------------------------------------------------------------------===// // Mips branch codes. These correspond to condcode in MipsInstrInfo.h. // They must be kept in synch. def MIPS_BRANCH_F : PatLeaf<(i32 0)>; def MIPS_BRANCH_T : PatLeaf<(i32 1)>; /// Floating Point Branch of False/True (Likely) let isBranch=1, isTerminator=1, hasDelaySlot=1, base=0x8, Uses=[FCR31] in - class FBRANCH : FFI<0x11, (outs), - (ins brtarget:$dst), !strconcat(asmstr, "\t$dst"), - [(MipsFPBrcond op, bb:$dst)]>; + class FBRANCH nd, bits<1> tf, PatLeaf op, string asmstr> : + FFI<0x11, (outs), (ins brtarget:$dst), !strconcat(asmstr, "\t$dst"), + [(MipsFPBrcond op, bb:$dst)]> { + let Inst{20-18} = 0; + let Inst{17} = nd; + let Inst{16} = tf; +} -def BC1F : FBRANCH; -def BC1T : FBRANCH; +def BC1F : FBRANCH<0, 0, MIPS_BRANCH_F, "bc1f">; +def BC1T : FBRANCH<0, 1, MIPS_BRANCH_T, "bc1t">; //===----------------------------------------------------------------------===// // Floating Point Flag Conditions //===----------------------------------------------------------------------===// // Mips condition codes. They must correspond to condcode in MipsInstrInfo.h. // They must be kept in synch. def MIPS_FCOND_F : PatLeaf<(i32 0)>; def MIPS_FCOND_UN : PatLeaf<(i32 1)>; def MIPS_FCOND_OEQ : PatLeaf<(i32 2)>; def MIPS_FCOND_UEQ : PatLeaf<(i32 3)>; def MIPS_FCOND_OLT : PatLeaf<(i32 4)>; def MIPS_FCOND_ULT : PatLeaf<(i32 5)>; def MIPS_FCOND_OLE : PatLeaf<(i32 6)>; def MIPS_FCOND_ULE : PatLeaf<(i32 7)>; def MIPS_FCOND_SF : PatLeaf<(i32 8)>; def MIPS_FCOND_NGLE : PatLeaf<(i32 9)>; def MIPS_FCOND_SEQ : PatLeaf<(i32 10)>; def MIPS_FCOND_NGL : PatLeaf<(i32 11)>; def MIPS_FCOND_LT : PatLeaf<(i32 12)>; def MIPS_FCOND_NGE : PatLeaf<(i32 13)>; def MIPS_FCOND_LE : PatLeaf<(i32 14)>; def MIPS_FCOND_NGT : PatLeaf<(i32 15)>; /// Floating Point Compare let Defs=[FCR31] in { - def FCMP_S32 : FCC<0x0, (outs), (ins FGR32:$fs, FGR32:$ft, condcode:$cc), + def FCMP_S32 : FCC<0x10, (outs), (ins FGR32:$fs, FGR32:$ft, condcode:$cc), "c.$cc.s\t$fs, $ft", [(MipsFPCmp FGR32:$fs, FGR32:$ft, imm:$cc)]>; - def FCMP_D32 : FCC<0x1, (outs), (ins AFGR64:$fs, AFGR64:$ft, condcode:$cc), + def FCMP_D32 : FCC<0x11, (outs), (ins AFGR64:$fs, AFGR64:$ft, condcode:$cc), "c.$cc.d\t$fs, $ft", [(MipsFPCmp AFGR64:$fs, AFGR64:$ft, imm:$cc)]>, Requires<[NotFP64bit]>; } // Conditional moves: // These instructions are expanded in // MipsISelLowering::EmitInstrWithCustomInserter if target does not have // conditional move instructions. // flag:int, data:float let usesCustomInserter = 1, Constraints = "$F = $dst" in class CondMovIntFP fmt, bits<6> func, string instr_asm> : FFR<0x11, func, fmt, (outs RC:$dst), (ins RC:$T, CPURegs:$cond, RC:$F), !strconcat(instr_asm, "\t$dst, $T, $cond"), []>; def MOVZ_S : CondMovIntFP; def MOVN_S : CondMovIntFP; let Predicates = [NotFP64bit] in { def MOVZ_D : CondMovIntFP; def MOVN_D : CondMovIntFP; } defm : MovzPats; defm : MovnPats; let Predicates = [NotFP64bit] in { defm : MovzPats; defm : MovnPats; } -let usesCustomInserter = 1, Uses = [FCR31], Constraints = "$F = $dst" in { +let cc = 0, usesCustomInserter = 1, Uses = [FCR31], + Constraints = "$F = $dst" in { // flag:float, data:int class CondMovFPInt tf, string instr_asm> : FCMOV; // flag:float, data:float +let cc = 0 in class CondMovFPFP fmt, bits<1> tf, string instr_asm> : FFCMOV; } def MOVT : CondMovFPInt; def MOVF : CondMovFPInt; def MOVT_S : CondMovFPFP; def MOVF_S : CondMovFPFP; let Predicates = [NotFP64bit] in { def MOVT_D : CondMovFPFP; def MOVF_D : CondMovFPFP; } //===----------------------------------------------------------------------===// // Floating Point Pseudo-Instructions //===----------------------------------------------------------------------===// def MOVCCRToCCR : MipsPseudo<(outs CCR:$dst), (ins CCR:$src), "# MOVCCRToCCR", []>; // This pseudo instr gets expanded into 2 mtc1 instrs after register // allocation. def BuildPairF64 : MipsPseudo<(outs AFGR64:$dst), (ins CPURegs:$lo, CPURegs:$hi), "", [(set AFGR64:$dst, (MipsBuildPairF64 CPURegs:$lo, CPURegs:$hi))]>; // This pseudo instr gets expanded into 2 mfc1 instrs after register // allocation. // if n is 0, lower part of src is extracted. // if n is 1, higher part of src is extracted. def ExtractElementF64 : MipsPseudo<(outs CPURegs:$dst), (ins AFGR64:$src, i32imm:$n), "", [(set CPURegs:$dst, (MipsExtractElementF64 AFGR64:$src, imm:$n))]>; //===----------------------------------------------------------------------===// // Floating Point Patterns //===----------------------------------------------------------------------===// def fpimm0 : PatLeaf<(fpimm), [{ return N->isExactlyValue(+0.0); }]>; def fpimm0neg : PatLeaf<(fpimm), [{ return N->isExactlyValue(-0.0); }]>; def : Pat<(f32 fpimm0), (MTC1 ZERO)>; def : Pat<(f32 fpimm0neg), (FNEG_S (MTC1 ZERO))>; def : Pat<(f32 (sint_to_fp CPURegs:$src)), (CVT_S_W (MTC1 CPURegs:$src))>; def : Pat<(f64 (sint_to_fp CPURegs:$src)), (CVT_D32_W (MTC1 CPURegs:$src))>; def : Pat<(i32 (fp_to_sint FGR32:$src)), (MFC1 (TRUNC_W_S FGR32:$src))>; def : Pat<(i32 (fp_to_sint AFGR64:$src)), (MFC1 (TRUNC_W_D32 AFGR64:$src))>; let Predicates = [NotFP64bit] in { def : Pat<(f32 (fround AFGR64:$src)), (CVT_S_D32 AFGR64:$src)>; def : Pat<(f64 (fextend FGR32:$src)), (CVT_D32_S FGR32:$src)>; } Index: head/contrib/llvm/lib/Target/Mips/MipsInstrFormats.td =================================================================== --- head/contrib/llvm/lib/Target/Mips/MipsInstrFormats.td (revision 228378) +++ head/contrib/llvm/lib/Target/Mips/MipsInstrFormats.td (revision 228379) @@ -1,267 +1,292 @@ //===- MipsInstrFormats.td - Mips Instruction Formats ------*- tablegen -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// // Describe MIPS instructions format // // CPU INSTRUCTION FORMATS // // opcode - operation code. // rs - src reg. // rt - dst reg (on a 2 regs instr) or src reg (on a 3 reg instr). // rd - dst reg, only used on 3 regs instr. // shamt - only used on shift instructions, contains the shift amount. // funct - combined with opcode field give us an operation code. // //===----------------------------------------------------------------------===// +// Format specifies the encoding used by the instruction. This is part of the +// ad-hoc solution used to emit machine instruction encodings by our machine +// code emitter. +class Format val> { + bits<4> Value = val; +} + +def Pseudo : Format<0>; +def FrmR : Format<1>; +def FrmI : Format<2>; +def FrmJ : Format<3>; +def FrmFR : Format<4>; +def FrmFI : Format<5>; +def FrmOther : Format<6>; // Instruction w/ a custom format + // Generic Mips Format class MipsInst pattern, - InstrItinClass itin>: Instruction + InstrItinClass itin, Format f>: Instruction { field bits<32> Inst; + Format Form = f; let Namespace = "Mips"; - bits<6> opcode; + bits<6> Opcode = 0; - // Top 5 bits are the 'opcode' field - let Inst{31-26} = opcode; + // Top 6 bits are the 'opcode' field + let Inst{31-26} = Opcode; - dag OutOperandList = outs; - dag InOperandList = ins; + let OutOperandList = outs; + let InOperandList = ins; let AsmString = asmstr; let Pattern = pattern; let Itinerary = itin; + + // + // Attributes specific to Mips instructions... + // + bits<4> FormBits = Form.Value; + + // TSFlags layout should be kept in sync with MipsInstrInfo.h. + let TSFlags{3-0} = FormBits; } // Mips Pseudo Instructions Format class MipsPseudo pattern>: - MipsInst { + MipsInst { + let isCodeGenOnly = 1; let isPseudo = 1; } //===----------------------------------------------------------------------===// // Format R instruction class in Mips : <|opcode|rs|rt|rd|shamt|funct|> //===----------------------------------------------------------------------===// class FR op, bits<6> _funct, dag outs, dag ins, string asmstr, list pattern, InstrItinClass itin>: - MipsInst + MipsInst { bits<5> rd; bits<5> rs; bits<5> rt; bits<5> shamt; bits<6> funct; - let opcode = op; + let Opcode = op; let funct = _funct; let Inst{25-21} = rs; let Inst{20-16} = rt; let Inst{15-11} = rd; let Inst{10-6} = shamt; let Inst{5-0} = funct; } //===----------------------------------------------------------------------===// // Format I instruction class in Mips : <|opcode|rs|rt|immediate|> //===----------------------------------------------------------------------===// class FI op, dag outs, dag ins, string asmstr, list pattern, - InstrItinClass itin>: MipsInst + InstrItinClass itin>: MipsInst { bits<5> rt; bits<5> rs; bits<16> imm16; - let opcode = op; + let Opcode = op; let Inst{25-21} = rs; let Inst{20-16} = rt; let Inst{15-0} = imm16; } class CBranchBase op, dag outs, dag ins, string asmstr, list pattern, InstrItinClass itin>: - MipsInst + MipsInst { bits<5> rs; bits<5> rt; bits<16> imm16; - let opcode = op; + let Opcode = op; let Inst{25-21} = rs; let Inst{20-16} = rt; let Inst{15-0} = imm16; } //===----------------------------------------------------------------------===// // Format J instruction class in Mips : <|opcode|address|> //===----------------------------------------------------------------------===// class FJ op, dag outs, dag ins, string asmstr, list pattern, - InstrItinClass itin>: MipsInst + InstrItinClass itin>: MipsInst { bits<26> addr; - let opcode = op; + let Opcode = op; let Inst{25-0} = addr; } //===----------------------------------------------------------------------===// // // FLOATING POINT INSTRUCTION FORMATS // // opcode - operation code. // fs - src reg. // ft - dst reg (on a 2 regs instr) or src reg (on a 3 reg instr). // fd - dst reg, only used on 3 regs instr. // fmt - double or single precision. // funct - combined with opcode field give us an operation code. // //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// // Format FR instruction class in Mips : <|opcode|fmt|ft|fs|fd|funct|> //===----------------------------------------------------------------------===// class FFR op, bits<6> _funct, bits<5> _fmt, dag outs, dag ins, string asmstr, list pattern> : - MipsInst + MipsInst { bits<5> fd; bits<5> fs; bits<5> ft; bits<5> fmt; bits<6> funct; - let opcode = op; + let Opcode = op; let funct = _funct; let fmt = _fmt; let Inst{25-21} = fmt; let Inst{20-16} = ft; let Inst{15-11} = fs; let Inst{10-6} = fd; let Inst{5-0} = funct; } //===----------------------------------------------------------------------===// // Format FI instruction class in Mips : <|opcode|base|ft|immediate|> //===----------------------------------------------------------------------===// class FFI op, dag outs, dag ins, string asmstr, list pattern>: - MipsInst + MipsInst { bits<5> ft; bits<5> base; bits<16> imm16; - let opcode = op; + let Opcode = op; let Inst{25-21} = base; let Inst{20-16} = ft; let Inst{15-0} = imm16; } //===----------------------------------------------------------------------===// // Compare instruction class in Mips : <|010001|fmt|ft|fs|0000011|condcode|> //===----------------------------------------------------------------------===// class FCC _fmt, dag outs, dag ins, string asmstr, list pattern> : - MipsInst + MipsInst { bits<5> fs; bits<5> ft; bits<4> cc; bits<5> fmt; - let opcode = 0x11; + let Opcode = 0x11; let fmt = _fmt; let Inst{25-21} = fmt; let Inst{20-16} = ft; let Inst{15-11} = fs; let Inst{10-6} = 0; let Inst{5-4} = 0b11; let Inst{3-0} = cc; } class FCMOV _tf, dag outs, dag ins, string asmstr, list pattern> : - MipsInst + MipsInst { bits<5> rd; bits<5> rs; - bits<3> N; + bits<3> cc; bits<1> tf; - let opcode = 0; + let Opcode = 0; let tf = _tf; let Inst{25-21} = rs; - let Inst{20-18} = N; + let Inst{20-18} = cc; let Inst{17} = 0; let Inst{16} = tf; let Inst{15-11} = rd; let Inst{10-6} = 0; let Inst{5-0} = 1; } class FFCMOV _fmt, bits<1> _tf, dag outs, dag ins, string asmstr, list pattern> : - MipsInst + MipsInst { bits<5> fd; bits<5> fs; - bits<3> N; + bits<3> cc; bits<5> fmt; bits<1> tf; - let opcode = 17; + let Opcode = 17; let fmt = _fmt; let tf = _tf; let Inst{25-21} = fmt; - let Inst{20-18} = N; + let Inst{20-18} = cc; let Inst{17} = 0; let Inst{16} = tf; let Inst{15-11} = fs; let Inst{10-6} = fd; let Inst{5-0} = 17; } // FP unary instructions without patterns. class FFR1 funct, bits<5> fmt, string opstr, string fmtstr, RegisterClass DstRC, RegisterClass SrcRC> : FFR<0x11, funct, fmt, (outs DstRC:$fd), (ins SrcRC:$fs), !strconcat(opstr, ".", fmtstr, "\t$fd, $fs"), []> { let ft = 0; } // FP unary instructions with patterns. class FFR1P funct, bits<5> fmt, string opstr, string fmtstr, RegisterClass DstRC, RegisterClass SrcRC, SDNode OpNode> : FFR<0x11, funct, fmt, (outs DstRC:$fd), (ins SrcRC:$fs), !strconcat(opstr, ".", fmtstr, "\t$fd, $fs"), [(set DstRC:$fd, (OpNode SrcRC:$fs))]> { let ft = 0; } class FFR2P funct, bits<5> fmt, string opstr, string fmtstr, RegisterClass RC, SDNode OpNode> : FFR<0x11, funct, fmt, (outs RC:$fd), (ins RC:$fs, RC:$ft), !strconcat(opstr, ".", fmtstr, "\t$fd, $fs, $ft"), [(set RC:$fd, (OpNode RC:$fs, RC:$ft))]>; Index: head/contrib/llvm/lib/Target/Mips/MipsInstrInfo.td =================================================================== --- head/contrib/llvm/lib/Target/Mips/MipsInstrInfo.td (revision 228378) +++ head/contrib/llvm/lib/Target/Mips/MipsInstrInfo.td (revision 228379) @@ -1,1017 +1,1038 @@ //===- MipsInstrInfo.td - Target Description for Mips Target -*- tablegen -*-=// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file contains the Mips implementation of the TargetInstrInfo class. // //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// // Instruction format superclass //===----------------------------------------------------------------------===// include "MipsInstrFormats.td" //===----------------------------------------------------------------------===// // Mips profiles and nodes //===----------------------------------------------------------------------===// def SDT_MipsRet : SDTypeProfile<0, 1, [SDTCisInt<0>]>; def SDT_MipsJmpLink : SDTypeProfile<0, 1, [SDTCisVT<0, iPTR>]>; def SDT_MipsCMov : SDTypeProfile<1, 4, [SDTCisSameAs<0, 1>, SDTCisSameAs<1, 2>, SDTCisSameAs<3, 4>, SDTCisInt<4>]>; def SDT_MipsCallSeqStart : SDCallSeqStart<[SDTCisVT<0, i32>]>; def SDT_MipsCallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; def SDT_MipsMAddMSub : SDTypeProfile<0, 4, [SDTCisVT<0, i32>, SDTCisSameAs<0, 1>, SDTCisSameAs<1, 2>, SDTCisSameAs<2, 3>]>; def SDT_MipsDivRem : SDTypeProfile<0, 2, [SDTCisInt<0>, SDTCisSameAs<0, 1>]>; def SDT_MipsThreadPointer : SDTypeProfile<1, 0, [SDTCisPtrTy<0>]>; def SDT_MipsDynAlloc : SDTypeProfile<1, 1, [SDTCisVT<0, i32>, SDTCisVT<1, iPTR>]>; def SDT_Sync : SDTypeProfile<0, 1, [SDTCisVT<0, i32>]>; def SDT_Ext : SDTypeProfile<1, 3, [SDTCisInt<0>, SDTCisSameAs<0, 1>, SDTCisVT<2, i32>, SDTCisSameAs<2, 3>]>; def SDT_Ins : SDTypeProfile<1, 4, [SDTCisInt<0>, SDTCisSameAs<0, 1>, SDTCisVT<2, i32>, SDTCisSameAs<2, 3>, SDTCisSameAs<0, 4>]>; // Call def MipsJmpLink : SDNode<"MipsISD::JmpLink",SDT_MipsJmpLink, [SDNPHasChain, SDNPOutGlue, SDNPOptInGlue, SDNPVariadic]>; // Hi and Lo nodes are used to handle global addresses. Used on // MipsISelLowering to lower stuff like GlobalAddress, ExternalSymbol // static model. (nothing to do with Mips Registers Hi and Lo) def MipsHi : SDNode<"MipsISD::Hi", SDTIntUnaryOp>; def MipsLo : SDNode<"MipsISD::Lo", SDTIntUnaryOp>; def MipsGPRel : SDNode<"MipsISD::GPRel", SDTIntUnaryOp>; // TlsGd node is used to handle General Dynamic TLS def MipsTlsGd : SDNode<"MipsISD::TlsGd", SDTIntUnaryOp>; // TprelHi and TprelLo nodes are used to handle Local Exec TLS def MipsTprelHi : SDNode<"MipsISD::TprelHi", SDTIntUnaryOp>; def MipsTprelLo : SDNode<"MipsISD::TprelLo", SDTIntUnaryOp>; // Thread pointer def MipsThreadPointer: SDNode<"MipsISD::ThreadPointer", SDT_MipsThreadPointer>; // Return def MipsRet : SDNode<"MipsISD::Ret", SDT_MipsRet, [SDNPHasChain, SDNPOptInGlue]>; // These are target-independent nodes, but have target-specific formats. def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_MipsCallSeqStart, [SDNPHasChain, SDNPOutGlue]>; def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_MipsCallSeqEnd, [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>; // MAdd*/MSub* nodes def MipsMAdd : SDNode<"MipsISD::MAdd", SDT_MipsMAddMSub, [SDNPOptInGlue, SDNPOutGlue]>; def MipsMAddu : SDNode<"MipsISD::MAddu", SDT_MipsMAddMSub, [SDNPOptInGlue, SDNPOutGlue]>; def MipsMSub : SDNode<"MipsISD::MSub", SDT_MipsMAddMSub, [SDNPOptInGlue, SDNPOutGlue]>; def MipsMSubu : SDNode<"MipsISD::MSubu", SDT_MipsMAddMSub, [SDNPOptInGlue, SDNPOutGlue]>; // DivRem(u) nodes def MipsDivRem : SDNode<"MipsISD::DivRem", SDT_MipsDivRem, [SDNPOutGlue]>; def MipsDivRemU : SDNode<"MipsISD::DivRemU", SDT_MipsDivRem, [SDNPOutGlue]>; // Target constant nodes that are not part of any isel patterns and remain // unchanged can cause instructions with illegal operands to be emitted. // Wrapper node patterns give the instruction selector a chance to replace // target constant nodes that would otherwise remain unchanged with ADDiu // nodes. Without these wrapper node patterns, the following conditional move // instrucion is emitted when function cmov2 in test/CodeGen/Mips/cmov.ll is // compiled: // movn %got(d)($gp), %got(c)($gp), $4 // This instruction is illegal since movn can take only register operands. def MipsWrapperPIC : SDNode<"MipsISD::WrapperPIC", SDTIntUnaryOp>; // Pointer to dynamically allocated stack area. def MipsDynAlloc : SDNode<"MipsISD::DynAlloc", SDT_MipsDynAlloc, [SDNPHasChain, SDNPInGlue]>; def MipsSync : SDNode<"MipsISD::Sync", SDT_Sync, [SDNPHasChain]>; def MipsExt : SDNode<"MipsISD::Ext", SDT_Ext>; def MipsIns : SDNode<"MipsISD::Ins", SDT_Ins>; //===----------------------------------------------------------------------===// // Mips Instruction Predicate Definitions. //===----------------------------------------------------------------------===// def HasSEInReg : Predicate<"Subtarget.hasSEInReg()">; def HasBitCount : Predicate<"Subtarget.hasBitCount()">; def HasSwap : Predicate<"Subtarget.hasSwap()">; def HasCondMov : Predicate<"Subtarget.hasCondMov()">; def HasMips32 : Predicate<"Subtarget.hasMips32()">; def HasMips32r2 : Predicate<"Subtarget.hasMips32r2()">; def HasMips64 : Predicate<"Subtarget.hasMips64()">; def NotMips64 : Predicate<"!Subtarget.hasMips64()">; def HasMips64r2 : Predicate<"Subtarget.hasMips64r2()">; def IsN64 : Predicate<"Subtarget.isABI_N64()">; def NotN64 : Predicate<"!Subtarget.isABI_N64()">; //===----------------------------------------------------------------------===// // Mips Operand, Complex Patterns and Transformations Definitions. //===----------------------------------------------------------------------===// // Instruction operand types def brtarget : Operand; def calltarget : Operand; def simm16 : Operand; def simm16_64 : Operand; def shamt : Operand; // Unsigned Operand def uimm16 : Operand { let PrintMethod = "printUnsignedImm"; } // Address operand def mem : Operand { let PrintMethod = "printMemOperand"; let MIOperandInfo = (ops CPURegs, simm16); + let EncoderMethod = "getMemEncoding"; } def mem64 : Operand { let PrintMethod = "printMemOperand"; let MIOperandInfo = (ops CPU64Regs, simm16_64); } def mem_ea : Operand { let PrintMethod = "printMemOperandEA"; let MIOperandInfo = (ops CPURegs, simm16); + let EncoderMethod = "getMemEncoding"; } +// size operand of ext instruction +def size_ext : Operand { + let EncoderMethod = "getSizeExtEncoding"; +} + +// size operand of ins instruction +def size_ins : Operand { + let EncoderMethod = "getSizeInsEncoding"; +} + // Transformation Function - get the lower 16 bits. def LO16 : SDNodeXFormgetZExtValue() & 0xFFFF); }]>; // Transformation Function - get the higher 16 bits. def HI16 : SDNodeXFormgetZExtValue() >> 16); }]>; // Node immediate fits as 16-bit sign extended on target immediate. // e.g. addi, andi def immSExt16 : PatLeaf<(imm), [{ return isInt<16>(N->getSExtValue()); }]>; // Node immediate fits as 16-bit zero extended on target immediate. // The LO16 param means that only the lower 16 bits of the node // immediate are caught. // e.g. addiu, sltiu def immZExt16 : PatLeaf<(imm), [{ if (N->getValueType(0) == MVT::i32) return (uint32_t)N->getZExtValue() == (unsigned short)N->getZExtValue(); else return (uint64_t)N->getZExtValue() == (unsigned short)N->getZExtValue(); }], LO16>; // shamt field must fit in 5 bits. def immZExt5 : PatLeaf<(imm), [{ return N->getZExtValue() == ((N->getZExtValue()) & 0x1f) ; }]>; // Mips Address Mode! SDNode frameindex could possibily be a match // since load and store instructions from stack used it. def addr : ComplexPattern; //===----------------------------------------------------------------------===// // Pattern fragment for load/store //===----------------------------------------------------------------------===// class UnalignedLoad : PatFrag<(ops node:$ptr), (Node node:$ptr), [{ LoadSDNode *LD = cast(N); return LD->getMemoryVT().getSizeInBits()/8 > LD->getAlignment(); }]>; class AlignedLoad : PatFrag<(ops node:$ptr), (Node node:$ptr), [{ LoadSDNode *LD = cast(N); return LD->getMemoryVT().getSizeInBits()/8 <= LD->getAlignment(); }]>; class UnalignedStore : PatFrag<(ops node:$val, node:$ptr), (Node node:$val, node:$ptr), [{ StoreSDNode *SD = cast(N); return SD->getMemoryVT().getSizeInBits()/8 > SD->getAlignment(); }]>; class AlignedStore : PatFrag<(ops node:$val, node:$ptr), (Node node:$val, node:$ptr), [{ StoreSDNode *SD = cast(N); return SD->getMemoryVT().getSizeInBits()/8 <= SD->getAlignment(); }]>; // Load/Store PatFrags. def sextloadi16_a : AlignedLoad; def zextloadi16_a : AlignedLoad; def extloadi16_a : AlignedLoad; def load_a : AlignedLoad; def sextloadi32_a : AlignedLoad; def zextloadi32_a : AlignedLoad; def extloadi32_a : AlignedLoad; def truncstorei16_a : AlignedStore; def store_a : AlignedStore; def truncstorei32_a : AlignedStore; def sextloadi16_u : UnalignedLoad; def zextloadi16_u : UnalignedLoad; def extloadi16_u : UnalignedLoad; def load_u : UnalignedLoad; def sextloadi32_u : UnalignedLoad; def zextloadi32_u : UnalignedLoad; def extloadi32_u : UnalignedLoad; def truncstorei16_u : UnalignedStore; def store_u : UnalignedStore; def truncstorei32_u : UnalignedStore; //===----------------------------------------------------------------------===// // Instructions specific format //===----------------------------------------------------------------------===// // Arithmetic and logical instructions with 3 register operands. class ArithLogicR op, bits<6> func, string instr_asm, SDNode OpNode, InstrItinClass itin, RegisterClass RC, bit isComm = 0>: FR { let shamt = 0; let isCommutable = isComm; } class ArithOverflowR op, bits<6> func, string instr_asm, InstrItinClass itin, RegisterClass RC, bit isComm = 0>: FR { let shamt = 0; let isCommutable = isComm; } // Arithmetic and logical instructions with 2 register operands. class ArithLogicI op, string instr_asm, SDNode OpNode, Operand Od, PatLeaf imm_type, RegisterClass RC> : - FI; + FI; class ArithOverflowI op, string instr_asm, SDNode OpNode, Operand Od, PatLeaf imm_type, RegisterClass RC> : - FI; + FI; // Arithmetic Multiply ADD/SUB let rd = 0, shamt = 0, Defs = [HI, LO], Uses = [HI, LO] in class MArithR func, string instr_asm, SDNode op, bit isComm = 0> : FR<0x1c, func, (outs), (ins CPURegs:$rs, CPURegs:$rt), !strconcat(instr_asm, "\t$rs, $rt"), [(op CPURegs:$rs, CPURegs:$rt, LO, HI)], IIImul> { let rd = 0; let shamt = 0; let isCommutable = isComm; } // Logical class LogicNOR op, bits<6> func, string instr_asm, RegisterClass RC>: FR { let shamt = 0; let isCommutable = 1; } // Shifts class LogicR_shift_rotate_imm func, bits<5> _rs, string instr_asm, SDNode OpNode>: FR<0x00, func, (outs CPURegs:$rd), (ins CPURegs:$rt, shamt:$shamt), !strconcat(instr_asm, "\t$rd, $rt, $shamt"), [(set CPURegs:$rd, (OpNode CPURegs:$rt, (i32 immZExt5:$shamt)))], IIAlu> { let rs = _rs; } class LogicR_shift_rotate_reg func, bits<5> isRotate, string instr_asm, SDNode OpNode>: FR<0x00, func, (outs CPURegs:$rd), (ins CPURegs:$rs, CPURegs:$rt), !strconcat(instr_asm, "\t$rd, $rt, $rs"), [(set CPURegs:$rd, (OpNode CPURegs:$rt, CPURegs:$rs))], IIAlu> { let shamt = isRotate; } // Load Upper Imediate class LoadUpper op, string instr_asm>: - FI { + FI { let rs = 0; } +class FMem op, dag outs, dag ins, string asmstr, list pattern, + InstrItinClass itin>: FFI { + bits<21> addr; + let Inst{25-21} = addr{20-16}; + let Inst{15-0} = addr{15-0}; +} + // Memory Load/Store let canFoldAsLoad = 1 in class LoadM op, string instr_asm, PatFrag OpNode, RegisterClass RC, Operand MemOpnd, bit Pseudo>: - FI { let isPseudo = Pseudo; } class StoreM op, string instr_asm, PatFrag OpNode, RegisterClass RC, Operand MemOpnd, bit Pseudo>: - FI { let isPseudo = Pseudo; } // 32-bit load. multiclass LoadM32 op, string instr_asm, PatFrag OpNode, bit Pseudo = 0> { def #NAME# : LoadM, Requires<[NotN64]>; def _P8 : LoadM, Requires<[IsN64]>; } // 64-bit load. multiclass LoadM64 op, string instr_asm, PatFrag OpNode, bit Pseudo = 0> { def #NAME# : LoadM, Requires<[NotN64]>; def _P8 : LoadM, Requires<[IsN64]>; } // 32-bit store. multiclass StoreM32 op, string instr_asm, PatFrag OpNode, bit Pseudo = 0> { def #NAME# : StoreM, Requires<[NotN64]>; def _P8 : StoreM, Requires<[IsN64]>; } // 64-bit store. multiclass StoreM64 op, string instr_asm, PatFrag OpNode, bit Pseudo = 0> { def #NAME# : StoreM, Requires<[NotN64]>; def _P8 : StoreM, Requires<[IsN64]>; } // Conditional Branch class CBranch op, string instr_asm, PatFrag cond_op, RegisterClass RC>: - CBranchBase { + CBranchBase { let isBranch = 1; let isTerminator = 1; let hasDelaySlot = 1; } class CBranchZero op, bits<5> _rt, string instr_asm, PatFrag cond_op, RegisterClass RC>: - CBranchBase { + CBranchBase { let rt = _rt; let isBranch = 1; let isTerminator = 1; let hasDelaySlot = 1; } // SetCC class SetCC_R op, bits<6> func, string instr_asm, PatFrag cond_op, RegisterClass RC>: FR { let shamt = 0; } class SetCC_I op, string instr_asm, PatFrag cond_op, Operand Od, PatLeaf imm_type, RegisterClass RC>: - FI; // Unconditional branch let isBranch=1, isTerminator=1, isBarrier=1, hasDelaySlot = 1 in class JumpFJ op, string instr_asm>: FJ; let isBranch=1, isTerminator=1, isBarrier=1, rd=0, hasDelaySlot = 1 in class JumpFR op, bits<6> func, string instr_asm>: FR { let rt = 0; let rd = 0; let shamt = 0; } // Jump and Link (Call) let isCall=1, hasDelaySlot=1, // All calls clobber the non-callee saved registers... Defs = [AT, V0, V1, A0, A1, A2, A3, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, K0, K1, D0, D1, D2, D3, D4, D5, D6, D7, D8, D9], Uses = [GP] in { class JumpLink op, string instr_asm>: FJ; class JumpLinkReg op, bits<6> func, string instr_asm>: FR { let rt = 0; let rd = 31; let shamt = 0; } class BranchLink: - FI<0x1, (outs), (ins CPURegs:$rs, brtarget:$target, variable_ops), - !strconcat(instr_asm, "\t$rs, $target"), [], IIBranch> { - let rt = 0; - } + FI<0x1, (outs), (ins CPURegs:$rs, brtarget:$imm16, variable_ops), + !strconcat(instr_asm, "\t$rs, $imm16"), [], IIBranch>; } // Mul, Div class Mul func, string instr_asm, InstrItinClass itin>: FR<0x00, func, (outs), (ins CPURegs:$rs, CPURegs:$rt), !strconcat(instr_asm, "\t$rs, $rt"), [], itin> { let rd = 0; let shamt = 0; let isCommutable = 1; let Defs = [HI, LO]; } class Div func, string instr_asm, InstrItinClass itin>: FR<0x00, func, (outs), (ins CPURegs:$rs, CPURegs:$rt), !strconcat(instr_asm, "\t$$zero, $rs, $rt"), [(op CPURegs:$rs, CPURegs:$rt)], itin> { let rd = 0; let shamt = 0; let Defs = [HI, LO]; } // Move from Hi/Lo class MoveFromLOHI func, string instr_asm>: FR<0x00, func, (outs CPURegs:$rd), (ins), !strconcat(instr_asm, "\t$rd"), [], IIHiLo> { let rs = 0; let rt = 0; let shamt = 0; } class MoveToLOHI func, string instr_asm>: FR<0x00, func, (outs), (ins CPURegs:$rs), !strconcat(instr_asm, "\t$rs"), [], IIHiLo> { let rt = 0; let rd = 0; let shamt = 0; } class EffectiveAddress : - FI<0x09, (outs CPURegs:$rt), (ins mem_ea:$addr), + FMem<0x09, (outs CPURegs:$rt), (ins mem_ea:$addr), instr_asm, [(set CPURegs:$rt, addr:$addr)], IIAlu>; // Count Leading Ones/Zeros in Word class CountLeading func, string instr_asm, list pattern>: FR<0x1c, func, (outs CPURegs:$rd), (ins CPURegs:$rs), !strconcat(instr_asm, "\t$rd, $rs"), pattern, IIAlu>, Requires<[HasBitCount]> { let shamt = 0; let rt = rd; } // Sign Extend in Register. class SignExtInReg sa, string instr_asm, ValueType vt>: - FR<0x3f, 0x20, (outs CPURegs:$rd), (ins CPURegs:$rt), + FR<0x1f, 0x20, (outs CPURegs:$rd), (ins CPURegs:$rt), !strconcat(instr_asm, "\t$rd, $rt"), [(set CPURegs:$rd, (sext_inreg CPURegs:$rt, vt))], NoItinerary> { let rs = 0; let shamt = sa; let Predicates = [HasSEInReg]; } // Byte Swap class ByteSwap func, bits<5> sa, string instr_asm>: FR<0x1f, func, (outs CPURegs:$rd), (ins CPURegs:$rt), !strconcat(instr_asm, "\t$rd, $rt"), [(set CPURegs:$rd, (bswap CPURegs:$rt))], NoItinerary> { let rs = 0; let shamt = sa; let Predicates = [HasSwap]; } // Read Hardware class ReadHardware: FR<0x1f, 0x3b, (outs CPURegs:$rt), (ins HWRegs:$rd), "rdhwr\t$rt, $rd", [], IIAlu> { let rs = 0; let shamt = 0; } // Ext and Ins class ExtIns _funct, string instr_asm, dag outs, dag ins, list pattern, InstrItinClass itin>: FR<0x1f, _funct, outs, ins, !strconcat(instr_asm, " $rt, $rs, $pos, $sz"), pattern, itin>, Requires<[HasMips32r2]> { bits<5> pos; bits<5> sz; let rd = sz; let shamt = pos; } // Atomic instructions with 2 source operands (ATOMIC_SWAP & ATOMIC_LOAD_*). class Atomic2Ops : MipsPseudo<(outs CPURegs:$dst), (ins CPURegs:$ptr, CPURegs:$incr), !strconcat("atomic_", Opstr, "\t$dst, $ptr, $incr"), [(set CPURegs:$dst, (Op CPURegs:$ptr, CPURegs:$incr))]>; // Atomic Compare & Swap. class AtomicCmpSwap : MipsPseudo<(outs CPURegs:$dst), (ins CPURegs:$ptr, CPURegs:$cmp, CPURegs:$swap), !strconcat("atomic_cmp_swap_", Width, "\t$dst, $ptr, $cmp, $swap"), [(set CPURegs:$dst, (Op CPURegs:$ptr, CPURegs:$cmp, CPURegs:$swap))]>; //===----------------------------------------------------------------------===// // Pseudo instructions //===----------------------------------------------------------------------===// // As stack alignment is always done with addiu, we need a 16-bit immediate let Defs = [SP], Uses = [SP] in { def ADJCALLSTACKDOWN : MipsPseudo<(outs), (ins uimm16:$amt), "!ADJCALLSTACKDOWN $amt", [(callseq_start timm:$amt)]>; def ADJCALLSTACKUP : MipsPseudo<(outs), (ins uimm16:$amt1, uimm16:$amt2), "!ADJCALLSTACKUP $amt1", [(callseq_end timm:$amt1, timm:$amt2)]>; } // Some assembly macros need to avoid pseudoinstructions and assembler // automatic reodering, we should reorder ourselves. def MACRO : MipsPseudo<(outs), (ins), ".set\tmacro", []>; def REORDER : MipsPseudo<(outs), (ins), ".set\treorder", []>; def NOMACRO : MipsPseudo<(outs), (ins), ".set\tnomacro", []>; def NOREORDER : MipsPseudo<(outs), (ins), ".set\tnoreorder", []>; // These macros are inserted to prevent GAS from complaining // when using the AT register. def NOAT : MipsPseudo<(outs), (ins), ".set\tnoat", []>; def ATMACRO : MipsPseudo<(outs), (ins), ".set\tat", []>; // When handling PIC code the assembler needs .cpload and .cprestore // directives. If the real instructions corresponding these directives // are used, we have the same behavior, but get also a bunch of warnings // from the assembler. def CPLOAD : MipsPseudo<(outs), (ins CPURegs:$picreg), ".cpload\t$picreg", []>; def CPRESTORE : MipsPseudo<(outs), (ins i32imm:$loc), ".cprestore\t$loc", []>; let usesCustomInserter = 1 in { def ATOMIC_LOAD_ADD_I8 : Atomic2Ops; def ATOMIC_LOAD_ADD_I16 : Atomic2Ops; def ATOMIC_LOAD_ADD_I32 : Atomic2Ops; def ATOMIC_LOAD_SUB_I8 : Atomic2Ops; def ATOMIC_LOAD_SUB_I16 : Atomic2Ops; def ATOMIC_LOAD_SUB_I32 : Atomic2Ops; def ATOMIC_LOAD_AND_I8 : Atomic2Ops; def ATOMIC_LOAD_AND_I16 : Atomic2Ops; def ATOMIC_LOAD_AND_I32 : Atomic2Ops; def ATOMIC_LOAD_OR_I8 : Atomic2Ops; def ATOMIC_LOAD_OR_I16 : Atomic2Ops; def ATOMIC_LOAD_OR_I32 : Atomic2Ops; def ATOMIC_LOAD_XOR_I8 : Atomic2Ops; def ATOMIC_LOAD_XOR_I16 : Atomic2Ops; def ATOMIC_LOAD_XOR_I32 : Atomic2Ops; def ATOMIC_LOAD_NAND_I8 : Atomic2Ops; def ATOMIC_LOAD_NAND_I16 : Atomic2Ops; def ATOMIC_LOAD_NAND_I32 : Atomic2Ops; def ATOMIC_SWAP_I8 : Atomic2Ops; def ATOMIC_SWAP_I16 : Atomic2Ops; def ATOMIC_SWAP_I32 : Atomic2Ops; def ATOMIC_CMP_SWAP_I8 : AtomicCmpSwap; def ATOMIC_CMP_SWAP_I16 : AtomicCmpSwap; def ATOMIC_CMP_SWAP_I32 : AtomicCmpSwap; } //===----------------------------------------------------------------------===// // Instruction definition //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// // MipsI Instructions //===----------------------------------------------------------------------===// /// Arithmetic Instructions (ALU Immediate) def ADDiu : ArithLogicI<0x09, "addiu", add, simm16, immSExt16, CPURegs>; def ADDi : ArithOverflowI<0x08, "addi", add, simm16, immSExt16, CPURegs>; def SLTi : SetCC_I<0x0a, "slti", setlt, simm16, immSExt16, CPURegs>; def SLTiu : SetCC_I<0x0b, "sltiu", setult, simm16, immSExt16, CPURegs>; def ANDi : ArithLogicI<0x0c, "andi", and, uimm16, immZExt16, CPURegs>; def ORi : ArithLogicI<0x0d, "ori", or, uimm16, immZExt16, CPURegs>; def XORi : ArithLogicI<0x0e, "xori", xor, uimm16, immZExt16, CPURegs>; def LUi : LoadUpper<0x0f, "lui">; /// Arithmetic Instructions (3-Operand, R-Type) def ADDu : ArithLogicR<0x00, 0x21, "addu", add, IIAlu, CPURegs, 1>; def SUBu : ArithLogicR<0x00, 0x23, "subu", sub, IIAlu, CPURegs>; def ADD : ArithOverflowR<0x00, 0x20, "add", IIAlu, CPURegs, 1>; def SUB : ArithOverflowR<0x00, 0x22, "sub", IIAlu, CPURegs>; def SLT : SetCC_R<0x00, 0x2a, "slt", setlt, CPURegs>; def SLTu : SetCC_R<0x00, 0x2b, "sltu", setult, CPURegs>; def AND : ArithLogicR<0x00, 0x24, "and", and, IIAlu, CPURegs, 1>; def OR : ArithLogicR<0x00, 0x25, "or", or, IIAlu, CPURegs, 1>; def XOR : ArithLogicR<0x00, 0x26, "xor", xor, IIAlu, CPURegs, 1>; def NOR : LogicNOR<0x00, 0x27, "nor", CPURegs>; /// Shift Instructions def SLL : LogicR_shift_rotate_imm<0x00, 0x00, "sll", shl>; def SRL : LogicR_shift_rotate_imm<0x02, 0x00, "srl", srl>; def SRA : LogicR_shift_rotate_imm<0x03, 0x00, "sra", sra>; def SLLV : LogicR_shift_rotate_reg<0x04, 0x00, "sllv", shl>; def SRLV : LogicR_shift_rotate_reg<0x06, 0x00, "srlv", srl>; def SRAV : LogicR_shift_rotate_reg<0x07, 0x00, "srav", sra>; // Rotate Instructions let Predicates = [HasMips32r2] in { def ROTR : LogicR_shift_rotate_imm<0x02, 0x01, "rotr", rotr>; def ROTRV : LogicR_shift_rotate_reg<0x06, 0x01, "rotrv", rotr>; } /// Load and Store Instructions /// aligned defm LB : LoadM32<0x20, "lb", sextloadi8>; defm LBu : LoadM32<0x24, "lbu", zextloadi8>; defm LH : LoadM32<0x21, "lh", sextloadi16_a>; defm LHu : LoadM32<0x25, "lhu", zextloadi16_a>; defm LW : LoadM32<0x23, "lw", load_a>; defm SB : StoreM32<0x28, "sb", truncstorei8>; defm SH : StoreM32<0x29, "sh", truncstorei16_a>; defm SW : StoreM32<0x2b, "sw", store_a>; /// unaligned defm ULH : LoadM32<0x21, "ulh", sextloadi16_u, 1>; defm ULHu : LoadM32<0x25, "ulhu", zextloadi16_u, 1>; defm ULW : LoadM32<0x23, "ulw", load_u, 1>; defm USH : StoreM32<0x29, "ush", truncstorei16_u, 1>; defm USW : StoreM32<0x2b, "usw", store_u, 1>; let hasSideEffects = 1 in def SYNC : MipsInst<(outs), (ins i32imm:$stype), "sync $stype", - [(MipsSync imm:$stype)], NoItinerary> + [(MipsSync imm:$stype)], NoItinerary, FrmOther> { - let opcode = 0; + bits<5> stype; + let Opcode = 0; let Inst{25-11} = 0; + let Inst{10-6} = stype; let Inst{5-0} = 15; } /// Load-linked, Store-conditional let mayLoad = 1 in - def LL : FI<0x30, (outs CPURegs:$dst), (ins mem:$addr), - "ll\t$dst, $addr", [], IILoad>; -let mayStore = 1, Constraints = "$src = $dst" in - def SC : FI<0x38, (outs CPURegs:$dst), (ins CPURegs:$src, mem:$addr), - "sc\t$src, $addr", [], IIStore>; + def LL : FMem<0x30, (outs CPURegs:$rt), (ins mem:$addr), + "ll\t$rt, $addr", [], IILoad>; +let mayStore = 1, Constraints = "$rt = $dst" in + def SC : FMem<0x38, (outs CPURegs:$dst), (ins CPURegs:$rt, mem:$addr), + "sc\t$rt, $addr", [], IIStore>; /// Jump and Branch Instructions def J : JumpFJ<0x02, "j">; let isIndirectBranch = 1 in def JR : JumpFR<0x00, 0x08, "jr">; def JAL : JumpLink<0x03, "jal">; def JALR : JumpLinkReg<0x00, 0x09, "jalr">; def BEQ : CBranch<0x04, "beq", seteq, CPURegs>; def BNE : CBranch<0x05, "bne", setne, CPURegs>; def BGEZ : CBranchZero<0x01, 1, "bgez", setge, CPURegs>; def BGTZ : CBranchZero<0x07, 0, "bgtz", setgt, CPURegs>; -def BLEZ : CBranchZero<0x07, 0, "blez", setle, CPURegs>; +def BLEZ : CBranchZero<0x06, 0, "blez", setle, CPURegs>; def BLTZ : CBranchZero<0x01, 0, "bltz", setlt, CPURegs>; -def BGEZAL : BranchLink<"bgezal">; -def BLTZAL : BranchLink<"bltzal">; +let rt=0x11 in + def BGEZAL : BranchLink<"bgezal">; +let rt=0x10 in + def BLTZAL : BranchLink<"bltzal">; let isReturn=1, isTerminator=1, hasDelaySlot=1, - isBarrier=1, hasCtrlDep=1, rs=0, rt=0, shamt=0 in - def RET : FR <0x00, 0x02, (outs), (ins CPURegs:$target), + isBarrier=1, hasCtrlDep=1, rd=0, rt=0, shamt=0 in + def RET : FR <0x00, 0x08, (outs), (ins CPURegs:$target), "jr\t$target", [(MipsRet CPURegs:$target)], IIBranch>; /// Multiply and Divide Instructions. def MULT : Mul<0x18, "mult", IIImul>; def MULTu : Mul<0x19, "multu", IIImul>; def SDIV : Div; def UDIV : Div; let Defs = [HI] in def MTHI : MoveToLOHI<0x11, "mthi">; let Defs = [LO] in def MTLO : MoveToLOHI<0x13, "mtlo">; let Uses = [HI] in def MFHI : MoveFromLOHI<0x10, "mfhi">; let Uses = [LO] in def MFLO : MoveFromLOHI<0x12, "mflo">; /// Sign Ext In Register Instructions. def SEB : SignExtInReg<0x10, "seb", i8>; def SEH : SignExtInReg<0x18, "seh", i16>; /// Count Leading def CLZ : CountLeading<0x20, "clz", [(set CPURegs:$rd, (ctlz CPURegs:$rs))]>; def CLO : CountLeading<0x21, "clo", [(set CPURegs:$rd, (ctlz (not CPURegs:$rs)))]>; /// Byte Swap def WSBW : ByteSwap<0x20, 0x2, "wsbw">; // Conditional moves: // These instructions are expanded in // MipsISelLowering::EmitInstrWithCustomInserter if target does not have // conditional move instructions. // flag:int, data:int class CondMovIntInt funct, string instr_asm> : FR<0, funct, (outs CPURegs:$rd), (ins CPURegs:$rs, CPURegs:$rt, CPURegs:$F), !strconcat(instr_asm, "\t$rd, $rs, $rt"), [], NoItinerary> { let shamt = 0; let usesCustomInserter = 1; let Constraints = "$F = $rd"; } def MOVZ_I : CondMovIntInt<0x0a, "movz">; def MOVN_I : CondMovIntInt<0x0b, "movn">; /// No operation let addr=0 in def NOP : FJ<0, (outs), (ins), "nop", [], IIAlu>; // FrameIndexes are legalized when they are operands from load/store // instructions. The same not happens for stack address copies, so an // add op with mem ComplexPattern is used and the stack address copy // can be matched. It's similar to Sparc LEA_ADDRi def LEA_ADDiu : EffectiveAddress<"addiu\t$rt, $addr">; // DynAlloc node points to dynamically allocated stack space. // $sp is added to the list of implicitly used registers to prevent dead code // elimination from removing instructions that modify $sp. let Uses = [SP] in def DynAlloc : EffectiveAddress<"addiu\t$rt, $addr">; // MADD*/MSUB* def MADD : MArithR<0, "madd", MipsMAdd, 1>; def MADDU : MArithR<1, "maddu", MipsMAddu, 1>; def MSUB : MArithR<4, "msub", MipsMSub>; def MSUBU : MArithR<5, "msubu", MipsMSubu>; // MUL is a assembly macro in the current used ISAs. In recent ISA's // it is a real instruction. def MUL : ArithLogicR<0x1c, 0x02, "mul", mul, IIImul, CPURegs, 1>, Requires<[HasMips32]>; def RDHWR : ReadHardware; def EXT : ExtIns<0, "ext", (outs CPURegs:$rt), - (ins CPURegs:$rs, uimm16:$pos, uimm16:$sz), + (ins CPURegs:$rs, uimm16:$pos, size_ext:$sz), [(set CPURegs:$rt, (MipsExt CPURegs:$rs, immZExt5:$pos, immZExt5:$sz))], NoItinerary>; let Constraints = "$src = $rt" in def INS : ExtIns<4, "ins", (outs CPURegs:$rt), - (ins CPURegs:$rs, uimm16:$pos, uimm16:$sz, CPURegs:$src), + (ins CPURegs:$rs, uimm16:$pos, size_ins:$sz, CPURegs:$src), [(set CPURegs:$rt, (MipsIns CPURegs:$rs, immZExt5:$pos, immZExt5:$sz, CPURegs:$src))], NoItinerary>; //===----------------------------------------------------------------------===// // Arbitrary patterns that map to one or more instructions //===----------------------------------------------------------------------===// // Small immediates def : Pat<(i32 immSExt16:$in), (ADDiu ZERO, imm:$in)>; def : Pat<(i32 immZExt16:$in), (ORi ZERO, imm:$in)>; // Arbitrary immediates def : Pat<(i32 imm:$imm), (ORi (LUi (HI16 imm:$imm)), (LO16 imm:$imm))>; // Carry patterns def : Pat<(subc CPURegs:$lhs, CPURegs:$rhs), (SUBu CPURegs:$lhs, CPURegs:$rhs)>; def : Pat<(addc CPURegs:$lhs, CPURegs:$rhs), (ADDu CPURegs:$lhs, CPURegs:$rhs)>; def : Pat<(addc CPURegs:$src, immSExt16:$imm), (ADDiu CPURegs:$src, imm:$imm)>; // Call def : Pat<(MipsJmpLink (i32 tglobaladdr:$dst)), (JAL tglobaladdr:$dst)>; def : Pat<(MipsJmpLink (i32 texternalsym:$dst)), (JAL texternalsym:$dst)>; //def : Pat<(MipsJmpLink CPURegs:$dst), // (JALR CPURegs:$dst)>; // hi/lo relocs def : Pat<(MipsHi tglobaladdr:$in), (LUi tglobaladdr:$in)>; def : Pat<(MipsHi tblockaddress:$in), (LUi tblockaddress:$in)>; def : Pat<(MipsLo tglobaladdr:$in), (ADDiu ZERO, tglobaladdr:$in)>; def : Pat<(MipsLo tblockaddress:$in), (ADDiu ZERO, tblockaddress:$in)>; def : Pat<(add CPURegs:$hi, (MipsLo tglobaladdr:$lo)), (ADDiu CPURegs:$hi, tglobaladdr:$lo)>; def : Pat<(add CPURegs:$hi, (MipsLo tblockaddress:$lo)), (ADDiu CPURegs:$hi, tblockaddress:$lo)>; def : Pat<(MipsHi tjumptable:$in), (LUi tjumptable:$in)>; def : Pat<(MipsLo tjumptable:$in), (ADDiu ZERO, tjumptable:$in)>; def : Pat<(add CPURegs:$hi, (MipsLo tjumptable:$lo)), (ADDiu CPURegs:$hi, tjumptable:$lo)>; def : Pat<(MipsHi tconstpool:$in), (LUi tconstpool:$in)>; def : Pat<(MipsLo tconstpool:$in), (ADDiu ZERO, tconstpool:$in)>; def : Pat<(add CPURegs:$hi, (MipsLo tconstpool:$lo)), (ADDiu CPURegs:$hi, tconstpool:$lo)>; // gp_rel relocs def : Pat<(add CPURegs:$gp, (MipsGPRel tglobaladdr:$in)), (ADDiu CPURegs:$gp, tglobaladdr:$in)>; def : Pat<(add CPURegs:$gp, (MipsGPRel tconstpool:$in)), (ADDiu CPURegs:$gp, tconstpool:$in)>; // tlsgd def : Pat<(add CPURegs:$gp, (MipsTlsGd tglobaltlsaddr:$in)), (ADDiu CPURegs:$gp, tglobaltlsaddr:$in)>; // tprel hi/lo def : Pat<(MipsTprelHi tglobaltlsaddr:$in), (LUi tglobaltlsaddr:$in)>; def : Pat<(MipsTprelLo tglobaltlsaddr:$in), (ADDiu ZERO, tglobaltlsaddr:$in)>; def : Pat<(add CPURegs:$hi, (MipsTprelLo tglobaltlsaddr:$lo)), (ADDiu CPURegs:$hi, tglobaltlsaddr:$lo)>; // wrapper_pic class WrapperPICPat: Pat<(MipsWrapperPIC node:$in), (ADDiu GP, node:$in)>; def : WrapperPICPat; def : WrapperPICPat; def : WrapperPICPat; def : WrapperPICPat; def : WrapperPICPat; // Mips does not have "not", so we expand our way def : Pat<(not CPURegs:$in), (NOR CPURegs:$in, ZERO)>; // extended load and stores def : Pat<(extloadi1 addr:$src), (LBu addr:$src)>; def : Pat<(extloadi8 addr:$src), (LBu addr:$src)>; def : Pat<(extloadi16_a addr:$src), (LHu addr:$src)>; def : Pat<(extloadi16_u addr:$src), (ULHu addr:$src)>; // peepholes def : Pat<(store (i32 0), addr:$dst), (SW ZERO, addr:$dst)>; // brcond patterns multiclass BrcondPats { def : Pat<(brcond (i32 (setne RC:$lhs, 0)), bb:$dst), (BNEOp RC:$lhs, ZEROReg, bb:$dst)>; def : Pat<(brcond (i32 (seteq RC:$lhs, 0)), bb:$dst), (BEQOp RC:$lhs, ZEROReg, bb:$dst)>; def : Pat<(brcond (i32 (setge RC:$lhs, RC:$rhs)), bb:$dst), (BEQ (SLTOp RC:$lhs, RC:$rhs), ZERO, bb:$dst)>; def : Pat<(brcond (i32 (setuge RC:$lhs, RC:$rhs)), bb:$dst), (BEQ (SLTuOp RC:$lhs, RC:$rhs), ZERO, bb:$dst)>; def : Pat<(brcond (i32 (setge RC:$lhs, immSExt16:$rhs)), bb:$dst), (BEQ (SLTiOp RC:$lhs, immSExt16:$rhs), ZERO, bb:$dst)>; def : Pat<(brcond (i32 (setuge RC:$lhs, immSExt16:$rhs)), bb:$dst), (BEQ (SLTiuOp RC:$lhs, immSExt16:$rhs), ZERO, bb:$dst)>; def : Pat<(brcond (i32 (setle RC:$lhs, RC:$rhs)), bb:$dst), (BEQ (SLTOp RC:$rhs, RC:$lhs), ZERO, bb:$dst)>; def : Pat<(brcond (i32 (setule RC:$lhs, RC:$rhs)), bb:$dst), (BEQ (SLTuOp RC:$rhs, RC:$lhs), ZERO, bb:$dst)>; def : Pat<(brcond RC:$cond, bb:$dst), (BNEOp RC:$cond, ZEROReg, bb:$dst)>; } defm : BrcondPats; // select patterns multiclass MovzPats { def : Pat<(select (i32 (setge CPURegs:$lhs, CPURegs:$rhs)), RC:$T, RC:$F), (MOVZInst RC:$T, (SLT CPURegs:$lhs, CPURegs:$rhs), RC:$F)>; def : Pat<(select (i32 (setuge CPURegs:$lhs, CPURegs:$rhs)), RC:$T, RC:$F), (MOVZInst RC:$T, (SLTu CPURegs:$lhs, CPURegs:$rhs), RC:$F)>; def : Pat<(select (i32 (setge CPURegs:$lhs, immSExt16:$rhs)), RC:$T, RC:$F), (MOVZInst RC:$T, (SLTi CPURegs:$lhs, immSExt16:$rhs), RC:$F)>; def : Pat<(select (i32 (setuge CPURegs:$lh, immSExt16:$rh)), RC:$T, RC:$F), (MOVZInst RC:$T, (SLTiu CPURegs:$lh, immSExt16:$rh), RC:$F)>; def : Pat<(select (i32 (setle CPURegs:$lhs, CPURegs:$rhs)), RC:$T, RC:$F), (MOVZInst RC:$T, (SLT CPURegs:$rhs, CPURegs:$lhs), RC:$F)>; def : Pat<(select (i32 (setule CPURegs:$lhs, CPURegs:$rhs)), RC:$T, RC:$F), (MOVZInst RC:$T, (SLTu CPURegs:$rhs, CPURegs:$lhs), RC:$F)>; def : Pat<(select (i32 (seteq CPURegs:$lhs, CPURegs:$rhs)), RC:$T, RC:$F), (MOVZInst RC:$T, (XOR CPURegs:$lhs, CPURegs:$rhs), RC:$F)>; def : Pat<(select (i32 (seteq CPURegs:$lhs, 0)), RC:$T, RC:$F), (MOVZInst RC:$T, CPURegs:$lhs, RC:$F)>; } multiclass MovnPats { def : Pat<(select (i32 (setne CPURegs:$lhs, CPURegs:$rhs)), RC:$T, RC:$F), (MOVNInst RC:$T, (XOR CPURegs:$lhs, CPURegs:$rhs), RC:$F)>; def : Pat<(select CPURegs:$cond, RC:$T, RC:$F), (MOVNInst RC:$T, CPURegs:$cond, RC:$F)>; def : Pat<(select (i32 (setne CPURegs:$lhs, 0)), RC:$T, RC:$F), (MOVNInst RC:$T, CPURegs:$lhs, RC:$F)>; } defm : MovzPats; defm : MovnPats; // setcc patterns multiclass SeteqPats { def : Pat<(seteq RC:$lhs, RC:$rhs), (SLTiuOp (XOROp RC:$lhs, RC:$rhs), 1)>; def : Pat<(setne RC:$lhs, RC:$rhs), (SLTuOp ZEROReg, (XOROp RC:$lhs, RC:$rhs))>; } multiclass SetlePats { def : Pat<(setle RC:$lhs, RC:$rhs), (XORi (SLTOp RC:$rhs, RC:$lhs), 1)>; def : Pat<(setule RC:$lhs, RC:$rhs), (XORi (SLTuOp RC:$rhs, RC:$lhs), 1)>; } multiclass SetgtPats { def : Pat<(setgt RC:$lhs, RC:$rhs), (SLTOp RC:$rhs, RC:$lhs)>; def : Pat<(setugt RC:$lhs, RC:$rhs), (SLTuOp RC:$rhs, RC:$lhs)>; } multiclass SetgePats { def : Pat<(setge RC:$lhs, RC:$rhs), (XORi (SLTOp RC:$lhs, RC:$rhs), 1)>; def : Pat<(setuge RC:$lhs, RC:$rhs), (XORi (SLTuOp RC:$lhs, RC:$rhs), 1)>; } multiclass SetgeImmPats { def : Pat<(setge RC:$lhs, immSExt16:$rhs), (XORi (SLTiOp RC:$lhs, immSExt16:$rhs), 1)>; def : Pat<(setuge RC:$lhs, immSExt16:$rhs), (XORi (SLTiuOp RC:$lhs, immSExt16:$rhs), 1)>; } defm : SeteqPats; defm : SetlePats; defm : SetgtPats; defm : SetgePats; defm : SetgeImmPats; // select MipsDynAlloc def : Pat<(MipsDynAlloc addr:$f), (DynAlloc addr:$f)>; //===----------------------------------------------------------------------===// // Floating Point Support //===----------------------------------------------------------------------===// include "MipsInstrFPU.td" include "Mips64InstrInfo.td" Index: head/contrib/llvm/lib/Target/Mips/MipsJITInfo.cpp =================================================================== --- head/contrib/llvm/lib/Target/Mips/MipsJITInfo.cpp (revision 228378) +++ head/contrib/llvm/lib/Target/Mips/MipsJITInfo.cpp (revision 228379) @@ -1,230 +1,230 @@ //===- MipsJITInfo.cpp - Implement the JIT interfaces for the Mips target -===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the JIT interfaces for the Mips target. // //===----------------------------------------------------------------------===// #define DEBUG_TYPE "jit" #include "MipsJITInfo.h" #include "MipsInstrInfo.h" #include "MipsRelocations.h" #include "MipsSubtarget.h" #include "llvm/Function.h" #include "llvm/CodeGen/JITCodeEmitter.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Memory.h" #include using namespace llvm; void MipsJITInfo::replaceMachineCodeForFunction(void *Old, void *New) { report_fatal_error("MipsJITInfo::replaceMachineCodeForFunction"); } /// JITCompilerFunction - This contains the address of the JIT function used to /// compile a function lazily. static TargetJITInfo::JITCompilerFn JITCompilerFunction; // Get the ASMPREFIX for the current host. This is often '_'. #ifndef __USER_LABEL_PREFIX__ #define __USER_LABEL_PREFIX__ #endif #define GETASMPREFIX2(X) #X #define GETASMPREFIX(X) GETASMPREFIX2(X) #define ASMPREFIX GETASMPREFIX(__USER_LABEL_PREFIX__) // CompilationCallback stub - We can't use a C function with inline assembly in // it, because the prolog/epilog inserted by GCC won't work for us. Instead, // write our own wrapper, which does things our way, so we have complete control // over register saving and restoring. This code saves registers, calls // MipsCompilationCallbackC and restores registers. extern "C" { #if defined (__mips__) void MipsCompilationCallback(); asm( ".text\n" ".align 2\n" ".globl " ASMPREFIX "MipsCompilationCallback\n" ASMPREFIX "MipsCompilationCallback:\n" ".ent " ASMPREFIX "MipsCompilationCallback\n" - ".frame $29, 32, $31\n" + ".frame $sp, 32, $ra\n" ".set noreorder\n" ".cpload $t9\n" - "addiu $sp, $sp, -60\n" + "addiu $sp, $sp, -64\n" ".cprestore 16\n" // Save argument registers a0, a1, a2, a3, f12, f14 since they may contain // stuff for the real target function right now. We have to act as if this // whole compilation callback doesn't exist as far as the caller is // concerned. We also need to save the ra register since it contains the // original return address, and t8 register since it contains the address // of the end of function stub. "sw $a0, 20($sp)\n" "sw $a1, 24($sp)\n" "sw $a2, 28($sp)\n" "sw $a3, 32($sp)\n" "sw $ra, 36($sp)\n" "sw $t8, 40($sp)\n" - "sdc1 $f12, 44($sp)\n" - "sdc1 $f14, 52($sp)\n" + "sdc1 $f12, 48($sp)\n" + "sdc1 $f14, 56($sp)\n" // t8 points at the end of function stub. Pass the beginning of the stub // to the MipsCompilationCallbackC. "addiu $a0, $t8, -16\n" "jal " ASMPREFIX "MipsCompilationCallbackC\n" "nop\n" // Restore registers. "lw $a0, 20($sp)\n" "lw $a1, 24($sp)\n" "lw $a2, 28($sp)\n" "lw $a3, 32($sp)\n" "lw $ra, 36($sp)\n" "lw $t8, 40($sp)\n" - "ldc1 $f12, 44($sp)\n" - "ldc1 $f14, 52($sp)\n" - "addiu $sp, $sp, 60\n" + "ldc1 $f12, 48($sp)\n" + "ldc1 $f14, 56($sp)\n" + "addiu $sp, $sp, 64\n" // Jump to the (newly modified) stub to invoke the real function. "addiu $t8, $t8, -16\n" "jr $t8\n" "nop\n" ".set reorder\n" ".end " ASMPREFIX "MipsCompilationCallback\n" ); #else // host != Mips void MipsCompilationCallback() { llvm_unreachable( "Cannot call MipsCompilationCallback() on a non-Mips arch!"); } #endif } /// MipsCompilationCallbackC - This is the target-specific function invoked /// by the function stub when we did not know the real target of a call. /// This function must locate the start of the stub or call site and pass /// it into the JIT compiler function. extern "C" void MipsCompilationCallbackC(intptr_t StubAddr) { // Get the address of the compiled code for this function. intptr_t NewVal = (intptr_t) JITCompilerFunction((void*) StubAddr); // Rewrite the function stub so that we don't end up here every time we // execute the call. We're replacing the first four instructions of the // stub with code that jumps to the compiled function: // lui $t9, %hi(NewVal) // addiu $t9, $t9, %lo(NewVal) // jr $t9 // nop int Hi = ((unsigned)NewVal & 0xffff0000) >> 16; if ((NewVal & 0x8000) != 0) Hi++; int Lo = (int)(NewVal & 0xffff); *(intptr_t *)(StubAddr) = 0xf << 26 | 25 << 16 | Hi; *(intptr_t *)(StubAddr + 4) = 9 << 26 | 25 << 21 | 25 << 16 | Lo; *(intptr_t *)(StubAddr + 8) = 25 << 21 | 8; *(intptr_t *)(StubAddr + 12) = 0; sys::Memory::InvalidateInstructionCache((void*) StubAddr, 16); } TargetJITInfo::LazyResolverFn MipsJITInfo::getLazyResolverFunction( JITCompilerFn F) { JITCompilerFunction = F; return MipsCompilationCallback; } TargetJITInfo::StubLayout MipsJITInfo::getStubLayout() { // The stub contains 4 4-byte instructions, aligned at 4 bytes. See // emitFunctionStub for details. StubLayout Result = { 4*4, 4 }; return Result; } void *MipsJITInfo::emitFunctionStub(const Function* F, void *Fn, JITCodeEmitter &JCE) { JCE.emitAlignment(4); void *Addr = (void*) (JCE.getCurrentPCValue()); if (!sys::Memory::setRangeWritable(Addr, 16)) llvm_unreachable("ERROR: Unable to mark stub writable."); intptr_t EmittedAddr; if (Fn != (void*)(intptr_t)MipsCompilationCallback) EmittedAddr = (intptr_t)Fn; else EmittedAddr = (intptr_t)MipsCompilationCallback; int Hi = ((unsigned)EmittedAddr & 0xffff0000) >> 16; if ((EmittedAddr & 0x8000) != 0) Hi++; int Lo = (int)(EmittedAddr & 0xffff); // lui t9, %hi(EmittedAddr) // addiu t9, t9, %lo(EmittedAddr) // jalr t8, t9 // nop JCE.emitWordLE(0xf << 26 | 25 << 16 | Hi); JCE.emitWordLE(9 << 26 | 25 << 21 | 25 << 16 | Lo); JCE.emitWordLE(25 << 21 | 24 << 11 | 9); JCE.emitWordLE(0); sys::Memory::InvalidateInstructionCache(Addr, 16); if (!sys::Memory::setRangeExecutable(Addr, 16)) llvm_unreachable("ERROR: Unable to mark stub executable."); return Addr; } /// relocate - Before the JIT can run a block of code that has been emitted, /// it must rewrite the code to contain the actual addresses of any /// referenced global symbols. void MipsJITInfo::relocate(void *Function, MachineRelocation *MR, unsigned NumRelocs, unsigned char* GOTBase) { for (unsigned i = 0; i != NumRelocs; ++i, ++MR) { void *RelocPos = (char*) Function + MR->getMachineCodeOffset(); intptr_t ResultPtr = (intptr_t) MR->getResultPointer(); switch ((Mips::RelocationType) MR->getRelocationType()) { case Mips::reloc_mips_branch: ResultPtr = (((ResultPtr - (intptr_t) RelocPos) - 4) >> 2) & 0xffff; *((unsigned*) RelocPos) |= (unsigned) ResultPtr; break; case Mips::reloc_mips_26: ResultPtr = (ResultPtr & 0x0fffffff) >> 2; *((unsigned*) RelocPos) |= (unsigned) ResultPtr; break; case Mips::reloc_mips_hi: ResultPtr = ResultPtr >> 16; if ((((intptr_t) (MR->getResultPointer()) & 0xffff) >> 15) == 1) { ResultPtr += 1; } *((unsigned*) RelocPos) |= (unsigned) ResultPtr; break; case Mips::reloc_mips_lo: ResultPtr = ResultPtr & 0xffff; *((unsigned*) RelocPos) |= (unsigned) ResultPtr; break; default: llvm_unreachable("ERROR: Unknown Mips relocation."); } } } Index: head/contrib/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp =================================================================== --- head/contrib/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp (revision 228378) +++ head/contrib/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp (revision 228379) @@ -1,971 +1,969 @@ //=====- PPCFrameLowering.cpp - PPC Frame Information -----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file contains the PPC implementation of TargetFrameLowering class. // //===----------------------------------------------------------------------===// #include "PPCFrameLowering.h" #include "PPCInstrInfo.h" #include "PPCMachineFunctionInfo.h" #include "llvm/Function.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/RegisterScavenging.h" #include "llvm/Target/TargetOptions.h" using namespace llvm; // FIXME This disables some code that aligns the stack to a boundary bigger than // the default (16 bytes on Darwin) when there is a stack local of greater // alignment. This does not currently work, because the delta between old and // new stack pointers is added to offsets that reference incoming parameters // after the prolog is generated, and the code that does that doesn't handle a // variable delta. You don't want to do that anyway; a better approach is to // reserve another register that retains to the incoming stack pointer, and // reference parameters relative to that. #define ALIGN_STACK 0 /// VRRegNo - Map from a numbered VR register to its enum value. /// static const unsigned short VRRegNo[] = { PPC::V0 , PPC::V1 , PPC::V2 , PPC::V3 , PPC::V4 , PPC::V5 , PPC::V6 , PPC::V7 , PPC::V8 , PPC::V9 , PPC::V10, PPC::V11, PPC::V12, PPC::V13, PPC::V14, PPC::V15, PPC::V16, PPC::V17, PPC::V18, PPC::V19, PPC::V20, PPC::V21, PPC::V22, PPC::V23, PPC::V24, PPC::V25, PPC::V26, PPC::V27, PPC::V28, PPC::V29, PPC::V30, PPC::V31 }; /// RemoveVRSaveCode - We have found that this function does not need any code /// to manipulate the VRSAVE register, even though it uses vector registers. /// This can happen when the only registers used are known to be live in or out /// of the function. Remove all of the VRSAVE related code from the function. static void RemoveVRSaveCode(MachineInstr *MI) { MachineBasicBlock *Entry = MI->getParent(); MachineFunction *MF = Entry->getParent(); // We know that the MTVRSAVE instruction immediately follows MI. Remove it. MachineBasicBlock::iterator MBBI = MI; ++MBBI; assert(MBBI != Entry->end() && MBBI->getOpcode() == PPC::MTVRSAVE); MBBI->eraseFromParent(); bool RemovedAllMTVRSAVEs = true; // See if we can find and remove the MTVRSAVE instruction from all of the // epilog blocks. for (MachineFunction::iterator I = MF->begin(), E = MF->end(); I != E; ++I) { // If last instruction is a return instruction, add an epilogue if (!I->empty() && I->back().getDesc().isReturn()) { bool FoundIt = false; for (MBBI = I->end(); MBBI != I->begin(); ) { --MBBI; if (MBBI->getOpcode() == PPC::MTVRSAVE) { MBBI->eraseFromParent(); // remove it. FoundIt = true; break; } } RemovedAllMTVRSAVEs &= FoundIt; } } // If we found and removed all MTVRSAVE instructions, remove the read of // VRSAVE as well. if (RemovedAllMTVRSAVEs) { MBBI = MI; assert(MBBI != Entry->begin() && "UPDATE_VRSAVE is first instr in block?"); --MBBI; assert(MBBI->getOpcode() == PPC::MFVRSAVE && "VRSAVE instrs wandered?"); MBBI->eraseFromParent(); } // Finally, nuke the UPDATE_VRSAVE. MI->eraseFromParent(); } // HandleVRSaveUpdate - MI is the UPDATE_VRSAVE instruction introduced by the // instruction selector. Based on the vector registers that have been used, // transform this into the appropriate ORI instruction. static void HandleVRSaveUpdate(MachineInstr *MI, const TargetInstrInfo &TII) { MachineFunction *MF = MI->getParent()->getParent(); DebugLoc dl = MI->getDebugLoc(); unsigned UsedRegMask = 0; for (unsigned i = 0; i != 32; ++i) if (MF->getRegInfo().isPhysRegUsed(VRRegNo[i])) UsedRegMask |= 1 << (31-i); // Live in and live out values already must be in the mask, so don't bother // marking them. for (MachineRegisterInfo::livein_iterator I = MF->getRegInfo().livein_begin(), E = MF->getRegInfo().livein_end(); I != E; ++I) { unsigned RegNo = getPPCRegisterNumbering(I->first); if (VRRegNo[RegNo] == I->first) // If this really is a vector reg. UsedRegMask &= ~(1 << (31-RegNo)); // Doesn't need to be marked. } for (MachineRegisterInfo::liveout_iterator I = MF->getRegInfo().liveout_begin(), E = MF->getRegInfo().liveout_end(); I != E; ++I) { unsigned RegNo = getPPCRegisterNumbering(*I); if (VRRegNo[RegNo] == *I) // If this really is a vector reg. UsedRegMask &= ~(1 << (31-RegNo)); // Doesn't need to be marked. } // If no registers are used, turn this into a copy. if (UsedRegMask == 0) { // Remove all VRSAVE code. RemoveVRSaveCode(MI); return; } unsigned SrcReg = MI->getOperand(1).getReg(); unsigned DstReg = MI->getOperand(0).getReg(); if ((UsedRegMask & 0xFFFF) == UsedRegMask) { if (DstReg != SrcReg) BuildMI(*MI->getParent(), MI, dl, TII.get(PPC::ORI), DstReg) .addReg(SrcReg) .addImm(UsedRegMask); else BuildMI(*MI->getParent(), MI, dl, TII.get(PPC::ORI), DstReg) .addReg(SrcReg, RegState::Kill) .addImm(UsedRegMask); } else if ((UsedRegMask & 0xFFFF0000) == UsedRegMask) { if (DstReg != SrcReg) BuildMI(*MI->getParent(), MI, dl, TII.get(PPC::ORIS), DstReg) .addReg(SrcReg) .addImm(UsedRegMask >> 16); else BuildMI(*MI->getParent(), MI, dl, TII.get(PPC::ORIS), DstReg) .addReg(SrcReg, RegState::Kill) .addImm(UsedRegMask >> 16); } else { if (DstReg != SrcReg) BuildMI(*MI->getParent(), MI, dl, TII.get(PPC::ORIS), DstReg) .addReg(SrcReg) .addImm(UsedRegMask >> 16); else BuildMI(*MI->getParent(), MI, dl, TII.get(PPC::ORIS), DstReg) .addReg(SrcReg, RegState::Kill) .addImm(UsedRegMask >> 16); BuildMI(*MI->getParent(), MI, dl, TII.get(PPC::ORI), DstReg) .addReg(DstReg, RegState::Kill) .addImm(UsedRegMask & 0xFFFF); } // Remove the old UPDATE_VRSAVE instruction. MI->eraseFromParent(); } /// determineFrameLayout - Determine the size of the frame and maximum call /// frame size. void PPCFrameLowering::determineFrameLayout(MachineFunction &MF) const { MachineFrameInfo *MFI = MF.getFrameInfo(); // Get the number of bytes to allocate from the FrameInfo unsigned FrameSize = MFI->getStackSize(); // Get the alignments provided by the target, and the maximum alignment // (if any) of the fixed frame objects. unsigned MaxAlign = MFI->getMaxAlignment(); unsigned TargetAlign = getStackAlignment(); unsigned AlignMask = TargetAlign - 1; // // If we are a leaf function, and use up to 224 bytes of stack space, // don't have a frame pointer, calls, or dynamic alloca then we do not need // to adjust the stack pointer (we fit in the Red Zone). bool DisableRedZone = MF.getFunction()->hasFnAttr(Attribute::NoRedZone); // FIXME SVR4 The 32-bit SVR4 ABI has no red zone. if (!DisableRedZone && FrameSize <= 224 && // Fits in red zone. !MFI->hasVarSizedObjects() && // No dynamic alloca. !MFI->adjustsStack() && // No calls. (!ALIGN_STACK || MaxAlign <= TargetAlign)) { // No special alignment. // No need for frame MFI->setStackSize(0); return; } // Get the maximum call frame size of all the calls. unsigned maxCallFrameSize = MFI->getMaxCallFrameSize(); // Maximum call frame needs to be at least big enough for linkage and 8 args. unsigned minCallFrameSize = getMinCallFrameSize(Subtarget.isPPC64(), Subtarget.isDarwinABI()); maxCallFrameSize = std::max(maxCallFrameSize, minCallFrameSize); // If we have dynamic alloca then maxCallFrameSize needs to be aligned so // that allocations will be aligned. if (MFI->hasVarSizedObjects()) maxCallFrameSize = (maxCallFrameSize + AlignMask) & ~AlignMask; // Update maximum call frame size. MFI->setMaxCallFrameSize(maxCallFrameSize); // Include call frame size in total. FrameSize += maxCallFrameSize; // Make sure the frame is aligned. FrameSize = (FrameSize + AlignMask) & ~AlignMask; // Update frame info. MFI->setStackSize(FrameSize); } // hasFP - Return true if the specified function actually has a dedicated frame // pointer register. bool PPCFrameLowering::hasFP(const MachineFunction &MF) const { const MachineFrameInfo *MFI = MF.getFrameInfo(); // FIXME: This is pretty much broken by design: hasFP() might be called really // early, before the stack layout was calculated and thus hasFP() might return // true or false here depending on the time of call. return (MFI->getStackSize()) && needsFP(MF); } // needsFP - Return true if the specified function should have a dedicated frame // pointer register. This is true if the function has variable sized allocas or // if frame pointer elimination is disabled. bool PPCFrameLowering::needsFP(const MachineFunction &MF) const { const MachineFrameInfo *MFI = MF.getFrameInfo(); // Naked functions have no stack frame pushed, so we don't have a frame // pointer. if (MF.getFunction()->hasFnAttr(Attribute::Naked)) return false; return DisableFramePointerElim(MF) || MFI->hasVarSizedObjects() || (GuaranteedTailCallOpt && MF.getInfo()->hasFastCall()); } void PPCFrameLowering::emitPrologue(MachineFunction &MF) const { MachineBasicBlock &MBB = MF.front(); // Prolog goes in entry BB MachineBasicBlock::iterator MBBI = MBB.begin(); MachineFrameInfo *MFI = MF.getFrameInfo(); const PPCInstrInfo &TII = *static_cast(MF.getTarget().getInstrInfo()); MachineModuleInfo &MMI = MF.getMMI(); DebugLoc dl; bool needsFrameMoves = MMI.hasDebugInfo() || MF.getFunction()->needsUnwindTableEntry(); // Prepare for frame info. MCSymbol *FrameLabel = 0; // Scan the prolog, looking for an UPDATE_VRSAVE instruction. If we find it, // process it. for (unsigned i = 0; MBBI != MBB.end(); ++i, ++MBBI) { if (MBBI->getOpcode() == PPC::UPDATE_VRSAVE) { HandleVRSaveUpdate(MBBI, TII); break; } } // Move MBBI back to the beginning of the function. MBBI = MBB.begin(); // Work out frame sizes. // FIXME: determineFrameLayout() may change the frame size. This should be // moved upper, to some hook. determineFrameLayout(MF); unsigned FrameSize = MFI->getStackSize(); int NegFrameSize = -FrameSize; // Get processor type. bool isPPC64 = Subtarget.isPPC64(); // Get operating system bool isDarwinABI = Subtarget.isDarwinABI(); // Check if the link register (LR) must be saved. PPCFunctionInfo *FI = MF.getInfo(); bool MustSaveLR = FI->mustSaveLR(); // Do we have a frame pointer for this function? bool HasFP = hasFP(MF); int LROffset = PPCFrameLowering::getReturnSaveOffset(isPPC64, isDarwinABI); int FPOffset = 0; if (HasFP) { if (Subtarget.isSVR4ABI()) { MachineFrameInfo *FFI = MF.getFrameInfo(); int FPIndex = FI->getFramePointerSaveIndex(); assert(FPIndex && "No Frame Pointer Save Slot!"); FPOffset = FFI->getObjectOffset(FPIndex); } else { FPOffset = PPCFrameLowering::getFramePointerSaveOffset(isPPC64, isDarwinABI); } } if (isPPC64) { if (MustSaveLR) BuildMI(MBB, MBBI, dl, TII.get(PPC::MFLR8), PPC::X0); if (HasFP) BuildMI(MBB, MBBI, dl, TII.get(PPC::STD)) .addReg(PPC::X31) .addImm(FPOffset/4) .addReg(PPC::X1); if (MustSaveLR) BuildMI(MBB, MBBI, dl, TII.get(PPC::STD)) .addReg(PPC::X0) .addImm(LROffset / 4) .addReg(PPC::X1); } else { if (MustSaveLR) BuildMI(MBB, MBBI, dl, TII.get(PPC::MFLR), PPC::R0); if (HasFP) BuildMI(MBB, MBBI, dl, TII.get(PPC::STW)) .addReg(PPC::R31) .addImm(FPOffset) .addReg(PPC::R1); if (MustSaveLR) BuildMI(MBB, MBBI, dl, TII.get(PPC::STW)) .addReg(PPC::R0) .addImm(LROffset) .addReg(PPC::R1); } // Skip if a leaf routine. if (!FrameSize) return; // Get stack alignments. unsigned TargetAlign = getStackAlignment(); unsigned MaxAlign = MFI->getMaxAlignment(); // Adjust stack pointer: r1 += NegFrameSize. // If there is a preferred stack alignment, align R1 now if (!isPPC64) { // PPC32. if (ALIGN_STACK && MaxAlign > TargetAlign) { assert(isPowerOf2_32(MaxAlign) && isInt<16>(MaxAlign) && "Invalid alignment!"); assert(isInt<16>(NegFrameSize) && "Unhandled stack size and alignment!"); BuildMI(MBB, MBBI, dl, TII.get(PPC::RLWINM), PPC::R0) .addReg(PPC::R1) .addImm(0) .addImm(32 - Log2_32(MaxAlign)) .addImm(31); BuildMI(MBB, MBBI, dl, TII.get(PPC::SUBFIC) ,PPC::R0) .addReg(PPC::R0, RegState::Kill) .addImm(NegFrameSize); BuildMI(MBB, MBBI, dl, TII.get(PPC::STWUX)) .addReg(PPC::R1) .addReg(PPC::R1) .addReg(PPC::R0); } else if (isInt<16>(NegFrameSize)) { BuildMI(MBB, MBBI, dl, TII.get(PPC::STWU), PPC::R1) .addReg(PPC::R1) .addImm(NegFrameSize) .addReg(PPC::R1); } else { BuildMI(MBB, MBBI, dl, TII.get(PPC::LIS), PPC::R0) .addImm(NegFrameSize >> 16); BuildMI(MBB, MBBI, dl, TII.get(PPC::ORI), PPC::R0) .addReg(PPC::R0, RegState::Kill) .addImm(NegFrameSize & 0xFFFF); BuildMI(MBB, MBBI, dl, TII.get(PPC::STWUX)) .addReg(PPC::R1) .addReg(PPC::R1) .addReg(PPC::R0); } } else { // PPC64. if (ALIGN_STACK && MaxAlign > TargetAlign) { assert(isPowerOf2_32(MaxAlign) && isInt<16>(MaxAlign) && "Invalid alignment!"); assert(isInt<16>(NegFrameSize) && "Unhandled stack size and alignment!"); BuildMI(MBB, MBBI, dl, TII.get(PPC::RLDICL), PPC::X0) .addReg(PPC::X1) .addImm(0) .addImm(64 - Log2_32(MaxAlign)); BuildMI(MBB, MBBI, dl, TII.get(PPC::SUBFIC8), PPC::X0) .addReg(PPC::X0) .addImm(NegFrameSize); BuildMI(MBB, MBBI, dl, TII.get(PPC::STDUX)) .addReg(PPC::X1) .addReg(PPC::X1) .addReg(PPC::X0); } else if (isInt<16>(NegFrameSize)) { BuildMI(MBB, MBBI, dl, TII.get(PPC::STDU), PPC::X1) .addReg(PPC::X1) .addImm(NegFrameSize / 4) .addReg(PPC::X1); } else { BuildMI(MBB, MBBI, dl, TII.get(PPC::LIS8), PPC::X0) .addImm(NegFrameSize >> 16); BuildMI(MBB, MBBI, dl, TII.get(PPC::ORI8), PPC::X0) .addReg(PPC::X0, RegState::Kill) .addImm(NegFrameSize & 0xFFFF); BuildMI(MBB, MBBI, dl, TII.get(PPC::STDUX)) .addReg(PPC::X1) .addReg(PPC::X1) .addReg(PPC::X0); } } std::vector &Moves = MMI.getFrameMoves(); // Add the "machine moves" for the instructions we generated above, but in // reverse order. if (needsFrameMoves) { // Mark effective beginning of when frame pointer becomes valid. FrameLabel = MMI.getContext().CreateTempSymbol(); BuildMI(MBB, MBBI, dl, TII.get(PPC::PROLOG_LABEL)).addSym(FrameLabel); // Show update of SP. if (NegFrameSize) { MachineLocation SPDst(MachineLocation::VirtualFP); MachineLocation SPSrc(MachineLocation::VirtualFP, NegFrameSize); Moves.push_back(MachineMove(FrameLabel, SPDst, SPSrc)); } else { MachineLocation SP(isPPC64 ? PPC::X31 : PPC::R31); Moves.push_back(MachineMove(FrameLabel, SP, SP)); } if (HasFP) { MachineLocation FPDst(MachineLocation::VirtualFP, FPOffset); MachineLocation FPSrc(isPPC64 ? PPC::X31 : PPC::R31); Moves.push_back(MachineMove(FrameLabel, FPDst, FPSrc)); } if (MustSaveLR) { MachineLocation LRDst(MachineLocation::VirtualFP, LROffset); MachineLocation LRSrc(isPPC64 ? PPC::LR8 : PPC::LR); Moves.push_back(MachineMove(FrameLabel, LRDst, LRSrc)); } } MCSymbol *ReadyLabel = 0; // If there is a frame pointer, copy R1 into R31 if (HasFP) { if (!isPPC64) { BuildMI(MBB, MBBI, dl, TII.get(PPC::OR), PPC::R31) .addReg(PPC::R1) .addReg(PPC::R1); } else { BuildMI(MBB, MBBI, dl, TII.get(PPC::OR8), PPC::X31) .addReg(PPC::X1) .addReg(PPC::X1); } if (needsFrameMoves) { ReadyLabel = MMI.getContext().CreateTempSymbol(); // Mark effective beginning of when frame pointer is ready. BuildMI(MBB, MBBI, dl, TII.get(PPC::PROLOG_LABEL)).addSym(ReadyLabel); MachineLocation FPDst(HasFP ? (isPPC64 ? PPC::X31 : PPC::R31) : (isPPC64 ? PPC::X1 : PPC::R1)); MachineLocation FPSrc(MachineLocation::VirtualFP); Moves.push_back(MachineMove(ReadyLabel, FPDst, FPSrc)); } } if (needsFrameMoves) { MCSymbol *Label = HasFP ? ReadyLabel : FrameLabel; // Add callee saved registers to move list. const std::vector &CSI = MFI->getCalleeSavedInfo(); for (unsigned I = 0, E = CSI.size(); I != E; ++I) { int Offset = MFI->getObjectOffset(CSI[I].getFrameIdx()); unsigned Reg = CSI[I].getReg(); if (Reg == PPC::LR || Reg == PPC::LR8 || Reg == PPC::RM) continue; // This is a bit of a hack: CR2LT, CR2GT, CR2EQ and CR2UN are just // subregisters of CR2. We just need to emit a move of CR2. - if (Reg == PPC::CR2LT || Reg == PPC::CR2GT || Reg == PPC::CR2EQ) + if (PPC::CRBITRCRegisterClass->contains(Reg)) continue; - if (Reg == PPC::CR2UN) - Reg = PPC::CR2; MachineLocation CSDst(MachineLocation::VirtualFP, Offset); MachineLocation CSSrc(Reg); Moves.push_back(MachineMove(Label, CSDst, CSSrc)); } } } void PPCFrameLowering::emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const { MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); assert(MBBI != MBB.end() && "Returning block has no terminator"); const PPCInstrInfo &TII = *static_cast(MF.getTarget().getInstrInfo()); unsigned RetOpcode = MBBI->getOpcode(); DebugLoc dl; assert((RetOpcode == PPC::BLR || RetOpcode == PPC::TCRETURNri || RetOpcode == PPC::TCRETURNdi || RetOpcode == PPC::TCRETURNai || RetOpcode == PPC::TCRETURNri8 || RetOpcode == PPC::TCRETURNdi8 || RetOpcode == PPC::TCRETURNai8) && "Can only insert epilog into returning blocks"); // Get alignment info so we know how to restore r1 const MachineFrameInfo *MFI = MF.getFrameInfo(); unsigned TargetAlign = getStackAlignment(); unsigned MaxAlign = MFI->getMaxAlignment(); // Get the number of bytes allocated from the FrameInfo. int FrameSize = MFI->getStackSize(); // Get processor type. bool isPPC64 = Subtarget.isPPC64(); // Get operating system bool isDarwinABI = Subtarget.isDarwinABI(); // Check if the link register (LR) has been saved. PPCFunctionInfo *FI = MF.getInfo(); bool MustSaveLR = FI->mustSaveLR(); // Do we have a frame pointer for this function? bool HasFP = hasFP(MF); int LROffset = PPCFrameLowering::getReturnSaveOffset(isPPC64, isDarwinABI); int FPOffset = 0; if (HasFP) { if (Subtarget.isSVR4ABI()) { MachineFrameInfo *FFI = MF.getFrameInfo(); int FPIndex = FI->getFramePointerSaveIndex(); assert(FPIndex && "No Frame Pointer Save Slot!"); FPOffset = FFI->getObjectOffset(FPIndex); } else { FPOffset = PPCFrameLowering::getFramePointerSaveOffset(isPPC64, isDarwinABI); } } bool UsesTCRet = RetOpcode == PPC::TCRETURNri || RetOpcode == PPC::TCRETURNdi || RetOpcode == PPC::TCRETURNai || RetOpcode == PPC::TCRETURNri8 || RetOpcode == PPC::TCRETURNdi8 || RetOpcode == PPC::TCRETURNai8; if (UsesTCRet) { int MaxTCRetDelta = FI->getTailCallSPDelta(); MachineOperand &StackAdjust = MBBI->getOperand(1); assert(StackAdjust.isImm() && "Expecting immediate value."); // Adjust stack pointer. int StackAdj = StackAdjust.getImm(); int Delta = StackAdj - MaxTCRetDelta; assert((Delta >= 0) && "Delta must be positive"); if (MaxTCRetDelta>0) FrameSize += (StackAdj +Delta); else FrameSize += StackAdj; } if (FrameSize) { // The loaded (or persistent) stack pointer value is offset by the 'stwu' // on entry to the function. Add this offset back now. if (!isPPC64) { // If this function contained a fastcc call and GuaranteedTailCallOpt is // enabled (=> hasFastCall()==true) the fastcc call might contain a tail // call which invalidates the stack pointer value in SP(0). So we use the // value of R31 in this case. if (FI->hasFastCall() && isInt<16>(FrameSize)) { assert(hasFP(MF) && "Expecting a valid the frame pointer."); BuildMI(MBB, MBBI, dl, TII.get(PPC::ADDI), PPC::R1) .addReg(PPC::R31).addImm(FrameSize); } else if(FI->hasFastCall()) { BuildMI(MBB, MBBI, dl, TII.get(PPC::LIS), PPC::R0) .addImm(FrameSize >> 16); BuildMI(MBB, MBBI, dl, TII.get(PPC::ORI), PPC::R0) .addReg(PPC::R0, RegState::Kill) .addImm(FrameSize & 0xFFFF); BuildMI(MBB, MBBI, dl, TII.get(PPC::ADD4)) .addReg(PPC::R1) .addReg(PPC::R31) .addReg(PPC::R0); } else if (isInt<16>(FrameSize) && (!ALIGN_STACK || TargetAlign >= MaxAlign) && !MFI->hasVarSizedObjects()) { BuildMI(MBB, MBBI, dl, TII.get(PPC::ADDI), PPC::R1) .addReg(PPC::R1).addImm(FrameSize); } else { BuildMI(MBB, MBBI, dl, TII.get(PPC::LWZ),PPC::R1) .addImm(0).addReg(PPC::R1); } } else { if (FI->hasFastCall() && isInt<16>(FrameSize)) { assert(hasFP(MF) && "Expecting a valid the frame pointer."); BuildMI(MBB, MBBI, dl, TII.get(PPC::ADDI8), PPC::X1) .addReg(PPC::X31).addImm(FrameSize); } else if(FI->hasFastCall()) { BuildMI(MBB, MBBI, dl, TII.get(PPC::LIS8), PPC::X0) .addImm(FrameSize >> 16); BuildMI(MBB, MBBI, dl, TII.get(PPC::ORI8), PPC::X0) .addReg(PPC::X0, RegState::Kill) .addImm(FrameSize & 0xFFFF); BuildMI(MBB, MBBI, dl, TII.get(PPC::ADD8)) .addReg(PPC::X1) .addReg(PPC::X31) .addReg(PPC::X0); } else if (isInt<16>(FrameSize) && TargetAlign >= MaxAlign && !MFI->hasVarSizedObjects()) { BuildMI(MBB, MBBI, dl, TII.get(PPC::ADDI8), PPC::X1) .addReg(PPC::X1).addImm(FrameSize); } else { BuildMI(MBB, MBBI, dl, TII.get(PPC::LD), PPC::X1) .addImm(0).addReg(PPC::X1); } } } if (isPPC64) { if (MustSaveLR) BuildMI(MBB, MBBI, dl, TII.get(PPC::LD), PPC::X0) .addImm(LROffset/4).addReg(PPC::X1); if (HasFP) BuildMI(MBB, MBBI, dl, TII.get(PPC::LD), PPC::X31) .addImm(FPOffset/4).addReg(PPC::X1); if (MustSaveLR) BuildMI(MBB, MBBI, dl, TII.get(PPC::MTLR8)).addReg(PPC::X0); } else { if (MustSaveLR) BuildMI(MBB, MBBI, dl, TII.get(PPC::LWZ), PPC::R0) .addImm(LROffset).addReg(PPC::R1); if (HasFP) BuildMI(MBB, MBBI, dl, TII.get(PPC::LWZ), PPC::R31) .addImm(FPOffset).addReg(PPC::R1); if (MustSaveLR) BuildMI(MBB, MBBI, dl, TII.get(PPC::MTLR)).addReg(PPC::R0); } // Callee pop calling convention. Pop parameter/linkage area. Used for tail // call optimization if (GuaranteedTailCallOpt && RetOpcode == PPC::BLR && MF.getFunction()->getCallingConv() == CallingConv::Fast) { PPCFunctionInfo *FI = MF.getInfo(); unsigned CallerAllocatedAmt = FI->getMinReservedArea(); unsigned StackReg = isPPC64 ? PPC::X1 : PPC::R1; unsigned FPReg = isPPC64 ? PPC::X31 : PPC::R31; unsigned TmpReg = isPPC64 ? PPC::X0 : PPC::R0; unsigned ADDIInstr = isPPC64 ? PPC::ADDI8 : PPC::ADDI; unsigned ADDInstr = isPPC64 ? PPC::ADD8 : PPC::ADD4; unsigned LISInstr = isPPC64 ? PPC::LIS8 : PPC::LIS; unsigned ORIInstr = isPPC64 ? PPC::ORI8 : PPC::ORI; if (CallerAllocatedAmt && isInt<16>(CallerAllocatedAmt)) { BuildMI(MBB, MBBI, dl, TII.get(ADDIInstr), StackReg) .addReg(StackReg).addImm(CallerAllocatedAmt); } else { BuildMI(MBB, MBBI, dl, TII.get(LISInstr), TmpReg) .addImm(CallerAllocatedAmt >> 16); BuildMI(MBB, MBBI, dl, TII.get(ORIInstr), TmpReg) .addReg(TmpReg, RegState::Kill) .addImm(CallerAllocatedAmt & 0xFFFF); BuildMI(MBB, MBBI, dl, TII.get(ADDInstr)) .addReg(StackReg) .addReg(FPReg) .addReg(TmpReg); } } else if (RetOpcode == PPC::TCRETURNdi) { MBBI = MBB.getLastNonDebugInstr(); MachineOperand &JumpTarget = MBBI->getOperand(0); BuildMI(MBB, MBBI, dl, TII.get(PPC::TAILB)). addGlobalAddress(JumpTarget.getGlobal(), JumpTarget.getOffset()); } else if (RetOpcode == PPC::TCRETURNri) { MBBI = MBB.getLastNonDebugInstr(); assert(MBBI->getOperand(0).isReg() && "Expecting register operand."); BuildMI(MBB, MBBI, dl, TII.get(PPC::TAILBCTR)); } else if (RetOpcode == PPC::TCRETURNai) { MBBI = MBB.getLastNonDebugInstr(); MachineOperand &JumpTarget = MBBI->getOperand(0); BuildMI(MBB, MBBI, dl, TII.get(PPC::TAILBA)).addImm(JumpTarget.getImm()); } else if (RetOpcode == PPC::TCRETURNdi8) { MBBI = MBB.getLastNonDebugInstr(); MachineOperand &JumpTarget = MBBI->getOperand(0); BuildMI(MBB, MBBI, dl, TII.get(PPC::TAILB8)). addGlobalAddress(JumpTarget.getGlobal(), JumpTarget.getOffset()); } else if (RetOpcode == PPC::TCRETURNri8) { MBBI = MBB.getLastNonDebugInstr(); assert(MBBI->getOperand(0).isReg() && "Expecting register operand."); BuildMI(MBB, MBBI, dl, TII.get(PPC::TAILBCTR8)); } else if (RetOpcode == PPC::TCRETURNai8) { MBBI = MBB.getLastNonDebugInstr(); MachineOperand &JumpTarget = MBBI->getOperand(0); BuildMI(MBB, MBBI, dl, TII.get(PPC::TAILBA8)).addImm(JumpTarget.getImm()); } } static bool spillsCR(const MachineFunction &MF) { const PPCFunctionInfo *FuncInfo = MF.getInfo(); return FuncInfo->isCRSpilled(); } /// MustSaveLR - Return true if this function requires that we save the LR /// register onto the stack in the prolog and restore it in the epilog of the /// function. static bool MustSaveLR(const MachineFunction &MF, unsigned LR) { const PPCFunctionInfo *MFI = MF.getInfo(); // We need a save/restore of LR if there is any def of LR (which is // defined by calls, including the PIC setup sequence), or if there is // some use of the LR stack slot (e.g. for builtin_return_address). // (LR comes in 32 and 64 bit versions.) MachineRegisterInfo::def_iterator RI = MF.getRegInfo().def_begin(LR); return RI !=MF.getRegInfo().def_end() || MFI->isLRStoreRequired(); } void PPCFrameLowering::processFunctionBeforeCalleeSavedScan(MachineFunction &MF, RegScavenger *RS) const { const TargetRegisterInfo *RegInfo = MF.getTarget().getRegisterInfo(); // Save and clear the LR state. PPCFunctionInfo *FI = MF.getInfo(); unsigned LR = RegInfo->getRARegister(); FI->setMustSaveLR(MustSaveLR(MF, LR)); MF.getRegInfo().setPhysRegUnused(LR); // Save R31 if necessary int FPSI = FI->getFramePointerSaveIndex(); bool isPPC64 = Subtarget.isPPC64(); bool isDarwinABI = Subtarget.isDarwinABI(); MachineFrameInfo *MFI = MF.getFrameInfo(); // If the frame pointer save index hasn't been defined yet. if (!FPSI && needsFP(MF)) { // Find out what the fix offset of the frame pointer save area. int FPOffset = getFramePointerSaveOffset(isPPC64, isDarwinABI); // Allocate the frame index for frame pointer save area. FPSI = MFI->CreateFixedObject(isPPC64? 8 : 4, FPOffset, true); // Save the result. FI->setFramePointerSaveIndex(FPSI); } // Reserve stack space to move the linkage area to in case of a tail call. int TCSPDelta = 0; if (GuaranteedTailCallOpt && (TCSPDelta = FI->getTailCallSPDelta()) < 0) { MFI->CreateFixedObject(-1 * TCSPDelta, TCSPDelta, true); } // Reserve a slot closest to SP or frame pointer if we have a dynalloc or // a large stack, which will require scavenging a register to materialize a // large offset. // FIXME: this doesn't actually check stack size, so is a bit pessimistic // FIXME: doesn't detect whether or not we need to spill vXX, which requires // r0 for now. if (RegInfo->requiresRegisterScavenging(MF)) // FIXME (64-bit): Enable. if (needsFP(MF) || spillsCR(MF)) { const TargetRegisterClass *GPRC = &PPC::GPRCRegClass; const TargetRegisterClass *G8RC = &PPC::G8RCRegClass; const TargetRegisterClass *RC = isPPC64 ? G8RC : GPRC; RS->setScavengingFrameIndex(MFI->CreateStackObject(RC->getSize(), RC->getAlignment(), false)); } } void PPCFrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF) const { // Early exit if not using the SVR4 ABI. if (!Subtarget.isSVR4ABI()) return; // Get callee saved register information. MachineFrameInfo *FFI = MF.getFrameInfo(); const std::vector &CSI = FFI->getCalleeSavedInfo(); // Early exit if no callee saved registers are modified! if (CSI.empty() && !needsFP(MF)) { return; } unsigned MinGPR = PPC::R31; unsigned MinG8R = PPC::X31; unsigned MinFPR = PPC::F31; unsigned MinVR = PPC::V31; bool HasGPSaveArea = false; bool HasG8SaveArea = false; bool HasFPSaveArea = false; bool HasCRSaveArea = false; bool HasVRSAVESaveArea = false; bool HasVRSaveArea = false; SmallVector GPRegs; SmallVector G8Regs; SmallVector FPRegs; SmallVector VRegs; for (unsigned i = 0, e = CSI.size(); i != e; ++i) { unsigned Reg = CSI[i].getReg(); if (PPC::GPRCRegisterClass->contains(Reg)) { HasGPSaveArea = true; GPRegs.push_back(CSI[i]); if (Reg < MinGPR) { MinGPR = Reg; } } else if (PPC::G8RCRegisterClass->contains(Reg)) { HasG8SaveArea = true; G8Regs.push_back(CSI[i]); if (Reg < MinG8R) { MinG8R = Reg; } } else if (PPC::F8RCRegisterClass->contains(Reg)) { HasFPSaveArea = true; FPRegs.push_back(CSI[i]); if (Reg < MinFPR) { MinFPR = Reg; } // FIXME SVR4: Disable CR save area for now. } else if (PPC::CRBITRCRegisterClass->contains(Reg) || PPC::CRRCRegisterClass->contains(Reg)) { // HasCRSaveArea = true; } else if (PPC::VRSAVERCRegisterClass->contains(Reg)) { HasVRSAVESaveArea = true; } else if (PPC::VRRCRegisterClass->contains(Reg)) { HasVRSaveArea = true; VRegs.push_back(CSI[i]); if (Reg < MinVR) { MinVR = Reg; } } else { llvm_unreachable("Unknown RegisterClass!"); } } PPCFunctionInfo *PFI = MF.getInfo(); int64_t LowerBound = 0; // Take into account stack space reserved for tail calls. int TCSPDelta = 0; if (GuaranteedTailCallOpt && (TCSPDelta = PFI->getTailCallSPDelta()) < 0) { LowerBound = TCSPDelta; } // The Floating-point register save area is right below the back chain word // of the previous stack frame. if (HasFPSaveArea) { for (unsigned i = 0, e = FPRegs.size(); i != e; ++i) { int FI = FPRegs[i].getFrameIdx(); FFI->setObjectOffset(FI, LowerBound + FFI->getObjectOffset(FI)); } LowerBound -= (31 - getPPCRegisterNumbering(MinFPR) + 1) * 8; } // Check whether the frame pointer register is allocated. If so, make sure it // is spilled to the correct offset. if (needsFP(MF)) { HasGPSaveArea = true; int FI = PFI->getFramePointerSaveIndex(); assert(FI && "No Frame Pointer Save Slot!"); FFI->setObjectOffset(FI, LowerBound + FFI->getObjectOffset(FI)); } // General register save area starts right below the Floating-point // register save area. if (HasGPSaveArea || HasG8SaveArea) { // Move general register save area spill slots down, taking into account // the size of the Floating-point register save area. for (unsigned i = 0, e = GPRegs.size(); i != e; ++i) { int FI = GPRegs[i].getFrameIdx(); FFI->setObjectOffset(FI, LowerBound + FFI->getObjectOffset(FI)); } // Move general register save area spill slots down, taking into account // the size of the Floating-point register save area. for (unsigned i = 0, e = G8Regs.size(); i != e; ++i) { int FI = G8Regs[i].getFrameIdx(); FFI->setObjectOffset(FI, LowerBound + FFI->getObjectOffset(FI)); } unsigned MinReg = std::min(getPPCRegisterNumbering(MinGPR), getPPCRegisterNumbering(MinG8R)); if (Subtarget.isPPC64()) { LowerBound -= (31 - MinReg + 1) * 8; } else { LowerBound -= (31 - MinReg + 1) * 4; } } // The CR save area is below the general register save area. if (HasCRSaveArea) { // FIXME SVR4: Is it actually possible to have multiple elements in CSI // which have the CR/CRBIT register class? // Adjust the frame index of the CR spill slot. for (unsigned i = 0, e = CSI.size(); i != e; ++i) { unsigned Reg = CSI[i].getReg(); if (PPC::CRBITRCRegisterClass->contains(Reg) || PPC::CRRCRegisterClass->contains(Reg)) { int FI = CSI[i].getFrameIdx(); FFI->setObjectOffset(FI, LowerBound + FFI->getObjectOffset(FI)); } } LowerBound -= 4; // The CR save area is always 4 bytes long. } if (HasVRSAVESaveArea) { // FIXME SVR4: Is it actually possible to have multiple elements in CSI // which have the VRSAVE register class? // Adjust the frame index of the VRSAVE spill slot. for (unsigned i = 0, e = CSI.size(); i != e; ++i) { unsigned Reg = CSI[i].getReg(); if (PPC::VRSAVERCRegisterClass->contains(Reg)) { int FI = CSI[i].getFrameIdx(); FFI->setObjectOffset(FI, LowerBound + FFI->getObjectOffset(FI)); } } LowerBound -= 4; // The VRSAVE save area is always 4 bytes long. } if (HasVRSaveArea) { // Insert alignment padding, we need 16-byte alignment. LowerBound = (LowerBound - 15) & ~(15); for (unsigned i = 0, e = VRegs.size(); i != e; ++i) { int FI = VRegs[i].getFrameIdx(); FFI->setObjectOffset(FI, LowerBound + FFI->getObjectOffset(FI)); } } } Index: head/contrib/llvm/lib/Target/X86/X86CodeEmitter.cpp =================================================================== --- head/contrib/llvm/lib/Target/X86/X86CodeEmitter.cpp (revision 228378) +++ head/contrib/llvm/lib/Target/X86/X86CodeEmitter.cpp (revision 228379) @@ -1,999 +1,1014 @@ //===-- X86/X86CodeEmitter.cpp - Convert X86 code to machine code ---------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file contains the pass that transforms the X86 machine instructions into // relocatable machine code. // //===----------------------------------------------------------------------===// #define DEBUG_TYPE "x86-emitter" #include "X86InstrInfo.h" #include "X86JITInfo.h" #include "X86Subtarget.h" #include "X86TargetMachine.h" #include "X86Relocations.h" #include "X86.h" #include "llvm/LLVMContext.h" #include "llvm/PassManager.h" #include "llvm/CodeGen/JITCodeEmitter.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/Passes.h" #include "llvm/Function.h" #include "llvm/ADT/Statistic.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetOptions.h" using namespace llvm; STATISTIC(NumEmitted, "Number of machine instructions emitted"); namespace { template class Emitter : public MachineFunctionPass { const X86InstrInfo *II; const TargetData *TD; X86TargetMachine &TM; CodeEmitter &MCE; MachineModuleInfo *MMI; intptr_t PICBaseOffset; bool Is64BitMode; bool IsPIC; public: static char ID; explicit Emitter(X86TargetMachine &tm, CodeEmitter &mce) : MachineFunctionPass(ID), II(0), TD(0), TM(tm), MCE(mce), PICBaseOffset(0), Is64BitMode(false), IsPIC(TM.getRelocationModel() == Reloc::PIC_) {} Emitter(X86TargetMachine &tm, CodeEmitter &mce, const X86InstrInfo &ii, const TargetData &td, bool is64) : MachineFunctionPass(ID), II(&ii), TD(&td), TM(tm), MCE(mce), PICBaseOffset(0), Is64BitMode(is64), IsPIC(TM.getRelocationModel() == Reloc::PIC_) {} bool runOnMachineFunction(MachineFunction &MF); virtual const char *getPassName() const { return "X86 Machine Code Emitter"; } void emitInstruction(MachineInstr &MI, const MCInstrDesc *Desc); void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); AU.addRequired(); MachineFunctionPass::getAnalysisUsage(AU); } private: void emitPCRelativeBlockAddress(MachineBasicBlock *MBB); void emitGlobalAddress(const GlobalValue *GV, unsigned Reloc, intptr_t Disp = 0, intptr_t PCAdj = 0, bool Indirect = false); void emitExternalSymbolAddress(const char *ES, unsigned Reloc); void emitConstPoolAddress(unsigned CPI, unsigned Reloc, intptr_t Disp = 0, intptr_t PCAdj = 0); void emitJumpTableAddress(unsigned JTI, unsigned Reloc, intptr_t PCAdj = 0); void emitDisplacementField(const MachineOperand *RelocOp, int DispVal, intptr_t Adj = 0, bool IsPCRel = true); void emitRegModRMByte(unsigned ModRMReg, unsigned RegOpcodeField); void emitRegModRMByte(unsigned RegOpcodeField); void emitSIBByte(unsigned SS, unsigned Index, unsigned Base); void emitConstant(uint64_t Val, unsigned Size); void emitMemModRMByte(const MachineInstr &MI, unsigned Op, unsigned RegOpcodeField, intptr_t PCAdj = 0); }; template char Emitter::ID = 0; } // end anonymous namespace. /// createX86CodeEmitterPass - Return a pass that emits the collected X86 code /// to the specified templated MachineCodeEmitter object. FunctionPass *llvm::createX86JITCodeEmitterPass(X86TargetMachine &TM, JITCodeEmitter &JCE) { return new Emitter(TM, JCE); } template bool Emitter::runOnMachineFunction(MachineFunction &MF) { MMI = &getAnalysis(); MCE.setModuleInfo(MMI); II = TM.getInstrInfo(); TD = TM.getTargetData(); Is64BitMode = TM.getSubtarget().is64Bit(); IsPIC = TM.getRelocationModel() == Reloc::PIC_; do { DEBUG(dbgs() << "JITTing function '" << MF.getFunction()->getName() << "'\n"); MCE.startFunction(MF); for (MachineFunction::iterator MBB = MF.begin(), E = MF.end(); MBB != E; ++MBB) { MCE.StartMachineBasicBlock(MBB); for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end(); I != E; ++I) { const MCInstrDesc &Desc = I->getDesc(); emitInstruction(*I, &Desc); // MOVPC32r is basically a call plus a pop instruction. if (Desc.getOpcode() == X86::MOVPC32r) emitInstruction(*I, &II->get(X86::POP32r)); ++NumEmitted; // Keep track of the # of mi's emitted } } } while (MCE.finishFunction(MF)); return false; } /// determineREX - Determine if the MachineInstr has to be encoded with a X86-64 /// REX prefix which specifies 1) 64-bit instructions, 2) non-default operand /// size, and 3) use of X86-64 extended registers. static unsigned determineREX(const MachineInstr &MI) { unsigned REX = 0; const MCInstrDesc &Desc = MI.getDesc(); // Pseudo instructions do not need REX prefix byte. if ((Desc.TSFlags & X86II::FormMask) == X86II::Pseudo) return 0; if (Desc.TSFlags & X86II::REX_W) REX |= 1 << 3; unsigned NumOps = Desc.getNumOperands(); if (NumOps) { bool isTwoAddr = NumOps > 1 && Desc.getOperandConstraint(1, MCOI::TIED_TO) != -1; // If it accesses SPL, BPL, SIL, or DIL, then it requires a 0x40 REX prefix. unsigned i = isTwoAddr ? 1 : 0; for (unsigned e = NumOps; i != e; ++i) { const MachineOperand& MO = MI.getOperand(i); if (MO.isReg()) { unsigned Reg = MO.getReg(); if (X86II::isX86_64NonExtLowByteReg(Reg)) REX |= 0x40; } } switch (Desc.TSFlags & X86II::FormMask) { case X86II::MRMInitReg: if (X86InstrInfo::isX86_64ExtendedReg(MI.getOperand(0))) REX |= (1 << 0) | (1 << 2); break; case X86II::MRMSrcReg: { if (X86InstrInfo::isX86_64ExtendedReg(MI.getOperand(0))) REX |= 1 << 2; i = isTwoAddr ? 2 : 1; for (unsigned e = NumOps; i != e; ++i) { const MachineOperand& MO = MI.getOperand(i); if (X86InstrInfo::isX86_64ExtendedReg(MO)) REX |= 1 << 0; } break; } case X86II::MRMSrcMem: { if (X86InstrInfo::isX86_64ExtendedReg(MI.getOperand(0))) REX |= 1 << 2; unsigned Bit = 0; i = isTwoAddr ? 2 : 1; for (; i != NumOps; ++i) { const MachineOperand& MO = MI.getOperand(i); if (MO.isReg()) { if (X86InstrInfo::isX86_64ExtendedReg(MO)) REX |= 1 << Bit; Bit++; } } break; } case X86II::MRM0m: case X86II::MRM1m: case X86II::MRM2m: case X86II::MRM3m: case X86II::MRM4m: case X86II::MRM5m: case X86II::MRM6m: case X86II::MRM7m: case X86II::MRMDestMem: { unsigned e = (isTwoAddr ? X86::AddrNumOperands+1 : X86::AddrNumOperands); i = isTwoAddr ? 1 : 0; if (NumOps > e && X86InstrInfo::isX86_64ExtendedReg(MI.getOperand(e))) REX |= 1 << 2; unsigned Bit = 0; for (; i != e; ++i) { const MachineOperand& MO = MI.getOperand(i); if (MO.isReg()) { if (X86InstrInfo::isX86_64ExtendedReg(MO)) REX |= 1 << Bit; Bit++; } } break; } default: { if (X86InstrInfo::isX86_64ExtendedReg(MI.getOperand(0))) REX |= 1 << 0; i = isTwoAddr ? 2 : 1; for (unsigned e = NumOps; i != e; ++i) { const MachineOperand& MO = MI.getOperand(i); if (X86InstrInfo::isX86_64ExtendedReg(MO)) REX |= 1 << 2; } break; } } } return REX; } /// emitPCRelativeBlockAddress - This method keeps track of the information /// necessary to resolve the address of this block later and emits a dummy /// value. /// template void Emitter::emitPCRelativeBlockAddress(MachineBasicBlock *MBB) { // Remember where this reference was and where it is to so we can // deal with it later. MCE.addRelocation(MachineRelocation::getBB(MCE.getCurrentPCOffset(), X86::reloc_pcrel_word, MBB)); MCE.emitWordLE(0); } /// emitGlobalAddress - Emit the specified address to the code stream assuming /// this is part of a "take the address of a global" instruction. /// template void Emitter::emitGlobalAddress(const GlobalValue *GV, unsigned Reloc, intptr_t Disp /* = 0 */, intptr_t PCAdj /* = 0 */, bool Indirect /* = false */) { intptr_t RelocCST = Disp; if (Reloc == X86::reloc_picrel_word) RelocCST = PICBaseOffset; else if (Reloc == X86::reloc_pcrel_word) RelocCST = PCAdj; MachineRelocation MR = Indirect ? MachineRelocation::getIndirectSymbol(MCE.getCurrentPCOffset(), Reloc, const_cast(GV), RelocCST, false) : MachineRelocation::getGV(MCE.getCurrentPCOffset(), Reloc, const_cast(GV), RelocCST, false); MCE.addRelocation(MR); // The relocated value will be added to the displacement if (Reloc == X86::reloc_absolute_dword) MCE.emitDWordLE(Disp); else MCE.emitWordLE((int32_t)Disp); } /// emitExternalSymbolAddress - Arrange for the address of an external symbol to /// be emitted to the current location in the function, and allow it to be PC /// relative. template void Emitter::emitExternalSymbolAddress(const char *ES, unsigned Reloc) { intptr_t RelocCST = (Reloc == X86::reloc_picrel_word) ? PICBaseOffset : 0; // X86 never needs stubs because instruction selection will always pick // an instruction sequence that is large enough to hold any address // to a symbol. // (see X86ISelLowering.cpp, near 2039: X86TargetLowering::LowerCall) bool NeedStub = false; MCE.addRelocation(MachineRelocation::getExtSym(MCE.getCurrentPCOffset(), Reloc, ES, RelocCST, 0, NeedStub)); if (Reloc == X86::reloc_absolute_dword) MCE.emitDWordLE(0); else MCE.emitWordLE(0); } /// emitConstPoolAddress - Arrange for the address of an constant pool /// to be emitted to the current location in the function, and allow it to be PC /// relative. template void Emitter::emitConstPoolAddress(unsigned CPI, unsigned Reloc, intptr_t Disp /* = 0 */, intptr_t PCAdj /* = 0 */) { intptr_t RelocCST = 0; if (Reloc == X86::reloc_picrel_word) RelocCST = PICBaseOffset; else if (Reloc == X86::reloc_pcrel_word) RelocCST = PCAdj; MCE.addRelocation(MachineRelocation::getConstPool(MCE.getCurrentPCOffset(), Reloc, CPI, RelocCST)); // The relocated value will be added to the displacement if (Reloc == X86::reloc_absolute_dword) MCE.emitDWordLE(Disp); else MCE.emitWordLE((int32_t)Disp); } /// emitJumpTableAddress - Arrange for the address of a jump table to /// be emitted to the current location in the function, and allow it to be PC /// relative. template void Emitter::emitJumpTableAddress(unsigned JTI, unsigned Reloc, intptr_t PCAdj /* = 0 */) { intptr_t RelocCST = 0; if (Reloc == X86::reloc_picrel_word) RelocCST = PICBaseOffset; else if (Reloc == X86::reloc_pcrel_word) RelocCST = PCAdj; MCE.addRelocation(MachineRelocation::getJumpTable(MCE.getCurrentPCOffset(), Reloc, JTI, RelocCST)); // The relocated value will be added to the displacement if (Reloc == X86::reloc_absolute_dword) MCE.emitDWordLE(0); else MCE.emitWordLE(0); } inline static unsigned char ModRMByte(unsigned Mod, unsigned RegOpcode, unsigned RM) { assert(Mod < 4 && RegOpcode < 8 && RM < 8 && "ModRM Fields out of range!"); return RM | (RegOpcode << 3) | (Mod << 6); } template void Emitter::emitRegModRMByte(unsigned ModRMReg, unsigned RegOpcodeFld){ MCE.emitByte(ModRMByte(3, RegOpcodeFld, X86_MC::getX86RegNum(ModRMReg))); } template void Emitter::emitRegModRMByte(unsigned RegOpcodeFld) { MCE.emitByte(ModRMByte(3, RegOpcodeFld, 0)); } template void Emitter::emitSIBByte(unsigned SS, unsigned Index, unsigned Base) { // SIB byte is in the same format as the ModRMByte... MCE.emitByte(ModRMByte(SS, Index, Base)); } template void Emitter::emitConstant(uint64_t Val, unsigned Size) { // Output the constant in little endian byte order... for (unsigned i = 0; i != Size; ++i) { MCE.emitByte(Val & 255); Val >>= 8; } } /// isDisp8 - Return true if this signed displacement fits in a 8-bit /// sign-extended field. static bool isDisp8(int Value) { return Value == (signed char)Value; } static bool gvNeedsNonLazyPtr(const MachineOperand &GVOp, const TargetMachine &TM) { // For Darwin-64, simulate the linktime GOT by using the same non-lazy-pointer // mechanism as 32-bit mode. if (TM.getSubtarget().is64Bit() && !TM.getSubtarget().isTargetDarwin()) return false; // Return true if this is a reference to a stub containing the address of the // global, not the global itself. return isGlobalStubReference(GVOp.getTargetFlags()); } template void Emitter::emitDisplacementField(const MachineOperand *RelocOp, int DispVal, intptr_t Adj /* = 0 */, bool IsPCRel /* = true */) { // If this is a simple integer displacement that doesn't require a relocation, // emit it now. if (!RelocOp) { emitConstant(DispVal, 4); return; } // Otherwise, this is something that requires a relocation. Emit it as such // now. unsigned RelocType = Is64BitMode ? (IsPCRel ? X86::reloc_pcrel_word : X86::reloc_absolute_word_sext) : (IsPIC ? X86::reloc_picrel_word : X86::reloc_absolute_word); if (RelocOp->isGlobal()) { // In 64-bit static small code model, we could potentially emit absolute. // But it's probably not beneficial. If the MCE supports using RIP directly // do it, otherwise fallback to absolute (this is determined by IsPCRel). // 89 05 00 00 00 00 mov %eax,0(%rip) # PC-relative // 89 04 25 00 00 00 00 mov %eax,0x0 # Absolute bool Indirect = gvNeedsNonLazyPtr(*RelocOp, TM); emitGlobalAddress(RelocOp->getGlobal(), RelocType, RelocOp->getOffset(), Adj, Indirect); } else if (RelocOp->isSymbol()) { emitExternalSymbolAddress(RelocOp->getSymbolName(), RelocType); } else if (RelocOp->isCPI()) { emitConstPoolAddress(RelocOp->getIndex(), RelocType, RelocOp->getOffset(), Adj); } else { assert(RelocOp->isJTI() && "Unexpected machine operand!"); emitJumpTableAddress(RelocOp->getIndex(), RelocType, Adj); } } template void Emitter::emitMemModRMByte(const MachineInstr &MI, unsigned Op,unsigned RegOpcodeField, intptr_t PCAdj) { const MachineOperand &Op3 = MI.getOperand(Op+3); int DispVal = 0; const MachineOperand *DispForReloc = 0; // Figure out what sort of displacement we have to handle here. if (Op3.isGlobal()) { DispForReloc = &Op3; } else if (Op3.isSymbol()) { DispForReloc = &Op3; } else if (Op3.isCPI()) { if (!MCE.earlyResolveAddresses() || Is64BitMode || IsPIC) { DispForReloc = &Op3; } else { DispVal += MCE.getConstantPoolEntryAddress(Op3.getIndex()); DispVal += Op3.getOffset(); } } else if (Op3.isJTI()) { if (!MCE.earlyResolveAddresses() || Is64BitMode || IsPIC) { DispForReloc = &Op3; } else { DispVal += MCE.getJumpTableEntryAddress(Op3.getIndex()); } } else { DispVal = Op3.getImm(); } const MachineOperand &Base = MI.getOperand(Op); const MachineOperand &Scale = MI.getOperand(Op+1); const MachineOperand &IndexReg = MI.getOperand(Op+2); unsigned BaseReg = Base.getReg(); // Handle %rip relative addressing. if (BaseReg == X86::RIP || (Is64BitMode && DispForReloc)) { // [disp32+RIP] in X86-64 mode assert(IndexReg.getReg() == 0 && Is64BitMode && "Invalid rip-relative address"); MCE.emitByte(ModRMByte(0, RegOpcodeField, 5)); emitDisplacementField(DispForReloc, DispVal, PCAdj, true); return; } // Indicate that the displacement will use an pcrel or absolute reference // by default. MCEs able to resolve addresses on-the-fly use pcrel by default // while others, unless explicit asked to use RIP, use absolute references. bool IsPCRel = MCE.earlyResolveAddresses() ? true : false; // Is a SIB byte needed? // If no BaseReg, issue a RIP relative instruction only if the MCE can // resolve addresses on-the-fly, otherwise use SIB (Intel Manual 2A, table // 2-7) and absolute references. unsigned BaseRegNo = -1U; if (BaseReg != 0 && BaseReg != X86::RIP) BaseRegNo = X86_MC::getX86RegNum(BaseReg); if (// The SIB byte must be used if there is an index register. IndexReg.getReg() == 0 && // The SIB byte must be used if the base is ESP/RSP/R12, all of which // encode to an R/M value of 4, which indicates that a SIB byte is // present. BaseRegNo != N86::ESP && // If there is no base register and we're in 64-bit mode, we need a SIB // byte to emit an addr that is just 'disp32' (the non-RIP relative form). (!Is64BitMode || BaseReg != 0)) { if (BaseReg == 0 || // [disp32] in X86-32 mode BaseReg == X86::RIP) { // [disp32+RIP] in X86-64 mode MCE.emitByte(ModRMByte(0, RegOpcodeField, 5)); emitDisplacementField(DispForReloc, DispVal, PCAdj, true); return; } // If the base is not EBP/ESP and there is no displacement, use simple // indirect register encoding, this handles addresses like [EAX]. The // encoding for [EBP] with no displacement means [disp32] so we handle it // by emitting a displacement of 0 below. if (!DispForReloc && DispVal == 0 && BaseRegNo != N86::EBP) { MCE.emitByte(ModRMByte(0, RegOpcodeField, BaseRegNo)); return; } // Otherwise, if the displacement fits in a byte, encode as [REG+disp8]. if (!DispForReloc && isDisp8(DispVal)) { MCE.emitByte(ModRMByte(1, RegOpcodeField, BaseRegNo)); emitConstant(DispVal, 1); return; } // Otherwise, emit the most general non-SIB encoding: [REG+disp32] MCE.emitByte(ModRMByte(2, RegOpcodeField, BaseRegNo)); emitDisplacementField(DispForReloc, DispVal, PCAdj, IsPCRel); return; } // Otherwise we need a SIB byte, so start by outputting the ModR/M byte first. assert(IndexReg.getReg() != X86::ESP && IndexReg.getReg() != X86::RSP && "Cannot use ESP as index reg!"); bool ForceDisp32 = false; bool ForceDisp8 = false; if (BaseReg == 0) { // If there is no base register, we emit the special case SIB byte with // MOD=0, BASE=4, to JUST get the index, scale, and displacement. MCE.emitByte(ModRMByte(0, RegOpcodeField, 4)); ForceDisp32 = true; } else if (DispForReloc) { // Emit the normal disp32 encoding. MCE.emitByte(ModRMByte(2, RegOpcodeField, 4)); ForceDisp32 = true; } else if (DispVal == 0 && BaseRegNo != N86::EBP) { // Emit no displacement ModR/M byte MCE.emitByte(ModRMByte(0, RegOpcodeField, 4)); } else if (isDisp8(DispVal)) { // Emit the disp8 encoding... MCE.emitByte(ModRMByte(1, RegOpcodeField, 4)); ForceDisp8 = true; // Make sure to force 8 bit disp if Base=EBP } else { // Emit the normal disp32 encoding... MCE.emitByte(ModRMByte(2, RegOpcodeField, 4)); } // Calculate what the SS field value should be... static const unsigned SSTable[] = { ~0U, 0, 1, ~0U, 2, ~0U, ~0U, ~0U, 3 }; unsigned SS = SSTable[Scale.getImm()]; if (BaseReg == 0) { // Handle the SIB byte for the case where there is no base, see Intel // Manual 2A, table 2-7. The displacement has already been output. unsigned IndexRegNo; if (IndexReg.getReg()) IndexRegNo = X86_MC::getX86RegNum(IndexReg.getReg()); else // Examples: [ESP+1*+4] or [scaled idx]+disp32 (MOD=0,BASE=5) IndexRegNo = 4; emitSIBByte(SS, IndexRegNo, 5); } else { unsigned BaseRegNo = X86_MC::getX86RegNum(BaseReg); unsigned IndexRegNo; if (IndexReg.getReg()) IndexRegNo = X86_MC::getX86RegNum(IndexReg.getReg()); else IndexRegNo = 4; // For example [ESP+1*+4] emitSIBByte(SS, IndexRegNo, BaseRegNo); } // Do we need to output a displacement? if (ForceDisp8) { emitConstant(DispVal, 1); } else if (DispVal != 0 || ForceDisp32) { emitDisplacementField(DispForReloc, DispVal, PCAdj, IsPCRel); } } +static const MCInstrDesc *UpdateOp(MachineInstr &MI, const X86InstrInfo *II, + unsigned Opcode) { + const MCInstrDesc *Desc = &II->get(Opcode); + MI.setDesc(*Desc); + return Desc; +} + template void Emitter::emitInstruction(MachineInstr &MI, const MCInstrDesc *Desc) { DEBUG(dbgs() << MI); // If this is a pseudo instruction, lower it. switch (Desc->getOpcode()) { - case X86::ADD16rr_DB: Desc = &II->get(X86::OR16rr); MI.setDesc(*Desc);break; - case X86::ADD32rr_DB: Desc = &II->get(X86::OR32rr); MI.setDesc(*Desc);break; - case X86::ADD64rr_DB: Desc = &II->get(X86::OR64rr); MI.setDesc(*Desc);break; - case X86::ADD16ri_DB: Desc = &II->get(X86::OR16ri); MI.setDesc(*Desc);break; - case X86::ADD32ri_DB: Desc = &II->get(X86::OR32ri); MI.setDesc(*Desc);break; - case X86::ADD64ri32_DB:Desc = &II->get(X86::OR64ri32);MI.setDesc(*Desc);break; - case X86::ADD16ri8_DB: Desc = &II->get(X86::OR16ri8);MI.setDesc(*Desc);break; - case X86::ADD32ri8_DB: Desc = &II->get(X86::OR32ri8);MI.setDesc(*Desc);break; - case X86::ADD64ri8_DB: Desc = &II->get(X86::OR64ri8);MI.setDesc(*Desc);break; + case X86::ADD16rr_DB: Desc = UpdateOp(MI, II, X86::OR16rr); break; + case X86::ADD32rr_DB: Desc = UpdateOp(MI, II, X86::OR32rr); break; + case X86::ADD64rr_DB: Desc = UpdateOp(MI, II, X86::OR64rr); break; + case X86::ADD16ri_DB: Desc = UpdateOp(MI, II, X86::OR16ri); break; + case X86::ADD32ri_DB: Desc = UpdateOp(MI, II, X86::OR32ri); break; + case X86::ADD64ri32_DB: Desc = UpdateOp(MI, II, X86::OR64ri32); break; + case X86::ADD16ri8_DB: Desc = UpdateOp(MI, II, X86::OR16ri8); break; + case X86::ADD32ri8_DB: Desc = UpdateOp(MI, II, X86::OR32ri8); break; + case X86::ADD64ri8_DB: Desc = UpdateOp(MI, II, X86::OR64ri8); break; + case X86::ACQUIRE_MOV8rm: Desc = UpdateOp(MI, II, X86::MOV8rm); break; + case X86::ACQUIRE_MOV16rm: Desc = UpdateOp(MI, II, X86::MOV16rm); break; + case X86::ACQUIRE_MOV32rm: Desc = UpdateOp(MI, II, X86::MOV32rm); break; + case X86::ACQUIRE_MOV64rm: Desc = UpdateOp(MI, II, X86::MOV64rm); break; + case X86::RELEASE_MOV8mr: Desc = UpdateOp(MI, II, X86::MOV8mr); break; + case X86::RELEASE_MOV16mr: Desc = UpdateOp(MI, II, X86::MOV16mr); break; + case X86::RELEASE_MOV32mr: Desc = UpdateOp(MI, II, X86::MOV32mr); break; + case X86::RELEASE_MOV64mr: Desc = UpdateOp(MI, II, X86::MOV64mr); break; } MCE.processDebugLoc(MI.getDebugLoc(), true); unsigned Opcode = Desc->Opcode; // Emit the lock opcode prefix as needed. if (Desc->TSFlags & X86II::LOCK) MCE.emitByte(0xF0); // Emit segment override opcode prefix as needed. switch (Desc->TSFlags & X86II::SegOvrMask) { case X86II::FS: MCE.emitByte(0x64); break; case X86II::GS: MCE.emitByte(0x65); break; default: llvm_unreachable("Invalid segment!"); case 0: break; // No segment override! } // Emit the repeat opcode prefix as needed. if ((Desc->TSFlags & X86II::Op0Mask) == X86II::REP) MCE.emitByte(0xF3); // Emit the operand size opcode prefix as needed. if (Desc->TSFlags & X86II::OpSize) MCE.emitByte(0x66); // Emit the address size opcode prefix as needed. if (Desc->TSFlags & X86II::AdSize) MCE.emitByte(0x67); bool Need0FPrefix = false; switch (Desc->TSFlags & X86II::Op0Mask) { case X86II::TB: // Two-byte opcode prefix case X86II::T8: // 0F 38 case X86II::TA: // 0F 3A case X86II::A6: // 0F A6 case X86II::A7: // 0F A7 Need0FPrefix = true; break; case X86II::TF: // F2 0F 38 MCE.emitByte(0xF2); Need0FPrefix = true; break; case X86II::REP: break; // already handled. case X86II::XS: // F3 0F MCE.emitByte(0xF3); Need0FPrefix = true; break; case X86II::XD: // F2 0F MCE.emitByte(0xF2); Need0FPrefix = true; break; case X86II::D8: case X86II::D9: case X86II::DA: case X86II::DB: case X86II::DC: case X86II::DD: case X86II::DE: case X86II::DF: MCE.emitByte(0xD8+ (((Desc->TSFlags & X86II::Op0Mask)-X86II::D8) >> X86II::Op0Shift)); break; // Two-byte opcode prefix default: llvm_unreachable("Invalid prefix!"); case 0: break; // No prefix! } // Handle REX prefix. if (Is64BitMode) { if (unsigned REX = determineREX(MI)) MCE.emitByte(0x40 | REX); } // 0x0F escape code must be emitted just before the opcode. if (Need0FPrefix) MCE.emitByte(0x0F); switch (Desc->TSFlags & X86II::Op0Mask) { case X86II::TF: // F2 0F 38 case X86II::T8: // 0F 38 MCE.emitByte(0x38); break; case X86II::TA: // 0F 3A MCE.emitByte(0x3A); break; case X86II::A6: // 0F A6 MCE.emitByte(0xA6); break; case X86II::A7: // 0F A7 MCE.emitByte(0xA7); break; } // If this is a two-address instruction, skip one of the register operands. unsigned NumOps = Desc->getNumOperands(); unsigned CurOp = 0; if (NumOps > 1 && Desc->getOperandConstraint(1, MCOI::TIED_TO) != -1) ++CurOp; else if (NumOps > 2 && Desc->getOperandConstraint(NumOps-1,MCOI::TIED_TO)== 0) // Skip the last source operand that is tied_to the dest reg. e.g. LXADD32 --NumOps; unsigned char BaseOpcode = X86II::getBaseOpcodeFor(Desc->TSFlags); switch (Desc->TSFlags & X86II::FormMask) { default: llvm_unreachable("Unknown FormMask value in X86 MachineCodeEmitter!"); case X86II::Pseudo: // Remember the current PC offset, this is the PIC relocation // base address. switch (Opcode) { default: llvm_unreachable("pseudo instructions should be removed before code" " emission"); break; // Do nothing for Int_MemBarrier - it's just a comment. Add a debug // to make it slightly easier to see. case X86::Int_MemBarrier: DEBUG(dbgs() << "#MEMBARRIER\n"); break; case TargetOpcode::INLINEASM: // We allow inline assembler nodes with empty bodies - they can // implicitly define registers, which is ok for JIT. if (MI.getOperand(0).getSymbolName()[0]) report_fatal_error("JIT does not support inline asm!"); break; case TargetOpcode::PROLOG_LABEL: case TargetOpcode::GC_LABEL: case TargetOpcode::EH_LABEL: MCE.emitLabel(MI.getOperand(0).getMCSymbol()); break; case TargetOpcode::IMPLICIT_DEF: case TargetOpcode::KILL: break; case X86::MOVPC32r: { // This emits the "call" portion of this pseudo instruction. MCE.emitByte(BaseOpcode); emitConstant(0, X86II::getSizeOfImm(Desc->TSFlags)); // Remember PIC base. PICBaseOffset = (intptr_t) MCE.getCurrentPCOffset(); X86JITInfo *JTI = TM.getJITInfo(); JTI->setPICBase(MCE.getCurrentPCValue()); break; } } CurOp = NumOps; break; case X86II::RawFrm: { MCE.emitByte(BaseOpcode); if (CurOp == NumOps) break; const MachineOperand &MO = MI.getOperand(CurOp++); DEBUG(dbgs() << "RawFrm CurOp " << CurOp << "\n"); DEBUG(dbgs() << "isMBB " << MO.isMBB() << "\n"); DEBUG(dbgs() << "isGlobal " << MO.isGlobal() << "\n"); DEBUG(dbgs() << "isSymbol " << MO.isSymbol() << "\n"); DEBUG(dbgs() << "isImm " << MO.isImm() << "\n"); if (MO.isMBB()) { emitPCRelativeBlockAddress(MO.getMBB()); break; } if (MO.isGlobal()) { emitGlobalAddress(MO.getGlobal(), X86::reloc_pcrel_word, MO.getOffset(), 0); break; } if (MO.isSymbol()) { emitExternalSymbolAddress(MO.getSymbolName(), X86::reloc_pcrel_word); break; } // FIXME: Only used by hackish MCCodeEmitter, remove when dead. if (MO.isJTI()) { emitJumpTableAddress(MO.getIndex(), X86::reloc_pcrel_word); break; } assert(MO.isImm() && "Unknown RawFrm operand!"); if (Opcode == X86::CALLpcrel32 || Opcode == X86::CALL64pcrel32 || Opcode == X86::WINCALL64pcrel32) { // Fix up immediate operand for pc relative calls. intptr_t Imm = (intptr_t)MO.getImm(); Imm = Imm - MCE.getCurrentPCValue() - 4; emitConstant(Imm, X86II::getSizeOfImm(Desc->TSFlags)); } else emitConstant(MO.getImm(), X86II::getSizeOfImm(Desc->TSFlags)); break; } case X86II::AddRegFrm: { MCE.emitByte(BaseOpcode + X86_MC::getX86RegNum(MI.getOperand(CurOp++).getReg())); if (CurOp == NumOps) break; const MachineOperand &MO1 = MI.getOperand(CurOp++); unsigned Size = X86II::getSizeOfImm(Desc->TSFlags); if (MO1.isImm()) { emitConstant(MO1.getImm(), Size); break; } unsigned rt = Is64BitMode ? X86::reloc_pcrel_word : (IsPIC ? X86::reloc_picrel_word : X86::reloc_absolute_word); if (Opcode == X86::MOV64ri64i32) rt = X86::reloc_absolute_word; // FIXME: add X86II flag? // This should not occur on Darwin for relocatable objects. if (Opcode == X86::MOV64ri) rt = X86::reloc_absolute_dword; // FIXME: add X86II flag? if (MO1.isGlobal()) { bool Indirect = gvNeedsNonLazyPtr(MO1, TM); emitGlobalAddress(MO1.getGlobal(), rt, MO1.getOffset(), 0, Indirect); } else if (MO1.isSymbol()) emitExternalSymbolAddress(MO1.getSymbolName(), rt); else if (MO1.isCPI()) emitConstPoolAddress(MO1.getIndex(), rt); else if (MO1.isJTI()) emitJumpTableAddress(MO1.getIndex(), rt); break; } case X86II::MRMDestReg: { MCE.emitByte(BaseOpcode); emitRegModRMByte(MI.getOperand(CurOp).getReg(), X86_MC::getX86RegNum(MI.getOperand(CurOp+1).getReg())); CurOp += 2; if (CurOp != NumOps) emitConstant(MI.getOperand(CurOp++).getImm(), X86II::getSizeOfImm(Desc->TSFlags)); break; } case X86II::MRMDestMem: { MCE.emitByte(BaseOpcode); emitMemModRMByte(MI, CurOp, X86_MC::getX86RegNum(MI.getOperand(CurOp + X86::AddrNumOperands) .getReg())); CurOp += X86::AddrNumOperands + 1; if (CurOp != NumOps) emitConstant(MI.getOperand(CurOp++).getImm(), X86II::getSizeOfImm(Desc->TSFlags)); break; } case X86II::MRMSrcReg: MCE.emitByte(BaseOpcode); emitRegModRMByte(MI.getOperand(CurOp+1).getReg(), X86_MC::getX86RegNum(MI.getOperand(CurOp).getReg())); CurOp += 2; if (CurOp != NumOps) emitConstant(MI.getOperand(CurOp++).getImm(), X86II::getSizeOfImm(Desc->TSFlags)); break; case X86II::MRMSrcMem: { int AddrOperands = X86::AddrNumOperands; intptr_t PCAdj = (CurOp + AddrOperands + 1 != NumOps) ? X86II::getSizeOfImm(Desc->TSFlags) : 0; MCE.emitByte(BaseOpcode); emitMemModRMByte(MI, CurOp+1, X86_MC::getX86RegNum(MI.getOperand(CurOp).getReg()),PCAdj); CurOp += AddrOperands + 1; if (CurOp != NumOps) emitConstant(MI.getOperand(CurOp++).getImm(), X86II::getSizeOfImm(Desc->TSFlags)); break; } case X86II::MRM0r: case X86II::MRM1r: case X86II::MRM2r: case X86II::MRM3r: case X86II::MRM4r: case X86II::MRM5r: case X86II::MRM6r: case X86II::MRM7r: { MCE.emitByte(BaseOpcode); emitRegModRMByte(MI.getOperand(CurOp++).getReg(), (Desc->TSFlags & X86II::FormMask)-X86II::MRM0r); if (CurOp == NumOps) break; const MachineOperand &MO1 = MI.getOperand(CurOp++); unsigned Size = X86II::getSizeOfImm(Desc->TSFlags); if (MO1.isImm()) { emitConstant(MO1.getImm(), Size); break; } unsigned rt = Is64BitMode ? X86::reloc_pcrel_word : (IsPIC ? X86::reloc_picrel_word : X86::reloc_absolute_word); if (Opcode == X86::MOV64ri32) rt = X86::reloc_absolute_word_sext; // FIXME: add X86II flag? if (MO1.isGlobal()) { bool Indirect = gvNeedsNonLazyPtr(MO1, TM); emitGlobalAddress(MO1.getGlobal(), rt, MO1.getOffset(), 0, Indirect); } else if (MO1.isSymbol()) emitExternalSymbolAddress(MO1.getSymbolName(), rt); else if (MO1.isCPI()) emitConstPoolAddress(MO1.getIndex(), rt); else if (MO1.isJTI()) emitJumpTableAddress(MO1.getIndex(), rt); break; } case X86II::MRM0m: case X86II::MRM1m: case X86II::MRM2m: case X86II::MRM3m: case X86II::MRM4m: case X86II::MRM5m: case X86II::MRM6m: case X86II::MRM7m: { intptr_t PCAdj = (CurOp + X86::AddrNumOperands != NumOps) ? (MI.getOperand(CurOp+X86::AddrNumOperands).isImm() ? X86II::getSizeOfImm(Desc->TSFlags) : 4) : 0; MCE.emitByte(BaseOpcode); emitMemModRMByte(MI, CurOp, (Desc->TSFlags & X86II::FormMask)-X86II::MRM0m, PCAdj); CurOp += X86::AddrNumOperands; if (CurOp == NumOps) break; const MachineOperand &MO = MI.getOperand(CurOp++); unsigned Size = X86II::getSizeOfImm(Desc->TSFlags); if (MO.isImm()) { emitConstant(MO.getImm(), Size); break; } unsigned rt = Is64BitMode ? X86::reloc_pcrel_word : (IsPIC ? X86::reloc_picrel_word : X86::reloc_absolute_word); if (Opcode == X86::MOV64mi32) rt = X86::reloc_absolute_word_sext; // FIXME: add X86II flag? if (MO.isGlobal()) { bool Indirect = gvNeedsNonLazyPtr(MO, TM); emitGlobalAddress(MO.getGlobal(), rt, MO.getOffset(), 0, Indirect); } else if (MO.isSymbol()) emitExternalSymbolAddress(MO.getSymbolName(), rt); else if (MO.isCPI()) emitConstPoolAddress(MO.getIndex(), rt); else if (MO.isJTI()) emitJumpTableAddress(MO.getIndex(), rt); break; } case X86II::MRMInitReg: MCE.emitByte(BaseOpcode); // Duplicate register, used by things like MOV8r0 (aka xor reg,reg). emitRegModRMByte(MI.getOperand(CurOp).getReg(), X86_MC::getX86RegNum(MI.getOperand(CurOp).getReg())); ++CurOp; break; case X86II::MRM_C1: MCE.emitByte(BaseOpcode); MCE.emitByte(0xC1); break; case X86II::MRM_C8: MCE.emitByte(BaseOpcode); MCE.emitByte(0xC8); break; case X86II::MRM_C9: MCE.emitByte(BaseOpcode); MCE.emitByte(0xC9); break; case X86II::MRM_E8: MCE.emitByte(BaseOpcode); MCE.emitByte(0xE8); break; case X86II::MRM_F0: MCE.emitByte(BaseOpcode); MCE.emitByte(0xF0); break; } if (!Desc->isVariadic() && CurOp != NumOps) { #ifndef NDEBUG dbgs() << "Cannot encode all operands of: " << MI << "\n"; #endif llvm_unreachable(0); } MCE.processDebugLoc(MI.getDebugLoc(), false); } Index: head/contrib/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- head/contrib/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp (revision 228378) +++ head/contrib/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp (revision 228379) @@ -1,2087 +1,2088 @@ //===- InstructionCombining.cpp - Combine multiple instructions -----------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // InstructionCombining - Combine instructions to form fewer, simple // instructions. This pass does not modify the CFG. This pass is where // algebraic simplification happens. // // This pass combines things like: // %Y = add i32 %X, 1 // %Z = add i32 %Y, 1 // into: // %Z = add i32 %X, 2 // // This is a simple worklist driven algorithm. // // This pass guarantees that the following canonicalizations are performed on // the program: // 1. If a binary operator has a constant operand, it is moved to the RHS // 2. Bitwise operators with constant operands are always grouped so that // shifts are performed first, then or's, then and's, then xor's. // 3. Compare instructions are converted from <,>,<=,>= to ==,!= if possible // 4. All cmp instructions on boolean values are replaced with logical ops // 5. add X, X is represented as (X*2) => (X << 1) // 6. Multiplies with a power-of-two constant argument are transformed into // shifts. // ... etc. // //===----------------------------------------------------------------------===// #define DEBUG_TYPE "instcombine" #include "llvm/Transforms/Scalar.h" #include "InstCombine.h" #include "llvm/IntrinsicInst.h" #include "llvm/Analysis/ConstantFolding.h" #include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Analysis/MemoryBuiltins.h" #include "llvm/Target/TargetData.h" #include "llvm/Transforms/Utils/Local.h" #include "llvm/Support/CFG.h" #include "llvm/Support/Debug.h" #include "llvm/Support/GetElementPtrTypeIterator.h" #include "llvm/Support/PatternMatch.h" #include "llvm/Support/ValueHandle.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringSwitch.h" #include "llvm-c/Initialization.h" #include #include using namespace llvm; using namespace llvm::PatternMatch; STATISTIC(NumCombined , "Number of insts combined"); STATISTIC(NumConstProp, "Number of constant folds"); STATISTIC(NumDeadInst , "Number of dead inst eliminated"); STATISTIC(NumSunkInst , "Number of instructions sunk"); STATISTIC(NumExpand, "Number of expansions"); STATISTIC(NumFactor , "Number of factorizations"); STATISTIC(NumReassoc , "Number of reassociations"); // Initialization Routines void llvm::initializeInstCombine(PassRegistry &Registry) { initializeInstCombinerPass(Registry); } void LLVMInitializeInstCombine(LLVMPassRegistryRef R) { initializeInstCombine(*unwrap(R)); } char InstCombiner::ID = 0; INITIALIZE_PASS(InstCombiner, "instcombine", "Combine redundant instructions", false, false) void InstCombiner::getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesCFG(); } /// ShouldChangeType - Return true if it is desirable to convert a computation /// from 'From' to 'To'. We don't want to convert from a legal to an illegal /// type for example, or from a smaller to a larger illegal type. bool InstCombiner::ShouldChangeType(Type *From, Type *To) const { assert(From->isIntegerTy() && To->isIntegerTy()); // If we don't have TD, we don't know if the source/dest are legal. if (!TD) return false; unsigned FromWidth = From->getPrimitiveSizeInBits(); unsigned ToWidth = To->getPrimitiveSizeInBits(); bool FromLegal = TD->isLegalInteger(FromWidth); bool ToLegal = TD->isLegalInteger(ToWidth); // If this is a legal integer from type, and the result would be an illegal // type, don't do the transformation. if (FromLegal && !ToLegal) return false; // Otherwise, if both are illegal, do not increase the size of the result. We // do allow things like i160 -> i64, but not i64 -> i160. if (!FromLegal && !ToLegal && ToWidth > FromWidth) return false; return true; } // Return true, if No Signed Wrap should be maintained for I. // The No Signed Wrap flag can be kept if the operation "B (I.getOpcode) C", // where both B and C should be ConstantInts, results in a constant that does // not overflow. This function only handles the Add and Sub opcodes. For // all other opcodes, the function conservatively returns false. static bool MaintainNoSignedWrap(BinaryOperator &I, Value *B, Value *C) { OverflowingBinaryOperator *OBO = dyn_cast(&I); if (!OBO || !OBO->hasNoSignedWrap()) { return false; } // We reason about Add and Sub Only. Instruction::BinaryOps Opcode = I.getOpcode(); if (Opcode != Instruction::Add && Opcode != Instruction::Sub) { return false; } ConstantInt *CB = dyn_cast(B); ConstantInt *CC = dyn_cast(C); if (!CB || !CC) { return false; } const APInt &BVal = CB->getValue(); const APInt &CVal = CC->getValue(); bool Overflow = false; if (Opcode == Instruction::Add) { BVal.sadd_ov(CVal, Overflow); } else { BVal.ssub_ov(CVal, Overflow); } return !Overflow; } /// SimplifyAssociativeOrCommutative - This performs a few simplifications for /// operators which are associative or commutative: // // Commutative operators: // // 1. Order operands such that they are listed from right (least complex) to // left (most complex). This puts constants before unary operators before // binary operators. // // Associative operators: // // 2. Transform: "(A op B) op C" ==> "A op (B op C)" if "B op C" simplifies. // 3. Transform: "A op (B op C)" ==> "(A op B) op C" if "A op B" simplifies. // // Associative and commutative operators: // // 4. Transform: "(A op B) op C" ==> "(C op A) op B" if "C op A" simplifies. // 5. Transform: "A op (B op C)" ==> "B op (C op A)" if "C op A" simplifies. // 6. Transform: "(A op C1) op (B op C2)" ==> "(A op B) op (C1 op C2)" // if C1 and C2 are constants. // bool InstCombiner::SimplifyAssociativeOrCommutative(BinaryOperator &I) { Instruction::BinaryOps Opcode = I.getOpcode(); bool Changed = false; do { // Order operands such that they are listed from right (least complex) to // left (most complex). This puts constants before unary operators before // binary operators. if (I.isCommutative() && getComplexity(I.getOperand(0)) < getComplexity(I.getOperand(1))) Changed = !I.swapOperands(); BinaryOperator *Op0 = dyn_cast(I.getOperand(0)); BinaryOperator *Op1 = dyn_cast(I.getOperand(1)); if (I.isAssociative()) { // Transform: "(A op B) op C" ==> "A op (B op C)" if "B op C" simplifies. if (Op0 && Op0->getOpcode() == Opcode) { Value *A = Op0->getOperand(0); Value *B = Op0->getOperand(1); Value *C = I.getOperand(1); // Does "B op C" simplify? if (Value *V = SimplifyBinOp(Opcode, B, C, TD)) { // It simplifies to V. Form "A op V". I.setOperand(0, A); I.setOperand(1, V); // Conservatively clear the optional flags, since they may not be // preserved by the reassociation. if (MaintainNoSignedWrap(I, B, C) && (!Op0 || (isa(Op0) && Op0->hasNoSignedWrap()))) { // Note: this is only valid because SimplifyBinOp doesn't look at // the operands to Op0. I.clearSubclassOptionalData(); I.setHasNoSignedWrap(true); } else { I.clearSubclassOptionalData(); } Changed = true; ++NumReassoc; continue; } } // Transform: "A op (B op C)" ==> "(A op B) op C" if "A op B" simplifies. if (Op1 && Op1->getOpcode() == Opcode) { Value *A = I.getOperand(0); Value *B = Op1->getOperand(0); Value *C = Op1->getOperand(1); // Does "A op B" simplify? if (Value *V = SimplifyBinOp(Opcode, A, B, TD)) { // It simplifies to V. Form "V op C". I.setOperand(0, V); I.setOperand(1, C); // Conservatively clear the optional flags, since they may not be // preserved by the reassociation. I.clearSubclassOptionalData(); Changed = true; ++NumReassoc; continue; } } } if (I.isAssociative() && I.isCommutative()) { // Transform: "(A op B) op C" ==> "(C op A) op B" if "C op A" simplifies. if (Op0 && Op0->getOpcode() == Opcode) { Value *A = Op0->getOperand(0); Value *B = Op0->getOperand(1); Value *C = I.getOperand(1); // Does "C op A" simplify? if (Value *V = SimplifyBinOp(Opcode, C, A, TD)) { // It simplifies to V. Form "V op B". I.setOperand(0, V); I.setOperand(1, B); // Conservatively clear the optional flags, since they may not be // preserved by the reassociation. I.clearSubclassOptionalData(); Changed = true; ++NumReassoc; continue; } } // Transform: "A op (B op C)" ==> "B op (C op A)" if "C op A" simplifies. if (Op1 && Op1->getOpcode() == Opcode) { Value *A = I.getOperand(0); Value *B = Op1->getOperand(0); Value *C = Op1->getOperand(1); // Does "C op A" simplify? if (Value *V = SimplifyBinOp(Opcode, C, A, TD)) { // It simplifies to V. Form "B op V". I.setOperand(0, B); I.setOperand(1, V); // Conservatively clear the optional flags, since they may not be // preserved by the reassociation. I.clearSubclassOptionalData(); Changed = true; ++NumReassoc; continue; } } // Transform: "(A op C1) op (B op C2)" ==> "(A op B) op (C1 op C2)" // if C1 and C2 are constants. if (Op0 && Op1 && Op0->getOpcode() == Opcode && Op1->getOpcode() == Opcode && isa(Op0->getOperand(1)) && isa(Op1->getOperand(1)) && Op0->hasOneUse() && Op1->hasOneUse()) { Value *A = Op0->getOperand(0); Constant *C1 = cast(Op0->getOperand(1)); Value *B = Op1->getOperand(0); Constant *C2 = cast(Op1->getOperand(1)); Constant *Folded = ConstantExpr::get(Opcode, C1, C2); BinaryOperator *New = BinaryOperator::Create(Opcode, A, B); InsertNewInstWith(New, I); New->takeName(Op1); I.setOperand(0, New); I.setOperand(1, Folded); // Conservatively clear the optional flags, since they may not be // preserved by the reassociation. I.clearSubclassOptionalData(); Changed = true; continue; } } // No further simplifications. return Changed; } while (1); } /// LeftDistributesOverRight - Whether "X LOp (Y ROp Z)" is always equal to /// "(X LOp Y) ROp (X LOp Z)". static bool LeftDistributesOverRight(Instruction::BinaryOps LOp, Instruction::BinaryOps ROp) { switch (LOp) { default: return false; case Instruction::And: // And distributes over Or and Xor. switch (ROp) { default: return false; case Instruction::Or: case Instruction::Xor: return true; } case Instruction::Mul: // Multiplication distributes over addition and subtraction. switch (ROp) { default: return false; case Instruction::Add: case Instruction::Sub: return true; } case Instruction::Or: // Or distributes over And. switch (ROp) { default: return false; case Instruction::And: return true; } } } /// RightDistributesOverLeft - Whether "(X LOp Y) ROp Z" is always equal to /// "(X ROp Z) LOp (Y ROp Z)". static bool RightDistributesOverLeft(Instruction::BinaryOps LOp, Instruction::BinaryOps ROp) { if (Instruction::isCommutative(ROp)) return LeftDistributesOverRight(ROp, LOp); // TODO: It would be nice to handle division, aka "(X + Y)/Z = X/Z + Y/Z", // but this requires knowing that the addition does not overflow and other // such subtleties. return false; } /// SimplifyUsingDistributiveLaws - This tries to simplify binary operations /// which some other binary operation distributes over either by factorizing /// out common terms (eg "(A*B)+(A*C)" -> "A*(B+C)") or expanding out if this /// results in simplifications (eg: "A & (B | C) -> (A&B) | (A&C)" if this is /// a win). Returns the simplified value, or null if it didn't simplify. Value *InstCombiner::SimplifyUsingDistributiveLaws(BinaryOperator &I) { Value *LHS = I.getOperand(0), *RHS = I.getOperand(1); BinaryOperator *Op0 = dyn_cast(LHS); BinaryOperator *Op1 = dyn_cast(RHS); Instruction::BinaryOps TopLevelOpcode = I.getOpcode(); // op // Factorization. if (Op0 && Op1 && Op0->getOpcode() == Op1->getOpcode()) { // The instruction has the form "(A op' B) op (C op' D)". Try to factorize // a common term. Value *A = Op0->getOperand(0), *B = Op0->getOperand(1); Value *C = Op1->getOperand(0), *D = Op1->getOperand(1); Instruction::BinaryOps InnerOpcode = Op0->getOpcode(); // op' // Does "X op' Y" always equal "Y op' X"? bool InnerCommutative = Instruction::isCommutative(InnerOpcode); // Does "X op' (Y op Z)" always equal "(X op' Y) op (X op' Z)"? if (LeftDistributesOverRight(InnerOpcode, TopLevelOpcode)) // Does the instruction have the form "(A op' B) op (A op' D)" or, in the // commutative case, "(A op' B) op (C op' A)"? if (A == C || (InnerCommutative && A == D)) { if (A != C) std::swap(C, D); // Consider forming "A op' (B op D)". // If "B op D" simplifies then it can be formed with no cost. Value *V = SimplifyBinOp(TopLevelOpcode, B, D, TD); // If "B op D" doesn't simplify then only go on if both of the existing // operations "A op' B" and "C op' D" will be zapped as no longer used. if (!V && Op0->hasOneUse() && Op1->hasOneUse()) V = Builder->CreateBinOp(TopLevelOpcode, B, D, Op1->getName()); if (V) { ++NumFactor; V = Builder->CreateBinOp(InnerOpcode, A, V); V->takeName(&I); return V; } } // Does "(X op Y) op' Z" always equal "(X op' Z) op (Y op' Z)"? if (RightDistributesOverLeft(TopLevelOpcode, InnerOpcode)) // Does the instruction have the form "(A op' B) op (C op' B)" or, in the // commutative case, "(A op' B) op (B op' D)"? if (B == D || (InnerCommutative && B == C)) { if (B != D) std::swap(C, D); // Consider forming "(A op C) op' B". // If "A op C" simplifies then it can be formed with no cost. Value *V = SimplifyBinOp(TopLevelOpcode, A, C, TD); // If "A op C" doesn't simplify then only go on if both of the existing // operations "A op' B" and "C op' D" will be zapped as no longer used. if (!V && Op0->hasOneUse() && Op1->hasOneUse()) V = Builder->CreateBinOp(TopLevelOpcode, A, C, Op0->getName()); if (V) { ++NumFactor; V = Builder->CreateBinOp(InnerOpcode, V, B); V->takeName(&I); return V; } } } // Expansion. if (Op0 && RightDistributesOverLeft(Op0->getOpcode(), TopLevelOpcode)) { // The instruction has the form "(A op' B) op C". See if expanding it out // to "(A op C) op' (B op C)" results in simplifications. Value *A = Op0->getOperand(0), *B = Op0->getOperand(1), *C = RHS; Instruction::BinaryOps InnerOpcode = Op0->getOpcode(); // op' // Do "A op C" and "B op C" both simplify? if (Value *L = SimplifyBinOp(TopLevelOpcode, A, C, TD)) if (Value *R = SimplifyBinOp(TopLevelOpcode, B, C, TD)) { // They do! Return "L op' R". ++NumExpand; // If "L op' R" equals "A op' B" then "L op' R" is just the LHS. if ((L == A && R == B) || (Instruction::isCommutative(InnerOpcode) && L == B && R == A)) return Op0; // Otherwise return "L op' R" if it simplifies. if (Value *V = SimplifyBinOp(InnerOpcode, L, R, TD)) return V; // Otherwise, create a new instruction. C = Builder->CreateBinOp(InnerOpcode, L, R); C->takeName(&I); return C; } } if (Op1 && LeftDistributesOverRight(TopLevelOpcode, Op1->getOpcode())) { // The instruction has the form "A op (B op' C)". See if expanding it out // to "(A op B) op' (A op C)" results in simplifications. Value *A = LHS, *B = Op1->getOperand(0), *C = Op1->getOperand(1); Instruction::BinaryOps InnerOpcode = Op1->getOpcode(); // op' // Do "A op B" and "A op C" both simplify? if (Value *L = SimplifyBinOp(TopLevelOpcode, A, B, TD)) if (Value *R = SimplifyBinOp(TopLevelOpcode, A, C, TD)) { // They do! Return "L op' R". ++NumExpand; // If "L op' R" equals "B op' C" then "L op' R" is just the RHS. if ((L == B && R == C) || (Instruction::isCommutative(InnerOpcode) && L == C && R == B)) return Op1; // Otherwise return "L op' R" if it simplifies. if (Value *V = SimplifyBinOp(InnerOpcode, L, R, TD)) return V; // Otherwise, create a new instruction. A = Builder->CreateBinOp(InnerOpcode, L, R); A->takeName(&I); return A; } } return 0; } // dyn_castNegVal - Given a 'sub' instruction, return the RHS of the instruction // if the LHS is a constant zero (which is the 'negate' form). // Value *InstCombiner::dyn_castNegVal(Value *V) const { if (BinaryOperator::isNeg(V)) return BinaryOperator::getNegArgument(V); // Constants can be considered to be negated values if they can be folded. if (ConstantInt *C = dyn_cast(V)) return ConstantExpr::getNeg(C); if (ConstantVector *C = dyn_cast(V)) if (C->getType()->getElementType()->isIntegerTy()) return ConstantExpr::getNeg(C); return 0; } // dyn_castFNegVal - Given a 'fsub' instruction, return the RHS of the // instruction if the LHS is a constant negative zero (which is the 'negate' // form). // Value *InstCombiner::dyn_castFNegVal(Value *V) const { if (BinaryOperator::isFNeg(V)) return BinaryOperator::getFNegArgument(V); // Constants can be considered to be negated values if they can be folded. if (ConstantFP *C = dyn_cast(V)) return ConstantExpr::getFNeg(C); if (ConstantVector *C = dyn_cast(V)) if (C->getType()->getElementType()->isFloatingPointTy()) return ConstantExpr::getFNeg(C); return 0; } static Value *FoldOperationIntoSelectOperand(Instruction &I, Value *SO, InstCombiner *IC) { if (CastInst *CI = dyn_cast(&I)) { return IC->Builder->CreateCast(CI->getOpcode(), SO, I.getType()); } // Figure out if the constant is the left or the right argument. bool ConstIsRHS = isa(I.getOperand(1)); Constant *ConstOperand = cast(I.getOperand(ConstIsRHS)); if (Constant *SOC = dyn_cast(SO)) { if (ConstIsRHS) return ConstantExpr::get(I.getOpcode(), SOC, ConstOperand); return ConstantExpr::get(I.getOpcode(), ConstOperand, SOC); } Value *Op0 = SO, *Op1 = ConstOperand; if (!ConstIsRHS) std::swap(Op0, Op1); if (BinaryOperator *BO = dyn_cast(&I)) return IC->Builder->CreateBinOp(BO->getOpcode(), Op0, Op1, SO->getName()+".op"); if (ICmpInst *CI = dyn_cast(&I)) return IC->Builder->CreateICmp(CI->getPredicate(), Op0, Op1, SO->getName()+".cmp"); if (FCmpInst *CI = dyn_cast(&I)) return IC->Builder->CreateICmp(CI->getPredicate(), Op0, Op1, SO->getName()+".cmp"); llvm_unreachable("Unknown binary instruction type!"); } // FoldOpIntoSelect - Given an instruction with a select as one operand and a // constant as the other operand, try to fold the binary operator into the // select arguments. This also works for Cast instructions, which obviously do // not have a second operand. Instruction *InstCombiner::FoldOpIntoSelect(Instruction &Op, SelectInst *SI) { // Don't modify shared select instructions if (!SI->hasOneUse()) return 0; Value *TV = SI->getOperand(1); Value *FV = SI->getOperand(2); if (isa(TV) || isa(FV)) { // Bool selects with constant operands can be folded to logical ops. if (SI->getType()->isIntegerTy(1)) return 0; // If it's a bitcast involving vectors, make sure it has the same number of // elements on both sides. if (BitCastInst *BC = dyn_cast(&Op)) { VectorType *DestTy = dyn_cast(BC->getDestTy()); VectorType *SrcTy = dyn_cast(BC->getSrcTy()); // Verify that either both or neither are vectors. if ((SrcTy == NULL) != (DestTy == NULL)) return 0; // If vectors, verify that they have the same number of elements. if (SrcTy && SrcTy->getNumElements() != DestTy->getNumElements()) return 0; } Value *SelectTrueVal = FoldOperationIntoSelectOperand(Op, TV, this); Value *SelectFalseVal = FoldOperationIntoSelectOperand(Op, FV, this); return SelectInst::Create(SI->getCondition(), SelectTrueVal, SelectFalseVal); } return 0; } /// FoldOpIntoPhi - Given a binary operator, cast instruction, or select which /// has a PHI node as operand #0, see if we can fold the instruction into the /// PHI (which is only possible if all operands to the PHI are constants). /// Instruction *InstCombiner::FoldOpIntoPhi(Instruction &I) { PHINode *PN = cast(I.getOperand(0)); unsigned NumPHIValues = PN->getNumIncomingValues(); if (NumPHIValues == 0) return 0; // We normally only transform phis with a single use. However, if a PHI has // multiple uses and they are all the same operation, we can fold *all* of the // uses into the PHI. if (!PN->hasOneUse()) { // Walk the use list for the instruction, comparing them to I. for (Value::use_iterator UI = PN->use_begin(), E = PN->use_end(); UI != E; ++UI) { Instruction *User = cast(*UI); if (User != &I && !I.isIdenticalTo(User)) return 0; } // Otherwise, we can replace *all* users with the new PHI we form. } // Check to see if all of the operands of the PHI are simple constants // (constantint/constantfp/undef). If there is one non-constant value, // remember the BB it is in. If there is more than one or if *it* is a PHI, // bail out. We don't do arbitrary constant expressions here because moving // their computation can be expensive without a cost model. BasicBlock *NonConstBB = 0; for (unsigned i = 0; i != NumPHIValues; ++i) { Value *InVal = PN->getIncomingValue(i); if (isa(InVal) && !isa(InVal)) continue; if (isa(InVal)) return 0; // Itself a phi. if (NonConstBB) return 0; // More than one non-const value. NonConstBB = PN->getIncomingBlock(i); // If the InVal is an invoke at the end of the pred block, then we can't // insert a computation after it without breaking the edge. if (InvokeInst *II = dyn_cast(InVal)) if (II->getParent() == NonConstBB) return 0; // If the incoming non-constant value is in I's block, we will remove one // instruction, but insert another equivalent one, leading to infinite // instcombine. if (NonConstBB == I.getParent()) return 0; } // If there is exactly one non-constant value, we can insert a copy of the // operation in that block. However, if this is a critical edge, we would be // inserting the computation one some other paths (e.g. inside a loop). Only // do this if the pred block is unconditionally branching into the phi block. if (NonConstBB != 0) { BranchInst *BI = dyn_cast(NonConstBB->getTerminator()); if (!BI || !BI->isUnconditional()) return 0; } // Okay, we can do the transformation: create the new PHI node. PHINode *NewPN = PHINode::Create(I.getType(), PN->getNumIncomingValues()); InsertNewInstBefore(NewPN, *PN); NewPN->takeName(PN); // If we are going to have to insert a new computation, do so right before the // predecessors terminator. if (NonConstBB) Builder->SetInsertPoint(NonConstBB->getTerminator()); // Next, add all of the operands to the PHI. if (SelectInst *SI = dyn_cast(&I)) { // We only currently try to fold the condition of a select when it is a phi, // not the true/false values. Value *TrueV = SI->getTrueValue(); Value *FalseV = SI->getFalseValue(); BasicBlock *PhiTransBB = PN->getParent(); for (unsigned i = 0; i != NumPHIValues; ++i) { BasicBlock *ThisBB = PN->getIncomingBlock(i); Value *TrueVInPred = TrueV->DoPHITranslation(PhiTransBB, ThisBB); Value *FalseVInPred = FalseV->DoPHITranslation(PhiTransBB, ThisBB); Value *InV = 0; if (Constant *InC = dyn_cast(PN->getIncomingValue(i))) InV = InC->isNullValue() ? FalseVInPred : TrueVInPred; else InV = Builder->CreateSelect(PN->getIncomingValue(i), TrueVInPred, FalseVInPred, "phitmp"); NewPN->addIncoming(InV, ThisBB); } } else if (CmpInst *CI = dyn_cast(&I)) { Constant *C = cast(I.getOperand(1)); for (unsigned i = 0; i != NumPHIValues; ++i) { Value *InV = 0; if (Constant *InC = dyn_cast(PN->getIncomingValue(i))) InV = ConstantExpr::getCompare(CI->getPredicate(), InC, C); else if (isa(CI)) InV = Builder->CreateICmp(CI->getPredicate(), PN->getIncomingValue(i), C, "phitmp"); else InV = Builder->CreateFCmp(CI->getPredicate(), PN->getIncomingValue(i), C, "phitmp"); NewPN->addIncoming(InV, PN->getIncomingBlock(i)); } } else if (I.getNumOperands() == 2) { Constant *C = cast(I.getOperand(1)); for (unsigned i = 0; i != NumPHIValues; ++i) { Value *InV = 0; if (Constant *InC = dyn_cast(PN->getIncomingValue(i))) InV = ConstantExpr::get(I.getOpcode(), InC, C); else InV = Builder->CreateBinOp(cast(I).getOpcode(), PN->getIncomingValue(i), C, "phitmp"); NewPN->addIncoming(InV, PN->getIncomingBlock(i)); } } else { CastInst *CI = cast(&I); Type *RetTy = CI->getType(); for (unsigned i = 0; i != NumPHIValues; ++i) { Value *InV; if (Constant *InC = dyn_cast(PN->getIncomingValue(i))) InV = ConstantExpr::getCast(CI->getOpcode(), InC, RetTy); else InV = Builder->CreateCast(CI->getOpcode(), PN->getIncomingValue(i), I.getType(), "phitmp"); NewPN->addIncoming(InV, PN->getIncomingBlock(i)); } } for (Value::use_iterator UI = PN->use_begin(), E = PN->use_end(); UI != E; ) { Instruction *User = cast(*UI++); if (User == &I) continue; ReplaceInstUsesWith(*User, NewPN); EraseInstFromFunction(*User); } return ReplaceInstUsesWith(I, NewPN); } /// FindElementAtOffset - Given a type and a constant offset, determine whether /// or not there is a sequence of GEP indices into the type that will land us at /// the specified offset. If so, fill them into NewIndices and return the /// resultant element type, otherwise return null. Type *InstCombiner::FindElementAtOffset(Type *Ty, int64_t Offset, SmallVectorImpl &NewIndices) { if (!TD) return 0; if (!Ty->isSized()) return 0; // Start with the index over the outer type. Note that the type size // might be zero (even if the offset isn't zero) if the indexed type // is something like [0 x {int, int}] Type *IntPtrTy = TD->getIntPtrType(Ty->getContext()); int64_t FirstIdx = 0; if (int64_t TySize = TD->getTypeAllocSize(Ty)) { FirstIdx = Offset/TySize; Offset -= FirstIdx*TySize; // Handle hosts where % returns negative instead of values [0..TySize). if (Offset < 0) { --FirstIdx; Offset += TySize; assert(Offset >= 0); } assert((uint64_t)Offset < (uint64_t)TySize && "Out of range offset"); } NewIndices.push_back(ConstantInt::get(IntPtrTy, FirstIdx)); // Index into the types. If we fail, set OrigBase to null. while (Offset) { // Indexing into tail padding between struct/array elements. if (uint64_t(Offset*8) >= TD->getTypeSizeInBits(Ty)) return 0; if (StructType *STy = dyn_cast(Ty)) { const StructLayout *SL = TD->getStructLayout(STy); assert(Offset < (int64_t)SL->getSizeInBytes() && "Offset must stay within the indexed type"); unsigned Elt = SL->getElementContainingOffset(Offset); NewIndices.push_back(ConstantInt::get(Type::getInt32Ty(Ty->getContext()), Elt)); Offset -= SL->getElementOffset(Elt); Ty = STy->getElementType(Elt); } else if (ArrayType *AT = dyn_cast(Ty)) { uint64_t EltSize = TD->getTypeAllocSize(AT->getElementType()); assert(EltSize && "Cannot index into a zero-sized array"); NewIndices.push_back(ConstantInt::get(IntPtrTy,Offset/EltSize)); Offset %= EltSize; Ty = AT->getElementType(); } else { // Otherwise, we can't index into the middle of this atomic type, bail. return 0; } } return Ty; } static bool shouldMergeGEPs(GEPOperator &GEP, GEPOperator &Src) { // If this GEP has only 0 indices, it is the same pointer as // Src. If Src is not a trivial GEP too, don't combine // the indices. if (GEP.hasAllZeroIndices() && !Src.hasAllZeroIndices() && !Src.hasOneUse()) return false; return true; } Instruction *InstCombiner::visitGetElementPtrInst(GetElementPtrInst &GEP) { SmallVector Ops(GEP.op_begin(), GEP.op_end()); if (Value *V = SimplifyGEPInst(Ops, TD)) return ReplaceInstUsesWith(GEP, V); Value *PtrOp = GEP.getOperand(0); // Eliminate unneeded casts for indices, and replace indices which displace // by multiples of a zero size type with zero. if (TD) { bool MadeChange = false; Type *IntPtrTy = TD->getIntPtrType(GEP.getContext()); gep_type_iterator GTI = gep_type_begin(GEP); for (User::op_iterator I = GEP.op_begin() + 1, E = GEP.op_end(); I != E; ++I, ++GTI) { // Skip indices into struct types. SequentialType *SeqTy = dyn_cast(*GTI); if (!SeqTy) continue; // If the element type has zero size then any index over it is equivalent // to an index of zero, so replace it with zero if it is not zero already. if (SeqTy->getElementType()->isSized() && TD->getTypeAllocSize(SeqTy->getElementType()) == 0) if (!isa(*I) || !cast(*I)->isNullValue()) { *I = Constant::getNullValue(IntPtrTy); MadeChange = true; } if ((*I)->getType() != IntPtrTy) { // If we are using a wider index than needed for this platform, shrink // it to what we need. If narrower, sign-extend it to what we need. // This explicit cast can make subsequent optimizations more obvious. *I = Builder->CreateIntCast(*I, IntPtrTy, true); MadeChange = true; } } if (MadeChange) return &GEP; } // Combine Indices - If the source pointer to this getelementptr instruction // is a getelementptr instruction, combine the indices of the two // getelementptr instructions into a single instruction. // if (GEPOperator *Src = dyn_cast(PtrOp)) { if (!shouldMergeGEPs(*cast(&GEP), *Src)) return 0; // Note that if our source is a gep chain itself that we wait for that // chain to be resolved before we perform this transformation. This // avoids us creating a TON of code in some cases. if (GEPOperator *SrcGEP = dyn_cast(Src->getOperand(0))) if (SrcGEP->getNumOperands() == 2 && shouldMergeGEPs(*Src, *SrcGEP)) return 0; // Wait until our source is folded to completion. SmallVector Indices; // Find out whether the last index in the source GEP is a sequential idx. bool EndsWithSequential = false; for (gep_type_iterator I = gep_type_begin(*Src), E = gep_type_end(*Src); I != E; ++I) EndsWithSequential = !(*I)->isStructTy(); // Can we combine the two pointer arithmetics offsets? if (EndsWithSequential) { // Replace: gep (gep %P, long B), long A, ... // With: T = long A+B; gep %P, T, ... // Value *Sum; Value *SO1 = Src->getOperand(Src->getNumOperands()-1); Value *GO1 = GEP.getOperand(1); if (SO1 == Constant::getNullValue(SO1->getType())) { Sum = GO1; } else if (GO1 == Constant::getNullValue(GO1->getType())) { Sum = SO1; } else { // If they aren't the same type, then the input hasn't been processed // by the loop above yet (which canonicalizes sequential index types to // intptr_t). Just avoid transforming this until the input has been // normalized. if (SO1->getType() != GO1->getType()) return 0; Sum = Builder->CreateAdd(SO1, GO1, PtrOp->getName()+".sum"); } // Update the GEP in place if possible. if (Src->getNumOperands() == 2) { GEP.setOperand(0, Src->getOperand(0)); GEP.setOperand(1, Sum); return &GEP; } Indices.append(Src->op_begin()+1, Src->op_end()-1); Indices.push_back(Sum); Indices.append(GEP.op_begin()+2, GEP.op_end()); } else if (isa(*GEP.idx_begin()) && cast(*GEP.idx_begin())->isNullValue() && Src->getNumOperands() != 1) { // Otherwise we can do the fold if the first index of the GEP is a zero Indices.append(Src->op_begin()+1, Src->op_end()); Indices.append(GEP.idx_begin()+1, GEP.idx_end()); } if (!Indices.empty()) return (GEP.isInBounds() && Src->isInBounds()) ? GetElementPtrInst::CreateInBounds(Src->getOperand(0), Indices, GEP.getName()) : GetElementPtrInst::Create(Src->getOperand(0), Indices, GEP.getName()); } // Handle gep(bitcast x) and gep(gep x, 0, 0, 0). Value *StrippedPtr = PtrOp->stripPointerCasts(); PointerType *StrippedPtrTy =cast(StrippedPtr->getType()); if (StrippedPtr != PtrOp && StrippedPtrTy->getAddressSpace() == GEP.getPointerAddressSpace()) { bool HasZeroPointerIndex = false; if (ConstantInt *C = dyn_cast(GEP.getOperand(1))) HasZeroPointerIndex = C->isZero(); // Transform: GEP (bitcast [10 x i8]* X to [0 x i8]*), i32 0, ... // into : GEP [10 x i8]* X, i32 0, ... // // Likewise, transform: GEP (bitcast i8* X to [0 x i8]*), i32 0, ... // into : GEP i8* X, ... // // This occurs when the program declares an array extern like "int X[];" if (HasZeroPointerIndex) { PointerType *CPTy = cast(PtrOp->getType()); if (ArrayType *CATy = dyn_cast(CPTy->getElementType())) { // GEP (bitcast i8* X to [0 x i8]*), i32 0, ... ? if (CATy->getElementType() == StrippedPtrTy->getElementType()) { // -> GEP i8* X, ... SmallVector Idx(GEP.idx_begin()+1, GEP.idx_end()); GetElementPtrInst *Res = GetElementPtrInst::Create(StrippedPtr, Idx, GEP.getName()); Res->setIsInBounds(GEP.isInBounds()); return Res; } if (ArrayType *XATy = dyn_cast(StrippedPtrTy->getElementType())){ // GEP (bitcast [10 x i8]* X to [0 x i8]*), i32 0, ... ? if (CATy->getElementType() == XATy->getElementType()) { // -> GEP [10 x i8]* X, i32 0, ... // At this point, we know that the cast source type is a pointer // to an array of the same type as the destination pointer // array. Because the array type is never stepped over (there // is a leading zero) we can fold the cast into this GEP. GEP.setOperand(0, StrippedPtr); return &GEP; } } } } else if (GEP.getNumOperands() == 2) { // Transform things like: // %t = getelementptr i32* bitcast ([2 x i32]* %str to i32*), i32 %V // into: %t1 = getelementptr [2 x i32]* %str, i32 0, i32 %V; bitcast Type *SrcElTy = StrippedPtrTy->getElementType(); Type *ResElTy=cast(PtrOp->getType())->getElementType(); if (TD && SrcElTy->isArrayTy() && TD->getTypeAllocSize(cast(SrcElTy)->getElementType()) == TD->getTypeAllocSize(ResElTy)) { Value *Idx[2]; Idx[0] = Constant::getNullValue(Type::getInt32Ty(GEP.getContext())); Idx[1] = GEP.getOperand(1); Value *NewGEP = GEP.isInBounds() ? Builder->CreateInBoundsGEP(StrippedPtr, Idx, GEP.getName()) : Builder->CreateGEP(StrippedPtr, Idx, GEP.getName()); // V and GEP are both pointer types --> BitCast return new BitCastInst(NewGEP, GEP.getType()); } // Transform things like: // getelementptr i8* bitcast ([100 x double]* X to i8*), i32 %tmp // (where tmp = 8*tmp2) into: // getelementptr [100 x double]* %arr, i32 0, i32 %tmp2; bitcast if (TD && SrcElTy->isArrayTy() && ResElTy->isIntegerTy(8)) { uint64_t ArrayEltSize = TD->getTypeAllocSize(cast(SrcElTy)->getElementType()); // Check to see if "tmp" is a scale by a multiple of ArrayEltSize. We // allow either a mul, shift, or constant here. Value *NewIdx = 0; ConstantInt *Scale = 0; if (ArrayEltSize == 1) { NewIdx = GEP.getOperand(1); Scale = ConstantInt::get(cast(NewIdx->getType()), 1); } else if (ConstantInt *CI = dyn_cast(GEP.getOperand(1))) { NewIdx = ConstantInt::get(CI->getType(), 1); Scale = CI; } else if (Instruction *Inst =dyn_cast(GEP.getOperand(1))){ if (Inst->getOpcode() == Instruction::Shl && isa(Inst->getOperand(1))) { ConstantInt *ShAmt = cast(Inst->getOperand(1)); uint32_t ShAmtVal = ShAmt->getLimitedValue(64); Scale = ConstantInt::get(cast(Inst->getType()), 1ULL << ShAmtVal); NewIdx = Inst->getOperand(0); } else if (Inst->getOpcode() == Instruction::Mul && isa(Inst->getOperand(1))) { Scale = cast(Inst->getOperand(1)); NewIdx = Inst->getOperand(0); } } // If the index will be to exactly the right offset with the scale taken // out, perform the transformation. Note, we don't know whether Scale is // signed or not. We'll use unsigned version of division/modulo // operation after making sure Scale doesn't have the sign bit set. if (ArrayEltSize && Scale && Scale->getSExtValue() >= 0LL && Scale->getZExtValue() % ArrayEltSize == 0) { Scale = ConstantInt::get(Scale->getType(), Scale->getZExtValue() / ArrayEltSize); if (Scale->getZExtValue() != 1) { Constant *C = ConstantExpr::getIntegerCast(Scale, NewIdx->getType(), false /*ZExt*/); NewIdx = Builder->CreateMul(NewIdx, C, "idxscale"); } // Insert the new GEP instruction. Value *Idx[2]; Idx[0] = Constant::getNullValue(Type::getInt32Ty(GEP.getContext())); Idx[1] = NewIdx; Value *NewGEP = GEP.isInBounds() ? Builder->CreateInBoundsGEP(StrippedPtr, Idx, GEP.getName()): Builder->CreateGEP(StrippedPtr, Idx, GEP.getName()); // The NewGEP must be pointer typed, so must the old one -> BitCast return new BitCastInst(NewGEP, GEP.getType()); } } } } /// See if we can simplify: /// X = bitcast A* to B* /// Y = gep X, <...constant indices...> /// into a gep of the original struct. This is important for SROA and alias /// analysis of unions. If "A" is also a bitcast, wait for A/X to be merged. if (BitCastInst *BCI = dyn_cast(PtrOp)) { if (TD && !isa(BCI->getOperand(0)) && GEP.hasAllConstantIndices() && StrippedPtrTy->getAddressSpace() == GEP.getPointerAddressSpace()) { // Determine how much the GEP moves the pointer. We are guaranteed to get // a constant back from EmitGEPOffset. ConstantInt *OffsetV = cast(EmitGEPOffset(&GEP)); int64_t Offset = OffsetV->getSExtValue(); // If this GEP instruction doesn't move the pointer, just replace the GEP // with a bitcast of the real input to the dest type. if (Offset == 0) { // If the bitcast is of an allocation, and the allocation will be // converted to match the type of the cast, don't touch this. if (isa(BCI->getOperand(0)) || isMalloc(BCI->getOperand(0))) { // See if the bitcast simplifies, if so, don't nuke this GEP yet. if (Instruction *I = visitBitCast(*BCI)) { if (I != BCI) { I->takeName(BCI); BCI->getParent()->getInstList().insert(BCI, I); ReplaceInstUsesWith(*BCI, I); } return &GEP; } } return new BitCastInst(BCI->getOperand(0), GEP.getType()); } // Otherwise, if the offset is non-zero, we need to find out if there is a // field at Offset in 'A's type. If so, we can pull the cast through the // GEP. SmallVector NewIndices; Type *InTy = cast(BCI->getOperand(0)->getType())->getElementType(); if (FindElementAtOffset(InTy, Offset, NewIndices)) { Value *NGEP = GEP.isInBounds() ? Builder->CreateInBoundsGEP(BCI->getOperand(0), NewIndices) : Builder->CreateGEP(BCI->getOperand(0), NewIndices); if (NGEP->getType() == GEP.getType()) return ReplaceInstUsesWith(GEP, NGEP); NGEP->takeName(&GEP); return new BitCastInst(NGEP, GEP.getType()); } } } return 0; } static bool IsOnlyNullComparedAndFreed(Value *V, SmallVectorImpl &Users, int Depth = 0) { if (Depth == 8) return false; for (Value::use_iterator UI = V->use_begin(), UE = V->use_end(); UI != UE; ++UI) { User *U = *UI; if (isFreeCall(U)) { Users.push_back(U); continue; } if (ICmpInst *ICI = dyn_cast(U)) { if (ICI->isEquality() && isa(ICI->getOperand(1))) { Users.push_back(ICI); continue; } } if (BitCastInst *BCI = dyn_cast(U)) { if (IsOnlyNullComparedAndFreed(BCI, Users, Depth+1)) { Users.push_back(BCI); continue; } } if (GetElementPtrInst *GEPI = dyn_cast(U)) { if (IsOnlyNullComparedAndFreed(GEPI, Users, Depth+1)) { Users.push_back(GEPI); continue; } } if (IntrinsicInst *II = dyn_cast(U)) { if (II->getIntrinsicID() == Intrinsic::lifetime_start || II->getIntrinsicID() == Intrinsic::lifetime_end) { Users.push_back(II); continue; } } return false; } return true; } Instruction *InstCombiner::visitMalloc(Instruction &MI) { // If we have a malloc call which is only used in any amount of comparisons // to null and free calls, delete the calls and replace the comparisons with // true or false as appropriate. SmallVector Users; if (IsOnlyNullComparedAndFreed(&MI, Users)) { for (unsigned i = 0, e = Users.size(); i != e; ++i) { Instruction *I = cast_or_null(&*Users[i]); if (!I) continue; if (ICmpInst *C = dyn_cast(I)) { ReplaceInstUsesWith(*C, ConstantInt::get(Type::getInt1Ty(C->getContext()), C->isFalseWhenEqual())); } else if (isa(I) || isa(I)) { ReplaceInstUsesWith(*I, UndefValue::get(I->getType())); } EraseInstFromFunction(*I); } return EraseInstFromFunction(MI); } return 0; } Instruction *InstCombiner::visitFree(CallInst &FI) { Value *Op = FI.getArgOperand(0); // free undef -> unreachable. if (isa(Op)) { // Insert a new store to null because we cannot modify the CFG here. Builder->CreateStore(ConstantInt::getTrue(FI.getContext()), UndefValue::get(Type::getInt1PtrTy(FI.getContext()))); return EraseInstFromFunction(FI); } // If we have 'free null' delete the instruction. This can happen in stl code // when lots of inlining happens. if (isa(Op)) return EraseInstFromFunction(FI); return 0; } Instruction *InstCombiner::visitBranchInst(BranchInst &BI) { // Change br (not X), label True, label False to: br X, label False, True Value *X = 0; BasicBlock *TrueDest; BasicBlock *FalseDest; if (match(&BI, m_Br(m_Not(m_Value(X)), TrueDest, FalseDest)) && !isa(X)) { // Swap Destinations and condition... BI.setCondition(X); BI.swapSuccessors(); return &BI; } // Cannonicalize fcmp_one -> fcmp_oeq FCmpInst::Predicate FPred; Value *Y; if (match(&BI, m_Br(m_FCmp(FPred, m_Value(X), m_Value(Y)), TrueDest, FalseDest)) && BI.getCondition()->hasOneUse()) if (FPred == FCmpInst::FCMP_ONE || FPred == FCmpInst::FCMP_OLE || FPred == FCmpInst::FCMP_OGE) { FCmpInst *Cond = cast(BI.getCondition()); Cond->setPredicate(FCmpInst::getInversePredicate(FPred)); // Swap Destinations and condition. BI.swapSuccessors(); Worklist.Add(Cond); return &BI; } // Cannonicalize icmp_ne -> icmp_eq ICmpInst::Predicate IPred; if (match(&BI, m_Br(m_ICmp(IPred, m_Value(X), m_Value(Y)), TrueDest, FalseDest)) && BI.getCondition()->hasOneUse()) if (IPred == ICmpInst::ICMP_NE || IPred == ICmpInst::ICMP_ULE || IPred == ICmpInst::ICMP_SLE || IPred == ICmpInst::ICMP_UGE || IPred == ICmpInst::ICMP_SGE) { ICmpInst *Cond = cast(BI.getCondition()); Cond->setPredicate(ICmpInst::getInversePredicate(IPred)); // Swap Destinations and condition. BI.swapSuccessors(); Worklist.Add(Cond); return &BI; } return 0; } Instruction *InstCombiner::visitSwitchInst(SwitchInst &SI) { Value *Cond = SI.getCondition(); if (Instruction *I = dyn_cast(Cond)) { if (I->getOpcode() == Instruction::Add) if (ConstantInt *AddRHS = dyn_cast(I->getOperand(1))) { // change 'switch (X+4) case 1:' into 'switch (X) case -3' unsigned NumCases = SI.getNumCases(); // Skip the first item since that's the default case. for (unsigned i = 1; i < NumCases; ++i) { ConstantInt* CaseVal = SI.getCaseValue(i); Constant* NewCaseVal = ConstantExpr::getSub(cast(CaseVal), AddRHS); assert(isa(NewCaseVal) && "Result of expression should be constant"); SI.setSuccessorValue(i, cast(NewCaseVal)); } SI.setCondition(I->getOperand(0)); Worklist.Add(I); return &SI; } } return 0; } Instruction *InstCombiner::visitExtractValueInst(ExtractValueInst &EV) { Value *Agg = EV.getAggregateOperand(); if (!EV.hasIndices()) return ReplaceInstUsesWith(EV, Agg); if (Constant *C = dyn_cast(Agg)) { if (isa(C)) return ReplaceInstUsesWith(EV, UndefValue::get(EV.getType())); if (isa(C)) return ReplaceInstUsesWith(EV, Constant::getNullValue(EV.getType())); if (isa(C) || isa(C)) { // Extract the element indexed by the first index out of the constant Value *V = C->getOperand(*EV.idx_begin()); if (EV.getNumIndices() > 1) // Extract the remaining indices out of the constant indexed by the // first index return ExtractValueInst::Create(V, EV.getIndices().slice(1)); else return ReplaceInstUsesWith(EV, V); } return 0; // Can't handle other constants } if (InsertValueInst *IV = dyn_cast(Agg)) { // We're extracting from an insertvalue instruction, compare the indices const unsigned *exti, *exte, *insi, *inse; for (exti = EV.idx_begin(), insi = IV->idx_begin(), exte = EV.idx_end(), inse = IV->idx_end(); exti != exte && insi != inse; ++exti, ++insi) { if (*insi != *exti) // The insert and extract both reference distinctly different elements. // This means the extract is not influenced by the insert, and we can // replace the aggregate operand of the extract with the aggregate // operand of the insert. i.e., replace // %I = insertvalue { i32, { i32 } } %A, { i32 } { i32 42 }, 1 // %E = extractvalue { i32, { i32 } } %I, 0 // with // %E = extractvalue { i32, { i32 } } %A, 0 return ExtractValueInst::Create(IV->getAggregateOperand(), EV.getIndices()); } if (exti == exte && insi == inse) // Both iterators are at the end: Index lists are identical. Replace // %B = insertvalue { i32, { i32 } } %A, i32 42, 1, 0 // %C = extractvalue { i32, { i32 } } %B, 1, 0 // with "i32 42" return ReplaceInstUsesWith(EV, IV->getInsertedValueOperand()); if (exti == exte) { // The extract list is a prefix of the insert list. i.e. replace // %I = insertvalue { i32, { i32 } } %A, i32 42, 1, 0 // %E = extractvalue { i32, { i32 } } %I, 1 // with // %X = extractvalue { i32, { i32 } } %A, 1 // %E = insertvalue { i32 } %X, i32 42, 0 // by switching the order of the insert and extract (though the // insertvalue should be left in, since it may have other uses). Value *NewEV = Builder->CreateExtractValue(IV->getAggregateOperand(), EV.getIndices()); return InsertValueInst::Create(NewEV, IV->getInsertedValueOperand(), makeArrayRef(insi, inse)); } if (insi == inse) // The insert list is a prefix of the extract list // We can simply remove the common indices from the extract and make it // operate on the inserted value instead of the insertvalue result. // i.e., replace // %I = insertvalue { i32, { i32 } } %A, { i32 } { i32 42 }, 1 // %E = extractvalue { i32, { i32 } } %I, 1, 0 // with // %E extractvalue { i32 } { i32 42 }, 0 return ExtractValueInst::Create(IV->getInsertedValueOperand(), makeArrayRef(exti, exte)); } if (IntrinsicInst *II = dyn_cast(Agg)) { // We're extracting from an intrinsic, see if we're the only user, which // allows us to simplify multiple result intrinsics to simpler things that // just get one value. if (II->hasOneUse()) { // Check if we're grabbing the overflow bit or the result of a 'with // overflow' intrinsic. If it's the latter we can remove the intrinsic // and replace it with a traditional binary instruction. switch (II->getIntrinsicID()) { case Intrinsic::uadd_with_overflow: case Intrinsic::sadd_with_overflow: if (*EV.idx_begin() == 0) { // Normal result. Value *LHS = II->getArgOperand(0), *RHS = II->getArgOperand(1); ReplaceInstUsesWith(*II, UndefValue::get(II->getType())); EraseInstFromFunction(*II); return BinaryOperator::CreateAdd(LHS, RHS); } // If the normal result of the add is dead, and the RHS is a constant, // we can transform this into a range comparison. // overflow = uadd a, -4 --> overflow = icmp ugt a, 3 if (II->getIntrinsicID() == Intrinsic::uadd_with_overflow) if (ConstantInt *CI = dyn_cast(II->getArgOperand(1))) return new ICmpInst(ICmpInst::ICMP_UGT, II->getArgOperand(0), ConstantExpr::getNot(CI)); break; case Intrinsic::usub_with_overflow: case Intrinsic::ssub_with_overflow: if (*EV.idx_begin() == 0) { // Normal result. Value *LHS = II->getArgOperand(0), *RHS = II->getArgOperand(1); ReplaceInstUsesWith(*II, UndefValue::get(II->getType())); EraseInstFromFunction(*II); return BinaryOperator::CreateSub(LHS, RHS); } break; case Intrinsic::umul_with_overflow: case Intrinsic::smul_with_overflow: if (*EV.idx_begin() == 0) { // Normal result. Value *LHS = II->getArgOperand(0), *RHS = II->getArgOperand(1); ReplaceInstUsesWith(*II, UndefValue::get(II->getType())); EraseInstFromFunction(*II); return BinaryOperator::CreateMul(LHS, RHS); } break; default: break; } } } if (LoadInst *L = dyn_cast(Agg)) // If the (non-volatile) load only has one use, we can rewrite this to a // load from a GEP. This reduces the size of the load. // FIXME: If a load is used only by extractvalue instructions then this // could be done regardless of having multiple uses. if (L->isSimple() && L->hasOneUse()) { // extractvalue has integer indices, getelementptr has Value*s. Convert. SmallVector Indices; // Prefix an i32 0 since we need the first element. Indices.push_back(Builder->getInt32(0)); for (ExtractValueInst::idx_iterator I = EV.idx_begin(), E = EV.idx_end(); I != E; ++I) Indices.push_back(Builder->getInt32(*I)); // We need to insert these at the location of the old load, not at that of // the extractvalue. Builder->SetInsertPoint(L->getParent(), L); Value *GEP = Builder->CreateInBoundsGEP(L->getPointerOperand(), Indices); // Returning the load directly will cause the main loop to insert it in // the wrong spot, so use ReplaceInstUsesWith(). return ReplaceInstUsesWith(EV, Builder->CreateLoad(GEP)); } // We could simplify extracts from other values. Note that nested extracts may // already be simplified implicitly by the above: extract (extract (insert) ) // will be translated into extract ( insert ( extract ) ) first and then just // the value inserted, if appropriate. Similarly for extracts from single-use // loads: extract (extract (load)) will be translated to extract (load (gep)) // and if again single-use then via load (gep (gep)) to load (gep). // However, double extracts from e.g. function arguments or return values // aren't handled yet. return 0; } enum Personality_Type { Unknown_Personality, GNU_Ada_Personality, GNU_CXX_Personality }; /// RecognizePersonality - See if the given exception handling personality /// function is one that we understand. If so, return a description of it; /// otherwise return Unknown_Personality. static Personality_Type RecognizePersonality(Value *Pers) { Function *F = dyn_cast(Pers->stripPointerCasts()); if (!F) return Unknown_Personality; return StringSwitch(F->getName()) .Case("__gnat_eh_personality", GNU_Ada_Personality) .Case("__gxx_personality_v0", GNU_CXX_Personality) .Default(Unknown_Personality); } /// isCatchAll - Return 'true' if the given typeinfo will match anything. static bool isCatchAll(Personality_Type Personality, Constant *TypeInfo) { switch (Personality) { case Unknown_Personality: return false; case GNU_Ada_Personality: // While __gnat_all_others_value will match any Ada exception, it doesn't // match foreign exceptions (or didn't, before gcc-4.7). return false; case GNU_CXX_Personality: return TypeInfo->isNullValue(); } llvm_unreachable("Unknown personality!"); } static bool shorter_filter(const Value *LHS, const Value *RHS) { return cast(LHS->getType())->getNumElements() < cast(RHS->getType())->getNumElements(); } Instruction *InstCombiner::visitLandingPadInst(LandingPadInst &LI) { // The logic here should be correct for any real-world personality function. // However if that turns out not to be true, the offending logic can always // be conditioned on the personality function, like the catch-all logic is. Personality_Type Personality = RecognizePersonality(LI.getPersonalityFn()); // Simplify the list of clauses, eg by removing repeated catch clauses // (these are often created by inlining). bool MakeNewInstruction = false; // If true, recreate using the following: SmallVector NewClauses; // - Clauses for the new instruction; bool CleanupFlag = LI.isCleanup(); // - The new instruction is a cleanup. SmallPtrSet AlreadyCaught; // Typeinfos known caught already. for (unsigned i = 0, e = LI.getNumClauses(); i != e; ++i) { bool isLastClause = i + 1 == e; if (LI.isCatch(i)) { // A catch clause. Value *CatchClause = LI.getClause(i); Constant *TypeInfo = cast(CatchClause->stripPointerCasts()); // If we already saw this clause, there is no point in having a second // copy of it. if (AlreadyCaught.insert(TypeInfo)) { // This catch clause was not already seen. NewClauses.push_back(CatchClause); } else { // Repeated catch clause - drop the redundant copy. MakeNewInstruction = true; } // If this is a catch-all then there is no point in keeping any following // clauses or marking the landingpad as having a cleanup. if (isCatchAll(Personality, TypeInfo)) { if (!isLastClause) MakeNewInstruction = true; CleanupFlag = false; break; } } else { // A filter clause. If any of the filter elements were already caught // then they can be dropped from the filter. It is tempting to try to // exploit the filter further by saying that any typeinfo that does not // occur in the filter can't be caught later (and thus can be dropped). // However this would be wrong, since typeinfos can match without being // equal (for example if one represents a C++ class, and the other some // class derived from it). assert(LI.isFilter(i) && "Unsupported landingpad clause!"); Value *FilterClause = LI.getClause(i); ArrayType *FilterType = cast(FilterClause->getType()); unsigned NumTypeInfos = FilterType->getNumElements(); // An empty filter catches everything, so there is no point in keeping any // following clauses or marking the landingpad as having a cleanup. By // dealing with this case here the following code is made a bit simpler. if (!NumTypeInfos) { NewClauses.push_back(FilterClause); if (!isLastClause) MakeNewInstruction = true; CleanupFlag = false; break; } bool MakeNewFilter = false; // If true, make a new filter. SmallVector NewFilterElts; // New elements. if (isa(FilterClause)) { // Not an empty filter - it contains at least one null typeinfo. assert(NumTypeInfos > 0 && "Should have handled empty filter already!"); Constant *TypeInfo = Constant::getNullValue(FilterType->getElementType()); // If this typeinfo is a catch-all then the filter can never match. if (isCatchAll(Personality, TypeInfo)) { // Throw the filter away. MakeNewInstruction = true; continue; } // There is no point in having multiple copies of this typeinfo, so // discard all but the first copy if there is more than one. NewFilterElts.push_back(TypeInfo); if (NumTypeInfos > 1) MakeNewFilter = true; } else { ConstantArray *Filter = cast(FilterClause); SmallPtrSet SeenInFilter; // For uniquing the elements. NewFilterElts.reserve(NumTypeInfos); // Remove any filter elements that were already caught or that already // occurred in the filter. While there, see if any of the elements are // catch-alls. If so, the filter can be discarded. bool SawCatchAll = false; for (unsigned j = 0; j != NumTypeInfos; ++j) { Value *Elt = Filter->getOperand(j); Constant *TypeInfo = cast(Elt->stripPointerCasts()); if (isCatchAll(Personality, TypeInfo)) { // This element is a catch-all. Bail out, noting this fact. SawCatchAll = true; break; } if (AlreadyCaught.count(TypeInfo)) // Already caught by an earlier clause, so having it in the filter // is pointless. continue; // There is no point in having multiple copies of the same typeinfo in // a filter, so only add it if we didn't already. if (SeenInFilter.insert(TypeInfo)) NewFilterElts.push_back(cast(Elt)); } // A filter containing a catch-all cannot match anything by definition. if (SawCatchAll) { // Throw the filter away. MakeNewInstruction = true; continue; } // If we dropped something from the filter, make a new one. if (NewFilterElts.size() < NumTypeInfos) MakeNewFilter = true; } if (MakeNewFilter) { FilterType = ArrayType::get(FilterType->getElementType(), NewFilterElts.size()); FilterClause = ConstantArray::get(FilterType, NewFilterElts); MakeNewInstruction = true; } NewClauses.push_back(FilterClause); // If the new filter is empty then it will catch everything so there is // no point in keeping any following clauses or marking the landingpad // as having a cleanup. The case of the original filter being empty was // already handled above. if (MakeNewFilter && !NewFilterElts.size()) { assert(MakeNewInstruction && "New filter but not a new instruction!"); CleanupFlag = false; break; } } } // If several filters occur in a row then reorder them so that the shortest // filters come first (those with the smallest number of elements). This is // advantageous because shorter filters are more likely to match, speeding up // unwinding, but mostly because it increases the effectiveness of the other // filter optimizations below. for (unsigned i = 0, e = NewClauses.size(); i + 1 < e; ) { unsigned j; // Find the maximal 'j' s.t. the range [i, j) consists entirely of filters. for (j = i; j != e; ++j) if (!isa(NewClauses[j]->getType())) break; // Check whether the filters are already sorted by length. We need to know // if sorting them is actually going to do anything so that we only make a // new landingpad instruction if it does. for (unsigned k = i; k + 1 < j; ++k) if (shorter_filter(NewClauses[k+1], NewClauses[k])) { // Not sorted, so sort the filters now. Doing an unstable sort would be // correct too but reordering filters pointlessly might confuse users. std::stable_sort(NewClauses.begin() + i, NewClauses.begin() + j, shorter_filter); MakeNewInstruction = true; break; } // Look for the next batch of filters. i = j + 1; } // If typeinfos matched if and only if equal, then the elements of a filter L // that occurs later than a filter F could be replaced by the intersection of // the elements of F and L. In reality two typeinfos can match without being // equal (for example if one represents a C++ class, and the other some class // derived from it) so it would be wrong to perform this transform in general. // However the transform is correct and useful if F is a subset of L. In that // case L can be replaced by F, and thus removed altogether since repeating a // filter is pointless. So here we look at all pairs of filters F and L where // L follows F in the list of clauses, and remove L if every element of F is // an element of L. This can occur when inlining C++ functions with exception // specifications. for (unsigned i = 0; i + 1 < NewClauses.size(); ++i) { // Examine each filter in turn. Value *Filter = NewClauses[i]; ArrayType *FTy = dyn_cast(Filter->getType()); if (!FTy) // Not a filter - skip it. continue; unsigned FElts = FTy->getNumElements(); // Examine each filter following this one. Doing this backwards means that // we don't have to worry about filters disappearing under us when removed. for (unsigned j = NewClauses.size() - 1; j != i; --j) { Value *LFilter = NewClauses[j]; ArrayType *LTy = dyn_cast(LFilter->getType()); if (!LTy) // Not a filter - skip it. continue; // If Filter is a subset of LFilter, i.e. every element of Filter is also // an element of LFilter, then discard LFilter. SmallVector::iterator J = NewClauses.begin() + j; // If Filter is empty then it is a subset of LFilter. if (!FElts) { // Discard LFilter. NewClauses.erase(J); MakeNewInstruction = true; // Move on to the next filter. continue; } unsigned LElts = LTy->getNumElements(); // If Filter is longer than LFilter then it cannot be a subset of it. if (FElts > LElts) // Move on to the next filter. continue; // At this point we know that LFilter has at least one element. if (isa(LFilter)) { // LFilter only contains zeros. // Filter is a subset of LFilter iff Filter contains only zeros (as we // already know that Filter is not longer than LFilter). if (isa(Filter)) { assert(FElts <= LElts && "Should have handled this case earlier!"); // Discard LFilter. NewClauses.erase(J); MakeNewInstruction = true; } // Move on to the next filter. continue; } ConstantArray *LArray = cast(LFilter); if (isa(Filter)) { // Filter only contains zeros. // Since Filter is non-empty and contains only zeros, it is a subset of // LFilter iff LFilter contains a zero. assert(FElts > 0 && "Should have eliminated the empty filter earlier!"); for (unsigned l = 0; l != LElts; ++l) if (LArray->getOperand(l)->isNullValue()) { // LFilter contains a zero - discard it. NewClauses.erase(J); MakeNewInstruction = true; break; } // Move on to the next filter. continue; } // At this point we know that both filters are ConstantArrays. Loop over // operands to see whether every element of Filter is also an element of // LFilter. Since filters tend to be short this is probably faster than // using a method that scales nicely. ConstantArray *FArray = cast(Filter); bool AllFound = true; for (unsigned f = 0; f != FElts; ++f) { Value *FTypeInfo = FArray->getOperand(f)->stripPointerCasts(); AllFound = false; for (unsigned l = 0; l != LElts; ++l) { Value *LTypeInfo = LArray->getOperand(l)->stripPointerCasts(); if (LTypeInfo == FTypeInfo) { AllFound = true; break; } } if (!AllFound) break; } if (AllFound) { // Discard LFilter. NewClauses.erase(J); MakeNewInstruction = true; } // Move on to the next filter. } } // If we changed any of the clauses, replace the old landingpad instruction // with a new one. if (MakeNewInstruction) { LandingPadInst *NLI = LandingPadInst::Create(LI.getType(), LI.getPersonalityFn(), NewClauses.size()); for (unsigned i = 0, e = NewClauses.size(); i != e; ++i) NLI->addClause(NewClauses[i]); // A landing pad with no clauses must have the cleanup flag set. It is // theoretically possible, though highly unlikely, that we eliminated all // clauses. If so, force the cleanup flag to true. if (NewClauses.empty()) CleanupFlag = true; NLI->setCleanup(CleanupFlag); return NLI; } // Even if none of the clauses changed, we may nonetheless have understood // that the cleanup flag is pointless. Clear it if so. if (LI.isCleanup() != CleanupFlag) { assert(!CleanupFlag && "Adding a cleanup, not removing one?!"); LI.setCleanup(CleanupFlag); return &LI; } return 0; } /// TryToSinkInstruction - Try to move the specified instruction from its /// current block into the beginning of DestBlock, which can only happen if it's /// safe to move the instruction past all of the instructions between it and the /// end of its block. static bool TryToSinkInstruction(Instruction *I, BasicBlock *DestBlock) { assert(I->hasOneUse() && "Invariants didn't hold!"); // Cannot move control-flow-involving, volatile loads, vaarg, etc. if (isa(I) || isa(I) || I->mayHaveSideEffects() || isa(I)) return false; // Do not sink alloca instructions out of the entry block. if (isa(I) && I->getParent() == &DestBlock->getParent()->getEntryBlock()) return false; // We can only sink load instructions if there is nothing between the load and // the end of block that could change the value. if (I->mayReadFromMemory()) { for (BasicBlock::iterator Scan = I, E = I->getParent()->end(); Scan != E; ++Scan) if (Scan->mayWriteToMemory()) return false; } BasicBlock::iterator InsertPos = DestBlock->getFirstInsertionPt(); I->moveBefore(InsertPos); ++NumSunkInst; return true; } /// AddReachableCodeToWorklist - Walk the function in depth-first order, adding /// all reachable code to the worklist. /// /// This has a couple of tricks to make the code faster and more powerful. In /// particular, we constant fold and DCE instructions as we go, to avoid adding /// them to the worklist (this significantly speeds up instcombine on code where /// many instructions are dead or constant). Additionally, if we find a branch /// whose condition is a known constant, we only visit the reachable successors. /// static bool AddReachableCodeToWorklist(BasicBlock *BB, SmallPtrSet &Visited, InstCombiner &IC, const TargetData *TD) { bool MadeIRChange = false; SmallVector Worklist; Worklist.push_back(BB); SmallVector InstrsForInstCombineWorklist; DenseMap FoldedConstants; do { BB = Worklist.pop_back_val(); // We have now visited this block! If we've already been here, ignore it. if (!Visited.insert(BB)) continue; for (BasicBlock::iterator BBI = BB->begin(), E = BB->end(); BBI != E; ) { Instruction *Inst = BBI++; // DCE instruction if trivially dead. if (isInstructionTriviallyDead(Inst)) { ++NumDeadInst; DEBUG(errs() << "IC: DCE: " << *Inst << '\n'); Inst->eraseFromParent(); continue; } // ConstantProp instruction if trivially constant. if (!Inst->use_empty() && isa(Inst->getOperand(0))) if (Constant *C = ConstantFoldInstruction(Inst, TD)) { DEBUG(errs() << "IC: ConstFold to: " << *C << " from: " << *Inst << '\n'); Inst->replaceAllUsesWith(C); ++NumConstProp; Inst->eraseFromParent(); continue; } if (TD) { // See if we can constant fold its operands. for (User::op_iterator i = Inst->op_begin(), e = Inst->op_end(); i != e; ++i) { ConstantExpr *CE = dyn_cast(i); if (CE == 0) continue; Constant*& FoldRes = FoldedConstants[CE]; if (!FoldRes) FoldRes = ConstantFoldConstantExpression(CE, TD); if (!FoldRes) FoldRes = CE; if (FoldRes != CE) { *i = FoldRes; MadeIRChange = true; } } } InstrsForInstCombineWorklist.push_back(Inst); } // Recursively visit successors. If this is a branch or switch on a // constant, only visit the reachable successor. TerminatorInst *TI = BB->getTerminator(); if (BranchInst *BI = dyn_cast(TI)) { if (BI->isConditional() && isa(BI->getCondition())) { bool CondVal = cast(BI->getCondition())->getZExtValue(); BasicBlock *ReachableBB = BI->getSuccessor(!CondVal); Worklist.push_back(ReachableBB); continue; } } else if (SwitchInst *SI = dyn_cast(TI)) { if (ConstantInt *Cond = dyn_cast(SI->getCondition())) { // See if this is an explicit destination. for (unsigned i = 1, e = SI->getNumSuccessors(); i != e; ++i) if (SI->getCaseValue(i) == Cond) { BasicBlock *ReachableBB = SI->getSuccessor(i); Worklist.push_back(ReachableBB); continue; } // Otherwise it is the default destination. Worklist.push_back(SI->getSuccessor(0)); continue; } } for (unsigned i = 0, e = TI->getNumSuccessors(); i != e; ++i) Worklist.push_back(TI->getSuccessor(i)); } while (!Worklist.empty()); // Once we've found all of the instructions to add to instcombine's worklist, // add them in reverse order. This way instcombine will visit from the top // of the function down. This jives well with the way that it adds all uses // of instructions to the worklist after doing a transformation, thus avoiding // some N^2 behavior in pathological cases. IC.Worklist.AddInitialGroup(&InstrsForInstCombineWorklist[0], InstrsForInstCombineWorklist.size()); return MadeIRChange; } bool InstCombiner::DoOneIteration(Function &F, unsigned Iteration) { MadeIRChange = false; DEBUG(errs() << "\n\nINSTCOMBINE ITERATION #" << Iteration << " on " << F.getNameStr() << "\n"); { // Do a depth-first traversal of the function, populate the worklist with // the reachable instructions. Ignore blocks that are not reachable. Keep // track of which blocks we visit. SmallPtrSet Visited; MadeIRChange |= AddReachableCodeToWorklist(F.begin(), Visited, *this, TD); // Do a quick scan over the function. If we find any blocks that are // unreachable, remove any instructions inside of them. This prevents // the instcombine code from having to deal with some bad special cases. for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) { if (Visited.count(BB)) continue; // Delete the instructions backwards, as it has a reduced likelihood of // having to update as many def-use and use-def chains. Instruction *EndInst = BB->getTerminator(); // Last not to be deleted. while (EndInst != BB->begin()) { // Delete the next to last instruction. BasicBlock::iterator I = EndInst; Instruction *Inst = --I; if (!Inst->use_empty()) Inst->replaceAllUsesWith(UndefValue::get(Inst->getType())); if (isa(Inst)) { EndInst = Inst; continue; } if (!isa(Inst)) { ++NumDeadInst; MadeIRChange = true; } Inst->eraseFromParent(); } } } while (!Worklist.isEmpty()) { Instruction *I = Worklist.RemoveOne(); if (I == 0) continue; // skip null values. // Check to see if we can DCE the instruction. if (isInstructionTriviallyDead(I)) { DEBUG(errs() << "IC: DCE: " << *I << '\n'); EraseInstFromFunction(*I); ++NumDeadInst; MadeIRChange = true; continue; } // Instruction isn't dead, see if we can constant propagate it. if (!I->use_empty() && isa(I->getOperand(0))) if (Constant *C = ConstantFoldInstruction(I, TD)) { DEBUG(errs() << "IC: ConstFold to: " << *C << " from: " << *I << '\n'); // Add operands to the worklist. ReplaceInstUsesWith(*I, C); ++NumConstProp; EraseInstFromFunction(*I); MadeIRChange = true; continue; } // See if we can trivially sink this instruction to a successor basic block. if (I->hasOneUse()) { BasicBlock *BB = I->getParent(); Instruction *UserInst = cast(I->use_back()); BasicBlock *UserParent; // Get the block the use occurs in. if (PHINode *PN = dyn_cast(UserInst)) UserParent = PN->getIncomingBlock(I->use_begin().getUse()); else UserParent = UserInst->getParent(); if (UserParent != BB) { bool UserIsSuccessor = false; // See if the user is one of our successors. for (succ_iterator SI = succ_begin(BB), E = succ_end(BB); SI != E; ++SI) if (*SI == UserParent) { UserIsSuccessor = true; break; } // If the user is one of our immediate successors, and if that successor // only has us as a predecessors (we'd have to split the critical edge // otherwise), we can keep going. if (UserIsSuccessor && UserParent->getSinglePredecessor()) // Okay, the CFG is simple enough, try to sink this instruction. MadeIRChange |= TryToSinkInstruction(I, UserParent); } } // Now that we have an instruction, try combining it to simplify it. Builder->SetInsertPoint(I->getParent(), I); Builder->SetCurrentDebugLocation(I->getDebugLoc()); #ifndef NDEBUG std::string OrigI; #endif DEBUG(raw_string_ostream SS(OrigI); I->print(SS); OrigI = SS.str();); DEBUG(errs() << "IC: Visiting: " << OrigI << '\n'); if (Instruction *Result = visit(*I)) { ++NumCombined; // Should we replace the old instruction with a new one? if (Result != I) { DEBUG(errs() << "IC: Old = " << *I << '\n' << " New = " << *Result << '\n'); if (!I->getDebugLoc().isUnknown()) Result->setDebugLoc(I->getDebugLoc()); // Everything uses the new instruction now. I->replaceAllUsesWith(Result); // Move the name to the new instruction first. Result->takeName(I); // Push the new instruction and any users onto the worklist. Worklist.Add(Result); Worklist.AddUsersToWorkList(*Result); // Insert the new instruction into the basic block... BasicBlock *InstParent = I->getParent(); BasicBlock::iterator InsertPos = I; - if (!isa(Result)) // If combining a PHI, don't insert - while (isa(InsertPos)) // middle of a block of PHIs. - ++InsertPos; + // If we replace a PHI with something that isn't a PHI, fix up the + // insertion point. + if (!isa(Result) && isa(InsertPos)) + InsertPos = InstParent->getFirstInsertionPt(); InstParent->getInstList().insert(InsertPos, Result); EraseInstFromFunction(*I); } else { #ifndef NDEBUG DEBUG(errs() << "IC: Mod = " << OrigI << '\n' << " New = " << *I << '\n'); #endif // If the instruction was modified, it's possible that it is now dead. // if so, remove it. if (isInstructionTriviallyDead(I)) { EraseInstFromFunction(*I); } else { Worklist.Add(I); Worklist.AddUsersToWorkList(*I); } } MadeIRChange = true; } } Worklist.Zap(); return MadeIRChange; } bool InstCombiner::runOnFunction(Function &F) { TD = getAnalysisIfAvailable(); /// Builder - This is an IRBuilder that automatically inserts new /// instructions into the worklist when they are created. IRBuilder TheBuilder(F.getContext(), TargetFolder(TD), InstCombineIRInserter(Worklist)); Builder = &TheBuilder; bool EverMadeChange = false; // Lower dbg.declare intrinsics otherwise their value may be clobbered // by instcombiner. EverMadeChange = LowerDbgDeclare(F); // Iterate while there is work to do. unsigned Iteration = 0; while (DoOneIteration(F, Iteration++)) EverMadeChange = true; Builder = 0; return EverMadeChange; } FunctionPass *llvm::createInstructionCombiningPass() { return new InstCombiner(); } Index: head/contrib/llvm/tools/clang/include/clang/Driver/CC1Options.td =================================================================== --- head/contrib/llvm/tools/clang/include/clang/Driver/CC1Options.td (revision 228378) +++ head/contrib/llvm/tools/clang/include/clang/Driver/CC1Options.td (revision 228379) @@ -1,725 +1,736 @@ //===--- CC1Options.td - Options for clang -cc1 ---------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines the options accepted by clang -cc1. // //===----------------------------------------------------------------------===// // Include the common option parsing interfaces. include "OptParser.td" //===----------------------------------------------------------------------===// // Target Options //===----------------------------------------------------------------------===// def cxx_abi : Separate<"-cxx-abi">, HelpText<"Target a particular C++ ABI type">; def target_abi : Separate<"-target-abi">, HelpText<"Target a particular ABI type">; def target_cpu : Separate<"-target-cpu">, HelpText<"Target a specific cpu type">; def target_feature : Separate<"-target-feature">, HelpText<"Target specific attributes">; def target_linker_version : Separate<"-target-linker-version">, HelpText<"Target linker version">; def triple : Separate<"-triple">, HelpText<"Specify target triple (e.g. i686-apple-darwin9)">; def triple_EQ : Joined<"-triple=">, Alias; //===----------------------------------------------------------------------===// // Analyzer Options //===----------------------------------------------------------------------===// def analysis_UnoptimizedCFG : Flag<"-unoptimized-cfg">, HelpText<"Generate unoptimized CFGs for all analyses">; def analysis_CFGAddImplicitDtors : Flag<"-cfg-add-implicit-dtors">, HelpText<"Add C++ implicit destructors to CFGs for all analyses">; def analysis_CFGAddInitializers : Flag<"-cfg-add-initializers">, HelpText<"Add C++ initializers to CFGs for all analyses">; def analyzer_store : Separate<"-analyzer-store">, HelpText<"Source Code Analysis - Abstract Memory Store Models">; def analyzer_store_EQ : Joined<"-analyzer-store=">, Alias; def analyzer_constraints : Separate<"-analyzer-constraints">, HelpText<"Source Code Analysis - Symbolic Constraint Engines">; def analyzer_constraints_EQ : Joined<"-analyzer-constraints=">, Alias; def analyzer_output : Separate<"-analyzer-output">, HelpText<"Source Code Analysis - Output Options">; def analyzer_output_EQ : Joined<"-analyzer-output=">, Alias; def analyzer_purge : Separate<"-analyzer-purge">, HelpText<"Source Code Analysis - Dead Symbol Removal Frequency">; def analyzer_purge_EQ : Joined<"-analyzer-purge=">, Alias; def analyzer_opt_analyze_headers : Flag<"-analyzer-opt-analyze-headers">, HelpText<"Force the static analyzer to analyze functions defined in header files">; def analyzer_opt_analyze_nested_blocks : Flag<"-analyzer-opt-analyze-nested-blocks">, HelpText<"Analyze the definitions of blocks in addition to functions">; def analyzer_display_progress : Flag<"-analyzer-display-progress">, HelpText<"Emit verbose output about the analyzer's progress">; def analyze_function : Separate<"-analyze-function">, HelpText<"Run analysis on specific function">; def analyze_function_EQ : Joined<"-analyze-function=">, Alias; def analyzer_eagerly_assume : Flag<"-analyzer-eagerly-assume">, HelpText<"Eagerly assume the truth/falseness of some symbolic constraints">; def analyzer_no_eagerly_trim_egraph : Flag<"-analyzer-no-eagerly-trim-egraph">, HelpText<"Don't eagerly remove uninteresting ExplodedNodes from the ExplodedGraph">; def trim_egraph : Flag<"-trim-egraph">, HelpText<"Only show error-related paths in the analysis graph">; def analyzer_viz_egraph_graphviz : Flag<"-analyzer-viz-egraph-graphviz">, HelpText<"Display exploded graph using GraphViz">; def analyzer_viz_egraph_ubigraph : Flag<"-analyzer-viz-egraph-ubigraph">, HelpText<"Display exploded graph using Ubigraph">; def analyzer_inline_call : Flag<"-analyzer-inline-call">, HelpText<"Experimental transfer function inlining callees when its definition is available.">; def analyzer_max_nodes : Separate<"-analyzer-max-nodes">, HelpText<"The maximum number of nodes the analyzer can generate (150000 default, 0 = no limit)">; def analyzer_max_loop : Separate<"-analyzer-max-loop">, HelpText<"The maximum number of times the analyzer will go through a loop">; def analyzer_checker : Separate<"-analyzer-checker">, HelpText<"Choose analyzer checkers to enable">; def analyzer_checker_EQ : Joined<"-analyzer-checker=">, Alias; def analyzer_disable_checker : Separate<"-analyzer-disable-checker">, HelpText<"Choose analyzer checkers to disable">; def analyzer_disable_checker_EQ : Joined<"-analyzer-disable-checker=">, Alias; def analyzer_checker_help : Flag<"-analyzer-checker-help">, HelpText<"Display the list of analyzer checkers that are available">; //===----------------------------------------------------------------------===// // CodeGen Options //===----------------------------------------------------------------------===// def disable_llvm_optzns : Flag<"-disable-llvm-optzns">, HelpText<"Don't run LLVM optimization passes">; def disable_llvm_verifier : Flag<"-disable-llvm-verifier">, HelpText<"Don't run the LLVM IR verifier pass">; def disable_red_zone : Flag<"-disable-red-zone">, HelpText<"Do not emit code that uses the red zone.">; def dwarf_debug_flags : Separate<"-dwarf-debug-flags">, HelpText<"The string to embed in the Dwarf debug flags record.">; def fforbid_guard_variables : Flag<"-fforbid-guard-variables">, HelpText<"Emit an error if a C++ static local initializer would need a guard variable">; def g : Flag<"-g">, HelpText<"Generate source level debug information">; def fno_dwarf2_cfi_asm : Flag<"-fno-dwarf2-cfi-asm">, HelpText<"Don't use the cfi directives">; def fcatch_undefined_behavior : Flag<"-fcatch-undefined-behavior">, HelpText<"Generate runtime checks for undefined behavior.">; def flimit_debug_info : Flag<"-flimit-debug-info">, HelpText<"Limit debug information produced to reduce size of debug binary">; def fno_common : Flag<"-fno-common">, HelpText<"Compile common globals like normal definitions">; def no_implicit_float : Flag<"-no-implicit-float">, HelpText<"Don't generate implicit floating point instructions (x86-only)">; def finstrument_functions : Flag<"-finstrument-functions">, HelpText<"Generate calls to instrument function entry and exit">; def fno_merge_all_constants : Flag<"-fno-merge-all-constants">, HelpText<"Disallow merging of constants.">; def fno_threadsafe_statics : Flag<"-fno-threadsafe-statics">, HelpText<"Do not emit code to make initialization of local statics thread safe">; def fdump_vtable_layouts : Flag<"-fdump-vtable-layouts">, HelpText<"Dump the layouts of all vtables that will be emitted in a translation unit">; def ffunction_sections : Flag<"-ffunction-sections">, HelpText<"Place each function in its own section (ELF Only)">; def fdata_sections : Flag<"-fdata-sections">, HelpText<"Place each data in its own section (ELF Only)">; def funroll_loops : Flag<"-funroll-loops">, HelpText<"Turn on loop unroller">; def femit_coverage_notes : Flag<"-femit-coverage-notes">, HelpText<"Emit a gcov coverage notes file when compiling.">; def femit_coverage_data: Flag<"-femit-coverage-data">, HelpText<"Instrument the program to emit gcov coverage data when run.">; def coverage_file : Separate<"-coverage-file">, HelpText<"Emit coverage data to this filename. The extension will be replaced.">; def coverage_file_EQ : Joined<"-coverage-file=">, Alias; def fuse_register_sized_bitfield_access: Flag<"-fuse-register-sized-bitfield-access">, HelpText<"Use register sized accesses to bit-fields, when possible.">; def relaxed_aliasing : Flag<"-relaxed-aliasing">, HelpText<"Turn off Type Based Alias Analysis">; def masm_verbose : Flag<"-masm-verbose">, HelpText<"Generate verbose assembly output">; def mcode_model : Separate<"-mcode-model">, HelpText<"The code model to use">; def mdebug_pass : Separate<"-mdebug-pass">, HelpText<"Enable additional debug output">; def mdisable_fp_elim : Flag<"-mdisable-fp-elim">, HelpText<"Disable frame pointer elimination optimization">; def mfloat_abi : Separate<"-mfloat-abi">, HelpText<"The float ABI to use">; def mno_global_merge : Flag<"-mno-global-merge">, HelpText<"Disable merging of globals">; def mlimit_float_precision : Separate<"-mlimit-float-precision">, HelpText<"Limit float precision to the given value">; def mno_exec_stack : Flag<"-mnoexecstack">, HelpText<"Mark the file as not needing an executable stack">; def mno_zero_initialized_in_bss : Flag<"-mno-zero-initialized-in-bss">, HelpText<"Do not put zero initialized data in the BSS">; def momit_leaf_frame_pointer : Flag<"-momit-leaf-frame-pointer">, HelpText<"Omit frame pointer setup for leaf functions.">; def msoft_float : Flag<"-msoft-float">, HelpText<"Use software floating point">; def backend_option : Separate<"-backend-option">, HelpText<"Additional arguments to forward to LLVM backend (during code gen)">; def mregparm : Separate<"-mregparm">, HelpText<"Limit the number of registers available for integer arguments">; def mrelax_all : Flag<"-mrelax-all">, HelpText<"(integrated-as) Relax all machine instructions">; def msave_temp_labels : Flag<"-msave-temp-labels">, HelpText<"(integrated-as) Save temporary labels">; def mrtd: Flag<"-mrtd">, HelpText<"Make StdCall calling convention the default">; def mrelocation_model : Separate<"-mrelocation-model">, HelpText<"The relocation model to use">; def munwind_tables : Flag<"-munwind-tables">, HelpText<"Generate unwinding tables for all functions">; def mconstructor_aliases : Flag<"-mconstructor-aliases">, HelpText<"Emit complete constructors and destructors as aliases when possible">; def mms_bitfields : Flag<"-mms-bitfields">, HelpText<"Set the default structure layout to be compatible with the Microsoft compiler standard.">; def mstackrealign : Flag<"-mstackrealign">, HelpText<"Force realign the stack at entry to every function.">; def O : Joined<"-O">, HelpText<"Optimization level">; def Os : Flag<"-Os">, HelpText<"Optimize for size">; def Oz : Flag<"-Oz">, HelpText<"Optimize for size, regardless of performance">; def pg : Flag<"-pg">, HelpText<"Enable mcount instrumentation">; //===----------------------------------------------------------------------===// // Dependency Output Options //===----------------------------------------------------------------------===// def dependency_file : Separate<"-dependency-file">, HelpText<"Filename (or -) to write dependency output to">; def sys_header_deps : Flag<"-sys-header-deps">, HelpText<"Include system headers in dependency output">; def header_include_file : Separate<"-header-include-file">, HelpText<"Filename (or -) to write header include output to">; def H : Flag<"-H">, HelpText<"Show header includes and nesting depth">; def MQ : Separate<"-MQ">, HelpText<"Specify target to quote for dependency">; def MT : Separate<"-MT">, HelpText<"Specify target for dependency">; def MP : Flag<"-MP">, HelpText<"Create phony target for each dependency (other than main file)">; def MG : Flag<"-MG">, HelpText<"Add missing headers to dependency list">; //===----------------------------------------------------------------------===// // Diagnostic Options //===----------------------------------------------------------------------===// def dump_build_information : Separate<"-dump-build-information">, MetaVarName<"">, HelpText<"output a dump of some build information to a file">; def diagnostic_log_file : Separate<"-diagnostic-log-file">, HelpText<"Filename (or -) to log diagnostics to">; def fno_show_column : Flag<"-fno-show-column">, HelpText<"Do not include column number on diagnostics">; def fshow_column : Flag<"-fshow-column">, HelpText<"Include column number on diagnostics">; def fno_show_source_location : Flag<"-fno-show-source-location">, HelpText<"Do not include source location information with diagnostics">; def fshow_overloads_EQ : Joined<"-fshow-overloads=">, HelpText<"Which overload candidates to show when overload resolution fails: " "best|all; defaults to all">; def fno_caret_diagnostics : Flag<"-fno-caret-diagnostics">, HelpText<"Do not include source line and caret with diagnostics">; def fno_diagnostics_fixit_info : Flag<"-fno-diagnostics-fixit-info">, HelpText<"Do not include fixit information in diagnostics">; def fno_diagnostics_show_note_include_stack : Flag<"-fno-diagnostics-show-note-include-stack">, HelpText<"Display include stacks for diagnostic notes">; def w : Flag<"-w">, HelpText<"Suppress all warnings">; def pedantic : Flag<"-pedantic">; def pedantic_errors : Flag<"-pedantic-errors">; // This gets all -W options, including -Werror, -W[no-]system-headers, etc. The // driver has stripped off -Wa,foo etc. The driver has also translated -W to // -Wextra, so we don't need to worry about it. def W : Joined<"-W">; def fdiagnostics_print_source_range_info : Flag<"-fdiagnostics-print-source-range-info">, HelpText<"Print source range spans in numeric form">; def fdiagnostics_parseable_fixits : Flag<"-fdiagnostics-parseable-fixits">, HelpText<"Print fix-its in machine parseable form">; def fdiagnostics_show_name : Flag<"-fdiagnostics-show-name">, HelpText<"Print diagnostic name">; def fdiagnostics_show_option : Flag<"-fdiagnostics-show-option">, HelpText<"Print option name with mappable diagnostics">; def fdiagnostics_format : Separate<"-fdiagnostics-format">, HelpText<"Change diagnostic formatting to match IDE and command line tools">; def fdiagnostics_show_category : Separate<"-fdiagnostics-show-category">, HelpText<"Print diagnostic category">; def fdiagnostics_show_note_include_stack : Flag<"-fdiagnostics-show-note-include-stack">, HelpText<"Display include stacks for diagnostic notes">; def ftabstop : Separate<"-ftabstop">, MetaVarName<"">, HelpText<"Set the tab stop distance.">; def ferror_limit : Separate<"-ferror-limit">, MetaVarName<"">, HelpText<"Set the maximum number of errors to emit before stopping (0 = no limit).">; def fmacro_backtrace_limit : Separate<"-fmacro-backtrace-limit">, MetaVarName<"">, HelpText<"Set the maximum number of entries to print in a macro expansion backtrace (0 = no limit).">; def ftemplate_backtrace_limit : Separate<"-ftemplate-backtrace-limit">, MetaVarName<"">, HelpText<"Set the maximum number of entries to print in a template instantiation backtrace (0 = no limit).">; def fmessage_length : Separate<"-fmessage-length">, MetaVarName<"">, HelpText<"Format message diagnostics so that they fit within N columns or fewer, when possible.">; def fcolor_diagnostics : Flag<"-fcolor-diagnostics">, HelpText<"Use colors in diagnostics">; def Wno_rewrite_macros : Flag<"-Wno-rewrite-macros">, HelpText<"Silence ObjC rewriting warnings">; def verify : Flag<"-verify">, HelpText<"Verify emitted diagnostics and warnings">; //===----------------------------------------------------------------------===// // Frontend Options //===----------------------------------------------------------------------===// // This isn't normally used, it is just here so we can parse a // CompilerInvocation out of a driver-derived argument vector. def cc1 : Flag<"-cc1">; def ast_merge : Separate<"-ast-merge">, MetaVarName<"">, HelpText<"Merge the given AST file into the translation unit being compiled.">; def code_completion_at : Separate<"-code-completion-at">, MetaVarName<"::">, HelpText<"Dump code-completion information at a location">; def remap_file : Separate<"-remap-file">, MetaVarName<";">, HelpText<"Replace the contents of the file with the contents of the file">; def code_completion_at_EQ : Joined<"-code-completion-at=">, Alias; def code_completion_macros : Flag<"-code-completion-macros">, HelpText<"Include macros in code-completion results">; def code_completion_patterns : Flag<"-code-completion-patterns">, HelpText<"Include code patterns in code-completion results">; def no_code_completion_globals : Flag<"-no-code-completion-globals">, HelpText<"Do not include global declarations in code-completion results.">; def disable_free : Flag<"-disable-free">, HelpText<"Disable freeing of memory on exit">; def help : Flag<"-help">, HelpText<"Print this help text">; def _help : Flag<"--help">, Alias; def x : Separate<"-x">, HelpText<"Input language type">; def o : Separate<"-o">, MetaVarName<"">, HelpText<"Specify output file">; def load : Separate<"-load">, MetaVarName<"">, HelpText<"Load the named plugin (dynamic shared object)">; def plugin : Separate<"-plugin">, MetaVarName<"">, HelpText<"Use the named plugin action instead of the default action (use \"help\" to list available options)">; def plugin_arg : JoinedAndSeparate<"-plugin-arg-">, MetaVarName<" ">, HelpText<"Pass to plugin ">; def add_plugin : Separate<"-add-plugin">, MetaVarName<"">, HelpText<"Use the named plugin action in addition to the default action">; def resource_dir : Separate<"-resource-dir">, HelpText<"The directory which holds the compiler resource files">; def version : Flag<"-version">, HelpText<"Print the compiler version">; def _version : Flag<"--version">, Alias; def Action_Group : OptionGroup<"">; let Group = Action_Group in { def Eonly : Flag<"-Eonly">, HelpText<"Just run preprocessor, no output (for timings)">; def E : Flag<"-E">, HelpText<"Run preprocessor, emit preprocessed file">; def dump_raw_tokens : Flag<"-dump-raw-tokens">, HelpText<"Lex file in raw mode and dump raw tokens">; def analyze : Flag<"-analyze">, HelpText<"Run static analysis engine">; def dump_tokens : Flag<"-dump-tokens">, HelpText<"Run preprocessor, dump internal rep of tokens">; def init_only : Flag<"-init-only">, HelpText<"Only execute frontend initialization">; def fsyntax_only : Flag<"-fsyntax-only">, HelpText<"Run parser and perform semantic analysis">; def fixit : Flag<"-fixit">, HelpText<"Apply fix-it advice to the input source">; def fixit_EQ : Joined<"-fixit=">, HelpText<"Apply fix-it advice creating a file with the given suffix">; def print_preamble : Flag<"-print-preamble">, HelpText<"Print the \"preamble\" of a file, which is a candidate for implicit" " precompiled headers.">; def emit_html : Flag<"-emit-html">, HelpText<"Output input source as HTML">; def ast_print : Flag<"-ast-print">, HelpText<"Build ASTs and then pretty-print them">; def ast_dump : Flag<"-ast-dump">, HelpText<"Build ASTs and then debug dump them">; def ast_dump_xml : Flag<"-ast-dump-xml">, HelpText<"Build ASTs and then debug dump them in a verbose XML format">; def ast_view : Flag<"-ast-view">, HelpText<"Build ASTs and view them with GraphViz">; def print_decl_contexts : Flag<"-print-decl-contexts">, HelpText<"Print DeclContexts and their Decls">; def emit_module : Flag<"-emit-module">, HelpText<"Generate pre-compiled module file">; def emit_pth : Flag<"-emit-pth">, HelpText<"Generate pre-tokenized header file">; def emit_pch : Flag<"-emit-pch">, HelpText<"Generate pre-compiled header file">; def S : Flag<"-S">, HelpText<"Emit native assembly code">; def emit_llvm : Flag<"-emit-llvm">, HelpText<"Build ASTs then convert to LLVM, emit .ll file">; def emit_llvm_bc : Flag<"-emit-llvm-bc">, HelpText<"Build ASTs then convert to LLVM, emit .bc file">; def emit_llvm_only : Flag<"-emit-llvm-only">, HelpText<"Build ASTs and convert to LLVM, discarding output">; def emit_codegen_only : Flag<"-emit-codegen-only">, HelpText<"Generate machine code, but discard output">; def emit_obj : Flag<"-emit-obj">, HelpText<"Emit native object files">; def rewrite_test : Flag<"-rewrite-test">, HelpText<"Rewriter playground">; def rewrite_objc : Flag<"-rewrite-objc">, HelpText<"Rewrite ObjC into C (code rewriter example)">; def rewrite_macros : Flag<"-rewrite-macros">, HelpText<"Expand macros without full preprocessing">; } def arcmt_check : Flag<"-arcmt-check">, HelpText<"Check for ARC migration issues that need manual handling">; def arcmt_modify : Flag<"-arcmt-modify">, HelpText<"Apply modifications to files to conform to ARC">; def arcmt_migrate : Flag<"-arcmt-migrate">, HelpText<"Apply modifications and produces temporary files that conform to ARC">; def arcmt_migrate_directory : Separate<"-arcmt-migrate-directory">, HelpText<"Directory for temporary files produced during ARC migration">; def arcmt_migrate_report_output : Separate<"-arcmt-migrate-report-output">, HelpText<"Output path for the plist report">; def arcmt_migrate_emit_arc_errors : Flag<"-arcmt-migrate-emit-errors">, HelpText<"Emit ARC errors even if the migrator can fix them">; def working_directory : JoinedOrSeparate<"-working-directory">, HelpText<"Resolve file paths relative to the specified directory">; def working_directory_EQ : Joined<"-working-directory=">, Alias; def relocatable_pch : Flag<"-relocatable-pch">, HelpText<"Whether to build a relocatable precompiled header">; def print_stats : Flag<"-print-stats">, HelpText<"Print performance metrics and statistics">; def ftime_report : Flag<"-ftime-report">, HelpText<"Print the amount of time each phase of compilation takes">; def fdump_record_layouts : Flag<"-fdump-record-layouts">, HelpText<"Dump record layout information">; def fix_what_you_can : Flag<"-fix-what-you-can">, HelpText<"Apply fix-it advice even in the presence of unfixable errors">; // Generic forwarding to LLVM options. This should only be used for debugging // and experimental features. def mllvm : Separate<"-mllvm">, HelpText<"Additional arguments to forward to LLVM's option processing">; //===----------------------------------------------------------------------===// // Language Options //===----------------------------------------------------------------------===// def fno_builtin : Flag<"-fno-builtin">, HelpText<"Disable implicit builtin knowledge of functions">; def faltivec : Flag<"-faltivec">, HelpText<"Enable AltiVec vector initializer syntax">; def fno_access_control : Flag<"-fno-access-control">, HelpText<"Disable C++ access control">; def fno_assume_sane_operator_new : Flag<"-fno-assume-sane-operator-new">, HelpText<"Don't assume that C++'s global operator new can't alias any pointer">; def fgnu_keywords : Flag<"-fgnu-keywords">, HelpText<"Allow GNU-extension keywords regardless of language standard">; def fgnu89_inline : Flag<"-fgnu89-inline">, HelpText<"Use the gnu89 inline semantics">; def fno_gnu_keywords : Flag<"-fno-gnu-keywords">, HelpText<"Disallow GNU-extension keywords regardless of language standard">; def fdollars_in_identifiers : Flag<"-fdollars-in-identifiers">, HelpText<"Allow '$' in identifiers">; def fno_dollars_in_identifiers : Flag<"-fno-dollars-in-identifiers">, HelpText<"Disallow '$' in identifiers">; def femit_all_decls : Flag<"-femit-all-decls">, HelpText<"Emit all declarations, even if unused">; def fblocks : Flag<"-fblocks">, HelpText<"Enable the 'blocks' language feature">; def fblocks_runtime_optional : Flag<"-fblocks-runtime-optional">, HelpText<"Weakly link in the blocks runtime">; def fheinous_gnu_extensions : Flag<"-fheinous-gnu-extensions">; def fexceptions : Flag<"-fexceptions">, HelpText<"Enable support for exception handling">; def fobjc_exceptions : Flag<"-fobjc-exceptions">, HelpText<"Enable Objective-C exceptions">; def fcxx_exceptions : Flag<"-fcxx-exceptions">, HelpText<"Enable C++ exceptions">; def fsjlj_exceptions : Flag<"-fsjlj-exceptions">, HelpText<"Use SjLj style exceptions">; def ffreestanding : Flag<"-ffreestanding">, HelpText<"Assert that the compilation takes place in a freestanding environment">; def fformat_extensions : Flag<"-fformat-extensions">, HelpText<"FreeBSD printf format extensions">; def fgnu_runtime : Flag<"-fgnu-runtime">, HelpText<"Generate output compatible with the standard GNU Objective-C runtime">; def fhidden_weak_vtables : Flag<"-fhidden-weak-vtables">, HelpText<"Generate weak vtables and RTTI with hidden visibility">; def std_EQ : Joined<"-std=">, HelpText<"Language standard to compile for">; def stdlib_EQ : Joined<"-stdlib=">, HelpText<"C++ standard library to use">; def fmath_errno : Flag<"-fmath-errno">, HelpText<"Require math functions to indicate errors by setting errno">; def fms_extensions : Flag<"-fms-extensions">, HelpText<"Accept some non-standard constructs supported by the Microsoft compiler">; def fms_compatibility : Flag<"-fms-compatibility">, HelpText<"Enable Microsoft compatibility mode">; def fmsc_version : Joined<"-fmsc-version=">, HelpText<"Version of the Microsoft C/C++ compiler to report in _MSC_VER (0 = don't define it (default))">; def fborland_extensions : Flag<"-fborland-extensions">, HelpText<"Accept non-standard constructs supported by the Borland compiler">; def main_file_name : Separate<"-main-file-name">, HelpText<"Main file name to use for debug info">; def fno_elide_constructors : Flag<"-fno-elide-constructors">, HelpText<"Disable C++ copy constructor elision">; def fno_lax_vector_conversions : Flag<"-fno-lax-vector-conversions">, HelpText<"Disallow implicit conversions between vectors with a different number of elements or different element types">; def fno_operator_names : Flag<"-fno-operator-names">, HelpText<"Do not treat C++ operator name keywords as synonyms for operators">; def fno_signed_char : Flag<"-fno-signed-char">, HelpText<"Char is unsigned">; def fno_spell_checking : Flag<"-fno-spell-checking">, HelpText<"Disable spell-checking">; def fno_use_cxa_atexit : Flag<"-fno-use-cxa-atexit">, HelpText<"Don't use __cxa_atexit for calling destructors">; def fconstant_string_class : Separate<"-fconstant-string-class">, MetaVarName<"">, HelpText<"Specify the class to use for constant Objective-C string objects.">; def fno_constant_cfstrings : Flag<"-fno-constant-cfstrings">, HelpText<"Enable creation of CodeFoundation-type constant strings">; def fobjc_arc : Flag<"-fobjc-arc">, HelpText<"Synthesize retain and release calls for Objective-C pointers">; def fobjc_arc_cxxlib_EQ : Joined<"-fobjc-arc-cxxlib=">, HelpText<"Objective-C++ Automatic Reference Counting standard library kind">; def fobjc_arc_exceptions : Flag<"-fobjc-arc-exceptions">, HelpText<"Use EH-safe code when synthesizing retains and releases in -fobjc-arc">; def fobjc_runtime_has_arc : Flag<"-fobjc-runtime-has-arc">, HelpText<"The target Objective-C runtime provides ARC entrypoints">; def fobjc_runtime_has_weak : Flag<"-fobjc-runtime-has-weak">, HelpText<"The target Objective-C runtime supports ARC weak operations">; def fobjc_runtime_has_terminate : Flag<"-fobjc-runtime-has-terminate">, HelpText<"The target Objective-C runtime provides an objc_terminate entrypoint">; def fobjc_gc : Flag<"-fobjc-gc">, HelpText<"Enable Objective-C garbage collection">; def fobjc_gc_only : Flag<"-fobjc-gc-only">, HelpText<"Use GC exclusively for Objective-C related memory management">; def fapple_kext : Flag<"-fapple-kext">, HelpText<"Use Apple's kernel extensions ABI">; def fobjc_dispatch_method_EQ : Joined<"-fobjc-dispatch-method=">, HelpText<"Objective-C dispatch method to use">; def fobjc_default_synthesize_properties : Flag<"-fobjc-default-synthesize-properties">, HelpText<"enable the default synthesis of Objective-C properties">; def print_ivar_layout : Flag<"-print-ivar-layout">, HelpText<"Enable Objective-C Ivar layout bitmap print trace">; def fobjc_fragile_abi : Flag<"-fobjc-fragile-abi">, HelpText<"Use Objective-C's fragile ABI">; def fno_objc_infer_related_result_type : Flag< "-fno-objc-infer-related-result-type">, HelpText< "do not infer Objective-C related result type based on method family">; def ftrapv : Flag<"-ftrapv">, HelpText<"Trap on integer overflow">; def ftrapv_handler : Separate<"-ftrapv-handler">, MetaVarName<"">, HelpText<"Specify the function to be called on overflow.">; def fwrapv : Flag<"-fwrapv">, HelpText<"Treat signed integer overflow as two's complement">; def pic_level : Separate<"-pic-level">, HelpText<"Value for __PIC__">; def pthread : Flag<"-pthread">, HelpText<"Support POSIX threads in generated code">; def fpack_struct : Separate<"-fpack-struct">, HelpText<"Specify the default maximum struct packing alignment">; def fpascal_strings : Flag<"-fpascal-strings">, HelpText<"Recognize and construct Pascal-style string literals">; def fno_rtti : Flag<"-fno-rtti">, HelpText<"Disable generation of rtti information">; def fno_validate_pch : Flag<"-fno-validate-pch">, HelpText<"Disable validation of precompiled headers">; def dump_deserialized_pch_decls : Flag<"-dump-deserialized-decls">, HelpText<"Dump declarations that are deserialized from PCH, for testing">; def error_on_deserialized_pch_decl : Separate<"-error-on-deserialized-decl">, HelpText<"Emit error if a specific declaration is deserialized from PCH, for testing">; def fshort_wchar : Flag<"-fshort-wchar">, HelpText<"Force wchar_t to be a short unsigned int">; def fshort_enums : Flag<"-fshort-enums">, HelpText<"Allocate to an enum type only as many bytes as it needs for the declared range of possible values">; def static_define : Flag<"-static-define">, HelpText<"Should __STATIC__ be defined">; def stack_protector : Separate<"-stack-protector">, HelpText<"Enable stack protectors">; def fvisibility : Separate<"-fvisibility">, HelpText<"Default symbol visibility">; def fvisibility_inlines_hidden : Flag<"-fvisibility-inlines-hidden">, HelpText<"Give inline C++ member functions default visibility by default">; def ftemplate_depth : Separate<"-ftemplate-depth">, HelpText<"Maximum depth of recursive template instantiation">; def Wlarge_by_value_copy : Separate<"-Wlarge-by-value-copy">, HelpText<"Warn if a function definition returns or accepts an object larger " "in bytes that a given value">; def Wlarge_by_value_copy_EQ : Joined<"-Wlarge-by-value-copy=">, Alias; def trigraphs : Flag<"-trigraphs">, HelpText<"Process trigraph sequences">; def fwritable_strings : Flag<"-fwritable-strings">, HelpText<"Store string literals as writable data">; def fconst_strings : Flag<"-fconst-strings">, HelpText<"Use a const qualified type for string literals in C and ObjC">; def fno_const_strings : Flag<"-fno-const-strings">, HelpText<"Don't use a const qualified type for string literals in C and ObjC">; def fno_bitfield_type_align : Flag<"-fno-bitfield-type-align">, HelpText<"Ignore bit-field types when aligning structures">; def traditional_cpp : Flag<"-traditional-cpp">, HelpText<"Enable some traditional CPP emulation">; def ffake_address_space_map : Flag<"-ffake-address-space-map">, HelpText<"Use a fake address space map; OpenCL testing purposes only">; def fdelayed_template_parsing : Flag<"-fdelayed-template-parsing">, HelpText<"Parse templated function definitions at the end of the " "translation unit ">; def funknown_anytype : Flag<"-funknown-anytype">, HelpText<"Enable parser support for the __unknown_anytype type; for testing purposes only">; def fdebugger_support : Flag<"-fdebugger-support">, HelpText<"Enable special debugger support behavior">; def fdeprecated_macro : Flag<"-fdeprecated-macro">, HelpText<"Defines the __DEPRECATED macro">; def fno_deprecated_macro : Flag<"-fno-deprecated-macro">, HelpText<"Undefines the __DEPRECATED macro">; //===----------------------------------------------------------------------===// // Header Search Options //===----------------------------------------------------------------------===// def nostdsysteminc : Flag<"-nostdsysteminc">, HelpText<"Disable standard system #include directories">; def nostdincxx : Flag<"-nostdinc++">, HelpText<"Disable standard #include directories for the C++ standard library">; def nobuiltininc : Flag<"-nobuiltininc">, HelpText<"Disable builtin #include directories">; def fmodule_cache_path : Separate<"-fmodule-cache-path">, MetaVarName<"">, HelpText<"Specify the module cache path">; def fdisable_module_hash : Flag<"-fdisable-module-hash">, HelpText<"Disable the module hash">; def fauto_module_import : Flag<"-fauto-module-import">, HelpText<"Automatically translate #include/#import into module imports " "when possible">; def F : JoinedOrSeparate<"-F">, MetaVarName<"">, HelpText<"Add directory to framework include search path">; def I : JoinedOrSeparate<"-I">, MetaVarName<"">, HelpText<"Add directory to include search path">; def idirafter : JoinedOrSeparate<"-idirafter">, MetaVarName<"">, HelpText<"Add directory to AFTER include search path">; def index_header_map : Flag<"-index-header-map">, HelpText<"Make the next included directory (-I or -F) an indexer header map">; def iquote : JoinedOrSeparate<"-iquote">, MetaVarName<"">, HelpText<"Add directory to QUOTE include search path">; def c_isystem : JoinedOrSeparate<"-c-isystem">, MetaVarName<"">, HelpText<"Add directory to the C SYSTEM include search path">; def cxx_isystem : JoinedOrSeparate<"-cxx-isystem">, MetaVarName<"">, HelpText<"Add directory to the C++ SYSTEM include search path">; def objc_isystem : JoinedOrSeparate<"-objc-isystem">, MetaVarName<"">, HelpText<"Add directory to the ObjC SYSTEM include search path">; def objcxx_isystem : JoinedOrSeparate<"-objcxx-isystem">, MetaVarName<"">, HelpText<"Add directory to the ObjC++ SYSTEM include search path">; def isystem : JoinedOrSeparate<"-isystem">, MetaVarName<"">, HelpText<"Add directory to SYSTEM include search path">; def iwithsysroot : JoinedOrSeparate<"-iwithsysroot">,MetaVarName<"">, HelpText<"Add directory to SYSTEM include search path, " "absolute paths are relative to -isysroot">; +def internal_isystem : JoinedOrSeparate<"-internal-isystem">, + MetaVarName<"">, + HelpText<"Add directory to the internal system include search path; these " + "are assumed to not be user-provided and are used to model system " + "and standard headers' paths.">; +def internal_externc_isystem : JoinedOrSeparate<"-internal-externc-isystem">, + MetaVarName<"">, + HelpText<"Add directory to the internal system include search path with " + "implicit extern \"C\" semantics; these are assumed to not be " + "user-provided and are used to model system and standard headers' " + "paths.">; def iprefix : JoinedOrSeparate<"-iprefix">, MetaVarName<"">, HelpText<"Set the -iwithprefix/-iwithprefixbefore prefix">; def iwithprefix : JoinedOrSeparate<"-iwithprefix">, MetaVarName<"">, HelpText<"Set directory to SYSTEM include search path with prefix">; def iwithprefixbefore : JoinedOrSeparate<"-iwithprefixbefore">, MetaVarName<"">, HelpText<"Set directory to include search path with prefix">; def isysroot : JoinedOrSeparate<"-isysroot">, MetaVarName<"">, HelpText<"Set the system root directory (usually /)">; def v : Flag<"-v">, HelpText<"Enable verbose output">; //===----------------------------------------------------------------------===// // Preprocessor Options //===----------------------------------------------------------------------===// def D : JoinedOrSeparate<"-D">, MetaVarName<"">, HelpText<"Predefine the specified macro">; def include_ : JoinedOrSeparate<"-include">, MetaVarName<"">, EnumName<"include">, HelpText<"Include file before parsing">; def imacros : JoinedOrSeparate<"-imacros">, MetaVarName<"">, HelpText<"Include macros from file before parsing">; def include_pch : Separate<"-include-pch">, MetaVarName<"">, HelpText<"Include precompiled header file">; def include_pth : Separate<"-include-pth">, MetaVarName<"">, HelpText<"Include file before parsing">; def chain_include : Separate<"-chain-include">, MetaVarName<"">, HelpText<"Include and chain a header file after turning it into PCH">; def preamble_bytes_EQ : Joined<"-preamble-bytes=">, HelpText<"Assume that the precompiled header is a precompiled preamble " "covering the first N bytes of the main file">; def token_cache : Separate<"-token-cache">, MetaVarName<"">, HelpText<"Use specified token cache file">; def U : JoinedOrSeparate<"-U">, MetaVarName<"">, HelpText<"Undefine the specified macro">; def undef : Flag<"-undef">, MetaVarName<"">, HelpText<"undef all system defines">; def detailed_preprocessing_record : Flag<"-detailed-preprocessing-record">, HelpText<"include a detailed record of preprocessing actions">; //===----------------------------------------------------------------------===// // Preprocessed Output Options //===----------------------------------------------------------------------===// def P : Flag<"-P">, HelpText<"Disable linemarker output in -E mode">; def C : Flag<"-C">, HelpText<"Enable comment output in -E mode">; def CC : Flag<"-CC">, HelpText<"Enable comment output in -E mode, even from macro expansions">; def dM : Flag<"-dM">, HelpText<"Print macro definitions in -E mode instead of normal output">; def dD : Flag<"-dD">, HelpText<"Print macro definitions in -E mode in addition to normal output">; //===----------------------------------------------------------------------===// // OpenCL Options //===----------------------------------------------------------------------===// def cl_opt_disable : Flag<"-cl-opt-disable">, HelpText<"OpenCL only. This option disables all optimizations. The default is optimizations are enabled.">; def cl_single_precision_constant : Flag<"-cl-single-precision-constant">, HelpText<"OpenCL only. Treat double precision floating-point constant as single precision constant.">; def cl_finite_math_only : Flag<"-cl-finite-math-only">, HelpText<"OpenCL only. Allow floating-point optimizations that assume arguments and results are not NaNs or +-Inf.">; def cl_unsafe_math_optimizations : Flag<"-cl-unsafe-math-optimizations">, HelpText<"OpenCL only. Allow unsafe floating-point optimizations. Also implies -cl-no-signed-zeros and -cl-mad-enable">; def cl_fast_relaxed_math : Flag<"-cl-fast-relaxed-math">, HelpText<"OpenCL only. Sets -cl-finite-math-only and -cl-unsafe-math-optimizations, and defines __FAST_RELAXED_MATH__">; def cl_mad_enable : Flag<"-cl-mad-enable">, HelpText<"OpenCL only. Enable less precise MAD instructions to be generated.">; def cl_std_EQ : Joined<"-cl-std=">, HelpText<"OpenCL language standard to compile for">; //===----------------------------------------------------------------------===// // CUDA Options //===----------------------------------------------------------------------===// def fcuda_is_device : Flag<"-fcuda-is-device">, HelpText<"Generate code for CUDA device">; Index: head/contrib/llvm/tools/clang/include/clang/Driver/ToolChain.h =================================================================== --- head/contrib/llvm/tools/clang/include/clang/Driver/ToolChain.h (revision 228378) +++ head/contrib/llvm/tools/clang/include/clang/Driver/ToolChain.h (revision 228379) @@ -1,222 +1,228 @@ //===--- ToolChain.h - Collections of tools for one platform ----*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef CLANG_DRIVER_TOOLCHAIN_H_ #define CLANG_DRIVER_TOOLCHAIN_H_ #include "clang/Driver/Util.h" #include "clang/Driver/Types.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/Path.h" #include namespace clang { namespace driver { class ArgList; class Compilation; class DerivedArgList; class Driver; class HostInfo; class InputArgList; class JobAction; class ObjCRuntime; class Tool; /// ToolChain - Access to tools for a single platform. class ToolChain { public: typedef SmallVector path_list; enum CXXStdlibType { CST_Libcxx, CST_Libstdcxx }; private: const HostInfo &Host; const llvm::Triple Triple; /// The list of toolchain specific path prefixes to search for /// files. path_list FilePaths; /// The list of toolchain specific path prefixes to search for /// programs. path_list ProgramPaths; protected: ToolChain(const HostInfo &Host, const llvm::Triple &_Triple); public: virtual ~ToolChain(); // Accessors const Driver &getDriver() const; const llvm::Triple &getTriple() const { return Triple; } llvm::Triple::ArchType getArch() const { return Triple.getArch(); } StringRef getArchName() const { return Triple.getArchName(); } StringRef getPlatform() const { return Triple.getVendorName(); } StringRef getOS() const { return Triple.getOSName(); } std::string getTripleString() const { return Triple.getTriple(); } path_list &getFilePaths() { return FilePaths; } const path_list &getFilePaths() const { return FilePaths; } path_list &getProgramPaths() { return ProgramPaths; } const path_list &getProgramPaths() const { return ProgramPaths; } // Tool access. /// TranslateArgs - Create a new derived argument list for any argument /// translations this ToolChain may wish to perform, or 0 if no tool chain /// specific translations are needed. /// /// \param BoundArch - The bound architecture name, or 0. virtual DerivedArgList *TranslateArgs(const DerivedArgList &Args, const char *BoundArch) const { return 0; } /// SelectTool - Choose a tool to use to handle the action \arg JA with the /// given \arg Inputs. virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const = 0; // Helper methods std::string GetFilePath(const char *Name) const; std::string GetProgramPath(const char *Name, bool WantFile = false) const; // Platform defaults information /// HasNativeLTOLinker - Check whether the linker and related tools have /// native LLVM support. virtual bool HasNativeLLVMSupport() const; /// LookupTypeForExtension - Return the default language type to use for the /// given extension. virtual types::ID LookupTypeForExtension(const char *Ext) const; /// IsBlocksDefault - Does this tool chain enable -fblocks by default. virtual bool IsBlocksDefault() const { return false; } /// IsIntegratedAssemblerDefault - Does this tool chain enable -integrated-as /// by default. virtual bool IsIntegratedAssemblerDefault() const { return false; } /// IsStrictAliasingDefault - Does this tool chain use -fstrict-aliasing by /// default. virtual bool IsStrictAliasingDefault() const { return true; } /// IsObjCDefaultSynthPropertiesDefault - Does this tool chain enable /// -fobjc-default-synthesize-properties by default. virtual bool IsObjCDefaultSynthPropertiesDefault() const { return false; } /// IsObjCNonFragileABIDefault - Does this tool chain set /// -fobjc-nonfragile-abi by default. virtual bool IsObjCNonFragileABIDefault() const { return false; } /// IsObjCLegacyDispatchDefault - Does this tool chain set /// -fobjc-legacy-dispatch by default (this is only used with the non-fragile /// ABI). virtual bool IsObjCLegacyDispatchDefault() const { return false; } /// UseObjCMixedDispatchDefault - When using non-legacy dispatch, should the /// mixed dispatch method be used? virtual bool UseObjCMixedDispatch() const { return false; } /// GetDefaultStackProtectorLevel - Get the default stack protector level for /// this tool chain (0=off, 1=on, 2=all). virtual unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const { return 0; } /// IsUnwindTablesDefault - Does this tool chain use -funwind-tables /// by default. virtual bool IsUnwindTablesDefault() const = 0; /// GetDefaultRelocationModel - Return the LLVM name of the default /// relocation model for this tool chain. virtual const char *GetDefaultRelocationModel() const = 0; /// GetForcedPicModel - Return the LLVM name of the forced PIC model /// for this tool chain, or 0 if this tool chain does not force a /// particular PIC mode. virtual const char *GetForcedPicModel() const = 0; /// SupportsProfiling - Does this tool chain support -pg. virtual bool SupportsProfiling() const { return true; } /// Does this tool chain support Objective-C garbage collection. virtual bool SupportsObjCGC() const { return true; } /// UseDwarfDebugFlags - Embed the compile options to clang into the Dwarf /// compile unit information. virtual bool UseDwarfDebugFlags() const { return false; } /// UseSjLjExceptions - Does this tool chain use SjLj exceptions. virtual bool UseSjLjExceptions() const { return false; } /// ComputeLLVMTriple - Return the LLVM target triple to use, after taking /// command line arguments into account. virtual std::string ComputeLLVMTriple(const ArgList &Args, types::ID InputType = types::TY_INVALID) const; /// ComputeEffectiveClangTriple - Return the Clang triple to use for this /// target, which may take into account the command line arguments. For /// example, on Darwin the -mmacosx-version-min= command line argument (which /// sets the deployment target) determines the version in the triple passed to /// Clang. virtual std::string ComputeEffectiveClangTriple(const ArgList &Args, types::ID InputType = types::TY_INVALID) const; /// configureObjCRuntime - Configure the known properties of the /// Objective-C runtime for this platform. /// /// FIXME: this really belongs on some sort of DeploymentTarget abstraction virtual void configureObjCRuntime(ObjCRuntime &runtime) const; /// hasBlocksRuntime - Given that the user is compiling with /// -fblocks, does this tool chain guarantee the existence of a /// blocks runtime? /// /// FIXME: this really belongs on some sort of DeploymentTarget abstraction virtual bool hasBlocksRuntime() const { return true; } + /// \brief Add the clang cc1 arguments for system include paths. + /// + /// This routine is responsible for adding the necessary cc1 arguments to + /// include headers from standard system header directories. + virtual void AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const; + // GetCXXStdlibType - Determine the C++ standard library type to use with the // given compilation arguments. virtual CXXStdlibType GetCXXStdlibType(const ArgList &Args) const; /// AddClangCXXStdlibIncludeArgs - Add the clang -cc1 level arguments to set /// the include paths to use for the given C++ standard library type. - virtual void AddClangCXXStdlibIncludeArgs(const ArgList &Args, - ArgStringList &CmdArgs, - bool ObjCXXAutoRefCount) const; + virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const; /// AddCXXStdlibLibArgs - Add the system specific linker arguments to use /// for the given C++ standard library type. virtual void AddCXXStdlibLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const; /// AddCCKextLibArgs - Add the system specific linker arguments to use /// for kernel extensions (Darwin-specific). virtual void AddCCKextLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const; }; } // end namespace driver } // end namespace clang #endif Index: head/contrib/llvm/tools/clang/include/clang/Frontend/HeaderSearchOptions.h =================================================================== --- head/contrib/llvm/tools/clang/include/clang/Frontend/HeaderSearchOptions.h (revision 228378) +++ head/contrib/llvm/tools/clang/include/clang/Frontend/HeaderSearchOptions.h (revision 228379) @@ -1,109 +1,124 @@ //===--- HeaderSearchOptions.h ----------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_FRONTEND_HEADERSEARCHOPTIONS_H #define LLVM_CLANG_FRONTEND_HEADERSEARCHOPTIONS_H #include "llvm/ADT/StringRef.h" #include namespace clang { namespace frontend { /// IncludeDirGroup - Identifiers the group a include entry belongs to, which /// represents its relative positive in the search list. A #include of a "" /// path starts at the -iquote group, then searches the Angled group, then /// searches the system group, etc. enum IncludeDirGroup { Quoted = 0, ///< '#include ""' paths, added by'gcc -iquote'. Angled, ///< Paths for '#include <>' added by '-I'. IndexHeaderMap, ///< Like Angled, but marks header maps used when /// building frameworks. System, ///< Like Angled, but marks system directories. CSystem, ///< Like System, but only used for C. CXXSystem, ///< Like System, but only used for C++. ObjCSystem, ///< Like System, but only used for ObjC. ObjCXXSystem, ///< Like System, but only used for ObjC++. After ///< Like System, but searched after the system directories. }; } /// HeaderSearchOptions - Helper class for storing options related to the /// initialization of the HeaderSearch object. class HeaderSearchOptions { public: struct Entry { std::string Path; frontend::IncludeDirGroup Group; unsigned IsUserSupplied : 1; unsigned IsFramework : 1; /// IgnoreSysRoot - This is false if an absolute path should be treated /// relative to the sysroot, or true if it should always be the absolute /// path. unsigned IgnoreSysRoot : 1; + /// \brief True if this entry is an internal search path. + /// + /// This typically indicates that users didn't directly provide it, but + /// instead it was provided by a compatibility layer for a particular + /// system. This isn't redundant with IsUserSupplied (even though perhaps + /// it should be) because that is false for user provided '-iwithprefix' + /// header search entries. + unsigned IsInternal : 1; + + /// \brief True if this entry's headers should be wrapped in extern "C". + unsigned ImplicitExternC : 1; + Entry(StringRef path, frontend::IncludeDirGroup group, - bool isUserSupplied, bool isFramework, bool ignoreSysRoot) + bool isUserSupplied, bool isFramework, bool ignoreSysRoot, + bool isInternal, bool implicitExternC) : Path(path), Group(group), IsUserSupplied(isUserSupplied), - IsFramework(isFramework), IgnoreSysRoot(ignoreSysRoot) {} + IsFramework(isFramework), IgnoreSysRoot(ignoreSysRoot), + IsInternal(isInternal), ImplicitExternC(implicitExternC) {} }; /// If non-empty, the directory to use as a "virtual system root" for include /// paths. std::string Sysroot; /// User specified include entries. std::vector UserEntries; /// The directory which holds the compiler resource files (builtin includes, /// etc.). std::string ResourceDir; /// \brief The directory used for the module cache. std::string ModuleCachePath; /// \brief Whether we should disable the use of the hash string within the /// module cache. /// /// Note: Only used for testing! unsigned DisableModuleHash : 1; /// Include the compiler builtin includes. unsigned UseBuiltinIncludes : 1; /// Include the system standard include search directories. unsigned UseStandardSystemIncludes : 1; /// Include the system standard C++ library include search directories. unsigned UseStandardCXXIncludes : 1; /// Use libc++ instead of the default libstdc++. unsigned UseLibcxx : 1; /// Whether header search information should be output as for -v. unsigned Verbose : 1; public: HeaderSearchOptions(StringRef _Sysroot = "/") : Sysroot(_Sysroot), DisableModuleHash(0), UseBuiltinIncludes(true), UseStandardSystemIncludes(true), UseStandardCXXIncludes(true), UseLibcxx(false), Verbose(false) {} /// AddPath - Add the \arg Path path to the specified \arg Group list. void AddPath(StringRef Path, frontend::IncludeDirGroup Group, - bool IsUserSupplied, bool IsFramework, bool IgnoreSysRoot) { + bool IsUserSupplied, bool IsFramework, bool IgnoreSysRoot, + bool IsInternal = false, bool ImplicitExternC = false) { UserEntries.push_back(Entry(Path, Group, IsUserSupplied, IsFramework, - IgnoreSysRoot)); + IgnoreSysRoot, IsInternal, ImplicitExternC)); } }; } // end namespace clang #endif Index: head/contrib/llvm/tools/clang/lib/Basic/Version.cpp =================================================================== --- head/contrib/llvm/tools/clang/lib/Basic/Version.cpp (revision 228378) +++ head/contrib/llvm/tools/clang/lib/Basic/Version.cpp (revision 228379) @@ -1,108 +1,108 @@ //===- Version.cpp - Clang Version Number -----------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines several version-related utility functions for Clang. // //===----------------------------------------------------------------------===// #include "clang/Basic/Version.h" #include "clang/Basic/LLVM.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Config/config.h" #include #include namespace clang { std::string getClangRepositoryPath() { #if defined(CLANG_REPOSITORY_STRING) return CLANG_REPOSITORY_STRING; #else #ifdef SVN_REPOSITORY StringRef URL(SVN_REPOSITORY); #else StringRef URL(""); #endif // If the SVN_REPOSITORY is empty, try to use the SVN keyword. This helps us // pick up a tag in an SVN export, for example. - static StringRef SVNRepository("$URL: http://llvm.org/svn/llvm-project/cfe/branches/release_30/lib/Basic/Version.cpp $"); + static StringRef SVNRepository("$URL: http://llvm.org/svn/llvm-project/cfe/tags/RELEASE_30/final/lib/Basic/Version.cpp $"); if (URL.empty()) { URL = SVNRepository.slice(SVNRepository.find(':'), SVNRepository.find("/lib/Basic")); } // Strip off version from a build from an integration branch. URL = URL.slice(0, URL.find("/src/tools/clang")); // Trim path prefix off, assuming path came from standard cfe path. size_t Start = URL.find("cfe/"); if (Start != StringRef::npos) URL = URL.substr(Start + 4); return URL; #endif } std::string getClangRevision() { #ifdef SVN_REVISION return SVN_REVISION; #else return ""; #endif } std::string getClangFullRepositoryVersion() { std::string buf; llvm::raw_string_ostream OS(buf); std::string Path = getClangRepositoryPath(); std::string Revision = getClangRevision(); if (!Path.empty()) OS << Path; if (!Revision.empty()) { if (!Path.empty()) OS << ' '; OS << Revision; } return OS.str(); } std::string getClangFullVersion() { std::string buf; llvm::raw_string_ostream OS(buf); #ifdef CLANG_VENDOR OS << CLANG_VENDOR; #endif OS << "clang version " CLANG_VERSION_STRING " (" << getClangFullRepositoryVersion() << ')'; #ifdef CLANG_VENDOR_SUFFIX OS << CLANG_VENDOR_SUFFIX; #elif defined(CLANG_VENDOR) // If vendor supplied, include the base LLVM version as well. OS << " (based on LLVM " << PACKAGE_VERSION << ")"; #endif return OS.str(); } std::string getClangFullCPPVersion() { // The version string we report in __VERSION__ is just a compacted version of // the one we report on the command line. std::string buf; llvm::raw_string_ostream OS(buf); #ifdef CLANG_VENDOR OS << CLANG_VENDOR; #endif OS << "Clang " CLANG_VERSION_STRING " (" << getClangFullRepositoryVersion() << ')'; return OS.str(); } } // end namespace clang Index: head/contrib/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp =================================================================== --- head/contrib/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp (revision 228378) +++ head/contrib/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp (revision 228379) @@ -1,2559 +1,2561 @@ //===------- CGObjCGNU.cpp - Emit LLVM Code from ASTs for a Module --------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This provides Objective-C code generation targeting the GNU runtime. The // class in this file generates structures used by the GNU Objective-C runtime // library. These structures are defined in objc/objc.h and objc/objc-api.h in // the GNU runtime distribution. // //===----------------------------------------------------------------------===// #include "CGObjCRuntime.h" #include "CodeGenModule.h" #include "CodeGenFunction.h" #include "CGCleanup.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/StmtObjC.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/FileManager.h" #include "llvm/Intrinsics.h" #include "llvm/Module.h" #include "llvm/LLVMContext.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/Support/CallSite.h" #include "llvm/Support/Compiler.h" #include "llvm/Target/TargetData.h" #include using namespace clang; using namespace CodeGen; namespace { /// Class that lazily initialises the runtime function. Avoids inserting the /// types and the function declaration into a module if they're not used, and /// avoids constructing the type more than once if it's used more than once. class LazyRuntimeFunction { CodeGenModule *CGM; std::vector ArgTys; const char *FunctionName; llvm::Constant *Function; public: /// Constructor leaves this class uninitialized, because it is intended to /// be used as a field in another class and not all of the types that are /// used as arguments will necessarily be available at construction time. LazyRuntimeFunction() : CGM(0), FunctionName(0), Function(0) {} /// Initialises the lazy function with the name, return type, and the types /// of the arguments. END_WITH_NULL void init(CodeGenModule *Mod, const char *name, llvm::Type *RetTy, ...) { CGM =Mod; FunctionName = name; Function = 0; ArgTys.clear(); va_list Args; va_start(Args, RetTy); while (llvm::Type *ArgTy = va_arg(Args, llvm::Type*)) ArgTys.push_back(ArgTy); va_end(Args); // Push the return type on at the end so we can pop it off easily ArgTys.push_back(RetTy); } /// Overloaded cast operator, allows the class to be implicitly cast to an /// LLVM constant. operator llvm::Constant*() { if (!Function) { if (0 == FunctionName) return 0; // We put the return type on the end of the vector, so pop it back off llvm::Type *RetTy = ArgTys.back(); ArgTys.pop_back(); llvm::FunctionType *FTy = llvm::FunctionType::get(RetTy, ArgTys, false); Function = cast(CGM->CreateRuntimeFunction(FTy, FunctionName)); // We won't need to use the types again, so we may as well clean up the // vector now ArgTys.resize(0); } return Function; } operator llvm::Function*() { return cast((llvm::Constant*)*this); } }; /// GNU Objective-C runtime code generation. This class implements the parts of /// Objective-C support that are specific to the GNU family of runtimes (GCC and /// GNUstep). class CGObjCGNU : public CGObjCRuntime { protected: /// The module that is using this class CodeGenModule &CGM; /// The LLVM module into which output is inserted llvm::Module &TheModule; /// strut objc_super. Used for sending messages to super. This structure /// contains the receiver (object) and the expected class. llvm::StructType *ObjCSuperTy; /// struct objc_super*. The type of the argument to the superclass message /// lookup functions. llvm::PointerType *PtrToObjCSuperTy; /// LLVM type for selectors. Opaque pointer (i8*) unless a header declaring /// SEL is included in a header somewhere, in which case it will be whatever /// type is declared in that header, most likely {i8*, i8*}. llvm::PointerType *SelectorTy; /// LLVM i8 type. Cached here to avoid repeatedly getting it in all of the /// places where it's used llvm::IntegerType *Int8Ty; /// Pointer to i8 - LLVM type of char*, for all of the places where the /// runtime needs to deal with C strings. llvm::PointerType *PtrToInt8Ty; /// Instance Method Pointer type. This is a pointer to a function that takes, /// at a minimum, an object and a selector, and is the generic type for /// Objective-C methods. Due to differences between variadic / non-variadic /// calling conventions, it must always be cast to the correct type before /// actually being used. llvm::PointerType *IMPTy; /// Type of an untyped Objective-C object. Clang treats id as a built-in type /// when compiling Objective-C code, so this may be an opaque pointer (i8*), /// but if the runtime header declaring it is included then it may be a /// pointer to a structure. llvm::PointerType *IdTy; /// Pointer to a pointer to an Objective-C object. Used in the new ABI /// message lookup function and some GC-related functions. llvm::PointerType *PtrToIdTy; /// The clang type of id. Used when using the clang CGCall infrastructure to /// call Objective-C methods. CanQualType ASTIdTy; /// LLVM type for C int type. llvm::IntegerType *IntTy; /// LLVM type for an opaque pointer. This is identical to PtrToInt8Ty, but is /// used in the code to document the difference between i8* meaning a pointer /// to a C string and i8* meaning a pointer to some opaque type. llvm::PointerType *PtrTy; /// LLVM type for C long type. The runtime uses this in a lot of places where /// it should be using intptr_t, but we can't fix this without breaking /// compatibility with GCC... llvm::IntegerType *LongTy; /// LLVM type for C size_t. Used in various runtime data structures. llvm::IntegerType *SizeTy; /// LLVM type for C intptr_t. llvm::IntegerType *IntPtrTy; /// LLVM type for C ptrdiff_t. Mainly used in property accessor functions. llvm::IntegerType *PtrDiffTy; /// LLVM type for C int*. Used for GCC-ABI-compatible non-fragile instance /// variables. llvm::PointerType *PtrToIntTy; /// LLVM type for Objective-C BOOL type. llvm::Type *BoolTy; /// 32-bit integer type, to save us needing to look it up every time it's used. llvm::IntegerType *Int32Ty; /// 64-bit integer type, to save us needing to look it up every time it's used. llvm::IntegerType *Int64Ty; /// Metadata kind used to tie method lookups to message sends. The GNUstep /// runtime provides some LLVM passes that can use this to do things like /// automatic IMP caching and speculative inlining. unsigned msgSendMDKind; /// Helper function that generates a constant string and returns a pointer to /// the start of the string. The result of this function can be used anywhere /// where the C code specifies const char*. llvm::Constant *MakeConstantString(const std::string &Str, const std::string &Name="") { llvm::Constant *ConstStr = CGM.GetAddrOfConstantCString(Str, Name.c_str()); return llvm::ConstantExpr::getGetElementPtr(ConstStr, Zeros); } /// Emits a linkonce_odr string, whose name is the prefix followed by the /// string value. This allows the linker to combine the strings between /// different modules. Used for EH typeinfo names, selector strings, and a /// few other things. llvm::Constant *ExportUniqueString(const std::string &Str, const std::string prefix) { std::string name = prefix + Str; llvm::Constant *ConstStr = TheModule.getGlobalVariable(name); if (!ConstStr) { llvm::Constant *value = llvm::ConstantArray::get(VMContext, Str, true); ConstStr = new llvm::GlobalVariable(TheModule, value->getType(), true, llvm::GlobalValue::LinkOnceODRLinkage, value, prefix + Str); } return llvm::ConstantExpr::getGetElementPtr(ConstStr, Zeros); } /// Generates a global structure, initialized by the elements in the vector. /// The element types must match the types of the structure elements in the /// first argument. llvm::GlobalVariable *MakeGlobal(llvm::StructType *Ty, llvm::ArrayRef V, StringRef Name="", llvm::GlobalValue::LinkageTypes linkage =llvm::GlobalValue::InternalLinkage) { llvm::Constant *C = llvm::ConstantStruct::get(Ty, V); return new llvm::GlobalVariable(TheModule, Ty, false, linkage, C, Name); } /// Generates a global array. The vector must contain the same number of /// elements that the array type declares, of the type specified as the array /// element type. llvm::GlobalVariable *MakeGlobal(llvm::ArrayType *Ty, llvm::ArrayRef V, StringRef Name="", llvm::GlobalValue::LinkageTypes linkage =llvm::GlobalValue::InternalLinkage) { llvm::Constant *C = llvm::ConstantArray::get(Ty, V); return new llvm::GlobalVariable(TheModule, Ty, false, linkage, C, Name); } /// Generates a global array, inferring the array type from the specified /// element type and the size of the initialiser. llvm::GlobalVariable *MakeGlobalArray(llvm::Type *Ty, llvm::ArrayRef V, StringRef Name="", llvm::GlobalValue::LinkageTypes linkage =llvm::GlobalValue::InternalLinkage) { llvm::ArrayType *ArrayTy = llvm::ArrayType::get(Ty, V.size()); return MakeGlobal(ArrayTy, V, Name, linkage); } /// Ensures that the value has the required type, by inserting a bitcast if /// required. This function lets us avoid inserting bitcasts that are /// redundant. llvm::Value* EnforceType(CGBuilderTy B, llvm::Value *V, llvm::Type *Ty){ if (V->getType() == Ty) return V; return B.CreateBitCast(V, Ty); } // Some zeros used for GEPs in lots of places. llvm::Constant *Zeros[2]; /// Null pointer value. Mainly used as a terminator in various arrays. llvm::Constant *NULLPtr; /// LLVM context. llvm::LLVMContext &VMContext; private: /// Placeholder for the class. Lots of things refer to the class before we've /// actually emitted it. We use this alias as a placeholder, and then replace /// it with a pointer to the class structure before finally emitting the /// module. llvm::GlobalAlias *ClassPtrAlias; /// Placeholder for the metaclass. Lots of things refer to the class before /// we've / actually emitted it. We use this alias as a placeholder, and then /// replace / it with a pointer to the metaclass structure before finally /// emitting the / module. llvm::GlobalAlias *MetaClassPtrAlias; /// All of the classes that have been generated for this compilation units. std::vector Classes; /// All of the categories that have been generated for this compilation units. std::vector Categories; /// All of the Objective-C constant strings that have been generated for this /// compilation units. std::vector ConstantStrings; /// Map from string values to Objective-C constant strings in the output. /// Used to prevent emitting Objective-C strings more than once. This should /// not be required at all - CodeGenModule should manage this list. llvm::StringMap ObjCStrings; /// All of the protocols that have been declared. llvm::StringMap ExistingProtocols; /// For each variant of a selector, we store the type encoding and a /// placeholder value. For an untyped selector, the type will be the empty /// string. Selector references are all done via the module's selector table, /// so we create an alias as a placeholder and then replace it with the real /// value later. typedef std::pair TypedSelector; /// Type of the selector map. This is roughly equivalent to the structure /// used in the GNUstep runtime, which maintains a list of all of the valid /// types for a selector in a table. typedef llvm::DenseMap > SelectorMap; /// A map from selectors to selector types. This allows us to emit all /// selectors of the same name and type together. SelectorMap SelectorTable; /// Selectors related to memory management. When compiling in GC mode, we /// omit these. Selector RetainSel, ReleaseSel, AutoreleaseSel; /// Runtime functions used for memory management in GC mode. Note that clang /// supports code generation for calling these functions, but neither GNU /// runtime actually supports this API properly yet. LazyRuntimeFunction IvarAssignFn, StrongCastAssignFn, MemMoveFn, WeakReadFn, WeakAssignFn, GlobalAssignFn; protected: /// Function used for throwing Objective-C exceptions. LazyRuntimeFunction ExceptionThrowFn; /// Function used for rethrowing exceptions, used at the end of @finally or /// @synchronize blocks. LazyRuntimeFunction ExceptionReThrowFn; /// Function called when entering a catch function. This is required for /// differentiating Objective-C exceptions and foreign exceptions. LazyRuntimeFunction EnterCatchFn; /// Function called when exiting from a catch block. Used to do exception /// cleanup. LazyRuntimeFunction ExitCatchFn; /// Function called when entering an @synchronize block. Acquires the lock. LazyRuntimeFunction SyncEnterFn; /// Function called when exiting an @synchronize block. Releases the lock. LazyRuntimeFunction SyncExitFn; private: /// Function called if fast enumeration detects that the collection is /// modified during the update. LazyRuntimeFunction EnumerationMutationFn; /// Function for implementing synthesized property getters that return an /// object. LazyRuntimeFunction GetPropertyFn; /// Function for implementing synthesized property setters that return an /// object. LazyRuntimeFunction SetPropertyFn; /// Function used for non-object declared property getters. LazyRuntimeFunction GetStructPropertyFn; /// Function used for non-object declared property setters. LazyRuntimeFunction SetStructPropertyFn; /// The version of the runtime that this class targets. Must match the /// version in the runtime. int RuntimeVersion; /// The version of the protocol class. Used to differentiate between ObjC1 /// and ObjC2 protocols. Objective-C 1 protocols can not contain optional /// components and can not contain declared properties. We always emit /// Objective-C 2 property structures, but we have to pretend that they're /// Objective-C 1 property structures when targeting the GCC runtime or it /// will abort. const int ProtocolVersion; private: /// Generates an instance variable list structure. This is a structure /// containing a size and an array of structures containing instance variable /// metadata. This is used purely for introspection in the fragile ABI. In /// the non-fragile ABI, it's used for instance variable fixup. llvm::Constant *GenerateIvarList( const SmallVectorImpl &IvarNames, const SmallVectorImpl &IvarTypes, const SmallVectorImpl &IvarOffsets); /// Generates a method list structure. This is a structure containing a size /// and an array of structures containing method metadata. /// /// This structure is used by both classes and categories, and contains a next /// pointer allowing them to be chained together in a linked list. llvm::Constant *GenerateMethodList(const StringRef &ClassName, const StringRef &CategoryName, const SmallVectorImpl &MethodSels, const SmallVectorImpl &MethodTypes, bool isClassMethodList); /// Emits an empty protocol. This is used for @protocol() where no protocol /// is found. The runtime will (hopefully) fix up the pointer to refer to the /// real protocol. llvm::Constant *GenerateEmptyProtocol(const std::string &ProtocolName); /// Generates a list of property metadata structures. This follows the same /// pattern as method and instance variable metadata lists. llvm::Constant *GeneratePropertyList(const ObjCImplementationDecl *OID, SmallVectorImpl &InstanceMethodSels, SmallVectorImpl &InstanceMethodTypes); /// Generates a list of referenced protocols. Classes, categories, and /// protocols all use this structure. llvm::Constant *GenerateProtocolList( const SmallVectorImpl &Protocols); /// To ensure that all protocols are seen by the runtime, we add a category on /// a class defined in the runtime, declaring no methods, but adopting the /// protocols. This is a horribly ugly hack, but it allows us to collect all /// of the protocols without changing the ABI. void GenerateProtocolHolderCategory(void); /// Generates a class structure. llvm::Constant *GenerateClassStructure( llvm::Constant *MetaClass, llvm::Constant *SuperClass, unsigned info, const char *Name, llvm::Constant *Version, llvm::Constant *InstanceSize, llvm::Constant *IVars, llvm::Constant *Methods, llvm::Constant *Protocols, llvm::Constant *IvarOffsets, llvm::Constant *Properties, llvm::Constant *StrongIvarBitmap, llvm::Constant *WeakIvarBitmap, bool isMeta=false); /// Generates a method list. This is used by protocols to define the required /// and optional methods. llvm::Constant *GenerateProtocolMethodList( const SmallVectorImpl &MethodNames, const SmallVectorImpl &MethodTypes); /// Returns a selector with the specified type encoding. An empty string is /// used to return an untyped selector (with the types field set to NULL). llvm::Value *GetSelector(CGBuilderTy &Builder, Selector Sel, const std::string &TypeEncoding, bool lval); /// Returns the variable used to store the offset of an instance variable. llvm::GlobalVariable *ObjCIvarOffsetVariable(const ObjCInterfaceDecl *ID, const ObjCIvarDecl *Ivar); /// Emits a reference to a class. This allows the linker to object if there /// is no class of the matching name. void EmitClassRef(const std::string &className); /// Emits a pointer to the named class llvm::Value *GetClassNamed(CGBuilderTy &Builder, const std::string &Name, bool isWeak); protected: /// Looks up the method for sending a message to the specified object. This /// mechanism differs between the GCC and GNU runtimes, so this method must be /// overridden in subclasses. virtual llvm::Value *LookupIMP(CodeGenFunction &CGF, llvm::Value *&Receiver, llvm::Value *cmd, llvm::MDNode *node) = 0; /// Looks up the method for sending a message to a superclass. This /// mechanism differs between the GCC and GNU runtimes, so this method must /// be overridden in subclasses. virtual llvm::Value *LookupIMPSuper(CodeGenFunction &CGF, llvm::Value *ObjCSuper, llvm::Value *cmd) = 0; /// Libobjc2 uses a bitfield representation where small(ish) bitfields are /// stored in a 64-bit value with the low bit set to 1 and the remaining 63 /// bits set to their values, LSB first, while larger ones are stored in a /// structure of this / form: /// /// struct { int32_t length; int32_t values[length]; }; /// /// The values in the array are stored in host-endian format, with the least /// significant bit being assumed to come first in the bitfield. Therefore, /// a bitfield with the 64th bit set will be (int64_t)&{ 2, [0, 1<<31] }, /// while a bitfield / with the 63rd bit set will be 1<<64. llvm::Constant *MakeBitField(llvm::SmallVectorImpl &bits); public: CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion, unsigned protocolClassVersion); virtual llvm::Constant *GenerateConstantString(const StringLiteral *); virtual RValue GenerateMessageSend(CodeGenFunction &CGF, ReturnValueSlot Return, QualType ResultType, Selector Sel, llvm::Value *Receiver, const CallArgList &CallArgs, const ObjCInterfaceDecl *Class, const ObjCMethodDecl *Method); virtual RValue GenerateMessageSendSuper(CodeGenFunction &CGF, ReturnValueSlot Return, QualType ResultType, Selector Sel, const ObjCInterfaceDecl *Class, bool isCategoryImpl, llvm::Value *Receiver, bool IsClassMessage, const CallArgList &CallArgs, const ObjCMethodDecl *Method); virtual llvm::Value *GetClass(CGBuilderTy &Builder, const ObjCInterfaceDecl *OID); virtual llvm::Value *GetSelector(CGBuilderTy &Builder, Selector Sel, bool lval = false); virtual llvm::Value *GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl *Method); virtual llvm::Constant *GetEHType(QualType T); virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD, const ObjCContainerDecl *CD); virtual void GenerateCategory(const ObjCCategoryImplDecl *CMD); virtual void GenerateClass(const ObjCImplementationDecl *ClassDecl); virtual llvm::Value *GenerateProtocolRef(CGBuilderTy &Builder, const ObjCProtocolDecl *PD); virtual void GenerateProtocol(const ObjCProtocolDecl *PD); virtual llvm::Function *ModuleInitFunction(); virtual llvm::Constant *GetPropertyGetFunction(); virtual llvm::Constant *GetPropertySetFunction(); virtual llvm::Constant *GetSetStructFunction(); virtual llvm::Constant *GetGetStructFunction(); virtual llvm::Constant *EnumerationMutationFunction(); virtual void EmitTryStmt(CodeGenFunction &CGF, const ObjCAtTryStmt &S); virtual void EmitSynchronizedStmt(CodeGenFunction &CGF, const ObjCAtSynchronizedStmt &S); virtual void EmitThrowStmt(CodeGenFunction &CGF, const ObjCAtThrowStmt &S); virtual llvm::Value * EmitObjCWeakRead(CodeGenFunction &CGF, llvm::Value *AddrWeakObj); virtual void EmitObjCWeakAssign(CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst); virtual void EmitObjCGlobalAssign(CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dest, bool threadlocal=false); virtual void EmitObjCIvarAssign(CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dest, llvm::Value *ivarOffset); virtual void EmitObjCStrongCastAssign(CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dest); virtual void EmitGCMemmoveCollectable(CodeGenFunction &CGF, llvm::Value *DestPtr, llvm::Value *SrcPtr, llvm::Value *Size); virtual LValue EmitObjCValueForIvar(CodeGenFunction &CGF, QualType ObjectTy, llvm::Value *BaseValue, const ObjCIvarDecl *Ivar, unsigned CVRQualifiers); virtual llvm::Value *EmitIvarOffset(CodeGenFunction &CGF, const ObjCInterfaceDecl *Interface, const ObjCIvarDecl *Ivar); virtual llvm::Value *EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder); virtual llvm::Constant *BuildGCBlockLayout(CodeGenModule &CGM, const CGBlockInfo &blockInfo) { return NULLPtr; } virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) { return 0; } }; /// Class representing the legacy GCC Objective-C ABI. This is the default when /// -fobjc-nonfragile-abi is not specified. /// /// The GCC ABI target actually generates code that is approximately compatible /// with the new GNUstep runtime ABI, but refrains from using any features that /// would not work with the GCC runtime. For example, clang always generates /// the extended form of the class structure, and the extra fields are simply /// ignored by GCC libobjc. class CGObjCGCC : public CGObjCGNU { /// The GCC ABI message lookup function. Returns an IMP pointing to the /// method implementation for this message. LazyRuntimeFunction MsgLookupFn; /// The GCC ABI superclass message lookup function. Takes a pointer to a /// structure describing the receiver and the class, and a selector as /// arguments. Returns the IMP for the corresponding method. LazyRuntimeFunction MsgLookupSuperFn; protected: virtual llvm::Value *LookupIMP(CodeGenFunction &CGF, llvm::Value *&Receiver, llvm::Value *cmd, llvm::MDNode *node) { CGBuilderTy &Builder = CGF.Builder; - llvm::Value *imp = Builder.CreateCall2(MsgLookupFn, - EnforceType(Builder, Receiver, IdTy), - EnforceType(Builder, cmd, SelectorTy)); - cast(imp)->setMetadata(msgSendMDKind, node); - return imp; + llvm::Value *args[] = { + EnforceType(Builder, Receiver, IdTy), + EnforceType(Builder, cmd, SelectorTy) }; + llvm::CallSite imp = CGF.EmitCallOrInvoke(MsgLookupFn, args); + imp->setMetadata(msgSendMDKind, node); + return imp.getInstruction(); } virtual llvm::Value *LookupIMPSuper(CodeGenFunction &CGF, llvm::Value *ObjCSuper, llvm::Value *cmd) { CGBuilderTy &Builder = CGF.Builder; llvm::Value *lookupArgs[] = {EnforceType(Builder, ObjCSuper, PtrToObjCSuperTy), cmd}; return Builder.CreateCall(MsgLookupSuperFn, lookupArgs); } public: CGObjCGCC(CodeGenModule &Mod) : CGObjCGNU(Mod, 8, 2) { // IMP objc_msg_lookup(id, SEL); MsgLookupFn.init(&CGM, "objc_msg_lookup", IMPTy, IdTy, SelectorTy, NULL); // IMP objc_msg_lookup_super(struct objc_super*, SEL); MsgLookupSuperFn.init(&CGM, "objc_msg_lookup_super", IMPTy, PtrToObjCSuperTy, SelectorTy, NULL); } }; /// Class used when targeting the new GNUstep runtime ABI. class CGObjCGNUstep : public CGObjCGNU { /// The slot lookup function. Returns a pointer to a cacheable structure /// that contains (among other things) the IMP. LazyRuntimeFunction SlotLookupFn; /// The GNUstep ABI superclass message lookup function. Takes a pointer to /// a structure describing the receiver and the class, and a selector as /// arguments. Returns the slot for the corresponding method. Superclass /// message lookup rarely changes, so this is a good caching opportunity. LazyRuntimeFunction SlotLookupSuperFn; /// Type of an slot structure pointer. This is returned by the various /// lookup functions. llvm::Type *SlotTy; protected: virtual llvm::Value *LookupIMP(CodeGenFunction &CGF, llvm::Value *&Receiver, llvm::Value *cmd, llvm::MDNode *node) { CGBuilderTy &Builder = CGF.Builder; llvm::Function *LookupFn = SlotLookupFn; // Store the receiver on the stack so that we can reload it later llvm::Value *ReceiverPtr = CGF.CreateTempAlloca(Receiver->getType()); Builder.CreateStore(Receiver, ReceiverPtr); llvm::Value *self; if (isa(CGF.CurCodeDecl)) { self = CGF.LoadObjCSelf(); } else { self = llvm::ConstantPointerNull::get(IdTy); } // The lookup function is guaranteed not to capture the receiver pointer. LookupFn->setDoesNotCapture(1); - llvm::CallInst *slot = - Builder.CreateCall3(LookupFn, - EnforceType(Builder, ReceiverPtr, PtrToIdTy), - EnforceType(Builder, cmd, SelectorTy), - EnforceType(Builder, self, IdTy)); - slot->setOnlyReadsMemory(); + llvm::Value *args[] = { + EnforceType(Builder, ReceiverPtr, PtrToIdTy), + EnforceType(Builder, cmd, SelectorTy), + EnforceType(Builder, self, IdTy) }; + llvm::CallSite slot = CGF.EmitCallOrInvoke(LookupFn, args); + slot.setOnlyReadsMemory(); slot->setMetadata(msgSendMDKind, node); // Load the imp from the slot - llvm::Value *imp = Builder.CreateLoad(Builder.CreateStructGEP(slot, 4)); + llvm::Value *imp = + Builder.CreateLoad(Builder.CreateStructGEP(slot.getInstruction(), 4)); // The lookup function may have changed the receiver, so make sure we use // the new one. Receiver = Builder.CreateLoad(ReceiverPtr, true); return imp; } virtual llvm::Value *LookupIMPSuper(CodeGenFunction &CGF, llvm::Value *ObjCSuper, llvm::Value *cmd) { CGBuilderTy &Builder = CGF.Builder; llvm::Value *lookupArgs[] = {ObjCSuper, cmd}; llvm::CallInst *slot = Builder.CreateCall(SlotLookupSuperFn, lookupArgs); slot->setOnlyReadsMemory(); return Builder.CreateLoad(Builder.CreateStructGEP(slot, 4)); } public: CGObjCGNUstep(CodeGenModule &Mod) : CGObjCGNU(Mod, 9, 3) { llvm::StructType *SlotStructTy = llvm::StructType::get(PtrTy, PtrTy, PtrTy, IntTy, IMPTy, NULL); SlotTy = llvm::PointerType::getUnqual(SlotStructTy); // Slot_t objc_msg_lookup_sender(id *receiver, SEL selector, id sender); SlotLookupFn.init(&CGM, "objc_msg_lookup_sender", SlotTy, PtrToIdTy, SelectorTy, IdTy, NULL); // Slot_t objc_msg_lookup_super(struct objc_super*, SEL); SlotLookupSuperFn.init(&CGM, "objc_slot_lookup_super", SlotTy, PtrToObjCSuperTy, SelectorTy, NULL); // If we're in ObjC++ mode, then we want to make if (CGM.getLangOptions().CPlusPlus) { llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext); // void *__cxa_begin_catch(void *e) EnterCatchFn.init(&CGM, "__cxa_begin_catch", PtrTy, PtrTy, NULL); // void __cxa_end_catch(void) ExitCatchFn.init(&CGM, "__cxa_end_catch", VoidTy, NULL); // void _Unwind_Resume_or_Rethrow(void*) ExceptionReThrowFn.init(&CGM, "_Unwind_Resume_or_Rethrow", VoidTy, PtrTy, NULL); } } }; } // end anonymous namespace /// Emits a reference to a dummy variable which is emitted with each class. /// This ensures that a linker error will be generated when trying to link /// together modules where a referenced class is not defined. void CGObjCGNU::EmitClassRef(const std::string &className) { std::string symbolRef = "__objc_class_ref_" + className; // Don't emit two copies of the same symbol if (TheModule.getGlobalVariable(symbolRef)) return; std::string symbolName = "__objc_class_name_" + className; llvm::GlobalVariable *ClassSymbol = TheModule.getGlobalVariable(symbolName); if (!ClassSymbol) { ClassSymbol = new llvm::GlobalVariable(TheModule, LongTy, false, llvm::GlobalValue::ExternalLinkage, 0, symbolName); } new llvm::GlobalVariable(TheModule, ClassSymbol->getType(), true, llvm::GlobalValue::WeakAnyLinkage, ClassSymbol, symbolRef); } static std::string SymbolNameForMethod(const StringRef &ClassName, const StringRef &CategoryName, const Selector MethodName, bool isClassMethod) { std::string MethodNameColonStripped = MethodName.getAsString(); std::replace(MethodNameColonStripped.begin(), MethodNameColonStripped.end(), ':', '_'); return (Twine(isClassMethod ? "_c_" : "_i_") + ClassName + "_" + CategoryName + "_" + MethodNameColonStripped).str(); } CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion, unsigned protocolClassVersion) : CGM(cgm), TheModule(CGM.getModule()), VMContext(cgm.getLLVMContext()), ClassPtrAlias(0), MetaClassPtrAlias(0), RuntimeVersion(runtimeABIVersion), ProtocolVersion(protocolClassVersion) { msgSendMDKind = VMContext.getMDKindID("GNUObjCMessageSend"); CodeGenTypes &Types = CGM.getTypes(); IntTy = cast( Types.ConvertType(CGM.getContext().IntTy)); LongTy = cast( Types.ConvertType(CGM.getContext().LongTy)); SizeTy = cast( Types.ConvertType(CGM.getContext().getSizeType())); PtrDiffTy = cast( Types.ConvertType(CGM.getContext().getPointerDiffType())); BoolTy = CGM.getTypes().ConvertType(CGM.getContext().BoolTy); Int8Ty = llvm::Type::getInt8Ty(VMContext); // C string type. Used in lots of places. PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); Zeros[0] = llvm::ConstantInt::get(LongTy, 0); Zeros[1] = Zeros[0]; NULLPtr = llvm::ConstantPointerNull::get(PtrToInt8Ty); // Get the selector Type. QualType selTy = CGM.getContext().getObjCSelType(); if (QualType() == selTy) { SelectorTy = PtrToInt8Ty; } else { SelectorTy = cast(CGM.getTypes().ConvertType(selTy)); } PtrToIntTy = llvm::PointerType::getUnqual(IntTy); PtrTy = PtrToInt8Ty; Int32Ty = llvm::Type::getInt32Ty(VMContext); Int64Ty = llvm::Type::getInt64Ty(VMContext); IntPtrTy = TheModule.getPointerSize() == llvm::Module::Pointer32 ? Int32Ty : Int64Ty; // Object type QualType UnqualIdTy = CGM.getContext().getObjCIdType(); ASTIdTy = CanQualType(); if (UnqualIdTy != QualType()) { ASTIdTy = CGM.getContext().getCanonicalType(UnqualIdTy); IdTy = cast(CGM.getTypes().ConvertType(ASTIdTy)); } else { IdTy = PtrToInt8Ty; } PtrToIdTy = llvm::PointerType::getUnqual(IdTy); ObjCSuperTy = llvm::StructType::get(IdTy, IdTy, NULL); PtrToObjCSuperTy = llvm::PointerType::getUnqual(ObjCSuperTy); llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext); // void objc_exception_throw(id); ExceptionThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy, NULL); ExceptionReThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy, NULL); // int objc_sync_enter(id); SyncEnterFn.init(&CGM, "objc_sync_enter", IntTy, IdTy, NULL); // int objc_sync_exit(id); SyncExitFn.init(&CGM, "objc_sync_exit", IntTy, IdTy, NULL); // void objc_enumerationMutation (id) EnumerationMutationFn.init(&CGM, "objc_enumerationMutation", VoidTy, IdTy, NULL); // id objc_getProperty(id, SEL, ptrdiff_t, BOOL) GetPropertyFn.init(&CGM, "objc_getProperty", IdTy, IdTy, SelectorTy, PtrDiffTy, BoolTy, NULL); // void objc_setProperty(id, SEL, ptrdiff_t, id, BOOL, BOOL) SetPropertyFn.init(&CGM, "objc_setProperty", VoidTy, IdTy, SelectorTy, PtrDiffTy, IdTy, BoolTy, BoolTy, NULL); // void objc_setPropertyStruct(void*, void*, ptrdiff_t, BOOL, BOOL) GetStructPropertyFn.init(&CGM, "objc_getPropertyStruct", VoidTy, PtrTy, PtrTy, PtrDiffTy, BoolTy, BoolTy, NULL); // void objc_setPropertyStruct(void*, void*, ptrdiff_t, BOOL, BOOL) SetStructPropertyFn.init(&CGM, "objc_setPropertyStruct", VoidTy, PtrTy, PtrTy, PtrDiffTy, BoolTy, BoolTy, NULL); // IMP type llvm::Type *IMPArgs[] = { IdTy, SelectorTy }; IMPTy = llvm::PointerType::getUnqual(llvm::FunctionType::get(IdTy, IMPArgs, true)); const LangOptions &Opts = CGM.getLangOptions(); if ((Opts.getGC() != LangOptions::NonGC) || Opts.ObjCAutoRefCount) RuntimeVersion = 10; // Don't bother initialising the GC stuff unless we're compiling in GC mode if (Opts.getGC() != LangOptions::NonGC) { // This is a bit of an hack. We should sort this out by having a proper // CGObjCGNUstep subclass for GC, but we may want to really support the old // ABI and GC added in ObjectiveC2.framework, so we fudge it a bit for now // Get selectors needed in GC mode RetainSel = GetNullarySelector("retain", CGM.getContext()); ReleaseSel = GetNullarySelector("release", CGM.getContext()); AutoreleaseSel = GetNullarySelector("autorelease", CGM.getContext()); // Get functions needed in GC mode // id objc_assign_ivar(id, id, ptrdiff_t); IvarAssignFn.init(&CGM, "objc_assign_ivar", IdTy, IdTy, IdTy, PtrDiffTy, NULL); // id objc_assign_strongCast (id, id*) StrongCastAssignFn.init(&CGM, "objc_assign_strongCast", IdTy, IdTy, PtrToIdTy, NULL); // id objc_assign_global(id, id*); GlobalAssignFn.init(&CGM, "objc_assign_global", IdTy, IdTy, PtrToIdTy, NULL); // id objc_assign_weak(id, id*); WeakAssignFn.init(&CGM, "objc_assign_weak", IdTy, IdTy, PtrToIdTy, NULL); // id objc_read_weak(id*); WeakReadFn.init(&CGM, "objc_read_weak", IdTy, PtrToIdTy, NULL); // void *objc_memmove_collectable(void*, void *, size_t); MemMoveFn.init(&CGM, "objc_memmove_collectable", PtrTy, PtrTy, PtrTy, SizeTy, NULL); } } llvm::Value *CGObjCGNU::GetClassNamed(CGBuilderTy &Builder, const std::string &Name, bool isWeak) { llvm::Value *ClassName = CGM.GetAddrOfConstantCString(Name); // With the incompatible ABI, this will need to be replaced with a direct // reference to the class symbol. For the compatible nonfragile ABI we are // still performing this lookup at run time but emitting the symbol for the // class externally so that we can make the switch later. // // Libobjc2 contains an LLVM pass that replaces calls to objc_lookup_class // with memoized versions or with static references if it's safe to do so. if (!isWeak) EmitClassRef(Name); ClassName = Builder.CreateStructGEP(ClassName, 0); llvm::Constant *ClassLookupFn = CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, PtrToInt8Ty, true), "objc_lookup_class"); return Builder.CreateCall(ClassLookupFn, ClassName); } // This has to perform the lookup every time, since posing and related // techniques can modify the name -> class mapping. llvm::Value *CGObjCGNU::GetClass(CGBuilderTy &Builder, const ObjCInterfaceDecl *OID) { return GetClassNamed(Builder, OID->getNameAsString(), OID->isWeakImported()); } llvm::Value *CGObjCGNU::EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder) { return GetClassNamed(Builder, "NSAutoreleasePool", false); } llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, Selector Sel, const std::string &TypeEncoding, bool lval) { SmallVector &Types = SelectorTable[Sel]; llvm::GlobalAlias *SelValue = 0; for (SmallVectorImpl::iterator i = Types.begin(), e = Types.end() ; i!=e ; i++) { if (i->first == TypeEncoding) { SelValue = i->second; break; } } if (0 == SelValue) { SelValue = new llvm::GlobalAlias(SelectorTy, llvm::GlobalValue::PrivateLinkage, ".objc_selector_"+Sel.getAsString(), NULL, &TheModule); Types.push_back(TypedSelector(TypeEncoding, SelValue)); } if (lval) { llvm::Value *tmp = Builder.CreateAlloca(SelValue->getType()); Builder.CreateStore(SelValue, tmp); return tmp; } return SelValue; } llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, Selector Sel, bool lval) { return GetSelector(Builder, Sel, std::string(), lval); } llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl *Method) { std::string SelTypes; CGM.getContext().getObjCEncodingForMethodDecl(Method, SelTypes); return GetSelector(Builder, Method->getSelector(), SelTypes, false); } llvm::Constant *CGObjCGNU::GetEHType(QualType T) { if (!CGM.getLangOptions().CPlusPlus) { if (T->isObjCIdType() || T->isObjCQualifiedIdType()) { // With the old ABI, there was only one kind of catchall, which broke // foreign exceptions. With the new ABI, we use __objc_id_typeinfo as // a pointer indicating object catchalls, and NULL to indicate real // catchalls if (CGM.getLangOptions().ObjCNonFragileABI) { return MakeConstantString("@id"); } else { return 0; } } // All other types should be Objective-C interface pointer types. const ObjCObjectPointerType *OPT = T->getAs(); assert(OPT && "Invalid @catch type."); const ObjCInterfaceDecl *IDecl = OPT->getObjectType()->getInterface(); assert(IDecl && "Invalid @catch type."); return MakeConstantString(IDecl->getIdentifier()->getName()); } // For Objective-C++, we want to provide the ability to catch both C++ and // Objective-C objects in the same function. // There's a particular fixed type info for 'id'. if (T->isObjCIdType() || T->isObjCQualifiedIdType()) { llvm::Constant *IDEHType = CGM.getModule().getGlobalVariable("__objc_id_type_info"); if (!IDEHType) IDEHType = new llvm::GlobalVariable(CGM.getModule(), PtrToInt8Ty, false, llvm::GlobalValue::ExternalLinkage, 0, "__objc_id_type_info"); return llvm::ConstantExpr::getBitCast(IDEHType, PtrToInt8Ty); } const ObjCObjectPointerType *PT = T->getAs(); assert(PT && "Invalid @catch type."); const ObjCInterfaceType *IT = PT->getInterfaceType(); assert(IT && "Invalid @catch type."); std::string className = IT->getDecl()->getIdentifier()->getName(); std::string typeinfoName = "__objc_eh_typeinfo_" + className; // Return the existing typeinfo if it exists llvm::Constant *typeinfo = TheModule.getGlobalVariable(typeinfoName); if (typeinfo) return typeinfo; // Otherwise create it. // vtable for gnustep::libobjc::__objc_class_type_info // It's quite ugly hard-coding this. Ideally we'd generate it using the host // platform's name mangling. const char *vtableName = "_ZTVN7gnustep7libobjc22__objc_class_type_infoE"; llvm::Constant *Vtable = TheModule.getGlobalVariable(vtableName); if (!Vtable) { Vtable = new llvm::GlobalVariable(TheModule, PtrToInt8Ty, true, llvm::GlobalValue::ExternalLinkage, 0, vtableName); } llvm::Constant *Two = llvm::ConstantInt::get(IntTy, 2); Vtable = llvm::ConstantExpr::getGetElementPtr(Vtable, Two); Vtable = llvm::ConstantExpr::getBitCast(Vtable, PtrToInt8Ty); llvm::Constant *typeName = ExportUniqueString(className, "__objc_eh_typename_"); std::vector fields; fields.push_back(Vtable); fields.push_back(typeName); llvm::Constant *TI = MakeGlobal(llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, NULL), fields, "__objc_eh_typeinfo_" + className, llvm::GlobalValue::LinkOnceODRLinkage); return llvm::ConstantExpr::getBitCast(TI, PtrToInt8Ty); } /// Generate an NSConstantString object. llvm::Constant *CGObjCGNU::GenerateConstantString(const StringLiteral *SL) { std::string Str = SL->getString().str(); // Look for an existing one llvm::StringMap::iterator old = ObjCStrings.find(Str); if (old != ObjCStrings.end()) return old->getValue(); std::vector Ivars; Ivars.push_back(NULLPtr); Ivars.push_back(MakeConstantString(Str)); Ivars.push_back(llvm::ConstantInt::get(IntTy, Str.size())); llvm::Constant *ObjCStr = MakeGlobal( llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, IntTy, NULL), Ivars, ".objc_str"); ObjCStr = llvm::ConstantExpr::getBitCast(ObjCStr, PtrToInt8Ty); ObjCStrings[Str] = ObjCStr; ConstantStrings.push_back(ObjCStr); return ObjCStr; } ///Generates a message send where the super is the receiver. This is a message ///send to self with special delivery semantics indicating which class's method ///should be called. RValue CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF, ReturnValueSlot Return, QualType ResultType, Selector Sel, const ObjCInterfaceDecl *Class, bool isCategoryImpl, llvm::Value *Receiver, bool IsClassMessage, const CallArgList &CallArgs, const ObjCMethodDecl *Method) { CGBuilderTy &Builder = CGF.Builder; if (CGM.getLangOptions().getGC() == LangOptions::GCOnly) { if (Sel == RetainSel || Sel == AutoreleaseSel) { return RValue::get(EnforceType(Builder, Receiver, CGM.getTypes().ConvertType(ResultType))); } if (Sel == ReleaseSel) { return RValue::get(0); } } llvm::Value *cmd = GetSelector(Builder, Sel); CallArgList ActualArgs; ActualArgs.add(RValue::get(EnforceType(Builder, Receiver, IdTy)), ASTIdTy); ActualArgs.add(RValue::get(cmd), CGF.getContext().getObjCSelType()); ActualArgs.addFrom(CallArgs); CodeGenTypes &Types = CGM.getTypes(); const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs, FunctionType::ExtInfo()); llvm::Value *ReceiverClass = 0; if (isCategoryImpl) { llvm::Constant *classLookupFunction = 0; if (IsClassMessage) { classLookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get( IdTy, PtrTy, true), "objc_get_meta_class"); } else { classLookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get( IdTy, PtrTy, true), "objc_get_class"); } ReceiverClass = Builder.CreateCall(classLookupFunction, MakeConstantString(Class->getNameAsString())); } else { // Set up global aliases for the metaclass or class pointer if they do not // already exist. These will are forward-references which will be set to // pointers to the class and metaclass structure created for the runtime // load function. To send a message to super, we look up the value of the // super_class pointer from either the class or metaclass structure. if (IsClassMessage) { if (!MetaClassPtrAlias) { MetaClassPtrAlias = new llvm::GlobalAlias(IdTy, llvm::GlobalValue::InternalLinkage, ".objc_metaclass_ref" + Class->getNameAsString(), NULL, &TheModule); } ReceiverClass = MetaClassPtrAlias; } else { if (!ClassPtrAlias) { ClassPtrAlias = new llvm::GlobalAlias(IdTy, llvm::GlobalValue::InternalLinkage, ".objc_class_ref" + Class->getNameAsString(), NULL, &TheModule); } ReceiverClass = ClassPtrAlias; } } // Cast the pointer to a simplified version of the class structure ReceiverClass = Builder.CreateBitCast(ReceiverClass, llvm::PointerType::getUnqual( llvm::StructType::get(IdTy, IdTy, NULL))); // Get the superclass pointer ReceiverClass = Builder.CreateStructGEP(ReceiverClass, 1); // Load the superclass pointer ReceiverClass = Builder.CreateLoad(ReceiverClass); // Construct the structure used to look up the IMP llvm::StructType *ObjCSuperTy = llvm::StructType::get( Receiver->getType(), IdTy, NULL); llvm::Value *ObjCSuper = Builder.CreateAlloca(ObjCSuperTy); Builder.CreateStore(Receiver, Builder.CreateStructGEP(ObjCSuper, 0)); Builder.CreateStore(ReceiverClass, Builder.CreateStructGEP(ObjCSuper, 1)); ObjCSuper = EnforceType(Builder, ObjCSuper, PtrToObjCSuperTy); llvm::FunctionType *impType = Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false); // Get the IMP llvm::Value *imp = LookupIMPSuper(CGF, ObjCSuper, cmd); imp = EnforceType(Builder, imp, llvm::PointerType::getUnqual(impType)); llvm::Value *impMD[] = { llvm::MDString::get(VMContext, Sel.getAsString()), llvm::MDString::get(VMContext, Class->getSuperClass()->getNameAsString()), llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), IsClassMessage) }; llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD); llvm::Instruction *call; RValue msgRet = CGF.EmitCall(FnInfo, imp, Return, ActualArgs, 0, &call); call->setMetadata(msgSendMDKind, node); return msgRet; } /// Generate code for a message send expression. RValue CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF, ReturnValueSlot Return, QualType ResultType, Selector Sel, llvm::Value *Receiver, const CallArgList &CallArgs, const ObjCInterfaceDecl *Class, const ObjCMethodDecl *Method) { CGBuilderTy &Builder = CGF.Builder; // Strip out message sends to retain / release in GC mode if (CGM.getLangOptions().getGC() == LangOptions::GCOnly) { if (Sel == RetainSel || Sel == AutoreleaseSel) { return RValue::get(EnforceType(Builder, Receiver, CGM.getTypes().ConvertType(ResultType))); } if (Sel == ReleaseSel) { return RValue::get(0); } } // If the return type is something that goes in an integer register, the // runtime will handle 0 returns. For other cases, we fill in the 0 value // ourselves. // // The language spec says the result of this kind of message send is // undefined, but lots of people seem to have forgotten to read that // paragraph and insist on sending messages to nil that have structure // returns. With GCC, this generates a random return value (whatever happens // to be on the stack / in those registers at the time) on most platforms, // and generates an illegal instruction trap on SPARC. With LLVM it corrupts // the stack. bool isPointerSizedReturn = (ResultType->isAnyPointerType() || ResultType->isIntegralOrEnumerationType() || ResultType->isVoidType()); llvm::BasicBlock *startBB = 0; llvm::BasicBlock *messageBB = 0; llvm::BasicBlock *continueBB = 0; if (!isPointerSizedReturn) { startBB = Builder.GetInsertBlock(); messageBB = CGF.createBasicBlock("msgSend"); continueBB = CGF.createBasicBlock("continue"); llvm::Value *isNil = Builder.CreateICmpEQ(Receiver, llvm::Constant::getNullValue(Receiver->getType())); Builder.CreateCondBr(isNil, continueBB, messageBB); CGF.EmitBlock(messageBB); } IdTy = cast(CGM.getTypes().ConvertType(ASTIdTy)); llvm::Value *cmd; if (Method) cmd = GetSelector(Builder, Method); else cmd = GetSelector(Builder, Sel); cmd = EnforceType(Builder, cmd, SelectorTy); Receiver = EnforceType(Builder, Receiver, IdTy); llvm::Value *impMD[] = { llvm::MDString::get(VMContext, Sel.getAsString()), llvm::MDString::get(VMContext, Class ? Class->getNameAsString() :""), llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), Class!=0) }; llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD); // Get the IMP to call llvm::Value *imp = LookupIMP(CGF, Receiver, cmd, node); CallArgList ActualArgs; ActualArgs.add(RValue::get(Receiver), ASTIdTy); ActualArgs.add(RValue::get(cmd), CGF.getContext().getObjCSelType()); ActualArgs.addFrom(CallArgs); CodeGenTypes &Types = CGM.getTypes(); const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs, FunctionType::ExtInfo()); llvm::FunctionType *impType = Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false); imp = EnforceType(Builder, imp, llvm::PointerType::getUnqual(impType)); // For sender-aware dispatch, we pass the sender as the third argument to a // lookup function. When sending messages from C code, the sender is nil. // objc_msg_lookup_sender(id *receiver, SEL selector, id sender); llvm::Instruction *call; RValue msgRet = CGF.EmitCall(FnInfo, imp, Return, ActualArgs, 0, &call); call->setMetadata(msgSendMDKind, node); if (!isPointerSizedReturn) { messageBB = CGF.Builder.GetInsertBlock(); CGF.Builder.CreateBr(continueBB); CGF.EmitBlock(continueBB); if (msgRet.isScalar()) { llvm::Value *v = msgRet.getScalarVal(); llvm::PHINode *phi = Builder.CreatePHI(v->getType(), 2); phi->addIncoming(v, messageBB); phi->addIncoming(llvm::Constant::getNullValue(v->getType()), startBB); msgRet = RValue::get(phi); } else if (msgRet.isAggregate()) { llvm::Value *v = msgRet.getAggregateAddr(); llvm::PHINode *phi = Builder.CreatePHI(v->getType(), 2); llvm::PointerType *RetTy = cast(v->getType()); llvm::AllocaInst *NullVal = CGF.CreateTempAlloca(RetTy->getElementType(), "null"); CGF.InitTempAlloca(NullVal, llvm::Constant::getNullValue(RetTy->getElementType())); phi->addIncoming(v, messageBB); phi->addIncoming(NullVal, startBB); msgRet = RValue::getAggregate(phi); } else /* isComplex() */ { std::pair v = msgRet.getComplexVal(); llvm::PHINode *phi = Builder.CreatePHI(v.first->getType(), 2); phi->addIncoming(v.first, messageBB); phi->addIncoming(llvm::Constant::getNullValue(v.first->getType()), startBB); llvm::PHINode *phi2 = Builder.CreatePHI(v.second->getType(), 2); phi2->addIncoming(v.second, messageBB); phi2->addIncoming(llvm::Constant::getNullValue(v.second->getType()), startBB); msgRet = RValue::getComplex(phi, phi2); } } return msgRet; } /// Generates a MethodList. Used in construction of a objc_class and /// objc_category structures. llvm::Constant *CGObjCGNU::GenerateMethodList(const StringRef &ClassName, const StringRef &CategoryName, const SmallVectorImpl &MethodSels, const SmallVectorImpl &MethodTypes, bool isClassMethodList) { if (MethodSels.empty()) return NULLPtr; // Get the method structure type. llvm::StructType *ObjCMethodTy = llvm::StructType::get( PtrToInt8Ty, // Really a selector, but the runtime creates it us. PtrToInt8Ty, // Method types IMPTy, //Method pointer NULL); std::vector Methods; std::vector Elements; for (unsigned int i = 0, e = MethodTypes.size(); i < e; ++i) { Elements.clear(); llvm::Constant *Method = TheModule.getFunction(SymbolNameForMethod(ClassName, CategoryName, MethodSels[i], isClassMethodList)); assert(Method && "Can't generate metadata for method that doesn't exist"); llvm::Constant *C = MakeConstantString(MethodSels[i].getAsString()); Elements.push_back(C); Elements.push_back(MethodTypes[i]); Method = llvm::ConstantExpr::getBitCast(Method, IMPTy); Elements.push_back(Method); Methods.push_back(llvm::ConstantStruct::get(ObjCMethodTy, Elements)); } // Array of method structures llvm::ArrayType *ObjCMethodArrayTy = llvm::ArrayType::get(ObjCMethodTy, Methods.size()); llvm::Constant *MethodArray = llvm::ConstantArray::get(ObjCMethodArrayTy, Methods); // Structure containing list pointer, array and array count llvm::StructType *ObjCMethodListTy = llvm::StructType::create(VMContext); llvm::Type *NextPtrTy = llvm::PointerType::getUnqual(ObjCMethodListTy); ObjCMethodListTy->setBody( NextPtrTy, IntTy, ObjCMethodArrayTy, NULL); Methods.clear(); Methods.push_back(llvm::ConstantPointerNull::get( llvm::PointerType::getUnqual(ObjCMethodListTy))); Methods.push_back(llvm::ConstantInt::get(Int32Ty, MethodTypes.size())); Methods.push_back(MethodArray); // Create an instance of the structure return MakeGlobal(ObjCMethodListTy, Methods, ".objc_method_list"); } /// Generates an IvarList. Used in construction of a objc_class. llvm::Constant *CGObjCGNU::GenerateIvarList( const SmallVectorImpl &IvarNames, const SmallVectorImpl &IvarTypes, const SmallVectorImpl &IvarOffsets) { if (IvarNames.size() == 0) return NULLPtr; // Get the method structure type. llvm::StructType *ObjCIvarTy = llvm::StructType::get( PtrToInt8Ty, PtrToInt8Ty, IntTy, NULL); std::vector Ivars; std::vector Elements; for (unsigned int i = 0, e = IvarNames.size() ; i < e ; i++) { Elements.clear(); Elements.push_back(IvarNames[i]); Elements.push_back(IvarTypes[i]); Elements.push_back(IvarOffsets[i]); Ivars.push_back(llvm::ConstantStruct::get(ObjCIvarTy, Elements)); } // Array of method structures llvm::ArrayType *ObjCIvarArrayTy = llvm::ArrayType::get(ObjCIvarTy, IvarNames.size()); Elements.clear(); Elements.push_back(llvm::ConstantInt::get(IntTy, (int)IvarNames.size())); Elements.push_back(llvm::ConstantArray::get(ObjCIvarArrayTy, Ivars)); // Structure containing array and array count llvm::StructType *ObjCIvarListTy = llvm::StructType::get(IntTy, ObjCIvarArrayTy, NULL); // Create an instance of the structure return MakeGlobal(ObjCIvarListTy, Elements, ".objc_ivar_list"); } /// Generate a class structure llvm::Constant *CGObjCGNU::GenerateClassStructure( llvm::Constant *MetaClass, llvm::Constant *SuperClass, unsigned info, const char *Name, llvm::Constant *Version, llvm::Constant *InstanceSize, llvm::Constant *IVars, llvm::Constant *Methods, llvm::Constant *Protocols, llvm::Constant *IvarOffsets, llvm::Constant *Properties, llvm::Constant *StrongIvarBitmap, llvm::Constant *WeakIvarBitmap, bool isMeta) { // Set up the class structure // Note: Several of these are char*s when they should be ids. This is // because the runtime performs this translation on load. // // Fields marked New ABI are part of the GNUstep runtime. We emit them // anyway; the classes will still work with the GNU runtime, they will just // be ignored. llvm::StructType *ClassTy = llvm::StructType::get( PtrToInt8Ty, // class_pointer PtrToInt8Ty, // super_class PtrToInt8Ty, // name LongTy, // version LongTy, // info LongTy, // instance_size IVars->getType(), // ivars Methods->getType(), // methods // These are all filled in by the runtime, so we pretend PtrTy, // dtable PtrTy, // subclass_list PtrTy, // sibling_class PtrTy, // protocols PtrTy, // gc_object_type // New ABI: LongTy, // abi_version IvarOffsets->getType(), // ivar_offsets Properties->getType(), // properties - Int64Ty, // strong_pointers - Int64Ty, // weak_pointers + IntPtrTy, // strong_pointers + IntPtrTy, // weak_pointers NULL); llvm::Constant *Zero = llvm::ConstantInt::get(LongTy, 0); // Fill in the structure std::vector Elements; Elements.push_back(llvm::ConstantExpr::getBitCast(MetaClass, PtrToInt8Ty)); Elements.push_back(SuperClass); Elements.push_back(MakeConstantString(Name, ".class_name")); Elements.push_back(Zero); Elements.push_back(llvm::ConstantInt::get(LongTy, info)); if (isMeta) { llvm::TargetData td(&TheModule); Elements.push_back( llvm::ConstantInt::get(LongTy, td.getTypeSizeInBits(ClassTy) / CGM.getContext().getCharWidth())); } else Elements.push_back(InstanceSize); Elements.push_back(IVars); Elements.push_back(Methods); Elements.push_back(NULLPtr); Elements.push_back(NULLPtr); Elements.push_back(NULLPtr); Elements.push_back(llvm::ConstantExpr::getBitCast(Protocols, PtrTy)); Elements.push_back(NULLPtr); Elements.push_back(llvm::ConstantInt::get(LongTy, 1)); Elements.push_back(IvarOffsets); Elements.push_back(Properties); Elements.push_back(StrongIvarBitmap); Elements.push_back(WeakIvarBitmap); // Create an instance of the structure // This is now an externally visible symbol, so that we can speed up class // messages in the next ABI. return MakeGlobal(ClassTy, Elements, (isMeta ? "_OBJC_METACLASS_": "_OBJC_CLASS_") + std::string(Name), llvm::GlobalValue::ExternalLinkage); } llvm::Constant *CGObjCGNU::GenerateProtocolMethodList( const SmallVectorImpl &MethodNames, const SmallVectorImpl &MethodTypes) { // Get the method structure type. llvm::StructType *ObjCMethodDescTy = llvm::StructType::get( PtrToInt8Ty, // Really a selector, but the runtime does the casting for us. PtrToInt8Ty, NULL); std::vector Methods; std::vector Elements; for (unsigned int i = 0, e = MethodTypes.size() ; i < e ; i++) { Elements.clear(); Elements.push_back(MethodNames[i]); Elements.push_back(MethodTypes[i]); Methods.push_back(llvm::ConstantStruct::get(ObjCMethodDescTy, Elements)); } llvm::ArrayType *ObjCMethodArrayTy = llvm::ArrayType::get(ObjCMethodDescTy, MethodNames.size()); llvm::Constant *Array = llvm::ConstantArray::get(ObjCMethodArrayTy, Methods); llvm::StructType *ObjCMethodDescListTy = llvm::StructType::get( IntTy, ObjCMethodArrayTy, NULL); Methods.clear(); Methods.push_back(llvm::ConstantInt::get(IntTy, MethodNames.size())); Methods.push_back(Array); return MakeGlobal(ObjCMethodDescListTy, Methods, ".objc_method_list"); } // Create the protocol list structure used in classes, categories and so on llvm::Constant *CGObjCGNU::GenerateProtocolList( const SmallVectorImpl &Protocols) { llvm::ArrayType *ProtocolArrayTy = llvm::ArrayType::get(PtrToInt8Ty, Protocols.size()); llvm::StructType *ProtocolListTy = llvm::StructType::get( PtrTy, //Should be a recurisve pointer, but it's always NULL here. SizeTy, ProtocolArrayTy, NULL); std::vector Elements; for (const std::string *iter = Protocols.begin(), *endIter = Protocols.end(); iter != endIter ; iter++) { llvm::Constant *protocol = 0; llvm::StringMap::iterator value = ExistingProtocols.find(*iter); if (value == ExistingProtocols.end()) { protocol = GenerateEmptyProtocol(*iter); } else { protocol = value->getValue(); } llvm::Constant *Ptr = llvm::ConstantExpr::getBitCast(protocol, PtrToInt8Ty); Elements.push_back(Ptr); } llvm::Constant * ProtocolArray = llvm::ConstantArray::get(ProtocolArrayTy, Elements); Elements.clear(); Elements.push_back(NULLPtr); Elements.push_back(llvm::ConstantInt::get(LongTy, Protocols.size())); Elements.push_back(ProtocolArray); return MakeGlobal(ProtocolListTy, Elements, ".objc_protocol_list"); } llvm::Value *CGObjCGNU::GenerateProtocolRef(CGBuilderTy &Builder, const ObjCProtocolDecl *PD) { llvm::Value *protocol = ExistingProtocols[PD->getNameAsString()]; llvm::Type *T = CGM.getTypes().ConvertType(CGM.getContext().getObjCProtoType()); return Builder.CreateBitCast(protocol, llvm::PointerType::getUnqual(T)); } llvm::Constant *CGObjCGNU::GenerateEmptyProtocol( const std::string &ProtocolName) { SmallVector EmptyStringVector; SmallVector EmptyConstantVector; llvm::Constant *ProtocolList = GenerateProtocolList(EmptyStringVector); llvm::Constant *MethodList = GenerateProtocolMethodList(EmptyConstantVector, EmptyConstantVector); // Protocols are objects containing lists of the methods implemented and // protocols adopted. llvm::StructType *ProtocolTy = llvm::StructType::get(IdTy, PtrToInt8Ty, ProtocolList->getType(), MethodList->getType(), MethodList->getType(), MethodList->getType(), MethodList->getType(), NULL); std::vector Elements; // The isa pointer must be set to a magic number so the runtime knows it's // the correct layout. Elements.push_back(llvm::ConstantExpr::getIntToPtr( llvm::ConstantInt::get(Int32Ty, ProtocolVersion), IdTy)); Elements.push_back(MakeConstantString(ProtocolName, ".objc_protocol_name")); Elements.push_back(ProtocolList); Elements.push_back(MethodList); Elements.push_back(MethodList); Elements.push_back(MethodList); Elements.push_back(MethodList); return MakeGlobal(ProtocolTy, Elements, ".objc_protocol"); } void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) { ASTContext &Context = CGM.getContext(); std::string ProtocolName = PD->getNameAsString(); SmallVector Protocols; for (ObjCProtocolDecl::protocol_iterator PI = PD->protocol_begin(), E = PD->protocol_end(); PI != E; ++PI) Protocols.push_back((*PI)->getNameAsString()); SmallVector InstanceMethodNames; SmallVector InstanceMethodTypes; SmallVector OptionalInstanceMethodNames; SmallVector OptionalInstanceMethodTypes; for (ObjCProtocolDecl::instmeth_iterator iter = PD->instmeth_begin(), E = PD->instmeth_end(); iter != E; iter++) { std::string TypeStr; Context.getObjCEncodingForMethodDecl(*iter, TypeStr); if ((*iter)->getImplementationControl() == ObjCMethodDecl::Optional) { InstanceMethodNames.push_back( MakeConstantString((*iter)->getSelector().getAsString())); InstanceMethodTypes.push_back(MakeConstantString(TypeStr)); } else { OptionalInstanceMethodNames.push_back( MakeConstantString((*iter)->getSelector().getAsString())); OptionalInstanceMethodTypes.push_back(MakeConstantString(TypeStr)); } } // Collect information about class methods: SmallVector ClassMethodNames; SmallVector ClassMethodTypes; SmallVector OptionalClassMethodNames; SmallVector OptionalClassMethodTypes; for (ObjCProtocolDecl::classmeth_iterator iter = PD->classmeth_begin(), endIter = PD->classmeth_end(); iter != endIter ; iter++) { std::string TypeStr; Context.getObjCEncodingForMethodDecl((*iter),TypeStr); if ((*iter)->getImplementationControl() == ObjCMethodDecl::Optional) { ClassMethodNames.push_back( MakeConstantString((*iter)->getSelector().getAsString())); ClassMethodTypes.push_back(MakeConstantString(TypeStr)); } else { OptionalClassMethodNames.push_back( MakeConstantString((*iter)->getSelector().getAsString())); OptionalClassMethodTypes.push_back(MakeConstantString(TypeStr)); } } llvm::Constant *ProtocolList = GenerateProtocolList(Protocols); llvm::Constant *InstanceMethodList = GenerateProtocolMethodList(InstanceMethodNames, InstanceMethodTypes); llvm::Constant *ClassMethodList = GenerateProtocolMethodList(ClassMethodNames, ClassMethodTypes); llvm::Constant *OptionalInstanceMethodList = GenerateProtocolMethodList(OptionalInstanceMethodNames, OptionalInstanceMethodTypes); llvm::Constant *OptionalClassMethodList = GenerateProtocolMethodList(OptionalClassMethodNames, OptionalClassMethodTypes); // Property metadata: name, attributes, isSynthesized, setter name, setter // types, getter name, getter types. // The isSynthesized value is always set to 0 in a protocol. It exists to // simplify the runtime library by allowing it to use the same data // structures for protocol metadata everywhere. llvm::StructType *PropertyMetadataTy = llvm::StructType::get( PtrToInt8Ty, Int8Ty, Int8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, NULL); std::vector Properties; std::vector OptionalProperties; // Add all of the property methods need adding to the method list and to the // property metadata list. for (ObjCContainerDecl::prop_iterator iter = PD->prop_begin(), endIter = PD->prop_end(); iter != endIter ; iter++) { std::vector Fields; ObjCPropertyDecl *property = (*iter); Fields.push_back(MakeConstantString(property->getNameAsString())); Fields.push_back(llvm::ConstantInt::get(Int8Ty, property->getPropertyAttributes())); Fields.push_back(llvm::ConstantInt::get(Int8Ty, 0)); if (ObjCMethodDecl *getter = property->getGetterMethodDecl()) { std::string TypeStr; Context.getObjCEncodingForMethodDecl(getter,TypeStr); llvm::Constant *TypeEncoding = MakeConstantString(TypeStr); InstanceMethodTypes.push_back(TypeEncoding); Fields.push_back(MakeConstantString(getter->getSelector().getAsString())); Fields.push_back(TypeEncoding); } else { Fields.push_back(NULLPtr); Fields.push_back(NULLPtr); } if (ObjCMethodDecl *setter = property->getSetterMethodDecl()) { std::string TypeStr; Context.getObjCEncodingForMethodDecl(setter,TypeStr); llvm::Constant *TypeEncoding = MakeConstantString(TypeStr); InstanceMethodTypes.push_back(TypeEncoding); Fields.push_back(MakeConstantString(setter->getSelector().getAsString())); Fields.push_back(TypeEncoding); } else { Fields.push_back(NULLPtr); Fields.push_back(NULLPtr); } if (property->getPropertyImplementation() == ObjCPropertyDecl::Optional) { OptionalProperties.push_back(llvm::ConstantStruct::get(PropertyMetadataTy, Fields)); } else { Properties.push_back(llvm::ConstantStruct::get(PropertyMetadataTy, Fields)); } } llvm::Constant *PropertyArray = llvm::ConstantArray::get( llvm::ArrayType::get(PropertyMetadataTy, Properties.size()), Properties); llvm::Constant* PropertyListInitFields[] = {llvm::ConstantInt::get(IntTy, Properties.size()), NULLPtr, PropertyArray}; llvm::Constant *PropertyListInit = llvm::ConstantStruct::getAnon(PropertyListInitFields); llvm::Constant *PropertyList = new llvm::GlobalVariable(TheModule, PropertyListInit->getType(), false, llvm::GlobalValue::InternalLinkage, PropertyListInit, ".objc_property_list"); llvm::Constant *OptionalPropertyArray = llvm::ConstantArray::get(llvm::ArrayType::get(PropertyMetadataTy, OptionalProperties.size()) , OptionalProperties); llvm::Constant* OptionalPropertyListInitFields[] = { llvm::ConstantInt::get(IntTy, OptionalProperties.size()), NULLPtr, OptionalPropertyArray }; llvm::Constant *OptionalPropertyListInit = llvm::ConstantStruct::getAnon(OptionalPropertyListInitFields); llvm::Constant *OptionalPropertyList = new llvm::GlobalVariable(TheModule, OptionalPropertyListInit->getType(), false, llvm::GlobalValue::InternalLinkage, OptionalPropertyListInit, ".objc_property_list"); // Protocols are objects containing lists of the methods implemented and // protocols adopted. llvm::StructType *ProtocolTy = llvm::StructType::get(IdTy, PtrToInt8Ty, ProtocolList->getType(), InstanceMethodList->getType(), ClassMethodList->getType(), OptionalInstanceMethodList->getType(), OptionalClassMethodList->getType(), PropertyList->getType(), OptionalPropertyList->getType(), NULL); std::vector Elements; // The isa pointer must be set to a magic number so the runtime knows it's // the correct layout. Elements.push_back(llvm::ConstantExpr::getIntToPtr( llvm::ConstantInt::get(Int32Ty, ProtocolVersion), IdTy)); Elements.push_back(MakeConstantString(ProtocolName, ".objc_protocol_name")); Elements.push_back(ProtocolList); Elements.push_back(InstanceMethodList); Elements.push_back(ClassMethodList); Elements.push_back(OptionalInstanceMethodList); Elements.push_back(OptionalClassMethodList); Elements.push_back(PropertyList); Elements.push_back(OptionalPropertyList); ExistingProtocols[ProtocolName] = llvm::ConstantExpr::getBitCast(MakeGlobal(ProtocolTy, Elements, ".objc_protocol"), IdTy); } void CGObjCGNU::GenerateProtocolHolderCategory(void) { // Collect information about instance methods SmallVector MethodSels; SmallVector MethodTypes; std::vector Elements; const std::string ClassName = "__ObjC_Protocol_Holder_Ugly_Hack"; const std::string CategoryName = "AnotherHack"; Elements.push_back(MakeConstantString(CategoryName)); Elements.push_back(MakeConstantString(ClassName)); // Instance method list Elements.push_back(llvm::ConstantExpr::getBitCast(GenerateMethodList( ClassName, CategoryName, MethodSels, MethodTypes, false), PtrTy)); // Class method list Elements.push_back(llvm::ConstantExpr::getBitCast(GenerateMethodList( ClassName, CategoryName, MethodSels, MethodTypes, true), PtrTy)); // Protocol list llvm::ArrayType *ProtocolArrayTy = llvm::ArrayType::get(PtrTy, ExistingProtocols.size()); llvm::StructType *ProtocolListTy = llvm::StructType::get( PtrTy, //Should be a recurisve pointer, but it's always NULL here. SizeTy, ProtocolArrayTy, NULL); std::vector ProtocolElements; for (llvm::StringMapIterator iter = ExistingProtocols.begin(), endIter = ExistingProtocols.end(); iter != endIter ; iter++) { llvm::Constant *Ptr = llvm::ConstantExpr::getBitCast(iter->getValue(), PtrTy); ProtocolElements.push_back(Ptr); } llvm::Constant * ProtocolArray = llvm::ConstantArray::get(ProtocolArrayTy, ProtocolElements); ProtocolElements.clear(); ProtocolElements.push_back(NULLPtr); ProtocolElements.push_back(llvm::ConstantInt::get(LongTy, ExistingProtocols.size())); ProtocolElements.push_back(ProtocolArray); Elements.push_back(llvm::ConstantExpr::getBitCast(MakeGlobal(ProtocolListTy, ProtocolElements, ".objc_protocol_list"), PtrTy)); Categories.push_back(llvm::ConstantExpr::getBitCast( MakeGlobal(llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, PtrTy, PtrTy, PtrTy, NULL), Elements), PtrTy)); } /// Libobjc2 uses a bitfield representation where small(ish) bitfields are /// stored in a 64-bit value with the low bit set to 1 and the remaining 63 /// bits set to their values, LSB first, while larger ones are stored in a /// structure of this / form: /// /// struct { int32_t length; int32_t values[length]; }; /// /// The values in the array are stored in host-endian format, with the least /// significant bit being assumed to come first in the bitfield. Therefore, a /// bitfield with the 64th bit set will be (int64_t)&{ 2, [0, 1<<31] }, while a /// bitfield / with the 63rd bit set will be 1<<64. llvm::Constant *CGObjCGNU::MakeBitField(llvm::SmallVectorImpl &bits) { int bitCount = bits.size(); - if (bitCount < 64) { + int ptrBits = + (TheModule.getPointerSize() == llvm::Module::Pointer32) ? 32 : 64; + if (bitCount < ptrBits) { uint64_t val = 1; for (int i=0 ; i values; int v=0; while (v < bitCount) { int32_t word = 0; for (int i=0 ; (i<32) && (vgetClassInterface()->getNameAsString(); std::string CategoryName = OCD->getNameAsString(); // Collect information about instance methods SmallVector InstanceMethodSels; SmallVector InstanceMethodTypes; for (ObjCCategoryImplDecl::instmeth_iterator iter = OCD->instmeth_begin(), endIter = OCD->instmeth_end(); iter != endIter ; iter++) { InstanceMethodSels.push_back((*iter)->getSelector()); std::string TypeStr; CGM.getContext().getObjCEncodingForMethodDecl(*iter,TypeStr); InstanceMethodTypes.push_back(MakeConstantString(TypeStr)); } // Collect information about class methods SmallVector ClassMethodSels; SmallVector ClassMethodTypes; for (ObjCCategoryImplDecl::classmeth_iterator iter = OCD->classmeth_begin(), endIter = OCD->classmeth_end(); iter != endIter ; iter++) { ClassMethodSels.push_back((*iter)->getSelector()); std::string TypeStr; CGM.getContext().getObjCEncodingForMethodDecl(*iter,TypeStr); ClassMethodTypes.push_back(MakeConstantString(TypeStr)); } // Collect the names of referenced protocols SmallVector Protocols; const ObjCCategoryDecl *CatDecl = OCD->getCategoryDecl(); const ObjCList &Protos = CatDecl->getReferencedProtocols(); for (ObjCList::iterator I = Protos.begin(), E = Protos.end(); I != E; ++I) Protocols.push_back((*I)->getNameAsString()); std::vector Elements; Elements.push_back(MakeConstantString(CategoryName)); Elements.push_back(MakeConstantString(ClassName)); // Instance method list Elements.push_back(llvm::ConstantExpr::getBitCast(GenerateMethodList( ClassName, CategoryName, InstanceMethodSels, InstanceMethodTypes, false), PtrTy)); // Class method list Elements.push_back(llvm::ConstantExpr::getBitCast(GenerateMethodList( ClassName, CategoryName, ClassMethodSels, ClassMethodTypes, true), PtrTy)); // Protocol list Elements.push_back(llvm::ConstantExpr::getBitCast( GenerateProtocolList(Protocols), PtrTy)); Categories.push_back(llvm::ConstantExpr::getBitCast( MakeGlobal(llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, PtrTy, PtrTy, PtrTy, NULL), Elements), PtrTy)); } llvm::Constant *CGObjCGNU::GeneratePropertyList(const ObjCImplementationDecl *OID, SmallVectorImpl &InstanceMethodSels, SmallVectorImpl &InstanceMethodTypes) { ASTContext &Context = CGM.getContext(); // // Property metadata: name, attributes, isSynthesized, setter name, setter // types, getter name, getter types. llvm::StructType *PropertyMetadataTy = llvm::StructType::get( PtrToInt8Ty, Int8Ty, Int8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, NULL); std::vector Properties; // Add all of the property methods need adding to the method list and to the // property metadata list. for (ObjCImplDecl::propimpl_iterator iter = OID->propimpl_begin(), endIter = OID->propimpl_end(); iter != endIter ; iter++) { std::vector Fields; ObjCPropertyDecl *property = (*iter)->getPropertyDecl(); ObjCPropertyImplDecl *propertyImpl = *iter; bool isSynthesized = (propertyImpl->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize); Fields.push_back(MakeConstantString(property->getNameAsString())); Fields.push_back(llvm::ConstantInt::get(Int8Ty, property->getPropertyAttributes())); Fields.push_back(llvm::ConstantInt::get(Int8Ty, isSynthesized)); if (ObjCMethodDecl *getter = property->getGetterMethodDecl()) { std::string TypeStr; Context.getObjCEncodingForMethodDecl(getter,TypeStr); llvm::Constant *TypeEncoding = MakeConstantString(TypeStr); if (isSynthesized) { InstanceMethodTypes.push_back(TypeEncoding); InstanceMethodSels.push_back(getter->getSelector()); } Fields.push_back(MakeConstantString(getter->getSelector().getAsString())); Fields.push_back(TypeEncoding); } else { Fields.push_back(NULLPtr); Fields.push_back(NULLPtr); } if (ObjCMethodDecl *setter = property->getSetterMethodDecl()) { std::string TypeStr; Context.getObjCEncodingForMethodDecl(setter,TypeStr); llvm::Constant *TypeEncoding = MakeConstantString(TypeStr); if (isSynthesized) { InstanceMethodTypes.push_back(TypeEncoding); InstanceMethodSels.push_back(setter->getSelector()); } Fields.push_back(MakeConstantString(setter->getSelector().getAsString())); Fields.push_back(TypeEncoding); } else { Fields.push_back(NULLPtr); Fields.push_back(NULLPtr); } Properties.push_back(llvm::ConstantStruct::get(PropertyMetadataTy, Fields)); } llvm::ArrayType *PropertyArrayTy = llvm::ArrayType::get(PropertyMetadataTy, Properties.size()); llvm::Constant *PropertyArray = llvm::ConstantArray::get(PropertyArrayTy, Properties); llvm::Constant* PropertyListInitFields[] = {llvm::ConstantInt::get(IntTy, Properties.size()), NULLPtr, PropertyArray}; llvm::Constant *PropertyListInit = llvm::ConstantStruct::getAnon(PropertyListInitFields); return new llvm::GlobalVariable(TheModule, PropertyListInit->getType(), false, llvm::GlobalValue::InternalLinkage, PropertyListInit, ".objc_property_list"); } void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { ASTContext &Context = CGM.getContext(); // Get the superclass name. const ObjCInterfaceDecl * SuperClassDecl = OID->getClassInterface()->getSuperClass(); std::string SuperClassName; if (SuperClassDecl) { SuperClassName = SuperClassDecl->getNameAsString(); EmitClassRef(SuperClassName); } // Get the class name ObjCInterfaceDecl *ClassDecl = const_cast(OID->getClassInterface()); std::string ClassName = ClassDecl->getNameAsString(); // Emit the symbol that is used to generate linker errors if this class is // referenced in other modules but not declared. std::string classSymbolName = "__objc_class_name_" + ClassName; if (llvm::GlobalVariable *symbol = TheModule.getGlobalVariable(classSymbolName)) { symbol->setInitializer(llvm::ConstantInt::get(LongTy, 0)); } else { new llvm::GlobalVariable(TheModule, LongTy, false, llvm::GlobalValue::ExternalLinkage, llvm::ConstantInt::get(LongTy, 0), classSymbolName); } // Get the size of instances. int instanceSize = Context.getASTObjCImplementationLayout(OID).getSize().getQuantity(); // Collect information about instance variables. SmallVector IvarNames; SmallVector IvarTypes; SmallVector IvarOffsets; std::vector IvarOffsetValues; SmallVector WeakIvars; SmallVector StrongIvars; int superInstanceSize = !SuperClassDecl ? 0 : Context.getASTObjCInterfaceLayout(SuperClassDecl).getSize().getQuantity(); // For non-fragile ivars, set the instance size to 0 - {the size of just this // class}. The runtime will then set this to the correct value on load. if (CGM.getContext().getLangOptions().ObjCNonFragileABI) { instanceSize = 0 - (instanceSize - superInstanceSize); } for (const ObjCIvarDecl *IVD = ClassDecl->all_declared_ivar_begin(); IVD; IVD = IVD->getNextIvar()) { // Store the name IvarNames.push_back(MakeConstantString(IVD->getNameAsString())); // Get the type encoding for this ivar std::string TypeStr; Context.getObjCEncodingForType(IVD->getType(), TypeStr); IvarTypes.push_back(MakeConstantString(TypeStr)); // Get the offset uint64_t BaseOffset = ComputeIvarBaseOffset(CGM, OID, IVD); uint64_t Offset = BaseOffset; if (CGM.getContext().getLangOptions().ObjCNonFragileABI) { Offset = BaseOffset - superInstanceSize; } llvm::Constant *OffsetValue = llvm::ConstantInt::get(IntTy, Offset); // Create the direct offset value std::string OffsetName = "__objc_ivar_offset_value_" + ClassName +"." + IVD->getNameAsString(); llvm::GlobalVariable *OffsetVar = TheModule.getGlobalVariable(OffsetName); if (OffsetVar) { OffsetVar->setInitializer(OffsetValue); // If this is the real definition, change its linkage type so that // different modules will use this one, rather than their private // copy. OffsetVar->setLinkage(llvm::GlobalValue::ExternalLinkage); } else OffsetVar = new llvm::GlobalVariable(TheModule, IntTy, false, llvm::GlobalValue::ExternalLinkage, OffsetValue, "__objc_ivar_offset_value_" + ClassName +"." + IVD->getNameAsString()); IvarOffsets.push_back(OffsetValue); IvarOffsetValues.push_back(OffsetVar); Qualifiers::ObjCLifetime lt = IVD->getType().getQualifiers().getObjCLifetime(); switch (lt) { case Qualifiers::OCL_Strong: StrongIvars.push_back(true); WeakIvars.push_back(false); break; case Qualifiers::OCL_Weak: StrongIvars.push_back(false); WeakIvars.push_back(true); break; default: StrongIvars.push_back(false); WeakIvars.push_back(false); } } llvm::Constant *StrongIvarBitmap = MakeBitField(StrongIvars); llvm::Constant *WeakIvarBitmap = MakeBitField(WeakIvars); llvm::GlobalVariable *IvarOffsetArray = MakeGlobalArray(PtrToIntTy, IvarOffsetValues, ".ivar.offsets"); // Collect information about instance methods SmallVector InstanceMethodSels; SmallVector InstanceMethodTypes; for (ObjCImplementationDecl::instmeth_iterator iter = OID->instmeth_begin(), endIter = OID->instmeth_end(); iter != endIter ; iter++) { InstanceMethodSels.push_back((*iter)->getSelector()); std::string TypeStr; Context.getObjCEncodingForMethodDecl((*iter),TypeStr); InstanceMethodTypes.push_back(MakeConstantString(TypeStr)); } llvm::Constant *Properties = GeneratePropertyList(OID, InstanceMethodSels, InstanceMethodTypes); // Collect information about class methods SmallVector ClassMethodSels; SmallVector ClassMethodTypes; for (ObjCImplementationDecl::classmeth_iterator iter = OID->classmeth_begin(), endIter = OID->classmeth_end(); iter != endIter ; iter++) { ClassMethodSels.push_back((*iter)->getSelector()); std::string TypeStr; Context.getObjCEncodingForMethodDecl((*iter),TypeStr); ClassMethodTypes.push_back(MakeConstantString(TypeStr)); } // Collect the names of referenced protocols SmallVector Protocols; const ObjCList &Protos =ClassDecl->getReferencedProtocols(); for (ObjCList::iterator I = Protos.begin(), E = Protos.end(); I != E; ++I) Protocols.push_back((*I)->getNameAsString()); // Get the superclass pointer. llvm::Constant *SuperClass; if (!SuperClassName.empty()) { SuperClass = MakeConstantString(SuperClassName, ".super_class_name"); } else { SuperClass = llvm::ConstantPointerNull::get(PtrToInt8Ty); } // Empty vector used to construct empty method lists SmallVector empty; // Generate the method and instance variable lists llvm::Constant *MethodList = GenerateMethodList(ClassName, "", InstanceMethodSels, InstanceMethodTypes, false); llvm::Constant *ClassMethodList = GenerateMethodList(ClassName, "", ClassMethodSels, ClassMethodTypes, true); llvm::Constant *IvarList = GenerateIvarList(IvarNames, IvarTypes, IvarOffsets); // Irrespective of whether we are compiling for a fragile or non-fragile ABI, // we emit a symbol containing the offset for each ivar in the class. This // allows code compiled for the non-Fragile ABI to inherit from code compiled // for the legacy ABI, without causing problems. The converse is also // possible, but causes all ivar accesses to be fragile. // Offset pointer for getting at the correct field in the ivar list when // setting up the alias. These are: The base address for the global, the // ivar array (second field), the ivar in this list (set for each ivar), and // the offset (third field in ivar structure) llvm::Type *IndexTy = Int32Ty; llvm::Constant *offsetPointerIndexes[] = {Zeros[0], llvm::ConstantInt::get(IndexTy, 1), 0, llvm::ConstantInt::get(IndexTy, 2) }; unsigned ivarIndex = 0; for (const ObjCIvarDecl *IVD = ClassDecl->all_declared_ivar_begin(); IVD; IVD = IVD->getNextIvar()) { const std::string Name = "__objc_ivar_offset_" + ClassName + '.' + IVD->getNameAsString(); offsetPointerIndexes[2] = llvm::ConstantInt::get(IndexTy, ivarIndex); // Get the correct ivar field llvm::Constant *offsetValue = llvm::ConstantExpr::getGetElementPtr( IvarList, offsetPointerIndexes); // Get the existing variable, if one exists. llvm::GlobalVariable *offset = TheModule.getNamedGlobal(Name); if (offset) { offset->setInitializer(offsetValue); // If this is the real definition, change its linkage type so that // different modules will use this one, rather than their private // copy. offset->setLinkage(llvm::GlobalValue::ExternalLinkage); } else { // Add a new alias if there isn't one already. offset = new llvm::GlobalVariable(TheModule, offsetValue->getType(), false, llvm::GlobalValue::ExternalLinkage, offsetValue, Name); } ++ivarIndex; } - llvm::Constant *Zero64 = llvm::ConstantInt::get(Int64Ty, 0); + llvm::Constant *ZeroPtr = llvm::ConstantInt::get(IntPtrTy, 0); //Generate metaclass for class methods llvm::Constant *MetaClassStruct = GenerateClassStructure(NULLPtr, NULLPtr, 0x12L, ClassName.c_str(), 0, Zeros[0], GenerateIvarList( empty, empty, empty), ClassMethodList, NULLPtr, - NULLPtr, NULLPtr, Zero64, Zero64, true); + NULLPtr, NULLPtr, ZeroPtr, ZeroPtr, true); // Generate the class structure llvm::Constant *ClassStruct = GenerateClassStructure(MetaClassStruct, SuperClass, 0x11L, ClassName.c_str(), 0, llvm::ConstantInt::get(LongTy, instanceSize), IvarList, MethodList, GenerateProtocolList(Protocols), IvarOffsetArray, Properties, StrongIvarBitmap, WeakIvarBitmap); // Resolve the class aliases, if they exist. if (ClassPtrAlias) { ClassPtrAlias->replaceAllUsesWith( llvm::ConstantExpr::getBitCast(ClassStruct, IdTy)); ClassPtrAlias->eraseFromParent(); ClassPtrAlias = 0; } if (MetaClassPtrAlias) { MetaClassPtrAlias->replaceAllUsesWith( llvm::ConstantExpr::getBitCast(MetaClassStruct, IdTy)); MetaClassPtrAlias->eraseFromParent(); MetaClassPtrAlias = 0; } // Add class structure to list to be added to the symtab later ClassStruct = llvm::ConstantExpr::getBitCast(ClassStruct, PtrToInt8Ty); Classes.push_back(ClassStruct); } llvm::Function *CGObjCGNU::ModuleInitFunction() { // Only emit an ObjC load function if no Objective-C stuff has been called if (Classes.empty() && Categories.empty() && ConstantStrings.empty() && ExistingProtocols.empty() && SelectorTable.empty()) return NULL; // Add all referenced protocols to a category. GenerateProtocolHolderCategory(); llvm::StructType *SelStructTy = dyn_cast( SelectorTy->getElementType()); llvm::Type *SelStructPtrTy = SelectorTy; if (SelStructTy == 0) { SelStructTy = llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, NULL); SelStructPtrTy = llvm::PointerType::getUnqual(SelStructTy); } std::vector Elements; llvm::Constant *Statics = NULLPtr; // Generate statics list: if (ConstantStrings.size()) { llvm::ArrayType *StaticsArrayTy = llvm::ArrayType::get(PtrToInt8Ty, ConstantStrings.size() + 1); ConstantStrings.push_back(NULLPtr); StringRef StringClass = CGM.getLangOptions().ObjCConstantStringClass; if (StringClass.empty()) StringClass = "NXConstantString"; Elements.push_back(MakeConstantString(StringClass, ".objc_static_class_name")); Elements.push_back(llvm::ConstantArray::get(StaticsArrayTy, ConstantStrings)); llvm::StructType *StaticsListTy = llvm::StructType::get(PtrToInt8Ty, StaticsArrayTy, NULL); llvm::Type *StaticsListPtrTy = llvm::PointerType::getUnqual(StaticsListTy); Statics = MakeGlobal(StaticsListTy, Elements, ".objc_statics"); llvm::ArrayType *StaticsListArrayTy = llvm::ArrayType::get(StaticsListPtrTy, 2); Elements.clear(); Elements.push_back(Statics); Elements.push_back(llvm::Constant::getNullValue(StaticsListPtrTy)); Statics = MakeGlobal(StaticsListArrayTy, Elements, ".objc_statics_ptr"); Statics = llvm::ConstantExpr::getBitCast(Statics, PtrTy); } // Array of classes, categories, and constant objects llvm::ArrayType *ClassListTy = llvm::ArrayType::get(PtrToInt8Ty, Classes.size() + Categories.size() + 2); llvm::StructType *SymTabTy = llvm::StructType::get(LongTy, SelStructPtrTy, llvm::Type::getInt16Ty(VMContext), llvm::Type::getInt16Ty(VMContext), ClassListTy, NULL); Elements.clear(); // Pointer to an array of selectors used in this module. std::vector Selectors; std::vector SelectorAliases; for (SelectorMap::iterator iter = SelectorTable.begin(), iterEnd = SelectorTable.end(); iter != iterEnd ; ++iter) { std::string SelNameStr = iter->first.getAsString(); llvm::Constant *SelName = ExportUniqueString(SelNameStr, ".objc_sel_name"); SmallVectorImpl &Types = iter->second; for (SmallVectorImpl::iterator i = Types.begin(), e = Types.end() ; i!=e ; i++) { llvm::Constant *SelectorTypeEncoding = NULLPtr; if (!i->first.empty()) SelectorTypeEncoding = MakeConstantString(i->first, ".objc_sel_types"); Elements.push_back(SelName); Elements.push_back(SelectorTypeEncoding); Selectors.push_back(llvm::ConstantStruct::get(SelStructTy, Elements)); Elements.clear(); // Store the selector alias for later replacement SelectorAliases.push_back(i->second); } } unsigned SelectorCount = Selectors.size(); // NULL-terminate the selector list. This should not actually be required, // because the selector list has a length field. Unfortunately, the GCC // runtime decides to ignore the length field and expects a NULL terminator, // and GCC cooperates with this by always setting the length to 0. Elements.push_back(NULLPtr); Elements.push_back(NULLPtr); Selectors.push_back(llvm::ConstantStruct::get(SelStructTy, Elements)); Elements.clear(); // Number of static selectors Elements.push_back(llvm::ConstantInt::get(LongTy, SelectorCount)); llvm::Constant *SelectorList = MakeGlobalArray(SelStructTy, Selectors, ".objc_selector_list"); Elements.push_back(llvm::ConstantExpr::getBitCast(SelectorList, SelStructPtrTy)); // Now that all of the static selectors exist, create pointers to them. for (unsigned int i=0 ; ireplaceAllUsesWith(SelPtr); SelectorAliases[i]->eraseFromParent(); } // Number of classes defined. Elements.push_back(llvm::ConstantInt::get(llvm::Type::getInt16Ty(VMContext), Classes.size())); // Number of categories defined Elements.push_back(llvm::ConstantInt::get(llvm::Type::getInt16Ty(VMContext), Categories.size())); // Create an array of classes, then categories, then static object instances Classes.insert(Classes.end(), Categories.begin(), Categories.end()); // NULL-terminated list of static object instances (mainly constant strings) Classes.push_back(Statics); Classes.push_back(NULLPtr); llvm::Constant *ClassList = llvm::ConstantArray::get(ClassListTy, Classes); Elements.push_back(ClassList); // Construct the symbol table llvm::Constant *SymTab= MakeGlobal(SymTabTy, Elements); // The symbol table is contained in a module which has some version-checking // constants llvm::StructType * ModuleTy = llvm::StructType::get(LongTy, LongTy, PtrToInt8Ty, llvm::PointerType::getUnqual(SymTabTy), (RuntimeVersion >= 10) ? IntTy : NULL, NULL); Elements.clear(); // Runtime version, used for ABI compatibility checking. Elements.push_back(llvm::ConstantInt::get(LongTy, RuntimeVersion)); // sizeof(ModuleTy) llvm::TargetData td(&TheModule); Elements.push_back( llvm::ConstantInt::get(LongTy, td.getTypeSizeInBits(ModuleTy) / CGM.getContext().getCharWidth())); // The path to the source file where this module was declared SourceManager &SM = CGM.getContext().getSourceManager(); const FileEntry *mainFile = SM.getFileEntryForID(SM.getMainFileID()); std::string path = std::string(mainFile->getDir()->getName()) + '/' + mainFile->getName(); Elements.push_back(MakeConstantString(path, ".objc_source_file_name")); Elements.push_back(SymTab); if (RuntimeVersion >= 10) switch (CGM.getLangOptions().getGC()) { case LangOptions::GCOnly: Elements.push_back(llvm::ConstantInt::get(IntTy, 2)); break; case LangOptions::NonGC: if (CGM.getLangOptions().ObjCAutoRefCount) Elements.push_back(llvm::ConstantInt::get(IntTy, 1)); else Elements.push_back(llvm::ConstantInt::get(IntTy, 0)); break; case LangOptions::HybridGC: Elements.push_back(llvm::ConstantInt::get(IntTy, 1)); break; } llvm::Value *Module = MakeGlobal(ModuleTy, Elements); // Create the load function calling the runtime entry point with the module // structure llvm::Function * LoadFunction = llvm::Function::Create( llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), false), llvm::GlobalValue::InternalLinkage, ".objc_load_function", &TheModule); llvm::BasicBlock *EntryBB = llvm::BasicBlock::Create(VMContext, "entry", LoadFunction); CGBuilderTy Builder(VMContext); Builder.SetInsertPoint(EntryBB); llvm::FunctionType *FT = llvm::FunctionType::get(Builder.getVoidTy(), llvm::PointerType::getUnqual(ModuleTy), true); llvm::Value *Register = CGM.CreateRuntimeFunction(FT, "__objc_exec_class"); Builder.CreateCall(Register, Module); Builder.CreateRetVoid(); return LoadFunction; } llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD, const ObjCContainerDecl *CD) { const ObjCCategoryImplDecl *OCD = dyn_cast(OMD->getDeclContext()); StringRef CategoryName = OCD ? OCD->getName() : ""; StringRef ClassName = CD->getName(); Selector MethodName = OMD->getSelector(); bool isClassMethod = !OMD->isInstanceMethod(); CodeGenTypes &Types = CGM.getTypes(); llvm::FunctionType *MethodTy = Types.GetFunctionType(Types.getFunctionInfo(OMD), OMD->isVariadic()); std::string FunctionName = SymbolNameForMethod(ClassName, CategoryName, MethodName, isClassMethod); llvm::Function *Method = llvm::Function::Create(MethodTy, llvm::GlobalValue::InternalLinkage, FunctionName, &TheModule); return Method; } llvm::Constant *CGObjCGNU::GetPropertyGetFunction() { return GetPropertyFn; } llvm::Constant *CGObjCGNU::GetPropertySetFunction() { return SetPropertyFn; } llvm::Constant *CGObjCGNU::GetGetStructFunction() { return GetStructPropertyFn; } llvm::Constant *CGObjCGNU::GetSetStructFunction() { return SetStructPropertyFn; } llvm::Constant *CGObjCGNU::EnumerationMutationFunction() { return EnumerationMutationFn; } void CGObjCGNU::EmitSynchronizedStmt(CodeGenFunction &CGF, const ObjCAtSynchronizedStmt &S) { EmitAtSynchronizedStmt(CGF, S, SyncEnterFn, SyncExitFn); } void CGObjCGNU::EmitTryStmt(CodeGenFunction &CGF, const ObjCAtTryStmt &S) { // Unlike the Apple non-fragile runtimes, which also uses // unwind-based zero cost exceptions, the GNU Objective C runtime's // EH support isn't a veneer over C++ EH. Instead, exception // objects are created by __objc_exception_throw and destroyed by // the personality function; this avoids the need for bracketing // catch handlers with calls to __blah_begin_catch/__blah_end_catch // (or even _Unwind_DeleteException), but probably doesn't // interoperate very well with foreign exceptions. // // In Objective-C++ mode, we actually emit something equivalent to the C++ // exception handler. EmitTryCatchStmt(CGF, S, EnterCatchFn, ExitCatchFn, ExceptionReThrowFn); return ; } void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF, const ObjCAtThrowStmt &S) { llvm::Value *ExceptionAsObject; if (const Expr *ThrowExpr = S.getThrowExpr()) { llvm::Value *Exception = CGF.EmitObjCThrowOperand(ThrowExpr); ExceptionAsObject = Exception; } else { assert((!CGF.ObjCEHValueStack.empty() && CGF.ObjCEHValueStack.back()) && "Unexpected rethrow outside @catch block."); ExceptionAsObject = CGF.ObjCEHValueStack.back(); } ExceptionAsObject = CGF.Builder.CreateBitCast(ExceptionAsObject, IdTy); // Note: This may have to be an invoke, if we want to support constructs like: // @try { // @throw(obj); // } // @catch(id) ... // // This is effectively turning @throw into an incredibly-expensive goto, but // it may happen as a result of inlining followed by missed optimizations, or // as a result of stupidity. llvm::BasicBlock *UnwindBB = CGF.getInvokeDest(); if (!UnwindBB) { CGF.Builder.CreateCall(ExceptionThrowFn, ExceptionAsObject); CGF.Builder.CreateUnreachable(); } else { CGF.Builder.CreateInvoke(ExceptionThrowFn, UnwindBB, UnwindBB, ExceptionAsObject); } // Clear the insertion point to indicate we are in unreachable code. CGF.Builder.ClearInsertionPoint(); } llvm::Value * CGObjCGNU::EmitObjCWeakRead(CodeGenFunction &CGF, llvm::Value *AddrWeakObj) { CGBuilderTy B = CGF.Builder; AddrWeakObj = EnforceType(B, AddrWeakObj, PtrToIdTy); return B.CreateCall(WeakReadFn, AddrWeakObj); } void CGObjCGNU::EmitObjCWeakAssign(CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst) { CGBuilderTy B = CGF.Builder; src = EnforceType(B, src, IdTy); dst = EnforceType(B, dst, PtrToIdTy); B.CreateCall2(WeakAssignFn, src, dst); } void CGObjCGNU::EmitObjCGlobalAssign(CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst, bool threadlocal) { CGBuilderTy B = CGF.Builder; src = EnforceType(B, src, IdTy); dst = EnforceType(B, dst, PtrToIdTy); if (!threadlocal) B.CreateCall2(GlobalAssignFn, src, dst); else // FIXME. Add threadloca assign API llvm_unreachable("EmitObjCGlobalAssign - Threal Local API NYI"); } void CGObjCGNU::EmitObjCIvarAssign(CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst, llvm::Value *ivarOffset) { CGBuilderTy B = CGF.Builder; src = EnforceType(B, src, IdTy); dst = EnforceType(B, dst, IdTy); B.CreateCall3(IvarAssignFn, src, dst, ivarOffset); } void CGObjCGNU::EmitObjCStrongCastAssign(CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst) { CGBuilderTy B = CGF.Builder; src = EnforceType(B, src, IdTy); dst = EnforceType(B, dst, PtrToIdTy); B.CreateCall2(StrongCastAssignFn, src, dst); } void CGObjCGNU::EmitGCMemmoveCollectable(CodeGenFunction &CGF, llvm::Value *DestPtr, llvm::Value *SrcPtr, llvm::Value *Size) { CGBuilderTy B = CGF.Builder; DestPtr = EnforceType(B, DestPtr, PtrTy); SrcPtr = EnforceType(B, SrcPtr, PtrTy); B.CreateCall3(MemMoveFn, DestPtr, SrcPtr, Size); } llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable( const ObjCInterfaceDecl *ID, const ObjCIvarDecl *Ivar) { const std::string Name = "__objc_ivar_offset_" + ID->getNameAsString() + '.' + Ivar->getNameAsString(); // Emit the variable and initialize it with what we think the correct value // is. This allows code compiled with non-fragile ivars to work correctly // when linked against code which isn't (most of the time). llvm::GlobalVariable *IvarOffsetPointer = TheModule.getNamedGlobal(Name); if (!IvarOffsetPointer) { // This will cause a run-time crash if we accidentally use it. A value of // 0 would seem more sensible, but will silently overwrite the isa pointer // causing a great deal of confusion. uint64_t Offset = -1; // We can't call ComputeIvarBaseOffset() here if we have the // implementation, because it will create an invalid ASTRecordLayout object // that we are then stuck with forever, so we only initialize the ivar // offset variable with a guess if we only have the interface. The // initializer will be reset later anyway, when we are generating the class // description. if (!CGM.getContext().getObjCImplementation( const_cast(ID))) Offset = ComputeIvarBaseOffset(CGM, ID, Ivar); llvm::ConstantInt *OffsetGuess = llvm::ConstantInt::get(Int32Ty, Offset, /*isSigned*/true); // Don't emit the guess in non-PIC code because the linker will not be able // to replace it with the real version for a library. In non-PIC code you // must compile with the fragile ABI if you want to use ivars from a // GCC-compiled class. if (CGM.getLangOptions().PICLevel) { llvm::GlobalVariable *IvarOffsetGV = new llvm::GlobalVariable(TheModule, Int32Ty, false, llvm::GlobalValue::PrivateLinkage, OffsetGuess, Name+".guess"); IvarOffsetPointer = new llvm::GlobalVariable(TheModule, IvarOffsetGV->getType(), false, llvm::GlobalValue::LinkOnceAnyLinkage, IvarOffsetGV, Name); } else { IvarOffsetPointer = new llvm::GlobalVariable(TheModule, llvm::Type::getInt32PtrTy(VMContext), false, llvm::GlobalValue::ExternalLinkage, 0, Name); } } return IvarOffsetPointer; } LValue CGObjCGNU::EmitObjCValueForIvar(CodeGenFunction &CGF, QualType ObjectTy, llvm::Value *BaseValue, const ObjCIvarDecl *Ivar, unsigned CVRQualifiers) { const ObjCInterfaceDecl *ID = ObjectTy->getAs()->getInterface(); return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers, EmitIvarOffset(CGF, ID, Ivar)); } static const ObjCInterfaceDecl *FindIvarInterface(ASTContext &Context, const ObjCInterfaceDecl *OID, const ObjCIvarDecl *OIVD) { for (const ObjCIvarDecl *next = OID->all_declared_ivar_begin(); next; next = next->getNextIvar()) { if (OIVD == next) return OID; } // Otherwise check in the super class. if (const ObjCInterfaceDecl *Super = OID->getSuperClass()) return FindIvarInterface(Context, Super, OIVD); return 0; } llvm::Value *CGObjCGNU::EmitIvarOffset(CodeGenFunction &CGF, const ObjCInterfaceDecl *Interface, const ObjCIvarDecl *Ivar) { if (CGM.getLangOptions().ObjCNonFragileABI) { Interface = FindIvarInterface(CGM.getContext(), Interface, Ivar); if (RuntimeVersion < 10) return CGF.Builder.CreateZExtOrBitCast( CGF.Builder.CreateLoad(CGF.Builder.CreateLoad( ObjCIvarOffsetVariable(Interface, Ivar), false, "ivar")), PtrDiffTy); std::string name = "__objc_ivar_offset_value_" + Interface->getNameAsString() +"." + Ivar->getNameAsString(); llvm::Value *Offset = TheModule.getGlobalVariable(name); if (!Offset) Offset = new llvm::GlobalVariable(TheModule, IntTy, false, llvm::GlobalValue::LinkOnceAnyLinkage, llvm::Constant::getNullValue(IntTy), name); return CGF.Builder.CreateLoad(Offset); } uint64_t Offset = ComputeIvarBaseOffset(CGF.CGM, Interface, Ivar); return llvm::ConstantInt::get(PtrDiffTy, Offset, /*isSigned*/true); } CGObjCRuntime * clang::CodeGen::CreateGNUObjCRuntime(CodeGenModule &CGM) { if (CGM.getLangOptions().ObjCNonFragileABI) return new CGObjCGNUstep(CGM); return new CGObjCGCC(CGM); } Index: head/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- head/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp (revision 228378) +++ head/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp (revision 228379) @@ -1,2435 +1,2486 @@ //===--- CodeGenModule.cpp - Emit LLVM Code from ASTs for a Module --------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This coordinates the per-module state used while generating code. // //===----------------------------------------------------------------------===// #include "CodeGenModule.h" #include "CGDebugInfo.h" #include "CodeGenFunction.h" #include "CodeGenTBAA.h" #include "CGCall.h" #include "CGCUDARuntime.h" #include "CGCXXABI.h" #include "CGObjCRuntime.h" #include "CGOpenCLRuntime.h" #include "TargetInfo.h" #include "clang/Frontend/CodeGenOptions.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CharUnits.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Mangle.h" #include "clang/AST/RecordLayout.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/ConvertUTF.h" #include "llvm/CallingConv.h" #include "llvm/Module.h" #include "llvm/Intrinsics.h" #include "llvm/LLVMContext.h" #include "llvm/ADT/Triple.h" #include "llvm/Target/Mangler.h" #include "llvm/Target/TargetData.h" #include "llvm/Support/CallSite.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; using namespace CodeGen; static const char AnnotationSection[] = "llvm.metadata"; static CGCXXABI &createCXXABI(CodeGenModule &CGM) { switch (CGM.getContext().getTargetInfo().getCXXABI()) { case CXXABI_ARM: return *CreateARMCXXABI(CGM); case CXXABI_Itanium: return *CreateItaniumCXXABI(CGM); case CXXABI_Microsoft: return *CreateMicrosoftCXXABI(CGM); } llvm_unreachable("invalid C++ ABI kind"); return *CreateItaniumCXXABI(CGM); } CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO, llvm::Module &M, const llvm::TargetData &TD, DiagnosticsEngine &diags) : Context(C), Features(C.getLangOptions()), CodeGenOpts(CGO), TheModule(M), TheTargetData(TD), TheTargetCodeGenInfo(0), Diags(diags), ABI(createCXXABI(*this)), Types(C, M, TD, getTargetCodeGenInfo().getABIInfo(), ABI, CGO), TBAA(0), VTables(*this), ObjCRuntime(0), OpenCLRuntime(0), CUDARuntime(0), DebugInfo(0), ARCData(0), RRData(0), CFConstantStringClassRef(0), ConstantStringClassRef(0), NSConstantStringType(0), VMContext(M.getContext()), NSConcreteGlobalBlock(0), NSConcreteStackBlock(0), BlockObjectAssign(0), BlockObjectDispose(0), BlockDescriptorType(0), GenericBlockLiteralType(0) { if (Features.ObjC1) createObjCRuntime(); if (Features.OpenCL) createOpenCLRuntime(); if (Features.CUDA) createCUDARuntime(); // Enable TBAA unless it's suppressed. if (!CodeGenOpts.RelaxedAliasing && CodeGenOpts.OptimizationLevel > 0) TBAA = new CodeGenTBAA(Context, VMContext, getLangOptions(), ABI.getMangleContext()); // If debug info or coverage generation is enabled, create the CGDebugInfo // object. if (CodeGenOpts.DebugInfo || CodeGenOpts.EmitGcovArcs || CodeGenOpts.EmitGcovNotes) DebugInfo = new CGDebugInfo(*this); Block.GlobalUniqueCount = 0; if (C.getLangOptions().ObjCAutoRefCount) ARCData = new ARCEntrypoints(); RRData = new RREntrypoints(); // Initialize the type cache. llvm::LLVMContext &LLVMContext = M.getContext(); VoidTy = llvm::Type::getVoidTy(LLVMContext); Int8Ty = llvm::Type::getInt8Ty(LLVMContext); Int32Ty = llvm::Type::getInt32Ty(LLVMContext); Int64Ty = llvm::Type::getInt64Ty(LLVMContext); PointerWidthInBits = C.getTargetInfo().getPointerWidth(0); PointerAlignInBytes = C.toCharUnitsFromBits(C.getTargetInfo().getPointerAlign(0)).getQuantity(); IntTy = llvm::IntegerType::get(LLVMContext, C.getTargetInfo().getIntWidth()); IntPtrTy = llvm::IntegerType::get(LLVMContext, PointerWidthInBits); Int8PtrTy = Int8Ty->getPointerTo(0); Int8PtrPtrTy = Int8PtrTy->getPointerTo(0); } CodeGenModule::~CodeGenModule() { delete ObjCRuntime; delete OpenCLRuntime; delete CUDARuntime; delete TheTargetCodeGenInfo; delete &ABI; delete TBAA; delete DebugInfo; delete ARCData; delete RRData; } void CodeGenModule::createObjCRuntime() { if (!Features.NeXTRuntime) ObjCRuntime = CreateGNUObjCRuntime(*this); else ObjCRuntime = CreateMacObjCRuntime(*this); } void CodeGenModule::createOpenCLRuntime() { OpenCLRuntime = new CGOpenCLRuntime(*this); } void CodeGenModule::createCUDARuntime() { CUDARuntime = CreateNVCUDARuntime(*this); } void CodeGenModule::Release() { EmitDeferred(); EmitCXXGlobalInitFunc(); EmitCXXGlobalDtorFunc(); if (ObjCRuntime) if (llvm::Function *ObjCInitFunction = ObjCRuntime->ModuleInitFunction()) AddGlobalCtor(ObjCInitFunction); EmitCtorList(GlobalCtors, "llvm.global_ctors"); EmitCtorList(GlobalDtors, "llvm.global_dtors"); EmitGlobalAnnotations(); EmitLLVMUsed(); SimplifyPersonality(); if (getCodeGenOpts().EmitDeclMetadata) EmitDeclMetadata(); if (getCodeGenOpts().EmitGcovArcs || getCodeGenOpts().EmitGcovNotes) EmitCoverageFile(); if (DebugInfo) DebugInfo->finalize(); } void CodeGenModule::UpdateCompletedType(const TagDecl *TD) { // Make sure that this type is translated. Types.UpdateCompletedType(TD); if (DebugInfo) DebugInfo->UpdateCompletedType(TD); } llvm::MDNode *CodeGenModule::getTBAAInfo(QualType QTy) { if (!TBAA) return 0; return TBAA->getTBAAInfo(QTy); } void CodeGenModule::DecorateInstruction(llvm::Instruction *Inst, llvm::MDNode *TBAAInfo) { Inst->setMetadata(llvm::LLVMContext::MD_tbaa, TBAAInfo); } bool CodeGenModule::isTargetDarwin() const { return getContext().getTargetInfo().getTriple().isOSDarwin(); } void CodeGenModule::Error(SourceLocation loc, StringRef error) { unsigned diagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, error); getDiags().Report(Context.getFullLoc(loc), diagID); } /// ErrorUnsupported - Print out an error that codegen doesn't support the /// specified stmt yet. void CodeGenModule::ErrorUnsupported(const Stmt *S, const char *Type, bool OmitOnError) { if (OmitOnError && getDiags().hasErrorOccurred()) return; unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, "cannot compile this %0 yet"); std::string Msg = Type; getDiags().Report(Context.getFullLoc(S->getLocStart()), DiagID) << Msg << S->getSourceRange(); } /// ErrorUnsupported - Print out an error that codegen doesn't support the /// specified decl yet. void CodeGenModule::ErrorUnsupported(const Decl *D, const char *Type, bool OmitOnError) { if (OmitOnError && getDiags().hasErrorOccurred()) return; unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, "cannot compile this %0 yet"); std::string Msg = Type; getDiags().Report(Context.getFullLoc(D->getLocation()), DiagID) << Msg; } llvm::ConstantInt *CodeGenModule::getSize(CharUnits size) { return llvm::ConstantInt::get(SizeTy, size.getQuantity()); } void CodeGenModule::setGlobalVisibility(llvm::GlobalValue *GV, const NamedDecl *D) const { // Internal definitions always have default visibility. if (GV->hasLocalLinkage()) { GV->setVisibility(llvm::GlobalValue::DefaultVisibility); return; } // Set visibility for definitions. NamedDecl::LinkageInfo LV = D->getLinkageAndVisibility(); if (LV.visibilityExplicit() || !GV->hasAvailableExternallyLinkage()) GV->setVisibility(GetLLVMVisibility(LV.visibility())); } /// Set the symbol visibility of type information (vtable and RTTI) /// associated with the given type. void CodeGenModule::setTypeVisibility(llvm::GlobalValue *GV, const CXXRecordDecl *RD, TypeVisibilityKind TVK) const { setGlobalVisibility(GV, RD); if (!CodeGenOpts.HiddenWeakVTables) return; // We never want to drop the visibility for RTTI names. if (TVK == TVK_ForRTTIName) return; // We want to drop the visibility to hidden for weak type symbols. // This isn't possible if there might be unresolved references // elsewhere that rely on this symbol being visible. // This should be kept roughly in sync with setThunkVisibility // in CGVTables.cpp. // Preconditions. if (GV->getLinkage() != llvm::GlobalVariable::LinkOnceODRLinkage || GV->getVisibility() != llvm::GlobalVariable::DefaultVisibility) return; // Don't override an explicit visibility attribute. if (RD->getExplicitVisibility()) return; switch (RD->getTemplateSpecializationKind()) { // We have to disable the optimization if this is an EI definition // because there might be EI declarations in other shared objects. case TSK_ExplicitInstantiationDefinition: case TSK_ExplicitInstantiationDeclaration: return; // Every use of a non-template class's type information has to emit it. case TSK_Undeclared: break; // In theory, implicit instantiations can ignore the possibility of // an explicit instantiation declaration because there necessarily // must be an EI definition somewhere with default visibility. In // practice, it's possible to have an explicit instantiation for // an arbitrary template class, and linkers aren't necessarily able // to deal with mixed-visibility symbols. case TSK_ExplicitSpecialization: case TSK_ImplicitInstantiation: if (!CodeGenOpts.HiddenWeakTemplateVTables) return; break; } // If there's a key function, there may be translation units // that don't have the key function's definition. But ignore // this if we're emitting RTTI under -fno-rtti. if (!(TVK != TVK_ForRTTI) || Features.RTTI) { if (Context.getKeyFunction(RD)) return; } // Otherwise, drop the visibility to hidden. GV->setVisibility(llvm::GlobalValue::HiddenVisibility); GV->setUnnamedAddr(true); } StringRef CodeGenModule::getMangledName(GlobalDecl GD) { const NamedDecl *ND = cast(GD.getDecl()); StringRef &Str = MangledDeclNames[GD.getCanonicalDecl()]; if (!Str.empty()) return Str; if (!getCXXABI().getMangleContext().shouldMangleDeclName(ND)) { IdentifierInfo *II = ND->getIdentifier(); assert(II && "Attempt to mangle unnamed decl."); Str = II->getName(); return Str; } llvm::SmallString<256> Buffer; llvm::raw_svector_ostream Out(Buffer); if (const CXXConstructorDecl *D = dyn_cast(ND)) getCXXABI().getMangleContext().mangleCXXCtor(D, GD.getCtorType(), Out); else if (const CXXDestructorDecl *D = dyn_cast(ND)) getCXXABI().getMangleContext().mangleCXXDtor(D, GD.getDtorType(), Out); else if (const BlockDecl *BD = dyn_cast(ND)) getCXXABI().getMangleContext().mangleBlock(BD, Out); else getCXXABI().getMangleContext().mangleName(ND, Out); // Allocate space for the mangled name. Out.flush(); size_t Length = Buffer.size(); char *Name = MangledNamesAllocator.Allocate(Length); std::copy(Buffer.begin(), Buffer.end(), Name); Str = StringRef(Name, Length); return Str; } void CodeGenModule::getBlockMangledName(GlobalDecl GD, MangleBuffer &Buffer, const BlockDecl *BD) { MangleContext &MangleCtx = getCXXABI().getMangleContext(); const Decl *D = GD.getDecl(); llvm::raw_svector_ostream Out(Buffer.getBuffer()); if (D == 0) MangleCtx.mangleGlobalBlock(BD, Out); else if (const CXXConstructorDecl *CD = dyn_cast(D)) MangleCtx.mangleCtorBlock(CD, GD.getCtorType(), BD, Out); else if (const CXXDestructorDecl *DD = dyn_cast(D)) MangleCtx.mangleDtorBlock(DD, GD.getDtorType(), BD, Out); else MangleCtx.mangleBlock(cast(D), BD, Out); } llvm::GlobalValue *CodeGenModule::GetGlobalValue(StringRef Name) { return getModule().getNamedValue(Name); } /// AddGlobalCtor - Add a function to the list that will be called before /// main() runs. void CodeGenModule::AddGlobalCtor(llvm::Function * Ctor, int Priority) { // FIXME: Type coercion of void()* types. GlobalCtors.push_back(std::make_pair(Ctor, Priority)); } /// AddGlobalDtor - Add a function to the list that will be called /// when the module is unloaded. void CodeGenModule::AddGlobalDtor(llvm::Function * Dtor, int Priority) { // FIXME: Type coercion of void()* types. GlobalDtors.push_back(std::make_pair(Dtor, Priority)); } void CodeGenModule::EmitCtorList(const CtorList &Fns, const char *GlobalName) { // Ctor function type is void()*. llvm::FunctionType* CtorFTy = llvm::FunctionType::get(VoidTy, false); llvm::Type *CtorPFTy = llvm::PointerType::getUnqual(CtorFTy); // Get the type of a ctor entry, { i32, void ()* }. llvm::StructType *CtorStructTy = llvm::StructType::get(llvm::Type::getInt32Ty(VMContext), llvm::PointerType::getUnqual(CtorFTy), NULL); // Construct the constructor and destructor arrays. std::vector Ctors; for (CtorList::const_iterator I = Fns.begin(), E = Fns.end(); I != E; ++I) { std::vector S; S.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), I->second, false)); S.push_back(llvm::ConstantExpr::getBitCast(I->first, CtorPFTy)); Ctors.push_back(llvm::ConstantStruct::get(CtorStructTy, S)); } if (!Ctors.empty()) { llvm::ArrayType *AT = llvm::ArrayType::get(CtorStructTy, Ctors.size()); new llvm::GlobalVariable(TheModule, AT, false, llvm::GlobalValue::AppendingLinkage, llvm::ConstantArray::get(AT, Ctors), GlobalName); } } llvm::GlobalValue::LinkageTypes CodeGenModule::getFunctionLinkage(const FunctionDecl *D) { GVALinkage Linkage = getContext().GetGVALinkageForFunction(D); if (Linkage == GVA_Internal) return llvm::Function::InternalLinkage; if (D->hasAttr()) return llvm::Function::DLLExportLinkage; if (D->hasAttr()) return llvm::Function::WeakAnyLinkage; // In C99 mode, 'inline' functions are guaranteed to have a strong // definition somewhere else, so we can use available_externally linkage. if (Linkage == GVA_C99Inline) return llvm::Function::AvailableExternallyLinkage; // Note that Apple's kernel linker doesn't support symbol // coalescing, so we need to avoid linkonce and weak linkages there. // Normally, this means we just map to internal, but for explicit // instantiations we'll map to external. // In C++, the compiler has to emit a definition in every translation unit // that references the function. We should use linkonce_odr because // a) if all references in this translation unit are optimized away, we // don't need to codegen it. b) if the function persists, it needs to be // merged with other definitions. c) C++ has the ODR, so we know the // definition is dependable. if (Linkage == GVA_CXXInline || Linkage == GVA_TemplateInstantiation) return !Context.getLangOptions().AppleKext ? llvm::Function::LinkOnceODRLinkage : llvm::Function::InternalLinkage; // An explicit instantiation of a template has weak linkage, since // explicit instantiations can occur in multiple translation units // and must all be equivalent. However, we are not allowed to // throw away these explicit instantiations. if (Linkage == GVA_ExplicitTemplateInstantiation) return !Context.getLangOptions().AppleKext ? llvm::Function::WeakODRLinkage : llvm::Function::ExternalLinkage; // Otherwise, we have strong external linkage. assert(Linkage == GVA_StrongExternal); return llvm::Function::ExternalLinkage; } /// SetFunctionDefinitionAttributes - Set attributes for a global. /// /// FIXME: This is currently only done for aliases and functions, but not for /// variables (these details are set in EmitGlobalVarDefinition for variables). void CodeGenModule::SetFunctionDefinitionAttributes(const FunctionDecl *D, llvm::GlobalValue *GV) { SetCommonAttributes(D, GV); } void CodeGenModule::SetLLVMFunctionAttributes(const Decl *D, const CGFunctionInfo &Info, llvm::Function *F) { unsigned CallingConv; AttributeListType AttributeList; ConstructAttributeList(Info, D, AttributeList, CallingConv); F->setAttributes(llvm::AttrListPtr::get(AttributeList.begin(), AttributeList.size())); F->setCallingConv(static_cast(CallingConv)); } /// Determines whether the language options require us to model /// unwind exceptions. We treat -fexceptions as mandating this /// except under the fragile ObjC ABI with only ObjC exceptions /// enabled. This means, for example, that C with -fexceptions /// enables this. static bool hasUnwindExceptions(const LangOptions &Features) { // If exceptions are completely disabled, obviously this is false. if (!Features.Exceptions) return false; // If C++ exceptions are enabled, this is true. if (Features.CXXExceptions) return true; // If ObjC exceptions are enabled, this depends on the ABI. if (Features.ObjCExceptions) { if (!Features.ObjCNonFragileABI) return false; } return true; } void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, llvm::Function *F) { if (CodeGenOpts.UnwindTables) F->setHasUWTable(); if (!hasUnwindExceptions(Features)) F->addFnAttr(llvm::Attribute::NoUnwind); if (D->hasAttr()) { // Naked implies noinline: we should not be inlining such functions. F->addFnAttr(llvm::Attribute::Naked); F->addFnAttr(llvm::Attribute::NoInline); } if (D->hasAttr()) F->addFnAttr(llvm::Attribute::NoInline); // (noinline wins over always_inline, and we can't specify both in IR) if (D->hasAttr() && !F->hasFnAttr(llvm::Attribute::NoInline)) F->addFnAttr(llvm::Attribute::AlwaysInline); if (isa(D) || isa(D)) F->setUnnamedAddr(true); if (Features.getStackProtector() == LangOptions::SSPOn) F->addFnAttr(llvm::Attribute::StackProtect); else if (Features.getStackProtector() == LangOptions::SSPReq) F->addFnAttr(llvm::Attribute::StackProtectReq); unsigned alignment = D->getMaxAlignment() / Context.getCharWidth(); if (alignment) F->setAlignment(alignment); // C++ ABI requires 2-byte alignment for member functions. if (F->getAlignment() < 2 && isa(D)) F->setAlignment(2); } void CodeGenModule::SetCommonAttributes(const Decl *D, llvm::GlobalValue *GV) { if (const NamedDecl *ND = dyn_cast(D)) setGlobalVisibility(GV, ND); else GV->setVisibility(llvm::GlobalValue::DefaultVisibility); if (D->hasAttr()) AddUsedGlobal(GV); if (const SectionAttr *SA = D->getAttr()) GV->setSection(SA->getName()); getTargetCodeGenInfo().SetTargetAttributes(D, GV, *this); } void CodeGenModule::SetInternalFunctionAttributes(const Decl *D, llvm::Function *F, const CGFunctionInfo &FI) { SetLLVMFunctionAttributes(D, FI, F); SetLLVMFunctionAttributesForDefinition(D, F); F->setLinkage(llvm::Function::InternalLinkage); SetCommonAttributes(D, F); } void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F, bool IsIncompleteFunction) { if (unsigned IID = F->getIntrinsicID()) { // If this is an intrinsic function, set the function's attributes // to the intrinsic's attributes. F->setAttributes(llvm::Intrinsic::getAttributes((llvm::Intrinsic::ID)IID)); return; } const FunctionDecl *FD = cast(GD.getDecl()); if (!IsIncompleteFunction) SetLLVMFunctionAttributes(FD, getTypes().getFunctionInfo(GD), F); // Only a few attributes are set on declarations; these may later be // overridden by a definition. if (FD->hasAttr()) { F->setLinkage(llvm::Function::DLLImportLinkage); } else if (FD->hasAttr() || FD->isWeakImported()) { // "extern_weak" is overloaded in LLVM; we probably should have // separate linkage types for this. F->setLinkage(llvm::Function::ExternalWeakLinkage); } else { F->setLinkage(llvm::Function::ExternalLinkage); NamedDecl::LinkageInfo LV = FD->getLinkageAndVisibility(); if (LV.linkage() == ExternalLinkage && LV.visibilityExplicit()) { F->setVisibility(GetLLVMVisibility(LV.visibility())); } } if (const SectionAttr *SA = FD->getAttr()) F->setSection(SA->getName()); } void CodeGenModule::AddUsedGlobal(llvm::GlobalValue *GV) { assert(!GV->isDeclaration() && "Only globals with definition can force usage."); LLVMUsed.push_back(GV); } void CodeGenModule::EmitLLVMUsed() { // Don't create llvm.used if there is no need. if (LLVMUsed.empty()) return; llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(VMContext); // Convert LLVMUsed to what ConstantArray needs. std::vector UsedArray; UsedArray.resize(LLVMUsed.size()); for (unsigned i = 0, e = LLVMUsed.size(); i != e; ++i) { UsedArray[i] = llvm::ConstantExpr::getBitCast(cast(&*LLVMUsed[i]), i8PTy); } if (UsedArray.empty()) return; llvm::ArrayType *ATy = llvm::ArrayType::get(i8PTy, UsedArray.size()); llvm::GlobalVariable *GV = new llvm::GlobalVariable(getModule(), ATy, false, llvm::GlobalValue::AppendingLinkage, llvm::ConstantArray::get(ATy, UsedArray), "llvm.used"); GV->setSection("llvm.metadata"); } void CodeGenModule::EmitDeferred() { // Emit code for any potentially referenced deferred decls. Since a // previously unused static decl may become used during the generation of code // for a static function, iterate until no changes are made. while (!DeferredDeclsToEmit.empty() || !DeferredVTables.empty()) { if (!DeferredVTables.empty()) { const CXXRecordDecl *RD = DeferredVTables.back(); DeferredVTables.pop_back(); getVTables().GenerateClassData(getVTableLinkage(RD), RD); continue; } GlobalDecl D = DeferredDeclsToEmit.back(); DeferredDeclsToEmit.pop_back(); // Check to see if we've already emitted this. This is necessary // for a couple of reasons: first, decls can end up in the // deferred-decls queue multiple times, and second, decls can end // up with definitions in unusual ways (e.g. by an extern inline // function acquiring a strong function redefinition). Just // ignore these cases. // // TODO: That said, looking this up multiple times is very wasteful. StringRef Name = getMangledName(D); llvm::GlobalValue *CGRef = GetGlobalValue(Name); assert(CGRef && "Deferred decl wasn't referenced?"); if (!CGRef->isDeclaration()) continue; // GlobalAlias::isDeclaration() defers to the aliasee, but for our // purposes an alias counts as a definition. if (isa(CGRef)) continue; // Otherwise, emit the definition and move on to the next one. EmitGlobalDefinition(D); } } void CodeGenModule::EmitGlobalAnnotations() { if (Annotations.empty()) return; // Create a new global variable for the ConstantStruct in the Module. llvm::Constant *Array = llvm::ConstantArray::get(llvm::ArrayType::get( Annotations[0]->getType(), Annotations.size()), Annotations); llvm::GlobalValue *gv = new llvm::GlobalVariable(getModule(), Array->getType(), false, llvm::GlobalValue::AppendingLinkage, Array, "llvm.global.annotations"); gv->setSection(AnnotationSection); } llvm::Constant *CodeGenModule::EmitAnnotationString(llvm::StringRef Str) { llvm::StringMap::iterator i = AnnotationStrings.find(Str); if (i != AnnotationStrings.end()) return i->second; // Not found yet, create a new global. llvm::Constant *s = llvm::ConstantArray::get(getLLVMContext(), Str, true); llvm::GlobalValue *gv = new llvm::GlobalVariable(getModule(), s->getType(), true, llvm::GlobalValue::PrivateLinkage, s, ".str"); gv->setSection(AnnotationSection); gv->setUnnamedAddr(true); AnnotationStrings[Str] = gv; return gv; } llvm::Constant *CodeGenModule::EmitAnnotationUnit(SourceLocation Loc) { SourceManager &SM = getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(Loc); if (PLoc.isValid()) return EmitAnnotationString(PLoc.getFilename()); return EmitAnnotationString(SM.getBufferName(Loc)); } llvm::Constant *CodeGenModule::EmitAnnotationLineNo(SourceLocation L) { SourceManager &SM = getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(L); unsigned LineNo = PLoc.isValid() ? PLoc.getLine() : SM.getExpansionLineNumber(L); return llvm::ConstantInt::get(Int32Ty, LineNo); } llvm::Constant *CodeGenModule::EmitAnnotateAttr(llvm::GlobalValue *GV, const AnnotateAttr *AA, SourceLocation L) { // Get the globals for file name, annotation, and the line number. llvm::Constant *AnnoGV = EmitAnnotationString(AA->getAnnotation()), *UnitGV = EmitAnnotationUnit(L), *LineNoCst = EmitAnnotationLineNo(L); // Create the ConstantStruct for the global annotation. llvm::Constant *Fields[4] = { llvm::ConstantExpr::getBitCast(GV, Int8PtrTy), llvm::ConstantExpr::getBitCast(AnnoGV, Int8PtrTy), llvm::ConstantExpr::getBitCast(UnitGV, Int8PtrTy), LineNoCst }; return llvm::ConstantStruct::getAnon(Fields); } void CodeGenModule::AddGlobalAnnotations(const ValueDecl *D, llvm::GlobalValue *GV) { assert(D->hasAttr() && "no annotate attribute"); // Get the struct elements for these annotations. for (specific_attr_iterator ai = D->specific_attr_begin(), ae = D->specific_attr_end(); ai != ae; ++ai) Annotations.push_back(EmitAnnotateAttr(GV, *ai, D->getLocation())); } bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) { // Never defer when EmitAllDecls is specified. if (Features.EmitAllDecls) return false; return !getContext().DeclMustBeEmitted(Global); } llvm::Constant *CodeGenModule::GetWeakRefReference(const ValueDecl *VD) { const AliasAttr *AA = VD->getAttr(); assert(AA && "No alias?"); llvm::Type *DeclTy = getTypes().ConvertTypeForMem(VD->getType()); // See if there is already something with the target's name in the module. llvm::GlobalValue *Entry = GetGlobalValue(AA->getAliasee()); llvm::Constant *Aliasee; if (isa(DeclTy)) Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy, GlobalDecl(), /*ForVTable=*/false); else Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(), llvm::PointerType::getUnqual(DeclTy), 0); if (!Entry) { llvm::GlobalValue* F = cast(Aliasee); F->setLinkage(llvm::Function::ExternalWeakLinkage); WeakRefReferences.insert(F); } return Aliasee; } void CodeGenModule::EmitGlobal(GlobalDecl GD) { const ValueDecl *Global = cast(GD.getDecl()); // Weak references don't produce any output by themselves. if (Global->hasAttr()) return; // If this is an alias definition (which otherwise looks like a declaration) // emit it now. if (Global->hasAttr()) return EmitAliasDefinition(GD); // If this is CUDA, be selective about which declarations we emit. if (Features.CUDA) { if (CodeGenOpts.CUDAIsDevice) { if (!Global->hasAttr() && !Global->hasAttr() && !Global->hasAttr() && !Global->hasAttr()) return; } else { if (!Global->hasAttr() && ( Global->hasAttr() || Global->hasAttr() || Global->hasAttr())) return; } } // Ignore declarations, they will be emitted on their first use. if (const FunctionDecl *FD = dyn_cast(Global)) { // Forward declarations are emitted lazily on first use. if (!FD->doesThisDeclarationHaveABody()) { if (!FD->doesDeclarationForceExternallyVisibleDefinition()) return; const FunctionDecl *InlineDefinition = 0; FD->getBody(InlineDefinition); StringRef MangledName = getMangledName(GD); llvm::StringMap::iterator DDI = DeferredDecls.find(MangledName); if (DDI != DeferredDecls.end()) DeferredDecls.erase(DDI); EmitGlobalDefinition(InlineDefinition); return; } } else { const VarDecl *VD = cast(Global); assert(VD->isFileVarDecl() && "Cannot emit local var decl as global."); if (VD->isThisDeclarationADefinition() != VarDecl::Definition) return; } // Defer code generation when possible if this is a static definition, inline // function etc. These we only want to emit if they are used. if (!MayDeferGeneration(Global)) { // Emit the definition if it can't be deferred. EmitGlobalDefinition(GD); return; } // If we're deferring emission of a C++ variable with an // initializer, remember the order in which it appeared in the file. if (getLangOptions().CPlusPlus && isa(Global) && cast(Global)->hasInit()) { DelayedCXXInitPosition[Global] = CXXGlobalInits.size(); CXXGlobalInits.push_back(0); } // If the value has already been used, add it directly to the // DeferredDeclsToEmit list. StringRef MangledName = getMangledName(GD); if (GetGlobalValue(MangledName)) DeferredDeclsToEmit.push_back(GD); else { // Otherwise, remember that we saw a deferred decl with this name. The // first use of the mangled name will cause it to move into // DeferredDeclsToEmit. DeferredDecls[MangledName] = GD; } } +namespace { + struct FunctionIsDirectlyRecursive : + public RecursiveASTVisitor { + const StringRef Name; + bool Result; + FunctionIsDirectlyRecursive(const FunctionDecl *F) : + Name(F->getName()), Result(false) { + } + typedef RecursiveASTVisitor Base; + + bool TraverseCallExpr(CallExpr *E) { + const Decl *D = E->getCalleeDecl(); + if (!D) + return true; + AsmLabelAttr *Attr = D->getAttr(); + if (!Attr) + return true; + if (Name == Attr->getLabel()) { + Result = true; + return false; + } + return true; + } + }; +} + +// isTriviallyRecursiveViaAsm - Check if this function calls another +// decl that, because of the asm attribute, ends up pointing to itself. +bool +CodeGenModule::isTriviallyRecursiveViaAsm(const FunctionDecl *F) { + if (getCXXABI().getMangleContext().shouldMangleDeclName(F)) + return false; + + FunctionIsDirectlyRecursive Walker(F); + Walker.TraverseFunctionDecl(const_cast(F)); + return Walker.Result; +} + +bool +CodeGenModule::shouldEmitFunction(const FunctionDecl *F) { + if (getFunctionLinkage(F) != llvm::Function::AvailableExternallyLinkage) + return true; + if (CodeGenOpts.OptimizationLevel == 0 && + !F->hasAttr()) + return false; + // PR9614. Avoid cases where the source code is lying to us. An available + // externally function should have an equivalent function somewhere else, + // but a function that calls itself is clearly not equivalent to the real + // implementation. + // This happens in glibc's btowc and in some configure checks. + return !isTriviallyRecursiveViaAsm(F); +} + void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { const ValueDecl *D = cast(GD.getDecl()); PrettyStackTraceDecl CrashInfo(const_cast(D), D->getLocation(), Context.getSourceManager(), "Generating code for declaration"); if (const FunctionDecl *Function = dyn_cast(D)) { // At -O0, don't generate IR for functions with available_externally // linkage. - if (CodeGenOpts.OptimizationLevel == 0 && - !Function->hasAttr() && - getFunctionLinkage(Function) - == llvm::Function::AvailableExternallyLinkage) + if (!shouldEmitFunction(Function)) return; if (const CXXMethodDecl *Method = dyn_cast(D)) { // Make sure to emit the definition(s) before we emit the thunks. // This is necessary for the generation of certain thunks. if (const CXXConstructorDecl *CD = dyn_cast(Method)) EmitCXXConstructor(CD, GD.getCtorType()); else if (const CXXDestructorDecl *DD =dyn_cast(Method)) EmitCXXDestructor(DD, GD.getDtorType()); else EmitGlobalFunctionDefinition(GD); if (Method->isVirtual()) getVTables().EmitThunks(GD); return; } return EmitGlobalFunctionDefinition(GD); } if (const VarDecl *VD = dyn_cast(D)) return EmitGlobalVarDefinition(VD); llvm_unreachable("Invalid argument to EmitGlobalDefinition()"); } /// GetOrCreateLLVMFunction - If the specified mangled name is not in the /// module, create and return an llvm Function with the specified type. If there /// is something in the module with the specified name, return it potentially /// bitcasted to the right type. /// /// If D is non-null, it specifies a decl that correspond to this. This is used /// to set the attributes on the function when it is first created. llvm::Constant * CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName, llvm::Type *Ty, GlobalDecl D, bool ForVTable, llvm::Attributes ExtraAttrs) { // Lookup the entry, lazily creating it if necessary. llvm::GlobalValue *Entry = GetGlobalValue(MangledName); if (Entry) { if (WeakRefReferences.count(Entry)) { const FunctionDecl *FD = cast_or_null(D.getDecl()); if (FD && !FD->hasAttr()) Entry->setLinkage(llvm::Function::ExternalLinkage); WeakRefReferences.erase(Entry); } if (Entry->getType()->getElementType() == Ty) return Entry; // Make sure the result is of the correct type. return llvm::ConstantExpr::getBitCast(Entry, Ty->getPointerTo()); } // This function doesn't have a complete type (for example, the return // type is an incomplete struct). Use a fake type instead, and make // sure not to try to set attributes. bool IsIncompleteFunction = false; llvm::FunctionType *FTy; if (isa(Ty)) { FTy = cast(Ty); } else { FTy = llvm::FunctionType::get(VoidTy, false); IsIncompleteFunction = true; } llvm::Function *F = llvm::Function::Create(FTy, llvm::Function::ExternalLinkage, MangledName, &getModule()); assert(F->getName() == MangledName && "name was uniqued!"); if (D.getDecl()) SetFunctionAttributes(D, F, IsIncompleteFunction); if (ExtraAttrs != llvm::Attribute::None) F->addFnAttr(ExtraAttrs); // This is the first use or definition of a mangled name. If there is a // deferred decl with this name, remember that we need to emit it at the end // of the file. llvm::StringMap::iterator DDI = DeferredDecls.find(MangledName); if (DDI != DeferredDecls.end()) { // Move the potentially referenced deferred decl to the DeferredDeclsToEmit // list, and remove it from DeferredDecls (since we don't need it anymore). DeferredDeclsToEmit.push_back(DDI->second); DeferredDecls.erase(DDI); // Otherwise, there are cases we have to worry about where we're // using a declaration for which we must emit a definition but where // we might not find a top-level definition: // - member functions defined inline in their classes // - friend functions defined inline in some class // - special member functions with implicit definitions // If we ever change our AST traversal to walk into class methods, // this will be unnecessary. // // We also don't emit a definition for a function if it's going to be an entry // in a vtable, unless it's already marked as used. } else if (getLangOptions().CPlusPlus && D.getDecl()) { // Look for a declaration that's lexically in a record. const FunctionDecl *FD = cast(D.getDecl()); do { if (isa(FD->getLexicalDeclContext())) { if (FD->isImplicit() && !ForVTable) { assert(FD->isUsed() && "Sema didn't mark implicit function as used!"); DeferredDeclsToEmit.push_back(D.getWithDecl(FD)); break; } else if (FD->doesThisDeclarationHaveABody()) { DeferredDeclsToEmit.push_back(D.getWithDecl(FD)); break; } } FD = FD->getPreviousDeclaration(); } while (FD); } // Make sure the result is of the requested type. if (!IsIncompleteFunction) { assert(F->getType()->getElementType() == Ty); return F; } llvm::Type *PTy = llvm::PointerType::getUnqual(Ty); return llvm::ConstantExpr::getBitCast(F, PTy); } /// GetAddrOfFunction - Return the address of the given function. If Ty is /// non-null, then this function will use the specified type if it has to /// create it (this occurs when we see a definition of the function). llvm::Constant *CodeGenModule::GetAddrOfFunction(GlobalDecl GD, llvm::Type *Ty, bool ForVTable) { // If there was no specific requested type, just convert it now. if (!Ty) Ty = getTypes().ConvertType(cast(GD.getDecl())->getType()); StringRef MangledName = getMangledName(GD); return GetOrCreateLLVMFunction(MangledName, Ty, GD, ForVTable); } /// CreateRuntimeFunction - Create a new runtime function with the specified /// type and name. llvm::Constant * CodeGenModule::CreateRuntimeFunction(llvm::FunctionType *FTy, StringRef Name, llvm::Attributes ExtraAttrs) { return GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false, ExtraAttrs); } static bool DeclIsConstantGlobal(ASTContext &Context, const VarDecl *D, bool ConstantInit) { if (!D->getType().isConstant(Context) && !D->getType()->isReferenceType()) return false; if (Context.getLangOptions().CPlusPlus) { if (const RecordType *Record = Context.getBaseElementType(D->getType())->getAs()) return ConstantInit && cast(Record->getDecl())->isPOD() && !cast(Record->getDecl())->hasMutableFields(); } return true; } /// GetOrCreateLLVMGlobal - If the specified mangled name is not in the module, /// create and return an llvm GlobalVariable with the specified type. If there /// is something in the module with the specified name, return it potentially /// bitcasted to the right type. /// /// If D is non-null, it specifies a decl that correspond to this. This is used /// to set the attributes on the global when it is first created. llvm::Constant * CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, llvm::PointerType *Ty, const VarDecl *D, bool UnnamedAddr) { // Lookup the entry, lazily creating it if necessary. llvm::GlobalValue *Entry = GetGlobalValue(MangledName); if (Entry) { if (WeakRefReferences.count(Entry)) { if (D && !D->hasAttr()) Entry->setLinkage(llvm::Function::ExternalLinkage); WeakRefReferences.erase(Entry); } if (UnnamedAddr) Entry->setUnnamedAddr(true); if (Entry->getType() == Ty) return Entry; // Make sure the result is of the correct type. return llvm::ConstantExpr::getBitCast(Entry, Ty); } // This is the first use or definition of a mangled name. If there is a // deferred decl with this name, remember that we need to emit it at the end // of the file. llvm::StringMap::iterator DDI = DeferredDecls.find(MangledName); if (DDI != DeferredDecls.end()) { // Move the potentially referenced deferred decl to the DeferredDeclsToEmit // list, and remove it from DeferredDecls (since we don't need it anymore). DeferredDeclsToEmit.push_back(DDI->second); DeferredDecls.erase(DDI); } llvm::GlobalVariable *GV = new llvm::GlobalVariable(getModule(), Ty->getElementType(), false, llvm::GlobalValue::ExternalLinkage, 0, MangledName, 0, false, Ty->getAddressSpace()); // Handle things which are present even on external declarations. if (D) { // FIXME: This code is overly simple and should be merged with other global // handling. GV->setConstant(DeclIsConstantGlobal(Context, D, false)); // Set linkage and visibility in case we never see a definition. NamedDecl::LinkageInfo LV = D->getLinkageAndVisibility(); if (LV.linkage() != ExternalLinkage) { // Don't set internal linkage on declarations. } else { if (D->hasAttr()) GV->setLinkage(llvm::GlobalValue::DLLImportLinkage); else if (D->hasAttr() || D->isWeakImported()) GV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); // Set visibility on a declaration only if it's explicit. if (LV.visibilityExplicit()) GV->setVisibility(GetLLVMVisibility(LV.visibility())); } GV->setThreadLocal(D->isThreadSpecified()); } return GV; } llvm::GlobalVariable * CodeGenModule::CreateOrReplaceCXXRuntimeVariable(StringRef Name, llvm::Type *Ty, llvm::GlobalValue::LinkageTypes Linkage) { llvm::GlobalVariable *GV = getModule().getNamedGlobal(Name); llvm::GlobalVariable *OldGV = 0; if (GV) { // Check if the variable has the right type. if (GV->getType()->getElementType() == Ty) return GV; // Because C++ name mangling, the only way we can end up with an already // existing global with the same name is if it has been declared extern "C". assert(GV->isDeclaration() && "Declaration has wrong type!"); OldGV = GV; } // Create a new variable. GV = new llvm::GlobalVariable(getModule(), Ty, /*isConstant=*/true, Linkage, 0, Name); if (OldGV) { // Replace occurrences of the old variable if needed. GV->takeName(OldGV); if (!OldGV->use_empty()) { llvm::Constant *NewPtrForOldDecl = llvm::ConstantExpr::getBitCast(GV, OldGV->getType()); OldGV->replaceAllUsesWith(NewPtrForOldDecl); } OldGV->eraseFromParent(); } return GV; } /// GetAddrOfGlobalVar - Return the llvm::Constant for the address of the /// given global variable. If Ty is non-null and if the global doesn't exist, /// then it will be greated with the specified type instead of whatever the /// normal requested type would be. llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D, llvm::Type *Ty) { assert(D->hasGlobalStorage() && "Not a global variable"); QualType ASTTy = D->getType(); if (Ty == 0) Ty = getTypes().ConvertTypeForMem(ASTTy); llvm::PointerType *PTy = llvm::PointerType::get(Ty, getContext().getTargetAddressSpace(ASTTy)); StringRef MangledName = getMangledName(D); return GetOrCreateLLVMGlobal(MangledName, PTy, D); } /// CreateRuntimeVariable - Create a new runtime global variable with the /// specified type and name. llvm::Constant * CodeGenModule::CreateRuntimeVariable(llvm::Type *Ty, StringRef Name) { return GetOrCreateLLVMGlobal(Name, llvm::PointerType::getUnqual(Ty), 0, true); } void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) { assert(!D->getInit() && "Cannot emit definite definitions here!"); if (MayDeferGeneration(D)) { // If we have not seen a reference to this variable yet, place it // into the deferred declarations table to be emitted if needed // later. StringRef MangledName = getMangledName(D); if (!GetGlobalValue(MangledName)) { DeferredDecls[MangledName] = D; return; } } // The tentative definition is the only definition. EmitGlobalVarDefinition(D); } void CodeGenModule::EmitVTable(CXXRecordDecl *Class, bool DefinitionRequired) { if (DefinitionRequired) getVTables().GenerateClassData(getVTableLinkage(Class), Class); } llvm::GlobalVariable::LinkageTypes CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) { if (RD->getLinkage() != ExternalLinkage) return llvm::GlobalVariable::InternalLinkage; if (const CXXMethodDecl *KeyFunction = RD->getASTContext().getKeyFunction(RD)) { // If this class has a key function, use that to determine the linkage of // the vtable. const FunctionDecl *Def = 0; if (KeyFunction->hasBody(Def)) KeyFunction = cast(Def); switch (KeyFunction->getTemplateSpecializationKind()) { case TSK_Undeclared: case TSK_ExplicitSpecialization: // When compiling with optimizations turned on, we emit all vtables, // even if the key function is not defined in the current translation // unit. If this is the case, use available_externally linkage. if (!Def && CodeGenOpts.OptimizationLevel) return llvm::GlobalVariable::AvailableExternallyLinkage; if (KeyFunction->isInlined()) return !Context.getLangOptions().AppleKext ? llvm::GlobalVariable::LinkOnceODRLinkage : llvm::Function::InternalLinkage; return llvm::GlobalVariable::ExternalLinkage; case TSK_ImplicitInstantiation: return !Context.getLangOptions().AppleKext ? llvm::GlobalVariable::LinkOnceODRLinkage : llvm::Function::InternalLinkage; case TSK_ExplicitInstantiationDefinition: return !Context.getLangOptions().AppleKext ? llvm::GlobalVariable::WeakODRLinkage : llvm::Function::InternalLinkage; case TSK_ExplicitInstantiationDeclaration: // FIXME: Use available_externally linkage. However, this currently // breaks LLVM's build due to undefined symbols. // return llvm::GlobalVariable::AvailableExternallyLinkage; return !Context.getLangOptions().AppleKext ? llvm::GlobalVariable::LinkOnceODRLinkage : llvm::Function::InternalLinkage; } } if (Context.getLangOptions().AppleKext) return llvm::Function::InternalLinkage; switch (RD->getTemplateSpecializationKind()) { case TSK_Undeclared: case TSK_ExplicitSpecialization: case TSK_ImplicitInstantiation: // FIXME: Use available_externally linkage. However, this currently // breaks LLVM's build due to undefined symbols. // return llvm::GlobalVariable::AvailableExternallyLinkage; case TSK_ExplicitInstantiationDeclaration: return llvm::GlobalVariable::LinkOnceODRLinkage; case TSK_ExplicitInstantiationDefinition: return llvm::GlobalVariable::WeakODRLinkage; } // Silence GCC warning. return llvm::GlobalVariable::LinkOnceODRLinkage; } CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const { return Context.toCharUnitsFromBits( TheTargetData.getTypeStoreSizeInBits(Ty)); } void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { llvm::Constant *Init = 0; QualType ASTTy = D->getType(); bool NonConstInit = false; const Expr *InitExpr = D->getAnyInitializer(); if (!InitExpr) { // This is a tentative definition; tentative definitions are // implicitly initialized with { 0 }. // // Note that tentative definitions are only emitted at the end of // a translation unit, so they should never have incomplete // type. In addition, EmitTentativeDefinition makes sure that we // never attempt to emit a tentative definition if a real one // exists. A use may still exists, however, so we still may need // to do a RAUW. assert(!ASTTy->isIncompleteType() && "Unexpected incomplete type"); Init = EmitNullConstant(D->getType()); } else { Init = EmitConstantExpr(InitExpr, D->getType()); if (!Init) { QualType T = InitExpr->getType(); if (D->getType()->isReferenceType()) T = D->getType(); if (getLangOptions().CPlusPlus) { Init = EmitNullConstant(T); NonConstInit = true; } else { ErrorUnsupported(D, "static initializer"); Init = llvm::UndefValue::get(getTypes().ConvertType(T)); } } else { // We don't need an initializer, so remove the entry for the delayed // initializer position (just in case this entry was delayed). if (getLangOptions().CPlusPlus) DelayedCXXInitPosition.erase(D); } } llvm::Type* InitType = Init->getType(); llvm::Constant *Entry = GetAddrOfGlobalVar(D, InitType); // Strip off a bitcast if we got one back. if (llvm::ConstantExpr *CE = dyn_cast(Entry)) { assert(CE->getOpcode() == llvm::Instruction::BitCast || // all zero index gep. CE->getOpcode() == llvm::Instruction::GetElementPtr); Entry = CE->getOperand(0); } // Entry is now either a Function or GlobalVariable. llvm::GlobalVariable *GV = dyn_cast(Entry); // We have a definition after a declaration with the wrong type. // We must make a new GlobalVariable* and update everything that used OldGV // (a declaration or tentative definition) with the new GlobalVariable* // (which will be a definition). // // This happens if there is a prototype for a global (e.g. // "extern int x[];") and then a definition of a different type (e.g. // "int x[10];"). This also happens when an initializer has a different type // from the type of the global (this happens with unions). if (GV == 0 || GV->getType()->getElementType() != InitType || GV->getType()->getAddressSpace() != getContext().getTargetAddressSpace(ASTTy)) { // Move the old entry aside so that we'll create a new one. Entry->setName(StringRef()); // Make a new global with the correct type, this is now guaranteed to work. GV = cast(GetAddrOfGlobalVar(D, InitType)); // Replace all uses of the old global with the new global llvm::Constant *NewPtrForOldDecl = llvm::ConstantExpr::getBitCast(GV, Entry->getType()); Entry->replaceAllUsesWith(NewPtrForOldDecl); // Erase the old global, since it is no longer used. cast(Entry)->eraseFromParent(); } if (D->hasAttr()) AddGlobalAnnotations(D, GV); GV->setInitializer(Init); // If it is safe to mark the global 'constant', do so now. GV->setConstant(false); if (!NonConstInit && DeclIsConstantGlobal(Context, D, true)) GV->setConstant(true); GV->setAlignment(getContext().getDeclAlign(D).getQuantity()); // Set the llvm linkage type as appropriate. llvm::GlobalValue::LinkageTypes Linkage = GetLLVMLinkageVarDefinition(D, GV); GV->setLinkage(Linkage); if (Linkage == llvm::GlobalVariable::CommonLinkage) // common vars aren't constant even if declared const. GV->setConstant(false); SetCommonAttributes(D, GV); // Emit the initializer function if necessary. if (NonConstInit) EmitCXXGlobalVarDeclInitFunc(D, GV); // Emit global variable debug information. if (CGDebugInfo *DI = getModuleDebugInfo()) DI->EmitGlobalVariable(GV, D); } llvm::GlobalValue::LinkageTypes CodeGenModule::GetLLVMLinkageVarDefinition(const VarDecl *D, llvm::GlobalVariable *GV) { GVALinkage Linkage = getContext().GetGVALinkageForVariable(D); if (Linkage == GVA_Internal) return llvm::Function::InternalLinkage; else if (D->hasAttr()) return llvm::Function::DLLImportLinkage; else if (D->hasAttr()) return llvm::Function::DLLExportLinkage; else if (D->hasAttr()) { if (GV->isConstant()) return llvm::GlobalVariable::WeakODRLinkage; else return llvm::GlobalVariable::WeakAnyLinkage; } else if (Linkage == GVA_TemplateInstantiation || Linkage == GVA_ExplicitTemplateInstantiation) return llvm::GlobalVariable::WeakODRLinkage; else if (!getLangOptions().CPlusPlus && ((!CodeGenOpts.NoCommon && !D->getAttr()) || D->getAttr()) && !D->hasExternalStorage() && !D->getInit() && !D->getAttr() && !D->isThreadSpecified() && !D->getAttr()) { // Thread local vars aren't considered common linkage. return llvm::GlobalVariable::CommonLinkage; } return llvm::GlobalVariable::ExternalLinkage; } /// ReplaceUsesOfNonProtoTypeWithRealFunction - This function is called when we /// implement a function with no prototype, e.g. "int foo() {}". If there are /// existing call uses of the old function in the module, this adjusts them to /// call the new function directly. /// /// This is not just a cleanup: the always_inline pass requires direct calls to /// functions to be able to inline them. If there is a bitcast in the way, it /// won't inline them. Instcombine normally deletes these calls, but it isn't /// run at -O0. static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, llvm::Function *NewFn) { // If we're redefining a global as a function, don't transform it. llvm::Function *OldFn = dyn_cast(Old); if (OldFn == 0) return; llvm::Type *NewRetTy = NewFn->getReturnType(); SmallVector ArgList; for (llvm::Value::use_iterator UI = OldFn->use_begin(), E = OldFn->use_end(); UI != E; ) { // TODO: Do invokes ever occur in C code? If so, we should handle them too. llvm::Value::use_iterator I = UI++; // Increment before the CI is erased. llvm::CallInst *CI = dyn_cast(*I); if (!CI) continue; // FIXME: when we allow Invoke, just do CallSite CS(*I) llvm::CallSite CS(CI); if (!CI || !CS.isCallee(I)) continue; // If the return types don't match exactly, and if the call isn't dead, then // we can't transform this call. if (CI->getType() != NewRetTy && !CI->use_empty()) continue; // Get the attribute list. llvm::SmallVector AttrVec; llvm::AttrListPtr AttrList = CI->getAttributes(); // Get any return attributes. llvm::Attributes RAttrs = AttrList.getRetAttributes(); // Add the return attributes. if (RAttrs) AttrVec.push_back(llvm::AttributeWithIndex::get(0, RAttrs)); // If the function was passed too few arguments, don't transform. If extra // arguments were passed, we silently drop them. If any of the types // mismatch, we don't transform. unsigned ArgNo = 0; bool DontTransform = false; for (llvm::Function::arg_iterator AI = NewFn->arg_begin(), E = NewFn->arg_end(); AI != E; ++AI, ++ArgNo) { if (CS.arg_size() == ArgNo || CS.getArgument(ArgNo)->getType() != AI->getType()) { DontTransform = true; break; } // Add any parameter attributes. if (llvm::Attributes PAttrs = AttrList.getParamAttributes(ArgNo + 1)) AttrVec.push_back(llvm::AttributeWithIndex::get(ArgNo + 1, PAttrs)); } if (DontTransform) continue; if (llvm::Attributes FnAttrs = AttrList.getFnAttributes()) AttrVec.push_back(llvm::AttributeWithIndex::get(~0, FnAttrs)); // Okay, we can transform this. Create the new call instruction and copy // over the required information. ArgList.append(CS.arg_begin(), CS.arg_begin() + ArgNo); llvm::CallInst *NewCall = llvm::CallInst::Create(NewFn, ArgList, "", CI); ArgList.clear(); if (!NewCall->getType()->isVoidTy()) NewCall->takeName(CI); NewCall->setAttributes(llvm::AttrListPtr::get(AttrVec.begin(), AttrVec.end())); NewCall->setCallingConv(CI->getCallingConv()); // Finally, remove the old call, replacing any uses with the new one. if (!CI->use_empty()) CI->replaceAllUsesWith(NewCall); // Copy debug location attached to CI. if (!CI->getDebugLoc().isUnknown()) NewCall->setDebugLoc(CI->getDebugLoc()); CI->eraseFromParent(); } } void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) { const FunctionDecl *D = cast(GD.getDecl()); // Compute the function info and LLVM type. const CGFunctionInfo &FI = getTypes().getFunctionInfo(GD); bool variadic = false; if (const FunctionProtoType *fpt = D->getType()->getAs()) variadic = fpt->isVariadic(); llvm::FunctionType *Ty = getTypes().GetFunctionType(FI, variadic); // Get or create the prototype for the function. llvm::Constant *Entry = GetAddrOfFunction(GD, Ty); // Strip off a bitcast if we got one back. if (llvm::ConstantExpr *CE = dyn_cast(Entry)) { assert(CE->getOpcode() == llvm::Instruction::BitCast); Entry = CE->getOperand(0); } if (cast(Entry)->getType()->getElementType() != Ty) { llvm::GlobalValue *OldFn = cast(Entry); // If the types mismatch then we have to rewrite the definition. assert(OldFn->isDeclaration() && "Shouldn't replace non-declaration"); // F is the Function* for the one with the wrong type, we must make a new // Function* and update everything that used F (a declaration) with the new // Function* (which will be a definition). // // This happens if there is a prototype for a function // (e.g. "int f()") and then a definition of a different type // (e.g. "int f(int x)"). Move the old function aside so that it // doesn't interfere with GetAddrOfFunction. OldFn->setName(StringRef()); llvm::Function *NewFn = cast(GetAddrOfFunction(GD, Ty)); // If this is an implementation of a function without a prototype, try to // replace any existing uses of the function (which may be calls) with uses // of the new function if (D->getType()->isFunctionNoProtoType()) { ReplaceUsesOfNonProtoTypeWithRealFunction(OldFn, NewFn); OldFn->removeDeadConstantUsers(); } // Replace uses of F with the Function we will endow with a body. if (!Entry->use_empty()) { llvm::Constant *NewPtrForOldDecl = llvm::ConstantExpr::getBitCast(NewFn, Entry->getType()); Entry->replaceAllUsesWith(NewPtrForOldDecl); } // Ok, delete the old function now, which is dead. OldFn->eraseFromParent(); Entry = NewFn; } // We need to set linkage and visibility on the function before // generating code for it because various parts of IR generation // want to propagate this information down (e.g. to local static // declarations). llvm::Function *Fn = cast(Entry); setFunctionLinkage(D, Fn); // FIXME: this is redundant with part of SetFunctionDefinitionAttributes setGlobalVisibility(Fn, D); CodeGenFunction(*this).GenerateCode(D, Fn, FI); SetFunctionDefinitionAttributes(D, Fn); SetLLVMFunctionAttributesForDefinition(D, Fn); if (const ConstructorAttr *CA = D->getAttr()) AddGlobalCtor(Fn, CA->getPriority()); if (const DestructorAttr *DA = D->getAttr()) AddGlobalDtor(Fn, DA->getPriority()); if (D->hasAttr()) AddGlobalAnnotations(D, Fn); } void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) { const ValueDecl *D = cast(GD.getDecl()); const AliasAttr *AA = D->getAttr(); assert(AA && "Not an alias?"); StringRef MangledName = getMangledName(GD); // If there is a definition in the module, then it wins over the alias. // This is dubious, but allow it to be safe. Just ignore the alias. llvm::GlobalValue *Entry = GetGlobalValue(MangledName); if (Entry && !Entry->isDeclaration()) return; llvm::Type *DeclTy = getTypes().ConvertTypeForMem(D->getType()); // Create a reference to the named value. This ensures that it is emitted // if a deferred decl. llvm::Constant *Aliasee; if (isa(DeclTy)) Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy, GlobalDecl(), /*ForVTable=*/false); else Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(), llvm::PointerType::getUnqual(DeclTy), 0); // Create the new alias itself, but don't set a name yet. llvm::GlobalValue *GA = new llvm::GlobalAlias(Aliasee->getType(), llvm::Function::ExternalLinkage, "", Aliasee, &getModule()); if (Entry) { assert(Entry->isDeclaration()); // If there is a declaration in the module, then we had an extern followed // by the alias, as in: // extern int test6(); // ... // int test6() __attribute__((alias("test7"))); // // Remove it and replace uses of it with the alias. GA->takeName(Entry); Entry->replaceAllUsesWith(llvm::ConstantExpr::getBitCast(GA, Entry->getType())); Entry->eraseFromParent(); } else { GA->setName(MangledName); } // Set attributes which are particular to an alias; this is a // specialization of the attributes which may be set on a global // variable/function. if (D->hasAttr()) { if (const FunctionDecl *FD = dyn_cast(D)) { // The dllexport attribute is ignored for undefined symbols. if (FD->hasBody()) GA->setLinkage(llvm::Function::DLLExportLinkage); } else { GA->setLinkage(llvm::Function::DLLExportLinkage); } } else if (D->hasAttr() || D->hasAttr() || D->isWeakImported()) { GA->setLinkage(llvm::Function::WeakAnyLinkage); } SetCommonAttributes(D, GA); } llvm::Function *CodeGenModule::getIntrinsic(unsigned IID, ArrayRef Tys) { return llvm::Intrinsic::getDeclaration(&getModule(), (llvm::Intrinsic::ID)IID, Tys); } static llvm::StringMapEntry & GetConstantCFStringEntry(llvm::StringMap &Map, const StringLiteral *Literal, bool TargetIsLSB, bool &IsUTF16, unsigned &StringLength) { StringRef String = Literal->getString(); unsigned NumBytes = String.size(); // Check for simple case. if (!Literal->containsNonAsciiOrNull()) { StringLength = NumBytes; return Map.GetOrCreateValue(String); } // Otherwise, convert the UTF8 literals into a byte string. SmallVector ToBuf(NumBytes); const UTF8 *FromPtr = (UTF8 *)String.data(); UTF16 *ToPtr = &ToBuf[0]; (void)ConvertUTF8toUTF16(&FromPtr, FromPtr + NumBytes, &ToPtr, ToPtr + NumBytes, strictConversion); // ConvertUTF8toUTF16 returns the length in ToPtr. StringLength = ToPtr - &ToBuf[0]; // Render the UTF-16 string into a byte array and convert to the target byte // order. // // FIXME: This isn't something we should need to do here. llvm::SmallString<128> AsBytes; AsBytes.reserve(StringLength * 2); for (unsigned i = 0; i != StringLength; ++i) { unsigned short Val = ToBuf[i]; if (TargetIsLSB) { AsBytes.push_back(Val & 0xFF); AsBytes.push_back(Val >> 8); } else { AsBytes.push_back(Val >> 8); AsBytes.push_back(Val & 0xFF); } } // Append one extra null character, the second is automatically added by our // caller. AsBytes.push_back(0); IsUTF16 = true; return Map.GetOrCreateValue(StringRef(AsBytes.data(), AsBytes.size())); } static llvm::StringMapEntry & GetConstantStringEntry(llvm::StringMap &Map, const StringLiteral *Literal, unsigned &StringLength) { StringRef String = Literal->getString(); StringLength = String.size(); return Map.GetOrCreateValue(String); } llvm::Constant * CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { unsigned StringLength = 0; bool isUTF16 = false; llvm::StringMapEntry &Entry = GetConstantCFStringEntry(CFConstantStringMap, Literal, getTargetData().isLittleEndian(), isUTF16, StringLength); if (llvm::Constant *C = Entry.getValue()) return C; llvm::Constant *Zero = llvm::Constant::getNullValue(llvm::Type::getInt32Ty(VMContext)); llvm::Constant *Zeros[] = { Zero, Zero }; // If we don't already have it, get __CFConstantStringClassReference. if (!CFConstantStringClassRef) { llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy); Ty = llvm::ArrayType::get(Ty, 0); llvm::Constant *GV = CreateRuntimeVariable(Ty, "__CFConstantStringClassReference"); // Decay array -> ptr CFConstantStringClassRef = llvm::ConstantExpr::getGetElementPtr(GV, Zeros); } QualType CFTy = getContext().getCFConstantStringType(); llvm::StructType *STy = cast(getTypes().ConvertType(CFTy)); std::vector Fields(4); // Class pointer. Fields[0] = CFConstantStringClassRef; // Flags. llvm::Type *Ty = getTypes().ConvertType(getContext().UnsignedIntTy); Fields[1] = isUTF16 ? llvm::ConstantInt::get(Ty, 0x07d0) : llvm::ConstantInt::get(Ty, 0x07C8); // String pointer. llvm::Constant *C = llvm::ConstantArray::get(VMContext, Entry.getKey().str()); llvm::GlobalValue::LinkageTypes Linkage; bool isConstant; if (isUTF16) { // FIXME: why do utf strings get "_" labels instead of "L" labels? Linkage = llvm::GlobalValue::InternalLinkage; // Note: -fwritable-strings doesn't make unicode CFStrings writable, but // does make plain ascii ones writable. isConstant = true; } else { // FIXME: With OS X ld 123.2 (xcode 4) and LTO we would get a linker error // when using private linkage. It is not clear if this is a bug in ld // or a reasonable new restriction. Linkage = llvm::GlobalValue::LinkerPrivateLinkage; isConstant = !Features.WritableStrings; } llvm::GlobalVariable *GV = new llvm::GlobalVariable(getModule(), C->getType(), isConstant, Linkage, C, ".str"); GV->setUnnamedAddr(true); if (isUTF16) { CharUnits Align = getContext().getTypeAlignInChars(getContext().ShortTy); GV->setAlignment(Align.getQuantity()); } else { CharUnits Align = getContext().getTypeAlignInChars(getContext().CharTy); GV->setAlignment(Align.getQuantity()); } Fields[2] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros); // String length. Ty = getTypes().ConvertType(getContext().LongTy); Fields[3] = llvm::ConstantInt::get(Ty, StringLength); // The struct. C = llvm::ConstantStruct::get(STy, Fields); GV = new llvm::GlobalVariable(getModule(), C->getType(), true, llvm::GlobalVariable::PrivateLinkage, C, "_unnamed_cfstring_"); if (const char *Sect = getContext().getTargetInfo().getCFStringSection()) GV->setSection(Sect); Entry.setValue(GV); return GV; } static RecordDecl * CreateRecordDecl(const ASTContext &Ctx, RecordDecl::TagKind TK, DeclContext *DC, IdentifierInfo *Id) { SourceLocation Loc; if (Ctx.getLangOptions().CPlusPlus) return CXXRecordDecl::Create(Ctx, TK, DC, Loc, Loc, Id); else return RecordDecl::Create(Ctx, TK, DC, Loc, Loc, Id); } llvm::Constant * CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) { unsigned StringLength = 0; llvm::StringMapEntry &Entry = GetConstantStringEntry(CFConstantStringMap, Literal, StringLength); if (llvm::Constant *C = Entry.getValue()) return C; llvm::Constant *Zero = llvm::Constant::getNullValue(llvm::Type::getInt32Ty(VMContext)); llvm::Constant *Zeros[] = { Zero, Zero }; // If we don't already have it, get _NSConstantStringClassReference. if (!ConstantStringClassRef) { std::string StringClass(getLangOptions().ObjCConstantStringClass); llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy); llvm::Constant *GV; if (Features.ObjCNonFragileABI) { std::string str = StringClass.empty() ? "OBJC_CLASS_$_NSConstantString" : "OBJC_CLASS_$_" + StringClass; GV = getObjCRuntime().GetClassGlobal(str); // Make sure the result is of the correct type. llvm::Type *PTy = llvm::PointerType::getUnqual(Ty); ConstantStringClassRef = llvm::ConstantExpr::getBitCast(GV, PTy); } else { std::string str = StringClass.empty() ? "_NSConstantStringClassReference" : "_" + StringClass + "ClassReference"; llvm::Type *PTy = llvm::ArrayType::get(Ty, 0); GV = CreateRuntimeVariable(PTy, str); // Decay array -> ptr ConstantStringClassRef = llvm::ConstantExpr::getGetElementPtr(GV, Zeros); } } if (!NSConstantStringType) { // Construct the type for a constant NSString. RecordDecl *D = CreateRecordDecl(Context, TTK_Struct, Context.getTranslationUnitDecl(), &Context.Idents.get("__builtin_NSString")); D->startDefinition(); QualType FieldTypes[3]; // const int *isa; FieldTypes[0] = Context.getPointerType(Context.IntTy.withConst()); // const char *str; FieldTypes[1] = Context.getPointerType(Context.CharTy.withConst()); // unsigned int length; FieldTypes[2] = Context.UnsignedIntTy; // Create fields for (unsigned i = 0; i < 3; ++i) { FieldDecl *Field = FieldDecl::Create(Context, D, SourceLocation(), SourceLocation(), 0, FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false, /*HasInit=*/false); Field->setAccess(AS_public); D->addDecl(Field); } D->completeDefinition(); QualType NSTy = Context.getTagDeclType(D); NSConstantStringType = cast(getTypes().ConvertType(NSTy)); } std::vector Fields(3); // Class pointer. Fields[0] = ConstantStringClassRef; // String pointer. llvm::Constant *C = llvm::ConstantArray::get(VMContext, Entry.getKey().str()); llvm::GlobalValue::LinkageTypes Linkage; bool isConstant; Linkage = llvm::GlobalValue::PrivateLinkage; isConstant = !Features.WritableStrings; llvm::GlobalVariable *GV = new llvm::GlobalVariable(getModule(), C->getType(), isConstant, Linkage, C, ".str"); GV->setUnnamedAddr(true); CharUnits Align = getContext().getTypeAlignInChars(getContext().CharTy); GV->setAlignment(Align.getQuantity()); Fields[1] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros); // String length. llvm::Type *Ty = getTypes().ConvertType(getContext().UnsignedIntTy); Fields[2] = llvm::ConstantInt::get(Ty, StringLength); // The struct. C = llvm::ConstantStruct::get(NSConstantStringType, Fields); GV = new llvm::GlobalVariable(getModule(), C->getType(), true, llvm::GlobalVariable::PrivateLinkage, C, "_unnamed_nsstring_"); // FIXME. Fix section. if (const char *Sect = Features.ObjCNonFragileABI ? getContext().getTargetInfo().getNSStringNonFragileABISection() : getContext().getTargetInfo().getNSStringSection()) GV->setSection(Sect); Entry.setValue(GV); return GV; } QualType CodeGenModule::getObjCFastEnumerationStateType() { if (ObjCFastEnumerationStateType.isNull()) { RecordDecl *D = CreateRecordDecl(Context, TTK_Struct, Context.getTranslationUnitDecl(), &Context.Idents.get("__objcFastEnumerationState")); D->startDefinition(); QualType FieldTypes[] = { Context.UnsignedLongTy, Context.getPointerType(Context.getObjCIdType()), Context.getPointerType(Context.UnsignedLongTy), Context.getConstantArrayType(Context.UnsignedLongTy, llvm::APInt(32, 5), ArrayType::Normal, 0) }; for (size_t i = 0; i < 4; ++i) { FieldDecl *Field = FieldDecl::Create(Context, D, SourceLocation(), SourceLocation(), 0, FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false, /*HasInit=*/false); Field->setAccess(AS_public); D->addDecl(Field); } D->completeDefinition(); ObjCFastEnumerationStateType = Context.getTagDeclType(D); } return ObjCFastEnumerationStateType; } /// GetStringForStringLiteral - Return the appropriate bytes for a /// string literal, properly padded to match the literal type. std::string CodeGenModule::GetStringForStringLiteral(const StringLiteral *E) { const ASTContext &Context = getContext(); const ConstantArrayType *CAT = Context.getAsConstantArrayType(E->getType()); assert(CAT && "String isn't pointer or array!"); // Resize the string to the right size. uint64_t RealLen = CAT->getSize().getZExtValue(); switch (E->getKind()) { case StringLiteral::Ascii: case StringLiteral::UTF8: break; case StringLiteral::Wide: RealLen *= Context.getTargetInfo().getWCharWidth() / Context.getCharWidth(); break; case StringLiteral::UTF16: RealLen *= Context.getTargetInfo().getChar16Width() / Context.getCharWidth(); break; case StringLiteral::UTF32: RealLen *= Context.getTargetInfo().getChar32Width() / Context.getCharWidth(); break; } std::string Str = E->getString().str(); Str.resize(RealLen, '\0'); return Str; } /// GetAddrOfConstantStringFromLiteral - Return a pointer to a /// constant array for the given string literal. llvm::Constant * CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S) { // FIXME: This can be more efficient. // FIXME: We shouldn't need to bitcast the constant in the wide string case. CharUnits Align = getContext().getTypeAlignInChars(S->getType()); llvm::Constant *C = GetAddrOfConstantString(GetStringForStringLiteral(S), /* GlobalName */ 0, Align.getQuantity()); if (S->isWide() || S->isUTF16() || S->isUTF32()) { llvm::Type *DestTy = llvm::PointerType::getUnqual(getTypes().ConvertType(S->getType())); C = llvm::ConstantExpr::getBitCast(C, DestTy); } return C; } /// GetAddrOfConstantStringFromObjCEncode - Return a pointer to a constant /// array for the given ObjCEncodeExpr node. llvm::Constant * CodeGenModule::GetAddrOfConstantStringFromObjCEncode(const ObjCEncodeExpr *E) { std::string Str; getContext().getObjCEncodingForType(E->getEncodedType(), Str); return GetAddrOfConstantCString(Str); } /// GenerateWritableString -- Creates storage for a string literal. static llvm::GlobalVariable *GenerateStringLiteral(StringRef str, bool constant, CodeGenModule &CGM, const char *GlobalName, unsigned Alignment) { // Create Constant for this string literal. Don't add a '\0'. llvm::Constant *C = llvm::ConstantArray::get(CGM.getLLVMContext(), str, false); // Create a global variable for this string llvm::GlobalVariable *GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), constant, llvm::GlobalValue::PrivateLinkage, C, GlobalName); GV->setAlignment(Alignment); GV->setUnnamedAddr(true); return GV; } /// GetAddrOfConstantString - Returns a pointer to a character array /// containing the literal. This contents are exactly that of the /// given string, i.e. it will not be null terminated automatically; /// see GetAddrOfConstantCString. Note that whether the result is /// actually a pointer to an LLVM constant depends on /// Feature.WriteableStrings. /// /// The result has pointer to array type. llvm::Constant *CodeGenModule::GetAddrOfConstantString(StringRef Str, const char *GlobalName, unsigned Alignment) { bool IsConstant = !Features.WritableStrings; // Get the default prefix if a name wasn't specified. if (!GlobalName) GlobalName = ".str"; // Don't share any string literals if strings aren't constant. if (!IsConstant) return GenerateStringLiteral(Str, false, *this, GlobalName, Alignment); llvm::StringMapEntry &Entry = ConstantStringMap.GetOrCreateValue(Str); if (llvm::GlobalVariable *GV = Entry.getValue()) { if (Alignment > GV->getAlignment()) { GV->setAlignment(Alignment); } return GV; } // Create a global variable for this. llvm::GlobalVariable *GV = GenerateStringLiteral(Str, true, *this, GlobalName, Alignment); Entry.setValue(GV); return GV; } /// GetAddrOfConstantCString - Returns a pointer to a character /// array containing the literal and a terminating '\0' /// character. The result has pointer to array type. llvm::Constant *CodeGenModule::GetAddrOfConstantCString(const std::string &Str, const char *GlobalName, unsigned Alignment) { StringRef StrWithNull(Str.c_str(), Str.size() + 1); return GetAddrOfConstantString(StrWithNull, GlobalName, Alignment); } /// EmitObjCPropertyImplementations - Emit information for synthesized /// properties for an implementation. void CodeGenModule::EmitObjCPropertyImplementations(const ObjCImplementationDecl *D) { for (ObjCImplementationDecl::propimpl_iterator i = D->propimpl_begin(), e = D->propimpl_end(); i != e; ++i) { ObjCPropertyImplDecl *PID = *i; // Dynamic is just for type-checking. if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) { ObjCPropertyDecl *PD = PID->getPropertyDecl(); // Determine which methods need to be implemented, some may have // been overridden. Note that ::isSynthesized is not the method // we want, that just indicates if the decl came from a // property. What we want to know is if the method is defined in // this implementation. if (!D->getInstanceMethod(PD->getGetterName())) CodeGenFunction(*this).GenerateObjCGetter( const_cast(D), PID); if (!PD->isReadOnly() && !D->getInstanceMethod(PD->getSetterName())) CodeGenFunction(*this).GenerateObjCSetter( const_cast(D), PID); } } } static bool needsDestructMethod(ObjCImplementationDecl *impl) { const ObjCInterfaceDecl *iface = impl->getClassInterface(); for (const ObjCIvarDecl *ivar = iface->all_declared_ivar_begin(); ivar; ivar = ivar->getNextIvar()) if (ivar->getType().isDestructedType()) return true; return false; } /// EmitObjCIvarInitializations - Emit information for ivar initialization /// for an implementation. void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) { // We might need a .cxx_destruct even if we don't have any ivar initializers. if (needsDestructMethod(D)) { IdentifierInfo *II = &getContext().Idents.get(".cxx_destruct"); Selector cxxSelector = getContext().Selectors.getSelector(0, &II); ObjCMethodDecl *DTORMethod = ObjCMethodDecl::Create(getContext(), D->getLocation(), D->getLocation(), cxxSelector, getContext().VoidTy, 0, D, /*isInstance=*/true, /*isVariadic=*/false, /*isSynthesized=*/true, /*isImplicitlyDeclared=*/true, /*isDefined=*/false, ObjCMethodDecl::Required); D->addInstanceMethod(DTORMethod); CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false); D->setHasCXXStructors(true); } // If the implementation doesn't have any ivar initializers, we don't need // a .cxx_construct. if (D->getNumIvarInitializers() == 0) return; IdentifierInfo *II = &getContext().Idents.get(".cxx_construct"); Selector cxxSelector = getContext().Selectors.getSelector(0, &II); // The constructor returns 'self'. ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create(getContext(), D->getLocation(), D->getLocation(), cxxSelector, getContext().getObjCIdType(), 0, D, /*isInstance=*/true, /*isVariadic=*/false, /*isSynthesized=*/true, /*isImplicitlyDeclared=*/true, /*isDefined=*/false, ObjCMethodDecl::Required); D->addInstanceMethod(CTORMethod); CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true); D->setHasCXXStructors(true); } /// EmitNamespace - Emit all declarations in a namespace. void CodeGenModule::EmitNamespace(const NamespaceDecl *ND) { for (RecordDecl::decl_iterator I = ND->decls_begin(), E = ND->decls_end(); I != E; ++I) EmitTopLevelDecl(*I); } // EmitLinkageSpec - Emit all declarations in a linkage spec. void CodeGenModule::EmitLinkageSpec(const LinkageSpecDecl *LSD) { if (LSD->getLanguage() != LinkageSpecDecl::lang_c && LSD->getLanguage() != LinkageSpecDecl::lang_cxx) { ErrorUnsupported(LSD, "linkage spec"); return; } for (RecordDecl::decl_iterator I = LSD->decls_begin(), E = LSD->decls_end(); I != E; ++I) EmitTopLevelDecl(*I); } /// EmitTopLevelDecl - Emit code for a single top level declaration. void CodeGenModule::EmitTopLevelDecl(Decl *D) { // If an error has occurred, stop code generation, but continue // parsing and semantic analysis (to ensure all warnings and errors // are emitted). if (Diags.hasErrorOccurred()) return; // Ignore dependent declarations. if (D->getDeclContext() && D->getDeclContext()->isDependentContext()) return; switch (D->getKind()) { case Decl::CXXConversion: case Decl::CXXMethod: case Decl::Function: // Skip function templates if (cast(D)->getDescribedFunctionTemplate() || cast(D)->isLateTemplateParsed()) return; EmitGlobal(cast(D)); break; case Decl::Var: EmitGlobal(cast(D)); break; // Indirect fields from global anonymous structs and unions can be // ignored; only the actual variable requires IR gen support. case Decl::IndirectField: break; // C++ Decls case Decl::Namespace: EmitNamespace(cast(D)); break; // No code generation needed. case Decl::UsingShadow: case Decl::Using: case Decl::UsingDirective: case Decl::ClassTemplate: case Decl::FunctionTemplate: case Decl::TypeAliasTemplate: case Decl::NamespaceAlias: case Decl::Block: break; case Decl::CXXConstructor: // Skip function templates if (cast(D)->getDescribedFunctionTemplate() || cast(D)->isLateTemplateParsed()) return; EmitCXXConstructors(cast(D)); break; case Decl::CXXDestructor: if (cast(D)->isLateTemplateParsed()) return; EmitCXXDestructors(cast(D)); break; case Decl::StaticAssert: // Nothing to do. break; // Objective-C Decls // Forward declarations, no (immediate) code generation. case Decl::ObjCClass: case Decl::ObjCForwardProtocol: case Decl::ObjCInterface: break; case Decl::ObjCCategory: { ObjCCategoryDecl *CD = cast(D); if (CD->IsClassExtension() && CD->hasSynthBitfield()) Context.ResetObjCLayout(CD->getClassInterface()); break; } case Decl::ObjCProtocol: ObjCRuntime->GenerateProtocol(cast(D)); break; case Decl::ObjCCategoryImpl: // Categories have properties but don't support synthesize so we // can ignore them here. ObjCRuntime->GenerateCategory(cast(D)); break; case Decl::ObjCImplementation: { ObjCImplementationDecl *OMD = cast(D); if (Features.ObjCNonFragileABI2 && OMD->hasSynthBitfield()) Context.ResetObjCLayout(OMD->getClassInterface()); EmitObjCPropertyImplementations(OMD); EmitObjCIvarInitializations(OMD); ObjCRuntime->GenerateClass(OMD); break; } case Decl::ObjCMethod: { ObjCMethodDecl *OMD = cast(D); // If this is not a prototype, emit the body. if (OMD->getBody()) CodeGenFunction(*this).GenerateObjCMethod(OMD); break; } case Decl::ObjCCompatibleAlias: // compatibility-alias is a directive and has no code gen. break; case Decl::LinkageSpec: EmitLinkageSpec(cast(D)); break; case Decl::FileScopeAsm: { FileScopeAsmDecl *AD = cast(D); StringRef AsmString = AD->getAsmString()->getString(); const std::string &S = getModule().getModuleInlineAsm(); if (S.empty()) getModule().setModuleInlineAsm(AsmString); else if (*--S.end() == '\n') getModule().setModuleInlineAsm(S + AsmString.str()); else getModule().setModuleInlineAsm(S + '\n' + AsmString.str()); break; } default: // Make sure we handled everything we should, every other kind is a // non-top-level decl. FIXME: Would be nice to have an isTopLevelDeclKind // function. Need to recode Decl::Kind to do that easily. assert(isa(D) && "Unsupported decl kind"); } } /// Turns the given pointer into a constant. static llvm::Constant *GetPointerConstant(llvm::LLVMContext &Context, const void *Ptr) { uintptr_t PtrInt = reinterpret_cast(Ptr); llvm::Type *i64 = llvm::Type::getInt64Ty(Context); return llvm::ConstantInt::get(i64, PtrInt); } static void EmitGlobalDeclMetadata(CodeGenModule &CGM, llvm::NamedMDNode *&GlobalMetadata, GlobalDecl D, llvm::GlobalValue *Addr) { if (!GlobalMetadata) GlobalMetadata = CGM.getModule().getOrInsertNamedMetadata("clang.global.decl.ptrs"); // TODO: should we report variant information for ctors/dtors? llvm::Value *Ops[] = { Addr, GetPointerConstant(CGM.getLLVMContext(), D.getDecl()) }; GlobalMetadata->addOperand(llvm::MDNode::get(CGM.getLLVMContext(), Ops)); } /// Emits metadata nodes associating all the global values in the /// current module with the Decls they came from. This is useful for /// projects using IR gen as a subroutine. /// /// Since there's currently no way to associate an MDNode directly /// with an llvm::GlobalValue, we create a global named metadata /// with the name 'clang.global.decl.ptrs'. void CodeGenModule::EmitDeclMetadata() { llvm::NamedMDNode *GlobalMetadata = 0; // StaticLocalDeclMap for (llvm::DenseMap::iterator I = MangledDeclNames.begin(), E = MangledDeclNames.end(); I != E; ++I) { llvm::GlobalValue *Addr = getModule().getNamedValue(I->second); EmitGlobalDeclMetadata(*this, GlobalMetadata, I->first, Addr); } } /// Emits metadata nodes for all the local variables in the current /// function. void CodeGenFunction::EmitDeclMetadata() { if (LocalDeclMap.empty()) return; llvm::LLVMContext &Context = getLLVMContext(); // Find the unique metadata ID for this name. unsigned DeclPtrKind = Context.getMDKindID("clang.decl.ptr"); llvm::NamedMDNode *GlobalMetadata = 0; for (llvm::DenseMap::iterator I = LocalDeclMap.begin(), E = LocalDeclMap.end(); I != E; ++I) { const Decl *D = I->first; llvm::Value *Addr = I->second; if (llvm::AllocaInst *Alloca = dyn_cast(Addr)) { llvm::Value *DAddr = GetPointerConstant(getLLVMContext(), D); Alloca->setMetadata(DeclPtrKind, llvm::MDNode::get(Context, DAddr)); } else if (llvm::GlobalValue *GV = dyn_cast(Addr)) { GlobalDecl GD = GlobalDecl(cast(D)); EmitGlobalDeclMetadata(CGM, GlobalMetadata, GD, GV); } } } void CodeGenModule::EmitCoverageFile() { if (!getCodeGenOpts().CoverageFile.empty()) { if (llvm::NamedMDNode *CUNode = TheModule.getNamedMetadata("llvm.dbg.cu")) { llvm::NamedMDNode *GCov = TheModule.getOrInsertNamedMetadata("llvm.gcov"); llvm::LLVMContext &Ctx = TheModule.getContext(); llvm::MDString *CoverageFile = llvm::MDString::get(Ctx, getCodeGenOpts().CoverageFile); for (int i = 0, e = CUNode->getNumOperands(); i != e; ++i) { llvm::MDNode *CU = CUNode->getOperand(i); llvm::Value *node[] = { CoverageFile, CU }; llvm::MDNode *N = llvm::MDNode::get(Ctx, node); GCov->addOperand(N); } } } } Index: head/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h =================================================================== --- head/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h (revision 228378) +++ head/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h (revision 228379) @@ -1,911 +1,913 @@ //===--- CodeGenModule.h - Per-Module state for LLVM CodeGen ----*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This is the internal per-translation-unit state used for llvm translation. // //===----------------------------------------------------------------------===// #ifndef CLANG_CODEGEN_CODEGENMODULE_H #define CLANG_CODEGEN_CODEGENMODULE_H #include "clang/Basic/ABI.h" #include "clang/Basic/LangOptions.h" #include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/GlobalDecl.h" #include "clang/AST/Mangle.h" #include "CGVTables.h" #include "CodeGenTypes.h" #include "llvm/Module.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSet.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/ValueHandle.h" namespace llvm { class Module; class Constant; class ConstantInt; class Function; class GlobalValue; class TargetData; class FunctionType; class LLVMContext; } namespace clang { class TargetCodeGenInfo; class ASTContext; class FunctionDecl; class IdentifierInfo; class ObjCMethodDecl; class ObjCImplementationDecl; class ObjCCategoryImplDecl; class ObjCProtocolDecl; class ObjCEncodeExpr; class BlockExpr; class CharUnits; class Decl; class Expr; class Stmt; class StringLiteral; class NamedDecl; class ValueDecl; class VarDecl; class LangOptions; class CodeGenOptions; class DiagnosticsEngine; class AnnotateAttr; class CXXDestructorDecl; class MangleBuffer; namespace CodeGen { class CallArgList; class CodeGenFunction; class CodeGenTBAA; class CGCXXABI; class CGDebugInfo; class CGObjCRuntime; class CGOpenCLRuntime; class CGCUDARuntime; class BlockFieldFlags; class FunctionArgList; struct OrderGlobalInits { unsigned int priority; unsigned int lex_order; OrderGlobalInits(unsigned int p, unsigned int l) : priority(p), lex_order(l) {} bool operator==(const OrderGlobalInits &RHS) const { return priority == RHS.priority && lex_order == RHS.lex_order; } bool operator<(const OrderGlobalInits &RHS) const { if (priority < RHS.priority) return true; return priority == RHS.priority && lex_order < RHS.lex_order; } }; struct CodeGenTypeCache { /// void llvm::Type *VoidTy; /// i8, i32, and i64 llvm::IntegerType *Int8Ty, *Int32Ty, *Int64Ty; /// int llvm::IntegerType *IntTy; /// intptr_t, size_t, and ptrdiff_t, which we assume are the same size. union { llvm::IntegerType *IntPtrTy; llvm::IntegerType *SizeTy; llvm::IntegerType *PtrDiffTy; }; /// void* in address space 0 union { llvm::PointerType *VoidPtrTy; llvm::PointerType *Int8PtrTy; }; /// void** in address space 0 union { llvm::PointerType *VoidPtrPtrTy; llvm::PointerType *Int8PtrPtrTy; }; /// The width of a pointer into the generic address space. unsigned char PointerWidthInBits; /// The size and alignment of a pointer into the generic address /// space. union { unsigned char PointerAlignInBytes; unsigned char PointerSizeInBytes; }; }; struct RREntrypoints { RREntrypoints() { memset(this, 0, sizeof(*this)); } /// void objc_autoreleasePoolPop(void*); llvm::Constant *objc_autoreleasePoolPop; /// void *objc_autoreleasePoolPush(void); llvm::Constant *objc_autoreleasePoolPush; }; struct ARCEntrypoints { ARCEntrypoints() { memset(this, 0, sizeof(*this)); } /// id objc_autorelease(id); llvm::Constant *objc_autorelease; /// id objc_autoreleaseReturnValue(id); llvm::Constant *objc_autoreleaseReturnValue; /// void objc_copyWeak(id *dest, id *src); llvm::Constant *objc_copyWeak; /// void objc_destroyWeak(id*); llvm::Constant *objc_destroyWeak; /// id objc_initWeak(id*, id); llvm::Constant *objc_initWeak; /// id objc_loadWeak(id*); llvm::Constant *objc_loadWeak; /// id objc_loadWeakRetained(id*); llvm::Constant *objc_loadWeakRetained; /// void objc_moveWeak(id *dest, id *src); llvm::Constant *objc_moveWeak; /// id objc_retain(id); llvm::Constant *objc_retain; /// id objc_retainAutorelease(id); llvm::Constant *objc_retainAutorelease; /// id objc_retainAutoreleaseReturnValue(id); llvm::Constant *objc_retainAutoreleaseReturnValue; /// id objc_retainAutoreleasedReturnValue(id); llvm::Constant *objc_retainAutoreleasedReturnValue; /// id objc_retainBlock(id); llvm::Constant *objc_retainBlock; /// void objc_release(id); llvm::Constant *objc_release; /// id objc_storeStrong(id*, id); llvm::Constant *objc_storeStrong; /// id objc_storeWeak(id*, id); llvm::Constant *objc_storeWeak; /// A void(void) inline asm to use to mark that the return value of /// a call will be immediately retain. llvm::InlineAsm *retainAutoreleasedReturnValueMarker; }; /// CodeGenModule - This class organizes the cross-function state that is used /// while generating LLVM code. class CodeGenModule : public CodeGenTypeCache { CodeGenModule(const CodeGenModule&); // DO NOT IMPLEMENT void operator=(const CodeGenModule&); // DO NOT IMPLEMENT typedef std::vector > CtorList; ASTContext &Context; const LangOptions &Features; const CodeGenOptions &CodeGenOpts; llvm::Module &TheModule; const llvm::TargetData &TheTargetData; mutable const TargetCodeGenInfo *TheTargetCodeGenInfo; DiagnosticsEngine &Diags; CGCXXABI &ABI; CodeGenTypes Types; CodeGenTBAA *TBAA; /// VTables - Holds information about C++ vtables. CodeGenVTables VTables; friend class CodeGenVTables; CGObjCRuntime* ObjCRuntime; CGOpenCLRuntime* OpenCLRuntime; CGCUDARuntime* CUDARuntime; CGDebugInfo* DebugInfo; ARCEntrypoints *ARCData; RREntrypoints *RRData; // WeakRefReferences - A set of references that have only been seen via // a weakref so far. This is used to remove the weak of the reference if we ever // see a direct reference or a definition. llvm::SmallPtrSet WeakRefReferences; /// DeferredDecls - This contains all the decls which have definitions but /// which are deferred for emission and therefore should only be output if /// they are actually used. If a decl is in this, then it is known to have /// not been referenced yet. llvm::StringMap DeferredDecls; /// DeferredDeclsToEmit - This is a list of deferred decls which we have seen /// that *are* actually referenced. These get code generated when the module /// is done. std::vector DeferredDeclsToEmit; /// LLVMUsed - List of global values which are required to be /// present in the object file; bitcast to i8*. This is used for /// forcing visibility of symbols which may otherwise be optimized /// out. std::vector LLVMUsed; /// GlobalCtors - Store the list of global constructors and their respective /// priorities to be emitted when the translation unit is complete. CtorList GlobalCtors; /// GlobalDtors - Store the list of global destructors and their respective /// priorities to be emitted when the translation unit is complete. CtorList GlobalDtors; /// MangledDeclNames - A map of canonical GlobalDecls to their mangled names. llvm::DenseMap MangledDeclNames; llvm::BumpPtrAllocator MangledNamesAllocator; /// Global annotations. std::vector Annotations; /// Map used to get unique annotation strings. llvm::StringMap AnnotationStrings; llvm::StringMap CFConstantStringMap; llvm::StringMap ConstantStringMap; llvm::DenseMap StaticLocalDeclMap; /// CXXGlobalInits - Global variables with initializers that need to run /// before main. std::vector CXXGlobalInits; /// When a C++ decl with an initializer is deferred, null is /// appended to CXXGlobalInits, and the index of that null is placed /// here so that the initializer will be performed in the correct /// order. llvm::DenseMap DelayedCXXInitPosition; /// - Global variables with initializers whose order of initialization /// is set by init_priority attribute. SmallVector, 8> PrioritizedCXXGlobalInits; /// CXXGlobalDtors - Global destructor functions and arguments that need to /// run on termination. std::vector > CXXGlobalDtors; /// @name Cache for Objective-C runtime types /// @{ /// CFConstantStringClassRef - Cached reference to the class for constant /// strings. This value has type int * but is actually an Obj-C class pointer. llvm::Constant *CFConstantStringClassRef; /// ConstantStringClassRef - Cached reference to the class for constant /// strings. This value has type int * but is actually an Obj-C class pointer. llvm::Constant *ConstantStringClassRef; /// \brief The LLVM type corresponding to NSConstantString. llvm::StructType *NSConstantStringType; /// \brief The type used to describe the state of a fast enumeration in /// Objective-C's for..in loop. QualType ObjCFastEnumerationStateType; /// @} /// Lazily create the Objective-C runtime void createObjCRuntime(); void createOpenCLRuntime(); void createCUDARuntime(); + bool isTriviallyRecursiveViaAsm(const FunctionDecl *F); + bool shouldEmitFunction(const FunctionDecl *F); llvm::LLVMContext &VMContext; /// @name Cache for Blocks Runtime Globals /// @{ llvm::Constant *NSConcreteGlobalBlock; llvm::Constant *NSConcreteStackBlock; llvm::Constant *BlockObjectAssign; llvm::Constant *BlockObjectDispose; llvm::Type *BlockDescriptorType; llvm::Type *GenericBlockLiteralType; struct { int GlobalUniqueCount; } Block; /// @} public: CodeGenModule(ASTContext &C, const CodeGenOptions &CodeGenOpts, llvm::Module &M, const llvm::TargetData &TD, DiagnosticsEngine &Diags); ~CodeGenModule(); /// Release - Finalize LLVM code generation. void Release(); /// getObjCRuntime() - Return a reference to the configured /// Objective-C runtime. CGObjCRuntime &getObjCRuntime() { if (!ObjCRuntime) createObjCRuntime(); return *ObjCRuntime; } /// hasObjCRuntime() - Return true iff an Objective-C runtime has /// been configured. bool hasObjCRuntime() { return !!ObjCRuntime; } /// getOpenCLRuntime() - Return a reference to the configured OpenCL runtime. CGOpenCLRuntime &getOpenCLRuntime() { assert(OpenCLRuntime != 0); return *OpenCLRuntime; } /// getCUDARuntime() - Return a reference to the configured CUDA runtime. CGCUDARuntime &getCUDARuntime() { assert(CUDARuntime != 0); return *CUDARuntime; } /// getCXXABI() - Return a reference to the configured C++ ABI. CGCXXABI &getCXXABI() { return ABI; } ARCEntrypoints &getARCEntrypoints() const { assert(getLangOptions().ObjCAutoRefCount && ARCData != 0); return *ARCData; } RREntrypoints &getRREntrypoints() const { assert(RRData != 0); return *RRData; } llvm::Value *getStaticLocalDeclAddress(const VarDecl *VD) { return StaticLocalDeclMap[VD]; } void setStaticLocalDeclAddress(const VarDecl *D, llvm::GlobalVariable *GV) { StaticLocalDeclMap[D] = GV; } CGDebugInfo *getModuleDebugInfo() { return DebugInfo; } ASTContext &getContext() const { return Context; } const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; } const LangOptions &getLangOptions() const { return Features; } llvm::Module &getModule() const { return TheModule; } CodeGenTypes &getTypes() { return Types; } CodeGenVTables &getVTables() { return VTables; } VTableContext &getVTableContext() { return VTables.getVTableContext(); } DiagnosticsEngine &getDiags() const { return Diags; } const llvm::TargetData &getTargetData() const { return TheTargetData; } const TargetInfo &getTarget() const { return Context.getTargetInfo(); } llvm::LLVMContext &getLLVMContext() { return VMContext; } const TargetCodeGenInfo &getTargetCodeGenInfo(); bool isTargetDarwin() const; bool shouldUseTBAA() const { return TBAA != 0; } llvm::MDNode *getTBAAInfo(QualType QTy); static void DecorateInstruction(llvm::Instruction *Inst, llvm::MDNode *TBAAInfo); /// getSize - Emit the given number of characters as a value of type size_t. llvm::ConstantInt *getSize(CharUnits numChars); /// setGlobalVisibility - Set the visibility for the given LLVM /// GlobalValue. void setGlobalVisibility(llvm::GlobalValue *GV, const NamedDecl *D) const; /// TypeVisibilityKind - The kind of global variable that is passed to /// setTypeVisibility enum TypeVisibilityKind { TVK_ForVTT, TVK_ForVTable, TVK_ForConstructionVTable, TVK_ForRTTI, TVK_ForRTTIName }; /// setTypeVisibility - Set the visibility for the given global /// value which holds information about a type. void setTypeVisibility(llvm::GlobalValue *GV, const CXXRecordDecl *D, TypeVisibilityKind TVK) const; static llvm::GlobalValue::VisibilityTypes GetLLVMVisibility(Visibility V) { switch (V) { case DefaultVisibility: return llvm::GlobalValue::DefaultVisibility; case HiddenVisibility: return llvm::GlobalValue::HiddenVisibility; case ProtectedVisibility: return llvm::GlobalValue::ProtectedVisibility; } llvm_unreachable("unknown visibility!"); return llvm::GlobalValue::DefaultVisibility; } llvm::Constant *GetAddrOfGlobal(GlobalDecl GD) { if (isa(GD.getDecl())) return GetAddrOfCXXConstructor(cast(GD.getDecl()), GD.getCtorType()); else if (isa(GD.getDecl())) return GetAddrOfCXXDestructor(cast(GD.getDecl()), GD.getDtorType()); else if (isa(GD.getDecl())) return GetAddrOfFunction(GD); else return GetAddrOfGlobalVar(cast(GD.getDecl())); } /// CreateOrReplaceCXXRuntimeVariable - Will return a global variable of the given /// type. If a variable with a different type already exists then a new /// variable with the right type will be created and all uses of the old /// variable will be replaced with a bitcast to the new variable. llvm::GlobalVariable * CreateOrReplaceCXXRuntimeVariable(StringRef Name, llvm::Type *Ty, llvm::GlobalValue::LinkageTypes Linkage); /// GetAddrOfGlobalVar - Return the llvm::Constant for the address of the /// given global variable. If Ty is non-null and if the global doesn't exist, /// then it will be greated with the specified type instead of whatever the /// normal requested type would be. llvm::Constant *GetAddrOfGlobalVar(const VarDecl *D, llvm::Type *Ty = 0); /// GetAddrOfFunction - Return the address of the given function. If Ty is /// non-null, then this function will use the specified type if it has to /// create it. llvm::Constant *GetAddrOfFunction(GlobalDecl GD, llvm::Type *Ty = 0, bool ForVTable = false); /// GetAddrOfRTTIDescriptor - Get the address of the RTTI descriptor /// for the given type. llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty, bool ForEH = false); /// GetAddrOfThunk - Get the address of the thunk for the given global decl. llvm::Constant *GetAddrOfThunk(GlobalDecl GD, const ThunkInfo &Thunk); /// GetWeakRefReference - Get a reference to the target of VD. llvm::Constant *GetWeakRefReference(const ValueDecl *VD); /// GetNonVirtualBaseClassOffset - Returns the offset from a derived class to /// a class. Returns null if the offset is 0. llvm::Constant * GetNonVirtualBaseClassOffset(const CXXRecordDecl *ClassDecl, CastExpr::path_const_iterator PathBegin, CastExpr::path_const_iterator PathEnd); /// A pair of helper functions for a __block variable. class ByrefHelpers : public llvm::FoldingSetNode { public: llvm::Constant *CopyHelper; llvm::Constant *DisposeHelper; /// The alignment of the field. This is important because /// different offsets to the field within the byref struct need to /// have different helper functions. CharUnits Alignment; ByrefHelpers(CharUnits alignment) : Alignment(alignment) {} virtual ~ByrefHelpers(); void Profile(llvm::FoldingSetNodeID &id) const { id.AddInteger(Alignment.getQuantity()); profileImpl(id); } virtual void profileImpl(llvm::FoldingSetNodeID &id) const = 0; virtual bool needsCopy() const { return true; } virtual void emitCopy(CodeGenFunction &CGF, llvm::Value *dest, llvm::Value *src) = 0; virtual bool needsDispose() const { return true; } virtual void emitDispose(CodeGenFunction &CGF, llvm::Value *field) = 0; }; llvm::FoldingSet ByrefHelpersCache; /// getUniqueBlockCount - Fetches the global unique block count. int getUniqueBlockCount() { return ++Block.GlobalUniqueCount; } /// getBlockDescriptorType - Fetches the type of a generic block /// descriptor. llvm::Type *getBlockDescriptorType(); /// getGenericBlockLiteralType - The type of a generic block literal. llvm::Type *getGenericBlockLiteralType(); /// GetAddrOfGlobalBlock - Gets the address of a block which /// requires no captures. llvm::Constant *GetAddrOfGlobalBlock(const BlockExpr *BE, const char *); /// GetStringForStringLiteral - Return the appropriate bytes for a string /// literal, properly padded to match the literal type. If only the address of /// a constant is needed consider using GetAddrOfConstantStringLiteral. std::string GetStringForStringLiteral(const StringLiteral *E); /// GetAddrOfConstantCFString - Return a pointer to a constant CFString object /// for the given string. llvm::Constant *GetAddrOfConstantCFString(const StringLiteral *Literal); /// GetAddrOfConstantString - Return a pointer to a constant NSString object /// for the given string. Or a user defined String object as defined via /// -fconstant-string-class=class_name option. llvm::Constant *GetAddrOfConstantString(const StringLiteral *Literal); /// GetAddrOfConstantStringFromLiteral - Return a pointer to a constant array /// for the given string literal. llvm::Constant *GetAddrOfConstantStringFromLiteral(const StringLiteral *S); /// GetAddrOfConstantStringFromObjCEncode - Return a pointer to a constant /// array for the given ObjCEncodeExpr node. llvm::Constant *GetAddrOfConstantStringFromObjCEncode(const ObjCEncodeExpr *); /// GetAddrOfConstantString - Returns a pointer to a character array /// containing the literal. This contents are exactly that of the given /// string, i.e. it will not be null terminated automatically; see /// GetAddrOfConstantCString. Note that whether the result is actually a /// pointer to an LLVM constant depends on Feature.WriteableStrings. /// /// The result has pointer to array type. /// /// \param GlobalName If provided, the name to use for the global /// (if one is created). llvm::Constant *GetAddrOfConstantString(StringRef Str, const char *GlobalName=0, unsigned Alignment=1); /// GetAddrOfConstantCString - Returns a pointer to a character array /// containing the literal and a terminating '\0' character. The result has /// pointer to array type. /// /// \param GlobalName If provided, the name to use for the global (if one is /// created). llvm::Constant *GetAddrOfConstantCString(const std::string &str, const char *GlobalName=0, unsigned Alignment=1); /// \brief Retrieve the record type that describes the state of an /// Objective-C fast enumeration loop (for..in). QualType getObjCFastEnumerationStateType(); /// GetAddrOfCXXConstructor - Return the address of the constructor of the /// given type. llvm::GlobalValue *GetAddrOfCXXConstructor(const CXXConstructorDecl *ctor, CXXCtorType ctorType, const CGFunctionInfo *fnInfo = 0); /// GetAddrOfCXXDestructor - Return the address of the constructor of the /// given type. llvm::GlobalValue *GetAddrOfCXXDestructor(const CXXDestructorDecl *dtor, CXXDtorType dtorType, const CGFunctionInfo *fnInfo = 0); /// getBuiltinLibFunction - Given a builtin id for a function like /// "__builtin_fabsf", return a Function* for "fabsf". llvm::Value *getBuiltinLibFunction(const FunctionDecl *FD, unsigned BuiltinID); llvm::Function *getIntrinsic(unsigned IID, ArrayRef Tys = ArrayRef()); /// EmitTopLevelDecl - Emit code for a single top level declaration. void EmitTopLevelDecl(Decl *D); /// AddUsedGlobal - Add a global which should be forced to be /// present in the object file; these are emitted to the llvm.used /// metadata global. void AddUsedGlobal(llvm::GlobalValue *GV); /// AddCXXDtorEntry - Add a destructor and object to add to the C++ global /// destructor function. void AddCXXDtorEntry(llvm::Constant *DtorFn, llvm::Constant *Object) { CXXGlobalDtors.push_back(std::make_pair(DtorFn, Object)); } /// CreateRuntimeFunction - Create a new runtime function with the specified /// type and name. llvm::Constant *CreateRuntimeFunction(llvm::FunctionType *Ty, StringRef Name, llvm::Attributes ExtraAttrs = llvm::Attribute::None); /// CreateRuntimeVariable - Create a new runtime global variable with the /// specified type and name. llvm::Constant *CreateRuntimeVariable(llvm::Type *Ty, StringRef Name); ///@name Custom Blocks Runtime Interfaces ///@{ llvm::Constant *getNSConcreteGlobalBlock(); llvm::Constant *getNSConcreteStackBlock(); llvm::Constant *getBlockObjectAssign(); llvm::Constant *getBlockObjectDispose(); ///@} // UpdateCompleteType - Make sure that this type is translated. void UpdateCompletedType(const TagDecl *TD); llvm::Constant *getMemberPointerConstant(const UnaryOperator *e); /// EmitConstantExpr - Try to emit the given expression as a /// constant; returns 0 if the expression cannot be emitted as a /// constant. llvm::Constant *EmitConstantExpr(const Expr *E, QualType DestType, CodeGenFunction *CGF = 0); /// EmitNullConstant - Return the result of value-initializing the given /// type, i.e. a null expression of the given type. This is usually, /// but not always, an LLVM null constant. llvm::Constant *EmitNullConstant(QualType T); /// EmitNullConstantForBase - Return a null constant appropriate for /// zero-initializing a base class with the given type. This is usually, /// but not always, an LLVM null constant. llvm::Constant *EmitNullConstantForBase(const CXXRecordDecl *Record); /// Error - Emit a general error that something can't be done. void Error(SourceLocation loc, StringRef error); /// ErrorUnsupported - Print out an error that codegen doesn't support the /// specified stmt yet. /// \param OmitOnError - If true, then this error should only be emitted if no /// other errors have been reported. void ErrorUnsupported(const Stmt *S, const char *Type, bool OmitOnError=false); /// ErrorUnsupported - Print out an error that codegen doesn't support the /// specified decl yet. /// \param OmitOnError - If true, then this error should only be emitted if no /// other errors have been reported. void ErrorUnsupported(const Decl *D, const char *Type, bool OmitOnError=false); /// SetInternalFunctionAttributes - Set the attributes on the LLVM /// function for the given decl and function info. This applies /// attributes necessary for handling the ABI as well as user /// specified attributes like section. void SetInternalFunctionAttributes(const Decl *D, llvm::Function *F, const CGFunctionInfo &FI); /// SetLLVMFunctionAttributes - Set the LLVM function attributes /// (sext, zext, etc). void SetLLVMFunctionAttributes(const Decl *D, const CGFunctionInfo &Info, llvm::Function *F); /// SetLLVMFunctionAttributesForDefinition - Set the LLVM function attributes /// which only apply to a function definintion. void SetLLVMFunctionAttributesForDefinition(const Decl *D, llvm::Function *F); /// ReturnTypeUsesSRet - Return true iff the given type uses 'sret' when used /// as a return type. bool ReturnTypeUsesSRet(const CGFunctionInfo &FI); /// ReturnTypeUsesSret - Return true iff the given type uses 'fpret' when used /// as a return type. bool ReturnTypeUsesFPRet(QualType ResultType); /// ConstructAttributeList - Get the LLVM attributes and calling convention to /// use for a particular function type. /// /// \param Info - The function type information. /// \param TargetDecl - The decl these attributes are being constructed /// for. If supplied the attributes applied to this decl may contribute to the /// function attributes and calling convention. /// \param PAL [out] - On return, the attribute list to use. /// \param CallingConv [out] - On return, the LLVM calling convention to use. void ConstructAttributeList(const CGFunctionInfo &Info, const Decl *TargetDecl, AttributeListType &PAL, unsigned &CallingConv); StringRef getMangledName(GlobalDecl GD); void getBlockMangledName(GlobalDecl GD, MangleBuffer &Buffer, const BlockDecl *BD); void EmitTentativeDefinition(const VarDecl *D); void EmitVTable(CXXRecordDecl *Class, bool DefinitionRequired); llvm::GlobalVariable::LinkageTypes getFunctionLinkage(const FunctionDecl *FD); void setFunctionLinkage(const FunctionDecl *FD, llvm::GlobalValue *V) { V->setLinkage(getFunctionLinkage(FD)); } /// getVTableLinkage - Return the appropriate linkage for the vtable, VTT, /// and type information of the given class. llvm::GlobalVariable::LinkageTypes getVTableLinkage(const CXXRecordDecl *RD); /// GetTargetTypeStoreSize - Return the store size, in character units, of /// the given LLVM type. CharUnits GetTargetTypeStoreSize(llvm::Type *Ty) const; /// GetLLVMLinkageVarDefinition - Returns LLVM linkage for a global /// variable. llvm::GlobalValue::LinkageTypes GetLLVMLinkageVarDefinition(const VarDecl *D, llvm::GlobalVariable *GV); std::vector DeferredVTables; /// Emit all the global annotations. void EmitGlobalAnnotations(); /// Emit an annotation string. llvm::Constant *EmitAnnotationString(llvm::StringRef Str); /// Emit the annotation's translation unit. llvm::Constant *EmitAnnotationUnit(SourceLocation Loc); /// Emit the annotation line number. llvm::Constant *EmitAnnotationLineNo(SourceLocation L); /// EmitAnnotateAttr - Generate the llvm::ConstantStruct which contains the /// annotation information for a given GlobalValue. The annotation struct is /// {i8 *, i8 *, i8 *, i32}. The first field is a constant expression, the /// GlobalValue being annotated. The second field is the constant string /// created from the AnnotateAttr's annotation. The third field is a constant /// string containing the name of the translation unit. The fourth field is /// the line number in the file of the annotated value declaration. llvm::Constant *EmitAnnotateAttr(llvm::GlobalValue *GV, const AnnotateAttr *AA, SourceLocation L); /// Add global annotations that are set on D, for the global GV. Those /// annotations are emitted during finalization of the LLVM code. void AddGlobalAnnotations(const ValueDecl *D, llvm::GlobalValue *GV); private: llvm::GlobalValue *GetGlobalValue(StringRef Ref); llvm::Constant *GetOrCreateLLVMFunction(StringRef MangledName, llvm::Type *Ty, GlobalDecl D, bool ForVTable, llvm::Attributes ExtraAttrs = llvm::Attribute::None); llvm::Constant *GetOrCreateLLVMGlobal(StringRef MangledName, llvm::PointerType *PTy, const VarDecl *D, bool UnnamedAddr = false); /// SetCommonAttributes - Set attributes which are common to any /// form of a global definition (alias, Objective-C method, /// function, global variable). /// /// NOTE: This should only be called for definitions. void SetCommonAttributes(const Decl *D, llvm::GlobalValue *GV); /// SetFunctionDefinitionAttributes - Set attributes for a global definition. void SetFunctionDefinitionAttributes(const FunctionDecl *D, llvm::GlobalValue *GV); /// SetFunctionAttributes - Set function attributes for a function /// declaration. void SetFunctionAttributes(GlobalDecl GD, llvm::Function *F, bool IsIncompleteFunction); /// EmitGlobal - Emit code for a singal global function or var decl. Forward /// declarations are emitted lazily. void EmitGlobal(GlobalDecl D); void EmitGlobalDefinition(GlobalDecl D); void EmitGlobalFunctionDefinition(GlobalDecl GD); void EmitGlobalVarDefinition(const VarDecl *D); void EmitAliasDefinition(GlobalDecl GD); void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D); void EmitObjCIvarInitializations(ObjCImplementationDecl *D); // C++ related functions. bool TryEmitDefinitionAsAlias(GlobalDecl Alias, GlobalDecl Target); bool TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D); void EmitNamespace(const NamespaceDecl *D); void EmitLinkageSpec(const LinkageSpecDecl *D); /// EmitCXXConstructors - Emit constructors (base, complete) from a /// C++ constructor Decl. void EmitCXXConstructors(const CXXConstructorDecl *D); /// EmitCXXConstructor - Emit a single constructor with the given type from /// a C++ constructor Decl. void EmitCXXConstructor(const CXXConstructorDecl *D, CXXCtorType Type); /// EmitCXXDestructors - Emit destructors (base, complete) from a /// C++ destructor Decl. void EmitCXXDestructors(const CXXDestructorDecl *D); /// EmitCXXDestructor - Emit a single destructor with the given type from /// a C++ destructor Decl. void EmitCXXDestructor(const CXXDestructorDecl *D, CXXDtorType Type); /// EmitCXXGlobalInitFunc - Emit the function that initializes C++ globals. void EmitCXXGlobalInitFunc(); /// EmitCXXGlobalDtorFunc - Emit the function that destroys C++ globals. void EmitCXXGlobalDtorFunc(); void EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, llvm::GlobalVariable *Addr); // FIXME: Hardcoding priority here is gross. void AddGlobalCtor(llvm::Function *Ctor, int Priority=65535); void AddGlobalDtor(llvm::Function *Dtor, int Priority=65535); /// EmitCtorList - Generates a global array of functions and priorities using /// the given list and name. This array will have appending linkage and is /// suitable for use as a LLVM constructor or destructor array. void EmitCtorList(const CtorList &Fns, const char *GlobalName); /// EmitFundamentalRTTIDescriptor - Emit the RTTI descriptors for the /// given type. void EmitFundamentalRTTIDescriptor(QualType Type); /// EmitFundamentalRTTIDescriptors - Emit the RTTI descriptors for the /// builtin types. void EmitFundamentalRTTIDescriptors(); /// EmitDeferred - Emit any needed decls for which code generation /// was deferred. void EmitDeferred(void); /// EmitLLVMUsed - Emit the llvm.used metadata used to force /// references to global which may otherwise be optimized out. void EmitLLVMUsed(void); void EmitDeclMetadata(); /// EmitCoverageFile - Emit the llvm.gcov metadata used to tell LLVM where /// to emit the .gcno and .gcda files in a way that persists in .bc files. void EmitCoverageFile(); /// MayDeferGeneration - Determine if the given decl can be emitted /// lazily; this is only relevant for definitions. The given decl /// must be either a function or var decl. bool MayDeferGeneration(const ValueDecl *D); /// SimplifyPersonality - Check whether we can use a "simpler", more /// core exceptions personality function. void SimplifyPersonality(); }; } // end namespace CodeGen } // end namespace clang #endif Index: head/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp =================================================================== --- head/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp (revision 228378) +++ head/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp (revision 228379) @@ -1,266 +1,265 @@ //===--- ToolChain.cpp - Collections of tools for one platform ------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "clang/Driver/ToolChain.h" #include "clang/Driver/Action.h" #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/HostInfo.h" #include "clang/Driver/ObjCRuntime.h" #include "clang/Driver/Options.h" #include "llvm/Support/ErrorHandling.h" using namespace clang::driver; using namespace clang; ToolChain::ToolChain(const HostInfo &H, const llvm::Triple &T) : Host(H), Triple(T) { } ToolChain::~ToolChain() { } const Driver &ToolChain::getDriver() const { return Host.getDriver(); } std::string ToolChain::GetFilePath(const char *Name) const { return Host.getDriver().GetFilePath(Name, *this); } std::string ToolChain::GetProgramPath(const char *Name, bool WantFile) const { return Host.getDriver().GetProgramPath(Name, *this, WantFile); } types::ID ToolChain::LookupTypeForExtension(const char *Ext) const { return types::lookupTypeForExtension(Ext); } bool ToolChain::HasNativeLLVMSupport() const { return false; } void ToolChain::configureObjCRuntime(ObjCRuntime &runtime) const { switch (runtime.getKind()) { case ObjCRuntime::NeXT: // Assume a minimal NeXT runtime. runtime.HasARC = false; runtime.HasWeak = false; runtime.HasTerminate = false; return; case ObjCRuntime::GNU: // Assume a maximal GNU runtime. runtime.HasARC = true; runtime.HasWeak = true; runtime.HasTerminate = false; // to be added return; } llvm_unreachable("invalid runtime kind!"); } /// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targeting. // // FIXME: tblgen this. static const char *getARMTargetCPU(const ArgList &Args, const llvm::Triple &Triple) { // FIXME: Warn on inconsistent use of -mcpu and -march. // If we have -mcpu=, use that. if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) return A->getValue(Args); StringRef MArch; if (Arg *A = Args.getLastArg(options::OPT_march_EQ)) { // Otherwise, if we have -march= choose the base CPU for that arch. MArch = A->getValue(Args); } else { // Otherwise, use the Arch from the triple. MArch = Triple.getArchName(); } if (MArch == "armv2" || MArch == "armv2a") return "arm2"; if (MArch == "armv3") return "arm6"; if (MArch == "armv3m") return "arm7m"; if (MArch == "armv4" || MArch == "armv4t") return "arm7tdmi"; if (MArch == "armv5" || MArch == "armv5t") return "arm10tdmi"; if (MArch == "armv5e" || MArch == "armv5te") return "arm1026ejs"; if (MArch == "armv5tej") return "arm926ej-s"; if (MArch == "armv6" || MArch == "armv6k") return "arm1136jf-s"; if (MArch == "armv6j") return "arm1136j-s"; if (MArch == "armv6z" || MArch == "armv6zk") return "arm1176jzf-s"; if (MArch == "armv6t2") return "arm1156t2-s"; if (MArch == "armv7" || MArch == "armv7a" || MArch == "armv7-a") return "cortex-a8"; if (MArch == "armv7r" || MArch == "armv7-r") return "cortex-r4"; if (MArch == "armv7m" || MArch == "armv7-m") return "cortex-m3"; if (MArch == "ep9312") return "ep9312"; if (MArch == "iwmmxt") return "iwmmxt"; if (MArch == "xscale") return "xscale"; if (MArch == "armv6m" || MArch == "armv6-m") return "cortex-m0"; // If all else failed, return the most base CPU LLVM supports. return "arm7tdmi"; } /// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular /// CPU. // // FIXME: This is redundant with -mcpu, why does LLVM use this. // FIXME: tblgen this, or kill it! static const char *getLLVMArchSuffixForARM(StringRef CPU) { if (CPU == "arm7tdmi" || CPU == "arm7tdmi-s" || CPU == "arm710t" || CPU == "arm720t" || CPU == "arm9" || CPU == "arm9tdmi" || CPU == "arm920" || CPU == "arm920t" || CPU == "arm922t" || CPU == "arm940t" || CPU == "ep9312") return "v4t"; if (CPU == "arm10tdmi" || CPU == "arm1020t") return "v5"; if (CPU == "arm9e" || CPU == "arm926ej-s" || CPU == "arm946e-s" || CPU == "arm966e-s" || CPU == "arm968e-s" || CPU == "arm10e" || CPU == "arm1020e" || CPU == "arm1022e" || CPU == "xscale" || CPU == "iwmmxt") return "v5e"; if (CPU == "arm1136j-s" || CPU == "arm1136jf-s" || CPU == "arm1176jz-s" || CPU == "arm1176jzf-s" || CPU == "mpcorenovfp" || CPU == "mpcore") return "v6"; if (CPU == "arm1156t2-s" || CPU == "arm1156t2f-s") return "v6t2"; if (CPU == "cortex-a8" || CPU == "cortex-a9") return "v7"; if (CPU == "cortex-m3") return "v7m"; if (CPU == "cortex-m0") return "v6m"; return ""; } std::string ToolChain::ComputeLLVMTriple(const ArgList &Args, types::ID InputType) const { switch (getTriple().getArch()) { default: return getTripleString(); case llvm::Triple::arm: case llvm::Triple::thumb: { // FIXME: Factor into subclasses. llvm::Triple Triple = getTriple(); // Thumb2 is the default for V7 on Darwin. // // FIXME: Thumb should just be another -target-feaure, not in the triple. StringRef Suffix = getLLVMArchSuffixForARM(getARMTargetCPU(Args, Triple)); bool ThumbDefault = (Suffix == "v7" && getTriple().isOSDarwin()); std::string ArchName = "arm"; // Assembly files should start in ARM mode. if (InputType != types::TY_PP_Asm && Args.hasFlag(options::OPT_mthumb, options::OPT_mno_thumb, ThumbDefault)) ArchName = "thumb"; Triple.setArchName(ArchName + Suffix.str()); return Triple.getTriple(); } } } std::string ToolChain::ComputeEffectiveClangTriple(const ArgList &Args, types::ID InputType) const { // Diagnose use of Darwin OS deployment target arguments on non-Darwin. if (Arg *A = Args.getLastArg(options::OPT_mmacosx_version_min_EQ, options::OPT_miphoneos_version_min_EQ, options::OPT_mios_simulator_version_min_EQ)) getDriver().Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); return ComputeLLVMTriple(Args, InputType); } +void ToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + // Each toolchain should provide the appropriate include flags. +} + ToolChain::CXXStdlibType ToolChain::GetCXXStdlibType(const ArgList &Args) const{ if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { StringRef Value = A->getValue(Args); if (Value == "libc++") return ToolChain::CST_Libcxx; if (Value == "libstdc++") return ToolChain::CST_Libstdcxx; getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args); } return ToolChain::CST_Libstdcxx; } -void ToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &Args, - ArgStringList &CmdArgs, - bool ObjCXXAutoRefCount) const { - CXXStdlibType Type = GetCXXStdlibType(Args); - - // Header search paths are handled by the mass of goop in InitHeaderSearch. - - switch (Type) { - case ToolChain::CST_Libcxx: - if (ObjCXXAutoRefCount) - CmdArgs.push_back("-fobjc-arc-cxxlib=libc++"); - break; - - case ToolChain::CST_Libstdcxx: - if (ObjCXXAutoRefCount) - CmdArgs.push_back("-fobjc-arc-cxxlib=libstdc++"); - break; - } +void ToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + // Header search paths should be handled by each of the subclasses. + // Historically, they have not been, and instead have been handled inside of + // the CC1-layer frontend. As the logic is hoisted out, this generic function + // will slowly stop being called. + // + // While it is being called, replicate a bit of a hack to propagate the + // '-stdlib=' flag down to CC1 so that it can in turn customize the C++ + // header search paths with it. Once all systems are overriding this + // function, the CC1 flag and this line can be removed. + DriverArgs.AddAllArgs(CC1Args, options::OPT_stdlib_EQ); } void ToolChain::AddCXXStdlibLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { CXXStdlibType Type = GetCXXStdlibType(Args); switch (Type) { case ToolChain::CST_Libcxx: CmdArgs.push_back("-lc++"); break; case ToolChain::CST_Libstdcxx: CmdArgs.push_back("-lstdc++"); break; } } void ToolChain::AddCCKextLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { CmdArgs.push_back("-lcc_kext"); } Index: head/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp =================================================================== --- head/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp (revision 228378) +++ head/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp (revision 228379) @@ -1,1992 +1,2436 @@ //===--- ToolChains.cpp - ToolChain Implementations -----------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "ToolChains.h" #ifdef HAVE_CLANG_CONFIG_H # include "clang/Config/config.h" #endif #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/HostInfo.h" #include "clang/Driver/ObjCRuntime.h" #include "clang/Driver/OptTable.h" #include "clang/Driver/Option.h" #include "clang/Driver/Options.h" #include "clang/Basic/Version.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Path.h" #include "llvm/Support/system_error.h" #include // ::getenv #include "llvm/Config/config.h" // for CXX_INCLUDE_ROOT +// Include the necessary headers to interface with the Windows registry and +// environment. +#ifdef _MSC_VER + #define WIN32_LEAN_AND_MEAN 1 + #include + #undef min + #undef max +#endif + #ifndef CLANG_PREFIX #define CLANG_PREFIX #endif using namespace clang::driver; using namespace clang::driver::toolchains; using namespace clang; +/// \brief Utility function to add a system include directory to CC1 arguments. +static void addSystemInclude(const ArgList &DriverArgs, ArgStringList &CC1Args, + const Twine &Path) { + CC1Args.push_back("-internal-isystem"); + CC1Args.push_back(DriverArgs.MakeArgString(Path)); +} + +/// \brief Utility function to add a system include directory with extern "C" +/// semantics to CC1 arguments. +/// +/// Note that this should be used rarely, and only for directories that +/// historically and for legacy reasons are treated as having implicit extern +/// "C" semantics. These semantics are *ignored* by and large today, but its +/// important to preserve the preprocessor changes resulting from the +/// classification. +static void addExternCSystemInclude(const ArgList &DriverArgs, + ArgStringList &CC1Args, const Twine &Path) { + CC1Args.push_back("-internal-externc-isystem"); + CC1Args.push_back(DriverArgs.MakeArgString(Path)); +} + +/// \brief Utility function to add a list of system include directories to CC1. +static void addSystemIncludes(const ArgList &DriverArgs, + ArgStringList &CC1Args, + ArrayRef Paths) { + for (ArrayRef::iterator I = Paths.begin(), E = Paths.end(); + I != E; ++I) { + CC1Args.push_back("-internal-isystem"); + CC1Args.push_back(DriverArgs.MakeArgString(*I)); + } +} + /// Darwin - Darwin tool chain for i386 and x86_64. Darwin::Darwin(const HostInfo &Host, const llvm::Triple& Triple) : ToolChain(Host, Triple), TargetInitialized(false), ARCRuntimeForSimulator(ARCSimulator_None), LibCXXForSimulator(LibCXXSimulator_None) { // Compute the initial Darwin version based on the host. bool HadExtra; std::string OSName = Triple.getOSName(); if (!Driver::GetReleaseVersion(&OSName.c_str()[6], DarwinVersion[0], DarwinVersion[1], DarwinVersion[2], HadExtra)) getDriver().Diag(diag::err_drv_invalid_darwin_version) << OSName; llvm::raw_string_ostream(MacosxVersionMin) << "10." << std::max(0, (int)DarwinVersion[0] - 4) << '.' << DarwinVersion[1]; } types::ID Darwin::LookupTypeForExtension(const char *Ext) const { types::ID Ty = types::lookupTypeForExtension(Ext); // Darwin always preprocesses assembly files (unless -x is used explicitly). if (Ty == types::TY_PP_Asm) return types::TY_Asm; return Ty; } bool Darwin::HasNativeLLVMSupport() const { return true; } bool Darwin::hasARCRuntime() const { // FIXME: Remove this once there is a proper way to detect an ARC runtime // for the simulator. switch (ARCRuntimeForSimulator) { case ARCSimulator_None: break; case ARCSimulator_HasARCRuntime: return true; case ARCSimulator_NoARCRuntime: return false; } if (isTargetIPhoneOS()) return !isIPhoneOSVersionLT(5); else return !isMacosxVersionLT(10, 7); } /// Darwin provides an ARC runtime starting in MacOS X 10.7 and iOS 5.0. void Darwin::configureObjCRuntime(ObjCRuntime &runtime) const { if (runtime.getKind() != ObjCRuntime::NeXT) return ToolChain::configureObjCRuntime(runtime); runtime.HasARC = runtime.HasWeak = hasARCRuntime(); // So far, objc_terminate is only available in iOS 5. // FIXME: do the simulator logic properly. if (!ARCRuntimeForSimulator && isTargetIPhoneOS()) runtime.HasTerminate = !isIPhoneOSVersionLT(5); else runtime.HasTerminate = false; } /// Darwin provides a blocks runtime starting in MacOS X 10.6 and iOS 3.2. bool Darwin::hasBlocksRuntime() const { if (isTargetIPhoneOS()) return !isIPhoneOSVersionLT(3, 2); else return !isMacosxVersionLT(10, 6); } static const char *GetArmArchForMArch(StringRef Value) { return llvm::StringSwitch(Value) .Case("armv6k", "armv6") .Case("armv5tej", "armv5") .Case("xscale", "xscale") .Case("armv4t", "armv4t") .Case("armv7", "armv7") .Cases("armv7a", "armv7-a", "armv7") .Cases("armv7r", "armv7-r", "armv7") .Cases("armv7m", "armv7-m", "armv7") .Default(0); } static const char *GetArmArchForMCpu(StringRef Value) { return llvm::StringSwitch(Value) .Cases("arm9e", "arm946e-s", "arm966e-s", "arm968e-s", "arm926ej-s","armv5") .Cases("arm10e", "arm10tdmi", "armv5") .Cases("arm1020t", "arm1020e", "arm1022e", "arm1026ej-s", "armv5") .Case("xscale", "xscale") .Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "arm1176jzf-s", "cortex-m0", "armv6") .Cases("cortex-a8", "cortex-r4", "cortex-m3", "cortex-a9", "armv7") .Default(0); } StringRef Darwin::getDarwinArchName(const ArgList &Args) const { switch (getTriple().getArch()) { default: return getArchName(); case llvm::Triple::thumb: case llvm::Triple::arm: { if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) if (const char *Arch = GetArmArchForMArch(A->getValue(Args))) return Arch; if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) if (const char *Arch = GetArmArchForMCpu(A->getValue(Args))) return Arch; return "arm"; } } } Darwin::~Darwin() { // Free tool implementations. for (llvm::DenseMap::iterator it = Tools.begin(), ie = Tools.end(); it != ie; ++it) delete it->second; } std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args, types::ID InputType) const { llvm::Triple Triple(ComputeLLVMTriple(Args, InputType)); // If the target isn't initialized (e.g., an unknown Darwin platform, return // the default triple). if (!isTargetInitialized()) return Triple.getTriple(); unsigned Version[3]; getTargetVersion(Version); llvm::SmallString<16> Str; llvm::raw_svector_ostream(Str) << (isTargetIPhoneOS() ? "ios" : "macosx") << Version[0] << "." << Version[1] << "." << Version[2]; Triple.setOSName(Str.str()); return Triple.getTriple(); } Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const { Action::ActionClass Key; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) { // Fallback to llvm-gcc for i386 kext compiles, we don't support that ABI. if (Inputs.size() == 1 && types::isCXX(Inputs[0]->getType()) && getTriple().isOSDarwin() && getTriple().getArch() == llvm::Triple::x86 && (C.getArgs().getLastArg(options::OPT_fapple_kext) || C.getArgs().getLastArg(options::OPT_mkernel))) Key = JA.getKind(); else Key = Action::AnalyzeJobClass; } else Key = JA.getKind(); // FIXME: This doesn't belong here, but ideally we will support static soon // anyway. bool HasStatic = (C.getArgs().hasArg(options::OPT_mkernel) || C.getArgs().hasArg(options::OPT_static) || C.getArgs().hasArg(options::OPT_fapple_kext)); bool IsIADefault = IsIntegratedAssemblerDefault() && !HasStatic; bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, options::OPT_no_integrated_as, IsIADefault); Tool *&T = Tools[Key]; if (!T) { switch (Key) { case Action::InputClass: case Action::BindArchClass: llvm_unreachable("Invalid tool kind."); case Action::PreprocessJobClass: T = new tools::darwin::Preprocess(*this); break; case Action::AnalyzeJobClass: T = new tools::Clang(*this); break; case Action::PrecompileJobClass: case Action::CompileJobClass: T = new tools::darwin::Compile(*this); break; case Action::AssembleJobClass: { if (UseIntegratedAs) T = new tools::ClangAs(*this); else T = new tools::darwin::Assemble(*this); break; } case Action::LinkJobClass: T = new tools::darwin::Link(*this); break; case Action::LipoJobClass: T = new tools::darwin::Lipo(*this); break; case Action::DsymutilJobClass: T = new tools::darwin::Dsymutil(*this); break; case Action::VerifyJobClass: T = new tools::darwin::VerifyDebug(*this); break; } } return *T; } DarwinClang::DarwinClang(const HostInfo &Host, const llvm::Triple& Triple) : Darwin(Host, Triple) { getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); // We expect 'as', 'ld', etc. to be adjacent to our install dir. getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); // For fallback, we need to know how to find the GCC cc1 executables, so we // also add the GCC libexec paths. This is legacy code that can be removed // once fallback is no longer useful. AddGCCLibexecPath(DarwinVersion[0]); AddGCCLibexecPath(DarwinVersion[0] - 2); AddGCCLibexecPath(DarwinVersion[0] - 1); AddGCCLibexecPath(DarwinVersion[0] + 1); AddGCCLibexecPath(DarwinVersion[0] + 2); } void DarwinClang::AddGCCLibexecPath(unsigned darwinVersion) { std::string ToolChainDir = "i686-apple-darwin"; ToolChainDir += llvm::utostr(darwinVersion); ToolChainDir += "/4.2.1"; std::string Path = getDriver().Dir; Path += "/../llvm-gcc-4.2/libexec/gcc/"; Path += ToolChainDir; getProgramPaths().push_back(Path); Path = "/usr/llvm-gcc-4.2/libexec/gcc/"; Path += ToolChainDir; getProgramPaths().push_back(Path); } void DarwinClang::AddLinkSearchPathArgs(const ArgList &Args, ArgStringList &CmdArgs) const { // The Clang toolchain uses explicit paths for internal libraries. // Unfortunately, we still might depend on a few of the libraries that are // only available in the gcc library directory (in particular // libstdc++.dylib). For now, hardcode the path to the known install location. llvm::sys::Path P(getDriver().Dir); P.eraseComponent(); // .../usr/bin -> ../usr P.appendComponent("lib"); P.appendComponent("gcc"); switch (getTriple().getArch()) { default: llvm_unreachable("Invalid Darwin arch!"); case llvm::Triple::x86: case llvm::Triple::x86_64: P.appendComponent("i686-apple-darwin10"); break; case llvm::Triple::arm: case llvm::Triple::thumb: P.appendComponent("arm-apple-darwin10"); break; case llvm::Triple::ppc: case llvm::Triple::ppc64: P.appendComponent("powerpc-apple-darwin10"); break; } P.appendComponent("4.2.1"); // Determine the arch specific GCC subdirectory. const char *ArchSpecificDir = 0; switch (getTriple().getArch()) { default: break; case llvm::Triple::arm: case llvm::Triple::thumb: { std::string Triple = ComputeLLVMTriple(Args); StringRef TripleStr = Triple; if (TripleStr.startswith("armv5") || TripleStr.startswith("thumbv5")) ArchSpecificDir = "v5"; else if (TripleStr.startswith("armv6") || TripleStr.startswith("thumbv6")) ArchSpecificDir = "v6"; else if (TripleStr.startswith("armv7") || TripleStr.startswith("thumbv7")) ArchSpecificDir = "v7"; break; } case llvm::Triple::ppc64: ArchSpecificDir = "ppc64"; break; case llvm::Triple::x86_64: ArchSpecificDir = "x86_64"; break; } if (ArchSpecificDir) { P.appendComponent(ArchSpecificDir); bool Exists; if (!llvm::sys::fs::exists(P.str(), Exists) && Exists) CmdArgs.push_back(Args.MakeArgString("-L" + P.str())); P.eraseComponent(); } bool Exists; if (!llvm::sys::fs::exists(P.str(), Exists) && Exists) CmdArgs.push_back(Args.MakeArgString("-L" + P.str())); } void DarwinClang::AddLinkARCArgs(const ArgList &Args, ArgStringList &CmdArgs) const { CmdArgs.push_back("-force_load"); llvm::sys::Path P(getDriver().ClangExecutable); P.eraseComponent(); // 'clang' P.eraseComponent(); // 'bin' P.appendComponent("lib"); P.appendComponent("arc"); P.appendComponent("libarclite_"); std::string s = P.str(); // Mash in the platform. if (isTargetIPhoneOS()) s += "iphoneos"; // FIXME: isTargetIphoneOSSimulator() is not returning true. else if (ARCRuntimeForSimulator != ARCSimulator_None) s += "iphonesimulator"; else s += "macosx"; s += ".a"; CmdArgs.push_back(Args.MakeArgString(s)); } void DarwinClang::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs, const char *DarwinStaticLib) const { llvm::sys::Path P(getDriver().ResourceDir); P.appendComponent("lib"); P.appendComponent("darwin"); P.appendComponent(DarwinStaticLib); // For now, allow missing resource libraries to support developers who may // not have compiler-rt checked out or integrated into their build. bool Exists; if (!llvm::sys::fs::exists(P.str(), Exists) && Exists) CmdArgs.push_back(Args.MakeArgString(P.str())); } void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { // Darwin doesn't support real static executables, don't link any runtime // libraries with -static. if (Args.hasArg(options::OPT_static)) return; // Reject -static-libgcc for now, we can deal with this when and if someone // cares. This is useful in situations where someone wants to statically link // something like libstdc++, and needs its runtime support routines. if (const Arg *A = Args.getLastArg(options::OPT_static_libgcc)) { getDriver().Diag(diag::err_drv_unsupported_opt) << A->getAsString(Args); return; } // Otherwise link libSystem, then the dynamic runtime library, and finally any // target specific static runtime library. CmdArgs.push_back("-lSystem"); // Select the dynamic runtime library and the target specific static library. if (isTargetIPhoneOS()) { // If we are compiling as iOS / simulator, don't attempt to link libgcc_s.1, // it never went into the SDK. // Linking against libgcc_s.1 isn't needed for iOS 5.0+ if (isIPhoneOSVersionLT(5, 0) && !isTargetIOSSimulator()) CmdArgs.push_back("-lgcc_s.1"); // We currently always need a static runtime library for iOS. AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.ios.a"); } else { // The dynamic runtime library was merged with libSystem for 10.6 and // beyond; only 10.4 and 10.5 need an additional runtime library. if (isMacosxVersionLT(10, 5)) CmdArgs.push_back("-lgcc_s.10.4"); else if (isMacosxVersionLT(10, 6)) CmdArgs.push_back("-lgcc_s.10.5"); // For OS X, we thought we would only need a static runtime library when // targeting 10.4, to provide versions of the static functions which were // omitted from 10.4.dylib. // // Unfortunately, that turned out to not be true, because Darwin system // headers can still use eprintf on i386, and it is not exported from // libSystem. Therefore, we still must provide a runtime library just for // the tiny tiny handful of projects that *might* use that symbol. if (isMacosxVersionLT(10, 5)) { AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.10.4.a"); } else { if (getTriple().getArch() == llvm::Triple::x86) AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.eprintf.a"); AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.osx.a"); } } } static inline StringRef SimulatorVersionDefineName() { return "__IPHONE_OS_VERSION_MIN_REQUIRED"; } /// \brief Parse the simulator version define: /// __IPHONE_OS_VERSION_MIN_REQUIRED=([0-9])([0-9][0-9])([0-9][0-9]) // and return the grouped values as integers, e.g: // __IPHONE_OS_VERSION_MIN_REQUIRED=40201 // will return Major=4, Minor=2, Micro=1. static bool GetVersionFromSimulatorDefine(StringRef define, unsigned &Major, unsigned &Minor, unsigned &Micro) { assert(define.startswith(SimulatorVersionDefineName())); StringRef name, version; llvm::tie(name, version) = define.split('='); if (version.empty()) return false; std::string verstr = version.str(); char *end; unsigned num = (unsigned) strtol(verstr.c_str(), &end, 10); if (*end != '\0') return false; Major = num / 10000; num = num % 10000; Minor = num / 100; Micro = num % 100; return true; } void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { const OptTable &Opts = getDriver().getOpts(); Arg *OSXVersion = Args.getLastArg(options::OPT_mmacosx_version_min_EQ); Arg *iOSVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ); Arg *iOSSimVersion = Args.getLastArg( options::OPT_mios_simulator_version_min_EQ); // FIXME: HACK! When compiling for the simulator we don't get a // '-miphoneos-version-min' to help us know whether there is an ARC runtime // or not; try to parse a __IPHONE_OS_VERSION_MIN_REQUIRED // define passed in command-line. if (!iOSVersion) { for (arg_iterator it = Args.filtered_begin(options::OPT_D), ie = Args.filtered_end(); it != ie; ++it) { StringRef define = (*it)->getValue(Args); if (define.startswith(SimulatorVersionDefineName())) { unsigned Major = 0, Minor = 0, Micro = 0; if (GetVersionFromSimulatorDefine(define, Major, Minor, Micro) && Major < 10 && Minor < 100 && Micro < 100) { ARCRuntimeForSimulator = Major < 5 ? ARCSimulator_NoARCRuntime : ARCSimulator_HasARCRuntime; LibCXXForSimulator = Major < 5 ? LibCXXSimulator_NotAvailable : LibCXXSimulator_Available; } break; } } } if (OSXVersion && (iOSVersion || iOSSimVersion)) { getDriver().Diag(diag::err_drv_argument_not_allowed_with) << OSXVersion->getAsString(Args) << (iOSVersion ? iOSVersion : iOSSimVersion)->getAsString(Args); iOSVersion = iOSSimVersion = 0; } else if (iOSVersion && iOSSimVersion) { getDriver().Diag(diag::err_drv_argument_not_allowed_with) << iOSVersion->getAsString(Args) << iOSSimVersion->getAsString(Args); iOSSimVersion = 0; } else if (!OSXVersion && !iOSVersion && !iOSSimVersion) { // If no deployment target was specified on the command line, check for // environment defines. StringRef OSXTarget; StringRef iOSTarget; StringRef iOSSimTarget; if (char *env = ::getenv("MACOSX_DEPLOYMENT_TARGET")) OSXTarget = env; if (char *env = ::getenv("IPHONEOS_DEPLOYMENT_TARGET")) iOSTarget = env; if (char *env = ::getenv("IOS_SIMULATOR_DEPLOYMENT_TARGET")) iOSSimTarget = env; // If no '-miphoneos-version-min' specified on the command line and // IPHONEOS_DEPLOYMENT_TARGET is not defined, see if we can set the default // based on isysroot. if (iOSTarget.empty()) { if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { StringRef first, second; StringRef isysroot = A->getValue(Args); llvm::tie(first, second) = isysroot.split(StringRef("SDKs/iPhoneOS")); if (second != "") iOSTarget = second.substr(0,3); } } // If no OSX or iOS target has been specified and we're compiling for armv7, // go ahead as assume we're targeting iOS. if (OSXTarget.empty() && iOSTarget.empty()) if (getDarwinArchName(Args) == "armv7") iOSTarget = "0.0"; // Handle conflicting deployment targets // // FIXME: Don't hardcode default here. // Do not allow conflicts with the iOS simulator target. if (!iOSSimTarget.empty() && (!OSXTarget.empty() || !iOSTarget.empty())) { getDriver().Diag(diag::err_drv_conflicting_deployment_targets) << "IOS_SIMULATOR_DEPLOYMENT_TARGET" << (!OSXTarget.empty() ? "MACOSX_DEPLOYMENT_TARGET" : "IPHONEOS_DEPLOYMENT_TARGET"); } // Allow conflicts among OSX and iOS for historical reasons, but choose the // default platform. if (!OSXTarget.empty() && !iOSTarget.empty()) { if (getTriple().getArch() == llvm::Triple::arm || getTriple().getArch() == llvm::Triple::thumb) OSXTarget = ""; else iOSTarget = ""; } if (!OSXTarget.empty()) { const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ); OSXVersion = Args.MakeJoinedArg(0, O, OSXTarget); Args.append(OSXVersion); } else if (!iOSTarget.empty()) { const Option *O = Opts.getOption(options::OPT_miphoneos_version_min_EQ); iOSVersion = Args.MakeJoinedArg(0, O, iOSTarget); Args.append(iOSVersion); } else if (!iOSSimTarget.empty()) { const Option *O = Opts.getOption( options::OPT_mios_simulator_version_min_EQ); iOSSimVersion = Args.MakeJoinedArg(0, O, iOSSimTarget); Args.append(iOSSimVersion); } else { // Otherwise, assume we are targeting OS X. const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ); OSXVersion = Args.MakeJoinedArg(0, O, MacosxVersionMin); Args.append(OSXVersion); } } // Reject invalid architecture combinations. if (iOSSimVersion && (getTriple().getArch() != llvm::Triple::x86 && getTriple().getArch() != llvm::Triple::x86_64)) { getDriver().Diag(diag::err_drv_invalid_arch_for_deployment_target) << getTriple().getArchName() << iOSSimVersion->getAsString(Args); } // Set the tool chain target information. unsigned Major, Minor, Micro; bool HadExtra; if (OSXVersion) { assert((!iOSVersion && !iOSSimVersion) && "Unknown target platform!"); if (!Driver::GetReleaseVersion(OSXVersion->getValue(Args), Major, Minor, Micro, HadExtra) || HadExtra || Major != 10 || Minor >= 100 || Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) << OSXVersion->getAsString(Args); } else { const Arg *Version = iOSVersion ? iOSVersion : iOSSimVersion; assert(Version && "Unknown target platform!"); if (!Driver::GetReleaseVersion(Version->getValue(Args), Major, Minor, Micro, HadExtra) || HadExtra || Major >= 10 || Minor >= 100 || Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) << Version->getAsString(Args); } bool IsIOSSim = bool(iOSSimVersion); // In GCC, the simulator historically was treated as being OS X in some // contexts, like determining the link logic, despite generally being called // with an iOS deployment target. For compatibility, we detect the // simulator as iOS + x86, and treat it differently in a few contexts. if (iOSVersion && (getTriple().getArch() == llvm::Triple::x86 || getTriple().getArch() == llvm::Triple::x86_64)) IsIOSSim = true; setTarget(/*IsIPhoneOS=*/ !OSXVersion, Major, Minor, Micro, IsIOSSim); } void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { CXXStdlibType Type = GetCXXStdlibType(Args); switch (Type) { case ToolChain::CST_Libcxx: CmdArgs.push_back("-lc++"); break; case ToolChain::CST_Libstdcxx: { // Unfortunately, -lstdc++ doesn't always exist in the standard search path; // it was previously found in the gcc lib dir. However, for all the Darwin // platforms we care about it was -lstdc++.6, so we search for that // explicitly if we can't see an obvious -lstdc++ candidate. // Check in the sysroot first. bool Exists; if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { llvm::sys::Path P(A->getValue(Args)); P.appendComponent("usr"); P.appendComponent("lib"); P.appendComponent("libstdc++.dylib"); if (llvm::sys::fs::exists(P.str(), Exists) || !Exists) { P.eraseComponent(); P.appendComponent("libstdc++.6.dylib"); if (!llvm::sys::fs::exists(P.str(), Exists) && Exists) { CmdArgs.push_back(Args.MakeArgString(P.str())); return; } } } // Otherwise, look in the root. if ((llvm::sys::fs::exists("/usr/lib/libstdc++.dylib", Exists) || !Exists)&& (!llvm::sys::fs::exists("/usr/lib/libstdc++.6.dylib", Exists) && Exists)){ CmdArgs.push_back("/usr/lib/libstdc++.6.dylib"); return; } // Otherwise, let the linker search. CmdArgs.push_back("-lstdc++"); break; } } } void DarwinClang::AddCCKextLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { // For Darwin platforms, use the compiler-rt-based support library // instead of the gcc-provided one (which is also incidentally // only present in the gcc lib dir, which makes it hard to find). llvm::sys::Path P(getDriver().ResourceDir); P.appendComponent("lib"); P.appendComponent("darwin"); P.appendComponent("libclang_rt.cc_kext.a"); // For now, allow missing resource libraries to support developers who may // not have compiler-rt checked out or integrated into their build. bool Exists; if (!llvm::sys::fs::exists(P.str(), Exists) && Exists) CmdArgs.push_back(Args.MakeArgString(P.str())); } DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, const char *BoundArch) const { DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); const OptTable &Opts = getDriver().getOpts(); // FIXME: We really want to get out of the tool chain level argument // translation business, as it makes the driver functionality much // more opaque. For now, we follow gcc closely solely for the // purpose of easily achieving feature parity & testability. Once we // have something that works, we should reevaluate each translation // and try to push it down into tool specific logic. for (ArgList::const_iterator it = Args.begin(), ie = Args.end(); it != ie; ++it) { Arg *A = *it; if (A->getOption().matches(options::OPT_Xarch__)) { // Skip this argument unless the architecture matches either the toolchain // triple arch, or the arch being bound. // // FIXME: Canonicalize name. StringRef XarchArch = A->getValue(Args, 0); if (!(XarchArch == getArchName() || (BoundArch && XarchArch == BoundArch))) continue; Arg *OriginalArg = A; unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(Args, 1)); unsigned Prev = Index; Arg *XarchArg = Opts.ParseOneArg(Args, Index); // If the argument parsing failed or more than one argument was // consumed, the -Xarch_ argument's parameter tried to consume // extra arguments. Emit an error and ignore. // // We also want to disallow any options which would alter the // driver behavior; that isn't going to work in our model. We // use isDriverOption() as an approximation, although things // like -O4 are going to slip through. if (!XarchArg || Index > Prev + 1) { getDriver().Diag(diag::err_drv_invalid_Xarch_argument_with_args) << A->getAsString(Args); continue; } else if (XarchArg->getOption().isDriverOption()) { getDriver().Diag(diag::err_drv_invalid_Xarch_argument_isdriver) << A->getAsString(Args); continue; } XarchArg->setBaseArg(A); A = XarchArg; DAL->AddSynthesizedArg(A); // Linker input arguments require custom handling. The problem is that we // have already constructed the phase actions, so we can not treat them as // "input arguments". if (A->getOption().isLinkerInput()) { // Convert the argument into individual Zlinker_input_args. for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) { DAL->AddSeparateArg(OriginalArg, Opts.getOption(options::OPT_Zlinker_input), A->getValue(Args, i)); } continue; } } // Sob. These is strictly gcc compatible for the time being. Apple // gcc translates options twice, which means that self-expanding // options add duplicates. switch ((options::ID) A->getOption().getID()) { default: DAL->append(A); break; case options::OPT_mkernel: case options::OPT_fapple_kext: DAL->append(A); DAL->AddFlagArg(A, Opts.getOption(options::OPT_static)); break; case options::OPT_dependency_file: DAL->AddSeparateArg(A, Opts.getOption(options::OPT_MF), A->getValue(Args)); break; case options::OPT_gfull: DAL->AddFlagArg(A, Opts.getOption(options::OPT_g_Flag)); DAL->AddFlagArg(A, Opts.getOption(options::OPT_fno_eliminate_unused_debug_symbols)); break; case options::OPT_gused: DAL->AddFlagArg(A, Opts.getOption(options::OPT_g_Flag)); DAL->AddFlagArg(A, Opts.getOption(options::OPT_feliminate_unused_debug_symbols)); break; case options::OPT_shared: DAL->AddFlagArg(A, Opts.getOption(options::OPT_dynamiclib)); break; case options::OPT_fconstant_cfstrings: DAL->AddFlagArg(A, Opts.getOption(options::OPT_mconstant_cfstrings)); break; case options::OPT_fno_constant_cfstrings: DAL->AddFlagArg(A, Opts.getOption(options::OPT_mno_constant_cfstrings)); break; case options::OPT_Wnonportable_cfstrings: DAL->AddFlagArg(A, Opts.getOption(options::OPT_mwarn_nonportable_cfstrings)); break; case options::OPT_Wno_nonportable_cfstrings: DAL->AddFlagArg(A, Opts.getOption(options::OPT_mno_warn_nonportable_cfstrings)); break; case options::OPT_fpascal_strings: DAL->AddFlagArg(A, Opts.getOption(options::OPT_mpascal_strings)); break; case options::OPT_fno_pascal_strings: DAL->AddFlagArg(A, Opts.getOption(options::OPT_mno_pascal_strings)); break; } } if (getTriple().getArch() == llvm::Triple::x86 || getTriple().getArch() == llvm::Triple::x86_64) if (!Args.hasArgNoClaim(options::OPT_mtune_EQ)) DAL->AddJoinedArg(0, Opts.getOption(options::OPT_mtune_EQ), "core2"); // Add the arch options based on the particular spelling of -arch, to match // how the driver driver works. if (BoundArch) { StringRef Name = BoundArch; const Option *MCpu = Opts.getOption(options::OPT_mcpu_EQ); const Option *MArch = Opts.getOption(options::OPT_march_EQ); // This code must be kept in sync with LLVM's getArchTypeForDarwinArch, // which defines the list of which architectures we accept. if (Name == "ppc") ; else if (Name == "ppc601") DAL->AddJoinedArg(0, MCpu, "601"); else if (Name == "ppc603") DAL->AddJoinedArg(0, MCpu, "603"); else if (Name == "ppc604") DAL->AddJoinedArg(0, MCpu, "604"); else if (Name == "ppc604e") DAL->AddJoinedArg(0, MCpu, "604e"); else if (Name == "ppc750") DAL->AddJoinedArg(0, MCpu, "750"); else if (Name == "ppc7400") DAL->AddJoinedArg(0, MCpu, "7400"); else if (Name == "ppc7450") DAL->AddJoinedArg(0, MCpu, "7450"); else if (Name == "ppc970") DAL->AddJoinedArg(0, MCpu, "970"); else if (Name == "ppc64") DAL->AddFlagArg(0, Opts.getOption(options::OPT_m64)); else if (Name == "i386") ; else if (Name == "i486") DAL->AddJoinedArg(0, MArch, "i486"); else if (Name == "i586") DAL->AddJoinedArg(0, MArch, "i586"); else if (Name == "i686") DAL->AddJoinedArg(0, MArch, "i686"); else if (Name == "pentium") DAL->AddJoinedArg(0, MArch, "pentium"); else if (Name == "pentium2") DAL->AddJoinedArg(0, MArch, "pentium2"); else if (Name == "pentpro") DAL->AddJoinedArg(0, MArch, "pentiumpro"); else if (Name == "pentIIm3") DAL->AddJoinedArg(0, MArch, "pentium2"); else if (Name == "x86_64") DAL->AddFlagArg(0, Opts.getOption(options::OPT_m64)); else if (Name == "arm") DAL->AddJoinedArg(0, MArch, "armv4t"); else if (Name == "armv4t") DAL->AddJoinedArg(0, MArch, "armv4t"); else if (Name == "armv5") DAL->AddJoinedArg(0, MArch, "armv5tej"); else if (Name == "xscale") DAL->AddJoinedArg(0, MArch, "xscale"); else if (Name == "armv6") DAL->AddJoinedArg(0, MArch, "armv6k"); else if (Name == "armv7") DAL->AddJoinedArg(0, MArch, "armv7a"); else llvm_unreachable("invalid Darwin arch"); } // Add an explicit version min argument for the deployment target. We do this // after argument translation because -Xarch_ arguments may add a version min // argument. AddDeploymentTarget(*DAL); // Validate the C++ standard library choice. CXXStdlibType Type = GetCXXStdlibType(*DAL); if (Type == ToolChain::CST_Libcxx) { switch (LibCXXForSimulator) { case LibCXXSimulator_None: // Handle non-simulator cases. if (isTargetIPhoneOS()) { if (isIPhoneOSVersionLT(5, 0)) { getDriver().Diag(clang::diag::err_drv_invalid_libcxx_deployment) << "iOS 5.0"; } } break; case LibCXXSimulator_NotAvailable: getDriver().Diag(clang::diag::err_drv_invalid_libcxx_deployment) << "iOS 5.0"; break; case LibCXXSimulator_Available: break; } } return DAL; } bool Darwin::IsUnwindTablesDefault() const { // FIXME: Gross; we should probably have some separate target // definition, possibly even reusing the one in clang. return getArchName() == "x86_64"; } bool Darwin::UseDwarfDebugFlags() const { if (const char *S = ::getenv("RC_DEBUG_OPTIONS")) return S[0] != '\0'; return false; } bool Darwin::UseSjLjExceptions() const { // Darwin uses SjLj exceptions on ARM. return (getTriple().getArch() == llvm::Triple::arm || getTriple().getArch() == llvm::Triple::thumb); } const char *Darwin::GetDefaultRelocationModel() const { return "pic"; } const char *Darwin::GetForcedPicModel() const { if (getArchName() == "x86_64") return "pic"; return 0; } bool Darwin::SupportsProfiling() const { // Profiling instrumentation is only supported on x86. return getArchName() == "i386" || getArchName() == "x86_64"; } bool Darwin::SupportsObjCGC() const { // Garbage collection is supported everywhere except on iPhone OS. return !isTargetIPhoneOS(); } std::string Darwin_Generic_GCC::ComputeEffectiveClangTriple(const ArgList &Args, types::ID InputType) const { return ComputeLLVMTriple(Args, InputType); } /// Generic_GCC - A tool chain using the 'gcc' command to perform /// all subcommands; this relies on gcc translating the majority of /// command line options. Generic_GCC::Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple) : ToolChain(Host, Triple) { getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); } Generic_GCC::~Generic_GCC() { // Free tool implementations. for (llvm::DenseMap::iterator it = Tools.begin(), ie = Tools.end(); it != ie; ++it) delete it->second; } Tool &Generic_GCC::SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const { Action::ActionClass Key; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; else Key = JA.getKind(); Tool *&T = Tools[Key]; if (!T) { switch (Key) { case Action::InputClass: case Action::BindArchClass: llvm_unreachable("Invalid tool kind."); case Action::PreprocessJobClass: T = new tools::gcc::Preprocess(*this); break; case Action::PrecompileJobClass: T = new tools::gcc::Precompile(*this); break; case Action::AnalyzeJobClass: T = new tools::Clang(*this); break; case Action::CompileJobClass: T = new tools::gcc::Compile(*this); break; case Action::AssembleJobClass: T = new tools::gcc::Assemble(*this); break; case Action::LinkJobClass: T = new tools::gcc::Link(*this); break; // This is a bit ungeneric, but the only platform using a driver // driver is Darwin. case Action::LipoJobClass: T = new tools::darwin::Lipo(*this); break; case Action::DsymutilJobClass: T = new tools::darwin::Dsymutil(*this); break; case Action::VerifyJobClass: T = new tools::darwin::VerifyDebug(*this); break; } } return *T; } bool Generic_GCC::IsUnwindTablesDefault() const { // FIXME: Gross; we should probably have some separate target // definition, possibly even reusing the one in clang. return getArchName() == "x86_64"; } const char *Generic_GCC::GetDefaultRelocationModel() const { return "static"; } const char *Generic_GCC::GetForcedPicModel() const { return 0; } /// TCEToolChain - A tool chain using the llvm bitcode tools to perform /// all subcommands. See http://tce.cs.tut.fi for our peculiar target. /// Currently does not support anything else but compilation. TCEToolChain::TCEToolChain(const HostInfo &Host, const llvm::Triple& Triple) : ToolChain(Host, Triple) { // Path mangling to find libexec std::string Path(getDriver().Dir); Path += "/../libexec"; getProgramPaths().push_back(Path); } TCEToolChain::~TCEToolChain() { for (llvm::DenseMap::iterator it = Tools.begin(), ie = Tools.end(); it != ie; ++it) delete it->second; } bool TCEToolChain::IsMathErrnoDefault() const { return true; } bool TCEToolChain::IsUnwindTablesDefault() const { return false; } const char *TCEToolChain::GetDefaultRelocationModel() const { return "static"; } const char *TCEToolChain::GetForcedPicModel() const { return 0; } Tool &TCEToolChain::SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const { Action::ActionClass Key; Key = Action::AnalyzeJobClass; Tool *&T = Tools[Key]; if (!T) { switch (Key) { case Action::PreprocessJobClass: T = new tools::gcc::Preprocess(*this); break; case Action::AnalyzeJobClass: T = new tools::Clang(*this); break; default: llvm_unreachable("Unsupported action for TCE target."); } } return *T; } /// OpenBSD - OpenBSD tool chain which can call as(1) and ld(1) directly. OpenBSD::OpenBSD(const HostInfo &Host, const llvm::Triple& Triple) : Generic_ELF(Host, Triple) { getFilePaths().push_back(getDriver().Dir + "/../lib"); getFilePaths().push_back("/usr/lib"); } Tool &OpenBSD::SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const { Action::ActionClass Key; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; else Key = JA.getKind(); bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, options::OPT_no_integrated_as, IsIntegratedAssemblerDefault()); Tool *&T = Tools[Key]; if (!T) { switch (Key) { case Action::AssembleJobClass: { if (UseIntegratedAs) T = new tools::ClangAs(*this); else T = new tools::openbsd::Assemble(*this); break; } case Action::LinkJobClass: T = new tools::openbsd::Link(*this); break; default: T = &Generic_GCC::SelectTool(C, JA, Inputs); } } return *T; } /// FreeBSD - FreeBSD tool chain which can call as(1) and ld(1) directly. FreeBSD::FreeBSD(const HostInfo &Host, const llvm::Triple& Triple) : Generic_ELF(Host, Triple) { // Determine if we are compiling 32-bit code on an x86_64 platform. bool Lib32 = false; if (Triple.getArch() == llvm::Triple::x86 && llvm::Triple(getDriver().DefaultHostTriple).getArch() == llvm::Triple::x86_64) Lib32 = true; if (Triple.getArch() == llvm::Triple::ppc && llvm::Triple(getDriver().DefaultHostTriple).getArch() == llvm::Triple::ppc64) Lib32 = true; if (Lib32) { getFilePaths().push_back(CLANG_PREFIX "/usr/lib32"); } else { getFilePaths().push_back(CLANG_PREFIX "/usr/lib"); } } Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const { Action::ActionClass Key; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; else Key = JA.getKind(); bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, options::OPT_no_integrated_as, IsIntegratedAssemblerDefault()); Tool *&T = Tools[Key]; if (!T) { switch (Key) { case Action::AssembleJobClass: if (UseIntegratedAs) T = new tools::ClangAs(*this); else T = new tools::freebsd::Assemble(*this); break; case Action::LinkJobClass: T = new tools::freebsd::Link(*this); break; default: T = &Generic_GCC::SelectTool(C, JA, Inputs); } } return *T; } /// NetBSD - NetBSD tool chain which can call as(1) and ld(1) directly. NetBSD::NetBSD(const HostInfo &Host, const llvm::Triple& Triple, const llvm::Triple& ToolTriple) : Generic_ELF(Host, Triple), ToolTriple(ToolTriple) { // Determine if we are compiling 32-bit code on an x86_64 platform. bool Lib32 = false; if (ToolTriple.getArch() == llvm::Triple::x86_64 && Triple.getArch() == llvm::Triple::x86) Lib32 = true; if (getDriver().UseStdLib) { if (Lib32) getFilePaths().push_back("=/usr/lib/i386"); else getFilePaths().push_back("=/usr/lib"); } } Tool &NetBSD::SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const { Action::ActionClass Key; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; else Key = JA.getKind(); bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, options::OPT_no_integrated_as, IsIntegratedAssemblerDefault()); Tool *&T = Tools[Key]; if (!T) { switch (Key) { case Action::AssembleJobClass: if (UseIntegratedAs) T = new tools::ClangAs(*this); else T = new tools::netbsd::Assemble(*this, ToolTriple); break; case Action::LinkJobClass: T = new tools::netbsd::Link(*this, ToolTriple); break; default: T = &Generic_GCC::SelectTool(C, JA, Inputs); } } return *T; } /// Minix - Minix tool chain which can call as(1) and ld(1) directly. Minix::Minix(const HostInfo &Host, const llvm::Triple& Triple) : Generic_GCC(Host, Triple) { getFilePaths().push_back(getDriver().Dir + "/../lib"); getFilePaths().push_back("/usr/lib"); getFilePaths().push_back("/usr/gnu/lib"); getFilePaths().push_back("/usr/gnu/lib/gcc/i686-pc-minix/4.4.3"); } Tool &Minix::SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const { Action::ActionClass Key; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; else Key = JA.getKind(); Tool *&T = Tools[Key]; if (!T) { switch (Key) { case Action::AssembleJobClass: T = new tools::minix::Assemble(*this); break; case Action::LinkJobClass: T = new tools::minix::Link(*this); break; default: T = &Generic_GCC::SelectTool(C, JA, Inputs); } } return *T; } /// AuroraUX - AuroraUX tool chain which can call as(1) and ld(1) directly. AuroraUX::AuroraUX(const HostInfo &Host, const llvm::Triple& Triple) : Generic_GCC(Host, Triple) { getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); getFilePaths().push_back(getDriver().Dir + "/../lib"); getFilePaths().push_back("/usr/lib"); getFilePaths().push_back("/usr/sfw/lib"); getFilePaths().push_back("/opt/gcc4/lib"); getFilePaths().push_back("/opt/gcc4/lib/gcc/i386-pc-solaris2.11/4.2.4"); } Tool &AuroraUX::SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const { Action::ActionClass Key; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; else Key = JA.getKind(); Tool *&T = Tools[Key]; if (!T) { switch (Key) { case Action::AssembleJobClass: T = new tools::auroraux::Assemble(*this); break; case Action::LinkJobClass: T = new tools::auroraux::Link(*this); break; default: T = &Generic_GCC::SelectTool(C, JA, Inputs); } } return *T; } /// Linux toolchain (very bare-bones at the moment). enum LinuxDistro { ArchLinux, DebianLenny, DebianSqueeze, DebianWheezy, Exherbo, RHEL4, RHEL5, RHEL6, Fedora13, Fedora14, Fedora15, FedoraRawhide, OpenSuse11_3, OpenSuse11_4, OpenSuse12_1, UbuntuHardy, UbuntuIntrepid, UbuntuJaunty, UbuntuKarmic, UbuntuLucid, UbuntuMaverick, UbuntuNatty, UbuntuOneiric, UnknownDistro }; static bool IsRedhat(enum LinuxDistro Distro) { return Distro == Fedora13 || Distro == Fedora14 || Distro == Fedora15 || Distro == FedoraRawhide || Distro == RHEL4 || Distro == RHEL5 || Distro == RHEL6; } static bool IsOpenSuse(enum LinuxDistro Distro) { return Distro == OpenSuse11_3 || Distro == OpenSuse11_4 || Distro == OpenSuse12_1; } static bool IsDebian(enum LinuxDistro Distro) { return Distro == DebianLenny || Distro == DebianSqueeze || Distro == DebianWheezy; } static bool IsUbuntu(enum LinuxDistro Distro) { return Distro == UbuntuHardy || Distro == UbuntuIntrepid || Distro == UbuntuLucid || Distro == UbuntuMaverick || Distro == UbuntuJaunty || Distro == UbuntuKarmic || Distro == UbuntuNatty || Distro == UbuntuOneiric; } -// FIXME: This should be deleted. We should assume a multilib environment, and -// fallback gracefully if any parts of it are absent. -static bool HasMultilib(llvm::Triple::ArchType Arch, enum LinuxDistro Distro) { - if (Arch == llvm::Triple::x86_64) { - bool Exists; - if (Distro == Exherbo && - (llvm::sys::fs::exists("/usr/lib32/libc.so", Exists) || !Exists)) - return false; - } - - return true; -} - static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) { llvm::OwningPtr File; if (!llvm::MemoryBuffer::getFile("/etc/lsb-release", File)) { StringRef Data = File.get()->getBuffer(); SmallVector Lines; Data.split(Lines, "\n"); for (unsigned int i = 0, s = Lines.size(); i < s; ++ i) { if (Lines[i] == "DISTRIB_CODENAME=hardy") return UbuntuHardy; else if (Lines[i] == "DISTRIB_CODENAME=intrepid") return UbuntuIntrepid; else if (Lines[i] == "DISTRIB_CODENAME=jaunty") return UbuntuJaunty; else if (Lines[i] == "DISTRIB_CODENAME=karmic") return UbuntuKarmic; else if (Lines[i] == "DISTRIB_CODENAME=lucid") return UbuntuLucid; else if (Lines[i] == "DISTRIB_CODENAME=maverick") return UbuntuMaverick; else if (Lines[i] == "DISTRIB_CODENAME=natty") return UbuntuNatty; else if (Lines[i] == "DISTRIB_CODENAME=oneiric") return UbuntuOneiric; } return UnknownDistro; } if (!llvm::MemoryBuffer::getFile("/etc/redhat-release", File)) { StringRef Data = File.get()->getBuffer(); if (Data.startswith("Fedora release 15")) return Fedora15; else if (Data.startswith("Fedora release 14")) return Fedora14; else if (Data.startswith("Fedora release 13")) return Fedora13; else if (Data.startswith("Fedora release") && Data.find("Rawhide") != StringRef::npos) return FedoraRawhide; else if (Data.startswith("Red Hat Enterprise Linux") && Data.find("release 6") != StringRef::npos) return RHEL6; else if ((Data.startswith("Red Hat Enterprise Linux") || Data.startswith("CentOS")) && Data.find("release 5") != StringRef::npos) return RHEL5; else if ((Data.startswith("Red Hat Enterprise Linux") || Data.startswith("CentOS")) && Data.find("release 4") != StringRef::npos) return RHEL4; return UnknownDistro; } if (!llvm::MemoryBuffer::getFile("/etc/debian_version", File)) { StringRef Data = File.get()->getBuffer(); if (Data[0] == '5') return DebianLenny; else if (Data.startswith("squeeze/sid")) return DebianSqueeze; else if (Data.startswith("wheezy/sid")) return DebianWheezy; return UnknownDistro; } if (!llvm::MemoryBuffer::getFile("/etc/SuSE-release", File)) { StringRef Data = File.get()->getBuffer(); if (Data.startswith("openSUSE 11.3")) return OpenSuse11_3; else if (Data.startswith("openSUSE 11.4")) return OpenSuse11_4; else if (Data.startswith("openSUSE 12.1")) return OpenSuse12_1; return UnknownDistro; } bool Exists; if (!llvm::sys::fs::exists("/etc/exherbo-release", Exists) && Exists) return Exherbo; if (!llvm::sys::fs::exists("/etc/arch-release", Exists) && Exists) return ArchLinux; return UnknownDistro; } -/// \brief Trivial helper function to simplify code checking path existence. -static bool PathExists(StringRef Path) { - bool Exists; - if (!llvm::sys::fs::exists(Path, Exists)) - return Exists; - return false; -} - -namespace { -/// \brief This is a class to find a viable GCC installation for Clang to use. +/// \brief Parse a GCCVersion object out of a string of text. /// -/// This class tries to find a GCC installation on the system, and report -/// information about it. It starts from the host information provided to the -/// Driver, and has logic for fuzzing that where appropriate. -class GCCInstallationDetector { - /// \brief Struct to store and manipulate GCC versions. - /// - /// We rely on assumptions about the form and structure of GCC version - /// numbers: they consist of at most three '.'-separated components, and each - /// component is a non-negative integer. - struct GCCVersion { - unsigned Major, Minor, Patch; +/// This is the primary means of forming GCCVersion objects. +/*static*/ Linux::GCCVersion Linux::GCCVersion::Parse(StringRef VersionText) { + const GCCVersion BadVersion = { VersionText.str(), -1, -1, -1, "" }; + std::pair First = VersionText.split('.'); + std::pair Second = First.second.split('.'); - static GCCVersion Parse(StringRef VersionText) { - const GCCVersion BadVersion = {0, 0, 0}; - std::pair First = VersionText.split('.'); - std::pair Second = First.second.split('.'); + GCCVersion GoodVersion = { VersionText.str(), -1, -1, -1, "" }; + if (First.first.getAsInteger(10, GoodVersion.Major) || + GoodVersion.Major < 0) + return BadVersion; + if (Second.first.getAsInteger(10, GoodVersion.Minor) || + GoodVersion.Minor < 0) + return BadVersion; - GCCVersion GoodVersion = {0, 0, 0}; - if (First.first.getAsInteger(10, GoodVersion.Major)) + // First look for a number prefix and parse that if present. Otherwise just + // stash the entire patch string in the suffix, and leave the number + // unspecified. This covers versions strings such as: + // 4.4 + // 4.4.0 + // 4.4.x + // 4.4.2-rc4 + // 4.4.x-patched + // And retains any patch number it finds. + StringRef PatchText = GoodVersion.PatchSuffix = Second.second.str(); + if (!PatchText.empty()) { + if (unsigned EndNumber = PatchText.find_first_not_of("0123456789")) { + // Try to parse the number and any suffix. + if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) || + GoodVersion.Patch < 0) return BadVersion; - if (Second.first.getAsInteger(10, GoodVersion.Minor)) - return BadVersion; - // We accept a number, or a string for the patch version, in case there - // is a strang suffix, or other mangling: '4.1.x', '4.1.2-rc3'. When it - // isn't a number, we just use '0' as the number but accept it. - if (Second.first.getAsInteger(10, GoodVersion.Patch)) - GoodVersion.Patch = 0; - return GoodVersion; + GoodVersion.PatchSuffix = PatchText.substr(EndNumber).str(); } + } - bool operator<(const GCCVersion &RHS) const { - if (Major < RHS.Major) return true; - if (Major > RHS.Major) return false; - if (Minor < RHS.Minor) return true; - if (Minor > RHS.Minor) return false; - return Patch < RHS.Patch; - } - bool operator>(const GCCVersion &RHS) const { return RHS < *this; } - bool operator<=(const GCCVersion &RHS) const { return !(*this > RHS); } - bool operator>=(const GCCVersion &RHS) const { return !(*this < RHS); } - }; + return GoodVersion; +} - bool IsValid; - std::string GccTriple; +/// \brief Less-than for GCCVersion, implementing a Strict Weak Ordering. +bool Linux::GCCVersion::operator<(const GCCVersion &RHS) const { + if (Major < RHS.Major) return true; if (Major > RHS.Major) return false; + if (Minor < RHS.Minor) return true; if (Minor > RHS.Minor) return false; - // FIXME: These might be better as path objects. - std::string GccInstallPath; - std::string GccParentLibPath; + // Note that we rank versions with *no* patch specified is better than ones + // hard-coding a patch version. Thus if the RHS has no patch, it always + // wins, and the LHS only wins if it has no patch and the RHS does have + // a patch. + if (RHS.Patch == -1) return true; if (Patch == -1) return false; + if (Patch < RHS.Patch) return true; if (Patch > RHS.Patch) return false; - llvm::SmallString<128> CxxIncludeRoot; + // Finally, between completely tied version numbers, the version with the + // suffix loses as we prefer full releases. + if (RHS.PatchSuffix.empty()) return true; + return false; +} -public: - /// \brief Construct a GCCInstallationDetector from the driver. - /// - /// This performs all of the autodetection and sets up the various paths. - /// Once constructed, a GCCInstallation is esentially immutable. - GCCInstallationDetector(const Driver &D) - : IsValid(false), - GccTriple(D.DefaultHostTriple), - CxxIncludeRoot(CXX_INCLUDE_ROOT) { - // FIXME: Using CXX_INCLUDE_ROOT is here is a bit of a hack, but - // avoids adding yet another option to configure/cmake. - // It would probably be cleaner to break it in two variables - // CXX_GCC_ROOT with just /foo/bar - // CXX_GCC_VER with 4.5.2 - // Then we would have - // CXX_INCLUDE_ROOT = CXX_GCC_ROOT/include/c++/CXX_GCC_VER - // and this function would return - // CXX_GCC_ROOT/lib/gcc/CXX_INCLUDE_ARCH/CXX_GCC_VER - if (CxxIncludeRoot != "") { - // This is of the form /foo/bar/include/c++/4.5.2/ - if (CxxIncludeRoot.back() == '/') - llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the / - StringRef Version = llvm::sys::path::filename(CxxIncludeRoot); - llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the version - llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the c++ - llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the include - GccInstallPath = CxxIncludeRoot.str(); - GccInstallPath.append("/lib/gcc/"); - GccInstallPath.append(CXX_INCLUDE_ARCH); - GccInstallPath.append("/"); - GccInstallPath.append(Version); - GccParentLibPath = GccInstallPath + "/../../.."; - IsValid = true; - return; - } +/// \brief Construct a GCCInstallationDetector from the driver. +/// +/// This performs all of the autodetection and sets up the various paths. +/// Once constructed, a GCCInstallation is esentially immutable. +Linux::GCCInstallationDetector::GCCInstallationDetector(const Driver &D) + : IsValid(false), + GccTriple(D.DefaultHostTriple) { + // FIXME: Using CXX_INCLUDE_ROOT is here is a bit of a hack, but + // avoids adding yet another option to configure/cmake. + // It would probably be cleaner to break it in two variables + // CXX_GCC_ROOT with just /foo/bar + // CXX_GCC_VER with 4.5.2 + // Then we would have + // CXX_INCLUDE_ROOT = CXX_GCC_ROOT/include/c++/CXX_GCC_VER + // and this function would return + // CXX_GCC_ROOT/lib/gcc/CXX_INCLUDE_ARCH/CXX_GCC_VER + llvm::SmallString<128> CxxIncludeRoot(CXX_INCLUDE_ROOT); + if (CxxIncludeRoot != "") { + // This is of the form /foo/bar/include/c++/4.5.2/ + if (CxxIncludeRoot.back() == '/') + llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the / + StringRef Version = llvm::sys::path::filename(CxxIncludeRoot); + llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the version + llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the c++ + llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the include + GccInstallPath = CxxIncludeRoot.str(); + GccInstallPath.append("/lib/gcc/"); + GccInstallPath.append(CXX_INCLUDE_ARCH); + GccInstallPath.append("/"); + GccInstallPath.append(Version); + GccParentLibPath = GccInstallPath + "/../../.."; + IsValid = true; + return; + } - llvm::Triple::ArchType HostArch = llvm::Triple(GccTriple).getArch(); - // The library directories which may contain GCC installations. - SmallVector CandidateLibDirs; - // The compatible GCC triples for this particular architecture. - SmallVector CandidateTriples; - CollectLibDirsAndTriples(HostArch, CandidateLibDirs, CandidateTriples); + llvm::Triple::ArchType HostArch = llvm::Triple(GccTriple).getArch(); + // The library directories which may contain GCC installations. + SmallVector CandidateLibDirs; + // The compatible GCC triples for this particular architecture. + SmallVector CandidateTriples; + CollectLibDirsAndTriples(HostArch, CandidateLibDirs, CandidateTriples); - // Always include the default host triple as the final fallback if no - // specific triple is detected. - CandidateTriples.push_back(D.DefaultHostTriple); + // Always include the default host triple as the final fallback if no + // specific triple is detected. + CandidateTriples.push_back(D.DefaultHostTriple); - // Compute the set of prefixes for our search. - SmallVector Prefixes(D.PrefixDirs.begin(), - D.PrefixDirs.end()); - Prefixes.push_back(D.SysRoot); - Prefixes.push_back(D.SysRoot + "/usr"); - Prefixes.push_back(D.InstalledDir + "/.."); + // Compute the set of prefixes for our search. + SmallVector Prefixes(D.PrefixDirs.begin(), + D.PrefixDirs.end()); + Prefixes.push_back(D.SysRoot); + Prefixes.push_back(D.SysRoot + "/usr"); + Prefixes.push_back(D.InstalledDir + "/.."); - // Loop over the various components which exist and select the best GCC - // installation available. GCC installs are ranked by version number. - GCCVersion BestVersion = {0, 0, 0}; - for (unsigned i = 0, ie = Prefixes.size(); i < ie; ++i) { - if (!PathExists(Prefixes[i])) + // Loop over the various components which exist and select the best GCC + // installation available. GCC installs are ranked by version number. + Version = GCCVersion::Parse("0.0.0"); + for (unsigned i = 0, ie = Prefixes.size(); i < ie; ++i) { + if (!llvm::sys::fs::exists(Prefixes[i])) + continue; + for (unsigned j = 0, je = CandidateLibDirs.size(); j < je; ++j) { + const std::string LibDir = Prefixes[i] + CandidateLibDirs[j].str(); + if (!llvm::sys::fs::exists(LibDir)) continue; - for (unsigned j = 0, je = CandidateLibDirs.size(); j < je; ++j) { - const std::string LibDir = Prefixes[i] + CandidateLibDirs[j].str(); - if (!PathExists(LibDir)) - continue; - for (unsigned k = 0, ke = CandidateTriples.size(); k < ke; ++k) - ScanLibDirForGCCTriple(LibDir, CandidateTriples[k], BestVersion); - } + for (unsigned k = 0, ke = CandidateTriples.size(); k < ke; ++k) + ScanLibDirForGCCTriple(HostArch, LibDir, CandidateTriples[k]); } } +} - /// \brief Check whether we detected a valid GCC install. - bool isValid() const { return IsValid; } +/*static*/ void Linux::GCCInstallationDetector::CollectLibDirsAndTriples( + llvm::Triple::ArchType HostArch, SmallVectorImpl &LibDirs, + SmallVectorImpl &Triples) { + if (HostArch == llvm::Triple::arm || HostArch == llvm::Triple::thumb) { + static const char *const ARMLibDirs[] = { "/lib" }; + static const char *const ARMTriples[] = { "arm-linux-gnueabi" }; + LibDirs.append(ARMLibDirs, ARMLibDirs + llvm::array_lengthof(ARMLibDirs)); + Triples.append(ARMTriples, ARMTriples + llvm::array_lengthof(ARMTriples)); + } else if (HostArch == llvm::Triple::x86_64) { + static const char *const X86_64LibDirs[] = { "/lib64", "/lib" }; + static const char *const X86_64Triples[] = { + "x86_64-linux-gnu", + "x86_64-unknown-linux-gnu", + "x86_64-pc-linux-gnu", + "x86_64-redhat-linux6E", + "x86_64-redhat-linux", + "x86_64-suse-linux", + "x86_64-manbo-linux-gnu", + "x86_64-linux-gnu", + "x86_64-slackware-linux" + }; + LibDirs.append(X86_64LibDirs, + X86_64LibDirs + llvm::array_lengthof(X86_64LibDirs)); + Triples.append(X86_64Triples, + X86_64Triples + llvm::array_lengthof(X86_64Triples)); + } else if (HostArch == llvm::Triple::x86) { + static const char *const X86LibDirs[] = { "/lib32", "/lib" }; + static const char *const X86Triples[] = { + "i686-linux-gnu", + "i686-pc-linux-gnu", + "i486-linux-gnu", + "i386-linux-gnu", + "i686-redhat-linux", + "i586-redhat-linux", + "i386-redhat-linux", + "i586-suse-linux", + "i486-slackware-linux" + }; + LibDirs.append(X86LibDirs, X86LibDirs + llvm::array_lengthof(X86LibDirs)); + Triples.append(X86Triples, X86Triples + llvm::array_lengthof(X86Triples)); + } else if (HostArch == llvm::Triple::ppc) { + static const char *const PPCLibDirs[] = { "/lib32", "/lib" }; + static const char *const PPCTriples[] = { + "powerpc-linux-gnu", + "powerpc-unknown-linux-gnu" + }; + LibDirs.append(PPCLibDirs, PPCLibDirs + llvm::array_lengthof(PPCLibDirs)); + Triples.append(PPCTriples, PPCTriples + llvm::array_lengthof(PPCTriples)); + } else if (HostArch == llvm::Triple::ppc64) { + static const char *const PPC64LibDirs[] = { "/lib64", "/lib" }; + static const char *const PPC64Triples[] = { + "powerpc64-unknown-linux-gnu" + }; + LibDirs.append(PPC64LibDirs, + PPC64LibDirs + llvm::array_lengthof(PPC64LibDirs)); + Triples.append(PPC64Triples, + PPC64Triples + llvm::array_lengthof(PPC64Triples)); + } +} - /// \brief Get the GCC triple for the detected install. - const std::string &getTriple() const { return GccTriple; } +void Linux::GCCInstallationDetector::ScanLibDirForGCCTriple( + llvm::Triple::ArchType HostArch, const std::string &LibDir, + StringRef CandidateTriple) { + // There are various different suffixes involving the triple we + // check for. We also record what is necessary to walk from each back + // up to the lib directory. + const std::string Suffixes[] = { + "/gcc/" + CandidateTriple.str(), + "/" + CandidateTriple.str() + "/gcc/" + CandidateTriple.str(), - /// \brief Get the detected GCC installation path. - const std::string &getInstallPath() const { return GccInstallPath; } + // Ubuntu has a strange mis-matched pair of triples that this happens to + // match. + // FIXME: It may be worthwhile to generalize this and look for a second + // triple. + "/i386-linux-gnu/gcc/" + CandidateTriple.str() + }; + const std::string InstallSuffixes[] = { + "/../../..", + "/../../../..", + "/../../../.." + }; + // Only look at the final, weird Ubuntu suffix for i386-linux-gnu. + const unsigned NumSuffixes = (llvm::array_lengthof(Suffixes) - + (HostArch != llvm::Triple::x86)); + for (unsigned i = 0; i < NumSuffixes; ++i) { + StringRef Suffix = Suffixes[i]; + llvm::error_code EC; + for (llvm::sys::fs::directory_iterator LI(LibDir + Suffix, EC), LE; + !EC && LI != LE; LI = LI.increment(EC)) { + StringRef VersionText = llvm::sys::path::filename(LI->path()); + GCCVersion CandidateVersion = GCCVersion::Parse(VersionText); + static const GCCVersion MinVersion = { "4.1.1", 4, 1, 1, "" }; + if (CandidateVersion < MinVersion) + continue; + if (CandidateVersion <= Version) + continue; + if (!llvm::sys::fs::exists(LI->path() + "/crtbegin.o")) + continue; - /// \brief Get the detected GCC parent lib path. - const std::string &getParentLibPath() const { return GccParentLibPath; } - -private: - static void CollectLibDirsAndTriples(llvm::Triple::ArchType HostArch, - SmallVectorImpl &LibDirs, - SmallVectorImpl &Triples) { - if (HostArch == llvm::Triple::arm || HostArch == llvm::Triple::thumb) { - static const char *const ARMLibDirs[] = { "/lib" }; - static const char *const ARMTriples[] = { "arm-linux-gnueabi" }; - LibDirs.append(ARMLibDirs, ARMLibDirs + llvm::array_lengthof(ARMLibDirs)); - Triples.append(ARMTriples, ARMTriples + llvm::array_lengthof(ARMTriples)); - } else if (HostArch == llvm::Triple::x86_64) { - static const char *const X86_64LibDirs[] = { "/lib64", "/lib" }; - static const char *const X86_64Triples[] = { - "x86_64-linux-gnu", - "x86_64-unknown-linux-gnu", - "x86_64-pc-linux-gnu", - "x86_64-redhat-linux6E", - "x86_64-redhat-linux", - "x86_64-suse-linux", - "x86_64-manbo-linux-gnu", - "x86_64-linux-gnu", - "x86_64-slackware-linux" - }; - LibDirs.append(X86_64LibDirs, - X86_64LibDirs + llvm::array_lengthof(X86_64LibDirs)); - Triples.append(X86_64Triples, - X86_64Triples + llvm::array_lengthof(X86_64Triples)); - } else if (HostArch == llvm::Triple::x86) { - static const char *const X86LibDirs[] = { "/lib32", "/lib" }; - static const char *const X86Triples[] = { - "i686-linux-gnu", - "i386-linux-gnu", - "i686-pc-linux-gnu", - "i486-linux-gnu", - "i686-redhat-linux", - "i386-redhat-linux", - "i586-suse-linux", - "i486-slackware-linux" - }; - LibDirs.append(X86LibDirs, X86LibDirs + llvm::array_lengthof(X86LibDirs)); - Triples.append(X86Triples, X86Triples + llvm::array_lengthof(X86Triples)); - } else if (HostArch == llvm::Triple::ppc) { - static const char *const PPCLibDirs[] = { "/lib32", "/lib" }; - static const char *const PPCTriples[] = { - "powerpc-linux-gnu", - "powerpc-unknown-linux-gnu" - }; - LibDirs.append(PPCLibDirs, PPCLibDirs + llvm::array_lengthof(PPCLibDirs)); - Triples.append(PPCTriples, PPCTriples + llvm::array_lengthof(PPCTriples)); - } else if (HostArch == llvm::Triple::ppc64) { - static const char *const PPC64LibDirs[] = { "/lib64", "/lib" }; - static const char *const PPC64Triples[] = { - "powerpc64-unknown-linux-gnu" - }; - LibDirs.append(PPC64LibDirs, - PPC64LibDirs + llvm::array_lengthof(PPC64LibDirs)); - Triples.append(PPC64Triples, - PPC64Triples + llvm::array_lengthof(PPC64Triples)); + Version = CandidateVersion; + GccTriple = CandidateTriple.str(); + // FIXME: We hack together the directory name here instead of + // using LI to ensure stable path separators across Windows and + // Linux. + GccInstallPath = LibDir + Suffixes[i] + "/" + VersionText.str(); + GccParentLibPath = GccInstallPath + InstallSuffixes[i]; + IsValid = true; } } +} - void ScanLibDirForGCCTriple(const std::string &LibDir, - StringRef CandidateTriple, - GCCVersion &BestVersion) { - // There are various different suffixes involving the triple we - // check for. We also record what is necessary to walk from each back - // up to the lib directory. - const std::string Suffixes[] = { - "/gcc/" + CandidateTriple.str(), - "/" + CandidateTriple.str() + "/gcc/" + CandidateTriple.str(), +static void addPathIfExists(Twine Path, ToolChain::path_list &Paths) { + if (llvm::sys::fs::exists(Path)) Paths.push_back(Path.str()); +} - // Ubuntu has a strange mis-matched pair of triples that this happens to - // match. - // FIXME: It may be worthwhile to generalize this and look for a second - // triple. - "/" + CandidateTriple.str() + "/gcc/i686-linux-gnu" - }; - const std::string InstallSuffixes[] = { - "/../../..", - "/../../../..", - "/../../../.." - }; - // Only look at the final, weird Ubuntu suffix for i386-linux-gnu. - const unsigned NumSuffixes = (llvm::array_lengthof(Suffixes) - - (CandidateTriple != "i386-linux-gnu")); - for (unsigned i = 0; i < NumSuffixes; ++i) { - StringRef Suffix = Suffixes[i]; - llvm::error_code EC; - for (llvm::sys::fs::directory_iterator LI(LibDir + Suffix, EC), LE; - !EC && LI != LE; LI = LI.increment(EC)) { - StringRef VersionText = llvm::sys::path::filename(LI->path()); - GCCVersion CandidateVersion = GCCVersion::Parse(VersionText); - static const GCCVersion MinVersion = { 4, 1, 1 }; - if (CandidateVersion < MinVersion) - continue; - if (CandidateVersion <= BestVersion) - continue; - if (!PathExists(LI->path() + "/crtbegin.o")) - continue; +/// \brief Get our best guess at the multiarch triple for a target. +/// +/// Debian-based systems are starting to use a multiarch setup where they use +/// a target-triple directory in the library and header search paths. +/// Unfortunately, this triple does not align with the vanilla target triple, +/// so we provide a rough mapping here. +static std::string getMultiarchTriple(const llvm::Triple TargetTriple, + StringRef SysRoot) { + // For most architectures, just use whatever we have rather than trying to be + // clever. + switch (TargetTriple.getArch()) { + default: + return TargetTriple.str(); - BestVersion = CandidateVersion; - GccTriple = CandidateTriple.str(); - // FIXME: We hack together the directory name here instead of - // using LI to ensure stable path separators across Windows and - // Linux. - GccInstallPath = LibDir + Suffixes[i] + "/" + VersionText.str(); - GccParentLibPath = GccInstallPath + InstallSuffixes[i]; - IsValid = true; - } - } + // We use the existence of '/lib/' as a directory to detect some + // common linux triples that don't quite match the Clang triple for both + // 32-bit and 64-bit targets. This works around annoying discrepancies on + // Debian-based systems. + case llvm::Triple::x86: + if (llvm::sys::fs::exists(SysRoot + "/lib/i686-linux-gnu")) + return "i686-linux-gnu"; + if (llvm::sys::fs::exists(SysRoot + "/lib/i386-linux-gnu")) + return "i386-linux-gnu"; + return TargetTriple.str(); + case llvm::Triple::x86_64: + if (llvm::sys::fs::exists(SysRoot + "/lib/x86_64-linux-gnu")) + return "x86_64-linux-gnu"; + if (llvm::sys::fs::exists(SysRoot + "/lib/x86_64-pc-linux-gnu")) + return "x86_64-pc-linux-gnu"; + if (llvm::sys::fs::exists(SysRoot + "/lib/x86_64-unknown-linux-gnu")) + return "x86_64-unknown-linux-gnu"; + return TargetTriple.str(); } -}; } -static void addPathIfExists(const std::string &Path, - ToolChain::path_list &Paths) { - if (PathExists(Path)) Paths.push_back(Path); -} - Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple) - : Generic_ELF(Host, Triple) { + : Generic_ELF(Host, Triple), GCCInstallation(getDriver()) { llvm::Triple::ArchType Arch = llvm::Triple(getDriver().DefaultHostTriple).getArch(); const std::string &SysRoot = getDriver().SysRoot; - GCCInstallationDetector GCCInstallation(getDriver()); // OpenSuse stores the linker with the compiler, add that to the search // path. ToolChain::path_list &PPaths = getProgramPaths(); - PPaths.push_back(GCCInstallation.getParentLibPath() + "/../" + - GCCInstallation.getTriple() + "/bin"); + PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" + + GCCInstallation.getTriple() + "/bin").str()); Linker = GetProgramPath("ld"); LinuxDistro Distro = DetectLinuxDistro(Arch); if (IsOpenSuse(Distro) || IsUbuntu(Distro)) { ExtraOpts.push_back("-z"); ExtraOpts.push_back("relro"); } if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb) ExtraOpts.push_back("-X"); if (IsRedhat(Distro) || IsOpenSuse(Distro) || Distro == UbuntuMaverick || Distro == UbuntuNatty || Distro == UbuntuOneiric) ExtraOpts.push_back("--hash-style=gnu"); if (IsDebian(Distro) || IsOpenSuse(Distro) || Distro == UbuntuLucid || Distro == UbuntuJaunty || Distro == UbuntuKarmic) ExtraOpts.push_back("--hash-style=both"); if (IsRedhat(Distro)) ExtraOpts.push_back("--no-add-needed"); if (Distro == DebianSqueeze || Distro == DebianWheezy || IsOpenSuse(Distro) || (IsRedhat(Distro) && Distro != RHEL4 && Distro != RHEL5) || Distro == UbuntuLucid || Distro == UbuntuMaverick || Distro == UbuntuKarmic || Distro == UbuntuNatty || Distro == UbuntuOneiric) ExtraOpts.push_back("--build-id"); if (IsOpenSuse(Distro)) ExtraOpts.push_back("--enable-new-dtags"); // The selection of paths to try here is designed to match the patterns which // the GCC driver itself uses, as this is part of the GCC-compatible driver. // This was determined by running GCC in a fake filesystem, creating all // possible permutations of these directories, and seeing which ones it added // to the link paths. path_list &Paths = getFilePaths(); const bool Is32Bits = (getArch() == llvm::Triple::x86 || getArch() == llvm::Triple::ppc); const std::string Suffix32 = Arch == llvm::Triple::x86_64 ? "/32" : ""; const std::string Suffix64 = Arch == llvm::Triple::x86_64 ? "" : "/64"; const std::string Suffix = Is32Bits ? Suffix32 : Suffix64; const std::string Multilib = Is32Bits ? "lib32" : "lib64"; + const std::string MultiarchTriple = getMultiarchTriple(Triple, SysRoot); - // FIXME: Because we add paths only when they exist on the system, I think we - // should remove the concept of 'HasMultilib'. It's more likely to break the - // behavior than to preserve any useful invariant on the system. - if (HasMultilib(Arch, Distro)) { - // Add the multilib suffixed paths. - if (GCCInstallation.isValid()) { - const std::string &LibPath = GCCInstallation.getParentLibPath(); - const std::string &GccTriple = GCCInstallation.getTriple(); - // FIXME: This OpenSuse-specific path shouldn't be needed any more, but - // I don't want to remove it without finding someone to test. - if (IsOpenSuse(Distro) && Is32Bits) - Paths.push_back(LibPath + "/../" + GccTriple + "/lib/../lib"); - - addPathIfExists(GCCInstallation.getInstallPath() + Suffix, Paths); - addPathIfExists(LibPath + "/../" + GccTriple + "/lib/../" + Multilib, - Paths); - addPathIfExists(LibPath + "/../" + Multilib, Paths); - } - addPathIfExists(SysRoot + "/lib/../" + Multilib, Paths); - addPathIfExists(SysRoot + "/usr/lib/../" + Multilib, Paths); - - // Try walking via the GCC triple path in case of multiarch GCC - // installations with strange symlinks. - if (GCCInstallation.isValid()) - addPathIfExists(SysRoot + "/usr/lib/" + GCCInstallation.getTriple() + - "/../../" + Multilib, Paths); + // Add the multilib suffixed paths where they are available. + if (GCCInstallation.isValid()) { + const std::string &LibPath = GCCInstallation.getParentLibPath(); + const std::string &GccTriple = GCCInstallation.getTriple(); + addPathIfExists(GCCInstallation.getInstallPath() + Suffix, Paths); + addPathIfExists(LibPath + "/../" + GccTriple + "/lib/../" + Multilib, + Paths); + addPathIfExists(LibPath + "/" + MultiarchTriple, Paths); + addPathIfExists(LibPath + "/../" + Multilib, Paths); } + addPathIfExists(SysRoot + "/lib/" + MultiarchTriple, Paths); + addPathIfExists(SysRoot + "/lib/../" + Multilib, Paths); + addPathIfExists(SysRoot + "/usr/lib/" + MultiarchTriple, Paths); + addPathIfExists(SysRoot + "/usr/lib/../" + Multilib, Paths); + // Try walking via the GCC triple path in case of multiarch GCC + // installations with strange symlinks. + if (GCCInstallation.isValid()) + addPathIfExists(SysRoot + "/usr/lib/" + GCCInstallation.getTriple() + + "/../../" + Multilib, Paths); + // Add the non-multilib suffixed paths (if potentially different). if (GCCInstallation.isValid()) { const std::string &LibPath = GCCInstallation.getParentLibPath(); const std::string &GccTriple = GCCInstallation.getTriple(); - if (!Suffix.empty() || !HasMultilib(Arch, Distro)) + if (!Suffix.empty()) addPathIfExists(GCCInstallation.getInstallPath(), Paths); addPathIfExists(LibPath + "/../" + GccTriple + "/lib", Paths); + addPathIfExists(LibPath + "/" + MultiarchTriple, Paths); addPathIfExists(LibPath, Paths); } + addPathIfExists(SysRoot + "/lib/" + MultiarchTriple, Paths); addPathIfExists(SysRoot + "/lib", Paths); + addPathIfExists(SysRoot + "/usr/lib/" + MultiarchTriple, Paths); addPathIfExists(SysRoot + "/usr/lib", Paths); - - // Add a multiarch lib directory whenever it exists and is plausible. - if (GCCInstallation.isValid() && Arch == getArch()) - addPathIfExists(SysRoot + "/usr/lib/" + GCCInstallation.getTriple(), Paths); } bool Linux::HasNativeLLVMSupport() const { return true; } Tool &Linux::SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const { Action::ActionClass Key; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; else Key = JA.getKind(); bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, options::OPT_no_integrated_as, IsIntegratedAssemblerDefault()); Tool *&T = Tools[Key]; if (!T) { switch (Key) { case Action::AssembleJobClass: if (UseIntegratedAs) T = new tools::ClangAs(*this); else T = new tools::linuxtools::Assemble(*this); break; case Action::LinkJobClass: T = new tools::linuxtools::Link(*this); break; default: T = &Generic_GCC::SelectTool(C, JA, Inputs); } } return *T; } +void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + const Driver &D = getDriver(); + + if (DriverArgs.hasArg(options::OPT_nostdinc)) + return; + + if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) + addSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/local/include"); + + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + llvm::sys::Path P(D.ResourceDir); + P.appendComponent("include"); + addSystemInclude(DriverArgs, CC1Args, P.str()); + } + + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + // Check for configure-time C include directories. + StringRef CIncludeDirs(C_INCLUDE_DIRS); + if (CIncludeDirs != "") { + SmallVector dirs; + CIncludeDirs.split(dirs, ":"); + for (SmallVectorImpl::iterator I = dirs.begin(), E = dirs.end(); + I != E; ++I) { + StringRef Prefix = llvm::sys::path::is_absolute(*I) ? D.SysRoot : ""; + addExternCSystemInclude(DriverArgs, CC1Args, Prefix + *I); + } + return; + } + + // Lacking those, try to detect the correct set of system includes for the + // target triple. + + // Implement generic Debian multiarch support. + const StringRef X86_64MultiarchIncludeDirs[] = { + "/usr/include/x86_64-linux-gnu", + + // FIXME: These are older forms of multiarch. It's not clear that they're + // in use in any released version of Debian, so we should consider + // removing them. + "/usr/include/i686-linux-gnu/64", + "/usr/include/i486-linux-gnu/64" + }; + const StringRef X86MultiarchIncludeDirs[] = { + "/usr/include/i386-linux-gnu", + + // FIXME: These are older forms of multiarch. It's not clear that they're + // in use in any released version of Debian, so we should consider + // removing them. + "/usr/include/x86_64-linux-gnu/32", + "/usr/include/i686-linux-gnu", + "/usr/include/i486-linux-gnu" + }; + const StringRef ARMMultiarchIncludeDirs[] = { + "/usr/include/arm-linux-gnueabi" + }; + ArrayRef MultiarchIncludeDirs; + if (getTriple().getArch() == llvm::Triple::x86_64) { + MultiarchIncludeDirs = X86_64MultiarchIncludeDirs; + } else if (getTriple().getArch() == llvm::Triple::x86) { + MultiarchIncludeDirs = X86MultiarchIncludeDirs; + } else if (getTriple().getArch() == llvm::Triple::arm) { + MultiarchIncludeDirs = ARMMultiarchIncludeDirs; + } + for (ArrayRef::iterator I = MultiarchIncludeDirs.begin(), + E = MultiarchIncludeDirs.end(); + I != E; ++I) { + if (llvm::sys::fs::exists(*I)) { + addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + *I); + break; + } + } + + if (getTriple().getOS() == llvm::Triple::RTEMS) + return; + + addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/include"); +} + +static bool addLibStdCXXIncludePaths(Twine Base, Twine TargetArchDir, + const ArgList &DriverArgs, + ArgStringList &CC1Args) { + if (!llvm::sys::fs::exists(Base)) + return false; + addSystemInclude(DriverArgs, CC1Args, Base); + addSystemInclude(DriverArgs, CC1Args, Base + "/" + TargetArchDir); + addSystemInclude(DriverArgs, CC1Args, Base + "/backward"); + return true; +} + +void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdlibinc) || + DriverArgs.hasArg(options::OPT_nostdincxx)) + return; + + // Check if libc++ has been enabled and provide its include paths if so. + if (GetCXXStdlibType(DriverArgs) == ToolChain::CST_Libcxx) { + // libc++ is always installed at a fixed path on Linux currently. + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/usr/include/c++/v1"); + return; + } + + const llvm::Triple &TargetTriple = getTriple(); + const llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); + bool IsTarget64Bit = (TargetArch == llvm::Triple::x86_64 || + TargetArch == llvm::Triple::ppc64); + + StringRef CxxIncludeRoot(CXX_INCLUDE_ROOT); + if (!CxxIncludeRoot.empty()) { + StringRef CxxIncludeArch(CXX_INCLUDE_ARCH); + if (CxxIncludeArch.empty()) + CxxIncludeArch = TargetTriple.str(); + + addLibStdCXXIncludePaths( + CxxIncludeRoot, + CxxIncludeArch + (IsTarget64Bit ? CXX_INCLUDE_64BIT_DIR + : CXX_INCLUDE_32BIT_DIR), + DriverArgs, CC1Args); + return; + } + + // Check if the target architecture specific dirs need a suffix. Note that we + // only support the suffix-based bi-arch-like header scheme for host/target + // mismatches of just bit width. + llvm::Triple::ArchType HostArch = + llvm::Triple(getDriver().DefaultHostTriple).getArch(); + StringRef Suffix; + if ((HostArch == llvm::Triple::x86 && TargetArch == llvm::Triple::x86_64) || + (HostArch == llvm::Triple::ppc && TargetArch == llvm::Triple::ppc64)) + Suffix = "/64"; + if ((HostArch == llvm::Triple::x86_64 && TargetArch == llvm::Triple::x86) || + (HostArch == llvm::Triple::ppc64 && TargetArch == llvm::Triple::ppc)) + Suffix = "/32"; + + // By default, look for the C++ headers in an include directory adjacent to + // the lib directory of the GCC installation. Note that this is expect to be + // equivalent to '/usr/include/c++/X.Y' in almost all cases. + StringRef LibDir = GCCInstallation.getParentLibPath(); + StringRef InstallDir = GCCInstallation.getInstallPath(); + StringRef Version = GCCInstallation.getVersion(); + if (!addLibStdCXXIncludePaths(LibDir + "/../include/c++/" + Version, + GCCInstallation.getTriple() + Suffix, + DriverArgs, CC1Args)) { + // Gentoo is weird and places its headers inside the GCC install, so if the + // first attempt to find the headers fails, try this pattern. + addLibStdCXXIncludePaths(InstallDir + "/include/g++-v4", + GCCInstallation.getTriple() + Suffix, + DriverArgs, CC1Args); + } +} + /// DragonFly - DragonFly tool chain which can call as(1) and ld(1) directly. DragonFly::DragonFly(const HostInfo &Host, const llvm::Triple& Triple) : Generic_ELF(Host, Triple) { // Path mangling to find libexec getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); getFilePaths().push_back(getDriver().Dir + "/../lib"); getFilePaths().push_back("/usr/lib"); getFilePaths().push_back("/usr/lib/gcc41"); } Tool &DragonFly::SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const { Action::ActionClass Key; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; else Key = JA.getKind(); Tool *&T = Tools[Key]; if (!T) { switch (Key) { case Action::AssembleJobClass: T = new tools::dragonfly::Assemble(*this); break; case Action::LinkJobClass: T = new tools::dragonfly::Link(*this); break; default: T = &Generic_GCC::SelectTool(C, JA, Inputs); } } return *T; } Windows::Windows(const HostInfo &Host, const llvm::Triple& Triple) : ToolChain(Host, Triple) { } Tool &Windows::SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const { Action::ActionClass Key; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; else Key = JA.getKind(); bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, options::OPT_no_integrated_as, IsIntegratedAssemblerDefault()); Tool *&T = Tools[Key]; if (!T) { switch (Key) { case Action::InputClass: case Action::BindArchClass: case Action::LipoJobClass: case Action::DsymutilJobClass: case Action::VerifyJobClass: llvm_unreachable("Invalid tool kind."); case Action::PreprocessJobClass: case Action::PrecompileJobClass: case Action::AnalyzeJobClass: case Action::CompileJobClass: T = new tools::Clang(*this); break; case Action::AssembleJobClass: if (!UseIntegratedAs && getTriple().getEnvironment() == llvm::Triple::MachO) T = new tools::darwin::Assemble(*this); else T = new tools::ClangAs(*this); break; case Action::LinkJobClass: T = new tools::visualstudio::Link(*this); break; } } return *T; } bool Windows::IsIntegratedAssemblerDefault() const { return true; } bool Windows::IsUnwindTablesDefault() const { // FIXME: Gross; we should probably have some separate target // definition, possibly even reusing the one in clang. return getArchName() == "x86_64"; } const char *Windows::GetDefaultRelocationModel() const { return "static"; } const char *Windows::GetForcedPicModel() const { if (getArchName() == "x86_64") return "pic"; return 0; +} + +// FIXME: This probably should goto to some platform utils place. +#ifdef _MSC_VER + +/// \brief Read registry string. +/// This also supports a means to look for high-versioned keys by use +/// of a $VERSION placeholder in the key path. +/// $VERSION in the key path is a placeholder for the version number, +/// causing the highest value path to be searched for and used. +/// I.e. "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION". +/// There can be additional characters in the component. Only the numberic +/// characters are compared. +static bool getSystemRegistryString(const char *keyPath, const char *valueName, + char *value, size_t maxLength) { + HKEY hRootKey = NULL; + HKEY hKey = NULL; + const char* subKey = NULL; + DWORD valueType; + DWORD valueSize = maxLength - 1; + long lResult; + bool returnValue = false; + + if (strncmp(keyPath, "HKEY_CLASSES_ROOT\\", 18) == 0) { + hRootKey = HKEY_CLASSES_ROOT; + subKey = keyPath + 18; + } else if (strncmp(keyPath, "HKEY_USERS\\", 11) == 0) { + hRootKey = HKEY_USERS; + subKey = keyPath + 11; + } else if (strncmp(keyPath, "HKEY_LOCAL_MACHINE\\", 19) == 0) { + hRootKey = HKEY_LOCAL_MACHINE; + subKey = keyPath + 19; + } else if (strncmp(keyPath, "HKEY_CURRENT_USER\\", 18) == 0) { + hRootKey = HKEY_CURRENT_USER; + subKey = keyPath + 18; + } else { + return false; + } + + const char *placeHolder = strstr(subKey, "$VERSION"); + char bestName[256]; + bestName[0] = '\0'; + // If we have a $VERSION placeholder, do the highest-version search. + if (placeHolder) { + const char *keyEnd = placeHolder - 1; + const char *nextKey = placeHolder; + // Find end of previous key. + while ((keyEnd > subKey) && (*keyEnd != '\\')) + keyEnd--; + // Find end of key containing $VERSION. + while (*nextKey && (*nextKey != '\\')) + nextKey++; + size_t partialKeyLength = keyEnd - subKey; + char partialKey[256]; + if (partialKeyLength > sizeof(partialKey)) + partialKeyLength = sizeof(partialKey); + strncpy(partialKey, subKey, partialKeyLength); + partialKey[partialKeyLength] = '\0'; + HKEY hTopKey = NULL; + lResult = RegOpenKeyEx(hRootKey, partialKey, 0, KEY_READ, &hTopKey); + if (lResult == ERROR_SUCCESS) { + char keyName[256]; + int bestIndex = -1; + double bestValue = 0.0; + DWORD index, size = sizeof(keyName) - 1; + for (index = 0; RegEnumKeyEx(hTopKey, index, keyName, &size, NULL, + NULL, NULL, NULL) == ERROR_SUCCESS; index++) { + const char *sp = keyName; + while (*sp && !isdigit(*sp)) + sp++; + if (!*sp) + continue; + const char *ep = sp + 1; + while (*ep && (isdigit(*ep) || (*ep == '.'))) + ep++; + char numBuf[32]; + strncpy(numBuf, sp, sizeof(numBuf) - 1); + numBuf[sizeof(numBuf) - 1] = '\0'; + double value = strtod(numBuf, NULL); + if (value > bestValue) { + bestIndex = (int)index; + bestValue = value; + strcpy(bestName, keyName); + } + size = sizeof(keyName) - 1; + } + // If we found the highest versioned key, open the key and get the value. + if (bestIndex != -1) { + // Append rest of key. + strncat(bestName, nextKey, sizeof(bestName) - 1); + bestName[sizeof(bestName) - 1] = '\0'; + // Open the chosen key path remainder. + lResult = RegOpenKeyEx(hTopKey, bestName, 0, KEY_READ, &hKey); + if (lResult == ERROR_SUCCESS) { + lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType, + (LPBYTE)value, &valueSize); + if (lResult == ERROR_SUCCESS) + returnValue = true; + RegCloseKey(hKey); + } + } + RegCloseKey(hTopKey); + } + } else { + lResult = RegOpenKeyEx(hRootKey, subKey, 0, KEY_READ, &hKey); + if (lResult == ERROR_SUCCESS) { + lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType, + (LPBYTE)value, &valueSize); + if (lResult == ERROR_SUCCESS) + returnValue = true; + RegCloseKey(hKey); + } + } + return returnValue; +} + +/// \brief Get Windows SDK installation directory. +static bool getWindowsSDKDir(std::string &path) { + char windowsSDKInstallDir[256]; + // Try the Windows registry. + bool hasSDKDir = getSystemRegistryString( + "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION", + "InstallationFolder", + windowsSDKInstallDir, + sizeof(windowsSDKInstallDir) - 1); + // If we have both vc80 and vc90, pick version we were compiled with. + if (hasSDKDir && windowsSDKInstallDir[0]) { + path = windowsSDKInstallDir; + return true; + } + return false; +} + + // Get Visual Studio installation directory. +static bool getVisualStudioDir(std::string &path) { + // First check the environment variables that vsvars32.bat sets. + const char* vcinstalldir = getenv("VCINSTALLDIR"); + if (vcinstalldir) { + char *p = const_cast(strstr(vcinstalldir, "\\VC")); + if (p) + *p = '\0'; + path = vcinstalldir; + return true; + } + + char vsIDEInstallDir[256]; + char vsExpressIDEInstallDir[256]; + // Then try the windows registry. + bool hasVCDir = getSystemRegistryString( + "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION", + "InstallDir", vsIDEInstallDir, sizeof(vsIDEInstallDir) - 1); + bool hasVCExpressDir = getSystemRegistryString( + "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\$VERSION", + "InstallDir", vsExpressIDEInstallDir, sizeof(vsExpressIDEInstallDir) - 1); + // If we have both vc80 and vc90, pick version we were compiled with. + if (hasVCDir && vsIDEInstallDir[0]) { + char *p = (char*)strstr(vsIDEInstallDir, "\\Common7\\IDE"); + if (p) + *p = '\0'; + path = vsIDEInstallDir; + return true; + } + + if (hasVCExpressDir && vsExpressIDEInstallDir[0]) { + char *p = (char*)strstr(vsExpressIDEInstallDir, "\\Common7\\IDE"); + if (p) + *p = '\0'; + path = vsExpressIDEInstallDir; + return true; + } + + // Try the environment. + const char *vs100comntools = getenv("VS100COMNTOOLS"); + const char *vs90comntools = getenv("VS90COMNTOOLS"); + const char *vs80comntools = getenv("VS80COMNTOOLS"); + const char *vscomntools = NULL; + + // Try to find the version that we were compiled with + if(false) {} + #if (_MSC_VER >= 1600) // VC100 + else if(vs100comntools) { + vscomntools = vs100comntools; + } + #elif (_MSC_VER == 1500) // VC80 + else if(vs90comntools) { + vscomntools = vs90comntools; + } + #elif (_MSC_VER == 1400) // VC80 + else if(vs80comntools) { + vscomntools = vs80comntools; + } + #endif + // Otherwise find any version we can + else if (vs100comntools) + vscomntools = vs100comntools; + else if (vs90comntools) + vscomntools = vs90comntools; + else if (vs80comntools) + vscomntools = vs80comntools; + + if (vscomntools && *vscomntools) { + const char *p = strstr(vscomntools, "\\Common7\\Tools"); + path = p ? std::string(vscomntools, p) : vscomntools; + return true; + } + return false; +} + +#endif // _MSC_VER + +void Windows::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdinc)) + return; + + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + llvm::sys::Path P(getDriver().ResourceDir); + P.appendComponent("include"); + addSystemInclude(DriverArgs, CC1Args, P.str()); + } + + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + std::string VSDir; + std::string WindowsSDKDir; + +#ifdef _MSC_VER + // When built with access to the proper Windows APIs, try to actually find + // the correct include paths first. + if (getVisualStudioDir(VSDir)) { + addSystemInclude(DriverArgs, CC1Args, VSDir + "\\VC\\include"); + if (getWindowsSDKDir(WindowsSDKDir)) + addSystemInclude(DriverArgs, CC1Args, WindowsSDKDir + "\\include"); + else + addSystemInclude(DriverArgs, CC1Args, + VSDir + "\\VC\\PlatformSDK\\Include"); + return; + } +#endif // _MSC_VER + + // As a fallback, select default install paths. + const StringRef Paths[] = { + "C:/Program Files/Microsoft Visual Studio 10.0/VC/include", + "C:/Program Files/Microsoft Visual Studio 9.0/VC/include", + "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include", + "C:/Program Files/Microsoft Visual Studio 8/VC/include", + "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include" + }; + addSystemIncludes(DriverArgs, CC1Args, Paths); +} + +void Windows::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + // FIXME: There should probably be logic here to find libc++ on Windows. } Index: head/contrib/llvm/tools/clang/lib/Driver/ToolChains.h =================================================================== --- head/contrib/llvm/tools/clang/lib/Driver/ToolChains.h (revision 228378) +++ head/contrib/llvm/tools/clang/lib/Driver/ToolChains.h (revision 228379) @@ -1,426 +1,517 @@ //===--- ToolChains.h - ToolChain Implementations ---------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef CLANG_LIB_DRIVER_TOOLCHAINS_H_ #define CLANG_LIB_DRIVER_TOOLCHAINS_H_ #include "clang/Driver/Action.h" #include "clang/Driver/ToolChain.h" #include "llvm/ADT/DenseMap.h" #include "llvm/Support/Compiler.h" #include "Tools.h" namespace clang { namespace driver { namespace toolchains { /// Generic_GCC - A tool chain using the 'gcc' command to perform /// all subcommands; this relies on gcc translating the majority of /// command line options. class LLVM_LIBRARY_VISIBILITY Generic_GCC : public ToolChain { protected: mutable llvm::DenseMap Tools; public: Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple); ~Generic_GCC(); virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const; virtual bool IsUnwindTablesDefault() const; virtual const char *GetDefaultRelocationModel() const; virtual const char *GetForcedPicModel() const; }; /// Darwin - The base Darwin tool chain. class LLVM_LIBRARY_VISIBILITY Darwin : public ToolChain { public: /// The host version. unsigned DarwinVersion[3]; private: mutable llvm::DenseMap Tools; /// Whether the information on the target has been initialized. // // FIXME: This should be eliminated. What we want to do is make this part of // the "default target for arguments" selection process, once we get out of // the argument translation business. mutable bool TargetInitialized; // FIXME: Remove this once there is a proper way to detect an ARC runtime // for the simulator. public: mutable enum { ARCSimulator_None, ARCSimulator_HasARCRuntime, ARCSimulator_NoARCRuntime } ARCRuntimeForSimulator; mutable enum { LibCXXSimulator_None, LibCXXSimulator_NotAvailable, LibCXXSimulator_Available } LibCXXForSimulator; private: /// Whether we are targeting iPhoneOS target. mutable bool TargetIsIPhoneOS; /// Whether we are targeting the iPhoneOS simulator target. mutable bool TargetIsIPhoneOSSimulator; /// The OS version we are targeting. mutable unsigned TargetVersion[3]; /// The default macosx-version-min of this tool chain; empty until /// initialized. std::string MacosxVersionMin; bool hasARCRuntime() const; private: void AddDeploymentTarget(DerivedArgList &Args) const; public: Darwin(const HostInfo &Host, const llvm::Triple& Triple); ~Darwin(); std::string ComputeEffectiveClangTriple(const ArgList &Args, types::ID InputType) const; /// @name Darwin Specific Toolchain API /// { // FIXME: Eliminate these ...Target functions and derive separate tool chains // for these targets and put version in constructor. void setTarget(bool IsIPhoneOS, unsigned Major, unsigned Minor, unsigned Micro, bool IsIOSSim) const { assert((!IsIOSSim || IsIPhoneOS) && "Unexpected deployment target!"); // FIXME: For now, allow reinitialization as long as values don't // change. This will go away when we move away from argument translation. if (TargetInitialized && TargetIsIPhoneOS == IsIPhoneOS && TargetIsIPhoneOSSimulator == IsIOSSim && TargetVersion[0] == Major && TargetVersion[1] == Minor && TargetVersion[2] == Micro) return; assert(!TargetInitialized && "Target already initialized!"); TargetInitialized = true; TargetIsIPhoneOS = IsIPhoneOS; TargetIsIPhoneOSSimulator = IsIOSSim; TargetVersion[0] = Major; TargetVersion[1] = Minor; TargetVersion[2] = Micro; } bool isTargetIPhoneOS() const { assert(TargetInitialized && "Target not initialized!"); return TargetIsIPhoneOS; } bool isTargetIOSSimulator() const { assert(TargetInitialized && "Target not initialized!"); return TargetIsIPhoneOSSimulator; } bool isTargetInitialized() const { return TargetInitialized; } void getTargetVersion(unsigned (&Res)[3]) const { assert(TargetInitialized && "Target not initialized!"); Res[0] = TargetVersion[0]; Res[1] = TargetVersion[1]; Res[2] = TargetVersion[2]; } /// getDarwinArchName - Get the "Darwin" arch name for a particular compiler /// invocation. For example, Darwin treats different ARM variations as /// distinct architectures. StringRef getDarwinArchName(const ArgList &Args) const; static bool isVersionLT(unsigned (&A)[3], unsigned (&B)[3]) { for (unsigned i=0; i < 3; ++i) { if (A[i] > B[i]) return false; if (A[i] < B[i]) return true; } return false; } bool isIPhoneOSVersionLT(unsigned V0, unsigned V1=0, unsigned V2=0) const { assert(isTargetIPhoneOS() && "Unexpected call for OS X target!"); unsigned B[3] = { V0, V1, V2 }; return isVersionLT(TargetVersion, B); } bool isMacosxVersionLT(unsigned V0, unsigned V1=0, unsigned V2=0) const { assert(!isTargetIPhoneOS() && "Unexpected call for iPhoneOS target!"); unsigned B[3] = { V0, V1, V2 }; return isVersionLT(TargetVersion, B); } /// AddLinkSearchPathArgs - Add the linker search paths to \arg CmdArgs. /// /// \param Args - The input argument list. /// \param CmdArgs [out] - The command argument list to append the paths /// (prefixed by -L) to. virtual void AddLinkSearchPathArgs(const ArgList &Args, ArgStringList &CmdArgs) const = 0; /// AddLinkARCArgs - Add the linker arguments to link the ARC runtime library. virtual void AddLinkARCArgs(const ArgList &Args, ArgStringList &CmdArgs) const = 0; /// AddLinkRuntimeLibArgs - Add the linker arguments to link the compiler /// runtime library. virtual void AddLinkRuntimeLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const = 0; /// } /// @name ToolChain Implementation /// { virtual types::ID LookupTypeForExtension(const char *Ext) const; virtual bool HasNativeLLVMSupport() const; virtual void configureObjCRuntime(ObjCRuntime &runtime) const; virtual bool hasBlocksRuntime() const; virtual DerivedArgList *TranslateArgs(const DerivedArgList &Args, const char *BoundArch) const; virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const; virtual bool IsBlocksDefault() const { // Always allow blocks on Darwin; users interested in versioning are // expected to use /usr/include/Blocks.h. return true; } virtual bool IsIntegratedAssemblerDefault() const { #ifdef DISABLE_DEFAULT_INTEGRATED_ASSEMBLER return false; #else // Default integrated assembler to on for x86. return (getTriple().getArch() == llvm::Triple::x86 || getTriple().getArch() == llvm::Triple::x86_64); #endif } virtual bool IsStrictAliasingDefault() const { #ifdef DISABLE_DEFAULT_STRICT_ALIASING return false; #else return ToolChain::IsStrictAliasingDefault(); #endif } virtual bool IsObjCDefaultSynthPropertiesDefault() const { return false; } virtual bool IsObjCNonFragileABIDefault() const { // Non-fragile ABI is default for everything but i386. return getTriple().getArch() != llvm::Triple::x86; } virtual bool IsObjCLegacyDispatchDefault() const { // This is only used with the non-fragile ABI. // Legacy dispatch is used everywhere except on x86_64. return getTriple().getArch() != llvm::Triple::x86_64; } virtual bool UseObjCMixedDispatch() const { // This is only used with the non-fragile ABI and non-legacy dispatch. // Mixed dispatch is used everywhere except OS X before 10.6. return !(!isTargetIPhoneOS() && isMacosxVersionLT(10, 6)); } virtual bool IsUnwindTablesDefault() const; virtual unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const { // Stack protectors default to on for user code on 10.5, // and for everything in 10.6 and beyond return !isTargetIPhoneOS() && (!isMacosxVersionLT(10, 6) || (!isMacosxVersionLT(10, 5) && !KernelOrKext)); } virtual const char *GetDefaultRelocationModel() const; virtual const char *GetForcedPicModel() const; virtual bool SupportsProfiling() const; virtual bool SupportsObjCGC() const; virtual bool UseDwarfDebugFlags() const; virtual bool UseSjLjExceptions() const; /// } }; /// DarwinClang - The Darwin toolchain used by Clang. class LLVM_LIBRARY_VISIBILITY DarwinClang : public Darwin { private: void AddGCCLibexecPath(unsigned darwinVersion); public: DarwinClang(const HostInfo &Host, const llvm::Triple& Triple); /// @name Darwin ToolChain Implementation /// { virtual void AddLinkSearchPathArgs(const ArgList &Args, ArgStringList &CmdArgs) const; virtual void AddLinkRuntimeLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const; void AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs, const char *DarwinStaticLib) const; virtual void AddCXXStdlibLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const; virtual void AddCCKextLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const; virtual void AddLinkARCArgs(const ArgList &Args, ArgStringList &CmdArgs) const; /// } }; /// Darwin_Generic_GCC - Generic Darwin tool chain using gcc. class LLVM_LIBRARY_VISIBILITY Darwin_Generic_GCC : public Generic_GCC { public: Darwin_Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple) : Generic_GCC(Host, Triple) {} std::string ComputeEffectiveClangTriple(const ArgList &Args, types::ID InputType) const; virtual const char *GetDefaultRelocationModel() const { return "pic"; } }; class LLVM_LIBRARY_VISIBILITY Generic_ELF : public Generic_GCC { public: Generic_ELF(const HostInfo &Host, const llvm::Triple& Triple) : Generic_GCC(Host, Triple) {} virtual bool IsIntegratedAssemblerDefault() const { // Default integrated assembler to on for x86. return (getTriple().getArch() == llvm::Triple::x86 || getTriple().getArch() == llvm::Triple::x86_64); } }; class LLVM_LIBRARY_VISIBILITY AuroraUX : public Generic_GCC { public: AuroraUX(const HostInfo &Host, const llvm::Triple& Triple); virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const; }; class LLVM_LIBRARY_VISIBILITY OpenBSD : public Generic_ELF { public: OpenBSD(const HostInfo &Host, const llvm::Triple& Triple); virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const; }; class LLVM_LIBRARY_VISIBILITY FreeBSD : public Generic_ELF { public: FreeBSD(const HostInfo &Host, const llvm::Triple& Triple); virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const; }; class LLVM_LIBRARY_VISIBILITY NetBSD : public Generic_ELF { const llvm::Triple ToolTriple; public: NetBSD(const HostInfo &Host, const llvm::Triple& Triple, const llvm::Triple& ToolTriple); virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const; }; class LLVM_LIBRARY_VISIBILITY Minix : public Generic_GCC { public: Minix(const HostInfo &Host, const llvm::Triple& Triple); virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const; }; class LLVM_LIBRARY_VISIBILITY DragonFly : public Generic_ELF { public: DragonFly(const HostInfo &Host, const llvm::Triple& Triple); virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const; }; class LLVM_LIBRARY_VISIBILITY Linux : public Generic_ELF { + /// \brief Struct to store and manipulate GCC versions. + /// + /// We rely on assumptions about the form and structure of GCC version + /// numbers: they consist of at most three '.'-separated components, and each + /// component is a non-negative integer except for the last component. For + /// the last component we are very flexible in order to tolerate release + /// candidates or 'x' wildcards. + /// + /// Note that the ordering established among GCCVersions is based on the + /// preferred version string to use. For example we prefer versions without + /// a hard-coded patch number to those with a hard coded patch number. + /// + /// Currently this doesn't provide any logic for textual suffixes to patches + /// in the way that (for example) Debian's version format does. If that ever + /// becomes necessary, it can be added. + struct GCCVersion { + /// \brief The unparsed text of the version. + std::string Text; + + /// \brief The parsed major, minor, and patch numbers. + int Major, Minor, Patch; + + /// \brief Any textual suffix on the patch number. + std::string PatchSuffix; + + static GCCVersion Parse(StringRef VersionText); + bool operator<(const GCCVersion &RHS) const; + bool operator>(const GCCVersion &RHS) const { return RHS < *this; } + bool operator<=(const GCCVersion &RHS) const { return !(*this > RHS); } + bool operator>=(const GCCVersion &RHS) const { return !(*this < RHS); } + }; + + + /// \brief This is a class to find a viable GCC installation for Clang to + /// use. + /// + /// This class tries to find a GCC installation on the system, and report + /// information about it. It starts from the host information provided to the + /// Driver, and has logic for fuzzing that where appropriate. + class GCCInstallationDetector { + + bool IsValid; + std::string GccTriple; + + // FIXME: These might be better as path objects. + std::string GccInstallPath; + std::string GccParentLibPath; + + GCCVersion Version; + + public: + GCCInstallationDetector(const Driver &D); + + /// \brief Check whether we detected a valid GCC install. + bool isValid() const { return IsValid; } + + /// \brief Get the GCC triple for the detected install. + StringRef getTriple() const { return GccTriple; } + + /// \brief Get the detected GCC installation path. + StringRef getInstallPath() const { return GccInstallPath; } + + /// \brief Get the detected GCC parent lib path. + StringRef getParentLibPath() const { return GccParentLibPath; } + + /// \brief Get the detected GCC version string. + StringRef getVersion() const { return Version.Text; } + + private: + static void CollectLibDirsAndTriples(llvm::Triple::ArchType HostArch, + SmallVectorImpl &LibDirs, + SmallVectorImpl &Triples); + + void ScanLibDirForGCCTriple(llvm::Triple::ArchType HostArch, + const std::string &LibDir, + StringRef CandidateTriple); + }; + + GCCInstallationDetector GCCInstallation; + public: Linux(const HostInfo &Host, const llvm::Triple& Triple); virtual bool HasNativeLLVMSupport() const; virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const; + virtual void AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const; + virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const; + std::string Linker; std::vector ExtraOpts; }; /// TCEToolChain - A tool chain using the llvm bitcode tools to perform /// all subcommands. See http://tce.cs.tut.fi for our peculiar target. class LLVM_LIBRARY_VISIBILITY TCEToolChain : public ToolChain { public: TCEToolChain(const HostInfo &Host, const llvm::Triple& Triple); ~TCEToolChain(); virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const; bool IsMathErrnoDefault() const; bool IsUnwindTablesDefault() const; const char* GetDefaultRelocationModel() const; const char* GetForcedPicModel() const; private: mutable llvm::DenseMap Tools; }; class LLVM_LIBRARY_VISIBILITY Windows : public ToolChain { mutable llvm::DenseMap Tools; public: Windows(const HostInfo &Host, const llvm::Triple& Triple); virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const; virtual bool IsIntegratedAssemblerDefault() const; virtual bool IsUnwindTablesDefault() const; virtual const char *GetDefaultRelocationModel() const; virtual const char *GetForcedPicModel() const; + + virtual void AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const; + virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const; + }; } // end namespace toolchains } // end namespace driver } // end namespace clang #endif Index: head/contrib/llvm/tools/clang/lib/Driver/Tools.cpp =================================================================== --- head/contrib/llvm/tools/clang/lib/Driver/Tools.cpp (revision 228378) +++ head/contrib/llvm/tools/clang/lib/Driver/Tools.cpp (revision 228379) @@ -1,4691 +1,4698 @@ //===--- Tools.cpp - Tools Implementations --------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Tools.h" #include "clang/Driver/Action.h" #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Job.h" #include "clang/Driver/HostInfo.h" #include "clang/Driver/ObjCRuntime.h" #include "clang/Driver/Option.h" #include "clang/Driver/Options.h" #include "clang/Driver/ToolChain.h" #include "clang/Driver/Util.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Host.h" #include "llvm/Support/Process.h" #include "llvm/Support/ErrorHandling.h" #include "InputInfo.h" #include "ToolChains.h" #ifdef __CYGWIN__ #include #if defined(CYGWIN_VERSION_DLL_MAJOR) && CYGWIN_VERSION_DLL_MAJOR<1007 #define IS_CYGWIN15 1 #endif #endif using namespace clang::driver; using namespace clang::driver::tools; using namespace clang; /// CheckPreprocessingOptions - Perform some validation of preprocessing /// arguments that is shared with gcc. static void CheckPreprocessingOptions(const Driver &D, const ArgList &Args) { if (Arg *A = Args.getLastArg(options::OPT_C, options::OPT_CC)) if (!Args.hasArg(options::OPT_E) && !D.CCCIsCPP) D.Diag(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args) << "-E"; } /// CheckCodeGenerationOptions - Perform some validation of code generation /// arguments that is shared with gcc. static void CheckCodeGenerationOptions(const Driver &D, const ArgList &Args) { // In gcc, only ARM checks this, but it seems reasonable to check universally. if (Args.hasArg(options::OPT_static)) if (const Arg *A = Args.getLastArg(options::OPT_dynamic, options::OPT_mdynamic_no_pic)) D.Diag(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args) << "-static"; } // Quote target names for inclusion in GNU Make dependency files. // Only the characters '$', '#', ' ', '\t' are quoted. static void QuoteTarget(StringRef Target, SmallVectorImpl &Res) { for (unsigned i = 0, e = Target.size(); i != e; ++i) { switch (Target[i]) { case ' ': case '\t': // Escape the preceding backslashes for (int j = i - 1; j >= 0 && Target[j] == '\\'; --j) Res.push_back('\\'); // Escape the space/tab Res.push_back('\\'); break; case '$': Res.push_back('$'); break; case '#': Res.push_back('\\'); break; default: break; } Res.push_back(Target[i]); } } static void AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, const ArgList &Args, ArgStringList &CmdArgs) { const Driver &D = TC.getDriver(); // Add extra linker input arguments which are not treated as inputs // (constructed via -Xarch_). Args.AddAllArgValues(CmdArgs, options::OPT_Zlinker_input); for (InputInfoList::const_iterator it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { const InputInfo &II = *it; if (!TC.HasNativeLLVMSupport()) { // Don't try to pass LLVM inputs unless we have native support. if (II.getType() == types::TY_LLVM_IR || II.getType() == types::TY_LTO_IR || II.getType() == types::TY_LLVM_BC || II.getType() == types::TY_LTO_BC) D.Diag(diag::err_drv_no_linker_llvm_support) << TC.getTripleString(); } // Add filenames immediately. if (II.isFilename()) { CmdArgs.push_back(II.getFilename()); continue; } // Otherwise, this is a linker input argument. const Arg &A = II.getInputArg(); // Handle reserved library options. if (A.getOption().matches(options::OPT_Z_reserved_lib_stdcxx)) { TC.AddCXXStdlibLibArgs(Args, CmdArgs); } else if (A.getOption().matches(options::OPT_Z_reserved_lib_cckext)) { TC.AddCCKextLibArgs(Args, CmdArgs); } else A.renderAsInput(Args, CmdArgs); } } /// \brief Determine whether Objective-C automated reference counting is /// enabled. static bool isObjCAutoRefCount(const ArgList &Args) { return Args.hasFlag(options::OPT_fobjc_arc, options::OPT_fno_objc_arc, false); } static void addProfileRT(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs, llvm::Triple Triple) { if (!(Args.hasArg(options::OPT_fprofile_arcs) || Args.hasArg(options::OPT_fprofile_generate) || Args.hasArg(options::OPT_fcreate_profile) || Args.hasArg(options::OPT_coverage))) return; // GCC links libgcov.a by adding -L/gcc/lib/gcc// -lgcov to // the link line. We cannot do the same thing because unlike gcov there is a // libprofile_rt.so. We used to use the -l:libprofile_rt.a syntax, but that is // not supported by old linkers. Twine ProfileRT = Twine(TC.getDriver().Dir) + "/../lib/" + "libprofile_rt.a"; if (Triple.isOSDarwin()) { // On Darwin, if the static library doesn't exist try the dylib. bool Exists; if (llvm::sys::fs::exists(ProfileRT.str(), Exists) || !Exists) ProfileRT = Twine(TC.getDriver().Dir) + "/../lib/" + "libprofile_rt.dylib"; } CmdArgs.push_back(Args.MakeArgString(ProfileRT)); } static void AddIncludeDirectoryList(const ArgList &Args, ArgStringList &CmdArgs, const char *ArgName, const char *DirList) { if (!DirList) return; // Nothing to do. StringRef Dirs(DirList); if (Dirs.empty()) // Empty string should not add '.'. return; StringRef::size_type Delim; while ((Delim = Dirs.find(llvm::sys::PathSeparator)) != StringRef::npos) { if (Delim == 0) { // Leading colon. CmdArgs.push_back(ArgName); CmdArgs.push_back("."); } else { CmdArgs.push_back(ArgName); CmdArgs.push_back(Args.MakeArgString(Dirs.substr(0, Delim))); } Dirs = Dirs.substr(Delim + 1); } if (Dirs.empty()) { // Trailing colon. CmdArgs.push_back(ArgName); CmdArgs.push_back("."); } else { // Add the last path. CmdArgs.push_back(ArgName); CmdArgs.push_back(Args.MakeArgString(Dirs)); } } void Clang::AddPreprocessingOptions(const Driver &D, const ArgList &Args, ArgStringList &CmdArgs, const InputInfo &Output, const InputInfoList &Inputs) const { Arg *A; CheckPreprocessingOptions(D, Args); Args.AddLastArg(CmdArgs, options::OPT_C); Args.AddLastArg(CmdArgs, options::OPT_CC); // Handle dependency file generation. if ((A = Args.getLastArg(options::OPT_M, options::OPT_MM)) || (A = Args.getLastArg(options::OPT_MD)) || (A = Args.getLastArg(options::OPT_MMD))) { // Determine the output location. const char *DepFile; if (Output.getType() == types::TY_Dependencies) { DepFile = Output.getFilename(); } else if (Arg *MF = Args.getLastArg(options::OPT_MF)) { DepFile = MF->getValue(Args); } else if (A->getOption().matches(options::OPT_M) || A->getOption().matches(options::OPT_MM)) { DepFile = "-"; } else { DepFile = darwin::CC1::getDependencyFileName(Args, Inputs); } CmdArgs.push_back("-dependency-file"); CmdArgs.push_back(DepFile); // Add a default target if one wasn't specified. if (!Args.hasArg(options::OPT_MT) && !Args.hasArg(options::OPT_MQ)) { const char *DepTarget; // If user provided -o, that is the dependency target, except // when we are only generating a dependency file. Arg *OutputOpt = Args.getLastArg(options::OPT_o); if (OutputOpt && Output.getType() != types::TY_Dependencies) { DepTarget = OutputOpt->getValue(Args); } else { // Otherwise derive from the base input. // // FIXME: This should use the computed output file location. llvm::SmallString<128> P(Inputs[0].getBaseInput()); llvm::sys::path::replace_extension(P, "o"); DepTarget = Args.MakeArgString(llvm::sys::path::filename(P)); } CmdArgs.push_back("-MT"); llvm::SmallString<128> Quoted; QuoteTarget(DepTarget, Quoted); CmdArgs.push_back(Args.MakeArgString(Quoted)); } if (A->getOption().matches(options::OPT_M) || A->getOption().matches(options::OPT_MD)) CmdArgs.push_back("-sys-header-deps"); } if (Args.hasArg(options::OPT_MG)) { if (!A || A->getOption().matches(options::OPT_MD) || A->getOption().matches(options::OPT_MMD)) D.Diag(diag::err_drv_mg_requires_m_or_mm); CmdArgs.push_back("-MG"); } Args.AddLastArg(CmdArgs, options::OPT_MP); // Convert all -MQ args to -MT for (arg_iterator it = Args.filtered_begin(options::OPT_MT, options::OPT_MQ), ie = Args.filtered_end(); it != ie; ++it) { const Arg *A = *it; A->claim(); if (A->getOption().matches(options::OPT_MQ)) { CmdArgs.push_back("-MT"); llvm::SmallString<128> Quoted; QuoteTarget(A->getValue(Args), Quoted); CmdArgs.push_back(Args.MakeArgString(Quoted)); // -MT flag - no change } else { A->render(Args, CmdArgs); } } // Add -i* options, and automatically translate to // -include-pch/-include-pth for transparent PCH support. It's // wonky, but we include looking for .gch so we can support seamless // replacement into a build system already set up to be generating // .gch files. bool RenderedImplicitInclude = false; for (arg_iterator it = Args.filtered_begin(options::OPT_clang_i_Group), ie = Args.filtered_end(); it != ie; ++it) { const Arg *A = it; if (A->getOption().matches(options::OPT_include)) { bool IsFirstImplicitInclude = !RenderedImplicitInclude; RenderedImplicitInclude = true; // Use PCH if the user requested it. bool UsePCH = D.CCCUsePCH; bool FoundPTH = false; bool FoundPCH = false; llvm::sys::Path P(A->getValue(Args)); bool Exists; if (UsePCH) { P.appendSuffix("pch"); if (!llvm::sys::fs::exists(P.str(), Exists) && Exists) FoundPCH = true; else P.eraseSuffix(); } if (!FoundPCH) { P.appendSuffix("pth"); if (!llvm::sys::fs::exists(P.str(), Exists) && Exists) FoundPTH = true; else P.eraseSuffix(); } if (!FoundPCH && !FoundPTH) { P.appendSuffix("gch"); if (!llvm::sys::fs::exists(P.str(), Exists) && Exists) { FoundPCH = UsePCH; FoundPTH = !UsePCH; } else P.eraseSuffix(); } if (FoundPCH || FoundPTH) { if (IsFirstImplicitInclude) { A->claim(); if (UsePCH) CmdArgs.push_back("-include-pch"); else CmdArgs.push_back("-include-pth"); CmdArgs.push_back(Args.MakeArgString(P.str())); continue; } else { // Ignore the PCH if not first on command line and emit warning. D.Diag(diag::warn_drv_pch_not_first_include) << P.str() << A->getAsString(Args); } } } // Not translated, render as usual. A->claim(); A->render(Args, CmdArgs); } Args.AddAllArgs(CmdArgs, options::OPT_D, options::OPT_U); Args.AddAllArgs(CmdArgs, options::OPT_I_Group, options::OPT_F, options::OPT_index_header_map); - // Add C++ include arguments, if needed. - types::ID InputType = Inputs[0].getType(); - if (types::isCXX(InputType)) { - bool ObjCXXAutoRefCount - = types::isObjC(InputType) && isObjCAutoRefCount(Args); - getToolChain().AddClangCXXStdlibIncludeArgs(Args, CmdArgs, - ObjCXXAutoRefCount); - Args.AddAllArgs(CmdArgs, options::OPT_stdlib_EQ); - } - // Add -Wp, and -Xassembler if using the preprocessor. // FIXME: There is a very unfortunate problem here, some troubled // souls abuse -Wp, to pass preprocessor options in gcc syntax. To // really support that we would have to parse and then translate // those options. :( Args.AddAllArgValues(CmdArgs, options::OPT_Wp_COMMA, options::OPT_Xpreprocessor); // -I- is a deprecated GCC feature, reject it. if (Arg *A = Args.getLastArg(options::OPT_I_)) D.Diag(diag::err_drv_I_dash_not_supported) << A->getAsString(Args); // If we have a --sysroot, and don't have an explicit -isysroot flag, add an // -isysroot to the CC1 invocation. if (Arg *A = Args.getLastArg(options::OPT__sysroot_EQ)) { if (!Args.hasArg(options::OPT_isysroot)) { CmdArgs.push_back("-isysroot"); CmdArgs.push_back(A->getValue(Args)); } } // If a module path was provided, pass it along. Otherwise, use a temporary // directory. if (Arg *A = Args.getLastArg(options::OPT_fmodule_cache_path)) { A->claim(); A->render(Args, CmdArgs); } else { llvm::SmallString<128> DefaultModuleCache; llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false, DefaultModuleCache); llvm::sys::path::append(DefaultModuleCache, "clang-module-cache"); CmdArgs.push_back("-fmodule-cache-path"); CmdArgs.push_back(Args.MakeArgString(DefaultModuleCache)); } Args.AddAllArgs(CmdArgs, options::OPT_fauto_module_import); // Parse additional include paths from environment variables. // CPATH - included following the user specified includes (but prior to // builtin and standard includes). AddIncludeDirectoryList(Args, CmdArgs, "-I", ::getenv("CPATH")); // C_INCLUDE_PATH - system includes enabled when compiling C. AddIncludeDirectoryList(Args, CmdArgs, "-c-isystem", ::getenv("C_INCLUDE_PATH")); // CPLUS_INCLUDE_PATH - system includes enabled when compiling C++. AddIncludeDirectoryList(Args, CmdArgs, "-cxx-isystem", ::getenv("CPLUS_INCLUDE_PATH")); // OBJC_INCLUDE_PATH - system includes enabled when compiling ObjC. AddIncludeDirectoryList(Args, CmdArgs, "-objc-isystem", ::getenv("OBJC_INCLUDE_PATH")); // OBJCPLUS_INCLUDE_PATH - system includes enabled when compiling ObjC++. AddIncludeDirectoryList(Args, CmdArgs, "-objcxx-isystem", ::getenv("OBJCPLUS_INCLUDE_PATH")); + + // Add C++ include arguments, if needed. + if (types::isCXX(Inputs[0].getType())) + getToolChain().AddClangCXXStdlibIncludeArgs(Args, CmdArgs); + + // Add system include arguments. + getToolChain().AddClangSystemIncludeArgs(Args, CmdArgs); } /// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targeting. // // FIXME: tblgen this. static const char *getARMTargetCPU(const ArgList &Args, const llvm::Triple &Triple) { // FIXME: Warn on inconsistent use of -mcpu and -march. // If we have -mcpu=, use that. if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) return A->getValue(Args); StringRef MArch; if (Arg *A = Args.getLastArg(options::OPT_march_EQ)) { // Otherwise, if we have -march= choose the base CPU for that arch. MArch = A->getValue(Args); } else { // Otherwise, use the Arch from the triple. MArch = Triple.getArchName(); } return llvm::StringSwitch(MArch) .Cases("armv2", "armv2a","arm2") .Case("armv3", "arm6") .Case("armv3m", "arm7m") .Cases("armv4", "armv4t", "arm7tdmi") .Cases("armv5", "armv5t", "arm10tdmi") .Cases("armv5e", "armv5te", "arm1026ejs") .Case("armv5tej", "arm926ej-s") .Cases("armv6", "armv6k", "arm1136jf-s") .Case("armv6j", "arm1136j-s") .Cases("armv6z", "armv6zk", "arm1176jzf-s") .Case("armv6t2", "arm1156t2-s") .Cases("armv7", "armv7a", "armv7-a", "cortex-a8") .Cases("armv7r", "armv7-r", "cortex-r4") .Cases("armv7m", "armv7-m", "cortex-m3") .Case("ep9312", "ep9312") .Case("iwmmxt", "iwmmxt") .Case("xscale", "xscale") .Cases("armv6m", "armv6-m", "cortex-m0") // If all else failed, return the most base CPU LLVM supports. .Default("arm7tdmi"); } /// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular /// CPU. // // FIXME: This is redundant with -mcpu, why does LLVM use this. // FIXME: tblgen this, or kill it! static const char *getLLVMArchSuffixForARM(StringRef CPU) { return llvm::StringSwitch(CPU) .Cases("arm7tdmi", "arm7tdmi-s", "arm710t", "v4t") .Cases("arm720t", "arm9", "arm9tdmi", "v4t") .Cases("arm920", "arm920t", "arm922t", "v4t") .Cases("arm940t", "ep9312","v4t") .Cases("arm10tdmi", "arm1020t", "v5") .Cases("arm9e", "arm926ej-s", "arm946e-s", "v5e") .Cases("arm966e-s", "arm968e-s", "arm10e", "v5e") .Cases("arm1020e", "arm1022e", "xscale", "iwmmxt", "v5e") .Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "v6") .Cases("arm1176jzf-s", "mpcorenovfp", "mpcore", "v6") .Cases("arm1156t2-s", "arm1156t2f-s", "v6t2") .Cases("cortex-a8", "cortex-a9", "v7") .Default(""); } // FIXME: Move to target hook. static bool isSignedCharDefault(const llvm::Triple &Triple) { switch (Triple.getArch()) { default: return true; case llvm::Triple::arm: case llvm::Triple::ppc: case llvm::Triple::ppc64: if (Triple.isOSDarwin()) return true; return false; case llvm::Triple::systemz: return false; } } void Clang::AddARMTargetArgs(const ArgList &Args, ArgStringList &CmdArgs, bool KernelOrKext) const { const Driver &D = getToolChain().getDriver(); llvm::Triple Triple = getToolChain().getTriple(); // Select the ABI to use. // // FIXME: Support -meabi. const char *ABIName = 0; if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { ABIName = A->getValue(Args); } else { // Select the default based on the platform. switch(Triple.getEnvironment()) { case llvm::Triple::GNUEABI: ABIName = "aapcs-linux"; break; case llvm::Triple::EABI: ABIName = "aapcs"; break; default: ABIName = "apcs-gnu"; } } CmdArgs.push_back("-target-abi"); CmdArgs.push_back(ABIName); // Set the CPU based on -march= and -mcpu=. CmdArgs.push_back("-target-cpu"); CmdArgs.push_back(getARMTargetCPU(Args, Triple)); // Select the float ABI as determined by -msoft-float, -mhard-float, and // -mfloat-abi=. StringRef FloatABI; if (Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, options::OPT_mfloat_abi_EQ)) { if (A->getOption().matches(options::OPT_msoft_float)) FloatABI = "soft"; else if (A->getOption().matches(options::OPT_mhard_float)) FloatABI = "hard"; else { FloatABI = A->getValue(Args); if (FloatABI != "soft" && FloatABI != "softfp" && FloatABI != "hard") { D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args); FloatABI = "soft"; } } } // If unspecified, choose the default based on the platform. if (FloatABI.empty()) { const llvm::Triple &Triple = getToolChain().getTriple(); switch (Triple.getOS()) { case llvm::Triple::Darwin: case llvm::Triple::MacOSX: case llvm::Triple::IOS: { // Darwin defaults to "softfp" for v6 and v7. // // FIXME: Factor out an ARM class so we can cache the arch somewhere. StringRef ArchName = getLLVMArchSuffixForARM(getARMTargetCPU(Args, Triple)); if (ArchName.startswith("v6") || ArchName.startswith("v7")) FloatABI = "softfp"; else FloatABI = "soft"; break; } case llvm::Triple::Linux: { if (getToolChain().getTriple().getEnvironment() == llvm::Triple::GNUEABI) { FloatABI = "softfp"; break; } } // fall through default: switch(Triple.getEnvironment()) { case llvm::Triple::GNUEABI: FloatABI = "softfp"; break; case llvm::Triple::EABI: // EABI is always AAPCS, and if it was not marked 'hard', it's softfp FloatABI = "softfp"; break; default: // Assume "soft", but warn the user we are guessing. FloatABI = "soft"; D.Diag(diag::warn_drv_assuming_mfloat_abi_is) << "soft"; break; } } } if (FloatABI == "soft") { // Floating point operations and argument passing are soft. // // FIXME: This changes CPP defines, we need -target-soft-float. CmdArgs.push_back("-msoft-float"); CmdArgs.push_back("-mfloat-abi"); CmdArgs.push_back("soft"); } else if (FloatABI == "softfp") { // Floating point operations are hard, but argument passing is soft. CmdArgs.push_back("-mfloat-abi"); CmdArgs.push_back("soft"); } else { // Floating point operations and argument passing are hard. assert(FloatABI == "hard" && "Invalid float abi!"); CmdArgs.push_back("-mfloat-abi"); CmdArgs.push_back("hard"); } // Set appropriate target features for floating point mode. // // FIXME: Note, this is a hack, the LLVM backend doesn't actually use these // yet (it uses the -mfloat-abi and -msoft-float options above), and it is // stripped out by the ARM target. // Use software floating point operations? if (FloatABI == "soft") { CmdArgs.push_back("-target-feature"); CmdArgs.push_back("+soft-float"); } // Use software floating point argument passing? if (FloatABI != "hard") { CmdArgs.push_back("-target-feature"); CmdArgs.push_back("+soft-float-abi"); } // Honor -mfpu=. // // FIXME: Centralize feature selection, defaulting shouldn't be also in the // frontend target. if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) { StringRef FPU = A->getValue(Args); // Set the target features based on the FPU. if (FPU == "fpa" || FPU == "fpe2" || FPU == "fpe3" || FPU == "maverick") { // Disable any default FPU support. CmdArgs.push_back("-target-feature"); CmdArgs.push_back("-vfp2"); CmdArgs.push_back("-target-feature"); CmdArgs.push_back("-vfp3"); CmdArgs.push_back("-target-feature"); CmdArgs.push_back("-neon"); } else if (FPU == "vfp") { CmdArgs.push_back("-target-feature"); CmdArgs.push_back("+vfp2"); } else if (FPU == "vfp3") { CmdArgs.push_back("-target-feature"); CmdArgs.push_back("+vfp3"); } else if (FPU == "neon") { CmdArgs.push_back("-target-feature"); CmdArgs.push_back("+neon"); } else D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); } // Setting -msoft-float effectively disables NEON because of the GCC // implementation, although the same isn't true of VFP or VFP3. if (FloatABI == "soft") { CmdArgs.push_back("-target-feature"); CmdArgs.push_back("-neon"); } // Kernel code has more strict alignment requirements. if (KernelOrKext) { CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-arm-long-calls"); CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-arm-strict-align"); // The kext linker doesn't know how to deal with movw/movt. CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-arm-darwin-use-movt=0"); } // Setting -mno-global-merge disables the codegen global merge pass. Setting // -mglobal-merge has no effect as the pass is enabled by default. if (Arg *A = Args.getLastArg(options::OPT_mglobal_merge, options::OPT_mno_global_merge)) { if (A->getOption().matches(options::OPT_mno_global_merge)) CmdArgs.push_back("-mno-global-merge"); } } // Get default architecture. static const char* getMipsArchFromCPU(StringRef CPUName) { if (CPUName == "mips32r1" || CPUName == "4ke") return "mips"; assert((CPUName == "mips64r1" || CPUName == "mips64r2") && "Unexpected cpu name."); return "mips64"; } // Get default target cpu. static const char* getMipsCPUFromArch(StringRef ArchName, const Driver &D) { if (ArchName == "mips" || ArchName == "mipsel") return "mips32r1"; else if (ArchName == "mips64" || ArchName == "mips64el") return "mips64r1"; else D.Diag(diag::err_drv_invalid_arch_name) << ArchName; return 0; } // Get default ABI. static const char* getMipsABIFromArch(StringRef ArchName) { if (ArchName == "mips" || ArchName == "mipsel") return "o32"; assert((ArchName == "mips64" || ArchName == "mips64el") && "Unexpected arch name."); return "n64"; } void Clang::AddMIPSTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { const Driver &D = getToolChain().getDriver(); StringRef ArchName; const char *CPUName; // Set target cpu and architecture. if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { CPUName = A->getValue(Args); ArchName = getMipsArchFromCPU(CPUName); } else { ArchName = Args.MakeArgString(getToolChain().getArchName()); CPUName = getMipsCPUFromArch(ArchName, D); } CmdArgs.push_back("-target-cpu"); CmdArgs.push_back(CPUName); // Select the ABI to use. const char *ABIName = 0; if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) ABIName = A->getValue(Args); else ABIName = getMipsABIFromArch(ArchName); CmdArgs.push_back("-target-abi"); CmdArgs.push_back(ABIName); // Select the float ABI as determined by -msoft-float, -mhard-float, and StringRef FloatABI; if (Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float)) { if (A->getOption().matches(options::OPT_msoft_float)) FloatABI = "soft"; else if (A->getOption().matches(options::OPT_mhard_float)) FloatABI = "hard"; } // If unspecified, choose the default based on the platform. if (FloatABI.empty()) { // Assume "soft", but warn the user we are guessing. FloatABI = "soft"; D.Diag(diag::warn_drv_assuming_mfloat_abi_is) << "soft"; } if (FloatABI == "soft") { // Floating point operations and argument passing are soft. // // FIXME: This changes CPP defines, we need -target-soft-float. CmdArgs.push_back("-msoft-float"); } else { assert(FloatABI == "hard" && "Invalid float abi!"); CmdArgs.push_back("-mhard-float"); } } void Clang::AddSparcTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { const Driver &D = getToolChain().getDriver(); if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { StringRef MArch = A->getValue(Args); CmdArgs.push_back("-target-cpu"); CmdArgs.push_back(MArch.str().c_str()); } // Select the float ABI as determined by -msoft-float, -mhard-float, and StringRef FloatABI; if (Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float)) { if (A->getOption().matches(options::OPT_msoft_float)) FloatABI = "soft"; else if (A->getOption().matches(options::OPT_mhard_float)) FloatABI = "hard"; } // If unspecified, choose the default based on the platform. if (FloatABI.empty()) { switch (getToolChain().getTriple().getOS()) { default: // Assume "soft", but warn the user we are guessing. FloatABI = "soft"; D.Diag(diag::warn_drv_assuming_mfloat_abi_is) << "soft"; break; } } if (FloatABI == "soft") { // Floating point operations and argument passing are soft. // // FIXME: This changes CPP defines, we need -target-soft-float. CmdArgs.push_back("-msoft-float"); CmdArgs.push_back("-target-feature"); CmdArgs.push_back("+soft-float"); } else { assert(FloatABI == "hard" && "Invalid float abi!"); CmdArgs.push_back("-mhard-float"); } } void Clang::AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { if (!Args.hasFlag(options::OPT_mred_zone, options::OPT_mno_red_zone, true) || Args.hasArg(options::OPT_mkernel) || Args.hasArg(options::OPT_fapple_kext)) CmdArgs.push_back("-disable-red-zone"); if (Args.hasFlag(options::OPT_msoft_float, options::OPT_mno_soft_float, false)) CmdArgs.push_back("-no-implicit-float"); const char *CPUName = 0; if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { if (StringRef(A->getValue(Args)) == "native") { // FIXME: Reject attempts to use -march=native unless the target matches // the host. // // FIXME: We should also incorporate the detected target features for use // with -native. std::string CPU = llvm::sys::getHostCPUName(); if (!CPU.empty()) CPUName = Args.MakeArgString(CPU); } else CPUName = A->getValue(Args); } // Select the default CPU if none was given (or detection failed). if (!CPUName) { // FIXME: Need target hooks. if (getToolChain().getTriple().isOSDarwin()) { if (getToolChain().getArch() == llvm::Triple::x86_64) CPUName = "core2"; else if (getToolChain().getArch() == llvm::Triple::x86) CPUName = "yonah"; } else if (getToolChain().getOS().startswith("haiku")) { if (getToolChain().getArch() == llvm::Triple::x86_64) CPUName = "x86-64"; else if (getToolChain().getArch() == llvm::Triple::x86) CPUName = "i586"; } else if (getToolChain().getOS().startswith("openbsd")) { if (getToolChain().getArch() == llvm::Triple::x86_64) CPUName = "x86-64"; else if (getToolChain().getArch() == llvm::Triple::x86) CPUName = "i486"; } else if (getToolChain().getOS().startswith("freebsd")) { if (getToolChain().getArch() == llvm::Triple::x86_64) CPUName = "x86-64"; else if (getToolChain().getArch() == llvm::Triple::x86) CPUName = "i486"; } else if (getToolChain().getOS().startswith("netbsd")) { if (getToolChain().getArch() == llvm::Triple::x86_64) CPUName = "x86-64"; else if (getToolChain().getArch() == llvm::Triple::x86) CPUName = "i486"; } else { if (getToolChain().getArch() == llvm::Triple::x86_64) CPUName = "x86-64"; else if (getToolChain().getArch() == llvm::Triple::x86) CPUName = "pentium4"; } } if (CPUName) { CmdArgs.push_back("-target-cpu"); CmdArgs.push_back(CPUName); } // The required algorithm here is slightly strange: the options are applied // in order (so -mno-sse -msse2 disables SSE3), but any option that gets // directly overridden later is ignored (so "-mno-sse -msse2 -mno-sse2 -msse" // is equivalent to "-mno-sse2 -msse"). The -cc1 handling deals with the // former correctly, but not the latter; handle directly-overridden // attributes here. llvm::StringMap PrevFeature; std::vector Features; for (arg_iterator it = Args.filtered_begin(options::OPT_m_x86_Features_Group), ie = Args.filtered_end(); it != ie; ++it) { StringRef Name = (*it)->getOption().getName(); (*it)->claim(); // Skip over "-m". assert(Name.startswith("-m") && "Invalid feature name."); Name = Name.substr(2); bool IsNegative = Name.startswith("no-"); if (IsNegative) Name = Name.substr(3); unsigned& Prev = PrevFeature[Name]; if (Prev) Features[Prev - 1] = 0; Prev = Features.size() + 1; Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name)); } for (unsigned i = 0; i < Features.size(); i++) { if (Features[i]) { CmdArgs.push_back("-target-feature"); CmdArgs.push_back(Features[i]); } } } static bool shouldUseExceptionTablesForObjCExceptions(unsigned objcABIVersion, const llvm::Triple &Triple) { // We use the zero-cost exception tables for Objective-C if the non-fragile // ABI is enabled or when compiling for x86_64 and ARM on Snow Leopard and // later. if (objcABIVersion >= 2) return true; if (!Triple.isOSDarwin()) return false; return (!Triple.isMacOSXVersionLT(10,5) && (Triple.getArch() == llvm::Triple::x86_64 || Triple.getArch() == llvm::Triple::arm)); } /// addExceptionArgs - Adds exception related arguments to the driver command /// arguments. There's a master flag, -fexceptions and also language specific /// flags to enable/disable C++ and Objective-C exceptions. /// This makes it possible to for example disable C++ exceptions but enable /// Objective-C exceptions. static void addExceptionArgs(const ArgList &Args, types::ID InputType, const llvm::Triple &Triple, bool KernelOrKext, bool IsRewriter, unsigned objcABIVersion, ArgStringList &CmdArgs) { if (KernelOrKext) return; // Exceptions are enabled by default. bool ExceptionsEnabled = true; // This keeps track of whether exceptions were explicitly turned on or off. bool DidHaveExplicitExceptionFlag = false; if (Arg *A = Args.getLastArg(options::OPT_fexceptions, options::OPT_fno_exceptions)) { if (A->getOption().matches(options::OPT_fexceptions)) ExceptionsEnabled = true; else ExceptionsEnabled = false; DidHaveExplicitExceptionFlag = true; } bool ShouldUseExceptionTables = false; // Exception tables and cleanups can be enabled with -fexceptions even if the // language itself doesn't support exceptions. if (ExceptionsEnabled && DidHaveExplicitExceptionFlag) ShouldUseExceptionTables = true; // Obj-C exceptions are enabled by default, regardless of -fexceptions. This // is not necessarily sensible, but follows GCC. if (types::isObjC(InputType) && Args.hasFlag(options::OPT_fobjc_exceptions, options::OPT_fno_objc_exceptions, true)) { CmdArgs.push_back("-fobjc-exceptions"); ShouldUseExceptionTables |= shouldUseExceptionTablesForObjCExceptions(objcABIVersion, Triple); } if (types::isCXX(InputType)) { bool CXXExceptionsEnabled = ExceptionsEnabled; if (Arg *A = Args.getLastArg(options::OPT_fcxx_exceptions, options::OPT_fno_cxx_exceptions, options::OPT_fexceptions, options::OPT_fno_exceptions)) { if (A->getOption().matches(options::OPT_fcxx_exceptions)) CXXExceptionsEnabled = true; else if (A->getOption().matches(options::OPT_fno_cxx_exceptions)) CXXExceptionsEnabled = false; } if (CXXExceptionsEnabled) { CmdArgs.push_back("-fcxx-exceptions"); ShouldUseExceptionTables = true; } } if (ShouldUseExceptionTables) CmdArgs.push_back("-fexceptions"); } static bool ShouldDisableCFI(const ArgList &Args, const ToolChain &TC) { if (TC.getTriple().isOSDarwin()) { // The native darwin assembler doesn't support cfi directives, so // we disable them if we think the .s file will be passed to it. // FIXME: Duplicated code with ToolChains.cpp // FIXME: This doesn't belong here, but ideally we will support static soon // anyway. bool HasStatic = (Args.hasArg(options::OPT_mkernel) || Args.hasArg(options::OPT_static) || Args.hasArg(options::OPT_fapple_kext)); bool IsIADefault = TC.IsIntegratedAssemblerDefault() && !HasStatic; bool UseIntegratedAs = Args.hasFlag(options::OPT_integrated_as, options::OPT_no_integrated_as, IsIADefault); bool UseCFI = Args.hasFlag(options::OPT_fdwarf2_cfi_asm, options::OPT_fno_dwarf2_cfi_asm, UseIntegratedAs); return !UseCFI; } // For now we assume that every other assembler support CFI. return false; } /// \brief Check whether the given input tree contains any compilation actions. static bool ContainsCompileAction(const Action *A) { if (isa(A)) return true; for (Action::const_iterator it = A->begin(), ie = A->end(); it != ie; ++it) if (ContainsCompileAction(*it)) return true; return false; } /// \brief Check if -relax-all should be passed to the internal assembler. /// This is done by default when compiling non-assembler source with -O0. static bool UseRelaxAll(Compilation &C, const ArgList &Args) { bool RelaxDefault = true; if (Arg *A = Args.getLastArg(options::OPT_O_Group)) RelaxDefault = A->getOption().matches(options::OPT_O0); if (RelaxDefault) { RelaxDefault = false; for (ActionList::const_iterator it = C.getActions().begin(), ie = C.getActions().end(); it != ie; ++it) { if (ContainsCompileAction(*it)) { RelaxDefault = true; break; } } } return Args.hasFlag(options::OPT_mrelax_all, options::OPT_mno_relax_all, RelaxDefault); } void Clang::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { bool KernelOrKext = Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; assert(Inputs.size() == 1 && "Unable to handle multiple inputs."); // Invoke ourselves in -cc1 mode. // // FIXME: Implement custom jobs for internal actions. CmdArgs.push_back("-cc1"); // Add the "effective" target triple. CmdArgs.push_back("-triple"); std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args); CmdArgs.push_back(Args.MakeArgString(TripleStr)); // Select the appropriate action. bool IsRewriter = false; if (isa(JA)) { assert(JA.getType() == types::TY_Plist && "Invalid output type."); CmdArgs.push_back("-analyze"); } else if (isa(JA)) { if (Output.getType() == types::TY_Dependencies) CmdArgs.push_back("-Eonly"); else CmdArgs.push_back("-E"); } else if (isa(JA)) { CmdArgs.push_back("-emit-obj"); if (UseRelaxAll(C, Args)) CmdArgs.push_back("-mrelax-all"); // When using an integrated assembler, translate -Wa, and -Xassembler // options. for (arg_iterator it = Args.filtered_begin(options::OPT_Wa_COMMA, options::OPT_Xassembler), ie = Args.filtered_end(); it != ie; ++it) { const Arg *A = *it; A->claim(); for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) { StringRef Value = A->getValue(Args, i); if (Value == "-force_cpusubtype_ALL") { // Do nothing, this is the default and we don't support anything else. } else if (Value == "-L") { CmdArgs.push_back("-msave-temp-labels"); } else if (Value == "--fatal-warnings") { CmdArgs.push_back("-mllvm"); CmdArgs.push_back("-fatal-assembler-warnings"); } else if (Value == "--noexecstack") { CmdArgs.push_back("-mnoexecstack"); } else { D.Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Value; } } } // Also ignore explicit -force_cpusubtype_ALL option. (void) Args.hasArg(options::OPT_force__cpusubtype__ALL); } else if (isa(JA)) { // Use PCH if the user requested it. bool UsePCH = D.CCCUsePCH; if (UsePCH) CmdArgs.push_back("-emit-pch"); else CmdArgs.push_back("-emit-pth"); } else { assert(isa(JA) && "Invalid action for clang tool."); if (JA.getType() == types::TY_Nothing) { CmdArgs.push_back("-fsyntax-only"); } else if (JA.getType() == types::TY_LLVM_IR || JA.getType() == types::TY_LTO_IR) { CmdArgs.push_back("-emit-llvm"); } else if (JA.getType() == types::TY_LLVM_BC || JA.getType() == types::TY_LTO_BC) { CmdArgs.push_back("-emit-llvm-bc"); } else if (JA.getType() == types::TY_PP_Asm) { CmdArgs.push_back("-S"); } else if (JA.getType() == types::TY_AST) { CmdArgs.push_back("-emit-pch"); } else if (JA.getType() == types::TY_RewrittenObjC) { CmdArgs.push_back("-rewrite-objc"); IsRewriter = true; } else { assert(JA.getType() == types::TY_PP_Asm && "Unexpected output type!"); } } // The make clang go fast button. CmdArgs.push_back("-disable-free"); // Disable the verification pass in -asserts builds. #ifdef NDEBUG CmdArgs.push_back("-disable-llvm-verifier"); #endif // Set the main file name, so that debug info works even with // -save-temps. CmdArgs.push_back("-main-file-name"); CmdArgs.push_back(darwin::CC1::getBaseInputName(Args, Inputs)); // Some flags which affect the language (via preprocessor // defines). See darwin::CC1::AddCPPArgs. if (Args.hasArg(options::OPT_static)) CmdArgs.push_back("-static-define"); if (isa(JA)) { // Enable region store model by default. CmdArgs.push_back("-analyzer-store=region"); // Treat blocks as analysis entry points. CmdArgs.push_back("-analyzer-opt-analyze-nested-blocks"); CmdArgs.push_back("-analyzer-eagerly-assume"); // Add default argument set. if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) { CmdArgs.push_back("-analyzer-checker=core"); CmdArgs.push_back("-analyzer-checker=deadcode"); CmdArgs.push_back("-analyzer-checker=security"); if (getToolChain().getTriple().getOS() != llvm::Triple::Win32) CmdArgs.push_back("-analyzer-checker=unix"); if (getToolChain().getTriple().getVendor() == llvm::Triple::Apple) CmdArgs.push_back("-analyzer-checker=osx"); } // Set the output format. The default is plist, for (lame) historical // reasons. CmdArgs.push_back("-analyzer-output"); if (Arg *A = Args.getLastArg(options::OPT__analyzer_output)) CmdArgs.push_back(A->getValue(Args)); else CmdArgs.push_back("plist"); // Disable the presentation of standard compiler warnings when // using --analyze. We only want to show static analyzer diagnostics // or frontend errors. CmdArgs.push_back("-w"); // Add -Xanalyzer arguments when running as analyzer. Args.AddAllArgValues(CmdArgs, options::OPT_Xanalyzer); } CheckCodeGenerationOptions(D, Args); // Perform argument translation for LLVM backend. This // takes some care in reconciling with llvm-gcc. The // issue is that llvm-gcc translates these options based on // the values in cc1, whereas we are processing based on // the driver arguments. // This comes from the default translation the driver + cc1 // would do to enable flag_pic. // // FIXME: Centralize this code. bool PICEnabled = (Args.hasArg(options::OPT_fPIC) || Args.hasArg(options::OPT_fpic) || Args.hasArg(options::OPT_fPIE) || Args.hasArg(options::OPT_fpie)); bool PICDisabled = (Args.hasArg(options::OPT_mkernel) || Args.hasArg(options::OPT_static)); const char *Model = getToolChain().GetForcedPicModel(); if (!Model) { if (Args.hasArg(options::OPT_mdynamic_no_pic)) Model = "dynamic-no-pic"; else if (PICDisabled) Model = "static"; else if (PICEnabled) Model = "pic"; else Model = getToolChain().GetDefaultRelocationModel(); } if (StringRef(Model) != "pic") { CmdArgs.push_back("-mrelocation-model"); CmdArgs.push_back(Model); } // Infer the __PIC__ value. // // FIXME: This isn't quite right on Darwin, which always sets // __PIC__=2. if (strcmp(Model, "pic") == 0 || strcmp(Model, "dynamic-no-pic") == 0) { CmdArgs.push_back("-pic-level"); CmdArgs.push_back(Args.hasArg(options::OPT_fPIC) ? "2" : "1"); } if (!Args.hasFlag(options::OPT_fmerge_all_constants, options::OPT_fno_merge_all_constants)) CmdArgs.push_back("-fno-merge-all-constants"); // LLVM Code Generator Options. if (Arg *A = Args.getLastArg(options::OPT_mregparm_EQ)) { CmdArgs.push_back("-mregparm"); CmdArgs.push_back(A->getValue(Args)); } if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false)) CmdArgs.push_back("-mrtd"); // FIXME: Set --enable-unsafe-fp-math. if (Args.hasFlag(options::OPT_fno_omit_frame_pointer, options::OPT_fomit_frame_pointer)) CmdArgs.push_back("-mdisable-fp-elim"); if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss, options::OPT_fno_zero_initialized_in_bss)) CmdArgs.push_back("-mno-zero-initialized-in-bss"); if (!Args.hasFlag(options::OPT_fstrict_aliasing, options::OPT_fno_strict_aliasing, getToolChain().IsStrictAliasingDefault())) CmdArgs.push_back("-relaxed-aliasing"); // Decide whether to use verbose asm. Verbose assembly is the default on // toolchains which have the integrated assembler on by default. bool IsVerboseAsmDefault = getToolChain().IsIntegratedAssemblerDefault(); if (Args.hasFlag(options::OPT_fverbose_asm, options::OPT_fno_verbose_asm, IsVerboseAsmDefault) || Args.hasArg(options::OPT_dA)) CmdArgs.push_back("-masm-verbose"); if (Args.hasArg(options::OPT_fdebug_pass_structure)) { CmdArgs.push_back("-mdebug-pass"); CmdArgs.push_back("Structure"); } if (Args.hasArg(options::OPT_fdebug_pass_arguments)) { CmdArgs.push_back("-mdebug-pass"); CmdArgs.push_back("Arguments"); } // Enable -mconstructor-aliases except on darwin, where we have to // work around a linker bug; see . if (!getToolChain().getTriple().isOSDarwin()) CmdArgs.push_back("-mconstructor-aliases"); // Darwin's kernel doesn't support guard variables; just die if we // try to use them. if (KernelOrKext && getToolChain().getTriple().isOSDarwin()) CmdArgs.push_back("-fforbid-guard-variables"); if (Args.hasArg(options::OPT_mms_bitfields)) { CmdArgs.push_back("-mms-bitfields"); } // This is a coarse approximation of what llvm-gcc actually does, both // -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more // complicated ways. bool AsynchronousUnwindTables = Args.hasFlag(options::OPT_fasynchronous_unwind_tables, options::OPT_fno_asynchronous_unwind_tables, getToolChain().IsUnwindTablesDefault() && !KernelOrKext); if (Args.hasFlag(options::OPT_funwind_tables, options::OPT_fno_unwind_tables, AsynchronousUnwindTables)) CmdArgs.push_back("-munwind-tables"); if (Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) { CmdArgs.push_back("-mlimit-float-precision"); CmdArgs.push_back(A->getValue(Args)); } // FIXME: Handle -mtune=. (void) Args.hasArg(options::OPT_mtune_EQ); if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) { CmdArgs.push_back("-mcode-model"); CmdArgs.push_back(A->getValue(Args)); } // Add target specific cpu and features flags. switch(getToolChain().getTriple().getArch()) { default: break; case llvm::Triple::arm: case llvm::Triple::thumb: AddARMTargetArgs(Args, CmdArgs, KernelOrKext); break; case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::mips64: case llvm::Triple::mips64el: AddMIPSTargetArgs(Args, CmdArgs); break; case llvm::Triple::sparc: AddSparcTargetArgs(Args, CmdArgs); break; case llvm::Triple::x86: case llvm::Triple::x86_64: AddX86TargetArgs(Args, CmdArgs); break; } // Pass the linker version in use. if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) { CmdArgs.push_back("-target-linker-version"); CmdArgs.push_back(A->getValue(Args)); } // -mno-omit-leaf-frame-pointer is the default on Darwin. if (Args.hasFlag(options::OPT_momit_leaf_frame_pointer, options::OPT_mno_omit_leaf_frame_pointer, !getToolChain().getTriple().isOSDarwin())) CmdArgs.push_back("-momit-leaf-frame-pointer"); // -fno-math-errno is default. if (Args.hasFlag(options::OPT_fmath_errno, options::OPT_fno_math_errno, false)) CmdArgs.push_back("-fmath-errno"); // Explicitly error on some things we know we don't support and can't just // ignore. types::ID InputType = Inputs[0].getType(); if (!Args.hasArg(options::OPT_fallow_unsupported)) { Arg *Unsupported; if ((Unsupported = Args.getLastArg(options::OPT_iframework))) D.Diag(diag::err_drv_clang_unsupported) << Unsupported->getOption().getName(); if (types::isCXX(InputType) && getToolChain().getTriple().isOSDarwin() && getToolChain().getTriple().getArch() == llvm::Triple::x86) { if ((Unsupported = Args.getLastArg(options::OPT_fapple_kext)) || (Unsupported = Args.getLastArg(options::OPT_mkernel))) D.Diag(diag::err_drv_clang_unsupported_opt_cxx_darwin_i386) << Unsupported->getOption().getName(); } } Args.AddAllArgs(CmdArgs, options::OPT_v); Args.AddLastArg(CmdArgs, options::OPT_H); if (D.CCPrintHeaders && !D.CCGenDiagnostics) { CmdArgs.push_back("-header-include-file"); CmdArgs.push_back(D.CCPrintHeadersFilename ? D.CCPrintHeadersFilename : "-"); } Args.AddLastArg(CmdArgs, options::OPT_P); Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout); if (D.CCLogDiagnostics && !D.CCGenDiagnostics) { CmdArgs.push_back("-diagnostic-log-file"); CmdArgs.push_back(D.CCLogDiagnosticsFilename ? D.CCLogDiagnosticsFilename : "-"); } // Special case debug options to only pass -g to clang. This is // wrong. Args.ClaimAllArgs(options::OPT_g_Group); if (Arg *A = Args.getLastArg(options::OPT_g_Group)) if (!A->getOption().matches(options::OPT_g0)) CmdArgs.push_back("-g"); Args.AddAllArgs(CmdArgs, options::OPT_ffunction_sections); Args.AddAllArgs(CmdArgs, options::OPT_fdata_sections); Args.AddAllArgs(CmdArgs, options::OPT_finstrument_functions); if (Args.hasArg(options::OPT_ftest_coverage) || Args.hasArg(options::OPT_coverage)) CmdArgs.push_back("-femit-coverage-notes"); if (Args.hasArg(options::OPT_fprofile_arcs) || Args.hasArg(options::OPT_coverage)) CmdArgs.push_back("-femit-coverage-data"); if (C.getArgs().hasArg(options::OPT_c) || C.getArgs().hasArg(options::OPT_S)) { if (Output.isFilename()) { CmdArgs.push_back("-coverage-file"); CmdArgs.push_back(Args.MakeArgString(Output.getFilename())); } } // Pass options for controlling the default header search paths. if (Args.hasArg(options::OPT_nostdinc)) { CmdArgs.push_back("-nostdsysteminc"); CmdArgs.push_back("-nobuiltininc"); } else { if (Args.hasArg(options::OPT_nostdlibinc)) CmdArgs.push_back("-nostdsysteminc"); Args.AddLastArg(CmdArgs, options::OPT_nostdincxx); Args.AddLastArg(CmdArgs, options::OPT_nobuiltininc); } // Pass the path to compiler resource files. CmdArgs.push_back("-resource-dir"); CmdArgs.push_back(D.ResourceDir.c_str()); Args.AddLastArg(CmdArgs, options::OPT_working_directory); if (!Args.hasArg(options::OPT_fno_objc_arc)) { if (const Arg *A = Args.getLastArg(options::OPT_ccc_arcmt_check, options::OPT_ccc_arcmt_modify, options::OPT_ccc_arcmt_migrate)) { switch (A->getOption().getID()) { default: llvm_unreachable("missed a case"); case options::OPT_ccc_arcmt_check: CmdArgs.push_back("-arcmt-check"); break; case options::OPT_ccc_arcmt_modify: CmdArgs.push_back("-arcmt-modify"); break; case options::OPT_ccc_arcmt_migrate: CmdArgs.push_back("-arcmt-migrate"); CmdArgs.push_back("-arcmt-migrate-directory"); CmdArgs.push_back(A->getValue(Args)); Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_report_output); Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_emit_arc_errors); break; } } } // Add preprocessing options like -I, -D, etc. if we are using the // preprocessor. // // FIXME: Support -fpreprocessed if (types::getPreprocessedType(InputType) != types::TY_INVALID) AddPreprocessingOptions(D, Args, CmdArgs, Output, Inputs); // Don't warn about "clang -c -DPIC -fPIC test.i" because libtool.m4 assumes // that "The compiler can only warn and ignore the option if not recognized". // When building with ccache, it will pass -D options to clang even on // preprocessed inputs and configure concludes that -fPIC is not supported. Args.ClaimAllArgs(options::OPT_D); // Manually translate -O to -O2 and -O4 to -O3; let clang reject // others. if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { if (A->getOption().matches(options::OPT_O4)) CmdArgs.push_back("-O3"); else if (A->getOption().matches(options::OPT_O) && A->getValue(Args)[0] == '\0') CmdArgs.push_back("-O2"); else A->render(Args, CmdArgs); } Args.AddAllArgs(CmdArgs, options::OPT_W_Group); Args.AddLastArg(CmdArgs, options::OPT_pedantic); Args.AddLastArg(CmdArgs, options::OPT_pedantic_errors); Args.AddLastArg(CmdArgs, options::OPT_w); // Handle -{std, ansi, trigraphs} -- take the last of -{std, ansi} // (-ansi is equivalent to -std=c89). // // If a std is supplied, only add -trigraphs if it follows the // option. if (Arg *Std = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi)) { if (Std->getOption().matches(options::OPT_ansi)) if (types::isCXX(InputType)) CmdArgs.push_back("-std=c++98"); else CmdArgs.push_back("-std=c89"); else Std->render(Args, CmdArgs); if (Arg *A = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi, options::OPT_trigraphs)) if (A != Std) A->render(Args, CmdArgs); } else { // Honor -std-default. // // FIXME: Clang doesn't correctly handle -std= when the input language // doesn't match. For the time being just ignore this for C++ inputs; // eventually we want to do all the standard defaulting here instead of // splitting it between the driver and clang -cc1. if (!types::isCXX(InputType)) Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ, "-std=", /*Joined=*/true); Args.AddLastArg(CmdArgs, options::OPT_trigraphs); } // Map the bizarre '-Wwrite-strings' flag to a more sensible // '-fconst-strings'; this better indicates its actual behavior. if (Args.hasFlag(options::OPT_Wwrite_strings, options::OPT_Wno_write_strings, false)) { // For perfect compatibility with GCC, we do this even in the presence of // '-w'. This flag names something other than a warning for GCC. CmdArgs.push_back("-fconst-strings"); } // GCC provides a macro definition '__DEPRECATED' when -Wdeprecated is active // during C++ compilation, which it is by default. GCC keeps this define even // in the presence of '-w', match this behavior bug-for-bug. if (types::isCXX(InputType) && Args.hasFlag(options::OPT_Wdeprecated, options::OPT_Wno_deprecated, true)) { CmdArgs.push_back("-fdeprecated-macro"); } // Translate GCC's misnamer '-fasm' arguments to '-fgnu-keywords'. if (Arg *Asm = Args.getLastArg(options::OPT_fasm, options::OPT_fno_asm)) { if (Asm->getOption().matches(options::OPT_fasm)) CmdArgs.push_back("-fgnu-keywords"); else CmdArgs.push_back("-fno-gnu-keywords"); } if (ShouldDisableCFI(Args, getToolChain())) CmdArgs.push_back("-fno-dwarf2-cfi-asm"); if (Arg *A = Args.getLastArg(options::OPT_ftemplate_depth_)) { CmdArgs.push_back("-ftemplate-depth"); CmdArgs.push_back(A->getValue(Args)); } if (Arg *A = Args.getLastArg(options::OPT_Wlarge_by_value_copy_EQ, options::OPT_Wlarge_by_value_copy_def)) { CmdArgs.push_back("-Wlarge-by-value-copy"); if (A->getNumValues()) CmdArgs.push_back(A->getValue(Args)); else CmdArgs.push_back("64"); // default value for -Wlarge-by-value-copy. } if (Args.hasArg(options::OPT__relocatable_pch)) CmdArgs.push_back("-relocatable-pch"); if (Arg *A = Args.getLastArg(options::OPT_fconstant_string_class_EQ)) { CmdArgs.push_back("-fconstant-string-class"); CmdArgs.push_back(A->getValue(Args)); } if (Arg *A = Args.getLastArg(options::OPT_ftabstop_EQ)) { CmdArgs.push_back("-ftabstop"); CmdArgs.push_back(A->getValue(Args)); } CmdArgs.push_back("-ferror-limit"); if (Arg *A = Args.getLastArg(options::OPT_ferror_limit_EQ)) CmdArgs.push_back(A->getValue(Args)); else CmdArgs.push_back("19"); if (Arg *A = Args.getLastArg(options::OPT_fmacro_backtrace_limit_EQ)) { CmdArgs.push_back("-fmacro-backtrace-limit"); CmdArgs.push_back(A->getValue(Args)); } if (Arg *A = Args.getLastArg(options::OPT_ftemplate_backtrace_limit_EQ)) { CmdArgs.push_back("-ftemplate-backtrace-limit"); CmdArgs.push_back(A->getValue(Args)); } // Pass -fmessage-length=. CmdArgs.push_back("-fmessage-length"); if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) { CmdArgs.push_back(A->getValue(Args)); } else { // If -fmessage-length=N was not specified, determine whether this is a // terminal and, if so, implicitly define -fmessage-length appropriately. unsigned N = llvm::sys::Process::StandardErrColumns(); CmdArgs.push_back(Args.MakeArgString(Twine(N))); } if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ)) { CmdArgs.push_back("-fvisibility"); CmdArgs.push_back(A->getValue(Args)); } Args.AddLastArg(CmdArgs, options::OPT_fvisibility_inlines_hidden); // -fhosted is default. if (KernelOrKext || Args.hasFlag(options::OPT_ffreestanding, options::OPT_fhosted, false)) CmdArgs.push_back("-ffreestanding"); // Forward -f (flag) options which we can pass directly. Args.AddLastArg(CmdArgs, options::OPT_fcatch_undefined_behavior); Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls); Args.AddLastArg(CmdArgs, options::OPT_fformat_extensions); Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions); Args.AddLastArg(CmdArgs, options::OPT_flimit_debug_info); if (getToolChain().SupportsProfiling()) Args.AddLastArg(CmdArgs, options::OPT_pg); // -flax-vector-conversions is default. if (!Args.hasFlag(options::OPT_flax_vector_conversions, options::OPT_fno_lax_vector_conversions)) CmdArgs.push_back("-fno-lax-vector-conversions"); if (Args.getLastArg(options::OPT_fapple_kext)) CmdArgs.push_back("-fapple-kext"); Args.AddLastArg(CmdArgs, options::OPT_fobjc_sender_dependent_dispatch); Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info); Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_parseable_fixits); Args.AddLastArg(CmdArgs, options::OPT_ftime_report); Args.AddLastArg(CmdArgs, options::OPT_ftrapv); if (Arg *A = Args.getLastArg(options::OPT_ftrapv_handler_EQ)) { CmdArgs.push_back("-ftrapv-handler"); CmdArgs.push_back(A->getValue(Args)); } // Forward -ftrap_function= options to the backend. if (Arg *A = Args.getLastArg(options::OPT_ftrap_function_EQ)) { StringRef FuncName = A->getValue(Args); CmdArgs.push_back("-backend-option"); CmdArgs.push_back(Args.MakeArgString("-trap-func=" + FuncName)); } // -fno-strict-overflow implies -fwrapv if it isn't disabled, but // -fstrict-overflow won't turn off an explicitly enabled -fwrapv. if (Arg *A = Args.getLastArg(options::OPT_fwrapv, options::OPT_fno_wrapv)) { if (A->getOption().matches(options::OPT_fwrapv)) CmdArgs.push_back("-fwrapv"); } else if (Arg *A = Args.getLastArg(options::OPT_fstrict_overflow, options::OPT_fno_strict_overflow)) { if (A->getOption().matches(options::OPT_fno_strict_overflow)) CmdArgs.push_back("-fwrapv"); } Args.AddLastArg(CmdArgs, options::OPT_fwritable_strings); Args.AddLastArg(CmdArgs, options::OPT_funroll_loops); Args.AddLastArg(CmdArgs, options::OPT_pthread); // -stack-protector=0 is default. unsigned StackProtectorLevel = 0; if (Arg *A = Args.getLastArg(options::OPT_fno_stack_protector, options::OPT_fstack_protector_all, options::OPT_fstack_protector)) { if (A->getOption().matches(options::OPT_fstack_protector)) StackProtectorLevel = 1; else if (A->getOption().matches(options::OPT_fstack_protector_all)) StackProtectorLevel = 2; } else { StackProtectorLevel = getToolChain().GetDefaultStackProtectorLevel(KernelOrKext); } if (StackProtectorLevel) { CmdArgs.push_back("-stack-protector"); CmdArgs.push_back(Args.MakeArgString(Twine(StackProtectorLevel))); } // Translate -mstackrealign if (Args.hasArg(options::OPT_mstackrealign)) { CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-force-align-stack"); } // Forward -f options with positive and negative forms; we translate // these by hand. if (Args.hasArg(options::OPT_mkernel)) { if (!Args.hasArg(options::OPT_fapple_kext) && types::isCXX(InputType)) CmdArgs.push_back("-fapple-kext"); if (!Args.hasArg(options::OPT_fbuiltin)) CmdArgs.push_back("-fno-builtin"); } // -fbuiltin is default. else if (!Args.hasFlag(options::OPT_fbuiltin, options::OPT_fno_builtin)) CmdArgs.push_back("-fno-builtin"); if (!Args.hasFlag(options::OPT_fassume_sane_operator_new, options::OPT_fno_assume_sane_operator_new)) CmdArgs.push_back("-fno-assume-sane-operator-new"); // -fblocks=0 is default. if (Args.hasFlag(options::OPT_fblocks, options::OPT_fno_blocks, getToolChain().IsBlocksDefault()) || (Args.hasArg(options::OPT_fgnu_runtime) && Args.hasArg(options::OPT_fobjc_nonfragile_abi) && !Args.hasArg(options::OPT_fno_blocks))) { CmdArgs.push_back("-fblocks"); if (!Args.hasArg(options::OPT_fgnu_runtime) && !getToolChain().hasBlocksRuntime()) CmdArgs.push_back("-fblocks-runtime-optional"); } // -faccess-control is default. if (Args.hasFlag(options::OPT_fno_access_control, options::OPT_faccess_control, false)) CmdArgs.push_back("-fno-access-control"); // -felide-constructors is the default. if (Args.hasFlag(options::OPT_fno_elide_constructors, options::OPT_felide_constructors, false)) CmdArgs.push_back("-fno-elide-constructors"); // -frtti is default. if (KernelOrKext || !Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti)) CmdArgs.push_back("-fno-rtti"); // -fshort-enums=0 is default. // FIXME: Are there targers where -fshort-enums is on by default ? if (Args.hasFlag(options::OPT_fshort_enums, options::OPT_fno_short_enums, false)) CmdArgs.push_back("-fshort-enums"); // -fsigned-char is default. if (!Args.hasFlag(options::OPT_fsigned_char, options::OPT_funsigned_char, isSignedCharDefault(getToolChain().getTriple()))) CmdArgs.push_back("-fno-signed-char"); // -fthreadsafe-static is default. if (!Args.hasFlag(options::OPT_fthreadsafe_statics, options::OPT_fno_threadsafe_statics)) CmdArgs.push_back("-fno-threadsafe-statics"); // -fuse-cxa-atexit is default. if (KernelOrKext || !Args.hasFlag(options::OPT_fuse_cxa_atexit, options::OPT_fno_use_cxa_atexit, getToolChain().getTriple().getOS() != llvm::Triple::Cygwin && getToolChain().getTriple().getOS() != llvm::Triple::MinGW32)) CmdArgs.push_back("-fno-use-cxa-atexit"); // -fms-extensions=0 is default. if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, getToolChain().getTriple().getOS() == llvm::Triple::Win32)) CmdArgs.push_back("-fms-extensions"); // -fms-compatibility=0 is default. if (Args.hasFlag(options::OPT_fms_compatibility, options::OPT_fno_ms_compatibility, getToolChain().getTriple().getOS() == llvm::Triple::Win32)) CmdArgs.push_back("-fms-compatibility"); // -fmsc-version=1300 is default. if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, getToolChain().getTriple().getOS() == llvm::Triple::Win32) || Args.hasArg(options::OPT_fmsc_version)) { StringRef msc_ver = Args.getLastArgValue(options::OPT_fmsc_version); if (msc_ver.empty()) CmdArgs.push_back("-fmsc-version=1300"); else CmdArgs.push_back(Args.MakeArgString("-fmsc-version=" + msc_ver)); } // -fborland-extensions=0 is default. if (Args.hasFlag(options::OPT_fborland_extensions, options::OPT_fno_borland_extensions, false)) CmdArgs.push_back("-fborland-extensions"); // -fno-delayed-template-parsing is default, except for Windows where MSVC STL // needs it. if (Args.hasFlag(options::OPT_fdelayed_template_parsing, options::OPT_fno_delayed_template_parsing, getToolChain().getTriple().getOS() == llvm::Triple::Win32)) CmdArgs.push_back("-fdelayed-template-parsing"); // -fgnu-keywords default varies depending on language; only pass if // specified. if (Arg *A = Args.getLastArg(options::OPT_fgnu_keywords, options::OPT_fno_gnu_keywords)) A->render(Args, CmdArgs); if (Args.hasFlag(options::OPT_fgnu89_inline, options::OPT_fno_gnu89_inline, false)) CmdArgs.push_back("-fgnu89-inline"); // -fobjc-nonfragile-abi=0 is default. ObjCRuntime objCRuntime; unsigned objcABIVersion = 0; bool NeXTRuntimeIsDefault = (IsRewriter || getToolChain().getTriple().isOSDarwin()); if (Args.hasFlag(options::OPT_fnext_runtime, options::OPT_fgnu_runtime, NeXTRuntimeIsDefault)) { objCRuntime.setKind(ObjCRuntime::NeXT); } else { CmdArgs.push_back("-fgnu-runtime"); objCRuntime.setKind(ObjCRuntime::GNU); } getToolChain().configureObjCRuntime(objCRuntime); if (objCRuntime.HasARC) CmdArgs.push_back("-fobjc-runtime-has-arc"); if (objCRuntime.HasWeak) CmdArgs.push_back("-fobjc-runtime-has-weak"); if (objCRuntime.HasTerminate) CmdArgs.push_back("-fobjc-runtime-has-terminate"); // Compute the Objective-C ABI "version" to use. Version numbers are // slightly confusing for historical reasons: // 1 - Traditional "fragile" ABI // 2 - Non-fragile ABI, version 1 // 3 - Non-fragile ABI, version 2 objcABIVersion = 1; // If -fobjc-abi-version= is present, use that to set the version. if (Arg *A = Args.getLastArg(options::OPT_fobjc_abi_version_EQ)) { if (StringRef(A->getValue(Args)) == "1") objcABIVersion = 1; else if (StringRef(A->getValue(Args)) == "2") objcABIVersion = 2; else if (StringRef(A->getValue(Args)) == "3") objcABIVersion = 3; else D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); } else { // Otherwise, determine if we are using the non-fragile ABI. bool NonFragileABIIsDefault = (!IsRewriter && getToolChain().IsObjCNonFragileABIDefault()); if (Args.hasFlag(options::OPT_fobjc_nonfragile_abi, options::OPT_fno_objc_nonfragile_abi, NonFragileABIIsDefault)) { // Determine the non-fragile ABI version to use. #ifdef DISABLE_DEFAULT_NONFRAGILEABI_TWO unsigned NonFragileABIVersion = 1; #else unsigned NonFragileABIVersion = 2; #endif if (Arg *A = Args.getLastArg( options::OPT_fobjc_nonfragile_abi_version_EQ)) { if (StringRef(A->getValue(Args)) == "1") NonFragileABIVersion = 1; else if (StringRef(A->getValue(Args)) == "2") NonFragileABIVersion = 2; else D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); } objcABIVersion = 1 + NonFragileABIVersion; } else { objcABIVersion = 1; } } if (objcABIVersion == 1) { CmdArgs.push_back("-fobjc-fragile-abi"); } else { // -fobjc-dispatch-method is only relevant with the nonfragile-abi, and // legacy is the default. if (!Args.hasFlag(options::OPT_fobjc_legacy_dispatch, options::OPT_fno_objc_legacy_dispatch, getToolChain().IsObjCLegacyDispatchDefault())) { if (getToolChain().UseObjCMixedDispatch()) CmdArgs.push_back("-fobjc-dispatch-method=mixed"); else CmdArgs.push_back("-fobjc-dispatch-method=non-legacy"); } } // -fobjc-default-synthesize-properties=0 is default. if (Args.hasFlag(options::OPT_fobjc_default_synthesize_properties, options::OPT_fno_objc_default_synthesize_properties, getToolChain().IsObjCDefaultSynthPropertiesDefault())) { CmdArgs.push_back("-fobjc-default-synthesize-properties"); } // Allow -fno-objc-arr to trump -fobjc-arr/-fobjc-arc. // NOTE: This logic is duplicated in ToolChains.cpp. bool ARC = isObjCAutoRefCount(Args); if (ARC) { CmdArgs.push_back("-fobjc-arc"); + + // FIXME: It seems like this entire block, and several around it should be + // wrapped in isObjC, but for now we just use it here as this is where it + // was being used previously. + if (types::isCXX(InputType) && types::isObjC(InputType)) { + if (getToolChain().GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) + CmdArgs.push_back("-fobjc-arc-cxxlib=libc++"); + else + CmdArgs.push_back("-fobjc-arc-cxxlib=libstdc++"); + } // Allow the user to enable full exceptions code emission. // We define off for Objective-CC, on for Objective-C++. if (Args.hasFlag(options::OPT_fobjc_arc_exceptions, options::OPT_fno_objc_arc_exceptions, /*default*/ types::isCXX(InputType))) CmdArgs.push_back("-fobjc-arc-exceptions"); } // -fobjc-infer-related-result-type is the default, except in the Objective-C // rewriter. if (IsRewriter) CmdArgs.push_back("-fno-objc-infer-related-result-type"); // Handle -fobjc-gc and -fobjc-gc-only. They are exclusive, and -fobjc-gc-only // takes precedence. const Arg *GCArg = Args.getLastArg(options::OPT_fobjc_gc_only); if (!GCArg) GCArg = Args.getLastArg(options::OPT_fobjc_gc); if (GCArg) { if (ARC) { D.Diag(diag::err_drv_objc_gc_arr) << GCArg->getAsString(Args); } else if (getToolChain().SupportsObjCGC()) { GCArg->render(Args, CmdArgs); } else { // FIXME: We should move this to a hard error. D.Diag(diag::warn_drv_objc_gc_unsupported) << GCArg->getAsString(Args); } } // Add exception args. addExceptionArgs(Args, InputType, getToolChain().getTriple(), KernelOrKext, IsRewriter, objcABIVersion, CmdArgs); if (getToolChain().UseSjLjExceptions()) CmdArgs.push_back("-fsjlj-exceptions"); // C++ "sane" operator new. if (!Args.hasFlag(options::OPT_fassume_sane_operator_new, options::OPT_fno_assume_sane_operator_new)) CmdArgs.push_back("-fno-assume-sane-operator-new"); // -fconstant-cfstrings is default, and may be subject to argument translation // on Darwin. if (!Args.hasFlag(options::OPT_fconstant_cfstrings, options::OPT_fno_constant_cfstrings) || !Args.hasFlag(options::OPT_mconstant_cfstrings, options::OPT_mno_constant_cfstrings)) CmdArgs.push_back("-fno-constant-cfstrings"); // -fshort-wchar default varies depending on platform; only // pass if specified. if (Arg *A = Args.getLastArg(options::OPT_fshort_wchar)) A->render(Args, CmdArgs); // -fno-pascal-strings is default, only pass non-default. If the tool chain // happened to translate to -mpascal-strings, we want to back translate here. // // FIXME: This is gross; that translation should be pulled from the // tool chain. if (Args.hasFlag(options::OPT_fpascal_strings, options::OPT_fno_pascal_strings, false) || Args.hasFlag(options::OPT_mpascal_strings, options::OPT_mno_pascal_strings, false)) CmdArgs.push_back("-fpascal-strings"); // Honor -fpack-struct= and -fpack-struct, if given. Note that // -fno-pack-struct doesn't apply to -fpack-struct=. if (Arg *A = Args.getLastArg(options::OPT_fpack_struct_EQ)) { CmdArgs.push_back("-fpack-struct"); CmdArgs.push_back(A->getValue(Args)); } else if (Args.hasFlag(options::OPT_fpack_struct, options::OPT_fno_pack_struct, false)) { CmdArgs.push_back("-fpack-struct"); CmdArgs.push_back("1"); } if (Args.hasArg(options::OPT_mkernel) || Args.hasArg(options::OPT_fapple_kext)) { if (!Args.hasArg(options::OPT_fcommon)) CmdArgs.push_back("-fno-common"); } // -fcommon is default, only pass non-default. else if (!Args.hasFlag(options::OPT_fcommon, options::OPT_fno_common)) CmdArgs.push_back("-fno-common"); // -fsigned-bitfields is default, and clang doesn't yet support // -funsigned-bitfields. if (!Args.hasFlag(options::OPT_fsigned_bitfields, options::OPT_funsigned_bitfields)) D.Diag(diag::warn_drv_clang_unsupported) << Args.getLastArg(options::OPT_funsigned_bitfields)->getAsString(Args); // -fsigned-bitfields is default, and clang doesn't support -fno-for-scope. if (!Args.hasFlag(options::OPT_ffor_scope, options::OPT_fno_for_scope)) D.Diag(diag::err_drv_clang_unsupported) << Args.getLastArg(options::OPT_fno_for_scope)->getAsString(Args); // -fcaret-diagnostics is default. if (!Args.hasFlag(options::OPT_fcaret_diagnostics, options::OPT_fno_caret_diagnostics, true)) CmdArgs.push_back("-fno-caret-diagnostics"); // -fdiagnostics-fixit-info is default, only pass non-default. if (!Args.hasFlag(options::OPT_fdiagnostics_fixit_info, options::OPT_fno_diagnostics_fixit_info)) CmdArgs.push_back("-fno-diagnostics-fixit-info"); // Enable -fdiagnostics-show-name by default. if (Args.hasFlag(options::OPT_fdiagnostics_show_name, options::OPT_fno_diagnostics_show_name, false)) CmdArgs.push_back("-fdiagnostics-show-name"); // Enable -fdiagnostics-show-option by default. if (Args.hasFlag(options::OPT_fdiagnostics_show_option, options::OPT_fno_diagnostics_show_option)) CmdArgs.push_back("-fdiagnostics-show-option"); if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_show_category_EQ)) { CmdArgs.push_back("-fdiagnostics-show-category"); CmdArgs.push_back(A->getValue(Args)); } if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_format_EQ)) { CmdArgs.push_back("-fdiagnostics-format"); CmdArgs.push_back(A->getValue(Args)); } if (Arg *A = Args.getLastArg( options::OPT_fdiagnostics_show_note_include_stack, options::OPT_fno_diagnostics_show_note_include_stack)) { if (A->getOption().matches( options::OPT_fdiagnostics_show_note_include_stack)) CmdArgs.push_back("-fdiagnostics-show-note-include-stack"); else CmdArgs.push_back("-fno-diagnostics-show-note-include-stack"); } // Color diagnostics are the default, unless the terminal doesn't support // them. if (Args.hasFlag(options::OPT_fcolor_diagnostics, options::OPT_fno_color_diagnostics, llvm::sys::Process::StandardErrHasColors())) CmdArgs.push_back("-fcolor-diagnostics"); if (!Args.hasFlag(options::OPT_fshow_source_location, options::OPT_fno_show_source_location)) CmdArgs.push_back("-fno-show-source-location"); if (!Args.hasFlag(options::OPT_fshow_column, options::OPT_fno_show_column, true)) CmdArgs.push_back("-fno-show-column"); if (!Args.hasFlag(options::OPT_fspell_checking, options::OPT_fno_spell_checking)) CmdArgs.push_back("-fno-spell-checking"); // Silently ignore -fasm-blocks for now. (void) Args.hasFlag(options::OPT_fasm_blocks, options::OPT_fno_asm_blocks, false); if (Arg *A = Args.getLastArg(options::OPT_fshow_overloads_EQ)) A->render(Args, CmdArgs); // -fdollars-in-identifiers default varies depending on platform and // language; only pass if specified. if (Arg *A = Args.getLastArg(options::OPT_fdollars_in_identifiers, options::OPT_fno_dollars_in_identifiers)) { if (A->getOption().matches(options::OPT_fdollars_in_identifiers)) CmdArgs.push_back("-fdollars-in-identifiers"); else CmdArgs.push_back("-fno-dollars-in-identifiers"); } // -funit-at-a-time is default, and we don't support -fno-unit-at-a-time for // practical purposes. if (Arg *A = Args.getLastArg(options::OPT_funit_at_a_time, options::OPT_fno_unit_at_a_time)) { if (A->getOption().matches(options::OPT_fno_unit_at_a_time)) D.Diag(diag::warn_drv_clang_unsupported) << A->getAsString(Args); } // Default to -fno-builtin-str{cat,cpy} on Darwin for ARM. // // FIXME: This is disabled until clang -cc1 supports -fno-builtin-foo. PR4941. #if 0 if (getToolChain().getTriple().isOSDarwin() && (getToolChain().getTriple().getArch() == llvm::Triple::arm || getToolChain().getTriple().getArch() == llvm::Triple::thumb)) { if (!Args.hasArg(options::OPT_fbuiltin_strcat)) CmdArgs.push_back("-fno-builtin-strcat"); if (!Args.hasArg(options::OPT_fbuiltin_strcpy)) CmdArgs.push_back("-fno-builtin-strcpy"); } #endif // Only allow -traditional or -traditional-cpp outside in preprocessing modes. if (Arg *A = Args.getLastArg(options::OPT_traditional, options::OPT_traditional_cpp)) { if (isa(JA)) CmdArgs.push_back("-traditional-cpp"); else D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); } Args.AddLastArg(CmdArgs, options::OPT_dM); Args.AddLastArg(CmdArgs, options::OPT_dD); // Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option // parser. Args.AddAllArgValues(CmdArgs, options::OPT_Xclang); for (arg_iterator it = Args.filtered_begin(options::OPT_mllvm), ie = Args.filtered_end(); it != ie; ++it) { (*it)->claim(); // We translate this by hand to the -cc1 argument, since nightly test uses // it and developers have been trained to spell it with -mllvm. if (StringRef((*it)->getValue(Args, 0)) == "-disable-llvm-optzns") CmdArgs.push_back("-disable-llvm-optzns"); else (*it)->render(Args, CmdArgs); } if (Output.getType() == types::TY_Dependencies) { // Handled with other dependency code. } else if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { assert(Output.isNothing() && "Invalid output."); } for (InputInfoList::const_iterator it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { const InputInfo &II = *it; CmdArgs.push_back("-x"); CmdArgs.push_back(types::getTypeName(II.getType())); if (II.isFilename()) CmdArgs.push_back(II.getFilename()); else II.getInputArg().renderAsInput(Args, CmdArgs); } Args.AddAllArgs(CmdArgs, options::OPT_undef); const char *Exec = getToolChain().getDriver().getClangProgramPath(); // Optionally embed the -cc1 level arguments into the debug info, for build // analysis. if (getToolChain().UseDwarfDebugFlags()) { ArgStringList OriginalArgs; for (ArgList::const_iterator it = Args.begin(), ie = Args.end(); it != ie; ++it) (*it)->render(Args, OriginalArgs); llvm::SmallString<256> Flags; Flags += Exec; for (unsigned i = 0, e = OriginalArgs.size(); i != e; ++i) { Flags += " "; Flags += OriginalArgs[i]; } CmdArgs.push_back("-dwarf-debug-flags"); CmdArgs.push_back(Args.MakeArgString(Flags.str())); } C.addCommand(new Command(JA, *this, Exec, CmdArgs)); if (Arg *A = Args.getLastArg(options::OPT_pg)) if (Args.hasArg(options::OPT_fomit_frame_pointer)) D.Diag(diag::err_drv_argument_not_allowed_with) << "-fomit-frame-pointer" << A->getAsString(Args); // Claim some arguments which clang supports automatically. // -fpch-preprocess is used with gcc to add a special marker in the output to // include the PCH file. Clang's PTH solution is completely transparent, so we // do not need to deal with it at all. Args.ClaimAllArgs(options::OPT_fpch_preprocess); // Claim some arguments which clang doesn't support, but we don't // care to warn the user about. Args.ClaimAllArgs(options::OPT_clang_ignored_f_Group); Args.ClaimAllArgs(options::OPT_clang_ignored_m_Group); // Disable warnings for clang -E -use-gold-plugin -emit-llvm foo.c Args.ClaimAllArgs(options::OPT_use_gold_plugin); Args.ClaimAllArgs(options::OPT_emit_llvm); } void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { ArgStringList CmdArgs; assert(Inputs.size() == 1 && "Unexpected number of inputs."); const InputInfo &Input = Inputs[0]; // Don't warn about "clang -w -c foo.s" Args.ClaimAllArgs(options::OPT_w); // and "clang -emit-llvm -c foo.s" Args.ClaimAllArgs(options::OPT_emit_llvm); // and "clang -use-gold-plugin -c foo.s" Args.ClaimAllArgs(options::OPT_use_gold_plugin); // Invoke ourselves in -cc1as mode. // // FIXME: Implement custom jobs for internal actions. CmdArgs.push_back("-cc1as"); // Add the "effective" target triple. CmdArgs.push_back("-triple"); std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args, Input.getType()); CmdArgs.push_back(Args.MakeArgString(TripleStr)); // Set the output mode, we currently only expect to be used as a real // assembler. CmdArgs.push_back("-filetype"); CmdArgs.push_back("obj"); if (UseRelaxAll(C, Args)) CmdArgs.push_back("-relax-all"); // Ignore explicit -force_cpusubtype_ALL option. (void) Args.hasArg(options::OPT_force__cpusubtype__ALL); // FIXME: Add -g support, once we have it. // FIXME: Add -static support, once we have it. Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); Args.AddAllArgs(CmdArgs, options::OPT_mllvm); assert(Output.isFilename() && "Unexpected lipo output."); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); assert(Input.isFilename() && "Invalid input."); CmdArgs.push_back(Input.getFilename()); const char *Exec = getToolChain().getDriver().getClangProgramPath(); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; for (ArgList::const_iterator it = Args.begin(), ie = Args.end(); it != ie; ++it) { Arg *A = *it; if (A->getOption().hasForwardToGCC()) { // Don't forward any -g arguments to assembly steps. if (isa(JA) && A->getOption().matches(options::OPT_g_Group)) continue; // It is unfortunate that we have to claim here, as this means // we will basically never report anything interesting for // platforms using a generic gcc, even if we are just using gcc // to get to the assembler. A->claim(); A->render(Args, CmdArgs); } } RenderExtraToolArgs(JA, CmdArgs); // If using a driver driver, force the arch. const std::string &Arch = getToolChain().getArchName(); if (getToolChain().getTriple().isOSDarwin()) { CmdArgs.push_back("-arch"); // FIXME: Remove these special cases. if (Arch == "powerpc") CmdArgs.push_back("ppc"); else if (Arch == "powerpc64") CmdArgs.push_back("ppc64"); else CmdArgs.push_back(Args.MakeArgString(Arch)); } // Try to force gcc to match the tool chain we want, if we recognize // the arch. // // FIXME: The triple class should directly provide the information we want // here. if (Arch == "i386" || Arch == "powerpc") CmdArgs.push_back("-m32"); else if (Arch == "x86_64" || Arch == "powerpc64") CmdArgs.push_back("-m64"); if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { assert(Output.isNothing() && "Unexpected output"); CmdArgs.push_back("-fsyntax-only"); } // Only pass -x if gcc will understand it; otherwise hope gcc // understands the suffix correctly. The main use case this would go // wrong in is for linker inputs if they happened to have an odd // suffix; really the only way to get this to happen is a command // like '-x foobar a.c' which will treat a.c like a linker input. // // FIXME: For the linker case specifically, can we safely convert // inputs into '-Wl,' options? for (InputInfoList::const_iterator it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { const InputInfo &II = *it; // Don't try to pass LLVM or AST inputs to a generic gcc. if (II.getType() == types::TY_LLVM_IR || II.getType() == types::TY_LTO_IR || II.getType() == types::TY_LLVM_BC || II.getType() == types::TY_LTO_BC) D.Diag(diag::err_drv_no_linker_llvm_support) << getToolChain().getTripleString(); else if (II.getType() == types::TY_AST) D.Diag(diag::err_drv_no_ast_support) << getToolChain().getTripleString(); if (types::canTypeBeUserSpecified(II.getType())) { CmdArgs.push_back("-x"); CmdArgs.push_back(types::getTypeName(II.getType())); } if (II.isFilename()) CmdArgs.push_back(II.getFilename()); else { const Arg &A = II.getInputArg(); // Reverse translate some rewritten options. if (A.getOption().matches(options::OPT_Z_reserved_lib_stdcxx)) { CmdArgs.push_back("-lstdc++"); continue; } // Don't render as input, we need gcc to do the translations. A.render(Args, CmdArgs); } } const std::string customGCCName = D.getCCCGenericGCCName(); const char *GCCName; if (!customGCCName.empty()) GCCName = customGCCName.c_str(); else if (D.CCCIsCXX) { #ifdef IS_CYGWIN15 // FIXME: Detect the version of Cygwin at runtime? GCCName = "g++-4"; #else GCCName = "g++"; #endif } else GCCName = "gcc"; const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(GCCName)); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void gcc::Preprocess::RenderExtraToolArgs(const JobAction &JA, ArgStringList &CmdArgs) const { CmdArgs.push_back("-E"); } void gcc::Precompile::RenderExtraToolArgs(const JobAction &JA, ArgStringList &CmdArgs) const { // The type is good enough. } void gcc::Compile::RenderExtraToolArgs(const JobAction &JA, ArgStringList &CmdArgs) const { const Driver &D = getToolChain().getDriver(); // If -flto, etc. are present then make sure not to force assembly output. if (JA.getType() == types::TY_LLVM_IR || JA.getType() == types::TY_LTO_IR || JA.getType() == types::TY_LLVM_BC || JA.getType() == types::TY_LTO_BC) CmdArgs.push_back("-c"); else { if (JA.getType() != types::TY_PP_Asm) D.Diag(diag::err_drv_invalid_gcc_output_type) << getTypeName(JA.getType()); CmdArgs.push_back("-S"); } } void gcc::Assemble::RenderExtraToolArgs(const JobAction &JA, ArgStringList &CmdArgs) const { CmdArgs.push_back("-c"); } void gcc::Link::RenderExtraToolArgs(const JobAction &JA, ArgStringList &CmdArgs) const { // The types are (hopefully) good enough. } const char *darwin::CC1::getCC1Name(types::ID Type) const { switch (Type) { default: llvm_unreachable("Unexpected type for Darwin CC1 tool."); case types::TY_Asm: case types::TY_C: case types::TY_CHeader: case types::TY_PP_C: case types::TY_PP_CHeader: return "cc1"; case types::TY_ObjC: case types::TY_ObjCHeader: case types::TY_PP_ObjC: case types::TY_PP_ObjC_Alias: case types::TY_PP_ObjCHeader: return "cc1obj"; case types::TY_CXX: case types::TY_CXXHeader: case types::TY_PP_CXX: case types::TY_PP_CXXHeader: return "cc1plus"; case types::TY_ObjCXX: case types::TY_ObjCXXHeader: case types::TY_PP_ObjCXX: case types::TY_PP_ObjCXX_Alias: case types::TY_PP_ObjCXXHeader: return "cc1objplus"; } } const char *darwin::CC1::getBaseInputName(const ArgList &Args, const InputInfoList &Inputs) { return Args.MakeArgString( llvm::sys::path::filename(Inputs[0].getBaseInput())); } const char *darwin::CC1::getBaseInputStem(const ArgList &Args, const InputInfoList &Inputs) { const char *Str = getBaseInputName(Args, Inputs); if (const char *End = strrchr(Str, '.')) return Args.MakeArgString(std::string(Str, End)); return Str; } const char * darwin::CC1::getDependencyFileName(const ArgList &Args, const InputInfoList &Inputs) { // FIXME: Think about this more. std::string Res; if (Arg *OutputOpt = Args.getLastArg(options::OPT_o)) { std::string Str(OutputOpt->getValue(Args)); Res = Str.substr(0, Str.rfind('.')); } else { Res = darwin::CC1::getBaseInputStem(Args, Inputs); } return Args.MakeArgString(Res + ".d"); } void darwin::CC1::RemoveCC1UnsupportedArgs(ArgStringList &CmdArgs) const { for (ArgStringList::iterator it = CmdArgs.begin(), ie = CmdArgs.end(); it != ie;) { StringRef Option = *it; bool RemoveOption = false; // Remove -faltivec if (Option.equals("-faltivec")) { it = CmdArgs.erase(it); ie = CmdArgs.end(); continue; } // Handle machine specific options. if (Option.startswith("-m")) { RemoveOption = llvm::StringSwitch(Option) .Case("-mthumb", true) .Case("-mno-thumb", true) .Case("-mno-fused-madd", true) .Case("-mlong-branch", true) .Case("-mlongcall", true) .Case("-mcpu=G4", true) .Case("-mcpu=G5", true) .Default(false); } // Handle warning options. if (Option.startswith("-W")) { // Remove -W/-Wno- to reduce the number of cases. if (Option.startswith("-Wno-")) Option = Option.substr(5); else Option = Option.substr(2); RemoveOption = llvm::StringSwitch(Option) .Case("address-of-temporary", true) .Case("ambiguous-member-template", true) .Case("analyzer-incompatible-plugin", true) .Case("array-bounds", true) .Case("array-bounds-pointer-arithmetic", true) .Case("bind-to-temporary-copy", true) .Case("bitwise-op-parentheses", true) .Case("bool-conversions", true) .Case("builtin-macro-redefined", true) .Case("c++-hex-floats", true) .Case("c++0x-compat", true) .Case("c++0x-extensions", true) .Case("c++0x-narrowing", true) .Case("c++11-compat", true) .Case("c++11-extensions", true) .Case("c++11-narrowing", true) .Case("conditional-uninitialized", true) .Case("constant-conversion", true) .Case("CFString-literal", true) .Case("constant-logical-operand", true) .Case("custom-atomic-properties", true) .Case("default-arg-special-member", true) .Case("delegating-ctor-cycles", true) .Case("delete-non-virtual-dtor", true) .Case("deprecated-implementations", true) .Case("deprecated-writable-strings", true) .Case("distributed-object-modifiers", true) .Case("duplicate-method-arg", true) .Case("dynamic-class-memaccess", true) .Case("enum-compare", true) .Case("exit-time-destructors", true) .Case("gnu", true) .Case("gnu-designator", true) .Case("header-hygiene", true) .Case("idiomatic-parentheses", true) .Case("ignored-qualifiers", true) .Case("implicit-atomic-properties", true) .Case("incompatible-pointer-types", true) .Case("incomplete-implementation", true) .Case("initializer-overrides", true) .Case("invalid-noreturn", true) .Case("invalid-token-paste", true) .Case("language-extension-token", true) .Case("literal-conversion", true) .Case("literal-range", true) .Case("local-type-template-args", true) .Case("logical-op-parentheses", true) .Case("method-signatures", true) .Case("microsoft", true) .Case("mismatched-tags", true) .Case("missing-method-return-type", true) .Case("non-pod-varargs", true) .Case("nonfragile-abi2", true) .Case("null-arithmetic", true) .Case("null-dereference", true) .Case("out-of-line-declaration", true) .Case("overriding-method-mismatch", true) .Case("readonly-setter-attrs", true) .Case("return-stack-address", true) .Case("self-assign", true) .Case("semicolon-before-method-body", true) .Case("sentinel", true) .Case("shift-overflow", true) .Case("shift-sign-overflow", true) .Case("sign-conversion", true) .Case("sizeof-array-argument", true) .Case("sizeof-pointer-memaccess", true) .Case("string-compare", true) .Case("super-class-method-mismatch", true) .Case("tautological-compare", true) .Case("typedef-redefinition", true) .Case("typename-missing", true) .Case("undefined-reinterpret-cast", true) .Case("unknown-warning-option", true) .Case("unnamed-type-template-args", true) .Case("unneeded-internal-declaration", true) .Case("unneeded-member-function", true) .Case("unused-comparison", true) .Case("unused-exception-parameter", true) .Case("unused-member-function", true) .Case("unused-result", true) .Case("vector-conversions", true) .Case("vla", true) .Case("used-but-marked-unused", true) .Case("weak-vtables", true) .Default(false); } // if (Option.startswith("-W")) if (RemoveOption) { it = CmdArgs.erase(it); ie = CmdArgs.end(); } else { ++it; } } } void darwin::CC1::AddCC1Args(const ArgList &Args, ArgStringList &CmdArgs) const { const Driver &D = getToolChain().getDriver(); CheckCodeGenerationOptions(D, Args); // Derived from cc1 spec. if (!Args.hasArg(options::OPT_mkernel) && !Args.hasArg(options::OPT_static) && !Args.hasArg(options::OPT_mdynamic_no_pic)) CmdArgs.push_back("-fPIC"); if (getToolChain().getTriple().getArch() == llvm::Triple::arm || getToolChain().getTriple().getArch() == llvm::Triple::thumb) { if (!Args.hasArg(options::OPT_fbuiltin_strcat)) CmdArgs.push_back("-fno-builtin-strcat"); if (!Args.hasArg(options::OPT_fbuiltin_strcpy)) CmdArgs.push_back("-fno-builtin-strcpy"); } if (Args.hasArg(options::OPT_g_Flag) && !Args.hasArg(options::OPT_fno_eliminate_unused_debug_symbols)) CmdArgs.push_back("-feliminate-unused-debug-symbols"); } void darwin::CC1::AddCC1OptionsArgs(const ArgList &Args, ArgStringList &CmdArgs, const InputInfoList &Inputs, const ArgStringList &OutputArgs) const { const Driver &D = getToolChain().getDriver(); // Derived from cc1_options spec. if (Args.hasArg(options::OPT_fast) || Args.hasArg(options::OPT_fastf) || Args.hasArg(options::OPT_fastcp)) CmdArgs.push_back("-O3"); if (Arg *A = Args.getLastArg(options::OPT_pg)) if (Args.hasArg(options::OPT_fomit_frame_pointer)) D.Diag(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args) << "-fomit-frame-pointer"; AddCC1Args(Args, CmdArgs); if (!Args.hasArg(options::OPT_Q)) CmdArgs.push_back("-quiet"); CmdArgs.push_back("-dumpbase"); CmdArgs.push_back(darwin::CC1::getBaseInputName(Args, Inputs)); Args.AddAllArgs(CmdArgs, options::OPT_d_Group); Args.AddAllArgs(CmdArgs, options::OPT_m_Group); Args.AddAllArgs(CmdArgs, options::OPT_a_Group); // FIXME: The goal is to use the user provided -o if that is our // final output, otherwise to drive from the original input // name. Find a clean way to go about this. if ((Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) && Args.hasArg(options::OPT_o)) { Arg *OutputOpt = Args.getLastArg(options::OPT_o); CmdArgs.push_back("-auxbase-strip"); CmdArgs.push_back(OutputOpt->getValue(Args)); } else { CmdArgs.push_back("-auxbase"); CmdArgs.push_back(darwin::CC1::getBaseInputStem(Args, Inputs)); } Args.AddAllArgs(CmdArgs, options::OPT_g_Group); Args.AddAllArgs(CmdArgs, options::OPT_O); // FIXME: -Wall is getting some special treatment. Investigate. Args.AddAllArgs(CmdArgs, options::OPT_W_Group, options::OPT_pedantic_Group); Args.AddLastArg(CmdArgs, options::OPT_w); Args.AddAllArgs(CmdArgs, options::OPT_std_EQ, options::OPT_ansi, options::OPT_trigraphs); if (!Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi)) { // Honor -std-default. Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ, "-std=", /*Joined=*/true); } if (Args.hasArg(options::OPT_v)) CmdArgs.push_back("-version"); if (Args.hasArg(options::OPT_pg) && getToolChain().SupportsProfiling()) CmdArgs.push_back("-p"); Args.AddLastArg(CmdArgs, options::OPT_p); // The driver treats -fsyntax-only specially. if (getToolChain().getTriple().getArch() == llvm::Triple::arm || getToolChain().getTriple().getArch() == llvm::Triple::thumb) { // Removes -fbuiltin-str{cat,cpy}; these aren't recognized by cc1 but are // used to inhibit the default -fno-builtin-str{cat,cpy}. // // FIXME: Should we grow a better way to deal with "removing" args? for (arg_iterator it = Args.filtered_begin(options::OPT_f_Group, options::OPT_fsyntax_only), ie = Args.filtered_end(); it != ie; ++it) { if (!(*it)->getOption().matches(options::OPT_fbuiltin_strcat) && !(*it)->getOption().matches(options::OPT_fbuiltin_strcpy)) { (*it)->claim(); (*it)->render(Args, CmdArgs); } } } else Args.AddAllArgs(CmdArgs, options::OPT_f_Group, options::OPT_fsyntax_only); // Claim Clang only -f options, they aren't worth warning about. Args.ClaimAllArgs(options::OPT_f_clang_Group); Args.AddAllArgs(CmdArgs, options::OPT_undef); if (Args.hasArg(options::OPT_Qn)) CmdArgs.push_back("-fno-ident"); // FIXME: This isn't correct. //Args.AddLastArg(CmdArgs, options::OPT__help) //Args.AddLastArg(CmdArgs, options::OPT__targetHelp) CmdArgs.append(OutputArgs.begin(), OutputArgs.end()); // FIXME: Still don't get what is happening here. Investigate. Args.AddAllArgs(CmdArgs, options::OPT__param); if (Args.hasArg(options::OPT_fmudflap) || Args.hasArg(options::OPT_fmudflapth)) { CmdArgs.push_back("-fno-builtin"); CmdArgs.push_back("-fno-merge-constants"); } if (Args.hasArg(options::OPT_coverage)) { CmdArgs.push_back("-fprofile-arcs"); CmdArgs.push_back("-ftest-coverage"); } if (types::isCXX(Inputs[0].getType())) CmdArgs.push_back("-D__private_extern__=extern"); } void darwin::CC1::AddCPPOptionsArgs(const ArgList &Args, ArgStringList &CmdArgs, const InputInfoList &Inputs, const ArgStringList &OutputArgs) const { // Derived from cpp_options AddCPPUniqueOptionsArgs(Args, CmdArgs, Inputs); CmdArgs.append(OutputArgs.begin(), OutputArgs.end()); AddCC1Args(Args, CmdArgs); // NOTE: The code below has some commonality with cpp_options, but // in classic gcc style ends up sending things in different // orders. This may be a good merge candidate once we drop pedantic // compatibility. Args.AddAllArgs(CmdArgs, options::OPT_m_Group); Args.AddAllArgs(CmdArgs, options::OPT_std_EQ, options::OPT_ansi, options::OPT_trigraphs); if (!Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi)) { // Honor -std-default. Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ, "-std=", /*Joined=*/true); } Args.AddAllArgs(CmdArgs, options::OPT_W_Group, options::OPT_pedantic_Group); Args.AddLastArg(CmdArgs, options::OPT_w); // The driver treats -fsyntax-only specially. Args.AddAllArgs(CmdArgs, options::OPT_f_Group, options::OPT_fsyntax_only); // Claim Clang only -f options, they aren't worth warning about. Args.ClaimAllArgs(options::OPT_f_clang_Group); if (Args.hasArg(options::OPT_g_Group) && !Args.hasArg(options::OPT_g0) && !Args.hasArg(options::OPT_fno_working_directory)) CmdArgs.push_back("-fworking-directory"); Args.AddAllArgs(CmdArgs, options::OPT_O); Args.AddAllArgs(CmdArgs, options::OPT_undef); if (Args.hasArg(options::OPT_save_temps)) CmdArgs.push_back("-fpch-preprocess"); } void darwin::CC1::AddCPPUniqueOptionsArgs(const ArgList &Args, ArgStringList &CmdArgs, const InputInfoList &Inputs) const { const Driver &D = getToolChain().getDriver(); CheckPreprocessingOptions(D, Args); // Derived from cpp_unique_options. // -{C,CC} only with -E is checked in CheckPreprocessingOptions(). Args.AddLastArg(CmdArgs, options::OPT_C); Args.AddLastArg(CmdArgs, options::OPT_CC); if (!Args.hasArg(options::OPT_Q)) CmdArgs.push_back("-quiet"); Args.AddAllArgs(CmdArgs, options::OPT_nostdinc); Args.AddAllArgs(CmdArgs, options::OPT_nostdincxx); Args.AddLastArg(CmdArgs, options::OPT_v); Args.AddAllArgs(CmdArgs, options::OPT_I_Group, options::OPT_F); Args.AddLastArg(CmdArgs, options::OPT_P); // FIXME: Handle %I properly. if (getToolChain().getArchName() == "x86_64") { CmdArgs.push_back("-imultilib"); CmdArgs.push_back("x86_64"); } if (Args.hasArg(options::OPT_MD)) { CmdArgs.push_back("-MD"); CmdArgs.push_back(darwin::CC1::getDependencyFileName(Args, Inputs)); } if (Args.hasArg(options::OPT_MMD)) { CmdArgs.push_back("-MMD"); CmdArgs.push_back(darwin::CC1::getDependencyFileName(Args, Inputs)); } Args.AddLastArg(CmdArgs, options::OPT_M); Args.AddLastArg(CmdArgs, options::OPT_MM); Args.AddAllArgs(CmdArgs, options::OPT_MF); Args.AddLastArg(CmdArgs, options::OPT_MG); Args.AddLastArg(CmdArgs, options::OPT_MP); Args.AddAllArgs(CmdArgs, options::OPT_MQ); Args.AddAllArgs(CmdArgs, options::OPT_MT); if (!Args.hasArg(options::OPT_M) && !Args.hasArg(options::OPT_MM) && (Args.hasArg(options::OPT_MD) || Args.hasArg(options::OPT_MMD))) { if (Arg *OutputOpt = Args.getLastArg(options::OPT_o)) { CmdArgs.push_back("-MQ"); CmdArgs.push_back(OutputOpt->getValue(Args)); } } Args.AddLastArg(CmdArgs, options::OPT_remap); if (Args.hasArg(options::OPT_g3)) CmdArgs.push_back("-dD"); Args.AddLastArg(CmdArgs, options::OPT_H); AddCPPArgs(Args, CmdArgs); Args.AddAllArgs(CmdArgs, options::OPT_D, options::OPT_U, options::OPT_A); Args.AddAllArgs(CmdArgs, options::OPT_i_Group); for (InputInfoList::const_iterator it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { const InputInfo &II = *it; CmdArgs.push_back(II.getFilename()); } Args.AddAllArgValues(CmdArgs, options::OPT_Wp_COMMA, options::OPT_Xpreprocessor); if (Args.hasArg(options::OPT_fmudflap)) { CmdArgs.push_back("-D_MUDFLAP"); CmdArgs.push_back("-include"); CmdArgs.push_back("mf-runtime.h"); } if (Args.hasArg(options::OPT_fmudflapth)) { CmdArgs.push_back("-D_MUDFLAP"); CmdArgs.push_back("-D_MUDFLAPTH"); CmdArgs.push_back("-include"); CmdArgs.push_back("mf-runtime.h"); } } void darwin::CC1::AddCPPArgs(const ArgList &Args, ArgStringList &CmdArgs) const { // Derived from cpp spec. if (Args.hasArg(options::OPT_static)) { // The gcc spec is broken here, it refers to dynamic but // that has been translated. Start by being bug compatible. // if (!Args.hasArg(arglist.parser.dynamicOption)) CmdArgs.push_back("-D__STATIC__"); } else CmdArgs.push_back("-D__DYNAMIC__"); if (Args.hasArg(options::OPT_pthread)) CmdArgs.push_back("-D_REENTRANT"); } void darwin::Preprocess::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { ArgStringList CmdArgs; assert(Inputs.size() == 1 && "Unexpected number of inputs!"); CmdArgs.push_back("-E"); if (Args.hasArg(options::OPT_traditional) || Args.hasArg(options::OPT_traditional_cpp)) CmdArgs.push_back("-traditional-cpp"); ArgStringList OutputArgs; assert(Output.isFilename() && "Unexpected CC1 output."); OutputArgs.push_back("-o"); OutputArgs.push_back(Output.getFilename()); if (Args.hasArg(options::OPT_E) || getToolChain().getDriver().CCCIsCPP) { AddCPPOptionsArgs(Args, CmdArgs, Inputs, OutputArgs); } else { AddCPPOptionsArgs(Args, CmdArgs, Inputs, ArgStringList()); CmdArgs.append(OutputArgs.begin(), OutputArgs.end()); } Args.AddAllArgs(CmdArgs, options::OPT_d_Group); RemoveCC1UnsupportedArgs(CmdArgs); const char *CC1Name = getCC1Name(Inputs[0].getType()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(CC1Name)); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; assert(Inputs.size() == 1 && "Unexpected number of inputs!"); types::ID InputType = Inputs[0].getType(); const Arg *A; if ((A = Args.getLastArg(options::OPT_traditional))) D.Diag(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args) << "-E"; if (JA.getType() == types::TY_LLVM_IR || JA.getType() == types::TY_LTO_IR) CmdArgs.push_back("-emit-llvm"); else if (JA.getType() == types::TY_LLVM_BC || JA.getType() == types::TY_LTO_BC) CmdArgs.push_back("-emit-llvm-bc"); else if (Output.getType() == types::TY_AST) D.Diag(diag::err_drv_no_ast_support) << getToolChain().getTripleString(); else if (JA.getType() != types::TY_PP_Asm && JA.getType() != types::TY_PCH) D.Diag(diag::err_drv_invalid_gcc_output_type) << getTypeName(JA.getType()); ArgStringList OutputArgs; if (Output.getType() != types::TY_PCH) { OutputArgs.push_back("-o"); if (Output.isNothing()) OutputArgs.push_back("/dev/null"); else OutputArgs.push_back(Output.getFilename()); } // There is no need for this level of compatibility, but it makes // diffing easier. bool OutputArgsEarly = (Args.hasArg(options::OPT_fsyntax_only) || Args.hasArg(options::OPT_S)); if (types::getPreprocessedType(InputType) != types::TY_INVALID) { AddCPPUniqueOptionsArgs(Args, CmdArgs, Inputs); if (OutputArgsEarly) { AddCC1OptionsArgs(Args, CmdArgs, Inputs, OutputArgs); } else { AddCC1OptionsArgs(Args, CmdArgs, Inputs, ArgStringList()); CmdArgs.append(OutputArgs.begin(), OutputArgs.end()); } } else { CmdArgs.push_back("-fpreprocessed"); for (InputInfoList::const_iterator it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { const InputInfo &II = *it; // Reject AST inputs. if (II.getType() == types::TY_AST) { D.Diag(diag::err_drv_no_ast_support) << getToolChain().getTripleString(); return; } CmdArgs.push_back(II.getFilename()); } if (OutputArgsEarly) { AddCC1OptionsArgs(Args, CmdArgs, Inputs, OutputArgs); } else { AddCC1OptionsArgs(Args, CmdArgs, Inputs, ArgStringList()); CmdArgs.append(OutputArgs.begin(), OutputArgs.end()); } } if (Output.getType() == types::TY_PCH) { assert(Output.isFilename() && "Invalid PCH output."); CmdArgs.push_back("-o"); // NOTE: gcc uses a temp .s file for this, but there doesn't seem // to be a good reason. const char *TmpPath = C.getArgs().MakeArgString( D.GetTemporaryPath("cc", "s")); C.addTempFile(TmpPath); CmdArgs.push_back(TmpPath); // If we're emitting a pch file with the last 4 characters of ".pth" // and falling back to llvm-gcc we want to use ".gch" instead. std::string OutputFile(Output.getFilename()); size_t loc = OutputFile.rfind(".pth"); if (loc != std::string::npos) OutputFile.replace(loc, 4, ".gch"); const char *Tmp = C.getArgs().MakeArgString("--output-pch="+OutputFile); CmdArgs.push_back(Tmp); } RemoveCC1UnsupportedArgs(CmdArgs); const char *CC1Name = getCC1Name(Inputs[0].getType()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(CC1Name)); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { ArgStringList CmdArgs; assert(Inputs.size() == 1 && "Unexpected number of inputs."); const InputInfo &Input = Inputs[0]; // Determine the original source input. const Action *SourceAction = &JA; while (SourceAction->getKind() != Action::InputClass) { assert(!SourceAction->getInputs().empty() && "unexpected root action!"); SourceAction = SourceAction->getInputs()[0]; } // Forward -g, assuming we are dealing with an actual assembly file. if (SourceAction->getType() == types::TY_Asm || SourceAction->getType() == types::TY_PP_Asm) { if (Args.hasArg(options::OPT_gstabs)) CmdArgs.push_back("--gstabs"); else if (Args.hasArg(options::OPT_g_Group)) CmdArgs.push_back("--gdwarf2"); } // Derived from asm spec. AddDarwinArch(Args, CmdArgs); // Use -force_cpusubtype_ALL on x86 by default. if (getToolChain().getTriple().getArch() == llvm::Triple::x86 || getToolChain().getTriple().getArch() == llvm::Triple::x86_64 || Args.hasArg(options::OPT_force__cpusubtype__ALL)) CmdArgs.push_back("-force_cpusubtype_ALL"); if (getToolChain().getTriple().getArch() != llvm::Triple::x86_64 && (Args.hasArg(options::OPT_mkernel) || Args.hasArg(options::OPT_static) || Args.hasArg(options::OPT_fapple_kext))) CmdArgs.push_back("-static"); Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); assert(Output.isFilename() && "Unexpected lipo output."); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); assert(Input.isFilename() && "Invalid input."); CmdArgs.push_back(Input.getFilename()); // asm_final spec is empty. const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void darwin::DarwinTool::AddDarwinArch(const ArgList &Args, ArgStringList &CmdArgs) const { StringRef ArchName = getDarwinToolChain().getDarwinArchName(Args); // Derived from darwin_arch spec. CmdArgs.push_back("-arch"); CmdArgs.push_back(Args.MakeArgString(ArchName)); // FIXME: Is this needed anymore? if (ArchName == "arm") CmdArgs.push_back("-force_cpusubtype_ALL"); } void darwin::Link::AddLinkArgs(Compilation &C, const ArgList &Args, ArgStringList &CmdArgs) const { const Driver &D = getToolChain().getDriver(); const toolchains::Darwin &DarwinTC = getDarwinToolChain(); unsigned Version[3] = { 0, 0, 0 }; if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) { bool HadExtra; if (!Driver::GetReleaseVersion(A->getValue(Args), Version[0], Version[1], Version[2], HadExtra) || HadExtra) D.Diag(diag::err_drv_invalid_version_number) << A->getAsString(Args); } // Newer linkers support -demangle, pass it if supported and not disabled by // the user. // // FIXME: We temporarily avoid passing -demangle to any iOS linker, because // unfortunately we can't be guaranteed that the linker version used there // will match the linker version detected at configure time. We need the // universal driver. if (Version[0] >= 100 && !Args.hasArg(options::OPT_Z_Xlinker__no_demangle) && !DarwinTC.isTargetIPhoneOS()) { // Don't pass -demangle to ld_classic. // // FIXME: This is a temporary workaround, ld should be handling this. bool UsesLdClassic = (getToolChain().getArch() == llvm::Triple::x86 && Args.hasArg(options::OPT_static)); if (getToolChain().getArch() == llvm::Triple::x86) { for (arg_iterator it = Args.filtered_begin(options::OPT_Xlinker, options::OPT_Wl_COMMA), ie = Args.filtered_end(); it != ie; ++it) { const Arg *A = *it; for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) if (StringRef(A->getValue(Args, i)) == "-kext") UsesLdClassic = true; } } if (!UsesLdClassic) CmdArgs.push_back("-demangle"); } // If we are using LTO, then automatically create a temporary file path for // the linker to use, so that it's lifetime will extend past a possible // dsymutil step. if (Version[0] >= 116 && D.IsUsingLTO(Args)) { const char *TmpPath = C.getArgs().MakeArgString( D.GetTemporaryPath("cc", types::getTypeTempSuffix(types::TY_Object))); C.addTempFile(TmpPath); CmdArgs.push_back("-object_path_lto"); CmdArgs.push_back(TmpPath); } // Derived from the "link" spec. Args.AddAllArgs(CmdArgs, options::OPT_static); if (!Args.hasArg(options::OPT_static)) CmdArgs.push_back("-dynamic"); if (Args.hasArg(options::OPT_fgnu_runtime)) { // FIXME: gcc replaces -lobjc in forward args with -lobjc-gnu // here. How do we wish to handle such things? } if (!Args.hasArg(options::OPT_dynamiclib)) { AddDarwinArch(Args, CmdArgs); // FIXME: Why do this only on this path? Args.AddLastArg(CmdArgs, options::OPT_force__cpusubtype__ALL); Args.AddLastArg(CmdArgs, options::OPT_bundle); Args.AddAllArgs(CmdArgs, options::OPT_bundle__loader); Args.AddAllArgs(CmdArgs, options::OPT_client__name); Arg *A; if ((A = Args.getLastArg(options::OPT_compatibility__version)) || (A = Args.getLastArg(options::OPT_current__version)) || (A = Args.getLastArg(options::OPT_install__name))) D.Diag(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args) << "-dynamiclib"; Args.AddLastArg(CmdArgs, options::OPT_force__flat__namespace); Args.AddLastArg(CmdArgs, options::OPT_keep__private__externs); Args.AddLastArg(CmdArgs, options::OPT_private__bundle); } else { CmdArgs.push_back("-dylib"); Arg *A; if ((A = Args.getLastArg(options::OPT_bundle)) || (A = Args.getLastArg(options::OPT_bundle__loader)) || (A = Args.getLastArg(options::OPT_client__name)) || (A = Args.getLastArg(options::OPT_force__flat__namespace)) || (A = Args.getLastArg(options::OPT_keep__private__externs)) || (A = Args.getLastArg(options::OPT_private__bundle))) D.Diag(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args) << "-dynamiclib"; Args.AddAllArgsTranslated(CmdArgs, options::OPT_compatibility__version, "-dylib_compatibility_version"); Args.AddAllArgsTranslated(CmdArgs, options::OPT_current__version, "-dylib_current_version"); AddDarwinArch(Args, CmdArgs); Args.AddAllArgsTranslated(CmdArgs, options::OPT_install__name, "-dylib_install_name"); } Args.AddLastArg(CmdArgs, options::OPT_all__load); Args.AddAllArgs(CmdArgs, options::OPT_allowable__client); Args.AddLastArg(CmdArgs, options::OPT_bind__at__load); if (DarwinTC.isTargetIPhoneOS()) Args.AddLastArg(CmdArgs, options::OPT_arch__errors__fatal); Args.AddLastArg(CmdArgs, options::OPT_dead__strip); Args.AddLastArg(CmdArgs, options::OPT_no__dead__strip__inits__and__terms); Args.AddAllArgs(CmdArgs, options::OPT_dylib__file); Args.AddLastArg(CmdArgs, options::OPT_dynamic); Args.AddAllArgs(CmdArgs, options::OPT_exported__symbols__list); Args.AddLastArg(CmdArgs, options::OPT_flat__namespace); Args.AddAllArgs(CmdArgs, options::OPT_force__load); Args.AddAllArgs(CmdArgs, options::OPT_headerpad__max__install__names); Args.AddAllArgs(CmdArgs, options::OPT_image__base); Args.AddAllArgs(CmdArgs, options::OPT_init); // Add the deployment target. unsigned TargetVersion[3]; DarwinTC.getTargetVersion(TargetVersion); // If we had an explicit -mios-simulator-version-min argument, honor that, // otherwise use the traditional deployment targets. We can't just check the // is-sim attribute because existing code follows this path, and the linker // may not handle the argument. // // FIXME: We may be able to remove this, once we can verify no one depends on // it. if (Args.hasArg(options::OPT_mios_simulator_version_min_EQ)) CmdArgs.push_back("-ios_simulator_version_min"); else if (DarwinTC.isTargetIPhoneOS()) CmdArgs.push_back("-iphoneos_version_min"); else CmdArgs.push_back("-macosx_version_min"); CmdArgs.push_back(Args.MakeArgString(Twine(TargetVersion[0]) + "." + Twine(TargetVersion[1]) + "." + Twine(TargetVersion[2]))); Args.AddLastArg(CmdArgs, options::OPT_nomultidefs); Args.AddLastArg(CmdArgs, options::OPT_multi__module); Args.AddLastArg(CmdArgs, options::OPT_single__module); Args.AddAllArgs(CmdArgs, options::OPT_multiply__defined); Args.AddAllArgs(CmdArgs, options::OPT_multiply__defined__unused); if (const Arg *A = Args.getLastArg(options::OPT_fpie, options::OPT_fPIE, options::OPT_fno_pie, options::OPT_fno_PIE)) { if (A->getOption().matches(options::OPT_fpie) || A->getOption().matches(options::OPT_fPIE)) CmdArgs.push_back("-pie"); else CmdArgs.push_back("-no_pie"); } Args.AddLastArg(CmdArgs, options::OPT_prebind); Args.AddLastArg(CmdArgs, options::OPT_noprebind); Args.AddLastArg(CmdArgs, options::OPT_nofixprebinding); Args.AddLastArg(CmdArgs, options::OPT_prebind__all__twolevel__modules); Args.AddLastArg(CmdArgs, options::OPT_read__only__relocs); Args.AddAllArgs(CmdArgs, options::OPT_sectcreate); Args.AddAllArgs(CmdArgs, options::OPT_sectorder); Args.AddAllArgs(CmdArgs, options::OPT_seg1addr); Args.AddAllArgs(CmdArgs, options::OPT_segprot); Args.AddAllArgs(CmdArgs, options::OPT_segaddr); Args.AddAllArgs(CmdArgs, options::OPT_segs__read__only__addr); Args.AddAllArgs(CmdArgs, options::OPT_segs__read__write__addr); Args.AddAllArgs(CmdArgs, options::OPT_seg__addr__table); Args.AddAllArgs(CmdArgs, options::OPT_seg__addr__table__filename); Args.AddAllArgs(CmdArgs, options::OPT_sub__library); Args.AddAllArgs(CmdArgs, options::OPT_sub__umbrella); // Give --sysroot= preference, over the Apple specific behavior to also use // --isysroot as the syslibroot. if (const Arg *A = Args.getLastArg(options::OPT__sysroot_EQ)) { CmdArgs.push_back("-syslibroot"); CmdArgs.push_back(A->getValue(Args)); } else if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { CmdArgs.push_back("-syslibroot"); CmdArgs.push_back(A->getValue(Args)); } else if (getDarwinToolChain().isTargetIPhoneOS()) { CmdArgs.push_back("-syslibroot"); CmdArgs.push_back("/Developer/SDKs/Extra"); } Args.AddLastArg(CmdArgs, options::OPT_twolevel__namespace); Args.AddLastArg(CmdArgs, options::OPT_twolevel__namespace__hints); Args.AddAllArgs(CmdArgs, options::OPT_umbrella); Args.AddAllArgs(CmdArgs, options::OPT_undefined); Args.AddAllArgs(CmdArgs, options::OPT_unexported__symbols__list); Args.AddAllArgs(CmdArgs, options::OPT_weak__reference__mismatches); Args.AddLastArg(CmdArgs, options::OPT_X_Flag); Args.AddAllArgs(CmdArgs, options::OPT_y); Args.AddLastArg(CmdArgs, options::OPT_w); Args.AddAllArgs(CmdArgs, options::OPT_pagezero__size); Args.AddAllArgs(CmdArgs, options::OPT_segs__read__); Args.AddLastArg(CmdArgs, options::OPT_seglinkedit); Args.AddLastArg(CmdArgs, options::OPT_noseglinkedit); Args.AddAllArgs(CmdArgs, options::OPT_sectalign); Args.AddAllArgs(CmdArgs, options::OPT_sectobjectsymbols); Args.AddAllArgs(CmdArgs, options::OPT_segcreate); Args.AddLastArg(CmdArgs, options::OPT_whyload); Args.AddLastArg(CmdArgs, options::OPT_whatsloaded); Args.AddAllArgs(CmdArgs, options::OPT_dylinker__install__name); Args.AddLastArg(CmdArgs, options::OPT_dylinker); Args.AddLastArg(CmdArgs, options::OPT_Mach); } void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { assert(Output.getType() == types::TY_Image && "Invalid linker output type."); // The logic here is derived from gcc's behavior; most of which // comes from specs (starting with link_command). Consult gcc for // more information. ArgStringList CmdArgs; /// Hack(tm) to ignore linking errors when we are doing ARC migration. if (Args.hasArg(options::OPT_ccc_arcmt_check, options::OPT_ccc_arcmt_migrate)) { for (ArgList::const_iterator I = Args.begin(), E = Args.end(); I != E; ++I) (*I)->claim(); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("touch")); CmdArgs.push_back(Output.getFilename()); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); return; } // I'm not sure why this particular decomposition exists in gcc, but // we follow suite for ease of comparison. AddLinkArgs(C, Args, CmdArgs); Args.AddAllArgs(CmdArgs, options::OPT_d_Flag); Args.AddAllArgs(CmdArgs, options::OPT_s); Args.AddAllArgs(CmdArgs, options::OPT_t); Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); Args.AddAllArgs(CmdArgs, options::OPT_u_Group); Args.AddAllArgs(CmdArgs, options::OPT_A); Args.AddLastArg(CmdArgs, options::OPT_e); Args.AddAllArgs(CmdArgs, options::OPT_m_Separate); Args.AddAllArgs(CmdArgs, options::OPT_r); // Forward -ObjC when either -ObjC or -ObjC++ is used, to force loading // members of static archive libraries which implement Objective-C classes or // categories. if (Args.hasArg(options::OPT_ObjC) || Args.hasArg(options::OPT_ObjCXX)) CmdArgs.push_back("-ObjC"); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); if (!Args.hasArg(options::OPT_A) && !Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { // Derived from startfile spec. if (Args.hasArg(options::OPT_dynamiclib)) { // Derived from darwin_dylib1 spec. if (getDarwinToolChain().isTargetIOSSimulator()) { // The simulator doesn't have a versioned crt1 file. CmdArgs.push_back("-ldylib1.o"); } else if (getDarwinToolChain().isTargetIPhoneOS()) { if (getDarwinToolChain().isIPhoneOSVersionLT(3, 1)) CmdArgs.push_back("-ldylib1.o"); } else { if (getDarwinToolChain().isMacosxVersionLT(10, 5)) CmdArgs.push_back("-ldylib1.o"); else if (getDarwinToolChain().isMacosxVersionLT(10, 6)) CmdArgs.push_back("-ldylib1.10.5.o"); } } else { if (Args.hasArg(options::OPT_bundle)) { if (!Args.hasArg(options::OPT_static)) { // Derived from darwin_bundle1 spec. if (getDarwinToolChain().isTargetIOSSimulator()) { // The simulator doesn't have a versioned crt1 file. CmdArgs.push_back("-lbundle1.o"); } else if (getDarwinToolChain().isTargetIPhoneOS()) { if (getDarwinToolChain().isIPhoneOSVersionLT(3, 1)) CmdArgs.push_back("-lbundle1.o"); } else { if (getDarwinToolChain().isMacosxVersionLT(10, 6)) CmdArgs.push_back("-lbundle1.o"); } } } else { if (Args.hasArg(options::OPT_pg) && getToolChain().SupportsProfiling()) { if (Args.hasArg(options::OPT_static) || Args.hasArg(options::OPT_object) || Args.hasArg(options::OPT_preload)) { CmdArgs.push_back("-lgcrt0.o"); } else { CmdArgs.push_back("-lgcrt1.o"); // darwin_crt2 spec is empty. } } else { if (Args.hasArg(options::OPT_static) || Args.hasArg(options::OPT_object) || Args.hasArg(options::OPT_preload)) { CmdArgs.push_back("-lcrt0.o"); } else { // Derived from darwin_crt1 spec. if (getDarwinToolChain().isTargetIOSSimulator()) { // The simulator doesn't have a versioned crt1 file. CmdArgs.push_back("-lcrt1.o"); } else if (getDarwinToolChain().isTargetIPhoneOS()) { if (getDarwinToolChain().isIPhoneOSVersionLT(3, 1)) CmdArgs.push_back("-lcrt1.o"); else CmdArgs.push_back("-lcrt1.3.1.o"); } else { if (getDarwinToolChain().isMacosxVersionLT(10, 5)) CmdArgs.push_back("-lcrt1.o"); else if (getDarwinToolChain().isMacosxVersionLT(10, 6)) CmdArgs.push_back("-lcrt1.10.5.o"); else CmdArgs.push_back("-lcrt1.10.6.o"); // darwin_crt2 spec is empty. } } } } } if (!getDarwinToolChain().isTargetIPhoneOS() && Args.hasArg(options::OPT_shared_libgcc) && getDarwinToolChain().isMacosxVersionLT(10, 5)) { const char *Str = Args.MakeArgString(getToolChain().GetFilePath("crt3.o")); CmdArgs.push_back(Str); } } Args.AddAllArgs(CmdArgs, options::OPT_L); if (Args.hasArg(options::OPT_fopenmp)) // This is more complicated in gcc... CmdArgs.push_back("-lgomp"); getDarwinToolChain().AddLinkSearchPathArgs(Args, CmdArgs); // In ARC, if we don't have runtime support, link in the runtime // stubs. We have to do this *before* adding any of the normal // linker inputs so that its initializer gets run first. if (isObjCAutoRefCount(Args)) { ObjCRuntime runtime; getDarwinToolChain().configureObjCRuntime(runtime); if (!runtime.HasARC) getDarwinToolChain().AddLinkARCArgs(Args, CmdArgs); } AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); if (LinkingOutput) { CmdArgs.push_back("-arch_multiple"); CmdArgs.push_back("-final_output"); CmdArgs.push_back(LinkingOutput); } if (Args.hasArg(options::OPT_fnested_functions)) CmdArgs.push_back("-allow_stack_execute"); if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { if (getToolChain().getDriver().CCCIsCXX) getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); // link_ssp spec is empty. // Let the tool chain choose which runtime library to link. getDarwinToolChain().AddLinkRuntimeLibArgs(Args, CmdArgs); } if (!Args.hasArg(options::OPT_A) && !Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { // endfile_spec is empty. } addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple()); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_F); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("ld")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { ArgStringList CmdArgs; CmdArgs.push_back("-create"); assert(Output.isFilename() && "Unexpected lipo output."); CmdArgs.push_back("-output"); CmdArgs.push_back(Output.getFilename()); for (InputInfoList::const_iterator it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { const InputInfo &II = *it; assert(II.isFilename() && "Unexpected lipo input."); CmdArgs.push_back(II.getFilename()); } const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("lipo")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void darwin::Dsymutil::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { ArgStringList CmdArgs; CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); assert(Inputs.size() == 1 && "Unable to handle multiple inputs."); const InputInfo &Input = Inputs[0]; assert(Input.isFilename() && "Unexpected dsymutil input."); CmdArgs.push_back(Input.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("dsymutil")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void darwin::VerifyDebug::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { ArgStringList CmdArgs; CmdArgs.push_back("--verify"); assert(Inputs.size() == 1 && "Unable to handle multiple inputs."); const InputInfo &Input = Inputs[0]; assert(Input.isFilename() && "Unexpected verify input"); // Grabbing the output of the earlier dsymutil run. CmdArgs.push_back(Input.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("dwarfdump")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void auroraux::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { ArgStringList CmdArgs; Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); for (InputInfoList::const_iterator it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { const InputInfo &II = *it; CmdArgs.push_back(II.getFilename()); } const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("gas")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { ArgStringList CmdArgs; if ((!Args.hasArg(options::OPT_nostdlib)) && (!Args.hasArg(options::OPT_shared))) { CmdArgs.push_back("-e"); CmdArgs.push_back("_start"); } if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-Bstatic"); CmdArgs.push_back("-dn"); } else { // CmdArgs.push_back("--eh-frame-hdr"); CmdArgs.push_back("-Bdynamic"); if (Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-shared"); } else { CmdArgs.push_back("--dynamic-linker"); CmdArgs.push_back("/lib/ld.so.1"); // 64Bit Path /lib/amd64/ld.so.1 } } if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { assert(Output.isNothing() && "Invalid output."); } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) { CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crt1.o"))); CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crti.o"))); CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crtbegin.o"))); } else { CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crti.o"))); } CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crtn.o"))); } CmdArgs.push_back(Args.MakeArgString("-L/opt/gcc4/lib/gcc/" + getToolChain().getTripleString() + "/4.2.4")); Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_e); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { // FIXME: For some reason GCC passes -lgcc before adding // the default system libraries. Just mimic this for now. CmdArgs.push_back("-lgcc"); if (Args.hasArg(options::OPT_pthread)) CmdArgs.push_back("-pthread"); if (!Args.hasArg(options::OPT_shared)) CmdArgs.push_back("-lc"); CmdArgs.push_back("-lgcc"); } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crtend.o"))); } addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("ld")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void openbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { ArgStringList CmdArgs; Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); for (InputInfoList::const_iterator it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { const InputInfo &II = *it; CmdArgs.push_back(II.getFilename()); } const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; if ((!Args.hasArg(options::OPT_nostdlib)) && (!Args.hasArg(options::OPT_shared))) { CmdArgs.push_back("-e"); CmdArgs.push_back("__start"); } if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-Bstatic"); } else { if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); CmdArgs.push_back("--eh-frame-hdr"); CmdArgs.push_back("-Bdynamic"); if (Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-shared"); } else { CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/usr/libexec/ld.so"); } } if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { assert(Output.isNothing() && "Invalid output."); } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) { CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crt0.o"))); CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crtbegin.o"))); } else { CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crtbeginS.o"))); } } std::string Triple = getToolChain().getTripleString(); if (Triple.substr(0, 6) == "x86_64") Triple.replace(0, 6, "amd64"); CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc-lib/" + Triple + "/4.2.1")); Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_e); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { if (D.CCCIsCXX) { getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } // FIXME: For some reason GCC passes -lgcc before adding // the default system libraries. Just mimic this for now. CmdArgs.push_back("-lgcc"); if (Args.hasArg(options::OPT_pthread)) CmdArgs.push_back("-lpthread"); if (!Args.hasArg(options::OPT_shared)) CmdArgs.push_back("-lc"); CmdArgs.push_back("-lgcc"); } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crtend.o"))); else CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crtendS.o"))); } const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("ld")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { ArgStringList CmdArgs; // When building 32-bit code on FreeBSD/amd64, we have to explicitly // instruct as in the base system to assemble 32-bit code. if (getToolChain().getArchName() == "i386") CmdArgs.push_back("--32"); if (getToolChain().getArchName() == "powerpc") CmdArgs.push_back("-a32"); // Set byte order explicitly if (getToolChain().getArchName() == "mips") CmdArgs.push_back("-EB"); else if (getToolChain().getArchName() == "mipsel") CmdArgs.push_back("-EL"); Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); for (InputInfoList::const_iterator it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { const InputInfo &II = *it; CmdArgs.push_back(II.getFilename()); } const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-Bstatic"); } else { if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); CmdArgs.push_back("--eh-frame-hdr"); if (Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-Bshareable"); } else { CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/libexec/ld-elf.so.1"); } } // When building 32-bit code on FreeBSD/amd64, we have to explicitly // instruct ld in the base system to link 32-bit code. if (getToolChain().getArchName() == "i386") { CmdArgs.push_back("-m"); CmdArgs.push_back("elf_i386_fbsd"); } if (getToolChain().getArchName() == "powerpc") { CmdArgs.push_back("-m"); CmdArgs.push_back("elf32ppc_fbsd"); } if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { assert(Output.isNothing() && "Invalid output."); } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) { if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("gcrt1.o"))); else { const char *crt = Args.hasArg(options::OPT_pie) ? "Scrt1.o" : "crt1.o"; CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath(crt))); } CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crti.o"))); CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crtbegin.o"))); } else { CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crti.o"))); CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crtbeginS.o"))); } } Args.AddAllArgs(CmdArgs, options::OPT_L); const ToolChain::path_list Paths = getToolChain().getFilePaths(); for (ToolChain::path_list::const_iterator i = Paths.begin(), e = Paths.end(); i != e; ++i) CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + *i)); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_e); Args.AddAllArgs(CmdArgs, options::OPT_s); Args.AddAllArgs(CmdArgs, options::OPT_t); Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); Args.AddAllArgs(CmdArgs, options::OPT_r); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { if (D.CCCIsCXX) { getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lm_p"); else CmdArgs.push_back("-lm"); } // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding // the default system libraries. Just mimic this for now. if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lgcc_p"); else CmdArgs.push_back("-lgcc"); if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-lgcc_eh"); } else if (Args.hasArg(options::OPT_pg)) { CmdArgs.push_back("-lgcc_eh_p"); } else { CmdArgs.push_back("--as-needed"); CmdArgs.push_back("-lgcc_s"); CmdArgs.push_back("--no-as-needed"); } if (Args.hasArg(options::OPT_pthread)) { if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lpthread_p"); else CmdArgs.push_back("-lpthread"); } if (Args.hasArg(options::OPT_pg)) { if (Args.hasArg(options::OPT_shared)) CmdArgs.push_back("-lc"); else CmdArgs.push_back("-lc_p"); CmdArgs.push_back("-lgcc_p"); } else { CmdArgs.push_back("-lc"); CmdArgs.push_back("-lgcc"); } if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-lgcc_eh"); } else if (Args.hasArg(options::OPT_pg)) { CmdArgs.push_back("-lgcc_eh_p"); } else { CmdArgs.push_back("--as-needed"); CmdArgs.push_back("-lgcc_s"); CmdArgs.push_back("--no-as-needed"); } } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath( "crtend.o"))); else CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath( "crtendS.o"))); CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath( "crtn.o"))); } addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("ld")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void netbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { ArgStringList CmdArgs; // When building 32-bit code on NetBSD/amd64, we have to explicitly // instruct as in the base system to assemble 32-bit code. if (ToolTriple.getArch() == llvm::Triple::x86_64 && getToolChain().getArch() == llvm::Triple::x86) CmdArgs.push_back("--32"); // Set byte order explicitly if (getToolChain().getArchName() == "mips") CmdArgs.push_back("-EB"); else if (getToolChain().getArchName() == "mipsel") CmdArgs.push_back("-EL"); Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); for (InputInfoList::const_iterator it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { const InputInfo &II = *it; CmdArgs.push_back(II.getFilename()); } const char *Exec = Args.MakeArgString((getToolChain().GetProgramPath("as"))); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-Bstatic"); } else { if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); CmdArgs.push_back("--eh-frame-hdr"); if (Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-Bshareable"); } else { CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/libexec/ld.elf_so"); } } // When building 32-bit code on NetBSD/amd64, we have to explicitly // instruct ld in the base system to link 32-bit code. if (ToolTriple.getArch() == llvm::Triple::x86_64 && getToolChain().getArch() == llvm::Triple::x86) { CmdArgs.push_back("-m"); CmdArgs.push_back("elf_i386"); } if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { assert(Output.isNothing() && "Invalid output."); } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) { CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crt0.o"))); CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crti.o"))); CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crtbegin.o"))); } else { CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crti.o"))); CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crtbeginS.o"))); } } Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_e); Args.AddAllArgs(CmdArgs, options::OPT_s); Args.AddAllArgs(CmdArgs, options::OPT_t); Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); Args.AddAllArgs(CmdArgs, options::OPT_r); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { if (D.CCCIsCXX) { getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding // the default system libraries. Just mimic this for now. if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-lgcc_eh"); } else { CmdArgs.push_back("--as-needed"); CmdArgs.push_back("-lgcc_s"); CmdArgs.push_back("--no-as-needed"); } CmdArgs.push_back("-lgcc"); if (Args.hasArg(options::OPT_pthread)) CmdArgs.push_back("-lpthread"); CmdArgs.push_back("-lc"); CmdArgs.push_back("-lgcc"); if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-lgcc_eh"); } else { CmdArgs.push_back("--as-needed"); CmdArgs.push_back("-lgcc_s"); CmdArgs.push_back("--no-as-needed"); } } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath( "crtend.o"))); else CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath( "crtendS.o"))); CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath( "crtn.o"))); } addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("ld")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void linuxtools::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { ArgStringList CmdArgs; // Add --32/--64 to make sure we get the format we want. // This is incomplete if (getToolChain().getArch() == llvm::Triple::x86) { CmdArgs.push_back("--32"); } else if (getToolChain().getArch() == llvm::Triple::x86_64) { CmdArgs.push_back("--64"); } else if (getToolChain().getArch() == llvm::Triple::arm) { StringRef MArch = getToolChain().getArchName(); if (MArch == "armv7" || MArch == "armv7a" || MArch == "armv7-a") CmdArgs.push_back("-mfpu=neon"); } Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); for (InputInfoList::const_iterator it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { const InputInfo &II = *it; CmdArgs.push_back(II.getFilename()); } const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const toolchains::Linux& ToolChain = static_cast(getToolChain()); const Driver &D = ToolChain.getDriver(); ArgStringList CmdArgs; // Silence warning for "clang -g foo.o -o foo" Args.ClaimAllArgs(options::OPT_g_Group); // and "clang -emit-llvm foo.o -o foo" Args.ClaimAllArgs(options::OPT_emit_llvm); // and for "clang -g foo.o -o foo". Other warning options are already // handled somewhere else. Args.ClaimAllArgs(options::OPT_w); if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); if (Args.hasArg(options::OPT_pie)) CmdArgs.push_back("-pie"); if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); if (Args.hasArg(options::OPT_s)) CmdArgs.push_back("-s"); for (std::vector::const_iterator i = ToolChain.ExtraOpts.begin(), e = ToolChain.ExtraOpts.end(); i != e; ++i) CmdArgs.push_back(i->c_str()); if (!Args.hasArg(options::OPT_static)) { CmdArgs.push_back("--eh-frame-hdr"); } CmdArgs.push_back("-m"); if (ToolChain.getArch() == llvm::Triple::x86) CmdArgs.push_back("elf_i386"); else if (ToolChain.getArch() == llvm::Triple::arm || ToolChain.getArch() == llvm::Triple::thumb) CmdArgs.push_back("armelf_linux_eabi"); else if (ToolChain.getArch() == llvm::Triple::ppc) CmdArgs.push_back("elf32ppclinux"); else if (ToolChain.getArch() == llvm::Triple::ppc64) CmdArgs.push_back("elf64ppc"); else CmdArgs.push_back("elf_x86_64"); if (Args.hasArg(options::OPT_static)) { if (ToolChain.getArch() == llvm::Triple::arm || ToolChain.getArch() == llvm::Triple::thumb) CmdArgs.push_back("-Bstatic"); else CmdArgs.push_back("-static"); } else if (Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-shared"); } if (ToolChain.getArch() == llvm::Triple::arm || ToolChain.getArch() == llvm::Triple::thumb || (!Args.hasArg(options::OPT_static) && !Args.hasArg(options::OPT_shared))) { CmdArgs.push_back("-dynamic-linker"); if (ToolChain.getArch() == llvm::Triple::x86) CmdArgs.push_back("/lib/ld-linux.so.2"); else if (ToolChain.getArch() == llvm::Triple::arm || ToolChain.getArch() == llvm::Triple::thumb) CmdArgs.push_back("/lib/ld-linux.so.3"); else if (ToolChain.getArch() == llvm::Triple::ppc) CmdArgs.push_back("/lib/ld.so.1"); else if (ToolChain.getArch() == llvm::Triple::ppc64) CmdArgs.push_back("/lib64/ld64.so.1"); else CmdArgs.push_back("/lib64/ld-linux-x86-64.so.2"); } CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { const char *crt1 = NULL; if (!Args.hasArg(options::OPT_shared)){ if (Args.hasArg(options::OPT_pie)) crt1 = "Scrt1.o"; else crt1 = "crt1.o"; } if (crt1) CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1))); CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); const char *crtbegin; if (Args.hasArg(options::OPT_static)) crtbegin = "crtbeginT.o"; else if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) crtbegin = "crtbeginS.o"; else crtbegin = "crtbegin.o"; CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); } Args.AddAllArgs(CmdArgs, options::OPT_L); const ToolChain::path_list Paths = ToolChain.getFilePaths(); for (ToolChain::path_list::const_iterator i = Paths.begin(), e = Paths.end(); i != e; ++i) CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + *i)); AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); if (D.CCCIsCXX && !Args.hasArg(options::OPT_nostdlib)) { ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } if (!Args.hasArg(options::OPT_nostdlib)) { if (Args.hasArg(options::OPT_static)) CmdArgs.push_back("--start-group"); if (!D.CCCIsCXX) CmdArgs.push_back("-lgcc"); if (Args.hasArg(options::OPT_static)) { if (D.CCCIsCXX) CmdArgs.push_back("-lgcc"); } else { if (!D.CCCIsCXX) CmdArgs.push_back("--as-needed"); CmdArgs.push_back("-lgcc_s"); if (!D.CCCIsCXX) CmdArgs.push_back("--no-as-needed"); } if (Args.hasArg(options::OPT_static)) CmdArgs.push_back("-lgcc_eh"); else if (!Args.hasArg(options::OPT_shared) && D.CCCIsCXX) CmdArgs.push_back("-lgcc"); if (Args.hasArg(options::OPT_pthread) || Args.hasArg(options::OPT_pthreads)) CmdArgs.push_back("-lpthread"); CmdArgs.push_back("-lc"); if (Args.hasArg(options::OPT_static)) CmdArgs.push_back("--end-group"); else { if (!D.CCCIsCXX) CmdArgs.push_back("-lgcc"); if (!D.CCCIsCXX) CmdArgs.push_back("--as-needed"); CmdArgs.push_back("-lgcc_s"); if (!D.CCCIsCXX) CmdArgs.push_back("--no-as-needed"); if (!Args.hasArg(options::OPT_shared) && D.CCCIsCXX) CmdArgs.push_back("-lgcc"); } if (!Args.hasArg(options::OPT_nostartfiles)) { const char *crtend; if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) crtend = "crtendS.o"; else crtend = "crtend.o"; CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); } } addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple()); if (Args.hasArg(options::OPT_use_gold_plugin)) { CmdArgs.push_back("-plugin"); std::string Plugin = ToolChain.getDriver().Dir + "/../lib/LLVMgold.so"; CmdArgs.push_back(Args.MakeArgString(Plugin)); } C.addCommand(new Command(JA, *this, ToolChain.Linker.c_str(), CmdArgs)); } void minix::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { ArgStringList CmdArgs; Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); for (InputInfoList::const_iterator it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { const InputInfo &II = *it; CmdArgs.push_back(II.getFilename()); } const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("gas")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void minix::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { assert(Output.isNothing() && "Invalid output."); } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath( "/usr/gnu/lib/crtso.o"))); Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_e); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { if (D.CCCIsCXX) { getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } if (Args.hasArg(options::OPT_pthread)) CmdArgs.push_back("-lpthread"); CmdArgs.push_back("-lc"); CmdArgs.push_back("-lgcc"); CmdArgs.push_back("-L/usr/gnu/lib"); // FIXME: fill in the correct search path for the final // support libraries. CmdArgs.push_back("-L/usr/gnu/lib/gcc/i686-pc-minix/4.4.3"); } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath( "/usr/gnu/lib/libend.a"))); } addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("/usr/gnu/bin/gld")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } /// DragonFly Tools // For now, DragonFly Assemble does just about the same as for // FreeBSD, but this may change soon. void dragonfly::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { ArgStringList CmdArgs; // When building 32-bit code on DragonFly/pc64, we have to explicitly // instruct as in the base system to assemble 32-bit code. if (getToolChain().getArchName() == "i386") CmdArgs.push_back("--32"); Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); for (InputInfoList::const_iterator it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { const InputInfo &II = *it; CmdArgs.push_back(II.getFilename()); } const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-Bstatic"); } else { if (Args.hasArg(options::OPT_shared)) CmdArgs.push_back("-Bshareable"); else { CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/usr/libexec/ld-elf.so.2"); } } // When building 32-bit code on DragonFly/pc64, we have to explicitly // instruct ld in the base system to link 32-bit code. if (getToolChain().getArchName() == "i386") { CmdArgs.push_back("-m"); CmdArgs.push_back("elf_i386"); } if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { assert(Output.isNothing() && "Invalid output."); } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) { CmdArgs.push_back( Args.MakeArgString(getToolChain().GetFilePath("crt1.o"))); CmdArgs.push_back( Args.MakeArgString(getToolChain().GetFilePath("crti.o"))); CmdArgs.push_back( Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o"))); } else { CmdArgs.push_back( Args.MakeArgString(getToolChain().GetFilePath("crti.o"))); CmdArgs.push_back( Args.MakeArgString(getToolChain().GetFilePath("crtbeginS.o"))); } } Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_e); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { // FIXME: GCC passes on -lgcc, -lgcc_pic and a whole lot of // rpaths CmdArgs.push_back("-L/usr/lib/gcc41"); if (!Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-rpath"); CmdArgs.push_back("/usr/lib/gcc41"); CmdArgs.push_back("-rpath-link"); CmdArgs.push_back("/usr/lib/gcc41"); CmdArgs.push_back("-rpath"); CmdArgs.push_back("/usr/lib"); CmdArgs.push_back("-rpath-link"); CmdArgs.push_back("/usr/lib"); } if (D.CCCIsCXX) { getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } if (Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-lgcc_pic"); } else { CmdArgs.push_back("-lgcc"); } if (Args.hasArg(options::OPT_pthread)) CmdArgs.push_back("-lpthread"); if (!Args.hasArg(options::OPT_nolibc)) { CmdArgs.push_back("-lc"); } if (Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-lgcc_pic"); } else { CmdArgs.push_back("-lgcc"); } } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crtend.o"))); else CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crtendS.o"))); CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crtn.o"))); } addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("ld")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void visualstudio::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { ArgStringList CmdArgs; if (Output.isFilename()) { CmdArgs.push_back(Args.MakeArgString(std::string("-out:") + Output.getFilename())); } else { assert(Output.isNothing() && "Invalid output."); } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { CmdArgs.push_back("-defaultlib:libcmt"); } CmdArgs.push_back("-nologo"); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("link.exe")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } Index: head/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- head/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp (revision 228378) +++ head/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp (revision 228379) @@ -1,2053 +1,2070 @@ //===--- CompilerInvocation.cpp -------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "clang/Frontend/CompilerInvocation.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/Version.h" #include "clang/Basic/FileManager.h" #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" #include "clang/Driver/CC1Options.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/OptTable.h" #include "clang/Driver/Option.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/LangStandard.h" #include "clang/Serialization/ASTReader.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Host.h" #include "llvm/Support/Path.h" using namespace clang; static const char *getAnalysisStoreName(AnalysisStores Kind) { switch (Kind) { default: llvm_unreachable("Unknown analysis store!"); #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \ case NAME##Model: return CMDFLAG; #include "clang/Frontend/Analyses.def" } } static const char *getAnalysisConstraintName(AnalysisConstraints Kind) { switch (Kind) { default: llvm_unreachable("Unknown analysis constraints!"); #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \ case NAME##Model: return CMDFLAG; #include "clang/Frontend/Analyses.def" } } static const char *getAnalysisDiagClientName(AnalysisDiagClients Kind) { switch (Kind) { default: llvm_unreachable("Unknown analysis client!"); #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREATE) \ case PD_##NAME: return CMDFLAG; #include "clang/Frontend/Analyses.def" } } static const char *getAnalysisPurgeModeName(AnalysisPurgeMode Kind) { switch (Kind) { default: llvm_unreachable("Unknown analysis client!"); #define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) \ case NAME: return CMDFLAG; #include "clang/Frontend/Analyses.def" } } //===----------------------------------------------------------------------===// // Serialization (to args) //===----------------------------------------------------------------------===// static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, std::vector &Res) { if (Opts.ShowCheckerHelp) Res.push_back("-analyzer-checker-help"); if (Opts.AnalysisStoreOpt != RegionStoreModel) { Res.push_back("-analyzer-store"); Res.push_back(getAnalysisStoreName(Opts.AnalysisStoreOpt)); } if (Opts.AnalysisConstraintsOpt != RangeConstraintsModel) { Res.push_back("-analyzer-constraints"); Res.push_back(getAnalysisConstraintName(Opts.AnalysisConstraintsOpt)); } if (Opts.AnalysisDiagOpt != PD_HTML) { Res.push_back("-analyzer-output"); Res.push_back(getAnalysisDiagClientName(Opts.AnalysisDiagOpt)); } if (Opts.AnalysisPurgeOpt != PurgeStmt) { Res.push_back("-analyzer-purge"); Res.push_back(getAnalysisPurgeModeName(Opts.AnalysisPurgeOpt)); } if (!Opts.AnalyzeSpecificFunction.empty()) { Res.push_back("-analyze-function"); Res.push_back(Opts.AnalyzeSpecificFunction); } if (Opts.AnalyzeAll) Res.push_back("-analyzer-opt-analyze-headers"); if (Opts.AnalyzerDisplayProgress) Res.push_back("-analyzer-display-progress"); if (Opts.AnalyzeNestedBlocks) Res.push_back("-analyzer-opt-analyze-nested-blocks"); if (Opts.EagerlyAssume) Res.push_back("-analyzer-eagerly-assume"); if (Opts.TrimGraph) Res.push_back("-trim-egraph"); if (Opts.VisualizeEGDot) Res.push_back("-analyzer-viz-egraph-graphviz"); if (Opts.VisualizeEGUbi) Res.push_back("-analyzer-viz-egraph-ubigraph"); for (unsigned i = 0, e = Opts.CheckersControlList.size(); i != e; ++i) { const std::pair &opt = Opts.CheckersControlList[i]; if (opt.second) Res.push_back("-analyzer-disable-checker"); else Res.push_back("-analyzer-checker"); Res.push_back(opt.first); } } static void CodeGenOptsToArgs(const CodeGenOptions &Opts, std::vector &Res) { if (Opts.DebugInfo) Res.push_back("-g"); if (Opts.DisableLLVMOpts) Res.push_back("-disable-llvm-optzns"); if (Opts.DisableRedZone) Res.push_back("-disable-red-zone"); if (!Opts.DwarfDebugFlags.empty()) { Res.push_back("-dwarf-debug-flags"); Res.push_back(Opts.DwarfDebugFlags); } if (Opts.ObjCRuntimeHasARC) Res.push_back("-fobjc-runtime-has-arc"); if (Opts.ObjCRuntimeHasTerminate) Res.push_back("-fobjc-runtime-has-terminate"); if (Opts.EmitGcovArcs) Res.push_back("-femit-coverage-data"); if (Opts.EmitGcovNotes) Res.push_back("-femit-coverage-notes"); if (!Opts.MergeAllConstants) Res.push_back("-fno-merge-all-constants"); if (Opts.NoCommon) Res.push_back("-fno-common"); if (Opts.ForbidGuardVariables) Res.push_back("-fforbid-guard-variables"); if (Opts.UseRegisterSizedBitfieldAccess) Res.push_back("-fuse-register-sized-bitfield-access"); if (Opts.NoImplicitFloat) Res.push_back("-no-implicit-float"); if (Opts.OmitLeafFramePointer) Res.push_back("-momit-leaf-frame-pointer"); if (Opts.OptimizeSize) { assert(Opts.OptimizationLevel == 2 && "Invalid options!"); Opts.OptimizeSize == 1 ? Res.push_back("-Os") : Res.push_back("-Oz"); } else if (Opts.OptimizationLevel != 0) Res.push_back("-O" + llvm::utostr(Opts.OptimizationLevel)); if (!Opts.MainFileName.empty()) { Res.push_back("-main-file-name"); Res.push_back(Opts.MainFileName); } // SimplifyLibCalls is only derived. // TimePasses is only derived. // UnitAtATime is unused. // Inlining is only derived. // UnrollLoops is derived, but also accepts an option, no // harm in pushing it back here. if (Opts.UnrollLoops) Res.push_back("-funroll-loops"); if (Opts.DataSections) Res.push_back("-fdata-sections"); if (Opts.FunctionSections) Res.push_back("-ffunction-sections"); if (Opts.AsmVerbose) Res.push_back("-masm-verbose"); if (!Opts.CodeModel.empty()) { Res.push_back("-mcode-model"); Res.push_back(Opts.CodeModel); } if (Opts.CUDAIsDevice) Res.push_back("-fcuda-is-device"); if (!Opts.CXAAtExit) Res.push_back("-fno-use-cxa-atexit"); if (Opts.CXXCtorDtorAliases) Res.push_back("-mconstructor-aliases"); if (Opts.ObjCAutoRefCountExceptions) Res.push_back("-fobjc-arc-eh"); if (!Opts.DebugPass.empty()) { Res.push_back("-mdebug-pass"); Res.push_back(Opts.DebugPass); } if (Opts.DisableFPElim) Res.push_back("-mdisable-fp-elim"); if (!Opts.FloatABI.empty()) { Res.push_back("-mfloat-abi"); Res.push_back(Opts.FloatABI); } if (!Opts.LimitFloatPrecision.empty()) { Res.push_back("-mlimit-float-precision"); Res.push_back(Opts.LimitFloatPrecision); } if (Opts.NoZeroInitializedInBSS) Res.push_back("-mno-zero-initialized-bss"); switch (Opts.getObjCDispatchMethod()) { case CodeGenOptions::Legacy: break; case CodeGenOptions::Mixed: Res.push_back("-fobjc-dispatch-method=mixed"); break; case CodeGenOptions::NonLegacy: Res.push_back("-fobjc-dispatch-method=non-legacy"); break; } if (Opts.NumRegisterParameters) { Res.push_back("-mregparm"); Res.push_back(llvm::utostr(Opts.NumRegisterParameters)); } if (Opts.NoGlobalMerge) Res.push_back("-mno-global-merge"); if (Opts.NoExecStack) Res.push_back("-mnoexecstack"); if (Opts.RelaxAll) Res.push_back("-mrelax-all"); if (Opts.SaveTempLabels) Res.push_back("-msave-temp-labels"); if (Opts.NoDwarf2CFIAsm) Res.push_back("-fno-dwarf2-cfi-asm"); if (Opts.SoftFloat) Res.push_back("-msoft-float"); if (Opts.UnwindTables) Res.push_back("-munwind-tables"); if (Opts.RelocationModel != "pic") { Res.push_back("-mrelocation-model"); Res.push_back(Opts.RelocationModel); } if (!Opts.VerifyModule) Res.push_back("-disable-llvm-verifier"); for (unsigned i = 0, e = Opts.BackendOptions.size(); i != e; ++i) { Res.push_back("-backend-option"); Res.push_back(Opts.BackendOptions[i]); } } static void DependencyOutputOptsToArgs(const DependencyOutputOptions &Opts, std::vector &Res) { if (Opts.IncludeSystemHeaders) Res.push_back("-sys-header-deps"); if (Opts.ShowHeaderIncludes) Res.push_back("-H"); if (!Opts.HeaderIncludeOutputFile.empty()) { Res.push_back("-header-include-file"); Res.push_back(Opts.HeaderIncludeOutputFile); } if (Opts.UsePhonyTargets) Res.push_back("-MP"); if (!Opts.OutputFile.empty()) { Res.push_back("-dependency-file"); Res.push_back(Opts.OutputFile); } for (unsigned i = 0, e = Opts.Targets.size(); i != e; ++i) { Res.push_back("-MT"); Res.push_back(Opts.Targets[i]); } } static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts, std::vector &Res) { if (Opts.IgnoreWarnings) Res.push_back("-w"); if (Opts.NoRewriteMacros) Res.push_back("-Wno-rewrite-macros"); if (Opts.Pedantic) Res.push_back("-pedantic"); if (Opts.PedanticErrors) Res.push_back("-pedantic-errors"); if (!Opts.ShowColumn) Res.push_back("-fno-show-column"); if (!Opts.ShowLocation) Res.push_back("-fno-show-source-location"); if (!Opts.ShowCarets) Res.push_back("-fno-caret-diagnostics"); if (!Opts.ShowFixits) Res.push_back("-fno-diagnostics-fixit-info"); if (Opts.ShowSourceRanges) Res.push_back("-fdiagnostics-print-source-range-info"); if (Opts.ShowParseableFixits) Res.push_back("-fdiagnostics-parseable-fixits"); if (Opts.ShowColors) Res.push_back("-fcolor-diagnostics"); if (Opts.VerifyDiagnostics) Res.push_back("-verify"); if (Opts.ShowNames) Res.push_back("-fdiagnostics-show-name"); if (Opts.ShowOptionNames) Res.push_back("-fdiagnostics-show-option"); if (Opts.ShowCategories == 1) Res.push_back("-fdiagnostics-show-category=id"); else if (Opts.ShowCategories == 2) Res.push_back("-fdiagnostics-show-category=name"); switch (Opts.Format) { case DiagnosticOptions::Clang: Res.push_back("-fdiagnostics-format=clang"); break; case DiagnosticOptions::Msvc: Res.push_back("-fdiagnostics-format=msvc"); break; case DiagnosticOptions::Vi: Res.push_back("-fdiagnostics-format=vi"); break; } if (Opts.ErrorLimit) { Res.push_back("-ferror-limit"); Res.push_back(llvm::utostr(Opts.ErrorLimit)); } if (!Opts.DiagnosticLogFile.empty()) { Res.push_back("-diagnostic-log-file"); Res.push_back(Opts.DiagnosticLogFile); } if (Opts.MacroBacktraceLimit != DiagnosticOptions::DefaultMacroBacktraceLimit) { Res.push_back("-fmacro-backtrace-limit"); Res.push_back(llvm::utostr(Opts.MacroBacktraceLimit)); } if (Opts.TemplateBacktraceLimit != DiagnosticOptions::DefaultTemplateBacktraceLimit) { Res.push_back("-ftemplate-backtrace-limit"); Res.push_back(llvm::utostr(Opts.TemplateBacktraceLimit)); } if (Opts.TabStop != DiagnosticOptions::DefaultTabStop) { Res.push_back("-ftabstop"); Res.push_back(llvm::utostr(Opts.TabStop)); } if (Opts.MessageLength) { Res.push_back("-fmessage-length"); Res.push_back(llvm::utostr(Opts.MessageLength)); } if (!Opts.DumpBuildInformation.empty()) { Res.push_back("-dump-build-information"); Res.push_back(Opts.DumpBuildInformation); } for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) Res.push_back("-W" + Opts.Warnings[i]); } static const char *getInputKindName(InputKind Kind) { switch (Kind) { case IK_None: break; case IK_AST: return "ast"; case IK_Asm: return "assembler-with-cpp"; case IK_C: return "c"; case IK_CXX: return "c++"; case IK_LLVM_IR: return "ir"; case IK_ObjC: return "objective-c"; case IK_ObjCXX: return "objective-c++"; case IK_OpenCL: return "cl"; case IK_CUDA: return "cuda"; case IK_PreprocessedC: return "cpp-output"; case IK_PreprocessedCXX: return "c++-cpp-output"; case IK_PreprocessedObjC: return "objective-c-cpp-output"; case IK_PreprocessedObjCXX:return "objective-c++-cpp-output"; } llvm_unreachable("Unexpected language kind!"); return 0; } static const char *getActionName(frontend::ActionKind Kind) { switch (Kind) { case frontend::PluginAction: llvm_unreachable("Invalid kind!"); case frontend::ASTDump: return "-ast-dump"; case frontend::ASTDumpXML: return "-ast-dump-xml"; case frontend::ASTPrint: return "-ast-print"; case frontend::ASTView: return "-ast-view"; case frontend::DumpRawTokens: return "-dump-raw-tokens"; case frontend::DumpTokens: return "-dump-tokens"; case frontend::EmitAssembly: return "-S"; case frontend::EmitBC: return "-emit-llvm-bc"; case frontend::EmitHTML: return "-emit-html"; case frontend::EmitLLVM: return "-emit-llvm"; case frontend::EmitLLVMOnly: return "-emit-llvm-only"; case frontend::EmitCodeGenOnly: return "-emit-codegen-only"; case frontend::EmitObj: return "-emit-obj"; case frontend::FixIt: return "-fixit"; case frontend::GenerateModule: return "-emit-module"; case frontend::GeneratePCH: return "-emit-pch"; case frontend::GeneratePTH: return "-emit-pth"; case frontend::InitOnly: return "-init-only"; case frontend::ParseSyntaxOnly: return "-fsyntax-only"; case frontend::PrintDeclContext: return "-print-decl-contexts"; case frontend::PrintPreamble: return "-print-preamble"; case frontend::PrintPreprocessedInput: return "-E"; case frontend::RewriteMacros: return "-rewrite-macros"; case frontend::RewriteObjC: return "-rewrite-objc"; case frontend::RewriteTest: return "-rewrite-test"; case frontend::RunAnalysis: return "-analyze"; case frontend::RunPreprocessorOnly: return "-Eonly"; } llvm_unreachable("Unexpected language kind!"); return 0; } static void FileSystemOptsToArgs(const FileSystemOptions &Opts, std::vector &Res) { if (!Opts.WorkingDir.empty()) { Res.push_back("-working-directory"); Res.push_back(Opts.WorkingDir); } } static void FrontendOptsToArgs(const FrontendOptions &Opts, std::vector &Res) { if (Opts.DisableFree) Res.push_back("-disable-free"); if (Opts.RelocatablePCH) Res.push_back("-relocatable-pch"); if (Opts.ShowHelp) Res.push_back("-help"); if (Opts.ShowMacrosInCodeCompletion) Res.push_back("-code-completion-macros"); if (Opts.ShowCodePatternsInCodeCompletion) Res.push_back("-code-completion-patterns"); if (!Opts.ShowGlobalSymbolsInCodeCompletion) Res.push_back("-no-code-completion-globals"); if (Opts.ShowStats) Res.push_back("-print-stats"); if (Opts.ShowTimers) Res.push_back("-ftime-report"); if (Opts.ShowVersion) Res.push_back("-version"); if (Opts.FixWhatYouCan) Res.push_back("-fix-what-you-can"); switch (Opts.ARCMTAction) { case FrontendOptions::ARCMT_None: break; case FrontendOptions::ARCMT_Check: Res.push_back("-arcmt-check"); break; case FrontendOptions::ARCMT_Modify: Res.push_back("-arcmt-modify"); break; case FrontendOptions::ARCMT_Migrate: Res.push_back("-arcmt-migrate"); break; } if (!Opts.ARCMTMigrateDir.empty()) { Res.push_back("-arcmt-migrate-directory"); Res.push_back(Opts.ARCMTMigrateDir); } if (!Opts.ARCMTMigrateReportOut.empty()) { Res.push_back("-arcmt-migrate-report-output"); Res.push_back(Opts.ARCMTMigrateReportOut); } if (Opts.ARCMTMigrateEmitARCErrors) Res.push_back("-arcmt-migrate-emit-errors"); bool NeedLang = false; for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i) if (FrontendOptions::getInputKindForExtension(Opts.Inputs[i].second) != Opts.Inputs[i].first) NeedLang = true; if (NeedLang) { Res.push_back("-x"); Res.push_back(getInputKindName(Opts.Inputs[0].first)); } for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i) { assert((!NeedLang || Opts.Inputs[i].first == Opts.Inputs[0].first) && "Unable to represent this input vector!"); Res.push_back(Opts.Inputs[i].second); } if (!Opts.OutputFile.empty()) { Res.push_back("-o"); Res.push_back(Opts.OutputFile); } if (!Opts.CodeCompletionAt.FileName.empty()) { Res.push_back("-code-completion-at"); Res.push_back(Opts.CodeCompletionAt.FileName + ":" + llvm::utostr(Opts.CodeCompletionAt.Line) + ":" + llvm::utostr(Opts.CodeCompletionAt.Column)); } if (Opts.ProgramAction != frontend::PluginAction) Res.push_back(getActionName(Opts.ProgramAction)); if (!Opts.ActionName.empty()) { Res.push_back("-plugin"); Res.push_back(Opts.ActionName); for(unsigned i = 0, e = Opts.PluginArgs.size(); i != e; ++i) { Res.push_back("-plugin-arg-" + Opts.ActionName); Res.push_back(Opts.PluginArgs[i]); } } for (unsigned i = 0, e = Opts.Plugins.size(); i != e; ++i) { Res.push_back("-load"); Res.push_back(Opts.Plugins[i]); } for (unsigned i = 0, e = Opts.AddPluginActions.size(); i != e; ++i) { Res.push_back("-add-plugin"); Res.push_back(Opts.AddPluginActions[i]); for(unsigned ai = 0, ae = Opts.AddPluginArgs.size(); ai != ae; ++ai) { Res.push_back("-plugin-arg-" + Opts.AddPluginActions[i]); Res.push_back(Opts.AddPluginArgs[i][ai]); } } for (unsigned i = 0, e = Opts.ASTMergeFiles.size(); i != e; ++i) { Res.push_back("-ast-merge"); Res.push_back(Opts.ASTMergeFiles[i]); } for (unsigned i = 0, e = Opts.LLVMArgs.size(); i != e; ++i) { Res.push_back("-mllvm"); Res.push_back(Opts.LLVMArgs[i]); } } static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts, std::vector &Res) { if (Opts.Sysroot != "/") { Res.push_back("-isysroot"); Res.push_back(Opts.Sysroot); } /// User specified include entries. for (unsigned i = 0, e = Opts.UserEntries.size(); i != e; ++i) { const HeaderSearchOptions::Entry &E = Opts.UserEntries[i]; if (E.IsFramework && (E.Group != frontend::Angled || !E.IsUserSupplied)) llvm::report_fatal_error("Invalid option set!"); if (E.IsUserSupplied) { switch (E.Group) { case frontend::After: Res.push_back("-idirafter"); break; case frontend::Quoted: Res.push_back("-iquote"); break; case frontend::System: Res.push_back("-isystem"); break; case frontend::IndexHeaderMap: Res.push_back("-index-header-map"); Res.push_back(E.IsFramework? "-F" : "-I"); break; case frontend::CSystem: Res.push_back("-c-isystem"); break; case frontend::CXXSystem: Res.push_back("-cxx-isystem"); break; case frontend::ObjCSystem: Res.push_back("-objc-isystem"); break; case frontend::ObjCXXSystem: Res.push_back("-objcxx-isystem"); break; case frontend::Angled: Res.push_back(E.IsFramework ? "-F" : "-I"); break; } } else { - if (E.Group != frontend::Angled && E.Group != frontend::System) - llvm::report_fatal_error("Invalid option set!"); - Res.push_back(E.Group == frontend::Angled ? "-iwithprefixbefore" : - "-iwithprefix"); + if (E.IsInternal) { + assert(E.Group == frontend::System && "Unexpected header search group"); + if (E.ImplicitExternC) + Res.push_back("-internal-externc-isystem"); + else + Res.push_back("-internal-isystem"); + } else { + if (E.Group != frontend::Angled && E.Group != frontend::System) + llvm::report_fatal_error("Invalid option set!"); + Res.push_back(E.Group == frontend::Angled ? "-iwithprefixbefore" : + "-iwithprefix"); + } } Res.push_back(E.Path); } if (!Opts.ResourceDir.empty()) { Res.push_back("-resource-dir"); Res.push_back(Opts.ResourceDir); } if (!Opts.ModuleCachePath.empty()) { Res.push_back("-fmodule-cache-path"); Res.push_back(Opts.ModuleCachePath); } if (!Opts.UseStandardSystemIncludes) Res.push_back("-nostdsysteminc"); if (!Opts.UseStandardCXXIncludes) Res.push_back("-nostdinc++"); if (Opts.UseLibcxx) Res.push_back("-stdlib=libc++"); if (Opts.Verbose) Res.push_back("-v"); } static void LangOptsToArgs(const LangOptions &Opts, std::vector &Res) { LangOptions DefaultLangOpts; // FIXME: Need to set -std to get all the implicit options. // FIXME: We want to only pass options relative to the defaults, which // requires constructing a target. :( // // It would be better to push the all target specific choices into the driver, // so that everything below that was more uniform. if (Opts.Trigraphs) Res.push_back("-trigraphs"); // Implicit based on the input kind: // AsmPreprocessor, CPlusPlus, ObjC1, ObjC2, OpenCL // Implicit based on the input language standard: // BCPLComment, C99, CPlusPlus0x, Digraphs, GNUInline, ImplicitInt, GNUMode if (Opts.DollarIdents) Res.push_back("-fdollars-in-identifiers"); if (Opts.GNUMode && !Opts.GNUKeywords) Res.push_back("-fno-gnu-keywords"); if (!Opts.GNUMode && Opts.GNUKeywords) Res.push_back("-fgnu-keywords"); if (Opts.MicrosoftExt) Res.push_back("-fms-extensions"); if (Opts.MSCVersion != 0) Res.push_back("-fmsc-version=" + llvm::utostr(Opts.MSCVersion)); if (Opts.Borland) Res.push_back("-fborland-extensions"); if (!Opts.ObjCNonFragileABI) Res.push_back("-fobjc-fragile-abi"); if (Opts.ObjCDefaultSynthProperties) Res.push_back("-fobjc-default-synthesize-properties"); // NoInline is implicit. if (!Opts.CXXOperatorNames) Res.push_back("-fno-operator-names"); if (Opts.PascalStrings) Res.push_back("-fpascal-strings"); if (Opts.CatchUndefined) Res.push_back("-fcatch-undefined-behavior"); if (Opts.WritableStrings) Res.push_back("-fwritable-strings"); if (Opts.ConstStrings) Res.push_back("-fconst-strings"); if (!Opts.LaxVectorConversions) Res.push_back("-fno-lax-vector-conversions"); if (Opts.AltiVec) Res.push_back("-faltivec"); if (Opts.Exceptions) Res.push_back("-fexceptions"); if (Opts.ObjCExceptions) Res.push_back("-fobjc-exceptions"); if (Opts.CXXExceptions) Res.push_back("-fcxx-exceptions"); if (Opts.SjLjExceptions) Res.push_back("-fsjlj-exceptions"); if (Opts.TraditionalCPP) Res.push_back("-traditional-cpp"); if (!Opts.RTTI) Res.push_back("-fno-rtti"); if (Opts.MSBitfields) Res.push_back("-mms-bitfields"); if (!Opts.NeXTRuntime) Res.push_back("-fgnu-runtime"); if (Opts.Freestanding) Res.push_back("-ffreestanding"); if (Opts.FormatExtensions) Res.push_back("-fformat-extensions"); if (Opts.NoBuiltin) Res.push_back("-fno-builtin"); if (!Opts.AssumeSaneOperatorNew) Res.push_back("-fno-assume-sane-operator-new"); if (!Opts.ThreadsafeStatics) Res.push_back("-fno-threadsafe-statics"); if (Opts.POSIXThreads) Res.push_back("-pthread"); if (Opts.Blocks) Res.push_back("-fblocks"); if (Opts.BlocksRuntimeOptional) Res.push_back("-fblocks-runtime-optional"); if (Opts.EmitAllDecls) Res.push_back("-femit-all-decls"); if (Opts.MathErrno) Res.push_back("-fmath-errno"); switch (Opts.getSignedOverflowBehavior()) { case LangOptions::SOB_Undefined: break; case LangOptions::SOB_Defined: Res.push_back("-fwrapv"); break; case LangOptions::SOB_Trapping: Res.push_back("-ftrapv"); break; if (!Opts.OverflowHandler.empty()) { Res.push_back("-ftrapv-handler"); Res.push_back(Opts.OverflowHandler); } } if (Opts.HeinousExtensions) Res.push_back("-fheinous-gnu-extensions"); // Optimize is implicit. // OptimizeSize is implicit. if (Opts.Static) Res.push_back("-static-define"); if (Opts.DumpRecordLayouts) Res.push_back("-fdump-record-layouts"); if (Opts.DumpVTableLayouts) Res.push_back("-fdump-vtable-layouts"); if (Opts.NoBitFieldTypeAlign) Res.push_back("-fno-bitfield-type-alignment"); if (Opts.PICLevel) { Res.push_back("-pic-level"); Res.push_back(llvm::utostr(Opts.PICLevel)); } if (Opts.ObjCGCBitmapPrint) Res.push_back("-print-ivar-layout"); if (Opts.NoConstantCFStrings) Res.push_back("-fno-constant-cfstrings"); if (!Opts.AccessControl) Res.push_back("-fno-access-control"); if (!Opts.CharIsSigned) Res.push_back("-fno-signed-char"); if (Opts.ShortWChar) Res.push_back("-fshort-wchar"); if (!Opts.ElideConstructors) Res.push_back("-fno-elide-constructors"); if (Opts.getGC() != LangOptions::NonGC) { if (Opts.getGC() == LangOptions::HybridGC) { Res.push_back("-fobjc-gc"); } else { assert(Opts.getGC() == LangOptions::GCOnly && "Invalid GC mode!"); Res.push_back("-fobjc-gc-only"); } } if (Opts.ObjCAutoRefCount) Res.push_back("-fobjc-arc"); if (Opts.ObjCRuntimeHasWeak) Res.push_back("-fobjc-runtime-has-weak"); if (!Opts.ObjCInferRelatedResultType) Res.push_back("-fno-objc-infer-related-result-type"); if (Opts.AppleKext) Res.push_back("-fapple-kext"); if (Opts.getVisibilityMode() != DefaultVisibility) { Res.push_back("-fvisibility"); if (Opts.getVisibilityMode() == HiddenVisibility) { Res.push_back("hidden"); } else { assert(Opts.getVisibilityMode() == ProtectedVisibility && "Invalid visibility!"); Res.push_back("protected"); } } if (Opts.InlineVisibilityHidden) Res.push_back("-fvisibility-inlines-hidden"); if (Opts.getStackProtector() != 0) { Res.push_back("-stack-protector"); Res.push_back(llvm::utostr(Opts.getStackProtector())); } if (Opts.InstantiationDepth != DefaultLangOpts.InstantiationDepth) { Res.push_back("-ftemplate-depth"); Res.push_back(llvm::utostr(Opts.InstantiationDepth)); } if (!Opts.ObjCConstantStringClass.empty()) { Res.push_back("-fconstant-string-class"); Res.push_back(Opts.ObjCConstantStringClass); } if (Opts.FakeAddressSpaceMap) Res.push_back("-ffake-address-space-map"); if (Opts.ParseUnknownAnytype) Res.push_back("-funknown-anytype"); if (Opts.DebuggerSupport) Res.push_back("-fdebugger-support"); if (Opts.DelayedTemplateParsing) Res.push_back("-fdelayed-template-parsing"); if (Opts.Deprecated) Res.push_back("-fdeprecated-macro"); } static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts, std::vector &Res) { for (unsigned i = 0, e = Opts.Macros.size(); i != e; ++i) Res.push_back(std::string(Opts.Macros[i].second ? "-U" : "-D") + Opts.Macros[i].first); for (unsigned i = 0, e = Opts.Includes.size(); i != e; ++i) { // FIXME: We need to avoid reincluding the implicit PCH and PTH includes. Res.push_back("-include"); Res.push_back(Opts.Includes[i]); } for (unsigned i = 0, e = Opts.MacroIncludes.size(); i != e; ++i) { Res.push_back("-imacros"); Res.push_back(Opts.MacroIncludes[i]); } if (!Opts.UsePredefines) Res.push_back("-undef"); if (Opts.DetailedRecord) Res.push_back("-detailed-preprocessing-record"); if (!Opts.ImplicitPCHInclude.empty()) { Res.push_back("-include-pch"); Res.push_back(Opts.ImplicitPCHInclude); } if (!Opts.ImplicitPTHInclude.empty()) { Res.push_back("-include-pth"); Res.push_back(Opts.ImplicitPTHInclude); } if (!Opts.TokenCache.empty()) { if (Opts.ImplicitPTHInclude.empty()) { Res.push_back("-token-cache"); Res.push_back(Opts.TokenCache); } else assert(Opts.ImplicitPTHInclude == Opts.TokenCache && "Unsupported option combination!"); } for (unsigned i = 0, e = Opts.ChainedIncludes.size(); i != e; ++i) { Res.push_back("-chain-include"); Res.push_back(Opts.ChainedIncludes[i]); } for (unsigned i = 0, e = Opts.RemappedFiles.size(); i != e; ++i) { Res.push_back("-remap-file"); Res.push_back(Opts.RemappedFiles[i].first + ";" + Opts.RemappedFiles[i].second); } } static void PreprocessorOutputOptsToArgs(const PreprocessorOutputOptions &Opts, std::vector &Res) { if (!Opts.ShowCPP && !Opts.ShowMacros) llvm::report_fatal_error("Invalid option combination!"); if (Opts.ShowCPP && Opts.ShowMacros) Res.push_back("-dD"); else if (!Opts.ShowCPP && Opts.ShowMacros) Res.push_back("-dM"); if (!Opts.ShowLineMarkers) Res.push_back("-P"); if (Opts.ShowComments) Res.push_back("-C"); if (Opts.ShowMacroComments) Res.push_back("-CC"); } static void TargetOptsToArgs(const TargetOptions &Opts, std::vector &Res) { Res.push_back("-triple"); Res.push_back(Opts.Triple); if (!Opts.CPU.empty()) { Res.push_back("-target-cpu"); Res.push_back(Opts.CPU); } if (!Opts.ABI.empty()) { Res.push_back("-target-abi"); Res.push_back(Opts.ABI); } if (!Opts.LinkerVersion.empty()) { Res.push_back("-target-linker-version"); Res.push_back(Opts.LinkerVersion); } if (!Opts.CXXABI.empty()) { Res.push_back("-cxx-abi"); Res.push_back(Opts.CXXABI); } for (unsigned i = 0, e = Opts.Features.size(); i != e; ++i) { Res.push_back("-target-feature"); Res.push_back(Opts.Features[i]); } } void CompilerInvocation::toArgs(std::vector &Res) { AnalyzerOptsToArgs(getAnalyzerOpts(), Res); CodeGenOptsToArgs(getCodeGenOpts(), Res); DependencyOutputOptsToArgs(getDependencyOutputOpts(), Res); DiagnosticOptsToArgs(getDiagnosticOpts(), Res); FileSystemOptsToArgs(getFileSystemOpts(), Res); FrontendOptsToArgs(getFrontendOpts(), Res); HeaderSearchOptsToArgs(getHeaderSearchOpts(), Res); LangOptsToArgs(getLangOpts(), Res); PreprocessorOptsToArgs(getPreprocessorOpts(), Res); PreprocessorOutputOptsToArgs(getPreprocessorOutputOpts(), Res); TargetOptsToArgs(getTargetOpts(), Res); } //===----------------------------------------------------------------------===// // Deserialization (to args) //===----------------------------------------------------------------------===// using namespace clang::driver; using namespace clang::driver::cc1options; // static unsigned getOptimizationLevel(ArgList &Args, InputKind IK, DiagnosticsEngine &Diags) { unsigned DefaultOpt = 0; if (IK == IK_OpenCL && !Args.hasArg(OPT_cl_opt_disable)) DefaultOpt = 2; // -Os/-Oz implies -O2 return (Args.hasArg(OPT_Os) || Args.hasArg (OPT_Oz)) ? 2 : Args.getLastArgIntValue(OPT_O, DefaultOpt, Diags); } static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, DiagnosticsEngine &Diags) { using namespace cc1options; if (Arg *A = Args.getLastArg(OPT_analyzer_store)) { StringRef Name = A->getValue(Args); AnalysisStores Value = llvm::StringSwitch(Name) #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \ .Case(CMDFLAG, NAME##Model) #include "clang/Frontend/Analyses.def" .Default(NumStores); // FIXME: Error handling. if (Value == NumStores) Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name; else Opts.AnalysisStoreOpt = Value; } if (Arg *A = Args.getLastArg(OPT_analyzer_constraints)) { StringRef Name = A->getValue(Args); AnalysisConstraints Value = llvm::StringSwitch(Name) #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \ .Case(CMDFLAG, NAME##Model) #include "clang/Frontend/Analyses.def" .Default(NumConstraints); // FIXME: Error handling. if (Value == NumConstraints) Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name; else Opts.AnalysisConstraintsOpt = Value; } if (Arg *A = Args.getLastArg(OPT_analyzer_output)) { StringRef Name = A->getValue(Args); AnalysisDiagClients Value = llvm::StringSwitch(Name) #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREAT) \ .Case(CMDFLAG, PD_##NAME) #include "clang/Frontend/Analyses.def" .Default(NUM_ANALYSIS_DIAG_CLIENTS); // FIXME: Error handling. if (Value == NUM_ANALYSIS_DIAG_CLIENTS) Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name; else Opts.AnalysisDiagOpt = Value; } if (Arg *A = Args.getLastArg(OPT_analyzer_purge)) { StringRef Name = A->getValue(Args); AnalysisPurgeMode Value = llvm::StringSwitch(Name) #define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) \ .Case(CMDFLAG, NAME) #include "clang/Frontend/Analyses.def" .Default(NumPurgeModes); // FIXME: Error handling. if (Value == NumPurgeModes) Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name; else Opts.AnalysisPurgeOpt = Value; } Opts.ShowCheckerHelp = Args.hasArg(OPT_analyzer_checker_help); Opts.VisualizeEGDot = Args.hasArg(OPT_analyzer_viz_egraph_graphviz); Opts.VisualizeEGUbi = Args.hasArg(OPT_analyzer_viz_egraph_ubigraph); Opts.AnalyzeAll = Args.hasArg(OPT_analyzer_opt_analyze_headers); Opts.AnalyzerDisplayProgress = Args.hasArg(OPT_analyzer_display_progress); Opts.AnalyzeNestedBlocks = Args.hasArg(OPT_analyzer_opt_analyze_nested_blocks); Opts.EagerlyAssume = Args.hasArg(OPT_analyzer_eagerly_assume); Opts.AnalyzeSpecificFunction = Args.getLastArgValue(OPT_analyze_function); Opts.UnoptimizedCFG = Args.hasArg(OPT_analysis_UnoptimizedCFG); Opts.CFGAddImplicitDtors = Args.hasArg(OPT_analysis_CFGAddImplicitDtors); Opts.CFGAddInitializers = Args.hasArg(OPT_analysis_CFGAddInitializers); Opts.TrimGraph = Args.hasArg(OPT_trim_egraph); Opts.MaxNodes = Args.getLastArgIntValue(OPT_analyzer_max_nodes, 150000,Diags); Opts.MaxLoop = Args.getLastArgIntValue(OPT_analyzer_max_loop, 4, Diags); Opts.EagerlyTrimEGraph = !Args.hasArg(OPT_analyzer_no_eagerly_trim_egraph); Opts.InlineCall = Args.hasArg(OPT_analyzer_inline_call); Opts.CheckersControlList.clear(); for (arg_iterator it = Args.filtered_begin(OPT_analyzer_checker, OPT_analyzer_disable_checker), ie = Args.filtered_end(); it != ie; ++it) { const Arg *A = *it; A->claim(); bool enable = (A->getOption().getID() == OPT_analyzer_checker); // We can have a list of comma separated checker names, e.g: // '-analyzer-checker=cocoa,unix' StringRef checkerList = A->getValue(Args); SmallVector checkers; checkerList.split(checkers, ","); for (unsigned i = 0, e = checkers.size(); i != e; ++i) Opts.CheckersControlList.push_back(std::make_pair(checkers[i], enable)); } } static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, DiagnosticsEngine &Diags) { using namespace cc1options; Opts.OptimizationLevel = getOptimizationLevel(Args, IK, Diags); if (Opts.OptimizationLevel > 3) { Diags.Report(diag::err_drv_invalid_value) << Args.getLastArg(OPT_O)->getAsString(Args) << Opts.OptimizationLevel; Opts.OptimizationLevel = 3; } // We must always run at least the always inlining pass. Opts.Inlining = (Opts.OptimizationLevel > 1) ? CodeGenOptions::NormalInlining : CodeGenOptions::OnlyAlwaysInlining; Opts.DebugInfo = Args.hasArg(OPT_g); Opts.LimitDebugInfo = Args.hasArg(OPT_flimit_debug_info); Opts.DisableLLVMOpts = Args.hasArg(OPT_disable_llvm_optzns); Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone); Opts.ForbidGuardVariables = Args.hasArg(OPT_fforbid_guard_variables); Opts.UseRegisterSizedBitfieldAccess = Args.hasArg( OPT_fuse_register_sized_bitfield_access); Opts.RelaxedAliasing = Args.hasArg(OPT_relaxed_aliasing); Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags); Opts.MergeAllConstants = !Args.hasArg(OPT_fno_merge_all_constants); Opts.NoCommon = Args.hasArg(OPT_fno_common); Opts.NoImplicitFloat = Args.hasArg(OPT_no_implicit_float); Opts.OptimizeSize = Args.hasArg(OPT_Os); Opts.OptimizeSize = Args.hasArg(OPT_Oz) ? 2 : Opts.OptimizeSize; Opts.SimplifyLibCalls = !(Args.hasArg(OPT_fno_builtin) || Args.hasArg(OPT_ffreestanding)); Opts.UnrollLoops = Args.hasArg(OPT_funroll_loops) || (Opts.OptimizationLevel > 1 && !Opts.OptimizeSize); Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose); Opts.ObjCAutoRefCountExceptions = Args.hasArg(OPT_fobjc_arc_exceptions); Opts.ObjCRuntimeHasARC = Args.hasArg(OPT_fobjc_runtime_has_arc); Opts.ObjCRuntimeHasTerminate = Args.hasArg(OPT_fobjc_runtime_has_terminate); Opts.CUDAIsDevice = Args.hasArg(OPT_fcuda_is_device); Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit); Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases); Opts.CodeModel = Args.getLastArgValue(OPT_mcode_model); Opts.DebugPass = Args.getLastArgValue(OPT_mdebug_pass); Opts.DisableFPElim = Args.hasArg(OPT_mdisable_fp_elim); Opts.FloatABI = Args.getLastArgValue(OPT_mfloat_abi); Opts.HiddenWeakVTables = Args.hasArg(OPT_fhidden_weak_vtables); Opts.LessPreciseFPMAD = Args.hasArg(OPT_cl_mad_enable); Opts.LimitFloatPrecision = Args.getLastArgValue(OPT_mlimit_float_precision); Opts.NoInfsFPMath = Opts.NoNaNsFPMath = Args.hasArg(OPT_cl_finite_math_only)|| Args.hasArg(OPT_cl_fast_relaxed_math); Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss); Opts.BackendOptions = Args.getAllArgValues(OPT_backend_option); Opts.NumRegisterParameters = Args.getLastArgIntValue(OPT_mregparm, 0, Diags); Opts.NoGlobalMerge = Args.hasArg(OPT_mno_global_merge); Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack); Opts.RelaxAll = Args.hasArg(OPT_mrelax_all); Opts.OmitLeafFramePointer = Args.hasArg(OPT_momit_leaf_frame_pointer); Opts.SaveTempLabels = Args.hasArg(OPT_msave_temp_labels); Opts.NoDwarf2CFIAsm = Args.hasArg(OPT_fno_dwarf2_cfi_asm); Opts.SoftFloat = Args.hasArg(OPT_msoft_float); Opts.UnsafeFPMath = Args.hasArg(OPT_cl_unsafe_math_optimizations) || Args.hasArg(OPT_cl_fast_relaxed_math); Opts.UnwindTables = Args.hasArg(OPT_munwind_tables); Opts.RelocationModel = Args.getLastArgValue(OPT_mrelocation_model, "pic"); Opts.FunctionSections = Args.hasArg(OPT_ffunction_sections); Opts.DataSections = Args.hasArg(OPT_fdata_sections); Opts.MainFileName = Args.getLastArgValue(OPT_main_file_name); Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier); Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions); Opts.InstrumentForProfiling = Args.hasArg(OPT_pg); Opts.EmitGcovArcs = Args.hasArg(OPT_femit_coverage_data); Opts.EmitGcovNotes = Args.hasArg(OPT_femit_coverage_notes); Opts.CoverageFile = Args.getLastArgValue(OPT_coverage_file); if (Arg *A = Args.getLastArg(OPT_fobjc_dispatch_method_EQ)) { StringRef Name = A->getValue(Args); unsigned Method = llvm::StringSwitch(Name) .Case("legacy", CodeGenOptions::Legacy) .Case("non-legacy", CodeGenOptions::NonLegacy) .Case("mixed", CodeGenOptions::Mixed) .Default(~0U); if (Method == ~0U) Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name; else Opts.ObjCDispatchMethod = Method; } } static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts, ArgList &Args) { using namespace cc1options; Opts.OutputFile = Args.getLastArgValue(OPT_dependency_file); Opts.Targets = Args.getAllArgValues(OPT_MT); Opts.IncludeSystemHeaders = Args.hasArg(OPT_sys_header_deps); Opts.UsePhonyTargets = Args.hasArg(OPT_MP); Opts.ShowHeaderIncludes = Args.hasArg(OPT_H); Opts.HeaderIncludeOutputFile = Args.getLastArgValue(OPT_header_include_file); Opts.AddMissingHeaderDeps = Args.hasArg(OPT_MG); } static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, DiagnosticsEngine &Diags) { using namespace cc1options; Opts.DiagnosticLogFile = Args.getLastArgValue(OPT_diagnostic_log_file); Opts.IgnoreWarnings = Args.hasArg(OPT_w); Opts.NoRewriteMacros = Args.hasArg(OPT_Wno_rewrite_macros); Opts.Pedantic = Args.hasArg(OPT_pedantic); Opts.PedanticErrors = Args.hasArg(OPT_pedantic_errors); Opts.ShowCarets = !Args.hasArg(OPT_fno_caret_diagnostics); Opts.ShowColors = Args.hasArg(OPT_fcolor_diagnostics); Opts.ShowColumn = Args.hasFlag(OPT_fshow_column, OPT_fno_show_column, /*Default=*/true); Opts.ShowFixits = !Args.hasArg(OPT_fno_diagnostics_fixit_info); Opts.ShowLocation = !Args.hasArg(OPT_fno_show_source_location); Opts.ShowNames = Args.hasArg(OPT_fdiagnostics_show_name); Opts.ShowOptionNames = Args.hasArg(OPT_fdiagnostics_show_option); // Default behavior is to not to show note include stacks. Opts.ShowNoteIncludeStack = false; if (Arg *A = Args.getLastArg(OPT_fdiagnostics_show_note_include_stack, OPT_fno_diagnostics_show_note_include_stack)) if (A->getOption().matches(OPT_fdiagnostics_show_note_include_stack)) Opts.ShowNoteIncludeStack = true; StringRef ShowOverloads = Args.getLastArgValue(OPT_fshow_overloads_EQ, "all"); if (ShowOverloads == "best") Opts.ShowOverloads = DiagnosticsEngine::Ovl_Best; else if (ShowOverloads == "all") Opts.ShowOverloads = DiagnosticsEngine::Ovl_All; else Diags.Report(diag::err_drv_invalid_value) << Args.getLastArg(OPT_fshow_overloads_EQ)->getAsString(Args) << ShowOverloads; StringRef ShowCategory = Args.getLastArgValue(OPT_fdiagnostics_show_category, "none"); if (ShowCategory == "none") Opts.ShowCategories = 0; else if (ShowCategory == "id") Opts.ShowCategories = 1; else if (ShowCategory == "name") Opts.ShowCategories = 2; else Diags.Report(diag::err_drv_invalid_value) << Args.getLastArg(OPT_fdiagnostics_show_category)->getAsString(Args) << ShowCategory; StringRef Format = Args.getLastArgValue(OPT_fdiagnostics_format, "clang"); if (Format == "clang") Opts.Format = DiagnosticOptions::Clang; else if (Format == "msvc") Opts.Format = DiagnosticOptions::Msvc; else if (Format == "vi") Opts.Format = DiagnosticOptions::Vi; else Diags.Report(diag::err_drv_invalid_value) << Args.getLastArg(OPT_fdiagnostics_format)->getAsString(Args) << Format; Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info); Opts.ShowParseableFixits = Args.hasArg(OPT_fdiagnostics_parseable_fixits); Opts.VerifyDiagnostics = Args.hasArg(OPT_verify); Opts.ErrorLimit = Args.getLastArgIntValue(OPT_ferror_limit, 0, Diags); Opts.MacroBacktraceLimit = Args.getLastArgIntValue(OPT_fmacro_backtrace_limit, DiagnosticOptions::DefaultMacroBacktraceLimit, Diags); Opts.TemplateBacktraceLimit = Args.getLastArgIntValue(OPT_ftemplate_backtrace_limit, DiagnosticOptions::DefaultTemplateBacktraceLimit, Diags); Opts.TabStop = Args.getLastArgIntValue(OPT_ftabstop, DiagnosticOptions::DefaultTabStop, Diags); if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) { Diags.Report(diag::warn_ignoring_ftabstop_value) << Opts.TabStop << DiagnosticOptions::DefaultTabStop; Opts.TabStop = DiagnosticOptions::DefaultTabStop; } Opts.MessageLength = Args.getLastArgIntValue(OPT_fmessage_length, 0, Diags); Opts.DumpBuildInformation = Args.getLastArgValue(OPT_dump_build_information); Opts.Warnings = Args.getAllArgValues(OPT_W); } static void ParseFileSystemArgs(FileSystemOptions &Opts, ArgList &Args) { Opts.WorkingDir = Args.getLastArgValue(OPT_working_directory); } static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, DiagnosticsEngine &Diags) { using namespace cc1options; Opts.ProgramAction = frontend::ParseSyntaxOnly; if (const Arg *A = Args.getLastArg(OPT_Action_Group)) { switch (A->getOption().getID()) { default: llvm_unreachable("Invalid option in group!"); case OPT_ast_dump: Opts.ProgramAction = frontend::ASTDump; break; case OPT_ast_dump_xml: Opts.ProgramAction = frontend::ASTDumpXML; break; case OPT_ast_print: Opts.ProgramAction = frontend::ASTPrint; break; case OPT_ast_view: Opts.ProgramAction = frontend::ASTView; break; case OPT_dump_raw_tokens: Opts.ProgramAction = frontend::DumpRawTokens; break; case OPT_dump_tokens: Opts.ProgramAction = frontend::DumpTokens; break; case OPT_S: Opts.ProgramAction = frontend::EmitAssembly; break; case OPT_emit_llvm_bc: Opts.ProgramAction = frontend::EmitBC; break; case OPT_emit_html: Opts.ProgramAction = frontend::EmitHTML; break; case OPT_emit_llvm: Opts.ProgramAction = frontend::EmitLLVM; break; case OPT_emit_llvm_only: Opts.ProgramAction = frontend::EmitLLVMOnly; break; case OPT_emit_codegen_only: Opts.ProgramAction = frontend::EmitCodeGenOnly; break; case OPT_emit_obj: Opts.ProgramAction = frontend::EmitObj; break; case OPT_fixit_EQ: Opts.FixItSuffix = A->getValue(Args); // fall-through! case OPT_fixit: Opts.ProgramAction = frontend::FixIt; break; case OPT_emit_module: Opts.ProgramAction = frontend::GenerateModule; break; case OPT_emit_pch: Opts.ProgramAction = frontend::GeneratePCH; break; case OPT_emit_pth: Opts.ProgramAction = frontend::GeneratePTH; break; case OPT_init_only: Opts.ProgramAction = frontend::InitOnly; break; case OPT_fsyntax_only: Opts.ProgramAction = frontend::ParseSyntaxOnly; break; case OPT_print_decl_contexts: Opts.ProgramAction = frontend::PrintDeclContext; break; case OPT_print_preamble: Opts.ProgramAction = frontend::PrintPreamble; break; case OPT_E: Opts.ProgramAction = frontend::PrintPreprocessedInput; break; case OPT_rewrite_macros: Opts.ProgramAction = frontend::RewriteMacros; break; case OPT_rewrite_objc: Opts.ProgramAction = frontend::RewriteObjC; break; case OPT_rewrite_test: Opts.ProgramAction = frontend::RewriteTest; break; case OPT_analyze: Opts.ProgramAction = frontend::RunAnalysis; break; case OPT_Eonly: Opts.ProgramAction = frontend::RunPreprocessorOnly; break; } } if (const Arg* A = Args.getLastArg(OPT_plugin)) { Opts.Plugins.push_back(A->getValue(Args,0)); Opts.ProgramAction = frontend::PluginAction; Opts.ActionName = A->getValue(Args); for (arg_iterator it = Args.filtered_begin(OPT_plugin_arg), end = Args.filtered_end(); it != end; ++it) { if ((*it)->getValue(Args, 0) == Opts.ActionName) Opts.PluginArgs.push_back((*it)->getValue(Args, 1)); } } Opts.AddPluginActions = Args.getAllArgValues(OPT_add_plugin); Opts.AddPluginArgs.resize(Opts.AddPluginActions.size()); for (int i = 0, e = Opts.AddPluginActions.size(); i != e; ++i) { for (arg_iterator it = Args.filtered_begin(OPT_plugin_arg), end = Args.filtered_end(); it != end; ++it) { if ((*it)->getValue(Args, 0) == Opts.AddPluginActions[i]) Opts.AddPluginArgs[i].push_back((*it)->getValue(Args, 1)); } } if (const Arg *A = Args.getLastArg(OPT_code_completion_at)) { Opts.CodeCompletionAt = ParsedSourceLocation::FromString(A->getValue(Args)); if (Opts.CodeCompletionAt.FileName.empty()) Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << A->getValue(Args); } Opts.DisableFree = Args.hasArg(OPT_disable_free); Opts.OutputFile = Args.getLastArgValue(OPT_o); Opts.Plugins = Args.getAllArgValues(OPT_load); Opts.RelocatablePCH = Args.hasArg(OPT_relocatable_pch); Opts.ShowHelp = Args.hasArg(OPT_help); Opts.ShowMacrosInCodeCompletion = Args.hasArg(OPT_code_completion_macros); Opts.ShowCodePatternsInCodeCompletion = Args.hasArg(OPT_code_completion_patterns); Opts.ShowGlobalSymbolsInCodeCompletion = !Args.hasArg(OPT_no_code_completion_globals); Opts.ShowStats = Args.hasArg(OPT_print_stats); Opts.ShowTimers = Args.hasArg(OPT_ftime_report); Opts.ShowVersion = Args.hasArg(OPT_version); Opts.ASTMergeFiles = Args.getAllArgValues(OPT_ast_merge); Opts.LLVMArgs = Args.getAllArgValues(OPT_mllvm); Opts.FixWhatYouCan = Args.hasArg(OPT_fix_what_you_can); Opts.ARCMTAction = FrontendOptions::ARCMT_None; if (const Arg *A = Args.getLastArg(OPT_arcmt_check, OPT_arcmt_modify, OPT_arcmt_migrate)) { switch (A->getOption().getID()) { default: llvm_unreachable("missed a case"); case OPT_arcmt_check: Opts.ARCMTAction = FrontendOptions::ARCMT_Check; break; case OPT_arcmt_modify: Opts.ARCMTAction = FrontendOptions::ARCMT_Modify; break; case OPT_arcmt_migrate: Opts.ARCMTAction = FrontendOptions::ARCMT_Migrate; break; } } Opts.ARCMTMigrateDir = Args.getLastArgValue(OPT_arcmt_migrate_directory); Opts.ARCMTMigrateReportOut = Args.getLastArgValue(OPT_arcmt_migrate_report_output); Opts.ARCMTMigrateEmitARCErrors = Args.hasArg(OPT_arcmt_migrate_emit_arc_errors); InputKind DashX = IK_None; if (const Arg *A = Args.getLastArg(OPT_x)) { DashX = llvm::StringSwitch(A->getValue(Args)) .Case("c", IK_C) .Case("cl", IK_OpenCL) .Case("cuda", IK_CUDA) .Case("c++", IK_CXX) .Case("objective-c", IK_ObjC) .Case("objective-c++", IK_ObjCXX) .Case("cpp-output", IK_PreprocessedC) .Case("assembler-with-cpp", IK_Asm) .Case("c++-cpp-output", IK_PreprocessedCXX) .Case("objective-c-cpp-output", IK_PreprocessedObjC) .Case("objc-cpp-output", IK_PreprocessedObjC) .Case("objective-c++-cpp-output", IK_PreprocessedObjCXX) .Case("objc++-cpp-output", IK_PreprocessedObjCXX) .Case("c-header", IK_C) .Case("cl-header", IK_OpenCL) .Case("objective-c-header", IK_ObjC) .Case("c++-header", IK_CXX) .Case("objective-c++-header", IK_ObjCXX) .Case("ast", IK_AST) .Case("ir", IK_LLVM_IR) .Default(IK_None); if (DashX == IK_None) Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << A->getValue(Args); } // '-' is the default input if none is given. std::vector Inputs = Args.getAllArgValues(OPT_INPUT); Opts.Inputs.clear(); if (Inputs.empty()) Inputs.push_back("-"); for (unsigned i = 0, e = Inputs.size(); i != e; ++i) { InputKind IK = DashX; if (IK == IK_None) { IK = FrontendOptions::getInputKindForExtension( StringRef(Inputs[i]).rsplit('.').second); // FIXME: Remove this hack. if (i == 0) DashX = IK; } Opts.Inputs.push_back(std::make_pair(IK, Inputs[i])); } return DashX; } std::string CompilerInvocation::GetResourcesPath(const char *Argv0, void *MainAddr) { llvm::sys::Path P = llvm::sys::Path::GetMainExecutable(Argv0, MainAddr); if (!P.isEmpty()) { P.eraseComponent(); // Remove /clang from foo/bin/clang P.eraseComponent(); // Remove /bin from foo/bin // Get foo/lib/clang//include P.appendComponent("lib"); P.appendComponent("clang"); P.appendComponent(CLANG_VERSION_STRING); } return P.str(); } static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { using namespace cc1options; Opts.Sysroot = Args.getLastArgValue(OPT_isysroot, "/"); Opts.Verbose = Args.hasArg(OPT_v); Opts.UseBuiltinIncludes = !Args.hasArg(OPT_nobuiltininc); Opts.UseStandardSystemIncludes = !Args.hasArg(OPT_nostdsysteminc); Opts.UseStandardCXXIncludes = !Args.hasArg(OPT_nostdincxx); if (const Arg *A = Args.getLastArg(OPT_stdlib_EQ)) Opts.UseLibcxx = (strcmp(A->getValue(Args), "libc++") == 0); Opts.ResourceDir = Args.getLastArgValue(OPT_resource_dir); Opts.ModuleCachePath = Args.getLastArgValue(OPT_fmodule_cache_path); Opts.DisableModuleHash = Args.hasArg(OPT_fdisable_module_hash); // Add -I..., -F..., and -index-header-map options in order. bool IsIndexHeaderMap = false; for (arg_iterator it = Args.filtered_begin(OPT_I, OPT_F, OPT_index_header_map), ie = Args.filtered_end(); it != ie; ++it) { if ((*it)->getOption().matches(OPT_index_header_map)) { // -index-header-map applies to the next -I or -F. IsIndexHeaderMap = true; continue; } frontend::IncludeDirGroup Group = IsIndexHeaderMap? frontend::IndexHeaderMap : frontend::Angled; Opts.AddPath((*it)->getValue(Args), Group, true, /*IsFramework=*/ (*it)->getOption().matches(OPT_F), false); IsIndexHeaderMap = false; } // Add -iprefix/-iwith-prefix/-iwithprefixbefore options. StringRef Prefix = ""; // FIXME: This isn't the correct default prefix. for (arg_iterator it = Args.filtered_begin(OPT_iprefix, OPT_iwithprefix, OPT_iwithprefixbefore), ie = Args.filtered_end(); it != ie; ++it) { const Arg *A = *it; if (A->getOption().matches(OPT_iprefix)) Prefix = A->getValue(Args); else if (A->getOption().matches(OPT_iwithprefix)) Opts.AddPath(Prefix.str() + A->getValue(Args), frontend::System, false, false, false); else Opts.AddPath(Prefix.str() + A->getValue(Args), frontend::Angled, false, false, false); } for (arg_iterator it = Args.filtered_begin(OPT_idirafter), ie = Args.filtered_end(); it != ie; ++it) Opts.AddPath((*it)->getValue(Args), frontend::After, true, false, false); for (arg_iterator it = Args.filtered_begin(OPT_iquote), ie = Args.filtered_end(); it != ie; ++it) Opts.AddPath((*it)->getValue(Args), frontend::Quoted, true, false, false); for (arg_iterator it = Args.filtered_begin(OPT_isystem, OPT_iwithsysroot), ie = Args.filtered_end(); it != ie; ++it) Opts.AddPath((*it)->getValue(Args), frontend::System, true, false, !(*it)->getOption().matches(OPT_iwithsysroot)); // Add the paths for the various language specific isystem flags. for (arg_iterator it = Args.filtered_begin(OPT_c_isystem), ie = Args.filtered_end(); it != ie; ++it) Opts.AddPath((*it)->getValue(Args), frontend::CSystem, true, false, true); for (arg_iterator it = Args.filtered_begin(OPT_cxx_isystem), ie = Args.filtered_end(); it != ie; ++it) Opts.AddPath((*it)->getValue(Args), frontend::CXXSystem, true, false, true); for (arg_iterator it = Args.filtered_begin(OPT_objc_isystem), ie = Args.filtered_end(); it != ie; ++it) Opts.AddPath((*it)->getValue(Args), frontend::ObjCSystem, true, false,true); for (arg_iterator it = Args.filtered_begin(OPT_objcxx_isystem), ie = Args.filtered_end(); it != ie; ++it) Opts.AddPath((*it)->getValue(Args), frontend::ObjCXXSystem, true, false, true); + + // Add the internal paths from a driver that detects standard include paths. + for (arg_iterator I = Args.filtered_begin(OPT_internal_isystem, + OPT_internal_externc_isystem), + E = Args.filtered_end(); + I != E; ++I) + Opts.AddPath((*I)->getValue(Args), frontend::System, + false, false, /*IgnoreSysRoot=*/true, /*IsInternal=*/true, + (*I)->getOption().matches(OPT_internal_externc_isystem)); } void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, LangStandard::Kind LangStd) { // Set some properties which depend solely on the input kind; it would be nice // to move these to the language standard, and have the driver resolve the // input kind + language standard. if (IK == IK_Asm) { Opts.AsmPreprocessor = 1; } else if (IK == IK_ObjC || IK == IK_ObjCXX || IK == IK_PreprocessedObjC || IK == IK_PreprocessedObjCXX) { Opts.ObjC1 = Opts.ObjC2 = 1; } if (LangStd == LangStandard::lang_unspecified) { // Based on the base language, pick one. switch (IK) { case IK_None: case IK_AST: case IK_LLVM_IR: llvm_unreachable("Invalid input kind!"); case IK_OpenCL: LangStd = LangStandard::lang_opencl; break; case IK_CUDA: LangStd = LangStandard::lang_cuda; break; case IK_Asm: case IK_C: case IK_PreprocessedC: case IK_ObjC: case IK_PreprocessedObjC: LangStd = LangStandard::lang_gnu99; break; case IK_CXX: case IK_PreprocessedCXX: case IK_ObjCXX: case IK_PreprocessedObjCXX: LangStd = LangStandard::lang_gnucxx98; break; } } const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd); Opts.BCPLComment = Std.hasBCPLComments(); Opts.C99 = Std.isC99(); Opts.C1X = Std.isC1X(); Opts.CPlusPlus = Std.isCPlusPlus(); Opts.CPlusPlus0x = Std.isCPlusPlus0x(); Opts.Digraphs = Std.hasDigraphs(); Opts.GNUMode = Std.isGNUMode(); Opts.GNUInline = !Std.isC99(); Opts.HexFloats = Std.hasHexFloats(); Opts.ImplicitInt = Std.hasImplicitInt(); // OpenCL has some additional defaults. if (LangStd == LangStandard::lang_opencl) { Opts.OpenCL = 1; Opts.AltiVec = 0; Opts.CXXOperatorNames = 1; Opts.LaxVectorConversions = 0; Opts.DefaultFPContract = 1; } if (LangStd == LangStandard::lang_cuda) Opts.CUDA = 1; // OpenCL and C++ both have bool, true, false keywords. Opts.Bool = Opts.OpenCL || Opts.CPlusPlus; Opts.GNUKeywords = Opts.GNUMode; Opts.CXXOperatorNames = Opts.CPlusPlus; // Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs // is specified, or -std is set to a conforming mode. Opts.Trigraphs = !Opts.GNUMode; Opts.DollarIdents = !Opts.AsmPreprocessor; } static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, DiagnosticsEngine &Diags) { // FIXME: Cleanup per-file based stuff. LangStandard::Kind LangStd = LangStandard::lang_unspecified; if (const Arg *A = Args.getLastArg(OPT_std_EQ)) { LangStd = llvm::StringSwitch(A->getValue(Args)) #define LANGSTANDARD(id, name, desc, features) \ .Case(name, LangStandard::lang_##id) #include "clang/Frontend/LangStandards.def" .Default(LangStandard::lang_unspecified); if (LangStd == LangStandard::lang_unspecified) Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << A->getValue(Args); else { // Valid standard, check to make sure language and standard are compatable. const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd); switch (IK) { case IK_C: case IK_ObjC: case IK_PreprocessedC: case IK_PreprocessedObjC: if (!(Std.isC89() || Std.isC99())) Diags.Report(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args) << "C/ObjC"; break; case IK_CXX: case IK_ObjCXX: case IK_PreprocessedCXX: case IK_PreprocessedObjCXX: if (!Std.isCPlusPlus()) Diags.Report(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args) << "C++/ObjC++"; break; case IK_OpenCL: if (!Std.isC99()) Diags.Report(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args) << "OpenCL"; break; case IK_CUDA: if (!Std.isCPlusPlus()) Diags.Report(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args) << "CUDA"; break; default: break; } } } if (const Arg *A = Args.getLastArg(OPT_cl_std_EQ)) { if (strcmp(A->getValue(Args), "CL1.1") != 0) { Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << A->getValue(Args); } } CompilerInvocation::setLangDefaults(Opts, IK, LangStd); // We abuse '-f[no-]gnu-keywords' to force overriding all GNU-extension // keywords. This behavior is provided by GCC's poorly named '-fasm' flag, // while a subset (the non-C++ GNU keywords) is provided by GCC's // '-fgnu-keywords'. Clang conflates the two for simplicity under the single // name, as it doesn't seem a useful distinction. Opts.GNUKeywords = Args.hasFlag(OPT_fgnu_keywords, OPT_fno_gnu_keywords, Opts.GNUKeywords); if (Args.hasArg(OPT_fno_operator_names)) Opts.CXXOperatorNames = 0; if (Opts.ObjC1) { if (Args.hasArg(OPT_fobjc_gc_only)) Opts.setGC(LangOptions::GCOnly); else if (Args.hasArg(OPT_fobjc_gc)) Opts.setGC(LangOptions::HybridGC); else if (Args.hasArg(OPT_fobjc_arc)) { Opts.ObjCAutoRefCount = 1; if (Args.hasArg(OPT_fobjc_fragile_abi)) Diags.Report(diag::err_arc_nonfragile_abi); } if (Args.hasArg(OPT_fobjc_runtime_has_weak)) Opts.ObjCRuntimeHasWeak = 1; if (Args.hasArg(OPT_fno_objc_infer_related_result_type)) Opts.ObjCInferRelatedResultType = 0; } if (Args.hasArg(OPT_fgnu89_inline)) Opts.GNUInline = 1; if (Args.hasArg(OPT_fapple_kext)) { if (!Opts.CPlusPlus) Diags.Report(diag::warn_c_kext); else Opts.AppleKext = 1; } if (Args.hasArg(OPT_print_ivar_layout)) Opts.ObjCGCBitmapPrint = 1; if (Args.hasArg(OPT_fno_constant_cfstrings)) Opts.NoConstantCFStrings = 1; if (Args.hasArg(OPT_faltivec)) Opts.AltiVec = 1; if (Args.hasArg(OPT_pthread)) Opts.POSIXThreads = 1; if (Args.hasArg(OPT_fdelayed_template_parsing)) Opts.DelayedTemplateParsing = 1; StringRef Vis = Args.getLastArgValue(OPT_fvisibility, "default"); if (Vis == "default") Opts.setVisibilityMode(DefaultVisibility); else if (Vis == "hidden") Opts.setVisibilityMode(HiddenVisibility); else if (Vis == "protected") Opts.setVisibilityMode(ProtectedVisibility); else Diags.Report(diag::err_drv_invalid_value) << Args.getLastArg(OPT_fvisibility)->getAsString(Args) << Vis; if (Args.hasArg(OPT_fvisibility_inlines_hidden)) Opts.InlineVisibilityHidden = 1; if (Args.hasArg(OPT_ftrapv)) { Opts.setSignedOverflowBehavior(LangOptions::SOB_Trapping); // Set the handler, if one is specified. Opts.OverflowHandler = Args.getLastArgValue(OPT_ftrapv_handler); } else if (Args.hasArg(OPT_fwrapv)) Opts.setSignedOverflowBehavior(LangOptions::SOB_Defined); if (Args.hasArg(OPT_trigraphs)) Opts.Trigraphs = 1; Opts.DollarIdents = Args.hasFlag(OPT_fdollars_in_identifiers, OPT_fno_dollars_in_identifiers, Opts.DollarIdents); Opts.PascalStrings = Args.hasArg(OPT_fpascal_strings); Opts.MicrosoftExt = Args.hasArg(OPT_fms_extensions); Opts.MicrosoftMode = Args.hasArg(OPT_fms_compatibility); Opts.MSCVersion = Args.getLastArgIntValue(OPT_fmsc_version, 0, Diags); Opts.Borland = Args.hasArg(OPT_fborland_extensions); Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings); Opts.ConstStrings = Args.hasFlag(OPT_fconst_strings, OPT_fno_const_strings, Opts.ConstStrings); if (Args.hasArg(OPT_fno_lax_vector_conversions)) Opts.LaxVectorConversions = 0; if (Args.hasArg(OPT_fno_threadsafe_statics)) Opts.ThreadsafeStatics = 0; Opts.Exceptions = Args.hasArg(OPT_fexceptions); Opts.ObjCExceptions = Args.hasArg(OPT_fobjc_exceptions); Opts.CXXExceptions = Args.hasArg(OPT_fcxx_exceptions); Opts.SjLjExceptions = Args.hasArg(OPT_fsjlj_exceptions); Opts.TraditionalCPP = Args.hasArg(OPT_traditional_cpp); Opts.RTTI = !Args.hasArg(OPT_fno_rtti); Opts.Blocks = Args.hasArg(OPT_fblocks); Opts.BlocksRuntimeOptional = Args.hasArg(OPT_fblocks_runtime_optional); Opts.CharIsSigned = !Args.hasArg(OPT_fno_signed_char); Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar); Opts.ShortEnums = Args.hasArg(OPT_fshort_enums); Opts.Freestanding = Args.hasArg(OPT_ffreestanding); Opts.FormatExtensions = Args.hasArg(OPT_fformat_extensions); Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding; Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new); Opts.HeinousExtensions = Args.hasArg(OPT_fheinous_gnu_extensions); Opts.AccessControl = !Args.hasArg(OPT_fno_access_control); Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors); Opts.MathErrno = Args.hasArg(OPT_fmath_errno); Opts.InstantiationDepth = Args.getLastArgIntValue(OPT_ftemplate_depth, 1024, Diags); Opts.DelayedTemplateParsing = Args.hasArg(OPT_fdelayed_template_parsing); Opts.NumLargeByValueCopy = Args.getLastArgIntValue(OPT_Wlarge_by_value_copy, 0, Diags); Opts.MSBitfields = Args.hasArg(OPT_mms_bitfields); Opts.NeXTRuntime = !Args.hasArg(OPT_fgnu_runtime); Opts.ObjCConstantStringClass = Args.getLastArgValue(OPT_fconstant_string_class); Opts.ObjCNonFragileABI = !Args.hasArg(OPT_fobjc_fragile_abi); if (Opts.ObjCNonFragileABI) Opts.ObjCNonFragileABI2 = true; Opts.ObjCDefaultSynthProperties = Args.hasArg(OPT_fobjc_default_synthesize_properties); Opts.CatchUndefined = Args.hasArg(OPT_fcatch_undefined_behavior); Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls); Opts.PackStruct = Args.getLastArgIntValue(OPT_fpack_struct, 0, Diags); Opts.PICLevel = Args.getLastArgIntValue(OPT_pic_level, 0, Diags); Opts.Static = Args.hasArg(OPT_static_define); Opts.DumpRecordLayouts = Args.hasArg(OPT_fdump_record_layouts); Opts.DumpVTableLayouts = Args.hasArg(OPT_fdump_vtable_layouts); Opts.SpellChecking = !Args.hasArg(OPT_fno_spell_checking); Opts.NoBitFieldTypeAlign = Args.hasArg(OPT_fno_bitfield_type_align); Opts.SinglePrecisionConstants = Args.hasArg(OPT_cl_single_precision_constant); Opts.FastRelaxedMath = Args.hasArg(OPT_cl_fast_relaxed_math); Opts.OptimizeSize = 0; Opts.MRTD = Args.hasArg(OPT_mrtd); Opts.FakeAddressSpaceMap = Args.hasArg(OPT_ffake_address_space_map); Opts.ParseUnknownAnytype = Args.hasArg(OPT_funknown_anytype); Opts.DebuggerSupport = Args.hasArg(OPT_fdebugger_support); // Record whether the __DEPRECATED define was requested. Opts.Deprecated = Args.hasFlag(OPT_fdeprecated_macro, OPT_fno_deprecated_macro, Opts.Deprecated); // FIXME: Eliminate this dependency. unsigned Opt = getOptimizationLevel(Args, IK, Diags); Opts.Optimize = Opt != 0; // This is the __NO_INLINE__ define, which just depends on things like the // optimization level and -fno-inline, not actually whether the backend has // inlining enabled. // // FIXME: This is affected by other options (-fno-inline). Opts.NoInline = !Opt; unsigned SSP = Args.getLastArgIntValue(OPT_stack_protector, 0, Diags); switch (SSP) { default: Diags.Report(diag::err_drv_invalid_value) << Args.getLastArg(OPT_stack_protector)->getAsString(Args) << SSP; break; case 0: Opts.setStackProtector(LangOptions::SSPOff); break; case 1: Opts.setStackProtector(LangOptions::SSPOn); break; case 2: Opts.setStackProtector(LangOptions::SSPReq); break; } } static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, FileManager &FileMgr, DiagnosticsEngine &Diags) { using namespace cc1options; Opts.ImplicitPCHInclude = Args.getLastArgValue(OPT_include_pch); Opts.ImplicitPTHInclude = Args.getLastArgValue(OPT_include_pth); if (const Arg *A = Args.getLastArg(OPT_token_cache)) Opts.TokenCache = A->getValue(Args); else Opts.TokenCache = Opts.ImplicitPTHInclude; Opts.UsePredefines = !Args.hasArg(OPT_undef); Opts.DetailedRecord = Args.hasArg(OPT_detailed_preprocessing_record); Opts.AutoModuleImport = Args.hasArg(OPT_fauto_module_import); Opts.DisablePCHValidation = Args.hasArg(OPT_fno_validate_pch); Opts.DumpDeserializedPCHDecls = Args.hasArg(OPT_dump_deserialized_pch_decls); for (arg_iterator it = Args.filtered_begin(OPT_error_on_deserialized_pch_decl), ie = Args.filtered_end(); it != ie; ++it) { const Arg *A = *it; Opts.DeserializedPCHDeclsToErrorOn.insert(A->getValue(Args)); } if (const Arg *A = Args.getLastArg(OPT_preamble_bytes_EQ)) { StringRef Value(A->getValue(Args)); size_t Comma = Value.find(','); unsigned Bytes = 0; unsigned EndOfLine = 0; if (Comma == StringRef::npos || Value.substr(0, Comma).getAsInteger(10, Bytes) || Value.substr(Comma + 1).getAsInteger(10, EndOfLine)) Diags.Report(diag::err_drv_preamble_format); else { Opts.PrecompiledPreambleBytes.first = Bytes; Opts.PrecompiledPreambleBytes.second = (EndOfLine != 0); } } // Add macros from the command line. for (arg_iterator it = Args.filtered_begin(OPT_D, OPT_U), ie = Args.filtered_end(); it != ie; ++it) { if ((*it)->getOption().matches(OPT_D)) Opts.addMacroDef((*it)->getValue(Args)); else Opts.addMacroUndef((*it)->getValue(Args)); } Opts.MacroIncludes = Args.getAllArgValues(OPT_imacros); // Add the ordered list of -includes. for (arg_iterator it = Args.filtered_begin(OPT_include, OPT_include_pch, OPT_include_pth), ie = Args.filtered_end(); it != ie; ++it) { const Arg *A = *it; // PCH is handled specially, we need to extra the original include path. if (A->getOption().matches(OPT_include_pch)) { std::string OriginalFile = ASTReader::getOriginalSourceFile(A->getValue(Args), FileMgr, Diags); if (OriginalFile.empty()) continue; Opts.Includes.push_back(OriginalFile); } else Opts.Includes.push_back(A->getValue(Args)); } for (arg_iterator it = Args.filtered_begin(OPT_chain_include), ie = Args.filtered_end(); it != ie; ++it) { const Arg *A = *it; Opts.ChainedIncludes.push_back(A->getValue(Args)); } // Include 'altivec.h' if -faltivec option present if (Args.hasArg(OPT_faltivec)) Opts.Includes.push_back("altivec.h"); for (arg_iterator it = Args.filtered_begin(OPT_remap_file), ie = Args.filtered_end(); it != ie; ++it) { const Arg *A = *it; std::pair Split = StringRef(A->getValue(Args)).split(';'); if (Split.second.empty()) { Diags.Report(diag::err_drv_invalid_remap_file) << A->getAsString(Args); continue; } Opts.addRemappedFile(Split.first, Split.second); } if (Arg *A = Args.getLastArg(OPT_fobjc_arc_cxxlib_EQ)) { StringRef Name = A->getValue(Args); unsigned Library = llvm::StringSwitch(Name) .Case("libc++", ARCXX_libcxx) .Case("libstdc++", ARCXX_libstdcxx) .Case("none", ARCXX_nolib) .Default(~0U); if (Library == ~0U) Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name; else Opts.ObjCXXARCStandardLibrary = (ObjCXXARCStandardLibraryKind)Library; } } static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts, ArgList &Args) { using namespace cc1options; Opts.ShowCPP = !Args.hasArg(OPT_dM); Opts.ShowComments = Args.hasArg(OPT_C); Opts.ShowLineMarkers = !Args.hasArg(OPT_P); Opts.ShowMacroComments = Args.hasArg(OPT_CC); Opts.ShowMacros = Args.hasArg(OPT_dM) || Args.hasArg(OPT_dD); } static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) { using namespace cc1options; Opts.ABI = Args.getLastArgValue(OPT_target_abi); Opts.CXXABI = Args.getLastArgValue(OPT_cxx_abi); Opts.CPU = Args.getLastArgValue(OPT_target_cpu); Opts.Features = Args.getAllArgValues(OPT_target_feature); Opts.LinkerVersion = Args.getLastArgValue(OPT_target_linker_version); Opts.Triple = llvm::Triple::normalize(Args.getLastArgValue(OPT_triple)); // Use the host triple if unspecified. if (Opts.Triple.empty()) Opts.Triple = llvm::sys::getHostTriple(); } // void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, const char *const *ArgBegin, const char *const *ArgEnd, DiagnosticsEngine &Diags) { // Parse the arguments. llvm::OwningPtr Opts(createCC1OptTable()); unsigned MissingArgIndex, MissingArgCount; llvm::OwningPtr Args( Opts->ParseArgs(ArgBegin, ArgEnd,MissingArgIndex, MissingArgCount)); // Check for missing argument error. if (MissingArgCount) Diags.Report(diag::err_drv_missing_argument) << Args->getArgString(MissingArgIndex) << MissingArgCount; // Issue errors on unknown arguments. for (arg_iterator it = Args->filtered_begin(OPT_UNKNOWN), ie = Args->filtered_end(); it != ie; ++it) Diags.Report(diag::err_drv_unknown_argument) << (*it)->getAsString(*Args); ParseAnalyzerArgs(Res.getAnalyzerOpts(), *Args, Diags); ParseDependencyOutputArgs(Res.getDependencyOutputOpts(), *Args); ParseDiagnosticArgs(Res.getDiagnosticOpts(), *Args, Diags); ParseFileSystemArgs(Res.getFileSystemOpts(), *Args); // FIXME: We shouldn't have to pass the DashX option around here InputKind DashX = ParseFrontendArgs(Res.getFrontendOpts(), *Args, Diags); ParseCodeGenArgs(Res.getCodeGenOpts(), *Args, DashX, Diags); ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), *Args); if (DashX != IK_AST && DashX != IK_LLVM_IR) { ParseLangArgs(Res.getLangOpts(), *Args, DashX, Diags); if (Res.getFrontendOpts().ProgramAction == frontend::RewriteObjC) Res.getLangOpts().ObjCExceptions = 1; } // FIXME: ParsePreprocessorArgs uses the FileManager to read the contents of // PCH file and find the original header name. Remove the need to do that in // ParsePreprocessorArgs and remove the FileManager // parameters from the function and the "FileManager.h" #include. FileManager FileMgr(Res.getFileSystemOpts()); ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args, FileMgr, Diags); ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args); ParseTargetArgs(Res.getTargetOpts(), *Args); } namespace { class ModuleSignature { llvm::SmallVector Data; unsigned CurBit; uint64_t CurValue; public: ModuleSignature() : CurBit(0), CurValue(0) { } void add(uint64_t Value, unsigned Bits); void add(StringRef Value); void flush(); llvm::APInt getAsInteger() const; }; } void ModuleSignature::add(uint64_t Value, unsigned int NumBits) { CurValue |= Value << CurBit; if (CurBit + NumBits < 64) { CurBit += NumBits; return; } // Add the current word. Data.push_back(CurValue); if (CurBit) CurValue = Value >> (64-CurBit); else CurValue = 0; CurBit = (CurBit+NumBits) & 63; } void ModuleSignature::flush() { if (CurBit == 0) return; Data.push_back(CurValue); CurBit = 0; CurValue = 0; } void ModuleSignature::add(StringRef Value) { for (StringRef::iterator I = Value.begin(), IEnd = Value.end(); I != IEnd;++I) add(*I, 8); } llvm::APInt ModuleSignature::getAsInteger() const { return llvm::APInt(Data.size() * 64, Data); } std::string CompilerInvocation::getModuleHash() const { ModuleSignature Signature; // Start the signature with the compiler version. Signature.add(getClangFullRepositoryVersion()); // Extend the signature with the language options #define LANGOPT(Name, Bits, Default, Description) \ Signature.add(LangOpts.Name, Bits); #define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ Signature.add(static_cast(LangOpts.get##Name()), Bits); #define BENIGN_LANGOPT(Name, Bits, Default, Description) #define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) #include "clang/Basic/LangOptions.def" // Extend the signature with the target triple llvm::Triple T(TargetOpts.Triple); Signature.add((unsigned)T.getArch(), 5); Signature.add((unsigned)T.getVendor(), 4); Signature.add((unsigned)T.getOS(), 5); Signature.add((unsigned)T.getEnvironment(), 4); // Extend the signature with preprocessor options. Signature.add(getPreprocessorOpts().UsePredefines, 1); Signature.add(getPreprocessorOpts().DetailedRecord, 1); // Hash the preprocessor defines. // FIXME: This is terrible. Use an MD5 sum of the preprocessor defines. std::vector MacroDefs; for (std::vector >::const_iterator I = getPreprocessorOpts().Macros.begin(), IEnd = getPreprocessorOpts().Macros.end(); I != IEnd; ++I) { if (!I->second) MacroDefs.push_back(I->first); } llvm::array_pod_sort(MacroDefs.begin(), MacroDefs.end()); unsigned PPHashResult = 0; for (unsigned I = 0, N = MacroDefs.size(); I != N; ++I) PPHashResult = llvm::HashString(MacroDefs[I], PPHashResult); Signature.add(PPHashResult, 32); // We've generated the signature. Treat it as one large APInt that we'll // encode in base-36 and return. Signature.flush(); return Signature.getAsInteger().toString(36, /*Signed=*/false); } Index: head/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp =================================================================== --- head/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp (revision 228378) +++ head/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp (revision 228379) @@ -1,1165 +1,679 @@ //===--- InitHeaderSearch.cpp - Initialize header search paths ------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the InitHeaderSearch class. // //===----------------------------------------------------------------------===// #ifdef HAVE_CLANG_CONFIG_H # include "clang/Config/config.h" #endif #include "clang/Frontend/Utils.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/Version.h" #include "clang/Frontend/HeaderSearchOptions.h" #include "clang/Lex/HeaderSearch.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Path.h" #include "llvm/Config/config.h" -#ifdef _MSC_VER - #define WIN32_LEAN_AND_MEAN 1 - #include -#endif #ifndef CLANG_PREFIX #define CLANG_PREFIX #endif using namespace clang; using namespace clang::frontend; namespace { /// InitHeaderSearch - This class makes it easier to set the search paths of /// a HeaderSearch object. InitHeaderSearch stores several search path lists /// internally, which can be sent to a HeaderSearch object in one swoop. class InitHeaderSearch { std::vector > IncludePath; typedef std::vector >::const_iterator path_iterator; HeaderSearch &Headers; bool Verbose; std::string IncludeSysroot; bool IsNotEmptyOrRoot; public: InitHeaderSearch(HeaderSearch &HS, bool verbose, StringRef sysroot) : Headers(HS), Verbose(verbose), IncludeSysroot(sysroot), IsNotEmptyOrRoot(!(sysroot.empty() || sysroot == "/")) { } /// AddPath - Add the specified path to the specified group list. void AddPath(const Twine &Path, IncludeDirGroup Group, bool isCXXAware, bool isUserSupplied, bool isFramework, bool IgnoreSysRoot = false); /// AddGnuCPlusPlusIncludePaths - Add the necessary paths to support a gnu /// libstdc++. void AddGnuCPlusPlusIncludePaths(StringRef Base, StringRef ArchDir, StringRef Dir32, StringRef Dir64, const llvm::Triple &triple); /// AddMinGWCPlusPlusIncludePaths - Add the necessary paths to support a MinGW /// libstdc++. void AddMinGWCPlusPlusIncludePaths(StringRef Base, StringRef Arch, StringRef Version); /// AddMinGW64CXXPaths - Add the necessary paths to support /// libstdc++ of x86_64-w64-mingw32 aka mingw-w64. void AddMinGW64CXXPaths(StringRef Base, StringRef Version); // AddDefaultCIncludePaths - Add paths that should always be searched. void AddDefaultCIncludePaths(const llvm::Triple &triple, const HeaderSearchOptions &HSOpts); // AddDefaultCPlusPlusIncludePaths - Add paths that should be searched when // compiling c++. void AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOptions &HSOpts); /// AddDefaultSystemIncludePaths - Adds the default system include paths so /// that e.g. stdio.h is found. void AddDefaultIncludePaths(const LangOptions &Lang, const llvm::Triple &triple, const HeaderSearchOptions &HSOpts); /// Realize - Merges all search path lists into one list and send it to /// HeaderSearch. void Realize(const LangOptions &Lang); }; } // end anonymous namespace. void InitHeaderSearch::AddPath(const Twine &Path, IncludeDirGroup Group, bool isCXXAware, bool isUserSupplied, bool isFramework, bool IgnoreSysRoot) { assert(!Path.isTriviallyEmpty() && "can't handle empty path here"); FileManager &FM = Headers.getFileMgr(); // Compute the actual path, taking into consideration -isysroot. llvm::SmallString<256> MappedPathStorage; StringRef MappedPathStr = Path.toStringRef(MappedPathStorage); // Handle isysroot. if ((Group == System || Group == CXXSystem) && !IgnoreSysRoot && #if defined(_WIN32) !MappedPathStr.empty() && llvm::sys::path::is_separator(MappedPathStr[0]) && #else llvm::sys::path::is_absolute(MappedPathStr) && #endif IsNotEmptyOrRoot) { MappedPathStorage.clear(); MappedPathStr = (IncludeSysroot + Path).toStringRef(MappedPathStorage); } // Compute the DirectoryLookup type. SrcMgr::CharacteristicKind Type; if (Group == Quoted || Group == Angled || Group == IndexHeaderMap) Type = SrcMgr::C_User; else if (isCXXAware) Type = SrcMgr::C_System; else Type = SrcMgr::C_ExternCSystem; // If the directory exists, add it. if (const DirectoryEntry *DE = FM.getDirectory(MappedPathStr)) { IncludePath.push_back(std::make_pair(Group, DirectoryLookup(DE, Type, isUserSupplied, isFramework))); return; } // Check to see if this is an apple-style headermap (which are not allowed to // be frameworks). if (!isFramework) { if (const FileEntry *FE = FM.getFile(MappedPathStr)) { if (const HeaderMap *HM = Headers.CreateHeaderMap(FE)) { // It is a headermap, add it to the search path. IncludePath.push_back(std::make_pair(Group, DirectoryLookup(HM, Type, isUserSupplied, Group == IndexHeaderMap))); return; } } } if (Verbose) llvm::errs() << "ignoring nonexistent directory \"" << MappedPathStr << "\"\n"; } void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(StringRef Base, StringRef ArchDir, StringRef Dir32, StringRef Dir64, const llvm::Triple &triple) { // Add the base dir AddPath(Base, CXXSystem, true, false, false); // Add the multilib dirs llvm::Triple::ArchType arch = triple.getArch(); bool is64bit = arch == llvm::Triple::ppc64 || arch == llvm::Triple::x86_64; if (is64bit) AddPath(Base + "/" + ArchDir + "/" + Dir64, CXXSystem, true, false, false); else AddPath(Base + "/" + ArchDir + "/" + Dir32, CXXSystem, true, false, false); // Add the backward dir AddPath(Base + "/backward", CXXSystem, true, false, false); } void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(StringRef Base, StringRef Arch, StringRef Version) { AddPath(Base + "/" + Arch + "/" + Version + "/include/c++", CXXSystem, true, false, false); AddPath(Base + "/" + Arch + "/" + Version + "/include/c++/" + Arch, CXXSystem, true, false, false); AddPath(Base + "/" + Arch + "/" + Version + "/include/c++/backward", CXXSystem, true, false, false); } void InitHeaderSearch::AddMinGW64CXXPaths(StringRef Base, StringRef Version) { // Assumes Base is HeaderSearchOpts' ResourceDir AddPath(Base + "/../../../include/c++/" + Version, CXXSystem, true, false, false); AddPath(Base + "/../../../include/c++/" + Version + "/x86_64-w64-mingw32", CXXSystem, true, false, false); AddPath(Base + "/../../../include/c++/" + Version + "/i686-w64-mingw32", CXXSystem, true, false, false); AddPath(Base + "/../../../include/c++/" + Version + "/backward", CXXSystem, true, false, false); } - // FIXME: This probably should goto to some platform utils place. -#ifdef _MSC_VER - - // Read registry string. - // This also supports a means to look for high-versioned keys by use - // of a $VERSION placeholder in the key path. - // $VERSION in the key path is a placeholder for the version number, - // causing the highest value path to be searched for and used. - // I.e. "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION". - // There can be additional characters in the component. Only the numberic - // characters are compared. -static bool getSystemRegistryString(const char *keyPath, const char *valueName, - char *value, size_t maxLength) { - HKEY hRootKey = NULL; - HKEY hKey = NULL; - const char* subKey = NULL; - DWORD valueType; - DWORD valueSize = maxLength - 1; - long lResult; - bool returnValue = false; - - if (strncmp(keyPath, "HKEY_CLASSES_ROOT\\", 18) == 0) { - hRootKey = HKEY_CLASSES_ROOT; - subKey = keyPath + 18; - } else if (strncmp(keyPath, "HKEY_USERS\\", 11) == 0) { - hRootKey = HKEY_USERS; - subKey = keyPath + 11; - } else if (strncmp(keyPath, "HKEY_LOCAL_MACHINE\\", 19) == 0) { - hRootKey = HKEY_LOCAL_MACHINE; - subKey = keyPath + 19; - } else if (strncmp(keyPath, "HKEY_CURRENT_USER\\", 18) == 0) { - hRootKey = HKEY_CURRENT_USER; - subKey = keyPath + 18; - } - else - return false; - - const char *placeHolder = strstr(subKey, "$VERSION"); - char bestName[256]; - bestName[0] = '\0'; - // If we have a $VERSION placeholder, do the highest-version search. - if (placeHolder) { - const char *keyEnd = placeHolder - 1; - const char *nextKey = placeHolder; - // Find end of previous key. - while ((keyEnd > subKey) && (*keyEnd != '\\')) - keyEnd--; - // Find end of key containing $VERSION. - while (*nextKey && (*nextKey != '\\')) - nextKey++; - size_t partialKeyLength = keyEnd - subKey; - char partialKey[256]; - if (partialKeyLength > sizeof(partialKey)) - partialKeyLength = sizeof(partialKey); - strncpy(partialKey, subKey, partialKeyLength); - partialKey[partialKeyLength] = '\0'; - HKEY hTopKey = NULL; - lResult = RegOpenKeyEx(hRootKey, partialKey, 0, KEY_READ, &hTopKey); - if (lResult == ERROR_SUCCESS) { - char keyName[256]; - int bestIndex = -1; - double bestValue = 0.0; - DWORD index, size = sizeof(keyName) - 1; - for (index = 0; RegEnumKeyEx(hTopKey, index, keyName, &size, NULL, - NULL, NULL, NULL) == ERROR_SUCCESS; index++) { - const char *sp = keyName; - while (*sp && !isdigit(*sp)) - sp++; - if (!*sp) - continue; - const char *ep = sp + 1; - while (*ep && (isdigit(*ep) || (*ep == '.'))) - ep++; - char numBuf[32]; - strncpy(numBuf, sp, sizeof(numBuf) - 1); - numBuf[sizeof(numBuf) - 1] = '\0'; - double value = strtod(numBuf, NULL); - if (value > bestValue) { - bestIndex = (int)index; - bestValue = value; - strcpy(bestName, keyName); - } - size = sizeof(keyName) - 1; - } - // If we found the highest versioned key, open the key and get the value. - if (bestIndex != -1) { - // Append rest of key. - strncat(bestName, nextKey, sizeof(bestName) - 1); - bestName[sizeof(bestName) - 1] = '\0'; - // Open the chosen key path remainder. - lResult = RegOpenKeyEx(hTopKey, bestName, 0, KEY_READ, &hKey); - if (lResult == ERROR_SUCCESS) { - lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType, - (LPBYTE)value, &valueSize); - if (lResult == ERROR_SUCCESS) - returnValue = true; - RegCloseKey(hKey); - } - } - RegCloseKey(hTopKey); - } - } - else { - lResult = RegOpenKeyEx(hRootKey, subKey, 0, KEY_READ, &hKey); - if (lResult == ERROR_SUCCESS) { - lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType, - (LPBYTE)value, &valueSize); - if (lResult == ERROR_SUCCESS) - returnValue = true; - RegCloseKey(hKey); - } - } - return returnValue; -} -#else // _MSC_VER - // Read registry string. -static bool getSystemRegistryString(const char*, const char*, char*, size_t) { - return(false); -} -#endif // _MSC_VER - - // Get Visual Studio installation directory. -static bool getVisualStudioDir(std::string &path) { - // First check the environment variables that vsvars32.bat sets. - const char* vcinstalldir = getenv("VCINSTALLDIR"); - if (vcinstalldir) { - char *p = const_cast(strstr(vcinstalldir, "\\VC")); - if (p) - *p = '\0'; - path = vcinstalldir; - return true; - } - - char vsIDEInstallDir[256]; - char vsExpressIDEInstallDir[256]; - // Then try the windows registry. - bool hasVCDir = getSystemRegistryString( - "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION", - "InstallDir", vsIDEInstallDir, sizeof(vsIDEInstallDir) - 1); - bool hasVCExpressDir = getSystemRegistryString( - "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\$VERSION", - "InstallDir", vsExpressIDEInstallDir, sizeof(vsExpressIDEInstallDir) - 1); - // If we have both vc80 and vc90, pick version we were compiled with. - if (hasVCDir && vsIDEInstallDir[0]) { - char *p = (char*)strstr(vsIDEInstallDir, "\\Common7\\IDE"); - if (p) - *p = '\0'; - path = vsIDEInstallDir; - return true; - } - - if (hasVCExpressDir && vsExpressIDEInstallDir[0]) { - char *p = (char*)strstr(vsExpressIDEInstallDir, "\\Common7\\IDE"); - if (p) - *p = '\0'; - path = vsExpressIDEInstallDir; - return true; - } - - // Try the environment. - const char *vs100comntools = getenv("VS100COMNTOOLS"); - const char *vs90comntools = getenv("VS90COMNTOOLS"); - const char *vs80comntools = getenv("VS80COMNTOOLS"); - const char *vscomntools = NULL; - - // Try to find the version that we were compiled with - if(false) {} - #if (_MSC_VER >= 1600) // VC100 - else if(vs100comntools) { - vscomntools = vs100comntools; - } - #elif (_MSC_VER == 1500) // VC80 - else if(vs90comntools) { - vscomntools = vs90comntools; - } - #elif (_MSC_VER == 1400) // VC80 - else if(vs80comntools) { - vscomntools = vs80comntools; - } - #endif - // Otherwise find any version we can - else if (vs100comntools) - vscomntools = vs100comntools; - else if (vs90comntools) - vscomntools = vs90comntools; - else if (vs80comntools) - vscomntools = vs80comntools; - - if (vscomntools && *vscomntools) { - const char *p = strstr(vscomntools, "\\Common7\\Tools"); - path = p ? std::string(vscomntools, p) : vscomntools; - return true; - } - return false; -} - - // Get Windows SDK installation directory. -static bool getWindowsSDKDir(std::string &path) { - char windowsSDKInstallDir[256]; - // Try the Windows registry. - bool hasSDKDir = getSystemRegistryString( - "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION", - "InstallationFolder", - windowsSDKInstallDir, - sizeof(windowsSDKInstallDir) - 1); - // If we have both vc80 and vc90, pick version we were compiled with. - if (hasSDKDir && windowsSDKInstallDir[0]) { - path = windowsSDKInstallDir; - return(true); - } - return(false); -} - void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, const HeaderSearchOptions &HSOpts) { llvm::Triple::OSType os = triple.getOS(); if (HSOpts.UseStandardSystemIncludes) { switch (os) { case llvm::Triple::FreeBSD: case llvm::Triple::NetBSD: break; default: // FIXME: temporary hack: hard-coded paths. AddPath("/usr/local/include", System, true, false, false); break; } } // Builtin includes use #include_next directives and should be positioned // just prior C include dirs. if (HSOpts.UseBuiltinIncludes) { // Ignore the sys root, we *always* look for clang headers relative to // supplied path. llvm::sys::Path P(HSOpts.ResourceDir); P.appendComponent("include"); AddPath(P.str(), System, false, false, false, /*IgnoreSysRoot=*/ true); } // All remaining additions are for system include directories, early exit if // we aren't using them. if (!HSOpts.UseStandardSystemIncludes) return; // Add dirs specified via 'configure --with-c-include-dirs'. StringRef CIncludeDirs(C_INCLUDE_DIRS); if (CIncludeDirs != "") { SmallVector dirs; CIncludeDirs.split(dirs, ":"); for (SmallVectorImpl::iterator i = dirs.begin(); i != dirs.end(); ++i) AddPath(*i, System, false, false, false); return; } switch (os) { - case llvm::Triple::Win32: { - std::string VSDir; - std::string WindowsSDKDir; - if (getVisualStudioDir(VSDir)) { - AddPath(VSDir + "\\VC\\include", System, false, false, false); - if (getWindowsSDKDir(WindowsSDKDir)) - AddPath(WindowsSDKDir + "\\include", System, false, false, false); - else - AddPath(VSDir + "\\VC\\PlatformSDK\\Include", - System, false, false, false); - } else { - // Default install paths. - AddPath("C:/Program Files/Microsoft Visual Studio 10.0/VC/include", - System, false, false, false); - AddPath("C:/Program Files/Microsoft Visual Studio 9.0/VC/include", - System, false, false, false); - AddPath( - "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include", - System, false, false, false); - AddPath("C:/Program Files/Microsoft Visual Studio 8/VC/include", - System, false, false, false); - AddPath( - "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include", - System, false, false, false); - } - break; - } + case llvm::Triple::Linux: + case llvm::Triple::Win32: + llvm_unreachable("Include management is handled in the driver."); + case llvm::Triple::Haiku: AddPath("/boot/common/include", System, true, false, false); AddPath("/boot/develop/headers/os", System, true, false, false); AddPath("/boot/develop/headers/os/app", System, true, false, false); AddPath("/boot/develop/headers/os/arch", System, true, false, false); AddPath("/boot/develop/headers/os/device", System, true, false, false); AddPath("/boot/develop/headers/os/drivers", System, true, false, false); AddPath("/boot/develop/headers/os/game", System, true, false, false); AddPath("/boot/develop/headers/os/interface", System, true, false, false); AddPath("/boot/develop/headers/os/kernel", System, true, false, false); AddPath("/boot/develop/headers/os/locale", System, true, false, false); AddPath("/boot/develop/headers/os/mail", System, true, false, false); AddPath("/boot/develop/headers/os/media", System, true, false, false); AddPath("/boot/develop/headers/os/midi", System, true, false, false); AddPath("/boot/develop/headers/os/midi2", System, true, false, false); AddPath("/boot/develop/headers/os/net", System, true, false, false); AddPath("/boot/develop/headers/os/storage", System, true, false, false); AddPath("/boot/develop/headers/os/support", System, true, false, false); AddPath("/boot/develop/headers/os/translation", System, true, false, false); AddPath("/boot/develop/headers/os/add-ons/graphics", System, true, false, false); AddPath("/boot/develop/headers/os/add-ons/input_server", System, true, false, false); AddPath("/boot/develop/headers/os/add-ons/screen_saver", System, true, false, false); AddPath("/boot/develop/headers/os/add-ons/tracker", System, true, false, false); AddPath("/boot/develop/headers/os/be_apps/Deskbar", System, true, false, false); AddPath("/boot/develop/headers/os/be_apps/NetPositive", System, true, false, false); AddPath("/boot/develop/headers/os/be_apps/Tracker", System, true, false, false); AddPath("/boot/develop/headers/cpp", System, true, false, false); AddPath("/boot/develop/headers/cpp/i586-pc-haiku", System, true, false, false); AddPath("/boot/develop/headers/3rdparty", System, true, false, false); AddPath("/boot/develop/headers/bsd", System, true, false, false); AddPath("/boot/develop/headers/glibc", System, true, false, false); AddPath("/boot/develop/headers/posix", System, true, false, false); AddPath("/boot/develop/headers", System, true, false, false); break; case llvm::Triple::RTEMS: break; case llvm::Triple::Cygwin: AddPath("/usr/include/w32api", System, true, false, false); break; case llvm::Triple::MinGW32: { // mingw-w64 crt include paths llvm::sys::Path P(HSOpts.ResourceDir); P.appendComponent("../../../i686-w64-mingw32/include"); // /i686-w64-mingw32/include AddPath(P.str(), System, true, false, false); P = llvm::sys::Path(HSOpts.ResourceDir); P.appendComponent("../../../x86_64-w64-mingw32/include"); // /x86_64-w64-mingw32/include AddPath(P.str(), System, true, false, false); // mingw.org crt include paths P = llvm::sys::Path(HSOpts.ResourceDir); P.appendComponent("../../../include"); // /include AddPath(P.str(), System, true, false, false); AddPath("/mingw/include", System, true, false, false); AddPath("c:/mingw/include", System, true, false, false); } break; case llvm::Triple::FreeBSD: AddPath(CLANG_PREFIX "/usr/include/clang/" CLANG_VERSION_STRING, System, false, false, false); break; - case llvm::Triple::Linux: - // Generic Debian multiarch support: - if (triple.getArch() == llvm::Triple::x86_64) { - AddPath("/usr/include/x86_64-linux-gnu", System, false, false, false); - AddPath("/usr/include/i686-linux-gnu/64", System, false, false, false); - AddPath("/usr/include/i486-linux-gnu/64", System, false, false, false); - } else if (triple.getArch() == llvm::Triple::x86) { - AddPath("/usr/include/x86_64-linux-gnu/32", System, false, false, false); - AddPath("/usr/include/i686-linux-gnu", System, false, false, false); - AddPath("/usr/include/i486-linux-gnu", System, false, false, false); - } else if (triple.getArch() == llvm::Triple::arm) { - AddPath("/usr/include/arm-linux-gnueabi", System, false, false, false); - } default: break; } if ( os != llvm::Triple::RTEMS ) AddPath(CLANG_PREFIX "/usr/include", System, false, false, false); } void InitHeaderSearch:: AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOptions &HSOpts) { llvm::Triple::OSType os = triple.getOS(); StringRef CxxIncludeRoot(CXX_INCLUDE_ROOT); if (CxxIncludeRoot != "") { StringRef CxxIncludeArch(CXX_INCLUDE_ARCH); if (CxxIncludeArch == "") AddGnuCPlusPlusIncludePaths(CxxIncludeRoot, triple.str().c_str(), CXX_INCLUDE_32BIT_DIR, CXX_INCLUDE_64BIT_DIR, triple); else AddGnuCPlusPlusIncludePaths(CxxIncludeRoot, CXX_INCLUDE_ARCH, CXX_INCLUDE_32BIT_DIR, CXX_INCLUDE_64BIT_DIR, triple); return; } // FIXME: temporary hack: hard-coded paths. if (triple.isOSDarwin()) { switch (triple.getArch()) { default: break; case llvm::Triple::ppc: case llvm::Triple::ppc64: AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1", "powerpc-apple-darwin10", "", "ppc64", triple); AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.0.0", "powerpc-apple-darwin10", "", "ppc64", triple); break; case llvm::Triple::x86: case llvm::Triple::x86_64: AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1", "i686-apple-darwin10", "", "x86_64", triple); AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.0.0", "i686-apple-darwin8", "", "", triple); break; case llvm::Triple::arm: case llvm::Triple::thumb: AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1", "arm-apple-darwin10", "v7", "", triple); AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1", "arm-apple-darwin10", "v6", "", triple); break; } return; } switch (os) { + case llvm::Triple::Linux: + case llvm::Triple::Win32: + llvm_unreachable("Include management is handled in the driver."); + case llvm::Triple::Cygwin: // Cygwin-1.7 AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.3.4"); // g++-4 / Cygwin-1.5 AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.3.2"); // FIXME: Do we support g++-3.4.4? AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "3.4.4"); break; case llvm::Triple::MinGW32: // mingw-w64 C++ include paths (i686-w64-mingw32 and x86_64-w64-mingw32) AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.5.0"); AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.5.1"); AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.5.2"); AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.5.3"); AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.6.0"); AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.6.1"); AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.6.2"); AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.7.0"); // mingw.org C++ include paths AddMinGWCPlusPlusIncludePaths("/mingw/lib/gcc", "mingw32", "4.5.2"); //MSYS AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.5.0"); AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.4.0"); AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.3.0"); break; case llvm::Triple::DragonFly: AddPath("/usr/include/c++/4.1", CXXSystem, true, false, false); break; - case llvm::Triple::Linux: - //===------------------------------------------------------------------===// - // Debian based distros. - // Note: these distros symlink /usr/include/c++/X.Y.Z -> X.Y - //===------------------------------------------------------------------===// - - // Ubuntu 11.11 "Oneiric Ocelot" -- gcc-4.6.0 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6", - "x86_64-linux-gnu", "32", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6", - "i686-linux-gnu", "", "64", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6", - "i486-linux-gnu", "", "64", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6", - "arm-linux-gnueabi", "", "", triple); - - // Ubuntu 11.04 "Natty Narwhal" -- gcc-4.5.2 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5", - "x86_64-linux-gnu", "32", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5", - "i686-linux-gnu", "", "64", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5", - "i486-linux-gnu", "", "64", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5", - "arm-linux-gnueabi", "", "", triple); - - // Ubuntu 10.10 "Maverick Meerkat" -- gcc-4.4.5 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4", - "i686-linux-gnu", "", "64", triple); - // The rest of 10.10 is the same as previous versions. - - // Ubuntu 10.04 LTS "Lucid Lynx" -- gcc-4.4.3 - // Ubuntu 9.10 "Karmic Koala" -- gcc-4.4.1 - // Debian 6.0 "squeeze" -- gcc-4.4.2 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4", - "x86_64-linux-gnu", "32", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4", - "i486-linux-gnu", "", "64", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4", - "arm-linux-gnueabi", "", "", triple); - // Ubuntu 9.04 "Jaunty Jackalope" -- gcc-4.3.3 - // Ubuntu 8.10 "Intrepid Ibex" -- gcc-4.3.2 - // Debian 5.0 "lenny" -- gcc-4.3.2 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", - "x86_64-linux-gnu", "32", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", - "i486-linux-gnu", "", "64", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", - "arm-linux-gnueabi", "", "", triple); - // Ubuntu 8.04.4 LTS "Hardy Heron" -- gcc-4.2.4 - // Ubuntu 8.04.[0-3] LTS "Hardy Heron" -- gcc-4.2.3 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2", - "x86_64-linux-gnu", "32", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2", - "i486-linux-gnu", "", "64", triple); - // Ubuntu 7.10 "Gutsy Gibbon" -- gcc-4.1.3 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1", - "x86_64-linux-gnu", "32", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1", - "i486-linux-gnu", "", "64", triple); - - //===------------------------------------------------------------------===// - // Redhat based distros. - //===------------------------------------------------------------------===// - // Fedora 15 (GCC 4.6.1) - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.1", - "x86_64-redhat-linux", "32", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.1", - "i686-redhat-linux", "", "", triple); - // Fedora 15 (GCC 4.6.0) - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.0", - "x86_64-redhat-linux", "32", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.0", - "i686-redhat-linux", "", "", triple); - // Fedora 14 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5.1", - "x86_64-redhat-linux", "32", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5.1", - "i686-redhat-linux", "", "", triple); - // RHEL5(gcc44) - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.4", - "x86_64-redhat-linux6E", "32", "", triple); - // Fedora 13 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.4", - "x86_64-redhat-linux", "32", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.4", - "i686-redhat-linux","", "", triple); - // Fedora 12 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3", - "x86_64-redhat-linux", "32", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3", - "i686-redhat-linux","", "", triple); - // Fedora 12 (pre-FEB-2010) - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", - "x86_64-redhat-linux", "32", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", - "i686-redhat-linux","", "", triple); - // Fedora 11 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1", - "x86_64-redhat-linux", "32", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1", - "i586-redhat-linux","", "", triple); - // Fedora 10 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.2", - "x86_64-redhat-linux", "32", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.2", - "i386-redhat-linux","", "", triple); - // Fedora 9 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.0", - "x86_64-redhat-linux", "32", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.0", - "i386-redhat-linux", "", "", triple); - // Fedora 8 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.2", - "x86_64-redhat-linux", "", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.2", - "i386-redhat-linux", "", "", triple); - - // RHEL 5 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.1", - "x86_64-redhat-linux", "32", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.1", - "i386-redhat-linux", "", "", triple); - - - //===------------------------------------------------------------------===// - - // Exherbo (2010-01-25) - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3", - "x86_64-pc-linux-gnu", "32", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3", - "i686-pc-linux-gnu", "", "", triple); - - // openSUSE 11.1 32 bit - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", - "i586-suse-linux", "", "", triple); - // openSUSE 11.1 64 bit - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", - "x86_64-suse-linux", "32", "", triple); - // openSUSE 11.2 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4", - "i586-suse-linux", "", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4", - "x86_64-suse-linux", "", "", triple); - - // openSUSE 11.4 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5", - "i586-suse-linux", "", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5", - "x86_64-suse-linux", "", "", triple); - - // openSUSE 12.1 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6", - "i586-suse-linux", "", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6", - "x86_64-suse-linux", "", "", triple); - // Arch Linux 2008-06-24 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1", - "i686-pc-linux-gnu", "", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1", - "x86_64-unknown-linux-gnu", "", "", triple); - - // Arch Linux gcc 4.6 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.1", - "i686-pc-linux-gnu", "", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.1", - "x86_64-unknown-linux-gnu", "", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.0", - "i686-pc-linux-gnu", "", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.0", - "x86_64-unknown-linux-gnu", "", "", triple); - - // Slackware gcc 4.5.2 (13.37) - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5.2", - "i486-slackware-linux", "", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5.2", - "x86_64-slackware-linux", "", "", triple); - // Slackware gcc 4.5.3 (-current) - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5.3", - "i486-slackware-linux", "", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5.3", - "x86_64-slackware-linux", "", "", triple); - - // Gentoo x86 gcc 4.5.2 - AddGnuCPlusPlusIncludePaths( - "/usr/lib/gcc/i686-pc-linux-gnu/4.5.2/include/g++-v4", - "i686-pc-linux-gnu", "", "", triple); - // Gentoo x86 gcc 4.4.5 - AddGnuCPlusPlusIncludePaths( - "/usr/lib/gcc/i686-pc-linux-gnu/4.4.5/include/g++-v4", - "i686-pc-linux-gnu", "", "", triple); - // Gentoo x86 gcc 4.4.4 - AddGnuCPlusPlusIncludePaths( - "/usr/lib/gcc/i686-pc-linux-gnu/4.4.4/include/g++-v4", - "i686-pc-linux-gnu", "", "", triple); - // Gentoo x86 2010.0 stable - AddGnuCPlusPlusIncludePaths( - "/usr/lib/gcc/i686-pc-linux-gnu/4.4.3/include/g++-v4", - "i686-pc-linux-gnu", "", "", triple); - // Gentoo x86 2009.1 stable - AddGnuCPlusPlusIncludePaths( - "/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4", - "i686-pc-linux-gnu", "", "", triple); - // Gentoo x86 2009.0 stable - AddGnuCPlusPlusIncludePaths( - "/usr/lib/gcc/i686-pc-linux-gnu/4.3.2/include/g++-v4", - "i686-pc-linux-gnu", "", "", triple); - // Gentoo x86 2008.0 stable - AddGnuCPlusPlusIncludePaths( - "/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4", - "i686-pc-linux-gnu", "", "", triple); - // Gentoo x86 llvm-gcc trunk - AddGnuCPlusPlusIncludePaths( - "/usr/lib/llvm-gcc-4.2-9999/include/c++/4.2.1", - "i686-pc-linux-gnu", "", "", triple); - - // Gentoo amd64 gcc 4.5.2 - AddGnuCPlusPlusIncludePaths( - "/usr/lib/gcc/x86_64-pc-linux-gnu/4.5.2/include/g++-v4", - "x86_64-pc-linux-gnu", "32", "", triple); - // Gentoo amd64 gcc 4.4.5 - AddGnuCPlusPlusIncludePaths( - "/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.5/include/g++-v4", - "x86_64-pc-linux-gnu", "32", "", triple); - // Gentoo amd64 gcc 4.4.4 - AddGnuCPlusPlusIncludePaths( - "/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.4/include/g++-v4", - "x86_64-pc-linux-gnu", "32", "", triple); - // Gentoo amd64 gcc 4.4.3 - AddGnuCPlusPlusIncludePaths( - "/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.3/include/g++-v4", - "x86_64-pc-linux-gnu", "32", "", triple); - // Gentoo amd64 gcc 4.3.4 - AddGnuCPlusPlusIncludePaths( - "/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.4/include/g++-v4", - "x86_64-pc-linux-gnu", "", "", triple); - // Gentoo amd64 gcc 4.3.2 - AddGnuCPlusPlusIncludePaths( - "/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.2/include/g++-v4", - "x86_64-pc-linux-gnu", "", "", triple); - // Gentoo amd64 stable - AddGnuCPlusPlusIncludePaths( - "/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4", - "x86_64-pc-linux-gnu", "", "", triple); - - // Gentoo amd64 llvm-gcc trunk - AddGnuCPlusPlusIncludePaths( - "/usr/lib/llvm-gcc-4.2-9999/include/c++/4.2.1", - "x86_64-pc-linux-gnu", "", "", triple); - - break; case llvm::Triple::FreeBSD: // FreeBSD 8.0 // FreeBSD 7.3 AddGnuCPlusPlusIncludePaths(CLANG_PREFIX "/usr/include/c++/4.2", "", "", "", triple); AddGnuCPlusPlusIncludePaths(CLANG_PREFIX "/usr/include/c++/4.2/backward", "", "", "", triple); break; case llvm::Triple::NetBSD: AddGnuCPlusPlusIncludePaths("/usr/include/g++", "", "", "", triple); break; case llvm::Triple::OpenBSD: { std::string t = triple.getTriple(); if (t.substr(0, 6) == "x86_64") t.replace(0, 6, "amd64"); AddGnuCPlusPlusIncludePaths("/usr/include/g++", t, "", "", triple); break; } case llvm::Triple::Minix: AddGnuCPlusPlusIncludePaths("/usr/gnu/include/c++/4.4.3", "", "", "", triple); break; case llvm::Triple::Solaris: // Solaris - Fall though.. case llvm::Triple::AuroraUX: // AuroraUX AddGnuCPlusPlusIncludePaths("/opt/gcc4/include/c++/4.2.4", "i386-pc-solaris2.11", "", "", triple); break; default: break; } } void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang, const llvm::Triple &triple, const HeaderSearchOptions &HSOpts) { + // NB: This code path is going away. All of the logic is moving into the + // driver which has the information necessary to do target-specific + // selections of default include paths. Each target which moves there will be + // exempted from this logic here until we can delete the entire pile of code. + switch (triple.getOS()) { + default: + break; // Everything else continues to use this routine's logic. + + case llvm::Triple::Linux: + case llvm::Triple::Win32: + return; + } + if (Lang.CPlusPlus && HSOpts.UseStandardCXXIncludes && HSOpts.UseStandardSystemIncludes) { if (HSOpts.UseLibcxx) { if (triple.isOSDarwin()) { // On Darwin, libc++ may be installed alongside the compiler in // lib/c++/v1. llvm::sys::Path P(HSOpts.ResourceDir); if (!P.isEmpty()) { P.eraseComponent(); // Remove version from foo/lib/clang/version P.eraseComponent(); // Remove clang from foo/lib/clang // Get foo/lib/c++/v1 P.appendComponent("c++"); P.appendComponent("v1"); AddPath(P.str(), CXXSystem, true, false, false, true); } } AddPath("/usr/include/c++/v1", CXXSystem, true, false, false); } else { AddDefaultCPlusPlusIncludePaths(triple, HSOpts); } } AddDefaultCIncludePaths(triple, HSOpts); // Add the default framework include paths on Darwin. if (HSOpts.UseStandardSystemIncludes) { if (triple.isOSDarwin()) { AddPath("/System/Library/Frameworks", System, true, false, true); AddPath("/Library/Frameworks", System, true, false, true); } } } /// RemoveDuplicates - If there are duplicate directory entries in the specified /// search list, remove the later (dead) ones. Returns the number of non-system /// headers removed, which is used to update NumAngled. static unsigned RemoveDuplicates(std::vector &SearchList, unsigned First, bool Verbose) { llvm::SmallPtrSet SeenDirs; llvm::SmallPtrSet SeenFrameworkDirs; llvm::SmallPtrSet SeenHeaderMaps; unsigned NonSystemRemoved = 0; for (unsigned i = First; i != SearchList.size(); ++i) { unsigned DirToRemove = i; const DirectoryLookup &CurEntry = SearchList[i]; if (CurEntry.isNormalDir()) { // If this isn't the first time we've seen this dir, remove it. if (SeenDirs.insert(CurEntry.getDir())) continue; } else if (CurEntry.isFramework()) { // If this isn't the first time we've seen this framework dir, remove it. if (SeenFrameworkDirs.insert(CurEntry.getFrameworkDir())) continue; } else { assert(CurEntry.isHeaderMap() && "Not a headermap or normal dir?"); // If this isn't the first time we've seen this headermap, remove it. if (SeenHeaderMaps.insert(CurEntry.getHeaderMap())) continue; } // If we have a normal #include dir/framework/headermap that is shadowed // later in the chain by a system include location, we actually want to // ignore the user's request and drop the user dir... keeping the system // dir. This is weird, but required to emulate GCC's search path correctly. // // Since dupes of system dirs are rare, just rescan to find the original // that we're nuking instead of using a DenseMap. if (CurEntry.getDirCharacteristic() != SrcMgr::C_User) { // Find the dir that this is the same of. unsigned FirstDir; for (FirstDir = 0; ; ++FirstDir) { assert(FirstDir != i && "Didn't find dupe?"); const DirectoryLookup &SearchEntry = SearchList[FirstDir]; // If these are different lookup types, then they can't be the dupe. if (SearchEntry.getLookupType() != CurEntry.getLookupType()) continue; bool isSame; if (CurEntry.isNormalDir()) isSame = SearchEntry.getDir() == CurEntry.getDir(); else if (CurEntry.isFramework()) isSame = SearchEntry.getFrameworkDir() == CurEntry.getFrameworkDir(); else { assert(CurEntry.isHeaderMap() && "Not a headermap or normal dir?"); isSame = SearchEntry.getHeaderMap() == CurEntry.getHeaderMap(); } if (isSame) break; } // If the first dir in the search path is a non-system dir, zap it // instead of the system one. if (SearchList[FirstDir].getDirCharacteristic() == SrcMgr::C_User) DirToRemove = FirstDir; } if (Verbose) { llvm::errs() << "ignoring duplicate directory \"" << CurEntry.getName() << "\"\n"; if (DirToRemove != i) llvm::errs() << " as it is a non-system directory that duplicates " << "a system directory\n"; } if (DirToRemove != i) ++NonSystemRemoved; // This is reached if the current entry is a duplicate. Remove the // DirToRemove (usually the current dir). SearchList.erase(SearchList.begin()+DirToRemove); --i; } return NonSystemRemoved; } void InitHeaderSearch::Realize(const LangOptions &Lang) { // Concatenate ANGLE+SYSTEM+AFTER chains together into SearchList. std::vector SearchList; SearchList.reserve(IncludePath.size()); // Quoted arguments go first. for (path_iterator it = IncludePath.begin(), ie = IncludePath.end(); it != ie; ++it) { if (it->first == Quoted) SearchList.push_back(it->second); } // Deduplicate and remember index. RemoveDuplicates(SearchList, 0, Verbose); unsigned NumQuoted = SearchList.size(); for (path_iterator it = IncludePath.begin(), ie = IncludePath.end(); it != ie; ++it) { if (it->first == Angled || it->first == IndexHeaderMap) SearchList.push_back(it->second); } RemoveDuplicates(SearchList, NumQuoted, Verbose); unsigned NumAngled = SearchList.size(); for (path_iterator it = IncludePath.begin(), ie = IncludePath.end(); it != ie; ++it) { if (it->first == System || (!Lang.ObjC1 && !Lang.CPlusPlus && it->first == CSystem) || (/*FIXME !Lang.ObjC1 && */Lang.CPlusPlus && it->first == CXXSystem) || (Lang.ObjC1 && !Lang.CPlusPlus && it->first == ObjCSystem) || (Lang.ObjC1 && Lang.CPlusPlus && it->first == ObjCXXSystem)) SearchList.push_back(it->second); } for (path_iterator it = IncludePath.begin(), ie = IncludePath.end(); it != ie; ++it) { if (it->first == After) SearchList.push_back(it->second); } // Remove duplicates across both the Angled and System directories. GCC does // this and failing to remove duplicates across these two groups breaks // #include_next. unsigned NonSystemRemoved = RemoveDuplicates(SearchList, NumQuoted, Verbose); NumAngled -= NonSystemRemoved; bool DontSearchCurDir = false; // TODO: set to true if -I- is set? Headers.SetSearchPaths(SearchList, NumQuoted, NumAngled, DontSearchCurDir); // If verbose, print the list of directories that will be searched. if (Verbose) { llvm::errs() << "#include \"...\" search starts here:\n"; for (unsigned i = 0, e = SearchList.size(); i != e; ++i) { if (i == NumQuoted) llvm::errs() << "#include <...> search starts here:\n"; const char *Name = SearchList[i].getName(); const char *Suffix; if (SearchList[i].isNormalDir()) Suffix = ""; else if (SearchList[i].isFramework()) Suffix = " (framework directory)"; else { assert(SearchList[i].isHeaderMap() && "Unknown DirectoryLookup"); Suffix = " (headermap)"; } llvm::errs() << " " << Name << Suffix << "\n"; } llvm::errs() << "End of search list.\n"; } } void clang::ApplyHeaderSearchOptions(HeaderSearch &HS, const HeaderSearchOptions &HSOpts, const LangOptions &Lang, const llvm::Triple &Triple) { InitHeaderSearch Init(HS, HSOpts.Verbose, HSOpts.Sysroot); // Add the user defined entries. for (unsigned i = 0, e = HSOpts.UserEntries.size(); i != e; ++i) { const HeaderSearchOptions::Entry &E = HSOpts.UserEntries[i]; - Init.AddPath(E.Path, E.Group, false, E.IsUserSupplied, E.IsFramework, - E.IgnoreSysRoot); + Init.AddPath(E.Path, E.Group, !E.ImplicitExternC, E.IsUserSupplied, + E.IsFramework, E.IgnoreSysRoot); } Init.AddDefaultIncludePaths(Lang, Triple, HSOpts); Init.Realize(Lang); } Index: head/contrib/llvm/tools/clang =================================================================== --- head/contrib/llvm/tools/clang (revision 228378) +++ head/contrib/llvm/tools/clang (revision 228379) Property changes on: head/contrib/llvm/tools/clang ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /vendor/clang/dist:r226608-228371 Index: head/contrib/llvm =================================================================== --- head/contrib/llvm (revision 228378) +++ head/contrib/llvm (revision 228379) Property changes on: head/contrib/llvm ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /vendor/llvm/dist:r226588-228368 Index: head/lib/clang/include/MipsGenCodeEmitter.inc =================================================================== --- head/lib/clang/include/MipsGenCodeEmitter.inc (nonexistent) +++ head/lib/clang/include/MipsGenCodeEmitter.inc (revision 228379) @@ -0,0 +1,2 @@ +/* $FreeBSD$ */ +#include "MipsGenCodeEmitter.inc.h" Property changes on: head/lib/clang/include/MipsGenCodeEmitter.inc ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: head/lib/clang/include/clang/Basic/Version.inc =================================================================== --- head/lib/clang/include/clang/Basic/Version.inc (revision 228378) +++ head/lib/clang/include/clang/Basic/Version.inc (revision 228379) @@ -1,10 +1,10 @@ /* $FreeBSD$ */ #define CLANG_VERSION 3.0 #define CLANG_VERSION_MAJOR 3 #define CLANG_VERSION_MINOR 0 #define CLANG_VENDOR "FreeBSD " -#define CLANG_VENDOR_SUFFIX " 20111021" +#define CLANG_VENDOR_SUFFIX " 20111209" -#define SVN_REVISION "142614" +#define SVN_REVISION "145546" Index: head/lib/clang/libllvmmipscodegen/Makefile =================================================================== --- head/lib/clang/libllvmmipscodegen/Makefile (revision 228378) +++ head/lib/clang/libllvmmipscodegen/Makefile (revision 228379) @@ -1,32 +1,33 @@ # $FreeBSD$ LIB= llvmmipscodegen SRCDIR= lib/Target/Mips SRCS= MipsAsmPrinter.cpp \ MipsCodeEmitter.cpp \ MipsDelaySlotFiller.cpp \ MipsEmitGPRestore.cpp \ MipsExpandPseudo.cpp \ MipsFrameLowering.cpp \ MipsISelDAGToDAG.cpp \ MipsISelLowering.cpp \ MipsInstrInfo.cpp \ MipsJITInfo.cpp \ MipsMCInstLower.cpp \ MipsMCSymbolRefExpr.cpp \ MipsRegisterInfo.cpp \ MipsSelectionDAGInfo.cpp \ MipsSubtarget.cpp \ MipsTargetMachine.cpp \ MipsTargetObjectFile.cpp TGHDRS= Intrinsics \ MipsGenAsmWriter \ MipsGenCallingConv \ + MipsGenCodeEmitter \ MipsGenDAGISel \ MipsGenInstrInfo \ MipsGenRegisterInfo \ MipsGenSubtargetInfo .include "../clang.lib.mk"