diff --git a/resources/examples/levenshtein.c3 b/resources/examples/levenshtein.c3 new file mode 100644 index 000000000..a8a70d4da --- /dev/null +++ b/resources/examples/levenshtein.c3 @@ -0,0 +1,26 @@ +module levenshtein; +import std::math; + +// This levenshtein exercises C3 subarrays. +fn int levenshtein(char[] s, char[] t) +{ + // if either string is empty, difference is inserting all chars + // from the other + if (!s.len) return t.len; + if (!t.len) return s.len; + + // if last letters are the same, the difference is whatever is + // required to edit the rest of the strings + if (s[^1] == t[^1]) return levenshtein(s[0..^2], t[0..^2]); + + // else try: + // changing last letter of s to that of t; or + // remove last letter of s; or + // remove last letter of t, + // any of which is 1 edit plus editing the rest of the strings + int a = levenshtein(s[0..^2], t[0..^2]); + int b = levenshtein(s, t[0..^2]); + int c = levenshtein(s[0..^2], t); + + return @min(@min(a, b), c) + 1; +} \ No newline at end of file diff --git a/resources/examples/notworking/levenshtein.c3 b/resources/examples/notworking/levenshtein.c3 deleted file mode 100644 index 25321e48a..000000000 --- a/resources/examples/notworking/levenshtein.c3 +++ /dev/null @@ -1,24 +0,0 @@ -module levenshtein; - -fn int levenshtein(String s, String t) -{ - // if either string is empty, difference is inserting all chars - // from the other - if (!s.len) return t.len; - if (!t.len) return s.len; - - // if last letters are the same, the difference is whatever is - // required to edit the rest of the strings - if (s[^1] == t[^1]) return levenshtein(s[0..^2], t[0..^2]); - - // else try: - // changing last letter of s to that of t; or - // remove last letter of s; or - // remove last letter of t, - // any of which is 1 edit plus editing the rest of the strings - int a = levenshtein(s[0..^2], t[0..^2]); - int b = levenshtein(s, t[0..^2]); - int c = levenshtein(s[0..^2], t); - - return @max(@max(a, b), c) + 1; -} \ No newline at end of file diff --git a/resources/examples/notworking/toml_parser_c2.c3 b/resources/examples/notworking/toml_parser_c2.c3 index c32c338e2..d35fbc0ed 100644 --- a/resources/examples/notworking/toml_parser_c2.c3 +++ b/resources/examples/notworking/toml_parser_c2.c3 @@ -373,7 +373,7 @@ fn void Parser.expect(Parser* p, TokenKind k) const u32 MaxDiag = 128; -public struct TomlReader @opaque +public struct TomlReader { char[MaxDiag] message; Blocks* blocks; diff --git a/resources/lib/std/math.c3 b/resources/lib/std/math.c3 index 8384e4a7a..137499b04 100644 --- a/resources/lib/std/math.c3 +++ b/resources/lib/std/math.c3 @@ -67,6 +67,16 @@ const QUAD_MIN_EXP = -16481; const QUAD_EPSILON = 1.92592994438723585305597794258492732e-34; */ +macro max(x, y) @autoimport +{ + return x > y ? x : y; +} + +macro min(x, y) @autoimport +{ + return x < y ? x : y; +} + fn double log10(double x) @inline { return $$log10(x); diff --git a/resources/testfragments/bigint.c3 b/resources/testfragments/bigint.c3 index 5c4bb8fc5..f9f220823 100644 --- a/resources/testfragments/bigint.c3 +++ b/resources/testfragments/bigint.c3 @@ -6,7 +6,7 @@ macro max(a, b) } // Horribly bad implementation of BigInt with add/sub. -public struct BigInt @opaque +public struct BigInt { byte* number; uint length; diff --git a/resources/testfragments/compilertest2.c3 b/resources/testfragments/compilertest2.c3 index ac1b136c0..a22850e89 100644 --- a/resources/testfragments/compilertest2.c3 +++ b/resources/testfragments/compilertest2.c3 @@ -6,7 +6,7 @@ macro @max(a, b) } // Horribly bad implementation of BigInt with add/sub. -public struct BigInt @opaque +public struct BigInt { byte& number; uint length; diff --git a/src/compiler/codegen_general.c b/src/compiler/codegen_general.c index 324ae096f..9dd41a282 100644 --- a/src/compiler/codegen_general.c +++ b/src/compiler/codegen_general.c @@ -274,8 +274,8 @@ bool type_is_homogenous_aggregate(Type *type, Type **base, unsigned *elements) if (type->type_kind == TYPE_VECTOR) { // Widen the type with elements. - unsigned vec_elements = type_size(type) / type_size(type->vector.base); - *base = type_get_vector(type->vector.base, vec_elements); + unsigned vec_elements = type_size(type) / type_size(type->array.base); + *base = type_get_vector(type->array.base, vec_elements); } } // One is vector - other isn't => failure diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 89eb21b2b..3671ee2ad 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -272,14 +272,12 @@ struct Type_ Decl *decl; // int, float, bool TypeBuiltin builtin; - // Type[], Type[*], Type[123] + // Type[], Type[*], Type[123], Type[<123>] or Type<[123]> TypeArray array; // func Type1(Type2, Type3, ...) throws Err1, Err2, ... TypeFunc func; // Type* Type *pointer; - // Type[<123>] or Type<[123]> - TypeVector vector; // Failable Type *failable; // Bitstruct @@ -583,7 +581,6 @@ typedef struct Decl_ Visibility visibility : 3; ResolveStatus resolve_status : 3; bool is_packed : 1; - bool is_opaque : 1; bool needs_additional_pad : 1; bool is_substruct : 1; bool has_variable_array : 1; @@ -1786,7 +1783,7 @@ static inline bool type_may_negate(Type *type) switch (type->type_kind) { case TYPE_VECTOR: - type = type->vector.base; + type = type->array.base; goto RETRY; case ALL_FLOATS: case ALL_INTS: @@ -2391,7 +2388,7 @@ static inline bool type_is_char_array(Type *type) static Type *type_vector_type(Type *type) { Type *flatten = type_flatten(type); - return flatten->type_kind == TYPE_VECTOR ? flatten->vector.base : NULL; + return flatten->type_kind == TYPE_VECTOR ? flatten->array.base : NULL; } static inline bool type_is_builtin(TypeKind kind) { return kind >= TYPE_VOID && kind <= TYPE_TYPEID; } diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 229ac6796..f715d60c4 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -641,7 +641,6 @@ typedef enum { ATTRIBUTE_INLINE, ATTRIBUTE_NOINLINE, - ATTRIBUTE_OPAQUE, ATTRIBUTE_BIGENDIAN, ATTRIBUTE_LITTLEENDIAN, ATTRIBUTE_NORETURN, diff --git a/src/compiler/llvm_codegen_c_abi_x64.c b/src/compiler/llvm_codegen_c_abi_x64.c index 43988b883..4b593480d 100644 --- a/src/compiler/llvm_codegen_c_abi_x64.c +++ b/src/compiler/llvm_codegen_c_abi_x64.c @@ -77,7 +77,7 @@ static bool x64_type_is_illegal_vector(Type *type) if (platform_target.x64.pass_int128_vector_in_mem) { // Illegal if i128/u128 - TypeKind kind = type->vector.base->type_kind; + TypeKind kind = type->array.base->type_kind; return kind == TYPE_I128 || kind == TYPE_U128; } // Otherwise fine! @@ -344,7 +344,7 @@ void x64_classify_vector(Type *type, ByteSize offset_base, X64Class *current, X6 } if (size == 8) { - Type *element = type->vector.base; + Type *element = type->array.base; // 1 x double passed in memory (by gcc) if (element->type_kind == TYPE_F64) return; @@ -628,7 +628,7 @@ static AbiType x64_get_byte_vector_type(Type *type) // If vector if (type->type_kind == TYPE_VECTOR) { - Type *element = type->vector.base->canonical; + Type *element = type->array.base->canonical; if (platform_target.x64.pass_int128_vector_in_mem && type_is_int128(element)) { // Convert to u64 diff --git a/src/compiler/llvm_codegen_c_abi_x86.c b/src/compiler/llvm_codegen_c_abi_x86.c index a00001225..36fcdceb5 100644 --- a/src/compiler/llvm_codegen_c_abi_x86.c +++ b/src/compiler/llvm_codegen_c_abi_x86.c @@ -187,7 +187,7 @@ ABIArgInfo *x86_classify_return(CallABI call, Regs *regs, Type *type) } // Always return in register if it fits in a general purpose // register, or if it is 64 bits and has a single field. - if (size == 1 || size == 2 || size == 4 || (size == 8 && type->vector.len == 1)) + if (size == 1 || size == 2 || size == 4 || (size == 8 && type->array.len == 1)) { return abi_arg_new_direct_coerce_type(type_int_unsigned_by_bitsize(size * 8)); } @@ -273,8 +273,8 @@ static inline bool x86_is_mmxtype(Type *type) { // Return true if the type is an MMX type <2 x i32>, <4 x i16>, or <8 x i8>. if (type->type_kind != TYPE_VECTOR) return false; - if (type_size(type->vector.base) >= 8) return false; - if (!type_is_integer(type->vector.base)) return false; + if (type_size(type->array.base) >= 8) return false; + if (!type_is_integer(type->array.base)) return false; return type_size(type) == 8; } @@ -442,7 +442,7 @@ static inline ABIArgInfo *x86_classify_vector(Regs *regs, Type *type) // it as an i8/i16/i32/i64. if (platform_target.x86.is_darwin_vector_abi) { - if ((size == 1 || size == 2 || size == 4) || (size == 8 && type->vector.len == 1)) + if ((size == 1 || size == 2 || size == 4) || (size == 8 && type->array.len == 1)) { return abi_arg_new_direct_coerce_type(type_int_unsigned_by_bitsize(size * 8)); } diff --git a/src/compiler/llvm_codegen_debug_info.c b/src/compiler/llvm_codegen_debug_info.c index 62278e385..a7738e17f 100644 --- a/src/compiler/llvm_codegen_debug_info.c +++ b/src/compiler/llvm_codegen_debug_info.c @@ -455,8 +455,8 @@ static LLVMMetadataRef llvm_debug_vector_type(GenContext *c, Type *type) Type *current_type = type; while (current_type->canonical->type_kind == TYPE_VECTOR) { - vec_add(ranges, LLVMDIBuilderGetOrCreateSubrange(c->debug.builder, 0, current_type->canonical->vector.len)); - current_type = current_type->canonical->vector.base; + vec_add(ranges, LLVMDIBuilderGetOrCreateSubrange(c->debug.builder, 0, current_type->canonical->array.len)); + current_type = current_type->canonical->array.base; } return LLVMDIBuilderCreateVectorType( c->debug.builder, diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 6cd35ffaa..45ad6f72c 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -495,11 +495,6 @@ static inline LLVMValueRef llvm_emit_sub_int(GenContext *c, Type *type, LLVMValu return LLVMBuildSub(c->builder, left, right, "sub"); } -static inline void llvm_emit_subscript_addr_base(GenContext *context, BEValue *value, Expr *parent) -{ - llvm_emit_expr(context, value, parent); - llvm_emit_ptr_from_array(context, value); -} static void llvm_emit_array_bounds_check(GenContext *c, BEValue *index, LLVMValueRef array_max_index, SourceLocation *loc) { @@ -527,13 +522,11 @@ static inline void llvm_emit_subscript_addr_with_base(GenContext *c, BEValue *re switch (type->type_kind) { case TYPE_POINTER: - llvm_value_set_address_abi_aligned(result, - llvm_emit_pointer_inbounds_gep_raw(c, - llvm_get_pointee_type(c, - parent->type), - parent->value, - index->value), - type->pointer); + llvm_value_set_address_abi_aligned(result, llvm_emit_pointer_inbounds_gep_raw( + c, + llvm_get_pointee_type(c, parent->type), + parent->value, + index->value), type->pointer); return; case TYPE_FLEXIBLE_ARRAY: { @@ -542,24 +535,17 @@ static inline void llvm_emit_subscript_addr_with_base(GenContext *c, BEValue *re llvm_value_set_address(result, ptr, type->array.base, alignment); return; } - case TYPE_ARRAY: case TYPE_VECTOR: + UNREACHABLE + case TYPE_ARRAY: + { // TODO vector - if (active_target.feature.safe_mode) - { - llvm_emit_array_bounds_check(c, index, llvm_const_int(c, index->type, type->array.len), loc); - } - { - AlignSize alignment; - LLVMValueRef ptr = llvm_emit_array_gep_raw_index(c, parent->value, llvm_get_type(c, type), index->value, parent->alignment, &alignment); - llvm_value_set_address(result, ptr, type->array.base, alignment); - } + AlignSize alignment; + LLVMValueRef ptr = llvm_emit_array_gep_raw_index(c, parent->value, llvm_get_type(c, type), index->value, parent->alignment, &alignment); + llvm_value_set_address(result, ptr, type->array.base, alignment); return; + } case TYPE_SUBARRAY: - if (active_target.feature.safe_mode) - { - // TODO insert trap on overflow. - } { LLVMValueRef ptr = llvm_emit_pointer_inbounds_gep_raw(c, llvm_get_type(c, type->array.base), parent->value, index->value); llvm_value_set_address(result, ptr, type->array.base, type_abi_alignment(type->array.base)); @@ -575,11 +561,17 @@ static inline void llvm_emit_vector_subscript(GenContext *c, BEValue *value, Exp { llvm_emit_expr(c, value, expr->subscript_expr.expr); llvm_value_rvalue(c, value); - Type *element = value->type->array.base; + Type *vec = value->type; + assert(vec->type_kind == TYPE_VECTOR); + Type *element = vec->array.base; LLVMValueRef vector = value->value; llvm_emit_expr(c, value, expr->subscript_expr.index); llvm_value_rvalue(c, value); LLVMValueRef index = value->value; + if (expr->subscript_expr.from_back) + { + 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); @@ -597,24 +589,55 @@ static inline void llvm_emit_vector_subscript(GenContext *c, BEValue *value, Exp static inline void gencontext_emit_subscript(GenContext *c, BEValue *value, Expr *expr) { bool is_value = expr->expr_kind == EXPR_SUBSCRIPT; - if (is_value && type_lowering(expr->subscript_expr.expr->type)->type_kind == TYPE_VECTOR) + Type *parent_type = type_lowering(expr->subscript_expr.expr->type); + if (is_value && parent_type->type_kind == TYPE_VECTOR) { llvm_emit_vector_subscript(c, value, expr); return; } BEValue ref; // First, get thing being subscripted. - llvm_emit_subscript_addr_base(c, &ref, expr->subscript_expr.expr); - // It needs to be an address. - llvm_value_addr(c, &ref); + llvm_emit_expr(c, value, expr->subscript_expr.expr); + BEValue len = { .value = NULL }; + TypeKind parent_type_kind = parent_type->type_kind; + // See if we need the length. + bool needs_len = false; + Expr *index_expr = expr->subscript_expr.index; + if (parent_type_kind == TYPE_SUBARRAY) + { + needs_len = active_target.feature.safe_mode || expr->subscript_expr.from_back; + } + else if (parent_type_kind == TYPE_ARRAY) + { + // From back should always be folded. + assert(expr->expr_kind != EXPR_CONST || !expr->subscript_expr.from_back); + needs_len = (active_target.feature.safe_mode && expr->expr_kind != EXPR_CONST) || expr->subscript_expr.from_back; + } + if (needs_len) + { + llvm_emit_len_for_expr(c, &len, value); + llvm_value_rvalue(c, &len); + } + + llvm_emit_ptr_from_array(c, value); + assert(llvm_value_is_addr(value)); // Now calculate the index: BEValue index; - llvm_emit_expr(c, &index, expr->subscript_expr.index); + llvm_emit_expr(c, &index, index_expr); // It needs to be an rvalue. llvm_value_rvalue(c, &index); - llvm_emit_subscript_addr_with_base(c, value, &ref, &index, TOKLOC(expr->subscript_expr.index->span.loc)); + if (expr->subscript_expr.from_back) + { + assert(needs_len); + index.value = LLVMBuildNUWSub(c->builder, llvm_zext_trunc(c, len.value, llvm_get_type(c, index.type)), index.value, ""); + } + if (needs_len && active_target.feature.safe_mode) + { + llvm_emit_array_bounds_check(c, &index, len.value, TOKLOC(expr->subscript_expr.index->span.loc)); + } + llvm_emit_subscript_addr_with_base(c, value, value, &index, TOKLOC(expr->subscript_expr.index->span.loc)); if (!is_value) { assert(llvm_value_is_addr(value)); @@ -1121,7 +1144,7 @@ void llvm_emit_array_to_vector_cast(GenContext *c, BEValue *value, Type *to_type 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->vector.len; i++) + for (unsigned i = 0; i < to_type->array.len; i++) { LLVMValueRef element = llvm_emit_extract_value(c, value->value, i); if (is_const) @@ -1971,7 +1994,7 @@ static inline void llvm_emit_inc_dec_change(GenContext *c, bool use_mod, BEValue } case TYPE_VECTOR: { - Type *element = type->vector.base; + Type *element = type->array.base; LLVMValueRef diff_value; bool is_integer = type_is_integer(element); if (is_integer) @@ -1982,7 +2005,7 @@ static inline void llvm_emit_inc_dec_change(GenContext *c, bool use_mod, BEValue { diff_value = LLVMConstReal(llvm_get_type(c, element), diff); } - ArraySize width = type->vector.len; + ArraySize width = type->array.len; LLVMValueRef val = LLVMGetUndef(llvm_get_type(c, type)); for (ArraySize i = 0; i < width; i++) { @@ -2165,22 +2188,27 @@ static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr void llvm_emit_len_for_expr(GenContext *c, BEValue *be_value, BEValue *expr_to_len) { - llvm_value_addr(c, expr_to_len); switch (expr_to_len->type->type_kind) { case TYPE_SUBARRAY: - { - LLVMTypeRef subarray_type = llvm_get_type(c, expr_to_len->type); - AlignSize alignment; - LLVMValueRef len_addr = llvm_emit_struct_gep_raw(c, - expr_to_len->value, - subarray_type, - 1, - expr_to_len->alignment, - &alignment); - llvm_value_set_address(be_value, len_addr, type_usize, alignment); + 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); + } + else + { + LLVMTypeRef subarray_type = llvm_get_type(c, expr_to_len->type); + AlignSize alignment; + LLVMValueRef len_addr = llvm_emit_struct_gep_raw(c, + expr_to_len->value, + subarray_type, + 1, + expr_to_len->alignment, + &alignment); + llvm_value_set_address(be_value, len_addr, type_usize, alignment); + } break; - } case TYPE_ARRAY: llvm_value_set(be_value, llvm_const_int(c, type_usize, expr_to_len->type->array.len), type_usize); break; @@ -2298,7 +2326,6 @@ static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_r // Check that index does not extend beyond the length. if (parent_type->type_kind != TYPE_POINTER && active_target.feature.safe_mode) { - assert(len.value); BEValue exceeds_size; llvm_emit_int_comparison(c, &exceeds_size, &start_index, &len, BINARYOP_GE); @@ -3016,7 +3043,7 @@ void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, BEValu Type *lhs_type = lhs.type; Type *rhs_type = rhs.type; - Type *vector_type = lhs_type->type_kind == TYPE_VECTOR ? lhs_type->vector.base : NULL; + Type *vector_type = lhs_type->type_kind == TYPE_VECTOR ? lhs_type->array.base : NULL; bool is_float = type_is_float(lhs_type) || (vector_type && type_is_float(vector_type)); LLVMValueRef val = NULL; LLVMValueRef lhs_value = lhs.value; @@ -3164,7 +3191,7 @@ void llvm_emit_derived_backend_type(GenContext *c, Type *type) original_type = type->failable; continue; case TYPE_VECTOR: - original_type = type->vector.base; + original_type = type->array.base; continue; case TYPE_ARRAY: case TYPE_SUBARRAY: @@ -5120,7 +5147,7 @@ static inline LLVMValueRef llvm_update_vector(GenContext *c, LLVMValueRef vector static inline void llvm_emit_vector_initializer_list(GenContext *c, BEValue *value, Expr *expr) { Type *type = type_lowering(expr->type); - Type *element_type = type->vector.base; + Type *element_type = type->array.base; LLVMTypeRef llvm_type = llvm_get_type(c, type); diff --git a/src/compiler/llvm_codegen_type.c b/src/compiler/llvm_codegen_type.c index b9c093448..54d498986 100644 --- a/src/compiler/llvm_codegen_type.c +++ b/src/compiler/llvm_codegen_type.c @@ -375,7 +375,7 @@ LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type) return any_type->backend_type = virtual_type; } case TYPE_VECTOR: - return any_type->backend_type = LLVMVectorType(llvm_get_type(c, any_type->vector.base), any_type->vector.len); + return any_type->backend_type = LLVMVectorType(llvm_get_type(c, any_type->array.base), any_type->array.len); } UNREACHABLE; } diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 8e18e0a45..21bec7041 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -494,7 +494,7 @@ bool cast_may_explicit(Type *from_type, Type *to_type, bool ignore_failability, case TYPE_ARRAY: if (to_kind == TYPE_VECTOR) { - return to_type->array.len == from_type->vector.len && to_type->array.base == from_type->array.base; + return to_type->array.len == from_type->array.len && to_type->array.base == from_type->array.base; } FALLTHROUGH; case TYPE_STRUCT: @@ -508,7 +508,7 @@ bool cast_may_explicit(Type *from_type, Type *to_type, bool ignore_failability, case TYPE_SUBARRAY: return to_kind == TYPE_POINTER; case TYPE_VECTOR: - return type_is_structurally_equivalent(type_get_array(from_type->vector.base, (uint32_t)from_type->vector.len), to_type); + return type_is_structurally_equivalent(type_get_array(from_type->array.base, (uint32_t)from_type->array.len), to_type); case TYPE_UNTYPED_LIST: REMINDER("Look at untyped list explicit conversions"); return false; diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 9af258426..5537699cd 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -389,10 +389,6 @@ static bool sema_analyse_struct_union(SemaContext *context, Decl *decl) had = decl->is_packed; decl->is_packed = true; break; - case ATTRIBUTE_OPAQUE: - had = decl->is_opaque; - decl->is_opaque = true; - break; default: UNREACHABLE } @@ -550,10 +546,6 @@ static bool sema_analyse_bitstruct(SemaContext *context, Decl *decl) case ATTRIBUTE_OVERLAP: SET_ATTR(overlap); break; - case ATTRIBUTE_OPAQUE: - had = decl->is_opaque; - decl->is_opaque = true; - break; case ATTRIBUTE_BIGENDIAN: if (decl->bitstruct.little_endian) { @@ -1143,7 +1135,6 @@ AttributeType sema_analyse_attribute(SemaContext *context, Attr *attr, Attribute [ATTRIBUTE_ALIGN] = ATTR_FUNC | ATTR_CONST | ATTR_LOCAL | ATTR_GLOBAL | ATTR_STRUCT | ATTR_UNION | ATTR_MEMBER, [ATTRIBUTE_INLINE] = ATTR_FUNC | ATTR_CALL, [ATTRIBUTE_NOINLINE] = ATTR_FUNC | ATTR_CALL, - [ATTRIBUTE_OPAQUE] = ATTR_STRUCT | ATTR_UNION | ATTR_BITSTRUCT, [ATTRIBUTE_BIGENDIAN] = ATTR_BITSTRUCT, [ATTRIBUTE_LITTLEENDIAN] = ATTR_BITSTRUCT, [ATTRIBUTE_USED] = (AttributeDomain)~ATTR_CALL, diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 0a233075d..5d856ae52 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -32,9 +32,8 @@ static bool sema_decay_array_pointers(Expr *expr) switch (expr_type->pointer->type_kind) { case TYPE_ARRAY: - return cast_implicit(expr, type_get_ptr(expr_type->pointer->array.base)); case TYPE_VECTOR: - return cast_implicit(expr, type_get_ptr(expr_type->pointer->vector.base)); + return cast_implicit(expr, type_get_ptr(expr_type->pointer->array.base)); default: return true; } @@ -93,7 +92,7 @@ static inline bool both_any_integer_or_integer_vector(Expr *left, Expr *right) if (flatten_left->type_kind != TYPE_VECTOR || flatten_right->type_kind != TYPE_VECTOR) return false; - return type_is_integer(flatten_left->vector.base) && type_is_integer(flatten_right->vector.base); + return type_is_integer(flatten_left->array.base) && type_is_integer(flatten_right->array.base); } Expr *expr_generate_decl(Decl *decl, Expr *assign) @@ -2385,7 +2384,7 @@ static void sema_deref_array_pointers(Expr *expr) } } -static bool expr_check_index_in_range(SemaContext *context, Type *type, Expr *index_expr, bool end_index, bool from_end) +static bool expr_check_index_in_range(SemaContext *context, Type *type, Expr *index_expr, bool end_index, bool from_end, bool *remove_from_end) { assert(type == type->canonical); if (index_expr->expr_kind != EXPR_CONST) return true; @@ -2416,6 +2415,8 @@ static bool expr_check_index_in_range(SemaContext *context, Type *type, Expr *in if (from_end) { idx = len - idx; + index_expr->const_expr.ixx.i.low = idx; + *remove_from_end = true; } // Checking end can only be done for arrays. if (end_index && idx >= len) @@ -2602,7 +2603,9 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, if (!expr_cast_to_index(index)) return false; // Check range - if (!expr_check_index_in_range(context, current_type, index, false, expr->subscript_expr.from_back)) return false; + bool remove_from_back = false; + if (!expr_check_index_in_range(context, current_type, index, false, expr->subscript_expr.from_back, &remove_from_back)) return false; + if (remove_from_back) expr->subscript_expr.from_back = false; expr->subscript_expr.expr = current_expr; if (is_addr) inner_type = type_get_ptr(inner_type); @@ -2656,8 +2659,12 @@ static inline bool sema_expr_analyse_slice(SemaContext *context, Expr *expr) return false; } } - if (!expr_check_index_in_range(context, type, start, false, expr->slice_expr.start_from_back)) return false; - if (end && !expr_check_index_in_range(context, type, end, true, expr->slice_expr.end_from_back)) return false; + bool remove_from_end = false; + if (!expr_check_index_in_range(context, type, start, false, expr->slice_expr.start_from_back, &remove_from_end)) return false; + if (remove_from_end) expr->slice_expr.start_from_back = false; + remove_from_end = false; + if (end && !expr_check_index_in_range(context, type, end, true, expr->slice_expr.end_from_back, &remove_from_end)) return false; + if (remove_from_end) expr->slice_expr.end_from_back = false; if (start && end && start->expr_kind == EXPR_CONST && end->expr_kind == EXPR_CONST) { @@ -3285,13 +3292,10 @@ static Type *sema_find_type_of_element(SemaContext *context, Type *type, Designa base = type_flattened->array.base; break; case TYPE_ARRAY: + case TYPE_VECTOR: len = type_flattened->array.len; base = type_flattened->array.base; break; - case TYPE_VECTOR: - len = type_flattened->vector.len; - base = type_flattened->vector.base; - break; default: return NULL; } @@ -5195,7 +5199,7 @@ static bool sema_expr_analyse_comp(SemaContext *context, Expr *expr, Expr *left, if (left_type->type_kind == TYPE_VECTOR && right_type->type_kind == TYPE_VECTOR) { - if (left_type->vector.len == right_type->vector.len) + if (left_type->array.len == right_type->array.len) { Type *left_vec = type_vector_type(left_type); Type *right_vec = type_vector_type(right_type); diff --git a/src/compiler/symtab.c b/src/compiler/symtab.c index e7ef9cd79..6703fb6dc 100644 --- a/src/compiler/symtab.c +++ b/src/compiler/symtab.c @@ -194,7 +194,6 @@ void symtab_init(uint32_t capacity) attribute_list[ATTRIBUTE_INLINE] = kw_inline; attribute_list[ATTRIBUTE_NOINLINE] = KW_DEF("noinline"); - attribute_list[ATTRIBUTE_OPAQUE] = KW_DEF("opaque"); attribute_list[ATTRIBUTE_BIGENDIAN] = KW_DEF("bigendian"); attribute_list[ATTRIBUTE_LITTLEENDIAN] = KW_DEF("littleendian"); attribute_list[ATTRIBUTE_NORETURN] = KW_DEF("noreturn"); diff --git a/src/compiler/types.c b/src/compiler/types.c index 14647e377..a3759a4bf 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -282,7 +282,7 @@ RETRY: goto RETRY; case TYPE_VECTOR: { - TypeSize width = type_size(type->vector.base) * type->vector.len; + TypeSize width = type_size(type->array.base) * type->array.len; if (width & (width - 1)) { AlignSize alignment = next_highest_power_of_2((uint32_t) width); @@ -340,7 +340,7 @@ const char *type_generate_qname(Type *type) bool type_is_float_or_float_vector(Type *type) { type = type_flatten(type); - if (type->type_kind == TYPE_VECTOR) type = type->vector.base; + if (type->type_kind == TYPE_VECTOR) type = type->array.base; TypeKind kind = type->type_kind; return kind >= TYPE_FLOAT_FIRST && kind <= TYPE_FLOAT_LAST; } @@ -494,7 +494,7 @@ AlignSize type_abi_alignment(Type *type) goto RETRY; case TYPE_VECTOR: { - ByteSize width = type_size(type->vector.base) * (uint32_t)type->vector.len; + ByteSize width = type_size(type->array.base) * (uint32_t)type->array.len; AlignSize alignment = (AlignSize)(int32_t)width; if (alignment & (alignment - 1)) { @@ -865,7 +865,7 @@ static Type *type_create_array(Type *element_type, ArraySize len, bool vector, b if (vector) { if (ptr_vec->type_kind != TYPE_VECTOR) continue; - if (ptr_vec->vector.len == len) return ptr_vec; + if (ptr_vec->array.len == len) return ptr_vec; } else { @@ -877,8 +877,8 @@ static Type *type_create_array(Type *element_type, ArraySize len, bool vector, b if (vector) { vec_arr = type_new(TYPE_VECTOR, strformat("%s[<%u>]", element_type->name, len)); - vec_arr->vector.base = element_type; - vec_arr->vector.len = len; + vec_arr->array.base = element_type; + vec_arr->array.len = len; } else { @@ -923,8 +923,8 @@ bool type_is_valid_for_vector(Type *type) Type *type_get_vector_bool(Type *original_type) { Type *type = type_flatten(original_type); - ByteSize size = type_size(type->vector.base); - return type_get_vector(type_int_signed_by_bitsize((unsigned)size * 8), (unsigned)original_type->vector.len); + ByteSize size = type_size(type->array.base); + return type_get_vector(type_int_signed_by_bitsize((unsigned)size * 8), (unsigned)original_type->array.len); } Type *type_get_vector(Type *vector_type, unsigned len) @@ -1468,9 +1468,8 @@ Type *type_decay_array_pointer(Type *type) switch (ptr->type_kind) { case TYPE_ARRAY: - return type_get_ptr(ptr->array.base->canonical); case TYPE_VECTOR: - return type_get_ptr(ptr->vector.base->canonical); + return type_get_ptr(ptr->array.base->canonical); default: return type; } @@ -1534,7 +1533,7 @@ Type *type_find_max_type(Type *type, Type *other) } if (type->pointer->type_kind == TYPE_VECTOR) { - Type *vector_base = type->pointer->vector.base->canonical; + Type *vector_base = type->pointer->array.base->canonical; if (other->type_kind == TYPE_SUBARRAY && vector_base == other->array.base->canonical) { return other; diff --git a/src/version.h b/src/version.h index 7be917e27..d2efbf31a 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "PRE.19" \ No newline at end of file +#define COMPILER_VERSION "PRE.20" \ No newline at end of file diff --git a/test/test_suite/arrays/index_from_back.c3t b/test/test_suite/arrays/index_from_back.c3t new file mode 100644 index 000000000..47eb18644 --- /dev/null +++ b/test/test_suite/arrays/index_from_back.c3t @@ -0,0 +1,61 @@ +// #target: x64-darwin + +module test; + +fn void test(int[10] x, int[<10>] y) +{ + int a = x[4]; + int b = x[^2]; + int c = y[4]; + int d = y[^2]; + int j = 3; + int e = y[^j]; + int f = x[^j]; +} + +/* #expect: test.ll + +define void @test.test([10 x i32]* byval([10 x i32]) align 8 %0, <10 x i32>* byval(<10 x i32>) align 64 %1) #0 { +entry: + %x = alloca [10 x i32], align 4 + %y = alloca <10 x i32>, align 64 + %a = alloca i32, align 4 + %b = alloca i32, align 4 + %c = alloca i32, align 4 + %d = alloca i32, align 4 + %j = alloca i32, align 4 + %e = alloca i32, align 4 + %f = alloca i32, align 4 + %2 = bitcast [10 x i32]* %x to i8* + %3 = bitcast [10 x i32]* %0 to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %2, i8* align 8 %3, i32 40, i1 false) + %4 = bitcast <10 x i32>* %y to i8* + %5 = bitcast <10 x i32>* %1 to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 64 %4, i8* align 64 %5, i32 64, i1 false) + %6 = getelementptr inbounds [10 x i32], [10 x i32]* %x, i64 0, i64 4 + %7 = load i32, i32* %6, align 4 + store i32 %7, i32* %a, align 4 + %8 = getelementptr inbounds [10 x i32], [10 x i32]* %x, i64 0, i64 8 + %9 = load i32, i32* %8, align 4 + store i32 %9, i32* %b, align 4 + %10 = load <10 x i32>, <10 x i32>* %y, align 64 + %11 = extractelement <10 x i32> %10, i64 4 + store i32 %11, i32* %c, align 4 + %12 = load <10 x i32>, <10 x i32>* %y, align 64 + %13 = extractelement <10 x i32> %12, i64 8 + store i32 %13, i32* %d, align 4 + store i32 3, i32* %j, align 4 + %14 = load <10 x i32>, <10 x i32>* %y, align 64 + %15 = load i32, i32* %j, align 4 + %sisiext = sext i32 %15 to i64 + %16 = sub nuw i64 10, %sisiext + %17 = extractelement <10 x i32> %14, i64 %16 + store i32 %17, i32* %e, align 4 + %18 = load i32, i32* %j, align 4 + %sisiext1 = sext i32 %18 to i64 + %19 = sub nuw i64 10, %sisiext1 + %20 = getelementptr inbounds [10 x i32], [10 x i32]* %x, i64 0, i64 %19 + %21 = load i32, i32* %20, align 4 + store i32 %21, i32* %f, align 4 + ret void +} \ No newline at end of file