Problems in the transformation from LLVM IR code to x86-64 executable file

Hello, I am a llvm beginner. I recently try to run my own toy-c-compiler project but the executable file has unexpected results.
Here are my test codes, LLVM IR codes and assembly codes.

TEST CODE
extern void printi(int n); 
extern void scanfi(int* intaddr);

int main(){
    int a = 1;
    int b = 2; 
    if(a<b)
    {
        a=a+1;
        printi(a);
    }
    else{
        b=b+1;
    }
    return 0; 
}

LLVM IR CODE
define i32 @main() {
entry:
  %a = alloca i32, align 4, addrspace(4)
  store i32 1, ptr addrspace(4) %a, align 4
  %b = alloca i32, align 4, addrspace(4)
  store i32 2, ptr addrspace(4) %b, align 4
  %a1 = load i32, ptr addrspace(4) %a, align 4
  %b2 = load i32, ptr addrspace(4) %b, align 4
  %lttmp = icmp slt i32 %a1, %b2
  br i1 %lttmp, label %then, label %else

then:                                             ; preds = %entry
  %a3 = load i32, ptr addrspace(4) %a, align 4
  store i32 %a3, ptr addrspace(4) %a, align 4
  %addtmp = add i32 %a3, 1
  %a4 = load i32, ptr addrspace(4) %a, align 4
  %calltmp = call void @printi(i32 %a4)
  br label %ifcont

else:                                             ; preds = %entry
  %b5 = load i32, ptr addrspace(4) %b, align 4
  store i32 %b5, ptr addrspace(4) %b, align 4
  %addtmp6 = add i32 %b5, 1
  br label %ifcont

ifcont:                                           ; preds = %else, %then
  ret i32 0
}

ASSEMBLY CODE

And here are my codes to generate executable files.

llvm::GenericValue CodeContext::runCode() {
    llvm::GenericValue err;
    err.IntVal= llvm::APInt(32, 1);
    std::string outputFilename = "output.o";


    llvm::InitializeAllTargetInfos();
    llvm::InitializeAllTargets();
    llvm::InitializeAllTargetMCs();
    llvm::InitializeAllAsmParsers();
    llvm::InitializeAllAsmPrinters();


    auto TargetTriple = llvm::Triple::normalize(LLVMGetDefaultTargetTriple());
    std::string error;
    auto target = llvm::TargetRegistry::lookupTarget(TargetTriple, error);
    if (!target) {
        llvm::errs() << error;
        std::cout << error<< std::endl;
        return err;
    }

    auto cpu = "generic";
    auto features = "";
    llvm::TargetOptions opt;
    auto rm = llvm::Optional<llvm::Reloc::Model>();
    auto targetMachine = target->createTargetMachine(TargetTriple, cpu, features, opt, rm);

    llvm::legacy::PassManager pass;
    auto fileType = llvm::CGFT_ObjectFile;
    std::string filename(outputFilename);
    std::error_code EC;
    llvm::raw_fd_ostream dest(filename, EC, llvm::sys::fs::OF_None);

    if (targetMachine->addPassesToEmitFile(pass, dest, nullptr, fileType)) {
        llvm::errs() << "TargetMachine can't emit a file of this type";
        std::cout << "TargetMachine can't emit a file of this type"<< std::endl;
        return err;
    }

    pass.run(*_module);

    dest.flush();
    llvm::outs() << "Object file written to " << outputFilename << "\n";


    llvm::ExecutionEngine* EE = llvm::EngineBuilder(std::unique_ptr<llvm::Module>(_module)).create();
    EE->finalizeObject();
    std::vector<llvm::GenericValue> noargs;
    llvm::GenericValue v = EE->runFunction(_module->getFunction("main"), noargs);

    std::cout << "Running\n";
    
    return v;
}

And my executable file runs like this.

Object file written to output.o
1
Running
gcc -o program output.o cfuncs.o
./program
1

It seems that the executable file does not do the “a=a+1” step. I don’t know where the problem is and I want to find a solution to debug my codes. Thank you in advance!

Why do you need address spaces?
addtmp does not end in the print expression!

ptr addrspace(4) %a means %a is a pointer of type i32*.
%addtmp refers to the add instruction, it has no relationship with printi function. Sorry, I don’t fully understand what you mean. :sob: :sob:

%addtmp is the result of an addition. Then you load %a from memory to %a4 and print %a4. But you leave %addtmp unused.

addrspace is usually for GPUs. For CPUs you don’t need addrspace.

It doesn’t mean that. Pointers no longer say what type they are in LLVM. addrspace is used to say that a pointer lives in a completely different region of memory that you have to use different instructions to access.

LLVM uses opaque pointers.

ptr is a pointer. addrspace(4) does not say anything about the type.

%a3 = load i32, ptr %a, align 4

In the load instruction, you specify the type.

oh yeah! Thank you for finding the problem!! :nerd_face: :nerd_face:I will check my codes for those parts! Many thanks! :smiling_face_with_three_hearts: :smiling_face_with_three_hearts:

Thank you for pointing out my wrong interpretion! :rose: :rose: I will check for ‘assignments’ part to find out the problem! :nerd_face: :face_with_monocle:

You can also have a look at:
https://mapping-high-level-constructs-to-llvm-ir.readthedocs.io/en/latest/

Thank you very much!!! :smiling_face_with_three_hearts: :smiling_face_with_three_hearts: How kind you are!! :nerd_face: