forked from OSchip/llvm-project
[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
This commit is contained in:
parent
1172bdecfa
commit
ce004fb4f2
|
@ -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<SDValue> &Ops,
|
||||
SelectionDAG &DAG) const;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Div utility functions
|
||||
//
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -5256,6 +5256,12 @@ void TargetLowering::LowerAsmOperandForConstraint(SDValue Op,
|
|||
}
|
||||
}
|
||||
|
||||
void TargetLowering::CollectTargetIntrinsicOperands(const CallInst &I,
|
||||
SmallVectorImpl<SDValue> &Ops,
|
||||
SelectionDAG &DAG) const {
|
||||
return;
|
||||
}
|
||||
|
||||
std::pair<unsigned, const TargetRegisterClass *>
|
||||
TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *RI,
|
||||
StringRef Constraint,
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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) {}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<SDValue, 4> 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;
|
||||
}
|
||||
break;
|
||||
|
||||
if (N->getNumOperands() > MDIndex) {
|
||||
SDValue MDV = N->getOperand(MDIndex);
|
||||
const MDNode *MD = cast<MDNodeSDNode>(MDV)->getMD();
|
||||
assert(MD->getNumOperands() != 0 && "Empty MDNode in operands!");
|
||||
assert((isa<MDString>(MD->getOperand(0)) && cast<MDString>(
|
||||
MD->getOperand(0))->getString().equals("ppc-trap-reason"))
|
||||
&& "Unsupported annotation data type!");
|
||||
for (unsigned i = 1; i < MD->getNumOperands(); i++) {
|
||||
assert(isa<MDString>(MD->getOperand(i)) &&
|
||||
"Invalid data type for annotation ppc-trap-reason!");
|
||||
OpsWithMD.push_back(
|
||||
getI32Imm(std::stoi(cast<MDString>(
|
||||
MD->getOperand(i))->getString().str()), dl));
|
||||
}
|
||||
}
|
||||
OpsWithMD.push_back(N->getOperand(0)); // chain
|
||||
CurDAG->SelectNodeTo(N, Opcode, MVT::Other, OpsWithMD);
|
||||
return;
|
||||
}
|
||||
|
||||
case ISD::INTRINSIC_WO_CHAIN: {
|
||||
|
|
|
@ -16227,6 +16227,24 @@ void PPCTargetLowering::LowerAsmOperandForConstraint(SDValue Op,
|
|||
TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG);
|
||||
}
|
||||
|
||||
void PPCTargetLowering::CollectTargetIntrinsicOperands(const CallInst &I,
|
||||
SmallVectorImpl<SDValue> &Ops,
|
||||
SelectionDAG &DAG) const {
|
||||
if (I.getNumOperands() <= 1)
|
||||
return;
|
||||
if (!isa<ConstantSDNode>(Ops[1].getNode()))
|
||||
return;
|
||||
auto IntrinsicID = cast<ConstantSDNode>(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,
|
||||
|
|
|
@ -995,6 +995,10 @@ namespace llvm {
|
|||
return TargetLowering::getInlineAsmMemConstraint(ConstraintCode);
|
||||
}
|
||||
|
||||
void CollectTargetIntrinsicOperands(const CallInst &I,
|
||||
SmallVectorImpl<SDValue> &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,
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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)>;
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue