[compiler-rt] [llvm] [Hexagon] Add XRay custom and typed event support (PR #191749)

via llvm-commits llvm-commits at lists.llvm.org
Sun Apr 12 19:05:45 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-selectiondag
@llvm/pr-subscribers-xray

@llvm/pr-subscribers-backend-hexagon

Author: Brian Cain (androm3da)

<details>
<summary>Changes</summary>

Add support for XRay custom events (llvm.xray.customevent) and typed events (llvm.xray.typedevent) for Hexagon.

LLVM:
* Add Hexagon to the architecture gate in SelectionDAGBuilder for xray_customevent and xray_typedevent intrinsic lowering
* Implement EmitInstrWithCustomInserter for PATCHABLE_EVENT_CALL and PATCHABLE_TYPED_EVENT_CALL pseudo instructions
* Implement LowerPATCHABLE_EVENT_CALL in HexagonAsmPrinter that emits inline sleds with jump-over, allocframe/deallocframe for LR:FP save, argument register save/restore, and call to the event handler
* Add event pseudo dispatch in HexagonMCInstLower
* Prevent event pseudos from being packetized (solo instructions)

compiler-rt:
* Implement patchCustomEvent and patchTypedEvent in xray_hexagon.cpp to patch the sled jump to nop (enable) or back (disable)
* Add __xray_CustomEvent and __xray_TypedEvent trampolines in the Hexagon XRay trampoline assembly

---

Patch is 20.31 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/191749.diff


10 Files Affected:

- (modified) compiler-rt/lib/xray/xray_hexagon.cpp (+32-3) 
- (modified) compiler-rt/lib/xray/xray_trampoline_hexagon.S (+50-12) 
- (modified) llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp (+4-2) 
- (modified) llvm/lib/Target/Hexagon/HexagonAsmPrinter.cpp (+175) 
- (modified) llvm/lib/Target/Hexagon/HexagonAsmPrinter.h (+1) 
- (modified) llvm/lib/Target/Hexagon/HexagonISelLowering.cpp (+12) 
- (modified) llvm/lib/Target/Hexagon/HexagonISelLowering.h (+4) 
- (modified) llvm/lib/Target/Hexagon/HexagonMCInstLower.cpp (+8) 
- (modified) llvm/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp (+3-1) 
- (added) llvm/test/CodeGen/Hexagon/xray-custom-event.ll (+83) 


``````````diff
diff --git a/compiler-rt/lib/xray/xray_hexagon.cpp b/compiler-rt/lib/xray/xray_hexagon.cpp
index b299f03d6daad..3e56a4d5ce7b9 100644
--- a/compiler-rt/lib/xray/xray_hexagon.cpp
+++ b/compiler-rt/lib/xray/xray_hexagon.cpp
@@ -20,8 +20,15 @@
 namespace __xray {
 
 // The machine codes for some instructions used in runtime patching.
+//
+// J2_jump encoding: bits [27:16] and [13:1] hold the PC-relative byte offset
+// divided by 4, with bits [15:14] = 0b11 for packet-end parse bits.
+// Formula: 0x5800c000 | ((ByteOffset >> 2) << 1)
 enum PatchOpcodes : uint32_t {
-  PO_JUMPI_1C = 0x5800c00e,     // jump #0x01c (PC + 0x01c)
+  PO_JUMPI_1C = 0x5800c00e,     // jump #0x01c (entry/exit sled, 28 bytes)
+  PO_JUMPI_30 = 0x5800c018,     // jump #0x030 (custom event sled, 48 bytes)
+  PO_JUMPI_3C = 0x5800c01e,     // jump #0x03c (typed event sled, 60 bytes)
+  PO_NOP = 0x7f00c000,          // { nop } with packet-end parse bits
   PO_CALLR_R6 = 0x50a6c000,     // indirect call: callr r6
   PO_TFR_IMM = 0x78000000,      // transfer immed
                                 // ICLASS 0x7 - S2-type A-type
@@ -176,13 +183,35 @@ bool patchFunctionTailExit(
 
 bool patchCustomEvent(const bool Enable, const uint32_t FuncId,
                       const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
-  // FIXME: Implement in hexagon?
+  // The custom event sled (2 args) is 12 words = 48 bytes:
+  //   .Lxray_sled_N:
+  //     { jump .Lend }     <-- first word: jump over (disabled) / nop (enabled)
+  //     allocframe, sp adjust, 2 saves, 2 moves, call, 2 restores,
+  //     sp adjust, deallocframe
+  //   .Lend:
+  uint32_t *FirstAddress = reinterpret_cast<uint32_t *>(Sled.address());
+  if (Enable) {
+    WriteInstFlushCache(FirstAddress, uint32_t(PO_NOP));
+  } else {
+    WriteInstFlushCache(FirstAddress, uint32_t(PO_JUMPI_30));
+  }
   return false;
 }
 
 bool patchTypedEvent(const bool Enable, const uint32_t FuncId,
                      const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
-  // FIXME: Implement in hexagon?
+  // The typed event sled (3 args) is 15 words = 60 bytes:
+  //   .Lxray_sled_N:
+  //     { jump .Lend }     <-- first word: jump over (disabled) / nop (enabled)
+  //     allocframe, sp adjust, 3 saves, 3 moves, call, 3 restores,
+  //     sp adjust, deallocframe
+  //   .Lend:
+  uint32_t *FirstAddress = reinterpret_cast<uint32_t *>(Sled.address());
+  if (Enable) {
+    WriteInstFlushCache(FirstAddress, uint32_t(PO_NOP));
+  } else {
+    WriteInstFlushCache(FirstAddress, uint32_t(PO_JUMPI_3C));
+  }
   return false;
 }
 
diff --git a/compiler-rt/lib/xray/xray_trampoline_hexagon.S b/compiler-rt/lib/xray/xray_trampoline_hexagon.S
index a7ba7c6b889a9..b9d2f1f2293e4 100644
--- a/compiler-rt/lib/xray/xray_trampoline_hexagon.S
+++ b/compiler-rt/lib/xray/xray_trampoline_hexagon.S
@@ -33,9 +33,7 @@
 	//   sp+#20: r5     (parameter)
 	//   sp+#24: r31    (return address back to sled's deallocframe)
 	//   sp+#28: (padding for 8-byte alignment)
-	{
-		sp = add(sp, #-32)
-	}
+	sp = add(sp, #-32)
 	memw(sp+#0) = r0
 	memw(sp+#4) = r1
 	memw(sp+#8) = r2
@@ -53,18 +51,14 @@
 	r4 = memw(sp+#16)
 	r5 = memw(sp+#20)
 	r31 = memw(sp+#24)
-	{
-		sp = add(sp, #32)
-	}
+	sp = add(sp, #32)
 .endm
 
 .macro CALL_PATCHED_FUNC entry_type
 	// Load the address of the global handler function pointer,
 	// then dereference it to get the actual handler.
 	r8 = ##ASM_SYMBOL(_ZN6__xray19XRayPatchedFunctionE)
-	{
-		r8 = memw(r8+#0)
-	}
+	r8 = memw(r8+#0)
 	// Skip if handler is not registered (null).
 	{
 		p0 = cmp.eq(r8, #0)
@@ -77,9 +71,7 @@
 		r0 = r7
 		r1 = \entry_type
 	}
-	{
-		callr r8
-	}
+	callr r8
 0:
 .endm
 
@@ -128,4 +120,50 @@ ASM_SYMBOL(__xray_FunctionTailExit):
 	ASM_SIZE(__xray_FunctionTailExit)
 	CFI_ENDPROC
 
+// __xray_*Event have default visibility so that they can be referenced by user
+// DSOs that do not link against the runtime.
+
+	.globl ASM_SYMBOL(__xray_CustomEvent)
+	ASM_TYPE_FUNCTION(__xray_CustomEvent)
+ASM_SYMBOL(__xray_CustomEvent):
+	CFI_STARTPROC
+	SAVE_REGISTERS
+
+	// Arguments (r0=ptr, r1=size) are already set by the inline sled.
+	// Load the handler address.
+	r8 = ##ASM_SYMBOL(_ZN6__xray22XRayPatchedCustomEventE)
+	r8 = memw(r8+#0)
+	{
+		p0 = cmp.eq(r8, #0)
+		if (p0.new) jump:nt 0f
+	}
+	callr r8
+0:
+	RESTORE_REGISTERS
+	jumpr r31
+	ASM_SIZE(__xray_CustomEvent)
+	CFI_ENDPROC
+
+
+	.globl ASM_SYMBOL(__xray_TypedEvent)
+	ASM_TYPE_FUNCTION(__xray_TypedEvent)
+ASM_SYMBOL(__xray_TypedEvent):
+	CFI_STARTPROC
+	SAVE_REGISTERS
+
+	// Arguments (r0=type, r1=ptr, r2=size) are already set by the inline sled.
+	// Load the handler address.
+	r8 = ##ASM_SYMBOL(_ZN6__xray21XRayPatchedTypedEventE)
+	r8 = memw(r8+#0)
+	{
+		p0 = cmp.eq(r8, #0)
+		if (p0.new) jump:nt 0f
+	}
+	callr r8
+0:
+	RESTORE_REGISTERS
+	jumpr r31
+	ASM_SIZE(__xray_TypedEvent)
+	CFI_ENDPROC
+
 NO_EXEC_STACK_DIRECTIVE
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 1f3b099c9c577..6ae97acb7f21c 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -7966,7 +7966,8 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
     // Here we want to make sure that the intrinsic behaves as if it has a
     // specific calling convention.
     const auto &Triple = DAG.getTarget().getTargetTriple();
-    if (!Triple.isAArch64(64) && Triple.getArch() != Triple::x86_64)
+    if (!Triple.isAArch64(64) && Triple.getArch() != Triple::x86_64 &&
+        Triple.getArch() != Triple::hexagon)
       return;
 
     SmallVector<SDValue, 8> Ops;
@@ -7995,7 +7996,8 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
     // Here we want to make sure that the intrinsic behaves as if it has a
     // specific calling convention.
     const auto &Triple = DAG.getTarget().getTargetTriple();
-    if (!Triple.isAArch64(64) && Triple.getArch() != Triple::x86_64)
+    if (!Triple.isAArch64(64) && Triple.getArch() != Triple::x86_64 &&
+        Triple.getArch() != Triple::hexagon)
       return;
 
     SmallVector<SDValue, 8> Ops;
diff --git a/llvm/lib/Target/Hexagon/HexagonAsmPrinter.cpp b/llvm/lib/Target/Hexagon/HexagonAsmPrinter.cpp
index a83a221b1a9b1..2ed5f9b774f83 100644
--- a/llvm/lib/Target/Hexagon/HexagonAsmPrinter.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonAsmPrinter.cpp
@@ -801,6 +801,181 @@ void HexagonAsmPrinter::emitAttributes() {
   HTS.emitTargetAttributes(*TM.getMCSubtargetInfo());
 }
 
+void HexagonAsmPrinter::LowerPATCHABLE_EVENT_CALL(const MachineInstr &MI,
+                                                  bool Typed) {
+  auto &O = *OutStreamer;
+  MCSymbol *CurSled = OutContext.createTempSymbol("xray_sled_", true);
+  O.emitLabel(CurSled);
+
+  auto *Sym = MCSymbolRefExpr::create(
+      OutContext.getOrCreateSymbol(Typed ? "__xray_TypedEvent"
+                                         : "__xray_CustomEvent"),
+      OutContext);
+
+  // The sled structure:
+  //   .Lxray_sled_N:
+  //     { jump .Lend }            -- disabled (patched to nop when enabled)
+  //     <save args, move operands, call handler, restore args>
+  //   .Lend:
+
+  MCSymbol *EndSled = OutContext.createTempSymbol();
+
+  // Packet 1: jump over the sled (disabled state).
+  MCInst *JumpInst = OutContext.createMCInst();
+  JumpInst->setOpcode(Hexagon::J2_jump);
+  JumpInst->addOperand(MCOperand::createExpr(HexagonMCExpr::create(
+      MCSymbolRefExpr::create(EndSled, OutContext), OutContext)));
+
+  MCInst JumpPacket;
+  JumpPacket.setOpcode(Hexagon::BUNDLE);
+  JumpPacket.addOperand(MCOperand::createImm(0));
+  JumpPacket.addOperand(MCOperand::createInst(JumpInst));
+  EmitToStreamer(O, JumpPacket);
+
+  // Packet 2: allocframe to save LR:FP.
+  MCInst *AllocInst = OutContext.createMCInst();
+  AllocInst->setOpcode(Hexagon::S2_allocframe);
+  AllocInst->addOperand(MCOperand::createReg(Hexagon::R29));
+  AllocInst->addOperand(MCOperand::createReg(Hexagon::R30));
+  AllocInst->addOperand(MCOperand::createExpr(HexagonMCExpr::create(
+      MCConstantExpr::create(0, OutContext), OutContext)));
+
+  MCInst AllocPacket;
+  AllocPacket.setOpcode(Hexagon::BUNDLE);
+  AllocPacket.addOperand(MCOperand::createImm(0));
+  AllocPacket.addOperand(MCOperand::createInst(AllocInst));
+  EmitToStreamer(O, AllocPacket);
+
+  // Save argument registers and set up call arguments.
+  // Custom event:  2 operands (ptr, size) in MI operands 0,1 -> r0, r1
+  // Typed event:   3 operands (type, ptr, size) in MI operands 0,1,2 ->
+  // r0,r1,r2
+  unsigned NumArgs = Typed ? 3 : 2;
+
+  // Save the original argument registers onto the stack.
+  // Packet 3: Allocate space and save r0.
+  MCInst *SubSpInst = OutContext.createMCInst();
+  SubSpInst->setOpcode(Hexagon::A2_addi);
+  SubSpInst->addOperand(MCOperand::createReg(Hexagon::R29));
+  SubSpInst->addOperand(MCOperand::createReg(Hexagon::R29));
+  SubSpInst->addOperand(MCOperand::createExpr(HexagonMCExpr::create(
+      MCConstantExpr::create(-(int64_t)(NumArgs * 4), OutContext),
+      OutContext)));
+
+  MCInst SubSpPacket;
+  SubSpPacket.setOpcode(Hexagon::BUNDLE);
+  SubSpPacket.addOperand(MCOperand::createImm(0));
+  SubSpPacket.addOperand(MCOperand::createInst(SubSpInst));
+  EmitToStreamer(O, SubSpPacket);
+
+  // Save each argument register.
+  for (unsigned I = 0; I < NumArgs; ++I) {
+    MCInst *StoreInst = OutContext.createMCInst();
+    StoreInst->setOpcode(Hexagon::S2_storeri_io);
+    StoreInst->addOperand(MCOperand::createReg(Hexagon::R29));
+    StoreInst->addOperand(MCOperand::createExpr(HexagonMCExpr::create(
+        MCConstantExpr::create(I * 4, OutContext), OutContext)));
+    StoreInst->addOperand(MCOperand::createReg(Hexagon::R0 + I));
+
+    MCInst StorePacket;
+    StorePacket.setOpcode(Hexagon::BUNDLE);
+    StorePacket.addOperand(MCOperand::createImm(0));
+    StorePacket.addOperand(MCOperand::createInst(StoreInst));
+    EmitToStreamer(O, StorePacket);
+  }
+
+  // Move operands into argument registers (r0, r1, [r2]).
+  // The XRay intrinsic uses i64 for size (and type) parameters. On 32-bit
+  // Hexagon these are in DoubleRegs (register pairs). The runtime handler
+  // expects 32-bit arguments, so extract the low sub-register.
+  //
+  // NOTE: Moves are always emitted (even identity moves like r0 = r0) so that
+  // the sled has a fixed size. The runtime patching code relies on the sled
+  // being a known number of words to encode the correct jump offset for the
+  // disabled state.
+  //
+  // NOTE: When source registers alias destination registers in a conflicting
+  // order (e.g., src0 in r1 and src1 in r0), the sequential moves can produce
+  // incorrect results. This is the same limitation as AArch64's implementation
+  // and is unlikely in practice since the register allocator rarely produces
+  // such assignments for XRay event intrinsics.
+  const auto &HRI = *MF->getSubtarget<HexagonSubtarget>().getRegisterInfo();
+  for (unsigned I = 0; I < NumArgs; ++I) {
+    Register SrcReg = MI.getOperand(I).getReg();
+    if (Hexagon::DoubleRegsRegClass.contains(SrcReg))
+      SrcReg = HRI.getSubReg(SrcReg, Hexagon::isub_lo);
+
+    MCInst *MovInst = OutContext.createMCInst();
+    MovInst->setOpcode(Hexagon::A2_tfr);
+    MovInst->addOperand(MCOperand::createReg(Hexagon::R0 + I));
+    MovInst->addOperand(MCOperand::createReg(SrcReg));
+
+    MCInst MovPacket;
+    MovPacket.setOpcode(Hexagon::BUNDLE);
+    MovPacket.addOperand(MCOperand::createImm(0));
+    MovPacket.addOperand(MCOperand::createInst(MovInst));
+    EmitToStreamer(O, MovPacket);
+  }
+
+  // Call the handler.
+  MCInst *CallInst = OutContext.createMCInst();
+  CallInst->setOpcode(Hexagon::J2_call);
+  CallInst->addOperand(
+      MCOperand::createExpr(HexagonMCExpr::create(Sym, OutContext)));
+
+  MCInst CallPacket;
+  CallPacket.setOpcode(Hexagon::BUNDLE);
+  CallPacket.addOperand(MCOperand::createImm(0));
+  CallPacket.addOperand(MCOperand::createInst(CallInst));
+  EmitToStreamer(O, CallPacket);
+
+  // Restore argument registers.
+  for (unsigned I = 0; I < NumArgs; ++I) {
+    MCInst *LoadInst = OutContext.createMCInst();
+    LoadInst->setOpcode(Hexagon::L2_loadri_io);
+    LoadInst->addOperand(MCOperand::createReg(Hexagon::R0 + I));
+    LoadInst->addOperand(MCOperand::createReg(Hexagon::R29));
+    LoadInst->addOperand(MCOperand::createExpr(HexagonMCExpr::create(
+        MCConstantExpr::create(I * 4, OutContext), OutContext)));
+
+    MCInst LoadPacket;
+    LoadPacket.setOpcode(Hexagon::BUNDLE);
+    LoadPacket.addOperand(MCOperand::createImm(0));
+    LoadPacket.addOperand(MCOperand::createInst(LoadInst));
+    EmitToStreamer(O, LoadPacket);
+  }
+
+  // Deallocate saved argument space.
+  MCInst *AddSpInst = OutContext.createMCInst();
+  AddSpInst->setOpcode(Hexagon::A2_addi);
+  AddSpInst->addOperand(MCOperand::createReg(Hexagon::R29));
+  AddSpInst->addOperand(MCOperand::createReg(Hexagon::R29));
+  AddSpInst->addOperand(MCOperand::createExpr(HexagonMCExpr::create(
+      MCConstantExpr::create(NumArgs * 4, OutContext), OutContext)));
+
+  MCInst AddSpPacket;
+  AddSpPacket.setOpcode(Hexagon::BUNDLE);
+  AddSpPacket.addOperand(MCOperand::createImm(0));
+  AddSpPacket.addOperand(MCOperand::createInst(AddSpInst));
+  EmitToStreamer(O, AddSpPacket);
+
+  // Deallocframe to restore LR:FP.
+  MCInst *DeallocInst = OutContext.createMCInst();
+  DeallocInst->setOpcode(Hexagon::L2_deallocframe);
+  DeallocInst->addOperand(MCOperand::createReg(Hexagon::D15));
+  DeallocInst->addOperand(MCOperand::createReg(Hexagon::R30));
+
+  MCInst DeallocPacket;
+  DeallocPacket.setOpcode(Hexagon::BUNDLE);
+  DeallocPacket.addOperand(MCOperand::createImm(0));
+  DeallocPacket.addOperand(MCOperand::createInst(DeallocInst));
+  EmitToStreamer(O, DeallocPacket);
+
+  OutStreamer->emitLabel(EndSled);
+  recordSled(CurSled, MI,
+             Typed ? SledKind::TYPED_EVENT : SledKind::CUSTOM_EVENT, 2);
+}
+
 void HexagonAsmPrinter::EmitSled(const MachineInstr &MI, SledKind Kind) {
   static const int8_t NoopsInSledCount = 6;
   // We want to emit the following pattern:
diff --git a/llvm/lib/Target/Hexagon/HexagonAsmPrinter.h b/llvm/lib/Target/Hexagon/HexagonAsmPrinter.h
index 8e34d2bf9209b..83621142ca5b5 100644
--- a/llvm/lib/Target/Hexagon/HexagonAsmPrinter.h
+++ b/llvm/lib/Target/Hexagon/HexagonAsmPrinter.h
@@ -65,6 +65,7 @@ class TargetMachine;
     void LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI);
     void LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI);
     void LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI);
+    void LowerPATCHABLE_EVENT_CALL(const MachineInstr &MI, bool Typed);
     void EmitSled(const MachineInstr &MI, SledKind Kind);
 
     void HexagonProcessInstruction(MCInst &Inst, const MachineInstr &MBB);
diff --git a/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp b/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp
index 6b2a963e2e777..1945216b13b17 100644
--- a/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp
@@ -3957,6 +3957,18 @@ HexagonTargetLowering::shouldExpandAtomicCmpXchgInIR(
   return AtomicExpansionKind::LLSC;
 }
 
+MachineBasicBlock *HexagonTargetLowering::EmitInstrWithCustomInserter(
+    MachineInstr &MI, MachineBasicBlock *BB) const {
+  switch (MI.getOpcode()) {
+  case TargetOpcode::PATCHABLE_EVENT_CALL:
+  case TargetOpcode::PATCHABLE_TYPED_EVENT_CALL:
+    // These are lowered in the AsmPrinter.
+    return BB;
+  default:
+    llvm_unreachable("Unexpected instruction with custom inserter");
+  }
+}
+
 bool HexagonTargetLowering::isMaskAndCmp0FoldingBeneficial(
     const Instruction &AndI) const {
   // Only sink 'and' mask to cmp use block if it is masking a single bit since
diff --git a/llvm/lib/Target/Hexagon/HexagonISelLowering.h b/llvm/lib/Target/Hexagon/HexagonISelLowering.h
index 55be8fd043ad5..38f613f92aa87 100644
--- a/llvm/lib/Target/Hexagon/HexagonISelLowering.h
+++ b/llvm/lib/Target/Hexagon/HexagonISelLowering.h
@@ -287,6 +287,10 @@ class HexagonTargetLowering : public TargetLowering {
     return AtomicExpansionKind::LLSC;
   }
 
+  MachineBasicBlock *
+  EmitInstrWithCustomInserter(MachineInstr &MI,
+                              MachineBasicBlock *BB) const override;
+
 private:
   void initializeHVXLowering();
   unsigned getPreferredHvxVectorAction(MVT VecTy) const;
diff --git a/llvm/lib/Target/Hexagon/HexagonMCInstLower.cpp b/llvm/lib/Target/Hexagon/HexagonMCInstLower.cpp
index 845e60bf1a2a1..c592a55615859 100644
--- a/llvm/lib/Target/Hexagon/HexagonMCInstLower.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonMCInstLower.cpp
@@ -115,6 +115,14 @@ void llvm::HexagonLowerToMC(const MCInstrInfo &MCII, const MachineInstr *MI,
     AP.EmitSled(*MI, HexagonAsmPrinter::SledKind::TAIL_CALL);
     return;
   }
+  if (MI->getOpcode() == Hexagon::PATCHABLE_EVENT_CALL) {
+    AP.LowerPATCHABLE_EVENT_CALL(*MI, false);
+    return;
+  }
+  if (MI->getOpcode() == Hexagon::PATCHABLE_TYPED_EVENT_CALL) {
+    AP.LowerPATCHABLE_EVENT_CALL(*MI, true);
+    return;
+  }
 
   MCInst *MCI = AP.OutContext.createMCInst();
   MCI->setOpcode(MI->getOpcode());
diff --git a/llvm/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp b/llvm/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp
index 8d1c17ca97421..fbf196a7a23e5 100644
--- a/llvm/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp
@@ -1077,7 +1077,9 @@ bool HexagonPacketizerList::isSoloInstruction(const MachineInstr &MI) {
 
   if (MI.getOpcode() == Hexagon::PATCHABLE_FUNCTION_ENTER ||
       MI.getOpcode() == Hexagon::PATCHABLE_FUNCTION_EXIT ||
-      MI.getOpcode() == Hexagon::PATCHABLE_TAIL_CALL)
+      MI.getOpcode() == Hexagon::PATCHABLE_TAIL_CALL ||
+      MI.getOpcode() == Hexagon::PATCHABLE_EVENT_CALL ||
+      MI.getOpcode() == Hexagon::PATCHABLE_TYPED_EVENT_CALL)
     return true;
 
   if (MI.getOpcode() == Hexagon::A2_nop)
diff --git a/llvm/test/CodeGen/Hexagon/xray-custom-event.ll b/llvm/test/CodeGen/Hexagon/xray-custom-event.ll
new file mode 100644
index 0000000000000..951ecace4ee38
--- /dev/null
+++ b/llvm/test/CodeGen/Hexagon/xray-custom-event.ll
@@ -0,0 +1,83 @@
+; RUN: llc -mtriple=hexagon-unknown-elf < %s | FileCheck %s
+; RUN: llc -mtriple=hexagon-unknown-linux-musl < %s | FileCheck %s
+
+define i32 @customevent(ptr %p, i32 %sz) nounwind noinline uwtable "function-instrument"="xray-always" {
+entry:
+;; Function entry sled.
+; CHECK-LABEL: .Lxray_sled_0:
+; CHECK:       jump
+
+;; Custom event sled (12 words = 48 bytes):
+;; jump-over, allocframe, sp adjust, 2 saves, 2 moves, call,
+;; 2 restores, sp adjust, deallocframe.
+; CHECK-LABEL: .Lxray_sled_1:
+; CHECK:       jump .Ltmp
+; CHECK:       allocframe(r29,#0):raw
+; CHECK:       r29 = add(r29,#-8)
+; CHECK:       memw(r29+#0) = r0
+; CHECK:       memw(r29+#4) = r1
+; CHECK:       r0 = r{{[0-9]+}}
+; CHECK:       r1 = r{{[0-9]+}}
+; CHECK:       call __xray_CustomEvent
+; CHECK:       r0 = memw(r29+#0)
+; CHECK:       r1 = memw(r29+#4)
+; CHECK:       r29 = add(r29,#8)
+; CHECK:       deallocframe
+; CHECK:       .Ltmp
+
+  call void @llvm.xray.customevent(ptr %p, i64 4)
+
+;; Function exit sled.
+; CHECK-LABEL: .Lxray_sled_2:
+; CHECK:       jump
+
+  ret i32 0
+}
+
+;; Verify the xray_instr_map entry records CUSTOM_EVENT kind (0x04).
+; CHECK:       .section xray_instr_map
+; CHECK:       .byte 0x04
+;; 0x04 = SledKind::CUSTOM_EVENT
+
+define i32 @typedevent(i64 %type, ptr %p, i32 %sz) nounwind noinline uwtable "function-instrument"="xray-always" {
+entry:
+;; Function entry sled.
+; CHECK-LABEL: .Lxray_sled_3:
+; CHECK:       jump
+
+;; Typed event sled (15 words = 60 bytes):
+;; jump-over, allocframe, sp adjust, 3 saves, 3 moves, call,
+;; 3 restores, sp adjust, deallocframe.
+; CHECK-LABEL: .Lxray_sled_4:
+; CHECK:       jump .Ltmp
+; CHECK:       allocframe(r29,#0):raw
+; CHECK:       r29 = add(r29,#-12)
+; CHECK:       memw(r29+#0) = r0
+; CHECK:       memw(r29+#4) = r1
+; CHECK:       memw(r29+#8) = r2
+; CHECK:       r0 = r{{[0-9]+}}
+; CHECK:       r1 = r{{[0-9]+}}
+; CHECK:       r2 = r{{[0-9]+}}
+; CHECK:       call __xray_TypedEvent
+; CHECK:       r0 = memw(r29+#0)
+; CHECK:       r1 = memw(r29+#4)
+; CHECK:       r2 = memw(r29+#8)
+; CHECK:       r29 = add(r29,#12)
+; CHECK:       deallocframe
+; CHECK:       .Ltmp
+
+  call void @llvm.xray.typedevent(i64 %type, ptr %p, i64 4)
+
+;; Funct...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/191749


More information about the llvm-commits mailing list