From 2f3174fe1064e0d0b81735d59ed5021bfe51247d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 29 Jun 2026 11:41:27 +0100 Subject: [PATCH] Fix `llvm_const_cast` with constant `union` literals --- src/llvm_backend_const.cpp | 68 ++++++++++++++++++++++++++++++++---- src/llvm_backend_general.cpp | 14 ++++++-- 2 files changed, 73 insertions(+), 9 deletions(-) diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 0973d49d5..fffc9f94c 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -99,23 +99,69 @@ gb_internal LLVMValueRef llvm_const_cast(lbModule *m, LLVMValueRef val, LLVMType return LLVMConstNull(dst); } - GB_ASSERT_MSG(lb_sizeof(dst) == lb_sizeof(src), "%s vs %s", LLVMPrintTypeToString(dst), LLVMPrintTypeToString(src)); LLVMTypeKind kind = LLVMGetTypeKind(dst); switch (kind) { case LLVMPointerTypeKind: { + GB_ASSERT_MSG(lb_sizeof(dst) == lb_sizeof(src), "dst:%s vs src:%s (dst:%lld vs src:%lld)", LLVMPrintTypeToString(dst), LLVMPrintTypeToString(src), + cast(long long)lb_sizeof(dst), + cast(long long)lb_sizeof(src)); + return LLVMConstPointerCast(val, dst); } case LLVMStructTypeKind: { + GB_ASSERT_MSG(lb_sizeof(dst) == lb_sizeof(src), "dst:%s vs src:%s (dst:%lld vs src:%lld)", LLVMPrintTypeToString(dst), LLVMPrintTypeToString(src), + cast(long long)lb_sizeof(dst), + cast(long long)lb_sizeof(src)); + unsigned src_n = LLVMCountStructElementTypes(src); unsigned dst_n = LLVMCountStructElementTypes(dst); if (src_n != dst_n) goto failure; + bool skip_cast = true; + for (unsigned i = 0; i < dst_n; i++) { + LLVMTypeKind dt = LLVMGetTypeKind(LLVMStructGetTypeAtIndex(dst, i)); + LLVMTypeKind st = LLVMGetTypeKind(LLVMStructGetTypeAtIndex(src, i)); + if (dt != st) { + skip_cast = false; + } + if (dt == LLVMIntegerTypeKind) { + continue; + } + if (dt != LLVMArrayTypeKind) { + skip_cast = false; + break; + } + + LLVMValueRef field_val = llvm_const_extract_value(m, val, i); + if (field_val == nullptr) goto failure; + + LLVMTypeRef dst_elem_ty = LLVMStructGetTypeAtIndex(dst, i); + LLVMTypeRef src_elem_ty = LLVMTypeOf(field_val); + if (lb_sizeof(dst_elem_ty) > lb_sizeof(src_elem_ty)) { + skip_cast = true; + continue; + } + + } + if (skip_cast) { + return val; + } + LLVMValueRef *field_vals = temporary_alloc_array(dst_n); for (unsigned i = 0; i < dst_n; i++) { LLVMValueRef field_val = llvm_const_extract_value(m, val, i); if (field_val == nullptr) goto failure; LLVMTypeRef dst_elem_ty = LLVMStructGetTypeAtIndex(dst, i); + LLVMTypeRef src_elem_ty = LLVMTypeOf(field_val); + + GB_ASSERT_MSG(lb_sizeof(dst_elem_ty) == lb_sizeof(src_elem_ty), "dst:%s vs src:%s (dst:%lld vs src:%lld) to %s from %s", LLVMPrintTypeToString(dst_elem_ty), LLVMPrintTypeToString(src_elem_ty), + cast(long long)lb_sizeof(dst_elem_ty), + cast(long long)lb_sizeof(src_elem_ty), + LLVMPrintTypeToString(dst), + LLVMPrintTypeToString(src) + ); + field_vals[i] = llvm_const_cast(m, field_val, dst_elem_ty, failure_); if (failure_ && *failure_) goto failure; } @@ -126,6 +172,9 @@ gb_internal LLVMValueRef llvm_const_cast(lbModule *m, LLVMValueRef val, LLVMType return LLVMConstStructInContext(m->ctx, field_vals, dst_n, LLVMIsPackedStruct(dst)); } } + case LLVMArrayTypeKind: { + goto failure; + } } failure: @@ -946,21 +995,26 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty res.type = original_type; return res; } else { + LLVMValueRef values[4] = {}; + isize value_count = 0; + + // Payload + values[value_count++] = cv.value; unsigned tag_value = 1; if (bt->Union.kind == UnionType_no_nil) { tag_value = 0; } - LLVMValueRef tag = LLVMConstInt(LLVMStructGetTypeAtIndex(llvm_type, 1), tag_value, false); - LLVMValueRef padding = nullptr; - isize value_count = 2; + // Tag + values[value_count++] = LLVMConstInt(LLVMStructGetTypeAtIndex(llvm_type, 1), tag_value, false);; + if (LLVMCountStructElementTypes(llvm_type) > 2) { - value_count = 3; - padding = LLVMConstNull(LLVMStructGetTypeAtIndex(llvm_type, 2)); + GB_ASSERT(LLVMCountStructElementTypes(llvm_type) == 3); + // Padding + values[value_count++] = LLVMConstNull(LLVMStructGetTypeAtIndex(llvm_type, 2)); } - LLVMValueRef values[3] = {cv.value, tag, padding}; res.value = llvm_const_named_struct_internal(m, llvm_type, values, value_count); res.type = original_type; return res; diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 45380e7b6..e91ce3fd7 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1636,22 +1636,32 @@ gb_internal lbValue lb_emit_union_tag_ptr(lbProcedure *p, lbValue u) { GB_ASSERT_MSG(is_type_pointer(t) && is_type_union(type_deref(t)), "%s", type_to_string(t)); Type *ut = type_deref(t); + Type *bt = base_type(ut); GB_ASSERT(!is_type_union_maybe_pointer_original_alignment(ut)); GB_ASSERT(!is_type_union_maybe_pointer(ut)); GB_ASSERT(type_size_of(ut) > 0); + GB_ASSERT(bt->kind == Type_Union); Type *tag_type = union_tag_type(ut); LLVMTypeRef uvt = llvm_addr_type(p->module, u); unsigned element_count = LLVMCountStructElementTypes(uvt); - GB_ASSERT_MSG(element_count >= 2, "element_count=%u (%s) != (%s)", element_count, type_to_string(ut), LLVMPrintTypeToString(uvt)); + if (LLVM_VERSION_MAJOR == 14 || bt->Union.variants.count == 1) { + GB_ASSERT_MSG(element_count >= 2, "element_count=%u (%s) != (%s)", element_count, type_to_string(ut), LLVMPrintTypeToString(uvt)); + } else { + GB_ASSERT_MSG(element_count >= 3, "element_count=%u (%s) != (%s)", element_count, type_to_string(ut), LLVMPrintTypeToString(uvt)); + } LLVMValueRef ptr = u.value; ptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(uvt, 0), ""); lbValue tag_ptr = {}; - tag_ptr.value = LLVMBuildStructGEP2(p->builder, uvt, ptr, 1, ""); + if (LLVM_VERSION_MAJOR == 14 || bt->Union.variants.count == 1) { + tag_ptr.value = LLVMBuildStructGEP2(p->builder, uvt, ptr, 1, ""); + } else { + tag_ptr.value = LLVMBuildStructGEP2(p->builder, uvt, ptr, 2, ""); + } tag_ptr.type = alloc_type_pointer(tag_type); return tag_ptr; }