1 /// Copyright: Copyright (c) 2017-2019 Andrey Penechko.
2 /// License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
3 /// Authors: Andrey Penechko.
4 module vox.fe.ast.decl.func;
5 
6 import vox.all;
7 
8 enum FuncDeclFlags : ushort
9 {
10 	isInline = AstFlags.userFlag << 0,
11 	isBuiltin = AstFlags.userFlag << 1,
12 }
13 
14 /// Refers to a function inside a module
15 struct FunctionIndex
16 {
17 	/// Index into ModuleDeclNode.functions
18 	uint functionIndex;
19 	ModuleIndex moduleIndex;
20 }
21 
22 struct FunctionBackendData
23 {
24 	/// Machine-independent IR
25 	AstIndex irData; // IrFunction
26 	AstIndex optimizedIrData; // IrFunction
27 	AstIndex loweredIrData; // IrFunction
28 	/// Machine-level IR
29 	AstIndex lirData; // IrFunction
30 	///
31 	LinkIndex objectSymIndex;
32 }
33 
34 @(AstType.decl_function)
35 struct FunctionDeclNode {
36 	mixin AstNodeData!(AstType.decl_function);
37 	AstIndex _module;
38 	// scopes are in a hierarchy as:
39 	// ownerScope
40 	// + parameterScope
41 	//   + body scope
42 	ScopeIndex parameterScope;
43 	AstIndex signature; // FunctionSignatureNode
44 	AstIndex block_stmt; // null if external
45 	Identifier id;
46 	FunctionBackendData backendData;
47 
48 	bool isInline() { return cast(bool)(flags & FuncDeclFlags.isInline); }
49 	bool isBuiltin() { return cast(bool)(flags & FuncDeclFlags.isBuiltin); }
50 	bool isCtfeOnly(CompilationContext* c) {
51 		return signature.get!FunctionSignatureNode(c).isCtfeOnly;
52 	}
53 	/// External functions have no body
54 	bool isExternal() { return block_stmt.isUndefined; }
55 
56 	this(TokenIndex loc, AstIndex _module, ScopeIndex parameterScope, AstIndex signature, Identifier id)
57 	{
58 		this.loc = loc;
59 		this.astType = AstType.decl_function;
60 		this.flags = 0;
61 		this._module = _module;
62 		this.parameterScope = parameterScope;
63 		this.signature = signature;
64 		this.id = id;
65 	}
66 
67 	IrIndex getIrIndex(CompilationContext* c) {
68 		// IR index of the function depends on full IR type of the signature
69 		signature.get!FunctionSignatureNode(c).getIrType(c);
70 
71 		AstIndex index = get_ast_index(&this, c);
72 		return IrIndex(index.storageIndex, IrValueKind.func);
73 	}
74 }
75 
76 void print_func(FunctionDeclNode* node, ref AstPrintState state)
77 {
78 	state.print("FUNC ", state.context.idString(node.id),
79 		node.isBuiltin ? " #builtin" : null,
80 		node.isInline ? " #inline" : null);
81 	print_ast(node.signature, state);
82 	if (node.block_stmt) print_ast(node.block_stmt, state);
83 }
84 
85 void post_clone_func(FunctionDeclNode* node, ref CloneState state)
86 {
87 	state.fixScope(node.parameterScope);
88 	state.fixAstIndex(node._module);
89 	state.fixAstIndex(node.signature);
90 	state.fixAstIndex(node.block_stmt);
91 }
92 
93 void name_register_self_func(AstIndex nodeIndex, FunctionDeclNode* node, ref NameRegisterState state) {
94 	auto c = state.context;
95 	node.state = AstNodeState.name_register_self;
96 
97 	// Template instance shouldn't register itself
98 	// They are discovered with template instantiation syntax
99 	// Instance is wrapped in special scope, which shouldn't have function name inserted, only template args
100 	if (!node.isTemplateInstance)
101 	{
102 		// can't be done at parse time because of conditional compilation
103 		node.parameterScope.get_scope(c).parentScope.insert_scope(node.id, nodeIndex, c);
104 	}
105 	auto mod = node._module.get!ModuleDeclNode(c);
106 	mod.addFunction(nodeIndex, c);
107 
108 	// Create link object
109 	{
110 		if (node.isExternal)
111 		{
112 			auto sig = node.signature.get!FunctionSignatureNode(c);
113 			if (!sig.hasExternAttrib) {
114 				c.error(node.loc, "External function `%s` must be annotated with @extern attribute", c.idString(node.id));
115 			} else {
116 				auto attrib = sig.getExternAttrib(c).as!BuiltinAttribNode(c);
117 
118 				final switch(cast(BuiltinAttribSubType)attrib.subType) {
119 					case BuiltinAttribSubType.extern_syscall:
120 						// Allowed if it is marked with @extern(syscall)
121 						// noop, syscall instruction will be generated
122 						break;
123 
124 					case BuiltinAttribSubType.extern_module:
125 						Identifier modId = Identifier(attrib.data);
126 						Identifier symId = node.id;
127 						auto externalId = ExternalSymbolId(modId, symId);
128 
129 						final switch(c.buildType) {
130 							case BuildType.jit:
131 								// When JIT-compiling, host can provide a set of modules that define external functions
132 								LinkIndex symbolIndex = c.externalSymbols.get(externalId);
133 
134 								if (!symbolIndex.isDefined) {
135 									if (c.externalModules.get(modId).isDefined)
136 										c.error(node.loc, "Cannot find external symbol `%s` in host module `%s`", symId.pr(c), modId.pr(c));
137 									else
138 										c.error(node.loc, "Cannot find external symbol `%s` in host module `%s`. No such module defined", symId.pr(c), modId.pr(c));
139 									break;
140 								}
141 
142 								// TODO: check that parameters match
143 								node.backendData.objectSymIndex = symbolIndex;
144 								break;
145 
146 							case BuildType.exe:
147 								// When compiling exe, external symbol will point to a shared library
148 								LinkIndex symbolIndex = c.externalSymbols.get(externalId);
149 
150 								if (!symbolIndex.isDefined) {
151 									// Will create a new module if not found
152 									// Dll symbols will be imported from this module
153 									LinkIndex moduleIndex = c.getOrCreateExternalModule(modId, ObjectModuleKind.isImported);
154 									// Create symbol if it doesn't exist
155 									symbolIndex = c.addDllModuleSymbol(moduleIndex, symId);
156 								}
157 
158 								node.backendData.objectSymIndex = symbolIndex;
159 								break;
160 						}
161 						break;
162 				}
163 			}
164 		}
165 		else
166 		{
167 			ObjectSymbol sym = {
168 				kind : ObjectSymbolKind.isLocal,
169 				sectionIndex : c.builtinSections[ObjectSectionType.code],
170 				moduleIndex : mod.objectSymIndex,
171 				alignmentPower : 0,
172 				id : node.id,
173 			};
174 			node.backendData.objectSymIndex = c.objSymTab.addSymbol(sym);
175 		}
176 	}
177 
178 	node.state = AstNodeState.name_register_self_done;
179 }
180 
181 void name_register_nested_func(AstIndex nodeIndex, FunctionDeclNode* node, ref NameRegisterState state) {
182 	node.state = AstNodeState.name_register_nested;
183 	require_name_register(node.signature, state);
184 	if (node.block_stmt)
185 	{
186 		// TODO: we don't need to register parameters on function without body
187 		require_name_register(node.block_stmt, state);
188 	}
189 	node.state = AstNodeState.name_register_nested_done;
190 }
191 
192 void name_resolve_func(FunctionDeclNode* node, ref NameResolveState state) {
193 	node.state = AstNodeState.name_resolve;
194 	// TODO: parameters don't need to see each other (including default param value expr)
195 	require_name_resolve(node.signature, state);
196 	if (node.block_stmt)
197 	{
198 		// TODO: we don't need to register parameters on function without body
199 		require_name_resolve(node.block_stmt, state);
200 	}
201 	node.state = AstNodeState.name_resolve_done;
202 }
203 
204 void type_check_func(FunctionDeclNode* node, ref TypeCheckState state)
205 {
206 	CompilationContext* c = state.context;
207 
208 	node.state = AstNodeState.type_check;
209 
210 	require_type_check(node.signature, state);
211 	if (node.block_stmt) require_type_check(node.block_stmt, state);
212 
213 	node.state = AstNodeState.type_check_done;
214 }
215 
216 // ModuleDeclNode.functions are processed sequentially. No nesting can occur.
217 void ir_gen_function(ref IrGenState gen, FunctionDeclNode* f)
218 {
219 	if (f.state >= AstNodeState.ir_gen_done) return; // already generated
220 
221 	CompilationContext* c = gen.context;
222 	IrBuilder* builder = &gen.builder;
223 
224 	c.currentFunction = f;
225 	scope(exit) c.currentFunction = null;
226 
227 
228 	f.state = AstNodeState.ir_gen;
229 	scope(exit) f.state = AstNodeState.ir_gen_done;
230 
231 
232 	// Do not generate body for the external functions
233 	if (f.isExternal) return;
234 
235 	// function type must be generated even if it is external
236 	auto signature = f.signature.get!FunctionSignatureNode(c);
237 	IrIndex type = f.signature.gen_ir_type(c);
238 
239 	gen.fun = f;
240 	scope(exit) gen.fun = null;
241 
242 	// create new function
243 	AstIndex irIndex = c.appendAst!IrFunction;
244 	f.backendData.irData = irIndex;
245 	gen.ir = c.getAst!IrFunction(irIndex);
246 	IrFunction* ir = gen.ir;
247 	ir.name = f.id;
248 
249 	ir.type = type;
250 	ir.instructionSet = IrInstructionSet.ir;
251 
252 	builder.begin(ir, c);
253 
254 	foreach (AstIndex param; signature.parameters)
255 	{
256 		IrLabel dummy;
257 		ir_gen_stmt(gen, param, ir.entryBasicBlock, dummy);
258 	}
259 
260 	builder.addJump(ir.entryBasicBlock);
261 
262 	IrIndex body_block = builder.addBasicBlock();
263 	builder.addBlockTarget(ir.entryBasicBlock, body_block);
264 	builder.sealBlock(body_block);
265 
266 	// label at the end of body
267 	IrLabel bodyExitLabel = IrLabel(body_block);
268 
269 	// compile body
270 	ir_gen_stmt(gen, f.block_stmt, body_block, bodyExitLabel);
271 
272 	IrIndex currentBlock = bodyExitLabel.blockIndex;
273 	// In case new block was created, no new predecessors will be added
274 	builder.sealBlock(currentBlock);
275 
276 	if (!signature.returnType.isVoidType(c))
277 	{
278 		// currentBlock must be finished with retVal
279 		if (!ir.getBlock(currentBlock).isFinished)
280 		{
281 			c.unrecoverable_error(f.loc,
282 				"function `%s` has no return statement, but is expected to return a value of type %s",
283 				c.idString(f.id), signature.returnType.typeName(c));
284 		}
285 
286 		auto exitBlock = ir.getBlock(ir.exitBasicBlock);
287 		if (exitBlock.predecessors.empty)
288 		{
289 			// control flow doesn't reach exit block. Remove return var phi function.
290 			removeAllPhis(*exitBlock);
291 			removeAllInstrs(*exitBlock);
292 			builder.emitInstr!(IrOpcode.unreachable)(ir.exitBasicBlock);
293 		}
294 	}
295 	else
296 	{
297 		// currentBlock must be finished with ret or, not finished
298 		if (!ir.getBlock(currentBlock).isFinished)
299 		{
300 			builder.addReturn(currentBlock);
301 		}
302 	}
303 
304 	//dumpFunction(c, ir, "IR gen end");
305 
306 	// all blocks with return (exit's predecessors) already connected, seal exit block
307 	builder.sealBlock(ir.exitBasicBlock);
308 
309 	builder.finalizeIr;
310 
311 	if (c.validateIr) validateIrFunction(c, ir, "IR gen");
312 	if (c.printIr && c.printDumpOf(f)) dumpFunction(c, ir, "IR gen");
313 }