blob: 692a179e927d0997aec451ffdf42cbfad1f20a2d [file] [log] [blame]
Alex Bradbury6b2cca72016-11-01 23:47:30 +00001//===-- RISCVAsmBackend.cpp - RISCV 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
Alex Bradbury9d3f1252017-09-28 08:26:24 +000010#include "MCTargetDesc/RISCVFixupKinds.h"
Alex Bradbury6b2cca72016-11-01 23:47:30 +000011#include "MCTargetDesc/RISCVMCTargetDesc.h"
Alex Bradbury9d3f1252017-09-28 08:26:24 +000012#include "llvm/ADT/APInt.h"
Alex Bradbury6b2cca72016-11-01 23:47:30 +000013#include "llvm/MC/MCAsmBackend.h"
14#include "llvm/MC/MCAssembler.h"
Alex Bradbury9d3f1252017-09-28 08:26:24 +000015#include "llvm/MC/MCContext.h"
Alex Bradbury6b2cca72016-11-01 23:47:30 +000016#include "llvm/MC/MCDirectives.h"
17#include "llvm/MC/MCELFObjectWriter.h"
Chandler Carruth6bda14b2017-06-06 11:49:48 +000018#include "llvm/MC/MCExpr.h"
Alex Bradbury6b2cca72016-11-01 23:47:30 +000019#include "llvm/MC/MCFixupKindInfo.h"
20#include "llvm/MC/MCObjectWriter.h"
21#include "llvm/MC/MCSubtargetInfo.h"
Alex Bradbury6b2cca72016-11-01 23:47:30 +000022#include "llvm/MC/MCSymbol.h"
23#include "llvm/Support/ErrorHandling.h"
24#include "llvm/Support/raw_ostream.h"
25
26using namespace llvm;
27
28namespace {
29class RISCVAsmBackend : public MCAsmBackend {
30 uint8_t OSABI;
31 bool Is64Bit;
32
33public:
34 RISCVAsmBackend(uint8_t OSABI, bool Is64Bit)
35 : MCAsmBackend(), OSABI(OSABI), Is64Bit(Is64Bit) {}
36 ~RISCVAsmBackend() override {}
37
Rafael Espindola801b42d2017-06-23 22:52:36 +000038 void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
39 const MCValue &Target, MutableArrayRef<char> Data,
Rafael Espindola1beb7022017-07-11 23:18:25 +000040 uint64_t Value, bool IsResolved) const override;
Alex Bradbury6b2cca72016-11-01 23:47:30 +000041
42 MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override;
43
44 bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
45 const MCRelaxableFragment *DF,
46 const MCAsmLayout &Layout) const override {
47 return false;
48 }
49
Alex Bradbury9d3f1252017-09-28 08:26:24 +000050 unsigned getNumFixupKinds() const override {
51 return RISCV::NumTargetFixupKinds;
52 }
53
54 const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override {
55 const static MCFixupKindInfo Infos[RISCV::NumTargetFixupKinds] = {
56 // This table *must* be in the order that the fixup_* kinds are defined in
57 // RISCVFixupKinds.h.
58 //
59 // name offset bits flags
60 { "fixup_riscv_hi20", 12, 20, 0 },
61 { "fixup_riscv_lo12_i", 20, 12, 0 },
62 { "fixup_riscv_lo12_s", 0, 32, 0 },
63 { "fixup_riscv_pcrel_hi20", 12, 20, MCFixupKindInfo::FKF_IsPCRel },
64 { "fixup_riscv_jal", 12, 20, MCFixupKindInfo::FKF_IsPCRel },
65 { "fixup_riscv_branch", 0, 32, MCFixupKindInfo::FKF_IsPCRel }
66 };
67
68 if (Kind < FirstTargetFixupKind)
69 return MCAsmBackend::getFixupKindInfo(Kind);
70
71 assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
72 "Invalid kind!");
73 return Infos[Kind - FirstTargetFixupKind];
74 }
Alex Bradbury6b2cca72016-11-01 23:47:30 +000075
76 bool mayNeedRelaxation(const MCInst &Inst) const override { return false; }
77
78 void relaxInstruction(const MCInst &Inst, const MCSubtargetInfo &STI,
79 MCInst &Res) const override {
80
Alex Bradburye45186d2017-08-20 06:57:27 +000081 report_fatal_error("RISCVAsmBackend::relaxInstruction() unimplemented");
Alex Bradbury6b2cca72016-11-01 23:47:30 +000082 }
83
84 bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override;
85};
86
87bool RISCVAsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const {
88 // Once support for the compressed instruction set is added, we will be able
89 // to conditionally support 16-bit NOPs
90 if ((Count % 4) != 0)
91 return false;
92
93 // The canonical nop on RISC-V is addi x0, x0, 0
94 for (uint64_t i = 0; i < Count; i += 4)
95 OW->write32(0x13);
96
97 return true;
98}
99
Alex Bradbury9d3f1252017-09-28 08:26:24 +0000100static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
101 MCContext &Ctx) {
102 unsigned Kind = Fixup.getKind();
103 switch (Kind) {
104 default:
105 llvm_unreachable("Unknown fixup kind!");
106 case FK_Data_1:
107 case FK_Data_2:
108 case FK_Data_4:
109 case FK_Data_8:
110 return Value;
111 case RISCV::fixup_riscv_lo12_i:
112 return Value & 0xfff;
113 case RISCV::fixup_riscv_lo12_s:
114 return (((Value >> 5) & 0x7f) << 25) | ((Value & 0x1f) << 7);
115 case RISCV::fixup_riscv_hi20:
116 case RISCV::fixup_riscv_pcrel_hi20:
117 // Add 1 if bit 11 is 1, to compensate for low 12 bits being negative.
118 return ((Value + 0x800) >> 12) & 0xfffff;
119 case RISCV::fixup_riscv_jal: {
120 if (!isInt<21>(Value))
121 Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
122 if (Value & 0x1)
123 Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned");
124 // Need to produce imm[19|10:1|11|19:12] from the 21-bit Value.
125 unsigned Sbit = (Value >> 20) & 0x1;
126 unsigned Hi8 = (Value >> 12) & 0xff;
127 unsigned Mid1 = (Value >> 11) & 0x1;
128 unsigned Lo10 = (Value >> 1) & 0x3ff;
129 // Inst{31} = Sbit;
130 // Inst{30-21} = Lo10;
131 // Inst{20} = Mid1;
132 // Inst{19-12} = Hi8;
133 Value = (Sbit << 19) | (Lo10 << 9) | (Mid1 << 8) | Hi8;
134 return Value;
135 }
136 case RISCV::fixup_riscv_branch: {
137 if (!isInt<13>(Value))
138 Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
139 if (Value & 0x1)
140 Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned");
141 // Need to extract imm[12], imm[10:5], imm[4:1], imm[11] from the 13-bit
142 // Value.
143 unsigned Sbit = (Value >> 12) & 0x1;
144 unsigned Hi1 = (Value >> 11) & 0x1;
145 unsigned Mid6 = (Value >> 5) & 0x3f;
146 unsigned Lo4 = (Value >> 1) & 0xf;
147 // Inst{31} = Sbit;
148 // Inst{30-25} = Mid6;
149 // Inst{11-8} = Lo4;
150 // Inst{7} = Hi1;
151 Value = (Sbit << 31) | (Mid6 << 25) | (Lo4 << 8) | (Hi1 << 7);
152 return Value;
153 }
154
155 }
156}
157
Rafael Espindola801b42d2017-06-23 22:52:36 +0000158void RISCVAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
159 const MCValue &Target,
Rafael Espindola88d9e372017-06-21 23:06:53 +0000160 MutableArrayRef<char> Data, uint64_t Value,
Rafael Espindola1beb7022017-07-11 23:18:25 +0000161 bool IsResolved) const {
Alex Bradbury9d3f1252017-09-28 08:26:24 +0000162 MCContext &Ctx = Asm.getContext();
163 MCFixupKind Kind = Fixup.getKind();
164 unsigned NumBytes = (getFixupKindInfo(Kind).TargetSize + 7) / 8;
165 if (!Value)
166 return; // Doesn't change encoding.
167 MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind());
168 // Apply any target-specific value adjustments.
169 Value = adjustFixupValue(Fixup, Value, Ctx);
170
171 // Shift the value into position.
172 Value <<= Info.TargetOffset;
173
174 unsigned Offset = Fixup.getOffset();
175 assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!");
176
177 // For each byte of the fragment that the fixup touches, mask in the
178 // bits from the fixup value.
179 for (unsigned i = 0; i != 4; ++i) {
180 Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff);
181 }
Alex Bradbury6b2cca72016-11-01 23:47:30 +0000182 return;
183}
184
185MCObjectWriter *
186RISCVAsmBackend::createObjectWriter(raw_pwrite_stream &OS) const {
187 return createRISCVELFObjectWriter(OS, OSABI, Is64Bit);
188}
189
190} // end anonymous namespace
191
192MCAsmBackend *llvm::createRISCVAsmBackend(const Target &T,
193 const MCRegisterInfo &MRI,
194 const Triple &TT, StringRef CPU,
195 const MCTargetOptions &Options) {
196 uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TT.getOS());
197 return new RISCVAsmBackend(OSABI, TT.isArch64Bit());
198}