📄 i370.md
字号:
;;- Machine description for GNU compiler -- System/370 version.;; Copyright (C) 1989, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2002;; Free Software Foundation, Inc.;; Contributed by Jan Stein (jan@cd.chalmers.se).;; Modified for OS/390 LanguageEnvironment C by Dave Pitts (dpitts@cozx.com);; Lots of Bug Fixes & Enhancements by Linas Vepstas (linas@linas.org);; This file is part of GNU CC.;; GNU CC is free software; you can redistribute it and/or modify;; it under the terms of the GNU General Public License as published by;; the Free Software Foundation; either version 2, or (at your option);; any later version.;; GNU CC is distributed in the hope that it will be useful,;; but WITHOUT ANY WARRANTY; without even the implied warranty of;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the;; GNU General Public License for more details.;; You should have received a copy of the GNU General Public License;; along with GNU CC; see the file COPYING. If not, write to;; the Free Software Foundation, 59 Temple Place - Suite 330,;; Boston, MA 02111-1307, USA.;; =======================================================================;; Condition codes for some of the instructions (in particular, for ;; add, sub, shift, abs, etc. are handled with the cpp macro NOTICE_UPDATE_CC ;;;; Special constraints for 370 machine description:;;;; a -- Any address register from 1 to 15.;; d -- Any register from 0 to 15.;; I -- An 8-bit constant (0..255).;; J -- A 12-bit constant (0..4095).;; K -- A 16-bit constant (-32768..32767).;; R -- a valid S operand in an RS, SI or SS instruction, or register;; S -- a valid S operand in an RS, SI or SS instruction;;;; Note this well: ;; When defining an instruction, e.g. the movsi pattern:;; ;; (define_insn "";; [(set (match_operand:SI 0 "r_or_s_operand" "=dm,d,dm");; (match_operand:SI 1 "r_or_s_operand" "diR,dim,*fF"))];;;; The "r_or_s_operand" predicate is used to recognize the instruction;;; however, it is not further used to enforce a constraint at later stages.;; Thus, for example, although "r_or_s_operand" bars operands of the form;; base+index+displacement, such operands can none-the-less show up during;; post-instruction-recog processing: thus, for example, garbage like;; MVC 152(4,r13),0(r5,r13) might be generated if both op0 and op1 are ;; mem operands. To avoid this, use the S constraint.;; ;;;; Special formats used for outputting 370 instructions.;;;; %B -- Print a constant byte integer.;; %H -- Print a signed 16-bit constant.;; %K -- Print a signed 16-bit constant signed-extended to 32-bits.;; %L -- Print least significant word of a CONST_DOUBLE.;; %M -- Print most significant word of a CONST_DOUBLE.;; %N -- Print next register (second word of a DImode reg).;; %O -- Print the offset of a memory reference (PLUS (REG) (CONST_INT)).;; %R -- Print the register of a memory reference (PLUS (REG) (CONST_INT)).;; %X -- Print a constant byte integer in hex.;; %W -- Print a signed 32-bit int sign-extended to 64-bits.;;;; We have a special constraint for pattern matching.;;;; s_operand -- Matches a valid S operand in a RS, SI or SS type instruction.;;;; r_or_s_operand -- Matches a register or a valid S operand in a RS, SI;; or SS type instruction or a register;;;; For MVS C/370 we use the following stack locations for:;;;; 136 - internal function result buffer;; 140 - numeric conversion buffer;; 144 - pointer to internal function result buffer;; 148 - start of automatic variables and function arguments;;;; To support programs larger than a page, 4096 bytes, PAGE_REGISTER points;; to a page origin table, all internal labels are generated to reload the;; BASE_REGISTER knowing what page it is on and all branch instructions go;; directly to the target if it is known that the target is on the current;; page (essentially backward references). All forward references and off;; page references are handled by loading the address of target into a;; register and branching indirectly.;;;; Some *di patterns have been commented out per advice from RMS, as gcc;; will generate the right things to do.;;;; See the note in i370.h about register 14, clobbering it, and optimization.;; Basically, using clobber in egcs-1.1.1 will ruin ability to optimize around;; branches, so don't do it.;;;; We use the "length" attirbute to store the max possible code size of an;; insn. We use this length to estimate the length of forward branches, to;; determine if they're on page or off.(define_attr "length" "" (const_int 0));;;;- Test instructions.;;;; tstdi instruction pattern(s).;(define_insn "tstdi" [(set (cc0) (match_operand:DI 0 "register_operand" "d"))] "" "*{ check_label_emit (); mvs_check_page (0, 4, 0); return \"SRDA %0,0\";}" [(set_attr "length" "4")]);; tstsi instruction pattern(s).;(define_insn "tstsi" [(set (cc0) (match_operand:SI 0 "register_operand" "d"))] "" "*{ check_label_emit (); mvs_check_page (0, 2, 0); return \"LTR %0,%0\";}" [(set_attr "length" "2")]);; tsthi instruction pattern(s).;(define_insn "tsthi" [(set (cc0) (match_operand:HI 0 "register_operand" "d"))] "" "*{ check_label_emit (); mvs_check_page (0, 4, 2); return \"CH %0,=H'0'\";}" [(set_attr "length" "4")]);; tstqi instruction pattern(s).;(define_insn "" [(set (cc0) (match_operand:QI 0 "r_or_s_operand" "dm"))] "unsigned_jump_follows_p (insn)" "*{ check_label_emit (); if (REG_P (operands[0])) { /* an unsigned compare to zero is always zero/not-zero... */ mvs_check_page (0, 4, 4); return \"N %0,=XL4'000000FF'\"; } mvs_check_page (0, 4, 0); return \"CLI %0,0\";}" [(set_attr "length" "4")])(define_insn "tstqi" [(set (cc0) (match_operand:QI 0 "register_operand" "d"))] "" "*{ check_label_emit (); if (unsigned_jump_follows_p (insn)) { /* an unsigned compare to zero is always zero/not-zero... */ mvs_check_page (0, 4, 4); return \"N %0,=XL4'000000FF'\"; } mvs_check_page (0, 8, 0); return \"SLL %0,24\;SRA %0,24\";}" [(set_attr "length" "8")]);; tstdf instruction pattern(s).;(define_insn "tstdf" [(set (cc0) (match_operand:DF 0 "general_operand" "f"))] "" "*{ check_label_emit (); mvs_check_page (0, 2, 0); return \"LTDR %0,%0\";}" [(set_attr "length" "2")]);; tstsf instruction pattern(s).;(define_insn "tstsf" [(set (cc0) (match_operand:SF 0 "general_operand" "f"))] "" "*{ check_label_emit (); mvs_check_page (0, 2, 0); return \"LTER %0,%0\";}" [(set_attr "length" "2")]);;;;- Compare instructions.;;;; cmpdi instruction pattern(s).;;(define_insn "cmpdi"; [(set (cc0); (compare (match_operand:DI 0 "register_operand" "d"); (match_operand:DI 1 "general_operand" "")))]; ""; "*;{; check_label_emit ();; if (REG_P (operands[1])); {; mvs_check_page (0, 8, 0);; if (unsigned_jump_follows_p (insn)); return \"CLR %0,%1\;BNE *+6\;CLR %N0,%N1\";; return \"CR %0,%1\;BNE *+6\;CLR %N0,%N1\";; }; mvs_check_page (0, 12, 0);; if (unsigned_jump_follows_p (insn)); return \"CL %0,%M1\;BNE *+8\;CL %N0,%L1\";; return \"C %0,%M1\;BNE *+8\;CL %N0,%L1\";;}");; cmpsi instruction pattern(s).;(define_insn "cmpsi" [(set (cc0) (compare (match_operand:SI 0 "register_operand" "d") (match_operand:SI 1 "general_operand" "md")))] "" "*{ check_label_emit (); if (REG_P (operands[1])) { mvs_check_page (0, 2, 0); if (unsigned_jump_follows_p (insn)) return \"CLR %0,%1\"; return \"CR %0,%1\"; } if (GET_CODE (operands[1]) == CONST_INT) { mvs_check_page (0, 4, 4); if (unsigned_jump_follows_p (insn)) return \"CL %0,=F'%c1'\"; return \"C %0,=F'%c1'\"; } mvs_check_page (0, 4, 0); if (unsigned_jump_follows_p (insn)) return \"CL %0,%1\"; return \"C %0,%1\";}" [(set_attr "length" "4")]);; cmphi instruction pattern(s).;; deprecate constraint d because it takes multiple instructions; and a memeory access ...(define_insn "cmphi" [(set (cc0) (compare (match_operand:HI 0 "register_operand" "d") (match_operand:HI 1 "general_operand" "???dim")))] "" "*{ check_label_emit (); if (REG_P (operands[1])) { mvs_check_page (0, 8, 0); if (unsigned_jump_follows_p (insn)) return \"STH %1,140(,13)\;CLM %0,3,140(13)\"; return \"STH %1,140(,13)\;CH %0,140(,13)\"; } if (GET_CODE (operands[1]) == CONST_INT) { mvs_check_page (0, 4, 0); return \"CH %0,%H1\"; } mvs_check_page (0, 4, 0); return \"CH %0,%1\";}" [(set_attr "length" "8")]);; cmpqi instruction pattern(s).;(define_insn "" [(set (cc0) (compare (match_operand:QI 0 "r_or_s_operand" "dS") (match_operand:QI 1 "r_or_s_operand" "diS")))] "unsigned_jump_follows_p (insn)" "*{ check_label_emit (); if (REG_P (operands[0])) { if (REG_P (operands[1])) { mvs_check_page (0, 8, 0); return \"STC %1,140(,13)\;CLM %0,1,140(13)\"; } if (GET_CODE (operands[1]) == CONST_INT) { mvs_check_page (0, 4, 1); return \"CLM %0,1,=XL1'%X1'\"; } mvs_check_page (0, 4, 0); return \"CLM %0,1,%1\"; } else if (GET_CODE (operands[0]) == CONST_INT) { cc_status.flags |= CC_REVERSED; if (REG_P (operands[1])) { mvs_check_page (0, 4, 1); return \"CLM %1,1,=XL1'%X0'\"; } mvs_check_page (0, 4, 0); return \"CLI %1,%B0\"; } if (GET_CODE (operands[1]) == CONST_INT) { mvs_check_page (0, 4, 0); return \"CLI %0,%B1\"; } if (GET_CODE (operands[1]) == MEM) { mvs_check_page (0, 6, 0); return \"CLC %O0(1,%R0),%1\"; } cc_status.flags |= CC_REVERSED; mvs_check_page (0, 4, 0); return \"CLM %1,1,%0\";}" [(set_attr "length" "8")])(define_insn "cmpqi" [(set (cc0) (compare (match_operand:QI 0 "register_operand" "d") (match_operand:QI 1 "general_operand" "di")))] "" "*{ check_label_emit (); if (unsigned_jump_follows_p (insn)) { if (GET_CODE (operands[1]) == CONST_INT) { mvs_check_page (0, 4, 1); return \"CLM %0,1,=XL1'%X1'\"; } if (!(REG_P (operands[1]))) { mvs_check_page (0, 4, 0); return \"CLM %0,1,%1\"; } mvs_check_page (0, 8, 0); return \"STC %1,140(,13)\;CLM %0,1,140(13)\"; } if (REG_P (operands[1])) { mvs_check_page (0, 18, 0); return \"SLL %0,24\;SRA %0,24\;SLL %1,24\;SRA %1,24\;CR %0,%1\"; } mvs_check_page (0, 12, 0); return \"SLL %0,24\;SRA %0,24\;C %0,%1\";}" [(set_attr "length" "18")]);; cmpdf instruction pattern(s).;(define_insn "cmpdf" [(set (cc0) (compare (match_operand:DF 0 "general_operand" "f,mF") (match_operand:DF 1 "general_operand" "fmF,f")))] "" "*{ check_label_emit (); if (FP_REG_P (operands[0])) { if (FP_REG_P (operands[1])) { mvs_check_page (0, 2, 0); return \"CDR %0,%1\"; } mvs_check_page (0, 4, 0); return \"CD %0,%1\"; } cc_status.flags |= CC_REVERSED; mvs_check_page (0, 4, 0); return \"CD %1,%0\";}" [(set_attr "length" "4")]);; cmpsf instruction pattern(s).;(define_insn "cmpsf" [(set (cc0) (compare (match_operand:SF 0 "general_operand" "f,mF") (match_operand:SF 1 "general_operand" "fmF,f")))] "" "*{check_label_emit (); if (FP_REG_P (operands[0])) { if (FP_REG_P (operands[1])) { mvs_check_page (0, 2, 0); return \"CER %0,%1\"; } mvs_check_page (0, 4, 0); return \"CE %0,%1\"; } cc_status.flags |= CC_REVERSED; mvs_check_page (0, 4, 0); return \"CE %1,%0\";}" [(set_attr "length" "4")]);; cmpmemsi instruction pattern(s).;(define_expand "cmpmemsi" [(set (match_operand:SI 0 "general_operand" "") (compare (match_operand:BLK 1 "general_operand" "") (match_operand:BLK 2 "general_operand" ""))) (use (match_operand:SI 3 "general_operand" "")) (use (match_operand:SI 4 "" ""))] "" "{ rtx op1, op2; op1 = XEXP (operands[1], 0); if (GET_CODE (op1) == REG || (GET_CODE (op1) == PLUS && GET_CODE (XEXP (op1, 0)) == REG && GET_CODE (XEXP (op1, 1)) == CONST_INT && (unsigned) INTVAL (XEXP (op1, 1)) < 4096)) { op1 = operands[1]; } else { op1 = gen_rtx_MEM (BLKmode, copy_to_mode_reg (SImode, op1)); } op2 = XEXP (operands[2], 0); if (GET_CODE (op2) == REG || (GET_CODE (op2) == PLUS && GET_CODE (XEXP (op2, 0)) == REG && GET_CODE (XEXP (op2, 1)) == CONST_INT && (unsigned) INTVAL (XEXP (op2, 1)) < 4096)) { op2 = operands[2]; } else { op2 = gen_rtx_MEM (BLKmode, copy_to_mode_reg (SImode, op2)); } if (GET_CODE (operands[3]) == CONST_INT && INTVAL (operands[3]) < 256) { emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, gen_rtx_SET (VOIDmode, operands[0], gen_rtx_COMPARE (VOIDmode, op1, op2)), gen_rtx_USE (VOIDmode, operands[3])))); } else { /* implementation suggested by Richard Henderson <rth@cygnus.com> */ rtx reg1 = gen_reg_rtx (DImode); rtx reg2 = gen_reg_rtx (DImode); rtx result = operands[0]; rtx mem1 = operands[1]; rtx mem2 = operands[2]; rtx len = operands[3]; if (!CONSTANT_P (len)) len = force_reg (SImode, len); /* Load up the address+length pairs. */ emit_insn (gen_rtx_CLOBBER (VOIDmode, reg1)); emit_move_insn (gen_rtx_SUBREG (SImode, reg1, 0), force_operand (XEXP (mem1, 0), NULL_RTX)); emit_move_insn (gen_rtx_SUBREG (SImode, reg1, GET_MODE_SIZE (SImode)), len); emit_insn (gen_rtx_CLOBBER (VOIDmode, reg2)); emit_move_insn (gen_rtx_SUBREG (SImode, reg2, 0), force_operand (XEXP (mem2, 0), NULL_RTX));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -