summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAbdoulaye Walsimou Gaye <awg@embtoolkit.org>2013-05-12 19:55:19 +0200
committerAbdoulaye Walsimou Gaye <awg@embtoolkit.org>2013-05-12 19:55:19 +0200
commit23d8d191eff180ba312a4d1b4fec8597e5a988d5 (patch)
tree25022dea79a8f9b830aad4d2845af6a2a9fa081b
parent0824091315296ab3da27856b76e7422348d3850d (diff)
parentfa49d7d6e4384381e4307a0d2495e6e5b15821e3 (diff)
downloadllvm-23d8d191eff180ba312a4d1b4fec8597e5a988d5.tar.gz
llvm-23d8d191eff180ba312a4d1b4fec8597e5a988d5.tar.bz2
llvm-23d8d191eff180ba312a4d1b4fec8597e5a988d5.tar.xz
Merge branch 'master' into embtk-support-master
-rw-r--r--docs/CommandLine.rst3
-rw-r--r--include/llvm/CodeGen/MachineModuleInfo.h7
-rw-r--r--include/llvm/DIBuilder.h9
-rw-r--r--include/llvm/DebugInfo.h2
-rw-r--r--include/llvm/Support/TargetRegistry.h9
-rw-r--r--lib/Bitcode/Reader/BitstreamReader.cpp13
-rw-r--r--lib/CodeGen/AsmPrinter/AsmPrinter.cpp7
-rw-r--r--lib/CodeGen/AsmPrinter/DwarfAccelTable.cpp2
-rw-r--r--lib/CodeGen/AsmPrinter/DwarfAccelTable.h2
-rw-r--r--lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp20
-rw-r--r--lib/CodeGen/AsmPrinter/DwarfDebug.cpp13
-rw-r--r--lib/CodeGen/AsmPrinter/DwarfDebug.h10
-rw-r--r--lib/CodeGen/SelectionDAG/DAGCombiner.cpp3
-rw-r--r--lib/ExecutionEngine/JIT/JITDwarfEmitter.h77
-rw-r--r--lib/ExecutionEngine/JIT/JITEmitter.cpp5
-rw-r--r--lib/IR/DIBuilder.cpp4
-rw-r--r--lib/IR/DebugInfo.cpp4
-rw-r--r--lib/Support/CommandLine.cpp24
-rw-r--r--lib/Target/AArch64/AArch64FrameLowering.cpp9
-rw-r--r--lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp2
-rw-r--r--lib/Target/ARM/AsmParser/ARMAsmParser.cpp255
-rw-r--r--lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp56
-rw-r--r--lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp2
-rw-r--r--lib/Target/Hexagon/Hexagon.td30
-rw-r--r--lib/Target/Hexagon/HexagonFrameLowering.cpp61
-rw-r--r--lib/Target/Hexagon/HexagonInstrFormats.td2
-rw-r--r--lib/Target/Hexagon/HexagonInstrInfo.cpp182
-rw-r--r--lib/Target/Hexagon/HexagonInstrInfo.h4
-rw-r--r--lib/Target/Hexagon/HexagonInstrInfoV4.td87
-rw-r--r--lib/Target/Hexagon/HexagonInstrInfoV5.td23
-rw-r--r--lib/Target/Hexagon/HexagonRegisterInfo.cpp10
-rw-r--r--lib/Target/Hexagon/HexagonRegisterInfo.h1
-rw-r--r--lib/Target/Hexagon/HexagonVLIWPacketizer.cpp1279
-rw-r--r--lib/Target/Hexagon/MCTargetDesc/HexagonMCAsmInfo.cpp2
-rw-r--r--lib/Target/Hexagon/MCTargetDesc/HexagonMCAsmInfo.h4
-rw-r--r--lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp4
-rw-r--r--lib/Target/MBlaze/MCTargetDesc/MBlazeMCTargetDesc.cpp2
-rw-r--r--lib/Target/MSP430/MCTargetDesc/MSP430MCAsmInfo.cpp2
-rw-r--r--lib/Target/MSP430/MCTargetDesc/MSP430MCAsmInfo.h3
-rw-r--r--lib/Target/Mips/CMakeLists.txt1
-rw-r--r--lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp2
-rw-r--r--lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h3
-rw-r--r--lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp4
-rw-r--r--lib/Target/Mips/Mips16FrameLowering.cpp9
-rw-r--r--lib/Target/Mips/Mips16HardFloat.cpp141
-rw-r--r--lib/Target/Mips/Mips16HardFloat.h54
-rw-r--r--lib/Target/Mips/Mips16ISelLowering.cpp11
-rw-r--r--lib/Target/Mips/MipsCallingConv.td10
-rw-r--r--lib/Target/Mips/MipsISelLowering.cpp40
-rw-r--r--lib/Target/Mips/MipsISelLowering.h14
-rw-r--r--lib/Target/Mips/MipsRegisterInfo.cpp4
-rw-r--r--lib/Target/Mips/MipsRegisterInfo.h1
-rw-r--r--lib/Target/Mips/MipsSEFrameLowering.cpp13
-rw-r--r--lib/Target/Mips/MipsSubtarget.cpp8
-rw-r--r--lib/Target/Mips/MipsSubtarget.h11
-rw-r--r--lib/Target/Mips/MipsTargetMachine.cpp3
-rw-r--r--lib/Target/NVPTX/MCTargetDesc/NVPTXMCAsmInfo.cpp2
-rw-r--r--lib/Target/NVPTX/MCTargetDesc/NVPTXMCAsmInfo.h2
-rw-r--r--lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp2
-rw-r--r--lib/Target/PowerPC/PPCFrameLowering.cpp16
-rw-r--r--lib/Target/R600/MCTargetDesc/AMDGPUMCAsmInfo.cpp2
-rw-r--r--lib/Target/R600/MCTargetDesc/AMDGPUMCAsmInfo.h3
-rw-r--r--lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp2
-rw-r--r--lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h3
-rw-r--r--lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp2
-rw-r--r--lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.h3
-rw-r--r--lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp4
-rw-r--r--lib/Target/SystemZ/SystemZFrameLowering.cpp9
-rw-r--r--lib/Target/X86/AsmParser/X86AsmParser.cpp8
-rw-r--r--lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp2
-rw-r--r--lib/Target/X86/X86FrameLowering.cpp18
-rw-r--r--lib/Target/X86/X86InstrInfo.td7
-rw-r--r--lib/Target/XCore/MCTargetDesc/XCoreMCAsmInfo.cpp2
-rw-r--r--lib/Target/XCore/MCTargetDesc/XCoreMCAsmInfo.h2
-rw-r--r--lib/Target/XCore/MCTargetDesc/XCoreMCTargetDesc.cpp4
-rw-r--r--lib/Target/XCore/XCoreFrameLowering.cpp14
-rw-r--r--lib/Transforms/InstCombine/InstCombineCasts.cpp12
-rw-r--r--lib/Transforms/InstCombine/InstCombineMulDivRem.cpp32
-rw-r--r--lib/Transforms/Vectorize/LoopVectorize.cpp135
-rw-r--r--lib/Transforms/Vectorize/SLPVectorizer.cpp2
-rw-r--r--lib/Transforms/Vectorize/VecUtils.cpp59
-rw-r--r--lib/Transforms/Vectorize/VecUtils.h5
-rw-r--r--test/CodeGen/Hexagon/pred-gp.ll28
-rw-r--r--test/CodeGen/Mips/mips16_fpret.ll77
-rw-r--r--test/CodeGen/X86/xor.ll11
-rw-r--r--test/DebugInfo/X86/template.ll84
-rw-r--r--test/ExecutionEngine/MCJIT/eh.ll2
-rw-r--r--test/MC/ARM/eh-compact-pr0.s104
-rw-r--r--test/MC/ARM/eh-compact-pr1.s74
-rw-r--r--test/MC/ARM/eh-directive-cantunwind-diagnostics.s106
-rw-r--r--test/MC/ARM/eh-directive-cantunwind.s51
-rw-r--r--test/MC/ARM/eh-directive-fnend-diagnostics.s17
-rw-r--r--test/MC/ARM/eh-directive-fnstart-diagnostics.s31
-rw-r--r--test/MC/ARM/eh-directive-handlerdata.s108
-rw-r--r--test/MC/ARM/eh-directive-pad-diagnostics.s39
-rw-r--r--test/MC/ARM/eh-directive-pad.s226
-rw-r--r--test/MC/ARM/eh-directive-personality-diagnostics.s39
-rw-r--r--test/MC/ARM/eh-directive-personality.s90
-rw-r--r--test/MC/ARM/eh-directive-save-diagnoatics.s41
-rw-r--r--test/MC/ARM/eh-directive-save.s298
-rw-r--r--test/MC/ARM/eh-directive-section-comdat.s126
-rw-r--r--test/MC/ARM/eh-directive-section-multiple-func.s129
-rw-r--r--test/MC/ARM/eh-directive-section.s164
-rw-r--r--test/MC/ARM/eh-directive-setfp-diagnostics.s87
-rw-r--r--test/MC/ARM/eh-directive-setfp.s239
-rw-r--r--test/MC/ARM/eh-directive-text-section-multiple-func.s81
-rw-r--r--test/MC/ARM/eh-directive-text-section.s82
-rw-r--r--test/MC/ARM/eh-directive-vsave-diagnostics.s41
-rw-r--r--test/MC/ARM/eh-directive-vsave.s130
-rw-r--r--test/MC/X86/x86_errors.s3
-rw-r--r--test/Transforms/InstCombine/cast.ll28
-rw-r--r--test/Transforms/InstCombine/rem.ll67
-rw-r--r--test/Transforms/LoopVectorize/reverse_induction.ll69
-rw-r--r--test/Transforms/LoopVectorize/reverse_iter.ll45
-rw-r--r--test/Transforms/SLPVectorizer/X86/diamond.ll9
-rw-r--r--unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp2
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));