one more question. I was going through this code here. the lines in bold are what happened when the second operand of the operation is a memory location. what is the IS_DEAD_ARG(1), is the register allocator doing some liveness analysis here ?
/* XXX: always mark arg dead if IS_DEAD_ARG(1) */
if (ts->val_type == TEMP_VAL_REG) { if (IS_DEAD_ARG(1) && !ts->fixed_reg && !ots->fixed_reg) { /* the mov can be suppressed */ if (ots->val_type == TEMP_VAL_REG)
s->reg_to_temp[ots->reg] = -1; reg = ts->reg; s->reg_to_temp[reg] = -1; ts->val_type = TEMP_VAL_DEAD; } else { if (ots->val_type == TEMP_VAL_REG) {
reg = ots->reg; } else { reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs); } if (ts->reg != reg) { tcg_out_mov(s, ots->type, reg, ts->reg);
} } } else if (ts->val_type == TEMP_VAL_MEM) { if (ots->val_type == TEMP_VAL_REG) { reg = ots->reg; } else { reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);
} tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
... }
Thanks
Xin
On Sun, Nov 27, 2011 at 7:32 PM, Xin Tong <address@hidden> wrote:
> Thank you very much. This is very helpful. > > Xin > > > On Sun, Nov 27, 2011 at 6:33 PM, Peter Maydell <address@hidden> wrote:
>> On 27 November 2011 23:07, Xin Tong <address@hidden> wrote: >>> can you please show me where the (120) is used. we pushed a global >>> TCGV to the gen_opparam_ptr. lets say the backend is i386 and the
>>> operation is an add. >> >> So, you can find it like this: >> >> (1) starting from tcg_global_mem_new_i64 we follow where that >> offset went, and we see that tcg_global_mem_new_internal stores
>> it in the mem_offset field of a TCGTemp structure. >> (2) So we grep for uses of mem_offset, and we find that tcg.c >> uses it in the register allocator; basically there are a lot >> of places where we say "if this is a TEMP_VAL_MEM then either
>> load or store the value". We do that load or store by calling >> tcg_out_ld() or tcg_out_st(), passing the mem_offset value >> (plus some other stuff like the base register and whatever
>> temporary register the allocator wants to use for it). >> (3) grepping for tcg_out_ld() we find it's implemented in the >> backends. Specifically, tcg/i386/tcg-target.c has the x86 >> version which writes out x86 code to do a load/store from
>> [reg+offset]. >> >> So we can deduce that TCG doesn't try to be particularly >> clever about these values -- we just load them when we need >> them and store them again when they are updated. (We don't
>> try to support issuing add instructions with memory operands >> even if the host CPU architecture has them.) >> >> I didn't particularly know this in advance -- I'm just looking
>> through the code and searching for uses of things and implementations >> of functions. QEMU's code generation is not particularly >> exotic: >> * guest-specific front end decodes instructions and writes
>> intermediate representation >> * optimisation pass that works on IR >> * liveness analysis (ie work out when data values are no >> longer needed, so we can reuse the registers they're in)
>> * turn IR into generated code by making calls to a handful >> of host-specific backend functions >> >> (about the only slightly unexpected thing is that we do the >> register allocation as we go along generating the final
>> code, rather than doing it as a separate pass.) >> So if you can get a grasp of the general structure then >> following through it to answer specific questions like this >> should be straightforward.
>> >> -- PMM >> >