Skip to content

Commit c166a43

Browse files
authored
New calling convention preserve_none (#76868)
The new experimental calling convention preserve_none is the opposite side of existing preserve_all. It tries to preserve as few general registers as possible. So all general registers are caller saved registers. It can also uses more general registers to pass arguments. This attribute doesn't impact floating-point registers. Floating-point registers still follow the c calling convention. Currently preserve_none is supported on X86-64 only. It changes the c calling convention in following fields: * RSP and RBP are the only preserved general registers, all other general registers are caller saved registers. * We can use [RDI, RSI, RDX, RCX, R8, R9, R11, R12, R13, R14, R15, RAX] to pass arguments. It can improve the performance of hot tailcall chain, because many callee saved registers' save/restore instructions can be removed if the tail functions are using preserve_none. In my experiment in protocol buffer, the parsing functions are improved by 3% to 10%.
1 parent 7670609 commit c166a43

38 files changed

+635
-3
lines changed

clang/include/clang-c/Index.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2986,6 +2986,7 @@ enum CXCallingConv {
29862986
CXCallingConv_SwiftAsync = 17,
29872987
CXCallingConv_AArch64SVEPCS = 18,
29882988
CXCallingConv_M68kRTD = 19,
2989+
CXCallingConv_PreserveNone = 20,
29892990

29902991
CXCallingConv_Invalid = 100,
29912992
CXCallingConv_Unexposed = 200

clang/include/clang/Basic/Attr.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2959,6 +2959,12 @@ def M68kRTD: DeclOrTypeAttr {
29592959
let Documentation = [M68kRTDDocs];
29602960
}
29612961

2962+
def PreserveNone : DeclOrTypeAttr, TargetSpecificAttr<TargetAnyX86> {
2963+
let Spellings = [Clang<"preserve_none">];
2964+
let Subjects = SubjectList<[FunctionLike]>;
2965+
let Documentation = [PreserveNoneDocs];
2966+
}
2967+
29622968
def Target : InheritableAttr {
29632969
let Spellings = [GCC<"target">];
29642970
let Args = [StringArgument<"featuresStr">];

clang/include/clang/Basic/AttrDocs.td

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5506,6 +5506,23 @@ experimental at this time.
55065506
}];
55075507
}
55085508

5509+
def PreserveNoneDocs : Documentation {
5510+
let Category = DocCatCallingConvs;
5511+
let Content = [{
5512+
On X86-64 target, this attribute changes the calling convention of a function.
5513+
The ``preserve_none`` calling convention tries to preserve as few general
5514+
registers as possible. So all general registers are caller saved registers. It
5515+
also uses more general registers to pass arguments. This attribute doesn't
5516+
impact floating-point registers (XMMs/YMMs). Floating-point registers still
5517+
follow the c calling convention.
5518+
5519+
- Only RSP and RBP are preserved by callee.
5520+
5521+
- Register RDI, RSI, RDX, RCX, R8, R9, R11, R12, R13, R14, R15 and RAX now can
5522+
be used to pass function arguments.
5523+
}];
5524+
}
5525+
55095526
def DeprecatedDocs : Documentation {
55105527
let Category = DocCatDecl;
55115528
let Content = [{

clang/include/clang/Basic/Specifiers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ namespace clang {
295295
CC_AArch64SVEPCS, // __attribute__((aarch64_sve_pcs))
296296
CC_AMDGPUKernelCall, // __attribute__((amdgpu_kernel))
297297
CC_M68kRTD, // __attribute__((m68k_rtd))
298+
CC_PreserveNone, // __attribute__((preserve_none))
298299
};
299300

300301
/// Checks whether the given calling convention supports variadic

clang/lib/AST/ItaniumMangle.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3443,6 +3443,7 @@ StringRef CXXNameMangler::getCallingConvQualifierName(CallingConv CC) {
34433443
case CC_PreserveMost:
34443444
case CC_PreserveAll:
34453445
case CC_M68kRTD:
3446+
case CC_PreserveNone:
34463447
// FIXME: we should be mangling all of the above.
34473448
return "";
34483449

clang/lib/AST/Type.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3438,6 +3438,7 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) {
34383438
case CC_PreserveMost: return "preserve_most";
34393439
case CC_PreserveAll: return "preserve_all";
34403440
case CC_M68kRTD: return "m68k_rtd";
3441+
case CC_PreserveNone: return "preserve_none";
34413442
}
34423443

34433444
llvm_unreachable("Invalid calling convention.");
@@ -3990,6 +3991,7 @@ bool AttributedType::isCallingConv() const {
39903991
case attr::PreserveMost:
39913992
case attr::PreserveAll:
39923993
case attr::M68kRTD:
3994+
case attr::PreserveNone:
39933995
return true;
39943996
}
39953997
llvm_unreachable("invalid attr kind");

clang/lib/AST/TypePrinter.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1067,6 +1067,9 @@ void TypePrinter::printFunctionAfter(const FunctionType::ExtInfo &Info,
10671067
case CC_M68kRTD:
10681068
OS << " __attribute__((m68k_rtd))";
10691069
break;
1070+
case CC_PreserveNone:
1071+
OS << " __attribute__((preserve_none))";
1072+
break;
10701073
}
10711074
}
10721075

@@ -1911,6 +1914,9 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
19111914
case attr::M68kRTD:
19121915
OS << "m68k_rtd";
19131916
break;
1917+
case attr::PreserveNone:
1918+
OS << "preserve_none";
1919+
break;
19141920
case attr::NoDeref:
19151921
OS << "noderef";
19161922
break;

clang/lib/Basic/Targets/X86.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,7 @@ class LLVM_LIBRARY_VISIBILITY X86_64TargetInfo : public X86TargetInfo {
777777
case CC_Win64:
778778
case CC_PreserveMost:
779779
case CC_PreserveAll:
780+
case CC_PreserveNone:
780781
case CC_X86RegCall:
781782
case CC_OpenCLKernel:
782783
return CCCR_OK;
@@ -854,6 +855,7 @@ class LLVM_LIBRARY_VISIBILITY WindowsX86_64TargetInfo
854855
case CC_IntelOclBicc:
855856
case CC_PreserveMost:
856857
case CC_PreserveAll:
858+
case CC_PreserveNone:
857859
case CC_X86_64SysV:
858860
case CC_Swift:
859861
case CC_SwiftAsync:

clang/lib/CodeGen/CGCall.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ unsigned CodeGenTypes::ClangCallConvToLLVMCallConv(CallingConv CC) {
7373
case CC_Swift: return llvm::CallingConv::Swift;
7474
case CC_SwiftAsync: return llvm::CallingConv::SwiftTail;
7575
case CC_M68kRTD: return llvm::CallingConv::M68k_RTD;
76+
case CC_PreserveNone: return llvm::CallingConv::PreserveNone;
7677
}
7778
}
7879

@@ -256,6 +257,9 @@ static CallingConv getCallingConventionForDecl(const ObjCMethodDecl *D,
256257
if (D->hasAttr<M68kRTDAttr>())
257258
return CC_M68kRTD;
258259

260+
if (D->hasAttr<PreserveNoneAttr>())
261+
return CC_PreserveNone;
262+
259263
return CC_C;
260264
}
261265

clang/lib/CodeGen/CGDebugInfo.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1450,6 +1450,8 @@ static unsigned getDwarfCC(CallingConv CC) {
14501450
return llvm::dwarf::DW_CC_LLVM_X86RegCall;
14511451
case CC_M68kRTD:
14521452
return llvm::dwarf::DW_CC_LLVM_M68kRTD;
1453+
case CC_PreserveNone:
1454+
return llvm::dwarf::DW_CC_LLVM_PreserveNone;
14531455
}
14541456
return 0;
14551457
}

0 commit comments

Comments
 (0)