#include "llvm/Module.h"
#include "llvm/Support/IRBuilder.h"
#include "llvm/ModuleProvider.h"
#include "llvm/ExecutionEngine/JIT.h"

using namespace llvm;

static float global[4] = {1, 1, 1, 1};

static Function *createFunction(Module *module, ExecutionEngine *executionEngine)
{
	Function *function = cast<Function>(module->getOrInsertFunction("", Type::VoidTy, (Type *)0));
	BasicBlock *BB = BasicBlock::Create("", function);
	IRBuilder *builder = new IRBuilder(BB);

	{
		GlobalValue *globalPointer = new GlobalVariable(VectorType::get(Type::FloatTy, 4), true, GlobalValue::ExternalLinkage, 0, "", module);
		globalPointer->setAlignment(1);
		executionEngine->addGlobalMapping(globalPointer, global);

		// Load global
		Value *vector1 = builder->Insert(new LoadInst(globalPointer, "", false, 1));

		// Shuffle a 0 into fourth element
		Constant *shuffle1[4];
		shuffle1[0] = ConstantInt::get(APInt(32, 0));
		shuffle1[1] = ConstantInt::get(APInt(32, 1));
		shuffle1[2] = ConstantInt::get(APInt(32, 2));
		shuffle1[3] = ConstantInt::get(APInt(32, 7));
		Value *vector2 = builder->CreateShuffleVector(vector1, ConstantVector::getNullValue(VectorType::get(Type::FloatTy, 4)), ConstantVector::get(shuffle1, 4));

		// Shuffle a 1 back into fourth element
		Constant *shuffle2[4];
		shuffle2[0] = ConstantInt::get(APInt(32, 4));
		shuffle2[1] = ConstantInt::get(APInt(32, 5));
		shuffle2[2] = ConstantInt::get(APInt(32, 6));
		shuffle2[3] = ConstantInt::get(APInt(32, 3));
		Value *vector3 = builder->CreateShuffleVector(vector1, vector2, ConstantVector::get(shuffle2, 4));

		// Store global
		builder->Insert(new StoreInst(vector3, globalPointer, false, 1));
	}

	builder->CreateRetVoid();

	return function;
}


int main()
{
	Module *module = new Module("");
	ExistingModuleProvider *MP = new ExistingModuleProvider(module);
	ExecutionEngine *executionEngine = ExecutionEngine::create(MP, false);
	Function *function = createFunction(module, executionEngine);

	((void(*)())executionEngine->getPointerToFunction(function))();

	assert(global[2] == 1);
}
