0

I am building a lifter that translates armv7m assembly instructions into llvm IR. A sample of my C++ code is:

IRBuilder<> builder(TheContext); //line 0

llvm::ConstantInt* I_0 = llvm::ConstantInt::get(TheContext, llvm::APInt(/nbits/32, 0, true)); //line 1

V = builder.CreateAlloca(Type::getInt32Ty(TheContext), nullptr, "V"); //line 2

Value* s3 = builder.CreateStore(I_0, V, /isVolatile=/false); //line 3

Value* loaded_V = builder.CreateLoad(V); //line 4

Value* result_V = builder.CreateICmpEQ(I_0, loaded_V); //line 5

result_V->print(errs()); //line 6

The result I get is:

%22 = icmp eq i32 0, %18

The result I want is:

i1 true

So my question is, even though I stored an Immediate value of 0 at the memory location pointed to by the ptr V in line 3. When I load this value from memory using memory load from ptr V in line 4 and then compare it to an immediate value of 0 in the icmpEq in line 5, why dont I get a true result in line 6 but instead it seems that the loaded_V doesnt evaluate to an immediate value of 0, its just represented by the variable %18.

1- How can I get the value stored inside the llvm variable %18 ?.

2- Is there a way to get the data stored in the memory address pointed to by the ptr V directly without having to load.

As you can see in another sample of my code where I am trying to translate the assembly instruction add DST, SRC1, SRC2 to an equivalent llvm IR:

            llvm::Value* SRC1 = builder.CreateAlloca(Type::getInt32Ty(TheContext), nullptr);
        
            llvm::Value* SRC2 = builder.CreateAlloca(Type::getInt32Ty(TheContext), nullptr);
            
            llvm::Value* s = builder.CreateStore(register1_val, SRC1,  /*isVolatile=*/false);
            
            llvm::Value* s2 = builder.CreateStore(register2_val, SRC2,  /*isVolatile=*/false);
            
            llvm::Value* LHS = builder.CreateLoad(SRC1, register1);
            
            llvm::Value* RHS = builder.CreateLoad(SRC2, register2);
            
            llvm::Value* add_ll = builder.CreateAdd(LHS, RHS, output_register);

            llvm::Value* DST = builder.CreateAlloca(Type::getInt32Ty(TheContext), nullptr);

            llvm::Value* s3 = builder.CreateStore(add_ll, DST,  /*isVolatile=*/false);

I represent an operand as a ptr to a memory address by using an alloca instruction and then loading from that memory address when using the operand in an llvm instruction creation.

3- Is there perhaps a better way of representing operands (virtual registers?!, instead of ptrs to memory).

hany erfan
  • 95
  • 7
  • Did you run any optimisation passes? If so which ones. – Mike Vine May 26 '21 at 12:06
  • IIRC you want `https://www.llvm.org/docs/Passes.html#mem2reg-promote-memory-to-register` – Mike Vine May 26 '21 at 12:09
  • @MikeVine no I didn't run any optimization passes. I'm just writing c++ functions translating each assembly instruction into its equivalent llvm instructions. I wanted to make checks like comparing values stored at specific memory locations with immediate values using icmpeq(i_0, loaded_memory). Isn't storing an immediate value into a specific – hany erfan May 26 '21 at 12:41
  • memory location enough for me to get an evaluation of the icmpeq instruction ..why does imcpeq(i_0,i_0)->print(errs()) returns true while (i_0,loaded_memory)->print(errs()) doesn't evaluate to true when I have stored i_0 into that memory location. I just get an unevaluated instruction (%22 = icmpeq i32 0, %18), so my question was how can I make sure that the value of the variable %18 here is in fact the I_0 that I have stored in it. – hany erfan May 26 '21 at 12:42
  • 1
    I dont understand. It _will_ return true once optimised or executed. But you are giving it a complex set of operations and assuming that it can "see through" all of the things you do to get a final result. That only can happen if you run optimisation passes which can look at all the complex operations and collapse them. You cannot assume that building IR will immediately result in an optimised result. – Mike Vine May 26 '21 at 12:47
  • Presumably, the `icmpeq(0, 0)` is simple enough that it immediately collapses into `true` without needing any optimisation pass at all. More likely its `icmpeq(constant_v, constant_v)` where _constant_v_ is the same `llvm::Constant*` allows this to happen. – Mike Vine May 26 '21 at 12:48
  • 1
    Also if you want to see what `%18` is you should presumably also print `loaded_V` as that is very likely to define %18. – Mike Vine May 26 '21 at 12:52
  • Im new to llvm still so forgive my basic question....should I write an optimisation pass ...indeed now I have a module with llvm functions and llvm basic blocks and ll instructions..this module is merely an object inside my c++ written lifter code (which is massive)..any hints how I can apply an optimisation pass on my module ? ....can the optimization pass be written inside my c++ lifter code as part of a function for example to which I pass my module?..then apply the optimisation pass by calling this function. – hany erfan May 26 '21 at 16:37

0 Answers0