diff --git a/code/demo.odin b/code/demo.odin index 323754a23..0be0acffa 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -1,18 +1,651 @@ #import "fmt.odin"; +#import "os.odin"; +#import "strconv.odin"; +#import "utf8.odin"; -main :: proc() { - immutable program := "+ + * - /"; - accumulator := 0; +Error :: enum { + NONE, +} - for token in program { - match token { - case '+': accumulator += 1; - case '-': accumulator -= 1; - case '*': accumulator *= 2; - case '/': accumulator /= 2; - default: // Ignore everything else +Style_Type :: enum { + ITALIC, + BOLD, + STRIKE, +} + +Node :: union { + children: [dynamic]Node, + content: []byte, + inline_content: ^Node, + line_number: int, + + // Block Variants + Header{level: int}, + Document{}, + Paragraph{}, + Quote{}, + Code_Block{language: string}, + Horizontal_Rule{}, + + // Inline Variants + Multiple_Inline{}, + String_Inline{}, + Soft_Line_Break{}, + Hard_Line_Break{}, + Code_Span{}, + Style{ + type: Style_Type, + } +} + + +Parser :: struct { + data: []byte, + nodes: [dynamic]Node, +} + +parse :: proc(data: []byte) -> ([]Node, Error) { + p := Parser{ + data = data, + }; + err := parse(^p); + + if err != Error.NONE { + return nil, err; + } + + return p.nodes[..], Error.NONE; +} + +parse :: proc(p: ^Parser) -> Error { + is_blank :: proc(line: []byte) -> bool { + line = trim_whitespace(line); + return len(line) == 0; + } + + is_horizontal_rule :: proc(line: []byte) -> bool { + char: byte; + count := 0; + for c, i in line { + if c != ' ' && c != '\n' { + if c != '-' && c != '_' && c != '*' { + return false; + } + if char == 0 { + if i >= 4 { + return false; + } + char = c; + count = 1; + } else if c == char { + count++; + } else { + return false; + } + } + } + + + return count >= 3; + } + + nodes := make([dynamic]Node); + + line_number: int = 0; + prev_was_blank := false; + in_code_block := false; + code_language := ""; + code_block_start := 0; + + pos := 0; + end := len(p.data); + for pos < len(p.data) { + line_start := pos; + line_end := pos; + for p.data[line_end] != '\n' { + line_end++; + } + line := p.data[pos..line_end]; + pos = line_end+1; + line_number++; + + line = tabs_to_spaces_and_append_newline(line); + str := cast(string)line; + + skip := in_code_block; + + node: Node; + if len(line) > 3 && cast(string)line[..3] == "```" { + if !in_code_block { + code_block_start = line_start+3; + in_code_block = true; + code_language = ""; + rest := trim_whitespace(line[3..]); + if len(rest) > 0 { + code_language = cast(string)rest; + } + } else { + end := line_start-1; + str := p.data[code_block_start..end]; + node = Node.Code_Block{content = str, language = code_language}; + in_code_block = false; + } + skip = true; + } + + indent_char := line[indentation(line)]; + if skip { + + } else if indent_char == '>' { + node = Node.Quote{content = line}; + } else if indent_char == '*' { + // fmt.println("List Item"); + } else if level, content := parse_header(line); level > 0 { + node = Node.Header{content = content, level = level}; + } else if is_horizontal_rule(line) { + node = Node.Horizontal_Rule{}; + } else if !is_blank(line) { + node = Node.Paragraph{content = line}; + } + + if node != nil { + node.line_number = line_number; + append(nodes, node); } } - fmt.printf("The program \"%s\" calculates the value %d\n", program, accumulator); + + for _, i in nodes { + using Node; + match n in nodes[i] { + case Paragraph, Horizontal_Rule, Header, Code_Block: + append(p.nodes, nodes[i]); + case Quote: + // fmt.println("Quote"); + } + } + + for _, i in p.nodes { + process_inlines(^p.nodes[i]); + } + + + return Error.NONE; +} + +process_inlines :: proc(node: ^Node) { + using Node; + match n in node { + case Header: + n.inline_content = parse_inlines(n.content); + case Paragraph: + n.inline_content = parse_inlines(trim_right_space(n.content)); + } + + for _, i in node.children { + process_inlines(^node.children[i]); + } +} + +Inline_Parser :: struct { + data: []byte, + pos: int, + string_start: int, + root: ^Node, +} + +parse_inlines :: proc(data: []byte) -> ^Node { + reset_string :: proc(p: ^Inline_Parser) { + p.string_start = p.pos; + } + finalize_string :: proc(p: ^Inline_Parser) { + if p.string_start >= p.pos { + return; + } + + + str := p.data[p.string_start..p.pos]; + append(p.root.children, Node.String_Inline{content = trim_right_whitespace(str)}); + } + + p := Inline_Parser{ + data = data, + root = new(Node), + }; + p.root^ = Node.Multiple_Inline{}; + + using Node; + + for p.pos < len(p.data) { + node: Node; + match p.data[p.pos] { + default: p.pos++; + + case '\n': + hard_break := false; + new_line_pos := p.pos; + + if p.pos >= 2 && p.data[p.pos-1] == ' ' && p.data[p.pos-2] == ' ' { + hard_break = true; + p.pos -= 2; + } + + if p.pos >= 1 && p.data[p.pos-1] == '\\' { + hard_break = true; + p.pos--; + } + + + for p.pos > 0 && p.data[p.pos-1] == ' ' { + p.pos--; + } + finalize_string(^p); + + if hard_break { + node = Hard_Line_Break{}; + } else { + node = Soft_Line_Break{}; + } + + p.pos = new_line_pos + 1; + + for p.pos < len(p.data) && p.data[p.pos] == ' ' { + p.pos++; + } + reset_string(^p); + + case '`': + // "A backtick string is a string of one or more backtick + // characters (`) that is neither preceded nor followed by a + // backtick." + backtick_count: int; + for p.pos+backtick_count < len(p.data) && p.data[p.pos+backtick_count] == '`' { + backtick_count++; + } + closing := char_string_index(p.data, '`', p.pos+backtick_count, backtick_count); + if closing == -1 { + p.pos += backtick_count; + break; + } + + finalize_string(^p); + p.pos += backtick_count; + + content := p.data[p.pos..closing]; + content = collapse_space(trim_whitespace(content)); + + node = Code_Span{content = content}; + + p.pos = closing + backtick_count; + reset_string(^p); + + case '\\': + // "Backslashes before other characters are treated as literal backslashes." + if p.pos+1 >= len(p.data) || !is_ascii_punc(p.data[p.pos+1]) { + p.pos++; + break; + } + // "Any ASCII punctuation character may be backslash-escaped." + finalize_string(^p); + p.pos++; + node = String_Inline{content = p.data[p.pos..p.pos+1]}; + p.pos++; + reset_string(^p); + + case '&': + // "[A]ll valid HTML entities in any context are recognized as such + // and converted into unicode characters before they are stored in + // the AST." + semicolon := -1; + for c, i in p.data[p.pos+1..] { + if c == ';' { + semicolon = i; + break; + } + } + + if semicolon < 0 { + p.pos++; + break; + } + + semicolon += p.pos+1; + entity := cast(string)p.data[p.pos+1..semicolon]; + + codepoints := make([dynamic]byte, 0, 6); + + if len(entity) > 0 { + if entity[0] != '#' { + append(codepoints, '&'); + append(codepoints, ..cast([]byte)entity); + append(codepoints, ';'); + } else { + if len(entity) > 1 { + base := 10; + if entity[1] == 'x' || entity[1] == 'X' { + // "Hexadecimal entities consist of &# + either X or x + a + // string of 1-8 hexadecimal digits + ;." + base = 16; + } else { + // "Decimal entities consist of &# + a string of 1–8 arabic + // digits + ;. Again, these entities need to be recognised and + // tranformed into their corresponding UTF8 codepoints. Invalid + // Unicode codepoints will be written as the “unknown + // codepoint” character (0xFFFD)." + } + codepoint := strconv.parse_uint(entity[2..], base); + data, len := utf8.encode_rune(cast(rune)codepoint); + append(codepoints, ..data[..len]); + } + } + } + + if len(codepoints) == 0 { + p.pos++; + break; + } + + finalize_string(^p); + node = String_Inline{content = codepoints[..]}; + p.pos = semicolon+1; + reset_string(^p); + } + + if node != nil { + append(p.root.children, node); + } + } + + finalize_string(^p); + + return p.root; +} + +is_ascii_punc :: proc(char: byte) -> bool { + match char { + case '!', '"', '#', '$', '%', + '&', '\'', '(', ')', + '*', '+', ',', '-', + '.', '/', ':', ';', + '<', '=', '>', '?', '@', '[', '\\', ']', + '^', '_', '`', '{', '|', '}', '~': + return true; + } + return false; +} + +char_string_index :: proc(data: []byte, char: byte, start, length: int) -> int { + count: int; + for i in start..len(data) { + if data[i] == char { + count++; + if count == length { + if i+1 >= len(data) || data[i+1] != char { + return i+1 - count; + } + } + } else { + count = 0; + } + } + return -1; +} + +collapse_space :: proc(data: []byte) -> []byte { + out := make([]byte, 0, len(data)); + prev_was_space := false; + for c in data { + if c == ' ' || c == '\n' { + if !prev_was_space { + append(out, ' '); + prev_was_space = true; + } + } else { + append(out, c); + prev_was_space = false; + } + } + + return out; +} + + +parse_header :: proc(line: []byte) -> (int, []byte) { + // "The opening # character may be indented 0-3 spaces." + indent := indentation(line); + if indent > 3 { + return -1, nil; + } + line = line[indent..]; + + // "The header level is equal to the number of # characters in the opening sequence." + level := 0; + for c, i in line { + if c != '#' { + level = i; + break; + } + } + + if level < 1 || level > 6 { + return -1, nil; + } + line = line[level..]; + // "The opening sequence of # characters cannot be followed directly by a + // nonspace character." + if line[0] != ' ' && line[0] != '\n' { + return -1, nil; + } + // "The optional closing sequence of #s [...] may be followed by spaces + // only." + + trailer_start := len(line) - 1; + for trailer_start > 0 && line[trailer_start-1] == ' ' { + trailer_start--; + } + for trailer_start > 0 && line[trailer_start-1] == '#' { + trailer_start--; + } + // "The optional closing sequence of #s must be preceded by a space [...]." + // Note that (if the header is empty) this may be the same space as after + // the opening sequence. + if trailer_start > 0 && line[trailer_start-1] == ' ' { + line = line[..trailer_start]; + } + + // "The raw contents of the header are stripped of leading and trailing + // spaces before being parsed as inline content." + line = trim_space(line); + return level, line; + +} + +indentation :: proc(line: []byte) -> int { + for c, i in line { + if c != ' ' { + return i; + } + } + panic("indentation() expects line to end in newline character"); + return 0; +} + + +TAB_STOP :: 4; + +tabs_to_spaces_and_append_newline :: proc(line: []byte) -> []byte { + tab_count: int; + for c in line { + if c == '\t' { + tab_count++; + } + } + + out := make([]byte, 0, len(line) + tab_count*(TAB_STOP-1) + 1); + + rune_count: int; + for r in cast(string)line { + if r == '\t' { + spaces_count := TAB_STOP - rune_count%TAB_STOP; + for i in 0..spaces_count { + append(out, ' '); + } + rune_count += spaces_count; + } else { + match r { + case '\r', '\v', '\f': + append(out, ' '); + default: + c, l := utf8.encode_rune(r); + append(out, ..c[0..l]); + } + rune_count++; + } + } + append(out, '\n'); + return out; +} + +trim_right_whitespace :: proc(data: []byte) -> []byte { + c := data; + for i := len(c)-1; i >= 0; i-- { + match c[i] { + case ' ', '\t', '\v', '\f', '\r', '\n': + c = c[..i]; + continue; + } + break; + } + + return c; +} + + +trim_right_space :: proc(data: []byte) -> []byte { + c := data; + for i := len(c)-1; i >= 0; i-- { + if c[i] != ' ' { + break; + } + c = c[..i]; + } + + return c; +} + +trim_whitespace :: proc(data: []byte) -> []byte { + data = trim_right_whitespace(data); + index := 0; + for c in data { + match c { + case ' ', '\t', '\v', '\f', '\r': + index++; + continue; + } + break; + } + return data[index..]; +} + +trim_space :: proc(data: []byte) -> []byte { + index := 0; + for c in data { + if c != ' ' { + break; + } + index++; + } + data = data[index..]; + + for i := len(data)-1; i >= 0; i-- { + if data[i] != ' ' { + break; + } + data = data[..i]; + } + + return data; +} + +escape_map := map[byte]string{ + '"' = """, + '&' = "&", + '<' = "<", + '>' = ">", +}; + + +main :: proc() { + data, ok := os.read_entire_file("W:/Odin/misc/markdown_test.md"); + if !ok { + fmt.println("Failure to load file"); + return; + } + + nodes, err := parse(data); + if err != Error.NONE { + fmt.println("Failure to parse file"); + return; + } + + write_espaced :: proc(data: []byte) { + start: int; + for c, i in data { + if escaped, ok := escape_map[c]; ok { + fmt.print(cast(string)data[start..i]); + fmt.print(escaped); + start = i+1; + } + } + fmt.print(cast(string)data[start..]); + } + + print_inline_as_html :: proc(node: ^Node) { + using Node; + match n in node { + case Multiple_Inline: + for _, i in n.children { + print_inline_as_html(^n.children[i]); + } + case String_Inline: + write_espaced(n.content); + case Soft_Line_Break: + // fmt.println(); + case Hard_Line_Break: + fmt.println("
"); + case Code_Span: + fmt.print(""); + write_espaced(n.content); + fmt.print(""); + } + } + + print_node_as_html :: proc(node: ^Node) { + using Node; + match n in node { + case Header: + fmt.printf("", n.level); + print_inline_as_html(n.inline_content); + fmt.printf("\n", n.level); + case Paragraph: + fmt.print("

"); + print_inline_as_html(n.inline_content); + fmt.println("

"); + case Horizontal_Rule: + fmt.println("
"); + case Code_Block: + if n.language != "" { + fmt.printf("
", n.language);
+			} else {
+				fmt.print("
");
+			}
+			fmt.print(cast(string)n.content);
+			fmt.println("
"); + case Quote: + } + } + + for _, i in nodes { + print_node_as_html(^nodes[i]); + } } diff --git a/src/check_expr.c b/src/check_expr.c index 1dba6dbbd..9d4eb0905 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -1014,6 +1014,50 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) { return tuple; } +Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type) { + Type *new_type = original_type; + // NOTE(bill): Changing the passing parameter value type is to match C's ABI + // IMPORTANT TODO(bill): This only matches the ABI on MSVC at the moment + Type *bt = core_type(original_type); + switch (bt->kind) { + // Okay to pass by value + // Especially the only Odin types + case Type_Basic: break; + case Type_Pointer: break; + case Type_Proc: break; // NOTE(bill): Just a pointer + + // Odin only types + case Type_Slice: + case Type_DynamicArray: + case Type_Map: + break; + + // Odin specific + case Type_Array: + case Type_Vector: + // Could be in C too + case Type_Record: { + i64 size = type_size_of(a, original_type); + switch (8*size) { + case 8: new_type = t_u8; break; + case 16: new_type = t_u16; break; + case 32: new_type = t_u32; break; + case 64: new_type = t_u64; break; + default: + // NOTE(bill): It could be an empty struct that is passed + // and if that is the case, no need to pass by pointer + // (I think..) + if (size > 0) { + new_type = make_type_pointer(a, original_type); + } + break; + } + } break; + } + + return new_type; +} + void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) { ast_node(pt, ProcType, proc_type_node); @@ -1034,6 +1078,20 @@ void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) { type->Proc.result_count = result_count; type->Proc.variadic = variadic; type->Proc.calling_convention = pt->calling_convention; + + + type->Proc.abi_compat_params = gb_alloc_array(c->allocator, Type *, param_count); + for (isize i = 0; i < param_count; i++) { + Type *original_type = type->Proc.params->Tuple.variables[i]->type; + Type *new_type = type_to_abi_compat_param_type(c->allocator, original_type); + type->Proc.abi_compat_params[i] = new_type; + } + + // NOTE(bill): The types are the same + type->Proc.abi_compat_results = gb_alloc_array(c->allocator, Type *, result_count); + for (isize i = 0; i < result_count; i++) { + type->Proc.abi_compat_results[i] = type->Proc.results->Tuple.variables[i]->type; + } } diff --git a/src/ir.c b/src/ir.c index e76503af2..446343c28 100644 --- a/src/ir.c +++ b/src/ir.c @@ -351,11 +351,20 @@ typedef struct irValueGlobal { bool is_unnamed_addr; } irValueGlobal; + +typedef enum irParamPasskind { + irParamPass_Value, // Pass by value + irParamPass_Pointer, // Pass as a pointer rather than by value + irParamPass_Integer, // Pass as an integer of the same size +} irParamPasskind; + typedef struct irValueParam { - irProcedure *parent; - Entity * entity; - Type * type; - irValueArray referrers; + irParamPasskind kind; + irProcedure * parent; + Entity * entity; + Type * type; + Type * original_type; + irValueArray referrers; } irValueParam; typedef struct irValue { @@ -755,11 +764,23 @@ irValue *ir_value_global(gbAllocator a, Entity *e, irValue *value) { array_init(&v->Global.referrers, heap_allocator()); // TODO(bill): Replace heap allocator here return v; } -irValue *ir_value_param(gbAllocator a, irProcedure *parent, Entity *e) { +irValue *ir_value_param(gbAllocator a, irProcedure *parent, Entity *e, Type *abi_type) { irValue *v = ir_alloc_value(a, irValue_Param); - v->Param.parent = parent; - v->Param.entity = e; - v->Param.type = e->type; + v->Param.kind = irParamPass_Value; + v->Param.parent = parent; + v->Param.entity = e; + v->Param.original_type = e->type; + v->Param.type = abi_type; + + if (abi_type != e->type) { + if (is_type_pointer(abi_type)) { + v->Param.kind = irParamPass_Pointer; + } else if (is_type_integer(abi_type)) { + v->Param.kind = irParamPass_Integer; + } else { + GB_PANIC("Invalid abi type pass kind"); + } + } array_init(&v->Param.referrers, heap_allocator()); // TODO(bill): Replace heap allocator here return v; } @@ -1280,16 +1301,30 @@ irValue *ir_add_local_generated(irProcedure *proc, Type *type) { } -irValue *ir_add_param(irProcedure *proc, Entity *e, AstNode *expr) { - irValue *v = ir_value_param(proc->module->allocator, proc, e); -#if 1 - irValue *l = ir_add_local(proc, e, expr); - ir_emit_store(proc, l, v); +irValue *ir_add_param(irProcedure *proc, Entity *e, AstNode *expr, Type *abi_type) { + irValue *v = ir_value_param(proc->module->allocator, proc, e, abi_type); + irValueParam *p = &v->Param; -#else - ir_module_add_value(proc->module, e, v); -#endif - return v; + switch (p->kind) { + case irParamPass_Value: { + irValue *l = ir_add_local(proc, e, expr); + ir_emit_store(proc, l, v); + return v; + } + case irParamPass_Pointer: { + ir_module_add_value(proc->module, e, v); + return ir_emit_load(proc, v); + } + case irParamPass_Integer: { + irValue *l = ir_add_local(proc, e, expr); + irValue *iptr = ir_emit_conv(proc, l, make_type_pointer(proc->module->allocator, p->type)); + ir_emit_store(proc, iptr, v); + return ir_emit_load(proc, l); + } + } + + GB_PANIC("Unreachable"); + return NULL; } @@ -1383,11 +1418,36 @@ irValue *ir_emit_comment(irProcedure *p, String text) { return ir_emit(p, ir_instr_comment(p, text)); } +irValue *ir_copy_value_to_ptr(irProcedure *proc, irValue *val) { + Type *t = ir_type(val); + irValue *ptr = ir_add_local_generated(proc, t); + ir_emit_store(proc, ptr, val); + return ptr; +} + +irValue *ir_emit_bitcast(irProcedure *proc, irValue *data, Type *type) { + return ir_emit(proc, ir_instr_conv(proc, irConv_bitcast, data, ir_type(data), type)); +} irValue *ir_emit_call(irProcedure *p, irValue *value, irValue **args, isize arg_count) { Type *pt = base_type(ir_type(value)); GB_ASSERT(pt->kind == Type_Proc); Type *results = pt->Proc.results; + + isize param_count = pt->Proc.param_count; + GB_ASSERT(param_count == arg_count); + for (isize i = 0; i < param_count; i++) { + Type *original_type = pt->Proc.params->Tuple.variables[i]->type; + Type *new_type = pt->Proc.abi_compat_params[i]; + if (original_type != new_type) { + if (is_type_pointer(new_type)) { + args[i] = ir_copy_value_to_ptr(p, args[i]); + } else if (is_type_integer(new_type)) { + args[i] = ir_emit_bitcast(p, args[i], new_type); + } + } + } + return ir_emit(p, ir_instr_call(p, value, args, arg_count, results)); } @@ -1475,9 +1535,7 @@ void ir_emit_startup_runtime(irProcedure *proc) { ir_emit(proc, ir_alloc_instr(proc, irInstr_StartupRuntime)); } -irValue *ir_emit_bitcast(irProcedure *proc, irValue *data, Type *type) { - return ir_emit(proc, ir_instr_conv(proc, irConv_bitcast, data, ir_type(data), type)); -} + irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index); @@ -6436,9 +6494,10 @@ void ir_begin_procedure_body(irProcedure *proc) { AstNode *name = field->names.e[q_index++]; Entity *e = params->variables[i]; + Type *abi_type = proc->type->Proc.abi_compat_params[i]; if (!str_eq(e->token.string, str_lit("")) && !str_eq(e->token.string, str_lit("_"))) { - irValue *param = ir_add_param(proc, e, name); + irValue *param = ir_add_param(proc, e, name, abi_type); array_add(&proc->params, param); } } diff --git a/src/ir_print.c b/src/ir_print.c index 560983537..a80cf73c9 100644 --- a/src/ir_print.c +++ b/src/ir_print.c @@ -135,6 +135,28 @@ void ir_print_encoded_global(irFileBuffer *f, String name, bool remove_prefix) { ir_print_escape_string(f, name, true); } +void ir_print_type(irFileBuffer *f, irModule *m, Type *t); + +void ir_print_proc_results(irFileBuffer *f, irModule *m, Type *t) { + GB_ASSERT(is_type_proc(t)); + t = base_type(t); + isize result_count = t->Proc.result_count; + if (result_count == 0) { + ir_fprintf(f, "void"); + } else if (result_count == 1) { + ir_print_type(f, m, t->Proc.abi_compat_results[0]); + } else { + ir_fprintf(f, "{"); + for (isize i = 0; i < result_count; i++) { + if (i > 0) { + ir_fprintf(f, ", "); + } + ir_print_type(f, m, t->Proc.abi_compat_results[i]); + } + ir_fprintf(f, "}"); + } +} + void ir_print_type(irFileBuffer *f, irModule *m, Type *t) { i64 word_bits = 8*build_context.word_size; @@ -273,18 +295,15 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) { } return; case Type_Proc: { - if (t->Proc.result_count == 0) { - ir_fprintf(f, "void"); - } else { - ir_print_type(f, m, t->Proc.results); - } + isize param_count = t->Proc.param_count; + isize result_count = t->Proc.result_count; + ir_print_proc_results(f, m, t); ir_fprintf(f, " ("); - TypeTuple *params = &t->Proc.params->Tuple; - for (isize i = 0; i < t->Proc.param_count; i++) { + for (isize i = 0; i < param_count; i++) { if (i > 0) { ir_fprintf(f, ", "); } - ir_print_type(f, m, params->variables[i]->type); + ir_print_type(f, m, t->Proc.abi_compat_params[i]); } ir_fprintf(f, ")*"); } return; @@ -1176,7 +1195,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { ir_fprintf(f, "call "); ir_print_calling_convention(f, m, proc_type->Proc.calling_convention); if (result_type) { - ir_print_type(f, m, result_type); + ir_print_proc_results(f, m, proc_type); } else { ir_fprintf(f, "void"); } @@ -1192,7 +1211,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { for (isize i = 0; i < call->arg_count; i++) { Entity *e = params->variables[i]; GB_ASSERT(e != NULL); - Type *t = e->type; + Type *t = proc_type->Proc.abi_compat_params[i]; if (i > 0) { ir_fprintf(f, ", "); } @@ -1405,12 +1424,9 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) { ir_print_calling_convention(f, m, proc_type->calling_convention); - if (proc_type->result_count == 0) { - ir_fprintf(f, "void"); - } else { - ir_print_type(f, m, proc_type->results); - } - + isize param_count = proc_type->param_count; + isize result_count = proc_type->result_count; + ir_print_proc_results(f, m, proc->type); ir_fprintf(f, " "); // #ifndef GB_SYSTEM_WINDOWS @@ -1423,14 +1439,16 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) { ir_fprintf(f, "("); - if (proc_type->param_count > 0) { + if (param_count > 0) { TypeTuple *params = &proc_type->params->Tuple; for (isize i = 0; i < params->variable_count; i++) { Entity *e = params->variables[i]; + Type *original_type = e->type; + Type *abi_type = proc_type->abi_compat_params[i]; if (i > 0) { ir_fprintf(f, ", "); } - ir_print_type(f, m, e->type); + ir_print_type(f, m, abi_type); if (e->flags&EntityFlag_NoAlias) { ir_fprintf(f, " noalias"); } diff --git a/src/types.c b/src/types.c index 02c01d4c9..0dc91f246 100644 --- a/src/types.c +++ b/src/types.c @@ -132,6 +132,8 @@ typedef struct TypeRecord { Type * results; /* Type_Tuple */ \ i32 param_count; \ i32 result_count; \ + Type **abi_compat_params; \ + Type **abi_compat_results; \ bool variadic; \ ProcCallingConvention calling_convention; \ }) \