public OptionalValue <BitcodeModule> Generate(IAstNode ast) { ast.ValidateNotNull(nameof(ast)); ast.Accept(this); if (AnonymousFunctions.Count > 0) { var mainFunction = Module.CreateFunction("main", Context.GetFunctionType(Context.VoidType)); var block = mainFunction.AppendBasicBlock("entry"); var irBuilder = new InstructionBuilder(block); var printdFunc = Module.CreateFunction("printd", Context.GetFunctionType(Context.DoubleType, Context.DoubleType)); foreach (var anonFunc in AnonymousFunctions) { var value = irBuilder.Call(anonFunc); irBuilder.Call(printdFunc, value); } irBuilder.Return( ); // Use always inline and Dead Code Elimination module passes to inline all of the // anonymous functions. This effectively strips all the calls just generated for main() // and inlines each of the anonymous functions directly into main, dropping the now // unused original anonymous functions all while retaining all of the original source // debug information locations. using var mpm = new ModulePassManager( ); mpm.AddAlwaysInlinerPass( ) .AddGlobalDCEPass( ) .Run(Module); Module.DIBuilder.Finish( ); } return(OptionalValue.Create(Module)); }
private Function DefineFunction(Function function, ExpressionContext body) { if (!function.IsDeclaration) { throw new ArgumentException($"Function {function.Name} cannot be redefined", nameof(function)); } var basicBlock = function.AppendBasicBlock("entry"); InstructionBuilder.PositionAtEnd(basicBlock); NamedValues.Clear( ); foreach (var arg in function.Parameters) { NamedValues[arg.Name] = arg; } var funcReturn = body.Accept(this); if (funcReturn == null) { function.EraseFromParent( ); return(null); } InstructionBuilder.Return(funcReturn); function.Verify( ); return(function); }
public override Value Visit(FunctionDefinition definition) { var function = GetOrDeclareFunction(definition.Signature); if (!function.IsDeclaration) { throw new CodeGeneratorException($"Function {function.Name} cannot be redefined in the same module"); } try { var entryBlock = function.AppendBasicBlock("entry"); InstructionBuilder.PositionAtEnd(entryBlock); using (NamedValues.EnterScope( )) { foreach (var param in definition.Signature.Parameters) { NamedValues[param.Name] = function.Parameters[param.Index]; } var funcReturn = definition.Body.Accept(this); InstructionBuilder.Return(funcReturn); function.Verify( ); FunctionPassManager.Run(function); return(function); } } catch (CodeGeneratorException) { function.EraseFromParent( ); throw; } }
public void Create_varargs_function_with_arbitrary_params_succeeds() { using var ctx = new Context(); var module = ctx.CreateBitcodeModule(); var varArgsSig = ctx.GetFunctionType(ctx.VoidType, Enumerable.Empty <ITypeRef>(), true); var callerSig = ctx.GetFunctionType(ctx.VoidType); var function = module.CreateFunction("VarArgFunc", varArgsSig); var entryBlock = function.PrependBasicBlock("entry"); var bldr = new InstructionBuilder(entryBlock); bldr.Return( ); var caller = module.CreateFunction("CallVarArgs", callerSig); entryBlock = caller.PrependBasicBlock("entry"); bldr = new InstructionBuilder(entryBlock); var callInstruction = bldr.Call(function, ctx.CreateConstant(0), ctx.CreateConstant(1), ctx.CreateConstant(2)); Assert.IsNotNull(callInstruction); // operands of call are all arguments, plus the target function Assert.AreEqual(4, callInstruction.Operands.Count); Assert.AreEqual(0UL, callInstruction.Operands.GetOperand <ConstantInt>(0) !.ZeroExtendedValue); Assert.AreEqual(1UL, callInstruction.Operands.GetOperand <ConstantInt>(1) !.ZeroExtendedValue); Assert.AreEqual(2UL, callInstruction.Operands.GetOperand <ConstantInt>(2) !.ZeroExtendedValue); }
public override Value?Visit(FunctionDefinition definition) { definition.ValidateNotNull(nameof(definition)); var function = GetOrDeclareFunction(definition.Signature); if (!function.IsDeclaration) { throw new CodeGeneratorException($"Function {function.Name} cannot be redefined in the same module"); } try { var entryBlock = function.AppendBasicBlock("entry"); InstructionBuilder.PositionAtEnd(entryBlock); using (NamedValues.EnterScope( )) { foreach (var param in definition.Signature.Parameters) { var argSlot = InstructionBuilder.Alloca(function.Context.DoubleType) .RegisterName(param.Name); InstructionBuilder.Store(function.Parameters[param.Index], argSlot); NamedValues[param.Name] = argSlot; } foreach (LocalVariableDeclaration local in definition.LocalVariables) { var localSlot = InstructionBuilder.Alloca(function.Context.DoubleType) .RegisterName(local.Name); NamedValues[local.Name] = localSlot; } EmitBranchToNewBlock("body"); var funcReturn = definition.Body.Accept(this) ?? throw new CodeGeneratorException(ExpectValidFunc); InstructionBuilder.Return(funcReturn); function.Verify( ); FunctionPassManager.Run(function); if (definition.IsAnonymous) { function.AddAttribute(FunctionAttributeIndex.Function, AttributeKind.AlwaysInline) .Linkage(Linkage.Private); AnonymousFunctions.Add(function); } return(function); } } catch (CodeGeneratorException) { function.EraseFromParent( ); throw; } }
private static BitcodeModule CreateModule(Context ctx, TargetMachine machine, int magicNumber, string modulename = "test", string functionname = "main") { var module = ctx.CreateBitcodeModule(modulename); module.Layout = machine.TargetData; IrFunction main = module.CreateFunction(functionname, ctx.GetFunctionType(ctx.Int32Type)); BasicBlock entryBlock = main.AppendBasicBlock("entry"); var bldr = new InstructionBuilder(entryBlock); bldr.Return(ctx.CreateConstant(magicNumber)); return(module); }
private static void CreateDoCopyFunctionBody(BitcodeModule module , DataLayout layout , Function doCopyFunc , IStructType foo , GlobalVariable bar , GlobalVariable baz , Function copyFunc ) { var bytePtrType = module.Context.Int8Type.CreatePointerType( ); // create block for the function body, only need one for this simple sample var blk = doCopyFunc.AppendBasicBlock("entry"); // create instruction builder to build the body var instBuilder = new InstructionBuilder(blk); bool param0ByVal = copyFunc.Attributes[FunctionAttributeIndex.Parameter0].Contains(AttributeKind.ByVal); if (!param0ByVal) { // create a temp local copy of the global structure var dstAddr = instBuilder.Alloca(foo) .RegisterName("agg.tmp") .Alignment(layout.CallFrameAlignmentOf(foo)); var bitCastDst = instBuilder.BitCast(dstAddr, bytePtrType) .SetDebugLocation(25, 11, doCopyFunc.DISubProgram); var bitCastSrc = instBuilder.BitCast(bar, bytePtrType) .SetDebugLocation(25, 11, doCopyFunc.DISubProgram); instBuilder.MemCpy(module , bitCastDst , bitCastSrc , module.Context.CreateConstant(layout.ByteSizeOf(foo)) , ( int )layout.CallFrameAlignmentOf(foo) , false ).SetDebugLocation(25, 11, doCopyFunc.DISubProgram); instBuilder.Call(copyFunc, dstAddr, baz) .SetDebugLocation(25, 5, doCopyFunc.DISubProgram); } else { instBuilder.Call(copyFunc, bar, baz) .SetDebugLocation(25, 5, doCopyFunc.DISubProgram) .AddAttributes(FunctionAttributeIndex.Parameter0, copyFunc.Parameters[0].Attributes); } instBuilder.Return( ) .SetDebugLocation(26, 1, doCopyFunc.DISubProgram); }
private static IrFunction CreateSimpleVoidNopTestFunction(BitcodeModule module, string name) { var ctx = module.Context; Assert.IsNotNull(ctx); var testFunc = module.AddFunction(name, ctx.GetFunctionType(ctx.VoidType)); testFunc.AppendBasicBlock("entry"); var irBuilder = new InstructionBuilder(testFunc.EntryBlock); irBuilder.Return( ); return(testFunc); }
public Value Generate(IAstNode ast, Action <CodeGeneratorException> codeGenerationErroHandler) { try { ast.Accept(this); if (AnonymousFunctions.Count > 0) { var mainFunction = Module.AddFunction("main", Context.GetFunctionType(Context.VoidType)); var block = mainFunction.AppendBasicBlock("entry"); var irBuilder = new InstructionBuilder(block); var printdFunc = Module.AddFunction("printd", Context.GetFunctionType(Context.DoubleType, Context.DoubleType)); foreach (var anonFunc in AnonymousFunctions) { var value = irBuilder.Call(anonFunc); irBuilder.Call(printdFunc, value); } irBuilder.Return( ); // Use always inline and Dead Code Elimination module passes to inline all of the // anonymous functions. This effectively strips all the calls just generated for main() // and inlines each of the anonymous functions directly into main, dropping the now // unused original anonymous functions all while retaining all of the original source // debug information locations. var mpm = new ModulePassManager( ) .AddAlwaysInlinerPass( ) .AddGlobalDCEPass( ); mpm.Run(Module); Module.DIBuilder.Finish( ); } } catch (CodeGeneratorException ex) when(codeGenerationErroHandler != null) { codeGenerationErroHandler(ex); } return(null); }
private static void CreateCopyFunctionBody(BitcodeModule module , DataLayout layout , Function copyFunc , DIFile diFile , ITypeRef foo , DebugPointerType fooPtr , DIType constFooType ) { var diBuilder = module.DIBuilder; copyFunc.Parameters[0].Name = "src"; copyFunc.Parameters[1].Name = "pDst"; // create block for the function body, only need one for this simple sample var blk = copyFunc.AppendBasicBlock("entry"); // create instruction builder to build the body var instBuilder = new InstructionBuilder(blk); // create debug info locals for the arguments // NOTE: Debug parameter indices are 1 based! var paramSrc = diBuilder.CreateArgument(copyFunc.DISubProgram, "src", diFile, 11, constFooType, false, 0, 1); var paramDst = diBuilder.CreateArgument(copyFunc.DISubProgram, "pDst", diFile, 12, fooPtr.DIType, false, 0, 2); uint ptrAlign = layout.CallFrameAlignmentOf(fooPtr); // create Locals // NOTE: There's no debug location attached to these instructions. // The debug info will come from the declare intrinsic below. var dstAddr = instBuilder.Alloca(fooPtr) .RegisterName("pDst.addr") .Alignment(ptrAlign); bool param0ByVal = copyFunc.Attributes[FunctionAttributeIndex.Parameter0].Contains(AttributeKind.ByVal); if (param0ByVal) { diBuilder.InsertDeclare(copyFunc.Parameters[0] , paramSrc , new DILocation(module.Context, 11, 43, copyFunc.DISubProgram) , blk ); } instBuilder.Store(copyFunc.Parameters[1], dstAddr) .Alignment(ptrAlign); // insert declare pseudo instruction to attach debug info to the local declarations diBuilder.InsertDeclare(dstAddr, paramDst, new DILocation(module.Context, 12, 38, copyFunc.DISubProgram), blk); if (!param0ByVal) { // since the function's LLVM signature uses a pointer, which is copied locally // inform the debugger to treat it as the value by dereferencing the pointer diBuilder.InsertDeclare(copyFunc.Parameters[0] , paramSrc , diBuilder.CreateExpression(ExpressionOp.deref) , new DILocation(module.Context, 11, 43, copyFunc.DISubProgram) , blk ); } var loadedDst = instBuilder.Load(dstAddr) .Alignment(ptrAlign) .SetDebugLocation(15, 6, copyFunc.DISubProgram); var dstPtr = instBuilder.BitCast(loadedDst, module.Context.Int8Type.CreatePointerType( )) .SetDebugLocation(15, 13, copyFunc.DISubProgram); var srcPtr = instBuilder.BitCast(copyFunc.Parameters[0], module.Context.Int8Type.CreatePointerType( )) .SetDebugLocation(15, 13, copyFunc.DISubProgram); uint pointerSize = layout.IntPtrType(module.Context).IntegerBitWidth; instBuilder.MemCpy(module , dstPtr , srcPtr , module.Context.CreateConstant(pointerSize, layout.ByteSizeOf(foo), false) , ( int )layout.AbiAlignmentOf(foo) , false ).SetDebugLocation(15, 13, copyFunc.DISubProgram); instBuilder.Return( ) .SetDebugLocation(16, 1, copyFunc.DISubProgram); }
public override Value?Visit(FunctionDefinition definition) { definition.ValidateNotNull(nameof(definition)); var function = GetOrDeclareFunction(definition.Signature); if (!function.IsDeclaration) { throw new CodeGeneratorException($"Function {function.Name} cannot be redefined in the same module"); } Debug.Assert(function.DISubProgram != null, "Expected function with non-null DISubProgram"); LexicalBlocks.Push(function.DISubProgram); try { var entryBlock = function.AppendBasicBlock("entry"); InstructionBuilder.PositionAtEnd(entryBlock); // Unset the location for the prologue emission (leading instructions with no // location in a function are considered part of the prologue and the debugger // will run past them when breaking on a function) EmitLocation(null); using (NamedValues.EnterScope( )) { foreach (var param in definition.Signature.Parameters) { var argSlot = InstructionBuilder.Alloca(function.Context.DoubleType) .RegisterName(param.Name); AddDebugInfoForAlloca(argSlot, function, param); InstructionBuilder.Store(function.Parameters[param.Index], argSlot); NamedValues[param.Name] = argSlot; } foreach (LocalVariableDeclaration local in definition.LocalVariables) { var localSlot = InstructionBuilder.Alloca(function.Context.DoubleType) .RegisterName(local.Name); AddDebugInfoForAlloca(localSlot, function, local); NamedValues[local.Name] = localSlot; } EmitBranchToNewBlock("body"); var funcReturn = definition.Body.Accept(this) ?? throw new CodeGeneratorException(ExpectValidFunc); InstructionBuilder.Return(funcReturn); Module.DIBuilder.Finish(function.DISubProgram); function.Verify( ); FunctionPassManager.Run(function); if (definition.IsAnonymous) { function.AddAttribute(FunctionAttributeIndex.Function, AttributeKind.AlwaysInline) .Linkage(Linkage.Private); AnonymousFunctions.Add(function); } return(function); } } catch (CodeGeneratorException) { function.EraseFromParent( ); throw; } }
private Function DefineFunction(Function function, ExpressionContext body) { if (!function.IsDeclaration) { throw new ArgumentException($"Function {function.Name} cannot be redefined", nameof(function)); } var proto = FunctionPrototypes[function.Name]; var basicBlock = function.AppendBasicBlock("entry"); InstructionBuilder.PositionAtEnd(basicBlock); var diFile = Module.DICompileUnit.File; var scope = Module.DICompileUnit; LexicalBlocks.Push(function.DISubProgram); // Unset the location for the prologue emission (leading instructions with no // location in a function are considered part of the prologue and the debugger // will run past them when breaking on a function) EmitLocation(null); NamedValues.Clear( ); foreach (var arg in function.Parameters) { uint line = ( uint )proto.Parameters[( int )(arg.Index)].Span.StartLine; uint col = ( uint )proto.Parameters[( int )(arg.Index)].Span.StartColumn; var argSlot = CreateEntryBlockAlloca(function, arg.Name); DILocalVariable debugVar = Module.DIBuilder.CreateArgument(function.DISubProgram , arg.Name , diFile , line , DoubleType , true , DebugInfoFlags.None , checked (( ushort )(arg.Index + 1)) // Debug index starts at 1! ); Module.DIBuilder.InsertDeclare(argSlot , debugVar , new DILocation(Context, line, col, function.DISubProgram) , InstructionBuilder.InsertBlock ); InstructionBuilder.Store(arg, argSlot); NamedValues[arg.Name] = argSlot; } var funcReturn = body.Accept(this); if (funcReturn == null) { function.EraseFromParent( ); LexicalBlocks.Pop( ); return(null); } InstructionBuilder.Return(funcReturn); LexicalBlocks.Pop( ); Module.DIBuilder.Finish(function.DISubProgram); function.Verify( ); Trace.TraceInformation(function.ToString( )); return(function); }