diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/slang/slang-ast-modifier.h | 12 | ||||
| -rw-r--r-- | source/slang/slang-check-conversion.cpp | 2 | ||||
| -rw-r--r-- | source/slang/slang-check-decl.cpp | 187 | ||||
| -rw-r--r-- | source/slang/slang-check-impl.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-diagnostic-defs.h | 4 | ||||
| -rw-r--r-- | source/slang/slang-ir-autodiff.cpp | 36 | ||||
| -rw-r--r-- | source/slang/slang-ir-autodiff.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-ir-bit-field-accessors.cpp | 160 | ||||
| -rw-r--r-- | source/slang/slang-ir-bit-field-accessors.h | 7 | ||||
| -rw-r--r-- | source/slang/slang-ir-inst-defs.h | 6 | ||||
| -rw-r--r-- | source/slang/slang-ir-insts.h | 8 | ||||
| -rw-r--r-- | source/slang/slang-ir.cpp | 39 | ||||
| -rw-r--r-- | source/slang/slang-ir.h | 7 | ||||
| -rw-r--r-- | source/slang/slang-lower-to-ir.cpp | 25 | ||||
| -rw-r--r-- | source/slang/slang-parser.cpp | 9 |
15 files changed, 471 insertions, 35 deletions
diff --git a/source/slang/slang-ast-modifier.h b/source/slang/slang-ast-modifier.h index 155363e0c..c5d18f4f8 100644 --- a/source/slang/slang-ast-modifier.h +++ b/source/slang/slang-ast-modifier.h @@ -1479,4 +1479,16 @@ class GLSLPatchModifier : public SimpleModifier SLANG_AST_CLASS(GLSLPatchModifier) }; +// +class BitFieldModifier : public Modifier +{ + SLANG_ABSTRACT_AST_CLASS(BitFieldModifier) + + IntegerLiteralValue width; + + // Fields filled during semantic analysis + IntegerLiteralValue offset = 0; + DeclRef<VarDecl> backingDeclRef; +}; + } // namespace Slang diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index d76b2a80e..9dae07018 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -645,7 +645,7 @@ namespace Slang } } - static int getTypeBitSize(Type* t) + int getTypeBitSize(Type* t) { auto basicType = as<BasicExpressionType>(t); if (!basicType) return 0; diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 5a9559ce6..4dfffc414 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -1,4 +1,6 @@ // slang-check-decl.cpp +#include "slang-ast-modifier.h" +#include "slang-ast-support-types.h" #include "slang-check-impl.h" // This file constaints the semantic checking logic and @@ -34,6 +36,8 @@ namespace Slang { checkModifiers(decl); } + + void visitStructDecl(StructDecl* structDecl); }; struct SemanticsDeclScopeWiringVisitor : public SemanticsDeclVisitorBase, public DeclVisitor<SemanticsDeclScopeWiringVisitor> @@ -64,6 +68,8 @@ namespace Slang void visitDecl(Decl*) {} void visitDeclGroup(DeclGroup*) {} + void visitStructDecl(StructDecl* structDecl); + void visitFunctionDeclBase(FunctionDeclBase* decl); void checkForwardDerivativeOfAttribute(FunctionDeclBase* funcDecl, ForwardDerivativeOfAttribute* attr); @@ -1375,6 +1381,47 @@ namespace Slang tryConstantFoldDeclRef(DeclRef<VarDeclBase>(varDecl), nullptr); } + void SemanticsDeclModifiersVisitor::visitStructDecl(StructDecl* structDecl) + { + checkModifiers(structDecl); + + // Replace any bitfield member with a property, do this here before + // name lookup to avoid the original var decl being referenced + for(auto& m : structDecl->members) + { + const auto bfm = m->findModifier<BitFieldModifier>(); + if(!bfm) + continue; + + auto property = m_astBuilder->create<PropertyDecl>(); + property->modifiers = m->modifiers; + property->type = as<VarDecl>(m)->type; + property->loc = m->loc; + property->nameAndLoc = m->getNameAndLoc(); + property->parentDecl = structDecl; + property->ownedScope = m_astBuilder->create<Scope>(); + property->ownedScope->containerDecl = property; + property->ownedScope->parent = getScope(structDecl); + m = property; + + const auto get = m_astBuilder->create<GetterDecl>(); + get->ownedScope = m_astBuilder->create<Scope>(); + get->ownedScope->containerDecl = get; + get->ownedScope->parent = getScope(property); + property->addMember(get); + + const auto set = m_astBuilder->create<SetterDecl>(); + addModifier(set, m_astBuilder->create<MutatingAttribute>()); + set->ownedScope = m_astBuilder->create<Scope>(); + set->ownedScope->containerDecl = set; + set->ownedScope->parent = getScope(property); + property->addMember(set); + + structDecl->invalidateMemberDictionary(); + } + structDecl->buildMemberDictionary(); + } + void SemanticsDeclHeaderVisitor::checkDerivativeMemberAttribute( VarDeclBase* varDecl, DerivativeMemberAttribute* derivativeMemberAttr) { @@ -8943,6 +8990,146 @@ namespace Slang this, funcDecl, attr, DeclAssociationKind::PrimalSubstituteFunc); } + void SemanticsDeclAttributesVisitor::visitStructDecl(StructDecl* structDecl) + { + int backingWidth = 0; + [[maybe_unused]] + int totalWidth = 0; + struct BitFieldInfo + { + int memberIndex; + int bitWidth; + Type* memberType; + BitFieldModifier* bitFieldModifier; + }; + List<BitFieldInfo> groupInfo; + + int memberIndex = 0; + int backing_nonce = 0; + const auto dispatchSomeBitPackedMembers = [&](){ + SLANG_ASSERT(totalWidth <= backingWidth); + SLANG_ASSERT(backingWidth <= 64); + + // We're going to insert a backing member to be referenced in + // all the bitfield properties + if(groupInfo.getCount()) + { + const auto backingMemberBasicType + = backingWidth <= 8 ? BaseType::UInt8 + : backingWidth <= 16 ? BaseType::UInt16 + : backingWidth <= 32 ? BaseType::UInt + : BaseType::UInt64; + auto backingMember = m_astBuilder->create<VarDecl>(); + backingMember->type.type = m_astBuilder->getBuiltinType(backingMemberBasicType); + backingMember->nameAndLoc.name = getName(String("$bit_field_backing_") + String(backing_nonce)); + backing_nonce++; + backingMember->initExpr = nullptr; + backingMember->parentDecl = structDecl; + const auto backingMemberDeclRef = DeclRef<VarDecl>(backingMember->getDefaultDeclRef()); + + int bottomOfMember = 0; + for(const auto m : groupInfo) + { + SLANG_ASSERT(bottomOfMember <= backingWidth); + + m.bitFieldModifier->backingDeclRef = backingMemberDeclRef; + m.bitFieldModifier->offset = bottomOfMember; + + bottomOfMember += m.bitWidth; + } + + const auto backingMemberIndex = groupInfo[0].memberIndex; + structDecl->members.insert(backingMemberIndex, backingMember); + structDecl->invalidateMemberDictionary(); + ++memberIndex; + } + structDecl->buildMemberDictionary(); + + // Reset everything + backingWidth = 0; + totalWidth = 0; + groupInfo.clear(); + }; + for(; memberIndex < structDecl->members.getCount(); ++memberIndex) + { + const auto& m = structDecl->members[memberIndex]; + + // We can trivially skip any non-property decls + const auto v = as<PropertyDecl>(m); + if(!v) + { + // If this is a non-bitfield member then finish the current group + if(as<VarDecl>(m)) + dispatchSomeBitPackedMembers(); + continue; + } + + const auto bfm = m->findModifier<BitFieldModifier>(); + // If there isn't a bit field modifier, then dispatch the + // current group and continue + if(!bfm) + { + dispatchSomeBitPackedMembers(); + continue; + } + + // Verify that this makes sense as a bitfield + const auto t = v->type.type->getCanonicalType(); + SLANG_ASSERT(t); + const auto b = as<BasicExpressionType>(t); + if(!b) + { + getSink()->diagnose(v->loc, Diagnostics::bitFieldNonIntegral, t); + continue; + } + const auto baseType = b->getBaseType(); + const bool isIntegerType = isIntegerBaseType(baseType); + if(!isIntegerType) + { + getSink()->diagnose(v->loc, Diagnostics::bitFieldNonIntegral, t); + continue; + } + + // The bit width of this member, and the member type width + const auto thisFieldWidth = bfm->width; + const auto thisFieldTypeWidth = getTypeBitSize(b); + SLANG_ASSERT(thisFieldTypeWidth != 0); + if(thisFieldWidth > thisFieldTypeWidth) + { + getSink()->diagnose( + v->loc, + Diagnostics::bitFieldTooWide, + thisFieldWidth, + t, + thisFieldTypeWidth + ); + // Not much we can do with this field, just ignore it + continue; + } + + // At this point we're sure that we have a bit field, + // update our bit packing state + + // If there's a 0 width type, dispatch the current group + if(thisFieldWidth == 0) + dispatchSomeBitPackedMembers(); + + // If this member wouldn't fit into the current group, dispatch + // everything so far; + if(totalWidth + thisFieldWidth > std::max(thisFieldTypeWidth, backingWidth)) + dispatchSomeBitPackedMembers(); + + // Add this member to the group, + // Grow the backing width if necessary + backingWidth = std::max(thisFieldTypeWidth, backingWidth); + // Grow the total width + totalWidth += int(thisFieldWidth); + groupInfo.add({memberIndex, int(thisFieldWidth), t, bfm}); + } + // If the struct ended with a bitpacked member, then make sure we don't forget the last group + dispatchSomeBitPackedMembers(); + } + void SemanticsDeclAttributesVisitor::visitFunctionDeclBase(FunctionDeclBase* decl) { // Run checking on attributes that can't be fully checked in header checking stage. diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index d91bbb75b..eb3f9486c 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -41,6 +41,8 @@ namespace Slang return result; } + int getTypeBitSize(Type* t); + // A flat representation of basic types (scalars, vectors and matrices) // that can be used as lookup key in caches struct BasicTypeKey diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index d638f7be6..037e441d4 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -518,6 +518,10 @@ DIAGNOSTIC(31101, Error, nonSetAccessorMustNotHaveParams, "accessors other than DIAGNOSTIC(31102, Error, setAccessorMayNotHaveMoreThanOneParam, "a 'set' accessor may not have more than one parameter") DIAGNOSTIC(31102, Error, setAccessorParamWrongType, "'set' parameter '$0' has type '$1' which does not match the expected type '$2'") +// 313xx: bit fields +DIAGNOSTIC(31300, Error, bitFieldTooWide, "bit-field size ($0) exceeds the width of its type $1 ($2)") +DIAGNOSTIC(31301, Error, bitFieldNonIntegral, "bit-field type ($0) must be an integral type") + // 39999 waiting to be placed in the right range DIAGNOSTIC(39999, Error, expectedIntegerConstantWrongType, "expected integer constant (found: '$0')") diff --git a/source/slang/slang-ir-autodiff.cpp b/source/slang/slang-ir-autodiff.cpp index 2cc4e3b57..14b53c0e0 100644 --- a/source/slang/slang-ir-autodiff.cpp +++ b/source/slang/slang-ir-autodiff.cpp @@ -96,32 +96,6 @@ IRInst* lookupForwardDerivativeReference(IRInst* primalFunction) return nullptr; } -IRStructField* DifferentialPairTypeBuilder::findField(IRInst* type, IRStructKey* key) -{ - if (auto irStructType = as<IRStructType>(type)) - { - for (auto field : irStructType->getFields()) - { - if (field->getKey() == key) - { - return field; - } - } - } - else if (auto irSpecialize = as<IRSpecialize>(type)) - { - if (auto irGeneric = as<IRGeneric>(irSpecialize->getBase())) - { - if (auto irGenericStructType = as<IRStructType>(findInnerMostGenericReturnVal(irGeneric))) - { - return findField(irGenericStructType, key); - } - } - } - - return nullptr; -} - IRInst* DifferentialPairTypeBuilder::findSpecializationForParam(IRInst* specializeInst, IRInst* genericParam) { // Get base generic that's being specialized. @@ -162,7 +136,7 @@ IRInst* DifferentialPairTypeBuilder::emitFieldAccessor(IRBuilder* builder, IRIns if (auto basePairStructType = as<IRStructType>(pairType)) { return as<IRFieldExtract>(builder->emitFieldExtract( - findField(basePairStructType, key)->getFieldType(), + findStructField(basePairStructType, key)->getFieldType(), baseInst, key )); @@ -178,7 +152,7 @@ IRInst* DifferentialPairTypeBuilder::emitFieldAccessor(IRBuilder* builder, IRIns builder->getPtrType((IRType*) findSpecializationForParam( ptrInnerSpecializedType, - findField(ptrInnerSpecializedType, key)->getFieldType())), + findStructField(ptrInnerSpecializedType, key)->getFieldType())), baseInst, key )); @@ -188,7 +162,7 @@ IRInst* DifferentialPairTypeBuilder::emitFieldAccessor(IRBuilder* builder, IRIns { return as<IRFieldAddress>(builder->emitFieldAddress( builder->getPtrType((IRType*) - findField(ptrBaseStructType, key)->getFieldType()), + findStructField(ptrBaseStructType, key)->getFieldType()), baseInst, key)); } @@ -204,7 +178,7 @@ IRInst* DifferentialPairTypeBuilder::emitFieldAccessor(IRBuilder* builder, IRIns return as<IRFieldExtract>(builder->emitFieldExtract( (IRType*)findSpecializationForParam( specializedType, - findField(genericBasePairStructType, key)->getFieldType()), + findStructField(genericBasePairStructType, key)->getFieldType()), baseInst, key )); @@ -217,7 +191,7 @@ IRInst* DifferentialPairTypeBuilder::emitFieldAccessor(IRBuilder* builder, IRIns builder->getPtrType((IRType*) findSpecializationForParam( specializedType, - findField(genericPairStructType, key)->getFieldType())), + findStructField(genericPairStructType, key)->getFieldType())), baseInst, key )); diff --git a/source/slang/slang-ir-autodiff.h b/source/slang/slang-ir-autodiff.h index 811002091..d8f0373ac 100644 --- a/source/slang/slang-ir-autodiff.h +++ b/source/slang/slang-ir-autodiff.h @@ -308,8 +308,6 @@ struct DifferentialPairTypeBuilder DifferentialPairTypeBuilder(AutoDiffSharedContext* sharedContext) : sharedContext(sharedContext) {} - IRStructField* findField(IRInst* type, IRStructKey* key); - IRInst* findSpecializationForParam(IRInst* specializeInst, IRInst* genericParam); IRInst* emitFieldAccessor(IRBuilder* builder, IRInst* baseInst, IRStructKey* key); diff --git a/source/slang/slang-ir-bit-field-accessors.cpp b/source/slang/slang-ir-bit-field-accessors.cpp new file mode 100644 index 000000000..3ca660a30 --- /dev/null +++ b/source/slang/slang-ir-bit-field-accessors.cpp @@ -0,0 +1,160 @@ +#include "slang-ir-bit-field-accessors.h" + +#include "slang-ir.h" +#include "slang-ir-insts.h" + +namespace Slang +{ +static IRInst* maybeUnwrapGeneric(IRInst* inst) +{ + if(const auto g = as<IRGeneric>(inst)) + return findInnerMostGenericReturnVal(g); + return inst; +} + +static IRInst* maybeUnwrapSpecialize(IRInst* inst) +{ + if(const auto g = as<IRSpecialize>(inst)) + return maybeUnwrapGeneric(maybeUnwrapSpecialize(g->getBase())); + return inst; +} + +static IRInst* shl(IRBuilder& builder, IRInst* inst, const IRIntegerValue value) +{ + if(value == 0) + return inst; + const auto [width, isSigned] = getIntTypeInfo(inst->getDataType()); + if(value >= width) + return builder.getIntValue(inst->getDataType(), 0); + if(value == 0) + return inst; + return builder.emitShl(inst->getDataType(), inst, builder.getIntValue(builder.getIntType(), value)); +} + +static IRInst* shr(IRBuilder& builder, IRInst* inst, const IRIntegerValue value) +{ + if(value == 0) + return inst; + const auto [width, isSigned] = getIntTypeInfo(inst->getDataType()); + // If it's not signed, then we just shift all the set bits away + if(value >= width && !isSigned) + return builder.getIntValue(inst->getDataType(), 0); + // Since on many platforms bit shifting by the number of bits in the number + // is undefined, correct this here assuming that the Slang IR has the same + // restriction + if(value >= width && isSigned) + return builder.emitShr(inst->getDataType(), inst, builder.getIntValue(builder.getIntType(), width-1)); + if(value == 0) + return inst; + return builder.emitShr(inst->getDataType(), inst, builder.getIntValue(builder.getIntType(), value)); +} + +static void synthesizeBitFieldGetter(IRFunc* func, IRBitFieldAccessorDecoration* dec) +{ + const auto bitFieldType = func->getResultType(); + SLANG_ASSERT(isIntegralType(bitFieldType)); + SLANG_ASSERT(func->getParamCount() == 1); + const auto structParamType = func->getParamType(0); + const auto structType = as<IRStructType>(maybeUnwrapSpecialize(structParamType)); + SLANG_ASSERT(structType); + + const auto backingMember = findStructField(structType, dec->getBackingMemberKey()); + const auto backingType = backingMember->getFieldType(); + SLANG_ASSERT(isIntegralType(backingType)); + + IRBuilder builder{func}; + + const auto isSigned = getIntTypeInfo(func->getResultType()).isSigned; + builder.setInsertInto(func); + builder.emitBlock(); + const auto s = builder.emitParam(structParamType); + + // Construct the equivalent of this: + // Note the cast of the backing value in order to get the correct sign + // extension behaviour on the right shift + // return (int(_backing) << (backingWidth-topOfFoo)) >> (backingWidth-fooWidth); + + const auto backingWidth = getIntTypeInfo(backingType).width; + const auto fieldWidth = dec->getFieldWidth(); + const auto topOfField = dec->getFieldOffset() + fieldWidth; + const auto leftShiftAmount = backingWidth - topOfField; + const auto rightShiftAmount = backingWidth - fieldWidth; + const auto backingValue = builder.emitFieldExtract(backingType, s, dec->getBackingMemberKey()); + const auto castBackingType = builder.getType(getIntTypeOpFromInfo({backingWidth, isSigned})); + const auto castedBacking = builder.emitCast(castBackingType, backingValue); + const auto leftShifted = shl(builder, castedBacking, leftShiftAmount); + const auto rightShifted = shr(builder, leftShifted, rightShiftAmount); + const auto castedToBitFieldType = builder.emitCast(bitFieldType, rightShifted); + builder.emitReturn(castedToBitFieldType); + + builder.addSimpleDecoration<IRForceInlineDecoration>(func); +} + +static IRIntegerValue setLowBits(IRIntegerValue bits) +{ + SLANG_ASSERT(bits >= 0 && bits <= 64); + return ~(bits >= 64 ? 0 : (~0 << bits)); +} + +static void synthesizeBitFieldSetter(IRFunc* func, IRBitFieldAccessorDecoration* dec) +{ + SLANG_ASSERT(func->getParamCount() == 2); + const auto ptrType = as<IRPtrTypeBase>(func->getParamType(0)); + SLANG_ASSERT(ptrType); + const auto structParamType = ptrType->getValueType(); + const auto structType = as<IRStructType>(maybeUnwrapSpecialize(structParamType)); + SLANG_ASSERT(structType); + const auto bitFieldType = func->getParamType(1); + SLANG_ASSERT(isIntegralType(bitFieldType)); + + const auto backingMember = findStructField(structType, dec->getBackingMemberKey()); + const auto backingType = backingMember->getFieldType(); + SLANG_ASSERT(isIntegralType(backingType)); + + IRBuilder builder{func}; + + builder.setInsertInto(func); + builder.emitBlock(); + const auto s = builder.emitParam(ptrType); + const auto v = builder.emitParam(bitFieldType); + + // Construct the equivalent of this: + // let fooMask = 0x00000FF0; + // let bottomOfFoo = 4; + // _backing = int((_backing & ~fooMask) | ((int(x) << bottomOfFoo) & fooMask)); + + const auto fieldWidth = dec->getFieldWidth(); + const auto bottomOfField = dec->getFieldOffset(); + const auto maskBits = setLowBits(fieldWidth) << bottomOfField; + const auto mask = builder.getIntValue(backingType, maskBits); + const auto notMask = builder.getIntValue(backingType, ~maskBits); + const auto memberAddr = builder.emitFieldAddress(builder.getPtrType(backingType), s, dec->getBackingMemberKey()); + const auto backingValue = builder.emitLoad(memberAddr); + const auto maskedOut = builder.emitBitAnd(backingType, backingValue, notMask); + const auto castValue = builder.emitCast(backingType, v); + const auto shiftedLeft = shl(builder, castValue, bottomOfField); + const auto maskedValue = builder.emitBitAnd(backingType, shiftedLeft, mask); + const auto combined = builder.emitBitOr(backingType, maskedOut, maskedValue); + builder.emitStore(memberAddr, combined); + builder.emitReturn(); + + builder.addSimpleDecoration<IRForceInlineDecoration>(func); +} + +void synthesizeBitFieldAccessors(IRModule* module) +{ + for(const auto inst : module->getModuleInst()->getGlobalInsts()) + { + const auto func = as<IRFunc>(maybeUnwrapGeneric(inst)); + if(!func) + continue; + const auto bfd = func->findDecoration<IRBitFieldAccessorDecoration>(); + if(!bfd) + continue; + if(func->getParamCount() == 1) + synthesizeBitFieldGetter(func, bfd); + else + synthesizeBitFieldSetter(func, bfd); + } +} +} diff --git a/source/slang/slang-ir-bit-field-accessors.h b/source/slang/slang-ir-bit-field-accessors.h new file mode 100644 index 000000000..f97eb8748 --- /dev/null +++ b/source/slang/slang-ir-bit-field-accessors.h @@ -0,0 +1,7 @@ +#pragma once + +namespace Slang +{ + struct IRModule; + void synthesizeBitFieldAccessors(IRModule* module); +} diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h index 5439a8d5b..656b3d320 100644 --- a/source/slang/slang-ir-inst-defs.h +++ b/source/slang/slang-ir-inst-defs.h @@ -970,7 +970,11 @@ INST(HighLevelDeclDecoration, highLevelDecl, 1, 0) /// Recognized by SPIRV-emit pass so we can emit a SPIRV `Block` decoration. INST(SPIRVBlockDecoration, spvBlock, 0, 0) - INST_RANGE(Decoration, HighLevelDeclDecoration, SPIRVBlockDecoration) + /// Marks a function as one which access a bitfield with the specified + /// backing value key, width and offset + INST(BitFieldAccessorDecoration, BitFieldAccessorDecoration, 3, 0) + + INST_RANGE(Decoration, HighLevelDeclDecoration, BitFieldAccessorDecoration) // diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h index 114250bae..620695d46 100644 --- a/source/slang/slang-ir-insts.h +++ b/source/slang/slang-ir-insts.h @@ -1240,6 +1240,14 @@ struct IRUnpackAnyValue : IRInst IRInst* getValue() { return getOperand(0); } }; +struct IRBitFieldAccessorDecoration : IRDecoration +{ + IR_LEAF_ISA(BitFieldAccessorDecoration); + IRStructKey* getBackingMemberKey() { return cast<IRStructKey>(getOperand(0)); } + IRIntegerValue getFieldWidth() { return as<IRIntLit>(getOperand(1))->getValue(); } + IRIntegerValue getFieldOffset() { return as<IRIntLit>(getOperand(2))->getValue(); } +}; + // Layout decorations /// A decoration that marks a field key as having been associated diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp index 3f10e3d3e..68b002153 100644 --- a/source/slang/slang-ir.cpp +++ b/source/slang/slang-ir.cpp @@ -7277,6 +7277,19 @@ namespace Slang } } + IROp getIntTypeOpFromInfo(const IntInfo info) + { + switch(info.width) + { + case 8: return info.isSigned ? kIROp_Int8Type : kIROp_UInt8Type; + case 16: return info.isSigned ? kIROp_Int16Type : kIROp_UInt16Type; + case 32: return info.isSigned ? kIROp_IntType : kIROp_UIntType; + case 64: return info.isSigned ? kIROp_Int64Type : kIROp_UInt64Type; + default: + SLANG_UNEXPECTED("Unhandled info passed to getIntTypeOpFromInfo"); + } + } + FloatInfo getFloatingTypeInfo(const IRType* floatType) { switch(floatType->getOp()) @@ -7303,6 +7316,32 @@ namespace Slang } } + IRStructField* findStructField(IRInst* type, IRStructKey* key) + { + if (auto irStructType = as<IRStructType>(type)) + { + for (auto field : irStructType->getFields()) + { + if (field->getKey() == key) + { + return field; + } + } + } + else if (auto irSpecialize = as<IRSpecialize>(type)) + { + if (auto irGeneric = as<IRGeneric>(irSpecialize->getBase())) + { + if (auto irGenericStructType = as<IRStructType>(findInnerMostGenericReturnVal(irGeneric))) + { + return findStructField(irGenericStructType, key); + } + } + } + + return nullptr; + } + void findAllInstsBreadthFirst(IRInst* inst, List<IRInst*>& outInsts) { Index index = outInsts.getCount(); diff --git a/source/slang/slang-ir.h b/source/slang/slang-ir.h index 3a459a501..f1c079cae 100644 --- a/source/slang/slang-ir.h +++ b/source/slang/slang-ir.h @@ -35,6 +35,8 @@ struct IRFunc; struct IRGlobalValueWithCode; struct IRInst; struct IRModule; +struct IRStructField; +struct IRStructKey; typedef unsigned int IROpFlags; enum : IROpFlags @@ -1036,6 +1038,9 @@ struct IntInfo IntInfo getIntTypeInfo(const IRType* intType); +// left-inverse of getIntTypeInfo +IROp getIntTypeOpFromInfo(const IntInfo info); + struct FloatInfo { Int width; @@ -1046,6 +1051,8 @@ FloatInfo getFloatingTypeInfo(const IRType* floatType); bool isIntegralScalarOrCompositeType(IRType* t); +IRStructField* findStructField(IRInst* type, IRStructKey* key); + void findAllInstsBreadthFirst(IRInst* inst, List<IRInst*>& outInsts); // Constant Instructions diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index cb9c8fc40..e4e324def 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -9,6 +9,7 @@ #include "../core/slang-performance-profiler.h" #include "slang-check.h" +#include "slang-ir-bit-field-accessors.h" #include "slang-ir-loop-inversion.h" #include "slang-ir.h" #include "slang-ir-constexpr.h" @@ -8872,6 +8873,25 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> } } + void addBitFieldAccessorDecorations(IRInst* irFunc, Decl* decl) + { + // If this is an accessor under a property we can move the bitfield + // modifiers on the property to the accessor function. + if(as<AccessorDecl>(decl) && as<PropertyDecl>(decl->parentDecl)) + { + if(const auto bfm = decl->parentDecl->findModifier<BitFieldModifier>()) + { + getBuilder()->addDecoration( + irFunc, + kIROp_BitFieldAccessorDecoration, + getSimpleVal(context, ensureDecl(context, bfm->backingDeclRef.getDecl())), + getBuilder()->getIntValue(getBuilder()->getIntType(), bfm->width), + getBuilder()->getIntValue(getBuilder()->getIntType(), bfm->offset) + ); + } + } + } + /// Is `decl` a member function (or effectively a member function) when considered as a stdlib declaration? bool isStdLibMemberFuncDecl( Decl* inDecl) @@ -9345,6 +9365,8 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> bool isInline = false; + addBitFieldAccessorDecorations(irFunc, decl); + for (auto modifier : decl->modifiers) { if (as<RequiresNVAPIAttribute>(modifier)) @@ -10360,6 +10382,9 @@ RefPtr<IRModule> generateIRForTranslationUnit( // normal `call` + `ifElse`, etc. lowerErrorHandling(module, compileRequest->getSink()); + // Synthesize some code we want to make sure is inlined and simplified + synthesizeBitFieldAccessors(module); + // Generate DebugValue insts to store values into debug variables, // if debug symbols are enabled. if (compileRequest->getLinkage()->m_optionSet.getEnumOption<DebugInfoLevel>(CompilerOptionName::DebugInformation) != DebugInfoLevel::None) diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp index 5555647f4..3f1ed3f76 100644 --- a/source/slang/slang-parser.cpp +++ b/source/slang/slang-parser.cpp @@ -2970,6 +2970,15 @@ namespace Slang semantic->name = parser->ReadToken(TokenType::Identifier); return semantic; } + else if (parser->LookAheadToken(TokenType::IntegerLiteral)) + { + BitFieldModifier* bitWidthMod = parser->astBuilder->create<BitFieldModifier>(); + parser->FillPosition(bitWidthMod); + const auto token = parser->tokenReader.advanceToken(); + UnownedStringSlice suffix; + bitWidthMod->width = getIntegerLiteralValue(token, &suffix); + return bitWidthMod; + } else if (parser->LookAheadToken(TokenType::CompletionRequest)) { HLSLSimpleSemantic* semantic = parser->astBuilder->create<HLSLSimpleSemantic>(); |
