2929#include < optional>
3030#include < string>
3131#include < utility>
32+ #include < variant>
3233#include < vector>
3334
3435namespace llvm {
@@ -531,83 +532,73 @@ class MCCFIInstruction {
531532 OpValOffset,
532533 };
533534
535+ // Held in ExtraFields for most common OpTypes, exceptions follow.
536+ struct CommonFields {
537+ unsigned Register;
538+ int64_t Offset;
539+ unsigned Register2;
540+ unsigned AddressSpace;
541+ // FIXME: Workaround for GCC7 bug with nested class used as std::variant
542+ // alternative where the compiler really wants a user-defined default
543+ // constructor. Once we no longer support GCC7 these constructors can be
544+ // replaced with default member initializers and aggregate initialization.
545+ CommonFields (unsigned Reg, int64_t Off = 0 ,
546+ unsigned Reg2 = std::numeric_limits<unsigned >::max(),
547+ unsigned AddrSpace = 0 )
548+ : Register(Reg), Offset(Off), Register2(Reg2), AddressSpace(AddrSpace) {
549+ }
550+ CommonFields () : CommonFields(std::numeric_limits<unsigned >::max()) {}
551+ };
552+ // Held in ExtraFields when OpEscape.
553+ struct EscapeFields {
554+ std::vector<char > Values;
555+ std::string Comment;
556+ };
557+ // Held in ExtraFields when OpLabel.
558+ struct LabelFields {
559+ MCSymbol *CfiLabel = nullptr ;
560+ };
561+
534562private:
535563 MCSymbol *Label;
536- union {
537- struct {
538- unsigned Register;
539- int64_t Offset;
540- } RI;
541- struct {
542- unsigned Register;
543- int64_t Offset;
544- unsigned AddressSpace;
545- } RIA;
546- struct {
547- unsigned Register;
548- unsigned Register2;
549- } RR;
550- MCSymbol *CfiLabel;
551- } U;
564+ std::variant<CommonFields, EscapeFields, LabelFields> ExtraFields;
552565 OpType Operation;
553566 SMLoc Loc;
554- std::vector<char > Values;
555- std::string Comment;
556567
557- MCCFIInstruction (OpType Op, MCSymbol *L, unsigned R, int64_t O, SMLoc Loc,
558- StringRef V = " " , StringRef Comment = " " )
559- : Label(L), Operation(Op), Loc(Loc), Values(V.begin(), V.end()),
560- Comment (Comment) {
561- assert (Op != OpRegister && Op != OpLLVMDefAspaceCfa);
562- U.RI = {R, O};
563- }
564- MCCFIInstruction (OpType Op, MCSymbol *L, unsigned R1, unsigned R2, SMLoc Loc)
565- : Label(L), Operation(Op), Loc(Loc) {
566- assert (Op == OpRegister);
567- U.RR = {R1, R2};
568- }
569- MCCFIInstruction (OpType Op, MCSymbol *L, unsigned R, int64_t O, unsigned AS,
570- SMLoc Loc)
571- : Label(L), Operation(Op), Loc(Loc) {
572- assert (Op == OpLLVMDefAspaceCfa);
573- U.RIA = {R, O, AS};
574- }
575-
576- MCCFIInstruction (OpType Op, MCSymbol *L, MCSymbol *CfiLabel, SMLoc Loc)
577- : Label(L), Operation(Op), Loc(Loc) {
578- assert (Op == OpLabel);
579- U.CfiLabel = CfiLabel;
580- }
568+ template <class FieldsType >
569+ MCCFIInstruction (OpType Op, MCSymbol *L, FieldsType &&EF, SMLoc Loc)
570+ : Label(L), ExtraFields(std::forward<FieldsType>(EF)), Operation(Op),
571+ Loc (Loc) {}
581572
582573public:
583574 // / .cfi_def_cfa defines a rule for computing CFA as: take address from
584575 // / Register and add Offset to it.
585576 static MCCFIInstruction cfiDefCfa (MCSymbol *L, unsigned Register,
586577 int64_t Offset, SMLoc Loc = {}) {
587- return MCCFIInstruction ( OpDefCfa, L, Register, Offset, Loc) ;
578+ return { OpDefCfa, L, CommonFields{ Register, Offset} , Loc} ;
588579 }
589580
590581 // / .cfi_def_cfa_register modifies a rule for computing CFA. From now
591582 // / on Register will be used instead of the old one. Offset remains the same.
592583 static MCCFIInstruction createDefCfaRegister (MCSymbol *L, unsigned Register,
593584 SMLoc Loc = {}) {
594- return MCCFIInstruction ( OpDefCfaRegister, L, Register, INT64_C ( 0 ), Loc) ;
585+ return { OpDefCfaRegister, L, CommonFields{ Register}, Loc} ;
595586 }
596587
597588 // / .cfi_def_cfa_offset modifies a rule for computing CFA. Register
598589 // / remains the same, but offset is new. Note that it is the absolute offset
599590 // / that will be added to a defined register to the compute CFA address.
600591 static MCCFIInstruction cfiDefCfaOffset (MCSymbol *L, int64_t Offset,
601592 SMLoc Loc = {}) {
602- return MCCFIInstruction ( OpDefCfaOffset, L, 0 , Offset, Loc) ;
593+ return { OpDefCfaOffset, L, CommonFields{ 0 , Offset} , Loc} ;
603594 }
604595
605596 // / .cfi_adjust_cfa_offset Same as .cfi_def_cfa_offset, but
606597 // / Offset is a relative value that is added/subtracted from the previous
607598 // / offset.
608599 static MCCFIInstruction createAdjustCfaOffset (MCSymbol *L, int64_t Adjustment,
609600 SMLoc Loc = {}) {
610- return MCCFIInstruction ( OpAdjustCfaOffset, L, 0 , Adjustment, Loc) ;
601+ return { OpAdjustCfaOffset, L, CommonFields{ 0 , Adjustment} , Loc} ;
611602 }
612603
613604 // FIXME: Update the remaining docs to use the new proposal wording.
@@ -618,151 +609,153 @@ class MCCFIInstruction {
618609 int64_t Offset,
619610 unsigned AddressSpace,
620611 SMLoc Loc) {
621- return MCCFIInstruction ( OpLLVMDefAspaceCfa, L, Register, Offset ,
622- AddressSpace, Loc) ;
612+ return { OpLLVMDefAspaceCfa, L,
613+ CommonFields{Register, Offset, 0 , AddressSpace} , Loc} ;
623614 }
624615
625616 // / .cfi_offset Previous value of Register is saved at offset Offset
626617 // / from CFA.
627618 static MCCFIInstruction createOffset (MCSymbol *L, unsigned Register,
628619 int64_t Offset, SMLoc Loc = {}) {
629- return MCCFIInstruction ( OpOffset, L, Register, Offset, Loc) ;
620+ return { OpOffset, L, CommonFields{ Register, Offset} , Loc} ;
630621 }
631622
632623 // / .cfi_rel_offset Previous value of Register is saved at offset
633624 // / Offset from the current CFA register. This is transformed to .cfi_offset
634625 // / using the known displacement of the CFA register from the CFA.
635626 static MCCFIInstruction createRelOffset (MCSymbol *L, unsigned Register,
636627 int64_t Offset, SMLoc Loc = {}) {
637- return MCCFIInstruction ( OpRelOffset, L, Register, Offset, Loc) ;
628+ return { OpRelOffset, L, CommonFields{ Register, Offset} , Loc} ;
638629 }
639630
640631 // / .cfi_register Previous value of Register1 is saved in
641632 // / register Register2.
642633 static MCCFIInstruction createRegister (MCSymbol *L, unsigned Register1,
643634 unsigned Register2, SMLoc Loc = {}) {
644- return MCCFIInstruction ( OpRegister, L, Register1, Register2, Loc) ;
635+ return { OpRegister, L, CommonFields{ Register1, 0 , Register2} , Loc} ;
645636 }
646637
647638 // / .cfi_window_save SPARC register window is saved.
648639 static MCCFIInstruction createWindowSave (MCSymbol *L, SMLoc Loc = {}) {
649- return MCCFIInstruction ( OpWindowSave, L, 0 , INT64_C ( 0 ), Loc) ;
640+ return { OpWindowSave, L, CommonFields{}, Loc} ;
650641 }
651642
652643 // / .cfi_negate_ra_state AArch64 negate RA state.
653644 static MCCFIInstruction createNegateRAState (MCSymbol *L, SMLoc Loc = {}) {
654- return MCCFIInstruction ( OpNegateRAState, L, 0 , INT64_C ( 0 ), Loc) ;
645+ return { OpNegateRAState, L, CommonFields{}, Loc} ;
655646 }
656647
657648 // / .cfi_negate_ra_state_with_pc AArch64 negate RA state with PC.
658649 static MCCFIInstruction createNegateRAStateWithPC (MCSymbol *L,
659650 SMLoc Loc = {}) {
660- return MCCFIInstruction ( OpNegateRAStateWithPC, L, 0 , INT64_C ( 0 ), Loc) ;
651+ return { OpNegateRAStateWithPC, L, CommonFields{}, Loc} ;
661652 }
662653
663654 // / .cfi_restore says that the rule for Register is now the same as it
664655 // / was at the beginning of the function, after all initial instructions added
665656 // / by .cfi_startproc were executed.
666657 static MCCFIInstruction createRestore (MCSymbol *L, unsigned Register,
667658 SMLoc Loc = {}) {
668- return MCCFIInstruction ( OpRestore, L, Register, INT64_C ( 0 ), Loc) ;
659+ return { OpRestore, L, CommonFields{ Register}, Loc} ;
669660 }
670661
671662 // / .cfi_undefined From now on the previous value of Register can't be
672663 // / restored anymore.
673664 static MCCFIInstruction createUndefined (MCSymbol *L, unsigned Register,
674665 SMLoc Loc = {}) {
675- return MCCFIInstruction ( OpUndefined, L, Register, INT64_C ( 0 ), Loc) ;
666+ return { OpUndefined, L, CommonFields{ Register}, Loc} ;
676667 }
677668
678669 // / .cfi_same_value Current value of Register is the same as in the
679670 // / previous frame. I.e., no restoration is needed.
680671 static MCCFIInstruction createSameValue (MCSymbol *L, unsigned Register,
681672 SMLoc Loc = {}) {
682- return MCCFIInstruction ( OpSameValue, L, Register, INT64_C ( 0 ), Loc) ;
673+ return { OpSameValue, L, CommonFields{ Register}, Loc} ;
683674 }
684675
685676 // / .cfi_remember_state Save all current rules for all registers.
686677 static MCCFIInstruction createRememberState (MCSymbol *L, SMLoc Loc = {}) {
687- return MCCFIInstruction ( OpRememberState, L, 0 , INT64_C ( 0 ), Loc) ;
678+ return { OpRememberState, L, CommonFields{}, Loc} ;
688679 }
689680
690681 // / .cfi_restore_state Restore the previously saved state.
691682 static MCCFIInstruction createRestoreState (MCSymbol *L, SMLoc Loc = {}) {
692- return MCCFIInstruction ( OpRestoreState, L, 0 , INT64_C ( 0 ), Loc) ;
683+ return { OpRestoreState, L, CommonFields{}, Loc} ;
693684 }
694685
695686 // / .cfi_escape Allows the user to add arbitrary bytes to the unwind
696687 // / info.
697688 static MCCFIInstruction createEscape (MCSymbol *L, StringRef Vals,
698689 SMLoc Loc = {}, StringRef Comment = " " ) {
699- return MCCFIInstruction (OpEscape, L, 0 , 0 , Loc, Vals, Comment);
690+ return {OpEscape, L,
691+ EscapeFields{std::vector<char >(Vals.begin (), Vals.end ()),
692+ Comment.str ()},
693+ Loc};
700694 }
701695
702696 // / A special wrapper for .cfi_escape that indicates GNU_ARGS_SIZE
703697 static MCCFIInstruction createGnuArgsSize (MCSymbol *L, int64_t Size,
704698 SMLoc Loc = {}) {
705- return MCCFIInstruction ( OpGnuArgsSize, L, 0 , Size, Loc) ;
699+ return { OpGnuArgsSize, L, CommonFields{ 0 , Size} , Loc} ;
706700 }
707701
708702 static MCCFIInstruction createLabel (MCSymbol *L, MCSymbol *CfiLabel,
709703 SMLoc Loc) {
710- return MCCFIInstruction ( OpLabel, L, CfiLabel, Loc) ;
704+ return { OpLabel, L, LabelFields{ CfiLabel} , Loc} ;
711705 }
712706
713707 // / .cfi_val_offset Previous value of Register is offset Offset from the
714708 // / current CFA register.
715709 static MCCFIInstruction createValOffset (MCSymbol *L, unsigned Register,
716710 int64_t Offset, SMLoc Loc = {}) {
717- return MCCFIInstruction ( OpValOffset, L, Register, Offset, Loc) ;
711+ return { OpValOffset, L, CommonFields{ Register, Offset} , Loc} ;
718712 }
719713
720714 OpType getOperation () const { return Operation; }
721715 MCSymbol *getLabel () const { return Label; }
722716
723717 unsigned getRegister () const {
724- if (Operation == OpRegister)
725- return U.RR .Register ;
726- if (Operation == OpLLVMDefAspaceCfa)
727- return U.RIA .Register ;
728718 assert (Operation == OpDefCfa || Operation == OpOffset ||
729719 Operation == OpRestore || Operation == OpUndefined ||
730720 Operation == OpSameValue || Operation == OpDefCfaRegister ||
731- Operation == OpRelOffset || Operation == OpValOffset);
732- return U.RI .Register ;
721+ Operation == OpRelOffset || Operation == OpValOffset ||
722+ Operation == OpRegister || Operation == OpLLVMDefAspaceCfa);
723+ return std::get<CommonFields>(ExtraFields).Register ;
733724 }
734725
735726 unsigned getRegister2 () const {
736727 assert (Operation == OpRegister);
737- return U. RR .Register2 ;
728+ return std::get<CommonFields>(ExtraFields) .Register2 ;
738729 }
739730
740731 unsigned getAddressSpace () const {
741732 assert (Operation == OpLLVMDefAspaceCfa);
742- return U. RIA .AddressSpace ;
733+ return std::get<CommonFields>(ExtraFields) .AddressSpace ;
743734 }
744735
745736 int64_t getOffset () const {
746- if (Operation == OpLLVMDefAspaceCfa)
747- return U.RIA .Offset ;
748737 assert (Operation == OpDefCfa || Operation == OpOffset ||
749738 Operation == OpRelOffset || Operation == OpDefCfaOffset ||
750739 Operation == OpAdjustCfaOffset || Operation == OpGnuArgsSize ||
751- Operation == OpValOffset);
752- return U. RI .Offset ;
740+ Operation == OpValOffset || Operation == OpLLVMDefAspaceCfa );
741+ return std::get<CommonFields>(ExtraFields) .Offset ;
753742 }
754743
755744 MCSymbol *getCfiLabel () const {
756745 assert (Operation == OpLabel);
757- return U .CfiLabel ;
746+ return std::get<LabelFields>(ExtraFields) .CfiLabel ;
758747 }
759748
760749 StringRef getValues () const {
761750 assert (Operation == OpEscape);
751+ auto &Values = std::get<EscapeFields>(ExtraFields).Values ;
762752 return StringRef (&Values[0 ], Values.size ());
763753 }
764754
765- StringRef getComment () const { return Comment; }
755+ StringRef getComment () const {
756+ assert (Operation == OpEscape);
757+ return std::get<EscapeFields>(ExtraFields).Comment ;
758+ }
766759 SMLoc getLoc () const { return Loc; }
767760};
768761
0 commit comments