diff options
| author | Tim Foley <tfoleyNV@users.noreply.github.com> | 2017-10-18 11:08:47 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-10-18 11:08:47 -0700 |
| commit | a12480fe49d5ba7c0a9c2ac63363dc76b599ddbd (patch) | |
| tree | 6344dec2a432f2f5cb1cdd981d0aafe21ea6a443 /source/slang/mangle.cpp | |
| parent | f12c2552b3f494cbc8245edb90b32b93ca8a1539 (diff) | |
Work on IR-based cross-compilation (#222)
There are two big changes here:
- Add logic during the initial IR cloning pass for an entry point + target that tries to pick the best possible version of any target-overloaded function. This allows us to pick the intrinsic version of `saturate()` when compiling for HLSL output, but then pick the non-intrinsic version (that is implemented in terms of `clamp()`) when targetting GLSL.
- Add an initial specialization pass that tries to deal with generics. This required some fixing work to IR generation, so that we correctly generate explicit operations to specialize a generic for specific types (this is currently implemented as a `specialize` instruction that takes the generic to specialize plus a declaration-reference that represents the specialized form). With that work in place, we can scan for `specialize` instructions inside of non-generic functions, and use them to trigger generation of specialized code. We rely on the name-mangling scheme to help us find pre-existing specializations when possible.
There are also a bunch of cleanups encountered along the way:
- Don't use the explicit `layout(offset=...)` for uniforms, because it isn't supported by all current drivers. For now we will just assume that our layout rules compute the same values that the driver would for un-marked-up code. We can come back later and try to implement a workaround in the cases where this doesn't apply (e.g., by re-running the layout logic as part of emission, and dropping layout modifiers from variables that don't need explicit layout).
- Fix some issues in IR dump printing so that we print function declarations more nicely.
- Testing: print out failing pixel when image-diff fails
Diffstat (limited to 'source/slang/mangle.cpp')
| -rw-r--r-- | source/slang/mangle.cpp | 231 |
1 files changed, 180 insertions, 51 deletions
diff --git a/source/slang/mangle.cpp b/source/slang/mangle.cpp index ce36a97b6..71c0605a9 100644 --- a/source/slang/mangle.cpp +++ b/source/slang/mangle.cpp @@ -44,75 +44,193 @@ namespace Slang context->sb.append(str); } + void emitVal( + ManglingContext* context, + Val* val); + + void emitQualifiedName( + ManglingContext* context, + DeclRef<Decl> declRef); + + void emitSimpleIntVal( + ManglingContext* context, + Val* val) + { + if( auto constVal = dynamic_cast<ConstantIntVal*>(val) ) + { + auto val = constVal->value; + if( val >= 0 && val <= 9 ) + { + emit(context, (UInt) val); + return; + } + } + + // Fallback: + emitVal(context, val); + } + void emitType( ManglingContext* context, Type* type) { // TODO: actually implement this bit... + + if( auto basicType = dynamic_cast<BasicExpressionType*>(type) ) + { + switch( basicType->baseType ) + { + case BaseType::Void: emitRaw(context, "V"); break; + case BaseType::Bool: emitRaw(context, "b"); break; + case BaseType::Int: emitRaw(context, "i"); break; + case BaseType::UInt: emitRaw(context, "u"); break; + case BaseType::UInt64: emitRaw(context, "U"); break; + case BaseType::Half: emitRaw(context, "h"); break; + case BaseType::Float: emitRaw(context, "f"); break; + case BaseType::Double: emitRaw(context, "d"); break; + break; + + default: + SLANG_UNEXPECTED("unimplemented case in mangling"); + break; + } + } + else if( auto vecType = dynamic_cast<VectorExpressionType*>(type) ) + { + emitRaw(context, "v"); + emitSimpleIntVal(context, vecType->elementCount); + emitType(context, vecType->elementType); + } + else if( auto matType = dynamic_cast<MatrixExpressionType*>(type) ) + { + emitRaw(context, "m"); + emitSimpleIntVal(context, matType->getRowCount()); + emitRaw(context, "x"); + emitSimpleIntVal(context, matType->getColumnCount()); + emitType(context, matType->getElementType()); + } + else if( auto namedType = dynamic_cast<NamedExpressionType*>(type) ) + { + emitType(context, GetType(namedType->declRef)); + } + else if( auto declRefType = dynamic_cast<DeclRefType*>(type) ) + { + emitQualifiedName(context, declRefType->declRef); + } + else + { + SLANG_UNEXPECTED("unimplemented case in mangling"); + } + } + + void emitVal( + ManglingContext* context, + Val* val) + { + if( auto type = dynamic_cast<Type*>(val) ) + { + emitType(context, type); + } + else + { + SLANG_UNEXPECTED("unimplemented case in mangling"); + } } void emitQualifiedName( ManglingContext* context, - Decl* decl) + DeclRef<Decl> declRef) { - auto parentDecl = decl->ParentDecl; - if( parentDecl ) + auto parentDeclRef = declRef.GetParent(); + auto parentGenericDeclRef = parentDeclRef.As<GenericDecl>(); + if( parentDeclRef ) { - emitQualifiedName(context, parentDecl); + // In certain cases we want to skip emitting the parent + if(parentGenericDeclRef && (parentGenericDeclRef.getDecl()->inner.Ptr() != declRef.getDecl())) + { + } + else if(parentDeclRef.As<FunctionDeclBase>()) + { + } + else + { + emitQualifiedName(context, parentDeclRef); + } } // A generic declaration is kind of a pseudo-declaration // as far as the user is concerned; so we don't want // to emit its name. - if( auto genericDecl = dynamic_cast<GenericDecl*>(decl) ) + if(auto genericDeclRef = declRef.As<GenericDecl>()) { return; } - emitName(context, decl->nameAndLoc.name); + emitName(context, declRef.GetName()); - if( auto parentGenericDecl = dynamic_cast<GenericDecl*>(parentDecl)) + // Are we the "inner" declaration beneath a generic decl? + if(parentGenericDeclRef && (parentGenericDeclRef.getDecl()->inner.Ptr() == declRef.getDecl())) { - emitRaw(context, "g"); - UInt genericParameterCount = 0; - for( auto mm : parentGenericDecl->Members ) + // There are two cases here: either we have specializations + // in place for the parent generic declaration, or we don't. + + auto subst = declRef.substitutions; + if( subst && subst->genericDecl == parentGenericDeclRef.getDecl() ) { - if(mm.As<GenericTypeParamDecl>()) - { - genericParameterCount++; - } - else if(mm.As<GenericValueParamDecl>()) - { - genericParameterCount++; - } - else if(mm.As<GenericTypeConstraintDecl>()) - { - genericParameterCount++; - } - else + // This is the case where we *do* have substitutions. + emitRaw(context, "G"); + UInt genericArgCount = subst->args.Count(); + emit(context, genericArgCount); + for( auto aa : subst->args ) { + emitVal(context, aa); } } - - emit(context, genericParameterCount); - for( auto mm : parentGenericDecl->Members ) + else { - if(auto genericTypeParamDecl = mm.As<GenericTypeParamDecl>()) + // We don't have substitutions, so we will emit + // information about the parameters of the generic here. + emitRaw(context, "g"); + UInt genericParameterCount = 0; + for( auto mm : getMembers(parentGenericDeclRef) ) { - emitRaw(context, "T"); + if(mm.As<GenericTypeParamDecl>()) + { + genericParameterCount++; + } + else if(mm.As<GenericValueParamDecl>()) + { + genericParameterCount++; + } + else if(mm.As<GenericTypeConstraintDecl>()) + { + genericParameterCount++; + } + else + { + } } - else if(auto genericValueParamDecl = mm.As<GenericValueParamDecl>()) - { - emitRaw(context, "v"); - emitType(context, genericValueParamDecl->getType()); - } - else if(mm.As<GenericTypeConstraintDecl>()) - { - emitRaw(context, "C"); - // TODO: actually emit info about the constraint - } - else + + emit(context, genericParameterCount); + for( auto mm : getMembers(parentGenericDeclRef) ) { + if(auto genericTypeParamDecl = mm.As<GenericTypeParamDecl>()) + { + emitRaw(context, "T"); + } + else if(auto genericValueParamDecl = mm.As<GenericValueParamDecl>()) + { + emitRaw(context, "v"); + emitType(context, GetType(genericValueParamDecl)); + } + else if(mm.As<GenericTypeConstraintDecl>()) + { + emitRaw(context, "C"); + // TODO: actually emit info about the constraint + } + else + { + } } } } @@ -124,23 +242,25 @@ namespace Slang // We'll also go ahead and emit the result type as well, // just for completeness. // - if( auto callableDecl = dynamic_cast<CallableDecl*>(decl) ) + if( auto callableDeclRef = declRef.As<CallableDecl>()) { emitRaw(context, "p"); - UInt parameterCount = callableDecl->GetParameters().Count(); + + auto parameters = GetParameters(callableDeclRef); + UInt parameterCount = parameters.Count(); emit(context, parameterCount); - for(auto pp : callableDecl->GetParameters()) + for(auto paramDeclRef : parameters) { - emitType(context, pp->getType()); + emitType(context, GetType(paramDeclRef)); } - emitType(context, callableDecl->ReturnType); + emitType(context, GetResultType(callableDeclRef)); } } void mangleName( ManglingContext* context, - Decl* decl) + DeclRef<Decl> declRef) { // TODO: catch cases where the declaration should // forward to something else? E.g., what if we @@ -150,6 +270,8 @@ namespace Slang // clashes with user-defined symbols: emitRaw(context, "_S"); + auto decl = declRef.getDecl(); + // Next we will add a bit of info to register // the *kind* of declaration we are dealing with. // @@ -174,17 +296,24 @@ namespace Slang } // Now we encode the qualified name of the decl. - emitQualifiedName(context, decl); + emitQualifiedName(context, declRef); } - - - String getMangledName(Decl* decl) + String getMangledName(DeclRef<Decl> const& declRef) { ManglingContext context; + mangleName(&context, declRef); + return context.sb.ProduceString(); + } - mangleName(&context, decl); + String getMangledName(DeclRefBase const & declRef) + { + return getMangledName( + DeclRef<Decl>(declRef.decl, declRef.substitutions)); + } - return context.sb.ProduceString(); + String getMangledName(Decl* decl) + { + return getMangledName(makeDeclRef(decl)); } } |
