private void generateBranch(RelationalExpression expr,
                                    Label label, boolean whenTrue) {
            // RelationalExpressions produce different comparision instructions
            // based on the type of the expression.

            Token operator = expr.getOperator();
            Expression left = expr.getLeftExpression();

            if (operator.getID() == Token.ISA) {
                TypeName typeName = expr.getIsaTypeName();

                generate(left);
                setLineNumber(operator.getSourceInfo());
                mBuilder.instanceOf(makeDesc(typeName.getType(), false));
                mBuilder.ifZeroComparisonBranch(label, whenTrue ? "!=" : "==");

                return;
            }

            Expression right = expr.getRightExpression();
            String choice = getChoice(operator, whenTrue);

            Type leftType = left.getType();
            Class<?> leftClass = leftType.getNaturalClass();

            Type rightType = right.getType();
            Class<?> rightClass = rightType.getNaturalClass();

            Class<?> clazz =
                leftType.getCompatibleType(rightType).getNaturalClass();

            if (clazz == null) {
                throw new RuntimeException("Relational type mismatch: " +
                                           leftType + ", " + rightType);
            }

            boolean isPrimitive =
                leftType.isPrimitive() && rightType.isPrimitive();

            // handle object comparisons where at least one value is an object
            // rather than both being primitives

            if (!isPrimitive) {

                // if both are a number value including both being numbers or
                // one being primitive and the other a number, then we are
                // assuming we have an unknown or general purpose number we
                // have to deal with at runtime so compare together using the
                // runtime types for type safety

                if (Number.class.equals(clazz)) {

                    if (!leftType.isPrimitive() && !rightType.isPrimitive()) {
                        // both are objects, so do pure equality checking
                        if (choice == "==" || choice == "!=") {
                            generateEquals(left, right, label, choice, operator);
                        }

                        // convert both to Numbers and runtime compare for
                        // relational checking
                        else {
                            generate(left);
                            generate(right);

                            Method method = getMethod(
                                WrapperTypeConversionUtil.class, "compare",
                                Number.class, Number.class
                            );

                            mBuilder.invoke(method);
                            mBuilder.ifZeroComparisonBranch(label, choice);
                        }
                    }

                    // handle cases where one value is primitive and the other
                    // is some unknown numeric object and compare at runtime
                    else {
                        leftClass = Number.class;
                        if (leftType.isPrimitive()) {
                            leftClass = leftType.getNaturalClass();
                        }

                        rightClass = Number.class;
                        if (rightType.isPrimitive()) {
                            rightClass = rightType.getNaturalClass();
                        }

                        Method method = getMethod(
                            WrapperTypeConversionUtil.class, "compare",
                            leftClass, rightClass
                        );

                        generate(left);
                        generate(right);
                        mBuilder.invoke(method);
                        mBuilder.ifZeroComparisonBranch(label, choice);
                    }
                }

                // non-numbers, so assume both are objects and do equality check
                else if (choice == "==" || choice == "!=") {
                    generateEquals(left, right, label, choice, operator);
                }

                // use comparable comparisons for relational checks
                else if (Comparable.class.isAssignableFrom(clazz) &&
                         (leftClass.isAssignableFrom(rightClass) ||
                          rightClass.isAssignableFrom(leftClass))) {

                    // check whether we need to compare left to right when
                    // left is the parent or right to left when right is the
                    // parent...in the latter case we also negate it

                    boolean leftToRight =
                        leftClass.isAssignableFrom(rightClass);

                    if (leftToRight) {
                        generate(left);
                        generate(right);
                    }
                    else {
                        generate(right);
                        generate(left);
                    }

                    setLineNumber(operator.getSourceInfo());

                    Method method =
                        getMethod(Comparable.class, "compareTo", Object.class);
                    mBuilder.invoke(method);

                    if (!leftToRight) {
                        mBuilder.math(Opcode.INEG);
                    }

                    mBuilder.ifZeroComparisonBranch(label, choice);
                }
                else if (Number.class.isAssignableFrom(clazz)) {
                    // numbers must be converted down to primitives to be
                    // compared...this is potentially dangerous as we are
                    // converting types
                    warn("compare.as.double", expr);

                    Method doubleMethod =
                        getMethod(Number.class, "doubleValue");

                    generate(left);
                    mBuilder.invoke(doubleMethod);
                    generate(right);
                    mBuilder.invoke(doubleMethod);
                    setLineNumber(operator.getSourceInfo());

                    byte op;
                    int ID = operator.getID();
                    if (ID == Token.LT || ID == Token.LE ||
                        ID == Token.EQ) {
                        op = Opcode.DCMPG;
                    }
                    else {
                        op = Opcode.DCMPL;
                    }

                    mBuilder.math(op);
                    mBuilder.ifZeroComparisonBranch(label, choice);
                }
                else {
                    throw new RuntimeException("Can't do " + choice +
                                               " for type " + leftType);
                }
            }

            // otherwise, handle purely primitive comparisons
            else {
                if (clazz == int.class) {
                    if (right.isValueKnown() && right.getValue() != null) {
                        int value = ((Integer)right.getValue()).intValue();
                        if (value == 0) {
                            generate(left);
                            mBuilder.ifZeroComparisonBranch(label, choice);
                            return;
                        }
                    }
                    else if (left.isValueKnown() && left.getValue() != null) {
                        int value = ((Integer)left.getValue()).intValue();
                        if (value == 0) {
                            generate(right);
                            choice = getChoice(operator, !whenTrue);
                            mBuilder.ifZeroComparisonBranch(label, choice);
                            return;
                        }
                    }

                    generate(left);
                    generate(right);
                    mBuilder.ifComparisonBranch(label, choice);
                }
                else if (clazz == boolean.class) {
                    // An optimizer should be able to detect and reduce this
                    // relational expression if the left or right side
                    // is constant.

                    generate(left);
                    generate(right);
                    mBuilder.ifComparisonBranch(label, choice);
                }
                else {
                    generate(left);
                    generate(right);

                    byte op;

                    if (clazz == long.class) {
                        op = Opcode.LCMP;
                    }
                    else if (clazz == float.class) {
                        int ID = operator.getID();
                        if (ID == Token.LT || ID == Token.LE ||
                            ID == Token.EQ) {
                            op = Opcode.FCMPG;
                        }
                        else {
                            op = Opcode.FCMPL;
                        }
                    }
                    else if (clazz == double.class) {
                        int ID = operator.getID();
                        if (ID == Token.LT || ID == Token.LE ||
                            ID == Token.EQ) {
                            op = Opcode.DCMPG;
                        }
                        else {
                            op = Opcode.DCMPL;
                        }
                    }
                    else {
                        throw new RuntimeException("Unsupported comparison " +
                                                   "type: " + leftType);
                    }

                    mBuilder.math(op);
                    mBuilder.ifZeroComparisonBranch(label, choice);
                }
            }
        }