mirror of
https://github.com/ziglang/zig.git
synced 2025-12-21 13:43:10 +00:00
C backend: while, struct tests, better undefined global handling
1. Function signatures that return a no member struct return void 2. Undefined var decls don't get a value generated for them 3. Don't generate bitcast code if the result isn't used, since bitcast is a pure function. Right now struct handling code generates some weird unused bitcast AIR, and this optimization side steps that issue.
This commit is contained in:
parent
a7d215759e
commit
e3d638a49e
@ -448,7 +448,12 @@ pub const DeclGen = struct {
|
|||||||
try w.writeAll("ZIG_COLD ");
|
try w.writeAll("ZIG_COLD ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try dg.renderType(w, dg.decl.ty.fnReturnType());
|
const return_ty = dg.decl.ty.fnReturnType();
|
||||||
|
if (return_ty.hasCodeGenBits()) {
|
||||||
|
try dg.renderType(w, return_ty);
|
||||||
|
} else {
|
||||||
|
try w.writeAll("void");
|
||||||
|
}
|
||||||
try w.writeAll(" ");
|
try w.writeAll(" ");
|
||||||
try dg.renderDeclName(dg.decl, w);
|
try dg.renderDeclName(dg.decl, w);
|
||||||
try w.writeAll("(");
|
try w.writeAll("(");
|
||||||
@ -947,6 +952,10 @@ pub fn genDecl(o: *Object) !void {
|
|||||||
}
|
}
|
||||||
try fwd_decl_writer.writeAll(";\n");
|
try fwd_decl_writer.writeAll(";\n");
|
||||||
|
|
||||||
|
if (variable.init.isUndef()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try o.indent_writer.insertNewline();
|
try o.indent_writer.insertNewline();
|
||||||
const w = o.writer();
|
const w = o.writer();
|
||||||
try o.dg.renderType(w, o.dg.decl.ty);
|
try o.dg.renderType(w, o.dg.decl.ty);
|
||||||
@ -1886,6 +1895,9 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
|
fn airBitcast(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 ty_op = f.air.instructions.items(.data)[inst].ty_op;
|
||||||
const operand = try f.resolveInst(ty_op.operand);
|
const operand = try f.resolveInst(ty_op.operand);
|
||||||
|
|
||||||
|
|||||||
@ -21,12 +21,15 @@ test {
|
|||||||
_ = @import("behavior/hasdecl.zig");
|
_ = @import("behavior/hasdecl.zig");
|
||||||
_ = @import("behavior/hasfield.zig");
|
_ = @import("behavior/hasfield.zig");
|
||||||
_ = @import("behavior/if.zig");
|
_ = @import("behavior/if.zig");
|
||||||
|
_ = @import("behavior/struct.zig");
|
||||||
|
_ = @import("behavior/truncate.zig");
|
||||||
_ = @import("behavior/null.zig");
|
_ = @import("behavior/null.zig");
|
||||||
_ = @import("behavior/ptrcast.zig");
|
_ = @import("behavior/ptrcast.zig");
|
||||||
_ = @import("behavior/pub_enum.zig");
|
_ = @import("behavior/pub_enum.zig");
|
||||||
_ = @import("behavior/truncate.zig");
|
_ = @import("behavior/truncate.zig");
|
||||||
_ = @import("behavior/underscore.zig");
|
_ = @import("behavior/underscore.zig");
|
||||||
_ = @import("behavior/usingnamespace.zig");
|
_ = @import("behavior/usingnamespace.zig");
|
||||||
|
_ = @import("behavior/while.zig");
|
||||||
|
|
||||||
if (builtin.object_format != .c) {
|
if (builtin.object_format != .c) {
|
||||||
// Tests that pass for stage1 and stage2 but not the C backend.
|
// Tests that pass for stage1 and stage2 but not the C backend.
|
||||||
@ -60,12 +63,11 @@ test {
|
|||||||
_ = @import("behavior/saturating_arithmetic.zig");
|
_ = @import("behavior/saturating_arithmetic.zig");
|
||||||
_ = @import("behavior/sizeof_and_typeof.zig");
|
_ = @import("behavior/sizeof_and_typeof.zig");
|
||||||
_ = @import("behavior/slice.zig");
|
_ = @import("behavior/slice.zig");
|
||||||
_ = @import("behavior/struct.zig");
|
_ = @import("behavior/struct_llvm.zig");
|
||||||
_ = @import("behavior/switch.zig");
|
_ = @import("behavior/switch.zig");
|
||||||
_ = @import("behavior/this.zig");
|
_ = @import("behavior/this.zig");
|
||||||
_ = @import("behavior/translate_c_macros.zig");
|
_ = @import("behavior/translate_c_macros.zig");
|
||||||
_ = @import("behavior/union.zig");
|
_ = @import("behavior/union.zig");
|
||||||
_ = @import("behavior/while.zig");
|
|
||||||
_ = @import("behavior/widening.zig");
|
_ = @import("behavior/widening.zig");
|
||||||
|
|
||||||
if (builtin.zig_is_stage2) {
|
if (builtin.zig_is_stage2) {
|
||||||
|
|||||||
@ -32,38 +32,6 @@ fn returnEmptyStructInstance() StructWithNoFields {
|
|||||||
return empty_global_instance;
|
return empty_global_instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StructFoo = struct {
|
|
||||||
a: i32,
|
|
||||||
b: bool,
|
|
||||||
c: f32,
|
|
||||||
};
|
|
||||||
test "structs" {
|
|
||||||
var foo: StructFoo = undefined;
|
|
||||||
@memset(@ptrCast([*]u8, &foo), 0, @sizeOf(StructFoo));
|
|
||||||
foo.a += 1;
|
|
||||||
foo.b = foo.a == 1;
|
|
||||||
try testFoo(foo);
|
|
||||||
testMutation(&foo);
|
|
||||||
try expect(foo.c == 100);
|
|
||||||
}
|
|
||||||
fn testFoo(foo: StructFoo) !void {
|
|
||||||
try expect(foo.b);
|
|
||||||
}
|
|
||||||
fn testMutation(foo: *StructFoo) void {
|
|
||||||
foo.c = 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
test "struct byval assign" {
|
|
||||||
var foo1: StructFoo = undefined;
|
|
||||||
var foo2: StructFoo = undefined;
|
|
||||||
|
|
||||||
foo1.a = 1234;
|
|
||||||
foo2.a = 0;
|
|
||||||
try expect(foo2.a == 0);
|
|
||||||
foo2 = foo1;
|
|
||||||
try expect(foo2.a == 1234);
|
|
||||||
}
|
|
||||||
|
|
||||||
const Node = struct {
|
const Node = struct {
|
||||||
val: Val,
|
val: Val,
|
||||||
next: *Node,
|
next: *Node,
|
||||||
@ -90,65 +58,3 @@ test "call member function directly" {
|
|||||||
const result = MemberFnTestFoo.member(instance);
|
const result = MemberFnTestFoo.member(instance);
|
||||||
try expect(result == 1234);
|
try expect(result == 1234);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "struct point to self" {
|
|
||||||
var root: Node = undefined;
|
|
||||||
root.val.x = 1;
|
|
||||||
|
|
||||||
var node: Node = undefined;
|
|
||||||
node.next = &root;
|
|
||||||
node.val.x = 2;
|
|
||||||
|
|
||||||
root.next = &node;
|
|
||||||
|
|
||||||
try expect(node.next.next.next.val.x == 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
test "void struct fields" {
|
|
||||||
const foo = VoidStructFieldsFoo{
|
|
||||||
.a = void{},
|
|
||||||
.b = 1,
|
|
||||||
.c = void{},
|
|
||||||
};
|
|
||||||
try expect(foo.b == 1);
|
|
||||||
try expect(@sizeOf(VoidStructFieldsFoo) == 4);
|
|
||||||
}
|
|
||||||
const VoidStructFieldsFoo = struct {
|
|
||||||
a: void,
|
|
||||||
b: i32,
|
|
||||||
c: void,
|
|
||||||
};
|
|
||||||
|
|
||||||
test "member functions" {
|
|
||||||
const r = MemberFnRand{ .seed = 1234 };
|
|
||||||
try expect(r.getSeed() == 1234);
|
|
||||||
}
|
|
||||||
const MemberFnRand = struct {
|
|
||||||
seed: u32,
|
|
||||||
pub fn getSeed(r: *const MemberFnRand) u32 {
|
|
||||||
return r.seed;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
test "return struct byval from function" {
|
|
||||||
const bar = makeBar2(1234, 5678);
|
|
||||||
try expect(bar.y == 5678);
|
|
||||||
}
|
|
||||||
const Bar = struct {
|
|
||||||
x: i32,
|
|
||||||
y: i32,
|
|
||||||
};
|
|
||||||
fn makeBar2(x: i32, y: i32) Bar {
|
|
||||||
return Bar{
|
|
||||||
.x = x,
|
|
||||||
.y = y,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
test "return empty struct from fn" {
|
|
||||||
_ = testReturnEmptyStructFromFn();
|
|
||||||
}
|
|
||||||
const EmptyStruct2 = struct {};
|
|
||||||
fn testReturnEmptyStructFromFn() EmptyStruct2 {
|
|
||||||
return EmptyStruct2{};
|
|
||||||
}
|
|
||||||
|
|||||||
134
test/behavior/struct_llvm.zig
Normal file
134
test/behavior/struct_llvm.zig
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
const native_endian = builtin.target.cpu.arch.endian();
|
||||||
|
const expect = std.testing.expect;
|
||||||
|
const expectEqual = std.testing.expectEqual;
|
||||||
|
const expectEqualSlices = std.testing.expectEqualSlices;
|
||||||
|
const maxInt = std.math.maxInt;
|
||||||
|
|
||||||
|
const StructWithNoFields = struct {
|
||||||
|
fn add(a: i32, b: i32) i32 {
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const StructFoo = struct {
|
||||||
|
a: i32,
|
||||||
|
b: bool,
|
||||||
|
c: f32,
|
||||||
|
};
|
||||||
|
test "structs" {
|
||||||
|
var foo: StructFoo = undefined;
|
||||||
|
@memset(@ptrCast([*]u8, &foo), 0, @sizeOf(StructFoo));
|
||||||
|
foo.a += 1;
|
||||||
|
foo.b = foo.a == 1;
|
||||||
|
try testFoo(foo);
|
||||||
|
testMutation(&foo);
|
||||||
|
try expect(foo.c == 100);
|
||||||
|
}
|
||||||
|
fn testFoo(foo: StructFoo) !void {
|
||||||
|
try expect(foo.b);
|
||||||
|
}
|
||||||
|
fn testMutation(foo: *StructFoo) void {
|
||||||
|
foo.c = 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
test "struct byval assign" {
|
||||||
|
var foo1: StructFoo = undefined;
|
||||||
|
var foo2: StructFoo = undefined;
|
||||||
|
|
||||||
|
foo1.a = 1234;
|
||||||
|
foo2.a = 0;
|
||||||
|
try expect(foo2.a == 0);
|
||||||
|
foo2 = foo1;
|
||||||
|
try expect(foo2.a == 1234);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Node = struct {
|
||||||
|
val: Val,
|
||||||
|
next: *Node,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Val = struct {
|
||||||
|
x: i32,
|
||||||
|
};
|
||||||
|
|
||||||
|
test "struct initializer" {
|
||||||
|
const val = Val{ .x = 42 };
|
||||||
|
try expect(val.x == 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
const MemberFnTestFoo = struct {
|
||||||
|
x: i32,
|
||||||
|
fn member(foo: MemberFnTestFoo) i32 {
|
||||||
|
return foo.x;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
test "call member function directly" {
|
||||||
|
const instance = MemberFnTestFoo{ .x = 1234 };
|
||||||
|
const result = MemberFnTestFoo.member(instance);
|
||||||
|
try expect(result == 1234);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "struct point to self" {
|
||||||
|
var root: Node = undefined;
|
||||||
|
root.val.x = 1;
|
||||||
|
|
||||||
|
var node: Node = undefined;
|
||||||
|
node.next = &root;
|
||||||
|
node.val.x = 2;
|
||||||
|
|
||||||
|
root.next = &node;
|
||||||
|
|
||||||
|
try expect(node.next.next.next.val.x == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "void struct fields" {
|
||||||
|
const foo = VoidStructFieldsFoo{
|
||||||
|
.a = void{},
|
||||||
|
.b = 1,
|
||||||
|
.c = void{},
|
||||||
|
};
|
||||||
|
try expect(foo.b == 1);
|
||||||
|
try expect(@sizeOf(VoidStructFieldsFoo) == 4);
|
||||||
|
}
|
||||||
|
const VoidStructFieldsFoo = struct {
|
||||||
|
a: void,
|
||||||
|
b: i32,
|
||||||
|
c: void,
|
||||||
|
};
|
||||||
|
|
||||||
|
test "member functions" {
|
||||||
|
const r = MemberFnRand{ .seed = 1234 };
|
||||||
|
try expect(r.getSeed() == 1234);
|
||||||
|
}
|
||||||
|
const MemberFnRand = struct {
|
||||||
|
seed: u32,
|
||||||
|
pub fn getSeed(r: *const MemberFnRand) u32 {
|
||||||
|
return r.seed;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
test "return struct byval from function" {
|
||||||
|
const bar = makeBar2(1234, 5678);
|
||||||
|
try expect(bar.y == 5678);
|
||||||
|
}
|
||||||
|
const Bar = struct {
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
};
|
||||||
|
fn makeBar2(x: i32, y: i32) Bar {
|
||||||
|
return Bar{
|
||||||
|
.x = x,
|
||||||
|
.y = y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
test "return empty struct from fn" {
|
||||||
|
_ = testReturnEmptyStructFromFn();
|
||||||
|
}
|
||||||
|
const EmptyStruct2 = struct {};
|
||||||
|
fn testReturnEmptyStructFromFn() EmptyStruct2 {
|
||||||
|
return EmptyStruct2{};
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user