GCC Middle and Back End API Reference
|
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "rtl-error.h"
#include "tm_p.h"
#include "function.h"
#include "insn-config.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "flags.h"
#include "recog.h"
#include "basic-block.h"
#include "reload.h"
#include "ggc.h"
#include "tree-pass.h"
#include "target.h"
#include "df.h"
#include "emit-rtl.h"
Functions | |
static bool | gate_handle_stack_regs () |
rtl_opt_pass * | make_pass_stack_regs () |
static unsigned int | rest_of_handle_stack_regs () |
rtl_opt_pass * | make_pass_stack_regs_run () |
|
static |
Register to Stack convert for GNU compiler. Copyright (C) 1992-2013 Free Software Foundation, Inc.
This file is part of GCC.
GCC 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 3, or (at your option) any later version.
GCC 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 GCC; see the file COPYING3. If not see http://www.gnu.org/licenses/. This pass converts stack-like registers from the "flat register file" model that gcc uses, to a stack convention that the 387 uses.
The form of the input:
On input, the function consists of insn that have had their registers fully allocated to a set of "virtual" registers. Note that the word "virtual" is used differently here than elsewhere in gcc: for each virtual stack reg, there is a hard reg, but the mapping between them is not known until this pass is run. On output, hard register numbers have been substituted, and various pop and exchange insns have been emitted. The hard register numbers and the virtual register numbers completely overlap - before this pass, all stack register numbers are virtual, and afterward they are all hard.
The virtual registers can be manipulated normally by gcc, and their semantics are the same as for normal registers. After the hard register numbers are substituted, the semantics of an insn containing stack-like regs are not the same as for an insn with normal regs: for instance, it is not safe to delete an insn that appears to be a no-op move. In general, no insn containing hard regs should be changed after this pass is done.
The form of the output:
After this pass, hard register numbers represent the distance from the current top of stack to the desired register. A reference to FIRST_STACK_REG references the top of stack, FIRST_STACK_REG + 1, represents the register just below that, and so forth. Also, REG_DEAD notes indicate whether or not a stack register should be popped.
A "swap" insn looks like a parallel of two patterns, where each pattern is a SET: one sets A to B, the other B to A.
A "push" or "load" insn is a SET whose SET_DEST is FIRST_STACK_REG and whose SET_DEST is REG or MEM. Any other SET_DEST, such as PLUS, will replace the existing stack top, not push a new value.
A store insn is a SET whose SET_DEST is FIRST_STACK_REG, and whose SET_SRC is REG or MEM.
The case where the SET_SRC and SET_DEST are both FIRST_STACK_REG appears ambiguous. As a special case, the presence of a REG_DEAD note for FIRST_STACK_REG differentiates between a load insn and a pop.
If a REG_DEAD is present, the insn represents a "pop" that discards the top of the register stack. If there is no REG_DEAD note, then the insn represents a "dup" or a push of the current top of stack onto the stack.
Methodology:
Existing REG_DEAD and REG_UNUSED notes for stack registers are deleted and recreated from scratch. REG_DEAD is never created for a SET_DEST, only REG_UNUSED.
asm_operands:
There are several rules on the usage of stack-like regs in asm_operands insns. These rules apply only to the operands that are stack-like regs:
Given a set of input regs that die in an asm_operands, it is necessary to know which are implicitly popped by the asm, and which must be explicitly popped by gcc.
An input reg that is implicitly popped by the asm must be explicitly clobbered, unless it is constrained to match an output operand.
For any input reg that is implicitly popped by an asm, it is necessary to know how to adjust the stack to compensate for the pop. If any non-popped input is closer to the top of the reg-stack than the implicitly popped reg, it would not be possible to know what the stack looked like - it's not clear how the rest of the stack "slides up".
All implicitly popped input regs must be closer to the top of the reg-stack than any input that is not implicitly popped.
It is possible that if an input dies in an insn, reload might use the input reg for an output reload. Consider this example:
asm ("foo" : "=t" (a) : "f" (b));
This asm says that input B is not popped by the asm, and that the asm pushes a result onto the reg-stack, i.e., the stack is one deeper after the asm than it was before. But, it is possible that reload will think that it can use the same reg for both the input and the output, if input B dies in this insn.
If any input operand uses the "f" constraint, all output reg constraints must use the "&" earlyclobber.
The asm above would be written as
asm ("foo" : "=&t" (a) : "f" (b));
Some operands need to be in particular places on the stack. All output operands fall in this category - there is no other way to know which regs the outputs appear in unless the user indicates this in the constraints.
Output operands must specifically indicate which reg an output appears in after an asm. "=f" is not allowed: the operand constraints must select a class with a single reg.
Output operands may not be "inserted" between existing stack regs. Since no 387 opcode uses a read/write operand, all output operands are dead before the asm_operands, and are pushed by the asm_operands. It makes no sense to push anywhere but the top of the reg-stack.
Output operands must start at the top of the reg-stack: output operands may not "skip" a reg.
Here are a couple of reasonable asms to want to write. This asm takes one input, which is internally popped, and produces two outputs.
asm ("fsincos" : "=t" (cos), "=u" (sin) : "0" (inp));
This asm takes two inputs, which are popped by the fyl2xp1 opcode, and replaces them with one output. The user must code the "st(1)" clobber for reg-stack.c to know that fyl2xp1 pops both inputs.
asm ("fyl2xp1" : "=t" (result) : "0" (x), "u" (y) : "st(1)");
rtl_opt_pass* make_pass_stack_regs | ( | ) |
rtl_opt_pass* make_pass_stack_regs_run | ( | ) |
|
static |
Convert register usage from flat register file usage to a stack register file.