/* * $Id: cmp.ops 37225 2009-03-09 03:16:29Z allison $ ** cmp.ops */ VERSION = PARROT_VERSION; =head1 NAME cmp.ops - Comparison Opcodes =cut =head1 DESCRIPTION Operations that compare two registers against each other. Some of these operations affect control flow directly; others do not. =cut ############################################################################### =head2 Flow control comparison operators These operators branch based on the relationship between their operands. =over 4 =cut ######################################## =item B(in INT, in INT, inconst LABEL) =item B(in NUM, in NUM, inconst LABEL) =item B(in STR, in STR, inconst LABEL) =item B(invar PMC, invar PMC, inconst LABEL) =item B(invar PMC, in INT, inconst LABEL) =item B(invar PMC, in NUM, inconst LABEL) =item B(invar PMC, in STR, inconst LABEL) =item B(invar PMC, invar PMC, inconst LABEL) =item B(invar PMC, invar PMC, inconst LABEL) =item B(in STR, in STR, inconst LABEL) =item B(invar PMC, invar PMC, inconst LABEL) Branch if $1 is equal to $2. For PMCs this does a generic comparison, whatever that is for the involved PMCs. Mixed PMC number/string operands do a numeric or string comparison respectively. B and B enforce string or number comparisons. B compares the address of the objects or strings. =cut inline op eq(in INT, in INT, inconst LABEL) :base_core { if ($1 == $2) { goto OFFSET($3); } } inline op eq(in NUM, in NUM, inconst LABEL) :base_core { if ($1 == $2) { goto OFFSET($3); } } op eq(in STR, in STR, inconst LABEL) :base_core { if (Parrot_str_equal(interp, $1, $2)) { goto OFFSET($3); } } op eq(invar PMC, invar PMC, inconst LABEL) :base_core { if (VTABLE_is_equal(interp, $1, $2)) { goto OFFSET($3); } } op eq(invar PMC, in INT, inconst LABEL) :base_core { PMC * temp = temporary_pmc_new(interp, enum_class_Integer); VTABLE_set_integer_native(interp, temp, $2); if (VTABLE_is_equal(interp, $1, temp)) { temporary_pmc_free(interp, temp); goto OFFSET($3); } temporary_pmc_free(interp, temp); } op eq(invar PMC, in NUM, inconst LABEL) :base_core { /* * the get_number and get_string should probably * be also replaced with code like above, as * overriding the compare multi subs wouldn't * have any effect with the current code */ if (VTABLE_get_number(interp, $1) == $2) { goto OFFSET($3); } } op eq(invar PMC, in STR, inconst LABEL) :base_core { if (Parrot_str_equal(interp, VTABLE_get_string(interp, $1), $2)) { goto OFFSET($3); } } op eq_str(invar PMC, invar PMC, inconst LABEL) :base_core { if (VTABLE_is_equal_string(interp, $1, $2)) { goto OFFSET($3); } } op eq_num(invar PMC, invar PMC, inconst LABEL) :base_core { if (VTABLE_is_equal_num(interp, $1, $2)) { goto OFFSET($3); } } op eq_addr(in STR, in STR, inconst LABEL) :base_core { if ($1 == $2) { goto OFFSET($3); } } op eq_addr(invar PMC, invar PMC, inconst LABEL) :base_core { if ($1 == $2) { goto OFFSET($3); } } ######################################## =item B(in INT, in INT, inconst LABEL) =item B(in NUM, in NUM, inconst LABEL) =item B(in STR, in STR, inconst LABEL) =item B(invar PMC, invar PMC, inconst LABEL) =item B(invar PMC, in INT, inconst LABEL) =item B(invar PMC, in NUM, inconst LABEL) =item B(invar PMC, in STR, inconst LABEL) =item B(invar PMC, invar PMC, inconst LABEL) =item B(invar PMC, invar PMC, inconst LABEL) =item B(in STR, in STR, inconst LABEL) =item B(invar PMC, invar PMC, inconst LABEL) Branch if $1 is not equal to $2. =cut inline op ne(in INT, in INT, inconst LABEL) :base_core { if ($1 != $2) { goto OFFSET($3); } } inline op ne(in NUM, in NUM, inconst LABEL) :base_core { if ($1 != $2) { goto OFFSET($3); } } op ne(in STR, in STR, inconst LABEL) :base_core { if (Parrot_str_not_equal(interp, $1, $2)) { goto OFFSET($3); } } op ne(invar PMC, invar PMC, inconst LABEL) :base_core { if (!VTABLE_is_equal(interp, $1, $2)) { goto OFFSET($3); } } op ne(invar PMC, in INT, inconst LABEL) :base_core { PMC * temp = temporary_pmc_new(interp, enum_class_Integer); VTABLE_set_integer_native(interp, temp, $2); if (!VTABLE_is_equal(interp, $1, temp)) { temporary_pmc_free(interp, temp); goto OFFSET($3); } temporary_pmc_free(interp, temp); } op ne(invar PMC, in NUM, inconst LABEL) :base_core { if (VTABLE_get_number(interp, $1) != $2) { goto OFFSET($3); } } op ne(invar PMC, in STR, inconst LABEL) :base_core { if (Parrot_str_not_equal(interp, VTABLE_get_string(interp, $1), $2)) { goto OFFSET($3); } } op ne_str(invar PMC, invar PMC, inconst LABEL) :base_core { if (VTABLE_cmp_string(interp, $1, $2) != 0) { goto OFFSET($3); } } op ne_num(invar PMC, invar PMC, inconst LABEL) :base_core { if (VTABLE_cmp_num(interp, $1, $2) != 0) { goto OFFSET($3); } } op ne_addr(in STR, in STR, inconst LABEL) :base_core { if ($1 != $2) { goto OFFSET($3); } } op ne_addr(invar PMC, invar PMC, inconst LABEL) :base_core { if ($1 != $2) { goto OFFSET($3); } } ######################################## =item B(in INT, in INT, inconst LABEL) =item B(in NUM, in NUM, inconst LABEL) =item B(in STR, in STR, inconst LABEL) =item B(invar PMC, invar PMC, inconst LABEL) =item B(invar PMC, in INT, inconst LABEL) =item B(invar PMC, in NUM, inconst LABEL) =item B(invar PMC, in STR, inconst LABEL) =item B(invar PMC, invar PMC, inconst LABEL) =item B(invar PMC, invar PMC, inconst LABEL) Branch if $1 is less than $2. =cut inline op lt(in INT, in INT, inconst LABEL) :base_core { if ($1 < $2) { goto OFFSET($3); } } inline op lt(in NUM, in NUM, inconst LABEL) :base_core { if ($1 < $2) { goto OFFSET($3); } } op lt(in STR, in STR, inconst LABEL) :base_core { if (Parrot_str_compare(interp, $1, $2) < 0) { goto OFFSET($3); } } op lt(invar PMC, invar PMC, inconst LABEL) :base_core { if (VTABLE_cmp(interp, $1, $2) < 0) { goto OFFSET($3); } } op lt(invar PMC, in INT, inconst LABEL) :base_core { PMC * temp = temporary_pmc_new(interp, enum_class_Integer); VTABLE_set_integer_native(interp, temp, $2); if (VTABLE_cmp(interp, $1, temp) < 0) { temporary_pmc_free(interp, temp); goto OFFSET($3); } temporary_pmc_free(interp, temp); } op lt(invar PMC, in NUM, inconst LABEL) :base_core { if (VTABLE_get_number(interp, $1) < $2) { goto OFFSET($3); } } op lt(invar PMC, in STR, inconst LABEL) :base_core { if (Parrot_str_compare(interp, VTABLE_get_string(interp, $1), $2) < 0) { goto OFFSET($3); } } op lt_str(invar PMC, invar PMC, inconst LABEL) :base_core { if (VTABLE_cmp_string(interp, $1, $2) < 0) { goto OFFSET($3); } } op lt_num(invar PMC, invar PMC, inconst LABEL) :base_core { if (VTABLE_cmp_num(interp, $1, $2) < 0) { goto OFFSET($3); } } ######################################## =item B(in INT, in INT, inconst LABEL) =item B(in NUM, in NUM, inconst LABEL) =item B(in STR, in STR, inconst LABEL) =item B(invar PMC, invar PMC, inconst LABEL) =item B(invar PMC, in INT, inconst LABEL) =item B(invar PMC, in NUM, inconst LABEL) =item B(invar PMC, in STR, inconst LABEL) =item B(invar PMC, invar PMC, inconst LABEL) =item B(invar PMC, invar PMC, inconst LABEL) Branch if $1 is less than or equal to $2. =cut inline op le(in INT, in INT, inconst LABEL) :base_core { if ($1 <= $2) { goto OFFSET($3); } } inline op le(in NUM, in NUM, inconst LABEL) :base_core { if ($1 <= $2) { goto OFFSET($3); } } op le(in STR, in STR, inconst LABEL) :base_core { if (Parrot_str_compare(interp, $1, $2) <= 0) { goto OFFSET($3); } } op le(invar PMC, invar PMC, inconst LABEL) :base_core { if (VTABLE_cmp(interp, $1, $2) <= 0) { goto OFFSET($3); } } op le(invar PMC, in INT, inconst LABEL) :base_core { PMC * temp = temporary_pmc_new(interp, enum_class_Integer); VTABLE_set_integer_native(interp, temp, $2); if (VTABLE_cmp(interp, $1, temp) <= 0) { temporary_pmc_free(interp, temp); goto OFFSET($3); } temporary_pmc_free(interp, temp); } op le(invar PMC, in NUM, inconst LABEL) :base_core { if (VTABLE_get_number(interp, $1) <= $2) { goto OFFSET($3); } } op le(invar PMC, in STR, inconst LABEL) :base_core { if (Parrot_str_compare(interp, VTABLE_get_string(interp, $1), $2) <= 0) { goto OFFSET($3); } } op le_str(invar PMC, invar PMC, inconst LABEL) :base_core { if (VTABLE_cmp_string(interp, $1, $2) <= 0) { goto OFFSET($3); } } op le_num(invar PMC, invar PMC, inconst LABEL) :base_core { if (VTABLE_cmp_num(interp, $1, $2) <= 0) { goto OFFSET($3); } } ######################################## =item B(invar PMC, invar PMC, inconst LABEL) =item B(invar PMC, in INT, inconst LABEL) =item B(invar PMC, in NUM, inconst LABEL) =item B(invar PMC, in STR, inconst LABEL) =item B(invar PMC, invar PMC, inconst LABEL) =item B(invar PMC, invar PMC, inconst LABEL) Branch if $1 is greater than $2. =cut op gt(invar PMC, invar PMC, inconst LABEL) :base_core { if (VTABLE_cmp(interp, $1, $2) > 0) { goto OFFSET($3); } } op gt(invar PMC, in INT, inconst LABEL) :base_core { PMC * temp = temporary_pmc_new(interp, enum_class_Integer); VTABLE_set_integer_native(interp, temp, $2); if (VTABLE_cmp(interp, $1, temp) > 0) { temporary_pmc_free(interp, temp); goto OFFSET($3); } temporary_pmc_free(interp, temp); } op gt(invar PMC, in NUM, inconst LABEL) :base_core { if (VTABLE_get_number(interp, $1) > $2) { goto OFFSET($3); } } op gt(invar PMC, in STR, inconst LABEL) :base_core { if (Parrot_str_compare(interp, VTABLE_get_string(interp, $1), $2) > 0) { goto OFFSET($3); } } op gt_str(invar PMC, invar PMC, inconst LABEL) :base_core { if (VTABLE_cmp_string(interp, $1, $2) > 0) { goto OFFSET($3); } } op gt_num(invar PMC, invar PMC, inconst LABEL) :base_core { if (VTABLE_cmp_num(interp, $1, $2) > 0) { goto OFFSET($3); } } ######################################## =item B(invar PMC, invar PMC, inconst LABEL) =item B(invar PMC, in INT, inconst LABEL) =item B(invar PMC, in NUM, inconst LABEL) =item B(invar PMC, in STR, inconst LABEL) =item B(invar PMC, invar PMC, inconst LABEL) =item B(invar PMC, invar PMC, inconst LABEL) Branch if $1 is greater than or equal to $2. =cut op ge(invar PMC, invar PMC, inconst LABEL) :base_core { if (VTABLE_cmp(interp, $1, $2) >= 0) { goto OFFSET($3); } } op ge(invar PMC, in INT, inconst LABEL) :base_core { PMC * temp = temporary_pmc_new(interp, enum_class_Integer); VTABLE_set_integer_native(interp, temp, $2); if (VTABLE_cmp(interp, $1, temp) >= 0) { temporary_pmc_free(interp, temp); goto OFFSET($3); } temporary_pmc_free(interp, temp); } op ge(invar PMC, in NUM, inconst LABEL) :base_core { if (VTABLE_get_number(interp, $1) >= $2) { goto OFFSET($3); } } op ge(invar PMC, in STR, inconst LABEL) :base_core { if (Parrot_str_compare(interp, VTABLE_get_string(interp, $1), $2) >= 0) { goto OFFSET($3); } } op ge_str(invar PMC, invar PMC, inconst LABEL) :base_core { if (VTABLE_cmp_string(interp, $1, $2) >= 0) { goto OFFSET($3); } } op ge_num(invar PMC, invar PMC, inconst LABEL) :base_core { if (VTABLE_cmp_num(interp, $1, $2) >= 0) { goto OFFSET($3); } } ######################################## =item B(invar PMC, inconst LABEL) Branch to $2 if $1 is a NULL PMC. =item B(invar STR, inconst LABEL) Branch to $2 if $1 is a NULL STRING. =cut op if_null(invar PMC, inconst LABEL) { if (PMC_IS_NULL($1)) { goto OFFSET($2); } } op if_null(invar STR, inconst LABEL) { if (!$1) { goto OFFSET($2); } } ######################################## =item B(invar PMC, inconst LABEL) Branch to $2 if $1 is I a NULL PMC. =item B(invar STR, inconst LABEL) Branch to $2 if $1 is I a NULL STRING. =cut op unless_null(invar PMC, inconst LABEL) { if (!PMC_IS_NULL($1)) { goto OFFSET($2); } } op unless_null(invar STR, inconst LABEL) { if ($1) { goto OFFSET($2); } } =back =cut ############################################################################### =head2 Non-flow control comparison ops These ops do comparisons and truth testing without doing flow control. =over 4 =item B(out INT, in INT, in INT) =item B(out INT, in NUM, in NUM) =item B(out INT, in STR, in STR) =item B(out INT, invar PMC, invar PMC) =item B(out INT, invar PMC, in INT) =item B(out INT, invar PMC, in NUM) =item B(out INT, invar PMC, in STR) =item B(out INT, invar PMC, invar PMC) =item B(out INT, invar PMC, invar PMC) Sets $1 to -1 if $2 < $3, +1 if $2 > $3, and 0 otherwise. =cut inline op cmp(out INT, in INT, in INT) :base_core { $1 = $2 < $3 ? -1 : $2 > $3 ? +1 : 0; } inline op cmp(out INT, in NUM, in NUM) :base_core { $1 = $2 < $3 ? -1 : $2 > $3 ? +1 : 0; } inline op cmp(out INT, in STR, in STR) :base_core { $1 = Parrot_str_compare(interp, $2, $3); } inline op cmp(out INT, invar PMC, invar PMC) :base_core { $1 = VTABLE_cmp(interp, $2, $3); } inline op cmp(out INT, invar PMC, in INT) :base_core { const INTVAL l = VTABLE_get_integer(interp, $2); $1 = l < $3 ? -1 : l > $3 ? +1 : 0; } inline op cmp(out INT, invar PMC, in NUM) :base_core { const FLOATVAL l = VTABLE_get_number(interp, $2); $1 = l < $3 ? -1 : l > $3 ? +1 : 0; } inline op cmp(out INT, invar PMC, in STR) :base_core { STRING* const l = VTABLE_get_string(interp, $2); $1 = Parrot_str_compare(interp, l, $3); } inline op cmp_str(out INT, invar PMC, invar PMC) :base_core { $1 = VTABLE_cmp_string(interp, $2, $3); } inline op cmp_num(out INT, invar PMC, invar PMC) :base_core { $1 = VTABLE_cmp_num(interp, $2, $3); } ######################################## =item B(out INT, invar PMC, invar PMC) =item B(out INT, in STR, in STR) Sets $1 to 1 or 0, depending on the identity of the 2 objects. The identity is the PMCs memory address. =item B(out INT, invar PMC, invar PMC) =item B(out INT, in STR, in STR) Sets $1 to 0 or 1, depending on the identity of the 2 objects. =item B(out INT, invar PMC) Sets $1 to 1 or 0, depending on whether $2 is true or not. =item B(out INT, invar PMC) Sets $1 to 1 or 0, depending on whether $2 is false or not. =item B(out INT, in PMC) Sets $1 to 1 if the object is null, 0 otherwise. =cut inline op issame(out INT, invar PMC, invar PMC) { if ($2 == $3) $1 = 1; else $1 = VTABLE_is_same(interp, $2, $3); } inline op issame(out INT, in STR, in STR) { $1 = $2 == $3; } inline op isntsame(out INT, invar PMC, invar PMC) { if ($2 == $3) $1 = 0; else $1 = !VTABLE_is_same(interp, $2, $3); } inline op isntsame(out INT, in STR, in STR) { $1 = $2 != $3; } inline op istrue(out INT, invar PMC) { $1 = VTABLE_get_bool(interp, $2); } inline op isfalse(out INT, invar PMC) { $1 = !VTABLE_get_bool(interp, $2); } inline op isnull(out INT, in PMC) { $1 = PMC_IS_NULL($2); } =item B(out INT, in INT, in INT) =item B(out INT, in NUM, in NUM) =item B(out INT, in STR, in STR) These 3 opcodes are valid, but create as their reverse. =item B(out INT, invar PMC, invar PMC) Sets $1 to 1 if $2 is greater than $3. =cut inline op isgt(out INT, invar PMC, invar PMC) { $1 = (VTABLE_cmp(interp, $2, $3) > 0); } =item B(out INT, in INT, in INT) =item B(out INT, in NUM, in NUM) =item B(out INT, in STR, in STR) These 3 opcodes are valid, but create as their reverse. =item B(out INT, invar PMC, invar PMC) Sets $1 to 1 if $2 is greater than or equal to $3. =cut inline op isge(out INT, invar PMC, invar PMC) { $1 = (VTABLE_cmp(interp, $2, $3) >= 0); } =item B(out INT, in INT, in INT) =item B(out INT, in NUM, in NUM) =item B(out INT, in STR, in STR) =item B(out INT, invar PMC, invar PMC) Sets $1 to 1 if $2 is less than or equal to $3. =cut inline op isle(out INT, in INT, in INT) { $1 = $2 <= $3; } inline op isle(out INT, in NUM, in NUM) { $1 = $2 <= $3; } inline op isle(out INT, in STR, in STR) { $1 = Parrot_str_compare(interp, $2, $3) <= 0; } inline op isle(out INT, invar PMC, invar PMC) { $1 = (VTABLE_cmp(interp, $2, $3) <= 0); } =item B(out INT, in INT, in INT) =item B(out INT, in NUM, in NUM) =item B(out INT, in STR, in STR) =item B(out INT, invar PMC, invar PMC) Sets $1 to 1 if $2 is less than $3. =cut inline op islt(out INT, in INT, in INT) { $1 = ($2 < $3) ? 1 : 0; } inline op islt(out INT, in NUM, in NUM) { $1 = $2 < $3; } inline op islt(out INT, in STR, in STR) { $1 = Parrot_str_compare(interp, $2, $3) < 0; } inline op islt(out INT, invar PMC, invar PMC) { $1 = (VTABLE_cmp(interp, $2, $3) < 0); } =item B(out INT, in INT, in INT) =item B(out INT, in NUM, in NUM) =item B(out INT, in STR, in STR) =item B(out INT, invar PMC, invar PMC) Sets $1 to 1 if $2 is equal to $3. =cut inline op iseq(out INT, in INT, in INT) { $1 = ($2 == $3) ? 1 : 0; } inline op iseq(out INT, in NUM, in NUM) { $1 = $2 == $3; } inline op iseq(out INT, in STR, in STR) { $1 = (Parrot_str_equal(interp, $2, $3) ? 1 : 0); } inline op iseq(out INT, invar PMC, invar PMC) { if (&$2 == &$3) $1 = 1; else $1 = VTABLE_is_equal(interp, $2, $3); } =item B(out INT, in INT, in INT) =item B(out INT, in NUM, in NUM) =item B(out INT, in STR, in STR) =item B(out INT, invar PMC, invar PMC) Sets $1 to 1 if $2 is not equal to $3. =cut inline op isne(out INT, in INT, in INT) { $1 = ($2 == $3) ? 0 : 1; } inline op isne(out INT, in NUM, in NUM) { $1 = $2 != $3; } inline op isne(out INT, in STR, in STR) { $1 = (Parrot_str_not_equal(interp, $2, $3) ? 1 : 0); } inline op isne(out INT, invar PMC, invar PMC) { if (&$2 == &$3) $1 = 0; else $1 = !VTABLE_is_equal(interp, $2, $3); } =back =cut ############################################################################### =head2 Logical operations These operations apply logical functions to their arguments. =over 4 =cut ######################################## =item B(out INT, in INT, in INT) =item B(invar PMC, invar PMC, invar PMC) Short-circuiting logical and. Returns $2 if it's false, else returns $3. =cut inline op and(out INT, in INT, in INT) :base_core { $1 = $2 ? $3 : $2; } inline op and(invar PMC, invar PMC, invar PMC) :base_core { $1 = VTABLE_logical_and(interp, $2, $3, $1); } ######################################## =item B(inout INT) =item B(invar PMC) Set the boolean state of $1 to the opposite of the boolean state from $1. =item B(out INT, in INT) =item B(out PMC, invar PMC) =cut inline op not(inout INT) :base_core { $1 = ! $1; } inline op not(out INT, in INT) :base_core { $1 = ! $2; } inline op not(invar PMC) :base_core { VTABLE_i_logical_not(interp, $1); } inline op not(out PMC, invar PMC) :base_core { $1 = VTABLE_logical_not(interp, $2, $1); } ######################################## =item B(out INT, in INT, in INT) =item B(invar PMC, invar PMC, invar PMC) Short-circuiting logical or. Returns $2 if it's true, else returns $3. =cut inline op or(out INT, in INT, in INT) :base_core { $1 = $2 ? $2 : $3; } inline op or(invar PMC, invar PMC, invar PMC) :base_core { $1 = VTABLE_logical_or(interp, $2, $3, $1); } ######################################## =item B(out INT, in INT, in INT) =item B(invar PMC, invar PMC, invar PMC) Logical xor. Returns $2 if it's true and $3 isn't, returns $3 if it's true and $2 isn't, else returns false. =cut inline op xor(out INT, in INT, in INT) :base_core { $1 = ($2 && ! $3) ? $2 : ($3 && ! $2) ? $3 : 0; } inline op xor(invar PMC, invar PMC, invar PMC) :base_core { $1 = VTABLE_logical_xor(interp, $2, $3, $1); } =back =cut ############################################################################### =head1 COPYRIGHT Copyright (C) 2001-2009, Parrot Foundation. =head1 LICENSE This program is free software. It is subject to the same license as the Parrot interpreter itself. =cut /* * Local variables: * c-file-style: "parrot" * End: * vim: expandtab shiftwidth=4: */