📄 stmt.c
字号:
error ("matching constraint references invalid operand number"); return; } /* ... fall through ... */ 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_temp (type, 1, 1, 1); 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 - ninout; 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); /* For in-out operands, copy output rtx to input rtx. */ for (i = 0; i < ninout; i++) { static char match[9+1][2] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}; int j = inout_opnum[i]; XVECEXP (body, 3, ninputs - ninout + i) /* argvec */ = output_rtx[j]; XVECEXP (body, 4, ninputs - ninout + i) /* constraints */ = gen_rtx (ASM_INPUT, inout_mode[j], match[j]); } /* 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)) { char *regname = TREE_STRING_POINTER (TREE_VALUE (tail)); int j = decode_reg_name (regname); if (j < 0) { if (j == -3) /* `cc', which is not a register */ continue; if (j == -4) /* `memory', don't cache memory across asm */ { XVECEXP (body, 0, i++) = gen_rtx (CLOBBER, VOIDmode, gen_rtx (MEM, BLKmode, gen_rtx (SCRATCH, VOIDmode, 0))); continue; } /* Ignore unknown register, error already signaled. */ continue; } /* 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); } free_temp_slots ();}/* 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 (output_bytecode) { int org_stack_depth = stack_depth; bc_expand_expr (exp); /* Restore stack depth */ if (stack_depth < org_stack_depth) abort (); bc_emit_instruction (drop); last_expr_type = TREE_TYPE (exp); return; } /* If -W, warn about statements with no side effects, except for an explicit cast to void (e.g. for assert()), and except inside a ({...}) where they may be useful. */ if (expr_stmts_for_value == 0 && exp != error_mark_node) { if (! TREE_SIDE_EFFECTS (exp) && (extra_warnings || warn_unused) && !(TREE_CODE (exp) == CONVERT_EXPR && TREE_TYPE (exp) == void_type_node)) warning_with_file_and_line (emit_filename, emit_lineno, "statement with no effect"); else if (warn_unused) warn_if_unused_value (exp); } /* If EXP is of function type and we are expanding statements for value, convert it to pointer-to-function. */ if (expr_stmts_for_value && TREE_CODE (TREE_TYPE (exp)) == FUNCTION_TYPE) exp = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (exp)), exp); last_expr_type = TREE_TYPE (exp); if (! flag_syntax_only) last_expr_value = expand_expr (exp, (expr_stmts_for_value ? NULL_RTX : const0_rtx), VOIDmode, 0); /* If all we do is reference a volatile value in memory, copy it to a register to be sure it is actually touched. */ if (last_expr_value != 0 && GET_CODE (last_expr_value) == MEM && TREE_THIS_VOLATILE (exp)) { if (TYPE_MODE (TREE_TYPE (exp)) == VOIDmode) ; else if (TYPE_MODE (TREE_TYPE (exp)) != BLKmode) copy_to_reg (last_expr_value); else { rtx lab = gen_label_rtx (); /* Compare the value with itself to reference it. */ emit_cmp_insn (last_expr_value, last_expr_value, EQ, expand_expr (TYPE_SIZE (last_expr_type), NULL_RTX, VOIDmode, 0), BLKmode, 0, TYPE_ALIGN (last_expr_type) / BITS_PER_UNIT); emit_jump_insn ((*bcc_gen_fctn[(int) EQ]) (lab)); emit_label (lab); } } /* If this expression is part of a ({...}) and is in memory, we may have to preserve temporaries. */ preserve_temp_slots (last_expr_value); /* Free any temporaries used to evaluate this expression. Any temporary used as a result of this expression will already have been preserved above. */ free_temp_slots (); emit_queue ();}/* Warn if EXP contains any computations whose results are not used. Return 1 if a warning is printed; 0 otherwise. */intwarn_if_unused_value (exp) tree exp;{ if (TREE_USED (exp)) return 0; switch (TREE_CODE (exp)) { case PREINCREMENT_EXPR: case POSTINCREMENT_EXPR: case PREDECREMENT_EXPR: case POSTDECREMENT_EXPR: case MODIFY_EXPR: case INIT_EXPR: case TARGET_EXPR: case CALL_EXPR: case METHOD_CALL_EXPR: case RTL_EXPR: case WITH_CLEANUP_EXPR: case EXIT_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 BIND_EXPR: /* For a binding, warn if no side effect within it. */ return warn_if_unused_value (TREE_OPERAND (exp, 1)); case SAVE_EXPR: return warn_if_unused_value (TREE_OPERAND (exp, 1)); 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 (TREE_NO_UNUSED_WARNING (exp)) return 0; if (warn_if_unused_value (TREE_OPERAND (exp, 0))) return 1; /* Let people do `(foo (), 0)' without a warning. */ if (TREE_CONSTANT (TREE_OPERAND (exp, 1))) return 0; return warn_if_unused_value (TREE_OPERAND (exp, 1)); case NOP_EXPR: case CONVERT_EXPR: case NON_LVALUE_EXPR: /* Don't warn about values cast to void. */ if (TREE_TYPE (exp) == void_type_node) return 0; /* Don't warn about conversions not explicit in the user's program. */ if (TREE_NO_UNUSED_WARNING (exp)) return 0; /* Assignment to a cast usually results in a cast of a modify. Don't complain about that. There can be an arbitrary number of casts before the modify, so we must loop until we find the first non-cast expression and then test to see if that is a modify. */ { tree tem = TREE_OPERAND (exp, 0); while (TREE_CODE (tem) == CONVERT_EXPR || TREE_CODE (tem) == NOP_EXPR) tem = TREE_OPERAND (tem, 0); if (TREE_CODE (tem) == MODIFY_EXPR || TREE_CODE (tem) == INIT_EXPR || TREE_CODE (tem) == CALL_EXPR) return 0; } goto warn; case INDIRECT_REF: /* Don't warn about automatic dereferencing of references, since the user cannot control it. */ if (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == REFERENCE_TYPE) return warn_if_unused_value (TREE_OPERAND (exp, 0)); /* ... fall through ... */ default: /* Referencing a volatile value is a side effect, so don't warn. */ if ((TREE_CODE_CLASS (TREE_CODE (exp)) == 'd' || TREE_CODE_CLASS (TREE_CODE (exp)) == 'r') && TREE_THIS_VOLATILE (exp)) return 0; warn: 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 (){ int momentary; tree t; /* When generating bytecode just note down the stack depth */ if (output_bytecode) return (build_int_2 (stack_depth, 0)); /* Make the RTL_EXPR node temporary, not momentary, so that rtl_expr_chain doesn't become garbage. */ momentary = suspend_momentary (); t = make_node (RTL_EXPR); resume_momentary (momentary); do_pending_stack_adjust (); start_sequence_for_rtl_expr (t); 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;{ if (output_bytecode) { int i; tree t; /* At this point, all expressions have been evaluated in order. However, all expression values have been popped when evaluated, which means we have to recover the last expression value. This is the last value removed by means of a `drop' instruction. Instead of adding code to inhibit dropping the last expression value, it is here recovered by undoing the `drop'. Since `drop' is equivalent to `adjustackSI [1]', it can be undone with `adjstackSI [-1]'. */ bc_adjust_stack (-1); if (!last_expr_type) last_expr_type = void_type_node; t = make_node (RTL_EXPR); T
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -