Beispiel #1
0
        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));
        }
Beispiel #2
0
        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;
            }
        }
Beispiel #4
0
        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);
        }
Beispiel #5
0
        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;
            }
        }
Beispiel #6
0
        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);
        }
Beispiel #7
0
        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);
        }
Beispiel #8
0
        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);
        }
Beispiel #10
0
        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);
        }
Beispiel #11
0
        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;
            }
        }
Beispiel #12
0
        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);
        }