From 0ccac79c8ebc1ed56dbdab068076a86924a015bc Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sun, 29 Dec 2019 19:34:54 +0100 Subject: [PATCH] Implement Thiscall CC --- lib/std/builtin.zig | 1 + src-self-hosted/translate_c.zig | 1 + src/all_types.hpp | 1 + src/analyze.cpp | 26 +++++++++++++++----------- src/codegen.cpp | 12 +++++++++--- src/ir.cpp | 1 + test/translate_c.zig | 2 ++ 7 files changed, 30 insertions(+), 14 deletions(-) diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 87b95786ec..9b3be8f424 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -104,6 +104,7 @@ pub const CallingConvention = enum { Stdcall, Fastcall, Vectorcall, + Thiscall, APCS, AAPCS, AAPCSVFP, diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 194217a600..1323c1a86d 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -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( diff --git a/src/all_types.hpp b/src/all_types.hpp index b2c3712f50..9ce29b6873 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -68,6 +68,7 @@ enum CallingConvention { CallingConventionStdcall, CallingConventionFastcall, CallingConventionVectorcall, + CallingConventionThiscall, CallingConventionAPCS, CallingConventionAAPCS, CallingConventionAAPCSVFP, diff --git a/src/analyze.cpp b/src/analyze.cpp index 9a4b1449b6..b71d3322a1 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -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. diff --git a/src/codegen.cpp b/src/codegen.cpp index b83767f9d6..23a9103877 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -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, ""); diff --git a/src/ir.cpp b/src/ir.cpp index da402887c4..de84852f59 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -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: diff --git a/test/translate_c.zig b/test/translate_c.zig index 78793b01cd..ceeff0c91e 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -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{