001/*
002 * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.lir.sparc;
024
025import jdk.internal.jvmci.code.*;
026import jdk.internal.jvmci.common.*;
027import jdk.internal.jvmci.meta.*;
028import static com.oracle.graal.asm.sparc.SPARCAssembler.*;
029import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
030import static jdk.internal.jvmci.code.ValueUtil.*;
031import static jdk.internal.jvmci.sparc.SPARC.*;
032
033import com.oracle.graal.asm.sparc.*;
034import com.oracle.graal.lir.*;
035import com.oracle.graal.lir.asm.*;
036import com.oracle.graal.lir.gen.*;
037
038public final class SPARCBitManipulationOp extends SPARCLIRInstruction {
039    public static final LIRInstructionClass<SPARCBitManipulationOp> TYPE = LIRInstructionClass.create(SPARCBitManipulationOp.class);
040
041    public enum IntrinsicOpcode {
042        IPOPCNT(SizeEstimate.create(2)),
043        LPOPCNT(SizeEstimate.create(1)),
044        IBSR(SizeEstimate.create(13)),
045        LBSR(SizeEstimate.create(14)),
046        BSF(SizeEstimate.create(4));
047
048        final SizeEstimate size;
049
050        private IntrinsicOpcode(SizeEstimate size) {
051            this.size = size;
052        }
053    }
054
055    @Opcode private final IntrinsicOpcode opcode;
056    @Def protected AllocatableValue result;
057    @Alive({REG}) protected AllocatableValue input;
058    @Temp({REG}) protected Value scratch;
059
060    public SPARCBitManipulationOp(IntrinsicOpcode opcode, AllocatableValue result, AllocatableValue input, LIRGeneratorTool gen) {
061        super(TYPE, opcode.size);
062        this.opcode = opcode;
063        this.result = result;
064        this.input = input;
065        scratch = gen.newVariable(LIRKind.combine(input));
066    }
067
068    @Override
069    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
070        Register dst = asIntReg(result);
071        if (isRegister(input)) {
072            Register src = asRegister(input);
073            switch (opcode) {
074                case IPOPCNT:
075                    // clear upper word for 64 bit POPC
076                    masm.srl(src, g0, dst);
077                    masm.popc(dst, dst);
078                    break;
079                case LPOPCNT:
080                    masm.popc(src, dst);
081                    break;
082                case BSF:
083                    Kind tkind = input.getKind();
084                    if (tkind == Kind.Int) {
085                        masm.sub(src, 1, dst);
086                        masm.andn(dst, src, dst);
087                        masm.srl(dst, g0, dst);
088                        masm.popc(dst, dst);
089                    } else if (tkind == Kind.Long) {
090                        masm.sub(src, 1, dst);
091                        masm.andn(dst, src, dst);
092                        masm.popc(dst, dst);
093                    } else {
094                        throw JVMCIError.shouldNotReachHere("missing: " + tkind);
095                    }
096                    break;
097                case IBSR: {
098                    Kind ikind = input.getKind();
099                    assert ikind == Kind.Int;
100                    Register tmp = asRegister(scratch);
101                    assert !tmp.equals(dst);
102                    masm.srl(src, 1, tmp);
103                    masm.srl(src, 0, dst);
104                    masm.or(dst, tmp, dst);
105                    masm.srl(dst, 2, tmp);
106                    masm.or(dst, tmp, dst);
107                    masm.srl(dst, 4, tmp);
108                    masm.or(dst, tmp, dst);
109                    masm.srl(dst, 8, tmp);
110                    masm.or(dst, tmp, dst);
111                    masm.srl(dst, 16, tmp);
112                    masm.or(dst, tmp, dst);
113                    masm.popc(dst, dst);
114                    masm.sub(dst, 1, dst);
115                    break;
116                }
117                case LBSR: {
118                    Kind lkind = input.getKind();
119                    assert lkind == Kind.Long;
120                    Register tmp = asRegister(scratch);
121                    assert !tmp.equals(dst);
122                    masm.srlx(src, 1, tmp);
123                    masm.or(src, tmp, dst);
124                    masm.srlx(dst, 2, tmp);
125                    masm.or(dst, tmp, dst);
126                    masm.srlx(dst, 4, tmp);
127                    masm.or(dst, tmp, dst);
128                    masm.srlx(dst, 8, tmp);
129                    masm.or(dst, tmp, dst);
130                    masm.srlx(dst, 16, tmp);
131                    masm.or(dst, tmp, dst);
132                    masm.srlx(dst, 32, tmp);
133                    masm.or(dst, tmp, dst);
134                    masm.popc(dst, dst);
135                    masm.sub(dst, 1, dst); // This is required to fit the given structure.
136                    break;
137                }
138                default:
139                    throw JVMCIError.shouldNotReachHere();
140
141            }
142        } else if (isConstant(input) && isSimm13(crb.asIntConst(input))) {
143            switch (opcode) {
144                case IPOPCNT:
145                    masm.popc(crb.asIntConst(input), dst);
146                    break;
147                case LPOPCNT:
148                    masm.popc(crb.asIntConst(input), dst);
149                    break;
150                default:
151                    throw JVMCIError.shouldNotReachHere();
152            }
153        } else {
154            throw JVMCIError.shouldNotReachHere();
155        }
156    }
157}