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 {...@@ -4419,51 +4419,94 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
4419 const dest_ty = f.air.typeOfIndex(inst);4419 const dest_ty = f.air.typeOfIndex(inst);
44204420
4421 const operand = try f.resolveInst(ty_op.operand);4421 const operand = try f.resolveInst(ty_op.operand);
4422 try reap(f, inst, &.{ty_op.operand});
4423 const operand_ty = f.air.typeOf(ty_op.operand);4422 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 it4463fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !LocalResult {
4430 const can_elide = operand == .local and operand.local == local.new_local;4464 const target = f.object.dg.module.getTarget();
4465 const writer = f.object.writer();
44314466
4432 if (operand_ty.isAbiInt() and dest_ty.isAbiInt()) {4467 if (operand_ty.isAbiInt() and dest_ty.isAbiInt()) {
4433 if (can_elide) return local;
4434 const src_info = dest_ty.intInfo(target);4468 const src_info = dest_ty.intInfo(target);
4435 const dest_info = operand_ty.intInfo(target);4469 const dest_info = operand_ty.intInfo(target);
4436 if (src_info.signedness == dest_info.signedness and4470 if (src_info.signedness == dest_info.signedness and
4437 src_info.bits == dest_info.bits)4471 src_info.bits == dest_info.bits)
4438 {4472 {
4439 try f.writeCValue(writer, local, .Other);4473 return .{
4440 try writer.writeAll(" = ");4474 .c_value = operand,
4441 try f.writeCValue(writer, operand, .Initializer);4475 .need_free = false,
4442 try writer.writeAll(";\n");4476 };
4443 return local;
4444 }4477 }
4445 }4478 }
44464479
4447 if (dest_ty.isPtrAtRuntime() and operand_ty.isPtrAtRuntime()) {4480 if (dest_ty.isPtrAtRuntime() and operand_ty.isPtrAtRuntime()) {
4448 if (can_elide) return local;4481 const local = try f.allocLocal(0, dest_ty);
4449 try f.writeCValue(writer, local, .Other);4482 try f.writeCValue(writer, local, .Other);
4450 try writer.writeAll(" = (");4483 try writer.writeAll(" = (");
4451 try f.renderType(writer, dest_ty);4484 try f.renderType(writer, dest_ty);
4452 try writer.writeByte(')');4485 try writer.writeByte(')');
4453 try f.writeCValue(writer, operand, .Other);4486 try f.writeCValue(writer, operand, .Other);
4454 try writer.writeAll(";\n");4487 try writer.writeAll(";\n");
4455 return local;4488 return .{
4489 .c_value = local,
4490 .need_free = true,
4491 };
4456 }4492 }
44574493
4458 const operand_lval = if (operand == .constant) blk: {4494 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);
4460 try f.writeCValue(writer, operand_local, .Other);4496 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 }
4462 try f.writeCValue(writer, operand, .Initializer);4504 try f.writeCValue(writer, operand, .Initializer);
4463 try writer.writeAll(";\n");4505 try writer.writeAll(";\n");
4464 break :blk operand_local;4506 break :blk operand_local;
4465 } else operand;4507 } else operand;
44664508
4509 const local = try f.allocLocal(0, dest_ty);
4467 try writer.writeAll("memcpy(&");4510 try writer.writeAll("memcpy(&");
4468 try f.writeCValue(writer, local, .Other);4511 try f.writeCValue(writer, local, .Other);
4469 try writer.writeAll(", &");4512 try writer.writeAll(", &");
...@@ -4528,10 +4571,13 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4528,10 +4571,13 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
4528 }4571 }
45294572
4530 if (operand == .constant) {4573 if (operand == .constant) {
4531 try freeLocal(f, inst, operand_lval.new_local, 0);4574 try freeLocal(f, 0, operand_lval.new_local, 0);
4532 }4575 }
45334576
4534 return local;4577 return .{
4578 .c_value = local,
4579 .need_free = true,
4580 };
4535}4581}
45364582
4537fn airTrap(writer: anytype) !CValue {4583fn airTrap(writer: anytype) !CValue {
...@@ -6288,15 +6334,27 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {...@@ -6288,15 +6334,27 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
6288 }6334 }
6289 try writer.writeAll("; ++");6335 try writer.writeAll("; ++");
6290 try f.writeCValue(writer, index, .Other);6336 try f.writeCValue(writer, index, .Other);
6291 try writer.writeAll(") ((");6337 try writer.writeAll(") ");
6292 try f.renderType(writer, elem_ptr_ty);6338 if (lowersToArray(elem_ty, target)) {
6293 try writer.writeByte(')');6339 // Arrays are not assignable, so we use memcpy here.
6294 try writeSliceOrPtr(f, writer, dest_slice, dest_ty);6340 try writer.writeAll("memcpy(");
6295 try writer.writeAll(")[");6341 try writeSliceOrPtr(f, writer, dest_slice, dest_ty);
6296 try f.writeCValue(writer, index, .Other);6342 try writer.writeAll("[");
6297 try writer.writeAll("] = ");6343 try f.writeCValue(writer, index, .Other);
6298 try f.writeCValue(writer, value, .FunctionArgument);6344 try writer.writeAll("], ");
6299 try writer.writeAll(";\n");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
6301 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });6359 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
6302 try freeLocal(f, inst, index.new_local, 0);6360 try freeLocal(f, inst, index.new_local, 0);
...@@ -6304,12 +6362,14 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {...@@ -6304,12 +6362,14 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
6304 return .none;6362 return .none;
6305 }6363 }
63066364
6365 const bitcasted = try bitcast(f, Type.u8, value, elem_ty);
6366
6307 try writer.writeAll("memset(");6367 try writer.writeAll("memset(");
6308 switch (dest_ty.ptrSize()) {6368 switch (dest_ty.ptrSize()) {
6309 .Slice => {6369 .Slice => {
6310 try f.writeCValueMember(writer, dest_slice, .{ .identifier = "ptr" });6370 try f.writeCValueMember(writer, dest_slice, .{ .identifier = "ptr" });
6311 try writer.writeAll(", ");6371 try writer.writeAll(", ");
6312 try f.writeCValue(writer, value, .FunctionArgument);6372 try f.writeCValue(writer, bitcasted.c_value, .FunctionArgument);
6313 try writer.writeAll(", ");6373 try writer.writeAll(", ");
6314 try f.writeCValueMember(writer, dest_slice, .{ .identifier = "len" });6374 try f.writeCValueMember(writer, dest_slice, .{ .identifier = "len" });
6315 try writer.writeAll(");\n");6375 try writer.writeAll(");\n");
...@@ -6320,11 +6380,12 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {...@@ -6320,11 +6380,12 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
63206380
6321 try f.writeCValue(writer, dest_slice, .FunctionArgument);6381 try f.writeCValue(writer, dest_slice, .FunctionArgument);
6322 try writer.writeAll(", ");6382 try writer.writeAll(", ");
6323 try f.writeCValue(writer, value, .FunctionArgument);6383 try f.writeCValue(writer, bitcasted.c_value, .FunctionArgument);
6324 try writer.print(", {d});\n", .{len});6384 try writer.print(", {d});\n", .{len});
6325 },6385 },
6326 .Many, .C => unreachable,6386 .Many, .C => unreachable,
6327 }6387 }
6388 try bitcasted.free(f);
6328 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });6389 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
6329 return .none;6390 return .none;
6330}6391}