| // Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| package com.android.tools.r8.ir.code; |
| |
| public class IRMetadata { |
| |
| private long first; |
| private long second; |
| |
| public IRMetadata() {} |
| |
| private IRMetadata(long first, long second) { |
| this.first = first; |
| this.second = second; |
| } |
| |
| public static IRMetadata unknown() { |
| return new IRMetadata(0xFFFFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFFFFL); |
| } |
| |
| private boolean get(int bit) { |
| if (bit < 64) { |
| return isAnySetInFirst(1L << bit); |
| } else { |
| assert bit < 128; |
| int adjusted = bit - 64; |
| return isAnySetInSecond(1L << adjusted); |
| } |
| } |
| |
| private boolean isAnySetInFirst(long mask) { |
| return (first & mask) != 0; |
| } |
| |
| private boolean isAnySetInSecond(long mask) { |
| return (second & mask) != 0; |
| } |
| |
| private void set(int bit) { |
| if (bit < 64) { |
| first |= (1L << bit); |
| } else { |
| assert bit < 128; |
| int adjusted = bit - 64; |
| second |= (1L << adjusted); |
| } |
| } |
| |
| public void record(Instruction instruction) { |
| set(instruction.opcode()); |
| } |
| |
| public void merge(IRMetadata metadata) { |
| first |= metadata.first; |
| second |= metadata.second; |
| } |
| |
| public boolean mayHaveAdd() { |
| return get(Opcodes.ADD); |
| } |
| |
| public boolean mayHaveAnd() { |
| return get(Opcodes.AND); |
| } |
| |
| public boolean mayHaveArrayLength() { |
| return get(Opcodes.ARRAY_LENGTH); |
| } |
| |
| public boolean mayHaveCheckCast() { |
| return get(Opcodes.CHECK_CAST); |
| } |
| |
| public boolean mayHaveConstNumber() { |
| return get(Opcodes.CONST_NUMBER); |
| } |
| |
| public boolean mayHaveConstString() { |
| return get(Opcodes.CONST_STRING); |
| } |
| |
| public boolean mayHaveDebugPosition() { |
| return get(Opcodes.DEBUG_POSITION); |
| } |
| |
| public boolean mayHaveDexItemBasedConstString() { |
| return get(Opcodes.DEX_ITEM_BASED_CONST_STRING); |
| } |
| |
| public boolean mayHaveDiv() { |
| return get(Opcodes.DIV); |
| } |
| |
| public boolean mayHaveFieldGet() { |
| return mayHaveInstanceGet() || mayHaveStaticGet(); |
| } |
| |
| public boolean mayHaveFieldInstruction() { |
| assert Opcodes.INSTANCE_GET < 64; |
| assert Opcodes.INSTANCE_PUT < 64; |
| assert Opcodes.STATIC_GET < 64; |
| assert Opcodes.STATIC_PUT < 64; |
| long mask = |
| (1L << Opcodes.INSTANCE_GET) |
| | (1L << Opcodes.INSTANCE_PUT) |
| | (1L << Opcodes.STATIC_GET) |
| | (1L << Opcodes.STATIC_PUT); |
| boolean result = isAnySetInFirst(mask); |
| assert result |
| == (mayHaveInstanceGet() |
| || mayHaveInstancePut() |
| || mayHaveStaticGet() |
| || mayHaveStaticPut()); |
| return result; |
| } |
| |
| public boolean mayHaveInitClass() { |
| return get(Opcodes.INIT_CLASS); |
| } |
| |
| public boolean mayHaveInstanceGet() { |
| return get(Opcodes.INSTANCE_GET); |
| } |
| |
| public boolean mayHaveInstancePut() { |
| return get(Opcodes.INSTANCE_PUT); |
| } |
| |
| public boolean mayHaveInstanceOf() { |
| return get(Opcodes.INSTANCE_OF); |
| } |
| |
| public boolean mayHaveIntSwitch() { |
| return get(Opcodes.INT_SWITCH); |
| } |
| |
| public boolean mayHaveInvokeDirect() { |
| return get(Opcodes.INVOKE_DIRECT); |
| } |
| |
| public boolean mayHaveInvokeInterface() { |
| return get(Opcodes.INVOKE_INTERFACE); |
| } |
| |
| @SuppressWarnings("ConstantConditions") |
| public boolean mayHaveInvokeMethod() { |
| assert Opcodes.INVOKE_DIRECT < 64; |
| assert Opcodes.INVOKE_INTERFACE < 64; |
| assert Opcodes.INVOKE_POLYMORPHIC < 64; |
| assert Opcodes.INVOKE_STATIC < 64; |
| assert Opcodes.INVOKE_SUPER < 64; |
| assert Opcodes.INVOKE_VIRTUAL < 64; |
| long mask = |
| (1L << Opcodes.INVOKE_DIRECT) |
| | (1L << Opcodes.INVOKE_INTERFACE) |
| | (1L << Opcodes.INVOKE_POLYMORPHIC) |
| | (1L << Opcodes.INVOKE_STATIC) |
| | (1L << Opcodes.INVOKE_SUPER) |
| | (1L << Opcodes.INVOKE_VIRTUAL); |
| boolean result = isAnySetInFirst(mask); |
| assert result |
| == (mayHaveInvokeDirect() |
| || mayHaveInvokeInterface() |
| || mayHaveInvokePolymorphic() |
| || mayHaveInvokeStatic() |
| || mayHaveInvokeSuper() |
| || mayHaveInvokeVirtual()); |
| return result; |
| } |
| |
| @SuppressWarnings("ConstantConditions") |
| public boolean mayHaveInvokeMethodWithReceiver() { |
| assert Opcodes.INVOKE_DIRECT < 64; |
| assert Opcodes.INVOKE_INTERFACE < 64; |
| assert Opcodes.INVOKE_SUPER < 64; |
| assert Opcodes.INVOKE_VIRTUAL < 64; |
| long mask = |
| (1L << Opcodes.INVOKE_DIRECT) |
| | (1L << Opcodes.INVOKE_INTERFACE) |
| | (1L << Opcodes.INVOKE_SUPER) |
| | (1L << Opcodes.INVOKE_VIRTUAL); |
| boolean result = isAnySetInFirst(mask); |
| assert result |
| == (mayHaveInvokeDirect() |
| || mayHaveInvokeInterface() |
| || mayHaveInvokeSuper() |
| || mayHaveInvokeVirtual()); |
| return result; |
| } |
| |
| public boolean mayHaveInvokePolymorphic() { |
| return get(Opcodes.INVOKE_POLYMORPHIC); |
| } |
| |
| public boolean mayHaveInvokeStatic() { |
| return get(Opcodes.INVOKE_STATIC); |
| } |
| |
| public boolean mayHaveInvokeSuper() { |
| return get(Opcodes.INVOKE_SUPER); |
| } |
| |
| public boolean mayHaveInvokeVirtual() { |
| return get(Opcodes.INVOKE_VIRTUAL); |
| } |
| |
| public boolean mayHaveMonitorInstruction() { |
| return get(Opcodes.MONITOR); |
| } |
| |
| public boolean mayHaveMul() { |
| return get(Opcodes.MUL); |
| } |
| |
| public boolean mayHaveNewInstance() { |
| return get(Opcodes.NEW_INSTANCE); |
| } |
| |
| public boolean mayHaveOr() { |
| return get(Opcodes.OR); |
| } |
| |
| public boolean mayHaveRem() { |
| return get(Opcodes.REM); |
| } |
| |
| public boolean mayHaveShl() { |
| return get(Opcodes.SHL); |
| } |
| |
| public boolean mayHaveShr() { |
| return get(Opcodes.SHR); |
| } |
| |
| public boolean mayHaveStaticGet() { |
| return get(Opcodes.STATIC_GET); |
| } |
| |
| public boolean mayHaveStaticPut() { |
| return get(Opcodes.STATIC_PUT); |
| } |
| |
| public boolean mayHaveStringSwitch() { |
| return get(Opcodes.STRING_SWITCH); |
| } |
| |
| public boolean mayHaveSub() { |
| return get(Opcodes.SUB); |
| } |
| |
| @SuppressWarnings("ConstantConditions") |
| public boolean mayHaveSwitch() { |
| assert Opcodes.INT_SWITCH < 64; |
| assert Opcodes.STRING_SWITCH < 64; |
| long mask = (1L << Opcodes.INT_SWITCH) | (1L << Opcodes.STRING_SWITCH); |
| boolean result = isAnySetInFirst(mask); |
| assert result == (mayHaveIntSwitch() || mayHaveStringSwitch()); |
| return result; |
| } |
| |
| public boolean mayHaveUshr() { |
| return get(Opcodes.USHR); |
| } |
| |
| public boolean mayHaveXor() { |
| return get(Opcodes.XOR); |
| } |
| |
| public boolean mayHaveArithmeticOrLogicalBinop() { |
| // ArithmeticBinop |
| assert Opcodes.ADD < 64; |
| assert Opcodes.DIV < 64; |
| assert Opcodes.MUL < 64; |
| assert Opcodes.REM < 64; |
| assert Opcodes.SUB < 64; |
| // LogicalBinop |
| assert Opcodes.AND < 64; |
| assert Opcodes.OR < 64; |
| assert Opcodes.SHL < 64; |
| assert Opcodes.SHR < 64; |
| assert Opcodes.USHR >= 64; |
| assert Opcodes.XOR >= 64; |
| long mask = |
| (1L << Opcodes.ADD) |
| | (1L << Opcodes.DIV) |
| | (1L << Opcodes.MUL) |
| | (1L << Opcodes.REM) |
| | (1L << Opcodes.SUB) |
| | (1L << Opcodes.AND) |
| | (1L << Opcodes.OR) |
| | (1L << Opcodes.SHL) |
| | (1L << Opcodes.SHR) |
| | (1L << Opcodes.USHR) |
| | (1L << Opcodes.XOR); |
| long other = (1L << (Opcodes.USHR - 64)) | (1L << (Opcodes.XOR - 64)); |
| boolean result = isAnySetInFirst(mask) || isAnySetInSecond(other); |
| assert result |
| == (mayHaveAdd() |
| || mayHaveDiv() |
| || mayHaveMul() |
| || mayHaveRem() |
| || mayHaveSub() |
| || mayHaveAnd() |
| || mayHaveOr() |
| || mayHaveShl() |
| || mayHaveShr() |
| || mayHaveUshr() |
| || mayHaveXor()); |
| return result; |
| } |
| } |