From 10190da440cd1c85c62c3d537f83893802deaff6 Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Mon, 21 May 2018 15:53:01 -0700 Subject: Handle structure initializers in IR type legalization (#567) Fixes #566 The basic problem here is that the front-end translates a structure initializer-list expression into a `makeStruct` instruction (with one argument per field), but the IR type legalization logic wasn't handling the case where a `makeStruct` is used to construct a struct value that needs to get split by legalization. The implementation is relatively straightforward, and like the other cases of instruction legalization for compound types, it follows the shape of the `LegalType`/`LegalVal` cases. The one interesting bit is that we need to be a bit careful and filter the single argument list for `makeStruct` into two in the case where we generate a "pair" type for something that has both "ordinary" and "special" (resource) fields. Luckily the `PairInfo` data that was generated by type legalization has exactly the information we need (by design). This change does not address several issues that could be handled in follow-on changes: * The `makeArray` instruction will face similar issues if it is applied to a type that requires legalization: we'd need to turn an array of `LegalVal`s into a bunch of distinct arrays. * The error message when we hit the unimplemented case here isn't great. Ideally we should provide the line number of the instruction that fails in an error message when legalization fails. This change tries to focus narrowly on the bug at hand, and leave these issues for later changes. --- source/slang/ir-legalize-types.cpp | 123 +++++++++++++++++++++++++++++++++++++ source/slang/legalize-types.h | 6 +- 2 files changed, 126 insertions(+), 3 deletions(-) (limited to 'source') diff --git a/source/slang/ir-legalize-types.cpp b/source/slang/ir-legalize-types.cpp index 05b8ca647..969e3eb96 100644 --- a/source/slang/ir-legalize-types.cpp +++ b/source/slang/ir-legalize-types.cpp @@ -669,6 +669,122 @@ static LegalVal legalizeGetElementPtr( indexOperand); } +static LegalVal legalizeMakeStruct( + IRTypeLegalizationContext* context, + LegalType legalType, + LegalVal const* legalArgs, + UInt argCount) +{ + auto builder = context->builder; + + switch(legalType.flavor) + { + case LegalType::Flavor::simple: + { + List args; + for(UInt aa = 0; aa < argCount; ++aa) + { + // Note: we assume that all the arguments + // must be simple here, because otherwise + // the `struct` type with them as fields + // would not be simple... + // + args.Add(legalArgs[aa].getSimple()); + } + return LegalVal::simple( + builder->emitMakeStruct( + legalType.getSimple(), + argCount, + args.Buffer())); + } + + case LegalType::Flavor::pair: + { + // There are two sides, the ordinary and the special, + // and we basically just dispatch to both of them. + auto pairType = legalType.getPair(); + auto pairInfo = pairType->pairInfo; + LegalType ordinaryType = pairType->ordinaryType; + LegalType specialType = pairType->specialType; + + List ordinaryArgs; + List specialArgs; + UInt argCounter = 0; + for(auto ee : pairInfo->elements) + { + UInt argIndex = argCounter++; + LegalVal arg = legalArgs[argIndex]; + + if((ee.flags & Slang::PairInfo::kFlag_hasOrdinaryAndSpecial) == Slang::PairInfo::kFlag_hasOrdinaryAndSpecial) + { + // The field is itself a pair type, so we expect + // the argument value to be one too... + auto argPair = arg.getPair(); + ordinaryArgs.Add(argPair->ordinaryVal); + specialArgs.Add(argPair->specialVal); + } + else if(ee.flags & Slang::PairInfo::kFlag_hasOrdinary) + { + ordinaryArgs.Add(arg); + } + else if(ee.flags & Slang::PairInfo::kFlag_hasSpecial) + { + specialArgs.Add(arg); + } + } + + LegalVal ordinaryVal = legalizeMakeStruct( + context, + ordinaryType, + ordinaryArgs.Buffer(), + ordinaryArgs.Count()); + + LegalVal specialVal = legalizeMakeStruct( + context, + specialType, + specialArgs.Buffer(), + specialArgs.Count()); + + return LegalVal::pair(ordinaryVal, specialVal, pairInfo); + } + break; + + case LegalType::Flavor::tuple: + { + // We are constructing a tuple of values from + // the individual fields. We need to identify + // for each tuple element what field it uses, + // and then extract that field's value. + + auto tupleType = legalType.getTuple(); + + RefPtr resTupleInfo = new TuplePseudoVal(); + UInt argCounter = 0; + for(auto typeElem : tupleType->elements) + { + auto elemKey = typeElem.key; + UInt argIndex = argCounter++; + SLANG_ASSERT(argIndex < argCount); + + LegalVal argVal = legalArgs[argIndex]; + + TuplePseudoVal::Element resElem; + resElem.key = elemKey; + resElem.val = argVal; + + resTupleInfo->elements.Add(resElem); + } + return LegalVal::tuple(resTupleInfo); + } + + default: + SLANG_UNEXPECTED("unhandled"); + UNREACHABLE_RETURN(LegalVal()); + } +} + + + static LegalVal legalizeInst( IRTypeLegalizationContext* context, IRInst* inst, @@ -695,6 +811,13 @@ static LegalVal legalizeInst( case kIROp_Call: return legalizeCall(context, (IRCall*)inst); + case kIROp_makeStruct: + return legalizeMakeStruct( + context, + type, + args, + inst->getOperandCount()); + default: // TODO: produce a user-visible diagnostic here SLANG_UNEXPECTED("non-simple operand(s)!"); diff --git a/source/slang/legalize-types.h b/source/slang/legalize-types.h index c4cafe157..014df123f 100644 --- a/source/slang/legalize-types.h +++ b/source/slang/legalize-types.h @@ -290,7 +290,7 @@ struct LegalVal return result; } - IRInst* getSimple() + IRInst* getSimple() const { SLANG_ASSERT(flavor == Flavor::simple); return irValue; @@ -298,7 +298,7 @@ struct LegalVal static LegalVal tuple(RefPtr tupleVal); - RefPtr getTuple() + RefPtr getTuple() const { SLANG_ASSERT(flavor == Flavor::tuple); return obj.As(); @@ -313,7 +313,7 @@ struct LegalVal LegalVal const& specialVal, RefPtr pairInfo); - RefPtr getPair() + RefPtr getPair() const { SLANG_ASSERT(flavor == Flavor::pair); return obj.As(); -- cgit v1.2.3