Implement ELF object file writing support for the MBlaze backend. Its not perfect yet, but it works for many tests.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@119952 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Target/MBlaze/MBlazeAsmBackend.cpp b/lib/Target/MBlaze/MBlazeAsmBackend.cpp
index 6fc36f7..fcf5de0 100644
--- a/lib/Target/MBlaze/MBlazeAsmBackend.cpp
+++ b/lib/Target/MBlaze/MBlazeAsmBackend.cpp
@@ -9,14 +9,18 @@
 
 #include "llvm/Target/TargetAsmBackend.h"
 #include "MBlaze.h"
+#include "MBlazeELFWriterInfo.h"
 #include "MBlazeFixupKinds.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCAsmLayout.h"
+#include "llvm/MC/MCELFSymbolFlags.h"
 #include "llvm/MC/MCExpr.h"
 #include "llvm/MC/MCObjectFormat.h"
 #include "llvm/MC/MCObjectWriter.h"
 #include "llvm/MC/MCSectionELF.h"
 #include "llvm/MC/MCSectionMachO.h"
+#include "llvm/MC/MCValue.h"
 #include "llvm/Support/ELF.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
@@ -55,13 +59,29 @@
   }
 };
 
+static unsigned getRelaxedOpcode(unsigned Op) {
+    switch (Op) {
+    default:            return Op;
+    case MBlaze::ADDI:  return MBlaze::ADDI32;
+    case MBlaze::ORI:   return MBlaze::ORI32;
+    case MBlaze::BRLID: return MBlaze::BRLID32;
+    }
+}
+
 bool MBlazeAsmBackend::MayNeedRelaxation(const MCInst &Inst) const {
-  return false;
+  if (getRelaxedOpcode(Inst.getOpcode()) == Inst.getOpcode())
+    return false;
+
+  bool hasExprOrImm = false;
+  for (unsigned i = 0; i < Inst.getNumOperands(); ++i)
+    hasExprOrImm |= Inst.getOperand(i).isExpr();
+
+  return hasExprOrImm;
 }
 
 void MBlazeAsmBackend::RelaxInstruction(const MCInst &Inst, MCInst &Res) const {
-  assert(0 && "MBlazeAsmBackend::RelaxInstruction() unimplemented");
-  return;
+  Res = Inst;
+  Res.setOpcode(getRelaxedOpcode(Inst.getOpcode()));
 }
 
 bool MBlazeAsmBackend::WriteNopData(uint64_t Count, MCObjectWriter *OW) const {
@@ -76,8 +96,6 @@
 } // end anonymous namespace
 
 namespace {
-// FIXME: This should be in a separate file.
-// ELF is an ELF of course...
 class ELFMBlazeAsmBackend : public MBlazeAsmBackend {
   MCELFObjectFormat Format;
 
@@ -97,7 +115,7 @@
                   uint64_t Value) const;
 
   MCObjectWriter *createObjectWriter(raw_ostream &OS) const {
-    return createELFObjectWriter(OS, /*Is64Bit=*/false,
+    return createELFObjectWriter(OS,/*Is64Bit=*/false,
                                  OSType, ELF::EM_MBLAZE,
                                  /*IsLittleEndian=*/false,
                                  /*HasRelocationAddend=*/true);
diff --git a/lib/Target/MBlaze/MBlazeELFWriterInfo.cpp b/lib/Target/MBlaze/MBlazeELFWriterInfo.cpp
index cf6312f..3f26ed1 100644
--- a/lib/Target/MBlaze/MBlazeELFWriterInfo.cpp
+++ b/lib/Target/MBlaze/MBlazeELFWriterInfo.cpp
@@ -14,6 +14,7 @@
 #include "MBlazeELFWriterInfo.h"
 #include "MBlazeRelocations.h"
 #include "llvm/Function.h"
+#include "llvm/Support/ELF.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Target/TargetData.h"
 #include "llvm/Target/TargetMachine.h"
@@ -34,9 +35,9 @@
 unsigned MBlazeELFWriterInfo::getRelocationType(unsigned MachineRelTy) const {
   switch (MachineRelTy) {
   case MBlaze::reloc_pcrel_word:
-    return R_MICROBLAZE_64_PCREL;
+    return ELF::R_MICROBLAZE_64_PCREL;
   case MBlaze::reloc_absolute_word:
-    return R_MICROBLAZE_NONE;
+    return ELF::R_MICROBLAZE_NONE;
   default:
     llvm_unreachable("unknown mblaze machine relocation type");
   }
@@ -46,9 +47,9 @@
 long int MBlazeELFWriterInfo::getDefaultAddendForRelTy(unsigned RelTy,
                                                     long int Modifier) const {
   switch (RelTy) {
-  case R_MICROBLAZE_32_PCREL:
+  case ELF::R_MICROBLAZE_32_PCREL:
     return Modifier - 4;
-  case R_MICROBLAZE_32:
+  case ELF::R_MICROBLAZE_32:
     return Modifier;
   default:
     llvm_unreachable("unknown mblaze relocation type");
@@ -59,22 +60,22 @@
 unsigned MBlazeELFWriterInfo::getRelocationTySize(unsigned RelTy) const {
   // FIXME: Most of these sizes are guesses based on the name
   switch (RelTy) {
-  case R_MICROBLAZE_32:
-  case R_MICROBLAZE_32_PCREL:
-  case R_MICROBLAZE_32_PCREL_LO:
-  case R_MICROBLAZE_32_LO:
-  case R_MICROBLAZE_SRO32:
-  case R_MICROBLAZE_SRW32:
-  case R_MICROBLAZE_32_SYM_OP_SYM:
-  case R_MICROBLAZE_GOTOFF_32:
+  case ELF::R_MICROBLAZE_32:
+  case ELF::R_MICROBLAZE_32_PCREL:
+  case ELF::R_MICROBLAZE_32_PCREL_LO:
+  case ELF::R_MICROBLAZE_32_LO:
+  case ELF::R_MICROBLAZE_SRO32:
+  case ELF::R_MICROBLAZE_SRW32:
+  case ELF::R_MICROBLAZE_32_SYM_OP_SYM:
+  case ELF::R_MICROBLAZE_GOTOFF_32:
     return 32;
 
-  case R_MICROBLAZE_64_PCREL:
-  case R_MICROBLAZE_64:
-  case R_MICROBLAZE_GOTPC_64:
-  case R_MICROBLAZE_GOT_64:
-  case R_MICROBLAZE_PLT_64:
-  case R_MICROBLAZE_GOTOFF_64:
+  case ELF::R_MICROBLAZE_64_PCREL:
+  case ELF::R_MICROBLAZE_64:
+  case ELF::R_MICROBLAZE_GOTPC_64:
+  case ELF::R_MICROBLAZE_GOT_64:
+  case ELF::R_MICROBLAZE_PLT_64:
+  case ELF::R_MICROBLAZE_GOTOFF_64:
     return 64;
   }
 
@@ -84,10 +85,10 @@
 bool MBlazeELFWriterInfo::isPCRelativeRel(unsigned RelTy) const {
   // FIXME: Most of these are guesses based on the name
   switch (RelTy) {
-  case R_MICROBLAZE_32_PCREL:
-  case R_MICROBLAZE_64_PCREL:
-  case R_MICROBLAZE_32_PCREL_LO:
-  case R_MICROBLAZE_GOTPC_64:
+  case ELF::R_MICROBLAZE_32_PCREL:
+  case ELF::R_MICROBLAZE_64_PCREL:
+  case ELF::R_MICROBLAZE_32_PCREL_LO:
+  case ELF::R_MICROBLAZE_GOTPC_64:
     return true;
   }
 
@@ -101,7 +102,7 @@
 long int MBlazeELFWriterInfo::computeRelocation(unsigned SymOffset,
                                                 unsigned RelOffset,
                                                 unsigned RelTy) const {
-  if (RelTy == R_MICROBLAZE_32_PCREL || R_MICROBLAZE_64_PCREL)
+  if (RelTy == ELF::R_MICROBLAZE_32_PCREL || ELF::R_MICROBLAZE_64_PCREL)
     return SymOffset - (RelOffset + 4);
   else
     assert("computeRelocation unknown for this relocation type");
diff --git a/lib/Target/MBlaze/MBlazeELFWriterInfo.h b/lib/Target/MBlaze/MBlazeELFWriterInfo.h
index abea992..63bfc0d 100644
--- a/lib/Target/MBlaze/MBlazeELFWriterInfo.h
+++ b/lib/Target/MBlaze/MBlazeELFWriterInfo.h
@@ -19,33 +19,6 @@
 namespace llvm {
 
   class MBlazeELFWriterInfo : public TargetELFWriterInfo {
-
-    // ELF Relocation types for MBlaze
-    enum MBlazeRelocationType {
-      R_MICROBLAZE_NONE = 0,
-      R_MICROBLAZE_32 = 1,
-      R_MICROBLAZE_32_PCREL = 2,
-      R_MICROBLAZE_64_PCREL = 3,
-      R_MICROBLAZE_32_PCREL_LO = 4,
-      R_MICROBLAZE_64 = 5,
-      R_MICROBLAZE_32_LO = 6,
-      R_MICROBLAZE_SRO32 = 7,
-      R_MICROBLAZE_SRW32 = 8,
-      R_MICROBLAZE_64_NONE = 9,
-      R_MICROBLAZE_32_SYM_OP_SYM = 10,
-      R_MICROBLAZE_GNU_VTINHERIT = 11,
-      R_MICROBLAZE_GNU_VTENTRY = 12,
-      R_MICROBLAZE_GOTPC_64 = 13,
-      R_MICROBLAZE_GOT_64 = 14,
-      R_MICROBLAZE_PLT_64 = 15,
-      R_MICROBLAZE_REL = 16,
-      R_MICROBLAZE_JUMP_SLOT = 17,
-      R_MICROBLAZE_GLOB_DAT = 18,
-      R_MICROBLAZE_GOTOFF_64 = 19,
-      R_MICROBLAZE_GOTOFF_32 = 20,
-      R_MICROBLAZE_COPY = 21
-    };
-
   public:
     MBlazeELFWriterInfo(TargetMachine &TM);
     virtual ~MBlazeELFWriterInfo();
diff --git a/lib/Target/MBlaze/MBlazeInstrInfo.td b/lib/Target/MBlaze/MBlazeInstrInfo.td
index 7c6c9aa..e1f68d2 100644
--- a/lib/Target/MBlaze/MBlazeInstrInfo.td
+++ b/lib/Target/MBlaze/MBlazeInstrInfo.td
@@ -169,6 +169,11 @@
                 !strconcat(instr_asm, "   $dst, $b, $c"),
                 [(set GPR:$dst, (OpNode GPR:$b, imm_type:$c))], IIAlu>;
 
+class ArithI32<bits<6> op, string instr_asm,Operand Od, PatLeaf imm_type> :
+               TB<op, (outs GPR:$dst), (ins GPR:$b, Od:$c),
+                  !strconcat(instr_asm, "   $dst, $b, $c"),
+                  [], IIAlu>;
+
 class ShiftI<bits<6> op, bits<2> flags, string instr_asm, SDNode OpNode,
              Operand Od, PatLeaf imm_type> :
              SHT<op, flags, (outs GPR:$dst), (ins GPR:$b, Od:$c),
@@ -224,6 +229,11 @@
                 [(set GPR:$dst, (OpNode GPR:$b, immZExt16:$c))],
                 IIAlu>;
 
+class LogicI32<bits<6> op, string instr_asm> :
+               TB<op, (outs GPR:$dst), (ins GPR:$b, uimm16:$c),
+                  !strconcat(instr_asm, "   $dst, $b, $c"),
+                  [], IIAlu>;
+
 class PatCmp<bits<6> op, bits<11> flags, string instr_asm> :
              TA<op, flags, (outs GPR:$dst), (ins GPR:$b, GPR:$c),
                 !strconcat(instr_asm, "   $dst, $b, $c"),
@@ -578,10 +588,10 @@
                   "src       $dst, $src", [], IIAlu>;
 }
 
-let opcode=0x08, isCodeGenOnly=1 in {
-  def LEA_ADDI : TB<0x08, (outs GPR:$dst), (ins memri:$addr),
-                    "addi     $dst, ${addr:stackloc}",
-                    [(set GPR:$dst, iaddr:$addr)], IIAlu>;
+let isCodeGenOnly=1 in {
+  def ADDI32  : ArithI32<0x08, "addi   ", simm16, immSExt16>;
+  def ORI32   : LogicI32<0x28, "ori    ">;
+  def BRLID32 : BranchLI<0x2E, 0x14, "brlid  ">;
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/lib/Target/MBlaze/MBlazeMCCodeEmitter.cpp b/lib/Target/MBlaze/MBlazeMCCodeEmitter.cpp
index 19dc89b..625c73f 100644
--- a/lib/Target/MBlaze/MBlazeMCCodeEmitter.cpp
+++ b/lib/Target/MBlaze/MBlazeMCCodeEmitter.cpp
@@ -58,8 +58,9 @@
 
   const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const {
     const static MCFixupKindInfo Infos[] = {
-      { "reloc_pcrel_4byte", 0, 4 * 8, MCFixupKindInfo::FKF_IsPCRel },
-      { "reloc_pcrel_2byte", 0, 2 * 8, MCFixupKindInfo::FKF_IsPCRel } };
+      // name                offset  bits    flags
+      { "reloc_pcrel_4byte", 2,      4 * 8,  MCFixupKindInfo::FKF_IsPCRel },
+      { "reloc_pcrel_2byte", 2,      2 * 8,  MCFixupKindInfo::FKF_IsPCRel } };
 
     if (Kind < FirstTargetFixupKind)
       return MCCodeEmitter::getFixupKindInfo(Kind);
@@ -103,11 +104,9 @@
   }
 
   void EmitIMM(const MCOperand &imm, unsigned &CurByte, raw_ostream &OS) const;
-  void EmitIMM(const MCInst &MI, unsigned op, unsigned &CurByte,
-               raw_ostream &OS) const;
+  void EmitIMM(const MCInst &MI, unsigned &CurByte, raw_ostream &OS) const;
 
-  void EmitImmediate(const MCInst &MI,
-                     unsigned opNo, MCFixupKind FixupKind,
+  void EmitImmediate(const MCInst &MI, unsigned opNo, bool pcrel,
                      unsigned &CurByte, raw_ostream &OS,
                      SmallVectorImpl<MCFixup> &Fixups) const;
 
@@ -155,28 +154,43 @@
 }
 
 void MBlazeMCCodeEmitter::
-EmitIMM(const MCInst &MI, unsigned op, unsigned &CurByte,
-        raw_ostream &OS) const {
-    MCOperand mcop = MI.getOperand(op);
-    if (mcop.isExpr()) {
-        EmitByte(0x0D, CurByte, OS);
-        EmitByte(0x00, CurByte, OS);
-        EmitRawByte(0, CurByte, OS);
-        EmitRawByte(0, CurByte, OS);
-    }
+EmitIMM(const MCInst &MI, unsigned &CurByte,raw_ostream &OS) const {
+  switch (MI.getOpcode()) {
+  default: break;
+
+  case MBlaze::ADDI32:
+  case MBlaze::ORI32:
+  case MBlaze::BRLID32:
+    EmitByte(0x0D, CurByte, OS);
+    EmitByte(0x00, CurByte, OS);
+    EmitRawByte(0, CurByte, OS);
+    EmitRawByte(0, CurByte, OS);
+  }
 }
 
 void MBlazeMCCodeEmitter::
-EmitImmediate(const MCInst &MI, unsigned opNo, MCFixupKind FixupKind,
-              unsigned &CurByte, raw_ostream &OS,
-              SmallVectorImpl<MCFixup> &Fixups) const {
+EmitImmediate(const MCInst &MI, unsigned opNo, bool pcrel, unsigned &CurByte,
+              raw_ostream &OS, SmallVectorImpl<MCFixup> &Fixups) const {
   assert(MI.getNumOperands()>opNo && "Not enought operands for instruction");
 
   MCOperand oper = MI.getOperand(opNo);
+
   if (oper.isImm()) {
-      EmitIMM(oper, CurByte, OS);
+    EmitIMM(oper, CurByte, OS);
   } else if (oper.isExpr()) {
+    MCFixupKind FixupKind;
+    switch (MI.getOpcode()) {
+    default:
+      FixupKind = pcrel ? MCFixupKind(MBlaze::reloc_pcrel_2byte) : FK_Data_2;
       Fixups.push_back(MCFixup::Create(0,oper.getExpr(),FixupKind));
+      break;
+    case MBlaze::ORI32:
+    case MBlaze::ADDI32:
+    case MBlaze::BRLID32:
+      FixupKind = pcrel ? MCFixupKind(MBlaze::reloc_pcrel_4byte) : FK_Data_4;
+      Fixups.push_back(MCFixup::Create(0,oper.getExpr(),FixupKind));
+      break;
+    }
   }
 }
 
@@ -191,56 +205,33 @@
   // Keep track of the current byte being emitted.
   unsigned CurByte = 0;
 
+  // Emit an IMM instruction if the instruction we are encoding requires it
+  EmitIMM(MI,CurByte,OS);
+
   switch ((TSFlags & MBlazeII::FormMask)) {
   default: break;
   case MBlazeII::FPseudo:
     // Pseudo instructions don't get encoded.
     return;
-
   case MBlazeII::FRRI:
-    EmitImmediate(MI, 2, FK_Data_4, CurByte, OS, Fixups);
+    EmitImmediate(MI, 2, false, CurByte, OS, Fixups);
     break;
-
   case MBlazeII::FRIR:
-    EmitImmediate(MI, 1, FK_Data_4, CurByte, OS, Fixups);
+    EmitImmediate(MI, 1, false, CurByte, OS, Fixups);
     break;
-
   case MBlazeII::FCRI:
-    EmitImmediate(MI, 1, MCFixupKind(MBlaze::reloc_pcrel_2byte), CurByte, OS,
-                  Fixups);
+    EmitImmediate(MI, 1, true, CurByte, OS, Fixups);
     break;
-
   case MBlazeII::FRCI:
-    EmitImmediate(MI, 1, MCFixupKind(MBlaze::reloc_pcrel_4byte), CurByte, OS,
-                  Fixups);
-
+    EmitImmediate(MI, 1, true, CurByte, OS, Fixups);
   case MBlazeII::FCCI:
-    EmitImmediate(MI, 0, MCFixupKind(MBlaze::reloc_pcrel_4byte), CurByte, OS,
-                  Fixups);
+    EmitImmediate(MI, 0, true, CurByte, OS, Fixups);
     break;
   }
 
   ++MCNumEmitted;  // Keep track of the # of mi's emitted
   unsigned Value = getBinaryCodeForInstr(MI);
-  switch (Opcode) {
-  default:
-    EmitConstant(Value, 4, CurByte, OS);
-    break;
-
-  case MBlaze::BRLID:
-  case MBlaze::BRALID:
-    EmitIMM(MI,1,CurByte,OS);
-    EmitConstant(Value, 4, CurByte, OS);
-    break;
-
-  case MBlaze::BRI:
-  case MBlaze::BRAI:
-  case MBlaze::BRID:
-  case MBlaze::BRAID:
-    EmitIMM(MI,0,CurByte,OS);
-    EmitConstant(Value, 4, CurByte, OS);
-    break;
-  }
+  EmitConstant(Value, 4, CurByte, OS);
 }
 
 // FIXME: These #defines shouldn't be necessary. Instead, tblgen should