Exemplo n.º 1
0
        public Construct VisitArray(Constructs.Array node)
        {
            // Prepare the value buffer list.
            List <LlvmValue> values = new List <LlvmValue>();

            // Iterate and emit all the values onto the buffer list.
            foreach (Value value in node.Values)
            {
                // Visit the value.
                this.VisitValue(value);

                // Pop the value off the stack.
                LlvmValue llvmValue = this.valueStack.Pop();

                // Append the value onto the buffer list.
                values.Add(llvmValue);
            }

            // Visit the kind.
            this.VisitKind(node.Kind);

            // Pop the type off the stack.
            LlvmType elementType = this.typeStack.Pop();

            // Create the array.
            LlvmValue array = LlvmFactory.Array(elementType, values.ToArray());

            // Append the array onto the stack.
            this.valueStack.Push(array);

            // Return the node.
            return(node);
        }
Exemplo n.º 2
0
        public Construct VisitStruct(Struct node)
        {
            // Ensure target struct exists on the symbol table.
            if (!context.SymbolTable.structs.Contains(node.TargetIdentifier))
            {
                throw new Exception($"Reference to undefined struct named '${node.TargetIdentifier}'");
            }

            // Retrieve the symbol from the symbol table.
            StructSymbol symbol = context.SymbolTable.structs[this.TargetIdentifier];

            // Retrieve the target struct's LLVM reference value from the symbol.
            LLVMTypeRef structDef = symbol.Value;

            // Create a value buffer list.
            List <LLVMValueRef> values = new List <LLVMValueRef>();

            // Populate body properties.
            foreach (StructProperty property in node.Body)
            {
                // Emit and append the value to the buffer list.
                values.Add(property.Value.Emit(context));
            }

            // Create the resulting struct assignment value.
            LlvmValue assignment = LLVM.ConstNamedStruct(structDef, values.ToArray()).Wrap();

            // Append the assignment value onto the stack.
            this.valueStack.Push(assignment);

            // Return the node.
            return(node);
        }
Exemplo n.º 3
0
        public Construct VisitGlobal(Global node)
        {
            // Visit the kind.
            this.VisitKind(node.Kind);

            // Pop the type off the stack.
            LlvmType type = this.typeStack.Pop();

            // Create the global variable.
            LlvmGlobal global = this.module.CreateGlobal(node.Identifier, type);

            // Set the linkage to common.
            global.SetLinkage(LLVMLinkage.LLVMCommonLinkage);

            // Assign initial value if applicable.
            if (node.InitialValue != null)
            {
                // Visit the initial value.
                this.Visit(node.InitialValue);

                // Pop off the initial value off the stack.
                LlvmValue initialValue = this.valueStack.Pop();

                // Set the initial value.
                global.SetInitialValue(initialValue);
            }

            // Append the global onto the stack.
            this.valueStack.Push(global);

            // Return the node.
            return(node);
        }
Exemplo n.º 4
0
        public Construct VisitStoreInst(StoreInst node)
        {
            // Create the LLVM store instruction.
            LlvmValue value = this.builder.CreateStore(node.Value, node.Target);

            // Append the resulting instruction onto the stack.
            this.valueStack.Push(value);

            // Return the node.
            return(node);
        }
Exemplo n.º 5
0
        public Construct VisitExtern(Extern node)
        {
            // Ensure prototype is set.
            if (node.Prototype == null)
            {
                throw new Exception("Unexpected external definition's prototype to be null");
            }

            // Create the argument buffer list.
            List <LlvmType> arguments = new List <LlvmType>();

            // TODO: What about reference? Arguments must be named for extern?
            foreach ((Kind kind, Reference reference) in node.Prototype.Arguments)
            {
                // Visit the kind.
                this.VisitKind(kind);

                // Pop the type off the stack.
                LlvmType argumentType = this.typeStack.Pop();

                // Append onto the arguments list.
                arguments.Add(argumentType);
            }

            // Visit the prototype's return kind.
            this.Visit(node.Prototype.ReturnKind);

            // Pop the return type off the stack.
            LlvmType returnType = this.typeStack.Pop();

            // Emit the function type.
            LlvmType type = LlvmFactory.Function(returnType, arguments.ToArray(), node.Prototype.HasInfiniteArguments);

            // Emit the external definition to context and capture the LLVM value reference.
            LlvmValue @extern = this.module.CreateFunction(node.Prototype.Identifier, type);

            // Determine if should be registered on the symbol table.
            if (!this.module.ContainsFunction(node.Prototype.Identifier))
            {
                // Register the external definition as a function in the symbol table.
                this.module.RegisterFunction((LlvmFunction)@extern);
            }
            // Otherwise, throw an error.
            else
            {
                throw new Exception($"Warning: Extern definition '{node.Prototype.Identifier}' being re-defined");
            }

            // Push the resulting value onto the stack.
            this.valueStack.Push(@extern);

            // Return the node.
            return(node);
        }
Exemplo n.º 6
0
        public Construct VisitNumericExpr(NumericExpr node)
        {
            // Create the value.
            LlvmValue reference = Resolver.Literal(node.TokenType, node.Value, node.Type);

            // Append the value onto the stack.
            this.valueStack.Push(reference);

            // Return the node.
            return(node);
        }
Exemplo n.º 7
0
        public Construct VisitIf(If node)
        {
            // TODO: Action and alternative blocks not being handled, for debugging purposes.

            // Visit the condition.
            this.Visit(node.Condition);

            // Pop the condition off the stack.
            LlvmValue conditionValue = this.valueStack.Pop();

            // Create a zero-value double for the boolean comparison.
            LlvmValue zero = LlvmFactory.Double(0);

            // TODO: Hard-coded name.
            // Build the comparison, condition will be convered to a boolean for a 'ONE' (non-equal) comparison.
            LlvmValue comparison = LLVM.BuildFCmp(this.builder.Unwrap(), LLVMRealPredicate.LLVMRealONE, conditionValue.Unwrap(), zero.Unwrap(), "ifcond").Wrap();

            // Retrieve the parent function from the builder.
            LlvmFunction function = this.builder.Block.Parent;

            // Create the action block.
            LlvmBlock action = function.AppendBlock("then");

            // TODO: Debugging, Ret void for action.
            action.Builder.CreateReturnVoid();

            LlvmBlock otherwise = function.AppendBlock("else");

            // TODO: Debugging, ret void for otherwise.
            otherwise.Builder.CreateReturnVoid();

            LlvmBlock merge = function.AppendBlock("ifcont");

            // TODO: Debugging, ret void for merge.
            merge.Builder.CreateReturnVoid();

            // Build the if construct.
            LlvmValue @if = LLVM.BuildCondBr(this.builder.Unwrap(), comparison.Unwrap(), action.Unwrap(), otherwise.Unwrap()).Wrap();

            // TODO: Complete implementation, based off: https://github.com/microsoft/LLVMSharp/blob/master/KaleidoscopeTutorial/Chapter5/KaleidoscopeLLVM/CodeGenVisitor.cs#L214
            // ...

            // TODO: Debugging, not complete.
            action.Builder.PositionAtEnd(); // ? Delete..

            // Append the if construct onto the stack.
            this.valueStack.Push(@if);

            // Return the node.
            return(node);
        }
Exemplo n.º 8
0
        public Construct VisitString(IR.Constructs.String node)
        {
            // TODO: Global string name.
            // Retrieve a string name.
            string name = "str";

            // Create the global string pointer.
            LlvmValue stringPtr = this.builder.CreateGlobalString(node.Value, name, true);

            // Append the pointer value onto the stack.
            this.valueStack.Push(stringPtr);

            // Return the node.
            return(node);
        }
Exemplo n.º 9
0
        public Construct VisitCallInst(CallInst node)
        {
            // Create an argument buffer list.
            List <LlvmValue> arguments = new List <LlvmValue>();

            // Emit the call arguments.
            foreach (Constructs.Construct argument in node.Arguments)
            {
                // Continue if the argument is null.
                if (argument == null)
                {
                    continue;
                }

                // Visit the argument.
                this.Visit(argument);

                // Pop the argument off the value stack.
                LlvmValue argumentValue = this.valueStack.Pop();

                // Append argument value to the argument buffer list.
                arguments.Add(argumentValue);
            }

            // Retrieve the callee function.
            LlvmFunction callee = node.Callee;

            // Ensure argument count is correct (with continuous arguments).
            if (callee.HasInfiniteArguments && arguments.Count < callee.ArgumentCount - 1)
            {
                throw new Exception($"Target function requires at least {callee.ArgumentCount - 1} argument(s)");
            }
            // Otherwise, expect the argument count to be exact.
            else if (arguments.Count != callee.ArgumentCount)
            {
                throw new Exception($"Argument amount mismatch, target function requires exactly {callee.ArgumentCount} argument(s)");
            }

            // Create the function call.
            LlvmValue call = this.builder.CreateCall(callee, node.ResultIdentifier, arguments.ToArray());

            // Append the value onto the stack.
            this.valueStack.Push(call);

            // Return the node.
            return(node);
        }
Exemplo n.º 10
0
        public Construct VisitInteger(Integer node)
        {
            // Visit the kind.
            this.VisitKind(node.Kind);

            // Pop the resulting type off the stack.
            LlvmType type = this.typeStack.Pop();

            // Convert to a constant and return as an llvm value wrapper instance.
            LlvmValue value = LlvmFactory.Int(type, node.Value);

            // Push the value onto the stack.
            this.valueStack.Push(value);

            // Return the node.
            return(node);
        }
Exemplo n.º 11
0
        public Construct VisitEndInst(EndInst node)
        {
            // Visit the value.
            this.VisitValue(node.Value);

            // Pop off the resulting value.
            LlvmValue value = this.valueStack.Pop();

            // Create the return instruction.
            LlvmValue returnInst = this.builder.CreateReturn(value);

            // Append the return instruction onto the stack.
            this.valueStack.Push(returnInst);

            // Return the node.
            return(node);
        }
Exemplo n.º 12
0
        public Construct VisitCreateInst(CreateInst node)
        {
            // Visit the kind.
            this.VisitKind(node.Kind);

            // Pop the type off the stack.
            LlvmType type = this.typeStack.Pop();

            // Create the LLVM alloca instruction.
            LlvmValue value = this.builder.CreateAlloca(type, node.ResultIdentifier);

            // Append the resulting value onto the stack.
            this.valueStack.Push(value);

            // Return the node.
            return(node);
        }
Exemplo n.º 13
0
        public Construct VisitVarDeclare(VarDeclare node)
        {
            // Create the variable.
            LlvmValue variable = LLVM.BuildAlloca(context.Target, this.ValueType.Emit(), node.Identifier);

            // Assign value if applicable.
            if (node.Value != null)
            {
                // Create the store instruction.
                LLVM.BuildStore(context.Target, node.Value.Emit(context), variable);

                // Register on symbol table.
                context.SymbolTable.localScope.Add(node.Identifier, variable);
            }

            // Append the value onto the stack.
            this.valueStack.Push(variable);

            // Return the node.
            return(node);
        }
Exemplo n.º 14
0
        public Construct VisitBinaryExpr(BinaryExpr node)
        {
            // Visit left side.
            this.Visit(node.LeftSide);

            // Visit right side.
            this.Visit(node.RightSide);

            // Pop right side off the stack.
            LlvmValue rightSide = this.valueStack.Pop();

            // Pop left side off the stack.
            LlvmValue leftSide = this.valueStack.Pop();

            // Create a value buffer.
            LlvmValue binaryExpr = this.builder.CreateAdd(leftSide, rightSide, node.ResultIdentifier);

            // Push the resulting value onto the stack.
            this.valueStack.Push(binaryExpr);

            // Return the node.
            return(node);
        }
Exemplo n.º 15
0
        public Construct VisitPrototype(Prototype node)
        {
            // Retrieve argument count within node.
            uint argumentCount = (uint)node.Arguments.Length;

            // Create the argument buffer array.
            LlvmType[] arguments = new LlvmType[Math.Max(argumentCount, 1)];

            // Attempt to retrieve an existing function value.
            LlvmFunction?function = this.module.GetFunction(node.Identifier);

            // Function may be already defined.
            if (function != null)
            {
                // Function already has a body, disallow re-definition.
                if (function.HasBlocks)
                {
                    throw new Exception($"Cannot re-define function: {node.Identifier}");
                }
                // If the function takes a different number of arguments, reject.
                else if (function.ArgumentCount != argumentCount)
                {
                    throw new Exception("redefinition of function with different # args");
                }
            }
            else
            {
                // TODO: Wrong type.
                for (int i = 0; i < argumentCount; ++i)
                {
                    arguments[i] = LLVM.DoubleType().Wrap();
                }

                // TODO: Support for infinite arguments and hard-coded return type.
                // Create the function type.
                LlvmType type = LlvmFactory.Function(LlvmFactory.Void(), arguments, false);

                // Create the function within the module.
                function = this.module.CreateFunction(node.Identifier, type);

                // Set the function's linkage.
                function.SetLinkage(LLVMLinkage.LLVMExternalLinkage);
            }

            // Process arguments.
            for (int i = 0; i < argumentCount; ++i)
            {
                // Retrieve the argument name.
                string argumentName = node.Arguments[i].Item2.Value;

                // Retrieve the argument at the current index iterator.
                LlvmValue argument = function.GetArgumentAt((uint)i);

                // Name the argument.
                argument.SetName(argumentName);

                // TODO: Watch out for already existing ones.
                // Stored the named argument in the named values cache.
                this.namedValues.Add(argumentName, argument);
            }

            // Push the function onto the stack.
            this.valueStack.Push(function);

            // Return the node.
            return(node);
        }
Exemplo n.º 16
0
        public Construct VisitRoutine(Routine node)
        {
            // Ensure body was provided or created.
            if (node.Body == null)
            {
                throw new Exception("Unexpected function body to be null");
            }
            // Ensure prototype is set.
            else if (node.Prototype == null)
            {
                throw new Exception("Unexpected function prototype to be null");
            }
            // Ensures the function does not already exist.
            else if (this.module.ContainsFunction(node.Prototype.Identifier))
            {
                throw new Exception($"A function with the identifier '{node.Prototype.Identifier}' already exists");
            }

            // Clear named values.
            this.namedValues.Clear();

            // Create an argument buffer list.
            List <LlvmType> arguments = new List <LlvmType>();

            // Process the prototype's arguments.
            foreach ((Kind kind, Reference reference) in node.Prototype.Arguments)
            {
                // Visit the argument's type.
                this.Visit(kind);

                // Pop the resulting type off the stack.
                LlvmType argumentType = this.typeStack.Pop();

                // Append the argument's type to the argument list.
                arguments.Add(argumentType);
            }

            // Visit the return type node.
            this.Visit(node.Prototype.ReturnKind);

            // Pop off the return type off the stack.
            LlvmType returnType = this.typeStack.Pop();

            // Emit the function type.
            LlvmType type = LlvmFactory.Function(returnType, arguments.ToArray(), node.Prototype.HasInfiniteArguments);

            // Create the function.
            LlvmFunction function = this.module.CreateFunction(node.Prototype.Identifier, type);

            // Register as the temporary, local function.
            this.function = function;

            // Create the argument index counter.
            uint argumentIndexCounter = 0;

            // Name arguments.
            foreach ((Kind kind, Reference reference) in node.Prototype.Arguments)
            {
                // Retrieve the argument.
                LlvmValue argument = function.GetArgumentAt(argumentIndexCounter);

                // Name the argument.
                argument.SetName(reference.Value);

                // Increment the index counter for next iteration.
                argumentIndexCounter++;
            }

            // Visit the body.
            this.VisitSection(node.Body);

            // Pop the body off the stack.
            this.blockStack.Pop();

            // TODO
            // Ensure that body returns a value if applicable.
            // else if (!node.Prototype.ReturnKind.IsVoid && !node.Body.HasReturnValue)
            // {
            //     throw new Exception("Functions that do not return void must return a value");
            // }

            // Verify the function.
            function.Verify();

            // Append the function onto the stack.
            this.valueStack.Push(function);

            // Return the node.
            return(node);
        }
Exemplo n.º 17
0
 public StoreInst(LlvmValue target, LlvmValue value) : base(InstructionName.Set)
 {
     this.Target = target;
     this.Value  = value;
 }