Browse Source

Handle calling conventions correctly

Ginger Bill 8 years ago
parent
commit
d714bece47

+ 6 - 11
code/demo.odin

@@ -1,4 +1,4 @@
-import (
+import {
 	"atomic.odin";
 	"fmt.odin";
 	"hash.odin";
@@ -8,17 +8,12 @@ import (
 	"os.odin";
 	"sync.odin";
 	"utf8.odin";
-)
+	win32 "sys/windows.odin";
+}
 
 proc main() {
-	var x = proc() -> int {
-		proc print_here() {
-			fmt.println("Here");
-		}
-
-		print_here();
-		return 1;
-	};
-	fmt.println(x());
+	var x = ~(0 as u32);
+	var y = x << 32;
+	fmt.println(y);
 }
 

+ 8 - 8
core/_preload.odin

@@ -1,10 +1,10 @@
 #shared_global_scope;
 
-import (
+import {
 	"os.odin";
 	"fmt.odin";
 	"mem.odin";
-)
+}
 
 // IMPORTANT NOTE(bill): `type_info` & `type_info_val` cannot be used within a
 // #shared_global_scope due to  the internals of the compiler.
@@ -14,7 +14,7 @@ import (
 
 // IMPORTANT NOTE(bill): Do not change the order of any of this data
 // The compiler relies upon this _exact_ order
-type (
+type {
 	Type_Info_Member struct #ordered {
 		name      string;     // can be empty if tuple
 		type_info ^Type_Info;
@@ -74,7 +74,7 @@ type (
 		Union     Type_Info_Record;
 		Raw_Union Type_Info_Record;
 	}
-)
+}
 
 proc type_info_base(info ^Type_Info) -> ^Type_Info {
 	if info == nil {
@@ -113,13 +113,13 @@ proc fmuladd64(a, b, c f64) -> f64 #foreign "llvm.fmuladd.f64"
 
 
 type Allocator_Mode u8;
-const (
+const {
 	ALLOCATOR_ALLOC Allocator_Mode = iota;
 	ALLOCATOR_FREE;
 	ALLOCATOR_FREE_ALL;
 	ALLOCATOR_RESIZE;
-);
-type (
+}
+type {
 	Allocator_Proc proc(allocator_data rawptr, mode Allocator_Mode,
 	                    size, alignment int,
 	                    old_memory rawptr, old_size int, flags u64) -> rawptr;
@@ -136,7 +136,7 @@ type (
 		user_data  rawptr;
 		user_index int;
 	}
-);
+}
 
 #thread_local var __context Context;
 

+ 2 - 2
core/fmt.odin

@@ -1,8 +1,8 @@
-import (
+import {
 	"os.odin";
 	"mem.odin";
 	"utf8.odin";
-)
+}
 
 const PRINT_BUF_SIZE = 1<<12;
 

+ 4 - 4
core/math.odin

@@ -1,4 +1,4 @@
-const (
+const {
 	TAU          = 6.28318530717958647692528676655900576;
 	PI           = 3.14159265358979323846264338327950288;
 	ONE_OVER_TAU = 0.636619772367581343075535053490057448;
@@ -16,9 +16,9 @@ const (
 
 	τ = TAU;
 	π = PI;
-)
+}
 
-type (
+type {
 	Vec2 [vector 2]f32;
 	Vec3 [vector 3]f32;
 	Vec4 [vector 4]f32;
@@ -26,7 +26,7 @@ type (
 	Mat2 [2]Vec2;
 	Mat3 [3]Vec3;
 	Mat4 [4]Vec4;
-)
+}
 
 proc sqrt32(x f32) -> f32 #foreign "llvm.sqrt.f32"
 proc sqrt64(x f64) -> f64 #foreign "llvm.sqrt.f64"

+ 4 - 4
core/mem.odin

@@ -1,7 +1,7 @@
-import (
+import {
 	"fmt.odin";
 	"os.odin";
-)
+}
 
 proc set(data rawptr, value i32, len int) -> rawptr #link_name "__mem_set" {
 	proc llvm_memset_64bit(dst rawptr, val byte, len int, align i32, is_volatile bool) #foreign "llvm.memset.p0i8.i64"
@@ -116,7 +116,7 @@ proc allocation_header(data rawptr) -> ^Allocation_Header {
 
 
 // Custom allocators
-type (
+type {
 	Arena struct {
 		backing    Allocator;
 		memory     []byte;
@@ -127,7 +127,7 @@ type (
 		arena          ^Arena;
 		original_count int;
 	}
-)
+}
 
 
 

+ 61 - 61
core/opengl.odin

@@ -32,7 +32,7 @@ proc GetIntegerv(name i32, v ^i32) #foreign "glGetIntegerv"
 
 var _libgl = win32.LoadLibraryA(("opengl32.dll\x00" as string).data);
 
-proc GetProcAddress(name string) -> proc() {
+proc GetProcAddress(name string) -> proc() #cc_c {
 	assert(name[name.count-1] == 0);
 	var res = win32.wglGetProcAddress(name.data);
 	if res == nil {
@@ -41,68 +41,68 @@ proc GetProcAddress(name string) -> proc() {
 	return res;
 }
 
-var (
-	GenBuffers      proc(count i32, buffers ^u32);
-	GenVertexArrays proc(count i32, buffers ^u32);
-	GenSamplers     proc(count i32, buffers ^u32);
-	BindBuffer      proc(target i32, buffer u32);
-	BindVertexArray proc(buffer u32);
-	BindSampler     proc(position i32, sampler u32);
-	BufferData      proc(target i32, size int, data rawptr, usage i32);
-	BufferSubData   proc(target i32, offset, size int, data rawptr);
-
-	DrawArrays      proc(mode, first i32, count u32);
-	DrawElements    proc(mode i32, count u32, type_ i32, indices rawptr);
-
-	MapBuffer       proc(target, access i32) -> rawptr;
-	UnmapBuffer     proc(target i32);
-
-	VertexAttribPointer proc(index u32, size, type_ i32, normalized i32, stride u32, pointer rawptr);
-	EnableVertexAttribArray proc(index u32);
-
-	CreateShader  proc(shader_type i32) -> u32;
-	ShaderSource  proc(shader u32, count u32, str ^^byte, length ^i32);
-	CompileShader proc(shader u32);
-	CreateProgram proc() -> u32;
-	AttachShader  proc(program, shader u32);
-	DetachShader  proc(program, shader u32);
-	DeleteShader  proc(shader u32);
-	LinkProgram   proc(program u32);
-	UseProgram    proc(program u32);
-	DeleteProgram proc(program u32);
-
-
-	GetShaderiv       proc(shader  u32, pname i32, params ^i32);
-	GetProgramiv      proc(program u32, pname i32, params ^i32);
-	GetShaderInfoLog  proc(shader  u32, max_length u32, length ^u32, info_long ^byte);
-	GetProgramInfoLog proc(program u32, max_length u32, length ^u32, info_long ^byte);
-
-	ActiveTexture  proc(texture i32);
-	GenerateMipmap proc(target i32);
-
-	SamplerParameteri    proc(sampler u32, pname i32, param i32);
-	SamplerParameterf    proc(sampler u32, pname i32, param f32);
-	SamplerParameteriv   proc(sampler u32, pname i32, params ^i32);
-	SamplerParameterfv   proc(sampler u32, pname i32, params ^f32);
-	SamplerParameterIiv  proc(sampler u32, pname i32, params ^i32);
-	SamplerParameterIuiv proc(sampler u32, pname i32, params ^u32);
-
-
-	Uniform1i        proc(loc i32, v0 i32);
-	Uniform2i        proc(loc i32, v0, v1 i32);
-	Uniform3i        proc(loc i32, v0, v1, v2 i32);
-	Uniform4i        proc(loc i32, v0, v1, v2, v3 i32);
-	Uniform1f        proc(loc i32, v0 f32);
-	Uniform2f        proc(loc i32, v0, v1 f32);
-	Uniform3f        proc(loc i32, v0, v1, v2 f32);
-	Uniform4f        proc(loc i32, v0, v1, v2, v3 f32);
-	UniformMatrix4fv proc(loc i32, count u32, transpose i32, value ^f32);
-
-	GetUniformLocation proc(program u32, name ^byte) -> i32;
-);
+var {
+	GenBuffers      proc(count i32, buffers ^u32) #cc_c;
+	GenVertexArrays proc(count i32, buffers ^u32) #cc_c;
+	GenSamplers     proc(count i32, buffers ^u32) #cc_c;
+	BindBuffer      proc(target i32, buffer u32) #cc_c;
+	BindVertexArray proc(buffer u32) #cc_c;
+	BindSampler     proc(position i32, sampler u32) #cc_c;
+	BufferData      proc(target i32, size int, data rawptr, usage i32) #cc_c;
+	BufferSubData   proc(target i32, offset, size int, data rawptr) #cc_c;
+
+	DrawArrays      proc(mode, first i32, count u32) #cc_c;
+	DrawElements    proc(mode i32, count u32, type_ i32, indices rawptr) #cc_c;
+
+	MapBuffer       proc(target, access i32) -> rawptr #cc_c;
+	UnmapBuffer     proc(target i32) #cc_c;
+
+	VertexAttribPointer proc(index u32, size, type_ i32, normalized i32, stride u32, pointer rawptr) #cc_c;
+	EnableVertexAttribArray proc(index u32) #cc_c;
+
+	CreateShader  proc(shader_type i32) -> u32 #cc_c;
+	ShaderSource  proc(shader u32, count u32, str ^^byte, length ^i32) #cc_c;
+	CompileShader proc(shader u32) #cc_c;
+	CreateProgram proc() -> u32 #cc_c;
+	AttachShader  proc(program, shader u32) #cc_c;
+	DetachShader  proc(program, shader u32) #cc_c;
+	DeleteShader  proc(shader u32) #cc_c;
+	LinkProgram   proc(program u32) #cc_c;
+	UseProgram    proc(program u32) #cc_c;
+	DeleteProgram proc(program u32) #cc_c;
+
+
+	GetShaderiv       proc(shader  u32, pname i32, params ^i32) #cc_c;
+	GetProgramiv      proc(program u32, pname i32, params ^i32) #cc_c;
+	GetShaderInfoLog  proc(shader  u32, max_length u32, length ^u32, info_long ^byte) #cc_c;
+	GetProgramInfoLog proc(program u32, max_length u32, length ^u32, info_long ^byte) #cc_c;
+
+	ActiveTexture  proc(texture i32) #cc_c;
+	GenerateMipmap proc(target i32) #cc_c;
+
+	SamplerParameteri    proc(sampler u32, pname i32, param i32) #cc_c;
+	SamplerParameterf    proc(sampler u32, pname i32, param f32) #cc_c;
+	SamplerParameteriv   proc(sampler u32, pname i32, params ^i32) #cc_c;
+	SamplerParameterfv   proc(sampler u32, pname i32, params ^f32) #cc_c;
+	SamplerParameterIiv  proc(sampler u32, pname i32, params ^i32) #cc_c;
+	SamplerParameterIuiv proc(sampler u32, pname i32, params ^u32) #cc_c;
+
+
+	Uniform1i        proc(loc i32, v0 i32) #cc_c;
+	Uniform2i        proc(loc i32, v0, v1 i32) #cc_c;
+	Uniform3i        proc(loc i32, v0, v1, v2 i32) #cc_c;
+	Uniform4i        proc(loc i32, v0, v1, v2, v3 i32) #cc_c;
+	Uniform1f        proc(loc i32, v0 f32) #cc_c;
+	Uniform2f        proc(loc i32, v0, v1 f32) #cc_c;
+	Uniform3f        proc(loc i32, v0, v1, v2 f32) #cc_c;
+	Uniform4f        proc(loc i32, v0, v1, v2, v3 f32) #cc_c;
+	UniformMatrix4fv proc(loc i32, count u32, transpose i32, value ^f32) #cc_c;
+
+	GetUniformLocation proc(program u32, name ^byte) -> i32 #cc_c;
+}
 
 proc init() {
-	proc set_proc_address(p rawptr, name string) #inline { (p as ^proc())^ = GetProcAddress(name); }
+	proc set_proc_address(p rawptr, name string) #inline { (p as ^(proc() #cc_c))^ = GetProcAddress(name); }
 
 	set_proc_address(^GenBuffers,      "glGenBuffers\x00");
 	set_proc_address(^GenVertexArrays, "glGenVertexArrays\x00");

+ 2 - 2
core/opengl_constants.odin

@@ -1,4 +1,4 @@
-const (
+const {
 	FALSE                          = 0;
 	TRUE                           = 1;
 
@@ -1382,4 +1382,4 @@ const (
 	DEBUG_SEVERITY_HIGH_ARB        = 0x9146;
 	DEBUG_SEVERITY_MEDIUM_ARB      = 0x9147;
 	DEBUG_SEVERITY_LOW_ARB         = 0x9148;
-);
+}

+ 8 - 8
core/os_windows.odin

@@ -1,9 +1,9 @@
-import (
+import {
 	win32 "sys/windows.odin";
 	"fmt.odin";
-)
+}
 
-type (
+type {
 	File_Time u64;
 
 	File_Handle raw_union {
@@ -15,7 +15,7 @@ type (
 		handle          File_Handle;
 		last_write_time File_Time;
 	}
-)
+}
 
 proc open(name string) -> (File, bool) {
 	using win32;
@@ -87,15 +87,15 @@ proc last_write_time_by_name(name string) -> File_Time {
 
 
 
-const (
+const {
 	FILE_STANDARD_INPUT = iota;
 	FILE_STANDARD_OUTPUT;
 	FILE_STANDARD_ERROR;
 
 	FILE_STANDARD_COUNT;
-)
+}
 // NOTE(bill): Uses startup to initialize it
-var (
+var {
 	__std_files = [FILE_STANDARD_COUNT]File{
 		{handle = win32.GetStdHandle(win32.STD_INPUT_HANDLE)  transmute File_Handle },
 		{handle = win32.GetStdHandle(win32.STD_OUTPUT_HANDLE) transmute File_Handle },
@@ -105,7 +105,7 @@ var (
 	stdin  = ^__std_files[FILE_STANDARD_INPUT];
 	stdout = ^__std_files[FILE_STANDARD_OUTPUT];
 	stderr = ^__std_files[FILE_STANDARD_ERROR];
-)
+}
 
 
 proc read_entire_file(name string) -> ([]byte, bool) {

+ 4 - 4
core/sync.odin

@@ -1,9 +1,9 @@
-import (
+import {
 	win32 "sys/windows.odin" when ODIN_OS == "windows";
 	"atomic.odin";
-)
+}
 
-type (
+type {
 	Semaphore struct {
 		handle win32.HANDLE;
 	}
@@ -14,7 +14,7 @@ type (
 		owner     i32;
 		recursion i32;
 	}
-)
+}
 
 proc current_thread_id() -> i32 {
 	return win32.GetCurrentThreadId() as i32;

+ 23 - 23
core/sys/windows.odin

@@ -1,7 +1,7 @@
 #foreign_system_library "user32" when ODIN_OS == "windows";
 #foreign_system_library "gdi32"  when ODIN_OS == "windows";
 
-type (
+type {
 	HANDLE    rawptr;
 	HWND      HANDLE;
 	HDC       HANDLE;
@@ -18,9 +18,9 @@ type (
 	ATOM      i16;
 	BOOL      i32;
 	WNDPROC   proc(hwnd HWND, msg u32, wparam WPARAM, lparam LPARAM) -> LRESULT;
-)
+}
 
-const (
+const {
 	INVALID_HANDLE_VALUE = (-1 as int) as HANDLE;
 
 	CS_VREDRAW    = 0x0001;
@@ -52,9 +52,9 @@ const (
 	SM_CYSCREEN = 1;
 
 	SW_SHOW = 5;
-)
+}
 
-type (
+type {
 	POINT struct #ordered {
 		x, y i32;
 	}
@@ -114,11 +114,11 @@ type (
 	}
 
 	GET_FILEEX_INFO_LEVELS i32;
-)
-const (
+}
+const {
 	GetFileExInfoStandard = 0 as GET_FILEEX_INFO_LEVELS;
 	GetFileExMaxInfoLevel = 1 as GET_FILEEX_INFO_LEVELS;
-)
+}
 
 proc GetLastError    () -> i32                           #foreign #dll_import
 proc ExitProcess     (exit_code u32)                    #foreign #dll_import
@@ -183,7 +183,7 @@ proc GetFileSizeEx             (file_handle HANDLE, file_size ^i64) -> BOOL #for
 proc GetFileAttributesExA      (filename ^u8, info_level_id GET_FILEEX_INFO_LEVELS, file_info rawptr) -> BOOL #foreign #dll_import
 proc GetFileInformationByHandle(file_handle HANDLE, file_info ^BY_HANDLE_FILE_INFORMATION) -> BOOL #foreign #dll_import
 
-const (
+const {
 	FILE_SHARE_READ      = 0x00000001;
 	FILE_SHARE_WRITE     = 0x00000002;
 	FILE_SHARE_DELETE    = 0x00000004;
@@ -201,7 +201,7 @@ const (
 	OPEN_EXISTING     = 3;
 	OPEN_ALWAYS       = 4;
 	TRUNCATE_EXISTING = 5;
-)
+}
 
 
 
@@ -248,7 +248,7 @@ proc ReadBarrier     () #foreign
 
 
 // GDI
-type (
+type {
 	BITMAPINFOHEADER struct #ordered {
 		size              u32;
 		width, height     i32;
@@ -269,13 +269,13 @@ type (
 	RGBQUAD struct #ordered {
 		blue, green, red, reserved byte;
 	}
-)
+}
 
-const (
+const {
 	BI_RGB         = 0;
 	DIB_RGB_COLORS = 0x00;
 	SRCCOPY        = 0x00cc0020 as u32;
-)
+}
 
 proc StretchDIBits(hdc HDC,
                    x_dst, y_dst, width_dst, height_dst i32,
@@ -295,7 +295,7 @@ proc GetClientRect(hwnd HWND, rect ^RECT) -> BOOL #foreign
 
 
 // Windows OpenGL
-const (
+const {
 	PFD_TYPE_RGBA             = 0;
 	PFD_TYPE_COLORINDEX       = 1;
 	PFD_MAIN_PLANE            = 0;
@@ -317,11 +317,11 @@ const (
 	PFD_DEPTH_DONTCARE        = 0x20000000;
 	PFD_DOUBLEBUFFER_DONTCARE = 0x40000000;
 	PFD_STEREO_DONTCARE       = 0x80000000;
-)
+}
 
-type (
+type {
 	HGLRC HANDLE;
-	PROC  proc();
+	PROC  proc() #cc_c;
 	wglCreateContextAttribsARBType proc(hdc HDC, hshareContext rawptr, attribList ^i32) -> HGLRC;
 
 
@@ -355,7 +355,7 @@ type (
 		visible_mask,
 		damage_mask u32;
 	}
-)
+}
 
 proc GetDC            (h HANDLE) -> HDC #foreign
 proc SetPixelFormat   (hdc HDC, pixel_format i32, pfd ^PIXELFORMATDESCRIPTOR ) -> BOOL #foreign #dll_import
@@ -363,13 +363,13 @@ proc ChoosePixelFormat(hdc HDC, pfd ^PIXELFORMATDESCRIPTOR) -> i32 #foreign #dll
 proc SwapBuffers      (hdc HDC) -> BOOL #foreign #dll_import
 proc ReleaseDC        (wnd HWND, hdc HDC) -> i32 #foreign #dll_import
 
-const (
+const {
 	WGL_CONTEXT_MAJOR_VERSION_ARB             = 0x2091;
 	WGL_CONTEXT_MINOR_VERSION_ARB             = 0x2092;
 	WGL_CONTEXT_PROFILE_MASK_ARB              = 0x9126;
 	WGL_CONTEXT_CORE_PROFILE_BIT_ARB          = 0x0001;
 	WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB = 0x0002;
-)
+}
 
 proc wglCreateContext (hdc HDC) -> HGLRC #foreign #dll_import
 proc wglMakeCurrent   (hdc HDC, hglrc HGLRC) -> BOOL #foreign #dll_import
@@ -383,7 +383,7 @@ proc GetAsyncKeyState(v_key i32) -> i16 #foreign #dll_import
 
 proc is_key_down(key i32) -> bool #inline { return GetAsyncKeyState(key) < 0; }
 
-const (
+const {
 	KEY_LBUTTON    = 0x01;
 	KEY_RBUTTON    = 0x02;
 	KEY_CANCEL     = 0x03;
@@ -535,5 +535,5 @@ const (
 	KEY_NONAME     = 0xFC;
 	KEY_PA1        = 0xFD;
 	KEY_OEM_CLEAR  = 0xFE;
-)
+}
 

+ 6 - 6
core/utf8.odin

@@ -1,4 +1,4 @@
-const (
+const {
 	RUNE_ERROR = '\ufffd';
 	RUNE_SELF  = 0x80;
 	RUNE_BOM   = 0xfeff;
@@ -8,13 +8,13 @@ const (
 
 	SURROGATE_MIN = 0xd800;
 	SURROGATE_MAX = 0xdfff;
-)
+}
 
 type Accept_Range struct {
 	lo, hi u8;
 }
 
-var (
+var {
 	accept_ranges = [5]Accept_Range{
 		{0x80, 0xbf},
 		{0xa0, 0xbf},
@@ -42,7 +42,7 @@ var (
 		0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, // 0xe0-0xef
 		0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xf0-0xff
 	};
-)
+}
 
 proc encode_rune(r rune) -> ([4]byte, int) {
 	var buf [4]byte;
@@ -99,12 +99,12 @@ proc decode_rune(s string) -> (rune, int) {
 		return RUNE_ERROR, 1;
 	}
 
-	const (
+	const {
 		MASK_X = 0b00111111;
 		MASK_2 = 0b00011111;
 		MASK_3 = 0b00001111;
 		MASK_4 = 0b00000111;
-	)
+	}
 
 	if size == 2 {
 		return (b0&MASK_2) as rune <<6 | (b1&MASK_X) as rune, 2;

+ 2 - 2
src/checker/checker.c

@@ -1142,8 +1142,8 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As
 			for_array(iota, gd->specs) {
 				AstNode *spec = gd->specs.e[iota];
 				switch (spec->kind) {
-				case_ast_node(bd, BadDecl, decl);
-				case_end;
+				case AstNode_BadDecl:
+					break;
 				case_ast_node(is, ImportSpec, spec);
 					if (!parent_scope->is_file) {
 						// NOTE(bill): _Should_ be caught by the parser

+ 1 - 1
src/checker/decl.c

@@ -308,7 +308,7 @@ bool are_signatures_similar_enough(Type *a_, Type *b_) {
 void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
 	GB_ASSERT(e->type == NULL);
 
-	Type *proc_type = make_type_proc(c->allocator, e->scope, NULL, 0, NULL, 0, false);
+	Type *proc_type = make_type_proc(c->allocator, e->scope, NULL, 0, NULL, 0, false, ProcCC_Odin);
 	e->type = proc_type;
 	ast_node(pd, ProcDecl, d->proc_decl);
 

+ 7 - 7
src/checker/expr.c

@@ -821,13 +821,13 @@ void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) {
 	if (params)  param_count  = params ->Tuple.variable_count;
 	if (results) result_count = results->Tuple.variable_count;
 
-	type->Proc.scope            = c->context.scope;
-	type->Proc.params           = params;
-	type->Proc.param_count      = param_count;
-	type->Proc.results          = results;
-	type->Proc.result_count     = result_count;
-	type->Proc.variadic         = variadic;
-	// type->Proc.implicit_context = implicit_context;
+	type->Proc.scope              = c->context.scope;
+	type->Proc.params             = params;
+	type->Proc.param_count        = param_count;
+	type->Proc.results            = results;
+	type->Proc.result_count       = result_count;
+	type->Proc.variadic           = variadic;
+	type->Proc.calling_convention = pt->calling_convention;
 }
 
 

+ 21 - 3
src/checker/types.c

@@ -110,6 +110,7 @@ typedef struct TypeRecord {
 		i32    param_count; \
 		i32    result_count; \
 		bool   variadic; \
+		ProcCallingConvention calling_convention; \
 	})
 
 typedef enum TypeKind {
@@ -382,7 +383,7 @@ Type *make_type_tuple(gbAllocator a) {
 	return t;
 }
 
-Type *make_type_proc(gbAllocator a, Scope *scope, Type *params, isize param_count, Type *results, isize result_count, bool variadic) {
+Type *make_type_proc(gbAllocator a, Scope *scope, Type *params, isize param_count, Type *results, isize result_count, bool variadic, ProcCallingConvention calling_convention) {
 	Type *t = alloc_type(a, Type_Proc);
 
 	if (variadic) {
@@ -403,6 +404,7 @@ Type *make_type_proc(gbAllocator a, Scope *scope, Type *params, isize param_coun
 	t->Proc.results      = results;
 	t->Proc.result_count = result_count;
 	t->Proc.variadic     = variadic;
+	t->Proc.calling_convention = calling_convention;
 	return t;
 }
 
@@ -655,8 +657,9 @@ bool is_type_comparable(Type *t) {
 }
 
 bool are_types_identical(Type *x, Type *y) {
-	if (x == y)
+	if (x == y) {
 		return true;
+	}
 
 	if ((x == NULL && y != NULL) ||
 	    (x != NULL && y == NULL)) {
@@ -747,7 +750,8 @@ bool are_types_identical(Type *x, Type *y) {
 
 	case Type_Proc:
 		if (y->kind == Type_Proc) {
-			return are_types_identical(x->Proc.params, y->Proc.params) &&
+			return x->Proc.calling_convention == y->Proc.calling_convention &&
+			       are_types_identical(x->Proc.params, y->Proc.params) &&
 			       are_types_identical(x->Proc.results, y->Proc.results);
 		}
 		break;
@@ -1547,6 +1551,20 @@ gbString write_type_to_string(gbString str, Type *type) {
 			str = gb_string_appendc(str, " -> ");
 			str = write_type_to_string(str, type->Proc.results);
 		}
+		switch (type->Proc.calling_convention) {
+		case ProcCC_Odin:
+			// str = gb_string_appendc(str, " #cc_odin");
+			break;
+		case ProcCC_C:
+			str = gb_string_appendc(str, " #cc_c");
+			break;
+		case ProcCC_Std:
+			str = gb_string_appendc(str, " #cc_std");
+			break;
+		case ProcCC_Fast:
+			str = gb_string_appendc(str, " #cc_fast");
+			break;
+		}
 		break;
 	}
 

+ 1 - 1
src/main.c

@@ -242,7 +242,7 @@ int main(int argc, char **argv) {
 	exit_code = win32_exec_command_line_app("msvc-link", true,
 		"link %.*s.obj -OUT:%.*s.%s %s "
 		"/defaultlib:libcmt "
-		"/nologo /incremental:no /opt:ref /subsystem:CONSOLE "
+		"/nologo /incremental:no /opt:ref /subsystem:WINDOWS "
 		" %.*s "
 		" %s "
 		"",

+ 113 - 52
src/parser.c

@@ -72,12 +72,17 @@ typedef enum ProcTag {
 	ProcTag_no_inline       = GB_BIT(14),
 	ProcTag_dll_import      = GB_BIT(15),
 	// ProcTag_dll_export      = GB_BIT(16),
-
-	ProcTag_stdcall         = GB_BIT(20),
-	ProcTag_fastcall        = GB_BIT(21),
-	// ProcTag_cdecl           = GB_BIT(22),
 } ProcTag;
 
+typedef enum ProcCallingConvention {
+	ProcCC_Odin = 0,
+	ProcCC_C,
+	ProcCC_Std,
+	ProcCC_Fast,
+
+	ProcCC_Invalid,
+} ProcCallingConvention;
+
 typedef enum VarDeclTag {
 	VarDeclTag_thread_local = GB_BIT(0),
 } VarDeclTag;
@@ -286,6 +291,7 @@ AST_NODE_KIND(_TypeBegin, "", i32) \
 		AstNodeArray params;  \
 		AstNodeArray results; \
 		u64          tags;    \
+		ProcCallingConvention calling_convention; \
 	}) \
 	AST_NODE_KIND(PointerType, "pointer type", struct { \
 		Token token; \
@@ -911,12 +917,13 @@ AstNode *make_field(AstFile *f, AstNodeArray names, AstNode *type, bool is_using
 	return result;
 }
 
-AstNode *make_proc_type(AstFile *f, Token token, AstNodeArray params, AstNodeArray results, u64 tags) {
+AstNode *make_proc_type(AstFile *f, Token token, AstNodeArray params, AstNodeArray results, u64 tags, ProcCallingConvention calling_convention) {
 	AstNode *result = make_node(f, AstNode_ProcType);
 	result->ProcType.token = token;
 	result->ProcType.params = params;
 	result->ProcType.results = results;
 	result->ProcType.tags = tags;
+	result->ProcType.calling_convention = calling_convention;
 	return result;
 }
 
@@ -1157,6 +1164,8 @@ void fix_advance_to_next_stmt(AstFile *f) {
 		case Token_const:
 		case Token_type:
 		case Token_proc:
+		case Token_import:
+		case Token_include:
 
 		case Token_if:
 		case Token_when:
@@ -1220,7 +1229,7 @@ void expect_semicolon(AstFile *f, AstNode *s) {
 		case AstNode_ProcDecl:
 			return;
 		case AstNode_GenericDecl:
-			if (s->GenericDecl.close.kind == Token_CloseParen) {
+			if (s->GenericDecl.close.kind == Token_CloseBrace) {
 				return;
 			} else if (s->GenericDecl.token.kind == Token_type) {
 				if (f->prev_token.kind == Token_CloseBrace) {
@@ -1246,10 +1255,15 @@ void expect_semicolon(AstFile *f, AstNode *s) {
 
 
 AstNode *    parse_expr(AstFile *f, bool lhs);
-AstNode *    parse_proc_type(AstFile *f);
+AstNode *    parse_proc_type(AstFile *f, String *foreign_name_, String *link_name_);
 AstNodeArray parse_stmt_list(AstFile *f);
 AstNode *    parse_stmt(AstFile *f);
 AstNode *    parse_body(AstFile *f);
+AstNode *    parse_proc_decl(AstFile *f);
+void         parse_proc_signature(AstFile *f, AstNodeArray *params, AstNodeArray *results);
+
+
+
 
 AstNode *parse_identifier(AstFile *f) {
 	Token token = f->curr_token;
@@ -1270,8 +1284,12 @@ AstNode *parse_tag_expr(AstFile *f, AstNode *expression) {
 
 AstNode *unparen_expr(AstNode *node) {
 	for (;;) {
-		if (node->kind != AstNode_ParenExpr)
+		if (node == NULL) {
+			return NULL;
+		}
+		if (node->kind != AstNode_ParenExpr) {
 			return node;
+		}
 		node = node->ParenExpr.expr;
 	}
 }
@@ -1380,10 +1398,13 @@ bool is_foreign_name_valid(String name) {
 	return true;
 }
 
-void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_name) {
+void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_name, ProcCallingConvention *calling_convention) {
 	// TODO(bill): Add this to procedure literals too
-	GB_ASSERT(foreign_name != NULL);
+	GB_ASSERT(tags         != NULL);
 	GB_ASSERT(link_name    != NULL);
+	GB_ASSERT(link_name    != NULL);
+
+	ProcCallingConvention cc = ProcCC_Invalid;
 
 	while (f->curr_token.kind == Token_Hash) {
 		AstNode *tag_expr = parse_tag_expr(f, NULL);
@@ -1427,16 +1448,49 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_n
 		ELSE_IF_ADD_TAG(no_inline)
 		ELSE_IF_ADD_TAG(dll_import)
 		// ELSE_IF_ADD_TAG(dll_export)
-		ELSE_IF_ADD_TAG(stdcall)
-		ELSE_IF_ADD_TAG(fastcall)
-		// ELSE_IF_ADD_TAG(cdecl)
-		else {
+		else if (str_eq(tag_name, str_lit("cc_odin"))) {
+			if (cc == ProcCC_Invalid) {
+				cc = ProcCC_Odin;
+			} else {
+				syntax_error_node(tag_expr, "Multiple calling conventions for procedure type");
+			}
+		} else if (str_eq(tag_name, str_lit("cc_c"))) {
+			if (cc == ProcCC_Invalid) {
+				cc = ProcCC_C;
+			} else {
+				syntax_error_node(tag_expr, "Multiple calling conventions for procedure type");
+			}
+		} else if (str_eq(tag_name, str_lit("cc_std"))) {
+			if (cc == ProcCC_Invalid) {
+				cc = ProcCC_Std;
+			} else {
+				syntax_error_node(tag_expr, "Multiple calling conventions for procedure type");
+			}
+		} else if (str_eq(tag_name, str_lit("cc_fast"))) {
+			if (cc == ProcCC_Invalid) {
+				cc = ProcCC_Fast;
+			} else {
+				syntax_error_node(tag_expr, "Multiple calling conventions for procedure type");
+			}
+		} else {
 			syntax_error_node(tag_expr, "Unknown procedure tag");
 		}
 
 		#undef ELSE_IF_ADD_TAG
 	}
 
+	if (cc == ProcCC_Invalid) {
+		if ((*tags) & ProcTag_foreign) {
+			cc = ProcCC_C;
+		} else {
+			cc = ProcCC_Odin;
+		}
+	}
+
+	if (calling_convention) {
+		*calling_convention = cc;
+	}
+
 	if ((*tags & ProcTag_foreign) && (*tags & ProcTag_export)) {
 		syntax_error(f->curr_token, "You cannot apply both #foreign and #export to a procedure");
 	}
@@ -1452,10 +1506,6 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_n
 	if (((*tags & ProcTag_bounds_check) || (*tags & ProcTag_no_bounds_check)) && (*tags & ProcTag_foreign)) {
 		syntax_error(f->curr_token, "You cannot apply both #bounds_check or #no_bounds_check to a procedure without a body");
 	}
-
-	if ((*tags & ProcTag_stdcall) && (*tags & ProcTag_fastcall)) {
-		syntax_error(f->curr_token, "You cannot apply one calling convention to a procedure");
-	}
 }
 
 AstNode *parse_operand(AstFile *f, bool lhs) {
@@ -1545,32 +1595,28 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
 
 	// Parse Procedure Type or Literal
 	case Token_proc: {
+		String foreign_name = {0};
+		String link_name = {0};
 		AstNode *curr_proc = f->curr_proc;
-		AstNode *type = parse_proc_type(f);
+		AstNode *type = parse_proc_type(f, &foreign_name, &link_name);
 		f->curr_proc = type;
 
-		u64 tags = 0;
-		String foreign_name = {0};
-		String link_name = {0};
-		parse_proc_tags(f, &tags, &foreign_name, &link_name);
-		if (tags & ProcTag_foreign) {
+		if (type->ProcType.tags & ProcTag_foreign) {
 			syntax_error(f->curr_token, "#foreign cannot be applied to procedure literals");
 		}
-		if (tags & ProcTag_export) {
+		if (type->ProcType.tags & ProcTag_export) {
 			syntax_error(f->curr_token, "#export cannot be applied to procedure literals");
 		}
 
 		if (f->curr_token.kind == Token_OpenBrace) {
 			AstNode *body;
 
-			if ((tags & ProcTag_foreign) != 0) {
+			if ((type->ProcType.tags & ProcTag_foreign) != 0) {
 				syntax_error(f->curr_token, "A procedure tagged as `#foreign` cannot have a body");
 			}
 
 			body = parse_body(f);
-			type = make_proc_lit(f, type, body, tags, foreign_name, link_name);
-		} else if (type != NULL && type->kind == AstNode_ProcType) {
-			type->ProcType.tags = tags;
+			type = make_proc_lit(f, type, body, type->ProcType.tags, foreign_name, link_name);
 		}
 
 		f->curr_proc = curr_proc;
@@ -1920,13 +1966,13 @@ AstNode *parse_generic_decl(AstFile *f, TokenKind keyword, ParserSpecProc spec_p
 	Token token = expect_token(f, keyword);
 	Token open = {0}, close = {0};
 	AstNodeArray specs = {0};
-	if (f->curr_token.kind == Token_OpenParen) {
-		open = expect_token(f, Token_OpenParen);
+	if (f->curr_token.kind == Token_OpenBrace) {
+		open = expect_token(f, Token_OpenBrace);
 		array_init(&specs, heap_allocator());
 
 
 		for (isize index = 0;
-		     f->curr_token.kind != Token_CloseParen &&
+		     f->curr_token.kind != Token_CloseBrace &&
 		     f->curr_token.kind != Token_EOF;
 		     index++) {
 			AstNode *spec = spec_proc(f, keyword, index);
@@ -1934,7 +1980,7 @@ AstNode *parse_generic_decl(AstFile *f, TokenKind keyword, ParserSpecProc spec_p
 			expect_semicolon(f, spec);
 		}
 
-		close = expect_token(f, Token_CloseParen);
+		close = expect_token(f, Token_CloseBrace);
 	} else {
 		array_init_reserve(&specs, heap_allocator(), 1);
 		array_add(&specs, spec_proc(f, keyword, 0));
@@ -2042,8 +2088,6 @@ PARSE_SPEC_PROC(parse_include_spec) {
 	return spec;
 }
 
-AstNode *parse_proc_decl(AstFile *f);
-
 AstNode *parse_decl(AstFile *f) {
 	switch (f->curr_token.kind) {
 	case Token_var:
@@ -2055,6 +2099,7 @@ AstNode *parse_decl(AstFile *f) {
 		return parse_generic_decl(f, f->curr_token.kind, parse_type_spec);
 
 	case Token_proc:
+		// TODO(bill): Should I allow procedures to use the generic declaration syntax?
 		return parse_proc_decl(f);
 
 	case Token_import:
@@ -2158,20 +2203,29 @@ AstNode *convert_stmt_to_expr(AstFile *f, AstNode *statement, String kind) {
 
 
 
-void parse_proc_signature(AstFile *f, AstNodeArray *params, AstNodeArray *results);
 
-AstNode *parse_proc_type(AstFile *f) {
+AstNode *parse_proc_type(AstFile *f, String *foreign_name_, String *link_name_) {
 	AstNodeArray params = {0};
 	AstNodeArray results = {0};
 
 	Token proc_token = expect_token(f, Token_proc);
 	parse_proc_signature(f, &params, &results);
 
-	return make_proc_type(f, proc_token, params, results, 0);
-}
+	u64 tags = 0;
+	String foreign_name = {0};
+	String link_name = {0};
+	ProcCallingConvention cc = ProcCC_Odin;
+
+	parse_proc_tags(f, &tags, &foreign_name, &link_name, &cc);
 
+	if (foreign_name_) *foreign_name_ = foreign_name;
+	if (link_name_)    *link_name_    = link_name;
 
-AstNodeArray parse_field_list(AstFile *f, isize *name_count_, bool allow_using, TokenKind separator, TokenKind follow) {
+	return make_proc_type(f, proc_token, params, results, tags, cc);
+}
+
+AstNodeArray parse_field_list(AstFile *f, isize *name_count_, bool allow_using, bool ellipsis_ok,
+                              TokenKind separator, TokenKind follow) {
 	AstNodeArray params = make_ast_node_array(f);
 	isize name_count = 0;
 
@@ -2203,7 +2257,7 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, bool allow_using,
 		// expect_token_after(f, Token_Colon, "parameter list");
 
 		AstNode *type = NULL;
-		if (f->curr_token.kind == Token_Ellipsis) {
+		if (ellipsis_ok && f->curr_token.kind == Token_Ellipsis) {
 			Token ellipsis = f->curr_token;
 			next_token(f);
 			type = parse_type_attempt(f);
@@ -2245,7 +2299,7 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, bool allow_using,
 
 
 AstNodeArray parse_record_fields(AstFile *f, isize *field_count_, bool allow_using, String context) {
-	return parse_field_list(f, field_count_, allow_using, Token_Semicolon, Token_CloseBrace);
+	return parse_field_list(f, field_count_, allow_using, false, Token_Semicolon, Token_CloseBrace);
 }
 
 AstNode *parse_identifier_or_type(AstFile *f) {
@@ -2358,8 +2412,14 @@ AstNode *parse_identifier_or_type(AstFile *f) {
 		return make_raw_union_type(f, token, decls, decl_count);
 	}
 
-	case Token_proc:
-		return parse_proc_type(f);
+	case Token_proc: {
+		Token token = f->curr_token;
+		AstNode *pt = parse_proc_type(f, NULL, NULL);
+		if (pt->ProcType.tags != 0) {
+			syntax_error(token, "A procedure type cannot have tags");
+		}
+		return pt;
+	}
 
 	case Token_OpenParen: {
 		// NOTE(bill): Skip the paren expression
@@ -2406,7 +2466,7 @@ void parse_proc_signature(AstFile *f,
                           AstNodeArray *params,
                           AstNodeArray *results) {
 	expect_token(f, Token_OpenParen);
-	*params = parse_field_list(f, NULL, true, Token_Comma, Token_CloseParen);
+	*params = parse_field_list(f, NULL, true, true, Token_Comma, Token_CloseParen);
 	expect_token_after(f, Token_CloseParen, "parameter list");
 	*results = parse_results(f);
 }
@@ -2431,21 +2491,22 @@ AstNode *parse_proc_decl(AstFile *f) {
 		return make_expr_stmt(f, parse_expr(f, true));
 	}
 
-	Token proc_token = expect_token(f, Token_proc);
-	AstNode *name = parse_identifier(f);
-
 	AstNodeArray params = {0};
 	AstNodeArray results = {0};
-	parse_proc_signature(f, &params, &results);
 
-	AstNode *proc_type = make_proc_type(f, proc_token, params, results, 0);
+	Token proc_token = expect_token(f, Token_proc);
+	AstNode *name = parse_identifier(f);
+	parse_proc_signature(f, &params, &results);
 
-	AstNode *body = NULL;
 	u64 tags = 0;
 	String foreign_name = {0};
 	String link_name = {0};
+	ProcCallingConvention cc = ProcCC_Odin;
+
+	parse_proc_tags(f, &tags, &foreign_name, &link_name, &cc);
 
-	parse_proc_tags(f, &tags, &foreign_name, &link_name);
+	AstNode *proc_type = make_proc_type(f, proc_token, params, results, tags, cc);
+	AstNode *body = NULL;
 
 	if (f->curr_token.kind == Token_OpenBrace) {
 		if ((tags & ProcTag_foreign) != 0) {

+ 8 - 6
src/ssa.c

@@ -2607,7 +2607,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 		} else if (e != NULL && e->kind == Entity_Variable) {
 			return ssa_addr_load(proc, ssa_build_addr(proc, expr));
 		}
-		GB_PANIC("nil value for expression from identifier: %.*s", LIT(i->string));
+		GB_PANIC("NULL value for expression from identifier: %.*s", LIT(i->string));
 		return NULL;
 	case_end;
 
@@ -5025,7 +5025,7 @@ void ssa_gen_tree(ssaGen *s) {
 
 		Type *proc_type = make_type_proc(a, proc_scope,
 		                                 proc_params, 3,
-		                                 proc_results, 1, false);
+		                                 proc_results, 1, false, ProcCC_Std);
 
 		AstNode *body = gb_alloc_item(a, AstNode);
 		Entity *e = make_entity_procedure(a, NULL, make_token_ident(name), proc_type, 0);
@@ -5035,7 +5035,7 @@ void ssa_gen_tree(ssaGen *s) {
 		map_ssa_value_set(&m->members, hash_string(name), p);
 
 		ssaProcedure *proc = &p->Proc;
-		proc->tags = ProcTag_no_inline | ProcTag_stdcall; // TODO(bill): is no_inline a good idea?
+		proc->tags = ProcTag_no_inline; // TODO(bill): is no_inline a good idea?
 		e->Procedure.link_name = name;
 
 		ssa_begin_procedure_body(proc);
@@ -5084,17 +5084,19 @@ void ssa_gen_tree(ssaGen *s) {
 
 		Type *proc_type = make_type_proc(a, proc_scope,
 		                                 proc_params, 4,
-		                                 proc_results, 1, false);
+		                                 proc_results, 1, false, ProcCC_Std);
 
 		AstNode *body = gb_alloc_item(a, AstNode);
 		Entity *e = make_entity_procedure(a, NULL, make_token_ident(name), proc_type, 0);
 		ssaValue *p = ssa_make_value_procedure(a, m, e, proc_type, NULL, body, name);
 
+		m->entry_point_entity = e;
+
 		map_ssa_value_set(&m->values, hash_pointer(e), p);
 		map_ssa_value_set(&m->members, hash_string(name), p);
 
 		ssaProcedure *proc = &p->Proc;
-		proc->tags = ProcTag_no_inline | ProcTag_stdcall; // TODO(bill): is no_inline a good idea?
+		proc->tags = ProcTag_no_inline; // TODO(bill): is no_inline a good idea?
 		e->Procedure.link_name = name;
 
 		ssa_begin_procedure_body(proc);
@@ -5108,7 +5110,7 @@ void ssa_gen_tree(ssaGen *s) {
 		String name = str_lit(SSA_STARTUP_RUNTIME_PROC_NAME);
 		Type *proc_type = make_type_proc(a, gb_alloc_item(a, Scope),
 		                                 NULL, 0,
-		                                 NULL, 0, false);
+		                                 NULL, 0, false, ProcCC_Odin);
 		AstNode *body = gb_alloc_item(a, AstNode);
 		Entity *e = make_entity_procedure(a, NULL, make_token_ident(name), proc_type, 0);
 		ssaValue *p = ssa_make_value_procedure(a, m, e, proc_type, NULL, body, name);

+ 17 - 6
src/ssa_print.c

@@ -636,6 +636,16 @@ void ssa_print_value(ssaFileBuffer *f, ssaModule *m, ssaValue *value, Type *type
 	}
 }
 
+void ssa_print_calling_convention(ssaFileBuffer *f, ssaModule *m, ProcCallingConvention cc) {
+	switch (cc) {
+	case ProcCC_Odin: ssa_fprintf(f, "");       break;
+	case ProcCC_C:    ssa_fprintf(f, "ccc ");   break;
+	case ProcCC_Std:  ssa_fprintf(f, "cc 64 "); break;
+	case ProcCC_Fast: ssa_fprintf(f, "cc 65 "); break;
+	default: GB_PANIC("unknown calling convention: %d", cc);
+	}
+}
+
 void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 	GB_ASSERT(value->kind == ssaValue_Instr);
 	ssaInstr *instr = &value->Instr;
@@ -933,6 +943,7 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 		if (gb_is_between(bo->op, Token__ComparisonBegin+1, Token__ComparisonEnd-1)) {
 			if (is_type_string(elem_type)) {
 				ssa_fprintf(f, "call ");
+				ssa_print_calling_convention(f, m, ProcCC_Odin);
 				ssa_print_type(f, m, t_bool);
 				char *runtime_proc = "";
 				switch (bo->op) {
@@ -1033,11 +1044,14 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 
 	case ssaInstr_Call: {
 		ssaInstrCall *call = &instr->Call;
+		Type *proc_type = base_type(ssa_type(call->value));
+		GB_ASSERT(is_type_proc(proc_type));
 		Type *result_type = call->type;
 		if (result_type) {
 			ssa_fprintf(f, "%%%d = ", value->index);
 		}
 		ssa_fprintf(f, "call ");
+		ssa_print_calling_convention(f, m, proc_type->Proc.calling_convention);
 		if (result_type) {
 			ssa_print_type(f, m, result_type);
 		} else {
@@ -1226,6 +1240,7 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 	}
 }
 
+
 void ssa_print_proc(ssaFileBuffer *f, ssaModule *m, ssaProcedure *proc) {
 	if (proc->body == NULL) {
 		ssa_fprintf(f, "declare ");
@@ -1243,14 +1258,10 @@ void ssa_print_proc(ssaFileBuffer *f, ssaModule *m, ssaProcedure *proc) {
 		}
 	}
 
-	if (proc->tags & ProcTag_stdcall) {
-		ssa_fprintf(f, "cc 64 ");
-	} else if (proc->tags & ProcTag_fastcall) {
-		ssa_fprintf(f, "cc 65 ");
-	}
-
 	TypeProc *proc_type = &proc->type->Proc;
 
+	ssa_print_calling_convention(f, m, proc_type->calling_convention);
+
 	if (proc_type->result_count == 0) {
 		ssa_fprintf(f, "void");
 	} else {