📄 mmix.md
字号:
;; FIXME: Perhaps a peep2 changing CCcode to a new code, that;; gets folded here.(define_insn "*cmpcc_folded" [(set (match_operand:CC 0 "register_operand" "=r") (compare:CC (match_operand:DI 1 "register_operand" "r") (const_int 0)))] ;; FIXME: Can we test equivalence any other way? ;; FIXME: Can we fold any other way? "REGNO (operands[1]) == REGNO (operands[0])" "%% folded: cmp %0,%1,0")(define_insn "*cmpcc" [(set (match_operand:CC 0 "register_operand" "=r") (compare:CC (match_operand:DI 1 "register_operand" "r") (match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))] "" "CMP %0,%1,%2")(define_insn "*cmpu" [(set (match_operand:CC_UNS 0 "register_operand" "=r") (compare:CC_UNS (match_operand:DI 1 "register_operand" "r") (match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))] "" "CMPU %0,%1,%2")(define_insn "*fcmp" [(set (match_operand:CC_FP 0 "register_operand" "=r") (compare:CC_FP (match_operand:DF 1 "register_operand" "r") (match_operand:DF 2 "register_operand" "r")))] "" "FCMP%e0 %0,%1,%2");; FIXME: for -mieee, add fsub %0,%1,%1\;fsub %0,%2,%2 before to;; make signalling compliant.(define_insn "*feql" [(set (match_operand:CC_FPEQ 0 "register_operand" "=r") (compare:CC_FPEQ (match_operand:DF 1 "register_operand" "r") (match_operand:DF 2 "register_operand" "r")))] "" "FEQL%e0 %0,%1,%2")(define_insn "*fun" [(set (match_operand:CC_FUN 0 "register_operand" "=r") (compare:CC_FUN (match_operand:DF 1 "register_operand" "r") (match_operand:DF 2 "register_operand" "r")))] "" "FUN%e0 %0,%1,%2");; In order to get correct rounding, we have to use SFLOT and SFLOTU for;; conversion. They do not convert to SFmode; they convert to DFmode,;; with rounding as of SFmode. They are not usable as is, but we pretend;; we have a single instruction but emit two.;; Note that this will (somewhat unexpectedly) create an inexact;; exception if rounding is necessary - has to be masked off in crt0?(define_expand "floatdisf2" [(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "=rm") (float:SF (match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI"))) ;; Let's use a DI scratch, since SF don't generally get into ;; registers. Dunno what's best; it's really a DF, but that ;; doesn't logically follow from operands in the pattern. (clobber (match_scratch:DI 2 "=&r"))])] "" "{ if (GET_CODE (operands[0]) != MEM) { rtx stack_slot; /* FIXME: This stack-slot remains even at -O3. There must be a better way. */ stack_slot = validize_mem (assign_stack_temp (SFmode, GET_MODE_SIZE (SFmode), 0)); emit_insn (gen_floatdisf2 (stack_slot, operands[1])); emit_move_insn (operands[0], stack_slot); DONE; }}")(define_insn "*floatdisf2_real" [(set (match_operand:SF 0 "memory_operand" "=m") (float:SF (match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI"))) (clobber (match_scratch:DI 2 "=&r"))] "" "SFLOT %2,%1\;STSF %2,%0")(define_expand "floatunsdisf2" [(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "=rm") (unsigned_float:SF (match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI"))) ;; Let's use a DI scratch, since SF don't generally get into ;; registers. Dunno what's best; it's really a DF, but that ;; doesn't logically follow from operands in the pattern. (clobber (scratch:DI))])] "" "{ if (GET_CODE (operands[0]) != MEM) { rtx stack_slot; /* FIXME: This stack-slot remains even at -O3. Must be a better way. */ stack_slot = validize_mem (assign_stack_temp (SFmode, GET_MODE_SIZE (SFmode), 0)); emit_insn (gen_floatunsdisf2 (stack_slot, operands[1])); emit_move_insn (operands[0], stack_slot); DONE; }}")(define_insn "*floatunsdisf2_real" [(set (match_operand:SF 0 "memory_operand" "=m") (unsigned_float:SF (match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI"))) (clobber (match_scratch:DI 2 "=&r"))] "" "SFLOTU %2,%1\;STSF %2,%0");; Note that this will (somewhat unexpectedly) create an inexact;; exception if rounding is necessary - has to be masked off in crt0?(define_insn "floatdidf2" [(set (match_operand:DF 0 "register_operand" "=r") (float:DF (match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI")))] "" "FLOT %0,%1")(define_insn "floatunsdidf2" [(set (match_operand:DF 0 "register_operand" "=r") (unsigned_float:DF (match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI")))] "" "FLOTU %0,%1")(define_insn "ftruncdf2" [(set (match_operand:DF 0 "register_operand" "=r") (fix:DF (match_operand:DF 1 "register_operand" "r")))] "" ;; ROUND_OFF "FINT %0,1,%1");; Note that this will (somewhat unexpectedly) create an inexact;; exception if rounding is necessary - has to be masked off in crt0?(define_insn "fix_truncdfdi2" [(set (match_operand:DI 0 "register_operand" "=r") (fix:DI (fix:DF (match_operand:DF 1 "register_operand" "r"))))] "" ;; ROUND_OFF "FIX %0,1,%1")(define_insn "fixuns_truncdfdi2" [(set (match_operand:DI 0 "register_operand" "=r") (unsigned_fix:DI (fix:DF (match_operand:DF 1 "register_operand" "r"))))] "" ;; ROUND_OFF "FIXU %0,1,%1");; It doesn't seem like it's possible to have memory_operand as a;; predicate here (testcase: libgcc2 floathisf). FIXME: Shouldn't it be;; possible to do that? Bug in GCC? Anyway, this used to be a simple;; pattern with a memory_operand predicate, but was split up with a;; define_expand with the old pattern as "anonymous".;; FIXME: Perhaps with SECONDARY_MEMORY_NEEDED?(define_expand "truncdfsf2" [(set (match_operand:SF 0 "memory_operand" "") (float_truncate:SF (match_operand:DF 1 "register_operand" "")))] "" "{ if (GET_CODE (operands[0]) != MEM) { /* FIXME: There should be a way to say: 'put this in operands[0] but *after* the expanded insn'. */ rtx stack_slot; /* There is no sane destination but a register here, if it wasn't already MEM. (It's too hard to get fatal_insn to work here.) */ if (! REG_P (operands[0])) internal_error (\"MMIX Internal: Bad truncdfsf2 expansion\"); /* FIXME: This stack-slot remains even at -O3. Must be a better way. */ stack_slot = validize_mem (assign_stack_temp (SFmode, GET_MODE_SIZE (SFmode), 0)); emit_insn (gen_truncdfsf2 (stack_slot, operands[1])); emit_move_insn (operands[0], stack_slot); DONE; }}")(define_insn "*truncdfsf2_real" [(set (match_operand:SF 0 "memory_operand" "=m") (float_truncate:SF (match_operand:DF 1 "register_operand" "r")))] "" "STSF %1,%0");; Same comment as for truncdfsf2.(define_expand "extendsfdf2" [(set (match_operand:DF 0 "register_operand" "=r") (float_extend:DF (match_operand:SF 1 "memory_operand" "m")))] "" "{ if (GET_CODE (operands[1]) != MEM) { rtx stack_slot; /* There is no sane destination but a register here, if it wasn't already MEM. (It's too hard to get fatal_insn to work here.) */ if (! REG_P (operands[0])) internal_error (\"MMIX Internal: Bad extendsfdf2 expansion\"); /* FIXME: This stack-slot remains even at -O3. There must be a better way. */ stack_slot = validize_mem (assign_stack_temp (SFmode, GET_MODE_SIZE (SFmode), 0)); emit_move_insn (stack_slot, operands[1]); emit_insn (gen_extendsfdf2 (operands[0], stack_slot)); DONE; }}")(define_insn "*extendsfdf2_real" [(set (match_operand:DF 0 "register_operand" "=r") (float_extend:DF (match_operand:SF 1 "memory_operand" "m")))] "" "LDSF %0,%1");; Neither sign-extend nor zero-extend are necessary; gcc knows how to;; synthesize using shifts or and, except with a memory source and not;; completely optimal. FIXME: Actually, other bugs surface when those;; patterns are defined; fix later.;; There are no sane values with the bit-patterns of (int) 0..255 except;; 0 to use in movdfcc.(define_expand "movdfcc" [(set (match_operand:DF 0 "register_operand" "") (if_then_else:DF (match_operand 1 "comparison_operator" "") (match_operand:DF 2 "mmix_reg_or_0_operand" "") (match_operand:DF 3 "mmix_reg_or_0_operand" "")))] "" "{ enum rtx_code code = GET_CODE (operands[1]); rtx cc_reg = mmix_gen_compare_reg (code, mmix_compare_op0, mmix_compare_op1); if (cc_reg == NULL_RTX) FAIL; operands[1] = gen_rtx (code, VOIDmode, cc_reg, const0_rtx);}")(define_expand "movdicc" [(set (match_operand:DI 0 "register_operand" "") (if_then_else:DI (match_operand 1 "comparison_operator" "") (match_operand:DI 2 "mmix_reg_or_8bit_operand" "") (match_operand:DI 3 "mmix_reg_or_8bit_operand" "")))] "" "{ enum rtx_code code = GET_CODE (operands[1]); rtx cc_reg = mmix_gen_compare_reg (code, mmix_compare_op0, mmix_compare_op1); if (cc_reg == NULL_RTX) FAIL; operands[1] = gen_rtx (code, VOIDmode, cc_reg, const0_rtx);}");; FIXME: Is this the right way to do "folding" of CCmode -> DImode?(define_insn "*movdicc_real_foldable" [(set (match_operand:DI 0 "register_operand" "=r,r,r,r") (if_then_else:DI (match_operator 2 "mmix_foldable_comparison_operator" [(match_operand 3 "register_operand" "r,r,r,r") (const_int 0)]) (match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI,0 ,rI,GM") (match_operand:DI 4 "mmix_reg_or_8bit_operand" "0 ,rI,GM,rI")))] "" "@ CS%d2 %0,%3,%1 CS%D2 %0,%3,%4 ZS%d2 %0,%3,%1 ZS%D2 %0,%3,%4")(define_insn "*movdicc_real" [(set (match_operand:DI 0 "register_operand" "=r ,r ,r ,r") (if_then_else:DI (match_operator 2 "mmix_comparison_operator" [(match_operand 3 "mmix_reg_cc_operand" "r ,r ,r ,r") (const_int 0)]) (match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI,0 ,rI,GM") (match_operand:DI 4 "mmix_reg_or_8bit_operand" "0 ,rI,GM,rI")))] "" "@ CS%d2 %0,%3,%1 CS%D2 %0,%3,%4 ZS%d2 %0,%3,%1 ZS%D2 %0,%3,%4")(define_insn "*movdfcc_real_foldable" [(set (match_operand:DF 0 "register_operand" "=r ,r ,r ,r") (if_then_else:DF (match_operator 2 "mmix_foldable_comparison_operator" [(match_operand 3 "register_operand" "r ,r ,r ,r") (const_int 0)]) (match_operand:DF 1 "mmix_reg_or_0_operand" "rGM,0 ,rGM,GM") (match_operand:DF 4 "mmix_reg_or_0_operand" "0 ,rGM,GM ,rGM")))] "" "@ CS%d2 %0,%3,%1 CS%D2 %0,%3,%4 ZS%d2 %0,%3,%1 ZS%D2 %0,%3,%4")(define_insn "*movdfcc_real" [(set (match_operand:DF 0 "register_operand" "=r ,r ,r ,r") (if_then_else:DF (match_operator 2 "mmix_comparison_operator" [(match_operand 3 "mmix_reg_cc_operand" "r ,r ,r ,r") (const_int 0)]) (match_operand:DF 1 "mmix_reg_or_0_operand" "rGM,0 ,rGM,GM") (match_operand:DF 4 "mmix_reg_or_0_operand" "0 ,rGM,GM ,rGM")))] "" "@ CS%d2 %0,%3,%1 CS%D2 %0,%3,%4 ZS%d2 %0,%3,%1 ZS%D2 %0,%3,%4");; FIXME: scc patterns will probably help, I just skip them;; right now. Revisit.(define_expand "beq" [(set (pc) (if_then_else (eq (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "{ operands[1] = mmix_gen_compare_reg (EQ, mmix_compare_op0, mmix_compare_op1);}")(define_expand "bne" [(set (pc) (if_then_else (ne (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "{ operands[1] = mmix_gen_compare_reg (NE, mmix_compare_op0, mmix_compare_op1);}")(define_expand "bgt" [(set (pc) (if_then_else (gt (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "{ operands[1] = mmix_gen_compare_reg (GT, mmix_compare_op0, mmix_compare_op1);}")(define_expand "ble" [(set (pc) (if_then_else (le (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "{ operands[1] = mmix_gen_compare_reg (LE, mmix_compare_op0, mmix_compare_op1); /* The head comment of optabs.c:can_compare_p says we're required to implement this, so we have to clean up the mess here. */ if (operands[1] == NULL_RTX) { /* FIXME: Watch out for sharing/unsharing of rtx:es. */ emit_jump_insn ((*bcc_gen_fctn[(int) LT]) (operands[0])); emit_jump_insn ((*bcc_gen_fctn[(int) EQ]) (operands[0])); DONE; }}")(define_expand "bge" [(set (pc) (if_then_else (ge (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "{ operands[1]
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -