diff options
author | Abdoulaye Walsimou Gaye <awg@embtoolkit.org> | 2013-05-12 19:55:19 +0200 |
---|---|---|
committer | Abdoulaye Walsimou Gaye <awg@embtoolkit.org> | 2013-05-12 19:55:19 +0200 |
commit | 23d8d191eff180ba312a4d1b4fec8597e5a988d5 (patch) | |
tree | 25022dea79a8f9b830aad4d2845af6a2a9fa081b | |
parent | 0824091315296ab3da27856b76e7422348d3850d (diff) | |
parent | fa49d7d6e4384381e4307a0d2495e6e5b15821e3 (diff) | |
download | llvm-23d8d191eff180ba312a4d1b4fec8597e5a988d5.tar.gz llvm-23d8d191eff180ba312a4d1b4fec8597e5a988d5.tar.bz2 llvm-23d8d191eff180ba312a4d1b4fec8597e5a988d5.tar.xz |
Merge branch 'master' into embtk-support-master
116 files changed, 3857 insertions, 1786 deletions
diff --git a/docs/CommandLine.rst b/docs/CommandLine.rst index 9b77a98908..6535551844 100644 --- a/docs/CommandLine.rst +++ b/docs/CommandLine.rst @@ -930,7 +930,8 @@ This section describes the basic attributes that you can specify on options. .. _cl::desc(...): * The **cl::desc** attribute specifies a description for the option to be - shown in the ``-help`` output for the program. + shown in the ``-help`` output for the program. This attribute supports + multi-line descriptions with lines separated by '\n'. .. _cl::value_desc: diff --git a/include/llvm/CodeGen/MachineModuleInfo.h b/include/llvm/CodeGen/MachineModuleInfo.h index a3acec8095..b719757822 100644 --- a/include/llvm/CodeGen/MachineModuleInfo.h +++ b/include/llvm/CodeGen/MachineModuleInfo.h @@ -234,7 +234,12 @@ public: /// getFrameMoves - Returns a reference to a list of moves done in the current /// function's prologue. Used to construct frame maps for debug and exception /// handling comsumers. - std::vector<MachineMove> &getFrameMoves() { return FrameMoves; } + const std::vector<MachineMove> &getFrameMoves() { return FrameMoves; } + + void addFrameMove(MCSymbol *Label, const MachineLocation &Dst, + const MachineLocation &Src) { + FrameMoves.push_back(MachineMove(Label, Dst, Src)); + } /// getCompactUnwindEncoding - Returns the compact unwind encoding for a /// function if the target supports the encoding. This encoding replaces a diff --git a/include/llvm/DIBuilder.h b/include/llvm/DIBuilder.h index 4ce884b736..72da916e45 100644 --- a/include/llvm/DIBuilder.h +++ b/include/llvm/DIBuilder.h @@ -327,15 +327,14 @@ namespace llvm { /// @param Scope Scope in which this type is defined. /// @param Name Value parameter name. /// @param Ty Parameter type. - /// @param Value Constant parameter value. + /// @param Val Constant parameter value. /// @param File File where this type parameter is defined. /// @param LineNo Line number. /// @param ColumnNo Column Number. DITemplateValueParameter - createTemplateValueParameter(DIDescriptor Scope, StringRef Name, DIType Ty, - uint64_t Value, - MDNode *File = 0, unsigned LineNo = 0, - unsigned ColumnNo = 0); + createTemplateValueParameter(DIDescriptor Scope, StringRef Name, + DIType Ty, Value *Val, MDNode *File = 0, + unsigned LineNo = 0, unsigned ColumnNo = 0); /// createArrayType - Create debugging information entry for an array. /// @param Size Array size. diff --git a/include/llvm/DebugInfo.h b/include/llvm/DebugInfo.h index 5f92ca22ec..91c3066338 100644 --- a/include/llvm/DebugInfo.h +++ b/include/llvm/DebugInfo.h @@ -401,7 +401,7 @@ namespace llvm { DIScope getContext() const { return getFieldAs<DIScope>(1); } StringRef getName() const { return getStringField(2); } DIType getType() const { return getFieldAs<DIType>(3); } - uint64_t getValue() const { return getUInt64Field(4); } + Value *getValue() const; StringRef getFilename() const { return getFieldAs<DIFile>(5).getFilename(); } diff --git a/include/llvm/Support/TargetRegistry.h b/include/llvm/Support/TargetRegistry.h index b06676d4d2..5bfb8ad41d 100644 --- a/include/llvm/Support/TargetRegistry.h +++ b/include/llvm/Support/TargetRegistry.h @@ -70,8 +70,7 @@ namespace llvm { typedef unsigned (*TripleMatchQualityFnTy)(const std::string &TT); - typedef MCAsmInfo *(*MCAsmInfoCtorFnTy)(const Target &T, - StringRef TT); + typedef MCAsmInfo *(*MCAsmInfoCtorFnTy)(StringRef TT); typedef MCCodeGenInfo *(*MCCodeGenInfoCtorFnTy)(StringRef TT, Reloc::Model RM, CodeModel::Model CM, @@ -269,7 +268,7 @@ namespace llvm { MCAsmInfo *createMCAsmInfo(StringRef Triple) const { if (!MCAsmInfoCtorFn) return 0; - return MCAsmInfoCtorFn(*this, Triple); + return MCAsmInfoCtorFn(Triple); } /// createMCCodeGenInfo - Create a MCCodeGenInfo implementation. @@ -804,8 +803,8 @@ namespace llvm { TargetRegistry::RegisterMCAsmInfo(T, &Allocator); } private: - static MCAsmInfo *Allocator(const Target &T, StringRef TT) { - return new MCAsmInfoImpl(T, TT); + static MCAsmInfo *Allocator(StringRef TT) { + return new MCAsmInfoImpl(TT); } }; diff --git a/lib/Bitcode/Reader/BitstreamReader.cpp b/lib/Bitcode/Reader/BitstreamReader.cpp index 9dafe2a036..1fd9abd8b1 100644 --- a/lib/Bitcode/Reader/BitstreamReader.cpp +++ b/lib/Bitcode/Reader/BitstreamReader.cpp @@ -204,7 +204,16 @@ unsigned BitstreamCursor::readRecord(unsigned AbbrevID, const BitCodeAbbrev *Abbv = getAbbrev(AbbrevID); - for (unsigned i = 0, e = Abbv->getNumOperandInfos(); i != e; ++i) { + // Read the record code first. + assert(Abbv->getNumOperandInfos() != 0 && "no record code in abbreviation?"); + const BitCodeAbbrevOp &CodeOp = Abbv->getOperandInfo(0); + if (CodeOp.isLiteral()) + readAbbreviatedLiteral(CodeOp, Vals); + else + readAbbreviatedField(CodeOp, Vals); + unsigned Code = (unsigned)Vals.pop_back_val(); + + for (unsigned i = 1, e = Abbv->getNumOperandInfos(); i != e; ++i) { const BitCodeAbbrevOp &Op = Abbv->getOperandInfo(i); if (Op.isLiteral()) { readAbbreviatedLiteral(Op, Vals); @@ -264,8 +273,6 @@ unsigned BitstreamCursor::readRecord(unsigned AbbrevID, JumpToBit(NewEnd); } - unsigned Code = (unsigned)Vals[0]; - Vals.erase(Vals.begin()); return Code; } diff --git a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 84162ace41..eb744d243b 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -636,11 +636,12 @@ void AsmPrinter::emitPrologLabel(const MachineInstr &MI) { OutStreamer.EmitCompactUnwindEncoding(MMI->getCompactUnwindEncoding()); MachineModuleInfo &MMI = MF->getMMI(); - std::vector<MachineMove> &Moves = MMI.getFrameMoves(); + const std::vector<MachineMove> &Moves = MMI.getFrameMoves(); bool FoundOne = false; (void)FoundOne; - for (std::vector<MachineMove>::iterator I = Moves.begin(), - E = Moves.end(); I != E; ++I) { + for (std::vector<MachineMove>::const_iterator I = Moves.begin(), + E = Moves.end(); + I != E; ++I) { if (I->getLabel() == Label) { EmitCFIFrameMove(*I); FoundOne = true; diff --git a/lib/CodeGen/AsmPrinter/DwarfAccelTable.cpp b/lib/CodeGen/AsmPrinter/DwarfAccelTable.cpp index f58ec9b4bf..a82a149ca3 100644 --- a/lib/CodeGen/AsmPrinter/DwarfAccelTable.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfAccelTable.cpp @@ -76,7 +76,7 @@ static bool compareDIEs(const DwarfAccelTable::HashDataContents *A, return A->Die->getOffset() < B->Die->getOffset(); } -void DwarfAccelTable::FinalizeTable(AsmPrinter *Asm, const char *Prefix) { +void DwarfAccelTable::FinalizeTable(AsmPrinter *Asm, StringRef Prefix) { // Create the individual hash data outputs. for (StringMap<DataArray>::iterator EI = Entries.begin(), EE = Entries.end(); EI != EE; ++EI) { diff --git a/lib/CodeGen/AsmPrinter/DwarfAccelTable.h b/lib/CodeGen/AsmPrinter/DwarfAccelTable.h index 9915bcaa9b..3ef1dc5544 100644 --- a/lib/CodeGen/AsmPrinter/DwarfAccelTable.h +++ b/lib/CodeGen/AsmPrinter/DwarfAccelTable.h @@ -271,7 +271,7 @@ private: DwarfAccelTable(ArrayRef<DwarfAccelTable::Atom>); ~DwarfAccelTable(); void AddName(StringRef, DIE*, char = 0); - void FinalizeTable(AsmPrinter *, const char *); + void FinalizeTable(AsmPrinter *, StringRef); void Emit(AsmPrinter *, MCSymbol *, DwarfUnits *); #ifndef NDEBUG void print(raw_ostream &O); diff --git a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp index c38ada6b66..7f0c33bb05 100644 --- a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -588,6 +588,9 @@ static bool isTypeSigned(DIType Ty, int *SizeInBits) { /// addConstantValue - Add constant value entry in variable DIE. bool CompileUnit::addConstantValue(DIE *Die, const MachineOperand &MO, DIType Ty) { + // FIXME: This is a bit conservative/simple - it emits negative values at + // their maximum bit width which is a bit unfortunate (& doesn't prefer + // udata/sdata over dataN as suggested by the DWARF spec) assert(MO.isImm() && "Invalid machine operand!"); DIEBlock *Block = new (DIEValueAllocator) DIEBlock(); int SizeInBits = -1; @@ -1095,8 +1098,21 @@ CompileUnit::getOrCreateTemplateValueParameterDIE(DITemplateValueParameter TPV){ addType(ParamDIE, TPV.getType()); if (!TPV.getName().empty()) addString(ParamDIE, dwarf::DW_AT_name, TPV.getName()); - addUInt(ParamDIE, dwarf::DW_AT_const_value, dwarf::DW_FORM_udata, - TPV.getValue()); + if (Value *Val = TPV.getValue()) { + if (ConstantInt *CI = dyn_cast<ConstantInt>(Val)) + addConstantValue(ParamDIE, CI, TPV.getType().isUnsignedDIType()); + else if (GlobalValue *GV = dyn_cast<GlobalValue>(Val)) { + // For declaration non-type template parameters (such as global values and + // functions) + DIEBlock *Block = new (DIEValueAllocator) DIEBlock(); + addOpAddress(Block, Asm->Mang->getSymbol(GV)); + // Emit DW_OP_stack_value to use the address as the immediate value of the + // parameter, rather than a pointer to it. + addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_stack_value); + addBlock(ParamDIE, dwarf::DW_AT_location, 0, Block); + } + } + return ParamDIE; } diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index d8de3ca859..19bbc73815 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -1677,9 +1677,6 @@ void DwarfDebug::endFunction(const MachineFunction *MF) { if (!MF->getTarget().Options.DisableFramePointerElim(*MF)) TheCU->addFlag(CurFnDIE, dwarf::DW_AT_APPLE_omit_frame_ptr); - DebugFrames.push_back(FunctionDebugFrameInfo(Asm->getFunctionNumber(), - MMI->getFrameMoves())); - // Clear debug info for (DenseMap<LexicalScope *, SmallVector<DbgVariable *, 8> >::iterator I = ScopeVariables.begin(), E = ScopeVariables.end(); I != E; ++I) @@ -2069,7 +2066,7 @@ void DwarfDebug::emitAccelNames() { const StringMap<std::vector<DIE*> > &Names = TheCU->getAccelNames(); for (StringMap<std::vector<DIE*> >::const_iterator GI = Names.begin(), GE = Names.end(); GI != GE; ++GI) { - const char *Name = GI->getKeyData(); + StringRef Name = GI->getKey(); const std::vector<DIE *> &Entities = GI->second; for (std::vector<DIE *>::const_iterator DI = Entities.begin(), DE = Entities.end(); DI != DE; ++DI) @@ -2098,7 +2095,7 @@ void DwarfDebug::emitAccelObjC() { const StringMap<std::vector<DIE*> > &Names = TheCU->getAccelObjC(); for (StringMap<std::vector<DIE*> >::const_iterator GI = Names.begin(), GE = Names.end(); GI != GE; ++GI) { - const char *Name = GI->getKeyData(); + StringRef Name = GI->getKey(); const std::vector<DIE *> &Entities = GI->second; for (std::vector<DIE *>::const_iterator DI = Entities.begin(), DE = Entities.end(); DI != DE; ++DI) @@ -2126,7 +2123,7 @@ void DwarfDebug::emitAccelNamespaces() { const StringMap<std::vector<DIE*> > &Names = TheCU->getAccelNamespace(); for (StringMap<std::vector<DIE*> >::const_iterator GI = Names.begin(), GE = Names.end(); GI != GE; ++GI) { - const char *Name = GI->getKeyData(); + StringRef Name = GI->getKey(); const std::vector<DIE *> &Entities = GI->second; for (std::vector<DIE *>::const_iterator DI = Entities.begin(), DE = Entities.end(); DI != DE; ++DI) @@ -2161,7 +2158,7 @@ void DwarfDebug::emitAccelTypes() { = TheCU->getAccelTypes(); for (StringMap<std::vector<std::pair<DIE*, unsigned> > >::const_iterator GI = Names.begin(), GE = Names.end(); GI != GE; ++GI) { - const char *Name = GI->getKeyData(); + StringRef Name = GI->getKey(); const std::vector<std::pair<DIE *, unsigned> > &Entities = GI->second; for (std::vector<std::pair<DIE *, unsigned> >::const_iterator DI = Entities.begin(), DE = Entities.end(); DI !=DE; ++DI) @@ -2225,7 +2222,7 @@ void DwarfDebug::emitDebugPubnames() { if (Asm->isVerbose()) Asm->OutStreamer.AddComment("External Name"); - Asm->OutStreamer.EmitBytes(StringRef(Name, strlen(Name)+1), 0); + Asm->OutStreamer.EmitBytes(StringRef(Name, GI->getKeyLength()+1), 0); } Asm->OutStreamer.AddComment("End Mark"); diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.h b/lib/CodeGen/AsmPrinter/DwarfDebug.h index b36b763720..6cc792b373 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -377,16 +377,6 @@ class DwarfDebug { // body. DebugLoc PrologEndLoc; - struct FunctionDebugFrameInfo { - unsigned Number; - std::vector<MachineMove> Moves; - - FunctionDebugFrameInfo(unsigned Num, const std::vector<MachineMove> &M) - : Number(Num), Moves(M) {} - }; - - std::vector<FunctionDebugFrameInfo> DebugFrames; - // Section Symbols: these are assembler temporary labels that are emitted at // the beginning of each supported dwarf section. These are used to form // section offsets and are created by EmitSectionLabels. diff --git a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index 700ee12072..c54dffbb13 100644 --- a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -3464,8 +3464,7 @@ SDValue DAGCombiner::visitXOR(SDNode *N) { if (N0.getOpcode() == ISD::AND && N0.getNode()->hasOneUse() && N0->getOperand(1) == N1) { SDValue X = N0->getOperand(0); - SDValue NotX = DAG.getNode(ISD::XOR, X.getDebugLoc(), VT, X, - DAG.getConstant(APInt::getAllOnesValue(VT.getSizeInBits()), VT)); + SDValue NotX = DAG.getNOT(X.getDebugLoc(), X, VT); AddToWorkList(NotX.getNode()); return DAG.getNode(ISD::AND, N->getDebugLoc(), VT, NotX, N1); } diff --git a/lib/ExecutionEngine/JIT/JITDwarfEmitter.h b/lib/ExecutionEngine/JIT/JITDwarfEmitter.h deleted file mode 100644 index 98ac340491..0000000000 --- a/lib/ExecutionEngine/JIT/JITDwarfEmitter.h +++ /dev/null @@ -1,77 +0,0 @@ -//===------ JITDwarfEmitter.h - Write dwarf tables into memory ------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines a JITDwarfEmitter object that is used by the JIT to -// write dwarf tables to memory. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_EXECUTION_ENGINE_JIT_DWARFEMITTER_H -#define LLVM_EXECUTION_ENGINE_JIT_DWARFEMITTER_H - -#include "llvm/Support/DataTypes.h" -#include <vector> - -namespace llvm { - -class Function; -class JIT; -class JITCodeEmitter; -class MachineFunction; -class MachineModuleInfo; -class MachineMove; -class MCAsmInfo; -class DataLayout; -class TargetMachine; -class TargetRegisterInfo; - -class JITDwarfEmitter { - const DataLayout* TD; - JITCodeEmitter* JCE; - const TargetRegisterInfo* RI; - const MCAsmInfo *MAI; - MachineModuleInfo* MMI; - JIT& Jit; - bool stackGrowthDirection; - - unsigned char* EmitExceptionTable(MachineFunction* MF, - unsigned char* StartFunction, - unsigned char* EndFunction) const; - - void EmitFrameMoves(intptr_t BaseLabelPtr, - const std::vector<MachineMove> &Moves) const; - - unsigned char* EmitCommonEHFrame(const Function* Personality) const; - - unsigned char* EmitEHFrame(const Function* Personality, - unsigned char* StartBufferPtr, - unsigned char* StartFunction, - unsigned char* EndFunction, - unsigned char* ExceptionTable) const; - -public: - - JITDwarfEmitter(JIT& jit); - - unsigned char* EmitDwarfTable(MachineFunction& F, - JITCodeEmitter& JCE, - unsigned char* StartFunction, - unsigned char* EndFunction, - unsigned char* &EHFramePtr); - - - void setModuleInfo(MachineModuleInfo* Info) { - MMI = Info; - } -}; - - -} // end namespace llvm - -#endif // LLVM_EXECUTION_ENGINE_JIT_DWARFEMITTER_H diff --git a/lib/ExecutionEngine/JIT/JITEmitter.cpp b/lib/ExecutionEngine/JIT/JITEmitter.cpp index d813c53dce..acbbfa1455 100644 --- a/lib/ExecutionEngine/JIT/JITEmitter.cpp +++ b/lib/ExecutionEngine/JIT/JITEmitter.cpp @@ -14,7 +14,6 @@ #define DEBUG_TYPE "jit" #include "JIT.h" -#include "JITDwarfEmitter.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallPtrSet.h" @@ -325,9 +324,6 @@ namespace { /// Resolver - This contains info about the currently resolved functions. JITResolver Resolver; - /// DE - The dwarf emitter for the jit. - OwningPtr<JITDwarfEmitter> DE; - /// LabelLocations - This vector is a mapping from Label ID's to their /// address. DenseMap<MCSymbol*, uintptr_t> LabelLocations; @@ -454,7 +450,6 @@ namespace { virtual void setModuleInfo(MachineModuleInfo* Info) { MMI = Info; - if (DE.get()) DE->setModuleInfo(Info); } private: diff --git a/lib/IR/DIBuilder.cpp b/lib/IR/DIBuilder.cpp index eb220b2349..4bb87c9afb 100644 --- a/lib/IR/DIBuilder.cpp +++ b/lib/IR/DIBuilder.cpp @@ -502,7 +502,7 @@ DIBuilder::createTemplateTypeParameter(DIDescriptor Context, StringRef Name, /// value parameter. DITemplateValueParameter DIBuilder::createTemplateValueParameter(DIDescriptor Context, StringRef Name, - DIType Ty, uint64_t Val, + DIType Ty, Value *Val, MDNode *File, unsigned LineNo, unsigned ColumnNo) { Value *Elts[] = { @@ -510,7 +510,7 @@ DIBuilder::createTemplateValueParameter(DIDescriptor Context, StringRef Name, getNonCompileUnitScope(Context), MDString::get(VMContext, Name), Ty, - ConstantInt::get(Type::getInt64Ty(VMContext), Val), + Val, File, ConstantInt::get(Type::getInt32Ty(VMContext), LineNo), ConstantInt::get(Type::getInt32Ty(VMContext), ColumnNo) diff --git a/lib/IR/DebugInfo.cpp b/lib/IR/DebugInfo.cpp index 38fc90f865..8a0fb8d5b1 100644 --- a/lib/IR/DebugInfo.cpp +++ b/lib/IR/DebugInfo.cpp @@ -695,6 +695,10 @@ DIArray DISubprogram::getVariables() const { return DIArray(); } +Value *DITemplateValueParameter::getValue() const { + return getField(DbgNode, 4); +} + void DIScope::setFilename(StringRef Name, LLVMContext &Context) { if (!DbgNode) return; diff --git a/lib/Support/CommandLine.cpp b/lib/Support/CommandLine.cpp index 18d3db527b..f09705e69a 100644 --- a/lib/Support/CommandLine.cpp +++ b/lib/Support/CommandLine.cpp @@ -913,11 +913,20 @@ size_t alias::getOptionWidth() const { return std::strlen(ArgStr)+6; } +static void printHelpStr(StringRef HelpStr, size_t Indent, + size_t FirstLineIndentedBy) { + std::pair<StringRef, StringRef> Split = HelpStr.split('\n'); + outs().indent(Indent - FirstLineIndentedBy) << " - " << Split.first << "\n"; + while (!Split.second.empty()) { + Split = Split.second.split('\n'); + outs().indent(Indent) << Split.first << "\n"; + } +} + // Print out the option for the alias. void alias::printOptionInfo(size_t GlobalWidth) const { - size_t L = std::strlen(ArgStr); outs() << " -" << ArgStr; - outs().indent(GlobalWidth-L-6) << " - " << HelpStr << "\n"; + printHelpStr(HelpStr, GlobalWidth, std::strlen(ArgStr) + 6); } //===----------------------------------------------------------------------===// @@ -946,7 +955,7 @@ void basic_parser_impl::printOptionInfo(const Option &O, if (const char *ValName = getValueName()) outs() << "=<" << getValueStr(O, ValName) << '>'; - outs().indent(GlobalWidth-getOptionWidth(O)) << " - " << O.HelpStr << '\n'; + printHelpStr(O.HelpStr, GlobalWidth, getOptionWidth(O)); } void basic_parser_impl::printOptionName(const Option &O, @@ -1087,9 +1096,8 @@ size_t generic_parser_base::getOptionWidth(const Option &O) const { void generic_parser_base::printOptionInfo(const Option &O, size_t GlobalWidth) const { if (O.hasArgStr()) { - size_t L = std::strlen(O.ArgStr); outs() << " -" << O.ArgStr; - outs().indent(GlobalWidth-L-6) << " - " << O.HelpStr << '\n'; + printHelpStr(O.HelpStr, GlobalWidth, std::strlen(O.ArgStr) + 6); for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { size_t NumSpaces = GlobalWidth-strlen(getOption(i))-8; @@ -1100,9 +1108,9 @@ void generic_parser_base::printOptionInfo(const Option &O, if (O.HelpStr[0]) outs() << " " << O.HelpStr << '\n'; for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { - size_t L = std::strlen(getOption(i)); - outs() << " -" << getOption(i); - outs().indent(GlobalWidth-L-8) << " - " << getDescription(i) << '\n'; + const char *Option = getOption(i); + outs() << " -" << Option; + printHelpStr(getDescription(i), GlobalWidth, std::strlen(Option) + 8); } } } diff --git a/lib/Target/AArch64/AArch64FrameLowering.cpp b/lib/Target/AArch64/AArch64FrameLowering.cpp index daa7f1d5ef..0474aaf487 100644 --- a/lib/Target/AArch64/AArch64FrameLowering.cpp +++ b/lib/Target/AArch64/AArch64FrameLowering.cpp @@ -54,7 +54,6 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF) const { DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); MachineModuleInfo &MMI = MF.getMMI(); - std::vector<MachineMove> &Moves = MMI.getFrameMoves(); bool NeedsFrameMoves = MMI.hasDebugInfo() || MF.getFunction()->needsUnwindTableEntry(); @@ -98,7 +97,7 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF) const { MachineLocation Dst(MachineLocation::VirtualFP); MachineLocation Src(AArch64::XSP, NumInitialBytes); - Moves.push_back(MachineMove(SPLabel, Dst, Src)); + MMI.addFrameMove(SPLabel, Dst, Src); } // Otherwise we need to set the frame pointer and/or add a second stack @@ -133,7 +132,7 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF) const { .addSym(FPLabel); MachineLocation Dst(MachineLocation::VirtualFP); MachineLocation Src(AArch64::X29, -MFI->getObjectOffset(X29FrameIdx)); - Moves.push_back(MachineMove(FPLabel, Dst, Src)); + MMI.addFrameMove(FPLabel, Dst, Src); } FPNeedsSetting = false; @@ -165,7 +164,7 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF) const { MachineLocation Dst(MachineLocation::VirtualFP); MachineLocation Src(AArch64::XSP, NumResidualBytes + NumInitialBytes); - Moves.push_back(MachineMove(CSLabel, Dst, Src)); + MMI.addFrameMove(CSLabel, Dst, Src); } // And any callee-saved registers (it's fine to leave them to the end here, @@ -183,7 +182,7 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF) const { MachineLocation Dst(MachineLocation::VirtualFP, MFI->getObjectOffset(I->getFrameIdx())); MachineLocation Src(I->getReg()); - Moves.push_back(MachineMove(CSLabel, Dst, Src)); + MMI.addFrameMove(CSLabel, Dst, Src); } } } diff --git a/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp b/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp index 819eeadb44..3435217bb2 100644 --- a/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp +++ b/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp @@ -57,7 +57,7 @@ static MCRegisterInfo *createAArch64MCRegisterInfo(StringRef Triple) { return X; } -static MCAsmInfo *createAArch64MCAsmInfo(const Target &T, StringRef TT) { +static MCAsmInfo *createAArch64MCAsmInfo(StringRef TT) { Triple TheTriple(TT); MCAsmInfo *MAI = new AArch64ELFMCAsmInfo(); diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 1dd2953b29..4d3bf34d48 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -49,6 +49,20 @@ class ARMAsmParser : public MCTargetAsmParser { MCAsmParser &Parser; const MCRegisterInfo *MRI; + // Unwind directives state + SMLoc FnStartLoc; + SMLoc CantUnwindLoc; + SMLoc PersonalityLoc; + SMLoc HandlerDataLoc; + int FPReg; + void resetUnwindDirectiveParserState() { + FnStartLoc = SMLoc(); + CantUnwindLoc = SMLoc(); + PersonalityLoc = SMLoc(); + HandlerDataLoc = SMLoc(); + FPReg = -1; + } + // Map of register aliases registers via the .req directive. StringMap<unsigned> RegisterReqs; @@ -113,6 +127,14 @@ class ARMAsmParser : public MCTargetAsmParser { bool parseDirectiveUnreq(SMLoc L); bool parseDirectiveArch(SMLoc L); bool parseDirectiveEabiAttr(SMLoc L); + bool parseDirectiveFnStart(SMLoc L); + bool parseDirectiveFnEnd(SMLoc L); + bool parseDirectiveCantUnwind(SMLoc L); + bool parseDirectivePersonality(SMLoc L); + bool parseDirectiveHandlerData(SMLoc L); + bool parseDirectiveSetFP(SMLoc L); + bool parseDirectivePad(SMLoc L); + bool parseDirectiveRegSave(SMLoc L, bool IsVector); StringRef splitMnemonic(StringRef Mnemonic, unsigned &PredicationCode, bool &CarrySetting, unsigned &ProcessorIMod, @@ -242,7 +264,7 @@ public: }; ARMAsmParser(MCSubtargetInfo &_STI, MCAsmParser &_Parser) - : MCTargetAsmParser(), STI(_STI), Parser(_Parser) { + : MCTargetAsmParser(), STI(_STI), Parser(_Parser), FPReg(-1) { MCAsmParserExtension::Initialize(_Parser); // Cache the MCRegisterInfo. @@ -7658,6 +7680,24 @@ bool ARMAsmParser::ParseDirective(AsmToken DirectiveID) { return parseDirectiveArch(DirectiveID.getLoc()); else if (IDVal == ".eabi_attribute") return parseDirectiveEabiAttr(DirectiveID.getLoc()); + else if (IDVal == ".fnstart") + return parseDirectiveFnStart(DirectiveID.getLoc()); + else if (IDVal == ".fnend") + return parseDirectiveFnEnd(DirectiveID.getLoc()); + else if (IDVal == ".cantunwind") + return parseDirectiveCantUnwind(DirectiveID.getLoc()); + else if (IDVal == ".personality") + return parseDirectivePersonality(DirectiveID.getLoc()); + else if (IDVal == ".handlerdata") + return parseDirectiveHandlerData(DirectiveID.getLoc()); + else if (IDVal == ".setfp") + return parseDirectiveSetFP(DirectiveID.getLoc()); + else if (IDVal == ".pad") + return parseDirectivePad(DirectiveID.getLoc()); + else if (IDVal == ".save") + return parseDirectiveRegSave(DirectiveID.getLoc(), false); + else if (IDVal == ".vsave") + return parseDirectiveRegSave(DirectiveID.getLoc(), true); return true; } @@ -7858,6 +7898,219 @@ bool ARMAsmParser::parseDirectiveEabiAttr(SMLoc L) { return true; } +/// parseDirectiveFnStart +/// ::= .fnstart +bool ARMAsmParser::parseDirectiveFnStart(SMLoc L) { + if (FnStartLoc.isValid()) { + Error(L, ".fnstart starts before the end of previous one"); + Error(FnStartLoc, "previous .fnstart starts here"); + return true; + } + + FnStartLoc = L; + getParser().getStreamer().EmitFnStart(); + return false; +} + +/// parseDirectiveFnEnd +/// ::= .fnend +bool ARMAsmParser::parseDirectiveFnEnd(SMLoc L) { + // Check the ordering of unwind directives + if (!FnStartLoc.isValid()) + return Error(L, ".fnstart must precede .fnend directive"); + + // Reset the unwind directives parser state + resetUnwindDirectiveParserState(); + + getParser().getStreamer().EmitFnEnd(); + return false; +} + +/// parseDirectiveCantUnwind +/// ::= .cantunwind +bool ARMAsmParser::parseDirectiveCantUnwind(SMLoc L) { + // Check the ordering of unwind directives + CantUnwindLoc = L; + if (!FnStartLoc.isValid()) + return Error(L, ".fnstart must precede .cantunwind directive"); + if (HandlerDataLoc.isValid()) { + Error(L, ".cantunwind can't be used with .handlerdata directive"); + Error(HandlerDataLoc, ".handlerdata was specified here"); + return true; + } + if (PersonalityLoc.isValid()) { + Error(L, ".cantunwind can't be used with .personality directive"); + Error(PersonalityLoc, ".personality was specified here"); + return true; + } + + getParser().getStreamer().EmitCantUnwind(); + return false; +} + +/// parseDirectivePersonality +/// ::= .personality name +bool ARMAsmParser::parseDirectivePersonality(SMLoc L) { + // Check the ordering of unwind directives + PersonalityLoc = L; + if (!FnStartLoc.isValid()) + return Error(L, ".fnstart must precede .personality directive"); + if (CantUnwindLoc.isValid()) { + Error(L, ".personality can't be used with .cantunwind directive"); + Error(CantUnwindLoc, ".cantunwind was specified here"); + return true; + } + if (HandlerDataLoc.isValid()) { + Error(L, ".personality must precede .handlerdata directive"); + Error(HandlerDataLoc, ".handlerdata was specified here"); + return true; + } + + // Parse the name of the personality routine + if (Parser.getTok().isNot(AsmToken::Identifier)) { + Parser.eatToEndOfStatement(); + return Error(L, "unexpected input in .personality directive."); + } + StringRef Name(Parser.getTok().getIdentifier()); + Parser.Lex(); + + MCSymbol *PR = getParser().getContext().GetOrCreateSymbol(Name); + getParser().getStreamer().EmitPersonality(PR); + return false; +} + +/// parseDirectiveHandlerData +/// ::= .handlerdata +bool ARMAsmParser::parseDirectiveHandlerData(SMLoc L) { + // Check the ordering of unwind directives + HandlerDataLoc = L; + if (!FnStartLoc.isValid()) + return Error(L, ".fnstart must precede .personality directive"); + if (CantUnwindLoc.isValid()) { + Error(L, ".handlerdata can't be used with .cantunwind directive"); + Error(CantUnwindLoc, ".cantunwind was specified here"); + return true; + } + + getParser().getStreamer().EmitHandlerData(); + return false; +} + +/// parseDirectiveSetFP +/// ::= .setfp fpreg, spreg [, offset] +bool ARMAsmParser::parseDirectiveSetFP(SMLoc L) { + // Check the ordering of unwind directives + if (!FnStartLoc.isValid()) + return Error(L, ".fnstart must precede .setfp directive"); + if (HandlerDataLoc.isValid()) + return Error(L, ".setfp must precede .handlerdata directive"); + + // Parse fpreg + SMLoc NewFPRegLoc = Parser.getTok().getLoc(); + int NewFPReg = tryParseRegister(); + if (NewFPReg == -1) + return Error(NewFPRegLoc, "frame pointer register expected"); + + // Consume comma + if (!Parser.getTok().is(AsmToken::Comma)) + return Error(Parser.getTok().getLoc(), "comma expected"); + Parser.Lex(); // skip comma + + // Parse spreg + SMLoc NewSPRegLoc = Parser.getTok().getLoc(); + int NewSPReg = tryParseRegister(); + if (NewSPReg == -1) + return Error(NewSPRegLoc, "stack pointer register expected"); + + if (NewSPReg != ARM::SP && NewSPReg != FPReg) + return Error(NewSPRegLoc, + "register should be either $sp or the latest fp register"); + + // Update the frame pointer register + FPReg = NewFPReg; + + // Parse offset + int64_t Offset = 0; + if (Parser.getTok().is(AsmToken::Comma)) { + Parser.Lex(); // skip comma + + if (Parser.getTok().isNot(AsmToken::Hash) && + Parser.getTok().isNot(AsmToken::Dollar)) { + return Error(Parser.getTok().getLoc(), "'#' expected"); + } + Parser.Lex(); // skip hash token. + + const MCExpr *OffsetExpr; + SMLoc ExLoc = Parser.getTok().getLoc(); + SMLoc EndLoc; + if (getParser().parseExpression(OffsetExpr, EndLoc)) + return Error(ExLoc, "malformed setfp offset"); + const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(OffsetExpr); + if (!CE) + return Error(ExLoc, "setfp offset must be an immediate"); + + Offset = CE->getValue(); + } + + getParser().getStreamer().EmitSetFP(static_cast<unsigned>(NewFPReg), + static_cast<unsigned>(NewSPReg), + Offset); + return false; +} + +/// parseDirective +/// ::= .pad offset +bool ARMAsmParser::parseDirectivePad(SMLoc L) { + // Check the ordering of unwind directives + if (!FnStartLoc.isValid()) + return Error(L, ".fnstart must precede .pad directive"); + if (HandlerDataLoc.isValid()) + return Error(L, ".pad must precede .handlerdata directive"); + + // Parse the offset + if (Parser.getTok().isNot(AsmToken::Hash) && + Parser.getTok().isNot(AsmToken::Dollar)) { + return Error(Parser.getTok().getLoc(), "'#' expected"); + } + Parser.Lex(); // skip hash token. + + const MCExpr *OffsetExpr; + SMLoc ExLoc = Parser.getTok().getLoc(); + SMLoc EndLoc; + if (getParser().parseExpression(OffsetExpr, EndLoc)) + return Error(ExLoc, "malformed pad offset"); + const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(OffsetExpr); + if (!CE) + return Error(ExLoc, "pad offset must be an immediate"); + + getParser().getStreamer().EmitPad(CE->getValue()); + return false; +} + +/// parseDirectiveRegSave +/// ::= .save { registers } +/// ::= .vsave { registers } +bool ARMAsmParser::parseDirectiveRegSave(SMLoc L, bool IsVector) { + // Check the ordering of unwind directives + if (!FnStartLoc.isValid()) + return Error(L, ".fnstart must precede .save or .vsave directives"); + if (HandlerDataLoc.isValid()) + return Error(L, ".save or .vsave must precede .handlerdata directive"); + + // Parse the register list + SmallVector<MCParsedAsmOperand*, 1> Operands; + if (parseRegisterList(Operands)) + return true; + ARMOperand *Op = (ARMOperand*)Operands[0]; + if (!IsVector && !Op->isRegList()) + return Error(L, ".save expects GPR registers"); + if (IsVector && !Op->isDPRRegList()) + return Error(L, ".vsave expects DPR registers"); + + getParser().getStreamer().EmitRegSave(Op->getRegList(), IsVector); + return false; +} + /// Force static initialization. extern "C" void LLVMInitializeARMAsmParser() { RegisterMCAsmParser<ARMAsmParser> X(TheARMTarget); diff --git a/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp b/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp index 6c3d247668..82d296ffd7 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp +++ b/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp @@ -204,6 +204,7 @@ private: void EmitPersonalityFixup(StringRef Name); void CollectUnwindOpcodes(); + void FlushUnwindOpcodes(bool AllowCompactModel0); void SwitchToEHSection(const char *Prefix, unsigned Type, unsigned Flags, SectionKind Kind, const MCSymbol &Fn); @@ -333,22 +334,8 @@ void ARMELFStreamer::EmitFnEnd() { assert(FnStart && ".fnstart must preceeds .fnend"); // Emit unwind opcodes if there is no .handlerdata directive - if (!ExTab && !CantUnwind) { - CollectUnwindOpcodes(); - - unsigned PersonalityIndex = UnwindOpAsm.getPersonalityIndex(); - if (PersonalityIndex == AEABI_UNWIND_CPP_PR1 || - PersonalityIndex == AEABI_UNWIND_CPP_PR2) { - // For the __aeabi_unwind_cpp_pr1 and __aeabi_unwind_cpp_pr2, we have to - // emit the unwind opcodes in the corresponding ".ARM.extab" section, and - // then emit a reference to these unwind opcodes in the second word of - // the exception index table entry. - SwitchToExTabSection(*FnStart); - ExTab = getContext().CreateTempSymbol(); - EmitLabel(ExTab); - EmitBytes(UnwindOpAsm.data(), 0); - } - } + if (!ExTab && !CantUnwind) + FlushUnwindOpcodes(true); // Emit the exception index table entry SwitchToExIdxSection(*FnStart); @@ -384,6 +371,9 @@ void ARMELFStreamer::EmitFnEnd() { EmitBytes(UnwindOpAsm.data(), 0); } + // Switch to the section containing FnStart + SwitchSection(&FnStart->getSection()); + // Clean exception handling frame information Reset(); } @@ -392,7 +382,18 @@ void ARMELFStreamer::EmitCantUnwind() { CantUnwind = true; } -void ARMELFStreamer::EmitHandlerData() { +void ARMELFStreamer::FlushUnwindOpcodes(bool AllowCompactModel0) { + // Collect and finalize the unwind opcodes + CollectUnwindOpcodes(); + + // For compact model 0, we have to emit the unwind opcodes in the .ARM.exidx + // section. Thus, we don't have to create an entry in the .ARM.extab + // section. + if (AllowCompactModel0 && + UnwindOpAsm.getPersonalityIndex() == AEABI_UNWIND_CPP_PR0) + return; + + // Switch to .ARM.extab section. SwitchToExTabSection(*FnStart); // Create .ARM.extab label for offset in .ARM.exidx @@ -400,21 +401,24 @@ void ARMELFStreamer::EmitHandlerData() { ExTab = getContext().CreateTempSymbol(); EmitLabel(ExTab); - // Emit Personality - assert(Personality && ".personality directive must preceed .handlerdata"); - - const MCSymbolRefExpr *PersonalityRef = - MCSymbolRefExpr::Create(Personality, - MCSymbolRefExpr::VK_ARM_PREL31, - getContext()); + // Emit personality + if (Personality) { + const MCSymbolRefExpr *PersonalityRef = + MCSymbolRefExpr::Create(Personality, + MCSymbolRefExpr::VK_ARM_PREL31, + getContext()); - EmitValue(PersonalityRef, 4, 0); + EmitValue(PersonalityRef, 4, 0); + } // Emit unwind opcodes - CollectUnwindOpcodes(); EmitBytes(UnwindOpAsm.data(), 0); } +void ARMELFStreamer::EmitHandlerData() { + FlushUnwindOpcodes(false); +} + void ARMELFStreamer::EmitPersonality(const MCSymbol *Per) { Personality = Per; UnwindOpAsm.setPersonality(Per); diff --git a/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp b/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp index f09fb5a94f..57239f8011 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp +++ b/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp @@ -159,7 +159,7 @@ static MCRegisterInfo *createARMMCRegisterInfo(StringRef Triple) { return X; } -static MCAsmInfo *createARMMCAsmInfo(const Target &T, StringRef TT) { +static MCAsmInfo *createARMMCAsmInfo(StringRef TT) { Triple TheTriple(TT); if (TheTriple.isOSDarwin()) diff --git a/lib/Target/Hexagon/Hexagon.td b/lib/Target/Hexagon/Hexagon.td index 9b3a64316a..568798c3a4 100644 --- a/lib/Target/Hexagon/Hexagon.td +++ b/lib/Target/Hexagon/Hexagon.td @@ -120,15 +120,39 @@ def getPredNewOpcode : InstrMapping { } //===----------------------------------------------------------------------===// +// Generate mapping table to relate .new predicated instructions with their old +// format. +// +def getPredOldOpcode : InstrMapping { + let FilterClass = "PredNewRel"; + let RowFields = ["BaseOpcode", "PredSense", "isNVStore"]; + let ColFields = ["PNewValue"]; + let KeyCol = ["new"]; + let ValueCols = [[""]]; +} + +//===----------------------------------------------------------------------===// // Generate mapping table to relate store instructions with their new-value // format. // def getNewValueOpcode : InstrMapping { let FilterClass = "NewValueRel"; let RowFields = ["BaseOpcode", "PredSense", "PNewValue"]; - let ColFields = ["isNVStore"]; - let KeyCol = ["0"]; - let ValueCols = [["1"]]; + let ColFields = ["NValueST"]; + let KeyCol = ["false"]; + let ValueCols = [["true"]]; +} + +//===----------------------------------------------------------------------===// +// Generate mapping table to relate new-value store instructions with their old +// format. +// +def getNonNVStore : InstrMapping { + let FilterClass = "NewValueRel"; + let RowFields = ["BaseOpcode", "PredSense", "PNewValue"]; + let ColFields = ["NValueST"]; + let KeyCol = ["true"]; + let ValueCols = [["false"]]; } def getBasedWithImmOffset : InstrMapping { diff --git a/lib/Target/Hexagon/HexagonFrameLowering.cpp b/lib/Target/Hexagon/HexagonFrameLowering.cpp index de993ee875..f9bc83bb20 100644 --- a/lib/Target/Hexagon/HexagonFrameLowering.cpp +++ b/lib/Target/Hexagon/HexagonFrameLowering.cpp @@ -113,8 +113,6 @@ void HexagonFrameLowering::emitPrologue(MachineFunction &MF) const { MO.setImm(MFI->getMaxCallFrameSize()); } - std::vector<MachineMove> &Moves = MMI.getFrameMoves(); - if (needsFrameMoves) { // Advance CFA. DW_CFA_def_cfa unsigned FPReg = QRI->getFrameRegister(); @@ -122,17 +120,17 @@ void HexagonFrameLowering::emitPrologue(MachineFunction &MF) const { MachineLocation Dst(MachineLocation::VirtualFP); MachineLocation Src(FPReg, -8); - Moves.push_back(MachineMove(0, Dst, Src)); + MMI.addFrameMove(0, Dst, Src); // R31 = (R31 - #4) MachineLocation LRDst(RAReg, -4); MachineLocation LRSrc(RAReg); - Moves.push_back(MachineMove(0, LRDst, LRSrc)); + MMI.addFrameMove(0, LRDst, LRSrc); // R30 = (R30 - #8) MachineLocation SPDst(FPReg, -8); MachineLocation SPSrc(FPReg); - Moves.push_back(MachineMove(0, SPDst, SPSrc)); + MMI.addFrameMove(0, SPDst, SPSrc); } // @@ -174,30 +172,55 @@ void HexagonFrameLowering::emitEpilogue(MachineFunction &MF, MachineBasicBlock::iterator MBBI = prior(MBB.end()); DebugLoc dl = MBBI->getDebugLoc(); // - // Only insert deallocframe if we need to. + // Only insert deallocframe if we need to. Also at -O0. See comment + // in emitPrologue above. // - if (hasFP(MF)) { + if (hasFP(MF) || MF.getTarget().getOptLevel() == CodeGenOpt::None) { MachineBasicBlock::iterator MBBI = prior(MBB.end()); MachineBasicBlock::iterator MBBI_end = MBB.end(); - // - // For Hexagon, we don't need the frame size. - // - MachineFrameInfo *MFI = MF.getFrameInfo(); - int NumBytes = (int) MFI->getStackSize(); const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo(); - + // Handle EH_RETURN. + if (MBBI->getOpcode() == Hexagon::EH_RETURN_JMPR) { + assert(MBBI->getOperand(0).isReg() && "Offset should be in register!"); + BuildMI(MBB, MBBI, dl, TII.get(Hexagon::DEALLOCFRAME)); + BuildMI(MBB, MBBI, dl, TII.get(Hexagon::ADD_rr), + Hexagon::R29).addReg(Hexagon::R29).addReg(Hexagon::R28); + return; + } // Replace 'jumpr r31' instruction with dealloc_return for V4 and higher // versions. if (STI.hasV4TOps() && MBBI->getOpcode() == Hexagon::JMPret && !DisableDeallocRet) { - // Remove jumpr node. - MBB.erase(MBBI); + // Check for RESTORE_DEALLOC_RET_JMP_V4 call. Don't emit an extra DEALLOC + // instruction if we encounter it. + MachineBasicBlock::iterator BeforeJMPR = + MBB.begin() == MBBI ? MBBI : prior(MBBI); + if (BeforeJMPR != MBBI && + BeforeJMPR->getOpcode() == Hexagon::RESTORE_DEALLOC_RET_JMP_V4) { + // Remove the JMPR node. + MBB.erase(MBBI); + return; + } + // Add dealloc_return. - BuildMI(MBB, MBBI_end, dl, TII.get(Hexagon::DEALLOC_RET_V4)) - .addImm(NumBytes); - } else { // Add deallocframe for V2 and V3. - BuildMI(MBB, MBBI, dl, TII.get(Hexagon::DEALLOCFRAME)).addImm(NumBytes); + MachineInstrBuilder MIB = + BuildMI(MBB, MBBI_end, dl, TII.get(Hexagon::DEALLOC_RET_V4)); + // Transfer the function live-out registers. + MIB->copyImplicitOps(*MBB.getParent(), &*MBBI); + // Remove the JUMPR node. + MBB.erase(MBBI); + } else { // Add deallocframe for V2 and V3, and V4 tail calls. + // Check for RESTORE_DEALLOC_BEFORE_TAILCALL_V4. We don't need an extra + // DEALLOCFRAME instruction after it. + MachineBasicBlock::iterator Term = MBB.getFirstTerminator(); + MachineBasicBlock::iterator I = + Term == MBB.begin() ? MBB.end() : prior(Term); + if (I != MBB.end() && + I->getOpcode() == Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4) + return; + + BuildMI(MBB, MBBI, dl, TII.get(Hexagon::DEALLOCFRAME)); } } } diff --git a/lib/Target/Hexagon/HexagonInstrFormats.td b/lib/Target/Hexagon/HexagonInstrFormats.td index f97143ff01..e71386ada2 100644 --- a/lib/Target/Hexagon/HexagonInstrFormats.td +++ b/lib/Target/Hexagon/HexagonInstrFormats.td @@ -158,6 +158,7 @@ class InstHexagon<dag outs, dag ins, string asmstr, list<dag> pattern, string CextOpcode = ""; string PredSense = ""; string PNewValue = ""; + string NValueST = ""; // Set to "true" for new-value stores. string InputType = ""; // Input is "imm" or "reg" type. string isMEMri = "false"; // Set to "true" for load/store with MEMri operand. string isFloat = "false"; // Set to "true" for the floating-point load/store. @@ -166,6 +167,7 @@ class InstHexagon<dag outs, dag ins, string asmstr, list<dag> pattern, let PredSense = !if(isPredicated, !if(isPredicatedFalse, "false", "true"), ""); let PNewValue = !if(isPredicatedNew, "new", ""); + let NValueST = !if(isNVStore, "true", "false"); // *** Must match MCTargetDesc/HexagonBaseInfo.h *** } diff --git a/lib/Target/Hexagon/HexagonInstrInfo.cpp b/lib/Target/Hexagon/HexagonInstrInfo.cpp index 469e8021fa..33a937308d 100644 --- a/lib/Target/Hexagon/HexagonInstrInfo.cpp +++ b/lib/Target/Hexagon/HexagonInstrInfo.cpp @@ -630,111 +630,6 @@ bool HexagonInstrInfo::isBranch (const MachineInstr *MI) const { return MI->getDesc().isBranch(); } -bool HexagonInstrInfo::isNewValueStore(const MachineInstr *MI) const { - switch (MI->getOpcode()) { - default: return false; - // Store Byte - case Hexagon::STrib_nv_V4: - case Hexagon::STrib_indexed_nv_V4: - case Hexagon::STrib_indexed_shl_nv_V4: - case Hexagon::STrib_shl_nv_V4: - case Hexagon::STb_GP_nv_V4: - case Hexagon::POST_STbri_nv_V4: - case Hexagon::STrib_cPt_nv_V4: - case Hexagon::STrib_cdnPt_nv_V4: - case Hexagon::STrib_cNotPt_nv_V4: - case Hexagon::STrib_cdnNotPt_nv_V4: - case Hexagon::STrib_indexed_cPt_nv_V4: - case Hexagon::STrib_indexed_cdnPt_nv_V4: - case Hexagon::STrib_indexed_cNotPt_nv_V4: - case Hexagon::STrib_indexed_cdnNotPt_nv_V4: - case Hexagon::STrib_indexed_shl_cPt_nv_V4: - case Hexagon::STrib_indexed_shl_cdnPt_nv_V4: - case Hexagon::STrib_indexed_shl_cNotPt_nv_V4: - case Hexagon::STrib_indexed_shl_cdnNotPt_nv_V4: - case Hexagon::POST_STbri_cPt_nv_V4: - case Hexagon::POST_STbri_cdnPt_nv_V4: - case Hexagon::POST_STbri_cNotPt_nv_V4: - case Hexagon::POST_STbri_cdnNotPt_nv_V4: - case Hexagon::STb_GP_cPt_nv_V4: - case Hexagon::STb_GP_cNotPt_nv_V4: - case Hexagon::STb_GP_cdnPt_nv_V4: - case Hexagon::STb_GP_cdnNotPt_nv_V4: - case Hexagon::STrib_abs_nv_V4: - case Hexagon::STrib_abs_cPt_nv_V4: - case Hexagon::STrib_abs_cdnPt_nv_V4: - case Hexagon::STrib_abs_cNotPt_nv_V4: - case Hexagon::STrib_abs_cdnNotPt_nv_V4: - - // Store Halfword - case Hexagon::STrih_nv_V4: - case Hexagon::STrih_indexed_nv_V4: - case Hexagon::STrih_indexed_shl_nv_V4: - case Hexagon::STrih_shl_nv_V4: - case Hexagon::STh_GP_nv_V4: - case Hexagon::POST_SThri_nv_V4: - case Hexagon::STrih_cPt_nv_V4: - case Hexagon::STrih_cdnPt_nv_V4: - case Hexagon::STrih_cNotPt_nv_V4: - case Hexagon::STrih_cdnNotPt_nv_V4: - case Hexagon::STrih_indexed_cPt_nv_V4: - case Hexagon::STrih_indexed_cdnPt_nv_V4: - case Hexagon::STrih_indexed_cNotPt_nv_V4: - case Hexagon::STrih_indexed_cdnNotPt_nv_V4: - case Hexagon::STrih_indexed_shl_cPt_nv_V4: - case Hexagon::STrih_indexed_shl_cdnPt_nv_V4: - case Hexagon::STrih_indexed_shl_cNotPt_nv_V4: - case Hexagon::STrih_indexed_shl_cdnNotPt_nv_V4: - case Hexagon::POST_SThri_cPt_nv_V4: - case Hexagon::POST_SThri_cdnPt_nv_V4: - case Hexagon::POST_SThri_cNotPt_nv_V4: - case Hexagon::POST_SThri_cdnNotPt_nv_V4: - case Hexagon::STh_GP_cPt_nv_V4: - case Hexagon::STh_GP_cNotPt_nv_V4: - case Hexagon::STh_GP_cdnPt_nv_V4: - case Hexagon::STh_GP_cdnNotPt_nv_V4: - case Hexagon::STrih_abs_nv_V4: - case Hexagon::STrih_abs_cPt_nv_V4: - case Hexagon::STrih_abs_cdnPt_nv_V4: - case Hexagon::STrih_abs_cNotPt_nv_V4: - case Hexagon::STrih_abs_cdnNotPt_nv_V4: - - // Store Word - case Hexagon::STriw_nv_V4: - case Hexagon::STriw_indexed_nv_V4: - case Hexagon::STriw_indexed_shl_nv_V4: - case Hexagon::STriw_shl_nv_V4: - case Hexagon::STw_GP_nv_V4: - case Hexagon::POST_STwri_nv_V4: - case Hexagon::STriw_cPt_nv_V4: - case Hexagon::STriw_cdnPt_nv_V4: - case Hexagon::STriw_cNotPt_nv_V4: - case Hexagon::STriw_cdnNotPt_nv_V4: - case Hexagon::STriw_indexed_cPt_nv_V4: - case Hexagon::STriw_indexed_cdnPt_nv_V4: - case Hexagon::STriw_indexed_cNotPt_nv_V4: - case Hexagon::STriw_indexed_cdnNotPt_nv_V4: - case Hexagon::STriw_indexed_shl_cPt_nv_V4: - case Hexagon::STriw_indexed_shl_cdnPt_nv_V4: - case Hexagon::STriw_indexed_shl_cNotPt_nv_V4: - case Hexagon::STriw_indexed_shl_cdnNotPt_nv_V4: - case Hexagon::POST_STwri_cPt_nv_V4: - case Hexagon::POST_STwri_cdnPt_nv_V4: - case Hexagon::POST_STwri_cNotPt_nv_V4: - case Hexagon::POST_STwri_cdnNotPt_nv_V4: - case Hexagon::STw_GP_cPt_nv_V4: - case Hexagon::STw_GP_cNotPt_nv_V4: - case Hexagon::STw_GP_cdnPt_nv_V4: - case Hexagon::STw_GP_cdnNotPt_nv_V4: - case Hexagon::STriw_abs_nv_V4: - case Hexagon::STriw_abs_cPt_nv_V4: - case Hexagon::STriw_abs_cdnPt_nv_V4: - case Hexagon::STriw_abs_cNotPt_nv_V4: - case Hexagon::STriw_abs_cdnNotPt_nv_V4: - return true; - } -} - bool HexagonInstrInfo::isNewValueInst(const MachineInstr *MI) const { if (isNewValueJump(MI)) return true; @@ -862,6 +757,18 @@ unsigned HexagonInstrInfo::getInvertedPredicatedOpcode(const int Opc) const { } } +// New Value Store instructions. +bool HexagonInstrInfo::isNewValueStore(const MachineInstr *MI) const { + const uint64_t F = MI->getDesc().TSFlags; + + return ((F >> HexagonII::NVStorePos) & HexagonII::NVStoreMask); +} + +bool HexagonInstrInfo::isNewValueStore(unsigned Opcode) const { + const uint64_t F = get(Opcode).TSFlags; + + return ((F >> HexagonII::NVStorePos) & HexagonII::NVStoreMask); +} int HexagonInstrInfo:: getMatchingCondBranchOpcode(int Opc, bool invertPredicate) const { @@ -1120,6 +1027,16 @@ bool HexagonInstrInfo::isPredicatedNew(unsigned Opcode) const { return ((F >> HexagonII::PredicatedNewPos) & HexagonII::PredicatedNewMask); } +// Returns true, if a ST insn can be promoted to a new-value store. +bool HexagonInstrInfo::mayBeNewStore(const MachineInstr *MI) const { + const HexagonRegisterInfo& QRI = getRegisterInfo(); + const uint64_t F = MI->getDesc().TSFlags; + + return ((F >> HexagonII::mayNVStorePos) & + HexagonII::mayNVStoreMask & + QRI.Subtarget.hasV4TOps()); +} + bool HexagonInstrInfo::DefinesPredicate(MachineInstr *MI, std::vector<MachineOperand> &Pred) const { @@ -1304,6 +1221,8 @@ isValidAutoIncImm(const EVT VT, const int Offset) const { bool HexagonInstrInfo:: isMemOp(const MachineInstr *MI) const { +// return MI->getDesc().mayLoad() && MI->getDesc().mayStore(); + switch (MI->getOpcode()) { default: return false; @@ -1611,6 +1530,59 @@ bool HexagonInstrInfo::isDotNewInst (const MachineInstr* MI) const { (isPredicated(MI) && isPredicatedNew(MI))); } +// Returns the most basic instruction for the .new predicated instructions and +// new-value stores. +// For example, all of the following instructions will be converted back to the +// same instruction: +// 1) if (p0.new) memw(R0+#0) = R1.new ---> +// 2) if (p0) memw(R0+#0)= R1.new -------> if (p0) memw(R0+#0) = R1 +// 3) if (p0.new) memw(R0+#0) = R1 ---> +// + +int HexagonInstrInfo::GetDotOldOp(const int opc) const { + int NewOp = opc; + if (isPredicated(NewOp) && isPredicatedNew(NewOp)) { // Get predicate old form + NewOp = Hexagon::getPredOldOpcode(NewOp); + if (NewOp < 0) + assert(0 && "Couldn't change predicate new instruction to its old form."); + } + + if (isNewValueStore(NewOp)) { // Convert into non new-value format + NewOp = Hexagon::getNonNVStore(NewOp); + if (NewOp < 0) + assert(0 && "Couldn't change new-value store to its old form."); + } + return NewOp; +} + +// Return the new value instruction for a given store. +int HexagonInstrInfo::GetDotNewOp(const MachineInstr* MI) const { + int NVOpcode = Hexagon::getNewValueOpcode(MI->getOpcode()); + if (NVOpcode >= 0) // Valid new-value store instruction. + return NVOpcode; + + switch (MI->getOpcode()) { + default: llvm_unreachable("Unknown .new type"); + // store new value byte + case Hexagon::STrib_shl_V4: + return Hexagon::STrib_shl_nv_V4; + + case Hexagon::STrih_shl_V4: + return Hexagon::STrih_shl_nv_V4; + + case Hexagon::STriw_f: + return Hexagon::STriw_nv_V4; + + case Hexagon::STriw_indexed_f: + return Hexagon::STriw_indexed_nv_V4; + + case Hexagon::STriw_shl_V4: + return Hexagon::STriw_shl_nv_V4; + + } + return 0; +} + // Return .new predicate version for an instruction. int HexagonInstrInfo::GetDotNewPredOp(MachineInstr *MI, const MachineBranchProbabilityInfo diff --git a/lib/Target/Hexagon/HexagonInstrInfo.h b/lib/Target/Hexagon/HexagonInstrInfo.h index 2becc02570..d1209dec3b 100644 --- a/lib/Target/Hexagon/HexagonInstrInfo.h +++ b/lib/Target/Hexagon/HexagonInstrInfo.h @@ -185,15 +185,19 @@ public: bool isNewValueInst(const MachineInstr* MI) const; bool isNewValue(const MachineInstr* MI) const; bool isDotNewInst(const MachineInstr* MI) const; + int GetDotOldOp(const int opc) const; + int GetDotNewOp(const MachineInstr* MI) const; int GetDotNewPredOp(MachineInstr *MI, const MachineBranchProbabilityInfo *MBPI) const; + bool mayBeNewStore(const MachineInstr* MI) const; bool isDeallocRet(const MachineInstr *MI) const; unsigned getInvertedPredicatedOpcode(const int Opc) const; bool isExtendable(const MachineInstr* MI) const; bool isExtended(const MachineInstr* MI) const; bool isPostIncrement(const MachineInstr* MI) const; bool isNewValueStore(const MachineInstr* MI) const; + bool isNewValueStore(unsigned Opcode) const; bool isNewValueJump(const MachineInstr* MI) const; bool isNewValueJumpCandidate(const MachineInstr *MI) const; diff --git a/lib/Target/Hexagon/HexagonInstrInfoV4.td b/lib/Target/Hexagon/HexagonInstrInfoV4.td index c7f4edfe67..022a7f6136 100644 --- a/lib/Target/Hexagon/HexagonInstrInfoV4.td +++ b/lib/Target/Hexagon/HexagonInstrInfoV4.td @@ -2564,8 +2564,9 @@ def NTSTBIT_ri : SInst<(outs PredRegs:$dst), (ins IntRegs:$src1, u5Imm:$src2), //Deallocate frame and return. // dealloc_return let isReturn = 1, isTerminator = 1, isBarrier = 1, isPredicable = 1, - Defs = [R29, R30, R31, PC], Uses = [R29, R31], neverHasSideEffects = 1 in { - def DEALLOC_RET_V4 : NVInst_V4<(outs), (ins i32imm:$amt1), + Defs = [R29, R30, R31, PC], Uses = [R30], neverHasSideEffects = 1 in { +let validSubTargets = HasV4SubT in + def DEALLOC_RET_V4 : LD0Inst<(outs), (ins), "dealloc_return", []>, Requires<[HasV4T]>; @@ -2574,9 +2575,10 @@ let isReturn = 1, isTerminator = 1, isBarrier = 1, isPredicable = 1, // Restore registers and dealloc return function call. let isCall = 1, isBarrier = 1, isReturn = 1, isTerminator = 1, Defs = [R29, R30, R31, PC] in { +let validSubTargets = HasV4SubT in def RESTORE_DEALLOC_RET_JMP_V4 : JInst<(outs), (ins calltarget:$dst), - "jump $dst // Restore_and_dealloc_return", + "jump $dst", []>, Requires<[HasV4T]>; } @@ -2584,9 +2586,10 @@ let isCall = 1, isBarrier = 1, isReturn = 1, isTerminator = 1, // Restore registers and dealloc frame before a tail call. let isCall = 1, isBarrier = 1, Defs = [R29, R30, R31, PC] in { +let validSubTargets = HasV4SubT in def RESTORE_DEALLOC_BEFORE_TAILCALL_V4 : JInst<(outs), (ins calltarget:$dst), - "call $dst // Restore_and_dealloc_before_tailcall", + "call $dst", []>, Requires<[HasV4T]>; } @@ -2603,10 +2606,11 @@ let isCall = 1, isBarrier = 1, // if (Ps) dealloc_return let isReturn = 1, isTerminator = 1, - Defs = [R29, R30, R31, PC], Uses = [R29, R31], neverHasSideEffects = 1, + Defs = [R29, R30, R31, PC], Uses = [R30], neverHasSideEffects = 1, isPredicated = 1 in { - def DEALLOC_RET_cPt_V4 : NVInst_V4<(outs), - (ins PredRegs:$src1, i32imm:$amt1), +let validSubTargets = HasV4SubT in + def DEALLOC_RET_cPt_V4 : LD0Inst<(outs), + (ins PredRegs:$src1), "if ($src1) dealloc_return", []>, Requires<[HasV4T]>; @@ -2614,10 +2618,10 @@ let isReturn = 1, isTerminator = 1, // if (!Ps) dealloc_return let isReturn = 1, isTerminator = 1, - Defs = [R29, R30, R31, PC], Uses = [R29, R31], neverHasSideEffects = 1, - isPredicated = 1 in { - def DEALLOC_RET_cNotPt_V4 : NVInst_V4<(outs), (ins PredRegs:$src1, - i32imm:$amt1), + Defs = [R29, R30, R31, PC], Uses = [R30], neverHasSideEffects = 1, + isPredicated = 1, isPredicatedFalse = 1 in { +let validSubTargets = HasV4SubT in + def DEALLOC_RET_cNotPt_V4 : LD0Inst<(outs), (ins PredRegs:$src1), "if (!$src1) dealloc_return", []>, Requires<[HasV4T]>; @@ -2625,10 +2629,10 @@ let isReturn = 1, isTerminator = 1, // if (Ps.new) dealloc_return:nt let isReturn = 1, isTerminator = 1, - Defs = [R29, R30, R31, PC], Uses = [R29, R31], neverHasSideEffects = 1, + Defs = [R29, R30, R31, PC], Uses = [R30], neverHasSideEffects = 1, isPredicated = 1 in { - def DEALLOC_RET_cdnPnt_V4 : NVInst_V4<(outs), (ins PredRegs:$src1, - i32imm:$amt1), +let validSubTargets = HasV4SubT in + def DEALLOC_RET_cdnPnt_V4 : LD0Inst<(outs), (ins PredRegs:$src1), "if ($src1.new) dealloc_return:nt", []>, Requires<[HasV4T]>; @@ -2636,10 +2640,10 @@ let isReturn = 1, isTerminator = 1, // if (!Ps.new) dealloc_return:nt let isReturn = 1, isTerminator = 1, - Defs = [R29, R30, R31, PC], Uses = [R29, R31], neverHasSideEffects = 1, - isPredicated = 1 in { - def DEALLOC_RET_cNotdnPnt_V4 : NVInst_V4<(outs), (ins PredRegs:$src1, - i32imm:$amt1), + Defs = [R29, R30, R31, PC], Uses = [R30], neverHasSideEffects = 1, + isPredicated = 1, isPredicatedFalse = 1 in { +let validSubTargets = HasV4SubT in + def DEALLOC_RET_cNotdnPnt_V4 : LD0Inst<(outs), (ins PredRegs:$src1), "if (!$src1.new) dealloc_return:nt", []>, Requires<[HasV4T]>; @@ -2647,21 +2651,21 @@ let isReturn = 1, isTerminator = 1, // if (Ps.new) dealloc_return:t let isReturn = 1, isTerminator = 1, - Defs = [R29, R30, R31, PC], Uses = [R29, R31], neverHasSideEffects = 1, + Defs = [R29, R30, R31, PC], Uses = [R30], neverHasSideEffects = 1, isPredicated = 1 in { - def DEALLOC_RET_cdnPt_V4 : NVInst_V4<(outs), (ins PredRegs:$src1, - i32imm:$amt1), +let validSubTargets = HasV4SubT in + def DEALLOC_RET_cdnPt_V4 : LD0Inst<(outs), (ins PredRegs:$src1), "if ($src1.new) dealloc_return:t", []>, Requires<[HasV4T]>; } -// if (!Ps.new) dealloc_return:nt +// if (!Ps.new) dealloc_return:nt let isReturn = 1, isTerminator = 1, - Defs = [R29, R30, R31, PC], Uses = [R29, R31], neverHasSideEffects = 1, - isPredicated = 1 in { - def DEALLOC_RET_cNotdnPt_V4 : NVInst_V4<(outs), (ins PredRegs:$src1, - i32imm:$amt1), + Defs = [R29, R30, R31, PC], Uses = [R30], neverHasSideEffects = 1, + isPredicated = 1, isPredicatedFalse = 1 in { +let validSubTargets = HasV4SubT in + def DEALLOC_RET_cNotdnPt_V4 : LD0Inst<(outs), (ins PredRegs:$src1), "if (!$src1.new) dealloc_return:t", []>, Requires<[HasV4T]>; @@ -3063,37 +3067,42 @@ def : Pat<(HexagonCONST32_GP tblockaddress:$src1), (TFRI_V4 tblockaddress:$src1)>, Requires<[HasV4T]>; -let AddedComplexity=50, neverHasSideEffects = 1, isPredicated = 1 in +let isExtended = 1, opExtendable = 2, AddedComplexity=50, +neverHasSideEffects = 1, isPredicated = 1, validSubTargets = HasV4SubT in def TFRI_cPt_V4 : ALU32_ri<(outs IntRegs:$dst), - (ins PredRegs:$src1, globaladdress:$src2), - "if($src1) $dst = ##$src2", + (ins PredRegs:$src1, s16Ext:$src2), + "if($src1) $dst = #$src2", []>, Requires<[HasV4T]>; -let AddedComplexity=50, neverHasSideEffects = 1, isPredicated = 1 in +let isExtended = 1, opExtendable = 2, AddedComplexity=50, isPredicatedFalse = 1, +neverHasSideEffects = 1, isPredicated = 1, validSubTargets = HasV4SubT in def TFRI_cNotPt_V4 : ALU32_ri<(outs IntRegs:$dst), - (ins PredRegs:$src1, globaladdress:$src2), - "if(!$src1) $dst = ##$src2", + (ins PredRegs:$src1, s16Ext:$src2), + "if(!$src1) $dst = #$src2", []>, Requires<[HasV4T]>; -let AddedComplexity=50, neverHasSideEffects = 1, isPredicated = 1 in +let isExtended = 1, opExtendable = 2, AddedComplexity=50, +neverHasSideEffects = 1, isPredicated = 1, validSubTargets = HasV4SubT in def TFRI_cdnPt_V4 : ALU32_ri<(outs IntRegs:$dst), - (ins PredRegs:$src1, globaladdress:$src2), - "if($src1.new) $dst = ##$src2", + (ins PredRegs:$src1, s16Ext:$src2), + "if($src1.new) $dst = #$src2", []>, Requires<[HasV4T]>; -let AddedComplexity=50, neverHasSideEffects = 1, isPredicated = 1 in +let isExtended = 1, opExtendable = 2, AddedComplexity=50, isPredicatedFalse = 1, +neverHasSideEffects = 1, isPredicated = 1, validSubTargets = HasV4SubT in def TFRI_cdnNotPt_V4 : ALU32_ri<(outs IntRegs:$dst), - (ins PredRegs:$src1, globaladdress:$src2), - "if(!$src1.new) $dst = ##$src2", + (ins PredRegs:$src1, s16Ext:$src2), + "if(!$src1.new) $dst = #$src2", []>, Requires<[HasV4T]>; let AddedComplexity = 50, Predicates = [HasV4T] in def : Pat<(HexagonCONST32_GP tglobaladdr:$src1), - (TFRI_V4 tglobaladdr:$src1)>; + (TFRI_V4 tglobaladdr:$src1)>, + Requires<[HasV4T]>; // Load - Indirect with long offset: These instructions take global address diff --git a/lib/Target/Hexagon/HexagonInstrInfoV5.td b/lib/Target/Hexagon/HexagonInstrInfoV5.td index 92d098cc04..9da6074558 100644 --- a/lib/Target/Hexagon/HexagonInstrInfoV5.td +++ b/lib/Target/Hexagon/HexagonInstrInfoV5.td @@ -26,22 +26,29 @@ def CONST32_Float_Real : LDInst<(outs IntRegs:$dst), (ins f32imm:$src1), // Only works with single precision fp value. // For double precision, use CONST64_float_real, as 64bit transfer // can only hold 40-bit values - 32 from const ext + 8 bit immediate. -let isMoveImm = 1, isReMaterializable = 1, isPredicable = 1 in -def TFRI_f : ALU32_ri<(outs IntRegs:$dst), (ins f32imm:$src1), - "$dst = ##$src1", +// Make sure that complexity is more than the CONST32 pattern in +// HexagonInstrInfo.td patterns. +let isExtended = 1, opExtendable = 1, isMoveImm = 1, isReMaterializable = 1, +isPredicable = 1, AddedComplexity = 30, validSubTargets = HasV5SubT, +isCodeGenOnly = 1 in +def TFRI_f : ALU32_ri<(outs IntRegs:$dst), (ins f32Ext:$src1), + "$dst = #$src1", [(set IntRegs:$dst, fpimm:$src1)]>, Requires<[HasV5T]>; +let isExtended = 1, opExtendable = 2, isPredicated = 1, +neverHasSideEffects = 1, validSubTargets = HasV5SubT in def TFRI_cPt_f : ALU32_ri<(outs IntRegs:$dst), - (ins PredRegs:$src1, f32imm:$src2), - "if ($src1) $dst = ##$src2", + (ins PredRegs:$src1, f32Ext:$src2), + "if ($src1) $dst = #$src2", []>, Requires<[HasV5T]>; -let isPredicated = 1 in +let isExtended = 1, opExtendable = 2, isPredicated = 1, isPredicatedFalse = 1, +neverHasSideEffects = 1, validSubTargets = HasV5SubT in def TFRI_cNotPt_f : ALU32_ri<(outs IntRegs:$dst), - (ins PredRegs:$src1, f32imm:$src2), - "if (!$src1) $dst = ##$src2", + (ins PredRegs:$src1, f32Ext:$src2), + "if (!$src1) $dst =#$src2", []>, Requires<[HasV5T]>; diff --git a/lib/Target/Hexagon/HexagonRegisterInfo.cpp b/lib/Target/Hexagon/HexagonRegisterInfo.cpp index d8b4e2fcb3..d59d7d3382 100644 --- a/lib/Target/Hexagon/HexagonRegisterInfo.cpp +++ b/lib/Target/Hexagon/HexagonRegisterInfo.cpp @@ -295,16 +295,6 @@ unsigned HexagonRegisterInfo::getStackRegister() const { return Hexagon::R29; } -void HexagonRegisterInfo::getInitialFrameState(std::vector<MachineMove> - &Moves) const -{ - // VirtualFP = (R30 + #0). - unsigned FPReg = getFrameRegister(); - MachineLocation Dst(MachineLocation::VirtualFP); - MachineLocation Src(FPReg, 0); - Moves.push_back(MachineMove(0, Dst, Src)); -} - unsigned HexagonRegisterInfo::getEHExceptionRegister() const { llvm_unreachable("What is the exception register"); } diff --git a/lib/Target/Hexagon/HexagonRegisterInfo.h b/lib/Target/Hexagon/HexagonRegisterInfo.h index 8a3f94a3fd..c74155ac3b 100644 --- a/lib/Target/Hexagon/HexagonRegisterInfo.h +++ b/lib/Target/Hexagon/HexagonRegisterInfo.h @@ -78,7 +78,6 @@ struct HexagonRegisterInfo : public HexagonGenRegisterInfo { unsigned getRARegister() const; unsigned getFrameRegister(const MachineFunction &MF) const; unsigned getFrameRegister() const; - void getInitialFrameState(std::vector<MachineMove> &Moves) const; unsigned getStackRegister() const; // Exception handling queries. diff --git a/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp b/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp index fbe67e3882..c508d124b3 100644 --- a/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp +++ b/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp @@ -164,7 +164,6 @@ namespace { unsigned, std::map <MachineInstr*, SUnit*>); bool isNewifiable(MachineInstr* MI); bool isCondInst(MachineInstr* MI); - bool IsNewifyStore (MachineInstr* MI); bool tryAllocateResourcesForConstExt(MachineInstr* MI); bool canReserveResourcesForConstExt(MachineInstr *MI); void reserveResourcesForConstExt(MachineInstr* MI); @@ -383,104 +382,6 @@ static bool IsControlFlow(MachineInstr* MI) { return (MI->getDesc().isTerminator() || MI->getDesc().isCall()); } -// Function returns true if an instruction can be promoted to the new-value -// store. It will always return false for v2 and v3. -// It lists all the conditional and unconditional stores that can be promoted -// to the new-value stores. - -bool HexagonPacketizerList::IsNewifyStore (MachineInstr* MI) { - const HexagonRegisterInfo* QRI = - (const HexagonRegisterInfo *) TM.getRegisterInfo(); - switch (MI->getOpcode()) - { - // store byte - case Hexagon::STrib: - case Hexagon::STrib_indexed: - case Hexagon::STrib_indexed_shl_V4: - case Hexagon::STrib_shl_V4: - case Hexagon::STb_GP_V4: - case Hexagon::POST_STbri: - case Hexagon::STrib_cPt: - case Hexagon::STrib_cdnPt_V4: - case Hexagon::STrib_cNotPt: - case Hexagon::STrib_cdnNotPt_V4: - case Hexagon::STrib_indexed_cPt: - case Hexagon::STrib_indexed_cdnPt_V4: - case Hexagon::STrib_indexed_cNotPt: - case Hexagon::STrib_indexed_cdnNotPt_V4: - case Hexagon::STrib_indexed_shl_cPt_V4: - case Hexagon::STrib_indexed_shl_cdnPt_V4: - case Hexagon::STrib_indexed_shl_cNotPt_V4: - case Hexagon::STrib_indexed_shl_cdnNotPt_V4: - case Hexagon::POST_STbri_cPt: - case Hexagon::POST_STbri_cdnPt_V4: - case Hexagon::POST_STbri_cNotPt: - case Hexagon::POST_STbri_cdnNotPt_V4: - case Hexagon::STb_GP_cPt_V4: - case Hexagon::STb_GP_cNotPt_V4: - case Hexagon::STb_GP_cdnPt_V4: - case Hexagon::STb_GP_cdnNotPt_V4: - - // store halfword - case Hexagon::STrih: - case Hexagon::STrih_indexed: - case Hexagon::STrih_indexed_shl_V4: - case Hexagon::STrih_shl_V4: - case Hexagon::STh_GP_V4: - case Hexagon::POST_SThri: - case Hexagon::STrih_cPt: - case Hexagon::STrih_cdnPt_V4: - case Hexagon::STrih_cNotPt: - case Hexagon::STrih_cdnNotPt_V4: - case Hexagon::STrih_indexed_cPt: - case Hexagon::STrih_indexed_cdnPt_V4: - case Hexagon::STrih_indexed_cNotPt: - case Hexagon::STrih_indexed_cdnNotPt_V4: - case Hexagon::STrih_indexed_shl_cPt_V4: - case Hexagon::STrih_indexed_shl_cdnPt_V4: - case Hexagon::STrih_indexed_shl_cNotPt_V4: - case Hexagon::STrih_indexed_shl_cdnNotPt_V4: - case Hexagon::POST_SThri_cPt: - case Hexagon::POST_SThri_cdnPt_V4: - case Hexagon::POST_SThri_cNotPt: - case Hexagon::POST_SThri_cdnNotPt_V4: - case Hexagon::STh_GP_cPt_V4: - case Hexagon::STh_GP_cNotPt_V4: - case Hexagon::STh_GP_cdnPt_V4: - case Hexagon::STh_GP_cdnNotPt_V4: - - // store word - case Hexagon::STriw: - case Hexagon::STriw_indexed: - case Hexagon::STriw_indexed_shl_V4: - case Hexagon::STriw_shl_V4: - case Hexagon::STw_GP_V4: - case Hexagon::POST_STwri: - case Hexagon::STriw_cPt: - case Hexagon::STriw_cdnPt_V4: - case Hexagon::STriw_cNotPt: - case Hexagon::STriw_cdnNotPt_V4: - case Hexagon::STriw_indexed_cPt: - case Hexagon::STriw_indexed_cdnPt_V4: - case Hexagon::STriw_indexed_cNotPt: - case Hexagon::STriw_indexed_cdnNotPt_V4: - case Hexagon::STriw_indexed_shl_cPt_V4: - case Hexagon::STriw_indexed_shl_cdnPt_V4: - case Hexagon::STriw_indexed_shl_cNotPt_V4: - case Hexagon::STriw_indexed_shl_cdnNotPt_V4: - case Hexagon::POST_STwri_cPt: - case Hexagon::POST_STwri_cdnPt_V4: - case Hexagon::POST_STwri_cNotPt: - case Hexagon::POST_STwri_cdnNotPt_V4: - case Hexagon::STw_GP_cPt_V4: - case Hexagon::STw_GP_cNotPt_V4: - case Hexagon::STw_GP_cdnPt_V4: - case Hexagon::STw_GP_cdnNotPt_V4: - return QRI->Subtarget.hasV4TOps(); - } - return false; -} - static bool IsLoopN(MachineInstr *MI) { return (MI->getOpcode() == Hexagon::LOOP0_i || MI->getOpcode() == Hexagon::LOOP0_r); @@ -498,254 +399,11 @@ static bool DoesModifyCalleeSavedReg(MachineInstr *MI, return false; } -// Return the new value instruction for a given store. -static int GetDotNewOp(const int opc) { - switch (opc) { - default: llvm_unreachable("Unknown .new type"); - // store new value byte - case Hexagon::STrib: - return Hexagon::STrib_nv_V4; - - case Hexagon::STrib_indexed: - return Hexagon::STrib_indexed_nv_V4; - - case Hexagon::STrib_indexed_shl_V4: - return Hexagon::STrib_indexed_shl_nv_V4; - - case Hexagon::STrib_shl_V4: - return Hexagon::STrib_shl_nv_V4; - - case Hexagon::STb_GP_V4: - return Hexagon::STb_GP_nv_V4; - - case Hexagon::POST_STbri: - return Hexagon::POST_STbri_nv_V4; - - case Hexagon::STrib_cPt: - return Hexagon::STrib_cPt_nv_V4; - - case Hexagon::STrib_cdnPt_V4: - return Hexagon::STrib_cdnPt_nv_V4; - - case Hexagon::STrib_cNotPt: - return Hexagon::STrib_cNotPt_nv_V4; - - case Hexagon::STrib_cdnNotPt_V4: - return Hexagon::STrib_cdnNotPt_nv_V4; - - case Hexagon::STrib_indexed_cPt: - return Hexagon::STrib_indexed_cPt_nv_V4; - - case Hexagon::STrib_indexed_cdnPt_V4: - return Hexagon::STrib_indexed_cdnPt_nv_V4; - - case Hexagon::STrib_indexed_cNotPt: - return Hexagon::STrib_indexed_cNotPt_nv_V4; - - case Hexagon::STrib_indexed_cdnNotPt_V4: - return Hexagon::STrib_indexed_cdnNotPt_nv_V4; - - case Hexagon::STrib_indexed_shl_cPt_V4: - return Hexagon::STrib_indexed_shl_cPt_nv_V4; - - case Hexagon::STrib_indexed_shl_cdnPt_V4: - return Hexagon::STrib_indexed_shl_cdnPt_nv_V4; - - case Hexagon::STrib_indexed_shl_cNotPt_V4: - return Hexagon::STrib_indexed_shl_cNotPt_nv_V4; - - case Hexagon::STrib_indexed_shl_cdnNotPt_V4: - return Hexagon::STrib_indexed_shl_cdnNotPt_nv_V4; - - case Hexagon::POST_STbri_cPt: - return Hexagon::POST_STbri_cPt_nv_V4; - - case Hexagon::POST_STbri_cdnPt_V4: - return Hexagon::POST_STbri_cdnPt_nv_V4; - - case Hexagon::POST_STbri_cNotPt: - return Hexagon::POST_STbri_cNotPt_nv_V4; - - case Hexagon::POST_STbri_cdnNotPt_V4: - return Hexagon::POST_STbri_cdnNotPt_nv_V4; - - case Hexagon::STb_GP_cPt_V4: - return Hexagon::STb_GP_cPt_nv_V4; - - case Hexagon::STb_GP_cNotPt_V4: - return Hexagon::STb_GP_cNotPt_nv_V4; - - case Hexagon::STb_GP_cdnPt_V4: - return Hexagon::STb_GP_cdnPt_nv_V4; - - case Hexagon::STb_GP_cdnNotPt_V4: - return Hexagon::STb_GP_cdnNotPt_nv_V4; - - // store new value halfword - case Hexagon::STrih: - return Hexagon::STrih_nv_V4; - - case Hexagon::STrih_indexed: - return Hexagon::STrih_indexed_nv_V4; - - case Hexagon::STrih_indexed_shl_V4: - return Hexagon::STrih_indexed_shl_nv_V4; - - case Hexagon::STrih_shl_V4: - return Hexagon::STrih_shl_nv_V4; - - case Hexagon::STh_GP_V4: - return Hexagon::STh_GP_nv_V4; - - case Hexagon::POST_SThri: - return Hexagon::POST_SThri_nv_V4; - - case Hexagon::STrih_cPt: - return Hexagon::STrih_cPt_nv_V4; - - case Hexagon::STrih_cdnPt_V4: - return Hexagon::STrih_cdnPt_nv_V4; - - case Hexagon::STrih_cNotPt: - return Hexagon::STrih_cNotPt_nv_V4; - - case Hexagon::STrih_cdnNotPt_V4: - return Hexagon::STrih_cdnNotPt_nv_V4; - - case Hexagon::STrih_indexed_cPt: - return Hexagon::STrih_indexed_cPt_nv_V4; - - case Hexagon::STrih_indexed_cdnPt_V4: - return Hexagon::STrih_indexed_cdnPt_nv_V4; - - case Hexagon::STrih_indexed_cNotPt: - return Hexagon::STrih_indexed_cNotPt_nv_V4; - - case Hexagon::STrih_indexed_cdnNotPt_V4: - return Hexagon::STrih_indexed_cdnNotPt_nv_V4; - - case Hexagon::STrih_indexed_shl_cPt_V4: - return Hexagon::STrih_indexed_shl_cPt_nv_V4; - - case Hexagon::STrih_indexed_shl_cdnPt_V4: - return Hexagon::STrih_indexed_shl_cdnPt_nv_V4; - - case Hexagon::STrih_indexed_shl_cNotPt_V4: - return Hexagon::STrih_indexed_shl_cNotPt_nv_V4; - - case Hexagon::STrih_indexed_shl_cdnNotPt_V4: - return Hexagon::STrih_indexed_shl_cdnNotPt_nv_V4; - - case Hexagon::POST_SThri_cPt: - return Hexagon::POST_SThri_cPt_nv_V4; - - case Hexagon::POST_SThri_cdnPt_V4: - return Hexagon::POST_SThri_cdnPt_nv_V4; - - case Hexagon::POST_SThri_cNotPt: - return Hexagon::POST_SThri_cNotPt_nv_V4; - - case Hexagon::POST_SThri_cdnNotPt_V4: - return Hexagon::POST_SThri_cdnNotPt_nv_V4; - - case Hexagon::STh_GP_cPt_V4: - return Hexagon::STh_GP_cPt_nv_V4; - - case Hexagon::STh_GP_cNotPt_V4: - return Hexagon::STh_GP_cNotPt_nv_V4; - - case Hexagon::STh_GP_cdnPt_V4: - return Hexagon::STh_GP_cdnPt_nv_V4; - - case Hexagon::STh_GP_cdnNotPt_V4: - return Hexagon::STh_GP_cdnNotPt_nv_V4; - - // store new value word - case Hexagon::STriw: - return Hexagon::STriw_nv_V4; - - case Hexagon::STriw_indexed: - return Hexagon::STriw_indexed_nv_V4; - - case Hexagon::STriw_indexed_shl_V4: - return Hexagon::STriw_indexed_shl_nv_V4; - - case Hexagon::STriw_shl_V4: - return Hexagon::STriw_shl_nv_V4; - - case Hexagon::STw_GP_V4: - return Hexagon::STw_GP_nv_V4; - - case Hexagon::POST_STwri: - return Hexagon::POST_STwri_nv_V4; - - case Hexagon::STriw_cPt: - return Hexagon::STriw_cPt_nv_V4; - - case Hexagon::STriw_cdnPt_V4: - return Hexagon::STriw_cdnPt_nv_V4; - - case Hexagon::STriw_cNotPt: - return Hexagon::STriw_cNotPt_nv_V4; - - case Hexagon::STriw_cdnNotPt_V4: - return Hexagon::STriw_cdnNotPt_nv_V4; - - case Hexagon::STriw_indexed_cPt: - return Hexagon::STriw_indexed_cPt_nv_V4; - - case Hexagon::STriw_indexed_cdnPt_V4: - return Hexagon::STriw_indexed_cdnPt_nv_V4; - - case Hexagon::STriw_indexed_cNotPt: - return Hexagon::STriw_indexed_cNotPt_nv_V4; - - case Hexagon::STriw_indexed_cdnNotPt_V4: - return Hexagon::STriw_indexed_cdnNotPt_nv_V4; - - case Hexagon::STriw_indexed_shl_cPt_V4: - return Hexagon::STriw_indexed_shl_cPt_nv_V4; - - case Hexagon::STriw_indexed_shl_cdnPt_V4: - return Hexagon::STriw_indexed_shl_cdnPt_nv_V4; - - case Hexagon::STriw_indexed_shl_cNotPt_V4: - return Hexagon::STriw_indexed_shl_cNotPt_nv_V4; - - case Hexagon::STriw_indexed_shl_cdnNotPt_V4: - return Hexagon::STriw_indexed_shl_cdnNotPt_nv_V4; - - case Hexagon::POST_STwri_cPt: - return Hexagon::POST_STwri_cPt_nv_V4; - - case Hexagon::POST_STwri_cdnPt_V4: - return Hexagon::POST_STwri_cdnPt_nv_V4; - - case Hexagon::POST_STwri_cNotPt: - return Hexagon::POST_STwri_cNotPt_nv_V4; - - case Hexagon::POST_STwri_cdnNotPt_V4: - return Hexagon::POST_STwri_cdnNotPt_nv_V4; - - case Hexagon::STw_GP_cPt_V4: - return Hexagon::STw_GP_cPt_nv_V4; - - case Hexagon::STw_GP_cNotPt_V4: - return Hexagon::STw_GP_cNotPt_nv_V4; - - case Hexagon::STw_GP_cdnPt_V4: - return Hexagon::STw_GP_cdnPt_nv_V4; - - case Hexagon::STw_GP_cdnNotPt_V4: - return Hexagon::STw_GP_cdnNotPt_nv_V4; - - } -} - // Returns true if an instruction can be promoted to .new predicate // or new-value store. bool HexagonPacketizerList::isNewifiable(MachineInstr* MI) { - if ( isCondInst(MI) || IsNewifyStore(MI)) + const HexagonInstrInfo *QII = (const HexagonInstrInfo *) TII; + if ( isCondInst(MI) || QII->mayBeNewStore(MI)) return true; else return false; @@ -781,894 +439,36 @@ bool HexagonPacketizerList::PromoteToDotNew(MachineInstr* MI, if (RC == &Hexagon::PredRegsRegClass) NewOpcode = QII->GetDotNewPredOp(MI, MBPI); else - NewOpcode = GetDotNewOp(MI->getOpcode()); + NewOpcode = QII->GetDotNewOp(MI); MI->setDesc(QII->get(NewOpcode)); return true; } -// Returns the most basic instruction for the .new predicated instructions and -// new-value stores. -// For example, all of the following instructions will be converted back to the -// same instruction: -// 1) if (p0.new) memw(R0+#0) = R1.new ---> -// 2) if (p0) memw(R0+#0)= R1.new -------> if (p0) memw(R0+#0) = R1 -// 3) if (p0.new) memw(R0+#0) = R1 ---> -// -// To understand the translation of instruction 1 to its original form, consider -// a packet with 3 instructions. -// { p0 = cmp.eq(R0,R1) -// if (p0.new) R2 = add(R3, R4) -// R5 = add (R3, R1) -// } -// if (p0) memw(R5+#0) = R2 <--- trying to include it in the previous packet -// -// This instruction can be part of the previous packet only if both p0 and R2 -// are promoted to .new values. This promotion happens in steps, first -// predicate register is promoted to .new and in the next iteration R2 is -// promoted. Therefore, in case of dependence check failure (due to R5) during -// next iteration, it should be converted back to its most basic form. - -static int GetDotOldOp(const int opc) { - switch (opc) { - default: llvm_unreachable("Unknown .old type"); - case Hexagon::TFR_cdnPt: - return Hexagon::TFR_cPt; - - case Hexagon::TFR_cdnNotPt: - return Hexagon::TFR_cNotPt; - - case Hexagon::TFRI_cdnPt: - return Hexagon::TFRI_cPt; - - case Hexagon::TFRI_cdnNotPt: - return Hexagon::TFRI_cNotPt; - - case Hexagon::JMP_tnew_t: - return Hexagon::JMP_t; - - case Hexagon::JMP_fnew_t: - return Hexagon::JMP_f; - - case Hexagon::JMPR_tnew_tV3: - return Hexagon::JMPR_t; - - case Hexagon::JMPR_fnew_tV3: - return Hexagon::JMPR_f; - - // Load double word - - case Hexagon::LDrid_cdnPt : - return Hexagon::LDrid_cPt; - - case Hexagon::LDrid_cdnNotPt : - return Hexagon::LDrid_cNotPt; - - case Hexagon::LDrid_indexed_cdnPt : - return Hexagon::LDrid_indexed_cPt; - - case Hexagon::LDrid_indexed_cdnNotPt : - return Hexagon::LDrid_indexed_cNotPt; - - case Hexagon::POST_LDrid_cdnPt_V4 : - return Hexagon::POST_LDrid_cPt; - - case Hexagon::POST_LDrid_cdnNotPt_V4 : - return Hexagon::POST_LDrid_cNotPt; - - // Load word - - case Hexagon::LDriw_cdnPt : - return Hexagon::LDriw_cPt; - - case Hexagon::LDriw_cdnNotPt : - return Hexagon::LDriw_cNotPt; - - case Hexagon::LDriw_indexed_cdnPt : - return Hexagon::LDriw_indexed_cPt; - - case Hexagon::LDriw_indexed_cdnNotPt : - return Hexagon::LDriw_indexed_cNotPt; - - case Hexagon::POST_LDriw_cdnPt_V4 : - return Hexagon::POST_LDriw_cPt; - - case Hexagon::POST_LDriw_cdnNotPt_V4 : - return Hexagon::POST_LDriw_cNotPt; - - // Load half - - case Hexagon::LDrih_cdnPt : - return Hexagon::LDrih_cPt; - - case Hexagon::LDrih_cdnNotPt : - return Hexagon::LDrih_cNotPt; - - case Hexagon::LDrih_indexed_cdnPt : - return Hexagon::LDrih_indexed_cPt; - - case Hexagon::LDrih_indexed_cdnNotPt : - return Hexagon::LDrih_indexed_cNotPt; - - case Hexagon::POST_LDrih_cdnPt_V4 : - return Hexagon::POST_LDrih_cPt; - - case Hexagon::POST_LDrih_cdnNotPt_V4 : - return Hexagon::POST_LDrih_cNotPt; - - // Load byte - - case Hexagon::LDrib_cdnPt : - return Hexagon::LDrib_cPt; - - case Hexagon::LDrib_cdnNotPt : - return Hexagon::LDrib_cNotPt; - - case Hexagon::LDrib_indexed_cdnPt : - return Hexagon::LDrib_indexed_cPt; - - case Hexagon::LDrib_indexed_cdnNotPt : - return Hexagon::LDrib_indexed_cNotPt; - - case Hexagon::POST_LDrib_cdnPt_V4 : - return Hexagon::POST_LDrib_cPt; - - case Hexagon::POST_LDrib_cdnNotPt_V4 : - return Hexagon::POST_LDrib_cNotPt; - - // Load unsigned half - - case Hexagon::LDriuh_cdnPt : - return Hexagon::LDriuh_cPt; - - case Hexagon::LDriuh_cdnNotPt : - return Hexagon::LDriuh_cNotPt; - - case Hexagon::LDriuh_indexed_cdnPt : - return Hexagon::LDriuh_indexed_cPt; - - case Hexagon::LDriuh_indexed_cdnNotPt : - return Hexagon::LDriuh_indexed_cNotPt; - - case Hexagon::POST_LDriuh_cdnPt_V4 : - return Hexagon::POST_LDriuh_cPt; - - case Hexagon::POST_LDriuh_cdnNotPt_V4 : - return Hexagon::POST_LDriuh_cNotPt; - - // Load unsigned byte - case Hexagon::LDriub_cdnPt : - return Hexagon::LDriub_cPt; - - case Hexagon::LDriub_cdnNotPt : - return Hexagon::LDriub_cNotPt; - - case Hexagon::LDriub_indexed_cdnPt : - return Hexagon::LDriub_indexed_cPt; - - case Hexagon::LDriub_indexed_cdnNotPt : - return Hexagon::LDriub_indexed_cNotPt; - - case Hexagon::POST_LDriub_cdnPt_V4 : - return Hexagon::POST_LDriub_cPt; - - case Hexagon::POST_LDriub_cdnNotPt_V4 : - return Hexagon::POST_LDriub_cNotPt; - - // V4 indexed+scaled Load - - case Hexagon::LDrid_indexed_shl_cdnPt_V4 : - return Hexagon::LDrid_indexed_shl_cPt_V4; - - case Hexagon::LDrid_indexed_shl_cdnNotPt_V4 : - return Hexagon::LDrid_indexed_shl_cNotPt_V4; - - case Hexagon::LDrib_indexed_shl_cdnPt_V4 : - return Hexagon::LDrib_indexed_shl_cPt_V4; - - case Hexagon::LDrib_indexed_shl_cdnNotPt_V4 : - return Hexagon::LDrib_indexed_shl_cNotPt_V4; - - case Hexagon::LDriub_indexed_shl_cdnPt_V4 : - return Hexagon::LDriub_indexed_shl_cPt_V4; - - case Hexagon::LDriub_indexed_shl_cdnNotPt_V4 : - return Hexagon::LDriub_indexed_shl_cNotPt_V4; - - case Hexagon::LDrih_indexed_shl_cdnPt_V4 : - return Hexagon::LDrih_indexed_shl_cPt_V4; - - case Hexagon::LDrih_indexed_shl_cdnNotPt_V4 : - return Hexagon::LDrih_indexed_shl_cNotPt_V4; - - case Hexagon::LDriuh_indexed_shl_cdnPt_V4 : - return Hexagon::LDriuh_indexed_shl_cPt_V4; - - case Hexagon::LDriuh_indexed_shl_cdnNotPt_V4 : - return Hexagon::LDriuh_indexed_shl_cNotPt_V4; - - case Hexagon::LDriw_indexed_shl_cdnPt_V4 : - return Hexagon::LDriw_indexed_shl_cPt_V4; - - case Hexagon::LDriw_indexed_shl_cdnNotPt_V4 : - return Hexagon::LDriw_indexed_shl_cNotPt_V4; - - // V4 global address load - - case Hexagon::LDd_GP_cdnPt_V4: - return Hexagon::LDd_GP_cPt_V4; - - case Hexagon::LDd_GP_cdnNotPt_V4: - return Hexagon::LDd_GP_cNotPt_V4; - - case Hexagon::LDb_GP_cdnPt_V4: - return Hexagon::LDb_GP_cPt_V4; - - case Hexagon::LDb_GP_cdnNotPt_V4: - return Hexagon::LDb_GP_cNotPt_V4; - - case Hexagon::LDub_GP_cdnPt_V4: - return Hexagon::LDub_GP_cPt_V4; - - case Hexagon::LDub_GP_cdnNotPt_V4: - return Hexagon::LDub_GP_cNotPt_V4; - - case Hexagon::LDh_GP_cdnPt_V4: - return Hexagon::LDh_GP_cPt_V4; - - case Hexagon::LDh_GP_cdnNotPt_V4: - return Hexagon::LDh_GP_cNotPt_V4; - - case Hexagon::LDuh_GP_cdnPt_V4: - return Hexagon::LDuh_GP_cPt_V4; - - case Hexagon::LDuh_GP_cdnNotPt_V4: - return Hexagon::LDuh_GP_cNotPt_V4; - - case Hexagon::LDw_GP_cdnPt_V4: - return Hexagon::LDw_GP_cPt_V4; - - case Hexagon::LDw_GP_cdnNotPt_V4: - return Hexagon::LDw_GP_cNotPt_V4; - - // Conditional add - - case Hexagon::ADD_ri_cdnPt : - return Hexagon::ADD_ri_cPt; - case Hexagon::ADD_ri_cdnNotPt : - return Hexagon::ADD_ri_cNotPt; - - case Hexagon::ADD_rr_cdnPt : - return Hexagon::ADD_rr_cPt; - case Hexagon::ADD_rr_cdnNotPt: - return Hexagon::ADD_rr_cNotPt; - - // Conditional logical Operations - - case Hexagon::XOR_rr_cdnPt : - return Hexagon::XOR_rr_cPt; - case Hexagon::XOR_rr_cdnNotPt : - return Hexagon::XOR_rr_cNotPt; - - case Hexagon::AND_rr_cdnPt : - return Hexagon::AND_rr_cPt; - case Hexagon::AND_rr_cdnNotPt : - return Hexagon::AND_rr_cNotPt; - - case Hexagon::OR_rr_cdnPt : - return Hexagon::OR_rr_cPt; - case Hexagon::OR_rr_cdnNotPt : - return Hexagon::OR_rr_cNotPt; - - // Conditional Subtract - - case Hexagon::SUB_rr_cdnPt : - return Hexagon::SUB_rr_cPt; - case Hexagon::SUB_rr_cdnNotPt : - return Hexagon::SUB_rr_cNotPt; - - // Conditional combine - - case Hexagon::COMBINE_rr_cdnPt : - return Hexagon::COMBINE_rr_cPt; - case Hexagon::COMBINE_rr_cdnNotPt : - return Hexagon::COMBINE_rr_cNotPt; - -// Conditional shift operations - - case Hexagon::ASLH_cdnPt_V4 : - return Hexagon::ASLH_cPt_V4; - case Hexagon::ASLH_cdnNotPt_V4 : - return Hexagon::ASLH_cNotPt_V4; - - case Hexagon::ASRH_cdnPt_V4 : - return Hexagon::ASRH_cPt_V4; - case Hexagon::ASRH_cdnNotPt_V4 : - return Hexagon::ASRH_cNotPt_V4; - - case Hexagon::SXTB_cdnPt_V4 : - return Hexagon::SXTB_cPt_V4; - case Hexagon::SXTB_cdnNotPt_V4 : - return Hexagon::SXTB_cNotPt_V4; - - case Hexagon::SXTH_cdnPt_V4 : - return Hexagon::SXTH_cPt_V4; - case Hexagon::SXTH_cdnNotPt_V4 : - return Hexagon::SXTH_cNotPt_V4; - - case Hexagon::ZXTB_cdnPt_V4 : - return Hexagon::ZXTB_cPt_V4; - case Hexagon::ZXTB_cdnNotPt_V4 : - return Hexagon::ZXTB_cNotPt_V4; - - case Hexagon::ZXTH_cdnPt_V4 : - return Hexagon::ZXTH_cPt_V4; - case Hexagon::ZXTH_cdnNotPt_V4 : - return Hexagon::ZXTH_cNotPt_V4; - - // Store byte - - case Hexagon::STrib_imm_cdnPt_V4 : - return Hexagon::STrib_imm_cPt_V4; - - case Hexagon::STrib_imm_cdnNotPt_V4 : - return Hexagon::STrib_imm_cNotPt_V4; - - case Hexagon::STrib_cdnPt_nv_V4 : - case Hexagon::STrib_cPt_nv_V4 : - case Hexagon::STrib_cdnPt_V4 : - return Hexagon::STrib_cPt; - - case Hexagon::STrib_cdnNotPt_nv_V4 : - case Hexagon::STrib_cNotPt_nv_V4 : - case Hexagon::STrib_cdnNotPt_V4 : - return Hexagon::STrib_cNotPt; - - case Hexagon::STrib_indexed_cdnPt_V4 : - case Hexagon::STrib_indexed_cPt_nv_V4 : - case Hexagon::STrib_indexed_cdnPt_nv_V4 : - return Hexagon::STrib_indexed_cPt; - - case Hexagon::STrib_indexed_cdnNotPt_V4 : - case Hexagon::STrib_indexed_cNotPt_nv_V4 : - case Hexagon::STrib_indexed_cdnNotPt_nv_V4 : - return Hexagon::STrib_indexed_cNotPt; - - case Hexagon::STrib_indexed_shl_cdnPt_nv_V4: - case Hexagon::STrib_indexed_shl_cPt_nv_V4 : - case Hexagon::STrib_indexed_shl_cdnPt_V4 : - return Hexagon::STrib_indexed_shl_cPt_V4; - - case Hexagon::STrib_indexed_shl_cdnNotPt_nv_V4: - case Hexagon::STrib_indexed_shl_cNotPt_nv_V4 : - case Hexagon::STrib_indexed_shl_cdnNotPt_V4 : - return Hexagon::STrib_indexed_shl_cNotPt_V4; - - case Hexagon::POST_STbri_cdnPt_nv_V4 : - case Hexagon::POST_STbri_cPt_nv_V4 : - case Hexagon::POST_STbri_cdnPt_V4 : - return Hexagon::POST_STbri_cPt; - - case Hexagon::POST_STbri_cdnNotPt_nv_V4 : - case Hexagon::POST_STbri_cNotPt_nv_V4: - case Hexagon::POST_STbri_cdnNotPt_V4 : - return Hexagon::POST_STbri_cNotPt; - - case Hexagon::STb_GP_cdnPt_nv_V4: - case Hexagon::STb_GP_cdnPt_V4: - case Hexagon::STb_GP_cPt_nv_V4: - return Hexagon::STb_GP_cPt_V4; - - case Hexagon::STb_GP_cdnNotPt_nv_V4: - case Hexagon::STb_GP_cdnNotPt_V4: - case Hexagon::STb_GP_cNotPt_nv_V4: - return Hexagon::STb_GP_cNotPt_V4; - - // Store new-value byte - unconditional - case Hexagon::STrib_nv_V4: - return Hexagon::STrib; - - case Hexagon::STrib_indexed_nv_V4: - return Hexagon::STrib_indexed; - - case Hexagon::STrib_indexed_shl_nv_V4: - return Hexagon::STrib_indexed_shl_V4; - - case Hexagon::STrib_shl_nv_V4: - return Hexagon::STrib_shl_V4; - - case Hexagon::STb_GP_nv_V4: - return Hexagon::STb_GP_V4; - - case Hexagon::POST_STbri_nv_V4: - return Hexagon::POST_STbri; - - // Store halfword - case Hexagon::STrih_imm_cdnPt_V4 : - return Hexagon::STrih_imm_cPt_V4; - - case Hexagon::STrih_imm_cdnNotPt_V4 : - return Hexagon::STrih_imm_cNotPt_V4; - - case Hexagon::STrih_cdnPt_nv_V4 : - case Hexagon::STrih_cPt_nv_V4 : - case Hexagon::STrih_cdnPt_V4 : - return Hexagon::STrih_cPt; - - case Hexagon::STrih_cdnNotPt_nv_V4 : - case Hexagon::STrih_cNotPt_nv_V4 : - case Hexagon::STrih_cdnNotPt_V4 : - return Hexagon::STrih_cNotPt; - - case Hexagon::STrih_indexed_cdnPt_nv_V4: - case Hexagon::STrih_indexed_cPt_nv_V4 : - case Hexagon::STrih_indexed_cdnPt_V4 : - return Hexagon::STrih_indexed_cPt; - - case Hexagon::STrih_indexed_cdnNotPt_nv_V4: - case Hexagon::STrih_indexed_cNotPt_nv_V4 : - case Hexagon::STrih_indexed_cdnNotPt_V4 : - return Hexagon::STrih_indexed_cNotPt; - - case Hexagon::STrih_indexed_shl_cdnPt_nv_V4 : - case Hexagon::STrih_indexed_shl_cPt_nv_V4 : - case Hexagon::STrih_indexed_shl_cdnPt_V4 : - return Hexagon::STrih_indexed_shl_cPt_V4; - - case Hexagon::STrih_indexed_shl_cdnNotPt_nv_V4 : - case Hexagon::STrih_indexed_shl_cNotPt_nv_V4 : - case Hexagon::STrih_indexed_shl_cdnNotPt_V4 : - return Hexagon::STrih_indexed_shl_cNotPt_V4; - - case Hexagon::POST_SThri_cdnPt_nv_V4 : - case Hexagon::POST_SThri_cPt_nv_V4 : - case Hexagon::POST_SThri_cdnPt_V4 : - return Hexagon::POST_SThri_cPt; - - case Hexagon::POST_SThri_cdnNotPt_nv_V4 : - case Hexagon::POST_SThri_cNotPt_nv_V4 : - case Hexagon::POST_SThri_cdnNotPt_V4 : - return Hexagon::POST_SThri_cNotPt; - - case Hexagon::STh_GP_cdnPt_nv_V4: - case Hexagon::STh_GP_cdnPt_V4: - case Hexagon::STh_GP_cPt_nv_V4: - return Hexagon::STh_GP_cPt_V4; - - case Hexagon::STh_GP_cdnNotPt_nv_V4: - case Hexagon::STh_GP_cdnNotPt_V4: - case Hexagon::STh_GP_cNotPt_nv_V4: - return Hexagon::STh_GP_cNotPt_V4; - - // Store new-value halfword - unconditional - - case Hexagon::STrih_nv_V4: - return Hexagon::STrih; - - case Hexagon::STrih_indexed_nv_V4: - return Hexagon::STrih_indexed; - - case Hexagon::STrih_indexed_shl_nv_V4: - return Hexagon::STrih_indexed_shl_V4; - - case Hexagon::STrih_shl_nv_V4: - return Hexagon::STrih_shl_V4; - - case Hexagon::STh_GP_nv_V4: - return Hexagon::STh_GP_V4; - - case Hexagon::POST_SThri_nv_V4: - return Hexagon::POST_SThri; - - // Store word - - case Hexagon::STriw_imm_cdnPt_V4 : - return Hexagon::STriw_imm_cPt_V4; - - case Hexagon::STriw_imm_cdnNotPt_V4 : - return Hexagon::STriw_imm_cNotPt_V4; - - case Hexagon::STriw_cdnPt_nv_V4 : - case Hexagon::STriw_cPt_nv_V4 : - case Hexagon::STriw_cdnPt_V4 : - return Hexagon::STriw_cPt; - - case Hexagon::STriw_cdnNotPt_nv_V4 : - case Hexagon::STriw_cNotPt_nv_V4 : - case Hexagon::STriw_cdnNotPt_V4 : - return Hexagon::STriw_cNotPt; - - case Hexagon::STriw_indexed_cdnPt_nv_V4 : - case Hexagon::STriw_indexed_cPt_nv_V4 : - case Hexagon::STriw_indexed_cdnPt_V4 : - return Hexagon::STriw_indexed_cPt; - - case Hexagon::STriw_indexed_cdnNotPt_nv_V4 : - case Hexagon::STriw_indexed_cNotPt_nv_V4 : - case Hexagon::STriw_indexed_cdnNotPt_V4 : - return Hexagon::STriw_indexed_cNotPt; - - case Hexagon::STriw_indexed_shl_cdnPt_nv_V4 : - case Hexagon::STriw_indexed_shl_cPt_nv_V4 : - case Hexagon::STriw_indexed_shl_cdnPt_V4 : - return Hexagon::STriw_indexed_shl_cPt_V4; - - case Hexagon::STriw_indexed_shl_cdnNotPt_nv_V4 : - case Hexagon::STriw_indexed_shl_cNotPt_nv_V4 : - case Hexagon::STriw_indexed_shl_cdnNotPt_V4 : - return Hexagon::STriw_indexed_shl_cNotPt_V4; - - case Hexagon::POST_STwri_cdnPt_nv_V4 : - case Hexagon::POST_STwri_cPt_nv_V4 : - case Hexagon::POST_STwri_cdnPt_V4 : - return Hexagon::POST_STwri_cPt; - - case Hexagon::POST_STwri_cdnNotPt_nv_V4 : - case Hexagon::POST_STwri_cNotPt_nv_V4 : - case Hexagon::POST_STwri_cdnNotPt_V4 : - return Hexagon::POST_STwri_cNotPt; - - case Hexagon::STw_GP_cdnPt_nv_V4: - case Hexagon::STw_GP_cdnPt_V4: - case Hexagon::STw_GP_cPt_nv_V4: - return Hexagon::STw_GP_cPt_V4; - - case Hexagon::STw_GP_cdnNotPt_nv_V4: - case Hexagon::STw_GP_cdnNotPt_V4: - case Hexagon::STw_GP_cNotPt_nv_V4: - return Hexagon::STw_GP_cNotPt_V4; - - // Store new-value word - unconditional - - case Hexagon::STriw_nv_V4: - return Hexagon::STriw; - - case Hexagon::STriw_indexed_nv_V4: - return Hexagon::STriw_indexed; - - case Hexagon::STriw_indexed_shl_nv_V4: - return Hexagon::STriw_indexed_shl_V4; - - case Hexagon::STriw_shl_nv_V4: - return Hexagon::STriw_shl_V4; - - case Hexagon::STw_GP_nv_V4: - return Hexagon::STw_GP_V4; - - case Hexagon::POST_STwri_nv_V4: - return Hexagon::POST_STwri; - - // Store doubleword - - case Hexagon::STrid_cdnPt_V4 : - return Hexagon::STrid_cPt; - - case Hexagon::STrid_cdnNotPt_V4 : - return Hexagon::STrid_cNotPt; - - case Hexagon::STrid_indexed_cdnPt_V4 : - return Hexagon::STrid_indexed_cPt; - - case Hexagon::STrid_indexed_cdnNotPt_V4 : - return Hexagon::STrid_indexed_cNotPt; - - case Hexagon::STrid_indexed_shl_cdnPt_V4 : - return Hexagon::STrid_indexed_shl_cPt_V4; - - case Hexagon::STrid_indexed_shl_cdnNotPt_V4 : - return Hexagon::STrid_indexed_shl_cNotPt_V4; - - case Hexagon::POST_STdri_cdnPt_V4 : - return Hexagon::POST_STdri_cPt; - - case Hexagon::POST_STdri_cdnNotPt_V4 : - return Hexagon::POST_STdri_cNotPt; - - case Hexagon::STd_GP_cdnPt_V4 : - return Hexagon::STd_GP_cPt_V4; - - case Hexagon::STd_GP_cdnNotPt_V4 : - return Hexagon::STd_GP_cNotPt_V4; - - } -} - bool HexagonPacketizerList::DemoteToDotOld(MachineInstr* MI) { const HexagonInstrInfo *QII = (const HexagonInstrInfo *) TII; - int NewOpcode = GetDotOldOp(MI->getOpcode()); + int NewOpcode = QII->GetDotOldOp(MI->getOpcode()); MI->setDesc(QII->get(NewOpcode)); return true; } -// Returns true if an instruction is predicated on p0 and false if it's -// predicated on !p0. +enum PredicateKind { + PK_False, + PK_True, + PK_Unknown +}; -static bool GetPredicateSense(MachineInstr* MI, - const HexagonInstrInfo *QII) { +/// Returns true if an instruction is predicated on p0 and false if it's +/// predicated on !p0. +static PredicateKind getPredicateSense(MachineInstr* MI, + const HexagonInstrInfo *QII) { + if (!QII->isPredicated(MI)) + return PK_Unknown; - switch (MI->getOpcode()) { - default: llvm_unreachable("Unknown predicate sense of the instruction"); - case Hexagon::TFR_cPt: - case Hexagon::TFR_cdnPt: - case Hexagon::TFRI_cPt: - case Hexagon::TFRI_cdnPt: - case Hexagon::STrib_cPt : - case Hexagon::STrib_cdnPt_V4 : - case Hexagon::STrib_indexed_cPt : - case Hexagon::STrib_indexed_cdnPt_V4 : - case Hexagon::STrib_indexed_shl_cPt_V4 : - case Hexagon::STrib_indexed_shl_cdnPt_V4 : - case Hexagon::POST_STbri_cPt : - case Hexagon::POST_STbri_cdnPt_V4 : - case Hexagon::STrih_cPt : - case Hexagon::STrih_cdnPt_V4 : - case Hexagon::STrih_indexed_cPt : - case Hexagon::STrih_indexed_cdnPt_V4 : - case Hexagon::STrih_indexed_shl_cPt_V4 : - case Hexagon::STrih_indexed_shl_cdnPt_V4 : - case Hexagon::POST_SThri_cPt : - case Hexagon::POST_SThri_cdnPt_V4 : - case Hexagon::STriw_cPt : - case Hexagon::STriw_cdnPt_V4 : - case Hexagon::STriw_indexed_cPt : - case Hexagon::STriw_indexed_cdnPt_V4 : - case Hexagon::STriw_indexed_shl_cPt_V4 : - case Hexagon::STriw_indexed_shl_cdnPt_V4 : - case Hexagon::POST_STwri_cPt : - case Hexagon::POST_STwri_cdnPt_V4 : - case Hexagon::STrib_imm_cPt_V4 : - case Hexagon::STrib_imm_cdnPt_V4 : - case Hexagon::STrid_cPt : - case Hexagon::STrid_cdnPt_V4 : - case Hexagon::STrid_indexed_cPt : - case Hexagon::STrid_indexed_cdnPt_V4 : - case Hexagon::STrid_indexed_shl_cPt_V4 : - case Hexagon::STrid_indexed_shl_cdnPt_V4 : - case Hexagon::POST_STdri_cPt : - case Hexagon::POST_STdri_cdnPt_V4 : - case Hexagon::STrih_imm_cPt_V4 : - case Hexagon::STrih_imm_cdnPt_V4 : - case Hexagon::STriw_imm_cPt_V4 : - case Hexagon::STriw_imm_cdnPt_V4 : - case Hexagon::JMP_tnew_t : - case Hexagon::LDrid_cPt : - case Hexagon::LDrid_cdnPt : - case Hexagon::LDrid_indexed_cPt : - case Hexagon::LDrid_indexed_cdnPt : - case Hexagon::POST_LDrid_cPt : - case Hexagon::POST_LDrid_cdnPt_V4 : - case Hexagon::LDriw_cPt : - case Hexagon::LDriw_cdnPt : - case Hexagon::LDriw_indexed_cPt : - case Hexagon::LDriw_indexed_cdnPt : - case Hexagon::POST_LDriw_cPt : - case Hexagon::POST_LDriw_cdnPt_V4 : - case Hexagon::LDrih_cPt : - case Hexagon::LDrih_cdnPt : - case Hexagon::LDrih_indexed_cPt : - case Hexagon::LDrih_indexed_cdnPt : - case Hexagon::POST_LDrih_cPt : - case Hexagon::POST_LDrih_cdnPt_V4 : - case Hexagon::LDrib_cPt : - case Hexagon::LDrib_cdnPt : - case Hexagon::LDrib_indexed_cPt : - case Hexagon::LDrib_indexed_cdnPt : - case Hexagon::POST_LDrib_cPt : - case Hexagon::POST_LDrib_cdnPt_V4 : - case Hexagon::LDriuh_cPt : - case Hexagon::LDriuh_cdnPt : - case Hexagon::LDriuh_indexed_cPt : - case Hexagon::LDriuh_indexed_cdnPt : - case Hexagon::POST_LDriuh_cPt : - case Hexagon::POST_LDriuh_cdnPt_V4 : - case Hexagon::LDriub_cPt : - case Hexagon::LDriub_cdnPt : - case Hexagon::LDriub_indexed_cPt : - case Hexagon::LDriub_indexed_cdnPt : - case Hexagon::POST_LDriub_cPt : - case Hexagon::POST_LDriub_cdnPt_V4 : - case Hexagon::LDrid_indexed_shl_cPt_V4 : - case Hexagon::LDrid_indexed_shl_cdnPt_V4 : - case Hexagon::LDrib_indexed_shl_cPt_V4 : - case Hexagon::LDrib_indexed_shl_cdnPt_V4 : - case Hexagon::LDriub_indexed_shl_cPt_V4 : - case Hexagon::LDriub_indexed_shl_cdnPt_V4 : - case Hexagon::LDrih_indexed_shl_cPt_V4 : - case Hexagon::LDrih_indexed_shl_cdnPt_V4 : - case Hexagon::LDriuh_indexed_shl_cPt_V4 : - case Hexagon::LDriuh_indexed_shl_cdnPt_V4 : - case Hexagon::LDriw_indexed_shl_cPt_V4 : - case Hexagon::LDriw_indexed_shl_cdnPt_V4 : - case Hexagon::ADD_ri_cPt : - case Hexagon::ADD_ri_cdnPt : - case Hexagon::ADD_rr_cPt : - case Hexagon::ADD_rr_cdnPt : - case Hexagon::XOR_rr_cPt : - case Hexagon::XOR_rr_cdnPt : - case Hexagon::AND_rr_cPt : - case Hexagon::AND_rr_cdnPt : - case Hexagon::OR_rr_cPt : - case Hexagon::OR_rr_cdnPt : - case Hexagon::SUB_rr_cPt : - case Hexagon::SUB_rr_cdnPt : - case Hexagon::COMBINE_rr_cPt : - case Hexagon::COMBINE_rr_cdnPt : - case Hexagon::ASLH_cPt_V4 : - case Hexagon::ASLH_cdnPt_V4 : - case Hexagon::ASRH_cPt_V4 : - case Hexagon::ASRH_cdnPt_V4 : - case Hexagon::SXTB_cPt_V4 : - case Hexagon::SXTB_cdnPt_V4 : - case Hexagon::SXTH_cPt_V4 : - case Hexagon::SXTH_cdnPt_V4 : - case Hexagon::ZXTB_cPt_V4 : - case Hexagon::ZXTB_cdnPt_V4 : - case Hexagon::ZXTH_cPt_V4 : - case Hexagon::ZXTH_cdnPt_V4 : - case Hexagon::LDd_GP_cPt_V4 : - case Hexagon::LDb_GP_cPt_V4 : - case Hexagon::LDub_GP_cPt_V4 : - case Hexagon::LDh_GP_cPt_V4 : - case Hexagon::LDuh_GP_cPt_V4 : - case Hexagon::LDw_GP_cPt_V4 : - case Hexagon::STd_GP_cPt_V4 : - case Hexagon::STb_GP_cPt_V4 : - case Hexagon::STh_GP_cPt_V4 : - case Hexagon::STw_GP_cPt_V4 : - case Hexagon::LDd_GP_cdnPt_V4 : - case Hexagon::LDb_GP_cdnPt_V4 : - case Hexagon::LDub_GP_cdnPt_V4 : - case Hexagon::LDh_GP_cdnPt_V4 : - case Hexagon::LDuh_GP_cdnPt_V4 : - case Hexagon::LDw_GP_cdnPt_V4 : - case Hexagon::STd_GP_cdnPt_V4 : - case Hexagon::STb_GP_cdnPt_V4 : - case Hexagon::STh_GP_cdnPt_V4 : - case Hexagon::STw_GP_cdnPt_V4 : - return true; + if (QII->isPredicatedTrue(MI)) + return PK_True; - case Hexagon::TFR_cNotPt: - case Hexagon::TFR_cdnNotPt: - case Hexagon::TFRI_cNotPt: - case Hexagon::TFRI_cdnNotPt: - case Hexagon::STrib_cNotPt : - case Hexagon::STrib_cdnNotPt_V4 : - case Hexagon::STrib_indexed_cNotPt : - case Hexagon::STrib_indexed_cdnNotPt_V4 : - case Hexagon::STrib_indexed_shl_cNotPt_V4 : - case Hexagon::STrib_indexed_shl_cdnNotPt_V4 : - case Hexagon::POST_STbri_cNotPt : - case Hexagon::POST_STbri_cdnNotPt_V4 : - case Hexagon::STrih_cNotPt : - case Hexagon::STrih_cdnNotPt_V4 : - case Hexagon::STrih_indexed_cNotPt : - case Hexagon::STrih_indexed_cdnNotPt_V4 : - case Hexagon::STrih_indexed_shl_cNotPt_V4 : - case Hexagon::STrih_indexed_shl_cdnNotPt_V4 : - case Hexagon::POST_SThri_cNotPt : - case Hexagon::POST_SThri_cdnNotPt_V4 : - case Hexagon::STriw_cNotPt : - case Hexagon::STriw_cdnNotPt_V4 : - case Hexagon::STriw_indexed_cNotPt : - case Hexagon::STriw_indexed_cdnNotPt_V4 : - case Hexagon::STriw_indexed_shl_cNotPt_V4 : - case Hexagon::STriw_indexed_shl_cdnNotPt_V4 : - case Hexagon::POST_STwri_cNotPt : - case Hexagon::POST_STwri_cdnNotPt_V4 : - case Hexagon::STrib_imm_cNotPt_V4 : - case Hexagon::STrib_imm_cdnNotPt_V4 : - case Hexagon::STrid_cNotPt : - case Hexagon::STrid_cdnNotPt_V4 : - case Hexagon::STrid_indexed_cdnNotPt_V4 : - case Hexagon::STrid_indexed_cNotPt : - case Hexagon::STrid_indexed_shl_cNotPt_V4 : - case Hexagon::STrid_indexed_shl_cdnNotPt_V4 : - case Hexagon::POST_STdri_cNotPt : - case Hexagon::POST_STdri_cdnNotPt_V4 : - case Hexagon::STrih_imm_cNotPt_V4 : - case Hexagon::STrih_imm_cdnNotPt_V4 : - case Hexagon::STriw_imm_cNotPt_V4 : - case Hexagon::STriw_imm_cdnNotPt_V4 : - case Hexagon::JMP_fnew_t : - case Hexagon::LDrid_cNotPt : - case Hexagon::LDrid_cdnNotPt : - case Hexagon::LDrid_indexed_cNotPt : - case Hexagon::LDrid_indexed_cdnNotPt : - case Hexagon::POST_LDrid_cNotPt : - case Hexagon::POST_LDrid_cdnNotPt_V4 : - case Hexagon::LDriw_cNotPt : - case Hexagon::LDriw_cdnNotPt : - case Hexagon::LDriw_indexed_cNotPt : - case Hexagon::LDriw_indexed_cdnNotPt : - case Hexagon::POST_LDriw_cNotPt : - case Hexagon::POST_LDriw_cdnNotPt_V4 : - case Hexagon::LDrih_cNotPt : - case Hexagon::LDrih_cdnNotPt : - case Hexagon::LDrih_indexed_cNotPt : - case Hexagon::LDrih_indexed_cdnNotPt : - case Hexagon::POST_LDrih_cNotPt : - case Hexagon::POST_LDrih_cdnNotPt_V4 : - case Hexagon::LDrib_cNotPt : - case Hexagon::LDrib_cdnNotPt : - case Hexagon::LDrib_indexed_cNotPt : - case Hexagon::LDrib_indexed_cdnNotPt : - case Hexagon::POST_LDrib_cNotPt : - case Hexagon::POST_LDrib_cdnNotPt_V4 : - case Hexagon::LDriuh_cNotPt : - case Hexagon::LDriuh_cdnNotPt : - case Hexagon::LDriuh_indexed_cNotPt : - case Hexagon::LDriuh_indexed_cdnNotPt : - case Hexagon::POST_LDriuh_cNotPt : - case Hexagon::POST_LDriuh_cdnNotPt_V4 : - case Hexagon::LDriub_cNotPt : - case Hexagon::LDriub_cdnNotPt : - case Hexagon::LDriub_indexed_cNotPt : - case Hexagon::LDriub_indexed_cdnNotPt : - case Hexagon::POST_LDriub_cNotPt : - case Hexagon::POST_LDriub_cdnNotPt_V4 : - case Hexagon::LDrid_indexed_shl_cNotPt_V4 : - case Hexagon::LDrid_indexed_shl_cdnNotPt_V4 : - case Hexagon::LDrib_indexed_shl_cNotPt_V4 : - case Hexagon::LDrib_indexed_shl_cdnNotPt_V4 : - case Hexagon::LDriub_indexed_shl_cNotPt_V4 : - case Hexagon::LDriub_indexed_shl_cdnNotPt_V4 : - case Hexagon::LDrih_indexed_shl_cNotPt_V4 : - case Hexagon::LDrih_indexed_shl_cdnNotPt_V4 : - case Hexagon::LDriuh_indexed_shl_cNotPt_V4 : - case Hexagon::LDriuh_indexed_shl_cdnNotPt_V4 : - case Hexagon::LDriw_indexed_shl_cNotPt_V4 : - case Hexagon::LDriw_indexed_shl_cdnNotPt_V4 : - case Hexagon::ADD_ri_cNotPt : - case Hexagon::ADD_ri_cdnNotPt : - case Hexagon::ADD_rr_cNotPt : - case Hexagon::ADD_rr_cdnNotPt : - case Hexagon::XOR_rr_cNotPt : - case Hexagon::XOR_rr_cdnNotPt : - case Hexagon::AND_rr_cNotPt : - case Hexagon::AND_rr_cdnNotPt : - case Hexagon::OR_rr_cNotPt : - case Hexagon::OR_rr_cdnNotPt : - case Hexagon::SUB_rr_cNotPt : - case Hexagon::SUB_rr_cdnNotPt : - case Hexagon::COMBINE_rr_cNotPt : - case Hexagon::COMBINE_rr_cdnNotPt : - case Hexagon::ASLH_cNotPt_V4 : - case Hexagon::ASLH_cdnNotPt_V4 : - case Hexagon::ASRH_cNotPt_V4 : - case Hexagon::ASRH_cdnNotPt_V4 : - case Hexagon::SXTB_cNotPt_V4 : - case Hexagon::SXTB_cdnNotPt_V4 : - case Hexagon::SXTH_cNotPt_V4 : - case Hexagon::SXTH_cdnNotPt_V4 : - case Hexagon::ZXTB_cNotPt_V4 : - case Hexagon::ZXTB_cdnNotPt_V4 : - case Hexagon::ZXTH_cNotPt_V4 : - case Hexagon::ZXTH_cdnNotPt_V4 : - - case Hexagon::LDd_GP_cNotPt_V4 : - case Hexagon::LDb_GP_cNotPt_V4 : - case Hexagon::LDub_GP_cNotPt_V4 : - case Hexagon::LDh_GP_cNotPt_V4 : - case Hexagon::LDuh_GP_cNotPt_V4 : - case Hexagon::LDw_GP_cNotPt_V4 : - case Hexagon::STd_GP_cNotPt_V4 : - case Hexagon::STb_GP_cNotPt_V4 : - case Hexagon::STh_GP_cNotPt_V4 : - case Hexagon::STw_GP_cNotPt_V4 : - case Hexagon::LDd_GP_cdnNotPt_V4 : - case Hexagon::LDb_GP_cdnNotPt_V4 : - case Hexagon::LDub_GP_cdnNotPt_V4 : - case Hexagon::LDh_GP_cdnNotPt_V4 : - case Hexagon::LDuh_GP_cdnNotPt_V4 : - case Hexagon::LDw_GP_cdnNotPt_V4 : - case Hexagon::STd_GP_cdnNotPt_V4 : - case Hexagon::STb_GP_cdnNotPt_V4 : - case Hexagon::STh_GP_cdnNotPt_V4 : - case Hexagon::STw_GP_cdnNotPt_V4 : - return false; - } - // return *some value* to avoid compiler warning - return false; + return PK_False; } static MachineOperand& GetPostIncrementOperand(MachineInstr *MI, @@ -1737,10 +537,10 @@ static MachineOperand& GetStoreValueOperand(MachineInstr *MI) { // Arch Spec: 3.4.4.2 bool HexagonPacketizerList::CanPromoteToNewValueStore( MachineInstr *MI, MachineInstr *PacketMI, unsigned DepReg, - std::map <MachineInstr*, SUnit*> MIToSUnit) -{ - // Make sure we are looking at the store - if (!IsNewifyStore(MI)) + std::map <MachineInstr*, SUnit*> MIToSUnit) { + const HexagonInstrInfo *QII = (const HexagonInstrInfo *) TII; + // Make sure we are looking at the store, that can be promoted. + if (!QII->mayBeNewStore(MI)) return false; // Make sure there is dependency and can be new value'ed @@ -1748,12 +548,11 @@ bool HexagonPacketizerList::CanPromoteToNewValueStore( MachineInstr *MI, GetStoreValueOperand(MI).getReg() != DepReg) return false; - const HexagonRegisterInfo* QRI = + const HexagonRegisterInfo* QRI = (const HexagonRegisterInfo *) TM.getRegisterInfo(); const MCInstrDesc& MCID = PacketMI->getDesc(); // first operand is always the result - const HexagonInstrInfo *QII = (const HexagonInstrInfo *) TII; const TargetRegisterClass* PacketRC = QII->getRegClass(MCID, 0, QRI, MF); // if there is already an store in the packet, no can do new value store @@ -1796,7 +595,7 @@ bool HexagonPacketizerList::CanPromoteToNewValueStore( MachineInstr *MI, } // If the source that feeds the store is predicated, new value store must - // also be also predicated. + // also be predicated. if (QII->isPredicated(PacketMI)) { if (!QII->isPredicated(MI)) return false; @@ -1842,7 +641,7 @@ bool HexagonPacketizerList::CanPromoteToNewValueStore( MachineInstr *MI, if (( predRegNumDst != predRegNumSrc) || QII->isDotNewInst(PacketMI) != QII->isDotNewInst(MI) || - GetPredicateSense(MI, QII) != GetPredicateSense(PacketMI, QII)) { + getPredicateSense(MI, QII) != getPredicateSense(PacketMI, QII)) { return false; } } @@ -1923,10 +722,11 @@ bool HexagonPacketizerList::CanPromoteToNewValue( MachineInstr *MI, MachineBasicBlock::iterator &MII) { + const HexagonInstrInfo *QII = (const HexagonInstrInfo *) TII; const HexagonRegisterInfo* QRI = (const HexagonRegisterInfo *) TM.getRegisterInfo(); if (!QRI->Subtarget.hasV4TOps() || - !IsNewifyStore(MI)) + !QII->mayBeNewStore(MI)) return false; MachineInstr *PacketMI = PacketSU->getInstr(); @@ -1953,7 +753,7 @@ bool HexagonPacketizerList::CanPromoteToDotNew( MachineInstr *MI, { const HexagonInstrInfo *QII = (const HexagonInstrInfo *) TII; // Already a dot new instruction. - if (QII->isDotNewInst(MI) && !IsNewifyStore(MI)) + if (QII->isDotNewInst(MI) && !QII->mayBeNewStore(MI)) return false; if (!isNewifiable(MI)) @@ -1963,12 +763,12 @@ bool HexagonPacketizerList::CanPromoteToDotNew( MachineInstr *MI, if (RC == &Hexagon::PredRegsRegClass && isCondInst(MI)) return true; else if (RC != &Hexagon::PredRegsRegClass && - !IsNewifyStore(MI)) // MI is not a new-value store + !QII->mayBeNewStore(MI)) // MI is not a new-value store return false; else { // Create a dot new machine instruction to see if resources can be // allocated. If not, bail out now. - int NewOpcode = GetDotNewOp(MI->getOpcode()); + int NewOpcode = QII->GetDotNewOp(MI); const MCInstrDesc &desc = QII->get(NewOpcode); DebugLoc dl; MachineInstr *NewMI = @@ -2109,7 +909,7 @@ bool HexagonPacketizerList::ArePredicatesComplements (MachineInstr* MI1, // We also need to differentiate .old vs. .new: // !p0 is not complimentary to p0.new return ((MI1->getOperand(1).getReg() == MI2->getOperand(1).getReg()) && - (GetPredicateSense(MI1, QII) != GetPredicateSense(MI2, QII)) && + (getPredicateSense(MI1, QII) != getPredicateSense(MI2, QII)) && (QII->isDotNewInst(MI1) == QII->isDotNewInst(MI2))); } @@ -2207,24 +1007,21 @@ bool HexagonPacketizerList::isLegalToPacketizeTogether(SUnit *SUI, SUnit *SUJ) { } // A LoopN instruction cannot appear in the same packet as a jump or call. - if (IsLoopN(I) && ( IsDirectJump(J) - || MCIDJ.isCall() - || QII->isDeallocRet(J))) { + if (IsLoopN(I) && + (IsDirectJump(J) || MCIDJ.isCall() || QII->isDeallocRet(J))) { Dependence = true; return false; } - if (IsLoopN(J) && ( IsDirectJump(I) - || MCIDI.isCall() - || QII->isDeallocRet(I))) { + if (IsLoopN(J) && + (IsDirectJump(I) || MCIDI.isCall() || QII->isDeallocRet(I))) { Dependence = true; return false; } // dealloc_return cannot appear in the same packet as a conditional or // unconditional jump. - if (QII->isDeallocRet(I) && ( MCIDJ.isBranch() - || MCIDJ.isCall() - || MCIDJ.isBarrier())) { + if (QII->isDeallocRet(I) && + (MCIDJ.isBranch() || MCIDJ.isCall() || MCIDJ.isBarrier())) { Dependence = true; return false; } @@ -2249,7 +1046,7 @@ bool HexagonPacketizerList::isLegalToPacketizeTogether(SUnit *SUI, SUnit *SUJ) { } //if dealloc_return - if (MCIDJ.mayStore() && QII->isDeallocRet(I)){ + if (MCIDJ.mayStore() && QII->isDeallocRet(I)) { Dependence = true; return false; } diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonMCAsmInfo.cpp b/lib/Target/Hexagon/MCTargetDesc/HexagonMCAsmInfo.cpp index 3deb8d1deb..495dbb97b0 100644 --- a/lib/Target/Hexagon/MCTargetDesc/HexagonMCAsmInfo.cpp +++ b/lib/Target/Hexagon/MCTargetDesc/HexagonMCAsmInfo.cpp @@ -15,7 +15,7 @@ using namespace llvm; -HexagonMCAsmInfo::HexagonMCAsmInfo(const Target &T, StringRef TT) { +HexagonMCAsmInfo::HexagonMCAsmInfo(StringRef TT) { Data16bitsDirective = "\t.half\t"; Data32bitsDirective = "\t.word\t"; Data64bitsDirective = 0; // .xword is only supported by V9. diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonMCAsmInfo.h b/lib/Target/Hexagon/MCTargetDesc/HexagonMCAsmInfo.h index d336cd5be9..0b94d2141c 100644 --- a/lib/Target/Hexagon/MCTargetDesc/HexagonMCAsmInfo.h +++ b/lib/Target/Hexagon/MCTargetDesc/HexagonMCAsmInfo.h @@ -18,11 +18,9 @@ #include "llvm/MC/MCAsmInfo.h" namespace llvm { - class Target; - class HexagonMCAsmInfo : public MCAsmInfo { public: - explicit HexagonMCAsmInfo(const Target &T, StringRef TT); + explicit HexagonMCAsmInfo(StringRef TT); }; } // namespace llvm diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp b/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp index 6b1d2d1619..273bc22b8e 100644 --- a/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp +++ b/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp @@ -54,8 +54,8 @@ static MCSubtargetInfo *createHexagonMCSubtargetInfo(StringRef TT, return X; } -static MCAsmInfo *createHexagonMCAsmInfo(const Target &T, StringRef TT) { - MCAsmInfo *MAI = new HexagonMCAsmInfo(T, TT); +static MCAsmInfo *createHexagonMCAsmInfo(StringRef TT) { + MCAsmInfo *MAI = new HexagonMCAsmInfo(TT); // VirtualFP = (R30 + #0). MachineLocation Dst(MachineLocation::VirtualFP); diff --git a/lib/Target/MBlaze/MCTargetDesc/MBlazeMCTargetDesc.cpp b/lib/Target/MBlaze/MCTargetDesc/MBlazeMCTargetDesc.cpp index 380750d50f..ec76dba491 100644 --- a/lib/Target/MBlaze/MCTargetDesc/MBlazeMCTargetDesc.cpp +++ b/lib/Target/MBlaze/MCTargetDesc/MBlazeMCTargetDesc.cpp @@ -53,7 +53,7 @@ static MCSubtargetInfo *createMBlazeMCSubtargetInfo(StringRef TT, StringRef CPU, return X; } -static MCAsmInfo *createMCAsmInfo(const Target &T, StringRef TT) { +static MCAsmInfo *createMCAsmInfo(StringRef TT) { Triple TheTriple(TT); switch (TheTriple.getOS()) { default: diff --git a/lib/Target/MSP430/MCTargetDesc/MSP430MCAsmInfo.cpp b/lib/Target/MSP430/MCTargetDesc/MSP430MCAsmInfo.cpp index 3c95760569..d213a45bb9 100644 --- a/lib/Target/MSP430/MCTargetDesc/MSP430MCAsmInfo.cpp +++ b/lib/Target/MSP430/MCTargetDesc/MSP430MCAsmInfo.cpp @@ -17,7 +17,7 @@ using namespace llvm; void MSP430MCAsmInfo::anchor() { } -MSP430MCAsmInfo::MSP430MCAsmInfo(const Target &T, StringRef TT) { +MSP430MCAsmInfo::MSP430MCAsmInfo(StringRef TT) { PointerSize = CalleeSaveStackSlotSize = 2; PrivateGlobalPrefix = ".L"; diff --git a/lib/Target/MSP430/MCTargetDesc/MSP430MCAsmInfo.h b/lib/Target/MSP430/MCTargetDesc/MSP430MCAsmInfo.h index e5c2fc283b..feb040d13b 100644 --- a/lib/Target/MSP430/MCTargetDesc/MSP430MCAsmInfo.h +++ b/lib/Target/MSP430/MCTargetDesc/MSP430MCAsmInfo.h @@ -18,12 +18,11 @@ namespace llvm { class StringRef; - class Target; class MSP430MCAsmInfo : public MCAsmInfo { virtual void anchor(); public: - explicit MSP430MCAsmInfo(const Target &T, StringRef TT); + explicit MSP430MCAsmInfo(StringRef TT); }; } // namespace llvm diff --git a/lib/Target/Mips/CMakeLists.txt b/lib/Target/Mips/CMakeLists.txt index 78a9f70c66..8be68c5b4f 100644 --- a/lib/Target/Mips/CMakeLists.txt +++ b/lib/Target/Mips/CMakeLists.txt @@ -15,6 +15,7 @@ add_public_tablegen_target(MipsCommonTableGen) add_llvm_target(MipsCodeGen Mips16FrameLowering.cpp + Mips16HardFloat.cpp Mips16InstrInfo.cpp Mips16ISelDAGToDAG.cpp Mips16ISelLowering.cpp diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp b/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp index 5d4b32d305..33f6f9620e 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp @@ -18,7 +18,7 @@ using namespace llvm; void MipsMCAsmInfo::anchor() { } -MipsMCAsmInfo::MipsMCAsmInfo(const Target &T, StringRef TT) { +MipsMCAsmInfo::MipsMCAsmInfo(StringRef TT) { Triple TheTriple(TT); if ((TheTriple.getArch() == Triple::mips) || (TheTriple.getArch() == Triple::mips64)) diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h b/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h index e1d878936f..772234eb71 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h +++ b/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h @@ -18,12 +18,11 @@ namespace llvm { class StringRef; - class Target; class MipsMCAsmInfo : public MCAsmInfo { virtual void anchor(); public: - explicit MipsMCAsmInfo(const Target &T, StringRef TT); + explicit MipsMCAsmInfo(StringRef TT); }; } // namespace llvm diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp b/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp index be83b54b61..26694ffdac 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp @@ -93,8 +93,8 @@ static MCSubtargetInfo *createMipsMCSubtargetInfo(StringRef TT, StringRef CPU, return X; } -static MCAsmInfo *createMipsMCAsmInfo(const Target &T, StringRef TT) { - MCAsmInfo *MAI = new MipsMCAsmInfo(T, TT); +static MCAsmInfo *createMipsMCAsmInfo(StringRef TT) { + MCAsmInfo *MAI = new MipsMCAsmInfo(TT); MachineLocation Dst(MachineLocation::VirtualFP); MachineLocation Src(Mips::SP, 0); diff --git a/lib/Target/Mips/Mips16FrameLowering.cpp b/lib/Target/Mips/Mips16FrameLowering.cpp index 1bb6fe4629..d9a7487bf7 100644 --- a/lib/Target/Mips/Mips16FrameLowering.cpp +++ b/lib/Target/Mips/Mips16FrameLowering.cpp @@ -40,7 +40,6 @@ void Mips16FrameLowering::emitPrologue(MachineFunction &MF) const { if (StackSize == 0 && !MFI->adjustsStack()) return; MachineModuleInfo &MMI = MF.getMMI(); - std::vector<MachineMove> &Moves = MMI.getFrameMoves(); MachineLocation DstML, SrcML; // Adjust stack. @@ -52,22 +51,22 @@ void Mips16FrameLowering::emitPrologue(MachineFunction &MF) const { TII.get(TargetOpcode::PROLOG_LABEL)).addSym(AdjustSPLabel); DstML = MachineLocation(MachineLocation::VirtualFP); SrcML = MachineLocation(MachineLocation::VirtualFP, -StackSize); - Moves.push_back(MachineMove(AdjustSPLabel, DstML, SrcML)); + MMI.addFrameMove(AdjustSPLabel, DstML, SrcML); MCSymbol *CSLabel = MMI.getContext().CreateTempSymbol(); BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::PROLOG_LABEL)).addSym(CSLabel); DstML = MachineLocation(MachineLocation::VirtualFP, -8); SrcML = MachineLocation(Mips::S1); - Moves.push_back(MachineMove(CSLabel, DstML, SrcML)); + MMI.addFrameMove(CSLabel, DstML, SrcML); DstML = MachineLocation(MachineLocation::VirtualFP, -12); SrcML = MachineLocation(Mips::S0); - Moves.push_back(MachineMove(CSLabel, DstML, SrcML)); + MMI.addFrameMove(CSLabel, DstML, SrcML); DstML = MachineLocation(MachineLocation::VirtualFP, -4); SrcML = MachineLocation(Mips::RA); - Moves.push_back(MachineMove(CSLabel, DstML, SrcML)); + MMI.addFrameMove(CSLabel, DstML, SrcML); if (hasFP(MF)) BuildMI(MBB, MBBI, dl, TII.get(Mips::MoveR3216), Mips::S0) diff --git a/lib/Target/Mips/Mips16HardFloat.cpp b/lib/Target/Mips/Mips16HardFloat.cpp new file mode 100644 index 0000000000..4d1e61bb99 --- /dev/null +++ b/lib/Target/Mips/Mips16HardFloat.cpp @@ -0,0 +1,141 @@ +//===---- Mips16HardFloat.cpp for Mips16 Hard Float --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a pass needed for Mips16 Hard Float +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mips16-hard-float" +#include "Mips16HardFloat.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include <string> + +// +// Return types that matter for hard float are: +// float, double, complex float, and complex double +// +enum FPReturnVariant { + FRet, DRet, CFRet, CDRet, NoFPRet +}; + +// +// Determine which FP return type this function has +// +static FPReturnVariant whichFPReturnVariant(Type *T) { + switch (T->getTypeID()) { + case Type::FloatTyID: + return FRet; + case Type::DoubleTyID: + return DRet; + case Type::StructTyID: + if (T->getStructNumElements() != 2) + break; + if ((T->getContainedType(0)->isFloatTy()) && + (T->getContainedType(1)->isFloatTy())) + return CFRet; + if ((T->getContainedType(0)->isDoubleTy()) && + (T->getContainedType(1)->isDoubleTy())) + return CDRet; + break; + default: + break; + } + return NoFPRet; +} + +// +// Returns of float, double and complex need to be handled with a helper +// function. The "AndCal" part is coming in a later patch. +// +static bool fixupFPReturnAndCall + (Function &F, Module *M, const MipsSubtarget &Subtarget) { + bool Modified = false; + LLVMContext &C = M->getContext(); + Type *MyVoid = Type::getVoidTy(C); + for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) + for (BasicBlock::iterator I = BB->begin(), E = BB->end(); + I != E; ++I) { + Instruction &Inst = *I; + if (const ReturnInst *RI = dyn_cast<ReturnInst>(I)) { + Value *RVal = RI->getReturnValue(); + if (!RVal) continue; + // + // If there is a return value and it needs a helper function, + // figure out which one and add a call before the actual + // return to this helper. The purpose of the helper is to move + // floating point values from their soft float return mapping to + // where they would have been mapped to in floating point registers. + // + Type *T = RVal->getType(); + FPReturnVariant RV = whichFPReturnVariant(T); + if (RV == NoFPRet) continue; + static const char* Helper[NoFPRet] = + {"__mips16_ret_sf", "__mips16_ret_df", "__mips16_ret_sc", + "__mips16_ret_dc"}; + const char *Name = Helper[RV]; + AttributeSet A; + Value *Params[] = {RVal}; + Modified = true; + // + // These helper functions have a different calling ABI so + // this __Mips16RetHelper indicates that so that later + // during call setup, the proper call lowering to the helper + // functions will take place. + // + A = A.addAttribute(C, AttributeSet::FunctionIndex, + "__Mips16RetHelper"); + A = A.addAttribute(C, AttributeSet::FunctionIndex, + Attribute::ReadNone); + Value *F = (M->getOrInsertFunction(Name, A, MyVoid, T, NULL)); + CallInst::Create(F, Params, "", &Inst ); + } + } + return Modified; +} + +namespace llvm { + +// +// This pass only makes sense when the underlying chip has floating point but +// we are compiling as mips16. +// For all mips16 functions (that are not stubs we have already generated), or +// declared via attributes as nomips16, we must: +// 1) fixup all returns of float, double, single and double complex +// by calling a helper function before the actual return. +// 2) generate helper functions (stubs) that can be called by mips32 functions +// that will move parameters passed normally passed in floating point +// registers the soft float equivalents. (Coming in a later patch). +// 3) in the case of static relocation, generate helper functions so that +// mips16 functions can call extern functions of unknown type (mips16 or +// mips32). (Coming in a later patch). +// 4) TBD. For pic, calls to extern functions of unknown type are handled by +// predefined helper functions in libc but this work is currently done +// during call lowering but it should be moved here in the future. +// +bool Mips16HardFloat::runOnModule(Module &M) { + DEBUG(errs() << "Run on Module Mips16HardFloat\n"); + bool Modified = false; + for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) { + if (F->isDeclaration() || F->hasFnAttribute("mips16_fp_stub") || + F->hasFnAttribute("nomips16")) continue; + Modified |= fixupFPReturnAndCall(*F, &M, Subtarget); + } + return Modified; +} + +char Mips16HardFloat::ID = 0; + +} + +ModulePass *llvm::createMips16HardFloat(MipsTargetMachine &TM) { + return new Mips16HardFloat(TM); +} + diff --git a/lib/Target/Mips/Mips16HardFloat.h b/lib/Target/Mips/Mips16HardFloat.h new file mode 100644 index 0000000000..b7f712af5b --- /dev/null +++ b/lib/Target/Mips/Mips16HardFloat.h @@ -0,0 +1,54 @@ +//===---- Mips16HardFloat.h for Mips16 Hard Float --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a phase which implements part of the floating point +// interoperability between Mips16 and Mips32 code. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/MipsMCTargetDesc.h" +#include "MipsTargetMachine.h" +#include "llvm/Pass.h" +#include "llvm/Target/TargetMachine.h" + + +#ifndef MIPS16HARDFLOAT_H +#define MIPS16HARDFLOAT_H + +using namespace llvm; + +namespace llvm { + +class Mips16HardFloat : public ModulePass { + +public: + static char ID; + + Mips16HardFloat(MipsTargetMachine &TM_) : ModulePass(ID), + TM(TM_), Subtarget(TM.getSubtarget<MipsSubtarget>()) { + } + + virtual const char *getPassName() const { + return "MIPS16 Hard Float Pass"; + } + + virtual bool runOnModule(Module &M); + +protected: + /// Keep a pointer to the MipsSubtarget around so that we can make the right + /// decision when generating code for different targets. + const TargetMachine &TM; + const MipsSubtarget &Subtarget; + +}; + +ModulePass *createMips16HardFloat(MipsTargetMachine &TM); + +} +#endif diff --git a/lib/Target/Mips/Mips16ISelLowering.cpp b/lib/Target/Mips/Mips16ISelLowering.cpp index f63318f1e6..c633d312bb 100644 --- a/lib/Target/Mips/Mips16ISelLowering.cpp +++ b/lib/Target/Mips/Mips16ISelLowering.cpp @@ -13,6 +13,7 @@ #define DEBUG_TYPE "mips-lower" #include "Mips16ISelLowering.h" #include "MipsRegisterInfo.h" +#include "MipsTargetMachine.h" #include "MCTargetDesc/MipsBaseInfo.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/Support/CommandLine.h" @@ -21,11 +22,6 @@ using namespace llvm; -static cl::opt<bool> -Mips16HardFloat("mips16-hard-float", cl::NotHidden, - cl::desc("MIPS: mips16 hard float enable."), - cl::init(false)); - static cl::opt<bool> DontExpandCondPseudos16( "mips16-dont-expand-cond-pseudo", cl::init(false), @@ -50,7 +46,7 @@ Mips16TargetLowering::Mips16TargetLowering(MipsTargetMachine &TM) // Set up the register classes addRegisterClass(MVT::i32, &Mips::CPU16RegsRegClass); - if (Mips16HardFloat) + if (Subtarget->inMips16HardFloat()) setMips16HardFloatLibCalls(); setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Expand); @@ -374,7 +370,8 @@ getOpndList(SmallVectorImpl<SDValue> &Ops, const char* Mips16HelperFunction = 0; bool NeedMips16Helper = false; - if (getTargetMachine().Options.UseSoftFloat && Mips16HardFloat) { + if (getTargetMachine().Options.UseSoftFloat && + Subtarget->inMips16HardFloat()) { // // currently we don't have symbols tagged with the mips16 or mips32 // qualifier so we will assume that we don't know what kind it is. diff --git a/lib/Target/Mips/MipsCallingConv.td b/lib/Target/Mips/MipsCallingConv.td index 462def76cc..6e8c5d24a8 100644 --- a/lib/Target/Mips/MipsCallingConv.td +++ b/lib/Target/Mips/MipsCallingConv.td @@ -196,6 +196,13 @@ def CC_Mips_FastCC : CallingConv<[ CCDelegateTo<CC_MipsN_FastCC> ]>; +//== + +def CC_Mips16RetHelper : CallingConv<[ + // Integer arguments are passed in integer registers. + CCIfType<[i32], CCAssignToReg<[V0, V1, A0, A1]>> +]>; + //===----------------------------------------------------------------------===// // Mips Calling Convention Dispatch //===----------------------------------------------------------------------===// @@ -223,3 +230,6 @@ def CSR_N32 : CalleeSavedRegs<(add D31_64, D29_64, D27_64, D25_64, D24_64, def CSR_N64 : CalleeSavedRegs<(add (sequence "D%u_64", 31, 24), RA_64, FP_64, GP_64, (sequence "S%u_64", 7, 0))>; + +def CSR_Mips16RetHelper : + CalleeSavedRegs<(add V0, V1, (sequence "A%u", 3, 0), S0, S1)>; diff --git a/lib/Target/Mips/MipsISelLowering.cpp b/lib/Target/Mips/MipsISelLowering.cpp index 4d76181f92..ab105b3655 100644 --- a/lib/Target/Mips/MipsISelLowering.cpp +++ b/lib/Target/Mips/MipsISelLowering.cpp @@ -2229,6 +2229,15 @@ getOpndList(SmallVectorImpl<SDValue> &Ops, const TargetRegisterInfo *TRI = getTargetMachine().getRegisterInfo(); const uint32_t *Mask = TRI->getCallPreservedMask(CLI.CallConv); assert(Mask && "Missing call preserved mask for calling convention"); + if (Subtarget->inMips16HardFloat()) { + if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(CLI.Callee)) { + llvm::StringRef Sym = G->getGlobal()->getName(); + Function *F = G->getGlobal()->getParent()->getFunction(Sym); + if (F->hasFnAttribute("__Mips16RetHelper")) { + Mask = MipsRegisterInfo::getMips16RetHelperMask(); + } + } + } Ops.push_back(CLI.DAG.getRegisterMask(Mask)); if (InFlag.getNode()) @@ -2260,7 +2269,9 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, SmallVector<CCValAssign, 16> ArgLocs; CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), getTargetMachine(), ArgLocs, *DAG.getContext()); - MipsCC MipsCCInfo(CallConv, IsO32, CCInfo); + MipsCC::SpecialCallingConvType SpecialCallingConv = + getSpecialCallingConv(Callee); + MipsCC MipsCCInfo(CallConv, IsO32, CCInfo, SpecialCallingConv); MipsCCInfo.analyzeCallOperands(Outs, IsVarArg, getTargetMachine().Options.UseSoftFloat, @@ -3029,13 +3040,32 @@ static bool originalTypeIsF128(const Type *Ty, const SDNode *CallNode) { return (ES && Ty->isIntegerTy(128) && isF128SoftLibCall(ES->getSymbol())); } -MipsTargetLowering::MipsCC::MipsCC(CallingConv::ID CC, bool IsO32_, - CCState &Info) - : CCInfo(Info), CallConv(CC), IsO32(IsO32_) { +MipsTargetLowering::MipsCC::SpecialCallingConvType + MipsTargetLowering::getSpecialCallingConv(SDValue Callee) const { + MipsCC::SpecialCallingConvType SpecialCallingConv = + MipsCC::NoSpecialCallingConv;; + if (Subtarget->inMips16HardFloat()) { + if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) { + llvm::StringRef Sym = G->getGlobal()->getName(); + Function *F = G->getGlobal()->getParent()->getFunction(Sym); + if (F->hasFnAttribute("__Mips16RetHelper")) { + SpecialCallingConv = MipsCC::Mips16RetHelperConv; + } + } + } + return SpecialCallingConv; +} + +MipsTargetLowering::MipsCC::MipsCC( + CallingConv::ID CC, bool IsO32_, CCState &Info, + MipsCC::SpecialCallingConvType SpecialCallingConv_) + : CCInfo(Info), CallConv(CC), IsO32(IsO32_), + SpecialCallingConv(SpecialCallingConv_){ // Pre-allocate reserved argument area. CCInfo.AllocateStack(reservedArgArea(), 1); } + void MipsTargetLowering::MipsCC:: analyzeCallOperands(const SmallVectorImpl<ISD::OutputArg> &Args, bool IsVarArg, bool IsSoftFloat, const SDNode *CallNode, @@ -3183,6 +3213,8 @@ llvm::CCAssignFn *MipsTargetLowering::MipsCC::fixedArgFn() const { if (CallConv == CallingConv::Fast) return CC_Mips_FastCC; + if (SpecialCallingConv == Mips16RetHelperConv) + return CC_Mips16RetHelper; return IsO32 ? CC_MipsO32 : CC_MipsN; } diff --git a/lib/Target/Mips/MipsISelLowering.h b/lib/Target/Mips/MipsISelLowering.h index 5587e8f581..233c11f789 100644 --- a/lib/Target/Mips/MipsISelLowering.h +++ b/lib/Target/Mips/MipsISelLowering.h @@ -240,7 +240,14 @@ namespace llvm { /// arguments and inquire about calling convention information. class MipsCC { public: - MipsCC(CallingConv::ID CallConv, bool IsO32, CCState &Info); + enum SpecialCallingConvType { + Mips16RetHelperConv, NoSpecialCallingConv + }; + + MipsCC( + CallingConv::ID CallConv, bool IsO32, CCState &Info, + SpecialCallingConvType SpecialCallingConv = NoSpecialCallingConv); + void analyzeCallOperands(const SmallVectorImpl<ISD::OutputArg> &Outs, bool IsVarArg, bool IsSoftFloat, @@ -313,15 +320,18 @@ namespace llvm { CCState &CCInfo; CallingConv::ID CallConv; bool IsO32; + SpecialCallingConvType SpecialCallingConv; SmallVector<ByValArgInfo, 2> ByValArgs; }; - + protected: // Subtarget Info const MipsSubtarget *Subtarget; bool HasMips64, IsN64, IsO32; private: + + MipsCC::SpecialCallingConvType getSpecialCallingConv(SDValue Callee) const; // Lower Operand helpers SDValue LowerCallResult(SDValue Chain, SDValue InFlag, CallingConv::ID CallConv, bool isVarArg, diff --git a/lib/Target/Mips/MipsRegisterInfo.cpp b/lib/Target/Mips/MipsRegisterInfo.cpp index dead07bacd..ae25e456d5 100644 --- a/lib/Target/Mips/MipsRegisterInfo.cpp +++ b/lib/Target/Mips/MipsRegisterInfo.cpp @@ -100,6 +100,10 @@ MipsRegisterInfo::getCallPreservedMask(CallingConv::ID) const { return CSR_N64_RegMask; } +const uint32_t *MipsRegisterInfo::getMips16RetHelperMask() { + return CSR_Mips16RetHelper_RegMask; +} + BitVector MipsRegisterInfo:: getReservedRegs(const MachineFunction &MF) const { static const uint16_t ReservedCPURegs[] = { diff --git a/lib/Target/Mips/MipsRegisterInfo.h b/lib/Target/Mips/MipsRegisterInfo.h index 5ed5124139..20ba41d7fd 100644 --- a/lib/Target/Mips/MipsRegisterInfo.h +++ b/lib/Target/Mips/MipsRegisterInfo.h @@ -46,6 +46,7 @@ public: MachineFunction &MF) const; const uint16_t *getCalleeSavedRegs(const MachineFunction *MF = 0) const; const uint32_t *getCallPreservedMask(CallingConv::ID) const; + static const uint32_t *getMips16RetHelperMask(); BitVector getReservedRegs(const MachineFunction &MF) const; diff --git a/lib/Target/Mips/MipsSEFrameLowering.cpp b/lib/Target/Mips/MipsSEFrameLowering.cpp index b295e911bd..535c17cd62 100644 --- a/lib/Target/Mips/MipsSEFrameLowering.cpp +++ b/lib/Target/Mips/MipsSEFrameLowering.cpp @@ -262,7 +262,6 @@ void MipsSEFrameLowering::emitPrologue(MachineFunction &MF) const { if (StackSize == 0 && !MFI->adjustsStack()) return; MachineModuleInfo &MMI = MF.getMMI(); - std::vector<MachineMove> &Moves = MMI.getFrameMoves(); MachineLocation DstML, SrcML; // Adjust stack. @@ -274,7 +273,7 @@ void MipsSEFrameLowering::emitPrologue(MachineFunction &MF) const { TII.get(TargetOpcode::PROLOG_LABEL)).addSym(AdjustSPLabel); DstML = MachineLocation(MachineLocation::VirtualFP); SrcML = MachineLocation(MachineLocation::VirtualFP, -StackSize); - Moves.push_back(MachineMove(AdjustSPLabel, DstML, SrcML)); + MMI.addFrameMove(AdjustSPLabel, DstML, SrcML); const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo(); @@ -306,13 +305,13 @@ void MipsSEFrameLowering::emitPrologue(MachineFunction &MF) const { if (!STI.isLittle()) std::swap(SrcML0, SrcML1); - Moves.push_back(MachineMove(CSLabel, DstML0, SrcML0)); - Moves.push_back(MachineMove(CSLabel, DstML1, SrcML1)); + MMI.addFrameMove(CSLabel, DstML0, SrcML0); + MMI.addFrameMove(CSLabel, DstML1, SrcML1); } else { // Reg is either in CPURegs or FGR32. DstML = MachineLocation(MachineLocation::VirtualFP, Offset); SrcML = MachineLocation(Reg); - Moves.push_back(MachineMove(CSLabel, DstML, SrcML)); + MMI.addFrameMove(CSLabel, DstML, SrcML); } } } @@ -337,7 +336,7 @@ void MipsSEFrameLowering::emitPrologue(MachineFunction &MF) const { int64_t Offset = MFI->getObjectOffset(MipsFI->getEhDataRegFI(I)); DstML = MachineLocation(MachineLocation::VirtualFP, Offset); SrcML = MachineLocation(ehDataReg(I)); - Moves.push_back(MachineMove(CSLabel2, DstML, SrcML)); + MMI.addFrameMove(CSLabel2, DstML, SrcML); } } @@ -352,7 +351,7 @@ void MipsSEFrameLowering::emitPrologue(MachineFunction &MF) const { TII.get(TargetOpcode::PROLOG_LABEL)).addSym(SetFPLabel); DstML = MachineLocation(FP); SrcML = MachineLocation(MachineLocation::VirtualFP); - Moves.push_back(MachineMove(SetFPLabel, DstML, SrcML)); + MMI.addFrameMove(SetFPLabel, DstML, SrcML); } } diff --git a/lib/Target/Mips/MipsSubtarget.cpp b/lib/Target/Mips/MipsSubtarget.cpp index 14a2b27795..259e68df32 100644 --- a/lib/Target/Mips/MipsSubtarget.cpp +++ b/lib/Target/Mips/MipsSubtarget.cpp @@ -48,6 +48,11 @@ static cl::opt<bool> Mips_Os16( "floating point as Mips 16"), cl::Hidden); +static cl::opt<bool> +Mips16HardFloat("mips16-hard-float", cl::NotHidden, + cl::desc("MIPS: mips16 hard float enable."), + cl::init(false)); + void MipsSubtarget::anchor() { } MipsSubtarget::MipsSubtarget(const std::string &TT, const std::string &CPU, @@ -58,7 +63,8 @@ MipsSubtarget::MipsSubtarget(const std::string &TT, const std::string &CPU, IsSingleFloat(false), IsFP64bit(false), IsGP64bit(false), HasVFPU(false), IsLinux(true), HasSEInReg(false), HasCondMov(false), HasSwap(false), HasBitCount(false), HasFPIdx(false), - InMips16Mode(false), InMicroMipsMode(false), HasDSP(false), HasDSPR2(false), + InMips16Mode(false), InMips16HardFloat(Mips16HardFloat), + InMicroMipsMode(false), HasDSP(false), HasDSPR2(false), AllowMixed16_32(Mixed16_32 | Mips_Os16), Os16(Mips_Os16), RM(_RM), OverrideMode(NoOverride), TM(_TM) { diff --git a/lib/Target/Mips/MipsSubtarget.h b/lib/Target/Mips/MipsSubtarget.h index f2f0e15887..ef7568a813 100644 --- a/lib/Target/Mips/MipsSubtarget.h +++ b/lib/Target/Mips/MipsSubtarget.h @@ -93,6 +93,9 @@ protected: // InMips16 -- can process Mips16 instructions bool InMips16Mode; + // Mips16 hard float + bool InMips16HardFloat; + // PreviousInMips16 -- the function we just processed was in Mips 16 Mode bool PreviousInMips16Mode; @@ -170,9 +173,12 @@ public: } llvm_unreachable("Unexpected mode"); } - bool inMips16ModeDefault() { + bool inMips16ModeDefault() const { return InMips16Mode; } + bool inMips16HardFloat() const { + return inMips16Mode() && InMips16HardFloat; + } bool inMicroMipsMode() const { return InMicroMipsMode; } bool hasDSP() const { return HasDSP; } bool hasDSPR2() const { return HasDSPR2; } @@ -188,7 +194,8 @@ public: bool hasBitCount() const { return HasBitCount; } bool hasFPIdx() const { return HasFPIdx; } - bool allowMixed16_32() const { return AllowMixed16_32;}; + bool allowMixed16_32() const { return inMips16ModeDefault() | + AllowMixed16_32;} bool os16() const { return Os16;}; diff --git a/lib/Target/Mips/MipsTargetMachine.cpp b/lib/Target/Mips/MipsTargetMachine.cpp index ee28e2a122..a876f1c7f0 100644 --- a/lib/Target/Mips/MipsTargetMachine.cpp +++ b/lib/Target/Mips/MipsTargetMachine.cpp @@ -22,6 +22,7 @@ #include "MipsSEISelLowering.h" #include "MipsSEISelDAGToDAG.h" #include "Mips16FrameLowering.h" +#include "Mips16HardFloat.h" #include "Mips16InstrInfo.h" #include "Mips16ISelDAGToDAG.h" #include "Mips16ISelLowering.h" @@ -156,6 +157,8 @@ void MipsPassConfig::addIRPasses() { TargetPassConfig::addIRPasses(); if (getMipsSubtarget().os16()) addPass(createMipsOs16(getMipsTargetMachine())); + if (getMipsSubtarget().inMips16HardFloat()) + addPass(createMips16HardFloat(getMipsTargetMachine())); } // Install an instruction selector pass using // the ISelDag to gen Mips code. diff --git a/lib/Target/NVPTX/MCTargetDesc/NVPTXMCAsmInfo.cpp b/lib/Target/NVPTX/MCTargetDesc/NVPTXMCAsmInfo.cpp index 459cd96cb0..fa33a75c61 100644 --- a/lib/Target/NVPTX/MCTargetDesc/NVPTXMCAsmInfo.cpp +++ b/lib/Target/NVPTX/MCTargetDesc/NVPTXMCAsmInfo.cpp @@ -27,7 +27,7 @@ Debug("debug-compile", cl::desc("Compile for debugging"), cl::Hidden, void NVPTXMCAsmInfo::anchor() {} -NVPTXMCAsmInfo::NVPTXMCAsmInfo(const Target &T, const StringRef &TT) { +NVPTXMCAsmInfo::NVPTXMCAsmInfo(const StringRef &TT) { Triple TheTriple(TT); if (TheTriple.getArch() == Triple::nvptx64) { PointerSize = CalleeSaveStackSlotSize = 8; diff --git a/lib/Target/NVPTX/MCTargetDesc/NVPTXMCAsmInfo.h b/lib/Target/NVPTX/MCTargetDesc/NVPTXMCAsmInfo.h index 82097daa4a..7d1633f60d 100644 --- a/lib/Target/NVPTX/MCTargetDesc/NVPTXMCAsmInfo.h +++ b/lib/Target/NVPTX/MCTargetDesc/NVPTXMCAsmInfo.h @@ -23,7 +23,7 @@ class StringRef; class NVPTXMCAsmInfo : public MCAsmInfo { virtual void anchor(); public: - explicit NVPTXMCAsmInfo(const Target &T, const StringRef &TT); + explicit NVPTXMCAsmInfo(const StringRef &TT); }; } // namespace llvm diff --git a/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp b/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp index 2209f936ec..a01fa44a9a 100644 --- a/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp +++ b/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp @@ -58,7 +58,7 @@ static MCSubtargetInfo *createPPCMCSubtargetInfo(StringRef TT, StringRef CPU, return X; } -static MCAsmInfo *createPPCMCAsmInfo(const Target &T, StringRef TT) { +static MCAsmInfo *createPPCMCAsmInfo(StringRef TT) { Triple TheTriple(TT); bool isPPC64 = TheTriple.getArch() == Triple::ppc64; diff --git a/lib/Target/PowerPC/PPCFrameLowering.cpp b/lib/Target/PowerPC/PPCFrameLowering.cpp index 9ec10f62f5..cd70aeed87 100644 --- a/lib/Target/PowerPC/PPCFrameLowering.cpp +++ b/lib/Target/PowerPC/PPCFrameLowering.cpp @@ -515,8 +515,6 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF) const { } } - std::vector<MachineMove> &Moves = MMI.getFrameMoves(); - // Add the "machine moves" for the instructions we generated above, but in // reverse order. if (needsFrameMoves) { @@ -528,22 +526,22 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF) const { if (NegFrameSize) { MachineLocation SPDst(MachineLocation::VirtualFP); MachineLocation SPSrc(MachineLocation::VirtualFP, NegFrameSize); - Moves.push_back(MachineMove(FrameLabel, SPDst, SPSrc)); + MMI.addFrameMove(FrameLabel, SPDst, SPSrc); } else { MachineLocation SP(isPPC64 ? PPC::X31 : PPC::R31); - Moves.push_back(MachineMove(FrameLabel, SP, SP)); + MMI.addFrameMove(FrameLabel, SP, SP); } if (HasFP) { MachineLocation FPDst(MachineLocation::VirtualFP, FPOffset); MachineLocation FPSrc(isPPC64 ? PPC::X31 : PPC::R31); - Moves.push_back(MachineMove(FrameLabel, FPDst, FPSrc)); + MMI.addFrameMove(FrameLabel, FPDst, FPSrc); } if (MustSaveLR) { MachineLocation LRDst(MachineLocation::VirtualFP, LROffset); MachineLocation LRSrc(isPPC64 ? PPC::LR8 : PPC::LR); - Moves.push_back(MachineMove(FrameLabel, LRDst, LRSrc)); + MMI.addFrameMove(FrameLabel, LRDst, LRSrc); } } @@ -570,7 +568,7 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF) const { MachineLocation FPDst(HasFP ? (isPPC64 ? PPC::X31 : PPC::R31) : (isPPC64 ? PPC::X1 : PPC::R1)); MachineLocation FPSrc(MachineLocation::VirtualFP); - Moves.push_back(MachineMove(ReadyLabel, FPDst, FPSrc)); + MMI.addFrameMove(ReadyLabel, FPDst, FPSrc); } } @@ -602,14 +600,14 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF) const { && (PPC::CR2 <= Reg && Reg <= PPC::CR4)) { MachineLocation CSDst(PPC::X1, 8); MachineLocation CSSrc(PPC::CR2); - Moves.push_back(MachineMove(Label, CSDst, CSSrc)); + MMI.addFrameMove(Label, CSDst, CSSrc); continue; } int Offset = MFI->getObjectOffset(CSI[I].getFrameIdx()); MachineLocation CSDst(MachineLocation::VirtualFP, Offset); MachineLocation CSSrc(Reg); - Moves.push_back(MachineMove(Label, CSDst, CSSrc)); + MMI.addFrameMove(Label, CSDst, CSSrc); } } } diff --git a/lib/Target/R600/MCTargetDesc/AMDGPUMCAsmInfo.cpp b/lib/Target/R600/MCTargetDesc/AMDGPUMCAsmInfo.cpp index 2aae26aa12..f1c44df975 100644 --- a/lib/Target/R600/MCTargetDesc/AMDGPUMCAsmInfo.cpp +++ b/lib/Target/R600/MCTargetDesc/AMDGPUMCAsmInfo.cpp @@ -11,7 +11,7 @@ #include "AMDGPUMCAsmInfo.h" using namespace llvm; -AMDGPUMCAsmInfo::AMDGPUMCAsmInfo(const Target &T, StringRef &TT) : MCAsmInfo() { +AMDGPUMCAsmInfo::AMDGPUMCAsmInfo(StringRef &TT) : MCAsmInfo() { HasSingleParameterDotFile = false; WeakDefDirective = 0; //===------------------------------------------------------------------===// diff --git a/lib/Target/R600/MCTargetDesc/AMDGPUMCAsmInfo.h b/lib/Target/R600/MCTargetDesc/AMDGPUMCAsmInfo.h index 3ad0fa6824..485167b3da 100644 --- a/lib/Target/R600/MCTargetDesc/AMDGPUMCAsmInfo.h +++ b/lib/Target/R600/MCTargetDesc/AMDGPUMCAsmInfo.h @@ -17,12 +17,11 @@ #include "llvm/MC/MCAsmInfo.h" namespace llvm { -class Target; class StringRef; class AMDGPUMCAsmInfo : public MCAsmInfo { public: - explicit AMDGPUMCAsmInfo(const Target &T, StringRef &TT); + explicit AMDGPUMCAsmInfo(StringRef &TT); const char* getDataASDirective(unsigned int Size, unsigned int AS) const; const MCSection* getNonexecutableStackSection(MCContext &CTX) const; }; diff --git a/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp b/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp index 3d4bfdcd5e..5a52abee03 100644 --- a/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp +++ b/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp @@ -18,7 +18,7 @@ using namespace llvm; void SparcELFMCAsmInfo::anchor() { } -SparcELFMCAsmInfo::SparcELFMCAsmInfo(const Target &T, StringRef TT) { +SparcELFMCAsmInfo::SparcELFMCAsmInfo(StringRef TT) { IsLittleEndian = false; Triple TheTriple(TT); if (TheTriple.getArch() == Triple::sparcv9) { diff --git a/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h b/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h index f0e1354c21..621e8ffadf 100644 --- a/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h +++ b/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h @@ -18,12 +18,11 @@ namespace llvm { class StringRef; - class Target; class SparcELFMCAsmInfo : public MCAsmInfo { virtual void anchor(); public: - explicit SparcELFMCAsmInfo(const Target &T, StringRef TT); + explicit SparcELFMCAsmInfo(StringRef TT); }; } // namespace llvm diff --git a/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp b/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp index c96a0d4c67..9e27aa004a 100644 --- a/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp +++ b/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp @@ -13,7 +13,7 @@ using namespace llvm; -SystemZMCAsmInfo::SystemZMCAsmInfo(const Target &T, StringRef TT) { +SystemZMCAsmInfo::SystemZMCAsmInfo(StringRef TT) { PointerSize = 8; CalleeSaveStackSlotSize = 8; IsLittleEndian = false; diff --git a/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.h b/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.h index bac1bca381..d440787de5 100644 --- a/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.h +++ b/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.h @@ -14,12 +14,11 @@ #include "llvm/Support/Compiler.h" namespace llvm { -class Target; class StringRef; class SystemZMCAsmInfo : public MCAsmInfo { public: - explicit SystemZMCAsmInfo(const Target &T, StringRef TT); + explicit SystemZMCAsmInfo(StringRef TT); // Override MCAsmInfo; virtual const MCSection *getNonexecutableStackSection(MCContext &Ctx) const diff --git a/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp b/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp index 49a7f47e7d..6844f92ec9 100644 --- a/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp +++ b/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp @@ -27,8 +27,8 @@ using namespace llvm; -static MCAsmInfo *createSystemZMCAsmInfo(const Target &T, StringRef TT) { - MCAsmInfo *MAI = new SystemZMCAsmInfo(T, TT); +static MCAsmInfo *createSystemZMCAsmInfo(StringRef TT) { + MCAsmInfo *MAI = new SystemZMCAsmInfo(TT); MachineLocation FPDst(MachineLocation::VirtualFP); MachineLocation FPSrc(SystemZ::R15D, -SystemZMC::CFAOffsetFromInitialSP); MAI->addInitialFrameState(0, FPDst, FPSrc); diff --git a/lib/Target/SystemZ/SystemZFrameLowering.cpp b/lib/Target/SystemZ/SystemZFrameLowering.cpp index fda33dee48..ab1d45f128 100644 --- a/lib/Target/SystemZ/SystemZFrameLowering.cpp +++ b/lib/Target/SystemZ/SystemZFrameLowering.cpp @@ -297,7 +297,6 @@ void SystemZFrameLowering::emitPrologue(MachineFunction &MF) const { SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>(); MachineBasicBlock::iterator MBBI = MBB.begin(); MachineModuleInfo &MMI = MF.getMMI(); - std::vector<MachineMove> &Moves = MMI.getFrameMoves(); const std::vector<CalleeSavedInfo> &CSI = MFFrame->getCalleeSavedInfo(); bool HasFP = hasFP(MF); DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); @@ -323,7 +322,7 @@ void SystemZFrameLowering::emitPrologue(MachineFunction &MF) const { int64_t Offset = SPOffsetFromCFA + RegSpillOffsets[Reg]; MachineLocation StackSlot(MachineLocation::VirtualFP, Offset); MachineLocation RegValue(Reg); - Moves.push_back(MachineMove(GPRSaveLabel, StackSlot, RegValue)); + MMI.addFrameMove(GPRSaveLabel, StackSlot, RegValue); } } } @@ -340,7 +339,7 @@ void SystemZFrameLowering::emitPrologue(MachineFunction &MF) const { .addSym(AdjustSPLabel); MachineLocation FPDest(MachineLocation::VirtualFP); MachineLocation FPSrc(MachineLocation::VirtualFP, SPOffsetFromCFA + Delta); - Moves.push_back(MachineMove(AdjustSPLabel, FPDest, FPSrc)); + MMI.addFrameMove(AdjustSPLabel, FPDest, FPSrc); SPOffsetFromCFA += Delta; } @@ -355,7 +354,7 @@ void SystemZFrameLowering::emitPrologue(MachineFunction &MF) const { .addSym(SetFPLabel); MachineLocation HardFP(SystemZ::R11D); MachineLocation VirtualFP(MachineLocation::VirtualFP); - Moves.push_back(MachineMove(SetFPLabel, HardFP, VirtualFP)); + MMI.addFrameMove(SetFPLabel, HardFP, VirtualFP); // Mark the FramePtr as live at the beginning of every block except // the entry block. (We'll have marked R11 as live on entry when @@ -386,7 +385,7 @@ void SystemZFrameLowering::emitPrologue(MachineFunction &MF) const { MachineLocation Slot(MachineLocation::VirtualFP, SPOffsetFromCFA + Offset); MachineLocation RegValue(Reg); - Moves.push_back(MachineMove(FPRSaveLabel, Slot, RegValue)); + MMI.addFrameMove(FPRSaveLabel, Slot, RegValue); } } // Complete the CFI for the FPR saves, modelling them as taking effect diff --git a/lib/Target/X86/AsmParser/X86AsmParser.cpp b/lib/Target/X86/AsmParser/X86AsmParser.cpp index 520c4c0048..019a670083 100644 --- a/lib/Target/X86/AsmParser/X86AsmParser.cpp +++ b/lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -2308,25 +2308,25 @@ MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, unsigned Match1, Match2, Match3, Match4; Match1 = MatchInstructionImpl(Operands, Inst, ErrorInfoIgnore, - isParsingIntelSyntax()); + MatchingInlineAsm, isParsingIntelSyntax()); // If this returned as a missing feature failure, remember that. if (Match1 == Match_MissingFeature) ErrorInfoMissingFeature = ErrorInfoIgnore; Tmp[Base.size()] = Suffixes[1]; Match2 = MatchInstructionImpl(Operands, Inst, ErrorInfoIgnore, - isParsingIntelSyntax()); + MatchingInlineAsm, isParsingIntelSyntax()); // If this returned as a missing feature failure, remember that. if (Match2 == Match_MissingFeature) ErrorInfoMissingFeature = ErrorInfoIgnore; Tmp[Base.size()] = Suffixes[2]; Match3 = MatchInstructionImpl(Operands, Inst, ErrorInfoIgnore, - isParsingIntelSyntax()); + MatchingInlineAsm, isParsingIntelSyntax()); // If this returned as a missing feature failure, remember that. if (Match3 == Match_MissingFeature) ErrorInfoMissingFeature = ErrorInfoIgnore; Tmp[Base.size()] = Suffixes[3]; Match4 = MatchInstructionImpl(Operands, Inst, ErrorInfoIgnore, - isParsingIntelSyntax()); + MatchingInlineAsm, isParsingIntelSyntax()); // If this returned as a missing feature failure, remember that. if (Match4 == Match_MissingFeature) ErrorInfoMissingFeature = ErrorInfoIgnore; diff --git a/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp b/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp index 5e84530cd7..226ebca8cb 100644 --- a/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp +++ b/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp @@ -263,7 +263,7 @@ static MCRegisterInfo *createX86MCRegisterInfo(StringRef TT) { return X; } -static MCAsmInfo *createX86MCAsmInfo(const Target &T, StringRef TT) { +static MCAsmInfo *createX86MCAsmInfo(StringRef TT) { Triple TheTriple(TT); bool is64Bit = TheTriple.getArch() == Triple::x86_64; diff --git a/lib/Target/X86/X86FrameLowering.cpp b/lib/Target/X86/X86FrameLowering.cpp index 42b4e73509..b9254d2ce3 100644 --- a/lib/Target/X86/X86FrameLowering.cpp +++ b/lib/Target/X86/X86FrameLowering.cpp @@ -312,7 +312,6 @@ void X86FrameLowering::emitCalleeSavedFrameMoves(MachineFunction &MF, const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo(); if (CSI.empty()) return; - std::vector<MachineMove> &Moves = MMI.getFrameMoves(); const X86RegisterInfo *RegInfo = TM.getRegisterInfo(); bool HasFP = hasFP(MF); @@ -362,7 +361,7 @@ void X86FrameLowering::emitCalleeSavedFrameMoves(MachineFunction &MF, MachineLocation CSDst(MachineLocation::VirtualFP, Offset); MachineLocation CSSrc(Reg); - Moves.push_back(MachineMove(Label, CSDst, CSSrc)); + MMI.addFrameMove(Label, CSDst, CSSrc); } } @@ -732,7 +731,6 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF) const { // REG < 64 => DW_CFA_offset + Reg // ELSE => DW_CFA_offset_extended - std::vector<MachineMove> &Moves = MMI.getFrameMoves(); uint64_t NumBytes = 0; int stackGrowth = -SlotSize; @@ -768,17 +766,17 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF) const { if (StackSize) { MachineLocation SPDst(MachineLocation::VirtualFP); MachineLocation SPSrc(MachineLocation::VirtualFP, 2 * stackGrowth); - Moves.push_back(MachineMove(FrameLabel, SPDst, SPSrc)); + MMI.addFrameMove(FrameLabel, SPDst, SPSrc); } else { MachineLocation SPDst(StackPtr); MachineLocation SPSrc(StackPtr, stackGrowth); - Moves.push_back(MachineMove(FrameLabel, SPDst, SPSrc)); + MMI.addFrameMove(FrameLabel, SPDst, SPSrc); } // Change the rule for the FramePtr to be an "offset" rule. MachineLocation FPDst(MachineLocation::VirtualFP, 2 * stackGrowth); MachineLocation FPSrc(FramePtr); - Moves.push_back(MachineMove(FrameLabel, FPDst, FPSrc)); + MMI.addFrameMove(FrameLabel, FPDst, FPSrc); } // Update EBP with the new base value. @@ -796,7 +794,7 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF) const { // Define the current CFA to use the EBP/RBP register. MachineLocation FPDst(FramePtr); MachineLocation FPSrc(MachineLocation::VirtualFP); - Moves.push_back(MachineMove(FrameLabel, FPDst, FPSrc)); + MMI.addFrameMove(FrameLabel, FPDst, FPSrc); } // Mark the FramePtr as live-in in every block except the entry. @@ -827,7 +825,7 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF) const { unsigned Ptr = StackSize ? MachineLocation::VirtualFP : StackPtr; MachineLocation SPDst(Ptr); MachineLocation SPSrc(Ptr, StackOffset); - Moves.push_back(MachineMove(Label, SPDst, SPSrc)); + MMI.addFrameMove(Label, SPDst, SPSrc); StackOffset += stackGrowth; } } @@ -965,11 +963,11 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF) const { MachineLocation SPDst(MachineLocation::VirtualFP); MachineLocation SPSrc(MachineLocation::VirtualFP, -StackSize + stackGrowth); - Moves.push_back(MachineMove(Label, SPDst, SPSrc)); + MMI.addFrameMove(Label, SPDst, SPSrc); } else { MachineLocation SPDst(StackPtr); MachineLocation SPSrc(StackPtr, stackGrowth); - Moves.push_back(MachineMove(Label, SPDst, SPSrc)); + MMI.addFrameMove(Label, SPDst, SPSrc); } } diff --git a/lib/Target/X86/X86InstrInfo.td b/lib/Target/X86/X86InstrInfo.td index 3380d8c64e..ad26bce01b 100644 --- a/lib/Target/X86/X86InstrInfo.td +++ b/lib/Target/X86/X86InstrInfo.td @@ -884,12 +884,12 @@ def PUSHF64 : I<0x9C, RawFrm, (outs), (ins), "pushfq", [], IIC_PUSH_F>, let Defs = [EDI, ESI, EBP, EBX, EDX, ECX, EAX, ESP], Uses = [ESP], mayLoad = 1, neverHasSideEffects = 1, SchedRW = [WriteLoad] in { -def POPA32 : I<0x61, RawFrm, (outs), (ins), "popa{l|d}", [], IIC_POP_A>, +def POPA32 : I<0x61, RawFrm, (outs), (ins), "popa{l}", [], IIC_POP_A>, Requires<[In32BitMode]>; } let Defs = [ESP], Uses = [EDI, ESI, EBP, EBX, EDX, ECX, EAX, ESP], mayStore = 1, neverHasSideEffects = 1, SchedRW = [WriteStore] in { -def PUSHA32 : I<0x60, RawFrm, (outs), (ins), "pusha{l|d}", [], IIC_PUSH_A>, +def PUSHA32 : I<0x60, RawFrm, (outs), (ins), "pusha{l}", [], IIC_PUSH_A>, Requires<[In32BitMode]>; } @@ -1867,6 +1867,9 @@ def : MnemonicAlias<"pushf", "pushfl", "att">, Requires<[In32BitMode]>; def : MnemonicAlias<"pushf", "pushfq", "att">, Requires<[In64BitMode]>; def : MnemonicAlias<"pushfd", "pushfl", "att">; +def : MnemonicAlias<"popad", "popa", "intel">, Requires<[In32BitMode]>; +def : MnemonicAlias<"pushad", "pusha", "intel">, Requires<[In32BitMode]>; + def : MnemonicAlias<"repe", "rep", "att">; def : MnemonicAlias<"repz", "rep", "att">; def : MnemonicAlias<"repnz", "repne", "att">; diff --git a/lib/Target/XCore/MCTargetDesc/XCoreMCAsmInfo.cpp b/lib/Target/XCore/MCTargetDesc/XCoreMCAsmInfo.cpp index 1cfdbda003..6f4455117a 100644 --- a/lib/Target/XCore/MCTargetDesc/XCoreMCAsmInfo.cpp +++ b/lib/Target/XCore/MCTargetDesc/XCoreMCAsmInfo.cpp @@ -13,7 +13,7 @@ using namespace llvm; void XCoreMCAsmInfo::anchor() { } -XCoreMCAsmInfo::XCoreMCAsmInfo(const Target &T, StringRef TT) { +XCoreMCAsmInfo::XCoreMCAsmInfo(StringRef TT) { SupportsDebugInformation = true; Data16bitsDirective = "\t.short\t"; Data32bitsDirective = "\t.long\t"; diff --git a/lib/Target/XCore/MCTargetDesc/XCoreMCAsmInfo.h b/lib/Target/XCore/MCTargetDesc/XCoreMCAsmInfo.h index 076777541e..b5a9660d5f 100644 --- a/lib/Target/XCore/MCTargetDesc/XCoreMCAsmInfo.h +++ b/lib/Target/XCore/MCTargetDesc/XCoreMCAsmInfo.h @@ -23,7 +23,7 @@ namespace llvm { class XCoreMCAsmInfo : public MCAsmInfo { virtual void anchor(); public: - explicit XCoreMCAsmInfo(const Target &T, StringRef TT); + explicit XCoreMCAsmInfo(StringRef TT); }; } // namespace llvm diff --git a/lib/Target/XCore/MCTargetDesc/XCoreMCTargetDesc.cpp b/lib/Target/XCore/MCTargetDesc/XCoreMCTargetDesc.cpp index c1773653f5..e38da34a81 100644 --- a/lib/Target/XCore/MCTargetDesc/XCoreMCTargetDesc.cpp +++ b/lib/Target/XCore/MCTargetDesc/XCoreMCTargetDesc.cpp @@ -51,8 +51,8 @@ static MCSubtargetInfo *createXCoreMCSubtargetInfo(StringRef TT, StringRef CPU, return X; } -static MCAsmInfo *createXCoreMCAsmInfo(const Target &T, StringRef TT) { - MCAsmInfo *MAI = new XCoreMCAsmInfo(T, TT); +static MCAsmInfo *createXCoreMCAsmInfo(StringRef TT) { + MCAsmInfo *MAI = new XCoreMCAsmInfo(TT); // Initial state of the frame pointer is SP. MachineLocation Dst(MachineLocation::VirtualFP); diff --git a/lib/Target/XCore/XCoreFrameLowering.cpp b/lib/Target/XCore/XCoreFrameLowering.cpp index 8cd10b4e74..9798411381 100644 --- a/lib/Target/XCore/XCoreFrameLowering.cpp +++ b/lib/Target/XCore/XCoreFrameLowering.cpp @@ -132,7 +132,6 @@ void XCoreFrameLowering::emitPrologue(MachineFunction &MF) const { BuildMI(MBB, MBBI, dl, TII.get(Opcode)).addImm(FrameSize); if (emitFrameMoves) { - std::vector<MachineMove> &Moves = MMI->getFrameMoves(); // Show update of SP. MCSymbol *FrameLabel = MMI->getContext().CreateTempSymbol(); @@ -140,12 +139,12 @@ void XCoreFrameLowering::emitPrologue(MachineFunction &MF) const { MachineLocation SPDst(MachineLocation::VirtualFP); MachineLocation SPSrc(MachineLocation::VirtualFP, -FrameSize * 4); - Moves.push_back(MachineMove(FrameLabel, SPDst, SPSrc)); + MMI->addFrameMove(FrameLabel, SPDst, SPSrc); if (LRSavedOnEntry) { MachineLocation CSDst(MachineLocation::VirtualFP, 0); MachineLocation CSSrc(XCore::LR); - Moves.push_back(MachineMove(FrameLabel, CSDst, CSSrc)); + MMI->addFrameMove(FrameLabel, CSDst, CSSrc); } } } @@ -159,7 +158,7 @@ void XCoreFrameLowering::emitPrologue(MachineFunction &MF) const { BuildMI(MBB, MBBI, dl, TII.get(XCore::PROLOG_LABEL)).addSym(SaveLRLabel); MachineLocation CSDst(MachineLocation::VirtualFP, LRSpillOffset); MachineLocation CSSrc(XCore::LR); - MMI->getFrameMoves().push_back(MachineMove(SaveLRLabel, CSDst, CSSrc)); + MMI->addFrameMove(SaveLRLabel, CSDst, CSSrc); } } @@ -174,7 +173,7 @@ void XCoreFrameLowering::emitPrologue(MachineFunction &MF) const { BuildMI(MBB, MBBI, dl, TII.get(XCore::PROLOG_LABEL)).addSym(SaveR10Label); MachineLocation CSDst(MachineLocation::VirtualFP, FPSpillOffset); MachineLocation CSSrc(XCore::R10); - MMI->getFrameMoves().push_back(MachineMove(SaveR10Label, CSDst, CSSrc)); + MMI->addFrameMove(SaveR10Label, CSDst, CSSrc); } // Set the FP from the SP. unsigned FramePtr = XCore::R10; @@ -186,13 +185,12 @@ void XCoreFrameLowering::emitPrologue(MachineFunction &MF) const { BuildMI(MBB, MBBI, dl, TII.get(XCore::PROLOG_LABEL)).addSym(FrameLabel); MachineLocation SPDst(FramePtr); MachineLocation SPSrc(MachineLocation::VirtualFP); - MMI->getFrameMoves().push_back(MachineMove(FrameLabel, SPDst, SPSrc)); + MMI->addFrameMove(FrameLabel, SPDst, SPSrc); } } if (emitFrameMoves) { // Frame moves for callee saved. - std::vector<MachineMove> &Moves = MMI->getFrameMoves(); std::vector<std::pair<MCSymbol*, CalleeSavedInfo> >&SpillLabels = XFI->getSpillLabels(); for (unsigned I = 0, E = SpillLabels.size(); I != E; ++I) { @@ -202,7 +200,7 @@ void XCoreFrameLowering::emitPrologue(MachineFunction &MF) const { unsigned Reg = CSI.getReg(); MachineLocation CSDst(MachineLocation::VirtualFP, Offset); MachineLocation CSSrc(Reg); - Moves.push_back(MachineMove(SpillLabel, CSDst, CSSrc)); + MMI->addFrameMove(SpillLabel, CSDst, CSSrc); } } } diff --git a/lib/Transforms/InstCombine/InstCombineCasts.cpp b/lib/Transforms/InstCombine/InstCombineCasts.cpp index 2ee1278d23..361acdde81 100644 --- a/lib/Transforms/InstCombine/InstCombineCasts.cpp +++ b/lib/Transforms/InstCombine/InstCombineCasts.cpp @@ -677,7 +677,6 @@ static bool CanEvaluateZExtd(Value *V, Type *Ty, unsigned &BitsToClear) { case Instruction::Add: case Instruction::Sub: case Instruction::Mul: - case Instruction::Shl: if (!CanEvaluateZExtd(I->getOperand(0), Ty, BitsToClear) || !CanEvaluateZExtd(I->getOperand(1), Ty, Tmp)) return false; @@ -701,6 +700,17 @@ static bool CanEvaluateZExtd(Value *V, Type *Ty, unsigned &BitsToClear) { // Otherwise, we don't know how to analyze this BitsToClear case yet. return false; + case Instruction::Shl: + // We can promote shl(x, cst) if we can promote x. Since shl overwrites the + // upper bits we can reduce BitsToClear by the shift amount. + if (ConstantInt *Amt = dyn_cast<ConstantInt>(I->getOperand(1))) { + if (!CanEvaluateZExtd(I->getOperand(0), Ty, BitsToClear)) + return false; + uint64_t ShiftAmt = Amt->getZExtValue(); + BitsToClear = ShiftAmt < BitsToClear ? BitsToClear - ShiftAmt : 0; + return true; + } + return false; case Instruction::LShr: // We can promote lshr(x, cst) if we can promote x. This requires the // ultimate 'and' to clear out the high zero bits we're clearing out though. diff --git a/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp index ecc9fc3e45..87d56214a3 100644 --- a/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ b/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -1027,37 +1027,19 @@ Instruction *InstCombiner::visitURem(BinaryOperator &I) { if (Instruction *common = commonIRemTransforms(I)) return common; - // X urem C^2 -> X and C-1 - { const APInt *C; - if (match(Op1, m_Power2(C))) - return BinaryOperator::CreateAnd(Op0, - ConstantInt::get(I.getType(), *C-1)); - } - - // Turn A % (C << N), where C is 2^k, into A & ((C << N)-1) - if (match(Op1, m_Shl(m_Power2(), m_Value()))) { - Constant *N1 = Constant::getAllOnesValue(I.getType()); - Value *Add = Builder->CreateAdd(Op1, N1); - return BinaryOperator::CreateAnd(Op0, Add); - } - - // urem X, (select Cond, 2^C1, 2^C2) --> - // select Cond, (and X, C1-1), (and X, C2-1) - // when C1&C2 are powers of two. - { Value *Cond; const APInt *C1, *C2; - if (match(Op1, m_Select(m_Value(Cond), m_Power2(C1), m_Power2(C2)))) { - Value *TrueAnd = Builder->CreateAnd(Op0, *C1-1, Op1->getName()+".t"); - Value *FalseAnd = Builder->CreateAnd(Op0, *C2-1, Op1->getName()+".f"); - return SelectInst::Create(Cond, TrueAnd, FalseAnd); - } - } - // (zext A) urem (zext B) --> zext (A urem B) if (ZExtInst *ZOp0 = dyn_cast<ZExtInst>(Op0)) if (Value *ZOp1 = dyn_castZExtVal(Op1, ZOp0->getSrcTy())) return new ZExtInst(Builder->CreateURem(ZOp0->getOperand(0), ZOp1), I.getType()); + // X urem Y -> X and Y-1, where Y is a power of 2, + if (isKnownToBeAPowerOfTwo(Op1, /*OrZero*/true)) { + Constant *N1 = Constant::getAllOnesValue(I.getType()); + Value *Add = Builder->CreateAdd(Op1, N1); + return BinaryOperator::CreateAnd(Op0, Add); + } + return 0; } diff --git a/lib/Transforms/Vectorize/LoopVectorize.cpp b/lib/Transforms/Vectorize/LoopVectorize.cpp index b16b371878..0dd6abb1ae 100644 --- a/lib/Transforms/Vectorize/LoopVectorize.cpp +++ b/lib/Transforms/Vectorize/LoopVectorize.cpp @@ -312,6 +312,8 @@ private: PHINode *Induction; /// The induction variable of the old basic block. PHINode *OldInduction; + /// Holds the extended (to the widest induction type) start index. + Value *ExtendedIdx; /// Maps scalars to widened vectors. ValueMap WidenMap; }; @@ -335,7 +337,7 @@ public: DominatorTree *DT, TargetTransformInfo* TTI, AliasAnalysis *AA, TargetLibraryInfo *TLI) : TheLoop(L), SE(SE), DL(DL), DT(DT), TTI(TTI), AA(AA), TLI(TLI), - Induction(0), HasFunNoNaNAttr(false) {} + Induction(0), WidestIndTy(0), HasFunNoNaNAttr(false) {} /// This enum represents the kinds of reductions that we support. enum ReductionKind { @@ -473,6 +475,9 @@ public: /// Returns the induction variables found in the loop. InductionList *getInductionVars() { return &Inductions; } + /// Returns the widest induction type. + Type *getWidestInductionType() { return WidestIndTy; } + /// Returns True if V is an induction variable in this loop. bool isInductionVariable(const Value *V); @@ -579,6 +584,8 @@ private: /// Notice that inductions don't need to start at zero and that induction /// variables can be pointers. InductionList Inductions; + /// Holds the widest induction type encountered. + Type *WidestIndTy; /// Allowed outside users. This holds the reduction /// vars which can be accessed from outside the loop. @@ -1243,8 +1250,7 @@ InnerLoopVectorizer::createEmptyLoop(LoopVectorizationLegality *Legal) { // induction variables. In the code below we also support a case where we // don't have a single induction variable. OldInduction = Legal->getInduction(); - Type *IdxTy = OldInduction ? OldInduction->getType() : - DL->getIntPtrType(SE->getContext()); + Type *IdxTy = Legal->getWidestInductionType(); // Find the loop boundaries. const SCEV *ExitCount = SE->getExitCount(OrigLoop, OrigLoop->getLoopLatch()); @@ -1265,9 +1271,11 @@ InnerLoopVectorizer::createEmptyLoop(LoopVectorizationLegality *Legal) { // The loop index does not have to start at Zero. Find the original start // value from the induction PHI node. If we don't have an induction variable // then we know that it starts at zero. - Value *StartIdx = OldInduction ? - OldInduction->getIncomingValueForBlock(BypassBlock): - ConstantInt::get(IdxTy, 0); + Builder.SetInsertPoint(BypassBlock->getTerminator()); + Value *StartIdx = ExtendedIdx = OldInduction ? + Builder.CreateZExt(OldInduction->getIncomingValueForBlock(BypassBlock), + IdxTy): + ConstantInt::get(IdxTy, 0); assert(BypassBlock && "Invalid loop structure"); LoopBypassBlocks.push_back(BypassBlock); @@ -1361,11 +1369,21 @@ InnerLoopVectorizer::createEmptyLoop(LoopVectorizationLegality *Legal) { PHINode *ResumeIndex = 0; LoopVectorizationLegality::InductionList::iterator I, E; LoopVectorizationLegality::InductionList *List = Legal->getInductionVars(); + // Set builder to point to last bypass block. + BypassBuilder.SetInsertPoint(LoopBypassBlocks.back()->getTerminator()); for (I = List->begin(), E = List->end(); I != E; ++I) { PHINode *OrigPhi = I->first; LoopVectorizationLegality::InductionInfo II = I->second; - PHINode *ResumeVal = PHINode::Create(OrigPhi->getType(), 2, "resume.val", + + Type *ResumeValTy = (OrigPhi == OldInduction) ? IdxTy : OrigPhi->getType(); + PHINode *ResumeVal = PHINode::Create(ResumeValTy, 2, "resume.val", MiddleBlock->getTerminator()); + // We might have extended the type of the induction variable but we need a + // truncated version for the scalar loop. + PHINode *TruncResumeVal = (OrigPhi == OldInduction) ? + PHINode::Create(OrigPhi->getType(), 2, "trunc.resume.val", + MiddleBlock->getTerminator()) : 0; + Value *EndValue = 0; switch (II.IK) { case LoopVectorizationLegality::IK_NoInduction: @@ -1374,6 +1392,17 @@ InnerLoopVectorizer::createEmptyLoop(LoopVectorizationLegality *Legal) { // Handle the integer induction counter: assert(OrigPhi->getType()->isIntegerTy() && "Invalid type"); assert(OrigPhi == OldInduction && "Unknown integer PHI"); + if (OrigPhi == OldInduction) { + // Create a truncated version of the resume value for the scalar loop, + // we might have promoted the type to a larger width. + EndValue = + BypassBuilder.CreateTrunc(IdxEndRoundDown, OrigPhi->getType()); + // The new PHI merges the original incoming value, in case of a bypass, + // or the value at the end of the vectorized loop. + for (unsigned I = 0, E = LoopBypassBlocks.size(); I != E; ++I) + TruncResumeVal->addIncoming(II.StartValue, LoopBypassBlocks[I]); + TruncResumeVal->addIncoming(EndValue, VecBody); + } // We know what the end value is. EndValue = IdxEndRoundDown; // We also know which PHI node holds it. @@ -1382,55 +1411,49 @@ InnerLoopVectorizer::createEmptyLoop(LoopVectorizationLegality *Legal) { } case LoopVectorizationLegality::IK_ReverseIntInduction: { // Convert the CountRoundDown variable to the PHI size. - unsigned CRDSize = CountRoundDown->getType()->getScalarSizeInBits(); - unsigned IISize = II.StartValue->getType()->getScalarSizeInBits(); - Value *CRD = CountRoundDown; - if (CRDSize > IISize) - CRD = CastInst::Create(Instruction::Trunc, CountRoundDown, - II.StartValue->getType(), "tr.crd", - LoopBypassBlocks.back()->getTerminator()); - else if (CRDSize < IISize) - CRD = CastInst::Create(Instruction::SExt, CountRoundDown, - II.StartValue->getType(), - "sext.crd", - LoopBypassBlocks.back()->getTerminator()); - // Handle reverse integer induction counter: - EndValue = - BinaryOperator::CreateSub(II.StartValue, CRD, "rev.ind.end", - LoopBypassBlocks.back()->getTerminator()); + Value *CRD = BypassBuilder.CreateSExtOrTrunc(CountRoundDown, + II.StartValue->getType(), + "cast.crd"); + // Handle reverse integer induction counter. + EndValue = BypassBuilder.CreateSub(II.StartValue, CRD, "rev.ind.end"); break; } case LoopVectorizationLegality::IK_PtrInduction: { // For pointer induction variables, calculate the offset using // the end index. - EndValue = - GetElementPtrInst::Create(II.StartValue, CountRoundDown, "ptr.ind.end", - LoopBypassBlocks.back()->getTerminator()); + EndValue = BypassBuilder.CreateGEP(II.StartValue, CountRoundDown, + "ptr.ind.end"); break; } case LoopVectorizationLegality::IK_ReversePtrInduction: { // The value at the end of the loop for the reverse pointer is calculated // by creating a GEP with a negative index starting from the start value. Value *Zero = ConstantInt::get(CountRoundDown->getType(), 0); - Value *NegIdx = BinaryOperator::CreateSub(Zero, CountRoundDown, - "rev.ind.end", - LoopBypassBlocks.back()->getTerminator()); - EndValue = GetElementPtrInst::Create(II.StartValue, NegIdx, - "rev.ptr.ind.end", - LoopBypassBlocks.back()->getTerminator()); + Value *NegIdx = BypassBuilder.CreateSub(Zero, CountRoundDown, + "rev.ind.end"); + EndValue = BypassBuilder.CreateGEP(II.StartValue, NegIdx, + "rev.ptr.ind.end"); break; } }// end of case // The new PHI merges the original incoming value, in case of a bypass, // or the value at the end of the vectorized loop. - for (unsigned I = 0, E = LoopBypassBlocks.size(); I != E; ++I) - ResumeVal->addIncoming(II.StartValue, LoopBypassBlocks[I]); + for (unsigned I = 0, E = LoopBypassBlocks.size(); I != E; ++I) { + if (OrigPhi == OldInduction) + ResumeVal->addIncoming(StartIdx, LoopBypassBlocks[I]); + else + ResumeVal->addIncoming(II.StartValue, LoopBypassBlocks[I]); + } ResumeVal->addIncoming(EndValue, VecBody); // Fix the scalar body counter (PHI node). unsigned BlockIdx = OrigPhi->getBasicBlockIndex(ScalarPH); - OrigPhi->setIncomingValue(BlockIdx, ResumeVal); + // The old inductions phi node in the scalar body needs the truncated value. + if (OrigPhi == OldInduction) + OrigPhi->setIncomingValue(BlockIdx, TruncResumeVal); + else + OrigPhi->setIncomingValue(BlockIdx, ResumeVal); } // If we are generating a new induction variable then we also need to @@ -2034,7 +2057,9 @@ InnerLoopVectorizer::vectorizeBlockInLoop(LoopVectorizationLegality *Legal, llvm_unreachable("Unknown induction"); case LoopVectorizationLegality::IK_IntInduction: { assert(P == OldInduction && "Unexpected PHI"); - Value *Broadcasted = getBroadcastInstrs(Induction); + // We might have had to extend the type. + Value *Trunc = Builder.CreateTrunc(Induction, P->getType()); + Value *Broadcasted = getBroadcastInstrs(Trunc); // After broadcasting the induction variable we need to make the // vector consecutive by adding 0, 1, 2 ... for (unsigned part = 0; part < UF; ++part) @@ -2045,16 +2070,7 @@ InnerLoopVectorizer::vectorizeBlockInLoop(LoopVectorizationLegality *Legal, case LoopVectorizationLegality::IK_PtrInduction: case LoopVectorizationLegality::IK_ReversePtrInduction: // Handle reverse integer and pointer inductions. - Value *StartIdx = 0; - // If we have a single integer induction variable then use it. - // Otherwise, start counting at zero. - if (OldInduction) { - LoopVectorizationLegality::InductionInfo OldII = - Legal->getInductionVars()->lookup(OldInduction); - StartIdx = OldII.StartValue; - } else { - StartIdx = ConstantInt::get(Induction->getType(), 0); - } + Value *StartIdx = ExtendedIdx; // This is the normalized GEP that starts counting at zero. Value *NormalizedIdx = Builder.CreateSub(Induction, StartIdx, "normalized.idx"); @@ -2374,6 +2390,20 @@ bool LoopVectorizationLegality::canVectorize() { return true; } +static Type *convertPointerToIntegerType(DataLayout &DL, Type *Ty) { + if (Ty->isPointerTy()) + return DL.getIntPtrType(Ty->getContext()); + return Ty; +} + +static Type* getWiderType(DataLayout &DL, Type *Ty0, Type *Ty1) { + Ty0 = convertPointerToIntegerType(DL, Ty0); + Ty1 = convertPointerToIntegerType(DL, Ty1); + if (Ty0->getScalarSizeInBits() > Ty1->getScalarSizeInBits()) + return Ty0; + return Ty1; +} + bool LoopVectorizationLegality::canVectorizeInstrs() { BasicBlock *PreHeader = TheLoop->getLoopPreheader(); BasicBlock *Header = TheLoop->getHeader(); @@ -2401,10 +2431,11 @@ bool LoopVectorizationLegality::canVectorizeInstrs() { ++it) { if (PHINode *Phi = dyn_cast<PHINode>(it)) { + Type *PhiTy = Phi->getType(); // Check that this PHI type is allowed. - if (!Phi->getType()->isIntegerTy() && - !Phi->getType()->isFloatingPointTy() && - !Phi->getType()->isPointerTy()) { + if (!PhiTy->isIntegerTy() && + !PhiTy->isFloatingPointTy() && + !PhiTy->isPointerTy()) { DEBUG(dbgs() << "LV: Found an non-int non-pointer PHI.\n"); return false; } @@ -2427,6 +2458,12 @@ bool LoopVectorizationLegality::canVectorizeInstrs() { InductionKind IK = isInductionVariable(Phi); if (IK_NoInduction != IK) { + // Get the widest type. + if (!WidestIndTy) + WidestIndTy = convertPointerToIntegerType(*DL, PhiTy); + else + WidestIndTy = getWiderType(*DL, PhiTy, WidestIndTy); + // Int inductions are special because we only allow one IV. if (IK == IK_IntInduction) { if (Induction) { diff --git a/lib/Transforms/Vectorize/SLPVectorizer.cpp b/lib/Transforms/Vectorize/SLPVectorizer.cpp index cc30cc9278..4e89ac7c09 100644 --- a/lib/Transforms/Vectorize/SLPVectorizer.cpp +++ b/lib/Transforms/Vectorize/SLPVectorizer.cpp @@ -77,6 +77,8 @@ struct SLPVectorizer : public FunctionPass { if (!DL) return false; + DEBUG(dbgs()<<"SLP: Analyzing blocks in " << F.getName() << ".\n"); + for (Function::iterator it = F.begin(), e = F.end(); it != e; ++it) { BasicBlock *BB = it; bool BBChanged = false; diff --git a/lib/Transforms/Vectorize/VecUtils.cpp b/lib/Transforms/Vectorize/VecUtils.cpp index 9b9436683b..55adf8a816 100644 --- a/lib/Transforms/Vectorize/VecUtils.cpp +++ b/lib/Transforms/Vectorize/VecUtils.cpp @@ -243,6 +243,10 @@ int BoUpSLP::getTreeCost(ArrayRef<Value *> VL) { LaneMap.clear(); MultiUserVals.clear(); MustScalarize.clear(); + MustExtract.clear(); + + // Find the location of the last root. + unsigned LastRootIndex = InstrIdx[GetLastInstr(VL, VL.size())]; // Scan the tree and find which value is used by which lane, and which values // must be scalarized. @@ -258,15 +262,31 @@ int BoUpSLP::getTreeCost(ArrayRef<Value *> VL) { for (Value::use_iterator I = (*it)->use_begin(), E = (*it)->use_end(); I != E; ++I) { if (LaneMap.find(*I) == LaneMap.end()) { - MustScalarize.insert(*it); - DEBUG(dbgs()<<"SLP: Adding " << **it << - " to MustScalarize because of an out of tree usage.\n"); - break; + DEBUG(dbgs()<<"SLP: Instr " << **it << " has multiple users.\n"); + + // We don't have an ordering problem if the user is not in this basic + // block. + Instruction *Inst = cast<Instruction>(*I); + if (Inst->getParent() == BB) { + // We don't have an ordering problem if the user is after the last + // root. + unsigned Idx = InstrIdx[Inst]; + if (Idx < LastRootIndex) { + MustScalarize.insert(*it); + DEBUG(dbgs()<<"SLP: Adding to MustScalarize " + "because of an unsafe out of tree usage.\n"); + break; + } + } + + DEBUG(dbgs()<<"SLP: Adding to MustExtract " + "because of a safe out of tree usage.\n"); + MustExtract.insert(*it); } if (Lane == -1) Lane = LaneMap[*I]; if (Lane != LaneMap[*I]) { MustScalarize.insert(*it); - DEBUG(dbgs()<<"Adding " << **it << + DEBUG(dbgs()<<"SLP: Adding " << **it << " to MustScalarize because multiple lane use it: " << Lane << " and " << LaneMap[*I] << ".\n"); break; @@ -456,6 +476,13 @@ int BoUpSLP::getTreeCost_rec(ArrayRef<Value *> VL, unsigned Depth) { } } + // Calculate the extract cost. + unsigned ExternalUserExtractCost = 0; + for (unsigned i = 0, e = VL.size(); i < e; ++i) + if (MustExtract.count(VL[i])) + ExternalUserExtractCost += + TTI->getVectorInstrCost(Instruction::ExtractElement, VecTy, i); + switch (Opcode) { case Instruction::ZExt: case Instruction::SExt: @@ -469,7 +496,7 @@ int BoUpSLP::getTreeCost_rec(ArrayRef<Value *> VL, unsigned Depth) { case Instruction::Trunc: case Instruction::FPTrunc: case Instruction::BitCast: { - int Cost = 0; + int Cost = ExternalUserExtractCost; ValueList Operands; Type *SrcTy = VL0->getOperand(0)->getType(); // Prepare the operand vector. @@ -510,7 +537,7 @@ int BoUpSLP::getTreeCost_rec(ArrayRef<Value *> VL, unsigned Depth) { case Instruction::And: case Instruction::Or: case Instruction::Xor: { - int Cost = 0; + int Cost = ExternalUserExtractCost; // Calculate the cost of all of the operands. for (unsigned i = 0, e = VL0->getNumOperands(); i < e; ++i) { ValueList Operands; @@ -540,7 +567,7 @@ int BoUpSLP::getTreeCost_rec(ArrayRef<Value *> VL, unsigned Depth) { int ScalarLdCost = VecTy->getNumElements() * TTI->getMemoryOpCost(Instruction::Load, ScalarTy, 1, 0); int VecLdCost = TTI->getMemoryOpCost(Instruction::Load, ScalarTy, 1, 0); - return VecLdCost - ScalarLdCost; + return VecLdCost - ScalarLdCost + ExternalUserExtractCost; } case Instruction::Store: { // We know that we can merge the stores. Calculate the cost. @@ -556,7 +583,7 @@ int BoUpSLP::getTreeCost_rec(ArrayRef<Value *> VL, unsigned Depth) { } int TotalCost = StoreCost + getTreeCost_rec(Operands, Depth + 1); - return TotalCost; + return TotalCost + ExternalUserExtractCost; } default: // Unable to vectorize unknown instructions. @@ -588,10 +615,24 @@ Value *BoUpSLP::Scalarize(ArrayRef<Value *> VL, VectorType *Ty) { Value *BoUpSLP::vectorizeTree(ArrayRef<Value *> VL, int VF) { Value *V = vectorizeTree_rec(VL, VF); + + Instruction *LastInstr = GetLastInstr(VL, VL.size()); + IRBuilder<> Builder(LastInstr); + for (ValueSet::iterator it = MustExtract.begin(), e = MustExtract.end(); + it != e; ++it) { + Instruction *I = cast<Instruction>(*it); + Value *Vec = VectorizedValues[I]; + assert(LaneMap.count(I) && "Unable to find the lane for the external use"); + Value *Idx = Builder.getInt32(LaneMap[I]); + Value *Extract = Builder.CreateExtractElement(Vec, Idx); + I->replaceAllUsesWith(Extract); + } + // We moved some instructions around. We have to number them again // before we can do any analysis. numberInstructions(); MustScalarize.clear(); + MustExtract.clear(); return V; } diff --git a/lib/Transforms/Vectorize/VecUtils.h b/lib/Transforms/Vectorize/VecUtils.h index 5456c6c779..abb35840e9 100644 --- a/lib/Transforms/Vectorize/VecUtils.h +++ b/lib/Transforms/Vectorize/VecUtils.h @@ -127,6 +127,11 @@ private: /// NOTICE: The vectorization methods also use this set. ValueSet MustScalarize; + /// Contains values that have users outside of the vectorized graph. + /// We need to generate extract instructions for these values. + /// NOTICE: The vectorization methods also use this set. + ValueSet MustExtract; + /// Contains a list of values that are used outside the current tree. This /// set must be reset between runs. ValueSet MultiUserVals; diff --git a/test/CodeGen/Hexagon/pred-gp.ll b/test/CodeGen/Hexagon/pred-gp.ll new file mode 100644 index 0000000000..299bd8679d --- /dev/null +++ b/test/CodeGen/Hexagon/pred-gp.ll @@ -0,0 +1,28 @@ +; RUN: llc -march=hexagon -mcpu=hexagonv4 < %s | FileCheck %s +; Check that we are able to predicate instructions with gp-relative +; addressing mode. + +@d = external global i32 +@c = common global i32 0, align 4 + +; Function Attrs: nounwind +define i32 @test2(i8 zeroext %a, i8 zeroext %b) #0 { +; CHECK: if{{ *}}({{!*}}p{{[0-3]+}}{{[.new]*}}){{ *}}r{{[0-9]+}}{{ *}}={{ *}}memw(##{{[cd]}}) +; CHECK: if{{ *}}({{!*}}p{{[0-3]+}}){{ *}}r{{[0-9]+}}{{ *}}={{ *}}memw(##{{[cd]}}) +entry: + %cmp = icmp eq i8 %a, %b + br i1 %cmp, label %if.then, label %entry.if.end_crit_edge + +entry.if.end_crit_edge: + %.pre = load i32* @c, align 4 + br label %if.end + +if.then: + %0 = load i32* @d, align 4 + store i32 %0, i32* @c, align 4 + br label %if.end + +if.end: + %1 = phi i32 [ %.pre, %entry.if.end_crit_edge ], [ %0, %if.then ] + ret i32 %1 +} diff --git a/test/CodeGen/Mips/mips16_fpret.ll b/test/CodeGen/Mips/mips16_fpret.ll new file mode 100644 index 0000000000..9113329396 --- /dev/null +++ b/test/CodeGen/Mips/mips16_fpret.ll @@ -0,0 +1,77 @@ +; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mcpu=mips16 -soft-float -mips16-hard-float -relocation-model=static < %s | FileCheck %s -check-prefix=1 +; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mcpu=mips16 -soft-float -mips16-hard-float -relocation-model=static < %s | FileCheck %s -check-prefix=2 +; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mcpu=mips16 -soft-float -mips16-hard-float -relocation-model=static < %s | FileCheck %s -check-prefix=3 +; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mcpu=mips16 -soft-float -mips16-hard-float -relocation-model=static < %s | FileCheck %s -check-prefix=4 + + +@x = global float 0x41F487E980000000, align 4 +@dx = global double 0x41CDCC8BC4800000, align 8 +@cx = global { float, float } { float 1.000000e+00, float 9.900000e+01 }, align 4 +@dcx = global { double, double } { double 0x42CE5E14A412B480, double 0x423AA4C580DB0000 }, align 8 + +define float @foox() { +entry: + %0 = load float* @x, align 4 + ret float %0 +; 1: .ent foox +; 1: lw $2, %lo(x)(${{[0-9]+}}) +; 1: jal __mips16_ret_sf +} + +define double @foodx() { +entry: + %0 = load double* @dx, align 8 + ret double %0 +; 1: .ent foodx +; 1: lw $2, %lo(dx)(${{[0-9]+}}) +; 1: jal __mips16_ret_df +; 2: .ent foodx +; 2: lw $3, 4(${{[0-9]+}}) +; 2: jal __mips16_ret_df + +} + +define { float, float } @foocx() { +entry: + %retval = alloca { float, float }, align 4 + %cx.real = load float* getelementptr inbounds ({ float, float }* @cx, i32 0, i32 0) + %cx.imag = load float* getelementptr inbounds ({ float, float }* @cx, i32 0, i32 1) + %real = getelementptr inbounds { float, float }* %retval, i32 0, i32 0 + %imag = getelementptr inbounds { float, float }* %retval, i32 0, i32 1 + store float %cx.real, float* %real + store float %cx.imag, float* %imag + %0 = load { float, float }* %retval + ret { float, float } %0 +; 1: .ent foocx +; 1: lw $2, %lo(cx)(${{[0-9]+}}) +; 1: jal __mips16_ret_sc +; 2: .ent foocx +; 2: lw $3, 4(${{[0-9]+}}) +; 2: jal __mips16_ret_sc +} + +define { double, double } @foodcx() { +entry: + %retval = alloca { double, double }, align 8 + %dcx.real = load double* getelementptr inbounds ({ double, double }* @dcx, i32 0, i32 0) + %dcx.imag = load double* getelementptr inbounds ({ double, double }* @dcx, i32 0, i32 1) + %real = getelementptr inbounds { double, double }* %retval, i32 0, i32 0 + %imag = getelementptr inbounds { double, double }* %retval, i32 0, i32 1 + store double %dcx.real, double* %real + store double %dcx.imag, double* %imag + %0 = load { double, double }* %retval + ret { double, double } %0 +; 1: .ent foodcx +; 1: lw $2, %lo(dcx)(${{[0-9]+}}) +; 1: jal __mips16_ret_dc +; 2: .ent foodcx +; 2: lw $3, 4(${{[0-9]+}}) +; 2: jal __mips16_ret_dc +; 3: .ent foodcx +; 3: lw $4, 8(${{[0-9]+}}) +; 3: jal __mips16_ret_dc +; 4: .ent foodcx +; 4: lw $5, 12(${{[0-9]+}}) +; 4: jal __mips16_ret_dc +} + diff --git a/test/CodeGen/X86/xor.ll b/test/CodeGen/X86/xor.ll index 2408bfe72c..574bb7817e 100644 --- a/test/CodeGen/X86/xor.ll +++ b/test/CodeGen/X86/xor.ll @@ -154,3 +154,14 @@ define i32 @test9(i32 %a) nounwind { ; X32: notl [[REG:%[a-z]+]] ; X32: andl {{.*}}[[REG:%[a-z]+]] } + +; PR15948 +define <4 x i32> @test10(<4 x i32> %a) nounwind { + %1 = and <4 x i32> %a, <i32 4096, i32 4096, i32 4096, i32 4096> + %2 = xor <4 x i32> %1, <i32 4096, i32 4096, i32 4096, i32 4096> + ret <4 x i32> %2 +; X64: test10: +; X64: andnps +; X32: test10: +; X32: andnps +} diff --git a/test/DebugInfo/X86/template.ll b/test/DebugInfo/X86/template.ll new file mode 100644 index 0000000000..817bdc9cf7 --- /dev/null +++ b/test/DebugInfo/X86/template.ll @@ -0,0 +1,84 @@ +; REQUIRES: object-emission + +; RUN: llc -mtriple=x86_64-linux -O0 -filetype=obj < %s > %t +; RUN: llvm-dwarfdump %t | FileCheck %s + +; IR generated with `clang++ -g -emit-llvm -S` from the following code: +; template<int, int* x> func() { } +; int glbl = func<3, &glbl>(); + +; CHECK: [[INT:0x[0-9a-f]*]]:{{ *}}DW_TAG_base_type +; CHECK-NEXT: DW_AT_name{{.*}} = "int" + +; CHECK: DW_AT_name{{.*}}"func<3, &glbl>" +; CHECK-NOT: NULL +; CHECK: DW_TAG_template_value_parameter +; CHECK-NEXT: DW_AT_type{{.*}}=> {[[INT]]} +; CHECK-NEXT: DW_AT_name{{.*}}= "x" + +; This could be made shorter by encoding it as _sdata rather than data4, or +; even as data1. DWARF strongly urges implementations to prefer +; _sdata/_udata rather than dataN + +; CHECK-NEXT: DW_AT_const_value [DW_FORM_data4]{{.*}}(0x00000003) + +; CHECK: DW_TAG_template_value_parameter +; CHECK-NEXT: DW_AT_type{{.*}}=> {[[INTPTR:0x[0-9a-f]*]]} + +; The address of the global 'glbl', followed by DW_OP_stack_value (9f), to use +; the value immediately, rather than indirecting through the address. + +; CHECK-NEXT: DW_AT_location [DW_FORM_block1]{{ *}}(<0x0a> 03 00 00 00 00 00 00 00 00 9f ) + +; CHECK: [[INTPTR]]:{{ *}}DW_TAG_pointer_type +; CHECK-NEXT: DW_AT_type{{.*}} => {[[INT]]} + +@glbl = global i32 0, align 4 +@llvm.global_ctors = appending global [1 x { i32, void ()* }] [{ i32, void ()* } { i32 65535, void ()* @_GLOBAL__I_a }] + +define internal void @__cxx_global_var_init() section ".text.startup" { +entry: + %call = call i32 @_Z4funcILi3EXadL_Z4glblEEEiv(), !dbg !20 + store i32 %call, i32* @glbl, align 4, !dbg !20 + ret void, !dbg !20 +} + +; Function Attrs: nounwind uwtable +define linkonce_odr i32 @_Z4funcILi3EXadL_Z4glblEEEiv() #0 { +entry: + ret i32 3, !dbg !21 +} + +define internal void @_GLOBAL__I_a() section ".text.startup" { +entry: + call void @__cxx_global_var_init(), !dbg !22 + ret void, !dbg !22 +} + +attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf"="true" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.dbg.cu = !{!0} + +!0 = metadata !{i32 786449, metadata !1, i32 4, metadata !"clang version 3.4 ", i1 false, metadata !"", i32 0, metadata !2, metadata !2, metadata !3, metadata !18, metadata !2, metadata !""} ; [ DW_TAG_compile_unit ] [/usr/local/google/home/blaikie/dev/scratch/templ.cpp] [DW_LANG_C_plus_plus] +!1 = metadata !{metadata !"templ.cpp", metadata !"/usr/local/google/home/blaikie/dev/scratch"} +!2 = metadata !{i32 0} +!3 = metadata !{metadata !4, metadata !8, metadata !16} +!4 = metadata !{i32 786478, metadata !1, metadata !5, metadata !"__cxx_global_var_init", metadata !"__cxx_global_var_init", metadata !"", i32 2, metadata !6, i1 true, i1 true, i32 0, i32 0, null, i32 256, i1 false, void ()* @__cxx_global_var_init, null, null, metadata !2, i32 2} ; [ DW_TAG_subprogram ] [line 2] [local] [def] [__cxx_global_var_init] +!5 = metadata !{i32 786473, metadata !1} ; [ DW_TAG_file_type ] [/usr/local/google/home/blaikie/dev/scratch/templ.cpp] +!6 = metadata !{i32 786453, i32 0, i32 0, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !7, i32 0, i32 0} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ] +!7 = metadata !{null} +!8 = metadata !{i32 786478, metadata !1, metadata !5, metadata !"func<3, &glbl>", metadata !"func<3, &glbl>", metadata !"_Z4funcILi3EXadL_Z4glblEEEiv", i32 1, metadata !9, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, i32 ()* @_Z4funcILi3EXadL_Z4glblEEEiv, metadata !12, null, metadata !2, i32 1} ; [ DW_TAG_subprogram ] [line 1] [def] [func<3, &glbl>] +!9 = metadata !{i32 786453, i32 0, i32 0, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !10, i32 0, i32 0} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ] +!10 = metadata !{metadata !11} +!11 = metadata !{i32 786468, null, null, metadata !"int", i32 0, i64 32, i64 32, i64 0, i32 0, i32 5} ; [ DW_TAG_base_type ] [int] [line 0, size 32, align 32, offset 0, enc DW_ATE_signed] +!12 = metadata !{metadata !13, metadata !14} +!13 = metadata !{i32 786480, null, metadata !"x", metadata !11, i32 3, null, i32 0, i32 0} ; [ DW_TAG_template_value_parameter ] +!14 = metadata !{i32 786480, null, metadata !"", metadata !15, i32* @glbl, null, i32 0, i32 0} ; [ DW_TAG_template_value_parameter ] +!15 = metadata !{i32 786447, null, null, metadata !"", i32 0, i64 64, i64 64, i64 0, i32 0, metadata !11} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [from int] +!16 = metadata !{i32 786478, metadata !1, metadata !5, metadata !"_GLOBAL__I_a", metadata !"_GLOBAL__I_a", metadata !"", i32 1, metadata !17, i1 true, i1 true, i32 0, i32 0, null, i32 64, i1 false, void ()* @_GLOBAL__I_a, null, null, metadata !2, i32 1} ; [ DW_TAG_subprogram ] [line 1] [local] [def] [_GLOBAL__I_a] +!17 = metadata !{i32 786453, i32 0, i32 0, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !2, i32 0, i32 0} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ] +!18 = metadata !{metadata !19} +!19 = metadata !{i32 786484, i32 0, null, metadata !"glbl", metadata !"glbl", metadata !"", metadata !5, i32 2, metadata !11, i32 0, i32 1, i32* @glbl, null} ; [ DW_TAG_variable ] [glbl] [line 2] [def] +!20 = metadata !{i32 2, i32 0, metadata !4, null} +!21 = metadata !{i32 1, i32 0, metadata !8, null} +!22 = metadata !{i32 1, i32 0, metadata !16, null} diff --git a/test/ExecutionEngine/MCJIT/eh.ll b/test/ExecutionEngine/MCJIT/eh.ll index 0c19b1bf2e..cd67dd70c5 100644 --- a/test/ExecutionEngine/MCJIT/eh.ll +++ b/test/ExecutionEngine/MCJIT/eh.ll @@ -1,5 +1,5 @@ ; RUN: %lli_mcjit %s -; XFAIL: arm, cygwin +; XFAIL: arm, cygwin, win32 declare i8* @__cxa_allocate_exception(i64) declare void @__cxa_throw(i8*, i8*, i8*) declare i32 @__gxx_personality_v0(...) diff --git a/test/MC/ARM/eh-compact-pr0.s b/test/MC/ARM/eh-compact-pr0.s new file mode 100644 index 0000000000..6b866d5538 --- /dev/null +++ b/test/MC/ARM/eh-compact-pr0.s @@ -0,0 +1,104 @@ +@ RUN: llvm-mc %s -triple=armv7-unknown-linux-gnueabi -filetype=obj -o - \ +@ RUN: | llvm-readobj -s -sd -sr | FileCheck %s + +@ Check the compact pr0 model + + .syntax unified + + .section .TEST1 + .globl func1 + .align 2 + .type func1,%function +func1: + .fnstart + .save {r11, lr} + push {r11, lr} + .setfp r11, sp + mov r11, sp + pop {r11, lr} + mov pc, lr + .fnend + + .section .TEST2 + .globl func2 + .align 2 + .type func2,%function +func2: + .fnstart + .save {r11, lr} + push {r11, lr} + pop {r11, pc} + .fnend + + + +@------------------------------------------------------------------------------- +@ Check .TEST1 section +@------------------------------------------------------------------------------- +@ CHECK: Sections [ +@ CHECK: Section { +@ CHECK: Name: .TEST1 +@ CHECK: SectionData ( +@ CHECK: 0000: 00482DE9 0DB0A0E1 0048BDE8 0EF0A0E1 |.H-......H......| +@ CHECK: ) +@ CHECK: } + + +@------------------------------------------------------------------------------- +@ Check .ARM.exidx.TEST1 section +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Name: .ARM.exidx.TEST1 +@------------------------------------------------------------------------------- +@ The first word should be relocated to .TEST1 section. Besides, there is +@ another relocation entry for __aeabi_unwind_cpp_pr0, so that the linker +@ will keep __aeabi_unwind_cpp_pr0. +@------------------------------------------------------------------------------- +@ CHECK: Relocations [ +@ CHECK: 0x0 R_ARM_PREL31 .TEST1 0x0 +@ CHECK: 0x0 R_ARM_NONE __aeabi_unwind_cpp_pr0 0x0 +@ CHECK: ] +@------------------------------------------------------------------------------- +@ 0x80 = Compact model 0, personality routine: __aeabi_unwind_cpp_pr0 +@ 0x9B = $sp can be found in $r11 +@ 0x8480 = pop {r11, r14} +@------------------------------------------------------------------------------- +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 80849B80 |........| +@ CHECK: ) +@ CHECK: } + + +@------------------------------------------------------------------------------- +@ Check .TEST2 section +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Name: .TEST2 +@ CHECK: SectionData ( +@ CHECK: 0000: 00482DE9 0088BDE8 |.H-.....| +@ CHECK: ) +@ CHECK: } +@------------------------------------------------------------------------------- +@ Check .ARM.exidx.TEST1 section +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Name: .ARM.exidx.TEST2 +@------------------------------------------------------------------------------- +@ The first word should be relocated to .TEST2 section. Besides, there is +@ another relocation entry for __aeabi_unwind_cpp_pr0, so that the linker +@ will keep __aeabi_unwind_cpp_pr0. +@------------------------------------------------------------------------------- +@ CHECK: Relocations [ +@ CHECK: 0x0 R_ARM_PREL31 .TEST2 0x0 +@ CHECK: 0x0 R_ARM_NONE __aeabi_unwind_cpp_pr0 0x0 +@ CHECK: ] +@------------------------------------------------------------------------------- +@ 0x80 = Compact model 0, personality routine: __aeabi_unwind_cpp_pr0 +@ 0x8480 = pop {r11, r14} +@ 0xB0 = finish +@------------------------------------------------------------------------------- +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 B0808480 |........| +@ CHECK: ) +@ CHECK: } +@ CHECK: ] diff --git a/test/MC/ARM/eh-compact-pr1.s b/test/MC/ARM/eh-compact-pr1.s new file mode 100644 index 0000000000..0fac3e2100 --- /dev/null +++ b/test/MC/ARM/eh-compact-pr1.s @@ -0,0 +1,74 @@ +@ RUN: llvm-mc %s -triple=armv7-unknown-linux-gnueabi -filetype=obj -o - \ +@ RUN: | llvm-readobj -s -sd -sr | FileCheck %s + +@ Check the compact pr1 model + + .syntax unified + + .section .TEST1 + .globl func1 + .align 2 + .type func1,%function +func1: + .fnstart + .save {r4, r5, r11, lr} + push {r4, r5, r11, lr} + add r0, r1, r0 + .setfp r11, sp, #8 + add r11, sp, #8 + pop {r4, r5, r11, pc} + .fnend + + + +@------------------------------------------------------------------------------- +@ Check .TEST1 section +@------------------------------------------------------------------------------- +@ CHECK: Sections [ +@ CHECK: Section { +@ CHECK: Name: .TEST1 +@ CHECK: SectionData ( +@ CHECK: 0000: 30482DE9 000081E0 08B08DE2 3088BDE8 |0H-.........0...| +@ CHECK: ) +@ CHECK: } + + +@------------------------------------------------------------------------------- +@ Check .ARM.extab.TEST1 section +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Name: .ARM.extab.TEST1 +@------------------------------------------------------------------------------- +@ 0x81 = Compact model 1, personality routine: __aeabi_unwind_cpp_pr1 +@ 0x9B = $sp can be found in $r11 +@ 0x41 = $sp = $sp - 8 +@ 0x8483 = pop {r4, r5, r11, r14} +@ 0xB0 = finish +@------------------------------------------------------------------------------- +@ CHECK: SectionData ( +@ CHECK: 0000: 419B0181 B0B08384 |A.......| +@ CHECK: ) +@ CHECK: } + + +@------------------------------------------------------------------------------- +@ Check .ARM.exidx.TEST1 section +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Name: .ARM.exidx.TEST1 +@------------------------------------------------------------------------------- +@ The first word should be relocated to .TEST1 section, and the second word +@ should be relocated to .ARM.extab.TEST1 section. Besides, there is +@ another relocation entry for __aeabi_unwind_cpp_pr1, so that the linker +@ will keep __aeabi_unwind_cpp_pr1. +@------------------------------------------------------------------------------- +@ CHECK: Relocations [ +@ CHECK: 0x0 R_ARM_PREL31 .TEST1 0x0 +@ CHECK: 0x0 R_ARM_NONE __aeabi_unwind_cpp_pr1 0x0 +@ CHECK: 0x4 R_ARM_PREL31 .ARM.extab.TEST1 0x0 +@ CHECK: ] +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 00000000 |........| +@ CHECK: ) +@ CHECK: } +@ CHECK: ] diff --git a/test/MC/ARM/eh-directive-cantunwind-diagnostics.s b/test/MC/ARM/eh-directive-cantunwind-diagnostics.s new file mode 100644 index 0000000000..5a6a46c69a --- /dev/null +++ b/test/MC/ARM/eh-directive-cantunwind-diagnostics.s @@ -0,0 +1,106 @@ +@ RUN: not llvm-mc -triple=armv7-unknown-linux-gnueabi < %s 2> %t +@ RUN: FileCheck < %t %s + +@ Check the diagnostics for .cantunwind, .handlerdata, and .personality + +@ .cantunwind directive can't be used with .handlerdata directive nor +@ .personality directive. This test case check for the diagnostics for +@ the conflicts. + + + .syntax unified + .text + +@------------------------------------------------------------------------------- +@ TEST1: cantunwind + personality +@------------------------------------------------------------------------------- + .globl func1 + .align 2 + .type func1,%function + .fnstart +func1: + .cantunwind + .personality __gxx_personality_v0 +@ CHECK: error: .personality can't be used with .cantunwind directive +@ CEHCK: .personality __gxx_personality_v0 +@ CHECK: ^ +@ CHECK: error: .cantunwind was specified here +@ CHECK: .cantunwind +@ CHECK: ^ + .fnend + + + +@------------------------------------------------------------------------------- +@ TEST2: cantunwind + handlerdata +@------------------------------------------------------------------------------- + .globl func2 + .align 2 + .type func2,%function + .fnstart +func2: + .cantunwind + .handlerdata +@ CHECK: error: .handlerdata can't be used with .cantunwind directive +@ CEHCK: .handlerdata +@ CHECK: ^ +@ CHECK: error: .cantunwind was specified here +@ CHECK: .cantunwind +@ CHECK: ^ + .fnend + + + +@------------------------------------------------------------------------------- +@ TEST3: personality + cantunwind +@------------------------------------------------------------------------------- + .globl func3 + .align 2 + .type func3,%function + .fnstart +func3: + .personality __gxx_personality_v0 + .cantunwind +@ CHECK: error: .cantunwind can't be used with .personality directive +@ CEHCK: .cantunwind +@ CHECK: ^ +@ CHECK: error: .personality was specified here +@ CHECK: .personality __gxx_personality_v0 +@ CHECK: ^ + .fnend + + + +@------------------------------------------------------------------------------- +@ TEST4: handlerdata + cantunwind +@------------------------------------------------------------------------------- + .globl func4 + .align 2 + .type func4,%function + .fnstart +func4: + .handlerdata + .cantunwind +@ CHECK: error: .cantunwind can't be used with .handlerdata directive +@ CEHCK: .cantunwind +@ CHECK: ^ +@ CHECK: error: .handlerdata was specified here +@ CHECK: .handlerdata +@ CHECK: ^ + .fnend + + + +@------------------------------------------------------------------------------- +@ TEST5: cantunwind + fnstart +@------------------------------------------------------------------------------- + .globl func5 + .align 2 + .type func5,%function + .cantunwind +@ CHECK: error: .fnstart must precede .cantunwind directive +@ CHECK: .cantunwind +@ CHECK: ^ + .fnstart +func5: + .fnend diff --git a/test/MC/ARM/eh-directive-cantunwind.s b/test/MC/ARM/eh-directive-cantunwind.s new file mode 100644 index 0000000000..0545f6d3c8 --- /dev/null +++ b/test/MC/ARM/eh-directive-cantunwind.s @@ -0,0 +1,51 @@ +@ RUN: llvm-mc %s -triple=armv7-unknown-linux-gnueabi -filetype=obj -o - \ +@ RUN: | llvm-readobj -s -sd -sr | FileCheck %s + +@ Check the .cantunwind directive + +@ When a function contains a .cantunwind directive, we should create an entry +@ in corresponding .ARM.exidx, and its second word should be EXIDX_CANTUNWIND. + + .syntax unified + + .text + .globl func1 + .align 2 + .type func1,%function + .fnstart +func1: + bx lr + .cantunwind + .fnend + + + +@------------------------------------------------------------------------------- +@ Check .text section +@------------------------------------------------------------------------------- +@ CHECK: Sections [ +@ CHECK: Section { +@ CHECK: Name: .text +@ CHECK: SectionData ( +@ CHECK: 0000: 1EFF2FE1 |../.| +@ CHECK: ) +@ CHECK: } + + +@------------------------------------------------------------------------------- +@ Check .ARM.exidx section +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Name: .ARM.exidx +@ CHECK: Relocations [ +@ CHECK: 0x0 R_ARM_PREL31 .text 0x0 +@ CHECK: ] +@------------------------------------------------------------------------------- +@ The first word should be the offset to .text. +@ The second word should be EXIDX_CANTUNWIND (01000000). +@------------------------------------------------------------------------------- +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 01000000 |........| +@ CHECK: ) +@ CHECK: } +@ CHECK: ] diff --git a/test/MC/ARM/eh-directive-fnend-diagnostics.s b/test/MC/ARM/eh-directive-fnend-diagnostics.s new file mode 100644 index 0000000000..a5e4d3bf5b --- /dev/null +++ b/test/MC/ARM/eh-directive-fnend-diagnostics.s @@ -0,0 +1,17 @@ +@ RUN: llvm-mc %s -triple=armv7-unknown-linux-gnueabi \ +@ RUN: -filetype=obj -o /dev/null 2>&1 | FileCheck %s + +@ Check the diagnostics for mismatched .fnend directive + + + .syntax unified + .text + + .globl func1 + .align 2 + .type func1,%function +func1: + .fnend +@ CHECK: error: .fnstart must precede .fnend directive +@ CHECK: .fnend +@ CHECK: ^ diff --git a/test/MC/ARM/eh-directive-fnstart-diagnostics.s b/test/MC/ARM/eh-directive-fnstart-diagnostics.s new file mode 100644 index 0000000000..29bcb0dd9c --- /dev/null +++ b/test/MC/ARM/eh-directive-fnstart-diagnostics.s @@ -0,0 +1,31 @@ +@ RUN: llvm-mc %s -triple=armv7-unknown-linux-gnueabi \ +@ RUN: -filetype=obj -o /dev/null 2>&1 | FileCheck %s + +@ Check the diagnostics for the mismatched .fnstart directives. + +@ There should be some diagnostics when the previous .fnstart is not closed +@ by the .fnend directive. + + + .syntax unified + .text + + .globl func1 + .align 2 + .type func1,%function + .fnstart +func1: + @ Intentionally miss the .fnend directive + + .globl func2 + .align 2 + .type func2,%function + .fnstart +@ CHECK: error: .fnstart starts before the end of previous one +@ CHECK: .fnstart +@ CHECK: ^ +@ CHECK: error: previous .fnstart starts here +@ CHECK: .fnstart +@ CHECK: ^ +func2: + .fnend diff --git a/test/MC/ARM/eh-directive-handlerdata.s b/test/MC/ARM/eh-directive-handlerdata.s new file mode 100644 index 0000000000..45f22ddb63 --- /dev/null +++ b/test/MC/ARM/eh-directive-handlerdata.s @@ -0,0 +1,108 @@ +@ RUN: llvm-mc %s -triple=armv7-unknown-linux-gnueabi -filetype=obj -o - \ +@ RUN: | llvm-readobj -s -sd -sr | FileCheck %s + +@ Check the .handlerdata directive (without .personality directive) + + .syntax unified + +@------------------------------------------------------------------------------- +@ TEST1 +@------------------------------------------------------------------------------- + .section .TEST1 + .globl func1 + .align 2 + .type func1,%function + .fnstart +func1: + bx lr + .handlerdata + .fnend + + +@ CHECK:Section { +@ CHECK: Name: .TEST1 +@ CHECK: SectionData ( +@ CHECK: 0000: 1EFF2FE1 |../.| +@ CHECK: ) +@ CHECK:} + +@ CHECK:Section { +@ CHECK: Name: .ARM.extab.TEST1 +@ CHECK: SectionData ( +@ CHECK: 0000: B0B0B080 |....| +@ CHECK: ) +@ CHECK:} + +@ CHECK:Section { +@ CHECK: Name: .ARM.exidx.TEST1 +@------------------------------------------------------------------------------- +@ We should see a relocation entry to __aeabi_unwind_cpp_pr0, so that the +@ linker can keep __aeabi_unwind_cpp_pr0. +@------------------------------------------------------------------------------- +@ CHECK: Relocations [ +@ CHECK: 0x0 R_ARM_PREL31 .TEST1 0x0 +@ CHECK: 0x0 R_ARM_NONE __aeabi_unwind_cpp_pr0 0x0 +@ CHECK: 0x4 R_ARM_PREL31 .ARM.extab.TEST1 0x0 +@ CHECK: ] +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 00000000 |........| +@ CHECK: ) +@ CHECK:} + + + + +@------------------------------------------------------------------------------- +@ TEST2 +@------------------------------------------------------------------------------- + .section .TEST2 + .globl func2 + .align 2 + .type func2,%function + .fnstart +func2: +@------------------------------------------------------------------------------- +@ Use a lot of unwind opcdes to get __aeabi_unwind_cpp_pr1. +@------------------------------------------------------------------------------- + .save {r4, r5, r6, r7, r8, r9, r10, r11, r12} + push {r4, r5, r6, r7, r8, r9, r10, r11, r12} + pop {r4, r5, r6, r7, r8, r9, r10, r11, r12} + .pad #0x240 + sub sp, sp, #0x240 + add sp, sp, #0x240 + bx lr + .handlerdata + .fnend + + + +@ CHECK:Section { +@ CHECK: Name: .TEST2 +@ CHECK: SectionData ( +@ CHECK: 0000: F01F2DE9 F01FBDE8 09DD4DE2 09DD8DE2 |..-.......M.....| +@ CHECK: 0010: 1EFF2FE1 |../.| +@ CHECK: ) +@ CHECK:} + +@ CHECK:Section { +@ CHECK: Name: .ARM.extab.TEST2 +@ CHECK: SectionData ( +@ CHECK: 0000: 0FB20181 B0B0FF81 |........| +@ CHECK: ) +@ CHECK:} + +@ CHECK:Section { +@ CHECK: Name: .ARM.exidx.TEST2 +@------------------------------------------------------------------------------- +@ We should see a relocation entry to __aeabi_unwind_cpp_pr0, so that the +@ linker can keep __aeabi_unwind_cpp_pr0. +@------------------------------------------------------------------------------- +@ CHECK: Relocations [ +@ CHECK: 0x0 R_ARM_PREL31 .TEST2 0x0 +@ CHECK: 0x0 R_ARM_NONE __aeabi_unwind_cpp_pr1 0x0 +@ CHECK: 0x4 R_ARM_PREL31 .ARM.extab.TEST2 0x0 +@ CHECK: ] +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 00000000 |........| +@ CHECK: ) +@ CHECK:} diff --git a/test/MC/ARM/eh-directive-pad-diagnostics.s b/test/MC/ARM/eh-directive-pad-diagnostics.s new file mode 100644 index 0000000000..7072159621 --- /dev/null +++ b/test/MC/ARM/eh-directive-pad-diagnostics.s @@ -0,0 +1,39 @@ +@ RUN: not llvm-mc -triple=armv7-unknown-linux-gnueabi < %s 2> %t +@ RUN: FileCheck --check-prefix=CHECK < %t %s + +@ Check the diagnostics for .pad directive. + + + .syntax unified + .text + +@------------------------------------------------------------------------------- +@ TEST1: .pad before .fnstart +@------------------------------------------------------------------------------- + .globl func1 + .align 2 + .type func1,%function + .pad #0 +@ CHECK: error: .fnstart must precede .pad directive +@ CHECK: .pad #0 +@ CHECK: ^ + .fnstart +func1: + .fnend + + + +@------------------------------------------------------------------------------- +@ TEST2: .pad after .handlerdata +@------------------------------------------------------------------------------- + .globl func2 + .align 2 + .type func2,%function + .fnstart +func2: + .handlerdata + .pad #0 +@ CHECK: error: .pad must precede .handlerdata directive +@ CHECK: .pad #0 +@ CHECK: ^ + .fnend diff --git a/test/MC/ARM/eh-directive-pad.s b/test/MC/ARM/eh-directive-pad.s new file mode 100644 index 0000000000..ba850ffe77 --- /dev/null +++ b/test/MC/ARM/eh-directive-pad.s @@ -0,0 +1,226 @@ +@ RUN: llvm-mc %s -triple=armv7-unknown-linux-gnueabi -filetype=obj -o - \ +@ RUN: | llvm-readobj -s -sd | FileCheck %s + +@ Check for different stack pointer offsets. + +@ The .pad directive will track the stack pointer offsets. There are several +@ ways to encode the stack offsets. We have to test: +@ +@ offset < 0x00 +@ offset == 0x00 +@ 0x04 <= offset <= 0x100 +@ 0x104 <= offset <= 0x200 +@ 0x204 <= offset + + + .syntax unified + +@------------------------------------------------------------------------------- +@ TEST1 +@------------------------------------------------------------------------------- + .section .TEST1 + .globl func1 + .align 2 + .type func1,%function + .fnstart +func1: + .pad #0 + sub sp, sp, #0 + add sp, sp, #0 + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + +@------------------------------------------------------------------------------- +@ The assembler should emit nothing (will be filled up with finish opcode). +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Name: .ARM.extab.TEST1 +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 B0B0B000 |........| +@ CHECK: ) +@ CHECK: } + + + +@------------------------------------------------------------------------------- +@ TEST2 +@------------------------------------------------------------------------------- + .section .TEST2 + .globl func2a + .align 2 + .type func2a,%function + .fnstart +func2a: + .pad #0x4 + sub sp, sp, #0x4 + add sp, sp, #0x4 + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + .globl func2b + .align 2 + .type func2b,%function + .fnstart +func2b: + .pad #0x100 + sub sp, sp, #0x100 + add sp, sp, #0x100 + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + +@------------------------------------------------------------------------------- +@ The assembler should emit ((offset - 4) >> 2). +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Name: .ARM.extab.TEST2 +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 B0B00000 00000000 B0B03F00 |..............?.| +@ CHECK: ) +@ CHECK: } + + +@------------------------------------------------------------------------------- +@ TEST3 +@------------------------------------------------------------------------------- + .section .TEST3 + .globl func3a + .align 2 + .type func3a,%function + .fnstart +func3a: + .pad #0x104 + sub sp, sp, #0x104 + add sp, sp, #0x104 + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + .globl func3b + .align 2 + .type func3b,%function + .fnstart +func3b: + .pad #0x200 + sub sp, sp, #0x200 + add sp, sp, #0x200 + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + +@------------------------------------------------------------------------------- +@ The assembler should emit 0x3F and ((offset - 0x104) >> 2). +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Name: .ARM.extab.TEST3 +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 B0003F00 00000000 B03F3F00 |......?......??.| +@ CHECK: ) +@ CHECK: } + + + +@------------------------------------------------------------------------------- +@ TEST4 +@------------------------------------------------------------------------------- + .section .TEST4 + .globl func4a + .align 2 + .type func4a,%function + .fnstart +func4a: + .pad #0x204 + sub sp, sp, #0x204 + add sp, sp, #0x204 + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + .globl func4b + .align 2 + .type func4b,%function + .fnstart +func4b: + .pad #0x580 + sub sp, sp, #0x580 + add sp, sp, #0x580 + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + +@------------------------------------------------------------------------------- +@ The assembler should emit 0xB2 and the ULEB128 encoding of +@ ((offset - 0x204) >> 2). +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Name: .ARM.extab.TEST4 +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 B000B200 00000000 01DFB200 |................| +@ CHECK: ) +@ CHECK: } + + + +@------------------------------------------------------------------------------- +@ TEST5 +@------------------------------------------------------------------------------- + .section .TEST5 + .globl func4a + .align 2 + .type func4a,%function + .fnstart +func5a: + .pad #-0x4 + add sp, sp, #0x4 + sub sp, sp, #0x4 + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + .globl func5b + .align 2 + .type func5b,%function + .fnstart +func5b: + .pad #-0x104 + add sp, sp, #0x104 + sub sp, sp, #0x4 + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + .globl func5c + .align 2 + .type func5c,%function + .fnstart +func5c: + .pad #-0x204 + add sp, sp, #0x204 + sub sp, sp, #0x4 + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + +@------------------------------------------------------------------------------- +@ The assembler should emit (0x40 | (-offset - 4)) >> 2. When (-offset - 4) +@ is greater than 0x3f, then multiple 0x7f should be emitted. +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Name: .ARM.extab.TEST5 +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 B0B04000 00000000 B0407F00 |......@......@..| +@ CHECK: 0010: 00000000 407F7F00 |....@...| +@ CHECK: ) +@ CHECK: } diff --git a/test/MC/ARM/eh-directive-personality-diagnostics.s b/test/MC/ARM/eh-directive-personality-diagnostics.s new file mode 100644 index 0000000000..83e9c25f0b --- /dev/null +++ b/test/MC/ARM/eh-directive-personality-diagnostics.s @@ -0,0 +1,39 @@ +@ RUN: not llvm-mc -triple=armv7-unknown-linux-gnueabi < %s 2> %t +@ RUN: FileCheck --check-prefix=CHECK < %t %s + +@ Check the diagnostics for .personality directive. + + + .syntax unified + .text + +@------------------------------------------------------------------------------- +@ TEST1: .personality before .fnstart +@------------------------------------------------------------------------------- + .globl func1 + .align 2 + .type func1,%function + .personality __gxx_personality_v0 +@ CHECK: error: .fnstart must precede .personality directive +@ CHECK: .personality __gxx_personality_v0 +@ CHECK: ^ + .fnstart +func1: + .fnend + + + +@------------------------------------------------------------------------------- +@ TEST2: .personality after .handlerdata +@------------------------------------------------------------------------------- + .globl func2 + .align 2 + .type func2,%function + .fnstart +func2: + .handlerdata + .personality __gxx_personality_v0 +@ CHECK: error: .personality must precede .handlerdata directive +@ CHECK: .personality __gxx_personality_v0 +@ CHECK: ^ + .fnend diff --git a/test/MC/ARM/eh-directive-personality.s b/test/MC/ARM/eh-directive-personality.s new file mode 100644 index 0000000000..2267108b28 --- /dev/null +++ b/test/MC/ARM/eh-directive-personality.s @@ -0,0 +1,90 @@ +@ RUN: llvm-mc %s -triple=armv7-unknown-linux-gnueabi -filetype=obj -o - \ +@ RUN: | llvm-readobj -s -sd -sr | FileCheck %s + +@ Check the .personality directive. + + .syntax unified + +@------------------------------------------------------------------------------- +@ TEST1 +@------------------------------------------------------------------------------- + .section .TEST1 + .globl func1 + .align 2 + .type func1,%function + .fnstart +func1: + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + +@ CHECK: Section { +@ CHECK: Name: .TEST1 +@ CHECK: SectionData ( +@ CHECK: 0000: 1EFF2FE1 |../.| +@ CHECK: ) +@ CHECK: } +@ CHECK: Section { +@ CHECK: Name: .ARM.extab.TEST1 +@ CHECK: Relocations [ +@ CHECK: 0x0 R_ARM_PREL31 __gxx_personality_v0 0x0 +@ CHECK: ] +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 B0B0B000 |........| +@ CHECK: ) +@ CHECK: } +@ CHECK: Section { +@ CHECK: Name: .ARM.exidx.TEST1 +@ CHECK: Relocations [ +@ CHECK: 0x0 R_ARM_PREL31 .TEST1 0x0 +@ CHECK: 0x4 R_ARM_PREL31 .ARM.extab.TEST1 0x0 +@ CHECK: ] +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 00000000 |........| +@ CHECK: ) +@ CHECK: } + + + +@------------------------------------------------------------------------------- +@ TEST2 +@------------------------------------------------------------------------------- + .section .TEST2 + .globl func2 + .align 2 + .type func2,%function + .fnstart +func2: + bx lr + .personality __gxx_personality_v0 + @ The .handlerdata directive is intentionally ignored. The .fnend @ directive should create the EXTAB entry and flush the unwind opcodes. + .fnend + + +@ CHECK: Section { +@ CHECK: Name: .TEST2 +@ CHECK: SectionData ( +@ CHECK: 0000: 1EFF2FE1 |../.| +@ CHECK: ) +@ CHECK: } +@ CHECK: Section { +@ CHECK: Name: .ARM.extab.TEST2 +@ CHECK: Relocations [ +@ CHECK: 0x0 R_ARM_PREL31 __gxx_personality_v0 0x0 +@ CHECK: ] +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 B0B0B000 |........| +@ CHECK: ) +@ CHECK: } +@ CHECK: Section { +@ CHECK: Name: .ARM.exidx.TEST2 +@ CHECK: Relocations [ +@ CHECK: 0x0 R_ARM_PREL31 .TEST2 0x0 +@ CHECK: 0x4 R_ARM_PREL31 .ARM.extab.TEST2 0x0 +@ CHECK: ] +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 00000000 |........| +@ CHECK: ) +@ CHECK: } diff --git a/test/MC/ARM/eh-directive-save-diagnoatics.s b/test/MC/ARM/eh-directive-save-diagnoatics.s new file mode 100644 index 0000000000..0e6d7404a3 --- /dev/null +++ b/test/MC/ARM/eh-directive-save-diagnoatics.s @@ -0,0 +1,41 @@ +@ RUN: not llvm-mc -triple=armv7-unknown-linux-gnueabi < %s 2> %t +@ RUN: FileCheck --check-prefix=CHECK < %t %s + +@ Check the diagnostics for .save directive + +@ .save directive should always come after .fnstart directive and +@ before .handlerdata directive. + + .syntax unified + .text + +@------------------------------------------------------------------------------- +@ TEST1: .save before .fnstart +@------------------------------------------------------------------------------- + .globl func1 + .align 2 + .type func1,%function + .save {r4, r5, r6, r7} +@ CHECK: error: .fnstart must precede .save or .vsave directives +@ CHECK: .save {r4, r5, r6, r7} +@ CHECK: ^ + .fnstart +func1: + .fnend + + + +@------------------------------------------------------------------------------- +@ TEST2: .save after .handlerdata +@------------------------------------------------------------------------------- + .globl func2 + .align 2 + .type func2,%function + .fnstart +func2: + .handlerdata + .save {r4, r5, r6, r7} +@ CHECK: error: .save or .vsave must precede .handlerdata directive +@ CHECK: .save {r4, r5, r6, r7} +@ CHECK: ^ + .fnend diff --git a/test/MC/ARM/eh-directive-save.s b/test/MC/ARM/eh-directive-save.s new file mode 100644 index 0000000000..f9c8c5f03f --- /dev/null +++ b/test/MC/ARM/eh-directive-save.s @@ -0,0 +1,298 @@ +@ RUN: llvm-mc %s -triple=armv7-unknown-linux-gnueabi -filetype=obj -o - \ +@ RUN: | llvm-readobj -s -sd | FileCheck %s + +@ Check the .save directive + +@ The .save directive records the GPR registers which are pushed to the +@ stack. There are 4 different unwind opcodes: +@ +@ 0xB100: pop r[3:0] +@ 0xA0: pop r[(4+x):4] @ r[4+x]-r[4] must be consecutive. +@ 0xA8: pop r14, r[(4+x):4] @ r[4+x]-r[4] must be consecutive. +@ 0x8000: pop r[15:4] +@ +@ If register list specifed by .save directive is possible to be encoded +@ by 0xA0 or 0xA8, then the assembler should prefer them over 0x8000. + + + .syntax unified + +@------------------------------------------------------------------------------- +@ TEST1 +@------------------------------------------------------------------------------- + .section .TEST1 + .globl func1a + .align 2 + .type func1a,%function + .fnstart +func1a: + .save {r0} + push {r0} + pop {r0} + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + .globl func1b + .align 2 + .type func1b,%function + .fnstart +func1b: + .save {r0, r1} + push {r0, r1} + pop {r0, r1} + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + .globl func1c + .align 2 + .type func1c,%function + .fnstart +func1c: + .save {r0, r2} + push {r0, r2} + pop {r0, r2} + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + .globl func1d + .align 2 + .type func1d,%function + .fnstart +func1d: + .save {r1, r2} + push {r1, r2} + pop {r1, r2} + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + .globl func1e + .align 2 + .type func1e,%function + .fnstart +func1e: + .save {r0, r1, r2, r3} + push {r0, r1, r2, r3} + pop {r0, r1, r2, r3} + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + +@------------------------------------------------------------------------------- +@ The assembler should emit 0xB000 unwind opcode. +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Name: .ARM.extab.TEST1 +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 B001B100 00000000 B003B100 |................| +@ CHECK: 0010: 00000000 B005B100 00000000 B006B100 |................| +@ CHECK: 0020: 00000000 B00FB100 |........| +@ CHECK: ) +@ CHECK: } + + + +@------------------------------------------------------------------------------- +@ TEST2 +@------------------------------------------------------------------------------- + .section .TEST2 + .globl func2a + .align 2 + .type func2a,%function + .fnstart +func2a: + .save {r4} + push {r4} + pop {r4} + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + .globl func2b + .align 2 + .type func2b,%function + .fnstart +func2b: + .save {r4, r5} + push {r4, r5} + pop {r4, r5} + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + .globl func2c + .align 2 + .type func2c,%function + .fnstart +func2c: + .save {r4, r5, r6, r7, r8, r9, r10, r11} + push {r4, r5, r6, r7, r8, r9, r10, r11} + pop {r4, r5, r6, r7, r8, r9, r10, r11} + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + +@------------------------------------------------------------------------------- +@ The assembler should emit 0xA0 unwind opcode. +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Name: .ARM.extab.TEST2 +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 B0B0A000 00000000 B0B0A100 |................| +@ CHECK: 0010: 00000000 B0B0A700 |........| +@ CHECK: ) +@ CHECK: } + + + +@------------------------------------------------------------------------------- +@ TEST3 +@------------------------------------------------------------------------------- + .section .TEST3 + .globl func3a + .align 2 + .type func3a,%function + .fnstart +func3a: + .save {r4, r14} + push {r4, r14} + pop {r4, r14} + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + .globl func3b + .align 2 + .type func3b,%function + .fnstart +func3b: + .save {r4, r5, r14} + push {r4, r5, r14} + pop {r4, r5, r14} + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + .globl func3c + .align 2 + .type func3c,%function + .fnstart +func3c: + .save {r4, r5, r6, r7, r8, r9, r10, r11, r14} + push {r4, r5, r6, r7, r8, r9, r10, r11, r14} + pop {r4, r5, r6, r7, r8, r9, r10, r11, r14} + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + +@------------------------------------------------------------------------------- +@ The assembler should emit 0xA8 unwind opcode. +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Name: .ARM.extab.TEST3 +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 B0B0A800 00000000 B0B0A900 |................| +@ CHECK: 0010: 00000000 B0B0AF00 |........| +@ CHECK: ) +@ CHECK: } + + + +@------------------------------------------------------------------------------- +@ TEST4 +@------------------------------------------------------------------------------- + .section .TEST4 + .globl func4a + .align 2 + .type func4a,%function + .fnstart +func4a: + .save {r4, r5, r6, r7, r8, r9, r10, r11, r12, r14} + push {r4, r5, r6, r7, r8, r9, r10, r11, r12, r14} + pop {r4, r5, r6, r7, r8, r9, r10, r11, r12, r14} + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + .globl func4b + .align 2 + .type func4b,%function + .fnstart +func4b: + @ Note: r7 is missing intentionally. + .save {r4, r5, r6, r8, r9, r10, r11} + push {r4, r5, r6, r8, r9, r10, r11} + pop {r4, r5, r6, r8, r9, r10, r11} + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + .globl func4c + .align 2 + .type func4c,%function + .fnstart +func4c: + @ Note: r7 is missing intentionally. + .save {r4, r5, r6, r8, r9, r10, r11, r14} + push {r4, r5, r6, r8, r9, r10, r11, r14} + pop {r4, r5, r6, r8, r9, r10, r11, r14} + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + .globl func4d + .align 2 + .type func4d,%function + .fnstart +func4d: + @ Note: The register list is not start with r4. + .save {r5, r6, r7} + push {r5, r6, r7} + pop {r5, r6, r7} + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + .globl func4e + .align 2 + .type func4e,%function + .fnstart +func4e: + @ Note: The register list is not start with r4. + .save {r5, r6, r7, r14} + push {r5, r6, r7, r14} + pop {r5, r6, r7, r14} + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + +@------------------------------------------------------------------------------- +@ The assembler should emit 0x8000 unwind opcode. +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Name: .ARM.extab.TEST4 +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 B0FF8500 00000000 B0F78000 |................| +@ CHECK: 0010: 00000000 B0F78400 00000000 B00E8000 |................| +@ CHECK: 0020: 00000000 B00E8400 |........| +@ CHECK: ) +@ CHECK: } diff --git a/test/MC/ARM/eh-directive-section-comdat.s b/test/MC/ARM/eh-directive-section-comdat.s new file mode 100644 index 0000000000..296718f096 --- /dev/null +++ b/test/MC/ARM/eh-directive-section-comdat.s @@ -0,0 +1,126 @@ +@ RUN: llvm-mc %s -triple=armv7-unknown-linux-gnueabi -filetype=obj -o - \ +@ RUN: | llvm-readobj -s -sd -sr -t | FileCheck %s + +@ Check the .group section for the function in comdat section. + +@ In C++, the instantiation of the template will come with linkonce (or +@ linkonce_odr) linkage, so that the linker can remove the duplicated +@ instantiation. When the exception handling is enabled on those function, +@ we have to group the corresponding .ARM.extab and .ARM.exidx with the +@ text section together. +@ +@ This test case will check the content of .group section. The section index +@ of the grouped sections should be recorded in .group section. + + .syntax unified + .section .TEST1,"axG",%progbits,func1,comdat + .weak func1 + .align 2 + .type func1,%function +func1: + .fnstart + .save {r4, lr} + push {r4, lr} + .vsave {d8, d9, d10, d11, d12} + vpush {d8, d9, d10, d11, d12} + .pad #24 + sub sp, sp, #24 + + add sp, sp, #24 + vpop {d8, d9, d10, d11, d12} + pop {r4, pc} + + .globl __gxx_personality_v0 + .personality __gxx_personality_v0 + .handlerdata + .fnend + + + +@------------------------------------------------------------------------------- +@ Check the .group section +@------------------------------------------------------------------------------- +@ CHECK: Sections [ +@ CHECK: Section { +@ CHECK: Index: 1 +@ CHECK: Name: .group +@ CHECK: Type: SHT_GROUP (0x11) +@ CHECK: Flags [ (0x0) +@ CHECK: ] +@ CHECK: SectionData ( +@------------------------------------------------------------------------------- +@ The second, third, and fourth word should correspond to the section index +@ of .TEST1, .ARM.extab.TEST1, and .ARM.exidx.TEST1. +@------------------------------------------------------------------------------- +@ CHECK: 0000: 01000000 05000000 06000000 08000000 |................| +@ CHECK: ) +@ CHECK: } + + +@------------------------------------------------------------------------------- +@ Check the .TEST1 section +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Index: 5 +@ CHECK: Name: .TEST1 +@ CHECK: Type: SHT_PROGBITS (0x1) +@------------------------------------------------------------------------------- +@ The flags should contain SHF_GROUP. +@------------------------------------------------------------------------------- +@ CHECK: Flags [ (0x206) +@ CHECK: SHF_ALLOC (0x2) +@ CHECK: SHF_EXECINSTR (0x4) +@ CHECK: SHF_GROUP (0x200) +@ CHECK: ] +@ CHECK: } + + +@------------------------------------------------------------------------------- +@ Check the .ARM.extab.TEST1 section +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Index: 6 +@ CHECK: Name: .ARM.extab.TEST1 +@ CHECK: Type: SHT_PROGBITS (0x1) +@------------------------------------------------------------------------------- +@ The flags should contain SHF_GROUP. +@------------------------------------------------------------------------------- +@ CHECK: Flags [ (0x202) +@ CHECK: SHF_ALLOC (0x2) +@ CHECK: SHF_GROUP (0x200) +@ CHECK: ] +@ CHECK: } + + +@------------------------------------------------------------------------------- +@ Check the .ARM.exidx.TEST1 section +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Index: 8 +@ CHECK: Name: .ARM.exidx.TEST1 +@ CHECK: Type: SHT_ARM_EXIDX (0x70000001) +@------------------------------------------------------------------------------- +@ The flags should contain SHF_GROUP. +@------------------------------------------------------------------------------- +@ CHECK: Flags [ (0x282) +@ CHECK: SHF_ALLOC (0x2) +@ CHECK: SHF_GROUP (0x200) +@ CHECK: SHF_LINK_ORDER (0x80) +@ CHECK: ] +@ CHECK: Link: 5 +@ CHECK: } +@ CHECK: ] + + + +@------------------------------------------------------------------------------- +@ Check symbol func1. It should be weak binding, and belong to .TEST1 section. +@------------------------------------------------------------------------------- +@ CHECK: Symbols [ +@ CHECK: Symbol { +@ CHECK: Name: func1 +@ CHECK: Binding: Weak (0x2) +@ CHECK: Type: Function (0x2) +@ CHECK: Section: .TEST1 (0x5) +@ CHECK: } +@ CHECK: ] diff --git a/test/MC/ARM/eh-directive-section-multiple-func.s b/test/MC/ARM/eh-directive-section-multiple-func.s new file mode 100644 index 0000000000..444099f8f6 --- /dev/null +++ b/test/MC/ARM/eh-directive-section-multiple-func.s @@ -0,0 +1,129 @@ +@ RUN: llvm-mc %s -triple=armv7-unknown-linux-gnueabi -filetype=obj -o - \ +@ RUN: | llvm-readobj -s -sd -sr -t | FileCheck %s + +@ Check whether the section is switched back properly. + +@ The assembler should switch the section back to the corresponding section +@ after it have emitted the exception handling indices and tables. In this +@ test case, we are checking whether the section is correct when .section +@ directives is used. + +@ In this example, func1 and func2 should be defined in .TEST1 section. +@ It is incorrect if the func2 is in .text, .ARM.extab.TEST1, or +@ .ARM.exidx.TEST1 sections. + + .syntax unified + + .section .TEST1 + + .globl func1 + .align 2 + .type func1,%function + .fnstart +func1: + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + .globl func2 + .align 2 + .type func2,%function + .fnstart +func2: + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + +@------------------------------------------------------------------------------- +@ Check the .text section. This should be empty. +@------------------------------------------------------------------------------- +@ CHECK: Sections [ +@ CHECK: Section { +@ CHECK: Name: .text +@ CHECK: SectionData ( +@ CHECK: ) +@ CHECK: } + + +@------------------------------------------------------------------------------- +@ Check the .TEST1 section. There should be two "bx lr" instructions. +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Name: .TEST1 +@ CHECK: SectionData ( +@ CHECK: 0000: 1EFF2FE1 1EFF2FE1 |../.../.| +@ CHECK: ) +@ CHECK: } + + + +@------------------------------------------------------------------------------- +@ Check the .ARM.extab.TEST1 section. +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Name: .ARM.extab.TEST1 +@ CHECK: Relocations [ +@ CHECK: 0x0 R_ARM_PREL31 __gxx_personality_v0 0x0 +@ CHECK: 0x8 R_ARM_PREL31 __gxx_personality_v0 0x0 +@ CHECK: ] +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 B0B0B000 00000000 B0B0B000 |................| +@ CHECK: ) +@ CHECK: } + + +@------------------------------------------------------------------------------- +@ Check the .ARM.exidx.TEST1 section. +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Name: .ARM.exidx.TEST1 +@ CHECK: Link: 4 +@------------------------------------------------------------------------------- +@ The first word of each entry should be relocated to .TEST1 section. +@ The second word of each entry should be relocated to +@ .ARM.extab.TESET1 section. +@------------------------------------------------------------------------------- +@ CHECK: Relocations [ +@ CHECK: 0x0 R_ARM_PREL31 .TEST1 0x0 +@ CHECK: 0x4 R_ARM_PREL31 .ARM.extab.TEST1 0x0 +@ CHECK: 0x8 R_ARM_PREL31 .TEST1 0x0 +@ CHECK: 0xC R_ARM_PREL31 .ARM.extab.TEST1 0x0 +@ CHECK: ] +@------------------------------------------------------------------------------- +@ The first word should be the offset to .TEST1. +@ The second word should be the offset to .ARM.extab.TEST1 +@------------------------------------------------------------------------------- +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 00000000 04000000 08000000 |................| +@ CHECK: ) +@ CHECK: } +@ CHECK: ] + + + +@------------------------------------------------------------------------------- +@ Check the symbols "func1" and "func2". They should belong to .TEST1 section. +@------------------------------------------------------------------------------- +@ CHECK: Symbols [ +@ CHECK: Symbol { +@ CHECK: Name: func1 +@ CHECK: Value: 0x0 +@ CHECK: Size: 0 +@ CHECK: Binding: Global (0x1) +@ CHECK: Type: Function (0x2) +@ CHECK: Other: 0 +@ CHECK: Section: .TEST1 (0x4) +@ CHECK: } +@ CHECK: Symbol { +@ CHECK: Name: func2 +@ CHECK: Value: 0x4 +@ CHECK: Size: 0 +@ CHECK: Binding: Global (0x1) +@ CHECK: Type: Function (0x2) +@ CHECK: Other: 0 +@ CHECK: Section: .TEST1 (0x4) +@ CHECK: } +@ CHECK: ] diff --git a/test/MC/ARM/eh-directive-section.s b/test/MC/ARM/eh-directive-section.s new file mode 100644 index 0000000000..5f5d1252f8 --- /dev/null +++ b/test/MC/ARM/eh-directive-section.s @@ -0,0 +1,164 @@ +@ RUN: llvm-mc %s -triple=armv7-unknown-linux-gnueabi -filetype=obj -o - \ +@ RUN: | llvm-readobj -s -sd -sr -t | FileCheck %s + +@ Check the combination of .section, .fnstart, and .fnend directives. + +@ For the functions in .text section, the exception handling index (EXIDX) +@ should be generated in .ARM.exidx, and the exception handling table (EXTAB) +@ should be generated in .ARM.extab. + +@ For the functions in custom section specified by .section directives, +@ the EXIDX should be generated in ".ARM.exidx[[SECTION_NAME]]", and the EXTAB +@ should be generated in ".ARM.extab[[SECTION_NAME]]". + + .syntax unified + +@------------------------------------------------------------------------------- +@ .TEST1 section +@------------------------------------------------------------------------------- + .section .TEST1 + .globl func1 + .align 2 + .type func1,%function + .fnstart +func1: + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + +@------------------------------------------------------------------------------- +@ TEST2 section (without the dot in the beginning) +@------------------------------------------------------------------------------- + .section TEST2 + .globl func2 + .align 2 + .type func2,%function + .fnstart +func2: + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + +@------------------------------------------------------------------------------- +@ Check the .TEST1 section. +@------------------------------------------------------------------------------- +@ CHECK: Sections [ +@ CHECK: Section { +@ CHECK: Index: 4 +@ CHECK: Name: .TEST1 +@ CHECK: SectionData ( +@ CHECK: 0000: 1EFF2FE1 |../.| +@ CHECK: ) +@ CHECK: } + +@------------------------------------------------------------------------------- +@ Check the .ARM.extab.TEST1 section, the EXTAB of .TEST1 section. +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Name: .ARM.extab.TEST1 +@ CHECK: Relocations [ +@ CHECK: 0x0 R_ARM_PREL31 __gxx_personality_v0 0x0 +@ CHECK: ] +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 B0B0B000 |........| +@ CHECK: ) +@ CHECK: } + + +@------------------------------------------------------------------------------- +@ Check the.ARM.exidx.TEST1 section, the EXIDX of .TEST1 section. +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Name: .ARM.exidx.TEST1 + +@------------------------------------------------------------------------------- +@ This section should linked with .TEST1 section. +@------------------------------------------------------------------------------- +@ CHECK: Link: 4 + +@------------------------------------------------------------------------------- +@ The first word should be relocated to the code address in .TEST1 section. +@ The second word should be relocated to the EHTAB entry in .ARM.extab.TEST1 +@ section. +@------------------------------------------------------------------------------- +@ CHECK: Relocations [ +@ CHECK: 0x0 R_ARM_PREL31 .TEST1 0x0 +@ CHECK: 0x4 R_ARM_PREL31 .ARM.extab.TEST1 0x0 +@ CHECK: ] +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 00000000 |........| +@ CHECK: ) +@ CHECK: } + + + +@------------------------------------------------------------------------------- +@ Check the TEST2 section (without the dot in the beginning) +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Index: 9 +@ CHECK: Name: TEST2 +@ CHECK: SectionData ( +@ CHECK: 0000: 1EFF2FE1 |../.| +@ CHECK: ) +@ CHECK: } + +@------------------------------------------------------------------------------- +@ Check the .ARM.extabTEST2 section, the EXTAB of TEST2 section. +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Name: .ARM.extabTEST2 +@ CHECK: Relocations [ +@ CHECK: 0x0 R_ARM_PREL31 __gxx_personality_v0 0x0 +@ CHECK: ] +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 B0B0B000 |........| +@ CHECK: ) +@ CHECK: } + + +@------------------------------------------------------------------------------- +@ Check the .ARM.exidxTEST2 section, the EXIDX of TEST2 section. +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Name: .ARM.exidxTEST2 + +@------------------------------------------------------------------------------- +@ This section should linked with TEST2 section. +@------------------------------------------------------------------------------- +@ CHECK: Link: 9 + +@------------------------------------------------------------------------------- +@ The first word should be relocated to the code address in TEST2 section. +@ The second word should be relocated to the EHTAB entry in .ARM.extabTEST2 +@ section. +@------------------------------------------------------------------------------- +@ CHECK: Relocations [ +@ CHECK: 0x0 R_ARM_PREL31 TEST2 0x0 +@ CHECK: 0x4 R_ARM_PREL31 .ARM.extabTEST2 0x0 +@ CHECK: ] +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 00000000 |........| +@ CHECK: ) +@ CHECK: } +@ CHECK: ] + + + +@------------------------------------------------------------------------------- +@ Check the symbols and the sections they belong to +@------------------------------------------------------------------------------- +@ CHECK: Symbols [ +@ CHECK: Symbol { +@ CHECK: Name: func1 +@ CHECK: Section: .TEST1 (0x4) +@ CHECK: } +@ CHECK: Symbol { +@ CHECK: Name: func2 +@ CHECK: Section: TEST2 (0x9) +@ CHECK: } +@ CHECK: ] diff --git a/test/MC/ARM/eh-directive-setfp-diagnostics.s b/test/MC/ARM/eh-directive-setfp-diagnostics.s new file mode 100644 index 0000000000..a5b8aa2386 --- /dev/null +++ b/test/MC/ARM/eh-directive-setfp-diagnostics.s @@ -0,0 +1,87 @@ +@ RUN: not llvm-mc -triple=armv7-unknown-linux-gnueabi < %s 2> %t +@ RUN: FileCheck --check-prefix=CHECK < %t %s + +@ Check the diagnostics for .setfp directive. + + + .syntax unified + .text + +@------------------------------------------------------------------------------- +@ TEST1: .setfp before .fnstart +@------------------------------------------------------------------------------- + .globl func1 + .align 2 + .type func1,%function + .setfp fp, sp, #0 +@ CHECK: error: .fnstart must precede .setfp directive +@ CHECK: .setfp fp, sp, #0 +@ CHECK: ^ + .fnstart +func1: + .fnend + + + +@------------------------------------------------------------------------------- +@ TEST2: .setfp after .handlerdata +@------------------------------------------------------------------------------- + .globl func2 + .align 2 + .type func2,%function + .fnstart +func2: + .handlerdata + .setfp fp, sp, #0 +@ CHECK: error: .setfp must precede .handlerdata directive +@ CHECK: .setfp fp, sp, #0 +@ CHECK: ^ + .fnend + + + +@------------------------------------------------------------------------------- +@ TEST3: .setfp with bad fp register +@------------------------------------------------------------------------------- + .globl func3 + .align 2 + .type func3,%function + .fnstart +func3: + .setfp 0, r0, #0 +@ CHECK: error: frame pointer register expected +@ CHECK: .setfp 0, r0, #0 +@ CHECK: ^ + .fnend + + + +@------------------------------------------------------------------------------- +@ TEST4: .setfp with bad sp register +@------------------------------------------------------------------------------- + .globl func4 + .align 2 + .type func4,%function + .fnstart +func4: + .setfp fp, 0, #0 +@ CHECK: error: stack pointer register expected +@ CHECK: .setfp fp, 0, #0 +@ CHECK: ^ + .fnend + + + +@------------------------------------------------------------------------------- +@ TEST5: .setfp with non-sp register as second operand +@------------------------------------------------------------------------------- + .globl func5 + .align 2 + .type func5,%function + .fnstart +func5: + .setfp fp, r0, #0 +@ CHECK: error: register should be either $sp or the latest fp register +@ CHECK: .setfp fp, r0, #0 +@ CHECK: ^ + .fnend diff --git a/test/MC/ARM/eh-directive-setfp.s b/test/MC/ARM/eh-directive-setfp.s new file mode 100644 index 0000000000..3fbab5a3e7 --- /dev/null +++ b/test/MC/ARM/eh-directive-setfp.s @@ -0,0 +1,239 @@ +@ RUN: llvm-mc %s -triple=armv7-unknown-linux-gnueabi -filetype=obj -o - \ +@ RUN: | llvm-readobj -s -sd | FileCheck %s + +@ Check for .setfp directive. + +@ The .setfp directive will track the offset between the frame pointer and +@ the stack pointer. This is required for the function that will change +@ the stack pointer out of the function prologue. If the exception is thrown, +@ then libunwind will reconstruct the stack pointer from the frame pointer. +@ The reconstruction code is implemented by two different unwind opcode: +@ (i) the unwind opcode to copy stack offset from the other register, and +@ (ii) the unwind opcode to add or substract the stack offset. +@ +@ This file includes several cases separated by different range of -offset +@ +@ (-offset) < 0x00 +@ (-offset) == 0x00 +@ 0x04 <= (-offset) <= 0x100 +@ 0x104 <= (-offset) <= 0x200 +@ 0x204 <= (-offset) + + + .syntax unified + +@------------------------------------------------------------------------------- +@ TEST1 +@------------------------------------------------------------------------------- + .section .TEST1 + .globl func1 + .align 2 + .type func1,%function + .fnstart +func1: + .setfp fp, sp, #0 + add fp, sp, #0 + sub sp, fp, #0 + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + +@------------------------------------------------------------------------------- +@ The assembler should emit 0x9B to copy stack pointer from r11. +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Name: .ARM.extab.TEST1 +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 B0B09B00 |........| +@ CHECK: ) +@ CHECK: } + + + +@------------------------------------------------------------------------------- +@ TEST2 +@------------------------------------------------------------------------------- + .section .TEST2 + .globl func2a + .align 2 + .type func2a,%function + .fnstart +func2a: + .setfp fp, sp, #-4 + add fp, sp, #4 + sub sp, fp, #4 + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + .globl func2b + .align 2 + .type func2b,%function + .fnstart +func2b: + .setfp fp, sp, #-0x100 + add fp, sp, #0x100 + sub sp, fp, #0x100 + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + +@------------------------------------------------------------------------------- +@ The assembler should emit 0x9B to copy stack pointer from r11. +@ The assembler should emit ((-offset - 4) >> 2) for offset. +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Name: .ARM.extab.TEST2 +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 B0009B00 00000000 B03F9B00 |.............?..| +@ CHECK: ) +@ CHECK: } + + + +@------------------------------------------------------------------------------- +@ TEST3 +@------------------------------------------------------------------------------- + .section .TEST3 + .globl func3a + .align 2 + .type func3a,%function + .fnstart +func3a: + .setfp fp, sp, #-0x104 + sub fp, sp, #0x104 + add sp, fp, #0x104 + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + .globl func3b + .align 2 + .type func3b,%function + .fnstart +func3b: + .setfp fp, sp, #-0x200 + sub fp, sp, #0x200 + add sp, fp, #0x200 + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + +@------------------------------------------------------------------------------- +@ The assembler should emit 0x9B to copy stack pointer from r11. +@ The assembler should emit 0x3F and ((-offset - 0x104) >> 2) for offset. +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Name: .ARM.extab.TEST3 +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 003F9B00 00000000 3F3F9B00 |.....?......??..| +@ CHECK: ) +@ CHECK: } + + + +@------------------------------------------------------------------------------- +@ TEST4 +@------------------------------------------------------------------------------- + .section .TEST4 + .globl func4a + .align 2 + .type func4a,%function + .fnstart +func4a: + .setfp fp, sp, #-0x204 + sub fp, sp, #0x204 + add sp, fp, #0x204 + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + .globl func4b + .align 2 + .type func4b,%function + .fnstart +func4b: + .setfp fp, sp, #-0x580 + sub fp, sp, #0x580 + add sp, fp, #0x580 + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + +@------------------------------------------------------------------------------- +@ The assembler should emit 0x9B to copy stack pointer from r11. +@ The assembler should emit 0xB2 and the ULEB128 encoding of +@ ((-offset - 0x204) >> 2) for offset. +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Name: .ARM.extab.TEST4 +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 00B29B00 00000000 DFB29B01 |................| +@ CHECK: 0010: B0B0B001 |....| +@ CHECK: ) +@ CHECK: } + + + +@------------------------------------------------------------------------------- +@ TEST5 +@------------------------------------------------------------------------------- + .section .TEST5 + .globl func5a + .align 2 + .type func5a,%function + .fnstart +func5a: + .setfp fp, sp, #0x4 + add fp, sp, #0x4 + sub sp, fp, #0x4 + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + .globl func5b + .align 2 + .type func5b,%function + .fnstart +func5b: + .setfp fp, sp, #0x104 + add fp, sp, #0x104 + sub sp, fp, #0x104 + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + .globl func5c + .align 2 + .type func5c,%function + .fnstart +func5c: + .setfp fp, sp, #0x204 + add fp, sp, #0x204 + sub sp, fp, #0x204 + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + +@------------------------------------------------------------------------------- +@ The assembler should emit 0x9B to copy stack pointer from r11. +@ The assembler should emit (0x40 | (offset - 4)) >> 2 for offset. +@ If (offset - 4) is greater than 0x3f, then multiple 0x7f should be emitted. +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Name: .ARM.extab.TEST5 +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 B0409B00 00000000 407F9B00 |.....@......@...| +@ CHECK: 0010: 00000000 7F7F9B01 B0B0B040 |...........@| +@ CHECK: ) +@ CHECK: } diff --git a/test/MC/ARM/eh-directive-text-section-multiple-func.s b/test/MC/ARM/eh-directive-text-section-multiple-func.s new file mode 100644 index 0000000000..c9412763a8 --- /dev/null +++ b/test/MC/ARM/eh-directive-text-section-multiple-func.s @@ -0,0 +1,81 @@ +@ RUN: llvm-mc %s -triple=armv7-unknown-linux-gnueabi -filetype=obj -o - \ +@ RUN: | llvm-readobj -s -sd -sr -r -t | FileCheck %s + +@ Check whether the section is switched back or not. + +@ The assembler should emit the machine code of "func2" in .text section. +@ It is incorrect if the machine code is emitted in .ARM.exidx or .ARM.extab. +@ Besides, there should be two entries in .ARM.exidx section. + + .syntax unified + + .text + .globl func1 + .align 2 + .type func1,%function + .fnstart +func1: + bx lr + .fnend + + .globl func2 + .align 2 + .type func2,%function + .fnstart +func2: + bx lr + .fnend + + +@------------------------------------------------------------------------------- +@ Check the .text section. There should be two "bx lr" instructions. +@------------------------------------------------------------------------------- +@ CHECK: Sections [ +@ CHECK: Section { +@ CHECK: Name: .text +@ CHECK: SectionData ( +@ CHECK: 0000: 1EFF2FE1 1EFF2FE1 |../.../.| +@ CHECK: ) +@ CHECK: } + + +@------------------------------------------------------------------------------- +@ Check the .ARM.exidx section. +@ There should be two entries (two words per entry.) +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Name: .ARM.exidx +@------------------------------------------------------------------------------- +@ The first word of each entry should be relocated to .text section. +@------------------------------------------------------------------------------- +@ CHECK: Relocations [ +@ CHECK: 0x0 R_ARM_PREL31 .text 0x0 +@ CHECK: 0x0 R_ARM_NONE __aeabi_unwind_cpp_pr0 0x0 +@ CHECK: 0x8 R_ARM_PREL31 .text 0x0 +@ CHECK: ] +@ CHECK: SectionData ( +@------------------------------------------------------------------------------- +@ The first word should be the offset to .text. The second word should be +@ 0xB0B0B080, which means compact model 0 is used (0x80) and the rest of the +@ word is filled with FINISH opcode (0xB0). +@------------------------------------------------------------------------------- +@ CHECK: 0000: 00000000 B0B0B080 04000000 B0B0B080 |................| +@ CHECK: ) +@ CHECK: } +@ CHECK: ] + + + +@------------------------------------------------------------------------------- +@ Check the symbols "func1" and "func2". They should belong to .text section. +@------------------------------------------------------------------------------- +@ CHECK: Symbols [ +@ CHECK: Symbol { +@ CHECK: Name: func1 +@ CHECK: Section: .text (0x1) +@ CHECK: } +@ CHECK: Symbol { +@ CHECK: Name: func2 +@ CHECK: Section: .text (0x1) +@ CHECK: } +@ CHECK: ] diff --git a/test/MC/ARM/eh-directive-text-section.s b/test/MC/ARM/eh-directive-text-section.s new file mode 100644 index 0000000000..5ab1baa592 --- /dev/null +++ b/test/MC/ARM/eh-directive-text-section.s @@ -0,0 +1,82 @@ +@ RUN: llvm-mc %s -triple=armv7-unknown-linux-gnueabi -filetype=obj -o - \ +@ RUN: | llvm-readobj -s -sd -sr | FileCheck %s + +@ Check the .fnstart directive and the .fnend directive. + +@ The .fnstart directive and .fnend directive should create an entry in +@ exception handling table. For example, if the function is defined in .text +@ section, then there should be an entry in .ARM.exidx section. + + .syntax unified + + .text + .globl func1 + .align 2 + .type func1,%function + .fnstart +func1: + bx lr + .fnend + + + +@------------------------------------------------------------------------------- +@ Check the .text section. +@------------------------------------------------------------------------------- +@ CHECK: Sections [ +@ CHECK: Section { + +@------------------------------------------------------------------------------- +@ Check the index of .text section. This will be used in .ARM.exidx. +@------------------------------------------------------------------------------- +@ CHECK: Index: 1 +@ CHECK: Name: .text +@ CHECK: Type: SHT_PROGBITS (0x1) +@ CHECK: Flags [ (0x6) +@ CHECK: SHF_ALLOC (0x2) +@ CHECK: SHF_EXECINSTR (0x4) +@ CHECK: ] +@ CHECK: SectionData ( +@ CHECK: 0000: 1EFF2FE1 |../.| +@ CHECK: ) +@ CHECK: } + + +@------------------------------------------------------------------------------- +@ Check the name of the EXIDX section. For the function in the .text section, +@ this should be .ARM.exidx. It is incorrect to see .ARM.exidx.text here. +@------------------------------------------------------------------------------- +@ CHECK: Section { +@ CHECK: Name: .ARM.exidx +@ CHECK: Type: SHT_ARM_EXIDX (0x70000001) +@ CHECK: Flags [ (0x82) +@ CHECK: SHF_ALLOC (0x2) +@ CHECK: SHF_LINK_ORDER (0x80) +@ CHECK: ] + +@------------------------------------------------------------------------------- +@ Check the linked section of the EXIDX section. This should be the index +@ of the .text section. +@------------------------------------------------------------------------------- +@ CHECK: Link: 1 + +@------------------------------------------------------------------------------- +@ The first word should be relocated to the code address in .text section. +@ Besides, since this function is using compact model 0, thus we have to +@ add an relocation to __aeabi_unwind_cpp_pr0. +@------------------------------------------------------------------------------- +@ CHECK: Relocations [ +@ CHECK: 0x0 R_ARM_PREL31 .text 0x0 +@ CHECK: 0x0 R_ARM_NONE __aeabi_unwind_cpp_pr0 0x0 +@ CHECK: ] + +@------------------------------------------------------------------------------- +@ The first word should be the offset to .text. The second word should be +@ 0xB0B0B080, which means compact model 0 is used (0x80) and the rest of the +@ word is filled with FINISH opcode (0xB0). +@------------------------------------------------------------------------------- +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 B0B0B080 |........| +@ CHECK: ) +@ CHECK: } +@ CHECK: ] diff --git a/test/MC/ARM/eh-directive-vsave-diagnostics.s b/test/MC/ARM/eh-directive-vsave-diagnostics.s new file mode 100644 index 0000000000..62787f37c2 --- /dev/null +++ b/test/MC/ARM/eh-directive-vsave-diagnostics.s @@ -0,0 +1,41 @@ +@ RUN: not llvm-mc -triple=armv7-unknown-linux-gnueabi < %s 2> %t +@ RUN: FileCheck --check-prefix=CHECK < %t %s + +@ Check the diagnostics for .vsave directive + +@ .vsave directive should always come after .fnstart directive +@ and before .handlerdata directive. + + .syntax unified + .text + +@------------------------------------------------------------------------------- +@ TEST1: .vsave before .fnstart +@------------------------------------------------------------------------------- + .globl func1 + .align 2 + .type func1,%function + .vsave {d0, d1, d2, d3} +@ CHECK: error: .fnstart must precede .save or .vsave directives +@ CHECK: .vsave {d0, d1, d2, d3} +@ CHECK: ^ + .fnstart +func1: + .fnend + + + +@------------------------------------------------------------------------------- +@ TEST2: .vsave after .handlerdata +@------------------------------------------------------------------------------- + .globl func2 + .align 2 + .type func2,%function + .fnstart +func2: + .handlerdata + .vsave {d0, d1, d2, d3} +@ CHECK: error: .save or .vsave must precede .handlerdata directive +@ CHECK: .vsave {d0, d1, d2, d3} +@ CHECK: ^ + .fnend diff --git a/test/MC/ARM/eh-directive-vsave.s b/test/MC/ARM/eh-directive-vsave.s new file mode 100644 index 0000000000..c9b78d7e27 --- /dev/null +++ b/test/MC/ARM/eh-directive-vsave.s @@ -0,0 +1,130 @@ +@ RUN: llvm-mc %s -triple=armv7-unknown-linux-gnueabi -filetype=obj -o - \ +@ RUN: | llvm-readobj -s -sd -sr | FileCheck %s + +@ Check the .vsave directive + +@ The .vsave directive records the VFP registers which are pushed to the +@ stack. There are two different opcodes: +@ +@ 0xC800: pop d[(16+x+y):(16+x)] @ d[16+x+y]-d[16+x] must be consecutive +@ 0xC900: pop d[(x+y):x] @ d[x+y]-d[x] must be consecutive + + + .syntax unified + +@------------------------------------------------------------------------------- +@ TEST1 +@------------------------------------------------------------------------------- + .section .TEST1 + .globl func1a + .align 2 + .type func1a,%function + .fnstart +func1a: + .vsave {d0} + vpush {d0} + vpop {d0} + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + .globl func1b + .align 2 + .type func1b,%function + .fnstart +func1b: + .vsave {d0, d1, d2, d3} + vpush {d0, d1, d2, d3} + vpop {d0, d1, d2, d3} + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + .globl func1c + .align 2 + .type func1c,%function + .fnstart +func1c: + .vsave {d0, d1, d2, d3, d4, d5, d6, d7} + vpush {d0, d1, d2, d3, d4, d5, d6, d7} + vpop {d0, d1, d2, d3, d4, d5, d6, d7} + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + .globl func1d + .align 2 + .type func1d,%function + .fnstart +func1d: + .vsave {d2, d3, d4, d5, d6, d7} + vpush {d2, d3, d4, d5, d6, d7} + vpop {d2, d3, d4, d5, d6, d7} + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + +@ CHECK: Section { +@ CHECK: Name: .ARM.extab.TEST1 +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 B000C900 00000000 B003C900 |................| +@ CHECK: 0010: 00000000 B007C900 00000000 B025C900 |.............%..| +@ CHECK: ) +@ CHECK: } + + + +@------------------------------------------------------------------------------- +@ TEST2 +@------------------------------------------------------------------------------- + .section .TEST2 + .globl func2a + .align 2 + .type func2a,%function + .fnstart +func2a: + .vsave {d16} + vpush {d16} + vpop {d16} + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + .globl func2b + .align 2 + .type func2b,%function + .fnstart +func2b: + .vsave {d16, d17, d18, d19} + vpush {d16, d17, d18, d19} + vpop {d16, d17, d18, d19} + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + + .globl func2c + .align 2 + .type func2c,%function + .fnstart +func2c: + .vsave {d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31} + vpush {d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31} + vpop {d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31} + bx lr + .personality __gxx_personality_v0 + .handlerdata + .fnend + +@ CHECK: Section { +@ CHECK: Name: .ARM.extab.TEST2 +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 B000C800 00000000 B003C800 |................| +@ CHECK: 0010: 00000000 B00FC800 |........| +@ CHECK: ) +@ CHECK: } diff --git a/test/MC/X86/x86_errors.s b/test/MC/X86/x86_errors.s index 6e14d62fda..a974233d2f 100644 --- a/test/MC/X86/x86_errors.s +++ b/test/MC/X86/x86_errors.s @@ -28,3 +28,6 @@ lea (%rsp, %rbp, $4), %rax // rdar://10423777 // 64: error: index register is 32-bit, but base register is 64-bit movq (%rsi,%ecx),%xmm0 + +// 32: error: invalid operand for instruction +outb al, 4 diff --git a/test/Transforms/InstCombine/cast.ll b/test/Transforms/InstCombine/cast.ll index de738bb7c0..ff2c0a9289 100644 --- a/test/Transforms/InstCombine/cast.ll +++ b/test/Transforms/InstCombine/cast.ll @@ -898,3 +898,31 @@ define double @test81(double *%p, float %f) { %l = load double* %r ret double %l } + +define i64 @test82(i64 %A) nounwind { + %B = trunc i64 %A to i32 + %C = lshr i32 %B, 8 + %D = shl i32 %C, 9 + %E = zext i32 %D to i64 + ret i64 %E + +; CHECK: @test82 +; CHECK-NEXT: [[REG:%[0-9]*]] = shl i64 %A, 1 +; CHECK-NEXT: %E = and i64 [[REG]], 4294966784 +; CHECK-NEXT: ret i64 %E +} + +; PR15959 +define i64 @test83(i16 %a, i64 %k) { + %conv = sext i16 %a to i32 + %sub = add nsw i64 %k, -1 + %sh_prom = trunc i64 %sub to i32 + %shl = shl i32 %conv, %sh_prom + %sh_prom1 = zext i32 %shl to i64 + ret i64 %sh_prom1 + +; CHECK: @test83 +; CHECK: %sub = add nsw i64 %k, 4294967295 +; CHECK: %sh_prom = trunc i64 %sub to i32 +; CHECK: %shl = shl i32 %conv, %sh_prom +} diff --git a/test/Transforms/InstCombine/rem.ll b/test/Transforms/InstCombine/rem.ll index b421b7c0e8..450a62ae6d 100644 --- a/test/Transforms/InstCombine/rem.ll +++ b/test/Transforms/InstCombine/rem.ll @@ -1,36 +1,56 @@ -; This test makes sure that these instructions are properly eliminated. +; This test makes sure that urem instructions are properly eliminated. ; -; RUN: opt < %s -instcombine -S | not grep rem +; RUN: opt < %s -instcombine -S | FileCheck %s ; END. define i32 @test1(i32 %A) { +; CHECK: @test1 +; CHECK-NEXT: ret i32 0 %B = srem i32 %A, 1 ; ISA constant 0 ret i32 %B } define i32 @test2(i32 %A) { ; 0 % X = 0, we don't need to preserve traps +; CHECK: @test2 +; CHECK-NEXT: ret i32 0 %B = srem i32 0, %A ret i32 %B } define i32 @test3(i32 %A) { +; CHECK: @test3 +; CHECK-NEXT: [[AND:%.*]] = and i32 %A, 7 +; CHECK-NEXT: ret i32 [[AND]] %B = urem i32 %A, 8 ret i32 %B } define i1 @test3a(i32 %A) { +; CHECK: @test3a +; CHECK-NEXT: [[AND:%.*]] = and i32 %A, 7 +; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[AND]], 0 +; CHECK-NEXT: ret i1 [[CMP]] %B = srem i32 %A, -8 %C = icmp ne i32 %B, 0 ret i1 %C } define i32 @test4(i32 %X, i1 %C) { +; CHECK: @test4 +; CHECK-NEXT: [[SEL:%.*]] = select i1 %C, i32 0, i32 7 +; CHECK-NEXT: [[AND:%.*]] = and i32 [[SEL]], %X %V = select i1 %C, i32 1, i32 8 %R = urem i32 %X, %V ret i32 %R } define i32 @test5(i32 %X, i8 %B) { +; CHECK: @test5 +; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 %B to i32 +; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 32, [[ZEXT]] +; CHECK-NEXT: [[ADD:%.*]] = add i32 [[SHL]], -1 +; CHECK-NEXT: [[AND:%.*]] = and i32 [[ADD]], %X +; CHECK-NEXT: ret i32 [[AND]] %shift.upgrd.1 = zext i8 %B to i32 %Amt = shl i32 32, %shift.upgrd.1 %V = urem i32 %X, %Amt @@ -38,29 +58,39 @@ define i32 @test5(i32 %X, i8 %B) { } define i32 @test6(i32 %A) { +; CHECK: @test6 +; CHECK-NEXT: ret i32 undef %B = srem i32 %A, 0 ;; undef ret i32 %B } define i32 @test7(i32 %A) { +; CHECK: @test7 +; CHECK-NEXT: ret i32 0 %B = mul i32 %A, 8 %C = srem i32 %B, 4 ret i32 %C } define i32 @test8(i32 %A) { +; CHECK: @test8 +; CHECK-NEXT: ret i32 0 %B = shl i32 %A, 4 %C = srem i32 %B, 8 ret i32 %C } define i32 @test9(i32 %A) { +; CHECK: @test9 +; CHECK-NEXT: ret i32 0 %B = mul i32 %A, 64 %C = urem i32 %B, 32 ret i32 %C } define i32 @test10(i8 %c) { +; CHECK: @test10 +; CHECK-NEXT: ret i32 0 %tmp.1 = zext i8 %c to i32 %tmp.2 = mul i32 %tmp.1, 4 %tmp.3 = sext i32 %tmp.2 to i64 @@ -70,6 +100,8 @@ define i32 @test10(i8 %c) { } define i32 @test11(i32 %i) { +; CHECK: @test11 +; CHECK-NEXT: ret i32 0 %tmp.1 = and i32 %i, -2 %tmp.3 = mul i32 %tmp.1, 2 %tmp.5 = urem i32 %tmp.3, 4 @@ -77,12 +109,43 @@ define i32 @test11(i32 %i) { } define i32 @test12(i32 %i) { +; CHECK: @test12 +; CHECK-NEXT: ret i32 0 %tmp.1 = and i32 %i, -4 %tmp.5 = srem i32 %tmp.1, 2 ret i32 %tmp.5 } define i32 @test13(i32 %i) { +; CHECK: @test13 +; CHECK-NEXT: ret i32 0 %x = srem i32 %i, %i ret i32 %x } + +define i64 @test14(i64 %x, i32 %y) { +; CHECK: @test14 +; CHECK-NEXT: [[SHL:%.*]] = shl i32 1, %y +; CHECK-NEXT: [[ZEXT:%.*]] = zext i32 [[SHL]] to i64 +; CHECK-NEXT: [[ADD:%.*]] = add i64 [[ZEXT]], -1 +; CHECK-NEXT: [[AND:%.*]] = and i64 [[ADD]], %x +; CHECK-NEXT: ret i64 [[AND]] + %shl = shl i32 1, %y + %zext = zext i32 %shl to i64 + %urem = urem i64 %x, %zext + ret i64 %urem +} + +define i64 @test15(i32 %x, i32 %y) { +; CHECK: @test15 +; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 1, %y +; CHECK-NEXT: [[ADD:%.*]] = add i32 [[SHL]], -1 +; CHECK-NEXT: [[AND:%.*]] = and i32 [[ADD]], %x +; CHECK-NEXT: [[ZEXT:%.*]] = zext i32 [[AND]] to i64 +; CHECK-NEXT: ret i64 [[ZEXT]] + %shl = shl i32 1, %y + %zext0 = zext i32 %shl to i64 + %zext1 = zext i32 %x to i64 + %urem = urem i64 %zext1, %zext0 + ret i64 %urem +} diff --git a/test/Transforms/LoopVectorize/reverse_induction.ll b/test/Transforms/LoopVectorize/reverse_induction.ll index f43f02bc31..9e8c1b116d 100644 --- a/test/Transforms/LoopVectorize/reverse_induction.ll +++ b/test/Transforms/LoopVectorize/reverse_induction.ll @@ -77,3 +77,72 @@ loopend: } +@a = common global [1024 x i32] zeroinitializer, align 16 + +; We incorrectly transformed this loop into an empty one because we left the +; induction variable in i8 type and truncated the exit value 1024 to 0. +; int a[1024]; +; +; void fail() { +; int reverse_induction = 1023; +; unsigned char forward_induction = 0; +; while ((reverse_induction) >= 0) { +; forward_induction++; +; a[reverse_induction] = forward_induction; +; --reverse_induction; +; } +; } + +; CHECK: reverse_forward_induction_i64_i8 +; CHECK: vector.body +; CHECK: %index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ] +; CHECK: %normalized.idx = sub i64 %index, 0 +; CHECK: %reverse.idx = sub i64 1023, %normalized.idx +; CHECK: trunc i64 %index to i8 + +define void @reverse_forward_induction_i64_i8() { +entry: + br label %while.body + +while.body: + %indvars.iv = phi i64 [ 1023, %entry ], [ %indvars.iv.next, %while.body ] + %forward_induction.05 = phi i8 [ 0, %entry ], [ %inc, %while.body ] + %inc = add i8 %forward_induction.05, 1 + %conv = zext i8 %inc to i32 + %arrayidx = getelementptr inbounds [1024 x i32]* @a, i64 0, i64 %indvars.iv + store i32 %conv, i32* %arrayidx, align 4 + %indvars.iv.next = add i64 %indvars.iv, -1 + %0 = trunc i64 %indvars.iv to i32 + %cmp = icmp sgt i32 %0, 0 + br i1 %cmp, label %while.body, label %while.end + +while.end: + ret void +} + +; CHECK: reverse_forward_induction_i64_i8_signed +; CHECK: vector.body: +; CHECK: %index = phi i64 [ 129, %vector.ph ], [ %index.next, %vector.body ] +; CHECK: %normalized.idx = sub i64 %index, 129 +; CHECK: %reverse.idx = sub i64 1023, %normalized.idx +; CHECK: trunc i64 %index to i8 + +define void @reverse_forward_induction_i64_i8_signed() { +entry: + br label %while.body + +while.body: + %indvars.iv = phi i64 [ 1023, %entry ], [ %indvars.iv.next, %while.body ] + %forward_induction.05 = phi i8 [ -127, %entry ], [ %inc, %while.body ] + %inc = add i8 %forward_induction.05, 1 + %conv = sext i8 %inc to i32 + %arrayidx = getelementptr inbounds [1024 x i32]* @a, i64 0, i64 %indvars.iv + store i32 %conv, i32* %arrayidx, align 4 + %indvars.iv.next = add i64 %indvars.iv, -1 + %0 = trunc i64 %indvars.iv to i32 + %cmp = icmp sgt i32 %0, 0 + br i1 %cmp, label %while.body, label %while.end + +while.end: + ret void +} diff --git a/test/Transforms/LoopVectorize/reverse_iter.ll b/test/Transforms/LoopVectorize/reverse_iter.ll new file mode 100644 index 0000000000..6ff4f1f8d1 --- /dev/null +++ b/test/Transforms/LoopVectorize/reverse_iter.ll @@ -0,0 +1,45 @@ +; RUN: opt < %s -loop-vectorize -force-vector-unroll=1 -force-vector-width=4 -dce -instcombine -S | FileCheck %s + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.8.0" + +; Make sure that the reverse iterators are calculated using 64bit arithmetic, not 32. +; +; int foo(int n, int *A) { +; int sum; +; for (int i=n; i > 0; i--) +; sum += A[i*2]; +; return sum; +; } +; + +;CHECK: @foo +;CHECK: <i64 0, i64 -1, i64 -2, i64 -3> +;CHECK: ret +define i32 @foo(i32 %n, i32* nocapture %A) { + %1 = icmp sgt i32 %n, 0 + br i1 %1, label %.lr.ph, label %._crit_edge + +.lr.ph: ; preds = %0 + %2 = sext i32 %n to i64 + br label %3 + +; <label>:3 ; preds = %.lr.ph, %3 + %indvars.iv = phi i64 [ %2, %.lr.ph ], [ %indvars.iv.next, %3 ] + %sum.01 = phi i32 [ undef, %.lr.ph ], [ %9, %3 ] + %4 = trunc i64 %indvars.iv to i32 + %5 = shl nsw i32 %4, 1 + %6 = sext i32 %5 to i64 + %7 = getelementptr inbounds i32* %A, i64 %6 + %8 = load i32* %7, align 4 + %9 = add nsw i32 %8, %sum.01 + %indvars.iv.next = add i64 %indvars.iv, -1 + %10 = trunc i64 %indvars.iv.next to i32 + %11 = icmp sgt i32 %10, 0 + br i1 %11, label %3, label %._crit_edge + +._crit_edge: ; preds = %3, %0 + %sum.0.lcssa = phi i32 [ undef, %0 ], [ %9, %3 ] + ret i32 %sum.0.lcssa +} + diff --git a/test/Transforms/SLPVectorizer/X86/diamond.ll b/test/Transforms/SLPVectorizer/X86/diamond.ll index 8e85cb6c9b..49c8712d20 100644 --- a/test/Transforms/SLPVectorizer/X86/diamond.ll +++ b/test/Transforms/SLPVectorizer/X86/diamond.ll @@ -41,7 +41,7 @@ entry: } -; int foo_fail(int * restrict B, int * restrict A, int n, int m) { +; int extr_user(int * restrict B, int * restrict A, int n, int m) { ; B[0] = n * A[0] + m * A[0]; ; B[1] = n * A[1] + m * A[1]; ; B[2] = n * A[2] + m * A[2]; @@ -49,10 +49,11 @@ entry: ; return A[0]; ; } -; CHECK: @foo_fail -; CHECK-NOT: load <4 x i32> +; CHECK: @extr_user +; CHECK: store <4 x i32> +; CHECK-NEXT: extractelement <4 x i32> ; CHECK: ret -define i32 @foo_fail(i32* noalias nocapture %B, i32* noalias nocapture %A, i32 %n, i32 %m) { +define i32 @extr_user(i32* noalias nocapture %B, i32* noalias nocapture %A, i32 %n, i32 %m) { entry: %0 = load i32* %A, align 4 %mul238 = add i32 %m, %n diff --git a/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp b/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp index d8cf6c592d..07ea1afe1a 100644 --- a/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp +++ b/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp @@ -48,6 +48,8 @@ TEST_F(MCJITCAPITest, simple_function) { // Creates a function that returns 42, compiles it, and runs it. LLVMModuleRef module = LLVMModuleCreateWithName("simple_module"); + + LLVMSetTarget(module, HostTriple.c_str()); LLVMValueRef function = LLVMAddFunction( module, "simple_function", LLVMFunctionType(LLVMInt32Type(), 0, 0, 0)); |