Index: lib/Target/AArch64/AArch64InstrInfo.h =================================================================== --- lib/Target/AArch64/AArch64InstrInfo.h +++ lib/Target/AArch64/AArch64InstrInfo.h @@ -87,6 +87,8 @@ /// Return true if this is an unscaled load/store. bool isUnscaledLdSt(MachineInstr &MI) const; + bool isTailCall(const MachineInstr &Inst) const override; + static bool isPairableLdStInst(const MachineInstr &MI) { switch (MI.getOpcode()) { default: Index: lib/Target/AArch64/AArch64InstrInfo.cpp =================================================================== --- lib/Target/AArch64/AArch64InstrInfo.cpp +++ lib/Target/AArch64/AArch64InstrInfo.cpp @@ -1627,6 +1627,17 @@ return isUnscaledLdSt(MI.getOpcode()); } +bool AArch64InstrInfo::isTailCall(const MachineInstr &Inst) const +{ + switch (Inst.getOpcode()) { + case AArch64::TCRETURNdi: + case AArch64::TCRETURNri: + return true; + default: + return false; + } +} + // Is this a candidate for ld/st merging or pairing? For example, we don't // touch volatiles or load/stores that have a hint to avoid pair formation. bool AArch64InstrInfo::isCandidateToMergeOrPair(MachineInstr &MI) const { Index: test/CodeGen/AArch64/xray-tail-call-sled.ll =================================================================== --- test/CodeGen/AArch64/xray-tail-call-sled.ll +++ test/CodeGen/AArch64/xray-tail-call-sled.ll @@ -0,0 +1,69 @@ +; RUN: llc -filetype=asm -o - -mtriple=aarch64-linux-gnu < %s | FileCheck %s + +define i32 @callee() nounwind noinline uwtable "function-instrument"="xray-always" { +; CHECK: .p2align 2 +; CHECK-LABEL: .Lxray_sled_0: +; CHECK-NEXT: b #32 +; CHECK-NEXT: nop +; CHECK-NEXT: nop +; CHECK-NEXT: nop +; CHECK-NEXT: nop +; CHECK-NEXT: nop +; CHECK-NEXT: nop +; CHECK-NEXT: nop +; CHECK-LABEL: .Ltmp0: + ret i32 0 +; CHECK-NEXT: mov w0, wzr +; CHECK-NEXT: .p2align 2 +; CHECK-LABEL: .Lxray_sled_1: +; CHECK-NEXT: b #32 +; CHECK-NEXT: nop +; CHECK-NEXT: nop +; CHECK-NEXT: nop +; CHECK-NEXT: nop +; CHECK-NEXT: nop +; CHECK-NEXT: nop +; CHECK-NEXT: nop +; CHECK-LABEL: .Ltmp1: +; CHECK-NEXT: ret +} +; CHECK: .p2align 4 +; CHECK-NEXT: .xword .Lxray_synthetic_0 +; CHECK-NEXT: .section xray_instr_map,{{.*}} +; CHECK-LABEL: Lxray_synthetic_0: +; CHECK: .xword .Lxray_sled_0 +; CHECK: .xword .Lxray_sled_1 + +define i32 @caller() nounwind noinline uwtable "function-instrument"="xray-always" { +; CHECK: .p2align 2 +; CHECK-LABEL: .Lxray_sled_2: +; CHECK-NEXT: b #32 +; CHECK-NEXT: nop +; CHECK-NEXT: nop +; CHECK-NEXT: nop +; CHECK-NEXT: nop +; CHECK-NEXT: nop +; CHECK-NEXT: nop +; CHECK-NEXT: nop +; CHECK-LABEL: .Ltmp2: +; CHECK: .p2align 2 +; CHECK-LABEL: .Lxray_sled_3: +; CHECK-NEXT: b #32 +; CHECK-NEXT: nop +; CHECK-NEXT: nop +; CHECK-NEXT: nop +; CHECK-NEXT: nop +; CHECK-NEXT: nop +; CHECK-NEXT: nop +; CHECK-NEXT: nop +; CHECK-LABEL: .Ltmp3: + %retval = tail call i32 @callee() +; CHECK: b callee + ret i32 %retval +} +; CHECK: .p2align 4 +; CHECK-NEXT: .xword .Lxray_synthetic_1 +; CHECK-NEXT: .section xray_instr_map,{{.*}} +; CHECK-LABEL: Lxray_synthetic_1: +; CHECK: .xword .Lxray_sled_2 +; CHECK: .xword .Lxray_sled_3