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