1 /** 2 Copyright: Copyright (c) 2018-2019 Andrey Penechko. 3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 4 Authors: Andrey Penechko. 5 */ 6 7 module vox.context; 8 9 import std.stdio; 10 import std.string : format; 11 import vox.all; 12 13 enum BuildType : ubyte { 14 jit, 15 exe, 16 //dll 17 } 18 19 /// 20 class CompilationException : Exception 21 { 22 this(bool isICE, string file = __MODULE__, int line = __LINE__) 23 { 24 super(null, file, line); 25 this.isICE = isICE; 26 } 27 /// True if Internal Compiler Error and not regular compilation error 28 bool isICE; 29 } 30 31 /// 32 enum IceBehavior : ubyte { 33 exception, 34 error, 35 breakpoint 36 } 37 38 enum TargetOs : ubyte { 39 windows, 40 linux, 41 macos, 42 } 43 44 immutable string[] TARGET_OS_STRING = [ 45 "windows-x64", 46 "linux-x64", 47 "macos-x64", 48 ]; 49 50 /// 51 struct CompilationContext 52 { 53 auto c() { pragma(inline, true); return &this; } 54 55 // storage 56 57 /// Source file info storage 58 Arena!SourceFileInfo files; 59 /// Buffer for sources of all modules 60 Arena!char sourceBuffer; 61 /// Token buffer 62 Arena!TokenType tokenBuffer; 63 /// Token locations in source code 64 Arena!SourceLocation tokenLocationBuffer; 65 /// For AST nodes 66 Arena!uint astBuffer; 67 /// For arrays and hashmaps used in AST nodes 68 ArrayArena arrayArena; 69 /// Identifier interning/deduplication 70 IdentifierMap idMap; 71 // TODO: replace with arena. This one uses GC 72 TextSink tempBuf; 73 74 /// Buffer for intra-pass temporary data 75 Arena!uint tempBuffer; 76 /// Buffer for frame data of IR interpreter 77 Arena!ubyte vmBuffer; 78 /// Buffer for function IR generation 79 IrFuncStorage irStorage; 80 /// Type storage 81 IrTypeStorage types; 82 /// Global constant storage 83 IrConstantStorage constants; 84 /// Module global values and literals. 85 IrGlobalStorage globals; 86 87 /// Buffer for string/array/struct literals 88 /// String literals have \0 after last character 89 /// Must be allocated before or after code segment to allow relative addressing 90 /// Static read-only data 91 Arena!ubyte roStaticDataBuffer; 92 /// Static read-write data. zero-initialized data is stored after initialized data 93 Arena!ubyte staticDataBuffer; 94 uint zeroDataLength; 95 /// Buffer for resulting machine code 96 Arena!ubyte codeBuffer; 97 /// Buffer for indirect addresses when in JIT mode 98 /// Buffer for import section when in exe mode 99 Arena!ubyte importBuffer; 100 101 HashMap!(ExtraNodeProperty, uint, ExtraNodeProperty.init) extraProperties; 102 /// Vox modules and packages 103 HashMap!(Identifier, AstIndex, Identifier.init) modules; 104 105 /// External modules that are provided by driver or created at runtime from @extern(module) dll functions 106 HashMap!(Identifier, LinkIndex, Identifier.init) externalModules; 107 /// Symbols provided by the environment (host symbols must be provided prior to compilation) 108 /// Symbols imported from dll that are demanded by functions marked with @extern(module) 109 HashMap!(ExternalSymbolId, LinkIndex, ExternalSymbolId.init) externalSymbols; 110 /// Symbols, sections and references 111 ObjectSymbolTable objSymTab; 112 113 /// Buffer for output file generation (.exe) 114 Arena!ubyte binaryBuffer; 115 /// Buffer for output file generation (.har) 116 Arena!ubyte bundleBuffer; 117 118 // Stores astBuffer.length after initialize() call 119 // to be reset on beginCompilation() 120 private size_t initializedAstBufSize; 121 private size_t initializedIrTypeBufSize; // ditto, types.buffer.length 122 private size_t initializedSourceBufSize; // ditto, sourceBuffer.length 123 size_t initializedTokenLocBufSize; // ditto, tokenLocationBuffer.length 124 125 IrIndex i8PtrType; 126 IrIndex i64PtrType; 127 IrIndex v128Type; 128 129 // sections 130 LinkIndex[NUM_BUILTIN_SECTIONS] builtinSections; 131 132 // modules 133 LinkIndex builtinModuleIndex; 134 135 // errors and debug 136 137 Array!AnalysedNode analisysStack; 138 // Used for error message, when crashing in the backend 139 FunctionDeclNode* currentFunction; 140 141 /// 142 string outputFilename = "out.exe"; 143 144 /// Set when BuildType.exe is used 145 /// Set in CodeEmitter.compileFunction 146 FunctionDeclNode* entryPoint; 147 148 // build settings 149 150 /// Target machine info 151 MachineInfo* machineInfo = &mach_info_amd64; 152 /// Host OS 153 version(Windows) enum TargetOs hostOS = TargetOs.windows; 154 else version(linux) enum TargetOs hostOS = TargetOs.linux; 155 else version(OSX) enum TargetOs hostOS = TargetOs.macos; 156 else static assert(false, "Unhandled OS"); 157 /// Target OS 158 TargetOs targetOs = hostOS; 159 /// 160 BuildType buildType; 161 /// Build executable 162 WindowsSubsystem windowsSubsystem = WindowsSubsystem.WINDOWS_CUI; 163 /// 164 uint sectionAlignemnt = 512; 165 /// If true attempt to maximize debuggability 166 bool buildDebug = false; 167 /// 168 bool useFramePointer = false; 169 170 // Bitset of built-in version identifiers that are enabled 171 uint enabledVersionIdentifiers; 172 173 /// True if current/last pass had errors 174 bool hasErrors; 175 /// Text output for errors 176 TextSink errorSink; 177 /// Text output for errors and stack traces 178 TextSink sink; 179 /// If true, stack traces are added to output 180 bool printTraceOnError; 181 /// What happens on Internal Compiler Error 182 IceBehavior iceBehavior = IceBehavior.exception; 183 /// If true, every pass that generates/changes IR, performs validation 184 bool validateIr = false; 185 bool runTesters = true; 186 /// More details in errors 187 bool verboseErrors = false; 188 bool conciseErrors() { return !verboseErrors; } 189 190 bool printTodos = false; 191 /// Print source before lexing 192 bool printSource = false; 193 /// Print lexemes after lexing 194 bool printLexemes = false; 195 /// Print AST right after parsing 196 bool printAstFresh = false; 197 /// Print AST after semantic analysis 198 bool printAstSema = false; 199 /// Print IR after AST to IR pass 200 bool printIr = false; 201 /// Print IR after all IR lowering passes 202 /// Will not activate if printIrLowerEach is true 203 bool printIrLower = false; 204 /// Print IR after each IR lowering pass 205 bool printIrLowerEach = false; 206 /// Print IR after all optimization passes 207 /// Will not activate if printIrOptEach is true 208 bool printIrOpt = false; 209 /// Print IR after each optimization pass 210 bool printIrOptEach = false; 211 /// Print LIR after IR to LIR pass 212 bool printLir = false; 213 /// Print liveness analisys info 214 bool printLiveIntervals = false; 215 /// Print LIR after Register Allocation 216 bool printLirRA = false; 217 bool printStaticData = false; 218 bool printStackLayout = false; 219 bool printSymbols = false; 220 bool printCodeHex = false; 221 bool printTimings = false; 222 // limit number of regs for allocation 223 bool debugRegAlloc = false; 224 225 // Disables Dead Code Elimination 226 bool disableDCE = false; 227 // Disables inlining 228 bool disableInline = false; 229 230 // Don't output any files, but instead create a .har file containing all input files 231 bool bundleInputs; 232 233 Identifier printOnlyFun; 234 void setDumpFilter(string name) { printOnlyFun = idMap.getOrRegFqn(c, name); } 235 236 // Counters 237 uint numCtfeRuns = 0; 238 uint numTemplateInstanceLookups = 0; 239 uint numTemplateInstantiations = 0; 240 uint numLinesLexed = 0; 241 242 /// Check if printing of this function needed (including if all functions are requested) 243 bool printDumpOf(FunctionDeclNode* fun) { 244 if (printOnlyFun.isUndefined) return true; 245 if (printOnlyFun == fun.id) return true; 246 return false; 247 } 248 249 /// Check if printing of this function only is needed (not all functions) 250 bool printDumpOnlyOf(FunctionDeclNode* fun) { 251 return printOnlyFun == fun.id; 252 } 253 254 /// Check if printing of all functions requested 255 bool printDumpOfAll() { 256 return printOnlyFun.isUndefined; 257 } 258 259 const(char)[] getTokenString(TokenIndex tokenIndex) pure 260 { 261 return tokenLocationBuffer[tokenIndex].getTokenString(tokenBuffer[tokenIndex], sourceBuffer.data); 262 } 263 264 SourceLocation tokenLoc(TokenIndex tokenIndex) 265 { 266 return tokenLocationBuffer[tokenIndex]; 267 } 268 269 /// Only returns self string 270 string idString(const Identifier id) { return idMap.get(id); } 271 272 AstIndex basicTypeNodes(BasicType basicType) { 273 return basicTypesArray[basicType]; 274 } 275 AstIndex builtinNodes(BuiltinId builtinId) { 276 return builtinsArray[builtinId]; 277 } 278 279 CallConvention defaultCallConvention() { 280 final switch(targetOs) { 281 case TargetOs.windows: return CallConvention.win64; 282 case TargetOs.linux: return CallConvention.sysv64; 283 case TargetOs.macos: return CallConvention.sysv64; 284 } 285 } 286 287 void error(Args...)(TokenIndex tokIdx, string format, Args args) 288 { 289 size_t startLen = sink.data.length; 290 sink.putf("%s: Error: ", FmtSrcLoc(tokIdx, c)); 291 sink.putfln(format, args); 292 errorSink.put(sink.data[startLen..$]); 293 if (printTraceOnError) 294 try 295 throw new Exception(null); 296 catch (Exception e) 297 sink.putf("%s", e.info); 298 hasErrors = true; 299 } 300 301 void error(Args...)(string format, Args args) 302 { 303 size_t startLen = sink.data.length; 304 sink.put("Error: "); 305 sink.putfln(format, args); 306 errorSink.put(sink.data[startLen..$]); 307 if (printTraceOnError) 308 try 309 throw new Exception(null); 310 catch (Exception e) 311 sink.putf("%s", e.info); 312 hasErrors = true; 313 } 314 315 noreturn unrecoverable_error(Args...)(TokenIndex tokIdx, string format, Args args) 316 { 317 size_t startLen = sink.data.length; 318 sink.putf("%s: Error: ", FmtSrcLoc(tokIdx, c)); 319 sink.putfln(format, args); 320 errorSink.put(sink.data[startLen..$]); 321 if (printTraceOnError) 322 try 323 throw new Exception(null); 324 catch (Exception e) 325 sink.putf("%s", e.info); 326 hasErrors = true; 327 throw new CompilationException(false); 328 } 329 330 void assertf(Args...)(bool cond, string fmt, Args args, string file = __MODULE__, int line = __LINE__) 331 { 332 if (cond) return; 333 334 auto ice_state = begin_ice(file, line); 335 sink.putfln(fmt, args); 336 end_ice(ice_state); 337 } 338 339 void assertf(Args...)(bool cond, TokenIndex tokIdx, string fmt, Args args, string file = __MODULE__, int line = __LINE__) 340 { 341 if (cond) return; 342 343 auto ice_state = begin_ice(file, line); 344 sink.putfln(fmt, args); 345 end_ice(ice_state, tokIdx); 346 } 347 348 noreturn unreachable(string file = __MODULE__, int line = __LINE__) 349 { 350 auto ice_state = begin_ice(file, line); 351 sink.putfln("Unreachable"); 352 end_ice(ice_state); 353 } 354 355 noreturn internal_error(Args...)(TokenIndex tokIdx, string format, Args args, string file = __MODULE__, int line = __LINE__) 356 { 357 auto ice_state = begin_ice(file, line); 358 sink.putfln(format, args); 359 end_ice(ice_state, tokIdx); 360 } 361 362 noreturn internal_error(Args...)(string format, Args args, string file = __MODULE__, int line = __LINE__) 363 { 364 auto ice_state = begin_ice(file, line); 365 sink.putfln(format, args); 366 end_ice(ice_state); 367 } 368 369 void begin_node_property_calculation(T)(T* node, NodeProperty prop) 370 if (hasAstNodeType!T) 371 { 372 AstIndex nodeIndex = getAstNodeIndex(node); 373 node.setPropertyState(prop, PropertyState.calculating); 374 push_analized_node(AnalysedNode(nodeIndex, prop)); 375 } 376 377 void end_node_property_calculation(T)(T* node, NodeProperty prop) 378 if (hasAstNodeType!T) 379 { 380 node.setPropertyState(prop, PropertyState.calculated); 381 pop_analized_node; 382 } 383 384 void push_analized_node(AnalysedNode item) { 385 analisysStack.put(arrayArena, item); 386 } 387 388 void pop_analized_node() { 389 assertf(!analisysStack.empty, "Excessive popping detected"); 390 analisysStack.unput(1); 391 } 392 393 noreturn circular_dependency(AstIndex nodeIndex, NodeProperty prop, string file = __MODULE__, int line = __LINE__) 394 { 395 push_analized_node(AnalysedNode(nodeIndex, prop)); 396 circular_dependency(file, line); 397 } 398 399 noreturn circular_dependency(string file = __MODULE__, int line = __LINE__) 400 { 401 size_t startLen = sink.data.length; 402 sink.putfln("Error: Circular dependency"); 403 print_analysis_stack; 404 if (printTraceOnError) 405 try 406 throw new Exception(null); 407 catch (Exception e) 408 sink.putf("%s", e.info); 409 errorSink.put(sink.data[startLen..$]); 410 hasErrors = true; 411 throw new CompilationException(false, file, line); 412 } 413 414 private static struct IceState { 415 size_t startLen; 416 string file; 417 int line; 418 } 419 420 private IceState begin_ice(string file, int line) 421 { 422 stdout.flush; 423 424 size_t startLen = sink.data.length; 425 sink.putf("%s:%s: ICE: ", file, line); 426 return IceState(startLen, file, line); 427 } 428 429 private noreturn end_ice(IceState state, TokenIndex tokIdx = TokenIndex.init) 430 { 431 print_location(tokIdx); 432 errorSink.put(sink.data[state.startLen..$]); 433 hasErrors = true; 434 handleICE(state.file, state.line); 435 } 436 437 private void print_location(TokenIndex tokIdx = TokenIndex.init) 438 { 439 if (tokIdx.isValid) { 440 sink.putfln("- token %s", FmtSrcLoc(tokIdx, c)); 441 } 442 if (currentFunction) { 443 sink.putfln("- module `%s`", currentFunction._module.get!ModuleDeclNode(c).fqn.pr(c)); 444 sink.putfln("- function `%s`", currentFunction.id.pr(c)); 445 sink.putfln(" - defined at %s", FmtSrcLoc(currentFunction.loc, c)); 446 } 447 print_analysis_stack; 448 } 449 450 private void print_analysis_stack() 451 { 452 if (analisysStack.empty) return; 453 454 sink.putfln("Stack:"); 455 456 AnalysedNode top = analisysStack.back; 457 458 while(!analisysStack.empty) 459 { 460 AnalysedNode currentItem = analisysStack.back; 461 TokenIndex tokIdx = currentItem.nodeIndex.loc(c); 462 if (currentItem.nodeIndex == top.nodeIndex) sink.put("> "); 463 else sink.put(" "); 464 sink.putf("%s: node.%s %s %s ", FmtSrcLoc(tokIdx, c), currentItem.nodeIndex.storageIndex, currentItem.prop, currentItem.nodeIndex.astType(c)); 465 print_node_name(sink, currentItem.nodeIndex, c); 466 sink.putln; 467 analisysStack.unput(1); 468 } 469 } 470 471 void todo(Args...)(string format, Args args, string file = __MODULE__, int line = __LINE__) 472 { 473 if (printTodos) { 474 writef("TODO(%s:%s): ", file, line); 475 writefln(format, args); 476 } 477 } 478 479 private noreturn handleICE(string file, int line) 480 { 481 final switch(iceBehavior) 482 { 483 case IceBehavior.exception: throw new CompilationException(true, file, line); 484 case IceBehavior.error: assert(false); 485 case IceBehavior.breakpoint: 486 writeln(sink.text); 487 stdout.flush; 488 version(D_InlineAsm_X86_64) { 489 asm nothrow @nogc { int 3; } // breakpoint 490 assert(false); 491 } else version(LDC) { 492 import ldc.intrinsics: llvm_debugtrap; 493 llvm_debugtrap(); 494 } else { 495 assert(false); 496 } 497 } 498 } 499 500 void throwOnErrors(string file = __MODULE__, int line = __LINE__) 501 { 502 if (hasErrors) throw new CompilationException(false, file, line); 503 } 504 505 IrVmSlotInfo pushVmStack(uint numBytes) 506 { 507 IrVmSlotInfo result; 508 result.offset = vmBuffer.uintLength; 509 result.length = numBytes; 510 vmBuffer.voidPut(numBytes); 511 //writefln("pushVmStack %s %s", result, vmBuffer.uintLength); 512 return result; 513 } 514 515 void popVmStack(IrVmSlotInfo slot) 516 { 517 //writefln("popVmStack %s %s", slot, vmBuffer.uintLength); 518 vmBuffer.unput(slot.length); 519 assertf(slot.offset == vmBuffer.uintLength, 520 "popped item is in the middle of the stack"); 521 } 522 523 IrIndex appendTemp(T)(uint howMany = 1) 524 { 525 static assert(T.alignof <= 4, "Can only store types aligned to 4 bytes"); 526 527 IrIndex result; 528 result.storageUintIndex = tempBuffer.uintLength; 529 result.kind = getIrValueKind!T; 530 531 size_t numAllocatedSlots = divCeil(T.sizeof, uint.sizeof)*howMany; 532 tempBuffer.voidPut(numAllocatedSlots); 533 534 (&getTemp!T(result))[0..howMany] = T.init; 535 return result; 536 } 537 538 ref T getTemp(T)(IrIndex index) 539 { 540 assert(index.kind != IrValueKind.none, "null index"); 541 assert(index.kind == getIrValueKind!T, format("%s != %s", index.kind, getIrValueKind!T)); 542 return *cast(T*)(&tempBuffer.bufPtr[index.storageUintIndex]); 543 } 544 545 T[] allocateTempArray(T)(uint howMany) 546 { 547 static assert(T.sizeof % uint.sizeof == 0, "T.sizeof is not multiple of uint.sizeof"); 548 //static assert(T.alignof == 4, "Can only store types aligned to 4 bytes"); 549 550 size_t numAllocatedSlots = divCeil(T.sizeof, uint.sizeof)*howMany; 551 T[] result = cast(T[])tempBuffer.voidPut(numAllocatedSlots); 552 result[] = T.init; 553 return result; 554 } 555 556 void freeTempArray(T)(T[] array) 557 { 558 static assert(T.sizeof % uint.sizeof == 0, "T.sizeof is not multiple of uint.sizeof"); 559 static assert(T.alignof == 4, "Can only store types aligned to 4 bytes"); 560 uint[] buf = cast(uint[])array; 561 tempBuffer.free(buf); 562 } 563 564 AstIndex appendAst(T, Args...)(Args args) { 565 uint resIndex = astBuffer.uintLength; 566 T* obj = cast(T*)astBuffer.nextPtr; 567 enum size_t numAllocatedSlots = divCeil(T.sizeof, uint.sizeof); 568 astBuffer.voidPut(numAllocatedSlots); 569 *obj = T(args); 570 return AstIndex(resIndex); 571 } 572 573 T* getAst(T)(AstIndex index) { 574 //assert(index, "node is null"); 575 if (!index) return null; 576 T* result = cast(T*)(&astBuffer.bufPtr[index.storageIndex]); 577 static if (hasAstNodeType!T) 578 { 579 assertf(result.astType == getAstNodeType!T, "getAst(%s) got %s", T.stringof, result.astType); 580 } 581 return result; 582 } 583 584 AstIndex getAstNodeIndex(T)(T* node) { 585 assert(node, "node is null"); 586 uint* ptr = cast(uint*)node; 587 ptrdiff_t diff = ptr - astBuffer.bufPtr; 588 assert(diff > 0, "<= 0"); 589 assert(diff < astBuffer.length, "> length"); 590 return AstIndex(cast(uint)diff); 591 } 592 593 ScopeIndex appendScope() { 594 uint resIndex = astBuffer.uintLength; 595 Scope* obj = cast(Scope*)astBuffer.nextPtr; 596 enum size_t numAllocatedSlots = divCeil(Scope.sizeof, uint.sizeof); 597 astBuffer.voidPut(numAllocatedSlots); 598 *obj = Scope.init; 599 return ScopeIndex(resIndex); 600 } 601 602 Scope* getAstScope(ScopeIndex index) { 603 if (!index) return null; 604 return cast(Scope*)(&astBuffer.bufPtr[index.storageIndex]); 605 } 606 AstNode* getAstNode(AstIndex index) { return getAst!AstNode(index); } 607 TypeNode* getAstType(AstIndex index) { 608 assertf(index.isDefined, "getAstType: null index"); 609 TypeNode* t = getAst!TypeNode(index); 610 assertf(t.isType, t.loc, "node is not a type: %s", t.astType); 611 return t; 612 } 613 ExpressionNode* getAstExpr(AstIndex index) { return getAst!ExpressionNode(index); } 614 615 SourceFileInfo* getFileFromToken(TokenIndex tokIndex) { 616 assert(tokIndex < tokenBuffer.length, format("getFileFromToken(%s), numTokens %s", tokIndex, tokenBuffer.length)); 617 618 SourceFileInfo* lastFile; 619 foreach(ref SourceFileInfo file; files.data) 620 { 621 // We are parsing and this module is not parsed yet, so it's previous one 622 if (!file.firstTokenIndex.isValid) break; 623 624 if (tokIndex < file.firstTokenIndex) { 625 assertf(lastFile !is null, 626 "Cannot find file of token %s, before first file starting at %s", 627 tokIndex, file.firstTokenIndex); 628 return lastFile; 629 } 630 lastFile = &file; 631 } 632 if (lastFile is null) { 633 internal_error("Cannot find file of token %s, no files", tokIndex); 634 } 635 return lastFile; 636 } 637 638 // Checks if symbol can be accessed from code segment with 32bit signed offset 639 private bool canReferenceFromCode(void* hostSym) 640 { 641 void* start = codeBuffer.bufPtr; 642 void* end = codeBuffer.bufPtr + codeBuffer.length; 643 bool reachesFromStart = (hostSym - start) == cast(int)(hostSym - start); 644 bool reachesFromEnd = (hostSym - end) == cast(int)(hostSym - end); 645 return reachesFromStart && reachesFromEnd; 646 } 647 648 /// Returns index of external (host or dll) module 649 LinkIndex getOrCreateExternalModule(Identifier modId, ObjectModuleKind modKind) { 650 LinkIndex externalModuleIndex = externalModules.get(modId); 651 if (externalModuleIndex.isDefined) return externalModuleIndex; 652 653 ObjectModule externalModule = { 654 kind : modKind, 655 id : modId 656 }; 657 externalModuleIndex = objSymTab.addModule(externalModule); 658 externalModules.put(arrayArena, modId, externalModuleIndex); 659 660 return externalModuleIndex; 661 } 662 663 // Automatically choses to use direct referencing or to use import table to access symbol 664 // Adds to external symbol table 665 LinkIndex addHostSymbol(LinkIndex hostModuleIndex, Identifier symId, void* symPtr) 666 { 667 LinkIndex symIndex; 668 if (canReferenceFromCode(symPtr)) 669 symIndex = addHostSymbolDirect(hostModuleIndex, symId, symPtr); 670 else 671 symIndex = addHostSymbolIndirect(hostModuleIndex, symId, symPtr); 672 673 registerExternalSymbol(hostModuleIndex, symId, symIndex); 674 675 return symIndex; 676 } 677 678 // Force host symbol to be accessed directly 679 private LinkIndex addHostSymbolDirect(LinkIndex hostModuleIndex, Identifier symId, void* symPtr) 680 { 681 ObjectSymbol sym = { 682 kind : ObjectSymbolKind.isHost, 683 id : symId, 684 dataPtr : cast(ubyte*)symPtr, 685 sectionOffset : cast(ulong)symPtr, 686 sectionIndex : builtinSections[ObjectSectionType.host], 687 moduleIndex : hostModuleIndex, 688 }; 689 return objSymTab.addSymbol(sym); 690 } 691 692 // Force host symbol to be accessed through import table 693 private LinkIndex addHostSymbolIndirect(LinkIndex hostModuleIndex, Identifier symId, void* symPtr) 694 { 695 ulong sectionOffset = importBuffer.length; 696 ubyte* dataPtr = importBuffer.nextPtr; 697 size_t ptr = cast(size_t)symPtr; 698 importBuffer.put(*cast(ubyte[size_t.sizeof]*)&ptr); 699 700 ObjectSymbol sym = { 701 kind : ObjectSymbolKind.isHost, 702 flags : ObjectSymbolFlags.isIndirect | ObjectSymbolFlags.isPointer, 703 id : symId, 704 dataPtr : dataPtr, 705 length : size_t.sizeof, 706 sectionOffset : sectionOffset, 707 sectionIndex : builtinSections[ObjectSectionType.imports], 708 moduleIndex : hostModuleIndex, 709 }; 710 return objSymTab.addSymbol(sym); 711 } 712 713 private void registerExternalSymbol(LinkIndex moduleIndex, Identifier symId, LinkIndex symIndex) 714 { 715 Identifier modId = objSymTab.getModule(moduleIndex).id; 716 externalSymbols.put(arrayArena, ExternalSymbolId(modId, symId), symIndex); 717 } 718 719 LinkIndex addDllModuleSymbol(LinkIndex dllModuleIndex, Identifier symId) 720 { 721 ObjectSymbol importedSymbol = { 722 kind : ObjectSymbolKind.isImported, 723 flags : ObjectSymbolFlags.isIndirect | ObjectSymbolFlags.isPointer, 724 id : symId, 725 alignmentPower : 3, // pointer size 726 sectionIndex : builtinSections[ObjectSectionType.imports], 727 moduleIndex : dllModuleIndex, 728 }; 729 LinkIndex importedSymbolIndex = objSymTab.addSymbol(importedSymbol); 730 Identifier modId = objSymTab.getModule(dllModuleIndex).id; 731 externalSymbols.put(arrayArena, ExternalSymbolId(modId, symId), importedSymbolIndex); 732 return importedSymbolIndex; 733 } 734 735 ModuleDeclNode* getModuleFromToken(TokenIndex tokIndex) { 736 return getFileFromToken(tokIndex).mod; 737 } 738 739 ModuleDeclNode* getModule(ModuleIndex index) { 740 return files[index.fileIndex].mod; 741 } 742 743 FunctionDeclNode* findFunctionImpl(bool err)(Identifier funcId) { 744 static FunctionDeclNode* noMod(Identifier funcId, CompilationContext* c) { 745 static if (err) c.internal_error("Cannot find function `%s`. No module was specified", funcId.pr(c)); 746 else return null; 747 } 748 749 static FunctionDeclNode* missingPack(bool isMod, Identifier modId, Identifier funcId, CompilationContext* c) { 750 static if (err) c.internal_error("Cannot find function `%s`. Cannot find %s `%s`", 751 funcId.pr(c), 752 isMod ? "module" : "package", 753 modId.pr(c)); 754 else return null; 755 } 756 757 static FunctionDeclNode* wrongType(bool isMod, Identifier modId, Identifier funcId, CompilationContext* c) { 758 static if (err) c.internal_error("Cannot find function `%s`. `%s` is a %s", 759 funcId.pr(c), modId.pr(c), 760 isMod ? "module" : "package"); 761 else return null; 762 } 763 764 static FunctionDeclNode* missingFunc(Identifier modId, Identifier funcId, CompilationContext* c) { 765 static if (err) c.internal_error("Cannot find function `%s` in module `%s`", 766 funcId.pr(c), modId.pr(c)); 767 else return null; 768 } 769 770 if (!funcId.hasParent) return noMod(funcId, c); 771 772 Identifier parentId = funcId.getParent(c); 773 AstIndex subpackageIndex = modules.get(parentId, AstIndex.init); 774 if (subpackageIndex.isUndefined) return missingPack(true, parentId, funcId, c); 775 auto subpackage_node = subpackageIndex.get_node(c); 776 if (subpackage_node.astType != AstType.decl_module) return wrongType(false, parentId, funcId, c); 777 ModuleDeclNode* mod = subpackage_node.as!ModuleDeclNode(c); 778 779 auto fun = mod.tryFindFunction(funcId.getSelf(c), c); 780 if (fun is null) return missingFunc(parentId, funcId, c); 781 return fun; 782 } 783 alias findFunction = findFunctionImpl!true; 784 alias tryFindFunction = findFunctionImpl!false; 785 786 FunctionDeclNode* getFunction(IrIndex index) 787 { 788 assertf(index.isFunction, "index is %s", index); 789 AstIndex astIndex = AstIndex(index.storageUintIndex); 790 return getAst!FunctionDeclNode(astIndex); 791 } 792 793 FunctionDeclNode* findUniquelyNamedFunction(Identifier funcId) 794 { 795 FunctionDeclNode* funDecl; 796 if (funcId.hasParent) { 797 funDecl = findFunction(funcId); 798 } else { 799 foreach (ref SourceFileInfo file; files.data) 800 { 801 FunctionDeclNode* fun = file.mod.tryFindFunction(funcId, c); 802 if (fun !is null) 803 { 804 if (funDecl !is null) 805 internal_error("Function %s is found in 2 places", funcId.pr(c)); 806 funDecl = fun; 807 } 808 } 809 810 if (funDecl is null) 811 internal_error("Function `%s` is not found in %s modules", funcId.pr(c), files.length); 812 } 813 814 return funDecl; 815 } 816 817 FunctionDeclNode* tryFindUniquelyNamedFunction(Identifier funcId) 818 { 819 FunctionDeclNode* funDecl; 820 if (funcId.hasParent) { 821 return tryFindFunction(funcId); 822 } 823 824 foreach (ref SourceFileInfo file; files.data) 825 { 826 FunctionDeclNode* fun = file.mod.tryFindFunction(funcId, c); 827 if (fun !is null) 828 { 829 if (funDecl !is null) 830 internal_error("Function %s is found in 2 places", funcId.pr(c)); 831 funDecl = fun; 832 } 833 } 834 835 return funDecl; 836 } 837 838 auto getFunctionPtr(ResultType, ParamTypes...)(FunctionDeclNode* funcDecl) 839 { 840 // TODO: check that passed D types match retrieved function signature 841 //assert(funcDecl.returnType.isSameTypeAs!ParamType, "wrong result type"); 842 843 auto numRequestedParams = ParamTypes.length; 844 auto numParams = funcDecl.signature.get!FunctionSignatureNode(c).parameters.length; 845 846 Identifier funcId = funcDecl.id; 847 848 if (numRequestedParams < numParams) 849 internal_error("Insufficient parameters to '%s', got %s, expected %s", 850 funcId.pr(c), numRequestedParams, numParams); 851 else if (numRequestedParams > numParams) 852 internal_error("Too much parameters to '%s', got %s, expected %s", 853 funcId.pr(c), numRequestedParams, numParams); 854 855 //foreach(i, ParamType; ParamTypes) 856 //{ 857 // assert(funcDecl.parameters[i].type.isSameTypeAs!ParamType, "wrong param type"); 858 //} 859 860 alias JittedFunc = extern(C) ResultType function(ParamTypes); 861 ObjectSymbol* funcSym = objSymTab.getSymbol(funcDecl.backendData.objectSymIndex); 862 return cast(JittedFunc)funcSym.dataPtr; 863 } 864 865 IrIndex get_file_name_constant(AstIndex mod) { 866 auto node = mod.get!ModuleDeclNode(c); 867 bool wasCreated; 868 auto key = ExtraNodeProperty(ExtraProperty.fileName, mod.storageIndex); 869 uint* value = extraProperties.getOrCreate(arrayArena, key, wasCreated); 870 if (wasCreated) { 871 IrIndex val = makeStringLiteralIrConstant(node.fileName(c), node.objectSymIndex, c); 872 *value = val.asUint; 873 } 874 return IrIndex.fromUint(*value); 875 } 876 IrIndex get_function_name_constant(AstIndex func) { 877 auto node = func.get!FunctionDeclNode(c); 878 bool wasCreated; 879 auto key = ExtraNodeProperty(ExtraProperty.nodeName, func.storageIndex); 880 uint* value = extraProperties.getOrCreate(arrayArena, key, wasCreated); 881 if (wasCreated) { 882 IrIndex val = makeStringLiteralIrConstant(idString(node.id), node._module.get!ModuleDeclNode(c).objectSymIndex, c); 883 *value = val.asUint; 884 } 885 return IrIndex.fromUint(*value); 886 } 887 IrIndex get_module_name_constant(AstIndex mod) { 888 auto node = mod.get!ModuleDeclNode(c); 889 bool wasCreated; 890 auto key = ExtraNodeProperty(ExtraProperty.nodeName, mod.storageIndex); 891 uint* value = extraProperties.getOrCreate(arrayArena, key, wasCreated); 892 if (wasCreated) { 893 IrIndex val = makeStringLiteralIrConstant(idString(node.fqn), node.objectSymIndex, c); 894 *value = val.asUint; 895 } 896 return IrIndex.fromUint(*value); 897 } 898 899 void printMemSize() { 900 TextSink sink; 901 printMemSize(sink); 902 write(cast(string)sink.data.data); 903 } 904 void printMemSize(ref TextSink sink) 905 { 906 size_t byteLength; 907 size_t committedBytes; 908 size_t reservedBytes; 909 sink.putfln("Arena sizes: used committed reserved"); 910 void printArena(A)(ref A arena, string name) { 911 sink.putfln(" %-16s%-6iB %-6iB %-6iB", 912 name, 913 scaledNumberFmt(arena.byteLength), 914 scaledNumberFmt(arena.committedBytes), 915 scaledNumberFmt(arena.reservedBytes)); 916 byteLength += arena.byteLength; 917 committedBytes += arena.committedBytes; 918 reservedBytes += arena.reservedBytes; 919 } 920 printArena(sourceBuffer, "source"); 921 printArena(files, "files"); 922 printArena(tokenBuffer, "tokens"); 923 printArena(tokenLocationBuffer, "token loc"); 924 printArena(astBuffer, "AST"); 925 printArena(arrayArena, "arrays"); 926 927 printArena(irStorage.instrHeaderBuffer, "IR instr header"); 928 printArena(irStorage.instrPayloadBuffer, "IR instr payload"); 929 printArena(irStorage.instrNextBuffer, "IR next ptr"); 930 printArena(irStorage.instrPrevBuffer, "IR prev ptr"); 931 printArena(irStorage.vregBuffer, "IR virt regs"); 932 printArena(irStorage.phiBuffer, "IR phi"); 933 printArena(irStorage.basicBlockBuffer, "IR basic blocks"); 934 printArena(irStorage.arrayBuffer, "IR arrays"); 935 printArena(irStorage.stackSlotBuffer, "IR stack slots"); 936 irStorage.printMemSize(sink); 937 938 printArena(vmBuffer, "vm"); 939 printArena(tempBuffer, "temp"); 940 printArena(types.buffer, "types"); 941 printArena(staticDataBuffer, "static RW data"); 942 printArena(roStaticDataBuffer, "static RO data"); 943 printArena(globals.buffer, "globals"); 944 printArena(globals.initializerBuffer, "global ini-rs"); 945 printArena(constants.buffer, "constants"); 946 printArena(constants.aggregateBuffer, "aggregates"); 947 printArena(importBuffer, "imports"); 948 printArena(objSymTab.buffer, "symbols"); 949 printArena(codeBuffer, "machine code"); 950 printArena(binaryBuffer, "binary"); 951 printArena(bundleBuffer, "bundle"); 952 953 sink.putfln(" %-16s%-6iB %-6iB %-6iB", 954 " Total", 955 scaledNumberFmt(byteLength), 956 scaledNumberFmt(committedBytes), 957 scaledNumberFmt(reservedBytes)); 958 } 959 960 void initialize() 961 { 962 // populates idMap with common identifiers like this, length, ptr, min, max, sizeof... 963 idMap.regCommonIds(c); 964 965 // Next we create ast node per CommonAstNodes entry. Make sure the order is the same 966 967 // CommonAstNodes.undefined 968 astBuffer.voidPut(1); // 0th slot is reserved for undefined index 969 970 // CommonAstNodes.node_error 971 AstIndex node_error = appendAst!ErrorAstNode(); 972 assertf(node_error == CommonAstNodes.node_error, "AstIndex mismatch for node_error %s != %s", node_error, cast(AstIndex)CommonAstNodes.node_error); 973 974 // CommonAstNodes.node_root_package 975 AstIndex node_root_package = appendAst!PackageDeclNode(); 976 assertf(node_root_package == CommonAstNodes.node_root_package, "AstIndex mismatch for node_root_package %s != %s", node_root_package, cast(AstIndex)CommonAstNodes.node_root_package); 977 978 // add basic types 979 void makeBasic(AstIndex reqIndex, uint size, ubyte alignPow, ulong minValue, ulong maxValue, BasicType basicType, int typeFlags = 0) 980 { 981 uint startPos = sourceBuffer.uintLength; 982 string str = basicTypeNames[basicType]; 983 uint endPos = cast(uint)(startPos + str.length); 984 sourceBuffer.put(str); 985 TokenIndex tokIndex = TokenIndex(tokenLocationBuffer.uintLength); 986 tokenLocationBuffer.put(SourceLocation(startPos, endPos, 0, 0)); 987 tokenBuffer.voidPut(1); // bump token buf too 988 989 // we want the index returned from appendAst to be equal to reqIndex 990 // because we have CommonAstNodes enum 991 AstIndex index = appendAst!BasicTypeNode(tokIndex, CommonAstNodes.type_type, SizeAndAlignment(size, alignPow), minValue, maxValue, basicType, cast(ubyte)typeFlags); 992 assertf(index == reqIndex, 993 "Result AstIndex of basic type %s (%s) is not equal to required (%s). Creation order must match CommonAstNodes order", 994 basicType, index, reqIndex); 995 } 996 997 // type nodes 998 makeBasic(CommonAstNodes.type_error, 0, 0, 0, 0, BasicType.t_error); 999 makeBasic(CommonAstNodes.type_auto, 0, 0, 0, 0, BasicType.t_auto); 1000 makeBasic(CommonAstNodes.type_noreturn, 0, 0, 0, 0, BasicType.t_noreturn); 1001 makeBasic(CommonAstNodes.type_void, 0, 0, 0, 0, BasicType.t_void); 1002 makeBasic(CommonAstNodes.type_bool, 1, 0, 0, 1, BasicType.t_bool , BasicTypeFlag.isBoolean); 1003 makeBasic(CommonAstNodes.type_null, 8, 3, 0, 0, BasicType.t_null); 1004 1005 // basic type nodes 1006 makeBasic(CommonAstNodes.type_i8, 1, 0, byte.min, byte.max, BasicType.t_i8, BasicTypeFlag.isInteger | BasicTypeFlag.isSigned); 1007 makeBasic(CommonAstNodes.type_i16, 2, 1, short.min, short.max, BasicType.t_i16, BasicTypeFlag.isInteger | BasicTypeFlag.isSigned); 1008 makeBasic(CommonAstNodes.type_i32, 4, 2, int.min, int.max, BasicType.t_i32, BasicTypeFlag.isInteger | BasicTypeFlag.isSigned); 1009 makeBasic(CommonAstNodes.type_i64, 8, 3, long.min, long.max, BasicType.t_i64, BasicTypeFlag.isInteger | BasicTypeFlag.isSigned); 1010 1011 makeBasic(CommonAstNodes.type_u8, 1, 0, ubyte.min, ubyte.max, BasicType.t_u8, BasicTypeFlag.isInteger); 1012 makeBasic(CommonAstNodes.type_u16, 2, 1, ushort.min, ushort.max, BasicType.t_u16, BasicTypeFlag.isInteger); 1013 makeBasic(CommonAstNodes.type_u32, 4, 2, uint.min, uint.max, BasicType.t_u32, BasicTypeFlag.isInteger); 1014 makeBasic(CommonAstNodes.type_u64, 8, 3, ulong.min, ulong.max, BasicType.t_u64, BasicTypeFlag.isInteger); 1015 1016 makeBasic(CommonAstNodes.type_f32, 4, 2, 0, 0, BasicType.t_f32, BasicTypeFlag.isFloat); 1017 makeBasic(CommonAstNodes.type_f64, 8, 3, 0, 0, BasicType.t_f64, BasicTypeFlag.isFloat); 1018 1019 makeBasic(CommonAstNodes.type_alias, 4, 2, uint.min, uint.max, BasicType.t_alias); 1020 makeBasic(CommonAstNodes.type_type, 4, 2, uint.min, uint.max, BasicType.t_type); 1021 1022 // custom types 1023 auto type_u8Ptr = appendAst!PtrTypeNode(TokenIndex(), CommonAstNodes.type_type, CommonAstNodes.type_u8); 1024 assertf(type_u8Ptr == CommonAstNodes.type_u8Ptr, "AstIndex mismatch for type_u8Ptr %s != %s", type_u8Ptr, cast(AstIndex)CommonAstNodes.type_u8Ptr); 1025 type_u8Ptr.gen_ir_type(c); // we need to cache IR types too 1026 1027 auto type_u8Slice = appendAst!SliceTypeNode(TokenIndex(), CommonAstNodes.type_type, CommonAstNodes.type_u8); 1028 assertf(type_u8Slice == CommonAstNodes.type_u8Slice, "AstIndex mismatch for type_u8Slice %s != %s", type_u8Slice, cast(AstIndex)CommonAstNodes.type_u8Slice); 1029 type_u8Slice.gen_ir_type(c); // we need to cache IR types too 1030 1031 auto type_aliasSlice = appendAst!SliceTypeNode(TokenIndex(), CommonAstNodes.type_type, CommonAstNodes.type_alias); 1032 assertf(type_aliasSlice == CommonAstNodes.type_aliasSlice, "AstIndex mismatch for type_aliasSlice %s != %s", type_aliasSlice, cast(AstIndex)CommonAstNodes.type_aliasSlice); 1033 type_aliasSlice.gen_ir_type(c); // we need to cache IR types too 1034 1035 // builtin nodes 1036 void makeBuiltin(AstIndex reqIndex, Identifier id, BuiltinId builtin) { 1037 AstIndex index = appendAst!BuiltinNode(TokenIndex(), id, builtin); 1038 assertf(index == reqIndex, 1039 "Result AstIndex of builtin node %s (%s) is not equal to required (%s). Creation order must match CommonAstNodes order", 1040 id.pr(c), index, reqIndex); 1041 } 1042 1043 makeBuiltin(CommonAstNodes.builtin_min, CommonIds.id_min, BuiltinId.int_min); 1044 makeBuiltin(CommonAstNodes.builtin_max, CommonIds.id_max, BuiltinId.int_max); 1045 makeBuiltin(CommonAstNodes.builtin_slice_length, CommonIds.id_length, BuiltinId.slice_length); 1046 makeBuiltin(CommonAstNodes.builtin_slice_ptr, CommonIds.id_ptr, BuiltinId.slice_ptr); 1047 makeBuiltin(CommonAstNodes.builtin_array_length, CommonIds.id_length, BuiltinId.array_length); 1048 makeBuiltin(CommonAstNodes.builtin_array_ptr, CommonIds.id_ptr, BuiltinId.array_ptr); 1049 makeBuiltin(CommonAstNodes.builtin_sizeof, CommonIds.id_sizeof, BuiltinId.type_sizeof); 1050 makeBuiltin(CommonAstNodes.builtin_offsetof, CommonIds.id_offsetof, BuiltinId.type_offsetof); 1051 // CommonAstNodes end 1052 1053 i8PtrType = types.appendPtr(makeIrType(IrBasicType.i8)); 1054 i64PtrType = types.appendPtr(makeIrType(IrBasicType.i64)); 1055 v128Type = types.appendArray(makeIrType(IrBasicType.i8), 16); 1056 1057 initializedAstBufSize = astBuffer.length; 1058 initializedIrTypeBufSize = types.buffer.length; 1059 1060 // cache buitin type strings for error reporting 1061 initializedSourceBufSize = sourceBuffer.length; 1062 initializedTokenLocBufSize = tokenLocationBuffer.length; 1063 } 1064 1065 void beginCompilation() 1066 { 1067 hasErrors = false; 1068 sourceBuffer.length = initializedSourceBufSize; 1069 files.clear; 1070 codeBuffer.clear; 1071 importBuffer.clear; 1072 tokenBuffer.length = initializedTokenLocBufSize; // same size as tok loc buf 1073 tokenLocationBuffer.length = initializedTokenLocBufSize; 1074 binaryBuffer.clear; 1075 bundleBuffer.clear; 1076 irStorage.instrHeaderBuffer.clear; 1077 irStorage.instrPayloadBuffer.clear; 1078 irStorage.instrNextBuffer.clear; 1079 irStorage.instrPrevBuffer.clear; 1080 irStorage.vregBuffer.clear; 1081 irStorage.phiBuffer.clear; 1082 irStorage.basicBlockBuffer.clear; 1083 irStorage.arrayBuffer.clear; 1084 irStorage.stackSlotBuffer.clear; 1085 types.buffer.length = initializedIrTypeBufSize; 1086 vmBuffer.clear; 1087 tempBuffer.clear; 1088 roStaticDataBuffer.clear; 1089 staticDataBuffer.clear; 1090 objSymTab.buffer.clear; 1091 objSymTab.firstModule = LinkIndex(); 1092 globals.buffer.clear; 1093 globals.initializerBuffer.clear; 1094 constants.buffer.clear; 1095 constants.aggregateBuffer.clear; 1096 astBuffer.length = initializedAstBufSize; 1097 arrayArena.clear; 1098 entryPoint = null; 1099 sink.clear; 1100 errorSink.clear; 1101 idMap.stringDataBuffer.clear; 1102 idMap.entries.clear; 1103 idMap.map = typeof(idMap.map).init; 1104 idMap.fqnMap = typeof(idMap.fqnMap).init; 1105 1106 analisysStack = analisysStack.init; 1107 currentFunction = null; 1108 1109 extraProperties = extraProperties.init; 1110 modules = modules.init; 1111 1112 externalModules = externalModules.init; 1113 externalSymbols = externalSymbols.init; 1114 1115 auto rootPackage = CommonAstNodes.node_root_package.get!PackageDeclNode(c); 1116 *rootPackage = PackageDeclNode.init; 1117 1118 // needed because all arrays are cleared 1119 idMap.regCommonIds(c); 1120 1121 addSections(c); 1122 createBuiltinFunctions(c); 1123 setVersionIds(c); 1124 } 1125 } 1126 1127 enum ExtraProperty : uint { 1128 fileName, // __FILE__ 1129 nodeName, // __FUNCTION_NAME__, __MODULE_NAME__ 1130 nodeFqn, // __FUNCTION_FQN__, __MODULE_FQN__ 1131 } 1132 1133 struct ExtraNodeProperty 1134 { 1135 ExtraProperty prop; 1136 uint node; 1137 } 1138 1139 struct AnalysedNode 1140 { 1141 AstIndex nodeIndex; 1142 NodeProperty prop; 1143 } 1144 1145 // How many 4 byte slots are required to store node in astBuffer 1146 enum slotsPerNode(T) = divCeil(T.sizeof, uint.sizeof); 1147 1148 enum BASE_NODE_SLOTS = slotsPerNode!AstNode; 1149 enum BUILTIN_FUNC_SLOTS = slotsPerNode!VariableDeclNode + slotsPerNode!FunctionSignatureNode + slotsPerNode!FunctionDeclNode; // assumes single parameter 1150 1151 enum CommonAstNodes : AstIndex 1152 { 1153 // reserved for undefined 1154 undefined = AstIndex(0), 1155 1156 // error. Nodes can point to error when name resolution failed 1157 node_error = AstIndex(1), 1158 node_root_package = AstIndex(node_error.storageIndex+BASE_NODE_SLOTS), 1159 1160 first_type = AstIndex(node_root_package.storageIndex + slotsPerNode!PackageDeclNode), 1161 // basic type nodes 1162 // The order is the same as in TokenType enum 1163 // The order is the same as in BasicType enum 1164 type_error = AstIndex(first_type.storageIndex + 0*NumBasicTypeNodeSlots), 1165 type_auto = AstIndex(first_type.storageIndex + 1*NumBasicTypeNodeSlots), 1166 type_noreturn = AstIndex(first_type.storageIndex + 2*NumBasicTypeNodeSlots), 1167 type_void = AstIndex(first_type.storageIndex + 3*NumBasicTypeNodeSlots), 1168 type_bool = AstIndex(first_type.storageIndex + 4*NumBasicTypeNodeSlots), 1169 type_null = AstIndex(first_type.storageIndex + 5*NumBasicTypeNodeSlots), 1170 1171 type_i8 = AstIndex(first_type.storageIndex + 6*NumBasicTypeNodeSlots), 1172 type_i16 = AstIndex(first_type.storageIndex + 7*NumBasicTypeNodeSlots), 1173 type_i32 = AstIndex(first_type.storageIndex + 8*NumBasicTypeNodeSlots), 1174 type_i64 = AstIndex(first_type.storageIndex + 9*NumBasicTypeNodeSlots), 1175 1176 type_u8 = AstIndex(first_type.storageIndex + 10*NumBasicTypeNodeSlots), 1177 type_u16 = AstIndex(first_type.storageIndex + 11*NumBasicTypeNodeSlots), 1178 type_u32 = AstIndex(first_type.storageIndex + 12*NumBasicTypeNodeSlots), 1179 type_u64 = AstIndex(first_type.storageIndex + 13*NumBasicTypeNodeSlots), 1180 1181 type_f32 = AstIndex(first_type.storageIndex + 14*NumBasicTypeNodeSlots), 1182 type_f64 = AstIndex(first_type.storageIndex + 15*NumBasicTypeNodeSlots), 1183 1184 type_alias = AstIndex(first_type.storageIndex + 16*NumBasicTypeNodeSlots), 1185 type_type = AstIndex(first_type.storageIndex + 17*NumBasicTypeNodeSlots), 1186 // basic type nodes end 1187 1188 first_compound = AstIndex(first_type.storageIndex + 18*NumBasicTypeNodeSlots), 1189 1190 // common custom types 1191 type_u8Ptr = AstIndex(first_compound.storageIndex), 1192 type_u8Slice = AstIndex(type_u8Ptr.storageIndex + slotsPerNode!PtrTypeNode), 1193 type_aliasSlice = AstIndex(type_u8Slice.storageIndex + slotsPerNode!SliceTypeNode), 1194 1195 first_builtin_member = AstIndex(type_aliasSlice.storageIndex + slotsPerNode!SliceTypeNode), 1196 1197 // builtin nodes 1198 // The order is the same as in BuiltinId enum 1199 builtin_min = AstIndex(first_builtin_member.storageIndex + 0*slotsPerNode!BuiltinNode), 1200 builtin_max = AstIndex(first_builtin_member.storageIndex + 1*slotsPerNode!BuiltinNode), 1201 builtin_slice_length = AstIndex(first_builtin_member.storageIndex + 2*slotsPerNode!BuiltinNode), 1202 builtin_slice_ptr = AstIndex(first_builtin_member.storageIndex + 3*slotsPerNode!BuiltinNode), 1203 builtin_array_length = AstIndex(first_builtin_member.storageIndex + 4*slotsPerNode!BuiltinNode), 1204 builtin_array_ptr = AstIndex(first_builtin_member.storageIndex + 5*slotsPerNode!BuiltinNode), 1205 builtin_sizeof = AstIndex(first_builtin_member.storageIndex + 6*slotsPerNode!BuiltinNode), 1206 builtin_offsetof = AstIndex(first_builtin_member.storageIndex + 7*slotsPerNode!BuiltinNode), 1207 // builtin nodes end 1208 1209 // builtin functions 1210 first_builtin_func = AstIndex(first_builtin_member.storageIndex + 8*slotsPerNode!BuiltinNode + slotsPerNode!VariableDeclNode + slotsPerNode!FunctionSignatureNode), 1211 1212 compile_error = AstIndex(first_builtin_func.storageIndex + 0*BUILTIN_FUNC_SLOTS), 1213 is_slice = AstIndex(first_builtin_func.storageIndex + 1*BUILTIN_FUNC_SLOTS), 1214 is_integer = AstIndex(first_builtin_func.storageIndex + 2*BUILTIN_FUNC_SLOTS), 1215 is_pointer = AstIndex(first_builtin_func.storageIndex + 3*BUILTIN_FUNC_SLOTS), 1216 base_of = AstIndex(first_builtin_func.storageIndex + 4*BUILTIN_FUNC_SLOTS), 1217 } 1218 1219 private immutable AstIndex[BasicType.max + 1] basicTypesArray = [ 1220 CommonAstNodes.type_error, 1221 CommonAstNodes.type_auto, 1222 CommonAstNodes.type_noreturn, 1223 CommonAstNodes.type_void, 1224 CommonAstNodes.type_bool, 1225 CommonAstNodes.type_null, 1226 CommonAstNodes.type_i8, 1227 CommonAstNodes.type_i16, 1228 CommonAstNodes.type_i32, 1229 CommonAstNodes.type_i64, 1230 CommonAstNodes.type_u8, 1231 CommonAstNodes.type_u16, 1232 CommonAstNodes.type_u32, 1233 CommonAstNodes.type_u64, 1234 CommonAstNodes.type_f32, 1235 CommonAstNodes.type_f64, 1236 CommonAstNodes.type_alias, 1237 CommonAstNodes.type_type, 1238 ]; 1239 private immutable AstIndex[BuiltinId.max + 1] builtinsArray = [ 1240 CommonAstNodes.builtin_min, 1241 CommonAstNodes.builtin_max, 1242 CommonAstNodes.builtin_slice_length, 1243 CommonAstNodes.builtin_slice_ptr, 1244 CommonAstNodes.builtin_array_length, 1245 CommonAstNodes.builtin_array_ptr, 1246 CommonAstNodes.builtin_sizeof, 1247 CommonAstNodes.builtin_offsetof, 1248 ]; 1249 immutable AstIndex[5] builtinFuncsArray = [ 1250 CommonAstNodes.compile_error, 1251 CommonAstNodes.is_slice, 1252 CommonAstNodes.is_integer, 1253 CommonAstNodes.is_pointer, 1254 CommonAstNodes.base_of, 1255 ]; 1256 1257 void builtin_function_stub() { 1258 assert(false, "Trying to call CTFE-only function at runtime"); 1259 } 1260 1261 void createBuiltinFunctions(CompilationContext* c) 1262 { 1263 ObjectModule builtinModule = { 1264 kind : ObjectModuleKind.isHost, 1265 flags : ObjectModuleFlags.isVerbose, 1266 id : c.idMap.getOrReg(c, ":builtin") 1267 }; 1268 c.builtinModuleIndex = c.objSymTab.addModule(builtinModule); 1269 1270 AstNodes params; 1271 ubyte numDefaultParams; 1272 void addParam(AstIndex type, Identifier id, AstIndex defaultValue = AstIndex()) 1273 { 1274 ushort paramIndex = cast(ushort)params.length; 1275 AstIndex param = c.appendAst!VariableDeclNode(TokenIndex(), ScopeIndex(), type, defaultValue, id); 1276 auto paramNode = param.get!VariableDeclNode(c); 1277 paramNode.flags |= VariableFlags.isParameter; 1278 paramNode.scopeIndex = paramIndex; 1279 paramNode.state = AstNodeState.type_check_done; 1280 if (numDefaultParams > 0) c.assertf(defaultValue.isDefined, "default params cannot be followed by non-default"); 1281 if (defaultValue.isDefined) ++numDefaultParams; 1282 params.put(c.arrayArena, param); 1283 } 1284 void make(AstIndex reqIndex, Identifier id, AstIndex retType) { 1285 AstIndex signature = c.appendAst!FunctionSignatureNode(TokenIndex(), retType, params, c.defaultCallConvention, numDefaultParams); 1286 auto sigNode = signature.get!FunctionSignatureNode(c); 1287 sigNode.state = AstNodeState.type_check_done; 1288 sigNode.flags |= FuncSignatureFlags.isCtfeOnly; 1289 params = AstNodes.init; 1290 numDefaultParams = 0; 1291 1292 AstIndex func = c.appendAst!FunctionDeclNode(TokenIndex(), AstIndex(), ScopeIndex(), signature, id); 1293 auto funcNode = func.get!FunctionDeclNode(c); 1294 funcNode.state = AstNodeState.type_check_done; 1295 funcNode.flags |= FuncDeclFlags.isBuiltin; 1296 1297 funcNode.backendData.objectSymIndex = c.addHostSymbolIndirect(c.builtinModuleIndex, id, &builtin_function_stub); 1298 1299 c.assertf(func == reqIndex, 1300 "Result AstIndex of builtin node %s (%s) is not equal to required (%s). Creation order must match CommonAstNodes order", 1301 id.pr(c), func, reqIndex); 1302 } 1303 1304 addParam(CommonAstNodes.type_u8Slice, CommonIds.id_message); 1305 make(CommonAstNodes.compile_error, CommonIds.cash_compile_error, CommonAstNodes.type_noreturn); 1306 1307 addParam(CommonAstNodes.type_type, CommonIds.id_type); 1308 make(CommonAstNodes.is_slice, CommonIds.cash_is_slice, CommonAstNodes.type_bool); 1309 1310 addParam(CommonAstNodes.type_type, CommonIds.id_type); 1311 make(CommonAstNodes.is_integer, CommonIds.cash_is_integer, CommonAstNodes.type_bool); 1312 1313 addParam(CommonAstNodes.type_type, CommonIds.id_type); 1314 make(CommonAstNodes.is_pointer, CommonIds.cash_is_pointer, CommonAstNodes.type_bool); 1315 1316 addParam(CommonAstNodes.type_type, CommonIds.id_type); 1317 make(CommonAstNodes.base_of, CommonIds.cash_base_of, CommonAstNodes.type_type); 1318 1319 //print_ast(CommonAstNodes.is_slice, c); 1320 } 1321 1322 void addSections(CompilationContext* c) 1323 { 1324 ObjectSection hostSection = { 1325 type : ObjectSectionType.host, 1326 alignmentPower : 0, 1327 id : c.idMap.getOrReg(c, ".host") 1328 }; 1329 c.builtinSections[ObjectSectionType.host] = c.objSymTab.addSection(hostSection); 1330 1331 ObjectSection importSection = { 1332 type : ObjectSectionType.imports, 1333 flags : ObjectSectionFlags.read | ObjectSectionFlags.write, 1334 alignmentPower : 12, // 4096 1335 id : c.idMap.getOrReg(c, ".idata"), 1336 buffer : &c.importBuffer, 1337 }; 1338 c.builtinSections[ObjectSectionType.imports] = c.objSymTab.addSection(importSection); 1339 1340 ObjectSection dataSection = { 1341 type : ObjectSectionType.rw_data, 1342 flags : ObjectSectionFlags.read | ObjectSectionFlags.write, 1343 alignmentPower : 12, // 4096 1344 id : c.idMap.getOrReg(c, ".data"), 1345 buffer : &c.staticDataBuffer, 1346 }; 1347 c.builtinSections[ObjectSectionType.rw_data] = c.objSymTab.addSection(dataSection); 1348 1349 ObjectSection rdataSection = { 1350 type : ObjectSectionType.ro_data, 1351 flags : ObjectSectionFlags.read, 1352 alignmentPower : 12, // 4096 1353 id : c.idMap.getOrReg(c, ".rdata"), 1354 buffer : &c.roStaticDataBuffer, 1355 }; 1356 c.builtinSections[ObjectSectionType.ro_data] = c.objSymTab.addSection(rdataSection); 1357 1358 ObjectSection textSection = { 1359 type : ObjectSectionType.code, 1360 flags : ObjectSectionFlags.execute | ObjectSectionFlags.read, 1361 alignmentPower : 12, // 4096 1362 id : c.idMap.getOrReg(c, ".text"), 1363 buffer : &c.codeBuffer, 1364 }; 1365 c.builtinSections[ObjectSectionType.code] = c.objSymTab.addSection(textSection); 1366 } 1367 1368 void setVersionIds(CompilationContext* c) 1369 { 1370 final switch(c.targetOs) { 1371 case TargetOs.windows: c.enabledVersionIdentifiers |= 1 << VersionId.id_windows; break; 1372 case TargetOs.linux: c.enabledVersionIdentifiers |= 1 << VersionId.id_linux; break; 1373 case TargetOs.macos: c.enabledVersionIdentifiers |= 1 << VersionId.id_macos; break; 1374 } 1375 } 1376 1377 struct Slice(T) { 1378 this(T[] data) { 1379 ptr = data.ptr; 1380 length = data.length; 1381 } 1382 ulong length; 1383 T* ptr; 1384 T[] slice() { return ptr[0..length]; } 1385 alias slice this; 1386 } 1387 alias SliceString = Slice!(const(char));