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