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
This commit is contained in:
kcbanner 2022-12-11 23:31:41 -05:00
parent 36212e9d17
commit 00b54a5fe5

View File

@ -431,6 +431,10 @@ pub const Function = struct {
return f.object.dg.renderTypecast(w, t);
}
fn renderIntCast(f: *Function, w: anytype, dest_ty: Type, src: CValue, src_ty: Type, location: ValueRenderLocation) !void {
return f.object.dg.renderIntCast(w, dest_ty, .{ .c_value = .{ .f = f, .value = src } }, src_ty, location);
}
fn fmtIntLiteral(f: *Function, ty: Type, val: Value) !std.fmt.Formatter(formatIntLiteral) {
return f.object.dg.fmtIntLiteral(ty, val);
}
@ -1263,25 +1267,85 @@ pub const DeclGen = struct {
var bit_offset_val_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = 0 };
const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base);
try writer.writeByte('(');
var empty = true;
for (field_vals) |field_val, index| {
var eff_num_fields: usize = 0;
for (field_vals) |_, index| {
const field_ty = ty.structFieldType(index);
if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
if (!empty) try writer.writeAll(" | ");
try writer.writeByte('(');
try dg.renderTypecast(writer, ty);
try writer.writeByte(')');
try dg.renderValue(writer, field_ty, field_val, .Other);
try writer.writeAll(" << ");
try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
bit_offset_val_pl.data += field_ty.bitSize(target);
empty = false;
eff_num_fields += 1;
}
if (eff_num_fields == 0) {
try writer.writeByte('(');
try dg.renderValue(writer, ty, Value.undef, .Initializer);
try writer.writeByte(')');
} else if (ty.bitSize(target) > 64) {
// zig_or_u128(zig_or_u128(zig_shl_u128(a, a_off), zig_shl_u128(b, b_off)), zig_shl_u128(c, c_off))
var num_or = eff_num_fields - 1;
while (num_or > 0) : (num_or -= 1) {
try writer.writeAll("zig_or_");
try dg.renderTypeForBuiltinFnName(writer, ty);
try writer.writeByte('(');
}
var eff_index: usize = 0;
var needs_closing_paren = false;
for (field_vals) |field_val, index| {
const field_ty = ty.structFieldType(index);
if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
//const cast_context = IntCastContext{ .value = .{ .value = field_val } };
if (bit_offset_val_pl.data != 0) {
try writer.writeAll("zig_shl_");
try dg.renderTypeForBuiltinFnName(writer, ty);
try writer.writeByte('(');
//try dg.renderIntCast(writer, ty,_context, field_ty, .FunctionArgument);
try dg.renderValue(writer, field_ty, field_val, .FunctionArgument);
try writer.writeAll(", ");
try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
try writer.writeByte(')');
} else {
try dg.renderValue(writer, field_ty, field_val, .FunctionArgument);
//try dg.renderIntCast(writer, ty, cast_context, field_ty, .FunctionArgument);
}
if (needs_closing_paren) try writer.writeByte(')');
if (eff_index != eff_num_fields - 1) try writer.writeAll(", ");
bit_offset_val_pl.data += field_ty.bitSize(target);
needs_closing_paren = true;
eff_index += 1;
}
} else {
try writer.writeByte('(');
// a << a_off | b << b_off | c << c_off
var empty = true;
for (field_vals) |field_val, index| {
const field_ty = ty.structFieldType(index);
if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
if (!empty) try writer.writeAll(" | ");
try writer.writeByte('(');
try dg.renderTypecast(writer, ty);
try writer.writeByte(')');
if (bit_offset_val_pl.data != 0) {
try dg.renderValue(writer, field_ty, field_val, .Other);
try writer.writeAll(" << ");
try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
} else {
try dg.renderValue(writer, field_ty, field_val, .Other);
}
bit_offset_val_pl.data += field_ty.bitSize(target);
empty = false;
}
try writer.writeByte(')');
}
if (empty) try dg.renderValue(writer, ty, Value.undef, .Initializer);
try writer.writeByte(')');
},
},
.Union => {
@ -2103,6 +2167,101 @@ pub const DeclGen = struct {
});
}
const IntCastContext = union(enum) {
c_value: struct {
f: *Function,
value: CValue,
},
value: struct {
value: Value,
},
pub fn writeValue(self: *const IntCastContext, dg: *DeclGen, w: anytype, value_ty: Type, location: ValueRenderLocation) !void {
switch (self.*) {
.c_value => |v| {
try v.f.writeCValue(w, v.value, location);
},
.value => |v| {
try dg.renderValue(w, value_ty, v.value, location);
},
}
}
};
/// Renders a cast to an int type, from either an int or a pointer.
///
/// Some platforms don't have 128 bit integers, so we need to use
/// the zig_as_ and zig_lo_ macros in those cases.
///
/// | Dest type bits | Src type | Result
/// |------------------|------------------|---------------------------|
/// | < 64 bit integer | pointer | (zig_<dest_ty>)(zig_<u|i>size)src
/// | < 64 bit integer | < 64 bit integer | (zig_<dest_ty>)src
/// | < 64 bit integer | > 64 bit integer | zig_lo(src)
/// | > 64 bit integer | pointer | zig_as_<dest_ty>(0, (zig_<u|i>size)src)
/// | > 64 bit integer | < 64 bit integer | zig_as_<dest_ty>(0, src)
/// | > 64 bit integer | > 64 bit integer | zig_as_<dest_ty>(zig_hi_<src_ty>(src), zig_lo_<src_ty>(src))
fn renderIntCast(dg: *DeclGen, w: anytype, dest_ty: Type, context: IntCastContext, src_ty: Type, location: ValueRenderLocation) !void {
const target = dg.module.getTarget();
const dest_bits = dest_ty.bitSize(target);
const dest_int_info = dest_ty.intInfo(target);
const src_is_ptr = src_ty.isPtrAtRuntime();
const src_eff_ty: Type = if (src_is_ptr) switch (dest_int_info.signedness) {
.unsigned => Type.usize,
.signed => Type.isize,
} else src_ty;
const src_bits = src_eff_ty.bitSize(target);
const src_int_info = src_eff_ty.intInfo(target);
if (dest_bits <= 64 and src_bits <= 64) {
const needs_cast = toCIntBits(dest_int_info.bits) != toCIntBits(src_int_info.bits) or
dest_int_info.signedness != src_int_info.signedness;
if (needs_cast) {
try w.writeByte('(');
try dg.renderTypecast(w, dest_ty);
try w.writeByte(')');
}
if (src_is_ptr) {
try w.writeByte('(');
try dg.renderTypecast(w, src_eff_ty);
try w.writeByte(')');
}
try context.writeValue(dg, w, src_ty, location);
} else if (dest_bits <= 64 and src_bits > 64) {
assert(!src_is_ptr);
try w.writeAll("zig_lo_");
try dg.renderTypeForBuiltinFnName(w, src_eff_ty);
try w.writeByte('(');
try context.writeValue(dg, w, src_ty, .FunctionArgument);
try w.writeByte(')');
} else if (dest_bits > 64 and src_bits <= 64) {
try w.writeAll("zig_as_");
try dg.renderTypeForBuiltinFnName(w, dest_ty);
try w.writeAll("(0, "); // TODO: Should the 0 go through fmtIntLiteral?
if (src_is_ptr) {
try w.writeByte('(');
try dg.renderTypecast(w, src_eff_ty);
try w.writeByte(')');
}
try context.writeValue(dg, w, src_ty, .FunctionArgument);
try w.writeByte(')');
} else {
assert(!src_is_ptr);
try w.writeAll("zig_as_");
try dg.renderTypeForBuiltinFnName(w, dest_ty);
try w.writeAll("(zig_hi_");
try dg.renderTypeForBuiltinFnName(w, src_eff_ty);
try w.writeByte('(');
try context.writeValue(dg, w, src_ty, .FunctionArgument);
try w.writeAll("), zig_lo_");
try dg.renderTypeForBuiltinFnName(w, src_eff_ty);
try w.writeByte('(');
try context.writeValue(dg, w, src_ty, .FunctionArgument);
try w.writeAll("))");
}
}
/// Renders a type in C typecast format.
///
/// 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 {
return CValue.none;
}
const target = f.object.dg.module.getTarget();
const operand = try f.resolveInst(ty_op.operand);
try reap(f, inst, &.{ty_op.operand});
const writer = f.object.writer();
const inst_ty = f.air.typeOfIndex(inst);
const local = try f.allocLocal(inst, inst_ty);
const inst_bits = inst_ty.bitSize(target);
const inst_int_info = inst_ty.intInfo(target);
const operand_ty = f.air.typeOf(ty_op.operand);
const operand_bits = operand_ty.bitSize(target);
const operand_int_info = operand_ty.intInfo(target);
try f.writeCValue(writer, local, .Other);
try writer.writeAll(" = ");
if (inst_bits <= 64 and operand_bits <= 64) {
if (toCIntBits(inst_int_info.bits) != toCIntBits(operand_int_info.bits) or inst_int_info.signedness != operand_int_info.signedness) {
try writer.writeByte('(');
try f.renderTypecast(writer, inst_ty);
try writer.writeByte(')');
}
try f.writeCValue(writer, operand, .Other);
} else if (inst_bits > 64 and operand_bits <= 64) {
try writer.writeAll("zig_as_");
try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
try writer.writeAll("(0, "); // TODO: Should the 0 go through fmtIntLiteral?
try f.writeCValue(writer, operand, .FunctionArgument);
try writer.writeByte(')');
} else if (inst_bits <= 64 and operand_bits > 64) {
try writer.writeAll("zig_lo_");
try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
try writer.writeByte('(');
try f.writeCValue(writer, operand, .FunctionArgument);
try writer.writeByte(')');
} else {
try writer.writeAll("zig_as_");
try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
try writer.writeAll("(zig_hi_");
try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
try writer.writeByte('(');
try f.writeCValue(writer, operand, .FunctionArgument);
try writer.writeAll("), zig_lo_");
try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
try writer.writeByte('(');
try f.writeCValue(writer, operand, .FunctionArgument);
try writer.writeAll("))");
}
try f.renderIntCast(writer, inst_ty, operand, operand_ty, .Other);
try writer.writeAll(";\n");
return local;
}
@ -6509,9 +6629,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
},
.Packed => {
try f.writeCValue(writer, local, .Other);
try writer.writeAll(" = (");
try f.renderTypecast(writer, inst_ty);
try writer.writeAll(")");
try writer.writeAll(" = ");
const int_info = inst_ty.intInfo(target);
var bit_offset_ty_pl = Type.Payload.Bits{
@ -6541,20 +6659,28 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
if (!empty) try writer.writeAll(", ");
// TODO: Skip this entire shift if val is 0?
try writer.writeAll("zig_shlw_");
try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
try writer.writeAll("((");
try f.renderTypecast(writer, inst_ty);
try writer.writeByte(')');
if (field_ty.isPtrAtRuntime()) {
try writer.writeByte('(');
if (inst_ty.isAbiInt() and (field_ty.isAbiInt() or field_ty.isPtrAtRuntime())) {
try f.renderIntCast(writer, inst_ty, element, field_ty, .FunctionArgument);
} else {
try writer.writeByte('(');
try f.renderTypecast(writer, switch (int_info.signedness) {
.unsigned => Type.usize,
.signed => Type.isize,
});
try f.renderTypecast(writer, inst_ty);
try writer.writeByte(')');
if (field_ty.isPtrAtRuntime()) {
try writer.writeByte('(');
try f.renderTypecast(writer, switch (int_info.signedness) {
.unsigned => Type.usize,
.signed => Type.isize,
});
try writer.writeByte(')');
}
try f.writeCValue(writer, element, .Other);
}
try f.writeCValue(writer, element, .Other);
try writer.writeAll(", ");
try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
try f.object.dg.renderBuiltinInfo(writer, inst_ty, .Bits);
@ -6564,7 +6690,14 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
bit_offset_val_pl.data += field_ty.bitSize(target);
empty = false;
}
if (empty) try f.writeCValue(writer, .{ .undef = inst_ty }, .Initializer);
if (empty) {
try writer.writeByte('(');
try f.renderTypecast(writer, inst_ty);
try writer.writeByte(')');
try f.writeCValue(writer, .{ .undef = inst_ty }, .Initializer);
}
try writer.writeAll(";\n");
},
},
@ -6937,7 +7070,7 @@ fn StringLiteral(comptime WriterType: type) type {
}
}
pub fn writeChar(self: *Self, c: u8) Error!void {
pub fn writeChar(self: *Self, c: u8) Error!void {
const writer = self.counting_writer.writer();
if (self.cur_len == 0 and self.counting_writer.bytes_written > 1)