/* Definitions of target machine for GNU compiler, for the pdp-11
- Copyright (C) 1994-2018 Free Software Foundation, Inc.
+ Copyright (C) 1994-2024 Free Software Foundation, Inc.
Contributed by Michael K. Gschwind (mike@vlsivie.tuwien.ac.at).
This file is part of GCC.
do \
{ \
builtin_define_std ("pdp11"); \
+ if (TARGET_INT16) \
+ builtin_define_with_int_value ("__pdp11_int", 16); \
+ else \
+ builtin_define_with_int_value ("__pdp11_int", 32); \
+ if (TARGET_40) \
+ builtin_define_with_int_value ("__pdp11_model", 40); \
+ else if (TARGET_45) \
+ builtin_define_with_int_value ("__pdp11_model", 45); \
+ else \
+ builtin_define_with_int_value ("__pdp11_model", 10); \
+ if (TARGET_FPU) \
+ builtin_define ("__pdp11_fpu"); \
+ if (TARGET_AC0) \
+ builtin_define ("__pdp11_ac0"); \
} \
while (0)
-
-/* Generate DBX debugging information. */
-
-#define DBX_DEBUGGING_INFO
+#undef PREFERRED_DEBUGGING_TYPE
+#define PREFERRED_DEBUGGING_TYPE NO_DEBUG
#define TARGET_40_PLUS (TARGET_40 || TARGET_45)
#define TARGET_10 (! TARGET_40_PLUS)
#define TARGET_UNIX_ASM_DEFAULT 0
+/* "Dialect" just distinguishes between standard DEC mnemonics, which
+ are also used by the GNU assembler, vs. Unix mnemonics and float
+ register names. So it is tied to the -munit-asm option, and treats
+ -mgnu-asm and -mdec-asm as equivalent (both are dialect zero). */
#define ASSEMBLER_DIALECT (TARGET_UNIX_ASM ? 1 : 0)
\f
#define LONG_TYPE_SIZE 32
#define LONG_LONG_TYPE_SIZE 64
-/* if we set FLOAT_TYPE_SIZE to 32, we could have the benefit
- of saving core for huge arrays - the definitions are
- already in md - but floats can never reside in
- an FPU register - we keep the FPU in double float mode
- all the time !! */
-#define FLOAT_TYPE_SIZE (TARGET_FLOAT32 ? 32 : 64)
+/* In earlier versions, FLOAT_TYPE_SIZE was selectable as 32 or 64,
+ but that conflicts with Fortran language rules. Since there is no
+ obvious reason why we should have that feature -- other targets
+ generally don't have float and double the same size -- I've removed
+ it. Note that it continues to be true (for now) that arithmetic is
+ always done with 64-bit values, i.e., the FPU is always in "double"
+ mode. */
+#define FLOAT_TYPE_SIZE 32
#define DOUBLE_TYPE_SIZE 64
#define LONG_DOUBLE_TYPE_SIZE 64
when given unaligned data. */
#define STRICT_ALIGNMENT 1
-/* Adjust the length of shifts by small constant amounts. The base
- value (in "length" on input) is the length of a shift by one, not
- including the CLC in logical shifts. */
-#define ADJUST_INSN_LENGTH(insn, length) \
- if ((GET_CODE (insn) == ASHIFT || \
- GET_CODE (insn) == ASHIFTRT || \
- GET_CODE (insn) == LSHIFTRT) && \
- GET_CODE (XEXP (insn, 2)) == CONST_INT && \
- pdp11_small_shift (XINT (insn, 2))) \
- { \
- if (GET_CODE (insn) == LSHIFTRT) \
- length = (length * XINT (insn, 2)) + 2; \
- else \
- length *= XINT (insn, 2); \
- }
+/* "HW_DIVIDE" actually means 64 by 32 bit divide. While some PDP11
+ models have hardware divide, it is for 32 by 16 bits only, so we
+ call this platform "no hardware divide". */
+#define TARGET_HAS_NO_HW_DIVIDE 1
\f
/* Standard register usage. */
#define FIXED_REGISTERS \
{0, 0, 0, 0, 0, 0, 1, 1, \
0, 0, 0, 0, 0, 0, 1, 1, \
- 1, 1 }
+ 1 }
#define CALL_USED_REGISTERS \
{1, 1, 0, 0, 0, 0, 1, 1, \
0, 0, 0, 0, 0, 0, 1, 1, \
- 1, 1 }
+ 1 }
/* Specify the registers used for certain standard purposes.
MUL_REGS are used for odd numbered regs, to use in 16-bit multiplication
(even numbered do 32-bit multiply)
-LMUL_REGS long multiply registers (even numbered regs )
- (don't need them, all 32-bit regs are even numbered!)
GENERAL_REGS is all cpu
LOAD_FPU_REGS is the first four cpu regs, they are easier to load
NO_LOAD_FPU_REGS is ac4 and ac5, currently - difficult to load them
FPU_REGS is all fpu regs
+CC_REGS is the condition codes (CPU and FPU)
*/
enum reg_class
{ NO_REGS,
+ NOTR0_REG,
+ NOTR1_REG,
+ NOTR2_REG,
+ NOTR3_REG,
+ NOTR4_REG,
+ NOTR5_REG,
+ NOTSP_REG,
MUL_REGS,
GENERAL_REGS,
LOAD_FPU_REGS,
#define REG_CLASS_NAMES \
{ "NO_REGS", \
+ "NOTR0_REG", \
+ "NOTR1_REG", \
+ "NOTR2_REG", \
+ "NOTR3_REG", \
+ "NOTR4_REG", \
+ "NOTR5_REG", \
+ "SP_REG", \
"MUL_REGS", \
"GENERAL_REGS", \
"LOAD_FPU_REGS", \
#define REG_CLASS_CONTENTS \
{ {0x00000}, /* NO_REGS */ \
- {0x000aa}, /* MUL_REGS */ \
- {0x0c0ff}, /* GENERAL_REGS */ \
+ {0x000fe}, /* NOTR0_REG */ \
+ {0x000fd}, /* NOTR1_REG */ \
+ {0x000fb}, /* NOTR2_REG */ \
+ {0x000f7}, /* NOTR3_REG */ \
+ {0x000ef}, /* NOTR4_REG */ \
+ {0x000df}, /* NOTR5_REG */ \
+ {0x000bf}, /* NOTSP_REG */ \
+ {0x0002a}, /* MUL_REGS */ \
+ {0x040ff}, /* GENERAL_REGS */ \
{0x00f00}, /* LOAD_FPU_REGS */ \
{0x03000}, /* NO_LOAD_FPU_REGS */ \
{0x03f00}, /* FPU_REGS */ \
- {0x30000}, /* CC_REGS */ \
- {0x3ffff}} /* ALL_REGS */
+ {0x18000}, /* CC_REGS */ \
+ {0x1ffff}} /* ALL_REGS */
/* The same information, inverted:
Return the class number of the smallest class containing
#define INDEX_REG_CLASS GENERAL_REGS
#define BASE_REG_CLASS GENERAL_REGS
+/* Return TRUE if the class is a CPU register. */
+#define CPU_REG_CLASS(CLASS) \
+ (CLASS >= NOTR0_REG && CLASS <= GENERAL_REGS)
+
/* Return the maximum number of consecutive registers
needed to represent mode MODE in a register of class CLASS. */
#define CLASS_MAX_NREGS(CLASS, MODE) \
-((CLASS == GENERAL_REGS || CLASS == MUL_REGS)? \
- ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD): \
- 1 \
-)
+ (CPU_REG_CLASS (CLASS) ? \
+ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD): \
+ 1 \
+ )
\f
/* Stack layout; function entry, exit and calling. */
/* Output assembler code to FILE to increment profiler label # LABELNO
for profiling a function entry. */
-#define FUNCTION_PROFILER(FILE, LABELNO) \
- gcc_unreachable ();
+#define FUNCTION_PROFILER(FILE, LABELNO)
/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function,
the stack pointer does not matter. The value is tested only in
functions that have frame pointers.
No definition is equivalent to always zero. */
-extern int may_call_alloca;
-
#define EXIT_IGNORE_STACK 1
/* Definitions for register eliminations.
followed by "to". Eliminations of the same "from" register are listed
in order of preference.
- There are two registers that can always be eliminated on the pdp11.
- The frame pointer and the arg pointer can be replaced by either the
- hard frame pointer or to the stack pointer, depending upon the
- circumstances. The hard frame pointer is not used before reload and
- so it is not eligible for elimination. */
+ There are two registers that can be eliminated on the pdp11. The
+ arg pointer can be replaced by the frame pointer; the frame pointer
+ can often be replaced by the stack pointer. */
#define ELIMINABLE_REGS \
{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
- { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \
- { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
- { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}}
+ { ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \
+ { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}}
#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
((OFFSET) = pdp11_initial_elimination_offset ((FROM), (TO)))
They give nonzero only if REGNO is a hard reg of the suitable class
or a pseudo reg currently allocated to a suitable hard reg.
Since they use reg_renumber, they are safe only once reg_renumber
- has been allocated, which happens in reginfo.c during register
+ has been allocated, which happens in reginfo.cc during register
allocation. */
#define REGNO_OK_FOR_BASE_P(REGNO) \
/* Max number of bytes we can move from memory to memory
in one reasonably fast instruction.
*/
-
#define MOVE_MAX 2
-/* Nonzero if access to memory by byte is slow and undesirable. -
-*/
-#define SLOW_BYTE_ACCESS 0
+/* Max number of insns to use for inline move rather than library
+ call. */
+#define MOVE_RATIO(speed) 6
-/* Do not break .stabs pseudos into continuations. */
-#define DBX_CONTIN_LENGTH 0
+/* Nonzero if access to memory by byte is no faster than by word. */
+#define SLOW_BYTE_ACCESS 1
/* Give a comparison code (EQ, NE etc) and the first operand of a COMPARE,
return the mode to be used for the comparison. */
#define SELECT_CC_MODE(OP,X,Y) pdp11_cc_mode (OP, X, Y)
-/* Enable compare elimination pass.
- FIXME: how can this be enabled for two registers? */
+/* Enable compare elimination pass. */
#undef TARGET_FLAGS_REGNUM
#define TARGET_FLAGS_REGNUM CC_REGNUM
/* Output before read-only data. */
-#define TEXT_SECTION_ASM_OP "\t.text\n"
+#define TEXT_SECTION_ASM_OP \
+ ((TARGET_DEC_ASM) ? "\t.psect\tcode,i,ro,con" : "\t.text")
/* Output before writable data. */
-#define DATA_SECTION_ASM_OP "\t.data\n"
+#define DATA_SECTION_ASM_OP \
+ ((TARGET_DEC_ASM) ? "\t.psect\tdata,d,rw,con" : "\t.data")
+
+/* Output before read-only data. Same as read-write data for non-DEC
+ assemblers because they don't know about .rodata. */
+
+#define READONLY_DATA_SECTION_ASM_OP \
+ ((TARGET_DEC_ASM) ? "\t.psect\trodata,d,ro,con" : "\t.data")
/* How to refer to registers in assembler output.
This sequence is indexed by compiler's hard-register-number (see above). */
#define REGISTER_NAMES \
{"r0", "r1", "r2", "r3", "r4", "r5", "sp", "pc", \
- "ac0", "ac1", "ac2", "ac3", "ac4", "ac5", "fp", "ap", \
- "cc", "fcc" }
+ "ac0", "ac1", "ac2", "ac3", "ac4", "ac5", "ap", "cc", \
+ "fcc" }
/* Globalizing directive for a label. */
-#define GLOBAL_ASM_OP "\t.globl "
+#define GLOBAL_ASM_OP "\t.globl\t"
-/* The prefix to add to user-visible assembler symbols. */
+/* The prefix to add to user-visible assembler symbols. For the DEC
+ assembler case, this is not used. */
#define USER_LABEL_PREFIX "_"
+/* Line separators. */
+
+#define IS_ASM_LOGICAL_LINE_SEPARATOR(C, STR) \
+ ((C) == '\n' || (!TARGET_DEC_ASM && (C) == ';'))
+
/* This is how to store into the string LABEL
the symbol_ref name of an internal numbered label where
PREFIX is the class of label and NUM is the number within the class.
This is suitable for output with `assemble_name'. */
-#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \
- sprintf (LABEL, "*%s_%lu", PREFIX, (unsigned long)(NUM))
+#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \
+ pdp11_gen_int_label ((LABEL), (PREFIX), (NUM))
+
+/* Emit a string. */
#define ASM_OUTPUT_ASCII(FILE, P, SIZE) \
output_ascii (FILE, P, SIZE)
-/* This is how to output an element of a case-vector that is absolute. */
+/* Print a label reference, with _ prefix if not DEC. */
-#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
- fprintf (FILE, "\t%sL_%d\n", TARGET_UNIX_ASM ? "" : ".word ", VALUE)
+#define ASM_OUTPUT_LABELREF(STREAM, NAME) \
+ pdp11_output_labelref ((STREAM), (NAME))
+
+/* Equate a symbol to an expression. */
-/* This is how to output an element of a case-vector that is relative.
- Don't define this if it is not supported. */
+#define ASM_OUTPUT_DEF(STREAM, NAME, VALUE) \
+ pdp11_output_def (STREAM, NAME, VALUE)
-/* #define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) */
+/* Mark a reference to an external symbol. Needed for DEC assembler. */
-/* This is how to output an assembler line
- that says to advance the location counter
- to a multiple of 2**LOG bytes.
+#define ASM_OUTPUT_EXTERNAL(STREAM, DECL, NAME) \
+ if (TARGET_DEC_ASM) \
+ fprintf ((STREAM), "\t.globl\t%s\n", (NAME))
- who needs this????
+#define ASM_OUTPUT_SOURCE_FILENAME(STREAM, NAME) \
+ if (TARGET_DEC_ASM) \
+ fprintf ((STREAM), ".title\t%s\n", (NAME))
+
+/* This is how to output an element of a case-vector that is absolute. */
+
+#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
+ pdp11_output_addr_vec_elt (FILE, VALUE)
+
+/* This is how to output an assembler line that says to advance the
+ location counter to a multiple of 2**LOG bytes. Only values 0 and
+ 1 should appear, but due to PR87795 larger values (which are not
+ supported) can also appear. So we treat all alignment of LOG >= 1
+ as word (2 byte) alignment.
*/
#define ASM_OUTPUT_ALIGN(FILE,LOG) \
- switch (LOG) \
- { \
- case 0: \
- break; \
- case 1: \
- fprintf (FILE, "\t.even\n"); \
- break; \
- default: \
- gcc_unreachable (); \
- }
+ if (LOG != 0) \
+ fprintf (FILE, "\t.even\n")
#define ASM_OUTPUT_SKIP(FILE,SIZE) \
- fprintf (FILE, "\t.=.+ %#ho\n", (unsigned short)(SIZE))
+ do { \
+ if (TARGET_DEC_ASM) \
+ fprintf (FILE, "\t.blkb\t%o\n", (int) ((SIZE) & 0xffff)); \
+ else \
+ fprintf (FILE, "\t.=.+ %#o\n", (int) ((SIZE) & 0xffff)); \
+ } while (0)
/* This says how to output an assembler line
to define a global common symbol. */
#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \
- pdp11_asm_output_var (FILE, NAME, SIZE, ALIGN, true)
-
+ pdp11_asm_output_var (FILE, NAME, SIZE, ALIGN, true)
/* This says how to output an assembler line
to define a local common symbol. */
#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \
- pdp11_asm_output_var (FILE, NAME, SIZE, ALIGN, false)
+ pdp11_asm_output_var (FILE, NAME, SIZE, ALIGN, false)
/* Print a memory address as an operand to reference that memory location. */
#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \
- print_operand_address (FILE, ADDR)
+ print_operand_address (FILE, ADDR)
-#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \
-( \
- fprintf (FILE, "\tmov %s, -(sp)\n", reg_names[REGNO]) \
-)
+#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \
+ fprintf (FILE, "\tmov\t%s,-(sp)\n", reg_names[REGNO])
-#define ASM_OUTPUT_REG_POP(FILE,REGNO) \
-( \
- fprintf (FILE, "\tmov (sp)+, %s\n", reg_names[REGNO]) \
-)
+#define ASM_OUTPUT_REG_POP(FILE,REGNO) \
+ fprintf (FILE, "\tmov\t(sp)+,%s\n", reg_names[REGNO])
#define TRAMPOLINE_SIZE 8
#define TRAMPOLINE_ALIGNMENT 16
#define COMPARE_FLAG_MODE HImode
+/* May be overridden by command option processing. */
#define TARGET_HAVE_NAMED_SECTIONS false
/* pdp11-unknown-aout target has no support of C99 runtime */