pdp11-protos.h (pdp11_cannot_change_mode_class, [...]): Declare.
* config/pdp11/pdp11-protos.h (pdp11_cannot_change_mode_class, pdp11_secondary_memory_needed): Declare. * config/pdp11/predicates.md (float_operand): New predicate. * config/pdp11/pdp11.md (RETVAL_REGNUM): New constant. (cbranchdf4, movdf): Change predicate. (movsf): Handle FPU register case. (truncdfsf2, extendsfdf2): Add FPU register case. * config/pdp11/pdp11.c (TARGET_SECONDARY_RELOAD, TARGET_REGISTER_MOVE_COST, TARGET_PREFERRED_RELOAD_CLASS, TARGET_PREFERRED_OUTPUT_RELOAD_CLASS): Define. (pdp11_register_move_cost): Update cost matrix. (pdp11_cannot_change_mode_class, pdp11_preferred_reload_class, pdp11_preferred_output_reload_class, pdp11_secondary_reload, pdp11_secondary_memory_needed): New function. (pdp11_return_in_memory): Add other float types. * config/pdp11/pdp11.h (HARD_REGNO_MODE_OK): Add other float types. (SECONDARY_MEMORY_NEEDED, CANNOT_CHANGE_MODE_CLASS): Define. (PREFERRED_RELOAD_CLASS, SECONDARY_RELOAD_CLASS, REGISTER_MOVE_COST): Delete. (BASE_RETURN_VALUE_REG): Add other float types. From-SVN: r166060
This commit is contained in:
parent
1e4bf85b80
commit
a01c666cc6
6 changed files with 201 additions and 54 deletions
|
@ -1,3 +1,27 @@
|
|||
2010-10-29 Paul Koning <pkoning@equallogic.com>
|
||||
|
||||
* config/pdp11/pdp11-protos.h (pdp11_cannot_change_mode_class,
|
||||
pdp11_secondary_memory_needed): Declare.
|
||||
* config/pdp11/predicates.md (float_operand): New predicate.
|
||||
* config/pdp11/pdp11.md (RETVAL_REGNUM): New constant.
|
||||
(cbranchdf4, movdf): Change predicate.
|
||||
(movsf): Handle FPU register case.
|
||||
(truncdfsf2, extendsfdf2): Add FPU register case.
|
||||
* config/pdp11/pdp11.c (TARGET_SECONDARY_RELOAD,
|
||||
TARGET_REGISTER_MOVE_COST, TARGET_PREFERRED_RELOAD_CLASS,
|
||||
TARGET_PREFERRED_OUTPUT_RELOAD_CLASS): Define.
|
||||
(pdp11_register_move_cost): Update cost matrix.
|
||||
(pdp11_cannot_change_mode_class, pdp11_preferred_reload_class,
|
||||
pdp11_preferred_output_reload_class, pdp11_secondary_reload,
|
||||
pdp11_secondary_memory_needed): New function.
|
||||
(pdp11_return_in_memory): Add other float types.
|
||||
* config/pdp11/pdp11.h (HARD_REGNO_MODE_OK): Add other float
|
||||
types.
|
||||
(SECONDARY_MEMORY_NEEDED, CANNOT_CHANGE_MODE_CLASS): Define.
|
||||
(PREFERRED_RELOAD_CLASS, SECONDARY_RELOAD_CLASS,
|
||||
REGISTER_MOVE_COST): Delete.
|
||||
(BASE_RETURN_VALUE_REG): Add other float types.
|
||||
|
||||
2010-10-29 Nick Clifton<nickc@redhat.com>
|
||||
|
||||
* doc/invoke.texi: Document -mam34 and -mtune options.
|
||||
|
|
|
@ -31,7 +31,11 @@ extern const char *output_move_quad (rtx *);
|
|||
extern const char *output_block_move (rtx *);
|
||||
extern const char *output_jump (enum rtx_code, int, int);
|
||||
extern void print_operand_address (FILE *, rtx);
|
||||
extern int pdp11_register_move_cost (enum reg_class, enum reg_class);
|
||||
extern bool pdp11_cannot_change_mode_class (enum machine_mode,
|
||||
enum machine_mode, enum reg_class);
|
||||
extern bool pdp11_secondary_memory_needed (reg_class_t, reg_class_t,
|
||||
enum machine_mode);
|
||||
|
||||
#endif /* RTX_CODE */
|
||||
|
||||
extern void output_ascii (FILE *, const char *, int);
|
||||
|
|
|
@ -216,7 +216,17 @@ static const struct default_options pdp11_option_optimization_table[] =
|
|||
#undef TARGET_TRAMPOLINE_INIT
|
||||
#define TARGET_TRAMPOLINE_INIT pdp11_trampoline_init
|
||||
|
||||
struct gcc_target targetm = TARGET_INITIALIZER;
|
||||
#undef TARGET_SECONDARY_RELOAD
|
||||
#define TARGET_SECONDARY_RELOAD pdp11_secondary_reload
|
||||
|
||||
#undef TARGET_REGISTER_MOVE_COST
|
||||
#define TARGET_REGISTER_MOVE_COST pdp11_register_move_cost
|
||||
|
||||
#undef TARGET_PREFERRED_RELOAD_CLASS
|
||||
#define TARGET_PREFERRED_RELOAD_CLASS pdp11_preferred_reload_class
|
||||
|
||||
#undef TARGET_PREFERRED_OUTPUT_RELOAD_CLASS
|
||||
#define TARGET_PREFERRED_OUTPUT_RELOAD_CLASS pdp11_preferred_output_reload_class
|
||||
|
||||
/* Implement TARGET_HANDLE_OPTION. */
|
||||
|
||||
|
@ -417,7 +427,7 @@ pdp11_output_function_epilogue (FILE *stream, HOST_WIDE_INT size)
|
|||
|
||||
/* get ACs */
|
||||
for (i = AC5_REGNUM; i >= AC0_REGNUM; i--)
|
||||
if (df_regs_ever_live_p (i) && call_used_regs[i])
|
||||
if (df_regs_ever_live_p (i) && ! call_used_regs[i])
|
||||
via_ac = i;
|
||||
|
||||
for (i = AC5_REGNUM; i >= AC0_REGNUM; i--)
|
||||
|
@ -1054,22 +1064,23 @@ static const int move_costs[N_REG_CLASSES][N_REG_CLASSES] =
|
|||
/* NO MUL GEN LFPU NLFPU FPU ALL */
|
||||
|
||||
/* NO */ { 0, 0, 0, 0, 0, 0, 0},
|
||||
/* MUL */ { 0, 2, 2, 10, 22, 22, 22},
|
||||
/* GEN */ { 0, 2, 2, 10, 22, 22, 22},
|
||||
/* LFPU */ { 0, 10, 10, 2, 2, 2, 10},
|
||||
/* NLFPU */ { 0, 22, 22, 2, 2, 2, 22},
|
||||
/* FPU */ { 0, 22, 22, 2, 2, 2, 22},
|
||||
/* ALL */ { 0, 22, 22, 10, 22, 22, 22}
|
||||
/* MUL */ { 0, 2, 2, 22, 22, 22, 22},
|
||||
/* GEN */ { 0, 2, 2, 22, 22, 22, 22},
|
||||
/* LFPU */ { 0, 22, 22, 2, 2, 2, 22},
|
||||
/* NLFPU */ { 0, 22, 22, 2, 10, 10, 22},
|
||||
/* FPU */ { 0, 22, 22, 2, 10, 10, 22},
|
||||
/* ALL */ { 0, 22, 22, 22, 22, 22, 22}
|
||||
} ;
|
||||
|
||||
|
||||
/* -- note that some moves are tremendously expensive,
|
||||
because they require lots of tricks! do we have to
|
||||
charge the costs incurred by secondary reload class
|
||||
-- as we do here with 22 -- or not ? */
|
||||
-- as we do here with 10 -- or not ? */
|
||||
|
||||
int
|
||||
pdp11_register_move_cost (enum reg_class c1, enum reg_class c2)
|
||||
static int
|
||||
pdp11_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
|
||||
reg_class_t c1, reg_class_t c2)
|
||||
{
|
||||
return move_costs[(int)c1][(int)c2];
|
||||
}
|
||||
|
@ -1634,6 +1645,108 @@ legitimate_const_double_p (rtx address)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Implement CANNOT_CHANGE_MODE_CLASS. */
|
||||
bool
|
||||
pdp11_cannot_change_mode_class (enum machine_mode from,
|
||||
enum machine_mode to,
|
||||
enum reg_class rclass)
|
||||
{
|
||||
/* Also, FPU registers contain a whole float value and the parts of
|
||||
it are not separately accessible.
|
||||
|
||||
So we disallow all mode changes involving FPRs. */
|
||||
if (FLOAT_MODE_P (from) != FLOAT_MODE_P (to))
|
||||
return true;
|
||||
|
||||
return reg_classes_intersect_p (FPU_REGS, rclass);
|
||||
}
|
||||
|
||||
/* TARGET_PREFERRED_RELOAD_CLASS
|
||||
|
||||
Given an rtx X being reloaded into a reg required to be
|
||||
in class CLASS, return the class of reg to actually use.
|
||||
In general this is just CLASS; but on some machines
|
||||
in some cases it is preferable to use a more restrictive class.
|
||||
|
||||
loading is easier into LOAD_FPU_REGS than FPU_REGS! */
|
||||
|
||||
static reg_class_t
|
||||
pdp11_preferred_reload_class (rtx x, reg_class_t class)
|
||||
{
|
||||
if (class == FPU_REGS)
|
||||
return LOAD_FPU_REGS;
|
||||
if (class == ALL_REGS)
|
||||
{
|
||||
if (FLOAT_MODE_P (GET_MODE (x)))
|
||||
return LOAD_FPU_REGS;
|
||||
else
|
||||
return GENERAL_REGS;
|
||||
}
|
||||
return class;
|
||||
}
|
||||
|
||||
/* TARGET_PREFERRED_OUTPUT_RELOAD_CLASS
|
||||
|
||||
Given an rtx X being reloaded into a reg required to be
|
||||
in class CLASS, return the class of reg to actually use.
|
||||
In general this is just CLASS; but on some machines
|
||||
in some cases it is preferable to use a more restrictive class.
|
||||
|
||||
loading is easier into LOAD_FPU_REGS than FPU_REGS! */
|
||||
|
||||
static reg_class_t
|
||||
pdp11_preferred_output_reload_class (rtx x, reg_class_t class)
|
||||
{
|
||||
if (class == FPU_REGS)
|
||||
return LOAD_FPU_REGS;
|
||||
if (class == ALL_REGS)
|
||||
{
|
||||
if (FLOAT_MODE_P (GET_MODE (x)))
|
||||
return LOAD_FPU_REGS;
|
||||
else
|
||||
return GENERAL_REGS;
|
||||
}
|
||||
return class;
|
||||
}
|
||||
|
||||
|
||||
/* TARGET_SECONDARY_RELOAD.
|
||||
|
||||
FPU registers AC4 and AC5 (class NO_LOAD_FPU_REGS) require an
|
||||
intermediate register (AC0-AC3: LOAD_FPU_REGS). Everything else
|
||||
can be loade/stored directly. */
|
||||
reg_class_t
|
||||
pdp11_secondary_reload (bool in_p ATTRIBUTE_UNUSED,
|
||||
rtx x,
|
||||
reg_class_t reload_class,
|
||||
enum machine_mode reload_mode ATTRIBUTE_UNUSED,
|
||||
secondary_reload_info *sri ATTRIBUTE_UNUSED)
|
||||
{
|
||||
if (reload_class != NO_LOAD_FPU_REGS || GET_CODE (x) != REG ||
|
||||
REGNO_REG_CLASS (REGNO (x)) == LOAD_FPU_REGS)
|
||||
return NO_REGS;
|
||||
|
||||
return LOAD_FPU_REGS;
|
||||
}
|
||||
|
||||
/* Target routine to check if register to register move requires memory.
|
||||
|
||||
The answer is yes if we're going between general register and FPU
|
||||
registers. The mode doesn't matter in making this check.
|
||||
*/
|
||||
bool
|
||||
pdp11_secondary_memory_needed (reg_class_t c1, reg_class_t c2,
|
||||
enum machine_mode mode ATTRIBUTE_UNUSED)
|
||||
{
|
||||
int fromfloat = (c1 == LOAD_FPU_REGS || c1 == NO_LOAD_FPU_REGS ||
|
||||
c1 == FPU_REGS);
|
||||
int tofloat = (c2 == LOAD_FPU_REGS || c2 == NO_LOAD_FPU_REGS ||
|
||||
c2 == FPU_REGS);
|
||||
|
||||
return (fromfloat != tofloat);
|
||||
}
|
||||
|
||||
|
||||
/* A copy of output_addr_const modified for pdp11 expression syntax.
|
||||
output_addr_const also gets called for %cDIGIT and %nDIGIT, which we don't
|
||||
use, and for debugging output, which we don't support with this port either.
|
||||
|
@ -1751,7 +1864,7 @@ pdp11_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
|
|||
ac0 if DFmode and FPU present - compatibility problem with
|
||||
libraries for non-floating point.... */
|
||||
return (TYPE_MODE (type) == DImode
|
||||
|| (TYPE_MODE (type) == DFmode && ! TARGET_AC0));
|
||||
|| (FLOAT_MODE_P (TYPE_MODE (type)) && ! TARGET_AC0));
|
||||
}
|
||||
|
||||
/* Worker function for TARGET_FUNCTION_VALUE.
|
||||
|
@ -1854,3 +1967,5 @@ pdp11_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
|
|||
? GET_MODE_SIZE (mode)
|
||||
: int_size_in_bytes (type));
|
||||
}
|
||||
|
||||
struct gcc_target targetm = TARGET_INITIALIZER;
|
||||
|
|
|
@ -215,15 +215,19 @@ extern const struct real_format pdp11_d_format;
|
|||
|
||||
|
||||
/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
|
||||
On the pdp, the cpu registers can hold any mode - check alignment
|
||||
On the pdp, the cpu registers can hold any mode other than float
|
||||
(because otherwise we may end up being asked to move from CPU to FPU
|
||||
register, which isn't a valid operation on the PDP11).
|
||||
For CPU registers, check alignment.
|
||||
|
||||
FPU can only hold DF - simplifies life!
|
||||
FPU accepts SF and DF but actually holds a DF - simplifies life!
|
||||
*/
|
||||
#define HARD_REGNO_MODE_OK(REGNO, MODE) \
|
||||
(((REGNO) <= PC_REGNUM)? \
|
||||
((GET_MODE_BITSIZE(MODE) <= 16) \
|
||||
|| (GET_MODE_BITSIZE(MODE) >= 32 && !((REGNO) & 1))) \
|
||||
:(MODE) == DFmode)
|
||||
|| (GET_MODE_BITSIZE(MODE) >= 32 && \
|
||||
!((REGNO) & 1) && !FLOAT_MODE_P (MODE))) \
|
||||
:FLOAT_MODE_P (MODE))
|
||||
|
||||
|
||||
/* Value is 1 if it is a good idea to tie two pseudo registers
|
||||
|
@ -322,18 +326,9 @@ enum reg_class { NO_REGS, MUL_REGS, GENERAL_REGS, LOAD_FPU_REGS, NO_LOAD_FPU_REG
|
|||
|
||||
#define IRA_COVER_CLASSES { GENERAL_REGS, FPU_REGS, LIM_REG_CLASSES }
|
||||
|
||||
/* Given an rtx X being reloaded into a reg required to be
|
||||
in class CLASS, return the class of reg to actually use.
|
||||
In general this is just CLASS; but on some machines
|
||||
in some cases it is preferable to use a more restrictive class.
|
||||
|
||||
loading is easier into LOAD_FPU_REGS than FPU_REGS! */
|
||||
|
||||
#define PREFERRED_RELOAD_CLASS(X,CLASS) \
|
||||
(((CLASS) != FPU_REGS)?(CLASS):LOAD_FPU_REGS)
|
||||
|
||||
#define SECONDARY_RELOAD_CLASS(CLASS,MODE,x) \
|
||||
(((CLASS) == NO_LOAD_FPU_REGS && !(REG_P(x) && LOAD_FPU_REG_P(REGNO(x))))?LOAD_FPU_REGS:NO_REGS)
|
||||
/* Hook for testing if memory is needed for moving between registers. */
|
||||
#define SECONDARY_MEMORY_NEEDED(class1, class2, m) \
|
||||
pdp11_secondary_memory_needed (class1, class2, m)
|
||||
|
||||
/* Return the maximum number of consecutive registers
|
||||
needed to represent mode MODE in a register of class CLASS. */
|
||||
|
@ -343,6 +338,8 @@ loading is easier into LOAD_FPU_REGS than FPU_REGS! */
|
|||
1 \
|
||||
)
|
||||
|
||||
#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \
|
||||
pdp11_cannot_change_mode_class (FROM, TO, CLASS)
|
||||
|
||||
/* Stack layout; function entry, exit and calling. */
|
||||
|
||||
|
@ -386,7 +383,7 @@ extern int current_first_parm_offset;
|
|||
If the precise function being called is known, FUNC is its FUNCTION_DECL;
|
||||
otherwise, FUNC is 0. */
|
||||
#define BASE_RETURN_VALUE_REG(MODE) \
|
||||
((MODE) == DFmode ? 8 : 0)
|
||||
(FLOAT_MODE_P (MODE) ? AC0_REGNUM : RETVAL_REGNUM)
|
||||
|
||||
/* 1 if N is a possible register number for function argument passing.
|
||||
- not used on pdp */
|
||||
|
@ -674,10 +671,6 @@ extern int may_call_alloca;
|
|||
/* #define NO_FUNCTION_CSE */
|
||||
|
||||
|
||||
/* cost of moving one register class to another */
|
||||
#define REGISTER_MOVE_COST(MODE, CLASS1, CLASS2) \
|
||||
pdp11_register_move_cost (CLASS1, CLASS2)
|
||||
|
||||
/* Tell emit-rtl.c how to initialize special values on a per-function base. */
|
||||
extern struct rtx_def *cc0_reg_rtx;
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
(define_constants
|
||||
[
|
||||
;; Register numbers
|
||||
(RETVAL_REGNUM 0)
|
||||
(FRAME_POINTER_REGNUM 5)
|
||||
(STACK_POINTER_REGNUM 6)
|
||||
(PC_REGNUM 7)
|
||||
|
@ -196,7 +197,7 @@
|
|||
(define_expand "cbranchdf4"
|
||||
[(set (cc0)
|
||||
(compare (match_operand:DF 1 "general_operand")
|
||||
(match_operand:DF 2 "general_operand")))
|
||||
(match_operand:DF 2 "register_or_const0_operand")))
|
||||
(set (pc)
|
||||
(if_then_else (match_operator 0 "ordered_comparison_operator"
|
||||
[(cc0) (const_int 0)])
|
||||
|
@ -318,11 +319,9 @@
|
|||
}"
|
||||
[(set_attr "length" "2,4,4,6")])
|
||||
|
||||
;; do we have to supply all these moves? e.g. to
|
||||
;; NO_LOAD_FPU_REGs ?
|
||||
(define_insn "movdf"
|
||||
[(set (match_operand:DF 0 "general_operand" "=a,fR,a,Q,g")
|
||||
(match_operand:DF 1 "general_operand" "fFR,a,Q,a,g"))]
|
||||
[(set (match_operand:DF 0 "float_operand" "=a,fR,a,Q,g")
|
||||
(match_operand:DF 1 "float_operand" "fFR,a,Q,a,g"))]
|
||||
"TARGET_FPU"
|
||||
"* if (which_alternative ==0 || which_alternative == 2)
|
||||
return \"ldd %1, %0\";
|
||||
|
@ -334,11 +333,17 @@
|
|||
[(set_attr "length" "2,2,10,10,32")])
|
||||
|
||||
(define_insn "movsf"
|
||||
[(set (match_operand:SF 0 "general_operand" "=g,r,g")
|
||||
(match_operand:SF 1 "general_operand" "r,rmF,g"))]
|
||||
[(set (match_operand:SF 0 "float_operand" "=a,fR,a,Q,g")
|
||||
(match_operand:SF 1 "float_operand" "fFR,a,Q,a,g"))]
|
||||
"TARGET_FPU"
|
||||
"* return output_move_double (operands);"
|
||||
[(set_attr "length" "16,16,16")])
|
||||
"* if (which_alternative ==0 || which_alternative == 2)
|
||||
return \"{ldcfd|movof} %1, %0\";
|
||||
else if (which_alternative == 1 || which_alternative == 3)
|
||||
return \"{stcdf|movfo} %1, %0\";
|
||||
else
|
||||
return output_move_double (operands); "
|
||||
;; just a guess..
|
||||
[(set_attr "length" "2,2,10,10,16")])
|
||||
|
||||
;; maybe fiddle a bit with move_ratio, then
|
||||
;; let constraints only accept a register ...
|
||||
|
@ -386,15 +391,11 @@
|
|||
;;- truncation instructions
|
||||
|
||||
(define_insn "truncdfsf2"
|
||||
[(set (match_operand:SF 0 "general_operand" "=r,R,Q")
|
||||
(float_truncate:SF (match_operand:DF 1 "register_operand" "a,a,a")))]
|
||||
[(set (match_operand:SF 0 "general_operand" "=f,R,Q")
|
||||
(float_truncate:SF (match_operand:DF 1 "register_operand" "f,a,a")))]
|
||||
"TARGET_FPU"
|
||||
"* if (which_alternative ==0)
|
||||
{
|
||||
output_asm_insn(\"{stcdf|movfo} %1, -(sp)\", operands);
|
||||
output_asm_insn(\"mov (sp)+, %0\", operands);
|
||||
operands[0] = gen_rtx_REG (HImode, REGNO (operands[0])+1);
|
||||
output_asm_insn(\"mov (sp)+, %0\", operands);
|
||||
return \"\";
|
||||
}
|
||||
else if (which_alternative == 1)
|
||||
|
@ -402,7 +403,7 @@
|
|||
else
|
||||
return \"{stcdf|movfo} %1, %0\";
|
||||
"
|
||||
[(set_attr "length" "6,2,4")])
|
||||
[(set_attr "length" "0,2,4")])
|
||||
|
||||
|
||||
(define_expand "truncsihi2"
|
||||
|
@ -439,14 +440,14 @@
|
|||
;;- sign extension instructions
|
||||
|
||||
(define_insn "extendsfdf2"
|
||||
[(set (match_operand:DF 0 "register_operand" "=a,a,a")
|
||||
(float_extend:DF (match_operand:SF 1 "general_operand" "r,R,Q")))]
|
||||
[(set (match_operand:DF 0 "register_operand" "=f,a,a")
|
||||
(float_extend:DF (match_operand:SF 1 "general_operand" "f,R,Q")))]
|
||||
"TARGET_FPU"
|
||||
"@
|
||||
mov %1, -(sp)\;{ldcfd|movof} (sp)+,%0
|
||||
/* nothing */
|
||||
{ldcfd|movof} %1, %0
|
||||
{ldcfd|movof} %1, %0"
|
||||
[(set_attr "length" "4,2,4")])
|
||||
[(set_attr "length" "0,2,4")])
|
||||
|
||||
;; does movb sign extend in register-to-register move?
|
||||
(define_insn "extendqihi2"
|
||||
|
@ -856,6 +857,7 @@
|
|||
}"
|
||||
[(set_attr "length" "4,8,8,12,4,4,8,6,6,12")])
|
||||
|
||||
;; FIXME This definition is wrong, PR/41822
|
||||
(define_insn "andhi3"
|
||||
[(set (match_operand:HI 0 "general_operand" "=rR,rR,Q,Q")
|
||||
(and:HI (match_operand:HI 1 "general_operand" "0,0,0,0")
|
||||
|
|
|
@ -35,3 +35,12 @@
|
|||
sh = INTVAL (op);
|
||||
return (abs (sh) > 1 && abs (sh) <= 4);
|
||||
})
|
||||
|
||||
;; Accept anything general-operand accepts, except that registers must
|
||||
;; be FPU registers.
|
||||
(define_predicate "float_operand"
|
||||
(if_then_else (match_code "reg")
|
||||
(ior
|
||||
(match_test "REGNO_REG_CLASS (REGNO (op)) == LOAD_FPU_REGS")
|
||||
(match_test "REGNO_REG_CLASS (REGNO (op)) == NO_LOAD_FPU_REGS"))
|
||||
(match_test "general_operand (op, mode)")))
|
||||
|
|
Loading…
Add table
Reference in a new issue