Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bitwise complement op #216

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -579,6 +579,22 @@ private void generate() {
}
push(op.result());
}
case ComplOp op -> {
// Lower to x ^ -1
processFirstOperand(op);
switch (rvt) {
case IntType, BooleanType, ByteType, ShortType, CharType -> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we intend to support boolean even though JLS doesn't allow complement ~ on boolean values?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I observed that too, but decided to copy the same pattern as used else where. @asotona will know more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, JVMS doesn't make a difference anyway, so why not?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then classfile api would need an enum dedicated to model actual loadable types :)

cob.iconst_m1();
cob.ixor();
}
case LongType -> {
cob.ldc(-1L);
cob.lxor();
}
default -> throw new IllegalArgumentException("Bad type: " + op.resultType());
}
push(op.result());
}
case NotOp op -> {
processFirstOperand(op);
cob.ifThenElse(CodeBuilder::iconst_0, CodeBuilder::iconst_1);
Original file line number Diff line number Diff line change
@@ -51,6 +51,10 @@ public static int neg(int l) {
return -l;
}

public static int compl(int l) {
return ~l;
}

public static int add(int l, int r) {
return l + r;
}
@@ -137,6 +141,10 @@ public static byte neg(byte l) {
return (byte) -l;
}

public static byte compl(byte l) {
return (byte) ~l;
}

public static byte add(byte l, byte r) {
return (byte) (l + r);
}
@@ -195,6 +203,10 @@ public static short neg(short l) {
return (short) -l;
}

public static short compl(short l) {
return (short) ~l;
}

public static short add(short l, short r) {
return (short) (l + r);
}
@@ -257,6 +269,10 @@ public static char neg(char l) {
return (char) -l;
}

public static char compl(char l) {
return (char) ~l;
}

public static char add(char l, char r) {
return (char) (l + r);
}
@@ -319,6 +335,10 @@ public static long neg(long l) {
return -l;
}

public static long compl(long l) {
return ~l;
}

public static long add(long l, long r) {
return l + r;
}
35 changes: 35 additions & 0 deletions src/java.base/share/classes/java/lang/reflect/code/op/CoreOp.java
Original file line number Diff line number Diff line change
@@ -2993,6 +2993,31 @@ public NegOp transform(CopyContext cc, OpTransformer ot) {
}
}

/**
* The bitwise complement operation, that can model the Java language unary {@code ~} operator for integral types
*/
@OpFactory.OpDeclaration(ComplOp.NAME)
public static final class ComplOp extends UnaryOp {
public static final String NAME = "compl";

public ComplOp(ExternalizedOp opdef) {
super(opdef);
}

ComplOp(ComplOp that, CopyContext cc) {
super(that, cc);
}

@Override
public ComplOp transform(CopyContext cc, OpTransformer ot) {
return new ComplOp(this, cc);
}

ComplOp(Value v) {
super(NAME, v);
}
}

/**
* The not operation, that can model the Java language unary {@code !} operator for boolean types
*/
@@ -3982,6 +4007,16 @@ public static UnaryOp neg(Value v) {
return new NegOp(v);
}

/**
* Creates a bitwise complement operation.
*
* @param v the operand
* @return the bitwise complement operation
*/
public static UnaryOp compl(Value v) {
return new ComplOp(v);
}

/**
* Creates a not operation.
*
Original file line number Diff line number Diff line change
@@ -450,8 +450,6 @@ class BodyScanner extends FilterScanner {
private static final EnumSet<JCTree.Tag> UNSUPPORTED_TAGS = EnumSet.of(
// statements
Tag.SWITCH, Tag.SYNCHRONIZED,
// operators
Tag.COMPL,

// the nodes below are not as relevant, either because they have already
// been handled by an earlier compiler pass, or because they are typically
@@ -463,6 +461,8 @@ class BodyScanner extends FilterScanner {
Tag.TOPLEVEL, Tag.PACKAGEDEF, Tag.IMPORT, Tag.METHODDEF,
// modules (likely outside the scope for code models)
Tag.MODULEDEF, Tag.EXPORTS, Tag.OPENS, Tag.PROVIDES, Tag.REQUIRES, Tag.USES,
// classes, ignore local class definitions (allows access to but does not model the definition)
// Tag.CLASSDEF,
// switch labels (these are handled by the enclosing construct, SWITCH or SWITCH_EXPRESSION)
Tag.CASE, Tag.DEFAULTCASELABEL, Tag.CONSTANTCASELABEL, Tag.PATTERNCASELABEL,
// patterns (these are handled by the enclosing construct, like IF, SWITCH_EXPRESSION, TYPETEST)
@@ -2125,6 +2125,10 @@ public void visitUnary(JCTree.JCUnary tree) {
Value rhs = toValue(tree.arg, tree.type);
result = append(CoreOp.not(rhs));
}
case COMPL -> {
Value rhs = toValue(tree.arg, tree.type);
result = append(CoreOp.compl(rhs));
}
case POS -> {
// Result is value of the operand
result = toValue(tree.arg, tree.type);
28 changes: 28 additions & 0 deletions test/jdk/java/lang/reflect/code/TestBinops.java
Original file line number Diff line number Diff line change
@@ -53,6 +53,34 @@ public void testNot() {
Assert.assertEquals(Interpreter.invoke(f, false), not(false));
}

@CodeReflection
public static int neg(int a) {
return -a;
}

@Test
public void testNeg() {
CoreOp.FuncOp f = getFuncOp("neg");

f.writeTo(System.out);

Assert.assertEquals(Interpreter.invoke(f, 42), neg(42));
}

@CodeReflection
public static int compl(int a) {
return ~a;
}

@Test
public void testCompl() {
CoreOp.FuncOp f = getFuncOp("compl");

f.writeTo(System.out);

Assert.assertEquals(Interpreter.invoke(f, 42), compl(42));
}

@CodeReflection
public static int mod(int a, int b) {
return a % b;
10 changes: 5 additions & 5 deletions test/jdk/java/lang/reflect/code/bytecode/TestBytecode.java
Original file line number Diff line number Diff line change
@@ -117,27 +117,27 @@ static double doubleNumOps(double i, double j, double k) {

@CodeReflection
static int intBitOps(int i, int j, int k) {
return i & j | k ^ j;
return ~(i & j | k ^ j);
}

@CodeReflection
static byte byteBitOps(byte i, byte j, byte k) {
return (byte) (i & j | k ^ j);
return (byte) ~(i & j | k ^ j);
}

@CodeReflection
static short shortBitOps(short i, short j, short k) {
return (short) (i & j | k ^ j);
return (short) ~(i & j | k ^ j);
}

@CodeReflection
static char charBitOps(char i, char j, char k) {
return (char) (i & j | k ^ j);
return (char) ~(i & j | k ^ j);
}

@CodeReflection
static long longBitOps(long i, long j, long k) {
return i & j | k ^ j;
return ~(i & j | k ^ j);
}

@CodeReflection
13 changes: 13 additions & 0 deletions test/langtools/tools/javac/reflect/UnaryopTest.java
Original file line number Diff line number Diff line change
@@ -85,4 +85,17 @@ static Integer test3(int v) {
static Integer test4(Integer v) {
return +v;
}

@CodeReflection
@IR("""
func @"test5" (%0 : int)int -> {
%1 : Var<int> = var %0 @"v" ;
%2 : int = var.load %1 ;
%3 : int = compl %2 ;
return %3 ;
};
""")
static int test5(int v) {
return ~v;
}
}