several major improvements to the sparc backend: support for weak linkage

and PIC codegen.  Patch by Venkatraman Govindaraju!



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@81877 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner
2009-09-15 17:46:24 +00:00
parent 307a7c48f1
commit db486a6d53
10 changed files with 212 additions and 48 deletions
+70 -12
View File
@@ -75,12 +75,14 @@ namespace {
unsigned AsmVariant, const char *ExtraCode);
bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant, const char *ExtraCode);
void emitFunctionHeader(const MachineFunction &MF);
bool printGetPCX(const MachineInstr *MI, unsigned OpNo);
};
} // end of anonymous namespace
#include "SparcGenAsmWriter.inc"
/// runOnMachineFunction - This uses the printInstruction()
/// method to print assembly for each instruction.
///
@@ -96,17 +98,9 @@ bool SparcAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
// BBs the same name. (If you have a better way, please let me know!)
O << "\n\n";
// Print out the label for the function.
const Function *F = MF.getFunction();
OutStreamer.SwitchSection(getObjFileLowering().SectionForGlobal(F, Mang, TM));
EmitAlignment(MF.getAlignment(), F);
O << "\t.globl\t" << CurrentFnName << '\n';
printVisibility(CurrentFnName, F->getVisibility());
O << "\t.type\t" << CurrentFnName << ", #function\n";
O << CurrentFnName << ":\n";
emitFunctionHeader(MF);
// Emit pre-function debug information.
DW->BeginFunction(&MF);
@@ -145,9 +139,43 @@ bool SparcAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
DW->EndFunction(&MF);
// We didn't modify anything.
O << "\t.size\t" << CurrentFnName << ", .-" << CurrentFnName << '\n';
return false;
}
void SparcAsmPrinter::emitFunctionHeader(const MachineFunction &MF) {
const Function *F = MF.getFunction();
OutStreamer.SwitchSection(getObjFileLowering().SectionForGlobal(F, Mang, TM));
EmitAlignment(MF.getAlignment(), F);
switch (F->getLinkage()) {
default: llvm_unreachable("Unknown linkage type");
case Function::PrivateLinkage:
case Function::InternalLinkage:
// Function is internal.
break;
case Function::DLLExportLinkage:
case Function::ExternalLinkage:
// Function is externally visible
O << "\t.global\t" << CurrentFnName << '\n';
break;
case Function::LinkerPrivateLinkage:
case Function::LinkOnceAnyLinkage:
case Function::LinkOnceODRLinkage:
case Function::WeakAnyLinkage:
case Function::WeakODRLinkage:
// Function is weak
O << "\t.weak\t" << CurrentFnName << '\n' ;
break;
}
printVisibility(CurrentFnName, F->getVisibility());
O << "\t.type\t" << CurrentFnName << ", #function\n";
O << CurrentFnName << ":\n";
}
void SparcAsmPrinter::printOperand(const MachineInstr *MI, int opNum) {
const MachineOperand &MO = MI->getOperand (opNum);
bool CloseParen = false;
@@ -215,6 +243,36 @@ void SparcAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum,
}
}
bool SparcAsmPrinter::printGetPCX(const MachineInstr *MI, unsigned opNum) {
std::string operand = "";
const MachineOperand &MO = MI->getOperand(opNum);
switch (MO.getType()) {
default: assert(0 && "Operand is not a register ");
case MachineOperand::MO_Register:
assert(TargetRegisterInfo::isPhysicalRegister(MO.getReg()) &&
"Operand is not a physical register ");
operand = "%" + LowercaseString(getRegisterName(MO.getReg()));
break;
}
unsigned bbNum = NumberForBB[MI->getParent()->getBasicBlock()];
O << '\n' << ".LLGETPCH" << bbNum << ":\n";
O << "\tcall\t.LLGETPC" << bbNum << '\n' ;
O << "\t sethi\t"
<< "%hi(_GLOBAL_OFFSET_TABLE_+(.-.LLGETPCH" << bbNum << ")), "
<< operand << '\n' ;
O << ".LLGETPC" << bbNum << ":\n" ;
O << "\tor\t" << operand
<< ", %lo(_GLOBAL_OFFSET_TABLE_+(.-.LLGETPCH" << bbNum << ")), "
<< operand << '\n';
O << "\tadd\t" << operand << ", %o7, " << operand << '\n';
return true;
}
void SparcAsmPrinter::printCCOperand(const MachineInstr *MI, int opNum) {
int CC = (int)MI->getOperand(opNum).getImm();
O << SPARCCondCodeToString((SPCC::CondCodes)CC);
+19 -4
View File
@@ -34,10 +34,13 @@ class SparcDAGToDAGISel : public SelectionDAGISel {
/// Subtarget - Keep a pointer to the Sparc Subtarget around so that we can
/// make the right decision when generating code for different targets.
const SparcSubtarget &Subtarget;
SparcTargetMachine& TM;
MachineBasicBlock *CurBB;
public:
explicit SparcDAGToDAGISel(SparcTargetMachine &TM)
: SelectionDAGISel(TM),
Subtarget(TM.getSubtarget<SparcSubtarget>()) {
explicit SparcDAGToDAGISel(SparcTargetMachine &tm)
: SelectionDAGISel(tm),
Subtarget(tm.getSubtarget<SparcSubtarget>()),
TM(tm) {
}
SDNode *Select(SDValue Op);
@@ -63,6 +66,9 @@ public:
// Include the pieces autogenerated from the target description.
#include "SparcGenDAGISel.inc"
private:
SDNode* getGlobalBaseReg();
};
} // end anonymous namespace
@@ -70,12 +76,18 @@ public:
/// SelectionDAGISel when it has created a SelectionDAG for us to codegen.
void SparcDAGToDAGISel::InstructionSelect() {
DEBUG(BB->dump());
CurBB = BB;
// Select target instructions for the DAG.
SelectRoot(*CurDAG);
CurDAG->RemoveDeadNodes();
}
SDNode* SparcDAGToDAGISel::getGlobalBaseReg() {
MachineFunction *MF = CurBB->getParent();
unsigned GlobalBaseReg = TM.getInstrInfo()->getGlobalBaseReg(MF);
return CurDAG->getRegister(GlobalBaseReg, TLI.getPointerTy()).getNode();
}
bool SparcDAGToDAGISel::SelectADDRri(SDValue Op, SDValue Addr,
SDValue &Base, SDValue &Offset) {
if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
@@ -149,6 +161,9 @@ SDNode *SparcDAGToDAGISel::Select(SDValue Op) {
switch (N->getOpcode()) {
default: break;
case SPISD::GLOBAL_BASE_REG:
return getGlobalBaseReg();
case ISD::SDIV:
case ISD::UDIV: {
// FIXME: should use a custom expander to expose the SRA to the dag.
+28 -7
View File
@@ -740,17 +740,29 @@ static void LookThroughSetCC(SDValue &LHS, SDValue &RHS,
}
}
static SDValue LowerGLOBALADDRESS(SDValue Op, SelectionDAG &DAG) {
SDValue SparcTargetLowering::LowerGlobalAddress(SDValue Op,
SelectionDAG &DAG) {
GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
// FIXME there isn't really any debug info here
DebugLoc dl = Op.getDebugLoc();
SDValue GA = DAG.getTargetGlobalAddress(GV, MVT::i32);
SDValue Hi = DAG.getNode(SPISD::Hi, dl, MVT::i32, GA);
SDValue Lo = DAG.getNode(SPISD::Lo, dl, MVT::i32, GA);
return DAG.getNode(ISD::ADD, dl, MVT::i32, Lo, Hi);
if (getTargetMachine().getRelocationModel() != Reloc::PIC_)
return DAG.getNode(ISD::ADD, dl, MVT::i32, Lo, Hi);
SDValue GlobalBase = DAG.getNode(SPISD::GLOBAL_BASE_REG, dl,
getPointerTy());
SDValue RelAddr = DAG.getNode(ISD::ADD, dl, MVT::i32, Lo, Hi);
SDValue AbsAddr = DAG.getNode(ISD::ADD, dl, MVT::i32,
GlobalBase, RelAddr);
return DAG.getLoad(getPointerTy(), dl, DAG.getEntryNode(),
AbsAddr, NULL, 0);
}
static SDValue LowerCONSTANTPOOL(SDValue Op, SelectionDAG &DAG) {
SDValue SparcTargetLowering::LowerConstantPool(SDValue Op,
SelectionDAG &DAG) {
ConstantPoolSDNode *N = cast<ConstantPoolSDNode>(Op);
// FIXME there isn't really any debug info here
DebugLoc dl = Op.getDebugLoc();
@@ -758,7 +770,16 @@ static SDValue LowerCONSTANTPOOL(SDValue Op, SelectionDAG &DAG) {
SDValue CP = DAG.getTargetConstantPool(C, MVT::i32, N->getAlignment());
SDValue Hi = DAG.getNode(SPISD::Hi, dl, MVT::i32, CP);
SDValue Lo = DAG.getNode(SPISD::Lo, dl, MVT::i32, CP);
return DAG.getNode(ISD::ADD, dl, MVT::i32, Lo, Hi);
if (getTargetMachine().getRelocationModel() != Reloc::PIC_)
return DAG.getNode(ISD::ADD, dl, MVT::i32, Lo, Hi);
SDValue GlobalBase = DAG.getNode(SPISD::GLOBAL_BASE_REG, dl,
getPointerTy());
SDValue RelAddr = DAG.getNode(ISD::ADD, dl, MVT::i32, Lo, Hi);
SDValue AbsAddr = DAG.getNode(ISD::ADD, dl, MVT::i32,
GlobalBase, RelAddr);
return DAG.getLoad(getPointerTy(), dl, DAG.getEntryNode(),
AbsAddr, NULL, 0);
}
static SDValue LowerFP_TO_SINT(SDValue Op, SelectionDAG &DAG) {
@@ -912,8 +933,8 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) {
case ISD::FRAMEADDR: return SDValue();
case ISD::GlobalTLSAddress:
llvm_unreachable("TLS not implemented for Sparc.");
case ISD::GlobalAddress: return LowerGLOBALADDRESS(Op, DAG);
case ISD::ConstantPool: return LowerCONSTANTPOOL(Op, DAG);
case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG);
case ISD::ConstantPool: return LowerConstantPool(Op, DAG);
case ISD::FP_TO_SINT: return LowerFP_TO_SINT(Op, DAG);
case ISD::SINT_TO_FP: return LowerSINT_TO_FP(Op, DAG);
case ISD::BR_CC: return LowerBR_CC(Op, DAG);
@@ -1054,5 +1075,5 @@ SparcTargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const {
/// getFunctionAlignment - Return the Log2 alignment of this function.
unsigned SparcTargetLowering::getFunctionAlignment(const Function *) const {
return 4;
return 2;
}
+5 -1
View File
@@ -35,7 +35,8 @@ namespace llvm {
ITOF, // Int to FP within a FP register.
CALL, // A call instruction.
RET_FLAG // Return with a flag operand.
RET_FLAG, // Return with a flag operand.
GLOBAL_BASE_REG // Global base reg for PIC
};
}
@@ -96,6 +97,9 @@ namespace llvm {
CallingConv::ID CallConv, bool isVarArg,
const SmallVectorImpl<ISD::OutputArg> &Outs,
DebugLoc dl, SelectionDAG &DAG);
SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG);
SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG);
};
} // end namespace llvm
+24
View File
@@ -17,8 +17,10 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Support/ErrorHandling.h"
#include "SparcGenInstrInfo.inc"
#include "SparcMachineFunctionInfo.h"
using namespace llvm;
SparcInstrInfo::SparcInstrInfo(SparcSubtarget &ST)
@@ -235,3 +237,25 @@ MachineInstr *SparcInstrInfo::foldMemoryOperandImpl(MachineFunction &MF,
return NewMI;
}
unsigned SparcInstrInfo::getGlobalBaseReg(MachineFunction *MF) const
{
SparcMachineFunctionInfo *SparcFI = MF->getInfo<SparcMachineFunctionInfo>();
unsigned GlobalBaseReg = SparcFI->getGlobalBaseReg();
if (GlobalBaseReg != 0)
return GlobalBaseReg;
// Insert the set of GlobalBaseReg into the first MBB of the function
MachineBasicBlock &FirstMBB = MF->front();
MachineBasicBlock::iterator MBBI = FirstMBB.begin();
MachineRegisterInfo &RegInfo = MF->getRegInfo();
GlobalBaseReg = RegInfo.createVirtualRegister(&SP::IntRegsRegClass);
DebugLoc dl = DebugLoc::getUnknownLoc();
BuildMI(FirstMBB, MBBI, dl, get(SP::GETPCX), GlobalBaseReg);
SparcFI->setGlobalBaseReg(GlobalBaseReg);
return GlobalBaseReg;
}
+2
View File
@@ -97,6 +97,8 @@ public:
MachineInstr* LoadMI) const {
return 0;
}
unsigned getGlobalBaseReg(MachineFunction *MF) const;
};
}
+39 -22
View File
@@ -134,6 +134,10 @@ def call : SDNode<"SPISD::CALL", SDT_SPCall,
def retflag : SDNode<"SPISD::RET_FLAG", SDTNone,
[SDNPHasChain, SDNPOptInFlag]>;
def getPCX : Operand<i32> {
let PrintMethod = "printGetPCX";
}
//===----------------------------------------------------------------------===//
// SPARC Flag Conditions
//===----------------------------------------------------------------------===//
@@ -207,6 +211,11 @@ multiclass F3_12np<string OpcStr, bits<6> Op3Val> {
class Pseudo<dag outs, dag ins, string asmstr, list<dag> pattern>
: InstSP<outs, ins, asmstr, pattern>;
// GETPCX for PIC
let Defs = [O7], Uses = [O7] in {
def GETPCX : Pseudo<(outs getPCX:$getpcseq), (ins), "$getpcseq", [] >;
}
let Defs = [O6], Uses = [O6] in {
def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i32imm:$amt),
"!ADJCALLSTACKDOWN $amt",
@@ -431,18 +440,23 @@ def LEA_ADDri : F3_2<2, 0b000000,
(outs IntRegs:$dst), (ins MEMri:$addr),
"add ${addr:arith}, $dst",
[(set IntRegs:$dst, ADDRri:$addr)]>;
defm ADDCC : F3_12<"addcc", 0b010000, addc>;
let Defs = [ICC] in
defm ADDCC : F3_12<"addcc", 0b010000, addc>;
defm ADDX : F3_12<"addx", 0b001000, adde>;
// Section B.15 - Subtract Instructions, p. 110
defm SUB : F3_12 <"sub" , 0b000100, sub>;
defm SUBX : F3_12 <"subx" , 0b001100, sube>;
defm SUBCC : F3_12 <"subcc", 0b010100, SPcmpicc>;
def SUBXCCrr: F3_1<2, 0b011100,
(outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c),
"subxcc $b, $c, $dst", []>;
let Defs = [ICC] in {
defm SUBCC : F3_12 <"subcc", 0b010100, SPcmpicc>;
def SUBXCCrr: F3_1<2, 0b011100,
(outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c),
"subxcc $b, $c, $dst", []>;
}
// Section B.18 - Multiply Instructions, p. 113
defm UMUL : F3_12np<"umul", 0b001010>;
@@ -471,11 +485,12 @@ let isBarrier = 1 in
def BA : BranchSP<0b1000, (ins brtarget:$dst),
"ba $dst",
[(br bb:$dst)]>;
// FIXME: the encoding for the JIT should look at the condition field.
def BCOND : BranchSP<0, (ins brtarget:$dst, CCOp:$cc),
"b$cc $dst",
[(SPbricc bb:$dst, imm:$cc)]>;
let Uses = [ICC] in
def BCOND : BranchSP<0, (ins brtarget:$dst, CCOp:$cc),
"b$cc $dst",
[(SPbricc bb:$dst, imm:$cc)]>;
// Section B.22 - Branch on Floating-point Condition Codes Instructions, p. 121
@@ -489,9 +504,10 @@ class FPBranchSP<bits<4> cc, dag ins, string asmstr, list<dag> pattern>
}
// FIXME: the encoding for the JIT should look at the condition field.
def FBCOND : FPBranchSP<0, (ins brtarget:$dst, CCOp:$cc),
"fb$cc $dst",
[(SPbrfcc bb:$dst, imm:$cc)]>;
let Uses = [FCC] in
def FBCOND : FPBranchSP<0, (ins brtarget:$dst, CCOp:$cc),
"fb$cc $dst",
[(SPbrfcc bb:$dst, imm:$cc)]>;
// Section B.24 - Call and Link Instruction, p. 125
@@ -633,15 +649,16 @@ def FDIVD : F3_3<2, 0b110100, 0b001001110,
// Note 2: the result of a FCMP is not available until the 2nd cycle
// after the instr is retired, but there is no interlock. This behavior
// is modelled with a forced noop after the instruction.
def FCMPS : F3_3<2, 0b110101, 0b001010001,
(outs), (ins FPRegs:$src1, FPRegs:$src2),
"fcmps $src1, $src2\n\tnop",
[(SPcmpfcc FPRegs:$src1, FPRegs:$src2)]>;
def FCMPD : F3_3<2, 0b110101, 0b001010010,
(outs), (ins DFPRegs:$src1, DFPRegs:$src2),
"fcmpd $src1, $src2\n\tnop",
[(SPcmpfcc DFPRegs:$src1, DFPRegs:$src2)]>;
let Defs = [FCC] in {
def FCMPS : F3_3<2, 0b110101, 0b001010001,
(outs), (ins FPRegs:$src1, FPRegs:$src2),
"fcmps $src1, $src2\n\tnop",
[(SPcmpfcc FPRegs:$src1, FPRegs:$src2)]>;
def FCMPD : F3_3<2, 0b110101, 0b001010010,
(outs), (ins DFPRegs:$src1, DFPRegs:$src2),
"fcmpd $src1, $src2\n\tnop",
[(SPcmpfcc DFPRegs:$src1, DFPRegs:$src2)]>;
}
//===----------------------------------------------------------------------===//
// V9 Instructions
+10 -2
View File
@@ -16,6 +16,10 @@ class SparcReg<string n> : Register<n> {
let Namespace = "SP";
}
class SparcCtrlReg<string n>: Register<n> {
let Namespace = "SP";
}
// Registers are identified with 5-bit ID numbers.
// Ri - 32-bit integer registers
class Ri<bits<5> num, string n> : SparcReg<n> {
@@ -31,6 +35,10 @@ class Rd<bits<5> num, string n, list<Register> subregs> : SparcReg<n> {
let SubRegs = subregs;
}
// Control Registers
def ICC : SparcCtrlReg<"ICC">;
def FCC : SparcCtrlReg<"FCC">;
// Integer registers
def G0 : Ri< 0, "G0">, DwarfRegNum<[0]>;
def G1 : Ri< 1, "G1">, DwarfRegNum<[1]>;
@@ -46,7 +54,7 @@ def O2 : Ri<10, "O2">, DwarfRegNum<[10]>;
def O3 : Ri<11, "O3">, DwarfRegNum<[11]>;
def O4 : Ri<12, "O4">, DwarfRegNum<[12]>;
def O5 : Ri<13, "O5">, DwarfRegNum<[13]>;
def O6 : Ri<14, "O6">, DwarfRegNum<[14]>;
def O6 : Ri<14, "SP">, DwarfRegNum<[14]>;
def O7 : Ri<15, "O7">, DwarfRegNum<[15]>;
def L0 : Ri<16, "L0">, DwarfRegNum<[16]>;
def L1 : Ri<17, "L1">, DwarfRegNum<[17]>;
@@ -62,7 +70,7 @@ def I2 : Ri<26, "I2">, DwarfRegNum<[26]>;
def I3 : Ri<27, "I3">, DwarfRegNum<[27]>;
def I4 : Ri<28, "I4">, DwarfRegNum<[28]>;
def I5 : Ri<29, "I5">, DwarfRegNum<[29]>;
def I6 : Ri<30, "I6">, DwarfRegNum<[30]>;
def I6 : Ri<30, "FP">, DwarfRegNum<[30]>;
def I7 : Ri<31, "I7">, DwarfRegNum<[31]>;
// Floating-point registers
+9
View File
@@ -0,0 +1,9 @@
; RUN: llvm-as < %s | llc -march=sparc --relocation-model=pic | grep _GLOBAL_OFFSET_TABLE_
@foo = global i32 0 ; <i32*> [#uses=1]
define i32 @func() nounwind readonly {
entry:
%0 = load i32* @foo, align 4 ; <i32> [#uses=1]
ret i32 %0
}
@@ -0,0 +1,6 @@
; RUN: llvm-as < %s | llc -march=sparc | grep weak
define weak i32 @func() nounwind {
entry:
ret i32 0
}