1 | //===-- RISCVTargetStreamer.cpp - RISC-V Target Streamer Methods ----------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file provides RISC-V specific target streamer methods. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "RISCVTargetStreamer.h" |
14 | #include "RISCVBaseInfo.h" |
15 | #include "RISCVMCTargetDesc.h" |
16 | #include "llvm/BinaryFormat/ELF.h" |
17 | #include "llvm/MC/MCContext.h" |
18 | #include "llvm/MC/MCExpr.h" |
19 | #include "llvm/MC/MCSectionELF.h" |
20 | #include "llvm/MC/MCStreamer.h" |
21 | #include "llvm/MC/MCSymbol.h" |
22 | #include "llvm/Support/Alignment.h" |
23 | #include "llvm/Support/CommandLine.h" |
24 | #include "llvm/Support/ErrorHandling.h" |
25 | #include "llvm/Support/FormattedStream.h" |
26 | #include "llvm/Support/RISCVAttributes.h" |
27 | #include "llvm/TargetParser/RISCVISAInfo.h" |
28 | |
29 | using namespace llvm; |
30 | |
31 | // This option controls whether or not we emit ELF attributes for ABI features, |
32 | // like RISC-V atomics or X3 usage. |
33 | static cl::opt<bool> RiscvAbiAttr( |
34 | "riscv-abi-attributes" , |
35 | cl::desc("Enable emitting RISC-V ELF attributes for ABI features" ), |
36 | cl::Hidden); |
37 | |
38 | RISCVTargetStreamer::RISCVTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {} |
39 | |
40 | void RISCVTargetStreamer::finish() { finishAttributeSection(); } |
41 | void RISCVTargetStreamer::reset() {} |
42 | |
43 | void RISCVTargetStreamer::emitDirectiveOptionArch( |
44 | ArrayRef<RISCVOptionArchArg> Args) {} |
45 | void RISCVTargetStreamer::emitDirectiveOptionExact() {} |
46 | void RISCVTargetStreamer::emitDirectiveOptionNoExact() {} |
47 | void RISCVTargetStreamer::emitDirectiveOptionPIC() {} |
48 | void RISCVTargetStreamer::emitDirectiveOptionNoPIC() {} |
49 | void RISCVTargetStreamer::emitDirectiveOptionPop() {} |
50 | void RISCVTargetStreamer::emitDirectiveOptionPush() {} |
51 | void RISCVTargetStreamer::emitDirectiveOptionRelax() {} |
52 | void RISCVTargetStreamer::emitDirectiveOptionNoRelax() {} |
53 | void RISCVTargetStreamer::emitDirectiveOptionRVC() {} |
54 | void RISCVTargetStreamer::emitDirectiveOptionNoRVC() {} |
55 | void RISCVTargetStreamer::emitDirectiveVariantCC(MCSymbol &Symbol) {} |
56 | void RISCVTargetStreamer::emitAttribute(unsigned Attribute, unsigned Value) {} |
57 | void RISCVTargetStreamer::finishAttributeSection() {} |
58 | void RISCVTargetStreamer::emitTextAttribute(unsigned Attribute, |
59 | StringRef String) {} |
60 | void RISCVTargetStreamer::emitIntTextAttribute(unsigned Attribute, |
61 | unsigned IntValue, |
62 | StringRef StringValue) {} |
63 | |
64 | void RISCVTargetStreamer::emitNoteGnuPropertySection( |
65 | const uint32_t Feature1And) { |
66 | MCStreamer &OutStreamer = getStreamer(); |
67 | MCContext &Ctx = OutStreamer.getContext(); |
68 | |
69 | const Triple &Triple = Ctx.getTargetTriple(); |
70 | Align NoteAlign; |
71 | if (Triple.isArch64Bit()) { |
72 | NoteAlign = Align(8); |
73 | } else { |
74 | assert(Triple.isArch32Bit()); |
75 | NoteAlign = Align(4); |
76 | } |
77 | |
78 | assert(Ctx.getObjectFileType() == MCContext::Environment::IsELF); |
79 | MCSection *const NoteSection = |
80 | Ctx.getELFSection(Section: ".note.gnu.property" , Type: ELF::SHT_NOTE, Flags: ELF::SHF_ALLOC); |
81 | NoteSection->setAlignment(NoteAlign); |
82 | OutStreamer.pushSection(); |
83 | OutStreamer.switchSection(Section: NoteSection); |
84 | |
85 | // Emit the note header |
86 | OutStreamer.emitIntValue(Value: 4, Size: 4); // n_namsz |
87 | |
88 | MCSymbol *const NDescBeginSym = Ctx.createTempSymbol(); |
89 | MCSymbol *const NDescEndSym = Ctx.createTempSymbol(); |
90 | const MCExpr *const NDescSzExpr = |
91 | MCBinaryExpr::createSub(LHS: MCSymbolRefExpr::create(Symbol: NDescEndSym, Ctx), |
92 | RHS: MCSymbolRefExpr::create(Symbol: NDescBeginSym, Ctx), Ctx); |
93 | |
94 | OutStreamer.emitValue(Value: NDescSzExpr, Size: 4); // n_descsz |
95 | OutStreamer.emitIntValue(Value: ELF::NT_GNU_PROPERTY_TYPE_0, Size: 4); // n_type |
96 | OutStreamer.emitBytes(Data: StringRef("GNU" , 4)); // n_name |
97 | |
98 | // Emit n_desc field |
99 | OutStreamer.emitLabel(Symbol: NDescBeginSym); |
100 | OutStreamer.emitValueToAlignment(Alignment: NoteAlign); |
101 | |
102 | // Emit the feature_1_and property |
103 | OutStreamer.emitIntValue(Value: ELF::GNU_PROPERTY_RISCV_FEATURE_1_AND, Size: 4); // pr_type |
104 | OutStreamer.emitIntValue(Value: 4, Size: 4); // pr_datasz |
105 | OutStreamer.emitIntValue(Value: Feature1And, Size: 4); // pr_data |
106 | OutStreamer.emitValueToAlignment(Alignment: NoteAlign); // pr_padding |
107 | |
108 | OutStreamer.emitLabel(Symbol: NDescEndSym); |
109 | OutStreamer.popSection(); |
110 | } |
111 | |
112 | void RISCVTargetStreamer::setTargetABI(RISCVABI::ABI ABI) { |
113 | assert(ABI != RISCVABI::ABI_Unknown && "Improperly initialized target ABI" ); |
114 | TargetABI = ABI; |
115 | } |
116 | |
117 | void RISCVTargetStreamer::setFlagsFromFeatures(const MCSubtargetInfo &STI) { |
118 | HasRVC = STI.hasFeature(Feature: RISCV::FeatureStdExtZca); |
119 | HasTSO = STI.hasFeature(Feature: RISCV::FeatureStdExtZtso); |
120 | } |
121 | |
122 | void RISCVTargetStreamer::emitTargetAttributes(const MCSubtargetInfo &STI, |
123 | bool EmitStackAlign) { |
124 | if (EmitStackAlign) { |
125 | unsigned StackAlign; |
126 | if (TargetABI == RISCVABI::ABI_ILP32E) |
127 | StackAlign = 4; |
128 | else if (TargetABI == RISCVABI::ABI_LP64E) |
129 | StackAlign = 8; |
130 | else |
131 | StackAlign = 16; |
132 | emitAttribute(Attribute: RISCVAttrs::STACK_ALIGN, Value: StackAlign); |
133 | } |
134 | |
135 | auto ParseResult = RISCVFeatures::parseFeatureBits( |
136 | IsRV64: STI.hasFeature(Feature: RISCV::Feature64Bit), FeatureBits: STI.getFeatureBits()); |
137 | if (!ParseResult) { |
138 | report_fatal_error(Err: ParseResult.takeError()); |
139 | } else { |
140 | auto &ISAInfo = *ParseResult; |
141 | emitTextAttribute(Attribute: RISCVAttrs::ARCH, String: ISAInfo->toString()); |
142 | } |
143 | |
144 | if (RiscvAbiAttr && STI.hasFeature(Feature: RISCV::FeatureStdExtA)) { |
145 | unsigned AtomicABITag; |
146 | if (STI.hasFeature(Feature: RISCV::FeatureStdExtZalasr)) |
147 | AtomicABITag = static_cast<unsigned>(RISCVAttrs::RISCVAtomicAbiTag::A7); |
148 | else if (STI.hasFeature(Feature: RISCV::FeatureNoTrailingSeqCstFence)) |
149 | AtomicABITag = static_cast<unsigned>(RISCVAttrs::RISCVAtomicAbiTag::A6C); |
150 | else |
151 | AtomicABITag = static_cast<unsigned>(RISCVAttrs::RISCVAtomicAbiTag::A6S); |
152 | emitAttribute(Attribute: RISCVAttrs::ATOMIC_ABI, Value: AtomicABITag); |
153 | } |
154 | } |
155 | |
156 | // This part is for ascii assembly output |
157 | RISCVTargetAsmStreamer::RISCVTargetAsmStreamer(MCStreamer &S, |
158 | formatted_raw_ostream &OS) |
159 | : RISCVTargetStreamer(S), OS(OS) {} |
160 | |
161 | void RISCVTargetAsmStreamer::emitDirectiveOptionPush() { |
162 | OS << "\t.option\tpush\n" ; |
163 | } |
164 | |
165 | void RISCVTargetAsmStreamer::emitDirectiveOptionPop() { |
166 | OS << "\t.option\tpop\n" ; |
167 | } |
168 | |
169 | void RISCVTargetAsmStreamer::emitDirectiveOptionPIC() { |
170 | OS << "\t.option\tpic\n" ; |
171 | } |
172 | |
173 | void RISCVTargetAsmStreamer::emitDirectiveOptionNoPIC() { |
174 | OS << "\t.option\tnopic\n" ; |
175 | } |
176 | |
177 | void RISCVTargetAsmStreamer::emitDirectiveOptionRVC() { |
178 | OS << "\t.option\trvc\n" ; |
179 | } |
180 | |
181 | void RISCVTargetAsmStreamer::emitDirectiveOptionNoRVC() { |
182 | OS << "\t.option\tnorvc\n" ; |
183 | } |
184 | |
185 | void RISCVTargetAsmStreamer::emitDirectiveOptionExact() { |
186 | OS << "\t.option\texact\n" ; |
187 | } |
188 | |
189 | void RISCVTargetAsmStreamer::emitDirectiveOptionNoExact() { |
190 | OS << "\t.option\tnoexact\n" ; |
191 | } |
192 | |
193 | void RISCVTargetAsmStreamer::emitDirectiveOptionRelax() { |
194 | OS << "\t.option\trelax\n" ; |
195 | } |
196 | |
197 | void RISCVTargetAsmStreamer::emitDirectiveOptionNoRelax() { |
198 | OS << "\t.option\tnorelax\n" ; |
199 | } |
200 | |
201 | void RISCVTargetAsmStreamer::emitDirectiveOptionArch( |
202 | ArrayRef<RISCVOptionArchArg> Args) { |
203 | OS << "\t.option\tarch" ; |
204 | for (const auto &Arg : Args) { |
205 | OS << ", " ; |
206 | switch (Arg.Type) { |
207 | case RISCVOptionArchArgType::Full: |
208 | break; |
209 | case RISCVOptionArchArgType::Plus: |
210 | OS << "+" ; |
211 | break; |
212 | case RISCVOptionArchArgType::Minus: |
213 | OS << "-" ; |
214 | break; |
215 | } |
216 | OS << Arg.Value; |
217 | } |
218 | OS << "\n" ; |
219 | } |
220 | |
221 | void RISCVTargetAsmStreamer::emitDirectiveVariantCC(MCSymbol &Symbol) { |
222 | OS << "\t.variant_cc\t" << Symbol.getName() << "\n" ; |
223 | } |
224 | |
225 | void RISCVTargetAsmStreamer::emitAttribute(unsigned Attribute, unsigned Value) { |
226 | OS << "\t.attribute\t" << Attribute << ", " << Twine(Value) << "\n" ; |
227 | } |
228 | |
229 | void RISCVTargetAsmStreamer::emitTextAttribute(unsigned Attribute, |
230 | StringRef String) { |
231 | OS << "\t.attribute\t" << Attribute << ", \"" << String << "\"\n" ; |
232 | } |
233 | |
234 | void RISCVTargetAsmStreamer::emitIntTextAttribute(unsigned Attribute, |
235 | unsigned IntValue, |
236 | StringRef StringValue) {} |
237 | |
238 | void RISCVTargetAsmStreamer::finishAttributeSection() {} |
239 | |