llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
29.19k stars 12.04k forks source link

[GlobalISel] Unable to translate callbr to asm goto label #110541

Open agostonrobert opened 1 month ago

agostonrobert commented 1 month ago

Reproducer: https://godbolt.org/z/9joYWTbW4

The following C code:

int foo(int count) {
  asm goto ("b %l[stop]" :::: stop);
  return count;
stop:
  return 0;
}

compiled for any global isel target (after adapting the jump instruction), produces the error:

fatal error: error in backend: unable to translate instruction: callbr (in function: foo)

Dumping the passes shows the input instruction:

  callbr void asm sideeffect "b ${0:l}", "!i"() #1
          to label %3 [label %2], !dbg !20, !srcloc !21

Works fine with SelectionDAG (or GCC).

tschuett commented 1 month ago

I got a different issue:

; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
; RUN: llc -O0 -mtriple=aarch64-linux-gnu -global-isel -stop-after=irtranslator %s -o - | FileCheck %s
; *** IR Dump After Annotation2MetadataPass on [module] ***
; ModuleID = '<source>'
source_filename = "<source>"
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32"
target triple = "aarch64-unknown-linux-gnu"

; Function Attrs: mustprogress nounwind uwtable
define dso_local noundef i32 @_Z3fooi(i32 noundef %0) #0 !dbg !10 {
  ; CHECK-LABEL: name: _Z3fooi
  ; CHECK: bb.0:
  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
  ; CHECK-NEXT:   liveins: $w0
  ; CHECK-NEXT: {{  $}}
  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $w0
  ; CHECK-NEXT: {{  $}}
  ; CHECK-NEXT: bb.1 (%ir-block.1):
  ; CHECK-NEXT:   successors:
  ; CHECK-NEXT: {{  $}}
  ; CHECK-NEXT:   [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0
  ; CHECK-NEXT:   [[FRAME_INDEX1:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.1
  ; CHECK-NEXT:   G_STORE [[COPY]](s32), [[FRAME_INDEX1]](p0) :: (store (s32) into %ir.3, !tbaa !18)
  ; CHECK-NEXT: {{  $}}
  ; CHECK-NEXT: bb.2 (%ir-block.4):
  ; CHECK-NEXT:   successors:
  ; CHECK-NEXT: {{  $}}
  ; CHECK-NEXT: bb.3 (%ir-block.6):
  ; CHECK-NEXT:   successors:
  ; CHECK-NEXT: {{  $}}
  ; CHECK-NEXT: bb.4 (%ir-block.7):
  %2 = alloca i32, align 4
  %3 = alloca i32, align 4
  store i32 %0, ptr %3, align 4, !tbaa !18
    #dbg_declare(ptr %3, !16, !DIExpression(), !22)
  callbr void asm sideeffect "b ${0:l}", "!i"() #1
          to label %4 [label %6], !dbg !23, !srcloc !24

4:                                                ; preds = %1
  %5 = load i32, ptr %3, align 4, !dbg !25, !tbaa !18
  store i32 %5, ptr %2, align 4, !dbg !26
  br label %7, !dbg !26

6:                                                ; preds = %1
    #dbg_label(!17, !27)
  store i32 0, ptr %2, align 4, !dbg !28
  br label %7, !dbg !28

7:                                                ; preds = %6, %4
  %8 = load i32, ptr %2, align 4, !dbg !29
  ret i32 %8, !dbg !29
}

attributes #0 = { mustprogress nounwind uwtable "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+fp-armv8,+neon,+outline-atomics,+v8a,-fmv" }
attributes #1 = { nounwind }

!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
!llvm.ident = !{!9}

!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 20.0.0git (https://github.com/llvm/llvm-project.git a5cd5d351ddb164d7bb5e6c5e20b2b6519d793f1)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
!1 = !DIFile(filename: "<source>", directory: "/app")
!2 = !{i32 7, !"Dwarf Version", i32 4}
!3 = !{i32 2, !"Debug Info Version", i32 3}
!4 = !{i32 1, !"wchar_size", i32 4}
!5 = !{i32 8, !"PIC Level", i32 2}
!6 = !{i32 7, !"PIE Level", i32 2}
!7 = !{i32 7, !"uwtable", i32 2}
!8 = !{i32 7, !"frame-pointer", i32 1}
!9 = !{!"clang version 20.0.0git (https://github.com/llvm/llvm-project.git a5cd5d351ddb164d7bb5e6c5e20b2b6519d793f1)"}
!10 = distinct !DISubprogram(name: "foo", linkageName: "_Z3fooi", scope: !11, file: !11, line: 1, type: !12, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !15)
!11 = !DIFile(filename: "example.cpp", directory: "/app")
!12 = !DISubroutineType(types: !13)
!13 = !{!14, !14}
!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!15 = !{!16, !17}
!16 = !DILocalVariable(name: "count", arg: 1, scope: !10, file: !11, line: 1, type: !14)
!17 = !DILabel(scope: !10, name: "stop", file: !11, line: 4)
!18 = !{!19, !19, i64 0}
!19 = !{!"int", !20, i64 0}
!20 = !{!"omnipotent char", !21, i64 0}
!21 = !{!"Simple C++ TBAA"}
!22 = !DILocation(line: 1, column: 13, scope: !10)
!23 = !DILocation(line: 2, column: 3, scope: !10)
!24 = !{i64 35}
!25 = !DILocation(line: 3, column: 10, scope: !10)
!26 = !DILocation(line: 3, column: 3, scope: !10)
!27 = !DILocation(line: 4, column: 1, scope: !10)
!28 = !DILocation(line: 5, column: 3, scope: !10)
!29 = !DILocation(line: 6, column: 1, scope: !10)

Note that in the CHECK-NEXT lines is no call expression. callbr was probably not imported to GlobalISel.

tschuett commented 1 month ago

I got the same error: fatal error: error in backend: unable to translate instruction: callbr (in function: _Z3fooi)

But: I used a fresh Clang and we compiled for x86. The AArch64 GlobalISel is much more complete than the x86.

tschuett commented 1 month ago

The IRTranslator of GlobalISel does not support callbr, independent of the backend/architecture: https://github.com/llvm/llvm-project/blob/47e6d1816251e90b3d589710c5203a92c6015a7c/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp#L2985