Model function calls as initializing expressions (#3089)

Start treating function calls as initializing expressions instead of as
value expressions.

This required adding support for expression categories. Value bindings
and temporary materialization conversions are created where necessary to
transition between expression categories. For a function call with a
return slot, we speculatively create a materialized temporary before the
call and either commit to it or replace it with something else later,
once we see how the function call expression is actually used.

This change follows the direction suggested in #3133 for initializing
expressions: depending on the return type of a function, the return
value will either be initialized in-place or returned directly. This is
visible in the semantics IR, which is a little unfortunate but is
probably necessary as this is part of the semantics of the program.

---------

Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
This commit is contained in:
Richard Smith
2023-08-24 19:35:07 +00:00
committed by GitHub
co-authored by Chandler Carruth
parent f790a27ace
commit 1013d1773c
101 changed files with 1802 additions and 777 deletions
@@ -15,7 +15,7 @@ fn Main() {
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str0, param_refs: block2, return_type: type0, body: [block4]},
// CHECK:STDOUT: {name: str2, param_refs: block0, body: [block5]},
// CHECK:STDOUT: {name: str3, param_refs: block0, body: [block5]},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: ]
@@ -24,6 +24,7 @@ fn Main() {
// CHECK:STDOUT: strings: [
// CHECK:STDOUT: Echo,
// CHECK:STDOUT: a,
// CHECK:STDOUT: return,
// CHECK:STDOUT: Main,
// CHECK:STDOUT: ]
// CHECK:STDOUT: types: [
@@ -36,11 +37,12 @@ fn Main() {
// CHECK:STDOUT: {kind: StructValue, arg0: block0, type: type0},
// CHECK:STDOUT: {kind: Parameter, arg0: str1, type: type0},
// CHECK:STDOUT: {kind: StructValue, arg0: block0, type: type0},
// CHECK:STDOUT: {kind: VarStorage, arg0: str2, type: type0},
// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function0},
// CHECK:STDOUT: {kind: ReturnExpression, arg0: node+2},
// CHECK:STDOUT: {kind: Return},
// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function1},
// CHECK:STDOUT: {kind: StructValue, arg0: block0, type: type0},
// CHECK:STDOUT: {kind: StubReference, arg0: node+7, type: type0},
// CHECK:STDOUT: {kind: StubReference, arg0: node+8, type: type0},
// CHECK:STDOUT: {kind: Call, arg0: block6, arg1: function0, type: type0},
// CHECK:STDOUT: {kind: Return},
// CHECK:STDOUT: ]
@@ -52,25 +54,26 @@ fn Main() {
// CHECK:STDOUT: node+1,
// CHECK:STDOUT: node+2,
// CHECK:STDOUT: node+3,
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+2,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: node+5,
// CHECK:STDOUT: node+7,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+6,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+5,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+7,
// CHECK:STDOUT: node+8,
// CHECK:STDOUT: node+9,
// CHECK:STDOUT: node+10,
// CHECK:STDOUT: node+11,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+8,
// CHECK:STDOUT: node+9,
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
// CHECK:STDOUT:
@@ -81,7 +84,7 @@ fn Main() {
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Echo(%a: {}) -> {} {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: return %a
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Main() {
+13 -10
View File
@@ -15,7 +15,7 @@ fn Main() {
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str0, param_refs: block2, return_type: type0, body: [block4]},
// CHECK:STDOUT: {name: str2, param_refs: block0, body: [block5]},
// CHECK:STDOUT: {name: str3, param_refs: block0, body: [block5]},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: ]
@@ -24,6 +24,7 @@ fn Main() {
// CHECK:STDOUT: strings: [
// CHECK:STDOUT: Echo,
// CHECK:STDOUT: a,
// CHECK:STDOUT: return,
// CHECK:STDOUT: Main,
// CHECK:STDOUT: ]
// CHECK:STDOUT: types: [
@@ -38,11 +39,12 @@ fn Main() {
// CHECK:STDOUT: {kind: TupleValue, arg0: block0, type: type0},
// CHECK:STDOUT: {kind: Parameter, arg0: str1, type: type0},
// CHECK:STDOUT: {kind: TupleValue, arg0: block0, type: type0},
// CHECK:STDOUT: {kind: VarStorage, arg0: str2, type: type0},
// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function0},
// CHECK:STDOUT: {kind: ReturnExpression, arg0: node+2},
// CHECK:STDOUT: {kind: Return},
// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function1},
// CHECK:STDOUT: {kind: TupleValue, arg0: block0, type: type0},
// CHECK:STDOUT: {kind: StubReference, arg0: node+7, type: type0},
// CHECK:STDOUT: {kind: StubReference, arg0: node+8, type: type0},
// CHECK:STDOUT: {kind: Call, arg0: block6, arg1: function0, type: type0},
// CHECK:STDOUT: {kind: Return},
// CHECK:STDOUT: ]
@@ -54,25 +56,26 @@ fn Main() {
// CHECK:STDOUT: node+1,
// CHECK:STDOUT: node+2,
// CHECK:STDOUT: node+3,
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+2,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: node+5,
// CHECK:STDOUT: node+7,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+6,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+5,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+7,
// CHECK:STDOUT: node+8,
// CHECK:STDOUT: node+9,
// CHECK:STDOUT: node+10,
// CHECK:STDOUT: node+11,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+8,
// CHECK:STDOUT: node+9,
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
// CHECK:STDOUT:
@@ -83,7 +86,7 @@ fn Main() {
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Echo(%a: ()) -> () {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: return %a
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Main() {
@@ -15,8 +15,8 @@ fn Run() {
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str0, param_refs: block0, return_type: type0, body: [block2]},
// CHECK:STDOUT: {name: str1, param_refs: block0, body: [block3]},
// CHECK:STDOUT: {name: str0, param_refs: block0, return_type: type0, body: [block3]},
// CHECK:STDOUT: {name: str2, param_refs: block0, body: [block4]},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: ]
@@ -25,6 +25,7 @@ fn Run() {
// CHECK:STDOUT: ]
// CHECK:STDOUT: strings: [
// CHECK:STDOUT: Foo,
// CHECK:STDOUT: return,
// CHECK:STDOUT: Run,
// CHECK:STDOUT: x,
// CHECK:STDOUT: ]
@@ -35,13 +36,14 @@ fn Run() {
// CHECK:STDOUT: type_blocks: [
// CHECK:STDOUT: ]
// CHECK:STDOUT: nodes: [
// CHECK:STDOUT: {kind: VarStorage, arg0: str1, type: type0},
// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function0},
// CHECK:STDOUT: {kind: RealLiteral, arg0: real0, type: type0},
// CHECK:STDOUT: {kind: ReturnExpression, arg0: node+1},
// CHECK:STDOUT: {kind: ReturnExpression, arg0: node+2},
// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function1},
// CHECK:STDOUT: {kind: VarStorage, arg0: str2, type: type1},
// CHECK:STDOUT: {kind: VarStorage, arg0: str3, type: type1},
// CHECK:STDOUT: {kind: Call, arg0: block0, arg1: function0, type: type0},
// CHECK:STDOUT: {kind: Assign, arg0: node+4, arg1: nodeError},
// CHECK:STDOUT: {kind: Assign, arg0: node+5, arg1: nodeError},
// CHECK:STDOUT: {kind: Return},
// CHECK:STDOUT: ]
// CHECK:STDOUT: node_blocks: [
@@ -49,17 +51,20 @@ fn Run() {
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+0,
// CHECK:STDOUT: node+3,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+1,
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+2,
// CHECK:STDOUT: node+3,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: node+5,
// CHECK:STDOUT: node+6,
// CHECK:STDOUT: node+7,
// CHECK:STDOUT: node+8,
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
// CHECK:STDOUT:
+13 -10
View File
@@ -15,7 +15,7 @@ fn Main() {
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str0, param_refs: block2, return_type: type0, body: [block4]},
// CHECK:STDOUT: {name: str2, param_refs: block0, body: [block5]},
// CHECK:STDOUT: {name: str3, param_refs: block0, body: [block5]},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: 1,
@@ -25,6 +25,7 @@ fn Main() {
// CHECK:STDOUT: strings: [
// CHECK:STDOUT: Echo,
// CHECK:STDOUT: a,
// CHECK:STDOUT: return,
// CHECK:STDOUT: Main,
// CHECK:STDOUT: b,
// CHECK:STDOUT: ]
@@ -35,14 +36,15 @@ fn Main() {
// CHECK:STDOUT: ]
// CHECK:STDOUT: nodes: [
// CHECK:STDOUT: {kind: Parameter, arg0: str1, type: type0},
// CHECK:STDOUT: {kind: VarStorage, arg0: str2, type: type0},
// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function0},
// CHECK:STDOUT: {kind: ReturnExpression, arg0: node+0},
// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function1},
// CHECK:STDOUT: {kind: VarStorage, arg0: str3, type: type0},
// CHECK:STDOUT: {kind: VarStorage, arg0: str4, type: type0},
// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int0, type: type0},
// CHECK:STDOUT: {kind: StubReference, arg0: node+5, type: type0},
// CHECK:STDOUT: {kind: StubReference, arg0: node+6, type: type0},
// CHECK:STDOUT: {kind: Call, arg0: block6, arg1: function0, type: type0},
// CHECK:STDOUT: {kind: Assign, arg0: node+4, arg1: node+7},
// CHECK:STDOUT: {kind: Assign, arg0: node+5, arg1: node+8},
// CHECK:STDOUT: {kind: Return},
// CHECK:STDOUT: ]
// CHECK:STDOUT: node_blocks: [
@@ -50,27 +52,28 @@ fn Main() {
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+0,
// CHECK:STDOUT: node+1,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+0,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+1,
// CHECK:STDOUT: node+2,
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+3,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+2,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: node+5,
// CHECK:STDOUT: node+6,
// CHECK:STDOUT: node+7,
// CHECK:STDOUT: node+8,
// CHECK:STDOUT: node+9,
// CHECK:STDOUT: node+10,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+6,
// CHECK:STDOUT: node+7,
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
// CHECK:STDOUT:
@@ -40,7 +40,6 @@ fn Main() {
// CHECK:STDOUT: {kind: TupleValue, arg0: block0, type: type0},
// CHECK:STDOUT: {kind: VarStorage, arg0: str2, type: type0},
// CHECK:STDOUT: {kind: Call, arg0: block0, arg1: function0, type: type0},
// CHECK:STDOUT: {kind: Assign, arg0: node+5, arg1: node+6},
// CHECK:STDOUT: {kind: Return},
// CHECK:STDOUT: ]
// CHECK:STDOUT: node_blocks: [
@@ -59,7 +58,6 @@ fn Main() {
// CHECK:STDOUT: node+5,
// CHECK:STDOUT: node+6,
// CHECK:STDOUT: node+7,
// CHECK:STDOUT: node+8,
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
// CHECK:STDOUT:
@@ -79,6 +77,5 @@ fn Main() {
// CHECK:STDOUT: %.loc11_11.2: () = tuple_value ()
// CHECK:STDOUT: %b: () = var "b"
// CHECK:STDOUT: %.loc11_37: () = call @MakeImplicitEmptyTuple()
// CHECK:STDOUT: assign %b, %.loc11_37
// CHECK:STDOUT: return
// CHECK:STDOUT: }