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 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); }
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")); } } }
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(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}"); } }
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}"); } }
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)); } }
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")); }
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")); }
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")); }