Commit 0ccac79c8e

LemonBoy <thatlemon@gmail.com>
2019-12-29 19:34:54
Implement Thiscall CC
1 parent 08a26fe
lib/std/builtin.zig
@@ -104,6 +104,7 @@ pub const CallingConvention = enum {
     Stdcall,
     Fastcall,
     Vectorcall,
+    Thiscall,
     APCS,
     AAPCS,
     AAPCSVFP,
src/all_types.hpp
@@ -68,6 +68,7 @@ enum CallingConvention {
     CallingConventionStdcall,
     CallingConventionFastcall,
     CallingConventionVectorcall,
+    CallingConventionThiscall,
     CallingConventionAPCS,
     CallingConventionAAPCS,
     CallingConventionAAPCSVFP,
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.
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, "");
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:
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(
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{