home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #16 / NN_1992_16.iso / spool / comp / lang / cplus / 11656 < prev    next >
Encoding:
Internet Message Format  |  1992-07-28  |  4.6 KB

  1. Xref: sparky comp.lang.c++:11656 comp.lang.eiffel:997
  2. Path: sparky!uunet!mcsun!corton!irisa!irisa.fr!jezequel
  3. From: jezequel@irisa.fr (Jean-Marc Jezequel)
  4. Newsgroups: comp.lang.c++,comp.lang.eiffel
  5. Subject: Re: Multi-operator expressions
  6. Message-ID: <1992Jul28.131455.1717@irisa.fr>
  7. Date: 28 Jul 92 13:14:55 GMT
  8. References: <1992Jul27.154135.17551@hemlock.cray.com>
  9. Sender: news@irisa.fr
  10. Organization: Irisa, Rennes(FR)
  11. Lines: 108
  12.  
  13. In article <1992Jul27.154135.17551@hemlock.cray.com>, dsf@cray.com (Dan Frankowski) writes:
  14. |> This posting is long.  :-(  I ask, "How do we optimize expressions
  15. |> involving more than one operator, such as A * B + C, x = x + y,
  16. |> and list = one + two + three + four?"
  17. As I think this discussion is not specific to C++, I cross-posted it to comp.lang.eiffel
  18.  
  19. |> Motivation
  20. |> ----------
  21. |> 
  22. |> In many cases there are important optimizations for expressions that
  23. |> involve more than one operator.  For example:
  24. |> 
  25. |>   A + B * C (where A, B, and C are matrices) on a Cray should be a
  26. |>   Cray Assembly Language (CAL) routine to pipeline the results of
  27. |>   multiplication to the adder while more multiplication is done.
  28. |> 
  29. |> This is a serious optimization, resulting in noticeable improvement in
  30. |> performance.  It is inhibited by the fact that in this expression,
  31. |> operator* doesn't know about operator+ nor vice-versa.  But to
  32. |> implement it properly, _something_ must know that both addition and
  33. |> multiplication are taking place.
  34. |> 
  35. |> Two present-day solutions:
  36. |> 
  37. |> - Specify the expression as addMult(A,B,C).
  38. |> 
  39. |> - Overload + and * to build a parse tree, and then make = optimize
  40. |>   the parse tree and perform all of the necessary calculations.
  41. |>   (See Jim Adcock's 1992 June 15 posting to comp.lang.c++)
  42. |> 
  43. |> The first solution is completely counter to the style of C++.  The
  44. |> second has runtime overhead for evaluating a parse tree, which is the
  45. |> bread and butter of a compiler.
  46. This is my feeling.
  47.  
  48. |> It also does not account for function
  49. |> calls with A + B * C as a parameter, or any other places where an
  50. |> expression may be used.
  51. |> 
  52. |> Wouldn't it be nice to have a simple notation to allow the programmer
  53. |> to specify functions to be put in the place of expressions that
  54. |> involve more than one operator?  The programmer could then tell the
  55. |> compiler, "Make A + B * C into AddMult(A,B,C)" much as we now say
  56. |> "Make A + B into operator+(const Matrix&, const Matrix&)" (which can
  57. |> be an inlined call to Add(A,B)).
  58. |> 
  59. |> Proposal
  60. |> --------
  61. |> 
  62. |> For the matrix example above, we could use
  63. |> 
  64. |> Matrix operator+*(const Matrix&, const Matrix&, const Matrix&);
  65. |> 
  66. |> The compiler would transform A + B * C into operator+*(A,B,C).  In
  67. |> other words, use operator<op1><op2>(<arguments>) to specify a two
  68. |> operator expression.  This is easily extended to any fixed number of
  69. |> operators.
  70. |> 
  71.  
  72. This sounds interesting, but I still think this kind of optimisation should be pure
  73. compiler job.
  74. Indeed, you seem to consider than your Matrix class is not to be subclassed
  75. (because otherwise this would'nt be possible at compile time, as the actual methods under
  76. names + and * would depend on actual (dynamic) type of your Matrices).
  77. But if you (the compiler) know statically what version of + and * will be invoked in the
  78. expression A + B * C, then a "normal" concatenation of compiler optimisations would give
  79. the wanted result. Here is an outline of this string (using pseudo-code):
  80.  
  81. D:=A+B*C
  82. --The parser gives: 
  83. D:=A.plus(B.mult(C)) which leads to E:=B.mult(C);D:=A.plus(E);
  84.  
  85. --Dynamic types of A, B and C are known at compile time, so are actual versions of plus and
  86. mult. Then a reasonably good OO compiler could do the inline expansion (see ISE Eiffel 2.3
  87. for example):
  88. for i:1..n 
  89.   for j:1..n
  90.     for k:1..n
  91.     e(i,j)+=b(i,k)*c(k,j)
  92. for i:1..n
  93.   for j:1..n
  94.     d(i,j):=a(i,j)+e(i,j)
  95.  
  96. --Then use standard loop merging (I think GCC 2.something can do it)
  97. for i:1..n 
  98.   for j:1..n {
  99.     for k:1..n
  100.     e(i,j)+=b(i,k)*c(k,j)
  101.     d(i,j):=a(i,j)+e(i,j)
  102.   }
  103.  
  104. --Dependance analysis (getting rid of e(i,j)):
  105. for i:1..n 
  106.   for j:1..n {
  107.     for k:1..n
  108.     d(i,j)+=b(i,k)*c(k,j)
  109.     d(i,j)+=a(i,j)
  110.   }
  111.  
  112. --And then no problem to pipe-line, or even execute as data parallel on a MIMD machine.
  113. So I guess this is today compiler technology, and the only problem should be to melt
  114. these different optimisations in the same compiler (or did I get anything wrong?)
  115. To test it, it would be interesting to try the ISE compiler (Eiffel->C) followed by GCC.
  116.  
  117. -- 
  118. +----------------------------------------------------------------------------+
  119. | Jean-Marc Jezequel, IRISA/CNRS, 35042 RENNES (FRANCE) // jezequel@irisa.fr |
  120. +----------------------------------------------------------------------------+
  121.