llvm.org GIT mirror llvm / 7d539ce
[codeview] Implement FPO data assembler directives Summary: This adds a set of new directives that describe 32-bit x86 prologues. The directives are limited and do not expose the full complexity of codeview FPO data. They are merely a convenience for the compiler to generate more readable assembly so we don't need to generate tons of labels in CodeGen. If our prologue emission changes in the future, we can change the set of available directives to suit our needs. These are modelled after the .seh_ directives, which use a different format that interacts with exception handling. The directives are: .cv_fpo_proc _foo .cv_fpo_pushreg ebp/ebx/etc .cv_fpo_setframe ebp/esi/etc .cv_fpo_stackalloc 200 .cv_fpo_endprologue .cv_fpo_endproc .cv_fpo_data _foo I tried to follow the implementation of ARM EHABI CFI directives by sinking most directives out of MCStreamer and into X86TargetStreamer. This helps avoid polluting non-X86 code with WinCOFF specific logic. I used cdb to confirm that this can show locals in parent CSRs in a few cases, most importantly the one where we use ESI as a frame pointer, i.e. the one in http://crbug.com/756153#c28 Once we have cdb integration in debuginfo-tests, we can add integration tests there. Reviewers: majnemer, hans Subscribers: aemerson, mgorny, kristof.beyls, llvm-commits, hiraditya Differential Revision: https://reviews.llvm.org/D38776 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@315513 91177308-0d34-0410-b5e6-96231b3b80d8 Reid Kleckner 2 years ago
28 changed file(s) with 2495 addition(s) and 55 deletion(s). Raw diff Collapse all Expand all
275275 /// Emits the offset into the checksum table of the given file number.
276276 void emitFileChecksumOffset(MCObjectStreamer &OS, unsigned FileNo);
277277
278 /// Add something to the string table. Returns the final string as well as
279 /// offset into the string table.
280 std::pair addToStringTable(StringRef S);
281
278282 private:
279283 /// The current CodeView line information from the last .cv_loc directive.
280284 MCCVLoc CurrentCVLoc = MCCVLoc(0, 0, 0, 0, false, true);
289293
290294 MCDataFragment *getStringTableFragment();
291295
292 /// Add something to the string table. Returns the final string as well as
293 /// offset into the string table.
294 std::pair addToStringTable(StringRef S);
295
296296 /// Get a string table offset.
297297 unsigned getStringTableOffset(StringRef S);
298298
788788 /// This implements the CodeView '.cv_filechecksumoffset' assembler
789789 /// directive.
790790 virtual void EmitCVFileChecksumOffsetDirective(unsigned FileNo) {}
791
792 /// This implements the CodeView '.cv_fpo_data' assembler directive.
793 virtual void EmitCVFPOData(const MCSymbol *ProcSym, SMLoc Loc = {}) {}
791794
792795 /// Emit the absolute difference between two symbols.
793796 ///
807807 if (FuncName.empty())
808808 FuncName = GlobalValue::dropLLVMManglingEscape(GV->getName());
809809
810 // Emit FPO data, but only on 32-bit x86. No other platforms use it.
811 if (Triple(MMI->getModule()->getTargetTriple()).getArch() == Triple::x86)
812 OS.EmitCVFPOData(Fn);
813
810814 // Emit a symbol subsection, required by VS2012+ to find function boundaries.
811815 OS.AddComment("Symbol subsection for " + Twine(FuncName));
812816 MCSymbol *SymbolsEnd = beginCVSubsection(DebugSubsectionKind::Symbols);
247247 void EmitCVStringTableDirective() override;
248248 void EmitCVFileChecksumsDirective() override;
249249 void EmitCVFileChecksumOffsetDirective(unsigned FileNo) override;
250 void EmitCVFPOData(const MCSymbol *ProcSym, SMLoc L) override;
250251
251252 void EmitIdent(StringRef IdentString) override;
252253 void EmitCFISections(bool EH, bool Debug) override;
12511252 EmitEOL();
12521253 }
12531254
1255 void MCAsmStreamer::EmitCVFPOData(const MCSymbol *ProcSym, SMLoc L) {
1256 OS << "\t.cv_fpo_data\t";
1257 ProcSym->print(OS, MAI);
1258 EmitEOL();
1259 }
1260
12541261 void MCAsmStreamer::EmitIdent(StringRef IdentString) {
12551262 assert(MAI->hasIdentDirective() && ".ident directive not supported");
12561263 OS << "\t.ident\t";
502502 DK_CV_STRINGTABLE,
503503 DK_CV_FILECHECKSUMS,
504504 DK_CV_FILECHECKSUM_OFFSET,
505 DK_CV_FPO_DATA,
505506 DK_CFI_SECTIONS,
506507 DK_CFI_STARTPROC,
507508 DK_CFI_ENDPROC,
579580 bool parseDirectiveCVStringTable();
580581 bool parseDirectiveCVFileChecksums();
581582 bool parseDirectiveCVFileChecksumOffset();
583 bool parseDirectiveCVFPOData();
582584
583585 // .cfi directives
584586 bool parseDirectiveCFIRegister(SMLoc DirectiveLoc);
20382040 return parseDirectiveCVFileChecksums();
20392041 case DK_CV_FILECHECKSUM_OFFSET:
20402042 return parseDirectiveCVFileChecksumOffset();
2043 case DK_CV_FPO_DATA:
2044 return parseDirectiveCVFPOData();
20412045 case DK_CFI_SECTIONS:
20422046 return parseDirectiveCFISections();
20432047 case DK_CFI_STARTPROC:
37903794 return false;
37913795 }
37923796
3797 /// parseDirectiveCVFPOData
3798 /// ::= .cv_fpo_data procsym
3799 bool AsmParser::parseDirectiveCVFPOData() {
3800 SMLoc DirLoc = getLexer().getLoc();
3801 StringRef ProcName;
3802 if (parseIdentifier(ProcName))
3803 return TokError("expected symbol name");
3804 if (parseEOL("unexpected tokens"))
3805 return addErrorSuffix(" in '.cv_fpo_data' directive");
3806 MCSymbol *ProcSym = getContext().getOrCreateSymbol(ProcName);
3807 getStreamer().EmitCVFPOData(ProcSym, DirLoc);
3808 return false;
3809 }
3810
37933811 /// parseDirectiveCFISections
37943812 /// ::= .cfi_sections section [, section]
37953813 bool AsmParser::parseDirectiveCFISections() {
51735191 DirectiveKindMap[".cv_stringtable"] = DK_CV_STRINGTABLE;
51745192 DirectiveKindMap[".cv_filechecksums"] = DK_CV_FILECHECKSUMS;
51755193 DirectiveKindMap[".cv_filechecksumoffset"] = DK_CV_FILECHECKSUM_OFFSET;
5194 DirectiveKindMap[".cv_fpo_data"] = DK_CV_FPO_DATA;
51765195 DirectiveKindMap[".sleb128"] = DK_SLEB128;
51775196 DirectiveKindMap[".uleb128"] = DK_ULEB128;
51785197 DirectiveKindMap[".cfi_sections"] = DK_CFI_SECTIONS;
66 //
77 //===----------------------------------------------------------------------===//
88
9 #include "InstPrinter/X86IntelInstPrinter.h"
910 #include "MCTargetDesc/X86BaseInfo.h"
11 #include "MCTargetDesc/X86TargetStreamer.h"
1012 #include "X86AsmInstrumentation.h"
1113 #include "X86AsmParserCommon.h"
1214 #include "X86Operand.h"
13 #include "InstPrinter/X86IntelInstPrinter.h"
1415 #include "llvm/ADT/STLExtras.h"
1516 #include "llvm/ADT/SmallString.h"
1617 #include "llvm/ADT/SmallVector.h"
7778 SMLoc Result = Parser.getTok().getLoc();
7879 Parser.Lex();
7980 return Result;
81 }
82
83 X86TargetStreamer &getTargetStreamer() {
84 assert(getParser().getStreamer().getTargetStreamer() &&
85 "do not have a target streamer");
86 MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer();
87 return static_cast(TS);
8088 }
8189
8290 unsigned MatchInstruction(const OperandVector &Operands, MCInst &Inst,
838846 bool ParseDirectiveWord(unsigned Size, SMLoc L);
839847 bool ParseDirectiveCode(StringRef IDVal, SMLoc L);
840848
849 /// CodeView FPO data directives.
850 bool parseDirectiveFPOProc(SMLoc L);
851 bool parseDirectiveFPOSetFrame(SMLoc L);
852 bool parseDirectiveFPOPushReg(SMLoc L);
853 bool parseDirectiveFPOStackAlloc(SMLoc L);
854 bool parseDirectiveFPOEndPrologue(SMLoc L);
855 bool parseDirectiveFPOEndProc(SMLoc L);
856 bool parseDirectiveFPOData(SMLoc L);
857
841858 bool processInstruction(MCInst &Inst, const OperandVector &Ops);
842859
843860 /// Wrapper around MCStreamer::EmitInstruction(). Possibly adds
30263043 return false;
30273044 } else if (IDVal == ".even")
30283045 return parseDirectiveEven(DirectiveID.getLoc());
3046 else if (IDVal == ".cv_fpo_proc")
3047 return parseDirectiveFPOProc(DirectiveID.getLoc());
3048 else if (IDVal == ".cv_fpo_setframe")
3049 return parseDirectiveFPOSetFrame(DirectiveID.getLoc());
3050 else if (IDVal == ".cv_fpo_pushreg")
3051 return parseDirectiveFPOPushReg(DirectiveID.getLoc());
3052 else if (IDVal == ".cv_fpo_stackalloc")
3053 return parseDirectiveFPOStackAlloc(DirectiveID.getLoc());
3054 else if (IDVal == ".cv_fpo_endprologue")
3055 return parseDirectiveFPOEndPrologue(DirectiveID.getLoc());
3056 else if (IDVal == ".cv_fpo_endproc")
3057 return parseDirectiveFPOEndProc(DirectiveID.getLoc());
3058
30293059 return true;
30303060 }
30313061
31233153 return false;
31243154 }
31253155
3156 // .cv_fpo_proc foo
3157 bool X86AsmParser::parseDirectiveFPOProc(SMLoc L) {
3158 MCAsmParser &Parser = getParser();
3159 StringRef ProcName;
3160 int64_t ParamsSize;
3161 if (Parser.parseIdentifier(ProcName))
3162 return Parser.TokError("expected symbol name");
3163 if (Parser.parseIntToken(ParamsSize, "expected parameter byte count"))
3164 return true;
3165 if (!isUIntN(32, ParamsSize))
3166 return Parser.TokError("parameters size out of range");
3167 if (Parser.parseEOL("unexpected tokens"))
3168 return addErrorSuffix(" in '.cv_fpo_proc' directive");
3169 MCSymbol *ProcSym = getContext().getOrCreateSymbol(ProcName);
3170 return getTargetStreamer().emitFPOProc(ProcSym, ParamsSize, L);
3171 }
3172
3173 // .cv_fpo_setframe ebp
3174 bool X86AsmParser::parseDirectiveFPOSetFrame(SMLoc L) {
3175 MCAsmParser &Parser = getParser();
3176 unsigned Reg;
3177 SMLoc DummyLoc;
3178 if (ParseRegister(Reg, DummyLoc, DummyLoc) ||
3179 Parser.parseEOL("unexpected tokens"))
3180 return addErrorSuffix(" in '.cv_fpo_setframe' directive");
3181 return getTargetStreamer().emitFPOSetFrame(Reg, L);
3182 }
3183
3184 // .cv_fpo_pushreg ebx
3185 bool X86AsmParser::parseDirectiveFPOPushReg(SMLoc L) {
3186 MCAsmParser &Parser = getParser();
3187 unsigned Reg;
3188 SMLoc DummyLoc;
3189 if (ParseRegister(Reg, DummyLoc, DummyLoc) ||
3190 Parser.parseEOL("unexpected tokens"))
3191 return addErrorSuffix(" in '.cv_fpo_pushreg' directive");
3192 return getTargetStreamer().emitFPOPushReg(Reg, L);
3193 }
3194
3195 // .cv_fpo_stackalloc 20
3196 bool X86AsmParser::parseDirectiveFPOStackAlloc(SMLoc L) {
3197 MCAsmParser &Parser = getParser();
3198 int64_t Offset;
3199 if (Parser.parseIntToken(Offset, "expected offset") ||
3200 Parser.parseEOL("unexpected tokens"))
3201 return addErrorSuffix(" in '.cv_fpo_stackalloc' directive");
3202 return getTargetStreamer().emitFPOStackAlloc(Offset, L);
3203 }
3204
3205 // .cv_fpo_endprologue
3206 bool X86AsmParser::parseDirectiveFPOEndPrologue(SMLoc L) {
3207 MCAsmParser &Parser = getParser();
3208 if (Parser.parseEOL("unexpected tokens"))
3209 return addErrorSuffix(" in '.cv_fpo_endprologue' directive");
3210 return getTargetStreamer().emitFPOEndPrologue(L);
3211 }
3212
3213 // .cv_fpo_endproc
3214 bool X86AsmParser::parseDirectiveFPOEndProc(SMLoc L) {
3215 MCAsmParser &Parser = getParser();
3216 if (Parser.parseEOL("unexpected tokens"))
3217 return addErrorSuffix(" in '.cv_fpo_endproc' directive");
3218 return getTargetStreamer().emitFPOEndProc(L);
3219 }
3220
31263221 // Force static initialization.
31273222 extern "C" void LLVMInitializeX86AsmParser() {
31283223 RegisterMCAsmParser X(getTheX86_32Target());
44 X86MCCodeEmitter.cpp
55 X86MachObjectWriter.cpp
66 X86ELFObjectWriter.cpp
7 X86WinCOFFObjectWriter.cpp
78 X86WinCOFFStreamer.cpp
8 X86WinCOFFObjectWriter.cpp
9 X86WinCOFFTargetStreamer.cpp
910 )
318318 // Register the code emitter.
319319 TargetRegistry::RegisterMCCodeEmitter(*T, createX86MCCodeEmitter);
320320
321 // Register the object streamer.
321 // Register the obj target streamer.
322 TargetRegistry::RegisterObjectTargetStreamer(*T,
323 createX86ObjectTargetStreamer);
324
325 // Register the asm target streamer.
326 TargetRegistry::RegisterAsmTargetStreamer(*T, createX86AsmTargetStreamer);
327
322328 TargetRegistry::RegisterCOFFStreamer(*T, createX86WinCOFFStreamer);
323329
324330 // Register the MCInstPrinter.
7676 const Triple &TT, StringRef CPU,
7777 const MCTargetOptions &Options);
7878
79 /// Implements X86-only directives for assembly emission.
80 MCTargetStreamer *createX86AsmTargetStreamer(MCStreamer &S,
81 formatted_raw_ostream &OS,
82 MCInstPrinter *InstPrint,
83 bool isVerboseAsm);
84
85 /// Implements X86-only directives for object files.
86 MCTargetStreamer *createX86ObjectTargetStreamer(MCStreamer &OS,
87 const MCSubtargetInfo &STI);
88
7989 /// Construct an X86 Windows COFF machine code streamer which will generate
8090 /// PE/COFF format object files.
8191 ///
0 //===- X86TargetStreamer.h ------------------------------*- C++ -*---------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_LIB_TARGET_X86_MCTARGETDESC_X86TARGETSTREAMER_H
10 #define LLVM_LIB_TARGET_X86_MCTARGETDESC_X86TARGETSTREAMER_H
11
12 #include "llvm/MC/MCStreamer.h"
13
14 namespace llvm {
15
16 /// X86 target streamer implementing x86-only assembly directives.
17 class X86TargetStreamer : public MCTargetStreamer {
18 public:
19 X86TargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {}
20
21 virtual bool emitFPOProc(const MCSymbol *ProcSym, unsigned ParamsSize,
22 SMLoc L = {}) = 0;
23 virtual bool emitFPOEndPrologue(SMLoc L = {}) = 0;
24 virtual bool emitFPOEndProc(SMLoc L = {}) = 0;
25 virtual bool emitFPOData(const MCSymbol *ProcSym, SMLoc L = {}) = 0;
26 virtual bool emitFPOPushReg(unsigned Reg, SMLoc L = {}) = 0;
27 virtual bool emitFPOStackAlloc(unsigned StackAlloc, SMLoc L = {}) = 0;
28 virtual bool emitFPOSetFrame(unsigned Reg, SMLoc L = {}) = 0;
29 };
30
31 } // end namespace llvm
32
33 #endif
77 //===----------------------------------------------------------------------===//
88
99 #include "X86MCTargetDesc.h"
10 #include "X86TargetStreamer.h"
1011 #include "llvm/MC/MCAsmBackend.h"
1112 #include "llvm/MC/MCWin64EH.h"
1213 #include "llvm/MC/MCWinCOFFStreamer.h"
2324
2425 void EmitWinEHHandlerData(SMLoc Loc) override;
2526 void EmitWindowsUnwindTables() override;
27 void EmitCVFPOData(const MCSymbol *ProcSym, SMLoc Loc) override;
2628 void FinishImpl() override;
2729 };
2830
3840 if (!getNumWinFrameInfos())
3941 return;
4042 EHStreamer.Emit(*this);
43 }
44
45 void X86WinCOFFStreamer::EmitCVFPOData(const MCSymbol *ProcSym, SMLoc Loc) {
46 X86TargetStreamer *XTS =
47 static_cast(getTargetStreamer());
48 XTS->emitFPOData(ProcSym, Loc);
4149 }
4250
4351 void X86WinCOFFStreamer::FinishImpl() {
0 //===-- X86WinCOFFTargetStreamer.cpp ----------------------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "X86MCTargetDesc.h"
10 #include "X86TargetStreamer.h"
11 #include "llvm/DebugInfo/CodeView/CodeView.h"
12 #include "llvm/MC/MCCodeView.h"
13 #include "llvm/MC/MCContext.h"
14 #include "llvm/MC/MCInstPrinter.h"
15 #include "llvm/MC/MCRegisterInfo.h"
16 #include "llvm/MC/MCSubtargetInfo.h"
17 #include "llvm/Support/FormattedStream.h"
18
19 using namespace llvm;
20 using namespace llvm::codeview;
21
22 namespace {
23 /// Implements Windows x86-only directives for assembly emission.
24 class X86WinCOFFAsmTargetStreamer : public X86TargetStreamer {
25 formatted_raw_ostream &OS;
26 MCInstPrinter &InstPrinter;
27
28 public:
29 X86WinCOFFAsmTargetStreamer(MCStreamer &S, formatted_raw_ostream &OS,
30 MCInstPrinter &InstPrinter)
31 : X86TargetStreamer(S), OS(OS), InstPrinter(InstPrinter) {}
32
33 bool emitFPOProc(const MCSymbol *ProcSym, unsigned ParamsSize,
34 SMLoc L) override;
35 bool emitFPOEndPrologue(SMLoc L) override;
36 bool emitFPOEndProc(SMLoc L) override;
37 bool emitFPOData(const MCSymbol *ProcSym, SMLoc L) override;
38 bool emitFPOPushReg(unsigned Reg, SMLoc L) override;
39 bool emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) override;
40 bool emitFPOSetFrame(unsigned Reg, SMLoc L) override;
41 };
42
43 /// Represents a single FPO directive.
44 struct FPOInstruction {
45 MCSymbol *Label;
46 enum Operation {
47 PushReg,
48 StackAlloc,
49 SetFrame,
50 } Op;
51 unsigned RegOrOffset;
52 };
53
54 struct FPOData {
55 const MCSymbol *Function = nullptr;
56 MCSymbol *Begin = nullptr;
57 MCSymbol *PrologueEnd = nullptr;
58 MCSymbol *End = nullptr;
59 unsigned ParamsSize = 0;
60
61 SmallVector Instructions;
62 };
63
64 /// Implements Windows x86-only directives for object emission.
65 class X86WinCOFFTargetStreamer : public X86TargetStreamer {
66 /// Map from function symbol to its FPO data.
67 DenseMap> AllFPOData;
68
69 /// Current FPO data created by .cv_fpo_proc.
70 std::unique_ptr CurFPOData;
71
72 bool haveOpenFPOData() { return !!CurFPOData; }
73
74 /// Diagnoses an error at L if we are not in an FPO prologue. Return true on
75 /// error.
76 bool checkInFPOPrologue(SMLoc L);
77
78 MCSymbol *emitFPOLabel();
79
80 MCContext &getContext() { return getStreamer().getContext(); }
81
82 public:
83 X86WinCOFFTargetStreamer(MCStreamer &S) : X86TargetStreamer(S) {}
84
85 bool emitFPOProc(const MCSymbol *ProcSym, unsigned ParamsSize,
86 SMLoc L) override;
87 bool emitFPOEndPrologue(SMLoc L) override;
88 bool emitFPOEndProc(SMLoc L) override;
89 bool emitFPOData(const MCSymbol *ProcSym, SMLoc L) override;
90 bool emitFPOPushReg(unsigned Reg, SMLoc L) override;
91 bool emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) override;
92 bool emitFPOSetFrame(unsigned Reg, SMLoc L) override;
93 };
94 } // end namespace
95
96 bool X86WinCOFFAsmTargetStreamer::emitFPOProc(const MCSymbol *ProcSym,
97 unsigned ParamsSize, SMLoc L) {
98 OS << "\t.cv_fpo_proc\t";
99 ProcSym->print(OS, getStreamer().getContext().getAsmInfo());
100 OS << ' ' << ParamsSize << '\n';
101 return false;
102 }
103
104 bool X86WinCOFFAsmTargetStreamer::emitFPOEndPrologue(SMLoc L) {
105 OS << "\t.cv_fpo_endprologue\n";
106 return false;
107 }
108
109 bool X86WinCOFFAsmTargetStreamer::emitFPOEndProc(SMLoc L) {
110 OS << "\t.cv_fpo_endproc\n";
111 return false;
112 }
113
114 bool X86WinCOFFAsmTargetStreamer::emitFPOData(const MCSymbol *ProcSym,
115 SMLoc L) {
116 OS << "\t.cv_fpo_data\t";
117 ProcSym->print(OS, getStreamer().getContext().getAsmInfo());
118 OS << '\n';
119 return false;
120 }
121
122 bool X86WinCOFFAsmTargetStreamer::emitFPOPushReg(unsigned Reg, SMLoc L) {
123 OS << "\t.cv_fpo_pushreg\t";
124 InstPrinter.printRegName(OS, Reg);
125 OS << '\n';
126 return false;
127 }
128
129 bool X86WinCOFFAsmTargetStreamer::emitFPOStackAlloc(unsigned StackAlloc,
130 SMLoc L) {
131 OS << "\t.cv_fpo_stackalloc\t" << StackAlloc << '\n';
132 return false;
133 }
134
135 bool X86WinCOFFAsmTargetStreamer::emitFPOSetFrame(unsigned Reg, SMLoc L) {
136 OS << "\t.cv_fpo_setframe\t";
137 InstPrinter.printRegName(OS, Reg);
138 OS << '\n';
139 return false;
140 }
141
142 bool X86WinCOFFTargetStreamer::checkInFPOPrologue(SMLoc L) {
143 if (!haveOpenFPOData() || CurFPOData->PrologueEnd) {
144 getContext().reportError(
145 L,
146 "directive must appear between .cv_fpo_proc and .cv_fpo_endprologue");
147 return true;
148 }
149 return false;
150 }
151
152 MCSymbol *X86WinCOFFTargetStreamer::emitFPOLabel() {
153 MCSymbol *Label = getContext().createTempSymbol("cfi", true);
154 getStreamer().EmitLabel(Label);
155 return Label;
156 }
157
158 bool X86WinCOFFTargetStreamer::emitFPOProc(const MCSymbol *ProcSym,
159 unsigned ParamsSize, SMLoc L) {
160 if (haveOpenFPOData()) {
161 getContext().reportError(
162 L, "opening new .cv_fpo_proc before closing previous frame");
163 return true;
164 }
165 CurFPOData = llvm::make_unique();
166 CurFPOData->Function = ProcSym;
167 CurFPOData->Begin = emitFPOLabel();
168 CurFPOData->ParamsSize = ParamsSize;
169 return false;
170 }
171
172 bool X86WinCOFFTargetStreamer::emitFPOEndProc(SMLoc L) {
173 if (!haveOpenFPOData()) {
174 getContext().reportError(L, ".cv_fpo_endproc must appear after .cv_proc");
175 return true;
176 }
177 if (!CurFPOData->PrologueEnd) {
178 // Complain if there were prologue setup instructions but no end prologue.
179 if (!CurFPOData->Instructions.empty()) {
180 getContext().reportError(L, "missing .cv_fpo_endprologue");
181 CurFPOData->Instructions.clear();
182 }
183
184 // Claim there is a zero-length prologue to make the label math work out
185 // later.
186 CurFPOData->PrologueEnd = CurFPOData->Begin;
187 }
188
189 CurFPOData->End = emitFPOLabel();
190 const MCSymbol *Fn = CurFPOData->Function;
191 AllFPOData.insert({Fn, std::move(CurFPOData)});
192 return false;
193 }
194
195 bool X86WinCOFFTargetStreamer::emitFPOSetFrame(unsigned Reg, SMLoc L) {
196 if (checkInFPOPrologue(L))
197 return true;
198 FPOInstruction Inst;
199 Inst.Label = emitFPOLabel();
200 Inst.Op = FPOInstruction::SetFrame;
201 Inst.RegOrOffset = Reg;
202 CurFPOData->Instructions.push_back(Inst);
203 return false;
204 }
205
206 bool X86WinCOFFTargetStreamer::emitFPOPushReg(unsigned Reg, SMLoc L) {
207 if (checkInFPOPrologue(L))
208 return true;
209 FPOInstruction Inst;
210 Inst.Label = emitFPOLabel();
211 Inst.Op = FPOInstruction::PushReg;
212 Inst.RegOrOffset = Reg;
213 CurFPOData->Instructions.push_back(Inst);
214 return false;
215 }
216
217 bool X86WinCOFFTargetStreamer::emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) {
218 if (checkInFPOPrologue(L))
219 return true;
220 FPOInstruction Inst;
221 Inst.Label = emitFPOLabel();
222 Inst.Op = FPOInstruction::StackAlloc;
223 Inst.RegOrOffset = StackAlloc;
224 CurFPOData->Instructions.push_back(Inst);
225 return false;
226 }
227
228 bool X86WinCOFFTargetStreamer::emitFPOEndPrologue(SMLoc L) {
229 if (checkInFPOPrologue(L))
230 return true;
231 CurFPOData->PrologueEnd = emitFPOLabel();
232 return false;
233 }
234
235 namespace {
236 struct RegSaveOffset {
237 RegSaveOffset(unsigned Reg, unsigned Offset) : Reg(Reg), Offset(Offset) {}
238
239 unsigned Reg = 0;
240 unsigned Offset = 0;
241 };
242
243 struct FPOStateMachine {
244 explicit FPOStateMachine(const FPOData *FPO) : FPO(FPO) {}
245
246 const FPOData *FPO = nullptr;
247 unsigned FrameReg = 0;
248 unsigned FrameRegOff = 0;
249 unsigned CurOffset = 0;
250 unsigned LocalSize = 0;
251 unsigned SavedRegSize = 0;
252 unsigned Flags = 0; // FIXME: Set HasSEH / HasEH.
253
254 SmallString<128> FrameFunc;
255
256 SmallVector RegSaveOffsets;
257
258 void emitFrameDataRecord(MCStreamer &OS, MCSymbol *Label);
259 };
260 } // end namespace
261
262 static Printable printFPOReg(const MCRegisterInfo *MRI, unsigned LLVMReg) {
263 return Printable([MRI, LLVMReg](raw_ostream &OS) {
264 switch (LLVMReg) {
265 // MSVC only seems to emit symbolic register names for EIP, EBP, and ESP,
266 // but the format seems to support more than that, so we emit them.
267 case X86::EAX: OS << "$eax"; break;
268 case X86::EBX: OS << "$ebx"; break;
269 case X86::ECX: OS << "$ecx"; break;
270 case X86::EDX: OS << "$edx"; break;
271 case X86::EDI: OS << "$edi"; break;
272 case X86::ESI: OS << "$esi"; break;
273 case X86::ESP: OS << "$esp"; break;
274 case X86::EBP: OS << "$ebp"; break;
275 case X86::EIP: OS << "$eip"; break;
276 // Otherwise, get the codeview register number and print $N.
277 default:
278 OS << '$' << MRI->getCodeViewRegNum(LLVMReg);
279 break;
280 }
281 });
282 }
283
284 void FPOStateMachine::emitFrameDataRecord(MCStreamer &OS, MCSymbol *Label) {
285 unsigned CurFlags = Flags;
286 if (Label == FPO->Begin)
287 CurFlags |= FrameData::IsFunctionStart;
288
289 // Compute the new FrameFunc string.
290 FrameFunc.clear();
291 raw_svector_ostream FuncOS(FrameFunc);
292 const MCRegisterInfo *MRI = OS.getContext().getRegisterInfo();
293 if (FrameReg) {
294 // CFA is FrameReg + FrameRegOff.
295 FuncOS << "$T0 " << printFPOReg(MRI, FrameReg) << " " << FrameRegOff
296 << " + = ";
297 } else {
298 // The address of return address is ESP + CurOffset, but we use .raSearch to
299 // match MSVC. This seems to ask the debugger to subtract some combination
300 // of LocalSize and SavedRegSize from ESP and grovel around in that memory
301 // to find the address of a plausible return address.
302 FuncOS << "$T0 .raSearch = ";
303 }
304
305 // Caller's $eip should be dereferenced CFA, and $esp should be CFA plus 4.
306 FuncOS << "$eip $T0 ^ = $esp $T0 4 + = ";
307
308 // Each saved register is stored at an unchanging negative CFA offset.
309 for (RegSaveOffset RO : RegSaveOffsets)
310 FuncOS << printFPOReg(MRI, RO.Reg) << " $T0 " << RO.Offset << " - ^ = ";
311
312 // Add it to the CV string table.
313 CodeViewContext &CVCtx = OS.getContext().getCVContext();
314 unsigned FrameFuncStrTabOff = CVCtx.addToStringTable(FuncOS.str()).second;
315
316 // MSVC has only ever been observed to emit a MaxStackSize of zero.
317 unsigned MaxStackSize = 0;
318
319 // The FrameData record format is:
320 // ulittle32_t RvaStart;
321 // ulittle32_t CodeSize;
322 // ulittle32_t LocalSize;
323 // ulittle32_t ParamsSize;
324 // ulittle32_t MaxStackSize;
325 // ulittle32_t FrameFunc; // String table offset
326 // ulittle16_t PrologSize;
327 // ulittle16_t SavedRegsSize;
328 // ulittle32_t Flags;
329
330 OS.emitAbsoluteSymbolDiff(Label, FPO->Begin, 4); // RvaStart
331 OS.emitAbsoluteSymbolDiff(FPO->End, Label, 4); // CodeSize
332 OS.EmitIntValue(LocalSize, 4);
333 OS.EmitIntValue(FPO->ParamsSize, 4);
334 OS.EmitIntValue(MaxStackSize, 4);
335 OS.EmitIntValue(FrameFuncStrTabOff, 4); // FrameFunc
336 OS.emitAbsoluteSymbolDiff(FPO->PrologueEnd, Label, 2);
337 OS.EmitIntValue(SavedRegSize, 2);
338 OS.EmitIntValue(CurFlags, 4);
339 }
340
341 /// Compute and emit the real CodeView FrameData subsection.
342 bool X86WinCOFFTargetStreamer::emitFPOData(const MCSymbol *ProcSym, SMLoc L) {
343 MCStreamer &OS = getStreamer();
344 MCContext &Ctx = OS.getContext();
345
346 auto I = AllFPOData.find(ProcSym);
347 if (I == AllFPOData.end()) {
348 Ctx.reportError(L, Twine("no FPO data found for symbol ") +
349 ProcSym->getName());
350 return true;
351 }
352 const FPOData *FPO = I->second.get();
353 assert(FPO->Begin && FPO->End && FPO->PrologueEnd && "missing FPO label");
354
355 MCSymbol *FrameBegin = Ctx.createTempSymbol(),
356 *FrameEnd = Ctx.createTempSymbol();
357
358 OS.EmitIntValue(unsigned(DebugSubsectionKind::FrameData), 4);
359 OS.emitAbsoluteSymbolDiff(FrameEnd, FrameBegin, 4);
360 OS.EmitLabel(FrameBegin);
361
362 // Start with the RVA of the function in question.
363 OS.EmitValue(MCSymbolRefExpr::create(FPO->Function,
364 MCSymbolRefExpr::VK_COFF_IMGREL32, Ctx),
365 4);
366
367 // Emit a sequence of FrameData records.
368 FPOStateMachine FSM(FPO);
369
370 FSM.emitFrameDataRecord(OS, FPO->Begin);
371 for (const FPOInstruction &Inst : FPO->Instructions) {
372 switch (Inst.Op) {
373 case FPOInstruction::PushReg:
374 FSM.CurOffset += 4;
375 FSM.SavedRegSize += 4;
376 FSM.RegSaveOffsets.push_back({Inst.RegOrOffset, FSM.CurOffset});
377 break;
378 case FPOInstruction::SetFrame:
379 FSM.FrameReg = Inst.RegOrOffset;
380 FSM.FrameRegOff = FSM.CurOffset;
381 break;
382 case FPOInstruction::StackAlloc:
383 FSM.CurOffset += Inst.RegOrOffset;
384 FSM.LocalSize += Inst.RegOrOffset;
385 // No need to emit FrameData for stack allocations with a frame pointer.
386 if (FSM.FrameReg)
387 continue;
388 break;
389 }
390 FSM.emitFrameDataRecord(OS, Inst.Label);
391 }
392
393 OS.EmitValueToAlignment(4, 0);
394 OS.EmitLabel(FrameEnd);
395 return false;
396 }
397
398 MCTargetStreamer *llvm::createX86AsmTargetStreamer(MCStreamer &S,
399 formatted_raw_ostream &OS,
400 MCInstPrinter *InstPrinter,
401 bool IsVerboseAsm) {
402 // FIXME: This makes it so we textually assemble COFF directives on ELF.
403 // That's kind of nonsensical.
404 return new X86WinCOFFAsmTargetStreamer(S, OS, *InstPrinter);
405 }
406
407 MCTargetStreamer *
408 llvm::createX86ObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) {
409 // No need to register a target streamer.
410 if (!STI.getTargetTriple().isOSBinFormatCOFF())
411 return nullptr;
412 // Registers itself to the MCStreamer.
413 return new X86WinCOFFTargetStreamer(S);
414 }
1414 #include "X86AsmPrinter.h"
1515 #include "InstPrinter/X86ATTInstPrinter.h"
1616 #include "MCTargetDesc/X86BaseInfo.h"
17 #include "MCTargetDesc/X86TargetStreamer.h"
1718 #include "X86InstrInfo.h"
1819 #include "X86MachineFunctionInfo.h"
1920 #include "llvm/BinaryFormat/COFF.h"
5051
5152 SMShadowTracker.startFunction(MF);
5253 CodeEmitter.reset(TM.getTarget().createMCCodeEmitter(
53 *MF.getSubtarget().getInstrInfo(), *MF.getSubtarget().getRegisterInfo(),
54 *Subtarget->getInstrInfo(), *Subtarget->getRegisterInfo(),
5455 MF.getContext()));
56
57 EmitFPOData =
58 Subtarget->isTargetWin32() && MF.getMMI().getModule()->getCodeViewFlag();
5559
5660 SetupMachineFunction(MF);
5761
7175 // Emit the XRay table for this function.
7276 emitXRayTable();
7377
78 EmitFPOData = false;
79
7480 // We didn't modify anything.
7581 return false;
82 }
83
84 void X86AsmPrinter::EmitFunctionBodyStart() {
85 if (EmitFPOData) {
86 X86TargetStreamer *XTS =
87 static_cast(OutStreamer->getTargetStreamer());
88 unsigned ParamsSize =
89 MF->getInfo()->getArgumentStackSize();
90 XTS->emitFPOProc(CurrentFnSym, ParamsSize);
91 }
92 }
93
94 void X86AsmPrinter::EmitFunctionBodyEnd() {
95 if (EmitFPOData) {
96 X86TargetStreamer *XTS =
97 static_cast(OutStreamer->getTargetStreamer());
98 XTS->emitFPOEndProc();
99 }
76100 }
77101
78102 /// printSymbolOperand - Print a raw symbol reference operand. This handles
2929 StackMaps SM;
3030 FaultMaps FM;
3131 std::unique_ptr CodeEmitter;
32 bool EmitFPOData = false;
3233
3334 // This utility class tracks the length of a stackmap instruction's 'shadow'.
3435 // It is used by the X86AsmPrinter to ensure that the stackmap shadow
9899 // function.
99100 void EmitXRayTable();
100101
102 // Choose between emitting .seh_ directives and .cv_fpo_ directives.
103 void EmitSEHInstruction(const MachineInstr *MI);
104
101105 public:
102106 explicit X86AsmPrinter(TargetMachine &TM,
103107 std::unique_ptr Streamer)
136140 }
137141
138142 bool runOnMachineFunction(MachineFunction &F) override;
143 void EmitFunctionBodyStart() override;
144 void EmitFunctionBodyEnd() override;
139145 };
140146
141147 } // end namespace llvm
923923
924924 Notes:
925925 - .seh directives are emitted only for Windows 64 ABI
926 - .cv_fpo directives are emitted on win32 when emitting CodeView
926927 - .cfi directives are emitted for all other ABIs
927928 - for 32-bit code, substitute %e?? registers for %r??
928929 */
948949 bool HasFP = hasFP(MF);
949950 bool IsWin64CC = STI.isCallingConvWin64(Fn->getCallingConv());
950951 bool IsWin64Prologue = MF.getTarget().getMCAsmInfo()->usesWindowsCFI();
951 bool NeedsWinCFI = IsWin64Prologue && Fn->needsUnwindTableEntry();
952 bool NeedsWin64CFI = IsWin64Prologue && Fn->needsUnwindTableEntry();
953 bool NeedsWinFPO = STI.isTargetWin32() && MMI.getModule()->getCodeViewFlag();
954 bool NeedsWinCFI = NeedsWin64CFI || NeedsWinFPO;
952955 bool NeedsDwarfCFI =
953956 !IsWin64Prologue && (MMI.hasDebugInfo() || Fn->needsUnwindTableEntry());
954957 unsigned FramePtr = TRI->getFrameRegister(MF);
957960 ? getX86SubSuperRegister(FramePtr, 64) : FramePtr;
958961 unsigned BasePtr = TRI->getBaseRegister();
959962 bool HasWinCFI = false;
960
963
961964 // Debug location must be unknown since the first debug location is used
962965 // to determine the end of the prologue.
963966 DebugLoc DL;
11191122 BuildCFI(MBB, MBBI, DL, MCCFIInstruction::createDefCfaRegister(
11201123 nullptr, DwarfFramePtr));
11211124 }
1125
1126 if (NeedsWinFPO) {
1127 // .cv_fpo_setframe $FramePtr
1128 HasWinCFI = true;
1129 BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_SetFrame))
1130 .addImm(FramePtr)
1131 .addImm(0)
1132 .setMIFlag(MachineInstr::FrameSetup);
1133 }
11221134 }
11231135 } else {
11241136 assert(!IsFunclet && "funclets without FPs not yet implemented");
11541166
11551167 if (NeedsWinCFI) {
11561168 HasWinCFI = true;
1157 BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_PushReg)).addImm(Reg).setMIFlag(
1158 MachineInstr::FrameSetup);
1169 BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_PushReg))
1170 .addImm(Reg)
1171 .setMIFlag(MachineInstr::FrameSetup);
11591172 }
11601173 }
11611174
12941307
12951308 // If this is not a funclet, emit the CFI describing our frame pointer.
12961309 if (NeedsWinCFI && !IsFunclet) {
1310 assert(!NeedsWinFPO && "this setframe incompatible with FPO data");
12971311 HasWinCFI = true;
12981312 BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_SetFrame))
12991313 .addImm(FramePtr)
13321346 Offset += SEHFrameOffset;
13331347
13341348 HasWinCFI = true;
1349 assert(!NeedsWinFPO && "SEH_SaveXMM incompatible with FPO data");
13351350 BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_SaveXMM))
13361351 .addImm(Reg)
13371352 .addImm(Offset)
15331548 Is64BitILP32 ? getX86SubSuperRegister(FramePtr, 64) : FramePtr;
15341549
15351550 bool IsWin64Prologue = MF.getTarget().getMCAsmInfo()->usesWindowsCFI();
1536 bool NeedsWinCFI =
1551 bool NeedsWin64CFI =
15371552 IsWin64Prologue && MF.getFunction()->needsUnwindTableEntry();
15381553 bool IsFunclet = MBBI == MBB.end() ? false : isFuncletReturnInstr(*MBBI);
15391554
16381653 // into the epilogue. To cope with that, we insert an epilogue marker here,
16391654 // then replace it with a 'nop' if it ends up immediately after a CALL in the
16401655 // final emitted code.
1641 if (NeedsWinCFI && MF.hasWinCFI())
1656 if (NeedsWin64CFI && MF.hasWinCFI())
16421657 BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_Epilogue));
16431658
16441659 if (Terminator == MBB.end() || !isTailCallOpcode(Terminator->getOpcode())) {
1414 #include "InstPrinter/X86ATTInstPrinter.h"
1515 #include "InstPrinter/X86InstComments.h"
1616 #include "MCTargetDesc/X86BaseInfo.h"
17 #include "MCTargetDesc/X86TargetStreamer.h"
1718 #include "Utils/X86ShuffleDecode.h"
1819 #include "X86AsmPrinter.h"
1920 #include "X86RegisterInfo.h"
13621363 }
13631364 }
13641365
1366 void X86AsmPrinter::EmitSEHInstruction(const MachineInstr *MI) {
1367 assert(MF->hasWinCFI() && "SEH_ instruction in function without WinCFI?");
1368 assert(getSubtarget().isOSWindows() && "SEH_ instruction Windows only");
1369 const X86RegisterInfo *RI =
1370 MF->getSubtarget().getRegisterInfo();
1371
1372 // Use the .cv_fpo directives if we're emitting CodeView on 32-bit x86.
1373 if (EmitFPOData) {
1374 X86TargetStreamer *XTS =
1375 static_cast(OutStreamer->getTargetStreamer());
1376 switch (MI->getOpcode()) {
1377 case X86::SEH_PushReg:
1378 XTS->emitFPOPushReg(MI->getOperand(0).getImm());
1379 break;
1380 case X86::SEH_StackAlloc:
1381 XTS->emitFPOStackAlloc(MI->getOperand(0).getImm());
1382 break;
1383 case X86::SEH_SetFrame:
1384 assert(MI->getOperand(1).getImm() == 0 &&
1385 ".cv_fpo_setframe takes no offset");
1386 XTS->emitFPOSetFrame(MI->getOperand(0).getImm());
1387 break;
1388 case X86::SEH_EndPrologue:
1389 XTS->emitFPOEndPrologue();
1390 break;
1391 case X86::SEH_SaveReg:
1392 case X86::SEH_SaveXMM:
1393 case X86::SEH_PushFrame:
1394 llvm_unreachable("SEH_ directive incompatible with FPO");
1395 break;
1396 default:
1397 llvm_unreachable("expected SEH_ instruction");
1398 }
1399 return;
1400 }
1401
1402 // Otherwise, use the .seh_ directives for all other Windows platforms.
1403 switch (MI->getOpcode()) {
1404 case X86::SEH_PushReg:
1405 OutStreamer->EmitWinCFIPushReg(
1406 RI->getSEHRegNum(MI->getOperand(0).getImm()));
1407 break;
1408
1409 case X86::SEH_SaveReg:
1410 OutStreamer->EmitWinCFISaveReg(RI->getSEHRegNum(MI->getOperand(0).getImm()),
1411 MI->getOperand(1).getImm());
1412 break;
1413
1414 case X86::SEH_SaveXMM:
1415 OutStreamer->EmitWinCFISaveXMM(RI->getSEHRegNum(MI->getOperand(0).getImm()),
1416 MI->getOperand(1).getImm());
1417 break;
1418
1419 case X86::SEH_StackAlloc:
1420 OutStreamer->EmitWinCFIAllocStack(MI->getOperand(0).getImm());
1421 break;
1422
1423 case X86::SEH_SetFrame:
1424 OutStreamer->EmitWinCFISetFrame(
1425 RI->getSEHRegNum(MI->getOperand(0).getImm()),
1426 MI->getOperand(1).getImm());
1427 break;
1428
1429 case X86::SEH_PushFrame:
1430 OutStreamer->EmitWinCFIPushFrame(MI->getOperand(0).getImm());
1431 break;
1432
1433 case X86::SEH_EndPrologue:
1434 OutStreamer->EmitWinCFIEndProlog();
1435 break;
1436
1437 default:
1438 llvm_unreachable("expected SEH_ instruction");
1439 }
1440 }
1441
13651442 void X86AsmPrinter::EmitInstruction(const MachineInstr *MI) {
13661443 X86MCInstLower MCInstLowering(*MF, *this);
13671444 const X86RegisterInfo *RI = MF->getSubtarget().getRegisterInfo();
15391616 return;
15401617
15411618 case X86::SEH_PushReg:
1542 assert(MF->hasWinCFI() && "SEH_ instruction in function without WinCFI?");
1543 OutStreamer->EmitWinCFIPushReg(RI->getSEHRegNum(MI->getOperand(0).getImm()));
1544 return;
1545
15461619 case X86::SEH_SaveReg:
1547 assert(MF->hasWinCFI() && "SEH_ instruction in function without WinCFI?");
1548 OutStreamer->EmitWinCFISaveReg(RI->getSEHRegNum(MI->getOperand(0).getImm()),
1549 MI->getOperand(1).getImm());
1550 return;
1551
15521620 case X86::SEH_SaveXMM:
1553 assert(MF->hasWinCFI() && "SEH_ instruction in function without WinCFI?");
1554 OutStreamer->EmitWinCFISaveXMM(RI->getSEHRegNum(MI->getOperand(0).getImm()),
1555 MI->getOperand(1).getImm());
1556 return;
1557
15581621 case X86::SEH_StackAlloc:
1559 assert(MF->hasWinCFI() && "SEH_ instruction in function without WinCFI?");
1560 OutStreamer->EmitWinCFIAllocStack(MI->getOperand(0).getImm());
1561 return;
1562
15631622 case X86::SEH_SetFrame:
1564 assert(MF->hasWinCFI() && "SEH_ instruction in function without WinCFI?");
1565 OutStreamer->EmitWinCFISetFrame(RI->getSEHRegNum(MI->getOperand(0).getImm()),
1566 MI->getOperand(1).getImm());
1567 return;
1568
15691623 case X86::SEH_PushFrame:
1570 assert(MF->hasWinCFI() && "SEH_ instruction in function without WinCFI?");
1571 OutStreamer->EmitWinCFIPushFrame(MI->getOperand(0).getImm());
1572 return;
1573
15741624 case X86::SEH_EndPrologue:
1575 assert(MF->hasWinCFI() && "SEH_ instruction in function without WinCFI?");
1576 OutStreamer->EmitWinCFIEndProlog();
1625 EmitSEHInstruction(MI);
15771626 return;
15781627
15791628 case X86::SEH_Epilogue: {
591591
592592 bool isOSWindows() const { return TargetTriple.isOSWindows(); }
593593
594 bool isTargetWin64() const {
595 return In64BitMode && TargetTriple.isOSWindows();
596 }
597
598 bool isTargetWin32() const {
599 return !In64BitMode && (isTargetCygMing() || isTargetKnownWindowsMSVC());
600 }
594 bool isTargetWin64() const { return In64BitMode && isOSWindows(); }
595
596 bool isTargetWin32() const { return !In64BitMode && isOSWindows(); }
601597
602598 bool isPICStyleGOT() const { return PICStyle == PICStyles::GOT; }
603599 bool isPICStyleRIPRel() const { return PICStyle == PICStyles::RIPRel; }
99 ; The module ctor has no debug info. All we have to do is don't crash.
1010 ; X86: _asan.module_ctor:
1111 ; X86-NEXT: L{{.*}}:
12 ; X86-NEXT: # BB
12 ; X86: # BB
1313 ; X86-NEXT: calll ___asan_init_v3
1414 ; X86-NEXT: retl
1515
0 ; RUN: llc < %s | grep cv_fpo_proc | FileCheck %s
1
2 ; C++ source:
3 ; extern "C" {
4 ; extern int g;
5 ;
6 ; void cdecl1(int a) { g += a; }
7 ; void cdecl2(int a, int b) { g += a + b; }
8 ; void cdecl3(int a, int b, int c) { g += a + b + c; }
9 ;
10 ; void __fastcall fastcall1(int a) { g += a; }
11 ; void __fastcall fastcall2(int a, int b) { g += a + b; }
12 ; void __fastcall fastcall3(int a, int b, int c) { g += a + b + c; }
13 ;
14 ; void __stdcall stdcall1(int a) { g += a; }
15 ; void __stdcall stdcall2(int a, int b) { g += a + b; }
16 ; void __stdcall stdcall3(int a, int b, int c) { g += a + b + c; }
17 ; }
18 ;
19 ; struct Foo {
20 ; void thiscall1(int a);
21 ; void thiscall2(int a, int b);
22 ; void thiscall3(int a, int b, int c);
23 ; };
24 ;
25 ; void Foo::thiscall1(int a) { g += a; }
26 ; void Foo::thiscall2(int a, int b) { g += a + b; }
27 ; void Foo::thiscall3(int a, int b, int c) { g += a + b + c; }
28
29 ; CHECK: .cv_fpo_proc _cdecl1 4
30 ; CHECK: .cv_fpo_proc _cdecl2 8
31 ; CHECK: .cv_fpo_proc _cdecl3 12
32
33 ; First two args are in registers and don't count.
34 ; CHECK: .cv_fpo_proc @fastcall1@4 0
35 ; CHECK: .cv_fpo_proc @fastcall2@8 0
36 ; CHECK: .cv_fpo_proc @fastcall3@12 4
37
38 ; CHECK: .cv_fpo_proc _stdcall1@4 4
39 ; CHECK: .cv_fpo_proc _stdcall2@8 8
40 ; CHECK: .cv_fpo_proc _stdcall3@12 12
41
42 ; 'this' is in ecx and doesn't count.
43 ; CHECK: .cv_fpo_proc "?thiscall1@Foo@@QAEXH@Z" 4
44 ; CHECK: .cv_fpo_proc "?thiscall2@Foo@@QAEXHH@Z" 8
45 ; CHECK: .cv_fpo_proc "?thiscall3@Foo@@QAEXHHH@Z" 12
46
47 ; ModuleID = 't.c'
48 source_filename = "t.c"
49 target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
50 target triple = "i386-pc-windows-msvc19.11.25508"
51
52 %struct.Foo = type { i8 }
53
54 @g = external global i32, align 4
55
56 ; Function Attrs: noinline nounwind optnone
57 define void @cdecl1(i32 %a) #0 !dbg !8 {
58 entry:
59 %a.addr = alloca i32, align 4
60 store i32 %a, i32* %a.addr, align 4
61 call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !12, metadata !DIExpression()), !dbg !13
62 %0 = load i32, i32* %a.addr, align 4, !dbg !14
63 %1 = load i32, i32* @g, align 4, !dbg !15
64 %add = add nsw i32 %1, %0, !dbg !15
65 store i32 %add, i32* @g, align 4, !dbg !15
66 ret void, !dbg !16
67 }
68
69 ; Function Attrs: nounwind readnone speculatable
70 declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
71
72 ; Function Attrs: noinline nounwind optnone
73 define void @cdecl2(i32 %a, i32 %b) #0 !dbg !17 {
74 entry:
75 %b.addr = alloca i32, align 4
76 %a.addr = alloca i32, align 4
77 store i32 %b, i32* %b.addr, align 4
78 call void @llvm.dbg.declare(metadata i32* %b.addr, metadata !20, metadata !DIExpression()), !dbg !21
79 store i32 %a, i32* %a.addr, align 4
80 call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !22, metadata !DIExpression()), !dbg !23
81 %0 = load i32, i32* %a.addr, align 4, !dbg !24
82 %1 = load i32, i32* %b.addr, align 4, !dbg !25
83 %add = add nsw i32 %0, %1, !dbg !26
84 %2 = load i32, i32* @g, align 4, !dbg !27
85 %add1 = add nsw i32 %2, %add, !dbg !27
86 store i32 %add1, i32* @g, align 4, !dbg !27
87 ret void, !dbg !28
88 }
89
90 ; Function Attrs: noinline nounwind optnone
91 define void @cdecl3(i32 %a, i32 %b, i32 %c) #0 !dbg !29 {
92 entry:
93 %c.addr = alloca i32, align 4
94 %b.addr = alloca i32, align 4
95 %a.addr = alloca i32, align 4
96 store i32 %c, i32* %c.addr, align 4
97 call void @llvm.dbg.declare(metadata i32* %c.addr, metadata !32, metadata !DIExpression()), !dbg !33
98 store i32 %b, i32* %b.addr, align 4
99 call void @llvm.dbg.declare(metadata i32* %b.addr, metadata !34, metadata !DIExpression()), !dbg !35
100 store i32 %a, i32* %a.addr, align 4
101 call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !36, metadata !DIExpression()), !dbg !37
102 %0 = load i32, i32* %a.addr, align 4, !dbg !38
103 %1 = load i32, i32* %b.addr, align 4, !dbg !39
104 %add = add nsw i32 %0, %1, !dbg !40
105 %2 = load i32, i32* %c.addr, align 4, !dbg !41
106 %add1 = add nsw i32 %add, %2, !dbg !42
107 %3 = load i32, i32* @g, align 4, !dbg !43
108 %add2 = add nsw i32 %3, %add1, !dbg !43
109 store i32 %add2, i32* @g, align 4, !dbg !43
110 ret void, !dbg !44
111 }
112
113 ; Function Attrs: noinline nounwind optnone
114 define x86_fastcallcc void @"\01@fastcall1@4"(i32 inreg %a) #0 !dbg !45 {
115 entry:
116 %a.addr = alloca i32, align 4
117 store i32 %a, i32* %a.addr, align 4
118 call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !47, metadata !DIExpression()), !dbg !48
119 %0 = load i32, i32* %a.addr, align 4, !dbg !49
120 %1 = load i32, i32* @g, align 4, !dbg !50
121 %add = add nsw i32 %1, %0, !dbg !50
122 store i32 %add, i32* @g, align 4, !dbg !50
123 ret void, !dbg !51
124 }
125
126 ; Function Attrs: noinline nounwind optnone
127 define x86_fastcallcc void @"\01@fastcall2@8"(i32 inreg %a, i32 inreg %b) #0 !dbg !52 {
128 entry:
129 %b.addr = alloca i32, align 4
130 %a.addr = alloca i32, align 4
131 store i32 %b, i32* %b.addr, align 4
132 call void @llvm.dbg.declare(metadata i32* %b.addr, metadata !54, metadata !DIExpression()), !dbg !55
133 store i32 %a, i32* %a.addr, align 4
134 call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !56, metadata !DIExpression()), !dbg !57
135 %0 = load i32, i32* %a.addr, align 4, !dbg !58
136 %1 = load i32, i32* %b.addr, align 4, !dbg !59
137 %add = add nsw i32 %0, %1, !dbg !60
138 %2 = load i32, i32* @g, align 4, !dbg !61
139 %add1 = add nsw i32 %2, %add, !dbg !61
140 store i32 %add1, i32* @g, align 4, !dbg !61
141 ret void, !dbg !62
142 }
143
144 ; Function Attrs: noinline nounwind optnone
145 define x86_fastcallcc void @"\01@fastcall3@12"(i32 inreg %a, i32 inreg %b, i32 %c) #0 !dbg !63 {
146 entry:
147 %c.addr = alloca i32, align 4
148 %b.addr = alloca i32, align 4
149 %a.addr = alloca i32, align 4
150 store i32 %c, i32* %c.addr, align 4
151 call void @llvm.dbg.declare(metadata i32* %c.addr, metadata !65, metadata !DIExpression()), !dbg !66
152 store i32 %b, i32* %b.addr, align 4
153 call void @llvm.dbg.declare(metadata i32* %b.addr, metadata !67, metadata !DIExpression()), !dbg !68
154 store i32 %a, i32* %a.addr, align 4
155 call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !69, metadata !DIExpression()), !dbg !70
156 %0 = load i32, i32* %a.addr, align 4, !dbg !71
157 %1 = load i32, i32* %b.addr, align 4, !dbg !72
158 %add = add nsw i32 %0, %1, !dbg !73
159 %2 = load i32, i32* %c.addr, align 4, !dbg !74
160 %add1 = add nsw i32 %add, %2, !dbg !75
161 %3 = load i32, i32* @g, align 4, !dbg !76
162 %add2 = add nsw i32 %3, %add1, !dbg !76
163 store i32 %add2, i32* @g, align 4, !dbg !76
164 ret void, !dbg !77
165 }
166
167 ; Function Attrs: noinline nounwind optnone
168 define x86_stdcallcc void @"\01_stdcall1@4"(i32 %a) #0 !dbg !78 {
169 entry:
170 %a.addr = alloca i32, align 4
171 store i32 %a, i32* %a.addr, align 4
172 call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !80, metadata !DIExpression()), !dbg !81
173 %0 = load i32, i32* %a.addr, align 4, !dbg !82
174 %1 = load i32, i32* @g, align 4, !dbg !83
175 %add = add nsw i32 %1, %0, !dbg !83
176 store i32 %add, i32* @g, align 4, !dbg !83
177 ret void, !dbg !84
178 }
179
180 ; Function Attrs: noinline nounwind optnone
181 define x86_stdcallcc void @"\01_stdcall2@8"(i32 %a, i32 %b) #0 !dbg !85 {
182 entry:
183 %b.addr = alloca i32, align 4
184 %a.addr = alloca i32, align 4
185 store i32 %b, i32* %b.addr, align 4
186 call void @llvm.dbg.declare(metadata i32* %b.addr, metadata !87, metadata !DIExpression()), !dbg !88
187 store i32 %a, i32* %a.addr, align 4
188 call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !89, metadata !DIExpression()), !dbg !90
189 %0 = load i32, i32* %a.addr, align 4, !dbg !91
190 %1 = load i32, i32* %b.addr, align 4, !dbg !92
191 %add = add nsw i32 %0, %1, !dbg !93
192 %2 = load i32, i32* @g, align 4, !dbg !94
193 %add1 = add nsw i32 %2, %add, !dbg !94
194 store i32 %add1, i32* @g, align 4, !dbg !94
195 ret void, !dbg !95
196 }
197
198 ; Function Attrs: noinline nounwind optnone
199 define x86_stdcallcc void @"\01_stdcall3@12"(i32 %a, i32 %b, i32 %c) #0 !dbg !96 {
200 entry:
201 %c.addr = alloca i32, align 4
202 %b.addr = alloca i32, align 4
203 %a.addr = alloca i32, align 4
204 store i32 %c, i32* %c.addr, align 4
205 call void @llvm.dbg.declare(metadata i32* %c.addr, metadata !98, metadata !DIExpression()), !dbg !99
206 store i32 %b, i32* %b.addr, align 4
207 call void @llvm.dbg.declare(metadata i32* %b.addr, metadata !100, metadata !DIExpression()), !dbg !101
208 store i32 %a, i32* %a.addr, align 4
209 call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !102, metadata !DIExpression()), !dbg !103
210 %0 = load i32, i32* %a.addr, align 4, !dbg !104
211 %1 = load i32, i32* %b.addr, align 4, !dbg !105
212 %add = add nsw i32 %0, %1, !dbg !106
213 %2 = load i32, i32* %c.addr, align 4, !dbg !107
214 %add1 = add nsw i32 %add, %2, !dbg !108
215 %3 = load i32, i32* @g, align 4, !dbg !109
216 %add2 = add nsw i32 %3, %add1, !dbg !109
217 store i32 %add2, i32* @g, align 4, !dbg !109
218 ret void, !dbg !110
219 }
220
221 ; Function Attrs: noinline nounwind optnone
222 define x86_thiscallcc void @"\01?thiscall1@Foo@@QAEXH@Z"(%struct.Foo* %this, i32 %a) #0 align 2 !dbg !111 {
223 entry:
224 %a.addr = alloca i32, align 4
225 %this.addr = alloca %struct.Foo*, align 4
226 store i32 %a, i32* %a.addr, align 4
227 call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !124, metadata !DIExpression()), !dbg !125
228 store %struct.Foo* %this, %struct.Foo** %this.addr, align 4
229 call void @llvm.dbg.declare(metadata %struct.Foo** %this.addr, metadata !126, metadata !DIExpression()), !dbg !128
230 %this1 = load %struct.Foo*, %struct.Foo** %this.addr, align 4
231 %0 = load i32, i32* %a.addr, align 4, !dbg !129
232 %1 = load i32, i32* @g, align 4, !dbg !130
233 %add = add nsw i32 %1, %0, !dbg !130
234 store i32 %add, i32* @g, align 4, !dbg !130
235 ret void, !dbg !131
236 }
237
238 ; Function Attrs: noinline nounwind optnone
239 define x86_thiscallcc void @"\01?thiscall2@Foo@@QAEXHH@Z"(%struct.Foo* %this, i32 %a, i32 %b) #0 align 2 !dbg !132 {
240 entry:
241 %b.addr = alloca i32, align 4
242 %a.addr = alloca i32, align 4
243 %this.addr = alloca %struct.Foo*, align 4
244 store i32 %b, i32* %b.addr, align 4
245 call void @llvm.dbg.declare(metadata i32* %b.addr, metadata !133, metadata !DIExpression()), !dbg !134
246 store i32 %a, i32* %a.addr, align 4
247 call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !135, metadata !DIExpression()), !dbg !136
248 store %struct.Foo* %this, %struct.Foo** %this.addr, align 4
249 call void @llvm.dbg.declare(metadata %struct.Foo** %this.addr, metadata !137, metadata !DIExpression()), !dbg !138
250 %this1 = load %struct.Foo*, %struct.Foo** %this.addr, align 4
251 %0 = load i32, i32* %a.addr, align 4, !dbg !139
252 %1 = load i32, i32* %b.addr, align 4, !dbg !140
253 %add = add nsw i32 %0, %1, !dbg !141
254 %2 = load i32, i32* @g, align 4, !dbg !142
255 %add2 = add nsw i32 %2, %add, !dbg !142
256 store i32 %add2, i32* @g, align 4, !dbg !142
257 ret void, !dbg !143
258 }
259
260 ; Function Attrs: noinline nounwind optnone
261 define x86_thiscallcc void @"\01?thiscall3@Foo@@QAEXHHH@Z"(%struct.Foo* %this, i32 %a, i32 %b, i32 %c) #0 align 2 !dbg !144 {
262 entry:
263 %c.addr = alloca i32, align 4
264 %b.addr = alloca i32, align 4
265 %a.addr = alloca i32, align 4
266 %this.addr = alloca %struct.Foo*, align 4
267 store i32 %c, i32* %c.addr, align 4
268 call void @llvm.dbg.declare(metadata i32* %c.addr, metadata !145, metadata !DIExpression()), !dbg !146
269 store i32 %b, i32* %b.addr, align 4
270 call void @llvm.dbg.declare(metadata i32* %b.addr, metadata !147, metadata !DIExpression()), !dbg !148
271 store i32 %a, i32* %a.addr, align 4
272 call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !149, metadata !DIExpression()), !dbg !150
273 store %struct.Foo* %this, %struct.Foo** %this.addr, align 4
274 call void @llvm.dbg.declare(metadata %struct.Foo** %this.addr, metadata !151, metadata !DIExpression()), !dbg !152
275 %this1 = load %struct.Foo*, %struct.Foo** %this.addr, align 4
276 %0 = load i32, i32* %a.addr, align 4, !dbg !153
277 %1 = load i32, i32* %b.addr, align 4, !dbg !154
278 %add = add nsw i32 %0, %1, !dbg !155
279 %2 = load i32, i32* %c.addr, align 4, !dbg !156
280 %add2 = add nsw i32 %add, %2, !dbg !157
281 %3 = load i32, i32* @g, align 4, !dbg !158
282 %add3 = add nsw i32 %3, %add2, !dbg !158
283 store i32 %add3, i32* @g, align 4, !dbg !158
284 ret void, !dbg !159
285 }
286
287 attributes #0 = { noinline nounwind optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
288 attributes #1 = { nounwind readnone speculatable }
289
290 !llvm.dbg.cu = !{!0}
291 !llvm.module.flags = !{!3, !4, !5, !6}
292 !llvm.ident = !{!7}
293
294 !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 6.0.0 ", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
295 !1 = !DIFile(filename: "t.c", directory: "C:\5Csrc\5Cllvm-project\5Cbuild", checksumkind: CSK_MD5, checksum: "0ce3e4edcf2f8511157da4edb99fcdf4")
296 !2 = !{}
297 !3 = !{i32 1, !"NumRegisterParameters", i32 0}
298 !4 = !{i32 2, !"CodeView", i32 1}
299 !5 = !{i32 2, !"Debug Info Version", i32 3}
300 !6 = !{i32 1, !"wchar_size", i32 2}
301 !7 = !{!"clang version 6.0.0 "}
302 !8 = distinct !DISubprogram(name: "cdecl1", scope: !1, file: !1, line: 4, type: !9, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
303 !9 = !DISubroutineType(types: !10)
304 !10 = !{null, !11}
305 !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
306 !12 = !DILocalVariable(name: "a", arg: 1, scope: !8, file: !1, line: 4, type: !11)
307 !13 = !DILocation(line: 4, column: 17, scope: !8)
308 !14 = !DILocation(line: 4, column: 27, scope: !8)
309 !15 = !DILocation(line: 4, column: 24, scope: !8)
310 !16 = !DILocation(line: 4, column: 30, scope: !8)
311 !17 = distinct !DISubprogram(name: "cdecl2", scope: !1, file: !1, line: 5, type: !18, isLocal: false, isDefinition: true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
312 !18 = !DISubroutineType(types: !19)
313 !19 = !{null, !11, !11}
314 !20 = !DILocalVariable(name: "b", arg: 2, scope: !17, file: !1, line: 5, type: !11)
315 !21 = !DILocation(line: 5, column: 24, scope: !17)
316 !22 = !DILocalVariable(name: "a", arg: 1, scope: !17, file: !1, line: 5, type: !11)
317 !23 = !DILocation(line: 5, column: 17, scope: !17)
318 !24 = !DILocation(line: 5, column: 34, scope: !17)
319 !25 = !DILocation(line: 5, column: 38, scope: !17)
320 !26 = !DILocation(line: 5, column: 36, scope: !17)
321 !27 = !DILocation(line: 5, column: 31, scope: !17)
322 !28 = !DILocation(line: 5, column: 41, scope: !17)
323 !29 = distinct !DISubprogram(name: "cdecl3", scope: !1, file: !1, line: 6, type: !30, isLocal: false, isDefinition: true, scopeLine: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
324 !30 = !DISubroutineType(types: !31)
325 !31 = !{null, !11, !11, !11}
326 !32 = !DILocalVariable(name: "c", arg: 3, scope: !29, file: !1, line: 6, type: !11)
327 !33 = !DILocation(line: 6, column: 31, scope: !29)
328 !34 = !DILocalVariable(name: "b", arg: 2, scope: !29, file: !1, line: 6, type: !11)
329 !35 = !DILocation(line: 6, column: 24, scope: !29)
330 !36 = !DILocalVariable(name: "a", arg: 1, scope: !29, file: !1, line: 6, type: !11)
331 !37 = !DILocation(line: 6, column: 17, scope: !29)
332 !38 = !DILocation(line: 6, column: 41, scope: !29)
333 !39 = !DILocation(line: 6, column: 45, scope: !29)
334 !40 = !DILocation(line: 6, column: 43, scope: !29)
335 !41 = !DILocation(line: 6, column: 49, scope: !29)
336 !42 = !DILocation(line: 6, column: 47, scope: !29)
337 !43 = !DILocation(line: 6, column: 38, scope: !29)
338 !44 = !DILocation(line: 6, column: 52, scope: !29)
339 !45 = distinct !DISubprogram(name: "fastcall1", linkageName: "\01@fastcall1@4", scope: !1, file: !1, line: 8, type: !46, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
340 !46 = !DISubroutineType(cc: DW_CC_BORLAND_msfastcall, types: !10)
341 !47 = !DILocalVariable(name: "a", arg: 1, scope: !45, file: !1, line: 8, type: !11)
342 !48 = !DILocation(line: 8, column: 31, scope: !45)
343 !49 = !DILocation(line: 8, column: 41, scope: !45)
344 !50 = !DILocation(line: 8, column: 38, scope: !45)
345 !51 = !DILocation(line: 8, column: 44, scope: !45)
346 !52 = distinct !DISubprogram(name: "fastcall2", linkageName: "\01@fastcall2@8", scope: !1, file: !1, line: 9, type: !53, isLocal: false, isDefinition: true, scopeLine: 9, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
347 !53 = !DISubroutineType(cc: DW_CC_BORLAND_msfastcall, types: !19)
348 !54 = !DILocalVariable(name: "b", arg: 2, scope: !52, file: !1, line: 9, type: !11)
349 !55 = !DILocation(line: 9, column: 38, scope: !52)
350 !56 = !DILocalVariable(name: "a", arg: 1, scope: !52, file: !1, line: 9, type: !11)
351 !57 = !DILocation(line: 9, column: 31, scope: !52)
352 !58 = !DILocation(line: 9, column: 48, scope: !52)
353 !59 = !DILocation(line: 9, column: 52, scope: !52)
354 !60 = !DILocation(line: 9, column: 50, scope: !52)
355 !61 = !DILocation(line: 9, column: 45, scope: !52)
356 !62 = !DILocation(line: 9, column: 55, scope: !52)
357 !63 = distinct !DISubprogram(name: "fastcall3", linkageName: "\01@fastcall3@12", scope: !1, file: !1, line: 10, type: !64, isLocal: false, isDefinition: true, scopeLine: 10, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
358 !64 = !DISubroutineType(cc: DW_CC_BORLAND_msfastcall, types: !31)
359 !65 = !DILocalVariable(name: "c", arg: 3, scope: !63, file: !1, line: 10, type: !11)
360 !66 = !DILocation(line: 10, column: 45, scope: !63)
361 !67 = !DILocalVariable(name: "b", arg: 2, scope: !63, file: !1, line: 10, type: !11)
362 !68 = !DILocation(line: 10, column: 38, scope: !63)
363 !69 = !DILocalVariable(name: "a", arg: 1, scope: !63, file: !1, line: 10, type: !11)
364 !70 = !DILocation(line: 10, column: 31, scope: !63)
365 !71 = !DILocation(line: 10, column: 55, scope: !63)
366 !72 = !DILocation(line: 10, column: 59, scope: !63)
367 !73 = !DILocation(line: 10, column: 57, scope: !63)
368 !74 = !DILocation(line: 10, column: 63, scope: !63)
369 !75 = !DILocation(line: 10, column: 61, scope: !63)
370 !76 = !DILocation(line: 10, column: 52, scope: !63)
371 !77 = !DILocation(line: 10, column: 66, scope: !63)
372 !78 = distinct !DISubprogram(name: "stdcall1", linkageName: "\01_stdcall1@4", scope: !1, file: !1, line: 12, type: !79, isLocal: false, isDefinition: true, scopeLine: 12, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
373 !79 = !DISubroutineType(cc: DW_CC_BORLAND_stdcall, types: !10)
374 !80 = !DILocalVariable(name: "a", arg: 1, scope: !78, file: !1, line: 12, type: !11)
375 !81 = !DILocation(line: 12, column: 29, scope: !78)
376 !82 = !DILocation(line: 12, column: 39, scope: !78)
377 !83 = !DILocation(line: 12, column: 36, scope: !78)
378 !84 = !DILocation(line: 12, column: 42, scope: !78)
379 !85 = distinct !DISubprogram(name: "stdcall2", linkageName: "\01_stdcall2@8", scope: !1, file: !1, line: 13, type: !86, isLocal: false, isDefinition: true, scopeLine: 13, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
380 !86 = !DISubroutineType(cc: DW_CC_BORLAND_stdcall, types: !19)
381 !87 = !DILocalVariable(name: "b", arg: 2, scope: !85, file: !1, line: 13, type: !11)
382 !88 = !DILocation(line: 13, column: 36, scope: !85)
383 !89 = !DILocalVariable(name: "a", arg: 1, scope: !85, file: !1, line: 13, type: !11)
384 !90 = !DILocation(line: 13, column: 29, scope: !85)
385 !91 = !DILocation(line: 13, column: 46, scope: !85)
386 !92 = !DILocation(line: 13, column: 50, scope: !85)
387 !93 = !DILocation(line: 13, column: 48, scope: !85)
388 !94 = !DILocation(line: 13, column: 43, scope: !85)
389 !95 = !DILocation(line: 13, column: 53, scope: !85)
390 !96 = distinct !DISubprogram(name: "stdcall3", linkageName: "\01_stdcall3@12", scope: !1, file: !1, line: 14, type: !97, isLocal: false, isDefinition: true, scopeLine: 14, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
391 !97 = !DISubroutineType(cc: DW_CC_BORLAND_stdcall, types: !31)
392 !98 = !DILocalVariable(name: "c", arg: 3, scope: !96, file: !1, line: 14, type: !11)
393 !99 = !DILocation(line: 14, column: 43, scope: !96)
394 !100 = !DILocalVariable(name: "b", arg: 2, scope: !96, file: !1, line: 14, type: !11)
395 !101 = !DILocation(line: 14, column: 36, scope: !96)
396 !102 = !DILocalVariable(name: "a", arg: 1, scope: !96, file: !1, line: 14, type: !11)
397 !103 = !DILocation(line: 14, column: 29, scope: !96)
398 !104 = !DILocation(line: 14, column: 53, scope: !96)
399 !105 = !DILocation(line: 14, column: 57, scope: !96)
400 !106 = !DILocation(line: 14, column: 55, scope: !96)
401 !107 = !DILocation(line: 14, column: 61, scope: !96)
402 !108 = !DILocation(line: 14, column: 59, scope: !96)
403 !109 = !DILocation(line: 14, column: 50, scope: !96)
404 !110 = !DILocation(line: 14, column: 64, scope: !96)
405 !111 = distinct !DISubprogram(name: "thiscall1", linkageName: "\01?thiscall1@Foo@@QAEXH@Z", scope: !112, file: !1, line: 23, type: !115, isLocal: false, isDefinition: true, scopeLine: 23, flags: DIFlagPrototyped, isOptimized: false, unit: !0, declaration: !114, variables: !2)
406 !112 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Foo", file: !1, line: 17, size: 8, elements: !113, identifier: ".?AUFoo@@")
407 !113 = !{!114, !118, !121}
408 !114 = !DISubprogram(name: "thiscall1", linkageName: "\01?thiscall1@Foo@@QAEXH@Z", scope: !112, file: !1, line: 18, type: !115, isLocal: false, isDefinition: false, scopeLine: 18, flags: DIFlagPrototyped, isOptimized: false)
409 !115 = !DISubroutineType(cc: DW_CC_BORLAND_thiscall, types: !116)
410 !116 = !{null, !117, !11}
411 !117 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !112, size: 32, flags: DIFlagArtificial | DIFlagObjectPointer)
412 !118 = !DISubprogram(name: "thiscall2", linkageName: "\01?thiscall2@Foo@@QAEXHH@Z", scope: !112, file: !1, line: 19, type: !119, isLocal: false, isDefinition: false, scopeLine: 19, flags: DIFlagPrototyped, isOptimized: false)
413 !119 = !DISubroutineType(cc: DW_CC_BORLAND_thiscall, types: !120)
414 !120 = !{null, !117, !11, !11}
415 !121 = !DISubprogram(name: "thiscall3", linkageName: "\01?thiscall3@Foo@@QAEXHHH@Z", scope: !112, file: !1, line: 20, type: !122, isLocal: false, isDefinition: false, scopeLine: 20, flags: DIFlagPrototyped, isOptimized: false)
416 !122 = !DISubroutineType(cc: DW_CC_BORLAND_thiscall, types: !123)
417 !123 = !{null, !117, !11, !11, !11}
418 !124 = !DILocalVariable(name: "a", arg: 2, scope: !111, file: !1, line: 23, type: !11)
419 !125 = !DILocation(line: 23, column: 25, scope: !111)
420 !126 = !DILocalVariable(name: "this", arg: 1, scope: !111, type: !127, flags: DIFlagArtificial | DIFlagObjectPointer)
421 !127 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !112, size: 32)
422 !128 = !DILocation(line: 0, scope: !111)
423 !129 = !DILocation(line: 23, column: 35, scope: !111)
424 !130 = !DILocation(line: 23, column: 32, scope: !111)
425 !131 = !DILocation(line: 23, column: 38, scope: !111)
426 !132 = distinct !DISubprogram(name: "thiscall2", linkageName: "\01?thiscall2@Foo@@QAEXHH@Z", scope: !112, file: !1, line: 24, type: !119, isLocal: false, isDefinition: true, scopeLine: 24, flags: DIFlagPrototyped, isOptimized: false, unit: !0, declaration: !118, variables: !2)
427 !133 = !DILocalVariable(name: "b", arg: 3, scope: !132, file: !1, line: 24, type: !11)
428 !134 = !DILocation(line: 24, column: 32, scope: !132)
429 !135 = !DILocalVariable(name: "a", arg: 2, scope: !132, file: !1, line: 24, type: !11)
430 !136 = !DILocation(line: 24, column: 25, scope: !132)
431 !137 = !DILocalVariable(name: "this", arg: 1, scope: !132, type: !127, flags: DIFlagArtificial | DIFlagObjectPointer)
432 !138 = !DILocation(line: 0, scope: !132)
433 !139 = !DILocation(line: 24, column: 42, scope: !132)
434 !140 = !DILocation(line: 24, column: 46, scope: !132)
435 !141 = !DILocation(line: 24, column: 44, scope: !132)
436 !142 = !DILocation(line: 24, column: 39, scope: !132)
437 !143 = !DILocation(line: 24, column: 49, scope: !132)
438 !144 = distinct !DISubprogram(name: "thiscall3", linkageName: "\01?thiscall3@Foo@@QAEXHHH@Z", scope: !112, file: !1, line: 25, type: !122, isLocal: false, isDefinition: true, scopeLine: 25, flags: DIFlagPrototyped, isOptimized: false, unit: !0, declaration: !121, variables: !2)
439 !145 = !DILocalVariable(name: "c", arg: 4, scope: !144, file: !1, line: 25, type: !11)
440 !146 = !DILocation(line: 25, column: 39, scope: !144)
441 !147 = !DILocalVariable(name: "b", arg: 3, scope: !144, file: !1, line: 25, type: !11)
442 !148 = !DILocation(line: 25, column: 32, scope: !144)
443 !149 = !DILocalVariable(name: "a", arg: 2, scope: !144, file: !1, line: 25, type: !11)
444 !150 = !DILocation(line: 25, column: 25, scope: !144)
445 !151 = !DILocalVariable(name: "this", arg: 1, scope: !144, type: !127, flags: DIFlagArtificial | DIFlagObjectPointer)
446 !152 = !DILocation(line: 0, scope: !144)
447 !153 = !DILocation(line: 25, column: 49, scope: !144)
448 !154 = !DILocation(line: 25, column: 53, scope: !144)
449 !155 = !DILocation(line: 25, column: 51, scope: !144)
450 !156 = !DILocation(line: 25, column: 57, scope: !144)
451 !157 = !DILocation(line: 25, column: 55, scope: !144)
452 !158 = !DILocation(line: 25, column: 46, scope: !144)
453 !159 = !DILocation(line: 25, column: 60, scope: !144)
0 ; RUN: llc < %s | FileCheck %s --check-prefix=ASM
1 ; RUN: llc -filetype=obj < %s | llvm-readobj -codeview | FileCheck %s --check-prefix=OBJ
2
3 ; C source:
4 ; int getval(void);
5 ; void usevals(int, ...);
6 ; int csr1() {
7 ; int a = getval();
8 ; usevals(a);
9 ; usevals(a);
10 ; return a;
11 ; }
12 ; int csr2() {
13 ; int a = getval();
14 ; int b = getval();
15 ; usevals(a, b);
16 ; usevals(a, b);
17 ; return a;
18 ; }
19 ; int csr3() {
20 ; int a = getval();
21 ; int b = getval();
22 ; int c = getval();
23 ; usevals(a, b, c);
24 ; usevals(a, b, c);
25 ; return a;
26 ; }
27 ; int csr4() {
28 ; int a = getval();
29 ; int b = getval();
30 ; int c = getval();
31 ; int d = getval();
32 ; usevals(a, b, c, d);
33 ; usevals(a, b, c, d);
34 ; return a;
35 ; }
36 ; int spill() {
37 ; int a = getval();
38 ; int b = getval();
39 ; int c = getval();
40 ; int d = getval();
41 ; int e = getval();
42 ; usevals(a, b, c, d, e);
43 ; usevals(a, b, c, d, e);
44 ; return a;
45 ; }
46
47 ; ModuleID = 't.c'
48 source_filename = "t.c"
49 target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
50 target triple = "i386-pc-windows-msvc19.11.25508"
51
52 ; Function Attrs: nounwind
53 define i32 @csr1() local_unnamed_addr #0 !dbg !8 {
54 entry:
55 %call = tail call i32 @getval() #3, !dbg !14
56 tail call void @llvm.dbg.value(metadata i32 %call, metadata !13, metadata !DIExpression()), !dbg !15
57 tail call void (i32, ...) @usevals(i32 %call) #3, !dbg !16
58 tail call void (i32, ...) @usevals(i32 %call) #3, !dbg !17
59 ret i32 %call, !dbg !18
60 }
61
62 ; ASM-LABEL: _csr1: # @csr1
63 ; ASM: .cv_fpo_proc _csr1
64 ; ASM: pushl %esi
65 ; ASM: .cv_fpo_pushreg %esi
66 ; ASM: .cv_fpo_endprologue
67 ; ASM: #DEBUG_VALUE: csr1:a <- %ESI
68 ; ASM: retl
69 ; ASM: .cv_fpo_endproc
70
71 ; OBJ-LABEL: SubSectionType: FrameData (0xF5)
72 ; OBJ-NEXT: SubSectionSize:
73 ; OBJ-NEXT: LinkageName: _csr1
74 ; OBJ-NEXT: FrameData {
75 ; OBJ-NEXT: RvaStart: 0x0
76 ; OBJ-NEXT: CodeSize: 0x1E
77 ; OBJ-NEXT: LocalSize: 0x0
78 ; OBJ-NEXT: ParamsSize: 0x0
79 ; OBJ-NEXT: MaxStackSize: 0x0
80 ; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
81 ; OBJ-NEXT: PrologSize: 0x1
82 ; OBJ-NEXT: SavedRegsSize: 0x0
83 ; OBJ-NEXT: Flags [ (0x4)
84 ; OBJ-NEXT: IsFunctionStart (0x4)
85 ; OBJ-NEXT: ]
86 ; OBJ-NEXT: }
87 ; OBJ-NEXT: FrameData {
88 ; OBJ-NEXT: RvaStart: 0x1
89 ; OBJ-NEXT: CodeSize: 0x1D
90 ; OBJ-NEXT: LocalSize: 0x0
91 ; OBJ-NEXT: ParamsSize: 0x0
92 ; OBJ-NEXT: MaxStackSize: 0x0
93 ; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $esi $T0 4 - ^ =
94 ; OBJ-NEXT: PrologSize: 0x0
95 ; OBJ-NEXT: SavedRegsSize: 0x4
96 ; OBJ-NEXT: Flags [ (0x0)
97 ; OBJ-NEXT: ]
98 ; OBJ-NEXT: }
99 ; OBJ-NOT: FrameData
100
101 declare i32 @getval() local_unnamed_addr #1
102
103 declare void @usevals(i32, ...) local_unnamed_addr #1
104
105 ; Function Attrs: nounwind
106 define i32 @csr2() local_unnamed_addr #0 !dbg !19 {
107 entry:
108 %call = tail call i32 @getval() #3, !dbg !23
109 tail call void @llvm.dbg.value(metadata i32 %call, metadata !21, metadata !DIExpression()), !dbg !24
110 %call1 = tail call i32 @getval() #3, !dbg !25
111 tail call void @llvm.dbg.value(metadata i32 %call1, metadata !22, metadata !DIExpression()), !dbg !26
112 tail call void (i32, ...) @usevals(i32 %call, i32 %call1) #3, !dbg !27
113 tail call void (i32, ...) @usevals(i32 %call, i32 %call1) #3, !dbg !28
114 ret i32 %call, !dbg !29
115 }
116
117 ; ASM-LABEL: _csr2: # @csr2
118 ; ASM: .cv_fpo_proc _csr2
119 ; ASM: pushl %edi
120 ; ASM: .cv_fpo_pushreg %edi
121 ; ASM: pushl %esi
122 ; ASM: .cv_fpo_pushreg %esi
123 ; ASM: .cv_fpo_endprologue
124 ; ASM: #DEBUG_VALUE: csr2:a <- %ESI
125 ; ASM: #DEBUG_VALUE: csr2:b <- %EDI
126 ; ASM: retl
127 ; ASM: .cv_fpo_endproc
128
129 ; OBJ-LABEL: SubSectionType: FrameData (0xF5)
130 ; OBJ-NEXT: SubSectionSize:
131 ; OBJ-NEXT: LinkageName: _csr2
132 ; OBJ-NEXT: FrameData {
133 ; OBJ-NEXT: RvaStart: 0x0
134 ; OBJ-NEXT: CodeSize: 0x29
135 ; OBJ-NEXT: LocalSize: 0x0
136 ; OBJ-NEXT: ParamsSize: 0x0
137 ; OBJ-NEXT: MaxStackSize: 0x0
138 ; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
139 ; OBJ-NEXT: PrologSize: 0x2
140 ; OBJ-NEXT: SavedRegsSize: 0x0
141 ; OBJ-NEXT: Flags [ (0x4)
142 ; OBJ-NEXT: IsFunctionStart (0x4)
143 ; OBJ-NEXT: ]
144 ; OBJ-NEXT: }
145 ; OBJ-NEXT: FrameData {
146 ; OBJ-NEXT: RvaStart: 0x1
147 ; OBJ-NEXT: CodeSize: 0x28
148 ; OBJ-NEXT: LocalSize: 0x0
149 ; OBJ-NEXT: ParamsSize: 0x0
150 ; OBJ-NEXT: MaxStackSize: 0x0
151 ; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $edi $T0 4 - ^ =
152 ; OBJ-NEXT: PrologSize: 0x1
153 ; OBJ-NEXT: SavedRegsSize: 0x4
154 ; OBJ-NEXT: Flags [ (0x0)
155 ; OBJ-NEXT: ]
156 ; OBJ-NEXT: }
157 ; OBJ-NEXT: FrameData {
158 ; OBJ-NEXT: RvaStart: 0x2
159 ; OBJ-NEXT: CodeSize: 0x27
160 ; OBJ-NEXT: LocalSize: 0x0
161 ; OBJ-NEXT: ParamsSize: 0x0
162 ; OBJ-NEXT: MaxStackSize: 0x0
163 ; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $edi $T0 4 - ^ = $esi $T0 8 - ^ =
164 ; OBJ-NEXT: PrologSize: 0x0
165 ; OBJ-NEXT: SavedRegsSize: 0x8
166 ; OBJ-NEXT: Flags [ (0x0)
167 ; OBJ-NEXT: ]
168 ; OBJ-NEXT: }
169 ; OBJ-NOT: FrameData
170
171 ; Function Attrs: nounwind
172 define i32 @csr3() local_unnamed_addr #0 !dbg !30 {
173 entry:
174 %call = tail call i32 @getval() #3, !dbg !35
175 tail call void @llvm.dbg.value(metadata i32 %call, metadata !32, metadata !DIExpression()), !dbg !36
176 %call1 = tail call i32 @getval() #3, !dbg !37
177 tail call void @llvm.dbg.value(metadata i32 %call1, metadata !33, metadata !DIExpression()), !dbg !38
178 %call2 = tail call i32 @getval() #3, !dbg !39
179 tail call void @llvm.dbg.value(metadata i32 %call2, metadata !34, metadata !DIExpression()), !dbg !40
180 tail call void (i32, ...) @usevals(i32 %call, i32 %call1, i32 %call2) #3, !dbg !41
181 tail call void (i32, ...) @usevals(i32 %call, i32 %call1, i32 %call2) #3, !dbg !42
182 ret i32 %call, !dbg !43
183 }
184
185 ; ASM-LABEL: _csr3: # @csr3
186 ; ASM: .cv_fpo_proc _csr3
187 ; ASM: pushl %ebx
188 ; ASM: .cv_fpo_pushreg %ebx
189 ; ASM: pushl %edi
190 ; ASM: .cv_fpo_pushreg %edi
191 ; ASM: pushl %esi
192 ; ASM: .cv_fpo_pushreg %esi
193 ; ASM: .cv_fpo_endprologue
194 ; ASM: #DEBUG_VALUE: csr3:a <- %ESI
195 ; ASM: #DEBUG_VALUE: csr3:b <- %EDI
196 ; ASM: #DEBUG_VALUE: csr3:c <- %EBX
197 ; ASM: retl
198 ; ASM: .cv_fpo_endproc
199
200 ; OBJ-LABEL: SubSectionType: FrameData (0xF5)
201 ; OBJ-NEXT: SubSectionSize:
202 ; OBJ-NEXT: LinkageName: _csr3
203 ; OBJ-NEXT: FrameData {
204 ; OBJ-NEXT: RvaStart: 0x0
205 ; OBJ-NEXT: CodeSize: 0x34
206 ; OBJ-NEXT: LocalSize: 0x0
207 ; OBJ-NEXT: ParamsSize: 0x0
208 ; OBJ-NEXT: MaxStackSize: 0x0
209 ; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
210 ; OBJ-NEXT: PrologSize: 0x3
211 ; OBJ-NEXT: SavedRegsSize: 0x0
212 ; OBJ-NEXT: Flags [ (0x4)
213 ; OBJ-NEXT: IsFunctionStart (0x4)
214 ; OBJ-NEXT: ]
215 ; OBJ-NEXT: }
216 ; OBJ-NEXT: FrameData {
217 ; OBJ-NEXT: RvaStart: 0x1
218 ; OBJ-NEXT: CodeSize: 0x33
219 ; OBJ-NEXT: LocalSize: 0x0
220 ; OBJ-NEXT: ParamsSize: 0x0
221 ; OBJ-NEXT: MaxStackSize: 0x0
222 ; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebx $T0 4 - ^ =
223 ; OBJ-NEXT: PrologSize: 0x2
224 ; OBJ-NEXT: SavedRegsSize: 0x4
225 ; OBJ-NEXT: Flags [ (0x0)
226 ; OBJ-NEXT: ]
227 ; OBJ-NEXT: }
228 ; OBJ-NEXT: FrameData {
229 ; OBJ-NEXT: RvaStart: 0x2
230 ; OBJ-NEXT: CodeSize: 0x32
231 ; OBJ-NEXT: LocalSize: 0x0
232 ; OBJ-NEXT: ParamsSize: 0x0
233 ; OBJ-NEXT: MaxStackSize: 0x0
234 ; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebx $T0 4 - ^ = $edi $T0 8 - ^ =
235 ; OBJ-NEXT: PrologSize: 0x1
236 ; OBJ-NEXT: SavedRegsSize: 0x8
237 ; OBJ-NEXT: Flags [ (0x0)
238 ; OBJ-NEXT: ]
239 ; OBJ-NEXT: }
240 ; OBJ-NEXT: FrameData {
241 ; OBJ-NEXT: RvaStart: 0x3
242 ; OBJ-NEXT: CodeSize: 0x31
243 ; OBJ-NEXT: LocalSize: 0x0
244 ; OBJ-NEXT: ParamsSize: 0x0
245 ; OBJ-NEXT: MaxStackSize: 0x0
246 ; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebx $T0 4 - ^ = $edi $T0 8 - ^ = $esi $T0 12 - ^ =
247 ; OBJ-NEXT: PrologSize: 0x0
248 ; OBJ-NEXT: SavedRegsSize: 0xC
249 ; OBJ-NEXT: Flags [ (0x0)
250 ; OBJ-NEXT: ]
251 ; OBJ-NEXT: }
252 ; OBJ-NOT: FrameData
253
254 ; Function Attrs: nounwind
255 define i32 @csr4() local_unnamed_addr #0 !dbg !44 {
256 entry:
257 %call = tail call i32 @getval() #3, !dbg !50
258 tail call void @llvm.dbg.value(metadata i32 %call, metadata !46, metadata !DIExpression()), !dbg !51
259 %call1 = tail call i32 @getval() #3, !dbg !52
260 tail call void @llvm.dbg.value(metadata i32 %call1, metadata !47, metadata !DIExpression()), !dbg !53
261 %call2 = tail call i32 @getval() #3, !dbg !54
262 tail call void @llvm.dbg.value(metadata i32 %call2, metadata !48, metadata !DIExpression()), !dbg !55
263 %call3 = tail call i32 @getval() #3, !dbg !56
264 tail call void @llvm.dbg.value(metadata i32 %call3, metadata !49, metadata !DIExpression()), !dbg !57
265 tail call void (i32, ...) @usevals(i32 %call, i32 %call1, i32 %call2, i32 %call3) #3, !dbg !58
266 tail call void (i32, ...) @usevals(i32 %call, i32 %call1, i32 %call2, i32 %call3) #3, !dbg !59
267 ret i32 %call, !dbg !60
268 }
269
270 ; ASM-LABEL: _csr4: # @csr4
271 ; ASM: .cv_fpo_proc _csr4
272 ; ASM: pushl %ebp
273 ; ASM: .cv_fpo_pushreg %ebp
274 ; ASM: pushl %ebx
275 ; ASM: .cv_fpo_pushreg %ebx
276 ; ASM: pushl %edi
277 ; ASM: .cv_fpo_pushreg %edi
278 ; ASM: pushl %esi
279 ; ASM: .cv_fpo_pushreg %esi
280 ; ASM: .cv_fpo_endprologue
281 ; ASM: #DEBUG_VALUE: csr4:a <- %ESI
282 ; ASM: #DEBUG_VALUE: csr4:b <- %EDI
283 ; ASM: #DEBUG_VALUE: csr4:c <- %EBX
284 ; ASM: #DEBUG_VALUE: csr4:d <- %EBP
285 ; ASM: retl
286 ; ASM: .cv_fpo_endproc
287
288 ; OBJ-LABEL: SubSectionType: FrameData (0xF5)
289 ; OBJ-NEXT: SubSectionSize:
290 ; OBJ-NEXT: LinkageName: _csr4
291 ; OBJ-NEXT: FrameData {
292 ; OBJ-NEXT: RvaStart: 0x0
293 ; OBJ-NEXT: CodeSize: 0x3F
294 ; OBJ-NEXT: LocalSize: 0x0
295 ; OBJ-NEXT: ParamsSize: 0x0
296 ; OBJ-NEXT: MaxStackSize: 0x0
297 ; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
298 ; OBJ-NEXT: PrologSize: 0x4
299 ; OBJ-NEXT: SavedRegsSize: 0x0
300 ; OBJ-NEXT: Flags [ (0x4)
301 ; OBJ-NEXT: IsFunctionStart (0x4)
302 ; OBJ-NEXT: ]
303 ; OBJ-NEXT: }
304 ; OBJ-NEXT: FrameData {
305 ; OBJ-NEXT: RvaStart: 0x1
306 ; OBJ-NEXT: CodeSize: 0x3E
307 ; OBJ-NEXT: LocalSize: 0x0
308 ; OBJ-NEXT: ParamsSize: 0x0
309 ; OBJ-NEXT: MaxStackSize: 0x0
310 ; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ =
311 ; OBJ-NEXT: PrologSize: 0x3
312 ; OBJ-NEXT: SavedRegsSize: 0x4
313 ; OBJ-NEXT: Flags [ (0x0)
314 ; OBJ-NEXT: ]
315 ; OBJ-NEXT: }
316 ; OBJ-NEXT: FrameData {
317 ; OBJ-NEXT: RvaStart: 0x2
318 ; OBJ-NEXT: CodeSize: 0x3D
319 ; OBJ-NEXT: LocalSize: 0x0
320 ; OBJ-NEXT: ParamsSize: 0x0
321 ; OBJ-NEXT: MaxStackSize: 0x0
322 ; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ =
323 ; OBJ-NEXT: PrologSize: 0x2
324 ; OBJ-NEXT: SavedRegsSize: 0x8
325 ; OBJ-NEXT: Flags [ (0x0)
326 ; OBJ-NEXT: ]
327 ; OBJ-NEXT: }
328 ; OBJ-NEXT: FrameData {
329 ; OBJ-NEXT: RvaStart: 0x3
330 ; OBJ-NEXT: CodeSize: 0x3C
331 ; OBJ-NEXT: LocalSize: 0x0
332 ; OBJ-NEXT: ParamsSize: 0x0
333 ; OBJ-NEXT: MaxStackSize: 0x0
334 ; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ = $edi $T0 12 - ^ =
335 ; OBJ-NEXT: PrologSize: 0x1
336 ; OBJ-NEXT: SavedRegsSize: 0xC
337 ; OBJ-NEXT: Flags [ (0x0)
338 ; OBJ-NEXT: ]
339 ; OBJ-NEXT: }
340 ; OBJ-NEXT: FrameData {
341 ; OBJ-NEXT: RvaStart: 0x4
342 ; OBJ-NEXT: CodeSize: 0x3B
343 ; OBJ-NEXT: LocalSize: 0x0
344 ; OBJ-NEXT: ParamsSize: 0x0
345 ; OBJ-NEXT: MaxStackSize: 0x0
346 ; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ = $edi $T0 12 - ^ = $esi $T0 16 - ^ =
347 ; OBJ-NEXT: PrologSize: 0x0
348 ; OBJ-NEXT: SavedRegsSize: 0x10
349 ; OBJ-NEXT: Flags [ (0x0)
350 ; OBJ-NEXT: ]
351 ; OBJ-NEXT: }
352 ; OBJ-NOT: FrameData
353
354 ; Function Attrs: nounwind
355 define i32 @spill() local_unnamed_addr #0 !dbg !61 {
356 entry:
357 %call = tail call i32 @getval() #3, !dbg !68
358 tail call void @llvm.dbg.value(metadata i32 %call, metadata !63, metadata !DIExpression()), !dbg !69
359 %call1 = tail call i32 @getval() #3, !dbg !70
360 tail call void @llvm.dbg.value(metadata i32 %call1, metadata !64, metadata !DIExpression()), !dbg !71
361 %call2 = tail call i32 @getval() #3, !dbg !72
362 tail call void @llvm.dbg.value(metadata i32 %call2, metadata !65, metadata !DIExpression()), !dbg !73
363 %call3 = tail call i32 @getval() #3, !dbg !74
364 tail call void @llvm.dbg.value(metadata i32 %call3, metadata !66, metadata !DIExpression()), !dbg !75
365 %call4 = tail call i32 @getval() #3, !dbg !76
366 tail call void @llvm.dbg.value(metadata i32 %call4, metadata !67, metadata !DIExpression()), !dbg !77
367 tail call void (i32, ...) @usevals(i32 %call, i32 %call1, i32 %call2, i32 %call3, i32 %call4) #3, !dbg !78
368 tail call void (i32, ...) @usevals(i32 %call, i32 %call1, i32 %call2, i32 %call3, i32 %call4) #3, !dbg !79
369 ret i32 %call, !dbg !80
370 }
371
372 ; ASM-LABEL: _spill: # @spill
373 ; ASM: .cv_fpo_proc _spill
374 ; ASM: pushl %ebp
375 ; ASM: .cv_fpo_pushreg %ebp
376 ; ASM: pushl %ebx
377 ; ASM: .cv_fpo_pushreg %ebx
378 ; ASM: pushl %edi
379 ; ASM: .cv_fpo_pushreg %edi
380 ; ASM: pushl %esi
381 ; ASM: .cv_fpo_pushreg %esi
382 ; ASM: subl $8, %esp
383 ; ASM: .cv_fpo_stackalloc 8
384 ; ASM: .cv_fpo_endprologue
385 ; ASM: retl
386 ; ASM: .cv_fpo_endproc
387
388 ; OBJ-LABEL: SubSectionType: FrameData (0xF5)
389 ; OBJ-NEXT: SubSectionSize:
390 ; OBJ-NEXT: LinkageName: _spill
391 ; OBJ-NEXT: FrameData {
392 ; OBJ-NEXT: RvaStart: 0x0
393 ; OBJ-NEXT: CodeSize: 0x5A
394 ; OBJ-NEXT: LocalSize: 0x0
395 ; OBJ-NEXT: ParamsSize: 0x0
396 ; OBJ-NEXT: MaxStackSize: 0x0
397 ; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
398 ; OBJ-NEXT: PrologSize: 0x7
399 ; OBJ-NEXT: SavedRegsSize: 0x0
400 ; OBJ-NEXT: Flags [ (0x4)
401 ; OBJ-NEXT: IsFunctionStart (0x4)
402 ; OBJ-NEXT: ]
403 ; OBJ-NEXT: }
404 ; OBJ-NEXT: FrameData {
405 ; OBJ-NEXT: RvaStart: 0x1
406 ; OBJ-NEXT: CodeSize: 0x59
407 ; OBJ-NEXT: LocalSize: 0x0
408 ; OBJ-NEXT: ParamsSize: 0x0
409 ; OBJ-NEXT: MaxStackSize: 0x0
410 ; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ =
411 ; OBJ-NEXT: PrologSize: 0x6
412 ; OBJ-NEXT: SavedRegsSize: 0x4
413 ; OBJ-NEXT: Flags [ (0x0)
414 ; OBJ-NEXT: ]
415 ; OBJ-NEXT: }
416 ; OBJ-NEXT: FrameData {
417 ; OBJ-NEXT: RvaStart: 0x2
418 ; OBJ-NEXT: CodeSize: 0x58
419 ; OBJ-NEXT: LocalSize: 0x0
420 ; OBJ-NEXT: ParamsSize: 0x0
421 ; OBJ-NEXT: MaxStackSize: 0x0
422 ; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ =
423 ; OBJ-NEXT: PrologSize: 0x5
424 ; OBJ-NEXT: SavedRegsSize: 0x8
425 ; OBJ-NEXT: Flags [ (0x0)
426 ; OBJ-NEXT: ]
427 ; OBJ-NEXT: }
428 ; OBJ-NEXT: FrameData {
429 ; OBJ-NEXT: RvaStart: 0x3
430 ; OBJ-NEXT: CodeSize: 0x57
431 ; OBJ-NEXT: LocalSize: 0x0
432 ; OBJ-NEXT: ParamsSize: 0x0
433 ; OBJ-NEXT: MaxStackSize: 0x0
434 ; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ = $edi $T0 12 - ^ =
435 ; OBJ-NEXT: PrologSize: 0x4
436 ; OBJ-NEXT: SavedRegsSize: 0xC
437 ; OBJ-NEXT: Flags [ (0x0)
438 ; OBJ-NEXT: ]
439 ; OBJ-NEXT: }
440 ; OBJ-NEXT: FrameData {
441 ; OBJ-NEXT: RvaStart: 0x4
442 ; OBJ-NEXT: CodeSize: 0x56
443 ; OBJ-NEXT: LocalSize: 0x0
444 ; OBJ-NEXT: ParamsSize: 0x0
445 ; OBJ-NEXT: MaxStackSize: 0x0
446 ; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ = $edi $T0 12 - ^ = $esi $T0 16 - ^ =
447 ; OBJ-NEXT: PrologSize: 0x3
448 ; OBJ-NEXT: SavedRegsSize: 0x10
449 ; OBJ-NEXT: Flags [ (0x0)
450 ; OBJ-NEXT: ]
451 ; OBJ-NEXT: }
452 ; OBJ-NEXT: FrameData {
453 ; OBJ-NEXT: RvaStart: 0x7
454 ; OBJ-NEXT: CodeSize: 0x53
455 ; OBJ-NEXT: LocalSize: 0x8
456 ; OBJ-NEXT: ParamsSize: 0x0
457 ; OBJ-NEXT: MaxStackSize: 0x0
458 ; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ = $edi $T0 12 - ^ = $esi $T0 16 - ^ =
459 ; OBJ-NEXT: PrologSize: 0x0
460 ; OBJ-NEXT: SavedRegsSize: 0x10
461 ; OBJ-NEXT: Flags [ (0x0)
462 ; OBJ-NEXT: ]
463 ; OBJ-NEXT: }
464 ; OBJ-NOT: FrameData
465
466 ; Function Attrs: nounwind readnone speculatable
467 declare void @llvm.dbg.value(metadata, metadata, metadata) #2
468
469 attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
470 attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
471 attributes #2 = { nounwind readnone speculatable }
472 attributes #3 = { nounwind }
473
474 !llvm.dbg.cu = !{!0}
475 !llvm.module.flags = !{!3, !4, !5, !6}
476 !llvm.ident = !{!7}
477
478 !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
479 !1 = !DIFile(filename: "t.c", directory: "C:\5Csrc\5Cllvm-project\5Cbuild", checksumkind: CSK_MD5, checksum: "0b1c85f8a0bfb41380df1fcaeadde306")
480 !2 = !{}
481 !3 = !{i32 1, !"NumRegisterParameters", i32 0}
482 !4 = !{i32 2, !"CodeView", i32 1}
483 !5 = !{i32 2, !"Debug Info Version", i32 3}
484 !6 = !{i32 1, !"wchar_size", i32 2}
485 !7 = !{!"clang version 6.0.0 "}
486 !8 = distinct !DISubprogram(name: "csr1", scope: !1, file: !1, line: 3, type: !9, isLocal: false, isDefinition: true, scopeLine: 3, isOptimized: true, unit: !0, variables: !12)
487 !9 = !DISubroutineType(types: !10)
488 !10 = !{!11}
489 !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
490 !12 = !{!13}
491 !13 = !DILocalVariable(name: "a", scope: !8, file: !1, line: 4, type: !11)
492 !14 = !DILocation(line: 4, column: 11, scope: !8)
493 !15 = !DILocation(line: 4, column: 7, scope: !8)
494 !16 = !DILocation(line: 5, column: 3, scope: !8)
495 !17 = !DILocation(line: 6, column: 3, scope: !8)
496 !18 = !DILocation(line: 7, column: 3, scope: !8)
497 !19 = distinct !DISubprogram(name: "csr2", scope: !1, file: !1, line: 9, type: !9, isLocal: false, isDefinition: true, scopeLine: 9, isOptimized: true, unit: !0, variables: !20)
498 !20 = !{!21, !22}
499 !21 = !DILocalVariable(name: "a", scope: !19, file: !1, line: 10, type: !11)
500 !22 = !DILocalVariable(name: "b", scope: !19, file: !1, line: 11, type: !11)
501 !23 = !DILocation(line: 10, column: 11, scope: !19)
502 !24 = !DILocation(line: 10, column: 7, scope: !19)
503 !25 = !DILocation(line: 11, column: 11, scope: !19)
504 !26 = !DILocation(line: 11, column: 7, scope: !19)
505 !27 = !DILocation(line: 12, column: 3, scope: !19)
506 !28 = !DILocation(line: 13, column: 3, scope: !19)
507 !29 = !DILocation(line: 14, column: 3, scope: !19)
508 !30 = distinct !DISubprogram(name: "csr3", scope: !1, file: !1, line: 16, type: !9, isLocal: false, isDefinition: true, scopeLine: 16, isOptimized: true, unit: !0, variables: !31)
509 !31 = !{!32, !33, !34}
510 !32 = !DILocalVariable(name: "a", scope: !30, file: !1, line: 17, type: !11)
511 !33 = !DILocalVariable(name: "b", scope: !30, file: !1, line: 18, type: !11)
512 !34 = !DILocalVariable(name: "c", scope: !30, file: !1, line: 19, type: !11)
513 !35 = !DILocation(line: 17, column: 11, scope: !30)
514 !36 = !DILocation(line: 17, column: 7, scope: !30)
515 !37 = !DILocation(line: 18, column: 11, scope: !30)
516 !38 = !DILocation(line: 18, column: 7, scope: !30)
517 !39 = !DILocation(line: 19, column: 11, scope: !30)
518 !40 = !DILocation(line: 19, column: 7, scope: !30)
519 !41 = !DILocation(line: 20, column: 3, scope: !30)
520 !42 = !DILocation(line: 21, column: 3, scope: !30)
521 !43 = !DILocation(line: 22, column: 3, scope: !30)
522 !44 = distinct !DISubprogram(name: "csr4", scope: !1, file: !1, line: 24, type: !9, isLocal: false, isDefinition: true, scopeLine: 24, isOptimized: true, unit: !0, variables: !45)
523 !45 = !{!46, !47, !48, !49}
524 !46 = !DILocalVariable(name: "a", scope: !44, file: !1, line: 25, type: !11)
525 !47 = !DILocalVariable(name: "b", scope: !44, file: !1, line: 26, type: !11)
526 !48 = !DILocalVariable(name: "c", scope: !44, file: !1, line: 27, type: !11)
527 !49 = !DILocalVariable(name: "d", scope: !44, file: !1, line: 28, type: !11)
528 !50 = !DILocation(line: 25, column: 11, scope: !44)
529 !51 = !DILocation(line: 25, column: 7, scope: !44)
530 !52 = !DILocation(line: 26, column: 11, scope: !44)
531 !53 = !DILocation(line: 26, column: 7, scope: !44)
532 !54 = !DILocation(line: 27, column: 11, scope: !44)
533 !55 = !DILocation(line: 27, column: 7, scope: !44)
534 !56 = !DILocation(line: 28, column: 11, scope: !44)
535 !57 = !DILocation(line: 28, column: 7, scope: !44)
536 !58 = !DILocation(line: 29, column: 3, scope: !44)
537 !59 = !DILocation(line: 30, column: 3, scope: !44)
538 !60 = !DILocation(line: 31, column: 3, scope: !44)
539 !61 = distinct !DISubprogram(name: "spill", scope: !1, file: !1, line: 33, type: !9, isLocal: false, isDefinition: true, scopeLine: 33, isOptimized: true, unit: !0, variables: !62)
540 !62 = !{!63, !64, !65, !66, !67}
541 !63 = !DILocalVariable(name: "a", scope: !61, file: !1, line: 34, type: !11)
542 !64 = !DILocalVariable(name: "b", scope: !61, file: !1, line: 35, type: !11)
543 !65 = !DILocalVariable(name: "c", scope: !61, file: !1, line: 36, type: !11)
544 !66 = !DILocalVariable(name: "d", scope: !61, file: !1, line: 37, type: !11)
545 !67 = !DILocalVariable(name: "e", scope: !61, file: !1, line: 38, type: !11)
546 !68 = !DILocation(line: 34, column: 11, scope: !61)
547 !69 = !DILocation(line: 34, column: 7, scope: !61)
548 !70 = !DILocation(line: 35, column: 11, scope: !61)
549 !71 = !DILocation(line: 35, column: 7, scope: !61)
550 !72 = !DILocation(line: 36, column: 11, scope: !61)
551 !73 = !DILocation(line: 36, column: 7, scope: !61)
552 !74 = !DILocation(line: 37, column: 11, scope: !61)
553 !75 = !DILocation(line: 37, column: 7, scope: !61)
554 !76 = !DILocation(line: 38, column: 11, scope: !61)
555 !77 = !DILocation(line: 38, column: 7, scope: !61)
556 !78 = !DILocation(line: 39, column: 3, scope: !61)
557 !79 = !DILocation(line: 40, column: 3, scope: !61)
558 !80 = !DILocation(line: 41, column: 3, scope: !61)
0 ; RUN: llc < %s | FileCheck %s
1
2 ; C source:
3 ; void usethings(double *, void *p);
4 ; int realign_and_alloca(int n) {
5 ; double d = 0;
6 ; void *p = __builtin_alloca(n);
7 ; usethings(&d, p);
8 ; return 0;
9 ; }
10
11 ; CHECK: _realign_and_alloca: # @realign_and_alloca
12 ; CHECK: .cv_fpo_proc _realign_and_alloca 4
13 ; CHECK: pushl %ebp
14 ; CHECK: .cv_fpo_pushreg %ebp
15 ; CHECK: movl %esp, %ebp
16 ; CHECK: .cv_fpo_setframe %ebp
17 ; CHECK: pushl %esi
18 ; CHECK: .cv_fpo_pushreg %esi
19 ; We don't seem to need to describe this AND because at this point CSRs
20 ; are stored relative to EBP, but it's suspicious.
21 ; CHECK: andl $-16, %esp
22 ; CHECK: subl $32, %esp
23 ; CHECK: .cv_fpo_stackalloc 32
24 ; CHECK: .cv_fpo_endprologue
25 ; CHECK: movl %esp, %esi
26 ; CHECK: leal 8(%esi),
27 ; CHECK: calll _usethings
28 ; CHECK: addl $8, %esp
29 ; CHECK: xorl %eax, %eax
30 ; CHECK: leal -4(%ebp), %esp
31 ; CHECK: popl %esi
32 ; CHECK: popl %ebp
33 ; CHECK: retl
34 ; CHECK: .cv_fpo_endproc
35
36
37 ; ModuleID = 't.c'
38 source_filename = "t.c"
39 target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
40 target triple = "i386-pc-windows-msvc19.11.25508"
41
42 ; Function Attrs: nounwind
43 define i32 @realign_and_alloca(i32 %n) local_unnamed_addr #0 !dbg !8 {
44 entry:
45 %d = alloca double, align 8
46 tail call void @llvm.dbg.value(metadata i32 %n, metadata !13, metadata !DIExpression()), !dbg !18
47 %0 = bitcast double* %d to i8*, !dbg !19
48 call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %0) #4, !dbg !19
49 tail call void @llvm.dbg.value(metadata double 0.000000e+00, metadata !14, metadata !DIExpression()), !dbg !20
50 store double 0.000000e+00, double* %d, align 8, !dbg !20, !tbaa !21
51 %1 = alloca i8, i32 %n, align 16, !dbg !25
52 tail call void @llvm.dbg.value(metadata i8* %1, metadata !16, metadata !DIExpression()), !dbg !26
53 tail call void @llvm.dbg.value(metadata double* %d, metadata !14, metadata !DIExpression()), !dbg !20
54 call void @usethings(double* nonnull %d, i8* nonnull %1) #4, !dbg !27
55 call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %0) #4, !dbg !28
56 ret i32 0, !dbg !29
57 }
58
59 ; Function Attrs: argmemonly nounwind
60 declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #1
61
62 declare void @usethings(double*, i8*) local_unnamed_addr #2
63
64 ; Function Attrs: argmemonly nounwind
65 declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #1
66
67 ; Function Attrs: nounwind readnone speculatable
68 declare void @llvm.dbg.value(metadata, metadata, metadata) #3
69
70 attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
71 attributes #1 = { argmemonly nounwind }
72 attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
73 attributes #3 = { nounwind readnone speculatable }
74 attributes #4 = { nounwind }
75
76 !llvm.dbg.cu = !{!0}
77 !llvm.module.flags = !{!3, !4, !5, !6}
78 !llvm.ident = !{!7}
79
80 !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
81 !1 = !DIFile(filename: "t.c", directory: "C:\5Csrc\5Cllvm-project\5Cbuild", checksumkind: CSK_MD5, checksum: "cfdc2deff5dc50f95e287f877660d4dd")
82 !2 = !{}
83 !3 = !{i32 1, !"NumRegisterParameters", i32 0}
84 !4 = !{i32 2, !"CodeView", i32 1}
85 !5 = !{i32 2, !"Debug Info Version", i32 3}
86 !6 = !{i32 1, !"wchar_size", i32 2}
87 !7 = !{!"clang version 6.0.0 "}
88 !8 = distinct !DISubprogram(name: "realign_and_alloca", scope: !1, file: !1, line: 2, type: !9, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !12)
89 !9 = !DISubroutineType(types: !10)
90 !10 = !{!11, !11}
91 !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
92 !12 = !{!13, !14, !16}
93 !13 = !DILocalVariable(name: "n", arg: 1, scope: !8, file: !1, line: 2, type: !11)
94 !14 = !DILocalVariable(name: "d", scope: !8, file: !1, line: 3, type: !15)
95 !15 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float)
96 !16 = !DILocalVariable(name: "p", scope: !8, file: !1, line: 4, type: !17)
97 !17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 32)
98 !18 = !DILocation(line: 2, column: 28, scope: !8)
99 !19 = !DILocation(line: 3, column: 3, scope: !8)
100 !20 = !DILocation(line: 3, column: 10, scope: !8)
101 !21 = !{!22, !22, i64 0}
102 !22 = !{!"double", !23, i64 0}
103 !23 = !{!"omnipotent char", !24, i64 0}
104 !24 = !{!"Simple C/C++ TBAA"}
105 !25 = !DILocation(line: 4, column: 13, scope: !8)
106 !26 = !DILocation(line: 4, column: 9, scope: !8)
107 !27 = !DILocation(line: 5, column: 3, scope: !8)
108 !28 = !DILocation(line: 7, column: 1, scope: !8)
109 !29 = !DILocation(line: 6, column: 3, scope: !8)
0 ; RUN: llc -enable-shrink-wrap=true < %s | FileCheck %s --check-prefix=ASM
1 ; RUN: llc -enable-shrink-wrap=true -filetype=obj < %s | llvm-readobj -codeview | FileCheck %s --check-prefix=OBJ
2
3 ; C source:
4 ; int doSomething(int*);
5 ; int __fastcall shrink_wrap_basic(int a, int b, int c, int d) {
6 ; if (a < b)
7 ; return a;
8 ; for (int i = c; i < d; ++i)
9 ; doSomething(&c);
10 ; return doSomething(&c);
11 ; }
12
13 ; ASM: @shrink_wrap_basic@16: # @"\01@shrink_wrap_basic@16"
14 ; ASM: .cv_fpo_proc @shrink_wrap_basic@16 8
15 ; ASM: .cv_loc 0 1 3 9 # t.c:3:9
16 ; ASM: movl %ecx, %eax
17 ; ASM: cmpl %edx, %eax
18 ; ASM: jl [[EPILOGUE:LBB0_[0-9]+]]
19
20 ; ASM: pushl %ebx
21 ; ASM: .cv_fpo_pushreg %ebx
22 ; ASM: pushl %edi
23 ; ASM: .cv_fpo_pushreg %edi
24 ; ASM: pushl %esi
25 ; ASM: .cv_fpo_pushreg %esi
26 ; ASM: .cv_fpo_endprologue
27
28 ; ASM: calll _doSomething
29
30 ; ASM: popl %esi
31 ; ASM: popl %edi
32 ; ASM: popl %ebx
33 ; ASM: [[EPILOGUE]]: # %return
34 ; ASM: retl $8
35 ; ASM: Ltmp11:
36 ; ASM: .cv_fpo_endproc
37
38 ; Note how RvaStart advances 7 bytes to skip the shrink-wrapped portion.
39 ; OBJ: SubSectionType: FrameData (0xF5)
40 ; OBJ: FrameData {
41 ; OBJ: RvaStart: 0x0
42 ; OBJ: CodeSize: 0x34
43 ; OBJ: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
44 ; OBJ: PrologSize: 0x9
45 ; OBJ: }
46 ; OBJ: FrameData {
47 ; OBJ: RvaStart: 0x7
48 ; OBJ: CodeSize: 0x2D
49 ; OBJ: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebx $T0 4 - ^ =
50 ; OBJ: PrologSize: 0x2
51 ; OBJ: }
52 ; OBJ: FrameData {
53 ; OBJ: RvaStart: 0x8
54 ; OBJ: CodeSize: 0x2C
55 ; OBJ: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebx $T0 4 - ^ = $edi $T0 8 - ^ =
56 ; OBJ: PrologSize: 0x1
57 ; OBJ: }
58 ; OBJ: FrameData {
59 ; OBJ: RvaStart: 0x9
60 ; OBJ: CodeSize: 0x2B
61 ; OBJ: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebx $T0 4 - ^ = $edi $T0 8 - ^ = $esi $T0 12 - ^ =
62 ; OBJ: PrologSize: 0x0
63 ; OBJ: }
64 ; OBJ-NOT: FrameData
65
66 ; ModuleID = 't.c'
67 source_filename = "t.c"
68 target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
69 target triple = "i386-pc-windows-msvc19.11.25508"
70
71 ; Function Attrs: nounwind
72 define x86_fastcallcc i32 @"\01@shrink_wrap_basic@16"(i32 inreg %a, i32 inreg %b, i32 %c, i32 %d) local_unnamed_addr #0 !dbg !8 {
73 entry:
74 %c.addr = alloca i32, align 4
75 tail call void @llvm.dbg.value(metadata i32 %d, metadata !13, metadata !DIExpression()), !dbg !19
76 tail call void @llvm.dbg.value(metadata i32 %c, metadata !14, metadata !DIExpression()), !dbg !20
77 store i32 %c, i32* %c.addr, align 4, !tbaa !21
78 tail call void @llvm.dbg.value(metadata i32 %b, metadata !15, metadata !DIExpression()), !dbg !25
79 tail call void @llvm.dbg.value(metadata i32 %a, metadata !16, metadata !DIExpression()), !dbg !26
80 %cmp = icmp slt i32 %a, %b, !dbg !27
81 br i1 %cmp, label %return, label %for.cond.preheader, !dbg !29
82
83 for.cond.preheader: ; preds = %entry
84 br label %for.cond, !dbg !30
85
86 for.cond: ; preds = %for.cond.preheader, %for.cond
87 %i.0 = phi i32 [ %inc, %for.cond ], [ %c, %for.cond.preheader ]
88 call void @llvm.dbg.value(metadata i32 %i.0, metadata !17, metadata !DIExpression()), !dbg !32
89 %cmp1 = icmp slt i32 %i.0, %d, !dbg !30
90 call void @llvm.dbg.value(metadata i32* %c.addr, metadata !14, metadata !DIExpression()), !dbg !20
91 %call = call i32 @doSomething(i32* nonnull %c.addr) #3, !dbg !33
92 %inc = add nsw i32 %i.0, 1, !dbg !34
93 call void @llvm.dbg.value(metadata i32 %inc, metadata !17, metadata !DIExpression()), !dbg !32
94 br i1 %cmp1, label %for.cond, label %return, !dbg !35, !llvm.loop !36
95
96 return: ; preds = %for.cond, %entry
97 %retval.0 = phi i32 [ %a, %entry ], [ %call, %for.cond ]
98 ret i32 %retval.0, !dbg !38
99 }
100
101 declare i32 @doSomething(i32*) local_unnamed_addr #1
102
103 ; Function Attrs: nounwind readnone speculatable
104 declare void @llvm.dbg.value(metadata, metadata, metadata) #2
105
106 attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
107 attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
108 attributes #2 = { nounwind readnone speculatable }
109 attributes #3 = { nounwind }
110
111 !llvm.dbg.cu = !{!0}
112 !llvm.module.flags = !{!3, !4, !5, !6}
113 !llvm.ident = !{!7}
114
115 !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
116 !1 = !DIFile(filename: "t.c", directory: "C:\5Csrc\5Cllvm-project\5Cbuild", checksumkind: CSK_MD5, checksum: "32f118fd5dd7e65ff7733c49b2f804ef")
117 !2 = !{}
118 !3 = !{i32 1, !"NumRegisterParameters", i32 0}
119 !4 = !{i32 2, !"CodeView", i32 1}
120 !5 = !{i32 2, !"Debug Info Version", i32 3}
121 !6 = !{i32 1, !"wchar_size", i32 2}
122 !7 = !{!"clang version 6.0.0 "}
123 !8 = distinct !DISubprogram(name: "shrink_wrap_basic", linkageName: "\01@shrink_wrap_basic@16", scope: !1, file: !1, line: 2, type: !9, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !12)
124 !9 = !DISubroutineType(cc: DW_CC_BORLAND_msfastcall, types: !10)
125 !10 = !{!11, !11, !11, !11, !11}
126 !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
127 !12 = !{!13, !14, !15, !16, !17}
128 !13 = !DILocalVariable(name: "d", arg: 4, scope: !8, file: !1, line: 2, type: !11)
129 !14 = !DILocalVariable(name: "c", arg: 3, scope: !8, file: !1, line: 2, type: !11)
130 !15 = !DILocalVariable(name: "b", arg: 2, scope: !8, file: !1, line: 2, type: !11)
131 !16 = !DILocalVariable(name: "a", arg: 1, scope: !8, file: !1, line: 2, type: !11)
132 !17 = !DILocalVariable(name: "i", scope: !18, file: !1, line: 5, type: !11)
133 !18 = distinct !DILexicalBlock(scope: !8, file: !1, line: 5, column: 3)
134 !19 = !DILocation(line: 2, column: 59, scope: !8)
135 !20 = !DILocation(line: 2, column: 52, scope: !8)
136 !21 = !{!22, !22, i64 0}
137 !22 = !{!"int", !23, i64 0}
138 !23 = !{!"omnipotent char", !24, i64 0}
139 !24 = !{!"Simple C/C++ TBAA"}
140 !25 = !DILocation(line: 2, column: 45, scope: !8)
141 !26 = !DILocation(line: 2, column: 38, scope: !8)
142 !27 = !DILocation(line: 3, column: 9, scope: !28)
143 !28 = distinct !DILexicalBlock(scope: !8, file: !1, line: 3, column: 7)
144 !29 = !DILocation(line: 3, column: 7, scope: !8)
145 !30 = !DILocation(line: 5, column: 21, scope: !31)
146 !31 = distinct !DILexicalBlock(scope: !18, file: !1, line: 5, column: 3)
147 !32 = !DILocation(line: 5, column: 12, scope: !18)
148 !33 = !DILocation(line: 0, scope: !8)
149 !34 = !DILocation(line: 5, column: 26, scope: !31)
150 !35 = !DILocation(line: 5, column: 3, scope: !18)
151 !36 = distinct !{!36, !35, !37}
152 !37 = !DILocation(line: 6, column: 19, scope: !18)
153 !38 = !DILocation(line: 8, column: 1, scope: !8)
0 ; RUN: llc < %s | FileCheck %s
1
2 ; C source:
3 ; void escape(int *);
4 ; int ssp(int a) {
5 ; int arr[4] = {a, a, a, a};
6 ; escape(&arr[0]);
7 ; return a;
8 ; }
9
10 ; CHECK: _ssp: # @ssp
11 ; CHECK: .cv_fpo_proc _ssp 4
12 ; CHECK: pushl %esi
13 ; CHECK: .cv_fpo_pushreg %esi
14 ; CHECK: subl $20, %esp
15 ; CHECK: .cv_fpo_stackalloc 20
16 ; CHECK: .cv_fpo_endprologue
17 ; CHECK: ___security_cookie
18
19 ; CHECK: movl 28(%esp), %esi
20 ; CHECK: movl %esi, {{[0-9]*}}(%esp)
21 ; CHECK: movl %esi, {{[0-9]*}}(%esp)
22 ; CHECK: movl %esi, {{[0-9]*}}(%esp)
23 ; CHECK: movl %esi, {{[0-9]*}}(%esp)
24
25 ; CHECK: calll _escape
26 ; CHECK: calll @__security_check_cookie@4
27
28 ; CHECK: movl %esi, %eax
29 ; CHECK: addl $20, %esp
30 ; CHECK: popl %esi
31 ; CHECK: retl
32 ; CHECK: Ltmp2:
33 ; CHECK: .cv_fpo_endproc
34
35 ; ModuleID = 't.c'
36 source_filename = "t.c"
37 target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
38 target triple = "i386-pc-windows-msvc19.11.25508"
39
40 ; Function Attrs: nounwind sspstrong
41 define i32 @ssp(i32 returned %a) local_unnamed_addr #0 !dbg !8 {
42 entry:
43 %arr = alloca [4 x i32], align 4
44 tail call void @llvm.dbg.value(metadata i32 %a, metadata !13, metadata !DIExpression()), !dbg !18
45 %0 = bitcast [4 x i32]* %arr to i8*, !dbg !19
46 call void @llvm.lifetime.start.p0i8(i64 16, i8* nonnull %0) #4, !dbg !19
47 tail call void @llvm.dbg.declare(metadata [4 x i32]* %arr, metadata !14, metadata !DIExpression()), !dbg !20
48 %arrayinit.begin = getelementptr inbounds [4 x i32], [4 x i32]* %arr, i32 0, i32 0, !dbg !21
49 store i32 %a, i32* %arrayinit.begin, align 4, !dbg !21, !tbaa !22
50 %arrayinit.element = getelementptr inbounds [4 x i32], [4 x i32]* %arr, i32 0, i32 1, !dbg !21
51 store i32 %a, i32* %arrayinit.element, align 4, !dbg !21, !tbaa !22
52 %arrayinit.element1 = getelementptr inbounds [4 x i32], [4 x i32]* %arr, i32 0, i32 2, !dbg !21
53 store i32 %a, i32* %arrayinit.element1, align 4, !dbg !21, !tbaa !22
54 %arrayinit.element2 = getelementptr inbounds [4 x i32], [4 x i32]* %arr, i32 0, i32 3, !dbg !21
55 store i32 %a, i32* %arrayinit.element2, align 4, !dbg !21, !tbaa !22
56 call void @escape(i32* nonnull %arrayinit.begin) #4, !dbg !26
57 call void @llvm.lifetime.end.p0i8(i64 16, i8* nonnull %0) #4, !dbg !27
58 ret i32 %a, !dbg !28
59 }
60
61 ; Function Attrs: nounwind readnone speculatable
62 declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
63
64 ; Function Attrs: argmemonly nounwind
65 declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #2
66
67 declare void @escape(i32*) local_unnamed_addr #3
68
69 ; Function Attrs: argmemonly nounwind
70 declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #2
71
72 ; Function Attrs: nounwind readnone speculatable
73 declare void @llvm.dbg.value(metadata, metadata, metadata) #1
74
75 attributes #0 = { nounwind sspstrong "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
76 attributes #1 = { nounwind readnone speculatable }
77 attributes #2 = { argmemonly nounwind }
78 attributes #3 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
79 attributes #4 = { nounwind }
80
81 !llvm.dbg.cu = !{!0}
82 !llvm.module.flags = !{!3, !4, !5, !6}
83 !llvm.ident = !{!7}
84
85 !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
86 !1 = !DIFile(filename: "t.c", directory: "C:\5Csrc\5Cllvm-project\5Cbuild", checksumkind: CSK_MD5, checksum: "df0c1a43acd19a1255d45a3f2802cf9f")
87 !2 = !{}
88 !3 = !{i32 1, !"NumRegisterParameters", i32 0}
89 !4 = !{i32 2, !"CodeView", i32 1}
90 !5 = !{i32 2, !"Debug Info Version", i32 3}
91 !6 = !{i32 1, !"wchar_size", i32 2}
92 !7 = !{!"clang version 6.0.0 "}
93 !8 = distinct !DISubprogram(name: "ssp", scope: !1, file: !1, line: 2, type: !9, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !12)
94 !9 = !DISubroutineType(types: !10)
95 !10 = !{!11, !11}
96 !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
97 !12 = !{!13, !14}
98 !13 = !DILocalVariable(name: "a", arg: 1, scope: !8, file: !1, line: 2, type: !11)
99 !14 = !DILocalVariable(name: "arr", scope: !8, file: !1, line: 3, type: !15)
100 !15 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 128, elements: !16)
101 !16 = !{!17}
102 !17 = !DISubrange(count: 4)
103 !18 = !DILocation(line: 2, column: 13, scope: !8)
104 !19 = !DILocation(line: 3, column: 3, scope: !8)
105 !20 = !DILocation(line: 3, column: 7, scope: !8)
106 !21 = !DILocation(line: 3, column: 16, scope: !8)
107 !22 = !{!23, !23, i64 0}
108 !23 = !{!"int", !24, i64 0}
109 !24 = !{!"omnipotent char", !25, i64 0}
110 !25 = !{!"Simple C/C++ TBAA"}
111 !26 = !DILocation(line: 4, column: 3, scope: !8)
112 !27 = !DILocation(line: 6, column: 1, scope: !8)
113 !28 = !DILocation(line: 5, column: 3, scope: !8)
6060 ; X86-NEXT: .short [[C1_END:.*]]-[[C1_START:.*]] #
6161 ; X86: [[COMPILE_END]]:
6262 ; X86-NEXT: .p2align 2
63 ; X86-NEXT: .cv_fpo_data _x
6364 ; Symbol subsection for x
6465 ; X86-NEXT: .long 241
6566 ; X86-NEXT: .long [[F1_END:.*]]-[[F1_START:.*]] #
8687 ; Line table subsection for x
8788 ; X86: .cv_linetable 0, _x, [[END_OF_X]]
8889 ; Symbol subsection for y
90 ; X86-NEXT: .cv_fpo_data _y
8991 ; X86-NEXT: .long 241
9092 ; X86-NEXT: .long [[COMPILE_END:.*]]-[[COMPILE_START:.*]] #
9193 ; X86-NEXT: [[COMPILE_START]]:
111113 ; Line table subsection for y
112114 ; X86: .cv_linetable 1, _y, [[END_OF_Y]]
113115 ; Symbol subsection for f
116 ; X86-NEXT: .cv_fpo_data _f
114117 ; X86-NEXT: .long 241
115118 ; X86-NEXT: .long [[COMPILE_END:.*]]-[[COMPILE_START:.*]] #
116119 ; X86-NEXT: [[COMPILE_START]]:
144147 ; OBJ32: ]
145148 ; OBJ32: Subsection [
146149 ; OBJ32-NEXT: SubSectionType: Symbols (0xF1)
150 ; OBJ32: Compile3Sym
151 ; OBJ32: ]
152 ; OBJ32: Subsection [
153 ; OBJ32-NEXT: SubSectionType: FrameData (0xF5)
154 ; OBJ32: ]
155 ; OBJ32: Subsection [
156 ; OBJ32-NEXT: SubSectionType: Symbols (0xF1)
147157 ; OBJ32: {{.*}}Proc{{.*}}Sym {
148158 ; OBJ32: Kind: S_LPROC32_ID (0x1146)
149159 ; OBJ32: CodeSize: 0x6
155165 ; OBJ32-NEXT: ]
156166 ; OBJ32: Subsection [
157167 ; OBJ32-NEXT: SubSectionType: Lines (0xF2)
168 ; OBJ32: ]
169 ; OBJ32: Subsection [
170 ; OBJ32-NEXT: SubSectionType: FrameData (0xF5)
158171 ; OBJ32: ]
159172 ; OBJ32: Subsection [
160173 ; OBJ32-NEXT: SubSectionType: Symbols (0xF1)
169182 ; OBJ32-NEXT: ]
170183 ; OBJ32: Subsection [
171184 ; OBJ32-NEXT: SubSectionType: Lines (0xF2)
185 ; OBJ32: ]
186 ; OBJ32: Subsection [
187 ; OBJ32-NEXT: SubSectionType: FrameData (0xF5)
172188 ; OBJ32: ]
173189 ; OBJ32: Subsection [
174190 ; OBJ32-NEXT: SubSectionType: Symbols (0xF1)
3535 ; X86: [[C1_END]]:
3636 ; X86-NEXT: [[COMPILE_END]]:
3737 ; X86-NEXT: .p2align 2
38 ; X86-NEXT: .cv_fpo_data _f
3839 ; X86-NEXT: .long 241 # Symbol subsection for f
3940 ; X86-NEXT: .long [[F1_END:.*]]-[[F1_START:.*]] # Subsection size
4041 ; X86-NEXT: [[F1_START]]:
6970 ; OBJ32: Characteristics [ (0x42300040)
7071 ; OBJ32: ]
7172 ; OBJ32: Relocations [
72 ; OBJ32-NEXT: 0x64 IMAGE_REL_I386_SECREL _f
73 ; OBJ32-NEXT: 0x68 IMAGE_REL_I386_SECTION _f
74 ; OBJ32-NEXT: 0x7C IMAGE_REL_I386_SECREL _f
75 ; OBJ32-NEXT: 0x80 IMAGE_REL_I386_SECTION _f
73 ; OBJ32-NEXT: 0x44 IMAGE_REL_I386_DIR32NB _f
74 ; OBJ32-NEXT: 0x90 IMAGE_REL_I386_SECREL _f
75 ; OBJ32-NEXT: 0x94 IMAGE_REL_I386_SECTION _f
76 ; OBJ32-NEXT: 0xA8 IMAGE_REL_I386_SECREL _f
77 ; OBJ32-NEXT: 0xAC IMAGE_REL_I386_SECTION _f
7678 ; OBJ32-NEXT: ]
79 ; OBJ32: Subsection [
80 ; OBJ32-NEXT: SubSectionType: Symbols (0xF1)
81 ; OBJ32: Compile3Sym
82 ; OBJ32: ]
83 ; OBJ32: Subsection [
84 ; OBJ32-NEXT: SubSectionType: FrameData (0xF5)
85 ; OBJ32: ]
7786 ; OBJ32: Subsection [
7887 ; OBJ32-NEXT: SubSectionType: Symbols (0xF1)
7988 ; OBJ32: {{.*}}Proc{{.*}}Sym {
0 # RUN: llvm-mc -filetype=asm < %s -triple i686-windows-msvc | FileCheck %s --check-prefix=ASM
1 # RUN: llvm-mc -filetype=obj < %s -triple i686-windows-msvc | llvm-readobj -codeview | FileCheck %s --check-prefix=OBJ
2
3 .globl _foo
4 _foo:
5 .cv_fpo_proc _foo 4
6 pushl %ebp
7 .cv_fpo_pushreg ebp # Test without %
8 pushl %ebx
9 .cv_fpo_pushreg %ebx
10 pushl %edi
11 .cv_fpo_pushreg %edi
12 pushl %esi
13 .cv_fpo_pushreg esi
14 subl $20, %esp
15 .cv_fpo_stackalloc 20
16 .cv_fpo_endprologue
17
18 # ASM: .cv_fpo_proc _foo 4
19 # ASM: pushl %ebp
20 # ASM: .cv_fpo_pushreg %ebp
21 # ASM: pushl %ebx
22 # ASM: .cv_fpo_pushreg %ebx
23 # ASM: pushl %edi
24 # ASM: .cv_fpo_pushreg %edi
25 # ASM: pushl %esi
26 # ASM: .cv_fpo_pushreg %esi
27 # ASM: subl $20, %esp
28 # ASM: .cv_fpo_stackalloc 20
29 # ASM: .cv_fpo_endprologue
30
31 # Clobbers
32 xorl %ebp, %ebp
33 xorl %ebx, %ebx
34 xorl %edi, %edi
35 xorl %esi, %esi
36 # Use that stack memory
37 leal 4(%esp), %eax
38 movl %eax, (%esp)
39 calll _bar
40
41 # ASM: calll _bar
42
43 # Epilogue
44 # FIXME: Get FPO data for this once we get it for DWARF.
45 addl $20, %esp
46 popl %esi
47 popl %edi
48 popl %ebx
49 popl %ebp
50 retl
51 .cv_fpo_endproc
52
53 # ASM: .cv_fpo_endproc
54
55 .section .debug$S,"dr"
56 .p2align 2
57 .long 4 # Debug section magic
58 .cv_fpo_data _foo
59 .cv_stringtable
60
61 # ASM: .cv_fpo_data
62
63 # OBJ: Subsection [
64 # OBJ-NEXT: SubSectionType: FrameData (0xF5)
65 # OBJ-NEXT: SubSectionSize: 0xC4
66 # OBJ-NEXT: LinkageName: _foo
67 # OBJ-NEXT: FrameData {
68 # OBJ-NEXT: RvaStart: 0x0
69 # OBJ-NEXT: CodeSize: 0x23
70 # OBJ-NEXT: LocalSize: 0x0
71 # OBJ-NEXT: ParamsSize: 0x4
72 # OBJ-NEXT: MaxStackSize: 0x0
73 # OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
74 # OBJ-NEXT: PrologSize: 0x7
75 # OBJ-NEXT: SavedRegsSize: 0x0
76 # OBJ-NEXT: Flags [ (0x4)
77 # OBJ-NEXT: IsFunctionStart (0x4)
78 # OBJ-NEXT: ]
79 # OBJ-NEXT: }
80 # OBJ-NEXT: FrameData {
81 # OBJ-NEXT: RvaStart: 0x1
82 # OBJ-NEXT: CodeSize: 0x22
83 # OBJ-NEXT: LocalSize: 0x0
84 # OBJ-NEXT: ParamsSize: 0x4
85 # OBJ-NEXT: MaxStackSize: 0x0
86 # OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ =
87 # OBJ-NEXT: PrologSize: 0x6
88 # OBJ-NEXT: SavedRegsSize: 0x4
89 # OBJ-NEXT: Flags [ (0x0)
90 # OBJ-NEXT: ]
91 # OBJ-NEXT: }
92 # OBJ-NEXT: FrameData {
93 # OBJ-NEXT: RvaStart: 0x2
94 # OBJ-NEXT: CodeSize: 0x21
95 # OBJ-NEXT: LocalSize: 0x0
96 # OBJ-NEXT: ParamsSize: 0x4
97 # OBJ-NEXT: MaxStackSize: 0x0
98 # OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ =
99 # OBJ-NEXT: PrologSize: 0x5
100 # OBJ-NEXT: SavedRegsSize: 0x8
101 # OBJ-NEXT: Flags [ (0x0)
102 # OBJ-NEXT: ]
103 # OBJ-NEXT: }
104 # OBJ-NEXT: FrameData {
105 # OBJ-NEXT: RvaStart: 0x3
106 # OBJ-NEXT: CodeSize: 0x20
107 # OBJ-NEXT: LocalSize: 0x0
108 # OBJ-NEXT: ParamsSize: 0x4
109 # OBJ-NEXT: MaxStackSize: 0x0
110 # OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ = $edi $T0 12 - ^ =
111 # OBJ-NEXT: PrologSize: 0x4
112 # OBJ-NEXT: SavedRegsSize: 0xC
113 # OBJ-NEXT: Flags [ (0x0)
114 # OBJ-NEXT: ]
115 # OBJ-NEXT: }
116 # OBJ-NEXT: FrameData {
117 # OBJ-NEXT: RvaStart: 0x4
118 # OBJ-NEXT: CodeSize: 0x1F
119 # OBJ-NEXT: LocalSize: 0x0
120 # OBJ-NEXT: ParamsSize: 0x4
121 # OBJ-NEXT: MaxStackSize: 0x0
122 # OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ = $edi $T0 12 - ^ = $esi $T0 16 - ^ =
123 # OBJ-NEXT: PrologSize: 0x3
124 # OBJ-NEXT: SavedRegsSize: 0x10
125 # OBJ-NEXT: Flags [ (0x0)
126 # OBJ-NEXT: ]
127 # OBJ-NEXT: }
128 # OBJ-NEXT: FrameData {
129 # OBJ-NEXT: RvaStart: 0x7
130 # OBJ-NEXT: CodeSize: 0x1C
131 # OBJ-NEXT: LocalSize: 0x14
132 # OBJ-NEXT: ParamsSize: 0x4
133 # OBJ-NEXT: MaxStackSize: 0x0
134 # OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ = $edi $T0 12 - ^ = $esi $T0 16 - ^ =
135 # OBJ-NEXT: PrologSize: 0x0
136 # OBJ-NEXT: SavedRegsSize: 0x10
137 # OBJ-NEXT: Flags [ (0x0)
138 # OBJ-NEXT: ]
139 # OBJ-NEXT: }
140 # OBJ-NOT: FrameData
0 # RUN: not llvm-mc < %s -triple i686-windows-msvc -o /dev/null 2>&1 | FileCheck %s --implicit-check-not=error:
1
2 .globl _foo
3 _foo:
4 .cv_fpo_proc
5 # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected symbol name
6 .cv_fpo_proc 1
7 # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected symbol name
8 .cv_fpo_proc _foo extra
9 # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected parameter byte count
10 .cv_fpo_proc _foo 4 extra
11 # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: unexpected tokens in '.cv_fpo_proc' directive
12 .cv_fpo_proc _foo 4
13
14 pushl %ebp
15 .cv_fpo_pushreg 1
16 # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: invalid register name in '.cv_fpo_pushreg' directive
17 .cv_fpo_pushreg ebp
18
19 subl $20, %esp
20 .cv_fpo_stackalloc asdf
21 # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected offset in '.cv_fpo_stackalloc' directive
22 .cv_fpo_stackalloc 20 asdf
23 # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: unexpected tokens in '.cv_fpo_stackalloc' directive
24 .cv_fpo_stackalloc 20
25 .cv_fpo_endprologue asdf
26 # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: unexpected tokens in '.cv_fpo_endprologue' directive
27 .cv_fpo_endprologue
28
29 addl $20, %esp
30 popl %ebp
31 retl
32 .cv_fpo_endproc asdf
33 # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: unexpected tokens in '.cv_fpo_endproc' directive
34 .cv_fpo_endproc
35
36 .section .debug$S,"dr"
37 .p2align 2
38 .long 4 # Debug section magic
39 .cv_fpo_data
40 # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected symbol name
41 .cv_fpo_data 1
42 # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected symbol name
43 .cv_fpo_data _foo asdf
44 # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: unexpected tokens in '.cv_fpo_data' directive
45 .cv_fpo_data _foo
46 .long 0
0 # RUN: llvm-mc -filetype=asm < %s -triple i686-windows-msvc | FileCheck %s --check-prefix=ASM
1 # RUN: llvm-mc -filetype=obj < %s -triple i686-windows-msvc | llvm-readobj -codeview | FileCheck %s --check-prefix=OBJ
2
3 .globl _foo
4 _foo:
5 .cv_fpo_proc _foo 4
6 pushl %ebp
7 .cv_fpo_pushreg %ebp
8 movl %ebp, %esp
9 .cv_fpo_setframe %ebp
10 pushl %ebx
11 .cv_fpo_pushreg %ebx
12 pushl %edi
13 .cv_fpo_pushreg %edi
14 pushl %esi
15 .cv_fpo_pushreg esi
16 subl $20, %esp
17 .cv_fpo_stackalloc 20
18 .cv_fpo_endprologue
19
20 # ASM: .cv_fpo_proc _foo 4
21 # ASM: pushl %ebp
22 # ASM: .cv_fpo_pushreg %ebp
23 # ASM: movl %ebp, %esp
24 # ASM: .cv_fpo_setframe %ebp
25 # ASM: pushl %ebx
26 # ASM: .cv_fpo_pushreg %ebx
27 # ASM: pushl %edi
28 # ASM: .cv_fpo_pushreg %edi
29 # ASM: pushl %esi
30 # ASM: .cv_fpo_pushreg %esi
31 # ASM: subl $20, %esp
32 # ASM: .cv_fpo_stackalloc 20
33 # ASM: .cv_fpo_endprologue
34
35 # Clobbers
36 xorl %ebx, %ebx
37 xorl %edi, %edi
38 xorl %esi, %esi
39 # Use that stack memory
40 leal 4(%esp), %eax
41 movl %eax, (%esp)
42 calll _bar
43
44 # ASM: calll _bar
45
46 # Epilogue
47 # FIXME: Get FPO data for this once we get it for DWARF.
48 addl $20, %esp
49 popl %esi
50 popl %edi
51 popl %ebx
52 popl %ebp
53 retl
54 .cv_fpo_endproc
55
56 # ASM: .cv_fpo_endproc
57
58 .section .debug$S,"dr"
59 .p2align 2
60 .long 4 # Debug section magic
61 .cv_fpo_data _foo
62 .cv_stringtable
63
64 # ASM: .cv_fpo_data
65
66 # OBJ: Subsection [
67 # OBJ-NEXT: SubSectionType: FrameData (0xF5)
68 # OBJ-NEXT: SubSectionSize:
69 # OBJ-NEXT: LinkageName: _foo
70 # OBJ-NEXT: FrameData {
71 # OBJ-NEXT: RvaStart: 0x0
72 # OBJ-NEXT: CodeSize: 0x23
73 # OBJ-NEXT: LocalSize: 0x0
74 # OBJ-NEXT: ParamsSize: 0x4
75 # OBJ-NEXT: MaxStackSize: 0x0
76 # OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
77 # OBJ-NEXT: PrologSize: 0x9
78 # OBJ-NEXT: SavedRegsSize: 0x0
79 # OBJ-NEXT: Flags [ (0x4)
80 # OBJ-NEXT: IsFunctionStart (0x4)
81 # OBJ-NEXT: ]
82 # OBJ-NEXT: }
83 # OBJ-NEXT: FrameData {
84 # OBJ-NEXT: RvaStart: 0x1
85 # OBJ-NEXT: CodeSize: 0x22
86 # OBJ-NEXT: LocalSize: 0x0
87 # OBJ-NEXT: ParamsSize: 0x4
88 # OBJ-NEXT: MaxStackSize: 0x0
89 # OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ =
90 # OBJ-NEXT: PrologSize: 0x8
91 # OBJ-NEXT: SavedRegsSize: 0x4
92 # OBJ-NEXT: Flags [ (0x0)
93 # OBJ-NEXT: ]
94 # OBJ-NEXT: }
95 # OBJ-NEXT: FrameData {
96 # OBJ-NEXT: RvaStart: 0x3
97 # OBJ-NEXT: CodeSize: 0x20
98 # OBJ-NEXT: LocalSize: 0x0
99 # OBJ-NEXT: ParamsSize: 0x4
100 # OBJ-NEXT: MaxStackSize: 0x0
101 # OBJ-NEXT: FrameFunc: $T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ =
102 # OBJ-NEXT: PrologSize: 0x6
103 # OBJ-NEXT: SavedRegsSize: 0x4
104 # OBJ-NEXT: Flags [ (0x0)
105 # OBJ-NEXT: ]
106 # OBJ-NEXT: }
107 # OBJ-NEXT: FrameData {
108 # OBJ-NEXT: RvaStart: 0x4
109 # OBJ-NEXT: CodeSize: 0x1F
110 # OBJ-NEXT: LocalSize: 0x0
111 # OBJ-NEXT: ParamsSize: 0x4
112 # OBJ-NEXT: MaxStackSize: 0x0
113 # OBJ-NEXT: FrameFunc: $T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ =
114 # OBJ-NEXT: PrologSize: 0x5
115 # OBJ-NEXT: SavedRegsSize: 0x8
116 # OBJ-NEXT: Flags [ (0x0)
117 # OBJ-NEXT: ]
118 # OBJ-NEXT: }
119 # OBJ-NEXT: FrameData {
120 # OBJ-NEXT: RvaStart: 0x5
121 # OBJ-NEXT: CodeSize: 0x1E
122 # OBJ-NEXT: LocalSize: 0x0
123 # OBJ-NEXT: ParamsSize: 0x4
124 # OBJ-NEXT: MaxStackSize: 0x0
125 # OBJ-NEXT: FrameFunc: $T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ = $edi $T0 12 - ^ =
126 # OBJ-NEXT: PrologSize: 0x4
127 # OBJ-NEXT: SavedRegsSize: 0xC
128 # OBJ-NEXT: Flags [ (0x0)
129 # OBJ-NEXT: ]
130 # OBJ-NEXT: }
131 # OBJ-NEXT: FrameData {
132 # OBJ-NEXT: RvaStart: 0x6
133 # OBJ-NEXT: CodeSize: 0x1D
134 # OBJ-NEXT: LocalSize: 0x0
135 # OBJ-NEXT: ParamsSize: 0x4
136 # OBJ-NEXT: MaxStackSize: 0x0
137 # OBJ-NEXT: FrameFunc: $T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ = $edi $T0 12 - ^ = $esi $T0 16 - ^ =
138 # OBJ-NEXT: PrologSize: 0x3
139 # OBJ-NEXT: SavedRegsSize: 0x10
140 # OBJ-NEXT: Flags [ (0x0)
141 # OBJ-NEXT: ]
142 # OBJ-NEXT: }
143 # OBJ-NOT: FrameData