@@ -4538,7 +4538,7 @@ pub const FuncGen = struct {
4538
4538
}
4539
4539
// We need to emit instructions to check for equality/inequality
4540
4540
// of optionals that are not pointers.
4541
- const is_by_ref = isByRef (operand_ty );
4541
+ const is_by_ref = isByRef (scalar_ty );
4542
4542
const lhs_non_null = self .optIsNonNull (lhs , is_by_ref );
4543
4543
const rhs_non_null = self .optIsNonNull (rhs , is_by_ref );
4544
4544
const llvm_i2 = self .context .intType (2 );
@@ -4563,8 +4563,8 @@ pub const FuncGen = struct {
4563
4563
_ = self .builder .buildBr (end_block );
4564
4564
4565
4565
self .builder .positionBuilderAtEnd (both_pl_block );
4566
- const lhs_payload = self .optPayloadHandle (lhs , is_by_ref );
4567
- const rhs_payload = self .optPayloadHandle (rhs , is_by_ref );
4566
+ const lhs_payload = self .optPayloadHandle (lhs , scalar_ty );
4567
+ const rhs_payload = self .optPayloadHandle (rhs , scalar_ty );
4568
4568
const payload_cmp = try self .cmp (lhs_payload , rhs_payload , payload_ty , op );
4569
4569
_ = self .builder .buildBr (end_block );
4570
4570
const both_pl_block_end = self .builder .getInsertBlock ();
@@ -5794,7 +5794,7 @@ pub const FuncGen = struct {
5794
5794
return operand ;
5795
5795
}
5796
5796
5797
- return self .optPayloadHandle (operand , isByRef ( payload_ty ) );
5797
+ return self .optPayloadHandle (operand , optional_ty );
5798
5798
}
5799
5799
5800
5800
fn airErrUnionPayload (
@@ -7345,10 +7345,8 @@ pub const FuncGen = struct {
7345
7345
return self .builder .buildSelect (success_bit , payload .typeOf ().constNull (), payload , "" );
7346
7346
}
7347
7347
7348
- const optional_llvm_ty = try self .dg .lowerType (optional_ty );
7349
7348
const non_null_bit = self .builder .buildNot (success_bit , "" );
7350
- const partial = self .builder .buildInsertValue (optional_llvm_ty .getUndef (), payload , 0 , "" );
7351
- return self .builder .buildInsertValue (partial , non_null_bit , 1 , "" );
7349
+ return buildOptional (self , optional_ty , payload , non_null_bit );
7352
7350
}
7353
7351
7354
7352
fn airAtomicRmw (self : * FuncGen , inst : Air.Inst.Index ) ! ? * const llvm.Value {
@@ -7512,11 +7510,13 @@ pub const FuncGen = struct {
7512
7510
const union_ptr = try self .resolveInst (bin_op .lhs );
7513
7511
const new_tag = try self .resolveInst (bin_op .rhs );
7514
7512
if (layout .payload_size == 0 ) {
7513
+ // TODO alignment on this store
7515
7514
_ = self .builder .buildStore (new_tag , union_ptr );
7516
7515
return null ;
7517
7516
}
7518
7517
const tag_index = @boolToInt (layout .tag_align < layout .payload_align );
7519
7518
const tag_field_ptr = self .builder .buildStructGEP (union_ptr , tag_index , "" );
7519
+ // TODO alignment on this store
7520
7520
_ = self .builder .buildStore (new_tag , tag_field_ptr );
7521
7521
return null ;
7522
7522
}
@@ -8347,18 +8347,76 @@ pub const FuncGen = struct {
8347
8347
}
8348
8348
8349
8349
/// Assumes the optional is not pointer-like and payload has bits.
8350
- fn optPayloadHandle (self : * FuncGen , opt_handle : * const llvm.Value , is_by_ref : bool ) * const llvm.Value {
8351
- if (is_by_ref ) {
8350
+ fn optPayloadHandle (
8351
+ fg : * FuncGen ,
8352
+ opt_handle : * const llvm.Value ,
8353
+ opt_ty : Type ,
8354
+ ) * const llvm.Value {
8355
+ var buf : Type.Payload.ElemType = undefined ;
8356
+ const payload_ty = opt_ty .optionalChild (& buf );
8357
+
8358
+ if (isByRef (opt_ty )) {
8352
8359
// We have a pointer and we need to return a pointer to the first field.
8353
- const index_type = self .context .intType (32 );
8360
+ const index_type = fg .context .intType (32 );
8354
8361
const indices : [2 ]* const llvm.Value = .{
8355
8362
index_type .constNull (), // dereference the pointer
8356
8363
index_type .constNull (), // first field is the payload
8357
8364
};
8358
- return self .builder .buildInBoundsGEP (opt_handle , & indices , indices .len , "" );
8365
+ const payload_ptr = fg .builder .buildInBoundsGEP (opt_handle , & indices , indices .len , "" );
8366
+
8367
+ if (isByRef (payload_ty )) {
8368
+ return payload_ptr ;
8369
+ }
8370
+ const target = fg .dg .module .getTarget ();
8371
+ const payload_alignment = payload_ty .abiAlignment (target );
8372
+ const load_inst = fg .builder .buildLoad (payload_ptr , "" );
8373
+ load_inst .setAlignment (payload_alignment );
8374
+ return load_inst ;
8375
+ }
8376
+
8377
+ assert (! isByRef (payload_ty ));
8378
+ return fg .builder .buildExtractValue (opt_handle , 0 , "" );
8379
+ }
8380
+
8381
+ fn buildOptional (
8382
+ self : * FuncGen ,
8383
+ optional_ty : Type ,
8384
+ payload : * const llvm.Value ,
8385
+ non_null_bit : * const llvm.Value ,
8386
+ ) ! ? * const llvm.Value {
8387
+ const optional_llvm_ty = try self .dg .lowerType (optional_ty );
8388
+
8389
+ if (isByRef (optional_ty )) {
8390
+ const target = self .dg .module .getTarget ();
8391
+ const alloca_inst = self .buildAlloca (optional_llvm_ty );
8392
+ const payload_alignment = optional_ty .abiAlignment (target );
8393
+ alloca_inst .setAlignment (payload_alignment );
8394
+
8395
+ const index_type = self .context .intType (32 );
8396
+ {
8397
+ const indices : [2 ]* const llvm.Value = .{
8398
+ index_type .constNull (), // dereference the pointer
8399
+ index_type .constNull (), // first field is the payload
8400
+ };
8401
+ const field_ptr = self .builder .buildInBoundsGEP (alloca_inst , & indices , indices .len , "" );
8402
+ const store_inst = self .builder .buildStore (payload , field_ptr );
8403
+ store_inst .setAlignment (payload_alignment );
8404
+ }
8405
+ {
8406
+ const indices : [2 ]* const llvm.Value = .{
8407
+ index_type .constNull (), // dereference the pointer
8408
+ index_type .constInt (1 , .False ), // second field is the non-null bit
8409
+ };
8410
+ const field_ptr = self .builder .buildInBoundsGEP (alloca_inst , & indices , indices .len , "" );
8411
+ const store_inst = self .builder .buildStore (non_null_bit , field_ptr );
8412
+ store_inst .setAlignment (1 );
8413
+ }
8414
+
8415
+ return alloca_inst ;
8359
8416
}
8360
8417
8361
- return self .builder .buildExtractValue (opt_handle , 0 , "" );
8418
+ const partial = self .builder .buildInsertValue (optional_llvm_ty .getUndef (), payload , 0 , "" );
8419
+ return self .builder .buildInsertValue (partial , non_null_bit , 1 , "" );
8362
8420
}
8363
8421
8364
8422
fn fieldPtr (
@@ -9327,7 +9385,18 @@ fn isByRef(ty: Type) bool {
9327
9385
.ErrorUnion = > return isByRef (ty .errorUnionPayload ()),
9328
9386
.Optional = > {
9329
9387
var buf : Type.Payload.ElemType = undefined ;
9330
- return isByRef (ty .optionalChild (& buf ));
9388
+ const payload_ty = ty .optionalChild (& buf );
9389
+ if (! payload_ty .hasRuntimeBitsIgnoreComptime ()) {
9390
+ return false ;
9391
+ }
9392
+ if (ty .optionalReprIsPayload ()) {
9393
+ return false ;
9394
+ }
9395
+ return true ;
9396
+ // TODO we actually want this logic:
9397
+ // however it is tripping an LLVM 14 regression:
9398
+ // https://github.com/llvm/llvm-project/issues/56585
9399
+ //return isByRef(payload_ty);
9331
9400
},
9332
9401
}
9333
9402
}
0 commit comments