blob: e6943338e9ffa8adc36d438e908595a22fc34da1 [file] [log] [blame]
/*
* Copyright (C) 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Compile like so:
// clang++ -O3 -o ComplexTest ComplexTest.cpp -std=c++14 `~/Downloads/clang+llvm-3.7.0-x86_64-apple-darwin/bin/llvm-config --cppflags --cxxflags --ldflags --libs` -lcurses -g -lz
#include <vector>
#include <memory>
#include <chrono>
#include <sys/time.h>
#include <llvm/Support/raw_ostream.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/DataLayout.h>
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/Constants.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/Instructions.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/Verifier.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/Transforms/Utils/BasicBlockUtils.h>
#include <llvm/Pass.h>
#include <llvm/IR/LegacyPassManager.h>
#include <llvm/Support/Host.h>
#include <llvm/Analysis/Passes.h>
#include <llvm/Transforms/Scalar.h>
#include <llvm/Transforms/IPO.h>
#include <llvm/Transforms/IPO/PassManagerBuilder.h>
#include <llvm/ExecutionEngine/MCJIT.h>
#include <llvm/Support/ErrorHandling.h>
#include <llvm/Support/TargetSelect.h>
using namespace llvm;
using namespace std;
namespace {
template<typename ToType, typename FromType>
inline ToType bitwise_cast(FromType from)
{
static_assert(sizeof(FromType) == sizeof(ToType), "bitwise_cast size of FromType and ToType must be equal!");
union {
FromType from;
ToType to;
} u;
u.from = from;
return u.to;
}
double monotonicallyIncreasingTimeMS()
{
return chrono::duration_cast<chrono::microseconds>(
chrono::steady_clock::now().time_since_epoch()).count() / 1000.;
}
void run(unsigned numVars, unsigned numConstructs)
{
LLVMContext context;
Type* int32Ty = Type::getInt32Ty(context);
Module* module = new Module("complexModule", context);
Function* function = Function::Create(
FunctionType::get(int32Ty, false), GlobalValue::ExternalLinkage, "complexFunction", module);
vector<int32_t> varSlots;
for (unsigned i = numVars; i--;)
varSlots.push_back(i);
BasicBlock* current = BasicBlock::Create(context, "", function);
unique_ptr<IRBuilder<>> builder = make_unique<IRBuilder<>>(current);
vector<Value*> vars;
for (int32_t& varSlot : varSlots) {
Value* ptr = builder->CreateIntToPtr(builder->getInt64(bitwise_cast<intptr_t>(&varSlot)),
int32Ty->getPointerTo());
vars.push_back(builder->CreateLoad(ptr));
}
for (unsigned i = 0; i < numConstructs; ++i) {
if (i & 1) {
// Control flow diamond.
unsigned predicateVarIndex = ((i >> 1) + 2) % numVars;
unsigned thenIncVarIndex = ((i >> 1) + 0) % numVars;
unsigned elseIncVarIndex = ((i >> 1) + 1) % numVars;
BasicBlock* thenBlock = BasicBlock::Create(context, "", function);
BasicBlock* elseBlock = BasicBlock::Create(context, "", function);
BasicBlock* continuation = BasicBlock::Create(context, "", function);
builder->CreateCondBr(
builder->CreateICmpNE(vars[predicateVarIndex], builder->getInt32(0)),
thenBlock, elseBlock);
builder = make_unique<IRBuilder<>>(thenBlock);
Value* thenValue = builder->CreateAdd(vars[thenIncVarIndex], builder->getInt32(1));
builder->CreateBr(continuation);
builder = make_unique<IRBuilder<>>(elseBlock);
Value* elseValue = builder->CreateAdd(vars[elseIncVarIndex], builder->getInt32(1));
builder->CreateBr(continuation);
builder = make_unique<IRBuilder<>>(current = continuation);
PHINode* thenPhi = builder->CreatePHI(int32Ty, 2);
thenPhi->addIncoming(thenValue, thenBlock);
thenPhi->addIncoming(vars[thenIncVarIndex], elseBlock);
PHINode* elsePhi = builder->CreatePHI(int32Ty, 2);
elsePhi->addIncoming(elseValue, elseBlock);
elsePhi->addIncoming(vars[elseIncVarIndex], thenBlock);
vars[thenIncVarIndex] = thenPhi;
vars[elseIncVarIndex] = elsePhi;
} else {
// Loop.
BasicBlock* loopBody = BasicBlock::Create(context, "", function);
BasicBlock* continuation = BasicBlock::Create(context, "", function);
Value* startIndex = vars[((i >> 1) + 1) % numVars];
Value* startSum = builder->getInt32(0);
builder->CreateCondBr(
builder->CreateICmpNE(startIndex, builder->getInt32(0)),
loopBody, continuation);
builder = make_unique<IRBuilder<>>(loopBody);
PHINode* bodyIndex = builder->CreatePHI(int32Ty, 2);
PHINode* bodySum = builder->CreatePHI(int32Ty, 2);
bodyIndex->addIncoming(startIndex, current);
bodySum->addIncoming(startSum, current);
Value* newBodyIndex = builder->CreateSub(bodyIndex, builder->getInt32(1));
Value* newBodySum = builder->CreateAdd(
bodySum,
builder->CreateLoad(
builder->CreateIntToPtr(
builder->CreateAdd(
builder->getInt64(bitwise_cast<intptr_t>(&varSlots[0])),
builder->CreateShl(
builder->CreateZExt(
builder->CreateAnd(
newBodyIndex,
builder->getInt32(numVars - 1)),
Type::getInt64Ty(context)),
builder->getInt64(2))),
int32Ty->getPointerTo())));
bodyIndex->addIncoming(newBodyIndex, loopBody);
bodySum->addIncoming(newBodySum, loopBody);
builder->CreateCondBr(
builder->CreateICmpNE(newBodyIndex, builder->getInt32(0)),
loopBody, continuation);
builder = make_unique<IRBuilder<>>(continuation);
PHINode* finalSum = builder->CreatePHI(int32Ty, 2);
finalSum->addIncoming(startSum, current);
finalSum->addIncoming(newBodySum, loopBody);
current = continuation;
vars[((i >> 1) + 0) % numVars] = finalSum;
}
}
builder->CreateRet(vars[0]);
builder = nullptr;
unique_ptr<ExecutionEngine> EE;
{
std::string errorMessage;
EngineBuilder builder((std::unique_ptr<Module>(module)));
builder.setMArch("");
builder.setMCPU(sys::getHostCPUName());
builder.setMAttrs(std::vector<std::string>());
builder.setRelocationModel(Reloc::Default);
builder.setCodeModel(CodeModel::JITDefault);
builder.setErrorStr(&errorMessage);
builder.setEngineKind(EngineKind::JIT);
builder.setOptLevel(CodeGenOpt::Default);
{
TargetOptions Options;
Options.FloatABIType = FloatABI::Default;
builder.setTargetOptions(Options);
}
EE = unique_ptr<ExecutionEngine>(builder.create());
}
legacy::PassManager passManager;
//passManager.add(new DataLayout(*EE->getDataLayout()));
passManager.add(createPromoteMemoryToRegisterPass());
passManager.add(createConstantPropagationPass());
passManager.add(createInstructionCombiningPass());
passManager.add(createBasicAliasAnalysisPass());
passManager.add(createTypeBasedAliasAnalysisPass());
passManager.add(createGVNPass());
passManager.add(createCFGSimplificationPass());
passManager.run(*module);
EE->getFunctionAddress(function->getName());
}
} // anonymous namespace
int main(int c, char** v)
{
InitializeAllTargets();
InitializeAllTargetMCs();
InitializeAllAsmPrinters();
InitializeAllAsmParsers();
for (unsigned i = 1; i <= 3; ++i) {
printf("Doing: run(4, %u)\n", i * 128);
double before = monotonicallyIncreasingTimeMS();
run(4, 128 * i);
double after = monotonicallyIncreasingTimeMS();
printf("That took %lf ms.\n", after - before);
}
for (unsigned i = 1; i <= 3; ++i) {
printf("Doing: run(64, %u)\n", i * 128);
double before = monotonicallyIncreasingTimeMS();
run(64, 128 * i);
double after = monotonicallyIncreasingTimeMS();
printf("That took %lf ms.\n", after - before);
}
return 0;
}