LLVM 20.0.0git
LoongArchISelDAGToDAG.cpp
Go to the documentation of this file.
1//=- LoongArchISelDAGToDAG.cpp - A dag to dag inst selector for LoongArch -===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines an instruction selector for the LoongArch target.
10//
11//===----------------------------------------------------------------------===//
12
19
20using namespace llvm;
21
22#define DEBUG_TYPE "loongarch-isel"
23#define PASS_NAME "LoongArch DAG->DAG Pattern Instruction Selection"
24
26
29 : SelectionDAGISelLegacy(ID, std::make_unique<LoongArchDAGToDAGISel>(TM)) {}
30
32 false)
33
35 // If we have a custom node, we have already selected.
36 if (Node->isMachineOpcode()) {
37 LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << "\n");
38 Node->setNodeId(-1);
39 return;
40 }
41
42 // Instruction Selection not handled by the auto-generated tablegen selection
43 // should be handled here.
44 unsigned Opcode = Node->getOpcode();
45 MVT GRLenVT = Subtarget->getGRLenVT();
46 SDLoc DL(Node);
47 MVT VT = Node->getSimpleValueType(0);
48
49 switch (Opcode) {
50 default:
51 break;
52 case ISD::Constant: {
53 int64_t Imm = cast<ConstantSDNode>(Node)->getSExtValue();
54 if (Imm == 0 && VT == GRLenVT) {
55 SDValue New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL,
56 LoongArch::R0, GRLenVT);
57 ReplaceNode(Node, New.getNode());
58 return;
59 }
60 SDNode *Result = nullptr;
61 SDValue SrcReg = CurDAG->getRegister(LoongArch::R0, GRLenVT);
62 // The instructions in the sequence are handled here.
64 SDValue SDImm = CurDAG->getSignedTargetConstant(Inst.Imm, DL, GRLenVT);
65 switch (Inst.Opc) {
66 case LoongArch::LU12I_W:
67 Result = CurDAG->getMachineNode(Inst.Opc, DL, GRLenVT, SDImm);
68 break;
69 case LoongArch::ADDI_W:
70 case LoongArch::ORI:
71 case LoongArch::LU32I_D:
72 case LoongArch::LU52I_D:
73 Result = CurDAG->getMachineNode(Inst.Opc, DL, GRLenVT, SrcReg, SDImm);
74 break;
75 case LoongArch::BSTRINS_D:
76 Result = CurDAG->getMachineNode(
77 Inst.Opc, DL, GRLenVT,
78 {SrcReg, SrcReg,
79 CurDAG->getTargetConstant(Inst.Imm >> 32, DL, GRLenVT),
80 CurDAG->getTargetConstant(Inst.Imm & 0xFF, DL, GRLenVT)});
81 break;
82 default:
83 llvm_unreachable("unexpected opcode generated by LoongArchMatInt");
84 }
85 SrcReg = SDValue(Result, 0);
86 }
87
88 ReplaceNode(Node, Result);
89 return;
90 }
91 case ISD::FrameIndex: {
92 SDValue Imm = CurDAG->getTargetConstant(0, DL, GRLenVT);
93 int FI = cast<FrameIndexSDNode>(Node)->getIndex();
94 SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
95 unsigned ADDIOp =
96 Subtarget->is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
97 ReplaceNode(Node, CurDAG->getMachineNode(ADDIOp, DL, VT, TFI, Imm));
98 return;
99 }
100 case ISD::BITCAST: {
101 if (VT.is128BitVector() || VT.is256BitVector()) {
102 ReplaceUses(SDValue(Node, 0), Node->getOperand(0));
103 CurDAG->RemoveDeadNode(Node);
104 return;
105 }
106 break;
107 }
108 case ISD::BUILD_VECTOR: {
109 // Select appropriate [x]vrepli.[bhwd] instructions for constant splats of
110 // 128/256-bit when LSX/LASX is enabled.
111 BuildVectorSDNode *BVN = cast<BuildVectorSDNode>(Node);
112 APInt SplatValue, SplatUndef;
113 unsigned SplatBitSize;
114 bool HasAnyUndefs;
115 unsigned Op;
116 EVT ViaVecTy;
117 bool Is128Vec = BVN->getValueType(0).is128BitVector();
118 bool Is256Vec = BVN->getValueType(0).is256BitVector();
119
120 if (!Subtarget->hasExtLSX() || (!Is128Vec && !Is256Vec))
121 break;
122 if (!BVN->isConstantSplat(SplatValue, SplatUndef, SplatBitSize,
123 HasAnyUndefs, 8))
124 break;
125
126 switch (SplatBitSize) {
127 default:
128 break;
129 case 8:
130 Op = Is256Vec ? LoongArch::PseudoXVREPLI_B : LoongArch::PseudoVREPLI_B;
131 ViaVecTy = Is256Vec ? MVT::v32i8 : MVT::v16i8;
132 break;
133 case 16:
134 Op = Is256Vec ? LoongArch::PseudoXVREPLI_H : LoongArch::PseudoVREPLI_H;
135 ViaVecTy = Is256Vec ? MVT::v16i16 : MVT::v8i16;
136 break;
137 case 32:
138 Op = Is256Vec ? LoongArch::PseudoXVREPLI_W : LoongArch::PseudoVREPLI_W;
139 ViaVecTy = Is256Vec ? MVT::v8i32 : MVT::v4i32;
140 break;
141 case 64:
142 Op = Is256Vec ? LoongArch::PseudoXVREPLI_D : LoongArch::PseudoVREPLI_D;
143 ViaVecTy = Is256Vec ? MVT::v4i64 : MVT::v2i64;
144 break;
145 }
146
147 SDNode *Res;
148 // If we have a signed 10 bit integer, we can splat it directly.
149 if (SplatValue.isSignedIntN(10)) {
150 SDValue Imm = CurDAG->getTargetConstant(SplatValue, DL,
151 ViaVecTy.getVectorElementType());
152 Res = CurDAG->getMachineNode(Op, DL, ViaVecTy, Imm);
153 ReplaceNode(Node, Res);
154 return;
155 }
156 break;
157 }
158 }
159
160 // Select the default instruction.
161 SelectCode(Node);
162}
163
165 const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,
166 std::vector<SDValue> &OutOps) {
167 SDValue Base = Op;
169 CurDAG->getTargetConstant(0, SDLoc(Op), Subtarget->getGRLenVT());
170 switch (ConstraintID) {
171 default:
172 llvm_unreachable("unexpected asm memory constraint");
173 // Reg+Reg addressing.
175 Base = Op.getOperand(0);
176 Offset = Op.getOperand(1);
177 break;
178 // Reg+simm12 addressing.
181 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Op.getOperand(1));
182 if (isIntN(12, CN->getSExtValue())) {
183 Base = Op.getOperand(0);
185 Op.getValueType());
186 }
187 }
188 break;
189 // Reg+0 addressing.
191 break;
192 // Reg+(simm14<<2) addressing.
195 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Op.getOperand(1));
196 if (isIntN(16, CN->getSExtValue()) &&
197 isAligned(Align(4ULL), CN->getZExtValue())) {
198 Base = Op.getOperand(0);
200 Op.getValueType());
201 }
202 }
203 break;
204 }
205 OutOps.push_back(Base);
206 OutOps.push_back(Offset);
207 return false;
208}
209
211 // If this is FrameIndex, select it directly. Otherwise just let it get
212 // selected to a register independently.
213 if (auto *FIN = dyn_cast<FrameIndexSDNode>(Addr))
214 Base =
215 CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getGRLenVT());
216 else
217 Base = Addr;
218 return true;
219}
220
221// Fold constant addresses.
223 SDValue &Offset) {
224 SDLoc DL(Addr);
225 MVT VT = Addr.getSimpleValueType();
226
227 if (!isa<ConstantSDNode>(Addr))
228 return false;
229
230 // If the constant is a simm12, we can fold the whole constant and use R0 as
231 // the base.
232 int64_t CVal = cast<ConstantSDNode>(Addr)->getSExtValue();
233 if (!isInt<12>(CVal))
234 return false;
235 Base = CurDAG->getRegister(LoongArch::R0, VT);
236 Offset = CurDAG->getTargetConstant(SignExtend64<12>(CVal), DL, VT);
237 return true;
238}
239
241 // If this is FrameIndex, don't select it.
242 if (isa<FrameIndexSDNode>(Addr))
243 return false;
244 Base = Addr;
245 return true;
246}
247
249 SDValue &Offset) {
250 SDLoc DL(Addr);
251 MVT VT = Addr.getSimpleValueType();
252
253 // The address is the result of an ADD. Here we only consider reg+simm12.
255 int64_t Imm = cast<ConstantSDNode>(Addr.getOperand(1))->getSExtValue();
256 if (isInt<12>(Imm)) {
257 Base = Addr.getOperand(0);
258 Offset = CurDAG->getTargetConstant(SignExtend64<12>(Imm), DL, VT);
259 return true;
260 }
261 }
262
263 // Otherwise, we assume Addr as the base address and use constant 0 as the
264 // offset.
265 Base = Addr;
267 return true;
268}
269
271 SDValue &ShAmt) {
272 // Shift instructions on LoongArch only read the lower 5 or 6 bits of the
273 // shift amount. If there is an AND on the shift amount, we can bypass it if
274 // it doesn't affect any of those bits.
275 if (N.getOpcode() == ISD::AND && isa<ConstantSDNode>(N.getOperand(1))) {
276 const APInt &AndMask = N->getConstantOperandAPInt(1);
277
278 // Since the max shift amount is a power of 2 we can subtract 1 to make a
279 // mask that covers the bits needed to represent all shift amounts.
280 assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!");
281 APInt ShMask(AndMask.getBitWidth(), ShiftWidth - 1);
282
283 if (ShMask.isSubsetOf(AndMask)) {
284 ShAmt = N.getOperand(0);
285 return true;
286 }
287
288 // SimplifyDemandedBits may have optimized the mask so try restoring any
289 // bits that are known zero.
290 KnownBits Known = CurDAG->computeKnownBits(N->getOperand(0));
291 if (ShMask.isSubsetOf(AndMask | Known.Zero)) {
292 ShAmt = N.getOperand(0);
293 return true;
294 }
295 } else if (N.getOpcode() == LoongArchISD::BSTRPICK) {
296 // Similar to the above AND, if there is a BSTRPICK on the shift amount, we
297 // can bypass it.
298 assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!");
299 assert(isa<ConstantSDNode>(N.getOperand(1)) && "Illegal msb operand!");
300 assert(isa<ConstantSDNode>(N.getOperand(2)) && "Illegal lsb operand!");
301 uint64_t msb = N.getConstantOperandVal(1), lsb = N.getConstantOperandVal(2);
302 if (lsb == 0 && Log2_32(ShiftWidth) <= msb + 1) {
303 ShAmt = N.getOperand(0);
304 return true;
305 }
306 } else if (N.getOpcode() == ISD::SUB &&
307 isa<ConstantSDNode>(N.getOperand(0))) {
308 uint64_t Imm = N.getConstantOperandVal(0);
309 // If we are shifting by N-X where N == 0 mod Size, then just shift by -X to
310 // generate a NEG instead of a SUB of a constant.
311 if (Imm != 0 && Imm % ShiftWidth == 0) {
312 SDLoc DL(N);
313 EVT VT = N.getValueType();
314 SDValue Zero =
315 CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, LoongArch::R0, VT);
316 unsigned NegOpc = VT == MVT::i64 ? LoongArch::SUB_D : LoongArch::SUB_W;
317 MachineSDNode *Neg =
318 CurDAG->getMachineNode(NegOpc, DL, VT, Zero, N.getOperand(1));
319 ShAmt = SDValue(Neg, 0);
320 return true;
321 }
322 }
323
324 ShAmt = N;
325 return true;
326}
327
329 if (N.getOpcode() == ISD::SIGN_EXTEND_INREG &&
330 cast<VTSDNode>(N.getOperand(1))->getVT() == MVT::i32) {
331 Val = N.getOperand(0);
332 return true;
333 }
334 if (N.getOpcode() == LoongArchISD::BSTRPICK &&
335 N.getConstantOperandVal(1) < UINT64_C(0X1F) &&
336 N.getConstantOperandVal(2) == UINT64_C(0)) {
337 Val = N;
338 return true;
339 }
340 MVT VT = N.getSimpleValueType();
341 if (CurDAG->ComputeNumSignBits(N) > (VT.getSizeInBits() - 32)) {
342 Val = N;
343 return true;
344 }
345
346 return false;
347}
348
350 if (N.getOpcode() == ISD::AND) {
351 auto *C = dyn_cast<ConstantSDNode>(N.getOperand(1));
352 if (C && C->getZExtValue() == UINT64_C(0xFFFFFFFF)) {
353 Val = N.getOperand(0);
354 return true;
355 }
356 }
357 MVT VT = N.getSimpleValueType();
359 if (CurDAG->MaskedValueIsZero(N, Mask)) {
360 Val = N;
361 return true;
362 }
363
364 return false;
365}
366
368 unsigned MinSizeInBits) const {
369 if (!Subtarget->hasExtLSX())
370 return false;
371
372 BuildVectorSDNode *Node = dyn_cast<BuildVectorSDNode>(N);
373
374 if (!Node)
375 return false;
376
377 APInt SplatValue, SplatUndef;
378 unsigned SplatBitSize;
379 bool HasAnyUndefs;
380
381 if (!Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs,
382 MinSizeInBits, /*IsBigEndian=*/false))
383 return false;
384
385 Imm = SplatValue;
386
387 return true;
388}
389
390template <unsigned ImmBitSize, bool IsSigned>
392 APInt ImmValue;
393 EVT EltTy = N->getValueType(0).getVectorElementType();
394
395 if (N->getOpcode() == ISD::BITCAST)
396 N = N->getOperand(0);
397
398 if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) &&
399 ImmValue.getBitWidth() == EltTy.getSizeInBits()) {
400 if (IsSigned && ImmValue.isSignedIntN(ImmBitSize)) {
401 SplatVal = CurDAG->getTargetConstant(ImmValue.getSExtValue(), SDLoc(N),
402 Subtarget->getGRLenVT());
403 return true;
404 }
405 if (!IsSigned && ImmValue.isIntN(ImmBitSize)) {
406 SplatVal = CurDAG->getTargetConstant(ImmValue.getZExtValue(), SDLoc(N),
407 Subtarget->getGRLenVT());
408 return true;
409 }
410 }
411
412 return false;
413}
414
416 SDValue &SplatImm) const {
417 APInt ImmValue;
418 EVT EltTy = N->getValueType(0).getVectorElementType();
419
420 if (N->getOpcode() == ISD::BITCAST)
421 N = N->getOperand(0);
422
423 if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) &&
424 ImmValue.getBitWidth() == EltTy.getSizeInBits()) {
425 int32_t Log2 = (~ImmValue).exactLogBase2();
426
427 if (Log2 != -1) {
428 SplatImm = CurDAG->getTargetConstant(Log2, SDLoc(N), EltTy);
429 return true;
430 }
431 }
432
433 return false;
434}
435
437 SDValue &SplatImm) const {
438 APInt ImmValue;
439 EVT EltTy = N->getValueType(0).getVectorElementType();
440
441 if (N->getOpcode() == ISD::BITCAST)
442 N = N->getOperand(0);
443
444 if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) &&
445 ImmValue.getBitWidth() == EltTy.getSizeInBits()) {
446 int32_t Log2 = ImmValue.exactLogBase2();
447
448 if (Log2 != -1) {
449 SplatImm = CurDAG->getTargetConstant(Log2, SDLoc(N), EltTy);
450 return true;
451 }
452 }
453
454 return false;
455}
456
457// This pass converts a legalized DAG into a LoongArch-specific DAG, ready
458// for instruction scheduling.
460 return new LoongArchDAGToDAGISelLegacy(TM);
461}
AMDGPU Register Bank Select
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
#define LLVM_DEBUG(...)
Definition: Debug.h:106
uint64_t Addr
#define DEBUG_TYPE
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:38
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
#define PASS_NAME
DEMANGLE_DUMP_METHOD void dump() const
Class for arbitrary precision integers.
Definition: APInt.h:78
uint64_t getZExtValue() const
Get zero extended value.
Definition: APInt.h:1520
unsigned getBitWidth() const
Return the number of bits in the APInt.
Definition: APInt.h:1468
int32_t exactLogBase2() const
Definition: APInt.h:1761
bool isSignedIntN(unsigned N) const
Check if this APInt has an N-bits signed integer value.
Definition: APInt.h:435
bool isSubsetOf(const APInt &RHS) const
This operation checks that all bits set in this APInt are also set in RHS.
Definition: APInt.h:1257
static APInt getHighBitsSet(unsigned numBits, unsigned hiBitsSet)
Constructs an APInt value that has the top hiBitsSet bits set.
Definition: APInt.h:296
bool isIntN(unsigned N) const
Check if this APInt has an N-bits unsigned integer value.
Definition: APInt.h:432
int64_t getSExtValue() const
Get sign extended value.
Definition: APInt.h:1542
A "pseudo-class" with methods for operating on BUILD_VECTORs.
bool isConstantSplat(APInt &SplatValue, APInt &SplatUndef, unsigned &SplatBitSize, bool &HasAnyUndefs, unsigned MinSplatBits=0, bool isBigEndian=false) const
Check if this is a constant splat, and if so, find the smallest element size that splats the vector.
uint64_t getZExtValue() const
int64_t getSExtValue() const
This class represents an Operation in the Expression.
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:310
LoongArchDAGToDAGISelLegacy(LoongArchTargetMachine &TM)
bool selectNonFIBaseAddr(SDValue Addr, SDValue &Base)
bool selectSExti32(SDValue N, SDValue &Val)
bool SelectInlineAsmMemoryOperand(const SDValue &Op, InlineAsm::ConstraintCode ConstraintID, std::vector< SDValue > &OutOps) override
SelectInlineAsmMemoryOperand - Select the specified address as a target addressing mode,...
bool selectVSplatUimmPow2(SDValue N, SDValue &SplatImm) const
bool selectShiftMask(SDValue N, unsigned ShiftWidth, SDValue &ShAmt)
bool selectZExti32(SDValue N, SDValue &Val)
bool SelectAddrRegImm12(SDValue Addr, SDValue &Base, SDValue &Offset)
bool SelectAddrConstant(SDValue Addr, SDValue &Base, SDValue &Offset)
bool selectVSplat(SDNode *N, APInt &Imm, unsigned MinSizeInBits) const
bool selectVSplatImm(SDValue N, SDValue &SplatVal)
bool selectVSplatUimmInvPow2(SDValue N, SDValue &SplatImm) const
bool SelectBaseAddr(SDValue Addr, SDValue &Base)
Machine Value Type.
bool is128BitVector() const
Return true if this is a 128-bit vector type.
TypeSize getSizeInBits() const
Returns the size of the specified MVT in bits.
bool is256BitVector() const
Return true if this is a 256-bit vector type.
An SDNode that represents everything that will be needed to construct a MachineInstr.
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
Represents one node in the SelectionDAG.
EVT getValueType(unsigned ResNo) const
Return the type of a specified result.
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation.
MachineSDNode * getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT)
These are used for target selectors to create a new node with specified return type(s),...
SDValue getRegister(Register Reg, EVT VT)
SDValue getCopyFromReg(SDValue Chain, const SDLoc &dl, Register Reg, EVT VT)
Definition: SelectionDAG.h:828
SDValue getTargetFrameIndex(int FI, EVT VT)
Definition: SelectionDAG.h:756
SDValue getTargetConstant(uint64_t Val, const SDLoc &DL, EVT VT, bool isOpaque=false)
Definition: SelectionDAG.h:701
unsigned ComputeNumSignBits(SDValue Op, unsigned Depth=0) const
Return the number of times the sign bit of the register is replicated into the other bits.
bool isBaseWithConstantOffset(SDValue Op) const
Return true if the specified operand is an ISD::ADD with a ConstantSDNode on the right-hand side,...
KnownBits computeKnownBits(SDValue Op, unsigned Depth=0) const
Determine which bits of Op are known to be either zero or one and return them in Known.
bool MaskedValueIsZero(SDValue Op, const APInt &Mask, unsigned Depth=0) const
Return true if 'Op & Mask' is known to be zero.
SDValue getEntryNode() const
Return the token chain corresponding to the entry of the function.
Definition: SelectionDAG.h:580
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
@ BITCAST
BITCAST - This operator converts between integer, vector and FP values, as if the value was stored to...
Definition: ISDOpcodes.h:954
@ FrameIndex
Definition: ISDOpcodes.h:80
@ SIGN_EXTEND_INREG
SIGN_EXTEND_INREG - This operator atomically performs a SHL/SRA pair to sign extend a small value in ...
Definition: ISDOpcodes.h:849
@ AND
Bitwise operators - logical and, logical or, logical xor.
Definition: ISDOpcodes.h:709
@ BUILD_VECTOR
BUILD_VECTOR(ELT0, ELT1, ELT2, ELT3,...) - Return a fixed-width vector with the specified,...
Definition: ISDOpcodes.h:530
InstSeq generateInstSeq(int64_t Val)
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:480
bool isAligned(Align Lhs, uint64_t SizeInBytes)
Checks that SizeInBytes is a multiple of the alignment.
Definition: Alignment.h:145
FunctionPass * createLoongArchISelDag(LoongArchTargetMachine &TM)
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
Definition: MathExtras.h:342
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition: MathExtras.h:293
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
bool isIntN(unsigned N, int64_t x)
Checks if an signed integer fits into the given (dynamic) bit width.
Definition: MathExtras.h:262
DWARFExpression::Operation Op
unsigned Log2(Align A)
Returns the log2 of the alignment.
Definition: Alignment.h:208
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858
#define N
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39
Extended Value Type.
Definition: ValueTypes.h:35
TypeSize getSizeInBits() const
Return the size of the specified value type in bits.
Definition: ValueTypes.h:368
bool is128BitVector() const
Return true if this is a 128-bit vector type.
Definition: ValueTypes.h:207
bool is256BitVector() const
Return true if this is a 256-bit vector type.
Definition: ValueTypes.h:212
EVT getVectorElementType() const
Given a vector type, return the type of each element.
Definition: ValueTypes.h:323