1// RUN: llvm-tblgen -gen-directive-decl -I %p/../../include %s | FileCheck -match-full-lines %s 2// RUN: llvm-tblgen -gen-directive-impl -I %p/../../include %s | FileCheck -match-full-lines %s -check-prefix=IMPL 3 4include "llvm/Frontend/Directive/DirectiveBase.td" 5 6def TestDirectiveLanguage : DirectiveLanguage { 7 let name = "Tdl"; 8 9 let cppNamespace = "tdl"; 10 let directivePrefix = "TDLD_"; 11 let clausePrefix = "TDLC_"; 12 let makeEnumAvailableInNamespace = 1; 13 let enableBitmaskEnumInNamespace = 1; 14 let flangClauseBaseClass = "TdlClause"; 15} 16 17def TDLCV_vala : ClauseVal<"vala",1,1> {} 18def TDLCV_valb : ClauseVal<"valb",2,1> {} 19def TDLCV_valc : ClauseVal<"valc",3,0> { let isDefault = 1; } 20 21def TDLC_ClauseA : Clause<"clausea"> { 22 let enumClauseValue = "AKind"; 23 let allowedClauseValues = [ 24 TDLCV_vala, 25 TDLCV_valb, 26 TDLCV_valc 27 ]; 28} 29 30def TDLC_ClauseB : Clause<"clauseb"> { 31 let flangClass = "IntExpr"; 32 let isValueOptional = 1; 33 let isDefault = 1; 34} 35 36def TDLC_ClauseC : Clause<"clausec"> { 37 let flangClass = "IntExpr"; 38 let isValueList = 1; 39} 40 41def TDL_DirA : Directive<"dira"> { 42 let allowedClauses = [ 43 VersionedClause<TDLC_ClauseA>, 44 VersionedClause<TDLC_ClauseB> 45 ]; 46 let isDefault = 1; 47 let association = AS_None; 48 let category = CA_Executable; 49} 50 51// CHECK: #ifndef LLVM_Tdl_INC 52// CHECK-NEXT: #define LLVM_Tdl_INC 53// CHECK-EMPTY: 54// CHECK-NEXT: #include "llvm/ADT/ArrayRef.h" 55// CHECK-NEXT: #include "llvm/ADT/BitmaskEnum.h" 56// CHECK-NEXT: #include "llvm/Support/Compiler.h" 57// CHECK-NEXT: #include <cstddef> 58// CHECK-EMPTY: 59// CHECK-NEXT: namespace llvm { 60// CHECK-NEXT: class StringRef; 61// CHECK-NEXT: namespace tdl { 62// CHECK-EMPTY: 63// CHECK-NEXT: LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); 64// CHECK-EMPTY: 65// CHECK-NEXT: enum class Association { 66// CHECK-NEXT: Block, 67// CHECK-NEXT: Declaration, 68// CHECK-NEXT: Delimited, 69// CHECK-NEXT: Loop, 70// CHECK-NEXT: None, 71// CHECK-NEXT: Separating, 72// CHECK-NEXT: }; 73// CHECK-EMPTY: 74// CHECK-NEXT: static constexpr std::size_t Association_enumSize = 6; 75// CHECK-EMPTY: 76// CHECK-NEXT: enum class Category { 77// CHECK-NEXT: Declarative, 78// CHECK-NEXT: Executable, 79// CHECK-NEXT: Informational, 80// CHECK-NEXT: Meta, 81// CHECK-NEXT: Subsidiary, 82// CHECK-NEXT: Utility, 83// CHECK-NEXT: }; 84// CHECK-EMPTY: 85// CHECK-NEXT: static constexpr std::size_t Category_enumSize = 6; 86// CHECK-EMPTY: 87// CHECK-NEXT: enum class Directive { 88// CHECK-NEXT: TDLD_dira, 89// CHECK-NEXT: }; 90// CHECK-EMPTY: 91// CHECK-NEXT: static constexpr std::size_t Directive_enumSize = 1; 92// CHECK-EMPTY: 93// CHECK-NEXT: constexpr auto TDLD_dira = llvm::tdl::Directive::TDLD_dira; 94// CHECK-EMPTY: 95// CHECK-NEXT: enum class Clause { 96// CHECK-NEXT: TDLC_clausea, 97// CHECK-NEXT: TDLC_clauseb, 98// CHECK-NEXT: TDLC_clausec, 99// CHECK-NEXT: }; 100// CHECK-EMPTY: 101// CHECK-NEXT: static constexpr std::size_t Clause_enumSize = 3; 102// CHECK-EMPTY: 103// CHECK-NEXT: constexpr auto TDLC_clausea = llvm::tdl::Clause::TDLC_clausea; 104// CHECK-NEXT: constexpr auto TDLC_clauseb = llvm::tdl::Clause::TDLC_clauseb; 105// CHECK-NEXT: constexpr auto TDLC_clausec = llvm::tdl::Clause::TDLC_clausec; 106// CHECK-EMPTY: 107// CHECK-NEXT: enum class AKind { 108// CHECK-NEXT: TDLCV_vala=1, 109// CHECK-NEXT: TDLCV_valb=2, 110// CHECK-NEXT: TDLCV_valc=3, 111// CHECK-NEXT: }; 112// CHECK-EMPTY: 113// CHECK-NEXT: constexpr auto TDLCV_vala = llvm::tdl::AKind::TDLCV_vala; 114// CHECK-NEXT: constexpr auto TDLCV_valb = llvm::tdl::AKind::TDLCV_valb; 115// CHECK-NEXT: constexpr auto TDLCV_valc = llvm::tdl::AKind::TDLCV_valc; 116// CHECK-EMPTY: 117// CHECK-NEXT: // Enumeration helper functions 118// CHECK-NEXT: LLVM_ABI Directive getTdlDirectiveKind(llvm::StringRef Str); 119// CHECK-EMPTY: 120// CHECK-NEXT: LLVM_ABI llvm::StringRef getTdlDirectiveName(Directive D); 121// CHECK-EMPTY: 122// CHECK-NEXT: LLVM_ABI Clause getTdlClauseKind(llvm::StringRef Str); 123// CHECK-EMPTY: 124// CHECK-NEXT: LLVM_ABI llvm::StringRef getTdlClauseName(Clause C); 125// CHECK-EMPTY: 126// CHECK-NEXT: /// Return true if \p C is a valid clause for \p D in version \p Version. 127// CHECK-NEXT: LLVM_ABI bool isAllowedClauseForDirective(Directive D, Clause C, unsigned Version); 128// CHECK-EMPTY: 129// CHECK-NEXT: constexpr std::size_t getMaxLeafCount() { return 0; } 130// CHECK-NEXT: LLVM_ABI Association getDirectiveAssociation(Directive D); 131// CHECK-NEXT: LLVM_ABI Category getDirectiveCategory(Directive D); 132// CHECK-NEXT: LLVM_ABI AKind getAKind(StringRef); 133// CHECK-NEXT: LLVM_ABI llvm::StringRef getTdlAKindName(AKind); 134// CHECK-EMPTY: 135// CHECK-NEXT: } // namespace tdl 136// CHECK-NEXT: } // namespace llvm 137// CHECK-NEXT: #endif // LLVM_Tdl_INC 138 139 140// IMPL: #ifdef GEN_FLANG_DIRECTIVE_CLAUSE_SETS 141// IMPL-NEXT: #undef GEN_FLANG_DIRECTIVE_CLAUSE_SETS 142// IMPL-EMPTY: 143// IMPL-NEXT: namespace llvm { 144// IMPL-NEXT: namespace tdl { 145// IMPL-EMPTY: 146// IMPL-NEXT: // Sets for dira 147// IMPL-EMPTY: 148// IMPL-NEXT: static allowedClauses_TDLD_dira { 149// IMPL-NEXT: llvm::tdl::Clause::TDLC_clausea, 150// IMPL-NEXT: llvm::tdl::Clause::TDLC_clauseb, 151// IMPL-NEXT: }; 152// IMPL-EMPTY: 153// IMPL-NEXT: static allowedOnceClauses_TDLD_dira { 154// IMPL-NEXT: }; 155// IMPL-EMPTY: 156// IMPL-NEXT: static allowedExclusiveClauses_TDLD_dira { 157// IMPL-NEXT: }; 158// IMPL-EMPTY: 159// IMPL-NEXT: static requiredClauses_TDLD_dira { 160// IMPL-NEXT: }; 161// IMPL-NEXT: } // namespace tdl 162// IMPL-NEXT: } // namespace llvm 163// IMPL-EMPTY: 164// IMPL-NEXT: #endif // GEN_FLANG_DIRECTIVE_CLAUSE_SETS 165// IMPL-EMPTY: 166// IMPL-NEXT: #ifdef GEN_FLANG_DIRECTIVE_CLAUSE_MAP 167// IMPL-NEXT: #undef GEN_FLANG_DIRECTIVE_CLAUSE_MAP 168// IMPL-EMPTY: 169// IMPL-NEXT: { 170// IMPL-NEXT: {llvm::tdl::Directive::TDLD_dira, 171// IMPL-NEXT: { 172// IMPL-NEXT: llvm::tdl::allowedClauses_TDLD_dira, 173// IMPL-NEXT: llvm::tdl::allowedOnceClauses_TDLD_dira, 174// IMPL-NEXT: llvm::tdl::allowedExclusiveClauses_TDLD_dira, 175// IMPL-NEXT: llvm::tdl::requiredClauses_TDLD_dira, 176// IMPL-NEXT: } 177// IMPL-NEXT: }, 178// IMPL-NEXT: } 179// IMPL-EMPTY: 180// IMPL-NEXT: #endif // GEN_FLANG_DIRECTIVE_CLAUSE_MAP 181// IMPL-EMPTY: 182// IMPL-NEXT: #ifdef GEN_FLANG_CLAUSE_PARSER_CLASSES 183// IMPL-NEXT: #undef GEN_FLANG_CLAUSE_PARSER_CLASSES 184// IMPL-EMPTY: 185// IMPL-NEXT: EMPTY_CLASS(Clausea); 186// IMPL-NEXT: WRAPPER_CLASS(Clauseb, std::optional<IntExpr>); 187// IMPL-NEXT: WRAPPER_CLASS(Clausec, std::list<IntExpr>); 188// IMPL-EMPTY: 189// IMPL-NEXT: #endif // GEN_FLANG_CLAUSE_PARSER_CLASSES 190// IMPL-EMPTY: 191// IMPL-NEXT: #ifdef GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST 192// IMPL-NEXT: #undef GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST 193// IMPL-EMPTY: 194// IMPL-NEXT: Clausea 195// IMPL-NEXT: , Clauseb 196// IMPL-NEXT: , Clausec 197// IMPL-EMPTY: 198// IMPL-NEXT: #endif // GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST 199// IMPL-EMPTY: 200// IMPL-NEXT: #ifdef GEN_FLANG_DUMP_PARSE_TREE_CLAUSES 201// IMPL-NEXT: #undef GEN_FLANG_DUMP_PARSE_TREE_CLAUSES 202// IMPL-EMPTY: 203// IMPL-NEXT: NODE(TdlClause, Clausea) 204// IMPL-NEXT: NODE(TdlClause, Clauseb) 205// IMPL-NEXT: NODE(TdlClause, Clausec) 206// IMPL-EMPTY: 207// IMPL-NEXT: #endif // GEN_FLANG_DUMP_PARSE_TREE_CLAUSES 208// IMPL-EMPTY: 209// IMPL-NEXT: #ifdef GEN_FLANG_CLAUSE_UNPARSE 210// IMPL-NEXT: #undef GEN_FLANG_CLAUSE_UNPARSE 211// IMPL-EMPTY: 212// IMPL-NEXT: void Before(const TdlClause::Clausea &) { Word("CLAUSEA"); } 213// IMPL-NEXT: void Unparse(const TdlClause::Clauseb &x) { 214// IMPL-NEXT: Word("CLAUSEB"); 215// IMPL-NEXT: Walk("(", x.v, ")"); 216// IMPL-NEXT: } 217// IMPL-NEXT: void Unparse(const TdlClause::Clausec &x) { 218// IMPL-NEXT: Word("CLAUSEC"); 219// IMPL-NEXT: Put("("); 220// IMPL-NEXT: Walk(x.v, ","); 221// IMPL-NEXT: Put(")"); 222// IMPL-NEXT: } 223// IMPL-EMPTY: 224// IMPL-NEXT: #endif // GEN_FLANG_CLAUSE_UNPARSE 225// IMPL-EMPTY: 226// IMPL-NEXT: #ifdef GEN_FLANG_CLAUSE_CHECK_ENTER 227// IMPL-NEXT: #undef GEN_FLANG_CLAUSE_CHECK_ENTER 228// IMPL-EMPTY: 229// IMPL-NEXT: void Enter(const parser::TdlClause::Clausea &); 230// IMPL-NEXT: void Enter(const parser::TdlClause::Clauseb &); 231// IMPL-NEXT: void Enter(const parser::TdlClause::Clausec &); 232// IMPL-EMPTY: 233// IMPL-NEXT: #endif // GEN_FLANG_CLAUSE_CHECK_ENTER 234// IMPL-EMPTY: 235// IMPL-NEXT: #ifdef GEN_FLANG_CLAUSE_PARSER_KIND_MAP 236// IMPL-NEXT: #undef GEN_FLANG_CLAUSE_PARSER_KIND_MAP 237// IMPL-EMPTY: 238// IMPL-NEXT: if constexpr (std::is_same_v<A, parser::TdlClause::Clausea>) 239// IMPL-NEXT: return llvm::tdl::Clause::TDLC_clausea; 240// IMPL-NEXT: if constexpr (std::is_same_v<A, parser::TdlClause::Clauseb>) 241// IMPL-NEXT: return llvm::tdl::Clause::TDLC_clauseb; 242// IMPL-NEXT: if constexpr (std::is_same_v<A, parser::TdlClause::Clausec>) 243// IMPL-NEXT: return llvm::tdl::Clause::TDLC_clausec; 244// IMPL-NEXT: llvm_unreachable("Invalid Tdl Parser clause"); 245// IMPL-EMPTY: 246// IMPL-NEXT: #endif // GEN_FLANG_CLAUSE_PARSER_KIND_MAP 247// IMPL-EMPTY: 248// IMPL-NEXT: #ifdef GEN_FLANG_CLAUSES_PARSER 249// IMPL-NEXT: #undef GEN_FLANG_CLAUSES_PARSER 250// IMPL-EMPTY: 251// IMPL-NEXT: TYPE_PARSER( 252// IMPL-NEXT: "clausec" >> construct<TdlClause>(construct<TdlClause::Clausec>(parenthesized(nonemptyList(Parser<IntExpr>{})))) || 253// IMPL-NEXT: "clauseb" >> construct<TdlClause>(construct<TdlClause::Clauseb>(maybe(parenthesized(Parser<IntExpr>{})))) || 254// IMPL-NEXT: "clausea" >> construct<TdlClause>(construct<TdlClause::Clausea>()) 255// IMPL-NEXT: ) 256// IMPL-EMPTY: 257// IMPL-NEXT: #endif // GEN_FLANG_CLAUSES_PARSER 258// IMPL-EMPTY: 259// IMPL-NEXT: #ifdef GEN_CLANG_CLAUSE_CLASS 260// IMPL-NEXT: #undef GEN_CLANG_CLAUSE_CLASS 261// IMPL-EMPTY: 262// IMPL-NEXT: #ifndef CLAUSE 263// IMPL-NEXT: #define CLAUSE(Enum, Str, Implicit) 264// IMPL-NEXT: #endif 265// IMPL-NEXT: #ifndef CLAUSE_CLASS 266// IMPL-NEXT: #define CLAUSE_CLASS(Enum, Str, Class) 267// IMPL-NEXT: #endif 268// IMPL-NEXT: #ifndef CLAUSE_NO_CLASS 269// IMPL-NEXT: #define CLAUSE_NO_CLASS(Enum, Str) 270// IMPL-NEXT: #endif 271// IMPL-EMPTY: 272// IMPL-NEXT: #define __CLAUSE(Name, Class) \ 273// IMPL-NEXT: CLAUSE(TDLC_##Name, #Name, /* Implicit */ false) \ 274// IMPL-NEXT: CLAUSE_CLASS(TDLC_##Name, #Name, Class) 275// IMPL-NEXT: #define __CLAUSE_NO_CLASS(Name) \ 276// IMPL-NEXT: CLAUSE(TDLC_##Name, #Name, /* Implicit */ false) \ 277// IMPL-NEXT: CLAUSE_NO_CLASS(TDLC_##Name, #Name) 278// IMPL-NEXT: #define __IMPLICIT_CLAUSE_CLASS(Name, Str, Class) \ 279// IMPL-NEXT: CLAUSE(TDLC_##Name, Str, /* Implicit */ true) \ 280// IMPL-NEXT: CLAUSE_CLASS(TDLC_##Name, Str, Class) 281// IMPL-NEXT: #define __IMPLICIT_CLAUSE_NO_CLASS(Name, Str) \ 282// IMPL-NEXT: CLAUSE(TDLC_##Name, Str, /* Implicit */ true) \ 283// IMPL-NEXT: CLAUSE_NO_CLASS(TDLC_##Name, Str) 284// IMPL-EMPTY: 285// IMPL-NEXT: __CLAUSE_NO_CLASS(clausea) 286// IMPL-NEXT: __CLAUSE_NO_CLASS(clauseb) 287// IMPL-NEXT: __CLAUSE_NO_CLASS(clausec) 288// IMPL-EMPTY: 289// IMPL-NEXT: #undef __IMPLICIT_CLAUSE_NO_CLASS 290// IMPL-NEXT: #undef __IMPLICIT_CLAUSE_CLASS 291// IMPL-NEXT: #undef __CLAUSE_NO_CLASS 292// IMPL-NEXT: #undef __CLAUSE 293// IMPL-NEXT: #undef CLAUSE_NO_CLASS 294// IMPL-NEXT: #undef CLAUSE_CLASS 295// IMPL-NEXT: #undef CLAUSE 296// IMPL-EMPTY: 297// IMPL-NEXT: #endif // GEN_CLANG_CLAUSE_CLASS 298// IMPL-EMPTY: 299 300// IMPL: #ifdef GEN_DIRECTIVES_IMPL 301// IMPL-NEXT: #undef GEN_DIRECTIVES_IMPL 302// IMPL-EMPTY: 303// IMPL-NEXT: #include "llvm/Support/ErrorHandling.h" 304// IMPL-EMPTY: 305// IMPL-NEXT: Directive llvm::tdl::getTdlDirectiveKind(llvm::StringRef Str) { 306// IMPL-NEXT: return llvm::StringSwitch<Directive>(Str) 307// IMPL-NEXT: .Case("dira",TDLD_dira) 308// IMPL-NEXT: .Default(TDLD_dira); 309// IMPL-NEXT: } 310// IMPL-EMPTY: 311// IMPL-NEXT: llvm::StringRef llvm::tdl::getTdlDirectiveName(Directive Kind) { 312// IMPL-NEXT: switch (Kind) { 313// IMPL-NEXT: case TDLD_dira: 314// IMPL-NEXT: return "dira"; 315// IMPL-NEXT: } 316// IMPL-NEXT: llvm_unreachable("Invalid Tdl Directive kind"); 317// IMPL-NEXT: } 318// IMPL-EMPTY: 319// IMPL-NEXT: Clause llvm::tdl::getTdlClauseKind(llvm::StringRef Str) { 320// IMPL-NEXT: return llvm::StringSwitch<Clause>(Str) 321// IMPL-NEXT: .Case("clausea",TDLC_clausea) 322// IMPL-NEXT: .Case("clauseb",TDLC_clauseb) 323// IMPL-NEXT: .Case("clausec",TDLC_clausec) 324// IMPL-NEXT: .Default(TDLC_clauseb); 325// IMPL-NEXT: } 326// IMPL-EMPTY: 327// IMPL-NEXT: llvm::StringRef llvm::tdl::getTdlClauseName(Clause Kind) { 328// IMPL-NEXT: switch (Kind) { 329// IMPL-NEXT: case TDLC_clausea: 330// IMPL-NEXT: return "clausea"; 331// IMPL-NEXT: case TDLC_clauseb: 332// IMPL-NEXT: return "clauseb"; 333// IMPL-NEXT: case TDLC_clausec: 334// IMPL-NEXT: return "clausec"; 335// IMPL-NEXT: } 336// IMPL-NEXT: llvm_unreachable("Invalid Tdl Clause kind"); 337// IMPL-NEXT: } 338// IMPL-EMPTY: 339// IMPL-NEXT: AKind llvm::tdl::getAKind(llvm::StringRef Str) { 340// IMPL-NEXT: return llvm::StringSwitch<AKind>(Str) 341// IMPL-NEXT: .Case("vala",TDLCV_vala) 342// IMPL-NEXT: .Case("valb",TDLCV_valb) 343// IMPL-NEXT: .Case("valc",TDLCV_valc) 344// IMPL-NEXT: .Default(TDLCV_valc); 345// IMPL-NEXT: } 346// IMPL-EMPTY: 347// IMPL-NEXT: llvm::StringRef llvm::tdl::getTdlAKindName(llvm::tdl::AKind x) { 348// IMPL-NEXT: switch (x) { 349// IMPL-NEXT: case TDLCV_vala: 350// IMPL-NEXT: return "vala"; 351// IMPL-NEXT: case TDLCV_valb: 352// IMPL-NEXT: return "valb"; 353// IMPL-NEXT: case TDLCV_valc: 354// IMPL-NEXT: return "valc"; 355// IMPL-NEXT: } 356// IMPL-NEXT: llvm_unreachable("Invalid Tdl AKind kind"); 357// IMPL-NEXT: } 358// IMPL-EMPTY: 359// IMPL-NEXT: bool llvm::tdl::isAllowedClauseForDirective(Directive D, Clause C, unsigned Version) { 360// IMPL-NEXT: assert(unsigned(D) <= llvm::tdl::Directive_enumSize); 361// IMPL-NEXT: assert(unsigned(C) <= llvm::tdl::Clause_enumSize); 362// IMPL-NEXT: switch (D) { 363// IMPL-NEXT: case TDLD_dira: 364// IMPL-NEXT: switch (C) { 365// IMPL-NEXT: case TDLC_clausea: 366// IMPL-NEXT: return 1 <= Version && 2147483647 >= Version; 367// IMPL-NEXT: case TDLC_clauseb: 368// IMPL-NEXT: return 1 <= Version && 2147483647 >= Version; 369// IMPL-NEXT: default: 370// IMPL-NEXT: return false; 371// IMPL-NEXT: } 372// IMPL-NEXT: break; 373// IMPL-NEXT: } 374// IMPL-NEXT: llvm_unreachable("Invalid Tdl Directive kind"); 375// IMPL-NEXT: } 376// IMPL-EMPTY: 377// IMPL-NEXT: llvm::tdl::Association llvm::tdl::getDirectiveAssociation(llvm::tdl::Directive Dir) { 378// IMPL-NEXT: switch (Dir) { 379// IMPL-NEXT: case llvm::tdl::Directive::TDLD_dira: 380// IMPL-NEXT: return llvm::tdl::Association::None; 381// IMPL-NEXT: } // switch (Dir) 382// IMPL-NEXT: llvm_unreachable("Unexpected directive"); 383// IMPL-NEXT: } 384// IMPL-EMPTY: 385// IMPL-NEXT: llvm::tdl::Category llvm::tdl::getDirectiveCategory(llvm::tdl::Directive Dir) { 386// IMPL-NEXT: switch (Dir) { 387// IMPL-NEXT: case llvm::tdl::TDLD_dira: 388// IMPL-NEXT: return llvm::tdl::Category::Executable; 389// IMPL-NEXT: } // switch (Dir) 390// IMPL-NEXT: llvm_unreachable("Unexpected directive"); 391// IMPL-NEXT: } 392// IMPL-EMPTY: 393// IMPL-NEXT: static_assert(sizeof(llvm::tdl::Directive) == sizeof(int)); 394// IMPL-NEXT: {{.*}} static const llvm::tdl::Directive LeafConstructTable[][2] = { 395// IMPL-NEXT: {llvm::tdl::TDLD_dira, static_cast<llvm::tdl::Directive>(0),}, 396// IMPL-NEXT: }; 397// IMPL-EMPTY: 398// IMPL-NEXT: {{.*}} static auto LeafConstructTableEndDirective = LeafConstructTable + 1; 399// IMPL-EMPTY: 400// IMPL-NEXT: {{.*}} static const int LeafConstructTableOrdering[] = { 401// IMPL-NEXT: 0, 402// IMPL-NEXT: }; 403// IMPL-EMPTY: 404// IMPL-NEXT: #endif // GEN_DIRECTIVES_IMPL 405