1e95e94adSJeff Niu //===- TestFormatUtils.cpp - MLIR Test Dialect Assembly Format Utilities --===// 2e95e94adSJeff Niu // 3e95e94adSJeff Niu // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e95e94adSJeff Niu // See https://llvm.org/LICENSE.txt for license information. 5e95e94adSJeff Niu // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e95e94adSJeff Niu // 7e95e94adSJeff Niu //===----------------------------------------------------------------------===// 8e95e94adSJeff Niu 9e95e94adSJeff Niu #include "TestFormatUtils.h" 10e95e94adSJeff Niu #include "mlir/IR/Builders.h" 11e95e94adSJeff Niu 12e95e94adSJeff Niu using namespace mlir; 13e95e94adSJeff Niu using namespace test; 14e95e94adSJeff Niu 15e95e94adSJeff Niu //===----------------------------------------------------------------------===// 16e95e94adSJeff Niu // CustomDirectiveOperands 17e95e94adSJeff Niu //===----------------------------------------------------------------------===// 18e95e94adSJeff Niu 19e95e94adSJeff Niu ParseResult test::parseCustomDirectiveOperands( 20e95e94adSJeff Niu OpAsmParser &parser, OpAsmParser::UnresolvedOperand &operand, 21e95e94adSJeff Niu std::optional<OpAsmParser::UnresolvedOperand> &optOperand, 22e95e94adSJeff Niu SmallVectorImpl<OpAsmParser::UnresolvedOperand> &varOperands) { 23e95e94adSJeff Niu if (parser.parseOperand(operand)) 24e95e94adSJeff Niu return failure(); 25e95e94adSJeff Niu if (succeeded(parser.parseOptionalComma())) { 26e95e94adSJeff Niu optOperand.emplace(); 27e95e94adSJeff Niu if (parser.parseOperand(*optOperand)) 28e95e94adSJeff Niu return failure(); 29e95e94adSJeff Niu } 30e95e94adSJeff Niu if (parser.parseArrow() || parser.parseLParen() || 31e95e94adSJeff Niu parser.parseOperandList(varOperands) || parser.parseRParen()) 32e95e94adSJeff Niu return failure(); 33e95e94adSJeff Niu return success(); 34e95e94adSJeff Niu } 35e95e94adSJeff Niu 36e95e94adSJeff Niu void test::printCustomDirectiveOperands(OpAsmPrinter &printer, Operation *, 37e95e94adSJeff Niu Value operand, Value optOperand, 38e95e94adSJeff Niu OperandRange varOperands) { 39e95e94adSJeff Niu printer << operand; 40e95e94adSJeff Niu if (optOperand) 41e95e94adSJeff Niu printer << ", " << optOperand; 42e95e94adSJeff Niu printer << " -> (" << varOperands << ")"; 43e95e94adSJeff Niu } 44e95e94adSJeff Niu 45e95e94adSJeff Niu //===----------------------------------------------------------------------===// 46e95e94adSJeff Niu // CustomDirectiveResults 47e95e94adSJeff Niu //===----------------------------------------------------------------------===// 48e95e94adSJeff Niu 49e95e94adSJeff Niu ParseResult 50e95e94adSJeff Niu test::parseCustomDirectiveResults(OpAsmParser &parser, Type &operandType, 51e95e94adSJeff Niu Type &optOperandType, 52e95e94adSJeff Niu SmallVectorImpl<Type> &varOperandTypes) { 53e95e94adSJeff Niu if (parser.parseColon()) 54e95e94adSJeff Niu return failure(); 55e95e94adSJeff Niu 56e95e94adSJeff Niu if (parser.parseType(operandType)) 57e95e94adSJeff Niu return failure(); 58e95e94adSJeff Niu if (succeeded(parser.parseOptionalComma())) 59e95e94adSJeff Niu if (parser.parseType(optOperandType)) 60e95e94adSJeff Niu return failure(); 61e95e94adSJeff Niu if (parser.parseArrow() || parser.parseLParen() || 62e95e94adSJeff Niu parser.parseTypeList(varOperandTypes) || parser.parseRParen()) 63e95e94adSJeff Niu return failure(); 64e95e94adSJeff Niu return success(); 65e95e94adSJeff Niu } 66e95e94adSJeff Niu 67e95e94adSJeff Niu void test::printCustomDirectiveResults(OpAsmPrinter &printer, Operation *, 68e95e94adSJeff Niu Type operandType, Type optOperandType, 69e95e94adSJeff Niu TypeRange varOperandTypes) { 70e95e94adSJeff Niu printer << " : " << operandType; 71e95e94adSJeff Niu if (optOperandType) 72e95e94adSJeff Niu printer << ", " << optOperandType; 73e95e94adSJeff Niu printer << " -> (" << varOperandTypes << ")"; 74e95e94adSJeff Niu } 75e95e94adSJeff Niu 76e95e94adSJeff Niu //===----------------------------------------------------------------------===// 77e95e94adSJeff Niu // CustomDirectiveWithTypeRefs 78e95e94adSJeff Niu //===----------------------------------------------------------------------===// 79e95e94adSJeff Niu 80e95e94adSJeff Niu ParseResult test::parseCustomDirectiveWithTypeRefs( 81e95e94adSJeff Niu OpAsmParser &parser, Type operandType, Type optOperandType, 82e95e94adSJeff Niu const SmallVectorImpl<Type> &varOperandTypes) { 83e95e94adSJeff Niu if (parser.parseKeyword("type_refs_capture")) 84e95e94adSJeff Niu return failure(); 85e95e94adSJeff Niu 86e95e94adSJeff Niu Type operandType2, optOperandType2; 87e95e94adSJeff Niu SmallVector<Type, 1> varOperandTypes2; 88e95e94adSJeff Niu if (parseCustomDirectiveResults(parser, operandType2, optOperandType2, 89e95e94adSJeff Niu varOperandTypes2)) 90e95e94adSJeff Niu return failure(); 91e95e94adSJeff Niu 92e95e94adSJeff Niu if (operandType != operandType2 || optOperandType != optOperandType2 || 93e95e94adSJeff Niu varOperandTypes != varOperandTypes2) 94e95e94adSJeff Niu return failure(); 95e95e94adSJeff Niu 96e95e94adSJeff Niu return success(); 97e95e94adSJeff Niu } 98e95e94adSJeff Niu 99e95e94adSJeff Niu void test::printCustomDirectiveWithTypeRefs(OpAsmPrinter &printer, 100e95e94adSJeff Niu Operation *op, Type operandType, 101e95e94adSJeff Niu Type optOperandType, 102e95e94adSJeff Niu TypeRange varOperandTypes) { 103e95e94adSJeff Niu printer << " type_refs_capture "; 104e95e94adSJeff Niu printCustomDirectiveResults(printer, op, operandType, optOperandType, 105e95e94adSJeff Niu varOperandTypes); 106e95e94adSJeff Niu } 107e95e94adSJeff Niu 108e95e94adSJeff Niu //===----------------------------------------------------------------------===// 109e95e94adSJeff Niu // CustomDirectiveOperandsAndTypes 110e95e94adSJeff Niu //===----------------------------------------------------------------------===// 111e95e94adSJeff Niu 112e95e94adSJeff Niu ParseResult test::parseCustomDirectiveOperandsAndTypes( 113e95e94adSJeff Niu OpAsmParser &parser, OpAsmParser::UnresolvedOperand &operand, 114e95e94adSJeff Niu std::optional<OpAsmParser::UnresolvedOperand> &optOperand, 115e95e94adSJeff Niu SmallVectorImpl<OpAsmParser::UnresolvedOperand> &varOperands, 116e95e94adSJeff Niu Type &operandType, Type &optOperandType, 117e95e94adSJeff Niu SmallVectorImpl<Type> &varOperandTypes) { 118e95e94adSJeff Niu if (parseCustomDirectiveOperands(parser, operand, optOperand, varOperands) || 119e95e94adSJeff Niu parseCustomDirectiveResults(parser, operandType, optOperandType, 120e95e94adSJeff Niu varOperandTypes)) 121e95e94adSJeff Niu return failure(); 122e95e94adSJeff Niu return success(); 123e95e94adSJeff Niu } 124e95e94adSJeff Niu 125e95e94adSJeff Niu void test::printCustomDirectiveOperandsAndTypes( 126e95e94adSJeff Niu OpAsmPrinter &printer, Operation *op, Value operand, Value optOperand, 127e95e94adSJeff Niu OperandRange varOperands, Type operandType, Type optOperandType, 128e95e94adSJeff Niu TypeRange varOperandTypes) { 129e95e94adSJeff Niu printCustomDirectiveOperands(printer, op, operand, optOperand, varOperands); 130e95e94adSJeff Niu printCustomDirectiveResults(printer, op, operandType, optOperandType, 131e95e94adSJeff Niu varOperandTypes); 132e95e94adSJeff Niu } 133e95e94adSJeff Niu 134e95e94adSJeff Niu //===----------------------------------------------------------------------===// 135e95e94adSJeff Niu // CustomDirectiveRegions 136e95e94adSJeff Niu //===----------------------------------------------------------------------===// 137e95e94adSJeff Niu 138e95e94adSJeff Niu ParseResult test::parseCustomDirectiveRegions( 139e95e94adSJeff Niu OpAsmParser &parser, Region ®ion, 140e95e94adSJeff Niu SmallVectorImpl<std::unique_ptr<Region>> &varRegions) { 141e95e94adSJeff Niu if (parser.parseRegion(region)) 142e95e94adSJeff Niu return failure(); 143e95e94adSJeff Niu if (failed(parser.parseOptionalComma())) 144e95e94adSJeff Niu return success(); 145e95e94adSJeff Niu std::unique_ptr<Region> varRegion = std::make_unique<Region>(); 146e95e94adSJeff Niu if (parser.parseRegion(*varRegion)) 147e95e94adSJeff Niu return failure(); 148e95e94adSJeff Niu varRegions.emplace_back(std::move(varRegion)); 149e95e94adSJeff Niu return success(); 150e95e94adSJeff Niu } 151e95e94adSJeff Niu 152e95e94adSJeff Niu void test::printCustomDirectiveRegions(OpAsmPrinter &printer, Operation *, 153e95e94adSJeff Niu Region ®ion, 154e95e94adSJeff Niu MutableArrayRef<Region> varRegions) { 155e95e94adSJeff Niu printer.printRegion(region); 156e95e94adSJeff Niu if (!varRegions.empty()) { 157e95e94adSJeff Niu printer << ", "; 158e95e94adSJeff Niu for (Region ®ion : varRegions) 159e95e94adSJeff Niu printer.printRegion(region); 160e95e94adSJeff Niu } 161e95e94adSJeff Niu } 162e95e94adSJeff Niu 163e95e94adSJeff Niu //===----------------------------------------------------------------------===// 164e95e94adSJeff Niu // CustomDirectiveSuccessors 165e95e94adSJeff Niu //===----------------------------------------------------------------------===// 166e95e94adSJeff Niu 167e95e94adSJeff Niu ParseResult 168e95e94adSJeff Niu test::parseCustomDirectiveSuccessors(OpAsmParser &parser, Block *&successor, 169e95e94adSJeff Niu SmallVectorImpl<Block *> &varSuccessors) { 170e95e94adSJeff Niu if (parser.parseSuccessor(successor)) 171e95e94adSJeff Niu return failure(); 172e95e94adSJeff Niu if (failed(parser.parseOptionalComma())) 173e95e94adSJeff Niu return success(); 174e95e94adSJeff Niu Block *varSuccessor; 175e95e94adSJeff Niu if (parser.parseSuccessor(varSuccessor)) 176e95e94adSJeff Niu return failure(); 177e95e94adSJeff Niu varSuccessors.append(2, varSuccessor); 178e95e94adSJeff Niu return success(); 179e95e94adSJeff Niu } 180e95e94adSJeff Niu 181e95e94adSJeff Niu void test::printCustomDirectiveSuccessors(OpAsmPrinter &printer, Operation *, 182e95e94adSJeff Niu Block *successor, 183e95e94adSJeff Niu SuccessorRange varSuccessors) { 184e95e94adSJeff Niu printer << successor; 185e95e94adSJeff Niu if (!varSuccessors.empty()) 186e95e94adSJeff Niu printer << ", " << varSuccessors.front(); 187e95e94adSJeff Niu } 188e95e94adSJeff Niu 189e95e94adSJeff Niu //===----------------------------------------------------------------------===// 190e95e94adSJeff Niu // CustomDirectiveAttributes 191e95e94adSJeff Niu //===----------------------------------------------------------------------===// 192e95e94adSJeff Niu 193e95e94adSJeff Niu ParseResult test::parseCustomDirectiveAttributes(OpAsmParser &parser, 194e95e94adSJeff Niu IntegerAttr &attr, 195e95e94adSJeff Niu IntegerAttr &optAttr) { 196e95e94adSJeff Niu if (parser.parseAttribute(attr)) 197e95e94adSJeff Niu return failure(); 198e95e94adSJeff Niu if (succeeded(parser.parseOptionalComma())) { 199e95e94adSJeff Niu if (parser.parseAttribute(optAttr)) 200e95e94adSJeff Niu return failure(); 201e95e94adSJeff Niu } 202e95e94adSJeff Niu return success(); 203e95e94adSJeff Niu } 204e95e94adSJeff Niu 205e95e94adSJeff Niu void test::printCustomDirectiveAttributes(OpAsmPrinter &printer, Operation *, 206e95e94adSJeff Niu Attribute attribute, 207e95e94adSJeff Niu Attribute optAttribute) { 208e95e94adSJeff Niu printer << attribute; 209e95e94adSJeff Niu if (optAttribute) 210e95e94adSJeff Niu printer << ", " << optAttribute; 211e95e94adSJeff Niu } 212e95e94adSJeff Niu 213e95e94adSJeff Niu //===----------------------------------------------------------------------===// 214e95e94adSJeff Niu // CustomDirectiveAttrDict 215e95e94adSJeff Niu //===----------------------------------------------------------------------===// 216e95e94adSJeff Niu 217e95e94adSJeff Niu ParseResult test::parseCustomDirectiveAttrDict(OpAsmParser &parser, 218e95e94adSJeff Niu NamedAttrList &attrs) { 219e95e94adSJeff Niu return parser.parseOptionalAttrDict(attrs); 220e95e94adSJeff Niu } 221e95e94adSJeff Niu 222e95e94adSJeff Niu void test::printCustomDirectiveAttrDict(OpAsmPrinter &printer, Operation *op, 223e95e94adSJeff Niu DictionaryAttr attrs) { 224e95e94adSJeff Niu printer.printOptionalAttrDict(attrs.getValue()); 225e95e94adSJeff Niu } 226e95e94adSJeff Niu 227e95e94adSJeff Niu //===----------------------------------------------------------------------===// 228e95e94adSJeff Niu // CustomDirectiveOptionalOperandRef 229e95e94adSJeff Niu //===----------------------------------------------------------------------===// 230e95e94adSJeff Niu 231e95e94adSJeff Niu ParseResult test::parseCustomDirectiveOptionalOperandRef( 232e95e94adSJeff Niu OpAsmParser &parser, 233e95e94adSJeff Niu std::optional<OpAsmParser::UnresolvedOperand> &optOperand) { 234e95e94adSJeff Niu int64_t operandCount = 0; 235e95e94adSJeff Niu if (parser.parseInteger(operandCount)) 236e95e94adSJeff Niu return failure(); 237e95e94adSJeff Niu bool expectedOptionalOperand = operandCount == 0; 238e95e94adSJeff Niu return success(expectedOptionalOperand != !!optOperand); 239e95e94adSJeff Niu } 240e95e94adSJeff Niu 241e95e94adSJeff Niu void test::printCustomDirectiveOptionalOperandRef(OpAsmPrinter &printer, 242e95e94adSJeff Niu Operation *op, 243e95e94adSJeff Niu Value optOperand) { 244e95e94adSJeff Niu printer << (optOperand ? "1" : "0"); 245e95e94adSJeff Niu } 246e95e94adSJeff Niu 247e95e94adSJeff Niu //===----------------------------------------------------------------------===// 248e95e94adSJeff Niu // CustomDirectiveOptionalOperand 249e95e94adSJeff Niu //===----------------------------------------------------------------------===// 250e95e94adSJeff Niu 251e95e94adSJeff Niu ParseResult test::parseCustomOptionalOperand( 252e95e94adSJeff Niu OpAsmParser &parser, 253e95e94adSJeff Niu std::optional<OpAsmParser::UnresolvedOperand> &optOperand) { 254e95e94adSJeff Niu if (succeeded(parser.parseOptionalLParen())) { 255e95e94adSJeff Niu optOperand.emplace(); 256e95e94adSJeff Niu if (parser.parseOperand(*optOperand) || parser.parseRParen()) 257e95e94adSJeff Niu return failure(); 258e95e94adSJeff Niu } 259e95e94adSJeff Niu return success(); 260e95e94adSJeff Niu } 261e95e94adSJeff Niu 262e95e94adSJeff Niu void test::printCustomOptionalOperand(OpAsmPrinter &printer, Operation *, 263e95e94adSJeff Niu Value optOperand) { 264e95e94adSJeff Niu if (optOperand) 265e95e94adSJeff Niu printer << "(" << optOperand << ") "; 266e95e94adSJeff Niu } 267e95e94adSJeff Niu 268e95e94adSJeff Niu //===----------------------------------------------------------------------===// 269e95e94adSJeff Niu // CustomDirectiveSwitchCases 270e95e94adSJeff Niu //===----------------------------------------------------------------------===// 271e95e94adSJeff Niu 272e95e94adSJeff Niu ParseResult 273e95e94adSJeff Niu test::parseSwitchCases(OpAsmParser &p, DenseI64ArrayAttr &cases, 274e95e94adSJeff Niu SmallVectorImpl<std::unique_ptr<Region>> &caseRegions) { 275e95e94adSJeff Niu SmallVector<int64_t> caseValues; 276e95e94adSJeff Niu while (succeeded(p.parseOptionalKeyword("case"))) { 277e95e94adSJeff Niu int64_t value; 278e95e94adSJeff Niu Region ®ion = *caseRegions.emplace_back(std::make_unique<Region>()); 279e95e94adSJeff Niu if (p.parseInteger(value) || p.parseRegion(region, /*arguments=*/{})) 280e95e94adSJeff Niu return failure(); 281e95e94adSJeff Niu caseValues.push_back(value); 282e95e94adSJeff Niu } 283e95e94adSJeff Niu cases = p.getBuilder().getDenseI64ArrayAttr(caseValues); 284e95e94adSJeff Niu return success(); 285e95e94adSJeff Niu } 286e95e94adSJeff Niu 287e95e94adSJeff Niu void test::printSwitchCases(OpAsmPrinter &p, Operation *op, 288e95e94adSJeff Niu DenseI64ArrayAttr cases, RegionRange caseRegions) { 289e95e94adSJeff Niu for (auto [value, region] : llvm::zip(cases.asArrayRef(), caseRegions)) { 290e95e94adSJeff Niu p.printNewline(); 291e95e94adSJeff Niu p << "case " << value << ' '; 292e95e94adSJeff Niu p.printRegion(*region, /*printEntryBlockArgs=*/false); 293e95e94adSJeff Niu } 294e95e94adSJeff Niu } 295e95e94adSJeff Niu 296e95e94adSJeff Niu //===----------------------------------------------------------------------===// 297e95e94adSJeff Niu // CustomUsingPropertyInCustom 298e95e94adSJeff Niu //===----------------------------------------------------------------------===// 299e95e94adSJeff Niu 300*8955e285SKrzysztof Drewniak bool test::parseUsingPropertyInCustom(OpAsmParser &parser, 301*8955e285SKrzysztof Drewniak SmallVector<int64_t> &value) { 302*8955e285SKrzysztof Drewniak auto elemParser = [&]() { 303*8955e285SKrzysztof Drewniak int64_t v = 0; 304*8955e285SKrzysztof Drewniak if (failed(parser.parseInteger(v))) 305*8955e285SKrzysztof Drewniak return failure(); 306*8955e285SKrzysztof Drewniak value.push_back(v); 307*8955e285SKrzysztof Drewniak return success(); 308*8955e285SKrzysztof Drewniak }; 309*8955e285SKrzysztof Drewniak return failed(parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Square, 310*8955e285SKrzysztof Drewniak elemParser)); 311e95e94adSJeff Niu } 312e95e94adSJeff Niu 313e95e94adSJeff Niu void test::printUsingPropertyInCustom(OpAsmPrinter &printer, Operation *op, 314e95e94adSJeff Niu ArrayRef<int64_t> value) { 315e95e94adSJeff Niu printer << '[' << value << ']'; 316e95e94adSJeff Niu } 317e95e94adSJeff Niu 318e95e94adSJeff Niu //===----------------------------------------------------------------------===// 319e95e94adSJeff Niu // CustomDirectiveIntProperty 320e95e94adSJeff Niu //===----------------------------------------------------------------------===// 321e95e94adSJeff Niu 322e95e94adSJeff Niu bool test::parseIntProperty(OpAsmParser &parser, int64_t &value) { 323e95e94adSJeff Niu return failed(parser.parseInteger(value)); 324e95e94adSJeff Niu } 325e95e94adSJeff Niu 326e95e94adSJeff Niu void test::printIntProperty(OpAsmPrinter &printer, Operation *op, 327e95e94adSJeff Niu int64_t value) { 328e95e94adSJeff Niu printer << value; 329e95e94adSJeff Niu } 330e95e94adSJeff Niu 331e95e94adSJeff Niu //===----------------------------------------------------------------------===// 332e95e94adSJeff Niu // CustomDirectiveSumProperty 333e95e94adSJeff Niu //===----------------------------------------------------------------------===// 334e95e94adSJeff Niu 335e95e94adSJeff Niu bool test::parseSumProperty(OpAsmParser &parser, int64_t &second, 336e95e94adSJeff Niu int64_t first) { 337e95e94adSJeff Niu int64_t sum; 338e95e94adSJeff Niu auto loc = parser.getCurrentLocation(); 339e95e94adSJeff Niu if (parser.parseInteger(second) || parser.parseEqual() || 340e95e94adSJeff Niu parser.parseInteger(sum)) 341e95e94adSJeff Niu return true; 342e95e94adSJeff Niu if (sum != second + first) { 343e95e94adSJeff Niu parser.emitError(loc, "Expected sum to equal first + second"); 344e95e94adSJeff Niu return true; 345e95e94adSJeff Niu } 346e95e94adSJeff Niu return false; 347e95e94adSJeff Niu } 348e95e94adSJeff Niu 349e95e94adSJeff Niu void test::printSumProperty(OpAsmPrinter &printer, Operation *op, 350e95e94adSJeff Niu int64_t second, int64_t first) { 351e95e94adSJeff Niu printer << second << " = " << (second + first); 352e95e94adSJeff Niu } 353e95e94adSJeff Niu 354e95e94adSJeff Niu //===----------------------------------------------------------------------===// 355e95e94adSJeff Niu // CustomDirectiveOptionalCustomParser 356e95e94adSJeff Niu //===----------------------------------------------------------------------===// 357e95e94adSJeff Niu 358e95e94adSJeff Niu OptionalParseResult test::parseOptionalCustomParser(AsmParser &p, 359e95e94adSJeff Niu IntegerAttr &result) { 360e95e94adSJeff Niu if (succeeded(p.parseOptionalKeyword("foo"))) 361e95e94adSJeff Niu return p.parseAttribute(result); 362e95e94adSJeff Niu return {}; 363e95e94adSJeff Niu } 364e95e94adSJeff Niu 365e95e94adSJeff Niu void test::printOptionalCustomParser(AsmPrinter &p, Operation *, 366e95e94adSJeff Niu IntegerAttr result) { 367e95e94adSJeff Niu p << "foo "; 368e95e94adSJeff Niu p.printAttribute(result); 369e95e94adSJeff Niu } 370e95e94adSJeff Niu 371e95e94adSJeff Niu //===----------------------------------------------------------------------===// 372e95e94adSJeff Niu // CustomDirectiveAttrElideType 373e95e94adSJeff Niu //===----------------------------------------------------------------------===// 374e95e94adSJeff Niu 375e95e94adSJeff Niu ParseResult test::parseAttrElideType(AsmParser &parser, TypeAttr type, 376e95e94adSJeff Niu Attribute &attr) { 377e95e94adSJeff Niu return parser.parseAttribute(attr, type.getValue()); 378e95e94adSJeff Niu } 379e95e94adSJeff Niu 380e95e94adSJeff Niu void test::printAttrElideType(AsmPrinter &printer, Operation *op, TypeAttr type, 381e95e94adSJeff Niu Attribute attr) { 382e95e94adSJeff Niu printer.printAttributeWithoutType(attr); 383e95e94adSJeff Niu } 384