Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Target/Mips/MipsAsmPrinter.cpp
35294 views
1
//===- MipsAsmPrinter.cpp - Mips LLVM Assembly Printer --------------------===//
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 GAS-format MIPS assembly language.
11
//
12
//===----------------------------------------------------------------------===//
13
14
#include "MipsAsmPrinter.h"
15
#include "MCTargetDesc/MipsABIInfo.h"
16
#include "MCTargetDesc/MipsBaseInfo.h"
17
#include "MCTargetDesc/MipsInstPrinter.h"
18
#include "MCTargetDesc/MipsMCNaCl.h"
19
#include "MCTargetDesc/MipsMCTargetDesc.h"
20
#include "Mips.h"
21
#include "MipsMCInstLower.h"
22
#include "MipsMachineFunction.h"
23
#include "MipsSubtarget.h"
24
#include "MipsTargetMachine.h"
25
#include "MipsTargetStreamer.h"
26
#include "TargetInfo/MipsTargetInfo.h"
27
#include "llvm/ADT/SmallString.h"
28
#include "llvm/ADT/StringRef.h"
29
#include "llvm/ADT/Twine.h"
30
#include "llvm/BinaryFormat/ELF.h"
31
#include "llvm/CodeGen/MachineBasicBlock.h"
32
#include "llvm/CodeGen/MachineConstantPool.h"
33
#include "llvm/CodeGen/MachineFrameInfo.h"
34
#include "llvm/CodeGen/MachineFunction.h"
35
#include "llvm/CodeGen/MachineInstr.h"
36
#include "llvm/CodeGen/MachineJumpTableInfo.h"
37
#include "llvm/CodeGen/MachineOperand.h"
38
#include "llvm/CodeGen/TargetRegisterInfo.h"
39
#include "llvm/CodeGen/TargetSubtargetInfo.h"
40
#include "llvm/IR/Attributes.h"
41
#include "llvm/IR/BasicBlock.h"
42
#include "llvm/IR/DataLayout.h"
43
#include "llvm/IR/Function.h"
44
#include "llvm/IR/InlineAsm.h"
45
#include "llvm/IR/Instructions.h"
46
#include "llvm/IR/Module.h"
47
#include "llvm/MC/MCContext.h"
48
#include "llvm/MC/MCExpr.h"
49
#include "llvm/MC/MCInst.h"
50
#include "llvm/MC/MCInstBuilder.h"
51
#include "llvm/MC/MCObjectFileInfo.h"
52
#include "llvm/MC/MCSectionELF.h"
53
#include "llvm/MC/MCSymbol.h"
54
#include "llvm/MC/MCSymbolELF.h"
55
#include "llvm/MC/TargetRegistry.h"
56
#include "llvm/Support/Casting.h"
57
#include "llvm/Support/ErrorHandling.h"
58
#include "llvm/Support/raw_ostream.h"
59
#include "llvm/Target/TargetLoweringObjectFile.h"
60
#include "llvm/Target/TargetMachine.h"
61
#include "llvm/TargetParser/Triple.h"
62
#include <cassert>
63
#include <cstdint>
64
#include <map>
65
#include <memory>
66
#include <string>
67
#include <vector>
68
69
using namespace llvm;
70
71
#define DEBUG_TYPE "mips-asm-printer"
72
73
extern cl::opt<bool> EmitJalrReloc;
74
75
MipsTargetStreamer &MipsAsmPrinter::getTargetStreamer() const {
76
return static_cast<MipsTargetStreamer &>(*OutStreamer->getTargetStreamer());
77
}
78
79
bool MipsAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
80
Subtarget = &MF.getSubtarget<MipsSubtarget>();
81
82
MipsFI = MF.getInfo<MipsFunctionInfo>();
83
if (Subtarget->inMips16Mode())
84
for (const auto &I : MipsFI->StubsNeeded) {
85
const char *Symbol = I.first;
86
const Mips16HardFloatInfo::FuncSignature *Signature = I.second;
87
if (StubsNeeded.find(Symbol) == StubsNeeded.end())
88
StubsNeeded[Symbol] = Signature;
89
}
90
MCP = MF.getConstantPool();
91
92
// In NaCl, all indirect jump targets must be aligned to bundle size.
93
if (Subtarget->isTargetNaCl())
94
NaClAlignIndirectJumpTargets(MF);
95
96
AsmPrinter::runOnMachineFunction(MF);
97
98
emitXRayTable();
99
100
return true;
101
}
102
103
bool MipsAsmPrinter::lowerOperand(const MachineOperand &MO, MCOperand &MCOp) {
104
MCOp = MCInstLowering.LowerOperand(MO);
105
return MCOp.isValid();
106
}
107
108
#include "MipsGenMCPseudoLowering.inc"
109
110
// Lower PseudoReturn/PseudoIndirectBranch/PseudoIndirectBranch64 to JR, JR_MM,
111
// JALR, or JALR64 as appropriate for the target.
112
void MipsAsmPrinter::emitPseudoIndirectBranch(MCStreamer &OutStreamer,
113
const MachineInstr *MI) {
114
bool HasLinkReg = false;
115
bool InMicroMipsMode = Subtarget->inMicroMipsMode();
116
MCInst TmpInst0;
117
118
if (Subtarget->hasMips64r6()) {
119
// MIPS64r6 should use (JALR64 ZERO_64, $rs)
120
TmpInst0.setOpcode(Mips::JALR64);
121
HasLinkReg = true;
122
} else if (Subtarget->hasMips32r6()) {
123
// MIPS32r6 should use (JALR ZERO, $rs)
124
if (InMicroMipsMode)
125
TmpInst0.setOpcode(Mips::JRC16_MMR6);
126
else {
127
TmpInst0.setOpcode(Mips::JALR);
128
HasLinkReg = true;
129
}
130
} else if (Subtarget->inMicroMipsMode())
131
// microMIPS should use (JR_MM $rs)
132
TmpInst0.setOpcode(Mips::JR_MM);
133
else {
134
// Everything else should use (JR $rs)
135
TmpInst0.setOpcode(Mips::JR);
136
}
137
138
MCOperand MCOp;
139
140
if (HasLinkReg) {
141
unsigned ZeroReg = Subtarget->isGP64bit() ? Mips::ZERO_64 : Mips::ZERO;
142
TmpInst0.addOperand(MCOperand::createReg(ZeroReg));
143
}
144
145
lowerOperand(MI->getOperand(0), MCOp);
146
TmpInst0.addOperand(MCOp);
147
148
EmitToStreamer(OutStreamer, TmpInst0);
149
}
150
151
// If there is an MO_JALR operand, insert:
152
//
153
// .reloc tmplabel, R_{MICRO}MIPS_JALR, symbol
154
// tmplabel:
155
//
156
// This is an optimization hint for the linker which may then replace
157
// an indirect call with a direct branch.
158
static void emitDirectiveRelocJalr(const MachineInstr &MI,
159
MCContext &OutContext,
160
TargetMachine &TM,
161
MCStreamer &OutStreamer,
162
const MipsSubtarget &Subtarget) {
163
for (const MachineOperand &MO :
164
llvm::drop_begin(MI.operands(), MI.getDesc().getNumOperands())) {
165
if (MO.isMCSymbol() && (MO.getTargetFlags() & MipsII::MO_JALR)) {
166
MCSymbol *Callee = MO.getMCSymbol();
167
if (Callee && !Callee->getName().empty()) {
168
MCSymbol *OffsetLabel = OutContext.createTempSymbol();
169
const MCExpr *OffsetExpr =
170
MCSymbolRefExpr::create(OffsetLabel, OutContext);
171
const MCExpr *CaleeExpr =
172
MCSymbolRefExpr::create(Callee, OutContext);
173
OutStreamer.emitRelocDirective(
174
*OffsetExpr,
175
Subtarget.inMicroMipsMode() ? "R_MICROMIPS_JALR" : "R_MIPS_JALR",
176
CaleeExpr, SMLoc(), *TM.getMCSubtargetInfo());
177
OutStreamer.emitLabel(OffsetLabel);
178
return;
179
}
180
}
181
}
182
}
183
184
void MipsAsmPrinter::emitInstruction(const MachineInstr *MI) {
185
// FIXME: Enable feature predicate checks once all the test pass.
186
// Mips_MC::verifyInstructionPredicates(MI->getOpcode(),
187
// getSubtargetInfo().getFeatureBits());
188
189
MipsTargetStreamer &TS = getTargetStreamer();
190
unsigned Opc = MI->getOpcode();
191
TS.forbidModuleDirective();
192
193
if (MI->isDebugValue()) {
194
SmallString<128> Str;
195
raw_svector_ostream OS(Str);
196
197
PrintDebugValueComment(MI, OS);
198
return;
199
}
200
if (MI->isDebugLabel())
201
return;
202
203
// If we just ended a constant pool, mark it as such.
204
if (InConstantPool && Opc != Mips::CONSTPOOL_ENTRY) {
205
OutStreamer->emitDataRegion(MCDR_DataRegionEnd);
206
InConstantPool = false;
207
}
208
if (Opc == Mips::CONSTPOOL_ENTRY) {
209
// CONSTPOOL_ENTRY - This instruction represents a floating
210
// constant pool in the function. The first operand is the ID#
211
// for this instruction, the second is the index into the
212
// MachineConstantPool that this is, the third is the size in
213
// bytes of this constant pool entry.
214
// The required alignment is specified on the basic block holding this MI.
215
//
216
unsigned LabelId = (unsigned)MI->getOperand(0).getImm();
217
unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex();
218
219
// If this is the first entry of the pool, mark it.
220
if (!InConstantPool) {
221
OutStreamer->emitDataRegion(MCDR_DataRegion);
222
InConstantPool = true;
223
}
224
225
OutStreamer->emitLabel(GetCPISymbol(LabelId));
226
227
const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx];
228
if (MCPE.isMachineConstantPoolEntry())
229
emitMachineConstantPoolValue(MCPE.Val.MachineCPVal);
230
else
231
emitGlobalConstant(MF->getDataLayout(), MCPE.Val.ConstVal);
232
return;
233
}
234
235
switch (Opc) {
236
case Mips::PATCHABLE_FUNCTION_ENTER:
237
LowerPATCHABLE_FUNCTION_ENTER(*MI);
238
return;
239
case Mips::PATCHABLE_FUNCTION_EXIT:
240
LowerPATCHABLE_FUNCTION_EXIT(*MI);
241
return;
242
case Mips::PATCHABLE_TAIL_CALL:
243
LowerPATCHABLE_TAIL_CALL(*MI);
244
return;
245
}
246
247
if (EmitJalrReloc &&
248
(MI->isReturn() || MI->isCall() || MI->isIndirectBranch())) {
249
emitDirectiveRelocJalr(*MI, OutContext, TM, *OutStreamer, *Subtarget);
250
}
251
252
MachineBasicBlock::const_instr_iterator I = MI->getIterator();
253
MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();
254
255
do {
256
// Do any auto-generated pseudo lowerings.
257
if (emitPseudoExpansionLowering(*OutStreamer, &*I))
258
continue;
259
260
// Skip the BUNDLE pseudo instruction and lower the contents
261
if (I->isBundle())
262
continue;
263
264
if (I->getOpcode() == Mips::PseudoReturn ||
265
I->getOpcode() == Mips::PseudoReturn64 ||
266
I->getOpcode() == Mips::PseudoIndirectBranch ||
267
I->getOpcode() == Mips::PseudoIndirectBranch64 ||
268
I->getOpcode() == Mips::TAILCALLREG ||
269
I->getOpcode() == Mips::TAILCALLREG64) {
270
emitPseudoIndirectBranch(*OutStreamer, &*I);
271
continue;
272
}
273
274
// The inMips16Mode() test is not permanent.
275
// Some instructions are marked as pseudo right now which
276
// would make the test fail for the wrong reason but
277
// that will be fixed soon. We need this here because we are
278
// removing another test for this situation downstream in the
279
// callchain.
280
//
281
if (I->isPseudo() && !Subtarget->inMips16Mode()
282
&& !isLongBranchPseudo(I->getOpcode()))
283
llvm_unreachable("Pseudo opcode found in emitInstruction()");
284
285
MCInst TmpInst0;
286
MCInstLowering.Lower(&*I, TmpInst0);
287
EmitToStreamer(*OutStreamer, TmpInst0);
288
} while ((++I != E) && I->isInsideBundle()); // Delay slot check
289
}
290
291
//===----------------------------------------------------------------------===//
292
//
293
// Mips Asm Directives
294
//
295
// -- Frame directive "frame Stackpointer, Stacksize, RARegister"
296
// Describe the stack frame.
297
//
298
// -- Mask directives "(f)mask bitmask, offset"
299
// Tells the assembler which registers are saved and where.
300
// bitmask - contain a little endian bitset indicating which registers are
301
// saved on function prologue (e.g. with a 0x80000000 mask, the
302
// assembler knows the register 31 (RA) is saved at prologue.
303
// offset - the position before stack pointer subtraction indicating where
304
// the first saved register on prologue is located. (e.g. with a
305
//
306
// Consider the following function prologue:
307
//
308
// .frame $fp,48,$ra
309
// .mask 0xc0000000,-8
310
// addiu $sp, $sp, -48
311
// sw $ra, 40($sp)
312
// sw $fp, 36($sp)
313
//
314
// With a 0xc0000000 mask, the assembler knows the register 31 (RA) and
315
// 30 (FP) are saved at prologue. As the save order on prologue is from
316
// left to right, RA is saved first. A -8 offset means that after the
317
// stack pointer subtration, the first register in the mask (RA) will be
318
// saved at address 48-8=40.
319
//
320
//===----------------------------------------------------------------------===//
321
322
//===----------------------------------------------------------------------===//
323
// Mask directives
324
//===----------------------------------------------------------------------===//
325
326
// Create a bitmask with all callee saved registers for CPU or Floating Point
327
// registers. For CPU registers consider RA, GP and FP for saving if necessary.
328
void MipsAsmPrinter::printSavedRegsBitmask() {
329
// CPU and FPU Saved Registers Bitmasks
330
unsigned CPUBitmask = 0, FPUBitmask = 0;
331
int CPUTopSavedRegOff, FPUTopSavedRegOff;
332
333
// Set the CPU and FPU Bitmasks
334
const MachineFrameInfo &MFI = MF->getFrameInfo();
335
const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
336
const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
337
// size of stack area to which FP callee-saved regs are saved.
338
unsigned CPURegSize = TRI->getRegSizeInBits(Mips::GPR32RegClass) / 8;
339
unsigned FGR32RegSize = TRI->getRegSizeInBits(Mips::FGR32RegClass) / 8;
340
unsigned AFGR64RegSize = TRI->getRegSizeInBits(Mips::AFGR64RegClass) / 8;
341
bool HasAFGR64Reg = false;
342
unsigned CSFPRegsSize = 0;
343
344
for (const auto &I : CSI) {
345
Register Reg = I.getReg();
346
unsigned RegNum = TRI->getEncodingValue(Reg);
347
348
// If it's a floating point register, set the FPU Bitmask.
349
// If it's a general purpose register, set the CPU Bitmask.
350
if (Mips::FGR32RegClass.contains(Reg)) {
351
FPUBitmask |= (1 << RegNum);
352
CSFPRegsSize += FGR32RegSize;
353
} else if (Mips::AFGR64RegClass.contains(Reg)) {
354
FPUBitmask |= (3 << RegNum);
355
CSFPRegsSize += AFGR64RegSize;
356
HasAFGR64Reg = true;
357
} else if (Mips::GPR32RegClass.contains(Reg))
358
CPUBitmask |= (1 << RegNum);
359
}
360
361
// FP Regs are saved right below where the virtual frame pointer points to.
362
FPUTopSavedRegOff = FPUBitmask ?
363
(HasAFGR64Reg ? -AFGR64RegSize : -FGR32RegSize) : 0;
364
365
// CPU Regs are saved below FP Regs.
366
CPUTopSavedRegOff = CPUBitmask ? -CSFPRegsSize - CPURegSize : 0;
367
368
MipsTargetStreamer &TS = getTargetStreamer();
369
// Print CPUBitmask
370
TS.emitMask(CPUBitmask, CPUTopSavedRegOff);
371
372
// Print FPUBitmask
373
TS.emitFMask(FPUBitmask, FPUTopSavedRegOff);
374
}
375
376
//===----------------------------------------------------------------------===//
377
// Frame and Set directives
378
//===----------------------------------------------------------------------===//
379
380
/// Frame Directive
381
void MipsAsmPrinter::emitFrameDirective() {
382
const TargetRegisterInfo &RI = *MF->getSubtarget().getRegisterInfo();
383
384
Register stackReg = RI.getFrameRegister(*MF);
385
unsigned returnReg = RI.getRARegister();
386
unsigned stackSize = MF->getFrameInfo().getStackSize();
387
388
getTargetStreamer().emitFrame(stackReg, stackSize, returnReg);
389
}
390
391
/// Emit Set directives.
392
const char *MipsAsmPrinter::getCurrentABIString() const {
393
switch (static_cast<MipsTargetMachine &>(TM).getABI().GetEnumValue()) {
394
case MipsABIInfo::ABI::O32: return "abi32";
395
case MipsABIInfo::ABI::N32: return "abiN32";
396
case MipsABIInfo::ABI::N64: return "abi64";
397
default: llvm_unreachable("Unknown Mips ABI");
398
}
399
}
400
401
void MipsAsmPrinter::emitFunctionEntryLabel() {
402
MipsTargetStreamer &TS = getTargetStreamer();
403
404
// NaCl sandboxing requires that indirect call instructions are masked.
405
// This means that function entry points should be bundle-aligned.
406
if (Subtarget->isTargetNaCl())
407
emitAlignment(std::max(MF->getAlignment(), MIPS_NACL_BUNDLE_ALIGN));
408
409
if (Subtarget->inMicroMipsMode()) {
410
TS.emitDirectiveSetMicroMips();
411
TS.setUsesMicroMips();
412
TS.updateABIInfo(*Subtarget);
413
} else
414
TS.emitDirectiveSetNoMicroMips();
415
416
if (Subtarget->inMips16Mode())
417
TS.emitDirectiveSetMips16();
418
else
419
TS.emitDirectiveSetNoMips16();
420
421
TS.emitDirectiveEnt(*CurrentFnSym);
422
OutStreamer->emitLabel(CurrentFnSym);
423
}
424
425
/// EmitFunctionBodyStart - Targets can override this to emit stuff before
426
/// the first basic block in the function.
427
void MipsAsmPrinter::emitFunctionBodyStart() {
428
MipsTargetStreamer &TS = getTargetStreamer();
429
430
MCInstLowering.Initialize(&MF->getContext());
431
432
bool IsNakedFunction = MF->getFunction().hasFnAttribute(Attribute::Naked);
433
if (!IsNakedFunction)
434
emitFrameDirective();
435
436
if (!IsNakedFunction)
437
printSavedRegsBitmask();
438
439
if (!Subtarget->inMips16Mode()) {
440
TS.emitDirectiveSetNoReorder();
441
TS.emitDirectiveSetNoMacro();
442
TS.emitDirectiveSetNoAt();
443
}
444
}
445
446
/// EmitFunctionBodyEnd - Targets can override this to emit stuff after
447
/// the last basic block in the function.
448
void MipsAsmPrinter::emitFunctionBodyEnd() {
449
MipsTargetStreamer &TS = getTargetStreamer();
450
451
// There are instruction for this macros, but they must
452
// always be at the function end, and we can't emit and
453
// break with BB logic.
454
if (!Subtarget->inMips16Mode()) {
455
TS.emitDirectiveSetAt();
456
TS.emitDirectiveSetMacro();
457
TS.emitDirectiveSetReorder();
458
}
459
TS.emitDirectiveEnd(CurrentFnSym->getName());
460
// Make sure to terminate any constant pools that were at the end
461
// of the function.
462
if (!InConstantPool)
463
return;
464
InConstantPool = false;
465
OutStreamer->emitDataRegion(MCDR_DataRegionEnd);
466
}
467
468
void MipsAsmPrinter::emitBasicBlockEnd(const MachineBasicBlock &MBB) {
469
AsmPrinter::emitBasicBlockEnd(MBB);
470
MipsTargetStreamer &TS = getTargetStreamer();
471
if (MBB.empty())
472
TS.emitDirectiveInsn();
473
}
474
475
// Print out an operand for an inline asm expression.
476
bool MipsAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
477
const char *ExtraCode, raw_ostream &O) {
478
// Does this asm operand have a single letter operand modifier?
479
if (ExtraCode && ExtraCode[0]) {
480
if (ExtraCode[1] != 0) return true; // Unknown modifier.
481
482
const MachineOperand &MO = MI->getOperand(OpNum);
483
switch (ExtraCode[0]) {
484
default:
485
// See if this is a generic print operand
486
return AsmPrinter::PrintAsmOperand(MI, OpNum, ExtraCode, O);
487
case 'X': // hex const int
488
if (!MO.isImm())
489
return true;
490
O << "0x" << Twine::utohexstr(MO.getImm());
491
return false;
492
case 'x': // hex const int (low 16 bits)
493
if (!MO.isImm())
494
return true;
495
O << "0x" << Twine::utohexstr(MO.getImm() & 0xffff);
496
return false;
497
case 'd': // decimal const int
498
if (!MO.isImm())
499
return true;
500
O << MO.getImm();
501
return false;
502
case 'm': // decimal const int minus 1
503
if (!MO.isImm())
504
return true;
505
O << MO.getImm() - 1;
506
return false;
507
case 'y': // exact log2
508
if (!MO.isImm())
509
return true;
510
if (!isPowerOf2_64(MO.getImm()))
511
return true;
512
O << Log2_64(MO.getImm());
513
return false;
514
case 'z':
515
// $0 if zero, regular printing otherwise
516
if (MO.isImm() && MO.getImm() == 0) {
517
O << "$0";
518
return false;
519
}
520
// If not, call printOperand as normal.
521
break;
522
case 'D': // Second part of a double word register operand
523
case 'L': // Low order register of a double word register operand
524
case 'M': // High order register of a double word register operand
525
{
526
if (OpNum == 0)
527
return true;
528
const MachineOperand &FlagsOP = MI->getOperand(OpNum - 1);
529
if (!FlagsOP.isImm())
530
return true;
531
const InlineAsm::Flag Flags(FlagsOP.getImm());
532
const unsigned NumVals = Flags.getNumOperandRegisters();
533
// Number of registers represented by this operand. We are looking
534
// for 2 for 32 bit mode and 1 for 64 bit mode.
535
if (NumVals != 2) {
536
if (Subtarget->isGP64bit() && NumVals == 1 && MO.isReg()) {
537
Register Reg = MO.getReg();
538
O << '$' << MipsInstPrinter::getRegisterName(Reg);
539
return false;
540
}
541
return true;
542
}
543
544
unsigned RegOp = OpNum;
545
if (!Subtarget->isGP64bit()){
546
// Endianness reverses which register holds the high or low value
547
// between M and L.
548
switch(ExtraCode[0]) {
549
case 'M':
550
RegOp = (Subtarget->isLittle()) ? OpNum + 1 : OpNum;
551
break;
552
case 'L':
553
RegOp = (Subtarget->isLittle()) ? OpNum : OpNum + 1;
554
break;
555
case 'D': // Always the second part
556
RegOp = OpNum + 1;
557
}
558
if (RegOp >= MI->getNumOperands())
559
return true;
560
const MachineOperand &MO = MI->getOperand(RegOp);
561
if (!MO.isReg())
562
return true;
563
Register Reg = MO.getReg();
564
O << '$' << MipsInstPrinter::getRegisterName(Reg);
565
return false;
566
}
567
break;
568
}
569
case 'w': {
570
MCRegister w = getMSARegFromFReg(MO.getReg());
571
if (w != Mips::NoRegister) {
572
O << '$' << MipsInstPrinter::getRegisterName(w);
573
return false;
574
}
575
break;
576
}
577
}
578
}
579
580
printOperand(MI, OpNum, O);
581
return false;
582
}
583
584
bool MipsAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
585
unsigned OpNum,
586
const char *ExtraCode,
587
raw_ostream &O) {
588
assert(OpNum + 1 < MI->getNumOperands() && "Insufficient operands");
589
const MachineOperand &BaseMO = MI->getOperand(OpNum);
590
const MachineOperand &OffsetMO = MI->getOperand(OpNum + 1);
591
assert(BaseMO.isReg() &&
592
"Unexpected base pointer for inline asm memory operand.");
593
assert(OffsetMO.isImm() &&
594
"Unexpected offset for inline asm memory operand.");
595
int Offset = OffsetMO.getImm();
596
597
// Currently we are expecting either no ExtraCode or 'D','M','L'.
598
if (ExtraCode) {
599
switch (ExtraCode[0]) {
600
case 'D':
601
Offset += 4;
602
break;
603
case 'M':
604
if (Subtarget->isLittle())
605
Offset += 4;
606
break;
607
case 'L':
608
if (!Subtarget->isLittle())
609
Offset += 4;
610
break;
611
default:
612
return true; // Unknown modifier.
613
}
614
}
615
616
O << Offset << "($" << MipsInstPrinter::getRegisterName(BaseMO.getReg())
617
<< ")";
618
619
return false;
620
}
621
622
void MipsAsmPrinter::printOperand(const MachineInstr *MI, int opNum,
623
raw_ostream &O) {
624
const MachineOperand &MO = MI->getOperand(opNum);
625
bool closeP = false;
626
627
if (MO.getTargetFlags())
628
closeP = true;
629
630
switch(MO.getTargetFlags()) {
631
case MipsII::MO_GPREL: O << "%gp_rel("; break;
632
case MipsII::MO_GOT_CALL: O << "%call16("; break;
633
case MipsII::MO_GOT: O << "%got("; break;
634
case MipsII::MO_ABS_HI: O << "%hi("; break;
635
case MipsII::MO_ABS_LO: O << "%lo("; break;
636
case MipsII::MO_HIGHER: O << "%higher("; break;
637
case MipsII::MO_HIGHEST: O << "%highest(("; break;
638
case MipsII::MO_TLSGD: O << "%tlsgd("; break;
639
case MipsII::MO_GOTTPREL: O << "%gottprel("; break;
640
case MipsII::MO_TPREL_HI: O << "%tprel_hi("; break;
641
case MipsII::MO_TPREL_LO: O << "%tprel_lo("; break;
642
case MipsII::MO_GPOFF_HI: O << "%hi(%neg(%gp_rel("; break;
643
case MipsII::MO_GPOFF_LO: O << "%lo(%neg(%gp_rel("; break;
644
case MipsII::MO_GOT_DISP: O << "%got_disp("; break;
645
case MipsII::MO_GOT_PAGE: O << "%got_page("; break;
646
case MipsII::MO_GOT_OFST: O << "%got_ofst("; break;
647
}
648
649
switch (MO.getType()) {
650
case MachineOperand::MO_Register:
651
O << '$'
652
<< StringRef(MipsInstPrinter::getRegisterName(MO.getReg())).lower();
653
break;
654
655
case MachineOperand::MO_Immediate:
656
O << MO.getImm();
657
break;
658
659
case MachineOperand::MO_MachineBasicBlock:
660
MO.getMBB()->getSymbol()->print(O, MAI);
661
return;
662
663
case MachineOperand::MO_GlobalAddress:
664
PrintSymbolOperand(MO, O);
665
break;
666
667
case MachineOperand::MO_BlockAddress: {
668
MCSymbol *BA = GetBlockAddressSymbol(MO.getBlockAddress());
669
O << BA->getName();
670
break;
671
}
672
673
case MachineOperand::MO_ConstantPoolIndex:
674
O << getDataLayout().getPrivateGlobalPrefix() << "CPI"
675
<< getFunctionNumber() << "_" << MO.getIndex();
676
if (MO.getOffset())
677
O << "+" << MO.getOffset();
678
break;
679
680
default:
681
llvm_unreachable("<unknown operand type>");
682
}
683
684
if (closeP) O << ")";
685
}
686
687
void MipsAsmPrinter::
688
printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O) {
689
// Load/Store memory operands -- imm($reg)
690
// If PIC target the target is loaded as the
691
// pattern lw $25,%call16($28)
692
693
// opNum can be invalid if instruction has reglist as operand.
694
// MemOperand is always last operand of instruction (base + offset).
695
switch (MI->getOpcode()) {
696
default:
697
break;
698
case Mips::SWM32_MM:
699
case Mips::LWM32_MM:
700
opNum = MI->getNumOperands() - 2;
701
break;
702
}
703
704
printOperand(MI, opNum+1, O);
705
O << "(";
706
printOperand(MI, opNum, O);
707
O << ")";
708
}
709
710
void MipsAsmPrinter::
711
printMemOperandEA(const MachineInstr *MI, int opNum, raw_ostream &O) {
712
// when using stack locations for not load/store instructions
713
// print the same way as all normal 3 operand instructions.
714
printOperand(MI, opNum, O);
715
O << ", ";
716
printOperand(MI, opNum+1, O);
717
}
718
719
void MipsAsmPrinter::
720
printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O,
721
const char *Modifier) {
722
const MachineOperand &MO = MI->getOperand(opNum);
723
O << Mips::MipsFCCToString((Mips::CondCode)MO.getImm());
724
}
725
726
void MipsAsmPrinter::
727
printRegisterList(const MachineInstr *MI, int opNum, raw_ostream &O) {
728
for (int i = opNum, e = MI->getNumOperands(); i != e; ++i) {
729
if (i != opNum) O << ", ";
730
printOperand(MI, i, O);
731
}
732
}
733
734
void MipsAsmPrinter::emitStartOfAsmFile(Module &M) {
735
MipsTargetStreamer &TS = getTargetStreamer();
736
737
// MipsTargetStreamer has an initialization order problem when emitting an
738
// object file directly (see MipsTargetELFStreamer for full details). Work
739
// around it by re-initializing the PIC state here.
740
TS.setPic(OutContext.getObjectFileInfo()->isPositionIndependent());
741
742
// Try to get target-features from the first function.
743
StringRef FS = TM.getTargetFeatureString();
744
Module::iterator F = M.begin();
745
if (FS.empty() && M.size() && F->hasFnAttribute("target-features"))
746
FS = F->getFnAttribute("target-features").getValueAsString();
747
748
// Compute MIPS architecture attributes based on the default subtarget
749
// that we'd have constructed.
750
// FIXME: For ifunc related functions we could iterate over and look
751
// for a feature string that doesn't match the default one.
752
const Triple &TT = TM.getTargetTriple();
753
StringRef CPU = MIPS_MC::selectMipsCPU(TT, TM.getTargetCPU());
754
const MipsTargetMachine &MTM = static_cast<const MipsTargetMachine &>(TM);
755
const MipsSubtarget STI(TT, CPU, FS, MTM.isLittleEndian(), MTM, std::nullopt);
756
757
bool IsABICalls = STI.isABICalls();
758
const MipsABIInfo &ABI = MTM.getABI();
759
if (IsABICalls) {
760
TS.emitDirectiveAbiCalls();
761
// FIXME: This condition should be a lot more complicated that it is here.
762
// Ideally it should test for properties of the ABI and not the ABI
763
// itself.
764
// For the moment, I'm only correcting enough to make MIPS-IV work.
765
if (!isPositionIndependent() && STI.hasSym32())
766
TS.emitDirectiveOptionPic0();
767
}
768
769
// Tell the assembler which ABI we are using
770
std::string SectionName = std::string(".mdebug.") + getCurrentABIString();
771
OutStreamer->switchSection(
772
OutContext.getELFSection(SectionName, ELF::SHT_PROGBITS, 0));
773
774
// NaN: At the moment we only support:
775
// 1. .nan legacy (default)
776
// 2. .nan 2008
777
STI.isNaN2008() ? TS.emitDirectiveNaN2008()
778
: TS.emitDirectiveNaNLegacy();
779
780
// TODO: handle O64 ABI
781
782
TS.updateABIInfo(STI);
783
784
// We should always emit a '.module fp=...' but binutils 2.24 does not accept
785
// it. We therefore emit it when it contradicts the ABI defaults (-mfpxx or
786
// -mfp64) and omit it otherwise.
787
if ((ABI.IsO32() && (STI.isABI_FPXX() || STI.isFP64bit())) ||
788
STI.useSoftFloat())
789
TS.emitDirectiveModuleFP();
790
791
// We should always emit a '.module [no]oddspreg' but binutils 2.24 does not
792
// accept it. We therefore emit it when it contradicts the default or an
793
// option has changed the default (i.e. FPXX) and omit it otherwise.
794
if (ABI.IsO32() && (!STI.useOddSPReg() || STI.isABI_FPXX()))
795
TS.emitDirectiveModuleOddSPReg();
796
797
// Switch to the .text section.
798
OutStreamer->switchSection(getObjFileLowering().getTextSection());
799
}
800
801
void MipsAsmPrinter::emitInlineAsmStart() const {
802
MipsTargetStreamer &TS = getTargetStreamer();
803
804
// GCC's choice of assembler options for inline assembly code ('at', 'macro'
805
// and 'reorder') is different from LLVM's choice for generated code ('noat',
806
// 'nomacro' and 'noreorder').
807
// In order to maintain compatibility with inline assembly code which depends
808
// on GCC's assembler options being used, we have to switch to those options
809
// for the duration of the inline assembly block and then switch back.
810
TS.emitDirectiveSetPush();
811
TS.emitDirectiveSetAt();
812
TS.emitDirectiveSetMacro();
813
TS.emitDirectiveSetReorder();
814
OutStreamer->addBlankLine();
815
}
816
817
void MipsAsmPrinter::emitInlineAsmEnd(const MCSubtargetInfo &StartInfo,
818
const MCSubtargetInfo *EndInfo) const {
819
OutStreamer->addBlankLine();
820
getTargetStreamer().emitDirectiveSetPop();
821
}
822
823
void MipsAsmPrinter::EmitJal(const MCSubtargetInfo &STI, MCSymbol *Symbol) {
824
MCInst I;
825
I.setOpcode(Mips::JAL);
826
I.addOperand(
827
MCOperand::createExpr(MCSymbolRefExpr::create(Symbol, OutContext)));
828
OutStreamer->emitInstruction(I, STI);
829
}
830
831
void MipsAsmPrinter::EmitInstrReg(const MCSubtargetInfo &STI, unsigned Opcode,
832
unsigned Reg) {
833
MCInst I;
834
I.setOpcode(Opcode);
835
I.addOperand(MCOperand::createReg(Reg));
836
OutStreamer->emitInstruction(I, STI);
837
}
838
839
void MipsAsmPrinter::EmitInstrRegReg(const MCSubtargetInfo &STI,
840
unsigned Opcode, unsigned Reg1,
841
unsigned Reg2) {
842
MCInst I;
843
//
844
// Because of the current td files for Mips32, the operands for MTC1
845
// appear backwards from their normal assembly order. It's not a trivial
846
// change to fix this in the td file so we adjust for it here.
847
//
848
if (Opcode == Mips::MTC1) {
849
unsigned Temp = Reg1;
850
Reg1 = Reg2;
851
Reg2 = Temp;
852
}
853
I.setOpcode(Opcode);
854
I.addOperand(MCOperand::createReg(Reg1));
855
I.addOperand(MCOperand::createReg(Reg2));
856
OutStreamer->emitInstruction(I, STI);
857
}
858
859
void MipsAsmPrinter::EmitInstrRegRegReg(const MCSubtargetInfo &STI,
860
unsigned Opcode, unsigned Reg1,
861
unsigned Reg2, unsigned Reg3) {
862
MCInst I;
863
I.setOpcode(Opcode);
864
I.addOperand(MCOperand::createReg(Reg1));
865
I.addOperand(MCOperand::createReg(Reg2));
866
I.addOperand(MCOperand::createReg(Reg3));
867
OutStreamer->emitInstruction(I, STI);
868
}
869
870
void MipsAsmPrinter::EmitMovFPIntPair(const MCSubtargetInfo &STI,
871
unsigned MovOpc, unsigned Reg1,
872
unsigned Reg2, unsigned FPReg1,
873
unsigned FPReg2, bool LE) {
874
if (!LE) {
875
unsigned temp = Reg1;
876
Reg1 = Reg2;
877
Reg2 = temp;
878
}
879
EmitInstrRegReg(STI, MovOpc, Reg1, FPReg1);
880
EmitInstrRegReg(STI, MovOpc, Reg2, FPReg2);
881
}
882
883
void MipsAsmPrinter::EmitSwapFPIntParams(const MCSubtargetInfo &STI,
884
Mips16HardFloatInfo::FPParamVariant PV,
885
bool LE, bool ToFP) {
886
using namespace Mips16HardFloatInfo;
887
888
unsigned MovOpc = ToFP ? Mips::MTC1 : Mips::MFC1;
889
switch (PV) {
890
case FSig:
891
EmitInstrRegReg(STI, MovOpc, Mips::A0, Mips::F12);
892
break;
893
case FFSig:
894
EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F14, LE);
895
break;
896
case FDSig:
897
EmitInstrRegReg(STI, MovOpc, Mips::A0, Mips::F12);
898
EmitMovFPIntPair(STI, MovOpc, Mips::A2, Mips::A3, Mips::F14, Mips::F15, LE);
899
break;
900
case DSig:
901
EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE);
902
break;
903
case DDSig:
904
EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE);
905
EmitMovFPIntPair(STI, MovOpc, Mips::A2, Mips::A3, Mips::F14, Mips::F15, LE);
906
break;
907
case DFSig:
908
EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE);
909
EmitInstrRegReg(STI, MovOpc, Mips::A2, Mips::F14);
910
break;
911
case NoSig:
912
return;
913
}
914
}
915
916
void MipsAsmPrinter::EmitSwapFPIntRetval(
917
const MCSubtargetInfo &STI, Mips16HardFloatInfo::FPReturnVariant RV,
918
bool LE) {
919
using namespace Mips16HardFloatInfo;
920
921
unsigned MovOpc = Mips::MFC1;
922
switch (RV) {
923
case FRet:
924
EmitInstrRegReg(STI, MovOpc, Mips::V0, Mips::F0);
925
break;
926
case DRet:
927
EmitMovFPIntPair(STI, MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE);
928
break;
929
case CFRet:
930
EmitMovFPIntPair(STI, MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE);
931
break;
932
case CDRet:
933
EmitMovFPIntPair(STI, MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE);
934
EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F2, Mips::F3, LE);
935
break;
936
case NoFPRet:
937
break;
938
}
939
}
940
941
void MipsAsmPrinter::EmitFPCallStub(
942
const char *Symbol, const Mips16HardFloatInfo::FuncSignature *Signature) {
943
using namespace Mips16HardFloatInfo;
944
945
MCSymbol *MSymbol = OutContext.getOrCreateSymbol(StringRef(Symbol));
946
bool LE = getDataLayout().isLittleEndian();
947
// Construct a local MCSubtargetInfo here.
948
// This is because the MachineFunction won't exist (but have not yet been
949
// freed) and since we're at the global level we can use the default
950
// constructed subtarget.
951
std::unique_ptr<MCSubtargetInfo> STI(TM.getTarget().createMCSubtargetInfo(
952
TM.getTargetTriple().str(), TM.getTargetCPU(),
953
TM.getTargetFeatureString()));
954
955
//
956
// .global xxxx
957
//
958
OutStreamer->emitSymbolAttribute(MSymbol, MCSA_Global);
959
const char *RetType;
960
//
961
// make the comment field identifying the return and parameter
962
// types of the floating point stub
963
// # Stub function to call rettype xxxx (params)
964
//
965
switch (Signature->RetSig) {
966
case FRet:
967
RetType = "float";
968
break;
969
case DRet:
970
RetType = "double";
971
break;
972
case CFRet:
973
RetType = "complex";
974
break;
975
case CDRet:
976
RetType = "double complex";
977
break;
978
case NoFPRet:
979
RetType = "";
980
break;
981
}
982
const char *Parms;
983
switch (Signature->ParamSig) {
984
case FSig:
985
Parms = "float";
986
break;
987
case FFSig:
988
Parms = "float, float";
989
break;
990
case FDSig:
991
Parms = "float, double";
992
break;
993
case DSig:
994
Parms = "double";
995
break;
996
case DDSig:
997
Parms = "double, double";
998
break;
999
case DFSig:
1000
Parms = "double, float";
1001
break;
1002
case NoSig:
1003
Parms = "";
1004
break;
1005
}
1006
OutStreamer->AddComment("\t# Stub function to call " + Twine(RetType) + " " +
1007
Twine(Symbol) + " (" + Twine(Parms) + ")");
1008
//
1009
// probably not necessary but we save and restore the current section state
1010
//
1011
OutStreamer->pushSection();
1012
//
1013
// .section mips16.call.fpxxxx,"ax",@progbits
1014
//
1015
MCSectionELF *M = OutContext.getELFSection(
1016
".mips16.call.fp." + std::string(Symbol), ELF::SHT_PROGBITS,
1017
ELF::SHF_ALLOC | ELF::SHF_EXECINSTR);
1018
OutStreamer->switchSection(M);
1019
//
1020
// .align 2
1021
//
1022
OutStreamer->emitValueToAlignment(Align(4));
1023
MipsTargetStreamer &TS = getTargetStreamer();
1024
//
1025
// .set nomips16
1026
// .set nomicromips
1027
//
1028
TS.emitDirectiveSetNoMips16();
1029
TS.emitDirectiveSetNoMicroMips();
1030
//
1031
// .ent __call_stub_fp_xxxx
1032
// .type __call_stub_fp_xxxx,@function
1033
// __call_stub_fp_xxxx:
1034
//
1035
std::string x = "__call_stub_fp_" + std::string(Symbol);
1036
MCSymbolELF *Stub =
1037
cast<MCSymbolELF>(OutContext.getOrCreateSymbol(StringRef(x)));
1038
TS.emitDirectiveEnt(*Stub);
1039
MCSymbol *MType =
1040
OutContext.getOrCreateSymbol("__call_stub_fp_" + Twine(Symbol));
1041
OutStreamer->emitSymbolAttribute(MType, MCSA_ELF_TypeFunction);
1042
OutStreamer->emitLabel(Stub);
1043
1044
// Only handle non-pic for now.
1045
assert(!isPositionIndependent() &&
1046
"should not be here if we are compiling pic");
1047
TS.emitDirectiveSetReorder();
1048
//
1049
// We need to add a MipsMCExpr class to MCTargetDesc to fully implement
1050
// stubs without raw text but this current patch is for compiler generated
1051
// functions and they all return some value.
1052
// The calling sequence for non pic is different in that case and we need
1053
// to implement %lo and %hi in order to handle the case of no return value
1054
// See the corresponding method in Mips16HardFloat for details.
1055
//
1056
// mov the return address to S2.
1057
// we have no stack space to store it and we are about to make another call.
1058
// We need to make sure that the enclosing function knows to save S2
1059
// This should have already been handled.
1060
//
1061
// Mov $18, $31
1062
1063
EmitInstrRegRegReg(*STI, Mips::OR, Mips::S2, Mips::RA, Mips::ZERO);
1064
1065
EmitSwapFPIntParams(*STI, Signature->ParamSig, LE, true);
1066
1067
// Jal xxxx
1068
//
1069
EmitJal(*STI, MSymbol);
1070
1071
// fix return values
1072
EmitSwapFPIntRetval(*STI, Signature->RetSig, LE);
1073
//
1074
// do the return
1075
// if (Signature->RetSig == NoFPRet)
1076
// llvm_unreachable("should not be any stubs here with no return value");
1077
// else
1078
EmitInstrReg(*STI, Mips::JR, Mips::S2);
1079
1080
MCSymbol *Tmp = OutContext.createTempSymbol();
1081
OutStreamer->emitLabel(Tmp);
1082
const MCSymbolRefExpr *E = MCSymbolRefExpr::create(Stub, OutContext);
1083
const MCSymbolRefExpr *T = MCSymbolRefExpr::create(Tmp, OutContext);
1084
const MCExpr *T_min_E = MCBinaryExpr::createSub(T, E, OutContext);
1085
OutStreamer->emitELFSize(Stub, T_min_E);
1086
TS.emitDirectiveEnd(x);
1087
OutStreamer->popSection();
1088
}
1089
1090
void MipsAsmPrinter::emitEndOfAsmFile(Module &M) {
1091
// Emit needed stubs
1092
//
1093
for (std::map<
1094
const char *,
1095
const Mips16HardFloatInfo::FuncSignature *>::const_iterator
1096
it = StubsNeeded.begin();
1097
it != StubsNeeded.end(); ++it) {
1098
const char *Symbol = it->first;
1099
const Mips16HardFloatInfo::FuncSignature *Signature = it->second;
1100
EmitFPCallStub(Symbol, Signature);
1101
}
1102
// return to the text section
1103
OutStreamer->switchSection(OutContext.getObjectFileInfo()->getTextSection());
1104
}
1105
1106
void MipsAsmPrinter::EmitSled(const MachineInstr &MI, SledKind Kind) {
1107
const uint8_t NoopsInSledCount = Subtarget->isGP64bit() ? 15 : 11;
1108
// For mips32 we want to emit the following pattern:
1109
//
1110
// .Lxray_sled_N:
1111
// ALIGN
1112
// B .tmpN
1113
// 11 NOP instructions (44 bytes)
1114
// ADDIU T9, T9, 52
1115
// .tmpN
1116
//
1117
// We need the 44 bytes (11 instructions) because at runtime, we'd
1118
// be patching over the full 48 bytes (12 instructions) with the following
1119
// pattern:
1120
//
1121
// ADDIU SP, SP, -8
1122
// NOP
1123
// SW RA, 4(SP)
1124
// SW T9, 0(SP)
1125
// LUI T9, %hi(__xray_FunctionEntry/Exit)
1126
// ORI T9, T9, %lo(__xray_FunctionEntry/Exit)
1127
// LUI T0, %hi(function_id)
1128
// JALR T9
1129
// ORI T0, T0, %lo(function_id)
1130
// LW T9, 0(SP)
1131
// LW RA, 4(SP)
1132
// ADDIU SP, SP, 8
1133
//
1134
// We add 52 bytes to t9 because we want to adjust the function pointer to
1135
// the actual start of function i.e. the address just after the noop sled.
1136
// We do this because gp displacement relocation is emitted at the start of
1137
// of the function i.e after the nop sled and to correctly calculate the
1138
// global offset table address, t9 must hold the address of the instruction
1139
// containing the gp displacement relocation.
1140
// FIXME: Is this correct for the static relocation model?
1141
//
1142
// For mips64 we want to emit the following pattern:
1143
//
1144
// .Lxray_sled_N:
1145
// ALIGN
1146
// B .tmpN
1147
// 15 NOP instructions (60 bytes)
1148
// .tmpN
1149
//
1150
// We need the 60 bytes (15 instructions) because at runtime, we'd
1151
// be patching over the full 64 bytes (16 instructions) with the following
1152
// pattern:
1153
//
1154
// DADDIU SP, SP, -16
1155
// NOP
1156
// SD RA, 8(SP)
1157
// SD T9, 0(SP)
1158
// LUI T9, %highest(__xray_FunctionEntry/Exit)
1159
// ORI T9, T9, %higher(__xray_FunctionEntry/Exit)
1160
// DSLL T9, T9, 16
1161
// ORI T9, T9, %hi(__xray_FunctionEntry/Exit)
1162
// DSLL T9, T9, 16
1163
// ORI T9, T9, %lo(__xray_FunctionEntry/Exit)
1164
// LUI T0, %hi(function_id)
1165
// JALR T9
1166
// ADDIU T0, T0, %lo(function_id)
1167
// LD T9, 0(SP)
1168
// LD RA, 8(SP)
1169
// DADDIU SP, SP, 16
1170
//
1171
OutStreamer->emitCodeAlignment(Align(4), &getSubtargetInfo());
1172
auto CurSled = OutContext.createTempSymbol("xray_sled_", true);
1173
OutStreamer->emitLabel(CurSled);
1174
auto Target = OutContext.createTempSymbol();
1175
1176
// Emit "B .tmpN" instruction, which jumps over the nop sled to the actual
1177
// start of function
1178
const MCExpr *TargetExpr = MCSymbolRefExpr::create(
1179
Target, MCSymbolRefExpr::VariantKind::VK_None, OutContext);
1180
EmitToStreamer(*OutStreamer, MCInstBuilder(Mips::BEQ)
1181
.addReg(Mips::ZERO)
1182
.addReg(Mips::ZERO)
1183
.addExpr(TargetExpr));
1184
1185
for (int8_t I = 0; I < NoopsInSledCount; I++)
1186
EmitToStreamer(*OutStreamer, MCInstBuilder(Mips::SLL)
1187
.addReg(Mips::ZERO)
1188
.addReg(Mips::ZERO)
1189
.addImm(0));
1190
1191
OutStreamer->emitLabel(Target);
1192
1193
if (!Subtarget->isGP64bit()) {
1194
EmitToStreamer(*OutStreamer,
1195
MCInstBuilder(Mips::ADDiu)
1196
.addReg(Mips::T9)
1197
.addReg(Mips::T9)
1198
.addImm(0x34));
1199
}
1200
1201
recordSled(CurSled, MI, Kind, 2);
1202
}
1203
1204
void MipsAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI) {
1205
EmitSled(MI, SledKind::FUNCTION_ENTER);
1206
}
1207
1208
void MipsAsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI) {
1209
EmitSled(MI, SledKind::FUNCTION_EXIT);
1210
}
1211
1212
void MipsAsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI) {
1213
EmitSled(MI, SledKind::TAIL_CALL);
1214
}
1215
1216
void MipsAsmPrinter::PrintDebugValueComment(const MachineInstr *MI,
1217
raw_ostream &OS) {
1218
// TODO: implement
1219
}
1220
1221
// Emit .dtprelword or .dtpreldword directive
1222
// and value for debug thread local expression.
1223
void MipsAsmPrinter::emitDebugValue(const MCExpr *Value, unsigned Size) const {
1224
if (auto *MipsExpr = dyn_cast<MipsMCExpr>(Value)) {
1225
if (MipsExpr && MipsExpr->getKind() == MipsMCExpr::MEK_DTPREL) {
1226
switch (Size) {
1227
case 4:
1228
OutStreamer->emitDTPRel32Value(MipsExpr->getSubExpr());
1229
break;
1230
case 8:
1231
OutStreamer->emitDTPRel64Value(MipsExpr->getSubExpr());
1232
break;
1233
default:
1234
llvm_unreachable("Unexpected size of expression value.");
1235
}
1236
return;
1237
}
1238
}
1239
AsmPrinter::emitDebugValue(Value, Size);
1240
}
1241
1242
// Align all targets of indirect branches on bundle size. Used only if target
1243
// is NaCl.
1244
void MipsAsmPrinter::NaClAlignIndirectJumpTargets(MachineFunction &MF) {
1245
// Align all blocks that are jumped to through jump table.
1246
if (MachineJumpTableInfo *JtInfo = MF.getJumpTableInfo()) {
1247
const std::vector<MachineJumpTableEntry> &JT = JtInfo->getJumpTables();
1248
for (const auto &I : JT) {
1249
const std::vector<MachineBasicBlock *> &MBBs = I.MBBs;
1250
1251
for (MachineBasicBlock *MBB : MBBs)
1252
MBB->setAlignment(MIPS_NACL_BUNDLE_ALIGN);
1253
}
1254
}
1255
1256
// If basic block address is taken, block can be target of indirect branch.
1257
for (auto &MBB : MF) {
1258
if (MBB.hasAddressTaken())
1259
MBB.setAlignment(MIPS_NACL_BUNDLE_ALIGN);
1260
}
1261
}
1262
1263
bool MipsAsmPrinter::isLongBranchPseudo(int Opcode) const {
1264
return (Opcode == Mips::LONG_BRANCH_LUi
1265
|| Opcode == Mips::LONG_BRANCH_LUi2Op
1266
|| Opcode == Mips::LONG_BRANCH_LUi2Op_64
1267
|| Opcode == Mips::LONG_BRANCH_ADDiu
1268
|| Opcode == Mips::LONG_BRANCH_ADDiu2Op
1269
|| Opcode == Mips::LONG_BRANCH_DADDiu
1270
|| Opcode == Mips::LONG_BRANCH_DADDiu2Op);
1271
}
1272
1273
// Force static initialization.
1274
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeMipsAsmPrinter() {
1275
RegisterAsmPrinter<MipsAsmPrinter> X(getTheMipsTarget());
1276
RegisterAsmPrinter<MipsAsmPrinter> Y(getTheMipselTarget());
1277
RegisterAsmPrinter<MipsAsmPrinter> A(getTheMips64Target());
1278
RegisterAsmPrinter<MipsAsmPrinter> B(getTheMips64elTarget());
1279
}
1280
1281