private void GenerateFunctionHeader(AstFuncExpr function, bool forceEmitCode) { // Don't emit global functions that aren't even used if (!forceEmitCode && dontEmitUnusedDeclarations && !function.IsUsed) { return; } if (function.IsMacroFunction) { return; } var name = ""; if (function.ImplBlock != null) { name += function.ImplBlock.TargetType + "."; if (function.ImplBlock.Trait != null) { name += function.ImplBlock.Trait + "."; } } name += function.Name; if (function.PolymorphicTypes != null && function.PolymorphicTypes.Count > 0) { name += "." + string.Join(".", function.PolymorphicTypes.Select(p => $"{p.Key}.{p.Value}")); } if (function.ConstParameters != null && function.ConstParameters.Count > 0) { name += "." + string.Join(".", function.ConstParameters.Select(p => $"{p.Key}.{p.Value.type}.{p.Value.value}")); } if (function.Body != null) { name += ".che"; } var linkname = function.GetDirective("linkname"); LLVMValueRef lfunc = new LLVMValueRef(); if (linkname != null) { name = linkname.Arguments[0].Value as string; lfunc = module.GetNamedFunction(name); } LLVMTypeRef ltype = FuncTypeToLLVMType(function.FunctionType); if (lfunc.Pointer.ToInt64() == 0) { lfunc = module.AddFunction(name, ltype); } // :temporary if (function.Body != null) { lfunc.SetLinkage(LLVMLinkage.LLVMInternalLinkage); } if (function.HasDirective("extern")) { lfunc.SetLinkage(LLVMLinkage.LLVMExternalLinkage); } // TODO if (function.HasDirective("noinline")) { lfunc.AddFunctionAttribute(context, LLVMAttributeKind.NoInline); } lfunc.AddFunctionAttribute(context, LLVMAttributeKind.NoUnwind); var ccDir = function.GetDirective("stdcall"); if (ccDir != null) { LLVM.SetFunctionCallConv(lfunc, (int)LLVMCallConv.LLVMX86StdcallCallConv); } valueMap[function] = lfunc; }
private void GenerateFunctionImplementation(AstFuncExpr function, bool forceEmitCode) { // Don't emit global functions that aren't even used if (!forceEmitCode && dontEmitUnusedDeclarations && !function.IsUsed) { return; } if (function.Body == null || function.IsMacroFunction) { return; } currentFunction = function; keepTrackOfStackTrace = !function.HasDirective("nostacktrace") && enableStackTrace; var lfunc = valueMap[function]; currentLLVMFunction = lfunc; // generate body { var builder = new IRBuilder(); this.builder = builder; var bbParams = lfunc.AppendBasicBlock("locals"); //var bbTemps = lfunc.AppendBasicBlock("temps"); var bbBody = lfunc.AppendBasicBlock("body"); // allocate space for parameters and return values on stack builder.PositionBuilderAtEnd(bbParams); PushStackTrace(function); for (int i = 0; i < function.Parameters.Count; i++) { var param = function.Parameters[i]; var p = lfunc.GetParam((uint)i); var ptype = LLVM.TypeOf(p); p = builder.CreateAlloca(ptype, $"p_{param.Name?.Name}"); valueMap[param] = p; } // @todo: do we still need this? //foreach (var c in function.ConstScope.Symbols) //{ // if (c.Value is ConstSymbol s && !s.Type.IsComptimeOnly) // { // var val = CheezValueToLLVMValue(s.Type, s.Value); // var cnst = builder.CreateAlloca(CheezTypeToLLVMType(s.Type), $"c_"); // builder.CreateStore(val, cnst); // valueMap[s] = cnst; // } //} if (function.ReturnTypeExpr != null) { var ptype = CheezTypeToLLVMType(function.ReturnTypeExpr.Type); var p = builder.CreateAlloca(ptype, $"ret_{function.ReturnTypeExpr.Name?.Name}"); valueMap[function.ReturnTypeExpr] = p; } // store params and rets in local variables for (int i = 0; i < function.Parameters.Count; i++) { var param = function.Parameters[i]; var p = lfunc.GetParam((uint)i); builder.CreateStore(p, valueMap[param]); } // temp values //builder.PositionBuilderAtEnd(bbTemps); builder.CreateBr(bbBody); // body builder.PositionBuilderAtEnd(bbBody); GenerateExpression(function.Body, false); // ret if void if (function.ReturnTypeExpr == null && !function.Body.GetFlag(ExprFlags.Returns)) { PopStackTrace(); builder.CreateRetVoid(); } builder.Dispose(); } // remove empty basic blocks var bb = lfunc.GetFirstBasicBlock(); while (bb.Pointer.ToInt64() != 0) { var first = bb.GetFirstInstruction(); if (bb.GetBasicBlockTerminator().Pointer.ToInt64() == 0) { var b = new IRBuilder(); b.PositionBuilderAtEnd(bb); b.CreateUnreachable(); b.Dispose(); } bb = bb.GetNextBasicBlock(); } // TODO //if (lfunc.VerifyFunction(LLVMVerifierFailureAction.LLVMPrintMessageAction)) //{ // Console.Error.WriteLine($"in function {lfunc}"); //} currentFunction = null; }