2929#include < optional>
3030#include < string>
3131#include < utility>
32+ #include < variant>
3233#include < vector>
3334
3435namespace llvm {
@@ -531,83 +532,74 @@ 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,
546+ int64_t Off = 0 ,
547+ unsigned Reg2 = std::numeric_limits<unsigned >::max(),
548+ unsigned AddrSpace = 0 )
549+ : Register(Reg), Offset(Off), Register2(Reg2), AddressSpace(AddrSpace) {
550+ }
551+ CommonFields () : CommonFields(std::numeric_limits<unsigned >::max()) {}
552+ };
553+ // Held in ExtraFields when OpEscape.
554+ struct EscapeFields {
555+ std::vector<char > Values;
556+ std::string Comment;
557+ };
558+ // Held in ExtraFields when OpLabel.
559+ struct LabelFields {
560+ MCSymbol *CfiLabel = nullptr ;
561+ };
562+
534563private:
535564 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;
565+ std::variant<CommonFields, EscapeFields, LabelFields> ExtraFields;
552566 OpType Operation;
553567 SMLoc Loc;
554- std::vector<char > Values;
555- std::string Comment;
556568
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- }
569+ template <class FieldsType >
570+ MCCFIInstruction (OpType Op, MCSymbol *L, FieldsType &&EF, SMLoc Loc)
571+ : Label(L), ExtraFields(std::forward<FieldsType>(EF)), Operation(Op),
572+ Loc (Loc) {}
581573
582574public:
583575 // / .cfi_def_cfa defines a rule for computing CFA as: take address from
584576 // / Register and add Offset to it.
585577 static MCCFIInstruction cfiDefCfa (MCSymbol *L, unsigned Register,
586578 int64_t Offset, SMLoc Loc = {}) {
587- return MCCFIInstruction ( OpDefCfa, L, Register, Offset, Loc) ;
579+ return { OpDefCfa, L, CommonFields{ Register, Offset} , Loc} ;
588580 }
589581
590582 // / .cfi_def_cfa_register modifies a rule for computing CFA. From now
591583 // / on Register will be used instead of the old one. Offset remains the same.
592584 static MCCFIInstruction createDefCfaRegister (MCSymbol *L, unsigned Register,
593585 SMLoc Loc = {}) {
594- return MCCFIInstruction ( OpDefCfaRegister, L, Register, INT64_C ( 0 ), Loc) ;
586+ return { OpDefCfaRegister, L, CommonFields{ Register}, Loc} ;
595587 }
596588
597589 // / .cfi_def_cfa_offset modifies a rule for computing CFA. Register
598590 // / remains the same, but offset is new. Note that it is the absolute offset
599591 // / that will be added to a defined register to the compute CFA address.
600592 static MCCFIInstruction cfiDefCfaOffset (MCSymbol *L, int64_t Offset,
601593 SMLoc Loc = {}) {
602- return MCCFIInstruction ( OpDefCfaOffset, L, 0 , Offset, Loc) ;
594+ return { OpDefCfaOffset, L, CommonFields{ 0 , Offset} , Loc} ;
603595 }
604596
605597 // / .cfi_adjust_cfa_offset Same as .cfi_def_cfa_offset, but
606598 // / Offset is a relative value that is added/subtracted from the previous
607599 // / offset.
608600 static MCCFIInstruction createAdjustCfaOffset (MCSymbol *L, int64_t Adjustment,
609601 SMLoc Loc = {}) {
610- return MCCFIInstruction ( OpAdjustCfaOffset, L, 0 , Adjustment, Loc) ;
602+ return { OpAdjustCfaOffset, L, CommonFields{ 0 , Adjustment} , Loc} ;
611603 }
612604
613605 // FIXME: Update the remaining docs to use the new proposal wording.
@@ -618,151 +610,153 @@ class MCCFIInstruction {
618610 int64_t Offset,
619611 unsigned AddressSpace,
620612 SMLoc Loc) {
621- return MCCFIInstruction ( OpLLVMDefAspaceCfa, L, Register, Offset ,
622- AddressSpace, Loc) ;
613+ return { OpLLVMDefAspaceCfa, L,
614+ CommonFields{Register, Offset, 0 , AddressSpace} , Loc} ;
623615 }
624616
625617 // / .cfi_offset Previous value of Register is saved at offset Offset
626618 // / from CFA.
627619 static MCCFIInstruction createOffset (MCSymbol *L, unsigned Register,
628620 int64_t Offset, SMLoc Loc = {}) {
629- return MCCFIInstruction ( OpOffset, L, Register, Offset, Loc) ;
621+ return { OpOffset, L, CommonFields{ Register, Offset} , Loc} ;
630622 }
631623
632624 // / .cfi_rel_offset Previous value of Register is saved at offset
633625 // / Offset from the current CFA register. This is transformed to .cfi_offset
634626 // / using the known displacement of the CFA register from the CFA.
635627 static MCCFIInstruction createRelOffset (MCSymbol *L, unsigned Register,
636628 int64_t Offset, SMLoc Loc = {}) {
637- return MCCFIInstruction ( OpRelOffset, L, Register, Offset, Loc) ;
629+ return { OpRelOffset, L, CommonFields{ Register, Offset} , Loc} ;
638630 }
639631
640632 // / .cfi_register Previous value of Register1 is saved in
641633 // / register Register2.
642634 static MCCFIInstruction createRegister (MCSymbol *L, unsigned Register1,
643635 unsigned Register2, SMLoc Loc = {}) {
644- return MCCFIInstruction ( OpRegister, L, Register1, Register2, Loc) ;
636+ return { OpRegister, L, CommonFields{ Register1, 0 , Register2} , Loc} ;
645637 }
646638
647639 // / .cfi_window_save SPARC register window is saved.
648640 static MCCFIInstruction createWindowSave (MCSymbol *L, SMLoc Loc = {}) {
649- return MCCFIInstruction ( OpWindowSave, L, 0 , INT64_C ( 0 ), Loc) ;
641+ return { OpWindowSave, L, CommonFields{}, Loc} ;
650642 }
651643
652644 // / .cfi_negate_ra_state AArch64 negate RA state.
653645 static MCCFIInstruction createNegateRAState (MCSymbol *L, SMLoc Loc = {}) {
654- return MCCFIInstruction ( OpNegateRAState, L, 0 , INT64_C ( 0 ), Loc) ;
646+ return { OpNegateRAState, L, CommonFields{}, Loc} ;
655647 }
656648
657649 // / .cfi_negate_ra_state_with_pc AArch64 negate RA state with PC.
658650 static MCCFIInstruction createNegateRAStateWithPC (MCSymbol *L,
659651 SMLoc Loc = {}) {
660- return MCCFIInstruction ( OpNegateRAStateWithPC, L, 0 , INT64_C ( 0 ), Loc) ;
652+ return { OpNegateRAStateWithPC, L, CommonFields{}, Loc} ;
661653 }
662654
663655 // / .cfi_restore says that the rule for Register is now the same as it
664656 // / was at the beginning of the function, after all initial instructions added
665657 // / by .cfi_startproc were executed.
666658 static MCCFIInstruction createRestore (MCSymbol *L, unsigned Register,
667659 SMLoc Loc = {}) {
668- return MCCFIInstruction ( OpRestore, L, Register, INT64_C ( 0 ), Loc) ;
660+ return { OpRestore, L, CommonFields{ Register}, Loc} ;
669661 }
670662
671663 // / .cfi_undefined From now on the previous value of Register can't be
672664 // / restored anymore.
673665 static MCCFIInstruction createUndefined (MCSymbol *L, unsigned Register,
674666 SMLoc Loc = {}) {
675- return MCCFIInstruction ( OpUndefined, L, Register, INT64_C ( 0 ), Loc) ;
667+ return { OpUndefined, L, CommonFields{ Register}, Loc} ;
676668 }
677669
678670 // / .cfi_same_value Current value of Register is the same as in the
679671 // / previous frame. I.e., no restoration is needed.
680672 static MCCFIInstruction createSameValue (MCSymbol *L, unsigned Register,
681673 SMLoc Loc = {}) {
682- return MCCFIInstruction ( OpSameValue, L, Register, INT64_C ( 0 ), Loc) ;
674+ return { OpSameValue, L, CommonFields{ Register}, Loc} ;
683675 }
684676
685677 // / .cfi_remember_state Save all current rules for all registers.
686678 static MCCFIInstruction createRememberState (MCSymbol *L, SMLoc Loc = {}) {
687- return MCCFIInstruction ( OpRememberState, L, 0 , INT64_C ( 0 ), Loc) ;
679+ return { OpRememberState, L, CommonFields{}, Loc} ;
688680 }
689681
690682 // / .cfi_restore_state Restore the previously saved state.
691683 static MCCFIInstruction createRestoreState (MCSymbol *L, SMLoc Loc = {}) {
692- return MCCFIInstruction ( OpRestoreState, L, 0 , INT64_C ( 0 ), Loc) ;
684+ return { OpRestoreState, L, CommonFields{}, Loc} ;
693685 }
694686
695687 // / .cfi_escape Allows the user to add arbitrary bytes to the unwind
696688 // / info.
697689 static MCCFIInstruction createEscape (MCSymbol *L, StringRef Vals,
698690 SMLoc Loc = {}, StringRef Comment = " " ) {
699- return MCCFIInstruction (OpEscape, L, 0 , 0 , Loc, Vals, Comment);
691+ return {OpEscape, L,
692+ EscapeFields{std::vector<char >(Vals.begin (), Vals.end ()),
693+ Comment.str ()},
694+ Loc};
700695 }
701696
702697 // / A special wrapper for .cfi_escape that indicates GNU_ARGS_SIZE
703698 static MCCFIInstruction createGnuArgsSize (MCSymbol *L, int64_t Size,
704699 SMLoc Loc = {}) {
705- return MCCFIInstruction ( OpGnuArgsSize, L, 0 , Size, Loc) ;
700+ return { OpGnuArgsSize, L, CommonFields{ 0 , Size} , Loc} ;
706701 }
707702
708703 static MCCFIInstruction createLabel (MCSymbol *L, MCSymbol *CfiLabel,
709704 SMLoc Loc) {
710- return MCCFIInstruction ( OpLabel, L, CfiLabel, Loc) ;
705+ return { OpLabel, L, LabelFields{ CfiLabel} , Loc} ;
711706 }
712707
713708 // / .cfi_val_offset Previous value of Register is offset Offset from the
714709 // / current CFA register.
715710 static MCCFIInstruction createValOffset (MCSymbol *L, unsigned Register,
716711 int64_t Offset, SMLoc Loc = {}) {
717- return MCCFIInstruction ( OpValOffset, L, Register, Offset, Loc) ;
712+ return { OpValOffset, L, CommonFields{ Register, Offset} , Loc} ;
718713 }
719714
720715 OpType getOperation () const { return Operation; }
721716 MCSymbol *getLabel () const { return Label; }
722717
723718 unsigned getRegister () const {
724- if (Operation == OpRegister)
725- return U.RR .Register ;
726- if (Operation == OpLLVMDefAspaceCfa)
727- return U.RIA .Register ;
728719 assert (Operation == OpDefCfa || Operation == OpOffset ||
729720 Operation == OpRestore || Operation == OpUndefined ||
730721 Operation == OpSameValue || Operation == OpDefCfaRegister ||
731- Operation == OpRelOffset || Operation == OpValOffset);
732- return U.RI .Register ;
722+ Operation == OpRelOffset || Operation == OpValOffset ||
723+ Operation == OpRegister || Operation == OpLLVMDefAspaceCfa);
724+ return std::get<CommonFields>(ExtraFields).Register ;
733725 }
734726
735727 unsigned getRegister2 () const {
736728 assert (Operation == OpRegister);
737- return U. RR .Register2 ;
729+ return std::get<CommonFields>(ExtraFields) .Register2 ;
738730 }
739731
740732 unsigned getAddressSpace () const {
741733 assert (Operation == OpLLVMDefAspaceCfa);
742- return U. RIA .AddressSpace ;
734+ return std::get<CommonFields>(ExtraFields) .AddressSpace ;
743735 }
744736
745737 int64_t getOffset () const {
746- if (Operation == OpLLVMDefAspaceCfa)
747- return U.RIA .Offset ;
748738 assert (Operation == OpDefCfa || Operation == OpOffset ||
749739 Operation == OpRelOffset || Operation == OpDefCfaOffset ||
750740 Operation == OpAdjustCfaOffset || Operation == OpGnuArgsSize ||
751- Operation == OpValOffset);
752- return U. RI .Offset ;
741+ Operation == OpValOffset || Operation == OpLLVMDefAspaceCfa );
742+ return std::get<CommonFields>(ExtraFields) .Offset ;
753743 }
754744
755745 MCSymbol *getCfiLabel () const {
756746 assert (Operation == OpLabel);
757- return U .CfiLabel ;
747+ return std::get<LabelFields>(ExtraFields) .CfiLabel ;
758748 }
759749
760750 StringRef getValues () const {
761751 assert (Operation == OpEscape);
752+ auto &Values = std::get<EscapeFields>(ExtraFields).Values ;
762753 return StringRef (&Values[0 ], Values.size ());
763754 }
764755
765- StringRef getComment () const { return Comment; }
756+ StringRef getComment () const {
757+ assert (Operation == OpEscape);
758+ return std::get<EscapeFields>(ExtraFields).Comment ;
759+ }
766760 SMLoc getLoc () const { return Loc; }
767761};
768762
0 commit comments