[LLVMdev] adding new instructions to support "swizzle" and "writemask"
Tzu-Chien Chiu
tzuchien.chiu at gmail.com
Wed Apr 20 01:03:43 PDT 2005
Hello, everyone:
I am writing a compiler for a programmable graphics hardware. Each
registers of the hardware has four channels, namely 'r', 'b', 'g',
'a', and each channel is a 32-bit floating point. It's similar to the
high and low 8-bit of an x86 16-bit general purpose register "AX" can
be individually referenced as "AH" and "AL". What's different is the
hardware further "source register swizzle" and "writemask". For
example:
# The following two instructions are equivalent.
# They cost the same instruction slot, and have same
# execution time. Four channels are added in parallel.
add r0, r1, r2
add r0.xyzw, r1.xyzw, r2.xyzw
# equivalent to:
# r0.x = r1.yy + r2.w
# r0.z = r1.yy + r2.x
# r0.y and r0.w remains unchanged
add r0.xz, r1.y, r2.wx
Note that the channel y of r1 is replicated in the third instruction.
Detailed documentation:
<http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/AssemblyLanguageShaders/PixelShaders/Registers/Modifiers/SourceRegisterModifiers/PS_Swizzling.asp>
The code must be be transformed in SSA (.ll file). The problem is that
no existing LLVM instruction or intrinsic function supports swizzle
and writemask.
I have a few solutions:
(1) Treat each channel of a register as a individual SSA variable.
This could generate inefficient machine code.
For example, the instruction:
add r0.xz, r1.y, r2.wx
is translated to two LLVM instructions:
r0_x = add float r1_y, r2_w
r0_z = add float r1_y, r2_x
Subsequent optimization passes could insert other instructions between
these two instruction (for example, in instruction scheduling pass). I
don't know how they could be easily merged back into one instruction.
It could lead to inefficient machine code (though correct).
(2) Add new LLVM instructions, "swizzle" and "merge".
# A swizzle instruction acts like a channel "selector",
# selecting channels from the temporary registers r1 and r2.
temp_0 = swizzle.yy r1
temp_1 = swizzle.wx r2
temp_3 = add float temp_0, temp_1
temp_4 = merge.xz float temp_3, r0
But implementing swizzle and merge instructions like this seems non-trivial.
I'd know if anyone knows if there is possible and ealier alternatives?
Thank you.
More information about the llvm-dev
mailing list