summaryrefslogtreecommitdiffstats
path: root/source/slang
diff options
context:
space:
mode:
authorTim Foley <tfoley@nvidia.com>2017-11-07 09:25:41 -0800
committerTim Foley <tfoley@nvidia.com>2017-11-07 10:48:17 -0800
commit5c220292d6ac2674942bb5f1bb09fe1817151c11 (patch)
tree0fceae3a5ca7799d839bdc9a4c17bb0840e75588 /source/slang
parent93a444fe1b5f1e3c6da67db4d948df53a0bdb3f6 (diff)
Fixes for name mangling/demangling
The source of a lot of these changes is that our current strategy for dealing with "builtin" operations when emitting HLSL from the IR is to de-mangle the mangled name of an operation, and then emit HLSL code for a function call to an operation with that de-mangled name. This change introduces a few fixups for that work: - It adds support for parsing the mangled names of generics (specialized and unspecialized) - It adds logic for detecting when the operation being invoked is a member function - This is currently a bit ugly, since we compare the number of actual arguments we have in the IR against the number of parameters declared for the callee, and if they don't match we assume we have an extra `this` argument. On the mangling side, we add (hacky) support for mangling a function name when its types involve generic parameters, e.g.: ``` __generic<T, let N : int> T length(vector<T,N> v); ``` In this case the mangled name of the function needs to include a mangling for the type `vector<T,N>` which means it also needs to include a mangling for `N`. The reason I describe this support as "hacky" is because we really shouldn't be reproducing the names `T` or `N` in the mangled symbol name. By doing so we make it so that a user changing the name of a generic parameter would break (IR) binary compatibility with existing code that was separately compiled. I've included comments in the code about a better way to handle this, but it isn't a priorit right now since binary compatibility isn't something meaningful until we start emitting usable bytecode modules.
Diffstat (limited to 'source/slang')
-rw-r--r--source/slang/emit.cpp144
-rw-r--r--source/slang/mangle.cpp12
2 files changed, 147 insertions, 9 deletions
diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp
index d95946204..7e4fca4e5 100644
--- a/source/slang/emit.cpp
+++ b/source/slang/emit.cpp
@@ -4677,7 +4677,7 @@ emitDeclImpl(decl, nullptr);
if(c == '0')
return 0;
- int count = 0;
+ UInt count = 0;
for(;;)
{
count = count*10 + c - '0';
@@ -4689,18 +4689,117 @@ emitDeclImpl(decl, nullptr);
}
}
+ void readGenericParam()
+ {
+ switch(peek())
+ {
+ case 'T':
+ get();
+ break;
+
+ default:
+ SLANG_UNEXPECTED("bad name mangling");
+ break;
+ }
+ }
+
+ void readGenericParams()
+ {
+ expect("g");
+ UInt paramCount = readCount();
+ for(UInt pp = 0; pp < paramCount; pp++)
+ {
+ readGenericParam();
+ }
+ }
+
+ void readSimpleIntVal()
+ {
+ int c = peek();
+ if(isDigit(c))
+ {
+ get();
+ }
+ else
+ {
+ readVal();
+ }
+ }
+
+ void readType()
+ {
+ int c = peek();
+ switch(c)
+ {
+ case 'V':
+ case 'b':
+ case 'i':
+ case 'u':
+ case 'U':
+ case 'h':
+ case 'f':
+ case 'd':
+ get();
+ break;
+
+ case 'v':
+ get();
+ readSimpleIntVal();
+ readType();
+ break;
+
+ default:
+ // TODO: need to read a named type
+ // here...
+ break;
+ }
+ }
+
+ void readVal()
+ {
+ // TODO: handle other cases here
+ readType();
+ }
+
+ void readGenericArg()
+ {
+ readVal();
+ }
+
+ void readGenericArgs()
+ {
+ expect("G");
+ UInt argCount = readCount();
+ for(UInt aa = 0; aa < argCount; aa++)
+ {
+ readGenericArg();
+ }
+ }
+
UnownedStringSlice readSimpleName()
{
UnownedStringSlice result;
for(;;)
{
int c = peek();
+
+ if(c == 'g')
+ {
+ readGenericParams();
+ continue;
+ }
+ else if(c == 'G')
+ {
+ readGenericArgs();
+ continue;
+ }
+
if(!isDigit((char)c))
return result;
// Read the length part
- int count = readCount();
- if(count > (end_ - cursor_))
+ UInt count = readCount();
+ if(count > UInt(end_ - cursor_))
{
SLANG_UNEXPECTED("bad name mangling");
UNREACHABLE_RETURN(result);
@@ -4710,6 +4809,12 @@ emitDeclImpl(decl, nullptr);
cursor_ += count;
}
}
+
+ UInt readParamCount()
+ {
+ expect("p");
+ return readCount();
+ }
};
void emitIntrinsicCallExpr(
@@ -4726,16 +4831,37 @@ emitDeclImpl(decl, nullptr);
auto name = um.readSimpleName();
- // TODO: need to detect if name represents
- // a member function, etc.
+ // The mangled function name currently records
+ // the number of explicit parameters, and thus
+ // doesn't include the implicit `this` parameter.
+ // We can compare the argument and parameter counts
+ // to figure out whether we have a member function call.
+ UInt paramCount = um.readParamCount();
+
+ // For a call with N arguments, the instruction will
+ // have N+1 operands.
+ UInt operandCount = inst->getArgCount();
+ UInt argCount = operandCount - 1;
+ UInt operandIndex = 1;
+
+ if(argCount != paramCount)
+ {
+ // Looks like a member function call
+ emit("(");
+ emitIROperand(ctx, inst->getArg(operandIndex));
+ emit(").");
+
+ operandIndex++;
+ }
emit(name);
emit("(");
- UInt argCount = inst->getArgCount();
- for( UInt aa = 1; aa < argCount; ++aa )
+ bool first = true;
+ for(; operandIndex < operandCount; ++operandIndex )
{
- if(aa != 1) emit(", ");
- emitIROperand(ctx, inst->getArg(aa));
+ if(!first) emit(", ");
+ emitIROperand(ctx, inst->getArg(operandIndex));
+ first = false;
}
emit(")");
}
diff --git a/source/slang/mangle.cpp b/source/slang/mangle.cpp
index b9fba6380..dca48f671 100644
--- a/source/slang/mangle.cpp
+++ b/source/slang/mangle.cpp
@@ -152,6 +152,18 @@ namespace Slang
// value, so we certainly don't want to include
// it in the mangling.
}
+ else if( auto genericParamIntVal = dynamic_cast<GenericParamIntVal*>(val) )
+ {
+ // TODO: we shouldn't be including the names of generic parameters
+ // anywhere in mangled names, since changing parameter names
+ // shouldn't break binary compatibility.
+ //
+ // The right solution in the long term is for generic parameters
+ // (both types and values) to be mangled in terms of their
+ // "depth" (how many outer generics) and "index" (which
+ // parameter are they at the specified depth).
+ emitName(context, genericParamIntVal->declRef.GetName());
+ }
else
{
SLANG_UNEXPECTED("unimplemented case in mangling");