void RunCompressedSplitFloatTest() { TRandom random(0); ui32 size = 115322; auto vec = TMirrorBuffer<float>::Create(NCudaLib::TMirrorMapping(size)); TVector<float> ref; float border = 0.3; TVector<ui32> refBits; for (ui32 i = 0; i < size; ++i) { ref.push_back(random.NextUniform()); refBits.push_back(ref.back() > border); } vec.Write(ref); auto compressedBits = TMirrorBuffer<ui64>::Create(NCudaLib::TMirrorMapping(CompressedSize<ui64>(size, 2))); auto decompressedBits = TMirrorBuffer<ui32>::Create(NCudaLib::TMirrorMapping(size)); CreateCompressedSplitFloat(vec, border, compressedBits); Decompress(compressedBits, decompressedBits, 2); TVector<ui32> bins; decompressedBits.Read(bins); for (ui32 i = 0; i < size; ++i) { UNIT_ASSERT_EQUAL(bins[i], refBits[i]); } }
// Recursively assigns indices to a sub DAG InitResult assignIndicesInternal(CreatorFunctionData *root) { // Iterative implementation of the index assignment algorithm. A recursive version // would be prettier but since the CallDAG creation runs before the limiting of the // call depth, we might get stack overflows (computation of the call depth uses the // CallDAG). ASSERT(root); if (root->indexAssigned) { return INITDAG_SUCCESS; } // If we didn't have to detect recursion, functionsToProcess could be a simple queue // in which we add the function being processed's callees. However in order to detect // recursion we need to know which functions we are currently visiting. For that reason // functionsToProcess will look like a concatenation of segments of the form // [F visiting = true, subset of F callees with visiting = false] and the following // segment (if any) will be start with a callee of F. // This way we can remember when we started visiting a function, to put visiting back // to false. TVector<CreatorFunctionData *> functionsToProcess; functionsToProcess.push_back(root); InitResult result = INITDAG_SUCCESS; std::stringstream errorStream; while (!functionsToProcess.empty()) { CreatorFunctionData *function = functionsToProcess.back(); if (function->visiting) { function->visiting = false; function->index = mCurrentIndex++; function->indexAssigned = true; functionsToProcess.pop_back(); continue; } if (!function->node) { errorStream << "Undefined function '" << function->name << ")' used in the following call chain:"; result = INITDAG_UNDEFINED; break; } if (function->indexAssigned) { functionsToProcess.pop_back(); continue; } function->visiting = true; for (auto callee : function->callees) { functionsToProcess.push_back(callee); // Check if the callee is already being visited after pushing it so that it appears // in the chain printed in the info log. if (callee->visiting) { errorStream << "Recursive function call in the following call chain:"; result = INITDAG_RECURSION; break; } } if (result != INITDAG_SUCCESS) { break; } } // The call chain is made of the function we were visiting when the error was detected. if (result != INITDAG_SUCCESS) { bool first = true; for (auto function : functionsToProcess) { if (function->visiting) { if (!first) { errorStream << " -> "; } errorStream << function->name << ")"; first = false; } } if (mDiagnostics) { std::string errorStr = errorStream.str(); mDiagnostics->globalError(errorStr.c_str()); } } return result; }
// // Check a token to see if it is a macro that should be expanded: // - If it is, and defined, push a tInput that will produce the appropriate // expansion and return MacroExpandStarted. // - If it is, but undefined, and expandUndef is requested, push a tInput // that will expand to 0 and return MacroExpandUndef. // - Otherwise, there is no expansion, and there are two cases: // * It might be okay there is no expansion, and no specific error was // detected. Returns MacroExpandNotStarted. // * The expansion was started, but could not be completed, due to an error // that cannot be recovered from. Returns MacroExpandError. // MacroExpandResult TPpContext::MacroExpand(TPpToken* ppToken, bool expandUndef, bool newLineOkay) { ppToken->space = false; int macroAtom = atomStrings.getAtom(ppToken->name); switch (macroAtom) { case PpAtomLineMacro: ppToken->ival = parseContext.getCurrentLoc().line; snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival); UngetToken(PpAtomConstInt, ppToken); return MacroExpandStarted; case PpAtomFileMacro: { if (parseContext.getCurrentLoc().name) parseContext.ppRequireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_cpp_style_line_directive, "filename-based __FILE__"); ppToken->ival = parseContext.getCurrentLoc().string; snprintf(ppToken->name, sizeof(ppToken->name), "%s", ppToken->loc.getStringNameOrNum().c_str()); UngetToken(PpAtomConstInt, ppToken); return MacroExpandStarted; } case PpAtomVersionMacro: ppToken->ival = parseContext.version; snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival); UngetToken(PpAtomConstInt, ppToken); return MacroExpandStarted; default: break; } MacroSymbol* macro = macroAtom == 0 ? nullptr : lookupMacroDef(macroAtom); // no recursive expansions if (macro != nullptr && macro->busy) return MacroExpandNotStarted; // not expanding undefined macros if ((macro == nullptr || macro->undef) && ! expandUndef) return MacroExpandNotStarted; // 0 is the value of an undefined macro if ((macro == nullptr || macro->undef) && expandUndef) { pushInput(new tZeroInput(this)); return MacroExpandUndef; } tMacroInput *in = new tMacroInput(this); TSourceLoc loc = ppToken->loc; // in case we go to the next line before discovering the error in->mac = macro; if (macro->functionLike) { // We don't know yet if this will be a successful call of a // function-like macro; need to look for a '(', but without trashing // the passed in ppToken, until we know we are no longer speculative. TPpToken parenToken; int token = scanToken(&parenToken); if (newLineOkay) { while (token == '\n') token = scanToken(&parenToken); } if (token != '(') { // Function-like macro called with object-like syntax: okay, don't expand. // (We ate exactly one token that might not be white space; put it back. UngetToken(token, &parenToken); delete in; return MacroExpandNotStarted; } in->args.resize(in->mac->args.size()); for (size_t i = 0; i < in->mac->args.size(); i++) in->args[i] = new TokenStream; in->expandedArgs.resize(in->mac->args.size()); for (size_t i = 0; i < in->mac->args.size(); i++) in->expandedArgs[i] = nullptr; size_t arg = 0; bool tokenRecorded = false; do { TVector<char> nestStack; while (true) { token = scanToken(ppToken); if (token == EndOfInput || token == tMarkerInput::marker) { parseContext.ppError(loc, "End of input in macro", "macro expansion", atomStrings.getString(macroAtom)); delete in; return MacroExpandError; } if (token == '\n') { if (! newLineOkay) { parseContext.ppError(loc, "End of line in macro substitution:", "macro expansion", atomStrings.getString(macroAtom)); delete in; return MacroExpandError; } continue; } if (token == '#') { parseContext.ppError(ppToken->loc, "unexpected '#'", "macro expansion", atomStrings.getString(macroAtom)); delete in; return MacroExpandError; } if (in->mac->args.size() == 0 && token != ')') break; if (nestStack.size() == 0 && (token == ',' || token == ')')) break; if (token == '(') nestStack.push_back(')'); else if (token == '{' && parseContext.isReadingHLSL()) nestStack.push_back('}'); else if (nestStack.size() > 0 && token == nestStack.back()) nestStack.pop_back(); in->args[arg]->putToken(token, ppToken); tokenRecorded = true; } // end of single argument scan if (token == ')') { // closing paren of call if (in->mac->args.size() == 1 && !tokenRecorded) break; arg++; break; } arg++; } while (arg < in->mac->args.size()); // end of all arguments scan if (arg < in->mac->args.size()) parseContext.ppError(loc, "Too few args in Macro", "macro expansion", atomStrings.getString(macroAtom)); else if (token != ')') { // Error recover code; find end of call, if possible int depth = 0; while (token != EndOfInput && (depth > 0 || token != ')')) { if (token == ')' || token == '}') depth--; token = scanToken(ppToken); if (token == '(' || token == '{') depth++; } if (token == EndOfInput) { parseContext.ppError(loc, "End of input in macro", "macro expansion", atomStrings.getString(macroAtom)); delete in; return MacroExpandError; } parseContext.ppError(loc, "Too many args in macro", "macro expansion", atomStrings.getString(macroAtom)); } // We need both expanded and non-expanded forms of the argument, for whether or // not token pasting will be applied later when the argument is consumed next to ##. for (size_t i = 0; i < in->mac->args.size(); i++) in->expandedArgs[i] = PrescanMacroArg(*in->args[i], ppToken, newLineOkay); } pushInput(in); macro->busy = 1; macro->body.reset(); return MacroExpandStarted; }