- Fix alignment for uint128 to 16 with WASM targets.

- Incorrect assert in struct alignment checking #2841
- Packed structs sometimes not lowered as such.
This commit is contained in:
Christoffer Lerno
2026-01-25 23:05:43 +01:00
parent 4899ee14e2
commit e901a3de55
9 changed files with 50 additions and 11 deletions

View File

@@ -154,12 +154,13 @@ const bool FREEBSD = LIBC && OS_TYPE == FREEBSD;
const bool NETBSD = LIBC && OS_TYPE == NETBSD;
const bool BSD_FAMILY = env::FREEBSD || env::OPENBSD || env::NETBSD;
const bool WASI = LIBC && OS_TYPE == WASI;
const bool WASM = ARCH_TYPE == ArchType.WASM32 || ARCH_TYPE == ArchType.WASM64;
const bool ANDROID = LIBC && OS_TYPE == ANDROID;
const bool WASM_NOLIBC @builtin @deprecated("Use 'FREESTANDING_WASM' instead") = !LIBC && ARCH_TYPE == ArchType.WASM32 || ARCH_TYPE == ArchType.WASM64;
const bool FREESTANDING_PE32 = NO_LIBC && OS_TYPE == WIN32;
const bool FREESTANDING_MACHO = NO_LIBC && OS_TYPE == MACOS;
const bool FREESTANDING_ELF = NO_LIBC && !env::FREESTANDING_PE32 && !env::FREESTANDING_MACHO && !env::FREESTANDING_WASM;
const bool FREESTANDING_WASM = NO_LIBC && (ARCH_TYPE == ArchType.WASM32 || ARCH_TYPE == ArchType.WASM64);
const bool FREESTANDING_WASM = NO_LIBC && WASM;
const bool FREESTANDING = env::FREESTANDING_PE32 || env::FREESTANDING_MACHO || env::FREESTANDING_ELF || env::FREESTANDING_WASM;
const bool ADDRESS_SANITIZER = $$ADDRESS_SANITIZER;
const bool MEMORY_SANITIZER = $$MEMORY_SANITIZER;

View File

@@ -7,7 +7,7 @@ import std::os::posix, std::os::win32;
import std::math;
const MAX_MEMORY_ALIGNMENT = 0x1000_0000;
const DEFAULT_MEM_ALIGNMENT = (void*.alignof) * 2;
const DEFAULT_MEM_ALIGNMENT = env::WASM ? 16 : (void*.alignof) * 2;
const ulong KB = 1024;
const ulong MB = KB * 1024;
const ulong GB = MB * 1024;

View File

@@ -134,6 +134,9 @@
- Lowering of optional in && was incorrect #2843
- Resolving &X.b when X is a const incorrectly checked for runtime constness #2842
- Alignment param on $$unaligned_* not checked for zero #2844
- Fix alignment for uint128 to 16 with WASM targets.
- Incorrect assert in struct alignment checking #2841
- Packed structs sometimes not lowered as such.
### Stdlib changes
- Add `ThreadPool` join function to wait for all threads to finish in the pool without destroying the threads.

View File

@@ -49,6 +49,7 @@ static inline LLVMTypeRef llvm_type_from_decl(GenContext *c, Decl *decl)
vec_add(types, llvm_const_padding_type(c, decl->strukt.padding));
}
LLVMStructSetBody(type, types, vec_size(types), decl->is_packed);
ASSERT_SPAN(decl, llvm_abi_size(c, type) == type_size(decl->type));
return type;
}
case DECL_UNION:

View File

@@ -679,7 +679,7 @@ static bool sema_analyse_struct_members(SemaContext *context, Decl *decl)
}
if (is_unaligned && size > offset)
{
ASSERT(!decl->strukt.padding);
ASSERT(!decl->strukt.padding || decl->strukt.padding == size - offset);
decl->strukt.padding = size - offset;
}
@@ -703,7 +703,7 @@ static bool sema_analyse_struct_members(SemaContext *context, Decl *decl)
}
}
decl->is_packed = is_unaligned;
decl->is_packed |= is_unaligned;
// Strip padding if we are aligned.
if (!decl->is_packed && is_naturally_aligned)
{

View File

@@ -1683,9 +1683,7 @@ static AlignData os_target_alignment_of_int(OsType os, ArchType arch, uint32_t b
case ARCH_TYPE_PPC64:
case ARCH_TYPE_PPC:
case ARCH_TYPE_PPC64LE:
case ARCH_TYPE_WASM64:
case ARCH_TYPE_RISCV32:
case ARCH_TYPE_WASM32:
case ARCH_TYPE_XTENSA:
return (AlignData) { MIN(64u, bits), MIN(64u, bits) };
case ARCH_TYPE_X86_64:
@@ -1694,6 +1692,8 @@ static AlignData os_target_alignment_of_int(OsType os, ArchType arch, uint32_t b
#else
FALLTHROUGH;
#endif
case ARCH_TYPE_WASM64:
case ARCH_TYPE_WASM32:
case ARCH_TYPE_RISCV64:
return (AlignData) { bits, bits };
case ARCH_TYPE_AARCH64:

View File

@@ -58,7 +58,7 @@ fn int test5(ichar x)
return y.foo + y.bar;
}
// { i32, i16, i16 }
// <{ i32, i16, i16 }>
struct Foo6 @packed
{
int a;
@@ -76,16 +76,15 @@ Foo6 foo6 = { 1, 2, 3 };
%Foo3 = type <{ i8, i64, [7 x i8] }>
%Foo4 = type <{ i8, i64 }>
%Foo5 = type { i32, [12 x i8], i8, [15 x i8] }
%Foo6 = type { i32, i16, i16 }
%Foo6 = type <{ i32, i16, i16 }>
@struct2.foo1 = local_unnamed_addr global %Foo1 <{ i64 1, i8 2, [3 x i8] undef }>, align 4
@struct2.foo2 = local_unnamed_addr global %Foo2 <{ i8 1, i64 2, [3 x i8] undef }>, align 4
@struct2.foo3 = local_unnamed_addr global %Foo3 <{ i8 1, i64 2, [7 x i8] undef }>, align 8
@struct2.foo4 = local_unnamed_addr global %Foo4 <{ i8 1, i64 2 }>, align 1
@struct2.foo5 = local_unnamed_addr global %Foo5 { i32 1, [12 x i8] undef, i8 2, [15 x i8] undef }, align 16
@struct2.foo6 = local_unnamed_addr global %Foo6 { i32 1, i16 2, i16 3 }, align 1
@struct2.foo6 = local_unnamed_addr global %Foo6 <{ i32 1, i16 2, i16 3 }>, align 1
; Function Attrs:
define i32 @struct2.test5(i8 signext %0) #0 {
entry:
%y = alloca %Foo5, align 16

View File

@@ -36,7 +36,7 @@ fn void main()
/* #expect: test.ll
%Client = type <{ i32, %MsgHeader, i16, [2 x i8], %"ElasticArray{ulong, 1}" }>
%MsgHeader = type { i64 }
%MsgHeader = type <{ i64 }>
%"ElasticArray{ulong, 1}" = type { i64, [1 x i64] }
define void @test.main() #0 {

View File

@@ -0,0 +1,35 @@
// #target: macos-x64
module test;
struct Foo3 @align(8)
{
char foo;
Foo6 bar;
}
struct Foo6 @packed
{
short c;
}
fn int main()
{
Foo3 x;
return 0;
}
/* #expect: test.ll
%Foo3 = type <{ i8, %Foo6, [5 x i8] }>
%Foo6 = type <{ i16 }>
@"$ct.test.Foo3" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Foo6" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 2, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8
define i32 @main() #0 {
entry:
%x = alloca %Foo3, align 8
store i8 0, ptr %x, align 8
%ptradd = getelementptr inbounds i8, ptr %x, i64 1
store i16 0, ptr %ptradd, align 1
ret i32 0
}