我想在我的玩具 C 编译器中支持编译。 我的想法是: 在支持 while 之前支持 do-while。然后使用 do-while AST 构造一个 while AST。这样我就可以简化while的codegen函数了
while (Cond) {
statements;
}
===>
if (!Cond)
br afterwhile
do {
statements;
} while (Cond);
afterwhile:
...
这里是 do-while 和 while 的 AST 代码:
// DoWhile
class DoWhileExprAST : public ExprAST {
std::unique_ptr<CodeBlocks> LoopBody;
std::unique_ptr<ExprAST> Cond;
friend class WhileExprAST;
public:
DoWhileExprAST(std::unique_ptr<CodeBlocks> LoopBody, std::unique_ptr<ExprAST> Cond) :
LoopBody(std::move(LoopBody)), Cond(std::move(Cond)) {}
Value *codegen() override;
};
// While : Convert to DoWhile when Paring
class WhileExprAST : public ExprAST {
std::unique_ptr<DoWhileExprAST> DoWhile;
public:
WhileExprAST(std::unique_ptr<DoWhileExprAST> DoWhile) : DoWhile(std::move(DoWhile)) {}
Value *codegen() override;
};
这里有两个codegen函数:
Value *DoWhileExprAST::codegen() {
Function *TheFunction = Builder->GetInsertBlock()->getParent();
// Create blocks for the loop and after. Insert the 'loop' block at the
// end of the function.
BasicBlock *LoopBB = BasicBlock::Create(*TheContext, "loop", TheFunction);
BasicBlock *AfterBB = BasicBlock::Create(*TheContext, "afterloop");
Builder->CreateBr(LoopBB);
// Emit then value.
Builder->SetInsertPoint(LoopBB);
Value *LoopBodyV = LoopBody->codegen();
if (!LoopBodyV)
return nullptr;
// emit the cond.
Value *CondV = Cond->codegen();
CondV = Builder->CreateICmpNE(CondV,
ConstantInt::get(CondV->getType(), 0), "loopcond");
Builder->CreateCondBr(CondV, LoopBB, AfterBB);
TheFunction->insert(TheFunction->end(), AfterBB);
Builder->SetInsertPoint(AfterBB);
// loop expr always return 0
return Constant::getNullValue(IntegerType::getInt64Ty(*TheContext));
}
Value *WhileExprAST::codegen() {
Function *TheFunction = Builder->GetInsertBlock()->getParent();
BasicBlock *FistTestBB = BasicBlock::Create(*TheContext, "test", TheFunction);
BasicBlock *DoWhileLoop = BasicBlock::Create(*TheContext, "dowhile");
BasicBlock *AfterWhile = BasicBlock::Create(*TheContext, "afterwhile");
Builder->CreateBr(FistTestBB);
Builder->SetInsertPoint(FistTestBB);
Value *CondV = DoWhile->Cond->codegen();
CondV = Builder->CreateICmpNE(CondV,
ConstantInt::get(CondV->getType(), 0), "testcond");
Builder->CreateCondBr(CondV, DoWhileLoop, AfterWhile);
TheFunction->insert(TheFunction->end(), DoWhileLoop);
Builder->SetInsertPoint(DoWhileLoop);
DoWhile->codegen();
TheFunction->insert(TheFunction->end(), AfterWhile);
Builder->SetInsertPoint(AfterWhile);
// loop expr always return 0
return Constant::getNullValue(IntegerType::getInt64Ty(*TheContext));
}
当我编译这段代码时,我得到了一个 Segmentation fault (core dumped):
int testLoop (int n) {
int add = 0;
while (n != 0) {
add = add + n;
--n;
}
return add;
}
红外编码:
define i64 @testLoop(i64 %n) {
entry:
%add = alloca i64, align 8
%return = alloca i64, align 8
%n1 = alloca i64, align 8
store i64 %n, ptr %n1, align 4
store i64 0, ptr %add, align 4
br label %test
test: ; preds = %entry
%n2 = load i64, ptr %n1, align 4
%netmp = icmp ne i64 %n2, 0
%ext64 = sext i1 %netmp to i64
%testcond = icmp ne i64 %ext64, 0
br i1 %testcond, label %dowhile, label %afterwhile
dowhile: ; preds = %test
br label %loop
loop: ; preds = %loop, %dowhile
%add3 = load i64, ptr %add, align 4
%n4 = load i64, ptr %n1, align 4
%addtmp = add i64 %add3, %n4
store i64 %addtmp, ptr %add, align 4
%n5 = load i64, ptr %n1, align 4
%selfsub = sub i64 %n5, 1
store i64 %selfsub, ptr %n1, align 4
%n6 = load i64, ptr %n1, align 4
%netmp7 = icmp ne i64 %n6, 0
%ext648 = sext i1 %netmp7 to i64
%loopcond = icmp ne i64 %ext648, 0
br i1 %loopcond, label %loop, label %afterloop
afterloop: ; preds = %loop
afterwhile: ; preds = %test
%add9 = load i64, ptr %add, align 4
store i64 %add9, ptr %return, align 4
%0 = load i64, ptr %return, align 4
ret i64 %0
}
Segmentation fault (core dumped)
我不知道是什么导致了这个错误。我很困惑,我只想知道问题出在哪里。