mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-02-27 02:31:09 +00:00
Initial revision
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@14283 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
31b24322ed
commit
5dfe3a9c3b
55
lib/Target/PowerPC/Makefile
Normal file
55
lib/Target/PowerPC/Makefile
Normal file
@ -0,0 +1,55 @@
|
||||
##===- lib/Target/PowerPC/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 = powerpc
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
||||
# Make sure that tblgen is run, first thing.
|
||||
$(SourceDepend): PowerPCGenRegisterInfo.h.inc PowerPCGenRegisterNames.inc \
|
||||
PowerPCGenRegisterInfo.inc PowerPCGenInstrNames.inc \
|
||||
PowerPCGenInstrInfo.inc PowerPCGenInstrSelector.inc
|
||||
|
||||
PowerPCGenRegisterNames.inc:: $(SourceDir)/PowerPC.td \
|
||||
$(SourceDir)/PowerPCReg.td \
|
||||
$(SourceDir)/../Target.td $(TBLGEN)
|
||||
@echo "Building PowerPC.td register names with tblgen"
|
||||
$(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $< -gen-register-enums -o $@
|
||||
|
||||
PowerPCGenRegisterInfo.h.inc:: $(SourceDir)/PowerPC.td \
|
||||
$(SourceDir)/PowerPCReg.td \
|
||||
$(SourceDir)/../Target.td $(TBLGEN)
|
||||
@echo "Building PowerPC.td register information header with tblgen"
|
||||
$(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $< -gen-register-desc-header -o $@
|
||||
|
||||
PowerPCGenRegisterInfo.inc:: $(SourceDir)/PowerPC.td \
|
||||
$(SourceDir)/PowerPCReg.td \
|
||||
$(SourceDir)/../Target.td $(TBLGEN)
|
||||
@echo "Building PowerPC.td register information implementation with tblgen"
|
||||
$(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $< -gen-register-desc -o $@
|
||||
|
||||
PowerPCGenInstrNames.inc:: $(SourceDir)/PowerPC.td \
|
||||
$(SourceDir)/PowerPCInstrs.td \
|
||||
$(SourceDir)/../Target.td $(TBLGEN)
|
||||
@echo "Building PowerPC.td instruction names with tblgen"
|
||||
$(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $< -gen-instr-enums -o $@
|
||||
|
||||
PowerPCGenInstrInfo.inc:: $(SourceDir)/PowerPC.td \
|
||||
$(SourceDir)/PowerPCInstrs.td \
|
||||
$(SourceDir)/../Target.td $(TBLGEN)
|
||||
@echo "Building PowerPC.td instruction information with tblgen"
|
||||
$(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $< -gen-instr-desc -o $@
|
||||
|
||||
PowerPCGenInstrSelector.inc:: $(SourceDir)/PowerPC.td \
|
||||
$(SourceDir)/PowerPCInstrs.td \
|
||||
$(SourceDir)/../Target.td $(TBLGEN)
|
||||
@echo "Building PowerPC.td instruction selector with tblgen"
|
||||
$(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $< -gen-instr-selector -o $@
|
||||
|
||||
clean::
|
||||
$(VERB) rm -f *.inc
|
40
lib/Target/PowerPC/PPC.h
Normal file
40
lib/Target/PowerPC/PPC.h
Normal file
@ -0,0 +1,40 @@
|
||||
//===-- PowerPC.h - Top-level interface for PowerPC 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
|
||||
// PowerPC back-end.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef TARGET_POWERPC_H
|
||||
#define TARGET_POWERPC_H
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class FunctionPass;
|
||||
class TargetMachine;
|
||||
|
||||
// Here is where you would define factory methods for powerpc-specific
|
||||
// passes. For example:
|
||||
FunctionPass *createPPCSimpleInstructionSelector (TargetMachine &TM);
|
||||
FunctionPass *createPPCCodePrinterPass(std::ostream &OS, TargetMachine &TM);
|
||||
} // end namespace llvm;
|
||||
|
||||
// Defines symbolic names for PowerPC registers. This defines a mapping from
|
||||
// register name to register number.
|
||||
//
|
||||
#include "PowerPCGenRegisterNames.inc"
|
||||
|
||||
// Defines symbolic names for the PowerPC instructions.
|
||||
//
|
||||
#include "PowerPCGenInstrNames.inc"
|
||||
|
||||
#endif
|
694
lib/Target/PowerPC/PPC32AsmPrinter.cpp
Normal file
694
lib/Target/PowerPC/PPC32AsmPrinter.cpp
Normal file
@ -0,0 +1,694 @@
|
||||
//===-- PPC32/Printer.cpp - Convert X86 LLVM code to Intel 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 Intel-format
|
||||
// assembly language. This printer is the output mechanism used
|
||||
// by `llc' and `lli -print-machineinstrs' on X86.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "PowerPC.h"
|
||||
#include "PowerPCInstrInfo.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"
|
||||
|
||||
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.
|
||||
///
|
||||
TargetMachine &TM;
|
||||
|
||||
/// Name-mangler for global names.
|
||||
///
|
||||
Mangler *Mang;
|
||||
std::set< std::string > Stubs;
|
||||
std::set<std::string> Strings;
|
||||
|
||||
Printer(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 "PowerPC Assembly Printer";
|
||||
}
|
||||
|
||||
void printMachineInstruction(const MachineInstr *MI);
|
||||
void printOp(const MachineOperand &MO,
|
||||
bool elideOffsetKeyword = false);
|
||||
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 X86
|
||||
/// 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 ConstantPointerRef *CPR = dyn_cast<ConstantPointerRef>(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(CPR->getValue());
|
||||
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 (CV->isNullValue()) {
|
||||
O << "\t.space\t " << TD.getTypeSize(CV->getType()) << "\n";
|
||||
return;
|
||||
} else if (const ConstantArray *CVA = dyn_cast<ConstantArray>(CV)) {
|
||||
if (isStringCompatible(CVA)) {
|
||||
O << ".ascii";
|
||||
printAsCString(O, CVA);
|
||||
O << "\n";
|
||||
} else { // Not a string. Print the values in successive locations
|
||||
const std::vector<Use> &constValues = CVA->getValues();
|
||||
for (unsigned i=0; i < constValues.size(); i++)
|
||||
emitGlobalConstant(cast<Constant>(constValues[i].get()));
|
||||
}
|
||||
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());
|
||||
const std::vector<Use>& constValues = CVS->getValues();
|
||||
unsigned sizeSoFar = 0;
|
||||
for (unsigned i=0, N = constValues.size(); i < N; i++) {
|
||||
const Constant* field = cast<Constant>(constValues[i].get());
|
||||
|
||||
// Check if padding is needed and insert one or more 0s.
|
||||
unsigned fieldSize = TD.getTypeSize(field->getType());
|
||||
unsigned padSize = ((i == N-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()->getPrimitiveID()) {
|
||||
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()->getPrimitiveSize() == 64) {
|
||||
const ConstantInt *CI = dyn_cast<ConstantInt>(CV);
|
||||
if(CI) {
|
||||
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->getPrimitiveID()) {
|
||||
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:
|
||||
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 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) {
|
||||
// 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.globl\t" << CurrentFnName << "\n";
|
||||
O << "\t.align 5\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 << "L" << NumberForBB[I->getBasicBlock()] << ":\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 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:
|
||||
O << RI.get(MO.getReg()).Name;
|
||||
return;
|
||||
|
||||
case MachineOperand::MO_SignExtendedImmed:
|
||||
case MachineOperand::MO_UnextendedImmed:
|
||||
O << (int)MO.getImmedValue();
|
||||
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_PCRelativeDisp:
|
||||
std::cerr << "Shouldn't use addPCDisp() when building PPC MachineInstrs";
|
||||
abort ();
|
||||
return;
|
||||
case MachineOperand::MO_GlobalAddress:
|
||||
if (!elideOffsetKeyword) {
|
||||
if(isa<Function>(MO.getGlobal())) {
|
||||
Stubs.insert(Mang->getValueName(MO.getGlobal()));
|
||||
O << "L" << Mang->getValueName(MO.getGlobal()) << "$stub";
|
||||
} else {
|
||||
O << Mang->getValueName(MO.getGlobal());
|
||||
}
|
||||
}
|
||||
return;
|
||||
case MachineOperand::MO_ExternalSymbol:
|
||||
O << MO.getSymbolName();
|
||||
return;
|
||||
default:
|
||||
O << "<unknown operand type>"; return;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static inline
|
||||
unsigned int ValidOpcodes(const MachineInstr *MI, unsigned int ArgType[5]) {
|
||||
int i;
|
||||
unsigned int retval = 1;
|
||||
|
||||
for(i = 0; i<5; i++) {
|
||||
switch(ArgType[i]) {
|
||||
case none:
|
||||
break;
|
||||
case Gpr:
|
||||
case Gpr0:
|
||||
Type::UIntTy
|
||||
case Simm16:
|
||||
case Zimm16:
|
||||
case PCRelimm24:
|
||||
case Imm24:
|
||||
case Imm5:
|
||||
case PCRelimm14:
|
||||
case Imm14:
|
||||
case Imm2:
|
||||
case Crf:
|
||||
case Imm3:
|
||||
case Imm1:
|
||||
case Fpr:
|
||||
case Imm4:
|
||||
case Imm8:
|
||||
case Disimm16:
|
||||
case Spr:
|
||||
case Sgr:
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// 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 int i;
|
||||
|
||||
unsigned int ArgCount = Desc.TSFlags & PPC32II::ArgCountMask;
|
||||
unsigned int ArgType[5];
|
||||
|
||||
|
||||
ArgType[0] = (Desc.TSFlags>>PPC32II::Arg0TypeShift) & PPC32II::ArgTypeMask;
|
||||
ArgType[1] = (Desc.TSFlags>>PPC32II::Arg1TypeShift) & PPC32II::ArgTypeMask;
|
||||
ArgType[2] = (Desc.TSFlags>>PPC32II::Arg2TypeShift) & PPC32II::ArgTypeMask;
|
||||
ArgType[3] = (Desc.TSFlags>>PPC32II::Arg3TypeShift) & PPC32II::ArgTypeMask;
|
||||
ArgType[4] = (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");
|
||||
//assert ( ValidOpcodes(MI, ArgType) && "Instruction has invalid inputs");
|
||||
++EmittedInsts;
|
||||
|
||||
if(Opcode == PPC32::MovePCtoLR) {
|
||||
O << "mflr r0\n";
|
||||
O << "bcl 20,31,L" << CurrentFnName << "$pb\n";
|
||||
O << "L" << CurrentFnName << "$pb:\n";
|
||||
return;
|
||||
}
|
||||
|
||||
O << TII.getName(MI->getOpcode()) << " ";
|
||||
std::cout << TII.getName(MI->getOpcode()) << " expects " << ArgCount << " args\n";
|
||||
|
||||
if(Opcode == PPC32::LOADLoAddr) {
|
||||
printOp(MI->getOperand(0));
|
||||
O << ", ";
|
||||
printOp(MI->getOperand(1));
|
||||
O << ", lo16(";
|
||||
printOp(MI->getOperand(2));
|
||||
O << "-L" << CurrentFnName << "$pb)\n";
|
||||
return;
|
||||
}
|
||||
|
||||
if(Opcode == PPC32::LOADHiAddr) {
|
||||
printOp(MI->getOperand(0));
|
||||
O << ", ";
|
||||
printOp(MI->getOperand(1));
|
||||
O << ", ha16(" ;
|
||||
printOp(MI->getOperand(2));
|
||||
O << "-L" << CurrentFnName << "$pb)\n";
|
||||
return;
|
||||
}
|
||||
|
||||
if( (ArgCount == 3) && (ArgType[1] == PPC32II::Disimm16) ) {
|
||||
printOp(MI->getOperand(0));
|
||||
O << ", ";
|
||||
printOp(MI->getOperand(1));
|
||||
O << "(";
|
||||
if((ArgType[2] == PPC32II::Gpr0) && (MI->getOperand(2).getReg() == PPC32::R0)) {
|
||||
O << "0";
|
||||
} else {
|
||||
printOp(MI->getOperand(2));
|
||||
}
|
||||
O << ")\n";
|
||||
} else {
|
||||
for(i = 0; i< ArgCount; i++) {
|
||||
if( (ArgType[i] == PPC32II::Gpr0) && ((MI->getOperand(i).getReg()) == PPC32::R0)) {
|
||||
O << "0";
|
||||
} else {
|
||||
//std::cout << "DEBUG " << (*(TM.getRegisterInfo())).get(MI->getOperand(i).getReg()).Name << "\n";
|
||||
printOp(MI->getOperand(i));
|
||||
}
|
||||
if( ArgCount - 1 == i) {
|
||||
O << "\n";
|
||||
} else {
|
||||
O << ", ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool Printer::doInitialization(Module &M) {
|
||||
// Tell gas we are outputting Intel syntax (not AT&T syntax) assembly.
|
||||
//
|
||||
// Bug: gas in `intel_syntax noprefix' mode interprets the symbol `Sp' in an
|
||||
// instruction as a reference to the register named sp, and if you try to
|
||||
// reference a symbol `Sp' (e.g. `mov ECX, OFFSET Sp') then it gets lowercased
|
||||
// before being looked up in the symbol table. This creates spurious
|
||||
// `undefined symbol' errors when linking. Workaround: Do not use `noprefix'
|
||||
// mode, and decorate all register names with percent signs.
|
||||
// O << "\t.intel_syntax\n";
|
||||
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() &&
|
||||
(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 << name << ":\t\t\t\t# ";
|
||||
WriteAsOperand(O, I, true, true, &M);
|
||||
O << " = ";
|
||||
WriteAsOperand(O, C, false, false, &M);
|
||||
O << "\n";
|
||||
emitGlobalConstant(C);
|
||||
}
|
||||
}
|
||||
|
||||
for(std::set<std::string>::iterator i = Stubs.begin(); i != Stubs.end(); ++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 << ".indirect_symbol " << *i << "\n";
|
||||
O << ".long dyld_stub_binding_helper\n";
|
||||
|
||||
}
|
||||
|
||||
delete Mang;
|
||||
return false; // success
|
||||
}
|
||||
|
||||
} // End llvm namespace
|
2621
lib/Target/PowerPC/PPC32ISelSimple.cpp
Normal file
2621
lib/Target/PowerPC/PPC32ISelSimple.cpp
Normal file
File diff suppressed because it is too large
Load Diff
694
lib/Target/PowerPC/PPCAsmPrinter.cpp
Normal file
694
lib/Target/PowerPC/PPCAsmPrinter.cpp
Normal file
@ -0,0 +1,694 @@
|
||||
//===-- PPC32/Printer.cpp - Convert X86 LLVM code to Intel 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 Intel-format
|
||||
// assembly language. This printer is the output mechanism used
|
||||
// by `llc' and `lli -print-machineinstrs' on X86.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "PowerPC.h"
|
||||
#include "PowerPCInstrInfo.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"
|
||||
|
||||
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.
|
||||
///
|
||||
TargetMachine &TM;
|
||||
|
||||
/// Name-mangler for global names.
|
||||
///
|
||||
Mangler *Mang;
|
||||
std::set< std::string > Stubs;
|
||||
std::set<std::string> Strings;
|
||||
|
||||
Printer(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 "PowerPC Assembly Printer";
|
||||
}
|
||||
|
||||
void printMachineInstruction(const MachineInstr *MI);
|
||||
void printOp(const MachineOperand &MO,
|
||||
bool elideOffsetKeyword = false);
|
||||
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 X86
|
||||
/// 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 ConstantPointerRef *CPR = dyn_cast<ConstantPointerRef>(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(CPR->getValue());
|
||||
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 (CV->isNullValue()) {
|
||||
O << "\t.space\t " << TD.getTypeSize(CV->getType()) << "\n";
|
||||
return;
|
||||
} else if (const ConstantArray *CVA = dyn_cast<ConstantArray>(CV)) {
|
||||
if (isStringCompatible(CVA)) {
|
||||
O << ".ascii";
|
||||
printAsCString(O, CVA);
|
||||
O << "\n";
|
||||
} else { // Not a string. Print the values in successive locations
|
||||
const std::vector<Use> &constValues = CVA->getValues();
|
||||
for (unsigned i=0; i < constValues.size(); i++)
|
||||
emitGlobalConstant(cast<Constant>(constValues[i].get()));
|
||||
}
|
||||
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());
|
||||
const std::vector<Use>& constValues = CVS->getValues();
|
||||
unsigned sizeSoFar = 0;
|
||||
for (unsigned i=0, N = constValues.size(); i < N; i++) {
|
||||
const Constant* field = cast<Constant>(constValues[i].get());
|
||||
|
||||
// Check if padding is needed and insert one or more 0s.
|
||||
unsigned fieldSize = TD.getTypeSize(field->getType());
|
||||
unsigned padSize = ((i == N-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()->getPrimitiveID()) {
|
||||
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()->getPrimitiveSize() == 64) {
|
||||
const ConstantInt *CI = dyn_cast<ConstantInt>(CV);
|
||||
if(CI) {
|
||||
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->getPrimitiveID()) {
|
||||
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:
|
||||
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 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) {
|
||||
// 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.globl\t" << CurrentFnName << "\n";
|
||||
O << "\t.align 5\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 << "L" << NumberForBB[I->getBasicBlock()] << ":\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 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:
|
||||
O << RI.get(MO.getReg()).Name;
|
||||
return;
|
||||
|
||||
case MachineOperand::MO_SignExtendedImmed:
|
||||
case MachineOperand::MO_UnextendedImmed:
|
||||
O << (int)MO.getImmedValue();
|
||||
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_PCRelativeDisp:
|
||||
std::cerr << "Shouldn't use addPCDisp() when building PPC MachineInstrs";
|
||||
abort ();
|
||||
return;
|
||||
case MachineOperand::MO_GlobalAddress:
|
||||
if (!elideOffsetKeyword) {
|
||||
if(isa<Function>(MO.getGlobal())) {
|
||||
Stubs.insert(Mang->getValueName(MO.getGlobal()));
|
||||
O << "L" << Mang->getValueName(MO.getGlobal()) << "$stub";
|
||||
} else {
|
||||
O << Mang->getValueName(MO.getGlobal());
|
||||
}
|
||||
}
|
||||
return;
|
||||
case MachineOperand::MO_ExternalSymbol:
|
||||
O << MO.getSymbolName();
|
||||
return;
|
||||
default:
|
||||
O << "<unknown operand type>"; return;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static inline
|
||||
unsigned int ValidOpcodes(const MachineInstr *MI, unsigned int ArgType[5]) {
|
||||
int i;
|
||||
unsigned int retval = 1;
|
||||
|
||||
for(i = 0; i<5; i++) {
|
||||
switch(ArgType[i]) {
|
||||
case none:
|
||||
break;
|
||||
case Gpr:
|
||||
case Gpr0:
|
||||
Type::UIntTy
|
||||
case Simm16:
|
||||
case Zimm16:
|
||||
case PCRelimm24:
|
||||
case Imm24:
|
||||
case Imm5:
|
||||
case PCRelimm14:
|
||||
case Imm14:
|
||||
case Imm2:
|
||||
case Crf:
|
||||
case Imm3:
|
||||
case Imm1:
|
||||
case Fpr:
|
||||
case Imm4:
|
||||
case Imm8:
|
||||
case Disimm16:
|
||||
case Spr:
|
||||
case Sgr:
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// 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 int i;
|
||||
|
||||
unsigned int ArgCount = Desc.TSFlags & PPC32II::ArgCountMask;
|
||||
unsigned int ArgType[5];
|
||||
|
||||
|
||||
ArgType[0] = (Desc.TSFlags>>PPC32II::Arg0TypeShift) & PPC32II::ArgTypeMask;
|
||||
ArgType[1] = (Desc.TSFlags>>PPC32II::Arg1TypeShift) & PPC32II::ArgTypeMask;
|
||||
ArgType[2] = (Desc.TSFlags>>PPC32II::Arg2TypeShift) & PPC32II::ArgTypeMask;
|
||||
ArgType[3] = (Desc.TSFlags>>PPC32II::Arg3TypeShift) & PPC32II::ArgTypeMask;
|
||||
ArgType[4] = (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");
|
||||
//assert ( ValidOpcodes(MI, ArgType) && "Instruction has invalid inputs");
|
||||
++EmittedInsts;
|
||||
|
||||
if(Opcode == PPC32::MovePCtoLR) {
|
||||
O << "mflr r0\n";
|
||||
O << "bcl 20,31,L" << CurrentFnName << "$pb\n";
|
||||
O << "L" << CurrentFnName << "$pb:\n";
|
||||
return;
|
||||
}
|
||||
|
||||
O << TII.getName(MI->getOpcode()) << " ";
|
||||
std::cout << TII.getName(MI->getOpcode()) << " expects " << ArgCount << " args\n";
|
||||
|
||||
if(Opcode == PPC32::LOADLoAddr) {
|
||||
printOp(MI->getOperand(0));
|
||||
O << ", ";
|
||||
printOp(MI->getOperand(1));
|
||||
O << ", lo16(";
|
||||
printOp(MI->getOperand(2));
|
||||
O << "-L" << CurrentFnName << "$pb)\n";
|
||||
return;
|
||||
}
|
||||
|
||||
if(Opcode == PPC32::LOADHiAddr) {
|
||||
printOp(MI->getOperand(0));
|
||||
O << ", ";
|
||||
printOp(MI->getOperand(1));
|
||||
O << ", ha16(" ;
|
||||
printOp(MI->getOperand(2));
|
||||
O << "-L" << CurrentFnName << "$pb)\n";
|
||||
return;
|
||||
}
|
||||
|
||||
if( (ArgCount == 3) && (ArgType[1] == PPC32II::Disimm16) ) {
|
||||
printOp(MI->getOperand(0));
|
||||
O << ", ";
|
||||
printOp(MI->getOperand(1));
|
||||
O << "(";
|
||||
if((ArgType[2] == PPC32II::Gpr0) && (MI->getOperand(2).getReg() == PPC32::R0)) {
|
||||
O << "0";
|
||||
} else {
|
||||
printOp(MI->getOperand(2));
|
||||
}
|
||||
O << ")\n";
|
||||
} else {
|
||||
for(i = 0; i< ArgCount; i++) {
|
||||
if( (ArgType[i] == PPC32II::Gpr0) && ((MI->getOperand(i).getReg()) == PPC32::R0)) {
|
||||
O << "0";
|
||||
} else {
|
||||
//std::cout << "DEBUG " << (*(TM.getRegisterInfo())).get(MI->getOperand(i).getReg()).Name << "\n";
|
||||
printOp(MI->getOperand(i));
|
||||
}
|
||||
if( ArgCount - 1 == i) {
|
||||
O << "\n";
|
||||
} else {
|
||||
O << ", ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool Printer::doInitialization(Module &M) {
|
||||
// Tell gas we are outputting Intel syntax (not AT&T syntax) assembly.
|
||||
//
|
||||
// Bug: gas in `intel_syntax noprefix' mode interprets the symbol `Sp' in an
|
||||
// instruction as a reference to the register named sp, and if you try to
|
||||
// reference a symbol `Sp' (e.g. `mov ECX, OFFSET Sp') then it gets lowercased
|
||||
// before being looked up in the symbol table. This creates spurious
|
||||
// `undefined symbol' errors when linking. Workaround: Do not use `noprefix'
|
||||
// mode, and decorate all register names with percent signs.
|
||||
// O << "\t.intel_syntax\n";
|
||||
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() &&
|
||||
(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 << name << ":\t\t\t\t# ";
|
||||
WriteAsOperand(O, I, true, true, &M);
|
||||
O << " = ";
|
||||
WriteAsOperand(O, C, false, false, &M);
|
||||
O << "\n";
|
||||
emitGlobalConstant(C);
|
||||
}
|
||||
}
|
||||
|
||||
for(std::set<std::string>::iterator i = Stubs.begin(); i != Stubs.end(); ++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 << ".indirect_symbol " << *i << "\n";
|
||||
O << ".long dyld_stub_binding_helper\n";
|
||||
|
||||
}
|
||||
|
||||
delete Mang;
|
||||
return false; // success
|
||||
}
|
||||
|
||||
} // End llvm namespace
|
43
lib/Target/PowerPC/PPCCodeEmitter.cpp
Normal file
43
lib/Target/PowerPC/PPCCodeEmitter.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
//===-- 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
|
||||
|
53
lib/Target/PowerPC/PPCInstrBuilder.h
Normal file
53
lib/Target/PowerPC/PPCInstrBuilder.h
Normal file
@ -0,0 +1,53 @@
|
||||
//===-- PowerPCInstrBuilder.h - Functions to aid building PPC insts -*- 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 exposes functions that may be used with BuildMI from the
|
||||
// MachineInstrBuilder.h file to simplify generating frame and constant pool
|
||||
// references.
|
||||
//
|
||||
// For reference, the order of operands for memory references is:
|
||||
// (Operand), Dest Reg, Base Reg, and either Reg Index or Immediate Displacement.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef PPCINSTRBUILDER_H
|
||||
#define PPCINSTRBUILDER_H
|
||||
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// addFrameReference - This function is used to add a reference to the base of
|
||||
/// an abstract object on the stack frame of the current function. This
|
||||
/// reference has base register as the FrameIndex offset until it is resolved.
|
||||
/// This allows a constant offset to be specified as well...
|
||||
///
|
||||
inline const MachineInstrBuilder &
|
||||
addFrameReference(const MachineInstrBuilder &MIB, int FI, int Offset = 0, bool mem = true) {
|
||||
if (mem)
|
||||
return MIB.addSImm(Offset).addFrameIndex(FI);
|
||||
else
|
||||
return MIB.addFrameIndex(FI).addSImm(Offset);
|
||||
}
|
||||
|
||||
/// addConstantPoolReference - This function is used to add a reference to the
|
||||
/// base of a constant value spilled to the per-function constant pool. The
|
||||
/// reference has base register ConstantPoolIndex offset which is retained until
|
||||
/// either machine code emission or assembly output. This allows an optional
|
||||
/// offset to be added as well.
|
||||
///
|
||||
inline const MachineInstrBuilder &
|
||||
addConstantPoolReference(const MachineInstrBuilder &MIB, unsigned CPI,
|
||||
int Offset = 0) {
|
||||
return MIB.addSImm(Offset).addConstantPoolIndex(CPI);
|
||||
}
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
2054
lib/Target/PowerPC/PPCInstrInfo.td
Normal file
2054
lib/Target/PowerPC/PPCInstrInfo.td
Normal file
File diff suppressed because it is too large
Load Diff
49
lib/Target/PowerPC/PPCJITInfo.h
Normal file
49
lib/Target/PowerPC/PPCJITInfo.h
Normal file
@ -0,0 +1,49 @@
|
||||
//===- PowerPCJITInfo.h - PowerPC 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 PowerPC implementation of the TargetJITInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef POWERPCJITINFO_H
|
||||
#define POWERPCJITINFO_H
|
||||
|
||||
#include "llvm/Target/TargetJITInfo.h"
|
||||
|
||||
namespace llvm {
|
||||
class TargetMachine;
|
||||
class IntrinsicLowering;
|
||||
|
||||
class PowerPCJITInfo : public TargetJITInfo {
|
||||
TargetMachine &TM;
|
||||
public:
|
||||
PowerPCJITInfo(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
|
82
lib/Target/PowerPC/PPCRegisterInfo.td
Normal file
82
lib/Target/PowerPC/PPCRegisterInfo.td
Normal file
@ -0,0 +1,82 @@
|
||||
//===- PowerPCReg.td - Describe the PowerPC 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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class PPCReg : Register {
|
||||
let Namespace = "PPC32";
|
||||
}
|
||||
|
||||
// We identify all our registers with a 5-bit ID, for consistency's sake.
|
||||
|
||||
// GPR - One of the 32 32-bit general-purpose registers
|
||||
class GPR<bits<5> num> : PPCReg {
|
||||
field bits<5> Num = num;
|
||||
}
|
||||
|
||||
// SPR - One of the 32-bit special-purpose registers
|
||||
class SPR<bits<5> num> : PPCReg {
|
||||
field bits<5> Num = num;
|
||||
}
|
||||
|
||||
// FPR - One of the 32 64-bit floating-point registers
|
||||
class FPR<bits<5> num> : PPCReg {
|
||||
field bits<5> Num = num;
|
||||
}
|
||||
|
||||
// CR - One of the 8 4-bit condition registers
|
||||
class CR<bits<5> num> : PPCReg {
|
||||
field bits<5> Num = num;
|
||||
}
|
||||
|
||||
// General-purpose registers
|
||||
def R0 : GPR< 0>; def R1 : GPR< 1>; def R2 : GPR< 2>; def R3 : GPR< 3>;
|
||||
def R4 : GPR< 4>; def R5 : GPR< 5>; def R6 : GPR< 6>; def R7 : GPR< 7>;
|
||||
def R8 : GPR< 8>; def R9 : GPR< 9>; def R10 : GPR<10>; def R11 : GPR<11>;
|
||||
def R12 : GPR<12>; def R13 : GPR<13>; def R14 : GPR<14>; def R15 : GPR<15>;
|
||||
def R16 : GPR<16>; def R17 : GPR<17>; def R18 : GPR<18>; def R19 : GPR<19>;
|
||||
def R20 : GPR<20>; def R21 : GPR<21>; def R22 : GPR<22>; def R23 : GPR<23>;
|
||||
def R24 : GPR<24>; def R25 : GPR<25>; def R26 : GPR<26>; def R27 : GPR<27>;
|
||||
def R28 : GPR<28>; def R29 : GPR<29>; def R30 : GPR<30>; def R31 : GPR<31>;
|
||||
|
||||
// Floating-point registers
|
||||
def F0 : FPR< 0>; def F1 : FPR< 1>; def F2 : FPR< 2>; def F3 : FPR< 3>;
|
||||
def F4 : FPR< 4>; def F5 : FPR< 5>; def F6 : FPR< 6>; def F7 : FPR< 7>;
|
||||
def F8 : FPR< 8>; def F9 : FPR< 9>; def F10 : FPR<10>; def F11 : FPR<11>;
|
||||
def F12 : FPR<12>; def F13 : FPR<13>; def F14 : FPR<14>; def F15 : FPR<15>;
|
||||
def F16 : FPR<16>; def F17 : FPR<17>; def F18 : FPR<18>; def F19 : FPR<19>;
|
||||
def F20 : FPR<20>; def F21 : FPR<21>; def F22 : FPR<22>; def F23 : FPR<23>;
|
||||
def F24 : FPR<24>; def F25 : FPR<25>; def F26 : FPR<26>; def F27 : FPR<27>;
|
||||
def F28 : FPR<28>; def F29 : FPR<29>; def F30 : FPR<30>; def F31 : FPR<31>;
|
||||
|
||||
// Condition registers
|
||||
def CR0 : CR<0>; def CR1 : CR<1>; def CR2 : CR<2>; def CR3 : CR<3>;
|
||||
def CR4 : CR<4>; def CR5 : CR<5>; def CR6 : CR<6>; def CR7 : CR<7>;
|
||||
|
||||
// Floating-point status and control register
|
||||
def FPSCR : SPR<0>;
|
||||
// fiXed-point Exception Register? :-)
|
||||
def XER : SPR<1>;
|
||||
// Link register
|
||||
def LR : SPR<2>;
|
||||
// Count register
|
||||
def CTR : SPR<3>;
|
||||
// These are the "time base" registers which are read-only in user mode.
|
||||
def TBL : SPR<4>;
|
||||
def TBU : SPR<5>;
|
||||
|
||||
/// Register classes: one for floats and another for non-floats.
|
||||
def GPRC : RegisterClass<i32, 4, [R0, R1, R2, R3, R4, R5, R6, R7,
|
||||
R8, R9, R10, R11, R12, R13, R14, R15, R16, R17, R18, R19, R20, R21,
|
||||
R22, R23, R24, R25, R26, R27, R28, R29, R30, R31]>;
|
||||
def FPRC : RegisterClass<f64, 8, [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]>;
|
||||
|
88
lib/Target/PowerPC/PPCTargetMachine.cpp
Normal file
88
lib/Target/PowerPC/PPCTargetMachine.cpp
Normal file
@ -0,0 +1,88 @@
|
||||
//===-- PowerPCTargetMachine.cpp - Define TargetMachine for PowerPC -------===//
|
||||
//
|
||||
// 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"
|
||||
#include "PowerPC.h"
|
||||
#include "llvm/IntrinsicLowering.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/PassManager.h"
|
||||
#include "llvm/Target/TargetMachineImpls.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/Passes.h"
|
||||
#include "llvm/Transforms/Scalar.h"
|
||||
using namespace llvm;
|
||||
|
||||
// allocatePowerPCTargetMachine - Allocate and return a subclass of
|
||||
// TargetMachine that implements the PowerPC backend.
|
||||
//
|
||||
TargetMachine *llvm::allocatePowerPCTargetMachine(const Module &M,
|
||||
IntrinsicLowering *IL) {
|
||||
return new PowerPCTargetMachine(M, IL);
|
||||
}
|
||||
|
||||
/// PowerPCTargetMachine ctor - Create an ILP32 architecture model
|
||||
///
|
||||
/// FIXME: Should double alignment be 8 bytes? Then we get a PtrAl != DoubleAl abort
|
||||
PowerPCTargetMachine::PowerPCTargetMachine(const Module &M,
|
||||
IntrinsicLowering *IL)
|
||||
: TargetMachine("PowerPC", IL, false, 4, 4, 4, 4, 4, 4, 4, 4),
|
||||
FrameInfo(TargetFrameInfo::StackGrowsDown, 16, -4), JITInfo(*this) {
|
||||
}
|
||||
|
||||
/// addPassesToEmitAssembly - Add passes to the specified pass manager
|
||||
/// to implement a static compiler for this target.
|
||||
///
|
||||
bool PowerPCTargetMachine::addPassesToEmitAssembly(PassManager &PM,
|
||||
std::ostream &Out) {
|
||||
// FIXME: Implement efficient support for garbage collection intrinsics.
|
||||
PM.add(createLowerGCPass());
|
||||
|
||||
// FIXME: Implement the invoke/unwind instructions!
|
||||
PM.add(createLowerInvokePass());
|
||||
|
||||
// FIXME: The code generator does not properly handle functions with
|
||||
// unreachable basic blocks.
|
||||
PM.add(createCFGSimplificationPass());
|
||||
|
||||
// FIXME: Implement the switch instruction in the instruction selector!
|
||||
PM.add(createLowerSwitchPass());
|
||||
|
||||
PM.add(createPPCSimpleInstructionSelector(*this));
|
||||
PM.add(createRegisterAllocator());
|
||||
PM.add(createPrologEpilogCodeInserter());
|
||||
PM.add(createPPCCodePrinterPass(Out, *this));
|
||||
PM.add(createMachineCodeDeleter());
|
||||
return false;
|
||||
}
|
||||
|
||||
/// addPassesToJITCompile - Add passes to the specified pass manager to
|
||||
/// implement a fast dynamic compiler for this target.
|
||||
///
|
||||
void PowerPCJITInfo::addPassesToJITCompile(FunctionPassManager &PM) {
|
||||
// FIXME: Implement efficient support for garbage collection intrinsics.
|
||||
PM.add(createLowerGCPass());
|
||||
|
||||
// FIXME: Implement the invoke/unwind instructions!
|
||||
PM.add(createLowerInvokePass());
|
||||
|
||||
// FIXME: The code generator does not properly handle functions with
|
||||
// unreachable basic blocks.
|
||||
PM.add(createCFGSimplificationPass());
|
||||
|
||||
// FIXME: Implement the switch instruction in the instruction selector!
|
||||
PM.add(createLowerSwitchPass());
|
||||
|
||||
PM.add(createPPCSimpleInstructionSelector(TM));
|
||||
PM.add(createRegisterAllocator());
|
||||
PM.add(createPrologEpilogCodeInserter());
|
||||
}
|
||||
|
44
lib/Target/PowerPC/PowerPC.td
Normal file
44
lib/Target/PowerPC/PowerPC.td
Normal file
@ -0,0 +1,44 @@
|
||||
//===- PowerPC.td - Describe the PowerPC 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 "PowerPCReg.td"
|
||||
include "PowerPCInstrs.td"
|
||||
|
||||
def PowerPCInstrInfo : InstrInfo {
|
||||
let PHIInst = PHI;
|
||||
|
||||
let TSFlagsFields = ["ArgCount", "Arg0Type", "Arg1Type", "Arg2Type", "Arg3Type", "Arg4Type", "VMX", "PPC64"];
|
||||
let TSFlagsShifts = [ 0, 3, 8, 13, 18, 23, 28, 29 ];
|
||||
}
|
||||
|
||||
def PowerPC : Target {
|
||||
// Pointers are 32-bits in size.
|
||||
let PointerType = i32;
|
||||
|
||||
// According to the Mach-O Runtime ABI, these regs are nonvolatile across
|
||||
// calls:
|
||||
let CalleeSavedRegisters = [R1, R13, R14, R15, R16, R17, R18, R19,
|
||||
R20, R21, R22, R23, R24, R25, R26, R27, R28, R29, R30, R31, F14, F15,
|
||||
F16, F17, F18, F19, F20, F21, F22, F23, F24, F25, F26, F27, F28, F29,
|
||||
F30, F31, CR2, CR3, CR4];
|
||||
|
||||
// Pull in Instruction Info:
|
||||
let InstructionSet = PowerPCInstrInfo;
|
||||
}
|
694
lib/Target/PowerPC/PowerPCAsmPrinter.cpp
Normal file
694
lib/Target/PowerPC/PowerPCAsmPrinter.cpp
Normal file
@ -0,0 +1,694 @@
|
||||
//===-- PPC32/Printer.cpp - Convert X86 LLVM code to Intel 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 Intel-format
|
||||
// assembly language. This printer is the output mechanism used
|
||||
// by `llc' and `lli -print-machineinstrs' on X86.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "PowerPC.h"
|
||||
#include "PowerPCInstrInfo.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"
|
||||
|
||||
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.
|
||||
///
|
||||
TargetMachine &TM;
|
||||
|
||||
/// Name-mangler for global names.
|
||||
///
|
||||
Mangler *Mang;
|
||||
std::set< std::string > Stubs;
|
||||
std::set<std::string> Strings;
|
||||
|
||||
Printer(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 "PowerPC Assembly Printer";
|
||||
}
|
||||
|
||||
void printMachineInstruction(const MachineInstr *MI);
|
||||
void printOp(const MachineOperand &MO,
|
||||
bool elideOffsetKeyword = false);
|
||||
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 X86
|
||||
/// 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 ConstantPointerRef *CPR = dyn_cast<ConstantPointerRef>(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(CPR->getValue());
|
||||
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 (CV->isNullValue()) {
|
||||
O << "\t.space\t " << TD.getTypeSize(CV->getType()) << "\n";
|
||||
return;
|
||||
} else if (const ConstantArray *CVA = dyn_cast<ConstantArray>(CV)) {
|
||||
if (isStringCompatible(CVA)) {
|
||||
O << ".ascii";
|
||||
printAsCString(O, CVA);
|
||||
O << "\n";
|
||||
} else { // Not a string. Print the values in successive locations
|
||||
const std::vector<Use> &constValues = CVA->getValues();
|
||||
for (unsigned i=0; i < constValues.size(); i++)
|
||||
emitGlobalConstant(cast<Constant>(constValues[i].get()));
|
||||
}
|
||||
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());
|
||||
const std::vector<Use>& constValues = CVS->getValues();
|
||||
unsigned sizeSoFar = 0;
|
||||
for (unsigned i=0, N = constValues.size(); i < N; i++) {
|
||||
const Constant* field = cast<Constant>(constValues[i].get());
|
||||
|
||||
// Check if padding is needed and insert one or more 0s.
|
||||
unsigned fieldSize = TD.getTypeSize(field->getType());
|
||||
unsigned padSize = ((i == N-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()->getPrimitiveID()) {
|
||||
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()->getPrimitiveSize() == 64) {
|
||||
const ConstantInt *CI = dyn_cast<ConstantInt>(CV);
|
||||
if(CI) {
|
||||
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->getPrimitiveID()) {
|
||||
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:
|
||||
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 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) {
|
||||
// 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.globl\t" << CurrentFnName << "\n";
|
||||
O << "\t.align 5\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 << "L" << NumberForBB[I->getBasicBlock()] << ":\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 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:
|
||||
O << RI.get(MO.getReg()).Name;
|
||||
return;
|
||||
|
||||
case MachineOperand::MO_SignExtendedImmed:
|
||||
case MachineOperand::MO_UnextendedImmed:
|
||||
O << (int)MO.getImmedValue();
|
||||
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_PCRelativeDisp:
|
||||
std::cerr << "Shouldn't use addPCDisp() when building PPC MachineInstrs";
|
||||
abort ();
|
||||
return;
|
||||
case MachineOperand::MO_GlobalAddress:
|
||||
if (!elideOffsetKeyword) {
|
||||
if(isa<Function>(MO.getGlobal())) {
|
||||
Stubs.insert(Mang->getValueName(MO.getGlobal()));
|
||||
O << "L" << Mang->getValueName(MO.getGlobal()) << "$stub";
|
||||
} else {
|
||||
O << Mang->getValueName(MO.getGlobal());
|
||||
}
|
||||
}
|
||||
return;
|
||||
case MachineOperand::MO_ExternalSymbol:
|
||||
O << MO.getSymbolName();
|
||||
return;
|
||||
default:
|
||||
O << "<unknown operand type>"; return;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static inline
|
||||
unsigned int ValidOpcodes(const MachineInstr *MI, unsigned int ArgType[5]) {
|
||||
int i;
|
||||
unsigned int retval = 1;
|
||||
|
||||
for(i = 0; i<5; i++) {
|
||||
switch(ArgType[i]) {
|
||||
case none:
|
||||
break;
|
||||
case Gpr:
|
||||
case Gpr0:
|
||||
Type::UIntTy
|
||||
case Simm16:
|
||||
case Zimm16:
|
||||
case PCRelimm24:
|
||||
case Imm24:
|
||||
case Imm5:
|
||||
case PCRelimm14:
|
||||
case Imm14:
|
||||
case Imm2:
|
||||
case Crf:
|
||||
case Imm3:
|
||||
case Imm1:
|
||||
case Fpr:
|
||||
case Imm4:
|
||||
case Imm8:
|
||||
case Disimm16:
|
||||
case Spr:
|
||||
case Sgr:
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// 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 int i;
|
||||
|
||||
unsigned int ArgCount = Desc.TSFlags & PPC32II::ArgCountMask;
|
||||
unsigned int ArgType[5];
|
||||
|
||||
|
||||
ArgType[0] = (Desc.TSFlags>>PPC32II::Arg0TypeShift) & PPC32II::ArgTypeMask;
|
||||
ArgType[1] = (Desc.TSFlags>>PPC32II::Arg1TypeShift) & PPC32II::ArgTypeMask;
|
||||
ArgType[2] = (Desc.TSFlags>>PPC32II::Arg2TypeShift) & PPC32II::ArgTypeMask;
|
||||
ArgType[3] = (Desc.TSFlags>>PPC32II::Arg3TypeShift) & PPC32II::ArgTypeMask;
|
||||
ArgType[4] = (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");
|
||||
//assert ( ValidOpcodes(MI, ArgType) && "Instruction has invalid inputs");
|
||||
++EmittedInsts;
|
||||
|
||||
if(Opcode == PPC32::MovePCtoLR) {
|
||||
O << "mflr r0\n";
|
||||
O << "bcl 20,31,L" << CurrentFnName << "$pb\n";
|
||||
O << "L" << CurrentFnName << "$pb:\n";
|
||||
return;
|
||||
}
|
||||
|
||||
O << TII.getName(MI->getOpcode()) << " ";
|
||||
std::cout << TII.getName(MI->getOpcode()) << " expects " << ArgCount << " args\n";
|
||||
|
||||
if(Opcode == PPC32::LOADLoAddr) {
|
||||
printOp(MI->getOperand(0));
|
||||
O << ", ";
|
||||
printOp(MI->getOperand(1));
|
||||
O << ", lo16(";
|
||||
printOp(MI->getOperand(2));
|
||||
O << "-L" << CurrentFnName << "$pb)\n";
|
||||
return;
|
||||
}
|
||||
|
||||
if(Opcode == PPC32::LOADHiAddr) {
|
||||
printOp(MI->getOperand(0));
|
||||
O << ", ";
|
||||
printOp(MI->getOperand(1));
|
||||
O << ", ha16(" ;
|
||||
printOp(MI->getOperand(2));
|
||||
O << "-L" << CurrentFnName << "$pb)\n";
|
||||
return;
|
||||
}
|
||||
|
||||
if( (ArgCount == 3) && (ArgType[1] == PPC32II::Disimm16) ) {
|
||||
printOp(MI->getOperand(0));
|
||||
O << ", ";
|
||||
printOp(MI->getOperand(1));
|
||||
O << "(";
|
||||
if((ArgType[2] == PPC32II::Gpr0) && (MI->getOperand(2).getReg() == PPC32::R0)) {
|
||||
O << "0";
|
||||
} else {
|
||||
printOp(MI->getOperand(2));
|
||||
}
|
||||
O << ")\n";
|
||||
} else {
|
||||
for(i = 0; i< ArgCount; i++) {
|
||||
if( (ArgType[i] == PPC32II::Gpr0) && ((MI->getOperand(i).getReg()) == PPC32::R0)) {
|
||||
O << "0";
|
||||
} else {
|
||||
//std::cout << "DEBUG " << (*(TM.getRegisterInfo())).get(MI->getOperand(i).getReg()).Name << "\n";
|
||||
printOp(MI->getOperand(i));
|
||||
}
|
||||
if( ArgCount - 1 == i) {
|
||||
O << "\n";
|
||||
} else {
|
||||
O << ", ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool Printer::doInitialization(Module &M) {
|
||||
// Tell gas we are outputting Intel syntax (not AT&T syntax) assembly.
|
||||
//
|
||||
// Bug: gas in `intel_syntax noprefix' mode interprets the symbol `Sp' in an
|
||||
// instruction as a reference to the register named sp, and if you try to
|
||||
// reference a symbol `Sp' (e.g. `mov ECX, OFFSET Sp') then it gets lowercased
|
||||
// before being looked up in the symbol table. This creates spurious
|
||||
// `undefined symbol' errors when linking. Workaround: Do not use `noprefix'
|
||||
// mode, and decorate all register names with percent signs.
|
||||
// O << "\t.intel_syntax\n";
|
||||
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() &&
|
||||
(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 << name << ":\t\t\t\t# ";
|
||||
WriteAsOperand(O, I, true, true, &M);
|
||||
O << " = ";
|
||||
WriteAsOperand(O, C, false, false, &M);
|
||||
O << "\n";
|
||||
emitGlobalConstant(C);
|
||||
}
|
||||
}
|
||||
|
||||
for(std::set<std::string>::iterator i = Stubs.begin(); i != Stubs.end(); ++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 << ".indirect_symbol " << *i << "\n";
|
||||
O << ".long dyld_stub_binding_helper\n";
|
||||
|
||||
}
|
||||
|
||||
delete Mang;
|
||||
return false; // success
|
||||
}
|
||||
|
||||
} // End llvm namespace
|
43
lib/Target/PowerPC/PowerPCCodeEmitter.cpp
Normal file
43
lib/Target/PowerPC/PowerPCCodeEmitter.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
//===-- 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
|
||||
|
2621
lib/Target/PowerPC/PowerPCISelSimple.cpp
Normal file
2621
lib/Target/PowerPC/PowerPCISelSimple.cpp
Normal file
File diff suppressed because it is too large
Load Diff
22
lib/Target/PowerPC/PowerPCInstrInfo.cpp
Normal file
22
lib/Target/PowerPC/PowerPCInstrInfo.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
//===- PowerPCInstrInfo.cpp - PowerPC 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 PowerPC implementation of the TargetInstrInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "PowerPCInstrInfo.h"
|
||||
#include "PowerPC.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "PowerPCGenInstrInfo.inc"
|
||||
using namespace llvm;
|
||||
|
||||
PowerPCInstrInfo::PowerPCInstrInfo()
|
||||
: TargetInstrInfo(PowerPCInsts, sizeof(PowerPCInsts)/sizeof(PowerPCInsts[0])){
|
||||
}
|
78
lib/Target/PowerPC/PowerPCInstrInfo.h
Normal file
78
lib/Target/PowerPC/PowerPCInstrInfo.h
Normal file
@ -0,0 +1,78 @@
|
||||
//===- PowerPCInstrInfo.h - PowerPC 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 PowerPC implementation of the TargetInstrInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef POWERPCINSTRUCTIONINFO_H
|
||||
#define POWERPCINSTRUCTIONINFO_H
|
||||
|
||||
#include "llvm/Target/TargetInstrInfo.h"
|
||||
#include "PowerPCRegisterInfo.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
namespace PPC32II {
|
||||
enum {
|
||||
ArgCountShift = 0,
|
||||
ArgCountMask = 7,
|
||||
|
||||
Arg0TypeShift = 3,
|
||||
Arg1TypeShift = 8,
|
||||
Arg2TypeShift = 13,
|
||||
Arg3TypeShift = 18,
|
||||
Arg4TypeShift = 23,
|
||||
VMX = 1<<28,
|
||||
PPC64 = 1<<29,
|
||||
ArgTypeMask = 31
|
||||
};
|
||||
|
||||
enum {
|
||||
None = 0,
|
||||
Gpr = 1,
|
||||
Gpr0 = 2,
|
||||
Simm16 = 3,
|
||||
Zimm16 = 4,
|
||||
PCRelimm24 = 5,
|
||||
Imm24 = 6,
|
||||
Imm5 = 7,
|
||||
PCRelimm14 = 8,
|
||||
Imm14 = 9,
|
||||
Imm2 = 10,
|
||||
Crf = 11,
|
||||
Imm3 = 12,
|
||||
Imm1 = 13,
|
||||
Fpr = 14,
|
||||
Imm4 = 15,
|
||||
Imm8 = 16,
|
||||
Disimm16 = 17,
|
||||
Disimm14 = 18,
|
||||
Spr = 19,
|
||||
Sgr = 20,
|
||||
Imm15 = 21,
|
||||
Vpr = 22
|
||||
};
|
||||
}
|
||||
|
||||
class PowerPCInstrInfo : public TargetInstrInfo {
|
||||
const PowerPCRegisterInfo RI;
|
||||
public:
|
||||
PowerPCInstrInfo();
|
||||
|
||||
/// 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; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
268
lib/Target/PowerPC/PowerPCRegisterInfo.cpp
Normal file
268
lib/Target/PowerPC/PowerPCRegisterInfo.cpp
Normal file
@ -0,0 +1,268 @@
|
||||
//===- PowerPCRegisterInfo.cpp - PowerPC 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 PowerPC implementation of the MRegisterInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "PowerPC.h"
|
||||
#include "PowerPCRegisterInfo.h"
|
||||
#include "PowerPCInstrBuilder.h"
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/Type.h"
|
||||
#include "llvm/CodeGen/ValueTypes.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Target/TargetFrameInfo.h"
|
||||
#include "Support/CommandLine.h"
|
||||
#include "Support/STLExtras.h"
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
cl::opt<bool>
|
||||
NoFPElim("disable-fp-elim",cl::desc("Disable frame pointer elimination optimization"));
|
||||
}
|
||||
|
||||
PowerPCRegisterInfo::PowerPCRegisterInfo()
|
||||
: PowerPCGenRegisterInfo(PPC32::ADJCALLSTACKDOWN,
|
||||
PPC32::ADJCALLSTACKUP) {}
|
||||
|
||||
static unsigned getIdx(const TargetRegisterClass *RC) {
|
||||
if (RC == PowerPC::GPRCRegisterClass) {
|
||||
switch (RC->getSize()) {
|
||||
default: assert(0 && "Invalid data size!");
|
||||
case 1: return 0;
|
||||
case 2: return 1;
|
||||
case 4: return 2;
|
||||
}
|
||||
}
|
||||
else if (RC == PowerPC::FPRCRegisterClass) {
|
||||
switch (RC->getSize()) {
|
||||
default: assert(0 && "Invalid data size!");
|
||||
case 4: return 3;
|
||||
case 8: return 4;
|
||||
}
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
int PowerPCRegisterInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MI,
|
||||
unsigned SrcReg, int FrameIdx,
|
||||
const TargetRegisterClass *RC) const {
|
||||
static const unsigned Opcode[] =
|
||||
{ PPC32::STB, PPC32::STH, PPC32::STW, PPC32::STFS, PPC32::STFD };
|
||||
|
||||
unsigned OC = Opcode[getIdx(RC)];
|
||||
MBB.insert(MI, addFrameReference(BuildMI(OC, 3).addReg(SrcReg),FrameIdx));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int PowerPCRegisterInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MI,
|
||||
unsigned DestReg, int FrameIdx,
|
||||
const TargetRegisterClass *RC) const{
|
||||
static const unsigned Opcode[] =
|
||||
|
||||
{ PPC32::LBZ, PPC32::LHZ, PPC32::LWZ, PPC32::LFS, PPC32::LFD };
|
||||
unsigned OC = Opcode[getIdx(RC)];
|
||||
MBB.insert(MI, addFrameReference(BuildMI(OC, 2, DestReg), FrameIdx));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int PowerPCRegisterInfo::copyRegToReg(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MI,
|
||||
unsigned DestReg, unsigned SrcReg,
|
||||
const TargetRegisterClass *RC) const {
|
||||
MachineInstr *I;
|
||||
|
||||
if(RC == PowerPC::GPRCRegisterClass) {
|
||||
I = BuildMI(PPC32::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg);
|
||||
} else if (RC == PowerPC::FPRCRegisterClass) {
|
||||
I = BuildMI(PPC32::FMR, 1, DestReg).addReg(SrcReg);
|
||||
} else {
|
||||
std::cerr << "Attempt to copy register that is not GPR or FPR";
|
||||
abort();
|
||||
}
|
||||
MBB.insert(MI, I);
|
||||
return 1;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Stack Frame Processing methods
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// hasFP - Return true if the specified function should have a dedicated frame
|
||||
// pointer register. This is true if the function has variable sized allocas or
|
||||
// if frame pointer elimination is disabled.
|
||||
//
|
||||
static bool hasFP(MachineFunction &MF) {
|
||||
return NoFPElim || MF.getFrameInfo()->hasVarSizedObjects();
|
||||
}
|
||||
|
||||
void PowerPCRegisterInfo::
|
||||
eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator I) const {
|
||||
if (hasFP(MF)) {
|
||||
// If we have a frame pointer, turn the adjcallstackdown instruction into a
|
||||
// 'sub r1, r1, <amt>' and the adjcallstackup instruction into 'add r1, r1, <amt>'
|
||||
MachineInstr *Old = I;
|
||||
int Amount = Old->getOperand(0).getImmedValue();
|
||||
if (Amount != 0) {
|
||||
// We need to keep the stack aligned properly. To do this, we round the
|
||||
// amount of space needed for the outgoing arguments up to the next
|
||||
// alignment boundary.
|
||||
unsigned Align = MF.getTarget().getFrameInfo()->getStackAlignment();
|
||||
Amount = (Amount+Align-1)/Align*Align;
|
||||
|
||||
MachineInstr *New;
|
||||
if (Old->getOpcode() == PPC32::ADJCALLSTACKDOWN) {
|
||||
New=BuildMI(PPC32::ADDI, 2, PPC32::R1).addReg(PPC32::R1).addSImm(-Amount);
|
||||
} else {
|
||||
assert(Old->getOpcode() == PPC32::ADJCALLSTACKUP);
|
||||
New=BuildMI(PPC32::ADDI, 2, PPC32::R1).addReg(PPC32::R1).addSImm(Amount);
|
||||
}
|
||||
|
||||
// Replace the pseudo instruction with a new instruction...
|
||||
MBB.insert(I, New);
|
||||
}
|
||||
}
|
||||
|
||||
MBB.erase(I);
|
||||
}
|
||||
|
||||
void
|
||||
PowerPCRegisterInfo::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();
|
||||
|
||||
// This must be part of a four operand memory reference. Replace the
|
||||
// FrameIndex with base register with GPR1.
|
||||
MI.SetMachineOperandReg(i, PPC32::R1);
|
||||
|
||||
// Take into account whether its an add or mem instruction
|
||||
if (i == 2) i--;
|
||||
|
||||
// Now add the frame object offset to the offset from r1.
|
||||
int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex) +
|
||||
MI.getOperand(i).getImmedValue()+4;
|
||||
|
||||
if (!hasFP(MF))
|
||||
Offset += MF.getFrameInfo()->getStackSize();
|
||||
|
||||
MI.SetMachineOperandConst(i-1, MachineOperand::MO_SignExtendedImmed, Offset);
|
||||
std::cout << "offset = " << Offset << std::endl;
|
||||
}
|
||||
|
||||
|
||||
void PowerPCRegisterInfo::processFunctionBeforeFrameFinalized(
|
||||
MachineFunction &MF) const {
|
||||
// Do Nothing
|
||||
}
|
||||
|
||||
void PowerPCRegisterInfo::emitPrologue(MachineFunction &MF) const {
|
||||
MachineBasicBlock &MBB = MF.front(); // Prolog goes in entry BB
|
||||
MachineBasicBlock::iterator MBBI = MBB.begin();
|
||||
MachineFrameInfo *MFI = MF.getFrameInfo();
|
||||
MachineInstr *MI;
|
||||
|
||||
// Get the number of bytes to allocate from the FrameInfo
|
||||
unsigned NumBytes = MFI->getStackSize();
|
||||
|
||||
if (MFI->hasCalls()) {
|
||||
// When we have no frame pointer, we reserve argument space for call sites
|
||||
// in the function immediately on entry to the current function. This
|
||||
// eliminates the need for add/sub brackets around call sites.
|
||||
//
|
||||
NumBytes += MFI->getMaxCallFrameSize();
|
||||
|
||||
// Round the size to a multiple of the alignment (don't forget the 4 byte
|
||||
// offset though).
|
||||
unsigned Align = MF.getTarget().getFrameInfo()->getStackAlignment();
|
||||
NumBytes = ((NumBytes+4)+Align-1)/Align*Align - 4;
|
||||
|
||||
// Store the incoming LR so it is preserved across calls
|
||||
MI= BuildMI(PPC32::MovePCtoLR, 0, PPC32::LR).addReg(PPC32::LR);
|
||||
MBB.insert(MBBI, MI);
|
||||
MI= BuildMI(PPC32::MFSPR, 1, PPC32::R0).addImm(8);
|
||||
MBB.insert(MBBI, MI);
|
||||
MI= BuildMI(PPC32::STW, 3).addReg(PPC32::R0).addSImm(8).addReg(PPC32::R1);
|
||||
MBB.insert(MBBI, MI);
|
||||
}
|
||||
|
||||
// Update frame info to pretend that this is part of the stack...
|
||||
MFI->setStackSize(NumBytes);
|
||||
|
||||
// adjust stack pointer: r1 -= numbytes
|
||||
if (NumBytes) {
|
||||
MI= BuildMI(PPC32::STWU, 2, PPC32::R1).addImm(-NumBytes).addReg(PPC32::R1);
|
||||
MBB.insert(MBBI, MI);
|
||||
}
|
||||
}
|
||||
|
||||
void PowerPCRegisterInfo::emitEpilogue(MachineFunction &MF,
|
||||
MachineBasicBlock &MBB) const {
|
||||
const MachineFrameInfo *MFI = MF.getFrameInfo();
|
||||
MachineBasicBlock::iterator MBBI = prior(MBB.end());
|
||||
MachineInstr *MI;
|
||||
assert(MBBI->getOpcode() == PPC32::BLR &&
|
||||
"Can only insert epilog into returning blocks");
|
||||
|
||||
// Get the number of bytes allocated from the FrameInfo...
|
||||
unsigned NumBytes = MFI->getStackSize();
|
||||
|
||||
// adjust stack pointer back: r1 += numbytes
|
||||
if (NumBytes) {
|
||||
MI =BuildMI(PPC32::ADDI, 2, PPC32::R1)
|
||||
.addReg(PPC32::R1)
|
||||
.addSImm(NumBytes);
|
||||
MBB.insert(MBBI, MI);
|
||||
}
|
||||
|
||||
// If we have calls, restore the LR value before we branch to it
|
||||
if (MFI->hasCalls()) {
|
||||
MI = BuildMI(PPC32::LWZ, 2, PPC32::R0).addSImm(8).addReg(PPC32::R1);
|
||||
MBB.insert(MBBI, MI);
|
||||
MI = BuildMI(PPC32::MTLR, 1).addReg(PPC32::R0);
|
||||
MBB.insert(MBBI, MI);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#include "PowerPCGenRegisterInfo.inc"
|
||||
|
||||
const TargetRegisterClass*
|
||||
PowerPCRegisterInfo::getRegClassForType(const Type* Ty) const {
|
||||
switch (Ty->getPrimitiveID()) {
|
||||
case Type::LongTyID:
|
||||
case Type::ULongTyID: assert(0 && "Long values can't 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 &GPRCInstance;
|
||||
|
||||
case Type::FloatTyID:
|
||||
case Type::DoubleTyID: return &FPRCInstance;
|
||||
}
|
||||
}
|
||||
|
58
lib/Target/PowerPC/PowerPCRegisterInfo.h
Normal file
58
lib/Target/PowerPC/PowerPCRegisterInfo.h
Normal file
@ -0,0 +1,58 @@
|
||||
//===- PowerPCRegisterInfo.h - PowerPC 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 PowerPC implementation of the MRegisterInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef POWERPCREGISTERINFO_H
|
||||
#define POWERPCREGISTERINFO_H
|
||||
|
||||
#include "llvm/Target/MRegisterInfo.h"
|
||||
#include "PowerPCGenRegisterInfo.h.inc"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Type;
|
||||
|
||||
struct PowerPCRegisterInfo : public PowerPCGenRegisterInfo {
|
||||
PowerPCRegisterInfo();
|
||||
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
|
57
lib/Target/PowerPC/PowerPCTargetMachine.h
Normal file
57
lib/Target/PowerPC/PowerPCTargetMachine.h
Normal file
@ -0,0 +1,57 @@
|
||||
//===-- PowerPCTargetMachine.h - Define TargetMachine 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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file declares the PowerPC specific subclass of TargetMachine.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef POWERPCTARGETMACHINE_H
|
||||
#define POWERPCTARGETMACHINE_H
|
||||
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Target/TargetFrameInfo.h"
|
||||
#include "llvm/PassManager.h"
|
||||
#include "PowerPCInstrInfo.h"
|
||||
#include "PowerPCJITInfo.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class IntrinsicLowering;
|
||||
|
||||
class PowerPCTargetMachine : public TargetMachine {
|
||||
PowerPCInstrInfo InstrInfo;
|
||||
TargetFrameInfo FrameInfo;
|
||||
PowerPCJITInfo JITInfo;
|
||||
public:
|
||||
PowerPCTargetMachine(const Module &M, IntrinsicLowering *IL);
|
||||
|
||||
virtual const PowerPCInstrInfo *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
|
26
lib/Target/PowerPC/README.txt
Normal file
26
lib/Target/PowerPC/README.txt
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
PowerPC backend skeleton
|
||||
------------------------
|
||||
|
||||
Someday we'd like to have a PowerPC backend. Unfortunately, this
|
||||
is not yet that day.
|
||||
|
||||
This directory contains mainly stubs and placeholders; there is no
|
||||
binary machine code emitter, no assembly writer, and no instruction
|
||||
selector here. Most of the functions in these files call abort()
|
||||
or fail assertions on purpose, just to reinforce the fact that they
|
||||
don't work.
|
||||
|
||||
If you want to use LLVM on the PowerPC *today*, use the C Backend
|
||||
(llc -march=c). It generates C code that you can compile with the
|
||||
native GCC compiler and run. A distant second choice would be the
|
||||
Interpreter (lli --force-interpreter=true).
|
||||
|
||||
A few things *are* really here, including:
|
||||
* PowerPC register file definition in TableGen format
|
||||
* PowerPC definitions of TargetMachine and other target-specific classes
|
||||
|
||||
"Patches," as they say, "are accepted."
|
||||
|
||||
$Date$
|
||||
|
Loading…
x
Reference in New Issue
Block a user