Consider the following example:
class Test8bitLogicalOperators {
private static byte and = 0b0011, or = 0b0011, xor = 0b0011;
private static byte mask = 0b0101;
public static void main(String... args) {
test();
if (and != 0b0001 || or != 0b0111 || xor != 0b0110)
throw new AssertionError("8-bit logical operator failure");
}
public static void test() {
and &= mask;
or |= mask;
xor ^= mask;
}
}
Running it with:
$ java -XX:+PrintOptoAssembly -Xcomp -XX:-Inline -XX:CompileOnly=Test8bitLogicalOperators::test Test8bitLogicalOperators
shows how 'test()' is currently assembled:
016 movsbl R8, [R10 + #112 (8-bit)] # byte ! Field: Test8bitLogicalOperators.and
01b movsbl R11, [R10 + #114 (8-bit)] # byte ! Field: Test8bitLogicalOperators.xor
020 movsbl RCX, [R10 + #113 (8-bit)] # byte ! Field: Test8bitLogicalOperators.or
025 movsbl R9, [R10 + #115 (8-bit)] # byte ! Field: Test8bitLogicalOperators.mask
02a andl R8, R9 # int
02d movb [R10 + #112 (8-bit)], R8 # byte ! Field: Test8bitLogicalOperators.and
031 xorl R11, R9 # int
034 movb [R10 + #114 (8-bit)], R11 # byte ! Field: Test8bitLogicalOperators.xor
038 orl RCX, R9 # int
03b movb [R10 + #113 (8-bit)], RCX # byte ! Field: Test8bitLogicalOperators.or
Which could be improved using 8-bit logical operators with destination in memory, as next:
016 movsbl R8, [R10 + #115 (8-bit)] # byte ! Field: Test8bitLogicalOperators.mask
01b andb [R10 + #112 (8-bit)], R8 # byte ! Field: Test8bitLogicalOperators.and
01f xorb [R10 + #114 (8-bit)], R8 # byte ! Field: Test8bitLogicalOperators.xor
023 orb [R10 + #113 (8-bit)], R8 # byte ! Field: Test8bitLogicalOperators.or
We see that only 4 instructions and 2 registers are necessary instead of 10 instructions and 5 registers.
class Test8bitLogicalOperators {
private static byte and = 0b0011, or = 0b0011, xor = 0b0011;
private static byte mask = 0b0101;
public static void main(String... args) {
test();
if (and != 0b0001 || or != 0b0111 || xor != 0b0110)
throw new AssertionError("8-bit logical operator failure");
}
public static void test() {
and &= mask;
or |= mask;
xor ^= mask;
}
}
Running it with:
$ java -XX:+PrintOptoAssembly -Xcomp -XX:-Inline -XX:CompileOnly=Test8bitLogicalOperators::test Test8bitLogicalOperators
shows how 'test()' is currently assembled:
016 movsbl R8, [R10 + #112 (8-bit)] # byte ! Field: Test8bitLogicalOperators.and
01b movsbl R11, [R10 + #114 (8-bit)] # byte ! Field: Test8bitLogicalOperators.xor
020 movsbl RCX, [R10 + #113 (8-bit)] # byte ! Field: Test8bitLogicalOperators.or
025 movsbl R9, [R10 + #115 (8-bit)] # byte ! Field: Test8bitLogicalOperators.mask
02a andl R8, R9 # int
02d movb [R10 + #112 (8-bit)], R8 # byte ! Field: Test8bitLogicalOperators.and
031 xorl R11, R9 # int
034 movb [R10 + #114 (8-bit)], R11 # byte ! Field: Test8bitLogicalOperators.xor
038 orl RCX, R9 # int
03b movb [R10 + #113 (8-bit)], RCX # byte ! Field: Test8bitLogicalOperators.or
Which could be improved using 8-bit logical operators with destination in memory, as next:
016 movsbl R8, [R10 + #115 (8-bit)] # byte ! Field: Test8bitLogicalOperators.mask
01b andb [R10 + #112 (8-bit)], R8 # byte ! Field: Test8bitLogicalOperators.and
01f xorb [R10 + #114 (8-bit)], R8 # byte ! Field: Test8bitLogicalOperators.xor
023 orb [R10 + #113 (8-bit)], R8 # byte ! Field: Test8bitLogicalOperators.or
We see that only 4 instructions and 2 registers are necessary instead of 10 instructions and 5 registers.