diff --git a/toolchain/check/context.cpp b/toolchain/check/context.cpp index 06f15753dd4d..4448a1d9b1f4 100644 --- a/toolchain/check/context.cpp +++ b/toolchain/check/context.cpp @@ -695,6 +695,7 @@ class TypeCompleter { case SemIR::TupleValue::Kind: case SemIR::UnaryOperatorNot::Kind: case SemIR::ValueAsReference::Kind: + case SemIR::ValueOfInitializer::Kind: case SemIR::VarStorage::Kind: CARBON_FATAL() << "Type refers to non-type node " << node; diff --git a/toolchain/check/convert.cpp b/toolchain/check/convert.cpp index 7faedc97da86..61ad6c6c1a46 100644 --- a/toolchain/check/convert.cpp +++ b/toolchain/check/convert.cpp @@ -563,10 +563,29 @@ static auto PerformBuiltinConversion(Context& context, Parse::Node parse_node, // If the value is already of the right kind and expression category, there's // nothing to do. Performing a conversion would decompose and rebuild tuples // and structs, so it's important that we bail out early in this case. - if (value_type_id == target.type_id && - IsValidExpressionCategoryForConversionTarget( - SemIR::GetExpressionCategory(sem_ir, value_id), target.kind)) { - return value_id; + if (value_type_id == target.type_id) { + auto value_cat = SemIR::GetExpressionCategory(sem_ir, value_id); + if (IsValidExpressionCategoryForConversionTarget(value_cat, target.kind)) { + return value_id; + } + + // If the source is an initializing expression, we may be able to pull a + // value right out of it. + if (value_cat == SemIR::ExpressionCategory::Initializing && + IsValidExpressionCategoryForConversionTarget( + SemIR::ExpressionCategory::Value, target.kind) && + SemIR::GetInitializingRepresentation(sem_ir, value_type_id).kind == + SemIR::InitializingRepresentation::ByCopy) { + auto value_rep = SemIR::GetValueRepresentation(sem_ir, value_type_id); + if (value_rep.kind == SemIR::ValueRepresentation::Copy && + value_rep.type_id == value_type_id) { + // The initializer produces an object representation by copy, and the + // value representation is a copy of the object representation, so we + // already have a value of the right form. + return context.AddNode( + SemIR::ValueOfInitializer{parse_node, value_type_id, value_id}); + } + } } // A tuple (T1, T2, ..., Tn) converts to (U1, U2, ..., Un) if each Ti diff --git a/toolchain/check/testdata/array/function_param.carbon b/toolchain/check/testdata/array/function_param.carbon index 4d473a534dc5..538654ec0d6d 100644 --- a/toolchain/check/testdata/array/function_param.carbon +++ b/toolchain/check/testdata/array/function_param.carbon @@ -50,9 +50,7 @@ fn G() -> i32 { // CHECK:STDOUT: %.loc12_20.13: init [i32; 3] = array_init %.loc12_20.2, (%.loc12_20.6, %.loc12_20.9, %.loc12_20.12) to %.loc12_20.3 // CHECK:STDOUT: %.loc12_20.14: ref [i32; 3] = temporary %.loc12_20.3, %.loc12_20.13 // CHECK:STDOUT: %.loc12_20.15: [i32; 3] = bind_value %.loc12_20.14 -// CHECK:STDOUT: %.loc12_11.1: init i32 = call %F.ref(%.loc12_20.15, %.loc12_23) -// CHECK:STDOUT: %.loc12_11.2: ref i32 = temporary_storage -// CHECK:STDOUT: %.loc12_11.3: ref i32 = temporary %.loc12_11.2, %.loc12_11.1 -// CHECK:STDOUT: %.loc12_11.4: i32 = bind_value %.loc12_11.3 -// CHECK:STDOUT: return %.loc12_11.4 +// CHECK:STDOUT: %.loc12_11: init i32 = call %F.ref(%.loc12_20.15, %.loc12_23) +// CHECK:STDOUT: %.loc12_25: i32 = value_of_initializer %.loc12_11 +// CHECK:STDOUT: return %.loc12_25 // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/class/basic.carbon b/toolchain/check/testdata/class/basic.carbon index 09a6a487d4b9..e1dba8ca17c3 100644 --- a/toolchain/check/testdata/class/basic.carbon +++ b/toolchain/check/testdata/class/basic.carbon @@ -60,9 +60,7 @@ fn Run() -> i32 { // CHECK:STDOUT: %Class.ref: type = name_reference "Class", file.%Class // CHECK:STDOUT: %F.ref: = name_reference "F", @Class.%F // CHECK:STDOUT: %.loc22_18: i32 = int_literal 4 -// CHECK:STDOUT: %.loc22_17.1: init i32 = call %F.ref(%.loc22_18) -// CHECK:STDOUT: %.loc22_17.2: ref i32 = temporary_storage -// CHECK:STDOUT: %.loc22_17.3: ref i32 = temporary %.loc22_17.2, %.loc22_17.1 -// CHECK:STDOUT: %.loc22_17.4: i32 = bind_value %.loc22_17.3 -// CHECK:STDOUT: return %.loc22_17.4 +// CHECK:STDOUT: %.loc22_17: init i32 = call %F.ref(%.loc22_18) +// CHECK:STDOUT: %.loc22_20: i32 = value_of_initializer %.loc22_17 +// CHECK:STDOUT: return %.loc22_20 // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/class/method.carbon b/toolchain/check/testdata/class/method.carbon index fc76b538e0eb..caa171b832ae 100644 --- a/toolchain/check/testdata/class/method.carbon +++ b/toolchain/check/testdata/class/method.carbon @@ -86,11 +86,9 @@ fn CallGOnInitializingExpression() -> i32 { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %c.ref: Class = name_reference "c", %c // CHECK:STDOUT: %.loc21_11: = bound_method %c.ref, @Class.%F -// CHECK:STDOUT: %.loc21_13.1: init i32 = call %.loc21_11(%c.ref) -// CHECK:STDOUT: %.loc21_13.2: ref i32 = temporary_storage -// CHECK:STDOUT: %.loc21_13.3: ref i32 = temporary %.loc21_13.2, %.loc21_13.1 -// CHECK:STDOUT: %.loc21_13.4: i32 = bind_value %.loc21_13.3 -// CHECK:STDOUT: return %.loc21_13.4 +// CHECK:STDOUT: %.loc21_13: init i32 = call %.loc21_11(%c.ref) +// CHECK:STDOUT: %.loc21_15: i32 = value_of_initializer %.loc21_13 +// CHECK:STDOUT: return %.loc21_15 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @CallWithAddr() -> i32 { @@ -101,11 +99,9 @@ fn CallGOnInitializingExpression() -> i32 { // CHECK:STDOUT: %c.ref: ref Class = name_reference "c", %c // CHECK:STDOUT: %.loc26_11: = bound_method %c.ref, @Class.%G // CHECK:STDOUT: %.loc26_10: Class* = address_of %c.ref -// CHECK:STDOUT: %.loc26_13.1: init i32 = call %.loc26_11(%.loc26_10) -// CHECK:STDOUT: %.loc26_13.2: ref i32 = temporary_storage -// CHECK:STDOUT: %.loc26_13.3: ref i32 = temporary %.loc26_13.2, %.loc26_13.1 -// CHECK:STDOUT: %.loc26_13.4: i32 = bind_value %.loc26_13.3 -// CHECK:STDOUT: return %.loc26_13.4 +// CHECK:STDOUT: %.loc26_13: init i32 = call %.loc26_11(%.loc26_10) +// CHECK:STDOUT: %.loc26_15: i32 = value_of_initializer %.loc26_13 +// CHECK:STDOUT: return %.loc26_15 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @CallFThroughPointer(%p: Class*) -> i32 { @@ -114,11 +110,9 @@ fn CallGOnInitializingExpression() -> i32 { // CHECK:STDOUT: %.loc30_11.1: ref Class = dereference %p.ref // CHECK:STDOUT: %.loc30_14: = bound_method %.loc30_11.1, @Class.%F // CHECK:STDOUT: %.loc30_11.2: Class = bind_value %.loc30_11.1 -// CHECK:STDOUT: %.loc30_16.1: init i32 = call %.loc30_14(%.loc30_11.2) -// CHECK:STDOUT: %.loc30_16.2: ref i32 = temporary_storage -// CHECK:STDOUT: %.loc30_16.3: ref i32 = temporary %.loc30_16.2, %.loc30_16.1 -// CHECK:STDOUT: %.loc30_16.4: i32 = bind_value %.loc30_16.3 -// CHECK:STDOUT: return %.loc30_16.4 +// CHECK:STDOUT: %.loc30_16: init i32 = call %.loc30_14(%.loc30_11.2) +// CHECK:STDOUT: %.loc30_18: i32 = value_of_initializer %.loc30_16 +// CHECK:STDOUT: return %.loc30_18 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @CallGThroughPointer(%p: Class*) -> i32 { @@ -127,11 +121,9 @@ fn CallGOnInitializingExpression() -> i32 { // CHECK:STDOUT: %.loc34_11.1: ref Class = dereference %p.ref // CHECK:STDOUT: %.loc34_14: = bound_method %.loc34_11.1, @Class.%G // CHECK:STDOUT: %.loc34_11.2: Class* = address_of %.loc34_11.1 -// CHECK:STDOUT: %.loc34_16.1: init i32 = call %.loc34_14(%.loc34_11.2) -// CHECK:STDOUT: %.loc34_16.2: ref i32 = temporary_storage -// CHECK:STDOUT: %.loc34_16.3: ref i32 = temporary %.loc34_16.2, %.loc34_16.1 -// CHECK:STDOUT: %.loc34_16.4: i32 = bind_value %.loc34_16.3 -// CHECK:STDOUT: return %.loc34_16.4 +// CHECK:STDOUT: %.loc34_16: init i32 = call %.loc34_14(%.loc34_11.2) +// CHECK:STDOUT: %.loc34_18: i32 = value_of_initializer %.loc34_16 +// CHECK:STDOUT: return %.loc34_18 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Make() -> %return: Class; @@ -144,11 +136,9 @@ fn CallGOnInitializingExpression() -> i32 { // CHECK:STDOUT: %.loc40_14.3: ref Class = temporary %.loc40_14.1, %.loc40_14.2 // CHECK:STDOUT: %.loc40_16: = bound_method %.loc40_14.3, @Class.%F // CHECK:STDOUT: %.loc40_14.4: Class = bind_value %.loc40_14.3 -// CHECK:STDOUT: %.loc40_18.1: init i32 = call %.loc40_16(%.loc40_14.4) -// CHECK:STDOUT: %.loc40_18.2: ref i32 = temporary_storage -// CHECK:STDOUT: %.loc40_18.3: ref i32 = temporary %.loc40_18.2, %.loc40_18.1 -// CHECK:STDOUT: %.loc40_18.4: i32 = bind_value %.loc40_18.3 -// CHECK:STDOUT: return %.loc40_18.4 +// CHECK:STDOUT: %.loc40_18: init i32 = call %.loc40_16(%.loc40_14.4) +// CHECK:STDOUT: %.loc40_20: i32 = value_of_initializer %.loc40_18 +// CHECK:STDOUT: return %.loc40_20 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @CallGOnInitializingExpression() -> i32 { @@ -159,9 +149,7 @@ fn CallGOnInitializingExpression() -> i32 { // CHECK:STDOUT: %.loc44_14.3: ref Class = temporary %.loc44_14.1, %.loc44_14.2 // CHECK:STDOUT: %.loc44_16: = bound_method %.loc44_14.3, @Class.%G // CHECK:STDOUT: %.loc44_14.4: Class* = address_of %.loc44_14.3 -// CHECK:STDOUT: %.loc44_18.1: init i32 = call %.loc44_16(%.loc44_14.4) -// CHECK:STDOUT: %.loc44_18.2: ref i32 = temporary_storage -// CHECK:STDOUT: %.loc44_18.3: ref i32 = temporary %.loc44_18.2, %.loc44_18.1 -// CHECK:STDOUT: %.loc44_18.4: i32 = bind_value %.loc44_18.3 -// CHECK:STDOUT: return %.loc44_18.4 +// CHECK:STDOUT: %.loc44_18: init i32 = call %.loc44_16(%.loc44_14.4) +// CHECK:STDOUT: %.loc44_20: i32 = value_of_initializer %.loc44_18 +// CHECK:STDOUT: return %.loc44_20 // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/class/scope.carbon b/toolchain/check/testdata/class/scope.carbon index eeb9ba80e1e7..70296e7efc7e 100644 --- a/toolchain/check/testdata/class/scope.carbon +++ b/toolchain/check/testdata/class/scope.carbon @@ -48,16 +48,12 @@ fn Run() -> i32 { // CHECK:STDOUT: fn @Run() -> i32 { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %F.ref.loc18_10: = name_reference "F", file.%F -// CHECK:STDOUT: %.loc18_11.1: init i32 = call %F.ref.loc18_10() +// CHECK:STDOUT: %.loc18_11: init i32 = call %F.ref.loc18_10() // CHECK:STDOUT: %Class.ref: type = name_reference "Class", file.%Class // CHECK:STDOUT: %F.ref.loc18_21: = name_reference "F", @Class.%F // CHECK:STDOUT: %.loc18_23.1: init i32 = call %F.ref.loc18_21() -// CHECK:STDOUT: %.loc18_11.2: ref i32 = temporary_storage -// CHECK:STDOUT: %.loc18_11.3: ref i32 = temporary %.loc18_11.2, %.loc18_11.1 -// CHECK:STDOUT: %.loc18_11.4: i32 = bind_value %.loc18_11.3 -// CHECK:STDOUT: %.loc18_23.2: ref i32 = temporary_storage -// CHECK:STDOUT: %.loc18_23.3: ref i32 = temporary %.loc18_23.2, %.loc18_23.1 -// CHECK:STDOUT: %.loc18_23.4: i32 = bind_value %.loc18_23.3 -// CHECK:STDOUT: %.loc18_14: i32 = add %.loc18_11.4, %.loc18_23.4 -// CHECK:STDOUT: return %.loc18_14 +// CHECK:STDOUT: %.loc18_14.1: i32 = value_of_initializer %.loc18_11 +// CHECK:STDOUT: %.loc18_23.2: i32 = value_of_initializer %.loc18_23.1 +// CHECK:STDOUT: %.loc18_14.2: i32 = add %.loc18_14.1, %.loc18_23.2 +// CHECK:STDOUT: return %.loc18_14.2 // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/class/self_type.carbon b/toolchain/check/testdata/class/self_type.carbon index 472bc2877d77..789071a30efc 100644 --- a/toolchain/check/testdata/class/self_type.carbon +++ b/toolchain/check/testdata/class/self_type.carbon @@ -45,9 +45,7 @@ fn Class.F[self: Class]() -> i32 { // CHECK:STDOUT: %.loc16_11.1: ref Class = dereference %.loc16_16.2 // CHECK:STDOUT: %.loc16_19: = bound_method %.loc16_11.1, @Class.%F // CHECK:STDOUT: %.loc16_11.2: Class = bind_value %.loc16_11.1 -// CHECK:STDOUT: %.loc16_21.1: init i32 = call %.loc16_19(%.loc16_11.2) -// CHECK:STDOUT: %.loc16_21.2: ref i32 = temporary_storage -// CHECK:STDOUT: %.loc16_21.3: ref i32 = temporary %.loc16_21.2, %.loc16_21.1 -// CHECK:STDOUT: %.loc16_21.4: i32 = bind_value %.loc16_21.3 -// CHECK:STDOUT: return %.loc16_21.4 +// CHECK:STDOUT: %.loc16_21: init i32 = call %.loc16_19(%.loc16_11.2) +// CHECK:STDOUT: %.loc16_23: i32 = value_of_initializer %.loc16_21 +// CHECK:STDOUT: return %.loc16_23 // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/class/static_method.carbon b/toolchain/check/testdata/class/static_method.carbon index b9fe68b12bae..cc0c65e7ced1 100644 --- a/toolchain/check/testdata/class/static_method.carbon +++ b/toolchain/check/testdata/class/static_method.carbon @@ -38,9 +38,7 @@ fn Run() -> i32 { // CHECK:STDOUT: %c: ref Class = bind_name "c", %c.var // CHECK:STDOUT: %c.ref: ref Class = name_reference "c", %c // CHECK:STDOUT: %F.ref: = name_reference "F", @Class.%F -// CHECK:STDOUT: %.loc13_13.1: init i32 = call %F.ref() -// CHECK:STDOUT: %.loc13_13.2: ref i32 = temporary_storage -// CHECK:STDOUT: %.loc13_13.3: ref i32 = temporary %.loc13_13.2, %.loc13_13.1 -// CHECK:STDOUT: %.loc13_13.4: i32 = bind_value %.loc13_13.3 -// CHECK:STDOUT: return %.loc13_13.4 +// CHECK:STDOUT: %.loc13_13: init i32 = call %F.ref() +// CHECK:STDOUT: %.loc13_15: i32 = value_of_initializer %.loc13_13 +// CHECK:STDOUT: return %.loc13_15 // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/if_expression/constant_condition.carbon b/toolchain/check/testdata/if_expression/constant_condition.carbon index 2321310b058c..dcb672bb3ea1 100644 --- a/toolchain/check/testdata/if_expression/constant_condition.carbon +++ b/toolchain/check/testdata/if_expression/constant_condition.carbon @@ -42,18 +42,14 @@ fn G() -> i32 { // CHECK:STDOUT: !if.expr.then: // CHECK:STDOUT: %A.ref: = name_reference "A", file.%A // CHECK:STDOUT: %.loc11_24.1: init i32 = call %A.ref() -// CHECK:STDOUT: %.loc11_24.2: ref i32 = temporary_storage -// CHECK:STDOUT: %.loc11_24.3: ref i32 = temporary %.loc11_24.2, %.loc11_24.1 -// CHECK:STDOUT: %.loc11_24.4: i32 = bind_value %.loc11_24.3 -// CHECK:STDOUT: br !if.expr.result(%.loc11_24.4) +// CHECK:STDOUT: %.loc11_24.2: i32 = value_of_initializer %.loc11_24.1 +// CHECK:STDOUT: br !if.expr.result(%.loc11_24.2) // CHECK:STDOUT: // CHECK:STDOUT: !if.expr.else: // CHECK:STDOUT: %B.ref: = name_reference "B", file.%B -// CHECK:STDOUT: %.loc11_33.1: init i32 = call %B.ref() -// CHECK:STDOUT: %.loc11_33.2: ref i32 = temporary_storage -// CHECK:STDOUT: %.loc11_33.3: ref i32 = temporary %.loc11_33.2, %.loc11_33.1 -// CHECK:STDOUT: %.loc11_33.4: i32 = bind_value %.loc11_33.3 -// CHECK:STDOUT: br !if.expr.result(%.loc11_33.4) +// CHECK:STDOUT: %.loc11_33: init i32 = call %B.ref() +// CHECK:STDOUT: %.loc11_27: i32 = value_of_initializer %.loc11_33 +// CHECK:STDOUT: br !if.expr.result(%.loc11_27) // CHECK:STDOUT: // CHECK:STDOUT: !if.expr.result: // CHECK:STDOUT: %.loc11_10: i32 = block_arg !if.expr.result @@ -68,18 +64,14 @@ fn G() -> i32 { // CHECK:STDOUT: !if.expr.then: // CHECK:STDOUT: %A.ref: = name_reference "A", file.%A // CHECK:STDOUT: %.loc15_25.1: init i32 = call %A.ref() -// CHECK:STDOUT: %.loc15_25.2: ref i32 = temporary_storage -// CHECK:STDOUT: %.loc15_25.3: ref i32 = temporary %.loc15_25.2, %.loc15_25.1 -// CHECK:STDOUT: %.loc15_25.4: i32 = bind_value %.loc15_25.3 -// CHECK:STDOUT: br !if.expr.result(%.loc15_25.4) +// CHECK:STDOUT: %.loc15_25.2: i32 = value_of_initializer %.loc15_25.1 +// CHECK:STDOUT: br !if.expr.result(%.loc15_25.2) // CHECK:STDOUT: // CHECK:STDOUT: !if.expr.else: // CHECK:STDOUT: %B.ref: = name_reference "B", file.%B -// CHECK:STDOUT: %.loc15_34.1: init i32 = call %B.ref() -// CHECK:STDOUT: %.loc15_34.2: ref i32 = temporary_storage -// CHECK:STDOUT: %.loc15_34.3: ref i32 = temporary %.loc15_34.2, %.loc15_34.1 -// CHECK:STDOUT: %.loc15_34.4: i32 = bind_value %.loc15_34.3 -// CHECK:STDOUT: br !if.expr.result(%.loc15_34.4) +// CHECK:STDOUT: %.loc15_34: init i32 = call %B.ref() +// CHECK:STDOUT: %.loc15_28: i32 = value_of_initializer %.loc15_34 +// CHECK:STDOUT: br !if.expr.result(%.loc15_28) // CHECK:STDOUT: // CHECK:STDOUT: !if.expr.result: // CHECK:STDOUT: %.loc15_10: i32 = block_arg !if.expr.result diff --git a/toolchain/check/testdata/if_expression/control_flow.carbon b/toolchain/check/testdata/if_expression/control_flow.carbon index ab7a5bbc28a9..49c579c0e285 100644 --- a/toolchain/check/testdata/if_expression/control_flow.carbon +++ b/toolchain/check/testdata/if_expression/control_flow.carbon @@ -37,18 +37,14 @@ fn F(b: bool) -> i32 { // CHECK:STDOUT: !if.expr.then: // CHECK:STDOUT: %A.ref: = name_reference "A", file.%A // CHECK:STDOUT: %.loc11_21.1: init i32 = call %A.ref() -// CHECK:STDOUT: %.loc11_21.2: ref i32 = temporary_storage -// CHECK:STDOUT: %.loc11_21.3: ref i32 = temporary %.loc11_21.2, %.loc11_21.1 -// CHECK:STDOUT: %.loc11_21.4: i32 = bind_value %.loc11_21.3 -// CHECK:STDOUT: br !if.expr.result(%.loc11_21.4) +// CHECK:STDOUT: %.loc11_21.2: i32 = value_of_initializer %.loc11_21.1 +// CHECK:STDOUT: br !if.expr.result(%.loc11_21.2) // CHECK:STDOUT: // CHECK:STDOUT: !if.expr.else: // CHECK:STDOUT: %B.ref: = name_reference "B", file.%B -// CHECK:STDOUT: %.loc11_30.1: init i32 = call %B.ref() -// CHECK:STDOUT: %.loc11_30.2: ref i32 = temporary_storage -// CHECK:STDOUT: %.loc11_30.3: ref i32 = temporary %.loc11_30.2, %.loc11_30.1 -// CHECK:STDOUT: %.loc11_30.4: i32 = bind_value %.loc11_30.3 -// CHECK:STDOUT: br !if.expr.result(%.loc11_30.4) +// CHECK:STDOUT: %.loc11_30: init i32 = call %B.ref() +// CHECK:STDOUT: %.loc11_24: i32 = value_of_initializer %.loc11_30 +// CHECK:STDOUT: br !if.expr.result(%.loc11_24) // CHECK:STDOUT: // CHECK:STDOUT: !if.expr.result: // CHECK:STDOUT: %.loc11_10: i32 = block_arg !if.expr.result diff --git a/toolchain/check/testdata/operators/and.carbon b/toolchain/check/testdata/operators/and.carbon index 019a4f535b98..31a00c384774 100644 --- a/toolchain/check/testdata/operators/and.carbon +++ b/toolchain/check/testdata/operators/and.carbon @@ -32,22 +32,18 @@ fn And() -> bool { // CHECK:STDOUT: fn @And() -> bool { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %F.ref: = name_reference "F", file.%F -// CHECK:STDOUT: %.loc11_11.1: init bool = call %F.ref() -// CHECK:STDOUT: %.loc11_11.2: ref bool = temporary_storage -// CHECK:STDOUT: %.loc11_11.3: ref bool = temporary %.loc11_11.2, %.loc11_11.1 -// CHECK:STDOUT: %.loc11_11.4: bool = bind_value %.loc11_11.3 -// CHECK:STDOUT: %.loc11_14.1: bool = bool_literal false -// CHECK:STDOUT: if %.loc11_11.4 br !and.rhs else br !and.result(%.loc11_14.1) +// CHECK:STDOUT: %.loc11_11: init bool = call %F.ref() +// CHECK:STDOUT: %.loc11_14.1: bool = value_of_initializer %.loc11_11 +// CHECK:STDOUT: %.loc11_14.2: bool = bool_literal false +// CHECK:STDOUT: if %.loc11_14.1 br !and.rhs else br !and.result(%.loc11_14.2) // CHECK:STDOUT: // CHECK:STDOUT: !and.rhs: // CHECK:STDOUT: %G.ref: = name_reference "G", file.%G -// CHECK:STDOUT: %.loc11_19.1: init bool = call %G.ref() -// CHECK:STDOUT: %.loc11_19.2: ref bool = temporary_storage -// CHECK:STDOUT: %.loc11_19.3: ref bool = temporary %.loc11_19.2, %.loc11_19.1 -// CHECK:STDOUT: %.loc11_19.4: bool = bind_value %.loc11_19.3 -// CHECK:STDOUT: br !and.result(%.loc11_19.4) +// CHECK:STDOUT: %.loc11_19: init bool = call %G.ref() +// CHECK:STDOUT: %.loc11_14.3: bool = value_of_initializer %.loc11_19 +// CHECK:STDOUT: br !and.result(%.loc11_14.3) // CHECK:STDOUT: // CHECK:STDOUT: !and.result: -// CHECK:STDOUT: %.loc11_14.2: bool = block_arg !and.result -// CHECK:STDOUT: return %.loc11_14.2 +// CHECK:STDOUT: %.loc11_14.4: bool = block_arg !and.result +// CHECK:STDOUT: return %.loc11_14.4 // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/operators/or.carbon b/toolchain/check/testdata/operators/or.carbon index 66944f0f1684..a497846a711d 100644 --- a/toolchain/check/testdata/operators/or.carbon +++ b/toolchain/check/testdata/operators/or.carbon @@ -32,23 +32,19 @@ fn Or() -> bool { // CHECK:STDOUT: fn @Or() -> bool { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %F.ref: = name_reference "F", file.%F -// CHECK:STDOUT: %.loc11_11.1: init bool = call %F.ref() -// CHECK:STDOUT: %.loc11_11.2: ref bool = temporary_storage -// CHECK:STDOUT: %.loc11_11.3: ref bool = temporary %.loc11_11.2, %.loc11_11.1 -// CHECK:STDOUT: %.loc11_11.4: bool = bind_value %.loc11_11.3 -// CHECK:STDOUT: %.loc11_14.1: bool = not %.loc11_11.4 -// CHECK:STDOUT: %.loc11_14.2: bool = bool_literal true -// CHECK:STDOUT: if %.loc11_14.1 br !or.rhs else br !or.result(%.loc11_14.2) +// CHECK:STDOUT: %.loc11_11: init bool = call %F.ref() +// CHECK:STDOUT: %.loc11_14.1: bool = value_of_initializer %.loc11_11 +// CHECK:STDOUT: %.loc11_14.2: bool = not %.loc11_14.1 +// CHECK:STDOUT: %.loc11_14.3: bool = bool_literal true +// CHECK:STDOUT: if %.loc11_14.2 br !or.rhs else br !or.result(%.loc11_14.3) // CHECK:STDOUT: // CHECK:STDOUT: !or.rhs: // CHECK:STDOUT: %G.ref: = name_reference "G", file.%G -// CHECK:STDOUT: %.loc11_18.1: init bool = call %G.ref() -// CHECK:STDOUT: %.loc11_18.2: ref bool = temporary_storage -// CHECK:STDOUT: %.loc11_18.3: ref bool = temporary %.loc11_18.2, %.loc11_18.1 -// CHECK:STDOUT: %.loc11_18.4: bool = bind_value %.loc11_18.3 -// CHECK:STDOUT: br !or.result(%.loc11_18.4) +// CHECK:STDOUT: %.loc11_18: init bool = call %G.ref() +// CHECK:STDOUT: %.loc11_14.4: bool = value_of_initializer %.loc11_18 +// CHECK:STDOUT: br !or.result(%.loc11_14.4) // CHECK:STDOUT: // CHECK:STDOUT: !or.result: -// CHECK:STDOUT: %.loc11_14.3: bool = block_arg !or.result -// CHECK:STDOUT: return %.loc11_14.3 +// CHECK:STDOUT: %.loc11_14.5: bool = block_arg !or.result +// CHECK:STDOUT: return %.loc11_14.5 // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/struct/reorder_fields.carbon b/toolchain/check/testdata/struct/reorder_fields.carbon index 68f44f0a4ffa..e992369ce1e6 100644 --- a/toolchain/check/testdata/struct/reorder_fields.carbon +++ b/toolchain/check/testdata/struct/reorder_fields.carbon @@ -28,21 +28,17 @@ fn F() -> {.a: i32, .b: f64} { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %.loc11_27: type = struct_type {.a: i32, .b: f64} // CHECK:STDOUT: %MakeF64.ref: = name_reference "MakeF64", file.%MakeF64 -// CHECK:STDOUT: %.loc11_44.1: init f64 = call %MakeF64.ref() +// CHECK:STDOUT: %.loc11_44: init f64 = call %MakeF64.ref() // CHECK:STDOUT: %MakeI32.ref: = name_reference "MakeI32", file.%MakeI32 -// CHECK:STDOUT: %.loc11_60.1: init i32 = call %MakeI32.ref() +// CHECK:STDOUT: %.loc11_60: init i32 = call %MakeI32.ref() // CHECK:STDOUT: %.loc11_62.1: type = struct_type {.b: f64, .a: i32} -// CHECK:STDOUT: %.loc11_62.2: {.b: f64, .a: i32} = struct_literal (%.loc11_44.1, %.loc11_60.1) -// CHECK:STDOUT: %.loc11_60.2: ref i32 = temporary_storage -// CHECK:STDOUT: %.loc11_60.3: ref i32 = temporary %.loc11_60.2, %.loc11_60.1 -// CHECK:STDOUT: %.loc11_60.4: i32 = bind_value %.loc11_60.3 -// CHECK:STDOUT: %.loc11_44.2: ref f64 = temporary_storage -// CHECK:STDOUT: %.loc11_44.3: ref f64 = temporary %.loc11_44.2, %.loc11_44.1 -// CHECK:STDOUT: %.loc11_44.4: f64 = bind_value %.loc11_44.3 -// CHECK:STDOUT: %.loc11_62.3: {.a: i32, .b: f64} = struct_value %.loc11_62.2, (%.loc11_60.4, %.loc11_44.4) -// CHECK:STDOUT: %x: {.a: i32, .b: f64} = bind_name "x", %.loc11_62.3 +// CHECK:STDOUT: %.loc11_62.2: {.b: f64, .a: i32} = struct_literal (%.loc11_44, %.loc11_60) +// CHECK:STDOUT: %.loc11_62.3: i32 = value_of_initializer %.loc11_60 +// CHECK:STDOUT: %.loc11_62.4: f64 = value_of_initializer %.loc11_44 +// CHECK:STDOUT: %.loc11_62.5: {.a: i32, .b: f64} = struct_value %.loc11_62.2, (%.loc11_62.3, %.loc11_62.4) +// CHECK:STDOUT: %x: {.a: i32, .b: f64} = bind_name "x", %.loc11_62.5 // CHECK:STDOUT: %.loc12_27: type = struct_type {.b: f64, .a: i32} -// CHECK:STDOUT: %.loc11_62.4: type = ptr_type {.b: f64, .a: i32} +// CHECK:STDOUT: %.loc11_62.6: type = ptr_type {.b: f64, .a: i32} // CHECK:STDOUT: %x.ref: {.a: i32, .b: f64} = name_reference "x", %x // CHECK:STDOUT: %.loc12_31.1: f64 = struct_access %x.ref, member1 // CHECK:STDOUT: %.loc12_31.2: i32 = struct_access %x.ref, member0 diff --git a/toolchain/check/testdata/while/break_continue.carbon b/toolchain/check/testdata/while/break_continue.carbon index 522ef0a6bfb8..c84f8a31e344 100644 --- a/toolchain/check/testdata/while/break_continue.carbon +++ b/toolchain/check/testdata/while/break_continue.carbon @@ -60,30 +60,24 @@ fn While() { // CHECK:STDOUT: // CHECK:STDOUT: !while.cond.loc17: // CHECK:STDOUT: %A.ref: = name_reference "A", file.%A -// CHECK:STDOUT: %.loc17_11.1: init bool = call %A.ref() -// CHECK:STDOUT: %.loc17_11.2: ref bool = temporary_storage -// CHECK:STDOUT: %.loc17_11.3: ref bool = temporary %.loc17_11.2, %.loc17_11.1 -// CHECK:STDOUT: %.loc17_11.4: bool = bind_value %.loc17_11.3 -// CHECK:STDOUT: if %.loc17_11.4 br !while.body.loc17 else br !while.done.loc17 +// CHECK:STDOUT: %.loc17_11: init bool = call %A.ref() +// CHECK:STDOUT: %.loc17_13: bool = value_of_initializer %.loc17_11 +// CHECK:STDOUT: if %.loc17_13 br !while.body.loc17 else br !while.done.loc17 // CHECK:STDOUT: // CHECK:STDOUT: !while.body.loc17: // CHECK:STDOUT: %B.ref: = name_reference "B", file.%B -// CHECK:STDOUT: %.loc18_10.1: init bool = call %B.ref() -// CHECK:STDOUT: %.loc18_10.2: ref bool = temporary_storage -// CHECK:STDOUT: %.loc18_10.3: ref bool = temporary %.loc18_10.2, %.loc18_10.1 -// CHECK:STDOUT: %.loc18_10.4: bool = bind_value %.loc18_10.3 -// CHECK:STDOUT: if %.loc18_10.4 br !if.then.loc18 else br !if.else.loc18 +// CHECK:STDOUT: %.loc18_10: init bool = call %B.ref() +// CHECK:STDOUT: %.loc18_12: bool = value_of_initializer %.loc18_10 +// CHECK:STDOUT: if %.loc18_12 br !if.then.loc18 else br !if.else.loc18 // CHECK:STDOUT: // CHECK:STDOUT: !if.then.loc18: // CHECK:STDOUT: br !while.cond.loc17 // CHECK:STDOUT: // CHECK:STDOUT: !if.else.loc18: // CHECK:STDOUT: %C.ref: = name_reference "C", file.%C -// CHECK:STDOUT: %.loc19_10.1: init bool = call %C.ref() -// CHECK:STDOUT: %.loc19_10.2: ref bool = temporary_storage -// CHECK:STDOUT: %.loc19_10.3: ref bool = temporary %.loc19_10.2, %.loc19_10.1 -// CHECK:STDOUT: %.loc19_10.4: bool = bind_value %.loc19_10.3 -// CHECK:STDOUT: if %.loc19_10.4 br !if.then.loc19 else br !if.else.loc19 +// CHECK:STDOUT: %.loc19_10: init bool = call %C.ref() +// CHECK:STDOUT: %.loc19_12: bool = value_of_initializer %.loc19_10 +// CHECK:STDOUT: if %.loc19_12 br !if.then.loc19 else br !if.else.loc19 // CHECK:STDOUT: // CHECK:STDOUT: !if.then.loc19: // CHECK:STDOUT: br !while.done.loc17 @@ -93,30 +87,24 @@ fn While() { // CHECK:STDOUT: // CHECK:STDOUT: !while.cond.loc20: // CHECK:STDOUT: %D.ref: = name_reference "D", file.%D -// CHECK:STDOUT: %.loc20_13.1: init bool = call %D.ref() -// CHECK:STDOUT: %.loc20_13.2: ref bool = temporary_storage -// CHECK:STDOUT: %.loc20_13.3: ref bool = temporary %.loc20_13.2, %.loc20_13.1 -// CHECK:STDOUT: %.loc20_13.4: bool = bind_value %.loc20_13.3 -// CHECK:STDOUT: if %.loc20_13.4 br !while.body.loc20 else br !while.done.loc20 +// CHECK:STDOUT: %.loc20_13: init bool = call %D.ref() +// CHECK:STDOUT: %.loc20_15: bool = value_of_initializer %.loc20_13 +// CHECK:STDOUT: if %.loc20_15 br !while.body.loc20 else br !while.done.loc20 // CHECK:STDOUT: // CHECK:STDOUT: !while.body.loc20: // CHECK:STDOUT: %E.ref: = name_reference "E", file.%E -// CHECK:STDOUT: %.loc21_12.1: init bool = call %E.ref() -// CHECK:STDOUT: %.loc21_12.2: ref bool = temporary_storage -// CHECK:STDOUT: %.loc21_12.3: ref bool = temporary %.loc21_12.2, %.loc21_12.1 -// CHECK:STDOUT: %.loc21_12.4: bool = bind_value %.loc21_12.3 -// CHECK:STDOUT: if %.loc21_12.4 br !if.then.loc21 else br !if.else.loc21 +// CHECK:STDOUT: %.loc21_12: init bool = call %E.ref() +// CHECK:STDOUT: %.loc21_14: bool = value_of_initializer %.loc21_12 +// CHECK:STDOUT: if %.loc21_14 br !if.then.loc21 else br !if.else.loc21 // CHECK:STDOUT: // CHECK:STDOUT: !if.then.loc21: // CHECK:STDOUT: br !while.cond.loc20 // CHECK:STDOUT: // CHECK:STDOUT: !if.else.loc21: // CHECK:STDOUT: %F.ref: = name_reference "F", file.%F -// CHECK:STDOUT: %.loc22_12.1: init bool = call %F.ref() -// CHECK:STDOUT: %.loc22_12.2: ref bool = temporary_storage -// CHECK:STDOUT: %.loc22_12.3: ref bool = temporary %.loc22_12.2, %.loc22_12.1 -// CHECK:STDOUT: %.loc22_12.4: bool = bind_value %.loc22_12.3 -// CHECK:STDOUT: if %.loc22_12.4 br !if.then.loc22 else br !if.else.loc22 +// CHECK:STDOUT: %.loc22_12: init bool = call %F.ref() +// CHECK:STDOUT: %.loc22_14: bool = value_of_initializer %.loc22_12 +// CHECK:STDOUT: if %.loc22_14 br !if.then.loc22 else br !if.else.loc22 // CHECK:STDOUT: // CHECK:STDOUT: !if.then.loc22: // CHECK:STDOUT: br !while.done.loc20 @@ -126,22 +114,18 @@ fn While() { // CHECK:STDOUT: // CHECK:STDOUT: !while.done.loc20: // CHECK:STDOUT: %G.ref: = name_reference "G", file.%G -// CHECK:STDOUT: %.loc24_10.1: init bool = call %G.ref() -// CHECK:STDOUT: %.loc24_10.2: ref bool = temporary_storage -// CHECK:STDOUT: %.loc24_10.3: ref bool = temporary %.loc24_10.2, %.loc24_10.1 -// CHECK:STDOUT: %.loc24_10.4: bool = bind_value %.loc24_10.3 -// CHECK:STDOUT: if %.loc24_10.4 br !if.then.loc24 else br !if.else.loc24 +// CHECK:STDOUT: %.loc24_10: init bool = call %G.ref() +// CHECK:STDOUT: %.loc24_12: bool = value_of_initializer %.loc24_10 +// CHECK:STDOUT: if %.loc24_12 br !if.then.loc24 else br !if.else.loc24 // CHECK:STDOUT: // CHECK:STDOUT: !if.then.loc24: // CHECK:STDOUT: br !while.cond.loc17 // CHECK:STDOUT: // CHECK:STDOUT: !if.else.loc24: // CHECK:STDOUT: %H.ref: = name_reference "H", file.%H -// CHECK:STDOUT: %.loc25_10.1: init bool = call %H.ref() -// CHECK:STDOUT: %.loc25_10.2: ref bool = temporary_storage -// CHECK:STDOUT: %.loc25_10.3: ref bool = temporary %.loc25_10.2, %.loc25_10.1 -// CHECK:STDOUT: %.loc25_10.4: bool = bind_value %.loc25_10.3 -// CHECK:STDOUT: if %.loc25_10.4 br !if.then.loc25 else br !if.else.loc25 +// CHECK:STDOUT: %.loc25_10: init bool = call %H.ref() +// CHECK:STDOUT: %.loc25_12: bool = value_of_initializer %.loc25_10 +// CHECK:STDOUT: if %.loc25_12 br !if.then.loc25 else br !if.else.loc25 // CHECK:STDOUT: // CHECK:STDOUT: !if.then.loc25: // CHECK:STDOUT: br !while.done.loc17 diff --git a/toolchain/check/testdata/while/unreachable_end.carbon b/toolchain/check/testdata/while/unreachable_end.carbon index 47ad2ed4098f..32fdcb5948b8 100644 --- a/toolchain/check/testdata/while/unreachable_end.carbon +++ b/toolchain/check/testdata/while/unreachable_end.carbon @@ -44,11 +44,9 @@ fn While() { // CHECK:STDOUT: // CHECK:STDOUT: !while.cond: // CHECK:STDOUT: %Cond.ref: = name_reference "Cond", file.%Cond -// CHECK:STDOUT: %.loc15_14.1: init bool = call %Cond.ref() -// CHECK:STDOUT: %.loc15_14.2: ref bool = temporary_storage -// CHECK:STDOUT: %.loc15_14.3: ref bool = temporary %.loc15_14.2, %.loc15_14.1 -// CHECK:STDOUT: %.loc15_14.4: bool = bind_value %.loc15_14.3 -// CHECK:STDOUT: if %.loc15_14.4 br !while.body else br !while.done +// CHECK:STDOUT: %.loc15_14: init bool = call %Cond.ref() +// CHECK:STDOUT: %.loc15_16: bool = value_of_initializer %.loc15_14 +// CHECK:STDOUT: if %.loc15_16 br !while.body else br !while.done // CHECK:STDOUT: // CHECK:STDOUT: !while.body: // CHECK:STDOUT: %G.ref: = name_reference "G", file.%G diff --git a/toolchain/check/testdata/while/while.carbon b/toolchain/check/testdata/while/while.carbon index bb6d56b6cd55..0b00176db47a 100644 --- a/toolchain/check/testdata/while/while.carbon +++ b/toolchain/check/testdata/while/while.carbon @@ -43,11 +43,9 @@ fn While() { // CHECK:STDOUT: // CHECK:STDOUT: !while.cond: // CHECK:STDOUT: %Cond.ref: = name_reference "Cond", file.%Cond -// CHECK:STDOUT: %.loc15_14.1: init bool = call %Cond.ref() -// CHECK:STDOUT: %.loc15_14.2: ref bool = temporary_storage -// CHECK:STDOUT: %.loc15_14.3: ref bool = temporary %.loc15_14.2, %.loc15_14.1 -// CHECK:STDOUT: %.loc15_14.4: bool = bind_value %.loc15_14.3 -// CHECK:STDOUT: if %.loc15_14.4 br !while.body else br !while.done +// CHECK:STDOUT: %.loc15_14: init bool = call %Cond.ref() +// CHECK:STDOUT: %.loc15_16: bool = value_of_initializer %.loc15_14 +// CHECK:STDOUT: if %.loc15_16 br !while.body else br !while.done // CHECK:STDOUT: // CHECK:STDOUT: !while.body: // CHECK:STDOUT: %G.ref: = name_reference "G", file.%G diff --git a/toolchain/lower/handle_expression_category.cpp b/toolchain/lower/handle_expression_category.cpp index a5300bf6f581..32356e81732b 100644 --- a/toolchain/lower/handle_expression_category.cpp +++ b/toolchain/lower/handle_expression_category.cpp @@ -58,4 +58,17 @@ auto HandleValueAsReference(FunctionContext& context, SemIR::NodeId node_id, context.SetLocal(node_id, context.GetLocal(node.value_id)); } +auto HandleValueOfInitializer(FunctionContext& context, SemIR::NodeId node_id, + SemIR::ValueOfInitializer node) -> void { + CARBON_CHECK(SemIR::GetExpressionCategory(context.sem_ir(), node.init_id) == + SemIR::ExpressionCategory::Initializing); + CARBON_CHECK( + SemIR::GetValueRepresentation(context.sem_ir(), node.type_id).kind == + SemIR::ValueRepresentation::Copy); + CARBON_CHECK( + SemIR::GetInitializingRepresentation(context.sem_ir(), node.type_id) + .kind == SemIR::InitializingRepresentation::ByCopy); + context.SetLocal(node_id, context.GetLocal(node.init_id)); +} + } // namespace Carbon::Lower diff --git a/toolchain/lower/testdata/array/function_param.carbon b/toolchain/lower/testdata/array/function_param.carbon index 584e38fc6e23..216b26a913af 100644 --- a/toolchain/lower/testdata/array/function_param.carbon +++ b/toolchain/lower/testdata/array/function_param.carbon @@ -30,8 +30,5 @@ fn G() -> i32 { // CHECK:STDOUT: %array.index2 = getelementptr inbounds [3 x i32], ptr %temp, i32 0, i32 2 // CHECK:STDOUT: store i32 3, ptr %array.index2, align 4 // CHECK:STDOUT: %F = call i32 @F(ptr %temp, i32 1) -// CHECK:STDOUT: %temp3 = alloca i32, align 4 -// CHECK:STDOUT: store i32 %F, ptr %temp3, align 4 -// CHECK:STDOUT: %1 = load i32, ptr %temp3, align 4 -// CHECK:STDOUT: ret i32 %1 +// CHECK:STDOUT: ret i32 %F // CHECK:STDOUT: } diff --git a/toolchain/lower/testdata/class/field.carbon b/toolchain/lower/testdata/class/field.carbon index 61d233e337ec..b688f90b9498 100644 --- a/toolchain/lower/testdata/class/field.carbon +++ b/toolchain/lower/testdata/class/field.carbon @@ -38,8 +38,5 @@ fn Run() -> i32 { // CHECK:STDOUT: %b = getelementptr inbounds { i32, ptr }, ptr %c, i32 0, i32 1 // CHECK:STDOUT: store ptr %c, ptr %b, align 8 // CHECK:STDOUT: %F = call i32 @F(ptr %c) -// CHECK:STDOUT: %temp = alloca i32, align 4 -// CHECK:STDOUT: store i32 %F, ptr %temp, align 4 -// CHECK:STDOUT: %1 = load i32, ptr %temp, align 4 -// CHECK:STDOUT: ret i32 %1 +// CHECK:STDOUT: ret i32 %F // CHECK:STDOUT: } diff --git a/toolchain/lower/testdata/class/method.carbon b/toolchain/lower/testdata/class/method.carbon index f84fcbbc3b11..a754b2918a26 100644 --- a/toolchain/lower/testdata/class/method.carbon +++ b/toolchain/lower/testdata/class/method.carbon @@ -25,9 +25,6 @@ fn F(p: C*) { // CHECK:STDOUT: // CHECK:STDOUT: define void @F(ptr %p) { // CHECK:STDOUT: %Get = call i32 @Get(ptr %p) -// CHECK:STDOUT: %temp = alloca i32, align 4 -// CHECK:STDOUT: store i32 %Get, ptr %temp, align 4 -// CHECK:STDOUT: %1 = load i32, ptr %temp, align 4 -// CHECK:STDOUT: call void @Set(ptr %p, i32 %1) +// CHECK:STDOUT: call void @Set(ptr %p, i32 %Get) // CHECK:STDOUT: ret void // CHECK:STDOUT: } diff --git a/toolchain/lower/testdata/if_expression/basic.carbon b/toolchain/lower/testdata/if_expression/basic.carbon index 8fd9dde43199..88b5ebc2921a 100644 --- a/toolchain/lower/testdata/if_expression/basic.carbon +++ b/toolchain/lower/testdata/if_expression/basic.carbon @@ -23,23 +23,17 @@ fn Select(b: bool) -> i32 { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: define i32 @Select(i1 %b) { -// CHECK:STDOUT: br i1 %b, label %1, label %3 +// CHECK:STDOUT: br i1 %b, label %1, label %2 // CHECK:STDOUT: // CHECK:STDOUT: 1: ; preds = %0 // CHECK:STDOUT: %F = call i32 @F() -// CHECK:STDOUT: %temp = alloca i32, align 4 -// CHECK:STDOUT: store i32 %F, ptr %temp, align 4 -// CHECK:STDOUT: %2 = load i32, ptr %temp, align 4 -// CHECK:STDOUT: br label %5 +// CHECK:STDOUT: br label %3 // CHECK:STDOUT: -// CHECK:STDOUT: 3: ; preds = %0 +// CHECK:STDOUT: 2: ; preds = %0 // CHECK:STDOUT: %G = call i32 @G() -// CHECK:STDOUT: %temp1 = alloca i32, align 4 -// CHECK:STDOUT: store i32 %G, ptr %temp1, align 4 -// CHECK:STDOUT: %4 = load i32, ptr %temp1, align 4 -// CHECK:STDOUT: br label %5 +// CHECK:STDOUT: br label %3 // CHECK:STDOUT: -// CHECK:STDOUT: 5: ; preds = %3, %1 -// CHECK:STDOUT: %6 = phi i32 [ %2, %1 ], [ %4, %3 ] -// CHECK:STDOUT: ret i32 %6 +// CHECK:STDOUT: 3: ; preds = %2, %1 +// CHECK:STDOUT: %4 = phi i32 [ %F, %1 ], [ %G, %2 ] +// CHECK:STDOUT: ret i32 %4 // CHECK:STDOUT: } diff --git a/toolchain/lower/testdata/operators/and.carbon b/toolchain/lower/testdata/operators/and.carbon index 600d5718ac55..418c98a51447 100644 --- a/toolchain/lower/testdata/operators/and.carbon +++ b/toolchain/lower/testdata/operators/and.carbon @@ -24,19 +24,13 @@ fn And() -> bool { // CHECK:STDOUT: // CHECK:STDOUT: define i1 @And() { // CHECK:STDOUT: %F = call i1 @F() -// CHECK:STDOUT: %temp = alloca i1, align 1 -// CHECK:STDOUT: store i1 %F, ptr %temp, align 1 -// CHECK:STDOUT: %1 = load i1, ptr %temp, align 1 -// CHECK:STDOUT: br i1 %1, label %2, label %4 +// CHECK:STDOUT: br i1 %F, label %1, label %2 // CHECK:STDOUT: -// CHECK:STDOUT: 2: ; preds = %0 +// CHECK:STDOUT: 1: ; preds = %0 // CHECK:STDOUT: %G = call i1 @G() -// CHECK:STDOUT: %temp1 = alloca i1, align 1 -// CHECK:STDOUT: store i1 %G, ptr %temp1, align 1 -// CHECK:STDOUT: %3 = load i1, ptr %temp1, align 1 -// CHECK:STDOUT: br label %4 +// CHECK:STDOUT: br label %2 // CHECK:STDOUT: -// CHECK:STDOUT: 4: ; preds = %2, %0 -// CHECK:STDOUT: %5 = phi i1 [ false, %0 ], [ %3, %2 ] -// CHECK:STDOUT: ret i1 %5 +// CHECK:STDOUT: 2: ; preds = %1, %0 +// CHECK:STDOUT: %3 = phi i1 [ false, %0 ], [ %G, %1 ] +// CHECK:STDOUT: ret i1 %3 // CHECK:STDOUT: } diff --git a/toolchain/lower/testdata/operators/or.carbon b/toolchain/lower/testdata/operators/or.carbon index 307e51bd9aff..b5214337ac68 100644 --- a/toolchain/lower/testdata/operators/or.carbon +++ b/toolchain/lower/testdata/operators/or.carbon @@ -24,20 +24,14 @@ fn Or() -> bool { // CHECK:STDOUT: // CHECK:STDOUT: define i1 @Or() { // CHECK:STDOUT: %F = call i1 @F() -// CHECK:STDOUT: %temp = alloca i1, align 1 -// CHECK:STDOUT: store i1 %F, ptr %temp, align 1 -// CHECK:STDOUT: %1 = load i1, ptr %temp, align 1 -// CHECK:STDOUT: %2 = xor i1 %1, true -// CHECK:STDOUT: br i1 %2, label %3, label %5 +// CHECK:STDOUT: %1 = xor i1 %F, true +// CHECK:STDOUT: br i1 %1, label %2, label %3 // CHECK:STDOUT: -// CHECK:STDOUT: 3: ; preds = %0 +// CHECK:STDOUT: 2: ; preds = %0 // CHECK:STDOUT: %G = call i1 @G() -// CHECK:STDOUT: %temp1 = alloca i1, align 1 -// CHECK:STDOUT: store i1 %G, ptr %temp1, align 1 -// CHECK:STDOUT: %4 = load i1, ptr %temp1, align 1 -// CHECK:STDOUT: br label %5 +// CHECK:STDOUT: br label %3 // CHECK:STDOUT: -// CHECK:STDOUT: 5: ; preds = %3, %0 -// CHECK:STDOUT: %6 = phi i1 [ true, %0 ], [ %4, %3 ] -// CHECK:STDOUT: ret i1 %6 +// CHECK:STDOUT: 3: ; preds = %2, %0 +// CHECK:STDOUT: %4 = phi i1 [ true, %0 ], [ %G, %2 ] +// CHECK:STDOUT: ret i1 %4 // CHECK:STDOUT: } diff --git a/toolchain/lower/testdata/pointer/basic.carbon b/toolchain/lower/testdata/pointer/basic.carbon index 82687f1105af..f970872be781 100644 --- a/toolchain/lower/testdata/pointer/basic.carbon +++ b/toolchain/lower/testdata/pointer/basic.carbon @@ -25,8 +25,5 @@ fn F() -> i32 { // CHECK:STDOUT: %n = alloca i32, align 4 // CHECK:STDOUT: store i32 0, ptr %n, align 4 // CHECK:STDOUT: %G = call i32 @G(ptr %n) -// CHECK:STDOUT: %temp = alloca i32, align 4 -// CHECK:STDOUT: store i32 %G, ptr %temp, align 4 -// CHECK:STDOUT: %1 = load i32, ptr %temp, align 4 -// CHECK:STDOUT: ret i32 %1 +// CHECK:STDOUT: ret i32 %G // CHECK:STDOUT: } diff --git a/toolchain/lower/testdata/while/break_continue.carbon b/toolchain/lower/testdata/while/break_continue.carbon index ca014b97067d..ab18c2a5e969 100644 --- a/toolchain/lower/testdata/while/break_continue.carbon +++ b/toolchain/lower/testdata/while/break_continue.carbon @@ -28,37 +28,28 @@ fn While() { // CHECK:STDOUT: entry: // CHECK:STDOUT: br label %0 // CHECK:STDOUT: -// CHECK:STDOUT: 0: ; preds = %entry, %8, %4 +// CHECK:STDOUT: 0: ; preds = %entry, %5, %2 // CHECK:STDOUT: %A = call i1 @A() -// CHECK:STDOUT: %temp = alloca i1, align 1 -// CHECK:STDOUT: store i1 %A, ptr %temp, align 1 -// CHECK:STDOUT: %1 = load i1, ptr %temp, align 1 -// CHECK:STDOUT: br i1 %1, label %2, label %9 +// CHECK:STDOUT: br i1 %A, label %1, label %6 // CHECK:STDOUT: -// CHECK:STDOUT: 2: ; preds = %0 +// CHECK:STDOUT: 1: ; preds = %0 // CHECK:STDOUT: %B = call i1 @B() -// CHECK:STDOUT: %temp1 = alloca i1, align 1 -// CHECK:STDOUT: store i1 %B, ptr %temp1, align 1 -// CHECK:STDOUT: %3 = load i1, ptr %temp1, align 1 -// CHECK:STDOUT: br i1 %3, label %4, label %5 +// CHECK:STDOUT: br i1 %B, label %2, label %3 // CHECK:STDOUT: -// CHECK:STDOUT: 4: ; preds = %2 +// CHECK:STDOUT: 2: ; preds = %1 // CHECK:STDOUT: br label %0 // CHECK:STDOUT: -// CHECK:STDOUT: 5: ; preds = %2 +// CHECK:STDOUT: 3: ; preds = %1 // CHECK:STDOUT: %C = call i1 @C() -// CHECK:STDOUT: %temp2 = alloca i1, align 1 -// CHECK:STDOUT: store i1 %C, ptr %temp2, align 1 -// CHECK:STDOUT: %6 = load i1, ptr %temp2, align 1 -// CHECK:STDOUT: br i1 %6, label %7, label %8 +// CHECK:STDOUT: br i1 %C, label %4, label %5 // CHECK:STDOUT: -// CHECK:STDOUT: 7: ; preds = %5 -// CHECK:STDOUT: br label %9 +// CHECK:STDOUT: 4: ; preds = %3 +// CHECK:STDOUT: br label %6 // CHECK:STDOUT: -// CHECK:STDOUT: 8: ; preds = %5 +// CHECK:STDOUT: 5: ; preds = %3 // CHECK:STDOUT: br label %0 // CHECK:STDOUT: -// CHECK:STDOUT: 9: ; preds = %7, %0 +// CHECK:STDOUT: 6: ; preds = %4, %0 // CHECK:STDOUT: ret void // CHECK:STDOUT: // CHECK:STDOUT: ; uselistorder directives diff --git a/toolchain/lower/testdata/while/preheader.carbon b/toolchain/lower/testdata/while/preheader.carbon index 22dceb127c65..9bf43324ddfc 100644 --- a/toolchain/lower/testdata/while/preheader.carbon +++ b/toolchain/lower/testdata/while/preheader.carbon @@ -37,39 +37,30 @@ fn While() { // CHECK:STDOUT: entry: // CHECK:STDOUT: br label %0 // CHECK:STDOUT: -// CHECK:STDOUT: 0: ; preds = %entry, %2 +// CHECK:STDOUT: 0: ; preds = %entry, %1 // CHECK:STDOUT: %Cond = call i1 @Cond() -// CHECK:STDOUT: %temp = alloca i1, align 1 -// CHECK:STDOUT: store i1 %Cond, ptr %temp, align 1 -// CHECK:STDOUT: %1 = load i1, ptr %temp, align 1 -// CHECK:STDOUT: br i1 %1, label %2, label %3 +// CHECK:STDOUT: br i1 %Cond, label %1, label %2 // CHECK:STDOUT: -// CHECK:STDOUT: 2: ; preds = %0 +// CHECK:STDOUT: 1: ; preds = %0 // CHECK:STDOUT: call void @F() // CHECK:STDOUT: br label %0 // CHECK:STDOUT: -// CHECK:STDOUT: 3: ; preds = %0 +// CHECK:STDOUT: 2: ; preds = %0 // CHECK:STDOUT: %Cond1 = call i1 @Cond() -// CHECK:STDOUT: %temp2 = alloca i1, align 1 -// CHECK:STDOUT: store i1 %Cond1, ptr %temp2, align 1 -// CHECK:STDOUT: %4 = load i1, ptr %temp2, align 1 -// CHECK:STDOUT: br i1 %4, label %5, label %9 +// CHECK:STDOUT: br i1 %Cond1, label %3, label %6 // CHECK:STDOUT: -// CHECK:STDOUT: 5: ; preds = %7, %3 -// CHECK:STDOUT: %Cond3 = call i1 @Cond() -// CHECK:STDOUT: %temp4 = alloca i1, align 1 -// CHECK:STDOUT: store i1 %Cond3, ptr %temp4, align 1 -// CHECK:STDOUT: %6 = load i1, ptr %temp4, align 1 -// CHECK:STDOUT: br i1 %6, label %7, label %8 +// CHECK:STDOUT: 3: ; preds = %4, %2 +// CHECK:STDOUT: %Cond2 = call i1 @Cond() +// CHECK:STDOUT: br i1 %Cond2, label %4, label %5 // CHECK:STDOUT: -// CHECK:STDOUT: 7: ; preds = %5 +// CHECK:STDOUT: 4: ; preds = %3 // CHECK:STDOUT: call void @G() -// CHECK:STDOUT: br label %5 +// CHECK:STDOUT: br label %3 // CHECK:STDOUT: -// CHECK:STDOUT: 8: ; preds = %5 -// CHECK:STDOUT: br label %9 +// CHECK:STDOUT: 5: ; preds = %3 +// CHECK:STDOUT: br label %6 // CHECK:STDOUT: -// CHECK:STDOUT: 9: ; preds = %8, %3 +// CHECK:STDOUT: 6: ; preds = %5, %2 // CHECK:STDOUT: ret void // CHECK:STDOUT: // CHECK:STDOUT: ; uselistorder directives diff --git a/toolchain/lower/testdata/while/unreachable_end.carbon b/toolchain/lower/testdata/while/unreachable_end.carbon index ef710601c6a5..8f8ded4aeac9 100644 --- a/toolchain/lower/testdata/while/unreachable_end.carbon +++ b/toolchain/lower/testdata/while/unreachable_end.carbon @@ -36,16 +36,13 @@ fn While() { // CHECK:STDOUT: // CHECK:STDOUT: 1: ; preds = %0 // CHECK:STDOUT: %Cond = call i1 @Cond() -// CHECK:STDOUT: %temp = alloca i1, align 1 -// CHECK:STDOUT: store i1 %Cond, ptr %temp, align 1 -// CHECK:STDOUT: %2 = load i1, ptr %temp, align 1 -// CHECK:STDOUT: br i1 %2, label %3, label %4 +// CHECK:STDOUT: br i1 %Cond, label %2, label %3 // CHECK:STDOUT: -// CHECK:STDOUT: 3: ; preds = %1 +// CHECK:STDOUT: 2: ; preds = %1 // CHECK:STDOUT: call void @G() // CHECK:STDOUT: ret void // CHECK:STDOUT: -// CHECK:STDOUT: 4: ; preds = %1 +// CHECK:STDOUT: 3: ; preds = %1 // CHECK:STDOUT: call void @H() // CHECK:STDOUT: ret void // CHECK:STDOUT: } diff --git a/toolchain/lower/testdata/while/while.carbon b/toolchain/lower/testdata/while/while.carbon index 64a173bb72e3..021b493f6736 100644 --- a/toolchain/lower/testdata/while/while.carbon +++ b/toolchain/lower/testdata/while/while.carbon @@ -33,18 +33,15 @@ fn While() { // CHECK:STDOUT: call void @F() // CHECK:STDOUT: br label %1 // CHECK:STDOUT: -// CHECK:STDOUT: 1: ; preds = %3, %0 +// CHECK:STDOUT: 1: ; preds = %2, %0 // CHECK:STDOUT: %Cond = call i1 @Cond() -// CHECK:STDOUT: %temp = alloca i1, align 1 -// CHECK:STDOUT: store i1 %Cond, ptr %temp, align 1 -// CHECK:STDOUT: %2 = load i1, ptr %temp, align 1 -// CHECK:STDOUT: br i1 %2, label %3, label %4 +// CHECK:STDOUT: br i1 %Cond, label %2, label %3 // CHECK:STDOUT: -// CHECK:STDOUT: 3: ; preds = %1 +// CHECK:STDOUT: 2: ; preds = %1 // CHECK:STDOUT: call void @G() // CHECK:STDOUT: br label %1 // CHECK:STDOUT: -// CHECK:STDOUT: 4: ; preds = %1 +// CHECK:STDOUT: 3: ; preds = %1 // CHECK:STDOUT: call void @H() // CHECK:STDOUT: ret void // CHECK:STDOUT: } diff --git a/toolchain/sem_ir/file.cpp b/toolchain/sem_ir/file.cpp index 091235ff45e5..a2ec88416275 100644 --- a/toolchain/sem_ir/file.cpp +++ b/toolchain/sem_ir/file.cpp @@ -226,6 +226,7 @@ static auto GetTypePrecedence(NodeKind kind) -> int { case TupleValue::Kind: case UnaryOperatorNot::Kind: case ValueAsReference::Kind: + case ValueOfInitializer::Kind: case VarStorage::Kind: CARBON_FATAL() << "GetTypePrecedence for non-type node kind " << kind; } @@ -426,6 +427,7 @@ auto File::StringifyTypeExpression(NodeId outer_node_id, case TupleValue::Kind: case UnaryOperatorNot::Kind: case ValueAsReference::Kind: + case ValueOfInitializer::Kind: case VarStorage::Kind: // We don't need to handle stringification for nodes that don't show up // in errors, but make it clear what's going on so that it's clearer @@ -508,6 +510,7 @@ auto GetExpressionCategory(const File& file, NodeId node_id) case TupleType::Kind: case UnaryOperatorNot::Kind: case UnboundFieldType::Kind: + case ValueOfInitializer::Kind: return value_category; case Builtin::Kind: { diff --git a/toolchain/sem_ir/file.h b/toolchain/sem_ir/file.h index 08ab1f9927d1..dd26f9550659 100644 --- a/toolchain/sem_ir/file.h +++ b/toolchain/sem_ir/file.h @@ -404,8 +404,8 @@ struct InitializingRepresentation { // The type has no initializing representation. This is used for empty // types, where no initialization is necessary. None, - // An initializing expression produces a value, which is copied into the - // initialized object. + // An initializing expression produces an object representation by value, + // which is copied into the initialized object. ByCopy, // An initializing expression takes a location as input, which is // initialized as a side effect of evaluating the expression. diff --git a/toolchain/sem_ir/node_kind.def b/toolchain/sem_ir/node_kind.def index 26f1440db797..d3547d745dc3 100644 --- a/toolchain/sem_ir/node_kind.def +++ b/toolchain/sem_ir/node_kind.def @@ -71,6 +71,7 @@ CARBON_SEM_IR_NODE_KIND(TupleValue) CARBON_SEM_IR_NODE_KIND(UnaryOperatorNot) CARBON_SEM_IR_NODE_KIND(UnboundFieldType) CARBON_SEM_IR_NODE_KIND(ValueAsReference) +CARBON_SEM_IR_NODE_KIND(ValueOfInitializer) CARBON_SEM_IR_NODE_KIND(VarStorage) #undef CARBON_SEM_IR_NODE_KIND diff --git a/toolchain/sem_ir/typed_nodes.h b/toolchain/sem_ir/typed_nodes.h index 47dc46e44750..ff3e0fb2f13e 100644 --- a/toolchain/sem_ir/typed_nodes.h +++ b/toolchain/sem_ir/typed_nodes.h @@ -541,6 +541,15 @@ struct ValueAsReference { NodeId value_id; }; +struct ValueOfInitializer { + static constexpr auto Kind = + NodeKind::ValueOfInitializer.Define("value_of_initializer"); + + Parse::Node parse_node; + TypeId type_id; + NodeId init_id; +}; + struct VarStorage { static constexpr auto Kind = NodeKind::VarStorage.Define("var");