Compare commits
24 Commits
llvmorg-5.
...
llvmorg-1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32e813e486 | ||
|
|
b6a9b36e21 | ||
|
|
0fe9bd9e6d | ||
|
|
322e13176f | ||
|
|
ab686a51f1 | ||
|
|
f2a68db009 | ||
|
|
ef095995c7 | ||
|
|
841e6949d7 | ||
|
|
a98c3d19a5 | ||
|
|
10b4a6323f | ||
|
|
7d4bacd1af | ||
|
|
f0958ae6eb | ||
|
|
7ee0099de5 | ||
|
|
7aa6c01be2 | ||
|
|
1e34901d4d | ||
|
|
362f4b3e5d | ||
|
|
67dee05f54 | ||
|
|
0ccbe35d71 | ||
|
|
7f6d3e7317 | ||
|
|
fb63a35c3c | ||
|
|
6dbb267760 | ||
|
|
50fe9297ba | ||
|
|
395900dcf5 | ||
|
|
a27fe0174c |
@@ -188,31 +188,31 @@ software you will need.</p>
|
|||||||
|
|
||||||
<li>Linux on x86 (Pentium and above)
|
<li>Linux on x86 (Pentium and above)
|
||||||
<ul>
|
<ul>
|
||||||
<li>Approximately 1.02 GB of Free Disk Space
|
<li>Approximately 2.6 GB of Free Disk Space
|
||||||
<ul>
|
<ul>
|
||||||
<li>Source code: 45 MB</li>
|
<li>Source code: 57 MB</li>
|
||||||
<li>Object code: 956 MB</li>
|
<li>Object code: 2.5 GB</li>
|
||||||
<li>GCC front end: 40 MB</li>
|
<li>GCC front end: 30 MB</li>
|
||||||
</ul></li>
|
</ul></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>Solaris on SparcV9 (Ultrasparc)
|
<li>Solaris on SparcV9 (Ultrasparc)
|
||||||
<ul>
|
<ul>
|
||||||
<li>Approximately 1.75 GB of Free Disk Space
|
<li>Approximately 2.6 GB of Free Disk Space
|
||||||
<ul>
|
<ul>
|
||||||
<li>Source code: 45 MB</li>
|
<li>Source code: 57 MB</li>
|
||||||
<li>Object code: 1705 MB</li>
|
<li>Object code: 2.5 GB</li>
|
||||||
<li>GCC front end: 50 MB</li>
|
<li>GCC front end: 46 MB</li>
|
||||||
</ul></li>
|
</ul></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>FreeBSD on x86 (Pentium and above)
|
<li>FreeBSD on x86 (Pentium and above)
|
||||||
<ul>
|
<ul>
|
||||||
<li>Approximately 935 MB of Free Disk Space
|
<li>Approximately 1 GB of Free Disk Space
|
||||||
<ul>
|
<ul>
|
||||||
<li>Source code: 45 MB</li>
|
<li>Source code: 57 MB</li>
|
||||||
<li>Object code: 850 MB</li>
|
<li>Object code: 850 MB</li>
|
||||||
<li>GCC front end: 40 MB</li>
|
<li>GCC front end: 40 MB</li>
|
||||||
</ul></li>
|
</ul></li>
|
||||||
@@ -221,12 +221,12 @@ software you will need.</p>
|
|||||||
|
|
||||||
<li>MacOS X on PowerPC
|
<li>MacOS X on PowerPC
|
||||||
<ul>
|
<ul>
|
||||||
<li>No native code generation
|
<li>Experimental support for static native code generation
|
||||||
<li>Approximately 1.25 GB of Free Disk Space
|
<li>Approximately 1.6 GB of Free Disk Space
|
||||||
<ul>
|
<ul>
|
||||||
<li>Source code: 45 MB</li>
|
<li>Source code: 57 MB</li>
|
||||||
<li>Object code: 1160 MB</li>
|
<li>Object code: 1.5 GB</li>
|
||||||
<li>GCC front end: 40 MB</li>
|
<li>GCC front end: 36 MB</li>
|
||||||
</ul></li>
|
</ul></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@@ -430,23 +430,23 @@ file is a TAR archive that is compressed with the gzip program.
|
|||||||
|
|
||||||
<p> The files are as follows:
|
<p> The files are as follows:
|
||||||
<dl>
|
<dl>
|
||||||
<dt>llvm-1.2.tar.gz
|
<dt>llvm-1.3.tar.gz
|
||||||
<dd>This is the source code to the LLVM suite.
|
<dd>This is the source code to the LLVM suite.
|
||||||
<p>
|
<p>
|
||||||
|
|
||||||
<dt>cfrontend-1.2.sparc-sun-solaris2.8.tar.gz
|
<dt>cfrontend-1.3.sparc-sun-solaris2.8.tar.gz
|
||||||
<dd>This is the binary release of the GCC front end for Solaris/Sparc.
|
<dd>This is the binary release of the GCC front end for Solaris/Sparc.
|
||||||
<p>
|
<p>
|
||||||
|
|
||||||
<dt>cfrontend-1.2.i686-redhat-linux-gnu.tar.gz
|
<dt>cfrontend-1.3.i686-redhat-linux-gnu.tar.gz
|
||||||
<dd>This is the binary release of the GCC front end for Linux/x86.
|
<dd>This is the binary release of the GCC front end for Linux/x86.
|
||||||
<p>
|
<p>
|
||||||
|
|
||||||
<dt>cfrontend-1.2.i386-unknown-freebsd5.1.tar.gz
|
<dt>cfrontend-1.3.i386-unknown-freebsd5.1.tar.gz
|
||||||
<dd>This is the binary release of the GCC front end for FreeBSD/x86.
|
<dd>This is the binary release of the GCC front end for FreeBSD/x86.
|
||||||
<p>
|
<p>
|
||||||
|
|
||||||
<dt>cfrontend-1.2.powerpc-apple-darwin7.0.0.tar.gz
|
<dt>cfrontend-1.3.powerpc-apple-darwin7.0.0.tar.gz
|
||||||
<dd>This is the binary release of the GCC front end for MacOS X/PPC.
|
<dd>This is the binary release of the GCC front end for MacOS X/PPC.
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
@@ -480,6 +480,7 @@ revision), you can specify a label. The following releases have the following
|
|||||||
label:</p>
|
label:</p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
|
<li>Release 1.3: <b>RELEASE_13</b></li>
|
||||||
<li>Release 1.2: <b>RELEASE_12</b></li>
|
<li>Release 1.2: <b>RELEASE_12</b></li>
|
||||||
<li>Release 1.1: <b>RELEASE_11</b></li>
|
<li>Release 1.1: <b>RELEASE_11</b></li>
|
||||||
<li>Release 1.0: <b>RELEASE_1</b></li>
|
<li>Release 1.0: <b>RELEASE_1</b></li>
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ prints the address of the object instead of its contents.</a></li>
|
|||||||
Needed</a></li>
|
Needed</a></li>
|
||||||
<li><a href="http://llvm.cs.uiuc.edu/PR404">[loopsimplify] Loop simplify is
|
<li><a href="http://llvm.cs.uiuc.edu/PR404">[loopsimplify] Loop simplify is
|
||||||
really slow on 252.eon</a></li>
|
really slow on 252.eon</a></li>
|
||||||
<li><a href="Http://llvm.cs.uiuc.edu/PR122">[code-cleanup] SymbolTable class
|
<li><a href="http://llvm.cs.uiuc.edu/PR122">[code-cleanup] SymbolTable class
|
||||||
cleanup, Type should not derive from Value, eliminate ConstantPointerRef
|
cleanup, Type should not derive from Value, eliminate ConstantPointerRef
|
||||||
class</a>.</li>
|
class</a>.</li>
|
||||||
<li>The memory footprint of the LLVM IR has been reduced substantially.</li>
|
<li>The memory footprint of the LLVM IR has been reduced substantially.</li>
|
||||||
@@ -430,9 +430,7 @@ work.</li>
|
|||||||
such, execution of a threaded program could cause these data structures to be
|
such, execution of a threaded program could cause these data structures to be
|
||||||
corrupted.</li>
|
corrupted.</li>
|
||||||
|
|
||||||
<li>It is not possible to <tt>dlopen</tt> an LLVM bytecode file in the JIT.</li>
|
<li>Linking in static archive files (.a files) is slow (there is no symbol
|
||||||
|
|
||||||
<li>Linking in static archive files (.a files) is very slow (there is no symbol
|
|
||||||
table in the archive).</li>
|
table in the archive).</li>
|
||||||
|
|
||||||
<li>The gccld program <a href="http://llvm.cs.uiuc.edu/PR139">does not link
|
<li>The gccld program <a href="http://llvm.cs.uiuc.edu/PR139">does not link
|
||||||
|
|||||||
@@ -51,8 +51,8 @@ Discusses how to get up and running quickly with the LLVM infrastructure.
|
|||||||
Everything from unpacking and compilation of the distribution to execution of
|
Everything from unpacking and compilation of the distribution to execution of
|
||||||
some tools.</li>
|
some tools.</li>
|
||||||
|
|
||||||
<li><a href="CommandGuide/">LLVM Command Guide</a> - A reference manual for
|
<li><a href="CommandGuide/index.html">LLVM Command Guide</a> - A reference
|
||||||
the LLVM command line utilities ("man" pages for LLVM tools).</li>
|
manual for the LLVM command line utilities ("man" pages for LLVM tools).</li>
|
||||||
|
|
||||||
<li><a href="FAQ.html">Frequently Asked Questions</a> - A list of common
|
<li><a href="FAQ.html">Frequently Asked Questions</a> - A list of common
|
||||||
questions and problems and their solutions.</li>
|
questions and problems and their solutions.</li>
|
||||||
|
|||||||
@@ -1390,9 +1390,13 @@ void CWriter::visitCallInst(CallInst &I) {
|
|||||||
Out << ")";
|
Out << ")";
|
||||||
return;
|
return;
|
||||||
case Intrinsic::vaend:
|
case Intrinsic::vaend:
|
||||||
Out << "va_end(*(va_list*)&";
|
if (!isa<ConstantPointerNull>(I.getOperand(1))) {
|
||||||
writeOperand(I.getOperand(1));
|
Out << "va_end(*(va_list*)&";
|
||||||
Out << ")";
|
writeOperand(I.getOperand(1));
|
||||||
|
Out << ")";
|
||||||
|
} else {
|
||||||
|
Out << "va_end(*(va_list*)0)";
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
case Intrinsic::vacopy:
|
case Intrinsic::vacopy:
|
||||||
Out << "0;";
|
Out << "0;";
|
||||||
|
|||||||
@@ -1,735 +0,0 @@
|
|||||||
//===-- PowerPCAsmPrinter.cpp - Print machine instrs to PowerPC assembly --===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and 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 PowerPC assembly language. This printer is
|
|
||||||
// the output mechanism used by `llc'.
|
|
||||||
//
|
|
||||||
// Documentation at http://developer.apple.com/documentation/DeveloperTools/
|
|
||||||
// Reference/Assembler/ASMIntroduction/chapter_1_section_1.html
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#define DEBUG_TYPE "asmprinter"
|
|
||||||
#include "PowerPC.h"
|
|
||||||
#include "PowerPCInstrInfo.h"
|
|
||||||
#include "PowerPCTargetMachine.h"
|
|
||||||
#include "llvm/Constants.h"
|
|
||||||
#include "llvm/DerivedTypes.h"
|
|
||||||
#include "llvm/Module.h"
|
|
||||||
#include "llvm/Assembly/Writer.h"
|
|
||||||
#include "llvm/CodeGen/MachineConstantPool.h"
|
|
||||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
|
||||||
#include "llvm/CodeGen/MachineInstr.h"
|
|
||||||
#include "llvm/Target/TargetMachine.h"
|
|
||||||
#include "llvm/Support/Mangler.h"
|
|
||||||
#include "Support/CommandLine.h"
|
|
||||||
#include "Support/Debug.h"
|
|
||||||
#include "Support/Statistic.h"
|
|
||||||
#include "Support/StringExtras.h"
|
|
||||||
#include <set>
|
|
||||||
|
|
||||||
namespace llvm {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
Statistic<> EmittedInsts("asm-printer", "Number of machine instrs printed");
|
|
||||||
|
|
||||||
struct Printer : public MachineFunctionPass {
|
|
||||||
/// Output stream on which we're printing assembly code.
|
|
||||||
///
|
|
||||||
std::ostream &O;
|
|
||||||
|
|
||||||
/// Target machine description which we query for reg. names, data
|
|
||||||
/// layout, etc.
|
|
||||||
///
|
|
||||||
PowerPCTargetMachine &TM;
|
|
||||||
|
|
||||||
/// Name-mangler for global names.
|
|
||||||
///
|
|
||||||
Mangler *Mang;
|
|
||||||
std::set<std::string> FnStubs, GVStubs, LinkOnceStubs;
|
|
||||||
std::set<std::string> Strings;
|
|
||||||
|
|
||||||
Printer(std::ostream &o, TargetMachine &tm) : O(o),
|
|
||||||
TM(reinterpret_cast<PowerPCTargetMachine&>(tm)), LabelNumber(0) {}
|
|
||||||
|
|
||||||
/// Cache of mangled name for current function. This is
|
|
||||||
/// recalculated at the beginning of each call to
|
|
||||||
/// runOnMachineFunction().
|
|
||||||
///
|
|
||||||
std::string CurrentFnName;
|
|
||||||
|
|
||||||
/// Unique incrementer for label values for referencing Global values.
|
|
||||||
///
|
|
||||||
unsigned LabelNumber;
|
|
||||||
|
|
||||||
virtual const char *getPassName() const {
|
|
||||||
return "PowerPC Assembly Printer";
|
|
||||||
}
|
|
||||||
|
|
||||||
void printMachineInstruction(const MachineInstr *MI);
|
|
||||||
void printOp(const MachineOperand &MO, bool elideOffsetKeyword = false);
|
|
||||||
void printImmOp(const MachineOperand &MO, unsigned ArgType);
|
|
||||||
void printConstantPool(MachineConstantPool *MCP);
|
|
||||||
bool runOnMachineFunction(MachineFunction &F);
|
|
||||||
bool doInitialization(Module &M);
|
|
||||||
bool doFinalization(Module &M);
|
|
||||||
void emitGlobalConstant(const Constant* CV);
|
|
||||||
void emitConstantValueOnly(const Constant *CV);
|
|
||||||
};
|
|
||||||
} // end of anonymous namespace
|
|
||||||
|
|
||||||
/// createPPCCodePrinterPass - Returns a pass that prints the PPC
|
|
||||||
/// 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 *createPPCCodePrinterPass(std::ostream &o,TargetMachine &tm) {
|
|
||||||
return new Printer(o, tm);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// isStringCompatible - Can we treat the specified array as a string?
|
|
||||||
/// Only if it is an array of ubytes or non-negative sbytes.
|
|
||||||
///
|
|
||||||
static bool isStringCompatible(const ConstantArray *CVA) {
|
|
||||||
const Type *ETy = cast<ArrayType>(CVA->getType())->getElementType();
|
|
||||||
if (ETy == Type::UByteTy) return true;
|
|
||||||
if (ETy != Type::SByteTy) return false;
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < CVA->getNumOperands(); ++i)
|
|
||||||
if (cast<ConstantSInt>(CVA->getOperand(i))->getValue() < 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// toOctal - Convert the low order bits of X into an octal digit.
|
|
||||||
///
|
|
||||||
static inline char toOctal(int X) {
|
|
||||||
return (X&7)+'0';
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getAsCString - Return the specified array as a C compatible
|
|
||||||
/// string, only if the predicate isStringCompatible is true.
|
|
||||||
///
|
|
||||||
static void printAsCString(std::ostream &O, const ConstantArray *CVA) {
|
|
||||||
assert(isStringCompatible(CVA) && "Array is not string compatible!");
|
|
||||||
|
|
||||||
O << "\"";
|
|
||||||
for (unsigned i = 0; i < CVA->getNumOperands(); ++i) {
|
|
||||||
unsigned char C = cast<ConstantInt>(CVA->getOperand(i))->getRawValue();
|
|
||||||
|
|
||||||
if (C == '"') {
|
|
||||||
O << "\\\"";
|
|
||||||
} else if (C == '\\') {
|
|
||||||
O << "\\\\";
|
|
||||||
} else if (isprint(C)) {
|
|
||||||
O << C;
|
|
||||||
} else {
|
|
||||||
switch (C) {
|
|
||||||
case '\b': O << "\\b"; break;
|
|
||||||
case '\f': O << "\\f"; break;
|
|
||||||
case '\n': O << "\\n"; break;
|
|
||||||
case '\r': O << "\\r"; break;
|
|
||||||
case '\t': O << "\\t"; break;
|
|
||||||
default:
|
|
||||||
O << '\\';
|
|
||||||
O << toOctal(C >> 6);
|
|
||||||
O << toOctal(C >> 3);
|
|
||||||
O << toOctal(C >> 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
O << "\"";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print out the specified constant, without a storage class. Only the
|
|
||||||
// constants valid in constant expressions can occur here.
|
|
||||||
void Printer::emitConstantValueOnly(const Constant *CV) {
|
|
||||||
if (CV->isNullValue())
|
|
||||||
O << "0";
|
|
||||||
else if (const ConstantBool *CB = dyn_cast<ConstantBool>(CV)) {
|
|
||||||
assert(CB == ConstantBool::True);
|
|
||||||
O << "1";
|
|
||||||
} else if (const ConstantSInt *CI = dyn_cast<ConstantSInt>(CV))
|
|
||||||
O << CI->getValue();
|
|
||||||
else if (const ConstantUInt *CI = dyn_cast<ConstantUInt>(CV))
|
|
||||||
O << CI->getValue();
|
|
||||||
else if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV))
|
|
||||||
// This is a constant address for a global variable or function. Use the
|
|
||||||
// name of the variable or function as the address value.
|
|
||||||
O << Mang->getValueName(GV);
|
|
||||||
else if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(CV)) {
|
|
||||||
const TargetData &TD = TM.getTargetData();
|
|
||||||
switch (CE->getOpcode()) {
|
|
||||||
case Instruction::GetElementPtr: {
|
|
||||||
// generate a symbolic expression for the byte address
|
|
||||||
const Constant *ptrVal = CE->getOperand(0);
|
|
||||||
std::vector<Value*> idxVec(CE->op_begin()+1, CE->op_end());
|
|
||||||
if (unsigned Offset = TD.getIndexedOffset(ptrVal->getType(), idxVec)) {
|
|
||||||
O << "(";
|
|
||||||
emitConstantValueOnly(ptrVal);
|
|
||||||
O << ") + " << Offset;
|
|
||||||
} else {
|
|
||||||
emitConstantValueOnly(ptrVal);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Instruction::Cast: {
|
|
||||||
// Support only non-converting or widening casts for now, that is, ones
|
|
||||||
// that do not involve a change in value. This assertion is really gross,
|
|
||||||
// and may not even be a complete check.
|
|
||||||
Constant *Op = CE->getOperand(0);
|
|
||||||
const Type *OpTy = Op->getType(), *Ty = CE->getType();
|
|
||||||
|
|
||||||
// Remember, kids, pointers on x86 can be losslessly converted back and
|
|
||||||
// forth into 32-bit or wider integers, regardless of signedness. :-P
|
|
||||||
assert(((isa<PointerType>(OpTy)
|
|
||||||
&& (Ty == Type::LongTy || Ty == Type::ULongTy
|
|
||||||
|| Ty == Type::IntTy || Ty == Type::UIntTy))
|
|
||||||
|| (isa<PointerType>(Ty)
|
|
||||||
&& (OpTy == Type::LongTy || OpTy == Type::ULongTy
|
|
||||||
|| OpTy == Type::IntTy || OpTy == Type::UIntTy))
|
|
||||||
|| (((TD.getTypeSize(Ty) >= TD.getTypeSize(OpTy))
|
|
||||||
&& OpTy->isLosslesslyConvertibleTo(Ty))))
|
|
||||||
&& "FIXME: Don't yet support this kind of constant cast expr");
|
|
||||||
O << "(";
|
|
||||||
emitConstantValueOnly(Op);
|
|
||||||
O << ")";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Instruction::Add:
|
|
||||||
O << "(";
|
|
||||||
emitConstantValueOnly(CE->getOperand(0));
|
|
||||||
O << ") + (";
|
|
||||||
emitConstantValueOnly(CE->getOperand(1));
|
|
||||||
O << ")";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(0 && "Unsupported operator!");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
assert(0 && "Unknown constant value!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print a constant value or values, with the appropriate storage class as a
|
|
||||||
// prefix.
|
|
||||||
void Printer::emitGlobalConstant(const Constant *CV) {
|
|
||||||
const TargetData &TD = TM.getTargetData();
|
|
||||||
|
|
||||||
if (const ConstantArray *CVA = dyn_cast<ConstantArray>(CV)) {
|
|
||||||
if (isStringCompatible(CVA)) {
|
|
||||||
O << "\t.ascii ";
|
|
||||||
printAsCString(O, CVA);
|
|
||||||
O << "\n";
|
|
||||||
} else { // Not a string. Print the values in successive locations
|
|
||||||
for (unsigned i=0, e = CVA->getNumOperands(); i != e; i++)
|
|
||||||
emitGlobalConstant(CVA->getOperand(i));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
} else if (const ConstantStruct *CVS = dyn_cast<ConstantStruct>(CV)) {
|
|
||||||
// Print the fields in successive locations. Pad to align if needed!
|
|
||||||
const StructLayout *cvsLayout = TD.getStructLayout(CVS->getType());
|
|
||||||
unsigned sizeSoFar = 0;
|
|
||||||
for (unsigned i = 0, e = CVS->getNumOperands(); i != e; i++) {
|
|
||||||
const Constant* field = CVS->getOperand(i);
|
|
||||||
|
|
||||||
// Check if padding is needed and insert one or more 0s.
|
|
||||||
unsigned fieldSize = TD.getTypeSize(field->getType());
|
|
||||||
unsigned padSize = ((i == e-1? cvsLayout->StructSize
|
|
||||||
: cvsLayout->MemberOffsets[i+1])
|
|
||||||
- cvsLayout->MemberOffsets[i]) - fieldSize;
|
|
||||||
sizeSoFar += fieldSize + padSize;
|
|
||||||
|
|
||||||
// Now print the actual field value
|
|
||||||
emitGlobalConstant(field);
|
|
||||||
|
|
||||||
// Insert the field padding unless it's zero bytes...
|
|
||||||
if (padSize)
|
|
||||||
O << "\t.space\t " << padSize << "\n";
|
|
||||||
}
|
|
||||||
assert(sizeSoFar == cvsLayout->StructSize &&
|
|
||||||
"Layout of constant struct may be incorrect!");
|
|
||||||
return;
|
|
||||||
} else if (const ConstantFP *CFP = dyn_cast<ConstantFP>(CV)) {
|
|
||||||
// FP Constants are printed as integer constants to avoid losing
|
|
||||||
// precision...
|
|
||||||
double Val = CFP->getValue();
|
|
||||||
switch (CFP->getType()->getTypeID()) {
|
|
||||||
default: assert(0 && "Unknown floating point type!");
|
|
||||||
case Type::FloatTyID: {
|
|
||||||
union FU { // Abide by C TBAA rules
|
|
||||||
float FVal;
|
|
||||||
unsigned UVal;
|
|
||||||
} U;
|
|
||||||
U.FVal = Val;
|
|
||||||
O << ".long\t" << U.UVal << "\t; float " << Val << "\n";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case Type::DoubleTyID: {
|
|
||||||
union DU { // Abide by C TBAA rules
|
|
||||||
double FVal;
|
|
||||||
uint64_t UVal;
|
|
||||||
struct {
|
|
||||||
uint32_t MSWord;
|
|
||||||
uint32_t LSWord;
|
|
||||||
} T;
|
|
||||||
} U;
|
|
||||||
U.FVal = Val;
|
|
||||||
|
|
||||||
O << ".long\t" << U.T.MSWord << "\t; double most significant word "
|
|
||||||
<< Val << "\n";
|
|
||||||
O << ".long\t" << U.T.LSWord << "\t; double least significant word "
|
|
||||||
<< Val << "\n";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (CV->getType() == Type::ULongTy || CV->getType() == Type::LongTy) {
|
|
||||||
if (const ConstantInt *CI = dyn_cast<ConstantInt>(CV)) {
|
|
||||||
union DU { // Abide by C TBAA rules
|
|
||||||
int64_t UVal;
|
|
||||||
struct {
|
|
||||||
uint32_t MSWord;
|
|
||||||
uint32_t LSWord;
|
|
||||||
} T;
|
|
||||||
} U;
|
|
||||||
U.UVal = CI->getRawValue();
|
|
||||||
|
|
||||||
O << ".long\t" << U.T.MSWord << "\t; Double-word most significant word "
|
|
||||||
<< U.UVal << "\n";
|
|
||||||
O << ".long\t" << U.T.LSWord << "\t; Double-word least significant word "
|
|
||||||
<< U.UVal << "\n";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const Type *type = CV->getType();
|
|
||||||
O << "\t";
|
|
||||||
switch (type->getTypeID()) {
|
|
||||||
case Type::UByteTyID: case Type::SByteTyID:
|
|
||||||
O << ".byte";
|
|
||||||
break;
|
|
||||||
case Type::UShortTyID: case Type::ShortTyID:
|
|
||||||
O << ".short";
|
|
||||||
break;
|
|
||||||
case Type::BoolTyID:
|
|
||||||
case Type::PointerTyID:
|
|
||||||
case Type::UIntTyID: case Type::IntTyID:
|
|
||||||
O << ".long";
|
|
||||||
break;
|
|
||||||
case Type::ULongTyID: case Type::LongTyID:
|
|
||||||
assert (0 && "Should have already output double-word constant.");
|
|
||||||
case Type::FloatTyID: case Type::DoubleTyID:
|
|
||||||
assert (0 && "Should have already output floating point constant.");
|
|
||||||
default:
|
|
||||||
if (CV == Constant::getNullValue(type)) { // Zero initializer?
|
|
||||||
O << ".space\t" << TD.getTypeSize(type) << "\n";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::cerr << "Can't handle printing: " << *CV;
|
|
||||||
abort();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
O << "\t";
|
|
||||||
emitConstantValueOnly(CV);
|
|
||||||
O << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
/// printConstantPool - Print to the current output stream assembly
|
|
||||||
/// representations of the constants in the constant pool MCP. This is
|
|
||||||
/// used to print out constants which have been "spilled to memory" by
|
|
||||||
/// the code generator.
|
|
||||||
///
|
|
||||||
void Printer::printConstantPool(MachineConstantPool *MCP) {
|
|
||||||
const std::vector<Constant*> &CP = MCP->getConstants();
|
|
||||||
const TargetData &TD = TM.getTargetData();
|
|
||||||
|
|
||||||
if (CP.empty()) return;
|
|
||||||
|
|
||||||
for (unsigned i = 0, e = CP.size(); i != e; ++i) {
|
|
||||||
O << "\t.const\n";
|
|
||||||
O << "\t.align " << (unsigned)TD.getTypeAlignment(CP[i]->getType())
|
|
||||||
<< "\n";
|
|
||||||
O << ".CPI" << CurrentFnName << "_" << i << ":\t\t\t\t\t;"
|
|
||||||
<< *CP[i] << "\n";
|
|
||||||
emitGlobalConstant(CP[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// runOnMachineFunction - This uses the printMachineInstruction()
|
|
||||||
/// method to print assembly for each instruction.
|
|
||||||
///
|
|
||||||
bool Printer::runOnMachineFunction(MachineFunction &MF) {
|
|
||||||
O << "\n\n";
|
|
||||||
// What's my mangled name?
|
|
||||||
CurrentFnName = Mang->getValueName(MF.getFunction());
|
|
||||||
|
|
||||||
// Print out constants referenced by the function
|
|
||||||
printConstantPool(MF.getConstantPool());
|
|
||||||
|
|
||||||
// Print out labels for the function.
|
|
||||||
O << "\t.text\n";
|
|
||||||
O << "\t.globl\t" << CurrentFnName << "\n";
|
|
||||||
O << "\t.align 2\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.
|
|
||||||
O << ".LBB" << CurrentFnName << "_" << I->getNumber() << ":\t; "
|
|
||||||
<< I->getBasicBlock()->getName() << "\n";
|
|
||||||
for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
|
|
||||||
II != E; ++II) {
|
|
||||||
// Print the assembly for the instruction.
|
|
||||||
O << "\t";
|
|
||||||
printMachineInstruction(II);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
++LabelNumber;
|
|
||||||
|
|
||||||
// We didn't modify anything.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Printer::printOp(const MachineOperand &MO,
|
|
||||||
bool elideOffsetKeyword /* = false */) {
|
|
||||||
const MRegisterInfo &RI = *TM.getRegisterInfo();
|
|
||||||
int new_symbol;
|
|
||||||
|
|
||||||
switch (MO.getType()) {
|
|
||||||
case MachineOperand::MO_VirtualRegister:
|
|
||||||
if (Value *V = MO.getVRegValueOrNull()) {
|
|
||||||
O << "<" << V->getName() << ">";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// FALLTHROUGH
|
|
||||||
case MachineOperand::MO_MachineRegister:
|
|
||||||
case MachineOperand::MO_CCRegister:
|
|
||||||
O << LowercaseString(RI.get(MO.getReg()).Name);
|
|
||||||
return;
|
|
||||||
|
|
||||||
case MachineOperand::MO_SignExtendedImmed:
|
|
||||||
case MachineOperand::MO_UnextendedImmed:
|
|
||||||
std::cerr << "printOp() does not handle immediate values\n";
|
|
||||||
abort();
|
|
||||||
return;
|
|
||||||
|
|
||||||
case MachineOperand::MO_PCRelativeDisp:
|
|
||||||
std::cerr << "Shouldn't use addPCDisp() when building PPC MachineInstrs";
|
|
||||||
abort();
|
|
||||||
return;
|
|
||||||
|
|
||||||
case MachineOperand::MO_MachineBasicBlock: {
|
|
||||||
MachineBasicBlock *MBBOp = MO.getMachineBasicBlock();
|
|
||||||
O << ".LBB" << Mang->getValueName(MBBOp->getParent()->getFunction())
|
|
||||||
<< "_" << MBBOp->getNumber() << "\t; "
|
|
||||||
<< MBBOp->getBasicBlock()->getName();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
case MachineOperand::MO_ConstantPoolIndex:
|
|
||||||
O << ".CPI" << CurrentFnName << "_" << MO.getConstantPoolIndex();
|
|
||||||
return;
|
|
||||||
|
|
||||||
case MachineOperand::MO_ExternalSymbol:
|
|
||||||
O << MO.getSymbolName();
|
|
||||||
return;
|
|
||||||
|
|
||||||
case MachineOperand::MO_GlobalAddress:
|
|
||||||
if (!elideOffsetKeyword) {
|
|
||||||
GlobalValue *GV = MO.getGlobal();
|
|
||||||
std::string Name = Mang->getValueName(GV);
|
|
||||||
|
|
||||||
// Dynamically-resolved functions need a stub for the function
|
|
||||||
Function *F = dyn_cast<Function>(GV);
|
|
||||||
if (F && F->isExternal() &&
|
|
||||||
TM.CalledFunctions.find(F) != TM.CalledFunctions.end()) {
|
|
||||||
FnStubs.insert(Name);
|
|
||||||
O << "L" << Name << "$stub";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// External global variables need a non-lazily-resolved stub
|
|
||||||
if (!GV->hasInternalLinkage() &&
|
|
||||||
TM.AddressTaken.find(GV) != TM.AddressTaken.end()) {
|
|
||||||
GVStubs.insert(Name);
|
|
||||||
O << "L" << Name << "$non_lazy_ptr";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
O << Mang->getValueName(GV);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
|
|
||||||
default:
|
|
||||||
O << "<unknown operand type: " << MO.getType() << ">";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Printer::printImmOp(const MachineOperand &MO, unsigned ArgType) {
|
|
||||||
int Imm = MO.getImmedValue();
|
|
||||||
if (ArgType == PPC32II::Simm16 || ArgType == PPC32II::Disimm16) {
|
|
||||||
O << (short)Imm;
|
|
||||||
} else if (ArgType == PPC32II::Zimm16) {
|
|
||||||
O << (unsigned short)Imm;
|
|
||||||
} else {
|
|
||||||
O << Imm;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// printMachineInstruction -- Print out a single PPC32 LLVM instruction
|
|
||||||
/// MI in Darwin syntax to the current output stream.
|
|
||||||
///
|
|
||||||
void Printer::printMachineInstruction(const MachineInstr *MI) {
|
|
||||||
unsigned Opcode = MI->getOpcode();
|
|
||||||
const TargetInstrInfo &TII = *TM.getInstrInfo();
|
|
||||||
const TargetInstrDescriptor &Desc = TII.get(Opcode);
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
unsigned ArgCount = MI->getNumOperands();
|
|
||||||
unsigned ArgType[] = {
|
|
||||||
(Desc.TSFlags >> PPC32II::Arg0TypeShift) & PPC32II::ArgTypeMask,
|
|
||||||
(Desc.TSFlags >> PPC32II::Arg1TypeShift) & PPC32II::ArgTypeMask,
|
|
||||||
(Desc.TSFlags >> PPC32II::Arg2TypeShift) & PPC32II::ArgTypeMask,
|
|
||||||
(Desc.TSFlags >> PPC32II::Arg3TypeShift) & PPC32II::ArgTypeMask,
|
|
||||||
(Desc.TSFlags >> PPC32II::Arg4TypeShift) & PPC32II::ArgTypeMask
|
|
||||||
};
|
|
||||||
assert(((Desc.TSFlags & PPC32II::VMX) == 0) &&
|
|
||||||
"Instruction requires VMX support");
|
|
||||||
assert(((Desc.TSFlags & PPC32II::PPC64) == 0) &&
|
|
||||||
"Instruction requires 64 bit support");
|
|
||||||
++EmittedInsts;
|
|
||||||
|
|
||||||
// CALLpcrel and CALLindirect are handled specially here to print only the
|
|
||||||
// appropriate number of args that the assembler expects. This is because
|
|
||||||
// may have many arguments appended to record the uses of registers that are
|
|
||||||
// holding arguments to the called function.
|
|
||||||
if (Opcode == PPC32::COND_BRANCH) {
|
|
||||||
std::cerr << "Error: untranslated conditional branch psuedo instruction!\n";
|
|
||||||
abort();
|
|
||||||
} else if (Opcode == PPC32::IMPLICIT_DEF) {
|
|
||||||
O << "; IMPLICIT DEF ";
|
|
||||||
printOp(MI->getOperand(0));
|
|
||||||
O << "\n";
|
|
||||||
return;
|
|
||||||
} else if (Opcode == PPC32::CALLpcrel) {
|
|
||||||
O << TII.getName(Opcode) << " ";
|
|
||||||
printOp(MI->getOperand(0));
|
|
||||||
O << "\n";
|
|
||||||
return;
|
|
||||||
} else if (Opcode == PPC32::CALLindirect) {
|
|
||||||
O << TII.getName(Opcode) << " ";
|
|
||||||
printImmOp(MI->getOperand(0), ArgType[0]);
|
|
||||||
O << ", ";
|
|
||||||
printImmOp(MI->getOperand(1), ArgType[0]);
|
|
||||||
O << "\n";
|
|
||||||
return;
|
|
||||||
} else if (Opcode == PPC32::MovePCtoLR) {
|
|
||||||
// FIXME: should probably be converted to cout.width and cout.fill
|
|
||||||
O << "bl \"L0000" << LabelNumber << "$pb\"\n";
|
|
||||||
O << "\"L0000" << LabelNumber << "$pb\":\n";
|
|
||||||
O << "\tmflr ";
|
|
||||||
printOp(MI->getOperand(0));
|
|
||||||
O << "\n";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
O << TII.getName(Opcode) << " ";
|
|
||||||
if (Opcode == PPC32::LOADLoDirect || Opcode == PPC32::LOADLoIndirect) {
|
|
||||||
printOp(MI->getOperand(0));
|
|
||||||
O << ", lo16(";
|
|
||||||
printOp(MI->getOperand(2));
|
|
||||||
O << "-\"L0000" << LabelNumber << "$pb\")";
|
|
||||||
O << "(";
|
|
||||||
if (MI->getOperand(1).getReg() == PPC32::R0)
|
|
||||||
O << "0";
|
|
||||||
else
|
|
||||||
printOp(MI->getOperand(1));
|
|
||||||
O << ")\n";
|
|
||||||
} else if (Opcode == PPC32::LOADHiAddr) {
|
|
||||||
printOp(MI->getOperand(0));
|
|
||||||
O << ", ";
|
|
||||||
if (MI->getOperand(1).getReg() == PPC32::R0)
|
|
||||||
O << "0";
|
|
||||||
else
|
|
||||||
printOp(MI->getOperand(1));
|
|
||||||
O << ", ha16(" ;
|
|
||||||
printOp(MI->getOperand(2));
|
|
||||||
O << "-\"L0000" << LabelNumber << "$pb\")\n";
|
|
||||||
} else if (ArgCount == 3 && ArgType[1] == PPC32II::Disimm16) {
|
|
||||||
printOp(MI->getOperand(0));
|
|
||||||
O << ", ";
|
|
||||||
printImmOp(MI->getOperand(1), ArgType[1]);
|
|
||||||
O << "(";
|
|
||||||
if (MI->getOperand(2).hasAllocatedReg() &&
|
|
||||||
MI->getOperand(2).getReg() == PPC32::R0)
|
|
||||||
O << "0";
|
|
||||||
else
|
|
||||||
printOp(MI->getOperand(2));
|
|
||||||
O << ")\n";
|
|
||||||
} else {
|
|
||||||
for (i = 0; i < ArgCount; ++i) {
|
|
||||||
// addi and friends
|
|
||||||
if (i == 1 && ArgCount == 3 && ArgType[2] == PPC32II::Simm16 &&
|
|
||||||
MI->getOperand(1).hasAllocatedReg() &&
|
|
||||||
MI->getOperand(1).getReg() == PPC32::R0) {
|
|
||||||
O << "0";
|
|
||||||
// for long branch support, bc $+8
|
|
||||||
} else if (i == 1 && ArgCount == 2 && MI->getOperand(1).isImmediate() &&
|
|
||||||
TII.isBranch(MI->getOpcode())) {
|
|
||||||
O << "$+8";
|
|
||||||
assert(8 == MI->getOperand(i).getImmedValue()
|
|
||||||
&& "branch off PC not to pc+8?");
|
|
||||||
//printOp(MI->getOperand(i));
|
|
||||||
} else if (MI->getOperand(i).isImmediate()) {
|
|
||||||
printImmOp(MI->getOperand(i), ArgType[i]);
|
|
||||||
} else {
|
|
||||||
printOp(MI->getOperand(i));
|
|
||||||
}
|
|
||||||
if (ArgCount - 1 == i)
|
|
||||||
O << "\n";
|
|
||||||
else
|
|
||||||
O << ", ";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Printer::doInitialization(Module &M) {
|
|
||||||
Mang = new Mangler(M, true);
|
|
||||||
return false; // success
|
|
||||||
}
|
|
||||||
|
|
||||||
// SwitchSection - Switch to the specified section of the executable if we are
|
|
||||||
// not already in it!
|
|
||||||
//
|
|
||||||
static void SwitchSection(std::ostream &OS, std::string &CurSection,
|
|
||||||
const char *NewSection) {
|
|
||||||
if (CurSection != NewSection) {
|
|
||||||
CurSection = NewSection;
|
|
||||||
if (!CurSection.empty())
|
|
||||||
OS << "\t" << NewSection << "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Printer::doFinalization(Module &M) {
|
|
||||||
const TargetData &TD = TM.getTargetData();
|
|
||||||
std::string CurSection;
|
|
||||||
|
|
||||||
// Print out module-level global variables here.
|
|
||||||
for (Module::const_giterator I = M.gbegin(), E = M.gend(); I != E; ++I)
|
|
||||||
if (I->hasInitializer()) { // External global require no code
|
|
||||||
O << "\n\n";
|
|
||||||
std::string name = Mang->getValueName(I);
|
|
||||||
Constant *C = I->getInitializer();
|
|
||||||
unsigned Size = TD.getTypeSize(C->getType());
|
|
||||||
unsigned Align = TD.getTypeAlignment(C->getType());
|
|
||||||
|
|
||||||
if (C->isNullValue() && /* FIXME: Verify correct */
|
|
||||||
(I->hasInternalLinkage() || I->hasWeakLinkage())) {
|
|
||||||
SwitchSection(O, CurSection, ".data");
|
|
||||||
if (I->hasInternalLinkage())
|
|
||||||
O << ".lcomm " << name << "," << TD.getTypeSize(C->getType())
|
|
||||||
<< "," << (unsigned)TD.getTypeAlignment(C->getType());
|
|
||||||
else
|
|
||||||
O << ".comm " << name << "," << TD.getTypeSize(C->getType());
|
|
||||||
O << "\t\t; ";
|
|
||||||
WriteAsOperand(O, I, true, true, &M);
|
|
||||||
O << "\n";
|
|
||||||
} else {
|
|
||||||
switch (I->getLinkage()) {
|
|
||||||
case GlobalValue::LinkOnceLinkage:
|
|
||||||
O << ".section __TEXT,__textcoal_nt,coalesced,no_toc\n"
|
|
||||||
<< ".weak_definition " << name << '\n'
|
|
||||||
<< ".private_extern " << name << '\n'
|
|
||||||
<< ".section __DATA,__datacoal_nt,coalesced,no_toc\n";
|
|
||||||
LinkOnceStubs.insert(name);
|
|
||||||
break;
|
|
||||||
case GlobalValue::WeakLinkage: // FIXME: Verify correct for weak.
|
|
||||||
// Nonnull linkonce -> weak
|
|
||||||
O << "\t.weak " << name << "\n";
|
|
||||||
SwitchSection(O, CurSection, "");
|
|
||||||
O << "\t.section\t.llvm.linkonce.d." << name << ",\"aw\",@progbits\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 << "\t.globl " << name << "\n";
|
|
||||||
// FALL THROUGH
|
|
||||||
case GlobalValue::InternalLinkage:
|
|
||||||
SwitchSection(O, CurSection, ".data");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
O << "\t.align " << Align << "\n";
|
|
||||||
O << name << ":\t\t\t\t; ";
|
|
||||||
WriteAsOperand(O, I, true, true, &M);
|
|
||||||
O << " = ";
|
|
||||||
WriteAsOperand(O, C, false, false, &M);
|
|
||||||
O << "\n";
|
|
||||||
emitGlobalConstant(C);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Output stubs for link-once variables
|
|
||||||
if (LinkOnceStubs.begin() != LinkOnceStubs.end())
|
|
||||||
O << ".data\n.align 2\n";
|
|
||||||
for (std::set<std::string>::iterator i = LinkOnceStubs.begin(),
|
|
||||||
e = LinkOnceStubs.end(); i != e; ++i) {
|
|
||||||
O << *i << "$non_lazy_ptr:\n"
|
|
||||||
<< "\t.long\t" << *i << '\n';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Output stubs for dynamically-linked functions
|
|
||||||
for (std::set<std::string>::iterator i = FnStubs.begin(), e = FnStubs.end();
|
|
||||||
i != e; ++i)
|
|
||||||
{
|
|
||||||
O << ".data\n";
|
|
||||||
O << ".section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32\n";
|
|
||||||
O << "\t.align 2\n";
|
|
||||||
O << "L" << *i << "$stub:\n";
|
|
||||||
O << "\t.indirect_symbol " << *i << "\n";
|
|
||||||
O << "\tmflr r0\n";
|
|
||||||
O << "\tbcl 20,31,L0$" << *i << "\n";
|
|
||||||
O << "L0$" << *i << ":\n";
|
|
||||||
O << "\tmflr r11\n";
|
|
||||||
O << "\taddis r11,r11,ha16(L" << *i << "$lazy_ptr-L0$" << *i << ")\n";
|
|
||||||
O << "\tmtlr r0\n";
|
|
||||||
O << "\tlwzu r12,lo16(L" << *i << "$lazy_ptr-L0$" << *i << ")(r11)\n";
|
|
||||||
O << "\tmtctr r12\n";
|
|
||||||
O << "\tbctr\n";
|
|
||||||
O << ".data\n";
|
|
||||||
O << ".lazy_symbol_pointer\n";
|
|
||||||
O << "L" << *i << "$lazy_ptr:\n";
|
|
||||||
O << "\t.indirect_symbol " << *i << "\n";
|
|
||||||
O << "\t.long dyld_stub_binding_helper\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
O << "\n";
|
|
||||||
|
|
||||||
// Output stubs for external global variables
|
|
||||||
if (GVStubs.begin() != GVStubs.end())
|
|
||||||
O << ".data\n.non_lazy_symbol_pointer\n";
|
|
||||||
for (std::set<std::string>::iterator i = GVStubs.begin(), e = GVStubs.end();
|
|
||||||
i != e; ++i) {
|
|
||||||
O << "L" << *i << "$non_lazy_ptr:\n";
|
|
||||||
O << "\t.indirect_symbol " << *i << "\n";
|
|
||||||
O << "\t.long\t0\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
delete Mang;
|
|
||||||
return false; // success
|
|
||||||
}
|
|
||||||
|
|
||||||
} // End llvm namespace
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
//===-- PowerPCCodeEmitter.cpp - JIT Code Emitter for PowerPC -----*- C++ -*-=//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "PowerPCTargetMachine.h"
|
|
||||||
|
|
||||||
namespace llvm {
|
|
||||||
|
|
||||||
/// addPassesToEmitMachineCode - Add passes to the specified pass manager to get
|
|
||||||
/// machine code emitted. This uses a MachineCodeEmitter object to handle
|
|
||||||
/// actually outputting the machine code and resolving things like the address
|
|
||||||
/// of functions. This method should returns true if machine code emission is
|
|
||||||
/// not supported.
|
|
||||||
///
|
|
||||||
bool PowerPCTargetMachine::addPassesToEmitMachineCode(FunctionPassManager &PM,
|
|
||||||
MachineCodeEmitter &MCE) {
|
|
||||||
return true;
|
|
||||||
// It should go something like this:
|
|
||||||
// PM.add(new Emitter(MCE)); // Machine code emitter pass for PowerPC
|
|
||||||
// Delete machine code for this function after emitting it:
|
|
||||||
// PM.add(createMachineCodeDeleter());
|
|
||||||
}
|
|
||||||
|
|
||||||
void *PowerPCJITInfo::getJITStubForFunction(Function *F,
|
|
||||||
MachineCodeEmitter &MCE) {
|
|
||||||
assert (0 && "PowerPCJITInfo::getJITStubForFunction not implemented");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PowerPCJITInfo::replaceMachineCodeForFunction (void *Old, void *New) {
|
|
||||||
assert (0 && "PowerPCJITInfo::replaceMachineCodeForFunction not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end llvm namespace
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,112 +0,0 @@
|
|||||||
//===-- DelaySlotFiller.cpp - SparcV8 delay slot filler -------------------===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// Simple local delay slot filler for SparcV8 machine code
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "SparcV8.h"
|
|
||||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
|
||||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
|
||||||
#include "Support/Statistic.h"
|
|
||||||
|
|
||||||
using namespace llvm;
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
Statistic<> FilledSlots ("delayslotfiller", "Num. of delay slots filled");
|
|
||||||
|
|
||||||
struct Filler : public MachineFunctionPass {
|
|
||||||
/// Target machine description which we query for reg. names, data
|
|
||||||
/// layout, etc.
|
|
||||||
///
|
|
||||||
TargetMachine &TM;
|
|
||||||
|
|
||||||
Filler (TargetMachine &tm) : TM (tm) { }
|
|
||||||
|
|
||||||
virtual const char *getPassName () const {
|
|
||||||
return "SparcV8 Delay Slot Filler";
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
} // end of anonymous namespace
|
|
||||||
|
|
||||||
/// createSparcV8DelaySlotFillerPass - Returns a pass that fills in delay
|
|
||||||
/// slots in SparcV8 MachineFunctions
|
|
||||||
///
|
|
||||||
FunctionPass *llvm::createSparcV8DelaySlotFillerPass (TargetMachine &tm) {
|
|
||||||
return new Filler (tm);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool hasDelaySlot (unsigned Opcode) {
|
|
||||||
switch (Opcode) {
|
|
||||||
case V8::BA:
|
|
||||||
case V8::BCC:
|
|
||||||
case V8::BCS:
|
|
||||||
case V8::BE:
|
|
||||||
case V8::BG:
|
|
||||||
case V8::BGE:
|
|
||||||
case V8::BGU:
|
|
||||||
case V8::BL:
|
|
||||||
case V8::BLE:
|
|
||||||
case V8::BLEU:
|
|
||||||
case V8::BNE:
|
|
||||||
case V8::CALL:
|
|
||||||
case V8::JMPLrr:
|
|
||||||
case V8::RETL:
|
|
||||||
case V8::FBA:
|
|
||||||
case V8::FBN:
|
|
||||||
case V8::FBU:
|
|
||||||
case V8::FBG:
|
|
||||||
case V8::FBUG:
|
|
||||||
case V8::FBL:
|
|
||||||
case V8::FBUL:
|
|
||||||
case V8::FBLG:
|
|
||||||
case V8::FBNE:
|
|
||||||
case V8::FBE:
|
|
||||||
case V8::FBUE:
|
|
||||||
case V8::FBGE:
|
|
||||||
case V8::FBUGE:
|
|
||||||
case V8::FBLE:
|
|
||||||
case V8::FBULE:
|
|
||||||
case V8::FBO:
|
|
||||||
case V8::FCMPS:
|
|
||||||
case V8::FCMPD:
|
|
||||||
case V8::FCMPES:
|
|
||||||
case V8::FCMPED:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// runOnMachineBasicBlock - Fill in delay slots for the given basic block.
|
|
||||||
/// Currently, we fill delay slots with NOPs. We assume there is only one
|
|
||||||
/// delay slot per delayed instruction.
|
|
||||||
///
|
|
||||||
bool Filler::runOnMachineBasicBlock (MachineBasicBlock &MBB) {
|
|
||||||
bool Changed = false;
|
|
||||||
for (MachineBasicBlock::iterator I = MBB.begin (); I != MBB.end (); ++I)
|
|
||||||
if (hasDelaySlot (I->getOpcode ())) {
|
|
||||||
MachineBasicBlock::iterator J = I;
|
|
||||||
++J;
|
|
||||||
BuildMI (MBB, J, V8::NOP, 0);
|
|
||||||
++FilledSlots;
|
|
||||||
Changed = true;
|
|
||||||
}
|
|
||||||
return Changed;
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,46 +0,0 @@
|
|||||||
##===- lib/Target/SparcV8/Makefile -------------------------*- Makefile -*-===##
|
|
||||||
#
|
|
||||||
# The LLVM Compiler Infrastructure
|
|
||||||
#
|
|
||||||
# This file was developed by the LLVM research group and is distributed under
|
|
||||||
# the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
#
|
|
||||||
##===----------------------------------------------------------------------===##
|
|
||||||
LEVEL = ../../..
|
|
||||||
LIBRARYNAME = sparcv8
|
|
||||||
include $(LEVEL)/Makefile.common
|
|
||||||
|
|
||||||
TDFILES := $(wildcard $(SourceDir)/*.td) $(SourceDir)/../Target.td
|
|
||||||
TDFILE := $(SourceDir)/SparcV8.td
|
|
||||||
|
|
||||||
# Make sure that tblgen is run, first thing.
|
|
||||||
$(SourceDepend): SparcV8GenRegisterInfo.h.inc SparcV8GenRegisterNames.inc \
|
|
||||||
SparcV8GenRegisterInfo.inc SparcV8GenInstrNames.inc \
|
|
||||||
SparcV8GenInstrInfo.inc SparcV8GenInstrSelector.inc
|
|
||||||
|
|
||||||
SparcV8GenRegisterNames.inc:: $(TDFILES) $(TBLGEN)
|
|
||||||
@echo "Building SparcV8.td register names with tblgen"
|
|
||||||
$(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $(TDFILE) -gen-register-enums -o $@
|
|
||||||
|
|
||||||
SparcV8GenRegisterInfo.h.inc:: $(TDFILES) $(TBLGEN)
|
|
||||||
@echo "Building SparcV8.td register information header with tblgen"
|
|
||||||
$(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $(TDFILE) -gen-register-desc-header -o $@
|
|
||||||
|
|
||||||
SparcV8GenRegisterInfo.inc:: $(TDFILES) $(TBLGEN)
|
|
||||||
@echo "Building SparcV8.td register information implementation with tblgen"
|
|
||||||
$(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $(TDFILE) -gen-register-desc -o $@
|
|
||||||
|
|
||||||
SparcV8GenInstrNames.inc:: $(TDFILES) $(TBLGEN)
|
|
||||||
@echo "Building SparcV8.td instruction names with tblgen"
|
|
||||||
$(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $(TDFILE) -gen-instr-enums -o $@
|
|
||||||
|
|
||||||
SparcV8GenInstrInfo.inc:: $(TDFILES) $(TBLGEN)
|
|
||||||
@echo "Building SparcV8.td instruction information with tblgen"
|
|
||||||
$(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $(TDFILE) -gen-instr-desc -o $@
|
|
||||||
|
|
||||||
SparcV8GenInstrSelector.inc:: $(TDFILES) $(TBLGEN)
|
|
||||||
@echo "Building SparcV8.td instruction selector with tblgen"
|
|
||||||
$(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $(TDFILE) -gen-instr-selector -o $@
|
|
||||||
|
|
||||||
clean::
|
|
||||||
$(VERB) rm -f *.inc
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
|
|
||||||
SparcV8 backend skeleton
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
This directory houses a 32-bit SPARC V8 backend employing a expander-based
|
|
||||||
instruction selector. It is not yet functionally complete. Watch
|
|
||||||
this space for more news coming soon!
|
|
||||||
|
|
||||||
To-do
|
|
||||||
-----
|
|
||||||
|
|
||||||
* support 64-bit (double FP, long, ulong) arguments to functions
|
|
||||||
* support functions with more than 6 args
|
|
||||||
* support setcc on longs
|
|
||||||
* support basic binary operations on longs
|
|
||||||
* support casting <=32-bit integers, bools to long
|
|
||||||
* support casting 64-bit integers to FP types
|
|
||||||
|
|
||||||
$Date$
|
|
||||||
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
//===-- SparcV8.h - Top-level interface for SparcV8 representation -*- C++ -*-//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and 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 LLVM
|
|
||||||
// SparcV8 back-end.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef TARGET_SPARCV8_H
|
|
||||||
#define TARGET_SPARCV8_H
|
|
||||||
|
|
||||||
#include <iosfwd>
|
|
||||||
|
|
||||||
namespace llvm {
|
|
||||||
|
|
||||||
class FunctionPass;
|
|
||||||
class TargetMachine;
|
|
||||||
|
|
||||||
FunctionPass *createSparcV8SimpleInstructionSelector(TargetMachine &TM);
|
|
||||||
FunctionPass *createSparcV8CodePrinterPass(std::ostream &OS,
|
|
||||||
TargetMachine &TM);
|
|
||||||
FunctionPass *createSparcV8DelaySlotFillerPass(TargetMachine &TM);
|
|
||||||
|
|
||||||
} // end namespace llvm;
|
|
||||||
|
|
||||||
// Defines symbolic names for SparcV8 registers. This defines a mapping from
|
|
||||||
// register name to register number.
|
|
||||||
//
|
|
||||||
#include "SparcV8GenRegisterNames.inc"
|
|
||||||
|
|
||||||
// Defines symbolic names for the SparcV8 instructions.
|
|
||||||
//
|
|
||||||
#include "SparcV8GenInstrNames.inc"
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
//===- SparcV8.td - Describe the SparcV8 Target Machine ---------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
// Get the target-independent interfaces which we are implementing...
|
|
||||||
//
|
|
||||||
include "../Target.td"
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Register File Description
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
include "SparcV8RegisterInfo.td"
|
|
||||||
include "SparcV8InstrInfo.td"
|
|
||||||
|
|
||||||
def SparcV8InstrInfo : InstrInfo {
|
|
||||||
let PHIInst = PHI;
|
|
||||||
}
|
|
||||||
|
|
||||||
def SparcV8 : Target {
|
|
||||||
// Pointers are 32-bits in size.
|
|
||||||
let PointerType = i32;
|
|
||||||
|
|
||||||
// These regs are nonvolatile across calls:
|
|
||||||
let CalleeSavedRegisters = [];
|
|
||||||
|
|
||||||
// Pull in Instruction Info:
|
|
||||||
let InstructionSet = SparcV8InstrInfo;
|
|
||||||
}
|
|
||||||
@@ -1,632 +0,0 @@
|
|||||||
//===-- SparcV8AsmPrinter.cpp - SparcV8 LLVM assembly writer --------------===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and 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 GAS-format Sparc V8 assembly language.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "SparcV8.h"
|
|
||||||
#include "SparcV8InstrInfo.h"
|
|
||||||
#include "llvm/Constants.h"
|
|
||||||
#include "llvm/DerivedTypes.h"
|
|
||||||
#include "llvm/Module.h"
|
|
||||||
#include "llvm/Assembly/Writer.h"
|
|
||||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
|
||||||
#include "llvm/CodeGen/MachineConstantPool.h"
|
|
||||||
#include "llvm/CodeGen/MachineInstr.h"
|
|
||||||
#include "llvm/Target/TargetMachine.h"
|
|
||||||
#include "llvm/Support/Mangler.h"
|
|
||||||
#include "Support/Statistic.h"
|
|
||||||
#include "Support/StringExtras.h"
|
|
||||||
#include "Support/CommandLine.h"
|
|
||||||
#include <cctype>
|
|
||||||
using namespace llvm;
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
Statistic<> EmittedInsts("asm-printer", "Number of machine instrs printed");
|
|
||||||
|
|
||||||
struct V8Printer : public MachineFunctionPass {
|
|
||||||
/// Output stream on which we're printing assembly code.
|
|
||||||
///
|
|
||||||
std::ostream &O;
|
|
||||||
|
|
||||||
/// Target machine description which we query for reg. names, data
|
|
||||||
/// layout, etc.
|
|
||||||
///
|
|
||||||
TargetMachine &TM;
|
|
||||||
|
|
||||||
/// Name-mangler for global names.
|
|
||||||
///
|
|
||||||
Mangler *Mang;
|
|
||||||
|
|
||||||
V8Printer(std::ostream &o, TargetMachine &tm) : O(o), TM(tm) { }
|
|
||||||
|
|
||||||
/// We name each basic block in a Function with a unique number, so
|
|
||||||
/// that we can consistently refer to them later. This is cleared
|
|
||||||
/// at the beginning of each call to runOnMachineFunction().
|
|
||||||
///
|
|
||||||
typedef std::map<const Value *, unsigned> ValueMapTy;
|
|
||||||
ValueMapTy NumberForBB;
|
|
||||||
|
|
||||||
/// Cache of mangled name for current function. This is
|
|
||||||
/// recalculated at the beginning of each call to
|
|
||||||
/// runOnMachineFunction().
|
|
||||||
///
|
|
||||||
std::string CurrentFnName;
|
|
||||||
|
|
||||||
virtual const char *getPassName() const {
|
|
||||||
return "SparcV8 Assembly Printer";
|
|
||||||
}
|
|
||||||
|
|
||||||
void emitConstantValueOnly(const Constant *CV);
|
|
||||||
void emitGlobalConstant(const Constant *CV);
|
|
||||||
void printConstantPool(MachineConstantPool *MCP);
|
|
||||||
void printOperand(const MachineInstr *MI, int opNum);
|
|
||||||
void printBaseOffsetPair (const MachineInstr *MI, int i, bool brackets=true);
|
|
||||||
void printMachineInstruction(const MachineInstr *MI);
|
|
||||||
bool runOnMachineFunction(MachineFunction &F);
|
|
||||||
bool doInitialization(Module &M);
|
|
||||||
bool doFinalization(Module &M);
|
|
||||||
};
|
|
||||||
} // end of anonymous namespace
|
|
||||||
|
|
||||||
/// createSparcV8CodePrinterPass - Returns a pass that prints the SparcV8
|
|
||||||
/// 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::createSparcV8CodePrinterPass (std::ostream &o,
|
|
||||||
TargetMachine &tm) {
|
|
||||||
return new V8Printer(o, tm);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// toOctal - Convert the low order bits of X into an octal digit.
|
|
||||||
///
|
|
||||||
static inline char toOctal(int X) {
|
|
||||||
return (X&7)+'0';
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getAsCString - Return the specified array as a C compatible
|
|
||||||
/// string, only if the predicate isStringCompatible is true.
|
|
||||||
///
|
|
||||||
static void printAsCString(std::ostream &O, const ConstantArray *CVA) {
|
|
||||||
assert(CVA->isString() && "Array is not string compatible!");
|
|
||||||
|
|
||||||
O << "\"";
|
|
||||||
for (unsigned i = 0; i != CVA->getNumOperands(); ++i) {
|
|
||||||
unsigned char C = cast<ConstantInt>(CVA->getOperand(i))->getRawValue();
|
|
||||||
|
|
||||||
if (C == '"') {
|
|
||||||
O << "\\\"";
|
|
||||||
} else if (C == '\\') {
|
|
||||||
O << "\\\\";
|
|
||||||
} else if (isprint(C)) {
|
|
||||||
O << C;
|
|
||||||
} else {
|
|
||||||
switch(C) {
|
|
||||||
case '\b': O << "\\b"; break;
|
|
||||||
case '\f': O << "\\f"; break;
|
|
||||||
case '\n': O << "\\n"; break;
|
|
||||||
case '\r': O << "\\r"; break;
|
|
||||||
case '\t': O << "\\t"; break;
|
|
||||||
default:
|
|
||||||
O << '\\';
|
|
||||||
O << toOctal(C >> 6);
|
|
||||||
O << toOctal(C >> 3);
|
|
||||||
O << toOctal(C >> 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
O << "\"";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print out the specified constant, without a storage class. Only the
|
|
||||||
// constants valid in constant expressions can occur here.
|
|
||||||
void V8Printer::emitConstantValueOnly(const Constant *CV) {
|
|
||||||
if (CV->isNullValue())
|
|
||||||
O << "0";
|
|
||||||
else if (const ConstantBool *CB = dyn_cast<ConstantBool>(CV)) {
|
|
||||||
assert(CB == ConstantBool::True);
|
|
||||||
O << "1";
|
|
||||||
} else if (const ConstantSInt *CI = dyn_cast<ConstantSInt>(CV))
|
|
||||||
if (((CI->getValue() << 32) >> 32) == CI->getValue())
|
|
||||||
O << CI->getValue();
|
|
||||||
else
|
|
||||||
O << (unsigned long long)CI->getValue();
|
|
||||||
else if (const ConstantUInt *CI = dyn_cast<ConstantUInt>(CV))
|
|
||||||
O << CI->getValue();
|
|
||||||
else if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV))
|
|
||||||
// This is a constant address for a global variable or function. Use the
|
|
||||||
// name of the variable or function as the address value.
|
|
||||||
O << Mang->getValueName(GV);
|
|
||||||
else if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(CV)) {
|
|
||||||
const TargetData &TD = TM.getTargetData();
|
|
||||||
switch(CE->getOpcode()) {
|
|
||||||
case Instruction::GetElementPtr: {
|
|
||||||
// generate a symbolic expression for the byte address
|
|
||||||
const Constant *ptrVal = CE->getOperand(0);
|
|
||||||
std::vector<Value*> idxVec(CE->op_begin()+1, CE->op_end());
|
|
||||||
if (unsigned Offset = TD.getIndexedOffset(ptrVal->getType(), idxVec)) {
|
|
||||||
O << "(";
|
|
||||||
emitConstantValueOnly(ptrVal);
|
|
||||||
O << ") + " << Offset;
|
|
||||||
} else {
|
|
||||||
emitConstantValueOnly(ptrVal);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Instruction::Cast: {
|
|
||||||
// Support only non-converting or widening casts for now, that is, ones
|
|
||||||
// that do not involve a change in value. This assertion is really gross,
|
|
||||||
// and may not even be a complete check.
|
|
||||||
Constant *Op = CE->getOperand(0);
|
|
||||||
const Type *OpTy = Op->getType(), *Ty = CE->getType();
|
|
||||||
|
|
||||||
// Pointers on ILP32 machines can be losslessly converted back and
|
|
||||||
// forth into 32-bit or wider integers, regardless of signedness.
|
|
||||||
assert(((isa<PointerType>(OpTy)
|
|
||||||
&& (Ty == Type::LongTy || Ty == Type::ULongTy
|
|
||||||
|| Ty == Type::IntTy || Ty == Type::UIntTy))
|
|
||||||
|| (isa<PointerType>(Ty)
|
|
||||||
&& (OpTy == Type::LongTy || OpTy == Type::ULongTy
|
|
||||||
|| OpTy == Type::IntTy || OpTy == Type::UIntTy))
|
|
||||||
|| (((TD.getTypeSize(Ty) >= TD.getTypeSize(OpTy))
|
|
||||||
&& OpTy->isLosslesslyConvertibleTo(Ty))))
|
|
||||||
&& "FIXME: Don't yet support this kind of constant cast expr");
|
|
||||||
O << "(";
|
|
||||||
emitConstantValueOnly(Op);
|
|
||||||
O << ")";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Instruction::Add:
|
|
||||||
O << "(";
|
|
||||||
emitConstantValueOnly(CE->getOperand(0));
|
|
||||||
O << ") + (";
|
|
||||||
emitConstantValueOnly(CE->getOperand(1));
|
|
||||||
O << ")";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(0 && "Unsupported operator!");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
assert(0 && "Unknown constant value!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print a constant value or values, with the appropriate storage class as a
|
|
||||||
// prefix.
|
|
||||||
void V8Printer::emitGlobalConstant(const Constant *CV) {
|
|
||||||
const TargetData &TD = TM.getTargetData();
|
|
||||||
|
|
||||||
if (const ConstantArray *CVA = dyn_cast<ConstantArray>(CV)) {
|
|
||||||
if (CVA->isString()) {
|
|
||||||
O << "\t.ascii\t";
|
|
||||||
printAsCString(O, CVA);
|
|
||||||
O << "\n";
|
|
||||||
} else { // Not a string. Print the values in successive locations
|
|
||||||
for (unsigned i = 0, e = CVA->getNumOperands(); i != e; i++)
|
|
||||||
emitGlobalConstant(CVA->getOperand(i));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
} else if (const ConstantStruct *CVS = dyn_cast<ConstantStruct>(CV)) {
|
|
||||||
// Print the fields in successive locations. Pad to align if needed!
|
|
||||||
const StructLayout *cvsLayout = TD.getStructLayout(CVS->getType());
|
|
||||||
unsigned sizeSoFar = 0;
|
|
||||||
for (unsigned i = 0, e = CVS->getNumOperands(); i != e; i++) {
|
|
||||||
const Constant* field = CVS->getOperand(i);
|
|
||||||
|
|
||||||
// Check if padding is needed and insert one or more 0s.
|
|
||||||
unsigned fieldSize = TD.getTypeSize(field->getType());
|
|
||||||
unsigned padSize = ((i == e-1? cvsLayout->StructSize
|
|
||||||
: cvsLayout->MemberOffsets[i+1])
|
|
||||||
- cvsLayout->MemberOffsets[i]) - fieldSize;
|
|
||||||
sizeSoFar += fieldSize + padSize;
|
|
||||||
|
|
||||||
// Now print the actual field value
|
|
||||||
emitGlobalConstant(field);
|
|
||||||
|
|
||||||
// Insert the field padding unless it's zero bytes...
|
|
||||||
if (padSize)
|
|
||||||
O << "\t.skip\t " << padSize << "\n";
|
|
||||||
}
|
|
||||||
assert(sizeSoFar == cvsLayout->StructSize &&
|
|
||||||
"Layout of constant struct may be incorrect!");
|
|
||||||
return;
|
|
||||||
} else if (const ConstantFP *CFP = dyn_cast<ConstantFP>(CV)) {
|
|
||||||
// FP Constants are printed as integer constants to avoid losing
|
|
||||||
// precision...
|
|
||||||
double Val = CFP->getValue();
|
|
||||||
switch (CFP->getType()->getTypeID()) {
|
|
||||||
default: assert(0 && "Unknown floating point type!");
|
|
||||||
case Type::FloatTyID: {
|
|
||||||
union FU { // Abide by C TBAA rules
|
|
||||||
float FVal;
|
|
||||||
unsigned UVal;
|
|
||||||
} U;
|
|
||||||
U.FVal = Val;
|
|
||||||
O << ".long\t" << U.UVal << "\t! float " << Val << "\n";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case Type::DoubleTyID: {
|
|
||||||
union DU { // Abide by C TBAA rules
|
|
||||||
double FVal;
|
|
||||||
uint64_t UVal;
|
|
||||||
} U;
|
|
||||||
U.FVal = Val;
|
|
||||||
O << ".quad\t" << U.UVal << "\t! double " << Val << "\n";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const Type *type = CV->getType();
|
|
||||||
O << "\t";
|
|
||||||
switch (type->getTypeID()) {
|
|
||||||
case Type::BoolTyID: case Type::UByteTyID: case Type::SByteTyID:
|
|
||||||
O << ".byte";
|
|
||||||
break;
|
|
||||||
case Type::UShortTyID: case Type::ShortTyID:
|
|
||||||
O << ".word";
|
|
||||||
break;
|
|
||||||
case Type::FloatTyID: case Type::PointerTyID:
|
|
||||||
case Type::UIntTyID: case Type::IntTyID:
|
|
||||||
O << ".long";
|
|
||||||
break;
|
|
||||||
case Type::DoubleTyID:
|
|
||||||
case Type::ULongTyID: case Type::LongTyID:
|
|
||||||
O << ".quad";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert (0 && "Can't handle printing this type of thing");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
O << "\t";
|
|
||||||
emitConstantValueOnly(CV);
|
|
||||||
O << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
/// printConstantPool - Print to the current output stream assembly
|
|
||||||
/// representations of the constants in the constant pool MCP. This is
|
|
||||||
/// used to print out constants which have been "spilled to memory" by
|
|
||||||
/// the code generator.
|
|
||||||
///
|
|
||||||
void V8Printer::printConstantPool(MachineConstantPool *MCP) {
|
|
||||||
const std::vector<Constant*> &CP = MCP->getConstants();
|
|
||||||
const TargetData &TD = TM.getTargetData();
|
|
||||||
|
|
||||||
if (CP.empty()) return;
|
|
||||||
|
|
||||||
for (unsigned i = 0, e = CP.size(); i != e; ++i) {
|
|
||||||
O << "\t.section .rodata\n";
|
|
||||||
O << "\t.align " << (unsigned)TD.getTypeAlignment(CP[i]->getType())
|
|
||||||
<< "\n";
|
|
||||||
O << ".CPI" << CurrentFnName << "_" << i << ":\t\t\t\t\t!"
|
|
||||||
<< *CP[i] << "\n";
|
|
||||||
emitGlobalConstant(CP[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// runOnMachineFunction - This uses the printMachineInstruction()
|
|
||||||
/// method to print assembly for each instruction.
|
|
||||||
///
|
|
||||||
bool V8Printer::runOnMachineFunction(MachineFunction &MF) {
|
|
||||||
// BBNumber is used here so that a given Printer will never give two
|
|
||||||
// BBs the same name. (If you have a better way, please let me know!)
|
|
||||||
static unsigned BBNumber = 0;
|
|
||||||
|
|
||||||
O << "\n\n";
|
|
||||||
// What's my mangled name?
|
|
||||||
CurrentFnName = Mang->getValueName(MF.getFunction());
|
|
||||||
|
|
||||||
// Print out constants referenced by the function
|
|
||||||
printConstantPool(MF.getConstantPool());
|
|
||||||
|
|
||||||
// Print out labels for the function.
|
|
||||||
O << "\t.text\n";
|
|
||||||
O << "\t.align 16\n";
|
|
||||||
O << "\t.globl\t" << CurrentFnName << "\n";
|
|
||||||
O << "\t.type\t" << CurrentFnName << ", #function\n";
|
|
||||||
O << CurrentFnName << ":\n";
|
|
||||||
|
|
||||||
// Number each basic block so that we can consistently refer to them
|
|
||||||
// in PC-relative references.
|
|
||||||
NumberForBB.clear();
|
|
||||||
for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
|
|
||||||
I != E; ++I) {
|
|
||||||
NumberForBB[I->getBasicBlock()] = BBNumber++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
O << ".LBB" << Mang->getValueName(MF.getFunction ())
|
|
||||||
<< "_" << I->getNumber () << ":\t! "
|
|
||||||
<< I->getBasicBlock ()->getName () << "\n";
|
|
||||||
for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
|
|
||||||
II != E; ++II) {
|
|
||||||
// Print the assembly for the instruction.
|
|
||||||
O << "\t";
|
|
||||||
printMachineInstruction(II);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We didn't modify anything.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void V8Printer::printOperand(const MachineInstr *MI, int opNum) {
|
|
||||||
const MachineOperand &MO = MI->getOperand (opNum);
|
|
||||||
const MRegisterInfo &RI = *TM.getRegisterInfo();
|
|
||||||
bool CloseParen = false;
|
|
||||||
if (MI->getOpcode() == V8::SETHIi && !MO.isRegister() && !MO.isImmediate()) {
|
|
||||||
O << "%hi(";
|
|
||||||
CloseParen = true;
|
|
||||||
} else if (MI->getOpcode() ==V8::ORri &&!MO.isRegister() &&!MO.isImmediate())
|
|
||||||
{
|
|
||||||
O << "%lo(";
|
|
||||||
CloseParen = true;
|
|
||||||
}
|
|
||||||
switch (MO.getType()) {
|
|
||||||
case MachineOperand::MO_VirtualRegister:
|
|
||||||
if (Value *V = MO.getVRegValueOrNull()) {
|
|
||||||
O << "<" << V->getName() << ">";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// FALLTHROUGH
|
|
||||||
case MachineOperand::MO_MachineRegister:
|
|
||||||
if (MRegisterInfo::isPhysicalRegister(MO.getReg()))
|
|
||||||
O << "%" << LowercaseString (RI.get(MO.getReg()).Name);
|
|
||||||
else
|
|
||||||
O << "%reg" << MO.getReg();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MachineOperand::MO_SignExtendedImmed:
|
|
||||||
case MachineOperand::MO_UnextendedImmed:
|
|
||||||
O << (int)MO.getImmedValue();
|
|
||||||
break;
|
|
||||||
case MachineOperand::MO_MachineBasicBlock: {
|
|
||||||
MachineBasicBlock *MBBOp = MO.getMachineBasicBlock();
|
|
||||||
O << ".LBB" << Mang->getValueName(MBBOp->getParent()->getFunction())
|
|
||||||
<< "_" << MBBOp->getNumber () << "\t! "
|
|
||||||
<< MBBOp->getBasicBlock ()->getName ();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case MachineOperand::MO_PCRelativeDisp:
|
|
||||||
std::cerr << "Shouldn't use addPCDisp() when building SparcV8 MachineInstrs";
|
|
||||||
abort ();
|
|
||||||
return;
|
|
||||||
case MachineOperand::MO_GlobalAddress:
|
|
||||||
O << Mang->getValueName(MO.getGlobal());
|
|
||||||
break;
|
|
||||||
case MachineOperand::MO_ExternalSymbol:
|
|
||||||
O << MO.getSymbolName();
|
|
||||||
break;
|
|
||||||
case MachineOperand::MO_ConstantPoolIndex:
|
|
||||||
O << ".CPI" << CurrentFnName << "_" << MO.getConstantPoolIndex();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
O << "<unknown operand type>"; abort (); break;
|
|
||||||
}
|
|
||||||
if (CloseParen) O << ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isLoadInstruction (const MachineInstr *MI) {
|
|
||||||
switch (MI->getOpcode ()) {
|
|
||||||
case V8::LDSB:
|
|
||||||
case V8::LDSH:
|
|
||||||
case V8::LDUB:
|
|
||||||
case V8::LDUH:
|
|
||||||
case V8::LD:
|
|
||||||
case V8::LDD:
|
|
||||||
case V8::LDFrr:
|
|
||||||
case V8::LDFri:
|
|
||||||
case V8::LDDFrr:
|
|
||||||
case V8::LDDFri:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isStoreInstruction (const MachineInstr *MI) {
|
|
||||||
switch (MI->getOpcode ()) {
|
|
||||||
case V8::STB:
|
|
||||||
case V8::STH:
|
|
||||||
case V8::ST:
|
|
||||||
case V8::STD:
|
|
||||||
case V8::STFrr:
|
|
||||||
case V8::STFri:
|
|
||||||
case V8::STDFrr:
|
|
||||||
case V8::STDFri:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isPseudoInstruction (const MachineInstr *MI) {
|
|
||||||
switch (MI->getOpcode ()) {
|
|
||||||
case V8::PHI:
|
|
||||||
case V8::ADJCALLSTACKUP:
|
|
||||||
case V8::ADJCALLSTACKDOWN:
|
|
||||||
case V8::IMPLICIT_USE:
|
|
||||||
case V8::IMPLICIT_DEF:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// printBaseOffsetPair - Print two consecutive operands of MI, starting at #i,
|
|
||||||
/// which form a base + offset pair (which may have brackets around it, if
|
|
||||||
/// brackets is true, or may be in the form base - constant, if offset is a
|
|
||||||
/// negative constant).
|
|
||||||
///
|
|
||||||
void V8Printer::printBaseOffsetPair (const MachineInstr *MI, int i,
|
|
||||||
bool brackets) {
|
|
||||||
if (brackets) O << "[";
|
|
||||||
printOperand (MI, i);
|
|
||||||
if (MI->getOperand (i + 1).isImmediate()) {
|
|
||||||
int Val = (int) MI->getOperand (i + 1).getImmedValue ();
|
|
||||||
if (Val != 0) {
|
|
||||||
O << ((Val >= 0) ? " + " : " - ");
|
|
||||||
O << ((Val >= 0) ? Val : -Val);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
O << " + ";
|
|
||||||
printOperand (MI, i + 1);
|
|
||||||
}
|
|
||||||
if (brackets) O << "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
/// printMachineInstruction -- Print out a single SparcV8 LLVM instruction
|
|
||||||
/// MI in GAS syntax to the current output stream.
|
|
||||||
///
|
|
||||||
void V8Printer::printMachineInstruction(const MachineInstr *MI) {
|
|
||||||
unsigned Opcode = MI->getOpcode();
|
|
||||||
const TargetInstrInfo &TII = *TM.getInstrInfo();
|
|
||||||
const TargetInstrDescriptor &Desc = TII.get(Opcode);
|
|
||||||
|
|
||||||
// If it's a pseudo-instruction, comment it out.
|
|
||||||
if (isPseudoInstruction (MI))
|
|
||||||
O << "! ";
|
|
||||||
|
|
||||||
O << Desc.Name << " ";
|
|
||||||
|
|
||||||
// Printing memory instructions is a special case.
|
|
||||||
// for loads: %dest = op %base, offset --> op [%base + offset], %dest
|
|
||||||
// for stores: op %base, offset, %src --> op %src, [%base + offset]
|
|
||||||
if (isLoadInstruction (MI)) {
|
|
||||||
printBaseOffsetPair (MI, 1);
|
|
||||||
O << ", ";
|
|
||||||
printOperand (MI, 0);
|
|
||||||
O << "\n";
|
|
||||||
return;
|
|
||||||
} else if (isStoreInstruction (MI)) {
|
|
||||||
printOperand (MI, 2);
|
|
||||||
O << ", ";
|
|
||||||
printBaseOffsetPair (MI, 0);
|
|
||||||
O << "\n";
|
|
||||||
return;
|
|
||||||
} else if (Opcode == V8::JMPLrr) {
|
|
||||||
printBaseOffsetPair (MI, 1, false);
|
|
||||||
O << ", ";
|
|
||||||
printOperand (MI, 0);
|
|
||||||
O << "\n";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// print non-immediate, non-register-def operands
|
|
||||||
// then print immediate operands
|
|
||||||
// then print register-def operands.
|
|
||||||
std::vector<int> print_order;
|
|
||||||
for (unsigned i = 0; i < MI->getNumOperands (); ++i)
|
|
||||||
if (!(MI->getOperand (i).isImmediate ()
|
|
||||||
|| (MI->getOperand (i).isRegister ()
|
|
||||||
&& MI->getOperand (i).isDef ())))
|
|
||||||
print_order.push_back (i);
|
|
||||||
for (unsigned i = 0; i < MI->getNumOperands (); ++i)
|
|
||||||
if (MI->getOperand (i).isImmediate ())
|
|
||||||
print_order.push_back (i);
|
|
||||||
for (unsigned i = 0; i < MI->getNumOperands (); ++i)
|
|
||||||
if (MI->getOperand (i).isRegister () && MI->getOperand (i).isDef ())
|
|
||||||
print_order.push_back (i);
|
|
||||||
for (unsigned i = 0, e = print_order.size (); i != e; ++i) {
|
|
||||||
printOperand (MI, print_order[i]);
|
|
||||||
if (i != (print_order.size () - 1))
|
|
||||||
O << ", ";
|
|
||||||
}
|
|
||||||
O << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
bool V8Printer::doInitialization(Module &M) {
|
|
||||||
Mang = new Mangler(M);
|
|
||||||
return false; // success
|
|
||||||
}
|
|
||||||
|
|
||||||
// SwitchSection - Switch to the specified section of the executable if we are
|
|
||||||
// not already in it!
|
|
||||||
//
|
|
||||||
static void SwitchSection(std::ostream &OS, std::string &CurSection,
|
|
||||||
const char *NewSection) {
|
|
||||||
if (CurSection != NewSection) {
|
|
||||||
CurSection = NewSection;
|
|
||||||
if (!CurSection.empty())
|
|
||||||
OS << "\t.section " << NewSection << "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool V8Printer::doFinalization(Module &M) {
|
|
||||||
const TargetData &TD = TM.getTargetData();
|
|
||||||
std::string CurSection;
|
|
||||||
|
|
||||||
// Print out module-level global variables here.
|
|
||||||
for (Module::const_giterator I = M.gbegin(), E = M.gend(); I != E; ++I)
|
|
||||||
if (I->hasInitializer()) { // External global require no code
|
|
||||||
O << "\n\n";
|
|
||||||
std::string name = Mang->getValueName(I);
|
|
||||||
Constant *C = I->getInitializer();
|
|
||||||
unsigned Size = TD.getTypeSize(C->getType());
|
|
||||||
unsigned Align = TD.getTypeAlignment(C->getType());
|
|
||||||
|
|
||||||
if (C->isNullValue() &&
|
|
||||||
(I->hasLinkOnceLinkage() || I->hasInternalLinkage() ||
|
|
||||||
I->hasWeakLinkage() /* FIXME: Verify correct */)) {
|
|
||||||
SwitchSection(O, CurSection, ".data");
|
|
||||||
if (I->hasInternalLinkage())
|
|
||||||
O << "\t.local " << name << "\n";
|
|
||||||
|
|
||||||
O << "\t.comm " << name << "," << TD.getTypeSize(C->getType())
|
|
||||||
<< "," << (unsigned)TD.getTypeAlignment(C->getType());
|
|
||||||
O << "\t\t! ";
|
|
||||||
WriteAsOperand(O, I, true, true, &M);
|
|
||||||
O << "\n";
|
|
||||||
} else {
|
|
||||||
switch (I->getLinkage()) {
|
|
||||||
case GlobalValue::LinkOnceLinkage:
|
|
||||||
case GlobalValue::WeakLinkage: // FIXME: Verify correct for weak.
|
|
||||||
// Nonnull linkonce -> weak
|
|
||||||
O << "\t.weak " << name << "\n";
|
|
||||||
SwitchSection(O, CurSection, "");
|
|
||||||
O << "\t.section\t.llvm.linkonce.d." << name << ",\"aw\",@progbits\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 << "\t.globl " << name << "\n";
|
|
||||||
// FALL THROUGH
|
|
||||||
case GlobalValue::InternalLinkage:
|
|
||||||
if (C->isNullValue())
|
|
||||||
SwitchSection(O, CurSection, ".bss");
|
|
||||||
else
|
|
||||||
SwitchSection(O, CurSection, ".data");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
O << "\t.align " << Align << "\n";
|
|
||||||
O << "\t.type " << name << ",#object\n";
|
|
||||||
O << "\t.size " << name << "," << Size << "\n";
|
|
||||||
O << name << ":\t\t\t\t! ";
|
|
||||||
WriteAsOperand(O, I, true, true, &M);
|
|
||||||
O << " = ";
|
|
||||||
WriteAsOperand(O, C, false, false, &M);
|
|
||||||
O << "\n";
|
|
||||||
emitGlobalConstant(C);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete Mang;
|
|
||||||
return false; // success
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
//===-- SparcV8CodeEmitter.cpp - JIT Code Emitter for SparcV8 -----*- C++ -*-=//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "SparcV8TargetMachine.h"
|
|
||||||
|
|
||||||
namespace llvm {
|
|
||||||
|
|
||||||
/// addPassesToEmitMachineCode - Add passes to the specified pass manager to get
|
|
||||||
/// machine code emitted. This uses a MachineCodeEmitter object to handle
|
|
||||||
/// actually outputting the machine code and resolving things like the address
|
|
||||||
/// of functions. This method should returns true if machine code emission is
|
|
||||||
/// not supported.
|
|
||||||
///
|
|
||||||
bool SparcV8TargetMachine::addPassesToEmitMachineCode(FunctionPassManager &PM,
|
|
||||||
MachineCodeEmitter &MCE) {
|
|
||||||
return true;
|
|
||||||
// It should go something like this:
|
|
||||||
// PM.add(new Emitter(MCE)); // Machine code emitter pass for SparcV8
|
|
||||||
// Delete machine code for this function after emitting it:
|
|
||||||
// PM.add(createMachineCodeDeleter());
|
|
||||||
}
|
|
||||||
|
|
||||||
void *SparcV8JITInfo::getJITStubForFunction(Function *F,
|
|
||||||
MachineCodeEmitter &MCE) {
|
|
||||||
assert (0 && "SparcV8JITInfo::getJITStubForFunction not implemented");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SparcV8JITInfo::replaceMachineCodeForFunction (void *Old, void *New) {
|
|
||||||
assert (0 && "SparcV8JITInfo::replaceMachineCodeForFunction not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end llvm namespace
|
|
||||||
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
//===- SparcV8InstrInfo.cpp - SparcV8 Instruction Information ---*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This file contains the SparcV8 implementation of the TargetInstrInfo class.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "SparcV8InstrInfo.h"
|
|
||||||
#include "SparcV8.h"
|
|
||||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
|
||||||
#include "SparcV8GenInstrInfo.inc"
|
|
||||||
using namespace llvm;
|
|
||||||
|
|
||||||
SparcV8InstrInfo::SparcV8InstrInfo()
|
|
||||||
: TargetInstrInfo(SparcV8Insts, sizeof(SparcV8Insts)/sizeof(SparcV8Insts[0])){
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return true if the instruction is a register to register move and
|
|
||||||
/// leave the source and dest operands in the passed parameters.
|
|
||||||
///
|
|
||||||
bool SparcV8InstrInfo::isMoveInstr(const MachineInstr &MI,
|
|
||||||
unsigned &SrcReg, unsigned &DstReg) const {
|
|
||||||
if (MI.getOpcode() == V8::ORrr) {
|
|
||||||
if (MI.getOperand(1).getReg() == V8::G0) { // X = or G0, Y -> X = Y
|
|
||||||
DstReg = MI.getOperand(0).getReg();
|
|
||||||
SrcReg = MI.getOperand(2).getReg();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} else if (MI.getOpcode() == V8::FMOVS) {
|
|
||||||
SrcReg = MI.getOperand(1).getReg();
|
|
||||||
DstReg = MI.getOperand(0).getReg();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
//===- SparcV8InstrInfo.h - SparcV8 Instruction Information -----*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This file contains the SparcV8 implementation of the TargetInstrInfo class.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef SPARCV8INSTRUCTIONINFO_H
|
|
||||||
#define SPARCV8INSTRUCTIONINFO_H
|
|
||||||
|
|
||||||
#include "llvm/Target/TargetInstrInfo.h"
|
|
||||||
#include "SparcV8RegisterInfo.h"
|
|
||||||
|
|
||||||
namespace llvm {
|
|
||||||
|
|
||||||
/// V8II - This namespace holds all of the target specific flags that
|
|
||||||
/// instruction info tracks.
|
|
||||||
///
|
|
||||||
namespace V8II {
|
|
||||||
enum {
|
|
||||||
Pseudo = (1<<0),
|
|
||||||
Load = (1<<1),
|
|
||||||
Store = (1<<2),
|
|
||||||
DelaySlot = (1<<3)
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
class SparcV8InstrInfo : public TargetInstrInfo {
|
|
||||||
const SparcV8RegisterInfo RI;
|
|
||||||
public:
|
|
||||||
SparcV8InstrInfo();
|
|
||||||
|
|
||||||
/// 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 MRegisterInfo &getRegisterInfo() const { return RI; }
|
|
||||||
|
|
||||||
/// Return true if the instruction is a register to register move and
|
|
||||||
/// leave the source and dest operands in the passed parameters.
|
|
||||||
///
|
|
||||||
virtual bool isMoveInstr(const MachineInstr &MI,
|
|
||||||
unsigned &SrcReg, unsigned &DstReg) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,242 +0,0 @@
|
|||||||
//===- SparcV8Instrs.td - Target Description for SparcV8 Target -----------===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This file describes the SparcV8 instructions in TableGen format.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Instruction format superclass
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
class InstV8 : Instruction { // SparcV8 instruction baseline
|
|
||||||
field bits<32> Inst;
|
|
||||||
|
|
||||||
let Namespace = "V8";
|
|
||||||
|
|
||||||
bits<2> op;
|
|
||||||
let Inst{31-30} = op; // Top two bits are the 'op' field
|
|
||||||
|
|
||||||
// Bit attributes specific to SparcV8 instructions
|
|
||||||
bit isPasi = 0; // Does this instruction affect an alternate addr space?
|
|
||||||
bit isPrivileged = 0; // Is this a privileged instruction?
|
|
||||||
}
|
|
||||||
|
|
||||||
include "SparcV8InstrInfo_F2.td"
|
|
||||||
include "SparcV8InstrInfo_F3.td"
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Instructions
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
// Pseudo instructions.
|
|
||||||
class PseudoInstV8<string nm> : InstV8 {
|
|
||||||
let Name = nm;
|
|
||||||
}
|
|
||||||
def PHI : PseudoInstV8<"PHI">;
|
|
||||||
def ADJCALLSTACKDOWN : PseudoInstV8<"ADJCALLSTACKDOWN">;
|
|
||||||
def ADJCALLSTACKUP : PseudoInstV8<"ADJCALLSTACKUP">;
|
|
||||||
def IMPLICIT_USE : PseudoInstV8<"IMPLICIT_USE">;
|
|
||||||
def IMPLICIT_DEF : PseudoInstV8<"IMPLICIT_DEF">;
|
|
||||||
|
|
||||||
// Section A.3 - Synthetic Instructions, p. 85
|
|
||||||
// special cases of JMPL:
|
|
||||||
let isReturn = 1, isTerminator = 1, simm13 = 8 in
|
|
||||||
def RET : F3_2<2, 0b111000, "ret">;
|
|
||||||
let isReturn = 1, isTerminator = 1, simm13 = 8 in
|
|
||||||
def RETL: F3_2<2, 0b111000, "retl">;
|
|
||||||
// CMP is a special case of SUBCC where destination is ignored, by setting it to
|
|
||||||
// %g0 (hardwired zero).
|
|
||||||
// FIXME: should keep track of the fact that it defs the integer condition codes
|
|
||||||
let rd = 0 in
|
|
||||||
def CMPri: F3_2<2, 0b010100, "cmp">;
|
|
||||||
|
|
||||||
// Section B.1 - Load Integer Instructions, p. 90
|
|
||||||
def LDSB: F3_2<3, 0b001001, "ldsb">;
|
|
||||||
def LDSH: F3_2<3, 0b001010, "ldsh">;
|
|
||||||
def LDUB: F3_2<3, 0b000001, "ldub">;
|
|
||||||
def LDUH: F3_2<3, 0b000010, "lduh">;
|
|
||||||
def LD : F3_2<3, 0b000000, "ld">;
|
|
||||||
def LDD : F3_2<3, 0b000011, "ldd">;
|
|
||||||
|
|
||||||
// Section B.2 - Load Floating-point Instructions, p. 92
|
|
||||||
def LDFrr : F3_1<3, 0b100000, "ld">;
|
|
||||||
def LDFri : F3_2<3, 0b100000, "ld">;
|
|
||||||
def LDDFrr : F3_1<3, 0b100011, "ldd">;
|
|
||||||
def LDDFri : F3_2<3, 0b100011, "ldd">;
|
|
||||||
def LDFSRrr: F3_1<3, 0b100001, "ld">;
|
|
||||||
def LDFSRri: F3_2<3, 0b100001, "ld">;
|
|
||||||
|
|
||||||
// Section B.4 - Store Integer Instructions, p. 95
|
|
||||||
def STB : F3_2<3, 0b000101, "stb">;
|
|
||||||
def STH : F3_2<3, 0b000110, "sth">;
|
|
||||||
def ST : F3_2<3, 0b000100, "st">;
|
|
||||||
def STD : F3_2<3, 0b000111, "std">;
|
|
||||||
|
|
||||||
// Section B.5 - Store Floating-point Instructions, p. 97
|
|
||||||
def STFrr : F3_1<3, 0b100100, "st">;
|
|
||||||
def STFri : F3_2<3, 0b100100, "st">;
|
|
||||||
def STDFrr : F3_1<3, 0b100111, "std">;
|
|
||||||
def STDFri : F3_2<3, 0b100111, "std">;
|
|
||||||
def STFSRrr : F3_1<3, 0b100101, "st">;
|
|
||||||
def STFSRri : F3_2<3, 0b100101, "st">;
|
|
||||||
def STDFQrr : F3_1<3, 0b100110, "std">;
|
|
||||||
def STDFQri : F3_2<3, 0b100110, "std">;
|
|
||||||
|
|
||||||
// Section B.9 - SETHI Instruction, p. 104
|
|
||||||
def SETHIi: F2_1<0b100, "sethi">;
|
|
||||||
|
|
||||||
// Section B.10 - NOP Instruction, p. 105
|
|
||||||
// (It's a special case of SETHI)
|
|
||||||
let rd = 0, imm = 0 in
|
|
||||||
def NOP : F2_1<0b100, "nop">;
|
|
||||||
|
|
||||||
// Section B.11 - Logical Instructions, p. 106
|
|
||||||
def ANDrr : F3_1<2, 0b000001, "and">;
|
|
||||||
def ANDri : F3_2<2, 0b000001, "and">;
|
|
||||||
def ORrr : F3_1<2, 0b000010, "or">;
|
|
||||||
def ORri : F3_2<2, 0b000010, "or">;
|
|
||||||
def XORrr : F3_1<2, 0b000011, "xor">;
|
|
||||||
def XORri : F3_2<2, 0b000011, "xor">;
|
|
||||||
|
|
||||||
// Section B.12 - Shift Instructions, p. 107
|
|
||||||
def SLLrr : F3_1<2, 0b100101, "sll">;
|
|
||||||
def SLLri : F3_2<2, 0b100101, "sll">;
|
|
||||||
def SRLrr : F3_1<2, 0b100110, "srl">;
|
|
||||||
def SRLri : F3_2<2, 0b100110, "srl">;
|
|
||||||
def SRArr : F3_1<2, 0b100111, "sra">;
|
|
||||||
def SRAri : F3_2<2, 0b100111, "sra">;
|
|
||||||
|
|
||||||
// Section B.13 - Add Instructions, p. 108
|
|
||||||
def ADDrr : F3_1<2, 0b000000, "add">;
|
|
||||||
def ADDri : F3_2<2, 0b000000, "add">;
|
|
||||||
|
|
||||||
// Section B.15 - Subtract Instructions, p. 110
|
|
||||||
def SUBrr : F3_1<2, 0b000100, "sub">;
|
|
||||||
def SUBCCrr : F3_1<2, 0b010100, "subcc">;
|
|
||||||
def SUBCCri : F3_2<2, 0b010100, "subcc">;
|
|
||||||
|
|
||||||
// Section B.18 - Multiply Instructions, p. 113
|
|
||||||
def UMULrr : F3_1<2, 0b001010, "umul">;
|
|
||||||
def SMULrr : F3_1<2, 0b001011, "smul">;
|
|
||||||
|
|
||||||
// Section B.19 - Divide Instructions, p. 115
|
|
||||||
def UDIVrr : F3_1<2, 0b001110, "udiv">;
|
|
||||||
def UDIVri : F3_2<2, 0b001110, "udiv">;
|
|
||||||
def SDIVrr : F3_1<2, 0b001111, "sdiv">;
|
|
||||||
def SDIVri : F3_2<2, 0b001111, "sdiv">;
|
|
||||||
def UDIVCCrr : F3_1<2, 0b011110, "udivcc">;
|
|
||||||
def UDIVCCri : F3_2<2, 0b011110, "udivcc">;
|
|
||||||
def SDIVCCrr : F3_1<2, 0b011111, "sdivcc">;
|
|
||||||
def SDIVCCri : F3_2<2, 0b011111, "sdivcc">;
|
|
||||||
|
|
||||||
// Section B.20 - SAVE and RESTORE, p. 117
|
|
||||||
def SAVErr : F3_1<2, 0b111100, "save">; // save r, r, r
|
|
||||||
def SAVEri : F3_2<2, 0b111100, "save">; // save r, i, r
|
|
||||||
def RESTORErr : F3_1<2, 0b111101, "restore">; // restore r, r, r
|
|
||||||
def RESTOREri : F3_2<2, 0b111101, "restore">; // restore r, i, r
|
|
||||||
|
|
||||||
// Section B.21 - Branch on Integer Condition Codes Instructions, p. 119
|
|
||||||
|
|
||||||
// conditional branch class:
|
|
||||||
class BranchV8<bits<4> cc, string nm> : F2_2<cc, 0b010, nm> {
|
|
||||||
let isBranch = 1;
|
|
||||||
let isTerminator = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
let isBarrier = 1 in
|
|
||||||
def BA : BranchV8<0b1000, "ba">;
|
|
||||||
def BN : BranchV8<0b0000, "bn">;
|
|
||||||
def BNE : BranchV8<0b1001, "bne">;
|
|
||||||
def BE : BranchV8<0b0001, "be">;
|
|
||||||
def BG : BranchV8<0b1010, "bg">;
|
|
||||||
def BLE : BranchV8<0b0010, "ble">;
|
|
||||||
def BGE : BranchV8<0b1011, "bge">;
|
|
||||||
def BL : BranchV8<0b0011, "bl">;
|
|
||||||
def BGU : BranchV8<0b1100, "bgu">;
|
|
||||||
def BLEU : BranchV8<0b0100, "bleu">;
|
|
||||||
def BCC : BranchV8<0b1101, "bcc">;
|
|
||||||
def BCS : BranchV8<0b0101, "bcs">;
|
|
||||||
|
|
||||||
// Section B.22 - Branch on Floating-point Condition Codes Instructions, p. 121
|
|
||||||
|
|
||||||
// floating-point conditional branch class:
|
|
||||||
class FPBranchV8<bits<4> cc, string nm> : F2_2<cc, 0b110, nm> {
|
|
||||||
let isBranch = 1;
|
|
||||||
let isTerminator = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
def FBA : FPBranchV8<0b1000, "fba">;
|
|
||||||
def FBN : FPBranchV8<0b0000, "fbn">;
|
|
||||||
def FBU : FPBranchV8<0b0111, "fbu">;
|
|
||||||
def FBG : FPBranchV8<0b0110, "fbg">;
|
|
||||||
def FBUG : FPBranchV8<0b0101, "fbug">;
|
|
||||||
def FBL : FPBranchV8<0b0100, "fbl">;
|
|
||||||
def FBUL : FPBranchV8<0b0011, "fbul">;
|
|
||||||
def FBLG : FPBranchV8<0b0010, "fblg">;
|
|
||||||
def FBNE : FPBranchV8<0b0001, "fbne">;
|
|
||||||
def FBE : FPBranchV8<0b1001, "fbe">;
|
|
||||||
def FBUE : FPBranchV8<0b1010, "fbue">;
|
|
||||||
def FBGE : FPBranchV8<0b1011, "fbge">;
|
|
||||||
def FBUGE: FPBranchV8<0b1100, "fbuge">;
|
|
||||||
def FBLE : FPBranchV8<0b1101, "fble">;
|
|
||||||
def FBULE: FPBranchV8<0b1110, "fbule">;
|
|
||||||
def FBO : FPBranchV8<0b1111, "fbo">;
|
|
||||||
|
|
||||||
// Section B.24 - Call and Link Instruction, p. 125
|
|
||||||
// This is the only Format 1 instruction
|
|
||||||
def CALL : InstV8 {
|
|
||||||
bits<30> disp;
|
|
||||||
let op = 1;
|
|
||||||
let Inst{29-0} = disp;
|
|
||||||
let Name = "call";
|
|
||||||
let isCall = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Section B.25 - Jump and Link, p. 126
|
|
||||||
let isCall = 1 in
|
|
||||||
def JMPLrr : F3_1<2, 0b111000, "jmpl">; // jmpl [rs1+rs2], rd
|
|
||||||
|
|
||||||
// Section B.29 - Write State Register Instructions
|
|
||||||
def WRrr : F3_1<2, 0b110000, "wr">; // wr rs1, rs2, rd
|
|
||||||
def WRri : F3_2<2, 0b110000, "wr">; // wr rs1, imm, rd
|
|
||||||
|
|
||||||
// Convert Integer to Floating-point Instructions, p. 141
|
|
||||||
def FITOS : F3_3<2, 0b110100, 0b011000100, "fitos">;
|
|
||||||
def FITOD : F3_3<2, 0b110100, 0b011001000, "fitos">;
|
|
||||||
|
|
||||||
// Convert between Floating-point Formats Instructions, p. 143
|
|
||||||
def FSTOD : F3_3<2, 0b110100, 0b011001001, "fstod">;
|
|
||||||
def FDTOS : F3_3<2, 0b110100, 0b011000110, "fdtos">;
|
|
||||||
|
|
||||||
// Floating-point Move Instructions, p. 144
|
|
||||||
def FMOVS : F3_3<2, 0b110100, 0b000000001, "fmovs">;
|
|
||||||
def FNEGS : F3_3<2, 0b110100, 0b000000101, "fnegs">;
|
|
||||||
def FABSS : F3_3<2, 0b110100, 0b000001001, "fabss">;
|
|
||||||
|
|
||||||
// Floating-point Add and Subtract Instructions, p. 146
|
|
||||||
def FADDS : F3_3<2, 0b110100, 0b001000001, "fadds">;
|
|
||||||
def FADDD : F3_3<2, 0b110100, 0b001000010, "faddd">;
|
|
||||||
def FSUBS : F3_3<2, 0b110100, 0b001000101, "fsubs">;
|
|
||||||
def FSUBD : F3_3<2, 0b110100, 0b001000110, "fsubd">;
|
|
||||||
|
|
||||||
// Floating-point Multiply and Divide Instructions, p. 147
|
|
||||||
def FMULS : F3_3<2, 0b110100, 0b001001001, "fmuls">;
|
|
||||||
def FMULD : F3_3<2, 0b110100, 0b001001010, "fmuld">;
|
|
||||||
def FSMULD : F3_3<2, 0b110100, 0b001101001, "fsmuld">;
|
|
||||||
def FDIVS : F3_3<2, 0b110100, 0b001001101, "fdivs">;
|
|
||||||
def FDIVD : F3_3<2, 0b110100, 0b001001110, "fdivd">;
|
|
||||||
|
|
||||||
// Floating-point Compare Instructions, p. 148
|
|
||||||
// Note: the 2nd template arg is different for these guys
|
|
||||||
def FCMPS : F3_3<2, 0b110101, 0b001010001, "fcmps">;
|
|
||||||
def FCMPD : F3_3<2, 0b110101, 0b001010010, "fcmpd">;
|
|
||||||
def FCMPES : F3_3<2, 0b110101, 0b001010101, "fcmpes">;
|
|
||||||
def FCMPED : F3_3<2, 0b110101, 0b001010110, "fcmped">;
|
|
||||||
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
//===- SparcV8Instrs_F2.td - Format 2 instructions: SparcV8 Target --------===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// Format #2 instruction classes in the SparcV8
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
class F2 : InstV8 { // Format 2 instructions
|
|
||||||
bits<3> op2;
|
|
||||||
bits<22> imm22;
|
|
||||||
let op = 0; // op = 0
|
|
||||||
let Inst{24-22} = op2;
|
|
||||||
let Inst{21-0} = imm22;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specific F2 classes: SparcV8 manual, page 44
|
|
||||||
//
|
|
||||||
class F2_1<bits<3> op2Val, string name> : F2 {
|
|
||||||
bits<5> rd;
|
|
||||||
bits<22> imm;
|
|
||||||
|
|
||||||
let op2 = op2Val;
|
|
||||||
let Name = name;
|
|
||||||
|
|
||||||
let Inst{29-25} = rd;
|
|
||||||
}
|
|
||||||
|
|
||||||
class F2_2<bits<4> condVal, bits<3> op2Val, string name> : F2 {
|
|
||||||
bits<4> cond;
|
|
||||||
bit annul = 0; // currently unused
|
|
||||||
|
|
||||||
let cond = condVal;
|
|
||||||
let op2 = op2Val;
|
|
||||||
let Name = name;
|
|
||||||
|
|
||||||
let Inst{29} = annul;
|
|
||||||
let Inst{28-25} = cond;
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
//===- SparcV8Instrs_F3.td - Format 3 Instructions: SparcV8 Target --------===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// Format #3 instruction classes in the SparcV8
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
class F3 : InstV8 {
|
|
||||||
bits<5> rd;
|
|
||||||
bits<6> op3;
|
|
||||||
bits<5> rs1;
|
|
||||||
let op{1} = 1; // Op = 2 or 3
|
|
||||||
let Inst{29-25} = rd;
|
|
||||||
let Inst{24-19} = op3;
|
|
||||||
let Inst{18-14} = rs1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specific F3 classes: SparcV8 manual, page 44
|
|
||||||
//
|
|
||||||
class F3_1<bits<2> opVal, bits<6> op3val, string name> : F3 {
|
|
||||||
bits<8> asi;
|
|
||||||
bits<5> rs2;
|
|
||||||
|
|
||||||
let op = opVal;
|
|
||||||
let op3 = op3val;
|
|
||||||
let Name = name;
|
|
||||||
|
|
||||||
let Inst{13} = 0; // i field = 0
|
|
||||||
let Inst{12-5} = asi; // address space identifier
|
|
||||||
let Inst{4-0} = rs2;
|
|
||||||
}
|
|
||||||
|
|
||||||
class F3_2<bits<2> opVal, bits<6> op3val, string name> : F3 {
|
|
||||||
bits<13> simm13;
|
|
||||||
|
|
||||||
let op = opVal;
|
|
||||||
let op3 = op3val;
|
|
||||||
let Name = name;
|
|
||||||
|
|
||||||
let Inst{13} = 1; // i field = 1
|
|
||||||
let Inst{12-0} = simm13;
|
|
||||||
}
|
|
||||||
|
|
||||||
// floating-point
|
|
||||||
class F3_3<bits<2> opVal, bits<6> op3val, bits<9> opfval, string name> : F3 {
|
|
||||||
bits<8> asi;
|
|
||||||
bits<5> rs2;
|
|
||||||
|
|
||||||
let op = opVal;
|
|
||||||
let op3 = op3val;
|
|
||||||
let Name = name;
|
|
||||||
|
|
||||||
let Inst{13-5} = opfval; // fp opcode
|
|
||||||
let Inst{4-0} = rs2;
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
//===- SparcV8JITInfo.h - SparcV8 impl. of the JIT interface ----*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This file contains the SparcV8 implementation of the TargetJITInfo class.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef SPARCV8JITINFO_H
|
|
||||||
#define SPARCV8JITINFO_H
|
|
||||||
|
|
||||||
#include "llvm/Target/TargetJITInfo.h"
|
|
||||||
|
|
||||||
namespace llvm {
|
|
||||||
class TargetMachine;
|
|
||||||
class IntrinsicLowering;
|
|
||||||
|
|
||||||
class SparcV8JITInfo : public TargetJITInfo {
|
|
||||||
TargetMachine &TM;
|
|
||||||
public:
|
|
||||||
SparcV8JITInfo(TargetMachine &tm) : TM(tm) {}
|
|
||||||
|
|
||||||
/// addPassesToJITCompile - Add passes to the specified pass manager to
|
|
||||||
/// implement a fast dynamic compiler for this target. Return true if this
|
|
||||||
/// is not supported for this target.
|
|
||||||
///
|
|
||||||
virtual void addPassesToJITCompile(FunctionPassManager &PM);
|
|
||||||
|
|
||||||
/// replaceMachineCodeForFunction - Make it so that calling the function
|
|
||||||
/// whose machine code is at OLD turns into a call to NEW, perhaps by
|
|
||||||
/// overwriting OLD with a branch to NEW. This is used for self-modifying
|
|
||||||
/// code.
|
|
||||||
///
|
|
||||||
virtual void replaceMachineCodeForFunction(void *Old, void *New);
|
|
||||||
|
|
||||||
/// getJITStubForFunction - Create or return a stub for the specified
|
|
||||||
/// function. This stub acts just like the specified function, except that
|
|
||||||
/// it allows the "address" of the function to be taken without having to
|
|
||||||
/// generate code for it.
|
|
||||||
virtual void *getJITStubForFunction(Function *F, MachineCodeEmitter &MCE);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,165 +0,0 @@
|
|||||||
//===- SparcV8RegisterInfo.cpp - SparcV8 Register Information ---*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This file contains the SparcV8 implementation of the MRegisterInfo class.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "SparcV8.h"
|
|
||||||
#include "SparcV8RegisterInfo.h"
|
|
||||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
|
||||||
#include "llvm/CodeGen/MachineFunction.h"
|
|
||||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
|
||||||
#include "llvm/Type.h"
|
|
||||||
#include "Support/STLExtras.h"
|
|
||||||
#include <iostream>
|
|
||||||
using namespace llvm;
|
|
||||||
|
|
||||||
SparcV8RegisterInfo::SparcV8RegisterInfo()
|
|
||||||
: SparcV8GenRegisterInfo(V8::ADJCALLSTACKDOWN,
|
|
||||||
V8::ADJCALLSTACKUP) {}
|
|
||||||
|
|
||||||
int SparcV8RegisterInfo::storeRegToStackSlot(
|
|
||||||
MachineBasicBlock &MBB,
|
|
||||||
MachineBasicBlock::iterator I,
|
|
||||||
unsigned SrcReg, int FrameIdx,
|
|
||||||
const TargetRegisterClass *RC) const
|
|
||||||
{
|
|
||||||
// On the order of operands here: think "[FrameIdx + 0] = SrcReg".
|
|
||||||
if (RC == SparcV8::IntRegsRegisterClass)
|
|
||||||
BuildMI (MBB, I, V8::ST, 3).addFrameIndex (FrameIdx).addSImm (0)
|
|
||||||
.addReg (SrcReg);
|
|
||||||
else if (RC == SparcV8::FPRegsRegisterClass)
|
|
||||||
BuildMI (MBB, I, V8::STFri, 3).addFrameIndex (FrameIdx).addSImm (0)
|
|
||||||
.addReg (SrcReg);
|
|
||||||
else if (RC == SparcV8::DFPRegsRegisterClass)
|
|
||||||
BuildMI (MBB, I, V8::STDFri, 3).addFrameIndex (FrameIdx).addSImm (0)
|
|
||||||
.addReg (SrcReg);
|
|
||||||
else
|
|
||||||
assert (0 && "Can't store this register to stack slot");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SparcV8RegisterInfo::loadRegFromStackSlot(
|
|
||||||
MachineBasicBlock &MBB,
|
|
||||||
MachineBasicBlock::iterator I,
|
|
||||||
unsigned DestReg, int FrameIdx,
|
|
||||||
const TargetRegisterClass *RC) const
|
|
||||||
{
|
|
||||||
if (RC == SparcV8::IntRegsRegisterClass)
|
|
||||||
BuildMI (MBB, I, V8::LD, 2, DestReg).addFrameIndex (FrameIdx).addSImm (0);
|
|
||||||
else if (RC == SparcV8::FPRegsRegisterClass)
|
|
||||||
BuildMI (MBB, I, V8::LDFri, 2, DestReg).addFrameIndex (FrameIdx)
|
|
||||||
.addSImm (0);
|
|
||||||
else if (RC == SparcV8::DFPRegsRegisterClass)
|
|
||||||
BuildMI (MBB, I, V8::LDDFri, 2, DestReg).addFrameIndex (FrameIdx)
|
|
||||||
.addSImm (0);
|
|
||||||
else
|
|
||||||
assert (0 && "Can't load this register from stack slot");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SparcV8RegisterInfo::copyRegToReg(MachineBasicBlock &MBB,
|
|
||||||
MachineBasicBlock::iterator I,
|
|
||||||
unsigned DestReg, unsigned SrcReg,
|
|
||||||
const TargetRegisterClass *RC) const {
|
|
||||||
if (RC == SparcV8::IntRegsRegisterClass)
|
|
||||||
BuildMI (MBB, I, V8::ORrr, 2, DestReg).addReg (V8::G0).addReg (SrcReg);
|
|
||||||
else if (RC == SparcV8::FPRegsRegisterClass)
|
|
||||||
BuildMI (MBB, I, V8::FMOVS, 1, DestReg).addReg (SrcReg);
|
|
||||||
else
|
|
||||||
assert (0 && "Can't copy this register");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SparcV8RegisterInfo::
|
|
||||||
eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
|
|
||||||
MachineBasicBlock::iterator I) const {
|
|
||||||
std::cerr
|
|
||||||
<< "Sorry, I don't know how to eliminate call frame pseudo instrs yet, in\n"
|
|
||||||
<< __FUNCTION__ << " at " << __FILE__ << ":" << __LINE__ << "\n";
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SparcV8RegisterInfo::eliminateFrameIndex(MachineFunction &MF,
|
|
||||||
MachineBasicBlock::iterator II) const {
|
|
||||||
unsigned i = 0;
|
|
||||||
MachineInstr &MI = *II;
|
|
||||||
while (!MI.getOperand(i).isFrameIndex()) {
|
|
||||||
++i;
|
|
||||||
assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!");
|
|
||||||
}
|
|
||||||
|
|
||||||
int FrameIndex = MI.getOperand(i).getFrameIndex();
|
|
||||||
|
|
||||||
// Replace frame index with a frame pointer reference
|
|
||||||
MI.SetMachineOperandReg (i, V8::FP);
|
|
||||||
|
|
||||||
// Addressable stack objects are accessed using neg. offsets from %fp
|
|
||||||
int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex) +
|
|
||||||
MI.getOperand(i+1).getImmedValue();
|
|
||||||
// note: Offset < 0
|
|
||||||
MI.SetMachineOperandConst (i+1, MachineOperand::MO_SignExtendedImmed, Offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SparcV8RegisterInfo::
|
|
||||||
processFunctionBeforeFrameFinalized(MachineFunction &MF) const {}
|
|
||||||
|
|
||||||
void SparcV8RegisterInfo::emitPrologue(MachineFunction &MF) const {
|
|
||||||
MachineBasicBlock &MBB = MF.front();
|
|
||||||
MachineFrameInfo *MFI = MF.getFrameInfo();
|
|
||||||
|
|
||||||
// Get the number of bytes to allocate from the FrameInfo
|
|
||||||
int NumBytes = (int) MFI->getStackSize();
|
|
||||||
|
|
||||||
// Emit the correct save instruction based on the number of bytes in the frame.
|
|
||||||
// Minimum stack frame size according to V8 ABI is:
|
|
||||||
// 16 words for register window spill
|
|
||||||
// 1 word for address of returned aggregate-value
|
|
||||||
// + 6 words for passing parameters on the stack
|
|
||||||
// ----------
|
|
||||||
// 23 words * 4 bytes per word = 92 bytes
|
|
||||||
NumBytes += 92;
|
|
||||||
// Round up to next doubleword boundary -- a double-word boundary
|
|
||||||
// is required by the ABI.
|
|
||||||
NumBytes = (NumBytes + 7) & ~7;
|
|
||||||
BuildMI(MBB, MBB.begin(), V8::SAVEri, 2,
|
|
||||||
V8::SP).addImm(-NumBytes).addReg(V8::SP);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SparcV8RegisterInfo::emitEpilogue(MachineFunction &MF,
|
|
||||||
MachineBasicBlock &MBB) const {
|
|
||||||
MachineBasicBlock::iterator MBBI = prior(MBB.end());
|
|
||||||
assert(MBBI->getOpcode() == V8::RETL &&
|
|
||||||
"Can only put epilog before 'retl' instruction!");
|
|
||||||
BuildMI(MBB, MBBI, V8::RESTORErr, 2, V8::G0).addReg(V8::G0).addReg(V8::G0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "SparcV8GenRegisterInfo.inc"
|
|
||||||
|
|
||||||
const TargetRegisterClass*
|
|
||||||
SparcV8RegisterInfo::getRegClassForType(const Type* Ty) const {
|
|
||||||
switch (Ty->getTypeID()) {
|
|
||||||
case Type::FloatTyID: return &FPRegsInstance;
|
|
||||||
case Type::DoubleTyID: return &DFPRegsInstance;
|
|
||||||
case Type::LongTyID:
|
|
||||||
case Type::ULongTyID: assert(0 && "Long values do not fit in registers!");
|
|
||||||
default: assert(0 && "Invalid type to getClass!");
|
|
||||||
case Type::BoolTyID:
|
|
||||||
case Type::SByteTyID:
|
|
||||||
case Type::UByteTyID:
|
|
||||||
case Type::ShortTyID:
|
|
||||||
case Type::UShortTyID:
|
|
||||||
case Type::IntTyID:
|
|
||||||
case Type::UIntTyID:
|
|
||||||
case Type::PointerTyID: return &IntRegsInstance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
//===- SparcV8RegisterInfo.h - SparcV8 Register Information Impl -*- C++ -*-==//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This file contains the SparcV8 implementation of the MRegisterInfo class.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef SPARCV8REGISTERINFO_H
|
|
||||||
#define SPARCV8REGISTERINFO_H
|
|
||||||
|
|
||||||
#include "llvm/Target/MRegisterInfo.h"
|
|
||||||
#include "SparcV8GenRegisterInfo.h.inc"
|
|
||||||
|
|
||||||
namespace llvm {
|
|
||||||
|
|
||||||
class Type;
|
|
||||||
|
|
||||||
struct SparcV8RegisterInfo : public SparcV8GenRegisterInfo {
|
|
||||||
SparcV8RegisterInfo();
|
|
||||||
const TargetRegisterClass* getRegClassForType(const Type* Ty) const;
|
|
||||||
|
|
||||||
/// Code Generation virtual methods...
|
|
||||||
int storeRegToStackSlot(MachineBasicBlock &MBB,
|
|
||||||
MachineBasicBlock::iterator MBBI,
|
|
||||||
unsigned SrcReg, int FrameIndex,
|
|
||||||
const TargetRegisterClass *RC) const;
|
|
||||||
|
|
||||||
int loadRegFromStackSlot(MachineBasicBlock &MBB,
|
|
||||||
MachineBasicBlock::iterator MBBI,
|
|
||||||
unsigned DestReg, int FrameIndex,
|
|
||||||
const TargetRegisterClass *RC) const;
|
|
||||||
|
|
||||||
int copyRegToReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
|
|
||||||
unsigned DestReg, unsigned SrcReg,
|
|
||||||
const TargetRegisterClass *RC) const;
|
|
||||||
|
|
||||||
void eliminateCallFramePseudoInstr(MachineFunction &MF,
|
|
||||||
MachineBasicBlock &MBB,
|
|
||||||
MachineBasicBlock::iterator I) const;
|
|
||||||
|
|
||||||
void eliminateFrameIndex(MachineFunction &MF,
|
|
||||||
MachineBasicBlock::iterator II) const;
|
|
||||||
|
|
||||||
void processFunctionBeforeFrameFinalized(MachineFunction &MF) const;
|
|
||||||
|
|
||||||
void emitPrologue(MachineFunction &MF) const;
|
|
||||||
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // end namespace llvm
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
//===- SparcV8Reg.td - Describe the SparcV8 Register File -------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// Declarations that describe the SparcV8 register file
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
// Registers are identified with 5-bit ID numbers.
|
|
||||||
// Ri - 32-bit integer registers
|
|
||||||
class Ri<bits<5> num> : Register {
|
|
||||||
field bits<5> Num = num;
|
|
||||||
}
|
|
||||||
// Rf - 32-bit floating-point registers
|
|
||||||
class Rf<bits<5> num> : Register {
|
|
||||||
field bits<5> Num = num;
|
|
||||||
}
|
|
||||||
// Rd - Slots in the FP register file for 64-bit floating-point values.
|
|
||||||
class Rd<bits<5> num, string realName> : Register {
|
|
||||||
field bits<5> Num = num;
|
|
||||||
let Name = realName;
|
|
||||||
}
|
|
||||||
// Rs - Special "ancillary state registers" registers, like the Y, ASR, PSR,
|
|
||||||
// WIM, TBR, etc registers
|
|
||||||
class Rs<bits<5> num> : Register {
|
|
||||||
field bits<5> Num = num;
|
|
||||||
}
|
|
||||||
|
|
||||||
let Namespace = "V8" in {
|
|
||||||
def G0 : Ri< 0>; def G1 : Ri< 1>; def G2 : Ri< 2>; def G3 : Ri< 3>;
|
|
||||||
def G4 : Ri< 4>; def G5 : Ri< 5>; def G6 : Ri< 6>; def G7 : Ri< 7>;
|
|
||||||
def O0 : Ri< 8>; def O1 : Ri< 9>; def O2 : Ri<10>; def O3 : Ri<11>;
|
|
||||||
def O4 : Ri<12>; def O5 : Ri<13>; def O6 : Ri<14>; def O7 : Ri<15>;
|
|
||||||
def L0 : Ri<16>; def L1 : Ri<17>; def L2 : Ri<18>; def L3 : Ri<19>;
|
|
||||||
def L4 : Ri<20>; def L5 : Ri<21>; def L6 : Ri<22>; def L7 : Ri<23>;
|
|
||||||
def I0 : Ri<24>; def I1 : Ri<25>; def I2 : Ri<26>; def I3 : Ri<27>;
|
|
||||||
def I4 : Ri<28>; def I5 : Ri<29>; def I6 : Ri<30>; def I7 : Ri<31>;
|
|
||||||
|
|
||||||
// Standard register aliases.
|
|
||||||
def SP : Ri<14>; def FP : Ri<30>;
|
|
||||||
|
|
||||||
// Floating-point registers:
|
|
||||||
def F0 : Rf< 0>; def F1 : Rf< 1>; def F2 : Rf< 2>; def F3 : Rf< 3>;
|
|
||||||
def F4 : Rf< 4>; def F5 : Rf< 5>; def F6 : Rf< 6>; def F7 : Rf< 7>;
|
|
||||||
def F8 : Rf< 8>; def F9 : Rf< 9>; def F10 : Rf<10>; def F11 : Rf<11>;
|
|
||||||
def F12 : Rf<12>; def F13 : Rf<13>; def F14 : Rf<14>; def F15 : Rf<15>;
|
|
||||||
def F16 : Rf<16>; def F17 : Rf<17>; def F18 : Rf<18>; def F19 : Rf<19>;
|
|
||||||
def F20 : Rf<20>; def F21 : Rf<21>; def F22 : Rf<22>; def F23 : Rf<23>;
|
|
||||||
def F24 : Rf<24>; def F25 : Rf<25>; def F26 : Rf<26>; def F27 : Rf<27>;
|
|
||||||
def F28 : Rf<28>; def F29 : Rf<29>; def F30 : Rf<30>; def F31 : Rf<31>;
|
|
||||||
|
|
||||||
// Aliases of the F* registers used to hold 64-bit fp values (doubles).
|
|
||||||
def D0 : Rd< 0, "F0">; def D1 : Rd< 2, "F2">; def D2 : Rd< 4, "F4">;
|
|
||||||
def D3 : Rd< 6, "F6">; def D4 : Rd< 8, "F8">; def D5 : Rd<10, "F10">;
|
|
||||||
def D6 : Rd<12, "F12">; def D7 : Rd<14, "F14">; def D8 : Rd<16, "F16">;
|
|
||||||
def D9 : Rd<18, "F18">; def D10 : Rd<20, "F20">; def D11 : Rd<22, "F22">;
|
|
||||||
def D12 : Rd<24, "F24">; def D13 : Rd<26, "F26">; def D14 : Rd<28, "F28">;
|
|
||||||
def D15 : Rd<30, "F30">;
|
|
||||||
|
|
||||||
// The Y register.
|
|
||||||
def Y : Rs<0>;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register classes.
|
|
||||||
//
|
|
||||||
// FIXME: the register order should be defined in terms of the preferred
|
|
||||||
// allocation order...
|
|
||||||
//
|
|
||||||
def IntRegs : RegisterClass<i32, 8, [L0, L1, L2, L3, L4, L5, L6, L7,
|
|
||||||
I0, I1, I2, I3, I4, I5,
|
|
||||||
G1, G2, G3, G4, G5, G6, G7,
|
|
||||||
O0, O1, O2, O3, O4, O5, O7,
|
|
||||||
// Non-allocatable regs
|
|
||||||
O6, I6, I7, G0]> {
|
|
||||||
let Methods = [{
|
|
||||||
iterator allocation_order_end(MachineFunction &MF) const {
|
|
||||||
return end()-4; // Don't allocate special registers
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
def FPRegs : RegisterClass<f32, 4, [F0, F1, F2, F3, F4, F5, F6, F7, F8,
|
|
||||||
F9, F10, F11, F12, F13, F14, F15, F16, F17, F18, F19, F20, F21, F22,
|
|
||||||
F23, F24, F25, F26, F27, F28, F29, F30, F31]>;
|
|
||||||
|
|
||||||
def DFPRegs : RegisterClass<f64, 8, [D0, D1, D2, D3, D4, D5, D6, D7,
|
|
||||||
D8, D9, D10, D11, D12, D13, D14, D15]>;
|
|
||||||
|
|
||||||
// Tell the register file generator that the double-fp pseudo-registers
|
|
||||||
// alias the registers used for single-fp values.
|
|
||||||
def : RegisterAliases<D0, [F0, F1]>;
|
|
||||||
def : RegisterAliases<D1, [F2, F3]>;
|
|
||||||
def : RegisterAliases<D2, [F4, F5]>;
|
|
||||||
def : RegisterAliases<D3, [F6, F7]>;
|
|
||||||
def : RegisterAliases<D4, [F8, F9]>;
|
|
||||||
def : RegisterAliases<D5, [F10, F11]>;
|
|
||||||
def : RegisterAliases<D6, [F12, F13]>;
|
|
||||||
def : RegisterAliases<D7, [F14, F15]>;
|
|
||||||
def : RegisterAliases<D8, [F16, F17]>;
|
|
||||||
def : RegisterAliases<D9, [F18, F19]>;
|
|
||||||
def : RegisterAliases<D10, [F20, F21]>;
|
|
||||||
def : RegisterAliases<D11, [F22, F23]>;
|
|
||||||
def : RegisterAliases<D12, [F24, F25]>;
|
|
||||||
def : RegisterAliases<D13, [F26, F27]>;
|
|
||||||
def : RegisterAliases<D14, [F28, F29]>;
|
|
||||||
def : RegisterAliases<D15, [F30, F31]>;
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
//===-- SparcV8TargetMachine.cpp - Define TargetMachine for SparcV8 -------===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "SparcV8TargetMachine.h"
|
|
||||||
#include "SparcV8.h"
|
|
||||||
#include "llvm/Module.h"
|
|
||||||
#include "llvm/PassManager.h"
|
|
||||||
#include "llvm/CodeGen/MachineFunction.h"
|
|
||||||
#include "llvm/CodeGen/Passes.h"
|
|
||||||
#include "llvm/Target/TargetOptions.h"
|
|
||||||
#include "llvm/Target/TargetMachineRegistry.h"
|
|
||||||
#include "llvm/Transforms/Scalar.h"
|
|
||||||
#include <iostream>
|
|
||||||
using namespace llvm;
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
// Register the target.
|
|
||||||
RegisterTarget<SparcV8TargetMachine> X("sparcv8"," SPARC V8 (experimental)");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// SparcV8TargetMachine ctor - Create an ILP32 architecture model
|
|
||||||
///
|
|
||||||
SparcV8TargetMachine::SparcV8TargetMachine(const Module &M,
|
|
||||||
IntrinsicLowering *IL)
|
|
||||||
: TargetMachine("SparcV8", IL, true, 4, 4, 4, 4, 4),
|
|
||||||
FrameInfo(TargetFrameInfo::StackGrowsDown, 8, 0), JITInfo(*this) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/// addPassesToEmitAssembly - Add passes to the specified pass manager
|
|
||||||
/// to implement a static compiler for this target.
|
|
||||||
///
|
|
||||||
bool SparcV8TargetMachine::addPassesToEmitAssembly(PassManager &PM,
|
|
||||||
std::ostream &Out) {
|
|
||||||
// FIXME: Implement efficient support for garbage collection intrinsics.
|
|
||||||
PM.add(createLowerGCPass());
|
|
||||||
|
|
||||||
// Replace malloc and free instructions with library calls.
|
|
||||||
PM.add(createLowerAllocationsPass());
|
|
||||||
|
|
||||||
// FIXME: implement the select instruction in the instruction selector.
|
|
||||||
PM.add(createLowerSelectPass());
|
|
||||||
|
|
||||||
// FIXME: implement the switch instruction in the instruction selector.
|
|
||||||
PM.add(createLowerSwitchPass());
|
|
||||||
|
|
||||||
// FIXME: implement the invoke/unwind instructions!
|
|
||||||
PM.add(createLowerInvokePass());
|
|
||||||
|
|
||||||
PM.add(createLowerConstantExpressionsPass());
|
|
||||||
|
|
||||||
// Make sure that no unreachable blocks are instruction selected.
|
|
||||||
PM.add(createUnreachableBlockEliminationPass());
|
|
||||||
|
|
||||||
PM.add(createSparcV8SimpleInstructionSelector(*this));
|
|
||||||
|
|
||||||
// Print machine instructions as they were initially generated.
|
|
||||||
if (PrintMachineCode)
|
|
||||||
PM.add(createMachineFunctionPrinterPass(&std::cerr));
|
|
||||||
|
|
||||||
PM.add(createRegisterAllocator());
|
|
||||||
PM.add(createPrologEpilogCodeInserter());
|
|
||||||
|
|
||||||
// Print machine instructions after register allocation and prolog/epilog
|
|
||||||
// insertion.
|
|
||||||
if (PrintMachineCode)
|
|
||||||
PM.add(createMachineFunctionPrinterPass(&std::cerr));
|
|
||||||
|
|
||||||
PM.add(createSparcV8DelaySlotFillerPass(*this));
|
|
||||||
|
|
||||||
// Print machine instructions after filling delay slots.
|
|
||||||
if (PrintMachineCode)
|
|
||||||
PM.add(createMachineFunctionPrinterPass(&std::cerr));
|
|
||||||
|
|
||||||
// Output assembly language.
|
|
||||||
PM.add(createSparcV8CodePrinterPass(Out, *this));
|
|
||||||
|
|
||||||
// Delete the MachineInstrs we generated, since they're no longer needed.
|
|
||||||
PM.add(createMachineCodeDeleter());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// addPassesToJITCompile - Add passes to the specified pass manager to
|
|
||||||
/// implement a fast dynamic compiler for this target.
|
|
||||||
///
|
|
||||||
void SparcV8JITInfo::addPassesToJITCompile(FunctionPassManager &PM) {
|
|
||||||
// FIXME: Implement efficient support for garbage collection intrinsics.
|
|
||||||
PM.add(createLowerGCPass());
|
|
||||||
|
|
||||||
// Replace malloc and free instructions with library calls.
|
|
||||||
PM.add(createLowerAllocationsPass());
|
|
||||||
|
|
||||||
// FIXME: implement the select instruction in the instruction selector.
|
|
||||||
PM.add(createLowerSelectPass());
|
|
||||||
|
|
||||||
// FIXME: implement the switch instruction in the instruction selector.
|
|
||||||
PM.add(createLowerSwitchPass());
|
|
||||||
|
|
||||||
// FIXME: implement the invoke/unwind instructions!
|
|
||||||
PM.add(createLowerInvokePass());
|
|
||||||
|
|
||||||
PM.add(createLowerConstantExpressionsPass());
|
|
||||||
|
|
||||||
// Make sure that no unreachable blocks are instruction selected.
|
|
||||||
PM.add(createUnreachableBlockEliminationPass());
|
|
||||||
|
|
||||||
PM.add(createSparcV8SimpleInstructionSelector(TM));
|
|
||||||
|
|
||||||
// Print machine instructions as they were initially generated.
|
|
||||||
if (PrintMachineCode)
|
|
||||||
PM.add(createMachineFunctionPrinterPass(&std::cerr));
|
|
||||||
|
|
||||||
PM.add(createRegisterAllocator());
|
|
||||||
PM.add(createPrologEpilogCodeInserter());
|
|
||||||
|
|
||||||
// Print machine instructions after register allocation and prolog/epilog
|
|
||||||
// insertion.
|
|
||||||
if (PrintMachineCode)
|
|
||||||
PM.add(createMachineFunctionPrinterPass(&std::cerr));
|
|
||||||
|
|
||||||
PM.add(createSparcV8DelaySlotFillerPass(TM));
|
|
||||||
|
|
||||||
// Print machine instructions after filling delay slots.
|
|
||||||
if (PrintMachineCode)
|
|
||||||
PM.add(createMachineFunctionPrinterPass(&std::cerr));
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
//===-- SparcV8TargetMachine.h - Define TargetMachine for SparcV8 -*- C++ -*-=//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by the LLVM research group and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This file declares the SparcV8 specific subclass of TargetMachine.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef SPARCV8TARGETMACHINE_H
|
|
||||||
#define SPARCV8TARGETMACHINE_H
|
|
||||||
|
|
||||||
#include "llvm/Target/TargetMachine.h"
|
|
||||||
#include "llvm/Target/TargetFrameInfo.h"
|
|
||||||
#include "llvm/PassManager.h"
|
|
||||||
#include "SparcV8InstrInfo.h"
|
|
||||||
#include "SparcV8JITInfo.h"
|
|
||||||
|
|
||||||
namespace llvm {
|
|
||||||
|
|
||||||
class IntrinsicLowering;
|
|
||||||
|
|
||||||
class SparcV8TargetMachine : public TargetMachine {
|
|
||||||
SparcV8InstrInfo InstrInfo;
|
|
||||||
TargetFrameInfo FrameInfo;
|
|
||||||
SparcV8JITInfo JITInfo;
|
|
||||||
public:
|
|
||||||
SparcV8TargetMachine(const Module &M, IntrinsicLowering *IL);
|
|
||||||
|
|
||||||
virtual const SparcV8InstrInfo *getInstrInfo() const { return &InstrInfo; }
|
|
||||||
virtual const TargetFrameInfo *getFrameInfo() const { return &FrameInfo; }
|
|
||||||
virtual const MRegisterInfo *getRegisterInfo() const {
|
|
||||||
return &InstrInfo.getRegisterInfo();
|
|
||||||
}
|
|
||||||
virtual TargetJITInfo *getJITInfo() {
|
|
||||||
return &JITInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// addPassesToEmitMachineCode - Add passes to the specified pass manager to
|
|
||||||
/// get machine code emitted. This uses a MachineCodeEmitter object to handle
|
|
||||||
/// actually outputting the machine code and resolving things like the address
|
|
||||||
/// of functions. This method should returns true if machine code emission is
|
|
||||||
/// not supported.
|
|
||||||
///
|
|
||||||
virtual bool addPassesToEmitMachineCode(FunctionPassManager &PM,
|
|
||||||
MachineCodeEmitter &MCE);
|
|
||||||
|
|
||||||
virtual bool addPassesToEmitAssembly(PassManager &PM, std::ostream &Out);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // end namespace llvm
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -151,7 +151,7 @@ bool llvm::ExpressionConvertibleToType(Value *V, const Type *Ty,
|
|||||||
// If it's a constant... all constants can be converted to a different
|
// If it's a constant... all constants can be converted to a different
|
||||||
// type.
|
// type.
|
||||||
//
|
//
|
||||||
if (Constant *CPV = dyn_cast<Constant>(V))
|
if (isa<Constant>(V) && !isa<GlobalValue>(V))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
CTMap[V] = Ty;
|
CTMap[V] = Ty;
|
||||||
@@ -984,10 +984,9 @@ static void ConvertOperandToType(User *U, Value *OldVal, Value *NewVal,
|
|||||||
|
|
||||||
unsigned OtherIdx = (OldVal == I->getOperand(0)) ? 1 : 0;
|
unsigned OtherIdx = (OldVal == I->getOperand(0)) ? 1 : 0;
|
||||||
Value *OtherOp = I->getOperand(OtherIdx);
|
Value *OtherOp = I->getOperand(OtherIdx);
|
||||||
Value *NewOther = ConvertExpressionToType(OtherOp, NewTy, VMC, TD);
|
|
||||||
|
|
||||||
Res->setOperand(OtherIdx, NewOther);
|
|
||||||
Res->setOperand(!OtherIdx, NewVal);
|
Res->setOperand(!OtherIdx, NewVal);
|
||||||
|
Value *NewOther = ConvertExpressionToType(OtherOp, NewTy, VMC, TD);
|
||||||
|
Res->setOperand(OtherIdx, NewOther);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Instruction::Shl:
|
case Instruction::Shl:
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include "llvm/Pass.h"
|
#include "llvm/Pass.h"
|
||||||
#include "llvm/Function.h"
|
#include "llvm/Function.h"
|
||||||
|
#include <iostream>
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|||||||
@@ -31,6 +31,16 @@ namespace {
|
|||||||
// FunctionInfo - For each function, calculate the size of it in blocks and
|
// FunctionInfo - For each function, calculate the size of it in blocks and
|
||||||
// instructions.
|
// instructions.
|
||||||
struct FunctionInfo {
|
struct FunctionInfo {
|
||||||
|
// HasAllocas - Keep track of whether or not a function contains an alloca
|
||||||
|
// instruction that is not in the entry block of the function. Inlining
|
||||||
|
// this call could cause us to blow out the stack, because the stack memory
|
||||||
|
// would never be released.
|
||||||
|
//
|
||||||
|
// FIXME: LLVM needs a way of dealloca'ing memory, which would make this
|
||||||
|
// irrelevant!
|
||||||
|
//
|
||||||
|
bool HasAllocas;
|
||||||
|
|
||||||
// NumInsts, NumBlocks - Keep track of how large each function is, which is
|
// NumInsts, NumBlocks - Keep track of how large each function is, which is
|
||||||
// used to estimate the code size cost of inlining it.
|
// used to estimate the code size cost of inlining it.
|
||||||
unsigned NumInsts, NumBlocks;
|
unsigned NumInsts, NumBlocks;
|
||||||
@@ -41,7 +51,11 @@ namespace {
|
|||||||
// entry here.
|
// entry here.
|
||||||
std::vector<ArgInfo> ArgumentWeights;
|
std::vector<ArgInfo> ArgumentWeights;
|
||||||
|
|
||||||
FunctionInfo() : NumInsts(0), NumBlocks(0) {}
|
FunctionInfo() : HasAllocas(false), NumInsts(0), NumBlocks(0) {}
|
||||||
|
|
||||||
|
/// analyzeFunction - Fill in the current structure with information gleaned
|
||||||
|
/// from the specified function.
|
||||||
|
void analyzeFunction(Function *F);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SimpleInliner : public Inliner {
|
class SimpleInliner : public Inliner {
|
||||||
@@ -123,6 +137,41 @@ static unsigned CountCodeReductionForAlloca(Value *V) {
|
|||||||
return Reduction;
|
return Reduction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// analyzeFunction - Fill in the current structure with information gleaned
|
||||||
|
/// from the specified function.
|
||||||
|
void FunctionInfo::analyzeFunction(Function *F) {
|
||||||
|
unsigned NumInsts = 0, NumBlocks = 0;
|
||||||
|
|
||||||
|
// Look at the size of the callee. Each basic block counts as 20 units, and
|
||||||
|
// each instruction counts as 10.
|
||||||
|
for (Function::const_iterator BB = F->begin(), E = F->end(); BB != E; ++BB) {
|
||||||
|
for (BasicBlock::const_iterator II = BB->begin(), E = BB->end();
|
||||||
|
II != E; ++II) {
|
||||||
|
++NumInsts;
|
||||||
|
|
||||||
|
// If there is an alloca in the body of the function, we cannot currently
|
||||||
|
// inline the function without the risk of exploding the stack.
|
||||||
|
if (isa<AllocaInst>(II) && BB != F->begin()) {
|
||||||
|
HasAllocas = true;
|
||||||
|
this->NumBlocks = this->NumInsts = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
++NumBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->NumBlocks = NumBlocks;
|
||||||
|
this->NumInsts = NumInsts;
|
||||||
|
|
||||||
|
// Check out all of the arguments to the function, figuring out how much
|
||||||
|
// code can be eliminated if one of the arguments is a constant.
|
||||||
|
for (Function::aiterator I = F->abegin(), E = F->aend(); I != E; ++I)
|
||||||
|
ArgumentWeights.push_back(ArgInfo(CountCodeReductionForConstant(I),
|
||||||
|
CountCodeReductionForAlloca(I)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// getInlineCost - The heuristic used to determine if we should inline the
|
// getInlineCost - The heuristic used to determine if we should inline the
|
||||||
// function call or not.
|
// function call or not.
|
||||||
//
|
//
|
||||||
@@ -149,31 +198,14 @@ int SimpleInliner::getInlineCost(CallSite CS) {
|
|||||||
// Get information about the callee...
|
// Get information about the callee...
|
||||||
FunctionInfo &CalleeFI = CachedFunctionInfo[Callee];
|
FunctionInfo &CalleeFI = CachedFunctionInfo[Callee];
|
||||||
|
|
||||||
// If we haven't calculated this information yet...
|
// If we haven't calculated this information yet, do so now.
|
||||||
if (CalleeFI.NumBlocks == 0) {
|
if (CalleeFI.NumBlocks == 0)
|
||||||
unsigned NumInsts = 0, NumBlocks = 0;
|
CalleeFI.analyzeFunction(Callee);
|
||||||
|
|
||||||
// Look at the size of the callee. Each basic block counts as 20 units, and
|
|
||||||
// each instruction counts as 10.
|
|
||||||
for (Function::const_iterator BB = Callee->begin(), E = Callee->end();
|
|
||||||
BB != E; ++BB) {
|
|
||||||
NumInsts += BB->size();
|
|
||||||
NumBlocks++;
|
|
||||||
}
|
|
||||||
|
|
||||||
CalleeFI.NumBlocks = NumBlocks;
|
|
||||||
CalleeFI.NumInsts = NumInsts;
|
|
||||||
|
|
||||||
// Check out all of the arguments to the function, figuring out how much
|
|
||||||
// code can be eliminated if one of the arguments is a constant.
|
|
||||||
std::vector<ArgInfo> &ArgWeights = CalleeFI.ArgumentWeights;
|
|
||||||
|
|
||||||
for (Function::aiterator I = Callee->abegin(), E = Callee->aend();
|
|
||||||
I != E; ++I)
|
|
||||||
ArgWeights.push_back(ArgInfo(CountCodeReductionForConstant(I),
|
|
||||||
CountCodeReductionForAlloca(I)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Don't inline calls to functions with allocas that are not in the entry
|
||||||
|
// block of the function.
|
||||||
|
if (CalleeFI.HasAllocas)
|
||||||
|
return 2000000000;
|
||||||
|
|
||||||
// Add to the inline quality for properties that make the call valuable to
|
// Add to the inline quality for properties that make the call valuable to
|
||||||
// inline. This includes factors that indicate that the result of inlining
|
// inline. This includes factors that indicate that the result of inlining
|
||||||
|
|||||||
@@ -54,8 +54,8 @@ static bool InlineCallIfPossible(CallSite CS, CallGraph &CG,
|
|||||||
E = CalleeNode->end(); I != E; ++I)
|
E = CalleeNode->end(); I != E; ++I)
|
||||||
CallerNode->addCalledFunction(*I);
|
CallerNode->addCalledFunction(*I);
|
||||||
|
|
||||||
// If we inlined the last possible call site to the function,
|
// If we inlined the last possible call site to the function, delete the
|
||||||
// delete the function body now.
|
// function body now.
|
||||||
if (Callee->use_empty() && Callee->hasInternalLinkage() &&
|
if (Callee->use_empty() && Callee->hasInternalLinkage() &&
|
||||||
!SCCFunctions.count(Callee)) {
|
!SCCFunctions.count(Callee)) {
|
||||||
DEBUG(std::cerr << " -> Deleting dead function: "
|
DEBUG(std::cerr << " -> Deleting dead function: "
|
||||||
@@ -64,7 +64,7 @@ static bool InlineCallIfPossible(CallSite CS, CallGraph &CG,
|
|||||||
// Remove any call graph edges from the callee to its callees.
|
// Remove any call graph edges from the callee to its callees.
|
||||||
while (CalleeNode->begin() != CalleeNode->end())
|
while (CalleeNode->begin() != CalleeNode->end())
|
||||||
CalleeNode->removeCallEdgeTo(*(CalleeNode->end()-1));
|
CalleeNode->removeCallEdgeTo(*(CalleeNode->end()-1));
|
||||||
|
|
||||||
// Removing the node for callee from the call graph and delete it.
|
// Removing the node for callee from the call graph and delete it.
|
||||||
delete CG.removeFunctionFromModule(CalleeNode);
|
delete CG.removeFunctionFromModule(CalleeNode);
|
||||||
++NumDeleted;
|
++NumDeleted;
|
||||||
@@ -167,27 +167,27 @@ bool Inliner::doFinalization(CallGraph &CG) {
|
|||||||
// from the program. Insert the dead ones in the FunctionsToRemove set.
|
// from the program. Insert the dead ones in the FunctionsToRemove set.
|
||||||
for (CallGraph::iterator I = CG.begin(), E = CG.end(); I != E; ++I) {
|
for (CallGraph::iterator I = CG.begin(), E = CG.end(); I != E; ++I) {
|
||||||
CallGraphNode *CGN = I->second;
|
CallGraphNode *CGN = I->second;
|
||||||
Function *F = CGN ? CGN->getFunction() : 0;
|
if (Function *F = CGN ? CGN->getFunction() : 0) {
|
||||||
|
// If the only remaining users of the function are dead constants,
|
||||||
|
// remove them.
|
||||||
|
bool HadDeadConstantUsers = !F->use_empty();
|
||||||
|
F->removeDeadConstantUsers();
|
||||||
|
|
||||||
// If the only remaining users of the function are dead constants,
|
if ((F->hasLinkOnceLinkage() || F->hasInternalLinkage()) &&
|
||||||
// remove them.
|
F->use_empty()) {
|
||||||
if (F) F->removeDeadConstantUsers();
|
// Remove any call graph edges from the function to its callees.
|
||||||
|
while (CGN->begin() != CGN->end())
|
||||||
if (F && (F->hasLinkOnceLinkage() || F->hasInternalLinkage()) &&
|
CGN->removeCallEdgeTo(*(CGN->end()-1));
|
||||||
F->use_empty()) {
|
|
||||||
|
// If the function has external linkage (basically if it's a linkonce
|
||||||
// Remove any call graph edges from the function to its callees.
|
// function) remove the edge from the external node to the callee
|
||||||
while (CGN->begin() != CGN->end())
|
// node.
|
||||||
CGN->removeCallEdgeTo(*(CGN->end()-1));
|
if (!F->hasInternalLinkage() || HadDeadConstantUsers)
|
||||||
|
CG.getExternalCallingNode()->removeCallEdgeTo(CGN);
|
||||||
// If the function has external linkage (basically if it's a linkonce
|
|
||||||
// function) remove the edge from the external node to the callee
|
// Removing the node for callee from the call graph and delete it.
|
||||||
// node.
|
FunctionsToRemove.insert(CGN);
|
||||||
if (!F->hasInternalLinkage())
|
}
|
||||||
CG.getExternalCallingNode()->removeCallEdgeTo(CGN);
|
|
||||||
|
|
||||||
// Removing the node for callee from the call graph and delete it.
|
|
||||||
FunctionsToRemove.insert(CGN);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -302,7 +302,8 @@ bool RPR::PeepholeOptimize(BasicBlock *BB, BasicBlock::iterator &BI) {
|
|||||||
// Make sure the source doesn't change type
|
// Make sure the source doesn't change type
|
||||||
ConvertedTypes[Src] = Src->getType();
|
ConvertedTypes[Src] = Src->getType();
|
||||||
if (ValueConvertibleToType(CI, Src->getType(), ConvertedTypes, TD)) {
|
if (ValueConvertibleToType(CI, Src->getType(), ConvertedTypes, TD)) {
|
||||||
PRINT_PEEPHOLE3("CAST-DEST-EXPR-CONV:in ", *Src, *CI, *BB->getParent());
|
//PRINT_PEEPHOLE3("CAST-DEST-EXPR-CONV:in ", *Src, *CI,
|
||||||
|
// *BB->getParent());
|
||||||
|
|
||||||
DEBUG(std::cerr << "\nCONVERTING EXPR TYPE:\n");
|
DEBUG(std::cerr << "\nCONVERTING EXPR TYPE:\n");
|
||||||
{ // ValueMap must be destroyed before function verified!
|
{ // ValueMap must be destroyed before function verified!
|
||||||
|
|||||||
@@ -829,7 +829,7 @@ Instruction *InstCombiner::visitRem(BinaryOperator &I) {
|
|||||||
if (I.getType()->isSigned())
|
if (I.getType()->isSigned())
|
||||||
if (Value *RHSNeg = dyn_castNegVal(I.getOperand(1)))
|
if (Value *RHSNeg = dyn_castNegVal(I.getOperand(1)))
|
||||||
if (!isa<ConstantSInt>(RHSNeg) ||
|
if (!isa<ConstantSInt>(RHSNeg) ||
|
||||||
cast<ConstantSInt>(RHSNeg)->getValue() >= 0) {
|
cast<ConstantSInt>(RHSNeg)->getValue() > 0) {
|
||||||
// X % -Y -> X % Y
|
// X % -Y -> X % Y
|
||||||
AddUsesToWorkList(I);
|
AddUsesToWorkList(I);
|
||||||
I.setOperand(1, RHSNeg);
|
I.setOperand(1, RHSNeg);
|
||||||
@@ -1392,34 +1392,33 @@ Instruction *InstCombiner::visitSetCondInst(BinaryOperator &I) {
|
|||||||
|
|
||||||
// setcc's with boolean values can always be turned into bitwise operations
|
// setcc's with boolean values can always be turned into bitwise operations
|
||||||
if (Ty == Type::BoolTy) {
|
if (Ty == Type::BoolTy) {
|
||||||
// If this is <, >, or !=, we can change this into a simple xor instruction
|
switch (I.getOpcode()) {
|
||||||
if (!isTrueWhenEqual(I))
|
default: assert(0 && "Invalid setcc instruction!");
|
||||||
return BinaryOperator::createXor(Op0, Op1);
|
case Instruction::SetEQ: { // seteq bool %A, %B -> ~(A^B)
|
||||||
|
|
||||||
// Otherwise we need to make a temporary intermediate instruction and insert
|
|
||||||
// it into the instruction stream. This is what we are after:
|
|
||||||
//
|
|
||||||
// seteq bool %A, %B -> ~(A^B)
|
|
||||||
// setle bool %A, %B -> ~A | B
|
|
||||||
// setge bool %A, %B -> A | ~B
|
|
||||||
//
|
|
||||||
if (I.getOpcode() == Instruction::SetEQ) { // seteq case
|
|
||||||
Instruction *Xor = BinaryOperator::createXor(Op0, Op1, I.getName()+"tmp");
|
Instruction *Xor = BinaryOperator::createXor(Op0, Op1, I.getName()+"tmp");
|
||||||
InsertNewInstBefore(Xor, I);
|
InsertNewInstBefore(Xor, I);
|
||||||
return BinaryOperator::createNot(Xor);
|
return BinaryOperator::createNot(Xor);
|
||||||
}
|
}
|
||||||
|
case Instruction::SetNE:
|
||||||
|
return BinaryOperator::createXor(Op0, Op1);
|
||||||
|
|
||||||
// Handle the setXe cases...
|
case Instruction::SetGT:
|
||||||
assert(I.getOpcode() == Instruction::SetGE ||
|
std::swap(Op0, Op1); // Change setgt -> setlt
|
||||||
I.getOpcode() == Instruction::SetLE);
|
// FALL THROUGH
|
||||||
|
case Instruction::SetLT: { // setlt bool A, B -> ~X & Y
|
||||||
if (I.getOpcode() == Instruction::SetGE)
|
Instruction *Not = BinaryOperator::createNot(Op0, I.getName()+"tmp");
|
||||||
|
InsertNewInstBefore(Not, I);
|
||||||
|
return BinaryOperator::createAnd(Not, Op1);
|
||||||
|
}
|
||||||
|
case Instruction::SetGE:
|
||||||
std::swap(Op0, Op1); // Change setge -> setle
|
std::swap(Op0, Op1); // Change setge -> setle
|
||||||
|
// FALL THROUGH
|
||||||
// Now we just have the SetLE case.
|
case Instruction::SetLE: { // setle bool %A, %B -> ~A | B
|
||||||
Instruction *Not = BinaryOperator::createNot(Op0, I.getName()+"tmp");
|
Instruction *Not = BinaryOperator::createNot(Op0, I.getName()+"tmp");
|
||||||
InsertNewInstBefore(Not, I);
|
InsertNewInstBefore(Not, I);
|
||||||
return BinaryOperator::createOr(Not, Op1);
|
return BinaryOperator::createOr(Not, Op1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// See if we are doing a comparison between a constant and an instruction that
|
// See if we are doing a comparison between a constant and an instruction that
|
||||||
|
|||||||
@@ -513,21 +513,24 @@ emitCallAndSwitchStatement(Function *newFunction, BasicBlock *codeReplacer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now that we've done the deed, simplify the switch instruction.
|
// Now that we've done the deed, simplify the switch instruction.
|
||||||
|
const Type *OldFnRetTy = TheSwitch->getParent()->getParent()->getReturnType();
|
||||||
switch (NumExitBlocks) {
|
switch (NumExitBlocks) {
|
||||||
case 0:
|
case 0:
|
||||||
// There is only 1 successor (the block containing the switch itself), which
|
// There are no successors (the block containing the switch itself), which
|
||||||
// means that previously this was the last part of the function, and hence
|
// means that previously this was the last part of the function, and hence
|
||||||
// this should be rewritten as a `ret'
|
// this should be rewritten as a `ret'
|
||||||
|
|
||||||
// Check if the function should return a value
|
// Check if the function should return a value
|
||||||
if (TheSwitch->getParent()->getParent()->getReturnType() != Type::VoidTy &&
|
if (OldFnRetTy == Type::VoidTy) {
|
||||||
TheSwitch->getParent()->getParent()->getReturnType() ==
|
new ReturnInst(0, TheSwitch); // Return void
|
||||||
TheSwitch->getCondition()->getType())
|
} else if (OldFnRetTy == TheSwitch->getCondition()->getType()) {
|
||||||
// return what we have
|
// return what we have
|
||||||
new ReturnInst(TheSwitch->getCondition(), TheSwitch);
|
new ReturnInst(TheSwitch->getCondition(), TheSwitch);
|
||||||
else
|
} else {
|
||||||
// just return
|
// Otherwise we must have code extracted an unwind or something, just
|
||||||
new ReturnInst(0, TheSwitch);
|
// return whatever we want.
|
||||||
|
new ReturnInst(Constant::getNullValue(OldFnRetTy), TheSwitch);
|
||||||
|
}
|
||||||
|
|
||||||
TheSwitch->getParent()->getInstList().erase(TheSwitch);
|
TheSwitch->getParent()->getInstList().erase(TheSwitch);
|
||||||
break;
|
break;
|
||||||
@@ -583,8 +586,8 @@ void CodeExtractor::moveCodeToFunction(Function *newFunction) {
|
|||||||
/// for each scalar output in the function: at every exit, store intermediate
|
/// for each scalar output in the function: at every exit, store intermediate
|
||||||
/// computed result back into memory.
|
/// computed result back into memory.
|
||||||
///
|
///
|
||||||
Function *CodeExtractor::ExtractCodeRegion(const std::vector<BasicBlock*> &code)
|
Function *CodeExtractor::
|
||||||
{
|
ExtractCodeRegion(const std::vector<BasicBlock*> &code) {
|
||||||
if (!isEligible(code))
|
if (!isEligible(code))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -619,7 +622,7 @@ Function *CodeExtractor::ExtractCodeRegion(const std::vector<BasicBlock*> &code)
|
|||||||
Function *oldFunction = header->getParent();
|
Function *oldFunction = header->getParent();
|
||||||
|
|
||||||
// This takes place of the original loop
|
// This takes place of the original loop
|
||||||
BasicBlock *codeReplacer = new BasicBlock("codeRepl", oldFunction);
|
BasicBlock *codeReplacer = new BasicBlock("codeRepl", oldFunction, header);
|
||||||
|
|
||||||
// The new function needs a root node because other nodes can branch to the
|
// The new function needs a root node because other nodes can branch to the
|
||||||
// head of the region, but the entry node of a function cannot have preds.
|
// head of the region, but the entry node of a function cannot have preds.
|
||||||
@@ -654,10 +657,19 @@ Function *CodeExtractor::ExtractCodeRegion(const std::vector<BasicBlock*> &code)
|
|||||||
succ_end(codeReplacer));
|
succ_end(codeReplacer));
|
||||||
for (unsigned i = 0, e = Succs.size(); i != e; ++i)
|
for (unsigned i = 0, e = Succs.size(); i != e; ++i)
|
||||||
for (BasicBlock::iterator I = Succs[i]->begin();
|
for (BasicBlock::iterator I = Succs[i]->begin();
|
||||||
PHINode *PN = dyn_cast<PHINode>(I); ++I)
|
PHINode *PN = dyn_cast<PHINode>(I); ++I) {
|
||||||
|
std::set<BasicBlock*> ProcessedPreds;
|
||||||
for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i)
|
for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i)
|
||||||
if (BlocksToExtract.count(PN->getIncomingBlock(i)))
|
if (BlocksToExtract.count(PN->getIncomingBlock(i)))
|
||||||
PN->setIncomingBlock(i, codeReplacer);
|
if (ProcessedPreds.insert(PN->getIncomingBlock(i)).second)
|
||||||
|
PN->setIncomingBlock(i, codeReplacer);
|
||||||
|
else {
|
||||||
|
// There were multiple entries in the PHI for this block, now there
|
||||||
|
// is only one, so remove the duplicated entries.
|
||||||
|
PN->removeIncomingValue(i, false);
|
||||||
|
--i; --e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//std::cerr << "NEW FUNCTION: " << *newFunction;
|
//std::cerr << "NEW FUNCTION: " << *newFunction;
|
||||||
// verifyFunction(*newFunction);
|
// verifyFunction(*newFunction);
|
||||||
|
|||||||
@@ -81,6 +81,11 @@ Value *llvm::MapValue(const Value *V, std::map<const Value*, Value*> &VM) {
|
|||||||
for (unsigned i = 1, e = CE->getNumOperands(); i != e; ++i)
|
for (unsigned i = 1, e = CE->getNumOperands(); i != e; ++i)
|
||||||
Idx.push_back(cast<Constant>(MapValue(CE->getOperand(i), VM)));
|
Idx.push_back(cast<Constant>(MapValue(CE->getOperand(i), VM)));
|
||||||
return VMSlot = ConstantExpr::getGetElementPtr(MV, Idx);
|
return VMSlot = ConstantExpr::getGetElementPtr(MV, Idx);
|
||||||
|
} else if (CE->getOpcode() == Instruction::Select) {
|
||||||
|
Constant *MV1 = cast<Constant>(MapValue(CE->getOperand(0), VM));
|
||||||
|
Constant *MV2 = cast<Constant>(MapValue(CE->getOperand(1), VM));
|
||||||
|
Constant *MV3 = cast<Constant>(MapValue(CE->getOperand(2), VM));
|
||||||
|
return VMSlot = ConstantExpr::getSelect(MV1, MV2, MV3);
|
||||||
} else {
|
} else {
|
||||||
assert(CE->getNumOperands() == 2 && "Must be binary operator?");
|
assert(CE->getNumOperands() == 2 && "Must be binary operator?");
|
||||||
Constant *MV1 = cast<Constant>(MapValue(CE->getOperand(0), VM));
|
Constant *MV1 = cast<Constant>(MapValue(CE->getOperand(0), VM));
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
Summary: Static and JIT research compiler infrastructure
|
Summary: Static and JIT research compiler infrastructure
|
||||||
Name: llvm
|
Name: llvm
|
||||||
Version: 1.2
|
Version: 1.3
|
||||||
Release: 0
|
Release: 0
|
||||||
License: U of Illinois/NCSA Open Source License
|
License: U of Illinois/NCSA Open Source License
|
||||||
Group: Development/Languages
|
Group: Development/Languages
|
||||||
|
|||||||
17
llvm/test/Regression/CFrontend/2004-08-06-LargeStructTest.c
Normal file
17
llvm/test/Regression/CFrontend/2004-08-06-LargeStructTest.c
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
#define A(X) int X;
|
||||||
|
#define B(X) A(X##0) A(X##1) A(X##2) A(X##3) A(X##4) A(X##5) A(X##6) A(X##7) \
|
||||||
|
A(X##8) A(X##9) A(X##A) A(X##B) A(X##C) A(X##D) A(X##E) A(X##F)
|
||||||
|
#define C(X) B(X##0) B(X##1) B(X##2) B(X##3) B(X##4) B(X##5) B(X##6) B(X##7) \
|
||||||
|
B(X##8) B(X##9) B(X##A) B(X##B) B(X##C) B(X##D) B(X##E) B(X##F)
|
||||||
|
|
||||||
|
struct foo {
|
||||||
|
C(x); // 256
|
||||||
|
C(y); // 256
|
||||||
|
C(z);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int test(struct foo *F) {
|
||||||
|
return F->xA1 + F->yFF + F->zC4;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
declare void %llvm.va_end(sbyte*)
|
||||||
|
|
||||||
|
void %test() {
|
||||||
|
call void %llvm.va_end( sbyte* null )
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
; RUN: llvm-as < %s | opt -instcombine
|
||||||
|
|
||||||
|
; This testcase should not send the instcombiner into an infinite loop!
|
||||||
|
|
||||||
|
int %test(int %X) {
|
||||||
|
%Y = rem int %X, 0
|
||||||
|
ret int %Y
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
; RUN: llvm-as < %s| opt -instcombine | llvm-dis | grep 'ret bool false'
|
||||||
|
bool %test(bool %V) {
|
||||||
|
%Y = setlt bool %V, false
|
||||||
|
ret bool %Y
|
||||||
|
}
|
||||||
|
|
||||||
49
llvm/utils/mkrel.sh
Executable file
49
llvm/utils/mkrel.sh
Executable file
@@ -0,0 +1,49 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# Shell Script: mkrel
|
||||||
|
#
|
||||||
|
# Description:
|
||||||
|
# Make LLVM Release source tarballs by grabbing the source from the CVS
|
||||||
|
# repository.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# mkrel <version> <release tag> <dir>
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Constants
|
||||||
|
#
|
||||||
|
cvsroot=":pserver:anon@llvm-cvs.cs.uiuc.edu:/var/cvs/llvm"
|
||||||
|
|
||||||
|
#
|
||||||
|
# Save the command line arguments into some variables.
|
||||||
|
#
|
||||||
|
version=$1
|
||||||
|
tag=$2
|
||||||
|
dir=$3
|
||||||
|
|
||||||
|
#
|
||||||
|
# Create the working directory and make it the current directory.
|
||||||
|
#
|
||||||
|
mkdir -p $dir
|
||||||
|
echo "Changing directory to $dir"
|
||||||
|
cd $dir
|
||||||
|
|
||||||
|
#
|
||||||
|
# Extract the LLVM sources given the label.
|
||||||
|
#
|
||||||
|
echo "Extracting source $tag from $cvsroot"
|
||||||
|
cvs -d $cvsroot export -r $tag llvm llvm-gcc
|
||||||
|
|
||||||
|
#
|
||||||
|
# Move the llvm-gcc sources so that they match what is used by end-users.
|
||||||
|
#
|
||||||
|
mkdir -p cfrontend
|
||||||
|
mv llvm-gcc cfrontend/src
|
||||||
|
|
||||||
|
#
|
||||||
|
# Create source tarballs.
|
||||||
|
#
|
||||||
|
tar -cf - llvm | gzip > llvm-${version}.tar.gz
|
||||||
|
tar -cf - cfrontend | gzip > cfrontend-${version}.source.tar.gz
|
||||||
Reference in New Issue
Block a user