Clang AST到IR的转换

边介绍了几节Clang AST,包括AST的读取,Rewriter,AST的插入等,这里想从AST到IR的转换,介绍一点Clang源码的内容。

前边已经提到了想打印AST树内容的话,需要使用clang -fsyntax-only -Xclang -ast-dump 命令来进行。对于llvm各种文件格式的转换,有一个图说的比较清楚,内容来源见水印。

 

 

 我们使用的源码还是以上次使用的view.cpp

 1 int foo(int a, int b, int *c) {
 2     int ret = 0;
 3     if (a > b) {
 4         ret = a;
 5     } else {
 6         ret = b;
 7     }
 8     for (int temp = 0; temp < 100; ++temp) {
 9         *c = (*c + temp);
10     }
11     return ret;
12 }
13 
14 
15 int main() {
16     int a = 1, b = 2;
17     int c = 0;
18     int d = foo(a, b, &c);
19     return 0;
20 }
View Code

打印出来的view.ll文件如下:

; ModuleID = 'view.cpp'
source_filename = "view.cpp"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

; Function Attrs: noinline nounwind optnone uwtable mustprogress
define dso_local i32 @_Z3fooiiPi(i32 %0, i32 %1, i32* %2) #0 {
  %4 = alloca i32, align 4
  %5 = alloca i32, align 4
  %6 = alloca i32*, align 8
  %7 = alloca i32, align 4
  %8 = alloca i32, align 4
  store i32 %0, i32* %4, align 4
  store i32 %1, i32* %5, align 4
  store i32* %2, i32** %6, align 8
  store i32 0, i32* %7, align 4
  %9 = load i32, i32* %4, align 4
  %10 = load i32, i32* %5, align 4
  %11 = icmp sgt i32 %9, %10
  br i1 %11, label %12, label %14

12:                                               ; preds = %3
  %13 = load i32, i32* %4, align 4
  store i32 %13, i32* %7, align 4
  br label %16

14:                                               ; preds = %3
  %15 = load i32, i32* %5, align 4
  store i32 %15, i32* %7, align 4
  br label %16

16:                                               ; preds = %14, %12
  store i32 0, i32* %8, align 4
  br label %17

17:                                               ; preds = %26, %16
  %18 = load i32, i32* %8, align 4
  %19 = icmp slt i32 %18, 100
  br i1 %19, label %20, label %29

20:                                               ; preds = %17
  %21 = load i32*, i32** %6, align 8
  %22 = load i32, i32* %21, align 4
  %23 = load i32, i32* %8, align 4
  %24 = add nsw i32 %22, %23
  %25 = load i32*, i32** %6, align 8
  store i32 %24, i32* %25, align 4
  br label %26

26:                                               ; preds = %20
  %27 = load i32, i32* %8, align 4
  %28 = add nsw i32 %27, 1
  store i32 %28, i32* %8, align 4
  br label %17, !llvm.loop !2

29:                                               ; preds = %17
  %30 = load i32, i32* %7, align 4
  ret i32 %30
}

; Function Attrs: noinline norecurse nounwind optnone uwtable mustprogress
define dso_local i32 @main() #1 {
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
  %3 = alloca i32, align 4
  %4 = alloca i32, align 4
  %5 = alloca i32, align 4
  store i32 0, i32* %1, align 4
  store i32 1, i32* %2, align 4
  store i32 2, i32* %3, align 4
  store i32 0, i32* %4, align 4
  %6 = load i32, i32* %2, align 4
  %7 = load i32, i32* %3, align 4
  %8 = call i32 @_Z3fooiiPi(i32 %6, i32 %7, i32* %4)
  store i32 %8, i32* %5, align 4
  ret i32 0
}

; Function Attrs: noinline norecurse nounwind optnone uwtable mustprogress
define dso_local i32 @main() #1 {
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
  %3 = alloca i32, align 4
  %4 = alloca i32, align 4
  %5 = alloca i32, align 4
  store i32 0, i32* %1, align 4
  store i32 1, i32* %2, align 4
  store i32 2, i32* %3, align 4
  store i32 0, i32* %4, align 4
  %6 = load i32, i32* %2, align 4
  %7 = load i32, i32* %3, align 4
  %8 = call i32 @_Z3fooiiPi(i32 %6, i32 %7, i32* %4)
  store i32 %8, i32* %5, align 4
  ret i32 0
}

attributes #0 = { noinline nounwind optnone uwtable mustprogress "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #1 = { noinline norecurse nounwind optnone uwtable mustprogress "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }

!llvm.module.flags = !{!0}
!llvm.ident = !{!1}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{!"clang version 13.0.0"}
!2 = distinct !{!2, !3}
!3 = !{!"llvm.loop.mustprogress"}

  对于如何生成llvm的IR(其实是以bc文件格式存在,这里为了human read),主要通过namespace clang::CodeGen来记性,在llvm/lib/CodeGen目录下有很多以CG开头的文件,负责各种类型的AST节点的CodeGen工作,这里我仅以ForStmt这个节点来进行介绍。

       从Clang 的Doxgen图上来看,ForStmt继承至Stmt(https://clang.llvm.org/doxygen/classclang_1_1ForStmt.html)

 

 

很多AST节点类型都继承至Stmt,因此,不看代码,从设计的调度来看,应该是一个switch case的结构,通过判断节点的类型来分别进入到每个AST节点进行CodeGen。

定位到clang/lib/CodeGen/CGStmt.cpp中,第二个函数就看到了

void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs)
从名字上就是“EmitStmt”,指令Emit,StmtEmit,这可以理解为一条线。我了解的阅读代码有两条线,一条是使用gdb一步步下断点,不停的跟进去,这是非常正确的,也是大家一般推荐的,但是在工程量非常大的project上可能不实用,主要是main函数进来到你真正想看的地方有点太过漫长,比较耗时耗力,还有一条路线是直接读代码,也就是所谓的猜,一般开源的,有一定影响力的代码,设计上都比较清晰,靠注释和函数名可以解决很多问题,前提是需要你对该领域有一定了解,对初学者来说难度巨大。一般来说,两条线是交替进行的,gdb加直接读,容易事半功倍,同时,可以考虑在源码上加一些输出(printf大法),来判断函数调用过程。
这里我将整个EmitStmt代码贴一下:
  1 void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) {
  2   assert(S && "Null statement?");
  3   llvm::errs()<<"EmitStmt\n";
  4   PGO.setCurrentStmt(S);
  5 
  6   // These statements have their own debug info handling.
  7   if (EmitSimpleStmt(S, Attrs))
  8     return;
  9 
 10   // Check if we are generating unreachable code.
 11   if (!HaveInsertPoint()) {
 12     // If so, and the statement doesn't contain a label, then we do not need to
 13     // generate actual code. This is safe because (1) the current point is
 14     // unreachable, so we don't need to execute the code, and (2) we've already
 15     // handled the statements which update internal data structures (like the
 16     // local variable map) which could be used by subsequent statements.
 17     if (!ContainsLabel(S)) {
 18       // Verify that any decl statements were handled as simple, they may be in
 19       // scope of subsequent reachable statements.
 20       assert(!isa<DeclStmt>(*S) && "Unexpected DeclStmt!");
 21       return;
 22     }
 23 
 24     // Otherwise, make a new block to hold the code.
 25     EnsureInsertPoint();
 26   }
 27 llvm::errs()<<"EmitStmt Emit\n";
 28   // Generate a stoppoint if we are emitting debug info.
 29   EmitStopPoint(S);
 30 
 31   // Ignore all OpenMP directives except for simd if OpenMP with Simd is
 32   // enabled.
 33   if (getLangOpts().OpenMP && getLangOpts().OpenMPSimd) {
 34     if (const auto *D = dyn_cast<OMPExecutableDirective>(S)) {
 35       EmitSimpleOMPExecutableDirective(*D);
 36       return;
 37     }
 38   }
 39 
 40   switch (S->getStmtClass()) {
 41   case Stmt::NoStmtClass:
 42   case Stmt::CXXCatchStmtClass:
 43   case Stmt::SEHExceptStmtClass:
 44   case Stmt::SEHFinallyStmtClass:
 45   case Stmt::MSDependentExistsStmtClass:
 46     llvm_unreachable("invalid statement class to emit generically");
 47   case Stmt::NullStmtClass:
 48   case Stmt::CompoundStmtClass:
 49   case Stmt::DeclStmtClass:
 50   case Stmt::LabelStmtClass:
 51   case Stmt::AttributedStmtClass:
 52   case Stmt::GotoStmtClass:
 53   case Stmt::BreakStmtClass:
 54   case Stmt::ContinueStmtClass:
 55   case Stmt::DefaultStmtClass:
 56   case Stmt::CaseStmtClass:
 57   case Stmt::SEHLeaveStmtClass:
 58     llvm_unreachable("should have emitted these statements as simple");
 59 
 60 #define STMT(Type, Base)
 61 #define ABSTRACT_STMT(Op)
 62 #define EXPR(Type, Base) \
 63   case Stmt::Type##Class:
 64 #include "clang/AST/StmtNodes.inc"
 65   {
 66     // Remember the block we came in on.
 67     llvm::BasicBlock *incoming = Builder.GetInsertBlock();
 68     assert(incoming && "expression emission must have an insertion point");
 69 
 70     EmitIgnoredExpr(cast<Expr>(S));
 71 
 72     llvm::BasicBlock *outgoing = Builder.GetInsertBlock();
 73     assert(outgoing && "expression emission cleared block!");
 74 
 75     // The expression emitters assume (reasonably!) that the insertion
 76     // point is always set.  To maintain that, the call-emission code
 77     // for noreturn functions has to enter a new block with no
 78     // predecessors.  We want to kill that block and mark the current
 79     // insertion point unreachable in the common case of a call like
 80     // "exit();".  Since expression emission doesn't otherwise create
 81     // blocks with no predecessors, we can just test for that.
 82     // However, we must be careful not to do this to our incoming
 83     // block, because *statement* emission does sometimes create
 84     // reachable blocks which will have no predecessors until later in
 85     // the function.  This occurs with, e.g., labels that are not
 86     // reachable by fallthrough.
 87     if (incoming != outgoing && outgoing->use_empty()) {
 88       outgoing->eraseFromParent();
 89       Builder.ClearInsertionPoint();
 90     }
 91     break;
 92   }
 93 
 94   case Stmt::IndirectGotoStmtClass:
 95     EmitIndirectGotoStmt(cast<IndirectGotoStmt>(*S)); break;
 96 
 97   case Stmt::IfStmtClass:      EmitIfStmt(cast<IfStmt>(*S));              break;
 98   case Stmt::WhileStmtClass:   EmitWhileStmt(cast<WhileStmt>(*S), Attrs); break;
 99   case Stmt::DoStmtClass:      EmitDoStmt(cast<DoStmt>(*S), Attrs);       break;
100   case Stmt::ForStmtClass:    llvm::errs()<<"EmitForStmt\n"; EmitForStmt(cast<ForStmt>(*S), Attrs);     break;
101 
102   case Stmt::ReturnStmtClass:  EmitReturnStmt(cast<ReturnStmt>(*S));      break;
103 
104   case Stmt::SwitchStmtClass:  EmitSwitchStmt(cast<SwitchStmt>(*S));      break;
105   case Stmt::GCCAsmStmtClass:  // Intentional fall-through.
106   case Stmt::MSAsmStmtClass:   EmitAsmStmt(cast<AsmStmt>(*S));            break;
107   case Stmt::CoroutineBodyStmtClass:
108     EmitCoroutineBody(cast<CoroutineBodyStmt>(*S));
109     break;
110   case Stmt::CoreturnStmtClass:
111     EmitCoreturnStmt(cast<CoreturnStmt>(*S));
112     break;
113   case Stmt::CapturedStmtClass: {
114     const CapturedStmt *CS = cast<CapturedStmt>(S);
115     EmitCapturedStmt(*CS, CS->getCapturedRegionKind());
116     }
117     break;
118   case Stmt::ObjCAtTryStmtClass:
119     EmitObjCAtTryStmt(cast<ObjCAtTryStmt>(*S));
120     break;
121   case Stmt::ObjCAtCatchStmtClass:
122     llvm_unreachable(
123                     "@catch statements should be handled by EmitObjCAtTryStmt");
124   case Stmt::ObjCAtFinallyStmtClass:
125     llvm_unreachable(
126                   "@finally statements should be handled by EmitObjCAtTryStmt");
127   case Stmt::ObjCAtThrowStmtClass:
128     EmitObjCAtThrowStmt(cast<ObjCAtThrowStmt>(*S));
129     break;
130   case Stmt::ObjCAtSynchronizedStmtClass:
131     EmitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(*S));
132     break;
133   case Stmt::ObjCForCollectionStmtClass:
134     EmitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(*S));
135     break;
136   case Stmt::ObjCAutoreleasePoolStmtClass:
137     EmitObjCAutoreleasePoolStmt(cast<ObjCAutoreleasePoolStmt>(*S));
138     break;
139 
140   case Stmt::CXXTryStmtClass:
141     EmitCXXTryStmt(cast<CXXTryStmt>(*S));
142     break;
143   case Stmt::CXXForRangeStmtClass:
144     EmitCXXForRangeStmt(cast<CXXForRangeStmt>(*S), Attrs);
145     break;
146   case Stmt::SEHTryStmtClass:
147     EmitSEHTryStmt(cast<SEHTryStmt>(*S));
148     break;
149   case Stmt::OMPCanonicalLoopClass:
150     EmitOMPCanonicalLoop(cast<OMPCanonicalLoop>(S));
151     break;
152   case Stmt::OMPParallelDirectiveClass:
153     EmitOMPParallelDirective(cast<OMPParallelDirective>(*S));
154     break;
155   case Stmt::OMPSimdDirectiveClass:
156     EmitOMPSimdDirective(cast<OMPSimdDirective>(*S));
157     break;
158   case Stmt::OMPTileDirectiveClass:
159     EmitOMPTileDirective(cast<OMPTileDirective>(*S));
160     break;
161   case Stmt::OMPForDirectiveClass:
162     EmitOMPForDirective(cast<OMPForDirective>(*S));
163     break;
164   case Stmt::OMPForSimdDirectiveClass:
165     EmitOMPForSimdDirective(cast<OMPForSimdDirective>(*S));
166     break;
167   case Stmt::OMPSectionsDirectiveClass:
168     EmitOMPSectionsDirective(cast<OMPSectionsDirective>(*S));
169     break;
170   case Stmt::OMPSectionDirectiveClass:
171     EmitOMPSectionDirective(cast<OMPSectionDirective>(*S));
172     break;
173   case Stmt::OMPSingleDirectiveClass:
174     EmitOMPSingleDirective(cast<OMPSingleDirective>(*S));
175     break;
176   case Stmt::OMPMasterDirectiveClass:
177     EmitOMPMasterDirective(cast<OMPMasterDirective>(*S));
178     break;
179   case Stmt::OMPCriticalDirectiveClass:
180     EmitOMPCriticalDirective(cast<OMPCriticalDirective>(*S));
181     break;
182   case Stmt::OMPParallelForDirectiveClass:
183     EmitOMPParallelForDirective(cast<OMPParallelForDirective>(*S));
184     break;
185   case Stmt::OMPParallelForSimdDirectiveClass:
186     EmitOMPParallelForSimdDirective(cast<OMPParallelForSimdDirective>(*S));
187     break;
188   case Stmt::OMPParallelMasterDirectiveClass:
189     EmitOMPParallelMasterDirective(cast<OMPParallelMasterDirective>(*S));
190     break;
191   case Stmt::OMPParallelSectionsDirectiveClass:
192     EmitOMPParallelSectionsDirective(cast<OMPParallelSectionsDirective>(*S));
193     break;
194   case Stmt::OMPTaskDirectiveClass:
195     EmitOMPTaskDirective(cast<OMPTaskDirective>(*S));
196     break;
197   case Stmt::OMPTaskyieldDirectiveClass:
198     EmitOMPTaskyieldDirective(cast<OMPTaskyieldDirective>(*S));
199     break;
200   case Stmt::OMPBarrierDirectiveClass:
201     EmitOMPBarrierDirective(cast<OMPBarrierDirective>(*S));
202     break;
203   case Stmt::OMPTaskwaitDirectiveClass:
204     EmitOMPTaskwaitDirective(cast<OMPTaskwaitDirective>(*S));
205     break;
206   case Stmt::OMPTaskgroupDirectiveClass:
207     EmitOMPTaskgroupDirective(cast<OMPTaskgroupDirective>(*S));
208     break;
209   case Stmt::OMPFlushDirectiveClass:
210     EmitOMPFlushDirective(cast<OMPFlushDirective>(*S));
211     break;
212   case Stmt::OMPDepobjDirectiveClass:
213     EmitOMPDepobjDirective(cast<OMPDepobjDirective>(*S));
214     break;
215   case Stmt::OMPScanDirectiveClass:
216     EmitOMPScanDirective(cast<OMPScanDirective>(*S));
217     break;
218   case Stmt::OMPOrderedDirectiveClass:
219     EmitOMPOrderedDirective(cast<OMPOrderedDirective>(*S));
220     break;
221   case Stmt::OMPAtomicDirectiveClass:
222     EmitOMPAtomicDirective(cast<OMPAtomicDirective>(*S));
223     break;
224   case Stmt::OMPTargetDirectiveClass:
225     EmitOMPTargetDirective(cast<OMPTargetDirective>(*S));
226     break;
227   case Stmt::OMPTeamsDirectiveClass:
228     EmitOMPTeamsDirective(cast<OMPTeamsDirective>(*S));
229     break;
230   case Stmt::OMPCancellationPointDirectiveClass:
231     EmitOMPCancellationPointDirective(cast<OMPCancellationPointDirective>(*S));
232     break;
233   case Stmt::OMPCancelDirectiveClass:
234     EmitOMPCancelDirective(cast<OMPCancelDirective>(*S));
235     break;
236   case Stmt::OMPTargetDataDirectiveClass:
237     EmitOMPTargetDataDirective(cast<OMPTargetDataDirective>(*S));
238     break;
239   case Stmt::OMPTargetEnterDataDirectiveClass:
240     EmitOMPTargetEnterDataDirective(cast<OMPTargetEnterDataDirective>(*S));
241     break;
242   case Stmt::OMPTargetExitDataDirectiveClass:
243     EmitOMPTargetExitDataDirective(cast<OMPTargetExitDataDirective>(*S));
244     break;
245   case Stmt::OMPTargetParallelDirectiveClass:
246     EmitOMPTargetParallelDirective(cast<OMPTargetParallelDirective>(*S));
247     break;
248   case Stmt::OMPTargetParallelForDirectiveClass:
249     EmitOMPTargetParallelForDirective(cast<OMPTargetParallelForDirective>(*S));
250     break;
251   case Stmt::OMPTaskLoopDirectiveClass:
252     EmitOMPTaskLoopDirective(cast<OMPTaskLoopDirective>(*S));
253     break;
254   case Stmt::OMPTaskLoopSimdDirectiveClass:
255     EmitOMPTaskLoopSimdDirective(cast<OMPTaskLoopSimdDirective>(*S));
256     break;
257   case Stmt::OMPMasterTaskLoopDirectiveClass:
258     EmitOMPMasterTaskLoopDirective(cast<OMPMasterTaskLoopDirective>(*S));
259     break;
260   case Stmt::OMPMasterTaskLoopSimdDirectiveClass:
261     EmitOMPMasterTaskLoopSimdDirective(
262         cast<OMPMasterTaskLoopSimdDirective>(*S));
263     break;
264   case Stmt::OMPParallelMasterTaskLoopDirectiveClass:
265     EmitOMPParallelMasterTaskLoopDirective(
266         cast<OMPParallelMasterTaskLoopDirective>(*S));
267     break;
268   case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass:
269     EmitOMPParallelMasterTaskLoopSimdDirective(
270         cast<OMPParallelMasterTaskLoopSimdDirective>(*S));
271     break;
272   case Stmt::OMPDistributeDirectiveClass:
273     EmitOMPDistributeDirective(cast<OMPDistributeDirective>(*S));
274     break;
275   case Stmt::OMPTargetUpdateDirectiveClass:
276     EmitOMPTargetUpdateDirective(cast<OMPTargetUpdateDirective>(*S));
277     break;
278   case Stmt::OMPDistributeParallelForDirectiveClass:
279     EmitOMPDistributeParallelForDirective(
280         cast<OMPDistributeParallelForDirective>(*S));
281     break;
282   case Stmt::OMPDistributeParallelForSimdDirectiveClass:
283     EmitOMPDistributeParallelForSimdDirective(
284         cast<OMPDistributeParallelForSimdDirective>(*S));
285     break;
286   case Stmt::OMPDistributeSimdDirectiveClass:
287     EmitOMPDistributeSimdDirective(cast<OMPDistributeSimdDirective>(*S));
288     break;
289   case Stmt::OMPTargetParallelForSimdDirectiveClass:
290     EmitOMPTargetParallelForSimdDirective(
291         cast<OMPTargetParallelForSimdDirective>(*S));
292     break;
293   case Stmt::OMPTargetSimdDirectiveClass:
294     EmitOMPTargetSimdDirective(cast<OMPTargetSimdDirective>(*S));
295     break;
296   case Stmt::OMPTeamsDistributeDirectiveClass:
297     EmitOMPTeamsDistributeDirective(cast<OMPTeamsDistributeDirective>(*S));
298     break;
299   case Stmt::OMPTeamsDistributeSimdDirectiveClass:
300     EmitOMPTeamsDistributeSimdDirective(
301         cast<OMPTeamsDistributeSimdDirective>(*S));
302     break;
303   case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass:
304     EmitOMPTeamsDistributeParallelForSimdDirective(
305         cast<OMPTeamsDistributeParallelForSimdDirective>(*S));
306     break;
307   case Stmt::OMPTeamsDistributeParallelForDirectiveClass:
308     EmitOMPTeamsDistributeParallelForDirective(
309         cast<OMPTeamsDistributeParallelForDirective>(*S));
310     break;
311   case Stmt::OMPTargetTeamsDirectiveClass:
312     EmitOMPTargetTeamsDirective(cast<OMPTargetTeamsDirective>(*S));
313     break;
314   case Stmt::OMPTargetTeamsDistributeDirectiveClass:
315     EmitOMPTargetTeamsDistributeDirective(
316         cast<OMPTargetTeamsDistributeDirective>(*S));
317     break;
318   case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass:
319     EmitOMPTargetTeamsDistributeParallelForDirective(
320         cast<OMPTargetTeamsDistributeParallelForDirective>(*S));
321     break;
322   case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass:
323     EmitOMPTargetTeamsDistributeParallelForSimdDirective(
324         cast<OMPTargetTeamsDistributeParallelForSimdDirective>(*S));
325     break;
326   case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:
327     EmitOMPTargetTeamsDistributeSimdDirective(
328         cast<OMPTargetTeamsDistributeSimdDirective>(*S));
329     break;
330   }
331 }
EmitStmt

前边是一些判断,主要的结构和我们猜想的一样是一个大的switch case判断,根据S->getStmtClass()来进行,中间还搞进来一个大的宏include,

#define STMT(Type, Base)
#define ABSTRACT_STMT(Op)
#define EXPR(Type, Base) \
  case Stmt::Type##Class:
#include "clang/AST/StmtNodes.inc"

  这里是把所有的StmtNodes.inc都包进来。后边紧跟着就是case Stmt::ForStmtClass类型的判断。

我们进入EmitForStmt(cast<ForStmt>(*S), Attrs);里边看一下

  1 void CodeGenFunction::EmitForStmt(const ForStmt &S,
  2                                   ArrayRef<const Attr *> ForAttrs) {
  3   JumpDest LoopExit = getJumpDestInCurrentScope("for.end");
  4 
  5   LexicalScope ForScope(*this, S.getSourceRange());
  6 
  7   // Evaluate the first part before the loop.
  8   if (S.getInit())
  9     EmitStmt(S.getInit());
 10 
 11   // Start the loop with a block that tests the condition.
 12   // If there's an increment, the continue scope will be overwritten
 13   // later.
 14   JumpDest Continue = getJumpDestInCurrentScope("for.cond");
 15   llvm::BasicBlock *CondBlock = Continue.getBlock();
 16   EmitBlock(CondBlock);
 17 
 18   bool LoopMustProgress = false;
 19   Expr::EvalResult Result;
 20   if (LanguageRequiresProgress()) {
 21     if (!S.getCond()) {
 22       FnIsMustProgress = false;
 23     } else if (!S.getCond()->EvaluateAsInt(Result, getContext())) {
 24       LoopMustProgress = true;
 25     }
 26   }
 27 
 28   const SourceRange &R = S.getSourceRange();
 29   LoopStack.push(CondBlock, CGM.getContext(), CGM.getCodeGenOpts(), ForAttrs,
 30                  SourceLocToDebugLoc(R.getBegin()),
 31                  SourceLocToDebugLoc(R.getEnd()), LoopMustProgress);
 32 
 33   // If the for loop doesn't have an increment we can just use the
 34   // condition as the continue block.  Otherwise we'll need to create
 35   // a block for it (in the current scope, i.e. in the scope of the
 36   // condition), and that we will become our continue block.
 37   if (S.getInc())
 38     Continue = getJumpDestInCurrentScope("for.inc");
 39 
 40   // Store the blocks to use for break and continue.
 41   BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
 42 
 43   // Create a cleanup scope for the condition variable cleanups.
 44   LexicalScope ConditionScope(*this, S.getSourceRange());
 45 
 46   if (S.getCond()) {
 47     // If the for statement has a condition scope, emit the local variable
 48     // declaration.
 49     if (S.getConditionVariable()) {
 50       EmitDecl(*S.getConditionVariable());
 51     }
 52 
 53     llvm::BasicBlock *ExitBlock = LoopExit.getBlock();
 54     // If there are any cleanups between here and the loop-exit scope,
 55     // create a block to stage a loop exit along.
 56     if (ForScope.requiresCleanups())
 57       ExitBlock = createBasicBlock("for.cond.cleanup");
 58 
 59     // As long as the condition is true, iterate the loop.
 60     llvm::BasicBlock *ForBody = createBasicBlock("for.body");
 61 
 62     // C99 6.8.5p2/p4: The first substatement is executed if the expression
 63     // compares unequal to 0.  The condition must be a scalar type.
 64     llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
 65     llvm::MDNode *Weights = createProfileOrBranchWeightsForLoop(
 66         S.getCond(), getProfileCount(S.getBody()), S.getBody());
 67 
 68     if (llvm::ConstantInt *C = dyn_cast<llvm::ConstantInt>(BoolCondVal))
 69       if (C->isOne())
 70         FnIsMustProgress = false;
 71 
 72     Builder.CreateCondBr(BoolCondVal, ForBody, ExitBlock, Weights);
 73 
 74     if (ExitBlock != LoopExit.getBlock()) {
 75       EmitBlock(ExitBlock);
 76       EmitBranchThroughCleanup(LoopExit);
 77     }
 78 
 79     EmitBlock(ForBody);
 80   } else {
 81     // Treat it as a non-zero constant.  Don't even create a new block for the
 82     // body, just fall into it.
 83   }
 84   incrementProfileCounter(&S);
 85 
 86   {
 87     // Create a separate cleanup scope for the body, in case it is not
 88     // a compound statement.
 89     RunCleanupsScope BodyScope(*this);
 90     EmitStmt(S.getBody());
 91   }
 92 
 93   // If there is an increment, emit it next.
 94   if (S.getInc()) {
 95     EmitBlock(Continue.getBlock());
 96     EmitStmt(S.getInc());
 97   }
 98 
 99   BreakContinueStack.pop_back();
100 
101   ConditionScope.ForceCleanup();
102 
103   EmitStopPoint(&S);
104   EmitBranch(CondBlock);
105 
106   ForScope.ForceCleanup();
107 
108   LoopStack.pop();
109 
110   // Emit the fall-through block.
111   EmitBlock(LoopExit.getBlock(), true);
112 }

大概流程和我之前处理ForStmt的读取的方式是一样的,getInit()/getCond()/getInc()/getBody()分别进行处理,每个生成对应Block,这里处理的时候,因为最后都需要处理成跳转的形式,需要预先记录下for结束的出口,然后按照Init() / Cond() /Body() / Inc() / Cond() 的顺序进行处理。

posted @ 2021-03-14 14:37  转换无极限  阅读(2567)  评论(2编辑  收藏  举报