public void ShouldMapAllConfigFields() { var console = new string[0]; var config = new ApplicationConfiguration { IsInGroupMode = true, IsTimedMode = true, IsVerbodeMode = true }; config.DefaultArguments.ExecuteAlias = "alias"; config.DefaultArguments.MethodArguments = new[] { "config" }; config.DefaultArguments.ConstructorArguments = new[] { "config" }; builder = new InstructionBuilder(console, config); var instructions = builder.Build(); Assert.That(instructions.ExecuteAlias.Alias, Is.EqualTo("alias")); Assert.That(instructions.Instructions.ContainsKey(InstructionType.DisplayHelp), Is.False); Assert.That(instructions.Instructions.ContainsKey(InstructionType.DisplayList), Is.False); Assert.That(instructions.Instructions[InstructionType.Constructor].Arguments, Is.EqualTo(new[] { "config" })); Assert.That(instructions.Instructions[InstructionType.Method].Arguments, Is.EqualTo(new[] { "config" })); Assert.That(instructions.Instructions[InstructionType.Group], Is.Not.Null); Assert.That(instructions.Instructions[InstructionType.Timed], Is.Not.Null); Assert.That(instructions.Instructions[InstructionType.Verbose], Is.Not.Null); }
private static Function EmitFunction(Module module, MethodBase method) { var methodInfo = method as MethodInfo; var methodConstructor = method as ConstructorInfo; var declaringType = method.DeclaringType; if (methodInfo == null && methodConstructor == null) throw new CudaSharpException("Unknown MethodBase type " + method.GetType().FullName); if (declaringType == null) throw new CudaSharpException("Could not find the declaring type of " + method.Name.StripNameToValidPtx()); var parameters = method.GetParameters().Select(p => p.ParameterType); if (methodConstructor != null) parameters = new[] { declaringType.MakeByRefType() }.Concat(parameters); if (methodInfo != null && methodInfo.IsStatic == false) { if (declaringType.IsValueType == false) throw new CudaSharpException("Cannot compile object instance methods (did you forget to mark the method as static?)"); parameters = new[] { declaringType.MakeByRefType() }.Concat(parameters); } var llvmParameters = parameters.Select(t => ConvertType(module, t)).ToArray(); var funcType = new FunctionType(ConvertType(module, methodInfo == null ? typeof(void) : methodInfo.ReturnType), llvmParameters); var intrinsic = method.GetCustomAttribute<Gpu.BuiltinAttribute>(); if (intrinsic != null) { var name = intrinsic.Intrinsic; var preExisting = module.GetFunction(name); if (preExisting != null) return preExisting; return module.CreateFunction(name, funcType); } var function = module.CreateFunction(methodConstructor == null ? method.Name.StripNameToValidPtx() : declaringType.Name.StripNameToValidPtx() + "_ctor", funcType); var block = new Block("entry", module.Context, function); var writer = new InstructionBuilder(module.Context, block); var opcodes = method.Disassemble().ToList(); FindBranchTargets(opcodes, module.Context, function); var body = method.GetMethodBody(); var efo = new EmitFuncObj(module, function, body, writer, null, new Stack<Value>(), body == null ? null : new Value[body.LocalVariables.Count], new Value[llvmParameters.Length]); PrintHeader(efo); foreach (var opcode in opcodes) { if (EmitFunctions.ContainsKey(opcode.Opcode) == false) throw new CudaSharpException("Unsupported CIL instruction " + opcode.Opcode); var func = EmitFunctions[opcode.Opcode]; efo.Argument = opcode.Parameter; func(efo); } return function; }
public void ShouldMapAllConsoleFields() { var console = new[] { "alias", "-m", "console", "-c", "console", "-v", "-t", "-g", "-h", "-l" }; builder = new InstructionBuilder(console, new ApplicationConfiguration()); var instructions = builder.Build(); Assert.That(instructions.ExecuteAlias.Alias, Is.EqualTo("alias")); Assert.That(instructions.Instructions[InstructionType.DisplayHelp], Is.Not.Null); Assert.That(instructions.Instructions[InstructionType.DisplayList], Is.Not.Null); Assert.That(instructions.Instructions[InstructionType.Constructor].Arguments, Is.EqualTo(new[] { "console" })); Assert.That(instructions.Instructions[InstructionType.Method].Arguments, Is.EqualTo(new[] { "console" })); Assert.That(instructions.Instructions[InstructionType.Group], Is.Not.Null); Assert.That(instructions.Instructions[InstructionType.Timed], Is.Not.Null); Assert.That(instructions.Instructions[InstructionType.Verbose], Is.Not.Null); }
public override Value?Visit(VarInExpression varInExpression) { varInExpression.ValidateNotNull(nameof(varInExpression)); using (NamedValues.EnterScope( )) { EmitBranchToNewBlock("VarInScope"); foreach (var localVar in varInExpression.LocalVariables) { Alloca alloca = LookupVariable(localVar.Name); Value initValue = Context.CreateConstant(0.0); if (localVar.Initializer != null) { initValue = localVar.Initializer.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr); } InstructionBuilder.Store(initValue, alloca); } return(varInExpression.Body.Accept(this)); } }
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 void Ps3p_GetTrampoline() { var arch = new PowerPcBe64Architecture("ppc-be-64"); var m = new InstructionBuilder(arch, Address.Ptr32(0x10030000)); m.Lis(m.r11, 0x1006); m.Lwz(m.r11, 0x1234, m.r11); m.Mtctr(m.r11); m.Bctr(); var host = mr.Stub <IRewriterHost>(); host.Stub(h => h.GetImportedProcedure( Arg <Address> .Matches(a => a.ToLinear() == 0x10061234), Arg <Address> .Is.Anything)).Return(new ExternalProcedure("foo", null)); mr.ReplayAll(); ProcedureBase proc = arch.GetTrampolineDestination(m.Instructions, host); Assert.IsNotNull(proc); Assert.AreEqual("foo", proc.Name); }
public void Ps3p_GetTrampoline() { var arch = new PowerPcBe64Architecture(new ServiceContainer(), "ppc-be-64", new Dictionary <string, object>()); var m = new InstructionBuilder(arch, Address.Ptr32(0x10030000)); m.Lis(m.r11, 0x1006); m.Lwz(m.r11, 0x1234, m.r11); m.Mtctr(m.r11); m.Bctr(); var host = new Mock <IRewriterHost>(); host.Setup(h => h.GetImportedProcedure( It.IsNotNull <IProcessorArchitecture>(), It.Is <Address>(a => a.ToLinear() == 0x10061234), It.IsAny <Address>())) .Returns(new ExternalProcedure("foo", new FunctionType())); ProcedureBase proc = arch.GetTrampolineDestination(m.Instructions, host.Object); Assert.IsNotNull(proc); Assert.AreEqual("foo", proc.Name); }
/// <summary> /// Tells if a particular value is strictly dominated by another value, /// that is, if control cannot flow to the value unless it first flowed /// through the dominator value. /// </summary> /// <param name="value"> /// An value that might be dominated by <paramref name="dominator"/>. /// </param> /// <param name="dominator"> /// An value that might dominate <paramref name="value"/>. /// </param> /// <returns> /// <c>true</c> if <paramref name="value"/> is strictly dominated by /// <paramref name="dominator"/>; otherwise, <c>false</c>. /// </returns> public bool IsStrictlyDominatedBy(InstructionBuilder value, ValueTag dominator) { if (value is NamedInstructionBuilder) { return(IsStrictlyDominatedBy((NamedInstructionBuilder)value, dominator, value.Graph)); } else { var block = value.Block; var dominatorBlock = value.Graph.GetValueParent(dominator); if (block == dominatorBlock) { // Anonymous flow instructions are always strictly dominated by // named values in the same block. return(true); } else { return(IsStrictlyDominatedBy(block, dominatorBlock)); } } }
public CodeGenerator(DynamicRuntimeState globalState, TargetMachine machine, string sourcePath, bool disableOptimization = false) : base(null) { globalState.ValidateNotNull(nameof(globalState)); machine.ValidateNotNull(nameof(machine)); if (globalState.LanguageLevel > LanguageLevel.MutableVariables) { throw new ArgumentException("Language features not supported by this generator", nameof(globalState)); } RuntimeState = globalState; Context = new Context( ); TargetMachine = machine; DisableOptimizations = disableOptimization; InstructionBuilder = new InstructionBuilder(Context); #region InitializeModuleAndPassManager Module = Context.CreateBitcodeModule(Path.GetFileName(sourcePath), SourceLanguage.C, sourcePath, "Kaleidoscope Compiler"); Debug.Assert(Module.DICompileUnit != null, "Expected non null compile unit"); Debug.Assert(Module.DICompileUnit.File != null, "Expected non-null file for compile unit"); Module.TargetTriple = machine.Triple; Module.Layout = TargetMachine.TargetData; DoubleType = new DebugBasicType(Context.DoubleType, Module, "double", DiTypeKind.Float); FunctionPassManager = new FunctionPassManager(Module); FunctionPassManager.AddPromoteMemoryToRegisterPass( ); if (!DisableOptimizations) { FunctionPassManager.AddInstructionCombiningPass( ) .AddReassociatePass( ) .AddGVNPass( ) .AddCFGSimplificationPass( ); } FunctionPassManager.Initialize( ); #endregion }
private (Function Function, int JitHandle) 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, default);
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")); }
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 bool TryGetCallee(InstructionBuilder instruction, out IMethod callee) { var proto = instruction.Prototype; if (proto is CallPrototype) { var callProto = (CallPrototype)proto; if (callProto.Lookup == MethodLookup.Static) { callee = callProto.Callee; return(true); } } else if (proto is NewObjectPrototype) { var newObjproto = (NewObjectPrototype)proto; callee = newObjproto.Constructor; return(true); } callee = null; return(false); }
public override Value Visit(VarInExpression varInExpression) { EmitLocation(varInExpression); using (NamedValues.EnterScope( )) { EmitBranchToNewBlock("VarInScope"); foreach (var localVar in varInExpression.LocalVariables) { EmitLocation(localVar); Alloca alloca = LookupVariable(localVar.Name); Value initValue = Context.CreateConstant(0.0); if (localVar.Initializer != null) { initValue = localVar.Initializer.Accept(this); } InstructionBuilder.Store(initValue, alloca); } EmitLocation(varInExpression); return(varInExpression.Body.Accept(this)); } }
public EmitFuncObj(Module module, Function function, MethodBody cilMethod, InstructionBuilder instructionBuilder, object argument, Stack <Value> stack, Value[] locals, Value[] parameters) { Module = module; Function = function; CilMethod = cilMethod; Builder = instructionBuilder; Argument = argument; Stack = stack; Locals = locals; Parameters = parameters; }
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); }
private static bool TrySimplify(InstructionBuilder instruction) { var proto = instruction.Prototype; if (proto is ConstrainedCallPrototype) { // // constrained_call(f)(this_ref, args...) // // is equivalent to // // call(impl(f), static)(this_ref, args...) if this_ref == T ref* where T is a value type, // call(f, virtual)(load(this_ref), args...) if this_ref == T any* ref*. var constrainedCallProto = (ConstrainedCallPrototype)proto; var thisArg = constrainedCallProto.GetThisArgument(instruction.Instruction); var thisRefType = instruction.Graph.GetValueType(thisArg) as PointerType; if (thisRefType == null) { return(false); } var thisValType = thisRefType.ElementType; if (thisValType is PointerType) { instruction.Instruction = Instruction.CreateCall( constrainedCallProto.Callee, MethodLookup.Virtual, instruction.InsertBefore( Instruction.CreateLoad(thisValType, thisArg), "this_value"), constrainedCallProto.GetArgumentList(instruction.Instruction).ToArray()); TrySimplify(instruction); return(true); } else if (!(thisValType is IGenericParameter)) { var realCallee = thisValType.GetImplementationOf(constrainedCallProto.Callee); if (realCallee != null && realCallee.ParentType == thisValType) { instruction.Instruction = Instruction.CreateCall( realCallee, MethodLookup.Static, constrainedCallProto.GetThisArgument(instruction.Instruction), constrainedCallProto.GetArgumentList(instruction.Instruction).ToArray()); return(true); } } } else if (proto is CallPrototype) { var callProto = (CallPrototype)proto; if (callProto.Callee.IsStatic) { return(false); } var thisType = GetActualType( callProto.GetThisArgument(instruction.Instruction), instruction.Graph.ImmutableGraph) as PointerType; if (thisType == null) { return(false); } var realCallee = thisType.ElementType.GetImplementationOf(callProto.Callee); if (realCallee == null || realCallee == callProto.Callee) { return(false); } instruction.Instruction = Instruction.CreateCall( realCallee, realCallee.IsVirtual() ? MethodLookup.Virtual : MethodLookup.Static, instruction.InsertBefore( Instruction.CreateReinterpretCast( realCallee.ParentType.MakePointerType(thisType.Kind), callProto.GetThisArgument(instruction.Instruction))), callProto.GetArgumentList(instruction.Instruction).ToArray()); return(true); } return(false); }
/* * // Output for-loop as: * // ... * // start = startexpr * // goto loop * // loop: * // variable = phi [start, loopheader], [nextvariable, loopend] * // ... * // bodyexpr * // ... * // loopend: * // step = stepexpr * // nextvariable = variable + step * // endcond = endexpr * // br endcond, loop, endloop * // outloop: */ public override Value VisitForExpression([NotNull] ForExpressionContext context) { var function = InstructionBuilder.InsertBlock.ContainingFunction; string varName = context.Initializer.Name; var allocaVar = CreateEntryBlockAlloca(function, varName); // Emit the start code first, without 'variable' in scope. Value startVal = null; if (context.Initializer.Value != null) { startVal = context.Initializer.Value.Accept(this); if (startVal == null) { return(null); } } else { startVal = Context.CreateConstant(0.0); } // store the value into allocated location InstructionBuilder.Store(startVal, allocaVar); // Make the new basic block for the loop header, inserting after current // block. var preHeaderBlock = InstructionBuilder.InsertBlock; var loopBlock = Context.CreateBasicBlock("loop", function); // Insert an explicit fall through from the current block to the loopBlock. InstructionBuilder.Branch(loopBlock); // Start insertion in loopBlock. InstructionBuilder.PositionAtEnd(loopBlock); // Start the PHI node with an entry for Start. var variable = InstructionBuilder.PhiNode(Context.DoubleType) .RegisterName(varName); variable.AddIncoming(startVal, preHeaderBlock); // Within the loop, the variable is defined equal to the PHI node. If it // shadows an existing variable, we have to restore it, so save it now. NamedValues.TryGetValue(varName, out Alloca oldValue); NamedValues[varName] = allocaVar; // Emit the body of the loop. This, like any other expr, can change the // current BB. Note that we ignore the value computed by the body, but don't // allow an error. if (context.BodyExpression.Accept(this) == null) { return(null); } Value stepValue = Context.CreateConstant(1.0); // DEBUG: How does ANTLR represent optional context (Null or IsEmpty == true) if (context.StepExpression != null) { stepValue = context.StepExpression.Accept(this); if (stepValue == null) { return(null); } } // Compute the end condition. Value endCondition = context.EndExpression.Accept(this); if (endCondition == null) { return(null); } var curVar = InstructionBuilder.Load(allocaVar) .RegisterName(varName); var nextVar = InstructionBuilder.FAdd(curVar, stepValue) .RegisterName("nextvar"); InstructionBuilder.Store(nextVar, allocaVar); // Convert condition to a bool by comparing non-equal to 0.0. endCondition = InstructionBuilder.Compare(RealPredicate.OrderedAndNotEqual, endCondition, Context.CreateConstant(1.0)) .RegisterName("loopcond"); // Create the "after loop" block and insert it. var loopEndBlock = InstructionBuilder.InsertBlock; var afterBlock = Context.CreateBasicBlock("afterloop", function); // Insert the conditional branch into the end of LoopEndBB. InstructionBuilder.Branch(endCondition, loopBlock, afterBlock); InstructionBuilder.PositionAtEnd(afterBlock); // Add a new entry to the PHI node for the backedge. variable.AddIncoming(nextVar, loopEndBlock); // Restore the unshadowed variable. if (oldValue != null) { NamedValues[varName] = oldValue; } else { NamedValues.Remove(varName); } // for expr always returns 0.0 for consistency, there is no 'void' return(Context.DoubleType.GetNullValue( )); }
public override Value?Visit(ForInExpression forInExpression) { forInExpression.ValidateNotNull(nameof(forInExpression)); EmitLocation(forInExpression); var function = InstructionBuilder.InsertFunction; if (function is null) { throw new InternalCodeGeneratorException("ICE: Expected block attached to a function at this point"); } string varName = forInExpression.LoopVariable.Name; Alloca allocaVar = LookupVariable(varName); // Emit the start code first, without 'variable' in scope. Value?startVal; if (forInExpression.LoopVariable.Initializer != null) { startVal = forInExpression.LoopVariable.Initializer.Accept(this); if (startVal is null) { return(null); } } else { startVal = Context.CreateConstant(0.0); } // store the value into allocated location InstructionBuilder.Store(startVal, allocaVar); // Make the new basic block for the loop header. var loopBlock = function.AppendBasicBlock("loop"); // Insert an explicit fall through from the current block to the loopBlock. InstructionBuilder.Branch(loopBlock); // Start insertion in loopBlock. InstructionBuilder.PositionAtEnd(loopBlock); // Within the loop, the variable is defined equal to the PHI node. // So, push a new scope for it and any values the body might set using (NamedValues.EnterScope( )) { EmitBranchToNewBlock("ForInScope"); // Emit the body of the loop. This, like any other expression, can change the // current BB. Note that we ignore the value computed by the body, but don't // allow an error. if (forInExpression.Body.Accept(this) == null) { return(null); } Value?stepValue = forInExpression.Step.Accept(this); if (stepValue == null) { return(null); } // Compute the end condition. Value?endCondition = forInExpression.Condition.Accept(this); if (endCondition == null) { return(null); } // since the Alloca is created as a non-opaque pointer it is OK to just use the // ElementType. If full opaque pointer support was used, then the Lookup map // would need to include the type of the value allocated. var curVar = InstructionBuilder.Load(allocaVar.ElementType, allocaVar) .RegisterName(varName); var nextVar = InstructionBuilder.FAdd(curVar, stepValue) .RegisterName("nextvar"); InstructionBuilder.Store(nextVar, allocaVar); // Convert condition to a bool by comparing non-equal to 0.0. endCondition = InstructionBuilder.Compare(RealPredicate.OrderedAndNotEqual, endCondition, Context.CreateConstant(0.0)) .RegisterName("loopcond"); // Create the "after loop" block and insert it. var afterBlock = function.AppendBasicBlock("afterloop"); // Insert the conditional branch into the end of LoopEndBB. InstructionBuilder.Branch(endCondition, loopBlock, afterBlock); InstructionBuilder.PositionAtEnd(afterBlock); // for expression always returns 0.0 for consistency, there is no 'void' return(Context.DoubleType.GetNullValue( )); } }
public EmitFuncObj(Module module, Function function, MethodBody cilMethod, InstructionBuilder instructionBuilder, object argument, Stack<Value> stack, Value[] locals, Value[] parameters) { Module = module; Function = function; CilMethod = cilMethod; Builder = instructionBuilder; Argument = argument; Stack = stack; Locals = locals; Parameters = parameters; }
public override Value?Visit(ConditionalExpression conditionalExpression) { conditionalExpression.ValidateNotNull(nameof(conditionalExpression)); var result = LookupVariable(conditionalExpression.ResultVariable.Name); EmitLocation(conditionalExpression); var condition = conditionalExpression.Condition.Accept(this); if (condition == null) { return(null); } EmitLocation(conditionalExpression); var condBool = InstructionBuilder.Compare(RealPredicate.OrderedAndNotEqual, condition, Context.CreateConstant(0.0)) .RegisterName("ifcond"); var function = InstructionBuilder.InsertFunction; if (function is null) { throw new InternalCodeGeneratorException("ICE: expected block that is attached to a function at this point"); } var thenBlock = function.AppendBasicBlock("then"); var elseBlock = function.AppendBasicBlock("else"); var continueBlock = function.AppendBasicBlock("ifcont"); InstructionBuilder.Branch(condBool, thenBlock, elseBlock); // generate then block instructions InstructionBuilder.PositionAtEnd(thenBlock); // InstructionBuilder.InserBlock after this point is !null Debug.Assert(InstructionBuilder.InsertBlock != null, "expected non-null InsertBlock"); var thenValue = conditionalExpression.ThenExpression.Accept(this); if (thenValue == null) { return(null); } InstructionBuilder.Store(thenValue, result); InstructionBuilder.Branch(continueBlock); // generate else block InstructionBuilder.PositionAtEnd(elseBlock); var elseValue = conditionalExpression.ElseExpression.Accept(this); if (elseValue == null) { return(null); } InstructionBuilder.Store(elseValue, result); InstructionBuilder.Branch(continueBlock); // generate continue block InstructionBuilder.PositionAtEnd(continueBlock); // since the Alloca is created as a non-opaque pointer it is OK to just use the // ElementType. If full opaque pointer support was used, then the Lookup map // would need to include the type of the value allocated. return(InstructionBuilder.Load(result.ElementType, result) .RegisterName("ifresult")); }
public static Value FloatExtend(this InstructionBuilder builder, Value value, LLVM.Type type, string name = "") { return((Value)ValueConstructor.Invoke(new object[] { LLVMBuildFPExt(builder, value, type, name) })); }
public EmitFuncObj(Context context, Module module, Function function, InstructionBuilder instructionBuilder, object argument, Stack<Value> stack, Value[] locals, Value[] parameters) { Context = context; Module = module; Function = function; Builder = instructionBuilder; Argument = argument; Stack = stack; Locals = locals; Parameters = parameters; }
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; } }
public static Value SignedIntToFloat(this InstructionBuilder builder, Value value, LLVM.Type type, string name = "") { return((Value)ValueConstructor.Invoke(new object[] { LLVMBuildSIToFP(builder, value, type, name) })); }
public override Value Visit(ForInExpression forInExpression) { var function = InstructionBuilder.InsertBlock.ContainingFunction; string varName = forInExpression.LoopVariable.Name; // Emit the start code first, without 'variable' in scope. Value startVal; if (forInExpression.LoopVariable.Initializer != null) { startVal = forInExpression.LoopVariable.Initializer.Accept(this); if (startVal == null) { return(null); } } else { startVal = Context.CreateConstant(0.0); } // Make the new basic block for the loop header, inserting after current // block. var preHeaderBlock = InstructionBuilder.InsertBlock; var loopBlock = function.AppendBasicBlock("loop"); // Insert an explicit fall through from the current block to the loopBlock. InstructionBuilder.Branch(loopBlock); // Start insertion in loopBlock. InstructionBuilder.PositionAtEnd(loopBlock); // Start the PHI node with an entry for Start. var variable = InstructionBuilder.PhiNode(Context.DoubleType) .RegisterName(varName); variable.AddIncoming(startVal, preHeaderBlock); // Within the loop, the variable is defined equal to the PHI node. // So, push a new scope for it and any values the body might set using (NamedValues.EnterScope( )) { NamedValues[varName] = variable; // Emit the body of the loop. This, like any other expression, can change the // current BB. Note that we ignore the value computed by the body, but don't // allow an error. if (forInExpression.Body.Accept(this) == null) { return(null); } Value stepValue = forInExpression.Step.Accept(this); if (stepValue == null) { return(null); } var nextVar = InstructionBuilder.FAdd(variable, stepValue) .RegisterName("nextvar"); // Compute the end condition. Value endCondition = forInExpression.Condition.Accept(this); if (endCondition == null) { return(null); } // Convert condition to a bool by comparing non-equal to 0.0. endCondition = InstructionBuilder.Compare(RealPredicate.OrderedAndNotEqual, endCondition, Context.CreateConstant(0.0)) .RegisterName("loopcond"); // capture loop end result block for loop variable PHI node var loopEndBlock = InstructionBuilder.InsertBlock; // Create the "after loop" block and insert it. var afterBlock = function.AppendBasicBlock("afterloop"); // Insert the conditional branch into the end of LoopEndBB. InstructionBuilder.Branch(endCondition, loopBlock, afterBlock); InstructionBuilder.PositionAtEnd(afterBlock); // Add a new entry to the PHI node for the back-edge. variable.AddIncoming(nextVar, loopEndBlock); // for expression always returns 0.0 for consistency, there is no 'void' return(Context.DoubleType.GetNullValue( )); } }
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); }
public override Value VisitBinaryOpExpression([NotNull] BinaryOpExpressionContext context) { EmitLocation(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 abstract void Lower(InstructionBuilder builder);
public override Matcher Build() { _entries.Sort((x, y) => { var comparison = x.Order.CompareTo(y.Order); if (comparison != 0) { return(comparison); } comparison = y.Precedence.CompareTo(x.Precedence); if (comparison != 0) { return(comparison); } return(x.Pattern.TemplateText.CompareTo(y.Pattern.TemplateText)); }); var roots = new List <OrderNode>(); for (var i = 0; i < _entries.Count; i++) { var entry = _entries[i]; var parent = (SequenceNode)GetOrCreateRootNode(roots, entry.Order); for (var depth = 0; depth < entry.Pattern.Segments.Count; depth++) { var segment = entry.Pattern.Segments[depth]; if (segment.IsSimple && segment.Parts[0].IsLiteral) { var branch = parent.GetNode <BranchNode>() ?? parent.AddNode(new BranchNode(depth)); var index = branch.Literals.IndexOf(segment.Parts[0].Text); if (index == -1) { branch.Literals.Add(segment.Parts[0].Text); branch.AddNode(new SequenceNode(depth + 1)); index = branch.Children.Count - 1; } parent = (SequenceNode)branch.Children[index]; } else if (segment.IsSimple && segment.Parts[0].IsParameter) { var parameter = parent.GetNode <ParameterNode>() ?? parent.AddNode(new ParameterNode(depth)); if (parameter.Children.Count == 0) { parameter.AddNode(new SequenceNode(depth + 1)); } parent = (SequenceNode)parameter.Children[0]; } else { throw new InvalidOperationException("Not implemented!"); } } parent.AddNode(new AcceptNode(entry.Endpoint)); } var builder = new InstructionBuilder(); for (var i = 0; i < roots.Count; i++) { roots[i].Lower(builder); } var(instructions, endpoints, tables) = builder; return(new InstructionMatcher(instructions, endpoints, tables)); }
private static Function EmitFunction(Context context, Module module, MethodInfo method) { var funcType = new FunctionType(ConvertType(context, method.ReturnType), AnalyzeArguments(context, method.GetParameters())); var intrinsic = method.GetCustomAttribute<Gpu.BuiltinAttribute>(); if (intrinsic != null) { var name = intrinsic.Intrinsic; var preExisting = module.GetFunction(name); if (preExisting != null) return preExisting; return module.CreateFunction(name, funcType); } var function = module.CreateFunction(method.Name, funcType); var block = new Block("entry", context, function); var writer = new InstructionBuilder(context, block); var opcodes = method.Decompile().ToList(); FindBranchTargets(opcodes, context, function); var body = method.GetMethodBody(); var efo = new EmitFuncObj(context, module, function, writer, null, new Stack<Value>(), body == null ? null : new Value[body.LocalVariables.Count], new Value[method.GetParameters().Length]); foreach (var opcode in opcodes) { if (EmitFunctions.ContainsKey(opcode.Opcode) == false) throw new Exception("Unsupported CIL instruction " + opcode.Opcode); var func = EmitFunctions[opcode.Opcode]; efo.Argument = opcode.Parameter; func(efo); } return function; }