Delete all stale files.
This commit is contained in:
parent
5effb5c6a1
commit
1adacceba9
@ -1,51 +0,0 @@
|
||||
Date: Sun, 8 Jul 2001 09:37:22 -0500
|
||||
From: Vikram S. Adve <vadve@cs.uiuc.edu>
|
||||
To: Ruchira Sasanka <sasanka@students.uiuc.edu>
|
||||
Cc: Chris Lattner <lattner@cs.uiuc.edu>
|
||||
Subject: machine instruction operands
|
||||
|
||||
Ruchira,
|
||||
|
||||
When generating machine instructions, I have to make several choices about
|
||||
operands. For cases were a register is required, there are 3 cases:
|
||||
|
||||
1. The register is for a Value* that is already in the VM code.
|
||||
|
||||
2. The register is for a value that is not in the VM code, usually because 2
|
||||
machine instructions get generated for a single VM instruction (and the
|
||||
register holds the result of the first m/c instruction and is used by the
|
||||
second m/c instruction).
|
||||
|
||||
3. The register is a pre-determined machine register.
|
||||
|
||||
E.g, for this VM instruction:
|
||||
ptr = alloca type, numElements
|
||||
I have to generate 2 machine instructions:
|
||||
reg = mul constant, numElements
|
||||
ptr = add %sp, reg
|
||||
|
||||
Each machine instruction is of class MachineInstr.
|
||||
It has a vector of operands. All register operands have type MO_REGISTER.
|
||||
The 3 types of register operands are marked using this enum:
|
||||
|
||||
enum VirtualRegisterType {
|
||||
MO_VMVirtualReg, // virtual register for *value
|
||||
MO_MInstrVirtualReg, // virtual register for result of *minstr
|
||||
MO_MachineReg // pre-assigned machine register `regNum'
|
||||
} vregType;
|
||||
|
||||
Here's how this affects register allocation:
|
||||
|
||||
1. MO_VMVirtualReg is the standard case: you just do the register
|
||||
allocation.
|
||||
|
||||
2. MO_MInstrVirtualReg is the case where there is a hidden register being
|
||||
used. You should decide how you want to handle it, e.g., do you want do
|
||||
create a Value object during the preprocessing phase to make the value
|
||||
explicit (like for address register for the RETURN instruction).
|
||||
|
||||
3. For case MO_MachineReg, you don't need to do anything, at least for
|
||||
SPARC. The only machine regs I am using so far are %g0 and %sp.
|
||||
|
||||
--Vikram
|
||||
|
@ -1,25 +0,0 @@
|
||||
Date: Sun, 8 Jul 2001 10:02:20 -0500
|
||||
From: Vikram S. Adve <vadve@cs.uiuc.edu>
|
||||
To: vadve@cs.uiuc.edu, Ruchira Sasanka <sasanka@students.uiuc.edu>
|
||||
Cc: Chris Lattner <lattner@cs.uiuc.edu>
|
||||
Subject: RE: machine instruction operands
|
||||
|
||||
I got interrupted and forgot to explain the example. In that case:
|
||||
|
||||
reg will be the 3rd operand of MUL and it will be of type
|
||||
MO_MInstrVirtualReg. The field MachineInstr* minstr will point to the
|
||||
instruction that computes reg.
|
||||
|
||||
numElements will be an immediate constant, not a register.
|
||||
|
||||
%sp will be operand 1 of ADD and it will be of type MO_MachineReg. The
|
||||
field regNum identifies the register.
|
||||
|
||||
numElements will be operand 2 of ADD and it will be of type
|
||||
MO_VMVirtualReg. The field Value* value identifies the value.
|
||||
|
||||
ptr will be operand 3 of ADD will also be %sp, i.e., of
|
||||
type MO_MachineReg. regNum identifies the register.
|
||||
|
||||
--Vikram
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,40 +0,0 @@
|
||||
//===-- llvm/ADT/HashExtras.h - Useful functions for STL hash ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains some templates that are useful if you are working with the
|
||||
// STL Hashed containers.
|
||||
//
|
||||
// No library is required when using these functions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_HASHEXTRAS_H
|
||||
#define LLVM_ADT_HASHEXTRAS_H
|
||||
|
||||
#include <string>
|
||||
|
||||
// Cannot specialize hash template from outside of the std namespace.
|
||||
namespace HASH_NAMESPACE {
|
||||
|
||||
// Provide a hash function for arbitrary pointers...
|
||||
template <class T> struct hash<T *> {
|
||||
inline size_t operator()(const T *Val) const {
|
||||
return reinterpret_cast<size_t>(Val);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct hash<std::string> {
|
||||
size_t operator()(std::string const &str) const {
|
||||
return hash<char const *>()(str.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
} // End namespace std
|
||||
|
||||
#endif
|
@ -1,62 +0,0 @@
|
||||
//===- llvm/ADT/Tree.h - Generic n-way tree structure -----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This class defines a generic N-way tree node structure. The tree structure
|
||||
// is immutable after creation, but the payload contained within it is not.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_TREE_H
|
||||
#define LLVM_ADT_TREE_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
template<class ConcreteTreeNode, class Payload>
|
||||
class Tree {
|
||||
std::vector<ConcreteTreeNode*> Children; // This node's children, if any.
|
||||
ConcreteTreeNode *Parent; // Parent of this node.
|
||||
Payload Data; // Data held in this node.
|
||||
|
||||
protected:
|
||||
void setChildren(const std::vector<ConcreteTreeNode*> &children) {
|
||||
Children = children;
|
||||
}
|
||||
public:
|
||||
inline Tree(ConcreteTreeNode *parent) : Parent(parent) {}
|
||||
inline Tree(const std::vector<ConcreteTreeNode*> &children,
|
||||
ConcreteTreeNode *par) : Children(children), Parent(par) {}
|
||||
|
||||
inline Tree(const std::vector<ConcreteTreeNode*> &children,
|
||||
ConcreteTreeNode *par, const Payload &data)
|
||||
: Children(children), Parent(par), Data(data) {}
|
||||
|
||||
// Tree dtor - Free all children
|
||||
inline ~Tree() {
|
||||
for (unsigned i = Children.size(); i > 0; --i)
|
||||
delete Children[i-1];
|
||||
}
|
||||
|
||||
// Tree manipulation/walking routines...
|
||||
inline ConcreteTreeNode *getParent() const { return Parent; }
|
||||
inline unsigned getNumChildren() const { return Children.size(); }
|
||||
inline ConcreteTreeNode *getChild(unsigned i) const {
|
||||
assert(i < Children.size() && "Tree::getChild with index out of range!");
|
||||
return Children[i];
|
||||
}
|
||||
|
||||
// Payload access...
|
||||
inline Payload &getTreeData() { return Data; }
|
||||
inline const Payload &getTreeData() const { return Data; }
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
@ -1,90 +0,0 @@
|
||||
//===- LoopVR.cpp - Value Range analysis driven by loop information -------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the interface for the loop-driven value range pass.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_LOOPVR_H
|
||||
#define LLVM_ANALYSIS_LOOPVR_H
|
||||
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Analysis/ScalarEvolution.h"
|
||||
#include "llvm/Support/ConstantRange.h"
|
||||
#include <iosfwd>
|
||||
#include <map>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// LoopVR - This class maintains a mapping of Values to ConstantRanges.
|
||||
/// There are interfaces to look up and update ranges by value, and for
|
||||
/// accessing all values with range information.
|
||||
///
|
||||
class LoopVR : public FunctionPass {
|
||||
public:
|
||||
static char ID; // Class identification, replacement for typeinfo
|
||||
|
||||
LoopVR() : FunctionPass(&ID) {}
|
||||
|
||||
bool runOnFunction(Function &F);
|
||||
virtual void print(std::ostream &os, const Module *) const;
|
||||
void releaseMemory();
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.addRequiredTransitive<LoopInfo>();
|
||||
AU.addRequiredTransitive<ScalarEvolution>();
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
|
||||
//===---------------------------------------------------------------------
|
||||
// Methods that are used to look up and update particular values.
|
||||
|
||||
/// get - return the ConstantRange for a given Value of IntegerType.
|
||||
ConstantRange get(Value *V);
|
||||
|
||||
/// remove - remove a value from this analysis.
|
||||
void remove(Value *V);
|
||||
|
||||
/// narrow - improve our unterstanding of a Value by pointing out that it
|
||||
/// must fall within ConstantRange. To replace a range, remove it first.
|
||||
void narrow(Value *V, const ConstantRange &CR);
|
||||
|
||||
//===---------------------------------------------------------------------
|
||||
// Methods that are used to iterate across all values with information.
|
||||
|
||||
/// size - returns the number of Values with information
|
||||
unsigned size() const { return Map.size(); }
|
||||
|
||||
typedef std::map<Value *, ConstantRange *>::iterator iterator;
|
||||
|
||||
/// begin - return an iterator to the first Value, ConstantRange pair
|
||||
iterator begin() { return Map.begin(); }
|
||||
|
||||
/// end - return an iterator one past the last Value, ConstantRange pair
|
||||
iterator end() { return Map.end(); }
|
||||
|
||||
/// getValue - return the Value referenced by an iterator
|
||||
Value *getValue(iterator I) { return I->first; }
|
||||
|
||||
/// getConstantRange - return the ConstantRange referenced by an iterator
|
||||
ConstantRange getConstantRange(iterator I) { return *I->second; }
|
||||
|
||||
private:
|
||||
ConstantRange compute(Value *V);
|
||||
|
||||
ConstantRange getRange(const SCEV* S, Loop *L, ScalarEvolution &SE);
|
||||
|
||||
ConstantRange getRange(const SCEV* S, const SCEV* T, ScalarEvolution &SE);
|
||||
|
||||
std::map<Value *, ConstantRange *> Map;
|
||||
};
|
||||
|
||||
} // end llvm namespace
|
||||
|
||||
#endif
|
@ -1,63 +0,0 @@
|
||||
//===- LazyLiveness.h - Lazy, CFG-invariant liveness information ----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This pass implements a lazy liveness analysis as per "Fast Liveness Checking
|
||||
// for SSA-form Programs," by Boissinot, et al.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_LAZYLIVENESS_H
|
||||
#define LLVM_CODEGEN_LAZYLIVENESS_H
|
||||
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineDominators.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/SparseBitVector.h"
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MachineRegisterInfo;
|
||||
|
||||
class LazyLiveness : public MachineFunctionPass {
|
||||
public:
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
LazyLiveness() : MachineFunctionPass(&ID) { }
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.setPreservesAll();
|
||||
AU.addRequired<MachineDominatorTree>();
|
||||
}
|
||||
|
||||
bool runOnMachineFunction(MachineFunction &mf);
|
||||
|
||||
bool vregLiveIntoMBB(unsigned vreg, MachineBasicBlock* MBB);
|
||||
|
||||
private:
|
||||
void computeBackedgeChain(MachineFunction& mf, MachineBasicBlock* MBB);
|
||||
|
||||
typedef std::pair<MachineBasicBlock*, MachineBasicBlock*> edge_t;
|
||||
|
||||
MachineRegisterInfo* MRI;
|
||||
|
||||
DenseMap<MachineBasicBlock*, unsigned> preorder;
|
||||
std::vector<MachineBasicBlock*> rev_preorder;
|
||||
DenseMap<MachineBasicBlock*, SparseBitVector<128> > rv;
|
||||
DenseMap<MachineBasicBlock*, SparseBitVector<128> > tv;
|
||||
DenseSet<edge_t> backedges;
|
||||
SparseBitVector<128> backedge_source;
|
||||
SparseBitVector<128> backedge_target;
|
||||
SparseBitVector<128> calculated;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,49 +0,0 @@
|
||||
/*
|
||||
* The LLVM Compiler Infrastructure
|
||||
*
|
||||
* This file is distributed under the University of Illinois Open Source
|
||||
* License. See LICENSE.TXT for details.
|
||||
*
|
||||
******************************************************************************
|
||||
*
|
||||
* Description:
|
||||
* This header file includes the infamous alloc.h header file if the
|
||||
* autoconf system has found it. It hides all of the autoconf details
|
||||
* from the rest of the application source code.
|
||||
*/
|
||||
|
||||
#ifndef _CONFIG_ALLOC_H
|
||||
#define _CONFIG_ALLOC_H
|
||||
|
||||
#include "llvm/Config/config.h"
|
||||
|
||||
/*
|
||||
* This is a modified version of that suggested by the Autoconf manual.
|
||||
* 1) The #pragma is indented so that pre-ANSI C compilers ignore it.
|
||||
* 2) If alloca.h cannot be found, then try stdlib.h. Some platforms
|
||||
* (notably FreeBSD) defined alloca() there.
|
||||
*/
|
||||
#ifdef _MSC_VER
|
||||
#include <malloc.h>
|
||||
#define alloca _alloca
|
||||
#elif defined(HAVE_ALLOCA_H)
|
||||
#include <alloca.h>
|
||||
#elif defined(__MINGW32__) && defined(HAVE_MALLOC_H)
|
||||
#include <malloc.h>
|
||||
#elif !defined(__GNUC__)
|
||||
# ifdef _AIX
|
||||
# pragma alloca
|
||||
# else
|
||||
# ifndef alloca
|
||||
char * alloca ();
|
||||
# endif
|
||||
# endif
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# else
|
||||
# error "The function alloca() is required but not found!"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,176 +0,0 @@
|
||||
//===- Debugger.h - LLVM debugger library interface -------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the LLVM source-level debugger library interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_DEBUGGER_DEBUGGER_H
|
||||
#define LLVM_DEBUGGER_DEBUGGER_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
class Module;
|
||||
class InferiorProcess;
|
||||
class LLVMContext;
|
||||
|
||||
/// Debugger class - This class implements the LLVM source-level debugger.
|
||||
/// This allows clients to handle the user IO processing without having to
|
||||
/// worry about how the debugger itself works.
|
||||
///
|
||||
class Debugger {
|
||||
// State the debugger needs when starting and stopping the program.
|
||||
std::vector<std::string> ProgramArguments;
|
||||
|
||||
// The environment to run the program with. This should eventually be
|
||||
// changed to vector of strings when we allow the user to edit the
|
||||
// environment.
|
||||
const char * const *Environment;
|
||||
|
||||
// Program - The currently loaded program, or null if none is loaded.
|
||||
Module *Program;
|
||||
|
||||
// Process - The currently executing inferior process.
|
||||
InferiorProcess *Process;
|
||||
|
||||
Debugger(const Debugger &); // DO NOT IMPLEMENT
|
||||
void operator=(const Debugger &); // DO NOT IMPLEMENT
|
||||
public:
|
||||
Debugger();
|
||||
~Debugger();
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Methods for manipulating and inspecting the execution environment.
|
||||
//
|
||||
|
||||
/// initializeEnvironment - Specify the environment the program should run
|
||||
/// with. This is used to initialize the environment of the program to the
|
||||
/// environment of the debugger.
|
||||
void initializeEnvironment(const char *const *envp) {
|
||||
Environment = envp;
|
||||
}
|
||||
|
||||
/// setWorkingDirectory - Specify the working directory for the program to
|
||||
/// be started from.
|
||||
void setWorkingDirectory(const std::string &Dir) {
|
||||
// FIXME: implement
|
||||
}
|
||||
|
||||
template<typename It>
|
||||
void setProgramArguments(It I, It E) {
|
||||
ProgramArguments.assign(I, E);
|
||||
}
|
||||
unsigned getNumProgramArguments() const {
|
||||
return static_cast<unsigned>(ProgramArguments.size());
|
||||
}
|
||||
const std::string &getProgramArgument(unsigned i) const {
|
||||
return ProgramArguments[i];
|
||||
}
|
||||
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Methods for manipulating and inspecting the program currently loaded.
|
||||
//
|
||||
|
||||
/// isProgramLoaded - Return true if there is a program currently loaded.
|
||||
///
|
||||
bool isProgramLoaded() const { return Program != 0; }
|
||||
|
||||
/// getProgram - Return the LLVM module corresponding to the program.
|
||||
///
|
||||
Module *getProgram() const { return Program; }
|
||||
|
||||
/// getProgramPath - Get the path of the currently loaded program, or an
|
||||
/// empty string if none is loaded.
|
||||
std::string getProgramPath() const;
|
||||
|
||||
/// loadProgram - If a program is currently loaded, unload it. Then search
|
||||
/// the PATH for the specified program, loading it when found. If the
|
||||
/// specified program cannot be found, an exception is thrown to indicate
|
||||
/// the error.
|
||||
void loadProgram(const std::string &Path, LLVMContext& Context);
|
||||
|
||||
/// unloadProgram - If a program is running, kill it, then unload all traces
|
||||
/// of the current program. If no program is loaded, this method silently
|
||||
/// succeeds.
|
||||
void unloadProgram();
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Methods for manipulating and inspecting the program currently running.
|
||||
//
|
||||
// If the program is running, and the debugger is active, then we know that
|
||||
// the program has stopped. This being the case, we can inspect the
|
||||
// program, ask it for its source location, set breakpoints, etc.
|
||||
//
|
||||
|
||||
/// isProgramRunning - Return true if a program is loaded and has a
|
||||
/// currently active instance.
|
||||
bool isProgramRunning() const { return Process != 0; }
|
||||
|
||||
/// getRunningProcess - If there is no program running, throw an exception.
|
||||
/// Otherwise return the running process so that it can be inspected by the
|
||||
/// debugger.
|
||||
const InferiorProcess &getRunningProcess() const {
|
||||
if (Process == 0) throw "No process running.";
|
||||
return *Process;
|
||||
}
|
||||
|
||||
/// createProgram - Create an instance of the currently loaded program,
|
||||
/// killing off any existing one. This creates the program and stops it at
|
||||
/// the first possible moment. If there is no program loaded or if there is
|
||||
/// a problem starting the program, this method throws an exception.
|
||||
void createProgram();
|
||||
|
||||
/// killProgram - If the program is currently executing, kill off the
|
||||
/// process and free up any state related to the currently running program.
|
||||
/// If there is no program currently running, this just silently succeeds.
|
||||
/// If something horrible happens when killing the program, an exception
|
||||
/// gets thrown.
|
||||
void killProgram();
|
||||
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Methods for continuing execution. These methods continue the execution
|
||||
// of the program by some amount. If the program is successfully stopped,
|
||||
// execution returns, otherwise an exception is thrown.
|
||||
//
|
||||
// NOTE: These methods should always be used in preference to directly
|
||||
// accessing the Dbg object, because these will delete the Process object if
|
||||
// the process unexpectedly dies.
|
||||
//
|
||||
|
||||
/// stepProgram - Implement the 'step' command, continuing execution until
|
||||
/// the next possible stop point.
|
||||
void stepProgram();
|
||||
|
||||
/// nextProgram - Implement the 'next' command, continuing execution until
|
||||
/// the next possible stop point that is in the current function.
|
||||
void nextProgram();
|
||||
|
||||
/// finishProgram - Implement the 'finish' command, continuing execution
|
||||
/// until the specified frame ID returns.
|
||||
void finishProgram(void *Frame);
|
||||
|
||||
/// contProgram - Implement the 'cont' command, continuing execution until
|
||||
/// the next breakpoint is encountered.
|
||||
void contProgram();
|
||||
};
|
||||
|
||||
class NonErrorException {
|
||||
std::string Message;
|
||||
public:
|
||||
NonErrorException(const std::string &M) : Message(M) {}
|
||||
const std::string &getMessage() const { return Message; }
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
@ -1,137 +0,0 @@
|
||||
//===- InferiorProcess.h - Represent the program being debugged -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the InferiorProcess class, which is used to represent,
|
||||
// inspect, and manipulate a process under the control of the LLVM debugger.
|
||||
//
|
||||
// This is an abstract class which should allow various different types of
|
||||
// implementations. Initially we implement a unix specific debugger backend
|
||||
// that does not require code generator support, but we could eventually use
|
||||
// code generator support with ptrace, support windows based targets, supported
|
||||
// remote targets, etc.
|
||||
//
|
||||
// If the inferior process unexpectedly dies, an attempt to communicate with it
|
||||
// will cause an InferiorProcessDead exception to be thrown, indicating the exit
|
||||
// code of the process. When this occurs, no methods on the InferiorProcess
|
||||
// class should be called except for the destructor.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_DEBUGGER_INFERIORPROCESS_H
|
||||
#define LLVM_DEBUGGER_INFERIORPROCESS_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
class Module;
|
||||
class GlobalVariable;
|
||||
|
||||
/// InferiorProcessDead exception - This class is thrown by methods that
|
||||
/// communicate with the interior process if the process unexpectedly exits or
|
||||
/// dies. The instance variable indicates what the exit code of the process
|
||||
/// was, or -1 if unknown.
|
||||
class InferiorProcessDead {
|
||||
int ExitCode;
|
||||
public:
|
||||
InferiorProcessDead(int EC) : ExitCode(EC) {}
|
||||
int getExitCode() const { return ExitCode; }
|
||||
};
|
||||
|
||||
/// InferiorProcess class - This class represents the process being debugged
|
||||
/// by the debugger. Objects of this class should not be stack allocated,
|
||||
/// because the destructor can throw exceptions.
|
||||
///
|
||||
class InferiorProcess {
|
||||
Module *M;
|
||||
protected:
|
||||
InferiorProcess(Module *m) : M(m) {}
|
||||
public:
|
||||
/// create - Create an inferior process of the specified module, and
|
||||
/// stop it at the first opportunity. If there is a problem starting the
|
||||
/// program (for example, it has no main), throw an exception.
|
||||
static InferiorProcess *create(Module *M,
|
||||
const std::vector<std::string> &Arguments,
|
||||
const char * const *envp);
|
||||
|
||||
// InferiorProcess destructor - Kill the current process. If something
|
||||
// terrible happens, we throw an exception from the destructor.
|
||||
virtual ~InferiorProcess() {}
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Status methods - These methods return information about the currently
|
||||
// stopped process.
|
||||
//
|
||||
|
||||
/// getStatus - Return a status message that is specific to the current type
|
||||
/// of inferior process that is created. This can return things like the
|
||||
/// PID of the inferior or other potentially interesting things.
|
||||
virtual std::string getStatus() const {
|
||||
return "";
|
||||
}
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Methods for inspecting the call stack.
|
||||
//
|
||||
|
||||
/// getPreviousFrame - Given the descriptor for the current stack frame,
|
||||
/// return the descriptor for the caller frame. This returns null when it
|
||||
/// runs out of frames. If Frame is null, the initial frame should be
|
||||
/// returned.
|
||||
virtual void *getPreviousFrame(void *Frame) const = 0;
|
||||
|
||||
/// getSubprogramDesc - Return the subprogram descriptor for the current
|
||||
/// stack frame.
|
||||
virtual const GlobalVariable *getSubprogramDesc(void *Frame) const = 0;
|
||||
|
||||
/// getFrameLocation - This method returns the source location where each
|
||||
/// stack frame is stopped.
|
||||
virtual void getFrameLocation(void *Frame, unsigned &LineNo,
|
||||
unsigned &ColNo,
|
||||
const GlobalVariable *&SourceDesc) const = 0;
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Methods for manipulating breakpoints.
|
||||
//
|
||||
|
||||
/// addBreakpoint - This method adds a breakpoint at the specified line,
|
||||
/// column, and source file, and returns a unique identifier for it.
|
||||
///
|
||||
/// It is up to the debugger to determine whether or not there is actually a
|
||||
/// stop-point that corresponds with the specified location.
|
||||
virtual unsigned addBreakpoint(unsigned LineNo, unsigned ColNo,
|
||||
const GlobalVariable *SourceDesc) = 0;
|
||||
|
||||
/// removeBreakpoint - This deletes the breakpoint with the specified ID
|
||||
/// number.
|
||||
virtual void removeBreakpoint(unsigned ID) = 0;
|
||||
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Execution methods - These methods cause the program to continue execution
|
||||
// by some amount. If the program successfully stops, this returns.
|
||||
// Otherwise, if the program unexpectedly terminates, an InferiorProcessDead
|
||||
// exception is thrown.
|
||||
//
|
||||
|
||||
/// stepProgram - Implement the 'step' command, continuing execution until
|
||||
/// the next possible stop point.
|
||||
virtual void stepProgram() = 0;
|
||||
|
||||
/// finishProgram - Implement the 'finish' command, continuing execution
|
||||
/// until the current function returns.
|
||||
virtual void finishProgram(void *Frame) = 0;
|
||||
|
||||
/// contProgram - Implement the 'cont' command, continuing execution until
|
||||
/// a breakpoint is encountered.
|
||||
virtual void contProgram() = 0;
|
||||
};
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
@ -1,246 +0,0 @@
|
||||
//===- ProgramInfo.h - Information about the loaded program -----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines various pieces of information about the currently loaded
|
||||
// program. One instance of this object is created every time a program is
|
||||
// loaded, and destroyed every time it is unloaded.
|
||||
//
|
||||
// The various pieces of information gathered about the source program are all
|
||||
// designed to be extended by various SourceLanguage implementations. This
|
||||
// allows source languages to keep any extended information that they support in
|
||||
// the derived class portions of the class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_DEBUGGER_PROGRAMINFO_H
|
||||
#define LLVM_DEBUGGER_PROGRAMINFO_H
|
||||
|
||||
#include "llvm/System/TimeValue.h"
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
class GlobalVariable;
|
||||
class Module;
|
||||
class SourceFile;
|
||||
class SourceLanguage;
|
||||
class ProgramInfo;
|
||||
|
||||
/// SourceLanguageCache - SourceLanguage implementations are allowed to cache
|
||||
/// stuff in the ProgramInfo object. The only requirement we have on these
|
||||
/// instances is that they are destroyable.
|
||||
struct SourceLanguageCache {
|
||||
virtual ~SourceLanguageCache() {}
|
||||
};
|
||||
|
||||
/// SourceFileInfo - One instance of this structure is created for each
|
||||
/// source file in the program.
|
||||
///
|
||||
class SourceFileInfo {
|
||||
/// BaseName - The filename of the source file.
|
||||
std::string BaseName;
|
||||
|
||||
/// Directory - The working directory of this source file when it was
|
||||
/// compiled.
|
||||
std::string Directory;
|
||||
|
||||
/// Version - The version of the LLVM debug information that this file was
|
||||
/// compiled with.
|
||||
unsigned Version;
|
||||
|
||||
/// Language - The source language that the file was compiled with. This
|
||||
/// pointer is never null.
|
||||
///
|
||||
const SourceLanguage *Language;
|
||||
|
||||
/// Descriptor - The LLVM Global Variable which describes the source file.
|
||||
///
|
||||
const GlobalVariable *Descriptor;
|
||||
|
||||
/// SourceText - The body of this source file, or null if it has not yet
|
||||
/// been loaded.
|
||||
mutable SourceFile *SourceText;
|
||||
public:
|
||||
SourceFileInfo(const GlobalVariable *Desc, const SourceLanguage &Lang);
|
||||
~SourceFileInfo();
|
||||
|
||||
const std::string &getBaseName() const { return BaseName; }
|
||||
const std::string &getDirectory() const { return Directory; }
|
||||
unsigned getDebugVersion() const { return Version; }
|
||||
const GlobalVariable *getDescriptor() const { return Descriptor; }
|
||||
SourceFile &getSourceText() const;
|
||||
|
||||
const SourceLanguage &getLanguage() const { return *Language; }
|
||||
};
|
||||
|
||||
|
||||
/// SourceFunctionInfo - An instance of this class is used to represent each
|
||||
/// source function in the program.
|
||||
///
|
||||
class SourceFunctionInfo {
|
||||
/// Name - This contains an abstract name that is potentially useful to the
|
||||
/// end-user. If there is no explicit support for the current language,
|
||||
/// then this string is used to identify the function.
|
||||
std::string Name;
|
||||
|
||||
/// Descriptor - The descriptor for this function.
|
||||
///
|
||||
const GlobalVariable *Descriptor;
|
||||
|
||||
/// SourceFile - The file that this function is defined in.
|
||||
///
|
||||
const SourceFileInfo *SourceFile;
|
||||
|
||||
/// LineNo, ColNo - The location of the first stop-point in the function.
|
||||
/// These are computed on demand.
|
||||
mutable unsigned LineNo, ColNo;
|
||||
|
||||
public:
|
||||
SourceFunctionInfo(ProgramInfo &PI, const GlobalVariable *Desc);
|
||||
virtual ~SourceFunctionInfo() {}
|
||||
|
||||
/// getSymbolicName - Return a human-readable symbolic name to identify the
|
||||
/// function (for example, in stack traces).
|
||||
virtual std::string getSymbolicName() const { return Name; }
|
||||
|
||||
/// getDescriptor - This returns the descriptor for the function.
|
||||
///
|
||||
const GlobalVariable *getDescriptor() const { return Descriptor; }
|
||||
|
||||
/// getSourceFile - This returns the source file that defines the function.
|
||||
///
|
||||
const SourceFileInfo &getSourceFile() const { return *SourceFile; }
|
||||
|
||||
/// getSourceLocation - This method returns the location of the first
|
||||
/// stopping point in the function. If the body of the function cannot be
|
||||
/// found, this returns zeros for both values.
|
||||
void getSourceLocation(unsigned &LineNo, unsigned &ColNo) const;
|
||||
};
|
||||
|
||||
|
||||
/// ProgramInfo - This object contains information about the loaded program.
|
||||
/// When a new program is loaded, an instance of this class is created. When
|
||||
/// the program is unloaded, the instance is destroyed. This object basically
|
||||
/// manages the lazy computation of information useful for the debugger.
|
||||
class ProgramInfo {
|
||||
Module *M;
|
||||
|
||||
/// ProgramTimeStamp - This is the timestamp of the executable file that we
|
||||
/// currently have loaded into the debugger.
|
||||
sys::TimeValue ProgramTimeStamp;
|
||||
|
||||
/// SourceFiles - This map is used to transform source file descriptors into
|
||||
/// their corresponding SourceFileInfo objects. This mapping owns the
|
||||
/// memory for the SourceFileInfo objects.
|
||||
///
|
||||
bool SourceFilesIsComplete;
|
||||
std::map<const GlobalVariable*, SourceFileInfo*> SourceFiles;
|
||||
|
||||
/// SourceFileIndex - Mapping from source file basenames to the information
|
||||
/// about the file. Note that there can be filename collisions, so this is
|
||||
/// a multimap. This map is populated incrementally as the user interacts
|
||||
/// with the program, through the getSourceFileFromDesc method. If ALL of
|
||||
/// the source files are needed, the getSourceFiles() method scans the
|
||||
/// entire program looking for them.
|
||||
///
|
||||
std::multimap<std::string, SourceFileInfo*> SourceFileIndex;
|
||||
|
||||
/// SourceFunctions - This map contains entries functions in the source
|
||||
/// program. If SourceFunctionsIsComplete is true, then this is ALL of the
|
||||
/// functions in the program are in this map.
|
||||
bool SourceFunctionsIsComplete;
|
||||
std::map<const GlobalVariable*, SourceFunctionInfo*> SourceFunctions;
|
||||
|
||||
/// LanguageCaches - Each source language is permitted to keep a per-program
|
||||
/// cache of information specific to whatever it needs. This vector is
|
||||
/// effectively a small map from the languages that are active in the
|
||||
/// program to their caches. This can be accessed by the language by the
|
||||
/// "getLanguageCache" method.
|
||||
std::vector<std::pair<const SourceLanguage*,
|
||||
SourceLanguageCache*> > LanguageCaches;
|
||||
public:
|
||||
ProgramInfo(Module *m);
|
||||
~ProgramInfo();
|
||||
|
||||
/// getProgramTimeStamp - Return the time-stamp of the program when it was
|
||||
/// loaded.
|
||||
sys::TimeValue getProgramTimeStamp() const { return ProgramTimeStamp; }
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Interfaces to the source code files that make up the program.
|
||||
//
|
||||
|
||||
/// getSourceFile - Return source file information for the specified source
|
||||
/// file descriptor object, adding it to the collection as needed. This
|
||||
/// method always succeeds (is unambiguous), and is always efficient.
|
||||
///
|
||||
const SourceFileInfo &getSourceFile(const GlobalVariable *Desc);
|
||||
|
||||
/// getSourceFile - Look up the file with the specified name. If there is
|
||||
/// more than one match for the specified filename, prompt the user to pick
|
||||
/// one. If there is no source file that matches the specified name, throw
|
||||
/// an exception indicating that we can't find the file. Otherwise, return
|
||||
/// the file information for that file.
|
||||
///
|
||||
/// If the source file hasn't been discovered yet in the program, this
|
||||
/// method might have to index the whole program by calling the
|
||||
/// getSourceFiles() method.
|
||||
///
|
||||
const SourceFileInfo &getSourceFile(const std::string &Filename);
|
||||
|
||||
/// getSourceFiles - Index all of the source files in the program and return
|
||||
/// them. This information is lazily computed the first time that it is
|
||||
/// requested. Since this information can take a long time to compute, the
|
||||
/// user is given a chance to cancel it. If this occurs, an exception is
|
||||
/// thrown.
|
||||
const std::map<const GlobalVariable*, SourceFileInfo*> &
|
||||
getSourceFiles(bool RequiresCompleteMap = true);
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Interfaces to the functions that make up the program.
|
||||
//
|
||||
|
||||
/// getFunction - Return source function information for the specified
|
||||
/// function descriptor object, adding it to the collection as needed. This
|
||||
/// method always succeeds (is unambiguous), and is always efficient.
|
||||
///
|
||||
const SourceFunctionInfo &getFunction(const GlobalVariable *Desc);
|
||||
|
||||
/// getSourceFunctions - Index all of the functions in the program and
|
||||
/// return them. This information is lazily computed the first time that it
|
||||
/// is requested. Since this information can take a long time to compute,
|
||||
/// the user is given a chance to cancel it. If this occurs, an exception
|
||||
/// is thrown.
|
||||
const std::map<const GlobalVariable*, SourceFunctionInfo*> &
|
||||
getSourceFunctions(bool RequiresCompleteMap = true);
|
||||
|
||||
/// addSourceFunctionsRead - Return true if the source functions map is
|
||||
/// complete: that is, all functions in the program have been read in.
|
||||
bool allSourceFunctionsRead() const { return SourceFunctionsIsComplete; }
|
||||
|
||||
/// getLanguageCache - This method is used to build per-program caches of
|
||||
/// information, such as the functions or types visible to the program.
|
||||
/// This can be used by SourceLanguage implementations because it requires
|
||||
/// an accessible [sl]::CacheType typedef, where [sl] is the C++ type of the
|
||||
/// source-language subclass.
|
||||
template<typename SL>
|
||||
typename SL::CacheType &getLanguageCache(const SL *L) {
|
||||
for (unsigned i = 0, e = LanguageCaches.size(); i != e; ++i)
|
||||
if (LanguageCaches[i].first == L)
|
||||
return *(typename SL::CacheType*)LanguageCaches[i].second;
|
||||
typename SL::CacheType *NewCache = L->createSourceLanguageCache(*this);
|
||||
LanguageCaches.push_back(std::make_pair(L, NewCache));
|
||||
return *NewCache;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
@ -1,142 +0,0 @@
|
||||
//===- RuntimeInfo.h - Information about running program --------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines classes that capture various pieces of information about
|
||||
// the currently executing, but stopped, program. One instance of this object
|
||||
// is created every time a program is stopped, and destroyed every time it
|
||||
// starts running again. This object's main goal is to make access to runtime
|
||||
// information easy and efficient, by caching information as requested.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_DEBUGGER_RUNTIMEINFO_H
|
||||
#define LLVM_DEBUGGER_RUNTIMEINFO_H
|
||||
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
|
||||
namespace llvm {
|
||||
class ProgramInfo;
|
||||
class RuntimeInfo;
|
||||
class InferiorProcess;
|
||||
class GlobalVariable;
|
||||
class SourceFileInfo;
|
||||
|
||||
/// StackFrame - One instance of this structure is created for each stack
|
||||
/// frame that is active in the program.
|
||||
///
|
||||
class StackFrame {
|
||||
RuntimeInfo &RI;
|
||||
void *FrameID;
|
||||
const GlobalVariable *FunctionDesc;
|
||||
|
||||
/// LineNo, ColNo, FileInfo - This information indicates WHERE in the source
|
||||
/// code for the program the stack frame is located.
|
||||
unsigned LineNo, ColNo;
|
||||
const SourceFileInfo *SourceInfo;
|
||||
public:
|
||||
StackFrame(RuntimeInfo &RI, void *ParentFrameID);
|
||||
|
||||
StackFrame &operator=(const StackFrame &RHS) {
|
||||
FrameID = RHS.FrameID;
|
||||
FunctionDesc = RHS.FunctionDesc;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// getFrameID - return the low-level opaque frame ID of this stack frame.
|
||||
///
|
||||
void *getFrameID() const { return FrameID; }
|
||||
|
||||
/// getFunctionDesc - Return the descriptor for the function that contains
|
||||
/// this stack frame, or null if it is unknown.
|
||||
///
|
||||
const GlobalVariable *getFunctionDesc();
|
||||
|
||||
/// getSourceLocation - Return the source location that this stack frame is
|
||||
/// sitting at.
|
||||
void getSourceLocation(unsigned &LineNo, unsigned &ColNo,
|
||||
const SourceFileInfo *&SourceInfo);
|
||||
};
|
||||
|
||||
|
||||
/// RuntimeInfo - This class collects information about the currently running
|
||||
/// process. It is created whenever the program stops execution for the
|
||||
/// debugger, and destroyed whenver execution continues.
|
||||
class RuntimeInfo {
|
||||
/// ProgInfo - This object contains static information about the program.
|
||||
///
|
||||
ProgramInfo *ProgInfo;
|
||||
|
||||
/// IP - This object contains information about the actual inferior process
|
||||
/// that we are communicating with and aggregating information from.
|
||||
const InferiorProcess &IP;
|
||||
|
||||
/// CallStack - This caches information about the current stack trace of the
|
||||
/// program. This is lazily computed as needed.
|
||||
std::vector<StackFrame> CallStack;
|
||||
|
||||
/// CurrentFrame - The user can traverse the stack frame with the
|
||||
/// up/down/frame family of commands. This index indicates the current
|
||||
/// stack frame.
|
||||
unsigned CurrentFrame;
|
||||
|
||||
public:
|
||||
RuntimeInfo(ProgramInfo *PI, const InferiorProcess &ip)
|
||||
: ProgInfo(PI), IP(ip), CurrentFrame(0) {
|
||||
// Make sure that the top of stack has been materialized. If this throws
|
||||
// an exception, something is seriously wrong and the RuntimeInfo object
|
||||
// would be unusable anyway.
|
||||
getStackFrame(0);
|
||||
}
|
||||
|
||||
ProgramInfo &getProgramInfo() { return *ProgInfo; }
|
||||
const InferiorProcess &getInferiorProcess() const { return IP; }
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Methods for inspecting the call stack of the program.
|
||||
//
|
||||
|
||||
/// getStackFrame - Materialize the specified stack frame and return it. If
|
||||
/// the specified ID is off of the bottom of the stack, throw an exception
|
||||
/// indicating the problem.
|
||||
StackFrame &getStackFrame(unsigned ID) {
|
||||
if (ID >= CallStack.size())
|
||||
materializeFrame(ID);
|
||||
return CallStack[ID];
|
||||
}
|
||||
|
||||
/// getCurrentFrame - Return the current stack frame object that the user is
|
||||
/// inspecting.
|
||||
StackFrame &getCurrentFrame() {
|
||||
assert(CallStack.size() > CurrentFrame &&
|
||||
"Must have materialized frame before making it current!");
|
||||
return CallStack[CurrentFrame];
|
||||
}
|
||||
|
||||
/// getCurrentFrameIdx - Return the current frame the user is inspecting.
|
||||
///
|
||||
unsigned getCurrentFrameIdx() const { return CurrentFrame; }
|
||||
|
||||
/// setCurrentFrameIdx - Set the current frame index to the specified value.
|
||||
/// Note that the specified frame must have been materialized with
|
||||
/// getStackFrame before it can be made current.
|
||||
void setCurrentFrameIdx(unsigned Idx) {
|
||||
assert(Idx < CallStack.size() &&
|
||||
"Must materialize frame before making it current!");
|
||||
CurrentFrame = Idx;
|
||||
}
|
||||
private:
|
||||
/// materializeFrame - Create and process all frames up to and including the
|
||||
/// specified frame number. This throws an exception if the specified frame
|
||||
/// ID is nonexistant.
|
||||
void materializeFrame(unsigned ID);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -1,87 +0,0 @@
|
||||
//===- SourceFile.h - Class to represent a source code file -----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the SourceFile class which is used to represent a single
|
||||
// file of source code in the program, caching data from the file to make access
|
||||
// efficient.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_DEBUGGER_SOURCEFILE_H
|
||||
#define LLVM_DEBUGGER_SOURCEFILE_H
|
||||
|
||||
#include "llvm/System/Path.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
class GlobalVariable;
|
||||
class MemoryBuffer;
|
||||
|
||||
class SourceFile {
|
||||
/// Filename - This is the full path of the file that is loaded.
|
||||
///
|
||||
sys::Path Filename;
|
||||
|
||||
/// Descriptor - The debugging descriptor for this source file. If there
|
||||
/// are multiple descriptors for the same file, this is just the first one
|
||||
/// encountered.
|
||||
///
|
||||
const GlobalVariable *Descriptor;
|
||||
|
||||
/// This is the memory mapping for the file so we can gain access to it.
|
||||
OwningPtr<MemoryBuffer> File;
|
||||
|
||||
/// LineOffset - This vector contains a mapping from source line numbers to
|
||||
/// their offsets in the file. This data is computed lazily, the first time
|
||||
/// it is asked for. If there are zero elements allocated in this vector,
|
||||
/// then it has not yet been computed.
|
||||
mutable std::vector<unsigned> LineOffset;
|
||||
|
||||
public:
|
||||
/// SourceFile constructor - Read in the specified source file if it exists,
|
||||
/// but do not build the LineOffsets table until it is requested. This will
|
||||
/// NOT throw an exception if the file is not found, if there is an error
|
||||
/// reading it, or if the user cancels the operation. Instead, it will just
|
||||
/// be an empty source file.
|
||||
SourceFile(const std::string &fn, const GlobalVariable *Desc);
|
||||
|
||||
~SourceFile();
|
||||
|
||||
/// getDescriptor - Return the debugging decriptor for this source file.
|
||||
///
|
||||
const GlobalVariable *getDescriptor() const { return Descriptor; }
|
||||
|
||||
/// getFilename - Return the fully resolved path that this file was loaded
|
||||
/// from.
|
||||
const std::string &getFilename() const { return Filename.toString(); }
|
||||
|
||||
/// getSourceLine - Given a line number, return the start and end of the
|
||||
/// line in the file. If the line number is invalid, or if the file could
|
||||
/// not be loaded, null pointers are returned for the start and end of the
|
||||
/// file. Note that line numbers start with 0, not 1. This also strips off
|
||||
/// any newlines from the end of the line, to ease formatting of the text.
|
||||
void getSourceLine(unsigned LineNo, const char *&LineStart,
|
||||
const char *&LineEnd) const;
|
||||
|
||||
/// getNumLines - Return the number of lines the source file contains.
|
||||
///
|
||||
unsigned getNumLines() const {
|
||||
if (LineOffset.empty()) calculateLineOffsets();
|
||||
return static_cast<unsigned>(LineOffset.size());
|
||||
}
|
||||
|
||||
private:
|
||||
/// calculateLineOffsets - Compute the LineOffset vector for the current
|
||||
/// file.
|
||||
void calculateLineOffsets() const;
|
||||
};
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
@ -1,99 +0,0 @@
|
||||
//===- SourceLanguage.h - Interact with source languages --------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the abstract SourceLanguage interface, which is used by the
|
||||
// LLVM debugger to parse source-language expressions and render program objects
|
||||
// into a human readable string. In general, these classes perform all of the
|
||||
// analysis and interpretation of the language-specific debugger information.
|
||||
//
|
||||
// This interface is designed to be completely stateless, so all methods are
|
||||
// const.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_DEBUGGER_SOURCELANGUAGE_H
|
||||
#define LLVM_DEBUGGER_SOURCELANGUAGE_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace llvm {
|
||||
class GlobalVariable;
|
||||
class SourceFileInfo;
|
||||
class SourceFunctionInfo;
|
||||
class ProgramInfo;
|
||||
class RuntimeInfo;
|
||||
|
||||
struct SourceLanguage {
|
||||
virtual ~SourceLanguage() {}
|
||||
|
||||
/// getSourceLanguageName - This method is used to implement the 'show
|
||||
/// language' command in the debugger.
|
||||
virtual const char *getSourceLanguageName() const = 0;
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Methods used to implement debugger hooks.
|
||||
//
|
||||
|
||||
/// printInfo - Implementing this method allows the debugger to use
|
||||
/// language-specific 'info' extensions, e.g., 'info selectors' for objc.
|
||||
/// This method should return true if the specified string is recognized.
|
||||
///
|
||||
virtual bool printInfo(const std::string &What) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// lookupFunction - Given a textual function name, return the
|
||||
/// SourceFunctionInfo descriptor for that function, or null if it cannot be
|
||||
/// found. If the program is currently running, the RuntimeInfo object
|
||||
/// provides information about the current evaluation context, otherwise it
|
||||
/// will be null.
|
||||
///
|
||||
virtual SourceFunctionInfo *lookupFunction(const std::string &FunctionName,
|
||||
ProgramInfo &PI,
|
||||
RuntimeInfo *RI = 0) const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Methods used to parse various pieces of program information.
|
||||
//
|
||||
|
||||
/// createSourceFileInfo - This method can be implemented by the front-end
|
||||
/// if it needs to keep track of information beyond what the debugger
|
||||
/// requires.
|
||||
virtual SourceFileInfo *
|
||||
createSourceFileInfo(const GlobalVariable *Desc, ProgramInfo &PI) const;
|
||||
|
||||
/// createSourceFunctionInfo - This method can be implemented by the derived
|
||||
/// SourceLanguage if it needs to keep track of more information than the
|
||||
/// SourceFunctionInfo has.
|
||||
virtual SourceFunctionInfo *
|
||||
createSourceFunctionInfo(const GlobalVariable *Desc, ProgramInfo &PI) const;
|
||||
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Static methods used to get instances of various source languages.
|
||||
//
|
||||
|
||||
/// get - This method returns a source-language instance for the specified
|
||||
/// Dwarf 3 language identifier. If the language is unknown, an object is
|
||||
/// returned that can support some minimal operations, but is not terribly
|
||||
/// bright.
|
||||
static const SourceLanguage &get(unsigned ID);
|
||||
|
||||
/// get*Instance() - These methods return specific instances of languages.
|
||||
///
|
||||
static const SourceLanguage &getCFamilyInstance();
|
||||
static const SourceLanguage &getCPlusPlusInstance();
|
||||
static const SourceLanguage &getUnknownLanguageInstance();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -1,135 +0,0 @@
|
||||
//===-- llvm/Metadata.h - Constant class subclass definitions ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
/// @file
|
||||
/// This file contains the declarations for the subclasses of Constant,
|
||||
/// which represent the different flavors of constant values that live in LLVM.
|
||||
/// Note that Constants are immutable (once created they never change) and are
|
||||
/// fully shared by structural equivalence. This means that two structurally
|
||||
/// equivalent constants will always have the same address. Constant's are
|
||||
/// created on demand as needed and never deleted: thus clients don't have to
|
||||
/// worry about the lifetime of the objects.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_MDNODE_H
|
||||
#define LLVM_MDNODE_H
|
||||
|
||||
#include "llvm/Constant.h"
|
||||
#include "llvm/Type.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/ValueHandle.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// MDNode - a tuple of other values.
|
||||
/// These contain a list of the Constants that represent the metadata. The
|
||||
/// operand list is always empty, query the element list instead.
|
||||
///
|
||||
/// This class will attempt to keep track of values as they are modified. When
|
||||
/// a value is replaced the element will be replaced with it, and when the
|
||||
/// value is deleted the element is set to a null pointer. In order to preserve
|
||||
/// structural equivalence while the elements mutate, the MDNode may call
|
||||
/// replaceAllUsesWith on itself. Because of this, users of MDNode must use a
|
||||
/// WeakVH or CallbackVH to hold the node pointer if there is a chance that one
|
||||
/// of the elements held by the node may change.
|
||||
///
|
||||
class MDNode : public Constant, public FoldingSetNode {
|
||||
MDNode(const MDNode &); // DO NOT IMPLEMENT
|
||||
|
||||
friend class ElementVH;
|
||||
struct ElementVH : public CallbackVH {
|
||||
MDNode *OwningNode;
|
||||
|
||||
ElementVH(Value *V, MDNode *Parent)
|
||||
: CallbackVH(V), OwningNode(Parent) {}
|
||||
|
||||
~ElementVH() {}
|
||||
|
||||
/// deleted - Set this entry in the MDNode to 'null'. This will reallocate
|
||||
/// the MDNode.
|
||||
virtual void deleted() {
|
||||
OwningNode->replaceElement(this->operator Value*(), 0);
|
||||
}
|
||||
|
||||
/// allUsesReplacedWith - Modify the MDNode by replacing this entry with
|
||||
/// new_value. This will reallocate the MDNode.
|
||||
virtual void allUsesReplacedWith(Value *new_value) {
|
||||
OwningNode->replaceElement(this->operator Value*(), new_value);
|
||||
}
|
||||
};
|
||||
|
||||
void replaceElement(Value *From, Value *To);
|
||||
|
||||
SmallVector<ElementVH, 4> Node;
|
||||
typedef SmallVectorImpl<ElementVH>::iterator elem_iterator;
|
||||
protected:
|
||||
explicit MDNode(Value*const* Vals, unsigned NumVals);
|
||||
public:
|
||||
typedef SmallVectorImpl<ElementVH>::const_iterator const_elem_iterator;
|
||||
|
||||
/// get() - Static factory methods - Return objects of the specified value.
|
||||
///
|
||||
static MDNode *get(Value*const* Vals, unsigned NumVals);
|
||||
|
||||
Value *getElement(unsigned i) const {
|
||||
return Node[i];
|
||||
}
|
||||
|
||||
unsigned getNumElements() const {
|
||||
return Node.size();
|
||||
}
|
||||
|
||||
bool elem_empty() const {
|
||||
return Node.empty();
|
||||
}
|
||||
|
||||
const_elem_iterator elem_begin() const {
|
||||
return Node.begin();
|
||||
}
|
||||
|
||||
const_elem_iterator elem_end() const {
|
||||
return Node.end();
|
||||
}
|
||||
|
||||
/// getType() specialization - Type is always MetadataTy.
|
||||
///
|
||||
inline const Type *getType() const {
|
||||
return Type::MetadataTy;
|
||||
}
|
||||
|
||||
/// isNullValue - Return true if this is the value that would be returned by
|
||||
/// getNullValue. This always returns false because getNullValue will never
|
||||
/// produce metadata.
|
||||
virtual bool isNullValue() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Profile - calculate a unique identifier for this MDNode to collapse
|
||||
/// duplicates
|
||||
void Profile(FoldingSetNodeID &ID) const;
|
||||
|
||||
virtual void destroyConstant();
|
||||
virtual void replaceUsesOfWithOnConstant(Value *From, Value *To, Use *U) {
|
||||
assert(0 && "This should never be called because MDNodes have no ops");
|
||||
abort();
|
||||
}
|
||||
|
||||
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
static inline bool classof(const MDNode *) { return true; }
|
||||
static bool classof(const Value *V) {
|
||||
return V->getValueID() == MDNodeVal;
|
||||
}
|
||||
};
|
||||
|
||||
} // end llvm namespace
|
||||
|
||||
#endif
|
@ -1,216 +0,0 @@
|
||||
//===-- llvm/Support/Annotation.h - Annotation classes ----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the declarations for two classes: Annotation & Annotable.
|
||||
// Using these two simple classes, anything that derives from Annotable can have
|
||||
// Annotation subclasses attached to them, ready for easy retrieval.
|
||||
//
|
||||
// Annotations are designed to be easily attachable to various classes.
|
||||
//
|
||||
// The AnnotationManager class is essential for using these classes. It is
|
||||
// responsible for turning Annotation name strings into tokens [unique id #'s]
|
||||
// that may be used to search for and create annotations.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_ANNOTATION_H
|
||||
#define LLVM_SUPPORT_ANNOTATION_H
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class AnnotationID;
|
||||
class Annotation;
|
||||
class Annotable;
|
||||
struct AnnotationManager;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// AnnotationID - This class is a thin wrapper around an unsigned integer that
|
||||
// is used to hopefully prevent errors using AnnotationID's. They may be copied
|
||||
// freely around and passed byvalue with little or no overhead.
|
||||
//
|
||||
class AnnotationID {
|
||||
friend struct AnnotationManager;
|
||||
unsigned ID;
|
||||
|
||||
AnnotationID(); // Default ctor is disabled
|
||||
|
||||
// AnnotationID is only creatable from AnnMgr.
|
||||
explicit inline AnnotationID(unsigned i) : ID(i) {}
|
||||
public:
|
||||
inline AnnotationID(const AnnotationID &A) : ID(A.ID) {}
|
||||
|
||||
inline bool operator==(const AnnotationID &A) const {
|
||||
return A.ID == ID;
|
||||
}
|
||||
inline bool operator<(const AnnotationID &A) const {
|
||||
return ID < A.ID;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Annotation Class - This class serves as a base class for any specific
|
||||
// annotations that you might need. Simply subclass this to add extra
|
||||
// information to the annotations.
|
||||
//
|
||||
class Annotation {
|
||||
friend class Annotable; // Annotable manipulates Next list
|
||||
AnnotationID ID; // ID number, as obtained from AnnotationManager
|
||||
Annotation *Next; // The next annotation in the linked list
|
||||
public:
|
||||
explicit inline Annotation(AnnotationID id) : ID(id), Next(0) {}
|
||||
virtual ~Annotation(); // Designed to be subclassed
|
||||
|
||||
// getID - Return the unique ID# of this annotation
|
||||
inline AnnotationID getID() const { return ID; }
|
||||
|
||||
// getNext - Return the next annotation in the list...
|
||||
inline Annotation *getNext() const { return Next; }
|
||||
};
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Annotable - This class is used as a base class for all objects that would
|
||||
// like to have annotation capability.
|
||||
//
|
||||
// Annotable objects keep their annotation list sorted as annotations are
|
||||
// inserted and deleted. This is used to ensure that annotations with identical
|
||||
// ID#'s are stored sequentially.
|
||||
//
|
||||
class Annotable {
|
||||
mutable Annotation *AnnotationList;
|
||||
|
||||
Annotable(const Annotable &); // Do not implement
|
||||
void operator=(const Annotable &); // Do not implement
|
||||
public:
|
||||
Annotable() : AnnotationList(0) {}
|
||||
~Annotable();
|
||||
|
||||
// getAnnotation - Search the list for annotations of the specified ID. The
|
||||
// pointer returned is either null (if no annotations of the specified ID
|
||||
// exist), or it points to the first element of a potentially list of elements
|
||||
// with identical ID #'s.
|
||||
//
|
||||
Annotation *getAnnotation(AnnotationID ID) const {
|
||||
for (Annotation *A = AnnotationList; A; A = A->getNext())
|
||||
if (A->getID() == ID) return A;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// getOrCreateAnnotation - Search through the annotation list, if there is
|
||||
// no annotation with the specified ID, then use the AnnotationManager to
|
||||
// create one.
|
||||
//
|
||||
inline Annotation *getOrCreateAnnotation(AnnotationID ID) const;
|
||||
|
||||
// addAnnotation - Insert the annotation into the list in a sorted location.
|
||||
//
|
||||
void addAnnotation(Annotation *A) const {
|
||||
assert(A->Next == 0 && "Annotation already in list?!?");
|
||||
|
||||
Annotation **AL = &AnnotationList;
|
||||
while (*AL && (*AL)->ID < A->getID()) // Find where to insert annotation
|
||||
AL = &((*AL)->Next);
|
||||
A->Next = *AL; // Link the annotation in
|
||||
*AL = A;
|
||||
}
|
||||
|
||||
// unlinkAnnotation - Remove the first annotation of the specified ID... and
|
||||
// then return the unlinked annotation. The annotation object is not deleted.
|
||||
//
|
||||
inline Annotation *unlinkAnnotation(AnnotationID ID) const {
|
||||
for (Annotation **A = &AnnotationList; *A; A = &((*A)->Next))
|
||||
if ((*A)->getID() == ID) {
|
||||
Annotation *Ret = *A;
|
||||
*A = Ret->Next;
|
||||
Ret->Next = 0;
|
||||
return Ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// deleteAnnotation - Delete the first annotation of the specified ID in the
|
||||
// list. Unlink unlinkAnnotation, this actually deletes the annotation object
|
||||
//
|
||||
bool deleteAnnotation(AnnotationID ID) const {
|
||||
Annotation *A = unlinkAnnotation(ID);
|
||||
delete A;
|
||||
return A != 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// AnnotationManager - This class is primarily responsible for maintaining a
|
||||
// one-to-one mapping between string Annotation names and Annotation ID numbers.
|
||||
//
|
||||
// Compared to the rest of the Annotation system, these mapping methods are
|
||||
// relatively slow, so they should be avoided by locally caching Annotation
|
||||
// ID #'s. These methods are safe to call at any time, even by static ctors, so
|
||||
// they should be used by static ctors most of the time.
|
||||
//
|
||||
// This class also provides support for annotations that are created on demand
|
||||
// by the Annotable::getOrCreateAnnotation method. To get this to work, simply
|
||||
// register an annotation handler
|
||||
//
|
||||
struct AnnotationManager {
|
||||
typedef Annotation *(*Factory)(AnnotationID, const Annotable *, void*);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Basic ID <-> Name map functionality
|
||||
|
||||
static AnnotationID getID(const char *Name); // Name -> ID
|
||||
static const char *getName(AnnotationID ID); // ID -> Name
|
||||
|
||||
// getID - Name -> ID + registration of a factory function for demand driven
|
||||
// annotation support.
|
||||
static AnnotationID getID(const char *Name, Factory Fact, void *Data = 0);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Annotation creation on demand support...
|
||||
|
||||
// registerAnnotationFactory - This method is used to register a callback
|
||||
// function used to create an annotation on demand if it is needed by the
|
||||
// Annotable::getOrCreateAnnotation method.
|
||||
//
|
||||
static void registerAnnotationFactory(AnnotationID ID, Factory Func,
|
||||
void *ExtraData = 0);
|
||||
|
||||
// createAnnotation - Create an annotation of the specified ID for the
|
||||
// specified object, using a register annotation creation function.
|
||||
//
|
||||
static Annotation *createAnnotation(AnnotationID ID, const Annotable *Obj);
|
||||
};
|
||||
|
||||
|
||||
|
||||
// getOrCreateAnnotation - Search through the annotation list, if there is
|
||||
// no annotation with the specified ID, then use the AnnotationManager to
|
||||
// create one.
|
||||
//
|
||||
inline Annotation *Annotable::getOrCreateAnnotation(AnnotationID ID) const {
|
||||
Annotation *A = getAnnotation(ID); // Fast path, check for preexisting ann
|
||||
if (A) return A;
|
||||
|
||||
// No annotation found, ask the annotation manager to create an annotation...
|
||||
A = AnnotationManager::createAnnotation(ID, this);
|
||||
assert(A && "AnnotationManager could not create annotation!");
|
||||
addAnnotation(A);
|
||||
return A;
|
||||
}
|
||||
|
||||
} // End namespace llvm
|
||||
|
||||
#endif
|
@ -1,91 +0,0 @@
|
||||
//===- llvm/Support/Streams.h - Wrappers for iostreams ----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements a wrapper for the STL I/O streams. It prevents the need
|
||||
// to include <iostream> in a file just to get I/O.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_STREAMS_H
|
||||
#define LLVM_SUPPORT_STREAMS_H
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// FlushStream - Function called by BaseStream to flush an ostream.
|
||||
void FlushStream(std::ostream &S);
|
||||
|
||||
/// BaseStream - Acts like the STL streams. It's a wrapper for the std::cerr,
|
||||
/// std::cout, std::cin, etc. streams. However, it doesn't require #including
|
||||
/// @verbatim <iostream> @endverbatm in every file (doing so increases static
|
||||
/// c'tors & d'tors in the object code).
|
||||
///
|
||||
template <typename StreamTy>
|
||||
class BaseStream {
|
||||
StreamTy *Stream;
|
||||
public:
|
||||
BaseStream() : Stream(0) {}
|
||||
BaseStream(StreamTy &S) : Stream(&S) {}
|
||||
BaseStream(StreamTy *S) : Stream(S) {}
|
||||
|
||||
StreamTy *stream() const { return Stream; }
|
||||
|
||||
inline BaseStream &operator << (std::ios_base &(*Func)(std::ios_base&)) {
|
||||
if (Stream) *Stream << Func;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline BaseStream &operator << (StreamTy &(*Func)(StreamTy&)) {
|
||||
if (Stream) *Stream << Func;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void flush() {
|
||||
if (Stream)
|
||||
FlushStream(*Stream);
|
||||
}
|
||||
|
||||
template <typename Ty>
|
||||
BaseStream &operator << (const Ty &Thing) {
|
||||
if (Stream) *Stream << Thing;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename Ty>
|
||||
BaseStream &operator >> (Ty &Thing) {
|
||||
if (Stream) *Stream >> Thing;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename Ty>
|
||||
BaseStream &write(const Ty &A, unsigned N) {
|
||||
if (Stream) Stream->write(A, N);
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator StreamTy* () { return Stream; }
|
||||
|
||||
bool operator == (const StreamTy &S) { return &S == Stream; }
|
||||
bool operator != (const StreamTy &S) { return !(*this == S); }
|
||||
bool operator == (const BaseStream &S) { return S.Stream == Stream; }
|
||||
bool operator != (const BaseStream &S) { return !(*this == S); }
|
||||
};
|
||||
|
||||
typedef BaseStream<std::ostream> OStream;
|
||||
typedef BaseStream<std::istream> IStream;
|
||||
typedef BaseStream<std::stringstream> StringStream;
|
||||
|
||||
extern OStream cout;
|
||||
extern OStream cerr;
|
||||
extern IStream cin;
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
@ -1,50 +0,0 @@
|
||||
//===---- DarwinTargetAsmInfo.h - Darwin asm properties ---------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines target asm properties related what form asm statements
|
||||
// should take in general on Darwin-based targets
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_DARWIN_TARGET_ASM_INFO_H
|
||||
#define LLVM_DARWIN_TARGET_ASM_INFO_H
|
||||
|
||||
#include "llvm/Target/TargetAsmInfo.h"
|
||||
|
||||
namespace llvm {
|
||||
class GlobalValue;
|
||||
class GlobalVariable;
|
||||
class Type;
|
||||
class Mangler;
|
||||
|
||||
struct DarwinTargetAsmInfo : public TargetAsmInfo {
|
||||
const Section* TextCoalSection;
|
||||
const Section* ConstTextCoalSection;
|
||||
const Section* ConstDataCoalSection;
|
||||
const Section* ConstDataSection;
|
||||
const Section* DataCoalSection;
|
||||
const Section* FourByteConstantSection;
|
||||
const Section* EightByteConstantSection;
|
||||
const Section* SixteenByteConstantSection;
|
||||
|
||||
explicit DarwinTargetAsmInfo(const TargetMachine &TM);
|
||||
virtual const Section* SelectSectionForGlobal(const GlobalValue *GV) const;
|
||||
virtual std::string UniqueSectionForGlobal(const GlobalValue* GV,
|
||||
SectionKind::Kind kind) const;
|
||||
virtual bool emitUsedDirectiveFor(const GlobalValue *GV,
|
||||
Mangler *Mang) const;
|
||||
const Section* MergeableConstSection(const GlobalVariable *GV) const;
|
||||
const Section* MergeableConstSection(const Type *Ty) const;
|
||||
const Section* MergeableStringSection(const GlobalVariable *GV) const;
|
||||
const Section* SelectSectionForMachineConst(const Type *Ty) const;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif // LLVM_DARWIN_TARGET_ASM_INFO_H
|
@ -1,45 +0,0 @@
|
||||
//===---- ELFTargetAsmInfo.h - ELF asm properties ---------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines target asm properties related what form asm statements
|
||||
// should take in general on ELF-based targets
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ELF_TARGET_ASM_INFO_H
|
||||
#define LLVM_ELF_TARGET_ASM_INFO_H
|
||||
|
||||
#include "llvm/Target/TargetAsmInfo.h"
|
||||
|
||||
namespace llvm {
|
||||
class GlobalValue;
|
||||
class GlobalVariable;
|
||||
class Type;
|
||||
|
||||
struct ELFTargetAsmInfo: public TargetAsmInfo {
|
||||
explicit ELFTargetAsmInfo(const TargetMachine &TM);
|
||||
|
||||
SectionKind::Kind SectionKindForGlobal(const GlobalValue *GV) const;
|
||||
virtual const Section* SelectSectionForGlobal(const GlobalValue *GV) const;
|
||||
virtual std::string printSectionFlags(unsigned flags) const;
|
||||
const Section* MergeableConstSection(const GlobalVariable *GV) const;
|
||||
inline const Section* MergeableConstSection(const Type *Ty) const;
|
||||
const Section* MergeableStringSection(const GlobalVariable *GV) const;
|
||||
virtual const Section*
|
||||
SelectSectionForMachineConst(const Type *Ty) const;
|
||||
|
||||
const Section* DataRelSection;
|
||||
const Section* DataRelLocalSection;
|
||||
const Section* DataRelROSection;
|
||||
const Section* DataRelROLocalSection;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif // LLVM_ELF_TARGET_ASM_INFO_H
|
@ -1,930 +0,0 @@
|
||||
//===-- llvm/Target/TargetAsmInfo.h - Asm info ------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains a class to be used as the basis for target specific
|
||||
// asm writers. This class primarily takes care of global printing constants,
|
||||
// which are used in very similar ways across all targets.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TARGET_ASM_INFO_H
|
||||
#define LLVM_TARGET_ASM_INFO_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include <string>
|
||||
|
||||
namespace llvm {
|
||||
// DWARF encoding query type
|
||||
namespace DwarfEncoding {
|
||||
enum Target {
|
||||
Data = 0,
|
||||
CodeLabels = 1,
|
||||
Functions = 2
|
||||
};
|
||||
}
|
||||
|
||||
namespace SectionKind {
|
||||
enum Kind {
|
||||
Unknown = 0, ///< Custom section
|
||||
Text, ///< Text section
|
||||
Data, ///< Data section
|
||||
DataRel, ///< Contains data that has relocations
|
||||
DataRelLocal, ///< Contains data that has only local relocations
|
||||
BSS, ///< BSS section
|
||||
ROData, ///< Readonly data section
|
||||
DataRelRO, ///< Contains data that is otherwise readonly
|
||||
DataRelROLocal, ///< Contains r/o data with only local relocations
|
||||
RODataMergeStr, ///< Readonly data section (mergeable strings)
|
||||
RODataMergeConst, ///< Readonly data section (mergeable constants)
|
||||
SmallData, ///< Small data section
|
||||
SmallBSS, ///< Small bss section
|
||||
SmallROData, ///< Small readonly section
|
||||
ThreadData, ///< Initialized TLS data objects
|
||||
ThreadBSS ///< Uninitialized TLS data objects
|
||||
};
|
||||
|
||||
static inline bool isReadOnly(Kind K) {
|
||||
return (K == SectionKind::ROData ||
|
||||
K == SectionKind::RODataMergeConst ||
|
||||
K == SectionKind::RODataMergeStr ||
|
||||
K == SectionKind::SmallROData);
|
||||
}
|
||||
|
||||
static inline bool isBSS(Kind K) {
|
||||
return (K == SectionKind::BSS ||
|
||||
K == SectionKind::SmallBSS);
|
||||
}
|
||||
}
|
||||
|
||||
namespace SectionFlags {
|
||||
const unsigned Invalid = -1U;
|
||||
const unsigned None = 0;
|
||||
const unsigned Code = 1 << 0; ///< Section contains code
|
||||
const unsigned Writeable = 1 << 1; ///< Section is writeable
|
||||
const unsigned BSS = 1 << 2; ///< Section contains only zeroes
|
||||
const unsigned Mergeable = 1 << 3; ///< Section contains mergeable data
|
||||
const unsigned Strings = 1 << 4; ///< Section contains C-type strings
|
||||
const unsigned TLS = 1 << 5; ///< Section contains thread-local data
|
||||
const unsigned Debug = 1 << 6; ///< Section contains debug data
|
||||
const unsigned Linkonce = 1 << 7; ///< Section is linkonce
|
||||
const unsigned Small = 1 << 8; ///< Section is small
|
||||
const unsigned TypeFlags = 0xFF;
|
||||
// Some gap for future flags
|
||||
const unsigned Named = 1 << 23; ///< Section is named
|
||||
const unsigned EntitySize = 0xFF << 24; ///< Entity size for mergeable stuff
|
||||
|
||||
static inline unsigned getEntitySize(unsigned Flags) {
|
||||
return (Flags >> 24) & 0xFF;
|
||||
}
|
||||
|
||||
static inline unsigned setEntitySize(unsigned Flags, unsigned Size) {
|
||||
return ((Flags & ~EntitySize) | ((Size & 0xFF) << 24));
|
||||
}
|
||||
|
||||
struct KeyInfo {
|
||||
static inline unsigned getEmptyKey() { return Invalid; }
|
||||
static inline unsigned getTombstoneKey() { return Invalid - 1; }
|
||||
static unsigned getHashValue(const unsigned &Key) { return Key; }
|
||||
static bool isEqual(unsigned LHS, unsigned RHS) { return LHS == RHS; }
|
||||
static bool isPod() { return true; }
|
||||
};
|
||||
|
||||
typedef DenseMap<unsigned, std::string, KeyInfo> FlagsStringsMapType;
|
||||
}
|
||||
|
||||
class TargetMachine;
|
||||
class CallInst;
|
||||
class GlobalValue;
|
||||
class Type;
|
||||
class Mangler;
|
||||
|
||||
class Section {
|
||||
friend class TargetAsmInfo;
|
||||
friend class StringMapEntry<Section>;
|
||||
friend class StringMap<Section>;
|
||||
|
||||
std::string Name;
|
||||
unsigned Flags;
|
||||
explicit Section(unsigned F = SectionFlags::Invalid):Flags(F) { }
|
||||
|
||||
public:
|
||||
|
||||
bool isNamed() const { return Flags & SectionFlags::Named; }
|
||||
unsigned getEntitySize() const { return (Flags >> 24) & 0xFF; }
|
||||
|
||||
const std::string& getName() const { return Name; }
|
||||
unsigned getFlags() const { return Flags; }
|
||||
};
|
||||
|
||||
/// TargetAsmInfo - This class is intended to be used as a base class for asm
|
||||
/// properties and features specific to the target.
|
||||
class TargetAsmInfo {
|
||||
private:
|
||||
mutable StringMap<Section> Sections;
|
||||
mutable SectionFlags::FlagsStringsMapType FlagsStrings;
|
||||
protected:
|
||||
/// TM - The current TargetMachine.
|
||||
const TargetMachine &TM;
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Properties to be set by the target writer, used to configure asm printer.
|
||||
//
|
||||
|
||||
/// TextSection - Section directive for standard text.
|
||||
///
|
||||
const Section *TextSection; // Defaults to ".text".
|
||||
|
||||
/// DataSection - Section directive for standard data.
|
||||
///
|
||||
const Section *DataSection; // Defaults to ".data".
|
||||
|
||||
/// BSSSection - Section directive for uninitialized data. Null if this
|
||||
/// target doesn't support a BSS section.
|
||||
///
|
||||
const char *BSSSection; // Default to ".bss".
|
||||
const Section *BSSSection_;
|
||||
|
||||
/// ReadOnlySection - This is the directive that is emitted to switch to a
|
||||
/// read-only section for constant data (e.g. data declared const,
|
||||
/// jump tables).
|
||||
const Section *ReadOnlySection; // Defaults to NULL
|
||||
|
||||
/// SmallDataSection - This is the directive that is emitted to switch to a
|
||||
/// small data section.
|
||||
///
|
||||
const Section *SmallDataSection; // Defaults to NULL
|
||||
|
||||
/// SmallBSSSection - This is the directive that is emitted to switch to a
|
||||
/// small bss section.
|
||||
///
|
||||
const Section *SmallBSSSection; // Defaults to NULL
|
||||
|
||||
/// SmallRODataSection - This is the directive that is emitted to switch to
|
||||
/// a small read-only data section.
|
||||
///
|
||||
const Section *SmallRODataSection; // Defaults to NULL
|
||||
|
||||
/// TLSDataSection - Section directive for Thread Local data.
|
||||
///
|
||||
const Section *TLSDataSection; // Defaults to ".tdata".
|
||||
|
||||
/// TLSBSSSection - Section directive for Thread Local uninitialized data.
|
||||
/// Null if this target doesn't support a BSS section.
|
||||
///
|
||||
const Section *TLSBSSSection; // Defaults to ".tbss".
|
||||
|
||||
/// ZeroFillDirective - Directive for emitting a global to the ZeroFill
|
||||
/// section on this target. Null if this target doesn't support zerofill.
|
||||
const char *ZeroFillDirective; // Default is null.
|
||||
|
||||
/// NonexecutableStackDirective - Directive for declaring to the
|
||||
/// linker and beyond that the emitted code does not require stack
|
||||
/// memory to be executable.
|
||||
const char *NonexecutableStackDirective; // Default is null.
|
||||
|
||||
/// NeedsSet - True if target asm treats expressions in data directives
|
||||
/// as linktime-relocatable. For assembly-time computation, we need to
|
||||
/// use a .set. Thus:
|
||||
/// .set w, x-y
|
||||
/// .long w
|
||||
/// is computed at assembly time, while
|
||||
/// .long x-y
|
||||
/// is relocated if the relative locations of x and y change at linktime.
|
||||
/// We want both these things in different places.
|
||||
bool NeedsSet; // Defaults to false.
|
||||
|
||||
/// MaxInstLength - This is the maximum possible length of an instruction,
|
||||
/// which is needed to compute the size of an inline asm.
|
||||
unsigned MaxInstLength; // Defaults to 4.
|
||||
|
||||
/// PCSymbol - The symbol used to represent the current PC. Used in PC
|
||||
/// relative expressions.
|
||||
const char *PCSymbol; // Defaults to "$".
|
||||
|
||||
/// SeparatorChar - This character, if specified, is used to separate
|
||||
/// instructions from each other when on the same line. This is used to
|
||||
/// measure inline asm instructions.
|
||||
char SeparatorChar; // Defaults to ';'
|
||||
|
||||
/// CommentString - This indicates the comment character used by the
|
||||
/// assembler.
|
||||
const char *CommentString; // Defaults to "#"
|
||||
|
||||
/// GlobalPrefix - If this is set to a non-empty string, it is prepended
|
||||
/// onto all global symbols. This is often used for "_" or ".".
|
||||
const char *GlobalPrefix; // Defaults to ""
|
||||
|
||||
/// PrivateGlobalPrefix - This prefix is used for globals like constant
|
||||
/// pool entries that are completely private to the .s file and should not
|
||||
/// have names in the .o file. This is often "." or "L".
|
||||
const char *PrivateGlobalPrefix; // Defaults to "."
|
||||
|
||||
/// LessPrivateGlobalPrefix - This prefix is used for symbols that should
|
||||
/// be passed through the assembler but be removed by the linker. This
|
||||
/// is "l" on Darwin, currently used for some ObjC metadata.
|
||||
const char *LessPrivateGlobalPrefix; // Defaults to ""
|
||||
|
||||
/// JumpTableSpecialLabelPrefix - If not null, a extra (dead) label is
|
||||
/// emitted before jump tables with the specified prefix.
|
||||
const char *JumpTableSpecialLabelPrefix; // Default to null.
|
||||
|
||||
/// GlobalVarAddrPrefix/Suffix - If these are nonempty, these strings
|
||||
/// will enclose any GlobalVariable (that isn't a function)
|
||||
///
|
||||
const char *GlobalVarAddrPrefix; // Defaults to ""
|
||||
const char *GlobalVarAddrSuffix; // Defaults to ""
|
||||
|
||||
/// FunctionAddrPrefix/Suffix - If these are nonempty, these strings
|
||||
/// will enclose any GlobalVariable that points to a function.
|
||||
/// For example, this is used by the IA64 backend to materialize
|
||||
/// function descriptors, by decorating the ".data8" object with the
|
||||
/// @verbatim @fptr( ) @endverbatim
|
||||
/// link-relocation operator.
|
||||
///
|
||||
const char *FunctionAddrPrefix; // Defaults to ""
|
||||
const char *FunctionAddrSuffix; // Defaults to ""
|
||||
|
||||
/// PersonalityPrefix/Suffix - If these are nonempty, these strings will
|
||||
/// enclose any personality function in the common frame section.
|
||||
///
|
||||
const char *PersonalityPrefix; // Defaults to ""
|
||||
const char *PersonalitySuffix; // Defaults to ""
|
||||
|
||||
/// NeedsIndirectEncoding - If set, we need to set the indirect encoding bit
|
||||
/// for EH in Dwarf.
|
||||
///
|
||||
bool NeedsIndirectEncoding; // Defaults to false
|
||||
|
||||
/// InlineAsmStart/End - If these are nonempty, they contain a directive to
|
||||
/// emit before and after an inline assembly statement.
|
||||
const char *InlineAsmStart; // Defaults to "#APP\n"
|
||||
const char *InlineAsmEnd; // Defaults to "#NO_APP\n"
|
||||
|
||||
/// AssemblerDialect - Which dialect of an assembler variant to use.
|
||||
unsigned AssemblerDialect; // Defaults to 0
|
||||
|
||||
/// StringConstantPrefix - Prefix for FEs to use when generating unnamed
|
||||
/// constant strings. These names get run through the Mangler later; if
|
||||
/// you want the Mangler not to add the GlobalPrefix as well,
|
||||
/// use '\1' as the first character.
|
||||
const char *StringConstantPrefix; // Defaults to ".str"
|
||||
|
||||
/// AllowQuotesInName - This is true if the assembler allows for complex
|
||||
/// symbol names to be surrounded in quotes. This defaults to false.
|
||||
bool AllowQuotesInName;
|
||||
|
||||
//===--- Data Emission Directives -------------------------------------===//
|
||||
|
||||
/// ZeroDirective - this should be set to the directive used to get some
|
||||
/// number of zero bytes emitted to the current section. Common cases are
|
||||
/// "\t.zero\t" and "\t.space\t". If this is set to null, the
|
||||
/// Data*bitsDirective's will be used to emit zero bytes.
|
||||
const char *ZeroDirective; // Defaults to "\t.zero\t"
|
||||
const char *ZeroDirectiveSuffix; // Defaults to ""
|
||||
|
||||
/// AsciiDirective - This directive allows emission of an ascii string with
|
||||
/// the standard C escape characters embedded into it.
|
||||
const char *AsciiDirective; // Defaults to "\t.ascii\t"
|
||||
|
||||
/// AscizDirective - If not null, this allows for special handling of
|
||||
/// zero terminated strings on this target. This is commonly supported as
|
||||
/// ".asciz". If a target doesn't support this, it can be set to null.
|
||||
const char *AscizDirective; // Defaults to "\t.asciz\t"
|
||||
|
||||
/// DataDirectives - These directives are used to output some unit of
|
||||
/// integer data to the current section. If a data directive is set to
|
||||
/// null, smaller data directives will be used to emit the large sizes.
|
||||
const char *Data8bitsDirective; // Defaults to "\t.byte\t"
|
||||
const char *Data16bitsDirective; // Defaults to "\t.short\t"
|
||||
const char *Data32bitsDirective; // Defaults to "\t.long\t"
|
||||
const char *Data64bitsDirective; // Defaults to "\t.quad\t"
|
||||
|
||||
/// getASDirective - Targets can override it to provide different data
|
||||
/// directives for various sizes and non-default address spaces.
|
||||
virtual const char *getASDirective(unsigned size,
|
||||
unsigned AS) const {
|
||||
assert(AS > 0 && "Dont know the directives for default addr space");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//===--- Alignment Information ----------------------------------------===//
|
||||
|
||||
/// AlignDirective - The directive used to emit round up to an alignment
|
||||
/// boundary.
|
||||
///
|
||||
const char *AlignDirective; // Defaults to "\t.align\t"
|
||||
|
||||
/// AlignmentIsInBytes - If this is true (the default) then the asmprinter
|
||||
/// emits ".align N" directives, where N is the number of bytes to align to.
|
||||
/// Otherwise, it emits ".align log2(N)", e.g. 3 to align to an 8 byte
|
||||
/// boundary.
|
||||
bool AlignmentIsInBytes; // Defaults to true
|
||||
|
||||
/// TextAlignFillValue - If non-zero, this is used to fill the executable
|
||||
/// space created as the result of a alignment directive.
|
||||
unsigned TextAlignFillValue;
|
||||
|
||||
//===--- Section Switching Directives ---------------------------------===//
|
||||
|
||||
/// SwitchToSectionDirective - This is the directive used when we want to
|
||||
/// emit a global to an arbitrary section. The section name is emited after
|
||||
/// this.
|
||||
const char *SwitchToSectionDirective; // Defaults to "\t.section\t"
|
||||
|
||||
/// TextSectionStartSuffix - This is printed after each start of section
|
||||
/// directive for text sections.
|
||||
const char *TextSectionStartSuffix; // Defaults to "".
|
||||
|
||||
/// DataSectionStartSuffix - This is printed after each start of section
|
||||
/// directive for data sections.
|
||||
const char *DataSectionStartSuffix; // Defaults to "".
|
||||
|
||||
/// SectionEndDirectiveSuffix - If non-null, the asm printer will close each
|
||||
/// section with the section name and this suffix printed.
|
||||
const char *SectionEndDirectiveSuffix;// Defaults to null.
|
||||
|
||||
/// ConstantPoolSection - This is the section that we SwitchToSection right
|
||||
/// before emitting the constant pool for a function.
|
||||
const char *ConstantPoolSection; // Defaults to "\t.section .rodata"
|
||||
|
||||
/// JumpTableDataSection - This is the section that we SwitchToSection right
|
||||
/// before emitting the jump tables for a function when the relocation model
|
||||
/// is not PIC.
|
||||
const char *JumpTableDataSection; // Defaults to "\t.section .rodata"
|
||||
|
||||
/// JumpTableDirective - if non-null, the directive to emit before a jump
|
||||
/// table.
|
||||
const char *JumpTableDirective;
|
||||
|
||||
/// CStringSection - If not null, this allows for special handling of
|
||||
/// cstring constants (null terminated string that does not contain any
|
||||
/// other null bytes) on this target. This is commonly supported as
|
||||
/// ".cstring".
|
||||
const char *CStringSection; // Defaults to NULL
|
||||
const Section *CStringSection_;
|
||||
|
||||
/// StaticCtorsSection - This is the directive that is emitted to switch to
|
||||
/// a section to emit the static constructor list.
|
||||
/// Defaults to "\t.section .ctors,\"aw\",@progbits".
|
||||
const char *StaticCtorsSection;
|
||||
|
||||
/// StaticDtorsSection - This is the directive that is emitted to switch to
|
||||
/// a section to emit the static destructor list.
|
||||
/// Defaults to "\t.section .dtors,\"aw\",@progbits".
|
||||
const char *StaticDtorsSection;
|
||||
|
||||
//===--- Global Variable Emission Directives --------------------------===//
|
||||
|
||||
/// GlobalDirective - This is the directive used to declare a global entity.
|
||||
///
|
||||
const char *GlobalDirective; // Defaults to NULL.
|
||||
|
||||
/// ExternDirective - This is the directive used to declare external
|
||||
/// globals.
|
||||
///
|
||||
const char *ExternDirective; // Defaults to NULL.
|
||||
|
||||
/// SetDirective - This is the name of a directive that can be used to tell
|
||||
/// the assembler to set the value of a variable to some expression.
|
||||
const char *SetDirective; // Defaults to null.
|
||||
|
||||
/// LCOMMDirective - This is the name of a directive (if supported) that can
|
||||
/// be used to efficiently declare a local (internal) block of zero
|
||||
/// initialized data in the .bss/.data section. The syntax expected is:
|
||||
/// @verbatim <LCOMMDirective> SYMBOLNAME LENGTHINBYTES, ALIGNMENT
|
||||
/// @endverbatim
|
||||
const char *LCOMMDirective; // Defaults to null.
|
||||
|
||||
const char *COMMDirective; // Defaults to "\t.comm\t".
|
||||
|
||||
/// COMMDirectiveTakesAlignment - True if COMMDirective take a third
|
||||
/// argument that specifies the alignment of the declaration.
|
||||
bool COMMDirectiveTakesAlignment; // Defaults to true.
|
||||
|
||||
/// HasDotTypeDotSizeDirective - True if the target has .type and .size
|
||||
/// directives, this is true for most ELF targets.
|
||||
bool HasDotTypeDotSizeDirective; // Defaults to true.
|
||||
|
||||
/// HasSingleParameterDotFile - True if the target has a single parameter
|
||||
/// .file directive, this is true for ELF targets.
|
||||
bool HasSingleParameterDotFile; // Defaults to true.
|
||||
|
||||
/// UsedDirective - This directive, if non-null, is used to declare a global
|
||||
/// as being used somehow that the assembler can't see. This prevents dead
|
||||
/// code elimination on some targets.
|
||||
const char *UsedDirective; // Defaults to null.
|
||||
|
||||
/// WeakRefDirective - This directive, if non-null, is used to declare a
|
||||
/// global as being a weak undefined symbol.
|
||||
const char *WeakRefDirective; // Defaults to null.
|
||||
|
||||
/// WeakDefDirective - This directive, if non-null, is used to declare a
|
||||
/// global as being a weak defined symbol.
|
||||
const char *WeakDefDirective; // Defaults to null.
|
||||
|
||||
/// HiddenDirective - This directive, if non-null, is used to declare a
|
||||
/// global or function as having hidden visibility.
|
||||
const char *HiddenDirective; // Defaults to "\t.hidden\t".
|
||||
|
||||
/// ProtectedDirective - This directive, if non-null, is used to declare a
|
||||
/// global or function as having protected visibility.
|
||||
const char *ProtectedDirective; // Defaults to "\t.protected\t".
|
||||
|
||||
//===--- Dwarf Emission Directives -----------------------------------===//
|
||||
|
||||
/// AbsoluteDebugSectionOffsets - True if we should emit abolute section
|
||||
/// offsets for debug information. Defaults to false.
|
||||
bool AbsoluteDebugSectionOffsets;
|
||||
|
||||
/// AbsoluteEHSectionOffsets - True if we should emit abolute section
|
||||
/// offsets for EH information. Defaults to false.
|
||||
bool AbsoluteEHSectionOffsets;
|
||||
|
||||
/// HasLEB128 - True if target asm supports leb128 directives.
|
||||
///
|
||||
bool HasLEB128; // Defaults to false.
|
||||
|
||||
/// hasDotLocAndDotFile - True if target asm supports .loc and .file
|
||||
/// directives for emitting debugging information.
|
||||
///
|
||||
bool HasDotLocAndDotFile; // Defaults to false.
|
||||
|
||||
/// SupportsDebugInformation - True if target supports emission of debugging
|
||||
/// information.
|
||||
bool SupportsDebugInformation;
|
||||
|
||||
/// SupportsExceptionHandling - True if target supports
|
||||
/// exception handling.
|
||||
///
|
||||
bool SupportsExceptionHandling; // Defaults to false.
|
||||
|
||||
/// RequiresFrameSection - true if the Dwarf2 output needs a frame section
|
||||
///
|
||||
bool DwarfRequiresFrameSection; // Defaults to true.
|
||||
|
||||
/// DwarfUsesInlineInfoSection - True if DwarfDebugInlineSection is used to
|
||||
/// encode inline subroutine information.
|
||||
bool DwarfUsesInlineInfoSection; // Defaults to false.
|
||||
|
||||
/// NonLocalEHFrameLabel - If set, the EH_frame label needs to be non-local.
|
||||
///
|
||||
bool NonLocalEHFrameLabel; // Defaults to false.
|
||||
|
||||
/// GlobalEHDirective - This is the directive used to make exception frame
|
||||
/// tables globally visible.
|
||||
///
|
||||
const char *GlobalEHDirective; // Defaults to NULL.
|
||||
|
||||
/// SupportsWeakEmptyEHFrame - True if target assembler and linker will
|
||||
/// handle a weak_definition of constant 0 for an omitted EH frame.
|
||||
bool SupportsWeakOmittedEHFrame; // Defaults to true.
|
||||
|
||||
/// DwarfSectionOffsetDirective - Special section offset directive.
|
||||
const char* DwarfSectionOffsetDirective; // Defaults to NULL
|
||||
|
||||
/// DwarfAbbrevSection - Section directive for Dwarf abbrev.
|
||||
///
|
||||
const char *DwarfAbbrevSection; // Defaults to ".debug_abbrev".
|
||||
|
||||
/// DwarfInfoSection - Section directive for Dwarf info.
|
||||
///
|
||||
const char *DwarfInfoSection; // Defaults to ".debug_info".
|
||||
|
||||
/// DwarfLineSection - Section directive for Dwarf info.
|
||||
///
|
||||
const char *DwarfLineSection; // Defaults to ".debug_line".
|
||||
|
||||
/// DwarfFrameSection - Section directive for Dwarf info.
|
||||
///
|
||||
const char *DwarfFrameSection; // Defaults to ".debug_frame".
|
||||
|
||||
/// DwarfPubNamesSection - Section directive for Dwarf info.
|
||||
///
|
||||
const char *DwarfPubNamesSection; // Defaults to ".debug_pubnames".
|
||||
|
||||
/// DwarfPubTypesSection - Section directive for Dwarf info.
|
||||
///
|
||||
const char *DwarfPubTypesSection; // Defaults to ".debug_pubtypes".
|
||||
|
||||
/// DwarfDebugInlineSection - Section directive for inline info.
|
||||
///
|
||||
const char *DwarfDebugInlineSection; // Defaults to ".debug_inlined"
|
||||
|
||||
/// DwarfStrSection - Section directive for Dwarf info.
|
||||
///
|
||||
const char *DwarfStrSection; // Defaults to ".debug_str".
|
||||
|
||||
/// DwarfLocSection - Section directive for Dwarf info.
|
||||
///
|
||||
const char *DwarfLocSection; // Defaults to ".debug_loc".
|
||||
|
||||
/// DwarfARangesSection - Section directive for Dwarf info.
|
||||
///
|
||||
const char *DwarfARangesSection; // Defaults to ".debug_aranges".
|
||||
|
||||
/// DwarfRangesSection - Section directive for Dwarf info.
|
||||
///
|
||||
const char *DwarfRangesSection; // Defaults to ".debug_ranges".
|
||||
|
||||
/// DwarfMacroInfoSection - Section directive for DWARF macro info.
|
||||
///
|
||||
const char *DwarfMacroInfoSection; // Defaults to ".debug_macinfo".
|
||||
|
||||
/// DwarfEHFrameSection - Section directive for Exception frames.
|
||||
///
|
||||
const char *DwarfEHFrameSection; // Defaults to ".eh_frame".
|
||||
|
||||
/// DwarfExceptionSection - Section directive for Exception table.
|
||||
///
|
||||
const char *DwarfExceptionSection; // Defaults to ".gcc_except_table".
|
||||
|
||||
//===--- CBE Asm Translation Table -----------------------------------===//
|
||||
|
||||
const char *const *AsmTransCBE; // Defaults to empty
|
||||
|
||||
public:
|
||||
explicit TargetAsmInfo(const TargetMachine &TM);
|
||||
virtual ~TargetAsmInfo();
|
||||
|
||||
const Section* getNamedSection(const char *Name,
|
||||
unsigned Flags = SectionFlags::None,
|
||||
bool Override = false) const;
|
||||
const Section* getUnnamedSection(const char *Directive,
|
||||
unsigned Flags = SectionFlags::None,
|
||||
bool Override = false) const;
|
||||
|
||||
/// Measure the specified inline asm to determine an approximation of its
|
||||
/// length.
|
||||
virtual unsigned getInlineAsmLength(const char *Str) const;
|
||||
|
||||
/// ExpandInlineAsm - This hook allows the target to expand an inline asm
|
||||
/// call to be explicit llvm code if it wants to. This is useful for
|
||||
/// turning simple inline asms into LLVM intrinsics, which gives the
|
||||
/// compiler more information about the behavior of the code.
|
||||
virtual bool ExpandInlineAsm(CallInst *CI) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// emitUsedDirectiveFor - This hook allows targets to selectively decide
|
||||
/// not to emit the UsedDirective for some symbols in llvm.used.
|
||||
virtual bool emitUsedDirectiveFor(const GlobalValue *GV,
|
||||
Mangler *Mang) const {
|
||||
return (GV!=0);
|
||||
}
|
||||
|
||||
/// PreferredEHDataFormat - This hook allows the target to select data
|
||||
/// format used for encoding pointers in exception handling data. Reason is
|
||||
/// 0 for data, 1 for code labels, 2 for function pointers. Global is true
|
||||
/// if the symbol can be relocated.
|
||||
virtual unsigned PreferredEHDataFormat(DwarfEncoding::Target Reason,
|
||||
bool Global) const;
|
||||
|
||||
/// SectionKindForGlobal - This hook allows the target to select proper
|
||||
/// section kind used for global emission.
|
||||
virtual SectionKind::Kind
|
||||
SectionKindForGlobal(const GlobalValue *GV) const;
|
||||
|
||||
/// RelocBehaviour - Describes how relocations should be treated when
|
||||
/// selecting sections. Reloc::Global bit should be set if global
|
||||
/// relocations should force object to be placed in read-write
|
||||
/// sections. Reloc::Local bit should be set if local relocations should
|
||||
/// force object to be placed in read-write sections.
|
||||
virtual unsigned RelocBehaviour() const;
|
||||
|
||||
/// SectionFlagsForGlobal - This hook allows the target to select proper
|
||||
/// section flags either for given global or for section.
|
||||
virtual unsigned
|
||||
SectionFlagsForGlobal(const GlobalValue *GV = NULL,
|
||||
const char* name = NULL) const;
|
||||
|
||||
/// SectionForGlobal - This hooks returns proper section name for given
|
||||
/// global with all necessary flags and marks.
|
||||
virtual const Section* SectionForGlobal(const GlobalValue *GV) const;
|
||||
|
||||
// Helper methods for SectionForGlobal
|
||||
virtual std::string UniqueSectionForGlobal(const GlobalValue* GV,
|
||||
SectionKind::Kind kind) const;
|
||||
|
||||
const std::string& getSectionFlags(unsigned Flags) const;
|
||||
virtual std::string printSectionFlags(unsigned flags) const { return ""; }
|
||||
|
||||
virtual const Section* SelectSectionForGlobal(const GlobalValue *GV) const;
|
||||
|
||||
virtual const Section* SelectSectionForMachineConst(const Type *Ty) const;
|
||||
|
||||
/// getSLEB128Size - Compute the number of bytes required for a signed
|
||||
/// leb128 value.
|
||||
|
||||
static unsigned getSLEB128Size(int Value);
|
||||
|
||||
/// getULEB128Size - Compute the number of bytes required for an unsigned
|
||||
/// leb128 value.
|
||||
|
||||
static unsigned getULEB128Size(unsigned Value);
|
||||
|
||||
// Data directive accessors
|
||||
//
|
||||
const char *getData8bitsDirective(unsigned AS = 0) const {
|
||||
return AS == 0 ? Data8bitsDirective : getASDirective(8, AS);
|
||||
}
|
||||
const char *getData16bitsDirective(unsigned AS = 0) const {
|
||||
return AS == 0 ? Data16bitsDirective : getASDirective(16, AS);
|
||||
}
|
||||
const char *getData32bitsDirective(unsigned AS = 0) const {
|
||||
return AS == 0 ? Data32bitsDirective : getASDirective(32, AS);
|
||||
}
|
||||
const char *getData64bitsDirective(unsigned AS = 0) const {
|
||||
return AS == 0 ? Data64bitsDirective : getASDirective(64, AS);
|
||||
}
|
||||
|
||||
|
||||
// Accessors.
|
||||
//
|
||||
const Section *getTextSection() const {
|
||||
return TextSection;
|
||||
}
|
||||
const Section *getDataSection() const {
|
||||
return DataSection;
|
||||
}
|
||||
const char *getBSSSection() const {
|
||||
return BSSSection;
|
||||
}
|
||||
const Section *getBSSSection_() const {
|
||||
return BSSSection_;
|
||||
}
|
||||
const Section *getReadOnlySection() const {
|
||||
return ReadOnlySection;
|
||||
}
|
||||
const Section *getSmallDataSection() const {
|
||||
return SmallDataSection;
|
||||
}
|
||||
const Section *getSmallBSSSection() const {
|
||||
return SmallBSSSection;
|
||||
}
|
||||
const Section *getSmallRODataSection() const {
|
||||
return SmallRODataSection;
|
||||
}
|
||||
const Section *getTLSDataSection() const {
|
||||
return TLSDataSection;
|
||||
}
|
||||
const Section *getTLSBSSSection() const {
|
||||
return TLSBSSSection;
|
||||
}
|
||||
const char *getZeroFillDirective() const {
|
||||
return ZeroFillDirective;
|
||||
}
|
||||
const char *getNonexecutableStackDirective() const {
|
||||
return NonexecutableStackDirective;
|
||||
}
|
||||
bool needsSet() const {
|
||||
return NeedsSet;
|
||||
}
|
||||
const char *getPCSymbol() const {
|
||||
return PCSymbol;
|
||||
}
|
||||
char getSeparatorChar() const {
|
||||
return SeparatorChar;
|
||||
}
|
||||
const char *getCommentString() const {
|
||||
return CommentString;
|
||||
}
|
||||
const char *getGlobalPrefix() const {
|
||||
return GlobalPrefix;
|
||||
}
|
||||
const char *getPrivateGlobalPrefix() const {
|
||||
return PrivateGlobalPrefix;
|
||||
}
|
||||
/// EHGlobalPrefix - Prefix for EH_frame and the .eh symbols.
|
||||
/// This is normally PrivateGlobalPrefix, but some targets want
|
||||
/// these symbols to be visible.
|
||||
virtual const char *getEHGlobalPrefix() const {
|
||||
return PrivateGlobalPrefix;
|
||||
}
|
||||
const char *getLessPrivateGlobalPrefix() const {
|
||||
return LessPrivateGlobalPrefix;
|
||||
}
|
||||
const char *getJumpTableSpecialLabelPrefix() const {
|
||||
return JumpTableSpecialLabelPrefix;
|
||||
}
|
||||
const char *getGlobalVarAddrPrefix() const {
|
||||
return GlobalVarAddrPrefix;
|
||||
}
|
||||
const char *getGlobalVarAddrSuffix() const {
|
||||
return GlobalVarAddrSuffix;
|
||||
}
|
||||
const char *getFunctionAddrPrefix() const {
|
||||
return FunctionAddrPrefix;
|
||||
}
|
||||
const char *getFunctionAddrSuffix() const {
|
||||
return FunctionAddrSuffix;
|
||||
}
|
||||
const char *getPersonalityPrefix() const {
|
||||
return PersonalityPrefix;
|
||||
}
|
||||
const char *getPersonalitySuffix() const {
|
||||
return PersonalitySuffix;
|
||||
}
|
||||
bool getNeedsIndirectEncoding() const {
|
||||
return NeedsIndirectEncoding;
|
||||
}
|
||||
const char *getInlineAsmStart() const {
|
||||
return InlineAsmStart;
|
||||
}
|
||||
const char *getInlineAsmEnd() const {
|
||||
return InlineAsmEnd;
|
||||
}
|
||||
unsigned getAssemblerDialect() const {
|
||||
return AssemblerDialect;
|
||||
}
|
||||
const char *getStringConstantPrefix() const {
|
||||
return StringConstantPrefix;
|
||||
}
|
||||
bool doesAllowQuotesInName() const {
|
||||
return AllowQuotesInName;
|
||||
}
|
||||
const char *getZeroDirective() const {
|
||||
return ZeroDirective;
|
||||
}
|
||||
const char *getZeroDirectiveSuffix() const {
|
||||
return ZeroDirectiveSuffix;
|
||||
}
|
||||
const char *getAsciiDirective() const {
|
||||
return AsciiDirective;
|
||||
}
|
||||
const char *getAscizDirective() const {
|
||||
return AscizDirective;
|
||||
}
|
||||
const char *getJumpTableDirective() const {
|
||||
return JumpTableDirective;
|
||||
}
|
||||
const char *getAlignDirective() const {
|
||||
return AlignDirective;
|
||||
}
|
||||
bool getAlignmentIsInBytes() const {
|
||||
return AlignmentIsInBytes;
|
||||
}
|
||||
unsigned getTextAlignFillValue() const {
|
||||
return TextAlignFillValue;
|
||||
}
|
||||
const char *getSwitchToSectionDirective() const {
|
||||
return SwitchToSectionDirective;
|
||||
}
|
||||
const char *getTextSectionStartSuffix() const {
|
||||
return TextSectionStartSuffix;
|
||||
}
|
||||
const char *getDataSectionStartSuffix() const {
|
||||
return DataSectionStartSuffix;
|
||||
}
|
||||
const char *getSectionEndDirectiveSuffix() const {
|
||||
return SectionEndDirectiveSuffix;
|
||||
}
|
||||
const char *getConstantPoolSection() const {
|
||||
return ConstantPoolSection;
|
||||
}
|
||||
const char *getJumpTableDataSection() const {
|
||||
return JumpTableDataSection;
|
||||
}
|
||||
const char *getCStringSection() const {
|
||||
return CStringSection;
|
||||
}
|
||||
const Section *getCStringSection_() const {
|
||||
return CStringSection_;
|
||||
}
|
||||
const char *getStaticCtorsSection() const {
|
||||
return StaticCtorsSection;
|
||||
}
|
||||
const char *getStaticDtorsSection() const {
|
||||
return StaticDtorsSection;
|
||||
}
|
||||
const char *getGlobalDirective() const {
|
||||
return GlobalDirective;
|
||||
}
|
||||
const char *getExternDirective() const {
|
||||
return ExternDirective;
|
||||
}
|
||||
const char *getSetDirective() const {
|
||||
return SetDirective;
|
||||
}
|
||||
const char *getLCOMMDirective() const {
|
||||
return LCOMMDirective;
|
||||
}
|
||||
const char *getCOMMDirective() const {
|
||||
return COMMDirective;
|
||||
}
|
||||
bool getCOMMDirectiveTakesAlignment() const {
|
||||
return COMMDirectiveTakesAlignment;
|
||||
}
|
||||
bool hasDotTypeDotSizeDirective() const {
|
||||
return HasDotTypeDotSizeDirective;
|
||||
}
|
||||
bool hasSingleParameterDotFile() const {
|
||||
return HasSingleParameterDotFile;
|
||||
}
|
||||
const char *getUsedDirective() const {
|
||||
return UsedDirective;
|
||||
}
|
||||
const char *getWeakRefDirective() const {
|
||||
return WeakRefDirective;
|
||||
}
|
||||
const char *getWeakDefDirective() const {
|
||||
return WeakDefDirective;
|
||||
}
|
||||
const char *getHiddenDirective() const {
|
||||
return HiddenDirective;
|
||||
}
|
||||
const char *getProtectedDirective() const {
|
||||
return ProtectedDirective;
|
||||
}
|
||||
bool isAbsoluteDebugSectionOffsets() const {
|
||||
return AbsoluteDebugSectionOffsets;
|
||||
}
|
||||
bool isAbsoluteEHSectionOffsets() const {
|
||||
return AbsoluteEHSectionOffsets;
|
||||
}
|
||||
bool hasLEB128() const {
|
||||
return HasLEB128;
|
||||
}
|
||||
bool hasDotLocAndDotFile() const {
|
||||
return HasDotLocAndDotFile;
|
||||
}
|
||||
bool doesSupportDebugInformation() const {
|
||||
return SupportsDebugInformation;
|
||||
}
|
||||
bool doesSupportExceptionHandling() const {
|
||||
return SupportsExceptionHandling;
|
||||
}
|
||||
bool doesDwarfRequireFrameSection() const {
|
||||
return DwarfRequiresFrameSection;
|
||||
}
|
||||
bool doesDwarfUsesInlineInfoSection() const {
|
||||
return DwarfUsesInlineInfoSection;
|
||||
}
|
||||
bool doesRequireNonLocalEHFrameLabel() const {
|
||||
return NonLocalEHFrameLabel;
|
||||
}
|
||||
const char *getGlobalEHDirective() const {
|
||||
return GlobalEHDirective;
|
||||
}
|
||||
bool getSupportsWeakOmittedEHFrame() const {
|
||||
return SupportsWeakOmittedEHFrame;
|
||||
}
|
||||
const char *getDwarfSectionOffsetDirective() const {
|
||||
return DwarfSectionOffsetDirective;
|
||||
}
|
||||
const char *getDwarfAbbrevSection() const {
|
||||
return DwarfAbbrevSection;
|
||||
}
|
||||
const char *getDwarfInfoSection() const {
|
||||
return DwarfInfoSection;
|
||||
}
|
||||
const char *getDwarfLineSection() const {
|
||||
return DwarfLineSection;
|
||||
}
|
||||
const char *getDwarfFrameSection() const {
|
||||
return DwarfFrameSection;
|
||||
}
|
||||
const char *getDwarfPubNamesSection() const {
|
||||
return DwarfPubNamesSection;
|
||||
}
|
||||
const char *getDwarfPubTypesSection() const {
|
||||
return DwarfPubTypesSection;
|
||||
}
|
||||
const char *getDwarfDebugInlineSection() const {
|
||||
return DwarfDebugInlineSection;
|
||||
}
|
||||
const char *getDwarfStrSection() const {
|
||||
return DwarfStrSection;
|
||||
}
|
||||
const char *getDwarfLocSection() const {
|
||||
return DwarfLocSection;
|
||||
}
|
||||
const char *getDwarfARangesSection() const {
|
||||
return DwarfARangesSection;
|
||||
}
|
||||
const char *getDwarfRangesSection() const {
|
||||
return DwarfRangesSection;
|
||||
}
|
||||
const char *getDwarfMacroInfoSection() const {
|
||||
return DwarfMacroInfoSection;
|
||||
}
|
||||
const char *getDwarfEHFrameSection() const {
|
||||
return DwarfEHFrameSection;
|
||||
}
|
||||
const char *getDwarfExceptionSection() const {
|
||||
return DwarfExceptionSection;
|
||||
}
|
||||
const char *const *getAsmCBE() const {
|
||||
return AsmTransCBE;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -1,97 +0,0 @@
|
||||
//===-- Target/TargetMachineRegistry.h - Target Registration ----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file exposes two classes: the TargetMachineRegistry class, which allows
|
||||
// tools to inspect all of registered targets, and the RegisterTarget class,
|
||||
// which TargetMachine implementations should use to register themselves with
|
||||
// the system.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TARGET_TARGETMACHINEREGISTRY_H
|
||||
#define LLVM_TARGET_TARGETMACHINEREGISTRY_H
|
||||
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Support/Registry.h"
|
||||
|
||||
namespace llvm {
|
||||
class Module;
|
||||
class TargetMachine;
|
||||
|
||||
struct TargetMachineRegistryEntry {
|
||||
const char *Name;
|
||||
const char *ShortDesc;
|
||||
TargetMachine *(*CtorFn)(const Module &, const std::string &);
|
||||
unsigned (*ModuleMatchQualityFn)(const Module &M);
|
||||
unsigned (*JITMatchQualityFn)();
|
||||
|
||||
public:
|
||||
TargetMachineRegistryEntry(const char *N, const char *SD,
|
||||
TargetMachine *(*CF)(const Module &, const std::string &),
|
||||
unsigned (*MMF)(const Module &M),
|
||||
unsigned (*JMF)())
|
||||
: Name(N), ShortDesc(SD), CtorFn(CF), ModuleMatchQualityFn(MMF),
|
||||
JITMatchQualityFn(JMF) {}
|
||||
};
|
||||
|
||||
template<>
|
||||
class RegistryTraits<TargetMachine> {
|
||||
public:
|
||||
typedef TargetMachineRegistryEntry entry;
|
||||
|
||||
static const char *nameof(const entry &Entry) { return Entry.Name; }
|
||||
static const char *descof(const entry &Entry) { return Entry.ShortDesc; }
|
||||
};
|
||||
|
||||
struct TargetMachineRegistry : public Registry<TargetMachine> {
|
||||
/// getClosestStaticTargetForModule - Given an LLVM module, pick the best
|
||||
/// target that is compatible with the module. If no close target can be
|
||||
/// found, this returns null and sets the Error string to a reason.
|
||||
static const entry *getClosestStaticTargetForModule(const Module &M,
|
||||
std::string &Error);
|
||||
|
||||
/// getClosestTargetForJIT - Pick the best target that is compatible with
|
||||
/// the current host. If no close target can be found, this returns null
|
||||
/// and sets the Error string to a reason.
|
||||
static const entry *getClosestTargetForJIT(std::string &Error);
|
||||
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// RegisterTarget - This class is used to make targets automatically register
|
||||
/// themselves with the tool they are linked. Targets should define an
|
||||
/// instance of this and implement the static methods described in the
|
||||
/// TargetMachine comments.
|
||||
/// The type 'TargetMachineImpl' should provide a constructor with two
|
||||
/// parameters:
|
||||
/// - const Module& M: the module that is being compiled:
|
||||
/// - const std::string& FS: target-specific string describing target
|
||||
/// flavour.
|
||||
|
||||
template<class TargetMachineImpl>
|
||||
struct RegisterTarget {
|
||||
RegisterTarget(const char *Name, const char *ShortDesc)
|
||||
: Entry(Name, ShortDesc, &Allocator,
|
||||
&TargetMachineImpl::getModuleMatchQuality,
|
||||
&TargetMachineImpl::getJITMatchQuality),
|
||||
Node(Entry)
|
||||
{}
|
||||
|
||||
private:
|
||||
TargetMachineRegistry::entry Entry;
|
||||
TargetMachineRegistry::node Node;
|
||||
|
||||
static TargetMachine *Allocator(const Module &M, const std::string &FS) {
|
||||
return new TargetMachineImpl(M, FS);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -1,155 +0,0 @@
|
||||
//===- InlineCost.cpp - Cost analysis for inliner ---------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements heuristics for inlining decisions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TRANSFORMS_UTILS_INLINECOST_H
|
||||
#define LLVM_TRANSFORMS_UTILS_INLINECOST_H
|
||||
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Value;
|
||||
class Function;
|
||||
class CallSite;
|
||||
|
||||
/// InlineCost - Represent the cost of inlining a function. This
|
||||
/// supports special values for functions which should "always" or
|
||||
/// "never" be inlined. Otherwise, the cost represents a unitless
|
||||
/// amount; smaller values increase the likelyhood of the function
|
||||
/// being inlined.
|
||||
class InlineCost {
|
||||
enum Kind {
|
||||
Value,
|
||||
Always,
|
||||
Never
|
||||
};
|
||||
|
||||
// This is a do-it-yourself implementation of
|
||||
// int Cost : 30;
|
||||
// unsigned Type : 2;
|
||||
// We used to use bitfields, but they were sometimes miscompiled (PR3822).
|
||||
enum { TYPE_BITS = 2 };
|
||||
enum { COST_BITS = unsigned(sizeof(unsigned)) * CHAR_BIT - TYPE_BITS };
|
||||
unsigned TypedCost; // int Cost : COST_BITS; unsigned Type : TYPE_BITS;
|
||||
|
||||
Kind getType() const {
|
||||
return Kind(TypedCost >> COST_BITS);
|
||||
}
|
||||
|
||||
int getCost() const {
|
||||
// Sign-extend the bottom COST_BITS bits.
|
||||
return (int(TypedCost << TYPE_BITS)) >> TYPE_BITS;
|
||||
}
|
||||
|
||||
InlineCost(int C, int T) {
|
||||
TypedCost = (unsigned(C << TYPE_BITS) >> TYPE_BITS) | (T << COST_BITS);
|
||||
assert(getCost() == C && "Cost exceeds InlineCost precision");
|
||||
}
|
||||
public:
|
||||
static InlineCost get(int Cost) { return InlineCost(Cost, Value); }
|
||||
static InlineCost getAlways() { return InlineCost(0, Always); }
|
||||
static InlineCost getNever() { return InlineCost(0, Never); }
|
||||
|
||||
bool isVariable() const { return getType() == Value; }
|
||||
bool isAlways() const { return getType() == Always; }
|
||||
bool isNever() const { return getType() == Never; }
|
||||
|
||||
/// getValue() - Return a "variable" inline cost's amount. It is
|
||||
/// an error to call this on an "always" or "never" InlineCost.
|
||||
int getValue() const {
|
||||
assert(getType() == Value && "Invalid access of InlineCost");
|
||||
return getCost();
|
||||
}
|
||||
};
|
||||
|
||||
/// InlineCostAnalyzer - Cost analyzer used by inliner.
|
||||
class InlineCostAnalyzer {
|
||||
struct ArgInfo {
|
||||
public:
|
||||
unsigned ConstantWeight;
|
||||
unsigned AllocaWeight;
|
||||
|
||||
ArgInfo(unsigned CWeight, unsigned AWeight)
|
||||
: ConstantWeight(CWeight), AllocaWeight(AWeight) {}
|
||||
};
|
||||
|
||||
// FunctionInfo - For each function, calculate the size of it in blocks and
|
||||
// instructions.
|
||||
struct FunctionInfo {
|
||||
/// NeverInline - True if this callee should never be inlined into a
|
||||
/// caller.
|
||||
bool NeverInline;
|
||||
|
||||
/// usesDynamicAlloca - True if this function calls alloca (in the C sense).
|
||||
bool usesDynamicAlloca;
|
||||
|
||||
/// NumInsts, NumBlocks - Keep track of how large each function is, which
|
||||
/// is used to estimate the code size cost of inlining it.
|
||||
unsigned NumInsts, NumBlocks;
|
||||
|
||||
/// NumVectorInsts - Keep track of how many instructions produce vector
|
||||
/// values. The inliner is being more aggressive with inlining vector
|
||||
/// kernels.
|
||||
unsigned NumVectorInsts;
|
||||
|
||||
/// ArgumentWeights - Each formal argument of the function is inspected to
|
||||
/// see if it is used in any contexts where making it a constant or alloca
|
||||
/// would reduce the code size. If so, we add some value to the argument
|
||||
/// entry here.
|
||||
std::vector<ArgInfo> ArgumentWeights;
|
||||
|
||||
FunctionInfo() : NeverInline(false), usesDynamicAlloca(false), NumInsts(0),
|
||||
NumBlocks(0), NumVectorInsts(0) {}
|
||||
|
||||
/// analyzeFunction - Fill in the current structure with information
|
||||
/// gleaned from the specified function.
|
||||
void analyzeFunction(Function *F);
|
||||
|
||||
/// CountCodeReductionForConstant - Figure out an approximation for how
|
||||
/// many instructions will be constant folded if the specified value is
|
||||
/// constant.
|
||||
unsigned CountCodeReductionForConstant(Value *V);
|
||||
|
||||
/// CountCodeReductionForAlloca - Figure out an approximation of how much
|
||||
/// smaller the function will be if it is inlined into a context where an
|
||||
/// argument becomes an alloca.
|
||||
///
|
||||
unsigned CountCodeReductionForAlloca(Value *V);
|
||||
};
|
||||
|
||||
std::map<const Function *, FunctionInfo> CachedFunctionInfo;
|
||||
|
||||
public:
|
||||
|
||||
/// getInlineCost - The heuristic used to determine if we should inline the
|
||||
/// function call or not.
|
||||
///
|
||||
InlineCost getInlineCost(CallSite CS,
|
||||
SmallPtrSet<const Function *, 16> &NeverInline);
|
||||
|
||||
/// getInlineFudgeFactor - Return a > 1.0 factor if the inliner should use a
|
||||
/// higher threshold to determine if the function call should be inlined.
|
||||
float getInlineFudgeFactor(CallSite CS);
|
||||
|
||||
/// resetCachedFunctionInfo - erase any cached cost info for this function.
|
||||
void resetCachedCostInfo(Function* Caller) {
|
||||
CachedFunctionInfo[Caller].NumBlocks = 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -1,291 +0,0 @@
|
||||
//===- LoopVR.cpp - Value Range analysis driven by loop information -------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// FIXME: What does this do?
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define DEBUG_TYPE "loopvr"
|
||||
#include "llvm/Analysis/LoopVR.h"
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/Instructions.h"
|
||||
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
|
||||
#include "llvm/Assembly/Writer.h"
|
||||
#include "llvm/Support/CFG.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
using namespace llvm;
|
||||
|
||||
char LoopVR::ID = 0;
|
||||
static RegisterPass<LoopVR> X("loopvr", "Loop Value Ranges", false, true);
|
||||
|
||||
/// getRange - determine the range for a particular SCEV within a given Loop
|
||||
ConstantRange LoopVR::getRange(const SCEV* S, Loop *L, ScalarEvolution &SE) {
|
||||
const SCEV* T = SE.getBackedgeTakenCount(L);
|
||||
if (isa<SCEVCouldNotCompute>(T))
|
||||
return ConstantRange(cast<IntegerType>(S->getType())->getBitWidth(), true);
|
||||
|
||||
T = SE.getTruncateOrZeroExtend(T, S->getType());
|
||||
return getRange(S, T, SE);
|
||||
}
|
||||
|
||||
/// getRange - determine the range for a particular SCEV with a given trip count
|
||||
ConstantRange LoopVR::getRange(const SCEV* S, const SCEV* T, ScalarEvolution &SE){
|
||||
|
||||
if (const SCEVConstant *C = dyn_cast<SCEVConstant>(S))
|
||||
return ConstantRange(C->getValue()->getValue());
|
||||
|
||||
ConstantRange FullSet(cast<IntegerType>(S->getType())->getBitWidth(), true);
|
||||
|
||||
// {x,+,y,+,...z}. We detect overflow by checking the size of the set after
|
||||
// summing the upper and lower.
|
||||
if (const SCEVAddExpr *Add = dyn_cast<SCEVAddExpr>(S)) {
|
||||
ConstantRange X = getRange(Add->getOperand(0), T, SE);
|
||||
if (X.isFullSet()) return FullSet;
|
||||
for (unsigned i = 1, e = Add->getNumOperands(); i != e; ++i) {
|
||||
ConstantRange Y = getRange(Add->getOperand(i), T, SE);
|
||||
if (Y.isFullSet()) return FullSet;
|
||||
|
||||
APInt Spread_X = X.getSetSize(), Spread_Y = Y.getSetSize();
|
||||
APInt NewLower = X.getLower() + Y.getLower();
|
||||
APInt NewUpper = X.getUpper() + Y.getUpper() - 1;
|
||||
if (NewLower == NewUpper)
|
||||
return FullSet;
|
||||
|
||||
X = ConstantRange(NewLower, NewUpper);
|
||||
if (X.getSetSize().ult(Spread_X) || X.getSetSize().ult(Spread_Y))
|
||||
return FullSet; // we've wrapped, therefore, full set.
|
||||
}
|
||||
return X;
|
||||
}
|
||||
|
||||
// {x,*,y,*,...,z}. In order to detect overflow, we use k*bitwidth where
|
||||
// k is the number of terms being multiplied.
|
||||
if (const SCEVMulExpr *Mul = dyn_cast<SCEVMulExpr>(S)) {
|
||||
ConstantRange X = getRange(Mul->getOperand(0), T, SE);
|
||||
if (X.isFullSet()) return FullSet;
|
||||
|
||||
const IntegerType *Ty = IntegerType::get(X.getBitWidth());
|
||||
const IntegerType *ExTy = IntegerType::get(X.getBitWidth() *
|
||||
Mul->getNumOperands());
|
||||
ConstantRange XExt = X.zeroExtend(ExTy->getBitWidth());
|
||||
|
||||
for (unsigned i = 1, e = Mul->getNumOperands(); i != e; ++i) {
|
||||
ConstantRange Y = getRange(Mul->getOperand(i), T, SE);
|
||||
if (Y.isFullSet()) return FullSet;
|
||||
|
||||
ConstantRange YExt = Y.zeroExtend(ExTy->getBitWidth());
|
||||
XExt = ConstantRange(XExt.getLower() * YExt.getLower(),
|
||||
((XExt.getUpper()-1) * (YExt.getUpper()-1)) + 1);
|
||||
}
|
||||
return XExt.truncate(Ty->getBitWidth());
|
||||
}
|
||||
|
||||
// X smax Y smax ... Z is: range(smax(X_smin, Y_smin, ..., Z_smin),
|
||||
// smax(X_smax, Y_smax, ..., Z_smax))
|
||||
// It doesn't matter if one of the SCEVs has FullSet because we're taking
|
||||
// a maximum of the minimums across all of them.
|
||||
if (const SCEVSMaxExpr *SMax = dyn_cast<SCEVSMaxExpr>(S)) {
|
||||
ConstantRange X = getRange(SMax->getOperand(0), T, SE);
|
||||
if (X.isFullSet()) return FullSet;
|
||||
|
||||
APInt smin = X.getSignedMin(), smax = X.getSignedMax();
|
||||
for (unsigned i = 1, e = SMax->getNumOperands(); i != e; ++i) {
|
||||
ConstantRange Y = getRange(SMax->getOperand(i), T, SE);
|
||||
smin = APIntOps::smax(smin, Y.getSignedMin());
|
||||
smax = APIntOps::smax(smax, Y.getSignedMax());
|
||||
}
|
||||
if (smax + 1 == smin) return FullSet;
|
||||
return ConstantRange(smin, smax + 1);
|
||||
}
|
||||
|
||||
// X umax Y umax ... Z is: range(umax(X_umin, Y_umin, ..., Z_umin),
|
||||
// umax(X_umax, Y_umax, ..., Z_umax))
|
||||
// It doesn't matter if one of the SCEVs has FullSet because we're taking
|
||||
// a maximum of the minimums across all of them.
|
||||
if (const SCEVUMaxExpr *UMax = dyn_cast<SCEVUMaxExpr>(S)) {
|
||||
ConstantRange X = getRange(UMax->getOperand(0), T, SE);
|
||||
if (X.isFullSet()) return FullSet;
|
||||
|
||||
APInt umin = X.getUnsignedMin(), umax = X.getUnsignedMax();
|
||||
for (unsigned i = 1, e = UMax->getNumOperands(); i != e; ++i) {
|
||||
ConstantRange Y = getRange(UMax->getOperand(i), T, SE);
|
||||
umin = APIntOps::umax(umin, Y.getUnsignedMin());
|
||||
umax = APIntOps::umax(umax, Y.getUnsignedMax());
|
||||
}
|
||||
if (umax + 1 == umin) return FullSet;
|
||||
return ConstantRange(umin, umax + 1);
|
||||
}
|
||||
|
||||
// L udiv R. Luckily, there's only ever 2 sides to a udiv.
|
||||
if (const SCEVUDivExpr *UDiv = dyn_cast<SCEVUDivExpr>(S)) {
|
||||
ConstantRange L = getRange(UDiv->getLHS(), T, SE);
|
||||
ConstantRange R = getRange(UDiv->getRHS(), T, SE);
|
||||
if (L.isFullSet() && R.isFullSet()) return FullSet;
|
||||
|
||||
if (R.getUnsignedMax() == 0) {
|
||||
// RHS must be single-element zero. Return an empty set.
|
||||
return ConstantRange(R.getBitWidth(), false);
|
||||
}
|
||||
|
||||
APInt Lower = L.getUnsignedMin().udiv(R.getUnsignedMax());
|
||||
|
||||
APInt Upper;
|
||||
|
||||
if (R.getUnsignedMin() == 0) {
|
||||
// Just because it contains zero, doesn't mean it will also contain one.
|
||||
// Use maximalIntersectWith to get the right behaviour.
|
||||
ConstantRange NotZero(APInt(L.getBitWidth(), 1),
|
||||
APInt::getNullValue(L.getBitWidth()));
|
||||
R = R.maximalIntersectWith(NotZero);
|
||||
}
|
||||
|
||||
// But, the maximal intersection might still include zero. If it does, then
|
||||
// we know it also included one.
|
||||
if (R.contains(APInt::getNullValue(L.getBitWidth())))
|
||||
Upper = L.getUnsignedMax();
|
||||
else
|
||||
Upper = L.getUnsignedMax().udiv(R.getUnsignedMin());
|
||||
|
||||
return ConstantRange(Lower, Upper);
|
||||
}
|
||||
|
||||
// ConstantRange already implements the cast operators.
|
||||
|
||||
if (const SCEVZeroExtendExpr *ZExt = dyn_cast<SCEVZeroExtendExpr>(S)) {
|
||||
T = SE.getTruncateOrZeroExtend(T, ZExt->getOperand()->getType());
|
||||
ConstantRange X = getRange(ZExt->getOperand(), T, SE);
|
||||
return X.zeroExtend(cast<IntegerType>(ZExt->getType())->getBitWidth());
|
||||
}
|
||||
|
||||
if (const SCEVSignExtendExpr *SExt = dyn_cast<SCEVSignExtendExpr>(S)) {
|
||||
T = SE.getTruncateOrZeroExtend(T, SExt->getOperand()->getType());
|
||||
ConstantRange X = getRange(SExt->getOperand(), T, SE);
|
||||
return X.signExtend(cast<IntegerType>(SExt->getType())->getBitWidth());
|
||||
}
|
||||
|
||||
if (const SCEVTruncateExpr *Trunc = dyn_cast<SCEVTruncateExpr>(S)) {
|
||||
T = SE.getTruncateOrZeroExtend(T, Trunc->getOperand()->getType());
|
||||
ConstantRange X = getRange(Trunc->getOperand(), T, SE);
|
||||
if (X.isFullSet()) return FullSet;
|
||||
return X.truncate(cast<IntegerType>(Trunc->getType())->getBitWidth());
|
||||
}
|
||||
|
||||
if (const SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(S)) {
|
||||
const SCEVConstant *Trip = dyn_cast<SCEVConstant>(T);
|
||||
if (!Trip) return FullSet;
|
||||
|
||||
if (AddRec->isAffine()) {
|
||||
const SCEV* StartHandle = AddRec->getStart();
|
||||
const SCEV* StepHandle = AddRec->getOperand(1);
|
||||
|
||||
const SCEVConstant *Step = dyn_cast<SCEVConstant>(StepHandle);
|
||||
if (!Step) return FullSet;
|
||||
|
||||
uint32_t ExWidth = 2 * Trip->getValue()->getBitWidth();
|
||||
APInt TripExt = Trip->getValue()->getValue(); TripExt.zext(ExWidth);
|
||||
APInt StepExt = Step->getValue()->getValue(); StepExt.zext(ExWidth);
|
||||
if ((TripExt * StepExt).ugt(APInt::getLowBitsSet(ExWidth, ExWidth >> 1)))
|
||||
return FullSet;
|
||||
|
||||
const SCEV* EndHandle = SE.getAddExpr(StartHandle,
|
||||
SE.getMulExpr(T, StepHandle));
|
||||
const SCEVConstant *Start = dyn_cast<SCEVConstant>(StartHandle);
|
||||
const SCEVConstant *End = dyn_cast<SCEVConstant>(EndHandle);
|
||||
if (!Start || !End) return FullSet;
|
||||
|
||||
const APInt &StartInt = Start->getValue()->getValue();
|
||||
const APInt &EndInt = End->getValue()->getValue();
|
||||
const APInt &StepInt = Step->getValue()->getValue();
|
||||
|
||||
if (StepInt.isNegative()) {
|
||||
if (EndInt == StartInt + 1) return FullSet;
|
||||
return ConstantRange(EndInt, StartInt + 1);
|
||||
} else {
|
||||
if (StartInt == EndInt + 1) return FullSet;
|
||||
return ConstantRange(StartInt, EndInt + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: non-affine addrec, udiv, SCEVUnknown (narrowed from elsewhere)?
|
||||
|
||||
return FullSet;
|
||||
}
|
||||
|
||||
bool LoopVR::runOnFunction(Function &F) { Map.clear(); return false; }
|
||||
|
||||
void LoopVR::print(std::ostream &os, const Module *) const {
|
||||
raw_os_ostream OS(os);
|
||||
for (std::map<Value *, ConstantRange *>::const_iterator I = Map.begin(),
|
||||
E = Map.end(); I != E; ++I) {
|
||||
OS << *I->first << ": " << *I->second << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
void LoopVR::releaseMemory() {
|
||||
for (std::map<Value *, ConstantRange *>::iterator I = Map.begin(),
|
||||
E = Map.end(); I != E; ++I) {
|
||||
delete I->second;
|
||||
}
|
||||
|
||||
Map.clear();
|
||||
}
|
||||
|
||||
ConstantRange LoopVR::compute(Value *V) {
|
||||
if (ConstantInt *CI = dyn_cast<ConstantInt>(V))
|
||||
return ConstantRange(CI->getValue());
|
||||
|
||||
Instruction *I = dyn_cast<Instruction>(V);
|
||||
if (!I)
|
||||
return ConstantRange(cast<IntegerType>(V->getType())->getBitWidth(), false);
|
||||
|
||||
LoopInfo &LI = getAnalysis<LoopInfo>();
|
||||
|
||||
Loop *L = LI.getLoopFor(I->getParent());
|
||||
if (!L || L->isLoopInvariant(I))
|
||||
return ConstantRange(cast<IntegerType>(V->getType())->getBitWidth(), false);
|
||||
|
||||
ScalarEvolution &SE = getAnalysis<ScalarEvolution>();
|
||||
|
||||
const SCEV* S = SE.getSCEV(I);
|
||||
if (isa<SCEVUnknown>(S) || isa<SCEVCouldNotCompute>(S))
|
||||
return ConstantRange(cast<IntegerType>(V->getType())->getBitWidth(), false);
|
||||
|
||||
return ConstantRange(getRange(S, L, SE));
|
||||
}
|
||||
|
||||
ConstantRange LoopVR::get(Value *V) {
|
||||
std::map<Value *, ConstantRange *>::iterator I = Map.find(V);
|
||||
if (I == Map.end()) {
|
||||
ConstantRange *CR = new ConstantRange(compute(V));
|
||||
Map[V] = CR;
|
||||
return *CR;
|
||||
}
|
||||
|
||||
return *I->second;
|
||||
}
|
||||
|
||||
void LoopVR::remove(Value *V) {
|
||||
std::map<Value *, ConstantRange *>::iterator I = Map.find(V);
|
||||
if (I != Map.end()) {
|
||||
delete I->second;
|
||||
Map.erase(I);
|
||||
}
|
||||
}
|
||||
|
||||
void LoopVR::narrow(Value *V, const ConstantRange &CR) {
|
||||
if (CR.isFullSet()) return;
|
||||
|
||||
std::map<Value *, ConstantRange *>::iterator I = Map.find(V);
|
||||
if (I == Map.end())
|
||||
Map[V] = new ConstantRange(CR);
|
||||
else
|
||||
Map[V] = new ConstantRange(Map[V]->maximalIntersectWith(CR));
|
||||
}
|
@ -1,167 +0,0 @@
|
||||
//===- LazyLiveness.cpp - Lazy, CFG-invariant liveness information --------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This pass implements a lazy liveness analysis as per "Fast Liveness Checking
|
||||
// for SSA-form Programs," by Boissinot, et al.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define DEBUG_TYPE "lazyliveness"
|
||||
#include "llvm/CodeGen/LazyLiveness.h"
|
||||
#include "llvm/CodeGen/MachineDominators.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/CodeGen/Passes.h"
|
||||
#include "llvm/ADT/DepthFirstIterator.h"
|
||||
#include "llvm/ADT/PostOrderIterator.h"
|
||||
using namespace llvm;
|
||||
|
||||
char LazyLiveness::ID = 0;
|
||||
static RegisterPass<LazyLiveness> X("lazy-liveness", "Lazy Liveness Analysis");
|
||||
|
||||
void LazyLiveness::computeBackedgeChain(MachineFunction& mf,
|
||||
MachineBasicBlock* MBB) {
|
||||
SparseBitVector<128> tmp = rv[MBB];
|
||||
tmp.set(preorder[MBB]);
|
||||
tmp &= backedge_source;
|
||||
calculated.set(preorder[MBB]);
|
||||
|
||||
for (SparseBitVector<128>::iterator I = tmp.begin(); I != tmp.end(); ++I) {
|
||||
assert(rev_preorder.size() > *I && "Unknown block!");
|
||||
|
||||
MachineBasicBlock* SrcMBB = rev_preorder[*I];
|
||||
|
||||
for (MachineBasicBlock::succ_iterator SI = SrcMBB->succ_begin(),
|
||||
SE = SrcMBB->succ_end(); SI != SE; ++SI) {
|
||||
MachineBasicBlock* TgtMBB = *SI;
|
||||
|
||||
if (backedges.count(std::make_pair(SrcMBB, TgtMBB)) &&
|
||||
!rv[MBB].test(preorder[TgtMBB])) {
|
||||
if (!calculated.test(preorder[TgtMBB]))
|
||||
computeBackedgeChain(mf, TgtMBB);
|
||||
|
||||
tv[MBB].set(preorder[TgtMBB]);
|
||||
SparseBitVector<128> right = tv[TgtMBB];
|
||||
tv[MBB] |= right;
|
||||
}
|
||||
}
|
||||
|
||||
tv[MBB].reset(preorder[MBB]);
|
||||
}
|
||||
}
|
||||
|
||||
bool LazyLiveness::runOnMachineFunction(MachineFunction &mf) {
|
||||
rv.clear();
|
||||
tv.clear();
|
||||
backedges.clear();
|
||||
backedge_source.clear();
|
||||
backedge_target.clear();
|
||||
calculated.clear();
|
||||
preorder.clear();
|
||||
rev_preorder.clear();
|
||||
|
||||
rv.resize(mf.size());
|
||||
tv.resize(mf.size());
|
||||
preorder.resize(mf.size());
|
||||
rev_preorder.reserve(mf.size());
|
||||
|
||||
MRI = &mf.getRegInfo();
|
||||
MachineDominatorTree& MDT = getAnalysis<MachineDominatorTree>();
|
||||
|
||||
// Step 0: Compute preorder numbering for all MBBs.
|
||||
unsigned num = 0;
|
||||
for (df_iterator<MachineDomTreeNode*> DI = df_begin(MDT.getRootNode()),
|
||||
DE = df_end(MDT.getRootNode()); DI != DE; ++DI) {
|
||||
preorder[(*DI)->getBlock()] = num++;
|
||||
rev_preorder.push_back((*DI)->getBlock());
|
||||
}
|
||||
|
||||
// Step 1: Compute the transitive closure of the CFG, ignoring backedges.
|
||||
for (po_iterator<MachineBasicBlock*> POI = po_begin(&*mf.begin()),
|
||||
POE = po_end(&*mf.begin()); POI != POE; ++POI) {
|
||||
MachineBasicBlock* MBB = *POI;
|
||||
SparseBitVector<128>& entry = rv[MBB];
|
||||
entry.set(preorder[MBB]);
|
||||
|
||||
for (MachineBasicBlock::succ_iterator SI = MBB->succ_begin(),
|
||||
SE = MBB->succ_end(); SI != SE; ++SI) {
|
||||
DenseMap<MachineBasicBlock*, SparseBitVector<128> >::iterator SII =
|
||||
rv.find(*SI);
|
||||
|
||||
// Because we're iterating in postorder, any successor that does not yet
|
||||
// have an rv entry must be on a backedge.
|
||||
if (SII != rv.end()) {
|
||||
entry |= SII->second;
|
||||
} else {
|
||||
backedges.insert(std::make_pair(MBB, *SI));
|
||||
backedge_source.set(preorder[MBB]);
|
||||
backedge_target.set(preorder[*SI]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (SparseBitVector<128>::iterator I = backedge_source.begin();
|
||||
I != backedge_source.end(); ++I)
|
||||
computeBackedgeChain(mf, rev_preorder[*I]);
|
||||
|
||||
for (po_iterator<MachineBasicBlock*> POI = po_begin(&*mf.begin()),
|
||||
POE = po_end(&*mf.begin()); POI != POE; ++POI)
|
||||
if (!backedge_target.test(preorder[*POI]))
|
||||
for (MachineBasicBlock::succ_iterator SI = (*POI)->succ_begin(),
|
||||
SE = (*POI)->succ_end(); SI != SE; ++SI)
|
||||
if (!backedges.count(std::make_pair(*POI, *SI)) && tv.count(*SI)) {
|
||||
SparseBitVector<128> right = tv[*SI];
|
||||
tv[*POI] |= right;
|
||||
}
|
||||
|
||||
for (po_iterator<MachineBasicBlock*> POI = po_begin(&*mf.begin()),
|
||||
POE = po_end(&*mf.begin()); POI != POE; ++POI)
|
||||
tv[*POI].set(preorder[*POI]);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LazyLiveness::vregLiveIntoMBB(unsigned vreg, MachineBasicBlock* MBB) {
|
||||
MachineDominatorTree& MDT = getAnalysis<MachineDominatorTree>();
|
||||
|
||||
MachineBasicBlock* DefMBB = MRI->def_begin(vreg)->getParent();
|
||||
unsigned def = preorder[DefMBB];
|
||||
unsigned max_dom = 0;
|
||||
for (df_iterator<MachineDomTreeNode*> DI = df_begin(MDT[DefMBB]),
|
||||
DE = df_end(MDT[DefMBB]); DI != DE; ++DI) {
|
||||
if (preorder[DI->getBlock()] > max_dom) {
|
||||
max_dom = preorder[(*DI)->getBlock()];
|
||||
}
|
||||
}
|
||||
|
||||
if (preorder[MBB] <= def || max_dom < preorder[MBB])
|
||||
return false;
|
||||
|
||||
SparseBitVector<128>::iterator I = tv[MBB].begin();
|
||||
while (I != tv[MBB].end() && *I <= def) ++I;
|
||||
while (I != tv[MBB].end() && *I < max_dom) {
|
||||
for (MachineRegisterInfo::use_iterator UI = MRI->use_begin(vreg),
|
||||
UE = MachineRegisterInfo::use_end(); UI != UE; ++UI) {
|
||||
MachineBasicBlock* UseMBB = UI->getParent();
|
||||
if (rv[rev_preorder[*I]].test(preorder[UseMBB]))
|
||||
return true;
|
||||
|
||||
unsigned t_dom = 0;
|
||||
for (df_iterator<MachineDomTreeNode*> DI =
|
||||
df_begin(MDT[rev_preorder[*I]]), DE = df_end(MDT[rev_preorder[*I]]);
|
||||
DI != DE; ++DI)
|
||||
if (preorder[DI->getBlock()] > t_dom) {
|
||||
max_dom = preorder[(*DI)->getBlock()];
|
||||
}
|
||||
I = tv[MBB].begin();
|
||||
while (I != tv[MBB].end() && *I < t_dom) ++I;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
1395
lib/CodeGen/PBQP.cpp
1395
lib/CodeGen/PBQP.cpp
File diff suppressed because it is too large
Load Diff
@ -1,284 +0,0 @@
|
||||
//===---------------- PBQP.cpp --------- PBQP Solver ------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Developed by: Bernhard Scholz
|
||||
// The University of Sydney
|
||||
// http://www.it.usyd.edu.au/~scholz
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// TODO:
|
||||
//
|
||||
// * Default to null costs on vector initialisation?
|
||||
// * C++-ify the rest of the solver.
|
||||
|
||||
#ifndef LLVM_CODEGEN_PBQPSOLVER_H
|
||||
#define LLVM_CODEGEN_PBQPSOLVER_H
|
||||
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
//! \brief Floating point type to use in PBQP solver.
|
||||
typedef double PBQPNum;
|
||||
|
||||
//! \brief PBQP Vector class.
|
||||
class PBQPVector {
|
||||
public:
|
||||
|
||||
//! \brief Construct a PBQP vector of the given size.
|
||||
explicit PBQPVector(unsigned length) :
|
||||
length(length), data(new PBQPNum[length]) {
|
||||
std::fill(data, data + length, 0);
|
||||
}
|
||||
|
||||
//! \brief Copy construct a PBQP vector.
|
||||
PBQPVector(const PBQPVector &v) :
|
||||
length(v.length), data(new PBQPNum[length]) {
|
||||
std::copy(v.data, v.data + length, data);
|
||||
}
|
||||
|
||||
~PBQPVector() { delete[] data; }
|
||||
|
||||
//! \brief Assignment operator.
|
||||
PBQPVector& operator=(const PBQPVector &v) {
|
||||
delete[] data;
|
||||
length = v.length;
|
||||
data = new PBQPNum[length];
|
||||
std::copy(v.data, v.data + length, data);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \brief Return the length of the vector
|
||||
unsigned getLength() const throw () {
|
||||
return length;
|
||||
}
|
||||
|
||||
//! \brief Element access.
|
||||
PBQPNum& operator[](unsigned index) {
|
||||
assert(index < length && "PBQPVector element access out of bounds.");
|
||||
return data[index];
|
||||
}
|
||||
|
||||
//! \brief Const element access.
|
||||
const PBQPNum& operator[](unsigned index) const {
|
||||
assert(index < length && "PBQPVector element access out of bounds.");
|
||||
return data[index];
|
||||
}
|
||||
|
||||
//! \brief Add another vector to this one.
|
||||
PBQPVector& operator+=(const PBQPVector &v) {
|
||||
assert(length == v.length && "PBQPVector length mismatch.");
|
||||
std::transform(data, data + length, v.data, data, std::plus<PBQPNum>());
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \brief Subtract another vector from this one.
|
||||
PBQPVector& operator-=(const PBQPVector &v) {
|
||||
assert(length == v.length && "PBQPVector length mismatch.");
|
||||
std::transform(data, data + length, v.data, data, std::minus<PBQPNum>());
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \brief Returns the index of the minimum value in this vector
|
||||
unsigned minIndex() const {
|
||||
return std::min_element(data, data + length) - data;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned length;
|
||||
PBQPNum *data;
|
||||
};
|
||||
|
||||
|
||||
//! \brief PBQP Matrix class
|
||||
class PBQPMatrix {
|
||||
public:
|
||||
|
||||
//! \brief Construct a PBQP Matrix with the given dimensions.
|
||||
PBQPMatrix(unsigned rows, unsigned cols) :
|
||||
rows(rows), cols(cols), data(new PBQPNum[rows * cols]) {
|
||||
std::fill(data, data + (rows * cols), 0);
|
||||
}
|
||||
|
||||
//! \brief Copy construct a PBQP matrix.
|
||||
PBQPMatrix(const PBQPMatrix &m) :
|
||||
rows(m.rows), cols(m.cols), data(new PBQPNum[rows * cols]) {
|
||||
std::copy(m.data, m.data + (rows * cols), data);
|
||||
}
|
||||
|
||||
~PBQPMatrix() { delete[] data; }
|
||||
|
||||
//! \brief Assignment operator.
|
||||
PBQPMatrix& operator=(const PBQPMatrix &m) {
|
||||
delete[] data;
|
||||
rows = m.rows; cols = m.cols;
|
||||
data = new PBQPNum[rows * cols];
|
||||
std::copy(m.data, m.data + (rows * cols), data);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \brief Return the number of rows in this matrix.
|
||||
unsigned getRows() const throw () { return rows; }
|
||||
|
||||
//! \brief Return the number of cols in this matrix.
|
||||
unsigned getCols() const throw () { return cols; }
|
||||
|
||||
//! \brief Matrix element access.
|
||||
PBQPNum* operator[](unsigned r) {
|
||||
assert(r < rows && "Row out of bounds.");
|
||||
return data + (r * cols);
|
||||
}
|
||||
|
||||
//! \brief Matrix element access.
|
||||
const PBQPNum* operator[](unsigned r) const {
|
||||
assert(r < rows && "Row out of bounds.");
|
||||
return data + (r * cols);
|
||||
}
|
||||
|
||||
//! \brief Returns the given row as a vector.
|
||||
PBQPVector getRowAsVector(unsigned r) const {
|
||||
PBQPVector v(cols);
|
||||
for (unsigned c = 0; c < cols; ++c)
|
||||
v[c] = (*this)[r][c];
|
||||
return v;
|
||||
}
|
||||
|
||||
//! \brief Reset the matrix to the given value.
|
||||
PBQPMatrix& reset(PBQPNum val = 0) {
|
||||
std::fill(data, data + (rows * cols), val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \brief Set a single row of this matrix to the given value.
|
||||
PBQPMatrix& setRow(unsigned r, PBQPNum val) {
|
||||
assert(r < rows && "Row out of bounds.");
|
||||
std::fill(data + (r * cols), data + ((r + 1) * cols), val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \brief Set a single column of this matrix to the given value.
|
||||
PBQPMatrix& setCol(unsigned c, PBQPNum val) {
|
||||
assert(c < cols && "Column out of bounds.");
|
||||
for (unsigned r = 0; r < rows; ++r)
|
||||
(*this)[r][c] = val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \brief Matrix transpose.
|
||||
PBQPMatrix transpose() const {
|
||||
PBQPMatrix m(cols, rows);
|
||||
for (unsigned r = 0; r < rows; ++r)
|
||||
for (unsigned c = 0; c < cols; ++c)
|
||||
m[c][r] = (*this)[r][c];
|
||||
return m;
|
||||
}
|
||||
|
||||
//! \brief Returns the diagonal of the matrix as a vector.
|
||||
//!
|
||||
//! Matrix must be square.
|
||||
PBQPVector diagonalize() const {
|
||||
assert(rows == cols && "Attempt to diagonalize non-square matrix.");
|
||||
|
||||
PBQPVector v(rows);
|
||||
for (unsigned r = 0; r < rows; ++r)
|
||||
v[r] = (*this)[r][r];
|
||||
return v;
|
||||
}
|
||||
|
||||
//! \brief Add the given matrix to this one.
|
||||
PBQPMatrix& operator+=(const PBQPMatrix &m) {
|
||||
assert(rows == m.rows && cols == m.cols &&
|
||||
"Matrix dimensions mismatch.");
|
||||
std::transform(data, data + (rows * cols), m.data, data,
|
||||
std::plus<PBQPNum>());
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \brief Returns the minimum of the given row
|
||||
PBQPNum getRowMin(unsigned r) const {
|
||||
assert(r < rows && "Row out of bounds");
|
||||
return *std::min_element(data + (r * cols), data + ((r + 1) * cols));
|
||||
}
|
||||
|
||||
//! \brief Returns the minimum of the given column
|
||||
PBQPNum getColMin(unsigned c) const {
|
||||
PBQPNum minElem = (*this)[0][c];
|
||||
for (unsigned r = 1; r < rows; ++r)
|
||||
if ((*this)[r][c] < minElem) minElem = (*this)[r][c];
|
||||
return minElem;
|
||||
}
|
||||
|
||||
//! \brief Subtracts the given scalar from the elements of the given row.
|
||||
PBQPMatrix& subFromRow(unsigned r, PBQPNum val) {
|
||||
assert(r < rows && "Row out of bounds");
|
||||
std::transform(data + (r * cols), data + ((r + 1) * cols),
|
||||
data + (r * cols),
|
||||
std::bind2nd(std::minus<PBQPNum>(), val));
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \brief Subtracts the given scalar from the elements of the given column.
|
||||
PBQPMatrix& subFromCol(unsigned c, PBQPNum val) {
|
||||
for (unsigned r = 0; r < rows; ++r)
|
||||
(*this)[r][c] -= val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \brief Returns true if this is a zero matrix.
|
||||
bool isZero() const {
|
||||
return find_if(data, data + (rows * cols),
|
||||
std::bind2nd(std::not_equal_to<PBQPNum>(), 0)) ==
|
||||
data + (rows * cols);
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned rows, cols;
|
||||
PBQPNum *data;
|
||||
};
|
||||
|
||||
#define EPS (1E-8)
|
||||
|
||||
#ifndef PBQP_TYPE
|
||||
#define PBQP_TYPE
|
||||
struct pbqp;
|
||||
typedef struct pbqp pbqp;
|
||||
#endif
|
||||
|
||||
/*****************
|
||||
* PBQP routines *
|
||||
*****************/
|
||||
|
||||
/* allocate pbqp problem */
|
||||
pbqp *alloc_pbqp(int num);
|
||||
|
||||
/* add node costs */
|
||||
void add_pbqp_nodecosts(pbqp *this_,int u, PBQPVector *costs);
|
||||
|
||||
/* add edge mat */
|
||||
void add_pbqp_edgecosts(pbqp *this_,int u,int v,PBQPMatrix *costs);
|
||||
|
||||
/* solve PBQP problem */
|
||||
void solve_pbqp(pbqp *this_);
|
||||
|
||||
/* get solution of a node */
|
||||
int get_pbqp_solution(pbqp *this_,int u);
|
||||
|
||||
/* alloc PBQP */
|
||||
pbqp *alloc_pbqp(int num);
|
||||
|
||||
/* free PBQP */
|
||||
void free_pbqp(pbqp *this_);
|
||||
|
||||
/* is optimal */
|
||||
bool is_pbqp_optimal(pbqp *this_);
|
||||
|
||||
}
|
||||
#endif
|
@ -1,892 +0,0 @@
|
||||
//===- RegAllocBigBlock.cpp - A register allocator for large basic blocks -===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the RABigBlock class
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This register allocator is derived from RegAllocLocal.cpp. Like it, this
|
||||
// allocator works on one basic block at a time, oblivious to others.
|
||||
// However, the algorithm used here is suited for long blocks of
|
||||
// instructions - registers are spilled by greedily choosing those holding
|
||||
// values that will not be needed for the longest amount of time. This works
|
||||
// particularly well for blocks with 10 or more times as many instructions
|
||||
// as machine registers, but can be used for general code.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// TODO: - automagically invoke linearscan for (groups of) small BBs?
|
||||
// - break ties when picking regs? (probably not worth it in a
|
||||
// JIT context)
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define DEBUG_TYPE "regalloc"
|
||||
#include "llvm/BasicBlock.h"
|
||||
#include "llvm/CodeGen/Passes.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/CodeGen/LiveVariables.h"
|
||||
#include "llvm/CodeGen/RegAllocRegistry.h"
|
||||
#include "llvm/Target/TargetInstrInfo.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/ADT/IndexedMap.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include <algorithm>
|
||||
using namespace llvm;
|
||||
|
||||
STATISTIC(NumStores, "Number of stores added");
|
||||
STATISTIC(NumLoads , "Number of loads added");
|
||||
STATISTIC(NumFolded, "Number of loads/stores folded into instructions");
|
||||
|
||||
static RegisterRegAlloc
|
||||
bigBlockRegAlloc("bigblock", "Big-block register allocator",
|
||||
createBigBlockRegisterAllocator);
|
||||
|
||||
namespace {
|
||||
/// VRegKeyInfo - Defines magic values required to use VirtRegs as DenseMap
|
||||
/// keys.
|
||||
struct VRegKeyInfo {
|
||||
static inline unsigned getEmptyKey() { return -1U; }
|
||||
static inline unsigned getTombstoneKey() { return -2U; }
|
||||
static bool isEqual(unsigned LHS, unsigned RHS) { return LHS == RHS; }
|
||||
static unsigned getHashValue(const unsigned &Key) { return Key; }
|
||||
};
|
||||
|
||||
|
||||
/// This register allocator is derived from RegAllocLocal.cpp. Like it, this
|
||||
/// allocator works on one basic block at a time, oblivious to others.
|
||||
/// However, the algorithm used here is suited for long blocks of
|
||||
/// instructions - registers are spilled by greedily choosing those holding
|
||||
/// values that will not be needed for the longest amount of time. This works
|
||||
/// particularly well for blocks with 10 or more times as many instructions
|
||||
/// as machine registers, but can be used for general code.
|
||||
///
|
||||
/// TODO: - automagically invoke linearscan for (groups of) small BBs?
|
||||
/// - break ties when picking regs? (probably not worth it in a
|
||||
/// JIT context)
|
||||
///
|
||||
class VISIBILITY_HIDDEN RABigBlock : public MachineFunctionPass {
|
||||
public:
|
||||
static char ID;
|
||||
RABigBlock() : MachineFunctionPass(&ID) {}
|
||||
private:
|
||||
/// TM - For getting at TargetMachine info
|
||||
///
|
||||
const TargetMachine *TM;
|
||||
|
||||
/// MF - Our generic MachineFunction pointer
|
||||
///
|
||||
MachineFunction *MF;
|
||||
|
||||
/// RegInfo - For dealing with machine register info (aliases, folds
|
||||
/// etc)
|
||||
const TargetRegisterInfo *RegInfo;
|
||||
|
||||
typedef SmallVector<unsigned, 2> VRegTimes;
|
||||
|
||||
/// VRegReadTable - maps VRegs in a BB to the set of times they are read
|
||||
///
|
||||
DenseMap<unsigned, VRegTimes*, VRegKeyInfo> VRegReadTable;
|
||||
|
||||
/// VRegReadIdx - keeps track of the "current time" in terms of
|
||||
/// positions in VRegReadTable
|
||||
DenseMap<unsigned, unsigned , VRegKeyInfo> VRegReadIdx;
|
||||
|
||||
/// StackSlotForVirtReg - Maps virtual regs to the frame index where these
|
||||
/// values are spilled.
|
||||
IndexedMap<unsigned, VirtReg2IndexFunctor> StackSlotForVirtReg;
|
||||
|
||||
/// Virt2PhysRegMap - This map contains entries for each virtual register
|
||||
/// that is currently available in a physical register.
|
||||
IndexedMap<unsigned, VirtReg2IndexFunctor> Virt2PhysRegMap;
|
||||
|
||||
/// PhysRegsUsed - This array is effectively a map, containing entries for
|
||||
/// each physical register that currently has a value (ie, it is in
|
||||
/// Virt2PhysRegMap). The value mapped to is the virtual register
|
||||
/// corresponding to the physical register (the inverse of the
|
||||
/// Virt2PhysRegMap), or 0. The value is set to 0 if this register is pinned
|
||||
/// because it is used by a future instruction, and to -2 if it is not
|
||||
/// allocatable. If the entry for a physical register is -1, then the
|
||||
/// physical register is "not in the map".
|
||||
///
|
||||
std::vector<int> PhysRegsUsed;
|
||||
|
||||
/// VirtRegModified - This bitset contains information about which virtual
|
||||
/// registers need to be spilled back to memory when their registers are
|
||||
/// scavenged. If a virtual register has simply been rematerialized, there
|
||||
/// is no reason to spill it to memory when we need the register back.
|
||||
///
|
||||
std::vector<int> VirtRegModified;
|
||||
|
||||
/// MBBLastInsnTime - the number of the the last instruction in MBB
|
||||
///
|
||||
int MBBLastInsnTime;
|
||||
|
||||
/// MBBCurTime - the number of the the instruction being currently processed
|
||||
///
|
||||
int MBBCurTime;
|
||||
|
||||
unsigned &getVirt2PhysRegMapSlot(unsigned VirtReg) {
|
||||
return Virt2PhysRegMap[VirtReg];
|
||||
}
|
||||
|
||||
unsigned &getVirt2StackSlot(unsigned VirtReg) {
|
||||
return StackSlotForVirtReg[VirtReg];
|
||||
}
|
||||
|
||||
/// markVirtRegModified - Lets us flip bits in the VirtRegModified bitset
|
||||
///
|
||||
void markVirtRegModified(unsigned Reg, bool Val = true) {
|
||||
assert(TargetRegisterInfo::isVirtualRegister(Reg) && "Illegal VirtReg!");
|
||||
Reg -= TargetRegisterInfo::FirstVirtualRegister;
|
||||
if (VirtRegModified.size() <= Reg)
|
||||
VirtRegModified.resize(Reg+1);
|
||||
VirtRegModified[Reg] = Val;
|
||||
}
|
||||
|
||||
/// isVirtRegModified - Lets us query the VirtRegModified bitset
|
||||
///
|
||||
bool isVirtRegModified(unsigned Reg) const {
|
||||
assert(TargetRegisterInfo::isVirtualRegister(Reg) && "Illegal VirtReg!");
|
||||
assert(Reg - TargetRegisterInfo::FirstVirtualRegister < VirtRegModified.size()
|
||||
&& "Illegal virtual register!");
|
||||
return VirtRegModified[Reg - TargetRegisterInfo::FirstVirtualRegister];
|
||||
}
|
||||
|
||||
public:
|
||||
/// getPassName - returns the BigBlock allocator's name
|
||||
///
|
||||
virtual const char *getPassName() const {
|
||||
return "BigBlock Register Allocator";
|
||||
}
|
||||
|
||||
/// getAnalaysisUsage - declares the required analyses
|
||||
///
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.addRequiredID(PHIEliminationID);
|
||||
AU.addRequiredID(TwoAddressInstructionPassID);
|
||||
MachineFunctionPass::getAnalysisUsage(AU);
|
||||
}
|
||||
|
||||
private:
|
||||
/// runOnMachineFunction - Register allocate the whole function
|
||||
///
|
||||
bool runOnMachineFunction(MachineFunction &Fn);
|
||||
|
||||
/// AllocateBasicBlock - Register allocate the specified basic block.
|
||||
///
|
||||
void AllocateBasicBlock(MachineBasicBlock &MBB);
|
||||
|
||||
/// FillVRegReadTable - Fill out the table of vreg read times given a BB
|
||||
///
|
||||
void FillVRegReadTable(MachineBasicBlock &MBB);
|
||||
|
||||
/// areRegsEqual - This method returns true if the specified registers are
|
||||
/// related to each other. To do this, it checks to see if they are equal
|
||||
/// or if the first register is in the alias set of the second register.
|
||||
///
|
||||
bool areRegsEqual(unsigned R1, unsigned R2) const {
|
||||
if (R1 == R2) return true;
|
||||
for (const unsigned *AliasSet = RegInfo->getAliasSet(R2);
|
||||
*AliasSet; ++AliasSet) {
|
||||
if (*AliasSet == R1) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// getStackSpaceFor - This returns the frame index of the specified virtual
|
||||
/// register on the stack, allocating space if necessary.
|
||||
int getStackSpaceFor(unsigned VirtReg, const TargetRegisterClass *RC);
|
||||
|
||||
/// removePhysReg - This method marks the specified physical register as no
|
||||
/// longer being in use.
|
||||
///
|
||||
void removePhysReg(unsigned PhysReg);
|
||||
|
||||
/// spillVirtReg - This method spills the value specified by PhysReg into
|
||||
/// the virtual register slot specified by VirtReg. It then updates the RA
|
||||
/// data structures to indicate the fact that PhysReg is now available.
|
||||
///
|
||||
void spillVirtReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
|
||||
unsigned VirtReg, unsigned PhysReg);
|
||||
|
||||
/// spillPhysReg - This method spills the specified physical register into
|
||||
/// the virtual register slot associated with it. If OnlyVirtRegs is set to
|
||||
/// true, then the request is ignored if the physical register does not
|
||||
/// contain a virtual register.
|
||||
///
|
||||
void spillPhysReg(MachineBasicBlock &MBB, MachineInstr *I,
|
||||
unsigned PhysReg, bool OnlyVirtRegs = false);
|
||||
|
||||
/// assignVirtToPhysReg - This method updates local state so that we know
|
||||
/// that PhysReg is the proper container for VirtReg now. The physical
|
||||
/// register must not be used for anything else when this is called.
|
||||
///
|
||||
void assignVirtToPhysReg(unsigned VirtReg, unsigned PhysReg);
|
||||
|
||||
/// isPhysRegAvailable - Return true if the specified physical register is
|
||||
/// free and available for use. This also includes checking to see if
|
||||
/// aliased registers are all free...
|
||||
///
|
||||
bool isPhysRegAvailable(unsigned PhysReg) const;
|
||||
|
||||
/// getFreeReg - Look to see if there is a free register available in the
|
||||
/// specified register class. If not, return 0.
|
||||
///
|
||||
unsigned getFreeReg(const TargetRegisterClass *RC);
|
||||
|
||||
/// chooseReg - Pick a physical register to hold the specified
|
||||
/// virtual register by choosing the one which will be read furthest
|
||||
/// in the future.
|
||||
///
|
||||
unsigned chooseReg(MachineBasicBlock &MBB, MachineInstr *MI,
|
||||
unsigned VirtReg);
|
||||
|
||||
/// reloadVirtReg - This method transforms the specified specified virtual
|
||||
/// register use to refer to a physical register. This method may do this
|
||||
/// in one of several ways: if the register is available in a physical
|
||||
/// register already, it uses that physical register. If the value is not
|
||||
/// in a physical register, and if there are physical registers available,
|
||||
/// it loads it into a register. If register pressure is high, and it is
|
||||
/// possible, it tries to fold the load of the virtual register into the
|
||||
/// instruction itself. It avoids doing this if register pressure is low to
|
||||
/// improve the chance that subsequent instructions can use the reloaded
|
||||
/// value. This method returns the modified instruction.
|
||||
///
|
||||
MachineInstr *reloadVirtReg(MachineBasicBlock &MBB, MachineInstr *MI,
|
||||
unsigned OpNum);
|
||||
|
||||
};
|
||||
char RABigBlock::ID = 0;
|
||||
}
|
||||
|
||||
/// getStackSpaceFor - This allocates space for the specified virtual register
|
||||
/// to be held on the stack.
|
||||
int RABigBlock::getStackSpaceFor(unsigned VirtReg, const TargetRegisterClass *RC) {
|
||||
// Find the location Reg would belong...
|
||||
int FrameIdx = getVirt2StackSlot(VirtReg);
|
||||
|
||||
if (FrameIdx)
|
||||
return FrameIdx - 1; // Already has space allocated?
|
||||
|
||||
// Allocate a new stack object for this spill location...
|
||||
FrameIdx = MF->getFrameInfo()->CreateStackObject(RC->getSize(),
|
||||
RC->getAlignment());
|
||||
|
||||
// Assign the slot...
|
||||
getVirt2StackSlot(VirtReg) = FrameIdx + 1;
|
||||
return FrameIdx;
|
||||
}
|
||||
|
||||
|
||||
/// removePhysReg - This method marks the specified physical register as no
|
||||
/// longer being in use.
|
||||
///
|
||||
void RABigBlock::removePhysReg(unsigned PhysReg) {
|
||||
PhysRegsUsed[PhysReg] = -1; // PhyReg no longer used
|
||||
}
|
||||
|
||||
|
||||
/// spillVirtReg - This method spills the value specified by PhysReg into the
|
||||
/// virtual register slot specified by VirtReg. It then updates the RA data
|
||||
/// structures to indicate the fact that PhysReg is now available.
|
||||
///
|
||||
void RABigBlock::spillVirtReg(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator I,
|
||||
unsigned VirtReg, unsigned PhysReg) {
|
||||
assert(VirtReg && "Spilling a physical register is illegal!"
|
||||
" Must not have appropriate kill for the register or use exists beyond"
|
||||
" the intended one.");
|
||||
DOUT << " Spilling register " << RegInfo->getName(PhysReg)
|
||||
<< " containing %reg" << VirtReg;
|
||||
|
||||
const TargetInstrInfo* TII = MBB.getParent()->getTarget().getInstrInfo();
|
||||
|
||||
if (!isVirtRegModified(VirtReg))
|
||||
DOUT << " which has not been modified, so no store necessary!";
|
||||
|
||||
// Otherwise, there is a virtual register corresponding to this physical
|
||||
// register. We only need to spill it into its stack slot if it has been
|
||||
// modified.
|
||||
if (isVirtRegModified(VirtReg)) {
|
||||
const TargetRegisterClass *RC = MF->getRegInfo().getRegClass(VirtReg);
|
||||
int FrameIndex = getStackSpaceFor(VirtReg, RC);
|
||||
DOUT << " to stack slot #" << FrameIndex;
|
||||
TII->storeRegToStackSlot(MBB, I, PhysReg, true, FrameIndex, RC);
|
||||
++NumStores; // Update statistics
|
||||
}
|
||||
|
||||
getVirt2PhysRegMapSlot(VirtReg) = 0; // VirtReg no longer available
|
||||
|
||||
DOUT << "\n";
|
||||
removePhysReg(PhysReg);
|
||||
}
|
||||
|
||||
|
||||
/// spillPhysReg - This method spills the specified physical register into the
|
||||
/// virtual register slot associated with it. If OnlyVirtRegs is set to true,
|
||||
/// then the request is ignored if the physical register does not contain a
|
||||
/// virtual register.
|
||||
///
|
||||
void RABigBlock::spillPhysReg(MachineBasicBlock &MBB, MachineInstr *I,
|
||||
unsigned PhysReg, bool OnlyVirtRegs) {
|
||||
if (PhysRegsUsed[PhysReg] != -1) { // Only spill it if it's used!
|
||||
assert(PhysRegsUsed[PhysReg] != -2 && "Non allocable reg used!");
|
||||
if (PhysRegsUsed[PhysReg] || !OnlyVirtRegs)
|
||||
spillVirtReg(MBB, I, PhysRegsUsed[PhysReg], PhysReg);
|
||||
} else {
|
||||
// If the selected register aliases any other registers, we must make
|
||||
// sure that one of the aliases isn't alive.
|
||||
for (const unsigned *AliasSet = RegInfo->getAliasSet(PhysReg);
|
||||
*AliasSet; ++AliasSet)
|
||||
if (PhysRegsUsed[*AliasSet] != -1 && // Spill aliased register.
|
||||
PhysRegsUsed[*AliasSet] != -2) // If allocatable.
|
||||
if (PhysRegsUsed[*AliasSet])
|
||||
spillVirtReg(MBB, I, PhysRegsUsed[*AliasSet], *AliasSet);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// assignVirtToPhysReg - This method updates local state so that we know
|
||||
/// that PhysReg is the proper container for VirtReg now. The physical
|
||||
/// register must not be used for anything else when this is called.
|
||||
///
|
||||
void RABigBlock::assignVirtToPhysReg(unsigned VirtReg, unsigned PhysReg) {
|
||||
assert(PhysRegsUsed[PhysReg] == -1 && "Phys reg already assigned!");
|
||||
// Update information to note the fact that this register was just used, and
|
||||
// it holds VirtReg.
|
||||
PhysRegsUsed[PhysReg] = VirtReg;
|
||||
getVirt2PhysRegMapSlot(VirtReg) = PhysReg;
|
||||
}
|
||||
|
||||
|
||||
/// isPhysRegAvailable - Return true if the specified physical register is free
|
||||
/// and available for use. This also includes checking to see if aliased
|
||||
/// registers are all free...
|
||||
///
|
||||
bool RABigBlock::isPhysRegAvailable(unsigned PhysReg) const {
|
||||
if (PhysRegsUsed[PhysReg] != -1) return false;
|
||||
|
||||
// If the selected register aliases any other allocated registers, it is
|
||||
// not free!
|
||||
for (const unsigned *AliasSet = RegInfo->getAliasSet(PhysReg);
|
||||
*AliasSet; ++AliasSet)
|
||||
if (PhysRegsUsed[*AliasSet] >= 0) // Aliased register in use?
|
||||
return false; // Can't use this reg then.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// getFreeReg - Look to see if there is a free register available in the
|
||||
/// specified register class. If not, return 0.
|
||||
///
|
||||
unsigned RABigBlock::getFreeReg(const TargetRegisterClass *RC) {
|
||||
// Get iterators defining the range of registers that are valid to allocate in
|
||||
// this class, which also specifies the preferred allocation order.
|
||||
TargetRegisterClass::iterator RI = RC->allocation_order_begin(*MF);
|
||||
TargetRegisterClass::iterator RE = RC->allocation_order_end(*MF);
|
||||
|
||||
for (; RI != RE; ++RI)
|
||||
if (isPhysRegAvailable(*RI)) { // Is reg unused?
|
||||
assert(*RI != 0 && "Cannot use register!");
|
||||
return *RI; // Found an unused register!
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/// chooseReg - Pick a physical register to hold the specified
|
||||
/// virtual register by choosing the one whose value will be read
|
||||
/// furthest in the future.
|
||||
///
|
||||
unsigned RABigBlock::chooseReg(MachineBasicBlock &MBB, MachineInstr *I,
|
||||
unsigned VirtReg) {
|
||||
const TargetRegisterClass *RC = MF->getRegInfo().getRegClass(VirtReg);
|
||||
// First check to see if we have a free register of the requested type...
|
||||
unsigned PhysReg = getFreeReg(RC);
|
||||
|
||||
// If we didn't find an unused register, find the one which will be
|
||||
// read at the most distant point in time.
|
||||
if (PhysReg == 0) {
|
||||
unsigned delay=0, longest_delay=0;
|
||||
VRegTimes* ReadTimes;
|
||||
|
||||
unsigned curTime = MBBCurTime;
|
||||
|
||||
// for all physical regs in the RC,
|
||||
for(TargetRegisterClass::iterator pReg = RC->begin();
|
||||
pReg != RC->end(); ++pReg) {
|
||||
// how long until they're read?
|
||||
if(PhysRegsUsed[*pReg]>0) { // ignore non-allocatable regs
|
||||
ReadTimes = VRegReadTable[PhysRegsUsed[*pReg]];
|
||||
if(ReadTimes && !ReadTimes->empty()) {
|
||||
unsigned& pt = VRegReadIdx[PhysRegsUsed[*pReg]];
|
||||
while(pt < ReadTimes->size() && (*ReadTimes)[pt] < curTime) {
|
||||
++pt;
|
||||
}
|
||||
|
||||
if(pt < ReadTimes->size())
|
||||
delay = (*ReadTimes)[pt] - curTime;
|
||||
else
|
||||
delay = MBBLastInsnTime + 1 - curTime;
|
||||
} else {
|
||||
// This register is only defined, but never
|
||||
// read in this MBB. Therefore the next read
|
||||
// happens after the end of this MBB
|
||||
delay = MBBLastInsnTime + 1 - curTime;
|
||||
}
|
||||
|
||||
|
||||
if(delay > longest_delay) {
|
||||
longest_delay = delay;
|
||||
PhysReg = *pReg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(PhysReg == 0) { // ok, now we're desperate. We couldn't choose
|
||||
// a register to spill by looking through the
|
||||
// read timetable, so now we just spill the
|
||||
// first allocatable register we find.
|
||||
|
||||
// for all physical regs in the RC,
|
||||
for(TargetRegisterClass::iterator pReg = RC->begin();
|
||||
pReg != RC->end(); ++pReg) {
|
||||
// if we find a register we can spill
|
||||
if(PhysRegsUsed[*pReg]>=-1)
|
||||
PhysReg = *pReg; // choose it to be spilled
|
||||
}
|
||||
}
|
||||
|
||||
assert(PhysReg && "couldn't choose a register to spill :( ");
|
||||
// TODO: assert that RC->contains(PhysReg) / handle aliased registers?
|
||||
|
||||
// since we needed to look in the table we need to spill this register.
|
||||
spillPhysReg(MBB, I, PhysReg);
|
||||
}
|
||||
|
||||
// assign the vreg to our chosen physical register
|
||||
assignVirtToPhysReg(VirtReg, PhysReg);
|
||||
return PhysReg; // and return it
|
||||
}
|
||||
|
||||
|
||||
/// reloadVirtReg - This method transforms an instruction with a virtual
|
||||
/// register use to one that references a physical register. It does this as
|
||||
/// follows:
|
||||
///
|
||||
/// 1) If the register is already in a physical register, it uses it.
|
||||
/// 2) Otherwise, if there is a free physical register, it uses that.
|
||||
/// 3) Otherwise, it calls chooseReg() to get the physical register
|
||||
/// holding the most distantly needed value, generating a spill in
|
||||
/// the process.
|
||||
///
|
||||
/// This method returns the modified instruction.
|
||||
MachineInstr *RABigBlock::reloadVirtReg(MachineBasicBlock &MBB, MachineInstr *MI,
|
||||
unsigned OpNum) {
|
||||
unsigned VirtReg = MI->getOperand(OpNum).getReg();
|
||||
const TargetInstrInfo* TII = MBB.getParent()->getTarget().getInstrInfo();
|
||||
|
||||
// If the virtual register is already available in a physical register,
|
||||
// just update the instruction and return.
|
||||
if (unsigned PR = getVirt2PhysRegMapSlot(VirtReg)) {
|
||||
MI->getOperand(OpNum).setReg(PR);
|
||||
return MI;
|
||||
}
|
||||
|
||||
// Otherwise, if we have free physical registers available to hold the
|
||||
// value, use them.
|
||||
const TargetRegisterClass *RC = MF->getRegInfo().getRegClass(VirtReg);
|
||||
unsigned PhysReg = getFreeReg(RC);
|
||||
int FrameIndex = getStackSpaceFor(VirtReg, RC);
|
||||
|
||||
if (PhysReg) { // we have a free register, so use it.
|
||||
assignVirtToPhysReg(VirtReg, PhysReg);
|
||||
} else { // no free registers available.
|
||||
// try to fold the spill into the instruction
|
||||
SmallVector<unsigned, 1> Ops;
|
||||
Ops.push_back(OpNum);
|
||||
if(MachineInstr* FMI = TII->foldMemoryOperand(*MF, MI, Ops, FrameIndex)) {
|
||||
++NumFolded;
|
||||
FMI->copyKillDeadInfo(MI);
|
||||
return MBB.insert(MBB.erase(MI), FMI);
|
||||
}
|
||||
|
||||
// determine which of the physical registers we'll kill off, since we
|
||||
// couldn't fold.
|
||||
PhysReg = chooseReg(MBB, MI, VirtReg);
|
||||
}
|
||||
|
||||
// this virtual register is now unmodified (since we just reloaded it)
|
||||
markVirtRegModified(VirtReg, false);
|
||||
|
||||
DOUT << " Reloading %reg" << VirtReg << " into "
|
||||
<< RegInfo->getName(PhysReg) << "\n";
|
||||
|
||||
// Add move instruction(s)
|
||||
TII->loadRegFromStackSlot(MBB, MI, PhysReg, FrameIndex, RC);
|
||||
++NumLoads; // Update statistics
|
||||
|
||||
MF->getRegInfo().setPhysRegUsed(PhysReg);
|
||||
MI->getOperand(OpNum).setReg(PhysReg); // Assign the input register
|
||||
return MI;
|
||||
}
|
||||
|
||||
/// Fill out the vreg read timetable. Since ReadTime increases
|
||||
/// monotonically, the individual readtime sets will be sorted
|
||||
/// in ascending order.
|
||||
void RABigBlock::FillVRegReadTable(MachineBasicBlock &MBB) {
|
||||
// loop over each instruction
|
||||
MachineBasicBlock::iterator MII;
|
||||
unsigned ReadTime;
|
||||
|
||||
for(ReadTime=0, MII = MBB.begin(); MII != MBB.end(); ++ReadTime, ++MII) {
|
||||
MachineInstr *MI = MII;
|
||||
|
||||
for (unsigned i = 0; i != MI->getNumOperands(); ++i) {
|
||||
MachineOperand& MO = MI->getOperand(i);
|
||||
// look for vreg reads..
|
||||
if (MO.isReg() && !MO.isDef() && MO.getReg() &&
|
||||
TargetRegisterInfo::isVirtualRegister(MO.getReg())) {
|
||||
// ..and add them to the read table.
|
||||
VRegTimes* &Times = VRegReadTable[MO.getReg()];
|
||||
if(!VRegReadTable[MO.getReg()]) {
|
||||
Times = new VRegTimes;
|
||||
VRegReadIdx[MO.getReg()] = 0;
|
||||
}
|
||||
Times->push_back(ReadTime);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MBBLastInsnTime = ReadTime;
|
||||
|
||||
for(DenseMap<unsigned, VRegTimes*, VRegKeyInfo>::iterator Reads = VRegReadTable.begin();
|
||||
Reads != VRegReadTable.end(); ++Reads) {
|
||||
if(Reads->second) {
|
||||
DOUT << "Reads[" << Reads->first << "]=" << Reads->second->size() << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// isReadModWriteImplicitKill - True if this is an implicit kill for a
|
||||
/// read/mod/write register, i.e. update partial register.
|
||||
static bool isReadModWriteImplicitKill(MachineInstr *MI, unsigned Reg) {
|
||||
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
|
||||
MachineOperand& MO = MI->getOperand(i);
|
||||
if (MO.isReg() && MO.getReg() == Reg && MO.isImplicit() &&
|
||||
MO.isDef() && !MO.isDead())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// isReadModWriteImplicitDef - True if this is an implicit def for a
|
||||
/// read/mod/write register, i.e. update partial register.
|
||||
static bool isReadModWriteImplicitDef(MachineInstr *MI, unsigned Reg) {
|
||||
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
|
||||
MachineOperand& MO = MI->getOperand(i);
|
||||
if (MO.isReg() && MO.getReg() == Reg && MO.isImplicit() &&
|
||||
!MO.isDef() && MO.isKill())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void RABigBlock::AllocateBasicBlock(MachineBasicBlock &MBB) {
|
||||
// loop over each instruction
|
||||
MachineBasicBlock::iterator MII = MBB.begin();
|
||||
const TargetInstrInfo &TII = *TM->getInstrInfo();
|
||||
|
||||
DEBUG(const BasicBlock *LBB = MBB.getBasicBlock();
|
||||
if (LBB) DOUT << "\nStarting RegAlloc of BB: " << LBB->getName());
|
||||
|
||||
// If this is the first basic block in the machine function, add live-in
|
||||
// registers as active.
|
||||
if (&MBB == &*MF->begin()) {
|
||||
for (MachineRegisterInfo::livein_iterator
|
||||
I = MF->getRegInfo().livein_begin(),
|
||||
E = MF->getRegInfo().livein_end(); I != E; ++I) {
|
||||
unsigned Reg = I->first;
|
||||
MF->getRegInfo().setPhysRegUsed(Reg);
|
||||
PhysRegsUsed[Reg] = 0; // It is free and reserved now
|
||||
for (const unsigned *AliasSet = RegInfo->getSubRegisters(Reg);
|
||||
*AliasSet; ++AliasSet) {
|
||||
if (PhysRegsUsed[*AliasSet] != -2) {
|
||||
PhysRegsUsed[*AliasSet] = 0; // It is free and reserved now
|
||||
MF->getRegInfo().setPhysRegUsed(*AliasSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, sequentially allocate each instruction in the MBB.
|
||||
MBBCurTime = -1;
|
||||
while (MII != MBB.end()) {
|
||||
MachineInstr *MI = MII++;
|
||||
MBBCurTime++;
|
||||
const TargetInstrDesc &TID = MI->getDesc();
|
||||
DEBUG(DOUT << "\nTime=" << MBBCurTime << " Starting RegAlloc of: " << *MI;
|
||||
DOUT << " Regs have values: ";
|
||||
for (unsigned i = 0; i != RegInfo->getNumRegs(); ++i)
|
||||
if (PhysRegsUsed[i] != -1 && PhysRegsUsed[i] != -2)
|
||||
DOUT << "[" << RegInfo->getName(i)
|
||||
<< ",%reg" << PhysRegsUsed[i] << "] ";
|
||||
DOUT << "\n");
|
||||
|
||||
SmallVector<unsigned, 8> Kills;
|
||||
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
|
||||
MachineOperand& MO = MI->getOperand(i);
|
||||
if (MO.isReg() && MO.isKill()) {
|
||||
if (!MO.isImplicit())
|
||||
Kills.push_back(MO.getReg());
|
||||
else if (!isReadModWriteImplicitKill(MI, MO.getReg()))
|
||||
// These are extra physical register kills when a sub-register
|
||||
// is defined (def of a sub-register is a read/mod/write of the
|
||||
// larger registers). Ignore.
|
||||
Kills.push_back(MO.getReg());
|
||||
}
|
||||
}
|
||||
|
||||
// Get the used operands into registers. This has the potential to spill
|
||||
// incoming values if we are out of registers. Note that we completely
|
||||
// ignore physical register uses here. We assume that if an explicit
|
||||
// physical register is referenced by the instruction, that it is guaranteed
|
||||
// to be live-in, or the input is badly hosed.
|
||||
//
|
||||
for (unsigned i = 0; i != MI->getNumOperands(); ++i) {
|
||||
MachineOperand& MO = MI->getOperand(i);
|
||||
// here we are looking for only used operands (never def&use)
|
||||
if (MO.isReg() && !MO.isDef() && MO.getReg() && !MO.isImplicit() &&
|
||||
TargetRegisterInfo::isVirtualRegister(MO.getReg()))
|
||||
MI = reloadVirtReg(MBB, MI, i);
|
||||
}
|
||||
|
||||
// If this instruction is the last user of this register, kill the
|
||||
// value, freeing the register being used, so it doesn't need to be
|
||||
// spilled to memory.
|
||||
//
|
||||
for (unsigned i = 0, e = Kills.size(); i != e; ++i) {
|
||||
unsigned VirtReg = Kills[i];
|
||||
unsigned PhysReg = VirtReg;
|
||||
if (TargetRegisterInfo::isVirtualRegister(VirtReg)) {
|
||||
// If the virtual register was never materialized into a register, it
|
||||
// might not be in the map, but it won't hurt to zero it out anyway.
|
||||
unsigned &PhysRegSlot = getVirt2PhysRegMapSlot(VirtReg);
|
||||
PhysReg = PhysRegSlot;
|
||||
PhysRegSlot = 0;
|
||||
} else if (PhysRegsUsed[PhysReg] == -2) {
|
||||
// Unallocatable register dead, ignore.
|
||||
continue;
|
||||
} else {
|
||||
assert((!PhysRegsUsed[PhysReg] || PhysRegsUsed[PhysReg] == -1) &&
|
||||
"Silently clearing a virtual register?");
|
||||
}
|
||||
|
||||
if (PhysReg) {
|
||||
DOUT << " Last use of " << RegInfo->getName(PhysReg)
|
||||
<< "[%reg" << VirtReg <<"], removing it from live set\n";
|
||||
removePhysReg(PhysReg);
|
||||
for (const unsigned *AliasSet = RegInfo->getSubRegisters(PhysReg);
|
||||
*AliasSet; ++AliasSet) {
|
||||
if (PhysRegsUsed[*AliasSet] != -2) {
|
||||
DOUT << " Last use of "
|
||||
<< RegInfo->getName(*AliasSet)
|
||||
<< "[%reg" << VirtReg <<"], removing it from live set\n";
|
||||
removePhysReg(*AliasSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Loop over all of the operands of the instruction, spilling registers that
|
||||
// are defined, and marking explicit destinations in the PhysRegsUsed map.
|
||||
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
|
||||
MachineOperand& MO = MI->getOperand(i);
|
||||
if (MO.isReg() && MO.isDef() && !MO.isImplicit() && MO.getReg() &&
|
||||
TargetRegisterInfo::isPhysicalRegister(MO.getReg())) {
|
||||
unsigned Reg = MO.getReg();
|
||||
if (PhysRegsUsed[Reg] == -2) continue; // Something like ESP.
|
||||
// These are extra physical register defs when a sub-register
|
||||
// is defined (def of a sub-register is a read/mod/write of the
|
||||
// larger registers). Ignore.
|
||||
if (isReadModWriteImplicitDef(MI, MO.getReg())) continue;
|
||||
|
||||
MF->getRegInfo().setPhysRegUsed(Reg);
|
||||
spillPhysReg(MBB, MI, Reg, true); // Spill any existing value in reg
|
||||
PhysRegsUsed[Reg] = 0; // It is free and reserved now
|
||||
for (const unsigned *AliasSet = RegInfo->getSubRegisters(Reg);
|
||||
*AliasSet; ++AliasSet) {
|
||||
if (PhysRegsUsed[*AliasSet] != -2) {
|
||||
PhysRegsUsed[*AliasSet] = 0; // It is free and reserved now
|
||||
MF->getRegInfo().setPhysRegUsed(*AliasSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Loop over the implicit defs, spilling them as well.
|
||||
if (TID.getImplicitDefs()) {
|
||||
for (const unsigned *ImplicitDefs = TID.getImplicitDefs();
|
||||
*ImplicitDefs; ++ImplicitDefs) {
|
||||
unsigned Reg = *ImplicitDefs;
|
||||
if (PhysRegsUsed[Reg] != -2) {
|
||||
spillPhysReg(MBB, MI, Reg, true);
|
||||
PhysRegsUsed[Reg] = 0; // It is free and reserved now
|
||||
}
|
||||
MF->getRegInfo().setPhysRegUsed(Reg);
|
||||
for (const unsigned *AliasSet = RegInfo->getSubRegisters(Reg);
|
||||
*AliasSet; ++AliasSet) {
|
||||
if (PhysRegsUsed[*AliasSet] != -2) {
|
||||
PhysRegsUsed[*AliasSet] = 0; // It is free and reserved now
|
||||
MF->getRegInfo().setPhysRegUsed(*AliasSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SmallVector<unsigned, 8> DeadDefs;
|
||||
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
|
||||
MachineOperand& MO = MI->getOperand(i);
|
||||
if (MO.isReg() && MO.isDead())
|
||||
DeadDefs.push_back(MO.getReg());
|
||||
}
|
||||
|
||||
// Okay, we have allocated all of the source operands and spilled any values
|
||||
// that would be destroyed by defs of this instruction. Loop over the
|
||||
// explicit defs and assign them to a register, spilling incoming values if
|
||||
// we need to scavenge a register.
|
||||
//
|
||||
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
|
||||
MachineOperand& MO = MI->getOperand(i);
|
||||
if (MO.isReg() && MO.isDef() && MO.getReg() &&
|
||||
TargetRegisterInfo::isVirtualRegister(MO.getReg())) {
|
||||
unsigned DestVirtReg = MO.getReg();
|
||||
unsigned DestPhysReg;
|
||||
|
||||
// If DestVirtReg already has a value, use it.
|
||||
if (!(DestPhysReg = getVirt2PhysRegMapSlot(DestVirtReg)))
|
||||
DestPhysReg = chooseReg(MBB, MI, DestVirtReg);
|
||||
MF->getRegInfo().setPhysRegUsed(DestPhysReg);
|
||||
markVirtRegModified(DestVirtReg);
|
||||
MI->getOperand(i).setReg(DestPhysReg); // Assign the output register
|
||||
}
|
||||
}
|
||||
|
||||
// If this instruction defines any registers that are immediately dead,
|
||||
// kill them now.
|
||||
//
|
||||
for (unsigned i = 0, e = DeadDefs.size(); i != e; ++i) {
|
||||
unsigned VirtReg = DeadDefs[i];
|
||||
unsigned PhysReg = VirtReg;
|
||||
if (TargetRegisterInfo::isVirtualRegister(VirtReg)) {
|
||||
unsigned &PhysRegSlot = getVirt2PhysRegMapSlot(VirtReg);
|
||||
PhysReg = PhysRegSlot;
|
||||
assert(PhysReg != 0);
|
||||
PhysRegSlot = 0;
|
||||
} else if (PhysRegsUsed[PhysReg] == -2) {
|
||||
// Unallocatable register dead, ignore.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (PhysReg) {
|
||||
DOUT << " Register " << RegInfo->getName(PhysReg)
|
||||
<< " [%reg" << VirtReg
|
||||
<< "] is never used, removing it from live set\n";
|
||||
removePhysReg(PhysReg);
|
||||
for (const unsigned *AliasSet = RegInfo->getAliasSet(PhysReg);
|
||||
*AliasSet; ++AliasSet) {
|
||||
if (PhysRegsUsed[*AliasSet] != -2) {
|
||||
DOUT << " Register " << RegInfo->getName(*AliasSet)
|
||||
<< " [%reg" << *AliasSet
|
||||
<< "] is never used, removing it from live set\n";
|
||||
removePhysReg(*AliasSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, if this is a noop copy instruction, zap it.
|
||||
unsigned SrcReg, DstReg, SrcSubReg, DstSubReg;
|
||||
if (TII.isMoveInstr(*MI, SrcReg, DstReg, SrcSubReg, DstSubReg) &&
|
||||
SrcReg == DstReg)
|
||||
MBB.erase(MI);
|
||||
}
|
||||
|
||||
MachineBasicBlock::iterator MI = MBB.getFirstTerminator();
|
||||
|
||||
// Spill all physical registers holding virtual registers now.
|
||||
for (unsigned i = 0, e = RegInfo->getNumRegs(); i != e; ++i)
|
||||
if (PhysRegsUsed[i] != -1 && PhysRegsUsed[i] != -2) {
|
||||
if (unsigned VirtReg = PhysRegsUsed[i])
|
||||
spillVirtReg(MBB, MI, VirtReg, i);
|
||||
else
|
||||
removePhysReg(i);
|
||||
}
|
||||
}
|
||||
|
||||
/// runOnMachineFunction - Register allocate the whole function
|
||||
///
|
||||
bool RABigBlock::runOnMachineFunction(MachineFunction &Fn) {
|
||||
DOUT << "Machine Function " << "\n";
|
||||
MF = &Fn;
|
||||
TM = &Fn.getTarget();
|
||||
RegInfo = TM->getRegisterInfo();
|
||||
|
||||
PhysRegsUsed.assign(RegInfo->getNumRegs(), -1);
|
||||
|
||||
// At various places we want to efficiently check to see whether a register
|
||||
// is allocatable. To handle this, we mark all unallocatable registers as
|
||||
// being pinned down, permanently.
|
||||
{
|
||||
BitVector Allocable = RegInfo->getAllocatableSet(Fn);
|
||||
for (unsigned i = 0, e = Allocable.size(); i != e; ++i)
|
||||
if (!Allocable[i])
|
||||
PhysRegsUsed[i] = -2; // Mark the reg unallocable.
|
||||
}
|
||||
|
||||
// initialize the virtual->physical register map to have a 'null'
|
||||
// mapping for all virtual registers
|
||||
Virt2PhysRegMap.grow(MF->getRegInfo().getLastVirtReg());
|
||||
StackSlotForVirtReg.grow(MF->getRegInfo().getLastVirtReg());
|
||||
VirtRegModified.resize(MF->getRegInfo().getLastVirtReg() -
|
||||
TargetRegisterInfo::FirstVirtualRegister + 1, 0);
|
||||
|
||||
// Loop over all of the basic blocks, eliminating virtual register references
|
||||
for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end();
|
||||
MBB != MBBe; ++MBB) {
|
||||
// fill out the read timetable
|
||||
FillVRegReadTable(*MBB);
|
||||
// use it to allocate the BB
|
||||
AllocateBasicBlock(*MBB);
|
||||
// clear it
|
||||
VRegReadTable.clear();
|
||||
}
|
||||
|
||||
StackSlotForVirtReg.clear();
|
||||
PhysRegsUsed.clear();
|
||||
VirtRegModified.clear();
|
||||
Virt2PhysRegMap.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
FunctionPass *llvm::createBigBlockRegisterAllocator() {
|
||||
return new RABigBlock();
|
||||
}
|
||||
|
@ -1,257 +0,0 @@
|
||||
//===-- RegAllocSimple.cpp - A simple generic register allocator ----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements a simple register allocator. *Very* simple: It immediate
|
||||
// spills every value right after it is computed, and it reloads all used
|
||||
// operands from the spill area to temporary registers before each instruction.
|
||||
// It does not keep values in registers across instructions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define DEBUG_TYPE "regalloc"
|
||||
#include "llvm/CodeGen/Passes.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/CodeGen/RegAllocRegistry.h"
|
||||
#include "llvm/Target/TargetInstrInfo.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include <map>
|
||||
using namespace llvm;
|
||||
|
||||
STATISTIC(NumStores, "Number of stores added");
|
||||
STATISTIC(NumLoads , "Number of loads added");
|
||||
|
||||
namespace {
|
||||
static RegisterRegAlloc
|
||||
simpleRegAlloc("simple", "simple register allocator",
|
||||
createSimpleRegisterAllocator);
|
||||
|
||||
class VISIBILITY_HIDDEN RegAllocSimple : public MachineFunctionPass {
|
||||
public:
|
||||
static char ID;
|
||||
RegAllocSimple() : MachineFunctionPass(&ID) {}
|
||||
private:
|
||||
MachineFunction *MF;
|
||||
const TargetMachine *TM;
|
||||
const TargetRegisterInfo *TRI;
|
||||
const TargetInstrInfo *TII;
|
||||
|
||||
// StackSlotForVirtReg - Maps SSA Regs => frame index on the stack where
|
||||
// these values are spilled
|
||||
std::map<unsigned, int> StackSlotForVirtReg;
|
||||
|
||||
// RegsUsed - Keep track of what registers are currently in use. This is a
|
||||
// bitset.
|
||||
std::vector<bool> RegsUsed;
|
||||
|
||||
// RegClassIdx - Maps RegClass => which index we can take a register
|
||||
// from. Since this is a simple register allocator, when we need a register
|
||||
// of a certain class, we just take the next available one.
|
||||
std::map<const TargetRegisterClass*, unsigned> RegClassIdx;
|
||||
|
||||
public:
|
||||
virtual const char *getPassName() const {
|
||||
return "Simple Register Allocator";
|
||||
}
|
||||
|
||||
/// runOnMachineFunction - Register allocate the whole function
|
||||
bool runOnMachineFunction(MachineFunction &Fn);
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.addRequiredID(PHIEliminationID); // Eliminate PHI nodes
|
||||
MachineFunctionPass::getAnalysisUsage(AU);
|
||||
}
|
||||
private:
|
||||
/// AllocateBasicBlock - Register allocate the specified basic block.
|
||||
void AllocateBasicBlock(MachineBasicBlock &MBB);
|
||||
|
||||
/// getStackSpaceFor - This returns the offset of the specified virtual
|
||||
/// register on the stack, allocating space if necessary.
|
||||
int getStackSpaceFor(unsigned VirtReg, const TargetRegisterClass *RC);
|
||||
|
||||
/// Given a virtual register, return a compatible physical register that is
|
||||
/// currently unused.
|
||||
///
|
||||
/// Side effect: marks that register as being used until manually cleared
|
||||
///
|
||||
unsigned getFreeReg(unsigned virtualReg);
|
||||
|
||||
/// Moves value from memory into that register
|
||||
unsigned reloadVirtReg(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator I, unsigned VirtReg);
|
||||
|
||||
/// Saves reg value on the stack (maps virtual register to stack value)
|
||||
void spillVirtReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
|
||||
unsigned VirtReg, unsigned PhysReg);
|
||||
};
|
||||
char RegAllocSimple::ID = 0;
|
||||
}
|
||||
|
||||
/// getStackSpaceFor - This allocates space for the specified virtual
|
||||
/// register to be held on the stack.
|
||||
int RegAllocSimple::getStackSpaceFor(unsigned VirtReg,
|
||||
const TargetRegisterClass *RC) {
|
||||
// Find the location VirtReg would belong...
|
||||
std::map<unsigned, int>::iterator I = StackSlotForVirtReg.find(VirtReg);
|
||||
|
||||
if (I != StackSlotForVirtReg.end())
|
||||
return I->second; // Already has space allocated?
|
||||
|
||||
// Allocate a new stack object for this spill location...
|
||||
int FrameIdx = MF->getFrameInfo()->CreateStackObject(RC->getSize(),
|
||||
RC->getAlignment());
|
||||
|
||||
// Assign the slot...
|
||||
StackSlotForVirtReg.insert(I, std::make_pair(VirtReg, FrameIdx));
|
||||
|
||||
return FrameIdx;
|
||||
}
|
||||
|
||||
unsigned RegAllocSimple::getFreeReg(unsigned virtualReg) {
|
||||
const TargetRegisterClass* RC = MF->getRegInfo().getRegClass(virtualReg);
|
||||
TargetRegisterClass::iterator RI = RC->allocation_order_begin(*MF);
|
||||
#ifndef NDEBUG
|
||||
TargetRegisterClass::iterator RE = RC->allocation_order_end(*MF);
|
||||
#endif
|
||||
|
||||
while (1) {
|
||||
unsigned regIdx = RegClassIdx[RC]++;
|
||||
assert(RI+regIdx != RE && "Not enough registers!");
|
||||
unsigned PhysReg = *(RI+regIdx);
|
||||
|
||||
if (!RegsUsed[PhysReg]) {
|
||||
MF->getRegInfo().setPhysRegUsed(PhysReg);
|
||||
return PhysReg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned RegAllocSimple::reloadVirtReg(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator I,
|
||||
unsigned VirtReg) {
|
||||
const TargetRegisterClass* RC = MF->getRegInfo().getRegClass(VirtReg);
|
||||
int FrameIdx = getStackSpaceFor(VirtReg, RC);
|
||||
unsigned PhysReg = getFreeReg(VirtReg);
|
||||
|
||||
// Add move instruction(s)
|
||||
++NumLoads;
|
||||
TII->loadRegFromStackSlot(MBB, I, PhysReg, FrameIdx, RC);
|
||||
return PhysReg;
|
||||
}
|
||||
|
||||
void RegAllocSimple::spillVirtReg(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator I,
|
||||
unsigned VirtReg, unsigned PhysReg) {
|
||||
const TargetRegisterClass* RC = MF->getRegInfo().getRegClass(VirtReg);
|
||||
|
||||
int FrameIdx = getStackSpaceFor(VirtReg, RC);
|
||||
|
||||
// Add move instruction(s)
|
||||
++NumStores;
|
||||
TII->storeRegToStackSlot(MBB, I, PhysReg, true, FrameIdx, RC);
|
||||
}
|
||||
|
||||
|
||||
void RegAllocSimple::AllocateBasicBlock(MachineBasicBlock &MBB) {
|
||||
// loop over each instruction
|
||||
for (MachineBasicBlock::iterator MI = MBB.begin(); MI != MBB.end(); ++MI) {
|
||||
// Made to combat the incorrect allocation of r2 = add r1, r1
|
||||
std::map<unsigned, unsigned> Virt2PhysRegMap;
|
||||
|
||||
RegsUsed.resize(TRI->getNumRegs());
|
||||
|
||||
// This is a preliminary pass that will invalidate any registers that are
|
||||
// used by the instruction (including implicit uses).
|
||||
const TargetInstrDesc &Desc = MI->getDesc();
|
||||
const unsigned *Regs;
|
||||
if (Desc.ImplicitUses) {
|
||||
for (Regs = Desc.ImplicitUses; *Regs; ++Regs)
|
||||
RegsUsed[*Regs] = true;
|
||||
}
|
||||
|
||||
if (Desc.ImplicitDefs) {
|
||||
for (Regs = Desc.ImplicitDefs; *Regs; ++Regs) {
|
||||
RegsUsed[*Regs] = true;
|
||||
MF->getRegInfo().setPhysRegUsed(*Regs);
|
||||
}
|
||||
}
|
||||
|
||||
// Loop over uses, move from memory into registers.
|
||||
for (int i = MI->getNumOperands() - 1; i >= 0; --i) {
|
||||
MachineOperand &MO = MI->getOperand(i);
|
||||
|
||||
if (MO.isReg() && MO.getReg() &&
|
||||
TargetRegisterInfo::isVirtualRegister(MO.getReg())) {
|
||||
unsigned virtualReg = (unsigned) MO.getReg();
|
||||
DOUT << "op: " << MO << "\n";
|
||||
DOUT << "\t inst[" << i << "]: ";
|
||||
DEBUG(MI->print(*cerr.stream(), TM));
|
||||
|
||||
// make sure the same virtual register maps to the same physical
|
||||
// register in any given instruction
|
||||
unsigned physReg = Virt2PhysRegMap[virtualReg];
|
||||
if (physReg == 0) {
|
||||
if (MO.isDef()) {
|
||||
unsigned TiedOp;
|
||||
if (!MI->isRegTiedToUseOperand(i, &TiedOp)) {
|
||||
physReg = getFreeReg(virtualReg);
|
||||
} else {
|
||||
// must be same register number as the source operand that is
|
||||
// tied to. This maps a = b + c into b = b + c, and saves b into
|
||||
// a's spot.
|
||||
assert(MI->getOperand(TiedOp).isReg() &&
|
||||
MI->getOperand(TiedOp).getReg() &&
|
||||
MI->getOperand(TiedOp).isUse() &&
|
||||
"Two address instruction invalid!");
|
||||
|
||||
physReg = MI->getOperand(TiedOp).getReg();
|
||||
}
|
||||
spillVirtReg(MBB, next(MI), virtualReg, physReg);
|
||||
} else {
|
||||
physReg = reloadVirtReg(MBB, MI, virtualReg);
|
||||
Virt2PhysRegMap[virtualReg] = physReg;
|
||||
}
|
||||
}
|
||||
MO.setReg(physReg);
|
||||
DOUT << "virt: " << virtualReg << ", phys: " << MO.getReg() << "\n";
|
||||
}
|
||||
}
|
||||
RegClassIdx.clear();
|
||||
RegsUsed.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// runOnMachineFunction - Register allocate the whole function
|
||||
///
|
||||
bool RegAllocSimple::runOnMachineFunction(MachineFunction &Fn) {
|
||||
DOUT << "Machine Function\n";
|
||||
MF = &Fn;
|
||||
TM = &MF->getTarget();
|
||||
TRI = TM->getRegisterInfo();
|
||||
TII = TM->getInstrInfo();
|
||||
|
||||
// Loop over all of the basic blocks, eliminating virtual register references
|
||||
for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end();
|
||||
MBB != MBBe; ++MBB)
|
||||
AllocateBasicBlock(*MBB);
|
||||
|
||||
StackSlotForVirtReg.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
FunctionPass *llvm::createSimpleRegisterAllocator() {
|
||||
return new RegAllocSimple();
|
||||
}
|
@ -1,671 +0,0 @@
|
||||
//===---- ScheduleDAGEmit.cpp - Emit routines for the ScheduleDAG class ---===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This implements the Emit routines for the ScheduleDAG class, which creates
|
||||
// MachineInstrs according to the computed schedule.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define DEBUG_TYPE "pre-RA-sched"
|
||||
#include "ScheduleDAGSDNodes.h"
|
||||
#include "llvm/CodeGen/MachineConstantPool.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/Target/TargetData.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Target/TargetInstrInfo.h"
|
||||
#include "llvm/Target/TargetLowering.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
using namespace llvm;
|
||||
|
||||
/// EmitCopyFromReg - Generate machine code for an CopyFromReg node or an
|
||||
/// implicit physical register output.
|
||||
void ScheduleDAGSDNodes::
|
||||
EmitCopyFromReg(SDNode *Node, unsigned ResNo, bool IsClone, bool IsCloned,
|
||||
unsigned SrcReg, DenseMap<SDValue, unsigned> &VRBaseMap) {
|
||||
unsigned VRBase = 0;
|
||||
if (TargetRegisterInfo::isVirtualRegister(SrcReg)) {
|
||||
// Just use the input register directly!
|
||||
SDValue Op(Node, ResNo);
|
||||
if (IsClone)
|
||||
VRBaseMap.erase(Op);
|
||||
bool isNew = VRBaseMap.insert(std::make_pair(Op, SrcReg)).second;
|
||||
isNew = isNew; // Silence compiler warning.
|
||||
assert(isNew && "Node emitted out of order - early");
|
||||
return;
|
||||
}
|
||||
|
||||
// If the node is only used by a CopyToReg and the dest reg is a vreg, use
|
||||
// the CopyToReg'd destination register instead of creating a new vreg.
|
||||
bool MatchReg = true;
|
||||
const TargetRegisterClass *UseRC = NULL;
|
||||
if (!IsClone && !IsCloned)
|
||||
for (SDNode::use_iterator UI = Node->use_begin(), E = Node->use_end();
|
||||
UI != E; ++UI) {
|
||||
SDNode *User = *UI;
|
||||
bool Match = true;
|
||||
if (User->getOpcode() == ISD::CopyToReg &&
|
||||
User->getOperand(2).getNode() == Node &&
|
||||
User->getOperand(2).getResNo() == ResNo) {
|
||||
unsigned DestReg = cast<RegisterSDNode>(User->getOperand(1))->getReg();
|
||||
if (TargetRegisterInfo::isVirtualRegister(DestReg)) {
|
||||
VRBase = DestReg;
|
||||
Match = false;
|
||||
} else if (DestReg != SrcReg)
|
||||
Match = false;
|
||||
} else {
|
||||
for (unsigned i = 0, e = User->getNumOperands(); i != e; ++i) {
|
||||
SDValue Op = User->getOperand(i);
|
||||
if (Op.getNode() != Node || Op.getResNo() != ResNo)
|
||||
continue;
|
||||
MVT VT = Node->getValueType(Op.getResNo());
|
||||
if (VT == MVT::Other || VT == MVT::Flag)
|
||||
continue;
|
||||
Match = false;
|
||||
if (User->isMachineOpcode()) {
|
||||
const TargetInstrDesc &II = TII->get(User->getMachineOpcode());
|
||||
const TargetRegisterClass *RC =
|
||||
getInstrOperandRegClass(TRI, II, i+II.getNumDefs());
|
||||
if (!UseRC)
|
||||
UseRC = RC;
|
||||
else if (RC) {
|
||||
if (UseRC->hasSuperClass(RC))
|
||||
UseRC = RC;
|
||||
else
|
||||
assert((UseRC == RC || RC->hasSuperClass(UseRC)) &&
|
||||
"Multiple uses expecting different register classes!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MatchReg &= Match;
|
||||
if (VRBase)
|
||||
break;
|
||||
}
|
||||
|
||||
MVT VT = Node->getValueType(ResNo);
|
||||
const TargetRegisterClass *SrcRC = 0, *DstRC = 0;
|
||||
SrcRC = TRI->getPhysicalRegisterRegClass(SrcReg, VT);
|
||||
|
||||
// Figure out the register class to create for the destreg.
|
||||
if (VRBase) {
|
||||
DstRC = MRI.getRegClass(VRBase);
|
||||
} else if (UseRC) {
|
||||
assert(UseRC->hasType(VT) && "Incompatible phys register def and uses!");
|
||||
DstRC = UseRC;
|
||||
} else {
|
||||
DstRC = TLI->getRegClassFor(VT);
|
||||
}
|
||||
|
||||
// If all uses are reading from the src physical register and copying the
|
||||
// register is either impossible or very expensive, then don't create a copy.
|
||||
if (MatchReg && SrcRC->getCopyCost() < 0) {
|
||||
VRBase = SrcReg;
|
||||
} else {
|
||||
// Create the reg, emit the copy.
|
||||
VRBase = MRI.createVirtualRegister(DstRC);
|
||||
bool Emitted = TII->copyRegToReg(*BB, InsertPos, VRBase, SrcReg,
|
||||
DstRC, SrcRC);
|
||||
|
||||
assert(Emitted && "Unable to issue a copy instruction!\n");
|
||||
(void) Emitted;
|
||||
}
|
||||
|
||||
SDValue Op(Node, ResNo);
|
||||
if (IsClone)
|
||||
VRBaseMap.erase(Op);
|
||||
bool isNew = VRBaseMap.insert(std::make_pair(Op, VRBase)).second;
|
||||
isNew = isNew; // Silence compiler warning.
|
||||
assert(isNew && "Node emitted out of order - early");
|
||||
}
|
||||
|
||||
/// getDstOfCopyToRegUse - If the only use of the specified result number of
|
||||
/// node is a CopyToReg, return its destination register. Return 0 otherwise.
|
||||
unsigned ScheduleDAGSDNodes::getDstOfOnlyCopyToRegUse(SDNode *Node,
|
||||
unsigned ResNo) const {
|
||||
if (!Node->hasOneUse())
|
||||
return 0;
|
||||
|
||||
SDNode *User = *Node->use_begin();
|
||||
if (User->getOpcode() == ISD::CopyToReg &&
|
||||
User->getOperand(2).getNode() == Node &&
|
||||
User->getOperand(2).getResNo() == ResNo) {
|
||||
unsigned Reg = cast<RegisterSDNode>(User->getOperand(1))->getReg();
|
||||
if (TargetRegisterInfo::isVirtualRegister(Reg))
|
||||
return Reg;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ScheduleDAGSDNodes::CreateVirtualRegisters(SDNode *Node, MachineInstr *MI,
|
||||
const TargetInstrDesc &II,
|
||||
bool IsClone, bool IsCloned,
|
||||
DenseMap<SDValue, unsigned> &VRBaseMap) {
|
||||
assert(Node->getMachineOpcode() != TargetInstrInfo::IMPLICIT_DEF &&
|
||||
"IMPLICIT_DEF should have been handled as a special case elsewhere!");
|
||||
|
||||
for (unsigned i = 0; i < II.getNumDefs(); ++i) {
|
||||
// If the specific node value is only used by a CopyToReg and the dest reg
|
||||
// is a vreg in the same register class, use the CopyToReg'd destination
|
||||
// register instead of creating a new vreg.
|
||||
unsigned VRBase = 0;
|
||||
const TargetRegisterClass *RC = getInstrOperandRegClass(TRI, II, i);
|
||||
|
||||
if (!IsClone && !IsCloned)
|
||||
for (SDNode::use_iterator UI = Node->use_begin(), E = Node->use_end();
|
||||
UI != E; ++UI) {
|
||||
SDNode *User = *UI;
|
||||
if (User->getOpcode() == ISD::CopyToReg &&
|
||||
User->getOperand(2).getNode() == Node &&
|
||||
User->getOperand(2).getResNo() == i) {
|
||||
unsigned Reg = cast<RegisterSDNode>(User->getOperand(1))->getReg();
|
||||
if (TargetRegisterInfo::isVirtualRegister(Reg)) {
|
||||
const TargetRegisterClass *RegRC = MRI.getRegClass(Reg);
|
||||
if (RegRC == RC) {
|
||||
VRBase = Reg;
|
||||
MI->addOperand(MachineOperand::CreateReg(Reg, true));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the result registers for this node and add the result regs to
|
||||
// the machine instruction.
|
||||
if (VRBase == 0) {
|
||||
assert(RC && "Isn't a register operand!");
|
||||
VRBase = MRI.createVirtualRegister(RC);
|
||||
MI->addOperand(MachineOperand::CreateReg(VRBase, true));
|
||||
}
|
||||
|
||||
SDValue Op(Node, i);
|
||||
if (IsClone)
|
||||
VRBaseMap.erase(Op);
|
||||
bool isNew = VRBaseMap.insert(std::make_pair(Op, VRBase)).second;
|
||||
isNew = isNew; // Silence compiler warning.
|
||||
assert(isNew && "Node emitted out of order - early");
|
||||
}
|
||||
}
|
||||
|
||||
/// getVR - Return the virtual register corresponding to the specified result
|
||||
/// of the specified node.
|
||||
unsigned ScheduleDAGSDNodes::getVR(SDValue Op,
|
||||
DenseMap<SDValue, unsigned> &VRBaseMap) {
|
||||
if (Op.isMachineOpcode() &&
|
||||
Op.getMachineOpcode() == TargetInstrInfo::IMPLICIT_DEF) {
|
||||
// Add an IMPLICIT_DEF instruction before every use.
|
||||
unsigned VReg = getDstOfOnlyCopyToRegUse(Op.getNode(), Op.getResNo());
|
||||
// IMPLICIT_DEF can produce any type of result so its TargetInstrDesc
|
||||
// does not include operand register class info.
|
||||
if (!VReg) {
|
||||
const TargetRegisterClass *RC = TLI->getRegClassFor(Op.getValueType());
|
||||
VReg = MRI.createVirtualRegister(RC);
|
||||
}
|
||||
BuildMI(BB, Op.getDebugLoc(), TII->get(TargetInstrInfo::IMPLICIT_DEF),VReg);
|
||||
return VReg;
|
||||
}
|
||||
|
||||
DenseMap<SDValue, unsigned>::iterator I = VRBaseMap.find(Op);
|
||||
assert(I != VRBaseMap.end() && "Node emitted out of order - late");
|
||||
return I->second;
|
||||
}
|
||||
|
||||
|
||||
/// AddRegisterOperand - Add the specified register as an operand to the
|
||||
/// specified machine instr. Insert register copies if the register is
|
||||
/// not in the required register class.
|
||||
void
|
||||
ScheduleDAGSDNodes::AddRegisterOperand(MachineInstr *MI, SDValue Op,
|
||||
unsigned IIOpNum,
|
||||
const TargetInstrDesc *II,
|
||||
DenseMap<SDValue, unsigned> &VRBaseMap) {
|
||||
assert(Op.getValueType() != MVT::Other &&
|
||||
Op.getValueType() != MVT::Flag &&
|
||||
"Chain and flag operands should occur at end of operand list!");
|
||||
// Get/emit the operand.
|
||||
unsigned VReg = getVR(Op, VRBaseMap);
|
||||
assert(TargetRegisterInfo::isVirtualRegister(VReg) && "Not a vreg?");
|
||||
|
||||
const TargetInstrDesc &TID = MI->getDesc();
|
||||
bool isOptDef = IIOpNum < TID.getNumOperands() &&
|
||||
TID.OpInfo[IIOpNum].isOptionalDef();
|
||||
|
||||
// If the instruction requires a register in a different class, create
|
||||
// a new virtual register and copy the value into it.
|
||||
if (II) {
|
||||
const TargetRegisterClass *SrcRC =
|
||||
MRI.getRegClass(VReg);
|
||||
const TargetRegisterClass *DstRC =
|
||||
getInstrOperandRegClass(TRI, *II, IIOpNum);
|
||||
assert((DstRC || (TID.isVariadic() && IIOpNum >= TID.getNumOperands())) &&
|
||||
"Don't have operand info for this instruction!");
|
||||
if (DstRC && SrcRC != DstRC && !SrcRC->hasSuperClass(DstRC)) {
|
||||
unsigned NewVReg = MRI.createVirtualRegister(DstRC);
|
||||
bool Emitted = TII->copyRegToReg(*BB, InsertPos, NewVReg, VReg,
|
||||
DstRC, SrcRC);
|
||||
assert(Emitted && "Unable to issue a copy instruction!\n");
|
||||
(void) Emitted;
|
||||
VReg = NewVReg;
|
||||
}
|
||||
}
|
||||
|
||||
MI->addOperand(MachineOperand::CreateReg(VReg, isOptDef));
|
||||
}
|
||||
|
||||
/// AddOperand - Add the specified operand to the specified machine instr. II
|
||||
/// specifies the instruction information for the node, and IIOpNum is the
|
||||
/// operand number (in the II) that we are adding. IIOpNum and II are used for
|
||||
/// assertions only.
|
||||
void ScheduleDAGSDNodes::AddOperand(MachineInstr *MI, SDValue Op,
|
||||
unsigned IIOpNum,
|
||||
const TargetInstrDesc *II,
|
||||
DenseMap<SDValue, unsigned> &VRBaseMap) {
|
||||
if (Op.isMachineOpcode()) {
|
||||
AddRegisterOperand(MI, Op, IIOpNum, II, VRBaseMap);
|
||||
} else if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) {
|
||||
MI->addOperand(MachineOperand::CreateImm(C->getZExtValue()));
|
||||
} else if (ConstantFPSDNode *F = dyn_cast<ConstantFPSDNode>(Op)) {
|
||||
const ConstantFP *CFP = F->getConstantFPValue();
|
||||
MI->addOperand(MachineOperand::CreateFPImm(CFP));
|
||||
} else if (RegisterSDNode *R = dyn_cast<RegisterSDNode>(Op)) {
|
||||
MI->addOperand(MachineOperand::CreateReg(R->getReg(), false));
|
||||
} else if (GlobalAddressSDNode *TGA = dyn_cast<GlobalAddressSDNode>(Op)) {
|
||||
MI->addOperand(MachineOperand::CreateGA(TGA->getGlobal(), TGA->getOffset(),
|
||||
TGA->getTargetFlags()));
|
||||
} else if (BasicBlockSDNode *BBNode = dyn_cast<BasicBlockSDNode>(Op)) {
|
||||
MI->addOperand(MachineOperand::CreateMBB(BBNode->getBasicBlock()));
|
||||
} else if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(Op)) {
|
||||
MI->addOperand(MachineOperand::CreateFI(FI->getIndex()));
|
||||
} else if (JumpTableSDNode *JT = dyn_cast<JumpTableSDNode>(Op)) {
|
||||
MI->addOperand(MachineOperand::CreateJTI(JT->getIndex(),
|
||||
JT->getTargetFlags()));
|
||||
} else if (ConstantPoolSDNode *CP = dyn_cast<ConstantPoolSDNode>(Op)) {
|
||||
int Offset = CP->getOffset();
|
||||
unsigned Align = CP->getAlignment();
|
||||
const Type *Type = CP->getType();
|
||||
// MachineConstantPool wants an explicit alignment.
|
||||
if (Align == 0) {
|
||||
Align = TM.getTargetData()->getPrefTypeAlignment(Type);
|
||||
if (Align == 0) {
|
||||
// Alignment of vector types. FIXME!
|
||||
Align = TM.getTargetData()->getTypeAllocSize(Type);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned Idx;
|
||||
if (CP->isMachineConstantPoolEntry())
|
||||
Idx = ConstPool->getConstantPoolIndex(CP->getMachineCPVal(), Align);
|
||||
else
|
||||
Idx = ConstPool->getConstantPoolIndex(CP->getConstVal(), Align);
|
||||
MI->addOperand(MachineOperand::CreateCPI(Idx, Offset,
|
||||
CP->getTargetFlags()));
|
||||
} else if (ExternalSymbolSDNode *ES = dyn_cast<ExternalSymbolSDNode>(Op)) {
|
||||
MI->addOperand(MachineOperand::CreateES(ES->getSymbol(), 0,
|
||||
ES->getTargetFlags()));
|
||||
} else {
|
||||
assert(Op.getValueType() != MVT::Other &&
|
||||
Op.getValueType() != MVT::Flag &&
|
||||
"Chain and flag operands should occur at end of operand list!");
|
||||
AddRegisterOperand(MI, Op, IIOpNum, II, VRBaseMap);
|
||||
}
|
||||
}
|
||||
|
||||
/// getSuperRegisterRegClass - Returns the register class of a superreg A whose
|
||||
/// "SubIdx"'th sub-register class is the specified register class and whose
|
||||
/// type matches the specified type.
|
||||
static const TargetRegisterClass*
|
||||
getSuperRegisterRegClass(const TargetRegisterClass *TRC,
|
||||
unsigned SubIdx, MVT VT) {
|
||||
// Pick the register class of the superegister for this type
|
||||
for (TargetRegisterInfo::regclass_iterator I = TRC->superregclasses_begin(),
|
||||
E = TRC->superregclasses_end(); I != E; ++I)
|
||||
if ((*I)->hasType(VT) && (*I)->getSubRegisterRegClass(SubIdx) == TRC)
|
||||
return *I;
|
||||
assert(false && "Couldn't find the register class");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// EmitSubregNode - Generate machine code for subreg nodes.
|
||||
///
|
||||
void ScheduleDAGSDNodes::EmitSubregNode(SDNode *Node,
|
||||
DenseMap<SDValue, unsigned> &VRBaseMap){
|
||||
unsigned VRBase = 0;
|
||||
unsigned Opc = Node->getMachineOpcode();
|
||||
|
||||
// If the node is only used by a CopyToReg and the dest reg is a vreg, use
|
||||
// the CopyToReg'd destination register instead of creating a new vreg.
|
||||
for (SDNode::use_iterator UI = Node->use_begin(), E = Node->use_end();
|
||||
UI != E; ++UI) {
|
||||
SDNode *User = *UI;
|
||||
if (User->getOpcode() == ISD::CopyToReg &&
|
||||
User->getOperand(2).getNode() == Node) {
|
||||
unsigned DestReg = cast<RegisterSDNode>(User->getOperand(1))->getReg();
|
||||
if (TargetRegisterInfo::isVirtualRegister(DestReg)) {
|
||||
VRBase = DestReg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Opc == TargetInstrInfo::EXTRACT_SUBREG) {
|
||||
unsigned SubIdx = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue();
|
||||
|
||||
// Create the extract_subreg machine instruction.
|
||||
MachineInstr *MI = BuildMI(MF, Node->getDebugLoc(),
|
||||
TII->get(TargetInstrInfo::EXTRACT_SUBREG));
|
||||
|
||||
// Figure out the register class to create for the destreg.
|
||||
unsigned VReg = getVR(Node->getOperand(0), VRBaseMap);
|
||||
const TargetRegisterClass *TRC = MRI.getRegClass(VReg);
|
||||
const TargetRegisterClass *SRC = TRC->getSubRegisterRegClass(SubIdx);
|
||||
assert(SRC && "Invalid subregister index in EXTRACT_SUBREG");
|
||||
|
||||
// Figure out the register class to create for the destreg.
|
||||
// Note that if we're going to directly use an existing register,
|
||||
// it must be precisely the required class, and not a subclass
|
||||
// thereof.
|
||||
if (VRBase == 0 || SRC != MRI.getRegClass(VRBase)) {
|
||||
// Create the reg
|
||||
assert(SRC && "Couldn't find source register class");
|
||||
VRBase = MRI.createVirtualRegister(SRC);
|
||||
}
|
||||
|
||||
// Add def, source, and subreg index
|
||||
MI->addOperand(MachineOperand::CreateReg(VRBase, true));
|
||||
AddOperand(MI, Node->getOperand(0), 0, 0, VRBaseMap);
|
||||
MI->addOperand(MachineOperand::CreateImm(SubIdx));
|
||||
BB->insert(InsertPos, MI);
|
||||
} else if (Opc == TargetInstrInfo::INSERT_SUBREG ||
|
||||
Opc == TargetInstrInfo::SUBREG_TO_REG) {
|
||||
SDValue N0 = Node->getOperand(0);
|
||||
SDValue N1 = Node->getOperand(1);
|
||||
SDValue N2 = Node->getOperand(2);
|
||||
unsigned SubReg = getVR(N1, VRBaseMap);
|
||||
unsigned SubIdx = cast<ConstantSDNode>(N2)->getZExtValue();
|
||||
const TargetRegisterClass *TRC = MRI.getRegClass(SubReg);
|
||||
const TargetRegisterClass *SRC =
|
||||
getSuperRegisterRegClass(TRC, SubIdx,
|
||||
Node->getValueType(0));
|
||||
|
||||
// Figure out the register class to create for the destreg.
|
||||
// Note that if we're going to directly use an existing register,
|
||||
// it must be precisely the required class, and not a subclass
|
||||
// thereof.
|
||||
if (VRBase == 0 || SRC != MRI.getRegClass(VRBase)) {
|
||||
// Create the reg
|
||||
assert(SRC && "Couldn't find source register class");
|
||||
VRBase = MRI.createVirtualRegister(SRC);
|
||||
}
|
||||
|
||||
// Create the insert_subreg or subreg_to_reg machine instruction.
|
||||
MachineInstr *MI = BuildMI(MF, Node->getDebugLoc(), TII->get(Opc));
|
||||
MI->addOperand(MachineOperand::CreateReg(VRBase, true));
|
||||
|
||||
// If creating a subreg_to_reg, then the first input operand
|
||||
// is an implicit value immediate, otherwise it's a register
|
||||
if (Opc == TargetInstrInfo::SUBREG_TO_REG) {
|
||||
const ConstantSDNode *SD = cast<ConstantSDNode>(N0);
|
||||
MI->addOperand(MachineOperand::CreateImm(SD->getZExtValue()));
|
||||
} else
|
||||
AddOperand(MI, N0, 0, 0, VRBaseMap);
|
||||
// Add the subregster being inserted
|
||||
AddOperand(MI, N1, 0, 0, VRBaseMap);
|
||||
MI->addOperand(MachineOperand::CreateImm(SubIdx));
|
||||
BB->insert(InsertPos, MI);
|
||||
} else
|
||||
assert(0 && "Node is not insert_subreg, extract_subreg, or subreg_to_reg");
|
||||
|
||||
SDValue Op(Node, 0);
|
||||
bool isNew = VRBaseMap.insert(std::make_pair(Op, VRBase)).second;
|
||||
isNew = isNew; // Silence compiler warning.
|
||||
assert(isNew && "Node emitted out of order - early");
|
||||
}
|
||||
|
||||
/// EmitCopyToRegClassNode - Generate machine code for COPY_TO_REGCLASS nodes.
|
||||
/// COPY_TO_REGCLASS is just a normal copy, except that the destination
|
||||
/// register is constrained to be in a particular register class.
|
||||
///
|
||||
void
|
||||
ScheduleDAGSDNodes::EmitCopyToRegClassNode(SDNode *Node,
|
||||
DenseMap<SDValue, unsigned> &VRBaseMap) {
|
||||
unsigned VReg = getVR(Node->getOperand(0), VRBaseMap);
|
||||
const TargetRegisterClass *SrcRC = MRI.getRegClass(VReg);
|
||||
|
||||
unsigned DstRCIdx = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue();
|
||||
const TargetRegisterClass *DstRC = TRI->getRegClass(DstRCIdx);
|
||||
|
||||
// Create the new VReg in the destination class and emit a copy.
|
||||
unsigned NewVReg = MRI.createVirtualRegister(DstRC);
|
||||
bool Emitted = TII->copyRegToReg(*BB, InsertPos, NewVReg, VReg,
|
||||
DstRC, SrcRC);
|
||||
assert(Emitted &&
|
||||
"Unable to issue a copy instruction for a COPY_TO_REGCLASS node!\n");
|
||||
(void) Emitted;
|
||||
|
||||
SDValue Op(Node, 0);
|
||||
bool isNew = VRBaseMap.insert(std::make_pair(Op, NewVReg)).second;
|
||||
isNew = isNew; // Silence compiler warning.
|
||||
assert(isNew && "Node emitted out of order - early");
|
||||
}
|
||||
|
||||
/// EmitNode - Generate machine code for an node and needed dependencies.
|
||||
///
|
||||
void ScheduleDAGSDNodes::EmitNode(SDNode *Node, bool IsClone, bool IsCloned,
|
||||
DenseMap<SDValue, unsigned> &VRBaseMap) {
|
||||
// If machine instruction
|
||||
if (Node->isMachineOpcode()) {
|
||||
unsigned Opc = Node->getMachineOpcode();
|
||||
|
||||
// Handle subreg insert/extract specially
|
||||
if (Opc == TargetInstrInfo::EXTRACT_SUBREG ||
|
||||
Opc == TargetInstrInfo::INSERT_SUBREG ||
|
||||
Opc == TargetInstrInfo::SUBREG_TO_REG) {
|
||||
EmitSubregNode(Node, VRBaseMap);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle COPY_TO_REGCLASS specially.
|
||||
if (Opc == TargetInstrInfo::COPY_TO_REGCLASS) {
|
||||
EmitCopyToRegClassNode(Node, VRBaseMap);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Opc == TargetInstrInfo::IMPLICIT_DEF)
|
||||
// We want a unique VR for each IMPLICIT_DEF use.
|
||||
return;
|
||||
|
||||
const TargetInstrDesc &II = TII->get(Opc);
|
||||
unsigned NumResults = CountResults(Node);
|
||||
unsigned NodeOperands = CountOperands(Node);
|
||||
unsigned MemOperandsEnd = ComputeMemOperandsEnd(Node);
|
||||
bool HasPhysRegOuts = (NumResults > II.getNumDefs()) &&
|
||||
II.getImplicitDefs() != 0;
|
||||
#ifndef NDEBUG
|
||||
unsigned NumMIOperands = NodeOperands + NumResults;
|
||||
assert((II.getNumOperands() == NumMIOperands ||
|
||||
HasPhysRegOuts || II.isVariadic()) &&
|
||||
"#operands for dag node doesn't match .td file!");
|
||||
#endif
|
||||
|
||||
// Create the new machine instruction.
|
||||
MachineInstr *MI = BuildMI(MF, Node->getDebugLoc(), II);
|
||||
|
||||
// Add result register values for things that are defined by this
|
||||
// instruction.
|
||||
if (NumResults)
|
||||
CreateVirtualRegisters(Node, MI, II, IsClone, IsCloned, VRBaseMap);
|
||||
|
||||
// Emit all of the actual operands of this instruction, adding them to the
|
||||
// instruction as appropriate.
|
||||
for (unsigned i = 0; i != NodeOperands; ++i)
|
||||
AddOperand(MI, Node->getOperand(i), i+II.getNumDefs(), &II, VRBaseMap);
|
||||
|
||||
// Emit all of the memory operands of this instruction
|
||||
for (unsigned i = NodeOperands; i != MemOperandsEnd; ++i)
|
||||
AddMemOperand(MI, cast<MemOperandSDNode>(Node->getOperand(i))->MO);
|
||||
|
||||
if (II.usesCustomDAGSchedInsertionHook()) {
|
||||
// Insert this instruction into the basic block using a target
|
||||
// specific inserter which may returns a new basic block.
|
||||
BB = TLI->EmitInstrWithCustomInserter(MI, BB);
|
||||
InsertPos = BB->end();
|
||||
} else {
|
||||
BB->insert(InsertPos, MI);
|
||||
}
|
||||
|
||||
// Additional results must be an physical register def.
|
||||
if (HasPhysRegOuts) {
|
||||
for (unsigned i = II.getNumDefs(); i < NumResults; ++i) {
|
||||
unsigned Reg = II.getImplicitDefs()[i - II.getNumDefs()];
|
||||
if (Node->hasAnyUseOfValue(i))
|
||||
EmitCopyFromReg(Node, i, IsClone, IsCloned, Reg, VRBaseMap);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (Node->getOpcode()) {
|
||||
default:
|
||||
#ifndef NDEBUG
|
||||
Node->dump(DAG);
|
||||
#endif
|
||||
assert(0 && "This target-independent node should have been selected!");
|
||||
break;
|
||||
case ISD::EntryToken:
|
||||
assert(0 && "EntryToken should have been excluded from the schedule!");
|
||||
break;
|
||||
case ISD::TokenFactor: // fall thru
|
||||
break;
|
||||
case ISD::CopyToReg: {
|
||||
unsigned SrcReg;
|
||||
SDValue SrcVal = Node->getOperand(2);
|
||||
if (RegisterSDNode *R = dyn_cast<RegisterSDNode>(SrcVal))
|
||||
SrcReg = R->getReg();
|
||||
else
|
||||
SrcReg = getVR(SrcVal, VRBaseMap);
|
||||
|
||||
unsigned DestReg = cast<RegisterSDNode>(Node->getOperand(1))->getReg();
|
||||
if (SrcReg == DestReg) // Coalesced away the copy? Ignore.
|
||||
break;
|
||||
|
||||
const TargetRegisterClass *SrcTRC = 0, *DstTRC = 0;
|
||||
// Get the register classes of the src/dst.
|
||||
if (TargetRegisterInfo::isVirtualRegister(SrcReg))
|
||||
SrcTRC = MRI.getRegClass(SrcReg);
|
||||
else
|
||||
SrcTRC = TRI->getPhysicalRegisterRegClass(SrcReg,SrcVal.getValueType());
|
||||
|
||||
if (TargetRegisterInfo::isVirtualRegister(DestReg))
|
||||
DstTRC = MRI.getRegClass(DestReg);
|
||||
else
|
||||
DstTRC = TRI->getPhysicalRegisterRegClass(DestReg,
|
||||
Node->getOperand(1).getValueType());
|
||||
|
||||
bool Emitted = TII->copyRegToReg(*BB, InsertPos, DestReg, SrcReg,
|
||||
DstTRC, SrcTRC);
|
||||
assert(Emitted && "Unable to issue a copy instruction!\n");
|
||||
(void) Emitted;
|
||||
break;
|
||||
}
|
||||
case ISD::CopyFromReg: {
|
||||
unsigned SrcReg = cast<RegisterSDNode>(Node->getOperand(1))->getReg();
|
||||
EmitCopyFromReg(Node, 0, IsClone, IsCloned, SrcReg, VRBaseMap);
|
||||
break;
|
||||
}
|
||||
case ISD::INLINEASM: {
|
||||
unsigned NumOps = Node->getNumOperands();
|
||||
if (Node->getOperand(NumOps-1).getValueType() == MVT::Flag)
|
||||
--NumOps; // Ignore the flag operand.
|
||||
|
||||
// Create the inline asm machine instruction.
|
||||
MachineInstr *MI = BuildMI(MF, Node->getDebugLoc(),
|
||||
TII->get(TargetInstrInfo::INLINEASM));
|
||||
|
||||
// Add the asm string as an external symbol operand.
|
||||
const char *AsmStr =
|
||||
cast<ExternalSymbolSDNode>(Node->getOperand(1))->getSymbol();
|
||||
MI->addOperand(MachineOperand::CreateES(AsmStr));
|
||||
|
||||
// Add all of the operand registers to the instruction.
|
||||
for (unsigned i = 2; i != NumOps;) {
|
||||
unsigned Flags =
|
||||
cast<ConstantSDNode>(Node->getOperand(i))->getZExtValue();
|
||||
unsigned NumVals = InlineAsm::getNumOperandRegisters(Flags);
|
||||
|
||||
MI->addOperand(MachineOperand::CreateImm(Flags));
|
||||
++i; // Skip the ID value.
|
||||
|
||||
switch (Flags & 7) {
|
||||
default: assert(0 && "Bad flags!");
|
||||
case 2: // Def of register.
|
||||
for (; NumVals; --NumVals, ++i) {
|
||||
unsigned Reg = cast<RegisterSDNode>(Node->getOperand(i))->getReg();
|
||||
MI->addOperand(MachineOperand::CreateReg(Reg, true));
|
||||
}
|
||||
break;
|
||||
case 6: // Def of earlyclobber register.
|
||||
for (; NumVals; --NumVals, ++i) {
|
||||
unsigned Reg = cast<RegisterSDNode>(Node->getOperand(i))->getReg();
|
||||
MI->addOperand(MachineOperand::CreateReg(Reg, true, false, false,
|
||||
false, false, true));
|
||||
}
|
||||
break;
|
||||
case 1: // Use of register.
|
||||
case 3: // Immediate.
|
||||
case 4: // Addressing mode.
|
||||
// The addressing mode has been selected, just add all of the
|
||||
// operands to the machine instruction.
|
||||
for (; NumVals; --NumVals, ++i)
|
||||
AddOperand(MI, Node->getOperand(i), 0, 0, VRBaseMap);
|
||||
break;
|
||||
}
|
||||
}
|
||||
BB->insert(InsertPos, MI);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// EmitSchedule - Emit the machine code in scheduled order.
|
||||
MachineBasicBlock *ScheduleDAGSDNodes::EmitSchedule() {
|
||||
DenseMap<SDValue, unsigned> VRBaseMap;
|
||||
DenseMap<SUnit*, unsigned> CopyVRBaseMap;
|
||||
for (unsigned i = 0, e = Sequence.size(); i != e; i++) {
|
||||
SUnit *SU = Sequence[i];
|
||||
if (!SU) {
|
||||
// Null SUnit* is a noop.
|
||||
EmitNoop();
|
||||
continue;
|
||||
}
|
||||
|
||||
// For pre-regalloc scheduling, create instructions corresponding to the
|
||||
// SDNode and any flagged SDNodes and append them to the block.
|
||||
if (!SU->getNode()) {
|
||||
// Emit a copy.
|
||||
EmitPhysRegCopy(SU, CopyVRBaseMap);
|
||||
continue;
|
||||
}
|
||||
|
||||
SmallVector<SDNode *, 4> FlaggedNodes;
|
||||
for (SDNode *N = SU->getNode()->getFlaggedNode(); N;
|
||||
N = N->getFlaggedNode())
|
||||
FlaggedNodes.push_back(N);
|
||||
while (!FlaggedNodes.empty()) {
|
||||
EmitNode(FlaggedNodes.back(), SU->OrigNode != SU, SU->isCloned,VRBaseMap);
|
||||
FlaggedNodes.pop_back();
|
||||
}
|
||||
EmitNode(SU->getNode(), SU->OrigNode != SU, SU->isCloned, VRBaseMap);
|
||||
}
|
||||
|
||||
return BB;
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
add_llvm_library(LLVMDebugger
|
||||
Debugger.cpp
|
||||
ProgramInfo.cpp
|
||||
RuntimeInfo.cpp
|
||||
SourceFile.cpp
|
||||
SourceLanguage-CFamily.cpp
|
||||
SourceLanguage-CPlusPlus.cpp
|
||||
SourceLanguage-Unknown.cpp
|
||||
SourceLanguage.cpp
|
||||
)
|
@ -1,231 +0,0 @@
|
||||
//===-- Debugger.cpp - LLVM debugger library implementation ---------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the main implementation of the LLVM debugger library.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Debugger/Debugger.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/ModuleProvider.h"
|
||||
#include "llvm/Bitcode/ReaderWriter.h"
|
||||
#include "llvm/Debugger/InferiorProcess.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
using namespace llvm;
|
||||
|
||||
/// Debugger constructor - Initialize the debugger to its initial, empty, state.
|
||||
///
|
||||
Debugger::Debugger() : Environment(0), Program(0), Process(0) {
|
||||
}
|
||||
|
||||
Debugger::~Debugger() {
|
||||
// Killing the program could throw an exception. We don't want to progagate
|
||||
// the exception out of our destructor though.
|
||||
try {
|
||||
killProgram();
|
||||
} catch (const char *) {
|
||||
} catch (const std::string &) {
|
||||
}
|
||||
|
||||
unloadProgram();
|
||||
}
|
||||
|
||||
/// getProgramPath - Get the path of the currently loaded program, or an
|
||||
/// empty string if none is loaded.
|
||||
std::string Debugger::getProgramPath() const {
|
||||
return Program ? Program->getModuleIdentifier() : "";
|
||||
}
|
||||
|
||||
static Module *
|
||||
getMaterializedModuleProvider(const std::string &Filename,
|
||||
LLVMContext& C) {
|
||||
std::auto_ptr<MemoryBuffer> Buffer;
|
||||
Buffer.reset(MemoryBuffer::getFileOrSTDIN(Filename.c_str()));
|
||||
if (Buffer.get())
|
||||
return ParseBitcodeFile(Buffer.get(), C);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// loadProgram - If a program is currently loaded, unload it. Then search
|
||||
/// the PATH for the specified program, loading it when found. If the
|
||||
/// specified program cannot be found, an exception is thrown to indicate the
|
||||
/// error.
|
||||
void Debugger::loadProgram(const std::string &Filename, LLVMContext& C) {
|
||||
if ((Program = getMaterializedModuleProvider(Filename, C)) ||
|
||||
(Program = getMaterializedModuleProvider(Filename+".bc", C)))
|
||||
return; // Successfully loaded the program.
|
||||
|
||||
// Search the program path for the file...
|
||||
if (const char *PathS = getenv("PATH")) {
|
||||
std::string Path = PathS;
|
||||
|
||||
std::string Directory = getToken(Path, ":");
|
||||
while (!Directory.empty()) {
|
||||
if ((Program = getMaterializedModuleProvider(Directory +"/"+ Filename, C))
|
||||
|| (Program = getMaterializedModuleProvider(Directory +"/"+ Filename
|
||||
+ ".bc", C)))
|
||||
return; // Successfully loaded the program.
|
||||
|
||||
Directory = getToken(Path, ":");
|
||||
}
|
||||
}
|
||||
|
||||
throw "Could not find program '" + Filename + "'!";
|
||||
}
|
||||
|
||||
/// unloadProgram - If a program is running, kill it, then unload all traces
|
||||
/// of the current program. If no program is loaded, this method silently
|
||||
/// succeeds.
|
||||
void Debugger::unloadProgram() {
|
||||
if (!isProgramLoaded()) return;
|
||||
killProgram();
|
||||
delete Program;
|
||||
Program = 0;
|
||||
}
|
||||
|
||||
|
||||
/// createProgram - Create an instance of the currently loaded program,
|
||||
/// killing off any existing one. This creates the program and stops it at
|
||||
/// the first possible moment. If there is no program loaded or if there is a
|
||||
/// problem starting the program, this method throws an exception.
|
||||
void Debugger::createProgram() {
|
||||
if (!isProgramLoaded())
|
||||
throw "Cannot start program: none is loaded.";
|
||||
|
||||
// Kill any existing program.
|
||||
killProgram();
|
||||
|
||||
// Add argv[0] to the arguments vector..
|
||||
std::vector<std::string> Args(ProgramArguments);
|
||||
Args.insert(Args.begin(), getProgramPath());
|
||||
|
||||
// Start the new program... this could throw if the program cannot be started.
|
||||
Process = InferiorProcess::create(Program, Args, Environment);
|
||||
}
|
||||
|
||||
InferiorProcess *
|
||||
InferiorProcess::create(Module *M, const std::vector<std::string> &Arguments,
|
||||
const char * const *envp) {
|
||||
throw"No supported binding to inferior processes (debugger not implemented).";
|
||||
}
|
||||
|
||||
/// killProgram - If the program is currently executing, kill off the
|
||||
/// process and free up any state related to the currently running program. If
|
||||
/// there is no program currently running, this just silently succeeds.
|
||||
void Debugger::killProgram() {
|
||||
// The destructor takes care of the dirty work.
|
||||
try {
|
||||
delete Process;
|
||||
} catch (...) {
|
||||
Process = 0;
|
||||
throw;
|
||||
}
|
||||
Process = 0;
|
||||
}
|
||||
|
||||
/// stepProgram - Implement the 'step' command, continuing execution until
|
||||
/// the next possible stop point.
|
||||
void Debugger::stepProgram() {
|
||||
assert(isProgramRunning() && "Cannot step if the program isn't running!");
|
||||
try {
|
||||
Process->stepProgram();
|
||||
} catch (InferiorProcessDead &IPD) {
|
||||
killProgram();
|
||||
throw NonErrorException("The program stopped with exit code " +
|
||||
itostr(IPD.getExitCode()));
|
||||
} catch (...) {
|
||||
killProgram();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// nextProgram - Implement the 'next' command, continuing execution until
|
||||
/// the next possible stop point that is in the current function.
|
||||
void Debugger::nextProgram() {
|
||||
assert(isProgramRunning() && "Cannot next if the program isn't running!");
|
||||
try {
|
||||
// This should step the process. If the process enters a function, then it
|
||||
// should 'finish' it. However, figuring this out is tricky. In
|
||||
// particular, the program can do any of:
|
||||
// 0. Not change current frame.
|
||||
// 1. Entering or exiting a region within the current function
|
||||
// (which changes the frame ID, but which we shouldn't 'finish')
|
||||
// 2. Exiting the current function (which changes the frame ID)
|
||||
// 3. Entering a function (which should be 'finish'ed)
|
||||
// For this reason, we have to be very careful about when we decide to do
|
||||
// the 'finish'.
|
||||
|
||||
// Get the current frame, but don't trust it. It could change...
|
||||
void *CurrentFrame = Process->getPreviousFrame(0);
|
||||
|
||||
// Don't trust the current frame: get the caller frame.
|
||||
void *ParentFrame = Process->getPreviousFrame(CurrentFrame);
|
||||
|
||||
// Ok, we have some information, run the program one step.
|
||||
Process->stepProgram();
|
||||
|
||||
// Where is the new frame? The most common case, by far is that it has not
|
||||
// been modified (Case #0), in which case we don't need to do anything more.
|
||||
void *NewFrame = Process->getPreviousFrame(0);
|
||||
if (NewFrame != CurrentFrame) {
|
||||
// Ok, the frame changed. If we are case #1, then the parent frame will
|
||||
// be identical.
|
||||
void *NewParentFrame = Process->getPreviousFrame(NewFrame);
|
||||
if (ParentFrame != NewParentFrame) {
|
||||
// Ok, now we know we aren't case #0 or #1. Check to see if we entered
|
||||
// a new function. If so, the parent frame will be "CurrentFrame".
|
||||
if (CurrentFrame == NewParentFrame)
|
||||
Process->finishProgram(NewFrame);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (InferiorProcessDead &IPD) {
|
||||
killProgram();
|
||||
throw NonErrorException("The program stopped with exit code " +
|
||||
itostr(IPD.getExitCode()));
|
||||
} catch (...) {
|
||||
killProgram();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// finishProgram - Implement the 'finish' command, continuing execution
|
||||
/// until the specified frame ID returns.
|
||||
void Debugger::finishProgram(void *Frame) {
|
||||
assert(isProgramRunning() && "Cannot cont if the program isn't running!");
|
||||
try {
|
||||
Process->finishProgram(Frame);
|
||||
} catch (InferiorProcessDead &IPD) {
|
||||
killProgram();
|
||||
throw NonErrorException("The program stopped with exit code " +
|
||||
itostr(IPD.getExitCode()));
|
||||
} catch (...) {
|
||||
killProgram();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// contProgram - Implement the 'cont' command, continuing execution until
|
||||
/// the next breakpoint is encountered.
|
||||
void Debugger::contProgram() {
|
||||
assert(isProgramRunning() && "Cannot cont if the program isn't running!");
|
||||
try {
|
||||
Process->contProgram();
|
||||
} catch (InferiorProcessDead &IPD) {
|
||||
killProgram();
|
||||
throw NonErrorException("The program stopped with exit code " +
|
||||
itostr(IPD.getExitCode()));
|
||||
} catch (...) {
|
||||
killProgram();
|
||||
throw;
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
##===- lib/Debugger/Makefile -------------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL = ../..
|
||||
LIBRARYNAME = LLVMDebugger
|
||||
EXTRA_DIST = README.txt
|
||||
REQUIRES_EH := 1
|
||||
BUILD_ARCHIVE = 1
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
@ -1,375 +0,0 @@
|
||||
//===-- ProgramInfo.cpp - Compute and cache info about a program ----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the ProgramInfo and related classes, by sorting through
|
||||
// the loaded Module.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Debugger/ProgramInfo.h"
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "llvm/Intrinsics.h"
|
||||
#include "llvm/IntrinsicInst.h"
|
||||
#include "llvm/Instructions.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Debugger/SourceFile.h"
|
||||
#include "llvm/Debugger/SourceLanguage.h"
|
||||
#include "llvm/Support/SlowOperationInformer.h"
|
||||
#include "llvm/Support/Streams.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
using namespace llvm;
|
||||
|
||||
/// getGlobalVariablesUsing - Return all of the global variables which have the
|
||||
/// specified value in their initializer somewhere.
|
||||
static void getGlobalVariablesUsing(Value *V,
|
||||
std::vector<GlobalVariable*> &Found) {
|
||||
for (Value::use_iterator I = V->use_begin(), E = V->use_end(); I != E; ++I) {
|
||||
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(*I))
|
||||
Found.push_back(GV);
|
||||
else if (Constant *C = dyn_cast<Constant>(*I))
|
||||
getGlobalVariablesUsing(C, Found);
|
||||
}
|
||||
}
|
||||
|
||||
/// getNextStopPoint - Follow the def-use chains of the specified LLVM value,
|
||||
/// traversing the use chains until we get to a stoppoint. When we do, return
|
||||
/// the source location of the stoppoint. If we don't find a stoppoint, return
|
||||
/// null.
|
||||
static const GlobalVariable *getNextStopPoint(const Value *V, unsigned &LineNo,
|
||||
unsigned &ColNo) {
|
||||
// The use-def chains can fork. As such, we pick the lowest numbered one we
|
||||
// find.
|
||||
const GlobalVariable *LastDesc = 0;
|
||||
unsigned LastLineNo = ~0;
|
||||
unsigned LastColNo = ~0;
|
||||
|
||||
for (Value::use_const_iterator UI = V->use_begin(), E = V->use_end();
|
||||
UI != E; ++UI) {
|
||||
bool ShouldRecurse = true;
|
||||
if (cast<Instruction>(*UI)->getOpcode() == Instruction::PHI) {
|
||||
// Infinite loops == bad, ignore PHI nodes.
|
||||
ShouldRecurse = false;
|
||||
} else if (const CallInst *CI = dyn_cast<CallInst>(*UI)) {
|
||||
|
||||
// If we found a stop point, check to see if it is earlier than what we
|
||||
// already have. If so, remember it.
|
||||
if (CI->getCalledFunction())
|
||||
if (const DbgStopPointInst *SPI = dyn_cast<DbgStopPointInst>(CI)) {
|
||||
unsigned CurLineNo = SPI->getLine();
|
||||
unsigned CurColNo = SPI->getColumn();
|
||||
const GlobalVariable *CurDesc = 0;
|
||||
const Value *Op = SPI->getContext();
|
||||
|
||||
if ((CurDesc = dyn_cast<GlobalVariable>(Op)) &&
|
||||
(LineNo < LastLineNo ||
|
||||
(LineNo == LastLineNo && ColNo < LastColNo))) {
|
||||
LastDesc = CurDesc;
|
||||
LastLineNo = CurLineNo;
|
||||
LastColNo = CurColNo;
|
||||
}
|
||||
ShouldRecurse = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If this is not a phi node or a stopping point, recursively scan the users
|
||||
// of this instruction to skip over region.begin's and the like.
|
||||
if (ShouldRecurse) {
|
||||
unsigned CurLineNo, CurColNo;
|
||||
if (const GlobalVariable *GV = getNextStopPoint(*UI, CurLineNo,CurColNo)){
|
||||
if (LineNo < LastLineNo || (LineNo == LastLineNo && ColNo < LastColNo)){
|
||||
LastDesc = GV;
|
||||
LastLineNo = CurLineNo;
|
||||
LastColNo = CurColNo;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (LastDesc) {
|
||||
LineNo = LastLineNo != ~0U ? LastLineNo : 0;
|
||||
ColNo = LastColNo != ~0U ? LastColNo : 0;
|
||||
}
|
||||
return LastDesc;
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// SourceFileInfo implementation
|
||||
//
|
||||
|
||||
SourceFileInfo::SourceFileInfo(const GlobalVariable *Desc,
|
||||
const SourceLanguage &Lang)
|
||||
: Language(&Lang), Descriptor(Desc) {
|
||||
Version = 0;
|
||||
SourceText = 0;
|
||||
|
||||
if (Desc && Desc->hasInitializer())
|
||||
if (ConstantStruct *CS = dyn_cast<ConstantStruct>(Desc->getInitializer()))
|
||||
if (CS->getNumOperands() > 4) {
|
||||
if (ConstantInt *CUI = dyn_cast<ConstantInt>(CS->getOperand(1)))
|
||||
Version = CUI->getZExtValue();
|
||||
|
||||
if (!GetConstantStringInfo(CS->getOperand(3), BaseName))
|
||||
BaseName = "";
|
||||
if (!GetConstantStringInfo(CS->getOperand(4), Directory))
|
||||
Directory = "";
|
||||
}
|
||||
}
|
||||
|
||||
SourceFileInfo::~SourceFileInfo() {
|
||||
delete SourceText;
|
||||
}
|
||||
|
||||
SourceFile &SourceFileInfo::getSourceText() const {
|
||||
// FIXME: this should take into account the source search directories!
|
||||
if (SourceText == 0) { // Read the file in if we haven't already.
|
||||
sys::Path tmpPath;
|
||||
if (!Directory.empty())
|
||||
tmpPath.set(Directory);
|
||||
tmpPath.appendComponent(BaseName);
|
||||
if (tmpPath.canRead())
|
||||
SourceText = new SourceFile(tmpPath.toString(), Descriptor);
|
||||
else
|
||||
SourceText = new SourceFile(BaseName, Descriptor);
|
||||
}
|
||||
return *SourceText;
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// SourceFunctionInfo implementation
|
||||
//
|
||||
SourceFunctionInfo::SourceFunctionInfo(ProgramInfo &PI,
|
||||
const GlobalVariable *Desc)
|
||||
: Descriptor(Desc) {
|
||||
LineNo = ColNo = 0;
|
||||
if (Desc && Desc->hasInitializer())
|
||||
if (ConstantStruct *CS = dyn_cast<ConstantStruct>(Desc->getInitializer()))
|
||||
if (CS->getNumOperands() > 2) {
|
||||
// Entry #1 is the file descriptor.
|
||||
if (const GlobalVariable *GV =
|
||||
dyn_cast<GlobalVariable>(CS->getOperand(1)))
|
||||
SourceFile = &PI.getSourceFile(GV);
|
||||
|
||||
// Entry #2 is the function name.
|
||||
if (!GetConstantStringInfo(CS->getOperand(2), Name))
|
||||
Name = "";
|
||||
}
|
||||
}
|
||||
|
||||
/// getSourceLocation - This method returns the location of the first stopping
|
||||
/// point in the function.
|
||||
void SourceFunctionInfo::getSourceLocation(unsigned &RetLineNo,
|
||||
unsigned &RetColNo) const {
|
||||
// If we haven't computed this yet...
|
||||
if (!LineNo) {
|
||||
// Look at all of the users of the function descriptor, looking for calls to
|
||||
// %llvm.dbg.func.start.
|
||||
for (Value::use_const_iterator UI = Descriptor->use_begin(),
|
||||
E = Descriptor->use_end(); UI != E; ++UI)
|
||||
if (const CallInst *CI = dyn_cast<CallInst>(*UI))
|
||||
if (const Function *F = CI->getCalledFunction())
|
||||
if (F->getIntrinsicID() == Intrinsic::dbg_func_start) {
|
||||
// We found the start of the function. Check to see if there are
|
||||
// any stop points on the use-list of the function start.
|
||||
const GlobalVariable *SD = getNextStopPoint(CI, LineNo, ColNo);
|
||||
if (SD) { // We found the first stop point!
|
||||
// This is just a sanity check.
|
||||
if (getSourceFile().getDescriptor() != SD)
|
||||
cout << "WARNING: first line of function is not in the"
|
||||
<< " file that the function descriptor claims it is in.\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
RetLineNo = LineNo; RetColNo = ColNo;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ProgramInfo implementation
|
||||
//
|
||||
|
||||
ProgramInfo::ProgramInfo(Module *m) : M(m), ProgramTimeStamp(0,0) {
|
||||
assert(M && "Cannot create program information with a null module!");
|
||||
sys::PathWithStatus ModPath(M->getModuleIdentifier());
|
||||
const sys::FileStatus *Stat = ModPath.getFileStatus();
|
||||
if (Stat)
|
||||
ProgramTimeStamp = Stat->getTimestamp();
|
||||
|
||||
SourceFilesIsComplete = false;
|
||||
SourceFunctionsIsComplete = false;
|
||||
}
|
||||
|
||||
ProgramInfo::~ProgramInfo() {
|
||||
// Delete cached information about source program objects...
|
||||
for (std::map<const GlobalVariable*, SourceFileInfo*>::iterator
|
||||
I = SourceFiles.begin(), E = SourceFiles.end(); I != E; ++I)
|
||||
delete I->second;
|
||||
for (std::map<const GlobalVariable*, SourceFunctionInfo*>::iterator
|
||||
I = SourceFunctions.begin(), E = SourceFunctions.end(); I != E; ++I)
|
||||
delete I->second;
|
||||
|
||||
// Delete the source language caches.
|
||||
for (unsigned i = 0, e = LanguageCaches.size(); i != e; ++i)
|
||||
delete LanguageCaches[i].second;
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// SourceFileInfo tracking...
|
||||
//
|
||||
|
||||
/// getSourceFile - Return source file information for the specified source file
|
||||
/// descriptor object, adding it to the collection as needed. This method
|
||||
/// always succeeds (is unambiguous), and is always efficient.
|
||||
///
|
||||
const SourceFileInfo &
|
||||
ProgramInfo::getSourceFile(const GlobalVariable *Desc) {
|
||||
SourceFileInfo *&Result = SourceFiles[Desc];
|
||||
if (Result) return *Result;
|
||||
|
||||
// Figure out what language this source file comes from...
|
||||
unsigned LangID = 0; // Zero is unknown language
|
||||
if (Desc && Desc->hasInitializer())
|
||||
if (ConstantStruct *CS = dyn_cast<ConstantStruct>(Desc->getInitializer()))
|
||||
if (CS->getNumOperands() > 2)
|
||||
if (ConstantInt *CUI = dyn_cast<ConstantInt>(CS->getOperand(2)))
|
||||
LangID = CUI->getZExtValue();
|
||||
|
||||
const SourceLanguage &Lang = SourceLanguage::get(LangID);
|
||||
SourceFileInfo *New = Lang.createSourceFileInfo(Desc, *this);
|
||||
|
||||
// FIXME: this should check to see if there is already a Filename/WorkingDir
|
||||
// pair that matches this one. If so, we shouldn't create the duplicate!
|
||||
//
|
||||
SourceFileIndex.insert(std::make_pair(New->getBaseName(), New));
|
||||
return *(Result = New);
|
||||
}
|
||||
|
||||
|
||||
/// getSourceFiles - Index all of the source files in the program and return
|
||||
/// a mapping of it. This information is lazily computed the first time
|
||||
/// that it is requested. Since this information can take a long time to
|
||||
/// compute, the user is given a chance to cancel it. If this occurs, an
|
||||
/// exception is thrown.
|
||||
const std::map<const GlobalVariable*, SourceFileInfo*> &
|
||||
ProgramInfo::getSourceFiles(bool RequiresCompleteMap) {
|
||||
// If we have a fully populated map, or if the client doesn't need one, just
|
||||
// return what we have.
|
||||
if (SourceFilesIsComplete || !RequiresCompleteMap)
|
||||
return SourceFiles;
|
||||
|
||||
// Ok, all of the source file descriptors (compile_unit in dwarf terms),
|
||||
// should be on the use list of the llvm.dbg.translation_units global.
|
||||
//
|
||||
GlobalVariable *Units =
|
||||
M->getGlobalVariable("llvm.dbg.translation_units", StructType::get());
|
||||
if (Units == 0)
|
||||
throw "Program contains no debugging information!";
|
||||
|
||||
std::vector<GlobalVariable*> TranslationUnits;
|
||||
getGlobalVariablesUsing(Units, TranslationUnits);
|
||||
|
||||
SlowOperationInformer SOI("building source files index");
|
||||
|
||||
// Loop over all of the translation units found, building the SourceFiles
|
||||
// mapping.
|
||||
for (unsigned i = 0, e = TranslationUnits.size(); i != e; ++i) {
|
||||
getSourceFile(TranslationUnits[i]);
|
||||
if (SOI.progress(i+1, e))
|
||||
throw "While building source files index, operation cancelled.";
|
||||
}
|
||||
|
||||
// Ok, if we got this far, then we indexed the whole program.
|
||||
SourceFilesIsComplete = true;
|
||||
return SourceFiles;
|
||||
}
|
||||
|
||||
/// getSourceFile - Look up the file with the specified name. If there is
|
||||
/// more than one match for the specified filename, prompt the user to pick
|
||||
/// one. If there is no source file that matches the specified name, throw
|
||||
/// an exception indicating that we can't find the file. Otherwise, return
|
||||
/// the file information for that file.
|
||||
const SourceFileInfo &ProgramInfo::getSourceFile(const std::string &Filename) {
|
||||
std::multimap<std::string, SourceFileInfo*>::const_iterator Start, End;
|
||||
getSourceFiles();
|
||||
tie(Start, End) = SourceFileIndex.equal_range(Filename);
|
||||
|
||||
if (Start == End) throw "Could not find source file '" + Filename + "'!";
|
||||
const SourceFileInfo &SFI = *Start->second;
|
||||
++Start;
|
||||
if (Start == End) return SFI;
|
||||
|
||||
throw "FIXME: Multiple source files with the same name not implemented!";
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// SourceFunctionInfo tracking...
|
||||
//
|
||||
|
||||
|
||||
/// getFunction - Return function information for the specified function
|
||||
/// descriptor object, adding it to the collection as needed. This method
|
||||
/// always succeeds (is unambiguous), and is always efficient.
|
||||
///
|
||||
const SourceFunctionInfo &
|
||||
ProgramInfo::getFunction(const GlobalVariable *Desc) {
|
||||
SourceFunctionInfo *&Result = SourceFunctions[Desc];
|
||||
if (Result) return *Result;
|
||||
|
||||
// Figure out what language this function comes from...
|
||||
const GlobalVariable *SourceFileDesc = 0;
|
||||
if (Desc && Desc->hasInitializer())
|
||||
if (ConstantStruct *CS = dyn_cast<ConstantStruct>(Desc->getInitializer()))
|
||||
if (CS->getNumOperands() > 0)
|
||||
if (const GlobalVariable *GV =
|
||||
dyn_cast<GlobalVariable>(CS->getOperand(1)))
|
||||
SourceFileDesc = GV;
|
||||
|
||||
const SourceLanguage &Lang = getSourceFile(SourceFileDesc).getLanguage();
|
||||
return *(Result = Lang.createSourceFunctionInfo(Desc, *this));
|
||||
}
|
||||
|
||||
|
||||
// getSourceFunctions - Index all of the functions in the program and return
|
||||
// them. This information is lazily computed the first time that it is
|
||||
// requested. Since this information can take a long time to compute, the user
|
||||
// is given a chance to cancel it. If this occurs, an exception is thrown.
|
||||
const std::map<const GlobalVariable*, SourceFunctionInfo*> &
|
||||
ProgramInfo::getSourceFunctions(bool RequiresCompleteMap) {
|
||||
if (SourceFunctionsIsComplete || !RequiresCompleteMap)
|
||||
return SourceFunctions;
|
||||
|
||||
// Ok, all of the source function descriptors (subprogram in dwarf terms),
|
||||
// should be on the use list of the llvm.dbg.translation_units global.
|
||||
//
|
||||
GlobalVariable *Units =
|
||||
M->getGlobalVariable("llvm.dbg.globals", StructType::get());
|
||||
if (Units == 0)
|
||||
throw "Program contains no debugging information!";
|
||||
|
||||
std::vector<GlobalVariable*> Functions;
|
||||
getGlobalVariablesUsing(Units, Functions);
|
||||
|
||||
SlowOperationInformer SOI("building functions index");
|
||||
|
||||
// Loop over all of the functions found, building the SourceFunctions mapping.
|
||||
for (unsigned i = 0, e = Functions.size(); i != e; ++i) {
|
||||
getFunction(Functions[i]);
|
||||
if (SOI.progress(i+1, e))
|
||||
throw "While functions index, operation cancelled.";
|
||||
}
|
||||
|
||||
// Ok, if we got this far, then we indexed the whole program.
|
||||
SourceFunctionsIsComplete = true;
|
||||
return SourceFunctions;
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
//===-- llvm/lib/Debugger/ - LLVM Debugger interfaces ---------------------===//
|
||||
|
||||
This directory contains the implementation of the LLVM debugger backend. This
|
||||
directory builds into a library which can be used by various debugger
|
||||
front-ends to debug LLVM programs. The current command line LLVM debugger,
|
||||
llvm-db is currently the only client of this library, but others could be
|
||||
built, to provide a GUI front-end for example.
|
@ -1,69 +0,0 @@
|
||||
//===-- RuntimeInfo.cpp - Compute and cache info about running program ----===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the RuntimeInfo and related classes, by querying and
|
||||
// cachine information from the running inferior process.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Debugger/InferiorProcess.h"
|
||||
#include "llvm/Debugger/ProgramInfo.h"
|
||||
#include "llvm/Debugger/RuntimeInfo.h"
|
||||
using namespace llvm;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// StackFrame class implementation
|
||||
|
||||
StackFrame::StackFrame(RuntimeInfo &ri, void *ParentFrameID)
|
||||
: RI(ri), SourceInfo(0) {
|
||||
FrameID = RI.getInferiorProcess().getPreviousFrame(ParentFrameID);
|
||||
if (FrameID == 0) throw "Stack frame does not exist!";
|
||||
|
||||
// Compute lazily as needed.
|
||||
FunctionDesc = 0;
|
||||
}
|
||||
|
||||
const GlobalVariable *StackFrame::getFunctionDesc() {
|
||||
if (FunctionDesc == 0)
|
||||
FunctionDesc = RI.getInferiorProcess().getSubprogramDesc(FrameID);
|
||||
return FunctionDesc;
|
||||
}
|
||||
|
||||
/// getSourceLocation - Return the source location that this stack frame is
|
||||
/// sitting at.
|
||||
void StackFrame::getSourceLocation(unsigned &lineNo, unsigned &colNo,
|
||||
const SourceFileInfo *&sourceInfo) {
|
||||
if (SourceInfo == 0) {
|
||||
const GlobalVariable *SourceDesc = 0;
|
||||
RI.getInferiorProcess().getFrameLocation(FrameID, LineNo,ColNo, SourceDesc);
|
||||
SourceInfo = &RI.getProgramInfo().getSourceFile(SourceDesc);
|
||||
}
|
||||
|
||||
lineNo = LineNo;
|
||||
colNo = ColNo;
|
||||
sourceInfo = SourceInfo;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// RuntimeInfo class implementation
|
||||
|
||||
/// materializeFrame - Create and process all frames up to and including the
|
||||
/// specified frame number. This throws an exception if the specified frame
|
||||
/// ID is nonexistant.
|
||||
void RuntimeInfo::materializeFrame(unsigned ID) {
|
||||
assert(ID >= CallStack.size() && "no need to materialize this frame!");
|
||||
void *CurFrame = 0;
|
||||
if (!CallStack.empty())
|
||||
CurFrame = CallStack.back().getFrameID();
|
||||
|
||||
while (CallStack.size() <= ID) {
|
||||
CallStack.push_back(StackFrame(*this, CurFrame));
|
||||
CurFrame = CallStack.back().getFrameID();
|
||||
}
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
//===-- SourceFile.cpp - SourceFile implementation for the debugger -------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the SourceFile class for the LLVM debugger.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Debugger/SourceFile.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include <cassert>
|
||||
using namespace llvm;
|
||||
|
||||
static const char EmptyFile = 0;
|
||||
|
||||
SourceFile::SourceFile(const std::string &fn, const GlobalVariable *Desc)
|
||||
: Filename(fn), Descriptor(Desc) {
|
||||
File.reset(MemoryBuffer::getFileOrSTDIN(fn));
|
||||
|
||||
// On error, return an empty buffer.
|
||||
if (File == 0)
|
||||
File.reset(MemoryBuffer::getMemBuffer(&EmptyFile, &EmptyFile));
|
||||
}
|
||||
|
||||
SourceFile::~SourceFile() {
|
||||
}
|
||||
|
||||
|
||||
/// calculateLineOffsets - Compute the LineOffset vector for the current file.
|
||||
///
|
||||
void SourceFile::calculateLineOffsets() const {
|
||||
assert(LineOffset.empty() && "Line offsets already computed!");
|
||||
const char *BufPtr = File->getBufferStart();
|
||||
const char *FileStart = BufPtr;
|
||||
const char *FileEnd = File->getBufferEnd();
|
||||
do {
|
||||
LineOffset.push_back(BufPtr-FileStart);
|
||||
|
||||
// Scan until we get to a newline.
|
||||
while (BufPtr != FileEnd && *BufPtr != '\n' && *BufPtr != '\r')
|
||||
++BufPtr;
|
||||
|
||||
if (BufPtr != FileEnd) {
|
||||
++BufPtr; // Skip over the \n or \r
|
||||
if (BufPtr[-1] == '\r' && BufPtr != FileEnd && BufPtr[0] == '\n')
|
||||
++BufPtr; // Skip over dos/windows style \r\n's
|
||||
}
|
||||
} while (BufPtr != FileEnd);
|
||||
}
|
||||
|
||||
|
||||
/// getSourceLine - Given a line number, return the start and end of the line
|
||||
/// in the file. If the line number is invalid, or if the file could not be
|
||||
/// loaded, null pointers are returned for the start and end of the file. Note
|
||||
/// that line numbers start with 0, not 1.
|
||||
void SourceFile::getSourceLine(unsigned LineNo, const char *&LineStart,
|
||||
const char *&LineEnd) const {
|
||||
LineStart = LineEnd = 0;
|
||||
if (LineOffset.empty()) calculateLineOffsets();
|
||||
|
||||
// Asking for an out-of-range line number?
|
||||
if (LineNo >= LineOffset.size()) return;
|
||||
|
||||
// Otherwise, they are asking for a valid line, which we can fulfill.
|
||||
LineStart = File->getBufferStart()+LineOffset[LineNo];
|
||||
|
||||
if (LineNo+1 < LineOffset.size())
|
||||
LineEnd = File->getBufferStart()+LineOffset[LineNo+1];
|
||||
else
|
||||
LineEnd = File->getBufferEnd();
|
||||
|
||||
// If the line ended with a newline, strip it off.
|
||||
while (LineEnd != LineStart && (LineEnd[-1] == '\n' || LineEnd[-1] == '\r'))
|
||||
--LineEnd;
|
||||
|
||||
assert(LineEnd >= LineStart && "We somehow got our pointers swizzled!");
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
//===-- SourceLanguage-CFamily.cpp - C family SourceLanguage impl ---------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the SourceLanguage class for the C family of languages
|
||||
// (K&R C, C89, C99, etc).
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Debugger/SourceLanguage.h"
|
||||
using namespace llvm;
|
||||
|
||||
#if 0
|
||||
namespace {
|
||||
struct CSL : public SourceLanguage {
|
||||
} TheCSourceLanguageInstance;
|
||||
}
|
||||
#endif
|
||||
|
||||
const SourceLanguage &SourceLanguage::getCFamilyInstance() {
|
||||
return get(0); // We don't have an implementation for C yet fall back on
|
||||
// generic
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
//===-- SourceLanguage-CPlusPlus.cpp - C++ SourceLanguage impl ------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the SourceLanguage class for the C++ language.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Debugger/SourceLanguage.h"
|
||||
using namespace llvm;
|
||||
|
||||
#if 0
|
||||
namespace {
|
||||
struct CPPSL : public SourceLanguage {
|
||||
} TheCPlusPlusLanguageInstance;
|
||||
}
|
||||
#endif
|
||||
|
||||
const SourceLanguage &SourceLanguage::getCPlusPlusInstance() {
|
||||
return get(0); // We don't have an implementation for C yet fall back on
|
||||
// generic
|
||||
}
|
@ -1,138 +0,0 @@
|
||||
//===-- SourceLanguage-Unknown.cpp - Implement itf for unknown languages --===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// If the LLVM debugger does not have a module for a particular language, it
|
||||
// falls back on using this one to perform the source-language interface. This
|
||||
// interface is not wonderful, but it gets the job done.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Debugger/SourceLanguage.h"
|
||||
#include "llvm/Debugger/ProgramInfo.h"
|
||||
#include "llvm/Support/Streams.h"
|
||||
#include <cassert>
|
||||
#include <ostream>
|
||||
using namespace llvm;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Implement the SourceLanguage cache for the Unknown language.
|
||||
//
|
||||
|
||||
namespace {
|
||||
/// SLUCache - This cache allows for efficient lookup of source functions by
|
||||
/// name.
|
||||
///
|
||||
struct SLUCache : public SourceLanguageCache {
|
||||
ProgramInfo &PI;
|
||||
std::multimap<std::string, SourceFunctionInfo*> FunctionMap;
|
||||
public:
|
||||
SLUCache(ProgramInfo &pi);
|
||||
|
||||
typedef std::multimap<std::string, SourceFunctionInfo*>::const_iterator
|
||||
fm_iterator;
|
||||
|
||||
std::pair<fm_iterator, fm_iterator>
|
||||
getFunction(const std::string &Name) const {
|
||||
return FunctionMap.equal_range(Name);
|
||||
}
|
||||
|
||||
SourceFunctionInfo *addSourceFunction(SourceFunctionInfo *SF) {
|
||||
FunctionMap.insert(std::make_pair(SF->getSymbolicName(), SF));
|
||||
return SF;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
SLUCache::SLUCache(ProgramInfo &pi) : PI(pi) {
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Implement SourceLanguageUnknown class, which is used to handle unrecognized
|
||||
// languages.
|
||||
//
|
||||
|
||||
namespace {
|
||||
static struct SLU : public SourceLanguage {
|
||||
//===------------------------------------------------------------------===//
|
||||
// Implement the miscellaneous methods...
|
||||
//
|
||||
virtual const char *getSourceLanguageName() const {
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
/// lookupFunction - Given a textual function name, return the
|
||||
/// SourceFunctionInfo descriptor for that function, or null if it cannot be
|
||||
/// found. If the program is currently running, the RuntimeInfo object
|
||||
/// provides information about the current evaluation context, otherwise it
|
||||
/// will be null.
|
||||
///
|
||||
virtual SourceFunctionInfo *lookupFunction(const std::string &FunctionName,
|
||||
ProgramInfo &PI,
|
||||
RuntimeInfo *RI = 0) const;
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// We do use a cache for information...
|
||||
//
|
||||
typedef SLUCache CacheType;
|
||||
SLUCache *createSourceLanguageCache(ProgramInfo &PI) const {
|
||||
return new SLUCache(PI);
|
||||
}
|
||||
|
||||
/// createSourceFunctionInfo - Create the new object and inform the cache of
|
||||
/// the new function.
|
||||
virtual SourceFunctionInfo *
|
||||
createSourceFunctionInfo(const GlobalVariable *Desc, ProgramInfo &PI) const;
|
||||
|
||||
} TheUnknownSourceLanguageInstance;
|
||||
}
|
||||
|
||||
const SourceLanguage &SourceLanguage::getUnknownLanguageInstance() {
|
||||
return TheUnknownSourceLanguageInstance;
|
||||
}
|
||||
|
||||
|
||||
SourceFunctionInfo *
|
||||
SLU::createSourceFunctionInfo(const GlobalVariable *Desc,
|
||||
ProgramInfo &PI) const {
|
||||
SourceFunctionInfo *Result = new SourceFunctionInfo(PI, Desc);
|
||||
return PI.getLanguageCache(this).addSourceFunction(Result);
|
||||
}
|
||||
|
||||
|
||||
/// lookupFunction - Given a textual function name, return the
|
||||
/// SourceFunctionInfo descriptor for that function, or null if it cannot be
|
||||
/// found. If the program is currently running, the RuntimeInfo object
|
||||
/// provides information about the current evaluation context, otherwise it will
|
||||
/// be null.
|
||||
///
|
||||
SourceFunctionInfo *SLU::lookupFunction(const std::string &FunctionName,
|
||||
ProgramInfo &PI, RuntimeInfo *RI) const{
|
||||
SLUCache &Cache = PI.getLanguageCache(this);
|
||||
std::pair<SLUCache::fm_iterator, SLUCache::fm_iterator> IP
|
||||
= Cache.getFunction(FunctionName);
|
||||
|
||||
if (IP.first == IP.second) {
|
||||
if (PI.allSourceFunctionsRead())
|
||||
return 0; // Nothing found
|
||||
|
||||
// Otherwise, we might be able to find the function if we read all of them
|
||||
// in. Do so now.
|
||||
PI.getSourceFunctions();
|
||||
assert(PI.allSourceFunctionsRead() && "Didn't read in all functions?");
|
||||
return lookupFunction(FunctionName, PI, RI);
|
||||
}
|
||||
|
||||
SourceFunctionInfo *Found = IP.first->second;
|
||||
++IP.first;
|
||||
if (IP.first != IP.second)
|
||||
cout << "Whoa, found multiple functions with the same name. I should"
|
||||
<< " ask the user which one to use: FIXME!\n";
|
||||
return Found;
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
//===-- SourceLanguage.cpp - Implement the SourceLanguage class -----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the SourceLanguage class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Debugger/SourceLanguage.h"
|
||||
#include "llvm/Debugger/ProgramInfo.h"
|
||||
using namespace llvm;
|
||||
|
||||
const SourceLanguage &SourceLanguage::get(unsigned ID) {
|
||||
switch (ID) {
|
||||
case 1: // DW_LANG_C89
|
||||
case 2: // DW_LANG_C
|
||||
case 12: // DW_LANG_C99
|
||||
return getCFamilyInstance();
|
||||
|
||||
case 4: // DW_LANG_C_plus_plus
|
||||
return getCPlusPlusInstance();
|
||||
|
||||
case 3: // DW_LANG_Ada83
|
||||
case 5: // DW_LANG_Cobol74
|
||||
case 6: // DW_LANG_Cobol85
|
||||
case 7: // DW_LANG_Fortran77
|
||||
case 8: // DW_LANG_Fortran90
|
||||
case 9: // DW_LANG_Pascal83
|
||||
case 10: // DW_LANG_Modula2
|
||||
case 11: // DW_LANG_Java
|
||||
case 13: // DW_LANG_Ada95
|
||||
case 14: // DW_LANG_Fortran95
|
||||
default:
|
||||
return getUnknownLanguageInstance();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SourceFileInfo *
|
||||
SourceLanguage::createSourceFileInfo(const GlobalVariable *Desc,
|
||||
ProgramInfo &PI) const {
|
||||
return new SourceFileInfo(Desc, *this);
|
||||
}
|
||||
|
||||
SourceFunctionInfo *
|
||||
SourceLanguage::createSourceFunctionInfo(const GlobalVariable *Desc,
|
||||
ProgramInfo &PI) const {
|
||||
return new SourceFunctionInfo(PI, Desc);
|
||||
}
|
@ -1,130 +0,0 @@
|
||||
//===-- Annotation.cpp - Implement the Annotation Classes -----------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the AnnotationManager class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Support/Annotation.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/System/RWMutex.h"
|
||||
#include <map>
|
||||
#include <cstring>
|
||||
using namespace llvm;
|
||||
|
||||
Annotation::~Annotation() {} // Designed to be subclassed
|
||||
|
||||
Annotable::~Annotable() { // Virtual because it's designed to be subclassed...
|
||||
Annotation *A = AnnotationList;
|
||||
while (A) {
|
||||
Annotation *Next = A->getNext();
|
||||
delete A;
|
||||
A = Next;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
class StrCmp {
|
||||
public:
|
||||
bool operator()(const char *a, const char *b) const {
|
||||
return strcmp(a, b) < 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
typedef std::map<const char*, unsigned, StrCmp> IDMapType;
|
||||
static volatile sys::cas_flag IDCounter = 0; // Unique ID counter
|
||||
|
||||
// Static member to ensure initialiation on demand.
|
||||
static ManagedStatic<IDMapType> IDMap;
|
||||
static ManagedStatic<sys::SmartRWMutex<true> > AnnotationsLock;
|
||||
|
||||
// On demand annotation creation support...
|
||||
typedef Annotation *(*AnnFactory)(AnnotationID, const Annotable *, void *);
|
||||
typedef std::map<unsigned, std::pair<AnnFactory,void*> > FactMapType;
|
||||
|
||||
static ManagedStatic<FactMapType> TheFactMap;
|
||||
static FactMapType &getFactMap() {
|
||||
return *TheFactMap;
|
||||
}
|
||||
|
||||
static void eraseFromFactMap(unsigned ID) {
|
||||
sys::SmartScopedWriter<true> Writer(&*AnnotationsLock);
|
||||
TheFactMap->erase(ID);
|
||||
}
|
||||
|
||||
AnnotationID AnnotationManager::getID(const char *Name) { // Name -> ID
|
||||
AnnotationsLock->reader_acquire();
|
||||
IDMapType::iterator I = IDMap->find(Name);
|
||||
IDMapType::iterator E = IDMap->end();
|
||||
AnnotationsLock->reader_release();
|
||||
|
||||
if (I == E) {
|
||||
sys::SmartScopedWriter<true> Writer(&*AnnotationsLock);
|
||||
I = IDMap->find(Name);
|
||||
if (I == IDMap->end()) {
|
||||
unsigned newCount = sys::AtomicIncrement(&IDCounter);
|
||||
(*IDMap)[Name] = newCount-1; // Add a new element
|
||||
return AnnotationID(newCount-1);
|
||||
} else
|
||||
return AnnotationID(I->second);
|
||||
}
|
||||
return AnnotationID(I->second);
|
||||
}
|
||||
|
||||
// getID - Name -> ID + registration of a factory function for demand driven
|
||||
// annotation support.
|
||||
AnnotationID AnnotationManager::getID(const char *Name, Factory Fact,
|
||||
void *Data) {
|
||||
AnnotationID Result(getID(Name));
|
||||
registerAnnotationFactory(Result, Fact, Data);
|
||||
return Result;
|
||||
}
|
||||
|
||||
// getName - This function is especially slow, but that's okay because it should
|
||||
// only be used for debugging.
|
||||
//
|
||||
const char *AnnotationManager::getName(AnnotationID ID) { // ID -> Name
|
||||
sys::SmartScopedReader<true> Reader(&*AnnotationsLock);
|
||||
IDMapType &TheMap = *IDMap;
|
||||
for (IDMapType::iterator I = TheMap.begin(); ; ++I) {
|
||||
assert(I != TheMap.end() && "Annotation ID is unknown!");
|
||||
if (I->second == ID.ID) return I->first;
|
||||
}
|
||||
}
|
||||
|
||||
// registerAnnotationFactory - This method is used to register a callback
|
||||
// function used to create an annotation on demand if it is needed by the
|
||||
// Annotable::findOrCreateAnnotation method.
|
||||
//
|
||||
void AnnotationManager::registerAnnotationFactory(AnnotationID ID, AnnFactory F,
|
||||
void *ExtraData) {
|
||||
if (F) {
|
||||
sys::SmartScopedWriter<true> Writer(&*AnnotationsLock);
|
||||
getFactMap()[ID.ID] = std::make_pair(F, ExtraData);
|
||||
} else {
|
||||
eraseFromFactMap(ID.ID);
|
||||
}
|
||||
}
|
||||
|
||||
// createAnnotation - Create an annotation of the specified ID for the
|
||||
// specified object, using a register annotation creation function.
|
||||
//
|
||||
Annotation *AnnotationManager::createAnnotation(AnnotationID ID,
|
||||
const Annotable *Obj) {
|
||||
AnnotationsLock->reader_acquire();
|
||||
FactMapType::iterator I = getFactMap().find(ID.ID);
|
||||
if (I == getFactMap().end()) {
|
||||
AnnotationsLock->reader_release();
|
||||
return 0;
|
||||
}
|
||||
|
||||
AnnotationsLock->reader_release();
|
||||
return I->second.first(ID, Obj, I->second.second);
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
//===-- Streams.cpp - Wrappers for iostreams ------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements a wrapper for the std::cout and std::cerr I/O streams.
|
||||
// It prevents the need to include <iostream> to each file just to get I/O.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Support/Streams.h"
|
||||
#include <iostream>
|
||||
using namespace llvm;
|
||||
|
||||
OStream llvm::cout(std::cout);
|
||||
OStream llvm::cerr(std::cerr);
|
||||
IStream llvm::cin(std::cin);
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// FlushStream - Function called by BaseStream to flush an ostream.
|
||||
void FlushStream(std::ostream &S) {
|
||||
S << std::flush;
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
@ -1,6 +0,0 @@
|
||||
LLVM System Interface Library
|
||||
-------------------------------------------------------------------------------
|
||||
The LLVM System Interface Library is licensed under the Illinois Open Source
|
||||
License and has the following additional copyright:
|
||||
|
||||
Copyright (C) 2004 eXtensible Systems, Inc.
|
@ -1,254 +0,0 @@
|
||||
//===-- ARMTargetAsmInfo.cpp - ARM asm properties ---------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the declarations of the ARMTargetAsmInfo properties.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ARMTargetAsmInfo.h"
|
||||
#include "ARMTargetMachine.h"
|
||||
#include <cstring>
|
||||
#include <cctype>
|
||||
using namespace llvm;
|
||||
|
||||
const char *const llvm::arm_asm_table[] = {
|
||||
"{r0}", "r0",
|
||||
"{r1}", "r1",
|
||||
"{r2}", "r2",
|
||||
"{r3}", "r3",
|
||||
"{r4}", "r4",
|
||||
"{r5}", "r5",
|
||||
"{r6}", "r6",
|
||||
"{r7}", "r7",
|
||||
"{r8}", "r8",
|
||||
"{r9}", "r9",
|
||||
"{r10}", "r10",
|
||||
"{r11}", "r11",
|
||||
"{r12}", "r12",
|
||||
"{r13}", "r13",
|
||||
"{r14}", "r14",
|
||||
"{lr}", "lr",
|
||||
"{sp}", "sp",
|
||||
"{ip}", "ip",
|
||||
"{fp}", "fp",
|
||||
"{sl}", "sl",
|
||||
"{memory}", "memory",
|
||||
"{cc}", "cc",
|
||||
0,0
|
||||
};
|
||||
|
||||
ARMDarwinTargetAsmInfo::ARMDarwinTargetAsmInfo(const ARMBaseTargetMachine &TM):
|
||||
ARMTargetAsmInfo<DarwinTargetAsmInfo>(TM) {
|
||||
Subtarget = &TM.getSubtarget<ARMSubtarget>();
|
||||
|
||||
ZeroDirective = "\t.space\t";
|
||||
ZeroFillDirective = "\t.zerofill\t"; // Uses .zerofill
|
||||
SetDirective = "\t.set\t";
|
||||
ProtectedDirective = NULL;
|
||||
HasDotTypeDotSizeDirective = false;
|
||||
SupportsDebugInformation = true;
|
||||
}
|
||||
|
||||
ARMELFTargetAsmInfo::ARMELFTargetAsmInfo(const ARMBaseTargetMachine &TM):
|
||||
ARMTargetAsmInfo<ELFTargetAsmInfo>(TM) {
|
||||
Subtarget = &TM.getSubtarget<ARMSubtarget>();
|
||||
|
||||
NeedsSet = false;
|
||||
HasLEB128 = true;
|
||||
AbsoluteDebugSectionOffsets = true;
|
||||
CStringSection = ".rodata.str";
|
||||
PrivateGlobalPrefix = ".L";
|
||||
WeakRefDirective = "\t.weak\t";
|
||||
SetDirective = "\t.set\t";
|
||||
DwarfRequiresFrameSection = false;
|
||||
DwarfAbbrevSection = "\t.section\t.debug_abbrev,\"\",%progbits";
|
||||
DwarfInfoSection = "\t.section\t.debug_info,\"\",%progbits";
|
||||
DwarfLineSection = "\t.section\t.debug_line,\"\",%progbits";
|
||||
DwarfFrameSection = "\t.section\t.debug_frame,\"\",%progbits";
|
||||
DwarfPubNamesSection ="\t.section\t.debug_pubnames,\"\",%progbits";
|
||||
DwarfPubTypesSection ="\t.section\t.debug_pubtypes,\"\",%progbits";
|
||||
DwarfStrSection = "\t.section\t.debug_str,\"\",%progbits";
|
||||
DwarfLocSection = "\t.section\t.debug_loc,\"\",%progbits";
|
||||
DwarfARangesSection = "\t.section\t.debug_aranges,\"\",%progbits";
|
||||
DwarfRangesSection = "\t.section\t.debug_ranges,\"\",%progbits";
|
||||
DwarfMacroInfoSection = "\t.section\t.debug_macinfo,\"\",%progbits";
|
||||
|
||||
if (Subtarget->isAAPCS_ABI()) {
|
||||
StaticCtorsSection = "\t.section .init_array,\"aw\",%init_array";
|
||||
StaticDtorsSection = "\t.section .fini_array,\"aw\",%fini_array";
|
||||
} else {
|
||||
StaticCtorsSection = "\t.section .ctors,\"aw\",%progbits";
|
||||
StaticDtorsSection = "\t.section .dtors,\"aw\",%progbits";
|
||||
}
|
||||
SupportsDebugInformation = true;
|
||||
}
|
||||
|
||||
/// Count the number of comma-separated arguments.
|
||||
/// Do not try to detect errors.
|
||||
template <class BaseTAI>
|
||||
unsigned ARMTargetAsmInfo<BaseTAI>::countArguments(const char* p) const {
|
||||
unsigned count = 0;
|
||||
while (*p && isspace(*p) && *p != '\n')
|
||||
p++;
|
||||
count++;
|
||||
while (*p && *p!='\n' &&
|
||||
strncmp(p, BaseTAI::CommentString,
|
||||
strlen(BaseTAI::CommentString))!=0) {
|
||||
if (*p==',')
|
||||
count++;
|
||||
p++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/// Count the length of a string enclosed in quote characters.
|
||||
/// Do not try to detect errors.
|
||||
template <class BaseTAI>
|
||||
unsigned ARMTargetAsmInfo<BaseTAI>::countString(const char* p) const {
|
||||
unsigned count = 0;
|
||||
while (*p && isspace(*p) && *p!='\n')
|
||||
p++;
|
||||
if (!*p || *p != '\"')
|
||||
return count;
|
||||
while (*++p && *p != '\"')
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
/// ARM-specific version of TargetAsmInfo::getInlineAsmLength.
|
||||
template <class BaseTAI>
|
||||
unsigned ARMTargetAsmInfo<BaseTAI>::getInlineAsmLength(const char *s) const {
|
||||
// Make a lowercase-folded version of s for counting purposes.
|
||||
char *q, *s_copy = (char *)malloc(strlen(s) + 1);
|
||||
strcpy(s_copy, s);
|
||||
for (q=s_copy; *q; q++)
|
||||
*q = tolower(*q);
|
||||
const char *Str = s_copy;
|
||||
|
||||
// Count the number of bytes in the asm.
|
||||
bool atInsnStart = true;
|
||||
bool inTextSection = true;
|
||||
unsigned Length = 0;
|
||||
for (; *Str; ++Str) {
|
||||
if (atInsnStart) {
|
||||
// Skip whitespace
|
||||
while (*Str && isspace(*Str) && *Str != '\n')
|
||||
Str++;
|
||||
// Skip label
|
||||
for (const char* p = Str; *p && !isspace(*p); p++)
|
||||
if (*p == ':') {
|
||||
Str = p+1;
|
||||
while (*Str && isspace(*Str) && *Str != '\n')
|
||||
Str++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (*Str == 0) break;
|
||||
|
||||
// Ignore everything from comment char(s) to EOL
|
||||
if (strncmp(Str, BaseTAI::CommentString,
|
||||
strlen(BaseTAI::CommentString)) == 0)
|
||||
atInsnStart = false;
|
||||
// FIXME do something like the following for non-Darwin
|
||||
else if (*Str == '.' && Subtarget->isTargetDarwin()) {
|
||||
// Directive.
|
||||
atInsnStart = false;
|
||||
|
||||
// Some change the section, but don't generate code.
|
||||
if (strncmp(Str, ".literal4", strlen(".literal4"))==0 ||
|
||||
strncmp(Str, ".literal8", strlen(".literal8"))==0 ||
|
||||
strncmp(Str, ".const", strlen(".const"))==0 ||
|
||||
strncmp(Str, ".constructor", strlen(".constructor"))==0 ||
|
||||
strncmp(Str, ".cstring", strlen(".cstring"))==0 ||
|
||||
strncmp(Str, ".data", strlen(".data"))==0 ||
|
||||
strncmp(Str, ".destructor", strlen(".destructor"))==0 ||
|
||||
strncmp(Str, ".fvmlib_init0", strlen(".fvmlib_init0"))==0 ||
|
||||
strncmp(Str, ".fvmlib_init1", strlen(".fvmlib_init1"))==0 ||
|
||||
strncmp(Str, ".mod_init_func", strlen(".mod_init_func"))==0 ||
|
||||
strncmp(Str, ".mod_term_func", strlen(".mod_term_func"))==0 ||
|
||||
strncmp(Str, ".picsymbol_stub", strlen(".picsymbol_stub"))==0 ||
|
||||
strncmp(Str, ".symbol_stub", strlen(".symbol_stub"))==0 ||
|
||||
strncmp(Str, ".static_data", strlen(".static_data"))==0 ||
|
||||
strncmp(Str, ".section", strlen(".section"))==0 ||
|
||||
strncmp(Str, ".lazy_symbol_pointer", strlen(".lazy_symbol_pointer"))==0 ||
|
||||
strncmp(Str, ".non_lazy_symbol_pointer", strlen(".non_lazy_symbol_pointer"))==0 ||
|
||||
strncmp(Str, ".dyld", strlen(".dyld"))==0 ||
|
||||
strncmp(Str, ".const_data", strlen(".const_data"))==0 ||
|
||||
strncmp(Str, ".objc", strlen(".objc"))==0 || //// many directives
|
||||
strncmp(Str, ".static_const", strlen(".static_const"))==0)
|
||||
inTextSection=false;
|
||||
else if (strncmp(Str, ".text", strlen(".text"))==0)
|
||||
inTextSection = true;
|
||||
// Some can't really be handled without implementing significant pieces
|
||||
// of an assembler. Others require dynamic adjustment of block sizes in
|
||||
// AdjustBBOffsetsAfter; it's a big compile-time speed hit to check every
|
||||
// instruction in there, and none of these are currently used in the kernel.
|
||||
else if (strncmp(Str, ".macro", strlen(".macro"))==0 ||
|
||||
strncmp(Str, ".if", strlen(".if"))==0 ||
|
||||
strncmp(Str, ".align", strlen(".align"))==0 ||
|
||||
strncmp(Str, ".fill", strlen(".fill"))==0 ||
|
||||
strncmp(Str, ".space", strlen(".space"))==0 ||
|
||||
strncmp(Str, ".zerofill", strlen(".zerofill"))==0 ||
|
||||
strncmp(Str, ".p2align", strlen(".p2align"))==0 ||
|
||||
strncmp(Str, ".p2alignw", strlen(".p2alignw"))==0 ||
|
||||
strncmp(Str, ".p2alignl", strlen(".p2alignl"))==0 ||
|
||||
strncmp(Str, ".align32", strlen(".p2align32"))==0 ||
|
||||
strncmp(Str, ".include", strlen(".include"))==0)
|
||||
cerr << "Directive " << Str << " in asm may lead to invalid offsets for" <<
|
||||
" constant pools (the assembler will tell you if this happens).\n";
|
||||
// Some generate code, but this is only interesting in the text section.
|
||||
else if (inTextSection) {
|
||||
if (strncmp(Str, ".long", strlen(".long"))==0)
|
||||
Length += 4*countArguments(Str+strlen(".long"));
|
||||
else if (strncmp(Str, ".short", strlen(".short"))==0)
|
||||
Length += 2*countArguments(Str+strlen(".short"));
|
||||
else if (strncmp(Str, ".byte", strlen(".byte"))==0)
|
||||
Length += 1*countArguments(Str+strlen(".byte"));
|
||||
else if (strncmp(Str, ".single", strlen(".single"))==0)
|
||||
Length += 4*countArguments(Str+strlen(".single"));
|
||||
else if (strncmp(Str, ".double", strlen(".double"))==0)
|
||||
Length += 8*countArguments(Str+strlen(".double"));
|
||||
else if (strncmp(Str, ".quad", strlen(".quad"))==0)
|
||||
Length += 16*countArguments(Str+strlen(".quad"));
|
||||
else if (strncmp(Str, ".ascii", strlen(".ascii"))==0)
|
||||
Length += countString(Str+strlen(".ascii"));
|
||||
else if (strncmp(Str, ".asciz", strlen(".asciz"))==0)
|
||||
Length += countString(Str+strlen(".asciz"))+1;
|
||||
}
|
||||
} else if (inTextSection) {
|
||||
// An instruction
|
||||
atInsnStart = false;
|
||||
if (Subtarget->isThumb()) {
|
||||
// BL and BLX <non-reg> are 4 bytes, all others 2.
|
||||
if (strncmp(Str, "blx", strlen("blx"))==0) {
|
||||
const char* p = Str+3;
|
||||
while (*p && isspace(*p))
|
||||
p++;
|
||||
if (*p == 'r' || *p=='R')
|
||||
Length += 2; // BLX reg
|
||||
else
|
||||
Length += 4; // BLX non-reg
|
||||
} else if (strncmp(Str, "bl", strlen("bl"))==0)
|
||||
Length += 4; // BL
|
||||
else
|
||||
Length += 2; // Thumb anything else
|
||||
}
|
||||
else
|
||||
Length += 4; // ARM
|
||||
}
|
||||
}
|
||||
if (*Str == '\n' || *Str == BaseTAI::SeparatorChar)
|
||||
atInsnStart = true;
|
||||
}
|
||||
free(s_copy);
|
||||
return Length;
|
||||
}
|
||||
|
||||
// Instantiate default implementation.
|
||||
TEMPLATE_INSTANTIATION(class ARMTargetAsmInfo<TargetAsmInfo>);
|
@ -1,63 +0,0 @@
|
||||
//=====-- ARMTargetAsmInfo.h - ARM asm properties -------------*- C++ -*--====//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the declaration of the ARMTargetAsmInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef ARMTARGETASMINFO_H
|
||||
#define ARMTARGETASMINFO_H
|
||||
|
||||
#include "ARMTargetMachine.h"
|
||||
#include "llvm/Target/TargetAsmInfo.h"
|
||||
#include "llvm/Target/ELFTargetAsmInfo.h"
|
||||
#include "llvm/Target/DarwinTargetAsmInfo.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
extern const char *const arm_asm_table[];
|
||||
|
||||
template <class BaseTAI>
|
||||
struct ARMTargetAsmInfo : public BaseTAI {
|
||||
explicit ARMTargetAsmInfo(const ARMBaseTargetMachine &TM) : BaseTAI(TM) {
|
||||
BaseTAI::AsmTransCBE = arm_asm_table;
|
||||
|
||||
BaseTAI::AlignmentIsInBytes = false;
|
||||
BaseTAI::Data64bitsDirective = 0;
|
||||
BaseTAI::CommentString = "@";
|
||||
BaseTAI::ConstantPoolSection = "\t.text\n";
|
||||
BaseTAI::COMMDirectiveTakesAlignment = false;
|
||||
BaseTAI::InlineAsmStart = "@ InlineAsm Start";
|
||||
BaseTAI::InlineAsmEnd = "@ InlineAsm End";
|
||||
BaseTAI::LCOMMDirective = "\t.lcomm\t";
|
||||
}
|
||||
|
||||
const ARMSubtarget *Subtarget;
|
||||
|
||||
virtual unsigned getInlineAsmLength(const char *Str) const;
|
||||
unsigned countArguments(const char *p) const;
|
||||
unsigned countString(const char *p) const;
|
||||
};
|
||||
|
||||
typedef ARMTargetAsmInfo<TargetAsmInfo> ARMGenericTargetAsmInfo;
|
||||
|
||||
EXTERN_TEMPLATE_INSTANTIATION(class ARMTargetAsmInfo<TargetAsmInfo>);
|
||||
|
||||
struct ARMDarwinTargetAsmInfo : public ARMTargetAsmInfo<DarwinTargetAsmInfo> {
|
||||
explicit ARMDarwinTargetAsmInfo(const ARMBaseTargetMachine &TM);
|
||||
};
|
||||
|
||||
struct ARMELFTargetAsmInfo : public ARMTargetAsmInfo<ELFTargetAsmInfo> {
|
||||
explicit ARMELFTargetAsmInfo(const ARMBaseTargetMachine &TM);
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
@ -1,31 +0,0 @@
|
||||
//===-- AlphaTargetAsmInfo.cpp - Alpha asm properties -----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the declarations of the AlphaTargetAsmInfo properties.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "AlphaTargetMachine.h"
|
||||
#include "AlphaTargetAsmInfo.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
AlphaTargetAsmInfo::AlphaTargetAsmInfo(const AlphaTargetMachine &TM)
|
||||
: TargetAsmInfo(TM) {
|
||||
AlignmentIsInBytes = false;
|
||||
PrivateGlobalPrefix = "$";
|
||||
JumpTableDirective = ".gprel32";
|
||||
JumpTableDataSection = "\t.section .rodata\n";
|
||||
WeakRefDirective = "\t.weak\t";
|
||||
}
|
||||
|
||||
unsigned AlphaTargetAsmInfo::RelocBehaviour() const {
|
||||
return (TM.getRelocationModel() != Reloc::Static ?
|
||||
Reloc::LocalOrGlobal : Reloc::Global);
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
//=====-- AlphaTargetAsmInfo.h - Alpha asm properties ---------*- C++ -*--====//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the declaration of the AlphaTargetAsmInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef ALPHATARGETASMINFO_H
|
||||
#define ALPHATARGETASMINFO_H
|
||||
|
||||
#include "llvm/Target/TargetAsmInfo.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
// Forward declaration.
|
||||
class AlphaTargetMachine;
|
||||
|
||||
struct AlphaTargetAsmInfo : public TargetAsmInfo {
|
||||
explicit AlphaTargetAsmInfo(const AlphaTargetMachine &TM);
|
||||
|
||||
virtual unsigned RelocBehaviour() const;
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
@ -1,73 +0,0 @@
|
||||
//===-- SPUTargetAsmInfo.cpp - Cell SPU asm properties ----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the declarations of the SPUTargetAsmInfo properties.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "SPUTargetAsmInfo.h"
|
||||
#include "SPUTargetMachine.h"
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/Dwarf.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::dwarf;
|
||||
|
||||
SPULinuxTargetAsmInfo::SPULinuxTargetAsmInfo(const SPUTargetMachine &TM) :
|
||||
SPUTargetAsmInfo<ELFTargetAsmInfo>(TM) {
|
||||
PCSymbol = ".";
|
||||
CommentString = "#";
|
||||
GlobalPrefix = "";
|
||||
PrivateGlobalPrefix = ".L";
|
||||
// This corresponds to what the gcc SPU compiler emits, for consistency.
|
||||
CStringSection = ".rodata.str";
|
||||
|
||||
// Has leb128, .loc and .file
|
||||
HasLEB128 = true;
|
||||
HasDotLocAndDotFile = true;
|
||||
|
||||
// BSS section needs to be emitted as ".section"
|
||||
BSSSection = "\t.section\t.bss";
|
||||
BSSSection_ = getUnnamedSection("\t.section\t.bss",
|
||||
SectionFlags::Writeable | SectionFlags::BSS,
|
||||
true);
|
||||
|
||||
SupportsDebugInformation = true;
|
||||
NeedsSet = true;
|
||||
DwarfAbbrevSection = "\t.section .debug_abbrev,\"\",@progbits";
|
||||
DwarfInfoSection = "\t.section .debug_info,\"\",@progbits";
|
||||
DwarfLineSection = "\t.section .debug_line,\"\",@progbits";
|
||||
DwarfFrameSection = "\t.section .debug_frame,\"\",@progbits";
|
||||
DwarfPubNamesSection = "\t.section .debug_pubnames,\"\",@progbits";
|
||||
DwarfPubTypesSection = "\t.section .debug_pubtypes,\"\",progbits";
|
||||
DwarfStrSection = "\t.section .debug_str,\"MS\",@progbits,1";
|
||||
DwarfLocSection = "\t.section .debug_loc,\"\",@progbits";
|
||||
DwarfARangesSection = "\t.section .debug_aranges,\"\",@progbits";
|
||||
DwarfRangesSection = "\t.section .debug_ranges,\"\",@progbits";
|
||||
DwarfMacroInfoSection = 0; // macro info not supported.
|
||||
|
||||
// Exception handling is not supported on CellSPU (think about it: you only
|
||||
// have 256K for code+data. Would you support exception handling?)
|
||||
SupportsExceptionHandling = false;
|
||||
}
|
||||
|
||||
/// PreferredEHDataFormat - This hook allows the target to select data
|
||||
/// format used for encoding pointers in exception handling data. Reason is
|
||||
/// 0 for data, 1 for code labels, 2 for function pointers. Global is true
|
||||
/// if the symbol can be relocated.
|
||||
unsigned
|
||||
SPULinuxTargetAsmInfo::PreferredEHDataFormat(DwarfEncoding::Target Reason,
|
||||
bool Global) const {
|
||||
// We really need to write something here.
|
||||
return TargetAsmInfo::PreferredEHDataFormat(Reason, Global);
|
||||
}
|
||||
|
||||
// Instantiate default implementation.
|
||||
TEMPLATE_INSTANTIATION(class SPUTargetAsmInfo<TargetAsmInfo>);
|
@ -1,51 +0,0 @@
|
||||
//===-- SPUTargetAsmInfo.h - Cell SPU asm properties -----------*- C++ -*--===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the declaration of the SPUTargetAsmInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SPUTARGETASMINFO_H
|
||||
#define SPUTARGETASMINFO_H
|
||||
|
||||
#include "llvm/Target/TargetAsmInfo.h"
|
||||
#include "llvm/Target/ELFTargetAsmInfo.h"
|
||||
#include "SPUTargetMachine.h"
|
||||
#include "SPUSubtarget.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
// Forward declaration.
|
||||
class SPUTargetMachine;
|
||||
|
||||
template <class BaseTAI>
|
||||
struct SPUTargetAsmInfo : public BaseTAI {
|
||||
explicit SPUTargetAsmInfo(const SPUTargetMachine &TM):
|
||||
BaseTAI(TM) {
|
||||
/* (unused today)
|
||||
* const SPUSubtarget *Subtarget = &TM.getSubtarget<SPUSubtarget>(); */
|
||||
|
||||
BaseTAI::ZeroDirective = "\t.space\t";
|
||||
BaseTAI::SetDirective = "\t.set";
|
||||
BaseTAI::Data64bitsDirective = "\t.quad\t";
|
||||
BaseTAI::AlignmentIsInBytes = false;
|
||||
BaseTAI::LCOMMDirective = "\t.lcomm\t";
|
||||
BaseTAI::InlineAsmStart = "# InlineAsm Start";
|
||||
BaseTAI::InlineAsmEnd = "# InlineAsm End";
|
||||
}
|
||||
};
|
||||
|
||||
struct SPULinuxTargetAsmInfo : public SPUTargetAsmInfo<ELFTargetAsmInfo> {
|
||||
explicit SPULinuxTargetAsmInfo(const SPUTargetMachine &TM);
|
||||
virtual unsigned PreferredEHDataFormat(DwarfEncoding::Target Reason,
|
||||
bool Global) const;
|
||||
};
|
||||
} // namespace llvm
|
||||
|
||||
#endif /* SPUTARGETASMINFO_H */
|
@ -1,216 +0,0 @@
|
||||
//===-- DarwinTargetAsmInfo.cpp - Darwin asm properties ---------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines target asm properties related what form asm statements
|
||||
// should take in general on Darwin-based targets
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/GlobalVariable.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/Support/Mangler.h"
|
||||
#include "llvm/Target/DarwinTargetAsmInfo.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Target/TargetData.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
DarwinTargetAsmInfo::DarwinTargetAsmInfo(const TargetMachine &TM)
|
||||
: TargetAsmInfo(TM) {
|
||||
|
||||
CStringSection_ = getUnnamedSection("\t.cstring",
|
||||
SectionFlags::Mergeable | SectionFlags::Strings);
|
||||
FourByteConstantSection = getUnnamedSection("\t.literal4\n",
|
||||
SectionFlags::Mergeable);
|
||||
EightByteConstantSection = getUnnamedSection("\t.literal8\n",
|
||||
SectionFlags::Mergeable);
|
||||
|
||||
// Note: 16-byte constant section is subtarget specific and should be provided
|
||||
// there, if needed.
|
||||
SixteenByteConstantSection = 0;
|
||||
|
||||
ReadOnlySection = getUnnamedSection("\t.const\n", SectionFlags::None);
|
||||
|
||||
TextCoalSection =
|
||||
getNamedSection("\t__TEXT,__textcoal_nt,coalesced,pure_instructions",
|
||||
SectionFlags::Code);
|
||||
ConstTextCoalSection = getNamedSection("\t__TEXT,__const_coal,coalesced",
|
||||
SectionFlags::None);
|
||||
ConstDataCoalSection = getNamedSection("\t__DATA,__const_coal,coalesced",
|
||||
SectionFlags::None);
|
||||
ConstDataSection = getUnnamedSection(".const_data", SectionFlags::None);
|
||||
DataCoalSection = getNamedSection("\t__DATA,__datacoal_nt,coalesced",
|
||||
SectionFlags::Writeable);
|
||||
|
||||
|
||||
// Common settings for all Darwin targets.
|
||||
// Syntax:
|
||||
GlobalPrefix = "_";
|
||||
PrivateGlobalPrefix = "L";
|
||||
LessPrivateGlobalPrefix = "l"; // Marker for some ObjC metadata
|
||||
StringConstantPrefix = "\1LC";
|
||||
NeedsSet = true;
|
||||
NeedsIndirectEncoding = true;
|
||||
AllowQuotesInName = true;
|
||||
HasSingleParameterDotFile = false;
|
||||
|
||||
// In non-PIC modes, emit a special label before jump tables so that the
|
||||
// linker can perform more accurate dead code stripping. We do not check the
|
||||
// relocation model here since it can be overridden later.
|
||||
JumpTableSpecialLabelPrefix = "l";
|
||||
|
||||
// Directives:
|
||||
WeakDefDirective = "\t.weak_definition ";
|
||||
WeakRefDirective = "\t.weak_reference ";
|
||||
HiddenDirective = "\t.private_extern ";
|
||||
|
||||
// Sections:
|
||||
CStringSection = "\t.cstring";
|
||||
JumpTableDataSection = "\t.const\n";
|
||||
BSSSection = 0;
|
||||
|
||||
if (TM.getRelocationModel() == Reloc::Static) {
|
||||
StaticCtorsSection = ".constructor";
|
||||
StaticDtorsSection = ".destructor";
|
||||
} else {
|
||||
StaticCtorsSection = ".mod_init_func";
|
||||
StaticDtorsSection = ".mod_term_func";
|
||||
}
|
||||
|
||||
DwarfAbbrevSection = ".section __DWARF,__debug_abbrev,regular,debug";
|
||||
DwarfInfoSection = ".section __DWARF,__debug_info,regular,debug";
|
||||
DwarfLineSection = ".section __DWARF,__debug_line,regular,debug";
|
||||
DwarfFrameSection = ".section __DWARF,__debug_frame,regular,debug";
|
||||
DwarfPubNamesSection = ".section __DWARF,__debug_pubnames,regular,debug";
|
||||
DwarfPubTypesSection = ".section __DWARF,__debug_pubtypes,regular,debug";
|
||||
DwarfStrSection = ".section __DWARF,__debug_str,regular,debug";
|
||||
DwarfLocSection = ".section __DWARF,__debug_loc,regular,debug";
|
||||
DwarfARangesSection = ".section __DWARF,__debug_aranges,regular,debug";
|
||||
DwarfRangesSection = ".section __DWARF,__debug_ranges,regular,debug";
|
||||
DwarfMacroInfoSection = ".section __DWARF,__debug_macinfo,regular,debug";
|
||||
}
|
||||
|
||||
/// emitUsedDirectiveFor - On Darwin, internally linked data beginning with
|
||||
/// the PrivateGlobalPrefix or the LessPrivateGlobalPrefix does not have the
|
||||
/// directive emitted (this occurs in ObjC metadata).
|
||||
|
||||
bool
|
||||
DarwinTargetAsmInfo::emitUsedDirectiveFor(const GlobalValue* GV,
|
||||
Mangler *Mang) const {
|
||||
if (GV==0)
|
||||
return false;
|
||||
if (GV->hasLocalLinkage() && !isa<Function>(GV) &&
|
||||
((strlen(getPrivateGlobalPrefix()) != 0 &&
|
||||
Mang->getValueName(GV).substr(0,strlen(getPrivateGlobalPrefix())) ==
|
||||
getPrivateGlobalPrefix()) ||
|
||||
(strlen(getLessPrivateGlobalPrefix()) != 0 &&
|
||||
Mang->getValueName(GV).substr(0,strlen(getLessPrivateGlobalPrefix())) ==
|
||||
getLessPrivateGlobalPrefix())))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
const Section*
|
||||
DarwinTargetAsmInfo::SelectSectionForGlobal(const GlobalValue *GV) const {
|
||||
SectionKind::Kind Kind = SectionKindForGlobal(GV);
|
||||
bool isWeak = GV->isWeakForLinker();
|
||||
bool isNonStatic = TM.getRelocationModel() != Reloc::Static;
|
||||
|
||||
switch (Kind) {
|
||||
case SectionKind::Text:
|
||||
if (isWeak)
|
||||
return TextCoalSection;
|
||||
else
|
||||
return TextSection;
|
||||
case SectionKind::Data:
|
||||
case SectionKind::ThreadData:
|
||||
case SectionKind::BSS:
|
||||
case SectionKind::ThreadBSS:
|
||||
if (cast<GlobalVariable>(GV)->isConstant())
|
||||
return (isWeak ? ConstDataCoalSection : ConstDataSection);
|
||||
else
|
||||
return (isWeak ? DataCoalSection : DataSection);
|
||||
case SectionKind::ROData:
|
||||
return (isWeak ? ConstDataCoalSection :
|
||||
(isNonStatic ? ConstDataSection : getReadOnlySection()));
|
||||
case SectionKind::RODataMergeStr:
|
||||
return (isWeak ?
|
||||
ConstTextCoalSection :
|
||||
MergeableStringSection(cast<GlobalVariable>(GV)));
|
||||
case SectionKind::RODataMergeConst:
|
||||
return (isWeak ?
|
||||
ConstDataCoalSection:
|
||||
MergeableConstSection(cast<GlobalVariable>(GV)));
|
||||
default:
|
||||
assert(0 && "Unsuported section kind for global");
|
||||
}
|
||||
|
||||
// FIXME: Do we have any extra special weird cases?
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const Section*
|
||||
DarwinTargetAsmInfo::MergeableStringSection(const GlobalVariable *GV) const {
|
||||
const TargetData *TD = TM.getTargetData();
|
||||
Constant *C = cast<GlobalVariable>(GV)->getInitializer();
|
||||
const Type *Ty = cast<ArrayType>(C->getType())->getElementType();
|
||||
|
||||
unsigned Size = TD->getTypeAllocSize(Ty);
|
||||
if (Size) {
|
||||
unsigned Align = TD->getPreferredAlignment(GV);
|
||||
if (Align <= 32)
|
||||
return getCStringSection_();
|
||||
}
|
||||
|
||||
return getReadOnlySection();
|
||||
}
|
||||
|
||||
const Section*
|
||||
DarwinTargetAsmInfo::MergeableConstSection(const GlobalVariable *GV) const {
|
||||
Constant *C = GV->getInitializer();
|
||||
|
||||
return MergeableConstSection(C->getType());
|
||||
}
|
||||
|
||||
inline const Section*
|
||||
DarwinTargetAsmInfo::MergeableConstSection(const Type *Ty) const {
|
||||
const TargetData *TD = TM.getTargetData();
|
||||
|
||||
unsigned Size = TD->getTypeAllocSize(Ty);
|
||||
if (Size == 4)
|
||||
return FourByteConstantSection;
|
||||
else if (Size == 8)
|
||||
return EightByteConstantSection;
|
||||
else if (Size == 16 && SixteenByteConstantSection)
|
||||
return SixteenByteConstantSection;
|
||||
|
||||
return getReadOnlySection();
|
||||
}
|
||||
|
||||
const Section*
|
||||
DarwinTargetAsmInfo::SelectSectionForMachineConst(const Type *Ty) const {
|
||||
const Section* S = MergeableConstSection(Ty);
|
||||
|
||||
// Handle weird special case, when compiling PIC stuff.
|
||||
if (S == getReadOnlySection() &&
|
||||
TM.getRelocationModel() != Reloc::Static)
|
||||
return ConstDataSection;
|
||||
|
||||
return S;
|
||||
}
|
||||
|
||||
std::string
|
||||
DarwinTargetAsmInfo::UniqueSectionForGlobal(const GlobalValue* GV,
|
||||
SectionKind::Kind kind) const {
|
||||
assert(0 && "Darwin does not use unique sections");
|
||||
return "";
|
||||
}
|
@ -1,227 +0,0 @@
|
||||
//===-- ELFTargetAsmInfo.cpp - ELF asm properties ---------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines target asm properties related what form asm statements
|
||||
// should take in general on ELF-based targets
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/GlobalVariable.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/CodeGen/MachineConstantPool.h"
|
||||
#include "llvm/Target/ELFTargetAsmInfo.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Target/TargetData.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
ELFTargetAsmInfo::ELFTargetAsmInfo(const TargetMachine &TM)
|
||||
: TargetAsmInfo(TM) {
|
||||
|
||||
BSSSection_ = getUnnamedSection("\t.bss",
|
||||
SectionFlags::Writeable | SectionFlags::BSS);
|
||||
ReadOnlySection = getNamedSection("\t.rodata", SectionFlags::None);
|
||||
TLSDataSection = getNamedSection("\t.tdata",
|
||||
SectionFlags::Writeable | SectionFlags::TLS);
|
||||
TLSBSSSection = getNamedSection("\t.tbss",
|
||||
SectionFlags::Writeable | SectionFlags::TLS | SectionFlags::BSS);
|
||||
|
||||
DataRelSection = getNamedSection("\t.data.rel", SectionFlags::Writeable);
|
||||
DataRelLocalSection = getNamedSection("\t.data.rel.local",
|
||||
SectionFlags::Writeable);
|
||||
DataRelROSection = getNamedSection("\t.data.rel.ro",
|
||||
SectionFlags::Writeable);
|
||||
DataRelROLocalSection = getNamedSection("\t.data.rel.ro.local",
|
||||
SectionFlags::Writeable);
|
||||
}
|
||||
|
||||
SectionKind::Kind
|
||||
ELFTargetAsmInfo::SectionKindForGlobal(const GlobalValue *GV) const {
|
||||
SectionKind::Kind Kind = TargetAsmInfo::SectionKindForGlobal(GV);
|
||||
|
||||
if (Kind != SectionKind::Data)
|
||||
return Kind;
|
||||
|
||||
// Decide, whether we need data.rel stuff
|
||||
const GlobalVariable* GVar = dyn_cast<GlobalVariable>(GV);
|
||||
if (GVar->hasInitializer()) {
|
||||
Constant *C = GVar->getInitializer();
|
||||
bool isConstant = GVar->isConstant();
|
||||
unsigned Reloc = RelocBehaviour();
|
||||
if (Reloc != Reloc::None && C->ContainsRelocations(Reloc))
|
||||
return (C->ContainsRelocations(Reloc::Global) ?
|
||||
(isConstant ?
|
||||
SectionKind::DataRelRO : SectionKind::DataRel) :
|
||||
(isConstant ?
|
||||
SectionKind::DataRelROLocal : SectionKind::DataRelLocal));
|
||||
}
|
||||
|
||||
return Kind;
|
||||
}
|
||||
|
||||
const Section*
|
||||
ELFTargetAsmInfo::SelectSectionForGlobal(const GlobalValue *GV) const {
|
||||
SectionKind::Kind Kind = SectionKindForGlobal(GV);
|
||||
|
||||
if (const Function *F = dyn_cast<Function>(GV)) {
|
||||
switch (F->getLinkage()) {
|
||||
default: assert(0 && "Unknown linkage type!");
|
||||
case Function::PrivateLinkage:
|
||||
case Function::InternalLinkage:
|
||||
case Function::DLLExportLinkage:
|
||||
case Function::ExternalLinkage:
|
||||
return TextSection;
|
||||
case Function::WeakAnyLinkage:
|
||||
case Function::WeakODRLinkage:
|
||||
case Function::LinkOnceAnyLinkage:
|
||||
case Function::LinkOnceODRLinkage:
|
||||
std::string Name = UniqueSectionForGlobal(GV, Kind);
|
||||
unsigned Flags = SectionFlagsForGlobal(GV, Name.c_str());
|
||||
return getNamedSection(Name.c_str(), Flags);
|
||||
}
|
||||
} else if (const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GV)) {
|
||||
if (GVar->isWeakForLinker()) {
|
||||
std::string Name = UniqueSectionForGlobal(GVar, Kind);
|
||||
unsigned Flags = SectionFlagsForGlobal(GVar, Name.c_str());
|
||||
return getNamedSection(Name.c_str(), Flags);
|
||||
} else {
|
||||
switch (Kind) {
|
||||
case SectionKind::Data:
|
||||
case SectionKind::SmallData:
|
||||
return DataSection;
|
||||
case SectionKind::DataRel:
|
||||
return DataRelSection;
|
||||
case SectionKind::DataRelLocal:
|
||||
return DataRelLocalSection;
|
||||
case SectionKind::DataRelRO:
|
||||
return DataRelROSection;
|
||||
case SectionKind::DataRelROLocal:
|
||||
return DataRelROLocalSection;
|
||||
case SectionKind::BSS:
|
||||
case SectionKind::SmallBSS:
|
||||
// ELF targets usually have BSS sections
|
||||
return getBSSSection_();
|
||||
case SectionKind::ROData:
|
||||
case SectionKind::SmallROData:
|
||||
return getReadOnlySection();
|
||||
case SectionKind::RODataMergeStr:
|
||||
return MergeableStringSection(GVar);
|
||||
case SectionKind::RODataMergeConst:
|
||||
return MergeableConstSection(GVar);
|
||||
case SectionKind::ThreadData:
|
||||
// ELF targets usually support TLS stuff
|
||||
return TLSDataSection;
|
||||
case SectionKind::ThreadBSS:
|
||||
return TLSBSSSection;
|
||||
default:
|
||||
assert(0 && "Unsuported section kind for global");
|
||||
}
|
||||
}
|
||||
} else
|
||||
assert(0 && "Unsupported global");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const Section*
|
||||
ELFTargetAsmInfo::SelectSectionForMachineConst(const Type *Ty) const {
|
||||
// FIXME: Support data.rel stuff someday
|
||||
return MergeableConstSection(Ty);
|
||||
}
|
||||
|
||||
const Section*
|
||||
ELFTargetAsmInfo::MergeableConstSection(const GlobalVariable *GV) const {
|
||||
Constant *C = GV->getInitializer();
|
||||
return MergeableConstSection(C->getType());
|
||||
}
|
||||
|
||||
inline const Section*
|
||||
ELFTargetAsmInfo::MergeableConstSection(const Type *Ty) const {
|
||||
const TargetData *TD = TM.getTargetData();
|
||||
|
||||
// FIXME: string here is temporary, until stuff will fully land in.
|
||||
// We cannot use {Four,Eight,Sixteen}ByteConstantSection here, since it's
|
||||
// currently directly used by asmprinter.
|
||||
unsigned Size = TD->getTypeAllocSize(Ty);
|
||||
if (Size == 4 || Size == 8 || Size == 16) {
|
||||
std::string Name = ".rodata.cst" + utostr(Size);
|
||||
|
||||
return getNamedSection(Name.c_str(),
|
||||
SectionFlags::setEntitySize(SectionFlags::Mergeable,
|
||||
Size));
|
||||
}
|
||||
|
||||
return getReadOnlySection();
|
||||
}
|
||||
|
||||
const Section*
|
||||
ELFTargetAsmInfo::MergeableStringSection(const GlobalVariable *GV) const {
|
||||
const TargetData *TD = TM.getTargetData();
|
||||
Constant *C = cast<GlobalVariable>(GV)->getInitializer();
|
||||
const Type *Ty = cast<ArrayType>(C->getType())->getElementType();
|
||||
|
||||
unsigned Size = TD->getTypeAllocSize(Ty);
|
||||
if (Size <= 16) {
|
||||
assert(getCStringSection() && "Should have string section prefix");
|
||||
|
||||
// We also need alignment here
|
||||
unsigned Align = TD->getPrefTypeAlignment(Ty);
|
||||
if (Align < Size)
|
||||
Align = Size;
|
||||
|
||||
std::string Name = getCStringSection() + utostr(Size) + '.' + utostr(Align);
|
||||
unsigned Flags = SectionFlags::setEntitySize(SectionFlags::Mergeable |
|
||||
SectionFlags::Strings,
|
||||
Size);
|
||||
return getNamedSection(Name.c_str(), Flags);
|
||||
}
|
||||
|
||||
return getReadOnlySection();
|
||||
}
|
||||
|
||||
std::string ELFTargetAsmInfo::printSectionFlags(unsigned flags) const {
|
||||
std::string Flags = ",\"";
|
||||
|
||||
if (!(flags & SectionFlags::Debug))
|
||||
Flags += 'a';
|
||||
if (flags & SectionFlags::Code)
|
||||
Flags += 'x';
|
||||
if (flags & SectionFlags::Writeable)
|
||||
Flags += 'w';
|
||||
if (flags & SectionFlags::Mergeable)
|
||||
Flags += 'M';
|
||||
if (flags & SectionFlags::Strings)
|
||||
Flags += 'S';
|
||||
if (flags & SectionFlags::TLS)
|
||||
Flags += 'T';
|
||||
if (flags & SectionFlags::Small)
|
||||
Flags += 's';
|
||||
|
||||
Flags += "\",";
|
||||
|
||||
// If comment string is '@', e.g. as on ARM - use '%' instead
|
||||
if (strcmp(CommentString, "@") == 0)
|
||||
Flags += '%';
|
||||
else
|
||||
Flags += '@';
|
||||
|
||||
// FIXME: There can be exceptions here
|
||||
if (flags & SectionFlags::BSS)
|
||||
Flags += "nobits";
|
||||
else
|
||||
Flags += "progbits";
|
||||
|
||||
if (unsigned entitySize = SectionFlags::getEntitySize(flags))
|
||||
Flags += "," + utostr(entitySize);
|
||||
|
||||
return Flags;
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
include_directories(
|
||||
${CMAKE_CURRENT_BINARY_DIR}/..
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/..
|
||||
)
|
||||
|
||||
add_llvm_library(LLVMIA64AsmPrinter
|
||||
IA64AsmPrinter.cpp
|
||||
)
|
||||
add_dependencies(LLVMIA64AsmPrinter IA64CodeGenTable_gen)
|
@ -1,389 +0,0 @@
|
||||
//===-- IA64AsmPrinter.cpp - Print out IA64 LLVM as assembly --------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains a printer that converts from our internal representation
|
||||
// of machine-dependent LLVM code to assembly accepted by the GNU binutils 'gas'
|
||||
// assembler. The Intel 'ias' and HP-UX 'as' assemblers *may* choke on this
|
||||
// output, but if so that's a bug I'd like to hear about: please file a bug
|
||||
// report in bugzilla. FYI, the not too bad 'ias' assembler is bundled with
|
||||
// the Intel C/C++ compiler for Itanium Linux.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define DEBUG_TYPE "asm-printer"
|
||||
#include "IA64.h"
|
||||
#include "IA64TargetMachine.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/MDNode.h"
|
||||
#include "llvm/Type.h"
|
||||
#include "llvm/CodeGen/AsmPrinter.h"
|
||||
#include "llvm/CodeGen/DwarfWriter.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/Target/TargetAsmInfo.h"
|
||||
#include "llvm/Support/Mangler.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
using namespace llvm;
|
||||
|
||||
STATISTIC(EmittedInsts, "Number of machine instrs printed");
|
||||
|
||||
namespace {
|
||||
class IA64AsmPrinter : public AsmPrinter {
|
||||
std::set<std::string> ExternalFunctionNames, ExternalObjectNames;
|
||||
public:
|
||||
explicit IA64AsmPrinter(raw_ostream &O, TargetMachine &TM,
|
||||
const TargetAsmInfo *T, bool V)
|
||||
: AsmPrinter(O, TM, T, V) {}
|
||||
|
||||
virtual const char *getPassName() const {
|
||||
return "IA64 Assembly Printer";
|
||||
}
|
||||
|
||||
/// printInstruction - This method is automatically generated by tablegen
|
||||
/// from the instruction set description. This method returns true if the
|
||||
/// machine instruction was sufficiently described to print it, otherwise it
|
||||
/// returns false.
|
||||
bool printInstruction(const MachineInstr *MI);
|
||||
|
||||
// This method is used by the tablegen'erated instruction printer.
|
||||
void printOperand(const MachineInstr *MI, unsigned OpNo){
|
||||
const MachineOperand &MO = MI->getOperand(OpNo);
|
||||
if (MO.getType() == MachineOperand::MO_Register) {
|
||||
assert(TargetRegisterInfo::isPhysicalRegister(MO.getReg()) &&
|
||||
"Not physref??");
|
||||
//XXX Bug Workaround: See note in Printer::doInitialization about %.
|
||||
O << TM.getRegisterInfo()->get(MO.getReg()).AsmName;
|
||||
} else {
|
||||
printOp(MO);
|
||||
}
|
||||
}
|
||||
|
||||
void printS8ImmOperand(const MachineInstr *MI, unsigned OpNo) {
|
||||
int val=(unsigned int)MI->getOperand(OpNo).getImm();
|
||||
if(val>=128) val=val-256; // if negative, flip sign
|
||||
O << val;
|
||||
}
|
||||
void printS14ImmOperand(const MachineInstr *MI, unsigned OpNo) {
|
||||
int val=(unsigned int)MI->getOperand(OpNo).getImm();
|
||||
if(val>=8192) val=val-16384; // if negative, flip sign
|
||||
O << val;
|
||||
}
|
||||
void printS22ImmOperand(const MachineInstr *MI, unsigned OpNo) {
|
||||
int val=(unsigned int)MI->getOperand(OpNo).getImm();
|
||||
if(val>=2097152) val=val-4194304; // if negative, flip sign
|
||||
O << val;
|
||||
}
|
||||
void printU64ImmOperand(const MachineInstr *MI, unsigned OpNo) {
|
||||
O << (uint64_t)MI->getOperand(OpNo).getImm();
|
||||
}
|
||||
void printS64ImmOperand(const MachineInstr *MI, unsigned OpNo) {
|
||||
// XXX : nasty hack to avoid GPREL22 "relocation truncated to fit" linker
|
||||
// errors - instead of add rX = @gprel(CPI<whatever>), r1;; we now
|
||||
// emit movl rX = @gprel(CPI<whatever);;
|
||||
// add rX = rX, r1;
|
||||
// this gives us 64 bits instead of 22 (for the add long imm) to play
|
||||
// with, which shuts up the linker. The problem is that the constant
|
||||
// pool entries aren't immediates at this stage, so we check here.
|
||||
// If it's an immediate, print it the old fashioned way. If it's
|
||||
// not, we print it as a constant pool index.
|
||||
if (MI->getOperand(OpNo).isImm()) {
|
||||
O << (int64_t)MI->getOperand(OpNo).getImm();
|
||||
} else { // this is a constant pool reference: FIXME: assert this
|
||||
printOp(MI->getOperand(OpNo));
|
||||
}
|
||||
}
|
||||
|
||||
void printGlobalOperand(const MachineInstr *MI, unsigned OpNo) {
|
||||
printOp(MI->getOperand(OpNo), false); // this is NOT a br.call instruction
|
||||
}
|
||||
|
||||
void printCallOperand(const MachineInstr *MI, unsigned OpNo) {
|
||||
printOp(MI->getOperand(OpNo), true); // this is a br.call instruction
|
||||
}
|
||||
|
||||
void printMachineInstruction(const MachineInstr *MI);
|
||||
void printOp(const MachineOperand &MO, bool isBRCALLinsn= false);
|
||||
void printModuleLevelGV(const GlobalVariable* GVar);
|
||||
bool runOnMachineFunction(MachineFunction &F);
|
||||
bool doInitialization(Module &M);
|
||||
bool doFinalization(Module &M);
|
||||
};
|
||||
} // end of anonymous namespace
|
||||
|
||||
|
||||
// Include the auto-generated portion of the assembly writer.
|
||||
#include "IA64GenAsmWriter.inc"
|
||||
|
||||
/// runOnMachineFunction - This uses the printMachineInstruction()
|
||||
/// method to print assembly for each instruction.
|
||||
///
|
||||
bool IA64AsmPrinter::runOnMachineFunction(MachineFunction &MF) {
|
||||
this->MF = &MF;
|
||||
|
||||
SetupMachineFunction(MF);
|
||||
O << "\n\n";
|
||||
|
||||
// Print out constants referenced by the function
|
||||
EmitConstantPool(MF.getConstantPool());
|
||||
|
||||
const Function *F = MF.getFunction();
|
||||
SwitchToSection(TAI->SectionForGlobal(F));
|
||||
|
||||
// Print out labels for the function.
|
||||
EmitAlignment(MF.getAlignment());
|
||||
O << "\t.global\t" << CurrentFnName << '\n';
|
||||
|
||||
printVisibility(CurrentFnName, F->getVisibility());
|
||||
|
||||
O << "\t.type\t" << CurrentFnName << ", @function\n";
|
||||
O << CurrentFnName << ":\n";
|
||||
|
||||
// Print out code for the function.
|
||||
for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
|
||||
I != E; ++I) {
|
||||
// Print a label for the basic block if there are any predecessors.
|
||||
if (!I->pred_empty()) {
|
||||
printBasicBlockLabel(I, true, true);
|
||||
O << '\n';
|
||||
}
|
||||
for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
|
||||
II != E; ++II) {
|
||||
// Print the assembly for the instruction.
|
||||
printMachineInstruction(II);
|
||||
}
|
||||
}
|
||||
|
||||
// We didn't modify anything.
|
||||
return false;
|
||||
}
|
||||
|
||||
void IA64AsmPrinter::printOp(const MachineOperand &MO,
|
||||
bool isBRCALLinsn /* = false */) {
|
||||
const TargetRegisterInfo &RI = *TM.getRegisterInfo();
|
||||
switch (MO.getType()) {
|
||||
case MachineOperand::MO_Register:
|
||||
O << RI.get(MO.getReg()).AsmName;
|
||||
return;
|
||||
|
||||
case MachineOperand::MO_Immediate:
|
||||
O << MO.getImm();
|
||||
return;
|
||||
case MachineOperand::MO_MachineBasicBlock:
|
||||
printBasicBlockLabel(MO.getMBB());
|
||||
return;
|
||||
case MachineOperand::MO_ConstantPoolIndex: {
|
||||
O << "@gprel(" << TAI->getPrivateGlobalPrefix()
|
||||
<< "CPI" << getFunctionNumber() << "_" << MO.getIndex() << ")";
|
||||
return;
|
||||
}
|
||||
|
||||
case MachineOperand::MO_GlobalAddress: {
|
||||
|
||||
// functions need @ltoff(@fptr(fn_name)) form
|
||||
GlobalValue *GV = MO.getGlobal();
|
||||
Function *F = dyn_cast<Function>(GV);
|
||||
|
||||
bool Needfptr=false; // if we're computing an address @ltoff(X), do
|
||||
// we need to decorate it so it becomes
|
||||
// @ltoff(@fptr(X)) ?
|
||||
if (F && !isBRCALLinsn /*&& F->isDeclaration()*/)
|
||||
Needfptr=true;
|
||||
|
||||
// if this is the target of a call instruction, we should define
|
||||
// the function somewhere (GNU gas has no problem without this, but
|
||||
// Intel ias rightly complains of an 'undefined symbol')
|
||||
|
||||
if (F /*&& isBRCALLinsn*/ && F->isDeclaration())
|
||||
ExternalFunctionNames.insert(Mang->getValueName(MO.getGlobal()));
|
||||
else
|
||||
if (GV->isDeclaration()) // e.g. stuff like 'stdin'
|
||||
ExternalObjectNames.insert(Mang->getValueName(MO.getGlobal()));
|
||||
|
||||
if (!isBRCALLinsn)
|
||||
O << "@ltoff(";
|
||||
if (Needfptr)
|
||||
O << "@fptr(";
|
||||
O << Mang->getValueName(MO.getGlobal());
|
||||
|
||||
if (Needfptr && !isBRCALLinsn)
|
||||
O << "#))"; // close both fptr( and ltoff(
|
||||
else {
|
||||
if (Needfptr)
|
||||
O << "#)"; // close only fptr(
|
||||
if (!isBRCALLinsn)
|
||||
O << "#)"; // close only ltoff(
|
||||
}
|
||||
|
||||
int Offset = MO.getOffset();
|
||||
if (Offset > 0)
|
||||
O << " + " << Offset;
|
||||
else if (Offset < 0)
|
||||
O << " - " << -Offset;
|
||||
return;
|
||||
}
|
||||
case MachineOperand::MO_ExternalSymbol:
|
||||
O << MO.getSymbolName();
|
||||
ExternalFunctionNames.insert(MO.getSymbolName());
|
||||
return;
|
||||
default:
|
||||
O << "<AsmPrinter: unknown operand type: " << MO.getType() << " >"; return;
|
||||
}
|
||||
}
|
||||
|
||||
/// printMachineInstruction -- Print out a single IA64 LLVM instruction
|
||||
/// MI to the current output stream.
|
||||
///
|
||||
void IA64AsmPrinter::printMachineInstruction(const MachineInstr *MI) {
|
||||
++EmittedInsts;
|
||||
|
||||
// Call the autogenerated instruction printer routines.
|
||||
printInstruction(MI);
|
||||
}
|
||||
|
||||
bool IA64AsmPrinter::doInitialization(Module &M) {
|
||||
bool Result = AsmPrinter::doInitialization(M);
|
||||
|
||||
O << "\n.ident \"LLVM-ia64\"\n\n"
|
||||
<< "\t.psr lsb\n" // should be "msb" on HP-UX, for starters
|
||||
<< "\t.radix C\n"
|
||||
<< "\t.psr abi64\n"; // we only support 64 bits for now
|
||||
return Result;
|
||||
}
|
||||
|
||||
void IA64AsmPrinter::printModuleLevelGV(const GlobalVariable* GVar) {
|
||||
const TargetData *TD = TM.getTargetData();
|
||||
|
||||
if (!GVar->hasInitializer())
|
||||
return; // External global require no code
|
||||
|
||||
// Check to see if this is a special global used by LLVM, if so, emit it.
|
||||
if (EmitSpecialLLVMGlobal(GVar))
|
||||
return;
|
||||
|
||||
O << "\n\n";
|
||||
std::string name = Mang->getValueName(GVar);
|
||||
Constant *C = GVar->getInitializer();
|
||||
if (isa<MDNode>(C) || isa<MDString>(C))
|
||||
return;
|
||||
unsigned Size = TD->getTypeAllocSize(C->getType());
|
||||
unsigned Align = TD->getPreferredAlignmentLog(GVar);
|
||||
|
||||
printVisibility(name, GVar->getVisibility());
|
||||
|
||||
SwitchToSection(TAI->SectionForGlobal(GVar));
|
||||
|
||||
if (C->isNullValue() && !GVar->hasSection()) {
|
||||
if (!GVar->isThreadLocal() &&
|
||||
(GVar->hasLocalLinkage() || GVar->isWeakForLinker())) {
|
||||
if (Size == 0) Size = 1; // .comm Foo, 0 is undefined, avoid it.
|
||||
|
||||
if (GVar->hasLocalLinkage()) {
|
||||
O << "\t.lcomm " << name << "#," << Size
|
||||
<< ',' << (1 << Align);
|
||||
O << '\n';
|
||||
} else {
|
||||
O << "\t.common " << name << "#," << Size
|
||||
<< ',' << (1 << Align);
|
||||
O << '\n';
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (GVar->getLinkage()) {
|
||||
case GlobalValue::LinkOnceAnyLinkage:
|
||||
case GlobalValue::LinkOnceODRLinkage:
|
||||
case GlobalValue::CommonLinkage:
|
||||
case GlobalValue::WeakAnyLinkage:
|
||||
case GlobalValue::WeakODRLinkage:
|
||||
// Nonnull linkonce -> weak
|
||||
O << "\t.weak " << name << '\n';
|
||||
break;
|
||||
case GlobalValue::AppendingLinkage:
|
||||
// FIXME: appending linkage variables should go into a section of
|
||||
// their name or something. For now, just emit them as external.
|
||||
case GlobalValue::ExternalLinkage:
|
||||
// If external or appending, declare as a global symbol
|
||||
O << TAI->getGlobalDirective() << name << '\n';
|
||||
// FALL THROUGH
|
||||
case GlobalValue::InternalLinkage:
|
||||
case GlobalValue::PrivateLinkage:
|
||||
break;
|
||||
case GlobalValue::GhostLinkage:
|
||||
cerr << "GhostLinkage cannot appear in IA64AsmPrinter!\n";
|
||||
abort();
|
||||
case GlobalValue::DLLImportLinkage:
|
||||
cerr << "DLLImport linkage is not supported by this target!\n";
|
||||
abort();
|
||||
case GlobalValue::DLLExportLinkage:
|
||||
cerr << "DLLExport linkage is not supported by this target!\n";
|
||||
abort();
|
||||
default:
|
||||
assert(0 && "Unknown linkage type!");
|
||||
}
|
||||
|
||||
EmitAlignment(Align, GVar);
|
||||
|
||||
if (TAI->hasDotTypeDotSizeDirective()) {
|
||||
O << "\t.type " << name << ",@object\n";
|
||||
O << "\t.size " << name << ',' << Size << '\n';
|
||||
}
|
||||
|
||||
O << name << ":\n";
|
||||
EmitGlobalConstant(C);
|
||||
}
|
||||
|
||||
|
||||
bool IA64AsmPrinter::doFinalization(Module &M) {
|
||||
// Print out module-level global variables here.
|
||||
for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
|
||||
I != E; ++I)
|
||||
printModuleLevelGV(I);
|
||||
|
||||
// we print out ".global X \n .type X, @function" for each external function
|
||||
O << "\n\n// br.call targets referenced (and not defined) above: \n";
|
||||
for (std::set<std::string>::iterator i = ExternalFunctionNames.begin(),
|
||||
e = ExternalFunctionNames.end(); i!=e; ++i) {
|
||||
O << "\t.global " << *i << "\n\t.type " << *i << ", @function\n";
|
||||
}
|
||||
O << "\n\n";
|
||||
|
||||
// we print out ".global X \n .type X, @object" for each external object
|
||||
O << "\n\n// (external) symbols referenced (and not defined) above: \n";
|
||||
for (std::set<std::string>::iterator i = ExternalObjectNames.begin(),
|
||||
e = ExternalObjectNames.end(); i!=e; ++i) {
|
||||
O << "\t.global " << *i << "\n\t.type " << *i << ", @object\n";
|
||||
}
|
||||
O << "\n\n";
|
||||
|
||||
return AsmPrinter::doFinalization(M);
|
||||
}
|
||||
|
||||
/// createIA64CodePrinterPass - Returns a pass that prints the IA64
|
||||
/// assembly code for a MachineFunction to the given output stream, using
|
||||
/// the given target machine description.
|
||||
///
|
||||
FunctionPass *llvm::createIA64CodePrinterPass(raw_ostream &o,
|
||||
IA64TargetMachine &tm,
|
||||
bool verbose) {
|
||||
return new IA64AsmPrinter(o, tm, tm.getTargetAsmInfo(), verbose);
|
||||
}
|
||||
|
||||
namespace {
|
||||
static struct Register {
|
||||
Register() {
|
||||
IA64TargetMachine::registerAsmPrinter(createIA64CodePrinterPass);
|
||||
}
|
||||
} Registrator;
|
||||
}
|
||||
|
||||
|
||||
// Force static initialization.
|
||||
extern "C" void LLVMInitializeIA64AsmPrinter() { }
|
@ -1,17 +0,0 @@
|
||||
##===- lib/Target/IA64/AsmPrinter/Makefile -----------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL = ../../../..
|
||||
LIBRARYNAME = LLVMIA64AsmPrinter
|
||||
|
||||
# Hack: we need to include 'main' IA64 target directory to grab
|
||||
# private headers
|
||||
CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/..
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
@ -1,22 +0,0 @@
|
||||
set(LLVM_TARGET_DEFINITIONS IA64.td)
|
||||
|
||||
tablegen(IA64GenRegisterInfo.h.inc -gen-register-desc-header)
|
||||
tablegen(IA64GenRegisterNames.inc -gen-register-enums)
|
||||
tablegen(IA64GenRegisterInfo.inc -gen-register-desc)
|
||||
tablegen(IA64GenInstrNames.inc -gen-instr-enums)
|
||||
tablegen(IA64GenInstrInfo.inc -gen-instr-desc)
|
||||
tablegen(IA64GenAsmWriter.inc -gen-asm-writer)
|
||||
tablegen(IA64GenDAGISel.inc -gen-dag-isel)
|
||||
|
||||
add_llvm_target(IA64CodeGen
|
||||
IA64Bundling.cpp
|
||||
IA64InstrInfo.cpp
|
||||
IA64ISelDAGToDAG.cpp
|
||||
IA64ISelLowering.cpp
|
||||
IA64RegisterInfo.cpp
|
||||
IA64Subtarget.cpp
|
||||
IA64TargetAsmInfo.cpp
|
||||
IA64TargetMachine.cpp
|
||||
)
|
||||
|
||||
target_link_libraries (LLVMIA64CodeGen LLVMSelectionDAG)
|
@ -1,57 +0,0 @@
|
||||
//===-- IA64.h - Top-level interface for IA64 representation ------*- C++ -*-===//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the entry points for global functions defined in the IA64
|
||||
// target library, as used by the LLVM JIT.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef TARGET_IA64_H
|
||||
#define TARGET_IA64_H
|
||||
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class IA64TargetMachine;
|
||||
class FunctionPass;
|
||||
class raw_ostream;
|
||||
|
||||
/// createIA64DAGToDAGInstructionSelector - This pass converts an LLVM
|
||||
/// function into IA64 machine code in a sane, DAG->DAG transform.
|
||||
///
|
||||
FunctionPass *createIA64DAGToDAGInstructionSelector(IA64TargetMachine &TM);
|
||||
|
||||
/// createIA64BundlingPass - This pass adds stop bits and bundles
|
||||
/// instructions.
|
||||
///
|
||||
FunctionPass *createIA64BundlingPass(IA64TargetMachine &TM);
|
||||
|
||||
/// createIA64CodePrinterPass - Returns a pass that prints the IA64
|
||||
/// assembly code for a MachineFunction to the given output stream,
|
||||
/// using the given target machine description. This should work
|
||||
/// regardless of whether the function is in SSA form.
|
||||
///
|
||||
FunctionPass *createIA64CodePrinterPass(raw_ostream &o,
|
||||
IA64TargetMachine &tm,
|
||||
bool verbose);
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
// Defines symbolic names for IA64 registers. This defines a mapping from
|
||||
// register name to register number.
|
||||
//
|
||||
#include "IA64GenRegisterNames.inc"
|
||||
|
||||
// Defines symbolic names for the IA64 instructions.
|
||||
//
|
||||
#include "IA64GenInstrNames.inc"
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1,39 +0,0 @@
|
||||
//===-- IA64.td - Target definition file for Intel IA64 -------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This is a target description file for the Intel IA64 architecture,
|
||||
// also known variously as ia64, IA-64, IPF, "the Itanium architecture" etc.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Get the target-independent interfaces which we are implementing...
|
||||
//
|
||||
include "llvm/Target/Target.td"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Register File Description
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
include "IA64RegisterInfo.td"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Instruction Descriptions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
include "IA64InstrInfo.td"
|
||||
|
||||
def IA64InstrInfo : InstrInfo { }
|
||||
|
||||
def IA64 : Target {
|
||||
// Our instruction set
|
||||
let InstructionSet = IA64InstrInfo;
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,118 +0,0 @@
|
||||
//===-- IA64Bundling.cpp - IA-64 instruction bundling pass. ------------ --===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Add stops where required to prevent read-after-write and write-after-write
|
||||
// dependencies, for both registers and memory addresses. There are exceptions:
|
||||
//
|
||||
// - Compare instructions (cmp*, tbit, tnat, fcmp, frcpa) are OK with
|
||||
// WAW dependencies so long as they all target p0, or are of parallel
|
||||
// type (.and*/.or*)
|
||||
//
|
||||
// FIXME: bundling, for now, is left to the assembler.
|
||||
// FIXME: this might be an appropriate place to translate between different
|
||||
// instructions that do the same thing, if this helps bundling.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define DEBUG_TYPE "ia64-codegen"
|
||||
#include "IA64.h"
|
||||
#include "IA64InstrInfo.h"
|
||||
#include "IA64TargetMachine.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/ADT/SetOperations.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include <set>
|
||||
using namespace llvm;
|
||||
|
||||
STATISTIC(StopBitsAdded, "Number of stop bits added");
|
||||
|
||||
namespace {
|
||||
struct IA64BundlingPass : public MachineFunctionPass {
|
||||
static char ID;
|
||||
/// Target machine description which we query for reg. names, data
|
||||
/// layout, etc.
|
||||
///
|
||||
IA64TargetMachine &TM;
|
||||
|
||||
IA64BundlingPass(IA64TargetMachine &tm)
|
||||
: MachineFunctionPass(&ID), TM(tm) { }
|
||||
|
||||
virtual const char *getPassName() const {
|
||||
return "IA64 (Itanium) Bundling Pass";
|
||||
}
|
||||
|
||||
bool runOnMachineBasicBlock(MachineBasicBlock &MBB);
|
||||
bool runOnMachineFunction(MachineFunction &F) {
|
||||
bool Changed = false;
|
||||
for (MachineFunction::iterator FI = F.begin(), FE = F.end();
|
||||
FI != FE; ++FI)
|
||||
Changed |= runOnMachineBasicBlock(*FI);
|
||||
return Changed;
|
||||
}
|
||||
|
||||
// XXX: ugly global, but pending writes can cross basic blocks. Note that
|
||||
// taken branches end instruction groups. So we only need to worry about
|
||||
// 'fallthrough' code
|
||||
std::set<unsigned> PendingRegWrites;
|
||||
};
|
||||
char IA64BundlingPass::ID = 0;
|
||||
} // end of anonymous namespace
|
||||
|
||||
/// createIA64BundlingPass - Returns a pass that adds STOP (;;) instructions
|
||||
/// and arranges the result into bundles.
|
||||
///
|
||||
FunctionPass *llvm::createIA64BundlingPass(IA64TargetMachine &tm) {
|
||||
return new IA64BundlingPass(tm);
|
||||
}
|
||||
|
||||
/// runOnMachineBasicBlock - add stops and bundle this MBB.
|
||||
///
|
||||
bool IA64BundlingPass::runOnMachineBasicBlock(MachineBasicBlock &MBB) {
|
||||
bool Changed = false;
|
||||
|
||||
for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ) {
|
||||
MachineInstr *CurrentInsn = I++;
|
||||
std::set<unsigned> CurrentReads, CurrentWrites, OrigWrites;
|
||||
|
||||
for(unsigned i=0; i < CurrentInsn->getNumOperands(); i++) {
|
||||
MachineOperand &MO=CurrentInsn->getOperand(i);
|
||||
if (MO.isReg()) {
|
||||
if(MO.isUse()) { // TODO: exclude p0
|
||||
CurrentReads.insert(MO.getReg());
|
||||
}
|
||||
if(MO.isDef()) { // TODO: exclude p0
|
||||
CurrentWrites.insert(MO.getReg());
|
||||
OrigWrites.insert(MO.getReg()); // FIXME: use a nondestructive
|
||||
// set_intersect instead?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CurrentReads/CurrentWrites contain info for the current instruction.
|
||||
// Does it read or write any registers that are pending a write?
|
||||
// (i.e. not separated by a stop)
|
||||
set_intersect(CurrentReads, PendingRegWrites);
|
||||
set_intersect(CurrentWrites, PendingRegWrites);
|
||||
|
||||
if(! (CurrentReads.empty() && CurrentWrites.empty()) ) {
|
||||
// there is a conflict, insert a stop and reset PendingRegWrites
|
||||
CurrentInsn = BuildMI(MBB, CurrentInsn, CurrentInsn->getDebugLoc(),
|
||||
TM.getInstrInfo()->get(IA64::STOP), 0);
|
||||
PendingRegWrites=OrigWrites; // carry over current writes to next insn
|
||||
Changed=true; StopBitsAdded++; // update stats
|
||||
} else { // otherwise, track additional pending writes
|
||||
set_union(PendingRegWrites, OrigWrites);
|
||||
}
|
||||
} // onto the next insn in the MBB
|
||||
|
||||
return Changed;
|
||||
}
|
||||
|
@ -1,575 +0,0 @@
|
||||
//===---- IA64ISelDAGToDAG.cpp - IA64 pattern matching inst selector ------===//
|
||||
//
|
||||
// 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 pattern matching instruction selector for IA64,
|
||||
// converting a legalized dag to an IA64 dag.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define DEBUG_TYPE "ia64-codegen"
|
||||
#include "IA64.h"
|
||||
#include "IA64TargetMachine.h"
|
||||
#include "IA64ISelLowering.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/SelectionDAG.h"
|
||||
#include "llvm/CodeGen/SelectionDAGISel.h"
|
||||
#include "llvm/Target/TargetOptions.h"
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/GlobalValue.h"
|
||||
#include "llvm/Intrinsics.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// IA64DAGToDAGISel - IA64 specific code to select IA64 machine
|
||||
/// instructions for SelectionDAG operations.
|
||||
///
|
||||
class IA64DAGToDAGISel : public SelectionDAGISel {
|
||||
unsigned GlobalBaseReg;
|
||||
public:
|
||||
explicit IA64DAGToDAGISel(IA64TargetMachine &TM)
|
||||
: SelectionDAGISel(TM) {}
|
||||
|
||||
virtual bool runOnFunction(Function &Fn) {
|
||||
// Make sure we re-emit a set of the global base reg if necessary
|
||||
GlobalBaseReg = 0;
|
||||
return SelectionDAGISel::runOnFunction(Fn);
|
||||
}
|
||||
|
||||
/// getI64Imm - Return a target constant with the specified value, of type
|
||||
/// i64.
|
||||
inline SDValue getI64Imm(uint64_t Imm) {
|
||||
return CurDAG->getTargetConstant(Imm, MVT::i64);
|
||||
}
|
||||
|
||||
/// getGlobalBaseReg - insert code into the entry mbb to materialize the PIC
|
||||
/// base register. Return the virtual register that holds this value.
|
||||
// SDValue getGlobalBaseReg(); TODO: hmm
|
||||
|
||||
// Select - Convert the specified operand from a target-independent to a
|
||||
// target-specific node if it hasn't already been changed.
|
||||
SDNode *Select(SDValue N);
|
||||
|
||||
SDNode *SelectIntImmediateExpr(SDValue LHS, SDValue RHS,
|
||||
unsigned OCHi, unsigned OCLo,
|
||||
bool IsArithmetic = false,
|
||||
bool Negate = false);
|
||||
SDNode *SelectBitfieldInsert(SDNode *N);
|
||||
|
||||
/// SelectCC - Select a comparison of the specified values with the
|
||||
/// specified condition code, returning the CR# of the expression.
|
||||
SDValue SelectCC(SDValue LHS, SDValue RHS, ISD::CondCode CC);
|
||||
|
||||
/// SelectAddr - Given the specified address, return the two operands for a
|
||||
/// load/store instruction, and return true if it should be an indexed [r+r]
|
||||
/// operation.
|
||||
bool SelectAddr(SDValue Addr, SDValue &Op1, SDValue &Op2);
|
||||
|
||||
/// InstructionSelect - This callback is invoked by
|
||||
/// SelectionDAGISel when it has created a SelectionDAG for us to codegen.
|
||||
virtual void InstructionSelect();
|
||||
|
||||
virtual const char *getPassName() const {
|
||||
return "IA64 (Itanium) DAG->DAG Instruction Selector";
|
||||
}
|
||||
|
||||
// Include the pieces autogenerated from the target description.
|
||||
#include "IA64GenDAGISel.inc"
|
||||
|
||||
private:
|
||||
SDNode *SelectDIV(SDValue Op);
|
||||
};
|
||||
}
|
||||
|
||||
/// InstructionSelect - This callback is invoked by
|
||||
/// SelectionDAGISel when it has created a SelectionDAG for us to codegen.
|
||||
void IA64DAGToDAGISel::InstructionSelect() {
|
||||
DEBUG(BB->dump());
|
||||
|
||||
// Select target instructions for the DAG.
|
||||
SelectRoot(*CurDAG);
|
||||
CurDAG->RemoveDeadNodes();
|
||||
}
|
||||
|
||||
SDNode *IA64DAGToDAGISel::SelectDIV(SDValue Op) {
|
||||
SDNode *N = Op.getNode();
|
||||
SDValue Chain = N->getOperand(0);
|
||||
SDValue Tmp1 = N->getOperand(0);
|
||||
SDValue Tmp2 = N->getOperand(1);
|
||||
DebugLoc dl = N->getDebugLoc();
|
||||
|
||||
bool isFP=false;
|
||||
|
||||
if(Tmp1.getValueType().isFloatingPoint())
|
||||
isFP=true;
|
||||
|
||||
bool isModulus=false; // is it a division or a modulus?
|
||||
bool isSigned=false;
|
||||
|
||||
switch(N->getOpcode()) {
|
||||
case ISD::FDIV:
|
||||
case ISD::SDIV: isModulus=false; isSigned=true; break;
|
||||
case ISD::UDIV: isModulus=false; isSigned=false; break;
|
||||
case ISD::FREM:
|
||||
case ISD::SREM: isModulus=true; isSigned=true; break;
|
||||
case ISD::UREM: isModulus=true; isSigned=false; break;
|
||||
}
|
||||
|
||||
// TODO: check for integer divides by powers of 2 (or other simple patterns?)
|
||||
|
||||
SDValue TmpPR, TmpPR2;
|
||||
SDValue TmpF1, TmpF2, TmpF3, TmpF4, TmpF5, TmpF6, TmpF7, TmpF8;
|
||||
SDValue TmpF9, TmpF10,TmpF11,TmpF12,TmpF13,TmpF14,TmpF15;
|
||||
SDNode *Result;
|
||||
|
||||
// we'll need copies of F0 and F1
|
||||
SDValue F0 = CurDAG->getRegister(IA64::F0, MVT::f64);
|
||||
SDValue F1 = CurDAG->getRegister(IA64::F1, MVT::f64);
|
||||
|
||||
// OK, emit some code:
|
||||
|
||||
if(!isFP) {
|
||||
// first, load the inputs into FP regs.
|
||||
TmpF1 =
|
||||
SDValue(CurDAG->getTargetNode(IA64::SETFSIG, dl, MVT::f64, Tmp1), 0);
|
||||
Chain = TmpF1.getValue(1);
|
||||
TmpF2 =
|
||||
SDValue(CurDAG->getTargetNode(IA64::SETFSIG, dl, MVT::f64, Tmp2), 0);
|
||||
Chain = TmpF2.getValue(1);
|
||||
|
||||
// next, convert the inputs to FP
|
||||
if(isSigned) {
|
||||
TmpF3 =
|
||||
SDValue(CurDAG->getTargetNode(IA64::FCVTXF, dl, MVT::f64, TmpF1), 0);
|
||||
Chain = TmpF3.getValue(1);
|
||||
TmpF4 =
|
||||
SDValue(CurDAG->getTargetNode(IA64::FCVTXF, dl, MVT::f64, TmpF2), 0);
|
||||
Chain = TmpF4.getValue(1);
|
||||
} else { // is unsigned
|
||||
TmpF3 =
|
||||
SDValue(CurDAG->getTargetNode(IA64::FCVTXUFS1, dl, MVT::f64, TmpF1),
|
||||
0);
|
||||
Chain = TmpF3.getValue(1);
|
||||
TmpF4 =
|
||||
SDValue(CurDAG->getTargetNode(IA64::FCVTXUFS1, dl, MVT::f64, TmpF2),
|
||||
0);
|
||||
Chain = TmpF4.getValue(1);
|
||||
}
|
||||
|
||||
} else { // this is an FP divide/remainder, so we 'leak' some temp
|
||||
// regs and assign TmpF3=Tmp1, TmpF4=Tmp2
|
||||
TmpF3=Tmp1;
|
||||
TmpF4=Tmp2;
|
||||
}
|
||||
|
||||
// we start by computing an approximate reciprocal (good to 9 bits?)
|
||||
// note, this instruction writes _both_ TmpF5 (answer) and TmpPR (predicate)
|
||||
if(isFP)
|
||||
TmpF5 = SDValue(CurDAG->getTargetNode(IA64::FRCPAS0, dl, MVT::f64,
|
||||
MVT::i1, TmpF3, TmpF4), 0);
|
||||
else
|
||||
TmpF5 = SDValue(CurDAG->getTargetNode(IA64::FRCPAS1, dl, MVT::f64,
|
||||
MVT::i1, TmpF3, TmpF4), 0);
|
||||
|
||||
TmpPR = TmpF5.getValue(1);
|
||||
Chain = TmpF5.getValue(2);
|
||||
|
||||
SDValue minusB;
|
||||
if(isModulus) { // for remainders, it'll be handy to have
|
||||
// copies of -input_b
|
||||
minusB = SDValue(CurDAG->getTargetNode(IA64::SUB, dl, MVT::i64,
|
||||
CurDAG->getRegister(IA64::r0, MVT::i64), Tmp2), 0);
|
||||
Chain = minusB.getValue(1);
|
||||
}
|
||||
|
||||
SDValue TmpE0, TmpY1, TmpE1, TmpY2;
|
||||
|
||||
SDValue OpsE0[] = { TmpF4, TmpF5, F1, TmpPR };
|
||||
TmpE0 = SDValue(CurDAG->getTargetNode(IA64::CFNMAS1, dl, MVT::f64,
|
||||
OpsE0, 4), 0);
|
||||
Chain = TmpE0.getValue(1);
|
||||
SDValue OpsY1[] = { TmpF5, TmpE0, TmpF5, TmpPR };
|
||||
TmpY1 = SDValue(CurDAG->getTargetNode(IA64::CFMAS1, dl, MVT::f64,
|
||||
OpsY1, 4), 0);
|
||||
Chain = TmpY1.getValue(1);
|
||||
SDValue OpsE1[] = { TmpE0, TmpE0, F0, TmpPR };
|
||||
TmpE1 = SDValue(CurDAG->getTargetNode(IA64::CFMAS1, dl, MVT::f64,
|
||||
OpsE1, 4), 0);
|
||||
Chain = TmpE1.getValue(1);
|
||||
SDValue OpsY2[] = { TmpY1, TmpE1, TmpY1, TmpPR };
|
||||
TmpY2 = SDValue(CurDAG->getTargetNode(IA64::CFMAS1, dl, MVT::f64,
|
||||
OpsY2, 4), 0);
|
||||
Chain = TmpY2.getValue(1);
|
||||
|
||||
if(isFP) { // if this is an FP divide, we finish up here and exit early
|
||||
if(isModulus)
|
||||
assert(0 && "Sorry, try another FORTRAN compiler.");
|
||||
|
||||
SDValue TmpE2, TmpY3, TmpQ0, TmpR0;
|
||||
|
||||
SDValue OpsE2[] = { TmpE1, TmpE1, F0, TmpPR };
|
||||
TmpE2 = SDValue(CurDAG->getTargetNode(IA64::CFMAS1, dl, MVT::f64,
|
||||
OpsE2, 4), 0);
|
||||
Chain = TmpE2.getValue(1);
|
||||
SDValue OpsY3[] = { TmpY2, TmpE2, TmpY2, TmpPR };
|
||||
TmpY3 = SDValue(CurDAG->getTargetNode(IA64::CFMAS1, dl, MVT::f64,
|
||||
OpsY3, 4), 0);
|
||||
Chain = TmpY3.getValue(1);
|
||||
SDValue OpsQ0[] = { Tmp1, TmpY3, F0, TmpPR };
|
||||
TmpQ0 =
|
||||
SDValue(CurDAG->getTargetNode(IA64::CFMADS1, dl, // double prec!
|
||||
MVT::f64, OpsQ0, 4), 0);
|
||||
Chain = TmpQ0.getValue(1);
|
||||
SDValue OpsR0[] = { Tmp2, TmpQ0, Tmp1, TmpPR };
|
||||
TmpR0 =
|
||||
SDValue(CurDAG->getTargetNode(IA64::CFNMADS1, dl, // double prec!
|
||||
MVT::f64, OpsR0, 4), 0);
|
||||
Chain = TmpR0.getValue(1);
|
||||
|
||||
// we want Result to have the same target register as the frcpa, so
|
||||
// we two-address hack it. See the comment "for this to work..." on
|
||||
// page 48 of Intel application note #245415
|
||||
SDValue Ops[] = { TmpF5, TmpY3, TmpR0, TmpQ0, TmpPR };
|
||||
Result = CurDAG->getTargetNode(IA64::TCFMADS0, dl, // d.p. s0 rndg!
|
||||
MVT::f64, Ops, 5);
|
||||
Chain = SDValue(Result, 1);
|
||||
return Result; // XXX: early exit!
|
||||
} else { // this is *not* an FP divide, so there's a bit left to do:
|
||||
|
||||
SDValue TmpQ2, TmpR2, TmpQ3, TmpQ;
|
||||
|
||||
SDValue OpsQ2[] = { TmpF3, TmpY2, F0, TmpPR };
|
||||
TmpQ2 = SDValue(CurDAG->getTargetNode(IA64::CFMAS1, dl, MVT::f64,
|
||||
OpsQ2, 4), 0);
|
||||
Chain = TmpQ2.getValue(1);
|
||||
SDValue OpsR2[] = { TmpF4, TmpQ2, TmpF3, TmpPR };
|
||||
TmpR2 = SDValue(CurDAG->getTargetNode(IA64::CFNMAS1, dl, MVT::f64,
|
||||
OpsR2, 4), 0);
|
||||
Chain = TmpR2.getValue(1);
|
||||
|
||||
// we want TmpQ3 to have the same target register as the frcpa? maybe we
|
||||
// should two-address hack it. See the comment "for this to work..." on page
|
||||
// 48 of Intel application note #245415
|
||||
SDValue OpsQ3[] = { TmpF5, TmpR2, TmpY2, TmpQ2, TmpPR };
|
||||
TmpQ3 = SDValue(CurDAG->getTargetNode(IA64::TCFMAS1, dl, MVT::f64,
|
||||
OpsQ3, 5), 0);
|
||||
Chain = TmpQ3.getValue(1);
|
||||
|
||||
// STORY: without these two-address instructions (TCFMAS1 and TCFMADS0)
|
||||
// the FPSWA won't be able to help out in the case of large/tiny
|
||||
// arguments. Other fun bugs may also appear, e.g. 0/x = x, not 0.
|
||||
|
||||
if(isSigned)
|
||||
TmpQ = SDValue(CurDAG->getTargetNode(IA64::FCVTFXTRUNCS1, dl,
|
||||
MVT::f64, TmpQ3), 0);
|
||||
else
|
||||
TmpQ = SDValue(CurDAG->getTargetNode(IA64::FCVTFXUTRUNCS1, dl,
|
||||
MVT::f64, TmpQ3), 0);
|
||||
|
||||
Chain = TmpQ.getValue(1);
|
||||
|
||||
if(isModulus) {
|
||||
SDValue FPminusB =
|
||||
SDValue(CurDAG->getTargetNode(IA64::SETFSIG, dl, MVT::f64, minusB),
|
||||
0);
|
||||
Chain = FPminusB.getValue(1);
|
||||
SDValue Remainder =
|
||||
SDValue(CurDAG->getTargetNode(IA64::XMAL, dl, MVT::f64,
|
||||
TmpQ, FPminusB, TmpF1), 0);
|
||||
Chain = Remainder.getValue(1);
|
||||
Result = CurDAG->getTargetNode(IA64::GETFSIG, dl, MVT::i64, Remainder);
|
||||
Chain = SDValue(Result, 1);
|
||||
} else { // just an integer divide
|
||||
Result = CurDAG->getTargetNode(IA64::GETFSIG, dl, MVT::i64, TmpQ);
|
||||
Chain = SDValue(Result, 1);
|
||||
}
|
||||
|
||||
return Result;
|
||||
} // wasn't an FP divide
|
||||
}
|
||||
|
||||
// Select - Convert the specified operand from a target-independent to a
|
||||
// target-specific node if it hasn't already been changed.
|
||||
SDNode *IA64DAGToDAGISel::Select(SDValue Op) {
|
||||
SDNode *N = Op.getNode();
|
||||
if (N->isMachineOpcode())
|
||||
return NULL; // Already selected.
|
||||
DebugLoc dl = Op.getDebugLoc();
|
||||
|
||||
switch (N->getOpcode()) {
|
||||
default: break;
|
||||
|
||||
case IA64ISD::BRCALL: { // XXX: this is also a hack!
|
||||
SDValue Chain = N->getOperand(0);
|
||||
SDValue InFlag; // Null incoming flag value.
|
||||
|
||||
if(N->getNumOperands()==3) { // we have an incoming chain, callee and flag
|
||||
InFlag = N->getOperand(2);
|
||||
}
|
||||
|
||||
unsigned CallOpcode;
|
||||
SDValue CallOperand;
|
||||
|
||||
// if we can call directly, do so
|
||||
if (GlobalAddressSDNode *GASD =
|
||||
dyn_cast<GlobalAddressSDNode>(N->getOperand(1))) {
|
||||
CallOpcode = IA64::BRCALL_IPREL_GA;
|
||||
CallOperand = CurDAG->getTargetGlobalAddress(GASD->getGlobal(), MVT::i64);
|
||||
} else if (isa<ExternalSymbolSDNode>(N->getOperand(1))) {
|
||||
// FIXME: we currently NEED this case for correctness, to avoid
|
||||
// "non-pic code with imm reloc.n against dynamic symbol" errors
|
||||
CallOpcode = IA64::BRCALL_IPREL_ES;
|
||||
CallOperand = N->getOperand(1);
|
||||
} else {
|
||||
// otherwise we need to load the function descriptor,
|
||||
// load the branch target (function)'s entry point and GP,
|
||||
// branch (call) then restore the GP
|
||||
SDValue FnDescriptor = N->getOperand(1);
|
||||
|
||||
// load the branch target's entry point [mem] and
|
||||
// GP value [mem+8]
|
||||
SDValue targetEntryPoint=
|
||||
SDValue(CurDAG->getTargetNode(IA64::LD8, dl, MVT::i64, MVT::Other,
|
||||
FnDescriptor, CurDAG->getEntryNode()), 0);
|
||||
Chain = targetEntryPoint.getValue(1);
|
||||
SDValue targetGPAddr=
|
||||
SDValue(CurDAG->getTargetNode(IA64::ADDS, dl, MVT::i64,
|
||||
FnDescriptor,
|
||||
CurDAG->getConstant(8, MVT::i64)), 0);
|
||||
Chain = targetGPAddr.getValue(1);
|
||||
SDValue targetGP =
|
||||
SDValue(CurDAG->getTargetNode(IA64::LD8, dl, MVT::i64,MVT::Other,
|
||||
targetGPAddr, CurDAG->getEntryNode()), 0);
|
||||
Chain = targetGP.getValue(1);
|
||||
|
||||
Chain = CurDAG->getCopyToReg(Chain, dl, IA64::r1, targetGP, InFlag);
|
||||
InFlag = Chain.getValue(1);
|
||||
Chain = CurDAG->getCopyToReg(Chain, dl, IA64::B6,
|
||||
targetEntryPoint, InFlag); // FLAG these?
|
||||
InFlag = Chain.getValue(1);
|
||||
|
||||
CallOperand = CurDAG->getRegister(IA64::B6, MVT::i64);
|
||||
CallOpcode = IA64::BRCALL_INDIRECT;
|
||||
}
|
||||
|
||||
// Finally, once everything is setup, emit the call itself
|
||||
if (InFlag.getNode())
|
||||
Chain = SDValue(CurDAG->getTargetNode(CallOpcode, dl, MVT::Other,
|
||||
MVT::Flag, CallOperand, InFlag), 0);
|
||||
else // there might be no arguments
|
||||
Chain = SDValue(CurDAG->getTargetNode(CallOpcode, dl, MVT::Other,
|
||||
MVT::Flag, CallOperand, Chain), 0);
|
||||
InFlag = Chain.getValue(1);
|
||||
|
||||
std::vector<SDValue> CallResults;
|
||||
|
||||
CallResults.push_back(Chain);
|
||||
CallResults.push_back(InFlag);
|
||||
|
||||
for (unsigned i = 0, e = CallResults.size(); i != e; ++i)
|
||||
ReplaceUses(Op.getValue(i), CallResults[i]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
case IA64ISD::GETFD: {
|
||||
SDValue Input = N->getOperand(0);
|
||||
return CurDAG->getTargetNode(IA64::GETFD, dl, MVT::i64, Input);
|
||||
}
|
||||
|
||||
case ISD::FDIV:
|
||||
case ISD::SDIV:
|
||||
case ISD::UDIV:
|
||||
case ISD::SREM:
|
||||
case ISD::UREM:
|
||||
return SelectDIV(Op);
|
||||
|
||||
case ISD::TargetConstantFP: {
|
||||
SDValue Chain = CurDAG->getEntryNode(); // this is a constant, so..
|
||||
|
||||
SDValue V;
|
||||
ConstantFPSDNode* N2 = cast<ConstantFPSDNode>(N);
|
||||
if (N2->getValueAPF().isPosZero()) {
|
||||
V = CurDAG->getCopyFromReg(Chain, dl, IA64::F0, MVT::f64);
|
||||
} else if (N2->isExactlyValue(N2->getValueType(0) == MVT::f32 ?
|
||||
APFloat(+1.0f) : APFloat(+1.0))) {
|
||||
V = CurDAG->getCopyFromReg(Chain, dl, IA64::F1, MVT::f64);
|
||||
} else
|
||||
assert(0 && "Unexpected FP constant!");
|
||||
|
||||
ReplaceUses(SDValue(N, 0), V);
|
||||
return 0;
|
||||
}
|
||||
|
||||
case ISD::FrameIndex: { // TODO: reduce creepyness
|
||||
int FI = cast<FrameIndexSDNode>(N)->getIndex();
|
||||
if (N->hasOneUse())
|
||||
return CurDAG->SelectNodeTo(N, IA64::MOV, MVT::i64,
|
||||
CurDAG->getTargetFrameIndex(FI, MVT::i64));
|
||||
else
|
||||
return CurDAG->getTargetNode(IA64::MOV, dl, MVT::i64,
|
||||
CurDAG->getTargetFrameIndex(FI, MVT::i64));
|
||||
}
|
||||
|
||||
case ISD::ConstantPool: { // TODO: nuke the constant pool
|
||||
// (ia64 doesn't need one)
|
||||
ConstantPoolSDNode *CP = cast<ConstantPoolSDNode>(N);
|
||||
Constant *C = CP->getConstVal();
|
||||
SDValue CPI = CurDAG->getTargetConstantPool(C, MVT::i64,
|
||||
CP->getAlignment());
|
||||
return CurDAG->getTargetNode(IA64::ADDL_GA, dl, MVT::i64, // ?
|
||||
CurDAG->getRegister(IA64::r1, MVT::i64), CPI);
|
||||
}
|
||||
|
||||
case ISD::GlobalAddress: {
|
||||
GlobalValue *GV = cast<GlobalAddressSDNode>(N)->getGlobal();
|
||||
SDValue GA = CurDAG->getTargetGlobalAddress(GV, MVT::i64);
|
||||
SDValue Tmp =
|
||||
SDValue(CurDAG->getTargetNode(IA64::ADDL_GA, dl, MVT::i64,
|
||||
CurDAG->getRegister(IA64::r1,
|
||||
MVT::i64), GA), 0);
|
||||
return CurDAG->getTargetNode(IA64::LD8, dl, MVT::i64, MVT::Other, Tmp,
|
||||
CurDAG->getEntryNode());
|
||||
}
|
||||
|
||||
/* XXX
|
||||
case ISD::ExternalSymbol: {
|
||||
SDValue EA = CurDAG->getTargetExternalSymbol(
|
||||
cast<ExternalSymbolSDNode>(N)->getSymbol(),
|
||||
MVT::i64);
|
||||
SDValue Tmp = CurDAG->getTargetNode(IA64::ADDL_EA, dl, MVT::i64,
|
||||
CurDAG->getRegister(IA64::r1,
|
||||
MVT::i64),
|
||||
EA);
|
||||
return CurDAG->getTargetNode(IA64::LD8, dl, MVT::i64, Tmp);
|
||||
}
|
||||
*/
|
||||
|
||||
case ISD::LOAD: { // FIXME: load -1, not 1, for bools?
|
||||
LoadSDNode *LD = cast<LoadSDNode>(N);
|
||||
SDValue Chain = LD->getChain();
|
||||
SDValue Address = LD->getBasePtr();
|
||||
|
||||
MVT TypeBeingLoaded = LD->getMemoryVT();
|
||||
unsigned Opc;
|
||||
switch (TypeBeingLoaded.getSimpleVT()) {
|
||||
default:
|
||||
#ifndef NDEBUG
|
||||
N->dump(CurDAG);
|
||||
#endif
|
||||
assert(0 && "Cannot load this type!");
|
||||
case MVT::i1: { // this is a bool
|
||||
Opc = IA64::LD1; // first we load a byte, then compare for != 0
|
||||
if(N->getValueType(0) == MVT::i1) { // XXX: early exit!
|
||||
return CurDAG->SelectNodeTo(N, IA64::CMPNE, MVT::i1, MVT::Other,
|
||||
SDValue(CurDAG->getTargetNode(Opc, dl,
|
||||
MVT::i64,
|
||||
Address), 0),
|
||||
CurDAG->getRegister(IA64::r0, MVT::i64),
|
||||
Chain);
|
||||
}
|
||||
/* otherwise, we want to load a bool into something bigger: LD1
|
||||
will do that for us, so we just fall through */
|
||||
}
|
||||
case MVT::i8: Opc = IA64::LD1; break;
|
||||
case MVT::i16: Opc = IA64::LD2; break;
|
||||
case MVT::i32: Opc = IA64::LD4; break;
|
||||
case MVT::i64: Opc = IA64::LD8; break;
|
||||
|
||||
case MVT::f32: Opc = IA64::LDF4; break;
|
||||
case MVT::f64: Opc = IA64::LDF8; break;
|
||||
}
|
||||
|
||||
// TODO: comment this
|
||||
return CurDAG->SelectNodeTo(N, Opc, N->getValueType(0), MVT::Other,
|
||||
Address, Chain);
|
||||
}
|
||||
|
||||
case ISD::STORE: {
|
||||
StoreSDNode *ST = cast<StoreSDNode>(N);
|
||||
SDValue Address = ST->getBasePtr();
|
||||
SDValue Chain = ST->getChain();
|
||||
|
||||
unsigned Opc;
|
||||
if (ISD::isNON_TRUNCStore(N)) {
|
||||
switch (N->getOperand(1).getValueType().getSimpleVT()) {
|
||||
default: assert(0 && "unknown type in store");
|
||||
case MVT::i1: { // this is a bool
|
||||
Opc = IA64::ST1; // we store either 0 or 1 as a byte
|
||||
// first load zero!
|
||||
SDValue Initial = CurDAG->getCopyFromReg(Chain, dl, IA64::r0, MVT::i64);
|
||||
Chain = Initial.getValue(1);
|
||||
// then load 1 into the same reg iff the predicate to store is 1
|
||||
SDValue Tmp = ST->getValue();
|
||||
Tmp =
|
||||
SDValue(CurDAG->getTargetNode(IA64::TPCADDS, dl, MVT::i64, Initial,
|
||||
CurDAG->getTargetConstant(1,
|
||||
MVT::i64),
|
||||
Tmp), 0);
|
||||
return CurDAG->SelectNodeTo(N, Opc, MVT::Other, Address, Tmp, Chain);
|
||||
}
|
||||
case MVT::i64: Opc = IA64::ST8; break;
|
||||
case MVT::f64: Opc = IA64::STF8; break;
|
||||
}
|
||||
} else { // Truncating store
|
||||
switch(ST->getMemoryVT().getSimpleVT()) {
|
||||
default: assert(0 && "unknown type in truncstore");
|
||||
case MVT::i8: Opc = IA64::ST1; break;
|
||||
case MVT::i16: Opc = IA64::ST2; break;
|
||||
case MVT::i32: Opc = IA64::ST4; break;
|
||||
case MVT::f32: Opc = IA64::STF4; break;
|
||||
}
|
||||
}
|
||||
|
||||
SDValue N1 = N->getOperand(1);
|
||||
SDValue N2 = N->getOperand(2);
|
||||
return CurDAG->SelectNodeTo(N, Opc, MVT::Other, N2, N1, Chain);
|
||||
}
|
||||
|
||||
case ISD::BRCOND: {
|
||||
SDValue Chain = N->getOperand(0);
|
||||
SDValue CC = N->getOperand(1);
|
||||
MachineBasicBlock *Dest =
|
||||
cast<BasicBlockSDNode>(N->getOperand(2))->getBasicBlock();
|
||||
//FIXME - we do NOT need long branches all the time
|
||||
return CurDAG->SelectNodeTo(N, IA64::BRLCOND_NOTCALL, MVT::Other, CC,
|
||||
CurDAG->getBasicBlock(Dest), Chain);
|
||||
}
|
||||
|
||||
case ISD::CALLSEQ_START:
|
||||
case ISD::CALLSEQ_END: {
|
||||
int64_t Amt = cast<ConstantSDNode>(N->getOperand(1))->getZExtValue();
|
||||
unsigned Opc = N->getOpcode() == ISD::CALLSEQ_START ?
|
||||
IA64::ADJUSTCALLSTACKDOWN : IA64::ADJUSTCALLSTACKUP;
|
||||
SDValue N0 = N->getOperand(0);
|
||||
return CurDAG->SelectNodeTo(N, Opc, MVT::Other, getI64Imm(Amt), N0);
|
||||
}
|
||||
|
||||
case ISD::BR:
|
||||
// FIXME: we don't need long branches all the time!
|
||||
SDValue N0 = N->getOperand(0);
|
||||
return CurDAG->SelectNodeTo(N, IA64::BRL_NOTCALL, MVT::Other,
|
||||
N->getOperand(1), N0);
|
||||
}
|
||||
|
||||
return SelectCode(Op);
|
||||
}
|
||||
|
||||
|
||||
/// createIA64DAGToDAGInstructionSelector - This pass converts a legalized DAG
|
||||
/// into an IA64-specific DAG, ready for instruction scheduling.
|
||||
///
|
||||
FunctionPass
|
||||
*llvm::createIA64DAGToDAGInstructionSelector(IA64TargetMachine &TM) {
|
||||
return new IA64DAGToDAGISel(TM);
|
||||
}
|
||||
|
@ -1,632 +0,0 @@
|
||||
//===-- IA64ISelLowering.cpp - IA64 DAG Lowering Implementation -----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the IA64ISelLowering class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "IA64ISelLowering.h"
|
||||
#include "IA64MachineFunctionInfo.h"
|
||||
#include "IA64TargetMachine.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/SelectionDAG.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/Function.h"
|
||||
using namespace llvm;
|
||||
|
||||
IA64TargetLowering::IA64TargetLowering(TargetMachine &TM)
|
||||
: TargetLowering(TM) {
|
||||
|
||||
// register class for general registers
|
||||
addRegisterClass(MVT::i64, IA64::GRRegisterClass);
|
||||
|
||||
// register class for FP registers
|
||||
addRegisterClass(MVT::f64, IA64::FPRegisterClass);
|
||||
|
||||
// register class for predicate registers
|
||||
addRegisterClass(MVT::i1, IA64::PRRegisterClass);
|
||||
|
||||
setLoadExtAction(ISD::EXTLOAD , MVT::i1 , Promote);
|
||||
|
||||
setLoadExtAction(ISD::ZEXTLOAD , MVT::i1 , Promote);
|
||||
|
||||
setLoadExtAction(ISD::SEXTLOAD , MVT::i1 , Promote);
|
||||
setLoadExtAction(ISD::SEXTLOAD , MVT::i8 , Expand);
|
||||
setLoadExtAction(ISD::SEXTLOAD , MVT::i16 , Expand);
|
||||
setLoadExtAction(ISD::SEXTLOAD , MVT::i32 , Expand);
|
||||
|
||||
setOperationAction(ISD::BRIND , MVT::Other, Expand);
|
||||
setOperationAction(ISD::BR_JT , MVT::Other, Expand);
|
||||
setOperationAction(ISD::BR_CC , MVT::Other, Expand);
|
||||
setOperationAction(ISD::FP_ROUND_INREG , MVT::f32 , Expand);
|
||||
|
||||
// ia64 uses SELECT not SELECT_CC
|
||||
setOperationAction(ISD::SELECT_CC , MVT::Other, Expand);
|
||||
|
||||
// We need to handle ISD::RET for void functions ourselves,
|
||||
// so we get a chance to restore ar.pfs before adding a
|
||||
// br.ret insn
|
||||
setOperationAction(ISD::RET, MVT::Other, Custom);
|
||||
|
||||
setShiftAmountType(MVT::i64);
|
||||
|
||||
setOperationAction(ISD::FREM , MVT::f32 , Expand);
|
||||
setOperationAction(ISD::FREM , MVT::f64 , Expand);
|
||||
|
||||
setOperationAction(ISD::UREM , MVT::f32 , Expand);
|
||||
setOperationAction(ISD::UREM , MVT::f64 , Expand);
|
||||
|
||||
setOperationAction(ISD::MEMBARRIER , MVT::Other, Expand);
|
||||
|
||||
setOperationAction(ISD::SINT_TO_FP , MVT::i1 , Promote);
|
||||
setOperationAction(ISD::UINT_TO_FP , MVT::i1 , Promote);
|
||||
|
||||
// We don't support sin/cos/sqrt/pow
|
||||
setOperationAction(ISD::FSIN , MVT::f64, Expand);
|
||||
setOperationAction(ISD::FCOS , MVT::f64, Expand);
|
||||
setOperationAction(ISD::FSQRT, MVT::f64, Expand);
|
||||
setOperationAction(ISD::FPOW , MVT::f64, Expand);
|
||||
setOperationAction(ISD::FSIN , MVT::f32, Expand);
|
||||
setOperationAction(ISD::FCOS , MVT::f32, Expand);
|
||||
setOperationAction(ISD::FSQRT, MVT::f32, Expand);
|
||||
setOperationAction(ISD::FPOW , MVT::f32, Expand);
|
||||
|
||||
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1 , Expand);
|
||||
|
||||
// FIXME: IA64 supports fcopysign natively!
|
||||
setOperationAction(ISD::FCOPYSIGN, MVT::f64, Expand);
|
||||
setOperationAction(ISD::FCOPYSIGN, MVT::f32, Expand);
|
||||
|
||||
// We don't have line number support yet.
|
||||
setOperationAction(ISD::DBG_STOPPOINT, MVT::Other, Expand);
|
||||
setOperationAction(ISD::DEBUG_LOC, MVT::Other, Expand);
|
||||
setOperationAction(ISD::DBG_LABEL, MVT::Other, Expand);
|
||||
setOperationAction(ISD::EH_LABEL, MVT::Other, Expand);
|
||||
|
||||
// IA64 has ctlz in the form of the 'fnorm' instruction. The Legalizer
|
||||
// expansion for ctlz/cttz in terms of ctpop is much larger, but lower
|
||||
// latency.
|
||||
// FIXME: Custom lower CTLZ when compiling for size?
|
||||
setOperationAction(ISD::CTLZ , MVT::i64 , Expand);
|
||||
setOperationAction(ISD::CTTZ , MVT::i64 , Expand);
|
||||
setOperationAction(ISD::ROTL , MVT::i64 , Expand);
|
||||
setOperationAction(ISD::ROTR , MVT::i64 , Expand);
|
||||
|
||||
// FIXME: IA64 has this, but is not implemented. should be mux @rev
|
||||
setOperationAction(ISD::BSWAP, MVT::i64 , Expand);
|
||||
|
||||
// VASTART needs to be custom lowered to use the VarArgsFrameIndex
|
||||
setOperationAction(ISD::VAARG , MVT::Other, Custom);
|
||||
setOperationAction(ISD::VASTART , MVT::Other, Custom);
|
||||
|
||||
// FIXME: These should be legal
|
||||
setOperationAction(ISD::BIT_CONVERT, MVT::i64, Expand);
|
||||
setOperationAction(ISD::BIT_CONVERT, MVT::f64, Expand);
|
||||
|
||||
// Use the default implementation.
|
||||
setOperationAction(ISD::VACOPY , MVT::Other, Expand);
|
||||
setOperationAction(ISD::VAEND , MVT::Other, Expand);
|
||||
setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
|
||||
setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
|
||||
setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Expand);
|
||||
|
||||
// Thread Local Storage
|
||||
setOperationAction(ISD::GlobalTLSAddress, MVT::i64, Custom);
|
||||
|
||||
setStackPointerRegisterToSaveRestore(IA64::r12);
|
||||
|
||||
setJumpBufSize(704); // on ia64-linux, jmp_bufs are 704 bytes..
|
||||
setJumpBufAlignment(16); // ...and must be 16-byte aligned
|
||||
|
||||
computeRegisterProperties();
|
||||
|
||||
addLegalFPImmediate(APFloat(+0.0));
|
||||
addLegalFPImmediate(APFloat(-0.0));
|
||||
addLegalFPImmediate(APFloat(+1.0));
|
||||
addLegalFPImmediate(APFloat(-1.0));
|
||||
}
|
||||
|
||||
const char *IA64TargetLowering::getTargetNodeName(unsigned Opcode) const {
|
||||
switch (Opcode) {
|
||||
default: return 0;
|
||||
case IA64ISD::GETFD: return "IA64ISD::GETFD";
|
||||
case IA64ISD::BRCALL: return "IA64ISD::BRCALL";
|
||||
case IA64ISD::RET_FLAG: return "IA64ISD::RET_FLAG";
|
||||
}
|
||||
}
|
||||
|
||||
MVT IA64TargetLowering::getSetCCResultType(MVT VT) const {
|
||||
return MVT::i1;
|
||||
}
|
||||
|
||||
/// getFunctionAlignment - Return the Log2 alignment of this function.
|
||||
unsigned IA64TargetLowering::getFunctionAlignment(const Function *) const {
|
||||
return 5;
|
||||
}
|
||||
|
||||
void IA64TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG,
|
||||
SmallVectorImpl<SDValue> &ArgValues,
|
||||
DebugLoc dl) {
|
||||
//
|
||||
// add beautiful description of IA64 stack frame format
|
||||
// here (from intel 24535803.pdf most likely)
|
||||
//
|
||||
MachineFunction &MF = DAG.getMachineFunction();
|
||||
MachineFrameInfo *MFI = MF.getFrameInfo();
|
||||
const TargetInstrInfo *TII = getTargetMachine().getInstrInfo();
|
||||
|
||||
GP = MF.getRegInfo().createVirtualRegister(getRegClassFor(MVT::i64));
|
||||
SP = MF.getRegInfo().createVirtualRegister(getRegClassFor(MVT::i64));
|
||||
RP = MF.getRegInfo().createVirtualRegister(getRegClassFor(MVT::i64));
|
||||
|
||||
MachineBasicBlock& BB = MF.front();
|
||||
|
||||
unsigned args_int[] = {IA64::r32, IA64::r33, IA64::r34, IA64::r35,
|
||||
IA64::r36, IA64::r37, IA64::r38, IA64::r39};
|
||||
|
||||
unsigned args_FP[] = {IA64::F8, IA64::F9, IA64::F10, IA64::F11,
|
||||
IA64::F12,IA64::F13,IA64::F14, IA64::F15};
|
||||
|
||||
unsigned argVreg[8];
|
||||
unsigned argPreg[8];
|
||||
unsigned argOpc[8];
|
||||
|
||||
unsigned used_FPArgs = 0; // how many FP args have been used so far?
|
||||
|
||||
unsigned ArgOffset = 0;
|
||||
int count = 0;
|
||||
|
||||
for (Function::arg_iterator I = F.arg_begin(), E = F.arg_end(); I != E; ++I)
|
||||
{
|
||||
SDValue newroot, argt;
|
||||
if(count < 8) { // need to fix this logic? maybe.
|
||||
|
||||
switch (getValueType(I->getType()).getSimpleVT()) {
|
||||
default:
|
||||
assert(0 && "ERROR in LowerArgs: can't lower this type of arg.\n");
|
||||
case MVT::f32:
|
||||
// fixme? (well, will need to for weird FP structy stuff,
|
||||
// see intel ABI docs)
|
||||
case MVT::f64:
|
||||
//XXX BuildMI(&BB, IA64::IDEF, 0, args_FP[used_FPArgs]);
|
||||
MF.getRegInfo().addLiveIn(args_FP[used_FPArgs]);
|
||||
// mark this reg as liveIn
|
||||
// floating point args go into f8..f15 as-needed, the increment
|
||||
argVreg[count] = // is below..:
|
||||
MF.getRegInfo().createVirtualRegister(getRegClassFor(MVT::f64));
|
||||
// FP args go into f8..f15 as needed: (hence the ++)
|
||||
argPreg[count] = args_FP[used_FPArgs++];
|
||||
argOpc[count] = IA64::FMOV;
|
||||
argt = newroot = DAG.getCopyFromReg(DAG.getRoot(), dl,
|
||||
argVreg[count], MVT::f64);
|
||||
if (I->getType() == Type::FloatTy)
|
||||
argt = DAG.getNode(ISD::FP_ROUND, dl, MVT::f32, argt,
|
||||
DAG.getIntPtrConstant(0));
|
||||
break;
|
||||
case MVT::i1: // NOTE: as far as C abi stuff goes,
|
||||
// bools are just boring old ints
|
||||
case MVT::i8:
|
||||
case MVT::i16:
|
||||
case MVT::i32:
|
||||
case MVT::i64:
|
||||
//XXX BuildMI(&BB, IA64::IDEF, 0, args_int[count]);
|
||||
MF.getRegInfo().addLiveIn(args_int[count]);
|
||||
// mark this register as liveIn
|
||||
argVreg[count] =
|
||||
MF.getRegInfo().createVirtualRegister(getRegClassFor(MVT::i64));
|
||||
argPreg[count] = args_int[count];
|
||||
argOpc[count] = IA64::MOV;
|
||||
argt = newroot =
|
||||
DAG.getCopyFromReg(DAG.getRoot(), dl, argVreg[count], MVT::i64);
|
||||
if ( getValueType(I->getType()) != MVT::i64)
|
||||
argt = DAG.getNode(ISD::TRUNCATE, dl, getValueType(I->getType()),
|
||||
newroot);
|
||||
break;
|
||||
}
|
||||
} else { // more than 8 args go into the frame
|
||||
// Create the frame index object for this incoming parameter...
|
||||
ArgOffset = 16 + 8 * (count - 8);
|
||||
int FI = MFI->CreateFixedObject(8, ArgOffset);
|
||||
|
||||
// Create the SelectionDAG nodes corresponding to a load
|
||||
//from this parameter
|
||||
SDValue FIN = DAG.getFrameIndex(FI, MVT::i64);
|
||||
argt = newroot = DAG.getLoad(getValueType(I->getType()), dl,
|
||||
DAG.getEntryNode(), FIN, NULL, 0);
|
||||
}
|
||||
++count;
|
||||
DAG.setRoot(newroot.getValue(1));
|
||||
ArgValues.push_back(argt);
|
||||
}
|
||||
|
||||
|
||||
// Create a vreg to hold the output of (what will become)
|
||||
// the "alloc" instruction
|
||||
VirtGPR = MF.getRegInfo().createVirtualRegister(getRegClassFor(MVT::i64));
|
||||
BuildMI(&BB, dl, TII->get(IA64::PSEUDO_ALLOC), VirtGPR);
|
||||
// we create a PSEUDO_ALLOC (pseudo)instruction for now
|
||||
/*
|
||||
BuildMI(&BB, IA64::IDEF, 0, IA64::r1);
|
||||
|
||||
// hmm:
|
||||
BuildMI(&BB, IA64::IDEF, 0, IA64::r12);
|
||||
BuildMI(&BB, IA64::IDEF, 0, IA64::rp);
|
||||
// ..hmm.
|
||||
|
||||
BuildMI(&BB, IA64::MOV, 1, GP).addReg(IA64::r1);
|
||||
|
||||
// hmm:
|
||||
BuildMI(&BB, IA64::MOV, 1, SP).addReg(IA64::r12);
|
||||
BuildMI(&BB, IA64::MOV, 1, RP).addReg(IA64::rp);
|
||||
// ..hmm.
|
||||
*/
|
||||
|
||||
unsigned tempOffset=0;
|
||||
|
||||
// if this is a varargs function, we simply lower llvm.va_start by
|
||||
// pointing to the first entry
|
||||
if(F.isVarArg()) {
|
||||
tempOffset=0;
|
||||
VarArgsFrameIndex = MFI->CreateFixedObject(8, tempOffset);
|
||||
}
|
||||
|
||||
// here we actually do the moving of args, and store them to the stack
|
||||
// too if this is a varargs function:
|
||||
for (int i = 0; i < count && i < 8; ++i) {
|
||||
BuildMI(&BB, dl, TII->get(argOpc[i]), argVreg[i]).addReg(argPreg[i]);
|
||||
if(F.isVarArg()) {
|
||||
// if this is a varargs function, we copy the input registers to the stack
|
||||
int FI = MFI->CreateFixedObject(8, tempOffset);
|
||||
tempOffset+=8; //XXX: is it safe to use r22 like this?
|
||||
BuildMI(&BB, dl, TII->get(IA64::MOV), IA64::r22).addFrameIndex(FI);
|
||||
// FIXME: we should use st8.spill here, one day
|
||||
BuildMI(&BB, dl, TII->get(IA64::ST8), IA64::r22).addReg(argPreg[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, inform the code generator which regs we return values in.
|
||||
// (see the ISD::RET: case in the instruction selector)
|
||||
switch (getValueType(F.getReturnType()).getSimpleVT()) {
|
||||
default: assert(0 && "i have no idea where to return this type!");
|
||||
case MVT::isVoid: break;
|
||||
case MVT::i1:
|
||||
case MVT::i8:
|
||||
case MVT::i16:
|
||||
case MVT::i32:
|
||||
case MVT::i64:
|
||||
MF.getRegInfo().addLiveOut(IA64::r8);
|
||||
break;
|
||||
case MVT::f32:
|
||||
case MVT::f64:
|
||||
MF.getRegInfo().addLiveOut(IA64::F8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<SDValue, SDValue>
|
||||
IA64TargetLowering::LowerCallTo(SDValue Chain, const Type *RetTy,
|
||||
bool RetSExt, bool RetZExt, bool isVarArg,
|
||||
bool isInreg, unsigned NumFixedArgs,
|
||||
unsigned CallingConv,
|
||||
bool isTailCall, SDValue Callee,
|
||||
ArgListTy &Args, SelectionDAG &DAG,
|
||||
DebugLoc dl) {
|
||||
|
||||
MachineFunction &MF = DAG.getMachineFunction();
|
||||
|
||||
unsigned NumBytes = 16;
|
||||
unsigned outRegsUsed = 0;
|
||||
|
||||
if (Args.size() > 8) {
|
||||
NumBytes += (Args.size() - 8) * 8;
|
||||
outRegsUsed = 8;
|
||||
} else {
|
||||
outRegsUsed = Args.size();
|
||||
}
|
||||
|
||||
// FIXME? this WILL fail if we ever try to pass around an arg that
|
||||
// consumes more than a single output slot (a 'real' double, int128
|
||||
// some sort of aggregate etc.), as we'll underestimate how many 'outX'
|
||||
// registers we use. Hopefully, the assembler will notice.
|
||||
MF.getInfo<IA64FunctionInfo>()->outRegsUsed=
|
||||
std::max(outRegsUsed, MF.getInfo<IA64FunctionInfo>()->outRegsUsed);
|
||||
|
||||
// keep stack frame 16-byte aligned
|
||||
// assert(NumBytes==((NumBytes+15) & ~15) &&
|
||||
// "stack frame not 16-byte aligned!");
|
||||
NumBytes = (NumBytes+15) & ~15;
|
||||
|
||||
Chain = DAG.getCALLSEQ_START(Chain, DAG.getIntPtrConstant(NumBytes, true));
|
||||
|
||||
SDValue StackPtr;
|
||||
std::vector<SDValue> Stores;
|
||||
std::vector<SDValue> Converts;
|
||||
std::vector<SDValue> RegValuesToPass;
|
||||
unsigned ArgOffset = 16;
|
||||
|
||||
for (unsigned i = 0, e = Args.size(); i != e; ++i)
|
||||
{
|
||||
SDValue Val = Args[i].Node;
|
||||
MVT ObjectVT = Val.getValueType();
|
||||
SDValue ValToStore(0, 0), ValToConvert(0, 0);
|
||||
unsigned ObjSize=8;
|
||||
switch (ObjectVT.getSimpleVT()) {
|
||||
default: assert(0 && "unexpected argument type!");
|
||||
case MVT::i1:
|
||||
case MVT::i8:
|
||||
case MVT::i16:
|
||||
case MVT::i32: {
|
||||
//promote to 64-bits, sign/zero extending based on type
|
||||
//of the argument
|
||||
ISD::NodeType ExtendKind = ISD::ANY_EXTEND;
|
||||
if (Args[i].isSExt)
|
||||
ExtendKind = ISD::SIGN_EXTEND;
|
||||
else if (Args[i].isZExt)
|
||||
ExtendKind = ISD::ZERO_EXTEND;
|
||||
Val = DAG.getNode(ExtendKind, dl, MVT::i64, Val);
|
||||
// XXX: fall through
|
||||
}
|
||||
case MVT::i64:
|
||||
//ObjSize = 8;
|
||||
if(RegValuesToPass.size() >= 8) {
|
||||
ValToStore = Val;
|
||||
} else {
|
||||
RegValuesToPass.push_back(Val);
|
||||
}
|
||||
break;
|
||||
case MVT::f32:
|
||||
//promote to 64-bits
|
||||
Val = DAG.getNode(ISD::FP_EXTEND, dl, MVT::f64, Val);
|
||||
// XXX: fall through
|
||||
case MVT::f64:
|
||||
if(RegValuesToPass.size() >= 8) {
|
||||
ValToStore = Val;
|
||||
} else {
|
||||
RegValuesToPass.push_back(Val);
|
||||
if(1 /* TODO: if(calling external or varadic function)*/ ) {
|
||||
ValToConvert = Val; // additionally pass this FP value as an int
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(ValToStore.getNode()) {
|
||||
if(!StackPtr.getNode()) {
|
||||
StackPtr = DAG.getRegister(IA64::r12, MVT::i64);
|
||||
}
|
||||
SDValue PtrOff = DAG.getConstant(ArgOffset, getPointerTy());
|
||||
PtrOff = DAG.getNode(ISD::ADD, dl, MVT::i64, StackPtr, PtrOff);
|
||||
Stores.push_back(DAG.getStore(Chain, dl, ValToStore, PtrOff, NULL, 0));
|
||||
ArgOffset += ObjSize;
|
||||
}
|
||||
|
||||
if(ValToConvert.getNode()) {
|
||||
Converts.push_back(DAG.getNode(IA64ISD::GETFD, dl,
|
||||
MVT::i64, ValToConvert));
|
||||
}
|
||||
}
|
||||
|
||||
// Emit all stores, make sure they occur before any copies into physregs.
|
||||
if (!Stores.empty())
|
||||
Chain = DAG.getNode(ISD::TokenFactor, dl,
|
||||
MVT::Other, &Stores[0],Stores.size());
|
||||
|
||||
static const unsigned IntArgRegs[] = {
|
||||
IA64::out0, IA64::out1, IA64::out2, IA64::out3,
|
||||
IA64::out4, IA64::out5, IA64::out6, IA64::out7
|
||||
};
|
||||
|
||||
static const unsigned FPArgRegs[] = {
|
||||
IA64::F8, IA64::F9, IA64::F10, IA64::F11,
|
||||
IA64::F12, IA64::F13, IA64::F14, IA64::F15
|
||||
};
|
||||
|
||||
SDValue InFlag;
|
||||
|
||||
// save the current GP, SP and RP : FIXME: do we need to do all 3 always?
|
||||
SDValue GPBeforeCall = DAG.getCopyFromReg(Chain, dl, IA64::r1,
|
||||
MVT::i64, InFlag);
|
||||
Chain = GPBeforeCall.getValue(1);
|
||||
InFlag = Chain.getValue(2);
|
||||
SDValue SPBeforeCall = DAG.getCopyFromReg(Chain, dl, IA64::r12,
|
||||
MVT::i64, InFlag);
|
||||
Chain = SPBeforeCall.getValue(1);
|
||||
InFlag = Chain.getValue(2);
|
||||
SDValue RPBeforeCall = DAG.getCopyFromReg(Chain, dl, IA64::rp,
|
||||
MVT::i64, InFlag);
|
||||
Chain = RPBeforeCall.getValue(1);
|
||||
InFlag = Chain.getValue(2);
|
||||
|
||||
// Build a sequence of copy-to-reg nodes chained together with token chain
|
||||
// and flag operands which copy the outgoing integer args into regs out[0-7]
|
||||
// mapped 1:1 and the FP args into regs F8-F15 "lazily"
|
||||
// TODO: for performance, we should only copy FP args into int regs when we
|
||||
// know this is required (i.e. for varardic or external (unknown) functions)
|
||||
|
||||
// first to the FP->(integer representation) conversions, these are
|
||||
// flagged for now, but shouldn't have to be (TODO)
|
||||
unsigned seenConverts = 0;
|
||||
for (unsigned i = 0, e = RegValuesToPass.size(); i != e; ++i) {
|
||||
if(RegValuesToPass[i].getValueType().isFloatingPoint()) {
|
||||
Chain = DAG.getCopyToReg(Chain, dl, IntArgRegs[i],
|
||||
Converts[seenConverts++], InFlag);
|
||||
InFlag = Chain.getValue(1);
|
||||
}
|
||||
}
|
||||
|
||||
// next copy args into the usual places, these are flagged
|
||||
unsigned usedFPArgs = 0;
|
||||
for (unsigned i = 0, e = RegValuesToPass.size(); i != e; ++i) {
|
||||
Chain = DAG.getCopyToReg(Chain, dl,
|
||||
RegValuesToPass[i].getValueType().isInteger() ?
|
||||
IntArgRegs[i] : FPArgRegs[usedFPArgs++], RegValuesToPass[i], InFlag);
|
||||
InFlag = Chain.getValue(1);
|
||||
}
|
||||
|
||||
// If the callee is a GlobalAddress node (quite common, every direct call is)
|
||||
// turn it into a TargetGlobalAddress node so that legalize doesn't hack it.
|
||||
/*
|
||||
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
|
||||
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), MVT::i64);
|
||||
}
|
||||
*/
|
||||
|
||||
std::vector<MVT> NodeTys;
|
||||
std::vector<SDValue> CallOperands;
|
||||
NodeTys.push_back(MVT::Other); // Returns a chain
|
||||
NodeTys.push_back(MVT::Flag); // Returns a flag for retval copy to use.
|
||||
CallOperands.push_back(Chain);
|
||||
CallOperands.push_back(Callee);
|
||||
|
||||
// emit the call itself
|
||||
if (InFlag.getNode())
|
||||
CallOperands.push_back(InFlag);
|
||||
else
|
||||
assert(0 && "this should never happen!\n");
|
||||
|
||||
// to make way for a hack:
|
||||
Chain = DAG.getNode(IA64ISD::BRCALL, dl, NodeTys,
|
||||
&CallOperands[0], CallOperands.size());
|
||||
InFlag = Chain.getValue(1);
|
||||
|
||||
// restore the GP, SP and RP after the call
|
||||
Chain = DAG.getCopyToReg(Chain, dl, IA64::r1, GPBeforeCall, InFlag);
|
||||
InFlag = Chain.getValue(1);
|
||||
Chain = DAG.getCopyToReg(Chain, dl, IA64::r12, SPBeforeCall, InFlag);
|
||||
InFlag = Chain.getValue(1);
|
||||
Chain = DAG.getCopyToReg(Chain, dl, IA64::rp, RPBeforeCall, InFlag);
|
||||
InFlag = Chain.getValue(1);
|
||||
|
||||
std::vector<MVT> RetVals;
|
||||
RetVals.push_back(MVT::Other);
|
||||
RetVals.push_back(MVT::Flag);
|
||||
|
||||
MVT RetTyVT = getValueType(RetTy);
|
||||
SDValue RetVal;
|
||||
if (RetTyVT != MVT::isVoid) {
|
||||
switch (RetTyVT.getSimpleVT()) {
|
||||
default: assert(0 && "Unknown value type to return!");
|
||||
case MVT::i1: { // bools are just like other integers (returned in r8)
|
||||
// we *could* fall through to the truncate below, but this saves a
|
||||
// few redundant predicate ops
|
||||
SDValue boolInR8 = DAG.getCopyFromReg(Chain, dl, IA64::r8,
|
||||
MVT::i64,InFlag);
|
||||
InFlag = boolInR8.getValue(2);
|
||||
Chain = boolInR8.getValue(1);
|
||||
SDValue zeroReg = DAG.getCopyFromReg(Chain, dl, IA64::r0,
|
||||
MVT::i64, InFlag);
|
||||
InFlag = zeroReg.getValue(2);
|
||||
Chain = zeroReg.getValue(1);
|
||||
|
||||
RetVal = DAG.getSetCC(dl, MVT::i1, boolInR8, zeroReg, ISD::SETNE);
|
||||
break;
|
||||
}
|
||||
case MVT::i8:
|
||||
case MVT::i16:
|
||||
case MVT::i32:
|
||||
RetVal = DAG.getCopyFromReg(Chain, dl, IA64::r8, MVT::i64, InFlag);
|
||||
Chain = RetVal.getValue(1);
|
||||
|
||||
// keep track of whether it is sign or zero extended (todo: bools?)
|
||||
/* XXX
|
||||
RetVal = DAG.getNode(RetTy->isSigned() ? ISD::AssertSext :ISD::AssertZext,
|
||||
dl, MVT::i64, RetVal, DAG.getValueType(RetTyVT));
|
||||
*/
|
||||
RetVal = DAG.getNode(ISD::TRUNCATE, dl, RetTyVT, RetVal);
|
||||
break;
|
||||
case MVT::i64:
|
||||
RetVal = DAG.getCopyFromReg(Chain, dl, IA64::r8, MVT::i64, InFlag);
|
||||
Chain = RetVal.getValue(1);
|
||||
InFlag = RetVal.getValue(2); // XXX dead
|
||||
break;
|
||||
case MVT::f32:
|
||||
RetVal = DAG.getCopyFromReg(Chain, dl, IA64::F8, MVT::f64, InFlag);
|
||||
Chain = RetVal.getValue(1);
|
||||
RetVal = DAG.getNode(ISD::FP_ROUND, dl, MVT::f32, RetVal,
|
||||
DAG.getIntPtrConstant(0));
|
||||
break;
|
||||
case MVT::f64:
|
||||
RetVal = DAG.getCopyFromReg(Chain, dl, IA64::F8, MVT::f64, InFlag);
|
||||
Chain = RetVal.getValue(1);
|
||||
InFlag = RetVal.getValue(2); // XXX dead
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(NumBytes, true),
|
||||
DAG.getIntPtrConstant(0, true), SDValue());
|
||||
return std::make_pair(RetVal, Chain);
|
||||
}
|
||||
|
||||
SDValue IA64TargetLowering::
|
||||
LowerOperation(SDValue Op, SelectionDAG &DAG) {
|
||||
DebugLoc dl = Op.getDebugLoc();
|
||||
switch (Op.getOpcode()) {
|
||||
default: assert(0 && "Should not custom lower this!");
|
||||
case ISD::GlobalTLSAddress:
|
||||
assert(0 && "TLS not implemented for IA64.");
|
||||
case ISD::RET: {
|
||||
SDValue AR_PFSVal, Copy;
|
||||
|
||||
switch(Op.getNumOperands()) {
|
||||
default:
|
||||
assert(0 && "Do not know how to return this many arguments!");
|
||||
abort();
|
||||
case 1:
|
||||
AR_PFSVal = DAG.getCopyFromReg(Op.getOperand(0), dl, VirtGPR, MVT::i64);
|
||||
AR_PFSVal = DAG.getCopyToReg(AR_PFSVal.getValue(1), dl, IA64::AR_PFS,
|
||||
AR_PFSVal);
|
||||
return DAG.getNode(IA64ISD::RET_FLAG, dl, MVT::Other, AR_PFSVal);
|
||||
case 3: {
|
||||
// Copy the result into the output register & restore ar.pfs
|
||||
MVT ArgVT = Op.getOperand(1).getValueType();
|
||||
unsigned ArgReg = ArgVT.isInteger() ? IA64::r8 : IA64::F8;
|
||||
|
||||
AR_PFSVal = DAG.getCopyFromReg(Op.getOperand(0), dl, VirtGPR, MVT::i64);
|
||||
Copy = DAG.getCopyToReg(AR_PFSVal.getValue(1), dl, ArgReg,
|
||||
Op.getOperand(1), SDValue());
|
||||
AR_PFSVal = DAG.getCopyToReg(Copy.getValue(0), dl,
|
||||
IA64::AR_PFS, AR_PFSVal, Copy.getValue(1));
|
||||
return DAG.getNode(IA64ISD::RET_FLAG, dl, MVT::Other,
|
||||
AR_PFSVal, AR_PFSVal.getValue(1));
|
||||
}
|
||||
}
|
||||
return SDValue();
|
||||
}
|
||||
case ISD::VAARG: {
|
||||
MVT VT = getPointerTy();
|
||||
const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
|
||||
SDValue VAList = DAG.getLoad(VT, dl, Op.getOperand(0), Op.getOperand(1),
|
||||
SV, 0);
|
||||
// Increment the pointer, VAList, to the next vaarg
|
||||
SDValue VAIncr = DAG.getNode(ISD::ADD, dl, VT, VAList,
|
||||
DAG.getConstant(VT.getSizeInBits()/8,
|
||||
VT));
|
||||
// Store the incremented VAList to the legalized pointer
|
||||
VAIncr = DAG.getStore(VAList.getValue(1), dl, VAIncr,
|
||||
Op.getOperand(1), SV, 0);
|
||||
// Load the actual argument out of the pointer VAList
|
||||
return DAG.getLoad(Op.getValueType(), dl, VAIncr, VAList, NULL, 0);
|
||||
}
|
||||
case ISD::VASTART: {
|
||||
// vastart just stores the address of the VarArgsFrameIndex slot into the
|
||||
// memory location argument.
|
||||
SDValue FR = DAG.getFrameIndex(VarArgsFrameIndex, MVT::i64);
|
||||
const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
|
||||
return DAG.getStore(Op.getOperand(0), dl, FR, Op.getOperand(1), SV, 0);
|
||||
}
|
||||
// Frame & Return address. Currently unimplemented
|
||||
case ISD::RETURNADDR: break;
|
||||
case ISD::FRAMEADDR: break;
|
||||
}
|
||||
return SDValue();
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
//===-- IA64ISelLowering.h - IA64 DAG Lowering Interface --------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the interfaces that IA64 uses to lower LLVM code into a
|
||||
// selection DAG.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TARGET_IA64_IA64ISELLOWERING_H
|
||||
#define LLVM_TARGET_IA64_IA64ISELLOWERING_H
|
||||
|
||||
#include "llvm/Target/TargetLowering.h"
|
||||
#include "llvm/CodeGen/SelectionDAG.h"
|
||||
#include "IA64.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace IA64ISD {
|
||||
enum NodeType {
|
||||
// Start the numbering where the builting ops and target ops leave off.
|
||||
FIRST_NUMBER = ISD::BUILTIN_OP_END,
|
||||
|
||||
/// GETFD - the getf.d instruction takes a floating point operand and
|
||||
/// returns its 64-bit memory representation as an i64
|
||||
GETFD,
|
||||
|
||||
// TODO: explain this hack
|
||||
BRCALL,
|
||||
|
||||
// RET_FLAG - Return with a flag operand
|
||||
RET_FLAG
|
||||
};
|
||||
}
|
||||
|
||||
class IA64TargetLowering : public TargetLowering {
|
||||
int VarArgsFrameIndex; // FrameIndex for start of varargs area.
|
||||
//int ReturnAddrIndex; // FrameIndex for return slot.
|
||||
unsigned GP, SP, RP; // FIXME - clean this mess up
|
||||
public:
|
||||
explicit IA64TargetLowering(TargetMachine &TM);
|
||||
|
||||
unsigned VirtGPR; // this is public so it can be accessed in the selector
|
||||
// for ISD::RET. add an accessor instead? FIXME
|
||||
const char *getTargetNodeName(unsigned Opcode) const;
|
||||
|
||||
/// getSetCCResultType: return ISD::SETCC's result type.
|
||||
virtual MVT getSetCCResultType(MVT VT) const;
|
||||
|
||||
/// LowerArguments - This hook must be implemented to indicate how we should
|
||||
/// lower the arguments for the specified function, into the specified DAG.
|
||||
virtual void LowerArguments(Function &F, SelectionDAG &DAG,
|
||||
SmallVectorImpl<SDValue> &ArgValues,
|
||||
DebugLoc dl);
|
||||
|
||||
/// LowerCallTo - This hook lowers an abstract call to a function into an
|
||||
/// actual call.
|
||||
virtual std::pair<SDValue, SDValue>
|
||||
LowerCallTo(SDValue Chain, const Type *RetTy,
|
||||
bool RetSExt, bool RetZExt, bool isVarArg, bool isInreg,
|
||||
unsigned NumFixedArgs, unsigned CC, bool isTailCall,
|
||||
SDValue Callee, ArgListTy &Args, SelectionDAG &DAG,
|
||||
DebugLoc dl);
|
||||
|
||||
/// LowerOperation - for custom lowering specific ops
|
||||
/// (currently, only "ret void")
|
||||
virtual SDValue LowerOperation(SDValue Op, SelectionDAG &DAG);
|
||||
|
||||
/// getFunctionAlignment - Return the Log2 alignment of this function.
|
||||
virtual unsigned getFunctionAlignment(const Function *F) const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // LLVM_TARGET_IA64_IA64ISELLOWERING_H
|
@ -1,40 +0,0 @@
|
||||
//===-- IA64PCInstrBuilder.h - Aids for building IA64 insts -----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file exposes functions that may be used with BuildMI from the
|
||||
// MachineInstrBuilder.h file to simplify generating frame and constant pool
|
||||
// references.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef IA64_INSTRBUILDER_H
|
||||
#define IA64_INSTRBUILDER_H
|
||||
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// addFrameReference - This function is used to add a reference to the base of
|
||||
/// an abstract object on the stack frame of the current function. This
|
||||
/// reference has base register as the FrameIndex offset until it is resolved.
|
||||
/// This allows a constant offset to be specified as well...
|
||||
///
|
||||
inline const MachineInstrBuilder&
|
||||
addFrameReference(const MachineInstrBuilder &MIB, int FI, int Offset = 0,
|
||||
bool mem = true) {
|
||||
if (mem)
|
||||
return MIB.addImm(Offset).addFrameIndex(FI);
|
||||
else
|
||||
return MIB.addFrameIndex(FI).addImm(Offset);
|
||||
}
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
||||
|
@ -1,80 +0,0 @@
|
||||
//===- IA64InstrFormats.td - IA64 Instruction Formats --*- tablegen -*-=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// - Warning: the stuff in here isn't really being used, so is mostly
|
||||
// junk. It'll get fixed as the JIT gets built.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Instruction format superclass
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class InstIA64<bits<4> op, dag OOL, dag IOL, string asmstr> : Instruction {
|
||||
// IA64 instruction baseline
|
||||
field bits<41> Inst;
|
||||
let Namespace = "IA64";
|
||||
let OutOperandList = OOL;
|
||||
let InOperandList = IOL;
|
||||
let AsmString = asmstr;
|
||||
|
||||
let Inst{40-37} = op;
|
||||
}
|
||||
|
||||
//"Each Itanium instruction is categorized into one of six types."
|
||||
//We should have:
|
||||
// A, I, M, F, B, L+X
|
||||
|
||||
class AForm<bits<4> opcode, bits<6> qpReg, dag OOL, dag IOL, string asmstr> :
|
||||
InstIA64<opcode, OOL, IOL, asmstr> {
|
||||
|
||||
let Inst{5-0} = qpReg;
|
||||
}
|
||||
|
||||
class AForm_DAG<bits<4> opcode, bits<6> qpReg, dag OOL, dag IOL, string asmstr,
|
||||
list<dag> pattern> :
|
||||
InstIA64<opcode, OOL, IOL, asmstr> {
|
||||
|
||||
let Pattern = pattern;
|
||||
let Inst{5-0} = qpReg;
|
||||
}
|
||||
|
||||
let isBranch = 1, isTerminator = 1 in
|
||||
class BForm<bits<4> opcode, bits<6> x6, bits<3> btype, dag OOL, dag IOL, string asmstr> :
|
||||
InstIA64<opcode, OOL, IOL, asmstr> {
|
||||
|
||||
let Inst{32-27} = x6;
|
||||
let Inst{8-6} = btype;
|
||||
}
|
||||
|
||||
class MForm<bits<4> opcode, bits<6> x6, dag OOL, dag IOL, string asmstr> :
|
||||
InstIA64<opcode, OOL, IOL, asmstr> {
|
||||
bits<7> Ra;
|
||||
bits<7> Rb;
|
||||
bits<16> disp;
|
||||
|
||||
let Inst{35-30} = x6;
|
||||
// let Inst{20-16} = Rb;
|
||||
let Inst{15-0} = disp;
|
||||
}
|
||||
|
||||
class RawForm<bits<4> opcode, bits<26> rest, dag OOL, dag IOL, string asmstr> :
|
||||
InstIA64<opcode, OOL, IOL, asmstr> {
|
||||
let Inst{25-0} = rest;
|
||||
}
|
||||
|
||||
// Pseudo instructions.
|
||||
class PseudoInstIA64<dag OOL, dag IOL, string nm> : InstIA64<0, OOL, IOL, nm> {
|
||||
}
|
||||
|
||||
class PseudoInstIA64_DAG<dag OOL, dag IOL, string nm, list<dag> pattern>
|
||||
: InstIA64<0, OOL, IOL, nm> {
|
||||
let Pattern = pattern;
|
||||
}
|
||||
|
@ -1,193 +0,0 @@
|
||||
//===- IA64InstrInfo.cpp - IA64 Instruction Information -----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the IA64 implementation of the TargetInstrInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "IA64InstrInfo.h"
|
||||
#include "IA64.h"
|
||||
#include "IA64InstrBuilder.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "IA64GenInstrInfo.inc"
|
||||
using namespace llvm;
|
||||
|
||||
IA64InstrInfo::IA64InstrInfo()
|
||||
: TargetInstrInfoImpl(IA64Insts, sizeof(IA64Insts)/sizeof(IA64Insts[0])),
|
||||
RI(*this) {
|
||||
}
|
||||
|
||||
|
||||
bool IA64InstrInfo::isMoveInstr(const MachineInstr& MI,
|
||||
unsigned& sourceReg,
|
||||
unsigned& destReg,
|
||||
unsigned& SrcSR, unsigned& DstSR) const {
|
||||
SrcSR = DstSR = 0; // No sub-registers.
|
||||
|
||||
unsigned oc = MI.getOpcode();
|
||||
if (oc == IA64::MOV || oc == IA64::FMOV) {
|
||||
// TODO: this doesn't detect predicate moves
|
||||
assert(MI.getNumOperands() >= 2 &&
|
||||
/* MI.getOperand(0).isReg() &&
|
||||
MI.getOperand(1).isReg() && */
|
||||
"invalid register-register move instruction");
|
||||
if (MI.getOperand(0).isReg() &&
|
||||
MI.getOperand(1).isReg()) {
|
||||
// if both operands of the MOV/FMOV are registers, then
|
||||
// yes, this is a move instruction
|
||||
sourceReg = MI.getOperand(1).getReg();
|
||||
destReg = MI.getOperand(0).getReg();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false; // we don't consider e.g. %regN = MOV <FrameIndex #x> a
|
||||
// move instruction
|
||||
}
|
||||
|
||||
unsigned
|
||||
IA64InstrInfo::InsertBranch(MachineBasicBlock &MBB,MachineBasicBlock *TBB,
|
||||
MachineBasicBlock *FBB,
|
||||
const SmallVectorImpl<MachineOperand> &Cond)const {
|
||||
// FIXME this should probably have a DebugLoc argument
|
||||
DebugLoc dl = DebugLoc::getUnknownLoc();
|
||||
// Can only insert uncond branches so far.
|
||||
assert(Cond.empty() && !FBB && TBB && "Can only handle uncond branches!");
|
||||
BuildMI(&MBB, dl, get(IA64::BRL_NOTCALL)).addMBB(TBB);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool IA64InstrInfo::copyRegToReg(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MI,
|
||||
unsigned DestReg, unsigned SrcReg,
|
||||
const TargetRegisterClass *DestRC,
|
||||
const TargetRegisterClass *SrcRC) const {
|
||||
if (DestRC != SrcRC) {
|
||||
// Not yet supported!
|
||||
return false;
|
||||
}
|
||||
|
||||
DebugLoc DL = DebugLoc::getUnknownLoc();
|
||||
if (MI != MBB.end()) DL = MI->getDebugLoc();
|
||||
|
||||
if(DestRC == IA64::PRRegisterClass ) // if a bool, we use pseudocode
|
||||
// (SrcReg) DestReg = cmp.eq.unc(r0, r0)
|
||||
BuildMI(MBB, MI, DL, get(IA64::PCMPEQUNC), DestReg)
|
||||
.addReg(IA64::r0).addReg(IA64::r0).addReg(SrcReg);
|
||||
else // otherwise, MOV works (for both gen. regs and FP regs)
|
||||
BuildMI(MBB, MI, DL, get(IA64::MOV), DestReg).addReg(SrcReg);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void IA64InstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MI,
|
||||
unsigned SrcReg, bool isKill,
|
||||
int FrameIdx,
|
||||
const TargetRegisterClass *RC) const{
|
||||
DebugLoc DL = DebugLoc::getUnknownLoc();
|
||||
if (MI != MBB.end()) DL = MI->getDebugLoc();
|
||||
|
||||
if (RC == IA64::FPRegisterClass) {
|
||||
BuildMI(MBB, MI, DL, get(IA64::STF_SPILL)).addFrameIndex(FrameIdx)
|
||||
.addReg(SrcReg, getKillRegState(isKill));
|
||||
} else if (RC == IA64::GRRegisterClass) {
|
||||
BuildMI(MBB, MI, DL, get(IA64::ST8)).addFrameIndex(FrameIdx)
|
||||
.addReg(SrcReg, getKillRegState(isKill));
|
||||
} else if (RC == IA64::PRRegisterClass) {
|
||||
/* we use IA64::r2 as a temporary register for doing this hackery. */
|
||||
// first we load 0:
|
||||
BuildMI(MBB, MI, DL, get(IA64::MOV), IA64::r2).addReg(IA64::r0);
|
||||
// then conditionally add 1:
|
||||
BuildMI(MBB, MI, DL, get(IA64::CADDIMM22), IA64::r2).addReg(IA64::r2)
|
||||
.addImm(1).addReg(SrcReg, getKillRegState(isKill));
|
||||
// and then store it to the stack
|
||||
BuildMI(MBB, MI, DL, get(IA64::ST8))
|
||||
.addFrameIndex(FrameIdx)
|
||||
.addReg(IA64::r2);
|
||||
} else assert(0 &&
|
||||
"sorry, I don't know how to store this sort of reg in the stack\n");
|
||||
}
|
||||
|
||||
void IA64InstrInfo::storeRegToAddr(MachineFunction &MF, unsigned SrcReg,
|
||||
bool isKill,
|
||||
SmallVectorImpl<MachineOperand> &Addr,
|
||||
const TargetRegisterClass *RC,
|
||||
SmallVectorImpl<MachineInstr*> &NewMIs) const {
|
||||
unsigned Opc = 0;
|
||||
if (RC == IA64::FPRegisterClass) {
|
||||
Opc = IA64::STF8;
|
||||
} else if (RC == IA64::GRRegisterClass) {
|
||||
Opc = IA64::ST8;
|
||||
} else if (RC == IA64::PRRegisterClass) {
|
||||
Opc = IA64::ST1;
|
||||
} else {
|
||||
assert(0 &&
|
||||
"sorry, I don't know how to store this sort of reg\n");
|
||||
}
|
||||
|
||||
DebugLoc DL = DebugLoc::getUnknownLoc();
|
||||
MachineInstrBuilder MIB = BuildMI(MF, DL, get(Opc));
|
||||
for (unsigned i = 0, e = Addr.size(); i != e; ++i)
|
||||
MIB.addOperand(Addr[i]);
|
||||
MIB.addReg(SrcReg, getKillRegState(isKill));
|
||||
NewMIs.push_back(MIB);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
void IA64InstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MI,
|
||||
unsigned DestReg, int FrameIdx,
|
||||
const TargetRegisterClass *RC)const{
|
||||
DebugLoc DL = DebugLoc::getUnknownLoc();
|
||||
if (MI != MBB.end()) DL = MI->getDebugLoc();
|
||||
|
||||
if (RC == IA64::FPRegisterClass) {
|
||||
BuildMI(MBB, MI, DL, get(IA64::LDF_FILL), DestReg).addFrameIndex(FrameIdx);
|
||||
} else if (RC == IA64::GRRegisterClass) {
|
||||
BuildMI(MBB, MI, DL, get(IA64::LD8), DestReg).addFrameIndex(FrameIdx);
|
||||
} else if (RC == IA64::PRRegisterClass) {
|
||||
// first we load a byte from the stack into r2, our 'predicate hackery'
|
||||
// scratch reg
|
||||
BuildMI(MBB, MI, DL, get(IA64::LD8), IA64::r2).addFrameIndex(FrameIdx);
|
||||
// then we compare it to zero. If it _is_ zero, compare-not-equal to
|
||||
// r0 gives us 0, which is what we want, so that's nice.
|
||||
BuildMI(MBB, MI, DL, get(IA64::CMPNE), DestReg)
|
||||
.addReg(IA64::r2)
|
||||
.addReg(IA64::r0);
|
||||
} else {
|
||||
assert(0 &&
|
||||
"sorry, I don't know how to load this sort of reg from the stack\n");
|
||||
}
|
||||
}
|
||||
|
||||
void IA64InstrInfo::loadRegFromAddr(MachineFunction &MF, unsigned DestReg,
|
||||
SmallVectorImpl<MachineOperand> &Addr,
|
||||
const TargetRegisterClass *RC,
|
||||
SmallVectorImpl<MachineInstr*> &NewMIs) const {
|
||||
unsigned Opc = 0;
|
||||
if (RC == IA64::FPRegisterClass) {
|
||||
Opc = IA64::LDF8;
|
||||
} else if (RC == IA64::GRRegisterClass) {
|
||||
Opc = IA64::LD8;
|
||||
} else if (RC == IA64::PRRegisterClass) {
|
||||
Opc = IA64::LD1;
|
||||
} else {
|
||||
assert(0 &&
|
||||
"sorry, I don't know how to load this sort of reg\n");
|
||||
}
|
||||
|
||||
DebugLoc DL = DebugLoc::getUnknownLoc();
|
||||
MachineInstrBuilder MIB = BuildMI(MF, DL, get(Opc), DestReg);
|
||||
for (unsigned i = 0, e = Addr.size(); i != e; ++i)
|
||||
MIB.addOperand(Addr[i]);
|
||||
NewMIs.push_back(MIB);
|
||||
return;
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
//===- IA64InstrInfo.h - IA64 Instruction Information ----------*- C++ -*- ===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the IA64 implementation of the TargetInstrInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef IA64INSTRUCTIONINFO_H
|
||||
#define IA64INSTRUCTIONINFO_H
|
||||
|
||||
#include "llvm/Target/TargetInstrInfo.h"
|
||||
#include "IA64RegisterInfo.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class IA64InstrInfo : public TargetInstrInfoImpl {
|
||||
const IA64RegisterInfo RI;
|
||||
public:
|
||||
IA64InstrInfo();
|
||||
|
||||
/// getRegisterInfo - TargetInstrInfo is a superset of MRegister info. As
|
||||
/// such, whenever a client has an instance of instruction info, it should
|
||||
/// always be able to get register info as well (through this method).
|
||||
///
|
||||
virtual const IA64RegisterInfo &getRegisterInfo() const { return RI; }
|
||||
|
||||
/// Return true if the instruction is a register to register move and return
|
||||
/// the source and dest operands and their sub-register indices by reference.
|
||||
virtual bool isMoveInstr(const MachineInstr &MI,
|
||||
unsigned &SrcReg, unsigned &DstReg,
|
||||
unsigned &SrcSubIdx, unsigned &DstSubIdx) const;
|
||||
virtual unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
|
||||
MachineBasicBlock *FBB,
|
||||
const SmallVectorImpl<MachineOperand> &Cond) const;
|
||||
virtual bool copyRegToReg(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MI,
|
||||
unsigned DestReg, unsigned SrcReg,
|
||||
const TargetRegisterClass *DestRC,
|
||||
const TargetRegisterClass *SrcRC) const;
|
||||
virtual void storeRegToStackSlot(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MI,
|
||||
unsigned SrcReg, bool isKill, int FrameIndex,
|
||||
const TargetRegisterClass *RC) const;
|
||||
|
||||
virtual void storeRegToAddr(MachineFunction &MF, unsigned SrcReg, bool isKill,
|
||||
SmallVectorImpl<MachineOperand> &Addr,
|
||||
const TargetRegisterClass *RC,
|
||||
SmallVectorImpl<MachineInstr*> &NewMIs) const;
|
||||
|
||||
virtual void loadRegFromStackSlot(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MI,
|
||||
unsigned DestReg, int FrameIndex,
|
||||
const TargetRegisterClass *RC) const;
|
||||
|
||||
virtual void loadRegFromAddr(MachineFunction &MF, unsigned DestReg,
|
||||
SmallVectorImpl<MachineOperand> &Addr,
|
||||
const TargetRegisterClass *RC,
|
||||
SmallVectorImpl<MachineInstr*> &NewMIs) const;
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
||||
|
@ -1,751 +0,0 @@
|
||||
//===- IA64InstrInfo.td - Describe the IA64 Instruction Set -----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file describes the IA64 instruction set, defining the instructions, and
|
||||
// properties of the instructions which are needed for code generation, machine
|
||||
// code emission, and analysis.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
include "IA64InstrFormats.td"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// IA-64 specific DAG Nodes.
|
||||
//
|
||||
|
||||
def IA64getfd : SDNode<"IA64ISD::GETFD", SDTFPToIntOp, []>;
|
||||
|
||||
def retflag : SDNode<"IA64ISD::RET_FLAG", SDTNone,
|
||||
[SDNPHasChain, SDNPOptInFlag]>;
|
||||
|
||||
//===---------
|
||||
// Instruction types
|
||||
|
||||
class isA { bit A=1; } // I or M unit
|
||||
class isM { bit M=1; } // M unit
|
||||
class isI { bit I=1; } // I unit
|
||||
class isB { bit B=1; } // B unit
|
||||
class isF { bit F=1; } // F unit
|
||||
class isLX { bit LX=1; } // I/B
|
||||
|
||||
//===---------
|
||||
|
||||
def u2imm : Operand<i8>;
|
||||
def u6imm : Operand<i8>;
|
||||
def s8imm : Operand<i8> {
|
||||
let PrintMethod = "printS8ImmOperand";
|
||||
}
|
||||
def s14imm : Operand<i64> {
|
||||
let PrintMethod = "printS14ImmOperand";
|
||||
}
|
||||
def s22imm : Operand<i64> {
|
||||
let PrintMethod = "printS22ImmOperand";
|
||||
}
|
||||
def u64imm : Operand<i64> {
|
||||
let PrintMethod = "printU64ImmOperand";
|
||||
}
|
||||
def s64imm : Operand<i64> {
|
||||
let PrintMethod = "printS64ImmOperand";
|
||||
}
|
||||
|
||||
let PrintMethod = "printGlobalOperand" in
|
||||
def globaladdress : Operand<i64>;
|
||||
|
||||
// the asmprinter needs to know about calls
|
||||
let PrintMethod = "printCallOperand" in
|
||||
def calltarget : Operand<i64>;
|
||||
|
||||
/* new daggy action!!! */
|
||||
|
||||
def is32ones : PatLeaf<(i64 imm), [{
|
||||
// is32ones predicate - True if the immediate is 0x00000000FFFFFFFF
|
||||
// Used to create ZXT4s appropriately
|
||||
uint64_t v = (uint64_t)N->getZExtValue();
|
||||
return (v == 0x00000000FFFFFFFFLL);
|
||||
}]>;
|
||||
|
||||
// isMIXable predicates - True if the immediate is
|
||||
// 0xFF00FF00FF00FF00, 0x00FF00FF00FF00FF
|
||||
// etc, through 0x00000000FFFFFFFF
|
||||
// Used to test for the suitability of mix*
|
||||
def isMIX1Lable: PatLeaf<(i64 imm), [{
|
||||
return((uint64_t)N->getZExtValue()==0xFF00FF00FF00FF00LL);
|
||||
}]>;
|
||||
def isMIX1Rable: PatLeaf<(i64 imm), [{
|
||||
return((uint64_t)N->getZExtValue()==0x00FF00FF00FF00FFLL);
|
||||
}]>;
|
||||
def isMIX2Lable: PatLeaf<(i64 imm), [{
|
||||
return((uint64_t)N->getZExtValue()==0xFFFF0000FFFF0000LL);
|
||||
}]>;
|
||||
def isMIX2Rable: PatLeaf<(i64 imm), [{
|
||||
return((uint64_t)N->getZExtValue()==0x0000FFFF0000FFFFLL);
|
||||
}]>;
|
||||
def isMIX4Lable: PatLeaf<(i64 imm), [{
|
||||
return((uint64_t)N->getZExtValue()==0xFFFFFFFF00000000LL);
|
||||
}]>;
|
||||
def isMIX4Rable: PatLeaf<(i64 imm), [{
|
||||
return((uint64_t)N->getZExtValue()==0x00000000FFFFFFFFLL);
|
||||
}]>;
|
||||
|
||||
def isSHLADDimm: PatLeaf<(i64 imm), [{
|
||||
// isSHLADDimm predicate - True if the immediate is exactly 1, 2, 3 or 4
|
||||
// - 0 is *not* okay.
|
||||
// Used to create shladd instructions appropriately
|
||||
int64_t v = (int64_t)N->getZExtValue();
|
||||
return (v >= 1 && v <= 4);
|
||||
}]>;
|
||||
|
||||
def immSExt14 : PatLeaf<(i64 imm), [{
|
||||
// immSExt14 predicate - True if the immediate fits in a 14-bit sign extended
|
||||
// field. Used by instructions like 'adds'.
|
||||
int64_t v = (int64_t)N->getZExtValue();
|
||||
return (v <= 8191 && v >= -8192);
|
||||
}]>;
|
||||
|
||||
// imm64 predicate - True if the immediate fits in a 64-bit
|
||||
// field - i.e., true. used to keep movl happy
|
||||
def imm64 : PatLeaf<(i64 imm)>;
|
||||
|
||||
def ADD : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
|
||||
"add $dst = $src1, $src2",
|
||||
[(set GR:$dst, (add GR:$src1, GR:$src2))]>, isA;
|
||||
|
||||
def ADD1 : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
|
||||
"add $dst = $src1, $src2, 1",
|
||||
[(set GR:$dst, (add (add GR:$src1, GR:$src2), 1))]>, isA;
|
||||
|
||||
def ADDS : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, s14imm:$imm),
|
||||
"adds $dst = $imm, $src1",
|
||||
[(set GR:$dst, (add GR:$src1, immSExt14:$imm))]>, isA;
|
||||
|
||||
def MOVL : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins s64imm:$imm),
|
||||
"movl $dst = $imm",
|
||||
[(set GR:$dst, imm64:$imm)]>, isLX;
|
||||
|
||||
def ADDL_GA : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, globaladdress:$imm),
|
||||
"addl $dst = $imm, $src1",
|
||||
[]>, isA;
|
||||
|
||||
// hmm
|
||||
def ADDL_EA : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, calltarget:$imm),
|
||||
"addl $dst = $imm, $src1",
|
||||
[]>, isA;
|
||||
|
||||
def SUB : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
|
||||
"sub $dst = $src1, $src2",
|
||||
[(set GR:$dst, (sub GR:$src1, GR:$src2))]>, isA;
|
||||
|
||||
def SUB1 : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
|
||||
"sub $dst = $src1, $src2, 1",
|
||||
[(set GR:$dst, (add (sub GR: $src1, GR:$src2), -1))]>, isA;
|
||||
|
||||
let isTwoAddress = 1 in {
|
||||
def TPCADDIMM22 : AForm<0x03, 0x0b,
|
||||
(outs GR:$dst), (ins GR:$src1, s22imm:$imm, PR:$qp),
|
||||
"($qp) add $dst = $imm, $dst">, isA;
|
||||
def TPCADDS : AForm_DAG<0x03, 0x0b,
|
||||
(outs GR:$dst), (ins GR:$src1, s14imm:$imm, PR:$qp),
|
||||
"($qp) adds $dst = $imm, $dst",
|
||||
[]>, isA;
|
||||
def TPCMPIMM8NE : AForm<0x03, 0x0b,
|
||||
(outs PR:$dst), (ins PR:$src1, s22imm:$imm, GR:$src2, PR:$qp),
|
||||
"($qp) cmp.ne $dst , p0 = $imm, $src2">, isA;
|
||||
}
|
||||
|
||||
// zero extend a bool (predicate reg) into an integer reg
|
||||
def ZXTb : Pat<(zext PR:$src),
|
||||
(TPCADDIMM22 (ADDS r0, 0), 1, PR:$src)>;
|
||||
def AXTb : Pat<(anyext PR:$src),
|
||||
(TPCADDIMM22 (ADDS r0, 0), 1, PR:$src)>;
|
||||
|
||||
// normal sign/zero-extends
|
||||
def SXT1 : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src), "sxt1 $dst = $src",
|
||||
[(set GR:$dst, (sext_inreg GR:$src, i8))]>, isI;
|
||||
def ZXT1 : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src), "zxt1 $dst = $src",
|
||||
[(set GR:$dst, (and GR:$src, 255))]>, isI;
|
||||
def SXT2 : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src), "sxt2 $dst = $src",
|
||||
[(set GR:$dst, (sext_inreg GR:$src, i16))]>, isI;
|
||||
def ZXT2 : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src), "zxt2 $dst = $src",
|
||||
[(set GR:$dst, (and GR:$src, 65535))]>, isI;
|
||||
def SXT4 : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src), "sxt4 $dst = $src",
|
||||
[(set GR:$dst, (sext_inreg GR:$src, i32))]>, isI;
|
||||
def ZXT4 : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src), "zxt4 $dst = $src",
|
||||
[(set GR:$dst, (and GR:$src, is32ones))]>, isI;
|
||||
|
||||
// fixme: shrs vs shru?
|
||||
def MIX1L : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
|
||||
"mix1.l $dst = $src1, $src2",
|
||||
[(set GR:$dst, (or (and GR:$src1, isMIX1Lable),
|
||||
(and (srl GR:$src2, (i64 8)), isMIX1Lable)))]>, isI;
|
||||
|
||||
def MIX2L : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
|
||||
"mix2.l $dst = $src1, $src2",
|
||||
[(set GR:$dst, (or (and GR:$src1, isMIX2Lable),
|
||||
(and (srl GR:$src2, (i64 16)), isMIX2Lable)))]>, isI;
|
||||
|
||||
def MIX4L : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
|
||||
"mix4.l $dst = $src1, $src2",
|
||||
[(set GR:$dst, (or (and GR:$src1, isMIX4Lable),
|
||||
(and (srl GR:$src2, (i64 32)), isMIX4Lable)))]>, isI;
|
||||
|
||||
def MIX1R : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
|
||||
"mix1.r $dst = $src1, $src2",
|
||||
[(set GR:$dst, (or (and (shl GR:$src1, (i64 8)), isMIX1Rable),
|
||||
(and GR:$src2, isMIX1Rable)))]>, isI;
|
||||
|
||||
def MIX2R : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
|
||||
"mix2.r $dst = $src1, $src2",
|
||||
[(set GR:$dst, (or (and (shl GR:$src1, (i64 16)), isMIX2Rable),
|
||||
(and GR:$src2, isMIX2Rable)))]>, isI;
|
||||
|
||||
def MIX4R : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
|
||||
"mix4.r $dst = $src1, $src2",
|
||||
[(set GR:$dst, (or (and (shl GR:$src1, (i64 32)), isMIX4Rable),
|
||||
(and GR:$src2, isMIX4Rable)))]>, isI;
|
||||
|
||||
def GETFSIGD : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins FP:$src),
|
||||
"getf.sig $dst = $src",
|
||||
[]>, isM;
|
||||
|
||||
def SETFSIGD : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins GR:$src),
|
||||
"setf.sig $dst = $src",
|
||||
[]>, isM;
|
||||
|
||||
def XMALD : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3),
|
||||
"xma.l $dst = $src1, $src2, $src3",
|
||||
[]>, isF;
|
||||
def XMAHD : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3),
|
||||
"xma.h $dst = $src1, $src2, $src3",
|
||||
[]>, isF;
|
||||
def XMAHUD : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3),
|
||||
"xma.hu $dst = $src1, $src2, $src3",
|
||||
[]>, isF;
|
||||
|
||||
// pseudocode for integer multiplication
|
||||
def : Pat<(mul GR:$src1, GR:$src2),
|
||||
(GETFSIGD (XMALD (SETFSIGD GR:$src1), (SETFSIGD GR:$src2), F0))>;
|
||||
def : Pat<(mulhs GR:$src1, GR:$src2),
|
||||
(GETFSIGD (XMAHD (SETFSIGD GR:$src1), (SETFSIGD GR:$src2), F0))>;
|
||||
def : Pat<(mulhu GR:$src1, GR:$src2),
|
||||
(GETFSIGD (XMAHUD (SETFSIGD GR:$src1), (SETFSIGD GR:$src2), F0))>;
|
||||
|
||||
// TODO: addp4 (addp4 dst = src, r0 is a 32-bit add)
|
||||
// has imm form, too
|
||||
|
||||
// def ADDS : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, s14imm:$imm),
|
||||
// "adds $dst = $imm, $src1">;
|
||||
|
||||
def AND : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
|
||||
"and $dst = $src1, $src2",
|
||||
[(set GR:$dst, (and GR:$src1, GR:$src2))]>, isA;
|
||||
def ANDCM : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
|
||||
"andcm $dst = $src1, $src2",
|
||||
[(set GR:$dst, (and GR:$src1, (not GR:$src2)))]>, isA;
|
||||
// TODO: and/andcm/or/xor/add/sub/shift immediate forms
|
||||
def OR : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
|
||||
"or $dst = $src1, $src2",
|
||||
[(set GR:$dst, (or GR:$src1, GR:$src2))]>, isA;
|
||||
|
||||
def pOR : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2, PR:$qp),
|
||||
"($qp) or $dst = $src1, $src2">, isA;
|
||||
|
||||
// the following are all a bit unfortunate: we throw away the complement
|
||||
// of the compare!
|
||||
def CMPEQ : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2),
|
||||
"cmp.eq $dst, p0 = $src1, $src2",
|
||||
[(set PR:$dst, (seteq GR:$src1, GR:$src2))]>, isA;
|
||||
def CMPGT : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2),
|
||||
"cmp.gt $dst, p0 = $src1, $src2",
|
||||
[(set PR:$dst, (setgt GR:$src1, GR:$src2))]>, isA;
|
||||
def CMPGE : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2),
|
||||
"cmp.ge $dst, p0 = $src1, $src2",
|
||||
[(set PR:$dst, (setge GR:$src1, GR:$src2))]>, isA;
|
||||
def CMPLT : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2),
|
||||
"cmp.lt $dst, p0 = $src1, $src2",
|
||||
[(set PR:$dst, (setlt GR:$src1, GR:$src2))]>, isA;
|
||||
def CMPLE : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2),
|
||||
"cmp.le $dst, p0 = $src1, $src2",
|
||||
[(set PR:$dst, (setle GR:$src1, GR:$src2))]>, isA;
|
||||
def CMPNE : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2),
|
||||
"cmp.ne $dst, p0 = $src1, $src2",
|
||||
[(set PR:$dst, (setne GR:$src1, GR:$src2))]>, isA;
|
||||
def CMPLTU: AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2),
|
||||
"cmp.ltu $dst, p0 = $src1, $src2",
|
||||
[(set PR:$dst, (setult GR:$src1, GR:$src2))]>, isA;
|
||||
def CMPGTU: AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2),
|
||||
"cmp.gtu $dst, p0 = $src1, $src2",
|
||||
[(set PR:$dst, (setugt GR:$src1, GR:$src2))]>, isA;
|
||||
def CMPLEU: AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2),
|
||||
"cmp.leu $dst, p0 = $src1, $src2",
|
||||
[(set PR:$dst, (setule GR:$src1, GR:$src2))]>, isA;
|
||||
def CMPGEU: AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2),
|
||||
"cmp.geu $dst, p0 = $src1, $src2",
|
||||
[(set PR:$dst, (setuge GR:$src1, GR:$src2))]>, isA;
|
||||
|
||||
// and we do the whole thing again for FP compares!
|
||||
def FCMPEQ : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins FP:$src1, FP:$src2),
|
||||
"fcmp.eq $dst, p0 = $src1, $src2",
|
||||
[(set PR:$dst, (seteq FP:$src1, FP:$src2))]>, isF;
|
||||
def FCMPGT : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins FP:$src1, FP:$src2),
|
||||
"fcmp.gt $dst, p0 = $src1, $src2",
|
||||
[(set PR:$dst, (setgt FP:$src1, FP:$src2))]>, isF;
|
||||
def FCMPGE : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins FP:$src1, FP:$src2),
|
||||
"fcmp.ge $dst, p0 = $src1, $src2",
|
||||
[(set PR:$dst, (setge FP:$src1, FP:$src2))]>, isF;
|
||||
def FCMPLT : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins FP:$src1, FP:$src2),
|
||||
"fcmp.lt $dst, p0 = $src1, $src2",
|
||||
[(set PR:$dst, (setlt FP:$src1, FP:$src2))]>, isF;
|
||||
def FCMPLE : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins FP:$src1, FP:$src2),
|
||||
"fcmp.le $dst, p0 = $src1, $src2",
|
||||
[(set PR:$dst, (setle FP:$src1, FP:$src2))]>, isF;
|
||||
def FCMPNE : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins FP:$src1, FP:$src2),
|
||||
"fcmp.neq $dst, p0 = $src1, $src2",
|
||||
[(set PR:$dst, (setne FP:$src1, FP:$src2))]>, isF;
|
||||
def FCMPLTU: AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins FP:$src1, FP:$src2),
|
||||
"fcmp.lt $dst, p0 = $src1, $src2",
|
||||
[(set PR:$dst, (setult FP:$src1, FP:$src2))]>, isF;
|
||||
def FCMPGTU: AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins FP:$src1, FP:$src2),
|
||||
"fcmp.gt $dst, p0 = $src1, $src2",
|
||||
[(set PR:$dst, (setugt FP:$src1, FP:$src2))]>, isF;
|
||||
def FCMPLEU: AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins FP:$src1, FP:$src2),
|
||||
"fcmp.le $dst, p0 = $src1, $src2",
|
||||
[(set PR:$dst, (setule FP:$src1, FP:$src2))]>, isF;
|
||||
def FCMPGEU: AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins FP:$src1, FP:$src2),
|
||||
"fcmp.ge $dst, p0 = $src1, $src2",
|
||||
[(set PR:$dst, (setuge FP:$src1, FP:$src2))]>, isF;
|
||||
|
||||
def PCMPEQUNCR0R0 : AForm<0x03, 0x0b, (outs PR:$dst), (ins PR:$qp),
|
||||
"($qp) cmp.eq.unc $dst, p0 = r0, r0">, isA;
|
||||
|
||||
def : Pat<(trunc GR:$src), // truncate i64 to i1
|
||||
(CMPNE GR:$src, r0)>; // $src!=0? If so, PR:$dst=true
|
||||
|
||||
let isTwoAddress=1 in {
|
||||
def TPCMPEQR0R0 : AForm<0x03, 0x0b, (outs PR:$dst), (ins PR:$bogus, PR:$qp),
|
||||
"($qp) cmp.eq $dst, p0 = r0, r0">, isA;
|
||||
def TPCMPNER0R0 : AForm<0x03, 0x0b, (outs PR:$dst), (ins PR:$bogus, PR:$qp),
|
||||
"($qp) cmp.ne $dst, p0 = r0, r0">, isA;
|
||||
}
|
||||
|
||||
/* our pseudocode for OR on predicates is:
|
||||
pC = pA OR pB
|
||||
-------------
|
||||
(pA) cmp.eq.unc pC,p0 = r0,r0 // pC = pA
|
||||
;;
|
||||
(pB) cmp.eq pC,p0 = r0,r0 // if (pB) pC = 1 */
|
||||
|
||||
def bOR : Pat<(or PR:$src1, PR:$src2),
|
||||
(TPCMPEQR0R0 (PCMPEQUNCR0R0 PR:$src1), PR:$src2)>;
|
||||
|
||||
/* our pseudocode for AND on predicates is:
|
||||
*
|
||||
(pA) cmp.eq.unc pC,p0 = r0,r0 // pC = pA
|
||||
cmp.eq pTemp,p0 = r0,r0 // pTemp = NOT pB
|
||||
;;
|
||||
(pB) cmp.ne pTemp,p0 = r0,r0
|
||||
;;
|
||||
(pTemp)cmp.ne pC,p0 = r0,r0 // if (NOT pB) pC = 0 */
|
||||
|
||||
def bAND : Pat<(and PR:$src1, PR:$src2),
|
||||
( TPCMPNER0R0 (PCMPEQUNCR0R0 PR:$src1),
|
||||
(TPCMPNER0R0 (CMPEQ r0, r0), PR:$src2) )>;
|
||||
|
||||
/* one possible routine for XOR on predicates is:
|
||||
|
||||
// Compute px = py ^ pz
|
||||
// using sum of products: px = (py & !pz) | (pz & !py)
|
||||
// Uses 5 instructions in 3 cycles.
|
||||
// cycle 1
|
||||
(pz) cmp.eq.unc px = r0, r0 // px = pz
|
||||
(py) cmp.eq.unc pt = r0, r0 // pt = py
|
||||
;;
|
||||
// cycle 2
|
||||
(pt) cmp.ne.and px = r0, r0 // px = px & !pt (px = pz & !pt)
|
||||
(pz) cmp.ne.and pt = r0, r0 // pt = pt & !pz
|
||||
;;
|
||||
} { .mmi
|
||||
// cycle 3
|
||||
(pt) cmp.eq.or px = r0, r0 // px = px | pt
|
||||
|
||||
*** Another, which we use here, requires one scratch GR. it is:
|
||||
|
||||
mov rt = 0 // initialize rt off critical path
|
||||
;;
|
||||
|
||||
// cycle 1
|
||||
(pz) cmp.eq.unc px = r0, r0 // px = pz
|
||||
(pz) mov rt = 1 // rt = pz
|
||||
;;
|
||||
// cycle 2
|
||||
(py) cmp.ne px = 1, rt // if (py) px = !pz
|
||||
|
||||
.. these routines kindly provided by Jim Hull
|
||||
*/
|
||||
|
||||
def bXOR : Pat<(xor PR:$src1, PR:$src2),
|
||||
(TPCMPIMM8NE (PCMPEQUNCR0R0 PR:$src2), 1,
|
||||
(TPCADDS (ADDS r0, 0), 1, PR:$src2),
|
||||
PR:$src1)>;
|
||||
|
||||
def XOR : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
|
||||
"xor $dst = $src1, $src2",
|
||||
[(set GR:$dst, (xor GR:$src1, GR:$src2))]>, isA;
|
||||
|
||||
def SHLADD: AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1,s64imm:$imm,GR:$src2),
|
||||
"shladd $dst = $src1, $imm, $src2",
|
||||
[(set GR:$dst, (add GR:$src2, (shl GR:$src1, isSHLADDimm:$imm)))]>, isA;
|
||||
|
||||
def SHL : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
|
||||
"shl $dst = $src1, $src2",
|
||||
[(set GR:$dst, (shl GR:$src1, GR:$src2))]>, isI;
|
||||
|
||||
def SHRU : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
|
||||
"shr.u $dst = $src1, $src2",
|
||||
[(set GR:$dst, (srl GR:$src1, GR:$src2))]>, isI;
|
||||
|
||||
def SHRS : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2),
|
||||
"shr $dst = $src1, $src2",
|
||||
[(set GR:$dst, (sra GR:$src1, GR:$src2))]>, isI;
|
||||
|
||||
def MOV : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src), "mov $dst = $src">, isA;
|
||||
def FMOV : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src),
|
||||
"mov $dst = $src">, isF; // XXX: there _is_ no fmov
|
||||
def PMOV : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src, PR:$qp),
|
||||
"($qp) mov $dst = $src">, isA;
|
||||
|
||||
def SPILL_ALL_PREDICATES_TO_GR : AForm<0x03, 0x0b, (outs GR:$dst), (ins),
|
||||
"mov $dst = pr">, isI;
|
||||
def FILL_ALL_PREDICATES_FROM_GR : AForm<0x03, 0x0b, (outs), (ins GR:$src),
|
||||
"mov pr = $src">, isI;
|
||||
|
||||
let isTwoAddress = 1 in {
|
||||
def CMOV : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src2, GR:$src, PR:$qp),
|
||||
"($qp) mov $dst = $src">, isA;
|
||||
}
|
||||
|
||||
def PFMOV : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src, PR:$qp),
|
||||
"($qp) mov $dst = $src">, isF;
|
||||
|
||||
let isTwoAddress = 1 in {
|
||||
def CFMOV : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src2, FP:$src, PR:$qp),
|
||||
"($qp) mov $dst = $src">, isF;
|
||||
}
|
||||
|
||||
def SELECTINT : Pat<(select PR:$which, GR:$src1, GR:$src2),
|
||||
(CMOV (MOV GR:$src2), GR:$src1, PR:$which)>; // note order!
|
||||
def SELECTFP : Pat<(select PR:$which, FP:$src1, FP:$src2),
|
||||
(CFMOV (FMOV FP:$src2), FP:$src1, PR:$which)>; // note order!
|
||||
// TODO: can do this faster, w/o using any integer regs (see pattern isel)
|
||||
def SELECTBOOL : Pat<(select PR:$which, PR:$src1, PR:$src2), // note order!
|
||||
(CMPNE (CMOV
|
||||
(MOV (TPCADDIMM22 (ADDS r0, 0), 1, PR:$src2)),
|
||||
(TPCADDIMM22 (ADDS r0, 0), 1, PR:$src1), PR:$which), r0)>;
|
||||
|
||||
// load constants of various sizes // FIXME: prettyprint -ve constants
|
||||
def : Pat<(i64 immSExt14:$imm), (ADDS r0, immSExt14:$imm)>;
|
||||
def : Pat<(i1 -1), (CMPEQ r0, r0)>; // TODO: this should just be a ref to p0
|
||||
def : Pat<(i1 0), (CMPNE r0, r0)>; // TODO: any instruction actually *using*
|
||||
// this predicate should be killed!
|
||||
|
||||
// TODO: support postincrement (reg, imm9) loads+stores - this needs more
|
||||
// tablegen support
|
||||
|
||||
def IUSE : PseudoInstIA64<(outs), (ins variable_ops), "// IUSE">;
|
||||
def ADJUSTCALLSTACKUP : PseudoInstIA64<(outs), (ins variable_ops),
|
||||
"// ADJUSTCALLSTACKUP">;
|
||||
def ADJUSTCALLSTACKDOWN : PseudoInstIA64<(outs), (ins variable_ops),
|
||||
"// ADJUSTCALLSTACKDOWN">;
|
||||
def PSEUDO_ALLOC : PseudoInstIA64<(outs), (ins GR:$foo), "// PSEUDO_ALLOC">;
|
||||
|
||||
def ALLOC : AForm<0x03, 0x0b,
|
||||
(outs GR:$dst), (ins i8imm:$inputs, i8imm:$locals, i8imm:$outputs, i8imm:$rotating),
|
||||
"alloc $dst = ar.pfs,$inputs,$locals,$outputs,$rotating">, isM;
|
||||
|
||||
let isTwoAddress = 1 in {
|
||||
def TCMPNE : AForm<0x03, 0x0b,
|
||||
(outs PR:$dst), (ins PR:$src2, GR:$src3, GR:$src4),
|
||||
"cmp.ne $dst, p0 = $src3, $src4">, isA;
|
||||
|
||||
def TPCMPEQOR : AForm<0x03, 0x0b,
|
||||
(outs PR:$dst), (ins PR:$src2, GR:$src3, GR:$src4, PR:$qp),
|
||||
"($qp) cmp.eq.or $dst, p0 = $src3, $src4">, isA;
|
||||
|
||||
def TPCMPNE : AForm<0x03, 0x0b,
|
||||
(outs PR:$dst), (ins PR:$src2, GR:$src3, GR:$src4, PR:$qp),
|
||||
"($qp) cmp.ne $dst, p0 = $src3, $src4">, isA;
|
||||
|
||||
def TPCMPEQ : AForm<0x03, 0x0b,
|
||||
(outs PR:$dst), (ins PR:$src2, GR:$src3, GR:$src4, PR:$qp),
|
||||
"($qp) cmp.eq $dst, p0 = $src3, $src4">, isA;
|
||||
}
|
||||
|
||||
def MOVSIMM14 : AForm<0x03, 0x0b, (outs GR:$dst), (ins s14imm:$imm),
|
||||
"mov $dst = $imm">, isA;
|
||||
def MOVSIMM22 : AForm<0x03, 0x0b, (outs GR:$dst), (ins s22imm:$imm),
|
||||
"mov $dst = $imm">, isA;
|
||||
def MOVLIMM64 : AForm<0x03, 0x0b, (outs GR:$dst), (ins s64imm:$imm),
|
||||
"movl $dst = $imm">, isLX;
|
||||
|
||||
def SHLI : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, u6imm:$imm),
|
||||
"shl $dst = $src1, $imm">, isI;
|
||||
def SHRUI : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, u6imm:$imm),
|
||||
"shr.u $dst = $src1, $imm">, isI;
|
||||
def SHRSI : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, u6imm:$imm),
|
||||
"shr $dst = $src1, $imm">, isI;
|
||||
|
||||
def EXTRU : AForm<0x03, 0x0b,
|
||||
(outs GR:$dst), (ins GR:$src1, u6imm:$imm1, u6imm:$imm2),
|
||||
"extr.u $dst = $src1, $imm1, $imm2">, isI;
|
||||
|
||||
def DEPZ : AForm<0x03, 0x0b,
|
||||
(outs GR:$dst), (ins GR:$src1, u6imm:$imm1, u6imm:$imm2),
|
||||
"dep.z $dst = $src1, $imm1, $imm2">, isI;
|
||||
|
||||
def PCMPEQOR : AForm<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2, PR:$qp),
|
||||
"($qp) cmp.eq.or $dst, p0 = $src1, $src2">, isA;
|
||||
def PCMPEQUNC : AForm<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2, PR:$qp),
|
||||
"($qp) cmp.eq.unc $dst, p0 = $src1, $src2">, isA;
|
||||
def PCMPNE : AForm<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2, PR:$qp),
|
||||
"($qp) cmp.ne $dst, p0 = $src1, $src2">, isA;
|
||||
|
||||
// two destinations!
|
||||
def BCMPEQ : AForm<0x03, 0x0b, (outs PR:$dst1, PR:$dst2), (ins GR:$src1, GR:$src2),
|
||||
"cmp.eq $dst1, dst2 = $src1, $src2">, isA;
|
||||
|
||||
def ADDIMM14 : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, s14imm:$imm),
|
||||
"adds $dst = $imm, $src1">, isA;
|
||||
|
||||
def ADDIMM22 : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, s22imm:$imm),
|
||||
"add $dst = $imm, $src1">, isA;
|
||||
def CADDIMM22 : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, s22imm:$imm, PR:$qp),
|
||||
"($qp) add $dst = $imm, $src1">, isA;
|
||||
|
||||
def SUBIMM8 : AForm<0x03, 0x0b, (outs GR:$dst), (ins s8imm:$imm, GR:$src2),
|
||||
"sub $dst = $imm, $src2">, isA;
|
||||
|
||||
let mayStore = 1 in {
|
||||
def ST1 : AForm<0x03, 0x0b, (outs), (ins GR:$dstPtr, GR:$value),
|
||||
"st1 [$dstPtr] = $value">, isM;
|
||||
def ST2 : AForm<0x03, 0x0b, (outs), (ins GR:$dstPtr, GR:$value),
|
||||
"st2 [$dstPtr] = $value">, isM;
|
||||
def ST4 : AForm<0x03, 0x0b, (outs), (ins GR:$dstPtr, GR:$value),
|
||||
"st4 [$dstPtr] = $value">, isM;
|
||||
def ST8 : AForm<0x03, 0x0b, (outs), (ins GR:$dstPtr, GR:$value),
|
||||
"st8 [$dstPtr] = $value">, isM;
|
||||
def STF4 : AForm<0x03, 0x0b, (outs), (ins GR:$dstPtr, FP:$value),
|
||||
"stfs [$dstPtr] = $value">, isM;
|
||||
def STF8 : AForm<0x03, 0x0b, (outs), (ins GR:$dstPtr, FP:$value),
|
||||
"stfd [$dstPtr] = $value">, isM;
|
||||
def STF_SPILL : AForm<0x03, 0x0b, (outs), (ins GR:$dstPtr, FP:$value),
|
||||
"stf.spill [$dstPtr] = $value">, isM;
|
||||
}
|
||||
|
||||
let canFoldAsLoad = 1 in {
|
||||
def LD1 : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$srcPtr),
|
||||
"ld1 $dst = [$srcPtr]">, isM;
|
||||
def LD2 : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$srcPtr),
|
||||
"ld2 $dst = [$srcPtr]">, isM;
|
||||
def LD4 : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$srcPtr),
|
||||
"ld4 $dst = [$srcPtr]">, isM;
|
||||
def LD8 : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$srcPtr),
|
||||
"ld8 $dst = [$srcPtr]">, isM;
|
||||
def LDF4 : AForm<0x03, 0x0b, (outs FP:$dst), (ins GR:$srcPtr),
|
||||
"ldfs $dst = [$srcPtr]">, isM;
|
||||
def LDF8 : AForm<0x03, 0x0b, (outs FP:$dst), (ins GR:$srcPtr),
|
||||
"ldfd $dst = [$srcPtr]">, isM;
|
||||
def LDF_FILL : AForm<0x03, 0x0b, (outs FP:$dst), (ins GR:$srcPtr),
|
||||
"ldf.fill $dst = [$srcPtr]">, isM;
|
||||
}
|
||||
|
||||
def POPCNT : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src),
|
||||
"popcnt $dst = $src",
|
||||
[(set GR:$dst, (ctpop GR:$src))]>, isI;
|
||||
|
||||
// some FP stuff: // TODO: single-precision stuff?
|
||||
def FADD : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2),
|
||||
"fadd $dst = $src1, $src2",
|
||||
[(set FP:$dst, (fadd FP:$src1, FP:$src2))]>, isF;
|
||||
def FADDS: AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2),
|
||||
"fadd.s $dst = $src1, $src2">, isF;
|
||||
def FSUB : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2),
|
||||
"fsub $dst = $src1, $src2",
|
||||
[(set FP:$dst, (fsub FP:$src1, FP:$src2))]>, isF;
|
||||
def FMPY : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2),
|
||||
"fmpy $dst = $src1, $src2",
|
||||
[(set FP:$dst, (fmul FP:$src1, FP:$src2))]>, isF;
|
||||
def FMA : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3),
|
||||
"fma $dst = $src1, $src2, $src3",
|
||||
[(set FP:$dst, (fadd (fmul FP:$src1, FP:$src2), FP:$src3))]>, isF;
|
||||
def FMS : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3),
|
||||
"fms $dst = $src1, $src2, $src3",
|
||||
[(set FP:$dst, (fsub (fmul FP:$src1, FP:$src2), FP:$src3))]>, isF;
|
||||
def FNMA : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3),
|
||||
"fnma $dst = $src1, $src2, $src3",
|
||||
[(set FP:$dst, (fneg (fadd (fmul FP:$src1, FP:$src2), FP:$src3)))]>, isF;
|
||||
def FABS : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src),
|
||||
"fabs $dst = $src",
|
||||
[(set FP:$dst, (fabs FP:$src))]>, isF;
|
||||
def FNEG : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src),
|
||||
"fneg $dst = $src",
|
||||
[(set FP:$dst, (fneg FP:$src))]>, isF;
|
||||
def FNEGABS : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src),
|
||||
"fnegabs $dst = $src",
|
||||
[(set FP:$dst, (fneg (fabs FP:$src)))]>, isF;
|
||||
|
||||
let isTwoAddress=1 in {
|
||||
def TCFMAS1 : AForm<0x03, 0x0b,
|
||||
(outs FP:$dst), (ins FP:$bogussrc, FP:$src1, FP:$src2, FP:$src3, PR:$qp),
|
||||
"($qp) fma.s1 $dst = $src1, $src2, $src3">, isF;
|
||||
def TCFMADS0 : AForm<0x03, 0x0b,
|
||||
(outs FP:$dst), (ins FP:$bogussrc, FP:$src1, FP:$src2, FP:$src3, PR:$qp),
|
||||
"($qp) fma.d.s0 $dst = $src1, $src2, $src3">, isF;
|
||||
}
|
||||
|
||||
def CFMAS1 : AForm<0x03, 0x0b,
|
||||
(outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3, PR:$qp),
|
||||
"($qp) fma.s1 $dst = $src1, $src2, $src3">, isF;
|
||||
def CFNMAS1 : AForm<0x03, 0x0b,
|
||||
(outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3, PR:$qp),
|
||||
"($qp) fnma.s1 $dst = $src1, $src2, $src3">, isF;
|
||||
|
||||
def CFMADS1 : AForm<0x03, 0x0b,
|
||||
(outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3, PR:$qp),
|
||||
"($qp) fma.d.s1 $dst = $src1, $src2, $src3">, isF;
|
||||
def CFMADS0 : AForm<0x03, 0x0b,
|
||||
(outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3, PR:$qp),
|
||||
"($qp) fma.d.s0 $dst = $src1, $src2, $src3">, isF;
|
||||
def CFNMADS1 : AForm<0x03, 0x0b,
|
||||
(outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3, PR:$qp),
|
||||
"($qp) fnma.d.s1 $dst = $src1, $src2, $src3">, isF;
|
||||
|
||||
def FRCPAS0 : AForm<0x03, 0x0b, (outs FP:$dstFR, PR:$dstPR), (ins FP:$src1, FP:$src2),
|
||||
"frcpa.s0 $dstFR, $dstPR = $src1, $src2">, isF;
|
||||
def FRCPAS1 : AForm<0x03, 0x0b, (outs FP:$dstFR, PR:$dstPR), (ins FP:$src1, FP:$src2),
|
||||
"frcpa.s1 $dstFR, $dstPR = $src1, $src2">, isF;
|
||||
|
||||
def XMAL : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3),
|
||||
"xma.l $dst = $src1, $src2, $src3">, isF;
|
||||
|
||||
def FCVTXF : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src),
|
||||
"fcvt.xf $dst = $src">, isF;
|
||||
def FCVTXUF : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src),
|
||||
"fcvt.xuf $dst = $src">, isF;
|
||||
def FCVTXUFS1 : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src),
|
||||
"fcvt.xuf.s1 $dst = $src">, isF;
|
||||
def FCVTFX : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src),
|
||||
"fcvt.fx $dst = $src">, isF;
|
||||
def FCVTFXU : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src),
|
||||
"fcvt.fxu $dst = $src">, isF;
|
||||
|
||||
def FCVTFXTRUNC : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src),
|
||||
"fcvt.fx.trunc $dst = $src">, isF;
|
||||
def FCVTFXUTRUNC : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src),
|
||||
"fcvt.fxu.trunc $dst = $src">, isF;
|
||||
|
||||
def FCVTFXTRUNCS1 : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src),
|
||||
"fcvt.fx.trunc.s1 $dst = $src">, isF;
|
||||
def FCVTFXUTRUNCS1 : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src),
|
||||
"fcvt.fxu.trunc.s1 $dst = $src">, isF;
|
||||
|
||||
def FNORMD : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src),
|
||||
"fnorm.d $dst = $src">, isF;
|
||||
|
||||
def GETFD : AForm<0x03, 0x0b, (outs GR:$dst), (ins FP:$src),
|
||||
"getf.d $dst = $src">, isM;
|
||||
def SETFD : AForm<0x03, 0x0b, (outs FP:$dst), (ins GR:$src),
|
||||
"setf.d $dst = $src">, isM;
|
||||
|
||||
def GETFSIG : AForm<0x03, 0x0b, (outs GR:$dst), (ins FP:$src),
|
||||
"getf.sig $dst = $src">, isM;
|
||||
def SETFSIG : AForm<0x03, 0x0b, (outs FP:$dst), (ins GR:$src),
|
||||
"setf.sig $dst = $src">, isM;
|
||||
|
||||
// these four FP<->int conversion patterns need checking/cleaning
|
||||
def SINT_TO_FP : Pat<(sint_to_fp GR:$src),
|
||||
(FNORMD (FCVTXF (SETFSIG GR:$src)))>;
|
||||
def UINT_TO_FP : Pat<(uint_to_fp GR:$src),
|
||||
(FNORMD (FCVTXUF (SETFSIG GR:$src)))>;
|
||||
def FP_TO_SINT : Pat<(i64 (fp_to_sint FP:$src)),
|
||||
(GETFSIG (FCVTFXTRUNC FP:$src))>;
|
||||
def FP_TO_UINT : Pat<(i64 (fp_to_uint FP:$src)),
|
||||
(GETFSIG (FCVTFXUTRUNC FP:$src))>;
|
||||
|
||||
def fpimm0 : PatLeaf<(fpimm), [{
|
||||
return N->isExactlyValue(+0.0);
|
||||
}]>;
|
||||
def fpimm1 : PatLeaf<(fpimm), [{
|
||||
return N->isExactlyValue(+1.0);
|
||||
}]>;
|
||||
def fpimmn0 : PatLeaf<(fpimm), [{
|
||||
return N->isExactlyValue(-0.0);
|
||||
}]>;
|
||||
def fpimmn1 : PatLeaf<(fpimm), [{
|
||||
return N->isExactlyValue(-1.0);
|
||||
}]>;
|
||||
|
||||
def : Pat<(f64 fpimm0), (FMOV F0)>;
|
||||
def : Pat<(f64 fpimm1), (FMOV F1)>;
|
||||
def : Pat<(f64 fpimmn0), (FNEG F0)>;
|
||||
def : Pat<(f64 fpimmn1), (FNEG F1)>;
|
||||
|
||||
let isTerminator = 1, isBranch = 1 in {
|
||||
def BRL_NOTCALL : RawForm<0x03, 0xb0, (outs), (ins i64imm:$dst),
|
||||
"(p0) brl.cond.sptk $dst">, isB;
|
||||
def BRLCOND_NOTCALL : RawForm<0x03, 0xb0, (outs), (ins PR:$qp, i64imm:$dst),
|
||||
"($qp) brl.cond.sptk $dst">, isB;
|
||||
def BRCOND_NOTCALL : RawForm<0x03, 0xb0, (outs), (ins PR:$qp, GR:$dst),
|
||||
"($qp) br.cond.sptk $dst">, isB;
|
||||
}
|
||||
|
||||
let isCall = 1, /* isTerminator = 1, isBranch = 1, */
|
||||
Uses = [out0,out1,out2,out3,out4,out5,out6,out7],
|
||||
// all calls clobber non-callee-saved registers, and for now, they are these:
|
||||
Defs = [r2,r3,r8,r9,r10,r11,r14,r15,r16,r17,r18,r19,r20,r21,r22,r23,r24,
|
||||
r25,r26,r27,r28,r29,r30,r31,
|
||||
p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,
|
||||
F6,F7,F8,F9,F10,F11,F12,F13,F14,F15,
|
||||
F32,F33,F34,F35,F36,F37,F38,F39,F40,F41,F42,F43,F44,F45,F46,F47,F48,F49,
|
||||
F50,F51,F52,F53,F54,F55,F56,
|
||||
F57,F58,F59,F60,F61,F62,F63,F64,F65,F66,F67,F68,F69,F70,F71,F72,F73,F74,
|
||||
F75,F76,F77,F78,F79,F80,F81,
|
||||
F82,F83,F84,F85,F86,F87,F88,F89,F90,F91,F92,F93,F94,F95,F96,F97,F98,F99,
|
||||
F100,F101,F102,F103,F104,F105,
|
||||
F106,F107,F108,F109,F110,F111,F112,F113,F114,F115,F116,F117,F118,F119,
|
||||
F120,F121,F122,F123,F124,F125,F126,F127,
|
||||
out0,out1,out2,out3,out4,out5,out6,out7] in {
|
||||
// old pattern call
|
||||
def BRCALL: RawForm<0x03, 0xb0, (outs), (ins calltarget:$dst),
|
||||
"br.call.sptk rp = $dst">, isB; // FIXME: teach llvm about branch regs?
|
||||
// new daggy stuff!
|
||||
|
||||
// calls a globaladdress
|
||||
def BRCALL_IPREL_GA : RawForm<0x03, 0xb0, (outs), (ins calltarget:$dst),
|
||||
"br.call.sptk rp = $dst">, isB; // FIXME: teach llvm about branch regs?
|
||||
// calls an externalsymbol
|
||||
def BRCALL_IPREL_ES : RawForm<0x03, 0xb0, (outs), (ins calltarget:$dst),
|
||||
"br.call.sptk rp = $dst">, isB; // FIXME: teach llvm about branch regs?
|
||||
// calls through a function descriptor
|
||||
def BRCALL_INDIRECT : RawForm<0x03, 0xb0, (outs), (ins GR:$branchreg),
|
||||
"br.call.sptk rp = $branchreg">, isB; // FIXME: teach llvm about branch regs?
|
||||
def BRLCOND_CALL : RawForm<0x03, 0xb0, (outs), (ins PR:$qp, i64imm:$dst),
|
||||
"($qp) brl.cond.call.sptk $dst">, isB;
|
||||
def BRCOND_CALL : RawForm<0x03, 0xb0, (outs), (ins PR:$qp, GR:$dst),
|
||||
"($qp) br.cond.call.sptk $dst">, isB;
|
||||
}
|
||||
|
||||
// Return branch:
|
||||
let isTerminator = 1, isReturn = 1 in
|
||||
def RET : AForm_DAG<0x03, 0x0b, (outs), (ins),
|
||||
"br.ret.sptk.many rp",
|
||||
[(retflag)]>, isB; // return
|
||||
def : Pat<(ret), (RET)>;
|
||||
|
||||
// the evil stop bit of despair
|
||||
def STOP : PseudoInstIA64<(outs), (ins variable_ops), ";;">;
|
||||
|
@ -1,34 +0,0 @@
|
||||
//===-- IA64MachineFunctionInfo.h - IA64-specific information ---*- C++ -*-===//
|
||||
//===-- for MachineFunction ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file declares IA64-specific per-machine-function information.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef IA64MACHINEFUNCTIONINFO_H
|
||||
#define IA64MACHINEFUNCTIONINFO_H
|
||||
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
//#include "IA64JITInfo.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class IA64FunctionInfo : public MachineFunctionInfo {
|
||||
|
||||
public:
|
||||
unsigned outRegsUsed; // how many 'out' registers are used
|
||||
// by this machinefunction? (used to compute the appropriate
|
||||
// entry in the 'alloc' instruction at the top of the
|
||||
// machinefunction)
|
||||
explicit IA64FunctionInfo(MachineFunction& MF) { outRegsUsed=0; };
|
||||
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
||||
|
@ -1,319 +0,0 @@
|
||||
//===- IA64RegisterInfo.cpp - IA64 Register Information ---------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the IA64 implementation of the TargetRegisterInfo class.
|
||||
// This file is responsible for the frame pointer elimination optimization
|
||||
// on IA64.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "IA64.h"
|
||||
#include "IA64RegisterInfo.h"
|
||||
#include "IA64InstrBuilder.h"
|
||||
#include "IA64MachineFunctionInfo.h"
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/Type.h"
|
||||
#include "llvm/CodeGen/ValueTypes.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineLocation.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/Target/TargetFrameInfo.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Target/TargetOptions.h"
|
||||
#include "llvm/Target/TargetInstrInfo.h"
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
using namespace llvm;
|
||||
|
||||
IA64RegisterInfo::IA64RegisterInfo(const TargetInstrInfo &tii)
|
||||
: IA64GenRegisterInfo(IA64::ADJUSTCALLSTACKDOWN, IA64::ADJUSTCALLSTACKUP),
|
||||
TII(tii) {}
|
||||
|
||||
const unsigned* IA64RegisterInfo::getCalleeSavedRegs(const MachineFunction *MF)
|
||||
const {
|
||||
static const unsigned CalleeSavedRegs[] = {
|
||||
IA64::r5, 0
|
||||
};
|
||||
return CalleeSavedRegs;
|
||||
}
|
||||
|
||||
const TargetRegisterClass* const*
|
||||
IA64RegisterInfo::getCalleeSavedRegClasses(const MachineFunction *MF) const {
|
||||
static const TargetRegisterClass * const CalleeSavedRegClasses[] = {
|
||||
&IA64::GRRegClass, 0
|
||||
};
|
||||
return CalleeSavedRegClasses;
|
||||
}
|
||||
|
||||
BitVector IA64RegisterInfo::getReservedRegs(const MachineFunction &MF) const {
|
||||
BitVector Reserved(getNumRegs());
|
||||
Reserved.set(IA64::r0);
|
||||
Reserved.set(IA64::r1);
|
||||
Reserved.set(IA64::r2);
|
||||
Reserved.set(IA64::r5);
|
||||
Reserved.set(IA64::r12);
|
||||
Reserved.set(IA64::r13);
|
||||
Reserved.set(IA64::r22);
|
||||
Reserved.set(IA64::rp);
|
||||
return Reserved;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Stack Frame Processing methods
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// hasFP - Return true if the specified function should have a dedicated frame
|
||||
// pointer register. This is true if the function has variable sized allocas or
|
||||
// if frame pointer elimination is disabled.
|
||||
//
|
||||
bool IA64RegisterInfo::hasFP(const MachineFunction &MF) const {
|
||||
const MachineFrameInfo *MFI = MF.getFrameInfo();
|
||||
return NoFramePointerElim || MFI->hasVarSizedObjects();
|
||||
}
|
||||
|
||||
void IA64RegisterInfo::
|
||||
eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator I) const {
|
||||
if (hasFP(MF)) {
|
||||
// If we have a frame pointer, turn the adjcallstackup instruction into a
|
||||
// 'sub SP, <amt>' and the adjcallstackdown instruction into 'add SP,
|
||||
// <amt>'
|
||||
MachineInstr *Old = I;
|
||||
unsigned Amount = Old->getOperand(0).getImm();
|
||||
DebugLoc dl = Old->getDebugLoc();
|
||||
if (Amount != 0) {
|
||||
// We need to keep the stack aligned properly. To do this, we round the
|
||||
// amount of space needed for the outgoing arguments up to the next
|
||||
// alignment boundary.
|
||||
unsigned Align = MF.getTarget().getFrameInfo()->getStackAlignment();
|
||||
Amount = (Amount+Align-1)/Align*Align;
|
||||
|
||||
// Replace the pseudo instruction with a new instruction...
|
||||
if (Old->getOpcode() == IA64::ADJUSTCALLSTACKDOWN) {
|
||||
BuildMI(MBB, I, dl, TII.get(IA64::ADDIMM22), IA64::r12)
|
||||
.addReg(IA64::r12).addImm(-Amount);
|
||||
} else {
|
||||
assert(Old->getOpcode() == IA64::ADJUSTCALLSTACKUP);
|
||||
BuildMI(MBB, I, dl, TII.get(IA64::ADDIMM22), IA64::r12)
|
||||
.addReg(IA64::r12).addImm(Amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MBB.erase(I);
|
||||
}
|
||||
|
||||
void IA64RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
|
||||
int SPAdj, RegScavenger *RS)const{
|
||||
assert(SPAdj == 0 && "Unexpected");
|
||||
|
||||
unsigned i = 0;
|
||||
MachineInstr &MI = *II;
|
||||
MachineBasicBlock &MBB = *MI.getParent();
|
||||
MachineFunction &MF = *MBB.getParent();
|
||||
DebugLoc dl = MI.getDebugLoc();
|
||||
|
||||
bool FP = hasFP(MF);
|
||||
|
||||
while (!MI.getOperand(i).isFI()) {
|
||||
++i;
|
||||
assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!");
|
||||
}
|
||||
|
||||
int FrameIndex = MI.getOperand(i).getIndex();
|
||||
|
||||
// choose a base register: ( hasFP? framepointer : stack pointer )
|
||||
unsigned BaseRegister = FP ? IA64::r5 : IA64::r12;
|
||||
// Add the base register
|
||||
MI.getOperand(i).ChangeToRegister(BaseRegister, false);
|
||||
|
||||
// Now add the frame object offset to the offset from r1.
|
||||
int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex);
|
||||
|
||||
// If we're not using a Frame Pointer that has been set to the value of the
|
||||
// SP before having the stack size subtracted from it, then add the stack size
|
||||
// to Offset to get the correct offset.
|
||||
Offset += MF.getFrameInfo()->getStackSize();
|
||||
|
||||
// XXX: we use 'r22' as another hack+slash temporary register here :(
|
||||
if (Offset <= 8191 && Offset >= -8192) { // smallish offset
|
||||
// Fix up the old:
|
||||
MI.getOperand(i).ChangeToRegister(IA64::r22, false);
|
||||
//insert the new
|
||||
BuildMI(MBB, II, dl, TII.get(IA64::ADDIMM22), IA64::r22)
|
||||
.addReg(BaseRegister).addImm(Offset);
|
||||
} else { // it's big
|
||||
//fix up the old:
|
||||
MI.getOperand(i).ChangeToRegister(IA64::r22, false);
|
||||
BuildMI(MBB, II, dl, TII.get(IA64::MOVLIMM64), IA64::r22).addImm(Offset);
|
||||
BuildMI(MBB, II, dl, TII.get(IA64::ADD), IA64::r22).addReg(BaseRegister)
|
||||
.addReg(IA64::r22);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void IA64RegisterInfo::emitPrologue(MachineFunction &MF) const {
|
||||
MachineBasicBlock &MBB = MF.front(); // Prolog goes in entry BB
|
||||
MachineBasicBlock::iterator MBBI = MBB.begin();
|
||||
MachineFrameInfo *MFI = MF.getFrameInfo();
|
||||
bool FP = hasFP(MF);
|
||||
DebugLoc dl = (MBBI != MBB.end() ?
|
||||
MBBI->getDebugLoc() : DebugLoc::getUnknownLoc());
|
||||
|
||||
// first, we handle the 'alloc' instruction, that should be right up the
|
||||
// top of any function
|
||||
static const unsigned RegsInOrder[96] = { // there are 96 GPRs the
|
||||
// RSE worries about
|
||||
IA64::r32, IA64::r33, IA64::r34, IA64::r35,
|
||||
IA64::r36, IA64::r37, IA64::r38, IA64::r39, IA64::r40, IA64::r41,
|
||||
IA64::r42, IA64::r43, IA64::r44, IA64::r45, IA64::r46, IA64::r47,
|
||||
IA64::r48, IA64::r49, IA64::r50, IA64::r51, IA64::r52, IA64::r53,
|
||||
IA64::r54, IA64::r55, IA64::r56, IA64::r57, IA64::r58, IA64::r59,
|
||||
IA64::r60, IA64::r61, IA64::r62, IA64::r63, IA64::r64, IA64::r65,
|
||||
IA64::r66, IA64::r67, IA64::r68, IA64::r69, IA64::r70, IA64::r71,
|
||||
IA64::r72, IA64::r73, IA64::r74, IA64::r75, IA64::r76, IA64::r77,
|
||||
IA64::r78, IA64::r79, IA64::r80, IA64::r81, IA64::r82, IA64::r83,
|
||||
IA64::r84, IA64::r85, IA64::r86, IA64::r87, IA64::r88, IA64::r89,
|
||||
IA64::r90, IA64::r91, IA64::r92, IA64::r93, IA64::r94, IA64::r95,
|
||||
IA64::r96, IA64::r97, IA64::r98, IA64::r99, IA64::r100, IA64::r101,
|
||||
IA64::r102, IA64::r103, IA64::r104, IA64::r105, IA64::r106, IA64::r107,
|
||||
IA64::r108, IA64::r109, IA64::r110, IA64::r111, IA64::r112, IA64::r113,
|
||||
IA64::r114, IA64::r115, IA64::r116, IA64::r117, IA64::r118, IA64::r119,
|
||||
IA64::r120, IA64::r121, IA64::r122, IA64::r123, IA64::r124, IA64::r125,
|
||||
IA64::r126, IA64::r127 };
|
||||
|
||||
unsigned numStackedGPRsUsed=0;
|
||||
for (int i=0; i != 96; i++) {
|
||||
if (MF.getRegInfo().isPhysRegUsed(RegsInOrder[i]))
|
||||
numStackedGPRsUsed=i+1; // (i+1 and not ++ - consider fn(fp, fp, int)
|
||||
}
|
||||
|
||||
unsigned numOutRegsUsed=MF.getInfo<IA64FunctionInfo>()->outRegsUsed;
|
||||
|
||||
// XXX FIXME : this code should be a bit more reliable (in case there _isn't_
|
||||
// a pseudo_alloc in the MBB)
|
||||
unsigned dstRegOfPseudoAlloc;
|
||||
for(MBBI = MBB.begin(); /*MBBI->getOpcode() != IA64::PSEUDO_ALLOC*/; ++MBBI) {
|
||||
assert(MBBI != MBB.end());
|
||||
if(MBBI->getOpcode() == IA64::PSEUDO_ALLOC) {
|
||||
dstRegOfPseudoAlloc=MBBI->getOperand(0).getReg();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (MBBI != MBB.end()) dl = MBBI->getDebugLoc();
|
||||
|
||||
BuildMI(MBB, MBBI, dl, TII.get(IA64::ALLOC)).
|
||||
addReg(dstRegOfPseudoAlloc).addImm(0).
|
||||
addImm(numStackedGPRsUsed).addImm(numOutRegsUsed).addImm(0);
|
||||
|
||||
// Get the number of bytes to allocate from the FrameInfo
|
||||
unsigned NumBytes = MFI->getStackSize();
|
||||
|
||||
if(FP)
|
||||
NumBytes += 8; // reserve space for the old FP
|
||||
|
||||
// Do we need to allocate space on the stack?
|
||||
if (NumBytes == 0)
|
||||
return;
|
||||
|
||||
// Add 16 bytes at the bottom of the stack (scratch area)
|
||||
// and round the size to a multiple of the alignment.
|
||||
unsigned Align = MF.getTarget().getFrameInfo()->getStackAlignment();
|
||||
unsigned Size = 16 + (FP ? 8 : 0);
|
||||
NumBytes = (NumBytes+Size+Align-1)/Align*Align;
|
||||
|
||||
// Update frame info to pretend that this is part of the stack...
|
||||
MFI->setStackSize(NumBytes);
|
||||
|
||||
// adjust stack pointer: r12 -= numbytes
|
||||
if (NumBytes <= 8191) {
|
||||
BuildMI(MBB, MBBI, dl, TII.get(IA64::ADDIMM22),IA64::r12).addReg(IA64::r12).
|
||||
addImm(-NumBytes);
|
||||
} else { // we use r22 as a scratch register here
|
||||
// first load the decrement into r22
|
||||
BuildMI(MBB, MBBI, dl, TII.get(IA64::MOVLIMM64), IA64::r22).
|
||||
addImm(-NumBytes);
|
||||
// FIXME: MOVLSI32 expects a _u_32imm
|
||||
// then add (subtract) it to r12 (stack ptr)
|
||||
BuildMI(MBB, MBBI, dl, TII.get(IA64::ADD), IA64::r12)
|
||||
.addReg(IA64::r12).addReg(IA64::r22);
|
||||
|
||||
}
|
||||
|
||||
// now if we need to, save the old FP and set the new
|
||||
if (FP) {
|
||||
BuildMI(MBB, MBBI,dl,TII.get(IA64::ST8)).addReg(IA64::r12).addReg(IA64::r5);
|
||||
// this must be the last instr in the prolog ? (XXX: why??)
|
||||
BuildMI(MBB, MBBI, dl, TII.get(IA64::MOV), IA64::r5).addReg(IA64::r12);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void IA64RegisterInfo::emitEpilogue(MachineFunction &MF,
|
||||
MachineBasicBlock &MBB) const {
|
||||
const MachineFrameInfo *MFI = MF.getFrameInfo();
|
||||
MachineBasicBlock::iterator MBBI = prior(MBB.end());
|
||||
assert(MBBI->getOpcode() == IA64::RET &&
|
||||
"Can only insert epilog into returning blocks");
|
||||
DebugLoc dl = MBBI->getDebugLoc();
|
||||
bool FP = hasFP(MF);
|
||||
|
||||
// Get the number of bytes allocated from the FrameInfo...
|
||||
unsigned NumBytes = MFI->getStackSize();
|
||||
|
||||
//now if we need to, restore the old FP
|
||||
if (FP) {
|
||||
//copy the FP into the SP (discards allocas)
|
||||
BuildMI(MBB, MBBI, dl, TII.get(IA64::MOV), IA64::r12).addReg(IA64::r5);
|
||||
//restore the FP
|
||||
BuildMI(MBB, MBBI, dl, TII.get(IA64::LD8), IA64::r5).addReg(IA64::r5);
|
||||
}
|
||||
|
||||
if (NumBytes != 0) {
|
||||
if (NumBytes <= 8191) {
|
||||
BuildMI(MBB, MBBI, dl, TII.get(IA64::ADDIMM22),IA64::r12).
|
||||
addReg(IA64::r12).addImm(NumBytes);
|
||||
} else {
|
||||
BuildMI(MBB, MBBI, dl, TII.get(IA64::MOVLIMM64), IA64::r22).
|
||||
addImm(NumBytes);
|
||||
BuildMI(MBB, MBBI, dl, TII.get(IA64::ADD), IA64::r12).addReg(IA64::r12).
|
||||
addReg(IA64::r22);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned IA64RegisterInfo::getRARegister() const {
|
||||
assert(0 && "What is the return address register");
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned IA64RegisterInfo::getFrameRegister(MachineFunction &MF) const {
|
||||
return hasFP(MF) ? IA64::r5 : IA64::r12;
|
||||
}
|
||||
|
||||
unsigned IA64RegisterInfo::getEHExceptionRegister() const {
|
||||
assert(0 && "What is the exception register");
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned IA64RegisterInfo::getEHHandlerRegister() const {
|
||||
assert(0 && "What is the exception handler register");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IA64RegisterInfo::getDwarfRegNum(unsigned RegNum, bool isEH) const {
|
||||
assert(0 && "What is the dwarf register number");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#include "IA64GenRegisterInfo.inc"
|
||||
|
@ -1,63 +0,0 @@
|
||||
//===- IA64RegisterInfo.h - IA64 Register Information Impl ------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the IA64 implementation of the TargetRegisterInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef IA64REGISTERINFO_H
|
||||
#define IA64REGISTERINFO_H
|
||||
|
||||
#include "llvm/Target/TargetRegisterInfo.h"
|
||||
#include "IA64GenRegisterInfo.h.inc"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class TargetInstrInfo;
|
||||
|
||||
struct IA64RegisterInfo : public IA64GenRegisterInfo {
|
||||
const TargetInstrInfo &TII;
|
||||
|
||||
IA64RegisterInfo(const TargetInstrInfo &tii);
|
||||
|
||||
/// Code Generation virtual methods...
|
||||
const unsigned *getCalleeSavedRegs(const MachineFunction *MF = 0) const;
|
||||
|
||||
const TargetRegisterClass* const* getCalleeSavedRegClasses(
|
||||
const MachineFunction *MF = 0) const;
|
||||
|
||||
BitVector getReservedRegs(const MachineFunction &MF) const;
|
||||
|
||||
bool hasFP(const MachineFunction &MF) const;
|
||||
|
||||
void eliminateCallFramePseudoInstr(MachineFunction &MF,
|
||||
MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MI) const;
|
||||
|
||||
void eliminateFrameIndex(MachineBasicBlock::iterator MI,
|
||||
int SPAdj, RegScavenger *RS = NULL) const;
|
||||
|
||||
void emitPrologue(MachineFunction &MF) const;
|
||||
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const;
|
||||
|
||||
// Debug information queries.
|
||||
unsigned getRARegister() const;
|
||||
unsigned getFrameRegister(MachineFunction &MF) const;
|
||||
|
||||
// Exception handling queries.
|
||||
unsigned getEHExceptionRegister() const;
|
||||
unsigned getEHHandlerRegister() const;
|
||||
|
||||
int getDwarfRegNum(unsigned RegNum, bool isEH) const;
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
||||
|
@ -1,509 +0,0 @@
|
||||
//===- IA64RegisterInfo.td - Describe the IA64 Register File ----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file describes the IA64 register file, defining the registers
|
||||
// themselves, aliases between the registers, and the register classes built
|
||||
// out of the registers.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Register definitions...
|
||||
//
|
||||
|
||||
class IA64Register<string n> : Register<n> {
|
||||
let Namespace = "IA64";
|
||||
}
|
||||
|
||||
// GR - One of 128 32-bit general registers
|
||||
class GR<bits<7> num, string n> : IA64Register<n> {
|
||||
field bits<7> Num = num;
|
||||
}
|
||||
|
||||
// FP - One of 128 82-bit floating-point registers
|
||||
class FP<bits<7> num, string n> : IA64Register<n> {
|
||||
field bits<7> Num = num;
|
||||
}
|
||||
|
||||
// PR - One of 64 1-bit predicate registers
|
||||
class PR<bits<6> num, string n> : IA64Register<n> {
|
||||
field bits<6> Num = num;
|
||||
}
|
||||
|
||||
/* general registers */
|
||||
def r0 : GR< 0, "r0">, DwarfRegNum<[0]>;
|
||||
def r1 : GR< 1, "r1">, DwarfRegNum<[1]>;
|
||||
def r2 : GR< 2, "r2">, DwarfRegNum<[2]>;
|
||||
def r3 : GR< 3, "r3">, DwarfRegNum<[3]>;
|
||||
def r4 : GR< 4, "r4">, DwarfRegNum<[4]>;
|
||||
def r5 : GR< 5, "r5">, DwarfRegNum<[5]>;
|
||||
def r6 : GR< 6, "r6">, DwarfRegNum<[6]>;
|
||||
def r7 : GR< 7, "r7">, DwarfRegNum<[7]>;
|
||||
def r8 : GR< 8, "r8">, DwarfRegNum<[8]>;
|
||||
def r9 : GR< 9, "r9">, DwarfRegNum<[9]>;
|
||||
def r10 : GR< 10, "r10">, DwarfRegNum<[10]>;
|
||||
def r11 : GR< 11, "r11">, DwarfRegNum<[11]>;
|
||||
def r12 : GR< 12, "r12">, DwarfRegNum<[12]>;
|
||||
def r13 : GR< 13, "r13">, DwarfRegNum<[13]>;
|
||||
def r14 : GR< 14, "r14">, DwarfRegNum<[14]>;
|
||||
def r15 : GR< 15, "r15">, DwarfRegNum<[15]>;
|
||||
def r16 : GR< 16, "r16">, DwarfRegNum<[16]>;
|
||||
def r17 : GR< 17, "r17">, DwarfRegNum<[17]>;
|
||||
def r18 : GR< 18, "r18">, DwarfRegNum<[18]>;
|
||||
def r19 : GR< 19, "r19">, DwarfRegNum<[19]>;
|
||||
def r20 : GR< 20, "r20">, DwarfRegNum<[20]>;
|
||||
def r21 : GR< 21, "r21">, DwarfRegNum<[21]>;
|
||||
def r22 : GR< 22, "r22">, DwarfRegNum<[22]>;
|
||||
def r23 : GR< 23, "r23">, DwarfRegNum<[23]>;
|
||||
def r24 : GR< 24, "r24">, DwarfRegNum<[24]>;
|
||||
def r25 : GR< 25, "r25">, DwarfRegNum<[25]>;
|
||||
def r26 : GR< 26, "r26">, DwarfRegNum<[26]>;
|
||||
def r27 : GR< 27, "r27">, DwarfRegNum<[27]>;
|
||||
def r28 : GR< 28, "r28">, DwarfRegNum<[28]>;
|
||||
def r29 : GR< 29, "r29">, DwarfRegNum<[29]>;
|
||||
def r30 : GR< 30, "r30">, DwarfRegNum<[30]>;
|
||||
def r31 : GR< 31, "r31">, DwarfRegNum<[31]>;
|
||||
def r32 : GR< 32, "r32">, DwarfRegNum<[32]>;
|
||||
def r33 : GR< 33, "r33">, DwarfRegNum<[33]>;
|
||||
def r34 : GR< 34, "r34">, DwarfRegNum<[34]>;
|
||||
def r35 : GR< 35, "r35">, DwarfRegNum<[35]>;
|
||||
def r36 : GR< 36, "r36">, DwarfRegNum<[36]>;
|
||||
def r37 : GR< 37, "r37">, DwarfRegNum<[37]>;
|
||||
def r38 : GR< 38, "r38">, DwarfRegNum<[38]>;
|
||||
def r39 : GR< 39, "r39">, DwarfRegNum<[39]>;
|
||||
def r40 : GR< 40, "r40">, DwarfRegNum<[40]>;
|
||||
def r41 : GR< 41, "r41">, DwarfRegNum<[41]>;
|
||||
def r42 : GR< 42, "r42">, DwarfRegNum<[42]>;
|
||||
def r43 : GR< 43, "r43">, DwarfRegNum<[43]>;
|
||||
def r44 : GR< 44, "r44">, DwarfRegNum<[44]>;
|
||||
def r45 : GR< 45, "r45">, DwarfRegNum<[45]>;
|
||||
def r46 : GR< 46, "r46">, DwarfRegNum<[46]>;
|
||||
def r47 : GR< 47, "r47">, DwarfRegNum<[47]>;
|
||||
def r48 : GR< 48, "r48">, DwarfRegNum<[48]>;
|
||||
def r49 : GR< 49, "r49">, DwarfRegNum<[49]>;
|
||||
def r50 : GR< 50, "r50">, DwarfRegNum<[50]>;
|
||||
def r51 : GR< 51, "r51">, DwarfRegNum<[51]>;
|
||||
def r52 : GR< 52, "r52">, DwarfRegNum<[52]>;
|
||||
def r53 : GR< 53, "r53">, DwarfRegNum<[53]>;
|
||||
def r54 : GR< 54, "r54">, DwarfRegNum<[54]>;
|
||||
def r55 : GR< 55, "r55">, DwarfRegNum<[55]>;
|
||||
def r56 : GR< 56, "r56">, DwarfRegNum<[56]>;
|
||||
def r57 : GR< 57, "r57">, DwarfRegNum<[57]>;
|
||||
def r58 : GR< 58, "r58">, DwarfRegNum<[58]>;
|
||||
def r59 : GR< 59, "r59">, DwarfRegNum<[59]>;
|
||||
def r60 : GR< 60, "r60">, DwarfRegNum<[60]>;
|
||||
def r61 : GR< 61, "r61">, DwarfRegNum<[61]>;
|
||||
def r62 : GR< 62, "r62">, DwarfRegNum<[62]>;
|
||||
def r63 : GR< 63, "r63">, DwarfRegNum<[63]>;
|
||||
def r64 : GR< 64, "r64">, DwarfRegNum<[64]>;
|
||||
def r65 : GR< 65, "r65">, DwarfRegNum<[65]>;
|
||||
def r66 : GR< 66, "r66">, DwarfRegNum<[66]>;
|
||||
def r67 : GR< 67, "r67">, DwarfRegNum<[67]>;
|
||||
def r68 : GR< 68, "r68">, DwarfRegNum<[68]>;
|
||||
def r69 : GR< 69, "r69">, DwarfRegNum<[69]>;
|
||||
def r70 : GR< 70, "r70">, DwarfRegNum<[70]>;
|
||||
def r71 : GR< 71, "r71">, DwarfRegNum<[71]>;
|
||||
def r72 : GR< 72, "r72">, DwarfRegNum<[72]>;
|
||||
def r73 : GR< 73, "r73">, DwarfRegNum<[73]>;
|
||||
def r74 : GR< 74, "r74">, DwarfRegNum<[74]>;
|
||||
def r75 : GR< 75, "r75">, DwarfRegNum<[75]>;
|
||||
def r76 : GR< 76, "r76">, DwarfRegNum<[76]>;
|
||||
def r77 : GR< 77, "r77">, DwarfRegNum<[77]>;
|
||||
def r78 : GR< 78, "r78">, DwarfRegNum<[78]>;
|
||||
def r79 : GR< 79, "r79">, DwarfRegNum<[79]>;
|
||||
def r80 : GR< 80, "r80">, DwarfRegNum<[80]>;
|
||||
def r81 : GR< 81, "r81">, DwarfRegNum<[81]>;
|
||||
def r82 : GR< 82, "r82">, DwarfRegNum<[82]>;
|
||||
def r83 : GR< 83, "r83">, DwarfRegNum<[83]>;
|
||||
def r84 : GR< 84, "r84">, DwarfRegNum<[84]>;
|
||||
def r85 : GR< 85, "r85">, DwarfRegNum<[85]>;
|
||||
def r86 : GR< 86, "r86">, DwarfRegNum<[86]>;
|
||||
def r87 : GR< 87, "r87">, DwarfRegNum<[87]>;
|
||||
def r88 : GR< 88, "r88">, DwarfRegNum<[88]>;
|
||||
def r89 : GR< 89, "r89">, DwarfRegNum<[89]>;
|
||||
def r90 : GR< 90, "r90">, DwarfRegNum<[90]>;
|
||||
def r91 : GR< 91, "r91">, DwarfRegNum<[91]>;
|
||||
def r92 : GR< 92, "r92">, DwarfRegNum<[92]>;
|
||||
def r93 : GR< 93, "r93">, DwarfRegNum<[93]>;
|
||||
def r94 : GR< 94, "r94">, DwarfRegNum<[94]>;
|
||||
def r95 : GR< 95, "r95">, DwarfRegNum<[95]>;
|
||||
def r96 : GR< 96, "r96">, DwarfRegNum<[96]>;
|
||||
def r97 : GR< 97, "r97">, DwarfRegNum<[97]>;
|
||||
def r98 : GR< 98, "r98">, DwarfRegNum<[98]>;
|
||||
def r99 : GR< 99, "r99">, DwarfRegNum<[99]>;
|
||||
def r100 : GR< 100, "r100">, DwarfRegNum<[100]>;
|
||||
def r101 : GR< 101, "r101">, DwarfRegNum<[101]>;
|
||||
def r102 : GR< 102, "r102">, DwarfRegNum<[102]>;
|
||||
def r103 : GR< 103, "r103">, DwarfRegNum<[103]>;
|
||||
def r104 : GR< 104, "r104">, DwarfRegNum<[104]>;
|
||||
def r105 : GR< 105, "r105">, DwarfRegNum<[105]>;
|
||||
def r106 : GR< 106, "r106">, DwarfRegNum<[106]>;
|
||||
def r107 : GR< 107, "r107">, DwarfRegNum<[107]>;
|
||||
def r108 : GR< 108, "r108">, DwarfRegNum<[108]>;
|
||||
def r109 : GR< 109, "r109">, DwarfRegNum<[109]>;
|
||||
def r110 : GR< 110, "r110">, DwarfRegNum<[110]>;
|
||||
def r111 : GR< 111, "r111">, DwarfRegNum<[111]>;
|
||||
def r112 : GR< 112, "r112">, DwarfRegNum<[112]>;
|
||||
def r113 : GR< 113, "r113">, DwarfRegNum<[113]>;
|
||||
def r114 : GR< 114, "r114">, DwarfRegNum<[114]>;
|
||||
def r115 : GR< 115, "r115">, DwarfRegNum<[115]>;
|
||||
def r116 : GR< 116, "r116">, DwarfRegNum<[116]>;
|
||||
def r117 : GR< 117, "r117">, DwarfRegNum<[117]>;
|
||||
def r118 : GR< 118, "r118">, DwarfRegNum<[118]>;
|
||||
def r119 : GR< 119, "r119">, DwarfRegNum<[119]>;
|
||||
def r120 : GR< 120, "r120">, DwarfRegNum<[120]>;
|
||||
def r121 : GR< 121, "r121">, DwarfRegNum<[121]>;
|
||||
def r122 : GR< 122, "r122">, DwarfRegNum<[122]>;
|
||||
def r123 : GR< 123, "r123">, DwarfRegNum<[123]>;
|
||||
def r124 : GR< 124, "r124">, DwarfRegNum<[124]>;
|
||||
def r125 : GR< 125, "r125">, DwarfRegNum<[125]>;
|
||||
def r126 : GR< 126, "r126">, DwarfRegNum<[126]>;
|
||||
def r127 : GR< 127, "r127">, DwarfRegNum<[127]>;
|
||||
|
||||
/* floating-point registers */
|
||||
def F0 : FP< 0, "f0">, DwarfRegNum<[128]>;
|
||||
def F1 : FP< 1, "f1">, DwarfRegNum<[129]>;
|
||||
def F2 : FP< 2, "f2">, DwarfRegNum<[130]>;
|
||||
def F3 : FP< 3, "f3">, DwarfRegNum<[131]>;
|
||||
def F4 : FP< 4, "f4">, DwarfRegNum<[132]>;
|
||||
def F5 : FP< 5, "f5">, DwarfRegNum<[133]>;
|
||||
def F6 : FP< 6, "f6">, DwarfRegNum<[134]>;
|
||||
def F7 : FP< 7, "f7">, DwarfRegNum<[135]>;
|
||||
def F8 : FP< 8, "f8">, DwarfRegNum<[136]>;
|
||||
def F9 : FP< 9, "f9">, DwarfRegNum<[137]>;
|
||||
def F10 : FP< 10, "f10">, DwarfRegNum<[138]>;
|
||||
def F11 : FP< 11, "f11">, DwarfRegNum<[139]>;
|
||||
def F12 : FP< 12, "f12">, DwarfRegNum<[140]>;
|
||||
def F13 : FP< 13, "f13">, DwarfRegNum<[141]>;
|
||||
def F14 : FP< 14, "f14">, DwarfRegNum<[142]>;
|
||||
def F15 : FP< 15, "f15">, DwarfRegNum<[143]>;
|
||||
def F16 : FP< 16, "f16">, DwarfRegNum<[144]>;
|
||||
def F17 : FP< 17, "f17">, DwarfRegNum<[145]>;
|
||||
def F18 : FP< 18, "f18">, DwarfRegNum<[146]>;
|
||||
def F19 : FP< 19, "f19">, DwarfRegNum<[147]>;
|
||||
def F20 : FP< 20, "f20">, DwarfRegNum<[148]>;
|
||||
def F21 : FP< 21, "f21">, DwarfRegNum<[149]>;
|
||||
def F22 : FP< 22, "f22">, DwarfRegNum<[150]>;
|
||||
def F23 : FP< 23, "f23">, DwarfRegNum<[151]>;
|
||||
def F24 : FP< 24, "f24">, DwarfRegNum<[152]>;
|
||||
def F25 : FP< 25, "f25">, DwarfRegNum<[153]>;
|
||||
def F26 : FP< 26, "f26">, DwarfRegNum<[154]>;
|
||||
def F27 : FP< 27, "f27">, DwarfRegNum<[155]>;
|
||||
def F28 : FP< 28, "f28">, DwarfRegNum<[156]>;
|
||||
def F29 : FP< 29, "f29">, DwarfRegNum<[157]>;
|
||||
def F30 : FP< 30, "f30">, DwarfRegNum<[158]>;
|
||||
def F31 : FP< 31, "f31">, DwarfRegNum<[159]>;
|
||||
def F32 : FP< 32, "f32">, DwarfRegNum<[160]>;
|
||||
def F33 : FP< 33, "f33">, DwarfRegNum<[161]>;
|
||||
def F34 : FP< 34, "f34">, DwarfRegNum<[162]>;
|
||||
def F35 : FP< 35, "f35">, DwarfRegNum<[163]>;
|
||||
def F36 : FP< 36, "f36">, DwarfRegNum<[164]>;
|
||||
def F37 : FP< 37, "f37">, DwarfRegNum<[165]>;
|
||||
def F38 : FP< 38, "f38">, DwarfRegNum<[166]>;
|
||||
def F39 : FP< 39, "f39">, DwarfRegNum<[167]>;
|
||||
def F40 : FP< 40, "f40">, DwarfRegNum<[168]>;
|
||||
def F41 : FP< 41, "f41">, DwarfRegNum<[169]>;
|
||||
def F42 : FP< 42, "f42">, DwarfRegNum<[170]>;
|
||||
def F43 : FP< 43, "f43">, DwarfRegNum<[171]>;
|
||||
def F44 : FP< 44, "f44">, DwarfRegNum<[172]>;
|
||||
def F45 : FP< 45, "f45">, DwarfRegNum<[173]>;
|
||||
def F46 : FP< 46, "f46">, DwarfRegNum<[174]>;
|
||||
def F47 : FP< 47, "f47">, DwarfRegNum<[175]>;
|
||||
def F48 : FP< 48, "f48">, DwarfRegNum<[176]>;
|
||||
def F49 : FP< 49, "f49">, DwarfRegNum<[177]>;
|
||||
def F50 : FP< 50, "f50">, DwarfRegNum<[178]>;
|
||||
def F51 : FP< 51, "f51">, DwarfRegNum<[179]>;
|
||||
def F52 : FP< 52, "f52">, DwarfRegNum<[180]>;
|
||||
def F53 : FP< 53, "f53">, DwarfRegNum<[181]>;
|
||||
def F54 : FP< 54, "f54">, DwarfRegNum<[182]>;
|
||||
def F55 : FP< 55, "f55">, DwarfRegNum<[183]>;
|
||||
def F56 : FP< 56, "f56">, DwarfRegNum<[184]>;
|
||||
def F57 : FP< 57, "f57">, DwarfRegNum<[185]>;
|
||||
def F58 : FP< 58, "f58">, DwarfRegNum<[186]>;
|
||||
def F59 : FP< 59, "f59">, DwarfRegNum<[187]>;
|
||||
def F60 : FP< 60, "f60">, DwarfRegNum<[188]>;
|
||||
def F61 : FP< 61, "f61">, DwarfRegNum<[189]>;
|
||||
def F62 : FP< 62, "f62">, DwarfRegNum<[190]>;
|
||||
def F63 : FP< 63, "f63">, DwarfRegNum<[191]>;
|
||||
def F64 : FP< 64, "f64">, DwarfRegNum<[192]>;
|
||||
def F65 : FP< 65, "f65">, DwarfRegNum<[193]>;
|
||||
def F66 : FP< 66, "f66">, DwarfRegNum<[194]>;
|
||||
def F67 : FP< 67, "f67">, DwarfRegNum<[195]>;
|
||||
def F68 : FP< 68, "f68">, DwarfRegNum<[196]>;
|
||||
def F69 : FP< 69, "f69">, DwarfRegNum<[197]>;
|
||||
def F70 : FP< 70, "f70">, DwarfRegNum<[198]>;
|
||||
def F71 : FP< 71, "f71">, DwarfRegNum<[199]>;
|
||||
def F72 : FP< 72, "f72">, DwarfRegNum<[200]>;
|
||||
def F73 : FP< 73, "f73">, DwarfRegNum<[201]>;
|
||||
def F74 : FP< 74, "f74">, DwarfRegNum<[202]>;
|
||||
def F75 : FP< 75, "f75">, DwarfRegNum<[203]>;
|
||||
def F76 : FP< 76, "f76">, DwarfRegNum<[204]>;
|
||||
def F77 : FP< 77, "f77">, DwarfRegNum<[205]>;
|
||||
def F78 : FP< 78, "f78">, DwarfRegNum<[206]>;
|
||||
def F79 : FP< 79, "f79">, DwarfRegNum<[207]>;
|
||||
def F80 : FP< 80, "f80">, DwarfRegNum<[208]>;
|
||||
def F81 : FP< 81, "f81">, DwarfRegNum<[209]>;
|
||||
def F82 : FP< 82, "f82">, DwarfRegNum<[210]>;
|
||||
def F83 : FP< 83, "f83">, DwarfRegNum<[211]>;
|
||||
def F84 : FP< 84, "f84">, DwarfRegNum<[212]>;
|
||||
def F85 : FP< 85, "f85">, DwarfRegNum<[213]>;
|
||||
def F86 : FP< 86, "f86">, DwarfRegNum<[214]>;
|
||||
def F87 : FP< 87, "f87">, DwarfRegNum<[215]>;
|
||||
def F88 : FP< 88, "f88">, DwarfRegNum<[216]>;
|
||||
def F89 : FP< 89, "f89">, DwarfRegNum<[217]>;
|
||||
def F90 : FP< 90, "f90">, DwarfRegNum<[218]>;
|
||||
def F91 : FP< 91, "f91">, DwarfRegNum<[219]>;
|
||||
def F92 : FP< 92, "f92">, DwarfRegNum<[220]>;
|
||||
def F93 : FP< 93, "f93">, DwarfRegNum<[221]>;
|
||||
def F94 : FP< 94, "f94">, DwarfRegNum<[222]>;
|
||||
def F95 : FP< 95, "f95">, DwarfRegNum<[223]>;
|
||||
def F96 : FP< 96, "f96">, DwarfRegNum<[224]>;
|
||||
def F97 : FP< 97, "f97">, DwarfRegNum<[225]>;
|
||||
def F98 : FP< 98, "f98">, DwarfRegNum<[226]>;
|
||||
def F99 : FP< 99, "f99">, DwarfRegNum<[227]>;
|
||||
def F100 : FP< 100, "f100">, DwarfRegNum<[228]>;
|
||||
def F101 : FP< 101, "f101">, DwarfRegNum<[229]>;
|
||||
def F102 : FP< 102, "f102">, DwarfRegNum<[230]>;
|
||||
def F103 : FP< 103, "f103">, DwarfRegNum<[231]>;
|
||||
def F104 : FP< 104, "f104">, DwarfRegNum<[232]>;
|
||||
def F105 : FP< 105, "f105">, DwarfRegNum<[233]>;
|
||||
def F106 : FP< 106, "f106">, DwarfRegNum<[234]>;
|
||||
def F107 : FP< 107, "f107">, DwarfRegNum<[235]>;
|
||||
def F108 : FP< 108, "f108">, DwarfRegNum<[236]>;
|
||||
def F109 : FP< 109, "f109">, DwarfRegNum<[237]>;
|
||||
def F110 : FP< 110, "f110">, DwarfRegNum<[238]>;
|
||||
def F111 : FP< 111, "f111">, DwarfRegNum<[239]>;
|
||||
def F112 : FP< 112, "f112">, DwarfRegNum<[240]>;
|
||||
def F113 : FP< 113, "f113">, DwarfRegNum<[241]>;
|
||||
def F114 : FP< 114, "f114">, DwarfRegNum<[242]>;
|
||||
def F115 : FP< 115, "f115">, DwarfRegNum<[243]>;
|
||||
def F116 : FP< 116, "f116">, DwarfRegNum<[244]>;
|
||||
def F117 : FP< 117, "f117">, DwarfRegNum<[245]>;
|
||||
def F118 : FP< 118, "f118">, DwarfRegNum<[246]>;
|
||||
def F119 : FP< 119, "f119">, DwarfRegNum<[247]>;
|
||||
def F120 : FP< 120, "f120">, DwarfRegNum<[248]>;
|
||||
def F121 : FP< 121, "f121">, DwarfRegNum<[249]>;
|
||||
def F122 : FP< 122, "f122">, DwarfRegNum<[250]>;
|
||||
def F123 : FP< 123, "f123">, DwarfRegNum<[251]>;
|
||||
def F124 : FP< 124, "f124">, DwarfRegNum<[252]>;
|
||||
def F125 : FP< 125, "f125">, DwarfRegNum<[253]>;
|
||||
def F126 : FP< 126, "f126">, DwarfRegNum<[254]>;
|
||||
def F127 : FP< 127, "f127">, DwarfRegNum<[255]>;
|
||||
|
||||
/* predicate registers */
|
||||
def p0 : PR< 0, "p0">, DwarfRegNum<[256]>;
|
||||
def p1 : PR< 1, "p1">, DwarfRegNum<[257]>;
|
||||
def p2 : PR< 2, "p2">, DwarfRegNum<[258]>;
|
||||
def p3 : PR< 3, "p3">, DwarfRegNum<[259]>;
|
||||
def p4 : PR< 4, "p4">, DwarfRegNum<[260]>;
|
||||
def p5 : PR< 5, "p5">, DwarfRegNum<[261]>;
|
||||
def p6 : PR< 6, "p6">, DwarfRegNum<[262]>;
|
||||
def p7 : PR< 7, "p7">, DwarfRegNum<[263]>;
|
||||
def p8 : PR< 8, "p8">, DwarfRegNum<[264]>;
|
||||
def p9 : PR< 9, "p9">, DwarfRegNum<[265]>;
|
||||
def p10 : PR< 10, "p10">, DwarfRegNum<[266]>;
|
||||
def p11 : PR< 11, "p11">, DwarfRegNum<[267]>;
|
||||
def p12 : PR< 12, "p12">, DwarfRegNum<[268]>;
|
||||
def p13 : PR< 13, "p13">, DwarfRegNum<[269]>;
|
||||
def p14 : PR< 14, "p14">, DwarfRegNum<[270]>;
|
||||
def p15 : PR< 15, "p15">, DwarfRegNum<[271]>;
|
||||
def p16 : PR< 16, "p16">, DwarfRegNum<[272]>;
|
||||
def p17 : PR< 17, "p17">, DwarfRegNum<[273]>;
|
||||
def p18 : PR< 18, "p18">, DwarfRegNum<[274]>;
|
||||
def p19 : PR< 19, "p19">, DwarfRegNum<[275]>;
|
||||
def p20 : PR< 20, "p20">, DwarfRegNum<[276]>;
|
||||
def p21 : PR< 21, "p21">, DwarfRegNum<[277]>;
|
||||
def p22 : PR< 22, "p22">, DwarfRegNum<[278]>;
|
||||
def p23 : PR< 23, "p23">, DwarfRegNum<[279]>;
|
||||
def p24 : PR< 24, "p24">, DwarfRegNum<[280]>;
|
||||
def p25 : PR< 25, "p25">, DwarfRegNum<[281]>;
|
||||
def p26 : PR< 26, "p26">, DwarfRegNum<[282]>;
|
||||
def p27 : PR< 27, "p27">, DwarfRegNum<[283]>;
|
||||
def p28 : PR< 28, "p28">, DwarfRegNum<[284]>;
|
||||
def p29 : PR< 29, "p29">, DwarfRegNum<[285]>;
|
||||
def p30 : PR< 30, "p30">, DwarfRegNum<[286]>;
|
||||
def p31 : PR< 31, "p31">, DwarfRegNum<[287]>;
|
||||
def p32 : PR< 32, "p32">, DwarfRegNum<[288]>;
|
||||
def p33 : PR< 33, "p33">, DwarfRegNum<[289]>;
|
||||
def p34 : PR< 34, "p34">, DwarfRegNum<[290]>;
|
||||
def p35 : PR< 35, "p35">, DwarfRegNum<[291]>;
|
||||
def p36 : PR< 36, "p36">, DwarfRegNum<[292]>;
|
||||
def p37 : PR< 37, "p37">, DwarfRegNum<[293]>;
|
||||
def p38 : PR< 38, "p38">, DwarfRegNum<[294]>;
|
||||
def p39 : PR< 39, "p39">, DwarfRegNum<[295]>;
|
||||
def p40 : PR< 40, "p40">, DwarfRegNum<[296]>;
|
||||
def p41 : PR< 41, "p41">, DwarfRegNum<[297]>;
|
||||
def p42 : PR< 42, "p42">, DwarfRegNum<[298]>;
|
||||
def p43 : PR< 43, "p43">, DwarfRegNum<[299]>;
|
||||
def p44 : PR< 44, "p44">, DwarfRegNum<[300]>;
|
||||
def p45 : PR< 45, "p45">, DwarfRegNum<[301]>;
|
||||
def p46 : PR< 46, "p46">, DwarfRegNum<[302]>;
|
||||
def p47 : PR< 47, "p47">, DwarfRegNum<[303]>;
|
||||
def p48 : PR< 48, "p48">, DwarfRegNum<[304]>;
|
||||
def p49 : PR< 49, "p49">, DwarfRegNum<[305]>;
|
||||
def p50 : PR< 50, "p50">, DwarfRegNum<[306]>;
|
||||
def p51 : PR< 51, "p51">, DwarfRegNum<[307]>;
|
||||
def p52 : PR< 52, "p52">, DwarfRegNum<[308]>;
|
||||
def p53 : PR< 53, "p53">, DwarfRegNum<[309]>;
|
||||
def p54 : PR< 54, "p54">, DwarfRegNum<[310]>;
|
||||
def p55 : PR< 55, "p55">, DwarfRegNum<[311]>;
|
||||
def p56 : PR< 56, "p56">, DwarfRegNum<[312]>;
|
||||
def p57 : PR< 57, "p57">, DwarfRegNum<[313]>;
|
||||
def p58 : PR< 58, "p58">, DwarfRegNum<[314]>;
|
||||
def p59 : PR< 59, "p59">, DwarfRegNum<[315]>;
|
||||
def p60 : PR< 60, "p60">, DwarfRegNum<[316]>;
|
||||
def p61 : PR< 61, "p61">, DwarfRegNum<[317]>;
|
||||
def p62 : PR< 62, "p62">, DwarfRegNum<[318]>;
|
||||
def p63 : PR< 63, "p63">, DwarfRegNum<[319]>;
|
||||
|
||||
// XXX : this is temporary, we'll eventually have the output registers
|
||||
// in the general purpose register class too?
|
||||
def out0 : GR<0, "out0">, DwarfRegNum<[120]>;
|
||||
def out1 : GR<1, "out1">, DwarfRegNum<[121]>;
|
||||
def out2 : GR<2, "out2">, DwarfRegNum<[122]>;
|
||||
def out3 : GR<3, "out3">, DwarfRegNum<[123]>;
|
||||
def out4 : GR<4, "out4">, DwarfRegNum<[124]>;
|
||||
def out5 : GR<5, "out5">, DwarfRegNum<[125]>;
|
||||
def out6 : GR<6, "out6">, DwarfRegNum<[126]>;
|
||||
def out7 : GR<7, "out7">, DwarfRegNum<[127]>;
|
||||
|
||||
// application (special) registers:
|
||||
|
||||
// "previous function state" application register
|
||||
def AR_PFS : GR<0, "ar.pfs">, DwarfRegNum<[331]>;
|
||||
|
||||
// "return pointer" (this is really branch register b0)
|
||||
def rp : GR<0, "rp">, DwarfRegNum<[-1]>;
|
||||
|
||||
// branch reg 6
|
||||
def B6 : GR<0, "b6">, DwarfRegNum<[326]>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Register Class Definitions... now that we have all of the pieces, define the
|
||||
// top-level register classes. The order specified in the register list is
|
||||
// implicitly defined to be the register allocation order.
|
||||
//
|
||||
|
||||
// these are the scratch (+stacked) general registers
|
||||
// FIXME/XXX we also reserve a frame pointer (r5)
|
||||
// FIXME/XXX we also reserve r2 for spilling/filling predicates
|
||||
// in IA64RegisterInfo.cpp
|
||||
// FIXME/XXX we also reserve r22 for calculating addresses
|
||||
// in IA64RegisterInfo.cpp
|
||||
|
||||
def GR : RegisterClass<"IA64", [i64], 64,
|
||||
[
|
||||
|
||||
//FIXME!: for both readability and performance, we don't want the out
|
||||
// registers to be the first ones allocated
|
||||
|
||||
out7, out6, out5, out4, out3, out2, out1, out0,
|
||||
r3, r8, r9, r10, r11, r14, r15,
|
||||
r16, r17, r18, r19, r20, r21, r23,
|
||||
r24, r25, r26, r27, r28, r29, r30, r31,
|
||||
r32, r33, r34, r35, r36, r37, r38, r39,
|
||||
r40, r41, r42, r43, r44, r45, r46, r47,
|
||||
r48, r49, r50, r51, r52, r53, r54, r55,
|
||||
r56, r57, r58, r59, r60, r61, r62, r63,
|
||||
r64, r65, r66, r67, r68, r69, r70, r71,
|
||||
r72, r73, r74, r75, r76, r77, r78, r79,
|
||||
r80, r81, r82, r83, r84, r85, r86, r87,
|
||||
r88, r89, r90, r91, r92, r93, r94, r95,
|
||||
r96, r97, r98, r99, r100, r101, r102, r103,
|
||||
r104, r105, r106, r107, r108, r109, r110, r111,
|
||||
r112, r113, r114, r115, r116, r117, r118, r119,
|
||||
// last 17 are special (look down)
|
||||
r120, r121, r122, r123, r124, r125, r126, r127,
|
||||
r0, r1, r2, r5, r12, r13, r22, rp, AR_PFS]>
|
||||
{
|
||||
let MethodProtos = [{
|
||||
iterator allocation_order_begin(const MachineFunction &MF) const;
|
||||
iterator allocation_order_end(const MachineFunction &MF) const;
|
||||
}];
|
||||
let MethodBodies = [{
|
||||
GRClass::iterator
|
||||
GRClass::allocation_order_begin(const MachineFunction &MF) const {
|
||||
// hide the 8 out? registers appropriately:
|
||||
return begin()+(8-(MF.getInfo<IA64FunctionInfo>()->outRegsUsed));
|
||||
}
|
||||
|
||||
GRClass::iterator
|
||||
GRClass::allocation_order_end(const MachineFunction &MF) const {
|
||||
// the 9 special registers r0,r1,r2,r5,r12,r13 etc
|
||||
int numReservedRegs=9;
|
||||
|
||||
// we also can't allocate registers for use as locals if they're already
|
||||
// required as 'out' registers
|
||||
numReservedRegs+=MF.getInfo<IA64FunctionInfo>()->outRegsUsed;
|
||||
return end()-numReservedRegs; // hide registers appropriately
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
// these are the scratch (+stacked) FP registers
|
||||
|
||||
def FP : RegisterClass<"IA64", [f64], 64,
|
||||
[F6, F7,
|
||||
F8, F9, F10, F11, F12, F13, F14, F15,
|
||||
F32, F33, F34, F35, F36, F37, F38, F39,
|
||||
F40, F41, F42, F43, F44, F45, F46, F47,
|
||||
F48, F49, F50, F51, F52, F53, F54, F55,
|
||||
F56, F57, F58, F59, F60, F61, F62, F63,
|
||||
F64, F65, F66, F67, F68, F69, F70, F71,
|
||||
F72, F73, F74, F75, F76, F77, F78, F79,
|
||||
F80, F81, F82, F83, F84, F85, F86, F87,
|
||||
F88, F89, F90, F91, F92, F93, F94, F95,
|
||||
F96, F97, F98, F99, F100, F101, F102, F103,
|
||||
F104, F105, F106, F107, F108, F109, F110, F111,
|
||||
F112, F113, F114, F115, F116, F117, F118, F119,
|
||||
F120, F121, F122, F123, F124, F125, F126, F127,
|
||||
F0, F1]> // these last two are hidden
|
||||
{
|
||||
// the 128s here are to make stf.spill/ldf.fill happy,
|
||||
// when storing full (82-bit) FP regs to stack slots
|
||||
// we need to 16-byte align
|
||||
let Size=128;
|
||||
let Alignment=128;
|
||||
|
||||
let MethodProtos = [{
|
||||
iterator allocation_order_begin(const MachineFunction &MF) const;
|
||||
iterator allocation_order_end(const MachineFunction &MF) const;
|
||||
}];
|
||||
let MethodBodies = [{
|
||||
FPClass::iterator
|
||||
FPClass::allocation_order_begin(const MachineFunction &MF) const {
|
||||
return begin(); // we don't hide any FP regs from the start
|
||||
}
|
||||
|
||||
FPClass::iterator
|
||||
FPClass::allocation_order_end(const MachineFunction &MF) const {
|
||||
return end()-2; // we hide regs F0, F1 from the end
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
// these are the predicate registers, p0 (1/TRUE) is not here
|
||||
def PR : RegisterClass<"IA64", [i1], 64,
|
||||
|
||||
// for now, let's be wimps and only have the scratch predicate regs
|
||||
[p6, p7, p8, p9, p10, p11, p12, p13, p14, p15]> {
|
||||
let Size = 64;
|
||||
}
|
||||
|
||||
/*
|
||||
[p1, p2, p3, p4, p5, p6, p7,
|
||||
p8, p9, p10, p11, p12, p13, p14, p15,
|
||||
p16, p17, p18, p19, p20, p21, p22, p23,
|
||||
p24, p25, p26, p27, p28, p29, p30, p31,
|
||||
p32, p33, p34, p35, p36, p37, p38, p39,
|
||||
p40, p41, p42, p43, p44, p45, p46, p47,
|
||||
p48, p49, p50, p51, p52, p53, p54, p55,
|
||||
p56, p57, p58, p59, p60, p61, p62, p63]>;
|
||||
*/
|
@ -1,18 +0,0 @@
|
||||
//===-- IA64Subtarget.cpp - IA64 Subtarget Information ----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the IA64 specific subclass of TargetSubtarget.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define DEBUG_TYPE "subtarget"
|
||||
#include "IA64Subtarget.h"
|
||||
using namespace llvm;
|
||||
|
||||
IA64Subtarget::IA64Subtarget() {}
|
@ -1,28 +0,0 @@
|
||||
//====---- IA64Subtarget.h - Define Subtarget for the IA64 -----*- C++ -*--===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file declares the IA64 specific subclass of TargetSubtarget.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef IA64SUBTARGET_H
|
||||
#define IA64SUBTARGET_H
|
||||
|
||||
#include "llvm/Target/TargetSubtarget.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class IA64Subtarget : public TargetSubtarget {
|
||||
public:
|
||||
IA64Subtarget();
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
@ -1,44 +0,0 @@
|
||||
//===-- IA64TargetAsmInfo.cpp - IA64 asm properties -------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the declarations of the IA64TargetAsmInfo properties.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "IA64TargetAsmInfo.h"
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
IA64TargetAsmInfo::IA64TargetAsmInfo(const TargetMachine &TM):
|
||||
ELFTargetAsmInfo(TM) {
|
||||
CommentString = "//";
|
||||
Data8bitsDirective = "\tdata1\t"; // FIXME: check that we are
|
||||
Data16bitsDirective = "\tdata2.ua\t"; // disabling auto-alignment
|
||||
Data32bitsDirective = "\tdata4.ua\t"; // properly
|
||||
Data64bitsDirective = "\tdata8.ua\t";
|
||||
ZeroDirective = "\t.skip\t";
|
||||
AsciiDirective = "\tstring\t";
|
||||
|
||||
GlobalVarAddrPrefix="";
|
||||
GlobalVarAddrSuffix="";
|
||||
FunctionAddrPrefix="@fptr(";
|
||||
FunctionAddrSuffix=")";
|
||||
|
||||
// FIXME: would be nice to have rodata (no 'w') when appropriate?
|
||||
ConstantPoolSection = "\n\t.section .data, \"aw\", \"progbits\"\n";
|
||||
}
|
||||
|
||||
unsigned IA64TargetAsmInfo::RelocBehaviour() const {
|
||||
return (TM.getRelocationModel() != Reloc::Static ?
|
||||
Reloc::LocalOrGlobal : Reloc::Global);
|
||||
}
|
||||
|
||||
// FIXME: Support small data/bss/rodata sections someday.
|
@ -1,33 +0,0 @@
|
||||
//=====-- IA64TargetAsmInfo.h - IA64 asm properties -----------*- C++ -*--====//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the declaration of the IA64TargetAsmInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef IA64TARGETASMINFO_H
|
||||
#define IA64TARGETASMINFO_H
|
||||
|
||||
#include "llvm/Target/TargetAsmInfo.h"
|
||||
#include "llvm/Target/ELFTargetAsmInfo.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
// Forward declaration.
|
||||
class TargetMachine;
|
||||
|
||||
struct IA64TargetAsmInfo : public ELFTargetAsmInfo {
|
||||
explicit IA64TargetAsmInfo(const TargetMachine &TM);
|
||||
virtual unsigned RelocBehaviour() const;
|
||||
};
|
||||
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
@ -1,97 +0,0 @@
|
||||
//===-- IA64TargetMachine.cpp - Define TargetMachine for IA64 -------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the IA64 specific subclass of TargetMachine.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "IA64TargetAsmInfo.h"
|
||||
#include "IA64TargetMachine.h"
|
||||
#include "IA64.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/PassManager.h"
|
||||
#include "llvm/Target/TargetMachineRegistry.h"
|
||||
using namespace llvm;
|
||||
|
||||
// Register the target
|
||||
static RegisterTarget<IA64TargetMachine> X("ia64",
|
||||
"IA-64 (Itanium) [experimental]");
|
||||
|
||||
// No assembler printer by default
|
||||
IA64TargetMachine::AsmPrinterCtorFn IA64TargetMachine::AsmPrinterCtor = 0;
|
||||
|
||||
// Force static initialization.
|
||||
extern "C" void LLVMInitializeIA64Target() { }
|
||||
|
||||
const TargetAsmInfo *IA64TargetMachine::createTargetAsmInfo() const {
|
||||
return new IA64TargetAsmInfo(*this);
|
||||
}
|
||||
|
||||
unsigned IA64TargetMachine::getModuleMatchQuality(const Module &M) {
|
||||
// we match [iI][aA]*64
|
||||
bool seenIA64=false;
|
||||
std::string TT = M.getTargetTriple();
|
||||
|
||||
if (TT.size() >= 4) {
|
||||
if( (TT[0]=='i' || TT[0]=='I') &&
|
||||
(TT[1]=='a' || TT[1]=='A') ) {
|
||||
for(unsigned int i=2; i<(TT.size()-1); i++)
|
||||
if(TT[i]=='6' && TT[i+1]=='4')
|
||||
seenIA64=true;
|
||||
}
|
||||
|
||||
if (seenIA64)
|
||||
return 20; // strong match
|
||||
}
|
||||
// If the target triple is something non-ia64, we don't match.
|
||||
if (!TT.empty()) return 0;
|
||||
|
||||
#if defined(__ia64__) || defined(__IA64__)
|
||||
return 5;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// IA64TargetMachine ctor - Create an LP64 architecture model
|
||||
///
|
||||
IA64TargetMachine::IA64TargetMachine(const Module &M, const std::string &FS)
|
||||
: DataLayout("e-f80:128:128"),
|
||||
FrameInfo(TargetFrameInfo::StackGrowsDown, 16, 0),
|
||||
TLInfo(*this) { // FIXME? check this stuff
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Pass Pipeline Configuration
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
bool IA64TargetMachine::addInstSelector(PassManagerBase &PM,
|
||||
CodeGenOpt::Level OptLevel) {
|
||||
PM.add(createIA64DAGToDAGInstructionSelector(*this));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IA64TargetMachine::addPreEmitPass(PassManagerBase &PM,
|
||||
CodeGenOpt::Level OptLevel) {
|
||||
// Make sure everything is bundled happily
|
||||
PM.add(createIA64BundlingPass(*this));
|
||||
return true;
|
||||
}
|
||||
bool IA64TargetMachine::addAssemblyEmitter(PassManagerBase &PM,
|
||||
CodeGenOpt::Level OptLevel,
|
||||
bool Verbose,
|
||||
raw_ostream &Out) {
|
||||
// Output assembly language.
|
||||
assert(AsmPrinterCtor && "AsmPrinter was not linked in");
|
||||
if (AsmPrinterCtor)
|
||||
PM.add(AsmPrinterCtor(Out, *this, Verbose));
|
||||
return false;
|
||||
}
|
||||
|
@ -1,75 +0,0 @@
|
||||
//===-- IA64TargetMachine.h - Define TargetMachine for IA64 ---*- C++ -*---===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file declares the IA64 specific subclass of TargetMachine.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TARGET_IA64TARGETMACHINE_H
|
||||
#define LLVM_TARGET_IA64TARGETMACHINE_H
|
||||
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Target/TargetData.h"
|
||||
#include "llvm/Target/TargetFrameInfo.h"
|
||||
#include "IA64InstrInfo.h"
|
||||
#include "IA64ISelLowering.h"
|
||||
#include "IA64Subtarget.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class IA64TargetMachine : public LLVMTargetMachine {
|
||||
IA64Subtarget Subtarget;
|
||||
const TargetData DataLayout; // Calculates type size & alignment
|
||||
IA64InstrInfo InstrInfo;
|
||||
TargetFrameInfo FrameInfo;
|
||||
//IA64JITInfo JITInfo;
|
||||
IA64TargetLowering TLInfo;
|
||||
|
||||
protected:
|
||||
virtual const TargetAsmInfo *createTargetAsmInfo() const;
|
||||
|
||||
// To avoid having target depend on the asmprinter stuff libraries, asmprinter
|
||||
// set this functions to ctor pointer at startup time if they are linked in.
|
||||
typedef FunctionPass *(*AsmPrinterCtorFn)(raw_ostream &o,
|
||||
IA64TargetMachine &tm,
|
||||
bool verbose);
|
||||
static AsmPrinterCtorFn AsmPrinterCtor;
|
||||
|
||||
public:
|
||||
IA64TargetMachine(const Module &M, const std::string &FS);
|
||||
|
||||
virtual const IA64InstrInfo *getInstrInfo() const { return &InstrInfo; }
|
||||
virtual const TargetFrameInfo *getFrameInfo() const { return &FrameInfo; }
|
||||
virtual const IA64Subtarget *getSubtargetImpl() const { return &Subtarget; }
|
||||
virtual IA64TargetLowering *getTargetLowering() const {
|
||||
return const_cast<IA64TargetLowering*>(&TLInfo);
|
||||
}
|
||||
virtual const IA64RegisterInfo *getRegisterInfo() const {
|
||||
return &InstrInfo.getRegisterInfo();
|
||||
}
|
||||
virtual const TargetData *getTargetData() const { return &DataLayout; }
|
||||
|
||||
static unsigned getModuleMatchQuality(const Module &M);
|
||||
|
||||
// Pass Pipeline Configuration
|
||||
virtual bool addInstSelector(PassManagerBase &PM, CodeGenOpt::Level OptLevel);
|
||||
virtual bool addPreEmitPass(PassManagerBase &PM, CodeGenOpt::Level OptLevel);
|
||||
virtual bool addAssemblyEmitter(PassManagerBase &PM,
|
||||
CodeGenOpt::Level OptLevel,
|
||||
bool Verbose, raw_ostream &Out);
|
||||
|
||||
static void registerAsmPrinter(AsmPrinterCtorFn F) {
|
||||
AsmPrinterCtor = F;
|
||||
}
|
||||
};
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1,20 +0,0 @@
|
||||
##===- lib/Target/IA64/Makefile -----------------------------*- Makefile -*-===##
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
LEVEL = ../../..
|
||||
LIBRARYNAME = LLVMIA64CodeGen
|
||||
TARGET = IA64
|
||||
# Make sure that tblgen is run, first thing.
|
||||
BUILT_SOURCES = IA64GenRegisterInfo.h.inc IA64GenRegisterNames.inc \
|
||||
IA64GenRegisterInfo.inc IA64GenInstrNames.inc \
|
||||
IA64GenInstrInfo.inc IA64GenAsmWriter.inc \
|
||||
IA64GenDAGISel.inc
|
||||
|
||||
DIRS = AsmPrinter
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
@ -1,48 +0,0 @@
|
||||
TODO:
|
||||
- Un-bitrot ISel
|
||||
- Hook up If-Conversion a la ARM target
|
||||
- Hook up all branch analysis functions
|
||||
- Instruction scheduling
|
||||
- Bundling
|
||||
- Dynamic Optimization
|
||||
- Testing and bugfixing
|
||||
- stop passing FP args in both FP *and* integer regs when not required
|
||||
- allocate low (nonstacked) registers more aggressively
|
||||
- clean up and thoroughly test the isel patterns.
|
||||
- fix stacked register allocation order: (for readability) we don't want
|
||||
the out? registers being the first ones used
|
||||
- fix up floating point
|
||||
(nb http://gcc.gnu.org/wiki?pagename=ia64%20floating%20point )
|
||||
- bundling!
|
||||
(we will avoid the mess that is:
|
||||
http://gcc.gnu.org/ml/gcc/2003-12/msg00832.html )
|
||||
- instruction scheduling (hmmmm! ;)
|
||||
- counted loop support
|
||||
- make integer + FP mul/div more clever (we have fixed pseudocode atm)
|
||||
- track and use comparison complements
|
||||
|
||||
INFO:
|
||||
- we are strictly LP64 here, no support for ILP32 on HP-UX. Linux users
|
||||
don't need to worry about this.
|
||||
- i have instruction scheduling/bundling pseudocode, that really works
|
||||
(has been tested, albeit at the perl-script level).
|
||||
so, before you go write your own, send me an email!
|
||||
|
||||
KNOWN DEFECTS AT THE CURRENT TIME:
|
||||
- C++ vtables contain naked function pointers, not function descriptors,
|
||||
which is bad. see http://llvm.cs.uiuc.edu/bugs/show_bug.cgi?id=406
|
||||
- varargs are broken
|
||||
- alloca doesn't work (indeed, stack frame layout is bogus)
|
||||
- no support for big-endian environments
|
||||
- (not really the backend, but...) the CFE has some issues on IA64.
|
||||
these will probably be fixed soon.
|
||||
|
||||
ACKNOWLEDGEMENTS:
|
||||
- Chris Lattner (x100)
|
||||
- Other LLVM developers ("hey, that looks familiar")
|
||||
|
||||
CONTACT:
|
||||
- You can email me at duraid@octopus.com.au. If you find a small bug,
|
||||
just email me. If you find a big bug, please file a bug report
|
||||
in bugzilla! http://llvm.cs.uiuc.edu is your one stop shop for all
|
||||
things LLVM.
|
@ -1,262 +0,0 @@
|
||||
//===-- MSP430AsmPrinter.cpp - MSP430 LLVM assembly writer ------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains a printer that converts from our internal representation
|
||||
// of machine-dependent LLVM code to the MSP430 assembly language.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define DEBUG_TYPE "asm-printer"
|
||||
#include "MSP430.h"
|
||||
#include "MSP430InstrInfo.h"
|
||||
#include "MSP430TargetMachine.h"
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/CodeGen/AsmPrinter.h"
|
||||
#include "llvm/CodeGen/DwarfWriter.h"
|
||||
#include "llvm/CodeGen/MachineModuleInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineConstantPool.h"
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
#include "llvm/Target/TargetAsmInfo.h"
|
||||
#include "llvm/Target/TargetData.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/Mangler.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
STATISTIC(EmittedInsts, "Number of machine instrs printed");
|
||||
|
||||
namespace {
|
||||
class VISIBILITY_HIDDEN MSP430AsmPrinter : public AsmPrinter {
|
||||
public:
|
||||
MSP430AsmPrinter(raw_ostream &O, MSP430TargetMachine &TM,
|
||||
const TargetAsmInfo *TAI, bool V)
|
||||
: AsmPrinter(O, TM, TAI, V) {}
|
||||
|
||||
virtual const char *getPassName() const {
|
||||
return "MSP430 Assembly Printer";
|
||||
}
|
||||
|
||||
void printOperand(const MachineInstr *MI, int OpNum,
|
||||
const char* Modifier = 0);
|
||||
void printSrcMemOperand(const MachineInstr *MI, int OpNum,
|
||||
const char* Modifier = 0);
|
||||
void printCCOperand(const MachineInstr *MI, int OpNum);
|
||||
bool printInstruction(const MachineInstr *MI); // autogenerated.
|
||||
void printMachineInstruction(const MachineInstr * MI);
|
||||
|
||||
void emitFunctionHeader(const MachineFunction &MF);
|
||||
bool runOnMachineFunction(MachineFunction &F);
|
||||
bool doInitialization(Module &M);
|
||||
bool doFinalization(Module &M);
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AsmPrinter::getAnalysisUsage(AU);
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
};
|
||||
} // end of anonymous namespace
|
||||
|
||||
#include "MSP430GenAsmWriter.inc"
|
||||
|
||||
/// createMSP430CodePrinterPass - Returns a pass that prints the MSP430
|
||||
/// assembly code for a MachineFunction to the given output stream,
|
||||
/// using the given target machine description. This should work
|
||||
/// regardless of whether the function is in SSA form.
|
||||
///
|
||||
FunctionPass *llvm::createMSP430CodePrinterPass(raw_ostream &o,
|
||||
MSP430TargetMachine &tm,
|
||||
bool verbose) {
|
||||
return new MSP430AsmPrinter(o, tm, tm.getTargetAsmInfo(), verbose);
|
||||
}
|
||||
|
||||
bool MSP430AsmPrinter::doInitialization(Module &M) {
|
||||
Mang = new Mangler(M, "", TAI->getPrivateGlobalPrefix());
|
||||
return false; // success
|
||||
}
|
||||
|
||||
|
||||
bool MSP430AsmPrinter::doFinalization(Module &M) {
|
||||
return AsmPrinter::doFinalization(M);
|
||||
}
|
||||
|
||||
void MSP430AsmPrinter::emitFunctionHeader(const MachineFunction &MF) {
|
||||
const Function *F = MF.getFunction();
|
||||
|
||||
SwitchToSection(TAI->SectionForGlobal(F));
|
||||
|
||||
unsigned FnAlign = MF.getAlignment();
|
||||
EmitAlignment(FnAlign, F);
|
||||
|
||||
switch (F->getLinkage()) {
|
||||
default: assert(0 && "Unknown linkage type!");
|
||||
case Function::InternalLinkage: // Symbols default to internal.
|
||||
case Function::PrivateLinkage:
|
||||
break;
|
||||
case Function::ExternalLinkage:
|
||||
O << "\t.globl\t" << CurrentFnName << '\n';
|
||||
break;
|
||||
case Function::LinkOnceAnyLinkage:
|
||||
case Function::LinkOnceODRLinkage:
|
||||
case Function::WeakAnyLinkage:
|
||||
case Function::WeakODRLinkage:
|
||||
O << "\t.weak\t" << CurrentFnName << '\n';
|
||||
break;
|
||||
}
|
||||
|
||||
printVisibility(CurrentFnName, F->getVisibility());
|
||||
|
||||
O << "\t.type\t" << CurrentFnName << ",@function\n"
|
||||
<< CurrentFnName << ":\n";
|
||||
}
|
||||
|
||||
bool MSP430AsmPrinter::runOnMachineFunction(MachineFunction &MF) {
|
||||
SetupMachineFunction(MF);
|
||||
O << "\n\n";
|
||||
|
||||
// Print the 'header' of function
|
||||
emitFunctionHeader(MF);
|
||||
|
||||
// Print out code for the function.
|
||||
for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
|
||||
I != E; ++I) {
|
||||
// Print a label for the basic block.
|
||||
if (!VerboseAsm && (I->pred_empty() || I->isOnlyReachableByFallthrough())) {
|
||||
// This is an entry block or a block that's only reachable via a
|
||||
// fallthrough edge. In non-VerboseAsm mode, don't print the label.
|
||||
} else {
|
||||
printBasicBlockLabel(I, true, true, VerboseAsm);
|
||||
O << '\n';
|
||||
}
|
||||
|
||||
for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
|
||||
II != E; ++II)
|
||||
// Print the assembly for the instruction.
|
||||
printMachineInstruction(II);
|
||||
}
|
||||
|
||||
if (TAI->hasDotTypeDotSizeDirective())
|
||||
O << "\t.size\t" << CurrentFnName << ", .-" << CurrentFnName << '\n';
|
||||
|
||||
O.flush();
|
||||
|
||||
// We didn't modify anything
|
||||
return false;
|
||||
}
|
||||
|
||||
void MSP430AsmPrinter::printMachineInstruction(const MachineInstr *MI) {
|
||||
++EmittedInsts;
|
||||
|
||||
// Call the autogenerated instruction printer routines.
|
||||
if (printInstruction(MI))
|
||||
return;
|
||||
|
||||
assert(0 && "Should not happen");
|
||||
}
|
||||
|
||||
void MSP430AsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
|
||||
const char* Modifier) {
|
||||
const MachineOperand &MO = MI->getOperand(OpNum);
|
||||
switch (MO.getType()) {
|
||||
case MachineOperand::MO_Register:
|
||||
assert (TargetRegisterInfo::isPhysicalRegister(MO.getReg()) &&
|
||||
"Virtual registers should be already mapped!");
|
||||
O << TM.getRegisterInfo()->get(MO.getReg()).AsmName;
|
||||
return;
|
||||
case MachineOperand::MO_Immediate:
|
||||
if (!Modifier || strcmp(Modifier, "nohash"))
|
||||
O << '#';
|
||||
O << MO.getImm();
|
||||
return;
|
||||
case MachineOperand::MO_MachineBasicBlock:
|
||||
printBasicBlockLabel(MO.getMBB());
|
||||
return;
|
||||
case MachineOperand::MO_GlobalAddress: {
|
||||
bool isMemOp = Modifier && !strcmp(Modifier, "mem");
|
||||
bool isCallOp = Modifier && !strcmp(Modifier, "call");
|
||||
std::string Name = Mang->getValueName(MO.getGlobal());
|
||||
assert(MO.getOffset() == 0 && "No offsets allowed!");
|
||||
|
||||
if (isCallOp)
|
||||
O << '#';
|
||||
else if (isMemOp)
|
||||
O << '&';
|
||||
|
||||
O << Name;
|
||||
|
||||
return;
|
||||
}
|
||||
case MachineOperand::MO_ExternalSymbol: {
|
||||
bool isCallOp = Modifier && !strcmp(Modifier, "call");
|
||||
std::string Name(TAI->getGlobalPrefix());
|
||||
Name += MO.getSymbolName();
|
||||
if (isCallOp)
|
||||
O << '#';
|
||||
O << Name;
|
||||
return;
|
||||
}
|
||||
default:
|
||||
assert(0 && "Not implemented yet!");
|
||||
}
|
||||
}
|
||||
|
||||
void MSP430AsmPrinter::printSrcMemOperand(const MachineInstr *MI, int OpNum,
|
||||
const char* Modifier) {
|
||||
const MachineOperand &Base = MI->getOperand(OpNum);
|
||||
const MachineOperand &Disp = MI->getOperand(OpNum+1);
|
||||
|
||||
if (Base.isGlobal())
|
||||
printOperand(MI, OpNum, "mem");
|
||||
else if (Disp.isImm() && !Base.getReg())
|
||||
printOperand(MI, OpNum);
|
||||
else if (Base.getReg()) {
|
||||
if (Disp.getImm()) {
|
||||
printOperand(MI, OpNum + 1, "nohash");
|
||||
O << '(';
|
||||
printOperand(MI, OpNum);
|
||||
O << ')';
|
||||
} else {
|
||||
O << '@';
|
||||
printOperand(MI, OpNum);
|
||||
}
|
||||
} else
|
||||
assert(0 && "Unsupported memory operand");
|
||||
}
|
||||
|
||||
void MSP430AsmPrinter::printCCOperand(const MachineInstr *MI, int OpNum) {
|
||||
unsigned CC = MI->getOperand(OpNum).getImm();
|
||||
|
||||
switch (CC) {
|
||||
default:
|
||||
assert(0 && "Unsupported CC code");
|
||||
break;
|
||||
case MSP430::COND_E:
|
||||
O << "eq";
|
||||
break;
|
||||
case MSP430::COND_NE:
|
||||
O << "ne";
|
||||
break;
|
||||
case MSP430::COND_HS:
|
||||
O << "hs";
|
||||
break;
|
||||
case MSP430::COND_LO:
|
||||
O << "lo";
|
||||
break;
|
||||
case MSP430::COND_GE:
|
||||
O << "ge";
|
||||
break;
|
||||
case MSP430::COND_L:
|
||||
O << 'l';
|
||||
break;
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
//===-- MSP430TargetAsmInfo.cpp - MSP430 asm properties -------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the declarations of the MSP430TargetAsmInfo properties.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "MSP430TargetAsmInfo.h"
|
||||
#include "MSP430TargetMachine.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
MSP430TargetAsmInfo::MSP430TargetAsmInfo(const MSP430TargetMachine &TM)
|
||||
: ELFTargetAsmInfo(TM) {
|
||||
AlignmentIsInBytes = false;
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
//=====-- MSP430TargetAsmInfo.h - MSP430 asm properties -------*- C++ -*--====//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the declaration of the MSP430TargetAsmInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef MSP430TARGETASMINFO_H
|
||||
#define MSP430TARGETASMINFO_H
|
||||
|
||||
#include "llvm/Target/TargetAsmInfo.h"
|
||||
#include "llvm/Target/ELFTargetAsmInfo.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
// Forward declaration.
|
||||
class MSP430TargetMachine;
|
||||
|
||||
struct MSP430TargetAsmInfo : public ELFTargetAsmInfo {
|
||||
explicit MSP430TargetAsmInfo(const MSP430TargetMachine &TM);
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
@ -1,98 +0,0 @@
|
||||
//===-- MipsTargetAsmInfo.cpp - Mips asm properties -------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the declarations of the MipsTargetAsmInfo properties.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "MipsTargetAsmInfo.h"
|
||||
#include "MipsTargetMachine.h"
|
||||
#include "llvm/GlobalVariable.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
MipsTargetAsmInfo::MipsTargetAsmInfo(const MipsTargetMachine &TM):
|
||||
ELFTargetAsmInfo(TM) {
|
||||
|
||||
Subtarget = &TM.getSubtarget<MipsSubtarget>();
|
||||
|
||||
AlignmentIsInBytes = false;
|
||||
COMMDirectiveTakesAlignment = true;
|
||||
Data16bitsDirective = "\t.half\t";
|
||||
Data32bitsDirective = "\t.word\t";
|
||||
Data64bitsDirective = NULL;
|
||||
PrivateGlobalPrefix = "$";
|
||||
JumpTableDataSection = "\t.rdata";
|
||||
CommentString = "#";
|
||||
ZeroDirective = "\t.space\t";
|
||||
BSSSection = "\t.section\t.bss";
|
||||
CStringSection = ".rodata.str";
|
||||
|
||||
if (!Subtarget->hasABICall()) {
|
||||
JumpTableDirective = "\t.word\t";
|
||||
SmallDataSection = getNamedSection("\t.sdata", SectionFlags::Writeable);
|
||||
SmallBSSSection = getNamedSection("\t.sbss",
|
||||
SectionFlags::Writeable |
|
||||
SectionFlags::BSS);
|
||||
} else
|
||||
JumpTableDirective = "\t.gpword\t";
|
||||
|
||||
}
|
||||
|
||||
unsigned MipsTargetAsmInfo::
|
||||
SectionFlagsForGlobal(const GlobalValue *GV, const char* Name) const {
|
||||
unsigned Flags = ELFTargetAsmInfo::SectionFlagsForGlobal(GV, Name);
|
||||
// Mask out Small Section flag bit, Mips doesnt support 's' section symbol
|
||||
// for its small sections.
|
||||
return (Flags & (~SectionFlags::Small));
|
||||
}
|
||||
|
||||
SectionKind::Kind MipsTargetAsmInfo::
|
||||
SectionKindForGlobal(const GlobalValue *GV) const {
|
||||
SectionKind::Kind K = ELFTargetAsmInfo::SectionKindForGlobal(GV);
|
||||
|
||||
if (Subtarget->hasABICall())
|
||||
return K;
|
||||
|
||||
if (K != SectionKind::Data && K != SectionKind::BSS &&
|
||||
K != SectionKind::RODataMergeConst)
|
||||
return K;
|
||||
|
||||
if (isa<GlobalVariable>(GV)) {
|
||||
const TargetData *TD = TM.getTargetData();
|
||||
unsigned Size = TD->getTypeAllocSize(GV->getType()->getElementType());
|
||||
unsigned Threshold = Subtarget->getSSectionThreshold();
|
||||
|
||||
if (Size > 0 && Size <= Threshold) {
|
||||
if (K == SectionKind::BSS)
|
||||
return SectionKind::SmallBSS;
|
||||
else
|
||||
return SectionKind::SmallData;
|
||||
}
|
||||
}
|
||||
|
||||
return K;
|
||||
}
|
||||
|
||||
const Section* MipsTargetAsmInfo::
|
||||
SelectSectionForGlobal(const GlobalValue *GV) const {
|
||||
SectionKind::Kind K = SectionKindForGlobal(GV);
|
||||
const GlobalVariable *GVA = dyn_cast<GlobalVariable>(GV);
|
||||
|
||||
if (GVA && (!GVA->isWeakForLinker()))
|
||||
switch (K) {
|
||||
case SectionKind::SmallData:
|
||||
return getSmallDataSection();
|
||||
case SectionKind::SmallBSS:
|
||||
return getSmallBSSSection();
|
||||
default: break;
|
||||
}
|
||||
|
||||
return ELFTargetAsmInfo::SelectSectionForGlobal(GV);
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
//=====-- MipsTargetAsmInfo.h - Mips asm properties -----------*- C++ -*--====//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the declaration of the MipsTargetAsmInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef MIPSTARGETASMINFO_H
|
||||
#define MIPSTARGETASMINFO_H
|
||||
|
||||
#include "MipsSubtarget.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "llvm/Target/TargetAsmInfo.h"
|
||||
#include "llvm/Target/TargetOptions.h"
|
||||
#include "llvm/Target/ELFTargetAsmInfo.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
// Forward declaration.
|
||||
class GlobalValue;
|
||||
class MipsTargetMachine;
|
||||
|
||||
struct MipsTargetAsmInfo : public ELFTargetAsmInfo {
|
||||
explicit MipsTargetAsmInfo(const MipsTargetMachine &TM);
|
||||
|
||||
/// SectionKindForGlobal - This hook allows the target to select proper
|
||||
/// section kind used for global emission.
|
||||
virtual SectionKind::Kind
|
||||
SectionKindForGlobal(const GlobalValue *GV) const;
|
||||
|
||||
/// SectionFlagsForGlobal - This hook allows the target to select proper
|
||||
/// section flags either for given global or for section.
|
||||
virtual unsigned
|
||||
SectionFlagsForGlobal(const GlobalValue *GV = NULL,
|
||||
const char* name = NULL) const;
|
||||
|
||||
virtual const Section* SelectSectionForGlobal(const GlobalValue *GV) const;
|
||||
|
||||
private:
|
||||
const MipsSubtarget *Subtarget;
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
@ -1,442 +0,0 @@
|
||||
//===-- PIC16AsmPrinter.cpp - PIC16 LLVM assembly writer ------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains a printer that converts from our internal representation
|
||||
// of machine-dependent LLVM code to PIC16 assembly language.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "PIC16AsmPrinter.h"
|
||||
#include "PIC16TargetAsmInfo.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/CodeGen/DwarfWriter.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/Mangler.h"
|
||||
#include "llvm/CodeGen/DwarfWriter.h"
|
||||
#include "llvm/CodeGen/MachineModuleInfo.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
#include "PIC16GenAsmWriter.inc"
|
||||
|
||||
bool PIC16AsmPrinter::printMachineInstruction(const MachineInstr *MI) {
|
||||
printInstruction(MI);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// runOnMachineFunction - This emits the frame section, autos section and
|
||||
/// assembly for each instruction. Also takes care of function begin debug
|
||||
/// directive and file begin debug directive (if required) for the function.
|
||||
///
|
||||
bool PIC16AsmPrinter::runOnMachineFunction(MachineFunction &MF) {
|
||||
this->MF = &MF;
|
||||
|
||||
// This calls the base class function required to be called at beginning
|
||||
// of runOnMachineFunction.
|
||||
SetupMachineFunction(MF);
|
||||
|
||||
// Get the mangled name.
|
||||
const Function *F = MF.getFunction();
|
||||
CurrentFnName = Mang->getValueName(F);
|
||||
|
||||
// Emit the function frame (args and temps).
|
||||
EmitFunctionFrame(MF);
|
||||
|
||||
DbgInfo.BeginFunction(MF);
|
||||
|
||||
// Emit the autos section of function.
|
||||
EmitAutos(CurrentFnName);
|
||||
|
||||
// Now emit the instructions of function in its code section.
|
||||
const char *codeSection = PAN::getCodeSectionName(CurrentFnName).c_str();
|
||||
|
||||
const Section *fCodeSection = TAI->getNamedSection(codeSection,
|
||||
SectionFlags::Code);
|
||||
// Start the Code Section.
|
||||
O << "\n";
|
||||
SwitchToSection (fCodeSection);
|
||||
|
||||
// Emit the frame address of the function at the beginning of code.
|
||||
O << "\tretlw low(" << PAN::getFrameLabel(CurrentFnName) << ")\n";
|
||||
O << "\tretlw high(" << PAN::getFrameLabel(CurrentFnName) << ")\n";
|
||||
|
||||
// Emit function start label.
|
||||
O << CurrentFnName << ":\n";
|
||||
|
||||
DebugLoc CurDL;
|
||||
O << "\n";
|
||||
// Print out code for the function.
|
||||
for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
|
||||
I != E; ++I) {
|
||||
|
||||
// Print a label for the basic block.
|
||||
if (I != MF.begin()) {
|
||||
printBasicBlockLabel(I, true);
|
||||
O << '\n';
|
||||
}
|
||||
|
||||
// Print a basic block.
|
||||
for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
|
||||
II != E; ++II) {
|
||||
|
||||
// Emit the line directive if source line changed.
|
||||
const DebugLoc DL = II->getDebugLoc();
|
||||
if (!DL.isUnknown() && DL != CurDL) {
|
||||
DbgInfo.ChangeDebugLoc(MF, DL);
|
||||
CurDL = DL;
|
||||
}
|
||||
|
||||
// Print the assembly for the instruction.
|
||||
printMachineInstruction(II);
|
||||
}
|
||||
}
|
||||
|
||||
// Emit function end debug directives.
|
||||
DbgInfo.EndFunction(MF);
|
||||
|
||||
return false; // we didn't modify anything.
|
||||
}
|
||||
|
||||
/// createPIC16CodePrinterPass - Returns a pass that prints the PIC16
|
||||
/// assembly code for a MachineFunction to the given output stream,
|
||||
/// using the given target machine description. This should work
|
||||
/// regardless of whether the function is in SSA form.
|
||||
///
|
||||
FunctionPass *llvm::createPIC16CodePrinterPass(raw_ostream &o,
|
||||
PIC16TargetMachine &tm,
|
||||
bool verbose) {
|
||||
return new PIC16AsmPrinter(o, tm, tm.getTargetAsmInfo(), verbose);
|
||||
}
|
||||
|
||||
|
||||
// printOperand - print operand of insn.
|
||||
void PIC16AsmPrinter::printOperand(const MachineInstr *MI, int opNum) {
|
||||
const MachineOperand &MO = MI->getOperand(opNum);
|
||||
|
||||
switch (MO.getType()) {
|
||||
case MachineOperand::MO_Register:
|
||||
if (TargetRegisterInfo::isPhysicalRegister(MO.getReg()))
|
||||
O << TM.getRegisterInfo()->get(MO.getReg()).AsmName;
|
||||
else
|
||||
assert(0 && "not implemented");
|
||||
return;
|
||||
|
||||
case MachineOperand::MO_Immediate:
|
||||
O << (int)MO.getImm();
|
||||
return;
|
||||
|
||||
case MachineOperand::MO_GlobalAddress: {
|
||||
O << Mang->getValueName(MO.getGlobal());
|
||||
break;
|
||||
}
|
||||
case MachineOperand::MO_ExternalSymbol: {
|
||||
const char *Sname = MO.getSymbolName();
|
||||
|
||||
// If its a libcall name, record it to decls section.
|
||||
if (PAN::getSymbolTag(Sname) == PAN::LIBCALL) {
|
||||
LibcallDecls.push_back(Sname);
|
||||
}
|
||||
|
||||
O << Sname;
|
||||
break;
|
||||
}
|
||||
case MachineOperand::MO_MachineBasicBlock:
|
||||
printBasicBlockLabel(MO.getMBB());
|
||||
return;
|
||||
|
||||
default:
|
||||
assert(0 && " Operand type not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
/// printCCOperand - Print the cond code operand.
|
||||
///
|
||||
void PIC16AsmPrinter::printCCOperand(const MachineInstr *MI, int opNum) {
|
||||
int CC = (int)MI->getOperand(opNum).getImm();
|
||||
O << PIC16CondCodeToString((PIC16CC::CondCodes)CC);
|
||||
}
|
||||
|
||||
/// printLibcallDecls - print the extern declarations for compiler
|
||||
/// intrinsics.
|
||||
///
|
||||
void PIC16AsmPrinter::printLibcallDecls(void) {
|
||||
// If no libcalls used, return.
|
||||
if (LibcallDecls.empty()) return;
|
||||
|
||||
O << TAI->getCommentString() << "External decls for libcalls - BEGIN." <<"\n";
|
||||
// Remove duplicate entries.
|
||||
LibcallDecls.sort();
|
||||
LibcallDecls.unique();
|
||||
for (std::list<const char*>::const_iterator I = LibcallDecls.begin();
|
||||
I != LibcallDecls.end(); I++) {
|
||||
O << TAI->getExternDirective() << *I << "\n";
|
||||
O << TAI->getExternDirective() << PAN::getArgsLabel(*I) << "\n";
|
||||
O << TAI->getExternDirective() << PAN::getRetvalLabel(*I) << "\n";
|
||||
}
|
||||
O << TAI->getCommentString() << "External decls for libcalls - END." <<"\n";
|
||||
}
|
||||
|
||||
/// doInitialization - Perfrom Module level initializations here.
|
||||
/// One task that we do here is to sectionize all global variables.
|
||||
/// The MemSelOptimizer pass depends on the sectionizing.
|
||||
///
|
||||
bool PIC16AsmPrinter::doInitialization (Module &M) {
|
||||
bool Result = AsmPrinter::doInitialization(M);
|
||||
|
||||
// FIXME:: This is temporary solution to generate the include file.
|
||||
// The processor should be passed to llc as in input and the header file
|
||||
// should be generated accordingly.
|
||||
O << "\n\t#include P16F1937.INC\n";
|
||||
|
||||
// Set the section names for all globals.
|
||||
for (Module::global_iterator I = M.global_begin(), E = M.global_end();
|
||||
I != E; ++I) {
|
||||
I->setSection(TAI->SectionForGlobal(I)->getName());
|
||||
}
|
||||
|
||||
DbgInfo.BeginModule(M);
|
||||
EmitFunctionDecls(M);
|
||||
EmitUndefinedVars(M);
|
||||
EmitDefinedVars(M);
|
||||
EmitIData(M);
|
||||
EmitUData(M);
|
||||
EmitRomData(M);
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// Emit extern decls for functions imported from other modules, and emit
|
||||
/// global declarations for function defined in this module and which are
|
||||
/// available to other modules.
|
||||
///
|
||||
void PIC16AsmPrinter::EmitFunctionDecls (Module &M) {
|
||||
// Emit declarations for external functions.
|
||||
O <<"\n"<<TAI->getCommentString() << "Function Declarations - BEGIN." <<"\n";
|
||||
for (Module::iterator I = M.begin(), E = M.end(); I != E; I++) {
|
||||
std::string Name = Mang->getValueName(I);
|
||||
if (Name.compare("@abort") == 0)
|
||||
continue;
|
||||
|
||||
// If it is llvm intrinsic call then don't emit
|
||||
if (Name.find("llvm.") != std::string::npos)
|
||||
continue;
|
||||
|
||||
if (! (I->isDeclaration() || I->hasExternalLinkage()))
|
||||
continue;
|
||||
|
||||
const char *directive = I->isDeclaration() ? TAI->getExternDirective() :
|
||||
TAI->getGlobalDirective();
|
||||
|
||||
O << directive << Name << "\n";
|
||||
O << directive << PAN::getRetvalLabel(Name) << "\n";
|
||||
O << directive << PAN::getArgsLabel(Name) << "\n";
|
||||
}
|
||||
|
||||
O << TAI->getCommentString() << "Function Declarations - END." <<"\n";
|
||||
}
|
||||
|
||||
// Emit variables imported from other Modules.
|
||||
void PIC16AsmPrinter::EmitUndefinedVars (Module &M)
|
||||
{
|
||||
std::vector<const GlobalVariable*> Items = PTAI->ExternalVarDecls->Items;
|
||||
if (! Items.size()) return;
|
||||
|
||||
O << "\n" << TAI->getCommentString() << "Imported Variables - BEGIN" << "\n";
|
||||
for (unsigned j = 0; j < Items.size(); j++) {
|
||||
O << TAI->getExternDirective() << Mang->getValueName(Items[j]) << "\n";
|
||||
}
|
||||
O << TAI->getCommentString() << "Imported Variables - END" << "\n";
|
||||
}
|
||||
|
||||
// Emit variables defined in this module and are available to other modules.
|
||||
void PIC16AsmPrinter::EmitDefinedVars (Module &M)
|
||||
{
|
||||
std::vector<const GlobalVariable*> Items = PTAI->ExternalVarDefs->Items;
|
||||
if (! Items.size()) return;
|
||||
|
||||
O << "\n" << TAI->getCommentString() << "Exported Variables - BEGIN" << "\n";
|
||||
for (unsigned j = 0; j < Items.size(); j++) {
|
||||
O << TAI->getGlobalDirective() << Mang->getValueName(Items[j]) << "\n";
|
||||
}
|
||||
O << TAI->getCommentString() << "Exported Variables - END" << "\n";
|
||||
}
|
||||
|
||||
// Emit initialized data placed in ROM.
|
||||
void PIC16AsmPrinter::EmitRomData (Module &M)
|
||||
{
|
||||
|
||||
std::vector<const GlobalVariable*> Items = PTAI->ROSection->Items;
|
||||
if (! Items.size()) return;
|
||||
|
||||
// Print ROData ection.
|
||||
O << "\n";
|
||||
SwitchToSection(PTAI->ROSection->S_);
|
||||
for (unsigned j = 0; j < Items.size(); j++) {
|
||||
O << Mang->getValueName(Items[j]);
|
||||
Constant *C = Items[j]->getInitializer();
|
||||
int AddrSpace = Items[j]->getType()->getAddressSpace();
|
||||
EmitGlobalConstant(C, AddrSpace);
|
||||
}
|
||||
}
|
||||
|
||||
bool PIC16AsmPrinter::doFinalization(Module &M) {
|
||||
printLibcallDecls();
|
||||
EmitRemainingAutos();
|
||||
DbgInfo.EndModule(M);
|
||||
O << "\n\t" << "END\n";
|
||||
bool Result = AsmPrinter::doFinalization(M);
|
||||
return Result;
|
||||
}
|
||||
|
||||
void PIC16AsmPrinter::EmitFunctionFrame(MachineFunction &MF) {
|
||||
const Function *F = MF.getFunction();
|
||||
std::string FuncName = Mang->getValueName(F);
|
||||
const TargetData *TD = TM.getTargetData();
|
||||
// Emit the data section name.
|
||||
O << "\n";
|
||||
const char *SectionName = PAN::getFrameSectionName(CurrentFnName).c_str();
|
||||
|
||||
const Section *fPDataSection = TAI->getNamedSection(SectionName,
|
||||
SectionFlags::Writeable);
|
||||
SwitchToSection(fPDataSection);
|
||||
|
||||
// Emit function frame label
|
||||
O << PAN::getFrameLabel(CurrentFnName) << ":\n";
|
||||
|
||||
const Type *RetType = F->getReturnType();
|
||||
unsigned RetSize = 0;
|
||||
if (RetType->getTypeID() != Type::VoidTyID)
|
||||
RetSize = TD->getTypeAllocSize(RetType);
|
||||
|
||||
//Emit function return value space
|
||||
// FIXME: Do not emit RetvalLable when retsize is zero. To do this
|
||||
// we will need to avoid printing a global directive for Retval label
|
||||
// in emitExternandGloblas.
|
||||
if(RetSize > 0)
|
||||
O << PAN::getRetvalLabel(CurrentFnName) << " RES " << RetSize << "\n";
|
||||
else
|
||||
O << PAN::getRetvalLabel(CurrentFnName) << ": \n";
|
||||
|
||||
// Emit variable to hold the space for function arguments
|
||||
unsigned ArgSize = 0;
|
||||
for (Function::const_arg_iterator argi = F->arg_begin(),
|
||||
arge = F->arg_end(); argi != arge ; ++argi) {
|
||||
const Type *Ty = argi->getType();
|
||||
ArgSize += TD->getTypeAllocSize(Ty);
|
||||
}
|
||||
|
||||
O << PAN::getArgsLabel(CurrentFnName) << " RES " << ArgSize << "\n";
|
||||
|
||||
// Emit temporary space
|
||||
int TempSize = PTLI->GetTmpSize();
|
||||
if (TempSize > 0 )
|
||||
O << PAN::getTempdataLabel(CurrentFnName) << " RES " << TempSize <<"\n";
|
||||
}
|
||||
|
||||
void PIC16AsmPrinter::EmitIData (Module &M) {
|
||||
|
||||
// Print all IDATA sections.
|
||||
std::vector <PIC16Section *>IDATASections = PTAI->IDATASections;
|
||||
for (unsigned i = 0; i < IDATASections.size(); i++) {
|
||||
O << "\n";
|
||||
SwitchToSection(IDATASections[i]->S_);
|
||||
std::vector<const GlobalVariable*> Items = IDATASections[i]->Items;
|
||||
for (unsigned j = 0; j < Items.size(); j++) {
|
||||
std::string Name = Mang->getValueName(Items[j]);
|
||||
Constant *C = Items[j]->getInitializer();
|
||||
int AddrSpace = Items[j]->getType()->getAddressSpace();
|
||||
O << Name;
|
||||
EmitGlobalConstant(C, AddrSpace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PIC16AsmPrinter::EmitUData (Module &M) {
|
||||
const TargetData *TD = TM.getTargetData();
|
||||
|
||||
// Print all BSS sections.
|
||||
std::vector <PIC16Section *>BSSSections = PTAI->BSSSections;
|
||||
for (unsigned i = 0; i < BSSSections.size(); i++) {
|
||||
O << "\n";
|
||||
SwitchToSection(BSSSections[i]->S_);
|
||||
std::vector<const GlobalVariable*> Items = BSSSections[i]->Items;
|
||||
for (unsigned j = 0; j < Items.size(); j++) {
|
||||
std::string Name = Mang->getValueName(Items[j]);
|
||||
Constant *C = Items[j]->getInitializer();
|
||||
const Type *Ty = C->getType();
|
||||
unsigned Size = TD->getTypeAllocSize(Ty);
|
||||
|
||||
O << Name << " " <<"RES"<< " " << Size ;
|
||||
O << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PIC16AsmPrinter::EmitAutos (std::string FunctName)
|
||||
{
|
||||
// Section names for all globals are already set.
|
||||
|
||||
const TargetData *TD = TM.getTargetData();
|
||||
|
||||
// Now print Autos section for this function.
|
||||
std::string SectionName = PAN::getAutosSectionName(FunctName);
|
||||
std::vector <PIC16Section *>AutosSections = PTAI->AutosSections;
|
||||
for (unsigned i = 0; i < AutosSections.size(); i++) {
|
||||
O << "\n";
|
||||
if (AutosSections[i]->S_->getName() == SectionName) {
|
||||
// Set the printing status to true
|
||||
AutosSections[i]->setPrintedStatus(true);
|
||||
SwitchToSection(AutosSections[i]->S_);
|
||||
std::vector<const GlobalVariable*> Items = AutosSections[i]->Items;
|
||||
for (unsigned j = 0; j < Items.size(); j++) {
|
||||
std::string VarName = Mang->getValueName(Items[j]);
|
||||
Constant *C = Items[j]->getInitializer();
|
||||
const Type *Ty = C->getType();
|
||||
unsigned Size = TD->getTypeAllocSize(Ty);
|
||||
// Emit memory reserve directive.
|
||||
O << VarName << " RES " << Size << "\n";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Print autos that were not printed during the code printing of functions.
|
||||
// As the functions might themselves would have got deleted by the optimizer.
|
||||
void PIC16AsmPrinter::EmitRemainingAutos()
|
||||
{
|
||||
const TargetData *TD = TM.getTargetData();
|
||||
|
||||
// Now print Autos section for this function.
|
||||
std::vector <PIC16Section *>AutosSections = PTAI->AutosSections;
|
||||
for (unsigned i = 0; i < AutosSections.size(); i++) {
|
||||
|
||||
// if the section is already printed then don't print again
|
||||
if (AutosSections[i]->isPrinted())
|
||||
continue;
|
||||
|
||||
// Set status as printed
|
||||
AutosSections[i]->setPrintedStatus(true);
|
||||
|
||||
O << "\n";
|
||||
SwitchToSection(AutosSections[i]->S_);
|
||||
std::vector<const GlobalVariable*> Items = AutosSections[i]->Items;
|
||||
for (unsigned j = 0; j < Items.size(); j++) {
|
||||
std::string VarName = Mang->getValueName(Items[j]);
|
||||
Constant *C = Items[j]->getInitializer();
|
||||
const Type *Ty = C->getType();
|
||||
unsigned Size = TD->getTypeAllocSize(Ty);
|
||||
// Emit memory reserve directive.
|
||||
O << VarName << " RES " << Size << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,70 +0,0 @@
|
||||
//===-- PIC16AsmPrinter.h - PIC16 LLVM assembly writer ------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains a printer that converts from our internal representation
|
||||
// of machine-dependent LLVM code to PIC16 assembly language.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef PIC16ASMPRINTER_H
|
||||
#define PIC16ASMPRINTER_H
|
||||
|
||||
#include "PIC16.h"
|
||||
#include "PIC16TargetMachine.h"
|
||||
#include "PIC16DebugInfo.h"
|
||||
#include "llvm/Analysis/DebugInfo.h"
|
||||
#include "PIC16TargetAsmInfo.h"
|
||||
#include "llvm/CodeGen/AsmPrinter.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Target/TargetAsmInfo.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
namespace llvm {
|
||||
struct VISIBILITY_HIDDEN PIC16AsmPrinter : public AsmPrinter {
|
||||
explicit PIC16AsmPrinter(raw_ostream &O, PIC16TargetMachine &TM,
|
||||
const TargetAsmInfo *T, bool V)
|
||||
: AsmPrinter(O, TM, T, V), DbgInfo(O, T) {
|
||||
PTLI = TM.getTargetLowering();
|
||||
PTAI = static_cast<const PIC16TargetAsmInfo *> (T);
|
||||
}
|
||||
private :
|
||||
virtual const char *getPassName() const {
|
||||
return "PIC16 Assembly Printer";
|
||||
}
|
||||
|
||||
bool runOnMachineFunction(MachineFunction &F);
|
||||
void printOperand(const MachineInstr *MI, int opNum);
|
||||
void printCCOperand(const MachineInstr *MI, int opNum);
|
||||
bool printInstruction(const MachineInstr *MI); // definition autogenerated.
|
||||
bool printMachineInstruction(const MachineInstr *MI);
|
||||
void EmitFunctionDecls (Module &M);
|
||||
void EmitUndefinedVars (Module &M);
|
||||
void EmitDefinedVars (Module &M);
|
||||
void EmitIData (Module &M);
|
||||
void EmitUData (Module &M);
|
||||
void EmitAutos (std::string FunctName);
|
||||
void EmitRemainingAutos ();
|
||||
void EmitRomData (Module &M);
|
||||
void EmitFunctionFrame(MachineFunction &MF);
|
||||
void printLibcallDecls(void);
|
||||
protected:
|
||||
bool doInitialization(Module &M);
|
||||
bool doFinalization(Module &M);
|
||||
|
||||
private:
|
||||
PIC16TargetLowering *PTLI;
|
||||
PIC16DbgInfo DbgInfo;
|
||||
const PIC16TargetAsmInfo *PTAI;
|
||||
std::list<const char *> LibcallDecls; // List of extern decls.
|
||||
};
|
||||
} // end of namespace
|
||||
|
||||
#endif
|
@ -1,264 +0,0 @@
|
||||
//===-- PIC16TargetAsmInfo.cpp - PIC16 asm properties ---------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the declarations of the PIC16TargetAsmInfo properties.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "PIC16TargetAsmInfo.h"
|
||||
#include "PIC16TargetMachine.h"
|
||||
#include "llvm/GlobalValue.h"
|
||||
#include "llvm/GlobalVariable.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
PIC16TargetAsmInfo::
|
||||
PIC16TargetAsmInfo(const PIC16TargetMachine &TM)
|
||||
: TargetAsmInfo(TM) {
|
||||
CommentString = ";";
|
||||
GlobalPrefix = PAN::getTagName(PAN::PREFIX_SYMBOL);
|
||||
GlobalDirective = "\tglobal\t";
|
||||
ExternDirective = "\textern\t";
|
||||
|
||||
Data8bitsDirective = " db ";
|
||||
Data16bitsDirective = " dw ";
|
||||
Data32bitsDirective = " dl ";
|
||||
RomData8bitsDirective = " dw ";
|
||||
RomData16bitsDirective = " rom_di ";
|
||||
RomData32bitsDirective = " rom_dl ";
|
||||
ZeroDirective = NULL;
|
||||
AsciiDirective = " dt ";
|
||||
AscizDirective = NULL;
|
||||
BSSSection_ = getNamedSection("udata.# UDATA",
|
||||
SectionFlags::Writeable | SectionFlags::BSS);
|
||||
ReadOnlySection = getNamedSection("romdata.# ROMDATA", SectionFlags::None);
|
||||
DataSection = getNamedSection("idata.# IDATA", SectionFlags::Writeable);
|
||||
SwitchToSectionDirective = "";
|
||||
// Need because otherwise a .text symbol is emitted by DwarfWriter
|
||||
// in BeginModule, and gpasm cribbs for that .text symbol.
|
||||
TextSection = getUnnamedSection("", SectionFlags::Code);
|
||||
ROSection = new PIC16Section(getReadOnlySection());
|
||||
ExternalVarDecls = new PIC16Section(getNamedSection("ExternalVarDecls"));
|
||||
ExternalVarDefs = new PIC16Section(getNamedSection("ExternalVarDefs"));
|
||||
// Set it to false because we weed to generate c file name and not bc file
|
||||
// name.
|
||||
HasSingleParameterDotFile = false;
|
||||
}
|
||||
|
||||
const char *PIC16TargetAsmInfo::getRomDirective(unsigned size) const
|
||||
{
|
||||
if (size == 8)
|
||||
return RomData8bitsDirective;
|
||||
else if (size == 16)
|
||||
return RomData16bitsDirective;
|
||||
else if (size == 32)
|
||||
return RomData32bitsDirective;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
const char *PIC16TargetAsmInfo::getASDirective(unsigned size,
|
||||
unsigned AS) const {
|
||||
if (AS == PIC16ISD::ROM_SPACE)
|
||||
return getRomDirective(size);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const Section *
|
||||
PIC16TargetAsmInfo::getBSSSectionForGlobal(const GlobalVariable *GV) const {
|
||||
assert (GV->hasInitializer() && "This global doesn't need space");
|
||||
Constant *C = GV->getInitializer();
|
||||
assert (C->isNullValue() && "Unitialized globals has non-zero initializer");
|
||||
|
||||
// Find how much space this global needs.
|
||||
const TargetData *TD = TM.getTargetData();
|
||||
const Type *Ty = C->getType();
|
||||
unsigned ValSize = TD->getTypeAllocSize(Ty);
|
||||
|
||||
// Go through all BSS Sections and assign this variable
|
||||
// to the first available section having enough space.
|
||||
PIC16Section *FoundBSS = NULL;
|
||||
for (unsigned i = 0; i < BSSSections.size(); i++) {
|
||||
if (DataBankSize - BSSSections[i]->Size >= ValSize) {
|
||||
FoundBSS = BSSSections[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// No BSS section spacious enough was found. Crate a new one.
|
||||
if (! FoundBSS) {
|
||||
std::string name = PAN::getUdataSectionName(BSSSections.size());
|
||||
const Section *NewSection = getNamedSection (name.c_str());
|
||||
|
||||
FoundBSS = new PIC16Section(NewSection);
|
||||
|
||||
// Add this newly created BSS section to the list of BSSSections.
|
||||
BSSSections.push_back(FoundBSS);
|
||||
}
|
||||
|
||||
// Insert the GV into this BSS.
|
||||
FoundBSS->Items.push_back(GV);
|
||||
FoundBSS->Size += ValSize;
|
||||
|
||||
// We can't do this here because GV is const .
|
||||
// const std::string SName = FoundBSS->S_->getName();
|
||||
// GV->setSection(SName);
|
||||
|
||||
return FoundBSS->S_;
|
||||
}
|
||||
|
||||
const Section *
|
||||
PIC16TargetAsmInfo::getIDATASectionForGlobal(const GlobalVariable *GV) const {
|
||||
assert (GV->hasInitializer() && "This global doesn't need space");
|
||||
Constant *C = GV->getInitializer();
|
||||
assert (!C->isNullValue() && "initialized globals has zero initializer");
|
||||
assert (GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE &&
|
||||
"can split initialized RAM data only");
|
||||
|
||||
// Find how much space this global needs.
|
||||
const TargetData *TD = TM.getTargetData();
|
||||
const Type *Ty = C->getType();
|
||||
unsigned ValSize = TD->getTypeAllocSize(Ty);
|
||||
|
||||
// Go through all IDATA Sections and assign this variable
|
||||
// to the first available section having enough space.
|
||||
PIC16Section *FoundIDATA = NULL;
|
||||
for (unsigned i = 0; i < IDATASections.size(); i++) {
|
||||
if ( DataBankSize - IDATASections[i]->Size >= ValSize) {
|
||||
FoundIDATA = IDATASections[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// No IDATA section spacious enough was found. Crate a new one.
|
||||
if (! FoundIDATA) {
|
||||
std::string name = PAN::getIdataSectionName(IDATASections.size());
|
||||
const Section *NewSection = getNamedSection (name.c_str());
|
||||
|
||||
FoundIDATA = new PIC16Section(NewSection);
|
||||
|
||||
// Add this newly created IDATA section to the list of IDATASections.
|
||||
IDATASections.push_back(FoundIDATA);
|
||||
}
|
||||
|
||||
// Insert the GV into this IDATA.
|
||||
FoundIDATA->Items.push_back(GV);
|
||||
FoundIDATA->Size += ValSize;
|
||||
|
||||
// We can't do this here because GV is const .
|
||||
// GV->setSection(FoundIDATA->S->getName());
|
||||
|
||||
return FoundIDATA->S_;
|
||||
}
|
||||
|
||||
// Get the section for an automatic variable of a function.
|
||||
// For PIC16 they are globals only with mangled names.
|
||||
const Section *
|
||||
PIC16TargetAsmInfo::getSectionForAuto(const GlobalVariable *GV) const {
|
||||
|
||||
const std::string name = PAN::getSectionNameForSym(GV->getName());
|
||||
|
||||
// Go through all Auto Sections and assign this variable
|
||||
// to the appropriate section.
|
||||
PIC16Section *FoundAutoSec = NULL;
|
||||
for (unsigned i = 0; i < AutosSections.size(); i++) {
|
||||
if ( AutosSections[i]->S_->getName() == name) {
|
||||
FoundAutoSec = AutosSections[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// No Auto section was found. Crate a new one.
|
||||
if (! FoundAutoSec) {
|
||||
const Section *NewSection = getNamedSection (name.c_str());
|
||||
|
||||
FoundAutoSec = new PIC16Section(NewSection);
|
||||
|
||||
// Add this newly created autos section to the list of AutosSections.
|
||||
AutosSections.push_back(FoundAutoSec);
|
||||
}
|
||||
|
||||
// Insert the auto into this section.
|
||||
FoundAutoSec->Items.push_back(GV);
|
||||
|
||||
return FoundAutoSec->S_;
|
||||
}
|
||||
|
||||
|
||||
// Override default implementation to put the true globals into
|
||||
// multiple data sections if required.
|
||||
const Section*
|
||||
PIC16TargetAsmInfo::SelectSectionForGlobal(const GlobalValue *GV1) const {
|
||||
// We select the section based on the initializer here, so it really
|
||||
// has to be a GlobalVariable.
|
||||
const GlobalVariable *GV = dyn_cast<GlobalVariable>(GV1);
|
||||
|
||||
if (!GV)
|
||||
return TargetAsmInfo::SelectSectionForGlobal(GV1);
|
||||
|
||||
// Record Exteranl Var Decls.
|
||||
if (GV->isDeclaration()) {
|
||||
ExternalVarDecls->Items.push_back(GV);
|
||||
return ExternalVarDecls->S_;
|
||||
}
|
||||
|
||||
assert (GV->hasInitializer() && "A def without initializer?");
|
||||
|
||||
// First, if this is an automatic variable for a function, get the section
|
||||
// name for it and return.
|
||||
const std::string name = GV->getName();
|
||||
if (PAN::isLocalName(name)) {
|
||||
return getSectionForAuto(GV);
|
||||
}
|
||||
|
||||
// Record Exteranl Var Defs.
|
||||
if (GV->hasExternalLinkage() || GV->hasCommonLinkage()) {
|
||||
ExternalVarDefs->Items.push_back(GV);
|
||||
}
|
||||
|
||||
// See if this is an uninitialized global.
|
||||
const Constant *C = GV->getInitializer();
|
||||
if (C->isNullValue())
|
||||
return getBSSSectionForGlobal(GV);
|
||||
|
||||
// If this is initialized data in RAM. Put it in the correct IDATA section.
|
||||
if (GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE)
|
||||
return getIDATASectionForGlobal(GV);
|
||||
|
||||
// This is initialized data in rom, put it in the readonly section.
|
||||
if (GV->getType()->getAddressSpace() == PIC16ISD::ROM_SPACE) {
|
||||
ROSection->Items.push_back(GV);
|
||||
return ROSection->S_;
|
||||
}
|
||||
|
||||
// Else let the default implementation take care of it.
|
||||
return TargetAsmInfo::SelectSectionForGlobal(GV);
|
||||
}
|
||||
|
||||
PIC16TargetAsmInfo::~PIC16TargetAsmInfo() {
|
||||
|
||||
for (unsigned i = 0; i < BSSSections.size(); i++) {
|
||||
delete BSSSections[i];
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < IDATASections.size(); i++) {
|
||||
delete IDATASections[i];
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < AutosSections.size(); i++) {
|
||||
delete AutosSections[i];
|
||||
}
|
||||
|
||||
delete ROSection;
|
||||
delete ExternalVarDecls;
|
||||
delete ExternalVarDefs;
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
//=====-- PIC16TargetAsmInfo.h - PIC16 asm properties ---------*- C++ -*--====//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the declaration of the PIC16TargetAsmInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef PIC16TARGETASMINFO_H
|
||||
#define PIC16TARGETASMINFO_H
|
||||
|
||||
#include "PIC16.h"
|
||||
#include "llvm/Target/TargetAsmInfo.h"
|
||||
#include <vector>
|
||||
#include "llvm/Module.h"
|
||||
#define DataBankSize 80
|
||||
namespace llvm {
|
||||
|
||||
// Forward declaration.
|
||||
class PIC16TargetMachine;
|
||||
class GlobalVariable;
|
||||
|
||||
// PIC16 Splits the global data into mulitple udata and idata sections.
|
||||
// Each udata and idata section needs to contain a list of globals that
|
||||
// they contain, in order to avoid scanning over all the global values
|
||||
// again and printing only those that match the current section.
|
||||
// Keeping values inside the sections make printing a section much easier.
|
||||
struct PIC16Section {
|
||||
const Section *S_; // Connection to actual Section.
|
||||
unsigned Size; // Total size of the objects contained.
|
||||
bool SectionPrinted;
|
||||
std::vector<const GlobalVariable*> Items;
|
||||
|
||||
PIC16Section (const Section *s) { S_ = s; Size = 0;
|
||||
SectionPrinted = false;}
|
||||
bool isPrinted() { return SectionPrinted ; }
|
||||
void setPrintedStatus(bool status) { SectionPrinted = status ;}
|
||||
};
|
||||
|
||||
struct PIC16TargetAsmInfo : public TargetAsmInfo {
|
||||
std::string getSectionNameForSym(const std::string &Sym) const;
|
||||
PIC16TargetAsmInfo(const PIC16TargetMachine &TM);
|
||||
mutable std::vector<PIC16Section *> BSSSections;
|
||||
mutable std::vector<PIC16Section *> IDATASections;
|
||||
mutable std::vector<PIC16Section *> AutosSections;
|
||||
mutable PIC16Section *ROSection;
|
||||
mutable PIC16Section *ExternalVarDecls;
|
||||
mutable PIC16Section *ExternalVarDefs;
|
||||
virtual ~PIC16TargetAsmInfo();
|
||||
|
||||
private:
|
||||
const char *RomData8bitsDirective;
|
||||
const char *RomData16bitsDirective;
|
||||
const char *RomData32bitsDirective;
|
||||
const char *getRomDirective(unsigned size) const;
|
||||
virtual const char *getASDirective(unsigned size, unsigned AS) const;
|
||||
const Section *getBSSSectionForGlobal(const GlobalVariable *GV) const;
|
||||
const Section *getIDATASectionForGlobal(const GlobalVariable *GV) const;
|
||||
const Section *getSectionForAuto(const GlobalVariable *GV) const;
|
||||
virtual const Section *SelectSectionForGlobal(const GlobalValue *GV) const;
|
||||
|
||||
|
||||
public:
|
||||
void SetSectionForGVs(Module &M);
|
||||
std::vector<PIC16Section *> getBSSSections() const {
|
||||
return BSSSections;
|
||||
}
|
||||
std::vector<PIC16Section *> getIDATASections() const {
|
||||
return IDATASections;
|
||||
}
|
||||
std::vector<PIC16Section *> getAutosSections() const {
|
||||
return AutosSections;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
@ -1,121 +0,0 @@
|
||||
//===-- PPCTargetAsmInfo.cpp - PPC asm properties ---------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the declarations of the DarwinTargetAsmInfo properties.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "PPCTargetAsmInfo.h"
|
||||
#include "PPCTargetMachine.h"
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/Support/Dwarf.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::dwarf;
|
||||
|
||||
PPCDarwinTargetAsmInfo::PPCDarwinTargetAsmInfo(const PPCTargetMachine &TM) :
|
||||
PPCTargetAsmInfo<DarwinTargetAsmInfo>(TM) {
|
||||
PCSymbol = ".";
|
||||
CommentString = ";";
|
||||
ConstantPoolSection = "\t.const\t";
|
||||
UsedDirective = "\t.no_dead_strip\t";
|
||||
SupportsExceptionHandling = true;
|
||||
|
||||
DwarfEHFrameSection =
|
||||
".section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support";
|
||||
DwarfExceptionSection = ".section __DATA,__gcc_except_tab";
|
||||
GlobalEHDirective = "\t.globl\t";
|
||||
SupportsWeakOmittedEHFrame = false;
|
||||
}
|
||||
|
||||
/// PreferredEHDataFormat - This hook allows the target to select data
|
||||
/// format used for encoding pointers in exception handling data. Reason is
|
||||
/// 0 for data, 1 for code labels, 2 for function pointers. Global is true
|
||||
/// if the symbol can be relocated.
|
||||
unsigned
|
||||
PPCDarwinTargetAsmInfo::PreferredEHDataFormat(DwarfEncoding::Target Reason,
|
||||
bool Global) const {
|
||||
if (Reason == DwarfEncoding::Functions && Global)
|
||||
return (DW_EH_PE_pcrel | DW_EH_PE_indirect | DW_EH_PE_sdata4);
|
||||
else if (Reason == DwarfEncoding::CodeLabels || !Global)
|
||||
return DW_EH_PE_pcrel;
|
||||
else
|
||||
return DW_EH_PE_absptr;
|
||||
}
|
||||
|
||||
const char *
|
||||
PPCDarwinTargetAsmInfo::getEHGlobalPrefix() const
|
||||
{
|
||||
const PPCSubtarget* Subtarget = &TM.getSubtarget<PPCSubtarget>();
|
||||
if (Subtarget->getDarwinVers() > 9)
|
||||
return PrivateGlobalPrefix;
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
PPCLinuxTargetAsmInfo::PPCLinuxTargetAsmInfo(const PPCTargetMachine &TM) :
|
||||
PPCTargetAsmInfo<ELFTargetAsmInfo>(TM) {
|
||||
CommentString = "#";
|
||||
GlobalPrefix = "";
|
||||
PrivateGlobalPrefix = ".L";
|
||||
ConstantPoolSection = "\t.section .rodata.cst4\t";
|
||||
JumpTableDataSection = ".section .rodata.cst4";
|
||||
CStringSection = ".rodata.str";
|
||||
StaticCtorsSection = ".section\t.ctors,\"aw\",@progbits";
|
||||
StaticDtorsSection = ".section\t.dtors,\"aw\",@progbits";
|
||||
UsedDirective = "\t# .no_dead_strip\t";
|
||||
WeakRefDirective = "\t.weak\t";
|
||||
BSSSection = "\t.section\t\".sbss\",\"aw\",@nobits";
|
||||
|
||||
// PPC/Linux normally uses named section for BSS.
|
||||
BSSSection_ = getNamedSection("\t.bss",
|
||||
SectionFlags::Writeable | SectionFlags::BSS,
|
||||
/* Override */ true);
|
||||
|
||||
// Debug Information
|
||||
AbsoluteDebugSectionOffsets = true;
|
||||
SupportsDebugInformation = true;
|
||||
DwarfAbbrevSection = "\t.section\t.debug_abbrev,\"\",@progbits";
|
||||
DwarfInfoSection = "\t.section\t.debug_info,\"\",@progbits";
|
||||
DwarfLineSection = "\t.section\t.debug_line,\"\",@progbits";
|
||||
DwarfFrameSection = "\t.section\t.debug_frame,\"\",@progbits";
|
||||
DwarfPubNamesSection ="\t.section\t.debug_pubnames,\"\",@progbits";
|
||||
DwarfPubTypesSection ="\t.section\t.debug_pubtypes,\"\",@progbits";
|
||||
DwarfStrSection = "\t.section\t.debug_str,\"\",@progbits";
|
||||
DwarfLocSection = "\t.section\t.debug_loc,\"\",@progbits";
|
||||
DwarfARangesSection = "\t.section\t.debug_aranges,\"\",@progbits";
|
||||
DwarfRangesSection = "\t.section\t.debug_ranges,\"\",@progbits";
|
||||
DwarfMacroInfoSection = "\t.section\t.debug_macinfo,\"\",@progbits";
|
||||
|
||||
PCSymbol = ".";
|
||||
|
||||
// Set up DWARF directives
|
||||
HasLEB128 = true; // Target asm supports leb128 directives (little-endian)
|
||||
|
||||
// Exceptions handling
|
||||
if (!TM.getSubtargetImpl()->isPPC64())
|
||||
SupportsExceptionHandling = true;
|
||||
AbsoluteEHSectionOffsets = false;
|
||||
DwarfEHFrameSection = "\t.section\t.eh_frame,\"aw\",@progbits";
|
||||
DwarfExceptionSection = "\t.section\t.gcc_except_table,\"a\",@progbits";
|
||||
}
|
||||
|
||||
/// PreferredEHDataFormat - This hook allows the target to select data
|
||||
/// format used for encoding pointers in exception handling data. Reason is
|
||||
/// 0 for data, 1 for code labels, 2 for function pointers. Global is true
|
||||
/// if the symbol can be relocated.
|
||||
unsigned
|
||||
PPCLinuxTargetAsmInfo::PreferredEHDataFormat(DwarfEncoding::Target Reason,
|
||||
bool Global) const {
|
||||
// We really need to write something here.
|
||||
return TargetAsmInfo::PreferredEHDataFormat(Reason, Global);
|
||||
}
|
||||
|
||||
// Instantiate default implementation.
|
||||
TEMPLATE_INSTANTIATION(class PPCTargetAsmInfo<TargetAsmInfo>);
|
@ -1,62 +0,0 @@
|
||||
//=====-- PPCTargetAsmInfo.h - PPC asm properties -------------*- C++ -*--====//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the declaration of the DarwinTargetAsmInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef PPCTARGETASMINFO_H
|
||||
#define PPCTARGETASMINFO_H
|
||||
|
||||
#include "PPCTargetMachine.h"
|
||||
#include "llvm/Target/TargetAsmInfo.h"
|
||||
#include "llvm/Target/DarwinTargetAsmInfo.h"
|
||||
#include "llvm/Target/ELFTargetAsmInfo.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
template <class BaseTAI>
|
||||
struct PPCTargetAsmInfo : public BaseTAI {
|
||||
explicit PPCTargetAsmInfo(const PPCTargetMachine &TM):
|
||||
BaseTAI(TM) {
|
||||
const PPCSubtarget *Subtarget = &TM.getSubtarget<PPCSubtarget>();
|
||||
bool isPPC64 = Subtarget->isPPC64();
|
||||
|
||||
BaseTAI::ZeroDirective = "\t.space\t";
|
||||
BaseTAI::SetDirective = "\t.set";
|
||||
BaseTAI::Data64bitsDirective = isPPC64 ? "\t.quad\t" : 0;
|
||||
BaseTAI::AlignmentIsInBytes = false;
|
||||
BaseTAI::LCOMMDirective = "\t.lcomm\t";
|
||||
BaseTAI::InlineAsmStart = "# InlineAsm Start";
|
||||
BaseTAI::InlineAsmEnd = "# InlineAsm End";
|
||||
BaseTAI::AssemblerDialect = Subtarget->getAsmFlavor();
|
||||
}
|
||||
};
|
||||
|
||||
typedef PPCTargetAsmInfo<TargetAsmInfo> PPCGenericTargetAsmInfo;
|
||||
|
||||
EXTERN_TEMPLATE_INSTANTIATION(class PPCTargetAsmInfo<TargetAsmInfo>);
|
||||
|
||||
struct PPCDarwinTargetAsmInfo : public PPCTargetAsmInfo<DarwinTargetAsmInfo> {
|
||||
explicit PPCDarwinTargetAsmInfo(const PPCTargetMachine &TM);
|
||||
virtual unsigned PreferredEHDataFormat(DwarfEncoding::Target Reason,
|
||||
bool Global) const;
|
||||
virtual const char *getEHGlobalPrefix() const;
|
||||
};
|
||||
|
||||
struct PPCLinuxTargetAsmInfo : public PPCTargetAsmInfo<ELFTargetAsmInfo> {
|
||||
explicit PPCLinuxTargetAsmInfo(const PPCTargetMachine &TM);
|
||||
virtual unsigned PreferredEHDataFormat(DwarfEncoding::Target Reason,
|
||||
bool Global) const;
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
@ -1,50 +0,0 @@
|
||||
//===-- SparcTargetAsmInfo.cpp - Sparc asm properties -----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the declarations of the SparcTargetAsmInfo properties.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "SparcTargetAsmInfo.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
SparcELFTargetAsmInfo::SparcELFTargetAsmInfo(const TargetMachine &TM):
|
||||
ELFTargetAsmInfo(TM) {
|
||||
Data16bitsDirective = "\t.half\t";
|
||||
Data32bitsDirective = "\t.word\t";
|
||||
Data64bitsDirective = 0; // .xword is only supported by V9.
|
||||
ZeroDirective = "\t.skip\t";
|
||||
CommentString = "!";
|
||||
ConstantPoolSection = "\t.section \".rodata\",#alloc\n";
|
||||
COMMDirectiveTakesAlignment = true;
|
||||
CStringSection=".rodata.str";
|
||||
|
||||
// Sparc normally uses named section for BSS.
|
||||
BSSSection_ = getNamedSection("\t.bss",
|
||||
SectionFlags::Writeable | SectionFlags::BSS,
|
||||
/* Override */ true);
|
||||
}
|
||||
|
||||
std::string SparcELFTargetAsmInfo::printSectionFlags(unsigned flags) const {
|
||||
if (flags & SectionFlags::Mergeable)
|
||||
return ELFTargetAsmInfo::printSectionFlags(flags);
|
||||
|
||||
std::string Flags;
|
||||
if (!(flags & SectionFlags::Debug))
|
||||
Flags += ",#alloc";
|
||||
if (flags & SectionFlags::Code)
|
||||
Flags += ",#execinstr";
|
||||
if (flags & SectionFlags::Writeable)
|
||||
Flags += ",#write";
|
||||
if (flags & SectionFlags::TLS)
|
||||
Flags += ",#tls";
|
||||
|
||||
return Flags;
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
//=====-- SparcTargetAsmInfo.h - Sparc asm properties ---------*- C++ -*--====//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the declaration of the SparcTargetAsmInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SPARCTARGETASMINFO_H
|
||||
#define SPARCTARGETASMINFO_H
|
||||
|
||||
#include "llvm/Target/TargetAsmInfo.h"
|
||||
#include "llvm/Target/ELFTargetAsmInfo.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
// Forward declaration.
|
||||
class TargetMachine;
|
||||
|
||||
struct SparcELFTargetAsmInfo : public ELFTargetAsmInfo {
|
||||
explicit SparcELFTargetAsmInfo(const TargetMachine &TM);
|
||||
|
||||
std::string printSectionFlags(unsigned flags) const;
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
@ -1,456 +0,0 @@
|
||||
//===-- TargetAsmInfo.cpp - Asm Info ---------------------------------------==//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines target asm properties related what form asm statements
|
||||
// should take.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "llvm/GlobalVariable.h"
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Type.h"
|
||||
#include "llvm/Target/TargetAsmInfo.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Target/TargetOptions.h"
|
||||
#include "llvm/Support/Dwarf.h"
|
||||
#include <cctype>
|
||||
#include <cstring>
|
||||
using namespace llvm;
|
||||
|
||||
TargetAsmInfo::TargetAsmInfo(const TargetMachine &tm)
|
||||
: TM(tm) {
|
||||
BSSSection = "\t.bss";
|
||||
BSSSection_ = 0;
|
||||
ReadOnlySection = 0;
|
||||
SmallDataSection = 0;
|
||||
SmallBSSSection = 0;
|
||||
SmallRODataSection = 0;
|
||||
TLSDataSection = 0;
|
||||
TLSBSSSection = 0;
|
||||
ZeroFillDirective = 0;
|
||||
NonexecutableStackDirective = 0;
|
||||
NeedsSet = false;
|
||||
MaxInstLength = 4;
|
||||
PCSymbol = "$";
|
||||
SeparatorChar = ';';
|
||||
CommentString = "#";
|
||||
GlobalPrefix = "";
|
||||
PrivateGlobalPrefix = ".";
|
||||
LessPrivateGlobalPrefix = "";
|
||||
JumpTableSpecialLabelPrefix = 0;
|
||||
GlobalVarAddrPrefix = "";
|
||||
GlobalVarAddrSuffix = "";
|
||||
FunctionAddrPrefix = "";
|
||||
FunctionAddrSuffix = "";
|
||||
PersonalityPrefix = "";
|
||||
PersonalitySuffix = "";
|
||||
NeedsIndirectEncoding = false;
|
||||
InlineAsmStart = "#APP";
|
||||
InlineAsmEnd = "#NO_APP";
|
||||
AssemblerDialect = 0;
|
||||
StringConstantPrefix = ".str";
|
||||
AllowQuotesInName = false;
|
||||
ZeroDirective = "\t.zero\t";
|
||||
ZeroDirectiveSuffix = 0;
|
||||
AsciiDirective = "\t.ascii\t";
|
||||
AscizDirective = "\t.asciz\t";
|
||||
Data8bitsDirective = "\t.byte\t";
|
||||
Data16bitsDirective = "\t.short\t";
|
||||
Data32bitsDirective = "\t.long\t";
|
||||
Data64bitsDirective = "\t.quad\t";
|
||||
AlignDirective = "\t.align\t";
|
||||
AlignmentIsInBytes = true;
|
||||
TextAlignFillValue = 0;
|
||||
SwitchToSectionDirective = "\t.section\t";
|
||||
TextSectionStartSuffix = "";
|
||||
DataSectionStartSuffix = "";
|
||||
SectionEndDirectiveSuffix = 0;
|
||||
ConstantPoolSection = "\t.section .rodata";
|
||||
JumpTableDataSection = "\t.section .rodata";
|
||||
JumpTableDirective = 0;
|
||||
CStringSection = 0;
|
||||
CStringSection_ = 0;
|
||||
// FIXME: Flags are ELFish - replace with normal section stuff.
|
||||
StaticCtorsSection = "\t.section .ctors,\"aw\",@progbits";
|
||||
StaticDtorsSection = "\t.section .dtors,\"aw\",@progbits";
|
||||
GlobalDirective = "\t.globl\t";
|
||||
SetDirective = 0;
|
||||
LCOMMDirective = 0;
|
||||
COMMDirective = "\t.comm\t";
|
||||
COMMDirectiveTakesAlignment = true;
|
||||
HasDotTypeDotSizeDirective = true;
|
||||
HasSingleParameterDotFile = true;
|
||||
UsedDirective = 0;
|
||||
WeakRefDirective = 0;
|
||||
WeakDefDirective = 0;
|
||||
// FIXME: These are ELFish - move to ELFTAI.
|
||||
HiddenDirective = "\t.hidden\t";
|
||||
ProtectedDirective = "\t.protected\t";
|
||||
AbsoluteDebugSectionOffsets = false;
|
||||
AbsoluteEHSectionOffsets = false;
|
||||
HasLEB128 = false;
|
||||
HasDotLocAndDotFile = false;
|
||||
SupportsDebugInformation = false;
|
||||
SupportsExceptionHandling = false;
|
||||
DwarfRequiresFrameSection = true;
|
||||
DwarfUsesInlineInfoSection = false;
|
||||
NonLocalEHFrameLabel = false;
|
||||
GlobalEHDirective = 0;
|
||||
SupportsWeakOmittedEHFrame = true;
|
||||
DwarfSectionOffsetDirective = 0;
|
||||
DwarfAbbrevSection = ".debug_abbrev";
|
||||
DwarfInfoSection = ".debug_info";
|
||||
DwarfLineSection = ".debug_line";
|
||||
DwarfFrameSection = ".debug_frame";
|
||||
DwarfPubNamesSection = ".debug_pubnames";
|
||||
DwarfPubTypesSection = ".debug_pubtypes";
|
||||
DwarfDebugInlineSection = ".debug_inlined";
|
||||
DwarfStrSection = ".debug_str";
|
||||
DwarfLocSection = ".debug_loc";
|
||||
DwarfARangesSection = ".debug_aranges";
|
||||
DwarfRangesSection = ".debug_ranges";
|
||||
DwarfMacroInfoSection = ".debug_macinfo";
|
||||
DwarfEHFrameSection = ".eh_frame";
|
||||
DwarfExceptionSection = ".gcc_except_table";
|
||||
AsmTransCBE = 0;
|
||||
TextSection = getUnnamedSection("\t.text", SectionFlags::Code);
|
||||
DataSection = getUnnamedSection("\t.data", SectionFlags::Writeable);
|
||||
}
|
||||
|
||||
TargetAsmInfo::~TargetAsmInfo() {
|
||||
}
|
||||
|
||||
/// Measure the specified inline asm to determine an approximation of its
|
||||
/// length.
|
||||
/// Comments (which run till the next SeparatorChar or newline) do not
|
||||
/// count as an instruction.
|
||||
/// Any other non-whitespace text is considered an instruction, with
|
||||
/// multiple instructions separated by SeparatorChar or newlines.
|
||||
/// Variable-length instructions are not handled here; this function
|
||||
/// may be overloaded in the target code to do that.
|
||||
unsigned TargetAsmInfo::getInlineAsmLength(const char *Str) const {
|
||||
// Count the number of instructions in the asm.
|
||||
bool atInsnStart = true;
|
||||
unsigned Length = 0;
|
||||
for (; *Str; ++Str) {
|
||||
if (*Str == '\n' || *Str == SeparatorChar)
|
||||
atInsnStart = true;
|
||||
if (atInsnStart && !isspace(*Str)) {
|
||||
Length += MaxInstLength;
|
||||
atInsnStart = false;
|
||||
}
|
||||
if (atInsnStart && strncmp(Str, CommentString, strlen(CommentString))==0)
|
||||
atInsnStart = false;
|
||||
}
|
||||
|
||||
return Length;
|
||||
}
|
||||
|
||||
unsigned TargetAsmInfo::PreferredEHDataFormat(DwarfEncoding::Target Reason,
|
||||
bool Global) const {
|
||||
return dwarf::DW_EH_PE_absptr;
|
||||
}
|
||||
|
||||
static bool isSuitableForBSS(const GlobalVariable *GV) {
|
||||
if (!GV->hasInitializer())
|
||||
return true;
|
||||
|
||||
// Leave constant zeros in readonly constant sections, so they can be shared
|
||||
Constant *C = GV->getInitializer();
|
||||
return (C->isNullValue() && !GV->isConstant() && !NoZerosInBSS);
|
||||
}
|
||||
|
||||
static bool isConstantString(const Constant *C) {
|
||||
// First check: is we have constant array of i8 terminated with zero
|
||||
const ConstantArray *CVA = dyn_cast<ConstantArray>(C);
|
||||
// Check, if initializer is a null-terminated string
|
||||
if (CVA && CVA->isCString())
|
||||
return true;
|
||||
|
||||
// Another possibility: [1 x i8] zeroinitializer
|
||||
if (isa<ConstantAggregateZero>(C)) {
|
||||
if (const ArrayType *Ty = dyn_cast<ArrayType>(C->getType())) {
|
||||
return (Ty->getElementType() == Type::Int8Ty &&
|
||||
Ty->getNumElements() == 1);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned TargetAsmInfo::RelocBehaviour() const {
|
||||
// By default - all relocations in PIC mode would force symbol to be
|
||||
// placed in r/w section.
|
||||
return (TM.getRelocationModel() != Reloc::Static ?
|
||||
Reloc::LocalOrGlobal : Reloc::None);
|
||||
}
|
||||
|
||||
SectionKind::Kind
|
||||
TargetAsmInfo::SectionKindForGlobal(const GlobalValue *GV) const {
|
||||
// Early exit - functions should be always in text sections.
|
||||
if (isa<Function>(GV))
|
||||
return SectionKind::Text;
|
||||
|
||||
const GlobalVariable* GVar = dyn_cast<GlobalVariable>(GV);
|
||||
bool isThreadLocal = GVar->isThreadLocal();
|
||||
assert(GVar && "Invalid global value for section selection");
|
||||
|
||||
if (isSuitableForBSS(GVar)) {
|
||||
// Variable can be easily put to BSS section.
|
||||
return (isThreadLocal ? SectionKind::ThreadBSS : SectionKind::BSS);
|
||||
} else if (GVar->isConstant() && !isThreadLocal) {
|
||||
// Now we know, that varible has initializer and it is constant. We need to
|
||||
// check its initializer to decide, which section to output it into. Also
|
||||
// note, there is no thread-local r/o section.
|
||||
Constant *C = GVar->getInitializer();
|
||||
if (C->ContainsRelocations(Reloc::LocalOrGlobal)) {
|
||||
// Decide, whether it is still possible to put symbol into r/o section.
|
||||
unsigned Reloc = RelocBehaviour();
|
||||
|
||||
// We already did a query for 'all' relocs, thus - early exits.
|
||||
if (Reloc == Reloc::LocalOrGlobal)
|
||||
return SectionKind::Data;
|
||||
else if (Reloc == Reloc::None)
|
||||
return SectionKind::ROData;
|
||||
else {
|
||||
// Ok, target wants something funny. Honour it.
|
||||
return (C->ContainsRelocations(Reloc) ?
|
||||
SectionKind::Data : SectionKind::ROData);
|
||||
}
|
||||
} else {
|
||||
// Check, if initializer is a null-terminated string
|
||||
if (isConstantString(C))
|
||||
return SectionKind::RODataMergeStr;
|
||||
else
|
||||
return SectionKind::RODataMergeConst;
|
||||
}
|
||||
}
|
||||
|
||||
// Variable either is not constant or thread-local - output to data section.
|
||||
return (isThreadLocal ? SectionKind::ThreadData : SectionKind::Data);
|
||||
}
|
||||
|
||||
unsigned
|
||||
TargetAsmInfo::SectionFlagsForGlobal(const GlobalValue *GV,
|
||||
const char* Name) const {
|
||||
unsigned Flags = SectionFlags::None;
|
||||
|
||||
// Decode flags from global itself.
|
||||
if (GV) {
|
||||
SectionKind::Kind Kind = SectionKindForGlobal(GV);
|
||||
switch (Kind) {
|
||||
case SectionKind::Text:
|
||||
Flags |= SectionFlags::Code;
|
||||
break;
|
||||
case SectionKind::ThreadData:
|
||||
case SectionKind::ThreadBSS:
|
||||
Flags |= SectionFlags::TLS;
|
||||
// FALLS THROUGH
|
||||
case SectionKind::Data:
|
||||
case SectionKind::DataRel:
|
||||
case SectionKind::DataRelLocal:
|
||||
case SectionKind::DataRelRO:
|
||||
case SectionKind::DataRelROLocal:
|
||||
case SectionKind::BSS:
|
||||
Flags |= SectionFlags::Writeable;
|
||||
break;
|
||||
case SectionKind::ROData:
|
||||
case SectionKind::RODataMergeStr:
|
||||
case SectionKind::RODataMergeConst:
|
||||
// No additional flags here
|
||||
break;
|
||||
case SectionKind::SmallData:
|
||||
case SectionKind::SmallBSS:
|
||||
Flags |= SectionFlags::Writeable;
|
||||
// FALLS THROUGH
|
||||
case SectionKind::SmallROData:
|
||||
Flags |= SectionFlags::Small;
|
||||
break;
|
||||
default:
|
||||
assert(0 && "Unexpected section kind!");
|
||||
}
|
||||
|
||||
if (GV->isWeakForLinker())
|
||||
Flags |= SectionFlags::Linkonce;
|
||||
}
|
||||
|
||||
// Add flags from sections, if any.
|
||||
if (Name && *Name) {
|
||||
Flags |= SectionFlags::Named;
|
||||
|
||||
// Some lame default implementation based on some magic section names.
|
||||
if (strncmp(Name, ".gnu.linkonce.b.", 16) == 0 ||
|
||||
strncmp(Name, ".llvm.linkonce.b.", 17) == 0 ||
|
||||
strncmp(Name, ".gnu.linkonce.sb.", 17) == 0 ||
|
||||
strncmp(Name, ".llvm.linkonce.sb.", 18) == 0)
|
||||
Flags |= SectionFlags::BSS;
|
||||
else if (strcmp(Name, ".tdata") == 0 ||
|
||||
strncmp(Name, ".tdata.", 7) == 0 ||
|
||||
strncmp(Name, ".gnu.linkonce.td.", 17) == 0 ||
|
||||
strncmp(Name, ".llvm.linkonce.td.", 18) == 0)
|
||||
Flags |= SectionFlags::TLS;
|
||||
else if (strcmp(Name, ".tbss") == 0 ||
|
||||
strncmp(Name, ".tbss.", 6) == 0 ||
|
||||
strncmp(Name, ".gnu.linkonce.tb.", 17) == 0 ||
|
||||
strncmp(Name, ".llvm.linkonce.tb.", 18) == 0)
|
||||
Flags |= SectionFlags::BSS | SectionFlags::TLS;
|
||||
}
|
||||
|
||||
return Flags;
|
||||
}
|
||||
|
||||
const Section*
|
||||
TargetAsmInfo::SectionForGlobal(const GlobalValue *GV) const {
|
||||
const Section* S;
|
||||
// Select section name
|
||||
if (GV->hasSection()) {
|
||||
// Honour section already set, if any
|
||||
unsigned Flags = SectionFlagsForGlobal(GV,
|
||||
GV->getSection().c_str());
|
||||
S = getNamedSection(GV->getSection().c_str(), Flags);
|
||||
} else {
|
||||
// Use default section depending on the 'type' of global
|
||||
S = SelectSectionForGlobal(GV);
|
||||
}
|
||||
|
||||
return S;
|
||||
}
|
||||
|
||||
// Lame default implementation. Calculate the section name for global.
|
||||
const Section*
|
||||
TargetAsmInfo::SelectSectionForGlobal(const GlobalValue *GV) const {
|
||||
SectionKind::Kind Kind = SectionKindForGlobal(GV);
|
||||
|
||||
if (GV->isWeakForLinker()) {
|
||||
std::string Name = UniqueSectionForGlobal(GV, Kind);
|
||||
unsigned Flags = SectionFlagsForGlobal(GV, Name.c_str());
|
||||
return getNamedSection(Name.c_str(), Flags);
|
||||
} else {
|
||||
if (Kind == SectionKind::Text)
|
||||
return getTextSection();
|
||||
else if (isBSS(Kind) && getBSSSection_())
|
||||
return getBSSSection_();
|
||||
else if (getReadOnlySection() && SectionKind::isReadOnly(Kind))
|
||||
return getReadOnlySection();
|
||||
}
|
||||
|
||||
return getDataSection();
|
||||
}
|
||||
|
||||
// Lame default implementation. Calculate the section name for machine const.
|
||||
const Section*
|
||||
TargetAsmInfo::SelectSectionForMachineConst(const Type *Ty) const {
|
||||
// FIXME: Support data.rel stuff someday
|
||||
return getDataSection();
|
||||
}
|
||||
|
||||
std::string
|
||||
TargetAsmInfo::UniqueSectionForGlobal(const GlobalValue* GV,
|
||||
SectionKind::Kind Kind) const {
|
||||
switch (Kind) {
|
||||
case SectionKind::Text:
|
||||
return ".gnu.linkonce.t." + GV->getName();
|
||||
case SectionKind::Data:
|
||||
return ".gnu.linkonce.d." + GV->getName();
|
||||
case SectionKind::DataRel:
|
||||
return ".gnu.linkonce.d.rel" + GV->getName();
|
||||
case SectionKind::DataRelLocal:
|
||||
return ".gnu.linkonce.d.rel.local" + GV->getName();
|
||||
case SectionKind::DataRelRO:
|
||||
return ".gnu.linkonce.d.rel.ro" + GV->getName();
|
||||
case SectionKind::DataRelROLocal:
|
||||
return ".gnu.linkonce.d.rel.ro.local" + GV->getName();
|
||||
case SectionKind::SmallData:
|
||||
return ".gnu.linkonce.s." + GV->getName();
|
||||
case SectionKind::BSS:
|
||||
return ".gnu.linkonce.b." + GV->getName();
|
||||
case SectionKind::SmallBSS:
|
||||
return ".gnu.linkonce.sb." + GV->getName();
|
||||
case SectionKind::ROData:
|
||||
case SectionKind::RODataMergeConst:
|
||||
case SectionKind::RODataMergeStr:
|
||||
return ".gnu.linkonce.r." + GV->getName();
|
||||
case SectionKind::SmallROData:
|
||||
return ".gnu.linkonce.s2." + GV->getName();
|
||||
case SectionKind::ThreadData:
|
||||
return ".gnu.linkonce.td." + GV->getName();
|
||||
case SectionKind::ThreadBSS:
|
||||
return ".gnu.linkonce.tb." + GV->getName();
|
||||
default:
|
||||
assert(0 && "Unknown section kind");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const Section*
|
||||
TargetAsmInfo::getNamedSection(const char *Name, unsigned Flags,
|
||||
bool Override) const {
|
||||
Section& S = Sections[Name];
|
||||
|
||||
// This is newly-created section, set it up properly.
|
||||
if (S.Flags == SectionFlags::Invalid || Override) {
|
||||
S.Flags = Flags | SectionFlags::Named;
|
||||
S.Name = Name;
|
||||
}
|
||||
|
||||
return &S;
|
||||
}
|
||||
|
||||
const Section*
|
||||
TargetAsmInfo::getUnnamedSection(const char *Directive, unsigned Flags,
|
||||
bool Override) const {
|
||||
Section& S = Sections[Directive];
|
||||
|
||||
// This is newly-created section, set it up properly.
|
||||
if (S.Flags == SectionFlags::Invalid || Override) {
|
||||
S.Flags = Flags & ~SectionFlags::Named;
|
||||
S.Name = Directive;
|
||||
}
|
||||
|
||||
return &S;
|
||||
}
|
||||
|
||||
const std::string&
|
||||
TargetAsmInfo::getSectionFlags(unsigned Flags) const {
|
||||
SectionFlags::FlagsStringsMapType::iterator I = FlagsStrings.find(Flags);
|
||||
|
||||
// We didn't print these flags yet, print and save them to map. This reduces
|
||||
// amount of heap trashing due to std::string construction / concatenation.
|
||||
if (I == FlagsStrings.end())
|
||||
I = FlagsStrings.insert(std::make_pair(Flags,
|
||||
printSectionFlags(Flags))).first;
|
||||
|
||||
return I->second;
|
||||
}
|
||||
|
||||
unsigned TargetAsmInfo::getULEB128Size(unsigned Value) {
|
||||
unsigned Size = 0;
|
||||
do {
|
||||
Value >>= 7;
|
||||
Size += sizeof(int8_t);
|
||||
} while (Value);
|
||||
return Size;
|
||||
}
|
||||
|
||||
unsigned TargetAsmInfo::getSLEB128Size(int Value) {
|
||||
unsigned Size = 0;
|
||||
int Sign = Value >> (8 * sizeof(Value) - 1);
|
||||
bool IsMore;
|
||||
|
||||
do {
|
||||
unsigned Byte = Value & 0x7f;
|
||||
Value >>= 7;
|
||||
IsMore = Value != Sign || ((Byte ^ Sign) & 0x40) != 0;
|
||||
Size += sizeof(int8_t);
|
||||
} while (IsMore);
|
||||
return Size;
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
//===-- TargetMachineRegistry.cpp - Target Auto Registration Impl ---------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file exposes the RegisterTarget class, which TargetMachine
|
||||
// implementations should use to register themselves with the system. This file
|
||||
// also exposes the TargetMachineRegistry class, which allows tools to inspect
|
||||
// all of registered targets.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Target/TargetMachineRegistry.h"
|
||||
#include <algorithm>
|
||||
using namespace llvm;
|
||||
|
||||
/// getClosestStaticTargetForModule - Given an LLVM module, pick the best target
|
||||
/// that is compatible with the module. If no close target can be found, this
|
||||
/// returns null and sets the Error string to a reason.
|
||||
const TargetMachineRegistry::entry *
|
||||
TargetMachineRegistry::getClosestStaticTargetForModule(const Module &M,
|
||||
std::string &Error) {
|
||||
std::vector<std::pair<unsigned, const entry *> > UsableTargets;
|
||||
for (Registry<TargetMachine>::iterator I = begin(), E = end(); I != E; ++I)
|
||||
if (unsigned Qual = I->ModuleMatchQualityFn(M))
|
||||
UsableTargets.push_back(std::make_pair(Qual, &*I));
|
||||
|
||||
if (UsableTargets.empty()) {
|
||||
Error = "No available targets are compatible with this module";
|
||||
return 0;
|
||||
} else if (UsableTargets.size() == 1)
|
||||
return UsableTargets.back().second;
|
||||
|
||||
// Otherwise, take the best target, but make sure we don't have two equally
|
||||
// good best targets.
|
||||
std::sort(UsableTargets.begin(), UsableTargets.end());
|
||||
if (UsableTargets.back().first ==UsableTargets[UsableTargets.size()-2].first){
|
||||
Error = "Cannot choose between targets \"" +
|
||||
std::string(UsableTargets.back().second->Name) + "\" and \"" +
|
||||
std::string(UsableTargets[UsableTargets.size()-2].second->Name) + "\"";
|
||||
return 0;
|
||||
}
|
||||
return UsableTargets.back().second;
|
||||
}
|
||||
|
||||
/// getClosestTargetForJIT - Pick the best target that is compatible with
|
||||
/// the current host. If no close target can be found, this returns null
|
||||
/// and sets the Error string to a reason.
|
||||
const TargetMachineRegistry::entry *
|
||||
TargetMachineRegistry::getClosestTargetForJIT(std::string &Error) {
|
||||
std::vector<std::pair<unsigned, const entry *> > UsableTargets;
|
||||
for (Registry<TargetMachine>::iterator I = begin(), E = end(); I != E; ++I)
|
||||
if (unsigned Qual = I->JITMatchQualityFn())
|
||||
UsableTargets.push_back(std::make_pair(Qual, &*I));
|
||||
|
||||
if (UsableTargets.empty()) {
|
||||
Error = "No JIT is available for this host";
|
||||
return 0;
|
||||
} else if (UsableTargets.size() == 1)
|
||||
return UsableTargets.back().second;
|
||||
|
||||
// Otherwise, take the best target. If there is a tie, just pick one.
|
||||
unsigned MaxQual = UsableTargets.front().first;
|
||||
const entry *MaxQualTarget = UsableTargets.front().second;
|
||||
|
||||
for (unsigned i = 1, e = UsableTargets.size(); i != e; ++i)
|
||||
if (UsableTargets[i].first > MaxQual) {
|
||||
MaxQual = UsableTargets[i].first;
|
||||
MaxQualTarget = UsableTargets[i].second;
|
||||
}
|
||||
|
||||
return MaxQualTarget;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,226 +0,0 @@
|
||||
//===-- X86ATTAsmPrinter.h - Convert X86 LLVM code to AT&T assembly -------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// AT&T assembly code printer class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef X86ATTASMPRINTER_H
|
||||
#define X86ATTASMPRINTER_H
|
||||
|
||||
#include "../X86.h"
|
||||
#include "../X86MachineFunctionInfo.h"
|
||||
#include "../X86TargetMachine.h"
|
||||
#include "llvm/ADT/StringSet.h"
|
||||
#include "llvm/CodeGen/AsmPrinter.h"
|
||||
#include "llvm/CodeGen/DwarfWriter.h"
|
||||
#include "llvm/CodeGen/MachineModuleInfo.h"
|
||||
#include "llvm/CodeGen/ValueTypes.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MachineJumpTableInfo;
|
||||
class MCContext;
|
||||
class MCInst;
|
||||
class MCStreamer;
|
||||
|
||||
class VISIBILITY_HIDDEN X86ATTAsmPrinter : public AsmPrinter {
|
||||
const X86Subtarget *Subtarget;
|
||||
|
||||
MCContext *Context;
|
||||
MCStreamer *Streamer;
|
||||
public:
|
||||
explicit X86ATTAsmPrinter(raw_ostream &O, X86TargetMachine &TM,
|
||||
const TargetAsmInfo *T, bool V)
|
||||
: AsmPrinter(O, TM, T, V) {
|
||||
Subtarget = &TM.getSubtarget<X86Subtarget>();
|
||||
Context = 0;
|
||||
Streamer = 0;
|
||||
}
|
||||
|
||||
virtual const char *getPassName() const {
|
||||
return "X86 AT&T-Style Assembly Printer";
|
||||
}
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.setPreservesAll();
|
||||
if (Subtarget->isTargetDarwin() ||
|
||||
Subtarget->isTargetELF() ||
|
||||
Subtarget->isTargetCygMing()) {
|
||||
AU.addRequired<MachineModuleInfo>();
|
||||
}
|
||||
AU.addRequired<DwarfWriter>();
|
||||
AsmPrinter::getAnalysisUsage(AU);
|
||||
}
|
||||
|
||||
bool doInitialization(Module &M);
|
||||
bool doFinalization(Module &M);
|
||||
|
||||
/// printInstruction - This method is automatically generated by tablegen
|
||||
/// from the instruction set description. This method returns true if the
|
||||
/// machine instruction was sufficiently described to print it, otherwise it
|
||||
/// returns false.
|
||||
bool printInstruction(const MachineInstr *MI);
|
||||
|
||||
|
||||
// New MCInst printing stuff.
|
||||
bool printInstruction(const MCInst *MI);
|
||||
|
||||
void printOperand(const MCInst *MI, unsigned OpNo,
|
||||
const char *Modifier = 0);
|
||||
void printMemReference(const MCInst *MI, unsigned Op);
|
||||
void printLeaMemReference(const MCInst *MI, unsigned Op);
|
||||
void printSSECC(const MCInst *MI, unsigned Op);
|
||||
void printPICLabel(const MCInst *MI, unsigned Op);
|
||||
void print_pcrel_imm(const MCInst *MI, unsigned OpNo);
|
||||
|
||||
void printi8mem(const MCInst *MI, unsigned OpNo) {
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printi16mem(const MCInst *MI, unsigned OpNo) {
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printi32mem(const MCInst *MI, unsigned OpNo) {
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printi64mem(const MCInst *MI, unsigned OpNo) {
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printi128mem(const MCInst *MI, unsigned OpNo) {
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printf32mem(const MCInst *MI, unsigned OpNo) {
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printf64mem(const MCInst *MI, unsigned OpNo) {
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printf80mem(const MCInst *MI, unsigned OpNo) {
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printf128mem(const MCInst *MI, unsigned OpNo) {
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printlea32mem(const MCInst *MI, unsigned OpNo) {
|
||||
printLeaMemReference(MI, OpNo);
|
||||
}
|
||||
void printlea64mem(const MCInst *MI, unsigned OpNo) {
|
||||
printLeaMemReference(MI, OpNo);
|
||||
}
|
||||
void printlea64_32mem(const MCInst *MI, unsigned OpNo) {
|
||||
printLeaMemReference(MI, OpNo);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// These methods are used by the tablegen'erated instruction printer.
|
||||
void printOperand(const MachineInstr *MI, unsigned OpNo,
|
||||
const char *Modifier = 0);
|
||||
void print_pcrel_imm(const MachineInstr *MI, unsigned OpNo);
|
||||
void printi8mem(const MachineInstr *MI, unsigned OpNo) {
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printi16mem(const MachineInstr *MI, unsigned OpNo) {
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printi32mem(const MachineInstr *MI, unsigned OpNo) {
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printi64mem(const MachineInstr *MI, unsigned OpNo) {
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printi128mem(const MachineInstr *MI, unsigned OpNo) {
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printi256mem(const MachineInstr *MI, unsigned OpNo) {
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printf32mem(const MachineInstr *MI, unsigned OpNo) {
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printf64mem(const MachineInstr *MI, unsigned OpNo) {
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printf80mem(const MachineInstr *MI, unsigned OpNo) {
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printf128mem(const MachineInstr *MI, unsigned OpNo) {
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printf256mem(const MachineInstr *MI, unsigned OpNo) {
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printlea32mem(const MachineInstr *MI, unsigned OpNo) {
|
||||
printLeaMemReference(MI, OpNo);
|
||||
}
|
||||
void printlea64mem(const MachineInstr *MI, unsigned OpNo) {
|
||||
printLeaMemReference(MI, OpNo);
|
||||
}
|
||||
void printlea64_32mem(const MachineInstr *MI, unsigned OpNo) {
|
||||
printLeaMemReference(MI, OpNo, "subreg64");
|
||||
}
|
||||
|
||||
bool printAsmMRegister(const MachineOperand &MO, char Mode);
|
||||
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
|
||||
unsigned AsmVariant, const char *ExtraCode);
|
||||
bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
|
||||
unsigned AsmVariant, const char *ExtraCode);
|
||||
|
||||
void printMachineInstruction(const MachineInstr *MI);
|
||||
void printSSECC(const MachineInstr *MI, unsigned Op);
|
||||
void printMemReference(const MachineInstr *MI, unsigned Op,
|
||||
const char *Modifier=NULL);
|
||||
void printLeaMemReference(const MachineInstr *MI, unsigned Op,
|
||||
const char *Modifier=NULL);
|
||||
void printPICJumpTableSetLabel(unsigned uid,
|
||||
const MachineBasicBlock *MBB) const;
|
||||
void printPICJumpTableSetLabel(unsigned uid, unsigned uid2,
|
||||
const MachineBasicBlock *MBB) const {
|
||||
AsmPrinter::printPICJumpTableSetLabel(uid, uid2, MBB);
|
||||
}
|
||||
void printPICJumpTableEntry(const MachineJumpTableInfo *MJTI,
|
||||
const MachineBasicBlock *MBB,
|
||||
unsigned uid) const;
|
||||
|
||||
void printPICLabel(const MachineInstr *MI, unsigned Op);
|
||||
void printModuleLevelGV(const GlobalVariable* GVar);
|
||||
|
||||
void PrintPICBaseSymbol() const;
|
||||
|
||||
bool runOnMachineFunction(MachineFunction &F);
|
||||
|
||||
void emitFunctionHeader(const MachineFunction &MF);
|
||||
|
||||
// Necessary for Darwin to print out the apprioriate types of linker stubs
|
||||
StringSet<> FnStubs, GVStubs, HiddenGVStubs;
|
||||
|
||||
// Necessary for dllexport support
|
||||
StringSet<> DLLExportedFns, DLLExportedGVs;
|
||||
|
||||
// We have to propagate some information about MachineFunction to
|
||||
// AsmPrinter. It's ok, when we're printing the function, since we have
|
||||
// access to MachineFunction and can get the appropriate MachineFunctionInfo.
|
||||
// Unfortunately, this is not possible when we're printing reference to
|
||||
// Function (e.g. calling it and so on). Even more, there is no way to get the
|
||||
// corresponding MachineFunctions: it can even be not created at all. That's
|
||||
// why we should use additional structure, when we're collecting all necessary
|
||||
// information.
|
||||
//
|
||||
// This structure is using e.g. for name decoration for stdcall & fastcall'ed
|
||||
// function, since we have to use arguments' size for decoration.
|
||||
typedef std::map<const Function*, X86MachineFunctionInfo> FMFInfoMap;
|
||||
FMFInfoMap FunctionInfoMap;
|
||||
|
||||
void decorateName(std::string& Name, const GlobalValue* GV);
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
@ -1,633 +0,0 @@
|
||||
//===-- X86IntelAsmPrinter.cpp - Convert X86 LLVM code to Intel assembly --===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains a printer that converts from our internal representation
|
||||
// of machine-dependent LLVM code to Intel format assembly language.
|
||||
// This printer is the output mechanism used by `llc'.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define DEBUG_TYPE "asm-printer"
|
||||
#include "X86IntelAsmPrinter.h"
|
||||
#include "X86InstrInfo.h"
|
||||
#include "X86TargetAsmInfo.h"
|
||||
#include "X86.h"
|
||||
#include "llvm/CallingConv.h"
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/Assembly/Writer.h"
|
||||
#include "llvm/CodeGen/DwarfWriter.h"
|
||||
#include "llvm/Support/Mangler.h"
|
||||
#include "llvm/Target/TargetAsmInfo.h"
|
||||
#include "llvm/Target/TargetOptions.h"
|
||||
using namespace llvm;
|
||||
|
||||
STATISTIC(EmittedInsts, "Number of machine instrs printed");
|
||||
|
||||
static X86MachineFunctionInfo calculateFunctionInfo(const Function *F,
|
||||
const TargetData *TD) {
|
||||
X86MachineFunctionInfo Info;
|
||||
uint64_t Size = 0;
|
||||
|
||||
switch (F->getCallingConv()) {
|
||||
case CallingConv::X86_StdCall:
|
||||
Info.setDecorationStyle(StdCall);
|
||||
break;
|
||||
case CallingConv::X86_FastCall:
|
||||
Info.setDecorationStyle(FastCall);
|
||||
break;
|
||||
default:
|
||||
return Info;
|
||||
}
|
||||
|
||||
unsigned argNum = 1;
|
||||
for (Function::const_arg_iterator AI = F->arg_begin(), AE = F->arg_end();
|
||||
AI != AE; ++AI, ++argNum) {
|
||||
const Type* Ty = AI->getType();
|
||||
|
||||
// 'Dereference' type in case of byval parameter attribute
|
||||
if (F->paramHasAttr(argNum, Attribute::ByVal))
|
||||
Ty = cast<PointerType>(Ty)->getElementType();
|
||||
|
||||
// Size should be aligned to DWORD boundary
|
||||
Size += ((TD->getTypeAllocSize(Ty) + 3)/4)*4;
|
||||
}
|
||||
|
||||
// We're not supporting tooooo huge arguments :)
|
||||
Info.setBytesToPopOnReturn((unsigned int)Size);
|
||||
return Info;
|
||||
}
|
||||
|
||||
|
||||
/// decorateName - Query FunctionInfoMap and use this information for various
|
||||
/// name decoration.
|
||||
void X86IntelAsmPrinter::decorateName(std::string &Name,
|
||||
const GlobalValue *GV) {
|
||||
const Function *F = dyn_cast<Function>(GV);
|
||||
if (!F) return;
|
||||
|
||||
// We don't want to decorate non-stdcall or non-fastcall functions right now
|
||||
unsigned CC = F->getCallingConv();
|
||||
if (CC != CallingConv::X86_StdCall && CC != CallingConv::X86_FastCall)
|
||||
return;
|
||||
|
||||
FMFInfoMap::const_iterator info_item = FunctionInfoMap.find(F);
|
||||
|
||||
const X86MachineFunctionInfo *Info;
|
||||
if (info_item == FunctionInfoMap.end()) {
|
||||
// Calculate apropriate function info and populate map
|
||||
FunctionInfoMap[F] = calculateFunctionInfo(F, TM.getTargetData());
|
||||
Info = &FunctionInfoMap[F];
|
||||
} else {
|
||||
Info = &info_item->second;
|
||||
}
|
||||
|
||||
const FunctionType *FT = F->getFunctionType();
|
||||
switch (Info->getDecorationStyle()) {
|
||||
case None:
|
||||
break;
|
||||
case StdCall:
|
||||
// "Pure" variadic functions do not receive @0 suffix.
|
||||
if (!FT->isVarArg() || (FT->getNumParams() == 0) ||
|
||||
(FT->getNumParams() == 1 && F->hasStructRetAttr()))
|
||||
Name += '@' + utostr_32(Info->getBytesToPopOnReturn());
|
||||
break;
|
||||
case FastCall:
|
||||
// "Pure" variadic functions do not receive @0 suffix.
|
||||
if (!FT->isVarArg() || (FT->getNumParams() == 0) ||
|
||||
(FT->getNumParams() == 1 && F->hasStructRetAttr()))
|
||||
Name += '@' + utostr_32(Info->getBytesToPopOnReturn());
|
||||
|
||||
if (Name[0] == '_')
|
||||
Name[0] = '@';
|
||||
else
|
||||
Name = '@' + Name;
|
||||
|
||||
break;
|
||||
default:
|
||||
assert(0 && "Unsupported DecorationStyle");
|
||||
}
|
||||
}
|
||||
|
||||
/// runOnMachineFunction - This uses the printMachineInstruction()
|
||||
/// method to print assembly for each instruction.
|
||||
///
|
||||
bool X86IntelAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
|
||||
this->MF = &MF;
|
||||
SetupMachineFunction(MF);
|
||||
O << "\n\n";
|
||||
|
||||
// Print out constants referenced by the function
|
||||
EmitConstantPool(MF.getConstantPool());
|
||||
|
||||
// Print out labels for the function.
|
||||
const Function *F = MF.getFunction();
|
||||
unsigned CC = F->getCallingConv();
|
||||
unsigned FnAlign = MF.getAlignment();
|
||||
|
||||
// Populate function information map. Actually, We don't want to populate
|
||||
// non-stdcall or non-fastcall functions' information right now.
|
||||
if (CC == CallingConv::X86_StdCall || CC == CallingConv::X86_FastCall)
|
||||
FunctionInfoMap[F] = *MF.getInfo<X86MachineFunctionInfo>();
|
||||
|
||||
decorateName(CurrentFnName, F);
|
||||
|
||||
SwitchToTextSection("_text", F);
|
||||
switch (F->getLinkage()) {
|
||||
default: assert(0 && "Unsupported linkage type!");
|
||||
case Function::PrivateLinkage:
|
||||
case Function::InternalLinkage:
|
||||
EmitAlignment(FnAlign);
|
||||
break;
|
||||
case Function::DLLExportLinkage:
|
||||
DLLExportedFns.insert(CurrentFnName);
|
||||
//FALLS THROUGH
|
||||
case Function::ExternalLinkage:
|
||||
O << "\tpublic " << CurrentFnName << "\n";
|
||||
EmitAlignment(FnAlign);
|
||||
break;
|
||||
}
|
||||
|
||||
O << CurrentFnName << "\tproc near\n";
|
||||
|
||||
// Print out code for the function.
|
||||
for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
|
||||
I != E; ++I) {
|
||||
// Print a label for the basic block if there are any predecessors.
|
||||
if (!I->pred_empty()) {
|
||||
printBasicBlockLabel(I, true, true);
|
||||
O << '\n';
|
||||
}
|
||||
for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
|
||||
II != E; ++II) {
|
||||
// Print the assembly for the instruction.
|
||||
printMachineInstruction(II);
|
||||
}
|
||||
}
|
||||
|
||||
// Print out jump tables referenced by the function.
|
||||
EmitJumpTableInfo(MF.getJumpTableInfo(), MF);
|
||||
|
||||
O << CurrentFnName << "\tendp\n";
|
||||
|
||||
O.flush();
|
||||
|
||||
// We didn't modify anything.
|
||||
return false;
|
||||
}
|
||||
|
||||
void X86IntelAsmPrinter::printSSECC(const MachineInstr *MI, unsigned Op) {
|
||||
unsigned char value = MI->getOperand(Op).getImm();
|
||||
assert(value <= 7 && "Invalid ssecc argument!");
|
||||
switch (value) {
|
||||
case 0: O << "eq"; break;
|
||||
case 1: O << "lt"; break;
|
||||
case 2: O << "le"; break;
|
||||
case 3: O << "unord"; break;
|
||||
case 4: O << "neq"; break;
|
||||
case 5: O << "nlt"; break;
|
||||
case 6: O << "nle"; break;
|
||||
case 7: O << "ord"; break;
|
||||
}
|
||||
}
|
||||
|
||||
void X86IntelAsmPrinter::printOp(const MachineOperand &MO,
|
||||
const char *Modifier) {
|
||||
switch (MO.getType()) {
|
||||
case MachineOperand::MO_Register: {
|
||||
if (TargetRegisterInfo::isPhysicalRegister(MO.getReg())) {
|
||||
unsigned Reg = MO.getReg();
|
||||
if (Modifier && strncmp(Modifier, "subreg", strlen("subreg")) == 0) {
|
||||
MVT VT = (strcmp(Modifier,"subreg64") == 0) ?
|
||||
MVT::i64 : ((strcmp(Modifier, "subreg32") == 0) ? MVT::i32 :
|
||||
((strcmp(Modifier,"subreg16") == 0) ? MVT::i16 :MVT::i8));
|
||||
Reg = getX86SubSuperRegister(Reg, VT);
|
||||
}
|
||||
O << TRI->getName(Reg);
|
||||
} else
|
||||
O << "reg" << MO.getReg();
|
||||
return;
|
||||
}
|
||||
case MachineOperand::MO_Immediate:
|
||||
O << MO.getImm();
|
||||
return;
|
||||
case MachineOperand::MO_JumpTableIndex: {
|
||||
bool isMemOp = Modifier && !strcmp(Modifier, "mem");
|
||||
if (!isMemOp) O << "OFFSET ";
|
||||
O << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
|
||||
<< "_" << MO.getIndex();
|
||||
return;
|
||||
}
|
||||
case MachineOperand::MO_ConstantPoolIndex: {
|
||||
bool isMemOp = Modifier && !strcmp(Modifier, "mem");
|
||||
if (!isMemOp) O << "OFFSET ";
|
||||
O << "[" << TAI->getPrivateGlobalPrefix() << "CPI"
|
||||
<< getFunctionNumber() << "_" << MO.getIndex();
|
||||
printOffset(MO.getOffset());
|
||||
O << "]";
|
||||
return;
|
||||
}
|
||||
case MachineOperand::MO_GlobalAddress: {
|
||||
bool isMemOp = Modifier && !strcmp(Modifier, "mem");
|
||||
GlobalValue *GV = MO.getGlobal();
|
||||
std::string Name = Mang->getValueName(GV);
|
||||
|
||||
decorateName(Name, GV);
|
||||
|
||||
if (!isMemOp) O << "OFFSET ";
|
||||
if (GV->hasDLLImportLinkage()) {
|
||||
// FIXME: This should be fixed with full support of stdcall & fastcall
|
||||
// CC's
|
||||
O << "__imp_";
|
||||
}
|
||||
O << Name;
|
||||
printOffset(MO.getOffset());
|
||||
return;
|
||||
}
|
||||
case MachineOperand::MO_ExternalSymbol: {
|
||||
O << TAI->getGlobalPrefix() << MO.getSymbolName();
|
||||
return;
|
||||
}
|
||||
default:
|
||||
O << "<unknown operand type>"; return;
|
||||
}
|
||||
}
|
||||
|
||||
void X86IntelAsmPrinter::print_pcrel_imm(const MachineInstr *MI, unsigned OpNo){
|
||||
const MachineOperand &MO = MI->getOperand(OpNo);
|
||||
switch (MO.getType()) {
|
||||
default: assert(0 && "Unknown pcrel immediate operand");
|
||||
case MachineOperand::MO_Immediate:
|
||||
O << MO.getImm();
|
||||
return;
|
||||
case MachineOperand::MO_MachineBasicBlock:
|
||||
printBasicBlockLabel(MO.getMBB());
|
||||
return;
|
||||
|
||||
case MachineOperand::MO_GlobalAddress: {
|
||||
GlobalValue *GV = MO.getGlobal();
|
||||
std::string Name = Mang->getValueName(GV);
|
||||
decorateName(Name, GV);
|
||||
|
||||
if (GV->hasDLLImportLinkage()) {
|
||||
// FIXME: This should be fixed with full support of stdcall & fastcall
|
||||
// CC's
|
||||
O << "__imp_";
|
||||
}
|
||||
O << Name;
|
||||
printOffset(MO.getOffset());
|
||||
return;
|
||||
}
|
||||
|
||||
case MachineOperand::MO_ExternalSymbol:
|
||||
O << TAI->getGlobalPrefix() << MO.getSymbolName();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void X86IntelAsmPrinter::printLeaMemReference(const MachineInstr *MI,
|
||||
unsigned Op,
|
||||
const char *Modifier) {
|
||||
const MachineOperand &BaseReg = MI->getOperand(Op);
|
||||
int ScaleVal = MI->getOperand(Op+1).getImm();
|
||||
const MachineOperand &IndexReg = MI->getOperand(Op+2);
|
||||
const MachineOperand &DispSpec = MI->getOperand(Op+3);
|
||||
|
||||
O << "[";
|
||||
bool NeedPlus = false;
|
||||
if (BaseReg.getReg()) {
|
||||
printOp(BaseReg, Modifier);
|
||||
NeedPlus = true;
|
||||
}
|
||||
|
||||
if (IndexReg.getReg()) {
|
||||
if (NeedPlus) O << " + ";
|
||||
if (ScaleVal != 1)
|
||||
O << ScaleVal << "*";
|
||||
printOp(IndexReg, Modifier);
|
||||
NeedPlus = true;
|
||||
}
|
||||
|
||||
if (DispSpec.isGlobal() || DispSpec.isCPI() ||
|
||||
DispSpec.isJTI()) {
|
||||
if (NeedPlus)
|
||||
O << " + ";
|
||||
printOp(DispSpec, "mem");
|
||||
} else {
|
||||
int DispVal = DispSpec.getImm();
|
||||
if (DispVal || (!BaseReg.getReg() && !IndexReg.getReg())) {
|
||||
if (NeedPlus) {
|
||||
if (DispVal > 0)
|
||||
O << " + ";
|
||||
else {
|
||||
O << " - ";
|
||||
DispVal = -DispVal;
|
||||
}
|
||||
}
|
||||
O << DispVal;
|
||||
}
|
||||
}
|
||||
O << "]";
|
||||
}
|
||||
|
||||
void X86IntelAsmPrinter::printMemReference(const MachineInstr *MI, unsigned Op,
|
||||
const char *Modifier) {
|
||||
assert(isMem(MI, Op) && "Invalid memory reference!");
|
||||
MachineOperand Segment = MI->getOperand(Op+4);
|
||||
if (Segment.getReg()) {
|
||||
printOperand(MI, Op+4, Modifier);
|
||||
O << ':';
|
||||
}
|
||||
printLeaMemReference(MI, Op, Modifier);
|
||||
}
|
||||
|
||||
void X86IntelAsmPrinter::printPICJumpTableSetLabel(unsigned uid,
|
||||
const MachineBasicBlock *MBB) const {
|
||||
if (!TAI->getSetDirective())
|
||||
return;
|
||||
|
||||
O << TAI->getSetDirective() << ' ' << TAI->getPrivateGlobalPrefix()
|
||||
<< getFunctionNumber() << '_' << uid << "_set_" << MBB->getNumber() << ',';
|
||||
printBasicBlockLabel(MBB, false, false, false);
|
||||
O << '-' << "\"L" << getFunctionNumber() << "$pb\"'\n";
|
||||
}
|
||||
|
||||
void X86IntelAsmPrinter::printPICLabel(const MachineInstr *MI, unsigned Op) {
|
||||
O << "L" << getFunctionNumber() << "$pb\n";
|
||||
O << "L" << getFunctionNumber() << "$pb:";
|
||||
}
|
||||
|
||||
bool X86IntelAsmPrinter::printAsmMRegister(const MachineOperand &MO,
|
||||
const char Mode) {
|
||||
unsigned Reg = MO.getReg();
|
||||
switch (Mode) {
|
||||
default: return true; // Unknown mode.
|
||||
case 'b': // Print QImode register
|
||||
Reg = getX86SubSuperRegister(Reg, MVT::i8);
|
||||
break;
|
||||
case 'h': // Print QImode high register
|
||||
Reg = getX86SubSuperRegister(Reg, MVT::i8, true);
|
||||
break;
|
||||
case 'w': // Print HImode register
|
||||
Reg = getX86SubSuperRegister(Reg, MVT::i16);
|
||||
break;
|
||||
case 'k': // Print SImode register
|
||||
Reg = getX86SubSuperRegister(Reg, MVT::i32);
|
||||
break;
|
||||
}
|
||||
|
||||
O << TRI->getName(Reg);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// PrintAsmOperand - Print out an operand for an inline asm expression.
|
||||
///
|
||||
bool X86IntelAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
|
||||
unsigned AsmVariant,
|
||||
const char *ExtraCode) {
|
||||
// Does this asm operand have a single letter operand modifier?
|
||||
if (ExtraCode && ExtraCode[0]) {
|
||||
if (ExtraCode[1] != 0) return true; // Unknown modifier.
|
||||
|
||||
switch (ExtraCode[0]) {
|
||||
default: return true; // Unknown modifier.
|
||||
case 'b': // Print QImode register
|
||||
case 'h': // Print QImode high register
|
||||
case 'w': // Print HImode register
|
||||
case 'k': // Print SImode register
|
||||
return printAsmMRegister(MI->getOperand(OpNo), ExtraCode[0]);
|
||||
}
|
||||
}
|
||||
|
||||
printOperand(MI, OpNo);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool X86IntelAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
|
||||
unsigned OpNo,
|
||||
unsigned AsmVariant,
|
||||
const char *ExtraCode) {
|
||||
if (ExtraCode && ExtraCode[0])
|
||||
return true; // Unknown modifier.
|
||||
printMemReference(MI, OpNo);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// printMachineInstruction -- Print out a single X86 LLVM instruction
|
||||
/// MI in Intel syntax to the current output stream.
|
||||
///
|
||||
void X86IntelAsmPrinter::printMachineInstruction(const MachineInstr *MI) {
|
||||
++EmittedInsts;
|
||||
|
||||
// Call the autogenerated instruction printer routines.
|
||||
printInstruction(MI);
|
||||
}
|
||||
|
||||
bool X86IntelAsmPrinter::doInitialization(Module &M) {
|
||||
bool Result = AsmPrinter::doInitialization(M);
|
||||
|
||||
Mang->markCharUnacceptable('.');
|
||||
|
||||
O << "\t.686\n\t.MMX\n\t.XMM\n\t.model flat\n\n";
|
||||
|
||||
// Emit declarations for external functions.
|
||||
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
|
||||
if (I->isDeclaration()) {
|
||||
std::string Name = Mang->getValueName(I);
|
||||
decorateName(Name, I);
|
||||
|
||||
O << "\tEXTERN " ;
|
||||
if (I->hasDLLImportLinkage()) {
|
||||
O << "__imp_";
|
||||
}
|
||||
O << Name << ":near\n";
|
||||
}
|
||||
|
||||
// Emit declarations for external globals. Note that VC++ always declares
|
||||
// external globals to have type byte, and if that's good enough for VC++...
|
||||
for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
|
||||
I != E; ++I) {
|
||||
if (I->isDeclaration()) {
|
||||
std::string Name = Mang->getValueName(I);
|
||||
|
||||
O << "\tEXTERN " ;
|
||||
if (I->hasDLLImportLinkage()) {
|
||||
O << "__imp_";
|
||||
}
|
||||
O << Name << ":byte\n";
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
bool X86IntelAsmPrinter::doFinalization(Module &M) {
|
||||
const TargetData *TD = TM.getTargetData();
|
||||
|
||||
// Print out module-level global variables here.
|
||||
for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
|
||||
I != E; ++I) {
|
||||
if (I->isDeclaration()) continue; // External global require no code
|
||||
|
||||
// Check to see if this is a special global used by LLVM, if so, emit it.
|
||||
if (EmitSpecialLLVMGlobal(I))
|
||||
continue;
|
||||
|
||||
std::string name = Mang->getValueName(I);
|
||||
Constant *C = I->getInitializer();
|
||||
unsigned Align = TD->getPreferredAlignmentLog(I);
|
||||
bool bCustomSegment = false;
|
||||
|
||||
switch (I->getLinkage()) {
|
||||
case GlobalValue::CommonLinkage:
|
||||
case GlobalValue::LinkOnceAnyLinkage:
|
||||
case GlobalValue::LinkOnceODRLinkage:
|
||||
case GlobalValue::WeakAnyLinkage:
|
||||
case GlobalValue::WeakODRLinkage:
|
||||
SwitchToDataSection("");
|
||||
O << name << "?\tSEGEMNT PARA common 'COMMON'\n";
|
||||
bCustomSegment = true;
|
||||
// FIXME: the default alignment is 16 bytes, but 1, 2, 4, and 256
|
||||
// are also available.
|
||||
break;
|
||||
case GlobalValue::AppendingLinkage:
|
||||
SwitchToDataSection("");
|
||||
O << name << "?\tSEGMENT PARA public 'DATA'\n";
|
||||
bCustomSegment = true;
|
||||
// FIXME: the default alignment is 16 bytes, but 1, 2, 4, and 256
|
||||
// are also available.
|
||||
break;
|
||||
case GlobalValue::DLLExportLinkage:
|
||||
DLLExportedGVs.insert(name);
|
||||
// FALL THROUGH
|
||||
case GlobalValue::ExternalLinkage:
|
||||
O << "\tpublic " << name << "\n";
|
||||
// FALL THROUGH
|
||||
case GlobalValue::InternalLinkage:
|
||||
SwitchToSection(TAI->getDataSection());
|
||||
break;
|
||||
default:
|
||||
assert(0 && "Unknown linkage type!");
|
||||
}
|
||||
|
||||
if (!bCustomSegment)
|
||||
EmitAlignment(Align, I);
|
||||
|
||||
O << name << ":";
|
||||
if (VerboseAsm)
|
||||
O << "\t\t\t\t" << TAI->getCommentString()
|
||||
<< " " << I->getName();
|
||||
O << '\n';
|
||||
|
||||
EmitGlobalConstant(C);
|
||||
|
||||
if (bCustomSegment)
|
||||
O << name << "?\tends\n";
|
||||
}
|
||||
|
||||
// Output linker support code for dllexported globals
|
||||
if (!DLLExportedGVs.empty() || !DLLExportedFns.empty()) {
|
||||
SwitchToDataSection("");
|
||||
O << "; WARNING: The following code is valid only with MASM v8.x"
|
||||
<< "and (possible) higher\n"
|
||||
<< "; This version of MASM is usually shipped with Microsoft "
|
||||
<< "Visual Studio 2005\n"
|
||||
<< "; or (possible) further versions. Unfortunately, there is no "
|
||||
<< "way to support\n"
|
||||
<< "; dllexported symbols in the earlier versions of MASM in fully "
|
||||
<< "automatic way\n\n";
|
||||
O << "_drectve\t segment info alias('.drectve')\n";
|
||||
}
|
||||
|
||||
for (StringSet<>::iterator i = DLLExportedGVs.begin(),
|
||||
e = DLLExportedGVs.end();
|
||||
i != e; ++i)
|
||||
O << "\t db ' /EXPORT:" << i->getKeyData() << ",data'\n";
|
||||
|
||||
for (StringSet<>::iterator i = DLLExportedFns.begin(),
|
||||
e = DLLExportedFns.end();
|
||||
i != e; ++i)
|
||||
O << "\t db ' /EXPORT:" << i->getKeyData() << "'\n";
|
||||
|
||||
if (!DLLExportedGVs.empty() || !DLLExportedFns.empty())
|
||||
O << "_drectve\t ends\n";
|
||||
|
||||
// Bypass X86SharedAsmPrinter::doFinalization().
|
||||
bool Result = AsmPrinter::doFinalization(M);
|
||||
SwitchToDataSection("");
|
||||
O << "\tend\n";
|
||||
return Result;
|
||||
}
|
||||
|
||||
void X86IntelAsmPrinter::EmitString(const ConstantArray *CVA) const {
|
||||
unsigned NumElts = CVA->getNumOperands();
|
||||
if (NumElts) {
|
||||
// ML does not have escape sequences except '' for '. It also has a maximum
|
||||
// string length of 255.
|
||||
unsigned len = 0;
|
||||
bool inString = false;
|
||||
for (unsigned i = 0; i < NumElts; i++) {
|
||||
int n = cast<ConstantInt>(CVA->getOperand(i))->getZExtValue() & 255;
|
||||
if (len == 0)
|
||||
O << "\tdb ";
|
||||
|
||||
if (n >= 32 && n <= 127) {
|
||||
if (!inString) {
|
||||
if (len > 0) {
|
||||
O << ",'";
|
||||
len += 2;
|
||||
} else {
|
||||
O << "'";
|
||||
len++;
|
||||
}
|
||||
inString = true;
|
||||
}
|
||||
if (n == '\'') {
|
||||
O << "'";
|
||||
len++;
|
||||
}
|
||||
O << char(n);
|
||||
} else {
|
||||
if (inString) {
|
||||
O << "'";
|
||||
len++;
|
||||
inString = false;
|
||||
}
|
||||
if (len > 0) {
|
||||
O << ",";
|
||||
len++;
|
||||
}
|
||||
O << n;
|
||||
len += 1 + (n > 9) + (n > 99);
|
||||
}
|
||||
|
||||
if (len > 60) {
|
||||
if (inString) {
|
||||
O << "'";
|
||||
inString = false;
|
||||
}
|
||||
O << "\n";
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (len > 0) {
|
||||
if (inString)
|
||||
O << "'";
|
||||
O << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Include the auto-generated portion of the assembly writer.
|
||||
#include "X86GenAsmWriter1.inc"
|
@ -1,162 +0,0 @@
|
||||
//===-- X86IntelAsmPrinter.h - Convert X86 LLVM code to Intel assembly ----===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Intel assembly code printer class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef X86INTELASMPRINTER_H
|
||||
#define X86INTELASMPRINTER_H
|
||||
|
||||
#include "../X86.h"
|
||||
#include "../X86MachineFunctionInfo.h"
|
||||
#include "../X86TargetMachine.h"
|
||||
#include "llvm/CodeGen/AsmPrinter.h"
|
||||
#include "llvm/ADT/StringSet.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
struct VISIBILITY_HIDDEN X86IntelAsmPrinter : public AsmPrinter {
|
||||
explicit X86IntelAsmPrinter(raw_ostream &O, X86TargetMachine &TM,
|
||||
const TargetAsmInfo *T, bool V)
|
||||
: AsmPrinter(O, TM, T, V) {}
|
||||
|
||||
virtual const char *getPassName() const {
|
||||
return "X86 Intel-Style Assembly Printer";
|
||||
}
|
||||
|
||||
/// printInstruction - This method is automatically generated by tablegen
|
||||
/// from the instruction set description. This method returns true if the
|
||||
/// machine instruction was sufficiently described to print it, otherwise it
|
||||
/// returns false.
|
||||
bool printInstruction(const MachineInstr *MI);
|
||||
|
||||
// This method is used by the tablegen'erated instruction printer.
|
||||
void printOperand(const MachineInstr *MI, unsigned OpNo,
|
||||
const char *Modifier = 0) {
|
||||
const MachineOperand &MO = MI->getOperand(OpNo);
|
||||
if (MO.isReg()) {
|
||||
assert(TargetRegisterInfo::isPhysicalRegister(MO.getReg()) &&
|
||||
"Not physreg??");
|
||||
O << TM.getRegisterInfo()->get(MO.getReg()).Name; // Capitalized names
|
||||
} else {
|
||||
printOp(MO, Modifier);
|
||||
}
|
||||
}
|
||||
|
||||
void print_pcrel_imm(const MachineInstr *MI, unsigned OpNo);
|
||||
|
||||
|
||||
void printi8mem(const MachineInstr *MI, unsigned OpNo) {
|
||||
O << "BYTE PTR ";
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printi16mem(const MachineInstr *MI, unsigned OpNo) {
|
||||
O << "WORD PTR ";
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printi32mem(const MachineInstr *MI, unsigned OpNo) {
|
||||
O << "DWORD PTR ";
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printi64mem(const MachineInstr *MI, unsigned OpNo) {
|
||||
O << "QWORD PTR ";
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printi128mem(const MachineInstr *MI, unsigned OpNo) {
|
||||
O << "XMMWORD PTR ";
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printi256mem(const MachineInstr *MI, unsigned OpNo) {
|
||||
O << "YMMWORD PTR ";
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printf32mem(const MachineInstr *MI, unsigned OpNo) {
|
||||
O << "DWORD PTR ";
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printf64mem(const MachineInstr *MI, unsigned OpNo) {
|
||||
O << "QWORD PTR ";
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printf80mem(const MachineInstr *MI, unsigned OpNo) {
|
||||
O << "XWORD PTR ";
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printf128mem(const MachineInstr *MI, unsigned OpNo) {
|
||||
O << "XMMWORD PTR ";
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printf256mem(const MachineInstr *MI, unsigned OpNo) {
|
||||
O << "YMMWORD PTR ";
|
||||
printMemReference(MI, OpNo);
|
||||
}
|
||||
void printlea32mem(const MachineInstr *MI, unsigned OpNo) {
|
||||
O << "DWORD PTR ";
|
||||
printLeaMemReference(MI, OpNo);
|
||||
}
|
||||
void printlea64mem(const MachineInstr *MI, unsigned OpNo) {
|
||||
O << "QWORD PTR ";
|
||||
printLeaMemReference(MI, OpNo);
|
||||
}
|
||||
void printlea64_32mem(const MachineInstr *MI, unsigned OpNo) {
|
||||
O << "QWORD PTR ";
|
||||
printLeaMemReference(MI, OpNo, "subreg64");
|
||||
}
|
||||
|
||||
bool printAsmMRegister(const MachineOperand &MO, const char Mode);
|
||||
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
|
||||
unsigned AsmVariant, const char *ExtraCode);
|
||||
bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
|
||||
unsigned AsmVariant, const char *ExtraCode);
|
||||
void printMachineInstruction(const MachineInstr *MI);
|
||||
void printOp(const MachineOperand &MO, const char *Modifier = 0);
|
||||
void printSSECC(const MachineInstr *MI, unsigned Op);
|
||||
void printMemReference(const MachineInstr *MI, unsigned Op,
|
||||
const char *Modifier=NULL);
|
||||
void printLeaMemReference(const MachineInstr *MI, unsigned Op,
|
||||
const char *Modifier=NULL);
|
||||
void printPICJumpTableSetLabel(unsigned uid,
|
||||
const MachineBasicBlock *MBB) const;
|
||||
void printPICJumpTableSetLabel(unsigned uid, unsigned uid2,
|
||||
const MachineBasicBlock *MBB) const {
|
||||
AsmPrinter::printPICJumpTableSetLabel(uid, uid2, MBB);
|
||||
}
|
||||
void printPICLabel(const MachineInstr *MI, unsigned Op);
|
||||
bool runOnMachineFunction(MachineFunction &F);
|
||||
bool doInitialization(Module &M);
|
||||
bool doFinalization(Module &M);
|
||||
|
||||
// We have to propagate some information about MachineFunction to
|
||||
// AsmPrinter. It's ok, when we're printing the function, since we have
|
||||
// access to MachineFunction and can get the appropriate MachineFunctionInfo.
|
||||
// Unfortunately, this is not possible when we're printing reference to
|
||||
// Function (e.g. calling it and so on). Even more, there is no way to get the
|
||||
// corresponding MachineFunctions: it can even be not created at all. That's
|
||||
// why we should use additional structure, when we're collecting all necessary
|
||||
// information.
|
||||
//
|
||||
// This structure is using e.g. for name decoration for stdcall & fastcall'ed
|
||||
// function, since we have to use arguments' size for decoration.
|
||||
typedef std::map<const Function*, X86MachineFunctionInfo> FMFInfoMap;
|
||||
FMFInfoMap FunctionInfoMap;
|
||||
|
||||
void decorateName(std::string& Name, const GlobalValue* GV);
|
||||
|
||||
virtual void EmitString(const ConstantArray *CVA) const;
|
||||
|
||||
// Necessary for dllexport support
|
||||
StringSet<> DLLExportedFns, DLLExportedGVs;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
@ -1,429 +0,0 @@
|
||||
//===-- X86TargetAsmInfo.cpp - X86 asm properties ---------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the declarations of the X86TargetAsmInfo properties.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "X86TargetAsmInfo.h"
|
||||
#include "X86TargetMachine.h"
|
||||
#include "X86Subtarget.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "llvm/InlineAsm.h"
|
||||
#include "llvm/Instructions.h"
|
||||
#include "llvm/Intrinsics.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/Support/Dwarf.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::dwarf;
|
||||
|
||||
const char *const llvm::x86_asm_table[] = {
|
||||
"{si}", "S",
|
||||
"{di}", "D",
|
||||
"{ax}", "a",
|
||||
"{cx}", "c",
|
||||
"{memory}", "memory",
|
||||
"{flags}", "",
|
||||
"{dirflag}", "",
|
||||
"{fpsr}", "",
|
||||
"{cc}", "cc",
|
||||
0,0};
|
||||
|
||||
X86DarwinTargetAsmInfo::X86DarwinTargetAsmInfo(const X86TargetMachine &TM):
|
||||
X86TargetAsmInfo<DarwinTargetAsmInfo>(TM) {
|
||||
const X86Subtarget* Subtarget = &TM.getSubtarget<X86Subtarget>();
|
||||
bool is64Bit = Subtarget->is64Bit();
|
||||
|
||||
AlignmentIsInBytes = false;
|
||||
TextAlignFillValue = 0x90;
|
||||
|
||||
|
||||
if (!is64Bit)
|
||||
Data64bitsDirective = 0; // we can't emit a 64-bit unit
|
||||
ZeroDirective = "\t.space\t"; // ".space N" emits N zeros.
|
||||
ZeroFillDirective = "\t.zerofill\t"; // Uses .zerofill
|
||||
if (TM.getRelocationModel() != Reloc::Static)
|
||||
ConstantPoolSection = "\t.const_data";
|
||||
else
|
||||
ConstantPoolSection = "\t.const\n";
|
||||
// FIXME: Why don't we always use this section?
|
||||
if (is64Bit)
|
||||
SixteenByteConstantSection = getUnnamedSection("\t.literal16\n",
|
||||
SectionFlags::Mergeable);
|
||||
LCOMMDirective = "\t.lcomm\t";
|
||||
// Leopard and above support aligned common symbols.
|
||||
COMMDirectiveTakesAlignment = (Subtarget->getDarwinVers() >= 9);
|
||||
HasDotTypeDotSizeDirective = false;
|
||||
NonLocalEHFrameLabel = true;
|
||||
if (is64Bit) {
|
||||
PersonalityPrefix = "";
|
||||
PersonalitySuffix = "+4@GOTPCREL";
|
||||
} else {
|
||||
PersonalityPrefix = "L";
|
||||
PersonalitySuffix = "$non_lazy_ptr";
|
||||
}
|
||||
InlineAsmStart = "## InlineAsm Start";
|
||||
InlineAsmEnd = "## InlineAsm End";
|
||||
CommentString = "##";
|
||||
SetDirective = "\t.set";
|
||||
PCSymbol = ".";
|
||||
UsedDirective = "\t.no_dead_strip\t";
|
||||
ProtectedDirective = "\t.globl\t";
|
||||
|
||||
SupportsDebugInformation = true;
|
||||
|
||||
DwarfDebugInlineSection = ".section __DWARF,__debug_inlined,regular,debug";
|
||||
DwarfUsesInlineInfoSection = true;
|
||||
|
||||
// Exceptions handling
|
||||
SupportsExceptionHandling = true;
|
||||
GlobalEHDirective = "\t.globl\t";
|
||||
SupportsWeakOmittedEHFrame = false;
|
||||
AbsoluteEHSectionOffsets = false;
|
||||
DwarfEHFrameSection =
|
||||
".section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support";
|
||||
DwarfExceptionSection = ".section __DATA,__gcc_except_tab";
|
||||
}
|
||||
|
||||
unsigned
|
||||
X86DarwinTargetAsmInfo::PreferredEHDataFormat(DwarfEncoding::Target Reason,
|
||||
bool Global) const {
|
||||
if (Reason == DwarfEncoding::Functions && Global)
|
||||
return (DW_EH_PE_pcrel | DW_EH_PE_indirect | DW_EH_PE_sdata4);
|
||||
else if (Reason == DwarfEncoding::CodeLabels || !Global)
|
||||
return DW_EH_PE_pcrel;
|
||||
else
|
||||
return DW_EH_PE_absptr;
|
||||
}
|
||||
|
||||
const char *
|
||||
X86DarwinTargetAsmInfo::getEHGlobalPrefix() const
|
||||
{
|
||||
const X86Subtarget* Subtarget = &TM.getSubtarget<X86Subtarget>();
|
||||
if (Subtarget->getDarwinVers() > 9)
|
||||
return PrivateGlobalPrefix;
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
X86ELFTargetAsmInfo::X86ELFTargetAsmInfo(const X86TargetMachine &TM):
|
||||
X86TargetAsmInfo<ELFTargetAsmInfo>(TM) {
|
||||
|
||||
CStringSection = ".rodata.str";
|
||||
PrivateGlobalPrefix = ".L";
|
||||
WeakRefDirective = "\t.weak\t";
|
||||
SetDirective = "\t.set\t";
|
||||
PCSymbol = ".";
|
||||
|
||||
// Set up DWARF directives
|
||||
HasLEB128 = true; // Target asm supports leb128 directives (little-endian)
|
||||
|
||||
// Debug Information
|
||||
AbsoluteDebugSectionOffsets = true;
|
||||
SupportsDebugInformation = true;
|
||||
DwarfAbbrevSection = "\t.section\t.debug_abbrev,\"\",@progbits";
|
||||
DwarfInfoSection = "\t.section\t.debug_info,\"\",@progbits";
|
||||
DwarfLineSection = "\t.section\t.debug_line,\"\",@progbits";
|
||||
DwarfFrameSection = "\t.section\t.debug_frame,\"\",@progbits";
|
||||
DwarfPubNamesSection ="\t.section\t.debug_pubnames,\"\",@progbits";
|
||||
DwarfPubTypesSection ="\t.section\t.debug_pubtypes,\"\",@progbits";
|
||||
DwarfStrSection = "\t.section\t.debug_str,\"\",@progbits";
|
||||
DwarfLocSection = "\t.section\t.debug_loc,\"\",@progbits";
|
||||
DwarfARangesSection = "\t.section\t.debug_aranges,\"\",@progbits";
|
||||
DwarfRangesSection = "\t.section\t.debug_ranges,\"\",@progbits";
|
||||
DwarfMacroInfoSection = "\t.section\t.debug_macinfo,\"\",@progbits";
|
||||
|
||||
// Exceptions handling
|
||||
SupportsExceptionHandling = true;
|
||||
AbsoluteEHSectionOffsets = false;
|
||||
DwarfEHFrameSection = "\t.section\t.eh_frame,\"aw\",@progbits";
|
||||
DwarfExceptionSection = "\t.section\t.gcc_except_table,\"a\",@progbits";
|
||||
|
||||
// On Linux we must declare when we can use a non-executable stack.
|
||||
if (TM.getSubtarget<X86Subtarget>().isLinux())
|
||||
NonexecutableStackDirective = "\t.section\t.note.GNU-stack,\"\",@progbits";
|
||||
}
|
||||
|
||||
unsigned
|
||||
X86ELFTargetAsmInfo::PreferredEHDataFormat(DwarfEncoding::Target Reason,
|
||||
bool Global) const {
|
||||
CodeModel::Model CM = TM.getCodeModel();
|
||||
bool is64Bit = TM.getSubtarget<X86Subtarget>().is64Bit();
|
||||
|
||||
if (TM.getRelocationModel() == Reloc::PIC_) {
|
||||
unsigned Format = 0;
|
||||
|
||||
if (!is64Bit)
|
||||
// 32 bit targets always encode pointers as 4 bytes
|
||||
Format = DW_EH_PE_sdata4;
|
||||
else {
|
||||
// 64 bit targets encode pointers in 4 bytes iff:
|
||||
// - code model is small OR
|
||||
// - code model is medium and we're emitting externally visible symbols
|
||||
// or any code symbols
|
||||
if (CM == CodeModel::Small ||
|
||||
(CM == CodeModel::Medium && (Global ||
|
||||
Reason != DwarfEncoding::Data)))
|
||||
Format = DW_EH_PE_sdata4;
|
||||
else
|
||||
Format = DW_EH_PE_sdata8;
|
||||
}
|
||||
|
||||
if (Global)
|
||||
Format |= DW_EH_PE_indirect;
|
||||
|
||||
return (Format | DW_EH_PE_pcrel);
|
||||
} else {
|
||||
if (is64Bit &&
|
||||
(CM == CodeModel::Small ||
|
||||
(CM == CodeModel::Medium && Reason != DwarfEncoding::Data)))
|
||||
return DW_EH_PE_udata4;
|
||||
else
|
||||
return DW_EH_PE_absptr;
|
||||
}
|
||||
}
|
||||
|
||||
X86COFFTargetAsmInfo::X86COFFTargetAsmInfo(const X86TargetMachine &TM):
|
||||
X86GenericTargetAsmInfo(TM) {
|
||||
|
||||
GlobalPrefix = "_";
|
||||
LCOMMDirective = "\t.lcomm\t";
|
||||
COMMDirectiveTakesAlignment = false;
|
||||
HasDotTypeDotSizeDirective = false;
|
||||
HasSingleParameterDotFile = false;
|
||||
StaticCtorsSection = "\t.section .ctors,\"aw\"";
|
||||
StaticDtorsSection = "\t.section .dtors,\"aw\"";
|
||||
HiddenDirective = NULL;
|
||||
PrivateGlobalPrefix = "L"; // Prefix for private global symbols
|
||||
WeakRefDirective = "\t.weak\t";
|
||||
SetDirective = "\t.set\t";
|
||||
|
||||
// Set up DWARF directives
|
||||
HasLEB128 = true; // Target asm supports leb128 directives (little-endian)
|
||||
AbsoluteDebugSectionOffsets = true;
|
||||
AbsoluteEHSectionOffsets = false;
|
||||
SupportsDebugInformation = true;
|
||||
DwarfSectionOffsetDirective = "\t.secrel32\t";
|
||||
DwarfAbbrevSection = "\t.section\t.debug_abbrev,\"dr\"";
|
||||
DwarfInfoSection = "\t.section\t.debug_info,\"dr\"";
|
||||
DwarfLineSection = "\t.section\t.debug_line,\"dr\"";
|
||||
DwarfFrameSection = "\t.section\t.debug_frame,\"dr\"";
|
||||
DwarfPubNamesSection ="\t.section\t.debug_pubnames,\"dr\"";
|
||||
DwarfPubTypesSection ="\t.section\t.debug_pubtypes,\"dr\"";
|
||||
DwarfStrSection = "\t.section\t.debug_str,\"dr\"";
|
||||
DwarfLocSection = "\t.section\t.debug_loc,\"dr\"";
|
||||
DwarfARangesSection = "\t.section\t.debug_aranges,\"dr\"";
|
||||
DwarfRangesSection = "\t.section\t.debug_ranges,\"dr\"";
|
||||
DwarfMacroInfoSection = "\t.section\t.debug_macinfo,\"dr\"";
|
||||
}
|
||||
|
||||
unsigned
|
||||
X86COFFTargetAsmInfo::PreferredEHDataFormat(DwarfEncoding::Target Reason,
|
||||
bool Global) const {
|
||||
CodeModel::Model CM = TM.getCodeModel();
|
||||
bool is64Bit = TM.getSubtarget<X86Subtarget>().is64Bit();
|
||||
|
||||
if (TM.getRelocationModel() == Reloc::PIC_) {
|
||||
unsigned Format = 0;
|
||||
|
||||
if (!is64Bit)
|
||||
// 32 bit targets always encode pointers as 4 bytes
|
||||
Format = DW_EH_PE_sdata4;
|
||||
else {
|
||||
// 64 bit targets encode pointers in 4 bytes iff:
|
||||
// - code model is small OR
|
||||
// - code model is medium and we're emitting externally visible symbols
|
||||
// or any code symbols
|
||||
if (CM == CodeModel::Small ||
|
||||
(CM == CodeModel::Medium && (Global ||
|
||||
Reason != DwarfEncoding::Data)))
|
||||
Format = DW_EH_PE_sdata4;
|
||||
else
|
||||
Format = DW_EH_PE_sdata8;
|
||||
}
|
||||
|
||||
if (Global)
|
||||
Format |= DW_EH_PE_indirect;
|
||||
|
||||
return (Format | DW_EH_PE_pcrel);
|
||||
} else {
|
||||
if (is64Bit &&
|
||||
(CM == CodeModel::Small ||
|
||||
(CM == CodeModel::Medium && Reason != DwarfEncoding::Data)))
|
||||
return DW_EH_PE_udata4;
|
||||
else
|
||||
return DW_EH_PE_absptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
X86COFFTargetAsmInfo::UniqueSectionForGlobal(const GlobalValue* GV,
|
||||
SectionKind::Kind kind) const {
|
||||
switch (kind) {
|
||||
case SectionKind::Text:
|
||||
return ".text$linkonce" + GV->getName();
|
||||
case SectionKind::Data:
|
||||
case SectionKind::BSS:
|
||||
case SectionKind::ThreadData:
|
||||
case SectionKind::ThreadBSS:
|
||||
return ".data$linkonce" + GV->getName();
|
||||
case SectionKind::ROData:
|
||||
case SectionKind::RODataMergeConst:
|
||||
case SectionKind::RODataMergeStr:
|
||||
return ".rdata$linkonce" + GV->getName();
|
||||
default:
|
||||
assert(0 && "Unknown section kind");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::string X86COFFTargetAsmInfo::printSectionFlags(unsigned flags) const {
|
||||
std::string Flags = ",\"";
|
||||
|
||||
if (flags & SectionFlags::Code)
|
||||
Flags += 'x';
|
||||
if (flags & SectionFlags::Writeable)
|
||||
Flags += 'w';
|
||||
|
||||
Flags += "\"";
|
||||
|
||||
return Flags;
|
||||
}
|
||||
|
||||
X86WinTargetAsmInfo::X86WinTargetAsmInfo(const X86TargetMachine &TM):
|
||||
X86GenericTargetAsmInfo(TM) {
|
||||
GlobalPrefix = "_";
|
||||
CommentString = ";";
|
||||
|
||||
InlineAsmStart = "; InlineAsm Start";
|
||||
InlineAsmEnd = "; InlineAsm End";
|
||||
|
||||
PrivateGlobalPrefix = "$";
|
||||
AlignDirective = "\tALIGN\t";
|
||||
ZeroDirective = "\tdb\t";
|
||||
ZeroDirectiveSuffix = " dup(0)";
|
||||
AsciiDirective = "\tdb\t";
|
||||
AscizDirective = 0;
|
||||
Data8bitsDirective = "\tdb\t";
|
||||
Data16bitsDirective = "\tdw\t";
|
||||
Data32bitsDirective = "\tdd\t";
|
||||
Data64bitsDirective = "\tdq\t";
|
||||
HasDotTypeDotSizeDirective = false;
|
||||
HasSingleParameterDotFile = false;
|
||||
|
||||
AlignmentIsInBytes = true;
|
||||
|
||||
TextSection = getUnnamedSection("_text", SectionFlags::Code);
|
||||
DataSection = getUnnamedSection("_data", SectionFlags::Writeable);
|
||||
|
||||
JumpTableDataSection = NULL;
|
||||
SwitchToSectionDirective = "";
|
||||
TextSectionStartSuffix = "\tSEGMENT PARA 'CODE'";
|
||||
DataSectionStartSuffix = "\tSEGMENT PARA 'DATA'";
|
||||
SectionEndDirectiveSuffix = "\tends\n";
|
||||
}
|
||||
|
||||
template <class BaseTAI>
|
||||
bool X86TargetAsmInfo<BaseTAI>::LowerToBSwap(CallInst *CI) const {
|
||||
// FIXME: this should verify that we are targetting a 486 or better. If not,
|
||||
// we will turn this bswap into something that will be lowered to logical ops
|
||||
// instead of emitting the bswap asm. For now, we don't support 486 or lower
|
||||
// so don't worry about this.
|
||||
|
||||
// Verify this is a simple bswap.
|
||||
if (CI->getNumOperands() != 2 ||
|
||||
CI->getType() != CI->getOperand(1)->getType() ||
|
||||
!CI->getType()->isInteger())
|
||||
return false;
|
||||
|
||||
const IntegerType *Ty = dyn_cast<IntegerType>(CI->getType());
|
||||
if (!Ty || Ty->getBitWidth() % 16 != 0)
|
||||
return false;
|
||||
|
||||
// Okay, we can do this xform, do so now.
|
||||
const Type *Tys[] = { Ty };
|
||||
Module *M = CI->getParent()->getParent()->getParent();
|
||||
Constant *Int = Intrinsic::getDeclaration(M, Intrinsic::bswap, Tys, 1);
|
||||
|
||||
Value *Op = CI->getOperand(1);
|
||||
Op = CallInst::Create(Int, Op, CI->getName(), CI);
|
||||
|
||||
CI->replaceAllUsesWith(Op);
|
||||
CI->eraseFromParent();
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class BaseTAI>
|
||||
bool X86TargetAsmInfo<BaseTAI>::ExpandInlineAsm(CallInst *CI) const {
|
||||
InlineAsm *IA = cast<InlineAsm>(CI->getCalledValue());
|
||||
std::vector<InlineAsm::ConstraintInfo> Constraints = IA->ParseConstraints();
|
||||
|
||||
std::string AsmStr = IA->getAsmString();
|
||||
|
||||
// TODO: should remove alternatives from the asmstring: "foo {a|b}" -> "foo a"
|
||||
std::vector<std::string> AsmPieces;
|
||||
SplitString(AsmStr, AsmPieces, "\n"); // ; as separator?
|
||||
|
||||
switch (AsmPieces.size()) {
|
||||
default: return false;
|
||||
case 1:
|
||||
AsmStr = AsmPieces[0];
|
||||
AsmPieces.clear();
|
||||
SplitString(AsmStr, AsmPieces, " \t"); // Split with whitespace.
|
||||
|
||||
// bswap $0
|
||||
if (AsmPieces.size() == 2 &&
|
||||
(AsmPieces[0] == "bswap" ||
|
||||
AsmPieces[0] == "bswapq" ||
|
||||
AsmPieces[0] == "bswapl") &&
|
||||
(AsmPieces[1] == "$0" ||
|
||||
AsmPieces[1] == "${0:q}")) {
|
||||
// No need to check constraints, nothing other than the equivalent of
|
||||
// "=r,0" would be valid here.
|
||||
return LowerToBSwap(CI);
|
||||
}
|
||||
// rorw $$8, ${0:w} --> llvm.bswap.i16
|
||||
if (CI->getType() == Type::Int16Ty &&
|
||||
AsmPieces.size() == 3 &&
|
||||
AsmPieces[0] == "rorw" &&
|
||||
AsmPieces[1] == "$$8," &&
|
||||
AsmPieces[2] == "${0:w}" &&
|
||||
IA->getConstraintString() == "=r,0,~{dirflag},~{fpsr},~{flags},~{cc}") {
|
||||
return LowerToBSwap(CI);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (CI->getType() == Type::Int64Ty && Constraints.size() >= 2 &&
|
||||
Constraints[0].Codes.size() == 1 && Constraints[0].Codes[0] == "A" &&
|
||||
Constraints[1].Codes.size() == 1 && Constraints[1].Codes[0] == "0") {
|
||||
// bswap %eax / bswap %edx / xchgl %eax, %edx -> llvm.bswap.i64
|
||||
std::vector<std::string> Words;
|
||||
SplitString(AsmPieces[0], Words, " \t");
|
||||
if (Words.size() == 2 && Words[0] == "bswap" && Words[1] == "%eax") {
|
||||
Words.clear();
|
||||
SplitString(AsmPieces[1], Words, " \t");
|
||||
if (Words.size() == 2 && Words[0] == "bswap" && Words[1] == "%edx") {
|
||||
Words.clear();
|
||||
SplitString(AsmPieces[2], Words, " \t,");
|
||||
if (Words.size() == 3 && Words[0] == "xchgl" && Words[1] == "%eax" &&
|
||||
Words[2] == "%edx") {
|
||||
return LowerToBSwap(CI);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Instantiate default implementation.
|
||||
TEMPLATE_INSTANTIATION(class X86TargetAsmInfo<TargetAsmInfo>);
|
@ -1,75 +0,0 @@
|
||||
//=====-- X86TargetAsmInfo.h - X86 asm properties -------------*- C++ -*--====//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the declaration of the X86TargetAsmInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef X86TARGETASMINFO_H
|
||||
#define X86TARGETASMINFO_H
|
||||
|
||||
#include "X86TargetMachine.h"
|
||||
#include "llvm/Target/TargetAsmInfo.h"
|
||||
#include "llvm/Target/ELFTargetAsmInfo.h"
|
||||
#include "llvm/Target/DarwinTargetAsmInfo.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
extern const char *const x86_asm_table[];
|
||||
|
||||
template <class BaseTAI>
|
||||
struct X86TargetAsmInfo : public BaseTAI {
|
||||
explicit X86TargetAsmInfo(const X86TargetMachine &TM):
|
||||
BaseTAI(TM) {
|
||||
const X86Subtarget *Subtarget = &TM.getSubtarget<X86Subtarget>();
|
||||
|
||||
BaseTAI::AsmTransCBE = x86_asm_table;
|
||||
BaseTAI::AssemblerDialect = Subtarget->getAsmFlavor();
|
||||
}
|
||||
|
||||
virtual bool ExpandInlineAsm(CallInst *CI) const;
|
||||
|
||||
private:
|
||||
bool LowerToBSwap(CallInst *CI) const;
|
||||
};
|
||||
|
||||
typedef X86TargetAsmInfo<TargetAsmInfo> X86GenericTargetAsmInfo;
|
||||
|
||||
EXTERN_TEMPLATE_INSTANTIATION(class X86TargetAsmInfo<TargetAsmInfo>);
|
||||
|
||||
struct X86DarwinTargetAsmInfo : public X86TargetAsmInfo<DarwinTargetAsmInfo> {
|
||||
explicit X86DarwinTargetAsmInfo(const X86TargetMachine &TM);
|
||||
virtual unsigned PreferredEHDataFormat(DwarfEncoding::Target Reason,
|
||||
bool Global) const;
|
||||
virtual const char *getEHGlobalPrefix() const;
|
||||
};
|
||||
|
||||
struct X86ELFTargetAsmInfo : public X86TargetAsmInfo<ELFTargetAsmInfo> {
|
||||
explicit X86ELFTargetAsmInfo(const X86TargetMachine &TM);
|
||||
virtual unsigned PreferredEHDataFormat(DwarfEncoding::Target Reason,
|
||||
bool Global) const;
|
||||
};
|
||||
|
||||
struct X86COFFTargetAsmInfo : public X86GenericTargetAsmInfo {
|
||||
explicit X86COFFTargetAsmInfo(const X86TargetMachine &TM);
|
||||
virtual unsigned PreferredEHDataFormat(DwarfEncoding::Target Reason,
|
||||
bool Global) const;
|
||||
virtual std::string UniqueSectionForGlobal(const GlobalValue* GV,
|
||||
SectionKind::Kind kind) const;
|
||||
virtual std::string printSectionFlags(unsigned flags) const;
|
||||
};
|
||||
|
||||
struct X86WinTargetAsmInfo : public X86GenericTargetAsmInfo {
|
||||
explicit X86WinTargetAsmInfo(const X86TargetMachine &TM);
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
@ -1,438 +0,0 @@
|
||||
//===-- XCoreAsmPrinter.cpp - XCore LLVM assembly writer ------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains a printer that converts from our internal representation
|
||||
// of machine-dependent LLVM code to the XAS-format XCore assembly language.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define DEBUG_TYPE "asm-printer"
|
||||
#include "XCore.h"
|
||||
#include "XCoreInstrInfo.h"
|
||||
#include "XCoreSubtarget.h"
|
||||
#include "XCoreTargetMachine.h"
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/CodeGen/AsmPrinter.h"
|
||||
#include "llvm/CodeGen/DwarfWriter.h"
|
||||
#include "llvm/CodeGen/MachineModuleInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineConstantPool.h"
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
#include "llvm/Target/TargetAsmInfo.h"
|
||||
#include "llvm/Target/TargetData.h"
|
||||
#include "llvm/Support/Mangler.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
using namespace llvm;
|
||||
|
||||
STATISTIC(EmittedInsts, "Number of machine instrs printed");
|
||||
|
||||
static cl::opt<std::string> FileDirective("xcore-file-directive", cl::Optional,
|
||||
cl::desc("Output a file directive into the assembly file"),
|
||||
cl::Hidden,
|
||||
cl::value_desc("filename"),
|
||||
cl::init(""));
|
||||
|
||||
static cl::opt<unsigned> MaxThreads("xcore-max-threads", cl::Optional,
|
||||
cl::desc("Maximum number of threads (for emulation thread-local storage)"),
|
||||
cl::Hidden,
|
||||
cl::value_desc("number"),
|
||||
cl::init(8));
|
||||
|
||||
namespace {
|
||||
class VISIBILITY_HIDDEN XCoreAsmPrinter : public AsmPrinter {
|
||||
DwarfWriter *DW;
|
||||
const XCoreSubtarget &Subtarget;
|
||||
public:
|
||||
explicit XCoreAsmPrinter(raw_ostream &O, XCoreTargetMachine &TM,
|
||||
const TargetAsmInfo *T, bool V)
|
||||
: AsmPrinter(O, TM, T, V), DW(0),
|
||||
Subtarget(*TM.getSubtargetImpl()) {}
|
||||
|
||||
virtual const char *getPassName() const {
|
||||
return "XCore Assembly Printer";
|
||||
}
|
||||
|
||||
void printMemOperand(const MachineInstr *MI, int opNum);
|
||||
void printOperand(const MachineInstr *MI, int opNum);
|
||||
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
|
||||
unsigned AsmVariant, const char *ExtraCode);
|
||||
|
||||
void emitFileDirective(const std::string &filename);
|
||||
void emitGlobalDirective(const std::string &name);
|
||||
void emitExternDirective(const std::string &name);
|
||||
|
||||
void emitArrayBound(const std::string &name, const GlobalVariable *GV);
|
||||
void emitGlobal(const GlobalVariable *GV);
|
||||
|
||||
void emitFunctionStart(MachineFunction &MF);
|
||||
void emitFunctionEnd(MachineFunction &MF);
|
||||
|
||||
bool printInstruction(const MachineInstr *MI); // autogenerated.
|
||||
void printMachineInstruction(const MachineInstr *MI);
|
||||
bool runOnMachineFunction(MachineFunction &F);
|
||||
bool doInitialization(Module &M);
|
||||
bool doFinalization(Module &M);
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AsmPrinter::getAnalysisUsage(AU);
|
||||
AU.setPreservesAll();
|
||||
AU.addRequired<MachineModuleInfo>();
|
||||
AU.addRequired<DwarfWriter>();
|
||||
}
|
||||
};
|
||||
} // end of anonymous namespace
|
||||
|
||||
#include "XCoreGenAsmWriter.inc"
|
||||
|
||||
/// createXCoreCodePrinterPass - Returns a pass that prints the XCore
|
||||
/// assembly code for a MachineFunction to the given output stream,
|
||||
/// using the given target machine description. This should work
|
||||
/// regardless of whether the function is in SSA form.
|
||||
///
|
||||
FunctionPass *llvm::createXCoreCodePrinterPass(raw_ostream &o,
|
||||
XCoreTargetMachine &tm,
|
||||
bool verbose) {
|
||||
return new XCoreAsmPrinter(o, tm, tm.getTargetAsmInfo(), verbose);
|
||||
}
|
||||
|
||||
// PrintEscapedString - Print each character of the specified string, escaping
|
||||
// it if it is not printable or if it is an escape char.
|
||||
static void PrintEscapedString(const std::string &Str, raw_ostream &Out) {
|
||||
for (unsigned i = 0, e = Str.size(); i != e; ++i) {
|
||||
unsigned char C = Str[i];
|
||||
if (isprint(C) && C != '"' && C != '\\') {
|
||||
Out << C;
|
||||
} else {
|
||||
Out << '\\'
|
||||
<< (char) ((C/16 < 10) ? ( C/16 +'0') : ( C/16 -10+'A'))
|
||||
<< (char)(((C&15) < 10) ? ((C&15)+'0') : ((C&15)-10+'A'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void XCoreAsmPrinter::
|
||||
emitFileDirective(const std::string &name)
|
||||
{
|
||||
O << "\t.file\t\"";
|
||||
PrintEscapedString(name, O);
|
||||
O << "\"\n";
|
||||
}
|
||||
|
||||
void XCoreAsmPrinter::
|
||||
emitGlobalDirective(const std::string &name)
|
||||
{
|
||||
O << TAI->getGlobalDirective() << name;
|
||||
O << "\n";
|
||||
}
|
||||
|
||||
void XCoreAsmPrinter::
|
||||
emitExternDirective(const std::string &name)
|
||||
{
|
||||
O << "\t.extern\t" << name;
|
||||
O << '\n';
|
||||
}
|
||||
|
||||
void XCoreAsmPrinter::
|
||||
emitArrayBound(const std::string &name, const GlobalVariable *GV)
|
||||
{
|
||||
assert(((GV->hasExternalLinkage() ||
|
||||
GV->hasWeakLinkage()) ||
|
||||
GV->hasLinkOnceLinkage()) && "Unexpected linkage");
|
||||
if (const ArrayType *ATy = dyn_cast<ArrayType>(
|
||||
cast<PointerType>(GV->getType())->getElementType()))
|
||||
{
|
||||
O << TAI->getGlobalDirective() << name << ".globound" << "\n";
|
||||
O << TAI->getSetDirective() << name << ".globound" << ","
|
||||
<< ATy->getNumElements() << "\n";
|
||||
if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage()) {
|
||||
// TODO Use COMDAT groups for LinkOnceLinkage
|
||||
O << TAI->getWeakDefDirective() << name << ".globound" << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void XCoreAsmPrinter::
|
||||
emitGlobal(const GlobalVariable *GV)
|
||||
{
|
||||
const TargetData *TD = TM.getTargetData();
|
||||
|
||||
if (GV->hasInitializer()) {
|
||||
// Check to see if this is a special global used by LLVM, if so, emit it.
|
||||
if (EmitSpecialLLVMGlobal(GV))
|
||||
return;
|
||||
|
||||
SwitchToSection(TAI->SectionForGlobal(GV));
|
||||
|
||||
std::string name = Mang->getValueName(GV);
|
||||
Constant *C = GV->getInitializer();
|
||||
unsigned Align = (unsigned)TD->getPreferredTypeAlignmentShift(C->getType());
|
||||
|
||||
// Mark the start of the global
|
||||
O << "\t.cc_top " << name << ".data," << name << "\n";
|
||||
|
||||
switch (GV->getLinkage()) {
|
||||
case GlobalValue::AppendingLinkage:
|
||||
cerr << "AppendingLinkage is not supported by this target!\n";
|
||||
abort();
|
||||
case GlobalValue::LinkOnceAnyLinkage:
|
||||
case GlobalValue::LinkOnceODRLinkage:
|
||||
case GlobalValue::WeakAnyLinkage:
|
||||
case GlobalValue::WeakODRLinkage:
|
||||
case GlobalValue::ExternalLinkage:
|
||||
emitArrayBound(name, GV);
|
||||
emitGlobalDirective(name);
|
||||
// TODO Use COMDAT groups for LinkOnceLinkage
|
||||
if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage()) {
|
||||
O << TAI->getWeakDefDirective() << name << "\n";
|
||||
}
|
||||
// FALL THROUGH
|
||||
case GlobalValue::InternalLinkage:
|
||||
case GlobalValue::PrivateLinkage:
|
||||
break;
|
||||
case GlobalValue::GhostLinkage:
|
||||
cerr << "Should not have any unmaterialized functions!\n";
|
||||
abort();
|
||||
case GlobalValue::DLLImportLinkage:
|
||||
cerr << "DLLImport linkage is not supported by this target!\n";
|
||||
abort();
|
||||
case GlobalValue::DLLExportLinkage:
|
||||
cerr << "DLLExport linkage is not supported by this target!\n";
|
||||
abort();
|
||||
default:
|
||||
assert(0 && "Unknown linkage type!");
|
||||
}
|
||||
|
||||
EmitAlignment(Align, GV, 2);
|
||||
|
||||
unsigned Size = TD->getTypeAllocSize(C->getType());
|
||||
if (GV->isThreadLocal()) {
|
||||
Size *= MaxThreads;
|
||||
}
|
||||
if (TAI->hasDotTypeDotSizeDirective()) {
|
||||
O << "\t.type " << name << ",@object\n";
|
||||
O << "\t.size " << name << "," << Size << "\n";
|
||||
}
|
||||
O << name << ":\n";
|
||||
|
||||
EmitGlobalConstant(C);
|
||||
if (GV->isThreadLocal()) {
|
||||
for (unsigned i = 1; i < MaxThreads; ++i) {
|
||||
EmitGlobalConstant(C);
|
||||
}
|
||||
}
|
||||
if (Size < 4) {
|
||||
// The ABI requires that unsigned scalar types smaller than 32 bits
|
||||
// are are padded to 32 bits.
|
||||
EmitZeros(4 - Size);
|
||||
}
|
||||
|
||||
// Mark the end of the global
|
||||
O << "\t.cc_bottom " << name << ".data\n";
|
||||
}
|
||||
}
|
||||
|
||||
/// Emit the directives on the start of functions
|
||||
void XCoreAsmPrinter::
|
||||
emitFunctionStart(MachineFunction &MF)
|
||||
{
|
||||
// Print out the label for the function.
|
||||
const Function *F = MF.getFunction();
|
||||
|
||||
SwitchToSection(TAI->SectionForGlobal(F));
|
||||
|
||||
// Mark the start of the function
|
||||
O << "\t.cc_top " << CurrentFnName << ".function," << CurrentFnName << "\n";
|
||||
|
||||
switch (F->getLinkage()) {
|
||||
default: assert(0 && "Unknown linkage type!");
|
||||
case Function::InternalLinkage: // Symbols default to internal.
|
||||
case Function::PrivateLinkage:
|
||||
break;
|
||||
case Function::ExternalLinkage:
|
||||
emitGlobalDirective(CurrentFnName);
|
||||
break;
|
||||
case Function::LinkOnceAnyLinkage:
|
||||
case Function::LinkOnceODRLinkage:
|
||||
case Function::WeakAnyLinkage:
|
||||
case Function::WeakODRLinkage:
|
||||
// TODO Use COMDAT groups for LinkOnceLinkage
|
||||
O << TAI->getGlobalDirective() << CurrentFnName << "\n";
|
||||
O << TAI->getWeakDefDirective() << CurrentFnName << "\n";
|
||||
break;
|
||||
}
|
||||
// (1 << 1) byte aligned
|
||||
EmitAlignment(MF.getAlignment(), F, 1);
|
||||
if (TAI->hasDotTypeDotSizeDirective()) {
|
||||
O << "\t.type " << CurrentFnName << ",@function\n";
|
||||
}
|
||||
O << CurrentFnName << ":\n";
|
||||
}
|
||||
|
||||
/// Emit the directives on the end of functions
|
||||
void XCoreAsmPrinter::
|
||||
emitFunctionEnd(MachineFunction &MF)
|
||||
{
|
||||
// Mark the end of the function
|
||||
O << "\t.cc_bottom " << CurrentFnName << ".function\n";
|
||||
}
|
||||
|
||||
/// runOnMachineFunction - This uses the printMachineInstruction()
|
||||
/// method to print assembly for each instruction.
|
||||
///
|
||||
bool XCoreAsmPrinter::runOnMachineFunction(MachineFunction &MF)
|
||||
{
|
||||
this->MF = &MF;
|
||||
|
||||
SetupMachineFunction(MF);
|
||||
|
||||
// Print out constants referenced by the function
|
||||
EmitConstantPool(MF.getConstantPool());
|
||||
|
||||
// Print out jump tables referenced by the function
|
||||
EmitJumpTableInfo(MF.getJumpTableInfo(), MF);
|
||||
|
||||
// Emit the function start directives
|
||||
emitFunctionStart(MF);
|
||||
|
||||
// Emit pre-function debug information.
|
||||
DW->BeginFunction(&MF);
|
||||
|
||||
// Print out code for the function.
|
||||
for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
|
||||
I != E; ++I) {
|
||||
|
||||
// Print a label for the basic block.
|
||||
if (I != MF.begin()) {
|
||||
printBasicBlockLabel(I, true , true);
|
||||
O << '\n';
|
||||
}
|
||||
|
||||
for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
|
||||
II != E; ++II) {
|
||||
// Print the assembly for the instruction.
|
||||
O << "\t";
|
||||
printMachineInstruction(II);
|
||||
}
|
||||
|
||||
// Each Basic Block is separated by a newline
|
||||
O << '\n';
|
||||
}
|
||||
|
||||
// Emit function end directives
|
||||
emitFunctionEnd(MF);
|
||||
|
||||
// Emit post-function debug information.
|
||||
DW->EndFunction(&MF);
|
||||
|
||||
// We didn't modify anything.
|
||||
return false;
|
||||
}
|
||||
|
||||
void XCoreAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum)
|
||||
{
|
||||
printOperand(MI, opNum);
|
||||
|
||||
if (MI->getOperand(opNum+1).isImm()
|
||||
&& MI->getOperand(opNum+1).getImm() == 0)
|
||||
return;
|
||||
|
||||
O << "+";
|
||||
printOperand(MI, opNum+1);
|
||||
}
|
||||
|
||||
void XCoreAsmPrinter::printOperand(const MachineInstr *MI, int opNum) {
|
||||
const MachineOperand &MO = MI->getOperand(opNum);
|
||||
switch (MO.getType()) {
|
||||
case MachineOperand::MO_Register:
|
||||
if (TargetRegisterInfo::isPhysicalRegister(MO.getReg()))
|
||||
O << TM.getRegisterInfo()->get(MO.getReg()).AsmName;
|
||||
else
|
||||
assert(0 && "not implemented");
|
||||
break;
|
||||
case MachineOperand::MO_Immediate:
|
||||
O << MO.getImm();
|
||||
break;
|
||||
case MachineOperand::MO_MachineBasicBlock:
|
||||
printBasicBlockLabel(MO.getMBB());
|
||||
break;
|
||||
case MachineOperand::MO_GlobalAddress:
|
||||
O << Mang->getValueName(MO.getGlobal());
|
||||
break;
|
||||
case MachineOperand::MO_ExternalSymbol:
|
||||
O << MO.getSymbolName();
|
||||
break;
|
||||
case MachineOperand::MO_ConstantPoolIndex:
|
||||
O << TAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
|
||||
<< '_' << MO.getIndex();
|
||||
break;
|
||||
case MachineOperand::MO_JumpTableIndex:
|
||||
O << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
|
||||
<< '_' << MO.getIndex();
|
||||
break;
|
||||
default:
|
||||
assert(0 && "not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
/// PrintAsmOperand - Print out an operand for an inline asm expression.
|
||||
///
|
||||
bool XCoreAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
|
||||
unsigned AsmVariant,
|
||||
const char *ExtraCode) {
|
||||
printOperand(MI, OpNo);
|
||||
return false;
|
||||
}
|
||||
|
||||
void XCoreAsmPrinter::printMachineInstruction(const MachineInstr *MI) {
|
||||
++EmittedInsts;
|
||||
|
||||
// Check for mov mnemonic
|
||||
unsigned src, dst, srcSR, dstSR;
|
||||
if (TM.getInstrInfo()->isMoveInstr(*MI, src, dst, srcSR, dstSR)) {
|
||||
O << "\tmov ";
|
||||
O << TM.getRegisterInfo()->get(dst).AsmName;
|
||||
O << ", ";
|
||||
O << TM.getRegisterInfo()->get(src).AsmName;
|
||||
O << "\n";
|
||||
return;
|
||||
}
|
||||
if (printInstruction(MI)) {
|
||||
return;
|
||||
}
|
||||
assert(0 && "Unhandled instruction in asm writer!");
|
||||
}
|
||||
|
||||
bool XCoreAsmPrinter::doInitialization(Module &M) {
|
||||
bool Result = AsmPrinter::doInitialization(M);
|
||||
DW = getAnalysisIfAvailable<DwarfWriter>();
|
||||
|
||||
if (!FileDirective.empty())
|
||||
emitFileDirective(FileDirective);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
bool XCoreAsmPrinter::doFinalization(Module &M) {
|
||||
|
||||
// Print out module-level global variables.
|
||||
for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
|
||||
I != E; ++I) {
|
||||
emitGlobal(I);
|
||||
}
|
||||
|
||||
return AsmPrinter::doFinalization(M);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user