Skip to content

Commit 2c63e76

Browse files
committed
[XCOFF][AIX] Alternative path in EHStreamer for platforms do not have uleb128 support
Summary: Not all system assembler supports `.uleb128 label2 - label1` form. When the target do not support this form, we have to take alternative manual calculation to get the offsets from them. Reviewed By: hubert.reinterpretcast Diffierential Revision: https://reviews.llvm.org/D92058
1 parent 70764c0 commit 2c63e76

File tree

8 files changed

+215
-8
lines changed

8 files changed

+215
-8
lines changed

llvm/include/llvm/MC/MCAsmInfo.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,9 @@ class MCAsmInfo {
186186
/// alignment is supported.
187187
bool UseDotAlignForAlignment = false;
188188

189+
/// True if the target supports LEB128 directives.
190+
bool HasLEB128Directives = true;
191+
189192
//===--- Data Emission Directives -------------------------------------===//
190193

191194
/// This should be set to the directive used to get some number of zero (and
@@ -575,6 +578,8 @@ class MCAsmInfo {
575578
return UseDotAlignForAlignment;
576579
}
577580

581+
bool hasLEB128Directives() const { return HasLEB128Directives; }
582+
578583
const char *getZeroDirective() const { return ZeroDirective; }
579584
bool doesZeroDirectiveSupportNonZeroValue() const {
580585
return ZeroDirectiveSupportsNonZeroValue;

llvm/include/llvm/Target/TargetLoweringObjectFile.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ class TargetLoweringObjectFile : public MCObjectFileInfo {
157157
unsigned getPersonalityEncoding() const { return PersonalityEncoding; }
158158
unsigned getLSDAEncoding() const { return LSDAEncoding; }
159159
unsigned getTTypeEncoding() const { return TTypeEncoding; }
160-
unsigned getCallSiteEncoding() const { return CallSiteEncoding; }
160+
unsigned getCallSiteEncoding() const;
161161

162162
const MCExpr *getTTypeReference(const MCSymbolRefExpr *Sym, unsigned Encoding,
163163
MCStreamer &Streamer) const;

llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,7 @@ MCSymbol *EHStreamer::emitExceptionTable() {
413413

414414
bool IsSJLJ = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::SjLj;
415415
bool IsWasm = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::Wasm;
416+
bool HasLEB128Directives = Asm->MAI->hasLEB128Directives();
416417
unsigned CallSiteEncoding =
417418
IsSJLJ ? static_cast<unsigned>(dwarf::DW_EH_PE_udata4) :
418419
Asm->getObjFileLowering().getCallSiteEncoding();
@@ -505,6 +506,79 @@ MCSymbol *EHStreamer::emitExceptionTable() {
505506
Asm->OutStreamer->emitLabel(CstBeginLabel);
506507
};
507508

509+
// An alternative path to EmitTypeTableRefAndCallSiteTableEndRef.
510+
// For some platforms, the system assembler does not accept the form of
511+
// `.uleb128 label2 - label1`. In those situations, we would need to calculate
512+
// the size between label1 and label2 manually.
513+
// In this case, we would need to calculate the LSDA size and the call
514+
// site table size.
515+
auto EmitTypeTableOffsetAndCallSiteTableOffset = [&]() {
516+
assert(CallSiteEncoding == dwarf::DW_EH_PE_udata4 && !HasLEB128Directives &&
517+
"Targets supporting .uleb128 do not need to take this path.");
518+
if (CallSiteRanges.size() > 1)
519+
report_fatal_error(
520+
"-fbasic-block-sections is not yet supported on "
521+
"platforms that do not have general LEB128 directive support.");
522+
523+
uint64_t CallSiteTableSize = 0;
524+
const CallSiteRange &CSRange = CallSiteRanges.back();
525+
for (size_t CallSiteIdx = CSRange.CallSiteBeginIdx;
526+
CallSiteIdx < CSRange.CallSiteEndIdx; ++CallSiteIdx) {
527+
const CallSiteEntry &S = CallSites[CallSiteIdx];
528+
// Each call site entry consists of 3 udata4 fields (12 bytes) and
529+
// 1 ULEB128 field.
530+
CallSiteTableSize += 12 + getULEB128Size(S.Action);
531+
assert(isUInt<32>(CallSiteTableSize) && "CallSiteTableSize overflows.");
532+
}
533+
534+
Asm->emitEncodingByte(TTypeEncoding, "@TType");
535+
if (HaveTTData) {
536+
const unsigned ByteSizeOfCallSiteOffset =
537+
getULEB128Size(CallSiteTableSize);
538+
uint64_t ActionTableSize = 0;
539+
for (const ActionEntry &Action : Actions) {
540+
// Each action entry consists of two SLEB128 fields.
541+
ActionTableSize += getSLEB128Size(Action.ValueForTypeID) +
542+
getSLEB128Size(Action.NextAction);
543+
assert(isUInt<32>(ActionTableSize) && "ActionTableSize overflows.");
544+
}
545+
546+
const unsigned TypeInfoSize =
547+
Asm->GetSizeOfEncodedValue(TTypeEncoding) * MF->getTypeInfos().size();
548+
549+
const uint64_t LSDASizeBeforeAlign =
550+
1 // Call site encoding byte.
551+
+ ByteSizeOfCallSiteOffset // ULEB128 encoding of CallSiteTableSize.
552+
+ CallSiteTableSize // Call site table content.
553+
+ ActionTableSize; // Action table content.
554+
555+
const uint64_t LSDASizeWithoutAlign = LSDASizeBeforeAlign + TypeInfoSize;
556+
const unsigned ByteSizeOfLSDAWithoutAlign =
557+
getULEB128Size(LSDASizeWithoutAlign);
558+
const uint64_t DisplacementBeforeAlign =
559+
2 // LPStartEncoding and TypeTableEncoding.
560+
+ ByteSizeOfLSDAWithoutAlign + LSDASizeBeforeAlign;
561+
562+
// The type info area starts with 4 byte alignment.
563+
const unsigned NeedAlignVal = (4 - DisplacementBeforeAlign % 4) % 4;
564+
uint64_t LSDASizeWithAlign = LSDASizeWithoutAlign + NeedAlignVal;
565+
const unsigned ByteSizeOfLSDAWithAlign =
566+
getULEB128Size(LSDASizeWithAlign);
567+
568+
// The LSDASizeWithAlign could use 1 byte less padding for alignment
569+
// when the data we use to represent the LSDA Size "needs" to be 1 byte
570+
// larger than the one previously calculated without alignment.
571+
if (ByteSizeOfLSDAWithAlign > ByteSizeOfLSDAWithoutAlign)
572+
LSDASizeWithAlign -= 1;
573+
574+
Asm->OutStreamer->emitULEB128IntValue(LSDASizeWithAlign,
575+
ByteSizeOfLSDAWithAlign);
576+
}
577+
578+
Asm->emitEncodingByte(CallSiteEncoding, "Call site");
579+
Asm->OutStreamer->emitULEB128IntValue(CallSiteTableSize);
580+
};
581+
508582
// SjLj / Wasm Exception handling
509583
if (IsSJLJ || IsWasm) {
510584
Asm->OutStreamer->emitLabel(Asm->getMBBExceptionSym(Asm->MF->front()));
@@ -620,7 +694,10 @@ MCSymbol *EHStreamer::emitExceptionTable() {
620694
Asm->MAI->getCodePointerSize());
621695
}
622696

623-
EmitTypeTableRefAndCallSiteTableEndRef();
697+
if (HasLEB128Directives)
698+
EmitTypeTableRefAndCallSiteTableEndRef();
699+
else
700+
EmitTypeTableOffsetAndCallSiteTableOffset();
624701

625702
for (size_t CallSiteIdx = CSRange.CallSiteBeginIdx;
626703
CallSiteIdx != CSRange.CallSiteEndIdx; ++CallSiteIdx) {

llvm/lib/MC/MCAsmInfo.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ static cl::opt<DefaultOnOff> DwarfExtendedLoc(
2828
clEnumVal(Enable, "Enabled"), clEnumVal(Disable, "Disabled")),
2929
cl::init(Default));
3030

31+
cl::opt<cl::boolOrDefault> UseLEB128Directives(
32+
"use-leb128-directives", cl::Hidden,
33+
cl::desc(
34+
"Disable the usage of LEB128 directives, and generate .byte instead."),
35+
cl::init(cl::BOU_UNSET));
36+
3137
MCAsmInfo::MCAsmInfo() {
3238
SeparatorString = ";";
3339
CommentString = "#";
@@ -51,6 +57,8 @@ MCAsmInfo::MCAsmInfo() {
5157
WeakDirective = "\t.weak\t";
5258
if (DwarfExtendedLoc != Default)
5359
SupportsExtendedDwarfLocDirective = DwarfExtendedLoc == Enable;
60+
if (UseLEB128Directives != cl::BOU_UNSET)
61+
HasLEB128Directives = UseLEB128Directives == cl::BOU_TRUE;
5462

5563
// FIXME: Clang's logic should be synced with the logic used to initialize
5664
// this member and the two implementations should be merged.

llvm/lib/MC/MCAsmInfoXCOFF.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@
88

99
#include "llvm/MC/MCAsmInfoXCOFF.h"
1010
#include "llvm/ADT/StringExtras.h"
11+
#include "llvm/Support/CommandLine.h"
1112

1213
using namespace llvm;
1314

15+
extern cl::opt<cl::boolOrDefault> UseLEB128Directives;
16+
1417
void MCAsmInfoXCOFF::anchor() {}
1518

1619
MCAsmInfoXCOFF::MCAsmInfoXCOFF() {
@@ -20,6 +23,8 @@ MCAsmInfoXCOFF::MCAsmInfoXCOFF() {
2023
PrivateLabelPrefix = "L..";
2124
SupportsQuotedNames = false;
2225
UseDotAlignForAlignment = true;
26+
if (UseLEB128Directives == cl::BOU_UNSET)
27+
HasLEB128Directives = false;
2328
ZeroDirective = "\t.space\t";
2429
ZeroDirectiveSupportsNonZeroValue = false;
2530
AsciiDirective = nullptr; // not supported

llvm/lib/Target/TargetLoweringObjectFile.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "llvm/IR/GlobalVariable.h"
2121
#include "llvm/IR/Mangler.h"
2222
#include "llvm/IR/Module.h"
23+
#include "llvm/MC/MCAsmInfo.h"
2324
#include "llvm/MC/MCContext.h"
2425
#include "llvm/MC/MCExpr.h"
2526
#include "llvm/MC/MCStreamer.h"
@@ -55,6 +56,15 @@ TargetLoweringObjectFile::~TargetLoweringObjectFile() {
5556
delete Mang;
5657
}
5758

59+
unsigned TargetLoweringObjectFile::getCallSiteEncoding() const {
60+
// If target does not have LEB128 directives, we would need the
61+
// call site encoding to be udata4 so that the alternative path
62+
// for not having LEB128 directives could work.
63+
if (!getContext().getAsmInfo()->hasLEB128Directives())
64+
return dwarf::DW_EH_PE_udata4;
65+
return CallSiteEncoding;
66+
}
67+
5868
static bool isNullOrUndef(const Constant *C) {
5969
// Check that the constant isn't all zeros or undefs.
6070
if (C->isNullValue() || isa<UndefValue>(C))

llvm/test/CodeGen/PowerPC/aix-exception.ll

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,10 @@ eh.resume: ; preds = %catch.dispatch
107107
; ASM: .byte 255 # @LPStart Encoding = omit
108108
; ASM32: .byte 187 # @TType Encoding = indirect datarel sdata4
109109
; ASM64: .byte 188 # @TType Encoding = indirect datarel sdata8
110-
; ASM: .uleb128 L..ttbase0-L..ttbaseref0
111-
; ASM: L..ttbaseref0:
110+
; ASM32: .byte 37
111+
; ASM64: .byte 41
112112
; ASM: .byte 3 # Call site Encoding = udata4
113-
; ASM: .uleb128 L..cst_end0-L..cst_begin0
114-
; ASM: L..cst_begin0:
113+
; ASM: .byte 26
115114
; ASM: .vbyte 4, L..tmp0-L..func_begin0 # >> Call Site 1 <<
116115
; ASM: .vbyte 4, L..tmp1-L..tmp0 # Call between L..tmp0 and L..tmp1
117116
; ASM: .vbyte 4, L..tmp2-L..func_begin0 # jumps to L..tmp2
@@ -140,9 +139,9 @@ eh.resume: ; preds = %catch.dispatch
140139
; ASM64: .vbyte 8, GCC_except_table1
141140
; ASM64: .vbyte 8, __xlcxx_personality_v1[DS]
142141

143-
; ASM: .toc
142+
; ASM: .toc
144143
; ASM: L..C0:
145-
; ASM: .tc _ZTIi[TC],_ZTIi[UA]
144+
; ASM: .tc _ZTIi[TC],_ZTIi[UA]
146145

147146
declare i8* @__cxa_allocate_exception(i32)
148147
declare void @__cxa_throw(i8*, i8*, i8*)
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
; RUN: llc -verify-machineinstrs -mtriple x86_64-pc-linux-gnu -filetype=asm < %s | \
2+
; RUN: FileCheck --check-prefixes=ASM,ULEB128 %s
3+
; RUN: llc -verify-machineinstrs -mtriple x86_64-pc-linux-gnu -use-leb128-directives=true -filetype=asm < %s | \
4+
; RUN: FileCheck --check-prefixes=ASM,ULEB128 %s
5+
; RUN: llc -verify-machineinstrs -mtriple x86_64-pc-linux-gnu -use-leb128-directives=false -filetype=asm < %s | \
6+
; RUN: FileCheck --check-prefixes=ASM,NO128 %s
7+
8+
@_ZTIi = external dso_local constant i8*
9+
10+
define dso_local i32 @main() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
11+
entry:
12+
%retval = alloca i32, align 4
13+
%exn.slot = alloca i8*, align 8
14+
%ehselector.slot = alloca i32, align 4
15+
store i32 0, i32* %retval, align 4
16+
%exception = call i8* @__cxa_allocate_exception(i64 4) #1
17+
%0 = bitcast i8* %exception to i32*
18+
store i32 1, i32* %0, align 16
19+
invoke void @__cxa_throw(i8* %exception, i8* bitcast (i8** @_ZTIi to i8*), i8* null) #2
20+
to label %unreachable unwind label %lpad
21+
22+
lpad: ; preds = %entry
23+
%1 = landingpad { i8*, i32 }
24+
catch i8* null
25+
%2 = extractvalue { i8*, i32 } %1, 0
26+
store i8* %2, i8** %exn.slot, align 8
27+
%3 = extractvalue { i8*, i32 } %1, 1
28+
store i32 %3, i32* %ehselector.slot, align 4
29+
br label %catch
30+
31+
catch: ; preds = %lpad
32+
%exn = load i8*, i8** %exn.slot, align 8
33+
%4 = call i8* @__cxa_begin_catch(i8* %exn) #1
34+
store i32 2, i32* %retval, align 4
35+
call void @__cxa_end_catch()
36+
br label %return
37+
38+
try.cont: ; No predecessors!
39+
store i32 1, i32* %retval, align 4
40+
br label %return
41+
42+
return: ; preds = %try.cont, %catch
43+
%5 = load i32, i32* %retval, align 4
44+
ret i32 %5
45+
46+
unreachable: ; preds = %entry
47+
unreachable
48+
}
49+
50+
; ASM: GCC_except_table0:
51+
; ASM: .Lexception0:
52+
; ASM: .byte 255 # @LPStart Encoding = omit
53+
; ASM: .byte 3 # @TType Encoding = udata4
54+
55+
; NO128: .byte 49
56+
; NO128: .byte 3 # Call site Encoding = udata4
57+
; NO128: .byte 39
58+
; NO128: .long .Lfunc_begin0-.Lfunc_begin0 # >> Call Site 1 <<
59+
; NO128: .long .Ltmp0-.Lfunc_begin0 # Call between .Lfunc_begin0 and .Ltmp0
60+
; NO128: .long 0 # has no landing pad
61+
; NO128: .byte 0 # On action: cleanup
62+
; NO128: .long .Ltmp0-.Lfunc_begin0 # >> Call Site 2 <<
63+
; NO128: .long .Ltmp1-.Ltmp0 # Call between .Ltmp0 and .Ltmp1
64+
; NO128: .long .Ltmp2-.Lfunc_begin0 # jumps to .Ltmp2
65+
; NO128: .byte 1 # On action: 1
66+
; NO128: .long .Ltmp1-.Lfunc_begin0 # >> Call Site 3 <<
67+
; NO128: .long .Lfunc_end0-.Ltmp1 # Call between .Ltmp1 and .Lfunc_end0
68+
; NO128: .long 0 # has no landing pad
69+
; NO128: .byte 0 # On action: cleanup
70+
71+
; ULEB128: .uleb128 .Lttbase0-.Lttbaseref0
72+
; ULEB128: .Lttbaseref0:
73+
; ULEB128: .byte 1 # Call site Encoding = uleb128
74+
; ULEB128: .uleb128 .Lcst_end0-.Lcst_begin0
75+
; ULEB128: .Lcst_begin0:
76+
; ULEB128: .uleb128 .Lfunc_begin0-.Lfunc_begin0 # >> Call Site 1 <<
77+
; ULEB128: .uleb128 .Ltmp0-.Lfunc_begin0 # Call between .Lfunc_begin0 and .Ltmp0
78+
; ULEB128: .byte 0 # has no landing pad
79+
; ULEB128: .byte 0 # On action: cleanup
80+
; ULEB128: .uleb128 .Ltmp0-.Lfunc_begin0 # >> Call Site 2 <<
81+
; ULEB128: .uleb128 .Ltmp1-.Ltmp0 # Call between .Ltmp0 and .Ltmp1
82+
; ULEB128: .uleb128 .Ltmp2-.Lfunc_begin0 # jumps to .Ltmp2
83+
; ULEB128: .byte 1 # On action: 1
84+
; ULEB128: .uleb128 .Ltmp1-.Lfunc_begin0 # >> Call Site 3 <<
85+
; ULEB128: .uleb128 .Lfunc_end0-.Ltmp1 # Call between .Ltmp1 and .Lfunc_end0
86+
; ULEB128: .byte 0 # has no landing pad
87+
; ULEB128: .byte 0 # On action: cleanup
88+
89+
; ASM: .Lcst_end0:
90+
; ASM: .byte 1 # >> Action Record 1 <<
91+
; ASM: # Catch TypeInfo 1
92+
; ASM: .byte 0 # No further actions
93+
; ASM: .p2align 2
94+
; ASM: # >> Catch TypeInfos <<
95+
; ASM: .long 0 # TypeInfo 1
96+
; ASM: .Lttbase0:
97+
; ASM: .p2align 2
98+
99+
declare dso_local i8* @__cxa_allocate_exception(i64)
100+
declare dso_local void @__cxa_throw(i8*, i8*, i8*)
101+
declare dso_local i32 @__gxx_personality_v0(...)
102+
declare dso_local i8* @__cxa_begin_catch(i8*)
103+
declare dso_local void @__cxa_end_catch()

0 commit comments

Comments
 (0)