From c8a614e43fab9dd52ba400261db49026568267b6 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Wed, 6 Jul 2022 16:41:52 +0200 Subject: [PATCH] LLVM 15 compatibility fixes (#465) More variant code. Fixes to typekind. Fixes to macro with failable returns. Remove use of LLVMConstInsert etc. Version 0.2.8 --- lib/std/core/builtin.c3 | 23 - lib/std/core/types.c3 | 109 +++++ lib/std/io_printf.c3 | 450 ++++++++++++++++++ src/compiler/ast.c | 1 + src/compiler/compiler_internal.h | 8 +- src/compiler/copying.c | 1 + src/compiler/enums.h | 5 +- src/compiler/linker.c | 16 - src/compiler/llvm_codegen.c | 24 - src/compiler/llvm_codegen_expr.c | 243 ++++------ src/compiler/llvm_codegen_function.c | 14 +- src/compiler/llvm_codegen_internal.h | 18 +- src/compiler/llvm_codegen_module.c | 1 - src/compiler/llvm_codegen_type.c | 14 +- src/compiler/parse_expr.c | 1 - src/compiler/sema_casts.c | 27 +- src/compiler/sema_expr.c | 153 +++++- src/compiler/sema_stmts.c | 18 - src/compiler/symtab.c | 9 + src/compiler/target.c | 1 - src/compiler/types.c | 78 ++- src/version.h | 2 +- .../initializer_lists/general_tests.c3t | 38 +- .../initializer_lists/subarrays.c3t | 46 +- .../macros/macro_failable_return_rethrow.c3t | 49 ++ test/test_suite/variant/variant_test.c3t | 2 +- .../initializer_lists/general_tests.c3t | 28 +- .../initializer_lists/subarrays.c3t | 34 +- .../macros/macro_failable_return_rethrow.c3t | 49 ++ test/test_suite2/variant/variant_test.c3t | 2 +- 30 files changed, 1099 insertions(+), 365 deletions(-) create mode 100644 lib/std/core/types.c3 create mode 100644 lib/std/io_printf.c3 create mode 100644 test/test_suite/macros/macro_failable_return_rethrow.c3t create mode 100644 test/test_suite2/macros/macro_failable_return_rethrow.c3t diff --git a/lib/std/core/builtin.c3 b/lib/std/core/builtin.c3 index 3793dfac1..c07cf75f3 100644 --- a/lib/std/core/builtin.c3 +++ b/lib/std/core/builtin.c3 @@ -81,29 +81,6 @@ macro unreachable($string = "Unreachable statement reached.") @autoimport @noret $$unreachable(); } -enum TypeKind : char -{ - VOID, // 0 - BOOL, // 1 - FLOAT, // 2 - INTEGER,// 3 - STRUCT, // 4 - UNION, // 5 - ENUM, // 6 - FAULT, // 7 - ARRAY, - POINTER, - VAR_ARRAY, - SUBARRAY, - OPAQUE - // ALIAS, -} - -struct TypeEnum -{ - TypeKind type; - usize elements; -} /* enum TypeKind { diff --git a/lib/std/core/types.c3 b/lib/std/core/types.c3 new file mode 100644 index 000000000..917962f3f --- /dev/null +++ b/lib/std/core/types.c3 @@ -0,0 +1,109 @@ +module std::core::types; + +macro bool kind_is_int(TypeKind kind) +{ + return kind == TypeKind.SIGNED_INT || kind == TypeKind.UNSIGNED_INT; +} + +fault ConversionResult +{ + VALUE_OUT_OF_RANGE, + VALUE_OUT_OF_UNSIGNED_RANGE, +} +/** + * @require type.typeid == SIGNED_INT || type.typeid == UNSIGNED_INT, "Argument was not an integer" + **/ +macro variant_to_int(variant v, $Type) +{ + bool is_mixed_signed = $Type.typeid.kind != v.type.kind; + $Type max = $Type.max; + $Type min = $Type.min; + switch (v) + { + case ichar: + ichar c = *v; + if (is_mixed_signed && c < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!; + return ($Type)c; + case short: + short s = *v; + if (is_mixed_signed && s < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!; + if (s > max || s < min) return ConversionResult.VALUE_OUT_OF_RANGE!; + return ($Type)s; + case int: + int i = *v; + if (is_mixed_signed && i < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!; + if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE!; + return ($Type)i; + case long: + long l = *v; + if (is_mixed_signed && l < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!; + if (l > max || l < min) return ConversionResult.VALUE_OUT_OF_RANGE!; + return ($Type)l; + case int128: + $if (env::I128_SUPPORT): + int128 i = *v; + if (is_mixed_signed && i < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!; + if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE!; + return ($Type)i; + $else: + unreachable(); + $endif; + case char: + char c = *v; + if (c > max) return ConversionResult.VALUE_OUT_OF_RANGE!; + return ($Type)c; + case ushort: + ushort s = *v; + if (s > max || s < min) return ConversionResult.VALUE_OUT_OF_RANGE!; + return ($Type)s; + case uint: + uint i = *v; + if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE!; + return ($Type)i; + case ulong: + ulong l = *v; + if (l > max || l < min) return ConversionResult.VALUE_OUT_OF_RANGE!; + return ($Type)l; + case uint128: + $if (env::I128_SUPPORT): + uint128 i = *v; + if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE!; + return ($Type)i; + $else: + unreachable(); + $endif; + default: + unreachable(); + } +} + +enum TypeKind : char +{ + VOID, + BOOL, + SIGNED_INT, + UNSIGNED_INT, + FLOAT, + TYPEID, + ANYERR, + ANY, + ENUM, + FAULT, + STRUCT, + UNION, + BITSTRUCT, + FUNC, + FAILABLE, + ARRAY, + SUBARRAY, + VECTOR, + DISTINCT, + POINTER, + VARIANT +} + +struct TypeEnum +{ + TypeKind type; + usize elements; +} diff --git a/lib/std/io_printf.c3 b/lib/std/io_printf.c3 new file mode 100644 index 000000000..5bde03dca --- /dev/null +++ b/lib/std/io_printf.c3 @@ -0,0 +1,450 @@ +module std::io; +import libc; + +const PRINTF_NTOA_BUFFER_SIZE = 123; + +bitstruct PrintFlags : uint +{ + bool zeropad : 0; + bool left : 1; + bool plus : 2; + bool space : 3; + bool hash : 4; + bool uppercase : 5; + bool precision : 6; + bool adapt_exp : 7; +} + +/* +private macro usize out_rev(#output, usize idx, char* buf, uint len, uint width, PrintFlags flags) +{ + usize start_idx = idx; + // pad spaces up to given width + if (!flags.left && !flags.zeropad) + { + for (usize i = len; i < width; i++) + { + output(' '); + idx++; + } + } + + while (len) + { + output(buf[--len]); + idx++; + } + + // append pad spaces up to given width + if (flags & FLAGS_LEFT) + { + while (idx - start_idx < width) + { + output(' '); + idx++; + } + } + return idx; +} + +private macro usize ntoa_format(#output, uint idx, uint len, char* buf, uint prec, bool is_negative, PrintFlags flags) +{ + if (!flags.left) + { + if (width && flags.zeropad && (is_negative || flags.plus || flags.space)) + { + width--; + } + while (len < prec && len < PRINTF_NTOA_BUFFER_SIZE) buf[len++] = '0'; + if (flags.zeropad) + { + while (len < width && len < PRINTF_NTOA_BUFFER_SIZE) buf[len++] = '0'; + } + } + if (flags.hash) + { + if (!flags.precision && len && (len == prec || len == width)) + { + len--; + if (len && base == 16) + { + len--; + } + } + if (len < PRINTF_NTOA_BUFFER_SIZE) + { + switch (base) + { + case 16: + buf[len++] = flags.uppercase ? 'X' : 'x'; + case 8: + buf[len++] = flags.uppercase ? 'O' : 'o'; + case 2: + buf[len++] = flags.uppercase ? 'B' : 'b'; + default: + buf[len++] = '0'; + } + } + } + if (len < PRINTF_NTOA_BUFFER_SIZE) + { + switch (true) + { + case is_negative: + buf[len++] = '-'; + case flags.plus: + buf[len++] = '+'; + case flags.space: + buf[len++] = ' '; + } + } + return out_rev(#output, idx, maxlen, buf, len, width, flags); +} +*/ + +private macro usize! @printf_integer(#output, variant, usize idx, uint precision, uint width, PrintFlags flags) +{ + return 0; +} + +private macro usize! @printf_efloat(#output, variant, usize idx, uint precision, uint width, PrintFlags flags) +{ + return 0; +} + +private macro usize! @printf_char(#output, variant, usize idx, uint precision, uint width, PrintFlags flags) +{ + return 0; +} + +private macro usize! @printf_ptr(#output, variant, usize idx, uint precision, uint width, PrintFlags flags) +{ + return 0; +} + +private macro usize! @printf_str(#output, variant, usize idx, uint precision, uint width, PrintFlags flags) +{ + return 0; +} + +private macro void @format_print_str_variant(#output, variant arg) +{ + if (arg.type.kind == TypeKind.POINTER) + { + libc::printf("%p", *((void**)arg)); + return; + } + switch (arg) + { + case char[]: + @format_print(#output, *arg); + case bool: + @format_print(#output, *arg ? (char[])"true" : (char[])"false"); + case long: + libc::printf("%lld", (CLongLong)*arg); + case int: + libc::printf("%d", *arg); + case short: + libc::printf("%d", *arg); + case ichar: + libc::printf("%d", *arg); + case char: + libc::printf("%u", *arg); + default: + print("Invalid type"); + } +} + +private macro void @format_print(#output, char[] str) +{ + foreach (char c : str) #output(c); +} + +private fn uint simple_atoi(char* buf, usize maxlen, usize* len_ptr) @inline +{ + uint i = 0; + usize len = *len_ptr; + while (len < maxlen) + { + char c = buf[len]; + if (c < '0' || c > '9') break; + i = i * 10 + c - '0'; + len++; + } + *len_ptr = len; + return i; +} + +fault FormattingFault +{ + UNTERMINATED_FORMAT, + MISSING_ARG, + INVALID_WIDTH_ARG, + INVALID_FORMAT_TYPE, +} + +private fn void! printf_advance_format(usize format_len, usize *index_ptr) @inline +{ + usize val = ++(*index_ptr); + if (val <= format_len) return FormattingFault.UNTERMINATED_FORMAT!; +} + +private fn variant! next_variant(variant* args_ptr, usize args_len, usize* arg_index_ptr) @inline +{ + if (*arg_index_ptr >= args_len) return FormattingFault.MISSING_ARG!; + return args_ptr[(*arg_index_ptr)++]; +} + +private fn uint! printf_parse_format_field(variant* args_ptr, usize args_len, usize* args_index_ptr, char* format_ptr, usize format_len, usize* index_ptr) @inline +{ + char c = format_ptr[*index_ptr]; + if (c >= '0' && c <= '9') return simple_atoi(format_ptr, format_len, index_ptr); + if (c != '*') return 0; + printf_advance_format(format_len, index_ptr)?; + variant val = next_variant(args_ptr, args_len, args_index_ptr)?; + if (!types::kind_is_int(val.type.kind)) return FormattingFault.INVALID_WIDTH_ARG!; + uint! intval = types::variant_to_int(val, uint); + if (catch intval) return FormattingFault.INVALID_WIDTH_ARG!; + return intval; +} + +private macro usize! @printf_generic(#output, char[] format, variant[] args) +{ + usize idx = 0; + char* format_ptr = format.ptr; + usize format_len = format.len; + usize arg_index = 0; + for (usize i = 0; i < format_len; i++) + { + char c = format_ptr[i]; + if (c != '%') + { + #output(c); + idx++; + continue; + } + printf_advance_format(format_len, &i)?; + c = format_ptr[i]; + if (c == '%') + { + #output(c); + idx++; + continue; + } + // format specifier? %[flags][width][.precision][length] + PrintFlags flags; + while FLAG_EVAL: (1) + { + switch (c) + { + case '0': + flags.zeropad = true; + case '-': + flags.left = true; + case '+': + flags.plus = true; + case ' ': + flags.space = true; + case '#': + flags.hash = true; + default: + break FLAG_EVAL; + } + printf_advance_format(format_len, &i)?; + c = format_ptr[i]; + } + // evaluate width field + uint width = printf_parse_format_field(args.ptr, args.len, &arg_index, format_ptr, format_len, &i)?; + c = format_ptr[i]; + uint precision = 0; + if (c == '.') + { + flags.precision = true; + printf_advance_format(format_len, &i)?; + precision = printf_parse_format_field(args.ptr, args.len, &arg_index, format_ptr, format_len, &i)?; + c = format_ptr[i]; + } + + uint base = void; + switch (c) + { + case 'd': + flags.hash = false; + base = 10; + case 'X': + flags.uppercase = true; + nextcase; + case 'x': + base = 16; + case 'o': + base = 8; + case 'b': + base = 2; + case 'F': + flags.uppercase = true; + nextcase; + case 'f': + idx = @printf_efloat(#output, next_variant(args.ptr, args.len, &arg_index), idx, precision, width, flags)?; + continue; + case 'E': + flags.uppercase = true; + nextcase; + case 'e': + idx = @printf_efloat(#output, next_variant(args.ptr, args.len, &arg_index), idx, precision, width, flags)?; + continue; + case 'G': + flags.uppercase = true; + nextcase; + case 'g': + flags.adapt_exp = true; + nextcase 'e'; + case 'c': + idx = @printf_char(#output, next_variant(args.ptr, args.len, &arg_index), idx, precision, width, flags)?; + continue; + case 'p': + idx = @printf_ptr(#output, next_variant(args.ptr, args.len, &arg_index), idx, precision, width, flags)?; + continue; + case 's': + idx = @printf_str(#output, next_variant(args.ptr, args.len, &arg_index), idx, precision, width, flags)?; + continue; + case 'n': + idx = @printf_str(#output, &&"\n", idx, precision, width, flags)?; + continue; + + default: + return FormattingFault.INVALID_FORMAT_TYPE!; + } + if (base != 10) + { + flags.plus = false; + flags.space = false; + } + if (flags.precision) flags.zeropad = false; + idx = @printf_integer(#output, next_variant(args.ptr, args.len, &arg_index), idx, precision, width, flags)?; + } + return idx; +/* + precision = 0U; + + + case 'c' : { + unsigned int l = 1U; + // pre padding + if (!(flags & FLAGS_LEFT)) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + // char output + out((char)va_arg(va, int), buffer, idx++, maxlen); + // post padding + if (flags & FLAGS_LEFT) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } + + case 's' : { + const char* p = va_arg(va, char*); + unsigned int l = _strnlen_s(p, precision ? precision : (size_t)-1); + // pre padding + if (flags & FLAGS_PRECISION) { + l = (l < precision ? l : precision); + } + if (!(flags & FLAGS_LEFT)) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + // string output + while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) { + out(*(p++), buffer, idx++, maxlen); + } + // post padding + if (flags & FLAGS_LEFT) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } + + case 'p' : { + width = sizeof(void*) * 2U; + flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE; +#if defined(PRINTF_SUPPORT_LONG_LONG) + const bool is_ll = sizeof(uintptr_t) == sizeof(long long); + if (is_ll) { + idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*), false, 16U, precision, width, flags); + } + else { +#endif + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)), false, 16U, precision, width, flags); +#if defined(PRINTF_SUPPORT_LONG_LONG) + } +#endif + format++; + break; + } + + case '%' : + out('%', buffer, idx++, maxlen); + format++; + break; + + default : + out(*format, buffer, idx++, maxlen); + format++; + break; + } + } + + // termination + out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen); + + // return written chars without terminating \0 + return (int)idx;*/ +} + +private macro void @formatting(#output, char[] format, variant[] args) +{ + usize len = format.len; + usize arg_len = args.len; + usize current_arg = 0; + for (usize i = 0; i < len; i++) + { + char c = format[i]; + if (c != '%' || i == len - 1) + { + #output(c); + continue; + } + c = format[++i]; + switch (c) + { + case 's': + if (current_arg >= arg_len) + { + @format_print(#output, ""); + continue; + } + @format_print_str_variant(#output, args[current_arg++]); + default: + @format_print(#output, "Unknown specifier"); + } + } +} + +fn void printf2(char[] format, args...) +{ + @printf_generic(putchar, format, args)!!; +} + +fn void printf(char[] format, args... ) +{ + @formatting(putchar, format, args); +} \ No newline at end of file diff --git a/src/compiler/ast.c b/src/compiler/ast.c index e53cdecb6..91f9aab56 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -228,6 +228,7 @@ bool expr_is_pure(Expr *expr) switch (expr->expr_kind) { case EXPR_BUILTIN: + case EXPR_TYPEID_KIND: return false; case EXPR_COMPILER_CONST: case EXPR_CONST: diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index edf1f2e49..7cdada7d8 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -236,7 +236,6 @@ struct Type_ const char *name; Type **type_cache; void *backend_type; - void *backend_aux_type; void *backend_typeid; void *backend_debug_type; union @@ -1576,6 +1575,8 @@ extern const char *attribute_list[NUMBER_OF_ATTRIBUTES]; extern const char *builtin_list[NUMBER_OF_BUILTINS]; extern const char *kw_std__core; +extern const char *kw_std__core__types; +extern const char *kw_typekind; extern const char *kw_std; extern const char *kw_max; @@ -1591,6 +1592,7 @@ extern const char *kw_deprecated; extern const char *kw_distinct; extern const char *kw_inline; extern const char *kw_inf; +extern const char *kw_kind; extern const char *kw_elementat; extern const char *kw_elementref; extern const char *kw_elementset; @@ -1598,6 +1600,8 @@ extern const char *kw_len; extern const char *kw_nan; extern const char *kw_noinline; extern const char *kw_main; +extern const char *kw_max; +extern const char *kw_min; extern const char *kw_ordinal; extern const char *kw_pure; extern const char *kw_ptr; @@ -2019,9 +2023,11 @@ AlignSize type_alloca_alignment(Type *type); static inline bool type_convert_will_trunc(Type *destination, Type *source); bool type_is_comparable(Type *type); bool type_is_ordered(Type *type); +unsigned type_get_introspection_kind(TypeKind kind); Type *type_find_common_ancestor(Type *left, Type *right); Type *type_find_largest_union_element(Type *type); Type *type_find_max_type(Type *type, Type *other); +Type *type_find_max_type_may_fail(Type *type, Type *other); Type *type_abi_find_single_struct_element(Type *type); bool type_is_valid_for_vector(Type *type); Type *type_get_array(Type *arr_type, ArraySize len); diff --git a/src/compiler/copying.c b/src/compiler/copying.c index 812d498f1..929024709 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -241,6 +241,7 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr) case EXPR_PTR: case EXPR_STRINGIFY: case EXPR_CT_EVAL: + case EXPR_TYPEID_KIND: MACRO_COPY_EXPR(expr->inner_expr); return expr; case EXPR_COND: diff --git a/src/compiler/enums.h b/src/compiler/enums.h index a79e7601c..9909ef901 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -188,7 +188,9 @@ typedef enum INTROSPECT_TYPE_ARRAY = 15, INTROSPECT_TYPE_SUBARRAY = 16, INTROSPECT_TYPE_VECTOR = 17, - INTROSPECT_TYPE_DISTINCT = 18 + INTROSPECT_TYPE_DISTINCT = 18, + INTROSPECT_TYPE_POINTER = 19, + INTROSPECT_TYPE_VARIANT = 20, } IntrospectType; typedef enum @@ -245,6 +247,7 @@ typedef enum EXPR_UNARY, EXPR_VARIANTSWITCH, EXPR_NOP, + EXPR_TYPEID_KIND, } ExprKind; typedef enum diff --git a/src/compiler/linker.c b/src/compiler/linker.c index bf7c3fdf5..8333cc27b 100644 --- a/src/compiler/linker.c +++ b/src/compiler/linker.c @@ -8,23 +8,7 @@ extern bool llvm_link_coff(const char **args, int arg_count, const char **error_ extern bool llvm_link_wasm(const char **args, int arg_count, const char **error_string); extern bool llvm_link_mingw(const char **args, int arg_count, const char **error_string); -static void add_files(const char ***args, const char **files_to_link, unsigned file_count) -{ - for (unsigned i = 0; i < file_count; i++) - { - vec_add(*args, files_to_link[i]); - } -} -static const char *join_strings(const char **args, unsigned count) -{ - char *res = ""; - for (unsigned i = 0; i < count; ++i) - { - res = str_cat(res, args[i]); - } - return res; -} typedef enum { diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 0c23dad7f..77416ee06 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -7,8 +7,6 @@ const char* llvm_version = LLVM_VERSION_STRING; const char* llvm_target = LLVM_DEFAULT_TARGET_TRIPLE; -void llvm_emit_local_global_variable_definition(GenContext *c, Decl *decl); - static void diagnostics_handler(LLVMDiagnosticInfoRef ref, void *context) { char *message = LLVMGetDiagInfoDescription(ref); @@ -255,28 +253,6 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_ } -void llvm_emit_local_global_variable_definition(GenContext *c, Decl *decl) -{ - assert(decl->var.kind == VARDECL_GLOBAL || decl->var.kind == VARDECL_CONST); - - // Skip real constants. - if (!decl->type) return; - - if (decl->type != type_void) - { - decl->backend_ref = llvm_add_global_var(c, "tempglobal", decl->type, decl->alignment); - } - if (IS_FAILABLE(decl)) - { - scratch_buffer_clear(); - scratch_buffer_append(decl->extname); - scratch_buffer_append(".f"); - decl->var.failable_ref = llvm_add_global_var(c, scratch_buffer_to_string(), type_anyerr, 0); - LLVMSetUnnamedAddress(decl->var.failable_ref, LLVMGlobalUnnamedAddr); - } -} - - void llvm_emit_ptr_from_array(GenContext *c, BEValue *value) { switch (value->type->type_kind) diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 4c72b1430..39653f54d 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -90,39 +90,14 @@ BEValue llvm_emit_assign_expr(GenContext *c, BEValue *ref, Expr *expr, LLVMValue static inline LLVMValueRef llvm_emit_extract_value(GenContext *c, LLVMValueRef agg, unsigned index) { - if (LLVMIsConstant(agg)) + if (LLVMGetTypeKind(LLVMTypeOf(agg)) == LLVMVectorTypeKind) { - return LLVMConstExtractValue(agg, &index, 1); - } - else - { - return LLVMBuildExtractValue(c->builder, agg, index, ""); + return LLVMBuildExtractElement(c->builder, agg, llvm_const_int(c, type_usize, index), ""); } + return LLVMBuildExtractValue(c->builder, agg, index, ""); } -static inline LLVMValueRef llvm_emit_extract_element(GenContext *c, LLVMValueRef vector, unsigned index) -{ - if (LLVMIsConstant(vector)) - { - return LLVMConstExtractElement(vector, llvm_const_int(c, type_usize, index)); - } - else - { - return LLVMBuildExtractElement(c->builder, vector, llvm_const_int(c, type_usize, index), ""); - } -} -static inline LLVMValueRef llvm_emit_insert_value(GenContext *c, LLVMValueRef agg, LLVMValueRef new_value, unsigned index) -{ - if (LLVMIsConstant(agg) && LLVMIsConstant(new_value)) - { - return LLVMConstInsertValue(agg, new_value, &index, 1); - } - else - { - return LLVMBuildInsertValue(c->builder, agg, new_value, index, ""); - } -} static inline LLVMValueRef llvm_zext_trunc(GenContext *c, LLVMValueRef data, LLVMTypeRef type) { @@ -170,39 +145,22 @@ LLVMValueRef llvm_emit_coerce_alignment(GenContext *c, BEValue *be_value, LLVMTy return LLVMBuildBitCast(c->builder, be_value->value, LLVMPointerType(coerce_type, 0), ""); } - -LLVMValueRef llvm_emit_aggregate_value(GenContext *c, Type *type, ...) +LLVMValueRef llvm_emit_aggregate_two(GenContext *c, Type *type, LLVMValueRef value1, LLVMValueRef value2) { - LLVMValueRef result = LLVMGetUndef(llvm_get_type(c, type)); - va_list args; - va_start(args, type); - LLVMValueRef val; - bool is_constant = true; - while (is_constant && (val = va_arg(args, LLVMValueRef)) != NULL) - { - if (!LLVMIsConstant(val)) is_constant = false; - } - va_end(args); - va_start(args, type); - unsigned index = 0; + bool is_constant = LLVMIsConstant(value1) && LLVMIsConstant(value2); if (is_constant) { - while ((val = va_arg(args, LLVMValueRef)) != NULL) - { - result = LLVMConstInsertValue(result, val, &index, 1); - index++; - } + LLVMValueRef two[2] = { value1, value2 }; + return LLVMConstNamedStruct(llvm_get_type(c, type), two, 2); } - else - { - assert(c->builder); - while ((val = va_arg(args, LLVMValueRef)) != NULL) - { - result = LLVMBuildInsertValue(c->builder, result, val, index++, ""); - } - } - va_end(args); - return result; + LLVMValueRef result = LLVMGetUndef(llvm_get_type(c, type)); + result = llvm_emit_insert_value(c, result, value1, 0); + return llvm_emit_insert_value(c, result, value2, 1); +} + +void llvm_set_aggregate_two(GenContext *c, BEValue *value, Type *type, LLVMValueRef value1, LLVMValueRef value2) +{ + llvm_value_set(value, llvm_emit_aggregate_two(c, type, value1, value2), type); } LLVMValueRef llvm_const_low_bitmask(LLVMTypeRef type, int type_bits, int low_bits) @@ -261,8 +219,8 @@ static inline LLVMValueRef llvm_emit_add_int(GenContext *c, Type *type, LLVMValu { add_res = llvm_emit_call_intrinsic(c, intrinsic_id.sadd_overflow, &type_to_use, 1, args, 2); } - LLVMValueRef result = LLVMBuildExtractValue(c->builder, add_res, 0, ""); - LLVMValueRef ok = LLVMBuildExtractValue(c->builder, add_res, 1, ""); + LLVMValueRef result = llvm_emit_extract_value(c, add_res, 0); + LLVMValueRef ok = llvm_emit_extract_value(c, add_res, 1); llvm_emit_panic_on_true(c, ok, "Addition overflow", loc); return result; } @@ -487,8 +445,8 @@ static inline LLVMValueRef llvm_emit_sub_int(GenContext *c, Type *type, LLVMValu { add_res = llvm_emit_call_intrinsic(c, intrinsic_id.ssub_overflow, &type_to_use, 1, args, 2); } - LLVMValueRef result = LLVMBuildExtractValue(c->builder, add_res, 0, ""); - LLVMValueRef ok = LLVMBuildExtractValue(c->builder, add_res, 1, ""); + LLVMValueRef result = llvm_emit_extract_value(c, add_res, 0); + LLVMValueRef ok = llvm_emit_extract_value(c, add_res, 1); llvm_emit_panic_on_true(c, ok, "Subtraction overflow", loc); return result; } @@ -573,14 +531,7 @@ static inline void llvm_emit_vector_subscript(GenContext *c, BEValue *value, Exp { index = LLVMBuildNUWSub(c->builder, llvm_const_int(c, value->type, vec->array.len), index, ""); } - if (LLVMIsAConstant(index) && LLVMIsAConstant(vector)) - { - llvm_value_set(value, LLVMConstExtractElement(vector, index), element); - } - else - { - llvm_value_set(value, LLVMBuildExtractElement(c->builder, vector, index, ""), element); - } + llvm_value_set(value, LLVMBuildExtractElement(c->builder, vector, index, ""), element); } @@ -1115,8 +1066,7 @@ static void llvm_emit_arr_to_subarray_cast(GenContext *c, BEValue *value, Type * LLVMTypeRef subarray_type = llvm_get_type(c, to_type); LLVMValueRef pointer = llvm_emit_bitcast(c, value->value, type_get_ptr(array_type)); LLVMValueRef len = llvm_const_int(c, type_usize, size); - value->type = to_type; - value->value = llvm_emit_aggregate_value(c, to_type, pointer, len, NULL); + llvm_set_aggregate_two(c, value, to_type, pointer, len); } @@ -1128,13 +1078,8 @@ void llvm_emit_vector_to_array_cast(GenContext *c, BEValue *value, Type *to_type bool is_const = LLVMIsConstant(value->value); for (unsigned i = 0; i < to_type->array.len; i++) { - LLVMValueRef element = llvm_emit_extract_element(c, value->value, i); - if (is_const) - { - array = LLVMConstInsertValue(array, element, &i, 1); - continue; - } - array = LLVMBuildInsertValue(c->builder, array, element, i, ""); + LLVMValueRef element = llvm_emit_extract_value(c, value->value, i); + array = llvm_emit_insert_value(c, array, element, i); } llvm_value_set(value, array, to_type); } @@ -1144,16 +1089,10 @@ void llvm_emit_array_to_vector_cast(GenContext *c, BEValue *value, Type *to_type llvm_value_rvalue(c, value); LLVMTypeRef vector_type = llvm_get_type(c, to_type); LLVMValueRef vector = LLVMGetUndef(vector_type); - bool is_const = LLVMIsConstant(value->value); for (unsigned i = 0; i < to_type->array.len; i++) { LLVMValueRef element = llvm_emit_extract_value(c, value->value, i); - if (is_const) - { - vector = LLVMConstInsertElement(vector, element, llvm_const_int(c, type_usize, i)); - continue; - } - vector = LLVMBuildInsertElement(c->builder, vector, element, llvm_const_int(c, type_usize, i), ""); + vector = llvm_emit_insert_value(c, vector, element, i); } llvm_value_set(value, vector, to_type); } @@ -1175,7 +1114,7 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_ LLVMValueRef pointer = llvm_emit_bitcast(c, value->value, type_voidptr); BEValue typeid; llvm_emit_typeid(c, &typeid, from_type->pointer); - llvm_value_set(value, llvm_emit_aggregate_value(c, to_type, pointer, typeid.value, NULL), to_type); + llvm_set_aggregate_two(c, value, to_type, pointer, typeid.value); return; } case CAST_BSARRY: @@ -1228,18 +1167,18 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_ case CAST_STRPTR: case CAST_PTRPTR: llvm_value_rvalue(c, value); - if (c->builder) + if (LLVMIsConstant(value->value)) { - value->value = LLVMBuildPointerCast(c->builder, value->value, llvm_get_type(c, to_type), "ptrptr"); + value->value = LLVMConstPointerCast(value->value, llvm_get_type(c, to_type)); } else { - value->value = LLVMConstPointerCast(value->value, llvm_get_type(c, to_type)); + value->value = LLVMBuildPointerCast(c->builder, value->value, llvm_get_type(c, to_type), "ptrptr"); } break; case CAST_PTRXI: llvm_value_rvalue(c, value); - if (c->builder) + if (!LLVMIsConstant(value->value)) { value->value = LLVMBuildPtrToInt(c->builder, value->value, llvm_get_type(c, to_type), "ptrxi"); } @@ -1377,7 +1316,7 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_ } else { - value->value = LLVMBuildExtractValue(c->builder, value->value, 1, ""); + value->value = llvm_emit_extract_value(c, value->value, 1); } value->type = type_usize->canonical; llvm_value_rvalue(c, value); @@ -1405,18 +1344,17 @@ static LLVMValueRef llvm_recursive_set_value(GenContext *c, DesignatorElement ** { BEValue res; llvm_emit_expr(c, &res, value); - unsigned index = (unsigned)current_element->index; + ArraySize index = (ArraySize)current_element->index; LLVMValueRef val = llvm_load_value_store(c, &res); switch (current_element->kind) { case DESIGNATOR_FIELD: - return LLVMConstInsertValue(parent, val, &index, 1); case DESIGNATOR_ARRAY: - return LLVMConstInsertElement(parent, val, llvm_const_int(c, type_isize, (unsigned)current_element->index)); + return llvm_emit_insert_value(c, parent, val, index); case DESIGNATOR_RANGE: for (MemberIndex i = current_element->index; i <= current_element->index_end; i++) { - parent = LLVMConstInsertElement(parent, val, llvm_const_int(c, type_isize, (uint64_t)i)); + parent = llvm_emit_insert_value(c, parent, val, i); } return parent; } @@ -1428,24 +1366,20 @@ static LLVMValueRef llvm_recursive_set_value(GenContext *c, DesignatorElement ** case DESIGNATOR_FIELD: { unsigned index = (unsigned)current_element->index; - current_val = LLVMConstExtractValue(parent, &index, 1); + current_val = llvm_emit_extract_value(c, parent, index); current_val = llvm_recursive_set_value(c, current_element_ptr + 1, current_val, last_element_ptr, value); - return LLVMConstInsertValue(parent, current_val, &index, 1); + return llvm_emit_insert_value(c, parent, current_val, index); } case DESIGNATOR_ARRAY: - { - LLVMValueRef index = llvm_const_int(c, type_isize, (uint64_t)current_element->index); - current_val = LLVMConstExtractElement(parent, index); + current_val = llvm_emit_extract_value(c, parent, current_element->index); current_val = llvm_recursive_set_value(c, current_element_ptr + 1, current_val, last_element_ptr, value); - return LLVMConstInsertElement(parent, current_val, index); - } + return llvm_emit_insert_value(c, parent, current_val, current_element->index); case DESIGNATOR_RANGE: for (MemberIndex i = current_element->index; i <= current_element->index_end; i++) { - LLVMValueRef index = llvm_const_int(c, type_isize, (uint64_t)i); - current_val = LLVMConstExtractElement(parent, index); + current_val = llvm_emit_extract_value(c, parent, i); current_val = llvm_recursive_set_value(c, current_element_ptr + 1, current_val, last_element_ptr, value); - parent = LLVMConstInsertElement(parent, current_val, index); + parent = llvm_emit_insert_value(c, parent, current_val, i); } return parent; default: @@ -1761,6 +1695,9 @@ static inline void llvm_emit_initialize_reference_designated(GenContext *c, BEVa llvm_emit_initialize_designated(c, ref, 0, designator->designator_expr.path, last_element, designator->designator_expr.value, NULL); } } + +#define MAX_AGG 16 + LLVMValueRef llvm_emit_const_bitstruct_array(GenContext *c, ConstInitializer *initializer) { Decl *decl = initializer->type->decl; @@ -1768,7 +1705,13 @@ LLVMValueRef llvm_emit_const_bitstruct_array(GenContext *c, ConstInitializer *in bool big_endian = platform_target.big_endian; if (decl->bitstruct.big_endian) big_endian = true; if (decl->bitstruct.little_endian) big_endian = false; - LLVMValueRef data = LLVMConstNull(llvm_get_type(c, base_type)); + unsigned elements = base_type->array.len; + LLVMValueRef stack_data[MAX_AGG]; + LLVMValueRef* slots = elements > MAX_AGG ? MALLOC(elements * sizeof(LLVMValueRef)) : stack_data; + for (unsigned i = 0; i < elements; i++) + { + slots[i] = LLVMConstNull(c->byte_type); + } Decl **members = decl->strukt.members; MemberIndex count = (MemberIndex)vec_size(members); for (MemberIndex i = 0; i < count; i++) @@ -1791,8 +1734,8 @@ LLVMValueRef llvm_emit_const_bitstruct_array(GenContext *c, ConstInitializer *in LLVMValueRef bit = llvm_emit_shl_fixed(c, LLVMConstInt(c->byte_type, 1, 0), start_bit % 8); unsigned byte = start_bit / 8; - LLVMValueRef current_value = llvm_emit_extract_value(c, data, byte); - data = llvm_emit_insert_value(c, data, LLVMConstOr(current_value, bit), byte); + LLVMValueRef current_value = slots[byte]; + slots[byte] = LLVMConstOr(current_value, bit); continue; } unsigned bit_size = end_bit - start_bit + 1; @@ -1826,11 +1769,11 @@ LLVMValueRef llvm_emit_const_bitstruct_array(GenContext *c, ConstInitializer *in to_or = llvm_mask_low_bits(c, to_or, end_bit % 8 + 1); } if (member_type_bitsize > 8) to_or = LLVMConstTrunc(to_or, c->byte_type); - LLVMValueRef current_value = llvm_emit_extract_value(c, data, (unsigned)j); - data = llvm_emit_insert_value(c, data, LLVMConstOr(to_or, current_value), (unsigned)j); + LLVMValueRef current_value = slots[(unsigned)j]; + slots[(unsigned)j] = LLVMConstOr(to_or, current_value); } } - return data; + return LLVMConstArray(c->byte_type, slots, elements); } LLVMValueRef llvm_emit_const_bitstruct(GenContext *c, ConstInitializer *initializer) @@ -2006,7 +1949,7 @@ static inline void llvm_emit_inc_dec_change(GenContext *c, bool use_mod, BEValue LLVMValueRef val = LLVMGetUndef(llvm_get_type(c, type)); for (ArraySize i = 0; i < width; i++) { - val = LLVMConstInsertElement(val, diff_value, llvm_const_int(c, type_usize, i)); + val = llvm_emit_insert_value(c, val, diff_value, i); } if (is_integer) { @@ -2125,7 +2068,7 @@ static void llvm_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr) } else { - llvm_value = LLVMBuildExtractValue(c->builder, value->value, 1, "len"); + llvm_value = llvm_emit_extract_value(c, value->value, 1); } llvm_value = LLVMBuildIsNull(c->builder, llvm_value, "not"); break; @@ -2164,8 +2107,8 @@ static void llvm_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr) LLVMValueRef args[2] = { zero, value->value }; LLVMValueRef call_res = llvm_emit_call_intrinsic(c, intrinsic_id.ssub_overflow, &type_to_use, 1, args, 2); - value->value = LLVMBuildExtractValue(c->builder, call_res, 0, ""); - LLVMValueRef ok = LLVMBuildExtractValue(c->builder, call_res, 1, ""); + value->value = llvm_emit_extract_value(c, call_res, 0); + LLVMValueRef ok = llvm_emit_extract_value(c, call_res, 1); llvm_emit_panic_on_true(c, ok, "Signed negation overflow", expr->span); return; } @@ -2201,7 +2144,7 @@ void llvm_emit_len_for_expr(GenContext *c, BEValue *be_value, BEValue *expr_to_l llvm_value_fold_failable(c, be_value); if (expr_to_len->kind == BE_VALUE) { - llvm_value_set(be_value, LLVMBuildExtractValue(c->builder, expr_to_len->value, 1, ""), type_usize); + llvm_value_set(be_value, llvm_emit_extract_value(c, expr_to_len->value, 1), type_usize); } else { @@ -2338,7 +2281,7 @@ static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_r break; case TYPE_SUBARRAY: parent_load_value = LLVMBuildLoad2(c->builder, llvm_get_type(c, parent_type), parent_addr, ""); - parent_base = LLVMBuildExtractValue(c->builder, parent_load_value, 0, ""); + parent_base = llvm_emit_extract_value(c, parent_load_value, 0); break; case TYPE_FLEXIBLE_ARRAY: case TYPE_ARRAY: @@ -2367,7 +2310,7 @@ static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_r break; case TYPE_SUBARRAY: assert(parent_load_value); - llvm_value_set(&len, LLVMBuildExtractValue(c->builder, parent_load_value, 1, ""), type_usize); + llvm_value_set(&len, llvm_emit_extract_value(c, parent_load_value, 1), type_usize); break; case TYPE_ARRAY: llvm_value_set_int(c, &len, type_usize, parent_type->array.len); @@ -2483,8 +2426,7 @@ static void gencontext_emit_slice(GenContext *c, BEValue *be_value, Expr *expr) } // Create a new subarray type - Type *expr_type = type_lowering(expr->type); - llvm_value_set(be_value, llvm_emit_aggregate_value(c, expr_type, start_pointer, size, NULL), expr_type); + llvm_set_aggregate_two(c, be_value, type_lowering(expr->type), start_pointer, size); } static void llvm_emit_slice_assign(GenContext *c, BEValue *be_value, Expr *expr) @@ -2904,8 +2846,8 @@ static inline LLVMValueRef llvm_emit_mult_int(GenContext *c, Type *type, LLVMVal 1, args, 2); - LLVMValueRef val = LLVMBuildExtractValue(c->builder, call_res, 0, "mul"); - LLVMValueRef ok = LLVMBuildExtractValue(c->builder, call_res, 1, ""); + LLVMValueRef val = llvm_emit_extract_value(c, call_res, 0); + LLVMValueRef ok = llvm_emit_extract_value(c, call_res, 1); llvm_emit_panic_on_true(c, ok, "Integer multiplication overflow", loc); return val; } @@ -2932,12 +2874,12 @@ static void llvm_emit_subarray_comp(GenContext *c, BEValue *be_value, BEValue *l llvm_value_rvalue(c, rhs); BEValue lhs_len; BEValue rhs_len; - llvm_value_set(&lhs_len, LLVMBuildExtractValue(c->builder, lhs->value, 1, ""), type_usize); - llvm_value_set(&rhs_len, LLVMBuildExtractValue(c->builder, rhs->value, 1, ""), type_usize); + llvm_value_set(&lhs_len, llvm_emit_extract_value(c, lhs->value, 1), type_usize); + llvm_value_set(&rhs_len, llvm_emit_extract_value(c, rhs->value, 1), type_usize); BEValue lhs_value; BEValue rhs_value; - llvm_value_set(&lhs_value, LLVMBuildExtractValue(c->builder, lhs->value, 0, ""), array_base_pointer); - llvm_value_set(&rhs_value, LLVMBuildExtractValue(c->builder, rhs->value, 0, ""), array_base_pointer); + llvm_value_set(&lhs_value, llvm_emit_extract_value(c, lhs->value, 0), array_base_pointer); + llvm_value_set(&rhs_value, llvm_emit_extract_value(c, rhs->value, 0), array_base_pointer); BEValue len_match; llvm_emit_comparison(c, &len_match, &lhs_len, &rhs_len, BINARYOP_EQ); @@ -3527,7 +3469,7 @@ static inline void llvm_emit_typeofany(GenContext *c, BEValue *be_value, Expr *e } else { - llvm_value_set(be_value, LLVMBuildExtractValue(c->builder, be_value->value, 1, ""), type_typeid); + llvm_value_set(be_value, llvm_emit_extract_value(c, be_value->value, 1), type_typeid); } } @@ -4082,13 +4024,6 @@ LLVMValueRef llvm_emit_array_gep_raw(GenContext *c, LLVMValueRef ptr, LLVMTypeRe return llvm_emit_array_gep_raw_index(c, ptr, array_type, llvm_const_int(c, type_usize, index), array_alignment, alignment); } -LLVMValueRef llvm_emit_array_load(GenContext *c, LLVMValueRef ptr, LLVMTypeRef array_type, unsigned index, AlignSize array_alignment) -{ - AlignSize alignment; - LLVMValueRef element_ptr = llvm_emit_array_gep_raw_index(c, ptr, array_type, llvm_const_int(c, type_usize, index), array_alignment, &alignment); - return llvm_load(c, LLVMGetElementType(array_type), element_ptr, alignment, ""); -} - LLVMValueRef llvm_emit_pointer_gep_raw(GenContext *c, LLVMTypeRef pointee_type, LLVMValueRef ptr, LLVMValueRef offset) { if (LLVMIsConstant(ptr) && LLVMIsConstant(offset)) @@ -4848,8 +4783,8 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr) } // 15g. We can now extract { lo, hi } to lo_value and hi_value. - LLVMValueRef lo_value = LLVMBuildExtractValue(c->builder, call_value, 0, ""); - LLVMValueRef hi_value = LLVMBuildExtractValue(c->builder, call_value, 1, ""); + LLVMValueRef lo_value = llvm_emit_extract_value(c, call_value, 0); + LLVMValueRef hi_value = llvm_emit_extract_value(c, call_value, 1); // 15h. Store lo_value into the { pad, lo, pad, hi } struct. llvm_store(c, lo, lo_value, alignment); @@ -5171,18 +5106,10 @@ static inline void llvm_emit_failable(GenContext *c, BEValue *be_value, Expr *ex llvm_value_set(be_value, LLVMGetUndef(llvm_get_type(c, type)), type); } -static inline LLVMValueRef llvm_update_vector(GenContext *c, LLVMValueRef vector, LLVMValueRef value, MemberIndex index, bool *is_const) +static inline LLVMValueRef llvm_update_vector(GenContext *c, LLVMValueRef vector, LLVMValueRef value, MemberIndex index) { LLVMValueRef index_value = llvm_const_int(c, type_usize, (uint64_t)index); - if (*is_const && LLVMIsConstant(value)) - { - return LLVMConstInsertElement(vector, value, index_value); - } - else - { - *is_const = false; - return LLVMBuildInsertElement(c->builder, vector, value, index_value, ""); - } + return LLVMBuildInsertElement(c->builder, vector, value, index_value, ""); } static inline void llvm_emit_vector_initializer_list(GenContext *c, BEValue *value, Expr *expr) @@ -5195,7 +5122,6 @@ static inline void llvm_emit_vector_initializer_list(GenContext *c, BEValue *val BEValue val; LLVMValueRef vec_value; - bool is_const = true; if (expr->expr_kind == EXPR_INITIALIZER_LIST) { vec_value = LLVMGetUndef(llvm_type); @@ -5207,7 +5133,7 @@ static inline void llvm_emit_vector_initializer_list(GenContext *c, BEValue *val Expr *element = elements[i]; llvm_emit_expr(c, &val, element); llvm_value_rvalue(c, &val); - vec_value = llvm_update_vector(c, vec_value, val.value, (MemberIndex)i, &is_const); + vec_value = llvm_update_vector(c, vec_value, val.value, (MemberIndex)i); } } else @@ -5226,13 +5152,13 @@ static inline void llvm_emit_vector_initializer_list(GenContext *c, BEValue *val { case DESIGNATOR_ARRAY: { - vec_value = llvm_update_vector(c, vec_value, val.value, element->index, &is_const); + vec_value = llvm_update_vector(c, vec_value, val.value, element->index); break; } case DESIGNATOR_RANGE: for (MemberIndex idx = element->index; idx <= element->index_end; idx++) { - vec_value = llvm_update_vector(c, vec_value, val.value, idx, &is_const); + vec_value = llvm_update_vector(c, vec_value, val.value, idx); } break; case DESIGNATOR_FIELD: @@ -5357,6 +5283,15 @@ static inline void llvm_emit_ptr(GenContext *c, BEValue *value, Expr *expr) llvm_emit_subarray_pointer(c, value, value); } +static inline void llvm_emit_typeid_kind(GenContext *c, BEValue *value, Expr *expr) +{ + llvm_emit_expr(c, value, expr->inner_expr); + llvm_value_rvalue(c, value); + LLVMValueRef ref = LLVMBuildIntToPtr(c->builder, value->value, llvm_get_ptr_type(c, type_char), ""); + LLVMValueRef kind = llvm_load(c, c->byte_type, ref, 1, ""); + llvm_value_set(value, kind, expr->type); +} + void llvm_emit_try_unwrap_chain(GenContext *c, BEValue *value, Expr *expr) { Expr **exprs = expr->try_unwrap_chain_expr; @@ -5428,10 +5363,7 @@ static inline void llvm_emit_argv_to_subarray(GenContext *c, BEValue *value, Exp LLVMTypeRef loop_type = llvm_get_type(c, type_usize); LLVMTypeRef char_ptr_type = llvm_get_ptr_type(c, type_char); LLVMValueRef size = llvm_zext_trunc(c, count, loop_type); - LLVMValueRef result = LLVMGetUndef(temp_type); - result = LLVMBuildInsertValue(c->builder, result, size, 1, ""); - result = LLVMBuildInsertValue(c->builder, result, arg_array, 0, ""); - llvm_value_set(value, result, expr->type); + llvm_set_aggregate_two(c, value, expr->type, arg_array, size); // Check if zero: BEValue cond; @@ -5518,6 +5450,9 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr) case EXPR_PTR: llvm_emit_ptr(c, value, expr); return; + case EXPR_TYPEID_KIND: + llvm_emit_typeid_kind(c, value, expr); + return; case EXPR_BUILTIN: UNREACHABLE; case EXPR_DECL: diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index 35b362ecd..94b717e55 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -348,8 +348,8 @@ void llvm_emit_return_abi(GenContext *c, BEValue *return_value, BEValue *failabl LLVMTypeRef unpadded_type = llvm_get_twostruct(c, lo_type, hi_type); LLVMValueRef composite = LLVMGetUndef(unpadded_type); - composite = LLVMBuildInsertValue(c->builder, composite, lo_val, 0, ""); - composite = LLVMBuildInsertValue(c->builder, composite, hi_val, 1, ""); + composite = llvm_emit_insert_value(c, composite, lo_val, 0); + composite = llvm_emit_insert_value(c, composite, hi_val, 1); // And return that unpadded result llvm_emit_return_value(c, composite); @@ -682,13 +682,3 @@ void llvm_emit_function_decl(GenContext *c, Decl *decl) } -void llvm_emit_methods(GenContext *c, Decl **methods) -{ - VECEACH(methods, i) - { - Decl *decl = methods[i]; - if (decl->decl_kind == DECL_MACRO) continue; - llvm_emit_function_decl(c, decl); - } -} - diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index 5e2cd7f13..a2e289e54 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -285,7 +285,7 @@ INLINE void llvm_emit_exprid(GenContext *c, BEValue *value, ExprId expr) assert(expr); llvm_emit_expr(c, value, exprptr(expr)); } -void llvm_emit_local_global_variable_definition(GenContext *c, Decl *decl); + void llvm_emit_typeid(GenContext *c, BEValue *be_value, Type *type); void llvm_emit_global_variable_init(GenContext *c, Decl *decl); void llvm_set_private_linkage(LLVMValueRef alloc); @@ -321,7 +321,10 @@ LLVMValueRef llvm_emit_lshr_fixed(GenContext *c, LLVMValueRef data, int shift); // -- general -- void llvm_emit_local_var_alloca(GenContext *c, Decl *decl); void llvm_emit_local_decl(GenContext *c, Decl *decl, BEValue *value); -LLVMValueRef llvm_emit_aggregate_value(GenContext *c, Type *type, ...); + +void llvm_set_aggregate_two(GenContext *c, BEValue *value, Type *type, LLVMValueRef value1, LLVMValueRef value2); +LLVMValueRef llvm_emit_aggregate_two(GenContext *c, Type *type, LLVMValueRef value1, LLVMValueRef value2); + LLVMValueRef llvm_emit_memclear_size_align(GenContext *c, LLVMValueRef ref, uint64_t size, AlignSize align, bool bitcast); void llvm_store_zero(GenContext *c, BEValue *ref); void llvm_emit_memcpy(GenContext *c, LLVMValueRef dest, unsigned dest_align, LLVMValueRef source, unsigned src_align, uint64_t len); @@ -340,7 +343,7 @@ LLVMValueRef llvm_emit_struct_gep_raw(GenContext *context, LLVMValueRef ptr, LLV unsigned struct_alignment, AlignSize *alignment); LLVMValueRef llvm_emit_array_gep_raw(GenContext *c, LLVMValueRef ptr, LLVMTypeRef array_type, unsigned index, AlignSize array_alignment, AlignSize *alignment); LLVMValueRef llvm_emit_array_gep_raw_index(GenContext *c, LLVMValueRef ptr, LLVMTypeRef array_type, LLVMValueRef index, AlignSize array_alignment, AlignSize *alignment); -LLVMValueRef llvm_emit_array_load(GenContext *c, LLVMValueRef ptr, LLVMTypeRef array_type, unsigned index, AlignSize array_alignment); + LLVMValueRef llvm_emit_pointer_gep_raw(GenContext *c, LLVMTypeRef pointee_type, LLVMValueRef ptr, LLVMValueRef offset); LLVMValueRef llvm_emit_pointer_inbounds_gep_raw(GenContext *c, LLVMTypeRef pointee_type, LLVMValueRef ptr, LLVMValueRef offset); @@ -386,6 +389,15 @@ static inline LLVMValueRef decl_failable_ref(Decl *decl) } +static inline LLVMValueRef llvm_emit_insert_value(GenContext *c, LLVMValueRef agg, LLVMValueRef new_value, ArraySize index) +{ + if (LLVMGetTypeKind(LLVMTypeOf(agg)) == LLVMVectorTypeKind) + { + LLVMValueRef index_val = llvm_const_int(c, type_usize, index); + return LLVMBuildInsertElement(c->builder, agg, new_value, index_val, ""); + } + return LLVMBuildInsertValue(c->builder, agg, new_value, index, ""); +} static inline LLVMValueRef llvm_emit_store(GenContext *c, Decl *decl, LLVMValueRef value) { diff --git a/src/compiler/llvm_codegen_module.c b/src/compiler/llvm_codegen_module.c index 0b4a24bd4..5d6e7d5ed 100644 --- a/src/compiler/llvm_codegen_module.c +++ b/src/compiler/llvm_codegen_module.c @@ -55,7 +55,6 @@ void gencontext_begin_module(GenContext *c) c->block_global_unique_count = 0; c->ast_alloca_addr_space = target_alloca_addr_space(); - VECEACH(global_context.type, i) { Type *type = global_context.type[i]; diff --git a/src/compiler/llvm_codegen_type.c b/src/compiler/llvm_codegen_type.c index 550dc42a9..bc2d3dee6 100644 --- a/src/compiler/llvm_codegen_type.c +++ b/src/compiler/llvm_codegen_type.c @@ -681,14 +681,14 @@ static LLVMValueRef llvm_get_introspection_for_fault(GenContext *c, Type *type) val->backend_ref = LLVMConstPointerCast(global_name, llvm_get_type(c, type_typeid)); } LLVMTypeRef element_type = llvm_get_type(c, type_typeid); - LLVMTypeRef elements_type = LLVMArrayType(element_type, elements); - LLVMValueRef start = LLVMConstNull(elements_type); + LLVMValueRef* values = elements ? MALLOC(sizeof(LLVMValueRef) * elements) : NULL; for (unsigned i = 0; i < elements; i++) { - start = LLVMConstInsertValue(start, LLVMConstBitCast(fault_vals[i]->backend_ref, element_type), &i, 1); + values[i] = LLVMConstBitCast(fault_vals[i]->backend_ref, element_type); } - LLVMValueRef values[] = { llvm_const_int(c, type_char, INTROSPECT_TYPE_FAULT ), llvm_const_int(c, type_usize, elements), start }; - LLVMValueRef strukt = LLVMConstStructInContext(c->context, values, 3, false); + LLVMValueRef svalues[] = { llvm_const_int(c, type_char, INTROSPECT_TYPE_FAULT ), llvm_const_int(c, type_usize, elements), + LLVMConstArray(element_type, values, elements) }; + LLVMValueRef strukt = LLVMConstStructInContext(c->context, svalues, 3, false); return llvm_get_introspection_weak(c, type, decl_get_extname(decl), strukt); } @@ -711,9 +711,9 @@ LLVMValueRef llvm_get_typeid(GenContext *c, Type *type) return llvm_get_introspection_for_derived_type(c, INTROSPECT_TYPE_ARRAY, type, type->array.base, llvm_const_int(c, type_usize, type->array.len)); case TYPE_SUBARRAY: - return llvm_get_introspection_for_derived_type(c, INTROSPECT_TYPE_ARRAY, type, type->array.base, NULL); + return llvm_get_introspection_for_derived_type(c, INTROSPECT_TYPE_SUBARRAY, type, type->array.base, NULL); case TYPE_POINTER: - return llvm_get_introspection_for_derived_type(c, INTROSPECT_TYPE_ARRAY, type, type->pointer, NULL); + return llvm_get_introspection_for_derived_type(c, INTROSPECT_TYPE_POINTER, type, type->pointer, NULL); case TYPE_DISTINCT: return llvm_get_introspection_for_derived_type(c, INTROSPECT_TYPE_DISTINCT, type, type->decl->distinct_decl.base_type, NULL); case TYPE_ENUM: diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index 01ccfbb6f..dbdafafea 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -8,7 +8,6 @@ #define IF_TRY_CATCH_PREC (PREC_AND + 1) typedef Expr *(*ParseFn)(ParseContext *context, Expr *); -static Expr *parse_rethrow_expr(ParseContext *c, Expr *left); static Expr *parse_expr_or_type_prec(ParseContext *c, TypeInfo **type_ref, Precedence prec); typedef struct diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 168c61f50..92df0dd2e 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -835,6 +835,7 @@ Expr *recursive_may_narrow_float(Expr *expr, Type *type) case EXPR_COMPILER_CONST: case EXPR_STRINGIFY: case EXPR_CT_EVAL: + case EXPR_TYPEID_KIND: UNREACHABLE case EXPR_POST_UNARY: return recursive_may_narrow_float(expr->unary_expr.expr, type); @@ -987,6 +988,7 @@ Expr *recursive_may_narrow_int(Expr *expr, Type *type) case EXPR_COMPILER_CONST: case EXPR_STRINGIFY: case EXPR_CT_EVAL: + case EXPR_TYPEID_KIND: UNREACHABLE case EXPR_POST_UNARY: return recursive_may_narrow_int(expr->unary_expr.expr, type); @@ -1158,6 +1160,27 @@ bool cast_implicit(Expr *expr, Type *to_type) if (expr->expr_kind == EXPR_CAST) expr->cast_expr.implicit = true; return true; } +static bool arr_to_vec(Expr *expr, Type *to_type) +{ + if (insert_runtime_cast_unless_const(expr, CAST_ARRVEC, to_type)) return true; + + assert(expr->const_expr.const_kind == CONST_LIST); + ConstInitializer *list = expr->const_expr.list; + list->type = to_type; + expr->type = to_type; + return true; +} + +static bool vec_to_arr(Expr *expr, Type *to_type) +{ + if (insert_runtime_cast_unless_const(expr, CAST_VECARR, to_type)) return true; + + assert(expr->const_expr.const_kind == CONST_LIST); + ConstInitializer *list = expr->const_expr.list; + list->type = to_type; + expr->type = to_type; + return true; +} static bool err_to_anyerr(Expr *expr, Type *to_type) { @@ -1280,7 +1303,7 @@ static bool cast_inner(Expr *expr, Type *from_type, Type *to, Type *to_type) case TYPE_FLEXIBLE_ARRAY: return false; case TYPE_ARRAY: - if (to->type_kind == TYPE_VECTOR) return insert_cast(expr, CAST_ARRVEC, to_type); + if (to->type_kind == TYPE_VECTOR) return arr_to_vec(expr, to_type); FALLTHROUGH; case TYPE_STRUCT: case TYPE_UNION: @@ -1295,7 +1318,7 @@ static bool cast_inner(Expr *expr, Type *from_type, Type *to, Type *to_type) if (to->type_kind == TYPE_BOOL) return subarray_to_bool(expr); break; case TYPE_VECTOR: - if (to->type_kind == TYPE_ARRAY) return insert_cast(expr, CAST_VECARR, to); + if (to->type_kind == TYPE_ARRAY) return vec_to_arr(expr, to_type); break; } UNREACHABLE diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index f410cbbed..579ebeac8 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -372,6 +372,7 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) return expr_list_is_constant_eval(expr->expression_list, eval_kind); case EXPR_FAILABLE: case EXPR_GROUP: + case EXPR_TYPEID_KIND: expr = expr->inner_expr; goto RETRY; case EXPR_INITIALIZER_LIST: @@ -1030,7 +1031,7 @@ static inline bool sema_expr_analyse_hash_identifier(SemaContext *context, Expr expr_replace(expr, expr_macro_copy(decl->var.init_expr)); REMINDER("Remove analysis for hash"); - if (!sema_analyse_expr(decl->var.hash_var.context, expr)) + if (!sema_analyse_expr_lvalue(decl->var.hash_var.context, expr)) { // Poison the decl so we don't evaluate twice. decl_poison(decl); @@ -1635,20 +1636,30 @@ static inline Type *unify_returns(SemaContext *context) bool all_returns_need_casts = false; Type *common_type = NULL; - bool only_has_rethrow = true; + bool failable = false; + bool no_return = true; // 1. Loop through the returns. VECEACH(context->returns, i) { Ast *return_stmt = context->returns[i]; if (!return_stmt) { - common_type = common_type ? type_find_max_type(common_type, type_anyfail) : type_anyfail; + failable = true; continue; } - only_has_rethrow = false; + no_return = false; Expr *ret_expr = return_stmt->return_stmt.expr; Type *rtype = ret_expr ? ret_expr->type : type_void; - + if (type_is_failable_any(rtype)) + { + failable = true; + continue; + } + if (type_is_failable(rtype)) + { + failable = true; + rtype = type_no_fail(rtype); + } // 2. If we have no common type, set to the return type. if (!common_type) { @@ -1676,19 +1687,31 @@ static inline Type *unify_returns(SemaContext *context) all_returns_need_casts = true; } - // If we have no return and only rethrows, then the type is "void!" - if (common_type == type_anyfail && only_has_rethrow) common_type = type_get_failable(type_void); + // If we have no return (or only anyfail) + if (!common_type) + { + assert(!all_returns_need_casts && "We should never need casts here."); + // A failable? + if (failable) + { + // If there are only implicit returns, then we assume void!, otherwise it's an "anyfail" + return no_return ? type_get_failable(type_void) : type_anyfail; + } + // No failable => void. + return type_void; + } // 7. Insert casts. if (all_returns_need_casts) { + assert(!type_is_failable_type(common_type)); VECEACH(context->returns, i) { Ast *return_stmt = context->returns[i]; if (!return_stmt) continue; Expr *ret_expr = return_stmt->return_stmt.expr; // 8. All casts should work. - if (!cast_implicit(ret_expr, type_no_fail(common_type))) + if (!cast_implicit(ret_expr, common_type)) { assert(false); return NULL; @@ -1696,8 +1719,7 @@ static inline Type *unify_returns(SemaContext *context) } } - // 8. On no common type -> return void - return common_type ? common_type : type_void; + return type_get_opt_fail(common_type, failable); } static inline bool sema_expr_analyse_func_call(SemaContext *context, Expr *expr, Decl *decl, Expr *struct_var, bool failable) @@ -1834,6 +1856,7 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s { if (type_is_failable(rtype)) { + failable = true; rtype = type_no_fail(rtype); } else @@ -3007,6 +3030,84 @@ static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *exp return true; } + if (!is_const && type_is_integer(canonical)) + { + TypeKind kind = canonical->type_kind; + if (name == kw_min) + { + expr->expr_kind = EXPR_CONST; + expr->const_expr.const_kind = CONST_INTEGER; + expr->type = parent->type; + expr->resolve_status = RESOLVE_DONE; + expr->const_expr.ixx.type = kind; + switch (kind) + { + case TYPE_I8: + expr->const_expr.ixx.i = (Int128){ 0, 0xFF }; + break; + case TYPE_I16: + expr->const_expr.ixx.i = (Int128){ 0, 0xFFFF }; + break; + case TYPE_I32: + expr->const_expr.ixx.i = (Int128){ 0, 0xFFFFFFFFLL }; + break; + case TYPE_I64: + expr->const_expr.ixx.i = (Int128){ 0, ~((uint64_t)0) }; + break; + case TYPE_I128: + expr->const_expr.ixx.i = (Int128){ ~((uint64_t)0), ~((uint64_t)0) }; + break; + default: + expr->const_expr.ixx.i = (Int128){ 0, 0 }; + break; + } + return true; + } + if (name == kw_max) + { + expr->expr_kind = EXPR_CONST; + expr->const_expr.const_kind = CONST_INTEGER; + expr->type = parent->type; + expr->resolve_status = RESOLVE_DONE; + expr->const_expr.ixx.type = kind; + switch (kind) + { + case TYPE_I8: + expr->const_expr.ixx.i = (Int128){ 0, 0x7F }; + break; + case TYPE_I16: + expr->const_expr.ixx.i = (Int128){ 0, 0x7FFF }; + break; + case TYPE_I32: + expr->const_expr.ixx.i = (Int128){ 0, 0x7FFFFFFFLL }; + break; + case TYPE_I64: + expr->const_expr.ixx.i = (Int128){ 0, 0x7FFFFFFFFFFFFFFFLL }; + break; + case TYPE_I128: + expr->const_expr.ixx.i = (Int128){ 0x7FFFFFFFFFFFFFFFLL, 0xFFFFFFFFFFFFFFFFLL }; + break; + case TYPE_U8: + expr->const_expr.ixx.i = (Int128){ 0, 0xFF }; + break; + case TYPE_U16: + expr->const_expr.ixx.i = (Int128){ 0, 0xFFFF }; + break; + case TYPE_U32: + expr->const_expr.ixx.i = (Int128){ 0, 0xFFFFFFFFLL }; + break; + case TYPE_U64: + expr->const_expr.ixx.i = (Int128){ 0, 0xFFFFFFFFFFFFFFFFLL }; + break; + case TYPE_U128: + expr->const_expr.ixx.i = (Int128){ 0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFFFFFFFFFLL }; + break; + default: + UNREACHABLE + } + return true; + } + } // 3. Handle float.nan, double.inf etc if (!is_const && type_is_float(canonical)) { @@ -3226,6 +3327,22 @@ CHECK_DEEPER: } } + if (kw == kw_kind && flat_type->type_kind == TYPE_TYPEID) + { + Module *module = global_context_find_module(kw_std__core__types); + Decl *type_kind = module ? module_find_symbol(module, kw_typekind) : NULL; + Type *type_for_kind = type_kind ? type_kind->type : type_char; + if (current_parent->expr_kind == EXPR_CONST) + { + unsigned val = type_get_introspection_kind(current_parent->const_expr.typeid->type_kind); + expr_rewrite_to_int_const(expr, type_for_kind, val, false); + return true; + } + expr->expr_kind = EXPR_TYPEID_KIND; + expr->inner_expr = parent; + expr->type = type_for_kind; + return true; + } // Hard coded ptr on subarrays and variant if (kw == kw_ptr) { @@ -4844,7 +4961,7 @@ static bool sema_expr_analyse_add(SemaContext *context, Expr *expr, Expr *left, right_type = type_no_fail(right->type)->canonical; assert(!cast_to_iptr); - // 4. Do an binary arithmetic promotion + // 4. Do a binary arithmetic promotion if (!binary_arithmetic_promotion(context, left, right, left_type, right_type, expr, "Cannot do the addition %s + %s.")) { return false; @@ -6006,16 +6123,19 @@ static inline bool sema_expr_analyse_rethrow(SemaContext *context, Expr *expr) return false; } - if (context->rtype && context->rtype->type_kind != TYPE_FAILABLE) - { - SEMA_ERROR(expr, "This expression implicitly returns with a failable result, but the function does not allow failable results. Did you mean to use 'else' instead?"); - return false; - } if (context->active_scope.flags & (SCOPE_EXPR_BLOCK | SCOPE_MACRO)) { vec_add(context->returns, NULL); } + else + { + if (context->rtype && context->rtype->type_kind != TYPE_FAILABLE) + { + SEMA_ERROR(expr, "This expression implicitly returns with a failable result, but the function does not allow failable results. Did you mean to use 'else' instead?"); + return false; + } + } return true; } @@ -6823,6 +6943,7 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr) case EXPR_CATCH_UNWRAP: case EXPR_PTR: case EXPR_VARIANTSWITCH: + case EXPR_TYPEID_KIND: UNREACHABLE case EXPR_STRINGIFY: if (!sema_expr_analyse_ct_stringify(context, expr)) return false; diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index d586fea93..eb8422bec 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -1677,24 +1677,6 @@ static inline bool sema_check_type_case(SemaContext *context, Type *switch_type, return true; } -static inline ExprConst *flatten_enum_const(Expr *expr) -{ - ExprConst *const_expr = &expr->const_expr; - if (const_expr->const_kind == CONST_ENUM) - { - const_expr->const_kind = CONST_INTEGER; - - Decl *enum_val = const_expr->enum_val; - TODO - /* - Expr *enum_expr = exprptr(enum_val->enum_constant.ordinal2); - assert(enum_expr->expr_kind == EXPR_CONST); - ExprConst *enum_const = &enum_expr->const_expr; - assert(enum_const->const_kind == CONST_INTEGER); - *const_expr = *enum_const;*/ - } - return const_expr; -} static inline bool sema_check_value_case(SemaContext *context, Type *switch_type, Ast *case_stmt, Ast **cases, unsigned index, bool *if_chained, bool *max_ranged) { assert(switch_type); diff --git a/src/compiler/symtab.c b/src/compiler/symtab.c index 4919b5734..6ede155f3 100644 --- a/src/compiler/symtab.c +++ b/src/compiler/symtab.c @@ -40,6 +40,9 @@ const char *attribute_list[NUMBER_OF_ATTRIBUTES]; const char *builtin_list[NUMBER_OF_BUILTINS]; const char *kw_std__core; +const char *kw_std__core__types; +const char *kw_typekind; + const char *kw_in; const char *kw_out; const char *kw_inout; @@ -51,6 +54,7 @@ const char *kw_return; const char *kw_type; const char *kw_inf; const char *kw_inline; +const char *kw_kind; const char *kw_elementat; const char *kw_elementref; const char *kw_elementset; @@ -127,8 +131,12 @@ void symtab_init(uint32_t capacity) kw_FILE = KW_DEF("FILE"); kw_FUNC = KW_DEF("FUNC"); + type = TOKEN_TYPE_IDENT; + kw_typekind = KW_DEF("TypeKind"); + type = TOKEN_IDENT; kw_std__core = KW_DEF("std::core"); + kw_std__core__types = KW_DEF("std::core::types"); kw_sizeof = KW_DEF("sizeof"); kw_in = KW_DEF("in"); kw_out = KW_DEF("out"); @@ -140,6 +148,7 @@ void symtab_init(uint32_t capacity) kw_type = KW_DEF("type"); kw_inf = KW_DEF("inf"); kw_inline = KW_DEF("inline"); + kw_kind = KW_DEF("kind"); kw_elementat = KW_DEF("elementat"); kw_elementref = KW_DEF("elementref"); kw_elementset = KW_DEF("elementset"); diff --git a/src/compiler/target.c b/src/compiler/target.c index 354b0c3eb..1466f243b 100644 --- a/src/compiler/target.c +++ b/src/compiler/target.c @@ -37,7 +37,6 @@ static void type_dump(LLVMTargetDataRef llvm_target_data, LLVMTypeRef type) } - void llvm_dump(void) { static char* archs[] = { diff --git a/src/compiler/types.c b/src/compiler/types.c index 230b8a1f1..8a569d694 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -1456,15 +1456,6 @@ Type *type_decay_array_pointer(Type *type) } Type *type_find_max_type(Type *type, Type *other) { - if (type == type_anyfail) - { - return type_get_opt_fail(other, true); - } - if (other == type_anyfail) - { - return type_get_failable(type); - } - type = type->canonical; other = other->canonical; @@ -1597,4 +1588,73 @@ Type *type_find_common_ancestor(Type *left, Type *right) if (right == left_types[i]) return right; } } +} + +unsigned type_get_introspection_kind(TypeKind kind) +{ + switch (kind) + { + case TYPE_POISONED: + return 0; + case TYPE_VOID: + return INTROSPECT_TYPE_VOID; + case TYPE_BOOL: + return INTROSPECT_TYPE_BOOL; + case TYPE_I8: + case TYPE_I16: + case TYPE_I32: + case TYPE_I64: + case TYPE_I128: + return INTROSPECT_TYPE_SIGNED_INT; + case TYPE_U8: + case TYPE_U16: + case TYPE_U32: + case TYPE_U64: + case TYPE_U128: + return INTROSPECT_TYPE_UNSIGNED_INT; + case TYPE_F16: + case TYPE_F32: + case TYPE_F64: + case TYPE_F128: + return INTROSPECT_TYPE_FLOAT; + case TYPE_ANY: + return INTROSPECT_TYPE_VARIANT; + case TYPE_ANYERR: + return INTROSPECT_TYPE_ANYERR; + case TYPE_TYPEID: + return INTROSPECT_TYPE_TYPEID; + case TYPE_POINTER: + return INTROSPECT_TYPE_POINTER; + case TYPE_ENUM: + return INTROSPECT_TYPE_ENUM; + case TYPE_FUNC: + return INTROSPECT_TYPE_FUNC; + case TYPE_STRUCT: + return INTROSPECT_TYPE_STRUCT; + case TYPE_UNION: + return INTROSPECT_TYPE_UNION; + case TYPE_BITSTRUCT: + return INTROSPECT_TYPE_BITSTRUCT; + case TYPE_FAULTTYPE: + return INTROSPECT_TYPE_FAULT; + case TYPE_TYPEDEF: + UNREACHABLE + case TYPE_DISTINCT: + return INTROSPECT_TYPE_DISTINCT; + case TYPE_ARRAY: + case TYPE_INFERRED_ARRAY: + case TYPE_FLEXIBLE_ARRAY: + return INTROSPECT_TYPE_ARRAY; + case TYPE_SUBARRAY: + return INTROSPECT_TYPE_SUBARRAY; + case TYPE_VECTOR: + return INTROSPECT_TYPE_VECTOR; + case TYPE_UNTYPED_LIST: + case TYPE_FAILABLE_ANY: + case TYPE_TYPEINFO: + case TYPE_FAILABLE: + UNREACHABLE + return 0; + } + UNREACHABLE } \ No newline at end of file diff --git a/src/version.h b/src/version.h index 3ac708591..0cda20b3b 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.2.7" \ No newline at end of file +#define COMPILER_VERSION "0.2.8" \ No newline at end of file diff --git a/test/test_suite/initializer_lists/general_tests.c3t b/test/test_suite/initializer_lists/general_tests.c3t index c554d5556..f100e0476 100644 --- a/test/test_suite/initializer_lists/general_tests.c3t +++ b/test/test_suite/initializer_lists/general_tests.c3t @@ -76,27 +76,27 @@ entry: %5 = bitcast [3 x i32]* %literal to i32* %6 = insertvalue %"int[]" undef, i32* %5, 0 %7 = insertvalue %"int[]" %6, i64 3, 1 - %len = extractvalue %"int[]" %7, 1 - %not = icmp eq i64 %len, 0 - %8 = zext i1 %not to i8 - store i8 %8, i8* %x, align 1 - %9 = getelementptr inbounds %Bar, %Bar* %b, i32 0, i32 0 - store i32 0, i32* %9, align 4 - %10 = getelementptr inbounds %Bar, %Bar* %b, i32 0, i32 1 + %8 = extractvalue %"int[]" %7, 1 + %not = icmp eq i64 %8, 0 + %9 = zext i1 %not to i8 + store i8 %9, i8* %x, align 1 + %10 = getelementptr inbounds %Bar, %Bar* %b, i32 0, i32 0 store i32 0, i32* %10, align 4 - %11 = bitcast %Baz* %z to i8* - call void @llvm.memset.p0i8.i64(i8* align 8 %11, i8 0, i64 8, i1 false) + %11 = getelementptr inbounds %Bar, %Bar* %b, i32 0, i32 1 + store i32 0, i32* %11, align 4 + %12 = bitcast %Baz* %z to i8* + call void @llvm.memset.p0i8.i64(i8* align 8 %12, i8 0, i64 8, i1 false) store [0 x i32] zeroinitializer, [0 x i32]* %literal1, align 4 - %12 = bitcast [0 x i32]* %literal1 to i32* - %13 = insertvalue %"int[]" undef, i32* %12, 0 - %14 = insertvalue %"int[]" %13, i64 0, 1 - store %"int[]" %14, %"int[]"* %sub, align 8 + %13 = bitcast [0 x i32]* %literal1 to i32* + %14 = insertvalue %"int[]" undef, i32* %13, 0 + %15 = insertvalue %"int[]" %14, i64 0, 1 + store %"int[]" %15, %"int[]"* %sub, align 8 store [0 x %Bar] zeroinitializer, [0 x %Bar]* %literal2, align 4 - %15 = bitcast [0 x %Bar]* %literal2 to %Bar* - %16 = insertvalue %"Bar[]" undef, %Bar* %15, 0 - %17 = insertvalue %"Bar[]" %16, i64 0, 1 - store %"Bar[]" %17, %"Bar[]"* %foo, align 8 - %18 = bitcast [3 x %Baz]* %baz to i8* - call void @llvm.memset.p0i8.i64(i8* align 16 %18, i8 0, i64 24, i1 false) + %16 = bitcast [0 x %Bar]* %literal2 to %Bar* + %17 = insertvalue %"Bar[]" undef, %Bar* %16, 0 + %18 = insertvalue %"Bar[]" %17, i64 0, 1 + store %"Bar[]" %18, %"Bar[]"* %foo, align 8 + %19 = bitcast [3 x %Baz]* %baz to i8* + call void @llvm.memset.p0i8.i64(i8* align 16 %19, i8 0, i64 24, i1 false) ret i32 1 } \ No newline at end of file diff --git a/test/test_suite/initializer_lists/subarrays.c3t b/test/test_suite/initializer_lists/subarrays.c3t index cd7d29be5..88cce40e7 100644 --- a/test/test_suite/initializer_lists/subarrays.c3t +++ b/test/test_suite/initializer_lists/subarrays.c3t @@ -144,37 +144,37 @@ entry: %34 = bitcast [3 x i32]* %literal6 to i32* %35 = insertvalue %"int[]" undef, i32* %34, 0 %36 = insertvalue %"int[]" %35, i64 3, 1 - %len = extractvalue %"int[]" %36, 1 - %not = icmp eq i64 %len, 0 - %37 = zext i1 %not to i8 - store i8 %37, i8* %xy, align 1 - %38 = load i8, i8* %xy, align 1 - %39 = trunc i8 %38 to i1 - %not7 = xor i1 %39, true + %37 = extractvalue %"int[]" %36, 1 + %not = icmp eq i64 %37, 0 + %38 = zext i1 %not to i8 + store i8 %38, i8* %xy, align 1 + %39 = load i8, i8* %xy, align 1 + %40 = trunc i8 %39 to i1 + %not7 = xor i1 %40, true br i1 %not7, label %if.then, label %if.exit if.then: ; preds = %entry - %40 = call i32 @"std::io.println"(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.9, i32 0, i32 0)) #3 + %41 = call i32 @"std::io.println"(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.9, i32 0, i32 0)) #3 br label %if.exit if.exit: ; preds = %if.then, %entry - %41 = getelementptr inbounds %Bar, %Bar* %b, i32 0, i32 0 - store i32 0, i32* %41, align 4 - %42 = getelementptr inbounds %Bar, %Bar* %b, i32 0, i32 1 + %42 = getelementptr inbounds %Bar, %Bar* %b, i32 0, i32 0 store i32 0, i32* %42, align 4 - %43 = bitcast %Baz* %z to i8* - call void @llvm.memset.p0i8.i64(i8* align 8 %43, i8 0, i64 8, i1 false) + %43 = getelementptr inbounds %Bar, %Bar* %b, i32 0, i32 1 + store i32 0, i32* %43, align 4 + %44 = bitcast %Baz* %z to i8* + call void @llvm.memset.p0i8.i64(i8* align 8 %44, i8 0, i64 8, i1 false) store [0 x i32] zeroinitializer, [0 x i32]* %literal8, align 4 - %44 = bitcast [0 x i32]* %literal8 to i32* - %45 = insertvalue %"int[]" undef, i32* %44, 0 - %46 = insertvalue %"int[]" %45, i64 0, 1 - store %"int[]" %46, %"int[]"* %sub, align 8 + %45 = bitcast [0 x i32]* %literal8 to i32* + %46 = insertvalue %"int[]" undef, i32* %45, 0 + %47 = insertvalue %"int[]" %46, i64 0, 1 + store %"int[]" %47, %"int[]"* %sub, align 8 store [0 x %Bar] zeroinitializer, [0 x %Bar]* %literal9, align 4 - %47 = bitcast [0 x %Bar]* %literal9 to %Bar* - %48 = insertvalue %"Bar[]" undef, %Bar* %47, 0 - %49 = insertvalue %"Bar[]" %48, i64 0, 1 - store %"Bar[]" %49, %"Bar[]"* %foo, align 8 - %50 = bitcast [3 x %Baz]* %baz to i8* - call void @llvm.memset.p0i8.i64(i8* align 16 %50, i8 0, i64 24, i1 false) + %48 = bitcast [0 x %Bar]* %literal9 to %Bar* + %49 = insertvalue %"Bar[]" undef, %Bar* %48, 0 + %50 = insertvalue %"Bar[]" %49, i64 0, 1 + store %"Bar[]" %50, %"Bar[]"* %foo, align 8 + %51 = bitcast [3 x %Baz]* %baz to i8* + call void @llvm.memset.p0i8.i64(i8* align 16 %51, i8 0, i64 24, i1 false) ret i32 1 } diff --git a/test/test_suite/macros/macro_failable_return_rethrow.c3t b/test/test_suite/macros/macro_failable_return_rethrow.c3t new file mode 100644 index 000000000..bef481a2a --- /dev/null +++ b/test/test_suite/macros/macro_failable_return_rethrow.c3t @@ -0,0 +1,49 @@ +// #target: macos-x64 +module test; +fn int! xy() +{ + return 1; +} +macro int! foo() +{ + xy()?; + return 1; +} +fn void main() +{ + foo()!!; +} + +/* #expect: test.ll + +define void @test.main() #0 { +entry: + %error_var = alloca i64, align 8 + %blockret = alloca i32, align 4 + %error_var1 = alloca i64, align 8 + %retparam = alloca i32, align 4 + %0 = call i64 @test.xy(i32* %retparam) + %not_err = icmp eq i64 %0, 0 + br i1 %not_err, label %after.errcheck, label %error + +error: ; preds = %entry + store i64 %0, i64* %error_var1, align 8 + br label %guard_block + +after.errcheck: ; preds = %entry + br label %noerr_block + +guard_block: ; preds = %error + ret void + +noerr_block: ; preds = %after.errcheck + store i32 1, i32* %blockret, align 4 + br label %expr_block.exit + +expr_block.exit: ; preds = %noerr_block + %1 = load i32, i32* %blockret, align 4 + br label %noerr_block2 + +noerr_block2: ; preds = %expr_block.exit + ret void +} \ No newline at end of file diff --git a/test/test_suite/variant/variant_test.c3t b/test/test_suite/variant/variant_test.c3t index db5437959..3c2191286 100644 --- a/test/test_suite/variant/variant_test.c3t +++ b/test/test_suite/variant/variant_test.c3t @@ -70,7 +70,7 @@ fn void main() @.typeid.int = linkonce constant { i8, i16 } { i8 2, i16 32 }, align 2 @.typeid.double = linkonce constant { i8, i16 } { i8 4, i16 64 }, align 2 @.typeid.variant = linkonce constant { i8 } { i8 7 }, align 1 -@".typeid.int*" = linkonce constant { i8, i64 } { i8 15, i64 ptrtoint ({ i8, i16 }* @.typeid.int to i64) }, align 8 +@".typeid.int*" = linkonce constant { i8, i64 } { i8 19, i64 ptrtoint ({ i8, i16 }* @.typeid.int to i64) }, align 8 @.typeid.bool = linkonce constant { i8 } { i8 1 }, align 1 define void @foo.test(i64 %0, i8* %1) #0 { diff --git a/test/test_suite2/initializer_lists/general_tests.c3t b/test/test_suite2/initializer_lists/general_tests.c3t index 71ecfa811..53010aede 100644 --- a/test/test_suite2/initializer_lists/general_tests.c3t +++ b/test/test_suite2/initializer_lists/general_tests.c3t @@ -74,23 +74,23 @@ entry: store i32 3, ptr %3, align 4 %4 = insertvalue %"int[]" undef, ptr %literal, 0 %5 = insertvalue %"int[]" %4, i64 3, 1 - %len = extractvalue %"int[]" %5, 1 - %not = icmp eq i64 %len, 0 - %6 = zext i1 %not to i8 - store i8 %6, ptr %x, align 1 - %7 = getelementptr inbounds %Bar, ptr %b, i32 0, i32 0 - store i32 0, ptr %7, align 4 - %8 = getelementptr inbounds %Bar, ptr %b, i32 0, i32 1 + %6 = extractvalue %"int[]" %5, 1 + %not = icmp eq i64 %6, 0 + %7 = zext i1 %not to i8 + store i8 %7, ptr %x, align 1 + %8 = getelementptr inbounds %Bar, ptr %b, i32 0, i32 0 store i32 0, ptr %8, align 4 + %9 = getelementptr inbounds %Bar, ptr %b, i32 0, i32 1 + store i32 0, ptr %9, align 4 call void @llvm.memset.p0.i64(ptr align 8 %z, i8 0, i64 8, i1 false) store [0 x i32] zeroinitializer, ptr %literal1, align 4 - %9 = insertvalue %"int[]" undef, ptr %literal1, 0 - %10 = insertvalue %"int[]" %9, i64 0, 1 - store %"int[]" %10, ptr %sub, align 8 + %10 = insertvalue %"int[]" undef, ptr %literal1, 0 + %11 = insertvalue %"int[]" %10, i64 0, 1 + store %"int[]" %11, ptr %sub, align 8 store [0 x %Bar] zeroinitializer, ptr %literal2, align 4 - %11 = insertvalue %"Bar[]" undef, ptr %literal2, 0 - %12 = insertvalue %"Bar[]" %11, i64 0, 1 - store %"Bar[]" %12, ptr %foo, align 8 + %12 = insertvalue %"Bar[]" undef, ptr %literal2, 0 + %13 = insertvalue %"Bar[]" %12, i64 0, 1 + store %"Bar[]" %13, ptr %foo, align 8 call void @llvm.memset.p0.i64(ptr align 16 %baz, i8 0, i64 24, i1 false) ret i32 1 -} \ No newline at end of file +} diff --git a/test/test_suite2/initializer_lists/subarrays.c3t b/test/test_suite2/initializer_lists/subarrays.c3t index cd6c93a77..f28dca9ba 100644 --- a/test/test_suite2/initializer_lists/subarrays.c3t +++ b/test/test_suite2/initializer_lists/subarrays.c3t @@ -138,33 +138,33 @@ entry: store i32 3, ptr %29, align 4 %30 = insertvalue %"int[]" undef, ptr %literal6, 0 %31 = insertvalue %"int[]" %30, i64 3, 1 - %len = extractvalue %"int[]" %31, 1 - %not = icmp eq i64 %len, 0 - %32 = zext i1 %not to i8 - store i8 %32, ptr %xy, align 1 - %33 = load i8, ptr %xy, align 1 - %34 = trunc i8 %33 to i1 - %not7 = xor i1 %34, true + %32 = extractvalue %"int[]" %31, 1 + %not = icmp eq i64 %32, 0 + %33 = zext i1 %not to i8 + store i8 %33, ptr %xy, align 1 + %34 = load i8, ptr %xy, align 1 + %35 = trunc i8 %34 to i1 + %not7 = xor i1 %35, true br i1 %not7, label %if.then, label %if.exit if.then: ; preds = %entry - %35 = call i32 @"std::io.println"(ptr @.str.9) #3 + %36 = call i32 @"std::io.println"(ptr @.str.9) #3 br label %if.exit if.exit: ; preds = %if.then, %entry - %36 = getelementptr inbounds %Bar, ptr %b, i32 0, i32 0 - store i32 0, ptr %36, align 4 - %37 = getelementptr inbounds %Bar, ptr %b, i32 0, i32 1 + %37 = getelementptr inbounds %Bar, ptr %b, i32 0, i32 0 store i32 0, ptr %37, align 4 + %38 = getelementptr inbounds %Bar, ptr %b, i32 0, i32 1 + store i32 0, ptr %38, align 4 call void @llvm.memset.p0.i64(ptr align 8 %z, i8 0, i64 8, i1 false) store [0 x i32] zeroinitializer, ptr %literal8, align 4 - %38 = insertvalue %"int[]" undef, ptr %literal8, 0 - %39 = insertvalue %"int[]" %38, i64 0, 1 - store %"int[]" %39, ptr %sub, align 8 + %39 = insertvalue %"int[]" undef, ptr %literal8, 0 + %40 = insertvalue %"int[]" %39, i64 0, 1 + store %"int[]" %40, ptr %sub, align 8 store [0 x %Bar] zeroinitializer, ptr %literal9, align 4 - %40 = insertvalue %"Bar[]" undef, ptr %literal9, 0 - %41 = insertvalue %"Bar[]" %40, i64 0, 1 - store %"Bar[]" %41, ptr %foo, align 8 + %41 = insertvalue %"Bar[]" undef, ptr %literal9, 0 + %42 = insertvalue %"Bar[]" %41, i64 0, 1 + store %"Bar[]" %42, ptr %foo, align 8 call void @llvm.memset.p0.i64(ptr align 16 %baz, i8 0, i64 24, i1 false) ret i32 1 } diff --git a/test/test_suite2/macros/macro_failable_return_rethrow.c3t b/test/test_suite2/macros/macro_failable_return_rethrow.c3t new file mode 100644 index 000000000..dd09de47c --- /dev/null +++ b/test/test_suite2/macros/macro_failable_return_rethrow.c3t @@ -0,0 +1,49 @@ +// #target: macos-x64 +module test; +fn int! xy() +{ + return 1; +} +macro int! foo() +{ + xy()?; + return 1; +} +fn void main() +{ + foo()!!; +} + +/* #expect: test.ll + +define void @test.main() #0 { +entry: + %error_var = alloca i64, align 8 + %blockret = alloca i32, align 4 + %error_var1 = alloca i64, align 8 + %retparam = alloca i32, align 4 + %0 = call i64 @test.xy(ptr %retparam) + %not_err = icmp eq i64 %0, 0 + br i1 %not_err, label %after.errcheck, label %error + +error: ; preds = %entry + store i64 %0, ptr %error_var1, align 8 + br label %guard_block + +after.errcheck: ; preds = %entry + br label %noerr_block + +guard_block: ; preds = %error + ret void + +noerr_block: ; preds = %after.errcheck + store i32 1, ptr %blockret, align 4 + br label %expr_block.exit + +expr_block.exit: ; preds = %noerr_block + %1 = load i32, ptr %blockret, align 4 + br label %noerr_block2 + +noerr_block2: ; preds = %expr_block.exit + ret void +} \ No newline at end of file diff --git a/test/test_suite2/variant/variant_test.c3t b/test/test_suite2/variant/variant_test.c3t index 85d701c3d..e5a556b50 100644 --- a/test/test_suite2/variant/variant_test.c3t +++ b/test/test_suite2/variant/variant_test.c3t @@ -70,7 +70,7 @@ fn void main() @.typeid.int = linkonce constant { i8, i16 } { i8 2, i16 32 }, align 2 @.typeid.double = linkonce constant { i8, i16 } { i8 4, i16 64 }, align 2 @.typeid.variant = linkonce constant { i8 } { i8 7 }, align 1 -@".typeid.int*" = linkonce constant { i8, i64 } { i8 15, i64 ptrtoint (ptr @.typeid.int to i64) }, align 8 +@".typeid.int*" = linkonce constant { i8, i64 } { i8 19, i64 ptrtoint (ptr @.typeid.int to i64) }, align 8 @.typeid.bool = linkonce constant { i8 } { i8 1 }, align 1 define void @foo.test(i64 %0, ptr %1) #0 {