6

I have a function signature similiar to this

void Mutliply(const MatrixMN& a, const MatrixMN& b, MatrixMN& out);

Internally the matrix class has a float* data; that represents the m x n components. I'd like to tell the compiler that a and b do not alias the out matrix so it doesn't do a ton of load-stores.

How would I go about doing that? I know I could pass in pointers to the function signature and mark the pointers with __restrict(in MSVC) but I'd like to keep the idiom of object passed by reference where the object contains pointers to memory.

I also know that __restrict does not work on object references.

Mat
  • 202,337
  • 40
  • 393
  • 406
coderdave
  • 895
  • 2
  • 6
  • 15
  • 2
    I don't suppose that applying [`__declspec(noalias)`](http://msdn.microsoft.com/en-us/library/k649tyc7.aspx) to the function has the semantics you want? – ildjarn Jun 09 '11 at 02:27
  • @ildjarn: it might be - I'd have to check the assembly to be sure – coderdave Jun 09 '11 at 02:32

4 Answers4

2

Depending on how the optimizer works, an assert(&in1 != &out && &in2 != &out) at the top may do the trick. You could also get rid of the out parameter, and trust the optimizer to get rid of the superfluous copies (assuming it is a pure out parameter, of course). If the code is a candidate for inlining the compiler may see nothing is aliased on it's own. If restrict really doesn't work on reference parameters, you can have an extra level to the function call, and pass all three to a second function that accepts pointers properly restricted. Hopefully, that one would get inlined for you.

Dennis Zickefoose
  • 10,791
  • 3
  • 29
  • 38
  • I'm not too worried about it generating incorrect code because the compiler will do that. I'm worried about the compiler not generating efficient code. We need to give hints to the compiler to allow it to do that. – coderdave Jun 09 '11 at 02:46
  • @coderdave: I'm not sure what you mean, but those are all hints to help it generate efficient code. Obviously it won't generate incorrect code. The first one, for instance, tells the compiler it can safely treat the three as unique, since otherwise the program will abort early. If it's inlined, the same assumption can be made on the basis of the surrounding code. – Dennis Zickefoose Jun 09 '11 at 03:43
  • The problem is that I don't care about the objects being passed in I care about the data that is pointed to inside the objects being aliased. Each object has a pointer to a float array and the compiler can make no assumptions that they alias because the pointers are dynamic there is no knowledge that they don't point to each other. We must tell the compiler that the float*'s inside the object never alias. – coderdave Jun 09 '11 at 20:31
1

Write a non-exported (file-static, private) multiplication function that takesfloat* arguments, mark the arguments with restrict. Make Multiply call this function.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • 1
    That would require Multiply to be a friend, which is fine if desired, but (particularly if MatrixMN isn't his class) may not be. – Fred Nurk Jun 09 '11 at 02:44
  • @Fred If `MatrixMN` isn't his class, it may use copy-on-write for all he knows. – n. m. could be an AI Jun 09 '11 at 02:59
  • 1
    Unless it's documented that it doesn't. For example, std::string doesn't in most implementations, so you can depend on that (with those implementations), but you cannot make your functions friends of it. – Fred Nurk Jun 09 '11 at 03:01
1

Since you seem to be comfortable with __restrict pointers, I would use what you know, but you can still wrap it and provide an interface using references:

void Multiply(const MatrixMN& a, const MatrixMN& b, MatrixMN& out) {
  if (&a == &b || &a == &out || &b == &out) {
    // indicate precondition violation however you like
    assert(!"precondition violated");
    abort();  // assert isn't always executed
  }
  else {
    DoMultiply(&a, &b, &out);
  }
}

void DoMultiply(MatrixMN const * __restrict a, MatrixMN const * __restrict b,
              MatrixMN * __restrict out)
{
  //...
}

Make the pointer version "non-public", such as placing it in a "details" namespace, giving it internal linkage (not applicable in this exact case), or giving it a special name. You could even use local variables instead of parameters and put the function body within the "else", but I find the above cleaner.

Fred Nurk
  • 13,952
  • 4
  • 37
  • 63
-1

How about a macro wrapper to have the __restrict effect at compile time itself: (below is pseudo code, not checked):

#define Multiply(A,B,C) Multiply_restrict(&A, &B, &C)

Now the intermediate method is defined as,

inline void Multiply_restrict(const MatrixMN* __restrict pA,
            const MatrixMN* __restrict pB, MatrixMN* __restrict pC)
{
  Multiply_(*pA, *pB, *pC);
}

And finally just add an _ after your original Multiply:

void Mutliply_(const MatrixMN& a, const MatrixMN& b, MatrixMN& out);

So final effect will be exactly same as you are calling:

Multiply(x, y, answer);
iammilind
  • 68,093
  • 33
  • 169
  • 336
  • @iammilind: Clever, but I'm not worried about if the objects alias only if the pointers inside the class alias. – coderdave Jun 09 '11 at 02:45
  • 4
    Why do people still use macros where they aren't warranted? – Fred Nurk Jun 09 '11 at 02:47
  • @Fred, macros are not **untouchables** ! Here there is no harm in using them. It could have been an `inline` function as well. I don't know who has downvoted but, I feel that sometimes use of macros are justifiable. – iammilind Jun 09 '11 at 04:04
  • 2
    Macros are needed for things similar to injecting \_\_FILE\_\_ or rudimentary code generation. I use macros often, but using a macro solely to avoid an inline function *is unforgivable.* – Fred Nurk Jun 09 '11 at 04:05
  • 3
    Hopefully no one ever writes a Multiply(string,int) function – or anything using "Multiply" at all – anywhere you have your Multiply macro. – Fred Nurk Jun 09 '11 at 04:08
  • 1
    @Fred, The macro changed the syntax from pass by pointer to look like pass by value. It wasn't just to avoid an inline function. I wouldn't of down voted for that. Of course, if anyone does use syntax like Multiply it would be a good idea to give the macro its own naming convention to avoid naming conflicts like you suggest can happen. Regardless, this answer still doesn't help the pointer aliasing problem from within the class. – coderdave Jun 09 '11 at 20:35
  • @coderdave: Check my profile – I don't downvote. Problems should be pointed out in comments, which I did. Neither the macro, nor your original, nor the inline functions suggested in other answers pass by value: they pass by reference (with the macro expecting lvalues). – Fred Nurk Jun 09 '11 at 20:38
  • 1
    @coderdave: The macro here is unwarranted, because it can be entirely replaced with an inline function and avoid the nasty macro complications. – Fred Nurk Jun 09 '11 at 20:39