LLVM
The LLVM, Low Level Virtual Machine, is a really cool compiler infrastructure project with many participants. The idea is that if you want to make a new high quality compiler you just have to generate LLVM code, and then there are lots of optimizations and code generators available to get fast code.There are different ways to generate input to the LLVM tools. You can generate a text file with LLVM code and feed it to the tools, or you can use bindings for some programming language and programmatically build the LLVM code. The original bindings from the LLVM project is for C++, but they also provide C bindings. On top of the C bindings you can easily interface to other languages; for instance O'Caml and Haskell.
There are also diffent things you can do to LLVM code you have build programmatically. You can transform it, you can write to a file, you can run an interpreter on it, or execute it with a JIT compiler.
Haskell LLVM bindings
There is a Haskell binding to the LLVM. It has two layers. You can either work on the C API level and have ample opportunity to shoot your own limbs to pieces, or you can use the high level interface which is mostly safe.Bryan O'Sullivan did all the hard work of taking the C header files and producing the corresponding Haskell FFI files. He also made a first stab at the high level interface, which I have since change a lot (for better or for worse).
An example
Let's do an example. We'll write the LLVM code for this functionf x y z = (x + y) * zIn Haskell this function is polymorphic, but when generating machine code we have to settle for a type. Let's pick Int32. (The Haskell Int type cannot be used in talking to LLVM; it doesn't a well defined size.) Here is how it looks:
mAddMul :: CodeGenModule (Function (Int32 -> Int32 -> Int32 -> IO Int32))
mAddMul =
createFunction ExternalLinkage $ \ x y z -> do
t <- add x y
r <- mul t z
ret r
For comparison, the LLVM code in text for for this would be:
define i32 @_fun1(i32, i32, i32) {
%3 = add i32 %0, %1
%4 = mul i32 %3, %2
ret i32 %4
}
So what does the Haskell code say? The mAddMul definition is something in the CodeGenModule monad, and it generates a Function of type Int32 -> Int32 -> Int32 -> IO Int32. That last is the type of f above, except for that IO. Why the IO? The Haskell LLVM bindings forces all defined functions to return something in the IO monad, because there are no restriction on what can happen in the LLVM code; it might very well do IO. So to be on the safe side, there's always an IO on the type. If we know the function is harmless, we can use unsafePerformIO to get rid of it.
So the code does a createFunction which does what the name suggests. The ExternalLinkage argument says that this function will be available outside the module it's in, the obvious opposite being InternalLinkage. Using InternalLinkage is like saying static on the top level in C. In this examples it doesn't really matter which we pick.
The function has three arguments x y z. The last argument to createFunction should be a lambda expression with the right number of arguments, i.e., the number of arguments should agree with the type. We the use monadic syntax to generate an add, mul, and ret instruction.
The code looks like assembly code, which is the level that LLVM is at. It's a somewhat peculiar assembly code, because it's on SSA (Static Single Assignment) form. More about that later.
So what can we do with this function? Well, we can generate machine code for it and call it.
main = do
addMul <- simpleFunction mAddMul
a <- addMul 2 3 4
print a
In this code addMul has type Int32 -> Int32 -> Int32 -> IO Int32, so it has to be called in the IO monad. Since this is a pure function, we can make the type pure, i.e., Int32 -> Int32 -> Int32 -> Int32.
main = do
addMul <- simpleFunction mAddMul
let addMul' = unsafePurify addMul
print (addMul' 2 3 4)
The unsafePurify functions is simply an extension of unsafePerformIO that drops the IO on the result of a function.
So that was pretty easy. To make a function, just specify the LLVM code using the LLVM DSEL that the Haskell bindings provides.
Fibonacci
No FP example is complete without the Fibonacci function, so here it is.
mFib :: CodeGenModule (Function (Word32 -> IO Word32))
mFib = do
fib <- newFunction ExternalLinkage
defineFunction fib $ \ arg -> do
-- Create the two basic blocks.
recurse <- newBasicBlock
exit <- newBasicBlock
-- Test if arg > 2
test <- icmp IntUGT arg (2::Word32)
condBr test recurse exit
-- Just return 1 if not > 2
defineBasicBlock exit
ret (1::Word32)
-- Recurse if > 2, using the cumbersome plus to add the results.
defineBasicBlock recurse
x1 <- sub arg (1::Word32)
fibx1 <- call fib x1
x2 <- sub arg (2::Word32)
fibx2 <- call fib x2
r <- add fibx1 fibx2
ret r
return fib
Instead of using createFunction to create the function we're using newFunction and defineFunction. The former is a shorthand for the latter two together. But splitting making the function and actually defining it means that we can refer to the function before it's been defined. We need this since fib is recursive.
Every instruction in the LLVM code belongs to a basic block. A basic block is a sequence of non-jump instructions (call is allowed in the LLVM) ending with some kind of jump. It is always entered at the top only. The top of each basic block can be thought of as a label that you can jump to, and those are the only places that you can jump to.
The code for fib starts with a test if the argument is Unsigned Greater Than 2. The condBr instruction branches to recurse if test is true otherwise to exit. To be able to refer to the two branch labels (i.e., basic blocks) before they are defined we create them with newBasicBlock and then later define them with defineBasicBlock. The defineBasicBlock simply starts a new basic block that runs to the next basic block start, or to the end of the function. The type system does not check that the basic block ends with a branch (I can't figure out how to do that without making the rest of the code more cumbersome).
In the false branch we simply return 1, and in the true branch we make the two usual recursive calls, add the results, and return the sum.
As you can see a few type annotations are necessary on constants. In my opinion they are quite annoying, because if you write anything different from ::Word32 in those annotations there will be a type error. This means that in principle the compiler has all the information, it's just too "stupid" to use it.
The performance you get from this Fibonacci function is decent, but in fact worse than GHC with -O2 gives. Even with full optimization turned on for the LLVM code it's still not as fast as GHC for this function.
[Edit: Added assembly] Here is the assembly code for Fibonacci. Note how there is only one recursive call. The other call has been transformed into a loop.
_fib: pushl %edi pushl %esi subl $4, %esp movl 16(%esp), %esi cmpl $2, %esi jbe LBB1_4 LBB1_1: movl $1, %edi .align 4,0x90 LBB1_2: leal -1(%esi), %eax movl %eax, (%esp) call _fib addl %edi, %eax addl $4294967294, %esi cmpl $2, %esi movl %eax, %edi ja LBB1_2 LBB1_3: addl $4, %esp popl %esi popl %edi ret LBB1_4: movl $1, %eax jmp LBB1_3
Hello, World!
The code for printing "Hello, World!":
import Data.Word
import LLVM.Core
import LLVM.ExecutionEngine
bldGreet :: CodeGenModule (Function (IO ()))
bldGreet = do
puts <- newNamedFunction ExternalLinkage "puts" :: TFunction (Ptr Word8 -> IO Word32)
greetz <- createStringNul "Hello, World!"
func <- createFunction ExternalLinkage $ do
tmp <- getElementPtr greetz (0::Word32, (0::Word32, ()))
call puts tmp -- Throw away return value.
ret ()
return func
main :: IO ()
main = do
greet <- simpleFunction bldGreet
greet
To get access to the C function puts we simply declare it and rely on the linker to link it in. The greetz variable has type pointer to array of characters. So to get a pointer to the first character we have to use the rather complicated getElementPtr instruction. See FAQ about it.
Phi instructions
Let's do the following simple C function
int f(int x)
{
if (x < 0) x = -x;
return (x+1);
}
Let's try to write some corresponding LLVM code:
createFunction ExternalLinkage $ \ x -> do
xneg <- newBasicBlock
xpos <- newBasicBlock
t <- icmp IntSLT x (0::Int32)
condBr t xneg xpos
defineBasicBlock xneg
x' <- sub (0::Int32) x
br xpos
defineBasicBlock xpos
r1 <- add ??? (1::Int32)
ret r1
But what should we put at ???? When jumping from the condBr the value is in x, but when jumping from the negation block the value is in x'. And this is how SSA works. Every instruction puts the value in a new "register", so this situation is unavoidable. This is why SSA (and thus LLVM) form has phi instructions. This is a pseudo-instruction to tell the code generator what registers should be merged at the entry of a basic block. So the real code looks like this:
mAbs1 :: CodeGenModule (Function (Int32 -> IO Int32))
mAbs1 =
createFunction ExternalLinkage $ \ x -> do
top <- getCurrentBasicBlock
xneg <- newBasicBlock
xpos <- newBasicBlock
t <- icmp IntSLT x (0::Int32)
condBr t xneg xpos
defineBasicBlock xneg
x' <- sub (0::Int32) x
br xpos
defineBasicBlock xpos
r <- phi [(x, top), (x', xneg)]
r1 <- add r (1::Int32)
ret r1
The phi instruction takes a list of registers to merge, and paired up with each register is the basic block that the jump comes from. Since the first basic block in a function is created implicitely we have to get it with getCurrentBasicBlock which returns the current basic block.
If, like me, you have a perverse interest in the machine code that gets generated here is the optimized code for that function on for x86:
__fun1:
movl 4(%esp), %eax
movl %eax, %ecx
sarl $31, %ecx
addl %ecx, %eax
xorl %ecx, %eax
incl %eax
ret
Note how the conditional jump has cleverly been replaced by some non-jumping instructions. I think this code is as good as it gets.
Loops and arrays
Let's do a some simple array code, the dot product of two vectors. The function takes a length and pointers to two vectors. It sums the elementwise product of the vectors. Here's the C code:
double
dotProd(unsigned int len, double *aPtr, double *bPtr)
{
unsigned int i;
double s;
s = 0;
for (i = 0; i != len; i++)
s += aPtr[i] * bPtr[i];
return s;
}
The corresponding LLVM code is much more complicated and has some new twists.
import Data.Word
import Foreign.Marshal.Array
import LLVM.Core
import LLVM.ExecutionEngine
mDotProd :: CodeGenModule (Function (Word32 -> Ptr Double -> Ptr Double -> IO Double))
mDotProd =
createFunction ExternalLinkage $ \ size aPtr bPtr -> do
top <- getCurrentBasicBlock
loop <- newBasicBlock
body <- newBasicBlock
exit <- newBasicBlock
-- Enter loop, must use a br since control flow joins at the loop bb.
br loop
-- The loop control.
defineBasicBlock loop
i <- phi [(valueOf (0 :: Word32), top)] -- i starts as 0, when entered from top bb
s <- phi [(valueOf 0, top)] -- s starts as 0, when entered from top bb
t <- icmp IntNE i size -- check for loop termination
condBr t body exit
-- Define the loop body
defineBasicBlock body
ap <- getElementPtr aPtr (i, ()) -- index into aPtr
bp <- getElementPtr bPtr (i, ()) -- index into bPtr
a <- load ap -- load element from a vector
b <- load bp -- load element from b vector
ab <- mul a b -- multiply them
s' <- add s ab -- accumulate sum
i' <- add i (valueOf (1 :: Word32)) -- Increment loop index
addPhiInputs i [(i', body)] -- Control flow reaches loop bb from body bb
addPhiInputs s [(s', body)]
br loop -- And loop
defineBasicBlock exit
ret (s :: Value Double) -- Return sum
main = do
ioDotProd <- simpleFunction mDotProd
let dotProd a b =
unsafePurify $
withArrayLen a $ \ aLen aPtr ->
withArrayLen b $ \ bLen bPtr ->
ioDotProd (fromIntegral (aLen `min` bLen)) aPtr bPtr
let a = [1,2,3]
b = [4,5,6]
print $ dotProd a b
print $ sum $ zipWith (*) a b
First we have to set up the looping machinery. There a four basic blocks involved: the implicit basic block that is created at the start of every function, top; the top of the loop, loop; the body of the loop, body; and finally the block with the return from the function, exit.
There are two "registers", the loop index i and the running sum s that arrive from two different basic blocks at the top of the loop. When entering the loop from the first time they should be 0. That's what the phi instruction specifies. The valueOf function simply turns a constant into an LLVM value. It's worth noting that the initial values for the two variables are constant rather than registers. The control flow also reached the basic block loop from the end of body, but we don't have the names of those registers in scope yet, so we can't put them in the phi instruction. Instead, we have to use addPhiInputs to add more phi inputs later (when the registers are in scope).
The most mysterious instruction in the LLVM is getElementPtr. It simply does address arithmetic, so it really does something quite simple. But it can perform several levels of address arithmetic when addressing through multilevel arrays and structs. In can take several indicies, but since here we simply want to add the index variable to a pointer the usage is pretty simple. Doing getElementPtr aPtr (i, ()) corresponds to aPtr + i in C.
To test this function we need pointers to two vectors. The FFI function withArrayLen temporarily allocates the vector and fills it with elements from the list.
The essential part of the function looks like this in optimized x86 code:
pxor %xmm0, %xmm0
xorl %esi, %esi
.align 4,0x90
LBB1_2:
movsd (%edx,%esi,8), %xmm1
mulsd (%ecx,%esi,8), %xmm1
incl %esi
cmpl %eax, %esi
addsd %xmm1, %xmm0
jne LBB1_2
Which is pretty good. Improving this would have to use SSD vector instructions. This is possible using the LLVM vector type, but I'll leave that for now.
Abstraction
The loop structure in dotProd is pretty common, so we would like to abstract it out for reuse. The creation of basic blocks and phi instructions is rather fiddly so it would be nice to do this once and not worry about it again.What are the parts of the loop? Well, let's just do a simple "for" loop that loops from a lower index (inclusive) to an upper index (exclusive) and executes the loop body for each iteration. So there should be three arguments to the loop function: lower bound, upper bound and loop body. What is the loop body? Since the LLVM is using SSA the loop body can't really update the loop state variables. Instead it's like a pure functional language where you have to express it as a state transformation. So the loop body will take the old state and return a new state. It's also useful to pass the loop index to the loop body. Now when we've introduced the notion of a loop state we also need to have an initial value for the loop state as an argument to the loop function.
Let's start out easy and let the state to be updated in the loop be a single value. In dotProd it's simply the running sum (s).
forLoop low high start incr = do
top <- getCurrentBasicBlock
loop <- newBasicBlock
body <- newBasicBlock
exit <- newBasicBlock
br loop
defineBasicBlock loop
i <- phi [(low, top)]
state <- phi [(start, top)]
t <- icmp IntNE i high
condBr t body exit
defineBasicBlock body
state' <- incr i state
i' <- add i (valueOf 1)
body' <- getCurrentBasicBlock
addPhiInputs i [(i', body')]
addPhiInputs state [(state', body')]
br loop
defineBasicBlock exit
return state
The low and high arguments are simply the loop bounds, start is the start value for the loop state variable, and finally incr is invoked in the loop body to get the new value for the state variable. Note that the incr can contain new basic blocks so there's no guarantee we're in the same basic block after incr has been called. That's why there is a call to getCurrentBasicBlock before adding to the phi instructions.
So the original loop in dotProd can now be written
s <- forLoop 0 size 0 $ \ i s -> do
ap <- getElementPtr aPtr (i, ()) -- index into aPtr
bp <- getElementPtr bPtr (i, ()) -- index into bPtr
a <- load ap -- load element from a vector
b <- load bp -- load element from b vector
ab <- mul a b -- multiply them
s' <- add s ab -- accumulate sum
return s'
So that wasn't too bad. But what if the loop needs multiple state variables? Or none? The tricky bit is handling the phi instructions since the number of instructions needed depends on how many state variables we have. So let's creat a class for types that can be state variables. This way we can use tuples for multiple state variables. The class needs two methods, the generalization of phi and the generalization of addPhiInputs.
class Phi a where
phis :: BasicBlock -> a -> CodeGenFunction r a
addPhis :: BasicBlock -> a -> a -> CodeGenFunction r ()
A simple instance is when we have no state variables.
instance Phi () where
phis _ _ = return ()
addPhis _ _ _ = return ()
We also need to handle the case with a single state variable. All LLVM values are encapsulated in the Value type, so this is the one we create an instance for.
instance (IsFirstClass a) => Phi (Value a) where
phis bb a = do
a' <- phi [(a, bb)]
return a'
addPhis bb a a' = do
addPhiInputs a [(a', bb)]
Finally, here's the instance for pair. Other tuples can be done in the same way (or we could just use nested pairs).
instance (Phi a, Phi b) => Phi (a, b) where
phis bb (a, b) = do
a' <- phis bb a
b' <- phis bb b
return (a', b')
addPhis bb (a, b) (a', b') = do
addPhis bb a a'
addPhis bb b b'
Using this new class the looping function becomes
forLoop :: forall i a r . (Phi a, Num i, IsConst i, IsInteger i, IsFirstClass i) =>
Value i -> Value i -> a -> (Value i -> a -> CodeGenFunction r a) -> CodeGenFunction r a
forLoop low high start incr = do
top <- getCurrentBasicBlock
loop <- newBasicBlock
body <- newBasicBlock
exit <- newBasicBlock
br loop
defineBasicBlock loop
i <- phi [(low, top)]
vars <- phis top start
t <- icmp IntNE i high
condBr t body exit
defineBasicBlock body
vars' <- incr i vars
i' <- add i (valueOf 1 :: Value i)
body' <- getCurrentBasicBlock
addPhis body' vars vars'
addPhiInputs i [(i', body')]
br loop
defineBasicBlock exit
return vars
File operations
The Haskell bindings provide two convenient functions - writeBitcodeToFile and readBitcodeFromFile - for writing and reading modules in the LLVM binary format.A simple example:
import Data.Int
import LLVM.Core
mIncr :: CodeGenModule (Function (Int32 -> IO Int32))
mIncr =
createNamedFunction ExternalLinkage "incr" $ \ x -> do
r <- add x (1 :: Int32)
ret r
main = do
m <- newModule
defineModule m mIncr
writeBitcodeToFile "incr.bc" m
Running this will produce the file incr.bc which can be processed with the usual LLVM tools. E.g.
$ llvm-dis < incr.bc # to look at the LLVM code $ opt -std-compile-opts incr.bc -f -o incrO.bc # run optimizer $ llvm-dis < incrO.bc # to look at the optimized LLVM code $ llc incrO.bc # generate assembly code $ cat incrO.s # look at assembly codeReading a module file is equally easy, but what can you do with a module you have read? It could contain anything. To extract things from a module there is a function getModuleValues which returns a list of name-value pairs of all externally visible functions and global variables. The values all have type ModuleValue. To convert a ModuleValue to a regular Value you have to use castModuleValue. This is a safe conversion function that makes a dynamic type test to make sure the types match (think of ModuleValue as Dynamic and castModuleValue as fromDynamic).
Here's an example:
import Data.Int
import LLVM.Core
import LLVM.ExecutionEngine
main = do
m <- readBitcodeFromFile "incr.bc"
ee <- createModuleProviderForExistingModule m >>= createExecutionEngine
funcs <- getModuleValues m
let ioincr :: Function (Int32 -> IO Int32)
Just ioincr = lookup "incr" funcs >>= castModuleValue
incr = unsafePurify $ generateFunction ee ioincr
print (incr 41)
This post is getting rather long, so I'll let this be the last example for today.Labels: Code generation, DSL, Haskell, LLVM

45 Comments:
Cool! Does simpleFunction really have to be in IO?
I think simpleFunction fits best in IO, because the whole LLVM framework is in IO. There are various effects going on.
Thanks for the reply, Lennart. I guess I'm looking for a "no" or more compelling "yes". Here's my thought process:
In pure lazy functional programming, there are always effects going on, such as thunk updating and stack frame munging. We've figured out how to encapsulate those effects behind simple functional semantics, which then means we can have tractable rigorous reasoning and terrific modularity. When other effects come along, I like to see if they can also be wrapped up as the implementation of a semantically simple abstraction. The LLVM framework looks fun and useful, so naturally I'd like that it be available functionally if possible.
So I guess a clearer form of my question is as follows.
Is there a semantic obstacle to simpleFunction producing indistinguishable results on successive calls with the same argument?
If not, how can LLVM be packaged safely, simply, and functionally (IO-free interface/semantics)?
Mind posting the assembly for LLVM fibonacci function?
Wow, totally mind boggling!
www.privacy.de.tc
Where you start looking at abstracting the for-loop, I think there's a typo:
state <- phi [(state, top)]
The second "state" should be "start".
Conal: Right now the code generation monads belong to MonadIO so you can do arbitrary effects in there. This isn't necessary and could be removed.
Assuming that this was removed I see no fundamental reason why simpleFunction couldn't be a pure function (it isn't now, in fact calling it a second time would probably make the program crash because of how the LLVM execution engine works).
kyle: assembly code added.
jag: thanks, fixed.
The homepage link on http://hackage.haskell.org/cgi-bin/hackage-scripts/package/llvm is broken.
LLVM is very very cool. I've been writing a compiler for Appel's Tiger language in Haskell in my spare time and I planning on using the Haskell LLVM bindings when implementing the backend (after first writing my own code gen phase as a learning experience - nothing quite as exciting as adding optimisations to your own code generator ;-).
Thanks for the great work!
-- Lauri
Nice!
Have you considered using circular programming techniques using recursive do?
Which is described by Russell O'Connor in his paper "Circular Programming with Recursive do" in The Monad Reader issue 6
Maybe this will allow you to refer to blocks before they are defined. Which allows you to remove the newBasicBlocks.
Here's an "artist impression" of your fib for example:
(sorry for the absent indentation, I couldn't figure out how to insert literate code into Blogger)
mFib = do
fib <- newFunction ExternalLinkage
defineFunction fib $ \ arg -> mdo
test <- icmp IntUGT arg (2::Word32)
condBr test recurse exit
recurse <- defineBasicBlock $
do x1 <- sub arg (1::Word32)
fibx1 <- call fib x1
x2 <- sub arg (2::Word32)
fibx2 <- call fib x2
r <- add fibx1 fibx2
ret r
exit <- defineBasicBlock $ ret (1::Word32)
return fib
Making code generation available from functional code (consistent with its referential transparency) would sure make it available in more circumstances and more compositionally, and hence more useful to me (and I assume others).
"calling it a second time would probably make the program crash because of how the LLVM execution engine works"
Yow! Can this problem be fixed?
Bas: I used recursive do in my Harpy experiments. It looked similar to what you describe. I've not tried it yet for LLVM.
Conal: I think I've fixed execution engine problems in the LLVM bindings now by changing the interface. And I'll think about making a pure code generation interface.
This post has been removed by the author.
Are you able to advise which version of GHC you're using for this? I have LLVM 2.4 and GHC 6.8.3, along with the bindings 0.6.4.0, but unfortunately I keep getting link errors when I try anything (including the code in the examples/ directory). This is despite a verbose output indicating the appropriate link flags *are* being called by ghc :(
看房子,買房子,建商自售,自售,台北新成屋,台北豪宅,新成屋,豪宅,美髮儀器,美髮,儀器,髮型,EMBA,MBA,學位,EMBA,專業認證,認證課程,博士學位,DBA,PHD,在職進修,碩士學位,推廣教育,DBA,進修課程,碩士學位,網路廣告,關鍵字廣告,關鍵字,課程介紹,學分班,文憑,牛樟芝,段木,牛樟菇,日式料理, 台北居酒屋,日本料理,結婚,婚宴場地,推車飲茶,港式點心,尾牙春酒,台北住宿,國內訂房,台北HOTEL,台北婚宴,飯店優惠,台北結婚,婚宴場地,推車飲茶,港式點心,尾牙春酒,住宿,訂房,HOTEL,飯店,造型系列,學位,牛樟芝,腦磷脂,磷脂絲胺酸,SEO,婚宴,捷運,學區,美髮,儀器,髮型,牛樟芝,腦磷脂,磷脂絲胺酸,看房子,買房子,建商自售,自售,房子,捷運,學區,台北新成屋,台北豪宅,新成屋,豪宅,學位,碩士學位,進修,在職進修, 課程,教育,學位,證照,mba,文憑,學分班,網路廣告,關鍵字廣告,關鍵字,SEO,关键词,网络广告,关键词广告,SEO,关键词,网络广告,关键词广告,SEO,台北住宿,國內訂房,台北HOTEL,台北婚宴,飯店優惠,住宿,訂房,HOTEL,飯店,婚宴,台北住宿,國內訂房,台北HOTEL,台北婚宴,飯店優惠,住宿,訂房,HOTEL,飯店,婚宴,台北住宿,國內訂房,台北HOTEL,台北婚宴,飯店優惠,住宿,訂房,HOTEL,飯店,婚宴,結婚,婚宴場地,推車飲茶,港式點心,尾牙春酒,台北結婚,婚宴場地,推車飲茶,港式點心,尾牙春酒,結婚,婚宴場地,推車飲茶,港式點心,尾牙春酒,台北結婚,婚宴場地,推車飲茶,港式點心,尾牙春酒,結婚,婚宴場地,推車飲茶,港式點心,尾牙春酒,台北結婚,婚宴場地,推車飲茶,港式點心,尾牙春酒,居酒屋,燒烤,美髮,儀器,髮型,美髮,儀器,髮型,美髮,儀器,髮型,美髮,儀器,髮型,小套房,小套房,進修,在職進修,留學,證照,MBA,EMBA,留學,MBA,EMBA,留學,進修,在職進修,牛樟芝,段木,牛樟菇,關鍵字排名,網路行銷,关键词排名,网络营销,網路行銷,關鍵字排名,关键词排名,网络营销,PMP,在職專班,研究所在職專班,碩士在職專班,PMP,證照,在職專班,研究所在職專班,碩士在職專班,SEO,廣告,關鍵字,關鍵字排名,網路行銷,網頁設計,網站設計,網站排名,搜尋引擎,網路廣告,SEO,廣告,關鍵字,關鍵字排名,網路行銷,網頁設計,網站設計,網站排名,搜尋引擎,網路廣告,SEO,廣告,關鍵字,關鍵字排名,網路行銷,網頁設計,網站設計,網站排名,搜尋引擎,網路廣告,SEO,廣告,關鍵字,關鍵字排名,網路行銷,網頁設計,網站設計,網站排名,搜尋引擎,網路廣告,EMBA,MBA,PMP
,在職進修,專案管理,出國留學,EMBA,MBA,PMP
,在職進修,專案管理,出國留學,EMBA,MBA,PMP
,在職進修,專案管理,出國留學
住宿,民宿,飯宿,旅遊,住宿,民宿,飯宿,旅遊,住宿,民宿,飯宿,旅遊,住宿,民宿,飯宿,旅遊,住宿,民宿,飯宿,旅遊,住宿,民宿,飯宿,旅遊,住宿,民宿,飯宿,旅遊,美容,美髮,整形,造型,美容,美髮,整形,造型,美容,美髮,整形,造型,美容,美髮,整形,造型,美容,美髮,整形,造型,美容,美髮,整形,造型,美容,美髮,整形,造型,設計,室內設計,裝潢,房地產,設計,室內設計,裝潢,房地產,設計,室內設計,裝潢,房地產,設計,室內設計,裝潢,房地產,設計,室內設計,裝潢,房地產,設計,室內設計,裝潢,房地產,設計,室內設計,裝潢,房地產,設計,室內設計,裝潢,房地產,進修,在職進修,MBA,EMBA,進修,在職進修,MBA,EMBA,進修,在職進修,MBA,EMBA,進修,在職進修,MBA,EMBA,進修,在職進修,MBA,EMBA,進修,在職進修,MBA,EMBA,進修,在職進修,MBA,EMBA,住宿,民宿,飯店,旅遊,美容,美髮,整形,造型,設計,室內設計,裝潢,房地產,進修,在職進修,MBA,EMBA,羅志祥,周杰倫,五月天,蔡依林,林志玲,羅志祥,周杰倫,五月天,蔡依林,林志玲,羅志祥,周杰倫,五月天,蔡依林,羅志祥,周杰倫,五月天,蔡依林
Why was there no follow on bankruptcy then? The bailout of AIG FP went to (wow power leveling) hedge funds that bound credit swaps on Lehman failing or others betting on rating (wow power leveling) declines. AIG has drained over 100 billion from the government. Which had to go to (wow power leveling) those who bet on failures and downgrades. Many of whom (power leveling)were hedge funds. I-banks that had offsetting swaps needed the money from the AIG bailout or they would have been caught. Its an (wow powerleveling) insiders game and it takes just a little bit too much time for most people to think (wow gold) through where the AIG 100 billion bailout money went to, hedge funds and players, many of whom hire from the top ranks of DOJ, Fed, Treasury, etc. ZHANG XIAO CHEN
nike tnEnter the necessary language
translation, up to 200 bytes winter, moves frequently in Chinanike chaussures showing that the deep strategy of the Chinese market. Harvard Business School, tn chaussures according to the relevant survey data show that in recent years the Chinese market three brands, Adidas, Li Ning market share at 21 percent, respectively,
mens clothing men's sweate, cheap columbia jackets, lacoste sweater, ralph lauren polo shirts,ski clothing. Free Shipping, PayPal Payment. Enjoy your shopping experience on mensclothingstore.us
cheap polos
polo shirts
ralph lauren polo shirtssport shoes
ugg boots
puma shoes
chaussures pumamp4
trade chinalacoste polo shirts
chaussure puma femmewedding dressestennis racket
cheap handbags
HAIR STRAIGHTENERS
ED HARDY SHIRTS
HAIR STRAIGHTENERS
MENSCLOTHING mans clothing
cheap ugg boots
converse shoes
wedding dresses
wholesale polo shirts
brand clothingcheap clothing
clothes sportspolos shirtair shoesair shoesed hardy clothinged hardy clothing
英文推广
wholesale jewelryhandmade jewelryjewelry wholesalefashion jewelrycostume jewelry
Lacoste polo shirtsnorth face jacketscheap handbagscheap pursewomen's nike shoes
Cheap Brand Jeans ShopMen Jeans - True Religion Jeans, Women JeansGUCCI Jeans, Levi's Jeans, D&G Jeans, RED MONKEY Jeans, Cheap JeansArmani Jeans, Diesel Jeans, Ed hardy Jeans, Evisu Jeans, Jack&Jones Jeans...ed hardy clothing Online Store - We wholesale and retail cheap ed hardy shirts
g including Ed Hardy Men's Clothing,ed hardy clothing Clothing,Ed Hardy Kids Clothing, ed hardy womens Sunglasses, Ed Hardy Swimwear and more.
For the polo shirts, many people loveralphlaurenpoloshirtscheappolos but hate it. This brand is favorite, products like his style; the same is hard not to develop the Lacoste polo shirts brand has been cheap lacoste polos the Asian market. There are stores to buy wholesale polo shirts, However, ralph lauren polo shirts is too many fakes. It will be out of shape cheap ralph lauren polos.
discount ralph lauren polos are one of the highest in demand cheappolos because along with protecting your skin it also enhances your looks. These polo clothingare the in-thing in today's ralph lauren polo shirts fashion world and among the youngstersdiscount polossummer polospolo shirts whosale.
It was just a ed hardy clothing with a colourful design of three wolves howling at the moon. Now, it’s a viral sensation with its own ed hardy clothes, videos and an exploding following that has swamped a tiny New ed hardy shirts. Longer arms extend the yoke farther up each side of the babolat pure drive. These arms - or Side Drivers wilson k six- create a stiffer construction and distribute maximum power from the base of the yoke to the middle of the head microgel.
Advanced precision comes from the connection of the Side prince-o3-tour to the cheap tennis racquets at three o'clock and nine o'clock, which results in less torque (or twisting) at polo logopolo shirts in voguepolo women clothinged-hardy shirtsed-hardy sunglassesimpact.
This issue ed hardy t-shirts is of paramount importance as forensic experts ed hardy mens claimed to have discovered in the collar of one of ed hardy womens the fragment of an electronic timer which provided the key link ed hardy sunglasses between the bombing and Libya.They will surely love polo ralph laurenlike this. The styles are so fabulous burberry polos catching the light who would not love lacoste polo shirts like these.
In a womens clothing boutique store, several girls were trying on fashionable new polos men poloswomen polos. In addition to flower dresspolo fashionembroodered polostennis racketsclothing poloclothingedhardyshirtedhardyclothingedhardysummer ed hardy clothingcheap shirtsed hardy brandcheap ed hardypolo shirts cheapcheap tennis racketsdiscount tennis racketsralphlaurenpoloshirtscheappolospolo fashion, flower shirt, flower jacket, even with the scarf pattern is all kinds of flowers.
And chaussure nike shoes
Come here to have a look of our Wholesale Jeans
Many fashionMens Jeans ,eye-catching
Womens Jeans ,and special out standing
Blue Jeans ,you can spend less money on our
Discount Jeans but gain really fine jeans, absolutely a great bargain.
www.crazypurchase.com
China Wholesale
wholesale from china
buy products wholesale
China Wholesalers
http://weddingdressseason.com
There are ed hardy shirts
,pretty ed hardy shirt for men,
ed hardy womens in the ed hardy online store
designed by ed hardy ,
many cheap ed hardy shirt ,glasses,caps,trouers ed hardy shirts on sale ,
You can go to edhardyshirts.com to have a look ,you may find one of ed hardy clothing fit for you
Top qualitymen's jacket,
These cheap jacket are on sale now,you can find
north face jackets inmage on our web
Do you wannaghd hair straighteners for you own , we have many
cheap ghd hair straightenersin style and great,you can choose one from these
hair straighteners
Authentic chaussure puma
chaussure sport
Ralph Lauren Polo is the most famous sports shirt.Burberry Polo Shirt is the most well-known in France jerseys. The north face jacket is a winter essential goods.Columbia jacket and spyder jacket let people have more choice of clothes. Different brands have different design styles, but all it attracts us.
cheap tennis racquet
tennis racquet discount
cheap tennis racket
discount Tennis Racket
Modern tennis racquet in the manufacturing sector have been in use for close to the aerospace industry and military-industrial material products. Over the past two decades, metal materials and chemical materials to upgrade the high level of tennis racket manufacturer has laid a solid foundation. In today's big brands have more than tennis: Head junior tennis racket,Wilson tennis racquet, Wilson tennis racket,Head tennis racket,Babolat tennis racket......
ed hardy clothing
ed hardy clothes
ed hardy shirts
ed hardy t-shirts
ed hardy sunglasses
ed hardy mens
ed hardy womens
Wholesale Handbags
Cheap Handbags
Womens Handbags
Cheap Purses
Designer Handbags
Thank you so much!!polo shirt men'ssweate,cheap polo shirts cheap columbia jackets, lacoste sweater, ralph lauren polo shirts,ski clothing. Free Shipping, PayPal Payment. Enjoy your shopping experience on mensclothingus.com.We have mens polo shirts.
Awesome!!!Best wishes for you !!wholesale polo shirts is the father of the summer should be prepared to most commonly used item, it has both style and shape of polo clothing, and vest with a random function, so that in the short-sleeved apply to both on many occasions, the pink and black color men's polo shirts brought into effect, lightweight cotton, linen texture to demonstrate masculine temperament and sense of fashion exhaustively. polo shirts for sale
Wonderful!!You can find the father who desire fashionable, intellectual cheap polos simultaneously, you can find a psychologist to study the most harmonious of families should be pink mens clothing, so do not want to take the mature route for the father, buy cheap polos, the learn from such a walk in between the formal and casual styling, refined style to create a sense of mild authority.
Perfect!!You are a outstanding person!Have you ever wore chaussures puma, puma CAT,Puma shoes store gives some preview of puma speed cat,puma basket, puma speed, puma speed and other puma shoes. These puma sport items are at store recently and available for anyone.
Do not mean bad.Thank you so much!Men's polo shirts was the shirt of choice for diverse groups of teenagers.Brightly coloured polo shirts can make you look like a Day-glo dirigible.
Wonderful!You can find the father who desire fashionable eg,uggs fashion,you can enjoy uggs online here, intellectual polo shirt simultaneously.
fantastic!God bless you!Meanwhile,you can visit my China Wholesale,we have the highest quality but the lowest price fashion products wholesale from China.Here are the most popular China Wholesale products for all of you.Also the polo clothing is a great choice for you.
God bless you!I really agree with your opinions.Also,there are some new fashion things here,gillette razor blades.gillette mach3 razor bladesfor men.As for ladies,gillette venus razor blades must the best gift for you in summer,gillette fusion blades are all the best choice for you.
cheap hair straighteners
chi hair straightener
chi flat iron
new polo shirts
cheap Lacoste polo shirts
cheap Lacoste polo shirts
cheap handbags
cheap bags
puma chaussures
chaussures puma
chaussure puma
Men's North Face
Women's North Face
hair straighteners
sexy lingerie store
cheap ugg boots
tattoo wholesale
men's clothing
women's clothing
2009 nike shoes
new nike shoes
Women's max
Men's max 93
nike shox
Nike air force
Nike air max 2003
nike air max ltd
nike air max tn
Nike air rift
Nike air Yeezy
nike airmax
Nike air max 90
Nike air max 97
nike birds nest shoes
nike dunk
nike RT1 shoes
nike SB
nike shox shoes
Nike shox OZ shoes
Nike shox R2 shoes
Nike shox R3 shoes
Nike shox R4 shoes
Nike shox R5 shoes
Nike shox TL3
nike trainers lovers
tennis rackets
Wilson tennis rackets
HEAD tennis rackets
Babolat tennis rackets
視訊|影音視訊聊天室|視訊聊天室|視訊交友|視訊聊天|視訊美女|視訊辣妹|免費視訊聊天室
自慰器|自慰器
網頁設計|網頁設計公司|最新消息|訪客留言|網站導覽
免費視訊聊天|辣妹視訊|視訊交友網|美女視訊|視訊交友|視訊交友90739|成人聊天室|視訊聊天室|視訊聊天|視訊聊天室|情色視訊|情人視訊網|視訊美女
一葉情貼圖片區|免費視訊聊天室|免費視訊|ut聊天室|聊天室|豆豆聊天室|尋夢園聊天室|聊天室尋夢園|影音視訊聊天室||
Post a Comment
<< Home