@@ -251,15 +251,96 @@ CIRGenFunction::buildAsmInput(const TargetInfo::ConstraintInfo &Info,
251
251
252
252
if (Info.allowsRegister () || !Info.allowsMemory ())
253
253
if (CIRGenFunction::hasScalarEvaluationKind (InputExpr->getType ()))
254
- return {buildScalarExpr (InputExpr), nullptr };
254
+ return {buildScalarExpr (InputExpr), mlir::Type () };
255
255
if (InputExpr->getStmtClass () == Expr::CXXThisExprClass)
256
- return {buildScalarExpr (InputExpr), nullptr };
256
+ return {buildScalarExpr (InputExpr), mlir::Type () };
257
257
InputExpr = InputExpr->IgnoreParenNoopCasts (getContext ());
258
258
LValue Dest = buildLValue (InputExpr);
259
259
return buildAsmInputLValue (Info, Dest, InputExpr->getType (), ConstraintStr,
260
260
InputExpr->getExprLoc ());
261
261
}
262
262
263
+ static void buildAsmStores (CIRGenFunction &CGF, const AsmStmt &S,
264
+ const llvm::ArrayRef<mlir::Value> RegResults,
265
+ const llvm::ArrayRef<mlir::Type> ResultRegTypes,
266
+ const llvm::ArrayRef<mlir::Type> ResultTruncRegTypes,
267
+ const llvm::ArrayRef<LValue> ResultRegDests,
268
+ const llvm::ArrayRef<QualType> ResultRegQualTys,
269
+ const llvm::BitVector &ResultTypeRequiresCast,
270
+ const llvm::BitVector &ResultRegIsFlagReg) {
271
+ CIRGenBuilderTy &Builder = CGF.getBuilder ();
272
+ CIRGenModule &CGM = CGF.CGM ;
273
+ auto CTX = Builder.getContext ();
274
+
275
+ assert (RegResults.size () == ResultRegTypes.size ());
276
+ assert (RegResults.size () == ResultTruncRegTypes.size ());
277
+ assert (RegResults.size () == ResultRegDests.size ());
278
+ // ResultRegDests can be also populated by addReturnRegisterOutputs() above,
279
+ // in which case its size may grow.
280
+ assert (ResultTypeRequiresCast.size () <= ResultRegDests.size ());
281
+ assert (ResultRegIsFlagReg.size () <= ResultRegDests.size ());
282
+
283
+ for (unsigned i = 0 , e = RegResults.size (); i != e; ++i) {
284
+ mlir::Value Tmp = RegResults[i];
285
+ mlir::Type TruncTy = ResultTruncRegTypes[i];
286
+
287
+ if ((i < ResultRegIsFlagReg.size ()) && ResultRegIsFlagReg[i]) {
288
+ assert (!UnimplementedFeature::asm_llvm_assume ());
289
+ }
290
+
291
+ // If the result type of the LLVM IR asm doesn't match the result type of
292
+ // the expression, do the conversion.
293
+ if (ResultRegTypes[i] != TruncTy) {
294
+
295
+ // Truncate the integer result to the right size, note that TruncTy can be
296
+ // a pointer.
297
+ if (TruncTy.isa <mlir::FloatType>())
298
+ Tmp = Builder.createFloatingCast (Tmp, TruncTy);
299
+ else if (isa<mlir::cir::PointerType>(TruncTy) &&
300
+ isa<mlir::cir::IntType>(Tmp.getType ())) {
301
+ uint64_t ResSize = CGM.getDataLayout ().getTypeSizeInBits (TruncTy);
302
+ Tmp = Builder.createIntCast (
303
+ Tmp, mlir::cir::IntType::get (CTX, (unsigned )ResSize, false ));
304
+ Tmp = Builder.createIntToPtr (Tmp, TruncTy);
305
+ } else if (isa<mlir::cir::PointerType>(Tmp.getType ()) &&
306
+ isa<mlir::cir::IntType>(TruncTy)) {
307
+ uint64_t TmpSize = CGM.getDataLayout ().getTypeSizeInBits (Tmp.getType ());
308
+ Tmp = Builder.createPtrToInt (
309
+ Tmp, mlir::cir::IntType::get (CTX, (unsigned )TmpSize, false ));
310
+ Tmp = Builder.createIntCast (Tmp, TruncTy);
311
+ } else if (isa<mlir::cir::IntType>(TruncTy)) {
312
+ Tmp = Builder.createIntCast (Tmp, TruncTy);
313
+ } else if (false /* TruncTy->isVectorTy()*/ ) {
314
+ assert (!UnimplementedFeature::asm_vector_type ());
315
+ }
316
+ }
317
+
318
+ LValue Dest = ResultRegDests[i];
319
+ // ResultTypeRequiresCast elements correspond to the first
320
+ // ResultTypeRequiresCast.size() elements of RegResults.
321
+ if ((i < ResultTypeRequiresCast.size ()) && ResultTypeRequiresCast[i]) {
322
+ unsigned Size = CGF.getContext ().getTypeSize (ResultRegQualTys[i]);
323
+ Address A = Dest.getAddress ().withElementType (ResultRegTypes[i]);
324
+ if (CGF.getTargetHooks ().isScalarizableAsmOperand (CGF, TruncTy)) {
325
+ Builder.createStore (CGF.getLoc (S.getAsmLoc ()), Tmp, A);
326
+ continue ;
327
+ }
328
+
329
+ QualType Ty =
330
+ CGF.getContext ().getIntTypeForBitwidth (Size , /* Signed=*/ false );
331
+ if (Ty.isNull ()) {
332
+ const Expr *OutExpr = S.getOutputExpr (i);
333
+ CGM.getDiags ().Report (OutExpr->getExprLoc (),
334
+ diag::err_store_value_to_reg);
335
+ return ;
336
+ }
337
+ Dest = CGF.makeAddrLValue (A, Ty);
338
+ }
339
+
340
+ CGF.buildStoreThroughLValue (RValue::get (Tmp), Dest);
341
+ }
342
+ }
343
+
263
344
mlir::LogicalResult CIRGenFunction::buildAsmStmt (const AsmStmt &S) {
264
345
// Assemble the final asm string.
265
346
std::string AsmString = S.generateAsmString (getContext ());
@@ -277,19 +358,24 @@ mlir::LogicalResult CIRGenFunction::buildAsmStmt(const AsmStmt &S) {
277
358
std::vector<mlir::Type> ResultTruncRegTypes;
278
359
std::vector<mlir::Type> ArgTypes;
279
360
std::vector<mlir::Type> ArgElemTypes;
361
+ std::vector<mlir::Value> OutArgs;
362
+ std::vector<mlir::Value> InArgs;
363
+ std::vector<mlir::Value> InOutArgs;
280
364
std::vector<mlir::Value> Args;
281
365
llvm::BitVector ResultTypeRequiresCast;
282
366
llvm::BitVector ResultRegIsFlagReg;
283
367
284
368
// Keep track of input constraints.
285
369
std::string InOutConstraints;
286
- std::vector<mlir::Value> InOutArgs;
287
370
std::vector<mlir::Type> InOutArgTypes;
288
371
std::vector<mlir::Type> InOutArgElemTypes;
289
372
290
373
// Keep track of out constraints for tied input operand.
291
374
std::vector<std::string> OutputConstraints;
292
375
376
+ // Keep track of defined physregs.
377
+ llvm::SmallSet<std::string, 8 > PhysRegOutputs;
378
+
293
379
// An inline asm can be marked readonly if it meets the following conditions:
294
380
// - it doesn't have any sideeffects
295
381
// - it doesn't clobber memory
@@ -314,6 +400,10 @@ mlir::LogicalResult CIRGenFunction::buildAsmStmt(const AsmStmt &S) {
314
400
AddVariableConstraints (OutputConstraint, *OutExpr, getTarget (), CGM, S,
315
401
Info.earlyClobber (), &GCCReg);
316
402
403
+ // Give an error on multiple outputs to same physreg.
404
+ if (!GCCReg.empty () && !PhysRegOutputs.insert (GCCReg).second )
405
+ CGM.Error (S.getAsmLoc (), " multiple outputs to hard register: " + GCCReg);
406
+
317
407
OutputConstraints.push_back (OutputConstraint);
318
408
LValue Dest = buildLValue (OutExpr);
319
409
@@ -392,6 +482,7 @@ mlir::LogicalResult CIRGenFunction::buildAsmStmt(const AsmStmt &S) {
392
482
393
483
ArgTypes.push_back (DestAddr.getType ());
394
484
ArgElemTypes.push_back (DestAddr.getElementType ());
485
+ OutArgs.push_back (DestAddr.getPointer ());
395
486
Args.push_back (DestAddr.getPointer ());
396
487
Constraints += " =*" ;
397
488
Constraints += OutputConstraint;
@@ -412,6 +503,9 @@ mlir::LogicalResult CIRGenFunction::buildAsmStmt(const AsmStmt &S) {
412
503
*this , OutputConstraint, Arg.getType ()))
413
504
Arg = builder.createBitcast (Arg, AdjTy);
414
505
506
+ // Update largest vector width for any vector types.
507
+ assert (!UnimplementedFeature::asm_vector_type ());
508
+
415
509
// Only tie earlyclobber physregs.
416
510
if (Info.allowsRegister () && (GCCReg.empty () || Info.earlyClobber ()))
417
511
InOutConstraints += llvm::utostr (i);
@@ -424,11 +518,28 @@ mlir::LogicalResult CIRGenFunction::buildAsmStmt(const AsmStmt &S) {
424
518
}
425
519
} // iterate over output operands
426
520
521
+ // If this is a Microsoft-style asm blob, store the return registers (EAX:EDX)
522
+ // to the return value slot. Only do this when returning in registers.
523
+ if (isa<MSAsmStmt>(&S)) {
524
+ const ABIArgInfo &RetAI = CurFnInfo->getReturnInfo ();
525
+ if (RetAI.isDirect () || RetAI.isExtend ()) {
526
+ // Make a fake lvalue for the return value slot.
527
+ LValue ReturnSlot = makeAddrLValue (ReturnValue, FnRetTy);
528
+ CGM.getTargetCIRGenInfo ().addReturnRegisterOutputs (
529
+ *this , ReturnSlot, Constraints, ResultRegTypes, ResultTruncRegTypes,
530
+ ResultRegDests, AsmString, S.getNumOutputs ());
531
+ SawAsmBlock = true ;
532
+ }
533
+ }
534
+
427
535
for (unsigned i = 0 , e = S.getNumInputs (); i != e; i++) {
428
536
const Expr *InputExpr = S.getInputExpr (i);
429
537
430
538
TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i];
431
539
540
+ if (Info.allowsMemory ())
541
+ ReadNone = false ;
542
+
432
543
if (!Constraints.empty ())
433
544
Constraints += ' ,' ;
434
545
@@ -481,17 +592,21 @@ mlir::LogicalResult CIRGenFunction::buildAsmStmt(const AsmStmt &S) {
481
592
CGM.getDiags ().Report (S.getAsmLoc (), diag::err_asm_invalid_type_in_input)
482
593
<< InputExpr->getType () << InputConstraint;
483
594
595
+ // Update largest vector width for any vector types.
596
+ assert (!UnimplementedFeature::asm_vector_type ());
597
+
484
598
ArgTypes.push_back (Arg.getType ());
485
599
ArgElemTypes.push_back (ArgElemType);
600
+ InArgs.push_back (Arg);
486
601
Args.push_back (Arg);
487
602
Constraints += InputConstraint;
488
603
} // iterate over input operands
489
604
490
605
// Append the "input" part of inout constraints.
491
606
for (unsigned i = 0 , e = InOutArgs.size (); i != e; i++) {
607
+ Args.push_back (InOutArgs[i]);
492
608
ArgTypes.push_back (InOutArgTypes[i]);
493
609
ArgElemTypes.push_back (InOutArgElemTypes[i]);
494
- Args.push_back (InOutArgs[i]);
495
610
}
496
611
Constraints += InOutConstraints;
497
612
@@ -509,9 +624,15 @@ mlir::LogicalResult CIRGenFunction::buildAsmStmt(const AsmStmt &S) {
509
624
}
510
625
511
626
bool HasSideEffect = S.isVolatile () || S.getNumOutputs () == 0 ;
627
+ std::vector<mlir::Value> RegResults;
628
+
629
+ llvm::SmallVector<mlir::ValueRange, 8 > operands;
630
+ operands.push_back (OutArgs);
631
+ operands.push_back (InArgs);
632
+ operands.push_back (InOutArgs);
512
633
513
634
auto IA = builder.create <mlir::cir::InlineAsmOp>(
514
- getLoc (S.getAsmLoc ()), ResultType, Args , AsmString, Constraints,
635
+ getLoc (S.getAsmLoc ()), ResultType, operands , AsmString, Constraints,
515
636
HasSideEffect, inferFlavor (CGM, S), mlir::ArrayAttr ());
516
637
517
638
if (false /* IsGCCAsmGoto*/ ) {
@@ -525,28 +646,55 @@ mlir::LogicalResult CIRGenFunction::buildAsmStmt(const AsmStmt &S) {
525
646
if (IA.getNumResults ())
526
647
result = IA.getResult (0 );
527
648
528
- std::vector<mlir::Attribute> operandAttrs;
529
-
530
- // this is for the lowering to LLVM from LLVm dialect. Otherwise, if we
531
- // don't have the result (i.e. void type as a result of operation), the
532
- // element type attribute will be attached to the whole instruction, but not
533
- // to the operand
534
- if (!IA.getNumResults ())
535
- operandAttrs.push_back (OptNoneAttr::get (builder.getContext ()));
649
+ llvm::SmallVector<mlir::Attribute> operandAttrs;
536
650
651
+ int i = 0 ;
537
652
for (auto typ : ArgElemTypes) {
538
653
if (typ) {
539
- operandAttrs.push_back (mlir::TypeAttr::get (typ));
654
+ auto op = Args[i++];
655
+ assert (op.getType ().isa <mlir::cir::PointerType>() &&
656
+ " pointer type expected" );
657
+ assert (cast<mlir::cir::PointerType>(op.getType ()).getPointee () == typ &&
658
+ " element type differs from pointee type!" );
659
+
660
+ operandAttrs.push_back (mlir::UnitAttr::get (builder.getContext ()));
540
661
} else {
541
662
// We need to add an attribute for every arg since later, during
542
663
// the lowering to LLVM IR the attributes will be assigned to the
543
664
// CallInsn argument by index, i.e. we can't skip null type here
544
- operandAttrs.push_back (OptNoneAttr::get (builder. getContext () ));
665
+ operandAttrs.push_back (mlir::Attribute ( ));
545
666
}
546
667
}
547
668
669
+ assert (Args.size () == operandAttrs.size () &&
670
+ " The number of attributes is not even with the number of operands" );
671
+
548
672
IA.setOperandAttrsAttr (builder.getArrayAttr (operandAttrs));
673
+
674
+ if (ResultRegTypes.size () == 1 ) {
675
+ RegResults.push_back (result);
676
+ } else if (ResultRegTypes.size () > 1 ) {
677
+ auto alignment = CharUnits::One ();
678
+ auto sname = cast<mlir::cir::StructType>(ResultType).getName ();
679
+ auto dest = buildAlloca (sname, ResultType, getLoc (S.getAsmLoc ()),
680
+ alignment, false );
681
+ auto addr = Address (dest, alignment);
682
+ builder.createStore (getLoc (S.getAsmLoc ()), result, addr);
683
+
684
+ for (unsigned i = 0 , e = ResultRegTypes.size (); i != e; ++i) {
685
+ auto typ = builder.getPointerTo (ResultRegTypes[i]);
686
+ auto ptr =
687
+ builder.createGetMember (getLoc (S.getAsmLoc ()), typ, dest, " " , i);
688
+ auto tmp =
689
+ builder.createLoad (getLoc (S.getAsmLoc ()), Address (ptr, alignment));
690
+ RegResults.push_back (tmp);
691
+ }
692
+ }
549
693
}
550
694
695
+ buildAsmStores (*this , S, RegResults, ResultRegTypes, ResultTruncRegTypes,
696
+ ResultRegDests, ResultRegQualTys, ResultTypeRequiresCast,
697
+ ResultRegIsFlagReg);
698
+
551
699
return mlir::success ();
552
700
}
0 commit comments