| author | |
| committer | |
| log | eb3726c502e92ec4a3689732a76479c6d561cff5 |
| tree | 91f14deeaffd5e475c11be3ec8572b66a3799b37 |
| parent | d1d3dbc7b5bc986849db476e491300ffd18d4db5 |
| parent | 3268276b58d8b65cb295b738d7c14174005bd84e |
11 files changed, 156 insertions(+), 20 deletions(-)
CMakeLists.txt+1| ... | ... | @@ -425,6 +425,7 @@ set(ZIG_STD_FILES |
| 425 | 425 | "math/tan.zig" |
| 426 | 426 | "math/tanh.zig" |
| 427 | 427 | "math/trunc.zig" |
| 428 | "math/x86_64/sqrt.zig" | |
| 428 | 429 | "mem.zig" |
| 429 | 430 | "net.zig" |
| 430 | 431 | "os/child_process.zig" |
src/all_types.hpp+1| ... | ... | @@ -1421,6 +1421,7 @@ struct CodeGen { |
| 1421 | 1421 | HashMap<ZigLLVMFnKey, LLVMValueRef, zig_llvm_fn_key_hash, zig_llvm_fn_key_eql> llvm_fn_table; |
| 1422 | 1422 | HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> exported_symbol_names; |
| 1423 | 1423 | HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes; |
| 1424 | HashMap<Buf *, ConstExprValue *, buf_hash, buf_eql_buf> string_literals_table; | |
| 1424 | 1425 | |
| 1425 | 1426 | |
| 1426 | 1427 | ZigList<ImportTableEntry *> import_queue; |
src/analyze.cpp+8| ... | ... | @@ -4370,6 +4370,12 @@ bool type_requires_comptime(TypeTableEntry *type_entry) { |
| 4370 | 4370 | } |
| 4371 | 4371 | |
| 4372 | 4372 | void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) { |
| 4373 | auto entry = g->string_literals_table.maybe_get(str); | |
| 4374 | if (entry != nullptr) { | |
| 4375 | *const_val = *entry->value; | |
| 4376 | return; | |
| 4377 | } | |
| 4378 | ||
| 4373 | 4379 | const_val->special = ConstValSpecialStatic; |
| 4374 | 4380 | const_val->type = get_array_type(g, g->builtin_types.entry_u8, buf_len(str)); |
| 4375 | 4381 | 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) { |
| 4380 | 4386 | this_char->type = g->builtin_types.entry_u8; |
| 4381 | 4387 | bigint_init_unsigned(&this_char->data.x_bigint, (uint8_t)buf_ptr(str)[i]); |
| 4382 | 4388 | } |
| 4389 | ||
| 4390 | g->string_literals_table.put(str, const_val); | |
| 4383 | 4391 | } |
| 4384 | 4392 | |
| 4385 | 4393 | ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str) { |
src/buffer.cpp+4-1| ... | ... | @@ -67,9 +67,12 @@ bool buf_eql_buf(Buf *buf, Buf *other) { |
| 67 | 67 | |
| 68 | 68 | uint32_t buf_hash(Buf *buf) { |
| 69 | 69 | assert(buf->list.length); |
| 70 | size_t interval = buf->list.length / 256; | |
| 71 | if (interval == 0) | |
| 72 | interval = 1; | |
| 70 | 73 | // FNV 32-bit hash |
| 71 | 74 | uint32_t h = 2166136261; |
| 72 | for (size_t i = 0; i < buf_len(buf); i += 1) { | |
| 75 | for (size_t i = 0; i < buf_len(buf); i += interval) { | |
| 73 | 76 | h = h ^ ((uint8_t)buf->list.at(i)); |
| 74 | 77 | h = h * 16777619; |
| 75 | 78 | } |
src/codegen.cpp+1| ... | ... | @@ -87,6 +87,7 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out |
| 87 | 87 | g->memoized_fn_eval_table.init(16); |
| 88 | 88 | g->exported_symbol_names.init(8); |
| 89 | 89 | g->external_prototypes.init(8); |
| 90 | g->string_literals_table.init(16); | |
| 90 | 91 | g->is_test_build = false; |
| 91 | 92 | g->want_h_file = (out_type == OutTypeObj || out_type == OutTypeLib); |
| 92 | 93 | buf_resize(&g->global_asm, 0); |
src/ir.cpp+4-4| ... | ... | @@ -13224,9 +13224,9 @@ static TypeTableEntry *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstr |
| 13224 | 13224 | os_path_resolve(&source_dir_path, rel_file_path, &file_path); |
| 13225 | 13225 | |
| 13226 | 13226 | // load from file system into const expr |
| 13227 | Buf file_contents = BUF_INIT; | |
| 13227 | Buf *file_contents = buf_alloc(); | |
| 13228 | 13228 | int err; |
| 13229 | if ((err = os_fetch_file_path(&file_path, &file_contents))) { | |
| 13229 | if ((err = os_fetch_file_path(&file_path, file_contents))) { | |
| 13230 | 13230 | if (err == ErrorFileNotFound) { |
| 13231 | 13231 | ir_add_error(ira, instruction->name, buf_sprintf("unable to find '%s'", buf_ptr(&file_path))); |
| 13232 | 13232 | return ira->codegen->builtin_types.entry_invalid; |
| ... | ... | @@ -13240,9 +13240,9 @@ static TypeTableEntry *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstr |
| 13240 | 13240 | // we'll have to invalidate the cache |
| 13241 | 13241 | |
| 13242 | 13242 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 13243 | init_const_str_lit(ira->codegen, out_val, &file_contents); | |
| 13243 | init_const_str_lit(ira->codegen, out_val, file_contents); | |
| 13244 | 13244 | |
| 13245 | return get_array_type(ira->codegen, ira->codegen->builtin_types.entry_u8, buf_len(&file_contents)); | |
| 13245 | return get_array_type(ira->codegen, ira->codegen->builtin_types.entry_u8, buf_len(file_contents)); | |
| 13246 | 13246 | } |
| 13247 | 13247 | |
| 13248 | 13248 | static TypeTableEntry *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructionCmpxchg *instruction) { |
std/endian.zig+8-3| ... | ... | @@ -2,11 +2,11 @@ const mem = @import("mem.zig"); |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | 3 | |
| 4 | 4 | pub fn swapIfLe(comptime T: type, x: T) -> T { |
| 5 | return swapIf(false, T, x); | |
| 5 | return swapIf(builtin.Endian.Little, T, x); | |
| 6 | 6 | } |
| 7 | 7 | |
| 8 | 8 | pub fn swapIfBe(comptime T: type, x: T) -> T { |
| 9 | return swapIf(true, T, x); | |
| 9 | return swapIf(builtin.Endian.Big, T, x); | |
| 10 | 10 | } |
| 11 | 11 | |
| 12 | 12 | 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 { |
| 15 | 15 | |
| 16 | 16 | pub fn swap(comptime T: type, x: T) -> T { |
| 17 | 17 | var buf: [@sizeOf(T)]u8 = undefined; |
| 18 | mem.writeInt(buf[0..], x, false); | |
| 18 | mem.writeInt(buf[0..], x, builtin.Endian.Little); | |
| 19 | 19 | return mem.readInt(buf, T, builtin.Endian.Big); |
| 20 | 20 | } |
| 21 | ||
| 22 | test "swap" { | |
| 23 | const debug = @import("debug/index.zig"); | |
| 24 | debug.assert(swap(u32, 0xDEADBEEF) == 0xEFBEADDE); | |
| 25 | } |
std/linked_list.zig+87-8| ... | ... | @@ -4,8 +4,18 @@ const assert = debug.assert; |
| 4 | 4 | const mem = std.mem; |
| 5 | 5 | const Allocator = mem.Allocator; |
| 6 | 6 | |
| 7 | /// Generic doubly linked list. | |
| 7 | /// Generic non-intrusive doubly linked list. | |
| 8 | 8 | pub fn LinkedList(comptime T: type) -> type { |
| 9 | return BaseLinkedList(T, void, ""); | |
| 10 | } | |
| 11 | ||
| 12 | /// Generic intrusive doubly linked list. | |
| 13 | pub fn IntrusiveLinkedList(comptime ParentType: type, comptime field_name: []const u8) -> type { | |
| 14 | return BaseLinkedList(void, ParentType, field_name); | |
| 15 | } | |
| 16 | ||
| 17 | /// Generic doubly linked list. | |
| 18 | fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_name: []const u8) -> type { | |
| 9 | 19 | return struct { |
| 10 | 20 | const Self = this; |
| 11 | 21 | |
| ... | ... | @@ -15,13 +25,23 @@ pub fn LinkedList(comptime T: type) -> type { |
| 15 | 25 | next: ?&Node, |
| 16 | 26 | data: T, |
| 17 | 27 | |
| 18 | pub fn init(data: &const T) -> Node { | |
| 28 | pub fn init(value: &const T) -> Node { | |
| 19 | 29 | return Node { |
| 20 | 30 | .prev = null, |
| 21 | 31 | .next = null, |
| 22 | .data = *data, | |
| 32 | .data = *value, | |
| 23 | 33 | }; |
| 24 | 34 | } |
| 35 | ||
| 36 | pub fn initIntrusive() -> Node { | |
| 37 | // TODO: when #678 is solved this can become `init`. | |
| 38 | return Node.init({}); | |
| 39 | } | |
| 40 | ||
| 41 | pub fn toData(node: &Node) -> &ParentType { | |
| 42 | comptime assert(isIntrusive()); | |
| 43 | return @fieldParentPtr(ParentType, field_name, node); | |
| 44 | } | |
| 25 | 45 | }; |
| 26 | 46 | |
| 27 | 47 | first: ?&Node, |
| ... | ... | @@ -40,6 +60,10 @@ pub fn LinkedList(comptime T: type) -> type { |
| 40 | 60 | }; |
| 41 | 61 | } |
| 42 | 62 | |
| 63 | fn isIntrusive() -> bool { | |
| 64 | return ParentType != void or field_name.len != 0; | |
| 65 | } | |
| 66 | ||
| 43 | 67 | /// Insert a new node after an existing one. |
| 44 | 68 | /// |
| 45 | 69 | /// Arguments: |
| ... | ... | @@ -167,6 +191,7 @@ pub fn LinkedList(comptime T: type) -> type { |
| 167 | 191 | /// Returns: |
| 168 | 192 | /// A pointer to the new node. |
| 169 | 193 | pub fn allocateNode(list: &Self, allocator: &Allocator) -> %&Node { |
| 194 | comptime assert(!isIntrusive()); | |
| 170 | 195 | return allocator.create(Node); |
| 171 | 196 | } |
| 172 | 197 | |
| ... | ... | @@ -176,6 +201,7 @@ pub fn LinkedList(comptime T: type) -> type { |
| 176 | 201 | /// node: Pointer to the node to deallocate. |
| 177 | 202 | /// allocator: Dynamic memory allocator. |
| 178 | 203 | pub fn destroyNode(list: &Self, node: &Node, allocator: &Allocator) { |
| 204 | comptime assert(!isIntrusive()); | |
| 179 | 205 | allocator.destroy(node); |
| 180 | 206 | } |
| 181 | 207 | |
| ... | ... | @@ -188,6 +214,7 @@ pub fn LinkedList(comptime T: type) -> type { |
| 188 | 214 | /// Returns: |
| 189 | 215 | /// A pointer to the new node. |
| 190 | 216 | pub fn createNode(list: &Self, data: &const T, allocator: &Allocator) -> %&Node { |
| 217 | comptime assert(!isIntrusive()); | |
| 191 | 218 | var node = try list.allocateNode(allocator); |
| 192 | 219 | *node = Node.init(data); |
| 193 | 220 | return node; |
| ... | ... | @@ -199,11 +226,11 @@ test "basic linked list test" { |
| 199 | 226 | const allocator = debug.global_allocator; |
| 200 | 227 | var list = LinkedList(u32).init(); |
| 201 | 228 | |
| 202 | var one = list.createNode(1, allocator) catch unreachable; | |
| 203 | var two = list.createNode(2, allocator) catch unreachable; | |
| 204 | var three = list.createNode(3, allocator) catch unreachable; | |
| 205 | var four = list.createNode(4, allocator) catch unreachable; | |
| 206 | var five = list.createNode(5, allocator) catch unreachable; | |
| 229 | var one = try list.createNode(1, allocator); | |
| 230 | var two = try list.createNode(2, allocator); | |
| 231 | var three = try list.createNode(3, allocator); | |
| 232 | var four = try list.createNode(4, allocator); | |
| 233 | var five = try list.createNode(5, allocator); | |
| 207 | 234 | defer { |
| 208 | 235 | list.destroyNode(one, allocator); |
| 209 | 236 | list.destroyNode(two, allocator); |
| ... | ... | @@ -246,3 +273,55 @@ test "basic linked list test" { |
| 246 | 273 | assert ((??list.last ).data == 4); |
| 247 | 274 | assert (list.len == 2); |
| 248 | 275 | } |
| 276 | ||
| 277 | const link = "link"; | |
| 278 | const ElementList = IntrusiveLinkedList(Element, link); | |
| 279 | const Element = struct { | |
| 280 | value: u32, | |
| 281 | link: IntrusiveLinkedList(Element, link).Node, | |
| 282 | }; | |
| 283 | ||
| 284 | test "basic intrusive linked list test" { | |
| 285 | const allocator = debug.global_allocator; | |
| 286 | var list = ElementList.init(); | |
| 287 | ||
| 288 | var one = Element { .value = 1, .link = ElementList.Node.initIntrusive() }; | |
| 289 | var two = Element { .value = 2, .link = ElementList.Node.initIntrusive() }; | |
| 290 | var three = Element { .value = 3, .link = ElementList.Node.initIntrusive() }; | |
| 291 | var four = Element { .value = 4, .link = ElementList.Node.initIntrusive() }; | |
| 292 | var five = Element { .value = 5, .link = ElementList.Node.initIntrusive() }; | |
| 293 | ||
| 294 | list.append(&two.link); // {2} | |
| 295 | list.append(&five.link); // {2, 5} | |
| 296 | list.prepend(&one.link); // {1, 2, 5} | |
| 297 | list.insertBefore(&five.link, &four.link); // {1, 2, 4, 5} | |
| 298 | list.insertAfter(&two.link, &three.link); // {1, 2, 3, 4, 5} | |
| 299 | ||
| 300 | // Traverse forwards. | |
| 301 | { | |
| 302 | var it = list.first; | |
| 303 | var index: u32 = 1; | |
| 304 | while (it) |node| : (it = node.next) { | |
| 305 | assert(node.toData().value == index); | |
| 306 | index += 1; | |
| 307 | } | |
| 308 | } | |
| 309 | ||
| 310 | // Traverse backwards. | |
| 311 | { | |
| 312 | var it = list.last; | |
| 313 | var index: u32 = 1; | |
| 314 | while (it) |node| : (it = node.prev) { | |
| 315 | assert(node.toData().value == (6 - index)); | |
| 316 | index += 1; | |
| 317 | } | |
| 318 | } | |
| 319 | ||
| 320 | var first = list.popFirst(); // {2, 3, 4, 5} | |
| 321 | var last = list.pop(); // {2, 3, 4} | |
| 322 | list.remove(&three.link); // {2, 4} | |
| 323 | ||
| 324 | assert ((??list.first).toData().value == 2); | |
| 325 | assert ((??list.last ).toData().value == 4); | |
| 326 | assert (list.len == 2); | |
| 327 | } |
std/math/sqrt.zig+14-4| ... | ... | @@ -18,11 +18,21 @@ pub fn sqrt(x: var) -> (if (@typeId(@typeOf(x)) == TypeId.Int) @IntType(false, @ |
| 18 | 18 | return T(sqrt64(x)); |
| 19 | 19 | }, |
| 20 | 20 | TypeId.Float => { |
| 21 | return switch (T) { | |
| 22 | f32 => sqrt32(x), | |
| 23 | f64 => sqrt64(x), | |
| 21 | switch (T) { | |
| 22 | f32 => { | |
| 23 | switch (builtin.arch) { | |
| 24 | builtin.Arch.x86_64 => return @import("x86_64/sqrt.zig").sqrt32(x), | |
| 25 | else => return sqrt32(x), | |
| 26 | } | |
| 27 | }, | |
| 28 | f64 => { | |
| 29 | switch (builtin.arch) { | |
| 30 | builtin.Arch.x86_64 => return @import("x86_64/sqrt.zig").sqrt64(x), | |
| 31 | else => return sqrt64(x), | |
| 32 | } | |
| 33 | }, | |
| 24 | 34 | else => @compileError("sqrt not implemented for " ++ @typeName(T)), |
| 25 | }; | |
| 35 | } | |
| 26 | 36 | }, |
| 27 | 37 | TypeId.IntLiteral => comptime { |
| 28 | 38 | if (x > @maxValue(u128)) { |
std/math/x86_64/sqrt.zig created+15| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | pub fn sqrt32(x: f32) -> f32 { | |
| 2 | return asm ( | |
| 3 | \\sqrtss %%xmm0, %%xmm0 | |
| 4 | : [ret] "={xmm0}" (-> f32) | |
| 5 | : [x] "{xmm0}" (x) | |
| 6 | ); | |
| 7 | } | |
| 8 | ||
| 9 | pub fn sqrt64(x: f64) -> f64 { | |
| 10 | return asm ( | |
| 11 | \\sqrtsd %%xmm0, %%xmm0 | |
| 12 | : [ret] "={xmm0}" (-> f64) | |
| 13 | : [x] "{xmm0}" (x) | |
| 14 | ); | |
| 15 | } |
test/cases/eval.zig+13| ... | ... | @@ -375,3 +375,16 @@ test "f128 at compile time is lossy" { |
| 375 | 375 | |
| 376 | 376 | // TODO need a better implementation of bigfloat_init_bigint |
| 377 | 377 | // assert(f128(1 << 113) == 10384593717069655257060992658440192); |
| 378 | ||
| 379 | pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) -> type { | |
| 380 | return struct { | |
| 381 | pub const Node = struct { }; | |
| 382 | }; | |
| 383 | } | |
| 384 | ||
| 385 | test "string literal used as comptime slice is memoized" { | |
| 386 | const a = "link"; | |
| 387 | const b = "link"; | |
| 388 | comptime assert(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node); | |
| 389 | comptime assert(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node); | |
| 390 | } |