authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-04-26 17:53:25-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-04-28 13:24:42-07:00
log36df2a83fc3a5ffbe7cb8022666adf7550da2913
tree27482e93ec4a82ecdf965cace97e1de8cedd6a8d
parent9295355985202c267b4326b5a6e2ad5158b48e5d

C backend: fix memset for structs and arrays


1 files changed, 90 insertions(+), 29 deletions(-)

src/codegen/c.zig+90-29
......@@ -4419,51 +4419,94 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
44194419 const dest_ty = f.air.typeOfIndex(inst);
44204420
44214421 const operand = try f.resolveInst(ty_op.operand);
4422 try reap(f, inst, &.{ty_op.operand});
44234422 const operand_ty = f.air.typeOf(ty_op.operand);
4424 const target = f.object.dg.module.getTarget();
4425 const writer = f.object.writer();
44264423
4427 const local = try f.allocLocal(inst, dest_ty);
4424 const bitcasted = try bitcast(f, dest_ty, operand, operand_ty);
4425 try reap(f, inst, &.{ty_op.operand});
4426 return bitcasted.move(f, inst, dest_ty);
4427}
4428
4429const LocalResult = struct {
4430 c_value: CValue,
4431 need_free: bool,
4432
4433 fn move(lr: LocalResult, f: *Function, inst: Air.Inst.Index, dest_ty: Type) !CValue {
4434 if (lr.need_free) {
4435 // Move the freshly allocated local to be owned by this instruction,
4436 // by returning it here instead of freeing it.
4437 return lr.c_value;
4438 }
4439
4440 const local = try f.allocLocal(inst, dest_ty);
4441 try lr.free(f);
4442 const writer = f.object.writer();
4443 try f.writeCValue(writer, local, .Other);
4444 if (dest_ty.isAbiInt()) {
4445 try writer.writeAll(" = ");
4446 } else {
4447 try writer.writeAll(" = (");
4448 try f.renderType(writer, dest_ty);
4449 try writer.writeByte(')');
4450 }
4451 try f.writeCValue(writer, lr.c_value, .Initializer);
4452 try writer.writeAll(";\n");
4453 return local;
4454 }
4455
4456 fn free(lr: LocalResult, f: *Function) !void {
4457 if (lr.need_free) {
4458 try freeLocal(f, 0, lr.c_value.new_local, 0);
4459 }
4460 }
4461};
44284462
4429 // If the assignment looks like 'x = x', we don't need it
4430 const can_elide = operand == .local and operand.local == local.new_local;
4463fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !LocalResult {
4464 const target = f.object.dg.module.getTarget();
4465 const writer = f.object.writer();
44314466
44324467 if (operand_ty.isAbiInt() and dest_ty.isAbiInt()) {
4433 if (can_elide) return local;
44344468 const src_info = dest_ty.intInfo(target);
44354469 const dest_info = operand_ty.intInfo(target);
44364470 if (src_info.signedness == dest_info.signedness and
44374471 src_info.bits == dest_info.bits)
44384472 {
4439 try f.writeCValue(writer, local, .Other);
4440 try writer.writeAll(" = ");
4441 try f.writeCValue(writer, operand, .Initializer);
4442 try writer.writeAll(";\n");
4443 return local;
4473 return .{
4474 .c_value = operand,
4475 .need_free = false,
4476 };
44444477 }
44454478 }
44464479
44474480 if (dest_ty.isPtrAtRuntime() and operand_ty.isPtrAtRuntime()) {
4448 if (can_elide) return local;
4481 const local = try f.allocLocal(0, dest_ty);
44494482 try f.writeCValue(writer, local, .Other);
44504483 try writer.writeAll(" = (");
44514484 try f.renderType(writer, dest_ty);
44524485 try writer.writeByte(')');
44534486 try f.writeCValue(writer, operand, .Other);
44544487 try writer.writeAll(";\n");
4455 return local;
4488 return .{
4489 .c_value = local,
4490 .need_free = true,
4491 };
44564492 }
44574493
44584494 const operand_lval = if (operand == .constant) blk: {
4459 const operand_local = try f.allocLocal(inst, operand_ty);
4495 const operand_local = try f.allocLocal(0, operand_ty);
44604496 try f.writeCValue(writer, operand_local, .Other);
4461 try writer.writeAll(" = ");
4497 if (operand_ty.isAbiInt()) {
4498 try writer.writeAll(" = ");
4499 } else {
4500 try writer.writeAll(" = (");
4501 try f.renderType(writer, operand_ty);
4502 try writer.writeByte(')');
4503 }
44624504 try f.writeCValue(writer, operand, .Initializer);
44634505 try writer.writeAll(";\n");
44644506 break :blk operand_local;
44654507 } else operand;
44664508
4509 const local = try f.allocLocal(0, dest_ty);
44674510 try writer.writeAll("memcpy(&");
44684511 try f.writeCValue(writer, local, .Other);
44694512 try writer.writeAll(", &");
......@@ -4528,10 +4571,13 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
45284571 }
45294572
45304573 if (operand == .constant) {
4531 try freeLocal(f, inst, operand_lval.new_local, 0);
4574 try freeLocal(f, 0, operand_lval.new_local, 0);
45324575 }
45334576
4534 return local;
4577 return .{
4578 .c_value = local,
4579 .need_free = true,
4580 };
45354581}
45364582
45374583fn airTrap(writer: anytype) !CValue {
......@@ -6288,15 +6334,27 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
62886334 }
62896335 try writer.writeAll("; ++");
62906336 try f.writeCValue(writer, index, .Other);
6291 try writer.writeAll(") ((");
6292 try f.renderType(writer, elem_ptr_ty);
6293 try writer.writeByte(')');
6294 try writeSliceOrPtr(f, writer, dest_slice, dest_ty);
6295 try writer.writeAll(")[");
6296 try f.writeCValue(writer, index, .Other);
6297 try writer.writeAll("] = ");
6298 try f.writeCValue(writer, value, .FunctionArgument);
6299 try writer.writeAll(";\n");
6337 try writer.writeAll(") ");
6338 if (lowersToArray(elem_ty, target)) {
6339 // Arrays are not assignable, so we use memcpy here.
6340 try writer.writeAll("memcpy(");
6341 try writeSliceOrPtr(f, writer, dest_slice, dest_ty);
6342 try writer.writeAll("[");
6343 try f.writeCValue(writer, index, .Other);
6344 try writer.writeAll("], ");
6345 try f.writeCValue(writer, value, .FunctionArgument);
6346 try writer.print(", {d});\n", .{elem_abi_size});
6347 } else {
6348 try writer.writeAll("((");
6349 try f.renderType(writer, elem_ptr_ty);
6350 try writer.writeByte(')');
6351 try writeSliceOrPtr(f, writer, dest_slice, dest_ty);
6352 try writer.writeAll(")[");
6353 try f.writeCValue(writer, index, .Other);
6354 try writer.writeAll("] = ");
6355 try f.writeCValue(writer, value, .FunctionArgument);
6356 try writer.writeAll(";\n");
6357 }
63006358
63016359 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
63026360 try freeLocal(f, inst, index.new_local, 0);
......@@ -6304,12 +6362,14 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
63046362 return .none;
63056363 }
63066364
6365 const bitcasted = try bitcast(f, Type.u8, value, elem_ty);
6366
63076367 try writer.writeAll("memset(");
63086368 switch (dest_ty.ptrSize()) {
63096369 .Slice => {
63106370 try f.writeCValueMember(writer, dest_slice, .{ .identifier = "ptr" });
63116371 try writer.writeAll(", ");
6312 try f.writeCValue(writer, value, .FunctionArgument);
6372 try f.writeCValue(writer, bitcasted.c_value, .FunctionArgument);
63136373 try writer.writeAll(", ");
63146374 try f.writeCValueMember(writer, dest_slice, .{ .identifier = "len" });
63156375 try writer.writeAll(");\n");
......@@ -6320,11 +6380,12 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
63206380
63216381 try f.writeCValue(writer, dest_slice, .FunctionArgument);
63226382 try writer.writeAll(", ");
6323 try f.writeCValue(writer, value, .FunctionArgument);
6383 try f.writeCValue(writer, bitcasted.c_value, .FunctionArgument);
63246384 try writer.print(", {d});\n", .{len});
63256385 },
63266386 .Many, .C => unreachable,
63276387 }
6388 try bitcasted.free(f);
63286389 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
63296390 return .none;
63306391}