LLVM API Documentation

MBlazeAsmBackend.cpp
Go to the documentation of this file.
00001 //===-- MBlazeAsmBackend.cpp - MBlaze Assembler Backend -------------------===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 
00010 #include "MCTargetDesc/MBlazeMCTargetDesc.h"
00011 #include "llvm/ADT/Twine.h"
00012 #include "llvm/MC/MCAsmBackend.h"
00013 #include "llvm/MC/MCAsmLayout.h"
00014 #include "llvm/MC/MCAssembler.h"
00015 #include "llvm/MC/MCELFObjectWriter.h"
00016 #include "llvm/MC/MCELFSymbolFlags.h"
00017 #include "llvm/MC/MCExpr.h"
00018 #include "llvm/MC/MCObjectWriter.h"
00019 #include "llvm/MC/MCSectionELF.h"
00020 #include "llvm/MC/MCSectionMachO.h"
00021 #include "llvm/MC/MCValue.h"
00022 #include "llvm/Support/ELF.h"
00023 #include "llvm/Support/ErrorHandling.h"
00024 #include "llvm/Support/TargetRegistry.h"
00025 #include "llvm/Support/raw_ostream.h"
00026 using namespace llvm;
00027 
00028 static unsigned getFixupKindSize(unsigned Kind) {
00029   switch (Kind) {
00030   default: llvm_unreachable("invalid fixup kind!");
00031   case FK_Data_1: return 1;
00032   case FK_PCRel_2:
00033   case FK_Data_2: return 2;
00034   case FK_PCRel_4:
00035   case FK_Data_4: return 4;
00036   case FK_Data_8: return 8;
00037   }
00038 }
00039 
00040 
00041 namespace {
00042 
00043 class MBlazeAsmBackend : public MCAsmBackend {
00044 public:
00045   MBlazeAsmBackend(const Target &T)
00046     : MCAsmBackend() {
00047   }
00048 
00049   unsigned getNumFixupKinds() const {
00050     return 2;
00051   }
00052 
00053   bool mayNeedRelaxation(const MCInst &Inst) const;
00054 
00055   bool fixupNeedsRelaxation(const MCFixup &Fixup,
00056                             uint64_t Value,
00057                             const MCRelaxableFragment *DF,
00058                             const MCAsmLayout &Layout) const;
00059 
00060   void relaxInstruction(const MCInst &Inst, MCInst &Res) const;
00061 
00062   bool writeNopData(uint64_t Count, MCObjectWriter *OW) const;
00063 
00064   unsigned getPointerSize() const {
00065     return 4;
00066   }
00067 };
00068 
00069 static unsigned getRelaxedOpcode(unsigned Op) {
00070     switch (Op) {
00071     default:            return Op;
00072     case MBlaze::ADDIK: return MBlaze::ADDIK32;
00073     case MBlaze::ORI:   return MBlaze::ORI32;
00074     case MBlaze::BRLID: return MBlaze::BRLID32;
00075     }
00076 }
00077 
00078 bool MBlazeAsmBackend::mayNeedRelaxation(const MCInst &Inst) const {
00079   if (getRelaxedOpcode(Inst.getOpcode()) == Inst.getOpcode())
00080     return false;
00081 
00082   bool hasExprOrImm = false;
00083   for (unsigned i = 0; i < Inst.getNumOperands(); ++i)
00084     hasExprOrImm |= Inst.getOperand(i).isExpr();
00085 
00086   return hasExprOrImm;
00087 }
00088 
00089 bool MBlazeAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup,
00090                                             uint64_t Value,
00091                                             const MCRelaxableFragment *DF,
00092                                             const MCAsmLayout &Layout) const {
00093   // FIXME: Is this right? It's what the "generic" code was doing before,
00094   // but is X86 specific. Is it actually true for MBlaze also, or was it
00095   // just close enough to not be a big deal?
00096   //
00097   // Relax if the value is too big for a (signed) i8.
00098   return int64_t(Value) != int64_t(int8_t(Value));
00099 }
00100 
00101 void MBlazeAsmBackend::relaxInstruction(const MCInst &Inst, MCInst &Res) const {
00102   Res = Inst;
00103   Res.setOpcode(getRelaxedOpcode(Inst.getOpcode()));
00104 }
00105 
00106 bool MBlazeAsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const {
00107   if ((Count % 4) != 0)
00108     return false;
00109 
00110   for (uint64_t i = 0; i < Count; i += 4)
00111       OW->Write32(0x00000000);
00112 
00113   return true;
00114 }
00115 } // end anonymous namespace
00116 
00117 namespace {
00118 class ELFMBlazeAsmBackend : public MBlazeAsmBackend {
00119 public:
00120   uint8_t OSABI;
00121   ELFMBlazeAsmBackend(const Target &T, uint8_t _OSABI)
00122     : MBlazeAsmBackend(T), OSABI(_OSABI) { }
00123 
00124   void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize,
00125                   uint64_t Value) const;
00126 
00127   MCObjectWriter *createObjectWriter(raw_ostream &OS) const {
00128     return createMBlazeELFObjectWriter(OS, OSABI);
00129   }
00130 };
00131 
00132 void ELFMBlazeAsmBackend::applyFixup(const MCFixup &Fixup, char *Data,
00133                                      unsigned DataSize, uint64_t Value) const {
00134   unsigned Size = getFixupKindSize(Fixup.getKind());
00135 
00136   assert(Fixup.getOffset() + Size <= DataSize &&
00137          "Invalid fixup offset!");
00138 
00139   char *data = Data + Fixup.getOffset();
00140   switch (Size) {
00141   default: llvm_unreachable("Cannot fixup unknown value.");
00142   case 1:  llvm_unreachable("Cannot fixup 1 byte value.");
00143   case 8:  llvm_unreachable("Cannot fixup 8 byte value.");
00144 
00145   case 4:
00146     *(data+7) = uint8_t(Value);
00147     *(data+6) = uint8_t(Value >> 8);
00148     *(data+3) = uint8_t(Value >> 16);
00149     *(data+2) = uint8_t(Value >> 24);
00150     break;
00151 
00152   case 2:
00153     *(data+3) = uint8_t(Value >> 0);
00154     *(data+2) = uint8_t(Value >> 8);
00155   }
00156 }
00157 } // end anonymous namespace
00158 
00159 MCAsmBackend *llvm::createMBlazeAsmBackend(const Target &T, StringRef TT,
00160                                            StringRef CPU) {
00161   Triple TheTriple(TT);
00162 
00163   if (TheTriple.isOSDarwin())
00164     assert(0 && "Mac not supported on MBlaze");
00165 
00166   if (TheTriple.isOSWindows())
00167     assert(0 && "Windows not supported on MBlaze");
00168 
00169   uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());
00170   return new ELFMBlazeAsmBackend(T, OSABI);
00171 }