Skip to content

Commit

Permalink
[XCOFF][AIX] Alternative path in EHStreamer for platforms do not have…
Browse files Browse the repository at this point in the history
… 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
  • Loading branch information
jasonliudev committed Dec 2, 2020
1 parent 70764c0 commit 2c63e76
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 8 deletions.
5 changes: 5 additions & 0 deletions llvm/include/llvm/MC/MCAsmInfo.h
Expand Up @@ -186,6 +186,9 @@ class MCAsmInfo {
/// alignment is supported.
bool UseDotAlignForAlignment = false;

/// True if the target supports LEB128 directives.
bool HasLEB128Directives = true;

//===--- Data Emission Directives -------------------------------------===//

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

bool hasLEB128Directives() const { return HasLEB128Directives; }

const char *getZeroDirective() const { return ZeroDirective; }
bool doesZeroDirectiveSupportNonZeroValue() const {
return ZeroDirectiveSupportsNonZeroValue;
Expand Down
2 changes: 1 addition & 1 deletion llvm/include/llvm/Target/TargetLoweringObjectFile.h
Expand Up @@ -157,7 +157,7 @@ class TargetLoweringObjectFile : public MCObjectFileInfo {
unsigned getPersonalityEncoding() const { return PersonalityEncoding; }
unsigned getLSDAEncoding() const { return LSDAEncoding; }
unsigned getTTypeEncoding() const { return TTypeEncoding; }
unsigned getCallSiteEncoding() const { return CallSiteEncoding; }
unsigned getCallSiteEncoding() const;

const MCExpr *getTTypeReference(const MCSymbolRefExpr *Sym, unsigned Encoding,
MCStreamer &Streamer) const;
Expand Down
79 changes: 78 additions & 1 deletion llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp
Expand Up @@ -413,6 +413,7 @@ MCSymbol *EHStreamer::emitExceptionTable() {

bool IsSJLJ = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::SjLj;
bool IsWasm = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::Wasm;
bool HasLEB128Directives = Asm->MAI->hasLEB128Directives();
unsigned CallSiteEncoding =
IsSJLJ ? static_cast<unsigned>(dwarf::DW_EH_PE_udata4) :
Asm->getObjFileLowering().getCallSiteEncoding();
Expand Down Expand Up @@ -505,6 +506,79 @@ MCSymbol *EHStreamer::emitExceptionTable() {
Asm->OutStreamer->emitLabel(CstBeginLabel);
};

// An alternative path to EmitTypeTableRefAndCallSiteTableEndRef.
// For some platforms, the system assembler does not accept the form of
// `.uleb128 label2 - label1`. In those situations, we would need to calculate
// the size between label1 and label2 manually.
// In this case, we would need to calculate the LSDA size and the call
// site table size.
auto EmitTypeTableOffsetAndCallSiteTableOffset = [&]() {
assert(CallSiteEncoding == dwarf::DW_EH_PE_udata4 && !HasLEB128Directives &&
"Targets supporting .uleb128 do not need to take this path.");
if (CallSiteRanges.size() > 1)
report_fatal_error(
"-fbasic-block-sections is not yet supported on "
"platforms that do not have general LEB128 directive support.");

uint64_t CallSiteTableSize = 0;
const CallSiteRange &CSRange = CallSiteRanges.back();
for (size_t CallSiteIdx = CSRange.CallSiteBeginIdx;
CallSiteIdx < CSRange.CallSiteEndIdx; ++CallSiteIdx) {
const CallSiteEntry &S = CallSites[CallSiteIdx];
// Each call site entry consists of 3 udata4 fields (12 bytes) and
// 1 ULEB128 field.
CallSiteTableSize += 12 + getULEB128Size(S.Action);
assert(isUInt<32>(CallSiteTableSize) && "CallSiteTableSize overflows.");
}

Asm->emitEncodingByte(TTypeEncoding, "@TType");
if (HaveTTData) {
const unsigned ByteSizeOfCallSiteOffset =
getULEB128Size(CallSiteTableSize);
uint64_t ActionTableSize = 0;
for (const ActionEntry &Action : Actions) {
// Each action entry consists of two SLEB128 fields.
ActionTableSize += getSLEB128Size(Action.ValueForTypeID) +
getSLEB128Size(Action.NextAction);
assert(isUInt<32>(ActionTableSize) && "ActionTableSize overflows.");
}

const unsigned TypeInfoSize =
Asm->GetSizeOfEncodedValue(TTypeEncoding) * MF->getTypeInfos().size();

const uint64_t LSDASizeBeforeAlign =
1 // Call site encoding byte.
+ ByteSizeOfCallSiteOffset // ULEB128 encoding of CallSiteTableSize.
+ CallSiteTableSize // Call site table content.
+ ActionTableSize; // Action table content.

const uint64_t LSDASizeWithoutAlign = LSDASizeBeforeAlign + TypeInfoSize;
const unsigned ByteSizeOfLSDAWithoutAlign =
getULEB128Size(LSDASizeWithoutAlign);
const uint64_t DisplacementBeforeAlign =
2 // LPStartEncoding and TypeTableEncoding.
+ ByteSizeOfLSDAWithoutAlign + LSDASizeBeforeAlign;

// The type info area starts with 4 byte alignment.
const unsigned NeedAlignVal = (4 - DisplacementBeforeAlign % 4) % 4;
uint64_t LSDASizeWithAlign = LSDASizeWithoutAlign + NeedAlignVal;
const unsigned ByteSizeOfLSDAWithAlign =
getULEB128Size(LSDASizeWithAlign);

// The LSDASizeWithAlign could use 1 byte less padding for alignment
// when the data we use to represent the LSDA Size "needs" to be 1 byte
// larger than the one previously calculated without alignment.
if (ByteSizeOfLSDAWithAlign > ByteSizeOfLSDAWithoutAlign)
LSDASizeWithAlign -= 1;

Asm->OutStreamer->emitULEB128IntValue(LSDASizeWithAlign,
ByteSizeOfLSDAWithAlign);
}

Asm->emitEncodingByte(CallSiteEncoding, "Call site");
Asm->OutStreamer->emitULEB128IntValue(CallSiteTableSize);
};

// SjLj / Wasm Exception handling
if (IsSJLJ || IsWasm) {
Asm->OutStreamer->emitLabel(Asm->getMBBExceptionSym(Asm->MF->front()));
Expand Down Expand Up @@ -620,7 +694,10 @@ MCSymbol *EHStreamer::emitExceptionTable() {
Asm->MAI->getCodePointerSize());
}

EmitTypeTableRefAndCallSiteTableEndRef();
if (HasLEB128Directives)
EmitTypeTableRefAndCallSiteTableEndRef();
else
EmitTypeTableOffsetAndCallSiteTableOffset();

for (size_t CallSiteIdx = CSRange.CallSiteBeginIdx;
CallSiteIdx != CSRange.CallSiteEndIdx; ++CallSiteIdx) {
Expand Down
8 changes: 8 additions & 0 deletions llvm/lib/MC/MCAsmInfo.cpp
Expand Up @@ -28,6 +28,12 @@ static cl::opt<DefaultOnOff> DwarfExtendedLoc(
clEnumVal(Enable, "Enabled"), clEnumVal(Disable, "Disabled")),
cl::init(Default));

cl::opt<cl::boolOrDefault> UseLEB128Directives(
"use-leb128-directives", cl::Hidden,
cl::desc(
"Disable the usage of LEB128 directives, and generate .byte instead."),
cl::init(cl::BOU_UNSET));

MCAsmInfo::MCAsmInfo() {
SeparatorString = ";";
CommentString = "#";
Expand All @@ -51,6 +57,8 @@ MCAsmInfo::MCAsmInfo() {
WeakDirective = "\t.weak\t";
if (DwarfExtendedLoc != Default)
SupportsExtendedDwarfLocDirective = DwarfExtendedLoc == Enable;
if (UseLEB128Directives != cl::BOU_UNSET)
HasLEB128Directives = UseLEB128Directives == cl::BOU_TRUE;

// FIXME: Clang's logic should be synced with the logic used to initialize
// this member and the two implementations should be merged.
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/MC/MCAsmInfoXCOFF.cpp
Expand Up @@ -8,9 +8,12 @@

#include "llvm/MC/MCAsmInfoXCOFF.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/CommandLine.h"

using namespace llvm;

extern cl::opt<cl::boolOrDefault> UseLEB128Directives;

void MCAsmInfoXCOFF::anchor() {}

MCAsmInfoXCOFF::MCAsmInfoXCOFF() {
Expand All @@ -20,6 +23,8 @@ MCAsmInfoXCOFF::MCAsmInfoXCOFF() {
PrivateLabelPrefix = "L..";
SupportsQuotedNames = false;
UseDotAlignForAlignment = true;
if (UseLEB128Directives == cl::BOU_UNSET)
HasLEB128Directives = false;
ZeroDirective = "\t.space\t";
ZeroDirectiveSupportsNonZeroValue = false;
AsciiDirective = nullptr; // not supported
Expand Down
10 changes: 10 additions & 0 deletions llvm/lib/Target/TargetLoweringObjectFile.cpp
Expand Up @@ -20,6 +20,7 @@
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Mangler.h"
#include "llvm/IR/Module.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCStreamer.h"
Expand Down Expand Up @@ -55,6 +56,15 @@ TargetLoweringObjectFile::~TargetLoweringObjectFile() {
delete Mang;
}

unsigned TargetLoweringObjectFile::getCallSiteEncoding() const {
// If target does not have LEB128 directives, we would need the
// call site encoding to be udata4 so that the alternative path
// for not having LEB128 directives could work.
if (!getContext().getAsmInfo()->hasLEB128Directives())
return dwarf::DW_EH_PE_udata4;
return CallSiteEncoding;
}

static bool isNullOrUndef(const Constant *C) {
// Check that the constant isn't all zeros or undefs.
if (C->isNullValue() || isa<UndefValue>(C))
Expand Down
11 changes: 5 additions & 6 deletions llvm/test/CodeGen/PowerPC/aix-exception.ll
Expand Up @@ -107,11 +107,10 @@ eh.resume: ; preds = %catch.dispatch
; ASM: .byte 255 # @LPStart Encoding = omit
; ASM32: .byte 187 # @TType Encoding = indirect datarel sdata4
; ASM64: .byte 188 # @TType Encoding = indirect datarel sdata8
; ASM: .uleb128 L..ttbase0-L..ttbaseref0
; ASM: L..ttbaseref0:
; ASM32: .byte 37
; ASM64: .byte 41
; ASM: .byte 3 # Call site Encoding = udata4
; ASM: .uleb128 L..cst_end0-L..cst_begin0
; ASM: L..cst_begin0:
; ASM: .byte 26
; ASM: .vbyte 4, L..tmp0-L..func_begin0 # >> Call Site 1 <<
; ASM: .vbyte 4, L..tmp1-L..tmp0 # Call between L..tmp0 and L..tmp1
; ASM: .vbyte 4, L..tmp2-L..func_begin0 # jumps to L..tmp2
Expand Down Expand Up @@ -140,9 +139,9 @@ eh.resume: ; preds = %catch.dispatch
; ASM64: .vbyte 8, GCC_except_table1
; ASM64: .vbyte 8, __xlcxx_personality_v1[DS]

; ASM: .toc
; ASM: .toc
; ASM: L..C0:
; ASM: .tc _ZTIi[TC],_ZTIi[UA]
; ASM: .tc _ZTIi[TC],_ZTIi[UA]

declare i8* @__cxa_allocate_exception(i32)
declare void @__cxa_throw(i8*, i8*, i8*)
Expand Down
103 changes: 103 additions & 0 deletions llvm/test/CodeGen/X86/gnu-eh-alternative.ll
@@ -0,0 +1,103 @@
; RUN: llc -verify-machineinstrs -mtriple x86_64-pc-linux-gnu -filetype=asm < %s | \
; RUN: FileCheck --check-prefixes=ASM,ULEB128 %s
; RUN: llc -verify-machineinstrs -mtriple x86_64-pc-linux-gnu -use-leb128-directives=true -filetype=asm < %s | \
; RUN: FileCheck --check-prefixes=ASM,ULEB128 %s
; RUN: llc -verify-machineinstrs -mtriple x86_64-pc-linux-gnu -use-leb128-directives=false -filetype=asm < %s | \
; RUN: FileCheck --check-prefixes=ASM,NO128 %s

@_ZTIi = external dso_local constant i8*

define dso_local i32 @main() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
entry:
%retval = alloca i32, align 4
%exn.slot = alloca i8*, align 8
%ehselector.slot = alloca i32, align 4
store i32 0, i32* %retval, align 4
%exception = call i8* @__cxa_allocate_exception(i64 4) #1
%0 = bitcast i8* %exception to i32*
store i32 1, i32* %0, align 16
invoke void @__cxa_throw(i8* %exception, i8* bitcast (i8** @_ZTIi to i8*), i8* null) #2
to label %unreachable unwind label %lpad

lpad: ; preds = %entry
%1 = landingpad { i8*, i32 }
catch i8* null
%2 = extractvalue { i8*, i32 } %1, 0
store i8* %2, i8** %exn.slot, align 8
%3 = extractvalue { i8*, i32 } %1, 1
store i32 %3, i32* %ehselector.slot, align 4
br label %catch

catch: ; preds = %lpad
%exn = load i8*, i8** %exn.slot, align 8
%4 = call i8* @__cxa_begin_catch(i8* %exn) #1
store i32 2, i32* %retval, align 4
call void @__cxa_end_catch()
br label %return

try.cont: ; No predecessors!
store i32 1, i32* %retval, align 4
br label %return

return: ; preds = %try.cont, %catch
%5 = load i32, i32* %retval, align 4
ret i32 %5

unreachable: ; preds = %entry
unreachable
}

; ASM: GCC_except_table0:
; ASM: .Lexception0:
; ASM: .byte 255 # @LPStart Encoding = omit
; ASM: .byte 3 # @TType Encoding = udata4

; NO128: .byte 49
; NO128: .byte 3 # Call site Encoding = udata4
; NO128: .byte 39
; NO128: .long .Lfunc_begin0-.Lfunc_begin0 # >> Call Site 1 <<
; NO128: .long .Ltmp0-.Lfunc_begin0 # Call between .Lfunc_begin0 and .Ltmp0
; NO128: .long 0 # has no landing pad
; NO128: .byte 0 # On action: cleanup
; NO128: .long .Ltmp0-.Lfunc_begin0 # >> Call Site 2 <<
; NO128: .long .Ltmp1-.Ltmp0 # Call between .Ltmp0 and .Ltmp1
; NO128: .long .Ltmp2-.Lfunc_begin0 # jumps to .Ltmp2
; NO128: .byte 1 # On action: 1
; NO128: .long .Ltmp1-.Lfunc_begin0 # >> Call Site 3 <<
; NO128: .long .Lfunc_end0-.Ltmp1 # Call between .Ltmp1 and .Lfunc_end0
; NO128: .long 0 # has no landing pad
; NO128: .byte 0 # On action: cleanup

; ULEB128: .uleb128 .Lttbase0-.Lttbaseref0
; ULEB128: .Lttbaseref0:
; ULEB128: .byte 1 # Call site Encoding = uleb128
; ULEB128: .uleb128 .Lcst_end0-.Lcst_begin0
; ULEB128: .Lcst_begin0:
; ULEB128: .uleb128 .Lfunc_begin0-.Lfunc_begin0 # >> Call Site 1 <<
; ULEB128: .uleb128 .Ltmp0-.Lfunc_begin0 # Call between .Lfunc_begin0 and .Ltmp0
; ULEB128: .byte 0 # has no landing pad
; ULEB128: .byte 0 # On action: cleanup
; ULEB128: .uleb128 .Ltmp0-.Lfunc_begin0 # >> Call Site 2 <<
; ULEB128: .uleb128 .Ltmp1-.Ltmp0 # Call between .Ltmp0 and .Ltmp1
; ULEB128: .uleb128 .Ltmp2-.Lfunc_begin0 # jumps to .Ltmp2
; ULEB128: .byte 1 # On action: 1
; ULEB128: .uleb128 .Ltmp1-.Lfunc_begin0 # >> Call Site 3 <<
; ULEB128: .uleb128 .Lfunc_end0-.Ltmp1 # Call between .Ltmp1 and .Lfunc_end0
; ULEB128: .byte 0 # has no landing pad
; ULEB128: .byte 0 # On action: cleanup

; ASM: .Lcst_end0:
; ASM: .byte 1 # >> Action Record 1 <<
; ASM: # Catch TypeInfo 1
; ASM: .byte 0 # No further actions
; ASM: .p2align 2
; ASM: # >> Catch TypeInfos <<
; ASM: .long 0 # TypeInfo 1
; ASM: .Lttbase0:
; ASM: .p2align 2

declare dso_local i8* @__cxa_allocate_exception(i64)
declare dso_local void @__cxa_throw(i8*, i8*, i8*)
declare dso_local i32 @__gxx_personality_v0(...)
declare dso_local i8* @__cxa_begin_catch(i8*)
declare dso_local void @__cxa_end_catch()

0 comments on commit 2c63e76

Please sign in to comment.