Skip to content

Commit 6398903

Browse files
Extend the uwtable attribute with unwind table kind
We have the `clang -cc1` command-line option `-funwind-tables=1|2` and the codegen option `VALUE_CODEGENOPT(UnwindTables, 2, 0) ///< Unwind tables (1) or asynchronous unwind tables (2)`. However, this is encoded in LLVM IR by the presence or the absence of the `uwtable` attribute, i.e. we lose the information whether to generate want just some unwind tables or asynchronous unwind tables. Asynchronous unwind tables take more space in the runtime image, I'd estimate something like 80-90% more, as the difference is adding roughly the same number of CFI directives as for prologues, only a bit simpler (e.g. `.cfi_offset reg, off` vs. `.cfi_restore reg`). Or even more, if you consider tail duplication of epilogue blocks. Asynchronous unwind tables could also restrict code generation to having only a finite number of frame pointer adjustments (an example of *not* having a finite number of `SP` adjustments is on AArch64 when untagging the stack (MTE) in some cases the compiler can modify `SP` in a loop). Having the CFI precise up to an instruction generally also means one cannot bundle together CFI instructions once the prologue is done, they need to be interspersed with ordinary instructions, which means extra `DW_CFA_advance_loc` commands, further increasing the unwind tables size. That is to say, async unwind tables impose a non-negligible overhead, yet for the most common use cases (like C++ exceptions), they are not even needed. This patch extends the `uwtable` attribute with an optional value: - `uwtable` (default to `async`) - `uwtable(sync)`, synchronous unwind tables - `uwtable(async)`, asynchronous (instruction precise) unwind tables Reviewed By: MaskRay Differential Revision: https://reviews.llvm.org/D114543
1 parent 48f1884 commit 6398903

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+473
-295
lines changed

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3188,7 +3188,7 @@ static void emitCheckHandlerCall(CodeGenFunction &CGF,
31883188
B.addAttribute(llvm::Attribute::NoReturn)
31893189
.addAttribute(llvm::Attribute::NoUnwind);
31903190
}
3191-
B.addAttribute(llvm::Attribute::UWTable);
3191+
B.addUWTableAttr(llvm::UWTableKind::Default);
31923192

31933193
llvm::FunctionCallee Fn = CGF.CGM.CreateRuntimeFunction(
31943194
FnType, FnName,

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -828,7 +828,7 @@ void CodeGenModule::Release() {
828828
if (CodeGenOpts.NoPLT)
829829
getModule().setRtLibUseGOT();
830830
if (CodeGenOpts.UnwindTables)
831-
getModule().setUwtable();
831+
getModule().setUwtable(llvm::UWTableKind(CodeGenOpts.UnwindTables));
832832

833833
switch (CodeGenOpts.getFramePointer()) {
834834
case CodeGenOptions::FramePointerKind::None:
@@ -1839,7 +1839,7 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
18391839
llvm::AttrBuilder B(F->getContext());
18401840

18411841
if (CodeGenOpts.UnwindTables)
1842-
B.addAttribute(llvm::Attribute::UWTable);
1842+
B.addUWTableAttr(llvm::UWTableKind(CodeGenOpts.UnwindTables));
18431843

18441844
if (CodeGenOpts.StackClashProtector)
18451845
B.addAttribute("probe-stack", "inline-asm");

clang/test/CodeGen/asan-globals.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ void func() {
4848
// RUN: %clang_cc1 -emit-llvm -fsanitize=address -funwind-tables=2 -o - %s | FileCheck %s --check-prefixes=UWTABLE
4949
// UWTABLE: define internal void @asan.module_dtor() #[[#ATTR:]] {
5050
// UWTABLE: attributes #[[#ATTR]] = { nounwind uwtable }
51-
// UWTABLE: ![[#]] = !{i32 7, !"uwtable", i32 1}
51+
// UWTABLE: ![[#]] = !{i32 7, !"uwtable", i32 2}
5252

5353
// CHECK: !llvm.asan.globals = !{![[EXTRA_GLOBAL:[0-9]+]], ![[GLOBAL:[0-9]+]], ![[DYN_INIT_GLOBAL:[0-9]+]], ![[ATTR_GLOBAL:[0-9]+]], ![[IGNORELISTED_GLOBAL:[0-9]+]], ![[SECTIONED_GLOBAL:[0-9]+]], ![[SPECIAL_GLOBAL:[0-9]+]], ![[STATIC_VAR:[0-9]+]], ![[LITERAL:[0-9]+]]}
5454
// CHECK: ![[EXTRA_GLOBAL]] = !{{{.*}} ![[EXTRA_GLOBAL_LOC:[0-9]+]], !"extra_global", i1 false, i1 false}

clang/test/CodeGen/uwtable-attr.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Test that function and modules attributes react on the command-line options,
2+
// it does not state the current behaviour makes sense in all cases (it does not).
3+
4+
// RUN: %clang -S -emit-llvm -o - %s | FileCheck %s -check-prefixes=CHECK,DEFAULT
5+
// RUN: %clang -S -emit-llvm -o - %s -funwind-tables -fno-asynchronous-unwind-tables | FileCheck %s -check-prefixes=CHECK,TABLES
6+
// RUN: %clang -S -emit-llvm -o - %s -fno-unwind-tables -fno-asynchronous-unwind-tables | FileCheck %s -check-prefixes=CHECK,NO_TABLES
7+
8+
// RUN: %clang -S -emit-llvm -o - -x c++ %s | FileCheck %s -check-prefixes=CHECK,DEFAULT
9+
// RUN: %clang -S -emit-llvm -o - -x c++ %s -funwind-tables -fno-asynchronous-unwind-tables | FileCheck %s -check-prefixes=CHECK,TABLES
10+
// RUN: %clang -S -emit-llvm -o - -x c++ %s -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables | FileCheck %s -check-prefixes=CHECK,NO_TABLES
11+
12+
#ifdef __cplusplus
13+
extern "C" void g(void);
14+
struct S { ~S(); };
15+
extern "C" int f() { S s; g(); return 0;};
16+
#else
17+
void g(void);
18+
int f() { g(); return 0; };
19+
#endif
20+
21+
// CHECK: define {{.*}} @f() #[[#F:]]
22+
// CHECK: declare {{.*}} @g() #[[#]]
23+
24+
// DEFAULT: attributes #[[#F]] = { {{.*}} uwtable{{ }}{{.*}} }
25+
// DEFAULT: ![[#]] = !{i32 7, !"uwtable", i32 2}
26+
27+
// TABLES: attributes #[[#F]] = { {{.*}} uwtable(sync){{.*}} }
28+
// TABLES: ![[#]] = !{i32 7, !"uwtable", i32 1}
29+
30+
// NO_TABLES-NOT: uwtable

llvm/bindings/go/llvm/ir_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ func TestAttributes(t *testing.T) {
8383
"sspstrong",
8484
"sanitize_thread",
8585
"sanitize_memory",
86-
"uwtable",
8786
"zeroext",
8887
"cold",
8988
"nocf_check",

llvm/docs/LangRef.rst

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2108,12 +2108,15 @@ example:
21082108
function with a tail call. The prototype of a thunk should not be used for
21092109
optimization purposes. The caller is expected to cast the thunk prototype to
21102110
match the thunk target prototype.
2111-
``uwtable``
2111+
``uwtable[(sync|async)]``
21122112
This attribute indicates that the ABI being targeted requires that
21132113
an unwind table entry be produced for this function even if we can
21142114
show that no exceptions passes by it. This is normally the case for
21152115
the ELF x86-64 abi, but it can be disabled for some compilation
2116-
units.
2116+
units. The optional parameter describes what kind of unwind tables
2117+
to generate: ``sync`` for normal unwind tables, ``async`` for asynchronous
2118+
(instruction precise) unwind tables. Without the parameter, the attribute
2119+
``uwtable`` is equivalent to ``uwtable(async)``.
21172120
``nocf_check``
21182121
This attribute indicates that no control-flow check will be performed on
21192122
the attributed entity. It disables -fcf-protection=<> for a specific
@@ -7215,8 +7218,9 @@ functions is small.
72157218
- "frame-pointer": **Max**. The value can be 0, 1, or 2. A synthesized function
72167219
will get the "frame-pointer" function attribute, with value being "none",
72177220
"non-leaf", or "all", respectively.
7218-
- "uwtable": **Max**. The value can be 0 or 1. If the value is 1, a synthesized
7219-
function will get the ``uwtable`` function attribute.
7221+
- "uwtable": **Max**. The value can be 0, 1, or 2. If the value is 1, a synthesized
7222+
function will get the ``uwtable(sync)`` function attribute, if the value is 2,
7223+
a synthesized function will get the ``uwtable(async)`` function attribute.
72207224

72217225
Objective-C Garbage Collection Module Flags Metadata
72227226
----------------------------------------------------

llvm/include/llvm/AsmParser/LLParser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ namespace llvm {
263263
bool parseOptionalAlignment(MaybeAlign &Alignment,
264264
bool AllowParens = false);
265265
bool parseOptionalDerefAttrBytes(lltok::Kind AttrKind, uint64_t &Bytes);
266+
bool parseOptionalUWTableKind(UWTableKind &Kind);
266267
bool parseScopeAndOrdering(bool IsAtomic, SyncScope::ID &SSID,
267268
AtomicOrdering &Ordering);
268269
bool parseScope(SyncScope::ID &SSID);

llvm/include/llvm/AsmParser/LLToken.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,8 @@ enum Kind {
252252
kw_immarg,
253253
kw_byref,
254254
kw_mustprogress,
255+
kw_sync,
256+
kw_async,
255257

256258
kw_type,
257259
kw_opaque,

llvm/include/llvm/IR/Attributes.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "llvm/ADT/StringRef.h"
2323
#include "llvm/Config/llvm-config.h"
2424
#include "llvm/Support/Alignment.h"
25+
#include "llvm/Support/CodeGen.h"
2526
#include "llvm/Support/PointerLikeTypeTraits.h"
2627
#include <bitset>
2728
#include <cassert>
@@ -130,6 +131,7 @@ class Attribute {
130131
static Attribute getWithByRefType(LLVMContext &Context, Type *Ty);
131132
static Attribute getWithPreallocatedType(LLVMContext &Context, Type *Ty);
132133
static Attribute getWithInAllocaType(LLVMContext &Context, Type *Ty);
134+
static Attribute getWithUWTableKind(LLVMContext &Context, UWTableKind Kind);
133135

134136
/// For a typed attribute, return the equivalent attribute with the type
135137
/// changed to \p ReplacementTy.
@@ -223,6 +225,9 @@ class Attribute {
223225
/// unknown.
224226
Optional<unsigned> getVScaleRangeMax() const;
225227

228+
// Returns the unwind table kind.
229+
UWTableKind getUWTableKind() const;
230+
226231
/// The Attribute is converted to a string of equivalent mnemonic. This
227232
/// is, presumably, for writing out the mnemonics for the assembly writer.
228233
std::string getAsString(bool InAttrGrp = false) const;
@@ -353,6 +358,7 @@ class AttributeSet {
353358
std::pair<unsigned, Optional<unsigned>> getAllocSizeArgs() const;
354359
unsigned getVScaleRangeMin() const;
355360
Optional<unsigned> getVScaleRangeMax() const;
361+
UWTableKind getUWTableKind() const;
356362
std::string getAsString(bool InAttrGrp = false) const;
357363

358364
/// Return true if this attribute set belongs to the LLVMContext.
@@ -841,6 +847,9 @@ class AttributeList {
841847
/// arg.
842848
uint64_t getParamDereferenceableOrNullBytes(unsigned ArgNo) const;
843849

850+
/// Get the unwind table kind requested for the function.
851+
UWTableKind getUWTableKind() const;
852+
844853
/// Return the attributes at the index as a string.
845854
std::string getAsString(unsigned Index, bool InAttrGrp = false) const;
846855

@@ -1190,6 +1199,10 @@ class AttrBuilder {
11901199
/// Attribute.getIntValue().
11911200
AttrBuilder &addVScaleRangeAttrFromRawRepr(uint64_t RawVScaleRangeRepr);
11921201

1202+
/// This turns the unwind table kind into the form used internally in
1203+
/// Attribute.
1204+
AttrBuilder &addUWTableAttr(UWTableKind Kind);
1205+
11931206
ArrayRef<Attribute> attrs() const { return Attrs; }
11941207

11951208
bool operator==(const AttrBuilder &B) const;

llvm/include/llvm/IR/Attributes.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ def SwiftSelf : EnumAttr<"swiftself", [ParamAttr]>;
273273
def SwiftAsync : EnumAttr<"swiftasync", [ParamAttr]>;
274274

275275
/// Function must be in a unwind table.
276-
def UWTable : EnumAttr<"uwtable", [FnAttr]>;
276+
def UWTable : IntAttr<"uwtable", [FnAttr]>;
277277

278278
/// Minimum/Maximum vscale value for function.
279279
def VScaleRange : IntAttr<"vscale_range", [FnAttr]>;

llvm/include/llvm/IR/Function.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -623,15 +623,19 @@ class LLVM_EXTERNAL_VISIBILITY Function : public GlobalObject,
623623
bool willReturn() const { return hasFnAttribute(Attribute::WillReturn); }
624624
void setWillReturn() { addFnAttr(Attribute::WillReturn); }
625625

626+
/// Get what kind of unwind table entry to generate for this function.
627+
UWTableKind getUWTableKind() const {
628+
return AttributeSets.getUWTableKind();
629+
}
630+
626631
/// True if the ABI mandates (or the user requested) that this
627632
/// function be in a unwind table.
628633
bool hasUWTable() const {
629-
return hasFnAttribute(Attribute::UWTable);
634+
return getUWTableKind() != UWTableKind::None;
630635
}
631-
void setHasUWTable() {
632-
addFnAttr(Attribute::UWTable);
636+
void setUWTableKind(UWTableKind K) {
637+
addFnAttr(Attribute::getWithUWTableKind(getContext(), K));
633638
}
634-
635639
/// True if this function needs an unwind table.
636640
bool needsUnwindTableEntry() const {
637641
return hasUWTable() || !doesNotThrow() || hasPersonalityFn();

llvm/include/llvm/IR/Module.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -888,8 +888,8 @@ class LLVM_EXTERNAL_VISIBILITY Module {
888888
void setRtLibUseGOT();
889889

890890
/// Get/set whether synthesized functions should get the uwtable attribute.
891-
bool getUwtable() const;
892-
void setUwtable();
891+
UWTableKind getUwtable() const;
892+
void setUwtable(UWTableKind Kind);
893893

894894
/// Get/set whether synthesized functions should get the "frame-pointer"
895895
/// attribute.

llvm/include/llvm/Support/CodeGen.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,12 @@ namespace llvm {
9797
};
9898
} // namespace ZeroCallUsedRegs
9999

100-
} // end llvm namespace
100+
enum class UWTableKind {
101+
None = 0, ///< No unwind table requested
102+
Sync = 1, ///< "Synchronous" unwind tables
103+
Async = 2, ///< "Asynchronous" unwind tables (instr precise)
104+
Default = 2,
105+
};
106+
} // namespace llvm
101107

102108
#endif

llvm/lib/AsmParser/LLLexer.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,8 @@ lltok::Kind LLLexer::LexIdentifier() {
708708
KEYWORD(immarg);
709709
KEYWORD(byref);
710710
KEYWORD(mustprogress);
711+
KEYWORD(sync);
712+
KEYWORD(async);
711713

712714
KEYWORD(type);
713715
KEYWORD(opaque);

llvm/lib/AsmParser/LLParser.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1333,6 +1333,13 @@ bool LLParser::parseEnumAttribute(Attribute::AttrKind Attr, AttrBuilder &B,
13331333
B.addDereferenceableOrNullAttr(Bytes);
13341334
return false;
13351335
}
1336+
case Attribute::UWTable: {
1337+
UWTableKind Kind;
1338+
if (parseOptionalUWTableKind(Kind))
1339+
return true;
1340+
B.addUWTableAttr(Kind);
1341+
return false;
1342+
}
13361343
default:
13371344
B.addAttribute(Attr);
13381345
Lex.Lex();
@@ -1996,6 +2003,22 @@ bool LLParser::parseOptionalDerefAttrBytes(lltok::Kind AttrKind,
19962003
return false;
19972004
}
19982005

2006+
bool LLParser::parseOptionalUWTableKind(UWTableKind &Kind) {
2007+
Lex.Lex();
2008+
Kind = UWTableKind::Default;
2009+
if (!EatIfPresent(lltok::lparen))
2010+
return false;
2011+
LocTy KindLoc = Lex.getLoc();
2012+
if (Lex.getKind() == lltok::kw_sync)
2013+
Kind = UWTableKind::Sync;
2014+
else if (Lex.getKind() == lltok::kw_async)
2015+
Kind = UWTableKind::Async;
2016+
else
2017+
return error(KindLoc, "expected unwind table kind");
2018+
Lex.Lex();
2019+
return parseToken(lltok::rparen, "expected ')'");
2020+
}
2021+
19992022
/// parseOptionalCommaAlign
20002023
/// ::=
20012024
/// ::= ',' align 4

llvm/lib/Bitcode/Reader/BitcodeReader.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1628,6 +1628,8 @@ Error BitcodeReader::parseAttributeGroupBlock() {
16281628
B.addStructRetAttr(nullptr);
16291629
else if (Kind == Attribute::InAlloca)
16301630
B.addInAllocaAttr(nullptr);
1631+
else if (Kind == Attribute::UWTable)
1632+
B.addUWTableAttr(UWTableKind::Default);
16311633
else if (Attribute::isEnumAttrKind(Kind))
16321634
B.addAttribute(Kind);
16331635
else
@@ -1650,6 +1652,8 @@ Error BitcodeReader::parseAttributeGroupBlock() {
16501652
B.addAllocSizeAttrFromRawRepr(Record[++i]);
16511653
else if (Kind == Attribute::VScaleRange)
16521654
B.addVScaleRangeAttrFromRawRepr(Record[++i]);
1655+
else if (Kind == Attribute::UWTable)
1656+
B.addUWTableAttr(UWTableKind(Record[++i]));
16531657
} else if (Record[i] == 3 || Record[i] == 4) { // String attribute
16541658
bool HasValue = (Record[i++] == 4);
16551659
SmallString<64> KindStr;

llvm/lib/CodeGen/MachineOutliner.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,15 @@ MachineFunction *MachineOutliner::createOutlinedFunction(
623623

624624
TII.mergeOutliningCandidateAttributes(*F, OF.Candidates);
625625

626+
// Set uwtable, so we generate eh_frame.
627+
UWTableKind UW = std::accumulate(
628+
OF.Candidates.cbegin(), OF.Candidates.cend(), UWTableKind::None,
629+
[](UWTableKind K, const outliner::Candidate &C) {
630+
return std::max(K, C.getMF()->getFunction().getUWTableKind());
631+
});
632+
if (UW != UWTableKind::None)
633+
F->setUWTableKind(UW);
634+
626635
BasicBlock *EntryBB = BasicBlock::Create(C, "entry", F);
627636
IRBuilder<> Builder(EntryBB);
628637
Builder.CreateRetVoid();

llvm/lib/IR/AttributeImpl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ class AttributeSetNode final
255255
std::pair<unsigned, Optional<unsigned>> getAllocSizeArgs() const;
256256
unsigned getVScaleRangeMin() const;
257257
Optional<unsigned> getVScaleRangeMax() const;
258+
UWTableKind getUWTableKind() const;
258259
std::string getAsString(bool InAttrGrp) const;
259260
Type *getAttributeType(Attribute::AttrKind Kind) const;
260261

0 commit comments

Comments
 (0)