Skip to content

Commit a65d8c5

Browse files
committed
[XCOFF][AIX] Generate LSDA data and compact unwind section on AIX
Summary: AIX uses the existing EH infrastructure in clang and llvm. The major differences would be 1. AIX do not have CFI instructions. 2. AIX uses a new personality routine, named __xlcxx_personality_v1. It doesn't use the GCC personality rountine, because the interoperability is not there yet on AIX. 3. AIX do not use eh_frame sections. Instead, it would use a eh_info section (compat unwind section) to store the information about personality routine and LSDA data address. Reviewed By: daltenty, hubert.reinterpretcast Differential Revision: https://reviews.llvm.org/D91455
1 parent 9d6d24c commit a65d8c5

File tree

20 files changed

+319
-10
lines changed

20 files changed

+319
-10
lines changed

clang/lib/CodeGen/CGCleanup.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,7 @@ struct EHPersonality {
612612
static const EHPersonality MSVC_C_specific_handler;
613613
static const EHPersonality MSVC_CxxFrameHandler3;
614614
static const EHPersonality GNU_Wasm_CPlusPlus;
615+
static const EHPersonality XL_CPlusPlus;
615616

616617
/// Does this personality use landingpads or the family of pad instructions
617618
/// designed to form funclets?

clang/lib/CodeGen/CGException.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ const EHPersonality
113113
EHPersonality::MSVC_CxxFrameHandler3 = { "__CxxFrameHandler3", nullptr };
114114
const EHPersonality
115115
EHPersonality::GNU_Wasm_CPlusPlus = { "__gxx_wasm_personality_v0", nullptr };
116+
const EHPersonality EHPersonality::XL_CPlusPlus = {"__xlcxx_personality_v1",
117+
nullptr};
116118

117119
static const EHPersonality &getCPersonality(const TargetInfo &Target,
118120
const LangOptions &L) {
@@ -161,6 +163,8 @@ static const EHPersonality &getCXXPersonality(const TargetInfo &Target,
161163
const llvm::Triple &T = Target.getTriple();
162164
if (T.isWindowsMSVCEnvironment())
163165
return EHPersonality::MSVC_CxxFrameHandler3;
166+
if (T.isOSAIX())
167+
return EHPersonality::XL_CPlusPlus;
164168
if (L.SjLjExceptions)
165169
return EHPersonality::GNU_CPlusPlus_SJLJ;
166170
if (L.DWARFExceptions)

clang/test/CodeGenCXX/personality.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
// RUN: %clang_cc1 -triple i686-unknown-windows-gnu -fexceptions -fseh-exceptions -fcxx-exceptions -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-GNU-SEH
1313
// RUN: %clang_cc1 -triple i686-unknown-windows-gnu -fexceptions -fsjlj-exceptions -fcxx-exceptions -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-GNU-SJLJ
1414

15+
// RUN: %clang_cc1 -triple powerpc-unknown-aix-xcoff -fexceptions -fcxx-exceptions -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-AIX
16+
// RUN: %clang_cc1 -triple powerpc64-unknown-aix-xcoff -fexceptions -fcxx-exceptions -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-AIX
17+
1518
extern void g();
1619

1720
// CHECK-GNU: personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
@@ -21,6 +24,8 @@ extern void g();
2124

2225
// CHECK-WIN: personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
2326

27+
// CHECK-AIX: personality i8* bitcast (i32 (...)* @__xlcxx_personality_v1 to i8*)
28+
2429
void f() {
2530
try {
2631
g();

llvm/include/llvm/Analysis/EHPersonalities.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ enum class EHPersonality {
3232
MSVC_CXX,
3333
CoreCLR,
3434
Rust,
35-
Wasm_CXX
35+
Wasm_CXX,
36+
XL_CXX
3637
};
3738

3839
/// See if the given exception handling personality function is one

llvm/include/llvm/CodeGen/AsmPrinter.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,7 @@ class AsmPrinter : public MachineFunctionPass {
603603
unsigned GetSizeOfEncodedValue(unsigned Encoding) const;
604604

605605
/// Emit reference to a ttype global with a specified encoding.
606-
void emitTTypeReference(const GlobalValue *GV, unsigned Encoding) const;
606+
virtual void emitTTypeReference(const GlobalValue *GV, unsigned Encoding);
607607

608608
/// Emit a reference to a symbol for use in dwarf. Different object formats
609609
/// represent this in different ways. Some use a relocation others encode

llvm/include/llvm/MC/MCTargetOptions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ enum class ExceptionHandling {
2222
ARM, ///< ARM EHABI
2323
WinEH, ///< Windows Exception Handling
2424
Wasm, ///< WebAssembly Exception Handling
25+
AIX, ///< AIX Exception Handling
2526
};
2627

2728
enum class DebugCompressionType {

llvm/lib/Analysis/EHPersonalities.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ EHPersonality llvm::classifyEHPersonality(const Value *Pers) {
3939
.Case("ProcessCLRException", EHPersonality::CoreCLR)
4040
.Case("rust_eh_personality", EHPersonality::Rust)
4141
.Case("__gxx_wasm_personality_v0", EHPersonality::Wasm_CXX)
42+
.Case("__xlcxx_personality_v1", EHPersonality::XL_CXX)
4243
.Default(EHPersonality::Unknown);
4344
}
4445

@@ -57,6 +58,8 @@ StringRef llvm::getEHPersonalityName(EHPersonality Pers) {
5758
case EHPersonality::CoreCLR: return "ProcessCLRException";
5859
case EHPersonality::Rust: return "rust_eh_personality";
5960
case EHPersonality::Wasm_CXX: return "__gxx_wasm_personality_v0";
61+
case EHPersonality::XL_CXX:
62+
return "__xlcxx_personality_v1";
6063
case EHPersonality::Unknown: llvm_unreachable("Unknown EHPersonality!");
6164
}
6265

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
//===-- CodeGen/AsmPrinter/AIXException.cpp - AIX Exception Impl ----------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file contains support for writing AIX exception info into asm files.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "DwarfException.h"
14+
#include "llvm/CodeGen/AsmPrinter.h"
15+
#include "llvm/CodeGen/MachineModuleInfo.h"
16+
#include "llvm/MC/MCSectionXCOFF.h"
17+
#include "llvm/MC/MCStreamer.h"
18+
#include "llvm/Target/TargetLoweringObjectFile.h"
19+
#include "llvm/Target/TargetMachine.h"
20+
21+
namespace llvm {
22+
23+
AIXException::AIXException(AsmPrinter *A) : DwarfCFIExceptionBase(A) {}
24+
25+
void AIXException::emitExceptionInfoTable(const MCSymbol *LSDA,
26+
const MCSymbol *PerSym) {
27+
// Generate EH Info Table.
28+
// The EH Info Table, aka, 'compat unwind section' on AIX, have the following
29+
// format: struct eh_info_t {
30+
// unsigned version; /* EH info verion 0 */
31+
// #if defined(__64BIT__)
32+
// char _pad[4]; /* padding */
33+
// #endif
34+
// unsigned long lsda; /* Pointer to LSDA */
35+
// unsigned long personality; /* Pointer to the personality routine */
36+
// }
37+
38+
Asm->OutStreamer->SwitchSection(
39+
Asm->getObjFileLowering().getCompactUnwindSection());
40+
MCSymbol *EHInfoLabel = MMI->getContext().getOrCreateSymbol(
41+
"__ehinfo." + Twine(Asm->getFunctionNumber()));
42+
Asm->OutStreamer->emitLabel(EHInfoLabel);
43+
44+
// Version number.
45+
Asm->emitInt32(0);
46+
47+
const DataLayout &DL = MMI->getModule()->getDataLayout();
48+
const unsigned PointerSize = DL.getPointerSize();
49+
50+
// Add necessary paddings in 64 bit mode.
51+
Asm->OutStreamer->emitValueToAlignment(PointerSize);
52+
53+
// LSDA location.
54+
Asm->OutStreamer->emitValue(MCSymbolRefExpr::create(LSDA, Asm->OutContext),
55+
PointerSize);
56+
57+
// Personality routine.
58+
Asm->OutStreamer->emitValue(MCSymbolRefExpr::create(PerSym, Asm->OutContext),
59+
PointerSize);
60+
}
61+
62+
void AIXException::endFunction(const MachineFunction *MF) {
63+
const Function &F = MF->getFunction();
64+
bool HasLandingPads = !MF->getLandingPads().empty();
65+
const Function *Per = nullptr;
66+
if (F.hasPersonalityFn())
67+
Per = dyn_cast<Function>(F.getPersonalityFn()->stripPointerCasts());
68+
bool EmitEHBlock =
69+
HasLandingPads || (F.hasPersonalityFn() &&
70+
!isNoOpWithoutInvoke(classifyEHPersonality(Per)) &&
71+
F.needsUnwindTableEntry());
72+
73+
if (!EmitEHBlock)
74+
return;
75+
76+
const MCSymbol *LSDALabel = emitExceptionTable();
77+
const MCSymbol *PerSym = Asm->TM.getSymbol(Per);
78+
79+
emitExceptionInfoTable(LSDALabel, PerSym);
80+
}
81+
82+
} // End of namespace llvm

llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,9 @@ bool AsmPrinter::doInitialization(Module &M) {
380380
case ExceptionHandling::Wasm:
381381
ES = new WasmException(this);
382382
break;
383+
case ExceptionHandling::AIX:
384+
ES = new AIXException(this);
385+
break;
383386
}
384387
if (ES)
385388
Handlers.emplace_back(std::unique_ptr<EHStreamer>(ES), EHTimerName,

llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,12 @@ static const char *DecodeDWARFEncoding(unsigned Encoding) {
9898
case dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata8
9999
:
100100
return "indirect pcrel sdata8";
101+
case dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_datarel |
102+
dwarf::DW_EH_PE_sdata4:
103+
return "indirect datarel sdata4";
104+
case dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_datarel |
105+
dwarf::DW_EH_PE_sdata8:
106+
return "indirect datarel sdata8";
101107
}
102108

103109
return "<unknown encoding>";
@@ -138,8 +144,7 @@ unsigned AsmPrinter::GetSizeOfEncodedValue(unsigned Encoding) const {
138144
}
139145
}
140146

141-
void AsmPrinter::emitTTypeReference(const GlobalValue *GV,
142-
unsigned Encoding) const {
147+
void AsmPrinter::emitTTypeReference(const GlobalValue *GV, unsigned Encoding) {
143148
if (GV) {
144149
const TargetLoweringObjectFile &TLOF = getObjFileLowering();
145150

llvm/lib/CodeGen/AsmPrinter/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
add_llvm_component_library(LLVMAsmPrinter
22
AccelTable.cpp
33
AddressPool.cpp
4+
AIXException.cpp
45
ARMException.cpp
56
AsmPrinter.cpp
67
AsmPrinterDwarf.cpp

llvm/lib/CodeGen/AsmPrinter/DwarfException.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,20 @@ class LLVM_LIBRARY_VISIBILITY ARMException : public DwarfCFIExceptionBase {
9292
/// Gather and emit post-function exception information.
9393
void endFunction(const MachineFunction *) override;
9494
};
95+
96+
class LLVM_LIBRARY_VISIBILITY AIXException : public DwarfCFIExceptionBase {
97+
/// This is AIX's compat unwind section, which unwinder would use
98+
/// to find the location of LSDA area and personality rountine.
99+
void emitExceptionInfoTable(const MCSymbol *LSDA, const MCSymbol *PerSym);
100+
101+
public:
102+
AIXException(AsmPrinter *A);
103+
104+
void endModule() override {}
105+
void beginFunction(const MachineFunction *MF) override {}
106+
107+
void endFunction(const MachineFunction *MF) override;
108+
};
95109
} // End of namespace llvm
96110

97111
#endif

llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -288,11 +288,13 @@ void EHStreamer::computeCallSiteTable(
288288
assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] &&
289289
"Inconsistent landing pad map!");
290290

291-
// For Dwarf exception handling (SjLj handling doesn't use this). If some
292-
// instruction between the previous try-range and this one may throw,
293-
// create a call-site entry with no landing pad for the region between the
294-
// try-ranges.
295-
if (SawPotentiallyThrowing && Asm->MAI->usesCFIForEH()) {
291+
// For Dwarf and AIX exception handling (SjLj handling doesn't use this).
292+
// If some instruction between the previous try-range and this one may
293+
// throw, create a call-site entry with no landing pad for the region
294+
// between the try-ranges.
295+
if (SawPotentiallyThrowing &&
296+
(Asm->MAI->usesCFIForEH() ||
297+
Asm->MAI->getExceptionHandlingType() == ExceptionHandling::AIX)) {
296298
CallSites.push_back({LastLabel, BeginLabel, nullptr, 0});
297299
PreviousIsInvoke = false;
298300
}

llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2272,9 +2272,13 @@ MCSection *TargetLoweringObjectFileXCOFF::getSectionForConstant(
22722272
void TargetLoweringObjectFileXCOFF::Initialize(MCContext &Ctx,
22732273
const TargetMachine &TgtM) {
22742274
TargetLoweringObjectFile::Initialize(Ctx, TgtM);
2275-
TTypeEncoding = 0;
2275+
TTypeEncoding =
2276+
dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_datarel |
2277+
(TgtM.getTargetTriple().isArch32Bit() ? dwarf::DW_EH_PE_sdata4
2278+
: dwarf::DW_EH_PE_sdata8);
22762279
PersonalityEncoding = 0;
22772280
LSDAEncoding = 0;
2281+
CallSiteEncoding = dwarf::DW_EH_PE_udata4;
22782282
}
22792283

22802284
MCSection *TargetLoweringObjectFileXCOFF::getStaticCtorSection(

llvm/lib/CodeGen/TargetPassConfig.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,7 @@ void TargetPassConfig::addPassesToHandleExceptions() {
735735
LLVM_FALLTHROUGH;
736736
case ExceptionHandling::DwarfCFI:
737737
case ExceptionHandling::ARM:
738+
case ExceptionHandling::AIX:
738739
addPass(createDwarfEHPass(getOptLevel()));
739740
break;
740741
case ExceptionHandling::WinEH:

llvm/lib/MC/MCAsmInfoXCOFF.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ MCAsmInfoXCOFF::MCAsmInfoXCOFF() {
3737
HasDotTypeDotSizeDirective = false;
3838
UseIntegratedAssembler = false;
3939
NeedsFunctionDescriptors = true;
40+
41+
ExceptionsType = ExceptionHandling::AIX;
4042
}
4143

4244
bool MCAsmInfoXCOFF::isAcceptableChar(char C) const {

llvm/lib/MC/MCObjectFileInfo.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,14 @@ void MCObjectFileInfo::initXCOFFMCObjectFileInfo(const Triple &T) {
883883
// The TOC-base always has 0 size, but 4 byte alignment.
884884
TOCBaseSection->setAlignment(Align(4));
885885

886+
LSDASection = Ctx->getXCOFFSection(".gcc_except_table",
887+
XCOFF::StorageMappingClass::XMC_RO,
888+
XCOFF::XTY_SD, SectionKind::getReadOnly());
889+
890+
CompactUnwindSection =
891+
Ctx->getXCOFFSection(".eh_info_table", XCOFF::StorageMappingClass::XMC_RW,
892+
XCOFF::XTY_SD, SectionKind::getData());
893+
886894
// DWARF sections for XCOFF are not csects. They are special STYP_DWARF
887895
// sections, and the individual DWARF sections are distinguished by their
888896
// section subtype.

llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,8 @@ class PPCAIXAsmPrinter : public PPCAsmPrinter {
193193
void emitInstruction(const MachineInstr *MI) override;
194194

195195
bool doFinalization(Module &M) override;
196+
197+
void emitTTypeReference(const GlobalValue *GV, unsigned Encoding) override;
196198
};
197199

198200
} // end anonymous namespace
@@ -2056,6 +2058,23 @@ void PPCAIXAsmPrinter::emitXXStructorList(const DataLayout &DL,
20562058
}
20572059
}
20582060

2061+
void PPCAIXAsmPrinter::emitTTypeReference(const GlobalValue *GV,
2062+
unsigned Encoding) {
2063+
if (GV) {
2064+
MCSymbol *TypeInfoSym = TM.getSymbol(GV);
2065+
MCSymbol *TOCEntry = lookUpOrCreateTOCEntry(TypeInfoSym);
2066+
const MCSymbol *TOCBaseSym =
2067+
cast<MCSectionXCOFF>(getObjFileLowering().getTOCBaseSection())
2068+
->getQualNameSymbol();
2069+
auto &Ctx = OutStreamer->getContext();
2070+
const MCExpr *Exp =
2071+
MCBinaryExpr::createSub(MCSymbolRefExpr::create(TOCEntry, Ctx),
2072+
MCSymbolRefExpr::create(TOCBaseSym, Ctx), Ctx);
2073+
OutStreamer->emitValue(Exp, GetSizeOfEncodedValue(Encoding));
2074+
} else
2075+
OutStreamer->emitIntValue(0, GetSizeOfEncodedValue(Encoding));
2076+
}
2077+
20592078
// Return a pass that prints the PPC assembly code for a MachineFunction to the
20602079
// given output stream.
20612080
static AsmPrinter *

llvm/lib/Transforms/InstCombine/InstructionCombining.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3109,6 +3109,7 @@ static bool isCatchAll(EHPersonality Personality, Constant *TypeInfo) {
31093109
case EHPersonality::MSVC_CXX:
31103110
case EHPersonality::CoreCLR:
31113111
case EHPersonality::Wasm_CXX:
3112+
case EHPersonality::XL_CXX:
31123113
return TypeInfo->isNullValue();
31133114
}
31143115
llvm_unreachable("invalid enum");

0 commit comments

Comments
 (0)