📄 ia64.md
字号:
If op0 is a register, then we spill op1, so that we now have a MEM operand. This requires creating an XFmode subreg of a TImode reg to force the spill. */ if (register_operand (operands[0], XFmode)) { rtx op1 = gen_rtx_REG (TImode, REGNO (operands[1])); op1 = gen_rtx_SUBREG (XFmode, op1, 0); operands[1] = spill_xfmode_operand (op1, 0); } else if (GET_CODE (operands[0]) == MEM) { rtx in[2]; in[WORDS_BIG_ENDIAN] = gen_rtx_REG (DImode, REGNO (operands[1])); in[!WORDS_BIG_ENDIAN] = gen_rtx_REG (DImode, REGNO (operands[1]) + 1); emit_move_insn (adjust_address (operands[0], DImode, 0), in[0]); emit_move_insn (adjust_address (operands[0], DImode, 8), in[1]); DONE; } else abort (); } if (! reload_in_progress && ! reload_completed) { operands[1] = spill_xfmode_operand (operands[1], 0); if (GET_MODE (op0) == TImode && GET_CODE (op0) == REG) { rtx memt, memx, in = operands[1]; if (CONSTANT_P (in)) in = validize_mem (force_const_mem (XFmode, in)); if (GET_CODE (in) == MEM) memt = adjust_address (in, TImode, 0); else { memt = assign_stack_temp (TImode, 16, 0); memx = adjust_address (memt, XFmode, 0); emit_move_insn (memx, in); } emit_move_insn (op0, memt); DONE; } if (! ia64_move_ok (operands[0], operands[1])) operands[1] = force_reg (XFmode, operands[1]); }});; ??? There's no easy way to mind volatile acquire/release semantics.(define_insn "*movxf_internal" [(set (match_operand:XF 0 "destination_operand" "=f,f, m") (match_operand:XF 1 "general_operand" "fG,m,fG"))] "ia64_move_ok (operands[0], operands[1])" "@ mov %0 = %F1 ldfe %0 = %1%P1 stfe %0 = %F1%P0" [(set_attr "itanium_class" "fmisc,fld,stf")]);; Better code generation via insns that deal with TFmode register pairs;; directly. Same concerns apply as for TImode.(define_expand "movtf" [(set (match_operand:TF 0 "general_operand" "") (match_operand:TF 1 "general_operand" ""))] ""{ rtx op1 = ia64_expand_move (operands[0], operands[1]); if (!op1) DONE; operands[1] = op1;})(define_insn_and_split "*movtf_internal" [(set (match_operand:TF 0 "destination_operand" "=r,r,m") (match_operand:TF 1 "general_operand" "ri,m,r"))] "ia64_move_ok (operands[0], operands[1])" "#" "reload_completed" [(const_int 0)]{ ia64_split_tmode_move (operands); DONE;} [(set_attr "itanium_class" "unknown") (set_attr "predicable" "no")]);; ::::::::::::::::::::;; ::;; :: Conversions;; ::;; ::::::::::::::::::::;; Signed conversions from a smaller integer to a larger integer(define_insn "extendqidi2" [(set (match_operand:DI 0 "gr_register_operand" "=r") (sign_extend:DI (match_operand:QI 1 "gr_register_operand" "r")))] "" "sxt1 %0 = %1" [(set_attr "itanium_class" "xtd")])(define_insn "extendhidi2" [(set (match_operand:DI 0 "gr_register_operand" "=r") (sign_extend:DI (match_operand:HI 1 "gr_register_operand" "r")))] "" "sxt2 %0 = %1" [(set_attr "itanium_class" "xtd")])(define_insn "extendsidi2" [(set (match_operand:DI 0 "grfr_register_operand" "=r,?f") (sign_extend:DI (match_operand:SI 1 "grfr_register_operand" "r,f")))] "" "@ sxt4 %0 = %1 fsxt.r %0 = %1, %1" [(set_attr "itanium_class" "xtd,fmisc")]);; Unsigned conversions from a smaller integer to a larger integer(define_insn "zero_extendqidi2" [(set (match_operand:DI 0 "gr_register_operand" "=r,r") (zero_extend:DI (match_operand:QI 1 "gr_nonimmediate_operand" "r,m")))] "" "@ zxt1 %0 = %1 ld1%O1 %0 = %1%P1" [(set_attr "itanium_class" "xtd,ld")])(define_insn "zero_extendhidi2" [(set (match_operand:DI 0 "gr_register_operand" "=r,r") (zero_extend:DI (match_operand:HI 1 "gr_nonimmediate_operand" "r,m")))] "" "@ zxt2 %0 = %1 ld2%O1 %0 = %1%P1" [(set_attr "itanium_class" "xtd,ld")])(define_insn "zero_extendsidi2" [(set (match_operand:DI 0 "grfr_register_operand" "=r,r,?f") (zero_extend:DI (match_operand:SI 1 "grfr_nonimmediate_operand" "r,m,f")))] "" "@ addp4 %0 = %1, r0 ld4%O1 %0 = %1%P1 fmix.r %0 = f0, %1" [(set_attr "itanium_class" "ialu,ld,fmisc")]);; Convert between floating point types of different sizes.;; At first glance, it would appear that emitting fnorm for an extending;; conversion is unnecessary. However, the stf and getf instructions work;; correctly only if the input is properly rounded for its type. In;; particular, we get the wrong result for getf.d/stfd if the input is a;; denorm single. Since we don't know what the next instruction will be, we;; have to emit an fnorm.;; ??? Optimization opportunity here. Get rid of the insn altogether;; when we can. Should probably use a scheme like has been proposed;; for ia32 in dealing with operands that match unary operators. This;; would let combine merge the thing into adjacent insns. See also how the;; mips port handles SIGN_EXTEND as operands to integer arithmetic insns via;; se_register_operand.(define_insn "extendsfdf2" [(set (match_operand:DF 0 "fr_register_operand" "=f") (float_extend:DF (match_operand:SF 1 "fr_register_operand" "f")))] "" "fnorm.d %0 = %1" [(set_attr "itanium_class" "fmac")])(define_insn "extendsfxf2" [(set (match_operand:XF 0 "fr_register_operand" "=f") (float_extend:XF (match_operand:SF 1 "fr_register_operand" "f")))] "" "fnorm %0 = %1" [(set_attr "itanium_class" "fmac")])(define_insn "extenddfxf2" [(set (match_operand:XF 0 "fr_register_operand" "=f") (float_extend:XF (match_operand:DF 1 "fr_register_operand" "f")))] "" "fnorm %0 = %1" [(set_attr "itanium_class" "fmac")])(define_insn "truncdfsf2" [(set (match_operand:SF 0 "fr_register_operand" "=f") (float_truncate:SF (match_operand:DF 1 "fr_register_operand" "f")))] "" "fnorm.s %0 = %1" [(set_attr "itanium_class" "fmac")])(define_insn "truncxfsf2" [(set (match_operand:SF 0 "fr_register_operand" "=f") (float_truncate:SF (match_operand:XF 1 "fr_register_operand" "f")))] "" "fnorm.s %0 = %1" [(set_attr "itanium_class" "fmac")])(define_insn "truncxfdf2" [(set (match_operand:DF 0 "fr_register_operand" "=f") (float_truncate:DF (match_operand:XF 1 "fr_register_operand" "f")))] "" "fnorm.d %0 = %1" [(set_attr "itanium_class" "fmac")]);; Convert between signed integer types and floating point.(define_insn "floatdixf2" [(set (match_operand:XF 0 "fr_register_operand" "=f") (float:XF (match_operand:DI 1 "fr_register_operand" "f")))] "" "fcvt.xf %0 = %1" [(set_attr "itanium_class" "fcvtfx")])(define_insn "fix_truncsfdi2" [(set (match_operand:DI 0 "fr_register_operand" "=f") (fix:DI (match_operand:SF 1 "fr_register_operand" "f")))] "" "fcvt.fx.trunc %0 = %1" [(set_attr "itanium_class" "fcvtfx")])(define_insn "fix_truncdfdi2" [(set (match_operand:DI 0 "fr_register_operand" "=f") (fix:DI (match_operand:DF 1 "fr_register_operand" "f")))] "" "fcvt.fx.trunc %0 = %1" [(set_attr "itanium_class" "fcvtfx")])(define_insn "fix_truncxfdi2" [(set (match_operand:DI 0 "fr_register_operand" "=f") (fix:DI (match_operand:XF 1 "fr_register_operand" "f")))] "" "fcvt.fx.trunc %0 = %1" [(set_attr "itanium_class" "fcvtfx")])(define_insn "fix_truncxfdi2_alts" [(set (match_operand:DI 0 "fr_register_operand" "=f") (fix:DI (match_operand:XF 1 "fr_register_operand" "f"))) (use (match_operand:SI 2 "const_int_operand" ""))] "" "fcvt.fx.trunc.s%2 %0 = %1" [(set_attr "itanium_class" "fcvtfx")]);; Convert between unsigned integer types and floating point.(define_insn "floatunsdisf2" [(set (match_operand:SF 0 "fr_register_operand" "=f") (unsigned_float:SF (match_operand:DI 1 "fr_register_operand" "f")))] "" "fcvt.xuf.s %0 = %1" [(set_attr "itanium_class" "fcvtfx")])(define_insn "floatunsdidf2" [(set (match_operand:DF 0 "fr_register_operand" "=f") (unsigned_float:DF (match_operand:DI 1 "fr_register_operand" "f")))] "" "fcvt.xuf.d %0 = %1" [(set_attr "itanium_class" "fcvtfx")])(define_insn "floatunsdixf2" [(set (match_operand:XF 0 "fr_register_operand" "=f") (unsigned_float:XF (match_operand:DI 1 "fr_register_operand" "f")))] "" "fcvt.xuf %0 = %1" [(set_attr "itanium_class" "fcvtfx")])(define_insn "fixuns_truncsfdi2" [(set (match_operand:DI 0 "fr_register_operand" "=f") (unsigned_fix:DI (match_operand:SF 1 "fr_register_operand" "f")))] "" "fcvt.fxu.trunc %0 = %1" [(set_attr "itanium_class" "fcvtfx")])(define_insn "fixuns_truncdfdi2" [(set (match_operand:DI 0 "fr_register_operand" "=f") (unsigned_fix:DI (match_operand:DF 1 "fr_register_operand" "f")))] "" "fcvt.fxu.trunc %0 = %1" [(set_attr "itanium_class" "fcvtfx")])(define_insn "fixuns_truncxfdi2" [(set (match_operand:DI 0 "fr_register_operand" "=f") (unsigned_fix:DI (match_operand:XF 1 "fr_register_operand" "f")))] "" "fcvt.fxu.trunc %0 = %1" [(set_attr "itanium_class" "fcvtfx")])(define_insn "fixuns_truncxfdi2_alts" [(set (match_operand:DI 0 "fr_register_operand" "=f") (unsigned_fix:DI (match_operand:XF 1 "fr_register_operand" "f"))) (use (match_operand:SI 2 "const_int_operand" ""))] "" "fcvt.fxu.trunc.s%2 %0 = %1" [(set_attr "itanium_class" "fcvtfx")]);; ::::::::::::::::::::;; ::;; :: Bit field extraction;; ::;; ::::::::::::::::::::(define_insn "extv" [(set (match_operand:DI 0 "gr_register_operand" "=r") (sign_extract:DI (match_operand:DI 1 "gr_register_operand" "r") (match_operand:DI 2 "const_int_operand" "n") (match_operand:DI 3 "const_int_operand" "n")))] "" "extr %0 = %1, %3, %2" [(set_attr "itanium_class" "ishf")])(define_insn "extzv" [(set (match_operand:DI 0 "gr_register_operand" "=r") (zero_extract:DI (match_operand:DI 1 "gr_register_operand" "r") (match_operand:DI 2 "const_int_operand" "n") (match_operand:DI 3 "const_int_operand" "n")))] "" "extr.u %0 = %1, %3, %2" [(set_attr "itanium_class" "ishf")]);; Insert a bit field.;; Can have 3 operands, source1 (inserter), source2 (insertee), dest.;; Source1 can be 0 or -1.;; Source2 can be 0.;; ??? Actual dep instruction is more powerful than what these insv;; patterns support. Unfortunately, combine is unable to create patterns;; where source2 != dest.(define_expand "insv" [(set (zero_extract:DI (match_operand:DI 0 "gr_register_operand" "") (match_operand:DI 1 "const_int_operand" "") (match_operand:DI 2 "const_int_operand" "")) (match_operand:DI 3 "nonmemory_operand" ""))] ""{ int width = INTVAL (operands[1]); int shift = INTVAL (operands[2]); /* If operand[3] is a constant, and isn't 0 or -1, then load it into a pseudo. */ if (! register_operand (operands[3], DImode) && operands[3] != const0_rtx && operands[3] != constm1_rtx) operands[3] = force_reg (DImode, operands[3]); /* If this is a single dep instruction, we have nothing to do. */ if (! ((register_operand (operands[3], DImode) && width <= 16) || operands[3] == const0_rtx || operands[3] == constm1_rtx)) { /* Check for cases that can be implemented with a mix instruction. */ if (width == 32 && shift == 0) { /* Directly generating the mix4left instruction confuses optimize_bit_field in function.c. Since this is performing a useful optimization, we defer generation of the complicated mix4left RTL to the first splitting phase. */ rtx tmp = gen_reg_rtx (DImode); emit_insn (gen_shift_mix4left (operands[0], operands[3], tmp)); DONE; } else if (width == 32 && shift == 32) { emit_insn (gen_mix4right (operands[0], operands[3])); DONE; } /* We could handle remaining cases by emitting multiple dep instructions. If we need more than two dep instructions then we lose. A 6 insn sequence mov mask1,mov mask2,shl;;and,and;;or is better than mov;;dep,shr;;dep,shr;;dep. The former can be executed in 3 cycles, the latter is 6 cycles on an Itanium (TM) processor, because there is only one function unit that can execute dep and shr immed. If we only need two dep instruction, then we still lose. mov;;dep,shr;;dep is still 4 cycles. Even if we optimize away the unnecessary mov, this is still undesirable because it will be hard to optimize, and it creates unnecessary pressure on the I0 function unit. */ FAIL;#if 0 /* This code may be useful for other IA-64 processors, so we leave it in for now. */ while (width > 16) { rtx tmp; emit_insn (gen_insv (operands[0], GEN_INT (16), GEN_INT (shift), operands[3])); shift += 16; width -= 16; tmp = gen_reg_rtx (DImode); emit_insn (gen_lshrdi3 (tmp, operands[3], GEN_INT (16))); operands[3] = tmp; } operands[1] = GEN_INT (width);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -