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: 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 41 namespace { 42 class MBlazeELFObjectWriter : public MCELFObjectTargetWriter { 43 public: 44 MBlazeELFObjectWriter(Triple::OSType OSType) 45 : MCELFObjectTargetWriter(/*is64Bit*/ false, OSType, ELF::EM_MBLAZE, 46 /*HasRelocationAddend*/ true) {} 47 }; 48 49 class MBlazeAsmBackend : public MCAsmBackend { 50 public: 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 void RelaxInstruction(const MCInst &Inst, MCInst &Res) const; 62 63 bool WriteNopData(uint64_t Count, MCObjectWriter *OW) const; 64 65 unsigned getPointerSize() const { 66 return 4; 67 } 68 }; 69 70 static unsigned getRelaxedOpcode(unsigned Op) { 71 switch (Op) { 72 default: return Op; 73 case MBlaze::ADDIK: return MBlaze::ADDIK32; 74 case MBlaze::ORI: return MBlaze::ORI32; 75 case MBlaze::BRLID: return MBlaze::BRLID32; 76 } 77 } 78 79 bool MBlazeAsmBackend::MayNeedRelaxation(const MCInst &Inst) const { 80 if (getRelaxedOpcode(Inst.getOpcode()) == Inst.getOpcode()) 81 return false; 82 83 bool hasExprOrImm = false; 84 for (unsigned i = 0; i < Inst.getNumOperands(); ++i) 85 hasExprOrImm |= Inst.getOperand(i).isExpr(); 86 87 return hasExprOrImm; 88 } 89 90 void MBlazeAsmBackend::RelaxInstruction(const MCInst &Inst, MCInst &Res) const { 91 Res = Inst; 92 Res.setOpcode(getRelaxedOpcode(Inst.getOpcode())); 93 } 94 95 bool MBlazeAsmBackend::WriteNopData(uint64_t Count, MCObjectWriter *OW) const { 96 if ((Count % 4) != 0) 97 return false; 98 99 for (uint64_t i = 0; i < Count; i += 4) 100 OW->Write32(0x00000000); 101 102 return true; 103 } 104 } // end anonymous namespace 105 106 namespace { 107 class ELFMBlazeAsmBackend : public MBlazeAsmBackend { 108 public: 109 Triple::OSType OSType; 110 ELFMBlazeAsmBackend(const Target &T, Triple::OSType _OSType) 111 : MBlazeAsmBackend(T), OSType(_OSType) { } 112 113 void ApplyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, 114 uint64_t Value) const; 115 116 MCObjectWriter *createObjectWriter(raw_ostream &OS) const { 117 return createELFObjectWriter(new MBlazeELFObjectWriter(OSType), OS, 118 /*IsLittleEndian*/ false); 119 } 120 }; 121 122 void ELFMBlazeAsmBackend::ApplyFixup(const MCFixup &Fixup, char *Data, 123 unsigned DataSize, uint64_t Value) const { 124 unsigned Size = getFixupKindSize(Fixup.getKind()); 125 126 assert(Fixup.getOffset() + Size <= DataSize && 127 "Invalid fixup offset!"); 128 129 char *data = Data + Fixup.getOffset(); 130 switch (Size) { 131 default: llvm_unreachable("Cannot fixup unknown value."); 132 case 1: llvm_unreachable("Cannot fixup 1 byte value."); 133 case 8: llvm_unreachable("Cannot fixup 8 byte value."); 134 135 case 4: 136 *(data+7) = uint8_t(Value); 137 *(data+6) = uint8_t(Value >> 8); 138 *(data+3) = uint8_t(Value >> 16); 139 *(data+2) = uint8_t(Value >> 24); 140 break; 141 142 case 2: 143 *(data+3) = uint8_t(Value >> 0); 144 *(data+2) = uint8_t(Value >> 8); 145 } 146 } 147 } // end anonymous namespace 148 149 MCAsmBackend *llvm::createMBlazeAsmBackend(const Target &T, StringRef TT) { 150 Triple TheTriple(TT); 151 152 if (TheTriple.isOSDarwin()) 153 assert(0 && "Mac not supported on MBlaze"); 154 155 if (TheTriple.isOSWindows()) 156 assert(0 && "Windows not supported on MBlaze"); 157 158 return new ELFMBlazeAsmBackend(T, TheTriple.getOS()); 159 } 160