1e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer//===-- examples/ParallelJIT/ParallelJIT.cpp - Exercise threaded-safe JIT -===//
2e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer//
3e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer//                     The LLVM Compiler Infrastructure
4e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer//
5fc001bbfc360ab828e5a4b0cbe4bb7db87361b85Chris Lattner// This file is distributed under the University of Illinois Open Source
6fc001bbfc360ab828e5a4b0cbe4bb7db87361b85Chris Lattner// License. See LICENSE.TXT for details.
7e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer//
8e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer//===----------------------------------------------------------------------===//
9e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer//
10e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer// Parallel JIT
11e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer//
1200b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen// This test program creates two LLVM functions then calls them from three
13e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer// separate threads.  It requires the pthreads library.
14e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer// The three threads are created and then block waiting on a condition variable.
15e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer// Once all threads are blocked on the conditional variable, the main thread
16e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer// wakes them up. This complicated work is performed so that all three threads
17e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer// call into the JIT at the same time (or the best possible approximation of the
18e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer// same time). This test had assertion errors until I got the locking right.
19e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer
20e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer#include "llvm/ExecutionEngine/GenericValue.h"
214ca7e09b7c1e41535f2a1bd86915375d023daf27Chandler Carruth#include "llvm/ExecutionEngine/Interpreter.h"
224ca7e09b7c1e41535f2a1bd86915375d023daf27Chandler Carruth#include "llvm/ExecutionEngine/JIT.h"
230a08460599eed603e469e3e16d0cf6aa33b8ba93Chandler Carruth#include "llvm/IR/Constants.h"
240a08460599eed603e469e3e16d0cf6aa33b8ba93Chandler Carruth#include "llvm/IR/DerivedTypes.h"
250a08460599eed603e469e3e16d0cf6aa33b8ba93Chandler Carruth#include "llvm/IR/Instructions.h"
260a08460599eed603e469e3e16d0cf6aa33b8ba93Chandler Carruth#include "llvm/IR/LLVMContext.h"
270a08460599eed603e469e3e16d0cf6aa33b8ba93Chandler Carruth#include "llvm/IR/Module.h"
283e74d6fdd248e20a280f1dff3da9a6c689c2c4c3Evan Cheng#include "llvm/Support/TargetSelect.h"
29e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer#include <iostream>
304ca7e09b7c1e41535f2a1bd86915375d023daf27Chandler Carruth#include <pthread.h>
31e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencerusing namespace llvm;
32e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer
336a98754ebbc211958297b0d20a77e8c3261c3708Chris Lattnerstatic Function* createAdd1(Module *M) {
34e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  // Create the add1 function entry and insert this entry into module M.  The
35e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  // function will have a return type of "int" and take an argument of "int".
36e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  // The '0' terminates the list of argument types.
376a98754ebbc211958297b0d20a77e8c3261c3708Chris Lattner  Function *Add1F =
381d0be15f89cb5056e20e2d24faa8d6afb1573bcaOwen Anderson    cast<Function>(M->getOrInsertFunction("add1",
391d0be15f89cb5056e20e2d24faa8d6afb1573bcaOwen Anderson                                          Type::getInt32Ty(M->getContext()),
401d0be15f89cb5056e20e2d24faa8d6afb1573bcaOwen Anderson                                          Type::getInt32Ty(M->getContext()),
416a98754ebbc211958297b0d20a77e8c3261c3708Chris Lattner                                          (Type *)0));
4200b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
43e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  // Add a basic block to the function. As before, it automatically inserts
44e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  // because of the last argument.
451d0be15f89cb5056e20e2d24faa8d6afb1573bcaOwen Anderson  BasicBlock *BB = BasicBlock::Create(M->getContext(), "EntryBlock", Add1F);
4600b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
47e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  // Get pointers to the constant `1'.
481d0be15f89cb5056e20e2d24faa8d6afb1573bcaOwen Anderson  Value *One = ConstantInt::get(Type::getInt32Ty(M->getContext()), 1);
4900b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
50e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  // Get pointers to the integer argument of the add1 function...
51e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  assert(Add1F->arg_begin() != Add1F->arg_end()); // Make sure there's an arg
52e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  Argument *ArgX = Add1F->arg_begin();  // Get the arg
53e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  ArgX->setName("AnArg");            // Give it a nice symbolic name for fun.
5400b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
55e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  // Create the add instruction, inserting it into the end of BB.
567cbd8a3e92221437048b484d5ef9c0a22d0f8c58Gabor Greif  Instruction *Add = BinaryOperator::CreateAdd(One, ArgX, "addresult", BB);
5700b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
58e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  // Create the return instruction and add it to the basic block
591d0be15f89cb5056e20e2d24faa8d6afb1573bcaOwen Anderson  ReturnInst::Create(M->getContext(), Add, BB);
6000b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
6100b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen  // Now, function add1 is ready.
62e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  return Add1F;
63e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer}
64e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer
656a98754ebbc211958297b0d20a77e8c3261c3708Chris Lattnerstatic Function *CreateFibFunction(Module *M) {
66e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  // Create the fib function and insert it into module M.  This function is said
67e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  // to return an int and take an int parameter.
686a98754ebbc211958297b0d20a77e8c3261c3708Chris Lattner  Function *FibF =
691d0be15f89cb5056e20e2d24faa8d6afb1573bcaOwen Anderson    cast<Function>(M->getOrInsertFunction("fib",
701d0be15f89cb5056e20e2d24faa8d6afb1573bcaOwen Anderson                                          Type::getInt32Ty(M->getContext()),
711d0be15f89cb5056e20e2d24faa8d6afb1573bcaOwen Anderson                                          Type::getInt32Ty(M->getContext()),
726a98754ebbc211958297b0d20a77e8c3261c3708Chris Lattner                                          (Type *)0));
7300b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
74e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  // Add a basic block to the function.
751d0be15f89cb5056e20e2d24faa8d6afb1573bcaOwen Anderson  BasicBlock *BB = BasicBlock::Create(M->getContext(), "EntryBlock", FibF);
7600b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
77e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  // Get pointers to the constants.
781d0be15f89cb5056e20e2d24faa8d6afb1573bcaOwen Anderson  Value *One = ConstantInt::get(Type::getInt32Ty(M->getContext()), 1);
791d0be15f89cb5056e20e2d24faa8d6afb1573bcaOwen Anderson  Value *Two = ConstantInt::get(Type::getInt32Ty(M->getContext()), 2);
8000b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
81e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  // Get pointer to the integer argument of the add1 function...
82e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  Argument *ArgX = FibF->arg_begin();   // Get the arg.
83e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  ArgX->setName("AnArg");            // Give it a nice symbolic name for fun.
8400b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
85e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  // Create the true_block.
861d0be15f89cb5056e20e2d24faa8d6afb1573bcaOwen Anderson  BasicBlock *RetBB = BasicBlock::Create(M->getContext(), "return", FibF);
87e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  // Create an exit block.
881d0be15f89cb5056e20e2d24faa8d6afb1573bcaOwen Anderson  BasicBlock* RecurseBB = BasicBlock::Create(M->getContext(), "recurse", FibF);
8900b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
90e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  // Create the "if (arg < 2) goto exitbb"
91333c40096561218bc3597cf153c0a3895274414cOwen Anderson  Value *CondInst = new ICmpInst(*BB, ICmpInst::ICMP_SLE, ArgX, Two, "cond");
92051a950000e21935165db56695e35bade668193bGabor Greif  BranchInst::Create(RetBB, RecurseBB, CondInst, BB);
9300b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
94e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  // Create: ret int 1
951d0be15f89cb5056e20e2d24faa8d6afb1573bcaOwen Anderson  ReturnInst::Create(M->getContext(), One, RetBB);
9600b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
97e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  // create fib(x-1)
987cbd8a3e92221437048b484d5ef9c0a22d0f8c58Gabor Greif  Value *Sub = BinaryOperator::CreateSub(ArgX, One, "arg", RecurseBB);
99051a950000e21935165db56695e35bade668193bGabor Greif  Value *CallFibX1 = CallInst::Create(FibF, Sub, "fibx1", RecurseBB);
10000b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
101e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  // create fib(x-2)
1027cbd8a3e92221437048b484d5ef9c0a22d0f8c58Gabor Greif  Sub = BinaryOperator::CreateSub(ArgX, Two, "arg", RecurseBB);
103051a950000e21935165db56695e35bade668193bGabor Greif  Value *CallFibX2 = CallInst::Create(FibF, Sub, "fibx2", RecurseBB);
10400b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
105e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  // fib(x-1)+fib(x-2)
10600b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen  Value *Sum =
1077cbd8a3e92221437048b484d5ef9c0a22d0f8c58Gabor Greif    BinaryOperator::CreateAdd(CallFibX1, CallFibX2, "addresult", RecurseBB);
10800b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
109e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  // Create the return instruction and add it to the basic block
1101d0be15f89cb5056e20e2d24faa8d6afb1573bcaOwen Anderson  ReturnInst::Create(M->getContext(), Sum, RecurseBB);
11100b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
112e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  return FibF;
113e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer}
114e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer
115e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencerstruct threadParams {
116e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  ExecutionEngine* EE;
117e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  Function* F;
118e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  int value;
119e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer};
120e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer
121e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer// We block the subthreads just before they begin to execute:
122e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer// we want all of them to call into the JIT at the same time,
123e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer// to verify that the locking is working correctly.
124e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencerclass WaitForThreads
125e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer{
126e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencerpublic:
127e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  WaitForThreads()
128e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  {
129e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    n = 0;
130e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    waitFor = 0;
13100b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
132e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    int result = pthread_cond_init( &condition, NULL );
133e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    assert( result == 0 );
13400b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
135e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    result = pthread_mutex_init( &mutex, NULL );
136e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    assert( result == 0 );
137e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  }
13800b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
139e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  ~WaitForThreads()
140e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  {
141e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    int result = pthread_cond_destroy( &condition );
14236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    (void)result;
143e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    assert( result == 0 );
14400b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
145e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    result = pthread_mutex_destroy( &mutex );
146e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    assert( result == 0 );
147e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  }
14800b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
149e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  // All threads will stop here until another thread calls releaseThreads
150e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  void block()
151e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  {
152e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    int result = pthread_mutex_lock( &mutex );
15336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    (void)result;
154e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    assert( result == 0 );
155e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    n ++;
156e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    //~ std::cout << "block() n " << n << " waitFor " << waitFor << std::endl;
15700b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
158e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    assert( waitFor == 0 || n <= waitFor );
15900b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen    if ( waitFor > 0 && n == waitFor )
160e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    {
161e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer      // There are enough threads blocked that we can release all of them
162e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer      std::cout << "Unblocking threads from block()" << std::endl;
163e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer      unblockThreads();
16400b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen    }
16500b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen    else
166e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    {
167e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer      // We just need to wait until someone unblocks us
168e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer      result = pthread_cond_wait( &condition, &mutex );
169e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer      assert( result == 0 );
170e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    }
17100b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
172e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    // unlock the mutex before returning
173e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    result = pthread_mutex_unlock( &mutex );
174e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    assert( result == 0 );
175e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  }
17600b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
177e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  // If there are num or more threads blocked, it will signal them all
178e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  // Otherwise, this thread blocks until there are enough OTHER threads
179e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  // blocked
180e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  void releaseThreads( size_t num )
181e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  {
182e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    int result = pthread_mutex_lock( &mutex );
18336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    (void)result;
184e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    assert( result == 0 );
18500b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
186e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    if ( n >= num ) {
187e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer      std::cout << "Unblocking threads from releaseThreads()" << std::endl;
188e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer      unblockThreads();
18900b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen    }
19000b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen    else
191e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    {
192e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer      waitFor = num;
193e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer      pthread_cond_wait( &condition, &mutex );
194e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    }
19500b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
196e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    // unlock the mutex before returning
197e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    result = pthread_mutex_unlock( &mutex );
198e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    assert( result == 0 );
199e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  }
20000b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
201e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencerprivate:
202e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  void unblockThreads()
203e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  {
204e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    // Reset the counters to zero: this way, if any new threads
205e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    // enter while threads are exiting, they will block instead
206e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    // of triggering a new release of threads
207e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    n = 0;
20800b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
209e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    // Reset waitFor to zero: this way, if waitFor threads enter
210e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    // while threads are exiting, they will block instead of
211e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    // triggering a new release of threads
212e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    waitFor = 0;
213e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer
214e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer    int result = pthread_cond_broadcast( &condition );
215637f949a7fc97aa42e7360e9ed9462316b772d88Chandler Carruth    (void)result;
216637f949a7fc97aa42e7360e9ed9462316b772d88Chandler Carruth    assert(result == 0);
217e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  }
21800b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
219e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  size_t n;
220e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  size_t waitFor;
221e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  pthread_cond_t condition;
222e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  pthread_mutex_t mutex;
223e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer};
224e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer
225e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencerstatic WaitForThreads synchronize;
226e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer
227e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencervoid* callFunc( void* param )
228e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer{
229e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  struct threadParams* p = (struct threadParams*) param;
23000b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
231e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  // Call the `foo' function with no arguments:
232e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  std::vector<GenericValue> Args(1);
23334bd70de3c344034b82dc9a964a6b6893efa3e82Reid Spencer  Args[0].IntVal = APInt(32, p->value);
23400b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
235e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  synchronize.block(); // wait until other threads are at this point
236e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  GenericValue gv = p->EE->runFunction(p->F, Args);
23700b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
23834bd70de3c344034b82dc9a964a6b6893efa3e82Reid Spencer  return (void*)(intptr_t)gv.IntVal.getZExtValue();
239e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer}
240e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer
241da06288aeb28393b937e17dcd180658c3737a6e5Chris Lattnerint main() {
242da06288aeb28393b937e17dcd180658c3737a6e5Chris Lattner  InitializeNativeTarget();
2438b477ed579794ba6d76915d56b3f448a7dd20120Owen Anderson  LLVMContext Context;
244da06288aeb28393b937e17dcd180658c3737a6e5Chris Lattner
245e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  // Create some module to put our function into it.
24631895e73591d3c9ceae731a1274c8f56194b9616Owen Anderson  Module *M = new Module("test", Context);
24700b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
248e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  Function* add1F = createAdd1( M );
249e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  Function* fibF = CreateFibFunction( M );
25000b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
251e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  // Now we create the JIT.
2524b1511b027ce0b648b3379f2891816c25b46f515Reid Kleckner  ExecutionEngine* EE = EngineBuilder(M).create();
25300b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
254e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  //~ std::cout << "We just constructed this LLVM module:\n\n" << *M;
255e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  //~ std::cout << "\n\nRunning foo: " << std::flush;
25600b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
257e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  // Create one thread for add1 and two threads for fib
258e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  struct threadParams add1 = { EE, add1F, 1000 };
259e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  struct threadParams fib1 = { EE, fibF, 39 };
260e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  struct threadParams fib2 = { EE, fibF, 42 };
26100b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
262e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  pthread_t add1Thread;
263e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  int result = pthread_create( &add1Thread, NULL, callFunc, &add1 );
264e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  if ( result != 0 ) {
265e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer          std::cerr << "Could not create thread" << std::endl;
266e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer          return 1;
267e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  }
26800b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
269e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  pthread_t fibThread1;
270e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  result = pthread_create( &fibThread1, NULL, callFunc, &fib1 );
271e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  if ( result != 0 ) {
272e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer          std::cerr << "Could not create thread" << std::endl;
273e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer          return 1;
274e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  }
27500b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
276e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  pthread_t fibThread2;
277e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  result = pthread_create( &fibThread2, NULL, callFunc, &fib2 );
278e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  if ( result != 0 ) {
279e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer          std::cerr << "Could not create thread" << std::endl;
280e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer          return 1;
281e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  }
28200b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
283e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  synchronize.releaseThreads(3); // wait until other threads are at this point
28400b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
285e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  void* returnValue;
286e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  result = pthread_join( add1Thread, &returnValue );
287e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  if ( result != 0 ) {
288e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer          std::cerr << "Could not join thread" << std::endl;
289e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer          return 1;
290e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  }
2916fb0d735f0ffdf4cd1b0a1fa04bd436586097448Reid Spencer  std::cout << "Add1 returned " << intptr_t(returnValue) << std::endl;
29200b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
293e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  result = pthread_join( fibThread1, &returnValue );
294e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  if ( result != 0 ) {
295e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer          std::cerr << "Could not join thread" << std::endl;
296e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer          return 1;
297e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  }
2986fb0d735f0ffdf4cd1b0a1fa04bd436586097448Reid Spencer  std::cout << "Fib1 returned " << intptr_t(returnValue) << std::endl;
29900b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
300e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  result = pthread_join( fibThread2, &returnValue );
301e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  if ( result != 0 ) {
302e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer          std::cerr << "Could not join thread" << std::endl;
303e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer          return 1;
304e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  }
3056fb0d735f0ffdf4cd1b0a1fa04bd436586097448Reid Spencer  std::cout << "Fib2 returned " << intptr_t(returnValue) << std::endl;
30600b16889ab461b7ecef1c91ade101186b7f1fce2Jeff Cohen
307e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer  return 0;
308e8cdc8b3a372015728bfbe494e4a8949fb66f6a6Reid Spencer}
309