aboutsummaryrefslogtreecommitdiff
path: root/src/ir_print.cpp
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2021-04-25 19:52:37 +0100
committergingerBill <bill@gingerbill.org>2021-04-25 19:52:37 +0100
commita25e796b0016dbf180492ef660d0abcc023f5d56 (patch)
tree7ef3a9ad314ae338c17d83d70427978b18988ec6 /src/ir_print.cpp
parent833784e196d9b96f62b7d1a771b087e9feb918bf (diff)
Delete ir.cpp and related files
Diffstat (limited to 'src/ir_print.cpp')
-rw-r--r--src/ir_print.cpp3092
1 files changed, 0 insertions, 3092 deletions
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
deleted file mode 100644
index 54ce5dca1..000000000
--- a/src/ir_print.cpp
+++ /dev/null
@@ -1,3092 +0,0 @@
-#define IR_FILE_BUFFER_BUF_LEN (4096)
-
-struct irFileBuffer {
- gbVirtualMemory vm;
- isize offset;
- gbFile * output;
- char buf[IR_FILE_BUFFER_BUF_LEN];
-};
-
-void ir_file_buffer_init(irFileBuffer *f, gbFile *output) {
- isize size = 8*gb_virtual_memory_page_size(nullptr);
- f->vm = gb_vm_alloc(nullptr, size);
- f->offset = 0;
- f->output = output;
-}
-
-void ir_file_buffer_destroy(irFileBuffer *f) {
- if (f->offset > 0) {
- // NOTE(bill): finish writing buffered data
- gb_file_write(f->output, f->vm.data, f->offset);
- }
-
- gb_vm_free(f->vm);
-}
-
-void ir_file_buffer_write(irFileBuffer *f, void const *data, isize len) {
- if (len > f->vm.size) {
- //NOTE(thebirk): Flush the vm data before we print this directly
- // otherwise we get out of order printing which is no good
- gb_file_write(f->output, f->vm.data, f->offset);
- f->offset = 0;
-
- gb_file_write(f->output, data, len);
- return;
- }
-
- if ((f->vm.size - f->offset) < len) {
- gb_file_write(f->output, f->vm.data, f->offset);
- f->offset = 0;
- }
- u8 *cursor = cast(u8 *)f->vm.data + f->offset;
- gb_memmove(cursor, data, len);
- f->offset += len;
-}
-
-
-void ir_fprintf(irFileBuffer *f, char const *fmt, ...) {
- va_list va;
- va_start(va, fmt);
- isize len = gb_snprintf_va(f->buf, IR_FILE_BUFFER_BUF_LEN-1, fmt, va);
- ir_file_buffer_write(f, f->buf, len-1);
- va_end(va);
-}
-void ir_write_string(irFileBuffer *f, String s) {
- ir_file_buffer_write(f, s.text, s.len);
-}
-
-#if 1
-#define ir_write_str_lit(f, s) ir_write_string((f), str_lit(s))
-#else
-void ir_write_str_lit(irFileBuffer *f, char const *s) {
- isize len = gb_strlen(s);
- ir_file_buffer_write(f, s, len);
-}
-#endif
-void ir_write_byte(irFileBuffer *f, u8 c) {
- ir_file_buffer_write(f, &c, 1);
-}
-void ir_write_escaped_byte(irFileBuffer *f, u8 c) {
- static char const hex_table[] = "0123456789ABCDEF";
- char buf[3];
- buf[0] = '\\';
- buf[1] = hex_table[c >> 4];
- buf[2] = hex_table[c & 0x0f];
- ir_file_buffer_write(f, buf, 3);
-}
-
-void ir_write_i64(irFileBuffer *f, i64 i) {
- String str = i64_to_string(i, f->buf, IR_FILE_BUFFER_BUF_LEN-1);
- ir_write_string(f, str);
-}
-void ir_write_u64(irFileBuffer *f, u64 i) {
- String str = u64_to_string(i, f->buf, IR_FILE_BUFFER_BUF_LEN-1);
- ir_write_string(f, str);
-}
-void ir_write_big_int(irFileBuffer *f, BigInt const &x, Type *type, bool swap_endian) {
- if (x.len == 2) {
- u64 words[2] = {};
- BigInt y = x;
- if (swap_endian) {
- gb_memmove(words, y.d.words, 16);
- u8 *bytes = cast(u8 *)words;
- for (isize i = 0; i < 8; i++) {
- bytes[i] = bytes[16-i]; // byte swap
- }
- y.d.words = words;
- }
-
- String s = big_int_to_string(temporary_allocator(), &y, 10);
- ir_write_string(f, s);
- } else {
- i64 i = 0;
- if (x.neg) {
- i = big_int_to_i64(&x);
- } else {
- i = cast(i64)big_int_to_u64(&x);
- }
- if (swap_endian) {
- i64 size = type_size_of(type);
- switch (size) {
- case 2: i = cast(i64)cast(i16)gb_endian_swap16(cast(u16)cast(i16)i); break;
- case 4: i = cast(i64)cast(i32)gb_endian_swap32(cast(u32)cast(i32)i); break;
- case 8: i = cast(i64)gb_endian_swap64(cast(u64)i); break;
- }
- }
- ir_write_i64(f, i);
- }
-}
-
-void ir_file_write(irFileBuffer *f, void *data, isize len) {
- ir_file_buffer_write(f, data, len);
-}
-
-
-bool ir_valid_char(u8 c) {
- if (c >= 0x80) {
- return false;
- }
-
- if (gb_char_is_alphanumeric(c)) {
- return true;
- }
-
- switch (c) {
- case '$':
- case '-':
- case '.':
- case '_':
- return true;
- }
-
- return false;
-}
-
-void ir_print_escape_string(irFileBuffer *f, String name, bool print_quotes, bool prefix_with_dot) {
- isize extra = 0;
- for (isize i = 0; i < name.len; i++) {
- u8 c = name[i];
- if (!ir_valid_char(c)) {
- extra += 2;
- }
- }
-
- if (extra == 0) {
- ir_write_string(f, name);
- return;
- }
-
- if (print_quotes) {
- ir_write_byte(f, '"');
- }
-
- if (prefix_with_dot) {
- ir_write_byte(f, '.');
- }
-
- for (isize i = 0; i < name.len; i++) {
- u8 c = name[i];
- if (ir_valid_char(c)) {
- ir_write_byte(f, c);
- } else {
- ir_write_escaped_byte(f, c);
- }
- }
-
- if (print_quotes) {
- ir_write_byte(f, '"');
- }
-}
-
-
-void ir_print_escape_path(irFileBuffer *f, String path) {
- isize extra = 0;
- for (isize i = 0; i < path.len; i++) {
- u8 c = path[i];
- if (!ir_valid_char(c)) {
- extra += 2;
- }
- }
-
- if (extra == 0) {
- ir_write_string(f, path);
- return;
- }
-
- for (isize i = 0; i < path.len; i++) {
- u8 c = path[i];
- if (ir_valid_char(c) || c == ':') {
- ir_write_byte(f, c);
- } else if (c == '\\') {
- ir_write_byte(f, '/');
- } else {
- ir_write_escaped_byte(f, c);
- }
- }
-}
-
-
-void ir_print_encoded_local(irFileBuffer *f, String name) {
- ir_write_byte(f, '%');
- ir_print_escape_string(f, name, true, false);
-}
-
-void ir_print_encoded_global(irFileBuffer *f, String name, bool remove_prefix) {
- ir_write_byte(f, '@');
- ir_print_escape_string(f, name, true, !remove_prefix);
-}
-
-
-bool ir_print_debug_location(irFileBuffer *f, irModule *m, irValue *v) {
- if (!m->generate_debug_info) {
- return false;
- }
-
- GB_ASSERT_NOT_NULL(v);
- GB_ASSERT(v->kind == irValue_Instr);
-
- if (v->loc != nullptr) {
- if (v->loc->kind == irDebugInfo_Location) {
- ir_fprintf(f, ", !dbg !%d", v->loc->id);
- return true;
- }
- } else {
- irProcedure *proc = v->Instr.block->proc;
- if (proc->entity != nullptr) {
- // GB_ASSERT(proc->is_entry_point || (string_compare(proc->name, str_lit(IR_STARTUP_RUNTIME_PROC_NAME)) == 0));
- }
- }
- return false;
-}
-
-void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct = false);
-void ir_print_value(irFileBuffer *f, irModule *m, irValue *value, Type *type_hint);
-
-
-void ir_print_alignment_prefix_hack(irFileBuffer *f, i64 alignment) {
- // NOTE(bill): This is written like this as it may need to
- // changed for specific alignments
- switch (alignment) {
- case 1:
- ir_write_string(f, str_lit("[0 x i8]"));
- break;
- case 2:
- ir_write_string(f, str_lit("[0 x i16]"));
- break;
- case 4:
- ir_write_string(f, str_lit("[0 x i32]"));
- break;
- case 8:
- ir_write_string(f, str_lit("[0 x i64]"));
- break;
- case 16:
- ir_write_string(f, str_lit("[0 x <4 x i32>]"));
- break;
- default:
- GB_PANIC("Invalid alignment");
- break;
- }
-}
-
-
-void ir_print_proc_results(irFileBuffer *f, irModule *m, Type *t) {
- set_procedure_abi_types(t);
-
- GB_ASSERT(is_type_proc(t));
- t = base_type(t);
- isize result_count = t->Proc.result_count;
- if (result_count == 0 || t->Proc.return_by_pointer) {
- ir_write_string(f, str_lit("void"));
- } else {
- Type *rt = t->Proc.abi_compat_result_type;
- if (!is_type_tuple(rt)) {
- ir_print_type(f, m, rt);
- } else if (rt->Tuple.variables.count == 1) {
- ir_print_type(f, m, rt->Tuple.variables[0]->type);
- } else {
- ir_write_byte(f, '{');
- for_array(i, rt->Tuple.variables) {
- Entity *e = rt->Tuple.variables[i];
- if (i > 0) {
- ir_write_string(f, str_lit(", "));
- }
- ir_print_type(f, m, e->type);
- }
- ir_write_byte(f, '}');
- }
- }
-}
-
-
-void ir_print_proc_type_without_pointer(irFileBuffer *f, irModule *m, Type *t) {
- set_procedure_abi_types(t);
-
- i64 word_bits = 8*build_context.word_size;
- t = base_type(t);
- GB_ASSERT(is_type_proc(t));
-
- isize param_count = t->Proc.param_count;
- isize result_count = t->Proc.result_count;
-
- ir_print_proc_results(f, m, t);
- ir_write_string(f, str_lit(" ("));
- if (t->Proc.return_by_pointer) {
- ir_print_type(f, m, reduce_tuple_to_single_type(t->Proc.results));
- // ir_fprintf(f, "* sret noalias ");
- // ir_write_string(f, str_lit("* noalias "));
- ir_write_string(f, str_lit("*"));
- if (build_context.ODIN_OS == "darwin") {
- ir_fprintf(f, " byval");
- }
- if (param_count > 0 || t->Proc.calling_convention == ProcCC_Odin) {
- ir_write_string(f, str_lit(", "));
- }
- }
- isize param_index = 0;
- for (isize i = 0; i < param_count; i++) {
- Entity *e = t->Proc.params->Tuple.variables[i];
- if (e->kind != Entity_Variable) continue;
- if (param_index > 0) ir_write_string(f, str_lit(", "));
-
- if (i+1 == param_count && t->Proc.c_vararg) {
- ir_write_string(f, str_lit("..."));
- } else {
- Type *et = t->Proc.abi_compat_params[i];
- if (is_type_tuple(et)) {
- for_array(j, et->Tuple.variables) {
- if (j > 0) ir_write_str_lit(f, ", ");
-
- ir_print_type(f, m, et->Tuple.variables[j]->type);
- if (e->flags&EntityFlag_NoAlias) {
- ir_write_str_lit(f, " noalias");
- }
- if (e->flags&EntityFlag_ByVal) {
- ir_write_str_lit(f, " byval");
- }
- ir_write_byte(f, ' ');
- param_index++;
- }
- continue;
- } else {
- ir_print_type(f, m, et);
- }
- }
-
- param_index++;
- }
- if (t->Proc.calling_convention == ProcCC_Odin) {
- if (param_index > 0) ir_write_string(f, str_lit(", "));
- ir_print_type(f, m, t_context_ptr);
- }
- ir_write_byte(f, ')');
-}
-
-void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct) {
- i64 word_bits = 8*build_context.word_size;
- GB_ASSERT_NOT_NULL(t);
- t = default_type(t);
- GB_ASSERT(is_type_typed(t));
-
- switch (t->kind) {
- case Type_Basic:
- switch (t->Basic.kind) {
- case Basic_llvm_bool: ir_write_str_lit(f, "i1"); return;
- case Basic_bool: ir_write_str_lit(f, "i8"); return;
- case Basic_b8: ir_write_str_lit(f, "i8"); return;
- case Basic_b16: ir_write_str_lit(f, "i16"); return;
- case Basic_b32: ir_write_str_lit(f, "i32"); return;
- case Basic_b64: ir_write_str_lit(f, "i64"); return;
-
- case Basic_i8: ir_write_str_lit(f, "i8"); return;
- case Basic_u8: ir_write_str_lit(f, "i8"); return;
- case Basic_i16: ir_write_str_lit(f, "i16"); return;
- case Basic_u16: ir_write_str_lit(f, "i16"); return;
- case Basic_i32: ir_write_str_lit(f, "i32"); return;
- case Basic_u32: ir_write_str_lit(f, "i32"); return;
- case Basic_i64: ir_write_str_lit(f, "i64"); return;
- case Basic_u64: ir_write_str_lit(f, "i64"); return;
- case Basic_i128: ir_write_str_lit(f, "i128"); return;
- case Basic_u128: ir_write_str_lit(f, "i128"); return;
-
- case Basic_i16le: ir_write_str_lit(f, "i16"); return;
- case Basic_u16le: ir_write_str_lit(f, "i16"); return;
- case Basic_i32le: ir_write_str_lit(f, "i32"); return;
- case Basic_u32le: ir_write_str_lit(f, "i32"); return;
- case Basic_i64le: ir_write_str_lit(f, "i64"); return;
- case Basic_u64le: ir_write_str_lit(f, "i64"); return;
- case Basic_i128le: ir_write_str_lit(f, "i128"); return;
- case Basic_u128le: ir_write_str_lit(f, "i128"); return;
-
- case Basic_i16be: ir_write_str_lit(f, "i16"); return;
- case Basic_u16be: ir_write_str_lit(f, "i16"); return;
- case Basic_i32be: ir_write_str_lit(f, "i32"); return;
- case Basic_u32be: ir_write_str_lit(f, "i32"); return;
- case Basic_i64be: ir_write_str_lit(f, "i64"); return;
- case Basic_u64be: ir_write_str_lit(f, "i64"); return;
- case Basic_i128be: ir_write_str_lit(f, "i128"); return;
- case Basic_u128be: ir_write_str_lit(f, "i128"); return;
-
- case Basic_rune: ir_write_str_lit(f, "i32"); return;
-
- case Basic_int:
- case Basic_uint:
- case Basic_uintptr:
- switch (word_bits) {
- case 32: ir_write_str_lit(f, "i32"); break;
- case 64: ir_write_str_lit(f, "i64"); break;
- default: GB_PANIC("Unhandled word size: %td bits", word_bits); break;
- }
- return;
-
- case Basic_f16: ir_write_str_lit(f, "half"); return;
- case Basic_f32: ir_write_str_lit(f, "float"); return;
- case Basic_f64: ir_write_str_lit(f, "double"); return;
-
-
- case Basic_f16le: ir_write_str_lit(f, "half"); return;
- case Basic_f32le: ir_write_str_lit(f, "float"); return;
- case Basic_f64le: ir_write_str_lit(f, "double"); return;
-
- case Basic_f16be: ir_write_str_lit(f, "half"); return;
- case Basic_f32be: ir_write_str_lit(f, "float"); return;
- case Basic_f64be: ir_write_str_lit(f, "double"); return;
-
- case Basic_complex32: ir_write_str_lit(f, "%%..complex32"); return;
- case Basic_complex64: ir_write_str_lit(f, "%..complex64"); return;
- case Basic_complex128: ir_write_str_lit(f, "%..complex128"); return;
-
- case Basic_quaternion64: ir_write_str_lit(f, "%..quaternion64"); return;
- case Basic_quaternion128: ir_write_str_lit(f, "%..quaternion128"); return;
- case Basic_quaternion256: ir_write_str_lit(f, "%..quaternion256"); return;
-
- case Basic_any: ir_write_str_lit(f, "%..any"); return;
- case Basic_rawptr: ir_write_str_lit(f, "%..rawptr"); return;
- case Basic_string: ir_write_str_lit(f, "%..string"); return;
- case Basic_cstring: ir_write_str_lit(f, "i8*"); return;
-
- case Basic_typeid: ir_write_str_lit(f, "%..typeid"); return;
- }
- break;
-
- case Type_Pointer:
- // TODO(bill, 2019-12-22): Why did I make add this edge case? Is this some weird LLVM issue?
- // if (!is_type_named(t->Pointer.elem) && is_type_empty_struct(t->Pointer.elem)) {
- // ir_print_type(f, m, t_rawptr);
- // } else {
- ir_print_type(f, m, t->Pointer.elem);
- ir_write_byte(f, '*');
- // }
- return;
- case Type_Array:
- ir_write_byte(f, '[');
- ir_write_i64(f, t->Array.count);
- ir_write_str_lit(f, " x ");
- ir_print_type(f, m, t->Array.elem);
- ir_write_byte(f, ']');
- return;
- case Type_EnumeratedArray:
- ir_write_byte(f, '[');
- ir_write_i64(f, t->EnumeratedArray.count);
- ir_write_str_lit(f, " x ");
- ir_print_type(f, m, t->EnumeratedArray.elem);
- ir_write_byte(f, ']');
- return;
-
- case Type_Slice:
- ir_write_byte(f, '{');
- ir_print_type(f, m, t->Slice.elem); ir_write_str_lit(f, "*, ");
- ir_print_type(f, m, t_int);
- ir_write_byte(f, '}');
- return;
- case Type_DynamicArray:
- ir_write_byte(f, '{');
- ir_print_type(f, m, t->DynamicArray.elem); ir_write_str_lit(f, "*, ");
- ir_print_type(f, m, t_int); ir_write_str_lit(f, ", ");
- ir_print_type(f, m, t_int); ir_write_str_lit(f, ", ");
- ir_print_type(f, m, t_allocator);
- ir_write_byte(f, '}');
- return;
-
- case Type_Enum:
- ir_print_type(f, m, base_enum_type(t));
- return;
-
- case Type_Union:
- if (t->Union.variants.count == 0) {
- ir_print_encoded_local(f, str_lit("..opaque"));
- } else {
- // NOTE(bill): The zero size array is used to fix the alignment used in a structure as
- // LLVM takes the first element's alignment as the entire alignment (like C)
- i64 align = type_align_of(t);
-
- if (is_type_union_maybe_pointer_original_alignment(t)) {
- ir_write_byte(f, '{');
- ir_print_type(f, m, t->Union.variants[0]);
- ir_write_byte(f, '}');
- return;
- }
-
- i64 block_size = t->Union.variant_block_size;
-
- ir_write_byte(f, '{');
- ir_print_alignment_prefix_hack(f, align);
- if (is_type_union_maybe_pointer(t)) {
- ir_fprintf(f, ", ");
- ir_print_type(f, m, t->Union.variants[0]);
- } else {
- ir_fprintf(f, ", [%lld x i8], ", block_size);
- ir_print_type(f, m, union_tag_type(t));
- }
- ir_write_byte(f, '}');
- }
- return;
-
- case Type_Struct: {
- if (t->Struct.is_raw_union) {
- // NOTE(bill): The zero size array is used to fix the alignment used in a structure as
- // LLVM takes the first element's alignment as the entire alignment (like C)
- i64 size_of_union = type_size_of(t);
- i64 align_of_union = type_align_of(t);
- ir_write_byte(f, '{');
- ir_print_alignment_prefix_hack(f, align_of_union);
- ir_fprintf(f, ", [%lld x i8]}", size_of_union);
- return;
- } else {
- if (t->Struct.is_packed) {
- ir_write_byte(f, '<');
- }
- ir_write_byte(f, '{');
- if (t->Struct.custom_align > 0) {
- ir_print_alignment_prefix_hack(f, t->Struct.custom_align);
- if (t->Struct.fields.count > 0) {
- ir_write_string(f, str_lit(", "));
- }
- }
- for_array(i, t->Struct.fields) {
- if (i > 0) {
- ir_write_string(f, str_lit(", "));
- }
- ir_print_type(f, m, t->Struct.fields[i]->type, true);
- }
- ir_write_byte(f, '}');
- if (t->Struct.is_packed) {
- ir_write_byte(f, '>');
- }
- return;
- }
- break;
- }
-
- case Type_Named: {
- Type *bt = base_type(t);
- switch (bt->kind) {
- case Type_Struct:
- case Type_Union: {
- Entity *e = t->Named.type_name;
- GB_ASSERT(e != nullptr);
- GB_ASSERT(e->kind == Entity_TypeName);
-
- String name = e->TypeName.ir_mangled_name;
- if (name.len > 0) {
- ir_print_encoded_local(f, name);
- } else {
- // TODO(bill): Is this correct behaviour?!
- // GB_ASSERT_MSG(name.len > 0, "%.*s %p", LIT(t->Named.name), e);
- // gb_printf_err("%.*s %p\n", LIT(t->Named.name), t->Named.type_name);
- ir_print_type(f, m, bt);
- }
- break;
- }
- default:
- ir_print_type(f, m, bt);
- break;
- }
- return;
- }
-
- case Type_Tuple:
- if (t->Tuple.variables.count == 1) {
- ir_print_type(f, m, t->Tuple.variables[0]->type);
- } else {
- ir_write_byte(f, '{');
- isize index = 0;
- for_array(i, t->Tuple.variables) {
- if (i > 0) ir_write_string(f, str_lit(", "));
- Entity *e = t->Tuple.variables[i];
- if (e->kind == Entity_Variable) {
- ir_print_type(f, m, e->type);
- index++;
- }
- }
- ir_write_byte(f, '}');
- }
- return;
-
- case Type_Proc:
- ir_print_proc_type_without_pointer(f, m, t);
- ir_write_byte(f, '*');
- return;
-
- case Type_Map:
- init_map_internal_types(t);
- GB_ASSERT(t->Map.internal_type != nullptr);
- ir_print_type(f, m, t->Map.internal_type);
- break;
-
- case Type_BitSet: {
- i64 size = type_size_of(t);
- if (size == 0) {
- ir_write_str_lit(f, "{}");
- return;
- }
- ir_print_type(f, m, bit_set_to_int(t));
- return;
- }
-
- case Type_SimdVector:
- ir_fprintf(f, "<%lld x ", t->SimdVector.count);;
- ir_print_type(f, m, t->SimdVector.elem);
- ir_write_byte(f, '>');
- return;
-
- case Type_RelativePointer:
- ir_print_type(f, m, t->RelativePointer.base_integer);
- return;
-
- case Type_RelativeSlice:
- ir_write_byte(f, '{');
- ir_print_type(f, m, t->RelativePointer.base_integer);
- ir_write_str_lit(f, ", ");
- ir_print_type(f, m, t->RelativePointer.base_integer);
- ir_write_byte(f, '}');
- return;
- }
-}
-
-void ir_print_debug_encoding(irFileBuffer *f, irDebugInfoKind kind, irDebugEncoding encoding) {
- switch (kind) {
- case irDebugInfo_BasicType:
- switch (encoding) {
- case irDebugBasicEncoding_address: ir_write_str_lit(f, "DW_ATE_address"); return;
- case irDebugBasicEncoding_boolean: ir_write_str_lit(f, "DW_ATE_boolean"); return;
- case irDebugBasicEncoding_float: ir_write_str_lit(f, "DW_ATE_float"); return;
- case irDebugBasicEncoding_signed: ir_write_str_lit(f, "DW_ATE_signed"); return;
- case irDebugBasicEncoding_signed_char: ir_write_str_lit(f, "DW_ATE_signed_char"); return;
- case irDebugBasicEncoding_unsigned: ir_write_str_lit(f, "DW_ATE_unsigned"); return;
- case irDebugBasicEncoding_unsigned_char: ir_write_str_lit(f, "DW_ATE_unsigned_char"); return;
- }
- case irDebugInfo_DerivedType:
- switch (encoding) {
- case irDebugBasicEncoding_member: ir_write_str_lit(f, "DW_TAG_member"); return;
- case irDebugBasicEncoding_pointer_type: ir_write_str_lit(f, "DW_TAG_pointer_type"); return;
- case irDebugBasicEncoding_typedef: ir_write_str_lit(f, "DW_TAG_typedef"); return;
- }
- case irDebugInfo_CompositeType:
- switch (encoding) {
- case irDebugBasicEncoding_array_type: ir_write_str_lit(f, "DW_TAG_array_type"); return;
- case irDebugBasicEncoding_enumeration_type: ir_write_str_lit(f, "DW_TAG_enumeration_type"); return;
- case irDebugBasicEncoding_structure_type: ir_write_str_lit(f, "DW_TAG_structure_type"); return;
- case irDebugBasicEncoding_union_type: ir_write_str_lit(f, "DW_TAG_union_type"); return;
- }
- }
-
- GB_PANIC("Unreachable");
-}
-
-void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *type);
-
-void ir_print_compound_element(irFileBuffer *f, irModule *m, ExactValue v, Type *elem_type) {
- ir_print_type(f, m, elem_type);
- ir_write_byte(f, ' ');
-
- if (v.kind == ExactValue_Invalid || !elem_type_can_be_constant(elem_type)) {
- ir_fprintf(f, "zeroinitializer");
- } else {
- ir_print_exact_value(f, m, v, elem_type);
- }
-}
-
-void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *type) {
- Type *original_type = type;
- type = core_type(type);
- value = convert_exact_value_for_type(value, type);
-
- // NOTE(bill): Is this correct? Does this handle all cases regarding arrays?
- if (is_type_array(type) && value.kind == ExactValue_String && !is_type_u8(core_array_type(type))) {
- i64 count = type->Array.count;
- Type *elem = type->Array.elem;
-
- if (is_type_rune_array(type)) {
- Rune rune;
- isize offset = 0;
- isize width = 1;
- String s = value.value_string;
- ir_write_byte(f, '[');
- for (i64 i = 0; i < count && offset < s.len; i++) {
- width = gb_utf8_decode(s.text+offset, s.len-offset, &rune);
- if (i > 0) ir_write_str_lit(f, ", ");
- ir_print_type(f, m, elem);
- ir_write_byte(f, ' ');
- ir_print_exact_value(f, m, exact_value_i64(rune), elem);
- offset += width;
- }
- GB_ASSERT(offset == s.len);
-
- ir_write_byte(f, ']');
- return;
- }
-
-
- ir_write_byte(f, '[');
-
- for (i64 i = 0; i < count; i++) {
- if (i > 0) ir_write_str_lit(f, ", ");
- ir_print_type(f, m, elem);
- ir_write_byte(f, ' ');
- ir_print_exact_value(f, m, value, elem);
- }
-
- ir_write_byte(f, ']');
- return;
- } else if (is_type_array(type) &&
- value.kind != ExactValue_Invalid &&
- value.kind != ExactValue_String &&
- value.kind != ExactValue_Compound) {
- i64 count = type->Array.count;
- Type *elem = type->Array.elem;
- ir_write_byte(f, '[');
-
- for (i64 i = 0; i < count; i++) {
- if (i > 0) ir_write_str_lit(f, ", ");
- ir_print_type(f, m, elem);
- ir_write_byte(f, ' ');
- ir_print_exact_value(f, m, value, elem);
- }
-
- ir_write_byte(f, ']');
- return;
- }
-
- switch (value.kind) {
- case ExactValue_Typeid:
- GB_ASSERT(is_type_typeid(type));
- ir_write_u64(f, ir_typeid_as_integer(m, value.value_typeid));
- break;
-
- case ExactValue_Bool:
- if (value.value_bool) {
- ir_write_string(f, are_types_identical(type, t_llvm_bool) ? str_lit("true") : str_lit("1"));
- } else {
- ir_write_string(f, are_types_identical(type, t_llvm_bool) ? str_lit("false") : str_lit("0"));
- }
- break;
- case ExactValue_String: {
- String str = value.value_string;
- Type *t = core_type(type);
- if (str.len == 0 && !is_type_cstring(t)) {
- ir_write_str_lit(f, "zeroinitializer");
- break;
- }
- if (is_type_u8_slice(type)) {
- irValue *str_array = ir_add_global_string_array(m, str);
- ir_write_str_lit(f, "{i8* getelementptr inbounds (");
- ir_print_type(f, m, str_array->Global.entity->type);
- ir_write_str_lit(f, ", ");
- ir_print_type(f, m, str_array->Global.entity->type);
- ir_write_str_lit(f, "* ");
- ir_print_encoded_global(f, str_array->Global.entity->token.string, false);
- ir_write_str_lit(f, ", ");
- ir_print_type(f, m, t_i32);
- ir_write_str_lit(f, " 0, i32 0), ");
- ir_print_type(f, m, t_int);
- ir_fprintf(f, " %lld}", cast(i64)str.len);
- } else if (!is_type_string(type)) {
- GB_ASSERT(is_type_array(type));
- ir_write_str_lit(f, "c\"");
- ir_print_escape_string(f, str, false, false);
- if (type->Array.count == str.len) {
- ir_write_str_lit(f, "\"");
- } else {
- ir_write_str_lit(f, "\\00\"");
- }
- } else if (is_type_cstring(t)) {
- // HACK NOTE(bill): This is a hack but it works because strings are created at the very end
- // of the .ll file
- irValue *str_array = ir_add_global_string_array(m, str);
- ir_write_str_lit(f, "getelementptr inbounds (");
- ir_print_type(f, m, str_array->Global.entity->type);
- ir_write_str_lit(f, ", ");
- ir_print_type(f, m, str_array->Global.entity->type);
- ir_write_str_lit(f, "* ");
- ir_print_encoded_global(f, str_array->Global.entity->token.string, false);
- ir_write_str_lit(f, ", ");
- ir_print_type(f, m, t_i32);
- ir_write_str_lit(f, " 0, i32 0)");
- } else {
- // HACK NOTE(bill): This is a hack but it works because strings are created at the very end
- // of the .ll file
- irValue *str_array = ir_add_global_string_array(m, str);
- ir_write_str_lit(f, "{i8* getelementptr inbounds (");
- ir_print_type(f, m, str_array->Global.entity->type);
- ir_write_str_lit(f, ", ");
- ir_print_type(f, m, str_array->Global.entity->type);
- ir_write_str_lit(f, "* ");
- ir_print_encoded_global(f, str_array->Global.entity->token.string, false);
- ir_write_str_lit(f, ", ");
- ir_print_type(f, m, t_i32);
- ir_write_str_lit(f, " 0, i32 0), ");
- ir_print_type(f, m, t_int);
- ir_fprintf(f, " %lld}", cast(i64)str.len);
- }
- break;
- }
- case ExactValue_Integer: {
- if (is_type_pointer(type)) {
- if (big_int_is_zero(&value.value_integer)) {
- ir_write_str_lit(f, "null");
- } else {
- ir_write_str_lit(f, "inttoptr (");
- ir_print_type(f, m, t_int);
- ir_write_byte(f, ' ');
- ir_write_big_int(f, value.value_integer, type, is_type_different_to_arch_endianness(type));
- ir_write_str_lit(f, " to ");
- ir_print_type(f, m, t_rawptr);
- ir_write_str_lit(f, ")");
- }
- } else {
- ir_write_big_int(f, value.value_integer, type, is_type_different_to_arch_endianness(type));
- }
- break;
- }
- case ExactValue_Float: {
- GB_ASSERT_MSG(is_type_float(type), "%s", type_to_string(type));
- type = core_type(type);
- u64 u_64 = bit_cast<u64>(value.value_float);
- u32 u_32 = bit_cast<u32>(cast(f32)value.value_float);
-
-
- #if 0
- switch (type->Basic.kind) {
- case Basic_f32:
- // IMPORTANT NOTE(bill): LLVM requires all floating point constants to be
- // a 64 bit number if bits_of(float type) <= 64.
- // https://groups.google.com/forum/#!topic/llvm-dev/IlqV3TbSk6M
- // 64 bit mantissa: 52 bits ==> 52-52 == 0
- // 32 bit mantissa: 23 bits ==> 52-23 == 29
- // 16 bit mantissa: 10 bits ==> 52=10 == 42
- // 29 == 52-23
- u >>= 29;
- u <<= 29;
- break;
- // case Basic_f16:
- // u >>= 42;
- // u <<= 42;
- // break;
- }
-
- switch (type->Basic.kind) {
- case 0: break;
- default:
- ir_fprintf(f, "0x%016llx", u);
- break;
- }
- #else
- switch (type->Basic.kind) {
- case Basic_f16:
- ir_fprintf(f, "fptrunc (float bitcast (i32 %u to float) to half)", u_32);
- break;
- case Basic_f16le:
- if (build_context.endian_kind != TargetEndian_Little) {
- u_32 = gb_endian_swap32(u_32);
- }
- ir_fprintf(f, "fptrunc (float bitcast (i32 %u to float) to half)", u_32);
- break;
- case Basic_f16be:
- if (build_context.endian_kind != TargetEndian_Big) {
- u_32 = gb_endian_swap32(u_32);
- }
- ir_fprintf(f, "fptrunc (float bitcast (i32 %u to float) to half)", u_32);
- break;
-
-
- case Basic_f32:
- ir_fprintf(f, "bitcast (i32 %u to float)", u_32);
- break;
- case Basic_f32le:
- if (build_context.endian_kind != TargetEndian_Little) {
- u_32 = gb_endian_swap32(u_32);
- }
- ir_fprintf(f, "bitcast (i32 %u to float)", u_32);
- break;
- case Basic_f32be:
- if (build_context.endian_kind != TargetEndian_Big) {
- u_32 = gb_endian_swap32(u_32);
- }
- ir_fprintf(f, "bitcast (i32 %u to float)", u_32);
- break;
-
- case Basic_f64:
- ir_fprintf(f, "0x%016llx", u_64);
- break;
- case Basic_f64le:
- if (build_context.endian_kind != TargetEndian_Little) {
- u_64 = gb_endian_swap64(u_64);
- }
- ir_fprintf(f, "0x%016llx", u_64);
- break;
- case Basic_f64be:
- if (build_context.endian_kind != TargetEndian_Big) {
- u_64 = gb_endian_swap64(u_64);
- }
- ir_fprintf(f, "0x%016llx", u_64);
- break;
-
- default:
- ir_fprintf(f, "0x%016llx", u_64);
- break;
- }
- #endif
- break;
- }
- case ExactValue_Complex: {
- // xy/ri format
- type = core_type(type);
- GB_ASSERT_MSG(is_type_complex(type), "%s", type_to_string(type));
- Type *ft = base_complex_elem_type(type);
- ir_write_byte(f, ' ');
- ir_write_byte(f, '{');
- ir_print_type(f, m, ft); ir_write_byte(f, ' ');
- ir_print_exact_value(f, m, exact_value_float(value.value_complex->real), ft);
- ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' ');
- ir_print_exact_value(f, m, exact_value_float(value.value_complex->imag), ft);
- ir_write_byte(f, '}');
- break;
- }
-
- case ExactValue_Quaternion: {
- // xyzw/ijkr format
- type = core_type(type);
- GB_ASSERT_MSG(is_type_quaternion(type), "%s", type_to_string(type));
- Type *ft = base_complex_elem_type(type);
- ir_write_byte(f, ' ');
- ir_write_byte(f, '{');
- ir_print_type(f, m, ft); ir_write_byte(f, ' ');
- ir_print_exact_value(f, m, exact_value_float(value.value_quaternion->imag), ft);
- ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' ');
- ir_print_exact_value(f, m, exact_value_float(value.value_quaternion->jmag), ft);
- ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' ');
- ir_print_exact_value(f, m, exact_value_float(value.value_quaternion->kmag), ft);
- ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' ');
- ir_print_exact_value(f, m, exact_value_float(value.value_quaternion->real), ft);
- ir_write_byte(f, '}');
- break;
- }
-
- case ExactValue_Pointer:
- if (value.value_pointer == 0) {
- if (is_type_typeid(type)) {
- ir_write_str_lit(f, "0");
- } else {
- ir_write_str_lit(f, "null");
- }
- } else {
- ir_write_str_lit(f, "inttoptr (");
- ir_print_type(f, m, t_int);
- ir_fprintf(f, " %llu to ", cast(u64)cast(uintptr)value.value_pointer);
- ir_print_type(f, m, t_rawptr);
- ir_write_byte(f, ')');
- }
- break;
- case ExactValue_Compound: {
- type = base_type(type);
- if (is_type_slice(type)) {
- irValue *s = ir_add_module_constant(m, type, value);
- ir_print_value(f, m, s, type);
- } else if (is_type_array(type)) {
- ast_node(cl, CompoundLit, value.value_compound);
-
- Type *elem_type = type->Array.elem;
- isize elem_count = cl->elems.count;
- if (elem_count == 0) {
- ir_write_str_lit(f, "zeroinitializer");
- break;
- }
- if (cl->elems[0]->kind == Ast_FieldValue) {
- // TODO(bill): This is O(N*M) and will be quite slow; it should probably be sorted before hand
- ir_write_byte(f, '[');
- for (i64 i = 0; i < type->Array.count; i++) {
- if (i > 0) ir_write_str_lit(f, ", ");
-
- bool found = false;
-
- for (isize j = 0; j < elem_count; j++) {
- Ast *elem = cl->elems[j];
- ast_node(fv, FieldValue, elem);
- if (is_ast_range(fv->field)) {
- ast_node(ie, BinaryExpr, fv->field);
- TypeAndValue lo_tav = ie->left->tav;
- TypeAndValue hi_tav = ie->right->tav;
- GB_ASSERT(lo_tav.mode == Addressing_Constant);
- GB_ASSERT(hi_tav.mode == Addressing_Constant);
-
- TokenKind op = ie->op.kind;
- i64 lo = exact_value_to_i64(lo_tav.value);
- i64 hi = exact_value_to_i64(hi_tav.value);
- if (op == Token_Ellipsis) {
- hi += 1;
- }
- if (lo == i) {
- TypeAndValue tav = fv->value->tav;
- if (tav.mode != Addressing_Constant) {
- break;
- }
- for (i64 k = lo; k < hi; k++) {
- if (k > lo) ir_write_str_lit(f, ", ");
-
- ir_print_compound_element(f, m, tav.value, elem_type);
- }
-
- found = true;
- i += (hi-lo-1);
- break;
- }
- } else {
- TypeAndValue index_tav = fv->field->tav;
- GB_ASSERT(index_tav.mode == Addressing_Constant);
- i64 index = exact_value_to_i64(index_tav.value);
- if (index == i) {
- TypeAndValue tav = fv->value->tav;
- if (tav.mode != Addressing_Constant) {
- break;
- }
- ir_print_compound_element(f, m, tav.value, elem_type);
- found = true;
- break;
- }
- }
- }
-
- if (!found) {
- ir_print_type(f, m, elem_type);
- ir_write_byte(f, ' ');
- ir_write_str_lit(f, "zeroinitializer");
- }
- }
- ir_write_byte(f, ']');
- } else {
- GB_ASSERT_MSG(elem_count == type->Array.count, "%td != %td", elem_count, type->Array.count);
-
- ir_write_byte(f, '[');
-
- for (isize i = 0; i < elem_count; i++) {
- if (i > 0) ir_write_str_lit(f, ", ");
- TypeAndValue tav = cl->elems[i]->tav;
- GB_ASSERT(tav.mode != Addressing_Invalid);
- ir_print_compound_element(f, m, tav.value, elem_type);
- }
- for (isize i = elem_count; i < type->Array.count; i++) {
- if (i >= elem_count) ir_write_str_lit(f, ", ");
- ir_print_compound_element(f, m, empty_exact_value, elem_type);
- }
-
- ir_write_byte(f, ']');
- }
- } else if (is_type_enumerated_array(type)) {
- ast_node(cl, CompoundLit, value.value_compound);
-
- Type *elem_type = type->EnumeratedArray.elem;
- isize elem_count = cl->elems.count;
- if (elem_count == 0) {
- ir_write_str_lit(f, "zeroinitializer");
- break;
- }
- if (cl->elems[0]->kind == Ast_FieldValue) {
- // TODO(bill): This is O(N*M) and will be quite slow; it should probably be sorted before hand
- ir_write_byte(f, '[');
-
- i64 total_lo = exact_value_to_i64(type->EnumeratedArray.min_value);
- i64 total_hi = exact_value_to_i64(type->EnumeratedArray.max_value);
-
- for (i64 i = total_lo; i <= total_hi; i++) {
- if (i > total_lo) ir_write_str_lit(f, ", ");
-
- bool found = false;
-
- for (isize j = 0; j < elem_count; j++) {
- Ast *elem = cl->elems[j];
- ast_node(fv, FieldValue, elem);
- if (is_ast_range(fv->field)) {
- ast_node(ie, BinaryExpr, fv->field);
- TypeAndValue lo_tav = ie->left->tav;
- TypeAndValue hi_tav = ie->right->tav;
- GB_ASSERT(lo_tav.mode == Addressing_Constant);
- GB_ASSERT(hi_tav.mode == Addressing_Constant);
-
- TokenKind op = ie->op.kind;
- i64 lo = exact_value_to_i64(lo_tav.value);
- i64 hi = exact_value_to_i64(hi_tav.value);
- if (op == Token_Ellipsis) {
- hi += 1;
- }
- if (lo == i) {
- TypeAndValue tav = fv->value->tav;
- if (tav.mode != Addressing_Constant) {
- break;
- }
- for (i64 k = lo; k < hi; k++) {
- if (k > lo) ir_write_str_lit(f, ", ");
-
- ir_print_compound_element(f, m, tav.value, elem_type);
- }
-
- found = true;
- i += (hi-lo-1);
- break;
- }
- } else {
- TypeAndValue index_tav = fv->field->tav;
- GB_ASSERT(index_tav.mode == Addressing_Constant);
- i64 index = exact_value_to_i64(index_tav.value);
- if (index == i) {
- TypeAndValue tav = fv->value->tav;
- if (tav.mode != Addressing_Constant) {
- break;
- }
- ir_print_compound_element(f, m, tav.value, elem_type);
- found = true;
- break;
- }
- }
- }
-
- if (!found) {
- ir_print_type(f, m, elem_type);
- ir_write_byte(f, ' ');
- ir_write_str_lit(f, "zeroinitializer");
- }
- }
- ir_write_byte(f, ']');
- } else {
- GB_ASSERT_MSG(elem_count == type->EnumeratedArray.count, "%td != %td", elem_count, type->EnumeratedArray.count);
-
- ir_write_byte(f, '[');
-
- for (isize i = 0; i < elem_count; i++) {
- if (i > 0) ir_write_str_lit(f, ", ");
- TypeAndValue tav = cl->elems[i]->tav;
- GB_ASSERT(tav.mode != Addressing_Invalid);
- ir_print_compound_element(f, m, tav.value, elem_type);
- }
- for (isize i = elem_count; i < type->EnumeratedArray.count; i++) {
- if (i >= elem_count) ir_write_str_lit(f, ", ");
- ir_print_compound_element(f, m, empty_exact_value, elem_type);
- }
-
- ir_write_byte(f, ']');
- }
- } else if (is_type_simd_vector(type)) {
- ast_node(cl, CompoundLit, value.value_compound);
-
- Type *elem_type = type->SimdVector.elem;
- isize elem_count = cl->elems.count;
- if (elem_count == 0) {
- ir_write_str_lit(f, "zeroinitializer");
- break;
- }
- GB_ASSERT_MSG(elem_count == type->SimdVector.count, "%td != %td", elem_count, type->SimdVector.count);
-
- ir_write_byte(f, '<');
-
- for (isize i = 0; i < elem_count; i++) {
- if (i > 0) ir_write_str_lit(f, ", ");
- TypeAndValue tav = cl->elems[i]->tav;
- GB_ASSERT(tav.mode != Addressing_Invalid);
- ir_print_compound_element(f, m, tav.value, elem_type);
- }
- for (isize i = elem_count; i < type->SimdVector.count; i++) {
- if (i >= elem_count) ir_write_str_lit(f, ", ");
- ir_print_compound_element(f, m, empty_exact_value, elem_type);
- }
-
- ir_write_byte(f, '>');
- } else if (is_type_struct(type)) {
- gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena);
- defer (gb_temp_arena_memory_end(tmp));
-
- ast_node(cl, CompoundLit, value.value_compound);
-
- if (cl->elems.count == 0) {
- ir_write_str_lit(f, "zeroinitializer");
- break;
- }
-
- String tstr = make_string_c(type_to_string(original_type));
-
- isize value_count = type->Struct.fields.count;
- ExactValue *values = gb_alloc_array(m->tmp_allocator, ExactValue, value_count);
- bool *visited = gb_alloc_array(m->tmp_allocator, bool, value_count);
-
- if (cl->elems.count > 0) {
- if (cl->elems[0]->kind == Ast_FieldValue) {
- isize elem_count = cl->elems.count;
- for (isize i = 0; i < elem_count; i++) {
- ast_node(fv, FieldValue, cl->elems[i]);
- String name = fv->field->Ident.token.string;
-
- TypeAndValue tav = fv->value->tav;
- GB_ASSERT(tav.mode != Addressing_Invalid);
-
- Selection sel = lookup_field(type, name, false);
- Entity *f = type->Struct.fields[sel.index[0]];
-
- values[f->Variable.field_src_index] = tav.value;
- visited[f->Variable.field_src_index] = true;
- }
- } else {
- for_array(i, cl->elems) {
- Entity *f = type->Struct.fields[i];
- TypeAndValue tav = cl->elems[i]->tav;
- ExactValue val = {};
- if (tav.mode != Addressing_Invalid) {
- val = tav.value;
- }
- values[f->Variable.field_src_index] = val;
- visited[f->Variable.field_src_index] = true;
- }
- }
- }
-
- if (type->Struct.is_packed) ir_write_byte(f, '<');
- ir_write_byte(f, '{');
- if (type->Struct.custom_align > 0) {
- ir_print_alignment_prefix_hack(f, cast(i64)type->Struct.custom_align);
- ir_write_str_lit(f, " zeroinitializer");
- if (value_count > 0) {
- ir_write_string(f, str_lit(", "));
- }
- }
-
-
- for (isize i = 0; i < value_count; i++) {
- if (i > 0) ir_write_string(f, str_lit(", "));
- Entity *e = type->Struct.fields[i];
- GB_ASSERT(e->kind == Entity_Variable);
- ir_print_compound_element(f, m, values[e->Variable.field_src_index], e->type);
- }
-
-
- ir_write_byte(f, '}');
- if (type->Struct.is_packed) ir_write_byte(f, '>');
- } else if (is_type_bit_set(type)) {
- ast_node(cl, CompoundLit, value.value_compound);
- if (cl->elems.count == 0) {
- ir_write_str_lit(f, "zeroinitializer");
- break;
- }
-
- i64 sz = type_size_of(type);
- if (sz == 0) {
- ir_write_str_lit(f, "zeroinitializer");
- break;
- }
-
- u64 bits = 0;
- for_array(i, cl->elems) {
- Ast *e = cl->elems[i];
- GB_ASSERT(e->kind != Ast_FieldValue);
-
- TypeAndValue tav = e->tav;
- if (tav.mode != Addressing_Constant) {
- continue;
- }
- GB_ASSERT(tav.value.kind == ExactValue_Integer);
- i64 v = big_int_to_i64(&tav.value.value_integer);
- i64 lower = type->BitSet.lower;
- bits |= 1ull<<cast(u64)(v-lower);
- }
- if (is_type_different_to_arch_endianness(type)) {
- i64 size = type_size_of(type);
- switch (size) {
- case 2: bits = cast(u64)gb_endian_swap16(cast(u16)bits); break;
- case 4: bits = cast(u64)gb_endian_swap32(cast(u32)bits); break;
- case 8: bits = cast(u64)gb_endian_swap64(cast(u64)bits); break;
- }
- }
- ir_write_u64(f, bits);
- } else {
- ir_write_str_lit(f, "zeroinitializer");
- }
-
- break;
- }
- case ExactValue_Procedure: {
- irValue **found = nullptr;
- Ast *expr = unparen_expr(value.value_procedure);
- GB_ASSERT(expr != nullptr);
-
- if (expr->kind == Ast_ProcLit) {
- found = map_get(&m->anonymous_proc_lits, hash_pointer(expr));
- } else {
- Entity *e = strip_entity_wrapping(expr);
- GB_ASSERT(e != nullptr);
- found = map_get(&m->values, hash_entity(e));
- }
- GB_ASSERT_MSG(found != nullptr, "%s", expr_to_string(expr));
- irValue *val = *found;
- ir_print_value(f, m, val, type);
- break;
- }
- default:
- ir_write_str_lit(f, "zeroinitializer");
- break;
- }
-}
-
-void ir_print_block_name(irFileBuffer *f, irBlock *b) {
- if (b != nullptr) {
- ir_print_escape_string(f, b->label, false, false);
- ir_fprintf(f, "-%td", b->index);
- } else {
- ir_write_str_lit(f, "<INVALID-BLOCK>");
- }
-}
-
-bool ir_print_is_proc_global(irModule *m, irProcedure *proc) {
- if (proc->entity != nullptr &&
- proc->entity->kind == Entity_Procedure) {
- if (m->entry_point_entity == proc->entity) {
- // gb_printf("%.*s\n", LIT(proc->entity->token.string));
- // TODO(bill): This may not be needed during windows
- return true;
- }
- if (proc->entity->Procedure.link_name.len > 0) {
- return true;
- }
- }
- return proc->is_foreign || proc->is_export;
-}
-
-void ir_print_value(irFileBuffer *f, irModule *m, irValue *value, Type *type_hint) {
- if (value == nullptr) {
- ir_write_str_lit(f, "!!!nullptr_VALUE");
- return;
- }
- switch (value->kind) {
- default: GB_PANIC("Unknown irValue kind"); break;
-
- case irValue_Constant:
- ir_print_exact_value(f, m, value->Constant.value, type_hint);
- break;
-
- case irValue_ConstantSlice: {
- irValueConstantSlice *cs = &value->ConstantSlice;
- if (cs->backing_array == nullptr || cs->count == 0) {
- ir_write_str_lit(f, "zeroinitializer");
- } else {
- Type *at = base_type(type_deref(ir_type(cs->backing_array)));
- Type *et = at->Array.elem;
- ir_write_byte(f, '{');
- ir_print_type(f, m, et);
- ir_write_str_lit(f, "* getelementptr inbounds (");
- ir_print_type(f, m, at);
- ir_write_str_lit(f, ", ");
- ir_print_type(f, m, at);
- ir_write_str_lit(f, "* ");
- ir_print_value(f, m, cs->backing_array, at);
- ir_write_str_lit(f, ", i32 0, i32 0), ");
- ir_print_type(f, m, t_int);
- ir_fprintf(f, " %lld}", cs->count);
- }
- break;
- }
-
- case irValue_Nil:
- ir_write_str_lit(f, "zeroinitializer");
- break;
-
- case irValue_Undef:
- ir_write_str_lit(f, "undef");
- break;
-
- case irValue_TypeName:
- ir_print_encoded_local(f, value->TypeName.name);
- break;
- case irValue_Global: {
- Entity *e = value->Global.entity;
- Scope *scope = e->scope;
- bool in_global_scope = false;
- if (scope != nullptr) {
- in_global_scope = (scope->flags & ScopeFlag_Global) != 0;
- }
- ir_print_encoded_global(f, ir_get_global_name(m, value), in_global_scope);
- break;
- }
- case irValue_Param:
- if (value->Param.index >= 0) {
- ir_fprintf(f, "%%_.%d", value->Param.index);
- } else {
- ir_print_encoded_local(f, value->Param.entity->token.string);
- }
- break;
- case irValue_SourceCodeLocation: {
- irValue *file = value->SourceCodeLocation.file;
- irValue *line = value->SourceCodeLocation.line;
- irValue *column = value->SourceCodeLocation.column;
- irValue *procedure = value->SourceCodeLocation.procedure;
-
- ir_write_byte(f, '{');
- ir_print_type(f, m, t_string); ir_write_byte(f, ' '); ir_print_value(f, m, file, t_string);
- ir_write_string(f, str_lit(", "));
- ir_print_type(f, m, t_i32); ir_write_byte(f, ' '); ir_print_value(f, m, line, t_i32);
- ir_write_string(f, str_lit(", "));
- ir_print_type(f, m, t_i32); ir_write_byte(f, ' '); ir_print_value(f, m, column, t_i32);
- ir_write_string(f, str_lit(", "));
- ir_print_type(f, m, t_string); ir_write_byte(f, ' '); ir_print_value(f, m, procedure, t_string);
- ir_write_byte(f, '}');
- break;
- }
- case irValue_Proc:
- ir_print_encoded_global(f, value->Proc.name, ir_print_is_proc_global(m, &value->Proc));
- break;
- case irValue_Instr:
- ir_fprintf(f, "%%%d", value->index);
- break;
- }
-}
-
-void ir_print_calling_convention(irFileBuffer *f, irModule *m, ProcCallingConvention cc) {
- switch (cc) {
- case ProcCC_Odin: ir_write_str_lit(f, ""); break;
- case ProcCC_Contextless: ir_write_str_lit(f, ""); break;
- // case ProcCC_CDecl: ir_write_str_lit(f, "ccc "); break;
- case ProcCC_CDecl: ir_write_str_lit(f, ""); break;
- case ProcCC_StdCall: ir_write_str_lit(f, "cc 64 "); break;
- case ProcCC_FastCall: ir_write_str_lit(f, "cc 65 "); break;
- case ProcCC_None: ir_write_str_lit(f, ""); break;
- default: GB_PANIC("unknown calling convention: %d", cc);
- }
-}
-
-void ir_print_context_parameter_prefix(irFileBuffer *f, irModule *m) {
- ir_print_type(f, m, t_context_ptr);
- // ir_write_str_lit(f, " noalias nonnull nocapture inreg ");
- ir_write_str_lit(f, " noalias nonnull nocapture ");
-}
-
-void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
- GB_ASSERT(value->kind == irValue_Instr);
- irInstr *instr = &value->Instr;
-
- ir_write_byte(f, '\t');
- defer (ir_write_byte(f, '\n'));
-
- switch (instr->kind) {
- default: {
- GB_PANIC("<unknown instr> %d\n", instr->kind);
- ir_fprintf(f, "; <unknown instr> %d\n", instr->kind);
- break;
- }
-
- case irInstr_StartupRuntime: {
- ir_write_str_lit(f, "call void ");
- ir_print_encoded_global(f, str_lit(IR_STARTUP_RUNTIME_PROC_NAME), false);
- ir_write_str_lit(f, "()");
- break;
- }
-
- case irInstr_Comment:
- ir_write_str_lit(f, "; ");
- ir_write_string(f, instr->Comment.text);
- break;
-
- case irInstr_Local: {
- Type *type = instr->Local.entity->type;
- i64 align = instr->Local.alignment;
- if (align <= 0) {
- align = type_align_of(type);
- }
- ir_fprintf(f, "%%%d = alloca ", value->index);
- ir_print_type(f, m, type);
- ir_fprintf(f, ", align %lld", align);
- break;
- }
-
- case irInstr_ZeroInit: {
- Type *type = type_deref(ir_type(instr->ZeroInit.address));
- ir_write_str_lit(f, "; ZeroInit\n\t");
- ir_write_str_lit(f, "store ");
- ir_print_type(f, m, type);
- ir_write_byte(f, ' ');
- ir_print_exact_value(f, m, empty_exact_value, type);
- ir_write_str_lit(f, ", ");
- ir_print_type(f, m, type);
- ir_fprintf(f, "* %%%d, align 1", instr->ZeroInit.address->index);
- // ir_fprintf(f, "* %%%d", instr->ZeroInit.address->index);
- break;
- }
-
- case irInstr_Store: {
- Type *type = type_deref(ir_type(instr->Store.address));
- ir_write_str_lit(f, "store ");
- if (instr->Store.is_volatile) {
- ir_write_str_lit(f, "volatile ");
- }
- ir_print_type(f, m, type);
- ir_write_byte(f, ' ');
- ir_print_value(f, m, instr->Store.value, type);
- ir_write_str_lit(f, ", ");
- ir_print_type(f, m, type);
- ir_write_str_lit(f, "* ");
- ir_print_value(f, m, instr->Store.address, type);
- ir_print_debug_location(f, m, value);
- break;
- }
-
- case irInstr_Load: {
- Type *type = instr->Load.type;
- ir_fprintf(f, "%%%d = load ", value->index);
- if (instr->Load.is_volatile) {
- ir_write_str_lit(f, "volatile ");
- }
- ir_print_type(f, m, type);
- ir_write_str_lit(f, ", ");
- ir_print_type(f, m, type);
- ir_write_str_lit(f, "* ");
- ir_print_value(f, m, instr->Load.address, type);
- if (instr->Load.custom_align > 0) {
- ir_fprintf(f, ", align %lld", instr->Load.custom_align);
- } else {
- ir_fprintf(f, ", align %lld", type_align_of(type));
- }
- ir_print_debug_location(f, m, value);
- break;
- }
-
- case irInstr_InlineCode:
- {
- switch (instr->InlineCode.id) {
- case BuiltinProc_alloca:
- ir_fprintf(f, "%%%d = ", value->index);
- ir_write_str_lit(f, "alloca i8, ");
- ir_print_type(f, m, ir_type(instr->InlineCode.operands[0]));
- ir_write_str_lit(f, " ");
- ir_print_value(f, m, instr->InlineCode.operands[0], ir_type(instr->InlineCode.operands[0]));
- ir_write_str_lit(f, ", align ");
- ir_print_value(f, m, instr->InlineCode.operands[1], t_i32);
- break;
-
- case BuiltinProc_cpu_relax:
- if (build_context.metrics.arch == TargetArch_amd64) {
- ir_write_str_lit(f, "call void asm sideeffect \"pause\", \"\"()");
- } else {
- // ir_write_str_lit(f, "call void asm sideeffect \"yield\", \"\"()");
- }
- break;
- default: GB_PANIC("Unknown inline code %d", instr->InlineCode.id); break;
- }
- }
- break;
-
-
- case irInstr_AtomicFence:
- ir_write_str_lit(f, "fence ");
- switch (instr->AtomicFence.id) {
- case BuiltinProc_atomic_fence: ir_write_str_lit(f, "seq_cst"); break;
- case BuiltinProc_atomic_fence_acq: ir_write_str_lit(f, "acquire"); break;
- case BuiltinProc_atomic_fence_rel: ir_write_str_lit(f, "release"); break;
- case BuiltinProc_atomic_fence_acqrel: ir_write_str_lit(f, "acq_rel"); break;
- default: GB_PANIC("Unknown atomic fence"); break;
- }
- break;
-
- case irInstr_AtomicStore: {
- Type *type = type_deref(ir_type(instr->AtomicStore.address));
- ir_write_str_lit(f, "store atomic ");
- ir_print_type(f, m, type);
- ir_write_byte(f, ' ');
- ir_print_value(f, m, instr->AtomicStore.value, type);
- ir_write_str_lit(f, ", ");
- ir_print_type(f, m, type);
- ir_write_str_lit(f, "* ");
- ir_print_value(f, m, instr->AtomicStore.address, type);
-
- switch (instr->AtomicStore.id) {
- case BuiltinProc_atomic_store: ir_write_str_lit(f, " seq_cst "); break;
- case BuiltinProc_atomic_store_rel: ir_write_str_lit(f, " release"); break;
- case BuiltinProc_atomic_store_relaxed: ir_write_str_lit(f, " monotonic"); break;
- case BuiltinProc_atomic_store_unordered: ir_write_str_lit(f, " unordered"); break;
- default: GB_PANIC("Unknown atomic store"); break;
- }
-
- ir_fprintf(f, ", align %lld", type_align_of(type));
-
- ir_print_debug_location(f, m, value);
- break;
- }
-
- case irInstr_AtomicLoad: {
- Type *type = instr->AtomicLoad.type;
- ir_fprintf(f, "%%%d = load atomic ", value->index);
- ir_print_type(f, m, type);
- ir_write_str_lit(f, ", ");
- ir_print_type(f, m, type);
- ir_write_str_lit(f, "* ");
- ir_print_value(f, m, instr->AtomicLoad.address, type);
-
- switch (instr->AtomicLoad.id) {
- case BuiltinProc_atomic_load: ir_fprintf(f, " seq_cst"); break;
- case BuiltinProc_atomic_load_acq: ir_fprintf(f, " acquire"); break;
- case BuiltinProc_atomic_load_relaxed: ir_fprintf(f, " monotonic"); break;
- case BuiltinProc_atomic_load_unordered: ir_fprintf(f, " unordered"); break;
- default: GB_PANIC("Unknown atomic load"); break;
- }
-
- ir_fprintf(f, ", align %lld", type_align_of(type));
- ir_print_debug_location(f, m, value);
- break;
- }
-
- case irInstr_AtomicRmw: {
- String operation = {};
- String ordering = {};
- switch (instr->AtomicRmw.id) {
- case BuiltinProc_atomic_add:
- case BuiltinProc_atomic_add_acq:
- case BuiltinProc_atomic_add_rel:
- case BuiltinProc_atomic_add_acqrel:
- case BuiltinProc_atomic_add_relaxed:
- operation = str_lit("add");
- break;
- case BuiltinProc_atomic_sub:
- case BuiltinProc_atomic_sub_acq:
- case BuiltinProc_atomic_sub_rel:
- case BuiltinProc_atomic_sub_acqrel:
- case BuiltinProc_atomic_sub_relaxed:
- operation = str_lit("sub");
- break;
- case BuiltinProc_atomic_and:
- case BuiltinProc_atomic_and_acq:
- case BuiltinProc_atomic_and_rel:
- case BuiltinProc_atomic_and_acqrel:
- case BuiltinProc_atomic_and_relaxed:
- operation = str_lit("and");
- break;
- case BuiltinProc_atomic_nand:
- case BuiltinProc_atomic_nand_acq:
- case BuiltinProc_atomic_nand_rel:
- case BuiltinProc_atomic_nand_acqrel:
- case BuiltinProc_atomic_nand_relaxed:
- operation = str_lit("nand");
- break;
- case BuiltinProc_atomic_or:
- case BuiltinProc_atomic_or_acq:
- case BuiltinProc_atomic_or_rel:
- case BuiltinProc_atomic_or_acqrel:
- case BuiltinProc_atomic_or_relaxed:
- operation = str_lit("or");
- break;
- case BuiltinProc_atomic_xor:
- case BuiltinProc_atomic_xor_acq:
- case BuiltinProc_atomic_xor_rel:
- case BuiltinProc_atomic_xor_acqrel:
- case BuiltinProc_atomic_xor_relaxed:
- operation = str_lit("xor");
- break;
- case BuiltinProc_atomic_xchg:
- case BuiltinProc_atomic_xchg_acq:
- case BuiltinProc_atomic_xchg_rel:
- case BuiltinProc_atomic_xchg_acqrel:
- case BuiltinProc_atomic_xchg_relaxed:
- operation = str_lit("xchg");
- break;
- }
-
- switch (instr->AtomicRmw.id) {
- case BuiltinProc_atomic_add:
- case BuiltinProc_atomic_sub:
- case BuiltinProc_atomic_and:
- case BuiltinProc_atomic_nand:
- case BuiltinProc_atomic_or:
- case BuiltinProc_atomic_xor:
- case BuiltinProc_atomic_xchg:
- ordering = str_lit("seq_cst");
- break;
- case BuiltinProc_atomic_add_acq:
- case BuiltinProc_atomic_sub_acq:
- case BuiltinProc_atomic_and_acq:
- case BuiltinProc_atomic_nand_acq:
- case BuiltinProc_atomic_or_acq:
- case BuiltinProc_atomic_xor_acq:
- case BuiltinProc_atomic_xchg_acq:
- ordering = str_lit("acquire");
- break;
- case BuiltinProc_atomic_add_rel:
- case BuiltinProc_atomic_sub_rel:
- case BuiltinProc_atomic_and_rel:
- case BuiltinProc_atomic_nand_rel:
- case BuiltinProc_atomic_or_rel:
- case BuiltinProc_atomic_xor_rel:
- case BuiltinProc_atomic_xchg_rel:
- ordering = str_lit("release");
- break;
- case BuiltinProc_atomic_add_acqrel:
- case BuiltinProc_atomic_sub_acqrel:
- case BuiltinProc_atomic_and_acqrel:
- case BuiltinProc_atomic_nand_acqrel:
- case BuiltinProc_atomic_or_acqrel:
- case BuiltinProc_atomic_xor_acqrel:
- case BuiltinProc_atomic_xchg_acqrel:
- ordering = str_lit("acq_rel");
- break;
- case BuiltinProc_atomic_add_relaxed:
- case BuiltinProc_atomic_sub_relaxed:
- case BuiltinProc_atomic_and_relaxed:
- case BuiltinProc_atomic_nand_relaxed:
- case BuiltinProc_atomic_or_relaxed:
- case BuiltinProc_atomic_xor_relaxed:
- case BuiltinProc_atomic_xchg_relaxed:
- ordering = str_lit("monotonic");
- break;
- }
-
- Type *type = type_deref(ir_type(instr->AtomicRmw.address));
- ir_write_str_lit(f, "atomicrmw ");
- ir_write_string(f, operation);
- ir_write_byte(f, ' ');
- ir_print_type(f, m, type);
- ir_write_str_lit(f, "* ");
- ir_print_value(f, m, instr->AtomicRmw.address, type);
- ir_write_str_lit(f, ", ");
- ir_print_type(f, m, type);
- ir_write_byte(f, ' ');
- ir_print_value(f, m, instr->AtomicRmw.value, type);
-
- ir_write_byte(f, ' ');
- ir_write_string(f, ordering);
-
- ir_print_debug_location(f, m, value);
- break;
- }
-
- case irInstr_AtomicCxchg: {
- Type *type = type_deref(ir_type(instr->AtomicCxchg.address));
- bool weak = false;
- String success = {};
- String failure = {};
-
- switch (instr->AtomicCxchg.id) {
- case BuiltinProc_atomic_cxchgweak:
- case BuiltinProc_atomic_cxchgweak_acq:
- case BuiltinProc_atomic_cxchgweak_rel:
- case BuiltinProc_atomic_cxchgweak_acqrel:
- case BuiltinProc_atomic_cxchgweak_relaxed:
- case BuiltinProc_atomic_cxchgweak_failrelaxed:
- case BuiltinProc_atomic_cxchgweak_failacq:
- case BuiltinProc_atomic_cxchgweak_acq_failrelaxed:
- case BuiltinProc_atomic_cxchgweak_acqrel_failrelaxed:
- weak = true;
- break;
- }
-
- switch (instr->AtomicCxchg.id) {
- case BuiltinProc_atomic_cxchg:
- case BuiltinProc_atomic_cxchgweak:
- success = str_lit("seq_cst");
- failure = str_lit("seq_cst");
- break;
- case BuiltinProc_atomic_cxchg_acq:
- case BuiltinProc_atomic_cxchgweak_acq:
- success = str_lit("acquire");
- failure = str_lit("seq_cst");
- break;
- case BuiltinProc_atomic_cxchg_rel:
- case BuiltinProc_atomic_cxchgweak_rel:
- success = str_lit("release");
- failure = str_lit("seq_cst");
- break;
- case BuiltinProc_atomic_cxchg_acqrel:
- case BuiltinProc_atomic_cxchgweak_acqrel:
- success = str_lit("acq_rel");
- failure = str_lit("seq_cst");
- break;
- case BuiltinProc_atomic_cxchg_relaxed:
- case BuiltinProc_atomic_cxchgweak_relaxed:
- success = str_lit("monotonic");
- failure = str_lit("monotonic");
- break;
- case BuiltinProc_atomic_cxchg_failrelaxed:
- case BuiltinProc_atomic_cxchgweak_failrelaxed:
- success = str_lit("seq_cst");
- failure = str_lit("monotonic");
- break;
- case BuiltinProc_atomic_cxchg_failacq:
- case BuiltinProc_atomic_cxchgweak_failacq:
- success = str_lit("seq_cst");
- failure = str_lit("acquire");
- break;
- case BuiltinProc_atomic_cxchg_acq_failrelaxed:
- case BuiltinProc_atomic_cxchgweak_acq_failrelaxed:
- success = str_lit("acquire");
- failure = str_lit("monotonic");
- break;
- case BuiltinProc_atomic_cxchg_acqrel_failrelaxed:
- case BuiltinProc_atomic_cxchgweak_acqrel_failrelaxed:
- success = str_lit("acq_rel");
- failure = str_lit("monotonic");
- break;
- }
-
- ir_fprintf(f, "%%%d = cmpxchg ", value->index);
- if (weak) {
- ir_write_str_lit(f, "weak ");
- }
- ir_print_type(f, m, type);
- ir_write_str_lit(f, "* ");
- ir_print_value(f, m, instr->AtomicCxchg.address, type);
- ir_write_str_lit(f, ", ");
- ir_print_type(f, m, type); ir_write_str_lit(f, " ");
- ir_print_value(f, m, instr->AtomicCxchg.old_value, type);
- ir_write_str_lit(f, ", ");
- ir_print_type(f, m, type); ir_write_str_lit(f, " ");
- ir_print_value(f, m, instr->AtomicCxchg.new_value, type);
- ir_write_str_lit(f, " ");
- ir_write_string(f, success);
- ir_write_str_lit(f, " ");
- ir_write_string(f, failure);
- break;
- }
-
- case irInstr_ArrayElementPtr: {
- Type *et = ir_type(instr->ArrayElementPtr.address);
- ir_fprintf(f, "%%%d = getelementptr inbounds ", value->index);
-
- ir_print_type(f, m, type_deref(et));
- ir_write_str_lit(f, ", ");
- ir_print_type(f, m, et);
- ir_write_byte(f, ' ');
- ir_print_value(f, m, instr->ArrayElementPtr.address, et);
- ir_write_str_lit(f, ", i32 0, ");
-
- irValue *index =instr->ArrayElementPtr.elem_index;
- Type *t = ir_type(index);
- ir_print_type(f, m, t);
- ir_write_byte(f, ' ');
- ir_print_value(f, m, index, t);
- break;
- }
-
- case irInstr_StructElementPtr: {
- Type *et = ir_type(instr->StructElementPtr.address);
- ir_fprintf(f, "%%%d = getelementptr inbounds ", value->index);
- i32 index = instr->StructElementPtr.elem_index;
- Type *st = base_type(type_deref(et));
- if (is_type_struct(st)) {
- if (st->Struct.custom_align > 0) {
- index += 1;
- }
- } else if (is_type_union(st)) {
- index += 1;
- }
-
- ir_print_type(f, m, type_deref(et));
- ir_write_str_lit(f, ", ");
- ir_print_type(f, m, et);
- ir_write_byte(f, ' ');
- ir_print_value(f, m, instr->StructElementPtr.address, et);
- ir_write_str_lit(f, ", i32 0, ");
- ir_print_type(f, m, t_i32);
- ir_fprintf(f, " %d", index);
- break;
- }
-
- case irInstr_PtrOffset: {
- Type *pt = ir_type(instr->PtrOffset.address);
- ir_fprintf(f, "%%%d = getelementptr inbounds ", value->index);
- ir_print_type(f, m, type_deref(pt));
- ir_write_str_lit(f, ", ");
- ir_print_type(f, m, pt);
- ir_write_byte(f, ' ');
- ir_print_value(f, m, instr->PtrOffset.address, pt);
-
- irValue *offset = instr->PtrOffset.offset;
- Type *t = ir_type(offset);
- ir_write_str_lit(f, ", ");
- ir_print_type(f, m, t);
- ir_write_byte(f, ' ');
- ir_print_value(f, m, offset, t);
- break;
- }
-
- case irInstr_Phi: {
- ir_fprintf(f, "%%%d = phi ", value->index);
- ir_print_type(f, m, instr->Phi.type);
- // ir_fprintf(f, " ", value->index);
- ir_write_byte(f, ' ');
-
- for (isize i = 0; i < instr->Phi.edges.count; i++) {
- if (i > 0) {
- ir_write_string(f, str_lit(", "));
- }
-
- irValue *edge = instr->Phi.edges[i];
- irBlock *block = nullptr;
- if (instr->block != nullptr &&
- i < instr->block->preds.count) {
- block = instr->block->preds[i];
- }
-
- ir_write_str_lit(f, "[ ");
- ir_print_value(f, m, edge, instr->Phi.type);
- ir_write_str_lit(f, ", %");
- ir_print_block_name(f, block);
- ir_write_str_lit(f, " ]");
- }
- break;
- }
-
- case irInstr_StructExtractValue: {
- Type *et = ir_type(instr->StructExtractValue.address);
- ir_fprintf(f, "%%%d = extractvalue ", value->index);
- i32 index = instr->StructExtractValue.index;
- Type *st = base_type(et);
- if (is_type_struct(st)) {
- if (st->Struct.custom_align > 0) {
- index += 1;
- }
- } else if (is_type_union(st)) {
- index += 1;
- }
-
-
- ir_print_type(f, m, et);
- ir_write_byte(f, ' ');
- ir_print_value(f, m, instr->StructExtractValue.address, et);
- ir_fprintf(f, ", %d", index);
- break;
- }
-
- case irInstr_UnionTagPtr: {
- Type *et = ir_type(instr->UnionTagPtr.address);
-
- Type *ut = type_deref(et);
- if (is_type_union_maybe_pointer(ut)) {
- GB_PANIC("union #maybe UnionTagPtr");
- }
-
- ir_fprintf(f, "%%%d = getelementptr inbounds ", value->index);
- Type *t = base_type(type_deref(et));
- GB_ASSERT(is_type_union(t));
-
- ir_print_type(f, m, type_deref(et));
- ir_write_str_lit(f, ", ");
- ir_print_type(f, m, et);
- ir_write_byte(f, ' ');
- ir_print_value(f, m, instr->UnionTagPtr.address, et);
- ir_write_str_lit(f, ", ");
- ir_print_type(f, m, t_int);
- ir_write_str_lit(f, " 0, ");
- ir_print_type(f, m, t_i32);
- ir_fprintf(f, " 2 ; UnionTagPtr");
- break;
- }
-
- case irInstr_UnionTagValue: {
- Type *et = ir_type(instr->UnionTagValue.address);
- Type *t = base_type(et);
-
- if (is_type_union_maybe_pointer(t)) {
- GB_PANIC("union #maybe UnionTagValue");
- }
-
- ir_fprintf(f, "%%%d = extractvalue ", value->index);
- GB_ASSERT(is_type_union(t));
-
-
- ir_print_type(f, m, et);
- ir_write_byte(f, ' ');
- ir_print_value(f, m, instr->UnionTagValue.address, et);
- ir_fprintf(f, ", 2 ; UnionTagValue");
- break;
- }
-
- case irInstr_Jump: {
- ir_write_str_lit(f, "br label %");
- ir_print_block_name(f, instr->Jump.block);
- ir_print_debug_location(f, m, value);
- break;
- }
-
- case irInstr_If: {
- ir_write_str_lit(f, "br i1");
- ir_write_byte(f, ' ');
- ir_print_value(f, m, instr->If.cond, t_bool);
- ir_write_str_lit(f, ", ");
- ir_write_str_lit(f, "label %"); ir_print_block_name(f, instr->If.true_block);
- ir_write_str_lit(f, ", label %"); ir_print_block_name(f, instr->If.false_block);
- ir_print_debug_location(f, m, value);
- break;
- }
-
- case irInstr_Return: {
- irInstrReturn *ret = &instr->Return;
- ir_write_str_lit(f, "ret ");
- if (ret->value == nullptr) {
- ir_write_str_lit(f, "void");
- } else {
- Type *t = ir_type(ret->value);
- ir_print_type(f, m, t);
- ir_write_byte(f, ' ');
- ir_print_value(f, m, ret->value, t);
- }
- ir_print_debug_location(f, m, value);
- break;
- }
-
- case irInstr_Conv: {
- irInstrConv *c = &instr->Conv;
- if (c->kind == irConv_byteswap) {
- int sz = cast(int)(8*type_size_of(c->from));
- ir_fprintf(f, "%%%d = call i%d @llvm.bswap.i%d(", value->index, sz, sz);
- ir_print_type(f, m, c->from);
- ir_write_byte(f, ' ');
- ir_print_value(f, m, c->value, c->from);
- ir_write_byte(f, ')');
- ir_print_debug_location(f, m, value);
- } else {
- ir_fprintf(f, "%%%d = ", value->index);
- ir_write_string(f, ir_conv_strings[c->kind]);
- ir_write_byte(f, ' ');
- ir_print_type(f, m, c->from);
- ir_write_byte(f, ' ');
- ir_print_value(f, m, c->value, c->from);
- ir_write_str_lit(f, " to ");
- ir_print_type(f, m, c->to);
- ir_print_debug_location(f, m, value);
- }
- break;
- }
-
- case irInstr_Unreachable: {
- ir_write_str_lit(f, "unreachable");
- break;
- }
-
- case irInstr_UnaryOp: {
- irInstrUnaryOp *uo = &value->Instr.UnaryOp;
- Type *type = base_type(ir_type(uo->expr));
- Type *elem_type = type;
-
- ir_fprintf(f, "%%%d = ", value->index);
- switch (uo->op) {
- case Token_Sub:
- if (is_type_float(elem_type)) {
- ir_write_str_lit(f, "fsub");
- } else {
- ir_write_str_lit(f, "sub");
- }
- break;
- case Token_Xor:
- case Token_Not:
- GB_ASSERT(is_type_integer(type) || is_type_boolean(type) || is_type_bit_set(type));
- ir_write_str_lit(f, "xor");
- break;
- default:
- GB_PANIC("Unknown unary operator");
- break;
- }
-
- ir_write_byte(f, ' ');
- ir_print_type(f, m, type);
- ir_write_byte(f, ' ');
- switch (uo->op) {
- case Token_Sub:
- if (is_type_float(elem_type)) {
- ir_print_exact_value(f, m, exact_value_float(0), elem_type);
- } else {
- ir_write_byte(f, '0');
- }
- break;
- case Token_Xor:
- case Token_Not:
- GB_ASSERT(is_type_integer(type) || is_type_boolean(type) || is_type_bit_set(type));
- ir_write_str_lit(f, "-1");
- break;
- }
- ir_write_str_lit(f, ", ");
- ir_print_value(f, m, uo->expr, type);
- ir_print_debug_location(f, m, value);
- break;
- }
-
- case irInstr_BinaryOp: {
- irInstrBinaryOp *bo = &value->Instr.BinaryOp;
- Type *type = base_type(ir_type(bo->left));
- Type *elem_type = base_array_type(type);
-
- ir_fprintf(f, "%%%d = ", value->index);
-
- if (gb_is_between(bo->op, Token__ComparisonBegin+1, Token__ComparisonEnd-1)) {
- if (is_type_string(elem_type)) {
- GB_PANIC("Unhandled string type");
- } else if (is_type_float(elem_type)) {
- ir_write_str_lit(f, "fcmp ");
- switch (bo->op) {
- case Token_CmpEq: ir_write_str_lit(f, "oeq"); break;
- case Token_NotEq: ir_write_str_lit(f, "one"); break;
- case Token_Lt: ir_write_str_lit(f, "olt"); break;
- case Token_Gt: ir_write_str_lit(f, "ogt"); break;
- case Token_LtEq: ir_write_str_lit(f, "ole"); break;
- case Token_GtEq: ir_write_str_lit(f, "oge"); break;
- }
- } else if (is_type_complex(elem_type)) {
- GB_PANIC("Unhandled complex type");
- return;
- } else {
- ir_write_str_lit(f, "icmp ");
- if (bo->op != Token_CmpEq &&
- bo->op != Token_NotEq) {
- if (is_type_unsigned(elem_type)) {
- ir_write_str_lit(f, "u");
- } else {
- ir_write_str_lit(f, "s");
- }
- }
- switch (bo->op) {
- case Token_CmpEq: ir_write_str_lit(f, "eq"); break;
- case Token_NotEq: ir_write_str_lit(f, "ne"); break;
- case Token_Lt: ir_write_str_lit(f, "lt"); break;
- case Token_Gt: ir_write_str_lit(f, "gt"); break;
- case Token_LtEq: ir_write_str_lit(f, "le"); break;
- case Token_GtEq: ir_write_str_lit(f, "ge"); break;
- default: GB_PANIC("invalid comparison");break;
- }
- }
- } else {
- if (is_type_float(elem_type)) {
- ir_write_str_lit(f, "f");
- }
-
- switch (bo->op) {
- case Token_Add: ir_write_str_lit(f, "add"); break;
- case Token_Sub: ir_write_str_lit(f, "sub"); break;
- case Token_And: ir_write_str_lit(f, "and"); break;
- case Token_Or: ir_write_str_lit(f, "or"); break;
- case Token_Xor: ir_write_str_lit(f, "xor"); break;
- case Token_Shl: ir_write_str_lit(f, "shl"); break;
- case Token_Mul: ir_write_str_lit(f, "mul"); break;
- case Token_Not: ir_write_str_lit(f, "xor"); break;
- case Token_Shr:
- if (is_type_unsigned(elem_type)) {
- ir_write_str_lit(f, "lshr");
- } else {
- ir_write_str_lit(f, "ashr");
- }
- break;
-
- case Token_AndNot: GB_PANIC("Token_AndNot Should never be called");
-
- default: {
- if (!is_type_float(elem_type)) {
- if (is_type_unsigned(elem_type)) {
- ir_write_str_lit(f, "u");
- } else {
- ir_write_str_lit(f, "s");
- }
- }
-
- switch (bo->op) {
- case Token_Quo: ir_write_str_lit(f, "div"); break;
- case Token_Mod: ir_write_str_lit(f, "rem"); break;
- }
- break;
- }
- }
- }
-
- ir_write_byte(f, ' ');
- ir_print_type(f, m, type);
- ir_write_byte(f, ' ');
- ir_print_value(f, m, bo->left, type);
- ir_write_str_lit(f, ", ");
- ir_print_value(f, m, bo->right, type);
-
- ir_print_debug_location(f, m, value);
- break;
- }
-
- case irInstr_Call: {
- irInstrCall *call = &instr->Call;
- Type *proc_type = base_type(ir_type(call->value));
- GB_ASSERT(is_type_proc(proc_type));
- set_procedure_abi_types(proc_type);
-
- bool is_c_vararg = proc_type->Proc.c_vararg;
- Type *result_type = call->type;
- if (result_type) {
- ir_fprintf(f, "%%%d = ", value->index);
- }
- ir_write_str_lit(f, "call ");
- ir_print_calling_convention(f, m, proc_type->Proc.calling_convention);
- if (is_c_vararg) {
- ir_print_proc_type_without_pointer(f, m, proc_type);
- } else if (result_type && !proc_type->Proc.return_by_pointer) {
- ir_print_proc_results(f, m, proc_type);
- } else {
- ir_write_str_lit(f, "void");
- }
- ir_write_byte(f, ' ');
- ir_print_value(f, m, call->value, call->type);
-
- bool return_by_pointer = proc_type->Proc.return_by_pointer;
-
- isize param_index = 0;
-
- ir_write_byte(f, '(');
- if (return_by_pointer) {
- GB_ASSERT(call->return_ptr != nullptr);
- ir_print_type(f, m, proc_type->Proc.results);
- ir_write_str_lit(f, "* ");
- ir_print_value(f, m, call->return_ptr, ir_type(call->return_ptr));
- param_index += 1;
- }
-
-
- if (call->args.count > 0) {
- TypeTuple *params = &proc_type->Proc.params->Tuple;
- if (proc_type->Proc.c_vararg) {
- isize i = 0;
- isize arg_index = 0;
- for (; i < params->variables.count-1; i++) {
- Entity *e = params->variables[i];
- GB_ASSERT(e != nullptr);
- if (e->kind != Entity_Variable) {
- arg_index++;
- continue;
- }
-
- if (param_index > 0) ir_write_str_lit(f, ", ");
-
- Type *t = proc_type->Proc.abi_compat_params[i];
- if (is_type_tuple(t)) {
- for_array(j, t->Tuple.variables) {
- if (j > 0) ir_write_str_lit(f, ", ");
-
- irValue *arg = call->args[arg_index++];
-
- ir_print_type(f, m, t->Tuple.variables[j]->type);
- if (e->flags&EntityFlag_NoAlias) {
- ir_write_str_lit(f, " noalias");
- }
- if (e->flags&EntityFlag_ByVal) {
- ir_write_str_lit(f, " byval");
- }
- ir_write_byte(f, ' ');
- ir_print_value(f, m, arg, t);
- param_index++;
- }
- } else {
- ir_print_type(f, m, t);
- if (e->flags&EntityFlag_NoAlias) {
- ir_write_str_lit(f, " noalias");
- }
- if (e->flags&EntityFlag_ImplicitReference) {
- ir_write_str_lit(f, " nonnull dereferenceable");
- }
- if (e->flags&EntityFlag_ByVal) {
- ir_write_str_lit(f, " byval");
- }
- ir_write_byte(f, ' ');
- irValue *arg = call->args[arg_index++];
- ir_print_value(f, m, arg, t);
- param_index++;
- }
- }
- while (arg_index < call->args.count) {
- if (param_index > 0) ir_write_str_lit(f, ", ");
-
- irValue *arg = call->args[arg_index];
- Type *t = ir_type(arg);
- ir_print_type(f, m, t);
- ir_write_byte(f, ' ');
- ir_print_value(f, m, arg, t);
- arg_index++;
- }
- } else {
- // GB_ASSERT(call->args.count == params->variables.count);
- isize arg_index = 0;
- for_array(i, params->variables) {
- Entity *e = params->variables[i];
- GB_ASSERT(e != nullptr);
- if (e->kind != Entity_Variable) {
- arg_index++;
- continue;
- }
-
- if (param_index > 0) ir_write_str_lit(f, ", ");
-
- Type *t = proc_type->Proc.abi_compat_params[i];
- if (is_type_tuple(t)) {
- for_array(j, t->Tuple.variables) {
- if (j > 0) ir_write_str_lit(f, ", ");
-
- irValue *arg = call->args[arg_index++];
-
- ir_print_type(f, m, t->Tuple.variables[j]->type);
- if (e->flags&EntityFlag_NoAlias) {
- ir_write_str_lit(f, " noalias");
- }
- if (e->flags&EntityFlag_ByVal) {
- ir_write_str_lit(f, " byval");
- }
- ir_write_byte(f, ' ');
- ir_print_value(f, m, arg, t);
- param_index++;
- }
- } else {
- irValue *arg = call->args[arg_index++];
- ir_print_type(f, m, t);
- if (e->flags&EntityFlag_NoAlias) {
- ir_write_str_lit(f, " noalias");
- }
- if (e->flags&EntityFlag_ByVal) {
- ir_write_str_lit(f, " byval");
- }
- ir_write_byte(f, ' ');
- ir_print_value(f, m, arg, t);
- param_index++;
- }
- }
- }
- }
- if (proc_type->Proc.calling_convention == ProcCC_Odin) {
- if (param_index > 0) ir_write_str_lit(f, ", ");
-
- ir_print_context_parameter_prefix(f, m);
- ir_print_value(f, m, call->context_ptr, t_context_ptr);
- }
- ir_write_str_lit(f, ")");
-
- if (proc_type->Proc.diverging) {
- ir_write_str_lit(f, " noreturn");
- }
- switch (call->inlining) {
- case ProcInlining_inline: ir_write_str_lit(f, " alwaysinline"); break;
- case ProcInlining_no_inline: ir_write_str_lit(f, " noinline"); break;
- }
- ir_print_debug_location(f, m, value);
-
- break;
- }
-
- case irInstr_Select: {
- ir_fprintf(f, "%%%d = select i1 ", value->index);
- ir_print_value(f, m, instr->Select.cond, t_bool);
- ir_write_string(f, str_lit(", "));
- ir_print_type(f, m, ir_type(instr->Select.true_value));
- ir_write_byte(f, ' ');
- ir_print_value(f, m, instr->Select.true_value, ir_type(instr->Select.true_value));
- ir_write_string(f, str_lit(", "));
- ir_print_type(f, m, ir_type(instr->Select.false_value));
- ir_write_byte(f, ' ');
- ir_print_value(f, m, instr->Select.false_value, ir_type(instr->Select.false_value));
- ir_print_debug_location(f, m, value);
- break;
- }
-
- case irInstr_DebugDeclare: {
- if (!m->generate_debug_info) {
- break;
- }
-
- irInstrDebugDeclare *dd = &instr->DebugDeclare;
- Type *vt = ir_type(dd->value);
- Entity *e = dd->entity;
- String name = e->token.string;
- TokenPos pos = e->token.pos;
-
- irDebugInfo **lookup_di = map_get(&m->debug_info, hash_entity(e));
- if (lookup_di != nullptr) {
- GB_ASSERT_NOT_NULL(*lookup_di);
- irDebugInfo* local_var_di = *lookup_di;
-
- ir_write_str_lit(f, "call void @llvm.dbg.declare(");
- ir_write_str_lit(f, "metadata ");
- ir_print_type(f, m, vt);
- ir_write_byte(f, ' ');
- ir_print_value(f, m, dd->value, vt);
- ir_fprintf(f, ", metadata !%d", local_var_di->id);
- ir_write_str_lit(f, ", metadata !DIExpression())");
- ir_print_debug_location(f, m, value);
- }
- break;
- }
- }
-}
-
-
-void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
- set_procedure_abi_types(proc->type);
-
- if (proc->body == nullptr) {
- ir_write_str_lit(f, "declare ");
- // if (proc->tags & ProcTag_dll_import) {
- // ir_write_string(f, "dllimport ");
- // }
- } else {
- ir_write_byte(f, '\n');
- ir_write_str_lit(f, "define ");
- if (proc->is_export) {
- ir_write_str_lit(f, "dllexport ");
- }
- // if (!proc->is_export && !proc->is_foreign && !proc->is_entry_point) {
- // ir_write_string(f, "internal ");
- // }
- }
-
- TypeProc *proc_type = &proc->type->Proc;
-
- ir_print_calling_convention(f, m, proc_type->calling_convention);
-
- isize param_count = proc_type->param_count;
- isize result_count = proc_type->result_count;
- ir_print_proc_results(f, m, proc->type);
- ir_write_byte(f, ' ');
-
-// #ifndef GB_SYSTEM_WINDOWS
-#if 0
- if(uses_args)
- ir_write_string(f, "@.nix_argpatch_main");
- else
-#endif
- ir_print_encoded_global(f, proc->name, ir_print_is_proc_global(m, proc));
-
-
- isize param_index = 0;
-
- ir_write_byte(f, '(');
- if (proc_type->return_by_pointer) {
- ir_print_type(f, m, reduce_tuple_to_single_type(proc_type->results));
- ir_write_str_lit(f, "* sret noalias ");
- if (build_context.ODIN_OS == "darwin") {
- ir_fprintf(f, "byval ");
- }
- ir_write_str_lit(f, "%agg.result");
- param_index += 1;
- }
-
- if (param_count > 0) {
- TypeTuple *params = &proc_type->params->Tuple;
- isize parameter_index = 0;
- for (isize i = 0; i < param_count; i++, parameter_index++) {
- Entity *e = params->variables[i];
- Type *original_type = e->type;
- Type *abi_type = proc_type->abi_compat_params[i];
- if (e->kind != Entity_Variable) continue;
- if (param_index > 0) ir_write_string(f, str_lit(", "));
-
- if (i+1 == params->variables.count && proc_type->c_vararg) {
- ir_write_str_lit(f, " ...");
- } else {
- if (is_type_tuple(abi_type)) {
- for_array(j, abi_type->Tuple.variables) {
- if (j > 0) ir_write_string(f, str_lit(", "));
-
- Type *tft = abi_type->Tuple.variables[j]->type;
- ir_print_type(f, m, tft);
- if (e->flags&EntityFlag_NoAlias) {
- ir_write_str_lit(f, " noalias");
- }
- if (e->flags&EntityFlag_ByVal) {
- ir_write_str_lit(f, " byval");
- }
-
-
- if (proc->body != nullptr) {
- ir_fprintf(f, " %%_.%td", parameter_index+j);
- }
- }
- parameter_index += abi_type->Tuple.variables.count-1;
- param_index += abi_type->Tuple.variables.count-1;
- } else {
- ir_print_type(f, m, abi_type);
- if (e->flags&EntityFlag_NoAlias) {
- ir_write_str_lit(f, " noalias");
- }
- if (e->flags&EntityFlag_ByVal) {
- ir_write_str_lit(f, " byval");
- }
- if (proc->body != nullptr) {
- ir_fprintf(f, " %%_.%td", parameter_index);
- }
- }
- }
-
- param_index++;
- }
- }
- if (proc_type->calling_convention == ProcCC_Odin) {
- if (param_index > 0) ir_write_str_lit(f, ", ");
-
- ir_print_context_parameter_prefix(f, m);
- ir_write_str_lit(f, "%__.context_ptr");
- }
-
- ir_write_str_lit(f, ") ");
-
- switch (proc->inlining) {
- default:
- ir_fprintf(f, "#0 ");
- break;
- case ProcInlining_inline:
- ir_write_str_lit(f, "alwaysinline ");
- ir_fprintf(f, "#1 ");
- break;
- case ProcInlining_no_inline:
- ir_write_str_lit(f, "noinline ");
- ir_fprintf(f, "#2 ");
- break;
- }
-
- if (proc_type->diverging) {
- ir_write_str_lit(f, "noreturn ");
- }
-
- if (m->generate_debug_info && proc->entity != nullptr && proc->body != nullptr) {
- irDebugInfo **di_ = map_get(&proc->module->debug_info, hash_pointer(proc->entity));
- if (di_ != nullptr) {
- irDebugInfo *di = *di_;
- GB_ASSERT(di->kind == irDebugInfo_Proc);
- ir_fprintf(f, "!dbg !%d ", di->id); // TODO(lachsinc): !dbg
- }
- }
-
-
-
- if (proc->body != nullptr) {
- // ir_fprintf(f, "nounwind uwtable {\n");
-
- ir_write_str_lit(f, "{\n");
- for_array(i, proc->blocks) {
- irBlock *block = proc->blocks[i];
-
- if (i > 0) ir_write_byte(f, '\n');
- ir_print_block_name(f, block);
- ir_write_str_lit(f, ":\n");
-
- for_array(j, block->instrs) {
- irValue *value = block->instrs[j];
- ir_print_instr(f, m, value);
- }
- }
- ir_write_str_lit(f, "}\n");
- } else {
- ir_write_byte(f, '\n');
- }
-
- for_array(i, proc->children) {
- ir_print_proc(f, m, proc->children[i]);
- }
-}
-
-
-void ir_print_type_name(irFileBuffer *f, irModule *m, irValue *v) {
- GB_ASSERT(v->kind == irValue_TypeName);
- Type *t = base_type(v->TypeName.type);
-
- ir_print_encoded_local(f, v->TypeName.name);
- ir_write_string(f, str_lit(" = type "));
-
-
- switch (t->kind) {
- case Type_Union:
- if (t->Union.variants.count == 0) {
- ir_write_string(f, str_lit("{}"));
- } else {
- ir_print_type(f, m, t);
- }
- break;
- case Type_Struct:
- if (t->Struct.fields.count == 0) {
- if (t->Struct.is_packed) {
- ir_write_byte(f, '<');
- }
- ir_write_byte(f, '{');
- if (t->Struct.custom_align > 0) {
- ir_print_alignment_prefix_hack(f, t->Struct.custom_align);
- }
- ir_write_byte(f, '}');
- if (t->Struct.is_packed) {
- ir_write_byte(f, '>');
- }
- } else {
- ir_print_type(f, m, t);
- }
- break;
- default:
- ir_print_type(f, m, t);
- break;
- }
-
- ir_write_byte(f, '\n');
-}
-
-bool ir_print_global_type_allowed(Type *t) {
- if (t == nullptr) {
- return true;
- }
- t = core_type(t);
- switch (t->kind) {
- case Type_DynamicArray:
- case Type_Map:
- case Type_Union:
- return false;
- }
-
- return true;
-}
-
-void print_llvm_ir(irGen *ir) {
- irModule *m = &ir->module;
-
- irFileBuffer buf = {}, *f = &buf;
- ir_file_buffer_init(f, &ir->output_file);
- defer (ir_file_buffer_destroy(f));
-
- i32 word_bits = cast(i32)(8*build_context.word_size);
- if (build_context.ODIN_OS == "darwin") {
- GB_ASSERT(word_bits == 64);
- ir_write_str_lit(f, "target datalayout = \"e-m:o-i64:64-f80:128-n8:16:32:64-S128\"\n");
- ir_write_str_lit(f, "target triple = \"x86_64-apple-macosx10.8\"\n");
- ir_write_str_lit(f, "\n");
- } else if (build_context.ODIN_OS == "windows") {
- ir_fprintf(f, "target triple = \"x86%s-pc-windows-msvc\"\n\n", word_bits == 64 ? "_64" : "");
- if (word_bits == 64 && build_context.metrics.arch == TargetArch_amd64) {
- ir_fprintf(f, "target datalayout = \"e-m:w-i64:64-f80:128-n8:16:32:64-S128\"\n\n");
- }
- }
-
- ir_print_encoded_local(f, str_lit("..opaque"));
- ir_write_str_lit(f, " = type {};\n");
- ir_print_encoded_local(f, str_lit("..string"));
- ir_write_str_lit(f, " = type {i8*, ");
- ir_print_type(f, m, t_int);
- ir_write_str_lit(f, "} ; Basic_string\n");
- ir_print_encoded_local(f, str_lit("..rawptr"));
- ir_write_str_lit(f, " = type i8* ; Basic_rawptr\n");
-
- ir_print_encoded_local(f, str_lit("..complex32"));
- ir_write_str_lit(f, " = type {half, half} ; Basic_complex32\n");
- ir_print_encoded_local(f, str_lit("..complex64"));
- ir_write_str_lit(f, " = type {float, float} ; Basic_complex64\n");
- ir_print_encoded_local(f, str_lit("..complex128"));
- ir_write_str_lit(f, " = type {double, double} ; Basic_complex128\n");
-
- ir_print_encoded_local(f, str_lit("..quaternion64"));
- ir_write_str_lit(f, " = type {half, half, half, half} ; Basic_quaternion64\n");
- ir_print_encoded_local(f, str_lit("..quaternion128"));
- ir_write_str_lit(f, " = type {float, float, float, float} ; Basic_quaternion128\n");
- ir_print_encoded_local(f, str_lit("..quaternion256"));
- ir_write_str_lit(f, " = type {double, double, double, double} ; Basic_quaternion256\n");
-
- ir_print_encoded_local(f, str_lit("..typeid"));
- ir_write_str_lit(f, " = type ");
- ir_print_type(f, m, t_uintptr);
- ir_write_str_lit(f, " ; Basic_typeid\n");
-
- ir_print_encoded_local(f, str_lit("..any"));
- ir_write_str_lit(f, " = type {");
- ir_print_type(f, m, t_rawptr);
- ir_write_str_lit(f, ", ");
- ir_print_type(f, m, t_typeid);
- ir_write_str_lit(f, "} ; Basic_any\n");
-
- ir_write_str_lit(f, "declare void @llvm.dbg.declare(metadata, metadata, metadata) #3 \n");
-
- if (string_map_get(&m->members, str_lit("llvm.bswap.i16")) == nullptr) {
- ir_write_str_lit(f, "declare i16 @llvm.bswap.i16(i16) \n");
- }
- if (string_map_get(&m->members, str_lit("llvm.bswap.i32")) == nullptr) {
- ir_write_str_lit(f, "declare i32 @llvm.bswap.i32(i32) \n");
- }
- if (string_map_get(&m->members, str_lit("llvm.bswap.i64")) == nullptr) {
- ir_write_str_lit(f, "declare i64 @llvm.bswap.i64(i64) \n");
- }
- if (string_map_get(&m->members, str_lit("llvm.bswap.i128")) == nullptr) {
- ir_write_str_lit(f, "declare i128 @llvm.bswap.i128(i128) \n");
- }
- ir_write_byte(f, '\n');
-
-
- for_array(member_index, m->members.entries) {
- auto *entry = &m->members.entries[member_index];
- irValue *v = entry->value;
- if (v->kind != irValue_TypeName) {
- continue;
- }
- ir_print_type_name(f, m, v);
- }
-
- ir_write_byte(f, '\n');
-
- bool dll_main_found = false;
-
- // NOTE(bill): Print foreign prototypes first
- for_array(member_index, m->members.entries) {
- auto *entry = &m->members.entries[member_index];
- irValue *v = entry->value;
- if (v->kind != irValue_Proc) {
- continue;
- }
-
- if (v->Proc.body == nullptr) {
- ir_print_proc(f, m, &v->Proc);
- }
- }
-
- if (ir->print_chkstk) {
- // TODO(bill): Clean up this code
- ir_write_str_lit(f, "\n\n");
- ir_write_str_lit(f, "define void @__chkstk() #0 {\n");
- ir_write_str_lit(f, "\tcall void asm sideeffect \"push %rcx \\09\\0Apush %rax \\09\\0Acmp $$0x1000,%rax \\09\\0Alea 24(%rsp),%rcx \\09\\0Ajb 1f \\09\\0A2: \\09\\0Asub $$0x1000,%rcx \\09\\0Aorl $$0,(%rcx) \\09\\0Asub $$0x1000,%rax \\09\\0Acmp $$0x1000,%rax \\09\\0Aja 2b \\09\\0A1: \\09\\0Asub %rax,%rcx \\09\\0Aorl $$0,(%rcx) \\09\\0Apop %rax \\09\\0Apop %rcx \\09\\0Aret \\09\\0A\", \"~{dirflag},~{fpsr},~{flags}\"()\n");
- ir_write_str_lit(f, "\tret void\n");
- ir_write_str_lit(f, "}\n\n");
- }
-
- // NOTE(bill): Print procedures with bodies next
- for_array(member_index, m->members.entries) {
- auto *entry = &m->members.entries[member_index];
- irValue *v = entry->value;
- if (v->kind != irValue_Proc) {
- continue;
- }
-
- if (v->Proc.body != nullptr) {
- ir_print_proc(f, m, &v->Proc);
- }
- }
-
- for_array(member_index, m->members.entries) {
- auto *entry = &m->members.entries[member_index];
- irValue *v = entry->value;
- if (v->kind != irValue_Global) {
- continue;
- }
- irValueGlobal *g = &v->Global;
- Scope *scope = g->entity->scope;
- bool in_global_scope = false;
- if (scope != nullptr) {
- // TODO(bill): Fix this rule. What should it be?
- in_global_scope = (scope->flags & ScopeFlag_Global) != 0;
- }
-
- ir_print_encoded_global(f, ir_get_global_name(m, v), in_global_scope);
- ir_write_string(f, str_lit(" = "));
- if (g->is_foreign) {
- ir_write_string(f, str_lit("external "));
- }
- if (g->is_export) {
- ir_write_string(f, str_lit("dllexport "));
- }
-
- if (g->is_private) {
- ir_write_string(f, str_lit("private "));
- } else if (g->is_internal) {
- ir_write_string(f, str_lit("internal "));
- }
- if (g->thread_local_model.len > 0) {
- String model = g->thread_local_model;
- if (model == "default") {
- ir_write_string(f, str_lit("thread_local "));
- } else {
- ir_fprintf(f, "thread_local(%.*s) ", LIT(model));
-
- }
- }
- if (g->is_constant) {
- if (g->is_unnamed_addr) {
- ir_write_string(f, str_lit("unnamed_addr "));
- }
- ir_write_string(f, str_lit("constant "));
- } else {
- ir_write_string(f, str_lit("global "));
- }
-
-
- ir_print_type(f, m, g->entity->type);
- ir_write_byte(f, ' ');
- if (!g->is_foreign) {
- if (g->value != nullptr && ir_print_global_type_allowed(g->entity->type)) {
- ir_print_value(f, m, g->value, g->entity->type);
- } else {
- ir_write_string(f, str_lit("zeroinitializer"));
- }
- if (m->generate_debug_info) {
- irDebugInfo **di_lookup = map_get(&m->debug_info, hash_entity(g->entity));
- if (di_lookup != nullptr) {
- irDebugInfo *di = *di_lookup;
- GB_ASSERT(di);
- GB_ASSERT(di->kind == irDebugInfo_GlobalVariableExpression);
- ir_fprintf(f, ", !dbg !%d", di->id);
- }
- }
- }
- ir_write_byte(f, '\n');
- }
-
- // TODO(lachsinc): Attribute map inside ir module?
- ir_fprintf(f, "attributes #0 = {nounwind uwtable}\n");
- ir_fprintf(f, "attributes #1 = {nounwind alwaysinline uwtable}\n");
- ir_fprintf(f, "attributes #2 = {nounwind noinline optnone uwtable}\n");
- ir_fprintf(f, "attributes #3 = {nounwind readnone}\n");
-
- if (m->generate_debug_info) {
- ir_write_byte(f, '\n');
-
- i32 diec = cast(i32)m->debug_info.entries.count;
-
- i32 di_version = diec+1;
- i32 di_debug_info = diec+2;
- i32 di_code_view = diec+3;
- i32 di_wchar_size = diec+4;
-
-
-
- ir_fprintf(f, "!llvm.dbg.cu = !{!%d}\n", m->debug_compile_unit->id);
- ir_fprintf(f, "!llvm.ident = !{!%d}\n", di_version);
- ir_fprintf(f, "!llvm.module.flags = !{!%d, !%d, !%d}\n", di_debug_info, di_code_view, di_wchar_size);
-
- ir_fprintf(f, "!0 = !{}\n");
-
- for_array(di_index, m->debug_info.entries) {
- irDebugInfo *di = m->debug_info.entries[di_index].value;
- GB_ASSERT_MSG(di != nullptr, "Invalid irDebugInfo");
- ir_fprintf(f, "!%d = ", di->id);
- switch (di->kind) {
- case irDebugInfo_CompileUnit: {
- irDebugInfo **found = map_get(&m->debug_info, hash_pointer(di->CompileUnit.file));
- GB_ASSERT_MSG(found != nullptr, "Missing debug info for: %.*s\n", LIT(di->CompileUnit.file->fullpath));
- irDebugInfo *file = *found;
- ir_fprintf(f,
- "distinct !DICompileUnit("
- "language: DW_LANG_C_plus_plus" // Is this good enough?
- ", file: !%d"
- ", producer: \"Odin %.*s\""
- ", runtimeVersion: 0"
- ", isOptimized: false"
- ", emissionKind: FullDebug"
- ", retainedTypes: !0" // TODO(lachsinc)
- ", enums: !%d"
- ", globals: !%d"
- ")",
- file->id,
- LIT(build_context.ODIN_VERSION),
- m->debug_compile_unit->CompileUnit.enums->id,
- m->debug_compile_unit->CompileUnit.globals->id);
- break;
- }
- case irDebugInfo_File:
- ir_fprintf(f, "!DIFile(filename: \""); ir_print_escape_path(f, di->File.filename);
- ir_fprintf(f, "\", directory: \""); ir_print_escape_path(f, di->File.directory);
- ir_fprintf(f, "\"");
- ir_fprintf(f, ")");
- break;
- case irDebugInfo_Proc:
- // TODO(lachsinc): We need to store scope info inside di, not just file info, for procs.
- // Should all subprograms have distinct ??
- ir_fprintf(f, "distinct !DISubprogram("
- "name: \"%.*s\""
- ", linkageName: \"%.*s\""
- ", scope: !%d"
- ", file: !%d"
- ", line: %d"
- ", scopeLine: %d"
- ", isDefinition: true"
- ", isLocal: false" // TODO(lachsinc): Is this fine?
- ", flags: DIFlagPrototyped"
- ", isOptimized: false"
- ", unit: !%d"
- ", type: !%d",
- LIT(di->Proc.entity->token.string),
- LIT(di->Proc.name),
- di->Proc.file->id, // TODO(lachsinc): HACK For now lets pretend all procs scope's == file.
- di->Proc.file->id,
- di->Proc.pos.line,
- di->Proc.pos.line, // NOTE(lachsinc): Assume scopeLine always same as line.
- m->debug_compile_unit->id,
- di->Proc.type->id);
- ir_write_byte(f, ')'); // !DISubprogram(
- break;
- case irDebugInfo_ProcType:
- ir_fprintf(f, "!DISubroutineType(types: !%d)",
- di->ProcType.types->id);
- break;
- case irDebugInfo_Location:
- GB_ASSERT_NOT_NULL(di->Location.scope);
- ir_fprintf(f, "!DILocation("
- "line: %d"
- ", column: %d"
- ", scope: !%d)",
- di->Location.pos.line,
- di->Location.pos.column,
- di->Location.scope->id);
- break;
- case irDebugInfo_LexicalBlock:
- GB_ASSERT_NOT_NULL(di->LexicalBlock.file);
- GB_ASSERT_NOT_NULL(di->LexicalBlock.scope);
- ir_fprintf(f, "distinct !DILexicalBlock("
- "line: %d"
- ", column: %d"
- ", file: !%d"
- ", scope: !%d)",
- di->LexicalBlock.pos.line,
- di->LexicalBlock.pos.column,
- di->LexicalBlock.file->id,
- di->LexicalBlock.scope->id);
- break;
- case irDebugInfo_GlobalVariableExpression: {
- ir_fprintf(f, "!DIGlobalVariableExpression("
- "var: !%d"
- ", expr: !DIExpression(",
- di->GlobalVariableExpression.var->id);
- if (di->GlobalVariableExpression.var->GlobalVariable.variable->Global.is_constant) {
- ir_write_str_lit(f, "DW_OP_constu, ");
- ir_print_value(f, m, di->GlobalVariable.variable, ir_type(di->GlobalVariable.variable));
- ir_write_str_lit(f, ", DW_OP_stack_value");
- } else {
- // NOTE(lachsinc): non-const globals expect empty "!DIExpression()"
- }
- ir_write_byte(f, ')'); // !DIExpression(
- ir_write_byte(f, ')'); // !DIGlobalVariableExpression(
- break;
- }
- case irDebugInfo_GlobalVariable: {
- ir_fprintf(f, "distinct !DIGlobalVariable("
- "name: \"%.*s\""
- ", scope: !%d"
- ", file: !%d"
- ", line: %d"
- ", type: !%d"
- ", isLocal: true" // TODO(lachsinc): Check locality ??
- ", isDefinition: true)", // TODO(lachsinc): ??
- LIT(di->GlobalVariable.name),
- di->GlobalVariable.scope->id,
- di->GlobalVariable.file->id,
- di->GlobalVariable.pos.line,
- di->GlobalVariable.type->id);
- break;
- }
- case irDebugInfo_LocalVariable: {
- ir_fprintf(f, "!DILocalVariable("
- "scope: !%d"
- ", file: !%d"
- ", line: %d"
- ", type: !%d",
- di->LocalVariable.scope->id,
- di->LocalVariable.file->id,
- di->LocalVariable.pos.line,
- di->LocalVariable.type->id);
- if (di->DerivedType.name.len > 0) {
- ir_fprintf(f, ", name: \"%.*s\"", LIT(di->LocalVariable.name));
- }
- if (di->LocalVariable.arg > 0) {
- ir_fprintf(f, ", arg: %d", di->LocalVariable.arg);
- }
- ir_write_byte(f, ')');
- break;
- }
- case irDebugInfo_BasicType:
- ir_fprintf(f, "!DIBasicType("
- "name: \"%.*s\""
- ", size: %d"
- ", encoding: ",
- LIT(di->BasicType.name),
- di->BasicType.size);
- ir_print_debug_encoding(f, irDebugInfo_BasicType, di->BasicType.encoding);
- ir_write_byte(f, ')');
- break;
- case irDebugInfo_DerivedType: {
- if (di->DerivedType.tag == irDebugBasicEncoding_member) {
- // NOTE(lachsinc): We crash llvm super hard if we don't specify a name :)
- Type *t = di->DerivedType.type;
- GB_ASSERT_MSG(di->DerivedType.name.len > 0, "%s", type_to_string(di->DerivedType.type));
- }
- ir_write_str_lit(f, "!DIDerivedType(tag: ");
- ir_print_debug_encoding(f, irDebugInfo_DerivedType, di->DerivedType.tag);
- if (di->DerivedType.name.len > 0) {
- ir_fprintf(f, ", name: \"%.*s\"", LIT(di->DerivedType.name));
- }
- if (di->DerivedType.base_type != nullptr) {
- ir_fprintf(f, ", baseType: !%d", di->DerivedType.base_type->id);
- } else {
- ir_write_str_lit(f, ", baseType: null"); // Valid/required for rawptr
- }
- if (di->DerivedType.size > 0) ir_fprintf(f, ", size: %d", di->DerivedType.size);
- if (di->DerivedType.align > 0) ir_fprintf(f, ", align: %d", di->DerivedType.align);
- if (di->DerivedType.offset > 0) ir_fprintf(f, ", offset: %d", di->DerivedType.offset);
- if (di->DerivedType.flags > 0) {
- // TODO(lachsinc): Handle in a more generic manner.
- if (di->DerivedType.flags & irDebugInfoFlag_Bitfield) ir_write_str_lit(f, ", flags: DIFlagBitField, extraData: i64 0");
- }
- ir_write_byte(f, ')');
- break;
- }
- case irDebugInfo_CompositeType: {
- if (di->CompositeType.tag == irDebugBasicEncoding_array_type) {
- GB_ASSERT_NOT_NULL(di->CompositeType.base_type);
- GB_ASSERT(di->CompositeType.array_count >= 0);
- GB_ASSERT(di->CompositeType.name.len == 0);
- GB_ASSERT(di->CompositeType.size >= 0);
- }
-
- if (di->CompositeType.tag == irDebugBasicEncoding_union_type) {
- GB_ASSERT_NOT_NULL(di->CompositeType.file); // Union _requires_ file to be valid.
- }
-
- ir_write_str_lit(f, "!DICompositeType(tag: ");
- ir_print_debug_encoding(f, irDebugInfo_CompositeType, di->CompositeType.tag);
- if (di->CompositeType.name.len > 0) {
- ir_fprintf(f, ", name: \"%.*s\"", LIT(di->CompositeType.name));
- }
- if (di->CompositeType.scope != nullptr) {
- ir_fprintf(f, ", scope: !%d", di->CompositeType.scope->id);
- }
- if (di->CompositeType.file != nullptr) {
- ir_fprintf(f, ", file: !%d"
- ", line: %d",
- di->CompositeType.file->id,
- di->CompositeType.pos.line);
- }
- if (di->CompositeType.size > 0) ir_fprintf(f, ", size: %d", di->CompositeType.size);
- if (di->CompositeType.align > 0) ir_fprintf(f, ", align: %d", di->CompositeType.align);
- if (di->CompositeType.base_type != nullptr) {
- GB_ASSERT(di->CompositeType.tag != irDebugBasicEncoding_structure_type);
- GB_ASSERT(di->CompositeType.tag != irDebugBasicEncoding_union_type);
- ir_fprintf(f, ", baseType: !%d", di->CompositeType.base_type->id);
- }
- if (di->CompositeType.tag == irDebugBasicEncoding_array_type) {
- ir_fprintf(f, ", elements: !{!DISubrange(count: %d)}", di->CompositeType.array_count);
- } else {
- if (di->CompositeType.elements != nullptr) {
- ir_fprintf(f, ", elements: !%d", di->CompositeType.elements->id);
- }
- }
- ir_write_byte(f, ')');
- break;
- }
- case irDebugInfo_Enumerator: {
- ir_fprintf(f, "!DIEnumerator("
- "name: \"%.*s\""
- ", value: %lld)",
- LIT(di->Enumerator.name),
- di->Enumerator.value);
- break;
- }
- case irDebugInfo_DebugInfoArray:
- ir_fprintf(f, "!{");
- for_array(element_index, di->DebugInfoArray.elements) {
- irDebugInfo *elem = di->DebugInfoArray.elements[element_index];
- if (element_index > 0) ir_write_str_lit(f, ", ");
- if (elem != nullptr) {
- ir_fprintf(f, "!%d", elem->id);
- } else {
- ir_fprintf(f, "null"); // NOTE(lachsinc): Proc's can contain "nullptr" entries to represent void return values.
- }
- }
- ir_write_byte(f, '}');
- break;
-
- default:
- GB_PANIC("Unhandled irDebugInfo kind %d", di->kind);
- break;
- }
-
- ir_write_byte(f, '\n');
- }
-
-
- ir_fprintf(f, "!%d = !{!\"Odin version %.*s \"}\n", di_version, LIT(build_context.ODIN_VERSION));
- ir_fprintf(f, "!%d = !{i32 2, !\"Debug Info Version\", i32 3}\n", di_debug_info);
- ir_fprintf(f, "!%d = !{i32 2, !\"CodeView\", i32 1}\n", di_code_view);
- ir_fprintf(f, "!%d = !{i32 1, !\"wchar_size\", i32 2}\n", di_wchar_size);
- }
-}