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));