Exemple #1
0
        private static MethodInfo CompileMethod(Function function, CompilationContext context)
        {
            var methodBuilder = context.TypeBuilder.DefineMethod(
                function.Name,
                MethodAttributes.Static | MethodAttributes.Public, // TODO
                GetMsilType(function.FunctionType.ReturnType),
                Array.Empty <System.Type>());                      // TODO: parameters

            if (function.Name == "main")
            {
                context.AssemblyBuilder.SetEntryPoint(methodBuilder);
            }

            var ilGenerator = methodBuilder.GetILGenerator();

            var functionCompilationContext = new FunctionCompilationContext(context, ilGenerator);

            foreach (var basicBlock in function.BasicBlocks)
            {
                var basicBlockLabel = functionCompilationContext.GetOrCreateLabel(basicBlock);
                ilGenerator.MarkLabel(basicBlockLabel);

                foreach (var instruction in basicBlock.Instructions)
                {
                    CompileInstruction(instruction, functionCompilationContext);
                }
            }

            return(methodBuilder);
        }
        private static void CompileInstruction(
            Instruction instruction,
            FunctionCompilationContext context)
        {
            var ilGenerator = context.ILGenerator;

            switch (instruction)
            {
            case AllocaInst _:
            {
                var operand = instruction.Operands[0];
                var local   = ilGenerator.DeclareLocal(GetMsilType(operand.Type));
                context.Locals.Add(instruction, local);
                break;
            }

            case StoreInst _:
            {
                EmitLoad(ilGenerator, instruction.Operands[0], context);
                EmitStloc(ilGenerator, instruction.Operands[1], context);
                break;
            }

            case BranchInst i:
            {
                if (i.IsConditional)
                {
                    EmitLoad(ilGenerator, i.Condition, context);
                    ilGenerator.Emit(OpCodes.Brtrue, context.GetOrCreateLabel(instruction.Operands[2]));
                    ilGenerator.Emit(OpCodes.Br, context.GetOrCreateLabel(instruction.Operands[1]));
                }
                else
                {
                    var label = context.GetOrCreateLabel(instruction.Operands[0]);
                    ilGenerator.Emit(OpCodes.Br, label);
                }
                break;
            }

            case LoadInst _:
            {
                EmitLoad(ilGenerator, instruction.Operands[0], context);
                EmitStoreResult(ilGenerator, instruction, context);
                break;
            }

            case ICmpInst i:
            {
                EmitLoad(ilGenerator, instruction.Operands[0], context);
                EmitLoad(ilGenerator, instruction.Operands[1], context);
                switch (i.ICmpPredicate)
                {
                case IntPredicate.SLE:
                    ilGenerator.Emit(OpCodes.Cgt);
                    ilGenerator.Emit(OpCodes.Ldc_I4_0);
                    ilGenerator.Emit(OpCodes.Ceq);
                    break;

                case IntPredicate.SLT:
                    ilGenerator.Emit(OpCodes.Clt);
                    break;

                default:
                    throw new NotImplementedException();
                }
                EmitStoreResult(ilGenerator, instruction, context);
                break;
            }

            case Add _:
            {
                EmitLoad(ilGenerator, instruction.Operands[0], context);
                EmitLoad(ilGenerator, instruction.Operands[1], context);
                ilGenerator.Emit(OpCodes.Add);
                EmitStoreResult(ilGenerator, instruction, context);
                break;
            }

            case CallInst _:
            {
                // TODO: This is totally hardcoded to printf call.
                var fieldRef = instruction.Operands[0].Operands[0];
                ilGenerator.Emit(OpCodes.Ldsfld, context.CompilationContext.Globals[fieldRef]);
                EmitLoad(ilGenerator, instruction.Operands[1], context);
                ilGenerator.EmitCall(
                    OpCodes.Call,
                    GetOrCreateMethod((Function)instruction.Operands[2], context.CompilationContext),
                    new[] { typeof(int) });
                ilGenerator.Emit(OpCodes.Pop);
                break;
            }

            case ReturnInst _:
            {
                if (instruction.Operands.Count > 0)
                {
                    var returnOperand = instruction.Operands[0];
                    EmitLoad(ilGenerator, returnOperand, context);
                }
                ilGenerator.Emit(OpCodes.Ret);
                break;
            }

            default:
                throw new NotImplementedException();
            }
        }