@@ -2124,6 +2124,82 @@ std::vector<Operand> GetExtractOperandsForElementOfCompositeConstruct(
21242124 return {};
21252125}
21262126
2127+ // If the OpCompositeConstruct that feeds an OpCopyLogical can be retyped to
2128+ // the OpCopyLogical's result type, the layout conversion can be expressed at
2129+ // constituent granularity instead of at aggregate granularity. This rewrites
2130+ // the OpCopyLogical as an OpCompositeConstruct of the result type, using the
2131+ // same constituents where their types already match the corresponding
2132+ // field/element of the result type, and inserting per-field OpCopyLogical
2133+ // instructions only for the fields that genuinely require a layout
2134+ // conversion.
2135+ bool CompositeConstructFeedingCopyLogical (
2136+ IRContext* context, Instruction* inst,
2137+ const std::vector<const analysis::Constant*>&) {
2138+ assert (inst->opcode () == spv::Op::OpCopyLogical &&
2139+ " Wrong opcode. Should be OpCopyLogical." );
2140+ analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr ();
2141+
2142+ uint32_t src_id = inst->GetSingleWordInOperand (0 );
2143+ Instruction* src_inst = def_use_mgr->GetDef (src_id);
2144+ if (src_inst->opcode () != spv::Op::OpCompositeConstruct) {
2145+ return false ;
2146+ }
2147+
2148+ Instruction* dst_type_inst = def_use_mgr->GetDef (inst->type_id ());
2149+ const uint32_t num_constituents = src_inst->NumInOperands ();
2150+
2151+ // Determine the expected type id for each constituent of the destination
2152+ // type.
2153+ std::vector<uint32_t > expected_type_ids;
2154+ expected_type_ids.reserve (num_constituents);
2155+ if (dst_type_inst->opcode () == spv::Op::OpTypeStruct) {
2156+ if (dst_type_inst->NumInOperands () != num_constituents) {
2157+ return false ;
2158+ }
2159+ for (uint32_t i = 0 ; i < num_constituents; ++i) {
2160+ expected_type_ids.push_back (dst_type_inst->GetSingleWordInOperand (i));
2161+ }
2162+ } else if (dst_type_inst->opcode () == spv::Op::OpTypeArray) {
2163+ const uint32_t elem_type_id = dst_type_inst->GetSingleWordInOperand (0 );
2164+ for (uint32_t i = 0 ; i < num_constituents; ++i) {
2165+ expected_type_ids.push_back (elem_type_id);
2166+ }
2167+ } else {
2168+ return false ;
2169+ }
2170+
2171+ // Build the new constituent list, inserting OpCopyLogical instructions for
2172+ // the fields whose types differ from the result type.
2173+ InstructionBuilder ir_builder (
2174+ context, inst,
2175+ IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping );
2176+ std::vector<Operand> operands;
2177+ operands.reserve (num_constituents);
2178+ for (uint32_t i = 0 ; i < num_constituents; ++i) {
2179+ const uint32_t cid = src_inst->GetSingleWordInOperand (i);
2180+ Instruction* cdef = def_use_mgr->GetDef (cid);
2181+ if (cdef->type_id () == expected_type_ids[i]) {
2182+ operands.push_back ({SPV_OPERAND_TYPE_ID , {cid}});
2183+ continue ;
2184+ }
2185+ assert (def_use_mgr->GetDef (expected_type_ids[i])->opcode () !=
2186+ spv::Op::OpTypePointer &&
2187+ " OpCopyLogical result type must not contain a pointer-typed "
2188+ " field." );
2189+ Instruction* per_field_copy = ir_builder.AddUnaryOp (
2190+ expected_type_ids[i], spv::Op::OpCopyLogical, cid);
2191+ if (per_field_copy == nullptr ) {
2192+ return false ;
2193+ }
2194+ operands.push_back ({SPV_OPERAND_TYPE_ID , {per_field_copy->result_id ()}});
2195+ }
2196+
2197+ inst->SetOpcode (spv::Op::OpCompositeConstruct);
2198+ inst->SetInOperands (std::move (operands));
2199+ context->UpdateDefUse (inst);
2200+ return true ;
2201+ }
2202+
21272203bool CompositeConstructFeedingExtract (
21282204 IRContext* context, Instruction* inst,
21292205 const std::vector<const analysis::Constant*>&) {
@@ -4476,6 +4552,9 @@ void FoldingRules::AddFoldingRules() {
44764552 rules_[spv::Op::OpCompositeConstruct].push_back (
44774553 CompositeExtractFeedingConstruct);
44784554
4555+ rules_[spv::Op::OpCopyLogical].push_back (
4556+ CompositeConstructFeedingCopyLogical);
4557+
44794558 rules_[spv::Op::OpCompositeExtract].push_back (InsertFeedingExtract ());
44804559 rules_[spv::Op::OpCompositeExtract].push_back (
44814560 CompositeConstructFeedingExtract);
0 commit comments