Add formatted textual IR output (#3056)

Add a textual IR format to the toolchain.

The exact details of the format are somewhat arbitrary right now, and I
expect them to change as we refine the semantics IR model, but at the
moment they're somewhat directly following the current structure of the
IR.

Semantics tests currently test both the "raw" format, which shows the
details of the representation, and the textual format, which is somewhat
higher level. We may want to revisit that decision once the textual
format is a bit more stable, and test only the textual format in most of
these tests, but for now it seems prudent to keep both sets of tests.

---------

Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
This commit is contained in:
Richard Smith
2023-08-10 19:41:39 +00:00
committed by GitHub
co-authored by Chandler Carruth
parent fc5a9541ce
commit 6cbf280a68
140 changed files with 3127 additions and 64 deletions
@@ -60,3 +60,20 @@ fn F() -> i32 {
// CHECK:STDOUT: node+10,
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
// CHECK:STDOUT:
// CHECK:STDOUT: package {
// CHECK:STDOUT: %.loc7 = fn_decl @F
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F() -> i32 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %n: i32 = var
// CHECK:STDOUT: %.loc8: i32 = int_value 0
// CHECK:STDOUT: assign %n, %.loc8
// CHECK:STDOUT: %.loc9_13.1: type = ptr_type i32
// CHECK:STDOUT: %.loc9_13.2: i32* = address_of %n
// CHECK:STDOUT: %.loc9_12: i32 = dereference %.loc9_13.2
// CHECK:STDOUT: %.loc9_11: i32* = address_of %.loc9_12
// CHECK:STDOUT: %.loc9_10: i32 = dereference %.loc9_11
// CHECK:STDOUT: return %.loc9_10
// CHECK:STDOUT: }
@@ -239,3 +239,62 @@ fn F(param: i32) {
// CHECK:STDOUT: node+45,
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
// CHECK:STDOUT:
// CHECK:STDOUT: package {
// CHECK:STDOUT: %.loc7 = fn_decl @F
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F(%param: i32) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc8_27: type = struct_type {.a: i32, .b: i32}
// CHECK:STDOUT: %s: {.a: i32, .b: i32} = var
// CHECK:STDOUT: %.loc8_37: i32 = int_value 1
// CHECK:STDOUT: %.loc8_35: i32 = stub_reference %.loc8_37
// CHECK:STDOUT: %.loc8_45: i32 = int_value 2
// CHECK:STDOUT: %.loc8_43: i32 = stub_reference %.loc8_45
// CHECK:STDOUT: %.loc8_46: {.a: i32, .b: i32} = struct_value (%.loc8_35, %.loc8_43)
// CHECK:STDOUT: assign %s, %.loc8_46
// CHECK:STDOUT: %.loc10_28: type = ptr_type {.a: i32, .b: i32}
// CHECK:STDOUT: %p: {.a: i32, .b: i32}* = var
// CHECK:STDOUT: %.loc10_32: {.a: i32, .b: i32}* = address_of %s
// CHECK:STDOUT: assign %p, %.loc10_32
// CHECK:STDOUT: %.loc11_13: type = ptr_type i32
// CHECK:STDOUT: %q: i32* = var
// CHECK:STDOUT: %.loc11_19: i32 = struct_access %s, member0
// CHECK:STDOUT: %.loc11_17: i32* = address_of %.loc11_19
// CHECK:STDOUT: assign %q, %.loc11_17
// CHECK:STDOUT: %.loc12_13: type = ptr_type i32
// CHECK:STDOUT: %r: i32* = var
// CHECK:STDOUT: %.loc12_19: i32 = struct_access %s, member1
// CHECK:STDOUT: %.loc12_17: i32* = address_of %.loc12_19
// CHECK:STDOUT: assign %r, %.loc12_17
// CHECK:STDOUT: %.loc14_11: type = stub_reference i32
// CHECK:STDOUT: %.loc14_16: type = stub_reference i32
// CHECK:STDOUT: %.loc14_19.1: type = tuple_type (type, type)
// CHECK:STDOUT: %.loc14_19.2: (type, type) = tuple_value (%.loc14_11, %.loc14_16)
// CHECK:STDOUT: %.loc14_19.3: type = tuple_type (i32, i32)
// CHECK:STDOUT: %t: (i32, i32) = var
// CHECK:STDOUT: %.loc14_24.1: i32 = int_value 1
// CHECK:STDOUT: %.loc14_24.2: i32 = stub_reference %.loc14_24.1
// CHECK:STDOUT: %.loc14_27.1: i32 = int_value 2
// CHECK:STDOUT: %.loc14_27.2: i32 = stub_reference %.loc14_27.1
// CHECK:STDOUT: %.loc14_28: (i32, i32) = tuple_value (%.loc14_24.2, %.loc14_27.2)
// CHECK:STDOUT: assign %t, %.loc14_28
// CHECK:STDOUT: %.loc15_14: type = ptr_type i32
// CHECK:STDOUT: %t0: i32* = var
// CHECK:STDOUT: %.loc15_21: i32 = int_value 0
// CHECK:STDOUT: %.loc15_22: i32 = tuple_index %t, %.loc15_21
// CHECK:STDOUT: %.loc15_18: i32* = address_of %.loc15_22
// CHECK:STDOUT: assign %t0, %.loc15_18
// CHECK:STDOUT: %.loc16_14: type = ptr_type i32
// CHECK:STDOUT: %t1: i32* = var
// CHECK:STDOUT: %.loc16_21: i32 = int_value 1
// CHECK:STDOUT: %.loc16_22: i32 = tuple_index %t, %.loc16_21
// CHECK:STDOUT: %.loc16_18: i32* = address_of %.loc16_22
// CHECK:STDOUT: assign %t1, %.loc16_18
// CHECK:STDOUT: %.loc20_22: type = ptr_type i32
// CHECK:STDOUT: %param_addr: i32* = var
// CHECK:STDOUT: %.loc20_26: i32* = address_of %param
// CHECK:STDOUT: assign %param_addr, %.loc20_26
// CHECK:STDOUT: return
// CHECK:STDOUT: }
+17
View File
@@ -65,3 +65,20 @@ fn F() -> i32 {
// CHECK:STDOUT: node+11,
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
// CHECK:STDOUT:
// CHECK:STDOUT: package {
// CHECK:STDOUT: %.loc7 = fn_decl @F
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F() -> i32 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %n: i32 = var
// CHECK:STDOUT: %.loc8: i32 = int_value 0
// CHECK:STDOUT: assign %n, %.loc8
// CHECK:STDOUT: %.loc9_13: type = ptr_type i32
// CHECK:STDOUT: %p: i32* = var
// CHECK:STDOUT: %.loc9_17: i32* = address_of %n
// CHECK:STDOUT: assign %p, %.loc9_17
// CHECK:STDOUT: %.loc11: i32 = dereference %p
// CHECK:STDOUT: return %.loc11
// CHECK:STDOUT: }
@@ -296,3 +296,93 @@ fn AddressOfTupleElementValue() {
// CHECK:STDOUT: node+59,
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
// CHECK:STDOUT:
// CHECK:STDOUT: package {
// CHECK:STDOUT: %.loc7 = fn_decl @G
// CHECK:STDOUT: %.loc9_19: type = struct_type {.a: i32}
// CHECK:STDOUT: %.loc9_1 = fn_decl @H
// CHECK:STDOUT: %.loc11 = fn_decl @AddressOfLiteral
// CHECK:STDOUT: %.loc38 = fn_decl @AddressOfOperator
// CHECK:STDOUT: %.loc53 = fn_decl @AddressOfCall
// CHECK:STDOUT: %.loc60 = fn_decl @AddressOfType
// CHECK:STDOUT: %.loc71 = fn_decl @AddressOfTupleElementValue
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @G() -> i32;
// CHECK:STDOUT:
// CHECK:STDOUT: fn @H() -> {.a: i32};
// CHECK:STDOUT:
// CHECK:STDOUT: fn @AddressOfLiteral() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc15_4: i32 = int_value 0
// CHECK:STDOUT: %.loc15_3.1: type = ptr_type i32
// CHECK:STDOUT: %.loc15_3.2: i32* = address_of %.loc15_4
// CHECK:STDOUT: %.loc19_4: bool = bool_value true
// CHECK:STDOUT: %.loc19_3.1: type = ptr_type bool
// CHECK:STDOUT: %.loc19_3.2: bool* = address_of %.loc19_4
// CHECK:STDOUT: %.loc23_4: f64 = real_value 10e-1
// CHECK:STDOUT: %.loc23_3.1: type = ptr_type f64
// CHECK:STDOUT: %.loc23_3.2: f64* = address_of %.loc23_4
// CHECK:STDOUT: %.loc27_4: String = string_value "Hello"
// CHECK:STDOUT: %.loc27_3.1: type = ptr_type String
// CHECK:STDOUT: %.loc27_3.2: String* = address_of %.loc27_4
// CHECK:STDOUT: %.loc31_5.1: i32 = int_value 1
// CHECK:STDOUT: %.loc31_5.2: i32 = stub_reference %.loc31_5.1
// CHECK:STDOUT: %.loc31_8.1: i32 = int_value 2
// CHECK:STDOUT: %.loc31_8.2: i32 = stub_reference %.loc31_8.1
// CHECK:STDOUT: %.loc31_9.1: type = tuple_type (i32, i32)
// CHECK:STDOUT: %.loc31_9.2: (i32, i32) = tuple_value (%.loc31_5.2, %.loc31_8.2)
// CHECK:STDOUT: %.loc31_3.1: type = ptr_type (i32, i32)
// CHECK:STDOUT: %.loc31_3.2: (i32, i32)* = address_of %.loc31_9.2
// CHECK:STDOUT: %.loc35_10: i32 = int_value 5
// CHECK:STDOUT: %.loc35_8: i32 = stub_reference %.loc35_10
// CHECK:STDOUT: %.loc35_11: {.a: i32} = struct_value (%.loc35_8)
// CHECK:STDOUT: %.loc35_3.1: type = ptr_type {.a: i32}
// CHECK:STDOUT: %.loc35_3.2: {.a: i32}* = address_of %.loc35_11
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @AddressOfOperator() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc42_5: i32 = int_value 1
// CHECK:STDOUT: %.loc42_9: i32 = int_value 1
// CHECK:STDOUT: %.loc42_7: i32 = add %.loc42_5, %.loc42_9
// CHECK:STDOUT: %.loc42_3: i32* = address_of %.loc42_7
// CHECK:STDOUT: %.loc46_5: {.a: i32} = call @H()
// CHECK:STDOUT: %.loc46_7: i32 = struct_access %.loc46_5, member0
// CHECK:STDOUT: %.loc46_3: i32* = address_of %.loc46_7
// CHECK:STDOUT: %.loc50_9: bool = bool_value true
// CHECK:STDOUT: %.loc50_5: bool = not %.loc50_9
// CHECK:STDOUT: %.loc50_3: bool* = address_of %.loc50_5
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @AddressOfCall() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc57_5: i32 = call @G()
// CHECK:STDOUT: %.loc57_3: i32* = address_of %.loc57_5
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @AddressOfType() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc64_3.1: type = ptr_type type
// CHECK:STDOUT: %.loc64_3.2: type* = address_of i32
// CHECK:STDOUT: %.loc68_5: type = const_type i32
// CHECK:STDOUT: %.loc68_14: type = ptr_type const i32
// CHECK:STDOUT: %.loc68_3: type* = address_of %.loc68_14
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @AddressOfTupleElementValue() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc75_6.1: i32 = int_value 1
// CHECK:STDOUT: %.loc75_6.2: i32 = stub_reference %.loc75_6.1
// CHECK:STDOUT: %.loc75_9.1: i32 = int_value 2
// CHECK:STDOUT: %.loc75_9.2: i32 = stub_reference %.loc75_9.1
// CHECK:STDOUT: %.loc75_10: (i32, i32) = tuple_value (%.loc75_6.2, %.loc75_9.2)
// CHECK:STDOUT: %.loc75_12: i32 = int_value 0
// CHECK:STDOUT: %.loc75_13: i32 = tuple_index %.loc75_10, %.loc75_12
// CHECK:STDOUT: %.loc75_3: i32* = address_of %.loc75_13
// CHECK:STDOUT: return
// CHECK:STDOUT: }
@@ -77,3 +77,19 @@ fn Deref(n: i32) {
// CHECK:STDOUT: node+10,
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
// CHECK:STDOUT:
// CHECK:STDOUT: package {
// CHECK:STDOUT: %.loc7 = fn_decl @Deref
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Deref(%n: i32) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc11: <error> = dereference %n
// CHECK:STDOUT: %.loc15_5.1: type = tuple_type ()
// CHECK:STDOUT: %.loc15_5.2: () = tuple_value ()
// CHECK:STDOUT: %.loc15_3: <error> = dereference %.loc15_5.2
// CHECK:STDOUT: %.loc19_5.1: type = struct_type {}
// CHECK:STDOUT: %.loc19_5.2: {} = struct_value ()
// CHECK:STDOUT: %.loc19_3: <error> = dereference %.loc19_5.2
// CHECK:STDOUT: return
// CHECK:STDOUT: }
@@ -40,3 +40,8 @@ var p: *i32;
// CHECK:STDOUT: node+2,
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
// CHECK:STDOUT:
// CHECK:STDOUT: package {
// CHECK:STDOUT: %.loc13: <error> = dereference i32
// CHECK:STDOUT: %p: <error> = var
// CHECK:STDOUT: }
@@ -69,3 +69,15 @@ fn ConstMismatch(p: const {}*) -> const ({}*) {
// CHECK:STDOUT: node+10,
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
// CHECK:STDOUT:
// CHECK:STDOUT: package {
// CHECK:STDOUT: %.loc7_43: {} = struct_value ()
// CHECK:STDOUT: %.loc7_44: type = ptr_type {}
// CHECK:STDOUT: %.loc7_35: type = const_type {}*
// CHECK:STDOUT: %.loc7_1 = fn_decl @ConstMismatch
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @ConstMismatch(%p: const {}*) -> const ({}*) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: return <error>
// CHECK:STDOUT: }
@@ -70,3 +70,15 @@ fn F(p: const (const (const i32*)*)) -> const i32 {
// CHECK:STDOUT: node+11,
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
// CHECK:STDOUT:
// CHECK:STDOUT: package {
// CHECK:STDOUT: %.loc8_41: type = const_type i32
// CHECK:STDOUT: %.loc8_1 = fn_decl @F
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F(%p: const (const (const i32*)*)) -> const i32 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc9_11: const (const i32*) = dereference %p
// CHECK:STDOUT: %.loc9_10: const i32 = dereference %.loc9_11
// CHECK:STDOUT: return %.loc9_10
// CHECK:STDOUT: }
+18
View File
@@ -84,3 +84,21 @@ fn ConstPtr(p: const i32*) -> (const i32)* {
// CHECK:STDOUT: node+13,
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
// CHECK:STDOUT:
// CHECK:STDOUT: package {
// CHECK:STDOUT: %.loc7_23: type = ptr_type i32
// CHECK:STDOUT: %.loc7_1 = fn_decl @Ptr
// CHECK:STDOUT: %.loc11_32: type = const_type i32
// CHECK:STDOUT: %.loc11_42: type = ptr_type const i32
// CHECK:STDOUT: %.loc11_1 = fn_decl @ConstPtr
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Ptr(%p: i32*) -> i32* {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: return %p
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @ConstPtr(%p: const i32*) -> const i32* {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: return %p
// CHECK:STDOUT: }