Implement Thiscall CC

This commit is contained in:
LemonBoy 2019-12-29 19:34:54 +01:00
parent 08a26fea09
commit 0ccac79c8e
7 changed files with 30 additions and 14 deletions

View File

@ -104,6 +104,7 @@ pub const CallingConvention = enum {
Stdcall,
Fastcall,
Vectorcall,
Thiscall,
APCS,
AAPCS,
AAPCSVFP,

View File

@ -3975,6 +3975,7 @@ fn transCC(
.X86StdCall => return CallingConvention.Stdcall,
.X86FastCall => return CallingConvention.Fastcall,
.X86VectorCall, .AArch64VectorCall => return CallingConvention.Vectorcall,
.X86ThisCall => return CallingConvention.Thiscall,
.AAPCS => return CallingConvention.AAPCS,
.AAPCS_VFP => return CallingConvention.AAPCSVFP,
else => return revertAndWarn(

View File

@ -68,6 +68,7 @@ enum CallingConvention {
CallingConventionStdcall,
CallingConventionFastcall,
CallingConventionVectorcall,
CallingConventionThiscall,
CallingConventionAPCS,
CallingConventionAAPCS,
CallingConventionAAPCSVFP,

View File

@ -929,6 +929,7 @@ const char *calling_convention_name(CallingConvention cc) {
case CallingConventionStdcall: return "Stdcall";
case CallingConventionFastcall: return "Fastcall";
case CallingConventionVectorcall: return "Vectorcall";
case CallingConventionThiscall: return "Thiscall";
case CallingConventionAPCS: return "Apcs";
case CallingConventionAAPCS: return "Aapcs";
case CallingConventionAAPCSVFP: return "Aapcsvfp";
@ -949,6 +950,7 @@ bool calling_convention_allows_zig_types(CallingConvention cc) {
case CallingConventionStdcall:
case CallingConventionFastcall:
case CallingConventionVectorcall:
case CallingConventionThiscall:
case CallingConventionAPCS:
case CallingConventionAAPCS:
case CallingConventionAAPCSVFP:
@ -1706,9 +1708,7 @@ Error type_allowed_in_extern(CodeGen *g, ZigType *type_entry, bool *result) {
case ZigTypeIdArray:
return type_allowed_in_extern(g, type_entry->data.array.child_type, result);
case ZigTypeIdFn:
*result = type_entry->data.fn.fn_type_id.cc == CallingConventionC ||
type_entry->data.fn.fn_type_id.cc == CallingConventionStdcall ||
type_entry->data.fn.fn_type_id.cc == CallingConventionAAPCS;
*result = !calling_convention_allows_zig_types(type_entry->data.fn.fn_type_id.cc);
return ErrorNone;
case ZigTypeIdPointer:
if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown)))
@ -3445,24 +3445,21 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
fn_table_entry->cc = (CallingConvention)bigint_as_u32(&result_val->data.x_enum_tag);
}
fn_table_entry->type_entry = analyze_fn_type(g, source_node, child_scope, fn_table_entry);
if (fn_proto->section_expr != nullptr) {
if (!analyze_const_string(g, child_scope, fn_proto->section_expr, &fn_table_entry->section_name)) {
fn_table_entry->type_entry = g->builtin_types.entry_invalid;
tld_fn->base.resolution = TldResolutionInvalid;
return;
}
}
if (fn_table_entry->type_entry->id == ZigTypeIdInvalid) {
fn_table_entry->type_entry = analyze_fn_type(g, source_node, child_scope, fn_table_entry);
if (type_is_invalid(fn_table_entry->type_entry)) {
tld_fn->base.resolution = TldResolutionInvalid;
return;
}
if (!fn_table_entry->type_entry->data.fn.is_generic) {
if (fn_def_node)
g->fn_defs.append(fn_table_entry);
}
const CallingConvention fn_cc = fn_table_entry->type_entry->data.fn.fn_type_id.cc;
if (fn_proto->is_export) {
@ -3470,6 +3467,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
case CallingConventionAsync:
add_node_error(g, fn_def_node,
buf_sprintf("exported function cannot be async"));
fn_table_entry->type_entry = g->builtin_types.entry_invalid;
tld_fn->base.resolution = TldResolutionInvalid;
return;
case CallingConventionC:
@ -3480,6 +3478,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
case CallingConventionStdcall:
case CallingConventionFastcall:
case CallingConventionVectorcall:
case CallingConventionThiscall:
case CallingConventionAPCS:
case CallingConventionAAPCS:
case CallingConventionAAPCSVFP:
@ -3495,6 +3494,11 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
}
}
if (!fn_table_entry->type_entry->data.fn.is_generic) {
if (fn_def_node)
g->fn_defs.append(fn_table_entry);
}
// if the calling convention implies that it cannot be async, we save that for later
// and leave the value to be nullptr to indicate that we have not emitted possible
// compile errors for improperly calling async functions.

View File

@ -301,6 +301,10 @@ static LLVMCallConv get_llvm_cc(CodeGen *g, CallingConvention cc) {
return LLVMAARCH64VectorCallCallConv;
#endif
return LLVMCCallConv;
case CallingConventionThiscall:
if (g->zig_target->arch == ZigLLVM_x86)
return LLVMX86ThisCallCallConv;
return LLVMCCallConv;
case CallingConventionAsync:
return LLVMFastCallConv;
case CallingConventionAPCS:
@ -424,6 +428,7 @@ static bool cc_want_sret_attr(CallingConvention cc) {
case CallingConventionStdcall:
case CallingConventionFastcall:
case CallingConventionVectorcall:
case CallingConventionThiscall:
case CallingConventionAPCS:
case CallingConventionAAPCS:
case CallingConventionAAPCSVFP:
@ -8512,9 +8517,10 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
static_assert(CallingConventionStdcall == 7, "");
static_assert(CallingConventionFastcall == 8, "");
static_assert(CallingConventionVectorcall == 9, "");
static_assert(CallingConventionAPCS == 10, "");
static_assert(CallingConventionAAPCS == 11, "");
static_assert(CallingConventionAAPCSVFP == 12, "");
static_assert(CallingConventionThiscall == 10, "");
static_assert(CallingConventionAPCS == 11, "");
static_assert(CallingConventionAAPCS == 12, "");
static_assert(CallingConventionAAPCSVFP == 13, "");
static_assert(FnInlineAuto == 0, "");
static_assert(FnInlineAlways == 1, "");

View File

@ -16752,6 +16752,7 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
case CallingConventionStdcall:
case CallingConventionFastcall:
case CallingConventionVectorcall:
case CallingConventionThiscall:
case CallingConventionAPCS:
case CallingConventionAAPCS:
case CallingConventionAAPCSVFP:

View File

@ -850,11 +850,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\void __attribute__((stdcall)) foo2(float *a);
\\void __attribute__((vectorcall)) foo3(float *a);
\\void __attribute__((cdecl)) foo4(float *a);
\\void __attribute__((thiscall)) foo5(float *a);
, &[_][]const u8{
\\pub fn foo1(a: [*c]f32) callconv(.Fastcall) void;
\\pub fn foo2(a: [*c]f32) callconv(.Stdcall) void;
\\pub fn foo3(a: [*c]f32) callconv(.Vectorcall) void;
\\pub extern fn foo4(a: [*c]f32) void;
\\pub fn foo5(a: [*c]f32) callconv(.Thiscall) void;
});
cases.addWithTarget("Calling convention", tests.Target{