@@ -1499,7 +1499,7 @@ pub const Object = struct {
1499
1499
break :blk fwd_decl ;
1500
1500
};
1501
1501
1502
- const non_null_ty = Type .bool ;
1502
+ const non_null_ty = Type .u8 ;
1503
1503
const payload_size = child_ty .abiSize (target );
1504
1504
const payload_align = child_ty .abiAlignment (target );
1505
1505
const non_null_size = non_null_ty .abiSize (target );
@@ -2530,16 +2530,16 @@ pub const DeclGen = struct {
2530
2530
var buf : Type.Payload.ElemType = undefined ;
2531
2531
const child_ty = t .optionalChild (& buf );
2532
2532
if (! child_ty .hasRuntimeBitsIgnoreComptime ()) {
2533
- return dg .context .intType (1 );
2533
+ return dg .context .intType (8 );
2534
2534
}
2535
2535
const payload_llvm_ty = try dg .lowerType (child_ty );
2536
2536
if (t .optionalReprIsPayload ()) {
2537
2537
return payload_llvm_ty ;
2538
2538
}
2539
2539
2540
- comptime assert (optional_layout_version == 2 );
2540
+ comptime assert (optional_layout_version == 3 );
2541
2541
var fields_buf : [3 ]* const llvm.Type = .{
2542
- payload_llvm_ty , dg .context .intType (1 ), undefined ,
2542
+ payload_llvm_ty , dg .context .intType (8 ), undefined ,
2543
2543
};
2544
2544
const offset = child_ty .abiSize (target ) + 1 ;
2545
2545
const abi_size = t .abiSize (target );
@@ -3134,12 +3134,13 @@ pub const DeclGen = struct {
3134
3134
else = > unreachable ,
3135
3135
},
3136
3136
.Optional = > {
3137
- comptime assert (optional_layout_version == 2 );
3137
+ comptime assert (optional_layout_version == 3 );
3138
3138
var buf : Type.Payload.ElemType = undefined ;
3139
3139
const payload_ty = tv .ty .optionalChild (& buf );
3140
- const llvm_i1 = dg .context .intType (1 );
3140
+
3141
+ const llvm_i8 = dg .context .intType (8 );
3141
3142
const is_pl = ! tv .val .isNull ();
3142
- const non_null_bit = if (is_pl ) llvm_i1 . constAllOnes ( ) else llvm_i1 .constNull ();
3143
+ const non_null_bit = if (is_pl ) llvm_i8 . constInt ( 1 , .False ) else llvm_i8 .constNull ();
3143
3144
if (! payload_ty .hasRuntimeBitsIgnoreComptime ()) {
3144
3145
return non_null_bit ;
3145
3146
}
@@ -4041,10 +4042,10 @@ pub const FuncGen = struct {
4041
4042
.cmp_vector = > try self .airCmpVector (inst ),
4042
4043
.cmp_lt_errors_len = > try self .airCmpLtErrorsLen (inst ),
4043
4044
4044
- .is_non_null = > try self .airIsNonNull (inst , false , false , .NE ),
4045
- .is_non_null_ptr = > try self .airIsNonNull (inst , true , false , .NE ),
4046
- .is_null = > try self .airIsNonNull (inst , false , true , .EQ ),
4047
- .is_null_ptr = > try self .airIsNonNull (inst , true , true , .EQ ),
4045
+ .is_non_null = > try self .airIsNonNull (inst , false , .NE ),
4046
+ .is_non_null_ptr = > try self .airIsNonNull (inst , true , .NE ),
4047
+ .is_null = > try self .airIsNonNull (inst , false , .EQ ),
4048
+ .is_null_ptr = > try self .airIsNonNull (inst , true , .EQ ),
4048
4049
4049
4050
.is_non_err = > try self .airIsErr (inst , .EQ , false ),
4050
4051
.is_non_err_ptr = > try self .airIsErr (inst , .EQ , true ),
@@ -5633,7 +5634,6 @@ pub const FuncGen = struct {
5633
5634
self : * FuncGen ,
5634
5635
inst : Air.Inst.Index ,
5635
5636
operand_is_ptr : bool ,
5636
- invert : bool ,
5637
5637
pred : llvm.IntPredicate ,
5638
5638
) ! ? * const llvm.Value {
5639
5639
if (self .liveness .isUnused (inst )) return null ;
@@ -5648,20 +5648,19 @@ pub const FuncGen = struct {
5648
5648
return self .builder .buildICmp (pred , loaded , optional_llvm_ty .constNull (), "" );
5649
5649
}
5650
5650
5651
+ comptime assert (optional_layout_version == 3 );
5652
+
5651
5653
var buf : Type.Payload.ElemType = undefined ;
5652
5654
const payload_ty = optional_ty .optionalChild (& buf );
5653
5655
if (! payload_ty .hasRuntimeBitsIgnoreComptime ()) {
5654
5656
const loaded = if (operand_is_ptr ) self .builder .buildLoad (operand , "" ) else operand ;
5655
- if (invert ) {
5656
- return self .builder .buildNot (loaded , "" );
5657
- } else {
5658
- return loaded ;
5659
- }
5657
+ const llvm_i8 = self .dg .context .intType (8 );
5658
+ return self .builder .buildICmp (pred , loaded , llvm_i8 .constNull (), "" );
5660
5659
}
5661
5660
5662
5661
const is_by_ref = operand_is_ptr or isByRef (optional_ty );
5663
5662
const non_null_bit = self .optIsNonNull (operand , is_by_ref );
5664
- if (invert ) {
5663
+ if (pred == .EQ ) {
5665
5664
return self .builder .buildNot (non_null_bit , "" );
5666
5665
} else {
5667
5666
return non_null_bit ;
@@ -5740,15 +5739,17 @@ pub const FuncGen = struct {
5740
5739
}
5741
5740
5742
5741
fn airOptionalPayloadPtrSet (self : * FuncGen , inst : Air.Inst.Index ) ! ? * const llvm.Value {
5742
+ comptime assert (optional_layout_version == 3 );
5743
+
5743
5744
const ty_op = self .air .instructions .items (.data )[inst ].ty_op ;
5744
5745
const operand = try self .resolveInst (ty_op .operand );
5745
5746
const optional_ty = self .air .typeOf (ty_op .operand ).childType ();
5746
5747
const result_ty = self .air .getRefType (ty_op .ty );
5747
5748
var buf : Type.Payload.ElemType = undefined ;
5748
5749
const payload_ty = optional_ty .optionalChild (& buf );
5749
- const non_null_bit = self .context .intType (1 ). constAllOnes ( );
5750
+ const non_null_bit = self .context .intType (8 ). constInt ( 1 , .False );
5750
5751
if (! payload_ty .hasRuntimeBitsIgnoreComptime ()) {
5751
- // We have a pointer to a i1 . We need to set it to 1 and then return the same pointer.
5752
+ // We have a pointer to a i8 . We need to set it to 1 and then return the same pointer.
5752
5753
_ = self .builder .buildStore (non_null_bit , operand );
5753
5754
5754
5755
// TODO once we update to LLVM 14 this bitcast won't be necessary.
@@ -5914,8 +5915,8 @@ pub const FuncGen = struct {
5914
5915
5915
5916
const ty_op = self .air .instructions .items (.data )[inst ].ty_op ;
5916
5917
const payload_ty = self .air .typeOf (ty_op .operand );
5917
- const non_null_bit = self .context .intType (1 ). constAllOnes ( );
5918
- comptime assert (optional_layout_version == 2 );
5918
+ const non_null_bit = self .context .intType (8 ). constInt ( 1 , .False );
5919
+ comptime assert (optional_layout_version == 3 );
5919
5920
if (! payload_ty .hasRuntimeBitsIgnoreComptime ()) return non_null_bit ;
5920
5921
const operand = try self .resolveInst (ty_op .operand );
5921
5922
const optional_ty = self .air .typeOfIndex (inst );
@@ -7345,10 +7346,12 @@ pub const FuncGen = struct {
7345
7346
return self .builder .buildSelect (success_bit , payload .typeOf ().constNull (), payload , "" );
7346
7347
}
7347
7348
7349
+ comptime assert (optional_layout_version == 3 );
7348
7350
const optional_llvm_ty = try self .dg .lowerType (optional_ty );
7349
7351
const non_null_bit = self .builder .buildNot (success_bit , "" );
7352
+ const non_null_field = self .builder .buildZExt (non_null_bit , self .dg .context .intType (8 ), "" );
7350
7353
const partial = self .builder .buildInsertValue (optional_llvm_ty .getUndef (), payload , 0 , "" );
7351
- return self .builder .buildInsertValue (partial , non_null_bit , 1 , "" );
7354
+ return self .builder .buildInsertValue (partial , non_null_field , 1 , "" );
7352
7355
}
7353
7356
7354
7357
fn airAtomicRmw (self : * FuncGen , inst : Air.Inst.Index ) ! ? * const llvm.Value {
@@ -8331,19 +8334,24 @@ pub const FuncGen = struct {
8331
8334
8332
8335
/// Assumes the optional is not pointer-like and payload has bits.
8333
8336
fn optIsNonNull (self : * FuncGen , opt_handle : * const llvm.Value , is_by_ref : bool ) * const llvm.Value {
8334
- if (is_by_ref ) {
8335
- const index_type = self .context .intType (32 );
8337
+ const field = b : {
8338
+ if (is_by_ref ) {
8339
+ const index_type = self .context .intType (32 );
8336
8340
8337
- const indices : [2 ]* const llvm.Value = .{
8338
- index_type .constNull (),
8339
- index_type .constInt (1 , .False ),
8340
- };
8341
+ const indices : [2 ]* const llvm.Value = .{
8342
+ index_type .constNull (),
8343
+ index_type .constInt (1 , .False ),
8344
+ };
8341
8345
8342
- const field_ptr = self .builder .buildInBoundsGEP (opt_handle , & indices , indices .len , "" );
8343
- return self .builder .buildLoad (field_ptr , "" );
8344
- }
8346
+ const field_ptr = self .builder .buildInBoundsGEP (opt_handle , & indices , indices .len , "" );
8347
+ break :b self .builder .buildLoad (field_ptr , "" );
8348
+ }
8349
+
8350
+ break :b self .builder .buildExtractValue (opt_handle , 1 , "" );
8351
+ };
8352
+ comptime assert (optional_layout_version == 3 );
8345
8353
8346
- return self .builder .buildExtractValue ( opt_handle , 1 , "" );
8354
+ return self .builder .buildICmp ( .NE , field , self . context . intType ( 8 ). constInt ( 0 , .False ) , "" );
8347
8355
}
8348
8356
8349
8357
/// Assumes the optional is not pointer-like and payload has bits.
@@ -9369,7 +9377,10 @@ fn intrinsicsAllowed(scalar_ty: Type, target: std.Target) bool {
9369
9377
/// We can do this because for all types, Zig ABI alignment >= LLVM ABI
9370
9378
/// alignment.
9371
9379
const struct_layout_version = 2 ;
9372
- const optional_layout_version = 2 ;
9380
+
9381
+ // TODO: Restore the non_null field to i1 once
9382
+ // https://github.com/llvm/llvm-project/issues/56585/ is fixed
9383
+ const optional_layout_version = 3 ;
9373
9384
9374
9385
/// We use the least significant bit of the pointer address to tell us
9375
9386
/// whether the type is fully resolved. Types that are only fwd declared
0 commit comments