From ce004fb4f2e64650c37ac057dc18934b379a6016 Mon Sep 17 00:00:00 2001 From: Paul Scoropan Date: Mon, 26 Sep 2022 22:03:49 -0400 Subject: [PATCH] [PowerPC] XCOFF exception section support on the direct assembler path This feature implements support for making entries in the exception section on XCOFF on the direct assembly path using the ".except" pseudo-op. It also provides functionality to lower entries (comprised of language and reason codes) into the exception section through the use of annotation metadata attached to llvm.ppc.trap/trapd/tw/tdw intrinsics. Integrated assembler support will be provided in another review. https://reviews.llvm.org/D133030 needs to merge first for LIT tests Reviewed By: shchenz, RKSimon Differential Revision: https://reviews.llvm.org/D132146 --- llvm/include/llvm/CodeGen/TargetLowering.h | 6 +++ llvm/include/llvm/MC/MCStreamer.h | 10 +++++ llvm/include/llvm/MC/MCXCOFFStreamer.h | 3 ++ .../CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 2 + llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp | 6 +++ llvm/lib/MC/MCAsmStreamer.cpp | 15 +++++++ llvm/lib/MC/MCStreamer.cpp | 9 ++++ llvm/lib/MC/MCXCOFFStreamer.cpp | 10 +++++ llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp | 19 +++++++++ llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp | 41 +++++++++++++++--- llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 18 ++++++++ llvm/lib/Target/PowerPC/PPCISelLowering.h | 4 ++ llvm/lib/Target/PowerPC/PPCInstr64Bit.td | 3 -- llvm/lib/Target/PowerPC/PPCInstrInfo.td | 10 ++--- .../builtins-ppc-xlcompat-trap-annotations-td.ll | 46 ++++++++++++++++++++ .../builtins-ppc-xlcompat-trap-annotations-tw.ll | 49 ++++++++++++++++++++++ 16 files changed, 237 insertions(+), 14 deletions(-) create mode 100644 llvm/test/CodeGen/PowerPC/builtins-ppc-xlcompat-trap-annotations-td.ll create mode 100644 llvm/test/CodeGen/PowerPC/builtins-ppc-xlcompat-trap-annotations-tw.ll diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h index 0d6fa56..eed9c41 100644 --- a/llvm/include/llvm/CodeGen/TargetLowering.h +++ b/llvm/include/llvm/CodeGen/TargetLowering.h @@ -4623,6 +4623,12 @@ public: const AsmOperandInfo &OpInfo, SelectionDAG &DAG) const; + // Targets may override this function to collect operands from the CallInst + // and for example, lower them into the SelectionDAG operands. + virtual void CollectTargetIntrinsicOperands(const CallInst &I, + SmallVectorImpl &Ops, + SelectionDAG &DAG) const; + //===--------------------------------------------------------------------===// // Div utility functions // diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h index e71014b..ef7ab09 100644 --- a/llvm/include/llvm/MC/MCStreamer.h +++ b/llvm/include/llvm/MC/MCStreamer.h @@ -628,6 +628,16 @@ public: /// changed at the end of assembly. virtual void emitXCOFFRenameDirective(const MCSymbol *Name, StringRef Rename); + /// Emit an XCOFF .except directive which adds information about + /// a trap instruction to the object file exception section + /// + /// \param Symbol - The function containing the trap. + /// \param Lang - The language code for the exception entry. + /// \param Reason - The reason code for the exception entry. + virtual void emitXCOFFExceptDirective(const MCSymbol *Symbol, MCSymbol *Trap, + unsigned Lang, unsigned Reason, + unsigned FunctionSize, bool hasDebug); + /// Emit a XCOFF .ref directive which creates R_REF type entry in the /// relocation table for one or more symbols. /// diff --git a/llvm/include/llvm/MC/MCXCOFFStreamer.h b/llvm/include/llvm/MC/MCXCOFFStreamer.h index 3faa03f..3e82724 100644 --- a/llvm/include/llvm/MC/MCXCOFFStreamer.h +++ b/llvm/include/llvm/MC/MCXCOFFStreamer.h @@ -41,6 +41,9 @@ public: report_fatal_error("emitXCOFFRenameDirective is not implemented yet on " "object generation path"); } + void emitXCOFFExceptDirective(const MCSymbol *Symbol, MCSymbol *Trap, + unsigned Lang, unsigned Reason, + unsigned FunctionSize, bool hasDebug) override; }; } // end namespace llvm diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 660ecb5..6b85e4d 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -4865,6 +4865,8 @@ void SelectionDAGBuilder::visitTargetIntrinsic(const CallInst &I, // Create the node. SDValue Result; + // In some cases, custom collection of operands from CallInst I may be needed. + TLI.CollectTargetIntrinsicOperands(I, Ops, DAG); if (IsTgtIntrinsic) { // This is target intrinsic that touches memory Result = diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp index 74a6bab..a3070fe 100644 --- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -5256,6 +5256,12 @@ void TargetLowering::LowerAsmOperandForConstraint(SDValue Op, } } +void TargetLowering::CollectTargetIntrinsicOperands(const CallInst &I, + SmallVectorImpl &Ops, + SelectionDAG &DAG) const { + return; +} + std::pair TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *RI, StringRef Constraint, diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp index efb1a03..c1fcc81 100644 --- a/llvm/lib/MC/MCAsmStreamer.cpp +++ b/llvm/lib/MC/MCAsmStreamer.cpp @@ -197,6 +197,10 @@ public: void emitXCOFFRefDirective(StringRef Name) override; + void emitXCOFFExceptDirective(const MCSymbol *Symbol, MCSymbol *Trap, + unsigned Lang, unsigned Reason, + unsigned FunctionSize, bool hasDebug) override; + void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override; void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) override; @@ -942,6 +946,17 @@ void MCAsmStreamer::emitXCOFFRefDirective(StringRef Name) { EmitEOL(); } +void MCAsmStreamer::emitXCOFFExceptDirective(const MCSymbol *Symbol, + MCSymbol *Trap, unsigned Lang, + unsigned Reason, + unsigned FunctionSize, + bool hasDebug) { + OS << "\t.except\t"; + Symbol->print(OS, MAI); + OS << ", " << Lang << ", " << Reason; + EmitEOL(); +} + void MCAsmStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) { assert(MAI->hasDotTypeDotSizeDirective()); OS << "\t.size\t"; diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp index e93787c..de303f5 100644 --- a/llvm/lib/MC/MCStreamer.cpp +++ b/llvm/lib/MC/MCStreamer.cpp @@ -1190,6 +1190,15 @@ void MCStreamer::emitXCOFFRefDirective(StringRef Name) { llvm_unreachable("emitXCOFFRefDirective is only supported on XCOFF targets"); } +void MCStreamer::emitXCOFFExceptDirective(const MCSymbol *Symbol, + MCSymbol *Trap, unsigned Lang, + unsigned Reason, + unsigned FunctionSize, + bool hasDebug) { + report_fatal_error("emitXCOFFExceptDirective is only supported on " + "XCOFF targets"); +} + void MCStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) {} void MCStreamer::emitELFSymverDirective(const MCSymbol *OriginalSym, StringRef Name, bool KeepOriginalSym) {} diff --git a/llvm/lib/MC/MCXCOFFStreamer.cpp b/llvm/lib/MC/MCXCOFFStreamer.cpp index 7b4f649..055d244 100644 --- a/llvm/lib/MC/MCXCOFFStreamer.cpp +++ b/llvm/lib/MC/MCXCOFFStreamer.cpp @@ -81,6 +81,16 @@ void MCXCOFFStreamer::emitXCOFFSymbolLinkageWithVisibility( emitSymbolAttribute(Symbol, Visibility); } +void MCXCOFFStreamer::emitXCOFFExceptDirective(const MCSymbol *Symbol, + MCSymbol *Trap, unsigned Lang, + unsigned Reason, + unsigned FunctionSize, + bool hasDebug) { + report_fatal_error( + "emitXCOFFExceptDirective not yet supported for integrated " + "assembler path."); +} + void MCXCOFFStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) { getAssembler().registerSymbol(*Symbol); diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp index 17a829b..7a0ab70 100644 --- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -2646,6 +2646,25 @@ void PPCAIXAsmPrinter::emitInstruction(const MachineInstr *MI) { switch (MI->getOpcode()) { default: break; + case PPC::TW: + case PPC::TWI: + case PPC::TD: + case PPC::TDI: { + if (MI->getNumOperands() < 5) + break; + const MachineOperand &LangMO = MI->getOperand(3); + const MachineOperand &ReasonMO = MI->getOperand(4); + if (!LangMO.isImm() || !ReasonMO.isImm()) + break; + MCSymbol *TempSym = OutContext.createNamedTempSymbol(); + OutStreamer->emitLabel(TempSym); + OutStreamer->emitXCOFFExceptDirective(CurrentFnSym, TempSym, + LangMO.getImm(), ReasonMO.getImm(), + Subtarget->isPPC64() ? MI->getMF()->getInstructionCount() * 8 : + MI->getMF()->getInstructionCount() * 4, + MMI->hasDebugInfo()); + break; + } case PPC::GETtlsADDR64AIX: case PPC::GETtlsADDR32AIX: { // The reference to .__tls_get_addr is unknown to the assembler diff --git a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp index 54d2ce4..101e0b6 100644 --- a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp @@ -5053,8 +5053,18 @@ void PPCDAGToDAGISel::Select(SDNode *N) { case ISD::INTRINSIC_VOID: { auto IntrinsicID = N->getConstantOperandVal(1); - if (IntrinsicID == Intrinsic::ppc_tdw || IntrinsicID == Intrinsic::ppc_tw) { - unsigned Opcode = IntrinsicID == Intrinsic::ppc_tdw ? PPC::TDI : PPC::TWI; + if (IntrinsicID != Intrinsic::ppc_tdw && IntrinsicID != Intrinsic::ppc_tw && + IntrinsicID != Intrinsic::ppc_trapd && + IntrinsicID != Intrinsic::ppc_trap) + break; + unsigned Opcode = (IntrinsicID == Intrinsic::ppc_tdw || + IntrinsicID == Intrinsic::ppc_trapd) + ? PPC::TDI + : PPC::TWI; + SmallVector OpsWithMD; + unsigned MDIndex; + if (IntrinsicID == Intrinsic::ppc_tdw || + IntrinsicID == Intrinsic::ppc_tw) { SDValue Ops[] = {N->getOperand(4), N->getOperand(2), N->getOperand(3)}; int16_t SImmOperand2; int16_t SImmOperand3; @@ -5090,10 +5100,31 @@ void PPCDAGToDAGISel::Select(SDNode *N) { Ops[1] = N->getOperand(3); Ops[2] = getI32Imm(int(SImmOperand2) & 0xFFFF, dl); } - CurDAG->SelectNodeTo(N, Opcode, MVT::Other, Ops); - return; + OpsWithMD = {Ops[0], Ops[1], Ops[2]}; + MDIndex = 5; + } else { + OpsWithMD = {getI32Imm(24, dl), N->getOperand(2), getI32Imm(0, dl)}; + MDIndex = 3; + } + + if (N->getNumOperands() > MDIndex) { + SDValue MDV = N->getOperand(MDIndex); + const MDNode *MD = cast(MDV)->getMD(); + assert(MD->getNumOperands() != 0 && "Empty MDNode in operands!"); + assert((isa(MD->getOperand(0)) && cast( + MD->getOperand(0))->getString().equals("ppc-trap-reason")) + && "Unsupported annotation data type!"); + for (unsigned i = 1; i < MD->getNumOperands(); i++) { + assert(isa(MD->getOperand(i)) && + "Invalid data type for annotation ppc-trap-reason!"); + OpsWithMD.push_back( + getI32Imm(std::stoi(cast( + MD->getOperand(i))->getString().str()), dl)); + } } - break; + OpsWithMD.push_back(N->getOperand(0)); // chain + CurDAG->SelectNodeTo(N, Opcode, MVT::Other, OpsWithMD); + return; } case ISD::INTRINSIC_WO_CHAIN: { diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp index 9f2e71e..f46ba36 100644 --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -16227,6 +16227,24 @@ void PPCTargetLowering::LowerAsmOperandForConstraint(SDValue Op, TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG); } +void PPCTargetLowering::CollectTargetIntrinsicOperands(const CallInst &I, + SmallVectorImpl &Ops, + SelectionDAG &DAG) const { + if (I.getNumOperands() <= 1) + return; + if (!isa(Ops[1].getNode())) + return; + auto IntrinsicID = cast(Ops[1].getNode())->getZExtValue(); + if (IntrinsicID != Intrinsic::ppc_tdw && IntrinsicID != Intrinsic::ppc_tw && + IntrinsicID != Intrinsic::ppc_trapd && IntrinsicID != Intrinsic::ppc_trap) + return; + + if (I.hasMetadata("annotation")) { + MDNode *MDN = I.getMetadata("annotation"); + Ops.push_back(DAG.getMDNode(MDN)); + } +} + // isLegalAddressingMode - Return true if the addressing mode represented // by AM is legal for this target, for a load/store of the specified type. bool PPCTargetLowering::isLegalAddressingMode(const DataLayout &DL, diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.h b/llvm/lib/Target/PowerPC/PPCISelLowering.h index d7122b6..98d911e0d 100644 --- a/llvm/lib/Target/PowerPC/PPCISelLowering.h +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.h @@ -995,6 +995,10 @@ namespace llvm { return TargetLowering::getInlineAsmMemConstraint(ConstraintCode); } + void CollectTargetIntrinsicOperands(const CallInst &I, + SmallVectorImpl &Ops, + SelectionDAG &DAG) const override; + /// isLegalAddressingMode - Return true if the addressing mode represented /// by AM is legal for this target, for a load/store of the specified type. bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, diff --git a/llvm/lib/Target/PowerPC/PPCInstr64Bit.td b/llvm/lib/Target/PowerPC/PPCInstr64Bit.td index d8a74e7..2598934 100644 --- a/llvm/lib/Target/PowerPC/PPCInstr64Bit.td +++ b/llvm/lib/Target/PowerPC/PPCInstr64Bit.td @@ -1973,9 +1973,6 @@ def SLBSYNC : XForm_0<31, 338, (outs), (ins), "slbsync", IIC_SprSLBSYNC, []>; def : Pat<(int_ppc_stdcx ForceXForm:$dst, g8rc:$A), (STDCX g8rc:$A, ForceXForm:$dst)>; -// trapd -def : Pat<(int_ppc_trapd g8rc:$A), - (TDI 24, $A, 0)>; def : Pat<(i64 (int_ppc_mfspr timm:$SPR)), (MFSPR8 $SPR)>; def : Pat<(int_ppc_mtspr timm:$SPR, g8rc:$RT), diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.td b/llvm/lib/Target/PowerPC/PPCInstrInfo.td index 426442d..df470ae 100644 --- a/llvm/lib/Target/PowerPC/PPCInstrInfo.td +++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.td @@ -1770,13 +1770,13 @@ def STWAT : X_RD5_RS5_IM5<31, 710, (outs), (ins gprc:$rS, gprc:$rA, u5imm:$FC), let isTerminator = 1, isBarrier = 1, hasCtrlDep = 1 in def TRAP : XForm_24<31, 4, (outs), (ins), "trap", IIC_LdStLoad, [(trap)]>; -def TWI : DForm_base<3, (outs), (ins u5imm:$to, gprc:$rA, s16imm:$imm), +def TWI : DForm_base<3, (outs), (ins u5imm:$to, gprc:$rA, s16imm:$imm, variable_ops), "twi $to, $rA, $imm", IIC_IntTrapW, []>; -def TW : XForm_1<31, 4, (outs), (ins u5imm:$to, gprc:$rA, gprc:$rB), +def TW : XForm_1<31, 4, (outs), (ins u5imm:$to, gprc:$rA, gprc:$rB, variable_ops), "tw $to, $rA, $rB", IIC_IntTrapW, []>; -def TDI : DForm_base<2, (outs), (ins u5imm:$to, g8rc:$rA, s16imm:$imm), +def TDI : DForm_base<2, (outs), (ins u5imm:$to, g8rc:$rA, s16imm:$imm, variable_ops), "tdi $to, $rA, $imm", IIC_IntTrapD, []>; -def TD : XForm_1<31, 68, (outs), (ins u5imm:$to, g8rc:$rA, g8rc:$rB), +def TD : XForm_1<31, 68, (outs), (ins u5imm:$to, g8rc:$rA, g8rc:$rB, variable_ops), "td $to, $rA, $rB", IIC_IntTrapD, []>; def POPCNTB : XForm_11<31, 122, (outs gprc:$rA), (ins gprc:$rS), @@ -5085,8 +5085,6 @@ def : Pat<(int_ppc_stwcx ForceXForm:$dst, gprc:$A), (STWCX gprc:$A, ForceXForm:$dst)>; def : Pat<(int_ppc_stbcx ForceXForm:$dst, gprc:$A), (STBCX gprc:$A, ForceXForm:$dst)>; -def : Pat<(int_ppc_trap gprc:$A), - (TWI 24, $A, 0)>; def : Pat<(int_ppc_fcfid f64:$A), (XSCVSXDDP $A)>; diff --git a/llvm/test/CodeGen/PowerPC/builtins-ppc-xlcompat-trap-annotations-td.ll b/llvm/test/CodeGen/PowerPC/builtins-ppc-xlcompat-trap-annotations-td.ll new file mode 100644 index 0000000..8f6f399 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/builtins-ppc-xlcompat-trap-annotations-td.ll @@ -0,0 +1,46 @@ +; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu \ +; RUN: --ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s +; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-linux-gnu \ +; RUN: --ppc-asm-full-reg-names -mcpu=pwr7 < %s | FileCheck %s +; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-aix \ +; RUN: --ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s -check-prefix=AIX +; RUN: not --crash llc -verify-machineinstrs -mtriple=powerpc64-unknown-aix \ +; RUN: --ppc-asm-full-reg-names -mcpu=pwr8 --filetype=obj -o /dev/null %s 2>&1 | FileCheck %s -check-prefix=OBJ + +; OBJ: LLVM ERROR: emitXCOFFExceptDirective not yet supported for integrated assembler path. + +!1 = !{!"ppc-trap-reason", !"1", !"2"} +declare void @llvm.ppc.trapd(i64 %a) +declare void @llvm.ppc.tdw(i64 %a, i64 %b, i32 immarg) + +define dso_local void @test__trapd_annotation(i64 %a) { +; CHECK-LABEL: test__trapd_annotation: +; CHECK: # %bb.0: +; CHECK-NEXT: tdi 24, r3, 0 +; CHECK-NEXT: blr +; +; AIX-LABEL: test__trapd_annotation: +; AIX: # %bb.0: +; AIX-NEXT: L..tmp0: +; AIX-NEXT: .except .test__trapd_annotation, 1, 2 +; AIX-NEXT: tdi 24, r3, 0 +; AIX-NEXT: blr + call void @llvm.ppc.trapd(i64 %a), !annotation !1 + ret void +} + +define dso_local void @test__tdw_annotation(i64 %a) { +; CHECK-LABEL: test__tdw_annotation: +; CHECK: # %bb.0: +; CHECK-NEXT: tdi 0, r3, 4 +; CHECK-NEXT: blr +; +; AIX-LABEL: test__tdw_annotation: +; AIX: # %bb.0: +; AIX-NEXT: L..tmp1: +; AIX-NEXT: .except .test__tdw_annotation, 1, 2 +; AIX-NEXT: tdi 0, r3, 4 +; AIX-NEXT: blr + call void @llvm.ppc.tdw(i64 4, i64 %a, i32 0), !annotation !1 + ret void +} diff --git a/llvm/test/CodeGen/PowerPC/builtins-ppc-xlcompat-trap-annotations-tw.ll b/llvm/test/CodeGen/PowerPC/builtins-ppc-xlcompat-trap-annotations-tw.ll new file mode 100644 index 0000000..00b5755 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/builtins-ppc-xlcompat-trap-annotations-tw.ll @@ -0,0 +1,49 @@ +; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu \ +; RUN: --ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s +; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-linux-gnu \ +; RUN: --ppc-asm-full-reg-names -mcpu=pwr7 < %s | FileCheck %s +; RUN: llc -verify-machineinstrs -mtriple=powerpc-unknown-linux-gnu \ +; RUN: --ppc-asm-full-reg-names -mcpu=pwr7 < %s | FileCheck %s +; RUN: llc -verify-machineinstrs -mtriple=powerpc-unknown-aix \ +; RUN: --ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s -check-prefix=AIX +; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-aix \ +; RUN: --ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s -check-prefix=AIX +; RUN: not --crash llc -verify-machineinstrs -mtriple=powerpc64-unknown-aix \ +; RUN: --ppc-asm-full-reg-names -mcpu=pwr8 --filetype=obj -o /dev/null %s 2>&1 | FileCheck %s -check-prefix=OBJ + +; OBJ: LLVM ERROR: emitXCOFFExceptDirective not yet supported for integrated assembler path. + +!1 = !{!"ppc-trap-reason", !"1", !"2"} +declare void @llvm.ppc.trap(i32 %a) +declare void @llvm.ppc.tw(i32 %a, i32 %b, i32 immarg) +define dso_local void @test__trap_annotation(i32 %a) { +; CHECK-LABEL: test__trap_annotation: +; CHECK: # %bb.0: +; CHECK-NEXT: twi 24, r3, 0 +; CHECK-NEXT: blr +; +; AIX-LABEL: test__trap_annotation: +; AIX: # %bb.0: +; AIX-NEXT: L..tmp0: +; AIX-NEXT: .except .test__trap_annotation, 1, 2 +; AIX-NEXT: twi 24, r3, 0 +; AIX-NEXT: blr + call void @llvm.ppc.trap(i32 %a), !annotation !1 + ret void +} + +define dso_local void @test__tw_annotation(i32 %a) { +; CHECK-LABEL: test__tw_annotation: +; CHECK: # %bb.0: +; CHECK-NEXT: twi 0, r3, 4 +; CHECK-NEXT: blr +; +; AIX-LABEL: test__tw_annotation: +; AIX: # %bb.0: +; AIX-NEXT: L..tmp1: +; AIX-NEXT: .except .test__tw_annotation, 1, 2 +; AIX-NEXT: twi 0, r3, 4 +; AIX-NEXT: blr + call void @llvm.ppc.tw(i32 4, i32 %a, i32 0), !annotation !1 + ret void +} -- 2.7.4