aboutsummaryrefslogtreecommitdiff
path: root/src/codegen
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2022-03-27 14:21:32 -0700
committerAndrew Kelley <andrew@ziglang.org>2022-03-27 14:22:47 -0700
commit6d2ec7a4e39e3464bb5f14747937df9544e89ee7 (patch)
tree2fe3eaaef62f7cc9fb3c52aec6d7acf707786281 /src/codegen
parent052079c99455d01312d377d72fa1b8b5c0b22aad (diff)
downloadzig-6d2ec7a4e39e3464bb5f14747937df9544e89ee7.tar.gz
zig-6d2ec7a4e39e3464bb5f14747937df9544e89ee7.zip
LLVM: handle aggregate_init for packed structs
Diffstat (limited to 'src/codegen')
-rw-r--r--src/codegen/llvm.zig28
-rw-r--r--src/codegen/llvm/bindings.zig8
2 files changed, 36 insertions, 0 deletions
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index 049f7bfad6..431d158293 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -6459,6 +6459,34 @@ pub const FuncGen = struct {
return vector;
},
.Struct => {
+ if (result_ty.containerLayout() == .Packed) {
+ const struct_obj = result_ty.castTag(.@"struct").?.data;
+ const big_bits = struct_obj.packedIntegerBits(target);
+ const int_llvm_ty = self.dg.context.intType(big_bits);
+ const fields = struct_obj.fields.values();
+ comptime assert(Type.packed_struct_layout_version == 2);
+ var running_int: *const llvm.Value = int_llvm_ty.constNull();
+ var running_bits: u16 = 0;
+ for (elements) |elem, i| {
+ const field = fields[i];
+ if (!field.ty.hasRuntimeBitsIgnoreComptime()) continue;
+
+ const non_int_val = try self.resolveInst(elem);
+ const ty_bit_size = @intCast(u16, field.ty.bitSize(target));
+ const small_int_ty = self.dg.context.intType(ty_bit_size);
+ const small_int_val = self.builder.buildBitCast(non_int_val, small_int_ty, "");
+ const shift_rhs = int_llvm_ty.constInt(running_bits, .False);
+ // If the field is as large as the entire packed struct, this
+ // zext would go from, e.g. i16 to i16. This is legal with
+ // constZExtOrBitCast but not legal with constZExt.
+ const extended_int_val = self.builder.buildZExtOrBitCast(small_int_val, int_llvm_ty, "");
+ const shifted = self.builder.buildShl(extended_int_val, shift_rhs, "");
+ running_int = self.builder.buildOr(running_int, shifted, "");
+ running_bits += ty_bit_size;
+ }
+ return running_int;
+ }
+
var ptr_ty_buf: Type.Payload.Pointer = undefined;
if (isByRef(result_ty)) {
diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig
index b7a3ff7230..33b862499c 100644
--- a/src/codegen/llvm/bindings.zig
+++ b/src/codegen/llvm/bindings.zig
@@ -448,6 +448,14 @@ pub const Builder = opaque {
Name: [*:0]const u8,
) *const Value;
+ pub const buildZExtOrBitCast = LLVMBuildZExtOrBitCast;
+ extern fn LLVMBuildZExtOrBitCast(
+ *const Builder,
+ Val: *const Value,
+ DestTy: *const Type,
+ Name: [*:0]const u8,
+ ) *const Value;
+
pub const buildSExt = LLVMBuildSExt;
extern fn LLVMBuildSExt(
*const Builder,