Home | History | Annotate | Download | only in MCTargetDesc
      1 //===-- MBlazeAsmBackend.cpp - MBlaze Assembler Backend -------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "MCTargetDesc/MBlazeMCTargetDesc.h"
     11 #include "llvm/MC/MCAsmBackend.h"
     12 #include "llvm/MC/MCAssembler.h"
     13 #include "llvm/MC/MCAsmLayout.h"
     14 #include "llvm/MC/MCELFObjectWriter.h"
     15 #include "llvm/MC/MCELFSymbolFlags.h"
     16 #include "llvm/MC/MCExpr.h"
     17 #include "llvm/MC/MCObjectWriter.h"
     18 #include "llvm/MC/MCSectionELF.h"
     19 #include "llvm/MC/MCSectionMachO.h"
     20 #include "llvm/MC/MCValue.h"
     21 #include "llvm/ADT/Twine.h"
     22 #include "llvm/Support/ELF.h"
     23 #include "llvm/Support/ErrorHandling.h"
     24 #include "llvm/Support/TargetRegistry.h"
     25 #include "llvm/Support/raw_ostream.h"
     26 using namespace llvm;
     27 
     28 static unsigned getFixupKindSize(unsigned Kind) {
     29   switch (Kind) {
     30   default: llvm_unreachable("invalid fixup kind!");
     31   case FK_Data_1: return 1;
     32   case FK_PCRel_2:
     33   case FK_Data_2: return 2;
     34   case FK_PCRel_4:
     35   case FK_Data_4: return 4;
     36   case FK_Data_8: return 8;
     37   }
     38 }
     39 
     40 
     41 namespace {
     42 
     43 class MBlazeAsmBackend : public MCAsmBackend {
     44 public:
     45   MBlazeAsmBackend(const Target &T)
     46     : MCAsmBackend() {
     47   }
     48 
     49   unsigned getNumFixupKinds() const {
     50     return 2;
     51   }
     52 
     53   bool mayNeedRelaxation(const MCInst &Inst) const;
     54 
     55   bool fixupNeedsRelaxation(const MCFixup &Fixup,
     56                             uint64_t Value,
     57                             const MCInstFragment *DF,
     58                             const MCAsmLayout &Layout) const;
     59 
     60   void relaxInstruction(const MCInst &Inst, MCInst &Res) const;
     61 
     62   bool writeNopData(uint64_t Count, MCObjectWriter *OW) const;
     63 
     64   unsigned getPointerSize() const {
     65     return 4;
     66   }
     67 };
     68 
     69 static unsigned getRelaxedOpcode(unsigned Op) {
     70     switch (Op) {
     71     default:            return Op;
     72     case MBlaze::ADDIK: return MBlaze::ADDIK32;
     73     case MBlaze::ORI:   return MBlaze::ORI32;
     74     case MBlaze::BRLID: return MBlaze::BRLID32;
     75     }
     76 }
     77 
     78 bool MBlazeAsmBackend::mayNeedRelaxation(const MCInst &Inst) const {
     79   if (getRelaxedOpcode(Inst.getOpcode()) == Inst.getOpcode())
     80     return false;
     81 
     82   bool hasExprOrImm = false;
     83   for (unsigned i = 0; i < Inst.getNumOperands(); ++i)
     84     hasExprOrImm |= Inst.getOperand(i).isExpr();
     85 
     86   return hasExprOrImm;
     87 }
     88 
     89 bool MBlazeAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup,
     90                                             uint64_t Value,
     91                                             const MCInstFragment *DF,
     92                                             const MCAsmLayout &Layout) const {
     93   // FIXME: Is this right? It's what the "generic" code was doing before,
     94   // but is X86 specific. Is it actually true for MBlaze also, or was it
     95   // just close enough to not be a big deal?
     96   //
     97   // Relax if the value is too big for a (signed) i8.
     98   return int64_t(Value) != int64_t(int8_t(Value));
     99 }
    100 
    101 void MBlazeAsmBackend::relaxInstruction(const MCInst &Inst, MCInst &Res) const {
    102   Res = Inst;
    103   Res.setOpcode(getRelaxedOpcode(Inst.getOpcode()));
    104 }
    105 
    106 bool MBlazeAsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const {
    107   if ((Count % 4) != 0)
    108     return false;
    109 
    110   for (uint64_t i = 0; i < Count; i += 4)
    111       OW->Write32(0x00000000);
    112 
    113   return true;
    114 }
    115 } // end anonymous namespace
    116 
    117 namespace {
    118 class ELFMBlazeAsmBackend : public MBlazeAsmBackend {
    119 public:
    120   uint8_t OSABI;
    121   ELFMBlazeAsmBackend(const Target &T, uint8_t _OSABI)
    122     : MBlazeAsmBackend(T), OSABI(_OSABI) { }
    123 
    124   void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize,
    125                   uint64_t Value) const;
    126 
    127   MCObjectWriter *createObjectWriter(raw_ostream &OS) const {
    128     return createMBlazeELFObjectWriter(OS, OSABI);
    129   }
    130 };
    131 
    132 void ELFMBlazeAsmBackend::applyFixup(const MCFixup &Fixup, char *Data,
    133                                      unsigned DataSize, uint64_t Value) const {
    134   unsigned Size = getFixupKindSize(Fixup.getKind());
    135 
    136   assert(Fixup.getOffset() + Size <= DataSize &&
    137          "Invalid fixup offset!");
    138 
    139   char *data = Data + Fixup.getOffset();
    140   switch (Size) {
    141   default: llvm_unreachable("Cannot fixup unknown value.");
    142   case 1:  llvm_unreachable("Cannot fixup 1 byte value.");
    143   case 8:  llvm_unreachable("Cannot fixup 8 byte value.");
    144 
    145   case 4:
    146     *(data+7) = uint8_t(Value);
    147     *(data+6) = uint8_t(Value >> 8);
    148     *(data+3) = uint8_t(Value >> 16);
    149     *(data+2) = uint8_t(Value >> 24);
    150     break;
    151 
    152   case 2:
    153     *(data+3) = uint8_t(Value >> 0);
    154     *(data+2) = uint8_t(Value >> 8);
    155   }
    156 }
    157 } // end anonymous namespace
    158 
    159 MCAsmBackend *llvm::createMBlazeAsmBackend(const Target &T, StringRef TT) {
    160   Triple TheTriple(TT);
    161 
    162   if (TheTriple.isOSDarwin())
    163     assert(0 && "Mac not supported on MBlaze");
    164 
    165   if (TheTriple.isOSWindows())
    166     assert(0 && "Windows not supported on MBlaze");
    167 
    168   uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());
    169   return new ELFMBlazeAsmBackend(T, OSABI);
    170 }
    171