From 09763435a85a6108cc4624b51ac1b016746078b6 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Tue, 1 Nov 2022 04:47:09 -0400 Subject: [PATCH] cbe: support arrays in more places --- src/codegen/c.zig | 183 +++++++++++++++++++++++++---------- test/behavior/bugs/11139.zig | 1 - test/behavior/fn.zig | 1 - 3 files changed, 130 insertions(+), 55 deletions(-) diff --git a/src/codegen/c.zig b/src/codegen/c.zig index d54ef6b660..645d2b996c 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -2597,19 +2597,36 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: [ } fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue { + const inst_ty = f.air.typeOfIndex(inst); const bin_op = f.air.instructions.items(.data)[inst].bin_op; const ptr_ty = f.air.typeOf(bin_op.lhs); - if (!ptr_ty.isVolatilePtr() and f.liveness.isUnused(inst)) return CValue.none; + if ((!ptr_ty.isVolatilePtr() and f.liveness.isUnused(inst)) or + !inst_ty.hasRuntimeBitsIgnoreComptime()) return CValue.none; const ptr = try f.resolveInst(bin_op.lhs); const index = try f.resolveInst(bin_op.rhs); + + const target = f.object.dg.module.getTarget(); + const is_array = lowersToArray(inst_ty, target); + + const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); const writer = f.object.writer(); - const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const); - try writer.writeAll(" = "); + if (is_array) { + try writer.writeAll(";\n"); + try writer.writeAll("memcpy("); + try f.writeCValue(writer, local, .FunctionArgument); + try writer.writeAll(", "); + } else try writer.writeAll(" = "); try f.writeCValue(writer, ptr, .Other); try writer.writeByte('['); try f.writeCValue(writer, index, .Other); - try writer.writeAll("];\n"); + try writer.writeByte(']'); + if (is_array) { + try writer.writeAll(", sizeof("); + try f.renderTypecast(writer, inst_ty); + try writer.writeAll("))"); + } + try writer.writeAll(";\n"); return local; } @@ -2639,19 +2656,36 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { } fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue { + const inst_ty = f.air.typeOfIndex(inst); const bin_op = f.air.instructions.items(.data)[inst].bin_op; const slice_ty = f.air.typeOf(bin_op.lhs); - if (!slice_ty.isVolatilePtr() and f.liveness.isUnused(inst)) return CValue.none; + if ((!slice_ty.isVolatilePtr() and f.liveness.isUnused(inst)) or + !inst_ty.hasRuntimeBitsIgnoreComptime()) return CValue.none; const slice = try f.resolveInst(bin_op.lhs); const index = try f.resolveInst(bin_op.rhs); + + const target = f.object.dg.module.getTarget(); + const is_array = lowersToArray(inst_ty, target); + + const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); const writer = f.object.writer(); - const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const); - try writer.writeAll(" = "); + if (is_array) { + try writer.writeAll(";\n"); + try writer.writeAll("memcpy("); + try f.writeCValue(writer, local, .FunctionArgument); + try writer.writeAll(", "); + } else try writer.writeAll(" = "); try f.writeCValue(writer, slice, .Other); try writer.writeAll(".ptr["); try f.writeCValue(writer, index, .Other); - try writer.writeAll("];\n"); + try writer.writeByte(']'); + if (is_array) { + try writer.writeAll(", sizeof("); + try f.renderTypecast(writer, inst_ty); + try writer.writeAll("))"); + } + try writer.writeAll(";\n"); return local; } @@ -2674,18 +2708,34 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { } fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue { - if (f.liveness.isUnused(inst)) return CValue.none; + const inst_ty = f.air.typeOfIndex(inst); + if (f.liveness.isUnused(inst) or !inst_ty.hasRuntimeBitsIgnoreComptime()) return CValue.none; const bin_op = f.air.instructions.items(.data)[inst].bin_op; const array = try f.resolveInst(bin_op.lhs); const index = try f.resolveInst(bin_op.rhs); + + const target = f.object.dg.module.getTarget(); + const is_array = lowersToArray(inst_ty, target); + + const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); const writer = f.object.writer(); - const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const); - try writer.writeAll(" = "); + if (is_array) { + try writer.writeAll(";\n"); + try writer.writeAll("memcpy("); + try f.writeCValue(writer, local, .FunctionArgument); + try writer.writeAll(", "); + } else try writer.writeAll(" = "); try f.writeCValue(writer, array, .Other); try writer.writeByte('['); try f.writeCValue(writer, index, .Other); - try writer.writeAll("];\n"); + try writer.writeByte(']'); + if (is_array) { + try writer.writeAll(", sizeof("); + try f.renderTypecast(writer, inst_ty); + try writer.writeAll("))"); + } + try writer.writeAll(";\n"); return local; } @@ -3592,13 +3642,26 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue { // If result is .none then the value of the block is unused. if (result != .none) { const operand = try f.resolveInst(branch.operand); - try f.writeCValue(writer, result, .Other); - try writer.writeAll(" = "); - try f.writeCValue(writer, operand, .Other); + + const operand_ty = f.air.typeOf(branch.operand); + const target = f.object.dg.module.getTarget(); + if (lowersToArray(operand_ty, target)) { + try writer.writeAll("memcpy("); + try f.writeCValue(writer, result, .FunctionArgument); + try writer.writeAll(", "); + try f.writeCValue(writer, operand, .FunctionArgument); + try writer.writeAll(", sizeof("); + try f.renderTypecast(writer, operand_ty); + try writer.writeAll("))"); + } else { + try f.writeCValue(writer, result, .Other); + try writer.writeAll(" = "); + try f.writeCValue(writer, operand, .Other); + } try writer.writeAll(";\n"); } - try f.object.writer().print("goto zig_block_{d};\n", .{block.block_id}); + try writer.print("goto zig_block_{d};\n", .{block.block_id}); return CValue.none; } @@ -4009,26 +4072,34 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue { if (f.liveness.isUnused(inst)) return CValue.none; const ty_op = f.air.instructions.items(.data)[inst].ty_op; - const writer = f.object.writer(); const operand = try f.resolveInst(ty_op.operand); const opt_ty = f.air.typeOf(ty_op.operand); var buf: Type.Payload.ElemType = undefined; const payload_ty = opt_ty.optionalChild(&buf); - if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { - return CValue.none; - } - - if (opt_ty.optionalReprIsPayload()) { - return operand; - } + if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return CValue.none; + if (opt_ty.optionalReprIsPayload()) return operand; const inst_ty = f.air.typeOfIndex(inst); - const local = try f.allocLocal(inst_ty, .Const); - try writer.writeAll(" = ("); - try f.writeCValue(writer, operand, .Other); - try writer.writeAll(").payload;\n"); + const target = f.object.dg.module.getTarget(); + const is_array = lowersToArray(inst_ty, target); + + const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); + const writer = f.object.writer(); + if (is_array) { + try writer.writeAll(";\n"); + try writer.writeAll("memcpy("); + try f.writeCValue(writer, local, .FunctionArgument); + try writer.writeAll(", "); + } else try writer.writeAll(" = "); + try f.writeCValueMember(writer, operand, .{ .identifier = "payload" }); + if (is_array) { + try writer.writeAll(", sizeof("); + try f.renderTypecast(writer, inst_ty); + try writer.writeAll("))"); + } + try writer.writeAll(";\n"); return local; } @@ -4387,25 +4458,33 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu } fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue { - if (f.liveness.isUnused(inst)) - return CValue.none; - - const ty_op = f.air.instructions.items(.data)[inst].ty_op; - const writer = f.object.writer(); - const operand = try f.resolveInst(ty_op.operand); + if (f.liveness.isUnused(inst)) return CValue.none; const inst_ty = f.air.typeOfIndex(inst); - if (inst_ty.optionalReprIsPayload()) { - return operand; - } + const ty_op = f.air.instructions.items(.data)[inst].ty_op; + const payload = try f.resolveInst(ty_op.operand); + if (inst_ty.optionalReprIsPayload()) return payload; - // .wrap_optional is used to convert non-optionals into optionals so it can never be null. - const local = try f.allocLocal(inst_ty, .Const); + const payload_ty = f.air.typeOf(ty_op.operand); + const target = f.object.dg.module.getTarget(); + const is_array = lowersToArray(payload_ty, target); + + const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); + const writer = f.object.writer(); try writer.writeAll(" = { .payload = "); - try f.writeCValue(writer, operand, .Initializer); + try f.writeCValue(writer, if (is_array) CValue{ .undef = payload_ty } else payload, .Initializer); try writer.writeAll(", .is_null = "); try f.object.dg.renderValue(writer, Type.bool, Value.@"false", .Initializer); try writer.writeAll(" };\n"); + if (is_array) { + try writer.writeAll("memcpy("); + try f.writeCValueMember(writer, local, .{ .identifier = "payload" }); + try writer.writeAll(", "); + try f.writeCValue(writer, payload, .FunctionArgument); + try writer.writeAll(", sizeof("); + try f.renderTypecast(writer, payload_ty); + try writer.writeAll("));\n"); + } return local; } @@ -4477,35 +4556,33 @@ fn airSaveErrReturnTraceIndex(f: *Function, inst: Air.Inst.Index) !CValue { } fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { - if (f.liveness.isUnused(inst)) - return CValue.none; - - const ty_op = f.air.instructions.items(.data)[inst].ty_op; - const writer = f.object.writer(); - const operand = try f.resolveInst(ty_op.operand); + if (f.liveness.isUnused(inst)) return CValue.none; const inst_ty = f.air.typeOfIndex(inst); - const payload_ty = inst_ty.errorUnionPayload(); const error_ty = inst_ty.errorUnionSet(); + const ty_op = f.air.instructions.items(.data)[inst].ty_op; + const payload_ty = inst_ty.errorUnionPayload(); + const payload = try f.resolveInst(ty_op.operand); + const target = f.object.dg.module.getTarget(); const is_array = lowersToArray(payload_ty, target); + const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); + const writer = f.object.writer(); try writer.writeAll(" = { .payload = "); - try f.writeCValue(writer, if (is_array) CValue{ .undef = payload_ty } else operand, .Initializer); + try f.writeCValue(writer, if (is_array) CValue{ .undef = payload_ty } else payload, .Initializer); try writer.writeAll(", .error = "); try f.object.dg.renderValue(writer, error_ty, Value.zero, .Initializer); try writer.writeAll(" };\n"); - if (is_array) { try writer.writeAll("memcpy("); - try f.writeCValue(writer, local, .Other); - try writer.writeAll(".payload, "); - try f.writeCValue(writer, operand, .FunctionArgument); + try f.writeCValueMember(writer, local, .{ .identifier = "payload" }); + try writer.writeAll(", "); + try f.writeCValue(writer, payload, .FunctionArgument); try writer.writeAll(", sizeof("); try f.renderTypecast(writer, payload_ty); try writer.writeAll("));\n"); } - return local; } diff --git a/test/behavior/bugs/11139.zig b/test/behavior/bugs/11139.zig index 9ceaaeb0e4..615fd37689 100644 --- a/test/behavior/bugs/11139.zig +++ b/test/behavior/bugs/11139.zig @@ -3,7 +3,6 @@ const builtin = @import("builtin"); const expect = std.testing.expect; test "store array of array of structs at comptime" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO diff --git a/test/behavior/fn.zig b/test/behavior/fn.zig index ad92cb8962..06127aa855 100644 --- a/test/behavior/fn.zig +++ b/test/behavior/fn.zig @@ -355,7 +355,6 @@ test "function call with anon list literal" { } test "function call with anon list literal - 2D" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO