[asm] Allow block address operands in `asm inteldialect`
authorNico Weber <thakis@chromium.org>
Thu, 18 Nov 2021 16:38:52 +0000 (11:38 -0500)
committerNico Weber <thakis@chromium.org>
Fri, 19 Nov 2021 14:27:30 +0000 (09:27 -0500)
This makes the following program build with -masm=intel:

    int foo(int count) {
      asm goto ("dec %0; jb %l[stop]" : "+r" (count) : : : stop);
      return count;
    stop:
      return 0;
    }

It's also is another step towards merging EmitGCCInlineAsmStr() and
EmitMSInlineAsmStr().

Differential Revision: https://reviews.llvm.org/D114167

llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp
llvm/test/CodeGen/X86/callbr-asm.ll

index b12437b..ef1abc4 100644 (file)
@@ -273,7 +273,15 @@ static void EmitMSInlineAsmStr(const char *AsmStr, const MachineInstr *MI,
           unsigned OpFlags = MI->getOperand(OpNo).getImm();
           ++OpNo; // Skip over the ID number.
 
-          if (InlineAsm::isMemKind(OpFlags)) {
+          // FIXME: Shouldn't arch-independent output template handling go into
+          // PrintAsmOperand?
+          // Labels are target independent.
+          if (MI->getOperand(OpNo).isBlockAddress()) {
+            const BlockAddress *BA = MI->getOperand(OpNo).getBlockAddress();
+            MCSymbol *Sym = AP->GetBlockAddressSymbol(BA);
+            Sym->print(OS, AP->MAI);
+            MMI->getContext().registerInlineAsmLabel(Sym);
+          } else if (InlineAsm::isMemKind(OpFlags)) {
             Error = AP->PrintAsmMemoryOperand(
                 MI, OpNo, Modifier[0] ? Modifier : nullptr, OS);
           } else {
index 1df69b6..c935928 100644 (file)
@@ -32,6 +32,36 @@ fail:
   ret i32 1
 }
 
+; Test 1b - Like test 1 but using `asm inteldialect`.
+define i32 @test1b(i32 %a) {
+; CHECK-LABEL: test1b:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; CHECK-NEXT:    addl $4, %eax
+; CHECK-NEXT:    #APP
+; CHECK-EMPTY:
+; CHECK-NEXT:    xorl %eax, %eax
+; CHECK-NEXT:    jmp .Ltmp1
+; CHECK-EMPTY:
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:  # %bb.1: # %normal
+; CHECK-NEXT:    xorl %eax, %eax
+; CHECK-NEXT:    retl
+; CHECK-NEXT:  .Ltmp1: # Block address taken
+; CHECK-NEXT:  .LBB1_2: # %fail
+; CHECK-NEXT:    movl $1, %eax
+; CHECK-NEXT:    retl
+entry:
+  %0 = add i32 %a, 4
+  callbr void asm inteldialect "xor $0, $0; jmp ${1:l}", "r,X,~{dirflag},~{fpsr},~{flags}"(i32 %0, i8* blockaddress(@test1b, %fail)) to label %normal [label %fail]
+
+normal:
+  ret i32 0
+
+fail:
+  ret i32 1
+}
+
 ; Test 2 - callbr terminates an unreachable block, function gets simplified
 ; to a trivial zero return.
 define i32 @test2(i32 %a) {
@@ -59,43 +89,43 @@ fail:
 define i32 @test3(i32 %a) {
 ; CHECK-LABEL: test3:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:  .Ltmp1: # Block address taken
-; CHECK-NEXT:  .LBB2_1: # %label01
-; CHECK-NEXT:    # =>This Loop Header: Depth=1
-; CHECK-NEXT:    # Child Loop BB2_2 Depth 2
-; CHECK-NEXT:    # Child Loop BB2_3 Depth 3
-; CHECK-NEXT:    # Child Loop BB2_4 Depth 4
 ; CHECK-NEXT:  .Ltmp2: # Block address taken
-; CHECK-NEXT:  .LBB2_2: # %label02
-; CHECK-NEXT:    # Parent Loop BB2_1 Depth=1
+; CHECK-NEXT:  .LBB3_1: # %label01
+; CHECK-NEXT:    # =>This Loop Header: Depth=1
+; CHECK-NEXT:    # Child Loop BB3_2 Depth 2
+; CHECK-NEXT:    # Child Loop BB3_3 Depth 3
+; CHECK-NEXT:    # Child Loop BB3_4 Depth 4
+; CHECK-NEXT:  .Ltmp3: # Block address taken
+; CHECK-NEXT:  .LBB3_2: # %label02
+; CHECK-NEXT:    # Parent Loop BB3_1 Depth=1
 ; CHECK-NEXT:    # => This Loop Header: Depth=2
-; CHECK-NEXT:    # Child Loop BB2_3 Depth 3
-; CHECK-NEXT:    # Child Loop BB2_4 Depth 4
+; CHECK-NEXT:    # Child Loop BB3_3 Depth 3
+; CHECK-NEXT:    # Child Loop BB3_4 Depth 4
 ; CHECK-NEXT:    addl $4, {{[0-9]+}}(%esp)
-; CHECK-NEXT:  .Ltmp3: # Block address taken
-; CHECK-NEXT:  .LBB2_3: # %label03
-; CHECK-NEXT:    # Parent Loop BB2_1 Depth=1
-; CHECK-NEXT:    # Parent Loop BB2_2 Depth=2
-; CHECK-NEXT:    # => This Loop Header: Depth=3
-; CHECK-NEXT:    # Child Loop BB2_4 Depth 4
 ; CHECK-NEXT:  .Ltmp4: # Block address taken
-; CHECK-NEXT:  .LBB2_4: # %label04
-; CHECK-NEXT:    # Parent Loop BB2_1 Depth=1
-; CHECK-NEXT:    # Parent Loop BB2_2 Depth=2
-; CHECK-NEXT:    # Parent Loop BB2_3 Depth=3
+; CHECK-NEXT:  .LBB3_3: # %label03
+; CHECK-NEXT:    # Parent Loop BB3_1 Depth=1
+; CHECK-NEXT:    # Parent Loop BB3_2 Depth=2
+; CHECK-NEXT:    # => This Loop Header: Depth=3
+; CHECK-NEXT:    # Child Loop BB3_4 Depth 4
+; CHECK-NEXT:  .Ltmp5: # Block address taken
+; CHECK-NEXT:  .LBB3_4: # %label04
+; CHECK-NEXT:    # Parent Loop BB3_1 Depth=1
+; CHECK-NEXT:    # Parent Loop BB3_2 Depth=2
+; CHECK-NEXT:    # Parent Loop BB3_3 Depth=3
 ; CHECK-NEXT:    # => This Inner Loop Header: Depth=4
 ; CHECK-NEXT:    #APP
-; CHECK-NEXT:    jmp .Ltmp1
 ; CHECK-NEXT:    jmp .Ltmp2
 ; CHECK-NEXT:    jmp .Ltmp3
+; CHECK-NEXT:    jmp .Ltmp4
 ; CHECK-NEXT:    #NO_APP
 ; CHECK-NEXT:  # %bb.5: # %normal0
-; CHECK-NEXT:    # in Loop: Header=BB2_4 Depth=4
+; CHECK-NEXT:    # in Loop: Header=BB3_4 Depth=4
 ; CHECK-NEXT:    #APP
-; CHECK-NEXT:    jmp .Ltmp1
 ; CHECK-NEXT:    jmp .Ltmp2
 ; CHECK-NEXT:    jmp .Ltmp3
 ; CHECK-NEXT:    jmp .Ltmp4
+; CHECK-NEXT:    jmp .Ltmp5
 ; CHECK-NEXT:    #NO_APP
 ; CHECK-NEXT:  # %bb.6: # %normal1
 ; CHECK-NEXT:    movl {{[0-9]+}}(%esp), %eax
@@ -135,14 +165,14 @@ define void @test4() {
 ; CHECK-LABEL: test4:
 ; CHECK:       # %bb.0: # %entry
 ; CHECK-NEXT:    #APP
-; CHECK-NEXT:    ja .Ltmp5
+; CHECK-NEXT:    ja .Ltmp6
 ; CHECK-NEXT:    #NO_APP
 ; CHECK-NEXT:  # %bb.1: # %asm.fallthrough
 ; CHECK-NEXT:    #APP
-; CHECK-NEXT:    ja .Ltmp5
+; CHECK-NEXT:    ja .Ltmp6
 ; CHECK-NEXT:    #NO_APP
-; CHECK-NEXT:  .Ltmp5: # Block address taken
-; CHECK-NEXT:  .LBB3_3: # %quux
+; CHECK-NEXT:  .Ltmp6: # Block address taken
+; CHECK-NEXT:  .LBB4_3: # %quux
 ; CHECK-NEXT:    retl
 entry:
   callbr void asm sideeffect "ja $0", "X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@test4, %quux))