aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/mn10300
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2011-02-15 17:09:39 +0000
committerNick Clifton <nickc@gcc.gnu.org>2011-02-15 17:09:39 +0000
commita45d420abf5125d73bfdc2d2af3753b810c349eb (patch)
tree060852815ff3bf81b7fef60acee53e79f440a99b /gcc/config/mn10300
parent8a73faf108721a76f55441f6d2a3937fff901b36 (diff)
downloadgcc-a45d420abf5125d73bfdc2d2af3753b810c349eb.zip
gcc-a45d420abf5125d73bfdc2d2af3753b810c349eb.tar.gz
gcc-a45d420abf5125d73bfdc2d2af3753b810c349eb.tar.bz2
mn10300.c: Include tm-constrs.h.
* config/mn10300/mn10300.c: Include tm-constrs.h. (struct liw_data): New data structure describing an LIW candidate instruction. (extract_bundle): Use struct liw_data. Allow small integer operands for some instructions. (check_liw_constraints): Use struct liw_data. Remove swapped parameter. Add comments describing the checks. Fix bug when assigning the source of liw1 to the source of liw2. (liw_candidate): Delete. Code moved into extract_bundle. (mn10300_bundle_liw): Use struct liw_data. Check constraints before swapping. * config/mn10300/predicates.md (liw_operand): New predicate. Allows registers and small integer constants. * config/mn10300/constraints.md (O): New constraint. Accetps integers in the range -8 to +7 inclusive. * config/mn10300/mn10300.md (movesi_internal): Add an alternative for moving a small integer into a register. Give this alternative LIW attributes. (addsi3, subsi3, cmpsi, lshrsi3, ashrsi3): Likewise. (ashlsi3): Likewise, plus give LIW attributes to the alternatives using the J,K,L and M constraints, (liw): Remove SI mode on second operands to allow for HI and QI mode values. (cmp_liw, liw_cmp): Likewise. Plus fix order of operands in the instruction. From-SVN: r170182
Diffstat (limited to 'gcc/config/mn10300')
-rw-r--r--gcc/config/mn10300/constraints.md6
-rw-r--r--gcc/config/mn10300/mn10300.c211
-rw-r--r--gcc/config/mn10300/mn10300.md109
-rw-r--r--gcc/config/mn10300/predicates.md4
4 files changed, 190 insertions, 140 deletions
diff --git a/gcc/config/mn10300/constraints.md b/gcc/config/mn10300/constraints.md
index a4816c1..c8ee2d4 100644
--- a/gcc/config/mn10300/constraints.md
+++ b/gcc/config/mn10300/constraints.md
@@ -94,6 +94,12 @@
(ior (match_test "ival == 255")
(match_test "ival == 65535"))))
+(define_constraint "O"
+ "An integer between -8 and +7 inclusive."
+ (and (match_code "const_int")
+ (and (match_test "ival >= -8")
+ (match_test "ival <= 7"))))
+
;; Floating-point constraints
(define_constraint "G"
"Floating-point zero."
diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c
index 5ff8852..0b68f2d 100644
--- a/gcc/config/mn10300/mn10300.c
+++ b/gcc/config/mn10300/mn10300.c
@@ -40,6 +40,7 @@
#include "obstack.h"
#include "diagnostic-core.h"
#include "tm_p.h"
+#include "tm-constrs.h"
#include "target.h"
#include "target-def.h"
#include "df.h"
@@ -2945,91 +2946,143 @@ mn10300_split_and_operand_count (rtx op)
}
}
-/* Extract operands and (if requested) the LIW op type from the insn.
- Returns false if the insn can't be bundled. */
+struct liw_data
+{
+ enum attr_liw slot;
+ enum attr_liw_op op;
+ rtx dest;
+ rtx src;
+};
+
+/* Decide if the given insn is a candidate for LIW bundling. If it is then
+ extract the operands and LIW attributes from the insn and use them to fill
+ in the liw_data structure. Return true upon success or false if the insn
+ cannot be bundled. */
static bool
-extract_bundle (rtx insn, rtx * ops, enum attr_liw_op * plop)
+extract_bundle (rtx insn, struct liw_data * pdata)
{
- enum attr_liw_op lop;
- rtx p, s;
+ bool allow_consts = true;
+ rtx p,s;
+ gcc_assert (pdata != NULL);
+
+ if (insn == NULL_RTX)
+ return false;
+ /* Make sure that we are dealing with a simple SET insn. */
p = single_set (insn);
+ if (p == NULL_RTX)
+ return false;
+
+ /* Make sure that it could go into one of the LIW pipelines. */
+ pdata->slot = get_attr_liw (insn);
+ if (pdata->slot == LIW_BOTH)
+ return false;
+
+ pdata->op = get_attr_liw_op (insn);
+
s = SET_SRC (p);
- lop = get_attr_liw_op (insn);
- if (plop != NULL)
- * plop = lop;
- switch (lop)
+ switch (pdata->op)
{
case LIW_OP_MOV:
- ops[0] = SET_DEST (p);
- ops[1] = SET_SRC (p);
+ pdata->dest = SET_DEST (p);
+ pdata->src = SET_SRC (p);
break;
case LIW_OP_CMP:
- ops[0] = XEXP (SET_SRC (p), 0);
- ops[1] = XEXP (SET_SRC (p), 1);
+ pdata->dest = XEXP (SET_SRC (p), 0);
+ pdata->src = XEXP (SET_SRC (p), 1);
break;
case LIW_OP_NONE:
return false;
+ case LIW_OP_AND:
+ case LIW_OP_OR:
+ case LIW_OP_XOR:
+ /* The AND, OR and XOR long instruction words only accept register arguments. */
+ allow_consts = false;
+ /* Fall through. */
default:
- ops[0] = SET_DEST (p);
- ops[1] = XEXP (SET_SRC (p), 1);
+ pdata->dest = SET_DEST (p);
+ pdata->src = XEXP (SET_SRC (p), 1);
break;
}
- return REG_P (ops[0]) && REG_P (ops[1]);
+ if (! REG_P (pdata->dest))
+ return false;
+
+ if (REG_P (pdata->src))
+ return true;
+
+ return allow_consts && satisfies_constraint_O (pdata->src);
}
-/* Look for conflicts in the operands used in
- the potential bundling of the two insns. */
+/* Make sure that it is OK to execute LIW1 and LIW2 in parallel. GCC generated
+ the instructions with the assumption that LIW1 would be executed before LIW2
+ so we must check for overlaps between their sources and destinations. */
static bool
-check_liw_constraints (rtx ops[4],
- enum attr_liw_op op1,
- enum attr_liw_op op2,
- bool swapped)
-{
- /* Look for the two destination registers being the same. This is OK if
- the first op is a comparison op, since it will compare the value prior
- to the completion of the second op. */
- if (REGNO (ops[0]) == REGNO (ops[2])
- && ( (! swapped && op1 != LIW_OP_CMP)
- || (swapped && op2 != LIW_OP_CMP)))
+check_liw_constraints (struct liw_data * pliw1, struct liw_data * pliw2)
+{
+ /* Check for slot conflicts. */
+ if (pliw2->slot == pliw1->slot && pliw1->slot != LIW_EITHER)
return false;
- /* Look for the source of the second op being the destination of the first op.
- Nomrally this will prevent the bundling since GCC has generated sequential
- operations and the LIW opcodes are executed in parallel. But if the first
- opcode is a MOV, we can copy its source to the second ops source. */
- if (swapped)
- return REGNO (ops[1]) != REGNO (ops[2]);
+ /* If either operation is a compare, then "dest" is really an input; the real
+ destination is CC_REG. So these instructions need different checks. */
+
+ /* Changing "CMP ; OP" into "CMP | OP" is OK because the comparison will
+ check its values prior to any changes made by OP. */
+ if (pliw1->op == LIW_OP_CMP)
+ {
+ /* Two sequential comparisons means dead code, which ought to
+ have been eliminated given that bundling only happens with
+ optimization. We cannot bundle them in any case. */
+ gcc_assert (pliw1->op != pliw2->op);
+ return true;
+ }
- if (REGNO (ops[3]) == REGNO (ops[0]))
+ /* Changing "OP ; CMP" into "OP | CMP" does not work if the value being compared
+ is the destination of OP, as the CMP will look at the old value, not the new
+ one. */
+ if (pliw2->op == LIW_OP_CMP)
{
- if (op1 == LIW_OP_MOV)
+ if (REGNO (pliw2->dest) == REGNO (pliw1->dest))
+ return false;
+
+ if (REG_P (pliw2->src))
+ return REGNO (pliw2->src) != REGNO (pliw1->dest);
+
+ return true;
+ }
+
+ /* Changing "OP1 ; OP2" into "OP1 | OP2" does not work if they both write to the
+ same destination register. */
+ if (REGNO (pliw2->dest) == REGNO (pliw1->dest))
+ return false;
+
+ /* Changing "OP1 ; OP2" into "OP1 | OP2" generally does not work if the destination
+ of OP1 is the source of OP2. The exception is when OP1 is a MOVE instruction when
+ we can replace the source in OP2 with the source of OP1. */
+ if (REG_P (pliw2->src) && REGNO (pliw2->src) == REGNO (pliw1->dest))
+ {
+ if (pliw1->op == LIW_OP_MOV && REG_P (pliw1->src))
{
- ops[3] = ops[1];
+ if (! REG_P (pliw1->src)
+ && (pliw2->op == LIW_OP_AND
+ || pliw2->op == LIW_OP_OR
+ || pliw2->op == LIW_OP_XOR))
+ return false;
+
+ pliw2->src = pliw1->src;
return true;
}
return false;
}
+ /* Everything else is OK. */
return true;
}
-/* Decide if the given insn is a candidate for LIW bundling. For now we just
- check that the insn has an LIW attribute. Later on we check operand
- constraints and such. */
-
-static bool
-liw_candidate (rtx insn)
-{
- return insn != NULL_RTX
- && single_set (insn) != NULL_RTX
- && get_attr_liw (insn) != LIW_BOTH;
-}
-
/* Combine pairs of insns into LIW bundles. */
static void
@@ -3039,61 +3092,41 @@ mn10300_bundle_liw (void)
for (r = get_insns (); r != NULL_RTX; r = next_nonnote_nondebug_insn (r))
{
- rtx insn1, insn2, ops[4];
- enum attr_liw liw1, liw2;
- enum attr_liw_op op1, op2;
- bool swapped = false;
+ rtx insn1, insn2;
+ struct liw_data liw1, liw2;
insn1 = r;
- if (! liw_candidate (insn1))
+ if (! extract_bundle (insn1, & liw1))
continue;
insn2 = next_nonnote_nondebug_insn (insn1);
- if (! liw_candidate (insn2))
+ if (! extract_bundle (insn2, & liw2))
continue;
- liw1 = get_attr_liw (insn1);
- if (liw1 == LIW_BOTH)
- continue;
- liw2 = get_attr_liw (insn2);
- if (liw2 == LIW_BOTH)
- continue;
- if (liw2 == liw1 && liw1 != LIW_EITHER)
+ /* Check for source/destination overlap. */
+ if (! check_liw_constraints (& liw1, & liw2))
continue;
- /* The scheduler always groups the insns correctly, but not
- always in sequence. So, we can do a naive check and expect
- it to work. */
- if (liw1 == LIW_OP2 || liw2 == LIW_OP1)
+ if (liw1.slot == LIW_OP2 || liw2.slot == LIW_OP1)
{
- rtx r;
- enum attr_liw lt;
-
- r = insn1;
- insn1 = insn2;
- insn2 = r;
- lt = liw1;
+ struct liw_data temp;
+
+ temp = liw1;
liw1 = liw2;
- liw2 = lt;
- swapped = true;
+ liw2 = temp;
}
- if (! extract_bundle (insn1, ops, & op1))
- continue;
- if (! extract_bundle (insn2, ops + 2, & op2))
- continue;
- if (! check_liw_constraints (ops, op1, op2, swapped))
- continue;
-
delete_insn (insn2);
- if (op1 == LIW_OP_CMP)
- insn2 = gen_cmp_liw (ops[2], ops[3], ops[0], ops[1], GEN_INT (op2));
- else if (op2 == LIW_OP_CMP)
- insn2 = gen_liw_cmp (ops[0], ops[1], ops[2], ops[3], GEN_INT (op1));
+ if (liw1.op == LIW_OP_CMP)
+ insn2 = gen_cmp_liw (liw2.dest, liw2.src, liw1.dest, liw1.src,
+ GEN_INT (liw2.op));
+ else if (liw2.op == LIW_OP_CMP)
+ insn2 = gen_liw_cmp (liw1.dest, liw1.src, liw2.dest, liw2.src,
+ GEN_INT (liw1.op));
else
- insn2 = gen_liw (ops[0], ops[2], ops[1], ops[3],
- GEN_INT (op1), GEN_INT (op2));
+ insn2 = gen_liw (liw1.dest, liw2.dest, liw1.src, liw2.src,
+ GEN_INT (liw1.op), GEN_INT (liw2.op));
insn2 = emit_insn_after (insn2, insn1);
delete_insn (insn1);
diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md
index e8d2ae1..3d8e914 100644
--- a/gcc/config/mn10300/mn10300.md
+++ b/gcc/config/mn10300/mn10300.md
@@ -419,9 +419,9 @@
(define_insn "*movsi_internal"
[(set (match_operand:SI 0 "nonimmediate_operand"
- "=r,r,r,m,r, A,*y,*y,*z,*d")
+ "=r,r,r,r,m,r, A,*y,*y,*z,*d")
(match_operand:SI 1 "general_operand"
- " 0,i,r,r,m,*y, A, i,*d,*z"))]
+ " 0,O,i,r,r,m,*y, A, i,*d,*z"))]
"register_operand (operands[0], SImode)
|| register_operand (operands[1], SImode)"
{
@@ -429,7 +429,8 @@
{
case 0:
return "";
- case 1: /* imm-reg*/
+ case 1: /* imm-reg. */
+ case 2:
/* See movhi for a discussion of sizes for 8-bit movu. Note that the
24-bit movu is 6 bytes, which is the same size as the full 32-bit
mov form for An and Dn. So again movu is only a win for Rn. */
@@ -443,25 +444,26 @@
return "movu %1,%0";
}
/* FALLTHRU */
- case 2: /* reg-reg */
- case 3: /* reg-mem */
- case 4: /* mem-reg */
- case 5: /* sp-reg */
- case 6: /* reg-sp */
- case 7: /* imm-sp */
- case 8: /* reg-mdr */
- case 9: /* mdr-reg */
+ case 3: /* reg-reg */
+ case 4: /* reg-mem */
+ case 5: /* mem-reg */
+ case 6: /* sp-reg */
+ case 7: /* reg-sp */
+ case 8: /* imm-sp */
+ case 9: /* reg-mdr */
+ case 10: /* mdr-reg */
return "mov %1,%0";
default:
gcc_unreachable ();
}
}
- [(set_attr "isa" "*,*,*,*,*,*,*,am33,*,*")
- (set_attr "liw" "*,*,either,*,*,*,*,*,*,*")
+ [(set_attr "isa" "*,*,*,*,*,*,*,*,am33,*,*")
+ (set_attr "liw" "*,either,*,either,*,*,*,*,*,*,*")
(set_attr "liw_op" "mov")
(set_attr_alternative "timings"
[(const_int 11)
(const_int 22)
+ (const_int 22)
(const_int 11)
(if_then_else (eq_attr "cpu" "am34")
(const_int 11) (const_int 22))
@@ -563,14 +565,14 @@
;; ----------------------------------------------------------------------
(define_insn "addsi3"
- [(set (match_operand:SI 0 "register_operand" "=r,r,!*y,!r")
- (plus:SI (match_operand:SI 1 "register_operand" "%0,0, 0, r")
- (match_operand:SI 2 "nonmemory_operand" "r,i, i, r")))
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,!*y,!r")
+ (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0, 0, r")
+ (match_operand:SI 2 "nonmemory_operand" "r,O,i, i, r")))
(clobber (reg:CC CC_REG))]
""
{ return mn10300_output_add (operands, false); }
- [(set_attr "timings" "11,11,11,22")
- (set_attr "liw" "either,*,*,*")
+ [(set_attr "timings" "11,11,11,11,22")
+ (set_attr "liw" "either,either,*,*,*")
(set_attr "liw_op" "add")]
)
@@ -758,19 +760,20 @@
;; ----------------------------------------------------------------------
(define_insn "subsi3"
- [(set (match_operand:SI 0 "register_operand" "=r,r,r")
- (minus:SI (match_operand:SI 1 "register_operand" "0,0,r")
- (match_operand:SI 2 "nonmemory_operand" "r,i,r")))
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
+ (minus:SI (match_operand:SI 1 "register_operand" "0,0,0,r")
+ (match_operand:SI 2 "nonmemory_operand" "r,O,i,r")))
(clobber (reg:CC CC_REG))]
""
"@
sub %2,%0
sub %2,%0
+ sub %2,%0
sub %2,%1,%0"
- [(set_attr "isa" "*,*,am33")
- (set_attr "liw" "either,*,*")
+ [(set_attr "isa" "*,*,*,am33")
+ (set_attr "liw" "either,either,*,*")
(set_attr "liw_op" "sub")
- (set_attr "timings" "11,11,22")]
+ (set_attr "timings" "11,11,11,22")]
)
(define_insn "*subsi3_flags"
@@ -1374,8 +1377,8 @@
(define_insn "*cmpsi"
[(set (reg CC_REG)
- (compare (match_operand:SI 0 "register_operand" "r,r")
- (match_operand:SI 1 "nonmemory_operand" "r,i")))]
+ (compare (match_operand:SI 0 "register_operand" "r,r,r")
+ (match_operand:SI 1 "nonmemory_operand" "r,O,i")))]
"reload_completed"
{
/* The operands of CMP must be distinct registers. In the case where
@@ -1390,8 +1393,9 @@
}
[(set_attr_alternative "timings"
[(if_then_else (eq_attr "cpu" "am34") (const_int 11) (const_int 22))
+ (if_then_else (eq_attr "cpu" "am34") (const_int 11) (const_int 22))
(if_then_else (eq_attr "cpu" "am34") (const_int 11) (const_int 22))])
- (set_attr "liw" "either,*")
+ (set_attr "liw" "either,either,*")
(set_attr "liw_op" "cmp")]
)
@@ -1732,10 +1736,10 @@
;; ----------------------------------------------------------------------
(define_insn "ashlsi3"
- [(set (match_operand:SI 0 "register_operand" "=r,D,d,d,D,D,r")
+ [(set (match_operand:SI 0 "register_operand" "=r,D,d,d,D,D,D,r")
(ashift:SI
- (match_operand:SI 1 "register_operand" " 0,0,0,0,0,0,r")
- (match_operand:QI 2 "nonmemory_operand" " J,K,M,L,D,i,r")))
+ (match_operand:SI 1 "register_operand" " 0,0,0,0,0,0,0,r")
+ (match_operand:QI 2 "nonmemory_operand" " J,K,M,L,D,O,i,r")))
(clobber (reg:CC CC_REG))]
""
"@
@@ -1745,42 +1749,45 @@
asl2 %0\;asl2 %0
asl %S2,%0
asl %S2,%0
+ asl %S2,%0
asl %2,%1,%0"
- [(set_attr "isa" "*,*,*,*,*,*,am33")
- (set_attr "liw" "*,*,*,*,op2,*,*")
+ [(set_attr "isa" "*,*,*,*,*,*,*,am33")
+ (set_attr "liw" "op2,op2,op2,op2,op2,op2,*,*")
(set_attr "liw_op" "asl")
- (set_attr "timings" "11,11,22,22,11,11,11")]
+ (set_attr "timings" "11,11,22,22,11,11,11,11")]
)
(define_insn "lshrsi3"
- [(set (match_operand:SI 0 "register_operand" "=D,D,r")
+ [(set (match_operand:SI 0 "register_operand" "=D,D,D,r")
(lshiftrt:SI
- (match_operand:SI 1 "register_operand" "0,0,r")
- (match_operand:QI 2 "nonmemory_operand" "D,i,r")))
+ (match_operand:SI 1 "register_operand" "0,0,0,r")
+ (match_operand:QI 2 "nonmemory_operand" "D,O,i,r")))
(clobber (reg:CC CC_REG))]
""
"@
lsr %S2,%0
lsr %S2,%0
+ lsr %S2,%0
lsr %2,%1,%0"
- [(set_attr "isa" "*,*,am33")
- (set_attr "liw" "op2,*,*")
+ [(set_attr "isa" "*,*,*,am33")
+ (set_attr "liw" "op2,op2,*,*")
(set_attr "liw_op" "lsr")]
)
(define_insn "ashrsi3"
- [(set (match_operand:SI 0 "register_operand" "=D,D,r")
+ [(set (match_operand:SI 0 "register_operand" "=D,D,D,r")
(ashiftrt:SI
- (match_operand:SI 1 "register_operand" "0,0,r")
- (match_operand:QI 2 "nonmemory_operand" "D,i,r")))
+ (match_operand:SI 1 "register_operand" "0,0,0,r")
+ (match_operand:QI 2 "nonmemory_operand" "D,O,i,r")))
(clobber (reg:CC CC_REG))]
""
"@
asr %S2,%0
asr %S2,%0
+ asr %S2,%0
asr %2,%1,%0"
- [(set_attr "isa" "*,*,am33")
- (set_attr "liw" "op2,*,*")
+ [(set_attr "isa" "*,*,*,am33")
+ (set_attr "liw" "op2,op2,*,*")
(set_attr "liw_op" "asr")]
)
@@ -2100,12 +2107,12 @@
(define_insn "liw"
[(set (match_operand:SI 0 "register_operand" "=r")
(unspec:SI [(match_dup 0)
- (match_operand:SI 2 "register_operand" "r")
+ (match_operand 2 "liw_operand" "rO")
(match_operand:SI 4 "const_int_operand" "")]
UNSPEC_LIW))
(set (match_operand:SI 1 "register_operand" "=r")
(unspec:SI [(match_dup 1)
- (match_operand 3 "register_operand" "r")
+ (match_operand 3 "liw_operand" "rO")
(match_operand:SI 5 "const_int_operand" "")]
UNSPEC_LIW))]
"TARGET_ALLOW_LIW"
@@ -2119,14 +2126,14 @@
(define_insn "cmp_liw"
[(set (reg:CC CC_REG)
(compare:CC (match_operand:SI 2 "register_operand" "r")
- (match_operand:SI 3 "register_operand" "r")))
+ (match_operand 3 "liw_operand" "rO")))
(set (match_operand:SI 0 "register_operand" "=r")
(unspec:SI [(match_dup 0)
- (match_operand 1 "register_operand" "r")
+ (match_operand 1 "liw_operand" "rO")
(match_operand:SI 4 "const_int_operand" "")]
UNSPEC_LIW))]
"TARGET_ALLOW_LIW"
- "cmp_%W4 %2, %3, %0, %1"
+ "cmp_%W4 %3, %2, %1, %0"
[(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
(const_int 13) (const_int 12)))]
)
@@ -2134,14 +2141,14 @@
(define_insn "liw_cmp"
[(set (match_operand:SI 0 "register_operand" "=r")
(unspec:SI [(match_dup 0)
- (match_operand:SI 1 "register_operand" "r")
+ (match_operand 1 "liw_operand" "rO")
(match_operand:SI 4 "const_int_operand" "")]
UNSPEC_LIW))
(set (reg:CC CC_REG)
(compare:CC (match_operand:SI 2 "register_operand" "r")
- (match_operand:SI 3 "register_operand" "r")))]
+ (match_operand 3 "liw_operand" "rO")))]
"TARGET_ALLOW_LIW"
- "%W4_cmp %0, %1, %2, %3"
+ "%W4_cmp %1, %0, %3, %2"
[(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
(const_int 13) (const_int 12)))]
)
diff --git a/gcc/config/mn10300/predicates.md b/gcc/config/mn10300/predicates.md
index 8316990..4c78c51 100644
--- a/gcc/config/mn10300/predicates.md
+++ b/gcc/config/mn10300/predicates.md
@@ -63,3 +63,7 @@
(define_predicate "CCZN_comparison_operator"
(match_code "eq,ne,lt,ge"))
+
+(define_predicate "liw_operand"
+ (ior (match_operand 0 "register_operand")
+ (match_test "satisfies_constraint_O (op)")))