mirror of
https://github.com/odin-lang/Odin.git
synced 2026-08-28 07:51:33 +00:00
Merge branch 'master' into const_array_broadcast
This commit is contained in:
@@ -782,6 +782,7 @@ cast_any_int_to_u128 :: proc(any_int_value: any) -> u128 {
|
||||
case i16le: u = u128(i)
|
||||
case i32le: u = u128(i)
|
||||
case i64le: u = u128(i)
|
||||
case i128le: u = u128(i)
|
||||
case u16le: u = u128(i)
|
||||
case u32le: u = u128(i)
|
||||
case u64le: u = u128(i)
|
||||
@@ -790,6 +791,7 @@ cast_any_int_to_u128 :: proc(any_int_value: any) -> u128 {
|
||||
case i16be: u = u128(i)
|
||||
case i32be: u = u128(i)
|
||||
case i64be: u = u128(i)
|
||||
case i128be: u = u128(i)
|
||||
case u16be: u = u128(i)
|
||||
case u32be: u = u128(i)
|
||||
case u64be: u = u128(i)
|
||||
|
||||
@@ -1037,7 +1037,9 @@ fmt_write_padding :: proc(fi: ^Info, width: int) {
|
||||
}
|
||||
|
||||
pad_byte: byte = ' '
|
||||
if !fi.space {
|
||||
if !fi.space && !fi.minus {
|
||||
// a left-justified field pads to the right of the digits, where a '0' would read
|
||||
// as part of the number rather than as filler
|
||||
pad_byte = '0'
|
||||
}
|
||||
|
||||
|
||||
@@ -5230,6 +5230,12 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
operand->type = t_invalid;
|
||||
return false;
|
||||
}
|
||||
convert_to_typed(c, &x, t_int);
|
||||
if (x.mode == Addressing_Invalid) {
|
||||
operand->mode = Addressing_Type;
|
||||
operand->type = t_invalid;
|
||||
return false;
|
||||
}
|
||||
i64 count = big_int_to_i64(&x.value.value_integer);
|
||||
|
||||
check_expr_or_type(c, &y, ce->args[1]);
|
||||
@@ -7710,6 +7716,12 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
return false;
|
||||
}
|
||||
|
||||
convert_to_typed(c, &x, t_int);
|
||||
if (x.mode == Addressing_Invalid) {
|
||||
operand->mode = Addressing_Type;
|
||||
operand->type = t_invalid;
|
||||
return false;
|
||||
}
|
||||
i64 index = big_int_to_i64(&x.value.value_integer);
|
||||
if (index < 0 || index >= u->Union.variants.count) {
|
||||
error(call, "Variant tag out of bounds index for '%.*s", LIT(builtin_name));
|
||||
|
||||
@@ -954,14 +954,17 @@ gb_internal void check_unroll_range_stmt(CheckerContext *ctx, Ast *node, u32 mod
|
||||
error(x.expr, "Expected a constant integer for #unroll, got '%s'", s);
|
||||
gb_string_free(s);
|
||||
} else {
|
||||
ExactValue value = exact_value_to_integer(x.value);
|
||||
i64 v = exact_value_to_i64(value);
|
||||
if (v < 1) {
|
||||
error(x.expr, "Expected a constant integer >= 1 for #unroll, got %lld", cast(long long)v);
|
||||
} else {
|
||||
unroll_count = v;
|
||||
if (v > 1024) {
|
||||
error(x.expr, "Too large of a value for #unroll, got %lld, expected <= 1024", cast(long long)v);
|
||||
convert_to_typed(ctx, &x, t_int);
|
||||
if (x.mode != Addressing_Invalid) {
|
||||
ExactValue value = exact_value_to_integer(x.value);
|
||||
i64 v = exact_value_to_i64(value);
|
||||
if (v < 1) {
|
||||
error(x.expr, "Expected a constant integer >= 1 for #unroll, got %lld", cast(long long)v);
|
||||
} else {
|
||||
unroll_count = v;
|
||||
if (v > 1024) {
|
||||
error(x.expr, "Too large of a value for #unroll, got %lld, expected <= 1024", cast(long long)v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1120,6 +1120,13 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type,
|
||||
gb_string_free(s);
|
||||
}
|
||||
|
||||
if (o.mode == Addressing_Constant) {
|
||||
convert_to_typed(ctx, &o, t_int);
|
||||
if (o.mode == Addressing_Invalid) {
|
||||
o.value = exact_value_i64(1);
|
||||
}
|
||||
}
|
||||
|
||||
ExactValue bit_size = o.value;
|
||||
|
||||
if (bit_size.kind != ExactValue_Integer) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Generates Documentation
|
||||
|
||||
gb_global int print_entity_kind_ordering[Entity_Count] = {
|
||||
gb_global int print_entity_kind_ordering[] = {
|
||||
/*Invalid*/ -1,
|
||||
/*Constant*/ 0,
|
||||
/*Variable*/ 1,
|
||||
@@ -12,8 +12,10 @@ gb_global int print_entity_kind_ordering[Entity_Count] = {
|
||||
/*LibraryName*/ -1,
|
||||
/*Nil*/ -1,
|
||||
/*Label*/ -1,
|
||||
/*AsmTemplate*/ 5,
|
||||
};
|
||||
gb_global char const *print_entity_names[Entity_Count] = {
|
||||
GB_STATIC_ASSERT(gb_count_of(print_entity_kind_ordering) == Entity_Count);
|
||||
gb_global char const *print_entity_names[] = {
|
||||
/*Invalid*/ "",
|
||||
/*Constant*/ "constants",
|
||||
/*Variable*/ "variables",
|
||||
@@ -25,7 +27,9 @@ gb_global char const *print_entity_names[Entity_Count] = {
|
||||
/*LibraryName*/ "library names",
|
||||
/*Nil*/ "",
|
||||
/*Label*/ "",
|
||||
/*AsmTemplate*/ "asm templates",
|
||||
};
|
||||
GB_STATIC_ASSERT(gb_count_of(print_entity_names) == Entity_Count);
|
||||
|
||||
|
||||
gb_internal GB_COMPARE_PROC(cmp_entities_for_printing) {
|
||||
@@ -257,6 +261,7 @@ gb_internal void print_doc_package(CheckerInfo *info, AstPackage *pkg) {
|
||||
case Entity_ProcGroup:
|
||||
case Entity_ImportName:
|
||||
case Entity_LibraryName:
|
||||
case Entity_AsmTemplate:
|
||||
// Fine
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -994,7 +994,7 @@ gb_internal lbAddr lb_find_or_generate_context_ptr(lbProcedure *p) {
|
||||
}
|
||||
|
||||
gb_internal lbValue lb_address_from_load_or_generate_local(lbProcedure *p, lbValue value) {
|
||||
if (LLVMIsALoadInst(value.value)) {
|
||||
if (!p->in_multi_assignment && LLVMIsALoadInst(value.value)) {
|
||||
lbValue res = {};
|
||||
res.value = LLVMGetOperand(value.value, 0);
|
||||
res.type = alloc_type_pointer(value.type);
|
||||
|
||||
@@ -3455,6 +3455,7 @@ gb_internal void print_show_unused(Checker *c) {
|
||||
case Entity_ProcGroup:
|
||||
case Entity_ImportName:
|
||||
case Entity_LibraryName:
|
||||
case Entity_AsmTemplate:
|
||||
// Fine
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2156,6 +2156,7 @@ gb_internal bool is_type_endian_specific(Type *t) {
|
||||
case Basic_u32le:
|
||||
case Basic_i64le:
|
||||
case Basic_u64le:
|
||||
case Basic_i128le:
|
||||
case Basic_u128le:
|
||||
return true;
|
||||
|
||||
@@ -2165,6 +2166,7 @@ gb_internal bool is_type_endian_specific(Type *t) {
|
||||
case Basic_u32be:
|
||||
case Basic_i64be:
|
||||
case Basic_u64be:
|
||||
case Basic_i128be:
|
||||
case Basic_u128be:
|
||||
return true;
|
||||
|
||||
@@ -3721,14 +3723,6 @@ gb_internal ProcTypeOverloadKind are_proc_types_overload_safe(Type *x, Type *y)
|
||||
return ProcOverload_TargetFeatures;
|
||||
}
|
||||
|
||||
if (px.params != nullptr && py.params != nullptr) {
|
||||
Entity *ex = px.params->Tuple.variables[0];
|
||||
Entity *ey = py.params->Tuple.variables[0];
|
||||
bool ok = are_types_identical(ex->type, ey->type);
|
||||
if (ok) {
|
||||
}
|
||||
}
|
||||
|
||||
return ProcOverload_Identical;
|
||||
}
|
||||
|
||||
|
||||
@@ -389,6 +389,34 @@ leaking_struct_tag :: proc(t: ^testing.T) {
|
||||
check(t, "My_Struct{names = [\"hello?\"], name_count = 1}", "%v", foo)
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_fmt_left_justified_padding :: proc(t: ^testing.T) {
|
||||
// a left-justified field pads to the right of the digits, so the fill has to be a space;
|
||||
// a '0' there is read back as part of the number
|
||||
check(t, "42 ", "%-5d", 42)
|
||||
check(t, "42 ", "%-5v", 42)
|
||||
check(t, "-42 ", "%-6d", -42)
|
||||
check(t, "ff ", "%-8x", 255)
|
||||
check(t, "101 ", "%-10b", 5)
|
||||
check(t, "3.140 ", "%-8f", 3.14)
|
||||
check(t, "3.0e+02 ", "%-10.1e", 300.0)
|
||||
check(t, "3.000000e+00 ", "%-14e", 3.0)
|
||||
check(t, "1tib ", "%-8.0m", mem.Terabyte)
|
||||
check(t, " ", "%-5.0d", 0)
|
||||
check(t, "ab ", "%-5s", "ab")
|
||||
check(t, "true ", "%-5t", true)
|
||||
check(t, "42 ", "%- 5d", 42)
|
||||
check(t, "42 ", "{:-5d}", 42)
|
||||
|
||||
// right-justified fields still zero fill, which is Odin's own convention
|
||||
check(t, "00042", "%5d", 42)
|
||||
check(t, "00042", "%05d", 42)
|
||||
check(t, "03.140", "%6f", 3.14)
|
||||
check(t, "-00042", "%6d", -42)
|
||||
check(t, "01tib", "%5.0m", mem.Terabyte)
|
||||
check(t, " ab", "%5s", "ab")
|
||||
}
|
||||
|
||||
@(private)
|
||||
check :: proc(t: ^testing.T, exp: string, format: string, args: ..any, loc := #caller_location) {
|
||||
got := fmt.tprintf(format, ..args)
|
||||
|
||||
@@ -49,11 +49,13 @@ set COMMON=-define:ODIN_TEST_FANCY=false -file -vet -strict-style -ignore-unused
|
||||
..\..\..\odin check ..\test_issue_ellipsis_type_call.odin -no-entry-point %COMMON% 2>&1 | find /c "Error:" | findstr /x "10" || exit /b
|
||||
..\..\..\odin check ..\test_issue_foreign_redeclaration.odin -no-entry-point %COMMON% || exit /b
|
||||
..\..\..\odin check ..\test_issue_foreign_redeclaration_mismatch.odin -no-entry-point %COMMON% 2>&1 | find /c "Error:" | findstr /x "1" || exit /b
|
||||
..\..\..\odin doc ..\test_issue_asm_doc_category.odin -file 2>&1 | find /c "asm templates" | findstr /x "1" || exit /b
|
||||
..\..\..\odin build ..\test_issue_7037.odin %COMMON% -o:none || exit /b
|
||||
..\..\..\odin build ..\test_issue_7188.odin %COMMON% || exit /b
|
||||
clang -c ..\test_issue_sysv_abi.c -o test_issue_sysv_abi_c.o || exit /b
|
||||
..\..\..\odin test ..\test_issue_sysv_abi.odin %COMMON% || exit /b
|
||||
..\..\..\odin build ..\test_issue_7073-1.odin %COMMON% 2>&1 | find /c "Error:" | findstr /x "2" || exit /b
|
||||
..\..\..\odin test ..\test_issue_swizzle_multi_assign.odin %COMMON% || exit /b
|
||||
|
||||
@echo off
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@ $ODIN check ../test_issue_7260.odin -no-entry-point $COMMON_CHECK
|
||||
$ODIN test ../test_issue_bool_to_be_conversion.odin $COMMON
|
||||
$ODIN test ../test_issue_bool_comparison_truthiness.odin $COMMON
|
||||
$ODIN test ../test_issue_const_array_broadcast.odin $COMMON
|
||||
$ODIN test ../test_issue_swizzle_multi_assign.odin $COMMON
|
||||
|
||||
$ODIN check ../test_issue_foreign_redeclaration.odin -no-entry-point $COMMON_CHECK
|
||||
if [[ $($ODIN check ../test_issue_foreign_redeclaration_mismatch.odin -no-entry-point $COMMON_CHECK 2>&1 >/dev/null | grep -c "Error:") -eq 1 ]]; then
|
||||
@@ -115,6 +116,16 @@ else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# `asm` templates are amd64-only, so this file is empty on every other architecture
|
||||
if [[ "$(uname -m)" == "x86_64" || "$(uname -m)" == "amd64" ]]; then
|
||||
if [[ $($ODIN doc ../test_issue_asm_doc_category.odin -file 2>&1 | grep -c "asm templates") -eq 1 ]]; then
|
||||
echo "SUCCESSFUL 1/1"
|
||||
else
|
||||
echo "SUCCESSFUL 0/1"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $($ODIN build ../test_issue_7108.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 2 ]]; then
|
||||
echo "SUCCESSFUL 1/1"
|
||||
else
|
||||
|
||||
16
tests/issues/test_issue_asm_doc_category.odin
Normal file
16
tests/issues/test_issue_asm_doc_category.odin
Normal file
@@ -0,0 +1,16 @@
|
||||
#+build amd64
|
||||
// `Entity_AsmTemplate` was added to `ENTITY_KINDS` but not to the two `[Entity_Count]` tables in
|
||||
// `src/docs.cpp`, so its slot was zero-filled: ordering `0` and a null name. `odin doc` and
|
||||
// `odin check -show-unused` printed an `asm` template under an empty category header, and passed
|
||||
// the null name to a `%s`.
|
||||
package test_issues
|
||||
|
||||
DOC_CONST :: 1
|
||||
|
||||
doc_proc :: proc() {}
|
||||
|
||||
doc_asm :: asm() { nop; }
|
||||
|
||||
doc_asm_32 :: asm(a: i32) -> (v: i32) { mov v, a; }
|
||||
doc_asm_64 :: asm(a: i64) -> (v: i64) { mov v, a; }
|
||||
doc_asm_group :: asm { doc_asm_32, doc_asm_64 }
|
||||
80
tests/issues/test_issue_swizzle_multi_assign.odin
Normal file
80
tests/issues/test_issue_swizzle_multi_assign.odin
Normal file
@@ -0,0 +1,80 @@
|
||||
package test_issues
|
||||
|
||||
import "core:testing"
|
||||
|
||||
// A multi-assignment reads every right-hand side before it stores into any target, which is what
|
||||
// makes `a, b = b, a` a swap. Storing into a swizzle reused the address the source was loaded from
|
||||
// instead of the value read at that point, so a source that named a target written earlier in the
|
||||
// same statement read back the new contents.
|
||||
|
||||
@(test)
|
||||
swizzle_multi_assign_swap :: proc(t: ^testing.T) {
|
||||
v := [4]f32{1, 2, 3, 4}
|
||||
v.xy, v.zw = v.zw, v.xy
|
||||
testing.expect_value(t, v, [4]f32{3, 4, 1, 2})
|
||||
|
||||
// the other order happened to be correct already
|
||||
w := [4]f32{1, 2, 3, 4}
|
||||
w.zw, w.xy = w.xy, w.zw
|
||||
testing.expect_value(t, w, [4]f32{3, 4, 1, 2})
|
||||
|
||||
x := [4]f32{1, 2, 3, 4}
|
||||
x.xy, x.wz = x.wz, x.xy
|
||||
testing.expect_value(t, x, [4]f32{4, 3, 2, 1})
|
||||
}
|
||||
|
||||
@(test)
|
||||
swizzle_multi_assign_element_types :: proc(t: ^testing.T) {
|
||||
a := [4]i32{1, 2, 3, 4}
|
||||
a.xy, a.zw = a.zw, a.xy
|
||||
testing.expect_value(t, a, [4]i32{3, 4, 1, 2})
|
||||
|
||||
b := [4]f64{1, 2, 3, 4}
|
||||
b.xy, b.zw = b.zw, b.xy
|
||||
testing.expect_value(t, b, [4]f64{3, 4, 1, 2})
|
||||
|
||||
c := [4]u8{1, 2, 3, 4}
|
||||
c.xy, c.zw = c.zw, c.xy
|
||||
testing.expect_value(t, c, [4]u8{3, 4, 1, 2})
|
||||
}
|
||||
|
||||
@(test)
|
||||
swizzle_multi_assign_through_pointer :: proc(t: ^testing.T) {
|
||||
v := [4]f32{1, 2, 3, 4}
|
||||
p := &v
|
||||
p.xy, p.zw = p.zw, p.xy
|
||||
testing.expect_value(t, v, [4]f32{3, 4, 1, 2})
|
||||
}
|
||||
|
||||
@(test)
|
||||
swizzle_multi_assign_across_variables :: proc(t: ^testing.T) {
|
||||
// the source names a different variable, which an earlier store still writes to
|
||||
a := [4]f32{1, 2, 3, 4}
|
||||
b := [4]f32{5, 6, 7, 8}
|
||||
a.xy, b.xy = b.xy, a.xy
|
||||
testing.expect_value(t, a, [4]f32{5, 6, 3, 4})
|
||||
testing.expect_value(t, b, [4]f32{1, 2, 7, 8})
|
||||
}
|
||||
|
||||
@(test)
|
||||
swizzle_multi_assign_three_targets :: proc(t: ^testing.T) {
|
||||
v := [4]f32{1, 2, 3, 4}
|
||||
v.xy, v.zw, v.x = v.zw, v.xy, v.w
|
||||
testing.expect_value(t, v, [4]f32{4, 4, 1, 2})
|
||||
}
|
||||
|
||||
@(test)
|
||||
swizzle_single_assign_unchanged :: proc(t: ^testing.T) {
|
||||
// one target still reads every lane before it writes any of them
|
||||
v := [4]f32{1, 2, 3, 4}
|
||||
v.yzw = v.xyz
|
||||
testing.expect_value(t, v, [4]f32{1, 1, 2, 3})
|
||||
|
||||
w := [4]f32{1, 2, 3, 4}
|
||||
w.xy = w.zw
|
||||
testing.expect_value(t, w, [4]f32{3, 4, 3, 4})
|
||||
|
||||
x := [4]f32{1, 2, 3, 4}
|
||||
x.x, x.y = x.y, x.x
|
||||
testing.expect_value(t, x, [4]f32{2, 1, 3, 4})
|
||||
}
|
||||
Reference in New Issue
Block a user