+2002-02-06 Hans-Peter Nilsson <hp@bitrange.com>
+
+ Implement using "base addresses" in insn operands as default.
+ * config/mmix/mmix.c (mmix_conditional_register_usage): if
+ -mabi=gnu, modify fixed_regs to fit the GNU ABI.
+ (mmix_extra_constraint): Use 'R' to indicate that GETA should be
+ used to read the rtx value.
+ (mmix_target_asm_function_epilogue): Fix spacing.
+ (mmix_constant_address_p): Handle TARGET_BASE_ADDRESSES.
+ (mmix_legitimate_address): Ditto.
+ (mmix_encode_section_info): Set SYMBOL_REF_FLAG on rtx:es that
+ should be loaded with a GETA insn. Don't allocate needless extra
+ char for nul termination and fix misleading comment.
+ (mmix_print_operand_address): Handle constants if
+ TARGET_BASE_ADDRESSES.
+ (mmix_output_register_setting): Use base addressing if
+ TARGET_BASE_ADDRESSES and the number of insns is 3.
+ * config/mmix/t-mmix (MULTILIB_EXTRA_OPTS): New.
+ * config/mmix/mmix.md ("movdi"): Change the alternative with GETA
+ to use R as constraint, add LDA to match s.
+ * config/mmix/mmix.h (TARGET_BASE_ADDRESSES): New.
+ (TARGET_DEFAULT): Add TARGET_MASK_BASE_ADDRESSES.
+ (TARGET_SWITCHES): Add -mbase-addresses, -mno-base-addresses.
+ (FIXED_REGISTERS): Make registers $231..$246 fixed by default.
+ (MMIX_MMIXWARE_ABI_REG_ALLOC_ORDER): Move $231..$246 last, in
+ order with other fixed registers.
+ (MMIX_GNU_ABI_REG_ALLOC_ORDER): Put forward $231, in order with
+ other parameter/call-clobbered registers.
+ * doc/invoke.texi (Option Summary) <MMIX Options>: Add
+ -mbase-addresses, -mno-base-addresses.
+ (MMIX Options): Ditto.
+
2002-02-05 John David Anglin <dave@hiauly1.hia.nrc.ca>
* pa.h (PREDICATE_CODES): Add reg_before_reload_operand.
mmixware ABI. */
for (i = 15; i <= 30; i++)
call_used_regs[i] = 0;
+
+ /* "Unfix" the parameter registers. */
+ for (i = MMIX_RESERVED_GNU_ARG_0_REGNUM;
+ i < MMIX_RESERVED_GNU_ARG_0_REGNUM + MMIX_MAX_ARGS_IN_REGS;
+ i++)
+ fixed_regs[i] = 0;
}
/* Step over the ":" in special register names. */
? strict_memory_address_p (Pmode, x)
: memory_address_p (Pmode, x);
+ /* R asks whether x is to be loaded with GETA or something else. Right
+ now, only a SYMBOL_REF and LABEL_REF can fit for
+ TARGET_BASE_ADDRESSES.
+
+ Only constant symbolic addresses apply. With TARGET_BASE_ADDRESSES,
+ we just allow straight LABEL_REF or SYMBOL_REFs with SYMBOL_REF_FLAG
+ set right now; only function addresses and code labels. If we change
+ to let SYMBOL_REF_FLAG be set on other symbols, we have to check
+ inside CONST expressions. When TARGET_BASE_ADDRESSES is not in
+ effect, a "raw" constant check together with mmix_constant_address_p
+ is all that's needed; we want all constant addresses to be loaded
+ with GETA then. */
+ if (c == 'R')
+ return
+ GET_CODE (x) != CONST_INT && GET_CODE (x) != CONST_DOUBLE
+ && mmix_constant_address_p (x)
+ && (! TARGET_BASE_ADDRESSES
+ || (GET_CODE (x) == LABEL_REF
+ || (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_FLAG (x))));
+
if (GET_CODE (x) != CONST_DOUBLE || GET_MODE (x) != VOIDmode)
return 0;
value = mmix_intval (x);
/* We used to map Q->J, R->K, S->L, T->N, U->O, but we don't have to any
- more ('U' taken for address_operand). Some letters map outside of
- CONST_INT, though; we still use 'S' and 'T'. */
+ more ('U' taken for address_operand, 'R' similarly). Some letters map
+ outside of CONST_INT, though; we still use 'S' and 'T'. */
if (c == 'S')
return mmix_shiftable_wyde_value (value);
else if (c == 'T')
if (frame_pointer_needed)
stack_space_to_deallocate += 8;
- /* Make sure we don't get an unaligned stack. */
+ /* Make sure we don't get an unaligned stack. */
if ((stack_space_to_deallocate % 8) != 0)
internal_error ("stack frame not a multiple of octabyte: %d",
stack_space_to_deallocate);
/* We must exclude constant addresses that have an increment that is not a
multiple of four bytes because of restrictions of the GETA
- instruction. FIXME: No, I don't think so. Just add a constraint. */
+ instruction, unless TARGET_BASE_ADDRESSES. */
int
mmix_constant_address_p (x)
{
RTX_CODE code = GET_CODE (x);
int addend = 0;
+ /* When using "base addresses", anything constant goes. */
+ int constant_ok = TARGET_BASE_ADDRESSES != 0;
if (code == LABEL_REF || code == SYMBOL_REF)
return 1;
if (code == CONSTANT_P_RTX || code == HIGH)
/* FIXME: Don't know how to dissect these. Avoid them for now. */
- return 0;
+ return constant_ok;
switch (code)
{
case SYMBOL_REF:
return 1;
- case PLUS:
- /* Can we get a naked PLUS? */
case CONSTANT_P_RTX:
case HIGH:
- /* FIXME: Don't know how to dissect these. Avoid them for now. */
- return 0;
+ /* FIXME: Don't know how to dissect these. Avoid them for now,
+ except we know they're constants. */
+ return constant_ok;
case CONST_INT:
addend = INTVAL (x);
case CONST_DOUBLE:
if (GET_MODE (x) != VOIDmode)
/* Strange that we got here. FIXME: Check if we do. */
- return 0;
+ return constant_ok;
addend = CONST_DOUBLE_LOW (x);
break;
&& GET_MODE (x1) == VOIDmode)))
addend = mmix_intval (x1);
else
- return 0;
+ return constant_ok;
}
else
- return 0;
+ return constant_ok;
break;
default:
return 0;
}
- return (addend & 3) == 0;
+ return constant_ok || (addend & 3) == 0;
}
/* Return 1 if the address is OK, otherwise 0.
/* We only accept:
(mem reg)
(mem (plus reg reg))
- (mem (plus reg 0..255)). */
+ (mem (plus reg 0..255)).
+ unless TARGET_BASE_ADDRESSES, in which case we accept all
+ (mem constant_address) too. */
/* (mem reg) */
x2 = tem;
}
- /* (mem (plus (reg) (?))) */
+ /* (mem (plus (reg?) (?))) */
if (!REG_P (x1) || !MMIX_REG_OK (x1))
- return 0;
+ return TARGET_BASE_ADDRESSES && mmix_constant_address_p (x);
- /* (mem (plus (reg) (reg))) */
+ /* (mem (plus (reg) (reg?))) */
if (REG_P (x2) && MMIX_REG_OK (x2))
return 1;
- /* (mem (plus (reg) (0..255))) */
+ /* (mem (plus (reg) (0..255?))) */
if (GET_CODE (x2) == CONST_INT
&& CONST_OK_FOR_LETTER_P (INTVAL (x2), 'I'))
return 1;
+
+ return 0;
}
- return 0;
+ return TARGET_BASE_ADDRESSES && mmix_constant_address_p (x);
}
/* LEGITIMATE_CONSTANT_P. */
{
/* For non-visible declarations, add a "@" prefix, which we skip
when the label is output. If the label does not have this
- prefix, a ":" is output.
+ prefix, a ":" is output if -mtoplevel-symbols.
Note that this does not work for data that is declared extern and
later defined as static. If there's code in between, that code
- will refer to the extern declaration. And vice versa. Until we
- can get rid of mmixal, we have to assume that code is
- well-behaved. */
+ will refer to the extern declaration, and vice versa. This just
+ means that when -mtoplevel-symbols is in use, we can just handle
+ well-behaved ISO-compliant code. */
const char *str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
int len = strlen (str);
char *newstr;
- /* Doing as rs6000 seems safe; always use ggc. Except don't copy
- the suspected off-by-one bug.
- FIXME: Is it still there? yes 2001-08-23
- Why is the return type of ggc_alloc_string const? */
- newstr = (char *) ggc_alloc_string ("", len + 2);
+ /* Why is the return type of ggc_alloc_string const? */
+ newstr = (char *) ggc_alloc_string ("", len + 1);
strcpy (newstr + 1, str);
*newstr = '@';
XSTR (XEXP (DECL_RTL (decl), 0), 0) = newstr;
}
- /* FIXME: Later on, add SYMBOL_REF_FLAG for things that we can reach
- from here via GETA, to check in LEGITIMATE_CONSTANT_P. Needs to have
- different options for the cases where we want *all* to be assumed
- reachable via GETA, or all constant symbols, or just text symbols in
- this file, or perhaps just the constant pool. */
+ /* Set SYMBOL_REF_FLAG for things that we want to access with GETA. We
+ may need different options to reach for different things with GETA.
+ For now, functions and things we know or have been told are constant. */
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ || TREE_CONSTANT (decl)
+ || (TREE_CODE (decl) == VAR_DECL
+ && TREE_READONLY (decl)
+ && !TREE_SIDE_EFFECTS (decl)
+ && (!DECL_INITIAL (decl)
+ || TREE_CONSTANT (DECL_INITIAL (decl)))))
+ {
+ rtx rtl = (TREE_CODE_CLASS (TREE_CODE (decl)) != 'd'
+ ? TREE_CST_RTL (decl) : DECL_RTL (decl));
+ SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
+ }
}
/* STRIP_NAME_ENCODING. */
}
}
+ if (TARGET_BASE_ADDRESSES && mmix_legitimate_constant_p (x))
+ {
+ output_addr_const (stream, x);
+ return;
+ }
+
fatal_insn ("MMIX Internal: This is not a recognized address", x);
}
static const char *const higher_parts[] = {"L", "ML", "MH", "H"};
const char *op = "SET";
const char *line_begin = "";
+ int insns = 0;
int i;
+ HOST_WIDEST_INT tmpvalue = value;
- /* Output pertinent parts of the 4-wyde sequence.
- Still more to do if we want this to be optimal, but hey...
- Note that the zero case has been handled above. */
- for (i = 0; i < 4 && value != 0; i++)
+ /* Compute the number of insns needed to output this constant. */
+ for (i = 0; i < 4 && tmpvalue != 0; i++)
+ {
+ if (tmpvalue & 65535)
+ insns++;
+ tmpvalue >>= 16;
+ }
+ if (TARGET_BASE_ADDRESSES && insns == 3)
+ {
+ /* The number three is based on a static observation on
+ ghostscript-6.52. Two and four are excluded because there
+ are too many such constants, and each unique constant (maybe
+ offset by 1..255) were used few times compared to other uses,
+ e.g. addresses.
+
+ We use base-plus-offset addressing to force it into a global
+ register; we just use a "LDA reg,VALUE", which will cause the
+ assembler and linker to DTRT (for constants as well as
+ addresses). */
+ fprintf (stream, "LDA %s,", reg_names[regno]);
+ mmix_output_octa (stream, value, 0);
+ }
+ else
{
- if (value & 65535)
+ /* Output pertinent parts of the 4-wyde sequence.
+ Still more to do if we want this to be optimal, but hey...
+ Note that the zero case has been handled above. */
+ for (i = 0; i < 4 && value != 0; i++)
{
- fprintf (stream, "%s%s%s %s,#%x", line_begin, op,
- higher_parts[i], reg_names[regno],
- (int) (value & 65535));
- /* The first one sets the rest of the bits to 0, the next
- ones add set bits. */
- op = "INC";
- line_begin = "\n\t";
- }
+ if (value & 65535)
+ {
+ fprintf (stream, "%s%s%s %s,#%x", line_begin, op,
+ higher_parts[i], reg_names[regno],
+ (int) (value & 65535));
+ /* The first one sets the rest of the bits to 0, the next
+ ones add set bits. */
+ op = "INC";
+ line_begin = "\n\t";
+ }
- value >>= 16;
+ value >>= 16;
+ }
}
}
#define TARGET_MASK_TOPLEVEL_SYMBOLS 32
#define TARGET_MASK_BRANCH_PREDICT 64
+/* We use the term "base address" since that's what Knuth uses. The base
+ address goes in a global register. When addressing, it's more like
+ "base address plus offset", with the offset being 0..255 from the base,
+ which itself can be a symbol plus an offset. The effect is like having
+ a constant pool in global registers, code offseting from those
+ registers (automatically causing a request for a suitable constant base
+ address register) without having to know the specific register or the
+ specific offset. */
+#define TARGET_MASK_BASE_ADDRESSES 128
+
/* FIXME: Get rid of this one. */
#define TARGET_LIBFUNC (target_flags & TARGET_MASK_LIBFUNCS)
#define TARGET_ABI_GNU (target_flags & TARGET_MASK_ABI_GNU)
#define TARGET_KNUTH_DIVISION (target_flags & TARGET_MASK_KNUTH_DIVISION)
#define TARGET_TOPLEVEL_SYMBOLS (target_flags & TARGET_MASK_TOPLEVEL_SYMBOLS)
#define TARGET_BRANCH_PREDICT (target_flags & TARGET_MASK_BRANCH_PREDICT)
+#define TARGET_BASE_ADDRESSES (target_flags & TARGET_MASK_BASE_ADDRESSES)
#define TARGET_DEFAULT \
- (TARGET_MASK_BRANCH_PREDICT)
+ (TARGET_MASK_BRANCH_PREDICT | TARGET_MASK_BASE_ADDRESSES)
/* FIXME: Provide a way to *load* the epsilon register. */
#define TARGET_SWITCHES \
N_("Use P-mnemonics for branches statically predicted as taken")}, \
{"no-branch-predict", -TARGET_MASK_BRANCH_PREDICT, \
N_("Don't use P-mnemonics for branches")}, \
+ {"base-addresses", TARGET_MASK_BASE_ADDRESSES, \
+ N_("Use addresses that allocate global registers")}, \
+ {"no-base-addresses", -TARGET_MASK_BASE_ADDRESSES, \
+ N_("Do not use addresses that allocate global registers")}, \
{"", TARGET_DEFAULT, ""}}
/* Unfortunately, this must not reference anything in "mmix.c". */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
- 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, \
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
+ 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, \
1, 1, 0, 0, 0, 1 \
}
24, 25, 26, 27, 28, 29, 30, 31, \
\
252, 251, 250, 249, 248, 247, \
- 246, 245, 244, 243, 242, 241, 240, 239, \
- 238, 237, 236, 235, 234, 233, 232, 231, \
\
253, \
\
208, 209, 210, 211, 212, 213, 214, 215, \
216, 217, 218, 219, 220, 221, 222, 223, \
224, 225, 226, 227, 228, 229, 230, 231, \
+ 232, 233, 234, 235, 236, 237, 238, 239, \
+ 240, 241, 242, 243, 244, 245, 246, \
+ \
254, 255, 256, 257, 261 \
}
#define MMIX_GNU_ABI_REG_ALLOC_ORDER \
{ 252, 251, 250, 249, 248, 247, 246, \
245, 244, 243, 242, 241, 240, 239, 238, \
- 237, 236, 235, 234, 233, 232, \
+ 237, 236, 235, 234, 233, 232, 231, \
\
0, 1, 2, 3, 4, 5, 6, 7, \
8, 9, 10, 11, 12, 13, 14, 15, \
200, 201, 202, 203, 204, 205, 206, 207, \
208, 209, 210, 211, 212, 213, 214, 215, \
216, 217, 218, 219, 220, 221, 222, 223, \
- 224, 225, 226, 227, 228, 229, 230, 231, \
+ 224, 225, 226, 227, 228, 229, 230, \
+ \
254, 255, 256, 257, 261 \
}
;; We assume all "s" are addresses. Does that hold?
(define_insn "movdi"
- [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r ,r,x,r,m,r,m,r,??r")
- (match_operand:DI 1 "general_operand" "r,LS,K,r,x,I,m,r,s,n"))]
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r ,r,x,r,m,r,m,r,r,??r")
+ (match_operand:DI 1 "general_operand" "r,LS,K,r,x,I,m,r,R,s,n"))]
""
"@
SET %0,%1
LDO %0,%1
STOU %1,%0
GETA %0,%1
+ LDA %0,%1
%r0%I1")
;; Note that we move around the float as a collection of bits; no
MULTILIB_OPTIONS = mabi=gnu
MULTILIB_DIRNAMES = gnuabi
+# Don't use global registers in libraries.
+MULTILIB_EXTRA_OPTS = mno-base-addresses
+
$(T)crti.o: $(srcdir)/config/mmix/crti.asm $(GCC_PASSES)
$(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \
-c -o $(T)crti.o -x assembler-with-cpp $(srcdir)/config/mmix/crti.asm
@gccoptlist{
-mlibfuncs -mno-libfuncs -mepsilon -mno-epsilon -mabi=gnu @gol
-mabi=mmixware -mzero-extend -mknuthdiv -mtoplevel-symbols @gol
--melf -mbranch-predict -mno-branch-predict}
+-melf -mbranch-predict -mno-branch-predict -mbase-addresses @gol
+-mno-base-addresses}
@emph{IA-64 Options}
@gccoptlist{
@opindex mno-branch-predict
Use (do not use) the probable-branch instructions, when static branch
prediction indicates a probable branch.
+
+@item -mbase-addresses
+@itemx -mno-base-addresses
+@opindex mbase-addresses
+@opindex mno-base-addresses
+Generate (do not generate) code that uses @emph{base addresses}. Using a
+base address automatically generates a request (handled by the assembler
+and the linker) for a constant to be set up in a global register. The
+register is used for one or more base address requests within the range 0
+to 255 from the value held in the register. The generally leads to short
+and fast code, but the number of different data items that can be
+addressed is limited. This means that a program that uses lots of static
+data may require @option{-mno-base-addresses}.
@end table
@node PDP-11 Options