| author | |
| committer | |
| log | e7ab2bc5534a53c57c900618ec2411542dc50f69 |
| tree | 42c572bf7414f59a98cd40a37e7d2f5d94955084 |
| parent | 7903a758a44d1a253f17a4a2383f36b5fdad8545 |
| parent | c721354b73508ec53bf72d8e7fb304147676625d |
4 files changed, 146 insertions(+), 57 deletions(-)
src/zig_llvm.cpp+8-27| ... | @@ -43,31 +43,8 @@ | ... | @@ -43,31 +43,8 @@ |
| 43 | 43 | ||
| 44 | #include <stdlib.h> | 44 | #include <stdlib.h> |
| 45 | 45 | ||
| 46 | #if defined(_MSC_VER) | ||
| 47 | #define ATTRIBUTE_RETURNS_NOALIAS __declspec(restrict) | ||
| 48 | #else | ||
| 49 | #define ATTRIBUTE_RETURNS_NOALIAS __attribute__((__malloc__)) | ||
| 50 | #endif | ||
| 51 | |||
| 52 | using namespace llvm; | 46 | using namespace llvm; |
| 53 | 47 | ||
| 54 | template<typename T, typename... Args> | ||
| 55 | ATTRIBUTE_RETURNS_NOALIAS static inline T * create(Args... args) { | ||
| 56 | T * ptr = reinterpret_cast<T*>(malloc(sizeof(T))); | ||
| 57 | if (ptr == nullptr) | ||
| 58 | return nullptr; | ||
| 59 | new (ptr) T(args...); | ||
| 60 | return ptr; | ||
| 61 | } | ||
| 62 | |||
| 63 | template<typename T> | ||
| 64 | static inline void destroy(T * ptr) { | ||
| 65 | if (ptr != nullptr) { | ||
| 66 | ptr[0].~T(); | ||
| 67 | } | ||
| 68 | free(ptr); | ||
| 69 | } | ||
| 70 | |||
| 71 | void ZigLLVMInitializeLoopStrengthReducePass(LLVMPassRegistryRef R) { | 48 | void ZigLLVMInitializeLoopStrengthReducePass(LLVMPassRegistryRef R) { |
| 72 | initializeLoopStrengthReducePass(*unwrap(R)); | 49 | initializeLoopStrengthReducePass(*unwrap(R)); |
| 73 | } | 50 | } |
| ... | @@ -116,7 +93,11 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM | ... | @@ -116,7 +93,11 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM |
| 116 | 93 | ||
| 117 | Module* module = unwrap(module_ref); | 94 | Module* module = unwrap(module_ref); |
| 118 | 95 | ||
| 119 | PassManagerBuilder *PMBuilder = create<PassManagerBuilder>(); | 96 | PassManagerBuilder *PMBuilder = new(std::nothrow) PassManagerBuilder(); |
| 97 | if (PMBuilder == nullptr) { | ||
| 98 | *error_message = strdup("memory allocation failure"); | ||
| 99 | return true; | ||
| 100 | } | ||
| 120 | PMBuilder->OptLevel = target_machine->getOptLevel(); | 101 | PMBuilder->OptLevel = target_machine->getOptLevel(); |
| 121 | PMBuilder->SizeLevel = 0; | 102 | PMBuilder->SizeLevel = 0; |
| 122 | 103 | ||
| ... | @@ -150,7 +131,8 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM | ... | @@ -150,7 +131,8 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM |
| 150 | 131 | ||
| 151 | // Set up the per-function pass manager. | 132 | // Set up the per-function pass manager. |
| 152 | legacy::FunctionPassManager FPM = legacy::FunctionPassManager(module); | 133 | legacy::FunctionPassManager FPM = legacy::FunctionPassManager(module); |
| 153 | FPM.add(create<TargetLibraryInfoWrapperPass>(tlii)); | 134 | auto tliwp = new(std::nothrow) TargetLibraryInfoWrapperPass(tlii); |
| 135 | FPM.add(tliwp); | ||
| 154 | FPM.add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis())); | 136 | FPM.add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis())); |
| 155 | if (assertions_on) { | 137 | if (assertions_on) { |
| 156 | FPM.add(createVerifierPass()); | 138 | FPM.add(createVerifierPass()); |
| ... | @@ -446,10 +428,9 @@ unsigned ZigLLVMTag_DW_union_type(void) { | ... | @@ -446,10 +428,9 @@ unsigned ZigLLVMTag_DW_union_type(void) { |
| 446 | } | 428 | } |
| 447 | 429 | ||
| 448 | ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved) { | 430 | ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved) { |
| 449 | DIBuilder *di_builder = reinterpret_cast<DIBuilder*>(malloc(sizeof(DIBuilder))); | 431 | DIBuilder *di_builder = new(std::nothrow) DIBuilder(*unwrap(module), allow_unresolved); |
| 450 | if (di_builder == nullptr) | 432 | if (di_builder == nullptr) |
| 451 | return nullptr; | 433 | return nullptr; |
| 452 | new (di_builder) DIBuilder(*unwrap(module), allow_unresolved); | ||
| 453 | return reinterpret_cast<ZigLLVMDIBuilder *>(di_builder); | 434 | return reinterpret_cast<ZigLLVMDIBuilder *>(di_builder); |
| 454 | } | 435 | } |
| 455 | 436 |
std/zig/ast.zig+17-15| ... | @@ -18,6 +18,7 @@ pub const Node = struct { | ... | @@ -18,6 +18,7 @@ pub const Node = struct { |
| 18 | PrefixOp, | 18 | PrefixOp, |
| 19 | IntegerLiteral, | 19 | IntegerLiteral, |
| 20 | FloatLiteral, | 20 | FloatLiteral, |
| 21 | BuiltinCall, | ||
| 21 | }; | 22 | }; |
| 22 | 23 | ||
| 23 | pub fn iterate(base: &Node, index: usize) ?&Node { | 24 | pub fn iterate(base: &Node, index: usize) ?&Node { |
| ... | @@ -32,21 +33,7 @@ pub const Node = struct { | ... | @@ -32,21 +33,7 @@ pub const Node = struct { |
| 32 | Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).iterate(index), | 33 | Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).iterate(index), |
| 33 | Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).iterate(index), | 34 | Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).iterate(index), |
| 34 | Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).iterate(index), | 35 | Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).iterate(index), |
| 35 | }; | 36 | Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).iterate(index), |
| 36 | } | ||
| 37 | |||
| 38 | pub fn destroy(base: &Node, allocator: &mem.Allocator) void { | ||
| 39 | return switch (base.id) { | ||
| 40 | Id.Root => allocator.destroy(@fieldParentPtr(NodeRoot, "base", base)), | ||
| 41 | Id.VarDecl => allocator.destroy(@fieldParentPtr(NodeVarDecl, "base", base)), | ||
| 42 | Id.Identifier => allocator.destroy(@fieldParentPtr(NodeIdentifier, "base", base)), | ||
| 43 | Id.FnProto => allocator.destroy(@fieldParentPtr(NodeFnProto, "base", base)), | ||
| 44 | Id.ParamDecl => allocator.destroy(@fieldParentPtr(NodeParamDecl, "base", base)), | ||
| 45 | Id.Block => allocator.destroy(@fieldParentPtr(NodeBlock, "base", base)), | ||
| 46 | Id.InfixOp => allocator.destroy(@fieldParentPtr(NodeInfixOp, "base", base)), | ||
| 47 | Id.PrefixOp => allocator.destroy(@fieldParentPtr(NodePrefixOp, "base", base)), | ||
| 48 | Id.IntegerLiteral => allocator.destroy(@fieldParentPtr(NodeIntegerLiteral, "base", base)), | ||
| 49 | Id.FloatLiteral => allocator.destroy(@fieldParentPtr(NodeFloatLiteral, "base", base)), | ||
| 50 | }; | 37 | }; |
| 51 | } | 38 | } |
| 52 | }; | 39 | }; |
| ... | @@ -269,3 +256,18 @@ pub const NodeFloatLiteral = struct { | ... | @@ -269,3 +256,18 @@ pub const NodeFloatLiteral = struct { |
| 269 | return null; | 256 | return null; |
| 270 | } | 257 | } |
| 271 | }; | 258 | }; |
| 259 | |||
| 260 | pub const NodeBuiltinCall = struct { | ||
| 261 | base: Node, | ||
| 262 | builtin_token: Token, | ||
| 263 | params: ArrayList(&Node), | ||
| 264 | |||
| 265 | pub fn iterate(self: &NodeBuiltinCall, index: usize) ?&Node { | ||
| 266 | var i = index; | ||
| 267 | |||
| 268 | if (i < self.params.len) return self.params.at(i); | ||
| 269 | i -= self.params.len; | ||
| 270 | |||
| 271 | return null; | ||
| 272 | } | ||
| 273 | }; |
std/zig/parser.zig+2-1| ... | @@ -95,7 +95,8 @@ pub const Parser = struct { | ... | @@ -95,7 +95,8 @@ pub const Parser = struct { |
| 95 | }; | 95 | }; |
| 96 | 96 | ||
| 97 | /// Returns an AST tree, allocated with the parser's allocator. | 97 | /// Returns an AST tree, allocated with the parser's allocator. |
| 98 | /// Result should be freed with `freeAst` when done. | 98 | /// Result should be freed with tree.deinit() when there are |
| 99 | /// no more references to any AST nodes of the tree. | ||
| 99 | pub fn parse(self: &Parser) !Tree { | 100 | pub fn parse(self: &Parser) !Tree { |
| 100 | var stack = self.initUtilityArrayList(State); | 101 | var stack = self.initUtilityArrayList(State); |
| 101 | defer self.deinitUtilityArrayList(stack); | 102 | defer self.deinitUtilityArrayList(stack); |
std/zig/tokenizer.zig+119-14| ... | @@ -68,9 +68,12 @@ pub const Token = struct { | ... | @@ -68,9 +68,12 @@ pub const Token = struct { |
| 68 | Invalid, | 68 | Invalid, |
| 69 | Identifier, | 69 | Identifier, |
| 70 | StringLiteral: StrLitKind, | 70 | StringLiteral: StrLitKind, |
| 71 | StringIdentifier, | ||
| 71 | Eof, | 72 | Eof, |
| 72 | Builtin, | 73 | Builtin, |
| 73 | Bang, | 74 | Bang, |
| 75 | Pipe, | ||
| 76 | PipeEqual, | ||
| 74 | Equal, | 77 | Equal, |
| 75 | EqualEqual, | 78 | EqualEqual, |
| 76 | BangEqual, | 79 | BangEqual, |
| ... | @@ -192,6 +195,7 @@ pub const Tokenizer = struct { | ... | @@ -192,6 +195,7 @@ pub const Tokenizer = struct { |
| 192 | StringLiteralBackslash, | 195 | StringLiteralBackslash, |
| 193 | Equal, | 196 | Equal, |
| 194 | Bang, | 197 | Bang, |
| 198 | Pipe, | ||
| 195 | Minus, | 199 | Minus, |
| 196 | Slash, | 200 | Slash, |
| 197 | LineComment, | 201 | LineComment, |
| ... | @@ -205,6 +209,7 @@ pub const Tokenizer = struct { | ... | @@ -205,6 +209,7 @@ pub const Tokenizer = struct { |
| 205 | Ampersand, | 209 | Ampersand, |
| 206 | Period, | 210 | Period, |
| 207 | Period2, | 211 | Period2, |
| 212 | SawAtSign, | ||
| 208 | }; | 213 | }; |
| 209 | 214 | ||
| 210 | pub fn next(self: &Tokenizer) Token { | 215 | pub fn next(self: &Tokenizer) Token { |
| ... | @@ -238,8 +243,7 @@ pub const Tokenizer = struct { | ... | @@ -238,8 +243,7 @@ pub const Tokenizer = struct { |
| 238 | result.id = Token.Id.Identifier; | 243 | result.id = Token.Id.Identifier; |
| 239 | }, | 244 | }, |
| 240 | '@' => { | 245 | '@' => { |
| 241 | state = State.Builtin; | 246 | state = State.SawAtSign; |
| 242 | result.id = Token.Id.Builtin; | ||
| 243 | }, | 247 | }, |
| 244 | '=' => { | 248 | '=' => { |
| 245 | state = State.Equal; | 249 | state = State.Equal; |
| ... | @@ -247,6 +251,9 @@ pub const Tokenizer = struct { | ... | @@ -247,6 +251,9 @@ pub const Tokenizer = struct { |
| 247 | '!' => { | 251 | '!' => { |
| 248 | state = State.Bang; | 252 | state = State.Bang; |
| 249 | }, | 253 | }, |
| 254 | '|' => { | ||
| 255 | state = State.Pipe; | ||
| 256 | }, | ||
| 250 | '(' => { | 257 | '(' => { |
| 251 | result.id = Token.Id.LParen; | 258 | result.id = Token.Id.LParen; |
| 252 | self.index += 1; | 259 | self.index += 1; |
| ... | @@ -313,6 +320,20 @@ pub const Tokenizer = struct { | ... | @@ -313,6 +320,20 @@ pub const Tokenizer = struct { |
| 313 | break; | 320 | break; |
| 314 | }, | 321 | }, |
| 315 | }, | 322 | }, |
| 323 | |||
| 324 | State.SawAtSign => switch (c) { | ||
| 325 | '"' => { | ||
| 326 | result.id = Token.Id.StringIdentifier; | ||
| 327 | state = State.StringLiteral; | ||
| 328 | }, | ||
| 329 | else => { | ||
| 330 | // reinterpret as a builtin | ||
| 331 | self.index -= 1; | ||
| 332 | state = State.Builtin; | ||
| 333 | result.id = Token.Id.Builtin; | ||
| 334 | }, | ||
| 335 | }, | ||
| 336 | |||
| 316 | State.Ampersand => switch (c) { | 337 | State.Ampersand => switch (c) { |
| 317 | '=' => { | 338 | '=' => { |
| 318 | result.id = Token.Id.AmpersandEqual; | 339 | result.id = Token.Id.AmpersandEqual; |
| ... | @@ -379,6 +400,18 @@ pub const Tokenizer = struct { | ... | @@ -379,6 +400,18 @@ pub const Tokenizer = struct { |
| 379 | }, | 400 | }, |
| 380 | }, | 401 | }, |
| 381 | 402 | ||
| 403 | State.Pipe => switch (c) { | ||
| 404 | '=' => { | ||
| 405 | result.id = Token.Id.PipeEqual; | ||
| 406 | self.index += 1; | ||
| 407 | break; | ||
| 408 | }, | ||
| 409 | else => { | ||
| 410 | result.id = Token.Id.Pipe; | ||
| 411 | break; | ||
| 412 | }, | ||
| 413 | }, | ||
| 414 | |||
| 382 | State.Equal => switch (c) { | 415 | State.Equal => switch (c) { |
| 383 | '=' => { | 416 | '=' => { |
| 384 | result.id = Token.Id.EqualEqual; | 417 | result.id = Token.Id.EqualEqual; |
| ... | @@ -510,9 +543,62 @@ pub const Tokenizer = struct { | ... | @@ -510,9 +543,62 @@ pub const Tokenizer = struct { |
| 510 | else => break, | 543 | else => break, |
| 511 | }, | 544 | }, |
| 512 | } | 545 | } |
| 513 | } | 546 | } else if (self.index == self.buffer.len) { |
| 514 | result.end = self.index; | 547 | switch (state) { |
| 548 | State.Start, | ||
| 549 | State.C, | ||
| 550 | State.IntegerLiteral, | ||
| 551 | State.IntegerLiteralWithRadix, | ||
| 552 | State.FloatFraction, | ||
| 553 | State.FloatExponentNumber, | ||
| 554 | State.StringLiteral, // find this error later | ||
| 555 | State.Builtin => {}, | ||
| 556 | |||
| 557 | State.Identifier => { | ||
| 558 | if (Token.getKeyword(self.buffer[result.start..self.index])) |id| { | ||
| 559 | result.id = id; | ||
| 560 | } | ||
| 561 | }, | ||
| 562 | State.LineComment => { | ||
| 563 | result.id = Token.Id.Eof; | ||
| 564 | }, | ||
| 565 | |||
| 566 | State.NumberDot, | ||
| 567 | State.FloatExponentUnsigned, | ||
| 568 | State.SawAtSign, | ||
| 569 | State.StringLiteralBackslash => { | ||
| 570 | result.id = Token.Id.Invalid; | ||
| 571 | }, | ||
| 515 | 572 | ||
| 573 | State.Equal => { | ||
| 574 | result.id = Token.Id.Equal; | ||
| 575 | }, | ||
| 576 | State.Bang => { | ||
| 577 | result.id = Token.Id.Bang; | ||
| 578 | }, | ||
| 579 | State.Minus => { | ||
| 580 | result.id = Token.Id.Minus; | ||
| 581 | }, | ||
| 582 | State.Slash => { | ||
| 583 | result.id = Token.Id.Slash; | ||
| 584 | }, | ||
| 585 | State.Zero => { | ||
| 586 | result.id = Token.Id.IntegerLiteral; | ||
| 587 | }, | ||
| 588 | State.Ampersand => { | ||
| 589 | result.id = Token.Id.Ampersand; | ||
| 590 | }, | ||
| 591 | State.Period => { | ||
| 592 | result.id = Token.Id.Period; | ||
| 593 | }, | ||
| 594 | State.Period2 => { | ||
| 595 | result.id = Token.Id.Ellipsis2; | ||
| 596 | }, | ||
| 597 | State.Pipe => { | ||
| 598 | result.id = Token.Id.Pipe; | ||
| 599 | }, | ||
| 600 | } | ||
| 601 | } | ||
| 516 | if (result.id == Token.Id.Eof) { | 602 | if (result.id == Token.Id.Eof) { |
| 517 | if (self.pending_invalid_token) |token| { | 603 | if (self.pending_invalid_token) |token| { |
| 518 | self.pending_invalid_token = null; | 604 | self.pending_invalid_token = null; |
| ... | @@ -520,6 +606,7 @@ pub const Tokenizer = struct { | ... | @@ -520,6 +606,7 @@ pub const Tokenizer = struct { |
| 520 | } | 606 | } |
| 521 | } | 607 | } |
| 522 | 608 | ||
| 609 | result.end = self.index; | ||
| 523 | return result; | 610 | return result; |
| 524 | } | 611 | } |
| 525 | 612 | ||
| ... | @@ -551,7 +638,7 @@ pub const Tokenizer = struct { | ... | @@ -551,7 +638,7 @@ pub const Tokenizer = struct { |
| 551 | } else { | 638 | } else { |
| 552 | // check utf8-encoded character. | 639 | // check utf8-encoded character. |
| 553 | const length = std.unicode.utf8ByteSequenceLength(c0) catch return 1; | 640 | const length = std.unicode.utf8ByteSequenceLength(c0) catch return 1; |
| 554 | if (self.index + length >= self.buffer.len) { | 641 | if (self.index + length > self.buffer.len) { |
| 555 | return u3(self.buffer.len - self.index); | 642 | return u3(self.buffer.len - self.index); |
| 556 | } | 643 | } |
| 557 | const bytes = self.buffer[self.index..self.index + length]; | 644 | const bytes = self.buffer[self.index..self.index + length]; |
| ... | @@ -632,15 +719,32 @@ test "tokenizer - illegal unicode codepoints" { | ... | @@ -632,15 +719,32 @@ test "tokenizer - illegal unicode codepoints" { |
| 632 | testTokenize("//\xe2\x80\xaa", []Token.Id{}); | 719 | testTokenize("//\xe2\x80\xaa", []Token.Id{}); |
| 633 | } | 720 | } |
| 634 | 721 | ||
| 722 | test "tokenizer - string identifier and builtin fns" { | ||
| 723 | testTokenize( | ||
| 724 | \\const @"if" = @import("std"); | ||
| 725 | , | ||
| 726 | []Token.Id{ | ||
| 727 | Token.Id.Keyword_const, | ||
| 728 | Token.Id.StringIdentifier, | ||
| 729 | Token.Id.Equal, | ||
| 730 | Token.Id.Builtin, | ||
| 731 | Token.Id.LParen, | ||
| 732 | Token.Id {.StringLiteral = Token.StrLitKind.Normal}, | ||
| 733 | Token.Id.RParen, | ||
| 734 | Token.Id.Semicolon, | ||
| 735 | } | ||
| 736 | ); | ||
| 737 | } | ||
| 738 | |||
| 739 | test "tokenizer - pipe and then invalid" { | ||
| 740 | testTokenize("||=", []Token.Id{ | ||
| 741 | Token.Id.Pipe, | ||
| 742 | Token.Id.PipeEqual, | ||
| 743 | }); | ||
| 744 | } | ||
| 745 | |||
| 635 | fn testTokenize(source: []const u8, expected_tokens: []const Token.Id) void { | 746 | fn testTokenize(source: []const u8, expected_tokens: []const Token.Id) void { |
| 636 | // (test authors, just make this bigger if you need it) | 747 | var tokenizer = Tokenizer.init(source); |
| 637 | var padded_source: [0x100]u8 = undefined; | ||
| 638 | std.mem.copy(u8, padded_source[0..source.len], source); | ||
| 639 | padded_source[source.len + 0] = '\n'; | ||
| 640 | padded_source[source.len + 1] = '\n'; | ||
| 641 | padded_source[source.len + 2] = '\n'; | ||
| 642 | |||
| 643 | var tokenizer = Tokenizer.init(padded_source[0..source.len + 3]); | ||
| 644 | for (expected_tokens) |expected_token_id| { | 748 | for (expected_tokens) |expected_token_id| { |
| 645 | const token = tokenizer.next(); | 749 | const token = tokenizer.next(); |
| 646 | std.debug.assert(@TagType(Token.Id)(token.id) == @TagType(Token.Id)(expected_token_id)); | 750 | std.debug.assert(@TagType(Token.Id)(token.id) == @TagType(Token.Id)(expected_token_id)); |
| ... | @@ -651,5 +755,6 @@ fn testTokenize(source: []const u8, expected_tokens: []const Token.Id) void { | ... | @@ -651,5 +755,6 @@ fn testTokenize(source: []const u8, expected_tokens: []const Token.Id) void { |
| 651 | else => {}, | 755 | else => {}, |
| 652 | } | 756 | } |
| 653 | } | 757 | } |
| 654 | std.debug.assert(tokenizer.next().id == Token.Id.Eof); | 758 | const last_token = tokenizer.next(); |
| 759 | std.debug.assert(last_token.id == Token.Id.Eof); | ||
| 655 | } | 760 | } |