@@ -4539,7 +4539,7 @@ pub const FuncGen = struct {
4539
4539
}
4540
4540
// We need to emit instructions to check for equality/inequality
4541
4541
// of optionals that are not pointers.
4542
- const is_by_ref = isByRef (operand_ty );
4542
+ const is_by_ref = isByRef (scalar_ty );
4543
4543
const lhs_non_null = self .optIsNonNull (lhs , is_by_ref );
4544
4544
const rhs_non_null = self .optIsNonNull (rhs , is_by_ref );
4545
4545
const llvm_i2 = self .context .intType (2 );
@@ -4564,8 +4564,8 @@ pub const FuncGen = struct {
4564
4564
_ = self .builder .buildBr (end_block );
4565
4565
4566
4566
self .builder .positionBuilderAtEnd (both_pl_block );
4567
- const lhs_payload = self .optPayloadHandle (lhs , is_by_ref );
4568
- const rhs_payload = self .optPayloadHandle (rhs , is_by_ref );
4567
+ const lhs_payload = self .optPayloadHandle (lhs , scalar_ty );
4568
+ const rhs_payload = self .optPayloadHandle (rhs , scalar_ty );
4569
4569
const payload_cmp = try self .cmp (lhs_payload , rhs_payload , payload_ty , op );
4570
4570
_ = self .builder .buildBr (end_block );
4571
4571
const both_pl_block_end = self .builder .getInsertBlock ();
@@ -5795,7 +5795,7 @@ pub const FuncGen = struct {
5795
5795
return operand ;
5796
5796
}
5797
5797
5798
- return self .optPayloadHandle (operand , isByRef ( payload_ty ) );
5798
+ return self .optPayloadHandle (operand , optional_ty );
5799
5799
}
5800
5800
5801
5801
fn airErrUnionPayload (
@@ -7347,11 +7347,9 @@ pub const FuncGen = struct {
7347
7347
}
7348
7348
7349
7349
comptime assert (optional_layout_version == 3 );
7350
- const optional_llvm_ty = try self . dg . lowerType ( optional_ty );
7350
+
7351
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 ), "" );
7353
- const partial = self .builder .buildInsertValue (optional_llvm_ty .getUndef (), payload , 0 , "" );
7354
- return self .builder .buildInsertValue (partial , non_null_field , 1 , "" );
7352
+ return buildOptional (self , optional_ty , payload , non_null_bit );
7355
7353
}
7356
7354
7357
7355
fn airAtomicRmw (self : * FuncGen , inst : Air.Inst.Index ) ! ? * const llvm.Value {
@@ -7515,11 +7513,13 @@ pub const FuncGen = struct {
7515
7513
const union_ptr = try self .resolveInst (bin_op .lhs );
7516
7514
const new_tag = try self .resolveInst (bin_op .rhs );
7517
7515
if (layout .payload_size == 0 ) {
7516
+ // TODO alignment on this store
7518
7517
_ = self .builder .buildStore (new_tag , union_ptr );
7519
7518
return null ;
7520
7519
}
7521
7520
const tag_index = @boolToInt (layout .tag_align < layout .payload_align );
7522
7521
const tag_field_ptr = self .builder .buildStructGEP (union_ptr , tag_index , "" );
7522
+ // TODO alignment on this store
7523
7523
_ = self .builder .buildStore (new_tag , tag_field_ptr );
7524
7524
return null ;
7525
7525
}
@@ -8355,18 +8355,77 @@ pub const FuncGen = struct {
8355
8355
}
8356
8356
8357
8357
/// Assumes the optional is not pointer-like and payload has bits.
8358
- fn optPayloadHandle (self : * FuncGen , opt_handle : * const llvm.Value , is_by_ref : bool ) * const llvm.Value {
8359
- if (is_by_ref ) {
8358
+ fn optPayloadHandle (
8359
+ fg : * FuncGen ,
8360
+ opt_handle : * const llvm.Value ,
8361
+ opt_ty : Type ,
8362
+ ) * const llvm.Value {
8363
+ var buf : Type.Payload.ElemType = undefined ;
8364
+ const payload_ty = opt_ty .optionalChild (& buf );
8365
+
8366
+ if (isByRef (opt_ty )) {
8360
8367
// We have a pointer and we need to return a pointer to the first field.
8361
- const index_type = self .context .intType (32 );
8368
+ const index_type = fg .context .intType (32 );
8362
8369
const indices : [2 ]* const llvm.Value = .{
8363
8370
index_type .constNull (), // dereference the pointer
8364
8371
index_type .constNull (), // first field is the payload
8365
8372
};
8366
- return self .builder .buildInBoundsGEP (opt_handle , & indices , indices .len , "" );
8373
+ const payload_ptr = fg .builder .buildInBoundsGEP (opt_handle , & indices , indices .len , "" );
8374
+
8375
+ if (isByRef (payload_ty )) {
8376
+ return payload_ptr ;
8377
+ }
8378
+ const target = fg .dg .module .getTarget ();
8379
+ const payload_alignment = payload_ty .abiAlignment (target );
8380
+ const load_inst = fg .builder .buildLoad (payload_ptr , "" );
8381
+ load_inst .setAlignment (payload_alignment );
8382
+ return load_inst ;
8383
+ }
8384
+
8385
+ assert (! isByRef (payload_ty ));
8386
+ return fg .builder .buildExtractValue (opt_handle , 0 , "" );
8387
+ }
8388
+
8389
+ fn buildOptional (
8390
+ self : * FuncGen ,
8391
+ optional_ty : Type ,
8392
+ payload : * const llvm.Value ,
8393
+ non_null_bit : * const llvm.Value ,
8394
+ ) ! ? * const llvm.Value {
8395
+ const optional_llvm_ty = try self .dg .lowerType (optional_ty );
8396
+ const non_null_field = self .builder .buildZExt (non_null_bit , self .dg .context .intType (8 ), "" );
8397
+
8398
+ if (isByRef (optional_ty )) {
8399
+ const target = self .dg .module .getTarget ();
8400
+ const alloca_inst = self .buildAlloca (optional_llvm_ty );
8401
+ const payload_alignment = optional_ty .abiAlignment (target );
8402
+ alloca_inst .setAlignment (payload_alignment );
8403
+
8404
+ const index_type = self .context .intType (32 );
8405
+ {
8406
+ const indices : [2 ]* const llvm.Value = .{
8407
+ index_type .constNull (), // dereference the pointer
8408
+ index_type .constNull (), // first field is the payload
8409
+ };
8410
+ const field_ptr = self .builder .buildInBoundsGEP (alloca_inst , & indices , indices .len , "" );
8411
+ const store_inst = self .builder .buildStore (payload , field_ptr );
8412
+ store_inst .setAlignment (payload_alignment );
8413
+ }
8414
+ {
8415
+ const indices : [2 ]* const llvm.Value = .{
8416
+ index_type .constNull (), // dereference the pointer
8417
+ index_type .constInt (1 , .False ), // second field is the non-null bit
8418
+ };
8419
+ const field_ptr = self .builder .buildInBoundsGEP (alloca_inst , & indices , indices .len , "" );
8420
+ const store_inst = self .builder .buildStore (non_null_field , field_ptr );
8421
+ store_inst .setAlignment (1 );
8422
+ }
8423
+
8424
+ return alloca_inst ;
8367
8425
}
8368
8426
8369
- return self .builder .buildExtractValue (opt_handle , 0 , "" );
8427
+ const partial = self .builder .buildInsertValue (optional_llvm_ty .getUndef (), payload , 0 , "" );
8428
+ return self .builder .buildInsertValue (partial , non_null_field , 1 , "" );
8370
8429
}
8371
8430
8372
8431
fn fieldPtr (
@@ -9335,7 +9394,18 @@ fn isByRef(ty: Type) bool {
9335
9394
.ErrorUnion = > return isByRef (ty .errorUnionPayload ()),
9336
9395
.Optional = > {
9337
9396
var buf : Type.Payload.ElemType = undefined ;
9338
- return isByRef (ty .optionalChild (& buf ));
9397
+ const payload_ty = ty .optionalChild (& buf );
9398
+ if (! payload_ty .hasRuntimeBitsIgnoreComptime ()) {
9399
+ return false ;
9400
+ }
9401
+ if (ty .optionalReprIsPayload ()) {
9402
+ return false ;
9403
+ }
9404
+ return true ;
9405
+ // TODO we actually want this logic:
9406
+ // however it is tripping an LLVM 14 regression:
9407
+ // https://github.com/llvm/llvm-project/issues/56585
9408
+ //return isByRef(payload_ty);
9339
9409
},
9340
9410
}
9341
9411
}
0 commit comments