diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2023-04-26 17:53:25 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2023-04-28 13:24:42 -0700 |
| commit | 36df2a83fc3a5ffbe7cb8022666adf7550da2913 (patch) | |
| tree | 27482e93ec4a82ecdf965cace97e1de8cedd6a8d /src/codegen/c.zig | |
| parent | 9295355985202c267b4326b5a6e2ad5158b48e5d (diff) | |
| download | zig-36df2a83fc3a5ffbe7cb8022666adf7550da2913.tar.gz zig-36df2a83fc3a5ffbe7cb8022666adf7550da2913.zip | |
C backend: fix memset for structs and arrays
Diffstat (limited to 'src/codegen/c.zig')
| -rw-r--r-- | src/codegen/c.zig | 119 |
1 files changed, 90 insertions, 29 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 385094e495..9556419988 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -4419,51 +4419,94 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { const dest_ty = f.air.typeOfIndex(inst); const operand = try f.resolveInst(ty_op.operand); - try reap(f, inst, &.{ty_op.operand}); const operand_ty = f.air.typeOf(ty_op.operand); - const target = f.object.dg.module.getTarget(); - const writer = f.object.writer(); - const local = try f.allocLocal(inst, dest_ty); + const bitcasted = try bitcast(f, dest_ty, operand, operand_ty); + try reap(f, inst, &.{ty_op.operand}); + return bitcasted.move(f, inst, dest_ty); +} + +const LocalResult = struct { + c_value: CValue, + need_free: bool, + + fn move(lr: LocalResult, f: *Function, inst: Air.Inst.Index, dest_ty: Type) !CValue { + if (lr.need_free) { + // Move the freshly allocated local to be owned by this instruction, + // by returning it here instead of freeing it. + return lr.c_value; + } + + const local = try f.allocLocal(inst, dest_ty); + try lr.free(f); + const writer = f.object.writer(); + try f.writeCValue(writer, local, .Other); + if (dest_ty.isAbiInt()) { + try writer.writeAll(" = "); + } else { + try writer.writeAll(" = ("); + try f.renderType(writer, dest_ty); + try writer.writeByte(')'); + } + try f.writeCValue(writer, lr.c_value, .Initializer); + try writer.writeAll(";\n"); + return local; + } + + fn free(lr: LocalResult, f: *Function) !void { + if (lr.need_free) { + try freeLocal(f, 0, lr.c_value.new_local, 0); + } + } +}; - // If the assignment looks like 'x = x', we don't need it - const can_elide = operand == .local and operand.local == local.new_local; +fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !LocalResult { + const target = f.object.dg.module.getTarget(); + const writer = f.object.writer(); if (operand_ty.isAbiInt() and dest_ty.isAbiInt()) { - if (can_elide) return local; const src_info = dest_ty.intInfo(target); const dest_info = operand_ty.intInfo(target); if (src_info.signedness == dest_info.signedness and src_info.bits == dest_info.bits) { - try f.writeCValue(writer, local, .Other); - try writer.writeAll(" = "); - try f.writeCValue(writer, operand, .Initializer); - try writer.writeAll(";\n"); - return local; + return .{ + .c_value = operand, + .need_free = false, + }; } } if (dest_ty.isPtrAtRuntime() and operand_ty.isPtrAtRuntime()) { - if (can_elide) return local; + const local = try f.allocLocal(0, dest_ty); try f.writeCValue(writer, local, .Other); try writer.writeAll(" = ("); try f.renderType(writer, dest_ty); try writer.writeByte(')'); try f.writeCValue(writer, operand, .Other); try writer.writeAll(";\n"); - return local; + return .{ + .c_value = local, + .need_free = true, + }; } const operand_lval = if (operand == .constant) blk: { - const operand_local = try f.allocLocal(inst, operand_ty); + const operand_local = try f.allocLocal(0, operand_ty); try f.writeCValue(writer, operand_local, .Other); - try writer.writeAll(" = "); + if (operand_ty.isAbiInt()) { + try writer.writeAll(" = "); + } else { + try writer.writeAll(" = ("); + try f.renderType(writer, operand_ty); + try writer.writeByte(')'); + } try f.writeCValue(writer, operand, .Initializer); try writer.writeAll(";\n"); break :blk operand_local; } else operand; + const local = try f.allocLocal(0, dest_ty); try writer.writeAll("memcpy(&"); try f.writeCValue(writer, local, .Other); try writer.writeAll(", &"); @@ -4528,10 +4571,13 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { } if (operand == .constant) { - try freeLocal(f, inst, operand_lval.new_local, 0); + try freeLocal(f, 0, operand_lval.new_local, 0); } - return local; + return .{ + .c_value = local, + .need_free = true, + }; } fn airTrap(writer: anytype) !CValue { @@ -6288,15 +6334,27 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { } try writer.writeAll("; ++"); try f.writeCValue(writer, index, .Other); - try writer.writeAll(") (("); - try f.renderType(writer, elem_ptr_ty); - try writer.writeByte(')'); - try writeSliceOrPtr(f, writer, dest_slice, dest_ty); - try writer.writeAll(")["); - try f.writeCValue(writer, index, .Other); - try writer.writeAll("] = "); - try f.writeCValue(writer, value, .FunctionArgument); - try writer.writeAll(";\n"); + try writer.writeAll(") "); + if (lowersToArray(elem_ty, target)) { + // Arrays are not assignable, so we use memcpy here. + try writer.writeAll("memcpy("); + try writeSliceOrPtr(f, writer, dest_slice, dest_ty); + try writer.writeAll("["); + try f.writeCValue(writer, index, .Other); + try writer.writeAll("], "); + try f.writeCValue(writer, value, .FunctionArgument); + try writer.print(", {d});\n", .{elem_abi_size}); + } else { + try writer.writeAll("(("); + try f.renderType(writer, elem_ptr_ty); + try writer.writeByte(')'); + try writeSliceOrPtr(f, writer, dest_slice, dest_ty); + try writer.writeAll(")["); + try f.writeCValue(writer, index, .Other); + try writer.writeAll("] = "); + try f.writeCValue(writer, value, .FunctionArgument); + try writer.writeAll(";\n"); + } try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); try freeLocal(f, inst, index.new_local, 0); @@ -6304,12 +6362,14 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { return .none; } + const bitcasted = try bitcast(f, Type.u8, value, elem_ty); + try writer.writeAll("memset("); switch (dest_ty.ptrSize()) { .Slice => { try f.writeCValueMember(writer, dest_slice, .{ .identifier = "ptr" }); try writer.writeAll(", "); - try f.writeCValue(writer, value, .FunctionArgument); + try f.writeCValue(writer, bitcasted.c_value, .FunctionArgument); try writer.writeAll(", "); try f.writeCValueMember(writer, dest_slice, .{ .identifier = "len" }); try writer.writeAll(");\n"); @@ -6320,11 +6380,12 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { try f.writeCValue(writer, dest_slice, .FunctionArgument); try writer.writeAll(", "); - try f.writeCValue(writer, value, .FunctionArgument); + try f.writeCValue(writer, bitcasted.c_value, .FunctionArgument); try writer.print(", {d});\n", .{len}); }, .Many, .C => unreachable, } + try bitcasted.free(f); try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); return .none; } |
