示例#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));
        }
示例#2
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);
        }
示例#3
0
        public override Value VisitBinaryOpExpression([NotNull] BinaryOpExpressionContext context)
        {
            var lhs = context.Lhs.Accept(this);
            var rhs = context.Rhs.Accept(this);

            if (lhs == null || rhs == null)
            {
                return(null);
            }

            switch (context.Op)
            {
            case '<':
            {
                var tmp = InstructionBuilder.Compare(RealPredicate.UnorderedOrLessThan, lhs, rhs)
                          .RegisterName("cmptmp");
                return(InstructionBuilder.UIToFPCast(tmp, InstructionBuilder.Context.DoubleType)
                       .RegisterName("booltmp"));
            }

            case '^':
            {
                var pow = GetOrDeclareFunction(new Prototype("llvm.pow.f64", "value", "power"));
                return(InstructionBuilder.Call(pow, lhs, rhs)
                       .RegisterName("powtmp"));
            }

            case '+':
                return(InstructionBuilder.FAdd(lhs, rhs).RegisterName("addtmp"));

            case '-':
                return(InstructionBuilder.FSub(lhs, rhs).RegisterName("subtmp"));

            case '*':
                return(InstructionBuilder.FMul(lhs, rhs).RegisterName("multmp"));

            case '/':
                return(InstructionBuilder.FDiv(lhs, rhs).RegisterName("divtmp"));

            default:
            {
                // User defined op?
                var opKind = context.GetOperatorInfo(ParserStack.Parser);
                if (opKind != OperatorKind.InfixLeftAssociative && opKind != OperatorKind.InfixRightAssociative)
                {
                    throw new ArgumentException($"Invalid binary operator {context.Op}", nameof(context));
                }

                string calleeName = $"$binary{context.Op}";
                var    function   = GetFunction(calleeName);
                if (function == null)
                {
                    throw new ArgumentException($"Unknown function reference {calleeName}", nameof(context));
                }

                var args = context.Args.Select(a => a.Accept(this)).ToList( );
                return(InstructionBuilder.Call(function, args).RegisterName("calltmp"));
            }
            }
        }
示例#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);
        }
示例#5
0
        public override Value?Visit(BinaryOperatorExpression binaryOperator)
        {
            binaryOperator.ValidateNotNull(nameof(binaryOperator));
            EmitLocation(binaryOperator);

            switch (binaryOperator.Op)
            {
            case BuiltInOperatorKind.Less:
            {
                var tmp = InstructionBuilder.Compare(RealPredicate.UnorderedOrLessThan
                                                     , binaryOperator.Left.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr)
                                                     , binaryOperator.Right.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr)
                                                     ).RegisterName("cmptmp");
                return(InstructionBuilder.UIToFPCast(tmp, InstructionBuilder.Context.DoubleType)
                       .RegisterName("booltmp"));
            }

            case BuiltInOperatorKind.Pow:
            {
                var pow = GetOrDeclareFunction(new Prototype("llvm.pow.f64", "value", "power"));
                return(InstructionBuilder.Call(pow
                                               , binaryOperator.Left.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr)
                                               , binaryOperator.Right.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr)
                                               ).RegisterName("powtmp"));
            }

            case BuiltInOperatorKind.Add:
                return(InstructionBuilder.FAdd(binaryOperator.Left.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr)
                                               , binaryOperator.Right.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr)
                                               ).RegisterName("addtmp"));

            case BuiltInOperatorKind.Subtract:
                return(InstructionBuilder.FSub(binaryOperator.Left.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr)
                                               , binaryOperator.Right.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr)
                                               ).RegisterName("subtmp"));

            case BuiltInOperatorKind.Multiply:
                return(InstructionBuilder.FMul(binaryOperator.Left.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr)
                                               , binaryOperator.Right.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr)
                                               ).RegisterName("multmp"));

            case BuiltInOperatorKind.Divide:
                return(InstructionBuilder.FDiv(binaryOperator.Left.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr)
                                               , binaryOperator.Right.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr)
                                               ).RegisterName("divtmp"));

            case BuiltInOperatorKind.Assign:
                Alloca target = LookupVariable((( VariableReferenceExpression )binaryOperator.Left).Name);
                Value  value  = binaryOperator.Right.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr);
                InstructionBuilder.Store(value, target);
                return(value);

            default:
                throw new CodeGeneratorException($"ICE: Invalid binary operator {binaryOperator.Op}");
            }
        }
示例#6
0
        public override Value VisitFunctionCallExpression([NotNull] FunctionCallExpressionContext context)
        {
            var function = GetFunction(context.CaleeName);

            if (function == null)
            {
                throw new ArgumentException($"Unknown function reference {context.CaleeName}", nameof(context));
            }

            var args = context.Args.Select(ctx => ctx.Accept(this)).ToArray( );

            return(InstructionBuilder.Call(function, args).RegisterName("calltmp"));
        }
        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);
        }
        public override Value Visit(BinaryOperatorExpression binaryOperator)
        {
            switch (binaryOperator.Op)
            {
            case BuiltInOperatorKind.Less:
            {
                var tmp = InstructionBuilder.Compare(RealPredicate.UnorderedOrLessThan
                                                     , binaryOperator.Left.Accept(this)
                                                     , binaryOperator.Right.Accept(this)
                                                     ).RegisterName("cmptmp");
                return(InstructionBuilder.UIToFPCast(tmp, InstructionBuilder.Context.DoubleType)
                       .RegisterName("booltmp"));
            }

            case BuiltInOperatorKind.Pow:
            {
                var pow = GetOrDeclareFunction(new Prototype("llvm.pow.f64", "value", "power"));
                return(InstructionBuilder.Call(pow
                                               , binaryOperator.Left.Accept(this)
                                               , binaryOperator.Right.Accept(this)
                                               ).RegisterName("powtmp"));
            }

            case BuiltInOperatorKind.Add:
                return(InstructionBuilder.FAdd(binaryOperator.Left.Accept(this)
                                               , binaryOperator.Right.Accept(this)
                                               ).RegisterName("addtmp"));

            case BuiltInOperatorKind.Subtract:
                return(InstructionBuilder.FSub(binaryOperator.Left.Accept(this)
                                               , binaryOperator.Right.Accept(this)
                                               ).RegisterName("subtmp"));

            case BuiltInOperatorKind.Multiply:
                return(InstructionBuilder.FMul(binaryOperator.Left.Accept(this)
                                               , binaryOperator.Right.Accept(this)
                                               ).RegisterName("multmp"));

            case BuiltInOperatorKind.Divide:
                return(InstructionBuilder.FDiv(binaryOperator.Left.Accept(this)
                                               , binaryOperator.Right.Accept(this)
                                               ).RegisterName("divtmp"));

            default:
                throw new CodeGeneratorException($"ICE: Invalid binary operator {binaryOperator.Op}");
            }
        }
示例#9
0
        public override Value VisitBinaryOpExpression([NotNull] BinaryOpExpressionContext context)
        {
            var lhs = context.Lhs.Accept(this);
            var rhs = context.Rhs.Accept(this);

            if (lhs == null || rhs == null)
            {
                return(null);
            }

            switch (context.Op)
            {
            case '<':
            {
                var tmp = InstructionBuilder.Compare(RealPredicate.UnorderedOrLessThan, lhs, rhs)
                          .RegisterName("cmptmp");
                return(InstructionBuilder.UIToFPCast(tmp, InstructionBuilder.Context.DoubleType)
                       .RegisterName("booltmp"));
            }

            case '^':
            {
                var pow = GetOrDeclareFunction(new Prototype("llvm.pow.f64", "value", "power"));
                return(InstructionBuilder.Call(pow, lhs, rhs)
                       .RegisterName("powtmp"));
            }

            case '+':
                return(InstructionBuilder.FAdd(lhs, rhs).RegisterName("addtmp"));

            case '-':
                return(InstructionBuilder.FSub(lhs, rhs).RegisterName("subtmp"));

            case '*':
                return(InstructionBuilder.FMul(lhs, rhs).RegisterName("multmp"));

            case '/':
                return(InstructionBuilder.FDiv(lhs, rhs).RegisterName("divtmp"));

            default:
                throw new ArgumentException($"Invalid binary operator {context.Op}", nameof(context));
            }
        }
示例#10
0
        public override Value Visit(FunctionCallExpression functionCall)
        {
            string     targetName = functionCall.FunctionPrototype.Name;
            IrFunction function;

            // try for an extern function declaration
            if (RuntimeState.FunctionDeclarations.TryGetValue(targetName, out Prototype target))
            {
                function = GetOrDeclareFunction(target);
            }
            else
            {
                function = Module.GetFunction(targetName) ?? throw new CodeGeneratorException($"Definition for function {targetName} not found");
            }

            var args = functionCall.Arguments.Select(ctx => ctx.Accept(this)).ToArray( );

            return(InstructionBuilder.Call(function, args).RegisterName("calltmp"));
        }
示例#11
0
        public override Value VisitUnaryOpExpression([NotNull] UnaryOpExpressionContext context)
        {
            var opKind = context.GetOperatorInfo(ParserStack.Parser);

            if (opKind == OperatorKind.None)
            {
                throw new ArgumentException($"invalid unary operator {context.Op}", nameof(context));
            }

            string calleeName = $"$unary{context.Op}";
            var    function   = GetFunction(calleeName);

            if (function == null)
            {
                throw new ArgumentException($"Unknown function reference {calleeName}", nameof(context));
            }

            var arg = context.Rhs.Accept(this);

            return(InstructionBuilder.Call(function, arg).RegisterName("calltmp"));
        }
示例#12
0
        public override Value?Visit(FunctionCallExpression functionCall)
        {
            functionCall.ValidateNotNull(nameof(functionCall));
            string targetName = functionCall.FunctionPrototype.Name;

            IrFunction?function;

            if (RuntimeState.FunctionDeclarations.TryGetValue(targetName, out Prototype target))
            {
                function = GetOrDeclareFunction(target);
            }
            else if (!Module.TryGetFunction(targetName, out function))
            {
                throw new CodeGeneratorException($"Definition for function {targetName} not found");
            }

            var args = (from expr in functionCall.Arguments
                        select expr.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr)
                        ).ToArray();

            return(InstructionBuilder.Call(function, args).RegisterName("calltmp"));
        }