Index: llvm/include/llvm/MC/MCAsmInfo.h =================================================================== --- llvm/include/llvm/MC/MCAsmInfo.h +++ llvm/include/llvm/MC/MCAsmInfo.h @@ -186,6 +186,9 @@ /// 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 @@ -575,6 +578,8 @@ return UseDotAlignForAlignment; } + bool hasLEB128Directives() const { return HasLEB128Directives; } + const char *getZeroDirective() const { return ZeroDirective; } bool doesZeroDirectiveSupportNonZeroValue() const { return ZeroDirectiveSupportsNonZeroValue; Index: llvm/include/llvm/Target/TargetLoweringObjectFile.h =================================================================== --- llvm/include/llvm/Target/TargetLoweringObjectFile.h +++ llvm/include/llvm/Target/TargetLoweringObjectFile.h @@ -155,7 +155,7 @@ 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; Index: llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp +++ llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp @@ -413,6 +413,7 @@ bool IsSJLJ = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::SjLj; bool IsWasm = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::Wasm; + bool HasLEB128Directives = Asm->MAI->hasLEB128Directives(); unsigned CallSiteEncoding = IsSJLJ ? static_cast(dwarf::DW_EH_PE_udata4) : Asm->getObjFileLowering().getCallSiteEncoding(); @@ -505,6 +506,79 @@ 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())); @@ -620,7 +694,10 @@ Asm->MAI->getCodePointerSize()); } - EmitTypeTableRefAndCallSiteTableEndRef(); + if (HasLEB128Directives) + EmitTypeTableRefAndCallSiteTableEndRef(); + else + EmitTypeTableOffsetAndCallSiteTableOffset(); for (size_t CallSiteIdx = CSRange.CallSiteBeginIdx; CallSiteIdx != CSRange.CallSiteEndIdx; ++CallSiteIdx) { Index: llvm/lib/MC/MCAsmInfo.cpp =================================================================== --- llvm/lib/MC/MCAsmInfo.cpp +++ llvm/lib/MC/MCAsmInfo.cpp @@ -28,6 +28,12 @@ clEnumVal(Enable, "Enabled"), clEnumVal(Disable, "Disabled")), cl::init(Default)); +cl::opt 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 = "#"; @@ -51,6 +57,8 @@ 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. Index: llvm/lib/MC/MCAsmInfoXCOFF.cpp =================================================================== --- llvm/lib/MC/MCAsmInfoXCOFF.cpp +++ llvm/lib/MC/MCAsmInfoXCOFF.cpp @@ -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 UseLEB128Directives; + void MCAsmInfoXCOFF::anchor() {} MCAsmInfoXCOFF::MCAsmInfoXCOFF() { @@ -20,6 +23,8 @@ PrivateLabelPrefix = "L.."; SupportsQuotedNames = false; UseDotAlignForAlignment = true; + if (UseLEB128Directives == cl::BOU_UNSET) + HasLEB128Directives = false; ZeroDirective = "\t.space\t"; ZeroDirectiveSupportsNonZeroValue = false; AsciiDirective = nullptr; // not supported Index: llvm/lib/Target/TargetLoweringObjectFile.cpp =================================================================== --- llvm/lib/Target/TargetLoweringObjectFile.cpp +++ llvm/lib/Target/TargetLoweringObjectFile.cpp @@ -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" @@ -55,6 +56,15 @@ 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(C)) Index: llvm/test/CodeGen/PowerPC/aix-exception.ll =================================================================== --- llvm/test/CodeGen/PowerPC/aix-exception.ll +++ llvm/test/CodeGen/PowerPC/aix-exception.ll @@ -107,11 +107,10 @@ ; 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 @@ -140,9 +139,9 @@ ; 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*) Index: llvm/test/CodeGen/X86/gnu-eh-alternative.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/X86/gnu-eh-alternative.ll @@ -0,0 +1,104 @@ +; 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() +