Compare commits

...

24 Commits

Author SHA1 Message Date
John Criswell
32e813e486 Merged from mainline.
llvm-svn: 15723
2004-08-13 18:52:00 +00:00
John Criswell
b6a9b36e21 Setup the llvm-gcc tarball the way we have always done.
llvm-svn: 15687
2004-08-12 14:34:38 +00:00
John Criswell
0fe9bd9e6d Merged from mainline.
llvm-svn: 15686
2004-08-12 14:28:44 +00:00
John Criswell
322e13176f Merged from mainline. This should fix 176.gcc.
llvm-svn: 15685
2004-08-12 14:20:45 +00:00
John Criswell
ab686a51f1 Updated code sizes for LLVM.
llvm-svn: 15666
2004-08-11 19:48:12 +00:00
John Criswell
f2a68db009 Adding 2004-08-10-BoolSetCC.ll (written by Chris) as a new regression test.
Merged from mainline.

llvm-svn: 15641
2004-08-11 01:28:05 +00:00
John Criswell
ef095995c7 Merged in revision 1.239 from mainline.
llvm-svn: 15640
2004-08-11 01:23:22 +00:00
CVS to SVN Conversion
841e6949d7 This commit was manufactured by cvs2svn to create branch 'release_13'.
llvm-svn: 15638
2004-08-11 00:49:50 +00:00
John Criswell
a98c3d19a5 Merged from mainline on August 10, 2004.
llvm-svn: 15619
2004-08-10 18:33:39 +00:00
CVS to SVN Conversion
10b4a6323f This commit was manufactured by cvs2svn to create branch 'release_13'.
llvm-svn: 15618
2004-08-10 18:33:39 +00:00
John Criswell
7d4bacd1af Merged in mainline.
llvm-svn: 15617
2004-08-10 18:32:06 +00:00
John Criswell
f0958ae6eb Merged in changes to the instruction combining pass.
llvm-svn: 15598
2004-08-09 21:34:34 +00:00
John Criswell
7ee0099de5 Merged in new regression test.
llvm-svn: 15597
2004-08-09 21:33:52 +00:00
CVS to SVN Conversion
7aa6c01be2 This commit was manufactured by cvs2svn to create branch 'release_13'.
llvm-svn: 15596
2004-08-09 21:33:52 +00:00
John Criswell
1e34901d4d Fix capitalization of URL.
llvm-svn: 15595
2004-08-09 21:17:16 +00:00
John Criswell
362f4b3e5d Updated release notes from mainline.
llvm-svn: 15594
2004-08-09 21:15:20 +00:00
John Criswell
67dee05f54 Merged in changes Chris commited over the weekend. Merge done on August 9,
2004.

llvm-svn: 15576
2004-08-09 15:35:51 +00:00
John Criswell
0ccbe35d71 Added note about new PowerPC code generator.
Updated versions to 1.3.

llvm-svn: 15560
2004-08-06 21:26:30 +00:00
John Criswell
7f6d3e7317 Fixed the link to the Command Guide. The previous revision only worked
if the browser is getting the file from a web server that autocompletes
the URL.

llvm-svn: 15559
2004-08-06 21:12:44 +00:00
John Criswell
fb63a35c3c Created script to help automate part of the release process.
llvm-svn: 15558
2004-08-06 21:03:59 +00:00
John Criswell
6dbb267760 Merge in test for structures with more than 256 members, courtesy of Chris.
llvm-svn: 15557
2004-08-06 19:57:05 +00:00
CVS to SVN Conversion
50fe9297ba This commit was manufactured by cvs2svn to create branch 'release_13'.
llvm-svn: 15556
2004-08-06 19:57:05 +00:00
John Criswell
395900dcf5 Updated version.
llvm-svn: 15549
2004-08-06 16:21:48 +00:00
CVS to SVN Conversion
a27fe0174c This commit was manufactured by cvs2svn to create branch 'release_13'.
llvm-svn: 15548
2004-08-06 16:21:48 +00:00
40 changed files with 257 additions and 7337 deletions

View File

@@ -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>

View File

@@ -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

View File

@@ -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>

View File

@@ -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;";

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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$

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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">;

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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]>;

View File

@@ -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));
}

View File

@@ -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

View File

@@ -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:

View File

@@ -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 {

View File

@@ -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

View File

@@ -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);
} }
} }

View File

@@ -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!

View File

@@ -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

View File

@@ -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);

View File

@@ -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));

View File

@@ -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

View 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;
}

View File

@@ -0,0 +1,7 @@
declare void %llvm.va_end(sbyte*)
void %test() {
call void %llvm.va_end( sbyte* null )
ret void
}

View File

@@ -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
}

View File

@@ -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
View 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