Skip to content

Commit e8d9c75

Browse files
committed
New "reverse C" calling convention in LLVM and Clang.
Test case: #define PARAMS \ const char *ptr, long p2, \ long p3, long p4, long p5, long p6 #define ARGS ptr, p2, p3, p4, p5, p6 #define UNLIKELY(x) \ __builtin_expect(x, 0) #if __has_attribute(reverse_call) #define CC __attribute__((reverse_call)) #else #define CC #endif CC const char *Next(PARAMS); const char *Fallback(PARAMS); CC const char *Parse(PARAMS) { if (UNLIKELY(!ptr)) { // This ruins everything. ptr = Fallback(ARGS); } ptr++; __attribute__((musttail)) return Next(ARGS); } Before (existing calling convention): 0000000000000000 <Parse>: 0: 41 57 push r15 2: 41 56 push r14 4: 41 55 push r13 6: 41 54 push r12 8: 53 push rbx 9: 4d 89 ce mov r14,r9 c: 4d 89 c7 mov r15,r8 f: 49 89 cc mov r12,rcx 12: 49 89 d5 mov r13,rdx 15: 48 89 f3 mov rbx,rsi 18: 48 85 ff test rdi,rdi 1b: 74 21 je 3e <Parse+0x3e> 1d: 48 83 c7 01 add rdi,0x1 21: 48 89 de mov rsi,rbx 24: 4c 89 ea mov rdx,r13 27: 4c 89 e1 mov rcx,r12 2a: 4d 89 f8 mov r8,r15 2d: 4d 89 f1 mov r9,r14 30: 5b pop rbx 31: 41 5c pop r12 33: 41 5d pop r13 35: 41 5e pop r14 37: 41 5f pop r15 39: e9 00 00 00 00 jmp 3e <Parse+0x3e> 3a: R_X86_64_PLT32 Next-0x4 3e: 31 ff xor edi,edi 40: 48 89 de mov rsi,rbx 43: 4c 89 ea mov rdx,r13 46: 4c 89 e1 mov rcx,r12 49: 4d 89 f8 mov r8,r15 4c: 4d 89 f1 mov r9,r14 4f: e8 00 00 00 00 call 54 <Parse+0x54> 50: R_X86_64_PLT32 Fallback-0x4 54: 48 89 c7 mov rdi,rax 57: eb c4 jmp 1d <Parse+0x1d> After (new reverse_call calling convention): 0000000000000000 <Parse>: 0: 48 85 db test rbx,rbx 3: 74 09 je e <Parse+0xe> 5: 48 83 c3 01 add rbx,0x1 9: e9 00 00 00 00 jmp e <Parse+0xe> a: R_X86_64_PLT32 Next-0x4 e: 50 push rax f: 31 ff xor edi,edi 11: 48 89 ee mov rsi,rbp 14: 4c 89 e2 mov rdx,r12 17: 4c 89 e9 mov rcx,r13 1a: 4d 89 f0 mov r8,r14 1d: 4d 89 f9 mov r9,r15 20: e8 00 00 00 00 call 25 <Parse+0x25> 21: R_X86_64_PLT32 Fallback-0x4 25: 48 89 c3 mov rbx,rax 28: 48 83 c4 08 add rsp,0x8 2c: 48 83 c3 01 add rbx,0x1 30: e9 00 00 00 00 jmp 35 <Parse+0x35> The fast path has gone from 24 instructions (including 5 spills) to 4 instructions (0 spills).
1 parent 0a2708d commit e8d9c75

File tree

20 files changed

+102
-1
lines changed

20 files changed

+102
-1
lines changed

clang/include/clang-c/Index.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3424,6 +3424,7 @@ enum CXCallingConv {
34243424
CXCallingConv_PreserveAll = 15,
34253425
CXCallingConv_AArch64VectorCall = 16,
34263426
CXCallingConv_SwiftAsync = 17,
3427+
CXCallingConv_ReverseCall = 18,
34273428

34283429
CXCallingConv_Invalid = 100,
34293430
CXCallingConv_Unexposed = 200

clang/include/clang/Basic/Attr.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2567,6 +2567,11 @@ def PreserveMost : DeclOrTypeAttr {
25672567
let Documentation = [PreserveMostDocs];
25682568
}
25692569

2570+
def ReverseCall : DeclOrTypeAttr {
2571+
let Spellings = [Clang<"reverse_call">];
2572+
let Documentation = [ReverseCallDocs];
2573+
}
2574+
25702575
def PreserveAll : DeclOrTypeAttr {
25712576
let Spellings = [Clang<"preserve_all">];
25722577
let Documentation = [PreserveAllDocs];

clang/include/clang/Basic/AttrDocs.td

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4864,6 +4864,20 @@ in the future.
48644864
}];
48654865
}
48664866

4867+
def ReverseCallDocs : Documentation {
4868+
let Category = DocCatCallingConvs;
4869+
let Content = [{
4870+
This calling convention makes all registers available for
4871+
passing arguments, but assigns them in reverse order from the default calling
4872+
convention to reduce the chance of overlap. There are no callee-saved
4873+
registers, and the registers that are callee-save under ``ccc`` are the first
4874+
to be assigned as arguments. This makes it very efficient to perform a series
4875+
of tail calls to other ``reverse_call`` functions in threaded code style, while
4876+
reducing the chance of spills or register shuffles when performing non-tail
4877+
calls to regular fallback functions.
4878+
}];
4879+
}
4880+
48674881
def PreserveAllDocs : Documentation {
48684882
let Category = DocCatCallingConvs;
48694883
let Content = [{

clang/include/clang/Basic/Specifiers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@ namespace clang {
280280
CC_PreserveMost, // __attribute__((preserve_most))
281281
CC_PreserveAll, // __attribute__((preserve_all))
282282
CC_AArch64VectorCall, // __attribute__((aarch64_vector_pcs))
283+
CC_ReverseCall, // __attribute__((reverse_call))
283284
};
284285

285286
/// 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
@@ -3098,6 +3098,7 @@ StringRef CXXNameMangler::getCallingConvQualifierName(CallingConv CC) {
30983098
case CC_OpenCLKernel:
30993099
case CC_PreserveMost:
31003100
case CC_PreserveAll:
3101+
case CC_ReverseCall:
31013102
// FIXME: we should be mangling all of the above.
31023103
return "";
31033104

clang/lib/AST/Type.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3156,6 +3156,7 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) {
31563156
case CC_SwiftAsync: return "swiftasynccall";
31573157
case CC_PreserveMost: return "preserve_most";
31583158
case CC_PreserveAll: return "preserve_all";
3159+
case CC_ReverseCall: return "reverse_call";
31593160
}
31603161

31613162
llvm_unreachable("Invalid calling convention.");

clang/lib/AST/TypePrinter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -983,6 +983,9 @@ void TypePrinter::printFunctionAfter(const FunctionType::ExtInfo &Info,
983983
case CC_PreserveMost:
984984
OS << " __attribute__((preserve_most))";
985985
break;
986+
case CC_ReverseCall:
987+
OS << " __attribute__((reverse_call))";
988+
break;
986989
case CC_PreserveAll:
987990
OS << " __attribute__((preserve_all))";
988991
break;
@@ -1718,6 +1721,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
17181721
case attr::MSABI: OS << "ms_abi"; break;
17191722
case attr::SysVABI: OS << "sysv_abi"; break;
17201723
case attr::RegCall: OS << "regcall"; break;
1724+
case attr::ReverseCall: OS << "reverse_call"; break;
17211725
case attr::Pcs: {
17221726
OS << "pcs(";
17231727
QualType t = T->getEquivalentType();

clang/lib/Basic/Targets/X86.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,7 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
358358
case CC_X86Pascal:
359359
case CC_IntelOclBicc:
360360
case CC_OpenCLKernel:
361+
case CC_ReverseCall:
361362
return CCCR_OK;
362363
case CC_SwiftAsync:
363364
return CCCR_Error;
@@ -729,6 +730,7 @@ class LLVM_LIBRARY_VISIBILITY X86_64TargetInfo : public X86TargetInfo {
729730
case CC_PreserveAll:
730731
case CC_X86RegCall:
731732
case CC_OpenCLKernel:
733+
case CC_ReverseCall:
732734
return CCCR_OK;
733735
default:
734736
return CCCR_Warning;
@@ -806,6 +808,7 @@ class LLVM_LIBRARY_VISIBILITY WindowsX86_64TargetInfo
806808
case CC_SwiftAsync:
807809
case CC_X86RegCall:
808810
case CC_OpenCLKernel:
811+
case CC_ReverseCall:
809812
return CCCR_OK;
810813
default:
811814
return CCCR_Warning;

clang/lib/CodeGen/CGCall.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ unsigned CodeGenTypes::ClangCallConvToLLVMCallConv(CallingConv CC) {
6767
case CC_PreserveAll: return llvm::CallingConv::PreserveAll;
6868
case CC_Swift: return llvm::CallingConv::Swift;
6969
case CC_SwiftAsync: return llvm::CallingConv::SwiftTail;
70+
case CC_ReverseCall: return llvm::CallingConv::ReverseC;
7071
}
7172
}
7273

@@ -242,6 +243,9 @@ static CallingConv getCallingConventionForDecl(const ObjCMethodDecl *D,
242243
if (D->hasAttr<PreserveAllAttr>())
243244
return CC_PreserveAll;
244245

246+
if (D->hasAttr<ReverseCallAttr>())
247+
return CC_ReverseCall;
248+
245249
return CC_C;
246250
}
247251

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4742,6 +4742,9 @@ static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
47424742
case ParsedAttr::AT_PreserveAll:
47434743
D->addAttr(::new (S.Context) PreserveAllAttr(S.Context, AL));
47444744
return;
4745+
case ParsedAttr::AT_ReverseCall:
4746+
D->addAttr(::new (S.Context) ReverseCallAttr(S.Context, AL));
4747+
return;
47454748
default:
47464749
llvm_unreachable("unexpected attribute kind");
47474750
}
@@ -4913,6 +4916,9 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC,
49134916
case ParsedAttr::AT_PreserveAll:
49144917
CC = CC_PreserveAll;
49154918
break;
4919+
case ParsedAttr::AT_ReverseCall:
4920+
CC = CC_ReverseCall;
4921+
break;
49164922
default: llvm_unreachable("unexpected attribute kind");
49174923
}
49184924

@@ -8290,6 +8296,7 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
82908296
case ParsedAttr::AT_PreserveMost:
82918297
case ParsedAttr::AT_PreserveAll:
82928298
case ParsedAttr::AT_AArch64VectorPcs:
8299+
case ParsedAttr::AT_ReverseCall:
82938300
handleCallConvAttr(S, D, AL);
82948301
break;
82958302
case ParsedAttr::AT_Suppress:

0 commit comments

Comments
 (0)