diff --git a/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/ArgStack.cs b/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/ArgStack.cs
deleted file mode 100644
index 76ce9f352830..000000000000
--- a/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/ArgStack.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-using System;
-using System.Collections.Generic;
-using LLVMSharp;
-
-
-namespace Mono.Compiler.BigStep
-{
-
- public struct ArgStackValue {
- public LLVMValueRef Ptr;
- public BSType StoredType;
- }
-
-
- ///
- /// The argument stack.
- ///
- /// We are going to want to clone this thing
- ///
- class ArgStack
- {
- //WISH: this really ought to be an immutable collection
- private Stack data;
-
- public ArgStack () : this (new Stack ()) {}
-
- ArgStack (Stack data) {
- this.data = data;
- }
-
- public ArgStack Clone () {
- ArgStackValue[] arr = new ArgStackValue[data.Count];
- data.CopyTo (arr, 0);
- Array.Reverse (arr);
- return new ArgStack (new Stack(arr));
- }
-
- public void Push (ArgStackValue x)
- {
- data.Push (x);
- }
-
- public ArgStackValue Pop ()
- {
- return data.Pop ();
- }
-
- public int Count
- {
- get { return data.Count; }
- }
- }
-
-}
diff --git a/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/BSType.cs b/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/BSType.cs
deleted file mode 100644
index a954490b476d..000000000000
--- a/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/BSType.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-using System;
-using System.Reflection;
-
-using SimpleJit.Metadata;
-using Mono.Compiler;
-
-using LLVMSharp;
-
-namespace Mono.Compiler.BigStep {
-
- ///
- /// Tie together runtime types and LLVM types.
- ///
- public class BSType
- {
- ClrType rttype;
- LLVMTypeRef? lowered;
-
- private BSType (ClrType t)
- {
- rttype = t;
- }
-
- private BSType (BSType t, LLVMTypeRef l)
- : this (t.rttype)
- {
- lowered = l;
- }
-
- public static BSType FromClrType (ClrType t)
- {
- // TODO: cache?
- return new BSType (t);
- }
-
- public static BSType FromTypeInfo (TypeInfo t)
- {
- return FromClrType (RuntimeInformation.ClrTypeFromType (t));
- }
-
- public LLVMTypeRef Lowered {
- get {
- if (lowered != null)
- return (LLVMTypeRef)lowered;
- else
- throw new NotImplementedException ("Don't know how to lower " + rttype.ToString ());
- }
- }
-
- internal BSType LowerAs (LLVMTypeRef l)
- {
- return new BSType (this, l);
- }
-
-
- }
-
- ///
- /// Some predefined BSType values from the runtime
- ///
- struct BSTypes {
- public readonly BSType VoidType;
- public readonly BSType Int32Type;
-
- internal BSTypes (IRuntimeInformation runtimeInfo) {
- VoidType = BSType.FromClrType (runtimeInfo.VoidType).LowerAs (LLVMTypeRef.VoidType ());
- Int32Type = BSType.FromClrType (runtimeInfo.Int32Type).LowerAs (LLVMTypeRef.Int32Type ());
- }
- }
-
-}
diff --git a/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/BigStep.cs b/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/BigStep.cs
index a4bf140b7ba7..0b3088a581c2 100644
--- a/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/BigStep.cs
+++ b/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/BigStep.cs
@@ -54,132 +54,19 @@ public CompilationResult CompileMethod (MethodInfo methodInfo, out NativeCodeHan
}
}
- private CompilationResult CompileMethodOld (MethodInfo methodInfo, out NativeCodeHandle result)
+ internal static void InitializeLLVM_OSX_AMD64 (LLVMMCJITCompilerOptions mcjitCompilerOptions)
{
- var builder = new Builder ();
- var env = new Env (RuntimeInfo, methodInfo);
-
- Preamble (env, builder);
-
- result = NativeCodeHandle.Invalid;
- var r = TranslateBody (env, builder, methodInfo.Body);
- if (r != Ok)
- return r;
- r = builder.Finish (out result);
- return r;
- }
-
- // translation environment for a single function
- class Env {
- private ArgStack currentStack;
- private IRuntimeInformation RuntimeInfo { get; }
- internal ArgStack ArgStack { get => currentStack ; }
- public Env (IRuntimeInformation runtimeInfo, MethodInfo methodInfo)
- {
- this.RuntimeInfo = runtimeInfo;
- this.MethodName = methodInfo.ClassInfo.Name + "::" + methodInfo.Name;
- this.BSTypes = new BSTypes (runtimeInfo);
- this.ReturnType = methodInfo.ReturnType;
-
- var parameters = methodInfo.Parameters;
- this.ArgumentTypes = new ClrType [parameters.Count];
- int i = 0;
- foreach (ParameterInfo pi in parameters)
- this.ArgumentTypes [i++] = pi.ParameterType;
-
- currentStack = new ArgStack ();
- }
-
- public ClrType ReturnType { get; }
- public ClrType[] ArgumentTypes { get; }
-
- public readonly BSTypes BSTypes;
- public readonly string MethodName;
- }
-
- // encapsulate the LLVM module and builder here.
- class Builder {
- static readonly LLVMBool Success = new LLVMBool (0);
-
- LLVMModuleRef module;
- LLVMBuilderRef builder;
- LLVMValueRef function;
- LLVMBasicBlockRef entry;
- LLVMBasicBlockRef currentBB;
- LLVMValueRef[] arguments;
-
- public LLVMModuleRef Module { get => module; }
- public LLVMValueRef Function { get => function; }
-
- public Builder () {
- module = LLVM.ModuleCreateWithName ("BigStepCompile");
- builder = LLVM.CreateBuilder ();
- }
-
- public void BeginFunction (string name, BSType returnType, BSType[] args) {
- var llvm_arguments = new LLVMTypeRef [args.Length];
- for (int i = 0; i < args.Length; i++)
- llvm_arguments [i] = args [i].Lowered;
-
- var funTy = LLVM.FunctionType (returnType.Lowered, llvm_arguments, false);
- function = LLVM.AddFunction (module, name, funTy);
- entry = LLVM.AppendBasicBlock (function, "entry");
- LLVM.PositionBuilderAtEnd (builder, entry);
- currentBB = entry;
-
- arguments = new LLVMValueRef [args.Length];
- for (int i = 0; i < args.Length; i++) {
- arguments [i] = LLVM.GetParam (function, (uint) i);
- LLVM.SetValueName (arguments [i], "arg" + i);
- }
- }
-
- internal unsafe void PrintDisassembly (NativeCodeHandle nch) {
- IntPtr fnptr = new IntPtr (nch.Blob);
-
- // FIXME: do this once
- LLVMDisasmContextRef disasm = LLVM.CreateDisasm (TargetTriple, IntPtr.Zero, 0, null, null);
- LLVM.SetDisasmOptions (disasm, 2 /* print imm as hex */);
-
- // FIXME: use codebuf length
- const long maxlength = 0x100;
- long pc = 0;
-
- Console.WriteLine ("disasm:");
- while (pc < maxlength) {
- const int stringBufSize = 0x40;
- IntPtr outString = Marshal.AllocHGlobal (stringBufSize);
-
- long oldPc = pc;
- pc += LLVM.DisasmInstruction (disasm, IntPtr.Add (fnptr, (int) pc), 0x100, 0, outString, stringBufSize);
-
- string s = Marshal.PtrToStringAnsi (outString);
-
- /* HACK because we don't know codbuf length; this is the disassembled string of 0x00 0x00 */
- if (s.Contains ("addb") && s.Contains ("%al, (%rax)")) {
- break;
- }
- Console.WriteLine ($"{oldPc:x4}: {s}");
- }
- }
-
- internal CompilationResult Finish (out NativeCodeHandle result) {
-
- // FIXME: get rid of this printf
- LLVM.DumpModule (Module);
-
- //FIXME: do this once
- LLVM.LinkInMCJIT ();
- LLVM.InitializeX86TargetMC ();
- LLVM.InitializeX86Target ();
- LLVM.InitializeX86TargetInfo ();
- LLVM.InitializeX86AsmParser ();
- LLVM.InitializeX86AsmPrinter ();
- LLVM.InitializeX86Disassembler ();
-
- /* this looks like unused code, but it initializes the target configuration */
- LLVMTargetRef target = LLVM.GetTargetFromName("x86-64");
- LLVMTargetMachineRef tmachine = LLVM.CreateTargetMachine(
+ LLVM.LinkInMCJIT ();
+ LLVM.InitializeX86TargetMC ();
+ LLVM.InitializeX86Target ();
+ LLVM.InitializeX86TargetInfo ();
+ LLVM.InitializeX86AsmParser ();
+ LLVM.InitializeX86AsmPrinter ();
+ LLVM.InitializeX86Disassembler ();
+
+ /* this looks like unused code, but it initializes the target configuration */
+ LLVMTargetRef target = LLVM.GetTargetFromName("x86-64");
+ LLVMTargetMachineRef tmachine = LLVM.CreateTargetMachine(
target,
TargetTriple,
"x86-64", // processor
@@ -187,220 +74,9 @@ internal CompilationResult Finish (out NativeCodeHandle result) {
LLVMCodeGenOptLevel.LLVMCodeGenLevelNone,
LLVMRelocMode.LLVMRelocDefault,
LLVMCodeModel.LLVMCodeModelDefault);
- /* */
-
- LLVMMCJITCompilerOptions options = new LLVMMCJITCompilerOptions { NoFramePointerElim = 0 };
- LLVM.InitializeMCJITCompilerOptions(options);
- if (LLVM.CreateMCJITCompilerForModule(out var engine, Module, options, out var error) != Success)
- {
- /* FIXME: If I make completely bogus LLVM IR, I would expect to
- * fail here and get some kind of error, but I don't.
- */
- Console.Error.WriteLine($"Error: {error}");
- result = NativeCodeHandle.Invalid;
- return CompilationResult.BadCode;
- }
- IntPtr fnptr = LLVM.GetPointerToGlobal (engine, Function);
- if (fnptr == IntPtr.Zero) {
- result = NativeCodeHandle.Invalid;
- Console.Error.WriteLine ("LLVM.GetPointerToGlobal returned null");
- return CompilationResult.InternalError;
- } else {
- Console.Error.WriteLine ("saw {0}", fnptr);
- }
- unsafe {
- result = new NativeCodeHandle ((byte*)fnptr, -1);
- }
-
- // FIXME: guard behind debug flag
- PrintDisassembly (result);
-
- //FIXME: cleanup in a Dispose method?
-
- LLVM.DisposeBuilder (builder);
-
- // FIXME: can I really dispose of the EE while code is installed in Mono :-(
-
- // LLVM.DisposeExecutionEngine (engine);
-
- return Ok;
- }
-
- public LLVMValueRef ConstInt (BSType t, ulong value, bool signextend)
- {
- return LLVM.ConstInt (t.Lowered, value, signextend);
- }
-
- public void EmitRetVoid () {
- LLVM.BuildRetVoid (builder);
- }
-
- public void EmitRet (LLVMValueRef v)
- {
- LLVM.BuildRet (builder, v);
- }
-
- public LLVMValueRef EmitAlloca (BSType t, string nameHint)
- {
- return LLVM.BuildAlloca (builder, t.Lowered, nameHint);
- }
-
- public LLVMValueRef EmitLoad (LLVMValueRef ptr, string nameHint)
- {
- return LLVM.BuildLoad (builder, ptr, nameHint);
- }
-
- public LLVMValueRef EmitArgumentLoad (uint position)
- {
- return arguments [position];
- }
-
- public void EmitStore (LLVMValueRef value, LLVMValueRef ptr)
- {
- LLVM.BuildStore (builder, value, ptr);
- }
-
- public LLVMValueRef EmitAdd (LLVMValueRef left, LLVMValueRef right)
- {
- return LLVM.BuildBinOp (builder, LLVMOpcode.LLVMAdd, left, right, "add");
- }
- }
-
- void Preamble (Env env, Builder builder)
- {
- var rt = LowerType (env, env.ReturnType);
-
- BSType[] args = new BSType [env.ArgumentTypes.Length];
- for (int i = 0; i < env.ArgumentTypes.Length; i++)
- args [i] = LowerType (env, env.ArgumentTypes [i]);
-
- builder.BeginFunction (env.MethodName, rt, args);
- }
-
- CompilationResult TranslateBody (Env env, Builder builder, MethodBody body)
- {
- var iter = body.GetIterator ();
- // TODO: alloca for locals and stack; store in env
-
- var r = Ok;
-
- while (iter.MoveNext ()) {
- var opcode = iter.Opcode;
- var opflags = iter.Flags;
- switch (opcode) {
- case Opcode.LdcI4_0:
- case Opcode.LdcI4_1:
- case Opcode.LdcI4_2:
- r = TranslateLdcI4 (env, builder, opcode - Opcode.LdcI4_0);
- break;
- case Opcode.LdcI4S:
- r = TranslateLdcI4 (env, builder, iter.DecodeParamI ());
- break;
- case Opcode.Ldarg0:
- case Opcode.Ldarg1:
- r = TranslateLdarg (env, builder, opcode - Opcode.Ldarg0);
- break;
- case Opcode.Add:
- // TODO: pass op
- r = TranslateBinaryOp (env, builder);
- break;
- case Opcode.Ret:
- r = TranslateRet (env, builder);
- break;
- default:
- throw NIE ($"BigStep.Translate {opcode}");
- }
- if (r != Ok)
- break;
- }
- return r;
- }
-
- CompilationResult TranslateRet (Env env, Builder builder)
- {
- if (env.ReturnType == RuntimeInfo.VoidType) {
- builder.EmitRetVoid ();
- return Ok;
- } else {
- var a = Pop (env, builder);
- var v = builder.EmitLoad (a.Ptr, "ret-value");
- builder.EmitRet (v);
- return Ok;
- }
-
- }
+ /* */
- CompilationResult TranslateLdcI4 (Env env, Builder builder, System.Int32 c)
- {
- BSType t = env.BSTypes.Int32Type;
- var a = Push (env, builder, t);
-
- var v = builder.ConstInt (t, (ulong)c, false);
- builder.EmitStore (v, a.Ptr);
- return Ok;
- }
-
- CompilationResult TranslateLdarg (Env env, Builder builder, uint position)
- {
- var t = LowerType (env, env.ArgumentTypes [position]);
- var a = Push (env, builder, t);
- var v = builder.EmitArgumentLoad (position);
- builder.EmitStore (v, a.Ptr);
- return Ok;
- }
-
- CompilationResult TranslateBinaryOp (Env env, Builder builder)
- {
- var a0 = Pop (env, builder);
- var a1 = Pop (env, builder);
- if (a0.StoredType != a1.StoredType) {
- Console.Error.WriteLine ("BinOp: Types of operands do not match");
- return CompilationResult.InternalError;
- }
-
- var v0 = builder.EmitLoad (a0.Ptr, "summand0");
- var v1 = builder.EmitLoad (a1.Ptr, "summand1");
-
- var vr = builder.EmitAdd (v0, v1);
-
- var ar = Push (env, builder, a0.StoredType);
- builder.EmitStore (vr, ar.Ptr);
-
- return Ok;
- }
-
- ArgStackValue Push (Env env, Builder builder, BSType t)
- {
- // FIXME: create stack slots up front and just bump a
- // stack height in the env and pick out the
- // pre-allocated slot.
- var v = builder.EmitAlloca (t, "stack-slot");
- var a = new ArgStackValue ();
- a.Ptr = v;
- a.StoredType = t;
- env.ArgStack.Push (a);
- return a;
- }
-
- ArgStackValue Pop (Env env, Builder builder)
- {
- var a = env.ArgStack.Pop ();
- return a;
- }
-
- BSType LowerType (Env env, ClrType t)
- {
- if (t == RuntimeInfo.VoidType)
- return env.BSTypes.VoidType;
- else if (t == RuntimeInfo.Int32Type)
- return env.BSTypes.Int32Type;
- else
- throw NIE ($"don't know how to lower type {t}");
- }
-
- private static Exception NIE (string msg)
- {
- return new NotImplementedException (msg);
+ LLVM.InitializeMCJITCompilerOptions(mcjitCompilerOptions);
}
}
diff --git a/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/CILSymbolicExecutor.cs b/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/CILSymbolicExecutor.cs
index d530b588aea5..30802646a039 100644
--- a/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/CILSymbolicExecutor.cs
+++ b/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/CILSymbolicExecutor.cs
@@ -5,399 +5,364 @@
using SimpleJit.Metadata;
using SimpleJit.CIL;
-namespace Mono.Compiler.BigStep
-{
- ///
- /// Emulate CIL execution only in the sense of stack change and delegates further handling for
- /// each operation to a processor.
- ///
- ///
- /// This class partially implements stack-based virtual machine as codified by ECMA-335. It tracks
- /// stack depth change and types associated with each operand, which may come from stack, locals
- /// or arguments. Upon completion of each operation it invokes a processor to perform customized
- /// operation. LLVM bitcode emitter is implemented as a processor.
- ///
- public class CILSymbolicExecutor : INameGenerator
- {
- private IOperationProcessor processor;
- private IRuntimeInformation runtime;
- private MethodBody body;
+namespace Mono.Compiler.BigStep {
+ ///
+ /// Emulate CIL execution only in the sense of stack change and delegates further handling for
+ /// each operation to a processor.
+ ///
+ ///
+ /// This class partially implements stack-based virtual machine as codified by ECMA-335. It tracks
+ /// stack depth change and types associated with each operand, which may come from stack, locals
+ /// or arguments. Upon completion of each operation it invokes a processor to perform customized
+ /// operation. LLVM bitcode emitter is implemented as a processor.
+ ///
+ public class CILSymbolicExecutor : INameGenerator {
+ private IOperationProcessor processor;
+ private IRuntimeInformation runtime;
+ private MethodBody body;
- private Stack stack;
- private int tempSeq = 0;
+ private Stack stack;
+ private int tempSeq = 0;
- private List locals;
- private List args;
+ private List locals;
+ private List args;
- // Physical => Logical index mapping for instructions which are jump targets
- private Dictionary targetIndices;
+ // Physical => Logical index mapping for instructions which are jump targets
+ private Dictionary targetIndices;
- // INameGenerator
- public string NextName()
- {
- return (tempSeq++).ToString();
- }
+ // INameGenerator
+ public string NextName ()
+ {
+ return (tempSeq++).ToString ();
+ }
- public CILSymbolicExecutor(
- IOperationProcessor processor,
- IRuntimeInformation runtime,
- MethodInfo methodInfo)
- {
- this.processor = processor;
- this.runtime = runtime;
- this.body = methodInfo.Body;
+ public CILSymbolicExecutor(IOperationProcessor processor, IRuntimeInformation runtime, MethodInfo methodInfo)
+ {
+ this.processor = processor;
+ this.runtime = runtime;
+ this.body = methodInfo.Body;
- this.stack = new Stack();
- this.targetIndices = new Dictionary();
+ this.stack = new Stack();
+ this.targetIndices = new Dictionary ();
- // The input is already ordered by index.
- this.locals = new List();
- foreach (LocalVariableInfo lvi in body.LocalVariables)
- {
- this.locals.Add(new LocalOperand(lvi.LocalIndex, lvi.LocalType));
- }
+ // The input is already ordered by index.
+ this.locals = new List ();
+ foreach (LocalVariableInfo lvi in body.LocalVariables) {
+ this.locals.Add (new LocalOperand (lvi.LocalIndex, lvi.LocalType));
+ }
- // The input is already ordered by index.
- this.args = new List();
- foreach (ParameterInfo pi in methodInfo.Parameters)
- {
- this.args.Add(new ArgumentOperand(pi.Position, pi.ParameterType));
- }
- }
+ // The input is already ordered by index.
+ this.args = new List ();
+ foreach (ParameterInfo pi in methodInfo.Parameters) {
+ this.args.Add (new ArgumentOperand (pi.Position, pi.ParameterType));
+ }
+ }
- public void Execute()
- {
- Pass1();
- Pass2();
- }
+ public void Execute ()
+ {
+ Pass1 ();
+ Pass2 ();
+ }
- /// In pass 1, collect jump information
- private void Pass1()
- {
- // The jump info encoded in CIL is the byte offset within the method. But for the processor
- // we want to represent jump target with the logical index of the first instruction in BB.
- // To collect these info in one pass, use two data structures to cross-reference the logical-physical
- // mapping.
+ /// In pass 1, collect jump information
+ private void Pass1 ()
+ {
+ // The jump info encoded in CIL is the byte offset within the method. But for the processor
+ // we want to represent jump target with the logical index of the first instruction in BB.
+ // To collect these info in one pass, use two data structures to cross-reference the logical-physical
+ // mapping.
- // logical => physical. This contains all instructions.
- List lpIndices = new List();
- // physical => logical. This contains all instructions.
- Dictionary plIndices = new Dictionary();
+ // logical => physical. This contains all instructions.
+ List lpIndices = new List ();
+ // physical => logical. This contains all instructions.
+ Dictionary plIndices = new Dictionary ();
- var iter = body.GetIterator();
- while (iter.MoveNext())
- {
- Opcode opcode = iter.Opcode;
- ExtendedOpcode? extOpCode = null;
- if (opcode == Opcode.ExtendedPrefix)
- {
- extOpCode = iter.ExtOpcode;
- }
- OpcodeFlags opflags = iter.Flags;
+ var iter = body.GetIterator ();
+ while (iter.MoveNext ()) {
+ Opcode opcode = iter.Opcode;
+ ExtendedOpcode? extOpCode = null;
+ if (opcode == Opcode.ExtendedPrefix) {
+ extOpCode = iter.ExtOpcode;
+ }
+ OpcodeFlags opflags = iter.Flags;
- // Record this instruction in both mappings
- int pindex = iter.Index;
- lpIndices.Add(pindex);
- int lindex = lpIndices.Count - 1;
- plIndices[pindex] = lindex;
- // Check if there is an entry in targets for this instruction
- if (targetIndices.ContainsKey(pindex))
- {
- // If so, populate the entry with P index we just learned
- targetIndices[pindex] = lindex;
- }
+ // Record this instruction in both mappings
+ int pindex = iter.Index;
+ lpIndices.Add (pindex);
+ int lindex = lpIndices.Count - 1;
+ plIndices[pindex] = lindex;
+ // Check if there is an entry in targets for this instruction
+ if (targetIndices.ContainsKey (pindex)) {
+ // If so, populate the entry with P index we just learned
+ targetIndices[pindex] = lindex;
+ }
- switch (opcode)
- {
- case Opcode.Br:
- case Opcode.BrS:
- case Opcode.Brfalse:
- case Opcode.BrfalseS:
- case Opcode.Brtrue:
- case Opcode.BrtrueS:
- int target = DecodeBranchTarget(iter);
- if (target <= pindex)
- {
- // CASE I: Jump backward
- // If jumping backward, we already have everything.
- targetIndices[pindex] = plIndices[pindex];
- }
- else
- {
- // CASE II: Jump forward
- // If jumping forward, we don't know the logic index yet. The value
- // will be filled later when we reach that instruction.
- targetIndices[pindex] = -1;
- }
- break;
- }
- }
- }
+ switch (opcode) {
+ case Opcode.Br:
+ case Opcode.BrS:
+ case Opcode.Brfalse:
+ case Opcode.BrfalseS:
+ case Opcode.Brtrue:
+ case Opcode.BrtrueS:
+ int target = DecodeBranchTarget(iter);
+ if (target <= pindex) {
+ // CASE I: Jump backward
+ // If jumping backward, we already have everything.
+ targetIndices[pindex] = plIndices[pindex];
+ } else {
+ // CASE II: Jump forward
+ // If jumping forward, we don't know the logic index yet. The value
+ // will be filled later when we reach that instruction.
+ targetIndices[pindex] = -1;
+ }
+ break;
+ }
+ }
+ }
- private int DecodeBranchTarget(IlIterator iter)
- {
- int opParam = iter.DecodeParamI();
- // Use next index to skip the bytes for the current instruction.
- int target = iter.NextIndex + opParam;
- return target;
- }
+ private int DecodeBranchTarget (IlIterator iter)
+ {
+ int opParam = iter.DecodeParamI ();
+ // Use next index to skip the bytes for the current instruction.
+ int target = iter.NextIndex + opParam;
+ return target;
+ }
- /// In pass 2, emulate execution
- private void Pass2()
- {
- int index = 0;
- var iter = body.GetIterator();
- while (iter.MoveNext())
- {
- Opcode opcode = iter.Opcode;
- ExtendedOpcode? extOpCode = null;
- if (opcode == Opcode.ExtendedPrefix)
- {
- extOpCode = iter.ExtOpcode;
- }
- OpcodeFlags opflags = iter.Flags;
- int opParam = 0;
- IOperand output = null;
+ /// In pass 2, emulate execution
+ private void Pass2 ()
+ {
+ int index = 0;
+ var iter = body.GetIterator ();
+ while (iter.MoveNext ()) {
+ Opcode opcode = iter.Opcode;
+ ExtendedOpcode? extOpCode = null;
+ if (opcode == Opcode.ExtendedPrefix) {
+ extOpCode = iter.ExtOpcode;
+ }
+ OpcodeFlags opflags = iter.Flags;
+ int opParam = 0;
+ IOperand output = null;
- // 1) Collect operands
- List operands = new List();
- // 1.1) operands not from stack
- switch (opcode)
- {
- // 1.1.1) operands from Arguments
- case Opcode.Ldarg0:
- operands.Add(output = args[0]);
- break;
- case Opcode.Ldarg1:
- operands.Add(output = args[1]);
- break;
- case Opcode.Ldarg2:
- operands.Add(output = args[2]);
- break;
- case Opcode.Ldarg3:
- operands.Add(output = args[3]);
- break;
- case Opcode.LdargS:
- opParam = iter.DecodeParamI();
- operands.Add(output = args[opParam]);
- break;
- // 1.1.2) operands from Locals
- case Opcode.Ldloc0:
- operands.Add(output = locals[0]);
- break;
- case Opcode.Ldloc1:
- operands.Add(output = locals[1]);
- break;
- case Opcode.Ldloc2:
- operands.Add(output = locals[2]);
- break;
- case Opcode.Ldloc3:
- operands.Add(output = locals[3]);
- break;
- case Opcode.LdlocS:
- opParam = iter.DecodeParamI();
- operands.Add(output = locals[opParam]);
- break;
- // 1.1.3) operands from constants
- case Opcode.LdcI4_0:
- operands.Add(output = new Int32ConstOperand(0));
- break;
- case Opcode.LdcI4_1:
- operands.Add(output = new Int32ConstOperand(1));
- break;
- case Opcode.LdcI4_2:
- operands.Add(output = new Int32ConstOperand(2));
- break;
- case Opcode.LdcI4_3:
- operands.Add(output = new Int32ConstOperand(3));
- break;
- case Opcode.LdcI4_4:
- operands.Add(output = new Int32ConstOperand(4));
- break;
- case Opcode.LdcI4_5:
- operands.Add(new Int32ConstOperand(5));
- break;
- case Opcode.LdcI4_6:
- operands.Add(output = new Int32ConstOperand(6));
- break;
- case Opcode.LdcI4_7:
- operands.Add(output = new Int32ConstOperand(7));
- break;
- case Opcode.LdcI4M1:
- operands.Add(output = new Int32ConstOperand(-1));
- break;
- case Opcode.LdcI4:
- case Opcode.LdcI4S:
- opParam = iter.DecodeParamI();
- operands.Add(output = new Int32ConstOperand(opParam));
- break;
- case Opcode.LdcI8:
- case Opcode.LdcR4:
- case Opcode.LdcR8:
- throw new Exception($"TODO: Cannot handle {opcode.ToString()} yet.");
- // TODO: ExtendedOpcode.Ldloc
- }
+ // 1) Collect operands
+ List operands = new List ();
+ // 1.1) operands not from stack
+ switch (opcode) {
+ // 1.1.1) operands from Arguments
+ case Opcode.Ldarg0:
+ operands.Add (output = args[0]);
+ break;
+ case Opcode.Ldarg1:
+ operands.Add (output = args[1]);
+ break;
+ case Opcode.Ldarg2:
+ operands.Add (output = args[2]);
+ break;
+ case Opcode.Ldarg3:
+ operands.Add (output = args[3]);
+ break;
+ case Opcode.LdargS:
+ opParam = iter.DecodeParamI ();
+ operands.Add (output = args[opParam]);
+ break;
+ // 1.1.2) operands from Locals
+ case Opcode.Ldloc0:
+ operands.Add (output = locals[0]);
+ break;
+ case Opcode.Ldloc1:
+ operands.Add (output = locals[1]);
+ break;
+ case Opcode.Ldloc2:
+ operands.Add (output = locals[2]);
+ break;
+ case Opcode.Ldloc3:
+ operands.Add (output = locals[3]);
+ break;
+ case Opcode.LdlocS:
+ opParam = iter.DecodeParamI();
+ operands.Add (output = locals[opParam]);
+ break;
+ // 1.1.3) operands from constants
+ case Opcode.LdcI4_0:
+ operands.Add (output = new Int32ConstOperand (0));
+ break;
+ case Opcode.LdcI4_1:
+ operands.Add (output = new Int32ConstOperand (1));
+ break;
+ case Opcode.LdcI4_2:
+ operands.Add (output = new Int32ConstOperand (2));
+ break;
+ case Opcode.LdcI4_3:
+ operands.Add (output = new Int32ConstOperand (3));
+ break;
+ case Opcode.LdcI4_4:
+ operands.Add (output = new Int32ConstOperand (4));
+ break;
+ case Opcode.LdcI4_5:
+ operands.Add (new Int32ConstOperand (5));
+ break;
+ case Opcode.LdcI4_6:
+ operands.Add (output = new Int32ConstOperand(6));
+ break;
+ case Opcode.LdcI4_7:
+ operands.Add (output = new Int32ConstOperand(7));
+ break;
+ case Opcode.LdcI4M1:
+ operands.Add (output = new Int32ConstOperand(-1));
+ break;
+ case Opcode.LdcI4:
+ case Opcode.LdcI4S:
+ opParam = iter.DecodeParamI();
+ operands.Add (output = new Int32ConstOperand(opParam));
+ break;
+ case Opcode.LdcI8:
+ case Opcode.LdcR4:
+ case Opcode.LdcR8:
+ throw new Exception($"TODO: Cannot handle {opcode.ToString()} yet.");
+ // TODO: ExtendedOpcode.Ldloc
+ }
- // 1.2) operands to be popped from stack
- PopBehavior popbhv = iter.PopBehavior;
- int popCount = 0;
- switch (popbhv)
- {
- case PopBehavior.Pop0:
- popCount = 0;
- break;
- case PopBehavior.Pop1:
- case PopBehavior.Popi:
- case PopBehavior.Popref:
- popCount = 1;
- break;
- case PopBehavior.Pop1_pop1:
- case PopBehavior.Popi_popi:
- case PopBehavior.Popi_popi8:
- case PopBehavior.Popi_popr4:
- case PopBehavior.Popi_popr8:
- case PopBehavior.Popref_pop1:
- case PopBehavior.Popi_pop1:
- case PopBehavior.Popref_popi:
- popCount = 2;
- break;
- case PopBehavior.Popi_popi_popi:
- case PopBehavior.Popref_popi_popi:
- case PopBehavior.Popref_popi_popi8:
- case PopBehavior.Popref_popi_popr4:
- case PopBehavior.Popref_popi_popr8:
- case PopBehavior.Popref_popi_popref:
- popCount = 3;
- break;
- case PopBehavior.PopAll:
- popCount = stack.Count;
- break;
- case PopBehavior.Varpop:
- if (opcode == Opcode.Ret)
- {
- if (stack.Count == 0)
- {
- break;
- }
- else if (stack.Count == 1)
- {
- popCount = 1;
- break;
- }
- else if (stack.Count > 1)
- {
- // Likely a bug somewhere else in the symbolic engine.
- throw new Exception($"Unexpected. Leaves function with non-empty stack.");
- }
- }
+ // 1.2) operands to be popped from stack
+ PopBehavior popbhv = iter.PopBehavior;
+ int popCount = 0;
+ switch (popbhv) {
+ case PopBehavior.Pop0:
+ popCount = 0;
+ break;
+ case PopBehavior.Pop1:
+ case PopBehavior.Popi:
+ case PopBehavior.Popref:
+ popCount = 1;
+ break;
+ case PopBehavior.Pop1_pop1:
+ case PopBehavior.Popi_popi:
+ case PopBehavior.Popi_popi8:
+ case PopBehavior.Popi_popr4:
+ case PopBehavior.Popi_popr8:
+ case PopBehavior.Popref_pop1:
+ case PopBehavior.Popi_pop1:
+ case PopBehavior.Popref_popi:
+ popCount = 2;
+ break;
+ case PopBehavior.Popi_popi_popi:
+ case PopBehavior.Popref_popi_popi:
+ case PopBehavior.Popref_popi_popi8:
+ case PopBehavior.Popref_popi_popr4:
+ case PopBehavior.Popref_popi_popr8:
+ case PopBehavior.Popref_popi_popref:
+ popCount = 3;
+ break;
+ case PopBehavior.PopAll:
+ popCount = stack.Count;
+ break;
+ case PopBehavior.Varpop:
+ if (opcode == Opcode.Ret) {
+ if (stack.Count == 0) {
+ break;
+ } else if (stack.Count == 1) {
+ popCount = 1;
+ break;
+ } else if (stack.Count > 1) {
+ // Likely a bug somewhere else in the symbolic engine.
+ throw new Exception ($"Unexpected. Leaves function with non-empty stack.");
+ }
+ }
- throw new Exception(
- $"TODO: Cannot handle PopBehavior.Varpop against { opcode } yet.");
- }
+ throw new Exception ($"TODO: Cannot handle PopBehavior.Varpop against { opcode } yet.");
+ }
- int count = popCount;
- ClrType[] exprOdTypes = new ClrType[count];
- while (count > 0)
- {
- TempOperand tmp = stack.Pop();
- operands.Add(tmp);
- exprOdTypes[count - 1] = tmp.Type;
- count--;
- }
+ int count = popCount;
+ ClrType[] exprOdTypes = new ClrType[count];
+ while (count > 0) {
+ TempOperand tmp = stack.Pop ();
+ operands.Add (tmp);
+ exprOdTypes[count - 1] = tmp.Type;
+ count--;
+ }
- // Additional operands
- switch (opcode)
- {
- case Opcode.Br:
- case Opcode.BrS:
- case Opcode.Brfalse:
- case Opcode.BrfalseS:
- case Opcode.Brtrue:
- case Opcode.BrtrueS:
- int target = DecodeBranchTarget(iter);
- int logicIndex = targetIndices[target];
- BranchTargetOperand bto = new BranchTargetOperand(logicIndex);
- operands.Add(bto);
- break;
- case Opcode.Stloc0:
- operands.Add(locals[0]);
- break;
- case Opcode.Stloc1:
- operands.Add(locals[1]);
- break;
- case Opcode.Stloc2:
- operands.Add(locals[2]);
- break;
- case Opcode.Stloc3:
- operands.Add(locals[3]);
- break;
- case Opcode.StlocS:
- opParam = iter.DecodeParamI();
- operands.Add(locals[opParam]);
- break;
- // TODO: ExtendedOpcode.Stloc
- }
+ // Additional operands
+ switch (opcode) {
+ case Opcode.Br:
+ case Opcode.BrS:
+ case Opcode.Brfalse:
+ case Opcode.BrfalseS:
+ case Opcode.Brtrue:
+ case Opcode.BrtrueS:
+ int target = DecodeBranchTarget (iter);
+ int logicIndex = targetIndices[target];
+ BranchTargetOperand bto = new BranchTargetOperand (logicIndex);
+ operands.Add (bto);
+ break;
+ case Opcode.Stloc0:
+ operands.Add (locals[0]);
+ break;
+ case Opcode.Stloc1:
+ operands.Add (locals[1]);
+ break;
+ case Opcode.Stloc2:
+ operands.Add (locals[2]);
+ break;
+ case Opcode.Stloc3:
+ operands.Add (locals[3]);
+ break;
+ case Opcode.StlocS:
+ opParam = iter.DecodeParamI ();
+ operands.Add (locals[opParam]);
+ break;
+ // TODO: ExtendedOpcode.Stloc
+ }
- // 2) Determine the result type for values to push into stack
- TempOperand tod = null;
- if (output != null)
- {
- tod = new TempOperand(this, output.Type);
- }
- else
- {
- ClrType? ctyp = OpResultTypeLookup.Query(opcode, extOpCode, exprOdTypes);
- if (ctyp.HasValue)
- {
- tod = new TempOperand(this, (ClrType)ctyp);
- }
- }
+ // 2) Determine the result type for values to push into stack
+ TempOperand tod = null;
+ if (output != null) {
+ tod = new TempOperand (this, output.Type);
+ } else {
+ ClrType? ctyp = OpResultTypeLookup.Query (opcode, extOpCode, exprOdTypes);
+ if (ctyp.HasValue) {
+ tod = new TempOperand(this, (ClrType)ctyp);
+ }
+ }
- // 3) Push result
- PushBehavior pushbhv = iter.PushBehavior;
- switch (pushbhv)
- {
- case PushBehavior.Push0:
- break;
- case PushBehavior.Push1:
- case PushBehavior.Pushi:
- case PushBehavior.Pushi8:
- case PushBehavior.Pushr4:
- case PushBehavior.Pushr8:
- if (tod == null)
- {
- throw new Exception("Unexpected: no value to push to stack.");
- }
- stack.Push(tod);
- break;
- case PushBehavior.Push1_push1:
- // This only applies to Opcode.Dup
- if (tod == null)
- {
- throw new Exception("Unexpected: no value to push to stack.");
- }
- stack.Push(tod);
- stack.Push(tod);
- break;
- case PushBehavior.Varpush:
- // This is a huge TODO. Function call (Opcode.Call/Calli/Callvirt) relies on this behavior.
- throw new Exception("TODO: Cannot handle PushBehavior.Varpush yet.");
- }
+ // 3) Push result
+ PushBehavior pushbhv = iter.PushBehavior;
+ switch (pushbhv) {
+ case PushBehavior.Push0:
+ break;
+ case PushBehavior.Push1:
+ case PushBehavior.Pushi:
+ case PushBehavior.Pushi8:
+ case PushBehavior.Pushr4:
+ case PushBehavior.Pushr8:
+ if (tod == null) {
+ throw new Exception ("Unexpected: no value to push to stack.");
+ }
+ stack.Push (tod);
+ break;
+ case PushBehavior.Push1_push1:
+ // This only applies to Opcode.Dup
+ if (tod == null) {
+ throw new Exception ("Unexpected: no value to push to stack.");
+ }
+ stack.Push(tod);
+ stack.Push(tod);
+ break;
+ case PushBehavior.Varpush:
+ // This is a huge TODO. Function call (Opcode.Call/Calli/Callvirt) relies on this behavior.
+ throw new Exception ("TODO: Cannot handle PushBehavior.Varpush yet.");
+ }
- // 4) Send the info to operation processor
- bool isJumpTarget = targetIndices.ContainsKey(iter.Index);
- OperationInfo opInfo = new OperationInfo
- {
- Index = index,
- Operation = opcode,
- ExtOperation = extOpCode,
- Operands = operands.ToArray(),
- Result = tod,
- JumpTarget = isJumpTarget
- };
- processor.Process(opInfo);
- index++;
- }
- }
- }
-}
\ No newline at end of file
+ // 4) Send the info to operation processor
+ bool isJumpTarget = targetIndices.ContainsKey(iter.Index);
+ OperationInfo opInfo = new OperationInfo {
+ Index = index,
+ Operation = opcode,
+ ExtOperation = extOpCode,
+ Operands = operands.ToArray (),
+ Result = tod,
+ JumpTarget = isJumpTarget
+ };
+ processor.Process (opInfo);
+ index++;
+ }
+ }
+ }
+}
diff --git a/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/LLVM/BitCodeEmitter.cs b/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/LLVM/BitCodeEmitter.cs
index 46d9adae0043..0c1dc1c17923 100644
--- a/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/LLVM/BitCodeEmitter.cs
+++ b/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/LLVM/BitCodeEmitter.cs
@@ -11,602 +11,490 @@
///
/// Emit LLVM bitcode via LLVMSharp.
///
-namespace Mono.Compiler.BigStep.LLVMBackend
-{
- public class BitCodeEmitter : IOperationProcessor
- {
- private static readonly LLVMBool Success = new LLVMBool(0);
- private static readonly LLVMBool True = new LLVMBool(1);
- private static readonly LLVMMCJITCompilerOptions s_options = new LLVMMCJITCompilerOptions { NoFramePointerElim = 0 };
-
- private static int s_moduleSeq;
- private static bool s_uninitialized;
-
- private LLVMModuleRef module;
- private LLVMBuilderRef builder;
- private LLVMValueRef function;
-
- private LLVMValueRef[] argAddrs;
- private LLVMValueRef[] localAddrs;
- private Dictionary temps;
- private Dictionary bbs;
-
- public bool PrintDebugInfo { get; set; }
- public bool VerifyGeneratedCode { get; set; }
-
- public BitCodeEmitter(MethodInfo method)
- {
- int seq = Interlocked.Increment(ref s_moduleSeq);
- string modName = "llvmmodule_" + seq;
- module = LLVM.ModuleCreateWithName(modName);
- builder = LLVM.CreateBuilder();
- temps = new Dictionary();
- bbs = new Dictionary();
-
- IReadOnlyCollection prms = method.Parameters;
- LLVMTypeRef[] largs = new LLVMTypeRef[prms.Count];
- int i = 0;
- foreach (ParameterInfo pinfo in prms)
- {
- largs[i] = TranslateType(pinfo.ParameterType);
- i++;
- }
- LLVMTypeRef rtyp = TranslateType(method.ReturnType);
-
- var funTy = LLVM.FunctionType(rtyp, largs, false);
- string funcName = modName + "_" + method.Name;
- function = LLVM.AddFunction(module, funcName, funTy);
- CreateFirstBasicBlock();
-
- IList locals = method.Body.LocalVariables;
- AllocateArgsAndLocals(largs, locals);
- }
-
- #region Basic Block operations
- private void CreateFirstBasicBlock()
- {
- LLVMBasicBlockRef bb = LLVM.AppendBasicBlock(function, "entry");
- LLVM.PositionBuilderAtEnd(builder, bb);
- }
-
- private LLVMBasicBlockRef GetOrAddBasicBlock(int opIndex, bool moveToEnd)
- {
- string name = "BB_" + opIndex;
- LLVMBasicBlockRef bbr;
- if (!bbs.TryGetValue(name, out bbr))
- {
- bbs[name] = bbr = LLVM.AppendBasicBlock(function, name);
- }
-
- if (moveToEnd)
- {
- LLVM.PositionBuilderAtEnd(builder, bbr);
- }
-
- return bbr;
- }
- #endregion
-
- private void AllocateArgsAndLocals(LLVMTypeRef[] args, IList locals)
- {
- this.argAddrs = new LLVMValueRef[args.Length];
- uint i = 0;
- for (; i < args.Length; i++)
- {
- LLVMValueRef vref = LLVM.GetParam(function, i);
- LLVMValueRef vaddr = LLVM.BuildAlloca(builder, args[i], "A" + i);
- LLVM.BuildStore(builder, vref, vaddr);
- this.argAddrs[i] = vaddr;
- }
-
- i = 0;
- localAddrs = new LLVMValueRef[locals.Count];
- foreach (LocalVariableInfo lvi in locals)
- {
- LLVMTypeRef ltyp = TranslateType(lvi.LocalType);
- LLVMValueRef lref = LLVM.BuildAlloca(builder, ltyp, "L" + i);
- this.localAddrs[i] = lref;
- }
- }
-
- // Emit LLVM instruction per CIL operation
- public void Process(OperationInfo opInfo)
- {
- if (opInfo.JumpTarget)
- {
- // If this op is a jump target, replace BB now
- this.GetOrAddBasicBlock(opInfo.Index, true);
- }
-
- Opcode op = opInfo.Operation;
- ExtendedOpcode? exop = opInfo.ExtOperation;
- IOperand[] operands = opInfo.Operands;
-
- // The result is the value pushed onto the stack by CLR at the end of instruction.
- // In the translation we treat each new frame on the stack as a distinct instance
- // that corresponds to a register in LLVM. If a frame is popped and pushed again it
- // becomes a new instance.
- //
- // CLR eval-stack frame = TempOperand = LLVM temp register
- //
- // If the result is non-null, we must generate a new temp value and associate it
- // with the temp operand's name. When a temp operand appears in the operands, it
- // means a previously pushed value is being consumed by instruction. Based on the
- // name of the operand we can retrieve the temp register and use that in LLVM
- // operation.
- string tempName = opInfo.Result?.Name;
-
- switch (op)
- {
- // Notation for comments:
- // op1, op2, ... => result pushed into expr-stack
- case Opcode.Nop:
- break;
- case Opcode.Ret:
- // tmp
- InvokeOperation(
- op, exop, operands,
- vm =>
- {
- if (operands.Length > 0)
- {
- LLVM.BuildRet(builder, vm.Temp0);
- }
- else
- {
- LLVM.BuildRetVoid(builder);
- }
- });
- break;
- case Opcode.Ldarg0:
- case Opcode.Ldarg1:
- case Opcode.Ldarg2:
- case Opcode.Ldarg3:
- case Opcode.LdargS:
- // arg => tmp
- InvokeOperation(
- op, exop, operands,
- vm =>
- {
- LLVMValueRef tmp = LLVM.BuildLoad(builder, vm.Address0, tempName);
- return new NamedTempValue(tmp, tempName);
- });
- break;
- case Opcode.Stloc0:
- case Opcode.Stloc1:
- case Opcode.Stloc2:
- case Opcode.Stloc3:
- // tmp, local
- InvokeOperation(
- op, exop, operands,
- vm =>
- {
- LLVM.BuildStore(builder, vm.Temp0, vm.Address1);
- });
- break;
- case Opcode.LdcI4:
- case Opcode.LdcI4_0:
- case Opcode.LdcI4_1:
- case Opcode.LdcI4_2:
- case Opcode.LdcI4_3:
- case Opcode.LdcI4_4:
- case Opcode.LdcI4_5:
- case Opcode.LdcI4_6:
- case Opcode.LdcI4_7:
- case Opcode.LdcI4_8:
- case Opcode.LdcI4M1:
- case Opcode.LdcI4S:
- // const => tmp
- InvokeOperation(
- op, exop, operands,
- vm =>
- {
- // LLVM doesn't allow assignment from constant to value.
- // So we just pretend that the constant is a temp value.
- // When it's used in an instruction it will be realized
- // in the form of "ty value-literal" (e.g. "i32 42")
- LLVMValueRef tmp = vm.Const0;
- return new NamedTempValue(tmp, tempName);
- });
- break;
- case Opcode.Ldloc0:
- case Opcode.Ldloc1:
- case Opcode.Ldloc2:
- case Opcode.Ldloc3:
- case Opcode.LdlocS:
- // local => tmp
- InvokeOperation(
- op, exop, operands,
- vm =>
- {
- LLVMValueRef tmp = LLVM.BuildLoad(builder, vm.Address0, tempName);
- return new NamedTempValue(tmp, tempName);
- });
- break;
- case Opcode.Add:
- case Opcode.AddOvf: // TODO - Handle overflow
- case Opcode.AddOvfUn: // TODO - Handle overflow, unsigned
- // tmp, tmp => tmp
- InvokeOperation(
- op, exop, operands,
- vm =>
- {
- LLVMValueRef tmp = LLVM.BuildAdd(builder, vm.Temp0, vm.Temp1, tempName);
- return new NamedTempValue(tmp, tempName);
- });
- break;
- case Opcode.Sub:
- case Opcode.SubOvf: // TODO - Handle overflow
- case Opcode.SubOvfUn: // TODO - Handle overflow, unsigned
- // tmp, tmp => tmp
- InvokeOperation(
- op, exop, operands,
- vm =>
- {
- LLVMValueRef tmp = LLVM.BuildSub(builder, vm.Temp0, vm.Temp1, tempName);
- return new NamedTempValue(tmp, tempName);
- });
- break;
- case Opcode.Mul:
- case Opcode.MulOvf: // TODO - Handle overflow
- case Opcode.MulOvfUn: // TODO - Handle overflow, unsigned
- // tmp, tmp => tmp
- InvokeOperation(
- op, exop, operands,
- vm =>
- {
- LLVMValueRef tmp = LLVM.BuildMul(builder, vm.Temp0, vm.Temp1, tempName);
- return new NamedTempValue(tmp, tempName);
- });
- break;
- case Opcode.Div:
- // tmp, tmp => tmp
- InvokeOperation(
- op, exop, operands,
- vm =>
- {
- LLVMValueRef tmp = LLVM.BuildFDiv(builder, vm.Temp0, vm.Temp1, tempName);
- return new NamedTempValue(tmp, tempName);
- });
- break;
- case Opcode.Br:
- case Opcode.BrS:
- // Special - jump to another BB
- LLVMBasicBlockRef bb = this.GetBranchTarget(operands[0]);
- LLVM.BuildBr(builder, bb);
- break;
- case Opcode.DivUn:
- // tmp, tmp => tmp
- InvokeOperation(
- op, exop, operands,
- vm =>
- {
- LLVMValueRef tmp = LLVM.BuildUDiv(builder, vm.Temp0, vm.Temp1, tempName);
- return new NamedTempValue(tmp, tempName);
- });
- break;
- }
- }
-
- /// Produce a native handle for the generated native code. Call this after Process()
- public NativeCodeHandle Yield()
- {
- if (PrintDebugInfo)
- {
- LLVM.DumpModule(module);
- }
-
- if (!BitCodeEmitter.s_uninitialized)
- {
- lock (typeof(BitCodeEmitter))
- {
- if (!BitCodeEmitter.s_uninitialized)
- {
- LLVM.LinkInMCJIT();
- LLVM.InitializeX86TargetMC();
- LLVM.InitializeX86Target();
- LLVM.InitializeX86TargetInfo();
- LLVM.InitializeX86AsmParser();
- LLVM.InitializeX86AsmPrinter();
- LLVM.InitializeMCJITCompilerOptions(s_options);
-
- BitCodeEmitter.s_uninitialized = true;
+namespace Mono.Compiler.BigStep.LLVMBackend {
+ public class BitCodeEmitter : IOperationProcessor {
+ private static readonly LLVMBool Success = new LLVMBool (0);
+ private static readonly LLVMBool True = new LLVMBool (1);
+ private static readonly LLVMMCJITCompilerOptions s_options = new LLVMMCJITCompilerOptions { NoFramePointerElim = 0 };
+
+ private static int s_moduleSeq;
+ private static bool s_initialized;
+
+ private LLVMModuleRef module;
+ private LLVMBuilderRef builder;
+ private LLVMValueRef function;
+
+ private LLVMValueRef[] argAddrs;
+ private LLVMValueRef[] localAddrs;
+ private Dictionary temps;
+ private Dictionary bbs;
+
+ public bool PrintDebugInfo { get; set; }
+ public bool VerifyGeneratedCode { get; set; }
+
+ public BitCodeEmitter (MethodInfo method)
+ {
+ int seq = Interlocked.Increment (ref s_moduleSeq);
+ string modName = "llvmmodule_" + seq;
+ module = LLVM.ModuleCreateWithName(modName);
+ builder = LLVM.CreateBuilder ();
+ temps = new Dictionary ();
+ bbs = new Dictionary ();
+
+ IReadOnlyCollection prms = method.Parameters;
+ LLVMTypeRef[] largs = new LLVMTypeRef[prms.Count];
+ int i = 0;
+ foreach (ParameterInfo pinfo in prms) {
+ largs[i] = TranslateType (pinfo.ParameterType);
+ i++;
+ }
+ LLVMTypeRef rtyp = TranslateType (method.ReturnType);
+
+ var funTy = LLVM.FunctionType (rtyp, largs, false);
+ string funcName = modName + "_" + method.Name;
+ function = LLVM.AddFunction (module, funcName, funTy);
+ CreateFirstBasicBlock ();
+
+ IList locals = method.Body.LocalVariables;
+ AllocateArgsAndLocals (largs, locals);
+ }
+
+ #region Basic Block operations
+ private void CreateFirstBasicBlock ()
+ {
+ LLVMBasicBlockRef bb = LLVM.AppendBasicBlock (function, "entry");
+ LLVM.PositionBuilderAtEnd (builder, bb);
+ }
+
+ private LLVMBasicBlockRef GetOrAddBasicBlock (int opIndex, bool moveToEnd)
+ {
+ string name = "BB_" + opIndex;
+ LLVMBasicBlockRef bbr;
+ if (!bbs.TryGetValue (name, out bbr)) {
+ bbs[name] = bbr = LLVM.AppendBasicBlock (function, name);
+ }
+
+ if (moveToEnd)
+ LLVM.PositionBuilderAtEnd (builder, bbr);
+
+ return bbr;
+ }
+ #endregion
+
+ private void AllocateArgsAndLocals (LLVMTypeRef[] args, IList locals)
+ {
+ this.argAddrs = new LLVMValueRef[args.Length];
+ uint i = 0;
+ for (; i < args.Length; i++) {
+ LLVMValueRef vref = LLVM.GetParam (function, i);
+ LLVMValueRef vaddr = LLVM.BuildAlloca (builder, args[i], "A" + i);
+ LLVM.BuildStore (builder, vref, vaddr);
+ this.argAddrs[i] = vaddr;
+ }
+
+ i = 0;
+ localAddrs = new LLVMValueRef[locals.Count];
+ foreach (LocalVariableInfo lvi in locals) {
+ LLVMTypeRef ltyp = TranslateType (lvi.LocalType);
+ LLVMValueRef lref = LLVM.BuildAlloca (builder, ltyp, "L" + i);
+ this.localAddrs[i++] = lref;
+ }
+ }
+
+ // Emit LLVM instruction per CIL operation
+ public void Process (OperationInfo opInfo)
+ {
+ if (opInfo.JumpTarget) {
+ // If this op is a jump target, replace BB now
+ this.GetOrAddBasicBlock (opInfo.Index, true);
+ }
+
+ Opcode op = opInfo.Operation;
+ ExtendedOpcode? exop = opInfo.ExtOperation;
+ IOperand[] operands = opInfo.Operands;
+
+ // The result is the value pushed onto the stack by CLR at the end of instruction.
+ // In the translation we treat each new frame on the stack as a distinct instance
+ // that corresponds to a register in LLVM. If a frame is popped and pushed again it
+ // becomes a new instance.
+ //
+ // CLR eval-stack frame = TempOperand = LLVM temp register
+ //
+ // If the result is non-null, we must generate a new temp value and associate it
+ // with the temp operand's name. When a temp operand appears in the operands, it
+ // means a previously pushed value is being consumed by instruction. Based on the
+ // name of the operand we can retrieve the temp register and use that in LLVM
+ // operation.
+ string tempName = opInfo.Result?.Name;
+
+ switch (op) {
+ // Notation for comments:
+ // op1, op2, ... => result pushed into expr-stack
+ case Opcode.Nop:
+ break;
+ case Opcode.Ret:
+ // tmp
+ InvokeOperation (op, exop, operands,
+ vm => {
+ if (operands.Length > 0) {
+ LLVM.BuildRet (builder, vm.Temp0);
+ } else {
+ LLVM.BuildRetVoid (builder);
+ }
+ });
+ break;
+ case Opcode.Ldarg0:
+ case Opcode.Ldarg1:
+ case Opcode.Ldarg2:
+ case Opcode.Ldarg3:
+ case Opcode.LdargS:
+ // arg => tmp
+ InvokeOperation (op, exop, operands,
+ vm => {
+ LLVMValueRef tmp = LLVM.BuildLoad (builder, vm.Address0, tempName);
+ return new NamedTempValue (tmp, tempName);
+ });
+ break;
+ case Opcode.Stloc0:
+ case Opcode.Stloc1:
+ case Opcode.Stloc2:
+ case Opcode.Stloc3:
+ // tmp, local
+ InvokeOperation (op, exop, operands,
+ vm => {
+ LLVM.BuildStore (builder, vm.Temp0, vm.Address1);
+ });
+ break;
+ case Opcode.LdcI4:
+ case Opcode.LdcI4_0:
+ case Opcode.LdcI4_1:
+ case Opcode.LdcI4_2:
+ case Opcode.LdcI4_3:
+ case Opcode.LdcI4_4:
+ case Opcode.LdcI4_5:
+ case Opcode.LdcI4_6:
+ case Opcode.LdcI4_7:
+ case Opcode.LdcI4_8:
+ case Opcode.LdcI4M1:
+ case Opcode.LdcI4S:
+ // const => tmp
+ InvokeOperation (op, exop, operands,
+ vm => {
+ // LLVM doesn't allow assignment from constant to value.
+ // So we just pretend that the constant is a temp value.
+ // When it's used in an instruction it will be realized
+ // in the form of "ty value-literal" (e.g. "i32 42")
+ LLVMValueRef tmp = vm.Const0;
+ return new NamedTempValue (tmp, tempName);
+ });
+ break;
+ case Opcode.Ldloc0:
+ case Opcode.Ldloc1:
+ case Opcode.Ldloc2:
+ case Opcode.Ldloc3:
+ case Opcode.LdlocS:
+ // local => tmp
+ InvokeOperation (op, exop, operands,
+ vm => {
+ LLVMValueRef tmp = LLVM.BuildLoad (builder, vm.Address0, tempName);
+ return new NamedTempValue (tmp, tempName);
+ });
+ break;
+ case Opcode.Add:
+ case Opcode.AddOvf: // TODO - Handle overflow
+ case Opcode.AddOvfUn: // TODO - Handle overflow, unsigned
+ // tmp, tmp => tmp
+ InvokeOperation (op, exop, operands,
+ vm => {
+ LLVMValueRef tmp = LLVM.BuildAdd (builder, vm.Temp0, vm.Temp1, tempName);
+ return new NamedTempValue (tmp, tempName);
+ });
+ break;
+ case Opcode.Sub:
+ case Opcode.SubOvf: // TODO - Handle overflow
+ case Opcode.SubOvfUn: // TODO - Handle overflow, unsigned
+ // tmp, tmp => tmp
+ InvokeOperation (op, exop, operands,
+ vm => {
+ LLVMValueRef tmp = LLVM.BuildSub (builder, vm.Temp0, vm.Temp1, tempName);
+ return new NamedTempValue (tmp, tempName);
+ });
+ break;
+ case Opcode.Mul:
+ case Opcode.MulOvf: // TODO - Handle overflow
+ case Opcode.MulOvfUn: // TODO - Handle overflow, unsigned
+ // tmp, tmp => tmp
+ InvokeOperation(op, exop, operands,
+ vm => {
+ LLVMValueRef tmp = LLVM.BuildMul (builder, vm.Temp0, vm.Temp1, tempName);
+ return new NamedTempValue (tmp, tempName);
+ });
+ break;
+ case Opcode.Div:
+ // tmp, tmp => tmp
+ InvokeOperation (op, exop, operands,
+ vm => {
+ LLVMValueRef tmp = LLVM.BuildFDiv (builder, vm.Temp0, vm.Temp1, tempName);
+ return new NamedTempValue (tmp, tempName);
+ });
+ break;
+ case Opcode.Br:
+ case Opcode.BrS:
+ // Special - jump to another BB
+ LLVMBasicBlockRef bb = this.GetBranchTarget (operands[0]);
+ LLVM.BuildBr(builder, bb);
+ break;
+ case Opcode.DivUn:
+ // tmp, tmp => tmp
+ InvokeOperation (op, exop, operands,
+ vm => {
+ LLVMValueRef tmp = LLVM.BuildUDiv (builder, vm.Temp0, vm.Temp1, tempName);
+ return new NamedTempValue (tmp, tempName);
+ });
+ break;
+ }
+ }
+
+ /// Produce a native handle for the generated native code. Call this after Process()
+ public NativeCodeHandle Yield ()
+ {
+ if (PrintDebugInfo)
+ LLVM.DumpModule (module);
+
+ if (!BitCodeEmitter.s_initialized) {
+ lock (typeof (BitCodeEmitter)) {
+ if (!BitCodeEmitter.s_initialized) {
+ BigStep.InitializeLLVM_OSX_AMD64 (s_options);
+
+ BitCodeEmitter.s_initialized = true;
//Console.WriteLine("[DEBUG] LLVM initialized.");
- }
- }
- }
-
- try
- {
- if (VerifyGeneratedCode)
- {
- if (LLVM.VerifyFunction(
- function, LLVMVerifierFailureAction.LLVMPrintMessageAction) != Success)
- {
- throw new Exception($"Couldn't verify the generated code. There is likely due to bug in code generation.");
}
}
+ }
+
+ try {
+ if (VerifyGeneratedCode) {
+ if (LLVM.VerifyFunction (function, LLVMVerifierFailureAction.LLVMPrintMessageAction) != Success)
+ throw new Exception ($"Couldn't verify the generated code. There is likely due to bug in code generation.");
+ }
- if (LLVM.CreateMCJITCompilerForModule(
- out LLVMExecutionEngineRef engine, module, s_options, out var error) != Success)
- {
- throw new Exception($"Compilation by LLVM failed: { error }");
- }
+ if (LLVM.CreateMCJITCompilerForModule(out LLVMExecutionEngineRef engine, module, s_options, out var error) != Success)
+ throw new Exception ($"Compilation by LLVM failed: { error }");
//Console.WriteLine("[DEBUG] LLVM compilation succeeded.");
- IntPtr fnptr = LLVM.GetPointerToGlobal(engine, function);
- unsafe
- {
- return new NativeCodeHandle((byte*)fnptr, -1);
- }
- }
- finally
- {
- LLVM.DisposeBuilder(builder);
- }
- }
-
- internal class ValueMappings
- {
- internal LLVMValueRef Const0
- {
- get
- {
- return Values[0].Value;
- }
- }
-
- internal LLVMValueRef Address0
- {
- get
- {
- return Values[0].Value;
- }
- }
-
- internal LLVMValueRef Address1
- {
- get
- {
- return Values[0].Value;
- }
- }
-
- internal LLVMValueRef Temp0
- {
- get
- {
- return Values[0].Value;
- }
- }
-
- internal LLVMValueRef Temp1
- {
- get
- {
- return Values[1].Value;
- }
- }
-
- internal StorageTypedValue[] Values { get; private set; }
-
- internal ValueMappings(int length)
- {
- Values = new StorageTypedValue[length];
- }
- }
-
- internal enum StorageType
- {
- Address,
- Temp,
- Const
- }
-
- internal class StorageTypedValue
- {
- internal StorageType Type { get; set; }
- internal LLVMValueRef Value { get; set; }
- }
-
- internal class NamedTempValue
- {
- internal string Name { get; set; }
- internal LLVMValueRef Value { get; set; }
-
- internal NamedTempValue(LLVMValueRef value, string name = null)
- {
- this.Value = value;
- this.Name = name;
- }
- }
-
- /// Invoke an LLVM operation with given value mappings.
- /// The operation is supposed to return a temp value to be stored.
- private void InvokeOperation(
- Opcode op,
- ExtendedOpcode? exop,
- IOperand[] operands,
- Func emitFunc)
- {
- if (this.PrintDebugInfo)
+ IntPtr fnptr = LLVM.GetPointerToGlobal (engine, function);
+ unsafe {
+ return new NativeCodeHandle((byte*)fnptr, -1);
+ }
+ } finally {
+ LLVM.DisposeBuilder(builder);
+ }
+ }
+
+ internal class ValueMappings {
+ internal LLVMValueRef Const0 {
+ get { return Values[0].Value; }
+ }
+
+ internal LLVMValueRef Address0 {
+ get { return Values[0].Value; }
+ }
+
+ internal LLVMValueRef Address1 {
+ get { return Values[0].Value; }
+ }
+
+ internal LLVMValueRef Temp0 {
+ get { return Values[0].Value; }
+ }
+
+ internal LLVMValueRef Temp1 {
+ get { return Values[1].Value; }
+ }
+
+ internal StorageTypedValue[] Values { get; private set; }
+
+ internal ValueMappings (int length)
+ {
+ Values = new StorageTypedValue[length];
+ }
+ }
+
+ internal enum StorageType {
+ Address,
+ Temp,
+ Const
+ }
+
+ internal class StorageTypedValue {
+ internal StorageType Type { get; set; }
+ internal LLVMValueRef Value { get; set; }
+ }
+
+ internal class NamedTempValue {
+ internal string Name { get; set; }
+ internal LLVMValueRef Value { get; set; }
+
+ internal NamedTempValue (LLVMValueRef value, string name = null)
{
+ this.Value = value;
+ this.Name = name;
+ }
+ }
+
+ /// Invoke an LLVM operation with given value mappings.
+ /// The operation is supposed to return a temp value to be stored.
+ private void InvokeOperation (Opcode op, ExtendedOpcode? exop, IOperand[] operands, Func emitFunc)
+ {
+ if (this.PrintDebugInfo) {
string opstr = $"[DEBUG] {op.ToString()} - ";
- foreach (IOperand od in operands)
- {
+ foreach (IOperand od in operands) {
opstr += od.Name;
opstr += " ";
}
- Console.WriteLine(opstr);
- }
-
- ValueMappings mappings = new ValueMappings(operands.Length);
- StorageTypedValue[] stvalues = mappings.Values;
- for (int i = 0; i < operands.Length; i++)
- {
- IOperand operand = operands[i];
- stvalues[i] = MakeStorageTypedValue(operand);
- }
-
- NamedTempValue ntv = emitFunc(mappings);
- if (ntv != null)
- {
- string name = ntv.Name;
- if (name == null)
- {
- name = LLVM.GetValueName(ntv.Value);
- }
- temps[name] = ntv.Value;
- }
- }
-
- /// Invoke an LLVM operation with given value mappings.
- /// The operation doesn't produce new temp values.
- private void InvokeOperation(
- Opcode op,
- ExtendedOpcode? exop,
- IOperand[] operands,
- Action emitFunc)
- {
- InvokeOperation(
- op,
- exop,
- operands,
- (vm) =>
- {
- emitFunc(vm);
- return null;
- });
- }
-
- private StorageTypedValue MakeStorageTypedValue(IOperand operand)
- {
- LLVMValueRef value = default(LLVMValueRef);
- StorageType stype = default(StorageType);
- switch (operand.OperandType)
- {
- case OperandType.Temp:
- stype = StorageType.Temp;
- value = GetTempValue(operand);
- break;
- case OperandType.Local:
- stype = StorageType.Address;
- value = GetLocalAddr(operand);
- break;
- case OperandType.Argument:
- stype = StorageType.Address;
- value = GetArgAddr(operand);
- break;
- case OperandType.Const:
- stype = StorageType.Const;
- value = GetConstValue(operand);
- break;
- }
- return new StorageTypedValue
- {
- Type = stype,
- Value = value
- };
- }
-
- private LLVMBasicBlockRef GetBranchTarget(IOperand operand)
- {
- BranchTargetOperand bto = (BranchTargetOperand)operand;
- int target = bto.PC;
- return GetOrAddBasicBlock(target, false);
- }
-
- private LLVMValueRef GetArgAddr(IOperand operand)
- {
- ArgumentOperand aod = (ArgumentOperand)operand;
- return this.argAddrs[aod.Index];
- }
-
- private LLVMValueRef GetLocalAddr(IOperand operand)
- {
- LocalOperand lod = (LocalOperand)operand;
- return this.localAddrs[lod.Index];
- }
-
- private LLVMValueRef GetTempValue(IOperand operand)
- {
- TempOperand tod = (TempOperand)operand;
- string name = tod.Name;
- return temps[tod.Name];
- }
-
- private LLVMValueRef GetConstValue(IOperand operand)
- {
- ConstOperand cod = (ConstOperand)operand;
- if (cod is Int32ConstOperand)
- {
- return LLVM.ConstInt(LLVM.Int32Type(), (ulong)((Int32ConstOperand)cod).Value, true);
- }
- if (cod is Int64ConstOperand)
- {
- return LLVM.ConstInt(LLVM.Int64Type(), (ulong)((Int64ConstOperand)cod).Value, true);
- }
- if (cod is Float32ConstOperand)
- {
- return LLVM.ConstReal(LLVM.FloatType(), ((Float32ConstOperand)cod).Value);
- }
- if (cod is Float64ConstOperand)
- {
- return LLVM.ConstReal(LLVM.FloatType(), ((Float64ConstOperand)cod).Value);
- }
-
- throw new Exception("Unexpected. The const operand is tno recognized.");
- }
-
- private static LLVMTypeRef TranslateType(ClrType ctyp)
- {
- if (ctyp == RuntimeInformation.BoolType)
- {
- return LLVM.Int1Type();
- }
- if (ctyp == RuntimeInformation.Int8Type)
- {
- return LLVM.Int8Type();
- }
- if (ctyp == RuntimeInformation.Int16Type || ctyp == RuntimeInformation.Int8Type)
- {
- return LLVM.Int16Type();
- }
- if (ctyp == RuntimeInformation.Int32TypeInstance || ctyp == RuntimeInformation.UInt16Type)
- {
- return LLVM.Int32Type();
- }
- if (ctyp == RuntimeInformation.Int64Type || ctyp == RuntimeInformation.UInt32Type)
- {
- return LLVM.Int64Type();
- }
- if (ctyp == RuntimeInformation.CharType)
- {
- return LLVM.Int16Type(); // Unicode
- }
- if (ctyp == RuntimeInformation.Float32Type || ctyp == RuntimeInformation.Float64Type)
- {
- return LLVM.FloatType();
- }
- if (ctyp == RuntimeInformation.NativeIntType || ctyp == RuntimeInformation.NativeUnsignedIntType)
- {
- return LLVM.Int64Type();
- }
- if (ctyp == RuntimeInformation.StringType)
- {
- return LLVM.PointerType(LLVM.Int16Type(), 0); // 0 = default address sapce
- }
- if (ctyp == RuntimeInformation.VoidTypeInstance)
- {
- return LLVM.VoidType();
- }
-
- Type typ = ctyp.AsSystemType;
- if (typ.IsClass)
- {
- return LLVM.PointerType(LLVM.Int64Type(), 0); // 0 = default address sapce
- }
-
- throw new Exception($"TODO: Cannot handle type { typ.Name } yet.");
- }
- }
-}
\ No newline at end of file
+ Console.WriteLine (opstr);
+ }
+
+ ValueMappings mappings = new ValueMappings (operands.Length);
+ StorageTypedValue[] stvalues = mappings.Values;
+ for (int i = 0; i < operands.Length; i++) {
+ IOperand operand = operands[i];
+ stvalues[i] = MakeStorageTypedValue (operand);
+ }
+
+ NamedTempValue ntv = emitFunc (mappings);
+ if (ntv != null) {
+ string name = ntv.Name;
+ if (name == null) {
+ name = LLVM.GetValueName (ntv.Value);
+ }
+ temps[name] = ntv.Value;
+ }
+ }
+
+ /// Invoke an LLVM operation with given value mappings.
+ /// The operation doesn't produce new temp values.
+ private void InvokeOperation (Opcode op, ExtendedOpcode? exop, IOperand[] operands, Action emitFunc)
+ {
+ InvokeOperation (op, exop, operands,
+ (vm) => {
+ emitFunc (vm);
+ return null;
+ });
+ }
+
+ private StorageTypedValue MakeStorageTypedValue (IOperand operand)
+ {
+ LLVMValueRef value = default (LLVMValueRef);
+ StorageType stype = default (StorageType);
+ switch (operand.OperandType) {
+ case OperandType.Temp:
+ stype = StorageType.Temp;
+ value = GetTempValue (operand);
+ break;
+ case OperandType.Local:
+ stype = StorageType.Address;
+ value = GetLocalAddr (operand);
+ break;
+ case OperandType.Argument:
+ stype = StorageType.Address;
+ value = GetArgAddr (operand);
+ break;
+ case OperandType.Const:
+ stype = StorageType.Const;
+ value = GetConstValue (operand);
+ break;
+ }
+ return new StorageTypedValue {
+ Type = stype,
+ Value = value
+ };
+ }
+
+ private LLVMBasicBlockRef GetBranchTarget (IOperand operand)
+ {
+ BranchTargetOperand bto = (BranchTargetOperand)operand;
+ int target = bto.PC;
+ return GetOrAddBasicBlock (target, false);
+ }
+
+ private LLVMValueRef GetArgAddr (IOperand operand)
+ {
+ ArgumentOperand aod = (ArgumentOperand)operand;
+ return this.argAddrs[aod.Index];
+ }
+
+ private LLVMValueRef GetLocalAddr (IOperand operand)
+ {
+ LocalOperand lod = (LocalOperand)operand;
+ return this.localAddrs[lod.Index];
+ }
+
+ private LLVMValueRef GetTempValue (IOperand operand)
+ {
+ TempOperand tod = (TempOperand)operand;
+ string name = tod.Name;
+ return temps[tod.Name];
+ }
+
+ private LLVMValueRef GetConstValue (IOperand operand)
+ {
+ ConstOperand cod = (ConstOperand)operand;
+ if (cod is Int32ConstOperand) {
+ return LLVM.ConstInt (LLVM.Int32Type (), (ulong)((Int32ConstOperand)cod).Value, true);
+ }
+ if (cod is Int64ConstOperand) {
+ return LLVM.ConstInt (LLVM.Int64Type (), (ulong)((Int64ConstOperand)cod).Value, true);
+ }
+ if (cod is Float32ConstOperand)
+ {
+ return LLVM.ConstReal (LLVM.FloatType (), ((Float32ConstOperand)cod).Value);
+ }
+ if (cod is Float64ConstOperand) {
+ return LLVM.ConstReal (LLVM.FloatType (), ((Float64ConstOperand)cod).Value);
+ }
+
+ throw new Exception ("Unexpected. The const operand is tno recognized.");
+ }
+
+ private static LLVMTypeRef TranslateType (ClrType ctyp)
+ {
+ if (ctyp == RuntimeInformation.BoolType) {
+ return LLVM.Int1Type ();
+ }
+ if (ctyp == RuntimeInformation.Int8Type) {
+ return LLVM.Int8Type ();
+ }
+ if (ctyp == RuntimeInformation.Int16Type || ctyp == RuntimeInformation.Int8Type) {
+ return LLVM.Int16Type ();
+ }
+ if (ctyp == RuntimeInformation.Int32TypeInstance || ctyp == RuntimeInformation.UInt16Type) {
+ return LLVM.Int32Type();
+ }
+ if (ctyp == RuntimeInformation.Int64Type || ctyp == RuntimeInformation.UInt32Type) {
+ return LLVM.Int64Type ();
+ }
+ if (ctyp == RuntimeInformation.CharType) {
+ return LLVM.Int16Type (); // Unicode
+ }
+ if (ctyp == RuntimeInformation.Float32Type || ctyp == RuntimeInformation.Float64Type) {
+ return LLVM.FloatType ();
+ }
+ if (ctyp == RuntimeInformation.NativeIntType || ctyp == RuntimeInformation.NativeUnsignedIntType) {
+ return LLVM.Int64Type ();
+ }
+ if (ctyp == RuntimeInformation.StringType) {
+ return LLVM.PointerType(LLVM.Int16Type (), 0); // 0 = default address sapce
+ }
+ if (ctyp == RuntimeInformation.VoidTypeInstance) {
+ return LLVM.VoidType();
+ }
+
+ Type typ = ctyp.AsSystemType;
+ if (typ.IsClass) {
+ return LLVM.PointerType(LLVM.Int64Type (), 0); // 0 = default address sapce
+ }
+
+ throw new Exception ($"TODO: Cannot handle type { typ.Name } yet.");
+ }
+ }
+}
diff --git a/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/OpResultTypeLookup.cs b/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/OpResultTypeLookup.cs
index 0ef5717acf51..fbac9b6a6103 100644
--- a/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/OpResultTypeLookup.cs
+++ b/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/OpResultTypeLookup.cs
@@ -8,267 +8,226 @@
///
/// Implemented "III.1.5 Operand type table"
///
-namespace Mono.Compiler.BigStep
-{
- // III.1.5 Operand type table
- internal class OpResultTypeLookup
- {
- internal static ClrType? Query(Opcode op, ExtendedOpcode? exop, params ClrType[] types)
- {
- if (exop.HasValue)
- {
- ExtendedOpcode exopcode = (ExtendedOpcode)exop;
- switch (exop)
- {
- // Table III.4: Binary Comparison or Branch Operations
- case ExtendedOpcode.Ceq:
- case ExtendedOpcode.Cgt:
- case ExtendedOpcode.CgtUn:
- case ExtendedOpcode.Clt:
- case ExtendedOpcode.CltUn:
- return RuntimeInformation.BoolType;
- }
- }
+namespace Mono.Compiler.BigStep {
+ // III.1.5 Operand type table
+ internal class OpResultTypeLookup {
+ internal static ClrType? Query (Opcode op, ExtendedOpcode? exop, params ClrType[] types)
+ {
+ if (exop.HasValue) {
+ ExtendedOpcode exopcode = (ExtendedOpcode)exop;
+ switch (exop) {
+ // Table III.4: Binary Comparison or Branch Operations
+ case ExtendedOpcode.Ceq:
+ case ExtendedOpcode.Cgt:
+ case ExtendedOpcode.CgtUn:
+ case ExtendedOpcode.Clt:
+ case ExtendedOpcode.CltUn:
+ return RuntimeInformation.BoolType;
+ }
+ }
- switch (op)
- {
- // Table III.2: Binary Numeric Operations
- // Table III.7: Overflow Arithmetic Operations
- case Opcode.Add:
- case Opcode.AddOvf:
- case Opcode.AddOvfUn:
- case Opcode.Sub:
- case Opcode.SubOvf:
- case Opcode.SubOvfUn:
- case Opcode.Mul:
- case Opcode.MulOvf:
- case Opcode.MulOvfUn:
- case Opcode.Div:
- case Opcode.Rem:
- return QueryBinaryOp(types[0], types[1]);
- // Table III.3: Unary Numeric Operations
- case Opcode.Neg:
- if (types[0] == RuntimeInformation.Int32TypeInstance && types[1] == RuntimeInformation.Int32TypeInstance)
- {
- return RuntimeInformation.BoolType;
- }
- if (types[0] == RuntimeInformation.Int64Type && types[1] == RuntimeInformation.Int64Type)
- {
- return RuntimeInformation.BoolType;
- }
- if (types[0] == RuntimeInformation.TypedRefType && types[1] == RuntimeInformation.TypedRefType)
- {
- return RuntimeInformation.BoolType;
- }
- if ((types[0] == RuntimeInformation.Float32Type || types[0] == RuntimeInformation.Float64Type) &&
- (types[1] == RuntimeInformation.Float32Type || types[1] == RuntimeInformation.Float64Type))
- {
- return RuntimeInformation.BoolType;
- }
- // This should never happen unless there are bugs in CSC.
- throw new Exception($"Unexpected. Operation { op.ToString() } cannot perform on operands of type { types[0].AsSystemType.Name } and { types[1].AsSystemType.Name }");
- // Table III.4: Binary Comparison or Branch Operations
- case Opcode.Beq:
- case Opcode.BeqS:
- case Opcode.Bge:
- case Opcode.BgeS:
- case Opcode.BgeUn:
- case Opcode.BgeUnS:
- case Opcode.Bgt:
- case Opcode.BgtS:
- case Opcode.BgtUn:
- case Opcode.BgtUnS:
- case Opcode.Ble:
- case Opcode.BleS:
- case Opcode.BleUn:
- case Opcode.BleUnS:
- case Opcode.Blt:
- case Opcode.BltS:
- case Opcode.BltUn:
- case Opcode.BltUnS:
- case Opcode.BneUn:
- case Opcode.BneUnS:
- return RuntimeInformation.BoolType;
- // Table III.5: Table III.5: Integer Operations
- case Opcode.And:
- case Opcode.Not:
- case Opcode.Or:
- case Opcode.Xor:
- case Opcode.RemUn:
- case Opcode.DivUn:
- // Reuse matrix defined for bianry ops since the valid set is a subset of the latter
- // and we always assume the validaity of input operands.
- return QueryBinaryOp(types[0], types[1]);
- // Table III.6: Shift Operations
- case Opcode.Shl:
- case Opcode.Shr:
- case Opcode.ShrUn:
- // operand 0: To Be Shifted
- // operand 1: Shift-By
- if (types[0] == RuntimeInformation.Int32TypeInstance &&
- (types[1] == RuntimeInformation.Int32TypeInstance || types[1] == RuntimeInformation.NativeIntType))
- {
- return RuntimeInformation.Int32TypeInstance;
- }
- if (types[0] == RuntimeInformation.Int64Type &&
- (types[1] == RuntimeInformation.Int32TypeInstance || types[1] == RuntimeInformation.NativeIntType))
- {
- return RuntimeInformation.Int64Type;
- }
- if (types[0] == RuntimeInformation.NativeIntType &&
- (types[1] == RuntimeInformation.Int32TypeInstance || types[1] == RuntimeInformation.NativeIntType))
- {
- return RuntimeInformation.NativeIntType;
- }
- // This should never happen unless there are bugs in CSC.
- throw new Exception($"Unexpected. Operation { op.ToString() } cannot perform on operands of type { types[0].AsSystemType.Name } and { types[1].AsSystemType.Name }");
- // Table III.8: Conversion Operations
- case Opcode.ConvI1:
- case Opcode.ConvU1:
- case Opcode.ConvI2:
- case Opcode.ConvU2:
- case Opcode.ConvI4:
- case Opcode.ConvU4:
- case Opcode.ConvOvfI1:
- case Opcode.ConvOvfI1Un:
- case Opcode.ConvOvfI2:
- case Opcode.ConvOvfI2Un:
- case Opcode.ConvOvfI4:
- case Opcode.ConvOvfI4Un:
- case Opcode.ConvI:
- case Opcode.ConvOvfI:
- case Opcode.ConvU:
- case Opcode.ConvOvfU:
- // For short integers,the stack value is truncated but remains the same type.
- return types[0];
- case Opcode.ConvI8:
- case Opcode.ConvU8:
- if (types[0] == RuntimeInformation.Float32Type ||
- (types[0] == RuntimeInformation.Int32TypeInstance))
- {
- return RuntimeInformation.Int64Type;
- }
- else
- {
- return types[0];
- }
- case Opcode.ConvR4:
- case Opcode.ConvR8:
- case Opcode.ConvRUn:
- return RuntimeInformation.Float64Type;
- default:
- return null;
- }
- }
+ switch (op) {
+ // Table III.2: Binary Numeric Operations
+ // Table III.7: Overflow Arithmetic Operations
+ case Opcode.Add:
+ case Opcode.AddOvf:
+ case Opcode.AddOvfUn:
+ case Opcode.Sub:
+ case Opcode.SubOvf:
+ case Opcode.SubOvfUn:
+ case Opcode.Mul:
+ case Opcode.MulOvf:
+ case Opcode.MulOvfUn:
+ case Opcode.Div:
+ case Opcode.Rem:
+ return QueryBinaryOp (types[0], types[1]);
+ // Table III.3: Unary Numeric Operations
+ case Opcode.Neg:
+ if (types[0] == RuntimeInformation.Int32TypeInstance && types[1] == RuntimeInformation.Int32TypeInstance) {
+ return RuntimeInformation.BoolType;
+ }
+ if (types[0] == RuntimeInformation.Int64Type && types[1] == RuntimeInformation.Int64Type) {
+ return RuntimeInformation.BoolType;
+ }
+ if (types[0] == RuntimeInformation.TypedRefType && types[1] == RuntimeInformation.TypedRefType) {
+ return RuntimeInformation.BoolType;
+ }
+ if ((types[0] == RuntimeInformation.Float32Type || types[0] == RuntimeInformation.Float64Type) &&
+ (types[1] == RuntimeInformation.Float32Type || types[1] == RuntimeInformation.Float64Type)) {
+ return RuntimeInformation.BoolType;
+ }
+ // This should never happen unless there are bugs in CSC.
+ throw new Exception ($"Unexpected. Operation { op.ToString () } cannot perform on operands of type { types[0].AsSystemType.Name } and { types[1].AsSystemType.Name }");
+ // Table III.4: Binary Comparison or Branch Operations
+ case Opcode.Beq:
+ case Opcode.BeqS:
+ case Opcode.Bge:
+ case Opcode.BgeS:
+ case Opcode.BgeUn:
+ case Opcode.BgeUnS:
+ case Opcode.Bgt:
+ case Opcode.BgtS:
+ case Opcode.BgtUn:
+ case Opcode.BgtUnS:
+ case Opcode.Ble:
+ case Opcode.BleS:
+ case Opcode.BleUn:
+ case Opcode.BleUnS:
+ case Opcode.Blt:
+ case Opcode.BltS:
+ case Opcode.BltUn:
+ case Opcode.BltUnS:
+ case Opcode.BneUn:
+ case Opcode.BneUnS:
+ return RuntimeInformation.BoolType;
+ // Table III.5: Table III.5: Integer Operations
+ case Opcode.And:
+ case Opcode.Not:
+ case Opcode.Or:
+ case Opcode.Xor:
+ case Opcode.RemUn:
+ case Opcode.DivUn:
+ // Reuse matrix defined for bianry ops since the valid set is a subset of the latter
+ // and we always assume the validaity of input operands.
+ return QueryBinaryOp (types[0], types[1]);
+ // Table III.6: Shift Operations
+ case Opcode.Shl:
+ case Opcode.Shr:
+ case Opcode.ShrUn:
+ // operand 0: To Be Shifted
+ // operand 1: Shift-By
+ if (types[0] == RuntimeInformation.Int32TypeInstance &&
+ (types[1] == RuntimeInformation.Int32TypeInstance || types[1] == RuntimeInformation.NativeIntType)) {
+ return RuntimeInformation.Int32TypeInstance;
+ }
+ if (types[0] == RuntimeInformation.Int64Type &&
+ (types[1] == RuntimeInformation.Int32TypeInstance || types[1] == RuntimeInformation.NativeIntType)) {
+ return RuntimeInformation.Int64Type;
+ }
+ if (types[0] == RuntimeInformation.NativeIntType &&
+ (types[1] == RuntimeInformation.Int32TypeInstance || types[1] == RuntimeInformation.NativeIntType)) {
+ return RuntimeInformation.NativeIntType;
+ }
+ // This should never happen unless there are bugs in CSC.
+ throw new Exception ($"Unexpected. Operation { op.ToString () } cannot perform on operands of type { types[0].AsSystemType.Name } and { types[1].AsSystemType.Name }");
+ // Table III.8: Conversion Operations
+ case Opcode.ConvI1:
+ case Opcode.ConvU1:
+ case Opcode.ConvI2:
+ case Opcode.ConvU2:
+ case Opcode.ConvI4:
+ case Opcode.ConvU4:
+ case Opcode.ConvOvfI1:
+ case Opcode.ConvOvfI1Un:
+ case Opcode.ConvOvfI2:
+ case Opcode.ConvOvfI2Un:
+ case Opcode.ConvOvfI4:
+ case Opcode.ConvOvfI4Un:
+ case Opcode.ConvI:
+ case Opcode.ConvOvfI:
+ case Opcode.ConvU:
+ case Opcode.ConvOvfU:
+ // For short integers,the stack value is truncated but remains the same type.
+ return types[0];
+ case Opcode.ConvI8:
+ case Opcode.ConvU8:
+ if (types[0] == RuntimeInformation.Float32Type ||
+ (types[0] == RuntimeInformation.Int32TypeInstance)) {
+ return RuntimeInformation.Int64Type;
+ } else {
+ return types[0];
+ }
+ case Opcode.ConvR4:
+ case Opcode.ConvR8:
+ case Opcode.ConvRUn:
+ return RuntimeInformation.Float64Type;
+ default:
+ return null;
+ }
+ }
- internal class CilTypePair
- {
- private string notation;
+ internal class CilTypePair {
+ private string notation;
- private CilTypePair(ClrType ta, ClrType tb)
- {
- string sa = ClrTypeToString(ta);
- string sb = ClrTypeToString(tb);
- notation = sb + "-" + sb;
- }
+ private CilTypePair (ClrType ta, ClrType tb)
+ {
+ string sa = ClrTypeToString (ta);
+ string sb = ClrTypeToString (tb);
+ notation = sb + "-" + sb;
+ }
- public override int GetHashCode()
- {
- return notation.GetHashCode();
- }
+ public override int GetHashCode ()
+ {
+ return notation.GetHashCode ();
+ }
- public override bool Equals(object obj)
- {
- if (obj != null && obj is CilTypePair)
- {
- return notation == ((CilTypePair)obj).notation;
- }
+ public override bool Equals (object obj)
+ {
+ if (obj != null && obj is CilTypePair) {
+ return notation == ((CilTypePair)obj).notation;
+ }
- return false;
- }
+ return false;
+ }
- internal static CilTypePair Create(ClrType ta, ClrType tb)
- {
- return new CilTypePair(ta, tb);
- }
- }
+ internal static CilTypePair Create (ClrType ta, ClrType tb)
+ {
+ return new CilTypePair (ta, tb);
+ }
+ }
- // Convert the type to one of five types tracked by CLI for operator result verification
- private static String ClrTypeToString(ClrType type)
- {
- if (type == RuntimeInformation.Int32TypeInstance)
- {
- return "int32";
- }
- if (type == RuntimeInformation.Int64Type)
- {
- return "int64";
- }
- if (type == RuntimeInformation.NativeIntType)
- {
- return "nativeint";
- }
- else if (type == RuntimeInformation.TypedRefType)
- {
- return "&"; // Is this even correct?
- }
- else
- {
- Type t = type.AsSystemType;
- if (t.IsClass)
- {
- return "O";
- }
- else
- {
- return "?";
- }
- }
- }
+ // Convert the type to one of five types tracked by CLI for operator result verification
+ private static String ClrTypeToString (ClrType type)
+ {
+ if (type == RuntimeInformation.Int32TypeInstance) {
+ return "int32";
+ }
+ if (type == RuntimeInformation.Int64Type) {
+ return "int64";
+ }
+ if (type == RuntimeInformation.NativeIntType) {
+ return "nativeint";
+ } else if (type == RuntimeInformation.TypedRefType) {
+ return "&"; // Is this even correct?
+ } else {
+ Type t = type.AsSystemType;
+ if (t.IsClass) {
+ return "O";
+ } else {
+ return "?";
+ }
+ }
+ }
- internal static ClrType QueryBinaryOp(ClrType ta, ClrType tb)
- {
- return binaryOpResults[CilTypePair.Create(ta, tb)];
- }
+ internal static ClrType QueryBinaryOp (ClrType ta, ClrType tb)
+ {
+ return binaryOpResults[CilTypePair.Create (ta, tb)];
+ }
- private static Dictionary binaryOpResults;
+ private static Dictionary binaryOpResults;
- static OpResultTypeLookup()
- {
- binaryOpResults = new Dictionary();
- binaryOpResults[CilTypePair.Create(RuntimeInformation.Int32TypeInstance, RuntimeInformation.Int32TypeInstance)]
- = RuntimeInformation.Int32TypeInstance;
- binaryOpResults[CilTypePair.Create(RuntimeInformation.Int64Type, RuntimeInformation.Int64Type)]
- = RuntimeInformation.Int64Type;
- binaryOpResults[CilTypePair.Create(RuntimeInformation.Int32TypeInstance, RuntimeInformation.NativeIntType)]
- = RuntimeInformation.NativeIntType;
- binaryOpResults[CilTypePair.Create(RuntimeInformation.NativeIntType, RuntimeInformation.Int32TypeInstance)]
- = RuntimeInformation.NativeIntType;
- binaryOpResults[CilTypePair.Create(RuntimeInformation.NativeIntType, RuntimeInformation.NativeIntType)]
- = RuntimeInformation.NativeIntType;
+ static OpResultTypeLookup ()
+ {
+ binaryOpResults = new Dictionary ();
+ binaryOpResults[CilTypePair.Create(RuntimeInformation.Int32TypeInstance, RuntimeInformation.Int32TypeInstance)] = RuntimeInformation.Int32TypeInstance;
+ binaryOpResults[CilTypePair.Create(RuntimeInformation.Int64Type, RuntimeInformation.Int64Type)] = RuntimeInformation.Int64Type;
+ binaryOpResults[CilTypePair.Create(RuntimeInformation.Int32TypeInstance, RuntimeInformation.NativeIntType)] = RuntimeInformation.NativeIntType;
+ binaryOpResults[CilTypePair.Create(RuntimeInformation.NativeIntType, RuntimeInformation.Int32TypeInstance)] = RuntimeInformation.NativeIntType;
+ binaryOpResults[CilTypePair.Create(RuntimeInformation.NativeIntType, RuntimeInformation.NativeIntType)] = RuntimeInformation.NativeIntType;
- // For F types, always result in long type for now. This needs re-visiting
- binaryOpResults[CilTypePair.Create(RuntimeInformation.Float32Type, RuntimeInformation.Float32Type)]
- = RuntimeInformation.Float64Type;
- binaryOpResults[CilTypePair.Create(RuntimeInformation.Float32Type, RuntimeInformation.Float64Type)]
- = RuntimeInformation.Float64Type;
- binaryOpResults[CilTypePair.Create(RuntimeInformation.Float64Type, RuntimeInformation.Float32Type)]
- = RuntimeInformation.Float64Type;
- binaryOpResults[CilTypePair.Create(RuntimeInformation.Float64Type, RuntimeInformation.Float64Type)]
- = RuntimeInformation.Float64Type;
+ // For F types, always result in long type for now. This needs re-visiting
+ binaryOpResults[CilTypePair.Create(RuntimeInformation.Float32Type, RuntimeInformation.Float32Type)] = RuntimeInformation.Float64Type;
+ binaryOpResults[CilTypePair.Create(RuntimeInformation.Float32Type, RuntimeInformation.Float64Type)] = RuntimeInformation.Float64Type;
+ binaryOpResults[CilTypePair.Create(RuntimeInformation.Float64Type, RuntimeInformation.Float32Type)] = RuntimeInformation.Float64Type;
+ binaryOpResults[CilTypePair.Create(RuntimeInformation.Float64Type, RuntimeInformation.Float64Type)] = RuntimeInformation.Float64Type;
- // For & types, they are only applicable to certain OPs.
- // But since we assume the validity of the input, do not perform such checks.
- binaryOpResults[CilTypePair.Create(RuntimeInformation.Int32TypeInstance, RuntimeInformation.TypedRefType)]
- = RuntimeInformation.TypedRefType;
- binaryOpResults[CilTypePair.Create(RuntimeInformation.NativeIntType, RuntimeInformation.TypedRefType)]
- = RuntimeInformation.TypedRefType;
- binaryOpResults[CilTypePair.Create(RuntimeInformation.TypedRefType, RuntimeInformation.Int32TypeInstance)]
- = RuntimeInformation.TypedRefType;
- binaryOpResults[CilTypePair.Create(RuntimeInformation.TypedRefType, RuntimeInformation.NativeIntType)]
- = RuntimeInformation.TypedRefType;
- binaryOpResults[CilTypePair.Create(RuntimeInformation.TypedRefType, RuntimeInformation.TypedRefType)]
- = RuntimeInformation.TypedRefType;
- }
- }
-}
\ No newline at end of file
+ // For & types, they are only applicable to certain OPs.
+ // But since we assume the validity of the input, do not perform such checks.
+ binaryOpResults[CilTypePair.Create(RuntimeInformation.Int32TypeInstance, RuntimeInformation.TypedRefType)] = RuntimeInformation.TypedRefType;
+ binaryOpResults[CilTypePair.Create(RuntimeInformation.NativeIntType, RuntimeInformation.TypedRefType)] = RuntimeInformation.TypedRefType;
+ binaryOpResults[CilTypePair.Create(RuntimeInformation.TypedRefType, RuntimeInformation.Int32TypeInstance)] = RuntimeInformation.TypedRefType;
+ binaryOpResults[CilTypePair.Create(RuntimeInformation.TypedRefType, RuntimeInformation.NativeIntType)] = RuntimeInformation.TypedRefType;
+ binaryOpResults[CilTypePair.Create(RuntimeInformation.TypedRefType, RuntimeInformation.TypedRefType)] = RuntimeInformation.TypedRefType;
+ }
+ }
+}
diff --git a/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/Operand.cs b/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/Operand.cs
index 374edeb9d18f..80b11352c441 100644
--- a/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/Operand.cs
+++ b/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/Operand.cs
@@ -20,175 +20,153 @@
/// Constant: C + [The value itself in form of string]
/// PC: PC (name for this operand type is not important)
///
-namespace Mono.Compiler.BigStep
-{
- internal enum OperandType
- {
- /// The operand is a method argument.
- Argument,
- /// The operand is a user-defined local variable.
- Local,
- /// The operand is a machine-defined local variable for temporary use.
- Temp,
- /// The operand is a constant value stored as part of the instruction.
- Const,
- /// The operand is a value for the logical program counter.
- PC
- }
-
- internal interface IOperand
- {
- string Name { get; }
- ClrType Type { get; }
- OperandType OperandType { get; }
- }
-
- abstract internal class Operand : IOperand
- {
- public virtual string Name { get; private set; }
- public ClrType Type { get; private set; }
-
- internal Operand(string name, ClrType type)
- {
- Name = name;
- Type = type;
- }
-
- public virtual OperandType OperandType { get; }
- }
-
- internal class BranchTargetOperand : Operand
- {
- public int PC { get; private set; }
-
- internal BranchTargetOperand(int pcvalue)
- : base("PC", RuntimeInformation.VoidTypeInstance)
- {
- PC = pcvalue;
- }
-
- public override OperandType OperandType => OperandType.PC;
- }
-
- internal class ArgumentOperand : Operand
- {
- public int Index { get; private set; }
-
- internal ArgumentOperand(int index, ClrType type)
- : base("A" + index, type)
- {
- Index = index;
- }
-
- public override OperandType OperandType => OperandType.Argument;
- }
-
- internal class LocalOperand : Operand
- {
- public int Index { get; private set; }
-
- internal LocalOperand(int index, ClrType type)
- : base("L" + index, type)
- {
- Index = index;
- }
-
- public override OperandType OperandType => OperandType.Local;
- }
-
- internal abstract class ConstOperand : Operand
- {
- protected ConstOperand(ClrType type)
- : base("C", type) // "C" is just a prefix. See overridden name getters in subclasses
- {
- }
-
- public override OperandType OperandType => OperandType.Const;
- }
-
- internal class Int32ConstOperand : ConstOperand
- {
- public int Value { get; private set; }
-
- internal Int32ConstOperand(int value)
- : base(RuntimeInformation.Int32TypeInstance)
- {
- Value = value;
- }
-
- public override string Name {
- get {
- return base.Name + Value.ToString();
- }
- }
- }
-
- internal class Int64ConstOperand : ConstOperand
- {
-
- public long Value { get; private set; }
-
- internal Int64ConstOperand(long value)
- : base(RuntimeInformation.Int64Type)
- {
- Value = value;
- }
-
- public override string Name {
- get {
- return base.Name + Value.ToString();
- }
- }
- }
-
- internal class Float32ConstOperand : ConstOperand
- {
- public float Value { get; private set; }
-
- internal Float32ConstOperand(float value)
- : base(RuntimeInformation.Float32Type)
- {
- Value = value;
- }
-
- public override string Name {
- get {
- return base.Name + Value.ToString();
- }
- }
- }
-
- internal class Float64ConstOperand : ConstOperand
- {
-
- public double Value { get; private set; }
-
- internal Float64ConstOperand(double value)
- : base(RuntimeInformation.Float64Type)
- {
- Value = value;
- }
-
- public override string Name {
- get {
- return base.Name + Value.ToString();
- }
- }
- }
-
- internal class TempOperand : Operand
- {
- internal TempOperand(INameGenerator nameGen, ClrType type)
- : base("T" + nameGen.NextName(), type)
- {
- }
-
- public override OperandType OperandType => OperandType.Temp;
- }
-
- public interface INameGenerator
- {
- string NextName();
- }
+namespace Mono.Compiler.BigStep {
+ internal enum OperandType {
+ /// The operand is a method argument.
+ Argument,
+ /// The operand is a user-defined local variable.
+ Local,
+ /// The operand is a machine-defined local variable for temporary use.
+ Temp,
+ /// The operand is a constant value stored as part of the instruction.
+ Const,
+ /// The operand is a value for the logical program counter.
+ PC
+ }
+
+ internal interface IOperand {
+ string Name { get; }
+ ClrType Type { get; }
+ OperandType OperandType { get; }
+ }
+
+ abstract internal class Operand : IOperand {
+ public virtual string Name { get; private set; }
+ public ClrType Type { get; private set; }
+
+ internal Operand (string name, ClrType type)
+ {
+ Name = name;
+ Type = type;
+ }
+
+ public virtual OperandType OperandType { get; }
+ }
+
+ internal class BranchTargetOperand : Operand {
+ public int PC { get; private set; }
+
+ internal BranchTargetOperand (int pcvalue)
+ : base ("PC", RuntimeInformation.VoidTypeInstance)
+ {
+ PC = pcvalue;
+ }
+
+ public override OperandType OperandType => OperandType.PC;
+ }
+
+ internal class ArgumentOperand : Operand {
+ public int Index { get; private set; }
+
+ internal ArgumentOperand (int index, ClrType type)
+ : base ("A" + index, type)
+ {
+ Index = index;
+ }
+
+ public override OperandType OperandType => OperandType.Argument;
+ }
+
+ internal class LocalOperand : Operand {
+ public int Index { get; private set; }
+
+ internal LocalOperand (int index, ClrType type)
+ : base ("L" + index, type)
+ {
+ Index = index;
+ }
+
+ public override OperandType OperandType => OperandType.Local;
+ }
+
+ internal abstract class ConstOperand : Operand {
+ protected ConstOperand (ClrType type)
+ : base ("C", type) // "C" is just a prefix. See overridden name getters in subclasses
+ {
+ }
+
+ public override OperandType OperandType => OperandType.Const;
+ }
+
+ internal class Int32ConstOperand : ConstOperand {
+ public int Value { get; private set; }
+
+ internal Int32ConstOperand (int value)
+ : base (RuntimeInformation.Int32TypeInstance)
+ {
+ Value = value;
+ }
+
+ public override string Name {
+ get { return base.Name + Value.ToString (); }
+ }
+ }
+
+ internal class Int64ConstOperand : ConstOperand {
+
+ public long Value { get; private set; }
+
+ internal Int64ConstOperand (long value)
+ : base (RuntimeInformation.Int64Type)
+ {
+ Value = value;
+ }
+
+ public override string Name {
+ get { return base.Name + Value.ToString (); }
+ }
+ }
+
+ internal class Float32ConstOperand : ConstOperand {
+ public float Value { get; private set; }
+
+ internal Float32ConstOperand (float value)
+ : base (RuntimeInformation.Float32Type)
+ {
+ Value = value;
+ }
+
+ public override string Name {
+ get { return base.Name + Value.ToString (); }
+ }
+ }
+
+ internal class Float64ConstOperand : ConstOperand {
+
+ public double Value { get; private set; }
+
+ internal Float64ConstOperand (double value)
+ : base (RuntimeInformation.Float64Type)
+ {
+ Value = value;
+ }
+
+ public override string Name {
+ get { return base.Name + Value.ToString (); }
+ }
+ }
+
+ internal class TempOperand : Operand {
+ internal TempOperand (INameGenerator nameGen, ClrType type)
+ : base ("T" + nameGen.NextName(), type)
+ {
+ }
+
+ public override OperandType OperandType => OperandType.Temp;
+ }
+
+ public interface INameGenerator {
+ string NextName ();
+ }
}
diff --git a/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/OperationProcessor.cs b/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/OperationProcessor.cs
index 4b3c8955e83f..183da5f9ed68 100644
--- a/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/OperationProcessor.cs
+++ b/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/OperationProcessor.cs
@@ -10,29 +10,29 @@
///
namespace Mono.Compiler.BigStep
{
- public class OperationInfo
- {
- /// The logical program counter for this operation.
- internal int Index { get; set; }
+ public class OperationInfo
+ {
+ /// The logical program counter for this operation.
+ internal int Index { get; set; }
- /// The operands may come from stack, arguments, locals or constants.
- internal IOperand[] Operands { get; set; }
+ /// The operands may come from stack, arguments, locals or constants.
+ internal IOperand[] Operands { get; set; }
- /// The result is pushed to the stack.
- internal TempOperand Result { get; set; }
+ /// The result is pushed to the stack.
+ internal TempOperand Result { get; set; }
- /// The operation.
- internal Opcode Operation { get; set; }
+ /// The operation.
+ internal Opcode Operation { get; set; }
- /// The extended operation. Has value only if Operation == Opcode.ExtendedPrefix
- internal ExtendedOpcode? ExtOperation { get; set; }
+ /// The extended operation. Has value only if Operation == Opcode.ExtendedPrefix
+ internal ExtendedOpcode? ExtOperation { get; set; }
- /// Thie operation is a jump target.
- internal bool JumpTarget { get; set; }
- }
+ /// Thie operation is a jump target.
+ internal bool JumpTarget { get; set; }
+ }
- public interface IOperationProcessor
- {
- void Process(OperationInfo opInfo);
- }
-}
\ No newline at end of file
+ public interface IOperationProcessor
+ {
+ void Process (OperationInfo opInfo);
+ }
+}
diff --git a/mcs/class/Mono.Compiler/Mono.Compiler.dll.sources b/mcs/class/Mono.Compiler/Mono.Compiler.dll.sources
index 5264f4c1f5b0..5d11f205a5e3 100644
--- a/mcs/class/Mono.Compiler/Mono.Compiler.dll.sources
+++ b/mcs/class/Mono.Compiler/Mono.Compiler.dll.sources
@@ -13,8 +13,6 @@ Mono.Compiler/NativeCodeHandle.cs
Mono.Compiler/RuntimeInformation.cs
Mono.Compiler.BigStep/BigStep.cs
-Mono.Compiler.BigStep/BSType.cs
-Mono.Compiler.BigStep/ArgStack.cs
Mono.Compiler.BigStep/CILSymbolicExecutor.cs
Mono.Compiler.BigStep/OpResultTypeLookup.cs