Skip to content

Commit ac41505

Browse files
committed
Fix the handling of signed bitfields
1 parent fdd9746 commit ac41505

34 files changed

+277
-232
lines changed

sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs

Lines changed: 61 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2439,7 +2439,8 @@ void VisitBitfieldDecl(FieldDecl fieldDecl, BitfieldDesc[] bitfieldDescs, Record
24392439
bitfieldName += index.ToString();
24402440
}
24412441

2442-
typeBacking = (index > 0) ? bitfieldDescs[index - 1].TypeBacking : bitfieldDescs[0].TypeBacking;
2442+
var bitfieldDesc = (index > 0) ? bitfieldDescs[index - 1] : bitfieldDescs[0];
2443+
typeBacking = bitfieldDesc.TypeBacking;
24432444
typeNameBacking = GetRemappedTypeName(fieldDecl, context: null, typeBacking, out _);
24442445
}
24452446

@@ -2452,6 +2453,8 @@ void VisitBitfieldDecl(FieldDecl fieldDecl, BitfieldDesc[] bitfieldDescs, Record
24522453
return;
24532454
}
24542455

2456+
var isTypeBackingSigned = false;
2457+
24552458
switch (builtinTypeBacking.Kind)
24562459
{
24572460
case CXType_Char_U:
@@ -2489,21 +2492,25 @@ void VisitBitfieldDecl(FieldDecl fieldDecl, BitfieldDesc[] bitfieldDescs, Record
24892492
case CXType_Short:
24902493
case CXType_Int:
24912494
{
2495+
isTypeBackingSigned = true;
24922496
break;
24932497
}
24942498

24952499
case CXType_Long:
24962500
{
2501+
isTypeBackingSigned = true;
2502+
24972503
if (_config.GenerateUnixTypes)
24982504
{
24992505
goto default;
25002506
}
2501-
2502-
goto case CXType_Int;
2507+
break;
25032508
}
25042509

25052510
case CXType_LongLong:
25062511
{
2512+
isTypeBackingSigned = true;
2513+
25072514
if (typeNameBacking == "nint")
25082515
{
25092516
goto case CXType_Int;
@@ -2545,6 +2552,8 @@ void VisitBitfieldDecl(FieldDecl fieldDecl, BitfieldDesc[] bitfieldDescs, Record
25452552
return;
25462553
}
25472554

2555+
var isTypeSigned = false;
2556+
25482557
switch (builtinType.Kind)
25492558
{
25502559
case CXType_Char_U:
@@ -2582,21 +2591,25 @@ void VisitBitfieldDecl(FieldDecl fieldDecl, BitfieldDesc[] bitfieldDescs, Record
25822591
case CXType_Short:
25832592
case CXType_Int:
25842593
{
2594+
isTypeSigned = true;
25852595
break;
25862596
}
25872597

25882598
case CXType_Long:
25892599
{
2600+
isTypeSigned = true;
2601+
25902602
if (_config.GenerateUnixTypes)
25912603
{
25922604
goto default;
25932605
}
2594-
2595-
goto case CXType_Int;
2606+
break;
25962607
}
25972608

25982609
case CXType_LongLong:
25992610
{
2611+
isTypeSigned = true;
2612+
26002613
if (typeNameBacking == "nint")
26012614
{
26022615
goto case CXType_Int;
@@ -2646,8 +2659,23 @@ void VisitBitfieldDecl(FieldDecl fieldDecl, BitfieldDesc[] bitfieldDescs, Record
26462659

26472660
var recordDeclName = GetCursorName(recordDecl);
26482661

2662+
var isSmallType = currentSize < 4;
26492663
var isRemappedToSelf = _config.RemappedNames.TryGetValue(typeName, out var remappedTypeName) && typeName.Equals(remappedTypeName);
2650-
var needsCast = (currentSize < 4) || (type != builtinTypeBacking) || isRemappedToSelf;
2664+
var isTypeMismatch = type != builtinTypeBacking;
2665+
var isUnsignedToSigned = !isTypeBackingSigned && isTypeSigned;
2666+
2667+
var needsCast = isSmallType || isRemappedToSelf || isTypeMismatch || isUnsignedToSigned;
2668+
var needsParenFirst = !isSmallType && isUnsignedToSigned;
2669+
var needsParenSecond = !needsParenFirst || isRemappedToSelf;
2670+
2671+
// backing int, current int (value << cns) >> cns
2672+
// backing int, current uint (uint)((value >> cns) & msk)
2673+
2674+
// backing uint, current int ((int)value << cns) >> cns
2675+
// backing uint, current uint (value >> cns) & msk
2676+
2677+
// backing uint, current byte (byte)((value >> cns) & msk)
2678+
// backing uint, current sbyte (sbyte)((value << cns) >> cns)
26512679

26522680
if (needsCast)
26532681
{
@@ -2658,7 +2686,7 @@ void VisitBitfieldDecl(FieldDecl fieldDecl, BitfieldDesc[] bitfieldDescs, Record
26582686
code.Write(")(");
26592687
}
26602688

2661-
if (bitfieldOffset != 0)
2689+
if ((!needsParenFirst && (bitfieldOffset != 0)) || (!needsCast && isTypeSigned))
26622690
{
26632691
code.Write('(');
26642692
}
@@ -2675,21 +2703,37 @@ void VisitBitfieldDecl(FieldDecl fieldDecl, BitfieldDesc[] bitfieldDescs, Record
26752703
code.Write(bitfieldName);
26762704
code.EndMarker("bitfieldName");
26772705

2678-
if (bitfieldOffset != 0)
2706+
if (isTypeSigned)
26792707
{
2680-
code.Write(" >> ");
2681-
code.BeginMarker("bitfieldOffset");
2682-
code.Write(bitfieldOffset);
2683-
code.EndMarker("bitfieldOffset");
2708+
code.Write(" << ");
2709+
code.BeginMarker("remainingBitsMinusBitWidth");
2710+
code.Write(remainingBits - fieldDecl.BitWidthValue);
2711+
code.EndMarker("remainingBitsMinusBitWidth");
26842712
code.Write(')');
2713+
2714+
code.Write(" >> ");
2715+
code.BeginMarker("currentSizeMinusBitWidth");
2716+
code.Write((currentSize * 8) - fieldDecl.BitWidthValue);
2717+
code.EndMarker("currentSizeMinusBitWidth");
26852718
}
2719+
else
2720+
{
2721+
if (bitfieldOffset != 0)
2722+
{
2723+
code.Write(" >> ");
2724+
code.BeginMarker("bitfieldOffset");
2725+
code.Write(bitfieldOffset);
2726+
code.EndMarker("bitfieldOffset");
2727+
code.Write(')');
2728+
}
26862729

2687-
code.Write(" & 0x");
2688-
code.BeginMarker("bitwidthHexStringBacking");
2689-
code.Write(bitwidthHexStringBacking);
2690-
code.EndMarker("bitwidthHexStringBacking");
2730+
code.Write(" & 0x");
2731+
code.BeginMarker("bitwidthHexStringBacking");
2732+
code.Write(bitwidthHexStringBacking);
2733+
code.EndMarker("bitwidthHexStringBacking");
2734+
}
26912735

2692-
if (needsCast)
2736+
if (needsCast && needsParenSecond)
26932737
{
26942738
code.Write(')');
26952739
}

sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2296,7 +2296,8 @@ private BitfieldDesc[] GetBitfieldDescs(RecordDecl recordDecl)
22962296
continue;
22972297
}
22982298

2299-
var currentSize = fieldDecl.Type.Handle.SizeOf;
2299+
var type = fieldDecl.Type;
2300+
var currentSize = type.Handle.SizeOf;
23002301

23012302
if ((!_config.GenerateUnixTypes && (currentSize != previousSize)) || (fieldDecl.BitWidthValue > remainingBits))
23022303
{
@@ -2305,15 +2306,15 @@ private BitfieldDesc[] GetBitfieldDescs(RecordDecl recordDecl)
23052306
remainingBits = currentBits;
23062307
previousSize = 0;
23072308

2308-
var type = fieldDecl.Type;
2309+
var typeBacking = type;
23092310

23102311
if (IsType<EnumType>(fieldDecl, type, out var enumType))
23112312
{
2312-
type = enumType.Decl.IntegerType;
2313+
typeBacking = enumType.Decl.IntegerType;
23132314
}
23142315

23152316
var bitfieldDesc = new BitfieldDesc {
2316-
TypeBacking = type,
2317+
TypeBacking = typeBacking,
23172318
Regions = new List<BitfieldRegion>() {
23182319
new BitfieldRegion {
23192320
Name = GetRemappedCursorName(fieldDecl),
@@ -2333,15 +2334,15 @@ private BitfieldDesc[] GetBitfieldDescs(RecordDecl recordDecl)
23332334
remainingBits += (currentSize - previousSize) * 8;
23342335
currentBits += (currentSize - previousSize) * 8;
23352336

2336-
var type = fieldDecl.Type;
2337+
var typeBacking = type;
23372338

23382339
if (IsType<EnumType>(fieldDecl, type, out var enumType))
23392340
{
2340-
type = enumType.Decl.IntegerType;
2341+
typeBacking = enumType.Decl.IntegerType;
23412342
}
23422343

23432344
bitfieldDescs[^1] = new BitfieldDesc {
2344-
TypeBacking = type,
2345+
TypeBacking = typeBacking,
23452346
Regions = bitfieldDesc.Regions,
23462347
};
23472348
}

tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpCompatibleUnix/StructDeclarationTest.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ public int o4_b19_3
193193
{
194194
get
195195
{
196-
return (int)((_bitfield2 >> 19) & 0x7u);
196+
return (int)(_bitfield2 << 10) >> 29;
197197
}
198198
199199
set
@@ -221,7 +221,7 @@ public int o4_b23_1
221221
{
222222
get
223223
{
224-
return (int)((_bitfield2 >> 23) & 0x1u);
224+
return (int)(_bitfield2 << 8) >> 31;
225225
}
226226
227227
set
@@ -235,7 +235,7 @@ public int o4_b24_1
235235
{
236236
get
237237
{
238-
return (int)((_bitfield2 >> 24) & 0x1u);
238+
return (int)(_bitfield2 << 7) >> 31;
239239
}
240240
241241
set
@@ -409,7 +409,7 @@ public int o4_b19_3
409409
{
410410
get
411411
{
412-
return (int)((_bitfield2 >> 19) & 0x7u);
412+
return (int)(_bitfield2 << 10) >> 29;
413413
}
414414
415415
set
@@ -437,7 +437,7 @@ public int o4_b23_1
437437
{
438438
get
439439
{
440-
return (int)((_bitfield2 >> 23) & 0x1u);
440+
return (int)(_bitfield2 << 8) >> 31;
441441
}
442442
443443
set
@@ -451,7 +451,7 @@ public int o4_b24_1
451451
{
452452
get
453453
{
454-
return (int)((_bitfield2 >> 24) & 0x1u);
454+
return (int)(_bitfield2 << 7) >> 31;
455455
}
456456
457457
set
@@ -1392,7 +1392,7 @@ public int o0_b0_16
13921392
{
13931393
get
13941394
{
1395-
return _bitfield & 0xFFFF;
1395+
return (_bitfield << 16) >> 16;
13961396
}
13971397
13981398
set
@@ -1406,7 +1406,7 @@ public int o0_b16_4
14061406
{
14071407
get
14081408
{
1409-
return (_bitfield >> 16) & 0xF;
1409+
return (_bitfield << 12) >> 28;
14101410
}
14111411
14121412
set

tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpCompatibleUnix/UnionDeclarationTest.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ public int o4_b19_3
195195
{{
196196
get
197197
{{
198-
return (int)((_bitfield2 >> 19) & 0x7u);
198+
return (int)(_bitfield2 << 10) >> 29;
199199
}}
200200
201201
set
@@ -223,7 +223,7 @@ public int o4_b23_1
223223
{{
224224
get
225225
{{
226-
return (int)((_bitfield2 >> 23) & 0x1u);
226+
return (int)(_bitfield2 << 8) >> 31;
227227
}}
228228
229229
set
@@ -237,7 +237,7 @@ public int o4_b24_1
237237
{{
238238
get
239239
{{
240-
return (int)((_bitfield2 >> 24) & 0x1u);
240+
return (int)(_bitfield2 << 7) >> 31;
241241
}}
242242
243243
set
@@ -974,7 +974,7 @@ public int o0_b0_16
974974
{
975975
get
976976
{
977-
return _bitfield & 0xFFFF;
977+
return (_bitfield << 16) >> 16;
978978
}
979979
980980
set
@@ -988,7 +988,7 @@ public int o0_b16_4
988988
{
989989
get
990990
{
991-
return (_bitfield >> 16) & 0xF;
991+
return (_bitfield << 12) >> 28;
992992
}
993993
994994
set

0 commit comments

Comments
 (0)