📄 stmt.c
字号:
/* Note: if THISBLOCK == 0 and we have a label that hasn't appeared, it means the label is undefined. That's erroneous, but possible. */ && (thisblock->data.block.block_start_count <= f->block_start_count)) { tree lists = f->cleanup_list_list; rtx cleanup_insns; for (; lists; lists = TREE_CHAIN (lists)) /* If the following elt. corresponds to our containing block then the elt. must be for this block. */ if (TREE_CHAIN (lists) == thisblock->data.block.outer_cleanups) { start_sequence (); pushlevel (0); set_block (f->context); expand_cleanups (TREE_VALUE (lists), NULL_TREE, 1, 1); do_pending_stack_adjust (); cleanup_insns = get_insns (); poplevel (1, 0, 0); end_sequence (); f->before_jump = emit_insns_after (cleanup_insns, f->before_jump); f->cleanup_list_list = TREE_CHAIN (lists); } if (stack_level) f->stack_level = stack_level; }}/* When exiting a binding contour, process all pending gotos requiring fixups. Note: STACK_DEPTH is not altered. The arguments are currently not used in the bytecode compiler, but we may need them one day for languages other than C. THISBLOCK is the structure that describes the block being exited. STACK_LEVEL is the rtx for the stack level to restore exiting this contour. CLEANUP_LIST is a list of expressions to evaluate on exiting this contour. FIRST_INSN is the insn that began this contour. Gotos that jump out of this contour must restore the stack level and do the cleanups before actually jumping. DONT_JUMP_IN nonzero means report error there is a jump into this contour from before the beginning of the contour. This is also done if STACK_LEVEL is nonzero. */static voidbc_fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in) struct nesting *thisblock; int stack_level; tree cleanup_list; rtx first_insn; int dont_jump_in;{ register struct goto_fixup *f, *prev; int saved_stack_depth; /* F is the fixup we are considering; PREV is the previous one. */ for (prev = 0, f = goto_fixup_chain; f; prev = f, f = f->next) { /* Test for a fixup that is inactive because it is already handled. */ if (f->before_jump == 0) { /* Delete inactive fixup from the chain, if that is easy to do. */ if (prev) prev->next = f->next; } /* Emit code to restore the stack and continue */ bc_emit_bytecode_labeldef (f->label); /* Save stack_depth across call, since bc_adjust_stack () will alter the perceived stack depth via the instructions generated. */ if (f->bc_stack_level >= 0) { saved_stack_depth = stack_depth; bc_adjust_stack (stack_depth - f->bc_stack_level); stack_depth = saved_stack_depth; } bc_emit_bytecode (jump); bc_emit_bytecode_labelref (f->bc_target);#ifdef DEBUG_PRINT_CODE fputc ('\n', stderr);#endif } goto_fixup_chain = NULL;}/* Generate RTL for an asm statement (explicit assembler code). BODY is a STRING_CST node containing the assembler code text, or an ADDR_EXPR containing a STRING_CST. */voidexpand_asm (body) tree body;{ if (output_bytecode) { error ("`asm' is invalid when generating bytecode"); return; } if (TREE_CODE (body) == ADDR_EXPR) body = TREE_OPERAND (body, 0); emit_insn (gen_rtx (ASM_INPUT, VOIDmode, TREE_STRING_POINTER (body))); last_expr_type = 0;}/* Generate RTL for an asm statement with arguments. STRING is the instruction template. OUTPUTS is a list of output arguments (lvalues); INPUTS a list of inputs. Each output or input has an expression in the TREE_VALUE and a constraint-string in the TREE_PURPOSE. CLOBBERS is a list of STRING_CST nodes each naming a hard register that is clobbered by this insn. Not all kinds of lvalue that may appear in OUTPUTS can be stored directly. Some elements of OUTPUTS may be replaced with trees representing temporary values. The caller should copy those temporary values to the originally specified lvalues. VOL nonzero means the insn is volatile; don't optimize it. */voidexpand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line) tree string, outputs, inputs, clobbers; int vol; char *filename; int line;{ rtvec argvec, constraints; rtx body; int ninputs = list_length (inputs); int noutputs = list_length (outputs); int nclobbers; tree tail; register int i; /* Vector of RTX's of evaluated output operands. */ rtx *output_rtx = (rtx *) alloca (noutputs * sizeof (rtx)); /* The insn we have emitted. */ rtx insn; if (output_bytecode) { error ("`asm' is invalid when generating bytecode"); return; } /* Count the number of meaningful clobbered registers, ignoring what we would ignore later. */ nclobbers = 0; for (tail = clobbers; tail; tail = TREE_CHAIN (tail)) { char *regname = TREE_STRING_POINTER (TREE_VALUE (tail)); i = decode_reg_name (regname); if (i >= 0 || i == -4) ++nclobbers; else if (i == -2) error ("unknown register name `%s' in `asm'", regname); } last_expr_type = 0; for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++) { tree val = TREE_VALUE (tail); tree type = TREE_TYPE (val); tree val1; int j; int found_equal = 0; int allows_reg = 0; /* If there's an erroneous arg, emit no insn. */ if (TREE_TYPE (val) == error_mark_node) return; /* Make sure constraint has `=' and does not have `+'. Also, see if it allows any register. Be liberal on the latter test, since the worst that happens if we get it wrong is we issue an error message. */ for (j = 0; j < TREE_STRING_LENGTH (TREE_PURPOSE (tail)) - 1; j++) switch (TREE_STRING_POINTER (TREE_PURPOSE (tail))[j]) { case '+': error ("output operand constraint contains `+'"); return; case '=': found_equal = 1; break; case '?': case '!': case '*': case '%': case '&': case '0': case '1': case '2': case '3': case '4': case 'V': case 'm': case 'o': case '<': case '>': case 'E': case 'F': case 'G': case 'H': case 'X': case 's': case 'i': case 'n': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case ',':#ifdef EXTRA_CONSTRAINT case 'Q': case 'R': case 'S': case 'T': case 'U':#endif break; case 'p': case 'g': case 'r': default: allows_reg = 1; break; } if (! found_equal) { error ("output operand constraint lacks `='"); return; } /* If an output operand is not a decl or indirect ref and our constraint allows a register, make a temporary to act as an intermediate. Make the asm insn write into that, then our caller will copy it to the real output operand. Likewise for promoted variables. */ if (TREE_CODE (val) == INDIRECT_REF || (TREE_CODE_CLASS (TREE_CODE (val)) == 'd' && ! (GET_CODE (DECL_RTL (val)) == REG && GET_MODE (DECL_RTL (val)) != TYPE_MODE (type))) || ! allows_reg) { if (! allows_reg) mark_addressable (TREE_VALUE (tail)); output_rtx[i] = expand_expr (TREE_VALUE (tail), NULL_RTX, VOIDmode, 0); if (! allows_reg && GET_CODE (output_rtx[i]) != MEM) error ("output number %d not directly addressable", i); } else { if (TYPE_MODE (type) == BLKmode) { output_rtx[i] = assign_stack_temp (BLKmode, int_size_in_bytes (type), 0); MEM_IN_STRUCT_P (output_rtx[i]) = AGGREGATE_TYPE_P (type); } else output_rtx[i] = gen_reg_rtx (TYPE_MODE (type)); TREE_VALUE (tail) = make_tree (type, output_rtx[i]); } } if (ninputs + noutputs > MAX_RECOG_OPERANDS) { error ("more than %d operands in `asm'", MAX_RECOG_OPERANDS); return; } /* Make vectors for the expression-rtx and constraint strings. */ argvec = rtvec_alloc (ninputs); constraints = rtvec_alloc (ninputs); body = gen_rtx (ASM_OPERANDS, VOIDmode, TREE_STRING_POINTER (string), "", 0, argvec, constraints, filename, line); MEM_VOLATILE_P (body) = vol; /* Eval the inputs and put them into ARGVEC. Put their constraints into ASM_INPUTs and store in CONSTRAINTS. */ i = 0; for (tail = inputs; tail; tail = TREE_CHAIN (tail)) { int j; int allows_reg = 0; /* If there's an erroneous arg, emit no insn, because the ASM_INPUT would get VOIDmode and that could cause a crash in reload. */ if (TREE_TYPE (TREE_VALUE (tail)) == error_mark_node) return; if (TREE_PURPOSE (tail) == NULL_TREE) { error ("hard register `%s' listed as input operand to `asm'", TREE_STRING_POINTER (TREE_VALUE (tail)) ); return; } /* Make sure constraint has neither `=' nor `+'. */ for (j = 0; j < TREE_STRING_LENGTH (TREE_PURPOSE (tail)) - 1; j++) switch (TREE_STRING_POINTER (TREE_PURPOSE (tail))[j]) { case '+': case '=': error ("input operand constraint contains `%c'", TREE_STRING_POINTER (TREE_PURPOSE (tail))[j]); return; case '?': case '!': case '*': case '%': case '&': case 'V': case 'm': case 'o': case '<': case '>': case 'E': case 'F': case 'G': case 'H': case 'X': case 's': case 'i': case 'n': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case ',':#ifdef EXTRA_CONSTRAINT case 'Q': case 'R': case 'S': case 'T': case 'U':#endif break; case '0': case '1': case '2': case '3': case '4': case 'p': case 'g': case 'r': default: allows_reg = 1; break; } if (! allows_reg) mark_addressable (TREE_VALUE (tail)); XVECEXP (body, 3, i) /* argvec */ = expand_expr (TREE_VALUE (tail), NULL_RTX, VOIDmode, 0); if (CONSTANT_P (XVECEXP (body, 3, i)) && ! general_operand (XVECEXP (body, 3, i), TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))))) { if (allows_reg) XVECEXP (body, 3, i) = force_reg (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))), XVECEXP (body, 3, i)); else XVECEXP (body, 3, i) = force_const_mem (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))), XVECEXP (body, 3, i)); } if (! allows_reg && (GET_CODE (XVECEXP (body, 3, i)) == REG || GET_CODE (XVECEXP (body, 3, i)) == SUBREG || GET_CODE (XVECEXP (body, 3, i)) == CONCAT)) { tree type = TREE_TYPE (TREE_VALUE (tail)); rtx memloc = assign_stack_temp (TYPE_MODE (type), int_size_in_bytes (type), 1); MEM_IN_STRUCT_P (memloc) = AGGREGATE_TYPE_P (type); emit_move_insn (memloc, XVECEXP (body, 3, i)); XVECEXP (body, 3, i) = memloc; } XVECEXP (body, 4, i) /* constraints */ = gen_rtx (ASM_INPUT, TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))), TREE_STRING_POINTER (TREE_PURPOSE (tail))); i++; } /* Protect all the operands from the queue, now that they have all been evaluated. */ for (i = 0; i < ninputs; i++) XVECEXP (body, 3, i) = protect_from_queue (XVECEXP (body, 3, i), 0); for (i = 0; i < noutputs; i++) output_rtx[i] = protect_from_queue (output_rtx[i], 1); /* Now, for each output, construct an rtx (set OUTPUT (asm_operands INSN OUTPUTNUMBER OUTPUTCONSTRAINT ARGVEC CONSTRAINTS)) If there is more than one, put them inside a PARALLEL. */ if (noutputs == 1 && nclobbers == 0) { XSTR (body, 1) = TREE_STRING_POINTER (TREE_PURPOSE (outputs)); insn = emit_insn (gen_rtx (SET, VOIDmode, output_rtx[0], body)); } else if (noutputs == 0 && nclobbers == 0) { /* No output operands: put in a raw ASM_OPERANDS rtx. */ insn = emit_insn (body); } else { rtx obody = body; int num = noutputs; if (num == 0) num = 1; body = gen_rtx (PARALLEL, VOIDmode, rtvec_alloc (num + nclobbers)); /* For each output operand, store a SET. */ for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++) { XVECEXP (body, 0, i) = gen_rtx (SET, VOIDmode, output_rtx[i], gen_rtx (ASM_OPERANDS, VOIDmode, TREE_STRING_POINTER (string), TREE_STRING_POINTER (TREE_PURPOSE (tail)),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -