Update llvm to r84175.
This commit is contained in:
parent
cd749a9c07
commit
5effb5c6a1
@ -89,7 +89,7 @@ template<> struct DenseMapInfo<unsigned long long> {
|
||||
static inline unsigned long long getEmptyKey() { return ~0ULL; }
|
||||
static inline unsigned long long getTombstoneKey() { return ~0ULL - 1ULL; }
|
||||
static unsigned getHashValue(const unsigned long long& Val) {
|
||||
return Val * 37ULL;
|
||||
return (unsigned)Val * 37ULL;
|
||||
}
|
||||
static bool isPod() { return true; }
|
||||
static bool isEqual(const unsigned long long& LHS,
|
||||
|
@ -988,8 +988,8 @@ public:
|
||||
BumpPtrAllocator& getAllocator() { return F.getAllocator(); }
|
||||
|
||||
private:
|
||||
Factory(const Factory& RHS) {};
|
||||
void operator=(const Factory& RHS) {};
|
||||
Factory(const Factory& RHS) {}
|
||||
void operator=(const Factory& RHS) {}
|
||||
};
|
||||
|
||||
friend class Factory;
|
||||
|
@ -500,8 +500,8 @@ namespace llvm {
|
||||
/// ComputeOperandLatency - Override dependence edge latency using
|
||||
/// operand use/def information
|
||||
///
|
||||
virtual void ComputeOperandLatency(SUnit *Def, SUnit *Use,
|
||||
SDep& dep) const { };
|
||||
virtual void ComputeOperandLatency(SUnit *, SUnit *,
|
||||
SDep&) const { }
|
||||
|
||||
/// Schedule - Order nodes according to selected style, filling
|
||||
/// in the Sequence member.
|
||||
|
@ -43,7 +43,7 @@ namespace llvmc {
|
||||
class Edge : public llvm::RefCountedBaseVPTR<Edge> {
|
||||
public:
|
||||
Edge(const std::string& T) : ToolName_(T) {}
|
||||
virtual ~Edge() {};
|
||||
virtual ~Edge() {}
|
||||
|
||||
const std::string& ToolName() const { return ToolName_; }
|
||||
virtual unsigned Weight(const InputLanguagesSet& InLangs) const = 0;
|
||||
|
@ -149,7 +149,7 @@ public:
|
||||
/// CheckInvariants - For testing only. Return true if all internal
|
||||
/// invariants are preserved, or return false and set ErrorStr to a helpful
|
||||
/// error message.
|
||||
virtual bool CheckInvariants(std::string &ErrorStr) {
|
||||
virtual bool CheckInvariants(std::string &) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -181,7 +181,7 @@ public:
|
||||
/// duplicates
|
||||
void Profile(FoldingSetNodeID &ID) const;
|
||||
|
||||
virtual void replaceUsesOfWithOnConstant(Value *From, Value *To, Use *U) {
|
||||
virtual void replaceUsesOfWithOnConstant(Value *, Value *, Use *) {
|
||||
llvm_unreachable("This should never be called because MDNodes have no ops");
|
||||
}
|
||||
|
||||
@ -291,7 +291,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void replaceUsesOfWithOnConstant(Value *From, Value *To, Use *U) {
|
||||
virtual void replaceUsesOfWithOnConstant(Value *, Value *, Use *) {
|
||||
llvm_unreachable(
|
||||
"This should never be called because NamedMDNodes have no ops");
|
||||
}
|
||||
@ -361,7 +361,7 @@ public:
|
||||
|
||||
/// ValueIsDeleted - This handler is used to update metadata store
|
||||
/// when a value is deleted.
|
||||
void ValueIsDeleted(const Value *V) {}
|
||||
void ValueIsDeleted(const Value *) {}
|
||||
void ValueIsDeleted(const Instruction *Inst) {
|
||||
removeMDs(Inst);
|
||||
}
|
||||
|
@ -57,8 +57,8 @@ public:
|
||||
}
|
||||
|
||||
static inline bool classof(const Operator *) { return true; }
|
||||
static inline bool classof(const Instruction *I) { return true; }
|
||||
static inline bool classof(const ConstantExpr *I) { return true; }
|
||||
static inline bool classof(const Instruction *) { return true; }
|
||||
static inline bool classof(const ConstantExpr *) { return true; }
|
||||
static inline bool classof(const Value *V) {
|
||||
return isa<Instruction>(V) || isa<ConstantExpr>(V);
|
||||
}
|
||||
|
@ -276,7 +276,7 @@ public:
|
||||
/// doInitialization - Virtual method overridden by subclasses to do
|
||||
/// any necessary per-module initialization.
|
||||
///
|
||||
virtual bool doInitialization(Module &M) { return false; }
|
||||
virtual bool doInitialization(Module &) { return false; }
|
||||
|
||||
/// runOnFunction - Virtual method overriden by subclasses to do the
|
||||
/// per-function processing of the pass.
|
||||
@ -328,7 +328,7 @@ public:
|
||||
/// doInitialization - Virtual method overridden by subclasses to do
|
||||
/// any necessary per-module initialization.
|
||||
///
|
||||
virtual bool doInitialization(Module &M) { return false; }
|
||||
virtual bool doInitialization(Module &) { return false; }
|
||||
|
||||
/// doInitialization - Virtual method overridden by BasicBlockPass subclasses
|
||||
/// to do any necessary per-function initialization.
|
||||
|
@ -660,7 +660,7 @@ template<>
|
||||
class parser<std::string> : public basic_parser<std::string> {
|
||||
public:
|
||||
// parse - Return true on error.
|
||||
bool parse(Option &, StringRef ArgName, StringRef Arg, std::string &Value) {
|
||||
bool parse(Option &, StringRef, StringRef Arg, std::string &Value) {
|
||||
Value = Arg.str();
|
||||
return false;
|
||||
}
|
||||
@ -681,7 +681,7 @@ template<>
|
||||
class parser<char> : public basic_parser<char> {
|
||||
public:
|
||||
// parse - Return true on error.
|
||||
bool parse(Option &, StringRef ArgName, StringRef Arg, char &Value) {
|
||||
bool parse(Option &, StringRef, StringRef Arg, char &Value) {
|
||||
Value = Arg[0];
|
||||
return false;
|
||||
}
|
||||
|
@ -29,10 +29,10 @@ namespace llvm {
|
||||
unsigned Line, Col;
|
||||
|
||||
DebugLocTuple()
|
||||
: Scope(0), InlinedAtLoc(0), Line(~0U), Col(~0U) {};
|
||||
: Scope(0), InlinedAtLoc(0), Line(~0U), Col(~0U) {}
|
||||
|
||||
DebugLocTuple(MDNode *n, MDNode *i, unsigned l, unsigned c)
|
||||
: Scope(n), InlinedAtLoc(i), Line(l), Col(c) {};
|
||||
: Scope(n), InlinedAtLoc(i), Line(l), Col(c) {}
|
||||
|
||||
bool operator==(const DebugLocTuple &DLT) const {
|
||||
return Scope == DLT.Scope &&
|
||||
|
@ -51,7 +51,7 @@ private:
|
||||
/// for a \see write_impl() call to handle the data which has been put into
|
||||
/// this buffer.
|
||||
char *OutBufStart, *OutBufEnd, *OutBufCur;
|
||||
|
||||
|
||||
enum BufferKind {
|
||||
Unbuffered = 0,
|
||||
InternalBuffer,
|
||||
@ -211,7 +211,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(double N);
|
||||
raw_ostream &operator<<(double N);
|
||||
|
||||
/// write_hex - Output \arg N in hexadecimal, without any prefix or padding.
|
||||
raw_ostream &write_hex(unsigned long long N);
|
||||
@ -224,8 +224,8 @@ public:
|
||||
|
||||
/// indent - Insert 'NumSpaces' spaces.
|
||||
raw_ostream &indent(unsigned NumSpaces);
|
||||
|
||||
|
||||
|
||||
|
||||
/// Changes the foreground color of text that will be output from this point
|
||||
/// forward.
|
||||
/// @param colors ANSI color to use, the special SAVEDCOLOR can be used to
|
||||
@ -233,8 +233,8 @@ public:
|
||||
/// @param bold bold/brighter text, default false
|
||||
/// @param bg if true change the background, default: change foreground
|
||||
/// @returns itself so it can be used within << invocations
|
||||
virtual raw_ostream &changeColor(enum Colors colors, bool bold=false,
|
||||
bool bg=false) { return *this; }
|
||||
virtual raw_ostream &changeColor(enum Colors, bool = false,
|
||||
bool = false) { return *this; }
|
||||
|
||||
/// Resets the colors to terminal defaults. Call this when you are done
|
||||
/// outputting colored text, or before program exit.
|
||||
@ -253,7 +253,7 @@ private:
|
||||
/// write_impl - The is the piece of the class that is implemented
|
||||
/// by subclasses. This writes the \args Size bytes starting at
|
||||
/// \arg Ptr to the underlying stream.
|
||||
///
|
||||
///
|
||||
/// This function is guaranteed to only be called at a point at which it is
|
||||
/// safe for the subclass to install a new buffer via SetBuffer.
|
||||
///
|
||||
@ -331,7 +331,7 @@ class raw_fd_ostream : public raw_ostream {
|
||||
virtual size_t preferred_buffer_size();
|
||||
|
||||
public:
|
||||
|
||||
|
||||
enum {
|
||||
/// F_Excl - When opening a file, this flag makes raw_fd_ostream
|
||||
/// report an error if the file already exists.
|
||||
@ -346,7 +346,7 @@ public:
|
||||
/// make this distinction.
|
||||
F_Binary = 4
|
||||
};
|
||||
|
||||
|
||||
/// raw_fd_ostream - Open the specified file for writing. If an error occurs,
|
||||
/// information about the error is put into ErrorInfo, and the stream should
|
||||
/// be immediately destroyed; the string will be empty if no error occurred.
|
||||
@ -359,10 +359,10 @@ public:
|
||||
|
||||
/// raw_fd_ostream ctor - FD is the file descriptor that this writes to. If
|
||||
/// ShouldClose is true, this closes the file when the stream is destroyed.
|
||||
raw_fd_ostream(int fd, bool shouldClose,
|
||||
bool unbuffered=false) : raw_ostream(unbuffered), FD(fd),
|
||||
raw_fd_ostream(int fd, bool shouldClose,
|
||||
bool unbuffered=false) : raw_ostream(unbuffered), FD(fd),
|
||||
ShouldClose(shouldClose) {}
|
||||
|
||||
|
||||
~raw_fd_ostream();
|
||||
|
||||
/// close - Manually flush the stream and close the file.
|
||||
@ -465,7 +465,7 @@ public:
|
||||
class raw_null_ostream : public raw_ostream {
|
||||
/// write_impl - See raw_ostream::write_impl.
|
||||
virtual void write_impl(const char *Ptr, size_t size);
|
||||
|
||||
|
||||
/// current_pos - Return the current position within the stream, not
|
||||
/// counting the bytes currently in the buffer.
|
||||
virtual uint64_t current_pos();
|
||||
|
@ -310,6 +310,28 @@ BasicAliasAnalysis::getModRefInfo(CallSite CS, Value *P, unsigned Size) {
|
||||
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(CS.getInstruction())) {
|
||||
switch (II->getIntrinsicID()) {
|
||||
default: break;
|
||||
case Intrinsic::memcpy:
|
||||
case Intrinsic::memmove: {
|
||||
unsigned Len = ~0U;
|
||||
if (ConstantInt *LenCI = dyn_cast<ConstantInt>(II->getOperand(3)))
|
||||
Len = LenCI->getZExtValue();
|
||||
Value *Dest = II->getOperand(1);
|
||||
Value *Src = II->getOperand(2);
|
||||
if (alias(Dest, Len, P, Size) == NoAlias) {
|
||||
if (alias(Src, Len, P, Size) == NoAlias)
|
||||
return NoModRef;
|
||||
return Ref;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Intrinsic::memset:
|
||||
if (ConstantInt *LenCI = dyn_cast<ConstantInt>(II->getOperand(3))) {
|
||||
unsigned Len = LenCI->getZExtValue();
|
||||
Value *Dest = II->getOperand(1);
|
||||
if (alias(Dest, Len, P, Size) == NoAlias)
|
||||
return NoModRef;
|
||||
}
|
||||
break;
|
||||
case Intrinsic::atomic_cmp_swap:
|
||||
case Intrinsic::atomic_swap:
|
||||
case Intrinsic::atomic_load_add:
|
||||
@ -322,9 +344,25 @@ BasicAliasAnalysis::getModRefInfo(CallSite CS, Value *P, unsigned Size) {
|
||||
case Intrinsic::atomic_load_min:
|
||||
case Intrinsic::atomic_load_umax:
|
||||
case Intrinsic::atomic_load_umin:
|
||||
if (alias(II->getOperand(1), Size, P, Size) == NoAlias)
|
||||
return NoModRef;
|
||||
if (TD) {
|
||||
Value *Op1 = II->getOperand(1);
|
||||
unsigned Op1Size = TD->getTypeStoreSize(Op1->getType());
|
||||
if (alias(Op1, Op1Size, P, Size) == NoAlias)
|
||||
return NoModRef;
|
||||
}
|
||||
break;
|
||||
case Intrinsic::lifetime_start:
|
||||
case Intrinsic::lifetime_end:
|
||||
case Intrinsic::invariant_start: {
|
||||
unsigned PtrSize = cast<ConstantInt>(II->getOperand(1))->getZExtValue();
|
||||
if (alias(II->getOperand(2), PtrSize, P, Size) == NoAlias)
|
||||
return NoModRef;
|
||||
}
|
||||
case Intrinsic::invariant_end: {
|
||||
unsigned PtrSize = cast<ConstantInt>(II->getOperand(2))->getZExtValue();
|
||||
if (alias(II->getOperand(3), PtrSize, P, Size) == NoAlias)
|
||||
return NoModRef;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -145,7 +145,10 @@ class DbgConcreteScope;
|
||||
class VISIBILITY_HIDDEN DbgScope {
|
||||
DbgScope *Parent; // Parent to this scope.
|
||||
DIDescriptor Desc; // Debug info descriptor for scope.
|
||||
// Either subprogram or block.
|
||||
// FIXME use WeakVH for Desc.
|
||||
WeakVH InlinedAt; // If this scope represents inlined
|
||||
// function body then this is the location
|
||||
// where this body is inlined.
|
||||
unsigned StartLabelID; // Label ID of the beginning of scope.
|
||||
unsigned EndLabelID; // Label ID of the end of scope.
|
||||
const MachineInstr *LastInsn; // Last instruction of this scope.
|
||||
@ -157,14 +160,17 @@ class VISIBILITY_HIDDEN DbgScope {
|
||||
// Private state for dump()
|
||||
mutable unsigned IndentLevel;
|
||||
public:
|
||||
DbgScope(DbgScope *P, DIDescriptor D)
|
||||
: Parent(P), Desc(D), StartLabelID(0), EndLabelID(0), LastInsn(0),
|
||||
FirstInsn(0), IndentLevel(0) {}
|
||||
DbgScope(DbgScope *P, DIDescriptor D, MDNode *I = 0)
|
||||
: Parent(P), Desc(D), InlinedAt(I), StartLabelID(0), EndLabelID(0),
|
||||
LastInsn(0), FirstInsn(0), IndentLevel(0) {}
|
||||
virtual ~DbgScope();
|
||||
|
||||
// Accessors.
|
||||
DbgScope *getParent() const { return Parent; }
|
||||
DIDescriptor getDesc() const { return Desc; }
|
||||
MDNode *getInlinedAt() const {
|
||||
return dyn_cast_or_null<MDNode>(InlinedAt);
|
||||
}
|
||||
unsigned getStartLabelID() const { return StartLabelID; }
|
||||
unsigned getEndLabelID() const { return EndLabelID; }
|
||||
SmallVector<DbgScope *, 4> &getScopes() { return Scopes; }
|
||||
@ -1296,29 +1302,39 @@ DIE *DwarfDebug::CreateDbgScopeVariable(DbgVariable *DV, CompileUnit *Unit) {
|
||||
|
||||
/// getOrCreateScope - Returns the scope associated with the given descriptor.
|
||||
///
|
||||
DbgScope *DwarfDebug::getDbgScope(MDNode *N, const MachineInstr *MI) {
|
||||
DbgScope *DwarfDebug::getDbgScope(MDNode *N, const MachineInstr *MI,
|
||||
MDNode *InlinedAt) {
|
||||
DbgScope *&Slot = DbgScopeMap[N];
|
||||
if (Slot) return Slot;
|
||||
|
||||
DbgScope *Parent = NULL;
|
||||
|
||||
DIDescriptor Scope(N);
|
||||
if (Scope.isCompileUnit()) {
|
||||
return NULL;
|
||||
} else if (Scope.isSubprogram()) {
|
||||
DISubprogram SP(N);
|
||||
DIDescriptor ParentDesc = SP.getContext();
|
||||
if (!ParentDesc.isNull() && !ParentDesc.isCompileUnit())
|
||||
Parent = getDbgScope(ParentDesc.getNode(), MI);
|
||||
} else if (Scope.isLexicalBlock()) {
|
||||
DILexicalBlock DB(N);
|
||||
DIDescriptor ParentDesc = DB.getContext();
|
||||
if (!ParentDesc.isNull())
|
||||
Parent = getDbgScope(ParentDesc.getNode(), MI);
|
||||
} else
|
||||
assert (0 && "Unexpected scope info");
|
||||
if (InlinedAt) {
|
||||
DILocation IL(InlinedAt);
|
||||
assert (!IL.isNull() && "Invalid InlindAt location!");
|
||||
DenseMap<MDNode *, DbgScope *>::iterator DSI =
|
||||
DbgScopeMap.find(IL.getScope().getNode());
|
||||
assert (DSI != DbgScopeMap.end() && "Unable to find InlineAt scope!");
|
||||
Parent = DSI->second;
|
||||
} else {
|
||||
DIDescriptor Scope(N);
|
||||
if (Scope.isCompileUnit()) {
|
||||
return NULL;
|
||||
} else if (Scope.isSubprogram()) {
|
||||
DISubprogram SP(N);
|
||||
DIDescriptor ParentDesc = SP.getContext();
|
||||
if (!ParentDesc.isNull() && !ParentDesc.isCompileUnit())
|
||||
Parent = getDbgScope(ParentDesc.getNode(), MI, InlinedAt);
|
||||
} else if (Scope.isLexicalBlock()) {
|
||||
DILexicalBlock DB(N);
|
||||
DIDescriptor ParentDesc = DB.getContext();
|
||||
if (!ParentDesc.isNull())
|
||||
Parent = getDbgScope(ParentDesc.getNode(), MI, InlinedAt);
|
||||
} else
|
||||
assert (0 && "Unexpected scope info");
|
||||
}
|
||||
|
||||
Slot = new DbgScope(Parent, DIDescriptor(N));
|
||||
Slot = new DbgScope(Parent, DIDescriptor(N), InlinedAt);
|
||||
Slot->setFirstInsn(MI);
|
||||
|
||||
if (Parent)
|
||||
@ -1795,7 +1811,10 @@ void DwarfDebug::CollectVariableInfo() {
|
||||
DIVariable DV (Var);
|
||||
if (DV.isNull()) continue;
|
||||
unsigned VSlot = VI->second;
|
||||
DbgScope *Scope = getDbgScope(DV.getContext().getNode(), NULL);
|
||||
DenseMap<MDNode *, DbgScope *>::iterator DSI =
|
||||
DbgScopeMap.find(DV.getContext().getNode());
|
||||
assert (DSI != DbgScopeMap.end() && "Unable to find variable scope!");
|
||||
DbgScope *Scope = DSI->second;
|
||||
Scope->AddVariable(new DbgVariable(DV, VSlot, false));
|
||||
}
|
||||
}
|
||||
@ -1849,7 +1868,7 @@ bool DwarfDebug::ExtractScopeInformation(MachineFunction *MF) {
|
||||
// into a scope DIE at the end.
|
||||
DIDescriptor D(DLT.Scope);
|
||||
if (!D.isCompileUnit()) {
|
||||
DbgScope *Scope = getDbgScope(DLT.Scope, MInsn);
|
||||
DbgScope *Scope = getDbgScope(DLT.Scope, MInsn, DLT.InlinedAtLoc);
|
||||
Scope->setLastInsn(MInsn);
|
||||
}
|
||||
}
|
||||
|
@ -364,7 +364,7 @@ class VISIBILITY_HIDDEN DwarfDebug : public Dwarf {
|
||||
/// getDbgScope - Returns the scope associated with the given descriptor.
|
||||
///
|
||||
DbgScope *getOrCreateScope(MDNode *N);
|
||||
DbgScope *getDbgScope(MDNode *N, const MachineInstr *MI);
|
||||
DbgScope *getDbgScope(MDNode *N, const MachineInstr *MI, MDNode *InlinedAt);
|
||||
|
||||
/// ConstructDbgScope - Construct the components of a scope.
|
||||
///
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
using namespace llvm;
|
||||
|
||||
STATISTIC(NumHeaderAligned, "Number of loop header aligned");
|
||||
STATISTIC(NumLoopsAligned, "Number of loops aligned");
|
||||
STATISTIC(NumIntraElim, "Number of intra loop branches eliminated");
|
||||
STATISTIC(NumIntraMoved, "Number of intra loop branches moved");
|
||||
|
||||
@ -42,9 +42,6 @@ namespace {
|
||||
SmallVector<std::pair<MachineBasicBlock*,MachineBasicBlock*>, 4>
|
||||
UncondJmpMBBs;
|
||||
|
||||
/// LoopHeaders - A list of BBs which are loop headers.
|
||||
SmallVector<MachineBasicBlock*, 4> LoopHeaders;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
CodePlacementOpt() : MachineFunctionPass(&ID) {}
|
||||
@ -62,9 +59,8 @@ namespace {
|
||||
|
||||
private:
|
||||
bool OptimizeIntraLoopEdges();
|
||||
bool HeaderShouldBeAligned(MachineBasicBlock *MBB, MachineLoop *L,
|
||||
SmallPtrSet<MachineBasicBlock*, 4> &DoNotAlign);
|
||||
bool AlignLoops(MachineFunction &MF);
|
||||
bool AlignLoop(MachineFunction &MF, MachineLoop *L, unsigned Align);
|
||||
};
|
||||
|
||||
char CodePlacementOpt::ID = 0;
|
||||
@ -233,57 +229,12 @@ bool CodePlacementOpt::OptimizeIntraLoopEdges() {
|
||||
ChangedMBBs.insert(FtMBB);
|
||||
}
|
||||
Changed = true;
|
||||
|
||||
// If BB is the loop latch, we may have a new loop headr.
|
||||
if (MBB == L->getLoopLatch()) {
|
||||
assert(MLI->isLoopHeader(SuccMBB) &&
|
||||
"Only succ of loop latch is not the header?");
|
||||
if (HasOneIntraSucc && IntraSucc)
|
||||
std::replace(LoopHeaders.begin(),LoopHeaders.end(), SuccMBB, IntraSucc);
|
||||
}
|
||||
}
|
||||
|
||||
++NumIntraMoved;
|
||||
return Changed;
|
||||
}
|
||||
|
||||
/// HeaderShouldBeAligned - Return true if the specified loop header block
|
||||
/// should be aligned. For now, we will not align it if all the predcessors
|
||||
/// (i.e. loop back edges) are laid out above the header. FIXME: Do not
|
||||
/// align small loops.
|
||||
bool
|
||||
CodePlacementOpt::HeaderShouldBeAligned(MachineBasicBlock *MBB, MachineLoop *L,
|
||||
SmallPtrSet<MachineBasicBlock*, 4> &DoNotAlign) {
|
||||
if (DoNotAlign.count(MBB))
|
||||
return false;
|
||||
|
||||
bool BackEdgeBelow = false;
|
||||
for (MachineBasicBlock::pred_iterator PI = MBB->pred_begin(),
|
||||
PE = MBB->pred_end(); PI != PE; ++PI) {
|
||||
MachineBasicBlock *PredMBB = *PI;
|
||||
if (PredMBB == MBB || PredMBB->getNumber() > MBB->getNumber()) {
|
||||
BackEdgeBelow = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!BackEdgeBelow)
|
||||
return false;
|
||||
|
||||
// Ok, we are going to align this loop header. If it's an inner loop,
|
||||
// do not align its outer loop.
|
||||
MachineBasicBlock *PreHeader = L->getLoopPreheader();
|
||||
if (PreHeader) {
|
||||
MachineLoop *L = MLI->getLoopFor(PreHeader);
|
||||
if (L) {
|
||||
MachineBasicBlock *HeaderBlock = L->getHeader();
|
||||
HeaderBlock->setAlignment(0);
|
||||
DoNotAlign.insert(HeaderBlock);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// AlignLoops - Align loop headers to target preferred alignments.
|
||||
///
|
||||
bool CodePlacementOpt::AlignLoops(MachineFunction &MF) {
|
||||
@ -295,26 +246,37 @@ bool CodePlacementOpt::AlignLoops(MachineFunction &MF) {
|
||||
if (!Align)
|
||||
return false; // Don't care about loop alignment.
|
||||
|
||||
// Make sure blocks are numbered in order
|
||||
MF.RenumberBlocks();
|
||||
|
||||
bool Changed = false;
|
||||
SmallPtrSet<MachineBasicBlock*, 4> DoNotAlign;
|
||||
for (unsigned i = 0, e = LoopHeaders.size(); i != e; ++i) {
|
||||
MachineBasicBlock *HeaderMBB = LoopHeaders[i];
|
||||
MachineBasicBlock *PredMBB = prior(MachineFunction::iterator(HeaderMBB));
|
||||
MachineLoop *L = MLI->getLoopFor(HeaderMBB);
|
||||
if (L == MLI->getLoopFor(PredMBB))
|
||||
// If previously BB is in the same loop, don't align this BB. We want
|
||||
// to prevent adding noop's inside a loop.
|
||||
continue;
|
||||
if (HeaderShouldBeAligned(HeaderMBB, L, DoNotAlign)) {
|
||||
HeaderMBB->setAlignment(Align);
|
||||
Changed = true;
|
||||
++NumHeaderAligned;
|
||||
}
|
||||
|
||||
for (MachineLoopInfo::iterator I = MLI->begin(), E = MLI->end();
|
||||
I != E; ++I)
|
||||
Changed |= AlignLoop(MF, *I, Align);
|
||||
|
||||
return Changed;
|
||||
}
|
||||
|
||||
bool CodePlacementOpt::AlignLoop(MachineFunction &MF, MachineLoop *L,
|
||||
unsigned Align) {
|
||||
bool Changed = false;
|
||||
|
||||
// Do alignment for nested loops.
|
||||
for (MachineLoop::iterator I = L->begin(), E = L->end(); I != E; ++I)
|
||||
Changed |= AlignLoop(MF, *I, Align);
|
||||
|
||||
MachineBasicBlock *TopMBB = L->getHeader();
|
||||
if (TopMBB == MF.begin()) return Changed;
|
||||
|
||||
MachineBasicBlock *PredMBB = prior(MachineFunction::iterator(TopMBB));
|
||||
while (MLI->getLoopFor(PredMBB) == L) {
|
||||
TopMBB = PredMBB;
|
||||
if (TopMBB == MF.begin()) return Changed;
|
||||
PredMBB = prior(MachineFunction::iterator(TopMBB));
|
||||
}
|
||||
|
||||
TopMBB->setAlignment(Align);
|
||||
Changed = true;
|
||||
++NumLoopsAligned;
|
||||
|
||||
return Changed;
|
||||
}
|
||||
|
||||
@ -326,7 +288,7 @@ bool CodePlacementOpt::runOnMachineFunction(MachineFunction &MF) {
|
||||
TLI = MF.getTarget().getTargetLowering();
|
||||
TII = MF.getTarget().getInstrInfo();
|
||||
|
||||
// Analyze the BBs first and keep track of loop headers and BBs that
|
||||
// Analyze the BBs first and keep track of BBs that
|
||||
// end with an unconditional jmp to another block in the same loop.
|
||||
for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) {
|
||||
MachineBasicBlock *MBB = I;
|
||||
@ -335,8 +297,6 @@ bool CodePlacementOpt::runOnMachineFunction(MachineFunction &MF) {
|
||||
MachineLoop *L = MLI->getLoopFor(MBB);
|
||||
if (!L)
|
||||
continue;
|
||||
if (MLI->isLoopHeader(MBB))
|
||||
LoopHeaders.push_back(MBB);
|
||||
|
||||
MachineBasicBlock *TBB = 0, *FBB = 0;
|
||||
SmallVector<MachineOperand, 4> Cond;
|
||||
@ -352,7 +312,6 @@ bool CodePlacementOpt::runOnMachineFunction(MachineFunction &MF) {
|
||||
|
||||
ChangedMBBs.clear();
|
||||
UncondJmpMBBs.clear();
|
||||
LoopHeaders.clear();
|
||||
|
||||
return Changed;
|
||||
}
|
||||
|
@ -323,10 +323,21 @@ bool LiveVariables::HandlePhysRegKill(unsigned Reg, MachineInstr *MI) {
|
||||
// The last partial def kills the register.
|
||||
LastPartDef->addOperand(MachineOperand::CreateReg(Reg, false/*IsDef*/,
|
||||
true/*IsImp*/, true/*IsKill*/));
|
||||
else
|
||||
else {
|
||||
MachineOperand *MO =
|
||||
LastRefOrPartRef->findRegisterDefOperand(Reg, false, TRI);
|
||||
bool NeedEC = MO->isEarlyClobber() && MO->getReg() != Reg;
|
||||
// If the last reference is the last def, then it's not used at all.
|
||||
// That is, unless we are currently processing the last reference itself.
|
||||
LastRefOrPartRef->addRegisterDead(Reg, TRI, true);
|
||||
if (NeedEC) {
|
||||
// If we are adding a subreg def and the superreg def is marked early
|
||||
// clobber, add an early clobber marker to the subreg def.
|
||||
MO = LastRefOrPartRef->findRegisterDefOperand(Reg);
|
||||
if (MO)
|
||||
MO->setIsEarlyClobber();
|
||||
}
|
||||
}
|
||||
} else if (!PhysRegUse[Reg]) {
|
||||
// Partial uses. Mark register def dead and add implicit def of
|
||||
// sub-registers which are used.
|
||||
|
@ -212,17 +212,17 @@ void MachineOperand::print(raw_ostream &OS, const TargetMachine *TM) const {
|
||||
isEarlyClobber()) {
|
||||
OS << '<';
|
||||
bool NeedComma = false;
|
||||
if (isImplicit()) {
|
||||
if (NeedComma) OS << ',';
|
||||
OS << (isDef() ? "imp-def" : "imp-use");
|
||||
NeedComma = true;
|
||||
} else if (isDef()) {
|
||||
if (isDef()) {
|
||||
if (NeedComma) OS << ',';
|
||||
if (isEarlyClobber())
|
||||
OS << "earlyclobber,";
|
||||
if (isImplicit())
|
||||
OS << "imp-";
|
||||
OS << "def";
|
||||
NeedComma = true;
|
||||
}
|
||||
} else if (isImplicit())
|
||||
OS << "imp-use";
|
||||
|
||||
if (isKill() || isDead() || isUndef()) {
|
||||
if (NeedComma) OS << ',';
|
||||
if (isKill()) OS << "kill";
|
||||
|
@ -767,7 +767,7 @@ void PEI::scavengeFrameVirtualRegs(MachineFunction &Fn) {
|
||||
unsigned CurrentScratchReg = 0;
|
||||
bool havePrevValue = false;
|
||||
unsigned PrevScratchReg = 0;
|
||||
int PrevValue;
|
||||
int PrevValue = 0;
|
||||
MachineInstr *PrevLastUseMI = NULL;
|
||||
unsigned PrevLastUseOp = 0;
|
||||
bool trackingCurrentValue = false;
|
||||
@ -778,9 +778,7 @@ void PEI::scavengeFrameVirtualRegs(MachineFunction &Fn) {
|
||||
// directly.
|
||||
for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); ++I) {
|
||||
MachineInstr *MI = I;
|
||||
// Likewise, call getNumOperands() each iteration, as the MI may change
|
||||
// inside the loop (with 'i' updated accordingly).
|
||||
for (unsigned i = 0; i != MI->getNumOperands(); ++i)
|
||||
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i)
|
||||
if (MI->getOperand(i).isReg()) {
|
||||
MachineOperand &MO = MI->getOperand(i);
|
||||
unsigned Reg = MO.getReg();
|
||||
@ -853,6 +851,7 @@ void PEI::scavengeFrameVirtualRegs(MachineFunction &Fn) {
|
||||
// just calculating the value we already have.
|
||||
BB->erase(I, LastUseMI);
|
||||
MI = I = LastUseMI;
|
||||
e = MI->getNumOperands();
|
||||
|
||||
CurrentScratchReg = PrevScratchReg;
|
||||
// Extend the live range of the register
|
||||
|
@ -74,16 +74,28 @@ namespace {
|
||||
|
||||
/// CPUser - One user of a constant pool, keeping the machine instruction
|
||||
/// pointer, the constant pool being referenced, and the max displacement
|
||||
/// allowed from the instruction to the CP.
|
||||
/// allowed from the instruction to the CP. The HighWaterMark records the
|
||||
/// highest basic block where a new CPEntry can be placed. To ensure this
|
||||
/// pass terminates, the CP entries are initially placed at the end of the
|
||||
/// function and then move monotonically to lower addresses. The
|
||||
/// exception to this rule is when the current CP entry for a particular
|
||||
/// CPUser is out of range, but there is another CP entry for the same
|
||||
/// constant value in range. We want to use the existing in-range CP
|
||||
/// entry, but if it later moves out of range, the search for new water
|
||||
/// should resume where it left off. The HighWaterMark is used to record
|
||||
/// that point.
|
||||
struct CPUser {
|
||||
MachineInstr *MI;
|
||||
MachineInstr *CPEMI;
|
||||
MachineBasicBlock *HighWaterMark;
|
||||
unsigned MaxDisp;
|
||||
bool NegOk;
|
||||
bool IsSoImm;
|
||||
CPUser(MachineInstr *mi, MachineInstr *cpemi, unsigned maxdisp,
|
||||
bool neg, bool soimm)
|
||||
: MI(mi), CPEMI(cpemi), MaxDisp(maxdisp), NegOk(neg), IsSoImm(soimm) {}
|
||||
: MI(mi), CPEMI(cpemi), MaxDisp(maxdisp), NegOk(neg), IsSoImm(soimm) {
|
||||
HighWaterMark = CPEMI->getParent();
|
||||
}
|
||||
};
|
||||
|
||||
/// CPUsers - Keep track of all of the machine instructions that use various
|
||||
@ -962,8 +974,8 @@ bool ARMConstantIslands::LookForWater(CPUser &U, unsigned UserOffset,
|
||||
B = WaterList.begin();; --IP) {
|
||||
MachineBasicBlock* WaterBB = *IP;
|
||||
// Check if water is in range and at a lower address than the current one.
|
||||
if (WaterIsInRange(UserOffset, WaterBB, U) &&
|
||||
WaterBB->getNumber() < U.CPEMI->getParent()->getNumber()) {
|
||||
if (WaterBB->getNumber() < U.HighWaterMark->getNumber() &&
|
||||
WaterIsInRange(UserOffset, WaterBB, U)) {
|
||||
unsigned WBBId = WaterBB->getNumber();
|
||||
if (isThumb &&
|
||||
(BBOffsets[WBBId] + BBSizes[WBBId])%4 != 0) {
|
||||
@ -1006,14 +1018,12 @@ void ARMConstantIslands::CreateNewWater(unsigned CPUserIndex,
|
||||
BBSizes[UserMBB->getNumber()];
|
||||
assert(OffsetOfNextBlock== BBOffsets[UserMBB->getNumber()+1]);
|
||||
|
||||
// If the use is at the end of the block, or the end of the block
|
||||
// is within range, make new water there. (The addition below is
|
||||
// for the unconditional branch we will be adding: 4 bytes on ARM + Thumb2,
|
||||
// 2 on Thumb1. Possible Thumb1 alignment padding is allowed for
|
||||
// If the block does not end in an unconditional branch already, and if the
|
||||
// end of the block is within range, make new water there. (The addition
|
||||
// below is for the unconditional branch we will be adding: 4 bytes on ARM +
|
||||
// Thumb2, 2 on Thumb1. Possible Thumb1 alignment padding is allowed for
|
||||
// inside OffsetIsInRange.
|
||||
// If the block ends in an unconditional branch already, it is water,
|
||||
// and is known to be out of range, so we'll always be adding a branch.)
|
||||
if (&UserMBB->back() == UserMI ||
|
||||
if (BBHasFallthrough(UserMBB) &&
|
||||
OffsetIsInRange(UserOffset, OffsetOfNextBlock + (isThumb1 ? 2: 4),
|
||||
U.MaxDisp, U.NegOk, U.IsSoImm)) {
|
||||
DEBUG(errs() << "Split at end of block\n");
|
||||
@ -1131,6 +1141,7 @@ bool ARMConstantIslands::HandleConstantPoolUser(MachineFunction &MF,
|
||||
|
||||
// Now that we have an island to add the CPE to, clone the original CPE and
|
||||
// add it to the island.
|
||||
U.HighWaterMark = NewIsland;
|
||||
U.CPEMI = BuildMI(NewIsland, DebugLoc::getUnknownLoc(),
|
||||
TII->get(ARM::CONSTPOOL_ENTRY))
|
||||
.addImm(ID).addConstantPoolIndex(CPI).addImm(Size);
|
||||
|
@ -133,6 +133,13 @@ private:
|
||||
SDNode *SelectVLD(SDValue Op, unsigned NumVecs, unsigned *DOpcodes,
|
||||
unsigned *QOpcodes0, unsigned *QOpcodes1);
|
||||
|
||||
/// SelectVST - Select NEON store intrinsics. NumVecs should
|
||||
/// be 2, 3 or 4. The opcode arrays specify the instructions used for
|
||||
/// stores of D registers and even subregs and odd subregs of Q registers.
|
||||
/// For NumVecs == 2, QOpcodes1 is not used.
|
||||
SDNode *SelectVST(SDValue Op, unsigned NumVecs, unsigned *DOpcodes,
|
||||
unsigned *QOpcodes0, unsigned *QOpcodes1);
|
||||
|
||||
/// SelectVLDSTLane - Select NEON load/store lane intrinsics. NumVecs should
|
||||
/// be 2, 3 or 4. The opcode arrays specify the instructions used for
|
||||
/// load/store of D registers and even subregs and odd subregs of Q registers.
|
||||
@ -1063,13 +1070,13 @@ SDNode *ARMDAGToDAGISel::SelectVLD(SDValue Op, unsigned NumVecs,
|
||||
ResTys.push_back(MemAddr.getValueType());
|
||||
ResTys.push_back(MVT::Other);
|
||||
|
||||
// Load the even subreg.
|
||||
// Load the even subregs.
|
||||
unsigned Opc = QOpcodes0[OpcodeIndex];
|
||||
const SDValue OpsA[] = { MemAddr, MemUpdate, MemOpc, Chain };
|
||||
SDNode *VLdA = CurDAG->getMachineNode(Opc, dl, ResTys, OpsA, 4);
|
||||
Chain = SDValue(VLdA, NumVecs+1);
|
||||
|
||||
// Load the odd subreg.
|
||||
// Load the odd subregs.
|
||||
Opc = QOpcodes1[OpcodeIndex];
|
||||
const SDValue OpsB[] = { SDValue(VLdA, NumVecs), MemUpdate, MemOpc, Chain };
|
||||
SDNode *VLdB = CurDAG->getMachineNode(Opc, dl, ResTys, OpsB, 4);
|
||||
@ -1085,6 +1092,95 @@ SDNode *ARMDAGToDAGISel::SelectVLD(SDValue Op, unsigned NumVecs,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDNode *ARMDAGToDAGISel::SelectVST(SDValue Op, unsigned NumVecs,
|
||||
unsigned *DOpcodes, unsigned *QOpcodes0,
|
||||
unsigned *QOpcodes1) {
|
||||
assert(NumVecs >=2 && NumVecs <= 4 && "VST NumVecs out-of-range");
|
||||
SDNode *N = Op.getNode();
|
||||
DebugLoc dl = N->getDebugLoc();
|
||||
|
||||
SDValue MemAddr, MemUpdate, MemOpc;
|
||||
if (!SelectAddrMode6(Op, N->getOperand(2), MemAddr, MemUpdate, MemOpc))
|
||||
return NULL;
|
||||
|
||||
SDValue Chain = N->getOperand(0);
|
||||
EVT VT = N->getOperand(3).getValueType();
|
||||
bool is64BitVector = VT.is64BitVector();
|
||||
|
||||
unsigned OpcodeIndex;
|
||||
switch (VT.getSimpleVT().SimpleTy) {
|
||||
default: llvm_unreachable("unhandled vst type");
|
||||
// Double-register operations:
|
||||
case MVT::v8i8: OpcodeIndex = 0; break;
|
||||
case MVT::v4i16: OpcodeIndex = 1; break;
|
||||
case MVT::v2f32:
|
||||
case MVT::v2i32: OpcodeIndex = 2; break;
|
||||
case MVT::v1i64: OpcodeIndex = 3; break;
|
||||
// Quad-register operations:
|
||||
case MVT::v16i8: OpcodeIndex = 0; break;
|
||||
case MVT::v8i16: OpcodeIndex = 1; break;
|
||||
case MVT::v4f32:
|
||||
case MVT::v4i32: OpcodeIndex = 2; break;
|
||||
}
|
||||
|
||||
SmallVector<SDValue, 8> Ops;
|
||||
Ops.push_back(MemAddr);
|
||||
Ops.push_back(MemUpdate);
|
||||
Ops.push_back(MemOpc);
|
||||
|
||||
if (is64BitVector) {
|
||||
unsigned Opc = DOpcodes[OpcodeIndex];
|
||||
for (unsigned Vec = 0; Vec < NumVecs; ++Vec)
|
||||
Ops.push_back(N->getOperand(Vec+3));
|
||||
Ops.push_back(Chain);
|
||||
return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops.data(), NumVecs+4);
|
||||
}
|
||||
|
||||
EVT RegVT = GetNEONSubregVT(VT);
|
||||
if (NumVecs == 2) {
|
||||
// Quad registers are directly supported for VST2,
|
||||
// storing 2 pairs of D regs.
|
||||
unsigned Opc = QOpcodes0[OpcodeIndex];
|
||||
for (unsigned Vec = 0; Vec < NumVecs; ++Vec) {
|
||||
Ops.push_back(CurDAG->getTargetExtractSubreg(ARM::DSUBREG_0, dl, RegVT,
|
||||
N->getOperand(Vec+3)));
|
||||
Ops.push_back(CurDAG->getTargetExtractSubreg(ARM::DSUBREG_1, dl, RegVT,
|
||||
N->getOperand(Vec+3)));
|
||||
}
|
||||
Ops.push_back(Chain);
|
||||
return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops.data(), 8);
|
||||
}
|
||||
|
||||
// Otherwise, quad registers are stored with two separate instructions,
|
||||
// where one stores the even registers and the other stores the odd registers.
|
||||
|
||||
// Enable writeback to the address register.
|
||||
MemOpc = CurDAG->getTargetConstant(ARM_AM::getAM6Opc(true), MVT::i32);
|
||||
|
||||
// Store the even subregs.
|
||||
for (unsigned Vec = 0; Vec < NumVecs; ++Vec)
|
||||
Ops.push_back(CurDAG->getTargetExtractSubreg(ARM::DSUBREG_0, dl, RegVT,
|
||||
N->getOperand(Vec+3)));
|
||||
Ops.push_back(Chain);
|
||||
unsigned Opc = QOpcodes0[OpcodeIndex];
|
||||
SDNode *VStA = CurDAG->getMachineNode(Opc, dl, MemAddr.getValueType(),
|
||||
MVT::Other, Ops.data(), NumVecs+4);
|
||||
Chain = SDValue(VStA, 1);
|
||||
|
||||
// Store the odd subregs.
|
||||
Ops[0] = SDValue(VStA, 0); // MemAddr
|
||||
for (unsigned Vec = 0; Vec < NumVecs; ++Vec)
|
||||
Ops[Vec+3] = CurDAG->getTargetExtractSubreg(ARM::DSUBREG_1, dl, RegVT,
|
||||
N->getOperand(Vec+3));
|
||||
Ops[NumVecs+3] = Chain;
|
||||
Opc = QOpcodes1[OpcodeIndex];
|
||||
SDNode *VStB = CurDAG->getMachineNode(Opc, dl, MemAddr.getValueType(),
|
||||
MVT::Other, Ops.data(), NumVecs+4);
|
||||
Chain = SDValue(VStB, 1);
|
||||
ReplaceUses(SDValue(N, 0), Chain);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDNode *ARMDAGToDAGISel::SelectVLDSTLane(SDValue Op, bool IsLoad,
|
||||
unsigned NumVecs, unsigned *DOpcodes,
|
||||
unsigned *QOpcodes0,
|
||||
@ -1612,9 +1708,6 @@ SDNode *ARMDAGToDAGISel::Select(SDValue Op) {
|
||||
case ISD::INTRINSIC_VOID:
|
||||
case ISD::INTRINSIC_W_CHAIN: {
|
||||
unsigned IntNo = cast<ConstantSDNode>(N->getOperand(1))->getZExtValue();
|
||||
EVT VT = N->getValueType(0);
|
||||
unsigned Opc = 0;
|
||||
|
||||
switch (IntNo) {
|
||||
default:
|
||||
break;
|
||||
@ -1664,178 +1757,26 @@ SDNode *ARMDAGToDAGISel::Select(SDValue Op) {
|
||||
}
|
||||
|
||||
case Intrinsic::arm_neon_vst2: {
|
||||
SDValue MemAddr, MemUpdate, MemOpc;
|
||||
if (!SelectAddrMode6(Op, N->getOperand(2), MemAddr, MemUpdate, MemOpc))
|
||||
return NULL;
|
||||
SDValue Chain = N->getOperand(0);
|
||||
VT = N->getOperand(3).getValueType();
|
||||
if (VT.is64BitVector()) {
|
||||
switch (VT.getSimpleVT().SimpleTy) {
|
||||
default: llvm_unreachable("unhandled vst2 type");
|
||||
case MVT::v8i8: Opc = ARM::VST2d8; break;
|
||||
case MVT::v4i16: Opc = ARM::VST2d16; break;
|
||||
case MVT::v2f32:
|
||||
case MVT::v2i32: Opc = ARM::VST2d32; break;
|
||||
case MVT::v1i64: Opc = ARM::VST2d64; break;
|
||||
}
|
||||
const SDValue Ops[] = { MemAddr, MemUpdate, MemOpc,
|
||||
N->getOperand(3), N->getOperand(4), Chain };
|
||||
return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops, 6);
|
||||
}
|
||||
// Quad registers are stored as pairs of double registers.
|
||||
EVT RegVT;
|
||||
switch (VT.getSimpleVT().SimpleTy) {
|
||||
default: llvm_unreachable("unhandled vst2 type");
|
||||
case MVT::v16i8: Opc = ARM::VST2q8; RegVT = MVT::v8i8; break;
|
||||
case MVT::v8i16: Opc = ARM::VST2q16; RegVT = MVT::v4i16; break;
|
||||
case MVT::v4f32: Opc = ARM::VST2q32; RegVT = MVT::v2f32; break;
|
||||
case MVT::v4i32: Opc = ARM::VST2q32; RegVT = MVT::v2i32; break;
|
||||
}
|
||||
SDValue D0 = CurDAG->getTargetExtractSubreg(ARM::DSUBREG_0, dl, RegVT,
|
||||
N->getOperand(3));
|
||||
SDValue D1 = CurDAG->getTargetExtractSubreg(ARM::DSUBREG_1, dl, RegVT,
|
||||
N->getOperand(3));
|
||||
SDValue D2 = CurDAG->getTargetExtractSubreg(ARM::DSUBREG_0, dl, RegVT,
|
||||
N->getOperand(4));
|
||||
SDValue D3 = CurDAG->getTargetExtractSubreg(ARM::DSUBREG_1, dl, RegVT,
|
||||
N->getOperand(4));
|
||||
const SDValue Ops[] = { MemAddr, MemUpdate, MemOpc,
|
||||
D0, D1, D2, D3, Chain };
|
||||
return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops, 8);
|
||||
unsigned DOpcodes[] = { ARM::VST2d8, ARM::VST2d16,
|
||||
ARM::VST2d32, ARM::VST2d64 };
|
||||
unsigned QOpcodes[] = { ARM::VST2q8, ARM::VST2q16, ARM::VST2q32 };
|
||||
return SelectVST(Op, 2, DOpcodes, QOpcodes, 0);
|
||||
}
|
||||
|
||||
case Intrinsic::arm_neon_vst3: {
|
||||
SDValue MemAddr, MemUpdate, MemOpc;
|
||||
if (!SelectAddrMode6(Op, N->getOperand(2), MemAddr, MemUpdate, MemOpc))
|
||||
return NULL;
|
||||
SDValue Chain = N->getOperand(0);
|
||||
VT = N->getOperand(3).getValueType();
|
||||
if (VT.is64BitVector()) {
|
||||
switch (VT.getSimpleVT().SimpleTy) {
|
||||
default: llvm_unreachable("unhandled vst3 type");
|
||||
case MVT::v8i8: Opc = ARM::VST3d8; break;
|
||||
case MVT::v4i16: Opc = ARM::VST3d16; break;
|
||||
case MVT::v2f32:
|
||||
case MVT::v2i32: Opc = ARM::VST3d32; break;
|
||||
case MVT::v1i64: Opc = ARM::VST3d64; break;
|
||||
}
|
||||
const SDValue Ops[] = { MemAddr, MemUpdate, MemOpc,
|
||||
N->getOperand(3), N->getOperand(4),
|
||||
N->getOperand(5), Chain };
|
||||
return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops, 7);
|
||||
}
|
||||
// Quad registers are stored with two separate instructions, where one
|
||||
// stores the even registers and the other stores the odd registers.
|
||||
EVT RegVT;
|
||||
unsigned Opc2 = 0;
|
||||
switch (VT.getSimpleVT().SimpleTy) {
|
||||
default: llvm_unreachable("unhandled vst3 type");
|
||||
case MVT::v16i8:
|
||||
Opc = ARM::VST3q8a; Opc2 = ARM::VST3q8b; RegVT = MVT::v8i8; break;
|
||||
case MVT::v8i16:
|
||||
Opc = ARM::VST3q16a; Opc2 = ARM::VST3q16b; RegVT = MVT::v4i16; break;
|
||||
case MVT::v4f32:
|
||||
Opc = ARM::VST3q32a; Opc2 = ARM::VST3q32b; RegVT = MVT::v2f32; break;
|
||||
case MVT::v4i32:
|
||||
Opc = ARM::VST3q32a; Opc2 = ARM::VST3q32b; RegVT = MVT::v2i32; break;
|
||||
}
|
||||
// Enable writeback to the address register.
|
||||
MemOpc = CurDAG->getTargetConstant(ARM_AM::getAM6Opc(true), MVT::i32);
|
||||
|
||||
SDValue D0 = CurDAG->getTargetExtractSubreg(ARM::DSUBREG_0, dl, RegVT,
|
||||
N->getOperand(3));
|
||||
SDValue D2 = CurDAG->getTargetExtractSubreg(ARM::DSUBREG_0, dl, RegVT,
|
||||
N->getOperand(4));
|
||||
SDValue D4 = CurDAG->getTargetExtractSubreg(ARM::DSUBREG_0, dl, RegVT,
|
||||
N->getOperand(5));
|
||||
const SDValue OpsA[] = { MemAddr, MemUpdate, MemOpc, D0, D2, D4, Chain };
|
||||
SDNode *VStA = CurDAG->getMachineNode(Opc, dl, MemAddr.getValueType(),
|
||||
MVT::Other, OpsA, 7);
|
||||
Chain = SDValue(VStA, 1);
|
||||
|
||||
SDValue D1 = CurDAG->getTargetExtractSubreg(ARM::DSUBREG_1, dl, RegVT,
|
||||
N->getOperand(3));
|
||||
SDValue D3 = CurDAG->getTargetExtractSubreg(ARM::DSUBREG_1, dl, RegVT,
|
||||
N->getOperand(4));
|
||||
SDValue D5 = CurDAG->getTargetExtractSubreg(ARM::DSUBREG_1, dl, RegVT,
|
||||
N->getOperand(5));
|
||||
MemAddr = SDValue(VStA, 0);
|
||||
const SDValue OpsB[] = { MemAddr, MemUpdate, MemOpc, D1, D3, D5, Chain };
|
||||
SDNode *VStB = CurDAG->getMachineNode(Opc2, dl, MemAddr.getValueType(),
|
||||
MVT::Other, OpsB, 7);
|
||||
Chain = SDValue(VStB, 1);
|
||||
ReplaceUses(SDValue(N, 0), Chain);
|
||||
return NULL;
|
||||
unsigned DOpcodes[] = { ARM::VST3d8, ARM::VST3d16,
|
||||
ARM::VST3d32, ARM::VST3d64 };
|
||||
unsigned QOpcodes0[] = { ARM::VST3q8a, ARM::VST3q16a, ARM::VST3q32a };
|
||||
unsigned QOpcodes1[] = { ARM::VST3q8b, ARM::VST3q16b, ARM::VST3q32b };
|
||||
return SelectVST(Op, 3, DOpcodes, QOpcodes0, QOpcodes1);
|
||||
}
|
||||
|
||||
case Intrinsic::arm_neon_vst4: {
|
||||
SDValue MemAddr, MemUpdate, MemOpc;
|
||||
if (!SelectAddrMode6(Op, N->getOperand(2), MemAddr, MemUpdate, MemOpc))
|
||||
return NULL;
|
||||
SDValue Chain = N->getOperand(0);
|
||||
VT = N->getOperand(3).getValueType();
|
||||
if (VT.is64BitVector()) {
|
||||
switch (VT.getSimpleVT().SimpleTy) {
|
||||
default: llvm_unreachable("unhandled vst4 type");
|
||||
case MVT::v8i8: Opc = ARM::VST4d8; break;
|
||||
case MVT::v4i16: Opc = ARM::VST4d16; break;
|
||||
case MVT::v2f32:
|
||||
case MVT::v2i32: Opc = ARM::VST4d32; break;
|
||||
case MVT::v1i64: Opc = ARM::VST4d64; break;
|
||||
}
|
||||
const SDValue Ops[] = { MemAddr, MemUpdate, MemOpc,
|
||||
N->getOperand(3), N->getOperand(4),
|
||||
N->getOperand(5), N->getOperand(6), Chain };
|
||||
return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops, 8);
|
||||
}
|
||||
// Quad registers are stored with two separate instructions, where one
|
||||
// stores the even registers and the other stores the odd registers.
|
||||
EVT RegVT;
|
||||
unsigned Opc2 = 0;
|
||||
switch (VT.getSimpleVT().SimpleTy) {
|
||||
default: llvm_unreachable("unhandled vst4 type");
|
||||
case MVT::v16i8:
|
||||
Opc = ARM::VST4q8a; Opc2 = ARM::VST4q8b; RegVT = MVT::v8i8; break;
|
||||
case MVT::v8i16:
|
||||
Opc = ARM::VST4q16a; Opc2 = ARM::VST4q16b; RegVT = MVT::v4i16; break;
|
||||
case MVT::v4f32:
|
||||
Opc = ARM::VST4q32a; Opc2 = ARM::VST4q32b; RegVT = MVT::v2f32; break;
|
||||
case MVT::v4i32:
|
||||
Opc = ARM::VST4q32a; Opc2 = ARM::VST4q32b; RegVT = MVT::v2i32; break;
|
||||
}
|
||||
// Enable writeback to the address register.
|
||||
MemOpc = CurDAG->getTargetConstant(ARM_AM::getAM6Opc(true), MVT::i32);
|
||||
|
||||
SDValue D0 = CurDAG->getTargetExtractSubreg(ARM::DSUBREG_0, dl, RegVT,
|
||||
N->getOperand(3));
|
||||
SDValue D2 = CurDAG->getTargetExtractSubreg(ARM::DSUBREG_0, dl, RegVT,
|
||||
N->getOperand(4));
|
||||
SDValue D4 = CurDAG->getTargetExtractSubreg(ARM::DSUBREG_0, dl, RegVT,
|
||||
N->getOperand(5));
|
||||
SDValue D6 = CurDAG->getTargetExtractSubreg(ARM::DSUBREG_0, dl, RegVT,
|
||||
N->getOperand(6));
|
||||
const SDValue OpsA[] = { MemAddr, MemUpdate, MemOpc,
|
||||
D0, D2, D4, D6, Chain };
|
||||
SDNode *VStA = CurDAG->getMachineNode(Opc, dl, MemAddr.getValueType(),
|
||||
MVT::Other, OpsA, 8);
|
||||
Chain = SDValue(VStA, 1);
|
||||
|
||||
SDValue D1 = CurDAG->getTargetExtractSubreg(ARM::DSUBREG_1, dl, RegVT,
|
||||
N->getOperand(3));
|
||||
SDValue D3 = CurDAG->getTargetExtractSubreg(ARM::DSUBREG_1, dl, RegVT,
|
||||
N->getOperand(4));
|
||||
SDValue D5 = CurDAG->getTargetExtractSubreg(ARM::DSUBREG_1, dl, RegVT,
|
||||
N->getOperand(5));
|
||||
SDValue D7 = CurDAG->getTargetExtractSubreg(ARM::DSUBREG_1, dl, RegVT,
|
||||
N->getOperand(6));
|
||||
MemAddr = SDValue(VStA, 0);
|
||||
const SDValue OpsB[] = { MemAddr, MemUpdate, MemOpc,
|
||||
D1, D3, D5, D7, Chain };
|
||||
SDNode *VStB = CurDAG->getMachineNode(Opc2, dl, MemAddr.getValueType(),
|
||||
MVT::Other, OpsB, 8);
|
||||
Chain = SDValue(VStB, 1);
|
||||
ReplaceUses(SDValue(N, 0), Chain);
|
||||
return NULL;
|
||||
unsigned DOpcodes[] = { ARM::VST4d8, ARM::VST4d16,
|
||||
ARM::VST4d32, ARM::VST4d64 };
|
||||
unsigned QOpcodes0[] = { ARM::VST4q8a, ARM::VST4q16a, ARM::VST4q32a };
|
||||
unsigned QOpcodes1[] = { ARM::VST4q8b, ARM::VST4q16b, ARM::VST4q32b };
|
||||
return SelectVST(Op, 4, DOpcodes, QOpcodes0, QOpcodes1);
|
||||
}
|
||||
|
||||
case Intrinsic::arm_neon_vst2lane: {
|
||||
|
@ -377,12 +377,15 @@ multiclass AsI1_bin_irs<bits<4> opcod, string opc, PatFrag opnode,
|
||||
def rr : AsI1<opcod, (outs GPR:$dst), (ins GPR:$a, GPR:$b), DPFrm,
|
||||
IIC_iALUr, opc, " $dst, $a, $b",
|
||||
[(set GPR:$dst, (opnode GPR:$a, GPR:$b))]> {
|
||||
let Inst{4} = 0;
|
||||
let Inst{25} = 0;
|
||||
let isCommutable = Commutable;
|
||||
}
|
||||
def rs : AsI1<opcod, (outs GPR:$dst), (ins GPR:$a, so_reg:$b), DPSoRegFrm,
|
||||
IIC_iALUsr, opc, " $dst, $a, $b",
|
||||
[(set GPR:$dst, (opnode GPR:$a, so_reg:$b))]> {
|
||||
let Inst{4} = 1;
|
||||
let Inst{7} = 0;
|
||||
let Inst{25} = 0;
|
||||
}
|
||||
}
|
||||
@ -401,11 +404,14 @@ multiclass AI1_bin_s_irs<bits<4> opcod, string opc, PatFrag opnode,
|
||||
IIC_iALUr, opc, "s $dst, $a, $b",
|
||||
[(set GPR:$dst, (opnode GPR:$a, GPR:$b))]> {
|
||||
let isCommutable = Commutable;
|
||||
let Inst{4} = 0;
|
||||
let Inst{25} = 0;
|
||||
}
|
||||
def rs : AI1<opcod, (outs GPR:$dst), (ins GPR:$a, so_reg:$b), DPSoRegFrm,
|
||||
IIC_iALUsr, opc, "s $dst, $a, $b",
|
||||
[(set GPR:$dst, (opnode GPR:$a, so_reg:$b))]> {
|
||||
let Inst{4} = 1;
|
||||
let Inst{7} = 0;
|
||||
let Inst{25} = 0;
|
||||
}
|
||||
}
|
||||
@ -426,6 +432,7 @@ multiclass AI1_cmp_irs<bits<4> opcod, string opc, PatFrag opnode,
|
||||
def rr : AI1<opcod, (outs), (ins GPR:$a, GPR:$b), DPFrm, IIC_iCMPr,
|
||||
opc, " $a, $b",
|
||||
[(opnode GPR:$a, GPR:$b)]> {
|
||||
let Inst{4} = 0;
|
||||
let Inst{20} = 1;
|
||||
let Inst{25} = 0;
|
||||
let isCommutable = Commutable;
|
||||
@ -433,6 +440,8 @@ multiclass AI1_cmp_irs<bits<4> opcod, string opc, PatFrag opnode,
|
||||
def rs : AI1<opcod, (outs), (ins GPR:$a, so_reg:$b), DPSoRegFrm, IIC_iCMPsr,
|
||||
opc, " $a, $b",
|
||||
[(opnode GPR:$a, so_reg:$b)]> {
|
||||
let Inst{4} = 1;
|
||||
let Inst{7} = 0;
|
||||
let Inst{20} = 1;
|
||||
let Inst{25} = 0;
|
||||
}
|
||||
@ -486,12 +495,15 @@ multiclass AI1_adde_sube_irs<bits<4> opcod, string opc, PatFrag opnode,
|
||||
[(set GPR:$dst, (opnode GPR:$a, GPR:$b))]>,
|
||||
Requires<[IsARM, CarryDefIsUnused]> {
|
||||
let isCommutable = Commutable;
|
||||
let Inst{4} = 0;
|
||||
let Inst{25} = 0;
|
||||
}
|
||||
def rs : AsI1<opcod, (outs GPR:$dst), (ins GPR:$a, so_reg:$b),
|
||||
DPSoRegFrm, IIC_iALUsr, opc, " $dst, $a, $b",
|
||||
[(set GPR:$dst, (opnode GPR:$a, so_reg:$b))]>,
|
||||
Requires<[IsARM, CarryDefIsUnused]> {
|
||||
let Inst{4} = 1;
|
||||
let Inst{7} = 0;
|
||||
let Inst{25} = 0;
|
||||
}
|
||||
// Carry setting variants
|
||||
@ -507,6 +519,7 @@ multiclass AI1_adde_sube_irs<bits<4> opcod, string opc, PatFrag opnode,
|
||||
[(set GPR:$dst, (opnode GPR:$a, GPR:$b))]>,
|
||||
Requires<[IsARM, CarryDefIsUsed]> {
|
||||
let Defs = [CPSR];
|
||||
let Inst{4} = 0;
|
||||
let Inst{25} = 0;
|
||||
}
|
||||
def Srs : AXI1<opcod, (outs GPR:$dst), (ins GPR:$a, so_reg:$b),
|
||||
@ -514,6 +527,8 @@ multiclass AI1_adde_sube_irs<bits<4> opcod, string opc, PatFrag opnode,
|
||||
[(set GPR:$dst, (opnode GPR:$a, so_reg:$b))]>,
|
||||
Requires<[IsARM, CarryDefIsUsed]> {
|
||||
let Defs = [CPSR];
|
||||
let Inst{4} = 1;
|
||||
let Inst{7} = 0;
|
||||
let Inst{25} = 0;
|
||||
}
|
||||
}
|
||||
@ -924,10 +939,18 @@ def STM : AXI4st<(outs),
|
||||
|
||||
let neverHasSideEffects = 1 in
|
||||
def MOVr : AsI1<0b1101, (outs GPR:$dst), (ins GPR:$src), DPFrm, IIC_iMOVr,
|
||||
"mov", " $dst, $src", []>, UnaryDP;
|
||||
"mov", " $dst, $src", []>, UnaryDP {
|
||||
let Inst{4} = 0;
|
||||
let Inst{25} = 0;
|
||||
}
|
||||
|
||||
def MOVs : AsI1<0b1101, (outs GPR:$dst), (ins so_reg:$src),
|
||||
DPSoRegFrm, IIC_iMOVsr,
|
||||
"mov", " $dst, $src", [(set GPR:$dst, so_reg:$src)]>, UnaryDP;
|
||||
"mov", " $dst, $src", [(set GPR:$dst, so_reg:$src)]>, UnaryDP {
|
||||
let Inst{4} = 1;
|
||||
let Inst{7} = 0;
|
||||
let Inst{25} = 0;
|
||||
}
|
||||
|
||||
let isReMaterializable = 1, isAsCheapAsAMove = 1 in
|
||||
def MOVi : AsI1<0b1101, (outs GPR:$dst), (ins so_imm:$src), DPFrm, IIC_iMOVi,
|
||||
@ -1146,10 +1169,15 @@ def BFC : I<(outs GPR:$dst), (ins GPR:$src, bf_inv_mask_imm:$imm),
|
||||
|
||||
def MVNr : AsI1<0b1111, (outs GPR:$dst), (ins GPR:$src), DPFrm, IIC_iMOVr,
|
||||
"mvn", " $dst, $src",
|
||||
[(set GPR:$dst, (not GPR:$src))]>, UnaryDP;
|
||||
[(set GPR:$dst, (not GPR:$src))]>, UnaryDP {
|
||||
let Inst{4} = 0;
|
||||
}
|
||||
def MVNs : AsI1<0b1111, (outs GPR:$dst), (ins so_reg:$src), DPSoRegFrm,
|
||||
IIC_iMOVsr, "mvn", " $dst, $src",
|
||||
[(set GPR:$dst, (not so_reg:$src))]>, UnaryDP;
|
||||
[(set GPR:$dst, (not so_reg:$src))]>, UnaryDP {
|
||||
let Inst{4} = 1;
|
||||
let Inst{7} = 0;
|
||||
}
|
||||
let isReMaterializable = 1, isAsCheapAsAMove = 1 in
|
||||
def MVNi : AsI1<0b1111, (outs GPR:$dst), (ins so_imm:$imm), DPFrm,
|
||||
IIC_iMOVi, "mvn", " $dst, $imm",
|
||||
@ -1461,20 +1489,27 @@ def : ARMPat<(ARMcmpZ GPR:$src, so_imm_neg:$imm),
|
||||
def MOVCCr : AI1<0b1101, (outs GPR:$dst), (ins GPR:$false, GPR:$true), DPFrm,
|
||||
IIC_iCMOVr, "mov", " $dst, $true",
|
||||
[/*(set GPR:$dst, (ARMcmov GPR:$false, GPR:$true, imm:$cc, CCR:$ccr))*/]>,
|
||||
RegConstraint<"$false = $dst">, UnaryDP;
|
||||
RegConstraint<"$false = $dst">, UnaryDP {
|
||||
let Inst{4} = 0;
|
||||
let Inst{25} = 0;
|
||||
}
|
||||
|
||||
def MOVCCs : AI1<0b1101, (outs GPR:$dst),
|
||||
(ins GPR:$false, so_reg:$true), DPSoRegFrm, IIC_iCMOVsr,
|
||||
"mov", " $dst, $true",
|
||||
[/*(set GPR:$dst, (ARMcmov GPR:$false, so_reg:$true, imm:$cc, CCR:$ccr))*/]>,
|
||||
RegConstraint<"$false = $dst">, UnaryDP;
|
||||
RegConstraint<"$false = $dst">, UnaryDP {
|
||||
let Inst{4} = 1;
|
||||
let Inst{7} = 0;
|
||||
let Inst{25} = 0;
|
||||
}
|
||||
|
||||
def MOVCCi : AI1<0b1101, (outs GPR:$dst),
|
||||
(ins GPR:$false, so_imm:$true), DPFrm, IIC_iCMOVi,
|
||||
"mov", " $dst, $true",
|
||||
[/*(set GPR:$dst, (ARMcmov GPR:$false, so_imm:$true, imm:$cc, CCR:$ccr))*/]>,
|
||||
RegConstraint<"$false = $dst">, UnaryDP {
|
||||
let Inst{25} = 1;
|
||||
let Inst{25} = 1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1951,9 +1951,9 @@ defm VPADDLu : N2VPLInt_QHS<0b11, 0b11, 0b00, 0b00101, 0, "vpaddl.u",
|
||||
int_arm_neon_vpaddlu>;
|
||||
|
||||
// VPADAL : Vector Pairwise Add and Accumulate Long
|
||||
defm VPADALs : N2VPLInt2_QHS<0b11, 0b11, 0b00, 0b00100, 0, "vpadal.s",
|
||||
defm VPADALs : N2VPLInt2_QHS<0b11, 0b11, 0b00, 0b01100, 0, "vpadal.s",
|
||||
int_arm_neon_vpadals>;
|
||||
defm VPADALu : N2VPLInt2_QHS<0b11, 0b11, 0b00, 0b00101, 0, "vpadal.u",
|
||||
defm VPADALu : N2VPLInt2_QHS<0b11, 0b11, 0b00, 0b01101, 0, "vpadal.u",
|
||||
int_arm_neon_vpadalu>;
|
||||
|
||||
// VPMAX : Vector Pairwise Maximum
|
||||
@ -2038,7 +2038,7 @@ defm VSHLs : N3VInt_QHSD<0, 0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ,
|
||||
defm VSHLu : N3VInt_QHSD<1, 0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ,
|
||||
IIC_VSHLiQ, "vshl.u", int_arm_neon_vshiftu, 0>;
|
||||
// VSHL : Vector Shift Left (Immediate)
|
||||
defm VSHLi : N2VSh_QHSD<0, 1, 0b0111, 1, IIC_VSHLiD, "vshl.i", NEONvshl>;
|
||||
defm VSHLi : N2VSh_QHSD<0, 1, 0b0101, 1, IIC_VSHLiD, "vshl.i", NEONvshl>;
|
||||
// VSHR : Vector Shift Right (Immediate)
|
||||
defm VSHRs : N2VSh_QHSD<0, 1, 0b0000, 1, IIC_VSHLiD, "vshr.s", NEONvshrs>;
|
||||
defm VSHRu : N2VSh_QHSD<1, 1, 0b0000, 1, IIC_VSHLiD, "vshr.u", NEONvshru>;
|
||||
|
@ -56,6 +56,7 @@
|
||||
#include "llvm/Support/IRBuilder.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Support/PatternMatch.h"
|
||||
#include "llvm/Support/TargetFolder.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
@ -186,7 +187,7 @@ namespace {
|
||||
|
||||
/// Builder - This is an IRBuilder that automatically inserts new
|
||||
/// instructions into the worklist when they are created.
|
||||
typedef IRBuilder<true, ConstantFolder, InstCombineIRInserter> BuilderTy;
|
||||
typedef IRBuilder<true, TargetFolder, InstCombineIRInserter> BuilderTy;
|
||||
BuilderTy *Builder;
|
||||
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
@ -12675,16 +12676,19 @@ static bool TryToSinkInstruction(Instruction *I, BasicBlock *DestBlock) {
|
||||
/// many instructions are dead or constant). Additionally, if we find a branch
|
||||
/// whose condition is a known constant, we only visit the reachable successors.
|
||||
///
|
||||
static void AddReachableCodeToWorklist(BasicBlock *BB,
|
||||
static bool AddReachableCodeToWorklist(BasicBlock *BB,
|
||||
SmallPtrSet<BasicBlock*, 64> &Visited,
|
||||
InstCombiner &IC,
|
||||
const TargetData *TD) {
|
||||
bool MadeIRChange = false;
|
||||
SmallVector<BasicBlock*, 256> Worklist;
|
||||
Worklist.push_back(BB);
|
||||
|
||||
std::vector<Instruction*> InstrsForInstCombineWorklist;
|
||||
InstrsForInstCombineWorklist.reserve(128);
|
||||
|
||||
SmallPtrSet<ConstantExpr*, 64> FoldedConstants;
|
||||
|
||||
while (!Worklist.empty()) {
|
||||
BB = Worklist.back();
|
||||
Worklist.pop_back();
|
||||
@ -12704,14 +12708,38 @@ static void AddReachableCodeToWorklist(BasicBlock *BB,
|
||||
}
|
||||
|
||||
// ConstantProp instruction if trivially constant.
|
||||
if (Constant *C = ConstantFoldInstruction(Inst, BB->getContext(), TD)) {
|
||||
DEBUG(errs() << "IC: ConstFold to: " << *C << " from: "
|
||||
<< *Inst << '\n');
|
||||
Inst->replaceAllUsesWith(C);
|
||||
++NumConstProp;
|
||||
Inst->eraseFromParent();
|
||||
continue;
|
||||
if (!Inst->use_empty() && isa<Constant>(Inst->getOperand(0)))
|
||||
if (Constant *C = ConstantFoldInstruction(Inst, BB->getContext(), TD)) {
|
||||
DEBUG(errs() << "IC: ConstFold to: " << *C << " from: "
|
||||
<< *Inst << '\n');
|
||||
Inst->replaceAllUsesWith(C);
|
||||
++NumConstProp;
|
||||
Inst->eraseFromParent();
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (TD) {
|
||||
// See if we can constant fold its operands.
|
||||
for (User::op_iterator i = Inst->op_begin(), e = Inst->op_end();
|
||||
i != e; ++i) {
|
||||
ConstantExpr *CE = dyn_cast<ConstantExpr>(i);
|
||||
if (CE == 0) continue;
|
||||
|
||||
// If we already folded this constant, don't try again.
|
||||
if (!FoldedConstants.insert(CE))
|
||||
continue;
|
||||
|
||||
Constant *NewC =
|
||||
ConstantFoldConstantExpression(CE, BB->getContext(), TD);
|
||||
if (NewC && NewC != CE) {
|
||||
*i = NewC;
|
||||
MadeIRChange = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
InstrsForInstCombineWorklist.push_back(Inst);
|
||||
}
|
||||
@ -12753,11 +12781,12 @@ static void AddReachableCodeToWorklist(BasicBlock *BB,
|
||||
// some N^2 behavior in pathological cases.
|
||||
IC.Worklist.AddInitialGroup(&InstrsForInstCombineWorklist[0],
|
||||
InstrsForInstCombineWorklist.size());
|
||||
|
||||
return MadeIRChange;
|
||||
}
|
||||
|
||||
bool InstCombiner::DoOneIteration(Function &F, unsigned Iteration) {
|
||||
MadeIRChange = false;
|
||||
TD = getAnalysisIfAvailable<TargetData>();
|
||||
|
||||
DEBUG(errs() << "\n\nINSTCOMBINE ITERATION #" << Iteration << " on "
|
||||
<< F.getNameStr() << "\n");
|
||||
@ -12767,7 +12796,7 @@ bool InstCombiner::DoOneIteration(Function &F, unsigned Iteration) {
|
||||
// the reachable instructions. Ignore blocks that are not reachable. Keep
|
||||
// track of which blocks we visit.
|
||||
SmallPtrSet<BasicBlock*, 64> Visited;
|
||||
AddReachableCodeToWorklist(F.begin(), Visited, *this, TD);
|
||||
MadeIRChange |= AddReachableCodeToWorklist(F.begin(), Visited, *this, TD);
|
||||
|
||||
// Do a quick scan over the function. If we find any blocks that are
|
||||
// unreachable, remove any instructions inside of them. This prevents
|
||||
@ -12786,7 +12815,6 @@ bool InstCombiner::DoOneIteration(Function &F, unsigned Iteration) {
|
||||
MadeIRChange = true;
|
||||
}
|
||||
|
||||
|
||||
// If I is not void type then replaceAllUsesWith undef.
|
||||
// This allows ValueHandlers and custom metadata to adjust itself.
|
||||
if (!I->getType()->isVoidTy())
|
||||
@ -12810,28 +12838,17 @@ bool InstCombiner::DoOneIteration(Function &F, unsigned Iteration) {
|
||||
}
|
||||
|
||||
// Instruction isn't dead, see if we can constant propagate it.
|
||||
if (Constant *C = ConstantFoldInstruction(I, F.getContext(), TD)) {
|
||||
DEBUG(errs() << "IC: ConstFold to: " << *C << " from: " << *I << '\n');
|
||||
if (!I->use_empty() && isa<Constant>(I->getOperand(0)))
|
||||
if (Constant *C = ConstantFoldInstruction(I, F.getContext(), TD)) {
|
||||
DEBUG(errs() << "IC: ConstFold to: " << *C << " from: " << *I << '\n');
|
||||
|
||||
// Add operands to the worklist.
|
||||
ReplaceInstUsesWith(*I, C);
|
||||
++NumConstProp;
|
||||
EraseInstFromFunction(*I);
|
||||
MadeIRChange = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (TD) {
|
||||
// See if we can constant fold its operands.
|
||||
for (User::op_iterator i = I->op_begin(), e = I->op_end(); i != e; ++i)
|
||||
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(i))
|
||||
if (Constant *NewC = ConstantFoldConstantExpression(CE,
|
||||
F.getContext(), TD))
|
||||
if (NewC != CE) {
|
||||
*i = NewC;
|
||||
MadeIRChange = true;
|
||||
}
|
||||
}
|
||||
// Add operands to the worklist.
|
||||
ReplaceInstUsesWith(*I, C);
|
||||
++NumConstProp;
|
||||
EraseInstFromFunction(*I);
|
||||
MadeIRChange = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// See if we can trivially sink this instruction to a successor basic block.
|
||||
if (I->hasOneUse()) {
|
||||
@ -12927,12 +12944,13 @@ bool InstCombiner::DoOneIteration(Function &F, unsigned Iteration) {
|
||||
bool InstCombiner::runOnFunction(Function &F) {
|
||||
MustPreserveLCSSA = mustPreserveAnalysisID(LCSSAID);
|
||||
Context = &F.getContext();
|
||||
|
||||
TD = getAnalysisIfAvailable<TargetData>();
|
||||
|
||||
|
||||
/// Builder - This is an IRBuilder that automatically inserts new
|
||||
/// instructions into the worklist when they are created.
|
||||
IRBuilder<true, ConstantFolder, InstCombineIRInserter>
|
||||
TheBuilder(F.getContext(), ConstantFolder(F.getContext()),
|
||||
IRBuilder<true, TargetFolder, InstCombineIRInserter>
|
||||
TheBuilder(F.getContext(), TargetFolder(TD, F.getContext()),
|
||||
InstCombineIRInserter(Worklist));
|
||||
Builder = &TheBuilder;
|
||||
|
||||
|
@ -1,16 +1,16 @@
|
||||
; RUN: opt -gvn -S < %s | FileCheck %s
|
||||
; RUN: opt -gvn -instcombine -S < %s | FileCheck %s
|
||||
|
||||
declare i8 @llvm.atomic.load.add.i8.p0i8(i8*, i8)
|
||||
|
||||
define void @foo(i8* %ptr) {
|
||||
define i8 @foo(i8* %ptr) {
|
||||
%P = getelementptr i8* %ptr, i32 0
|
||||
%Q = getelementptr i8* %ptr, i32 1
|
||||
; CHECK: getelementptr
|
||||
%X = load i8* %P
|
||||
; CHECK: = load
|
||||
%Y = call i8 @llvm.atomic.load.add.i8.p0i8(i8* %Q, i8 1)
|
||||
%Z = load i8* %P
|
||||
; CHECK-NOT: = load
|
||||
ret void
|
||||
; CHECK: ret void
|
||||
%A = sub i8 %X, %Z
|
||||
ret i8 %A
|
||||
; CHECK: ret i8 0
|
||||
}
|
||||
|
@ -1,4 +1,8 @@
|
||||
; RUN: llc < %s -march=x86 | grep align | count 3
|
||||
; RUN: llc < %s -march=x86 | grep align | count 4
|
||||
|
||||
; TODO: Is it a good idea to align inner loops? It's hard to know without
|
||||
; knowing what their trip counts are, or other dynamic information. For
|
||||
; now, CodeGen aligns all loops.
|
||||
|
||||
@x = external global i32* ; <i32**> [#uses=1]
|
||||
|
||||
|
@ -1,4 +1,11 @@
|
||||
; RUN: llc < %s -mtriple=i386-apple-darwin | grep align | count 1
|
||||
; RUN: llc < %s -mtriple=i386-apple-darwin | FileCheck %s
|
||||
|
||||
; CodeGen should align the top of the loop, which differs from the loop
|
||||
; header in this case.
|
||||
|
||||
; CHECK: jmp LBB1_2
|
||||
; CHECK: .align
|
||||
; CHECK: LBB1_1:
|
||||
|
||||
@A = common global [100 x i32] zeroinitializer, align 32 ; <[100 x i32]*> [#uses=1]
|
||||
|
||||
|
@ -66,8 +66,7 @@ NoOutput("disable-output",
|
||||
cl::desc("Do not write result bitcode file"), cl::Hidden);
|
||||
|
||||
static cl::opt<bool>
|
||||
OutputAssembly("S",
|
||||
cl::desc("Write output as LLVM assembly"), cl::Hidden);
|
||||
OutputAssembly("S", cl::desc("Write output as LLVM assembly"));
|
||||
|
||||
static cl::opt<bool>
|
||||
NoVerify("disable-verify", cl::desc("Do not verify result module"), cl::Hidden);
|
||||
|
@ -166,6 +166,7 @@ TEST_F(JITTest, FarCallToKnownFunction) {
|
||||
EXPECT_EQ(8, TestFunctionPtr());
|
||||
}
|
||||
|
||||
#if !defined(__arm__) && !defined(__ppc__)
|
||||
// Test a function C which calls A and B which call each other.
|
||||
TEST_F(JITTest, NonLazyCompilationStillNeedsStubs) {
|
||||
TheJIT->DisableLazyCompilation();
|
||||
@ -220,6 +221,7 @@ TEST_F(JITTest, NonLazyCompilationStillNeedsStubs) {
|
||||
|
||||
F1Ptr();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Regression test for PR5162. This used to trigger an AssertingVH inside the
|
||||
// JIT's Function to stub mapping.
|
||||
|
Loading…
x
Reference in New Issue
Block a user