cbe: fixes for compiling zig2.c under msvc

- add zig_mul_i128
- render slice structs in static initializers without casts / c99 style init
- add negative numbers and u128 to 128-bit multiply test
This commit is contained in:
kcbanner
2022-12-23 23:48:44 -05:00
parent 55c3551bef
commit f07d33f54b
3 changed files with 84 additions and 27 deletions

View File

@@ -1465,6 +1465,11 @@ static zig_u128 zig_mul_u128(zig_u128 lhs, zig_u128 rhs) {
static zig_u128 zig_mul_u128(zig_u128 lhs, zig_u128 rhs); // TODO
#endif
zig_extern zig_i128 __multi3(zig_i128 lhs, zig_i128 rhs);
static zig_i128 zig_mul_i128(zig_i128 lhs, zig_i128 rhs) {
return __multi3(lhs, rhs);
}
static inline zig_u128 zig_mulw_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
return zig_wrap_u128(zig_mul_u128(lhs, rhs), bits);
}

View File

@@ -320,7 +320,7 @@ pub const Function = struct {
try writer.writeAll("static ");
try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .Const, alignment, .Complete);
try writer.writeAll(" = ");
try f.object.dg.renderValue(writer, ty, val, .Initializer);
try f.object.dg.renderValue(writer, ty, val, .StaticInitializer);
try writer.writeAll(";\n ");
break :result decl_c_value;
} else CValue{ .constant = inst };
@@ -514,6 +514,7 @@ pub const DeclGen = struct {
ty: Type,
val: Value,
decl_index: Decl.Index,
location: ValueRenderLocation,
) error{ OutOfMemory, AnalysisFail }!void {
const decl = dg.module.declPtr(decl_index);
assert(decl.has_tv);
@@ -527,12 +528,16 @@ pub const DeclGen = struct {
inline for (.{ .function, .extern_fn }) |tag|
if (decl.val.castTag(tag)) |func|
if (func.data.owner_decl != decl_index)
return dg.renderDeclValue(writer, ty, val, func.data.owner_decl);
return dg.renderDeclValue(writer, ty, val, func.data.owner_decl, location);
if (ty.isSlice()) {
try writer.writeByte('(');
try dg.renderTypecast(writer, ty);
try writer.writeAll("){ .ptr = ");
if (location == .StaticInitializer) {
try writer.writeByte('{');
} else {
try writer.writeByte('(');
try dg.renderTypecast(writer, ty);
try writer.writeAll("){ .ptr = ");
}
var buf: Type.SlicePtrFieldTypeBuffer = undefined;
try dg.renderValue(writer, ty.slicePtrFieldType(&buf), val.slicePtr(), .Initializer);
@@ -542,7 +547,12 @@ pub const DeclGen = struct {
.data = val.sliceLen(dg.module),
};
const len_val = Value.initPayload(&len_pl.base);
return writer.print(", .len = {} }}", .{try dg.fmtIntLiteral(Type.usize, len_val)});
if (location == .StaticInitializer) {
return writer.print(", {} }}", .{try dg.fmtIntLiteral(Type.usize, len_val)});
} else {
return writer.print(", .len = {} }}", .{try dg.fmtIntLiteral(Type.usize, len_val)});
}
}
// We shouldn't cast C function pointers as this is UB (when you call
@@ -564,7 +574,7 @@ pub const DeclGen = struct {
// that its contents are defined with respect to.
//
// Used for .elem_ptr, .field_ptr, .opt_payload_ptr, .eu_payload_ptr
fn renderParentPtr(dg: *DeclGen, writer: anytype, ptr_val: Value, ptr_ty: Type) error{ OutOfMemory, AnalysisFail }!void {
fn renderParentPtr(dg: *DeclGen, writer: anytype, ptr_val: Value, ptr_ty: Type, location: ValueRenderLocation) error{ OutOfMemory, AnalysisFail }!void {
if (!ptr_ty.isSlice()) {
try writer.writeByte('(');
try dg.renderTypecast(writer, ptr_ty);
@@ -579,7 +589,7 @@ pub const DeclGen = struct {
.variable => ptr_val.castTag(.variable).?.data.owner_decl,
else => unreachable,
};
try dg.renderDeclValue(writer, ptr_ty, ptr_val, decl_index);
try dg.renderDeclValue(writer, ptr_ty, ptr_val, decl_index, location);
},
.field_ptr => {
const ptr_info = ptr_ty.ptrInfo();
@@ -617,7 +627,7 @@ pub const DeclGen = struct {
try writer.writeAll("&((");
try dg.renderTypecast(writer, u8_ptr_ty);
try writer.writeByte(')');
try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty);
try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty, location);
return writer.print(")[{}]", .{try dg.fmtIntLiteral(Type.usize, byte_offset_val)});
} else {
var host_pl = Type.Payload.Bits{
@@ -629,7 +639,7 @@ pub const DeclGen = struct {
try writer.writeByte('(');
try dg.renderTypecast(writer, ptr_ty);
try writer.writeByte(')');
return dg.renderParentPtr(writer, field_ptr.container_ptr, host_ty);
return dg.renderParentPtr(writer, field_ptr.container_ptr, host_ty, location);
},
},
.Union => switch (container_ty.containerLayout()) {
@@ -638,7 +648,7 @@ pub const DeclGen = struct {
.ty = container_ty.unionFields().values()[index].ty,
},
.Packed => {
return dg.renderParentPtr(writer, field_ptr.container_ptr, ptr_ty);
return dg.renderParentPtr(writer, field_ptr.container_ptr, ptr_ty, location);
},
},
.Pointer => field_info: {
@@ -657,7 +667,7 @@ pub const DeclGen = struct {
try dg.renderType(std.io.null_writer, field_ptr.container_ty, .Complete);
try writer.writeAll("&(");
try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty);
try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty, location);
try writer.writeAll(")->");
switch (field_ptr.container_ty.tag()) {
.union_tagged, .union_safety_tagged => try writer.writeAll("payload."),
@@ -665,7 +675,7 @@ pub const DeclGen = struct {
}
try writer.print("{ }", .{fmtIdent(field_info.name)});
} else {
try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty);
try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty, location);
}
},
.elem_ptr => {
@@ -677,7 +687,7 @@ pub const DeclGen = struct {
const elem_ptr_ty = Type.initPayload(&elem_ptr_ty_pl.base);
try writer.writeAll("&(");
try dg.renderParentPtr(writer, elem_ptr.array_ptr, elem_ptr_ty);
try dg.renderParentPtr(writer, elem_ptr.array_ptr, elem_ptr_ty, location);
try writer.print(")[{d}]", .{elem_ptr.index});
},
.opt_payload_ptr, .eu_payload_ptr => {
@@ -692,7 +702,7 @@ pub const DeclGen = struct {
try dg.renderType(std.io.null_writer, payload_ptr.container_ty, .Complete);
try writer.writeAll("&(");
try dg.renderParentPtr(writer, payload_ptr.container_ptr, container_ptr_ty);
try dg.renderParentPtr(writer, payload_ptr.container_ptr, container_ptr_ty, location);
try writer.writeAll(")->payload");
},
else => unreachable,
@@ -910,7 +920,7 @@ pub const DeclGen = struct {
.eu_payload_ptr,
.decl_ref_mut,
.decl_ref,
=> try dg.renderParentPtr(writer, val, ty),
=> try dg.renderParentPtr(writer, val, ty, location),
else => try writer.print("{}", .{try dg.fmtIntLiteralLoc(ty, val, location)}),
},
.Float => {
@@ -1024,7 +1034,7 @@ pub const DeclGen = struct {
},
.variable => {
const decl = val.castTag(.variable).?.data.owner_decl;
return dg.renderDeclValue(writer, ty, val, decl);
return dg.renderDeclValue(writer, ty, val, decl, location);
},
.slice => {
if (!location.isInitializer()) {
@@ -1061,7 +1071,7 @@ pub const DeclGen = struct {
.eu_payload_ptr,
.decl_ref_mut,
.decl_ref,
=> try dg.renderParentPtr(writer, val, ty),
=> try dg.renderParentPtr(writer, val, ty, location),
else => unreachable,
},
.Array, .Vector => {
@@ -1255,11 +1265,11 @@ pub const DeclGen = struct {
.Fn => switch (val.tag()) {
.function => {
const decl = val.castTag(.function).?.data.owner_decl;
return dg.renderDeclValue(writer, ty, val, decl);
return dg.renderDeclValue(writer, ty, val, decl, location);
},
.extern_fn => {
const decl = val.castTag(.extern_fn).?.data.owner_decl;
return dg.renderDeclValue(writer, ty, val, decl);
return dg.renderDeclValue(writer, ty, val, decl, location);
},
else => unreachable,
},
@@ -2512,6 +2522,9 @@ pub const DeclGen = struct {
try dg.writeCValue(writer, member);
}
const IdentHasher = std.crypto.auth.siphash.SipHash128(1, 3);
const ident_hasher_init: IdentHasher = IdentHasher.init(&[_]u8{0} ** IdentHasher.key_length);
fn renderDeclName(dg: *DeclGen, writer: anytype, decl_index: Decl.Index, export_index: u32) !void {
const decl = dg.module.declPtr(decl_index);
dg.module.markDeclAlive(decl);
@@ -2529,7 +2542,18 @@ pub const DeclGen = struct {
const gpa = dg.gpa;
const name = try decl.getFullyQualifiedName(dg.module);
defer gpa.free(name);
return writer.print("{}", .{fmtIdent(name)});
// MSVC has a limit of 4095 character token length limit, and fmtIdent can (worst case), expand
// to 3x the length of its input
if (name.len > 1365) {
var hash = ident_hasher_init;
hash.update(name);
const ident_hash = hash.finalInt();
try writer.writeAll("zig_D_");
return std.fmt.formatIntValue(ident_hash, "x", .{}, writer);
} else {
return writer.print("{}", .{fmtIdent(name)});
}
}
}
@@ -4648,7 +4672,15 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {
try f.writeCValue(writer, cond, .Other);
try writer.writeAll(") ");
try genBody(f, then_body);
try writer.writeAll(" else ");
// TODO: If body ends in goto, elide the else block?
const needs_else = then_body.len <= 0 or f.air.instructions.items(.tag)[then_body[then_body.len - 1]] != .br;
if (needs_else) {
try writer.writeAll(" else ");
} else {
try writer.writeByte('\n');
}
f.value_map.deinit();
f.value_map = cloned_map.move();
const free_locals = f.getFreeLocals();
@@ -4661,7 +4693,12 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {
try noticeBranchFrees(f, pre_locals_len, inst);
try genBody(f, else_body);
if (needs_else) {
try genBody(f, else_body);
} else {
try genBodyInner(f, else_body);
}
try f.object.indent_writer.insertNewline();
return CValue.none;

View File

@@ -632,10 +632,25 @@ test "128-bit multiplication" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
var a: i128 = 3;
var b: i128 = 2;
var c = a * b;
try expect(c == 6);
{
var a: i128 = 3;
var b: i128 = 2;
var c = a * b;
try expect(c == 6);
a = -3;
b = 2;
c = a * b;
try expect(c == -6);
}
{
var a: u128 = 0xffffffffffffffff;
var b: u128 = 100;
var c = a * b;
try expect(c == 0x63ffffffffffffff9c);
}
}
test "@addWithOverflow" {