mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 03:02:36 +01:00
[LLVM][XRAY][MIPS] Support xray on mips/mipsel/mips64/mips64el
Summary: Adds support for xray instrumentation on mips for both 32-bit and 64-bit. Reviewed by sdardis, dberris Differential: D27697 llvm-svn: 295164
This commit is contained in:
parent
e27f967c5e
commit
5602c70c9c
@ -158,6 +158,10 @@ bool XRayInstrumentation::runOnMachineFunction(MachineFunction &MF) {
|
||||
case Triple::ArchType::thumb:
|
||||
case Triple::ArchType::aarch64:
|
||||
case Triple::ArchType::ppc64le:
|
||||
case Triple::ArchType::mips:
|
||||
case Triple::ArchType::mipsel:
|
||||
case Triple::ArchType::mips64:
|
||||
case Triple::ArchType::mips64el:
|
||||
// For the architectures which don't have a single return instruction
|
||||
prependRetWithPatchableExit(MF, TII);
|
||||
break;
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "llvm/MC/MCELFStreamer.h"
|
||||
#include "llvm/MC/MCExpr.h"
|
||||
#include "llvm/MC/MCInst.h"
|
||||
#include "llvm/MC/MCInstBuilder.h"
|
||||
#include "llvm/MC/MCSection.h"
|
||||
#include "llvm/MC/MCSectionELF.h"
|
||||
#include "llvm/MC/MCSymbolELF.h"
|
||||
@ -79,6 +80,9 @@ bool MipsAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
|
||||
NaClAlignIndirectJumpTargets(MF);
|
||||
|
||||
AsmPrinter::runOnMachineFunction(MF);
|
||||
|
||||
EmitXRayTable();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -132,6 +136,7 @@ void MipsAsmPrinter::emitPseudoIndirectBranch(MCStreamer &OutStreamer,
|
||||
|
||||
void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) {
|
||||
MipsTargetStreamer &TS = getTargetStreamer();
|
||||
unsigned Opc = MI->getOpcode();
|
||||
TS.forbidModuleDirective();
|
||||
|
||||
if (MI->isDebugValue()) {
|
||||
@ -143,20 +148,20 @@ void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) {
|
||||
}
|
||||
|
||||
// If we just ended a constant pool, mark it as such.
|
||||
if (InConstantPool && MI->getOpcode() != Mips::CONSTPOOL_ENTRY) {
|
||||
if (InConstantPool && Opc != Mips::CONSTPOOL_ENTRY) {
|
||||
OutStreamer->EmitDataRegion(MCDR_DataRegionEnd);
|
||||
InConstantPool = false;
|
||||
}
|
||||
if (MI->getOpcode() == Mips::CONSTPOOL_ENTRY) {
|
||||
if (Opc == Mips::CONSTPOOL_ENTRY) {
|
||||
// CONSTPOOL_ENTRY - This instruction represents a floating
|
||||
//constant pool in the function. The first operand is the ID#
|
||||
// constant pool in the function. The first operand is the ID#
|
||||
// for this instruction, the second is the index into the
|
||||
// MachineConstantPool that this is, the third is the size in
|
||||
// bytes of this constant pool entry.
|
||||
// The required alignment is specified on the basic block holding this MI.
|
||||
//
|
||||
unsigned LabelId = (unsigned)MI->getOperand(0).getImm();
|
||||
unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex();
|
||||
unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex();
|
||||
|
||||
// If this is the first entry of the pool, mark it.
|
||||
if (!InConstantPool) {
|
||||
@ -174,6 +179,17 @@ void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (Opc) {
|
||||
case Mips::PATCHABLE_FUNCTION_ENTER:
|
||||
LowerPATCHABLE_FUNCTION_ENTER(*MI);
|
||||
return;
|
||||
case Mips::PATCHABLE_FUNCTION_EXIT:
|
||||
LowerPATCHABLE_FUNCTION_EXIT(*MI);
|
||||
return;
|
||||
case Mips::PATCHABLE_TAIL_CALL:
|
||||
LowerPATCHABLE_TAIL_CALL(*MI);
|
||||
return;
|
||||
}
|
||||
|
||||
MachineBasicBlock::const_instr_iterator I = MI->getIterator();
|
||||
MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();
|
||||
@ -1034,6 +1050,149 @@ void MipsAsmPrinter::EmitEndOfAsmFile(Module &M) {
|
||||
OutStreamer->SwitchSection(OutContext.getObjectFileInfo()->getTextSection());
|
||||
}
|
||||
|
||||
void MipsAsmPrinter::EmitSled(const MachineInstr &MI, SledKind Kind) {
|
||||
const uint8_t NoopsInSledCount = Subtarget->isGP64bit() ? 15 : 11;
|
||||
// For mips32 we want to emit the following pattern:
|
||||
//
|
||||
// .Lxray_sled_N:
|
||||
// ALIGN
|
||||
// B .tmpN
|
||||
// 11 NOP instructions (44 bytes)
|
||||
// ADDIU T9, T9, 52
|
||||
// .tmpN
|
||||
//
|
||||
// We need the 44 bytes (11 instructions) because at runtime, we'd
|
||||
// be patching over the full 48 bytes (12 instructions) with the following
|
||||
// pattern:
|
||||
//
|
||||
// ADDIU SP, SP, -8
|
||||
// NOP
|
||||
// SW RA, 4(SP)
|
||||
// SW T9, 0(SP)
|
||||
// LUI T9, %hi(__xray_FunctionEntry/Exit)
|
||||
// ORI T9, T9, %lo(__xray_FunctionEntry/Exit)
|
||||
// LUI T0, %hi(function_id)
|
||||
// JALR T9
|
||||
// ORI T0, T0, %lo(function_id)
|
||||
// LW T9, 0(SP)
|
||||
// LW RA, 4(SP)
|
||||
// ADDIU SP, SP, 8
|
||||
//
|
||||
// We add 52 bytes to t9 because we want to adjust the function pointer to
|
||||
// the actual start of function i.e. the address just after the noop sled.
|
||||
// We do this because gp displacement relocation is emitted at the start of
|
||||
// of the function i.e after the nop sled and to correctly calculate the
|
||||
// global offset table address, t9 must hold the address of the instruction
|
||||
// containing the gp displacement relocation.
|
||||
// FIXME: Is this correct for the static relocation model?
|
||||
//
|
||||
// For mips64 we want to emit the following pattern:
|
||||
//
|
||||
// .Lxray_sled_N:
|
||||
// ALIGN
|
||||
// B .tmpN
|
||||
// 15 NOP instructions (60 bytes)
|
||||
// .tmpN
|
||||
//
|
||||
// We need the 60 bytes (15 instructions) because at runtime, we'd
|
||||
// be patching over the full 64 bytes (16 instructions) with the following
|
||||
// pattern:
|
||||
//
|
||||
// DADDIU SP, SP, -16
|
||||
// NOP
|
||||
// SD RA, 8(SP)
|
||||
// SD T9, 0(SP)
|
||||
// LUI T9, %highest(__xray_FunctionEntry/Exit)
|
||||
// ORI T9, T9, %higher(__xray_FunctionEntry/Exit)
|
||||
// DSLL T9, T9, 16
|
||||
// ORI T9, T9, %hi(__xray_FunctionEntry/Exit)
|
||||
// DSLL T9, T9, 16
|
||||
// ORI T9, T9, %lo(__xray_FunctionEntry/Exit)
|
||||
// LUI T0, %hi(function_id)
|
||||
// JALR T9
|
||||
// ADDIU T0, T0, %lo(function_id)
|
||||
// LD T9, 0(SP)
|
||||
// LD RA, 8(SP)
|
||||
// DADDIU SP, SP, 16
|
||||
//
|
||||
OutStreamer->EmitCodeAlignment(4);
|
||||
auto CurSled = OutContext.createTempSymbol("xray_sled_", true);
|
||||
OutStreamer->EmitLabel(CurSled);
|
||||
auto Target = OutContext.createTempSymbol();
|
||||
|
||||
// Emit "B .tmpN" instruction, which jumps over the nop sled to the actual
|
||||
// start of function
|
||||
const MCExpr *TargetExpr = MCSymbolRefExpr::create(
|
||||
Target, MCSymbolRefExpr::VariantKind::VK_None, OutContext);
|
||||
EmitToStreamer(*OutStreamer, MCInstBuilder(Mips::BEQ)
|
||||
.addReg(Mips::ZERO)
|
||||
.addReg(Mips::ZERO)
|
||||
.addExpr(TargetExpr));
|
||||
|
||||
for (int8_t I = 0; I < NoopsInSledCount; I++)
|
||||
EmitToStreamer(*OutStreamer, MCInstBuilder(Mips::SLL)
|
||||
.addReg(Mips::ZERO)
|
||||
.addReg(Mips::ZERO)
|
||||
.addImm(0));
|
||||
|
||||
OutStreamer->EmitLabel(Target);
|
||||
|
||||
if (!Subtarget->isGP64bit()) {
|
||||
EmitToStreamer(*OutStreamer,
|
||||
MCInstBuilder(Mips::ADDiu)
|
||||
.addReg(Mips::T9)
|
||||
.addReg(Mips::T9)
|
||||
.addImm(0x34));
|
||||
}
|
||||
|
||||
recordSled(CurSled, MI, Kind);
|
||||
}
|
||||
|
||||
void MipsAsmPrinter::EmitXRayTable() {
|
||||
if (Sleds.empty())
|
||||
return;
|
||||
if (Subtarget->isTargetELF()) {
|
||||
auto PrevSection = OutStreamer->getCurrentSectionOnly();
|
||||
auto Fn = MF->getFunction();
|
||||
MCSection *Section;
|
||||
|
||||
if (Fn->hasComdat())
|
||||
Section = OutContext.getELFSection("xray_instr_map", ELF::SHT_PROGBITS,
|
||||
ELF::SHF_ALLOC | ELF::SHF_GROUP, 0,
|
||||
Fn->getComdat()->getName());
|
||||
else
|
||||
Section =
|
||||
OutContext.getELFSection("xray_instr_map", ELF::SHT_PROGBITS,
|
||||
ELF::SHF_ALLOC, 0, CurrentFnSym->getName());
|
||||
|
||||
OutStreamer->SwitchSection(Section);
|
||||
for (const auto &Sled : Sleds) {
|
||||
OutStreamer->EmitSymbolValue(Sled.Sled, Subtarget->isGP64bit() ? 8 : 4);
|
||||
OutStreamer->EmitSymbolValue(CurrentFnSym, Subtarget->isGP64bit() ? 8 : 4);
|
||||
auto Kind = static_cast<uint8_t>(Sled.Kind);
|
||||
OutStreamer->EmitBytes(
|
||||
StringRef(reinterpret_cast<const char *>(&Kind), 1));
|
||||
OutStreamer->EmitBytes(
|
||||
StringRef(reinterpret_cast<const char *>(&Sled.AlwaysInstrument), 1));
|
||||
OutStreamer->EmitZeros(Subtarget->isGP64bit() ? 14 : 6);
|
||||
}
|
||||
OutStreamer->SwitchSection(PrevSection);
|
||||
}
|
||||
Sleds.clear();
|
||||
}
|
||||
|
||||
void MipsAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI) {
|
||||
EmitSled(MI, SledKind::FUNCTION_ENTER);
|
||||
}
|
||||
|
||||
void MipsAsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI) {
|
||||
EmitSled(MI, SledKind::FUNCTION_EXIT);
|
||||
}
|
||||
|
||||
void MipsAsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI) {
|
||||
EmitSled(MI, SledKind::TAIL_CALL);
|
||||
}
|
||||
|
||||
void MipsAsmPrinter::PrintDebugValueComment(const MachineInstr *MI,
|
||||
raw_ostream &OS) {
|
||||
// TODO: implement
|
||||
|
@ -35,7 +35,21 @@ class LLVM_LIBRARY_VISIBILITY MipsAsmPrinter : public AsmPrinter {
|
||||
|
||||
void EmitInstrWithMacroNoAT(const MachineInstr *MI);
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// XRay implementation
|
||||
//===------------------------------------------------------------------===//
|
||||
public:
|
||||
// XRay-specific lowering for Mips.
|
||||
void LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI);
|
||||
void LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI);
|
||||
void LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI);
|
||||
// Helper function that emits the XRay sleds we've collected for a particular
|
||||
// function.
|
||||
void EmitXRayTable();
|
||||
|
||||
private:
|
||||
void EmitSled(const MachineInstr &MI, SledKind Kind);
|
||||
|
||||
// tblgen'erated function.
|
||||
bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,
|
||||
const MachineInstr *MI);
|
||||
|
@ -236,6 +236,7 @@ public:
|
||||
return (HasSym32 && isABI_N64()) || isABI_N32() || isABI_O32();
|
||||
}
|
||||
bool isSingleFloat() const { return IsSingleFloat; }
|
||||
bool isTargetELF() const { return TargetTriple.isOSBinFormatELF(); }
|
||||
bool hasVFPU() const { return HasVFPU; }
|
||||
bool inMips16Mode() const { return InMips16Mode; }
|
||||
bool inMips16ModeDefault() const {
|
||||
@ -277,6 +278,8 @@ public:
|
||||
|
||||
bool isTargetNaCl() const { return TargetTriple.isOSNaCl(); }
|
||||
|
||||
bool isXRaySupported() const override { return true; }
|
||||
|
||||
// for now constant islands are on for the whole compilation unit but we only
|
||||
// really use them if in addition we are in mips16 mode
|
||||
static bool useConstantIslands();
|
||||
|
147
test/CodeGen/Mips/xray-mips-attribute-instrumentation.ll
Normal file
147
test/CodeGen/Mips/xray-mips-attribute-instrumentation.ll
Normal file
@ -0,0 +1,147 @@
|
||||
; RUN: llc -filetype=asm -o - -mtriple=mips-unknown-linux-gnu < %s | FileCheck --check-prefix=CHECK --check-prefix=CHECK-MIPS32 %s
|
||||
; RUN: llc -filetype=asm -o - -mtriple=mipsel-unknown-linux-gnu < %s | FileCheck --check-prefix=CHECK --check-prefix=CHECK-MIPS32 %s
|
||||
; RUN: llc -filetype=asm -o - -mtriple=mips64-unknown-linux-gnu < %s | FileCheck --check-prefix=CHECK --check-prefix=CHECK-MIPS64 %s
|
||||
; RUN: llc -filetype=asm -o - -mtriple=mips64el-unknown-linux-gnu < %s | FileCheck --check-prefix=CHECK --check-prefix=CHECK-MIPS64 %s
|
||||
|
||||
define i32 @foo() nounwind noinline uwtable "function-instrument"="xray-always" {
|
||||
; CHECK: .p2align 2
|
||||
; CHECK-MIPS64-LABEL: .Lxray_sled_0:
|
||||
; CHECK-MIPS32-LABEL: $xray_sled_0:
|
||||
; CHECK-MIPS64: b .Ltmp0
|
||||
; CHECK-MIPS32: b $tmp0
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-MIPS64: nop
|
||||
; CHECK-MIPS64: nop
|
||||
; CHECK-MIPS64: nop
|
||||
; CHECK-MIPS64: nop
|
||||
; CHECK-MIPS64-LABEL: .Ltmp0:
|
||||
; CHECK-MIPS32-LABEL: $tmp0:
|
||||
; CHECK-MIPS32: addiu $25, $25, 52
|
||||
ret i32 0
|
||||
; CHECK: .p2align 2
|
||||
; CHECK-MIPS64-LABEL: .Lxray_sled_1:
|
||||
; CHECK-MIPS32-LABEL: $xray_sled_1:
|
||||
; CHECK-MIPS64: b .Ltmp1
|
||||
; CHECK-MIPS32: b $tmp1
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-MIPS64: nop
|
||||
; CHECK-MIPS64: nop
|
||||
; CHECK-MIPS64: nop
|
||||
; CHECK-MIPS64: nop
|
||||
; CHECK-MIPS64-LABEL: .Ltmp1:
|
||||
; CHECK-MIPS32-LABEL: $tmp1:
|
||||
; CHECK-MIPS32: addiu $25, $25, 52
|
||||
}
|
||||
; CHECK: .section xray_instr_map,{{.*}}
|
||||
; CHECK-MIPS64: .8byte .Lxray_sled_0
|
||||
; CHECK-MIPS64: .8byte .Lxray_sled_1
|
||||
; CHECK-MIPS32: .4byte ($xray_sled_0)
|
||||
; CHECK-MIPS32: .4byte ($xray_sled_1)
|
||||
|
||||
; We test multiple returns in a single function to make sure we're getting all
|
||||
; of them with XRay instrumentation.
|
||||
define i32 @bar(i32 %i) nounwind noinline uwtable "function-instrument"="xray-always" {
|
||||
; CHECK: .p2align 2
|
||||
; CHECK-MIPS64-LABEL: .Lxray_sled_2:
|
||||
; CHECK-MIPS32-LABEL: $xray_sled_2:
|
||||
; CHECK-MIPS64: b .Ltmp2
|
||||
; CHECK-MIPS32: b $tmp2
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-MIPS64: nop
|
||||
; CHECK-MIPS64: nop
|
||||
; CHECK-MIPS64: nop
|
||||
; CHECK-MIPS64: nop
|
||||
; CHECK-MIPS64-LABEL: .Ltmp2:
|
||||
; CHECK-MIPS32-LABEL: $tmp2:
|
||||
; CHECK-MIPS32: addiu $25, $25, 52
|
||||
Test:
|
||||
%cond = icmp eq i32 %i, 0
|
||||
br i1 %cond, label %IsEqual, label %NotEqual
|
||||
IsEqual:
|
||||
ret i32 0
|
||||
; CHECK: .p2align 2
|
||||
; CHECK-MIPS64-LABEL: .Lxray_sled_3:
|
||||
; CHECK-MIPS32-LABEL: $xray_sled_3:
|
||||
; CHECK-MIPS64: b .Ltmp3
|
||||
; CHECK-MIPS32: b $tmp3
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-MIPS64: nop
|
||||
; CHECK-MIPS64: nop
|
||||
; CHECK-MIPS64: nop
|
||||
; CHECK-MIPS64: nop
|
||||
; CHECK-MIPS64-LABEL: .Ltmp3:
|
||||
; CHECK-MIPS32-LABEL: $tmp3:
|
||||
; CHECK-MIPS32: addiu $25, $25, 52
|
||||
NotEqual:
|
||||
ret i32 1
|
||||
; CHECK: .p2align 2
|
||||
; CHECK-MIPS64-LABEL: .Lxray_sled_4:
|
||||
; CHECK-MIPS32-LABEL: $xray_sled_4:
|
||||
; CHECK-MIPS64: b .Ltmp4
|
||||
; CHECK-MIPS32: b $tmp4
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-NEXT: nop
|
||||
; CHECK-MIPS64: nop
|
||||
; CHECK-MIPS64: nop
|
||||
; CHECK-MIPS64: nop
|
||||
; CHECK-MIPS64: nop
|
||||
; CHECK-MIPS64-LABEL: .Ltmp4:
|
||||
; CHECK-MIPS32-LABEL: $tmp4:
|
||||
; CHECK-MIPS32: addiu $25, $25, 52
|
||||
}
|
||||
; CHECK: .section xray_instr_map,{{.*}}
|
||||
; CHECK-MIPS64: .8byte .Lxray_sled_2
|
||||
; CHECK-MIPS64: .8byte .Lxray_sled_3
|
||||
; CHECK-MIPS64: .8byte .Lxray_sled_4
|
||||
; CHECK-MIPS32: .4byte ($xray_sled_2)
|
||||
; CHECK-MIPS32: .4byte ($xray_sled_3)
|
||||
; CHECK-MIPS32: .4byte ($xray_sled_4)
|
31
test/CodeGen/Mips/xray-section-group.ll
Normal file
31
test/CodeGen/Mips/xray-section-group.ll
Normal file
@ -0,0 +1,31 @@
|
||||
; RUN: llc -filetype=asm -o - -mtriple=mips-unknown-linux-gnu -function-sections < %s | FileCheck %s
|
||||
; RUN: llc -filetype=asm -o - -mtriple=mipsel-unknown-linux-gnu -function-sections < %s | FileCheck %s
|
||||
; RUN: llc -filetype=obj -o %t -mtriple=mips-unknown-linux-gnu -function-sections < %s
|
||||
; RUN: llvm-readobj -sections %t | FileCheck %s --check-prefix=CHECK-OBJ
|
||||
; RUN: llc -filetype=obj -o %t -mtriple=mipsel-unknown-linux-gnu -function-sections < %s
|
||||
; RUN: llvm-readobj -sections %t | FileCheck %s --check-prefix=CHECK-OBJ
|
||||
; RUN: llc -filetype=asm -o - -mtriple=mips64-unknown-linux-gnu -function-sections < %s | FileCheck %s
|
||||
; RUN: llc -filetype=asm -o - -mtriple=mips64el-unknown-linux-gnu -function-sections < %s | FileCheck %s
|
||||
; RUN: llc -filetype=obj -o %t -mtriple=mips64-unknown-linux-gnu -function-sections < %s
|
||||
; RUN: llvm-readobj -sections %t | FileCheck %s --check-prefix=CHECK-OBJ
|
||||
; RUN: llc -filetype=obj -o %t -mtriple=mips64el-unknown-linux-gnu -function-sections < %s
|
||||
; RUN: llvm-readobj -sections %t | FileCheck %s --check-prefix=CHECK-OBJ
|
||||
|
||||
define i32 @foo() nounwind noinline uwtable "function-instrument"="xray-always" {
|
||||
; CHECK: .section .text.foo,"ax",@progbits
|
||||
ret i32 0
|
||||
; CHECK: .section xray_instr_map,"a",@progbits
|
||||
}
|
||||
|
||||
; CHECK-OBJ: Section {
|
||||
; CHECK-OBJ: Name: xray_instr_map
|
||||
|
||||
$bar = comdat any
|
||||
define i32 @bar() nounwind noinline uwtable "function-instrument"="xray-always" comdat($bar) {
|
||||
; CHECK: .section .text.bar,"axG",@progbits,bar,comdat
|
||||
ret i32 1
|
||||
; CHECK: .section xray_instr_map,"aG",@progbits,bar,comdat
|
||||
}
|
||||
|
||||
; CHECK-OBJ: Section {
|
||||
; CHECK-OBJ: Name: xray_instr_map
|
Loading…
Reference in New Issue
Block a user