#define DEBUG_TYPE "asmprinter"
#include "SPU.h"
#include "SPUTargetMachine.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Module.h"
#include "llvm/Assembly/Writer.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/DwarfWriter.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/Support/Mangler.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetAsmInfo.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringExtras.h"
#include <set>
using namespace llvm;
namespace {
STATISTIC(EmittedInsts, "Number of machine instrs printed");
const std::string bss_section(".bss");
class VISIBILITY_HIDDEN SPUAsmPrinter : public AsmPrinter {
std::set<std::string> FnStubs, GVStubs;
public:
explicit SPUAsmPrinter(raw_ostream &O, TargetMachine &TM,
const TargetAsmInfo *T, CodeGenOpt::Level OL,
bool V) :
AsmPrinter(O, TM, T, OL, V) {}
virtual const char *getPassName() const {
return "STI CBEA SPU Assembly Printer";
}
SPUTargetMachine &getTM() {
return static_cast<SPUTargetMachine&>(TM);
}
bool printInstruction(const MachineInstr *MI);
void printMachineInstruction(const MachineInstr *MI);
void printOp(const MachineOperand &MO);
void printRegister(const MachineOperand &MO, bool R0AsZero) {
unsigned RegNo = MO.getReg();
assert(TargetRegisterInfo::isPhysicalRegister(RegNo) &&
"Not physreg??");
O << TM.getRegisterInfo()->get(RegNo).AsmName;
}
void printOperand(const MachineInstr *MI, unsigned OpNo) {
const MachineOperand &MO = MI->getOperand(OpNo);
if (MO.isReg()) {
assert(TargetRegisterInfo::isPhysicalRegister(MO.getReg())&&"Not physreg??");
O << TM.getRegisterInfo()->get(MO.getReg()).AsmName;
} else if (MO.isImm()) {
O << MO.getImm();
} else {
printOp(MO);
}
}
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant, const char *ExtraCode);
bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant, const char *ExtraCode);
void
printS7ImmOperand(const MachineInstr *MI, unsigned OpNo)
{
int value = MI->getOperand(OpNo).getImm();
value = (value << (32 - 7)) >> (32 - 7);
assert((value >= -(1 << 8) && value <= (1 << 7) - 1)
&& "Invalid s7 argument");
O << value;
}
void
printU7ImmOperand(const MachineInstr *MI, unsigned OpNo)
{
unsigned int value = MI->getOperand(OpNo).getImm();
assert(value < (1 << 8) && "Invalid u7 argument");
O << value;
}
void
printShufAddr(const MachineInstr *MI, unsigned OpNo)
{
char value = MI->getOperand(OpNo).getImm();
O << (int) value;
O << "(";
printOperand(MI, OpNo+1);
O << ")";
}
void
printS16ImmOperand(const MachineInstr *MI, unsigned OpNo)
{
O << (short) MI->getOperand(OpNo).getImm();
}
void
printU16ImmOperand(const MachineInstr *MI, unsigned OpNo)
{
O << (unsigned short)MI->getOperand(OpNo).getImm();
}
void
printU32ImmOperand(const MachineInstr *MI, unsigned OpNo)
{
O << (unsigned)MI->getOperand(OpNo).getImm();
}
void
printMemRegReg(const MachineInstr *MI, unsigned OpNo) {
const MachineOperand &MO = MI->getOperand(OpNo);
O << TM.getRegisterInfo()->get(MO.getReg()).AsmName;
O << ", ";
printOperand(MI, OpNo+1);
}
void
printU18ImmOperand(const MachineInstr *MI, unsigned OpNo)
{
unsigned int value = MI->getOperand(OpNo).getImm();
assert(value <= (1 << 19) - 1 && "Invalid u18 argument");
O << value;
}
void
printS10ImmOperand(const MachineInstr *MI, unsigned OpNo)
{
short value = (short) (((int) MI->getOperand(OpNo).getImm() << 16)
>> 16);
assert((value >= -(1 << 9) && value <= (1 << 9) - 1)
&& "Invalid s10 argument");
O << value;
}
void
printU10ImmOperand(const MachineInstr *MI, unsigned OpNo)
{
short value = (short) (((int) MI->getOperand(OpNo).getImm() << 16)
>> 16);
assert((value <= (1 << 10) - 1) && "Invalid u10 argument");
O << value;
}
void
printDFormAddr(const MachineInstr *MI, unsigned OpNo)
{
assert(MI->getOperand(OpNo).isImm() &&
"printDFormAddr first operand is not immediate");
int64_t value = int64_t(MI->getOperand(OpNo).getImm());
int16_t value16 = int16_t(value);
assert((value16 >= -(1 << (9+4)) && value16 <= (1 << (9+4)) - 1)
&& "Invalid dform s10 offset argument");
O << (value16 & ~0xf) << "(";
printOperand(MI, OpNo+1);
O << ")";
}
void
printAddr256K(const MachineInstr *MI, unsigned OpNo)
{
if (MI->getOperand(OpNo).isImm()) {
printS16ImmOperand(MI, OpNo);
} else {
printOp(MI->getOperand(OpNo));
if (MI->getOperand(OpNo+1).isImm()) {
int displ = int(MI->getOperand(OpNo+1).getImm());
if (displ > 0)
O << "+" << displ;
else if (displ < 0)
O << displ;
}
}
}
void printCallOperand(const MachineInstr *MI, unsigned OpNo) {
printOp(MI->getOperand(OpNo));
}
void printPCRelativeOperand(const MachineInstr *MI, unsigned OpNo) {
printOp(MI->getOperand(OpNo));
}
void printHBROperand(const MachineInstr *MI, unsigned OpNo) {
O << ".+";
printOp(MI->getOperand(OpNo));
}
void printSymbolHi(const MachineInstr *MI, unsigned OpNo) {
if (MI->getOperand(OpNo).isImm()) {
printS16ImmOperand(MI, OpNo);
} else {
printOp(MI->getOperand(OpNo));
O << "@h";
}
}
void printSymbolLo(const MachineInstr *MI, unsigned OpNo) {
if (MI->getOperand(OpNo).isImm()) {
printS16ImmOperand(MI, OpNo);
} else {
printOp(MI->getOperand(OpNo));
O << "@l";
}
}
void printSymbolLSA(const MachineInstr *MI, unsigned OpNo) {
printOp(MI->getOperand(OpNo));
}
void printROTHNeg7Imm(const MachineInstr *MI, unsigned OpNo) {
if (MI->getOperand(OpNo).isImm()) {
int value = (int) MI->getOperand(OpNo).getImm();
assert((value >= 0 && value < 16)
&& "Invalid negated immediate rotate 7-bit argument");
O << -value;
} else {
assert(0 &&"Invalid/non-immediate rotate amount in printRotateNeg7Imm");
}
}
void printROTNeg7Imm(const MachineInstr *MI, unsigned OpNo) {
if (MI->getOperand(OpNo).isImm()) {
int value = (int) MI->getOperand(OpNo).getImm();
assert((value >= 0 && value <= 32)
&& "Invalid negated immediate rotate 7-bit argument");
O << -value;
} else {
assert(0 &&"Invalid/non-immediate rotate amount in printRotateNeg7Imm");
}
}
virtual bool runOnMachineFunction(MachineFunction &F) = 0;
virtual bool doFinalization(Module &M) = 0;
};
class VISIBILITY_HIDDEN LinuxAsmPrinter : public SPUAsmPrinter {
DwarfWriter *DW;
MachineModuleInfo *MMI;
public:
explicit LinuxAsmPrinter(raw_ostream &O, SPUTargetMachine &TM,
const TargetAsmInfo *T, CodeGenOpt::Level F,
bool V)
: SPUAsmPrinter(O, TM, T, F, V), DW(0), MMI(0) {}
virtual const char *getPassName() const {
return "STI CBEA SPU Assembly Printer";
}
bool runOnMachineFunction(MachineFunction &F);
bool doInitialization(Module &M);
bool doFinalization(Module &M);
void getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
AU.addRequired<MachineModuleInfo>();
AU.addRequired<DwarfWriter>();
SPUAsmPrinter::getAnalysisUsage(AU);
}
void printModuleLevelGV(const GlobalVariable* GVar);
};
}
#include "SPUGenAsmWriter.inc"
void SPUAsmPrinter::printOp(const MachineOperand &MO) {
switch (MO.getType()) {
case MachineOperand::MO_Immediate:
cerr << "printOp() does not handle immediate values\n";
abort();
return;
case MachineOperand::MO_MachineBasicBlock:
printBasicBlockLabel(MO.getMBB());
return;
case MachineOperand::MO_JumpTableIndex:
O << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
<< '_' << MO.getIndex();
return;
case MachineOperand::MO_ConstantPoolIndex:
O << TAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
<< '_' << MO.getIndex();
return;
case MachineOperand::MO_ExternalSymbol:
if (TM.getRelocationModel() != Reloc::Static) {
std::string Name(TAI->getGlobalPrefix()); Name += MO.getSymbolName();
GVStubs.insert(Name);
O << "L" << Name << "$non_lazy_ptr";
return;
}
O << TAI->getGlobalPrefix() << MO.getSymbolName();
return;
case MachineOperand::MO_GlobalAddress: {
GlobalValue *GV = MO.getGlobal();
std::string Name = Mang->getValueName(GV);
if (TM.getRelocationModel() != Reloc::Static) {
if (((GV->isDeclaration() || GV->hasWeakLinkage() ||
GV->hasLinkOnceLinkage() || GV->hasCommonLinkage()))) {
GVStubs.insert(Name);
O << "L" << Name << "$non_lazy_ptr";
return;
}
}
O << Name;
if (GV->hasExternalWeakLinkage())
ExtWeakSymbols.insert(GV);
return;
}
default:
O << "<unknown operand type: " << MO.getType() << ">";
return;
}
}
bool SPUAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant,
const char *ExtraCode) {
if (ExtraCode && ExtraCode[0]) {
if (ExtraCode[1] != 0) return true;
switch (ExtraCode[0]) {
default: return true; case 'L': if (!MI->getOperand(OpNo).isReg() ||
OpNo+1 == MI->getNumOperands() ||
!MI->getOperand(OpNo+1).isReg())
return true;
++OpNo; break;
}
}
printOperand(MI, OpNo);
return false;
}
bool SPUAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
unsigned OpNo,
unsigned AsmVariant,
const char *ExtraCode) {
if (ExtraCode && ExtraCode[0])
return true; printMemRegReg(MI, OpNo);
return false;
}
void SPUAsmPrinter::printMachineInstruction(const MachineInstr *MI) {
++EmittedInsts;
printInstruction(MI);
}
bool
LinuxAsmPrinter::runOnMachineFunction(MachineFunction &MF)
{
this->MF = &MF;
SetupMachineFunction(MF);
O << "\n\n";
EmitConstantPool(MF.getConstantPool());
const Function *F = MF.getFunction();
SwitchToSection(TAI->SectionForGlobal(F));
EmitAlignment(3, F);
switch (F->getLinkage()) {
default: assert(0 && "Unknown linkage type!");
case Function::PrivateLinkage:
case Function::InternalLinkage: break;
case Function::ExternalLinkage:
O << "\t.global\t" << CurrentFnName << "\n"
<< "\t.type\t" << CurrentFnName << ", @function\n";
break;
case Function::WeakAnyLinkage:
case Function::WeakODRLinkage:
case Function::LinkOnceAnyLinkage:
case Function::LinkOnceODRLinkage:
O << "\t.global\t" << CurrentFnName << "\n";
O << "\t.weak_definition\t" << CurrentFnName << "\n";
break;
}
O << CurrentFnName << ":\n";
DW->BeginFunction(&MF);
for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
I != E; ++I) {
if (I != MF.begin()) {
printBasicBlockLabel(I, true, true);
O << '\n';
}
for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
II != E; ++II) {
printMachineInstruction(II);
}
}
O << "\t.size\t" << CurrentFnName << ",.-" << CurrentFnName << "\n";
EmitJumpTableInfo(MF.getJumpTableInfo(), MF);
DW->EndFunction(&MF);
return false;
}
bool LinuxAsmPrinter::doInitialization(Module &M) {
bool Result = AsmPrinter::doInitialization(M);
SwitchToTextSection("\t.text");
DW = getAnalysisIfAvailable<DwarfWriter>();
assert(DW && "Dwarf Writer is not available");
MMI = getAnalysisIfAvailable<MachineModuleInfo>();
DW->BeginModule(&M, MMI, O, this, TAI);
return Result;
}
static void PrintUnmangledNameSafely(const Value *V, raw_ostream &OS) {
for (const char *Name = V->getNameStart(), *E = Name+V->getNameLen();
Name != E; ++Name)
if (isprint(*Name))
OS << *Name;
}
void LinuxAsmPrinter::printModuleLevelGV(const GlobalVariable* GVar) {
const TargetData *TD = TM.getTargetData();
if (!GVar->hasInitializer())
return;
if (EmitSpecialLLVMGlobal(GVar))
return;
std::string name = Mang->getValueName(GVar);
printVisibility(name, GVar->getVisibility());
Constant *C = GVar->getInitializer();
const Type *Type = C->getType();
unsigned Size = TD->getTypePaddedSize(Type);
unsigned Align = TD->getPreferredAlignmentLog(GVar);
SwitchToSection(TAI->SectionForGlobal(GVar));
if (C->isNullValue() &&
!GVar->hasSection() &&
(GVar->hasLocalLinkage() || GVar->hasExternalLinkage() ||
GVar->isWeakForLinker())) {
if (Size == 0) Size = 1;
if (GVar->hasExternalLinkage()) {
O << "\t.global " << name << '\n';
O << "\t.type " << name << ", @object\n";
O << name << ":\n";
O << "\t.zero " << Size << '\n';
} else if (GVar->hasLocalLinkage()) {
O << TAI->getLCOMMDirective() << name << ',' << Size;
} else {
O << ".comm " << name << ',' << Size;
}
O << "\t\t" << TAI->getCommentString() << " '";
PrintUnmangledNameSafely(GVar, O);
O << "'\n";
return;
}
switch (GVar->getLinkage()) {
case GlobalValue::LinkOnceAnyLinkage:
case GlobalValue::LinkOnceODRLinkage:
case GlobalValue::WeakAnyLinkage:
case GlobalValue::WeakODRLinkage:
case GlobalValue::CommonLinkage:
O << "\t.global " << name << '\n'
<< "\t.type " << name << ", @object\n"
<< "\t.weak " << name << '\n';
break;
case GlobalValue::AppendingLinkage:
case GlobalValue::ExternalLinkage:
O << "\t.global " << name << '\n'
<< "\t.type " << name << ", @object\n";
case GlobalValue::PrivateLinkage:
case GlobalValue::InternalLinkage:
break;
default:
cerr << "Unknown linkage type!";
abort();
}
EmitAlignment(Align, GVar);
O << name << ":\t\t\t\t" << TAI->getCommentString() << " '";
PrintUnmangledNameSafely(GVar, O);
O << "'\n";
if (const GlobalValue *GV = dyn_cast<GlobalValue>(C))
if (GV->hasExternalWeakLinkage())
ExtWeakSymbols.insert(GV);
EmitGlobalConstant(C);
O << '\n';
}
bool LinuxAsmPrinter::doFinalization(Module &M) {
for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
I != E; ++I)
printModuleLevelGV(I);
DW->EndModule();
return AsmPrinter::doFinalization(M);
}
FunctionPass *llvm::createSPUAsmPrinterPass(raw_ostream &o,
SPUTargetMachine &tm,
CodeGenOpt::Level OptLevel,
bool verbose) {
return new LinuxAsmPrinter(o, tm, tm.getTargetAsmInfo(), OptLevel, verbose);
}