/*
 * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */


package org.graalvm.compiler.loop.phases;

import org.graalvm.compiler.core.common.GraalOptions;
import org.graalvm.compiler.debug.CounterKey;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.loop.LoopEx;
import org.graalvm.compiler.loop.LoopPolicies;
import org.graalvm.compiler.loop.LoopsData;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.spi.CoreProviders;
import org.graalvm.compiler.phases.common.CanonicalizerPhase;

public class LoopFullUnrollPhase extends LoopPhase<LoopPolicies> {

    private static final CounterKey FULLY_UNROLLED_LOOPS = DebugContext.counter("FullUnrolls");
    private final CanonicalizerPhase canonicalizer;

    public LoopFullUnrollPhase(CanonicalizerPhase canonicalizer, LoopPolicies policies) {
        super(policies);
        this.canonicalizer = canonicalizer;
    }

    @Override
    protected void run(StructuredGraph graph, CoreProviders context) {
        if (GraalOptions.FullUnroll.getValue(graph.getOptions())) {
            DebugContext debug = graph.getDebug();
            if (graph.hasLoops()) {
                boolean peeled;
                do {
                    peeled = false;
                    final LoopsData dataCounted = new LoopsData(graph);
                    dataCounted.detectedCountedLoops();
                    for (LoopEx loop : dataCounted.countedLoops()) {
                        if (getPolicies().shouldFullUnroll(loop)) {
                            debug.log("FullUnroll %s", loop);
                            LoopTransformations.fullUnroll(loop, context, canonicalizer);
                            FULLY_UNROLLED_LOOPS.increment(debug);
                            debug.dump(DebugContext.DETAILED_LEVEL, graph, "FullUnroll %s", loop);
                            peeled = true;
                            break;
                        }
                    }
                    dataCounted.deleteUnusedNodes();
                } while (peeled);
            }
        }
    }

    @Override
    public boolean checkContract() {
        return false;
    }
}
