📄 stmt.c
字号:
{ error ("output operand constraint lacks `='"); return; } /* If an output operand is not a variable or indirect ref, or a part of one, create a SAVE_EXPR which is a pseudo-reg to act as an intermediate temporary. Make the asm insn write into that, then copy it to the real output operand. */ val1 = val; while (TREE_CODE (val1) == COMPONENT_REF || TREE_CODE (val1) == ARRAY_REF) val1 = TREE_OPERAND (val1, 0); if (TREE_CODE (val1) != VAR_DECL && TREE_CODE (val1) != PARM_DECL && TREE_CODE (val1) != INDIRECT_REF) { rtx reg = gen_reg_rtx (TYPE_MODE (TREE_TYPE (val))); /* `build' isn't safe; it really expects args to be trees. */ tree t = build_nt (SAVE_EXPR, val, reg); if (GET_MODE (reg) == BLKmode) abort (); save_expr_regs = gen_rtx (EXPR_LIST, VOIDmode, reg, save_expr_regs); TREE_VALUE (tail) = t; TREE_TYPE (t) = TREE_TYPE (val); } output_rtx[i] = expand_expr (TREE_VALUE (tail), 0, VOIDmode, 0); } 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; /* 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)); j++) if (TREE_STRING_POINTER (TREE_PURPOSE (tail))[j] == '=' || TREE_STRING_POINTER (TREE_PURPOSE (tail))[j] == '+') { error ("input operand constraint contains `%c'", TREE_STRING_POINTER (TREE_PURPOSE (tail))[j]); return; } XVECEXP (body, 3, i) /* argvec */ = expand_expr (TREE_VALUE (tail), 0, VOIDmode, 0); 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)), i, argvec, constraints, filename, line)); MEM_VOLATILE_P (SET_SRC (XVECEXP (body, 0, i))) = vol; } /* If there are no outputs (but there are some clobbers) store the bare ASM_OPERANDS into the PARALLEL. */ if (i == 0) XVECEXP (body, 0, i++) = obody; /* Store (clobber REG) for each clobbered register specified. */ for (tail = clobbers; tail; tail = TREE_CHAIN (tail), i++) { int j; char *regname = TREE_STRING_POINTER (TREE_VALUE (tail)); extern char *reg_names[]; for (j = 0; j < FIRST_PSEUDO_REGISTER; j++) if (!strcmp (regname, reg_names[j])) break; if (j == FIRST_PSEUDO_REGISTER) { error ("unknown register name `%s' in `asm'", regname); return; } /* Use QImode since that's guaranteed to clobber just one reg. */ XVECEXP (body, 0, i) = gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, QImode, j)); } insn = emit_insn (body); } last_expr_type = 0;}/* Nonzero if within a ({...}) grouping, in which case we must always compute a value for each expr-stmt in case it is the last one. */int expr_stmts_for_value;/* Generate RTL to evaluate the expression EXP and remember it in case this is the VALUE in a ({... VALUE; }) constr. */voidexpand_expr_stmt (exp) tree exp;{ /* If -W, warn about statements with no side effects, except inside a ({...}) where they may be useful. */ if (expr_stmts_for_value == 0 && exp != error_mark_node) { if (! TREE_VOLATILE (exp) && (extra_warnings || warn_unused)) warning_with_file_and_line (emit_filename, emit_lineno, "statement with no effect"); else if (warn_unused) warn_if_unused_value (exp); } last_expr_type = TREE_TYPE (exp); if (! flag_syntax_only) last_expr_value = expand_expr (exp, expr_stmts_for_value ? 0 : const0_rtx, VOIDmode, 0); emit_queue ();}/* Warn if EXP contains any computations whose results are not used. Return 1 if a warning is printed; 0 otherwise. */static intwarn_if_unused_value (exp) tree exp;{ switch (TREE_CODE (exp)) { case PREINCREMENT_EXPR: case POSTINCREMENT_EXPR: case PREDECREMENT_EXPR: case POSTDECREMENT_EXPR: case MODIFY_EXPR: case INIT_EXPR: case NEW_EXPR: case DELETE_EXPR: case PUSH_EXPR: case POP_EXPR: case CALL_EXPR: case METHOD_CALL_EXPR: case RTL_EXPR: case WRAPPER_EXPR: case ANTI_WRAPPER_EXPR: case WITH_CLEANUP_EXPR: /* We don't warn about COND_EXPR because it may be a useful construct if either arm contains a side effect. */ case COND_EXPR: return 0; case TRUTH_ORIF_EXPR: case TRUTH_ANDIF_EXPR: /* In && or ||, warn if 2nd operand has no side effect. */ return warn_if_unused_value (TREE_OPERAND (exp, 1)); case COMPOUND_EXPR: if (warn_if_unused_value (TREE_OPERAND (exp, 0))) return 1; return warn_if_unused_value (TREE_OPERAND (exp, 1)); case NOP_EXPR: case CONVERT_EXPR: /* Don't warn about values cast to void. */ if (TREE_TYPE (exp) == void_type_node) return 0; /* Assignment to a cast results in a cast of a modify. Don't complain about that. */ if (TREE_CODE (TREE_OPERAND (exp, 0)) == MODIFY_EXPR) return 0; default: warning_with_file_and_line (emit_filename, emit_lineno, "value computed is not used"); return 1; }}/* Clear out the memory of the last expression evaluated. */voidclear_last_expr (){ last_expr_type = 0;}/* Begin a statement which will return a value. Return the RTL_EXPR for this statement expr. The caller must save that value and pass it to expand_end_stmt_expr. */treeexpand_start_stmt_expr (){ rtx save = start_sequence (); /* Make the RTL_EXPR node temporary, not momentary, so that rtl_expr_chain doesn't become garbage. */ int momentary = suspend_momentary (); tree t = make_node (RTL_EXPR); resume_momentary (momentary); RTL_EXPR_RTL (t) = save; NO_DEFER_POP; expr_stmts_for_value++; return t;}/* Restore the previous state at the end of a statement that returns a value. Returns a tree node representing the statement's value and the insns to compute the value. The nodes of that expression have been freed by now, so we cannot use them. But we don't want to do that anyway; the expression has already been evaluated and now we just want to use the value. So generate a RTL_EXPR with the proper type and RTL value. If the last substatement was not an expression, return something with type `void'. */treeexpand_end_stmt_expr (t) tree t;{ rtx saved = RTL_EXPR_RTL (t); emit_queue (); OK_DEFER_POP; if (last_expr_type == 0) { last_expr_type = void_type_node; last_expr_value = const0_rtx; } else if (last_expr_value == 0) /* There are some cases where this can happen, such as when the statement is void type. */ last_expr_value = const0_rtx; else last_expr_value = protect_from_queue (last_expr_value, 0); TREE_TYPE (t) = last_expr_type; RTL_EXPR_RTL (t) = last_expr_value; RTL_EXPR_SEQUENCE (t) = get_insns (); rtl_expr_chain = tree_cons (NULL_TREE, t, rtl_expr_chain); end_sequence (saved); /* Don't consider deleting this expr or containing exprs at tree level. */ TREE_VOLATILE (t) = 1; /* Propagate volatility of the actual RTL expr. */ TREE_THIS_VOLATILE (t) = volatile_refs_p (last_expr_value); last_expr_type = 0; expr_stmts_for_value--; return t;}/* Generate RTL for the start of an if-then. COND is the expression whose truth should be tested. If EXITFLAG is nonzero, this conditional is visible to `exit_something'. */voidexpand_start_cond (cond, exitflag) tree cond; int exitflag;{ struct nesting *thiscond = (struct nesting *) xmalloc (sizeof (struct nesting)); /* Make an entry on cond_stack for the cond we are entering. */ thiscond->next = cond_stack; thiscond->all = nesting_stack; thiscond->depth = ++nesting_depth; thiscond->data.cond.after_label = 0; thiscond->data.cond.else_label = gen_label_rtx (); thiscond->exit_label = exitflag ? thiscond->data.cond.else_label : 0; cond_stack = thiscond; nesting_stack = thiscond; do_jump (cond, thiscond->data.cond.else_label, NULL);}/* Generate RTL for the end of an if-then with no else-clause. Pop the record for it off of cond_stack. */voidexpand_end_cond (){ struct nesting *thiscond = cond_stack; do_pending_stack_adjust (); emit_label (thiscond->data.cond.else_label); POPSTACK (cond_stack); last_expr_type = 0;}/* Generate RTL between the then-clause and the else-clause of an if-then-else. */voidexpand_start_else (){ cond_stack->data.cond.after_label = gen_label_rtx (); if (cond_stack->exit_label != 0) cond_stack->exit_label = cond_stack->data.cond.after_label; emit_jump (cond_stack->data.cond.after_label); if (cond_stack->data.cond.else_label) emit_label (cond_stack->data.cond.else_label);}/* Generate RTL for the end of an if-then-else. Pop the record for it off of cond_stack. */voidexpand_end_else (){ struct nesting *thiscond = cond_stack; do_pending_stack_adjust (); /* Note: a syntax error can cause this to be called without first calling `expand_start_else'. */ if (thiscond->data.cond.after_label) emit_label (thiscond->data.cond.after_label); POPSTACK (cond_stack); last_expr_type = 0;}/* Generate RTL for the start of a loop. EXIT_FLAG is nonzero if this loop should be exited by `exit_something'. This is a loop for which `expand_continue' will jump to the top of the loop.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -