All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.qbicc.machine.llvm.impl.AbstractFunction Maven / Gradle / Ivy

package org.qbicc.machine.llvm.impl;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.qbicc.machine.llvm.AddressNaming;
import org.qbicc.machine.llvm.CallingConvention;
import org.qbicc.machine.llvm.DllStorageClass;
import org.qbicc.machine.llvm.Function;
import org.qbicc.machine.llvm.Linkage;
import org.qbicc.machine.llvm.LLValue;
import org.qbicc.machine.llvm.Visibility;
import io.smallrye.common.constraint.Assert;

abstract class AbstractFunction extends AbstractMetable implements Function {
    final String name;
    final List attributes = new ArrayList<>();
    Linkage linkage = Linkage.EXTERNAL;
    Visibility visibility = Visibility.DEFAULT;
    DllStorageClass dllStorageClass = DllStorageClass.NONE;
    CallingConvention callingConvention = CallingConvention.C;
    AddressNaming addressNaming = AddressNaming.NAMED;
    ReturnsImpl returnType;

    int addressSpace = 0;
    // todo: return type attribute
    int alignment = 0;
    boolean variadic;
    // todo: prefix data https://llvm.org/docs/LangRef.html#prefixdata
    // todo: prologue data https://llvm.org/docs/LangRef.html#prologuedata
    ParameterImpl lastParam;

    AbstractFunction(final String name) {
        this.name = name;
    }

    public Returns returns(final LLValue returnType) {
        Assert.checkNotNullParam("returnType", returnType);
        // todo with attributes...
        this.returnType = new ReturnsImpl((AbstractValue) returnType);
        return this.returnType;
    }

    public ParameterImpl param(final LLValue type) {
        Assert.checkNotNullParam("type", type);
        return lastParam = new ParameterImpl(lastParam, this, (AbstractValue) type);
    }

    public Function linkage(final Linkage linkage) {
        Assert.checkNotNullParam("linkage", linkage);
        this.linkage = linkage;
        return this;
    }

    public Function visibility(final Visibility visibility) {
        Assert.checkNotNullParam("visibility", visibility);
        this.visibility = visibility;
        return this;
    }

    public Function dllStorageClass(final DllStorageClass dllStorageClass) {
        Assert.checkNotNullParam("dllStorageClass", dllStorageClass);
        this.dllStorageClass = dllStorageClass;
        return this;
    }

    public Function callingConvention(final CallingConvention callingConvention) {
        Assert.checkNotNullParam("callingConvention", callingConvention);
        this.callingConvention = callingConvention;
        return this;
    }

    public Function addressNaming(final AddressNaming addressNaming) {
        Assert.checkNotNullParam("addressNaming", addressNaming);
        this.addressNaming = addressNaming;
        return this;
    }

    public Function addressSpace(final int addressSpace) {
        Assert.checkMinimumParameter("addressSpace", 0, addressSpace);
        this.addressSpace = addressSpace;
        return this;
    }

    public Function alignment(final int alignment) {
        Assert.checkMinimumParameter("alignment", 1, alignment);
        Assert.checkMaximumParameter("alignment", 1 << 29, alignment);
        if (Integer.bitCount(alignment) != 1) {
            throw new IllegalArgumentException("Alignment must be a power of two");
        }
        return this;
    }

    public Function variadic() {
        variadic = true;
        return this;
    }

    public Function attribute(LLValue attribute) {
        attributes.add((AbstractValue) Assert.checkNotNullParam("attribute", attribute));
        return this;
    }

    public Function meta(final String name, final LLValue data) {
        super.meta(name, data);
        return this;
    }

    public Function comment(final String comment) {
        super.comment(comment);
        return this;
    }

    public LLValue asGlobal() {
        return new NamedGlobalValueOf(this.name);
    }

    protected final void appendLinkage(final Appendable target) throws IOException {
        if (linkage != Linkage.EXTERNAL) {
            target.append(linkage.toString()).append(' ');
        }
    }

    protected final void appendVisibility(final Appendable target) throws IOException {
        if (visibility != Visibility.DEFAULT) {
            target.append(visibility.toString()).append(' ');
        }
    }

    protected final void appendDllStorageClass(final Appendable target) throws IOException {
        if (dllStorageClass != DllStorageClass.NONE) {
            target.append(dllStorageClass.toString()).append(' ');
        }
    }

    protected final void appendCallingConvention(final Appendable target) throws IOException {
        if (callingConvention != CallingConvention.C) {
            target.append(callingConvention.toString()).append(' ');
        }
    }

    protected final void appendNameAndType(final Appendable target) throws IOException {
        returnType.appendTo(target);

        target.append(" @").append(LLVM.needsQuotes(name) ? LLVM.quoteString(name) : name).append('(');

        if (lastParam != null) {
            lastParam.appendTo(target);
            if (variadic) {
                target.append(", ...");
            }
        } else {
            if (variadic) {
                target.append("...");
            }
        }

        target.append(")");
    }

    protected final void appendAddressNaming(final Appendable target) throws IOException {
        if (addressNaming != AddressNaming.NAMED) {
            target.append(' ').append(addressNaming.toString());
        }
    }

    protected final void appendAddressSpace(final Appendable target) throws IOException {
        if (addressSpace != 0) {
            target.append(" addrspace(").append(Integer.toString(addressSpace)).append(')');
        }
    }

    protected final void appendFunctionAttributes(final Appendable target) throws IOException {
        for (AbstractValue attribute : attributes) {
            target.append(' ');
            attribute.appendTo(target);
        }
    }

    protected final void appendAlign(final Appendable target) throws IOException {
        if (alignment != 0) {
            target.append(" align ").append(Integer.toString(alignment));
        }
    }

    static final class ReturnsImpl extends AbstractEmittable implements Returns {
        final AbstractValue type;
        final List attributes = new ArrayList<>();

        ReturnsImpl(final AbstractValue type) {
            this.type = type;
        }

        public ReturnsImpl attribute(LLValue attribute) {
            this.attributes.add((AbstractValue) Assert.checkNotNullParam("attribute", attribute));
            return this;
        }

        public LLValue type() {
            return type;
        }

        public Appendable appendTo(Appendable target) throws IOException {
            for (AbstractValue attribute : attributes) {
                attribute.appendTo(target);
                target.append(' ');
            }

            type.appendTo(target);

            return target;
        }
    }

    static final class ParameterImpl extends AbstractEmittable implements Parameter {
        String name;
        final ParameterImpl prev;
        final AbstractFunction function;
        final AbstractValue type;
        final List attributes = new ArrayList<>();
        boolean immarg;

        ParameterImpl(final ParameterImpl prev, final AbstractFunction function, final AbstractValue type) {
            this.prev = prev;
            this.function = function;
            this.type = type;
        }

        public ParameterImpl param(final LLValue type) {
            return function.param(type);
        }

        public ParameterImpl name(final String name) {
            this.name = name;
            return this;
        }

        public ParameterImpl attribute(final LLValue attribute) {
            attributes.add((AbstractValue) Assert.checkNotNullParam("attribute", attribute));
            return this;
        }

        @Override
        public Parameter immarg() {
            immarg = true;
            return this;
        }

        public LLValue type() {
            return type;
        }

        public LLValue asValue() {
            return new AbstractValue() {
                public Appendable appendTo(final Appendable target) throws IOException {
                    return target.append('%').append(name);
                }
            };
        }

        public Appendable appendTo(final Appendable target) throws IOException {
            if (prev != null) {
                prev.appendTo(target);
                target.append(',').append(' ');
            }
            type.appendTo(target);
            if (immarg) {
                target.append(' ');
                target.append("immarg");
            }
            for (AbstractValue attribute : attributes) {
                target.append(' ');
                attribute.appendTo(target);
            }
            if (name != null) {
                target.append(' ').append('%').append(name);
            }
            return target;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy