commit eb3726c502e92ec4a3689732a76479c6d561cff5 (tree)
parent d1d3dbc7b5bc986849db476e491300ffd18d4db5
Author: Andrew Kelley <superjoe30@gmail.com>
Date: Thu, 11 Jan 2018 22:26:55 -0500
Merge branch 'master' into llvm6
Diffstat:
11 files changed, 156 insertions(+), 20 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
@@ -425,6 +425,7 @@ set(ZIG_STD_FILES
"math/tan.zig"
"math/tanh.zig"
"math/trunc.zig"
+ "math/x86_64/sqrt.zig"
"mem.zig"
"net.zig"
"os/child_process.zig"
diff --git a/src/all_types.hpp b/src/all_types.hpp
@@ -1421,6 +1421,7 @@ struct CodeGen {
HashMap<ZigLLVMFnKey, LLVMValueRef, zig_llvm_fn_key_hash, zig_llvm_fn_key_eql> llvm_fn_table;
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> exported_symbol_names;
HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes;
+ HashMap<Buf *, ConstExprValue *, buf_hash, buf_eql_buf> string_literals_table;
ZigList<ImportTableEntry *> import_queue;
diff --git a/src/analyze.cpp b/src/analyze.cpp
@@ -4370,6 +4370,12 @@ bool type_requires_comptime(TypeTableEntry *type_entry) {
}
void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) {
+ auto entry = g->string_literals_table.maybe_get(str);
+ if (entry != nullptr) {
+ *const_val = *entry->value;
+ return;
+ }
+
const_val->special = ConstValSpecialStatic;
const_val->type = get_array_type(g, g->builtin_types.entry_u8, buf_len(str));
const_val->data.x_array.s_none.elements = create_const_vals(buf_len(str));
@@ -4380,6 +4386,8 @@ void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) {
this_char->type = g->builtin_types.entry_u8;
bigint_init_unsigned(&this_char->data.x_bigint, (uint8_t)buf_ptr(str)[i]);
}
+
+ g->string_literals_table.put(str, const_val);
}
ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str) {
diff --git a/src/buffer.cpp b/src/buffer.cpp
@@ -67,9 +67,12 @@ bool buf_eql_buf(Buf *buf, Buf *other) {
uint32_t buf_hash(Buf *buf) {
assert(buf->list.length);
+ size_t interval = buf->list.length / 256;
+ if (interval == 0)
+ interval = 1;
// FNV 32-bit hash
uint32_t h = 2166136261;
- for (size_t i = 0; i < buf_len(buf); i += 1) {
+ for (size_t i = 0; i < buf_len(buf); i += interval) {
h = h ^ ((uint8_t)buf->list.at(i));
h = h * 16777619;
}
diff --git a/src/codegen.cpp b/src/codegen.cpp
@@ -87,6 +87,7 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
g->memoized_fn_eval_table.init(16);
g->exported_symbol_names.init(8);
g->external_prototypes.init(8);
+ g->string_literals_table.init(16);
g->is_test_build = false;
g->want_h_file = (out_type == OutTypeObj || out_type == OutTypeLib);
buf_resize(&g->global_asm, 0);
diff --git a/src/ir.cpp b/src/ir.cpp
@@ -13224,9 +13224,9 @@ static TypeTableEntry *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstr
os_path_resolve(&source_dir_path, rel_file_path, &file_path);
// load from file system into const expr
- Buf file_contents = BUF_INIT;
+ Buf *file_contents = buf_alloc();
int err;
- if ((err = os_fetch_file_path(&file_path, &file_contents))) {
+ if ((err = os_fetch_file_path(&file_path, file_contents))) {
if (err == ErrorFileNotFound) {
ir_add_error(ira, instruction->name, buf_sprintf("unable to find '%s'", buf_ptr(&file_path)));
return ira->codegen->builtin_types.entry_invalid;
@@ -13240,9 +13240,9 @@ static TypeTableEntry *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstr
// we'll have to invalidate the cache
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
- init_const_str_lit(ira->codegen, out_val, &file_contents);
+ init_const_str_lit(ira->codegen, out_val, file_contents);
- return get_array_type(ira->codegen, ira->codegen->builtin_types.entry_u8, buf_len(&file_contents));
+ return get_array_type(ira->codegen, ira->codegen->builtin_types.entry_u8, buf_len(file_contents));
}
static TypeTableEntry *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructionCmpxchg *instruction) {
diff --git a/std/endian.zig b/std/endian.zig
@@ -2,11 +2,11 @@ const mem = @import("mem.zig");
const builtin = @import("builtin");
pub fn swapIfLe(comptime T: type, x: T) -> T {
- return swapIf(false, T, x);
+ return swapIf(builtin.Endian.Little, T, x);
}
pub fn swapIfBe(comptime T: type, x: T) -> T {
- return swapIf(true, T, x);
+ return swapIf(builtin.Endian.Big, T, x);
}
pub fn swapIf(endian: builtin.Endian, comptime T: type, x: T) -> T {
@@ -15,6 +15,11 @@ pub fn swapIf(endian: builtin.Endian, comptime T: type, x: T) -> T {
pub fn swap(comptime T: type, x: T) -> T {
var buf: [@sizeOf(T)]u8 = undefined;
- mem.writeInt(buf[0..], x, false);
+ mem.writeInt(buf[0..], x, builtin.Endian.Little);
return mem.readInt(buf, T, builtin.Endian.Big);
}
+
+test "swap" {
+ const debug = @import("debug/index.zig");
+ debug.assert(swap(u32, 0xDEADBEEF) == 0xEFBEADDE);
+}
diff --git a/std/linked_list.zig b/std/linked_list.zig
@@ -4,8 +4,18 @@ const assert = debug.assert;
const mem = std.mem;
const Allocator = mem.Allocator;
-/// Generic doubly linked list.
+/// Generic non-intrusive doubly linked list.
pub fn LinkedList(comptime T: type) -> type {
+ return BaseLinkedList(T, void, "");
+}
+
+/// Generic intrusive doubly linked list.
+pub fn IntrusiveLinkedList(comptime ParentType: type, comptime field_name: []const u8) -> type {
+ return BaseLinkedList(void, ParentType, field_name);
+}
+
+/// Generic doubly linked list.
+fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_name: []const u8) -> type {
return struct {
const Self = this;
@@ -15,13 +25,23 @@ pub fn LinkedList(comptime T: type) -> type {
next: ?&Node,
data: T,
- pub fn init(data: &const T) -> Node {
+ pub fn init(value: &const T) -> Node {
return Node {
.prev = null,
.next = null,
- .data = *data,
+ .data = *value,
};
}
+
+ pub fn initIntrusive() -> Node {
+ // TODO: when #678 is solved this can become `init`.
+ return Node.init({});
+ }
+
+ pub fn toData(node: &Node) -> &ParentType {
+ comptime assert(isIntrusive());
+ return @fieldParentPtr(ParentType, field_name, node);
+ }
};
first: ?&Node,
@@ -40,6 +60,10 @@ pub fn LinkedList(comptime T: type) -> type {
};
}
+ fn isIntrusive() -> bool {
+ return ParentType != void or field_name.len != 0;
+ }
+
/// Insert a new node after an existing one.
///
/// Arguments:
@@ -167,6 +191,7 @@ pub fn LinkedList(comptime T: type) -> type {
/// Returns:
/// A pointer to the new node.
pub fn allocateNode(list: &Self, allocator: &Allocator) -> %&Node {
+ comptime assert(!isIntrusive());
return allocator.create(Node);
}
@@ -176,6 +201,7 @@ pub fn LinkedList(comptime T: type) -> type {
/// node: Pointer to the node to deallocate.
/// allocator: Dynamic memory allocator.
pub fn destroyNode(list: &Self, node: &Node, allocator: &Allocator) {
+ comptime assert(!isIntrusive());
allocator.destroy(node);
}
@@ -188,6 +214,7 @@ pub fn LinkedList(comptime T: type) -> type {
/// Returns:
/// A pointer to the new node.
pub fn createNode(list: &Self, data: &const T, allocator: &Allocator) -> %&Node {
+ comptime assert(!isIntrusive());
var node = try list.allocateNode(allocator);
*node = Node.init(data);
return node;
@@ -199,11 +226,11 @@ test "basic linked list test" {
const allocator = debug.global_allocator;
var list = LinkedList(u32).init();
- var one = list.createNode(1, allocator) catch unreachable;
- var two = list.createNode(2, allocator) catch unreachable;
- var three = list.createNode(3, allocator) catch unreachable;
- var four = list.createNode(4, allocator) catch unreachable;
- var five = list.createNode(5, allocator) catch unreachable;
+ var one = try list.createNode(1, allocator);
+ var two = try list.createNode(2, allocator);
+ var three = try list.createNode(3, allocator);
+ var four = try list.createNode(4, allocator);
+ var five = try list.createNode(5, allocator);
defer {
list.destroyNode(one, allocator);
list.destroyNode(two, allocator);
@@ -246,3 +273,55 @@ test "basic linked list test" {
assert ((??list.last ).data == 4);
assert (list.len == 2);
}
+
+const link = "link";
+const ElementList = IntrusiveLinkedList(Element, link);
+const Element = struct {
+ value: u32,
+ link: IntrusiveLinkedList(Element, link).Node,
+};
+
+test "basic intrusive linked list test" {
+ const allocator = debug.global_allocator;
+ var list = ElementList.init();
+
+ var one = Element { .value = 1, .link = ElementList.Node.initIntrusive() };
+ var two = Element { .value = 2, .link = ElementList.Node.initIntrusive() };
+ var three = Element { .value = 3, .link = ElementList.Node.initIntrusive() };
+ var four = Element { .value = 4, .link = ElementList.Node.initIntrusive() };
+ var five = Element { .value = 5, .link = ElementList.Node.initIntrusive() };
+
+ list.append(&two.link); // {2}
+ list.append(&five.link); // {2, 5}
+ list.prepend(&one.link); // {1, 2, 5}
+ list.insertBefore(&five.link, &four.link); // {1, 2, 4, 5}
+ list.insertAfter(&two.link, &three.link); // {1, 2, 3, 4, 5}
+
+ // Traverse forwards.
+ {
+ var it = list.first;
+ var index: u32 = 1;
+ while (it) |node| : (it = node.next) {
+ assert(node.toData().value == index);
+ index += 1;
+ }
+ }
+
+ // Traverse backwards.
+ {
+ var it = list.last;
+ var index: u32 = 1;
+ while (it) |node| : (it = node.prev) {
+ assert(node.toData().value == (6 - index));
+ index += 1;
+ }
+ }
+
+ var first = list.popFirst(); // {2, 3, 4, 5}
+ var last = list.pop(); // {2, 3, 4}
+ list.remove(&three.link); // {2, 4}
+
+ assert ((??list.first).toData().value == 2);
+ assert ((??list.last ).toData().value == 4);
+ assert (list.len == 2);
+}
diff --git a/std/math/sqrt.zig b/std/math/sqrt.zig
@@ -18,11 +18,21 @@ pub fn sqrt(x: var) -> (if (@typeId(@typeOf(x)) == TypeId.Int) @IntType(false, @
return T(sqrt64(x));
},
TypeId.Float => {
- return switch (T) {
- f32 => sqrt32(x),
- f64 => sqrt64(x),
+ switch (T) {
+ f32 => {
+ switch (builtin.arch) {
+ builtin.Arch.x86_64 => return @import("x86_64/sqrt.zig").sqrt32(x),
+ else => return sqrt32(x),
+ }
+ },
+ f64 => {
+ switch (builtin.arch) {
+ builtin.Arch.x86_64 => return @import("x86_64/sqrt.zig").sqrt64(x),
+ else => return sqrt64(x),
+ }
+ },
else => @compileError("sqrt not implemented for " ++ @typeName(T)),
- };
+ }
},
TypeId.IntLiteral => comptime {
if (x > @maxValue(u128)) {
diff --git a/std/math/x86_64/sqrt.zig b/std/math/x86_64/sqrt.zig
@@ -0,0 +1,15 @@
+pub fn sqrt32(x: f32) -> f32 {
+ return asm (
+ \\sqrtss %%xmm0, %%xmm0
+ : [ret] "={xmm0}" (-> f32)
+ : [x] "{xmm0}" (x)
+ );
+}
+
+pub fn sqrt64(x: f64) -> f64 {
+ return asm (
+ \\sqrtsd %%xmm0, %%xmm0
+ : [ret] "={xmm0}" (-> f64)
+ : [x] "{xmm0}" (x)
+ );
+}
diff --git a/test/cases/eval.zig b/test/cases/eval.zig
@@ -375,3 +375,16 @@ test "f128 at compile time is lossy" {
// TODO need a better implementation of bigfloat_init_bigint
// assert(f128(1 << 113) == 10384593717069655257060992658440192);
+
+pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) -> type {
+ return struct {
+ pub const Node = struct { };
+ };
+}
+
+test "string literal used as comptime slice is memoized" {
+ const a = "link";
+ const b = "link";
+ comptime assert(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node);
+ comptime assert(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node);
+}