1*7330f729Sjoerg//===--- Opcodes.td - Opcode defitions for the constexpr VM -----*- C++ -*-===// 2*7330f729Sjoerg// 3*7330f729Sjoerg// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*7330f729Sjoerg// See https://llvm.org/LICENSE.txt for license information. 5*7330f729Sjoerg// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*7330f729Sjoerg// 7*7330f729Sjoerg//===----------------------------------------------------------------------===// 8*7330f729Sjoerg// 9*7330f729Sjoerg// Helper file used to generate opcodes, the interpreter and the disassembler. 10*7330f729Sjoerg// 11*7330f729Sjoerg//===----------------------------------------------------------------------===// 12*7330f729Sjoerg 13*7330f729Sjoerg 14*7330f729Sjoerg//===----------------------------------------------------------------------===// 15*7330f729Sjoerg// Types evaluated by the interpreter. 16*7330f729Sjoerg//===----------------------------------------------------------------------===// 17*7330f729Sjoerg 18*7330f729Sjoergclass Type; 19*7330f729Sjoergdef Bool : Type; 20*7330f729Sjoergdef Sint8 : Type; 21*7330f729Sjoergdef Uint8 : Type; 22*7330f729Sjoergdef Sint16 : Type; 23*7330f729Sjoergdef Uint16 : Type; 24*7330f729Sjoergdef Sint32 : Type; 25*7330f729Sjoergdef Uint32 : Type; 26*7330f729Sjoergdef Sint64 : Type; 27*7330f729Sjoergdef Uint64 : Type; 28*7330f729Sjoergdef Ptr : Type; 29*7330f729Sjoerg 30*7330f729Sjoerg//===----------------------------------------------------------------------===// 31*7330f729Sjoerg// Types transferred to the interpreter. 32*7330f729Sjoerg//===----------------------------------------------------------------------===// 33*7330f729Sjoerg 34*7330f729Sjoergclass ArgType { string Name = ?; } 35*7330f729Sjoergdef ArgSint8 : ArgType { let Name = "int8_t"; } 36*7330f729Sjoergdef ArgUint8 : ArgType { let Name = "uint8_t"; } 37*7330f729Sjoergdef ArgSint16 : ArgType { let Name = "int16_t"; } 38*7330f729Sjoergdef ArgUint16 : ArgType { let Name = "uint16_t"; } 39*7330f729Sjoergdef ArgSint32 : ArgType { let Name = "int32_t"; } 40*7330f729Sjoergdef ArgUint32 : ArgType { let Name = "uint32_t"; } 41*7330f729Sjoergdef ArgSint64 : ArgType { let Name = "int64_t"; } 42*7330f729Sjoergdef ArgUint64 : ArgType { let Name = "uint64_t"; } 43*7330f729Sjoergdef ArgBool : ArgType { let Name = "bool"; } 44*7330f729Sjoerg 45*7330f729Sjoergdef ArgFunction : ArgType { let Name = "Function *"; } 46*7330f729Sjoergdef ArgRecord : ArgType { let Name = "Record *"; } 47*7330f729Sjoerg 48*7330f729Sjoergdef ArgSema : ArgType { let Name = "const fltSemantics *"; } 49*7330f729Sjoerg 50*7330f729Sjoergdef ArgExpr : ArgType { let Name = "const Expr *"; } 51*7330f729Sjoergdef ArgFloatingLiteral : ArgType { let Name = "const FloatingLiteral *"; } 52*7330f729Sjoergdef ArgCXXMethodDecl : ArgType { let Name = "const CXXMethodDecl *"; } 53*7330f729Sjoergdef ArgFunctionDecl : ArgType { let Name = "const FunctionDecl *"; } 54*7330f729Sjoergdef ArgRecordDecl : ArgType { let Name = "const RecordDecl *"; } 55*7330f729Sjoergdef ArgCXXRecordDecl : ArgType { let Name = "const CXXRecordDecl *"; } 56*7330f729Sjoergdef ArgValueDecl : ArgType { let Name = "const ValueDecl *"; } 57*7330f729Sjoergdef ArgRecordField : ArgType { let Name = "const Record::Field *"; } 58*7330f729Sjoerg 59*7330f729Sjoerg//===----------------------------------------------------------------------===// 60*7330f729Sjoerg// Classes of types intructions operate on. 61*7330f729Sjoerg//===----------------------------------------------------------------------===// 62*7330f729Sjoerg 63*7330f729Sjoergclass TypeClass { 64*7330f729Sjoerg list<Type> Types; 65*7330f729Sjoerg} 66*7330f729Sjoerg 67*7330f729Sjoergdef AluTypeClass : TypeClass { 68*7330f729Sjoerg let Types = [Sint8, Uint8, Sint16, Uint16, Sint32, 69*7330f729Sjoerg Uint32, Sint64, Uint64, Bool]; 70*7330f729Sjoerg} 71*7330f729Sjoerg 72*7330f729Sjoergdef PtrTypeClass : TypeClass { 73*7330f729Sjoerg let Types = [Ptr]; 74*7330f729Sjoerg} 75*7330f729Sjoerg 76*7330f729Sjoergdef AllTypeClass : TypeClass { 77*7330f729Sjoerg let Types = !listconcat(AluTypeClass.Types, PtrTypeClass.Types); 78*7330f729Sjoerg} 79*7330f729Sjoerg 80*7330f729Sjoergdef ComparableTypeClass : TypeClass { 81*7330f729Sjoerg let Types = !listconcat(AluTypeClass.Types, [Ptr]); 82*7330f729Sjoerg} 83*7330f729Sjoerg 84*7330f729Sjoergclass SingletonTypeClass<Type Ty> : TypeClass { 85*7330f729Sjoerg let Types = [Ty]; 86*7330f729Sjoerg} 87*7330f729Sjoerg 88*7330f729Sjoerg//===----------------------------------------------------------------------===// 89*7330f729Sjoerg// Record describing all opcodes. 90*7330f729Sjoerg//===----------------------------------------------------------------------===// 91*7330f729Sjoerg 92*7330f729Sjoergclass Opcode { 93*7330f729Sjoerg list<TypeClass> Types = []; 94*7330f729Sjoerg list<ArgType> Args = []; 95*7330f729Sjoerg string Name = ""; 96*7330f729Sjoerg bit CanReturn = 0; 97*7330f729Sjoerg bit ChangesPC = 0; 98*7330f729Sjoerg bit HasCustomLink = 0; 99*7330f729Sjoerg bit HasCustomEval = 0; 100*7330f729Sjoerg bit HasGroup = 0; 101*7330f729Sjoerg} 102*7330f729Sjoerg 103*7330f729Sjoergclass AluOpcode : Opcode { 104*7330f729Sjoerg let Types = [AluTypeClass]; 105*7330f729Sjoerg let HasGroup = 1; 106*7330f729Sjoerg} 107*7330f729Sjoerg 108*7330f729Sjoerg//===----------------------------------------------------------------------===// 109*7330f729Sjoerg// Jump opcodes 110*7330f729Sjoerg//===----------------------------------------------------------------------===// 111*7330f729Sjoerg 112*7330f729Sjoergclass JumpOpcode : Opcode { 113*7330f729Sjoerg let Args = [ArgSint32]; 114*7330f729Sjoerg let ChangesPC = 1; 115*7330f729Sjoerg let HasCustomEval = 1; 116*7330f729Sjoerg} 117*7330f729Sjoerg 118*7330f729Sjoerg// [] -> [] 119*7330f729Sjoergdef Jmp : JumpOpcode; 120*7330f729Sjoerg// [Bool] -> [], jumps if true. 121*7330f729Sjoergdef Jt : JumpOpcode; 122*7330f729Sjoerg// [Bool] -> [], jumps if false. 123*7330f729Sjoergdef Jf : JumpOpcode; 124*7330f729Sjoerg 125*7330f729Sjoerg//===----------------------------------------------------------------------===// 126*7330f729Sjoerg// Returns 127*7330f729Sjoerg//===----------------------------------------------------------------------===// 128*7330f729Sjoerg 129*7330f729Sjoerg// [Value] -> [] 130*7330f729Sjoergdef Ret : Opcode { 131*7330f729Sjoerg let Types = [AllTypeClass]; 132*7330f729Sjoerg let ChangesPC = 1; 133*7330f729Sjoerg let CanReturn = 1; 134*7330f729Sjoerg let HasGroup = 1; 135*7330f729Sjoerg let HasCustomEval = 1; 136*7330f729Sjoerg} 137*7330f729Sjoerg// [] -> [] 138*7330f729Sjoergdef RetVoid : Opcode { 139*7330f729Sjoerg let CanReturn = 1; 140*7330f729Sjoerg let ChangesPC = 1; 141*7330f729Sjoerg let HasCustomEval = 1; 142*7330f729Sjoerg} 143*7330f729Sjoerg// [Value] -> [] 144*7330f729Sjoergdef RetValue : Opcode { 145*7330f729Sjoerg let CanReturn = 1; 146*7330f729Sjoerg let ChangesPC = 1; 147*7330f729Sjoerg let HasCustomEval = 1; 148*7330f729Sjoerg} 149*7330f729Sjoerg// [] -> EXIT 150*7330f729Sjoergdef NoRet : Opcode {} 151*7330f729Sjoerg 152*7330f729Sjoerg//===----------------------------------------------------------------------===// 153*7330f729Sjoerg// Frame management 154*7330f729Sjoerg//===----------------------------------------------------------------------===// 155*7330f729Sjoerg 156*7330f729Sjoerg// [] -> [] 157*7330f729Sjoergdef Destroy : Opcode { 158*7330f729Sjoerg let Args = [ArgUint32]; 159*7330f729Sjoerg let HasCustomEval = 1; 160*7330f729Sjoerg} 161*7330f729Sjoerg 162*7330f729Sjoerg//===----------------------------------------------------------------------===// 163*7330f729Sjoerg// Constants 164*7330f729Sjoerg//===----------------------------------------------------------------------===// 165*7330f729Sjoerg 166*7330f729Sjoergclass ConstOpcode<Type Ty, ArgType ArgTy> : Opcode { 167*7330f729Sjoerg let Types = [SingletonTypeClass<Ty>]; 168*7330f729Sjoerg let Args = [ArgTy]; 169*7330f729Sjoerg let Name = "Const"; 170*7330f729Sjoerg} 171*7330f729Sjoerg 172*7330f729Sjoerg// [] -> [Integer] 173*7330f729Sjoergdef ConstSint8 : ConstOpcode<Sint8, ArgSint8>; 174*7330f729Sjoergdef ConstUint8 : ConstOpcode<Uint8, ArgUint8>; 175*7330f729Sjoergdef ConstSint16 : ConstOpcode<Sint16, ArgSint16>; 176*7330f729Sjoergdef ConstUint16 : ConstOpcode<Uint16, ArgUint16>; 177*7330f729Sjoergdef ConstSint32 : ConstOpcode<Sint32, ArgSint32>; 178*7330f729Sjoergdef ConstUint32 : ConstOpcode<Uint32, ArgUint32>; 179*7330f729Sjoergdef ConstSint64 : ConstOpcode<Sint64, ArgSint64>; 180*7330f729Sjoergdef ConstUint64 : ConstOpcode<Uint64, ArgUint64>; 181*7330f729Sjoergdef ConstBool : ConstOpcode<Bool, ArgBool>; 182*7330f729Sjoerg 183*7330f729Sjoerg// [] -> [Integer] 184*7330f729Sjoergdef Zero : Opcode { 185*7330f729Sjoerg let Types = [AluTypeClass]; 186*7330f729Sjoerg} 187*7330f729Sjoerg 188*7330f729Sjoerg// [] -> [Pointer] 189*7330f729Sjoergdef Null : Opcode { 190*7330f729Sjoerg let Types = [PtrTypeClass]; 191*7330f729Sjoerg} 192*7330f729Sjoerg 193*7330f729Sjoerg//===----------------------------------------------------------------------===// 194*7330f729Sjoerg// Pointer generation 195*7330f729Sjoerg//===----------------------------------------------------------------------===// 196*7330f729Sjoerg 197*7330f729Sjoerg// [] -> [Pointer] 198*7330f729Sjoergdef GetPtrLocal : Opcode { 199*7330f729Sjoerg // Offset of local. 200*7330f729Sjoerg let Args = [ArgUint32]; 201*7330f729Sjoerg bit HasCustomEval = 1; 202*7330f729Sjoerg} 203*7330f729Sjoerg// [] -> [Pointer] 204*7330f729Sjoergdef GetPtrParam : Opcode { 205*7330f729Sjoerg // Offset of parameter. 206*7330f729Sjoerg let Args = [ArgUint32]; 207*7330f729Sjoerg} 208*7330f729Sjoerg// [] -> [Pointer] 209*7330f729Sjoergdef GetPtrGlobal : Opcode { 210*7330f729Sjoerg // Index of global. 211*7330f729Sjoerg let Args = [ArgUint32]; 212*7330f729Sjoerg} 213*7330f729Sjoerg// [Pointer] -> [Pointer] 214*7330f729Sjoergdef GetPtrField : Opcode { 215*7330f729Sjoerg // Offset of field. 216*7330f729Sjoerg let Args = [ArgUint32]; 217*7330f729Sjoerg} 218*7330f729Sjoerg// [Pointer] -> [Pointer] 219*7330f729Sjoergdef GetPtrActiveField : Opcode { 220*7330f729Sjoerg // Offset of field. 221*7330f729Sjoerg let Args = [ArgUint32]; 222*7330f729Sjoerg} 223*7330f729Sjoerg// [] -> [Pointer] 224*7330f729Sjoergdef GetPtrActiveThisField : Opcode { 225*7330f729Sjoerg // Offset of field. 226*7330f729Sjoerg let Args = [ArgUint32]; 227*7330f729Sjoerg} 228*7330f729Sjoerg// [] -> [Pointer] 229*7330f729Sjoergdef GetPtrThisField : Opcode { 230*7330f729Sjoerg // Offset of field. 231*7330f729Sjoerg let Args = [ArgUint32]; 232*7330f729Sjoerg} 233*7330f729Sjoerg// [Pointer] -> [Pointer] 234*7330f729Sjoergdef GetPtrBase : Opcode { 235*7330f729Sjoerg // Offset of field, which is a base. 236*7330f729Sjoerg let Args = [ArgUint32]; 237*7330f729Sjoerg} 238*7330f729Sjoerg// [Pointer] -> [Pointer] 239*7330f729Sjoergdef GetPtrVirtBase : Opcode { 240*7330f729Sjoerg // RecordDecl of base class. 241*7330f729Sjoerg let Args = [ArgRecordDecl]; 242*7330f729Sjoerg} 243*7330f729Sjoerg// [] -> [Pointer] 244*7330f729Sjoergdef GetPtrThisBase : Opcode { 245*7330f729Sjoerg // Offset of field, which is a base. 246*7330f729Sjoerg let Args = [ArgUint32]; 247*7330f729Sjoerg} 248*7330f729Sjoerg// [] -> [Pointer] 249*7330f729Sjoergdef GetPtrThisVirtBase : Opcode { 250*7330f729Sjoerg // RecordDecl of base class. 251*7330f729Sjoerg let Args = [ArgRecordDecl]; 252*7330f729Sjoerg} 253*7330f729Sjoerg// [] -> [Pointer] 254*7330f729Sjoergdef This : Opcode; 255*7330f729Sjoerg 256*7330f729Sjoerg// [Pointer] -> [Pointer] 257*7330f729Sjoergdef NarrowPtr : Opcode; 258*7330f729Sjoerg// [Pointer] -> [Pointer] 259*7330f729Sjoergdef ExpandPtr : Opcode; 260*7330f729Sjoerg 261*7330f729Sjoerg//===----------------------------------------------------------------------===// 262*7330f729Sjoerg// Direct field accessors 263*7330f729Sjoerg//===----------------------------------------------------------------------===// 264*7330f729Sjoerg 265*7330f729Sjoergclass AccessOpcode : Opcode { 266*7330f729Sjoerg let Types = [AllTypeClass]; 267*7330f729Sjoerg let Args = [ArgUint32]; 268*7330f729Sjoerg let HasGroup = 1; 269*7330f729Sjoerg} 270*7330f729Sjoerg 271*7330f729Sjoergclass BitFieldOpcode : Opcode { 272*7330f729Sjoerg let Types = [AluTypeClass]; 273*7330f729Sjoerg let Args = [ArgRecordField]; 274*7330f729Sjoerg let HasGroup = 1; 275*7330f729Sjoerg} 276*7330f729Sjoerg 277*7330f729Sjoerg// [] -> [Pointer] 278*7330f729Sjoergdef GetLocal : AccessOpcode { let HasCustomEval = 1; } 279*7330f729Sjoerg// [] -> [Pointer] 280*7330f729Sjoergdef SetLocal : AccessOpcode { let HasCustomEval = 1; } 281*7330f729Sjoerg 282*7330f729Sjoerg// [] -> [Value] 283*7330f729Sjoergdef GetGlobal : AccessOpcode; 284*7330f729Sjoerg// [Value] -> [] 285*7330f729Sjoergdef InitGlobal : AccessOpcode; 286*7330f729Sjoerg// [Value] -> [] 287*7330f729Sjoergdef SetGlobal : AccessOpcode; 288*7330f729Sjoerg 289*7330f729Sjoerg// [] -> [Value] 290*7330f729Sjoergdef GetParam : AccessOpcode; 291*7330f729Sjoerg// [Value] -> [] 292*7330f729Sjoergdef SetParam : AccessOpcode; 293*7330f729Sjoerg 294*7330f729Sjoerg// [Pointer] -> [Pointer, Value] 295*7330f729Sjoergdef GetField : AccessOpcode; 296*7330f729Sjoerg// [Pointer] -> [Value] 297*7330f729Sjoergdef GetFieldPop : AccessOpcode; 298*7330f729Sjoerg// [] -> [Value] 299*7330f729Sjoergdef GetThisField : AccessOpcode; 300*7330f729Sjoerg 301*7330f729Sjoerg// [Pointer, Value] -> [Pointer] 302*7330f729Sjoergdef SetField : AccessOpcode; 303*7330f729Sjoerg// [Value] -> [] 304*7330f729Sjoergdef SetThisField : AccessOpcode; 305*7330f729Sjoerg 306*7330f729Sjoerg// [Value] -> [] 307*7330f729Sjoergdef InitThisField : AccessOpcode; 308*7330f729Sjoerg// [Value] -> [] 309*7330f729Sjoergdef InitThisFieldActive : AccessOpcode; 310*7330f729Sjoerg// [Value] -> [] 311*7330f729Sjoergdef InitThisBitField : BitFieldOpcode; 312*7330f729Sjoerg// [Pointer, Value] -> [] 313*7330f729Sjoergdef InitField : AccessOpcode; 314*7330f729Sjoerg// [Pointer, Value] -> [] 315*7330f729Sjoergdef InitBitField : BitFieldOpcode; 316*7330f729Sjoerg// [Pointer, Value] -> [] 317*7330f729Sjoergdef InitFieldActive : AccessOpcode; 318*7330f729Sjoerg 319*7330f729Sjoerg//===----------------------------------------------------------------------===// 320*7330f729Sjoerg// Pointer access 321*7330f729Sjoerg//===----------------------------------------------------------------------===// 322*7330f729Sjoerg 323*7330f729Sjoergclass LoadOpcode : Opcode { 324*7330f729Sjoerg let Types = [AllTypeClass]; 325*7330f729Sjoerg let HasGroup = 1; 326*7330f729Sjoerg} 327*7330f729Sjoerg 328*7330f729Sjoerg// [Pointer] -> [Pointer, Value] 329*7330f729Sjoergdef Load : LoadOpcode {} 330*7330f729Sjoerg// [Pointer] -> [Value] 331*7330f729Sjoergdef LoadPop : LoadOpcode {} 332*7330f729Sjoerg 333*7330f729Sjoergclass StoreOpcode : Opcode { 334*7330f729Sjoerg let Types = [AllTypeClass]; 335*7330f729Sjoerg let HasGroup = 1; 336*7330f729Sjoerg} 337*7330f729Sjoerg 338*7330f729Sjoergclass StoreBitFieldOpcode : Opcode { 339*7330f729Sjoerg let Types = [AluTypeClass]; 340*7330f729Sjoerg let HasGroup = 1; 341*7330f729Sjoerg} 342*7330f729Sjoerg 343*7330f729Sjoerg// [Pointer, Value] -> [Pointer] 344*7330f729Sjoergdef Store : StoreOpcode {} 345*7330f729Sjoerg// [Pointer, Value] -> [] 346*7330f729Sjoergdef StorePop : StoreOpcode {} 347*7330f729Sjoerg 348*7330f729Sjoerg// [Pointer, Value] -> [Pointer] 349*7330f729Sjoergdef StoreBitField : StoreBitFieldOpcode {} 350*7330f729Sjoerg// [Pointer, Value] -> [] 351*7330f729Sjoergdef StoreBitFieldPop : StoreBitFieldOpcode {} 352*7330f729Sjoerg 353*7330f729Sjoerg// [Pointer, Value] -> [] 354*7330f729Sjoergdef InitPop : StoreOpcode {} 355*7330f729Sjoerg// [Pointer, Value] -> [Pointer] 356*7330f729Sjoergdef InitElem : Opcode { 357*7330f729Sjoerg let Types = [AllTypeClass]; 358*7330f729Sjoerg let Args = [ArgUint32]; 359*7330f729Sjoerg let HasGroup = 1; 360*7330f729Sjoerg} 361*7330f729Sjoerg// [Pointer, Value] -> [] 362*7330f729Sjoergdef InitElemPop : Opcode { 363*7330f729Sjoerg let Types = [AllTypeClass]; 364*7330f729Sjoerg let Args = [ArgUint32]; 365*7330f729Sjoerg let HasGroup = 1; 366*7330f729Sjoerg} 367*7330f729Sjoerg 368*7330f729Sjoerg//===----------------------------------------------------------------------===// 369*7330f729Sjoerg// Pointer arithmetic. 370*7330f729Sjoerg//===----------------------------------------------------------------------===// 371*7330f729Sjoerg 372*7330f729Sjoerg// [Pointer, Integral] -> [Pointer] 373*7330f729Sjoergdef AddOffset : AluOpcode; 374*7330f729Sjoerg// [Pointer, Integral] -> [Pointer] 375*7330f729Sjoergdef SubOffset : AluOpcode; 376*7330f729Sjoerg 377*7330f729Sjoerg//===----------------------------------------------------------------------===// 378*7330f729Sjoerg// Binary operators. 379*7330f729Sjoerg//===----------------------------------------------------------------------===// 380*7330f729Sjoerg 381*7330f729Sjoerg// [Real, Real] -> [Real] 382*7330f729Sjoergdef Sub : AluOpcode; 383*7330f729Sjoergdef Add : AluOpcode; 384*7330f729Sjoergdef Mul : AluOpcode; 385*7330f729Sjoerg 386*7330f729Sjoerg//===----------------------------------------------------------------------===// 387*7330f729Sjoerg// Comparison opcodes. 388*7330f729Sjoerg//===----------------------------------------------------------------------===// 389*7330f729Sjoerg 390*7330f729Sjoergclass EqualityOpcode : Opcode { 391*7330f729Sjoerg let Types = [AllTypeClass]; 392*7330f729Sjoerg let HasGroup = 1; 393*7330f729Sjoerg} 394*7330f729Sjoerg 395*7330f729Sjoergdef EQ : EqualityOpcode; 396*7330f729Sjoergdef NE : EqualityOpcode; 397*7330f729Sjoerg 398*7330f729Sjoergclass ComparisonOpcode : Opcode { 399*7330f729Sjoerg let Types = [ComparableTypeClass]; 400*7330f729Sjoerg let HasGroup = 1; 401*7330f729Sjoerg} 402*7330f729Sjoerg 403*7330f729Sjoergdef LT : ComparisonOpcode; 404*7330f729Sjoergdef LE : ComparisonOpcode; 405*7330f729Sjoergdef GT : ComparisonOpcode; 406*7330f729Sjoergdef GE : ComparisonOpcode; 407*7330f729Sjoerg 408*7330f729Sjoerg//===----------------------------------------------------------------------===// 409*7330f729Sjoerg// Stack management. 410*7330f729Sjoerg//===----------------------------------------------------------------------===// 411*7330f729Sjoerg 412*7330f729Sjoerg// [Value] -> [] 413*7330f729Sjoergdef Pop : Opcode { 414*7330f729Sjoerg let Types = [AllTypeClass]; 415*7330f729Sjoerg let HasGroup = 1; 416*7330f729Sjoerg} 417*7330f729Sjoerg 418*7330f729Sjoerg// [Value] -> [Value, Value] 419*7330f729Sjoergdef Dup : Opcode { 420*7330f729Sjoerg let Types = [AllTypeClass]; 421*7330f729Sjoerg let HasGroup = 1; 422*7330f729Sjoerg} 423