authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2022-12-11 23:31:41-05:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-01-01 16:44:28-05:00
log00b54a5fe565f404e0d7d8cdbc05a465d573fc32
tree859c0bb8c0742622f83aa087ab891d7a178c23ac
parent36212e9d178c32facd0d9d0c1069327758efb943

cbe: more msvc fixes

- Add Function.renderIntcast to handle common casting cases - Fixup casting inside aggregate initialization - Remove redundant cast in aggregate initialization - Fix renderValue .Packed branch for > 64 bit types

1 files changed, 199 insertions(+), 66 deletions(-)

src/codegen/c.zig+199-66
......@@ -431,6 +431,10 @@ pub const Function = struct {
431431 return f.object.dg.renderTypecast(w, t);
432432 }
433433
434 fn renderIntCast(f: *Function, w: anytype, dest_ty: Type, src: CValue, src_ty: Type, location: ValueRenderLocation) !void {
435 return f.object.dg.renderIntCast(w, dest_ty, .{ .c_value = .{ .f = f, .value = src } }, src_ty, location);
436 }
437
434438 fn fmtIntLiteral(f: *Function, ty: Type, val: Value) !std.fmt.Formatter(formatIntLiteral) {
435439 return f.object.dg.fmtIntLiteral(ty, val);
436440 }
......@@ -1263,25 +1267,85 @@ pub const DeclGen = struct {
12631267 var bit_offset_val_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = 0 };
12641268 const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base);
12651269
1266 try writer.writeByte('(');
1267 var empty = true;
1268 for (field_vals) |field_val, index| {
1270 var eff_num_fields: usize = 0;
1271 for (field_vals) |_, index| {
12691272 const field_ty = ty.structFieldType(index);
12701273 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
12711274
1272 if (!empty) try writer.writeAll(" | ");
1275 eff_num_fields += 1;
1276 }
1277
1278 if (eff_num_fields == 0) {
12731279 try writer.writeByte('(');
1274 try dg.renderTypecast(writer, ty);
1280 try dg.renderValue(writer, ty, Value.undef, .Initializer);
12751281 try writer.writeByte(')');
1276 try dg.renderValue(writer, field_ty, field_val, .Other);
1277 try writer.writeAll(" << ");
1278 try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
1282 } else if (ty.bitSize(target) > 64) {
1283 // zig_or_u128(zig_or_u128(zig_shl_u128(a, a_off), zig_shl_u128(b, b_off)), zig_shl_u128(c, c_off))
1284 var num_or = eff_num_fields - 1;
1285 while (num_or > 0) : (num_or -= 1) {
1286 try writer.writeAll("zig_or_");
1287 try dg.renderTypeForBuiltinFnName(writer, ty);
1288 try writer.writeByte('(');
1289 }
12791290
1280 bit_offset_val_pl.data += field_ty.bitSize(target);
1281 empty = false;
1291 var eff_index: usize = 0;
1292 var needs_closing_paren = false;
1293 for (field_vals) |field_val, index| {
1294 const field_ty = ty.structFieldType(index);
1295 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
1296
1297 //const cast_context = IntCastContext{ .value = .{ .value = field_val } };
1298 if (bit_offset_val_pl.data != 0) {
1299 try writer.writeAll("zig_shl_");
1300 try dg.renderTypeForBuiltinFnName(writer, ty);
1301 try writer.writeByte('(');
1302
1303 //try dg.renderIntCast(writer, ty,_context, field_ty, .FunctionArgument);
1304 try dg.renderValue(writer, field_ty, field_val, .FunctionArgument);
1305
1306 try writer.writeAll(", ");
1307 try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
1308 try writer.writeByte(')');
1309 } else {
1310
1311 try dg.renderValue(writer, field_ty, field_val, .FunctionArgument);
1312 //try dg.renderIntCast(writer, ty, cast_context, field_ty, .FunctionArgument);
1313
1314 }
1315
1316 if (needs_closing_paren) try writer.writeByte(')');
1317 if (eff_index != eff_num_fields - 1) try writer.writeAll(", ");
1318
1319 bit_offset_val_pl.data += field_ty.bitSize(target);
1320 needs_closing_paren = true;
1321 eff_index += 1;
1322 }
1323 } else {
1324 try writer.writeByte('(');
1325 // a << a_off | b << b_off | c << c_off
1326 var empty = true;
1327 for (field_vals) |field_val, index| {
1328 const field_ty = ty.structFieldType(index);
1329 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
1330
1331 if (!empty) try writer.writeAll(" | ");
1332 try writer.writeByte('(');
1333 try dg.renderTypecast(writer, ty);
1334 try writer.writeByte(')');
1335
1336 if (bit_offset_val_pl.data != 0) {
1337 try dg.renderValue(writer, field_ty, field_val, .Other);
1338 try writer.writeAll(" << ");
1339 try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
1340 } else {
1341 try dg.renderValue(writer, field_ty, field_val, .Other);
1342 }
1343
1344 bit_offset_val_pl.data += field_ty.bitSize(target);
1345 empty = false;
1346 }
1347 try writer.writeByte(')');
12821348 }
1283 if (empty) try dg.renderValue(writer, ty, Value.undef, .Initializer);
1284 try writer.writeByte(')');
12851349 },
12861350 },
12871351 .Union => {
......@@ -2103,6 +2167,101 @@ pub const DeclGen = struct {
21032167 });
21042168 }
21052169
2170 const IntCastContext = union(enum) {
2171 c_value: struct {
2172 f: *Function,
2173 value: CValue,
2174 },
2175 value: struct {
2176 value: Value,
2177 },
2178
2179 pub fn writeValue(self: *const IntCastContext, dg: *DeclGen, w: anytype, value_ty: Type, location: ValueRenderLocation) !void {
2180 switch (self.*) {
2181 .c_value => |v| {
2182 try v.f.writeCValue(w, v.value, location);
2183 },
2184 .value => |v| {
2185 try dg.renderValue(w, value_ty, v.value, location);
2186 },
2187 }
2188 }
2189 };
2190
2191 /// Renders a cast to an int type, from either an int or a pointer.
2192 ///
2193 /// Some platforms don't have 128 bit integers, so we need to use
2194 /// the zig_as_ and zig_lo_ macros in those cases.
2195 ///
2196 /// | Dest type bits | Src type | Result
2197 /// |------------------|------------------|---------------------------|
2198 /// | < 64 bit integer | pointer | (zig_<dest_ty>)(zig_<u|i>size)src
2199 /// | < 64 bit integer | < 64 bit integer | (zig_<dest_ty>)src
2200 /// | < 64 bit integer | > 64 bit integer | zig_lo(src)
2201 /// | > 64 bit integer | pointer | zig_as_<dest_ty>(0, (zig_<u|i>size)src)
2202 /// | > 64 bit integer | < 64 bit integer | zig_as_<dest_ty>(0, src)
2203 /// | > 64 bit integer | > 64 bit integer | zig_as_<dest_ty>(zig_hi_<src_ty>(src), zig_lo_<src_ty>(src))
2204 fn renderIntCast(dg: *DeclGen, w: anytype, dest_ty: Type, context: IntCastContext, src_ty: Type, location: ValueRenderLocation) !void {
2205 const target = dg.module.getTarget();
2206 const dest_bits = dest_ty.bitSize(target);
2207 const dest_int_info = dest_ty.intInfo(target);
2208
2209 const src_is_ptr = src_ty.isPtrAtRuntime();
2210 const src_eff_ty: Type = if (src_is_ptr) switch (dest_int_info.signedness) {
2211 .unsigned => Type.usize,
2212 .signed => Type.isize,
2213 } else src_ty;
2214
2215 const src_bits = src_eff_ty.bitSize(target);
2216 const src_int_info = src_eff_ty.intInfo(target);
2217 if (dest_bits <= 64 and src_bits <= 64) {
2218 const needs_cast = toCIntBits(dest_int_info.bits) != toCIntBits(src_int_info.bits) or
2219 dest_int_info.signedness != src_int_info.signedness;
2220 if (needs_cast) {
2221 try w.writeByte('(');
2222 try dg.renderTypecast(w, dest_ty);
2223 try w.writeByte(')');
2224 }
2225 if (src_is_ptr) {
2226 try w.writeByte('(');
2227 try dg.renderTypecast(w, src_eff_ty);
2228 try w.writeByte(')');
2229 }
2230 try context.writeValue(dg, w, src_ty, location);
2231 } else if (dest_bits <= 64 and src_bits > 64) {
2232 assert(!src_is_ptr);
2233 try w.writeAll("zig_lo_");
2234 try dg.renderTypeForBuiltinFnName(w, src_eff_ty);
2235 try w.writeByte('(');
2236 try context.writeValue(dg, w, src_ty, .FunctionArgument);
2237 try w.writeByte(')');
2238 } else if (dest_bits > 64 and src_bits <= 64) {
2239 try w.writeAll("zig_as_");
2240 try dg.renderTypeForBuiltinFnName(w, dest_ty);
2241 try w.writeAll("(0, "); // TODO: Should the 0 go through fmtIntLiteral?
2242 if (src_is_ptr) {
2243 try w.writeByte('(');
2244 try dg.renderTypecast(w, src_eff_ty);
2245 try w.writeByte(')');
2246 }
2247 try context.writeValue(dg, w, src_ty, .FunctionArgument);
2248 try w.writeByte(')');
2249 } else {
2250 assert(!src_is_ptr);
2251 try w.writeAll("zig_as_");
2252 try dg.renderTypeForBuiltinFnName(w, dest_ty);
2253 try w.writeAll("(zig_hi_");
2254 try dg.renderTypeForBuiltinFnName(w, src_eff_ty);
2255 try w.writeByte('(');
2256 try context.writeValue(dg, w, src_ty, .FunctionArgument);
2257 try w.writeAll("), zig_lo_");
2258 try dg.renderTypeForBuiltinFnName(w, src_eff_ty);
2259 try w.writeByte('(');
2260 try context.writeValue(dg, w, src_ty, .FunctionArgument);
2261 try w.writeAll("))");
2262 }
2263 }
2264
21062265 /// Renders a type in C typecast format.
21072266 ///
21082267 /// This is guaranteed to be valid in a typecast expression, but not
......@@ -3344,55 +3503,16 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {
33443503 return CValue.none;
33453504 }
33463505
3347 const target = f.object.dg.module.getTarget();
33483506 const operand = try f.resolveInst(ty_op.operand);
33493507 try reap(f, inst, &.{ty_op.operand});
33503508 const writer = f.object.writer();
33513509 const inst_ty = f.air.typeOfIndex(inst);
33523510 const local = try f.allocLocal(inst, inst_ty);
3353 const inst_bits = inst_ty.bitSize(target);
3354 const inst_int_info = inst_ty.intInfo(target);
33553511 const operand_ty = f.air.typeOf(ty_op.operand);
3356 const operand_bits = operand_ty.bitSize(target);
3357 const operand_int_info = operand_ty.intInfo(target);
33583512
33593513 try f.writeCValue(writer, local, .Other);
33603514 try writer.writeAll(" = ");
3361
3362 if (inst_bits <= 64 and operand_bits <= 64) {
3363 if (toCIntBits(inst_int_info.bits) != toCIntBits(operand_int_info.bits) or inst_int_info.signedness != operand_int_info.signedness) {
3364 try writer.writeByte('(');
3365 try f.renderTypecast(writer, inst_ty);
3366 try writer.writeByte(')');
3367 }
3368
3369 try f.writeCValue(writer, operand, .Other);
3370 } else if (inst_bits > 64 and operand_bits <= 64) {
3371 try writer.writeAll("zig_as_");
3372 try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
3373 try writer.writeAll("(0, "); // TODO: Should the 0 go through fmtIntLiteral?
3374 try f.writeCValue(writer, operand, .FunctionArgument);
3375 try writer.writeByte(')');
3376 } else if (inst_bits <= 64 and operand_bits > 64) {
3377 try writer.writeAll("zig_lo_");
3378 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
3379 try writer.writeByte('(');
3380 try f.writeCValue(writer, operand, .FunctionArgument);
3381 try writer.writeByte(')');
3382 } else {
3383 try writer.writeAll("zig_as_");
3384 try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
3385 try writer.writeAll("(zig_hi_");
3386 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
3387 try writer.writeByte('(');
3388 try f.writeCValue(writer, operand, .FunctionArgument);
3389 try writer.writeAll("), zig_lo_");
3390 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
3391 try writer.writeByte('(');
3392 try f.writeCValue(writer, operand, .FunctionArgument);
3393 try writer.writeAll("))");
3394 }
3395
3515 try f.renderIntCast(writer, inst_ty, operand, operand_ty, .Other);
33963516 try writer.writeAll(";\n");
33973517 return local;
33983518}
......@@ -6509,9 +6629,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
65096629 },
65106630 .Packed => {
65116631 try f.writeCValue(writer, local, .Other);
6512 try writer.writeAll(" = (");
6513 try f.renderTypecast(writer, inst_ty);
6514 try writer.writeAll(")");
6632 try writer.writeAll(" = ");
65156633 const int_info = inst_ty.intInfo(target);
65166634
65176635 var bit_offset_ty_pl = Type.Payload.Bits{
......@@ -6541,20 +6659,28 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
65416659 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
65426660
65436661 if (!empty) try writer.writeAll(", ");
6662 // TODO: Skip this entire shift if val is 0?
65446663 try writer.writeAll("zig_shlw_");
65456664 try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
6546 try writer.writeAll("((");
6547 try f.renderTypecast(writer, inst_ty);
6548 try writer.writeByte(')');
6549 if (field_ty.isPtrAtRuntime()) {
6665 try writer.writeByte('(');
6666
6667 if (inst_ty.isAbiInt() and (field_ty.isAbiInt() or field_ty.isPtrAtRuntime())) {
6668 try f.renderIntCast(writer, inst_ty, element, field_ty, .FunctionArgument);
6669 } else {
65506670 try writer.writeByte('(');
6551 try f.renderTypecast(writer, switch (int_info.signedness) {
6552 .unsigned => Type.usize,
6553 .signed => Type.isize,
6554 });
6671 try f.renderTypecast(writer, inst_ty);
65556672 try writer.writeByte(')');
6673 if (field_ty.isPtrAtRuntime()) {
6674 try writer.writeByte('(');
6675 try f.renderTypecast(writer, switch (int_info.signedness) {
6676 .unsigned => Type.usize,
6677 .signed => Type.isize,
6678 });
6679 try writer.writeByte(')');
6680 }
6681 try f.writeCValue(writer, element, .Other);
65566682 }
6557 try f.writeCValue(writer, element, .Other);
6683
65586684 try writer.writeAll(", ");
65596685 try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
65606686 try f.object.dg.renderBuiltinInfo(writer, inst_ty, .Bits);
......@@ -6564,7 +6690,14 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
65646690 bit_offset_val_pl.data += field_ty.bitSize(target);
65656691 empty = false;
65666692 }
6567 if (empty) try f.writeCValue(writer, .{ .undef = inst_ty }, .Initializer);
6693
6694 if (empty) {
6695 try writer.writeByte('(');
6696 try f.renderTypecast(writer, inst_ty);
6697 try writer.writeByte(')');
6698 try f.writeCValue(writer, .{ .undef = inst_ty }, .Initializer);
6699 }
6700
65686701 try writer.writeAll(";\n");
65696702 },
65706703 },
......@@ -6937,7 +7070,7 @@ fn StringLiteral(comptime WriterType: type) type {
69377070 }
69387071 }
69397072
6940 pub fn writeChar(self: *Self, c: u8) Error!void {
7073 pub fn writeChar(self: *Self, c: u8) Error!void {
69417074 const writer = self.counting_writer.writer();
69427075
69437076 if (self.cur_len == 0 and self.counting_writer.bytes_written > 1)