From 5c220292d6ac2674942bb5f1bb09fe1817151c11 Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Tue, 7 Nov 2017 09:25:41 -0800 Subject: 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 length(vector v); ``` In this case the mangled name of the function needs to include a mangling for the type `vector` 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. --- source/slang/emit.cpp | 144 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 135 insertions(+), 9 deletions(-) (limited to 'source/slang/emit.cpp') 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(")"); } -- cgit v1.2.3