/*****************************************************************************\
*                           Systems Research Group                            *
*******************************************************************************


                       #####    ######               ####
                      #######  ########             ######
                     ##        ##                  ##    ##
                     ##        ##  ####   #######        ##
                     ##        ##    ##                 ##
                     ##        ##    ##               ##
                      #######  ########             #######
                       #####    ######             ########


*******************************************************************************
*   I. D. Wilson           Last Modified   -   IDW   -   21/02/85             *
\*****************************************************************************/



SECTION "CG-2"


GET "LIBHDR"
GET "bcpl.cghdr"



LET cg.storeitem( node, type, value )  BE
$(
//  Store the expression represented by "node" into the location represented
//  by "type" and "value".

    LET v  =  evaluate( node )
    LET t  =  evaltype

    //  Having evaluated the expression, we had better store it in the
    //  location given.

    LET r  =  movetoanyr( t, v, TRUE )

    //  Now, store the register in the location given, and add this value
    //  to the information in the slave.

    IF  debugging & listing  THEN  writel( ";  Store [%N,%N] -> [%N,%N]", t, v, type, value )

    storeregister( r, type, value )

    //  Now remove any slave info relevant to the item being stored, and add
    //  the only correct one.

    scanslaveentries( type, value )

    addslaveinfo( r, type, value )

    //  We have now finished with the tree representing the expression, and
    //  it can now be freed.

    freenode( node )
$)



AND scanslaveentries( type, value )  BE
$(
//  Scan the slave entries, removing anything with a reference to "type" and
//  "value".

    FOR  r = r.hl  TO  r.bc  DO
    $(
        LET list  =  scanslaveentry( rinfo!r, type, value )

        unsetslave( r )

        rinfo!r  :=  list
    $)
$)



AND scanslaveentry( list, type, value )  =  list = NIL  ->  NIL,  VALOF
$(
//  Make a copy of the list "list", removing all references to "type" and
//  "value".

    LET l  =  list!l.link
    LET t  =  list!l.type
    LET v  =  list!l.value

    TEST  t = type  &  v = value
        THEN  RESULTIS  scanslaveentry( l, type, value )
        ELSE  RESULTIS  block3( scanslaveentry( l, type, value ), t, v )
$)



AND evaluate( node )  =  VALOF
$(
//  Evaluate the tree represented by "node".  The result is the register in
//  which the result is stored.

    LET type  =  node!n.type

    SWITCHON  type  INTO
    $(
        CASE t.local      :  CASE t.global     :
        CASE t.label      :  CASE t.number     :
        CASE t.lv.local   :  CASE t.lv.global  :
        CASE t.lv.label   :  CASE t.register   :
        CASE t.stack      :  CASE t.cherished  :

                             evaltype  :=  type

                             RESULTIS  node!n.arg1



        CASE s.plus       :  CASE s.minus      :
        CASE s.logand     :  CASE s.logor      :
        CASE s.eqv        :  CASE s.neqv       :
        CASE s.lshift     :  CASE s.rshift     :
        CASE s.mult       :  CASE s.div        :
        CASE s.rem        :  CASE s.eq         :
        CASE s.ne         :  CASE s.ls         :
        CASE s.gr         :  CASE s.le         :
        CASE s.ge         :  CASE s.getbyte    :

                             RESULTIS  cg.dyadic( type, node!n.arg1, node!n.arg2 )


        CASE s.neg        :  CASE s.not        :
        CASE s.abs        :  CASE s.rv         :

                             RESULTIS  cg.monadic( type, node!n.arg1 )


        DEFAULT           :  cgerror( "evaluate( %N )", type )
    $)
$)



AND cg.stind()  BE    pseudo.dyadic( s.stind, FALSE )



AND cg.putbyte()  BE  pseudo.dyadic( s.putbyte, TRUE )



AND pseudo.dyadic( op, swapargs )  BE
$(
//  Code generate for one of the pseudo dyadic operators (stind or putbyte).
//  This is a fudge, but it is by far the most efficient way of doing the
//  job.

    LET node1  =  arg1!a.node
    LET node2  =  arg2!a.node
    LET reg1   =  0
    LET reg2   =  0

    cg.stack( ssp-2 )

    //  It is possible that, in one of the nodes, there is a reference to
    //  the result register HL.  We must make sure that this register is
    //  saved on the BCPL stack if we are to avoid having problems with
    //  stack twisting!
    
    reg1  :=  scanforregister( node1 )
    reg2  :=  scanforregister( node2 )
    
    IF  reg1  &  reg2  THEN

        //  Oh dear - there was a register reference in both nodes, and
        //  so we should moan.

        cgerror( "pseudo.dyadic( 2regs )" )

    //  Having done that, we can safely swap the arguments if necessary, and
    //  get on with compiling the code for the operator.

    IF  swapargs  THEN
    $(
        LET node  =  node1

        node1  :=  node2
        node2  :=  node
    $)
    
    IF  op = s.putbyte  THEN
    
        //  If we are dealing with the "putbyte" operator, then there is a special
        //  case which we must consider.  This arises when the item being stored
        //  is the result of a function call (i.e. in HL).  The calculating of the
        //  address corrupts HL, and so we should store it now.
    
        IF  scanforregister( arg1!a.node )  &  (reg1 | reg2)  THEN
    
            //  Oh dear.  We have found register references in more than one
            //  place, and so we should complain about it.
        
            cgerror( "pseudo.dyadic( 2regs )" )

    cg.dyadic( op, node1, node2 )

    freenode( node1 )
    freenode( node2 )
$)



AND scanforregister( node )  =  VALOF
$(
//  Scan the data structure associated with the node given, and look for
//  a reference to the result register HL.  When found, we store this
//  register at its original location in the BCPL stack.

    LET type   =  node!n.type
    LET value  =  node!n.arg1
    LET ossp   =  0
    LET copy   =  0
    LET reg1   =  0
    LET reg2   =  0

    SWITCHON  type  INTO
    $(
        CASE t.register   :  //  This is a register node, and so we should
                             //  check that it refers to the right register,
                             //  and then save the register.

                             UNLESS  value = r.hl  DO

                                 //  This is the wrong register - oops!

                                 cgerror( "scanforregister( %N )", value )

                             //  This is the correct register, so call the
                             //  routine to store the register.

                             ossp         :=  node!n.arg2
                             copy         :=  block3( type, value, ossp )

                             cg.storeitem( copy, t.local, ossp )

                             node!n.type  :=  t.local
                             node!n.arg1  :=  ossp
                             node!n.arg2  :=  ossp

                             RESULTIS  TRUE


        CASE t.local      :  CASE t.global     :
        CASE t.label      :  CASE t.number     :
        CASE t.lv.local   :  CASE t.lv.global  :
        CASE t.lv.label   :  CASE t.stack      :
        CASE t.cherished  :

                             RESULTIS  FALSE


        CASE s.plus       :  CASE s.minus      :
        CASE s.logand     :  CASE s.logor      :
        CASE s.eqv        :  CASE s.neqv       :
        CASE s.lshift     :  CASE s.rshift     :
        CASE s.mult       :  CASE s.div        :
        CASE s.rem        :  CASE s.eq         :
        CASE s.ne         :  CASE s.ls         :
        CASE s.gr         :  CASE s.le         :
        CASE s.ge         :  CASE s.getbyte    :

                             reg1  :=  scanforregister( node!n.arg1 )
                             reg2  :=  scanforregister( node!n.arg2 )

                             IF  reg1  &  reg2  THEN

                                 //  Oh dear - registers in both halves of the
                                 //  expression, and so we should complain.

                                 cgerror( "scanforregister( 2regs )" )

                             RESULTIS  reg1  |  reg2


        CASE s.neg        :  CASE s.not        :
        CASE s.abs        :  CASE s.rv         :

                             RESULTIS  scanforregister( node!n.arg1 )


        DEFAULT           :  cgerror( "scanforregister( %N )", type )
    $)
$)



AND cg.dyadic( op, node1, node2 )  =  VALOF
$(
//  Evaluate a dyadic operator's operands, and generate code to evaluate the
//  expression.

    LET v1  =  0
    LET t1  =  0
    LET v2  =  0
    LET t2  =  0

    //  Before evaluating node 1, we should cherish node 2, if the value is
    //  a register.

    IF  node2!n.type = t.register  THEN
    $(
        //  The second argument is already in a register, so cherish it to
        //  stop it being clobbered by the evaluation of the first argument.

        LET r      =  node2!n.arg1
        LET rnode  =  block2( t.register, r )

        node2!n.type  :=  t.cherished
        node2!n.arg1  :=  rnode

        cherish( r, rnode )
    $)

    //  Now, evaluate the first argument, and see what sort of a revelation
    //  this brings.

    v1  :=  evaluate( node1 )
    t1  :=  evaltype

    //  Look at the data type of the first operand, and if it is a register
    //  then we must take special precautions to stop the register being
    //  destroyed.

    IF  t1 = t.register  THEN
    $(
        LET node  =  block2( t1, v1 )

        cherish( v1, node )

        t1  :=  t.cherished
        v1  :=  node
    $)

    //  Now evaluate the second argument.  We know that the first one will be
    //  safe, since it will be cherished if it is a register.

    v2  :=  evaluate( node2 )
    t2  :=  evaltype

    //  Having evaluated both operands, we can remove their cherished status

    IF  t1 = t.cherished  THEN
    $(
        LET node  =  v1

        t1  :=  node!n.type
        v1  :=  node!n.arg1

        IF  t1 = t.register  THEN  uncherish( v1 )

        freeblock2( node )
    $)

    IF  t2 = t.cherished  THEN
    $(
        LET node  =  v2

        t2  :=  node!n.type
        v2  :=  node!n.arg1

        IF  t2 = t.register  THEN  uncherish( v2 )

        freeblock2( node )
    $)

    //  First, look for the simple case where the operands are both numbers,
    //  and if they are, we can do some constant folding.

    IF  t1 = t.number  &  t2 = t.number  THEN
    $(
        evaltype  :=  t.number

        SWITCHON  op  INTO
        $(
            CASE s.plus       :  RESULTIS  v1  +   v2
            CASE s.minus      :  RESULTIS  v1  -   v2
            CASE s.logand     :  RESULTIS  v1  &   v2
            CASE s.logor      :  RESULTIS  v1  |   v2
            CASE s.eqv        :  RESULTIS  v1 EQV  v2
            CASE s.neqv       :  RESULTIS  v1 NEQV v2
            CASE s.lshift     :  RESULTIS  v1  <<  v2
            CASE s.rshift     :  RESULTIS  v1  >>  v2
            CASE s.mult       :  RESULTIS  v1  *   v2
            CASE s.div        :  RESULTIS  v1  /   v2
            CASE s.rem        :  RESULTIS  v1 REM  v2
            CASE s.eq         :  RESULTIS  v1  =   v2
            CASE s.ne         :  RESULTIS  v1  \=  v2
            CASE s.ls         :  RESULTIS  v1  <   v2
            CASE s.gr         :  RESULTIS  v1  >   v2
            CASE s.le         :  RESULTIS  v1  <=  v2
            CASE s.ge         :  RESULTIS  v1  >=  v2

            CASE s.getbyte    :
            CASE s.putbyte    :
            CASE s.stind      :  ENDCASE

            DEFAULT           :  cgerror( "cg.dyadic( %N )", op )
        $)
    $)

    //  Now, look at the case where only one of the operands is a constant,
    //  but it is one which can be optimised.  First, swap the operands if
    //  necessary.

    IF  symmetric( op )  &  t1 = t.number  THEN
    $(
        LET ot1  =  t1
        LET ov1  =  v1

        t1  :=  t2
        v1  :=  v2

        t2  :=  ot1
        v2  :=  ov1

        op  :=  reverse( op )
    $)

    //  Now look to see if the second operand is a number, and if it is,
    //  look to see if any optimisations can be done on it.

    IF  t2 = t.number  THEN
    $(
        //  If the number is zero, then many arithmetic operators become
        //  trivial.  This can be simulated here.

        IF  v2 = 0  THEN
            SWITCHON  op  INTO
            $(
                CASE s.plus       :
                CASE s.minus      :
                CASE s.logor      :
                CASE s.neqv       :
                CASE s.lshift     :
                CASE s.rshift     :  evaltype  :=  t1

                                     RESULTIS  v1


                CASE s.div        :
                CASE s.rem        :
                CASE s.logand     :
                CASE s.eqv        :
                CASE s.mult       :  evaltype  :=  t.number

                                     RESULTIS  0


                DEFAULT           :  ENDCASE
            $)

        //  If the second value is 1, then the multiplication/division
        //  operators become trivial.  Simulate this here.

        IF  v2 = 1  THEN
            SWITCHON  op  INTO
            $(
                CASE s.div        :
                CASE s.mult       :  evaltype  :=  t1

                                     RESULTIS  v1


                CASE s.rem        :  evaltype  :=  t.number

                                     RESULTIS  0


                DEFAULT           :  ENDCASE
            $)
    $)

    //  Otherwise, look to see if the operator is symmetric, and if so
    //  see if the second operand is already in a register.  If it is, then
    //  we can swap the operands.

    IF  symmetric( op )  &  t2 = t.register  THEN
    $(
        LET ot1  =  t1
        LET ov1  =  v1

        t1  :=  t2
        v1  :=  v2

        t2  :=  ot1
        v2  :=  ov1

        op     :=  reverse( op )
    $)

    //  At this point, we have decided that we do in fact need to compile
    //  some code to do the operation.  The code we compile depends very
    //  much on the operator concerned.

    SWITCHON  op  INTO
    $(
        CASE s.plus       :
        CASE s.minus      :  RESULTIS  cg.plusminus( op, t1, v1, t2, v2 )


        CASE s.logand     :
        CASE s.logor      :
        CASE s.eqv        :
        CASE s.neqv       :  RESULTIS  cg.logicalop( op, t1, v1, t2, v2 )


        CASE s.lshift     :  RESULTIS  cg.lshift( t1, v1, t2, v2 )


        CASE s.rshift     :  RESULTIS  cg.rshift( t1, v1, t2, v2 )


        CASE s.mult       :
        CASE s.div        :
        CASE s.rem        :
        CASE s.eq         :
        CASE s.ne         :
        CASE s.ls         :
        CASE s.gr         :
        CASE s.le         :
        CASE s.ge         :  RESULTIS  cg.stackop( op, t1, v1, t2, v2 )


        CASE s.getbyte    :
        CASE s.putbyte    :  RESULTIS  cg.byteop( op, t1, v1, t2, v2 )


        CASE s.stind      :  RESULTIS  cg.stindop( t1, v1, t2, v2 )


        DEFAULT           :  cgerror( "cg.dyadic( %N )", op )
    $)
$)



AND cg.plusminus( op, t1, v1, t2, v2 )  =  VALOF
$(
//  Generate code for a PLUS or MINUS operator.  At this point, we know that
//  the first operand may be in a register, and the second operand may be
//  a number.  If the second operand is a number, and is negative, then
//  we can alter the sign, and the corresponding operator.

    LET r  =  0

    IF  op = s.minus  &  t2 = t.number  THEN
    $(
        //  This is a negative number.  Make the number positive, and
        //  reverse the operator.

        op  :=  s.plus
        v2  :=  -v2
    $)

    //  If the second operand is a small number, then we can use the
    //  register increment and decrement instructions.

    IF  t2 = t.number  &  (-5 < v2 < +5)  THEN
    $(
        LET negv2  =  v2 < 0
        LET absv2  =  ABS v2
        LET inst   =  op = s.plus  ->  (negv2 -> i.dec, i.inc),
                   /* op = s.minus */  (negv2 -> i.inc, i.dec)

        r  :=  movetoanyr( t1, v1, FALSE )

        FOR  i = 1  TO  absv2  DO  code.ss.1( inst, r )

        UNLESS  absv2 = 0  DO  unsetslave( r )

        evaltype  :=  t.register

        RESULTIS  r
    $)

    //  Otherwise, there is nothing for it but to compile an ADD or an SBC
    //  instruction.  The target register must be HL, but the second operand
    //  can be in any register.

    IF  op = s.plus  &  (t1 = t.register  &  v1 \= r.hl)  THEN
    $(
        //  This is an addition, and the first operand is already in a
        //  register, but unfortunately the wrong one!  No matter, since
        //  we can swap the operands.

        LET ot1  =  t1
        LET ov1  =  v1

        t1  :=  t2
        v1  :=  v2
        t2  :=  ot1
        v2  :=  ov1
    $)

    //  We can now load the operands into their respective registers, and
    //  compile the instruction.  We must be very careful in which order
    //  we do the following moves (in case both arguments are on the stack,
    //  or the wrong argument is already in a register).

    TEST  (t1 = t.stack  &  t2 = t.stack  &  (v1 < v2))  |  t2 = t.register  THEN
    $(
        //  Items are on the stack in the wrong order, or the second value is
        //  already in a register.

        r  :=  movetoanybutr( r.hl, t2, v2, TRUE )

        movetor( r.hl, t1, v1 )
    $)
    ELSE
    $(
        //  The operands are on the stack and in the right order, or not on
        //  the stack at all.

        movetor( r.hl, t1, v1 )

        r  :=  movetoanybutr( r.hl, t2, v2, TRUE )
    $)

    TEST  op = s.plus  THEN  code.ss.1( i.addhl, r )
    ELSE
    $(
        code.s.1( i.or, r.a )
        code.ss.2( esc.ed, i.sbchl, r )

        //  In this case, and only in this case are the condition codes set
        //  ready for a branch.  Set the condition code flag to indicate
        //  this.

        compare.cc  :=  TRUE
    $)

    unsetslave( r.hl )

    evaltype  :=  t.register

    RESULTIS  r.hl
$)



AND cg.logicalop( op, t1, v1, t2, v2 )  =  VALOF
$(
//  Code generate for a logical operator, which is one of:
//
//      AND
//      OR
//      EQV
//      NEQV
//
//  All the operators are symmetric, and they will already have been put
//  the optimal way round for our purposes.  We must first put operand 1
//  into a register.

    LET r1    =  0
    LET r1h   =  0
    LET r1l   =  0

    //  The instructions to be compiled depend on the operation being
    //  performed.  Both EQV and NEQV are in fact XOR operation, with
    //  the added overhead with EQV being that the result must be
    //  complemented.

    LET inst  =  op = s.logand  ->  i.and,
                 op = s.logor   ->  i.or,
                                    i.xor

    LET cmpl  =  op = s.eqv

    //  If the items are on the stack in the wrong order, or the second
    //  operand is already in a register, then we should swap them, since
    //  all logical operators are symmetric.

    IF  (t1 = t.stack  &  t2 = t.stack  &  (v1 < v2))  |  t2 = t.register  THEN
    $(
        LET ot1  =  t1
        LET ov1  =  v1

        t1  :=  t2
        v1  :=  v2
        t2  :=  ot1
        v2  :=  ov1
    $)

    //  We can now safely move the items into their relevant register(s).

    r1   :=  movetoanyr( t1, v1, FALSE )
    r1h  :=  highbyte( r1 )
    r1l  :=  lowbyte( r1 )

    //  Now look at the data type of the second operand, and see if we can
    //  optimise the operation.

    TEST  t2 = t.number  THEN
    $(
        //  We can optimise this operation, since there is no need to use a
        //  second register.  We may also be able to optimise the operation
        //  further if either if the 8 bit operations involve constants
        //  which are all zeros or all ones.  Also, if the operation is EQV,
        //  then we can do the complement now, and not compile code to do it.

        LET v2h  =  0
        LET v2l  =  0

        IF  cmpl  THEN  v2  :=  NOT v2

        v2h  :=  (v2 >> 8)  &  #XFF
        v2l  :=  (v2)       &  #XFF

        cg.logical.byte( inst, r1h, v2h )
        cg.logical.byte( inst, r1l, v2l )
    $)
    ELSE
    $(
        //  We don't know what this is, so we had better load it into a
        //  register for good measure.

        LET r2  =  movetoanybutr( r1, t2, v2, TRUE )

        LET r2h  =  highbyte( r2 )
        LET r2l  =  lowbyte( r2 )

        //  Having done that, we can compile the code.

        cg.logical.byter( inst, r1h, r2h, cmpl )
        cg.logical.byter( inst, r1l, r2l, cmpl )
    $)

    //  Whatever code we compiled, the result is in register "r1", and so
    //  we can return that now.

    unsetslave( r1 )

    evaltype  :=  t.register

    RESULTIS  r1
$)



AND cg.logical.byte( inst, r, v )  BE
$(
//  Code generate for a 1 byte logical instruction.  We can perhaps
//  optimise the instruction depending on what the constant is.

    IF  (v = #X00)  &  (inst = i.and)  THEN
    $(
        //  Anything ANDed with #X00 is in fact #X00, and hence
        //  we can generate a sequence for this easily.

        code.s.1( i.xor, r.a )
        code.rr.1( i.ldrr, r, r.a )

        RETURN
    $)

    IF  (v = #XFF)  &  (inst = i.or)  THEN
    $(
        //  Anything ORed with #XFF is #XFF, and hence we can
        //  optimise this case as well.

        code.s.1( i.xor, r.a )
        code.i.1( i.cpl )
        code.rr.1( i.ldrr, r, r.a )

        RETURN
    $)

    IF  ((v = #X00)  &  (inst = i.or  |  inst = i.xor))  |
        ((v = #XFF)  &  (inst = i.and))  THEN

        //  This is easy to do, since anything ORed or XORed with
        //  #X00 is itself, as is anything ANDed with #XFF.

        RETURN

    IF  (v = #XFF)  &  (inst = i.xor)  THEN
    $(
        //  Anything XORed with #XFF is in fact the complement of it,
        //  and hence we can compile that.

        code.rr.1( i.ldrr, r.a, r )
        code.i.1( i.cpl )
        code.rr.1( i.ldrr, r, r.a )

        RETURN
    $)

    //  If all those potential optimisations fail, then we had better
    //  compile the code properly.

    code.rn.2( i.ldrn, r.a, v )
    code.s.1( inst, r )
    code.rr.1( i.ldrr, r, r.a )
$)



AND cg.logical.byter( inst, r1, r2, cmpl )  BE
$(
//  Code generate for a register to register logical operation.  The result
//  should be left in "r1", and the flag "cmpl" says whether the result
//  should be complemented or not.

    code.rr.1( i.ldrr, r.a, r1 )
    code.s.1( inst, r2 )

    IF  cmpl  THEN  code.i.1( i.cpl )

    code.rr.1( i.ldrr, r1, r.a )
$)



AND cg.rshift( t1, v1, t2, v2 )  =  VALOF
$(
//  Generate code for a ">>" operation.  We can optimise this if the amount to
//  be shifted by is a number, and that number is 8.

    TEST  t2 = t.number  &  v2 = 8  THEN
    $(
        //  This is simple.  We just move the value to be shifted into a
        //  register, and then swap the bytes.

        LET r   =  movetoanyr( t1, v1, FALSE )
        LET rh  =  highbyte( r )
        LET rl  =  lowbyte( r )

        code.rr.1( i.ldrr, rl, rh )
        code.s.1( i.xor, r.a )
        code.rr.1( i.ldrr, rh, r.a )

        unsetslave( r )

        evaltype  :=  t.register

        RESULTIS  r
    $)
    ELSE

    //  We cannot optimise this easily, so take the easy way out, and call
    //  the monitor function to do the job for us.

    RESULTIS  cg.stackop( s.rshift, t1, v1, t2, v2 )
$)



AND cg.lshift( t1, v1, t2, v2 )  =  VALOF
$(
//  Generate code for a "<<" operation.  We can optimise this if the
//  amount to be shifted by is a number, and that number is a factor of
//  two.

    TEST  t2 = t.number  &  factorof2( v2 )  THEN
    $(
        //  We can optimise shifting left by 2 just by adding registers
        //  together.  We can optimise even further if we are shifting by
        //  8, in which case we can just swap the halves of the register

        LET r   =  0
        LET rh  =  0
        LET rl  =  0

        TEST  v2 = 8  THEN
        $(
            r   :=  movetoanyr( t1, v1, FALSE )
            rh  :=  highbyte( r )
            rl  :=  lowbyte( r )

            code.rr.1( i.ldrr, rh, rl )
            code.s.1( i.xor, r.a )
            code.rr.1( i.ldrr, rl, r.a )
        $)
        ELSE
        $(
            //  This is only slightly more complicated, since we can perform
            //  the shift by repeated addition.

            movetor( r.hl, t1, v1 )

            FOR  i = 1  TO  v2  DO  code.ss.1( i.addhl, r.hl )

            r  :=  r.hl
        $)

        //  The result is now in register "r", and we can return this as the
        //  result of the operation.

        unsetslave( r )

        evaltype  :=  t.register

        RESULTIS  r
    $)
    ELSE

    //  We cannot optimise this easily, so take the easy way out, and turn
    //  this into a stack operation.

    RESULTIS  cg.stackop( s.lshift, t1, v1, t2, v2 )
$)



AND factorof2( n )  =  (n & -n)  =  n


