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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
public StoreInst(LlvmValue target, LlvmValue value) : base(InstructionName.Set) { this.Target = target; this.Value = value; }