You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@harmony.apache.org by Mikhail Fursov <mi...@gmail.com> on 2007/02/01 10:34:54 UTC

Re: [Drlvm][Opt]Some Questions about LIR expressions

Hi Zouqiong,
here are answers:

On 1/31/07, zouqiong <us...@gmail.com> wrote:
>
> Sorry, I still have two questions.
> 1.
>
> What is the difference between newOpnd, newImmOpnd and newMemOpnd?


Here is an extraction from sources that describes the difference:
Opnd * IRManager::newImmOpnd(Type * type, int64 immediate)
{
    Opnd * opnd = newOpnd(type);
    opnd->assignImmValue(immediate);
    return opnd;
}

Opnd * IRManager::newMemOpnd(Type * type, MemOpndKind k, Opnd * base, Opnd *
index, Opnd * scale, Opnd * displacement, RegName segReg)
{
    Opnd * opnd = newOpnd(type);
    opnd->assignMemLocation(k,base,index,scale,displacement);
        if (segReg != RegName_Null)
            opnd->setSegReg(segReg);
    return opnd;
}


So newImmOpnd and newMemOpnd are simple wrappers for newOpnd



Opnd* baseOpnd= irManager.newImmOpnd(typeManager.getUnmanagedPtrType(
>                         typeManager.getUIntPtrType()),
> (POINTER_SIZE_INT)&current_obj_acc_record_pointer);
> Opnd* RefOpnd = irManager.newMemOpnd(typeManager.getUIntPtrType(),
>                                 MemOpndKind_Heap,
> baseOpnd_current_obj_acc_record_pointer, NULL, NULL, NULL);
> appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, RefOpnd,
> (Opnd*)elemBase));
>
>
> Opnd* memOpnd = irManager.newMemOpnd(typeManager.getUIntPtrType(),
>                          MemOpndKind_Heap,
> baseOpnd_current_obj_acc_record_pointer, NULL, NULL, NULL);
> appendInsts(irManager.newInst(Mnemonic_SUB,memOpnd, irManager.newImmOpnd(
> typeManager.getUInt32Type(), 16)));
>
>
> What's the difference between memOpnd and baseOpnd?


Mem-opnd contains up to 4 opnds: base,index,scale,and displacement. So
mem-opnd is used to support complex address form in LIR.


I look the code emitted as below,  It seems that they have no difference.
>
> mov 0xb40534, %esi
> mov %ebp, (%esi)
>
> mov 0xb40534, %ebp
> subl 0x10, 0x0(%ebp)
>
> 2. If I want to generate such code:
> mov 0xb400534, %esi
> mov (%esi), %esi
>
> How should I write the LIR?


If you want to preserve register, use newRegOpnd with the register name. It
will add additional constraint to opnd.
If you want save value by address, create new mem-opnd with a base opnd
contains address and use newCopyPseudoInst to put new value to the address
represented by mem-opnd.


Feel free to ask more if you have questions..
-- 
Mikhail Fursov

Re: [Drlvm][Opt]Some Questions about LIR expressions

Posted by zouqiong <us...@gmail.com>.
Mikhail, thanks,  With your help, I understand it now :)

2007/2/2, Mikhail Fursov <mi...@gmail.com>:
>
> + some more details:
> > Opnd* baseOpnd = irManager.newImmOpnd(typeManager.getUnmanagedPtrType(
> > typeManager.getUIntPtrType()), (POINTER_SIZE_INT)&g_Address);
> > Opnd* memOpnd = irManager.newMemOpnd(typeManager.getUIntPtrType
> > (),MemOpndKind_Heap,baseOpnd,NULL, NULL, NULL);
>
> These 2 above are equivalent to the followin C code:
>
> [pseudo-code] Address memOpnd = (Address)&g_Address; // here, the
> &g_Address
> presumed to be the global static var
>
> Now, if you want to write to this, then
> [pseudo-code] *(int*)memOpnd = 0xFFFFFF;
>
> Is this what you're trying to achieve?
>
> If yes, then in LIR this is
>     Inst* inst = irManager.newCopyPseudoInst(Mnemonic_MOV, memOpnd,
> your0xFFFF);
>
>
> On 2/2/07, Mikhail Fursov <mi...@gmail.com> wrote:
> >
> > Zouqiong,
> > LIR is very lowlevel representation and you are allowed to use only x86
> > commands. See "Pentium4. Instruction reference set" for instructions
> details
> > every time you are not sure in results.
> >
> > The problem is that you can't encode mov [mem], [mem] in a single
> > instruction and have to use 2 instructions and intermediate value here.
> > Did I understand your problem right?
> >
> > On 2/1/07, zouqiong <us...@gmail.com> wrote:
> > >
> > > 2007/2/1, Mikhail Fursov <mi...@gmail.com>:
> > > >
> > > > Hi Zouqiong,
> > > > here are answers:
> > > >
> > > > On 1/31/07, zouqiong < ustczz@gmail.com> wrote:
> > > > >
> > > > > Sorry, I still have two questions.
> > > > > 1.
> > > > >
> > > > > What is the difference between newOpnd, newImmOpnd and newMemOpnd?
> > > >
> > > >
> > > > Here is an extraction from sources that describes the difference:
> > > > Opnd * IRManager::newImmOpnd(Type * type, int64 immediate)
> > > > {
> > > >     Opnd * opnd = newOpnd(type);
> > > >     opnd->assignImmValue(immediate);
> > > >     return opnd;
> > > > }
> > > >
> > > > Opnd * IRManager::newMemOpnd(Type * type, MemOpndKind k, Opnd *
> base,
> > > Opnd
> > > > *
> > > > index, Opnd * scale, Opnd * displacement, RegName segReg)
> > > > {
> > > >     Opnd * opnd = newOpnd(type);
> > > >     opnd->assignMemLocation(k,base,index,scale,displacement);
> > > >         if (segReg != RegName_Null)
> > > >             opnd->setSegReg(segReg);
> > > >     return opnd;
> > > > }
> > > >
> > > >
> > > > So newImmOpnd and newMemOpnd are simple wrappers for newOpnd
> > > >
> > > >
> > > >
> > > > Opnd* baseOpnd= irManager.newImmOpnd(typeManager.getUnmanagedPtrType
> (
> > > > >                         typeManager.getUIntPtrType()),
> > > > > (POINTER_SIZE_INT)&current_obj_acc_record_pointer);
> > > > > Opnd* RefOpnd = irManager.newMemOpnd(typeManager.getUIntPtrType(),
> > > > >                                 MemOpndKind_Heap,
> > > > > baseOpnd_current_obj_acc_record_pointer, NULL, NULL, NULL);
> > > > > appendInsts( irManager.newCopyPseudoInst(Mnemonic_MOV, RefOpnd,
> > > > > (Opnd*)elemBase));
> > > > >
> > > > >
> > > > > Opnd* memOpnd = irManager.newMemOpnd(typeManager.getUIntPtrType(),
> > > > >                          MemOpndKind_Heap,
> > > > > baseOpnd_current_obj_acc_record_pointer, NULL, NULL, NULL);
> > > > > appendInsts(irManager.newInst(Mnemonic_SUB,memOpnd,
> > > irManager.newImmOpnd
> > > > (
> > > > > typeManager.getUInt32Type(), 16)));
> > > > >
> > > > >
> > > > > What's the difference between memOpnd and baseOpnd?
> > > >
> > > >
> > > > Mem-opnd contains up to 4 opnds: base,index,scale,and displacement.
> So
> > > > mem-opnd is used to support complex address form in LIR.
> > > >
> > > >
> > > > I look the code emitted as below,  It seems that they have no
> > > difference.
> > > > >
> > > > > mov 0xb40534, %esi
> > > > > mov %ebp, (%esi)
> > > > >
> > > > > mov 0xb40534, %ebp
> > > > > subl 0x10, 0x0(%ebp)
> > > > >
> > > > > 2. If I want to generate such code:
> > > > > mov 0xb400534, %esi
> > > > > mov (%esi), %esi
> > > > >
> > > > > How should I write the LIR?
> > > >
> > > >
> > > > If you want to preserve register, use newRegOpnd with the register
> > > name.
> > > > It
> > > > will add additional constraint to opnd.
> > > > If you want save value by address, create new mem-opnd with a base
> > > opnd
> > > > contains address and use newCopyPseudoInst to put new value to the
> > > address
> > > > represented by mem-opnd.
> > > >
> > > >
> > > > Feel free to ask more if you have questions..
> > > > --
> > > > Mikhail Fursov
> > > >
> > > Thanks, Mikhail, you are very very very kind! :-)
> > >
> > > I want to use  value load from some address to index the memory.
> > >
> > > Opnd* baseOpnd = irManager.newImmOpnd(typeManager.getUnmanagedPtrType(
> > > typeManager.getUIntPtrType ()), (POINTER_SIZE_INT)&Address);
> > > Opnd* memOpnd = irManager.newMemOpnd(typeManager.getUIntPtrType
> > > (),MemOpndKind_Heap,baseOpnd,NULL, NULL, NULL);
> > >
> > > memOpnd means Address, right?
> > >
> > > I want to write to the memory pointed by Address. But I can't use the
> > > memOpnd as a base opnd of a mem opnd.
> > >
> > > In fact
> > >
> > > Opnd* RefOpnd =
> > > irManager.newMemOpnd(typeManager.getUIntPtrType(),MemOpndKind_Heap,
> > > memOpnd, NULL, NULL, NULL);
> > >
> > > will cause error.
> > >
> > > I don't know whether I have expressed myself rightly.
> > >
> > > Thanks
> > > Qiong
> > >
> > > --
> > > Best Regards,
> > > Qiong,Zou
> > >
> >
> >
> >
> > --
> > Mikhail Fursov
>
>
>
>
> --
> Mikhail Fursov
>



-- 
Best Regards,
Qiong,Zou

Re: [Drlvm][Opt]Some Questions about LIR expressions

Posted by Mikhail Fursov <mi...@gmail.com>.
+ some more details:
> Opnd* baseOpnd = irManager.newImmOpnd(typeManager.getUnmanagedPtrType(
> typeManager.getUIntPtrType()), (POINTER_SIZE_INT)&g_Address);
> Opnd* memOpnd = irManager.newMemOpnd(typeManager.getUIntPtrType
> (),MemOpndKind_Heap,baseOpnd,NULL, NULL, NULL);

These 2 above are equivalent to the followin C code:

[pseudo-code] Address memOpnd = (Address)&g_Address; // here, the &g_Address
presumed to be the global static var

Now, if you want to write to this, then
[pseudo-code] *(int*)memOpnd = 0xFFFFFF;

Is this what you're trying to achieve?

If yes, then in LIR this is
    Inst* inst = irManager.newCopyPseudoInst(Mnemonic_MOV, memOpnd,
your0xFFFF);


On 2/2/07, Mikhail Fursov <mi...@gmail.com> wrote:
>
> Zouqiong,
> LIR is very lowlevel representation and you are allowed to use only x86
> commands. See "Pentium4. Instruction reference set" for instructions details
> every time you are not sure in results.
>
> The problem is that you can't encode mov [mem], [mem] in a single
> instruction and have to use 2 instructions and intermediate value here.
> Did I understand your problem right?
>
> On 2/1/07, zouqiong <us...@gmail.com> wrote:
> >
> > 2007/2/1, Mikhail Fursov <mi...@gmail.com>:
> > >
> > > Hi Zouqiong,
> > > here are answers:
> > >
> > > On 1/31/07, zouqiong < ustczz@gmail.com> wrote:
> > > >
> > > > Sorry, I still have two questions.
> > > > 1.
> > > >
> > > > What is the difference between newOpnd, newImmOpnd and newMemOpnd?
> > >
> > >
> > > Here is an extraction from sources that describes the difference:
> > > Opnd * IRManager::newImmOpnd(Type * type, int64 immediate)
> > > {
> > >     Opnd * opnd = newOpnd(type);
> > >     opnd->assignImmValue(immediate);
> > >     return opnd;
> > > }
> > >
> > > Opnd * IRManager::newMemOpnd(Type * type, MemOpndKind k, Opnd * base,
> > Opnd
> > > *
> > > index, Opnd * scale, Opnd * displacement, RegName segReg)
> > > {
> > >     Opnd * opnd = newOpnd(type);
> > >     opnd->assignMemLocation(k,base,index,scale,displacement);
> > >         if (segReg != RegName_Null)
> > >             opnd->setSegReg(segReg);
> > >     return opnd;
> > > }
> > >
> > >
> > > So newImmOpnd and newMemOpnd are simple wrappers for newOpnd
> > >
> > >
> > >
> > > Opnd* baseOpnd= irManager.newImmOpnd(typeManager.getUnmanagedPtrType(
> > > >                         typeManager.getUIntPtrType()),
> > > > (POINTER_SIZE_INT)&current_obj_acc_record_pointer);
> > > > Opnd* RefOpnd = irManager.newMemOpnd(typeManager.getUIntPtrType(),
> > > >                                 MemOpndKind_Heap,
> > > > baseOpnd_current_obj_acc_record_pointer, NULL, NULL, NULL);
> > > > appendInsts( irManager.newCopyPseudoInst(Mnemonic_MOV, RefOpnd,
> > > > (Opnd*)elemBase));
> > > >
> > > >
> > > > Opnd* memOpnd = irManager.newMemOpnd(typeManager.getUIntPtrType(),
> > > >                          MemOpndKind_Heap,
> > > > baseOpnd_current_obj_acc_record_pointer, NULL, NULL, NULL);
> > > > appendInsts(irManager.newInst(Mnemonic_SUB,memOpnd,
> > irManager.newImmOpnd
> > > (
> > > > typeManager.getUInt32Type(), 16)));
> > > >
> > > >
> > > > What's the difference between memOpnd and baseOpnd?
> > >
> > >
> > > Mem-opnd contains up to 4 opnds: base,index,scale,and displacement. So
> > > mem-opnd is used to support complex address form in LIR.
> > >
> > >
> > > I look the code emitted as below,  It seems that they have no
> > difference.
> > > >
> > > > mov 0xb40534, %esi
> > > > mov %ebp, (%esi)
> > > >
> > > > mov 0xb40534, %ebp
> > > > subl 0x10, 0x0(%ebp)
> > > >
> > > > 2. If I want to generate such code:
> > > > mov 0xb400534, %esi
> > > > mov (%esi), %esi
> > > >
> > > > How should I write the LIR?
> > >
> > >
> > > If you want to preserve register, use newRegOpnd with the register
> > name.
> > > It
> > > will add additional constraint to opnd.
> > > If you want save value by address, create new mem-opnd with a base
> > opnd
> > > contains address and use newCopyPseudoInst to put new value to the
> > address
> > > represented by mem-opnd.
> > >
> > >
> > > Feel free to ask more if you have questions..
> > > --
> > > Mikhail Fursov
> > >
> > Thanks, Mikhail, you are very very very kind! :-)
> >
> > I want to use  value load from some address to index the memory.
> >
> > Opnd* baseOpnd = irManager.newImmOpnd(typeManager.getUnmanagedPtrType(
> > typeManager.getUIntPtrType ()), (POINTER_SIZE_INT)&Address);
> > Opnd* memOpnd = irManager.newMemOpnd(typeManager.getUIntPtrType
> > (),MemOpndKind_Heap,baseOpnd,NULL, NULL, NULL);
> >
> > memOpnd means Address, right?
> >
> > I want to write to the memory pointed by Address. But I can't use the
> > memOpnd as a base opnd of a mem opnd.
> >
> > In fact
> >
> > Opnd* RefOpnd =
> > irManager.newMemOpnd(typeManager.getUIntPtrType(),MemOpndKind_Heap,
> > memOpnd, NULL, NULL, NULL);
> >
> > will cause error.
> >
> > I don't know whether I have expressed myself rightly.
> >
> > Thanks
> > Qiong
> >
> > --
> > Best Regards,
> > Qiong,Zou
> >
>
>
>
> --
> Mikhail Fursov




-- 
Mikhail Fursov

Re: [Drlvm][Opt]Some Questions about LIR expressions

Posted by Mikhail Fursov <mi...@gmail.com>.
Zouqiong,
LIR is very lowlevel representation and you are allowed to use only x86
commands. See "Pentium4. Instruction reference set" for instructions details
every time you are not sure in results.

The problem is that you can't encode mov [mem], [mem] in a single
instruction and have to use 2 instructions and intermediate value here.
Did I understand your problem right?

On 2/1/07, zouqiong <us...@gmail.com> wrote:
>
> 2007/2/1, Mikhail Fursov <mi...@gmail.com>:
> >
> > Hi Zouqiong,
> > here are answers:
> >
> > On 1/31/07, zouqiong <us...@gmail.com> wrote:
> > >
> > > Sorry, I still have two questions.
> > > 1.
> > >
> > > What is the difference between newOpnd, newImmOpnd and newMemOpnd?
> >
> >
> > Here is an extraction from sources that describes the difference:
> > Opnd * IRManager::newImmOpnd(Type * type, int64 immediate)
> > {
> >     Opnd * opnd = newOpnd(type);
> >     opnd->assignImmValue(immediate);
> >     return opnd;
> > }
> >
> > Opnd * IRManager::newMemOpnd(Type * type, MemOpndKind k, Opnd * base,
> Opnd
> > *
> > index, Opnd * scale, Opnd * displacement, RegName segReg)
> > {
> >     Opnd * opnd = newOpnd(type);
> >     opnd->assignMemLocation(k,base,index,scale,displacement);
> >         if (segReg != RegName_Null)
> >             opnd->setSegReg(segReg);
> >     return opnd;
> > }
> >
> >
> > So newImmOpnd and newMemOpnd are simple wrappers for newOpnd
> >
> >
> >
> > Opnd* baseOpnd= irManager.newImmOpnd(typeManager.getUnmanagedPtrType(
> > >                         typeManager.getUIntPtrType()),
> > > (POINTER_SIZE_INT)&current_obj_acc_record_pointer);
> > > Opnd* RefOpnd = irManager.newMemOpnd(typeManager.getUIntPtrType(),
> > >                                 MemOpndKind_Heap,
> > > baseOpnd_current_obj_acc_record_pointer, NULL, NULL, NULL);
> > > appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, RefOpnd,
> > > (Opnd*)elemBase));
> > >
> > >
> > > Opnd* memOpnd = irManager.newMemOpnd(typeManager.getUIntPtrType(),
> > >                          MemOpndKind_Heap,
> > > baseOpnd_current_obj_acc_record_pointer, NULL, NULL, NULL);
> > > appendInsts(irManager.newInst(Mnemonic_SUB,memOpnd,
> irManager.newImmOpnd
> > (
> > > typeManager.getUInt32Type(), 16)));
> > >
> > >
> > > What's the difference between memOpnd and baseOpnd?
> >
> >
> > Mem-opnd contains up to 4 opnds: base,index,scale,and displacement. So
> > mem-opnd is used to support complex address form in LIR.
> >
> >
> > I look the code emitted as below,  It seems that they have no
> difference.
> > >
> > > mov 0xb40534, %esi
> > > mov %ebp, (%esi)
> > >
> > > mov 0xb40534, %ebp
> > > subl 0x10, 0x0(%ebp)
> > >
> > > 2. If I want to generate such code:
> > > mov 0xb400534, %esi
> > > mov (%esi), %esi
> > >
> > > How should I write the LIR?
> >
> >
> > If you want to preserve register, use newRegOpnd with the register name.
> > It
> > will add additional constraint to opnd.
> > If you want save value by address, create new mem-opnd with a base opnd
> > contains address and use newCopyPseudoInst to put new value to the
> address
> > represented by mem-opnd.
> >
> >
> > Feel free to ask more if you have questions..
> > --
> > Mikhail Fursov
> >
> Thanks, Mikhail, you are very very very kind! :-)
>
> I want to use  value load from some address to index the memory.
>
> Opnd* baseOpnd = irManager.newImmOpnd(typeManager.getUnmanagedPtrType(
> typeManager.getUIntPtrType()), (POINTER_SIZE_INT)&Address);
> Opnd* memOpnd = irManager.newMemOpnd(typeManager.getUIntPtrType
> (),MemOpndKind_Heap,baseOpnd,NULL, NULL, NULL);
>
> memOpnd means Address, right?
>
> I want to write to the memory pointed by Address. But I can't use the
> memOpnd as a base opnd of a mem opnd.
>
> In fact
>
> Opnd* RefOpnd =
> irManager.newMemOpnd(typeManager.getUIntPtrType(),MemOpndKind_Heap,
> memOpnd, NULL, NULL, NULL);
>
> will cause error.
>
> I don't know whether I have expressed myself rightly.
>
> Thanks
> Qiong
>
> --
> Best Regards,
> Qiong,Zou
>



-- 
Mikhail Fursov

Re: [Drlvm][Opt]Some Questions about LIR expressions

Posted by zouqiong <us...@gmail.com>.
2007/2/1, Mikhail Fursov <mi...@gmail.com>:
>
> Hi Zouqiong,
> here are answers:
>
> On 1/31/07, zouqiong <us...@gmail.com> wrote:
> >
> > Sorry, I still have two questions.
> > 1.
> >
> > What is the difference between newOpnd, newImmOpnd and newMemOpnd?
>
>
> Here is an extraction from sources that describes the difference:
> Opnd * IRManager::newImmOpnd(Type * type, int64 immediate)
> {
>     Opnd * opnd = newOpnd(type);
>     opnd->assignImmValue(immediate);
>     return opnd;
> }
>
> Opnd * IRManager::newMemOpnd(Type * type, MemOpndKind k, Opnd * base, Opnd
> *
> index, Opnd * scale, Opnd * displacement, RegName segReg)
> {
>     Opnd * opnd = newOpnd(type);
>     opnd->assignMemLocation(k,base,index,scale,displacement);
>         if (segReg != RegName_Null)
>             opnd->setSegReg(segReg);
>     return opnd;
> }
>
>
> So newImmOpnd and newMemOpnd are simple wrappers for newOpnd
>
>
>
> Opnd* baseOpnd= irManager.newImmOpnd(typeManager.getUnmanagedPtrType(
> >                         typeManager.getUIntPtrType()),
> > (POINTER_SIZE_INT)&current_obj_acc_record_pointer);
> > Opnd* RefOpnd = irManager.newMemOpnd(typeManager.getUIntPtrType(),
> >                                 MemOpndKind_Heap,
> > baseOpnd_current_obj_acc_record_pointer, NULL, NULL, NULL);
> > appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, RefOpnd,
> > (Opnd*)elemBase));
> >
> >
> > Opnd* memOpnd = irManager.newMemOpnd(typeManager.getUIntPtrType(),
> >                          MemOpndKind_Heap,
> > baseOpnd_current_obj_acc_record_pointer, NULL, NULL, NULL);
> > appendInsts(irManager.newInst(Mnemonic_SUB,memOpnd, irManager.newImmOpnd
> (
> > typeManager.getUInt32Type(), 16)));
> >
> >
> > What's the difference between memOpnd and baseOpnd?
>
>
> Mem-opnd contains up to 4 opnds: base,index,scale,and displacement. So
> mem-opnd is used to support complex address form in LIR.
>
>
> I look the code emitted as below,  It seems that they have no difference.
> >
> > mov 0xb40534, %esi
> > mov %ebp, (%esi)
> >
> > mov 0xb40534, %ebp
> > subl 0x10, 0x0(%ebp)
> >
> > 2. If I want to generate such code:
> > mov 0xb400534, %esi
> > mov (%esi), %esi
> >
> > How should I write the LIR?
>
>
> If you want to preserve register, use newRegOpnd with the register name.
> It
> will add additional constraint to opnd.
> If you want save value by address, create new mem-opnd with a base opnd
> contains address and use newCopyPseudoInst to put new value to the address
> represented by mem-opnd.
>
>
> Feel free to ask more if you have questions..
> --
> Mikhail Fursov
>
Thanks, Mikhail, you are very very very kind! :-)

I want to use  value load from some address to index the memory.

Opnd* baseOpnd = irManager.newImmOpnd(typeManager.getUnmanagedPtrType(
typeManager.getUIntPtrType()), (POINTER_SIZE_INT)&Address);
Opnd* memOpnd = irManager.newMemOpnd(typeManager.getUIntPtrType
(),MemOpndKind_Heap,baseOpnd,NULL, NULL, NULL);

memOpnd means Address, right?

I want to write to the memory pointed by Address. But I can't use the
memOpnd as a base opnd of a mem opnd.

In fact

Opnd* RefOpnd =
irManager.newMemOpnd(typeManager.getUIntPtrType(),MemOpndKind_Heap,
memOpnd, NULL, NULL, NULL);

will cause error.

I don't know whether I have expressed myself rightly.

Thanks
Qiong

-- 
Best Regards,
Qiong,Zou