Hi, I'm working on a project to generate native code for a domain specific langauge where the user defines functions in the complex plane. This implies that I need to support complex numbers as a datatype with LLVM. Its fairly straightforward to create a struct of two floats (or doubles, etc.) and do the simple operations like add, subtract, multiply, divide, etc. However, things get stickier when we get to the trig functions. At that point, I'd rather defer to the trig functions implemented in C++, possibly taking them from boost's TR1 support instead of my compiler's TR1 support. At any rate, these functions aren't like the cos function in the math library because they are possibly template expansions from a header file. This leaves me with two basic types of questions: 1. Is there a "best" representation for complex numbers in LLVM? Is my simple "struct of two floats" idea sufficient? Is there a way to maintain binary compatability with std::complex<float> or std::complex<double> so that those types can be used directly when calling LLVM generated native code? 2. What's the best way to expose the C++ complex trig, etc., functions? Is there a way I can use LLVM IR to write the type signature of these functions? Do I need to provide my own wrapper matching the representation used in 1. above? Thanks for your time. -- "The Direct3D Graphics Pipeline" -- DirectX 9 draft available for download <http://legalizeadulthood.wordpress.com/the-direct3d-graphics-pipeline/> Legalize Adulthood! <http://legalizeadulthood.wordpress.com>
On Dec 21, 2010, at 9:22 AM, Richard wrote:> I'm working on a project to generate native code for a domain specific > langauge where the user defines functions in the complex plane. This > implies that I need to support complex numbers as a datatype with > LLVM. Its fairly straightforward to create a struct of two floats (or > doubles, etc.) and do the simple operations like add, subtract, > multiply, divide, etc. > > However, things get stickier when we get to the trig functions. At > that point, I'd rather defer to the trig functions implemented in C++, > possibly taking them from boost's TR1 support instead of my compiler's > TR1 support. At any rate, these functions aren't like the cos > function in the math library because they are possibly template > expansions from a header file. > > This leaves me with two basic types of questions: > > 1. Is there a "best" representation for complex numbers in LLVM? > Is my simple "struct of two floats" idea sufficient?Assuming you're talking about how to represent complex values internally within your functions, you have three reasonable options: A) You can pass the components around as a first-class aggregate containing two floats. B) You can pass the components around as a vector of two floats. C) You can pass the components around as two separate values. Working with a single value instead of 2, i.e. using A or B, has a lot of elegance advantages. The disadvantage is that since most operations on complex values aren't just component-wise, you'll probably find yourself doing a lot of decompositions and recompositions. Of course, those operations will generally be optimized away, but they can cost you compile time. Another thing to consider is that LLVM doesn't have an autovectorizer right now, so if you want to make sure that adds and subtracts are done as vector operations, you'll probably need to emit them as such in the frontend.> Is there a way to maintain binary compatability with > std::complex<float> or std::complex<double> so that those types can > be used directly when calling LLVM generated native code?The psABI memory layout for _Complex blah is a struct of two blah on every platform I know of. The parameter-passing and return-value scheme is much more complicated; you basically have to examine the IR output of a C/C++ frontend (e.g. clang -S -emit-llvm) and do whatever it does, keeping in mind that it can vary from platform to platform.> 2. What's the best way to expose the C++ complex trig, etc., functions? > Is there a way I can use LLVM IR to write the type signature of > these functions?For the correct IR type signature, again, you'll need to run them a C++ frontend on every platform you're interested in. That will also tell you the right mangling to use. Alternatively, if you're running as a JIT, you can ignore the mangling problem by emitting calls to notional functions (e.g. @complexFloatSin) and then provide JIT mappings for those functions to the address of the appropriate C++ library functions. John.
Richard <legalize at xmission.com> writes:> This leaves me with two basic types of questions: > > 1. Is there a "best" representation for complex numbers in LLVM? > Is my simple "struct of two floats" idea sufficient?IMHO, the best representation would use a vector of two floats or two doubles. That way many of the operations map directly onto LLVM vector operations and can in turn make use of any target SIMD instructions. Complex multiplication is a typical example where the x86-style addsub instructions are very useful.> Is there a way to maintain binary compatability with > std::complex<float> or std::complex<double> so that those types can > be used directly when calling LLVM generated native code?You'll need some way to convert between your representation and whatever complex<> is on your platform. That's true no matter what your representation is. If you don't care too much about portability you can pick a representation that naturally converts to complex<> on your platform.> 2. What's the best way to expose the C++ complex trig, etc., functions? > Is there a way I can use LLVM IR to write the type signature of > these functions?I'm not exactly sure what you're asking. It's certainly possible to create a function signature that matches the C++ trig functions. How you expose that in your language is entirely up to you. Pick a signature that matches your language naturally and then do any conversion required to invoke the C++ trig functions with the arguments passed to your language trig API functions.> Do I need to provide my own wrapper matching the representation > used in 1. above?It depends on how you want to do it. With a wrapper you can write the representation conversion outside the compiler and link it in as a runtime library. But that means more little bits to keep track of. -Dave