public void Insert(Function function) { FunctionGroupName gname = new FunctionGroupName(function.GetFunctionType(), function.IsStatic()); gname.SetFunction(function); functions.Add(gname); }
private void PrepareReturning(AstNode where, Function function, LexicalScope scope) { // Get the definition node and check for generator. FunctionDefinition defNode = function.DefinitionNode; bool isGenerator = false; if(defNode != null) isGenerator = defNode.IsGenerator; // Use standard return. if(function.GetExceptionContext() == null && !isGenerator) return; // Create the return block. BasicBlock returnBlock = new BasicBlock(function); returnBlock.SetName("retBlock"); function.ReturnBlock = returnBlock; // Create the return value local. FunctionType functionType = function.GetFunctionType(); IChelaType retType = functionType.GetReturnType(); if(retType != ChelaType.GetVoidType() && !isGenerator) function.ReturnValueVar = new LocalVariable(GenSym() + "_retval", scope, retType); // Create the is returning flag. function.ReturningVar = new LocalVariable(GenSym() + "_isret", scope, ChelaType.GetBoolType(), isGenerator); function.ReturningVar.Type = LocalType.Return; // Create the field for generators. if(isGenerator) { FieldVariable returningField = new FieldVariable("returning", MemberFlags.Private, ChelaType.GetBoolType(), defNode.GeneratorClass); defNode.GeneratorClass.AddField(returningField); function.ReturningVar.ActualVariable = returningField; } // Initializer the returning flag to false. builder.CreateLoadBool(false); PerformAssignment(where, function.ReturningVar); }
private void FinishReturn(AstNode node, Function function) { // Get the return block. BasicBlock returnBlock = function.ReturnBlock; // Get the definition node and check for generator. FunctionDefinition defNode = function.DefinitionNode; bool isGenerator = false; if(defNode != null) isGenerator = defNode.IsGenerator; // Add implicit void return. FunctionType functionType = function.GetFunctionType(); IChelaType retType = functionType.GetReturnType(); IChelaType voidType = ChelaType.GetVoidType(); if(!builder.IsLastTerminator()) { if(retType == voidType || isGenerator) { if(returnBlock != null) { builder.CreateJmp(returnBlock); } else if(isGenerator) { builder.CreateLoadBool(false); builder.CreateRet(); } else { builder.CreateRetVoid(); } } else { //function.Dump(); Error(node, "not all of the function code paths returns something."); } } // Build the return block. if(returnBlock != null) { builder.SetBlock(returnBlock); // Perform return. if(isGenerator) { // Set the disposed state. builder.CreateLoadArg(0); builder.CreateLoadInt32(1); builder.CreateStoreField(defNode.GeneratorState); // Return false in MoveNext. builder.CreateLoadBool(false); builder.CreateRet(); } else if(retType == voidType) { builder.CreateRetVoid(); } else { builder.CreateLoadLocal(function.ReturnValueVar); builder.CreateRet(); } } }
private void CreateKernelEntryPoint(AstNode where, Function function) { // Only create once if(function.EntryPoint != null) return; // Get the function type. FunctionType functionType = function.GetFunctionType(); // The return type must be void. if(functionType.GetReturnType() != ChelaType.GetVoidType()) return; // Check the parameters for input and output streams, and not references. bool inputStream = false; bool outputStream = false; for(int i = 0; i < functionType.GetArgumentCount(); ++i) { IChelaType argType = functionType.GetArgument(i); // Streams are references. if(!argType.IsReference()) continue; // Cast the argument. ReferenceType argRef = (ReferenceType)argType; // Only stream and array references are supported in kernel entry points. if(!argRef.IsStreamReference()) { argType = argRef.GetReferencedType(); if(argType.IsArray()) continue; return; } // Check the stream flow. ReferenceFlow flow = argRef.GetReferenceFlow(); if(flow == ReferenceFlow.In || flow == ReferenceFlow.InOut) inputStream = true; if(flow == ReferenceFlow.Out || flow == ReferenceFlow.InOut) outputStream = true; // Don't stop the loop to check for the non-stream references. } // Both types of streams must be present. if(!inputStream || !outputStream) return; // Now create the entry point function type. List<IChelaType> arguments = new List<IChelaType> (); for(int i = 0; i < functionType.GetArgumentCount(); ++i) { IChelaType argType = functionType.GetArgument(i); // Select the adecuate holder. Class holder = null; if(!argType.IsReference()) { // Use uniform holder for non-stream and non-array arguments. holder = currentModule.GetUniformHolderClass(); } else { // De-Reference the argument type. ReferenceType refType = (ReferenceType)argType; argType = refType.GetReferencedType(); // Get the array dimensions. int dimensions = 0; if(argType.IsArray()) { ArrayType arrayType = (ArrayType)argType; argType = arrayType.GetValueType(); dimensions = arrayType.GetDimensions(); } else { // TODO: Read the dimensions from the reference type. } // Select the stream holder according to the dimensions. switch(dimensions) { case 0: holder = currentModule.GetStreamHolderClass(); break; case 1: holder = currentModule.GetStreamHolder1DClass(); break; case 2: holder = currentModule.GetStreamHolder2DClass(); break; case 3: holder = currentModule.GetStreamHolder3DClass(); break; default: Error(where, "unsupported array with more than 3 dimensions in kernels."); break; } } // Create an stream holder instance. GenericInstance instanceData = new GenericInstance(holder.GetGenericPrototype(), new IChelaType[]{argType}); IChelaType holderType = holder.InstanceGeneric(instanceData, currentModule); // Store the stream holder type. if(holderType.IsPassedByReference()) holderType = ReferenceType.Create(holderType); arguments.Add(holderType); } // Create the kernel binder type. IChelaType computeBindingType = ReferenceType.Create(currentModule.GetComputeBindingDelegate()); FunctionType kernelBinderType = FunctionType.Create(computeBindingType, arguments); // Create the kernel entry point. function.EntryPoint = new KernelEntryPoint(function, kernelBinderType); }
private void CheckMainCandidate(AstNode node, Function main) { // Ignore the main type if the module is not executable. if(currentModule.GetModuleType() != ModuleType.Executable) return; // Get the function type. FunctionType type = main.GetFunctionType(); // Check the return type. IChelaType returnType = type.GetReturnType(); if(returnType != ChelaType.GetVoidType() && returnType != ChelaType.GetIntType()) return; // Check the argument count. if(type.GetArgumentCount() > 1) return; // Check the argument. if(type.GetArgumentCount() == 1) { IChelaType strArrayType = ReferenceType.Create(ArrayType.Create(currentModule.TypeMap(ChelaType.GetStringType()))); if(strArrayType != type.GetArgument(0)) return; } // Make usure it could be. string fullName = main.GetFullName(); string mainName = currentModule.GetMainName(); if(mainName != null && fullName != mainName) return; // This is a main candidate. Function oldMain = currentModule.GetMainFunction(); if(oldMain != null && oldMain != main) Error(node, "multiple main functions defined"); // This is the main. currentModule.SetMainFunction(main); }