MBlazeAsmBackend.cpp revision 370b78d795154899a22ca2b4674e890661ff1d59
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" 26using namespace llvm; 27 28static unsigned getFixupKindSize(unsigned Kind) { 29 switch (Kind) { 30 default: assert(0 && "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 41namespace { 42class MBlazeELFObjectWriter : public MCELFObjectTargetWriter { 43public: 44 MBlazeELFObjectWriter(Triple::OSType OSType) 45 : MCELFObjectTargetWriter(/*is64Bit*/ false, OSType, ELF::EM_MBLAZE, 46 /*HasRelocationAddend*/ true) {} 47}; 48 49class MBlazeAsmBackend : public MCAsmBackend { 50public: 51 MBlazeAsmBackend(const Target &T) 52 : MCAsmBackend() { 53 } 54 55 unsigned getNumFixupKinds() const { 56 return 2; 57 } 58 59 bool MayNeedRelaxation(const MCInst &Inst) const; 60 61 bool fixupNeedsRelaxation(const MCFixup &Fixup, 62 uint64_t Value, 63 const MCInstFragment *DF, 64 const MCAsmLayout &Layout) const; 65 66 void RelaxInstruction(const MCInst &Inst, MCInst &Res) const; 67 68 bool WriteNopData(uint64_t Count, MCObjectWriter *OW) const; 69 70 unsigned getPointerSize() const { 71 return 4; 72 } 73}; 74 75static unsigned getRelaxedOpcode(unsigned Op) { 76 switch (Op) { 77 default: return Op; 78 case MBlaze::ADDIK: return MBlaze::ADDIK32; 79 case MBlaze::ORI: return MBlaze::ORI32; 80 case MBlaze::BRLID: return MBlaze::BRLID32; 81 } 82} 83 84bool MBlazeAsmBackend::MayNeedRelaxation(const MCInst &Inst) const { 85 if (getRelaxedOpcode(Inst.getOpcode()) == Inst.getOpcode()) 86 return false; 87 88 bool hasExprOrImm = false; 89 for (unsigned i = 0; i < Inst.getNumOperands(); ++i) 90 hasExprOrImm |= Inst.getOperand(i).isExpr(); 91 92 return hasExprOrImm; 93} 94 95bool MBlazeAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, 96 uint64_t Value, 97 const MCInstFragment *DF, 98 const MCAsmLayout &Layout) const { 99 // FIXME: Is this right? It's what the "generic" code was doing before, 100 // but is X86 specific. Is it actually true for MBlaze also, or was it 101 // just close enough to not be a big deal? 102 // 103 // Relax if the value is too big for a (signed) i8. 104 return int64_t(Value) != int64_t(int8_t(Value)); 105} 106 107void MBlazeAsmBackend::RelaxInstruction(const MCInst &Inst, MCInst &Res) const { 108 Res = Inst; 109 Res.setOpcode(getRelaxedOpcode(Inst.getOpcode())); 110} 111 112bool MBlazeAsmBackend::WriteNopData(uint64_t Count, MCObjectWriter *OW) const { 113 if ((Count % 4) != 0) 114 return false; 115 116 for (uint64_t i = 0; i < Count; i += 4) 117 OW->Write32(0x00000000); 118 119 return true; 120} 121} // end anonymous namespace 122 123namespace { 124class ELFMBlazeAsmBackend : public MBlazeAsmBackend { 125public: 126 Triple::OSType OSType; 127 ELFMBlazeAsmBackend(const Target &T, Triple::OSType _OSType) 128 : MBlazeAsmBackend(T), OSType(_OSType) { } 129 130 void ApplyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, 131 uint64_t Value) const; 132 133 MCObjectWriter *createObjectWriter(raw_ostream &OS) const { 134 return createELFObjectWriter(new MBlazeELFObjectWriter(OSType), OS, 135 /*IsLittleEndian*/ false); 136 } 137}; 138 139void ELFMBlazeAsmBackend::ApplyFixup(const MCFixup &Fixup, char *Data, 140 unsigned DataSize, uint64_t Value) const { 141 unsigned Size = getFixupKindSize(Fixup.getKind()); 142 143 assert(Fixup.getOffset() + Size <= DataSize && 144 "Invalid fixup offset!"); 145 146 char *data = Data + Fixup.getOffset(); 147 switch (Size) { 148 default: llvm_unreachable("Cannot fixup unknown value."); 149 case 1: llvm_unreachable("Cannot fixup 1 byte value."); 150 case 8: llvm_unreachable("Cannot fixup 8 byte value."); 151 152 case 4: 153 *(data+7) = uint8_t(Value); 154 *(data+6) = uint8_t(Value >> 8); 155 *(data+3) = uint8_t(Value >> 16); 156 *(data+2) = uint8_t(Value >> 24); 157 break; 158 159 case 2: 160 *(data+3) = uint8_t(Value >> 0); 161 *(data+2) = uint8_t(Value >> 8); 162 } 163} 164} // end anonymous namespace 165 166MCAsmBackend *llvm::createMBlazeAsmBackend(const Target &T, StringRef TT) { 167 Triple TheTriple(TT); 168 169 if (TheTriple.isOSDarwin()) 170 assert(0 && "Mac not supported on MBlaze"); 171 172 if (TheTriple.isOSWindows()) 173 assert(0 && "Windows not supported on MBlaze"); 174 175 return new ELFMBlazeAsmBackend(T, TheTriple.getOS()); 176} 177