Debug info: Use DW_OP_bit_piece instead of DW_OP_piece in the

intermediate representation. This
- increases consistency by using the same granularity everywhere
- allows for pieces < 1 byte
- DW_OP_piece didn't actually allow storing an offset.

Part of PR22495.

llvm-svn: 228631
This commit is contained in:
Adrian Prantl 2015-02-09 23:57:15 +00:00
parent 328b1633d7
commit 27bd01f71c
18 changed files with 80 additions and 83 deletions

View File

@ -517,13 +517,13 @@ namespace llvm {
DIExpression createExpression(ArrayRef<uint64_t> Addr = None);
DIExpression createExpression(ArrayRef<int64_t> Addr);
/// createPieceExpression - Create a descriptor to describe one part
/// createBitPieceExpression - Create a descriptor to describe one part
/// of aggregate variable that is fragmented across multiple Values.
///
/// @param OffsetInBytes Offset of the piece in bytes.
/// @param SizeInBytes Size of the piece in bytes.
DIExpression createPieceExpression(unsigned OffsetInBytes,
unsigned SizeInBytes);
/// @param OffsetInBits Offset of the piece in bits.
/// @param SizeInBits Size of the piece in bits.
DIExpression createBitPieceExpression(unsigned OffsetInBits,
unsigned SizeInBits);
/// createFunction - Create a new descriptor for the specified subprogram.
/// See comments in DISubprogram for descriptions of these fields.

View File

@ -851,11 +851,11 @@ public:
uint64_t getElement(unsigned Idx) const;
/// \brief Return whether this is a piece of an aggregate variable.
bool isVariablePiece() const;
/// \brief Return the offset of this piece in bytes.
uint64_t getPieceOffset() const;
/// \brief Return the size of this piece in bytes.
uint64_t getPieceSize() const;
bool isBitPiece() const;
/// \brief Return the offset of this piece in bits.
uint64_t getBitPieceOffset() const;
/// \brief Return the size of this piece in bits.
uint64_t getBitPieceSize() const;
class iterator;
/// \brief A lightweight wrapper around an element of a DIExpression.
@ -906,9 +906,9 @@ public:
private:
void increment() {
switch (**this) {
case dwarf::DW_OP_piece: std::advance(I, 3); break;
case dwarf::DW_OP_plus: std::advance(I, 2); break;
case dwarf::DW_OP_deref: std::advance(I, 1); break;
case dwarf::DW_OP_bit_piece: std::advance(I, 3); break;
case dwarf::DW_OP_plus: std::advance(I, 2); break;
case dwarf::DW_OP_deref: std::advance(I, 1); break;
default:
llvm_unreachable("unsupported operand");
}

View File

@ -656,9 +656,9 @@ static bool emitDebugValueComment(const MachineInstr *MI, AsmPrinter &AP) {
OS << V.getName();
DIExpression Expr = MI->getDebugExpression();
if (Expr.isVariablePiece())
OS << " [piece offset=" << Expr.getPieceOffset()
<< " size=" << Expr.getPieceSize() << "]";
if (Expr.isBitPiece())
OS << " [bit_piece offset=" << Expr.getBitPieceOffset()
<< " size=" << Expr.getBitPieceSize() << "]";
OS << " <- ";
// The second operand is only an offset if it's an immediate.

View File

@ -74,7 +74,7 @@ public:
MachineLocation getLoc() const { return Loc; }
const MDNode *getVariableNode() const { return Variable; }
DIVariable getVariable() const { return DIVariable(Variable); }
bool isVariablePiece() const { return getExpression().isVariablePiece(); }
bool isBitPiece() const { return getExpression().isBitPiece(); }
DIExpression getExpression() const { return DIExpression(Expression); }
friend bool operator==(const Value &, const Value &);
friend bool operator<(const Value &, const Value &);
@ -101,8 +101,8 @@ public:
DIVariable Var(Values[0].Variable);
DIExpression NextExpr(Next.Values[0].Expression);
DIVariable NextVar(Next.Values[0].Variable);
if (Var == NextVar && Expr.isVariablePiece() &&
NextExpr.isVariablePiece()) {
if (Var == NextVar && Expr.isBitPiece() &&
NextExpr.isBitPiece()) {
addValues(Next.Values);
End = Next.End;
return true;
@ -131,7 +131,7 @@ public:
Values.append(Vals.begin(), Vals.end());
sortUniqueValues();
assert(std::all_of(Values.begin(), Values.end(), [](DebugLocEntry::Value V){
return V.isVariablePiece();
return V.isBitPiece();
}) && "value must be a piece");
}
@ -176,8 +176,8 @@ inline bool operator==(const DebugLocEntry::Value &A,
/// Compare two pieces based on their offset.
inline bool operator<(const DebugLocEntry::Value &A,
const DebugLocEntry::Value &B) {
return A.getExpression().getPieceOffset() <
B.getExpression().getPieceOffset();
return A.getExpression().getBitPieceOffset() <
B.getExpression().getBitPieceOffset();
}
}

View File

@ -818,12 +818,12 @@ static DebugLocEntry::Value getDebugLocValue(const MachineInstr *MI) {
/// Determine whether two variable pieces overlap.
static bool piecesOverlap(DIExpression P1, DIExpression P2) {
if (!P1.isVariablePiece() || !P2.isVariablePiece())
if (!P1.isBitPiece() || !P2.isBitPiece())
return true;
unsigned l1 = P1.getPieceOffset();
unsigned l2 = P2.getPieceOffset();
unsigned r1 = l1 + P1.getPieceSize();
unsigned r2 = l2 + P2.getPieceSize();
unsigned l1 = P1.getBitPieceOffset();
unsigned l2 = P2.getBitPieceOffset();
unsigned r1 = l1 + P1.getBitPieceSize();
unsigned r2 = l2 + P2.getBitPieceSize();
// True where [l1,r1[ and [r1,r2[ overlap.
return (l1 < r2) && (l2 < r1);
}
@ -894,7 +894,7 @@ DwarfDebug::buildLocationList(SmallVectorImpl<DebugLocEntry> &DebugLoc,
bool couldMerge = false;
// If this is a piece, it may belong to the current DebugLocEntry.
if (DIExpr.isVariablePiece()) {
if (DIExpr.isBitPiece()) {
// Add this value to the list of open ranges.
OpenRanges.push_back(Value);
@ -1193,7 +1193,7 @@ void DwarfDebug::beginFunction(const MachineFunction *MF) {
if (DIVar.isVariable() && DIVar.getTag() == dwarf::DW_TAG_arg_variable &&
getDISubprogram(DIVar.getContext()).describes(MF->getFunction())) {
LabelsBeforeInsn[Ranges.front().first] = FunctionBeginSym;
if (Ranges.front().first->getDebugExpression().isVariablePiece()) {
if (Ranges.front().first->getDebugExpression().isBitPiece()) {
// Mark all non-overlapping initial pieces.
for (auto I = Ranges.begin(); I != Ranges.end(); ++I) {
DIExpression Piece = I->first->getDebugExpression();
@ -1661,21 +1661,20 @@ void DwarfDebug::emitLocPieces(ByteStreamer &Streamer,
const DITypeIdentifierMap &Map,
ArrayRef<DebugLocEntry::Value> Values) {
assert(std::all_of(Values.begin(), Values.end(), [](DebugLocEntry::Value P) {
return P.isVariablePiece();
return P.isBitPiece();
}) && "all values are expected to be pieces");
assert(std::is_sorted(Values.begin(), Values.end()) &&
"pieces are expected to be sorted");
unsigned Offset = 0;
for (auto Piece : Values) {
const unsigned SizeOfByte = 8;
DIExpression Expr = Piece.getExpression();
unsigned PieceOffset = Expr.getPieceOffset();
unsigned PieceSize = Expr.getPieceSize();
unsigned PieceOffset = Expr.getBitPieceOffset();
unsigned PieceSize = Expr.getBitPieceSize();
assert(Offset <= PieceOffset && "overlapping or duplicate pieces");
if (Offset < PieceOffset) {
// The DWARF spec seriously mandates pieces with no locations for gaps.
Asm->EmitDwarfOpPiece(Streamer, (PieceOffset-Offset)*SizeOfByte);
Asm->EmitDwarfOpPiece(Streamer, PieceOffset-Offset);
Offset += PieceOffset-Offset;
}
Offset += PieceSize;
@ -1683,12 +1682,12 @@ void DwarfDebug::emitLocPieces(ByteStreamer &Streamer,
#ifndef NDEBUG
DIVariable Var = Piece.getVariable();
unsigned VarSize = Var.getSizeInBits(Map);
assert(PieceSize+PieceOffset <= VarSize/SizeOfByte
assert(PieceSize+PieceOffset <= VarSize
&& "piece is larger than or outside of variable");
assert(PieceSize*SizeOfByte != VarSize
assert(PieceSize != VarSize
&& "piece covers entire variable");
#endif
emitDebugLocValue(Streamer, Piece, PieceOffset*SizeOfByte);
emitDebugLocValue(Streamer, Piece, PieceOffset);
}
}
@ -1696,7 +1695,7 @@ void DwarfDebug::emitLocPieces(ByteStreamer &Streamer,
void DwarfDebug::emitDebugLocEntry(ByteStreamer &Streamer,
const DebugLocEntry &Entry) {
const DebugLocEntry::Value Value = Entry.getValues()[0];
if (Value.isVariablePiece())
if (Value.isBitPiece())
// Emit all pieces that belong to the same variable and range.
return emitLocPieces(Streamer, TypeIdentifierMap, Entry.getValues());

View File

@ -211,10 +211,9 @@ bool DwarfExpression::AddMachineRegExpression(DIExpression Expr,
bool ValidReg = false;
switch (*I) {
case dwarf::DW_OP_piece: {
unsigned SizeOfByte = 8;
unsigned OffsetInBits = I->getArg(1) * SizeOfByte;
unsigned SizeInBits = I->getArg(2) * SizeOfByte;
case dwarf::DW_OP_bit_piece: {
unsigned OffsetInBits = I->getArg(1);
unsigned SizeInBits = I->getArg(2);
// Piece always comes at the end of the expression.
return AddMachineRegPiece(MachineReg, SizeInBits,
getOffsetOrZero(OffsetInBits, PieceOffsetInBits));
@ -249,10 +248,9 @@ void DwarfExpression::AddExpression(DIExpression::iterator I,
unsigned PieceOffsetInBits) {
for (; I != DIExpression::iterator(); ++I) {
switch (*I) {
case dwarf::DW_OP_piece: {
unsigned SizeOfByte = 8;
unsigned OffsetInBits = I->getArg(1) * SizeOfByte;
unsigned SizeInBits = I->getArg(2) * SizeOfByte;
case dwarf::DW_OP_bit_piece: {
unsigned OffsetInBits = I->getArg(1);
unsigned SizeInBits = I->getArg(2);
AddOpPiece(SizeInBits, getOffsetOrZero(OffsetInBits, PieceOffsetInBits));
break;
}

View File

@ -961,9 +961,9 @@ DIExpression DIBuilder::createExpression(ArrayRef<int64_t> Signed) {
return createExpression(Addr);
}
DIExpression DIBuilder::createPieceExpression(unsigned OffsetInBytes,
unsigned SizeInBytes) {
uint64_t Addr[] = {dwarf::DW_OP_piece, OffsetInBytes, SizeInBytes};
DIExpression DIBuilder::createBitPieceExpression(unsigned OffsetInBits,
unsigned SizeInBits) {
int64_t Addr[] = {dwarf::DW_OP_bit_piece, OffsetInBits, SizeInBits};
return createExpression(Addr);
}

View File

@ -147,18 +147,18 @@ uint64_t DIExpression::getElement(unsigned Idx) const {
return getHeaderFieldAs<int64_t>(I);
}
bool DIExpression::isVariablePiece() const {
bool DIExpression::isBitPiece() const {
unsigned N = getNumElements();
return N >=3 && getElement(N-3) == dwarf::DW_OP_piece;
return N >=3 && getElement(N-3) == dwarf::DW_OP_bit_piece;
}
uint64_t DIExpression::getPieceOffset() const {
assert(isVariablePiece() && "not a piece");
uint64_t DIExpression::getBitPieceOffset() const {
assert(isBitPiece() && "not a piece");
return getElement(getNumElements()-2);
}
uint64_t DIExpression::getPieceSize() const {
assert(isVariablePiece() && "not a piece");
uint64_t DIExpression::getBitPieceSize() const {
assert(isBitPiece() && "not a piece");
return getElement(getNumElements()-1);
}
@ -612,7 +612,7 @@ bool DIExpression::Verify() const {
for (auto Op : *this)
switch (Op) {
case DW_OP_piece:
case DW_OP_bit_piece:
// Must be the last element of the expression.
return std::distance(Op.getBase(), DIHeaderFieldIterator()) == 3;
case DW_OP_plus:
@ -1417,7 +1417,7 @@ void DIExpression::printInternal(raw_ostream &OS) const {
OS << " " << Op.getArg(1);
break;
}
case DW_OP_piece: {
case DW_OP_bit_piece: {
OS << " offset=" << Op.getArg(1) << ", size=" << Op.getArg(2);
break;
}

View File

@ -4175,15 +4175,15 @@ bool SROA::splitAlloca(AllocaInst &AI, AllocaSlices &AS) {
// Create a piece expression describing the new partition or reuse AI's
// expression if there is only one partition.
DIExpression PieceExpr = Expr;
if (IsSplit || Expr.isVariablePiece()) {
if (IsSplit || Expr.isBitPiece()) {
// If this alloca is already a scalar replacement of a larger aggregate,
// Piece.Offset describes the offset inside the scalar.
unsigned Offset = Expr.isVariablePiece() ? Expr.getPieceOffset() : 0;
unsigned Offset = Expr.isBitPiece() ? Expr.getBitPieceOffset() : 0;
assert((Offset == 0 ||
Offset+Piece.Offset+Piece.Size <=
Expr.getPieceOffset()+Expr.getPieceSize()) &&
Offset+Piece.Offset+Piece.Size*8 <=
Expr.getBitPieceOffset()+Expr.getBitPieceSize()) &&
"inner piece is not inside original alloca");
PieceExpr = DIB.createPieceExpression(Offset+Piece.Offset, Piece.Size);
PieceExpr = DIB.createBitPieceExpression(Offset+Piece.Offset*8, Piece.Size*8);
}
// Remove any existing dbg.declare intrinsic describing the same alloca.

View File

@ -18,7 +18,7 @@
; CHECK: define i32 @main
; CHECK: call void @llvm.dbg.value(metadata i32 42, i64 0, metadata ![[ARRAY:[0-9]+]], metadata ![[EXPR:[0-9]+]])
; CHECK: ![[ARRAY]] = {{.*}}; [ DW_TAG_auto_variable ] [array] [line 6]
; CHECK: ![[EXPR]] = {{.*}}; [ DW_TAG_expression ] [DW_OP_piece offset=0, size=4]
; CHECK: ![[EXPR]] = {{.*}}; [ DW_TAG_expression ] [DW_OP_bit_piece offset=0, size=32]
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.9.0"

View File

@ -169,9 +169,9 @@ attributes #3 = { ssp uwtable }
!30 = !{i32 2, !"Debug Info Version", i32 2}
!31 = !{i32 1, !"PIC Level", i32 2}
!32 = !{!"clang version 3.7.0 (trunk 227088) (llvm/trunk 227091)"}
!33 = !{!"0x102\00147\000\008"} ; [ DW_TAG_expression ] [DW_OP_piece offset=0, size=8]
!33 = !{!"0x102\00157\000\008"} ; [ DW_TAG_expression ] [DW_OP_bit_piece offset=0, size=8]
!34 = !MDLocation(line: 7, column: 42, scope: !11)
!35 = !{!"0x102\00147\008\004"} ; [ DW_TAG_expression ] [DW_OP_piece offset=8, size=4]
!35 = !{!"0x102\00157\008\004"} ; [ DW_TAG_expression ] [DW_OP_bit_piece offset=8, size=4]
!36 = !{!"0x102"} ; [ DW_TAG_expression ]
!37 = !MDLocation(line: 7, column: 48, scope: !11)
!38 = !MDLocation(line: 7, column: 66, scope: !11)

View File

@ -74,6 +74,6 @@ attributes #1 = { nounwind readnone }
!21 = !MDLocation(line: 3, scope: !4)
!22 = !{!"0x101\00s\0016777219\000", !4, !5, !9} ; [ DW_TAG_arg_variable ] [s] [line 3]
!23 = !MDLocation(line: 4, scope: !4)
!24 = !{!"0x102\00147\000\008"} ; [ DW_TAG_expression ] [DW_OP_piece 0 8] [piece, size 8, offset 0]
!24 = !{!"0x102\00157\000\0064"} ; [ DW_TAG_expression ] [DW_OP_bit_piece size=64, offset=0]
!25 = !{}
!27 = !{!"0x102\00147\008\004"} ; [ DW_TAG_expression ] [DW_OP_piece 8 4] [piece, size 4, offset 8]
!27 = !{!"0x102\00157\0064\0032"} ; [ DW_TAG_expression ] [DW_OP_bit_piece size=32, offset=64]

View File

@ -86,6 +86,6 @@ attributes #2 = { nounwind }
!26 = !MDLocation(line: 10, scope: !4)
!27 = !MDLocation(line: 11, scope: !4)
!28 = !{!"0x100\00i1\0011\000", !4, !5, !14} ; [ DW_TAG_auto_variable ] [i1] [line 11]
!29 = !{!"0x102\00147\000\004"} ; [ DW_TAG_expression ] [DW_OP_piece 0 4] [piece, size 4, offset 0]
!29 = !{!"0x102\00157\000\0032"} ; [ DW_TAG_expression ] [DW_OP_bit_piece size=32, offset=0]
!31 = !{i32 3, i32 0, i32 12}
!32 = !MDLocation(line: 12, scope: !4)

View File

@ -92,15 +92,15 @@ attributes #2 = { nounwind }
!22 = !{i32 1, !"Debug Info Version", i32 2}
!23 = !{!"clang version 3.5.0 "}
!24 = !{!"0x101\00outer\0016777226\000", !4, !5, !9} ; [ DW_TAG_arg_variable ] [outer] [line 10]
!25 = !{!"0x102\00147\000\008"} ; [ DW_TAG_expression ] [DW_OP_piece 0 8] [piece, size 8, offset 0]
!25 = !{!"0x102\00157\000\0064"} ; [ DW_TAG_expression ] [DW_OP_bit_piece size=64, offset=0]
!26 = !MDLocation(line: 10, scope: !4)
!27 = !{!"0x101\00outer\0016777226\000", !4, !5, !9} ; [ DW_TAG_arg_variable ] [outer] [line 10]
!28 = !{!"0x102\00147\008\008"} ; [ DW_TAG_expression ] [DW_OP_piece 8 8] [piece, size 8, offset 8]
!28 = !{!"0x102\00157\0064\0064"} ; [ DW_TAG_expression ] [DW_OP_bit_piece size=64, offset=64]
!29 = !{!"0x101\00outer\0016777226\000", !4, !5, !9} ; [ DW_TAG_arg_variable ] [outer] [line 10]
!30 = !{!"0x102\00147\0012\004"} ; [ DW_TAG_expression ] [DW_OP_piece 12 4] [piece, size 4, offset 12]
!30 = !{!"0x102\00157\0096\0032"} ; [ DW_TAG_expression ] [DW_OP_bit_piece size=32, offset=96]
!31 = !{!"0x101\00outer\0016777226\000", !4, !5, !9} ; [ DW_TAG_arg_variable ] [outer] [line 10]
!32 = !{!"0x102\00147\008\004"} ; [ DW_TAG_expression ] [DW_OP_piece 8 4] [piece, size 4, offset 8]
!32 = !{!"0x102\00157\0064\0032"} ; [ DW_TAG_expression ] [DW_OP_bit_piece size=32, offset=64]
!33 = !MDLocation(line: 11, scope: !4)
!34 = !{!"0x100\00i1\0011\000", !4, !5, !14} ; [ DW_TAG_auto_variable ] [i1] [line 11]
!35 = !{!"0x102\00147\000\004"} ; [ DW_TAG_expression ] [DW_OP_piece 0 4] [piece, size 4, offset 0]
!35 = !{!"0x102\00157\000\0032"} ; [ DW_TAG_expression ] [DW_OP_bit_piece size=32, offset=0]
!36 = !MDLocation(line: 12, scope: !4)

View File

@ -26,8 +26,8 @@
; CHECK: ret i32 %[[A]]
; Read Var and Piece:
; CHECK: ![[VAR]] = {{.*}} ; [ DW_TAG_auto_variable ] [i1] [line 11]
; CHECK: ![[PIECE1]] = {{.*}} ; [ DW_TAG_expression ] [DW_OP_piece offset=4, size=12]
; CHECK: ![[PIECE2]] = {{.*}} ; [ DW_TAG_expression ] [DW_OP_piece offset=0, size=4]
; CHECK: ![[PIECE1]] = {{.*}} ; [ DW_TAG_expression ] [DW_OP_bit_piece offset=32, size=96]
; CHECK: ![[PIECE2]] = {{.*}} ; [ DW_TAG_expression ] [DW_OP_bit_piece offset=0, size=32]
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.9.0"

View File

@ -24,10 +24,10 @@
; CHECK: call void @llvm.dbg.value(metadata i64 %outer.coerce1, i64 0, metadata ![[O]], metadata ![[PIECE2:[0-9]+]]),
; CHECK: call void @llvm.dbg.value({{.*}}, i64 0, metadata ![[I1:[0-9]+]], metadata ![[PIECE3:[0-9]+]]),
; CHECK-DAG: ![[O]] = {{.*}} [ DW_TAG_arg_variable ] [outer] [line 10]
; CHECK-DAG: ![[PIECE1]] = {{.*}} [ DW_TAG_expression ] [DW_OP_piece offset=0, size=8]
; CHECK-DAG: ![[PIECE2]] = {{.*}} [ DW_TAG_expression ] [DW_OP_piece offset=8, size=8]
; CHECK-DAG: ![[PIECE1]] = {{.*}} [ DW_TAG_expression ] [DW_OP_bit_piece offset=0, size=64]
; CHECK-DAG: ![[PIECE2]] = {{.*}} [ DW_TAG_expression ] [DW_OP_bit_piece offset=64, size=64]
; CHECK-DAG: ![[I1]] = {{.*}} [ DW_TAG_auto_variable ] [i1] [line 11]
; CHECK-DAG: ![[PIECE3]] = {{.*}} [ DW_TAG_expression ] [DW_OP_piece offset=0, size=4]
; CHECK-DAG: ![[PIECE3]] = {{.*}} [ DW_TAG_expression ] [DW_OP_bit_piece offset=0, size=32]
; ModuleID = 'sroasplit-2.c'
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"

View File

@ -6,7 +6,7 @@
; CHECK: call void @llvm.dbg.value(metadata float %s.coerce, i64 0, metadata ![[VAR:[0-9]+]], metadata ![[EXPR:[0-9]+]])
; CHECK: ![[VAR]] = {{.*}} [ DW_TAG_arg_variable ] [s] [line 3]
; CHECK: ![[EXPR]] = {{.*}} [ DW_TAG_expression ]
; CHECK-NOT: DW_OP_piece
; CHECK-NOT: DW_OP_bit_piece
;
; struct S { float f; };

View File

@ -7,10 +7,10 @@
; CHECK: call void @llvm.dbg.value(metadata i64 %[[T1]], i64 0, metadata ![[Y]], metadata ![[P2:.*]])
; CHECK: call void @llvm.dbg.value(metadata i64 %[[T]], i64 0, metadata ![[R:.*]], metadata ![[P3:.*]])
; CHECK: call void @llvm.dbg.value(metadata i64 %[[T1]], i64 0, metadata ![[R]], metadata ![[P4:.*]])
; CHECK: ![[P1]] = {{.*}} [DW_OP_piece offset=0, size=8]
; CHECK: ![[P2]] = {{.*}} [DW_OP_piece offset=8, size=8]
; CHECK: ![[P3]] = {{.*}} [DW_OP_piece offset=24, size=8]
; CHECK: ![[P4]] = {{.*}} [DW_OP_piece offset=32, size=8]
; CHECK: ![[P1]] = {{.*}} [DW_OP_bit_piece offset=0, size=64]
; CHECK: ![[P2]] = {{.*}} [DW_OP_bit_piece offset=64, size=64]
; CHECK: ![[P3]] = {{.*}} [DW_OP_bit_piece offset=192, size=64]
; CHECK: ![[P4]] = {{.*}} [DW_OP_bit_piece offset=256, size=64]
;
; struct p {
; __SIZE_TYPE__ s;