示例#1
0
        public override LLVMValueRef Emit(EmittingContext pContext)
        {
            System.Diagnostics.Debug.Assert(_definition.MangledName != null);
            pContext.EmitDebugLocation(this);

            LLVMValueRef[] arguments = null;
            int            start     = 0;

            //If we are calling an instance method, we need to add the "self" parameter
            if (pContext.AccessStack.Count > 0)
            {
                arguments = new LLVMValueRef[Arguments.Count + 1];

                //"consume" the entire access stack to get the object we are calling the method on
                arguments[0] = AccessStack <MemberAccess> .BuildGetElementPtr(pContext, null);

                pContext.AccessStack.Clear();
                start = 1;
            }
            else
            {
                arguments = new LLVMValueRef[Arguments.Count];
            }

            for (int i = 0; i < Arguments.Count; i++)
            {
                arguments[start + i] = Arguments[i].Emit(pContext);

                //Load the location of any pointer calculations
                //The exceptions to this are structs (arrays are structs) since we pass those as a pointer
                if (!Arguments[i].Type.IsStruct && !Arguments[i].Type.IsArray)
                {
                    Utils.LlvmHelper.LoadIfPointer(ref arguments[start + i], pContext);
                }

                //For external methods passing strings, we only grab the char pointer
                if (_definition.External && Arguments[i].Type == SmallTypeCache.String)
                {
                    if (!Utils.LlvmHelper.IsPointer(arguments[start + i]))
                    {
                        var tempVar = pContext.AllocateVariable(Value + "_temp", Arguments[i].Type);
                        LLVM.BuildStore(pContext.Builder, arguments[start + i], tempVar);
                        arguments[start + i] = tempVar;
                    }
                    arguments[start + i] = LLVM.BuildInBoundsGEP(pContext.Builder, arguments[start + i], new LLVMValueRef[] { pContext.GetInt(0), pContext.GetInt(1) }, "char_pointer");
                    Utils.LlvmHelper.LoadIfPointer(ref arguments[start + i], pContext);
                }

                //Implicitly cast any derived types
                if (_definition.ArgumentTypes[i] != Arguments[i].Type)
                {
                    var type = SmallTypeCache.GetLLVMType(_definition.ArgumentTypes[i], pContext);
                    Utils.LlvmHelper.MakePointer(arguments[start + i], ref type);
                    arguments[start + i] = LLVM.BuildBitCast(pContext.Builder, arguments[start + i], type, "");
                }
            }

            return(LLVM.BuildCall(pContext.Builder, pContext.GetMethod(_definition.MangledName), arguments, ""));
        }
        public override LLVMValueRef Emit(EmittingContext pContext)
        {
            pContext.EmitDebugLocation(this);

            NamespaceSyntax  ns     = null;
            IdentifierSyntax access = Identifier;

            if (Identifier.SyntaxType == SyntaxType.Namespace)
            {
                ns     = (NamespaceSyntax)Identifier;
                access = Value;
            }

            //Check if this is a "static" method
            if (!pContext.Cache.IsTypeDefined(ns, access.Value) || Value.SyntaxType == SyntaxType.MethodCall)
            {
                LLVMValueRef value;
                if (Identifier.SyntaxType == SyntaxType.Namespace)
                {
                    value = Value.Emit(pContext);
                    //Terminal nodes are fully emitted in their child most node
                    if (IsTerminalNode(Value))
                    {
                        value = AccessStack <MemberAccess> .BuildGetElementPtr(pContext, value);
                    }
                }
                else
                {
                    LLVMValueRef identifier = Identifier.Emit(pContext);

                    //For every method call we need to stop and allocate a new variable
                    //This is because our method call is going to return a value, but we need a pointer.
                    //To solve this we allocate a temporary variable, store the value, and continue
                    if (Identifier.SyntaxType == SyntaxType.MethodCall)
                    {
                        var tempVar = pContext.AllocateVariable("memberaccess_temp", Identifier.Type);
                        LLVM.BuildStore(pContext.Builder, identifier, tempVar);
                        identifier = tempVar;
                        pContext.AccessStack.Clear();
                    }

                    //Store the index we pushed at.
                    //We will later pop only if that index still exists
                    //This allows things like MethodCalls to wipe the stack (because the arguments aren't in the same stack) while still properly popping values
                    var index = pContext.AccessStack.Push(new MemberAccess(identifier, Identifier.Type));

                    value = Value.Emit(pContext);
                    //Terminal nodes are fully emitted in their child most node
                    if (IsTerminalNode(Value))
                    {
                        value = AccessStack <MemberAccess> .BuildGetElementPtr(pContext, value);
                    }

                    pContext.AccessStack.PopFrom(index);
                }

                return(value);
            }
            else
            {
                //Only this way while fields are allow to be accessed
                if (access.Type.IsEnum)
                {
                    int i = 0;
                    if (access.SyntaxType == SyntaxType.MemberAccess)
                    {
                        i = access.Type.GetEnumValue(((MemberAccessSyntax)access).Value.Value);
                    }
                    else
                    {
                        i = access.Type.GetEnumValue(Value.Value);
                    }
                    return(pContext.GetInt(i));
                }

                throw new NotSupportedException("Only static fields on Enums are supported");
            }
        }