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/ADT/Twine.h" 12 #include "llvm/MC/MCAsmBackend.h" 13 #include "llvm/MC/MCAsmLayout.h" 14 #include "llvm/MC/MCAssembler.h" 15 #include "llvm/MC/MCELFObjectWriter.h" 16 #include "llvm/MC/MCELFSymbolFlags.h" 17 #include "llvm/MC/MCExpr.h" 18 #include "llvm/MC/MCObjectWriter.h" 19 #include "llvm/MC/MCSectionELF.h" 20 #include "llvm/MC/MCSectionMachO.h" 21 #include "llvm/MC/MCValue.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 MCRelaxableFragment *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 MCRelaxableFragment *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 StringRef CPU) { 161 Triple TheTriple(TT); 162 163 if (TheTriple.isOSDarwin()) 164 assert(0 && "Mac not supported on MBlaze"); 165 166 if (TheTriple.isOSWindows()) 167 assert(0 && "Windows not supported on MBlaze"); 168 169 uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS()); 170 return new ELFMBlazeAsmBackend(T, OSABI); 171 } 172