something wrong when I declare an int64 global variable in llvm - llvm

I'm trying using llvm to build my own dsl.
Here I meet a strange problem when I'm using VS2017 win32 mode.
I defined a int64 global variable in one module with value 3 by external linkage.
Then when I declare this variable in another module and load it's value, I got 12884901891(same as 0x300000003). When I try this on Linux, it works well.
Hope someone can help me.
Blow is my code.CJITEngine is a simple singleton package.
PS. If I define the global variable with other type rather than int64, such as int32,float,double, this code can run well.
int main()
{
CJITEngine::Instance().Init();
DataLayout &layout = CJITEngine::Instance().GetDataLayout();
using fpType = void(*)(int64_t*);
fpType fp = nullptr;
string name("aaaaaaaa");
{
unique_ptr<Module> pModule = CJITEngine::Instance().CreateModule("module1");
IRBuilder<>& m_oBuilder = CJITEngine::Instance().GetIRBuilder();
Type* pType = m_oBuilder.getInt64Ty();
GlobalVariable* pVarValue = new GlobalVariable(*pModule, pType, false, GlobalValue::ExternalLinkage,
m_oBuilder.getInt64(3), name);
pVarValue->setAlignment(layout.getABITypeAlignment(pType));
pVarValue->setDSOLocal(true);
pModule->addModuleFlag(Module::Error, "NumRegisterParameters", m_oBuilder.getInt32(0));
pModule->addModuleFlag(Module::Error, "wchar_size", m_oBuilder.getInt32(2));
pModule->print(outs(), nullptr);
std::cout << "--------------------------------------------------------" << std::endl;
CJITEngine::Instance().AddModule(std::move(pModule));
}
/////////////////////////////////////////////////////////
{
unique_ptr<Module> pModule = CJITEngine::Instance().CreateModule("module2");
LLVMContext& m_oContext = CJITEngine::Instance().GetContext();
IRBuilder<>& m_oBuilder = CJITEngine::Instance().GetIRBuilder();
Type* pType = m_oBuilder.getInt64Ty();
GlobalVariable* pVarValue = new GlobalVariable(*pModule, pType, false, GlobalValue::ExternalLinkage,
nullptr, name);
pVarValue->setAlignment(layout.getABITypeAlignment(pType));
pVarValue->setDSOLocal(true);
FunctionType* pFuncType = FunctionType::get(m_oBuilder.getVoidTy(), {Type::getInt64PtrTy(m_oContext)}, false);
Function* pFunc = Function::Create(pFuncType, Function::ExternalLinkage, "func", pModule.get());
pFunc->setDSOLocal(true);
BasicBlock* pEntryBlock = BasicBlock::Create(m_oContext, "entry", pFunc);
BasicBlock* pExitBlock = BasicBlock::Create(m_oContext, "exit");
m_oBuilder.SetInsertPoint(pEntryBlock);
auto agr = pFunc->args().begin();
AllocaInst* pParam = m_oBuilder.CreateAlloca(agr->getType());
pParam->setAlignment(layout.getABITypeAlignment(Type::getInt64PtrTy(m_oContext)));
m_oBuilder.CreateAlignedStore(agr, pParam, layout.getABITypeAlignment(Type::getInt64PtrTy(m_oContext)));
Value* pStr = m_oBuilder.CreateAlignedLoad(pVarValue, layout.getABITypeAlignment(Type::getInt64Ty(m_oContext)));
Value* ppp= m_oBuilder.CreateAlignedLoad(pParam, layout.getABITypeAlignment(Type::getInt64PtrTy(m_oContext)));
m_oBuilder.CreateAlignedStore(pStr, ppp, layout.getABITypeAlignment(Type::getInt64Ty(m_oContext)));
m_oBuilder.CreateRetVoid();
pModule->addModuleFlag(Module::Error, "NumRegisterParameters", m_oBuilder.getInt32(0));
pModule->addModuleFlag(Module::Error, "wchar_size", m_oBuilder.getInt32(2));
pModule->print(outs(), nullptr);
CJITEngine::Instance().AddModule(std::move(pModule));
JITSymbol symbol = CJITEngine::Instance().FindSymbol("func");
fp = (fpType)static_cast<intptr_t>(cantFail(symbol.getAddress()));
int64_t x = 10;
fp(&x);
std::cout << hex << x << endl; // x is 0x300000003 here
}
return 0;
}

Related

How can I update global variable value in LLVM IR using IRBuilder?

I want to update value of global variable in LLVM IR.
I created new global variable in ModulePass:
bool runOnModule(llvm::Module &M) {
IRBuilder<> Builder(M.getContext());
Instruction *I = &*inst_begin(M.getFunction("main"));
Builder.SetInsertPoint(I);
M.getOrInsertGlobal("globalKey", Builder.getInt64Ty());
GlobalVariable* gVar = M.getNamedGlobal("globalKey");
gVar->setLinkage(GlobalValue::InternalLinkage);
gVar->setAlignment(Align(8));
gVar->setInitializer(Builder.getInt64(0));
gVar->setConstant(false);
for (Function &F : M.functions()) {
InstructionVisitor visitor(DL, getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F));
for (Instruction &I : instructions(F)) {
visitor.visit(I);
}
}
return true;
}
Later in InstructionVisitor I try to increment globalKey on each allocation and print it using printf function:
Instruction* InstructionVisitor::print(Instruction* I, const char* text, Value* arg1, Value* arg2, Value* arg3, Value* arg4) {
Function* printfFn = I->getModule()->getFunction("printf");
if (printfFn) {
IRBuilder<> Builder(I->getContext());
Builder.SetInsertPoint(I->getNextNode());
Value* convertedText = Builder.CreateGlobalStringPtr(text);
std::vector <Value *> params;
params.push_back(convertedText);
if (arg1)
params.push_back(arg1);
if (arg2)
params.push_back(arg2);
if (arg3)
params.push_back(arg3);
if (arg4)
params.push_back(arg4);
return Builder.CreateCall(printfFn, params);
}
return I;
}
Instruction* InstructionVisitor::incrementGlobalKey(Instruction* I) {
IRBuilder<> Builder(I->getContext());
Builder.SetInsertPoint(I->getNextNode());
GlobalVariable* key = I->getModule()->getNamedGlobal("globalKey");
if (key) {
LoadInst* load = Builder.CreateLoad(key);
Value* inc = Builder.CreateAdd(load, Builder.getInt64(1));
StoreInst* store = Builder.CreateStore(inc, key);
return store;
}
return I;
}
void InstructionVisitor::visitCallInst(CallInst &CI) {
if (isAllocationFn(&CI, &TLI)) {
Value* allocatedAddress = &CI;
Instruction* I = &CI;
Value* allocatedSize = I->getOperand(0);
Instruction* next = incrementGlobalKey(I);
GlobalVariable* key = I->getModule()->getNamedGlobal("globalKey");
const char* message = "Allocated address: 0x%p, size: %d, key: 0x%x\n";
print(next, message, allocatedAddress, allocatedSize, key->getOperand(0));
}
}
I print that global variable during execution of instrumented code (using injected printf call). I access it's value by key->getOperand(0) (as shown above), but it's unchanged. I'm using ORC JIT based on this tutorial: https://llvm.org/docs/tutorial/BuildingAJIT2.html and I run ModulePass from optimizeModule function from this tutorial.
IR, souce code that I'm instrumenting and program output can be found here:
https://pastebin.com/JbDR2Wug
Does anyone know how to make it work? I will be grateful for help!
After #droptop helpful comment I changed my code to actually load the global variable's value using load instruction. It works fine now. Updated code is shown below if anyone need it:
Instruction* InstructionVisitor::getGlobalValue(Instruction* I, StringRef Name) {
IRBuilder<> Builder(I->getContext());
Builder.SetInsertPoint(I->getNextNode());
GlobalVariable* key = I->getModule()->getNamedGlobal(Name);
if (key) {
LoadInst* load = Builder.CreateLoad(key);
return load;
}
return nullptr;
}
void InstructionVisitor::visitCallInst(CallInst &CI) {
if (isAllocationFn(&CI, &TLI)) {
Value* allocatedAddress = &CI;
Instruction* I = &CI;
Value* allocatedSize = I->getOperand(0);
Instruction* next = incrementGlobalKey(I, allocatedAddress, allocatedSize);
Instruction* loadKey = getGlobalValue(next, "globalKey"); //here
const char* message = "Allocated address: 0x%p, size: %d, key: %lld\n";
next = print(loadKey, message, allocatedAddress, allocatedSize, loadKey);
}
}

Vulkan timeline semaphore extension cannot be enabled

I've been at this for a better part of today and I'm at the end of my wits.
I'm running Vulkan SDK 1.2.131.2
I have a RTX 2080 Ti.
I have Windows 10 Education, version 1909, build 18363.657.
I'm using Vulkan.hpp instead of Vulkan.h directly.
Here is where I specify the API version I use:
appInfo.apiVersion = VK_API_VERSION_1_2;
This is the relevant part of the code that creates the device:
// bla bla
const std::vector<const char*> deviceExtensions = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME,
VK_NV_RAY_TRACING_EXTENSION_NAME
};
deviceCreateInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions.data();
m_logicalDevice = m_physicalDevice.createDeviceUnique(deviceCreateInfo);
I use the following validation layers:
"VK_LAYER_LUNARG_api_dump"
"VK_LAYER_KHRONOS_validation"
This is how I later try to create a timeline semaphore:
vk::UniqueSemaphore VulkanContext::createTimelineSemaphore(const uint32_t initialValue) const {
vk::SemaphoreTypeCreateInfo timelineCreateInfo;
timelineCreateInfo.semaphoreType = vk::SemaphoreType::eTimeline;
timelineCreateInfo.initialValue = initialValue;
vk::SemaphoreCreateInfo createInfo;
createInfo.pNext = &timelineCreateInfo;
return m_logicalDevice->createSemaphoreUnique(createInfo);
}
I get the following error:
vkCreateSemaphore(device, pCreateInfo, pAllocator, pSemaphore) returns VkResultVkCreateSemaphore: timelineSemaphore feature is not enabled, can not create timeline semaphores The Vulkan spec states: If the timelineSemaphore feature is not enabled, semaphoreType must not equal VK_SEMAPHORE_TYPE_TIMELINE (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSemaphoreTypeCreateInfo-timelineSemaphore-03252)
This is even more infuriating because timeline semaphores are supposed to be part of the core Vulkan 1.2, but I get the same error even if I ommit it from the extension list. Swapchain extension does work and I haven't had the time to verify that ray tracing extension is enabled.
It gets even more stupid because the next message tells me this:
VK_SUCCESS (0):
device: VkDevice = 0000023AA29BD8B0
pCreateInfo: const VkSemaphoreCreateInfo* = 0000008D145ED538:
sType: VkStructureType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO (9)
pNext: VkSemaphoreTypeCreateInfo = 0000008D145ED4F8:
sType: VkStructureType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO (1000207002)
pNext: const void* = NULL
semaphoreType: VkSemaphoreType = VK_SEMAPHORE_TYPE_TIMELINE (1)
initialValue: uint64_t = 0
flags: VkSemaphoreCreateFlags = 0
pAllocator: const VkAllocationCallbacks* = NULL
pSemaphore: VkSemaphore* = AA989B000000001E
I have no idea if this creates the timeline semaphore or just creates a normal binary one.
When I later use it to submit to a transfer queue:
vk::CommandBufferBeginInfo beginInfo;
transferCmdBuffer->begin(beginInfo);
object->recordUploadToGPU(*transferCmdBuffer);
transferCmdBuffer->end();
vk::TimelineSemaphoreSubmitInfo timelineSubmitInfo;
timelineSubmitInfo.signalSemaphoreValueCount = 1;
timelineSubmitInfo.pSignalSemaphoreValues = &signalValue;
vk::SubmitInfo submitInfo;
submitInfo.pNext = &timelineSubmitInfo;
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = &signalSemaphore;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &*transferCmdBuffer;
vkCtx.m_transferQueue.submit(submitInfo, nullptr);
I get this error here:
vkQueueSubmit(queue, submitCount, pSubmits, fence) returns VkResultVkQueueSubmit: VkQueue 0x23aa2539500[] contains timeline sempahore VkSemaphore 0xaa989b000000001e[] that sets its wait value with a margin greater than maxTimelineSemaphoreValueDifference The Vulkan spec states: For each element of pSignalSemaphores created with a VkSemaphoreType of VK_SEMAPHORE_TYPE_TIMELINE the corresponding element of VkTimelineSemaphoreSubmitInfo::pSignalSemaphoreValues must have a value which does not differ from the current value of the semaphore or the value of any outstanding semaphore wait or signal operation on that semaphore by more than maxTimelineSemaphoreValueDifference. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubmitInfo-pSignalSemaphores-03244)
And just to be futher mocked, this is the next line:
VK_SUCCESS (0):
queue: VkQueue = 0000023AA2539500
submitCount: uint32_t = 1
pSubmits: const VkSubmitInfo* = 0000008D145ED370
pSubmits[0]: const VkSubmitInfo = 0000008D145ED370:
sType: VkStructureType = VK_STRUCTURE_TYPE_SUBMIT_INFO (4)
pNext: VkTimelineSemaphoreSubmitInfo = 0000008D145ED318:
sType: VkStructureType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO (1000207003)
pNext: const void* = NULL
waitSemaphoreValueCount: uint32_t = 0
pWaitSemaphoreValues: const uint64_t* = NULL
signalSemaphoreValueCount: uint32_t = 1
pSignalSemaphoreValues: const uint64_t* = 0000008D145ED740
pSignalSemaphoreValues[0]: const uint64_t = 1
waitSemaphoreCount: uint32_t = 0
pWaitSemaphores: const VkSemaphore* = NULL
pWaitDstStageMask: const VkPipelineStageFlags* = NULL
commandBufferCount: uint32_t = 1
pCommandBuffers: const VkCommandBuffer* = 0000008D145EF408
pCommandBuffers[0]: const VkCommandBuffer = 0000023AA9CEC8E0
signalSemaphoreCount: uint32_t = 1
pSignalSemaphores: const VkSemaphore* = 0000008D145EF430
pSignalSemaphores[0]: const VkSemaphore = AA989B000000001E
fence: VkFence = 0000000000000000
I've also tried with VK_API_VERSION_1_1 and VK_API_VERSION_1_0, both with and without enabling the extension explicitly, none of them work.
The dumps are from the VK_LAYER_LUNARG_api_dump validation layer, while VK_LAYER_KHRONOS_validation validation layer is the one spewing out the errors. They seem to disagree.
So, what gives?
In what way am I stupid today?
EDIT:
Here is an example that you should be able to run yourself. I think I made it as minimal as I can:
#include <vulkan/vulkan.hpp>
#include <iostream>
VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageType,
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
void* pUserData) {
std::cerr << pCallbackData->pMessage << std::endl;
return VK_FALSE;
};
int main() {
vk::ApplicationInfo appInfo;
appInfo.apiVersion = VK_API_VERSION_1_2;
vk::InstanceCreateInfo instanceCreateInfo;
instanceCreateInfo.pApplicationInfo = &appInfo;
std::vector<const char*> extensions;
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
instanceCreateInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
instanceCreateInfo.ppEnabledExtensionNames = extensions.data();
const std::vector<const char*> validationLayers = {
"VK_LAYER_LUNARG_api_dump",
"VK_LAYER_KHRONOS_validation"
};
instanceCreateInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
instanceCreateInfo.ppEnabledLayerNames = validationLayers.data();
vk::DebugUtilsMessengerCreateInfoEXT debugCreateInfo;
debugCreateInfo.messageSeverity =
vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eError;
debugCreateInfo.messageType =
vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation |
vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance;
debugCreateInfo.pfnUserCallback = debugCallback;
instanceCreateInfo.pNext = &debugCreateInfo;
vk::Instance m_instance = vk::createInstance(instanceCreateInfo);
vk::DispatchLoaderDynamic m_loader = vk::DispatchLoaderDynamic(m_instance, vkGetInstanceProcAddr);
vk::DebugUtilsMessengerEXT m_debugMessenger = m_instance.createDebugUtilsMessengerEXT(debugCreateInfo, nullptr, m_loader);
vk::PhysicalDevice m_physicalDevice = m_instance.enumeratePhysicalDevices()[0];
std::vector<vk::DeviceQueueCreateInfo> queueCreateInfos;
vk::DeviceQueueCreateInfo queueInfo;
queueInfo.queueFamilyIndex = 0;
queueInfo.queueCount = 1;
queueCreateInfos.push_back(queueInfo);
vk::PhysicalDeviceFeatures deviceFeatures;
vk::DeviceCreateInfo deviceCreateInfo;
deviceCreateInfo.pQueueCreateInfos = queueCreateInfos.data();
deviceCreateInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
deviceCreateInfo.pEnabledFeatures = &deviceFeatures;
// This part can be omitted from here...
const std::vector<const char*> deviceExtensions = {
VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME
};
deviceCreateInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions.data();
// ...to here. It doesn't work either way.
vk::Device m_logicalDevice = m_physicalDevice.createDevice(deviceCreateInfo);
vk::SemaphoreTypeCreateInfo timelineCreateInfo;
timelineCreateInfo.semaphoreType = vk::SemaphoreType::eTimeline;
timelineCreateInfo.initialValue = 0;
vk::SemaphoreCreateInfo semaphoreCreateInfo;
semaphoreCreateInfo.pNext = &timelineCreateInfo;
m_logicalDevice.createSemaphore(semaphoreCreateInfo);
}
The feature needs to be enabled explicitly as well:
vk::PhysicalDeviceVulkan12Features features;
features.timelineSemaphore = true;
vk::DeviceCreateInfo deviceCreateInfo;
deviceCreateInfo.pNext = &features;

LLVM how to map custom function call to printf

I just started with LLVM. I am using C++ to create a compiler for Pascal-like language. Given that print functions are system calls, how do I map from my language writeln(5) to the system function printf ("%d",5)? I thought that code below should do it.
NamedValues.clear();
vector<Type *> Doubles(1, Type::getInt32Ty(TheContext));
FunctionType * FT = FunctionType::get(Type::getInt32Ty(TheContext), Doubles, false);
Function * function = Function::Create(FT, Function::ExternalLinkage, "writeln", TheModule.get());
// create function body
BasicBlock * BB = BasicBlock::Create(TheContext, "entry", function);
Builder.SetInsertPoint(BB);
// get param
Function::arg_iterator AI = function->arg_begin();
Value * val = AI;
AI->setName("val");
// get format string
string format = "%d";
Constant * ConstStr = ConstantDataArray::getString(TheContext, format.c_str());
ConstStr = new GlobalVariable(*TheModule, ConstStr->getType(), true, GlobalValue::InternalLinkage, ConstStr, format);
Constant * Idxs[] = {ConstantInt::get(Type::getInt32Ty(TheContext), 0), 0};
Idxs[1] = Idxs[0];
// make params
vector<Type *> params;
params.push_back(PointerType::getUnqual(Type::getInt8Ty(TheContext)));
// get printf function
FunctionCallee PrintF = TheModule->getOrInsertFunction("printf", FunctionType::get(Type::getVoidTy(TheContext), params, true));
// call
/*
* CallInst *CreateCall(FunctionCallee Callee, ArrayRef<Value *> Args = None,
const Twine &Name = "", MDNode *FPMathTag = nullptr)
*/
Builder.CreateCall(PrintF.getFunctionType(), ConstantExpr::getGetElementPtr(ConstStr->getType(), ConstStr, Idxs), val);
Builder.CreateRet(Builder.getInt32(0));
main_loop();
Error I got:
Assertion failed: (Ty == cast<PointerType>(C->getType()->getScalarType())->getElementType()), function getGetElementPtr, file /Users/ustynov/Documents/Study/HOMEWORKS/semestralwork/llvm/lib/IR/Constants.cpp, line 2012.

Retrieve ptr from function call asmjit

I am trying to generate a function call using AsmJit to which I pass an char*. This char* is in itself retrieved from another function call. I tried out this:
typedef
const char* getStr();
const char* getStrImpl() {
return "hello pie";
}
void use_str_impl(int id, const char* c_str) {
// do stuff...
}
int main() {
JitRuntime rt;
CodeHolder code;
code.init(rt.getCodeInfo());
X86Compiler c(&code);
auto jitted_func = c.addFunc(FuncSignature0<const char*>(code.getCodeInfo().getCdeclCallConv()));
auto err = c.getLastError();
auto call = c.call((uint64_t) fooFuncImpl, FuncSignature0<intptr_t>());
X86Gpd res(call->getRet().getId());
auto call2 = c.call((uint64_t) send_input, FuncSignature2<void, int, intptr_t>());
err = !call2->setArg(0, Imm(42));
err = !call2->setArg(1, res);
c.ret();
c.endFunc();
err = c.finalize();
if(err) return 0;
size_t size = code.getCodeSize();
VMemMgr vm;
void* p = vm.alloc(size);
if (!p) return 0;
code.relocate(p);
auto fun = (entrypoint*) p;
fun();
}
It turns out this does not generate any instructions for the second parameter or second call to setArg. I also tried to use .newIntPtr and using move instructions to move the result of call into place. But this generated dec and add instructions which made no sense to me and my small experience with assembly. What is the correct way of doing this type of thing?
Btw I am using the AsmJit next branch.
I have done few corrections to your sample with some comments.
Better Usage of JitRuntime:
JitRuntime rt;
size_t size = code.getCodeSize();
VMemMgr vm;
....
void* p = vm.alloc(size);
if (!p) return 0;
code.relocate(p);
auto fun = (entrypoint*) p;
You have used JitRuntime just to setup the parameters for CodeHolder, but then avoided it and allocated the memory for the function yourself. While that's a valid use case it's not what most people do. Using runtime's add() is sufficient in most cases.
Invalid use of CCFuncCall::getRet():
X86Gpd res(call->getRet().getId());
The call node at this point doesn't have any return register assigned so it would return an invalid id. If you need to create a virtual register you always have to call compiler's newSomething(). AsmJit's compiler provides API to check for that case at runtime, if you are unsure:
// Would print 0
printf("%d", (int)c.isVirtRegValid(call->getRet().getId()));
The solution is to create a new virtual register and ASSIGN it to the function's return value. Assigning return value requires an index (like assigning an argument), the reason is that some functions may return multiple values(like 64-bit value in 32-bit mode), using 0 as index is sufficient most of the time.
X86Gp reg = c.newIntPtr("reg");
call->setRet(0, reg);
You can verify getRet() functionality:
X86Gp reg = c.newIntPtr("reg");
assert(call->getRet(0).isNone());
call->setRet(0, reg);
assert(call->getRet(0) == reg);
Fully working example:
#include <stdio.h>
#include <asmjit/asmjit.h>
const char* func_a() {
printf("func_a(): Called\n");
return "hello pie";
}
void func_b(int id, const char* c_str) {
printf("func_b(%d, %s): Called\n", id, c_str);
}
int main() {
using namespace asmjit;
JitRuntime rt;
CodeHolder code;
code.init(rt.getCodeInfo());
X86Compiler c(&code);
X86Gp reg = c.newIntPtr("reg");
// Compilation step...
c.addFunc(FuncSignature0<void>(code.getCodeInfo().getCdeclCallConv()));
auto call_a = c.call((uint64_t)func_a, FuncSignature0<intptr_t>());
call_a->setRet(0, reg);
auto call_b = c.call((uint64_t)func_b, FuncSignature2<void, int, intptr_t>());
call_b->setArg(0, Imm(42));
call_b->setArg(1, reg);
c.ret();
c.endFunc();
// Finalize does the following:
// - allocates virtual registers
// - inserts prolog / epilog
// - assembles to CodeHolder
auto err = c.finalize();
if (err) {
printf("COMPILER FAILED: %s\b", DebugUtils::errorAsString(err));
return 1;
}
typedef void (*EntryPoint)(void);
EntryPoint entry;
// Adds function to the runtime. Should be freed by rt.release().
// Function is valid until the runtime is valid if not released.
err = rt.add(&entry, &code);
if (err) {
printf("RUNTIME FAILED: %s\b", DebugUtils::errorAsString(err));
return 1;
}
entry();
return 0;
}
I am trying to create a function that receives and returns a double. For the call method I used the approach with Mem. At the end I need to save the result in the variable xmm1.
I can't identify the error. The sine function is called correctly. But for the final assembler generation error occurs.
JitRuntime rt;
CodeHolder code;
code.init(rt.codeInfo());
asmjit::x86::Compiler cc(&code);
asmjit::x86::Gp reg = cc.newIntPtr("reg");
asmjit::Zone zonee(1024);
asmjit::ConstPool constPool(&zonee);
asmjit::Label constPoolLabel = cc.newLabel();
// Compilation step...
// c.addFunc(asmjit::FuncSignatureT<void>(code.codeInfo().getCdeclCallConv()));
cc.addFunc(asmjit::FuncSignatureT<void>());
auto call_a = cc.call((uint64_t)func_a, FuncSignatureT<intptr_t>());
call_a->setRet(0, reg);
auto call_b = cc.call((uint64_t)func_b, FuncSignatureT<void, int, intptr_t>());
call_b->setArg(0, Imm(42));
call_b->setArg(1, reg);
auto seno = [&](double value) {
size_t valueOffset;
double seno = static_cast<double_t>(std::sin(value));
cout << " seno " << seno << endl;
constPool.add(&seno, sizeof(double), valueOffset);
return asmjit::x86::ptr(constPoolLabel, valueOffset);
};
asmjit::x86::Mem mem;
double test = 180.5;
auto call_c = cc.call(seno(test), asmjit::FuncSignatureT<double_t>());
call_c->setArg(0, asmjit::Imm(test));
call_c->_setRet(0, mem);
cc.movsd(asmjit::x86::xmm1, mem);
cc.ret();
cc.endFunc();
// Finalize does the following:
// - allocates virtual registers
// - inserts prolog / epilog
// - assembles to CodeHolder
auto err = cc.finalize();
if (err) {
printf("COMPILER FAILED: %s\b", DebugUtils::errorAsString(err));
return;
}
typedef void (*EntryPoint)(void);
EntryPoint entry;
// Adds function to the runtime. Should be freed by rt.release().
// Function is valid until the runtime is valid if not released.
err = rt.add(&entry, &code);
if (err) {
printf("RUNTIME FAILED: %s\b", DebugUtils::errorAsString(err));
return;
}
entry();
return;
perhaps the memory object should relate to some memory address?
Mem mem = qword_ptr ((uint64_t) &test);

LLVM Test Example Issue with Type Comparison

I am working on an example from the LLVM Essentials book. The section is called Emitting if-else condition IR, and I keep getting the following error.
Assertion failed: (getOperand(0)->getType() == getOperand(1)->getType()
&& "Both operands to ICmp instruction are not of the same type!"),
function AssertOK,
file /usr/local/Cellar/llvm/3.6.2/include/llvm/IR/Instructions.h, line
997. Abort trap: 6
I've spent hours trying to figure this out, but I'm at my wit's end. I'm sure it's something minor, but I have no idea. The code I am using is below.
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include <vector>
#include <iostream>
#include <typeinfo>
using namespace llvm;
static LLVMContext &Context = getGlobalContext();
static Module *ModuleOb = new Module("my compiler", Context);
static std::vector<std::string> FunArgs;
typedef SmallVector<BasicBlock *, 16> BBList;
typedef SmallVector<Value *, 16> ValList;
Function *createFunc(IRBuilder<> &Builder, std::string Name) {
std::vector<Type *> Integers(FunArgs.size(), Type::getInt32Ty(Context));
FunctionType *funcType =
llvm::FunctionType::get(Builder.getInt32Ty(), Integers, false);
Function *fooFunc = llvm::Function::Create(
funcType, llvm::Function::ExternalLinkage, Name, ModuleOb);
return fooFunc;
}
void setFuncArgs(Function *fooFunc, std::vector<std::string> FunArgs) {
unsigned Idx = 0;
Function::arg_iterator AI, AE;
for (AI = fooFunc->arg_begin(), AE = fooFunc->arg_end(); AI != AE;
++AI, ++Idx)
AI->setName(FunArgs[Idx]);
}
BasicBlock *createBB(Function *fooFunc, std::string Name) {
return BasicBlock::Create(Context, Name, fooFunc);
}
GlobalVariable *createGlob(IRBuilder<> &Builder, std::string Name) {
ModuleOb->getOrInsertGlobal(Name, Builder.getInt32Ty());
GlobalVariable *gVar = ModuleOb->getNamedGlobal(Name);
gVar->setLinkage(GlobalValue::CommonLinkage);
gVar->setAlignment(4);
return gVar;
}
Value *createArith(IRBuilder<> &Builder, Value *L, Value *R) {
return Builder.CreateMul(L, R, "multmp");
}
Value *createIfElse(IRBuilder<> &Builder, BBList List, ValList VL) {
Value *Condtn = VL[0];
Value *Arg1 = VL[1];
BasicBlock *ThenBB = List[0];
BasicBlock *ElseBB = List[1];
BasicBlock *MergeBB = List[2];
Builder.CreateCondBr(Condtn, ThenBB, ElseBB);
Builder.SetInsertPoint(ThenBB);
Value *ThenVal = Builder.CreateAdd(Arg1, Builder.getInt32(1), "thenaddtmp");
Builder.CreateBr(MergeBB);
Builder.SetInsertPoint(ElseBB);
Value *ElseVal = Builder.CreateAdd(Arg1, Builder.getInt32(2), "elseaddtmp");
Builder.CreateBr(MergeBB);
unsigned PhiBBSize = List.size() - 1;
Builder.SetInsertPoint(MergeBB);
PHINode *Phi = Builder.CreatePHI(Type::getInt32Ty(getGlobalContext()), PhiBBSize, "iftmp");
Phi->addIncoming(ThenVal, ThenBB);
Phi->addIncoming(ElseVal, ElseBB);
return Phi;
}
int main(int argc, char *argv[]) {
FunArgs.push_back("a");
FunArgs.push_back("b");
static IRBuilder<> Builder(Context);
GlobalVariable *gVar = createGlob(Builder, "x");
Function *fooFunc = createFunc(Builder, "foo");
setFuncArgs(fooFunc, FunArgs);
BasicBlock *entry = createBB(fooFunc, "entry");
Builder.SetInsertPoint(entry);
Value *Arg1 = fooFunc->arg_begin();
Value *constant = Builder.getInt32(16);
Value *val = createArith(Builder, Arg1, constant);
Value *val2 = Builder.getInt32(100);
Value *Compare = Builder.CreateICmpULT(val, val2, "cmptmp");
Value *Condtn = Builder.CreateICmpNE(Compare, Builder.getInt32(0), "ifcond");
ValList VL;
VL.push_back(Condtn);
VL.push_back(Arg1);
BasicBlock *ThenBB = createBB(fooFunc, "then");
BasicBlock *ElseBB = createBB(fooFunc, "else");
BasicBlock *MergeBB = createBB(fooFunc, "ifcont");
BBList List;
List.push_back(ThenBB);
List.push_back(ElseBB);
List.push_back(MergeBB);
Value *v = createIfElse(Builder, List, VL);
Builder.CreateRet(v);
verifyFunction(*fooFunc);
ModuleOb->dump();
return 0;
}
I know the issue is occurring at this location. I've tried to dynamically cast both to the same type, but still not compiling.
Value *Condtn = Builder.CreateICmpNE(Compare, Builder.getInt32(0), "ifcond");
The problem is with these two lines:
Value *Compare = Builder.CreateICmpULT(val, val2, "cmptmp");
Value *Condtn = Builder.CreateICmpNE(Compare, Builder.getInt32(0), "ifcond");
The first icmp instruction evaluates to a value of type i1, and you're trying to compare that to a value of type i32.
Your best bet would be to avoid the second icmp altogether, as it's superfluous (it will evaluate to the same value as Compare). Just use Compare as your condition.
Otherwise, you'd have to make sure the types match -- in this case you can just use Builder.getInt1(false) instead of Builder.getInt32(0). More generally you might use Builder.CreateIntCast to insert trunc or zext or sext instructions as needed.