diff options
| -rw-r--r-- | source/slang/lower-to-ir.cpp | 137 |
1 files changed, 99 insertions, 38 deletions
diff --git a/source/slang/lower-to-ir.cpp b/source/slang/lower-to-ir.cpp index 761fe9c91..27325ee38 100644 --- a/source/slang/lower-to-ir.cpp +++ b/source/slang/lower-to-ir.cpp @@ -2948,39 +2948,32 @@ void lowerStmt( } } -static LoweredValInfo maybeMoveMutableTemp( +/// Create and return a mutable temporary initialized with `val` +static LoweredValInfo moveIntoMutableTemp( IRGenContext* context, LoweredValInfo const& val) { - switch(val.flavor) - { - case LoweredValInfo::Flavor::Ptr: - return val; + IRInst* irVal = getSimpleVal(context, val); + auto type = irVal->getDataType(); + auto var = createVar(context, type); - default: - { - IRInst* irVal = getSimpleVal(context, val); - auto type = irVal->getDataType(); - auto var = createVar(context, type); - - assign(context, var, LoweredValInfo::simple(irVal)); - return var; - } - break; - } + assign(context, var, LoweredValInfo::simple(irVal)); + return var; } -IRInst* getAddress( +/// Try to coerce `inVal` into a `LoweredValInfo::ptr()` with a simple address. +LoweredValInfo tryGetAddress( IRGenContext* context, - LoweredValInfo const& inVal, - SourceLoc diagnosticLocation) + LoweredValInfo const& inVal) { LoweredValInfo val = inVal; switch(val.flavor) { case LoweredValInfo::Flavor::Ptr: - return val.val; + // The `Ptr` case means that we already have an IR value with + // the address of our value. Easy! + return val; case LoweredValInfo::Flavor::BoundSubscript: { @@ -3005,13 +2998,60 @@ IRInst* getAddress( // The result from the call should be a pointer, and it // is the address that we wanted in the first place. - return getSimpleVal(context, refVal); + return LoweredValInfo::ptr(getSimpleVal(context, refVal)); } // Otherwise, there was no `ref` accessor, and so it is not possible // to materialize this location into a pointer for whatever purpose // we have in mind (e.g., passing it to an atomic operation). } + break; + + case LoweredValInfo::Flavor::BoundMember: + { + auto boundMemberInfo = val.getBoundMemberInfo(); + + // If we hit this case, then it means that we have a reference + // to a single field in something, but for whatever reason the + // higher-level logic was not able to turn it into a pointer + // already (maybe the base value for the field reference is + // a `BoundSubscript`, etc.). + // + // We need to read the entire base value out, modify the field + // we care about, and then write it back. + + auto declRef = boundMemberInfo->declRef; + if( auto fieldDeclRef = declRef.As<StructField>() ) + { + auto baseVal = boundMemberInfo->base; + auto basePtr = tryGetAddress(context, baseVal); + + return extractField(context, boundMemberInfo->type, basePtr, fieldDeclRef); + } + + } + break; + + case LoweredValInfo::Flavor::SwizzledLValue: + { + auto originalSwizzleInfo = val.getSwizzledLValueInfo(); + auto originalBase = originalSwizzleInfo->base; + + UInt elementCount = originalSwizzleInfo->elementCount; + + auto newBase = tryGetAddress(context, originalBase); + RefPtr<SwizzledLValueInfo> newSwizzleInfo = new SwizzledLValueInfo(); + context->shared->extValues.Add(newSwizzleInfo); + + newSwizzleInfo->base = newBase; + newSwizzleInfo->type = originalSwizzleInfo->type; + newSwizzleInfo->elementCount = elementCount; + for(UInt ee = 0; ee < elementCount; ++ee) + newSwizzleInfo->elementIndices[ee] = originalSwizzleInfo->elementIndices[ee]; + + return LoweredValInfo::swizzledLValue(newSwizzleInfo); + } + break; // TODO: are there other cases we need to handled here? @@ -3019,6 +3059,23 @@ IRInst* getAddress( break; } + // If none of the special cases above applied, then we werent' able to make + // this value into a pointer, and we should just return it as-is. + return val; +} + +IRInst* getAddress( + IRGenContext* context, + LoweredValInfo const& inVal, + SourceLoc diagnosticLocation) +{ + LoweredValInfo val = tryGetAddress(context, inVal); + + if( val.flavor == LoweredValInfo::Flavor::Ptr ) + { + return val.val; + } + context->getSink()->diagnose(diagnosticLocation, Diagnostics::invalidLValueForRefParameter); return nullptr; } @@ -3031,29 +3088,26 @@ void assign( LoweredValInfo left = inLeft; LoweredValInfo right = inRight; + // Before doing the case analysis on the shape of the `left` value, + // we might as well go ahead and see if we can coerce it into + // a simple pointer, since that would make our life a lot easier + // when handling complex cases. + // + left = tryGetAddress(context, left); + auto builder = context->irBuilder; top: switch (left.flavor) { case LoweredValInfo::Flavor::Ptr: - switch (right.flavor) { - case LoweredValInfo::Flavor::Simple: - case LoweredValInfo::Flavor::Ptr: - case LoweredValInfo::Flavor::SwizzledLValue: - case LoweredValInfo::Flavor::BoundSubscript: - case LoweredValInfo::Flavor::BoundMember: - { - builder->emitStore( - left.val, - getSimpleVal(context, right)); - } - break; - - default: - SLANG_UNIMPLEMENTED_X("assignment"); - break; + // The `left` value is just a pointer, so we can emit + // a store to it directly. + // + builder->emitStore( + left.val, + getSimpleVal(context, right)); } break; @@ -3064,6 +3118,11 @@ top: auto swizzleInfo = left.getSwizzledLValueInfo(); auto loweredBase = swizzleInfo->base; + // Note that the call to `tryGetAddress` at the start should + // ensure that `loweredBase` has been simplified as much as + // possible (e.g., if it is possible to turn it into a + // `LoweredValInfo::ptr()` then that will have been done). + switch( loweredBase.flavor ) { default: @@ -3209,7 +3268,7 @@ top: // materialize the base value and move it into // a mutable temporary if needed auto baseVal = boundMemberInfo->base; - auto tempVal = maybeMoveMutableTemp(context, materialize(context, baseVal)); + auto tempVal = moveIntoMutableTemp(context, baseVal); // extract the field l-value out of the temporary auto tempFieldVal = extractField(context, boundMemberInfo->type, tempVal, fieldDeclRef); @@ -3219,6 +3278,8 @@ top: // write back the modified temporary to the base l-value assign(context, baseVal, tempVal); + + return; } else { |
