@@ -5421,6 +5421,8 @@ pub const FuncGen = struct {
5421
5421
const llvm_params_len = inputs .len + outputs .len - return_count ;
5422
5422
const llvm_param_types = try arena .alloc (* const llvm .Type , llvm_params_len );
5423
5423
const llvm_param_values = try arena .alloc (* const llvm .Value , llvm_params_len );
5424
+ const target = self .dg .module .getTarget ();
5425
+
5424
5426
var llvm_param_i : usize = 0 ;
5425
5427
var total_i : usize = 0 ;
5426
5428
@@ -5449,7 +5451,18 @@ pub const FuncGen = struct {
5449
5451
llvm_param_types [llvm_param_i ] = output_inst .typeOf ();
5450
5452
llvm_param_i += 1 ;
5451
5453
}
5452
- llvm_constraints .appendSliceAssumeCapacity (constraint [1.. ]);
5454
+
5455
+ // LLVM uses commas internally to separate different constraints,
5456
+ // alternative constraints are achieved with pipes.
5457
+ // We still allow the user to use commas in a way that is similar
5458
+ // to GCC's inline assembly.
5459
+ // http://llvm.org/docs/LangRef.html#constraint-codes
5460
+ for (constraint [1.. ]) | byte | {
5461
+ llvm_constraints .appendAssumeCapacity (switch (byte ) {
5462
+ ',' = > '|' ,
5463
+ else = > byte ,
5464
+ });
5465
+ }
5453
5466
5454
5467
name_map .putAssumeCapacityNoClobber (name , {});
5455
5468
total_i += 1 ;
@@ -5464,15 +5477,43 @@ pub const FuncGen = struct {
5464
5477
extra_i += (constraint .len + name .len + (2 + 3 )) / 4 ;
5465
5478
5466
5479
const arg_llvm_value = try self .resolveInst (input );
5467
-
5468
- llvm_param_values [llvm_param_i ] = arg_llvm_value ;
5469
- llvm_param_types [llvm_param_i ] = arg_llvm_value .typeOf ();
5480
+ const arg_ty = self .air .typeOf (input );
5481
+ if (isByRef (arg_ty )) {
5482
+ if (constraintAllowsMemory (constraint )) {
5483
+ llvm_param_values [llvm_param_i ] = arg_llvm_value ;
5484
+ llvm_param_types [llvm_param_i ] = arg_llvm_value .typeOf ();
5485
+ } else {
5486
+ const alignment = arg_ty .abiAlignment (target );
5487
+ const load_inst = self .builder .buildLoad (arg_llvm_value , "" );
5488
+ load_inst .setAlignment (alignment );
5489
+ llvm_param_values [llvm_param_i ] = load_inst ;
5490
+ llvm_param_types [llvm_param_i ] = load_inst .typeOf ();
5491
+ }
5492
+ } else {
5493
+ if (constraintAllowsRegister (constraint )) {
5494
+ llvm_param_values [llvm_param_i ] = arg_llvm_value ;
5495
+ llvm_param_types [llvm_param_i ] = arg_llvm_value .typeOf ();
5496
+ } else {
5497
+ const alignment = arg_ty .abiAlignment (target );
5498
+ const arg_ptr = self .buildAlloca (arg_llvm_value .typeOf ());
5499
+ arg_ptr .setAlignment (alignment );
5500
+ const store_inst = self .builder .buildStore (arg_llvm_value , arg_ptr );
5501
+ store_inst .setAlignment (alignment );
5502
+ llvm_param_values [llvm_param_i ] = arg_ptr ;
5503
+ llvm_param_types [llvm_param_i ] = arg_ptr .typeOf ();
5504
+ }
5505
+ }
5470
5506
5471
5507
try llvm_constraints .ensureUnusedCapacity (self .gpa , constraint .len + 1 );
5472
5508
if (total_i != 0 ) {
5473
5509
llvm_constraints .appendAssumeCapacity (',' );
5474
5510
}
5475
- llvm_constraints .appendSliceAssumeCapacity (constraint );
5511
+ for (constraint ) | byte | {
5512
+ llvm_constraints .appendAssumeCapacity (switch (byte ) {
5513
+ ',' = > '|' ,
5514
+ else = > byte ,
5515
+ });
5516
+ }
5476
5517
5477
5518
if (! std .mem .eql (u8 , name , "_" )) {
5478
5519
name_map .putAssumeCapacityNoClobber (name , {});
@@ -9307,3 +9348,11 @@ fn errUnionPayloadOffset(payload_ty: Type, target: std.Target) u1 {
9307
9348
fn errUnionErrorOffset (payload_ty : Type , target : std.Target ) u1 {
9308
9349
return @boolToInt (Type .anyerror .abiAlignment (target ) <= payload_ty .abiAlignment (target ));
9309
9350
}
9351
+
9352
+ fn constraintAllowsMemory (constraint : []const u8 ) bool {
9353
+ return constraint [0 ] == 'm' ;
9354
+ }
9355
+
9356
+ fn constraintAllowsRegister (constraint : []const u8 ) bool {
9357
+ return constraint [0 ] != 'm' ;
9358
+ }
0 commit comments