| ... | ... | @@ -431,6 +431,10 @@ pub const Function = struct { |
| 431 | 431 | return f.object.dg.renderTypecast(w, t); |
| 432 | 432 | } |
| 433 | 433 | |
| 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 | |
| 434 | 438 | fn fmtIntLiteral(f: *Function, ty: Type, val: Value) !std.fmt.Formatter(formatIntLiteral) { |
| 435 | 439 | return f.object.dg.fmtIntLiteral(ty, val); |
| 436 | 440 | } |
| ... | ... | @@ -1263,25 +1267,85 @@ pub const DeclGen = struct { |
| 1263 | 1267 | var bit_offset_val_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = 0 }; |
| 1264 | 1268 | const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base); |
| 1265 | 1269 | |
| 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| { |
| 1269 | 1272 | const field_ty = ty.structFieldType(index); |
| 1270 | 1273 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; |
| 1271 | 1274 | |
| 1272 | | if (!empty) try writer.writeAll(" | "); |
| 1275 | eff_num_fields += 1; |
| 1276 | } |
| 1277 | |
| 1278 | if (eff_num_fields == 0) { |
| 1273 | 1279 | try writer.writeByte('('); |
| 1274 | | try dg.renderTypecast(writer, ty); |
| 1280 | try dg.renderValue(writer, ty, Value.undef, .Initializer); |
| 1275 | 1281 | 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 | } |
| 1279 | 1290 | |
| 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(')'); |
| 1282 | 1348 | } |
| 1283 | | if (empty) try dg.renderValue(writer, ty, Value.undef, .Initializer); |
| 1284 | | try writer.writeByte(')'); |
| 1285 | 1349 | }, |
| 1286 | 1350 | }, |
| 1287 | 1351 | .Union => { |
| ... | ... | @@ -2103,6 +2167,101 @@ pub const DeclGen = struct { |
| 2103 | 2167 | }); |
| 2104 | 2168 | } |
| 2105 | 2169 | |
| 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 | |
| 2106 | 2265 | /// Renders a type in C typecast format. |
| 2107 | 2266 | /// |
| 2108 | 2267 | /// 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 { |
| 3344 | 3503 | return CValue.none; |
| 3345 | 3504 | } |
| 3346 | 3505 | |
| 3347 | | const target = f.object.dg.module.getTarget(); |
| 3348 | 3506 | const operand = try f.resolveInst(ty_op.operand); |
| 3349 | 3507 | try reap(f, inst, &.{ty_op.operand}); |
| 3350 | 3508 | const writer = f.object.writer(); |
| 3351 | 3509 | const inst_ty = f.air.typeOfIndex(inst); |
| 3352 | 3510 | 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); |
| 3355 | 3511 | 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); |
| 3358 | 3512 | |
| 3359 | 3513 | try f.writeCValue(writer, local, .Other); |
| 3360 | 3514 | 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); |
| 3396 | 3516 | try writer.writeAll(";\n"); |
| 3397 | 3517 | return local; |
| 3398 | 3518 | } |
| ... | ... | @@ -6509,9 +6629,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6509 | 6629 | }, |
| 6510 | 6630 | .Packed => { |
| 6511 | 6631 | 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(" = "); |
| 6515 | 6633 | const int_info = inst_ty.intInfo(target); |
| 6516 | 6634 | |
| 6517 | 6635 | var bit_offset_ty_pl = Type.Payload.Bits{ |
| ... | ... | @@ -6541,20 +6659,28 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6541 | 6659 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; |
| 6542 | 6660 | |
| 6543 | 6661 | if (!empty) try writer.writeAll(", "); |
| 6662 | // TODO: Skip this entire shift if val is 0? |
| 6544 | 6663 | try writer.writeAll("zig_shlw_"); |
| 6545 | 6664 | 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 { |
| 6550 | 6670 | 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); |
| 6555 | 6672 | 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); |
| 6556 | 6682 | } |
| 6557 | | try f.writeCValue(writer, element, .Other); |
| 6683 | |
| 6558 | 6684 | try writer.writeAll(", "); |
| 6559 | 6685 | try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); |
| 6560 | 6686 | try f.object.dg.renderBuiltinInfo(writer, inst_ty, .Bits); |
| ... | ... | @@ -6564,7 +6690,14 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6564 | 6690 | bit_offset_val_pl.data += field_ty.bitSize(target); |
| 6565 | 6691 | empty = false; |
| 6566 | 6692 | } |
| 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 | |
| 6568 | 6701 | try writer.writeAll(";\n"); |
| 6569 | 6702 | }, |
| 6570 | 6703 | }, |
| ... | ... | @@ -6937,7 +7070,7 @@ fn StringLiteral(comptime WriterType: type) type { |
| 6937 | 7070 | } |
| 6938 | 7071 | } |
| 6939 | 7072 | |
| 6940 | | pub fn writeChar(self: *Self, c: u8) Error!void { |
| 7073 | pub fn writeChar(self: *Self, c: u8) Error!void { |
| 6941 | 7074 | const writer = self.counting_writer.writer(); |
| 6942 | 7075 | |
| 6943 | 7076 | if (self.cur_len == 0 and self.counting_writer.bytes_written > 1) |