How to fix "Function type not legal for constraints!" when inserting inline assembly using llvm pass?

Hi, I’m new to llvm and studying to make a llvm pass to insert inline assembly on the head of each basic block. (llvm github release 12.x branch)


But when I implement, build and run opt with the pass, I could only take the fail message from getting InlineAsm* type variable.

llvm::InlineAsm::InlineAsm(llvm::FunctionType*, const string&, const string&, bool, bool, llvm::InlineAsm::AsmDialect): Assertion 'Verify(getFunctionType(), constraints) && "Function type not legal for constraints!"' failed.


This is the part of my test pass code. I think that I should fix the FunctionType but I can’t find the way.
Is there any good way to fix?

PreservedAnalyses MyPass::run(Function &F, FunctionAnalysisManager &AM) { 
   StringRef asmString = "         mov $0, $1;         add $0, $1         ";
   StringRef constraints = "=r,r,~{dirflag},~{fpsr},~{flags}";
   if(F.hasName()){
       Type *Ty = Type::getInt32Ty(F.getContext());
       FunctionType *Fty = FunctionType::get(Ty, false);
       InlineAsm *IA = InlineAsm::get(Fty, asmString, constraints, true ,false, InlineAsm::AD_ATT);
   }
   return PreservedAnalyses::all();
}

More exactly, for example, I want to convert from this
#include <stdio.h>

void foo(void);

int main(void){
    return 0;
}

void foo(void){

    int a = 0;
    if (a == 0){
        printf("a = 0\n");
    }
    else{
        printf("a != 0\n");
    }

    printf("foo world\n");
}


To this
#include <stdio.h>

void foo(void);

int main(void){

    // inline asm block start
    int src = 2;
    int dst;

    __asm__ __volatile__(" \
        mov %0, %1; \
        add %0, %1 \
        " \
        : "=r" (dst) \
        : "r" (src)
    );

    printf("%d\n", dst);
    // end block

    return 0;
}

void foo(void){
    // wanna same block here
    int a = 0;
    if (a == 0){
        // wanna same block here
        printf("a = 0\n");
    }
    else{
        // wanna same block here
        printf("a != 0\n");
    }

    // wanna same block here
    printf("foo world\n");
}


Using clang, I compiled the source file above to IR file, and could find inlineasm IRs like under code (The line including %1)
; ModuleID = 'a.c'
source_filename = "a.c"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
@.str.1 = private unnamed_addr constant [7 x i8] c"a = 0\0A\00", align 1
@.str.2 = private unnamed_addr constant [8 x i8] c"a != 0\0A\00", align 1
@.str.3 = private unnamed_addr constant [11 x i8] c"foo world\0A\00", align 1

; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main() #0 {
entry:
  %retval = alloca i32, align 4
  %src = alloca i32, align 4
  %dst = alloca i32, align 4
  store i32 0, i32* %retval, align 4
  store i32 2, i32* %src, align 4
  %0 = load i32, i32* %src, align 4
  %1 = call i32 asm sideeffect "         mov $0, $1;         add $0, $1         ", "=r,r,~{dirflag},~{fpsr},~{flags}"(i32 %0) #2, !srcloc !2
  store i32 %1, i32* %dst, align 4
  %2 = load i32, i32* %dst, align 4
  %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), i32 %2)
  ret i32 0
}

declare dso_local i32 @printf(i8*, ...) #1

; Function Attrs: noinline nounwind optnone uwtable
define dso_local void @foo() #0 {
entry:
  %a = alloca i32, align 4
  store i32 0, i32* %a, align 4
  %0 = load i32, i32* %a, align 4
  %cmp = icmp eq i32 %0, 0
  br i1 %cmp, label %if.then, label %if.else

if.then:                                          ; preds = %entry
  %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.1, i64 0, i64 0))
  br label %if.end

if.else:                                          ; preds = %entry
  %call1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.2, i64 0, i64 0))
  br label %if.end

if.end:                                           ; preds = %if.else, %if.then
  %call2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.3, i64 0, i64 0))
  ret void
}

attributes #0 = { noinline nounwind optnone uwtable "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #2 = { nounwind }

!llvm.module.flags = !{!0}
!llvm.ident = !{!1}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{!"clang version 12.0.0 (my url)"}
!2 = !{i32 111}

So, I made the test pass code to make %1 = call i32 asm sideeffect " mov $0, $1; add $0, $1 ", "=r,r,~{dirflag},~{fpsr},~{flags}"(i32 %0) #2, !srcloc !2