1 | //===-- RISCVAsmPrinter.cpp - RISC-V LLVM assembly writer -----------------===// |
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 contains a printer that converts from our internal representation |
10 | // of machine-dependent LLVM code to the RISC-V assembly language. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "MCTargetDesc/RISCVBaseInfo.h" |
15 | #include "MCTargetDesc/RISCVInstPrinter.h" |
16 | #include "MCTargetDesc/RISCVMCAsmInfo.h" |
17 | #include "MCTargetDesc/RISCVMatInt.h" |
18 | #include "MCTargetDesc/RISCVTargetStreamer.h" |
19 | #include "RISCV.h" |
20 | #include "RISCVConstantPoolValue.h" |
21 | #include "RISCVMachineFunctionInfo.h" |
22 | #include "RISCVRegisterInfo.h" |
23 | #include "TargetInfo/RISCVTargetInfo.h" |
24 | #include "llvm/ADT/APInt.h" |
25 | #include "llvm/ADT/Statistic.h" |
26 | #include "llvm/BinaryFormat/ELF.h" |
27 | #include "llvm/CodeGen/AsmPrinter.h" |
28 | #include "llvm/CodeGen/MachineConstantPool.h" |
29 | #include "llvm/CodeGen/MachineInstr.h" |
30 | #include "llvm/CodeGen/MachineModuleInfo.h" |
31 | #include "llvm/IR/Module.h" |
32 | #include "llvm/MC/MCAsmInfo.h" |
33 | #include "llvm/MC/MCContext.h" |
34 | #include "llvm/MC/MCInst.h" |
35 | #include "llvm/MC/MCInstBuilder.h" |
36 | #include "llvm/MC/MCObjectFileInfo.h" |
37 | #include "llvm/MC/MCSectionELF.h" |
38 | #include "llvm/MC/MCStreamer.h" |
39 | #include "llvm/MC/MCSymbol.h" |
40 | #include "llvm/MC/TargetRegistry.h" |
41 | #include "llvm/Support/Compiler.h" |
42 | #include "llvm/Support/raw_ostream.h" |
43 | #include "llvm/TargetParser/RISCVISAInfo.h" |
44 | #include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h" |
45 | |
46 | using namespace llvm; |
47 | |
48 | #define DEBUG_TYPE "asm-printer" |
49 | |
50 | STATISTIC(RISCVNumInstrsCompressed, |
51 | "Number of RISC-V Compressed instructions emitted" ); |
52 | |
53 | namespace llvm { |
54 | extern const SubtargetFeatureKV RISCVFeatureKV[RISCV::NumSubtargetFeatures]; |
55 | } // namespace llvm |
56 | |
57 | namespace { |
58 | class RISCVAsmPrinter : public AsmPrinter { |
59 | public: |
60 | static char ID; |
61 | |
62 | private: |
63 | const RISCVSubtarget *STI; |
64 | |
65 | public: |
66 | explicit RISCVAsmPrinter(TargetMachine &TM, |
67 | std::unique_ptr<MCStreamer> Streamer) |
68 | : AsmPrinter(TM, std::move(Streamer), ID) {} |
69 | |
70 | StringRef getPassName() const override { return "RISC-V Assembly Printer" ; } |
71 | |
72 | void LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM, |
73 | const MachineInstr &MI); |
74 | |
75 | void LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM, |
76 | const MachineInstr &MI); |
77 | |
78 | void LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM, |
79 | const MachineInstr &MI); |
80 | |
81 | bool runOnMachineFunction(MachineFunction &MF) override; |
82 | |
83 | void emitInstruction(const MachineInstr *MI) override; |
84 | |
85 | void emitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) override; |
86 | |
87 | bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, |
88 | const char *, raw_ostream &OS) override; |
89 | bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, |
90 | const char *, raw_ostream &OS) override; |
91 | |
92 | // Returns whether Inst is compressed. |
93 | bool EmitToStreamer(MCStreamer &S, const MCInst &Inst, |
94 | const MCSubtargetInfo &SubtargetInfo); |
95 | bool EmitToStreamer(MCStreamer &S, const MCInst &Inst) { |
96 | return EmitToStreamer(S, Inst, SubtargetInfo: *STI); |
97 | } |
98 | |
99 | bool lowerPseudoInstExpansion(const MachineInstr *MI, MCInst &Inst); |
100 | |
101 | typedef std::tuple<unsigned, uint32_t> HwasanMemaccessTuple; |
102 | std::map<HwasanMemaccessTuple, MCSymbol *> HwasanMemaccessSymbols; |
103 | void LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI); |
104 | void LowerKCFI_CHECK(const MachineInstr &MI); |
105 | void EmitHwasanMemaccessSymbols(Module &M); |
106 | |
107 | // Wrapper needed for tblgenned pseudo lowering. |
108 | bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const; |
109 | |
110 | void emitStartOfAsmFile(Module &M) override; |
111 | void emitEndOfAsmFile(Module &M) override; |
112 | |
113 | void emitFunctionEntryLabel() override; |
114 | bool emitDirectiveOptionArch(); |
115 | |
116 | void emitNoteGnuProperty(const Module &M); |
117 | |
118 | private: |
119 | void emitAttributes(const MCSubtargetInfo &SubtargetInfo); |
120 | |
121 | void emitNTLHint(const MachineInstr *MI); |
122 | |
123 | // XRay Support |
124 | void LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr *MI); |
125 | void LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr *MI); |
126 | void LowerPATCHABLE_TAIL_CALL(const MachineInstr *MI); |
127 | void emitSled(const MachineInstr *MI, SledKind Kind); |
128 | |
129 | bool lowerToMCInst(const MachineInstr *MI, MCInst &OutMI); |
130 | }; |
131 | } |
132 | |
133 | void RISCVAsmPrinter::LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM, |
134 | const MachineInstr &MI) { |
135 | unsigned NOPBytes = STI->hasStdExtZca() ? 2 : 4; |
136 | unsigned NumNOPBytes = StackMapOpers(&MI).getNumPatchBytes(); |
137 | |
138 | auto &Ctx = OutStreamer.getContext(); |
139 | MCSymbol *MILabel = Ctx.createTempSymbol(); |
140 | OutStreamer.emitLabel(Symbol: MILabel); |
141 | |
142 | SM.recordStackMap(L: *MILabel, MI); |
143 | assert(NumNOPBytes % NOPBytes == 0 && |
144 | "Invalid number of NOP bytes requested!" ); |
145 | |
146 | // Scan ahead to trim the shadow. |
147 | const MachineBasicBlock &MBB = *MI.getParent(); |
148 | MachineBasicBlock::const_iterator MII(MI); |
149 | ++MII; |
150 | while (NumNOPBytes > 0) { |
151 | if (MII == MBB.end() || MII->isCall() || |
152 | MII->getOpcode() == RISCV::DBG_VALUE || |
153 | MII->getOpcode() == TargetOpcode::PATCHPOINT || |
154 | MII->getOpcode() == TargetOpcode::STACKMAP) |
155 | break; |
156 | ++MII; |
157 | NumNOPBytes -= 4; |
158 | } |
159 | |
160 | // Emit nops. |
161 | emitNops(N: NumNOPBytes / NOPBytes); |
162 | } |
163 | |
164 | // Lower a patchpoint of the form: |
165 | // [<def>], <id>, <numBytes>, <target>, <numArgs> |
166 | void RISCVAsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM, |
167 | const MachineInstr &MI) { |
168 | unsigned NOPBytes = STI->hasStdExtZca() ? 2 : 4; |
169 | |
170 | auto &Ctx = OutStreamer.getContext(); |
171 | MCSymbol *MILabel = Ctx.createTempSymbol(); |
172 | OutStreamer.emitLabel(Symbol: MILabel); |
173 | SM.recordPatchPoint(L: *MILabel, MI); |
174 | |
175 | PatchPointOpers Opers(&MI); |
176 | |
177 | const MachineOperand &CalleeMO = Opers.getCallTarget(); |
178 | unsigned EncodedBytes = 0; |
179 | |
180 | if (CalleeMO.isImm()) { |
181 | uint64_t CallTarget = CalleeMO.getImm(); |
182 | if (CallTarget) { |
183 | assert((CallTarget & 0xFFFF'FFFF'FFFF) == CallTarget && |
184 | "High 16 bits of call target should be zero." ); |
185 | // Materialize the jump address: |
186 | SmallVector<MCInst, 8> Seq; |
187 | RISCVMatInt::generateMCInstSeq(Val: CallTarget, STI: *STI, DestReg: RISCV::X1, Insts&: Seq); |
188 | for (MCInst &Inst : Seq) { |
189 | bool Compressed = EmitToStreamer(S&: OutStreamer, Inst); |
190 | EncodedBytes += Compressed ? 2 : 4; |
191 | } |
192 | bool Compressed = EmitToStreamer(S&: OutStreamer, Inst: MCInstBuilder(RISCV::JALR) |
193 | .addReg(Reg: RISCV::X1) |
194 | .addReg(Reg: RISCV::X1) |
195 | .addImm(Val: 0)); |
196 | EncodedBytes += Compressed ? 2 : 4; |
197 | } |
198 | } else if (CalleeMO.isGlobal()) { |
199 | MCOperand CallTargetMCOp; |
200 | lowerOperand(MO: CalleeMO, MCOp&: CallTargetMCOp); |
201 | EmitToStreamer(S&: OutStreamer, |
202 | Inst: MCInstBuilder(RISCV::PseudoCALL).addOperand(Op: CallTargetMCOp)); |
203 | EncodedBytes += 8; |
204 | } |
205 | |
206 | // Emit padding. |
207 | unsigned NumBytes = Opers.getNumPatchBytes(); |
208 | assert(NumBytes >= EncodedBytes && |
209 | "Patchpoint can't request size less than the length of a call." ); |
210 | assert((NumBytes - EncodedBytes) % NOPBytes == 0 && |
211 | "Invalid number of NOP bytes requested!" ); |
212 | emitNops(N: (NumBytes - EncodedBytes) / NOPBytes); |
213 | } |
214 | |
215 | void RISCVAsmPrinter::LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM, |
216 | const MachineInstr &MI) { |
217 | unsigned NOPBytes = STI->hasStdExtZca() ? 2 : 4; |
218 | |
219 | StatepointOpers SOpers(&MI); |
220 | if (unsigned PatchBytes = SOpers.getNumPatchBytes()) { |
221 | assert(PatchBytes % NOPBytes == 0 && |
222 | "Invalid number of NOP bytes requested!" ); |
223 | emitNops(N: PatchBytes / NOPBytes); |
224 | } else { |
225 | // Lower call target and choose correct opcode |
226 | const MachineOperand &CallTarget = SOpers.getCallTarget(); |
227 | MCOperand CallTargetMCOp; |
228 | switch (CallTarget.getType()) { |
229 | case MachineOperand::MO_GlobalAddress: |
230 | case MachineOperand::MO_ExternalSymbol: |
231 | lowerOperand(MO: CallTarget, MCOp&: CallTargetMCOp); |
232 | EmitToStreamer( |
233 | S&: OutStreamer, |
234 | Inst: MCInstBuilder(RISCV::PseudoCALL).addOperand(Op: CallTargetMCOp)); |
235 | break; |
236 | case MachineOperand::MO_Immediate: |
237 | CallTargetMCOp = MCOperand::createImm(Val: CallTarget.getImm()); |
238 | EmitToStreamer(S&: OutStreamer, Inst: MCInstBuilder(RISCV::JAL) |
239 | .addReg(Reg: RISCV::X1) |
240 | .addOperand(Op: CallTargetMCOp)); |
241 | break; |
242 | case MachineOperand::MO_Register: |
243 | CallTargetMCOp = MCOperand::createReg(Reg: CallTarget.getReg()); |
244 | EmitToStreamer(S&: OutStreamer, Inst: MCInstBuilder(RISCV::JALR) |
245 | .addReg(Reg: RISCV::X1) |
246 | .addOperand(Op: CallTargetMCOp) |
247 | .addImm(Val: 0)); |
248 | break; |
249 | default: |
250 | llvm_unreachable("Unsupported operand type in statepoint call target" ); |
251 | break; |
252 | } |
253 | } |
254 | |
255 | auto &Ctx = OutStreamer.getContext(); |
256 | MCSymbol *MILabel = Ctx.createTempSymbol(); |
257 | OutStreamer.emitLabel(Symbol: MILabel); |
258 | SM.recordStatepoint(L: *MILabel, MI); |
259 | } |
260 | |
261 | bool RISCVAsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst, |
262 | const MCSubtargetInfo &SubtargetInfo) { |
263 | MCInst CInst; |
264 | bool Res = RISCVRVC::compress(OutInst&: CInst, MI: Inst, STI: SubtargetInfo); |
265 | if (Res) |
266 | ++RISCVNumInstrsCompressed; |
267 | S.emitInstruction(Inst: Res ? CInst : Inst, STI: SubtargetInfo); |
268 | return Res; |
269 | } |
270 | |
271 | // Simple pseudo-instructions have their lowering (with expansion to real |
272 | // instructions) auto-generated. |
273 | #include "RISCVGenMCPseudoLowering.inc" |
274 | |
275 | // If the target supports Zihintntl and the instruction has a nontemporal |
276 | // MachineMemOperand, emit an NTLH hint instruction before it. |
277 | void RISCVAsmPrinter::emitNTLHint(const MachineInstr *MI) { |
278 | if (!STI->hasStdExtZihintntl()) |
279 | return; |
280 | |
281 | if (MI->memoperands_empty()) |
282 | return; |
283 | |
284 | MachineMemOperand *MMO = *(MI->memoperands_begin()); |
285 | if (!MMO->isNonTemporal()) |
286 | return; |
287 | |
288 | unsigned NontemporalMode = 0; |
289 | if (MMO->getFlags() & MONontemporalBit0) |
290 | NontemporalMode += 0b1; |
291 | if (MMO->getFlags() & MONontemporalBit1) |
292 | NontemporalMode += 0b10; |
293 | |
294 | MCInst Hint; |
295 | if (STI->hasStdExtZca()) |
296 | Hint.setOpcode(RISCV::C_ADD_HINT); |
297 | else |
298 | Hint.setOpcode(RISCV::ADD); |
299 | |
300 | Hint.addOperand(Op: MCOperand::createReg(Reg: RISCV::X0)); |
301 | Hint.addOperand(Op: MCOperand::createReg(Reg: RISCV::X0)); |
302 | Hint.addOperand(Op: MCOperand::createReg(Reg: RISCV::X2 + NontemporalMode)); |
303 | |
304 | EmitToStreamer(S&: *OutStreamer, Inst: Hint); |
305 | } |
306 | |
307 | void RISCVAsmPrinter::emitInstruction(const MachineInstr *MI) { |
308 | RISCV_MC::verifyInstructionPredicates(Opcode: MI->getOpcode(), |
309 | Features: getSubtargetInfo().getFeatureBits()); |
310 | |
311 | emitNTLHint(MI); |
312 | |
313 | // Do any auto-generated pseudo lowerings. |
314 | if (MCInst OutInst; lowerPseudoInstExpansion(MI, Inst&: OutInst)) { |
315 | EmitToStreamer(S&: *OutStreamer, Inst: OutInst); |
316 | return; |
317 | } |
318 | |
319 | switch (MI->getOpcode()) { |
320 | case RISCV::HWASAN_CHECK_MEMACCESS_SHORTGRANULES: |
321 | LowerHWASAN_CHECK_MEMACCESS(MI: *MI); |
322 | return; |
323 | case RISCV::KCFI_CHECK: |
324 | LowerKCFI_CHECK(MI: *MI); |
325 | return; |
326 | case TargetOpcode::STACKMAP: |
327 | return LowerSTACKMAP(OutStreamer&: *OutStreamer, SM, MI: *MI); |
328 | case TargetOpcode::PATCHPOINT: |
329 | return LowerPATCHPOINT(OutStreamer&: *OutStreamer, SM, MI: *MI); |
330 | case TargetOpcode::STATEPOINT: |
331 | return LowerSTATEPOINT(OutStreamer&: *OutStreamer, SM, MI: *MI); |
332 | case TargetOpcode::PATCHABLE_FUNCTION_ENTER: { |
333 | // patchable-function-entry is handled in lowerToMCInst |
334 | // Therefore, we break out of the switch statement if we encounter it here. |
335 | const Function &F = MI->getParent()->getParent()->getFunction(); |
336 | if (F.hasFnAttribute(Kind: "patchable-function-entry" )) |
337 | break; |
338 | |
339 | LowerPATCHABLE_FUNCTION_ENTER(MI); |
340 | return; |
341 | } |
342 | case TargetOpcode::PATCHABLE_FUNCTION_EXIT: |
343 | LowerPATCHABLE_FUNCTION_EXIT(MI); |
344 | return; |
345 | case TargetOpcode::PATCHABLE_TAIL_CALL: |
346 | LowerPATCHABLE_TAIL_CALL(MI); |
347 | return; |
348 | } |
349 | |
350 | MCInst OutInst; |
351 | if (!lowerToMCInst(MI, OutMI&: OutInst)) |
352 | EmitToStreamer(S&: *OutStreamer, Inst: OutInst); |
353 | } |
354 | |
355 | bool RISCVAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, |
356 | const char *, raw_ostream &OS) { |
357 | // First try the generic code, which knows about modifiers like 'c' and 'n'. |
358 | if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS)) |
359 | return false; |
360 | |
361 | const MachineOperand &MO = MI->getOperand(i: OpNo); |
362 | if (ExtraCode && ExtraCode[0]) { |
363 | if (ExtraCode[1] != 0) |
364 | return true; // Unknown modifier. |
365 | |
366 | switch (ExtraCode[0]) { |
367 | default: |
368 | return true; // Unknown modifier. |
369 | case 'z': // Print zero register if zero, regular printing otherwise. |
370 | if (MO.isImm() && MO.getImm() == 0) { |
371 | OS << RISCVInstPrinter::getRegisterName(Reg: RISCV::X0); |
372 | return false; |
373 | } |
374 | break; |
375 | case 'i': // Literal 'i' if operand is not a register. |
376 | if (!MO.isReg()) |
377 | OS << 'i'; |
378 | return false; |
379 | case 'N': // Print the register encoding as an integer (0-31) |
380 | if (!MO.isReg()) |
381 | return true; |
382 | |
383 | const RISCVRegisterInfo *TRI = STI->getRegisterInfo(); |
384 | OS << TRI->getEncodingValue(Reg: MO.getReg()); |
385 | return false; |
386 | } |
387 | } |
388 | |
389 | switch (MO.getType()) { |
390 | case MachineOperand::MO_Immediate: |
391 | OS << MO.getImm(); |
392 | return false; |
393 | case MachineOperand::MO_Register: |
394 | OS << RISCVInstPrinter::getRegisterName(Reg: MO.getReg()); |
395 | return false; |
396 | case MachineOperand::MO_GlobalAddress: |
397 | PrintSymbolOperand(MO, OS); |
398 | return false; |
399 | case MachineOperand::MO_BlockAddress: { |
400 | MCSymbol *Sym = GetBlockAddressSymbol(BA: MO.getBlockAddress()); |
401 | Sym->print(OS, MAI); |
402 | return false; |
403 | } |
404 | default: |
405 | break; |
406 | } |
407 | |
408 | return true; |
409 | } |
410 | |
411 | bool RISCVAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, |
412 | unsigned OpNo, |
413 | const char *, |
414 | raw_ostream &OS) { |
415 | if (ExtraCode) |
416 | return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS); |
417 | |
418 | const MachineOperand &AddrReg = MI->getOperand(i: OpNo); |
419 | assert(MI->getNumOperands() > OpNo + 1 && "Expected additional operand" ); |
420 | const MachineOperand &Offset = MI->getOperand(i: OpNo + 1); |
421 | // All memory operands should have a register and an immediate operand (see |
422 | // RISCVDAGToDAGISel::SelectInlineAsmMemoryOperand). |
423 | if (!AddrReg.isReg()) |
424 | return true; |
425 | if (!Offset.isImm() && !Offset.isGlobal() && !Offset.isBlockAddress() && |
426 | !Offset.isMCSymbol()) |
427 | return true; |
428 | |
429 | MCOperand MCO; |
430 | if (!lowerOperand(MO: Offset, MCOp&: MCO)) |
431 | return true; |
432 | |
433 | if (Offset.isImm()) |
434 | OS << MCO.getImm(); |
435 | else if (Offset.isGlobal() || Offset.isBlockAddress() || Offset.isMCSymbol()) |
436 | MAI->printExpr(OS, *MCO.getExpr()); |
437 | |
438 | if (Offset.isMCSymbol()) |
439 | MMI->getContext().registerInlineAsmLabel(Sym: Offset.getMCSymbol()); |
440 | if (Offset.isBlockAddress()) { |
441 | const BlockAddress *BA = Offset.getBlockAddress(); |
442 | MCSymbol *Sym = GetBlockAddressSymbol(BA); |
443 | MMI->getContext().registerInlineAsmLabel(Sym); |
444 | } |
445 | |
446 | OS << "(" << RISCVInstPrinter::getRegisterName(Reg: AddrReg.getReg()) << ")" ; |
447 | return false; |
448 | } |
449 | |
450 | bool RISCVAsmPrinter::emitDirectiveOptionArch() { |
451 | RISCVTargetStreamer &RTS = |
452 | static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer()); |
453 | SmallVector<RISCVOptionArchArg> NeedEmitStdOptionArgs; |
454 | const MCSubtargetInfo &MCSTI = *TM.getMCSubtargetInfo(); |
455 | for (const auto &Feature : RISCVFeatureKV) { |
456 | if (STI->hasFeature(Feature: Feature.Value) == MCSTI.hasFeature(Feature: Feature.Value)) |
457 | continue; |
458 | |
459 | if (!llvm::RISCVISAInfo::isSupportedExtensionFeature(Ext: Feature.Key)) |
460 | continue; |
461 | |
462 | auto Delta = STI->hasFeature(Feature: Feature.Value) ? RISCVOptionArchArgType::Plus |
463 | : RISCVOptionArchArgType::Minus; |
464 | NeedEmitStdOptionArgs.emplace_back(Args&: Delta, Args: Feature.Key); |
465 | } |
466 | if (!NeedEmitStdOptionArgs.empty()) { |
467 | RTS.emitDirectiveOptionPush(); |
468 | RTS.emitDirectiveOptionArch(Args: NeedEmitStdOptionArgs); |
469 | return true; |
470 | } |
471 | |
472 | return false; |
473 | } |
474 | |
475 | bool RISCVAsmPrinter::runOnMachineFunction(MachineFunction &MF) { |
476 | STI = &MF.getSubtarget<RISCVSubtarget>(); |
477 | RISCVTargetStreamer &RTS = |
478 | static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer()); |
479 | |
480 | bool EmittedOptionArch = emitDirectiveOptionArch(); |
481 | |
482 | SetupMachineFunction(MF); |
483 | emitFunctionBody(); |
484 | |
485 | // Emit the XRay table |
486 | emitXRayTable(); |
487 | |
488 | if (EmittedOptionArch) |
489 | RTS.emitDirectiveOptionPop(); |
490 | return false; |
491 | } |
492 | |
493 | void RISCVAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr *MI) { |
494 | emitSled(MI, Kind: SledKind::FUNCTION_ENTER); |
495 | } |
496 | |
497 | void RISCVAsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr *MI) { |
498 | emitSled(MI, Kind: SledKind::FUNCTION_EXIT); |
499 | } |
500 | |
501 | void RISCVAsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr *MI) { |
502 | emitSled(MI, Kind: SledKind::TAIL_CALL); |
503 | } |
504 | |
505 | void RISCVAsmPrinter::emitSled(const MachineInstr *MI, SledKind Kind) { |
506 | // We want to emit the jump instruction and the nops constituting the sled. |
507 | // The format is as follows: |
508 | // .Lxray_sled_N |
509 | // ALIGN |
510 | // J .tmpN |
511 | // 21 or 33 C.NOP instructions |
512 | // .tmpN |
513 | |
514 | // The following variable holds the count of the number of NOPs to be patched |
515 | // in for XRay instrumentation during compilation. |
516 | // Note that RV64 and RV32 each has a sled of 68 and 44 bytes, respectively. |
517 | // Assuming we're using JAL to jump to .tmpN, then we only need |
518 | // (68 - 4)/2 = 32 NOPs for RV64 and (44 - 4)/2 = 20 for RV32. However, there |
519 | // is a chance that we'll use C.JAL instead, so an additional NOP is needed. |
520 | const uint8_t NoopsInSledCount = |
521 | MI->getParent()->getParent()->getSubtarget<RISCVSubtarget>().is64Bit() |
522 | ? 33 |
523 | : 21; |
524 | |
525 | OutStreamer->emitCodeAlignment(Alignment: Align(4), STI: &getSubtargetInfo()); |
526 | auto CurSled = OutContext.createTempSymbol(Name: "xray_sled_" , AlwaysAddSuffix: true); |
527 | OutStreamer->emitLabel(Symbol: CurSled); |
528 | auto Target = OutContext.createTempSymbol(); |
529 | |
530 | const MCExpr *TargetExpr = MCSymbolRefExpr::create(Symbol: Target, Ctx&: OutContext); |
531 | |
532 | // Emit "J bytes" instruction, which jumps over the nop sled to the actual |
533 | // start of function. |
534 | EmitToStreamer( |
535 | S&: *OutStreamer, |
536 | Inst: MCInstBuilder(RISCV::JAL).addReg(Reg: RISCV::X0).addExpr(Val: TargetExpr)); |
537 | |
538 | // Emit NOP instructions |
539 | for (int8_t I = 0; I < NoopsInSledCount; ++I) |
540 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(RISCV::ADDI) |
541 | .addReg(Reg: RISCV::X0) |
542 | .addReg(Reg: RISCV::X0) |
543 | .addImm(Val: 0)); |
544 | |
545 | OutStreamer->emitLabel(Symbol: Target); |
546 | recordSled(Sled: CurSled, MI: *MI, Kind, Version: 2); |
547 | } |
548 | |
549 | void RISCVAsmPrinter::emitStartOfAsmFile(Module &M) { |
550 | RISCVTargetStreamer &RTS = |
551 | static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer()); |
552 | if (const MDString *ModuleTargetABI = |
553 | dyn_cast_or_null<MDString>(Val: M.getModuleFlag(Key: "target-abi" ))) |
554 | RTS.setTargetABI(RISCVABI::getTargetABI(ABIName: ModuleTargetABI->getString())); |
555 | |
556 | MCSubtargetInfo SubtargetInfo = *TM.getMCSubtargetInfo(); |
557 | |
558 | // Use module flag to update feature bits. |
559 | if (auto *MD = dyn_cast_or_null<MDNode>(Val: M.getModuleFlag(Key: "riscv-isa" ))) { |
560 | for (auto &ISA : MD->operands()) { |
561 | if (auto *ISAString = dyn_cast_or_null<MDString>(Val: ISA)) { |
562 | auto ParseResult = llvm::RISCVISAInfo::parseArchString( |
563 | Arch: ISAString->getString(), /*EnableExperimentalExtension=*/true, |
564 | /*ExperimentalExtensionVersionCheck=*/true); |
565 | if (!errorToBool(Err: ParseResult.takeError())) { |
566 | auto &ISAInfo = *ParseResult; |
567 | for (const auto &Feature : RISCVFeatureKV) { |
568 | if (ISAInfo->hasExtension(Ext: Feature.Key) && |
569 | !SubtargetInfo.hasFeature(Feature: Feature.Value)) |
570 | SubtargetInfo.ToggleFeature(FS: Feature.Key); |
571 | } |
572 | } |
573 | } |
574 | } |
575 | |
576 | RTS.setFlagsFromFeatures(SubtargetInfo); |
577 | } |
578 | |
579 | if (TM.getTargetTriple().isOSBinFormatELF()) |
580 | emitAttributes(SubtargetInfo); |
581 | } |
582 | |
583 | void RISCVAsmPrinter::emitEndOfAsmFile(Module &M) { |
584 | RISCVTargetStreamer &RTS = |
585 | static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer()); |
586 | |
587 | if (TM.getTargetTriple().isOSBinFormatELF()) { |
588 | RTS.finishAttributeSection(); |
589 | emitNoteGnuProperty(M); |
590 | } |
591 | EmitHwasanMemaccessSymbols(M); |
592 | } |
593 | |
594 | void RISCVAsmPrinter::emitAttributes(const MCSubtargetInfo &SubtargetInfo) { |
595 | RISCVTargetStreamer &RTS = |
596 | static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer()); |
597 | // Use MCSubtargetInfo from TargetMachine. Individual functions may have |
598 | // attributes that differ from other functions in the module and we have no |
599 | // way to know which function is correct. |
600 | RTS.emitTargetAttributes(STI: SubtargetInfo, /*EmitStackAlign*/ true); |
601 | } |
602 | |
603 | void RISCVAsmPrinter::emitFunctionEntryLabel() { |
604 | const auto *RMFI = MF->getInfo<RISCVMachineFunctionInfo>(); |
605 | if (RMFI->isVectorCall()) { |
606 | auto &RTS = |
607 | static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer()); |
608 | RTS.emitDirectiveVariantCC(Symbol&: *CurrentFnSym); |
609 | } |
610 | return AsmPrinter::emitFunctionEntryLabel(); |
611 | } |
612 | |
613 | // Force static initialization. |
614 | extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void |
615 | LLVMInitializeRISCVAsmPrinter() { |
616 | RegisterAsmPrinter<RISCVAsmPrinter> X(getTheRISCV32Target()); |
617 | RegisterAsmPrinter<RISCVAsmPrinter> Y(getTheRISCV64Target()); |
618 | } |
619 | |
620 | void RISCVAsmPrinter::LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI) { |
621 | Register Reg = MI.getOperand(i: 0).getReg(); |
622 | uint32_t AccessInfo = MI.getOperand(i: 1).getImm(); |
623 | MCSymbol *&Sym = |
624 | HwasanMemaccessSymbols[HwasanMemaccessTuple(Reg, AccessInfo)]; |
625 | if (!Sym) { |
626 | // FIXME: Make this work on non-ELF. |
627 | if (!TM.getTargetTriple().isOSBinFormatELF()) |
628 | report_fatal_error(reason: "llvm.hwasan.check.memaccess only supported on ELF" ); |
629 | |
630 | std::string SymName = "__hwasan_check_x" + utostr(X: Reg - RISCV::X0) + "_" + |
631 | utostr(X: AccessInfo) + "_short" ; |
632 | Sym = OutContext.getOrCreateSymbol(Name: SymName); |
633 | } |
634 | auto Res = MCSymbolRefExpr::create(Symbol: Sym, Ctx&: OutContext); |
635 | auto Expr = MCSpecifierExpr::create(Expr: Res, S: ELF::R_RISCV_CALL_PLT, Ctx&: OutContext); |
636 | |
637 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(RISCV::PseudoCALL).addExpr(Val: Expr)); |
638 | } |
639 | |
640 | void RISCVAsmPrinter::LowerKCFI_CHECK(const MachineInstr &MI) { |
641 | Register AddrReg = MI.getOperand(i: 0).getReg(); |
642 | assert(std::next(MI.getIterator())->isCall() && |
643 | "KCFI_CHECK not followed by a call instruction" ); |
644 | assert(std::next(MI.getIterator())->getOperand(0).getReg() == AddrReg && |
645 | "KCFI_CHECK call target doesn't match call operand" ); |
646 | |
647 | // Temporary registers for comparing the hashes. If a register is used |
648 | // for the call target, or reserved by the user, we can clobber another |
649 | // temporary register as the check is immediately followed by the |
650 | // call. The check defaults to X6/X7, but can fall back to X28-X31 if |
651 | // needed. |
652 | unsigned ScratchRegs[] = {RISCV::X6, RISCV::X7}; |
653 | unsigned NextReg = RISCV::X28; |
654 | auto isRegAvailable = [&](unsigned Reg) { |
655 | return Reg != AddrReg && !STI->isRegisterReservedByUser(i: Reg); |
656 | }; |
657 | for (auto &Reg : ScratchRegs) { |
658 | if (isRegAvailable(Reg)) |
659 | continue; |
660 | while (!isRegAvailable(NextReg)) |
661 | ++NextReg; |
662 | Reg = NextReg++; |
663 | if (Reg > RISCV::X31) |
664 | report_fatal_error(reason: "Unable to find scratch registers for KCFI_CHECK" ); |
665 | } |
666 | |
667 | if (AddrReg == RISCV::X0) { |
668 | // Checking X0 makes no sense. Instead of emitting a load, zero |
669 | // ScratchRegs[0]. |
670 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(RISCV::ADDI) |
671 | .addReg(Reg: ScratchRegs[0]) |
672 | .addReg(Reg: RISCV::X0) |
673 | .addImm(Val: 0)); |
674 | } else { |
675 | // Adjust the offset for patchable-function-prefix. This assumes that |
676 | // patchable-function-prefix is the same for all functions. |
677 | int NopSize = STI->hasStdExtZca() ? 2 : 4; |
678 | int64_t PrefixNops = 0; |
679 | (void)MI.getMF() |
680 | ->getFunction() |
681 | .getFnAttribute(Kind: "patchable-function-prefix" ) |
682 | .getValueAsString() |
683 | .getAsInteger(Radix: 10, Result&: PrefixNops); |
684 | |
685 | // Load the target function type hash. |
686 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(RISCV::LW) |
687 | .addReg(Reg: ScratchRegs[0]) |
688 | .addReg(Reg: AddrReg) |
689 | .addImm(Val: -(PrefixNops * NopSize + 4))); |
690 | } |
691 | |
692 | // Load the expected 32-bit type hash. |
693 | const int64_t Type = MI.getOperand(i: 1).getImm(); |
694 | const int64_t Hi20 = ((Type + 0x800) >> 12) & 0xFFFFF; |
695 | const int64_t Lo12 = SignExtend64<12>(x: Type); |
696 | if (Hi20) { |
697 | EmitToStreamer( |
698 | S&: *OutStreamer, |
699 | Inst: MCInstBuilder(RISCV::LUI).addReg(Reg: ScratchRegs[1]).addImm(Val: Hi20)); |
700 | } |
701 | if (Lo12 || Hi20 == 0) { |
702 | EmitToStreamer(S&: *OutStreamer, |
703 | Inst: MCInstBuilder((STI->hasFeature(Feature: RISCV::Feature64Bit) && Hi20) |
704 | ? RISCV::ADDIW |
705 | : RISCV::ADDI) |
706 | .addReg(Reg: ScratchRegs[1]) |
707 | .addReg(Reg: ScratchRegs[1]) |
708 | .addImm(Val: Lo12)); |
709 | } |
710 | |
711 | // Compare the hashes and trap if there's a mismatch. |
712 | MCSymbol *Pass = OutContext.createTempSymbol(); |
713 | EmitToStreamer(S&: *OutStreamer, |
714 | Inst: MCInstBuilder(RISCV::BEQ) |
715 | .addReg(Reg: ScratchRegs[0]) |
716 | .addReg(Reg: ScratchRegs[1]) |
717 | .addExpr(Val: MCSymbolRefExpr::create(Symbol: Pass, Ctx&: OutContext))); |
718 | |
719 | MCSymbol *Trap = OutContext.createTempSymbol(); |
720 | OutStreamer->emitLabel(Symbol: Trap); |
721 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(RISCV::EBREAK)); |
722 | emitKCFITrapEntry(MF: *MI.getMF(), Symbol: Trap); |
723 | OutStreamer->emitLabel(Symbol: Pass); |
724 | } |
725 | |
726 | void RISCVAsmPrinter::EmitHwasanMemaccessSymbols(Module &M) { |
727 | if (HwasanMemaccessSymbols.empty()) |
728 | return; |
729 | |
730 | assert(TM.getTargetTriple().isOSBinFormatELF()); |
731 | // Use MCSubtargetInfo from TargetMachine. Individual functions may have |
732 | // attributes that differ from other functions in the module and we have no |
733 | // way to know which function is correct. |
734 | const MCSubtargetInfo &MCSTI = *TM.getMCSubtargetInfo(); |
735 | |
736 | MCSymbol *HwasanTagMismatchV2Sym = |
737 | OutContext.getOrCreateSymbol(Name: "__hwasan_tag_mismatch_v2" ); |
738 | // Annotate symbol as one having incompatible calling convention, so |
739 | // run-time linkers can instead eagerly bind this function. |
740 | auto &RTS = |
741 | static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer()); |
742 | RTS.emitDirectiveVariantCC(Symbol&: *HwasanTagMismatchV2Sym); |
743 | |
744 | const MCSymbolRefExpr *HwasanTagMismatchV2Ref = |
745 | MCSymbolRefExpr::create(Symbol: HwasanTagMismatchV2Sym, Ctx&: OutContext); |
746 | auto Expr = MCSpecifierExpr::create(Expr: HwasanTagMismatchV2Ref, |
747 | S: ELF::R_RISCV_CALL_PLT, Ctx&: OutContext); |
748 | |
749 | for (auto &P : HwasanMemaccessSymbols) { |
750 | unsigned Reg = std::get<0>(t: P.first); |
751 | uint32_t AccessInfo = std::get<1>(t: P.first); |
752 | MCSymbol *Sym = P.second; |
753 | |
754 | unsigned Size = |
755 | 1 << ((AccessInfo >> HWASanAccessInfo::AccessSizeShift) & 0xf); |
756 | OutStreamer->switchSection(Section: OutContext.getELFSection( |
757 | Section: ".text.hot" , Type: ELF::SHT_PROGBITS, |
758 | Flags: ELF::SHF_EXECINSTR | ELF::SHF_ALLOC | ELF::SHF_GROUP, EntrySize: 0, Group: Sym->getName(), |
759 | /*IsComdat=*/true)); |
760 | |
761 | OutStreamer->emitSymbolAttribute(Symbol: Sym, Attribute: MCSA_ELF_TypeFunction); |
762 | OutStreamer->emitSymbolAttribute(Symbol: Sym, Attribute: MCSA_Weak); |
763 | OutStreamer->emitSymbolAttribute(Symbol: Sym, Attribute: MCSA_Hidden); |
764 | OutStreamer->emitLabel(Symbol: Sym); |
765 | |
766 | // Extract shadow offset from ptr |
767 | EmitToStreamer( |
768 | S&: *OutStreamer, |
769 | Inst: MCInstBuilder(RISCV::SLLI).addReg(Reg: RISCV::X6).addReg(Reg).addImm(Val: 8), |
770 | SubtargetInfo: MCSTI); |
771 | EmitToStreamer(S&: *OutStreamer, |
772 | Inst: MCInstBuilder(RISCV::SRLI) |
773 | .addReg(Reg: RISCV::X6) |
774 | .addReg(Reg: RISCV::X6) |
775 | .addImm(Val: 12), |
776 | SubtargetInfo: MCSTI); |
777 | // load shadow tag in X6, X5 contains shadow base |
778 | EmitToStreamer(S&: *OutStreamer, |
779 | Inst: MCInstBuilder(RISCV::ADD) |
780 | .addReg(Reg: RISCV::X6) |
781 | .addReg(Reg: RISCV::X5) |
782 | .addReg(Reg: RISCV::X6), |
783 | SubtargetInfo: MCSTI); |
784 | EmitToStreamer( |
785 | S&: *OutStreamer, |
786 | Inst: MCInstBuilder(RISCV::LBU).addReg(Reg: RISCV::X6).addReg(Reg: RISCV::X6).addImm(Val: 0), |
787 | SubtargetInfo: MCSTI); |
788 | // Extract tag from pointer and compare it with loaded tag from shadow |
789 | EmitToStreamer( |
790 | S&: *OutStreamer, |
791 | Inst: MCInstBuilder(RISCV::SRLI).addReg(Reg: RISCV::X7).addReg(Reg).addImm(Val: 56), |
792 | SubtargetInfo: MCSTI); |
793 | MCSymbol *HandleMismatchOrPartialSym = OutContext.createTempSymbol(); |
794 | // X7 contains tag from the pointer, while X6 contains tag from memory |
795 | EmitToStreamer(S&: *OutStreamer, |
796 | Inst: MCInstBuilder(RISCV::BNE) |
797 | .addReg(Reg: RISCV::X7) |
798 | .addReg(Reg: RISCV::X6) |
799 | .addExpr(Val: MCSymbolRefExpr::create( |
800 | Symbol: HandleMismatchOrPartialSym, Ctx&: OutContext)), |
801 | SubtargetInfo: MCSTI); |
802 | MCSymbol *ReturnSym = OutContext.createTempSymbol(); |
803 | OutStreamer->emitLabel(Symbol: ReturnSym); |
804 | EmitToStreamer(S&: *OutStreamer, |
805 | Inst: MCInstBuilder(RISCV::JALR) |
806 | .addReg(Reg: RISCV::X0) |
807 | .addReg(Reg: RISCV::X1) |
808 | .addImm(Val: 0), |
809 | SubtargetInfo: MCSTI); |
810 | OutStreamer->emitLabel(Symbol: HandleMismatchOrPartialSym); |
811 | |
812 | EmitToStreamer(S&: *OutStreamer, |
813 | Inst: MCInstBuilder(RISCV::ADDI) |
814 | .addReg(Reg: RISCV::X28) |
815 | .addReg(Reg: RISCV::X0) |
816 | .addImm(Val: 16), |
817 | SubtargetInfo: MCSTI); |
818 | MCSymbol *HandleMismatchSym = OutContext.createTempSymbol(); |
819 | EmitToStreamer( |
820 | S&: *OutStreamer, |
821 | Inst: MCInstBuilder(RISCV::BGEU) |
822 | .addReg(Reg: RISCV::X6) |
823 | .addReg(Reg: RISCV::X28) |
824 | .addExpr(Val: MCSymbolRefExpr::create(Symbol: HandleMismatchSym, Ctx&: OutContext)), |
825 | SubtargetInfo: MCSTI); |
826 | |
827 | EmitToStreamer( |
828 | S&: *OutStreamer, |
829 | Inst: MCInstBuilder(RISCV::ANDI).addReg(Reg: RISCV::X28).addReg(Reg).addImm(Val: 0xF), |
830 | SubtargetInfo: MCSTI); |
831 | |
832 | if (Size != 1) |
833 | EmitToStreamer(S&: *OutStreamer, |
834 | Inst: MCInstBuilder(RISCV::ADDI) |
835 | .addReg(Reg: RISCV::X28) |
836 | .addReg(Reg: RISCV::X28) |
837 | .addImm(Val: Size - 1), |
838 | SubtargetInfo: MCSTI); |
839 | EmitToStreamer( |
840 | S&: *OutStreamer, |
841 | Inst: MCInstBuilder(RISCV::BGE) |
842 | .addReg(Reg: RISCV::X28) |
843 | .addReg(Reg: RISCV::X6) |
844 | .addExpr(Val: MCSymbolRefExpr::create(Symbol: HandleMismatchSym, Ctx&: OutContext)), |
845 | SubtargetInfo: MCSTI); |
846 | |
847 | EmitToStreamer( |
848 | S&: *OutStreamer, |
849 | Inst: MCInstBuilder(RISCV::ORI).addReg(Reg: RISCV::X6).addReg(Reg).addImm(Val: 0xF), |
850 | SubtargetInfo: MCSTI); |
851 | EmitToStreamer( |
852 | S&: *OutStreamer, |
853 | Inst: MCInstBuilder(RISCV::LBU).addReg(Reg: RISCV::X6).addReg(Reg: RISCV::X6).addImm(Val: 0), |
854 | SubtargetInfo: MCSTI); |
855 | EmitToStreamer(S&: *OutStreamer, |
856 | Inst: MCInstBuilder(RISCV::BEQ) |
857 | .addReg(Reg: RISCV::X6) |
858 | .addReg(Reg: RISCV::X7) |
859 | .addExpr(Val: MCSymbolRefExpr::create(Symbol: ReturnSym, Ctx&: OutContext)), |
860 | SubtargetInfo: MCSTI); |
861 | |
862 | OutStreamer->emitLabel(Symbol: HandleMismatchSym); |
863 | |
864 | // | Previous stack frames... | |
865 | // +=================================+ <-- [SP + 256] |
866 | // | ... | |
867 | // | | |
868 | // | Stack frame space for x12 - x31.| |
869 | // | | |
870 | // | ... | |
871 | // +---------------------------------+ <-- [SP + 96] |
872 | // | Saved x11(arg1), as | |
873 | // | __hwasan_check_* clobbers it. | |
874 | // +---------------------------------+ <-- [SP + 88] |
875 | // | Saved x10(arg0), as | |
876 | // | __hwasan_check_* clobbers it. | |
877 | // +---------------------------------+ <-- [SP + 80] |
878 | // | | |
879 | // | Stack frame space for x9. | |
880 | // +---------------------------------+ <-- [SP + 72] |
881 | // | | |
882 | // | Saved x8(fp), as | |
883 | // | __hwasan_check_* clobbers it. | |
884 | // +---------------------------------+ <-- [SP + 64] |
885 | // | ... | |
886 | // | | |
887 | // | Stack frame space for x2 - x7. | |
888 | // | | |
889 | // | ... | |
890 | // +---------------------------------+ <-- [SP + 16] |
891 | // | Return address (x1) for caller | |
892 | // | of __hwasan_check_*. | |
893 | // +---------------------------------+ <-- [SP + 8] |
894 | // | Reserved place for x0, possibly | |
895 | // | junk, since we don't save it. | |
896 | // +---------------------------------+ <-- [x2 / SP] |
897 | |
898 | // Adjust sp |
899 | EmitToStreamer(S&: *OutStreamer, |
900 | Inst: MCInstBuilder(RISCV::ADDI) |
901 | .addReg(Reg: RISCV::X2) |
902 | .addReg(Reg: RISCV::X2) |
903 | .addImm(Val: -256), |
904 | SubtargetInfo: MCSTI); |
905 | |
906 | // store x10(arg0) by new sp |
907 | EmitToStreamer(S&: *OutStreamer, |
908 | Inst: MCInstBuilder(RISCV::SD) |
909 | .addReg(Reg: RISCV::X10) |
910 | .addReg(Reg: RISCV::X2) |
911 | .addImm(Val: 8 * 10), |
912 | SubtargetInfo: MCSTI); |
913 | // store x11(arg1) by new sp |
914 | EmitToStreamer(S&: *OutStreamer, |
915 | Inst: MCInstBuilder(RISCV::SD) |
916 | .addReg(Reg: RISCV::X11) |
917 | .addReg(Reg: RISCV::X2) |
918 | .addImm(Val: 8 * 11), |
919 | SubtargetInfo: MCSTI); |
920 | |
921 | // store x8(fp) by new sp |
922 | EmitToStreamer( |
923 | S&: *OutStreamer, |
924 | Inst: MCInstBuilder(RISCV::SD).addReg(Reg: RISCV::X8).addReg(Reg: RISCV::X2).addImm(Val: 8 * |
925 | 8), |
926 | SubtargetInfo: MCSTI); |
927 | // store x1(ra) by new sp |
928 | EmitToStreamer( |
929 | S&: *OutStreamer, |
930 | Inst: MCInstBuilder(RISCV::SD).addReg(Reg: RISCV::X1).addReg(Reg: RISCV::X2).addImm(Val: 1 * |
931 | 8), |
932 | SubtargetInfo: MCSTI); |
933 | if (Reg != RISCV::X10) |
934 | EmitToStreamer( |
935 | S&: *OutStreamer, |
936 | Inst: MCInstBuilder(RISCV::ADDI).addReg(Reg: RISCV::X10).addReg(Reg).addImm(Val: 0), |
937 | SubtargetInfo: MCSTI); |
938 | EmitToStreamer(S&: *OutStreamer, |
939 | Inst: MCInstBuilder(RISCV::ADDI) |
940 | .addReg(Reg: RISCV::X11) |
941 | .addReg(Reg: RISCV::X0) |
942 | .addImm(Val: AccessInfo & HWASanAccessInfo::RuntimeMask), |
943 | SubtargetInfo: MCSTI); |
944 | |
945 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(RISCV::PseudoCALL).addExpr(Val: Expr), |
946 | SubtargetInfo: MCSTI); |
947 | } |
948 | } |
949 | |
950 | void RISCVAsmPrinter::emitNoteGnuProperty(const Module &M) { |
951 | if (const Metadata *const Flag = M.getModuleFlag(Key: "cf-protection-return" ); |
952 | Flag && !mdconst::extract<ConstantInt>(MD: Flag)->isZero()) { |
953 | RISCVTargetStreamer &RTS = |
954 | static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer()); |
955 | RTS.emitNoteGnuPropertySection(Feature1And: ELF::GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS); |
956 | } |
957 | } |
958 | |
959 | static MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym, |
960 | const AsmPrinter &AP) { |
961 | MCContext &Ctx = AP.OutContext; |
962 | RISCV::Specifier Kind; |
963 | |
964 | switch (MO.getTargetFlags()) { |
965 | default: |
966 | llvm_unreachable("Unknown target flag on GV operand" ); |
967 | case RISCVII::MO_None: |
968 | Kind = RISCV::S_None; |
969 | break; |
970 | case RISCVII::MO_CALL: |
971 | Kind = ELF::R_RISCV_CALL_PLT; |
972 | break; |
973 | case RISCVII::MO_LO: |
974 | Kind = RISCV::S_LO; |
975 | break; |
976 | case RISCVII::MO_HI: |
977 | Kind = ELF::R_RISCV_HI20; |
978 | break; |
979 | case RISCVII::MO_PCREL_LO: |
980 | Kind = RISCV::S_PCREL_LO; |
981 | break; |
982 | case RISCVII::MO_PCREL_HI: |
983 | Kind = ELF::R_RISCV_PCREL_HI20; |
984 | break; |
985 | case RISCVII::MO_GOT_HI: |
986 | Kind = ELF::R_RISCV_GOT_HI20; |
987 | break; |
988 | case RISCVII::MO_TPREL_LO: |
989 | Kind = RISCV::S_TPREL_LO; |
990 | break; |
991 | case RISCVII::MO_TPREL_HI: |
992 | Kind = ELF::R_RISCV_TPREL_HI20; |
993 | break; |
994 | case RISCVII::MO_TPREL_ADD: |
995 | Kind = ELF::R_RISCV_TPREL_ADD; |
996 | break; |
997 | case RISCVII::MO_TLS_GOT_HI: |
998 | Kind = ELF::R_RISCV_TLS_GOT_HI20; |
999 | break; |
1000 | case RISCVII::MO_TLS_GD_HI: |
1001 | Kind = ELF::R_RISCV_TLS_GD_HI20; |
1002 | break; |
1003 | case RISCVII::MO_TLSDESC_HI: |
1004 | Kind = ELF::R_RISCV_TLSDESC_HI20; |
1005 | break; |
1006 | case RISCVII::MO_TLSDESC_LOAD_LO: |
1007 | Kind = ELF::R_RISCV_TLSDESC_LOAD_LO12; |
1008 | break; |
1009 | case RISCVII::MO_TLSDESC_ADD_LO: |
1010 | Kind = ELF::R_RISCV_TLSDESC_ADD_LO12; |
1011 | break; |
1012 | case RISCVII::MO_TLSDESC_CALL: |
1013 | Kind = ELF::R_RISCV_TLSDESC_CALL; |
1014 | break; |
1015 | } |
1016 | |
1017 | const MCExpr *ME = MCSymbolRefExpr::create(Symbol: Sym, Ctx); |
1018 | |
1019 | if (!MO.isJTI() && !MO.isMBB() && MO.getOffset()) |
1020 | ME = MCBinaryExpr::createAdd( |
1021 | LHS: ME, RHS: MCConstantExpr::create(Value: MO.getOffset(), Ctx), Ctx); |
1022 | |
1023 | if (Kind != RISCV::S_None) |
1024 | ME = MCSpecifierExpr::create(Expr: ME, S: Kind, Ctx); |
1025 | return MCOperand::createExpr(Val: ME); |
1026 | } |
1027 | |
1028 | bool RISCVAsmPrinter::lowerOperand(const MachineOperand &MO, |
1029 | MCOperand &MCOp) const { |
1030 | switch (MO.getType()) { |
1031 | default: |
1032 | report_fatal_error(reason: "lowerOperand: unknown operand type" ); |
1033 | case MachineOperand::MO_Register: |
1034 | // Ignore all implicit register operands. |
1035 | if (MO.isImplicit()) |
1036 | return false; |
1037 | MCOp = MCOperand::createReg(Reg: MO.getReg()); |
1038 | break; |
1039 | case MachineOperand::MO_RegisterMask: |
1040 | // Regmasks are like implicit defs. |
1041 | return false; |
1042 | case MachineOperand::MO_Immediate: |
1043 | MCOp = MCOperand::createImm(Val: MO.getImm()); |
1044 | break; |
1045 | case MachineOperand::MO_MachineBasicBlock: |
1046 | MCOp = lowerSymbolOperand(MO, Sym: MO.getMBB()->getSymbol(), AP: *this); |
1047 | break; |
1048 | case MachineOperand::MO_GlobalAddress: |
1049 | MCOp = lowerSymbolOperand(MO, Sym: getSymbolPreferLocal(GV: *MO.getGlobal()), AP: *this); |
1050 | break; |
1051 | case MachineOperand::MO_BlockAddress: |
1052 | MCOp = lowerSymbolOperand(MO, Sym: GetBlockAddressSymbol(BA: MO.getBlockAddress()), |
1053 | AP: *this); |
1054 | break; |
1055 | case MachineOperand::MO_ExternalSymbol: |
1056 | MCOp = lowerSymbolOperand(MO, Sym: GetExternalSymbolSymbol(Sym: MO.getSymbolName()), |
1057 | AP: *this); |
1058 | break; |
1059 | case MachineOperand::MO_ConstantPoolIndex: |
1060 | MCOp = lowerSymbolOperand(MO, Sym: GetCPISymbol(CPID: MO.getIndex()), AP: *this); |
1061 | break; |
1062 | case MachineOperand::MO_JumpTableIndex: |
1063 | MCOp = lowerSymbolOperand(MO, Sym: GetJTISymbol(JTID: MO.getIndex()), AP: *this); |
1064 | break; |
1065 | case MachineOperand::MO_MCSymbol: |
1066 | MCOp = lowerSymbolOperand(MO, Sym: MO.getMCSymbol(), AP: *this); |
1067 | break; |
1068 | } |
1069 | return true; |
1070 | } |
1071 | |
1072 | static bool lowerRISCVVMachineInstrToMCInst(const MachineInstr *MI, |
1073 | MCInst &OutMI) { |
1074 | const RISCVVPseudosTable::PseudoInfo *RVV = |
1075 | RISCVVPseudosTable::getPseudoInfo(Pseudo: MI->getOpcode()); |
1076 | if (!RVV) |
1077 | return false; |
1078 | |
1079 | OutMI.setOpcode(RVV->BaseInstr); |
1080 | |
1081 | const MachineBasicBlock *MBB = MI->getParent(); |
1082 | assert(MBB && "MI expected to be in a basic block" ); |
1083 | const MachineFunction *MF = MBB->getParent(); |
1084 | assert(MF && "MBB expected to be in a machine function" ); |
1085 | |
1086 | const RISCVSubtarget &Subtarget = MF->getSubtarget<RISCVSubtarget>(); |
1087 | const TargetInstrInfo *TII = Subtarget.getInstrInfo(); |
1088 | const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo(); |
1089 | assert(TRI && "TargetRegisterInfo expected" ); |
1090 | |
1091 | const MCInstrDesc &MCID = MI->getDesc(); |
1092 | uint64_t TSFlags = MCID.TSFlags; |
1093 | unsigned NumOps = MI->getNumExplicitOperands(); |
1094 | |
1095 | // Skip policy, SEW, VL, VXRM/FRM operands which are the last operands if |
1096 | // present. |
1097 | if (RISCVII::hasVecPolicyOp(TSFlags)) |
1098 | --NumOps; |
1099 | if (RISCVII::hasSEWOp(TSFlags)) |
1100 | --NumOps; |
1101 | if (RISCVII::hasVLOp(TSFlags)) |
1102 | --NumOps; |
1103 | if (RISCVII::hasRoundModeOp(TSFlags)) |
1104 | --NumOps; |
1105 | |
1106 | bool hasVLOutput = RISCVInstrInfo::isFaultOnlyFirstLoad(MI: *MI); |
1107 | for (unsigned OpNo = 0; OpNo != NumOps; ++OpNo) { |
1108 | const MachineOperand &MO = MI->getOperand(i: OpNo); |
1109 | // Skip vl output. It should be the second output. |
1110 | if (hasVLOutput && OpNo == 1) |
1111 | continue; |
1112 | |
1113 | // Skip passthru op. It should be the first operand after the defs. |
1114 | if (OpNo == MI->getNumExplicitDefs() && MO.isReg() && MO.isTied()) { |
1115 | assert(MCID.getOperandConstraint(OpNo, MCOI::TIED_TO) == 0 && |
1116 | "Expected tied to first def." ); |
1117 | const MCInstrDesc &OutMCID = TII->get(Opcode: OutMI.getOpcode()); |
1118 | // Skip if the next operand in OutMI is not supposed to be tied. Unless it |
1119 | // is a _TIED instruction. |
1120 | if (OutMCID.getOperandConstraint(OpNum: OutMI.getNumOperands(), Constraint: MCOI::TIED_TO) < |
1121 | 0 && |
1122 | !RISCVII::isTiedPseudo(TSFlags)) |
1123 | continue; |
1124 | } |
1125 | |
1126 | MCOperand MCOp; |
1127 | switch (MO.getType()) { |
1128 | default: |
1129 | llvm_unreachable("Unknown operand type" ); |
1130 | case MachineOperand::MO_Register: { |
1131 | Register Reg = MO.getReg(); |
1132 | |
1133 | if (RISCV::VRM2RegClass.contains(Reg) || |
1134 | RISCV::VRM4RegClass.contains(Reg) || |
1135 | RISCV::VRM8RegClass.contains(Reg)) { |
1136 | Reg = TRI->getSubReg(Reg, Idx: RISCV::sub_vrm1_0); |
1137 | assert(Reg && "Subregister does not exist" ); |
1138 | } else if (RISCV::FPR16RegClass.contains(Reg)) { |
1139 | Reg = |
1140 | TRI->getMatchingSuperReg(Reg, SubIdx: RISCV::sub_16, RC: &RISCV::FPR32RegClass); |
1141 | assert(Reg && "Subregister does not exist" ); |
1142 | } else if (RISCV::FPR64RegClass.contains(Reg)) { |
1143 | Reg = TRI->getSubReg(Reg, Idx: RISCV::sub_32); |
1144 | assert(Reg && "Superregister does not exist" ); |
1145 | } else if (RISCV::VRN2M1RegClass.contains(Reg) || |
1146 | RISCV::VRN2M2RegClass.contains(Reg) || |
1147 | RISCV::VRN2M4RegClass.contains(Reg) || |
1148 | RISCV::VRN3M1RegClass.contains(Reg) || |
1149 | RISCV::VRN3M2RegClass.contains(Reg) || |
1150 | RISCV::VRN4M1RegClass.contains(Reg) || |
1151 | RISCV::VRN4M2RegClass.contains(Reg) || |
1152 | RISCV::VRN5M1RegClass.contains(Reg) || |
1153 | RISCV::VRN6M1RegClass.contains(Reg) || |
1154 | RISCV::VRN7M1RegClass.contains(Reg) || |
1155 | RISCV::VRN8M1RegClass.contains(Reg)) { |
1156 | Reg = TRI->getSubReg(Reg, Idx: RISCV::sub_vrm1_0); |
1157 | assert(Reg && "Subregister does not exist" ); |
1158 | } |
1159 | |
1160 | MCOp = MCOperand::createReg(Reg); |
1161 | break; |
1162 | } |
1163 | case MachineOperand::MO_Immediate: |
1164 | MCOp = MCOperand::createImm(Val: MO.getImm()); |
1165 | break; |
1166 | } |
1167 | OutMI.addOperand(Op: MCOp); |
1168 | } |
1169 | |
1170 | // Unmasked pseudo instructions need to append dummy mask operand to |
1171 | // V instructions. All V instructions are modeled as the masked version. |
1172 | const MCInstrDesc &OutMCID = TII->get(Opcode: OutMI.getOpcode()); |
1173 | if (OutMI.getNumOperands() < OutMCID.getNumOperands()) { |
1174 | assert(OutMCID.operands()[OutMI.getNumOperands()].RegClass == |
1175 | RISCV::VMV0RegClassID && |
1176 | "Expected only mask operand to be missing" ); |
1177 | OutMI.addOperand(Op: MCOperand::createReg(Reg: RISCV::NoRegister)); |
1178 | } |
1179 | |
1180 | assert(OutMI.getNumOperands() == OutMCID.getNumOperands()); |
1181 | return true; |
1182 | } |
1183 | |
1184 | bool RISCVAsmPrinter::lowerToMCInst(const MachineInstr *MI, MCInst &OutMI) { |
1185 | if (lowerRISCVVMachineInstrToMCInst(MI, OutMI)) |
1186 | return false; |
1187 | |
1188 | OutMI.setOpcode(MI->getOpcode()); |
1189 | |
1190 | for (const MachineOperand &MO : MI->operands()) { |
1191 | MCOperand MCOp; |
1192 | if (lowerOperand(MO, MCOp)) |
1193 | OutMI.addOperand(Op: MCOp); |
1194 | } |
1195 | |
1196 | switch (OutMI.getOpcode()) { |
1197 | case TargetOpcode::PATCHABLE_FUNCTION_ENTER: { |
1198 | const Function &F = MI->getParent()->getParent()->getFunction(); |
1199 | if (F.hasFnAttribute(Kind: "patchable-function-entry" )) { |
1200 | unsigned Num; |
1201 | if (F.getFnAttribute(Kind: "patchable-function-entry" ) |
1202 | .getValueAsString() |
1203 | .getAsInteger(Radix: 10, Result&: Num)) |
1204 | return false; |
1205 | emitNops(N: Num); |
1206 | return true; |
1207 | } |
1208 | break; |
1209 | } |
1210 | } |
1211 | return false; |
1212 | } |
1213 | |
1214 | void RISCVAsmPrinter::emitMachineConstantPoolValue( |
1215 | MachineConstantPoolValue *MCPV) { |
1216 | auto *RCPV = static_cast<RISCVConstantPoolValue *>(MCPV); |
1217 | MCSymbol *MCSym; |
1218 | |
1219 | if (RCPV->isGlobalValue()) { |
1220 | auto *GV = RCPV->getGlobalValue(); |
1221 | MCSym = getSymbol(GV); |
1222 | } else { |
1223 | assert(RCPV->isExtSymbol() && "unrecognized constant pool type" ); |
1224 | auto Sym = RCPV->getSymbol(); |
1225 | MCSym = GetExternalSymbolSymbol(Sym); |
1226 | } |
1227 | |
1228 | const MCExpr *Expr = MCSymbolRefExpr::create(Symbol: MCSym, Ctx&: OutContext); |
1229 | uint64_t Size = getDataLayout().getTypeAllocSize(Ty: RCPV->getType()); |
1230 | OutStreamer->emitValue(Value: Expr, Size); |
1231 | } |
1232 | |
1233 | char RISCVAsmPrinter::ID = 0; |
1234 | |
1235 | INITIALIZE_PASS(RISCVAsmPrinter, "riscv-asm-printer" , "RISC-V Assembly Printer" , |
1236 | false, false) |
1237 | |